@veevarts/design-system 0.0.1 → 0.1.0

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
package/README.md CHANGED
@@ -2,276 +2,70 @@
2
2
 
3
3
  This repository contains our **Design System**: a shared library of reusable UI components, design tokens, and utilities built with **React**, **TypeScript**, **Vite**, and **Storybook**.
4
4
 
5
- The goal of this project is to provide:
5
+ ## Goals
6
6
 
7
7
  - A **single source of truth** for UI across products.
8
8
  - **Reusable, well-typed, accessible components**.
9
9
  - **Discoverable documentation** via Storybook.
10
10
 
11
- ---
12
-
13
11
  ## Tech Stack
14
12
 
15
- - **React + TypeScript** – Component library implementation.
16
- - **Vite** – Fast dev server and build tooling.
17
- - **Storybook** – Component explorer and documentation.
18
- - **ESLint + TypeScript ESLint** – Linting and type-aware rules.
19
- - (Optional) **React Compiler** – Can be enabled if needed (see note below).
20
-
21
- ---
13
+ - React + TypeScript
14
+ - Vite
15
+ - Storybook
16
+ - ESLint + TypeScript ESLint
22
17
 
23
18
  ## Getting Started
24
19
 
25
20
  ### Prerequisites
26
21
 
27
22
  - Node.js (LTS, e.g. 18+ recommended)
28
- - pnpm / npm / yarn (examples below use `npm`)
23
+ - npm / pnpm / yarn
29
24
 
30
- ### Install dependencies
25
+ ### Install
31
26
 
32
27
  ```bash
33
28
  npm install
34
29
  ```
35
30
 
36
- ### Run Storybook (recommended entrypoint)
31
+ ### Run Storybook
32
+
37
33
  ```bash
38
34
  npm run storybook
39
35
  ```
40
36
 
41
- This starts Storybook at http://localhost:6006 (or the configured port), where you can browse and interact with all components.
37
+ ### Run Dev Server
42
38
 
43
- ### Run the Vite dev server (if applicable)
44
-
45
- If this repo also includes a small playground app:
46
39
  ```bash
47
40
  npm run dev
48
41
  ```
49
42
 
