@umituz/web-design-system 3.1.21 → 4.0.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 +137 -469
- package/dist/styles.css +2 -0
- package/package.json +30 -31
- package/src/__tests__/cn.test.ts +24 -0
- package/src/__tests__/components.smoke.test.tsx +78 -0
- package/src/__tests__/styles.contract.test.ts +60 -0
- package/src/domain/tokens/index.ts +8 -49
- package/src/index.ts +8 -10
- package/src/infrastructure/constants/component.constants.ts +3 -17
- package/src/infrastructure/constants/index.ts +4 -2
- package/src/infrastructure/constants/timing.constants.ts +46 -0
- package/src/infrastructure/utils/calculation.utils.ts +74 -0
- package/src/infrastructure/utils/index.ts +12 -0
- package/src/presentation/atoms/IconButton.tsx +55 -0
- package/src/presentation/atoms/Progress.tsx +2 -1
- package/src/presentation/atoms/Spinner.tsx +1 -1
- package/src/presentation/atoms/Switch.tsx +2 -2
- package/src/presentation/atoms/Text.tsx +15 -13
- package/src/presentation/atoms/Tooltip.tsx +2 -1
- package/src/presentation/atoms/index.ts +3 -0
- package/src/presentation/hooks/index.ts +0 -3
- package/src/presentation/hooks/useClickOutside.ts +14 -10
- package/src/presentation/hooks/useClipboard.ts +30 -12
- package/src/presentation/hooks/useDebounce.ts +8 -10
- package/src/presentation/hooks/useLocalStorage.ts +28 -18
- package/src/presentation/hooks/useMediaQuery.ts +2 -1
- package/src/presentation/hooks/useScrollLock.ts +40 -12
- package/src/presentation/hooks/useToggle.ts +8 -6
- package/src/presentation/molecules/ActiveFilterTags.tsx +19 -18
- package/src/presentation/molecules/Avatar.tsx +1 -1
- package/src/presentation/molecules/CodeBlock.tsx +51 -48
- package/src/presentation/molecules/ListItem.tsx +40 -29
- package/src/presentation/molecules/Select.tsx +1 -1
- package/src/presentation/molecules/Toggle.tsx +4 -4
- package/src/presentation/molecules/index.ts +0 -3
- package/src/presentation/organisms/Alert.tsx +1 -1
- package/src/presentation/organisms/DataTable.tsx +24 -11
- package/src/presentation/organisms/Dialog.tsx +1 -1
- package/src/presentation/organisms/DropdownMenu.tsx +2 -2
- package/src/presentation/organisms/HoverCard.tsx +1 -1
- package/src/presentation/organisms/LoadingState.tsx +1 -5
- package/src/presentation/organisms/Popover.tsx +1 -1
- package/src/presentation/organisms/StatCard.tsx +2 -2
- package/src/presentation/organisms/Table.tsx +2 -2
- package/src/presentation/organisms/index.ts +0 -60
- package/src/styles/compile.css +18 -0
- package/src/styles/theme.css +131 -0
- package/src/domain/tokens/animation.tokens.ts +0 -87
- package/src/domain/tokens/color.tokens.ts +0 -95
- package/src/domain/tokens/radius.tokens.ts +0 -27
- package/src/domain/tokens/shadow.tokens.ts +0 -25
- package/src/domain/tokens/spacing.tokens.ts +0 -65
- package/src/domain/tokens/typography.tokens.ts +0 -74
- package/src/infrastructure/error/ErrorBoundary.tsx +0 -258
- package/src/infrastructure/error/ErrorDisplay.tsx +0 -346
- package/src/infrastructure/error/SuspenseWrapper.tsx +0 -133
- package/src/infrastructure/error/index.ts +0 -5
- package/src/infrastructure/performance/index.ts +0 -92
- package/src/infrastructure/performance/useLazyLoading.ts +0 -342
- package/src/infrastructure/performance/useMemoryOptimization.ts +0 -293
- package/src/infrastructure/performance/usePerformanceMonitor.ts +0 -158
- package/src/infrastructure/security/index.ts +0 -10
- package/src/infrastructure/security/security-config.ts +0 -171
- package/src/infrastructure/security/useFormValidation.ts +0 -216
- package/src/infrastructure/security/validation.ts +0 -246
- package/src/presentation/hooks/useLanguage.ts +0 -109
- package/src/presentation/molecules/Breadcrumb.tsx +0 -54
- package/src/presentation/organisms/AlertDialog.tsx +0 -181
- package/src/presentation/organisms/Calendar.tsx +0 -79
- package/src/presentation/organisms/Comments.tsx +0 -103
- package/src/presentation/organisms/ConfirmDialog.tsx +0 -97
- package/src/presentation/organisms/FilterBar.tsx +0 -244
- package/src/presentation/organisms/FilterSidebar.tsx +0 -172
- package/src/presentation/organisms/Footer.tsx +0 -86
- package/src/presentation/organisms/FormModal.tsx +0 -126
- package/src/presentation/organisms/Grid.tsx +0 -128
- package/src/presentation/organisms/ImageLightbox.tsx +0 -252
- package/src/presentation/organisms/MainNavbar.tsx +0 -320
- package/src/presentation/organisms/Modal.tsx +0 -173
- package/src/presentation/organisms/Navbar.tsx +0 -75
- package/src/presentation/organisms/NewsletterSignup.tsx +0 -165
- package/src/presentation/organisms/QuickActionCard.tsx +0 -93
package/README.md
CHANGED
|
@@ -1,503 +1,171 @@
|
|
|
1
1
|
# @umituz/web-design-system
|
|
2
2
|
|
|
3
|
-
|
|
3
|
+
Atomic Design component library for React: atoms, molecules, overlay/data
|
|
4
|
+
organisms, templates and hooks. **Authored in Tailwind v4, shipped as both
|
|
5
|
+
source and a precompiled stylesheet** — it works in any React host, with or
|
|
6
|
+
without Tailwind.
|
|
4
7
|
|
|
5
|
-
|
|
8
|
+
The package is **source-distributed** (raw TypeScript in `src/`); your
|
|
9
|
+
bundler compiles the components. Styling is available two ways:
|
|
6
10
|
|
|
7
|
-
|
|
8
|
-
|
|
9
|
-
|
|
10
|
-
|
|
11
|
-
# or
|
|
12
|
-
pnpm add @umituz/web-design-system
|
|
13
|
-
```
|
|
14
|
-
|
|
15
|
-
## 🚀 Quick Start
|
|
16
|
-
|
|
17
|
-
```tsx
|
|
18
|
-
// ✅ Use subpath imports (RECOMMENDED)
|
|
19
|
-
import { Button } from '@umituz/web-design-system/atoms';
|
|
20
|
-
import { Card } from '@umituz/web-design-system/organisms';
|
|
21
|
-
|
|
22
|
-
function App() {
|
|
23
|
-
return (
|
|
24
|
-
<Card>
|
|
25
|
-
<Button variant="primary">Click me</Button>
|
|
26
|
-
</Card>
|
|
27
|
-
);
|
|
28
|
-
}
|
|
29
|
-
```
|
|
30
|
-
|
|
31
|
-
## 📚 Available Subpaths
|
|
32
|
-
|
|
33
|
-
### Atoms (Smallest UI Elements)
|
|
34
|
-
```tsx
|
|
35
|
-
import {
|
|
36
|
-
Button,
|
|
37
|
-
Badge,
|
|
38
|
-
Input,
|
|
39
|
-
Text,
|
|
40
|
-
Icon,
|
|
41
|
-
Spinner
|
|
42
|
-
} from '@umituz/web-design-system/atoms';
|
|
43
|
-
```
|
|
44
|
-
|
|
45
|
-
### Molecules (Simple Combinations)
|
|
46
|
-
```tsx
|
|
47
|
-
import {
|
|
48
|
-
FormField,
|
|
49
|
-
SearchBox,
|
|
50
|
-
Avatar,
|
|
51
|
-
Chip,
|
|
52
|
-
Toggle
|
|
53
|
-
} from '@umituz/web-design-system/molecules';
|
|
54
|
-
```
|
|
55
|
-
|
|
56
|
-
### Organisms (Complex UI Components)
|
|
57
|
-
```tsx
|
|
58
|
-
import {
|
|
59
|
-
Card,
|
|
60
|
-
Alert,
|
|
61
|
-
Modal,
|
|
62
|
-
Navbar
|
|
63
|
-
} from '@umituz/web-design-system/organisms';
|
|
64
|
-
```
|
|
65
|
-
|
|
66
|
-
### Templates (Page Structures)
|
|
67
|
-
```tsx
|
|
68
|
-
import {
|
|
69
|
-
Form,
|
|
70
|
-
List,
|
|
71
|
-
Section,
|
|
72
|
-
PageLayout,
|
|
73
|
-
PageHeader,
|
|
74
|
-
ResponsiveContainer,
|
|
75
|
-
ProjectSkeleton
|
|
76
|
-
} from '@umituz/web-design-system/templates';
|
|
77
|
-
```
|
|
78
|
-
|
|
79
|
-
### Hooks (React Hooks)
|
|
80
|
-
```tsx
|
|
81
|
-
import {
|
|
82
|
-
useTheme,
|
|
83
|
-
useMediaQuery,
|
|
84
|
-
useBreakpoint,
|
|
85
|
-
useLocalStorage,
|
|
86
|
-
useLanguage,
|
|
87
|
-
useClickOutside,
|
|
88
|
-
useKeyboard,
|
|
89
|
-
useEscape,
|
|
90
|
-
useDebounce,
|
|
91
|
-
useClipboard,
|
|
92
|
-
useToggle,
|
|
93
|
-
useScrollLock
|
|
94
|
-
} from '@umituz/web-design-system/hooks';
|
|
95
|
-
```
|
|
96
|
-
|
|
97
|
-
### Tokens (Design Tokens)
|
|
98
|
-
```tsx
|
|
99
|
-
import {
|
|
100
|
-
lightColorTokens,
|
|
101
|
-
darkColorTokens,
|
|
102
|
-
spacing,
|
|
103
|
-
fontSizes,
|
|
104
|
-
radii,
|
|
105
|
-
shadows
|
|
106
|
-
} from '@umituz/web-design-system/tokens';
|
|
107
|
-
```
|
|
108
|
-
|
|
109
|
-
### Types (TypeScript Types)
|
|
110
|
-
```tsx
|
|
111
|
-
import type {
|
|
112
|
-
SizeVariant,
|
|
113
|
-
ColorVariant,
|
|
114
|
-
BaseProps
|
|
115
|
-
} from '@umituz/web-design-system/types';
|
|
116
|
-
```
|
|
11
|
+
- `@umituz/web-design-system/styles.css` — precompiled (`dist/styles.css`),
|
|
12
|
+
Tailwind included. For vanilla-CSS hosts.
|
|
13
|
+
- `@umituz/web-design-system/theme.css` — the `@theme` layer alone. For
|
|
14
|
+
Tailwind v4 hosts that compile the component classes themselves.
|
|
117
15
|
|
|
118
|
-
|
|
119
|
-
|
|
120
|
-
|
|
121
|
-
validateInput,
|
|
122
|
-
validateEmail,
|
|
123
|
-
validateUrl,
|
|
124
|
-
sanitizeInput,
|
|
125
|
-
validateFileName,
|
|
126
|
-
CSP_CONFIG,
|
|
127
|
-
SECURITY_HEADERS,
|
|
128
|
-
VALIDATION_CONFIGS
|
|
129
|
-
} from '@umituz/web-design-system/security';
|
|
130
|
-
|
|
131
|
-
import { useFormValidation, COMMON_RULES } from '@umituz/web-design-system/security';
|
|
132
|
-
```
|
|
16
|
+
**Never use both** — a Tailwind host that adds the package source to its own
|
|
17
|
+
`@source` scan must not also import the precompiled stylesheet (duplicate
|
|
18
|
+
rules).
|
|
133
19
|
|
|
134
|
-
|
|
135
|
-
```tsx
|
|
136
|
-
import {
|
|
137
|
-
usePerformanceMonitor,
|
|
138
|
-
useLazyLoading,
|
|
139
|
-
useMemoryOptimization,
|
|
140
|
-
useLazyImage,
|
|
141
|
-
useLazyComponent,
|
|
142
|
-
useVirtualList
|
|
143
|
-
} from '@umituz/web-design-system/performance';
|
|
144
|
-
```
|
|
20
|
+
## Installation
|
|
145
21
|
|
|
146
|
-
|
|
147
|
-
|
|
148
|
-
import {
|
|
149
|
-
ErrorBoundary,
|
|
150
|
-
ErrorDisplay,
|
|
151
|
-
SuspenseWrapper,
|
|
152
|
-
NetworkError,
|
|
153
|
-
NotFoundError,
|
|
154
|
-
ApiError
|
|
155
|
-
} from '@umituz/web-design-system/error';
|
|
22
|
+
```bash
|
|
23
|
+
npm install @umituz/web-design-system
|
|
156
24
|
```
|
|
157
25
|
|
|
158
|
-
|
|
26
|
+
`clsx`, `class-variance-authority` and `tailwind-merge` are real runtime
|
|
27
|
+
dependencies (installed automatically). Peers: `react`, `react-dom`,
|
|
28
|
+
`lucide-react`, `react-syntax-highlighter` (CodeBlock only) and the 14
|
|
29
|
+
Radix primitives actually imported (dialog, dropdown-menu, select, …).
|
|
159
30
|
|
|
160
|
-
###
|
|
31
|
+
### Vanilla host (no Tailwind)
|
|
161
32
|
|
|
162
33
|
```tsx
|
|
34
|
+
// main.tsx — one import, includes preflight
|
|
35
|
+
import '@umituz/web-design-system/styles.css';
|
|
163
36
|
import { Button } from '@umituz/web-design-system/atoms';
|
|
164
37
|
|
|
165
|
-
<Button
|
|
166
|
-
<Button variant="secondary" size="lg">Secondary Button</Button>
|
|
167
|
-
<Button variant="success" size="sm">Success Button</Button>
|
|
168
|
-
```
|
|
169
|
-
|
|
170
|
-
### Card
|
|
171
|
-
|
|
172
|
-
```tsx
|
|
173
|
-
import { Card, CardHeader, CardTitle, CardDescription, CardContent } from '@umituz/web-design-system/organisms';
|
|
174
|
-
|
|
175
|
-
<Card>
|
|
176
|
-
<CardHeader>
|
|
177
|
-
<CardTitle>Card Title</CardTitle>
|
|
178
|
-
<CardDescription>Card description goes here</CardDescription>
|
|
179
|
-
</CardHeader>
|
|
180
|
-
<CardContent>
|
|
181
|
-
<p>Card content</p>
|
|
182
|
-
</CardContent>
|
|
183
|
-
</Card>
|
|
184
|
-
```
|
|
185
|
-
|
|
186
|
-
### Alert
|
|
187
|
-
|
|
188
|
-
```tsx
|
|
189
|
-
import { Alert } from '@umituz/web-design-system/organisms';
|
|
190
|
-
|
|
191
|
-
<Alert variant="success">Success message!</Alert>
|
|
192
|
-
<Alert variant="warning">Warning message!</Alert>
|
|
193
|
-
<Alert variant="destructive">Error message!</Alert>
|
|
38
|
+
<Button>Save</Button>
|
|
194
39
|
```
|
|
195
40
|
|
|
196
|
-
|
|
41
|
+
Restyle by overriding the CSS variables — no rebuild needed:
|
|
197
42
|
|
|
198
|
-
```
|
|
199
|
-
|
|
200
|
-
|
|
201
|
-
|
|
202
|
-
|
|
203
|
-
return (
|
|
204
|
-
<Button onClick={toggleTheme}>
|
|
205
|
-
Current: {theme}
|
|
206
|
-
</Button>
|
|
207
|
-
);
|
|
208
|
-
}
|
|
209
|
-
```
|
|
210
|
-
|
|
211
|
-
### Language Hook
|
|
212
|
-
|
|
213
|
-
```tsx
|
|
214
|
-
import { useLanguage } from '@umituz/web-design-system/hooks';
|
|
215
|
-
|
|
216
|
-
function LanguageSelector() {
|
|
217
|
-
const { currentLanguage, changeLanguage, t, supportedLanguages } = useLanguage({
|
|
218
|
-
defaultLanguage: 'en-US',
|
|
219
|
-
supportedLanguages: {
|
|
220
|
-
'en-US': { name: 'English', flag: '🇺🇸' },
|
|
221
|
-
'tr-TR': { name: 'Türkçe', flag: '🇹🇷' },
|
|
222
|
-
'de-DE': { name: 'Deutsch', flag: '🇩🇪' },
|
|
223
|
-
}
|
|
224
|
-
});
|
|
225
|
-
|
|
226
|
-
return (
|
|
227
|
-
<select value={currentLanguage} onChange={(e) => changeLanguage(e.target.value)}>
|
|
228
|
-
{Object.entries(supportedLanguages).map(([code, { name, flag }]) => (
|
|
229
|
-
<option key={code} value={code}>{flag} {name}</option>
|
|
230
|
-
))}
|
|
231
|
-
</select>
|
|
232
|
-
);
|
|
233
|
-
}
|
|
234
|
-
```
|
|
235
|
-
|
|
236
|
-
### Breakpoint Hook
|
|
237
|
-
|
|
238
|
-
```tsx
|
|
239
|
-
import { useBreakpoint, useMediaQuery } from '@umituz/web-design-system/hooks';
|
|
240
|
-
|
|
241
|
-
function ResponsiveComponent() {
|
|
242
|
-
const breakpoint = useBreakpoint();
|
|
243
|
-
const isDesktop = useMediaQuery('lg');
|
|
244
|
-
const isTablet = useMediaQuery('md');
|
|
245
|
-
|
|
246
|
-
return (
|
|
247
|
-
<div>
|
|
248
|
-
Current breakpoint: {breakpoint || 'mobile'}
|
|
249
|
-
{isDesktop && <DesktopNavigation />}
|
|
250
|
-
{isTablet && !isDesktop && <TabletNavigation />}
|
|
251
|
-
</div>
|
|
252
|
-
);
|
|
43
|
+
```css
|
|
44
|
+
:root {
|
|
45
|
+
--color-primary: #2e8b5f; /* brand color, e.g. herb green */
|
|
46
|
+
--color-primary-foreground: #ffffff;
|
|
47
|
+
--color-ring: rgba(46, 139, 95, 0.45);
|
|
253
48
|
}
|
|
254
49
|
```
|
|
255
50
|
|
|
256
|
-
|
|
257
|
-
|
|
258
|
-
### ResponsiveContainer
|
|
259
|
-
|
|
260
|
-
```tsx
|
|
261
|
-
import { ResponsiveContainer } from '@umituz/web-design-system/templates';
|
|
262
|
-
|
|
263
|
-
// Auto-responsive container with different max widths per device
|
|
264
|
-
<ResponsiveContainer
|
|
265
|
-
mobileMaxWidth="full"
|
|
266
|
-
tabletMaxWidth="lg"
|
|
267
|
-
desktopMaxWidth="xl"
|
|
268
|
-
gradient
|
|
269
|
-
minHeight="screen"
|
|
270
|
-
>
|
|
271
|
-
<h1>Auto-responsive content</h1>
|
|
272
|
-
<p>This container automatically adjusts based on screen size</p>
|
|
273
|
-
</ResponsiveContainer>
|
|
274
|
-
|
|
275
|
-
// Custom responsive container
|
|
276
|
-
<ResponsiveContainer
|
|
277
|
-
mobilePadding={false}
|
|
278
|
-
tabletPadding={true}
|
|
279
|
-
desktopPadding={true}
|
|
280
|
-
centered={false}
|
|
281
|
-
>
|
|
282
|
-
<div>Custom responsive layout</div>
|
|
283
|
-
</ResponsiveContainer>
|
|
284
|
-
```
|
|
285
|
-
|
|
286
|
-
## 🎯 Design Tokens
|
|
287
|
-
|
|
288
|
-
### Colors
|
|
289
|
-
|
|
290
|
-
```tsx
|
|
291
|
-
import { lightColorTokens, darkColorTokens } from '@umituz/web-design-system/tokens';
|
|
292
|
-
|
|
293
|
-
// Light mode
|
|
294
|
-
const colors = lightColorTokens;
|
|
295
|
-
// {
|
|
296
|
-
// primary: 'hsl(187 75% 38%)',
|
|
297
|
-
// background: 'hsl(210 20% 98%)',
|
|
298
|
-
// ...
|
|
299
|
-
// }
|
|
300
|
-
|
|
301
|
-
// Dark mode
|
|
302
|
-
const darkColors = darkColorTokens;
|
|
303
|
-
```
|
|
304
|
-
|
|
305
|
-
### Spacing
|
|
306
|
-
|
|
307
|
-
```tsx
|
|
308
|
-
import { spacing } from '@umituz/web-design-system/tokens';
|
|
309
|
-
|
|
310
|
-
const gap = spacing['4']; // '1rem'
|
|
311
|
-
```
|
|
312
|
-
|
|
313
|
-
### Typography
|
|
51
|
+
Dark mode: add `data-theme="dark"` or `class="dark"` on any ancestor
|
|
52
|
+
(typically `<html>`). The package never switches themes on its own.
|
|
314
53
|
|
|
315
|
-
|
|
316
|
-
import { fontSizes, fontWeights } from '@umituz/web-design-system/tokens';
|
|
317
|
-
|
|
318
|
-
const fontSize = fontSizes['lg']; // '1.125rem'
|
|
319
|
-
const fontWeight = fontWeights['semibold']; // '600'
|
|
320
|
-
```
|
|
54
|
+
### Tailwind v4 host
|
|
321
55
|
|
|
322
|
-
|
|
56
|
+
Compile the component classes as part of your own build — then utilities
|
|
57
|
+
you pass via `className` merge naturally with the package's:
|
|
323
58
|
|
|
324
|
-
|
|
325
|
-
|
|
326
|
-
import
|
|
59
|
+
```css
|
|
60
|
+
/* app.css */
|
|
61
|
+
@import "tailwindcss";
|
|
62
|
+
@import "tw-animate-css";
|
|
63
|
+
@import "@umituz/web-design-system/theme.css";
|
|
64
|
+
@source "../node_modules/@umituz/web-design-system/src";
|
|
65
|
+
```
|
|
66
|
+
|
|
67
|
+
You control the palette the same way (override `--color-*` in your theme),
|
|
68
|
+
and your `@theme` extensions apply everywhere.
|
|
69
|
+
|
|
70
|
+
## Theming
|
|
71
|
+
|
|
72
|
+
Every component binds to semantic variables defined in `src/styles/theme.css`:
|
|
73
|
+
|
|
74
|
+
| Variable | Light default | Purpose |
|
|
75
|
+
| --- | --- | --- |
|
|
76
|
+
| `--color-background` / `--color-foreground` | `#f8fafc` / `#0f172a` | app surface & text |
|
|
77
|
+
| `--color-card` / `--color-popover` (+ `-foreground`) | `#ffffff` | elevated surfaces |
|
|
78
|
+
| `--color-primary` / `--color-primary-foreground` | `#2563eb` / `#fff` | brand actions |
|
|
79
|
+
| `--color-secondary` / `--color-secondary-foreground` | `#8b5cf6` / `#fff` | secondary actions |
|
|
80
|
+
| `--color-muted` / `--color-muted-foreground` | `#f1f5f9` / `#64748b` | quiet surfaces & text |
|
|
81
|
+
| `--color-accent` / `--color-accent-foreground` | `#f1f5f9` / `#0f172a` | hover accents |
|
|
82
|
+
| `--color-destructive` / `--color-destructive-foreground` | `#dc2626` / `#fff` | danger actions |
|
|
83
|
+
| `--color-success` / `--color-warning` / `--color-info` | `#16a34a` / `#d97706` / `#2563eb` | status (Badge variants) |
|
|
84
|
+
| `--color-border` / `--color-input` | `#e2e8f0` | borders & inputs |
|
|
85
|
+
| `--color-ring` | `rgba(37,99,235,.45)` | focus rings |
|
|
86
|
+
| `--radius-sm` / `--radius-md` / `--radius-lg` / `--radius-xl` | 6/8/12/16px | radii scale |
|
|
87
|
+
| `--shadow-sm` / `--shadow-md` / `--shadow-lg` | dashboard scale | elevation |
|
|
88
|
+
| `--font-sans` / `--font-mono` | system stacks | typography |
|
|
89
|
+
|
|
90
|
+
The defaults mirror `@umituz/web-dashboard`'s tokens, so dashboard adoption
|
|
91
|
+
is visually regression-free. A brand override (e.g. foodora's herb green)
|
|
92
|
+
is three variables:
|
|
327
93
|
|
|
328
|
-
|
|
329
|
-
|
|
330
|
-
|
|
331
|
-
|
|
94
|
+
```css
|
|
95
|
+
:root {
|
|
96
|
+
--color-primary: #2e8b5f;
|
|
97
|
+
--color-primary-foreground: #ffffff;
|
|
98
|
+
--color-info: #2e8b5f;
|
|
99
|
+
}
|
|
100
|
+
.dark {
|
|
101
|
+
--color-primary: #3aa76d;
|
|
332
102
|
}
|
|
333
|
-
|
|
334
|
-
// Sanitize user input
|
|
335
|
-
const clean = sanitizeInput(userInput);
|
|
336
|
-
|
|
337
|
-
// Validate file names
|
|
338
|
-
const fileResult = validateFileName(fileName);
|
|
339
|
-
```
|
|
340
|
-
|
|
341
|
-
### Form Validation Hook
|
|
342
|
-
```tsx
|
|
343
|
-
import { useFormValidation, COMMON_RULES } from '@umituz/web-design-system/security';
|
|
344
|
-
|
|
345
|
-
const MyForm = () => {
|
|
346
|
-
const { formData, errors, updateField, validateAllFields, isFormValid } = useFormValidation(
|
|
347
|
-
{ name: '', email: '' },
|
|
348
|
-
{
|
|
349
|
-
name: COMMON_RULES.name,
|
|
350
|
-
email: COMMON_RULES.email
|
|
351
|
-
}
|
|
352
|
-
);
|
|
353
|
-
|
|
354
|
-
return (
|
|
355
|
-
<form onSubmit={handleSubmit}>
|
|
356
|
-
<input
|
|
357
|
-
value={formData.name}
|
|
358
|
-
onChange={(e) => updateField('name', e.target.value)}
|
|
359
|
-
/>
|
|
360
|
-
{errors.name && <span className="error">{errors.name}</span>}
|
|
361
|
-
</form>
|
|
362
|
-
);
|
|
363
|
-
};
|
|
364
|
-
```
|
|
365
|
-
|
|
366
|
-
## ⚡ Performance Features
|
|
367
|
-
|
|
368
|
-
### Performance Monitoring
|
|
369
|
-
```tsx
|
|
370
|
-
import { usePerformanceMonitor } from '@umituz/web-design-system/performance';
|
|
371
|
-
|
|
372
|
-
const MyComponent = () => {
|
|
373
|
-
const { metrics, getPerformanceReport } = usePerformanceMonitor({
|
|
374
|
-
componentName: 'MyComponent',
|
|
375
|
-
trackRenders: true,
|
|
376
|
-
trackMemory: true
|
|
377
|
-
});
|
|
378
|
-
|
|
379
|
-
return <div>Render time: {metrics.renderTime}ms</div>;
|
|
380
|
-
};
|
|
381
|
-
```
|
|
382
|
-
|
|
383
|
-
### Lazy Loading
|
|
384
|
-
```tsx
|
|
385
|
-
import { useLazyLoading, useLazyImage } from '@umituz/web-design-system/performance';
|
|
386
|
-
|
|
387
|
-
const LazyImage = () => {
|
|
388
|
-
const { targetRef, imageSrc, isLoaded } = useLazyImage('/large-image.jpg');
|
|
389
|
-
|
|
390
|
-
return (
|
|
391
|
-
<div ref={targetRef}>
|
|
392
|
-
{isLoaded ? <img src={imageSrc} alt="Lazy loaded" /> : <div>Loading...</div>}
|
|
393
|
-
</div>
|
|
394
|
-
);
|
|
395
|
-
};
|
|
396
|
-
```
|
|
397
|
-
|
|
398
|
-
### Memory Optimization
|
|
399
|
-
```tsx
|
|
400
|
-
import { useMemoryOptimization } from '@umituz/web-design-system/performance';
|
|
401
|
-
|
|
402
|
-
const MyComponent = () => {
|
|
403
|
-
const { addEventListener, setTimeout, addCleanup, getMemoryStats } = useMemoryOptimization();
|
|
404
|
-
|
|
405
|
-
useEffect(() => {
|
|
406
|
-
const cleanup = addEventListener(window, 'resize', handleResize);
|
|
407
|
-
const timerId = setTimeout(() => {}, 1000);
|
|
408
|
-
|
|
409
|
-
return () => {
|
|
410
|
-
cleanup();
|
|
411
|
-
// Automatic cleanup on unmount
|
|
412
|
-
};
|
|
413
|
-
}, []);
|
|
414
|
-
|
|
415
|
-
return <div>Memory stats: {getMemoryStats().totalTrackedItems} items</div>;
|
|
416
|
-
};
|
|
417
|
-
```
|
|
418
|
-
|
|
419
|
-
## 🚨 Error Handling
|
|
420
|
-
|
|
421
|
-
### Error Boundary
|
|
422
|
-
```tsx
|
|
423
|
-
import { ErrorBoundary } from '@umituz/web-design-system/error';
|
|
424
|
-
|
|
425
|
-
<ErrorBoundary
|
|
426
|
-
level="page"
|
|
427
|
-
showDetails={true}
|
|
428
|
-
onError={(error, errorInfo) => console.error(error)}
|
|
429
|
-
>
|
|
430
|
-
<MyComponent />
|
|
431
|
-
</ErrorBoundary>
|
|
432
|
-
```
|
|
433
|
-
|
|
434
|
-
### Error Display
|
|
435
|
-
```tsx
|
|
436
|
-
import { ErrorDisplay, NetworkError, ApiError } from '@umituz/web-design-system/error';
|
|
437
|
-
|
|
438
|
-
<ErrorDisplay
|
|
439
|
-
error={error}
|
|
440
|
-
title="Something went wrong"
|
|
441
|
-
severity="error"
|
|
442
|
-
showRetry={true}
|
|
443
|
-
onRetry={retryFunction}
|
|
444
|
-
/>
|
|
445
|
-
|
|
446
|
-
<NetworkError onRetry={retry} />
|
|
447
|
-
<ApiError error={apiError} onRetry={retry} />
|
|
448
103
|
```
|
|
449
104
|
|
|
450
|
-
|
|
451
|
-
```tsx
|
|
452
|
-
import { SuspenseWrapper, PageSuspense } from '@umituz/web-design-system/error';
|
|
105
|
+
## Entry points
|
|
453
106
|
|
|
454
|
-
|
|
455
|
-
|
|
456
|
-
|
|
107
|
+
```bash
|
|
108
|
+
@umituz/web-design-system/styles.css # precompiled stylesheet (vanilla hosts)
|
|
109
|
+
@umituz/web-design-system/theme.css # @theme layer (Tailwind v4 hosts)
|
|
110
|
+
@umituz/web-design-system/atoms # Button, Input, Badge, Spinner, …
|
|
111
|
+
@umituz/web-design-system/molecules # FormField, Select, Avatar, …
|
|
112
|
+
@umituz/web-design-system/organisms # Card, Dialog, Sheet, Table, DataTable, …
|
|
113
|
+
@umituz/web-design-system/templates # page-level layouts
|
|
114
|
+
@umituz/web-design-system/hooks # useMediaQuery, useDebounce, useTheme, …
|
|
115
|
+
@umituz/web-design-system/utils # cn, responsive helpers, clamp/pagination math
|
|
116
|
+
@umituz/web-design-system/utils/cn # cn alone
|
|
117
|
+
@umituz/web-design-system/constants # size/type maps
|
|
118
|
+
@umituz/web-design-system/tokens # RESPONSIVE_* scale maps
|
|
119
|
+
@umituz/web-design-system/types # shared type contracts
|
|
120
|
+
```
|
|
121
|
+
|
|
122
|
+
Subpath imports are recommended; the root barrel exists but pulls
|
|
123
|
+
everything.
|
|
124
|
+
|
|
125
|
+
## What changed in v4 (major)
|
|
126
|
+
|
|
127
|
+
- **Authored in Tailwind v4, precompiled CSS shipped.** v3 required the
|
|
128
|
+
host to run Tailwind with matching config; v4 compiles itself and binds
|
|
129
|
+
semantic classes to `--color-*` variables (`dist/styles.css` is a
|
|
130
|
+
published artifact with contract tests).
|
|
131
|
+
- **Dead towers removed**: `infrastructure/security`, `performance`,
|
|
132
|
+
`calculation`, `error` (~2.5k lines, zero consumers). The four live
|
|
133
|
+
calculation helpers live in `utils` (`clampToRange`, `percentOfMax`,
|
|
134
|
+
`formatTrendMagnitude`, `computePageBounds`).
|
|
135
|
+
- **App-specific organisms removed**: Navbar, MainNavbar, Footer,
|
|
136
|
+
NewsletterSignup, Comments, ImageLightbox, Calendar, FilterBar,
|
|
137
|
+
FilterSidebar, QuickActionCard, Grid, Modal, FormModal, ConfirmDialog,
|
|
138
|
+
AlertDialog (use Dialog), Breadcrumb molecule (organism stays).
|
|
139
|
+
- **JS theme tokens removed** — theming is CSS-native now
|
|
140
|
+
(`src/styles/theme.css`). The `./tokens` subpath keeps the
|
|
141
|
+
`RESPONSIVE_*` scale maps only.
|
|
142
|
+
- **`useLanguage` removed** — i18n runtime belongs to the host (same
|
|
143
|
+
principle as dashboard v4). `react-i18next` is no longer a peer.
|
|
144
|
+
- **Peer list tightened to real imports** (14 Radix primitives;
|
|
145
|
+
`react-day-picker`, `react-alert-dialog`, `react-tabs`,
|
|
146
|
+
`react-tooltip` dropped). `clsx`/`class-variance-authority`/
|
|
147
|
+
`tailwind-merge` moved from peers to dependencies.
|
|
148
|
+
- **Package ships tests** (contract + unit + smoke) and a `build` step;
|
|
149
|
+
`prepublishOnly` runs the full gate.
|
|
150
|
+
|
|
151
|
+
## Platform compatibility
|
|
152
|
+
|
|
153
|
+
React 18 and 19. Rendering targets the DOM; React Native is not supported.
|
|
154
|
+
|
|
155
|
+
## Development
|
|
457
156
|
|
|
458
|
-
|
|
459
|
-
|
|
460
|
-
|
|
157
|
+
```bash
|
|
158
|
+
npm install
|
|
159
|
+
npm run lint # eslint
|
|
160
|
+
npm run typecheck # tsc --noEmit
|
|
161
|
+
npm run build # tailwindcss → dist/styles.css (minified)
|
|
162
|
+
npm test # build + vitest (contract, unit, smoke)
|
|
461
163
|
```
|
|
462
164
|
|
|
463
|
-
|
|
464
|
-
|
|
465
|
-
|
|
466
|
-
|
|
467
|
-
- **Atoms**: Basic building blocks (Button, Input, Icon)
|
|
468
|
-
- **Molecules**: Simple combinations (FormField, SearchBox, Chip)
|
|
469
|
-
- **Organisms**: Complex components (Card, Modal, Navbar)
|
|
470
|
-
- **Templates**: Page structures (Form, List, Section)
|
|
471
|
-
|
|
472
|
-
## 🌐 Tailwind CSS Integration
|
|
165
|
+
Component classes must stay literal in the source: `@source` scans
|
|
166
|
+
`src/`, so classes passed in from outside (props) are not compiled into
|
|
167
|
+
the precompiled stylesheet.
|
|
473
168
|
|
|
474
|
-
|
|
475
|
-
|
|
476
|
-
```css
|
|
477
|
-
/* Your global CSS */
|
|
478
|
-
@layer base {
|
|
479
|
-
:root {
|
|
480
|
-
--background: 210 20% 98%;
|
|
481
|
-
--foreground: 220 20% 12%;
|
|
482
|
-
--primary: 187 75% 38%;
|
|
483
|
-
--primary-foreground: 0 0% 100%;
|
|
484
|
-
/* ... more tokens */
|
|
485
|
-
}
|
|
486
|
-
|
|
487
|
-
.dark {
|
|
488
|
-
--background: 220 20% 7%;
|
|
489
|
-
--foreground: 210 20% 92%;
|
|
490
|
-
--primary: 187 85% 53%;
|
|
491
|
-
--primary-foreground: 220 20% 7%;
|
|
492
|
-
/* ... more tokens */
|
|
493
|
-
}
|
|
494
|
-
}
|
|
495
|
-
```
|
|
496
|
-
|
|
497
|
-
## 📄 License
|
|
169
|
+
## License
|
|
498
170
|
|
|
499
171
|
MIT
|
|
500
|
-
|
|
501
|
-
## 🤝 Contributing
|
|
502
|
-
|
|
503
|
-
This package is part of the @umituz organization. For issues and feature requests, please visit the GitHub repository.
|