@techv/design-system 0.1.1 → 0.1.3
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 +416 -0
- package/package.json +5 -4
package/README.md
ADDED
|
@@ -0,0 +1,416 @@
|
|
|
1
|
+
# @techv/design-system
|
|
2
|
+
|
|
3
|
+
A React component library and design token system. Single package — install once and get both UI components and design tokens.
|
|
4
|
+
|
|
5
|
+
## Requirements
|
|
6
|
+
|
|
7
|
+
| Peer dependency | Version |
|
|
8
|
+
|---|---|
|
|
9
|
+
| react | ^18.0.0 |
|
|
10
|
+
| react-dom | ^18.0.0 |
|
|
11
|
+
| styled-components | ^6.1.0 |
|
|
12
|
+
|
|
13
|
+
## Installation
|
|
14
|
+
|
|
15
|
+
```bash
|
|
16
|
+
npm install @techv/design-system styled-components
|
|
17
|
+
```
|
|
18
|
+
```bash
|
|
19
|
+
yarn add @techv/design-system styled-components
|
|
20
|
+
```
|
|
21
|
+
```bash
|
|
22
|
+
pnpm add @techv/design-system styled-components
|
|
23
|
+
```
|
|
24
|
+
|
|
25
|
+
## Setup
|
|
26
|
+
|
|
27
|
+
Import the global CSS in your app entry point. This loads the CSS custom properties (design tokens) and dark mode support.
|
|
28
|
+
|
|
29
|
+
```tsx
|
|
30
|
+
// index.tsx or App.tsx
|
|
31
|
+
import '@techv/design-system/styles.css';
|
|
32
|
+
```
|
|
33
|
+
|
|
34
|
+
---
|
|
35
|
+
|
|
36
|
+
## Components
|
|
37
|
+
|
|
38
|
+
### Button
|
|
39
|
+
|
|
40
|
+
```tsx
|
|
41
|
+
import { Button } from '@techv/design-system';
|
|
42
|
+
|
|
43
|
+
export default function App() {
|
|
44
|
+
return <Button>Click me</Button>;
|
|
45
|
+
}
|
|
46
|
+
```
|
|
47
|
+
|
|
48
|
+
#### Props
|
|
49
|
+
|
|
50
|
+
| Prop | Type | Default | Description |
|
|
51
|
+
|---|---|---|---|
|
|
52
|
+
| `variant` | `solid` \| `outline` \| `ghost` \| `soft` \| `link` | `solid` | Visual style |
|
|
53
|
+
| `color` | `brand` \| `danger` \| `success` \| `warning` \| `neutral` | `brand` | Color scheme |
|
|
54
|
+
| `size` | `xs` \| `sm` \| `md` \| `lg` \| `xl` | `md` | Button size |
|
|
55
|
+
| `isLoading` | `boolean` | `false` | Shows a spinner and disables the button |
|
|
56
|
+
| `leftIcon` | `ReactNode` | — | Icon rendered before the label |
|
|
57
|
+
| `rightIcon` | `ReactNode` | — | Icon rendered after the label |
|
|
58
|
+
| `disabled` | `boolean` | `false` | Disables the button |
|
|
59
|
+
|
|
60
|
+
Accepts all standard HTML `<button>` attributes.
|
|
61
|
+
|
|
62
|
+
#### Variants
|
|
63
|
+
|
|
64
|
+
```tsx
|
|
65
|
+
<Button variant="solid">Solid</Button>
|
|
66
|
+
<Button variant="outline">Outline</Button>
|
|
67
|
+
<Button variant="ghost">Ghost</Button>
|
|
68
|
+
<Button variant="soft">Soft</Button>
|
|
69
|
+
<Button variant="link">Link</Button>
|
|
70
|
+
```
|
|
71
|
+
|
|
72
|
+
#### Colors
|
|
73
|
+
|
|
74
|
+
```tsx
|
|
75
|
+
<Button color="brand">Brand</Button>
|
|
76
|
+
<Button color="danger">Danger</Button>
|
|
77
|
+
<Button color="success">Success</Button>
|
|
78
|
+
<Button color="warning">Warning</Button>
|
|
79
|
+
<Button color="neutral">Neutral</Button>
|
|
80
|
+
```
|
|
81
|
+
|
|
82
|
+
#### Sizes
|
|
83
|
+
|
|
84
|
+
```tsx
|
|
85
|
+
<Button size="xs">Extra Small</Button>
|
|
86
|
+
<Button size="sm">Small</Button>
|
|
87
|
+
<Button size="md">Medium</Button>
|
|
88
|
+
<Button size="lg">Large</Button>
|
|
89
|
+
<Button size="xl">Extra Large</Button>
|
|
90
|
+
```
|
|
91
|
+
|
|
92
|
+
#### With icons
|
|
93
|
+
|
|
94
|
+
```tsx
|
|
95
|
+
<Button leftIcon={<SearchIcon />}>Search</Button>
|
|
96
|
+
<Button rightIcon={<ArrowRightIcon />}>Next</Button>
|
|
97
|
+
```
|
|
98
|
+
|
|
99
|
+
#### Loading state
|
|
100
|
+
|
|
101
|
+
```tsx
|
|
102
|
+
<Button isLoading>Saving...</Button>
|
|
103
|
+
```
|
|
104
|
+
|
|
105
|
+
---
|
|
106
|
+
|
|
107
|
+
### IconButton
|
|
108
|
+
|
|
109
|
+
A square button that holds a single icon. Requires `aria-label` for accessibility.
|
|
110
|
+
|
|
111
|
+
```tsx
|
|
112
|
+
import { IconButton } from '@techv/design-system';
|
|
113
|
+
|
|
114
|
+
<IconButton icon={<SearchIcon />} aria-label="Search" />
|
|
115
|
+
```
|
|
116
|
+
|
|
117
|
+
#### Props
|
|
118
|
+
|
|
119
|
+
| Prop | Type | Default | Description |
|
|
120
|
+
|---|---|---|---|
|
|
121
|
+
| `icon` | `ReactNode` | **required** | The icon to display |
|
|
122
|
+
| `aria-label` | `string` | **required** | Accessible label |
|
|
123
|
+
| `variant` | `solid` \| `outline` \| `ghost` \| `soft` \| `link` | `solid` | Visual style |
|
|
124
|
+
| `color` | `brand` \| `danger` \| `success` \| `warning` \| `neutral` | `brand` | Color scheme |
|
|
125
|
+
| `size` | `xs` \| `sm` \| `md` \| `lg` \| `xl` | `md` | Button size |
|
|
126
|
+
| `isLoading` | `boolean` | `false` | Shows a spinner |
|
|
127
|
+
| `disabled` | `boolean` | `false` | Disables the button |
|
|
128
|
+
|
|
129
|
+
---
|
|
130
|
+
|
|
131
|
+
## Design Tokens
|
|
132
|
+
|
|
133
|
+
### CSS Custom Properties
|
|
134
|
+
|
|
135
|
+
Import `styles.css` to get all tokens as CSS variables on `:root`, usable anywhere in your app.
|
|
136
|
+
|
|
137
|
+
```css
|
|
138
|
+
.my-component {
|
|
139
|
+
background-color: var(--color-brand-500);
|
|
140
|
+
padding: var(--space-md);
|
|
141
|
+
border-radius: var(--radius-lg);
|
|
142
|
+
}
|
|
143
|
+
```
|
|
144
|
+
|
|
145
|
+
### JavaScript Tokens
|
|
146
|
+
|
|
147
|
+
#### Inline styles
|
|
148
|
+
|
|
149
|
+
Use tokens directly in React `style` props:
|
|
150
|
+
|
|
151
|
+
```tsx
|
|
152
|
+
import { tokens, colors, spacing, radii } from '@techv/design-system';
|
|
153
|
+
|
|
154
|
+
function Badge({ children }: { children: React.ReactNode }) {
|
|
155
|
+
return (
|
|
156
|
+
<span
|
|
157
|
+
style={{
|
|
158
|
+
backgroundColor: tokens.color.brand[50], // '#EEF2FF'
|
|
159
|
+
color: tokens.color.brand[700], // '#3730A3'
|
|
160
|
+
padding: `${tokens.space.xs}px ${tokens.space.sm}px`, // '4px 8px'
|
|
161
|
+
borderRadius: tokens.radius.full, // 9999
|
|
162
|
+
fontSize: tokens.fontSize.caption, // '12px'
|
|
163
|
+
fontFamily: tokens.font.text, // 'Inter'
|
|
164
|
+
}}
|
|
165
|
+
>
|
|
166
|
+
{children}
|
|
167
|
+
</span>
|
|
168
|
+
);
|
|
169
|
+
}
|
|
170
|
+
```
|
|
171
|
+
|
|
172
|
+
#### Alert / status banner
|
|
173
|
+
|
|
174
|
+
```tsx
|
|
175
|
+
import { tokens, colors } from '@techv/design-system';
|
|
176
|
+
|
|
177
|
+
type AlertType = 'success' | 'danger' | 'warning';
|
|
178
|
+
|
|
179
|
+
const alertStyles: Record<AlertType, React.CSSProperties> = {
|
|
180
|
+
success: {
|
|
181
|
+
backgroundColor: tokens.color.success[50], // '#ECFDF5'
|
|
182
|
+
color: tokens.color.success[500], // '#10B981'
|
|
183
|
+
border: `1px solid ${tokens.color.success[500]}`,
|
|
184
|
+
},
|
|
185
|
+
danger: {
|
|
186
|
+
backgroundColor: tokens.color.danger[50], // '#FEF2F2'
|
|
187
|
+
color: tokens.color.danger[500], // '#EF4444'
|
|
188
|
+
border: `1px solid ${tokens.color.danger[500]}`,
|
|
189
|
+
},
|
|
190
|
+
warning: {
|
|
191
|
+
backgroundColor: tokens.color.warning[50], // '#FFFBEB'
|
|
192
|
+
color: tokens.color.warning[500], // '#F59E0B'
|
|
193
|
+
border: `1px solid ${tokens.color.warning[500]}`,
|
|
194
|
+
},
|
|
195
|
+
};
|
|
196
|
+
|
|
197
|
+
function Alert({ type, message }: { type: AlertType; message: string }) {
|
|
198
|
+
return (
|
|
199
|
+
<div
|
|
200
|
+
role="alert"
|
|
201
|
+
style={{
|
|
202
|
+
...alertStyles[type],
|
|
203
|
+
padding: `${tokens.space.sm}px ${tokens.space.md}px`, // '8px 16px'
|
|
204
|
+
borderRadius: tokens.radius.md, // 6
|
|
205
|
+
fontSize: tokens.fontSize.bodyMd, // '14px'
|
|
206
|
+
}}
|
|
207
|
+
>
|
|
208
|
+
{message}
|
|
209
|
+
</div>
|
|
210
|
+
);
|
|
211
|
+
}
|
|
212
|
+
|
|
213
|
+
// Usage
|
|
214
|
+
<Alert type="success" message="Profile saved!" />
|
|
215
|
+
<Alert type="danger" message="Something went wrong." />
|
|
216
|
+
<Alert type="warning" message="Your session expires soon." />
|
|
217
|
+
```
|
|
218
|
+
|
|
219
|
+
#### Card component
|
|
220
|
+
|
|
221
|
+
```tsx
|
|
222
|
+
import { tokens } from '@techv/design-system';
|
|
223
|
+
|
|
224
|
+
function Card({ title, body }: { title: string; body: string }) {
|
|
225
|
+
return (
|
|
226
|
+
<div
|
|
227
|
+
style={{
|
|
228
|
+
backgroundColor: tokens.semantic.surface, // '#FFFFFF'
|
|
229
|
+
border: `1px solid ${tokens.semantic.border}`, // '#E5E7EB'
|
|
230
|
+
borderRadius: tokens.radius['2xl'], // 16
|
|
231
|
+
padding: tokens.space.xl, // 32
|
|
232
|
+
boxShadow: tokens.shadow.md,
|
|
233
|
+
maxWidth: '400px',
|
|
234
|
+
}}
|
|
235
|
+
>
|
|
236
|
+
<h2
|
|
237
|
+
style={{
|
|
238
|
+
margin: 0,
|
|
239
|
+
fontSize: tokens.fontSize.h4, // '18px'
|
|
240
|
+
color: tokens.semantic.textPrimary, // '#111827'
|
|
241
|
+
marginBottom: tokens.space.sm, // 8
|
|
242
|
+
}}
|
|
243
|
+
>
|
|
244
|
+
{title}
|
|
245
|
+
</h2>
|
|
246
|
+
<p
|
|
247
|
+
style={{
|
|
248
|
+
margin: 0,
|
|
249
|
+
fontSize: tokens.fontSize.bodyMd, // '14px'
|
|
250
|
+
color: tokens.semantic.textSecondary, // '#6B7280'
|
|
251
|
+
lineHeight: 1.6,
|
|
252
|
+
}}
|
|
253
|
+
>
|
|
254
|
+
{body}
|
|
255
|
+
</p>
|
|
256
|
+
</div>
|
|
257
|
+
);
|
|
258
|
+
}
|
|
259
|
+
```
|
|
260
|
+
|
|
261
|
+
#### Using flat `colors` / `spacing` / `radii` exports
|
|
262
|
+
|
|
263
|
+
```tsx
|
|
264
|
+
import { colors, spacing, radii } from '@techv/design-system';
|
|
265
|
+
|
|
266
|
+
function Tag({ label }: { label: string }) {
|
|
267
|
+
return (
|
|
268
|
+
<span
|
|
269
|
+
style={{
|
|
270
|
+
backgroundColor: colors.gray100, // '#F3F4F6'
|
|
271
|
+
color: colors.gray700, // '#374151'
|
|
272
|
+
padding: `${spacing.xs} ${spacing.sm}`, // '4px 8px'
|
|
273
|
+
borderRadius: radii.sm, // '4px'
|
|
274
|
+
border: `1px solid ${colors.border}`, // '#E5E7EB'
|
|
275
|
+
}}
|
|
276
|
+
>
|
|
277
|
+
{label}
|
|
278
|
+
</span>
|
|
279
|
+
);
|
|
280
|
+
}
|
|
281
|
+
```
|
|
282
|
+
|
|
283
|
+
#### Animated element using duration + easing tokens
|
|
284
|
+
|
|
285
|
+
```tsx
|
|
286
|
+
import { tokens } from '@techv/design-system';
|
|
287
|
+
|
|
288
|
+
function FadeInBox({ children }: { children: React.ReactNode }) {
|
|
289
|
+
return (
|
|
290
|
+
<div
|
|
291
|
+
style={{
|
|
292
|
+
padding: tokens.space.lg, // 24
|
|
293
|
+
backgroundColor: tokens.color.brand[50],
|
|
294
|
+
borderRadius: tokens.radius.xl, // 12
|
|
295
|
+
transition: `opacity ${tokens.duration.normal}ms ${tokens.ease.standard}`,
|
|
296
|
+
// 200ms cubic-bezier(0.4, 0, 0.2, 1)
|
|
297
|
+
}}
|
|
298
|
+
>
|
|
299
|
+
{children}
|
|
300
|
+
</div>
|
|
301
|
+
);
|
|
302
|
+
}
|
|
303
|
+
```
|
|
304
|
+
|
|
305
|
+
#### Quick reference
|
|
306
|
+
|
|
307
|
+
```tsx
|
|
308
|
+
import { tokens, colors, spacing, radii } from '@techv/design-system';
|
|
309
|
+
|
|
310
|
+
// tokens — full structured object
|
|
311
|
+
tokens.color.brand[500] // '#4F46E5'
|
|
312
|
+
tokens.color.gray[200] // '#E5E7EB'
|
|
313
|
+
tokens.space.md // 16 (number, use as px)
|
|
314
|
+
tokens.radius.lg // 8 (number, use as px)
|
|
315
|
+
tokens.shadow.md // '0 4px 6px rgba(0,0,0,0.07)...'
|
|
316
|
+
tokens.duration.normal // 200 (number, ms)
|
|
317
|
+
tokens.ease.standard // 'cubic-bezier(0.4, 0, 0.2, 1)'
|
|
318
|
+
tokens.font.text // 'Inter'
|
|
319
|
+
tokens.fontSize.h1 // '36px'
|
|
320
|
+
tokens.semantic.textPrimary // '#111827'
|
|
321
|
+
|
|
322
|
+
// colors — flat convenience object
|
|
323
|
+
colors.brand500 // '#4F46E5'
|
|
324
|
+
colors.textPrimary // '#111827'
|
|
325
|
+
colors.border // '#E5E7EB'
|
|
326
|
+
|
|
327
|
+
// spacing — string values ready for CSS
|
|
328
|
+
spacing.md // '16px'
|
|
329
|
+
spacing.lg // '24px'
|
|
330
|
+
|
|
331
|
+
// radii — string values ready for CSS
|
|
332
|
+
radii.sm // '4px'
|
|
333
|
+
radii.full // '9999px'
|
|
334
|
+
```
|
|
335
|
+
|
|
336
|
+
### Token Reference
|
|
337
|
+
|
|
338
|
+
#### Colors
|
|
339
|
+
|
|
340
|
+
| Token | Value |
|
|
341
|
+
|---|---|
|
|
342
|
+
| `brand 50–900` | Indigo scale |
|
|
343
|
+
| `success 50, 500` | Green |
|
|
344
|
+
| `danger 50, 500` | Red |
|
|
345
|
+
| `warning 50, 500` | Amber |
|
|
346
|
+
| `info 50, 500` | Blue |
|
|
347
|
+
| `gray 50–900` | Neutral gray scale |
|
|
348
|
+
|
|
349
|
+
#### Spacing
|
|
350
|
+
|
|
351
|
+
| Token | Value |
|
|
352
|
+
|---|---|
|
|
353
|
+
| `2xs` | 2px |
|
|
354
|
+
| `xs` | 4px |
|
|
355
|
+
| `sm` | 8px |
|
|
356
|
+
| `md` | 16px |
|
|
357
|
+
| `lg` | 24px |
|
|
358
|
+
| `xl` | 32px |
|
|
359
|
+
| `2xl` | 48px |
|
|
360
|
+
| `3xl` | 64px |
|
|
361
|
+
|
|
362
|
+
#### Border radius
|
|
363
|
+
|
|
364
|
+
| Token | Value |
|
|
365
|
+
|---|---|
|
|
366
|
+
| `none` | 0 |
|
|
367
|
+
| `xs` | 2px |
|
|
368
|
+
| `sm` | 4px |
|
|
369
|
+
| `md` | 6px |
|
|
370
|
+
| `lg` | 8px |
|
|
371
|
+
| `xl` | 12px |
|
|
372
|
+
| `2xl` | 16px |
|
|
373
|
+
| `full` | 9999px |
|
|
374
|
+
|
|
375
|
+
---
|
|
376
|
+
|
|
377
|
+
## Dark mode
|
|
378
|
+
|
|
379
|
+
The library ships with a built-in dark mode. Toggle it by setting `data-theme="dark"` on any ancestor element (typically `<html>` or `<body>`).
|
|
380
|
+
|
|
381
|
+
```tsx
|
|
382
|
+
// Enable dark mode
|
|
383
|
+
document.documentElement.setAttribute('data-theme', 'dark');
|
|
384
|
+
|
|
385
|
+
// Disable dark mode
|
|
386
|
+
document.documentElement.removeAttribute('data-theme');
|
|
387
|
+
```
|
|
388
|
+
|
|
389
|
+
All components and CSS custom properties respond automatically.
|
|
390
|
+
|
|
391
|
+
---
|
|
392
|
+
|
|
393
|
+
## TypeScript
|
|
394
|
+
|
|
395
|
+
Full TypeScript support is included. All component props and token types are exported.
|
|
396
|
+
|
|
397
|
+
```tsx
|
|
398
|
+
import type { ButtonProps, IconButtonProps } from '@techv/design-system';
|
|
399
|
+
```
|
|
400
|
+
|
|
401
|
+
---
|
|
402
|
+
|
|
403
|
+
## Using tokens in styled-components
|
|
404
|
+
|
|
405
|
+
```tsx
|
|
406
|
+
import styled from 'styled-components';
|
|
407
|
+
import { tokens } from '@techv/design-system';
|
|
408
|
+
|
|
409
|
+
const Card = styled.div`
|
|
410
|
+
background: ${tokens.semantic.surface};
|
|
411
|
+
border: 1px solid ${tokens.semantic.border};
|
|
412
|
+
border-radius: ${tokens.radius.xl}px;
|
|
413
|
+
padding: ${tokens.space.lg}px;
|
|
414
|
+
box-shadow: ${tokens.shadow.md};
|
|
415
|
+
`;
|
|
416
|
+
```
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@techv/design-system",
|
|
3
|
-
"version": "0.1.
|
|
3
|
+
"version": "0.1.3",
|
|
4
4
|
"author": "Pranav V K <pranavvk@techversantinfotech.com>",
|
|
5
5
|
"license": "MIT",
|
|
6
6
|
"main": "./dist/cjs/index.js",
|
|
@@ -20,7 +20,8 @@
|
|
|
20
20
|
"./styles.css": "./dist/styles.css"
|
|
21
21
|
},
|
|
22
22
|
"files": [
|
|
23
|
-
"dist"
|
|
23
|
+
"dist",
|
|
24
|
+
"README.md"
|
|
24
25
|
],
|
|
25
26
|
"sideEffects": [
|
|
26
27
|
"./dist/styles.css"
|
|
@@ -38,8 +39,8 @@
|
|
|
38
39
|
"ts-node": "^10.9.2",
|
|
39
40
|
"tslib": "^2.6.2",
|
|
40
41
|
"typescript": "~5.4.5",
|
|
41
|
-
"@techv/
|
|
42
|
-
"@techv/
|
|
42
|
+
"@techv/ui": "0.1.0",
|
|
43
|
+
"@techv/tokens": "0.1.0"
|
|
43
44
|
},
|
|
44
45
|
"publishConfig": {
|
|
45
46
|
"registry": "https://registry.npmjs.org",
|