50
- This will start the Vite dev server (usually at http://localhost:5173).
51
-
52
43
  ### Build
53
44
 
54
- Build the component library / app:
55
45
  ```bash
56
46
  npm run build
57
47
  ```
58
- Build the Storybook static site (for deployment):
59
- ```bash
60
- npm run build-storybook
61
- ```
62
- npm run build-storybook
63
- ```bash
64
- npm run build-storybook
65
- ```
48
+
66
49
  ### Lint
50
+
67
51
  ```bash
68
52
  npm run lint
69
53
  ```
70
54
 
71
- ## Project Structure (suggested)
55
+ ## Project Structure
72
56
 
73
- Your structure may vary slightly, but the Design System generally follows:
74
57
  ```
75
58
  src/
76
59
  components/
77
- Button/
78
- Button.tsx
79
- Button.types.ts
80
- Button.stories.tsx
81
- Button.test.tsx # if using tests
82
- index.ts
83
- Input/
84
- ...
85
60
  styles/
86
- tokens.css # or tokens.ts, etc.
87
61
  utils/
88
- ...
89
62
  .storybook/
90
- main.ts
91
- preview.tsx
92
63
  ```
93
64
 
94
- ## Creating a New Reusable Component
95
-
96
- When adding a new component to the Design System, follow these steps:
97
- 1. Create a folder under src/components
98
-
99
- Example: src/components/Button.
100
-
101
- 2. Create the component file
102
- - Use TypeScript and function components.
103
- - Export a named component and a typed props interface.
104
-
105
- ```tsx
106
- // src/components/Button/Button.tsx
107
- import type { ButtonHTMLAttributes, ReactNode } from 'react';
108
-
109
- export interface ButtonProps extends ButtonHTMLAttributes<HTMLButtonElement> {
110
- variant?: 'primary' | 'secondary' | 'ghost';
111
- size?: 'sm' | 'md' | 'lg';
112
- isLoading?: boolean;
113
- children: ReactNode;
114
- }
115
-
116
- export function Button({
117
- variant = 'primary',
118
- size = 'md',
119
- isLoading = false,
120
- children,
121
- ...rest
122
- }: ButtonProps) {
123
- return (
124
- <button
125
- data-variant={variant}
126
- data-size={size}
127
- aria-busy={isLoading || undefined}
128
- {...rest}
129
- >
130
- {isLoading ? 'Loading…' : children}
131
- </button>
132
- );
133
- }
134
- ```
135
- 3. Create an index.ts barrel file
136
-
137
- ```tsx
138
- // src/components/Button/index.ts
139
- export * from './Button';
140
- ```
141
- 4. Create the Storybook stories
142
- - Stories should live next to the component: Button.stories.tsx.
143
- - Use Storybook CSF (default export + named stories).
144
- - Document variants, states, and usage guidelines via args and docs.
145
-
146
- ```tsx
147
- // src/components/Button/Button.stories.tsx
148
- import type { Meta, StoryObj } from '@storybook/react';
149
- import { Button } from './Button';
150
-
151
- const meta: Meta<typeof Button> = {
152
- title: 'Components/Button',
153
- component: Button,
154
- args: {
155
- children: 'Click me',
156
- variant: 'primary',
157
- size: 'md',
158
- },
159
- };
160
-
161
- export default meta;
162
- type Story = StoryObj<typeof Button>;
163
-
164
- export const Primary: Story = {};
165
- export const Secondary: Story = {
166
- args: { variant: 'secondary' },
167
- };
168
- export const Loading: Story = {
169
- args: { isLoading: true },
170
- };
171
- ```
172
-
173
- 5. Add tests
174
- - If the project uses a test runner (e.g. Vitest / Jest), add Button.test.tsx with basic behavior and accessibility tests.
175
-
176
- ## Guidelines & Best Practices for Reusable Components
177
-
178
- 1. Design System Principles
179
- - Generic, not app-specific
180
- Components must not depend on product-specific business logic. Keep them generic and configurable via props.
181
- - Composition over configuration
182
- Prefer small building blocks that can be composed, instead of monolithic components with many boolean flags.
183
- - Single responsibility
184
- Each component should do one thing well (e.g. Button, Input, Modal, Tooltip).
185
- - Stable API
186
- Avoid frequent breaking changes to props. If a change is necessary, deprecate carefully and communicate it.
187
-
188
- 2. TypeScript & Props
189
- - Always export a typed props interface (ButtonProps, ModalProps, etc.).
190
- - Follow these patterns:
191
- - Use union types for variants ('primary' | 'secondary').
192
- - Prefer explicit props over any and broad object types.
193
- - Extend native HTML attributes when appropriate (e.g. ButtonHTMLAttributes<HTMLButtonElement>).
194
- - Provide sensible defaults for optional props.
195
-
196
- 3. Styling & Theming
197
- - Use design tokens (colors, spacing, typography) instead of hard-coded values.
198
- - Keep component styling encapsulated and consistent:
199
- - Prefer using a shared tokens/styles system.
200
- - Avoid importing product-specific styles into the Design System.
201
- - Support variants and sizes through props, not through ad-hoc CSS classes.
202
-
203
- 4. Accessibility (a11y)
204
-
205
- Every component should be built with accessibility in mind:
206
- - Ensure correct semantic elements (<button>, <label>, <input> etc.).
207
- - Use ARIA attributes only when necessary and correctly (avoid misusing them).
208
- - Keyboard support:
209
- - Focus states must be visible.
210
- - Interactive elements must be reachable and operable via keyboard.
211
- - Test with screen reader basics when possible (labels, roles, and announcements).
212
-
213
- 5. Storybook Best Practices
214
-
215
- Stories are documentation, not just demos:
216
- - Provide a “Default” story that shows the most common usage.
217
- - Include stories for:
218
- - Different variants and sizes.
219
- - Loading / disabled / error states.
220
- - Edge cases that are relevant for consumers.
221
- - Use args so consumers can experiment via Storybook controls.
222
- - Use Storybook Docs to write short guidelines:
223
- - When to use the component.
224
- - Do’s & Don’ts.
225
- - Example integration snippets.
226
-
227
- 6. Dependencies & Side Effects
228
- - Keep dependencies minimal and generic.
229
- - Avoid:
230
- - Direct calls to APIs.
231
- - Global singletons (e.g. accessing window without guards, global stores).
232
- - Side effects in component bodies (data fetching, logging, etc.).
233
- - If integration with external libraries is needed, wrap them in thin, replaceable adapters.
234
-
235
- ## Linting & Type-Aware Rules
236
-
237
- For production-grade usage, we recommend enabling type-aware ESLint rules. A sample configuration using eslint.config.js might look like this:
65
+ ## Usage Example
238
66
 
239
67
  ```js
240
- // eslint.config.js
241
- import tseslint from 'typescript-eslint';
242
- import reactX from 'eslint-plugin-react-x';
243
- import reactDom from 'eslint-plugin-react-dom';
244
-
245
- export default defineConfig([
246
- globalIgnores(['dist']),
247
- {
248
- files: ['**/*.{ts,tsx}'],
249
- extends: [
250
- // Type-aware TypeScript rules
251
- tseslint.configs.recommendedTypeChecked,
252
- // Alternatively, stricter rules:
253
- // tseslint.configs.strictTypeChecked,
254
- // Optional stylistic rules:
255
- // tseslint.configs.stylisticTypeChecked,
256
-
257
- // React-specific rules
258
- reactX.configs['recommended-typescript'],
259
- reactDom.configs.recommended,
260
- ],
261
- languageOptions: {
262
- parserOptions: {
263
- project: ['./tsconfig.node.json', './tsconfig.app.json'],
264
- tsconfigRootDir: import.meta.dirname,
265
- },
266
- },
267
- },
268
- ]);
68
+ import { Button } from '@veevarts/design-system';
269
69
  ```
270
- Run npm run lint regularly, and ensure no new warnings or errors are introduced in pull requests.
271
70
 
272
- ## Contributing
273
- - Before coding: Check if a similar component already exists or if an existing one can be extended.
274
- - Follow the guidelines above (types, a11y, tokens, stories).
275
- - Add or update stories so that your changes are visible in Storybook.
276
- - Run npm run lint and npm run test (if available) before opening a PR.
277
- - Keep PRs small and focused (one component or one concern per PR where possible).
71
+ For contributing guidelines, see [CONTRIBUTING.md](./CONTRIBUTING.md).
package/dist/index.cjs ADDED
@@ -0,0 +1,6 @@
1
+ "use strict";Object.defineProperty(exports,Symbol.toStringTag,{value:"Module"});const I=require("react");var _={exports:{}},p={};var $;function ne(){if($)return p;$=1;var s=Symbol.for("react.transitional.element"),i=Symbol.for("react.fragment");function u(d,l,c){var m=null;if(c!==void 0&&(m=""+c),l.key!==void 0&&(m=""+l.key),"key"in l){c={};for(var h in l)h!=="key"&&(c[h]=l[h])}else c=l;return l=c.ref,{$$typeof:s,type:d,key:m,ref:l!==void 0?l:null,props:c}}return p.Fragment=i,p.jsx=u,p.jsxs=u,p}var b={};var M;function oe(){return M||(M=1,process.env.NODE_ENV!=="production"&&(function(){function s(e){if(e==null)return null;if(typeof e=="function")return e.$$typeof===ee?null:e.displayName||e.name||null;if(typeof e=="string")return e;switch(e){case x:return"Fragment";case J:return"Profiler";case H:return"StrictMode";case X:return"Suspense";case Z:return"SuspenseList";case K:return"Activity"}if(typeof e=="object")switch(typeof e.tag=="number"&&console.error("Received an unexpected object in getComponentNameFromType(). This is likely a bug in React. Please file an issue."),e.$$typeof){case W:return"Portal";case B:return e.displayName||"Context";case q:return(e._context.displayName||"Context")+".Consumer";case G:var t=e.render;return e=e.displayName,e||(e=t.displayName||t.name||"",e=e!==""?"ForwardRef("+e+")":"ForwardRef"),e;case Q:return t=e.displayName||null,t!==null?t:s(e.type)||"Memo";case E:t=e._payload,e=e._init;try{return s(e(t))}catch{}}return null}function i(e){return""+e}function u(e){try{i(e);var t=!1}catch{t=!0}if(t){t=console;var n=t.error,o=typeof Symbol=="function"&&Symbol.toStringTag&&e[Symbol.toStringTag]||e.constructor.name||"Object";return n.call(t,"The provided key is an unsupported type %s. This value must be coerced to a string before using it here.",o),i(e)}}function d(e){if(e===x)return"<>";if(typeof e=="object"&&e!==null&&e.$$typeof===E)return"<...>";try{var t=s(e);return t?"<"+t+">":"<...>"}catch{return"<...>"}}function l(){var e=R.A;return e===null?null:e.getOwner()}function c(){return Error("react-stack-top-frame")}function m(e){if(P.call(e,"key")){var t=Object.getOwnPropertyDescriptor(e,"key").get;if(t&&t.isReactWarning)return!1}return e.key!==void 0}function h(e,t){function n(){N||(N=!0,console.error("%s: `key` is not a prop. Trying to access it will result in `undefined` being returned. If you need to access the same value within the child component, you should pass it as a different prop. (https://react.dev/link/special-props)",t))}n.isReactWarning=!0,Object.defineProperty(e,"key",{get:n,configurable:!0})}function D(){var e=s(this.type);return C[e]||(C[e]=!0,console.error("Accessing element.ref was removed in React 19. ref is now a regular prop. It will be removed from the JSX Element type in a future release.")),e=this.props.ref,e!==void 0?e:null}function U(e,t,n,o,g,y){var a=n.ref;return e={$$typeof:O,type:e,key:t,props:n,_owner:o},(a!==void 0?a:null)!==null?Object.defineProperty(e,"ref",{enumerable:!1,get:D}):Object.defineProperty(e,"ref",{enumerable:!1,value:null}),e._store={},Object.defineProperty(e._store,"validated",{configurable:!1,enumerable:!1,writable:!0,value:0}),Object.defineProperty(e,"_debugInfo",{configurable:!1,enumerable:!1,writable:!0,value:null}),Object.defineProperty(e,"_debugStack",{configurable:!1,enumerable:!1,writable:!0,value:g}),Object.defineProperty(e,"_debugTask",{configurable:!1,enumerable:!1,writable:!0,value:y}),Object.freeze&&(Object.freeze(e.props),Object.freeze(e)),e}function w(e,t,n,o,g,y){var a=t.children;if(a!==void 0)if(o)if(re(a)){for(o=0;o<a.length;o++)A(a[o]);Object.freeze&&Object.freeze(a)}else console.error("React.jsx: Static children should always be an array. You are likely explicitly calling React.jsxs or React.jsxDEV. Use the Babel transform instead.");else A(a);if(P.call(t,"key")){a=s(e);var f=Object.keys(t).filter(function(te){return te!=="key"});o=0<f.length?"{key: someKey, "+f.join(": ..., ")+": ...}":"{key: someKey}",z[a+o]||(f=0<f.length?"{"+f.join(": ..., ")+": ...}":"{}",console.error(`A props object containing a "key" prop is being spread into JSX:
2
+ let props = %s;
3
+ <%s {...props} />
4
+ React keys must be passed directly to JSX without using spread:
5
+ let props = %s;
6
+ <%s key={someKey} {...props} />`,o,a,f,a),z[a+o]=!0)}if(a=null,n!==void 0&&(u(n),a=""+n),m(t)&&(u(t.key),a=""+t.key),"key"in t){n={};for(var T in t)T!=="key"&&(n[T]=t[T])}else n=t;return a&&h(n,typeof e=="function"?e.displayName||e.name||"Unknown":e),U(e,a,n,l(),g,y)}function A(e){S(e)?e._store&&(e._store.validated=1):typeof e=="object"&&e!==null&&e.$$typeof===E&&(e._payload.status==="fulfilled"?S(e._payload.value)&&e._payload.value._store&&(e._payload.value._store.validated=1):e._store&&(e._store.validated=1))}function S(e){return typeof e=="object"&&e!==null&&e.$$typeof===O}var v=I,O=Symbol.for("react.transitional.element"),W=Symbol.for("react.portal"),x=Symbol.for("react.fragment"),H=Symbol.for("react.strict_mode"),J=Symbol.for("react.profiler"),q=Symbol.for("react.consumer"),B=Symbol.for("react.context"),G=Symbol.for("react.forward_ref"),X=Symbol.for("react.suspense"),Z=Symbol.for("react.suspense_list"),Q=Symbol.for("react.memo"),E=Symbol.for("react.lazy"),K=Symbol.for("react.activity"),ee=Symbol.for("react.client.reference"),R=v.__CLIENT_INTERNALS_DO_NOT_USE_OR_WARN_USERS_THEY_CANNOT_UPGRADE,P=Object.prototype.hasOwnProperty,re=Array.isArray,k=console.createTask?console.createTask:function(){return null};v={react_stack_bottom_frame:function(e){return e()}};var N,C={},Y=v.react_stack_bottom_frame.bind(v,c)(),F=k(d(c)),z={};b.Fragment=x,b.jsx=function(e,t,n){var o=1e4>R.recentlyCreatedOwnerStacks++;return w(e,t,n,!1,o?Error("react-stack-top-frame"):Y,o?k(d(e)):F)},b.jsxs=function(e,t,n){var o=1e4>R.recentlyCreatedOwnerStacks++;return w(e,t,n,!0,o?Error("react-stack-top-frame"):Y,o?k(d(e)):F)}})()),b}var V;function ae(){return V||(V=1,process.env.NODE_ENV==="production"?_.exports=ne():_.exports=oe()),_.exports}var r=ae();const j=({primary:s=!1,size:i="medium",backgroundColor:u,label:d,...l})=>{const c=s?"storybook-button--primary":"storybook-button--secondary";return r.jsx("button",{type:"button",className:["storybook-button",`storybook-button--${i}`,c].join(" "),style:{backgroundColor:u},...l,children:d})},L=({user:s,onLogin:i,onLogout:u,onCreateAccount:d})=>r.jsx("header",{children:r.jsxs("div",{className:"storybook-header",children:[r.jsxs("div",{children:[r.jsx("svg",{width:"32",height:"32",viewBox:"0 0 32 32",xmlns:"http://www.w3.org/2000/svg",children:r.jsxs("g",{fill:"none",fillRule:"evenodd",children:[r.jsx("path",{d:"M10 0h12a10 10 0 0110 10v12a10 10 0 01-10 10H10A10 10 0 010 22V10A10 10 0 0110 0z",fill:"#FFF"}),r.jsx("path",{d:"M5.3 10.6l10.4 6v11.1l-10.4-6v-11zm11.4-6.2l9.7 5.5-9.7 5.6V4.4z",fill:"#555AB9"}),r.jsx("path",{d:"M27.2 10.6v11.2l-10.5 6V16.5l10.5-6zM15.7 4.4v11L6 10l9.7-5.5z",fill:"#91BAF8"})]})}),r.jsx("h1",{children:"Acme"})]}),r.jsx("div",{children:s?r.jsxs(r.Fragment,{children:[r.jsxs("span",{className:"welcome",children:["Welcome, ",r.jsx("b",{children:s.name}),"!"]}),r.jsx(j,{size:"small",onClick:u,label:"Log out"})]}):r.jsxs(r.Fragment,{children:[r.jsx(j,{size:"small",onClick:i,label:"Log in"}),r.jsx(j,{primary:!0,size:"small",onClick:d,label:"Sign up"})]})})]})}),se=()=>{const[s,i]=I.useState();return r.jsxs("article",{children:[r.jsx(L,{user:s,onLogin:()=>i({name:"Jane Doe"}),onLogout:()=>i(void 0),onCreateAccount:()=>i({name:"Jane Doe"})}),r.jsxs("section",{className:"storybook-page",children:[r.jsx("h2",{children:"Pages in Storybook"}),r.jsxs("p",{children:["We recommend building UIs with a"," ",r.jsx("a",{href:"https://componentdriven.org",target:"_blank",rel:"noopener noreferrer",children:r.jsx("strong",{children:"component-driven"})})," ","process starting with atomic components and ending with pages."]}),r.jsx("p",{children:"Render pages with mock data. This makes it easy to build and review page states without needing to navigate to them in your app. Here are some handy patterns for managing page data in Storybook:"}),r.jsxs("ul",{children:[r.jsx("li",{children:'Use a higher-level connected component. Storybook helps you compose such data from the "args" of child component stories'}),r.jsx("li",{children:"Assemble data in the page component from your services. You can mock these services out using Storybook."})]}),r.jsxs("p",{children:["Get a guided tutorial on component-driven development at"," ",r.jsx("a",{href:"https://storybook.js.org/tutorials/",target:"_blank",rel:"noopener noreferrer",children:"Storybook tutorials"}),". Read more in the"," ",r.jsx("a",{href:"https://storybook.js.org/docs",target:"_blank",rel:"noopener noreferrer",children:"docs"}),"."]}),r.jsxs("div",{className:"tip-wrapper",children:[r.jsx("span",{className:"tip",children:"Tip"})," Adjust the width of the canvas with the"," ",r.jsx("svg",{width:"10",height:"10",viewBox:"0 0 12 12",xmlns:"http://www.w3.org/2000/svg",children:r.jsx("g",{fill:"none",fillRule:"evenodd",children:r.jsx("path",{d:"M1.5 5.2h4.8c.3 0 .5.2.5.4v5.1c-.1.2-.3.3-.4.3H1.4a.5.5 0 01-.5-.4V5.7c0-.3.2-.5.5-.5zm0-2.1h6.9c.3 0 .5.2.5.4v7a.5.5 0 01-1 0V4H1.5a.5.5 0 010-1zm0-2.1h9c.3 0 .5.2.5.4v9.1a.5.5 0 01-1 0V2H1.5a.5.5 0 010-1zm4.3 5.2H2V10h3.8V6.2z",id:"a",fill:"#999"})})}),"Viewports addon in the toolbar"]})]})]})};exports.Button=j;exports.Header=L;exports.Page=se;
package/dist/index.css ADDED
@@ -0,0 +1 @@
1
+ .storybook-button{display:inline-block;cursor:pointer;border:0;border-radius:3em;font-weight:700;line-height:1;font-family:Nunito Sans,Helvetica Neue,Helvetica,Arial,sans-serif}.storybook-button--primary{background-color:#555ab9;color:#fff}.storybook-button--secondary{box-shadow:#00000026 0 0 0 1px inset;background-color:transparent;color:#333}.storybook-button--small{padding:10px 16px;font-size:12px}.storybook-button--medium{padding:11px 20px;font-size:14px}.storybook-button--large{padding:12px 24px;font-size:16px}.storybook-header{display:flex;justify-content:space-between;align-items:center;border-bottom:1px solid rgba(0,0,0,.1);padding:15px 20px;font-family:Nunito Sans,Helvetica Neue,Helvetica,Arial,sans-serif}.storybook-header svg{display:inline-block;vertical-align:top}.storybook-header h1{display:inline-block;vertical-align:top;margin:6px 0 6px 10px;font-weight:700;font-size:20px;line-height:1}.storybook-header button+button{margin-left:10px}.storybook-header .welcome{margin-right:10px;color:#333;font-size:14px}.storybook-page{margin:0 auto;padding:48px 20px;max-width:600px;color:#333;font-size:14px;line-height:24px;font-family:Nunito Sans,Helvetica Neue,Helvetica,Arial,sans-serif}.storybook-page h2{display:inline-block;vertical-align:top;margin:0 0 4px;font-weight:700;font-size:32px;line-height:1}.storybook-page p{margin:1em 0}.storybook-page a{color:inherit}.storybook-page ul{margin:1em 0;padding-left:30px}.storybook-page li{margin-bottom:8px}.storybook-page .tip{display:inline-block;vertical-align:top;margin-right:10px;border-radius:1em;background:#e7fdd8;padding:4px 12px;color:#357a14;font-weight:700;font-size:11px;line-height:12px}.storybook-page .tip-wrapper{margin-top:40px;margin-bottom:40px;font-size:13px;line-height:20px}.storybook-page .tip-wrapper svg{display:inline-block;vertical-align:top;margin-top:3px;margin-right:4px;width:12px;height:12px}.storybook-page .tip-wrapper svg path{fill:#1ea7fd}