{"id":339286,"date":"2022-10-04T09:00:39","date_gmt":"2022-10-04T09:00:39","guid":{"rendered":"http:\/\/savepearlharbor.com\/?p=339286"},"modified":"-0001-11-30T00:00:00","modified_gmt":"-0001-11-29T21:00:00","slug":"","status":"publish","type":"post","link":"https:\/\/savepearlharbor.com\/?p=339286","title":{"rendered":"<span>\u0420\u0430\u0437\u0440\u0430\u0431\u0430\u0442\u044b\u0432\u0430\u0435\u043c \u0431\u0438\u0431\u043b\u0438\u043e\u0442\u0435\u043a\u0443 \u043a\u043e\u043c\u043f\u043e\u043d\u0435\u043d\u0442\u043e\u0432 \u0441 \u043f\u043e\u043c\u043e\u0449\u044c\u044e React \u0438 TypeScript<\/span>"},"content":{"rendered":"<div><\/div>\n<div id=\"post-content-body\">\n<div>\n<div class=\"article-formatted-body article-formatted-body article-formatted-body_version-1\">\n<div xmlns=\"http:\/\/www.w3.org\/1999\/xhtml\"><img decoding=\"async\" src=\"https:\/\/habrastorage.org\/r\/w780q1\/webt\/ma\/po\/lv\/mapolvqq4uunxfqoaviv3g9km9y.jpeg\" data-src=\"https:\/\/habrastorage.org\/webt\/ma\/po\/lv\/mapolvqq4uunxfqoaviv3g9km9y.jpeg\" data-blurred=\"true\"\/>  <\/p>\n<p>  \u041f\u0440\u0438\u0432\u0435\u0442, \u0434\u0440\u0443\u0437\u044c\u044f!<\/p>\n<p>  <\/p>\n<p>\u0412 \u044d\u0442\u043e\u0439 \u0441\u0442\u0430\u0442\u044c\u0435 \u044f \u043f\u043e\u043a\u0430\u0436\u0443 \u0432\u0430\u043c, \u043a\u0430\u043a \u043d\u0430\u0447\u0430\u0442\u044c \u0440\u0430\u0437\u0440\u0430\u0431\u043e\u0442\u043a\u0443 \u0431\u0438\u0431\u043b\u0438\u043e\u0442\u0435\u043a\u0438 \u043a\u043e\u043c\u043f\u043e\u043d\u0435\u043d\u0442\u043e\u0432 \u0441 \u043f\u043e\u043c\u043e\u0449\u044c\u044e <a href=\"https:\/\/vitejs.dev\/\">Vite<\/a>, <a href=\"https:\/\/ru.reactjs.org\/\">React<\/a>, <a href=\"https:\/\/www.typescriptlang.org\/\">TypeScript<\/a> \u0438 <a href=\"https:\/\/storybook.js.org\/\">Storybook<\/a>.<\/p>\n<p>  <\/p>\n<p>\u041c\u044b \u0440\u0430\u0437\u0440\u0430\u0431\u043e\u0442\u0430\u0435\u043c \u0431\u0438\u0431\u043b\u0438\u043e\u0442\u0435\u043a\u0443, \u0441\u043e\u0441\u0442\u043e\u044f\u0449\u0443\u044e \u0438\u0437 \u043e\u0434\u043d\u043e\u0433\u043e \u043f\u0440\u043e\u0441\u0442\u043e\u0433\u043e \u043a\u043e\u043c\u043f\u043e\u043d\u0435\u043d\u0442\u0430 \u2014 \u043a\u043d\u043e\u043f\u043a\u0438, \u043f\u043e\u0434\u0433\u043e\u0442\u043e\u0432\u0438\u043c \u0431\u0438\u0431\u043b\u0438\u043e\u0442\u0435\u043a\u0443 \u043a \u043f\u0443\u0431\u043b\u0438\u043a\u0430\u0446\u0438\u0438 \u0432 \u0440\u0435\u0435\u0441\u0442\u0440\u0435 <a href=\"https:\/\/www.npmjs.com\/\">npm<\/a>, \u0430 \u0442\u0430\u043a\u0436\u0435 \u0441\u0433\u0435\u043d\u0435\u0440\u0438\u0440\u0443\u0435\u043c \u0438 \u0432\u0438\u0437\u0443\u0430\u043b\u0438\u0437\u0438\u0440\u0443\u0435\u043c \u0434\u043e\u043a\u0443\u043c\u0435\u043d\u0442\u0430\u0446\u0438\u044e \u0434\u043b\u044f \u043a\u043d\u043e\u043f\u043a\u0438.<\/p>\n<p>  <\/p>\n<p><a href=\"https:\/\/github.com\/harryheman\/Blog-Posts\/tree\/master\/react-ts-lib\">\u0420\u0435\u043f\u043e\u0437\u0438\u0442\u043e\u0440\u0438\u0439 \u0441 \u043a\u043e\u0434\u043e\u043c \u043f\u0440\u043e\u0435\u043a\u0442\u0430<\/a>.<\/p>\n<p>  <\/p>\n<p>\u0415\u0441\u043b\u0438 \u0432\u0430\u043c \u044d\u0442\u043e \u0438\u043d\u0442\u0435\u0440\u0435\u0441\u043d\u043e, \u043f\u0440\u043e\u0448\u0443 \u043f\u043e\u0434 \u043a\u0430\u0442.<\/p>\n<p><a name=\"habracut\"><\/a>  <\/p>\n<h2 id=\"podgotovka-i-nastroyka-proekta\">\u041f\u043e\u0434\u0433\u043e\u0442\u043e\u0432\u043a\u0430 \u0438 \u043d\u0430\u0441\u0442\u0440\u043e\u0439\u043a\u0430 \u043f\u0440\u043e\u0435\u043a\u0442\u0430<\/h2>\n<p>  <\/p>\n<p>\u0421\u043e\u0437\u0434\u0430\u0435\u043c \u0448\u0430\u0431\u043b\u043e\u043d \u043f\u0440\u043e\u0435\u043a\u0442\u0430 \u0441 \u043f\u043e\u043c\u043e\u0449\u044c\u044e <code>Vite<\/code>:<\/p>\n<p>  <\/p>\n<pre><code class=\"bash\"># npm 7+ # react-ts-lib - \u043d\u0430\u0437\u0432\u0430\u043d\u0438\u0435 \u043f\u0440\u043e\u0435\u043a\u0442\u0430 # react-ts - \u0438\u0441\u043f\u043e\u043b\u044c\u0437\u0443\u0435\u043c\u044b\u0439 \u0448\u0430\u0431\u043b\u043e\u043d npm create vite react-ts-lib -- --template react-ts<\/code><\/pre>\n<p>  <\/p>\n<p>\u041f\u0435\u0440\u0435\u0445\u043e\u0434\u0438\u043c \u0432 \u0441\u043e\u0437\u0434\u0430\u043d\u043d\u0443\u044e \u0434\u0438\u0440\u0435\u043a\u0442\u043e\u0440\u0438\u044e, \u0443\u0441\u0442\u0430\u043d\u0430\u0432\u043b\u0438\u0432\u0430\u0435\u043c \u0437\u0430\u0432\u0438\u0441\u0438\u043c\u043e\u0441\u0442\u0438 \u0438 \u0437\u0430\u043f\u0443\u0441\u043a\u0430\u0435\u043c \u0441\u0435\u0440\u0432\u0435\u0440 \u0434\u043b\u044f \u0440\u0430\u0437\u0440\u0430\u0431\u043e\u0442\u043a\u0438:<\/p>\n<p>  <\/p>\n<pre><code class=\"bash\">cd react-ts-lib npm i npm run dev<\/code><\/pre>\n<p>  <\/p>\n<p>\u041f\u0440\u0438\u0432\u043e\u0434\u0438\u043c \u0434\u0438\u0440\u0435\u043a\u0442\u043e\u0440\u0438\u044e \u043a \u0441\u043b\u0435\u0434\u0443\u044e\u0449\u0435\u0439 \u0441\u0442\u0440\u0443\u043a\u0442\u0443\u0440\u0435:<\/p>\n<p>  <\/p>\n<pre><code class=\"plaintext\">- src   - lib     - Button       - Button.tsx     - index.ts - App.tsx - index.css - vite.config.ts - ...<\/code><\/pre>\n<p>  <\/p>\n<p>\u0423\u0441\u0442\u0430\u043d\u0430\u0432\u043b\u0438\u0432\u0430\u0435\u043c \u0431\u0438\u0431\u043b\u0438\u043e\u0442\u0435\u043a\u0443 <a href=\"https:\/\/www.styled-components.com\/\">styled-components<\/a> (\u043c\u044b \u0431\u0443\u0434\u0435\u043c \u0438\u0441\u043f\u043e\u043b\u044c\u0437\u043e\u0432\u0430\u0442\u044c \u044d\u0442\u0443 \u0431\u0438\u0431\u043b\u0438\u043e\u0442\u0435\u043a\u0443 \u0434\u043b\u044f \u0441\u0442\u0438\u043b\u0438\u0437\u0430\u0446\u0438\u0438 \u043a\u043d\u043e\u043f\u043a\u0438) \u0438 \u0442\u0438\u043f\u044b \u0434\u043b\u044f \u043d\u0435\u0435:<\/p>\n<p>  <\/p>\n<pre><code class=\"bash\">npm i styled-componets npm i -D @types\/styled-components<\/code><\/pre>\n<p>  <\/p>\n<p>\u0423\u0441\u0442\u0430\u043d\u0430\u0432\u043b\u0438\u0432\u0430\u0435\u043c \u043f\u043b\u0430\u0433\u0438\u043d <code>Vite<\/code> \u0434\u043b\u044f \u0430\u0432\u0442\u043e\u043c\u0430\u0442\u0438\u0447\u0435\u0441\u043a\u043e\u0439 \u0433\u0435\u043d\u0435\u0440\u0430\u0446\u0438\u0438 \u0444\u0430\u0439\u043b\u0430 \u0441 \u043e\u043f\u0440\u0435\u0434\u0435\u043b\u0435\u043d\u0438\u044f\u043c\u0438 \u0442\u0438\u043f\u043e\u0432:<\/p>\n<p>  <\/p>\n<pre><code class=\"bash\">npm i -D vite-plugin-dts<\/code><\/pre>\n<p>  <\/p>\n<p>\u041d\u0430\u0441\u0442\u0440\u0430\u0438\u0432\u0430\u0435\u043c \u0441\u0431\u043e\u0440\u043a\u0443, \u0440\u0435\u0434\u0430\u043a\u0442\u0438\u0440\u0443\u044f \u0444\u0430\u0439\u043b <code>vite.config.ts<\/code>:<\/p>\n<p>  <\/p>\n<pre><code class=\"javascript\">import { defineConfig } from \"vite\"; import dts from \"vite-plugin-dts\"; import path from \"path\"; import react from \"@vitejs\/plugin-react\";  export default defineConfig({   plugins: [     \/\/ \u043f\u043e\u0434\u0434\u0435\u0440\u0436\u043a\u0430 \u0441\u0438\u043d\u0442\u0430\u043a\u0441\u0438\u0441\u0430 React (JSX \u0438 \u043f\u0440\u043e\u0447\u0435\u0435)     react(),     \/\/ \u0433\u0435\u043d\u0435\u0440\u0430\u0446\u0438\u044f \u0444\u0430\u0439\u043b\u0430 `index.d.ts`     dts({       insertTypesEntry: true,     }),   ],   build: {     lib: {       \/\/ \u043f\u0443\u0442\u044c \u043a \u043e\u0441\u043d\u043e\u0432\u043d\u043e\u043c\u0443 \u0444\u0430\u0439\u043b\u0443 \u0431\u0438\u0431\u043b\u0438\u043e\u0442\u0435\u043a\u0438       entry: path.resolve(__dirname, \"src\/lib\/index.ts\"),       \/\/ \u043d\u0430\u0437\u0432\u0430\u043d\u0438\u0435 \u0431\u0438\u0431\u043b\u0438\u043e\u0442\u0435\u043a\u0438       name: \"ReactTSLib\",       \/\/ \u0444\u043e\u0440\u043c\u0430\u0442\u044b \u0433\u0435\u043d\u0435\u0440\u0438\u0440\u0443\u0435\u043c\u044b\u0445 \u0444\u0430\u0439\u043b\u043e\u0432       formats: [\"es\", \"umd\"],       \/\/ \u043d\u0430\u0437\u0432\u0430\u043d\u0438\u044f \u0433\u0435\u043d\u0435\u0440\u0438\u0440\u0443\u0435\u043c\u044b\u0445 \u0444\u0430\u0439\u043b\u043e\u0432       fileName: (format) => `react-ts-lib.${format}.js`,     },     \/\/ https:\/\/vitejs.dev\/config\/build-options.html#build-rollupoptions     rollupOptions: {       external: [\"react\", \"react-dom\", \"styled-components\"],       output: {         globals: {           react: \"React\",           \"react-dom\": \"ReactDOM\",           \"styled-components\": \"styled\",         },       },     },   }, });<\/code><\/pre>\n<p>  <\/p>\n<h2 id=\"razrabotka-komponenta\">\u0420\u0430\u0437\u0440\u0430\u0431\u043e\u0442\u043a\u0430 \u043a\u043e\u043c\u043f\u043e\u043d\u0435\u043d\u0442\u0430<\/h2>\n<p>  <\/p>\n<p>\u041e\u043f\u0440\u0435\u0434\u0435\u043b\u044f\u0435\u043c \u043c\u0438\u043d\u0438\u043c\u0430\u043b\u044c\u043d\u044b\u0435 \u0441\u0442\u0438\u043b\u0438 \u0438 \u043d\u0435\u0441\u043a\u043e\u043b\u044c\u043a\u043e \u043f\u0435\u0440\u0435\u043c\u0435\u043d\u043d\u044b\u0445 \u0432 \u0444\u0430\u0439\u043b\u0435 <code>index.css<\/code>:<\/p>\n<p>  <\/p>\n<pre><code class=\"css\">\/* \u0438\u043c\u043f\u043e\u0440\u0442\u0438\u0440\u0443\u0435\u043c \u0448\u0440\u0438\u0444\u0442 *\/ @import url(\"https:\/\/fonts.googleapis.com\/css2?family=Montserrat&amp;display=swap\");  \/* \u043e\u043f\u0440\u0435\u0434\u0435\u043b\u044f\u0435\u043c \u043f\u0435\u0440\u0435\u043c\u0435\u043d\u043d\u044b\u0435 *\/ \/* \u043f\u0430\u043b\u0438\u0442\u0440\u0430 `Bootstrap` *\/ :root {   --primary: #0275d8;   --success: #5cb85c;   --warning: #f0ad4e;   --danger: #d9534f;   --light: #f7f7f7;   --dark: #292b2c;   --gray: rgb(155, 155, 155); }  \/* \"\u043b\u0435\u0433\u043a\u0438\u0439\" \u0441\u0431\u0440\u043e\u0441 \u0441\u0442\u0438\u043b\u0435\u0439 *\/ *, *::before, *::after {   box-sizing: border-box;   font-family: \"Montserrat\", sans-serif;   margin: 0;   padding: 0; }  \/* \u0432\u044b\u0440\u0430\u0432\u043d\u0438\u0432\u0430\u043d\u0438\u0435 \u043f\u043e \u0446\u0435\u043d\u0442\u0440\u0443 *\/ #root {   align-items: center;   display: flex;   gap: 0.6rem;   height: 100vh;   justify-content: center; }<\/code><\/pre>\n<p>  <\/p>\n<p>\u041f\u0440\u0438\u0441\u0442\u0443\u043f\u0430\u0435\u043c \u043a \u0440\u0430\u0437\u0440\u0430\u0431\u043e\u0442\u043a\u0435 \u043a\u043d\u043e\u043f\u043a\u0438.<\/p>\n<p>  <\/p>\n<p>\u0420\u0430\u0431\u043e\u0442\u0430\u0435\u043c \u0441 \u0444\u0430\u0439\u043b\u043e\u043c <code>src\/lib\/Button\/Button.tsx<\/code>.<\/p>\n<p>  <\/p>\n<p>\u0418\u043c\u043f\u043e\u0440\u0442\u0438\u0440\u0443\u0435\u043c \u0437\u0430\u0432\u0438\u0441\u0438\u043c\u043e\u0441\u0442\u0438:<\/p>\n<p>  <\/p>\n<pre><code class=\"javascript\">import {   ButtonHTMLAttributes,   FC,   MouseEventHandler,   PropsWithChildren, } from \"react\"; import styled from \"styled-components\";<\/code><\/pre>\n<p>  <\/p>\n<p>\u041e\u043f\u0440\u0435\u0434\u0435\u043b\u044f\u0435\u043c \u043f\u0435\u0440\u0435\u0447\u0438\u0441\u043b\u0435\u043d\u0438\u0435 \u0441 \u0432\u0430\u0440\u0438\u0430\u043d\u0442\u0430\u043c\u0438 \u043a\u043d\u043e\u043f\u043a\u0438:<\/p>\n<p>  <\/p>\n<pre><code class=\"javascript\">export enum BUTTON_VARIANTS {   PRIMARY = \"primary\",   SUCCESS = \"success\",   WARNING = \"warning\",   DANGER = \"danger\", }<\/code><\/pre>\n<p>  <\/p>\n<p>\u041e\u043f\u0440\u0435\u0434\u0435\u043b\u044f\u0435\u043c \u0442\u0438\u043f\u044b \u043f\u0440\u043e\u043f\u043e\u0432:<\/p>\n<p>  <\/p>\n<pre><code class=\"javascript\">type Props = ButtonHTMLAttributes&lt;HTMLButtonElement> &amp; {   variant?: BUTTON_VARIANTS;   onClick?: MouseEventHandler&lt;HTMLButtonElement>; };<\/code><\/pre>\n<p>  <\/p>\n<p>\u041a\u0440\u043e\u043c\u0435 \u0441\u0442\u0430\u043d\u0434\u0430\u0440\u0442\u043d\u044b\u0445 \u0430\u0442\u0440\u0438\u0431\u0443\u0442\u043e\u0432, \u043a\u043d\u043e\u043f\u043a\u0430 \u043f\u0440\u0438\u043d\u0438\u043c\u0430\u0435\u0442 2 \u043f\u0440\u043e\u043f\u0430:<\/p>\n<p>  <\/p>\n<ul>\n<li><code>variant<\/code> \u2014 \u0432\u0430\u0440\u0438\u0430\u043d\u0442 \u043a\u043d\u043e\u043f\u043a\u0438 (<code>primary<\/code> \u0438 \u0434\u0440.);<\/li>\n<li><code>onClick<\/code> \u2014 \u043e\u0431\u0440\u0430\u0431\u043e\u0442\u0447\u0438\u043a \u043d\u0430\u0436\u0430\u0442\u0438\u044f \u043a\u043d\u043e\u043f\u043a\u0438.<\/li>\n<\/ul>\n<p>  <\/p>\n<p>\u041e\u043f\u0440\u0435\u0434\u0435\u043b\u044f\u0435\u043c \u043a\u043e\u043c\u043f\u043e\u043d\u0435\u043d\u0442 \u043a\u043d\u043e\u043f\u043a\u0438:<\/p>\n<p>  <\/p>\n<pre><code class=\"javascript\">const Button: FC&lt;PropsWithChildren&lt;Props>> = ({   children,   disabled,   onClick,   variant = BUTTON_VARIANTS.PRIMARY,   ...restProps }) => {   \/\/ \u0435\u0441\u043b\u0438 \u043a\u043d\u043e\u043f\u043a\u0430 \u0437\u0430\u0431\u043b\u043e\u043a\u0438\u0440\u043e\u0432\u0430\u043d\u0430, \u043f\u0435\u0440\u0435\u0434\u0430\u043d\u043d\u044b\u0439 \u043e\u0431\u0440\u0430\u0431\u043e\u0442\u0447\u0438\u043a \u043d\u0435 \u0432\u044b\u0437\u044b\u0432\u0430\u0435\u0442\u0441\u044f   const handleClick: MouseEventHandler&lt;HTMLButtonElement> = (e) => {     if (disabled) return;     onClick &amp;&amp; onClick(e);   };    return (     &lt;button disabled={disabled} onClick={handleClick} {...restProps}>       {children}     &lt;\/button>   ); };<\/code><\/pre>\n<p>  <\/p>\n<p>\u041e\u043f\u0440\u0435\u0434\u0435\u043b\u044f\u0435\u043c \u0441\u0442\u0438\u043b\u0438\u0437\u043e\u0432\u0430\u043d\u043d\u0443\u044e \u043a\u043d\u043e\u043f\u043a\u0443 \u0441 \u043f\u043e\u043c\u043e\u0449\u044c\u044e <code>styled<\/code>:<\/p>\n<p>  <\/p>\n<pre><code class=\"javascript\">const StyledButton = styled(Button)`   background-color: var(     --${(props) => (props.disabled ? \"gray\" : props.variant ?? \"primary\")}   );   border-radius: 6px;   border: none;   box-shadow: 0 1px 3px rgba(0, 0, 0, 0.4);   color: var(     ${(props) =>       props.variant &amp;&amp;       (props.variant === BUTTON_VARIANTS.SUCCESS ??         props.variant === BUTTON_VARIANTS.WARNING)         ? \"--dark\"         : \"--light\"}   );   cursor: ${(props) => (props.disabled ? \"default\" : \"pointer\")};   font-weight: 600;   letter-spacing: 1px;   opacity: ${(props) => (props.disabled ? \"0.6\" : \"1\")};   outline: none;   padding: 0.8rem;   text-transform: uppercase;   transition: 0.4s;    &amp;:not([disabled]):hover {     opacity: 0.8;   }    &amp;:active {     box-shadow: none;   } `;<\/code><\/pre>\n<p>  <\/p>\n<p>\u0417\u0434\u0435\u0441\u044c \u0445\u043e\u0447\u0435\u0442\u0441\u044f \u043e\u0442\u043c\u0435\u0442\u0438\u0442\u044c 2 \u043c\u043e\u043c\u0435\u043d\u0442\u0430:<\/p>\n<p>  <\/p>\n<ul>\n<li><code>background-color: var(--${(props) => (props.disabled ? \"gray\" : props.variant ?? \"primary\")});<\/code> \u043e\u0437\u043d\u0430\u0447\u0430\u0435\u0442, \u0447\u0442\u043e \u0444\u043e\u043d\u043e\u0432\u044b\u0439 \u0446\u0432\u0435\u0442 \u0437\u0430\u0432\u0438\u0441\u0438\u0442 \u043e\u0442 \u0432\u0430\u0440\u0438\u0430\u043d\u0442\u0430 \u043a\u043d\u043e\u043f\u043a\u0438 \u0438 \u043e\u043f\u0440\u0435\u0434\u0435\u043b\u044f\u0435\u0442\u0441\u044f \u0441 \u043f\u043e\u043c\u043e\u0449\u044c\u044e \u043f\u0435\u0440\u0435\u043c\u0435\u043d\u043d\u044b\u0445, \u043e\u0431\u044a\u044f\u0432\u043b\u0435\u043d\u043d\u044b\u0445 \u0432 <code>index.css<\/code>. \u0424\u043e\u043d \u0437\u0430\u0431\u043b\u043e\u043a\u0438\u0440\u043e\u0432\u0430\u043d\u043d\u043e\u0439 \u043a\u043d\u043e\u043f\u043a\u0438 \u2014 <code>--gray<\/code> \u0438\u043b\u0438 <code>rgb(155, 155, 155)<\/code>, \u0434\u0435\u0444\u043e\u043b\u0442\u043d\u044b\u0439 \u0444\u043e\u043d \u2014 <code>--primary<\/code> \u0438\u043b\u0438 <code>#0275d8<\/code>;<\/li>\n<li>\u044d\u0442\u043e:<\/li>\n<\/ul>\n<p>  <\/p>\n<pre><code class=\"javascript\">color: var(   ${(props) =>     props.variant &amp;&amp;     (props.variant === BUTTON_VARIANTS.SUCCESS ??       props.variant === BUTTON_VARIANTS.WARNING)       ? \"--dark\"       : \"--light\"} );<\/code><\/pre>\n<p>  <\/p>\n<p>\u043e\u0437\u043d\u0430\u0447\u0430\u0435\u0442, \u0447\u0442\u043e \u0446\u0432\u0435\u0442 \u0442\u0435\u043a\u0441\u0442\u0430 \u0442\u0430\u043a\u0436\u0435 \u0437\u0430\u0432\u0438\u0441\u0438\u0442 \u043e\u0442 \u0432\u0430\u0440\u0438\u0430\u043d\u0442\u0430 \u043a\u043d\u043e\u043f\u043a\u0438 \u0438 \u043e\u043f\u0440\u0435\u0434\u0435\u043b\u044f\u0435\u0442\u0441\u044f \u0441 \u043f\u043e\u043c\u043e\u0449\u044c\u044e \u043f\u0435\u0440\u0435\u043c\u0435\u043d\u043d\u044b\u0445 <code>CSS<\/code>. \u0426\u0432\u0435\u0442 \u0442\u0435\u043a\u0441\u0442\u0430 \u043a\u043d\u043e\u043f\u043a\u0438 \u0443\u0441\u043f\u0435\u0445\u0430 \u0438\u043b\u0438 \u043f\u0440\u0435\u0434\u0443\u043f\u0440\u0435\u0436\u0434\u0435\u043d\u0438\u044f \u2014 <code>--dark<\/code> \u0438\u043b\u0438 <code>#292b2c<\/code>, \u0446\u0432\u0435\u0442 \u043e\u0441\u0442\u0430\u043b\u044c\u043d\u044b\u0445 \u043a\u043d\u043e\u043f\u043e\u043a \u2014 <code>--light<\/code> \u0438\u043b\u0438 <code>#f7f7f7<\/code>.<\/p>\n<p>  <\/p>\n<p>\u041f\u043e\u043b\u0430\u0433\u0430\u044e, \u043e\u0441\u0442\u0430\u043b\u044c\u043d\u044b\u0435 \u0441\u0442\u0438\u043b\u0438 \u0432\u043e\u043f\u0440\u043e\u0441\u043e\u0432 \u043d\u0435 \u0432\u044b\u0437\u044b\u0432\u0430\u044e\u0442.<\/p>\n<p>  <\/p>\n<p>\u041f\u043e\u0432\u0442\u043e\u0440\u043d\u043e \u044d\u043a\u0441\u043f\u043e\u0440\u0442\u0438\u0440\u0443\u0435\u043c \u043a\u043d\u043e\u043f\u043a\u0443 \u0438 \u043f\u0435\u0440\u0435\u0447\u0438\u0441\u043b\u0435\u043d\u0438\u0435 \u0432 \u0444\u0430\u0439\u043b\u0435 <code>src\/lib\/index.ts<\/code>:<\/p>\n<p>  <\/p>\n<pre><code class=\"javascript\">export { default as Button, BUTTON_VARIANTS } from \".\/Button\/Button\";<\/code><\/pre>\n<p>  <\/p>\n<p>\u041f\u043e\u0441\u043c\u043e\u0442\u0440\u0438\u043c, \u043a\u0430\u043a \u0432\u044b\u0433\u043b\u044f\u0434\u0438\u0442 \u0438 \u0440\u0430\u0431\u043e\u0442\u0430\u0435\u0442 \u043d\u0430\u0448\u0430 \u043a\u043d\u043e\u043f\u043a\u0430.<\/p>\n<p>  <\/p>\n<p>\u0420\u0435\u0434\u0430\u043a\u0442\u0438\u0440\u0443\u0435\u043c \u0444\u0430\u0439\u043b <code>App.tsx<\/code>:<\/p>\n<p>  <\/p>\n<pre><code class=\"javascript\">import { Button, BUTTON_VARIANTS } from \".\/lib\";  function App() {   \/\/ \u043e\u0431\u0440\u0430\u0431\u043e\u0442\u0447\u0438\u043a \u043d\u0430\u0436\u0430\u0442\u0438\u044f \u043a\u043d\u043e\u043f\u043a\u0438   \/\/ \u043f\u0440\u0438\u043d\u0438\u043c\u0430\u0435\u0442 \u0432\u0430\u0440\u0438\u0430\u043d\u0442 \u043a\u043d\u043e\u043f\u043a\u0438   const onClick = (variant: string) => {     \/\/ \u0432\u044b\u0432\u043e\u0434\u0438\u043c \u0441\u043e\u043e\u0431\u0449\u0435\u043d\u0438\u0435 \u0432 \u043a\u043e\u043d\u0441\u043e\u043b\u044c \u0438\u043d\u0441\u0442\u0440\u0443\u043c\u0435\u043d\u0442\u043e\u0432 \u0440\u0430\u0437\u0440\u0430\u0431\u043e\u0442\u0447\u0438\u043a\u0430 \u0432 \u0431\u0440\u0430\u0443\u0437\u0435\u0440\u0435     console.log(`${variant} button clicked`);   };    return (     &lt;>       {\/* \u0434\u0435\u0444\u043e\u043b\u0442\u043d\u0430\u044f \u043a\u043d\u043e\u043f\u043a\u0430 *\/}       &lt;Button onClick={() => onClick(\"primary\")}>primary&lt;\/Button>       {\/* \u0437\u0430\u0431\u043b\u043e\u043a\u0438\u0440\u043e\u0432\u0430\u043d\u043d\u0430\u044f \u043a\u043d\u043e\u043f\u043a\u0430 *\/}       &lt;Button onClick={() => onClick(\"disabled\")} disabled>         disabled       &lt;\/Button>       {\/* \u0443\u0441\u043f\u0435\u0445 *\/}       &lt;Button         variant={BUTTON_VARIANTS.SUCCESS}         onClick={() => onClick(BUTTON_VARIANTS.SUCCESS)}       >         {BUTTON_VARIANTS.SUCCESS}       &lt;\/Button>       {\/* \u043f\u0440\u0435\u0434\u0443\u043f\u0440\u0435\u0436\u0434\u0435\u043d\u0438\u0435 *\/}       &lt;Button         variant={BUTTON_VARIANTS.WARNING}         onClick={() => onClick(BUTTON_VARIANTS.WARNING)}       >         {BUTTON_VARIANTS.WARNING}       &lt;\/Button>       {\/* \u043e\u043f\u0430\u0441\u043d\u043e\u0441\u0442\u044c *\/}       &lt;Button         variant={BUTTON_VARIANTS.DANGER}         onClick={() => onClick(BUTTON_VARIANTS.DANGER)}       >         {BUTTON_VARIANTS.DANGER}       &lt;\/Button>     &lt;\/>   ); }  export default App;<\/code><\/pre>\n<p>  <\/p>\n<p>\u0417\u0430\u043f\u0443\u0441\u043a\u0430\u0435\u043c \u0441\u0435\u0440\u0432\u0435\u0440 \u0434\u043b\u044f \u0440\u0430\u0437\u0440\u0430\u0431\u043e\u0442\u043a\u0438 \u0441 \u043f\u043e\u043c\u043e\u0449\u044c\u044e \u043a\u043e\u043c\u0430\u043d\u0434\u044b <code>npm run dev<\/code>:<\/p>\n<p>  <img decoding=\"async\" src=\"https:\/\/habrastorage.org\/r\/w1560\/webt\/s0\/be\/3a\/s0be3aiailkwuxdfjj-2tkcywo0.png\" data-src=\"https:\/\/habrastorage.org\/webt\/s0\/be\/3a\/s0be3aiailkwuxdfjj-2tkcywo0.png\"\/>  <\/p>\n<p>  <\/p>\n<p>  <\/p>\n<h2 id=\"sborka-i-publikaciya-paketa\">\u0421\u0431\u043e\u0440\u043a\u0430 \u0438 \u043f\u0443\u0431\u043b\u0438\u043a\u0430\u0446\u0438\u044f \u043f\u0430\u043a\u0435\u0442\u0430<\/h2>\n<p>  <\/p>\n<p>\u0420\u0435\u0434\u0430\u043a\u0442\u0438\u0440\u0443\u0435\u043c \u0444\u0430\u0439\u043b <code>package.json<\/code>, \u043e\u043f\u0440\u0435\u0434\u0435\u043b\u044f\u044f \u0432 \u043d\u0435\u043c \u043d\u0430\u0437\u0432\u0430\u043d\u0438\u0435 \u043f\u0430\u043a\u0435\u0442\u0430 (\u043d\u0430\u0448 \u043f\u0430\u043a\u0435\u0442 \u0431\u0443\u0434\u0435\u0442 \u0438\u043c\u0435\u0442\u044c <a href=\"https:\/\/docs.npmjs.com\/cli\/v8\/using-npm\/scope\">scope<\/a> \u0441 \u043e\u0440\u0438\u0433\u0438\u043d\u0430\u043b\u044c\u043d\u044b\u043c \u043d\u0430\u0437\u0432\u0430\u043d\u0438\u0435\u043c <code>@my-scope<\/code> (\u0432 \u0434\u0430\u043d\u043d\u043e\u043c \u0441\u043b\u0443\u0447\u0430\u0435 \u043f\u0440\u0435\u0444\u0438\u043a\u0441 <code>@<\/code> \u044f\u0432\u043b\u044f\u0435\u0442\u0441\u044f \u043e\u0431\u044f\u0437\u0430\u0442\u0435\u043b\u044c\u043d\u044b\u043c)), \u0435\u0433\u043e \u0432\u0435\u0440\u0441\u0438\u044e, \u043b\u0438\u0446\u0435\u043d\u0437\u0438\u044e, \u0434\u0438\u0440\u0435\u043a\u0442\u043e\u0440\u0438\u044e \u0441 \u0444\u0430\u0439\u043b\u0430\u043c\u0438, \u0444\u0430\u0439\u043b \u0441 \u0442\u0438\u043f\u0430\u043c\u0438, \u0430 \u0442\u0430\u043a\u0436\u0435 \u043d\u0430\u0441\u0442\u0440\u0430\u0438\u0432\u0430\u044f \u044d\u043a\u0441\u043f\u043e\u0440\u0442\u044b (\u0440\u0430\u0437\u0434\u0435\u043b\u044b <code>scripts<\/code>, <code>dependencies<\/code> \u0438 <code>devDependencies<\/code> \u043e\u043f\u0443\u0449\u0435\u043d\u044b):<\/p>\n<p>  <\/p>\n<pre><code class=\"json\">{   \"name\": \"@my-scope\/react-ts-lib\",   \"version\": \"0.0.0\",   \"license\": \"MIT\",   \"files\": [     \"dist\"   ],   \"main\": \".\/dist\/react-ts-lib.umd.js\",   \"module\": \".\/dist\/react-ts-lib.es.js\",   \"types\": \".\/dist\/index.d.ts\",   \"exports\": {     \".\": {       \"import\": \".\/dist\/react-ts-lib.es.js\",       \"require\": \".\/dist\/react-ts-lib.umd.js\"     }   } }<\/code><\/pre>\n<p>  <\/p>\n<p>\u041f\u0440\u0438\u043c\u0435\u0440 <code>package.json<\/code> (\u0441 \u0434\u043e\u043f\u043e\u043b\u043d\u0438\u0442\u0435\u043b\u044c\u043d\u044b\u043c\u0438 \u043f\u043e\u043b\u044f\u043c\u0438) \u0440\u0435\u0430\u043b\u044c\u043d\u043e\u0439 \u0431\u0438\u0431\u043b\u0438\u043e\u0442\u0435\u043a\u0438 \u043c\u043e\u0436\u043d\u043e \u043d\u0430\u0439\u0442\u0438 <a href=\"https:\/\/github.com\/harryheman\/simple-fetch\/blob\/master\/package.json\">\u0437\u0434\u0435\u0441\u044c<\/a>.<\/p>\n<p>  <\/p>\n<p><em>\u041e\u0431\u0440\u0430\u0442\u0438\u0442\u0435 \u0432\u043d\u0438\u043c\u0430\u043d\u0438\u0435<\/em>: \u043f\u0435\u0440\u0435\u0434 \u0441\u0431\u043e\u0440\u043a\u043e\u0439 \u0438\u043c\u0435\u0435\u0442 \u0441\u043c\u044b\u0441\u043b &#171;\u0447\u0438\u0441\u0442\u0438\u0442\u044c&#187; <code>package.json<\/code>.<\/p>\n<p>  <\/p>\n<p>\u0423\u0441\u0442\u0430\u043d\u0430\u0432\u043b\u0438\u0432\u0430\u0435\u043c \u043f\u0430\u043a\u0435\u0442 <a href=\"https:\/\/www.npmjs.com\/package\/json\">json<\/a> \u0432 \u043a\u0430\u0447\u0435\u0441\u0442\u0432\u0435 \u0437\u0430\u0432\u0438\u0441\u0438\u043c\u043e\u0441\u0442\u0438 \u0434\u043b\u044f \u0440\u0430\u0437\u0440\u0430\u0431\u043e\u0442\u043a\u0438:<\/p>\n<p>  <\/p>\n<pre><code class=\"bash\">npm i -D json<\/code><\/pre>\n<p>  <\/p>\n<p>\u0418 \u043e\u043f\u0440\u0435\u0434\u0435\u043b\u044f\u0435\u043c \u0432 \u0440\u0430\u0437\u0434\u0435\u043b\u0435 <code>scripts<\/code> \u0441\u043b\u0435\u0434\u0443\u044e\u0449\u0443\u044e \u043a\u043e\u043c\u0430\u043d\u0434\u0443:<\/p>\n<p>  <\/p>\n<pre><code class=\"json\">\"prepack\": \"json -f package.json -I -e \\\"delete this.devDependencies; delete this.dependencies\\\"\",<\/code><\/pre>\n<p>  <\/p>\n<p>\u0412\u044b\u043f\u043e\u043b\u043d\u044f\u0435\u043c \u0441\u0431\u043e\u0440\u043a\u0443 \u0441 \u043f\u043e\u043c\u043e\u0449\u044c\u044e \u043a\u043e\u043c\u0430\u043d\u0434\u044b <code>npm run build<\/code>:<\/p>\n<p>  <img decoding=\"async\" src=\"https:\/\/habrastorage.org\/r\/w1560\/webt\/yr\/fs\/nt\/yrfsnt7cknzhykkg_ibm01dp0i4.png\" data-src=\"https:\/\/habrastorage.org\/webt\/yr\/fs\/nt\/yrfsnt7cknzhykkg_ibm01dp0i4.png\"\/>  <\/p>\n<p>  <\/p>\n<p>  <\/p>\n<p>\u042d\u0442\u043e \u043f\u0440\u0438\u0432\u043e\u0434\u0438\u0442 \u043a \u0433\u0435\u043d\u0435\u0440\u0430\u0446\u0438\u0438 \u0434\u0438\u0440\u0435\u043a\u0442\u043e\u0440\u0438\u0438 <code>dist<\/code> \u0441 \u0444\u0430\u0439\u043b\u0430\u043c\u0438 \u0431\u0438\u0431\u043b\u0438\u043e\u0442\u0435\u043a\u0438.<\/p>\n<p>  <\/p>\n<p>\u0414\u043b\u044f \u043b\u043e\u043a\u0430\u043b\u044c\u043d\u043e\u0433\u043e \u0442\u0435\u0441\u0442\u0438\u0440\u043e\u0432\u0430\u043d\u0438\u044f \u0431\u0438\u0431\u043b\u0438\u043e\u0442\u0435\u043a\u0438 \u043d\u0435\u043e\u0431\u0445\u043e\u0434\u0438\u043c\u043e \u0441\u0434\u0435\u043b\u0430\u0442\u044c \u0441\u043b\u0435\u0434\u0443\u044e\u0449\u0435\u0435:<\/p>\n<p>  <\/p>\n<ul>\n<li>\u043d\u0430\u0445\u043e\u0434\u044f\u0441\u044c \u0432 \u043a\u043e\u0440\u043d\u0435\u0432\u043e\u0439 \u0434\u0438\u0440\u0435\u043a\u0442\u043e\u0440\u0438\u0438 \u043f\u0440\u043e\u0435\u043a\u0442\u0430, \u0432\u044b\u043f\u043e\u043b\u043d\u044f\u0435\u043c \u043a\u043e\u043c\u0430\u043d\u0434\u0443 <code>npm link<\/code> \u0434\u043b\u044f \u0441\u043e\u0437\u0434\u0430\u043d\u0438\u044f \u0441\u0438\u043c\u0432\u043e\u043b\u0438\u0447\u0435\u0441\u043a\u043e\u0439 \u0441\u0441\u044b\u043b\u043a\u0438. \u042d\u0442\u0430 \u043a\u043e\u043c\u0430\u043d\u0434\u0430 \u043f\u0440\u0438\u0432\u043e\u0434\u0438\u0442 \u043a \u0434\u043e\u0431\u0430\u0432\u043b\u0435\u043d\u0438\u044e \u043f\u0430\u043a\u0435\u0442\u0430 \u0432 \u0433\u043b\u043e\u0431\u0430\u043b\u044c\u043d\u0443\u044e \u0434\u0438\u0440\u0435\u043a\u0442\u043e\u0440\u0438\u044e <code>node_modules<\/code>. \u0421\u043f\u0438\u0441\u043e\u043a \u0433\u043b\u043e\u0431\u0430\u043b\u044c\u043d\u043e \u0443\u0441\u0442\u0430\u043d\u043e\u0432\u043b\u0435\u043d\u043d\u044b\u0445 \u043f\u0430\u043a\u0435\u0442\u043e\u0432 \u043c\u043e\u0436\u043d\u043e \u043f\u043e\u043b\u0443\u0447\u0438\u0442\u044c \u0441 \u043f\u043e\u043c\u043e\u0449\u044c\u044e \u043a\u043e\u043c\u0430\u043d\u0434\u044b <code>npm -g list --depth 0<\/code>:<\/li>\n<\/ul>\n<p>  <img decoding=\"async\" src=\"https:\/\/habrastorage.org\/r\/w1560\/webt\/pt\/0s\/yt\/pt0sytfzjdsdo--pijpqzb2zels.png\" data-src=\"https:\/\/habrastorage.org\/webt\/pt\/0s\/yt\/pt0sytfzjdsdo--pijpqzb2zels.png\"\/>  <\/p>\n<p>  <\/p>\n<p>  <\/p>\n<ul>\n<li>\u043d\u0430\u0445\u043e\u0434\u044f\u0441\u044c \u0432 \u043a\u043e\u0440\u043d\u0435\u0432\u043e\u0439 \u0434\u0438\u0440\u0435\u043a\u0442\u043e\u0440\u0438\u0438 (\u0438\u043b\u0438 \u043b\u044e\u0431\u043e\u0439 \u0434\u0440\u0443\u0433\u043e\u0439), \u0432\u044b\u043f\u043e\u043b\u043d\u044f\u0435\u043c \u043a\u043e\u043c\u0430\u043d\u0434\u0443 <code>npm link @my-scope\/react-ts-lib<\/code> \u0434\u043b\u044f \u043f\u0440\u0438\u0432\u044f\u0437\u043a\u0438 \u043f\u0430\u043a\u0435\u0442\u0430 \u043a \u043f\u0440\u043e\u0435\u043a\u0442\u0443.<\/li>\n<\/ul>\n<p>  <\/p>\n<p>\u0420\u0435\u0434\u0430\u043a\u0442\u0438\u0440\u0443\u0435\u043c \u0438\u043c\u043f\u043e\u0440\u0442 \u0432 \u0444\u0430\u0439\u043b\u0435 <code>App.tsx<\/code>:<\/p>\n<p>  <\/p>\n<pre><code class=\"javascript\">import { Button, BUTTON_VARIANTS } from \"@my-scope\/react-ts-lib\";<\/code><\/pre>\n<p>  <\/p>\n<p>\u0418 \u0437\u0430\u043f\u0443\u0441\u043a\u0430\u0435\u043c \u0441\u0435\u0440\u0432\u0435\u0440 \u0434\u043b\u044f \u0440\u0430\u0437\u0440\u0430\u0431\u043e\u0442\u043a\u0438 \u0441 \u043f\u043e\u043c\u043e\u0449\u044c\u044e \u043a\u043e\u043c\u0430\u043d\u0434\u044b <code>npm run dev<\/code>:<\/p>\n<p>  <img decoding=\"async\" src=\"https:\/\/habrastorage.org\/r\/w1560\/webt\/s0\/be\/3a\/s0be3aiailkwuxdfjj-2tkcywo0.png\" data-src=\"https:\/\/habrastorage.org\/webt\/s0\/be\/3a\/s0be3aiailkwuxdfjj-2tkcywo0.png\"\/>  <\/p>\n<p>  <\/p>\n<p>  <\/p>\n<p><em>\u041e\u0431\u0440\u0430\u0442\u0438\u0442\u0435 \u0432\u043d\u0438\u043c\u0430\u043d\u0438\u0435<\/em>: \u043f\u043e\u0441\u043b\u0435 \u043b\u043e\u043a\u0430\u043b\u044c\u043d\u043e\u0433\u043e \u0442\u0435\u0441\u0442\u0438\u0440\u043e\u0432\u0430\u043d\u0438\u044f \u043f\u0430\u043a\u0435\u0442\u0430 \u043d\u0435\u043e\u0431\u0445\u043e\u0434\u0438\u043c\u043e \u0432\u044b\u043f\u043e\u043b\u043d\u0438\u0442\u044c 2 \u043a\u043e\u043c\u0430\u043d\u0434\u044b:<\/p>\n<p>  <\/p>\n<ul>\n<li><code>npm unlink @my-scope\/react-ts-lib<\/code> \u0434\u043b\u044f \u0442\u043e\u0433\u043e, \u0447\u0442\u043e\u0431\u044b \u043e\u0442\u0432\u044f\u0437\u0430\u0442\u044c \u043f\u0430\u043a\u0435\u0442 \u043e\u0442 \u043f\u0440\u043e\u0435\u043a\u0442\u0430;<\/li>\n<li><code>npm -g rm @my-scope\/react-ts-lib<\/code> \u0434\u043b\u044f \u0443\u0434\u0430\u043b\u0435\u043d\u0438\u044f \u043f\u0430\u043a\u0435\u0442\u0430 \u0438\u0437 <code>node_modules<\/code> \u043d\u0430 \u0433\u043b\u043e\u0431\u0430\u043b\u044c\u043d\u043e\u043c \u0443\u0440\u043e\u0432\u043d\u0435.<\/li>\n<\/ul>\n<p>  <\/p>\n<p>\u0414\u043b\u044f \u043f\u0443\u0431\u043b\u0438\u043a\u0430\u0446\u0438\u0438 \u043f\u0430\u043a\u0435\u0442\u0430 \u0432 \u0440\u0435\u0435\u0441\u0442\u0440\u0435 <code>npm<\/code> \u043d\u0435\u043e\u0431\u0445\u043e\u0434\u0438\u043c\u043e \u0441\u0434\u0435\u043b\u0430\u0442\u044c \u0441\u043b\u0435\u0434\u0443\u044e\u0449\u0435\u0435:<\/p>\n<p>  <\/p>\n<ul>\n<li><a href=\"https:\/\/www.npmjs.com\/signup\">\u0441\u043e\u0437\u0434\u0430\u0435\u043c \u0430\u043a\u043a\u0430\u0443\u043d\u0442 npm<\/a>;<\/li>\n<li>\u0430\u0432\u0442\u043e\u0440\u0438\u0437\u0443\u0435\u043c\u0441\u044f \u0441 \u043f\u043e\u043c\u043e\u0449\u044c\u044e \u043a\u043e\u043c\u0430\u043d\u0434\u044b <code>npm login<\/code>;<\/li>\n<li>\u043f\u0443\u0431\u043b\u0438\u043a\u0443\u0435\u043c \u043f\u0430\u043a\u0435\u0442 \u0441 \u043f\u043e\u043c\u043e\u0449\u044c\u044e \u043a\u043e\u043c\u0430\u043d\u0434\u044b <code>npm publish<\/code>.<\/li>\n<\/ul>\n<p>  <\/p>\n<p>\u0421\u043f\u0438\u0441\u043e\u043a \u043e\u043f\u0443\u0431\u043b\u0438\u043a\u043e\u0432\u0430\u043d\u043d\u044b\u0445 \u043f\u0430\u043a\u0435\u0442\u043e\u0432 \u043c\u043e\u0436\u043d\u043e \u0443\u0432\u0438\u0434\u0435\u0442\u044c \u043d\u0430 \u0441\u0442\u0440\u0430\u043d\u0438\u0446\u0435 \u0441\u0432\u043e\u0435\u0433\u043e \u043f\u0440\u043e\u0444\u0438\u043b\u044f (\u0432 \u043c\u043e\u0435\u043c \u0441\u043b\u0443\u0447\u0430\u0435 \u2014 \u044d\u0442\u043e <a href=\"https:\/\/www.npmjs.com\/~igor_agapov\">https:\/\/www.npmjs.com\/~igor_agapov<\/a>):<\/p>\n<p>  <img decoding=\"async\" src=\"https:\/\/habrastorage.org\/r\/w1560\/webt\/jo\/pt\/fm\/joptfmqblejsvjc3jpqzsshqve0.png\" data-src=\"https:\/\/habrastorage.org\/webt\/jo\/pt\/fm\/joptfmqblejsvjc3jpqzsshqve0.png\"\/>  <\/p>\n<p>  <\/p>\n<p>  <\/p>\n<h2 id=\"generaciya-i-vizualizaciya-dokumentacii\">\u0413\u0435\u043d\u0435\u0440\u0430\u0446\u0438\u044f \u0438 \u0432\u0438\u0437\u0443\u0430\u043b\u0438\u0437\u0430\u0446\u0438\u044f \u0434\u043e\u043a\u0443\u043c\u0435\u043d\u0442\u0430\u0446\u0438\u0438<\/h2>\n<p>  <\/p>\n<p>\u0423\u0441\u0442\u0430\u043d\u0430\u0432\u043b\u0438\u0432\u0430\u0435\u043c \u043f\u0430\u043a\u0435\u0442 <a href=\"https:\/\/www.npmjs.com\/package\/@storybook\/builder-vite\">@storybook\/builder-vite<br \/>  <\/a> \u0432 \u043a\u0430\u0447\u0435\u0441\u0442\u0432\u0435 \u0437\u0430\u0432\u0438\u0441\u0438\u043c\u043e\u0441\u0442\u0438 \u0434\u043b\u044f \u0440\u0430\u0437\u0440\u0430\u0431\u043e\u0442\u043a\u0438:<\/p>\n<p>  <\/p>\n<pre><code class=\"bash\">npm i -D @storybook\/builder-vite<\/code><\/pre>\n<p>  <\/p>\n<p>\u0418 \u0438\u043d\u0438\u0446\u0438\u0430\u043b\u0438\u0437\u0438\u0440\u0443\u0435\u043c <code>Storybook<\/code> \u0441 \u043f\u043e\u043c\u043e\u0449\u044c\u044e \u0441\u043b\u0435\u0434\u0443\u044e\u0449\u0435\u0439 \u043a\u043e\u043c\u0430\u043d\u0434\u044b:<\/p>\n<p>  <\/p>\n<pre><code class=\"bash\">npx sb init --builder @storybook\/builder-vite<\/code><\/pre>\n<p>  <\/p>\n<p>\u042d\u0442\u043e \u043f\u0440\u0438\u0432\u043e\u0434\u0438\u0442 \u043a \u0433\u0435\u043d\u0435\u0440\u0430\u0446\u0438\u0438 \u0434\u0438\u0440\u0435\u043a\u0442\u043e\u0440\u0438\u0438 <code>.storybook<\/code>. \u0423\u0431\u0435\u0434\u0438\u0442\u0435\u0441\u044c, \u0447\u0442\u043e \u0444\u0430\u0439\u043b <code>main.js<\/code> \u0432 \u044d\u0442\u043e\u0439 \u0434\u0438\u0440\u0435\u043a\u0442\u043e\u0440\u0438\u0438 \u0438\u043c\u0435\u0435\u0442 \u0441\u043b\u0435\u0434\u0443\u044e\u0449\u0438\u0439 \u0432\u0438\u0434:<\/p>\n<p>  <\/p>\n<pre><code class=\"plaintext\">module.exports = {   \"stories\": [     \"..\/src\/**\/*.stories.mdx\",     \"..\/src\/**\/*.stories.@(js|jsx|ts|tsx)\"   ],   \"addons\": [     \"@storybook\/addon-links\",     \"@storybook\/addon-essentials\",     \"@storybook\/addon-interactions\"   ],   \"framework\": \"@storybook\/react\",   \"core\": {     \"builder\": \"@storybook\/builder-vite\"   },   \"features\": {     \"storyStoreV7\": true   } }<\/code><\/pre>\n<p>  <\/p>\n<p>\u0421\u043e\u0437\u0434\u0430\u0435\u043c \u0432 \u043a\u043e\u0440\u043d\u0435\u0432\u043e\u0439 \u0434\u0438\u0440\u0435\u043a\u0442\u043e\u0440\u0438\u0438 \u0444\u0430\u0439\u043b <code>.npmrc<\/code> \u0441\u043b\u0435\u0434\u0443\u044e\u0449\u0435\u0433\u043e \u0441\u043e\u0434\u0435\u0440\u0436\u0430\u043d\u0438\u044f:<\/p>\n<p>  <\/p>\n<pre><code class=\"bash\">legacy-peer-deps=true<\/code><\/pre>\n<p>  <\/p>\n<p>\u0421\u043e\u0437\u0434\u0430\u0435\u043c \u0444\u0430\u0439\u043b <code>src\/lib\/Button\/Button.stories.tsx<\/code> \u0441\u043b\u0435\u0434\u0443\u044e\u0449\u0435\u0433\u043e \u0441\u043e\u0434\u0435\u0440\u0436\u0430\u043d\u0438\u044f:<\/p>\n<p>  <\/p>\n<pre><code class=\"javascript\">import { ComponentMeta, ComponentStoryObj } from \"@storybook\/react\"; import Button, { BUTTON_VARIANTS } from \".\/Button\"; \/\/ \u0438\u043c\u043f\u043e\u0440\u0442\u0438\u0440\u0443\u0435\u043c \u0441\u0442\u0438\u043b\u0438 import \"..\/..\/index.css\";  \/\/ \u043e\u043f\u0438\u0441\u0430\u043d\u0438\u0435 \u043a\u043e\u043c\u043f\u043e\u043d\u0435\u043d\u0442\u0430 \u0438 \u0441\u0441\u044b\u043b\u043a\u0430 \u043d\u0430 \u043d\u0435\u0433\u043e const meta: ComponentMeta&lt;typeof Button> = {   title: \"Design System\/Button\",   component: Button, }; export default meta;  \/\/ \u0438\u0441\u0442\u043e\u0440\u0438\u0438 \/\/ \u0434\u0435\u0444\u043e\u043b\u0442\u043d\u0430\u044f \u043a\u043d\u043e\u043f\u043a\u0430 export const Default: ComponentStoryObj&lt;typeof Button> = {   args: {     children: \"primary\",   }, }; \/\/ \u0437\u0430\u0431\u043b\u043e\u043a\u0438\u0440\u043e\u0432\u0430\u043d\u043d\u0430\u044f \u043a\u043d\u043e\u043f\u043a\u0430 export const Disabled: ComponentStoryObj&lt;typeof Button> = {   args: {     children: \"disabled\",     disabled: true,   }, }; \/\/ \u0443\u0441\u043f\u0435\u0445 export const SuccessVariant: ComponentStoryObj&lt;typeof Button> = {   args: {     children: \"success\",     variant: BUTTON_VARIANTS.SUCCESS,   }, }; \/\/ \u043a\u043d\u043e\u043f\u043a\u0430 \u0441 \u043e\u0431\u0440\u0430\u0431\u043e\u0442\u0447\u0438\u043a\u043e\u043c \u043d\u0430\u0436\u0430\u0442\u0438\u044f export const WithClickHandler: ComponentStoryObj&lt;typeof Button> = {   args: {     children: \"click me\",     onClick: () => alert(\"button clicked\"),   }, };<\/code><\/pre>\n<p>  <\/p>\n<p>\u0412\u044b\u043f\u043e\u043b\u043d\u044f\u0435\u043c \u043a\u043e\u043c\u0430\u043d\u0434\u0443 <code>npm run storybook<\/code>:<\/p>\n<p>  <img decoding=\"async\" src=\"https:\/\/habrastorage.org\/r\/w1560\/webt\/lr\/9a\/wr\/lr9awrlxrdjsc4onpwdy3u4f5ic.png\" data-src=\"https:\/\/habrastorage.org\/webt\/lr\/9a\/wr\/lr9awrlxrdjsc4onpwdy3u4f5ic.png\"\/><br \/>  <img decoding=\"async\" src=\"https:\/\/habrastorage.org\/r\/w1560\/webt\/hg\/ro\/6h\/hgro6hwispor6u1cblbkt0ukna0.png\" data-src=\"https:\/\/habrastorage.org\/webt\/hg\/ro\/6h\/hgro6hwispor6u1cblbkt0ukna0.png\"\/><br \/>  <img decoding=\"async\" src=\"https:\/\/habrastorage.org\/r\/w1560\/webt\/ps\/m9\/h8\/psm9h8d1wc2ytelbagrwghkgpfk.png\" data-src=\"https:\/\/habrastorage.org\/webt\/ps\/m9\/h8\/psm9h8d1wc2ytelbagrwghkgpfk.png\"\/><br \/>  <img decoding=\"async\" src=\"https:\/\/habrastorage.org\/r\/w1560\/webt\/6c\/yx\/xs\/6cyxxs80f-9vscup1jczejb1weu.png\" data-src=\"https:\/\/habrastorage.org\/webt\/6c\/yx\/xs\/6cyxxs80f-9vscup1jczejb1weu.png\"\/><\/p>\n<p>\u041f\u043e\u0436\u0430\u043b\u0443\u0439, \u044d\u0442\u043e \u0432\u0441\u0435, \u043e \u0447\u0435\u043c \u044f \u0445\u043e\u0442\u0435\u043b \u0440\u0430\u0441\u0441\u043a\u0430\u0437\u0430\u0442\u044c \u0432 \u044d\u0442\u043e\u0439 \u0441\u0442\u0430\u0442\u044c\u0435.<\/p>\n<p>  <\/p>\n<p>\u041d\u0430\u0434\u0435\u044e\u0441\u044c, \u0432\u044b \u0443\u0437\u043d\u0430\u043b\u0438 \u0447\u0442\u043e-\u0442\u043e \u043d\u043e\u0432\u043e\u0435 \u0438 \u043d\u0435 \u0437\u0440\u044f \u043f\u043e\u0442\u0440\u0430\u0442\u0438\u043b\u0438 \u0432\u0440\u0435\u043c\u044f.<\/p>\n<p>  <\/p>\n<p>\u0411\u043b\u0430\u0433\u043e\u0434\u0430\u0440\u044e \u0437\u0430 \u0432\u043d\u0438\u043c\u0430\u043d\u0438\u0435 \u0438 happy coding!<\/p>\n<p>  <\/p>\n<hr\/>\n<p>  <\/p>\n<p><a href=\"https:\/\/cloud.timeweb.com\/vds-promo-8-rub?utm_source=habr&amp;utm_medium=blog_1560_476&amp;utm_campaign=habr&amp;utm_content=1560_476\"><img decoding=\"async\" src=\"https:\/\/habrastorage.org\/r\/w1560\/webt\/p-\/u9\/l2\/p-u9l27ynelxi92bcmdxhu76ma8.png\" data-src=\"https:\/\/habrastorage.org\/webt\/p-\/u9\/l2\/p-u9l27ynelxi92bcmdxhu76ma8.png\"\/><\/a><\/p>\n<\/div>\n<\/div>\n<\/div>\n<div class=\"v-portal\" style=\"display:none;\"><\/div>\n<\/div>\n<p> <!----> <!----><br \/> \u0441\u0441\u044b\u043b\u043a\u0430 \u043d\u0430 \u043e\u0440\u0438\u0433\u0438\u043d\u0430\u043b \u0441\u0442\u0430\u0442\u044c\u0438 <a href=\"https:\/\/habr.com\/ru\/company\/timeweb\/blog\/691338\/\"> https:\/\/habr.com\/ru\/company\/timeweb\/blog\/691338\/<\/a><\/p>\n","protected":false},"excerpt":{"rendered":"<div><\/div>\n<div id=\"post-content-body\">\n<div>\n<div class=\"article-formatted-body article-formatted-body article-formatted-body_version-1\">\n<div xmlns=\"http:\/\/www.w3.org\/1999\/xhtml\"><img decoding=\"async\" src=\"https:\/\/habrastorage.org\/r\/w780q1\/webt\/ma\/po\/lv\/mapolvqq4uunxfqoaviv3g9km9y.jpeg\" data-src=\"https:\/\/habrastorage.org\/webt\/ma\/po\/lv\/mapolvqq4uunxfqoaviv3g9km9y.jpeg\" data-blurred=\"true\"\/>  <\/p>\n<p>  \u041f\u0440\u0438\u0432\u0435\u0442, \u0434\u0440\u0443\u0437\u044c\u044f!<\/p>\n<p>  <\/p>\n<p>\u0412 \u044d\u0442\u043e\u0439 \u0441\u0442\u0430\u0442\u044c\u0435 \u044f \u043f\u043e\u043a\u0430\u0436\u0443 \u0432\u0430\u043c, \u043a\u0430\u043a \u043d\u0430\u0447\u0430\u0442\u044c \u0440\u0430\u0437\u0440\u0430\u0431\u043e\u0442\u043a\u0443 \u0431\u0438\u0431\u043b\u0438\u043e\u0442\u0435\u043a\u0438 \u043a\u043e\u043c\u043f\u043e\u043d\u0435\u043d\u0442\u043e\u0432 \u0441 \u043f\u043e\u043c\u043e\u0449\u044c\u044e <a href=\"https:\/\/vitejs.dev\/\">Vite<\/a>, <a href=\"https:\/\/ru.reactjs.org\/\">React<\/a>, <a href=\"https:\/\/www.typescriptlang.org\/\">TypeScript<\/a> \u0438 <a href=\"https:\/\/storybook.js.org\/\">Storybook<\/a>.<\/p>\n<p>  <\/p>\n<p>\u041c\u044b \u0440\u0430\u0437\u0440\u0430\u0431\u043e\u0442\u0430\u0435\u043c \u0431\u0438\u0431\u043b\u0438\u043e\u0442\u0435\u043a\u0443, \u0441\u043e\u0441\u0442\u043e\u044f\u0449\u0443\u044e \u0438\u0437 \u043e\u0434\u043d\u043e\u0433\u043e \u043f\u0440\u043e\u0441\u0442\u043e\u0433\u043e \u043a\u043e\u043c\u043f\u043e\u043d\u0435\u043d\u0442\u0430 \u2014 \u043a\u043d\u043e\u043f\u043a\u0438, \u043f\u043e\u0434\u0433\u043e\u0442\u043e\u0432\u0438\u043c \u0431\u0438\u0431\u043b\u0438\u043e\u0442\u0435\u043a\u0443 \u043a \u043f\u0443\u0431\u043b\u0438\u043a\u0430\u0446\u0438\u0438 \u0432 \u0440\u0435\u0435\u0441\u0442\u0440\u0435 <a href=\"https:\/\/www.npmjs.com\/\">npm<\/a>, \u0430 \u0442\u0430\u043a\u0436\u0435 \u0441\u0433\u0435\u043d\u0435\u0440\u0438\u0440\u0443\u0435\u043c \u0438 \u0432\u0438\u0437\u0443\u0430\u043b\u0438\u0437\u0438\u0440\u0443\u0435\u043c \u0434\u043e\u043a\u0443\u043c\u0435\u043d\u0442\u0430\u0446\u0438\u044e \u0434\u043b\u044f \u043a\u043d\u043e\u043f\u043a\u0438.<\/p>\n<p>  <\/p>\n<p><a href=\"https:\/\/github.com\/harryheman\/Blog-Posts\/tree\/master\/react-ts-lib\">\u0420\u0435\u043f\u043e\u0437\u0438\u0442\u043e\u0440\u0438\u0439 \u0441 \u043a\u043e\u0434\u043e\u043c \u043f\u0440\u043e\u0435\u043a\u0442\u0430<\/a>.<\/p>\n<p>  <\/p>\n<p>\u0415\u0441\u043b\u0438 \u0432\u0430\u043c \u044d\u0442\u043e \u0438\u043d\u0442\u0435\u0440\u0435\u0441\u043d\u043e, \u043f\u0440\u043e\u0448\u0443 \u043f\u043e\u0434 \u043a\u0430\u0442.<\/p>\n","protected":false},"author":1,"featured_media":0,"comment_status":"open","ping_status":"open","sticky":false,"template":"","format":"standard","meta":{"footnotes":""},"categories":[],"tags":[],"class_list":["post-339286","post","type-post","status-publish","format-standard","hentry"],"_links":{"self":[{"href":"https:\/\/savepearlharbor.com\/index.php?rest_route=\/wp\/v2\/posts\/339286","targetHints":{"allow":["GET"]}}],"collection":[{"href":"https:\/\/savepearlharbor.com\/index.php?rest_route=\/wp\/v2\/posts"}],"about":[{"href":"https:\/\/savepearlharbor.com\/index.php?rest_route=\/wp\/v2\/types\/post"}],"author":[{"embeddable":true,"href":"https:\/\/savepearlharbor.com\/index.php?rest_route=\/wp\/v2\/users\/1"}],"replies":[{"embeddable":true,"href":"https:\/\/savepearlharbor.com\/index.php?rest_route=%2Fwp%2Fv2%2Fcomments&post=339286"}],"version-history":[{"count":0,"href":"https:\/\/savepearlharbor.com\/index.php?rest_route=\/wp\/v2\/posts\/339286\/revisions"}],"wp:attachment":[{"href":"https:\/\/savepearlharbor.com\/index.php?rest_route=%2Fwp%2Fv2%2Fmedia&parent=339286"}],"wp:term":[{"taxonomy":"category","embeddable":true,"href":"https:\/\/savepearlharbor.com\/index.php?rest_route=%2Fwp%2Fv2%2Fcategories&post=339286"},{"taxonomy":"post_tag","embeddable":true,"href":"https:\/\/savepearlharbor.com\/index.php?rest_route=%2Fwp%2Fv2%2Ftags&post=339286"}],"curies":[{"name":"wp","href":"https:\/\/api.w.org\/{rel}","templated":true}]}}