react-18-ui-library 0.1.0 → 0.2.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.
Files changed (2) hide show
  1. package/README.md +600 -78
  2. package/package.json +1 -1
package/README.md CHANGED
@@ -1,41 +1,106 @@
1
1
  # react-18-ui-library
2
2
 
3
- A fully customizable, theme-aware React 18 enterprise UI component library. All components consume CSS custom properties from the parent app's `:root` — no hardcoded colors, no runtime CSS-in-JS overhead.
4
-
5
- ## Quick Start
3
+ > A fully customizable, theme-aware React 18 enterprise UI component library 70+ components, schema-driven forms, fluent validation, drag-and-drop file upload, and zero runtime CSS-in-JS overhead.
4
+
5
+ [![npm version](https://img.shields.io/npm/v/react-18-ui-library.svg)](https://www.npmjs.com/package/react-18-ui-library)
6
+ [![TypeScript](https://img.shields.io/badge/TypeScript-5.4-blue.svg)](https://www.typescriptlang.org/)
7
+ [![React](https://img.shields.io/badge/React-18-61dafb.svg)](https://react.dev/)
8
+ [![TailwindCSS](https://img.shields.io/badge/TailwindCSS-3-38bdf8.svg)](https://tailwindcss.com/)
9
+ [![Snyk](https://img.shields.io/badge/security-snyk-blueviolet.svg)](https://snyk.io/)
10
+
11
+ ---
12
+
13
+ ## Table of Contents
14
+
15
+ - [Installation](#installation)
16
+ - [Quick Start](#quick-start)
17
+ - [Theme System](#theme-system)
18
+ - [Component Reference](#component-reference)
19
+ - [Layout](#layout)
20
+ - [Navigation](#navigation)
21
+ - [Inputs](#inputs)
22
+ - [Forms](#forms)
23
+ - [Display](#display)
24
+ - [Feedback](#feedback)
25
+ - [Overlay](#overlay)
26
+ - [Typography](#typography)
27
+ - [Actions](#actions)
28
+ - [FormValidator — Fluent Validation API](#formvalidator--fluent-validation-api)
29
+ - [Hooks](#hooks)
30
+ - [CSS Token Reference](#css-token-reference)
31
+ - [Security — Snyk](#security--snyk)
32
+ - [Development](#development)
33
+ - [Peer Dependencies](#peer-dependencies)
34
+ - [License](#license)
35
+
36
+ ---
37
+
38
+ ## Installation
6
39
 
7
40
  ```bash
8
41
  npm install react-18-ui-library
42
+ # or
43
+ yarn add react-18-ui-library
44
+ # or
45
+ pnpm add react-18-ui-library
9
46
  ```
10
47
 
48
+ ---
49
+
50
+ ## Quick Start
51
+
11
52
  ```tsx
12
- // 1. Import the default theme tokens (fallback values)
53
+ // 1. Import default theme tokens once at your app root
13
54
  import 'react-18-ui-library/styles'
14
55
 
15
- // 2. Use components directly — they read CSS vars from your app's :root
16
- import { Button, TextField, AppShell } from 'react-18-ui-library'
56
+ // 2. Import and use components
57
+ import { Button, TextField, JSONForm } from 'react-18-ui-library'
58
+
59
+ export function App() {
60
+ return (
61
+ <div>
62
+ <TextField label="Name" placeholder="John Doe" />
63
+ <Button variant="primary">Submit</Button>
64
+ </div>
65
+ )
66
+ }
17
67
  ```
18
68
 
69
+ > The styles import injects CSS custom property defaults into `:root`. You can override any token in your own stylesheet — see [Theme System](#theme-system).
70
+
71
+ ---
72
+
19
73
  ## Theme System
20
74
 
21
- Components read CSS custom properties from the parent app's `:root`. Override any token in your app's CSS:
75
+ All components read CSS custom properties from the parent app's `:root`. There are **no hardcoded colors** and no runtime CSS-in-JS overhead.
76
+
77
+ ### Override tokens in CSS
22
78
 
23
79
  ```css
24
- /* your-app/globals.css */
80
+ /* globals.css */
25
81
  :root {
26
- --color-primary: #7c3aed;
27
- --color-primary-hover: #6d28d9;
82
+ --color-primary: #7c3aed;
83
+ --color-primary-hover: #6d28d9;
28
84
  --color-primary-foreground: #ffffff;
29
- --color-background: #fafafa;
30
- --color-surface: #ffffff;
31
- --color-text: #111827;
32
- --radius-md: 0.5rem;
33
- --font-family-base: 'Inter', sans-serif;
34
- /* ...etc */
85
+ --color-background: #fafafa;
86
+ --color-surface: #ffffff;
87
+ --color-text: #111827;
88
+ --color-text-muted: #6b7280;
89
+ --color-border: #e5e7eb;
90
+ --color-error: #ef4444;
91
+ --color-success: #22c55e;
92
+ --color-warning: #f59e0b;
93
+ --radius-sm: 0.25rem;
94
+ --radius-md: 0.5rem;
95
+ --radius-lg: 0.75rem;
96
+ --font-family-base: 'Inter', sans-serif;
97
+ --navbar-height: 64px;
98
+ --sidebar-width: 260px;
99
+ --sidebar-collapsed-width: 64px;
35
100
  }
36
101
  ```
37
102
 
38
- Or use the optional `ThemeProvider` to set tokens programmatically:
103
+ ### Or use `ThemeProvider` programmatically
39
104
 
40
105
  ```tsx
41
106
  import { ThemeProvider } from 'react-18-ui-library'
@@ -45,22 +110,22 @@ import { ThemeProvider } from 'react-18-ui-library'
45
110
  </ThemeProvider>
46
111
  ```
47
112
 
48
- ## Component Categories
113
+ ---
49
114
 
50
- | Category | Components |
51
- |---|---|
52
- | **Layout** | `AppShell`, `Navbar`, `Sidebar`, `Container`, `Stack`, `Grid`, `Divider`, `Spacer` |
53
- | **Navigation** | `Tabs`, `Breadcrumb`, `Pagination`, `StepIndicator` |
54
- | **Inputs** | `Button`, `IconButton`, `TextField`, `TextArea`, `Select`, `Checkbox`, `RadioGroup`, `Switch` |
55
- | **Forms** | `FormField`, `JSONForm`, `FileUpload` |
56
- | **Display** | `Card`, `Box`, `Image`, `Avatar`, `Badge`, `Tag`, `Icon`, `SVG`, `Table`, `List`, `Timeline`, `Stat`, `EmptyState` |
57
- | **Feedback** | `Alert`, `ToastProvider`, `Spinner`, `Skeleton`, `ProgressBar`, `ErrorBoundary` |
58
- | **Overlay** | `Modal`, `Drawer`, `Tooltip`, `Popover`, `ContextMenu` |
59
- | **Typography** | `Heading`, `Text`, `Label`, `Code`, `Link` |
115
+ ## Component Reference
60
116
 
61
- ## Key Components
117
+ ### Layout
62
118
 
63
- ### AppShell Full Layout
119
+ | Component | Description |
120
+ |---|---|
121
+ | `AppShell` | Full-page layout combining Navbar + Sidebar + main content area |
122
+ | `Navbar` | Top navigation bar with logo, links, and action slots |
123
+ | `Sidebar` | Collapsible sidebar with icons, badges, and nested items |
124
+ | `Container` | Max-width content wrapper with `xs`/`sm`/`md`/`lg`/`xl`/`full` sizes |
125
+ | `Stack` | Flexbox stack — `direction`, `gap`, `align`, `justify` props |
126
+ | `Grid` | CSS grid with responsive column count and gap control |
127
+ | `Divider` | Horizontal or vertical separator with optional label |
128
+ | `Spacer` | Flexible whitespace filler |
64
129
 
65
130
  ```tsx
66
131
  import { AppShell } from 'react-18-ui-library'
@@ -68,68 +133,195 @@ import { LayoutDashboard, Users, Settings } from 'lucide-react'
68
133
 
69
134
  <AppShell
70
135
  navbar={{
71
- logo: <Logo />,
136
+ logo: <img src="/logo.svg" alt="Logo" height={32} />,
72
137
  links: [{ label: 'Home', href: '/', active: true }],
73
138
  actions: <Button size="sm">Sign Out</Button>,
74
139
  }}
75
140
  sidebar={{
76
141
  items: [
77
- { id: 'dash', label: 'Dashboard', icon: <LayoutDashboard size={16} />, active: true },
78
- { id: 'users', label: 'Users', icon: <Users size={16} />, badge: 5 },
79
- { id: 'settings', label: 'Settings', icon: <Settings size={16} /> },
142
+ { id: 'dash', label: 'Dashboard', icon: <LayoutDashboard size={16} />, active: true },
143
+ { id: 'users', label: 'Users', icon: <Users size={16} />, badge: 5 },
144
+ { id: 'settings', label: 'Settings', icon: <Settings size={16} /> },
80
145
  ],
81
146
  }}
82
147
  >
83
- <main>Your page content</main>
148
+ <main>Page content</main>
84
149
  </AppShell>
85
150
  ```
86
151
 
87
- ### TextField — Prefix / Suffix
152
+ ---
153
+
154
+ ### Navigation
155
+
156
+ | Component | Description |
157
+ |---|---|
158
+ | `Tabs` | Horizontal/vertical tab panels with `line`, `pill`, `boxed` variants |
159
+ | `Breadcrumb` | Accessible breadcrumb trail with custom separator |
160
+ | `Pagination` | Page navigation with configurable page size and sibling count |
161
+ | `StepIndicator` | Multi-step wizard progress with `completed`/`current`/`upcoming` states |
88
162
 
89
163
  ```tsx
90
- <TextField
91
- label="Amount"
92
- prefixText="$"
93
- suffixText="USD"
94
- placeholder="0.00"
164
+ import { Tabs, StepIndicator, Pagination } from 'react-18-ui-library'
165
+
166
+ <Tabs
167
+ items={[
168
+ { id: 'profile', label: 'Profile', content: <ProfilePanel /> },
169
+ { id: 'billing', label: 'Billing', content: <BillingPanel /> },
170
+ { id: 'security', label: 'Security', content: <SecurityPanel /> },
171
+ ]}
172
+ variant="pill"
173
+ />
174
+
175
+ <StepIndicator
176
+ steps={[
177
+ { id: '1', label: 'Account', status: 'completed' },
178
+ { id: '2', label: 'Profile', status: 'current' },
179
+ { id: '3', label: 'Review', status: 'upcoming' },
180
+ ]}
181
+ />
182
+
183
+ <Pagination
184
+ page={currentPage}
185
+ totalPages={20}
186
+ onPageChange={setCurrentPage}
95
187
  />
188
+ ```
189
+
190
+ ---
96
191
 
192
+ ### Inputs
193
+
194
+ | Component | Description |
195
+ |---|---|
196
+ | `Button` | `primary`, `secondary`, `ghost`, `outline`, `destructive` variants + `xs`/`sm`/`md`/`lg` sizes |
197
+ | `IconButton` | Square icon-only button with same variants |
198
+ | `TextField` | Text input — prefix/suffix icon/text/image, clearable, password toggle, `showMaxLength` |
199
+ | `TextArea` | Auto-resize textarea with character count (`showCharCount` / `showMaxLength`) |
200
+ | `Select` | Radix-powered dropdown with option groups |
201
+ | `MultiSelect` | Multi-value select with chip display |
202
+ | `SearchSelect` | Combobox with single/multi mode and async search |
203
+ | `ChipSelect` | Inline chip-toggle multi-select |
204
+ | `Checkbox` | Accessible checkbox with indeterminate state |
205
+ | `RadioGroup` | Accessible radio group |
206
+ | `Switch` | Toggle switch |
207
+ | `Slider` | Range slider with `min`/`max`/`step` |
208
+ | `NumberInput` | Numeric input — increment/decrement controls, `hideControls`, blocks non-numeric keys, `showMaxLength` |
209
+ | `PhoneInput` | Phone input with country code dropdown (30+ countries), digit-only enforcement, `showMaxLength` |
210
+ | `OTPInput` | One-time password input with configurable digit count and auto-advance |
211
+ | `Rating` | Star rating with half-star support |
212
+ | `TagInput` | Free-form tag entry — Enter/comma separators, duplicate prevention |
213
+ | `DatePicker` | Calendar picker — single/range mode, month+year dropdowns, configurable year range, portal rendering |
214
+
215
+ ```tsx
216
+ import { TextField, PhoneInput, NumberInput, DatePicker, OTPInput } from 'react-18-ui-library'
217
+ import { Search } from 'lucide-react'
218
+
219
+ // Text field with icon prefix and max-length counter
97
220
  <TextField
98
- label="Search"
221
+ label="Username"
99
222
  prefixIcon={<Search size={14} />}
223
+ maxLength={30}
224
+ showMaxLength
100
225
  clearable
101
226
  />
102
227
 
103
- <TextField
104
- label="Phone"
105
- prefixImage="/flags/us.png"
106
- prefixText="+1"
107
- type="tel"
228
+ // Phone input with country code
229
+ <PhoneInput
230
+ label="Mobile Number"
231
+ defaultCountry="IN"
232
+ maxLength={10}
233
+ showMaxLength
234
+ onChange={(val) => console.log(val.full)} // "+91 9876543210"
235
+ />
236
+
237
+ // Number input — hide stepper buttons
238
+ <NumberInput
239
+ label="Quantity"
240
+ hideControls
241
+ min={0}
242
+ max={999}
108
243
  />
244
+
245
+ // Date picker — restrict year range
246
+ <DatePicker
247
+ label="Date of Birth"
248
+ yearRangeBefore={80}
249
+ yearRangeAfter={0}
250
+ onChange={(date) => console.log(date)}
251
+ />
252
+
253
+ // OTP input — 6 digits
254
+ <OTPInput length={6} onComplete={(code) => verifyOTP(code)} />
109
255
  ```
110
256
 
111
- ### JSONForm — Schema-Driven Forms
257
+ ---
258
+
259
+ ### Forms
260
+
261
+ #### `JSONForm` — Schema-Driven Forms
262
+
263
+ Build complete, validated forms from a JSON schema array. Powered by `react-hook-form`.
264
+
265
+ **Supported `type` values:** `text` · `email` · `password` · `url` · `tel` · `number` · `textarea` · `select` · `multiselect` · `radio` · `checkbox` · `switch` · `slider` · `chipselect` · `taginput` · `datepicker` · `file`
112
266
 
113
267
  ```tsx
114
- import { JSONForm } from 'react-18-ui-library'
268
+ import { JSONForm, v } from 'react-18-ui-library'
115
269
  import type { JSONFormField } from 'react-18-ui-library'
116
270
 
117
271
  const schema: JSONFormField[] = [
118
- { name: 'name', type: 'text', label: 'Full Name', required: true, prefixIcon: <User size={14} /> },
119
- { name: 'email', type: 'email', label: 'Email', required: true, prefixIcon: <Mail size={14} /> },
120
- { name: 'role', type: 'select', label: 'Role', options: [{ value: 'admin', label: 'Admin' }] },
121
- { name: 'bio', type: 'textarea', label: 'Bio', showCharCount: true, validation: { maxLength: 200 } },
272
+ {
273
+ name: 'firstName',
274
+ type: 'text',
275
+ label: 'First Name',
276
+ colSpan: 1,
277
+ validator: v.string().required().lengthBetween(2, 50),
278
+ },
279
+ {
280
+ name: 'email',
281
+ type: 'email',
282
+ label: 'Email',
283
+ colSpan: 1,
284
+ validator: v.email().required().blockedDomains(['mailinator.com']),
285
+ },
286
+ {
287
+ name: 'role',
288
+ type: 'select',
289
+ label: 'Role',
290
+ options: [
291
+ { value: 'admin', label: 'Admin' },
292
+ { value: 'editor', label: 'Editor' },
293
+ { value: 'viewer', label: 'Viewer' },
294
+ ],
295
+ validator: v.select().required(),
296
+ },
297
+ {
298
+ name: 'bio',
299
+ type: 'textarea',
300
+ label: 'Bio',
301
+ colSpan: 2,
302
+ showCharCount: true,
303
+ validator: v.string().maxLength(300),
304
+ },
305
+ {
306
+ name: 'terms',
307
+ type: 'checkbox',
308
+ label: 'I agree to the Terms and Conditions',
309
+ colSpan: 2,
310
+ validator: v.boolean().mustBeTrue('You must accept the terms'),
311
+ },
122
312
  ]
123
313
 
124
314
  <JSONForm
125
315
  schema={schema}
126
316
  columns={2}
127
317
  onSubmit={(data) => console.log(data)}
128
- submitLabel="Save"
318
+ onCancel={() => router.back()}
319
+ submitLabel="Create Account"
320
+ cancelLabel="Cancel"
129
321
  />
130
322
  ```
131
323
 
132
- ### FileUpload — Drag & Drop
324
+ #### `FileUpload` — Drag & Drop
133
325
 
134
326
  ```tsx
135
327
  import { FileUpload } from 'react-18-ui-library'
@@ -145,58 +337,388 @@ import { FileUpload } from 'react-18-ui-library'
145
337
  />
146
338
  ```
147
339
 
148
- ### Toast Notifications
340
+ ---
341
+
342
+ ## FormValidator — Fluent Validation API
343
+
344
+ A chainable, type-safe validation builder that compiles to `react-hook-form` rules. Import `v` and attach a `.validator` to any `JSONFormField`.
345
+
346
+ ### Validator reference
347
+
348
+ | Builder | Field types | Methods |
349
+ |---|---|---|
350
+ | `v.string()` | `text` `textarea` | `.required()` `.minLength(n)` `.maxLength(n)` `.lengthBetween(min,max)` `.length(n)` `.shouldMatch(regex)` `.shouldBeIn([...])` `.notEmpty()` `.noSpaces()` `.alphanumeric()` `.startsWith(s)` `.endsWith(s)` `.custom(name, fn)` |
351
+ | `v.number()` | `number` | `.required()` `.min(n)` `.max(n)` `.between(min,max)` `.integer()` `.positive()` `.negative()` `.nonZero()` `.multipleOf(n)` `.length(digits)` `.custom(name, fn)` |
352
+ | `v.password()` | `password` | `.required()` `.minLength(n)` `.maxLength(n)` `.hasUppercase()` `.hasLowercase()` `.hasDigit()` `.hasSpecialChar()` `.noSpaces()` `.confirmMatch(getter)` `.strong()` `.custom(name, fn)` |
353
+ | `v.email()` | `email` | `.required()` `.domain([...])` `.blockedDomains([...])` `.shouldMatch(regex)` `.custom(name, fn)` |
354
+ | `v.url()` | `url` | `.required()` `.httpsOnly()` `.allowedDomains([...])` `.noTrailingSlash()` `.custom(name, fn)` |
355
+ | `v.tel()` | `tel` | `.required()` `.length(n)` `.minLength(n)` `.maxLength(n)` `.shouldMatch(regex)` `.custom(name, fn)` |
356
+ | `v.date()` | `datepicker` `text` | `.required()` `.validDate()` `.minDate(d)` `.maxDate(d)` `.notInPast()` `.notInFuture()` `.between(min,max)` `.custom(name, fn)` |
357
+ | `v.select()` | `select` `radio` | `.required()` `.shouldBeIn([...])` `.notEmpty()` `.custom(name, fn)` |
358
+ | `v.boolean()` | `checkbox` `switch` | `.required()` `.mustBeTrue(msg)` `.custom(name, fn)` |
359
+ | `v.array()` | `chipselect` `taginput` `multiselect` | `.required()` `.minItems(n)` `.maxItems(n)` `.exactItems(n)` `.shouldBeIn([...])` `.noEmpty()` `.custom(name, fn)` |
360
+ | `v.file()` | `file` | `.required()` `.maxSize(bytes)` `.allowedTypes([...])` `.allowedExtensions([...])` `.maxFiles(n)` `.minFiles(n)` `.custom(name, fn)` |
361
+
362
+ ### Usage examples
363
+
364
+ ```tsx
365
+ import { v } from 'react-18-ui-library'
366
+
367
+ // String
368
+ v.string().required().lengthBetween(3, 20).noSpaces()
369
+ v.string().required().shouldBeIn(['admin', 'editor', 'viewer'])
370
+ v.string().required().shouldMatch(/^\d{5}(-\d{4})?$/, 'Invalid ZIP code')
371
+ v.string().required().startsWith('INVITE-').alphanumeric()
372
+
373
+ // Number
374
+ v.number().required().between(18, 120).integer()
375
+ v.number().required().positive().nonZero().multipleOf(5)
376
+ v.number().required().length(6) // exactly 6 digits (PIN)
377
+
378
+ // Password with confirm-match
379
+ const passwordRef = useRef('')
380
+ // field 1
381
+ v.password().required().strong()
382
+ // field 2 — reads field 1's value via getter
383
+ v.password().required().confirmMatch(() => passwordRef.current)
384
+
385
+ // Email
386
+ v.email().required()
387
+ v.email().required().domain(['company.com', 'company.org']) // whitelist
388
+ v.email().required().blockedDomains(['mailinator.com', 'yopmail.com']) // blacklist
389
+
390
+ // URL
391
+ v.url().required().httpsOnly().noTrailingSlash()
392
+ v.url().required().allowedDomains(['github.com'])
393
+
394
+ // Phone
395
+ v.tel().required().length(10)
396
+ v.tel().required().minLength(7).maxLength(15)
397
+
398
+ // Date
399
+ v.date().required().notInPast()
400
+ v.date().required().notInFuture()
401
+ v.date().required().between(new Date('2020-01-01'), new Date('2030-12-31'))
402
+
403
+ // Select / Radio
404
+ v.select().required().shouldBeIn(['us', 'gb', 'in', 'au'])
405
+
406
+ // Boolean
407
+ v.boolean().mustBeTrue('You must accept the terms')
408
+
409
+ // Array (chipselect / taginput)
410
+ v.array().required().minItems(2).maxItems(5)
411
+ v.array().required().exactItems(3).noEmpty()
412
+
413
+ // File upload
414
+ v.file().required()
415
+ .maxSize(5 * 1024 * 1024)
416
+ .allowedTypes(['image/*', 'application/pdf'])
417
+ .maxFiles(3)
418
+
419
+ // Custom rule
420
+ v.string().required().custom(
421
+ 'noBadWords',
422
+ (val) => !String(val).includes('spam'),
423
+ 'Inappropriate content detected'
424
+ )
425
+ ```
426
+
427
+ ---
428
+
429
+ ### Display
430
+
431
+ | Component | Description |
432
+ |---|---|
433
+ | `Card` | Surface container with optional header, footer, and padding variants |
434
+ | `Box` | Generic styled `div` with spacing and color props |
435
+ | `Image` | Responsive image with aspect ratio (`square`/`video`/`portrait`) and `fit` control |
436
+ | `Avatar` / `AvatarGroup` | User avatar with fallback initials, status dot, and group stacking |
437
+ | `Badge` / `BadgeAnchor` | Status badge chip and notification dot anchor |
438
+ | `Tag` | Dismissible label chip with color variants |
439
+ | `Icon` | Lucide icon wrapper with `xs`/`sm`/`md`/`lg`/`xl` sizes |
440
+ | `SVG` | Raw SVG wrapper with size props |
441
+ | `Table` | Sortable, selectable data table with sticky header |
442
+ | `DataTable` | Full-featured table with server-side pagination and column visibility |
443
+ | `List` / `ListItem` | Semantic list with icon, description, and action slots |
444
+ | `Timeline` | Vertical event timeline with icon and color variants |
445
+ | `Stat` | Metric card with label, value, delta, and trend indicator |
446
+ | `EmptyState` | Zero-state placeholder with icon, title, description, and CTA |
447
+ | `MarkdownReader` | Renders Markdown with GFM tables and syntax-highlighted code blocks |
448
+ | `Collapsible` | Animated expand/collapse panel |
449
+ | `TreeView` | Recursive tree with expand/collapse nodes and selection |
450
+
451
+ ---
452
+
453
+ ### Feedback
454
+
455
+ | Component | Description |
456
+ |---|---|
457
+ | `Alert` | Inline status message — `info` / `success` / `warning` / `error` |
458
+ | `ToastProvider` + `useToast` | Global toast notification system with position control |
459
+ | `Spinner` | Loading spinner — `xs` through `xl` sizes |
460
+ | `Skeleton` / `SkeletonCard` | Content placeholder shimmer animations |
461
+ | `ProgressBar` | Linear progress with `default` / `success` / `warning` / `error` variants |
462
+ | `ErrorBoundary` | React error boundary with customizable fallback UI |
463
+ | `FullScreenLoader` + `useFullScreenLoader` | Full-viewport loading overlay with programmatic control |
149
464
 
150
465
  ```tsx
151
466
  import { ToastProvider, useToast } from 'react-18-ui-library'
152
467
 
153
- // Wrap your app
468
+ // Wrap your app root
154
469
  <ToastProvider toasts={toasts} onDismiss={dismiss} position="bottom-right" />
155
470
 
156
471
  // In any component
157
- const { toast } = useToast()
158
- toast({ title: 'Saved!', description: 'Changes saved successfully.', variant: 'success' })
472
+ const { toast, dismiss } = useToast()
473
+ toast({ title: 'Saved!', description: 'Changes saved.', variant: 'success' })
474
+ toast({ title: 'Error', description: 'Something went wrong.', variant: 'error' })
475
+ toast({ title: 'Warning', description: 'Low disk space.', variant: 'warning' })
159
476
  ```
160
477
 
161
- ## Development
478
+ ---
162
479
 
163
- ```bash
164
- # Install dependencies
165
- npm install
480
+ ### Overlay
166
481
 
167
- # Start Storybook
168
- npm run dev
482
+ | Component | Description |
483
+ |---|---|
484
+ | `Modal` | Radix Dialog modal — `sm`/`md`/`lg`/`xl`/`full` sizes |
485
+ | `Drawer` | Slide-in panel from `top`/`right`/`bottom`/`left` |
486
+ | `Tooltip` | Hover tooltip with `top`/`right`/`bottom`/`left` placement |
487
+ | `Popover` | Click-triggered floating panel |
488
+ | `ContextMenu` | Right-click context menu with icons and dividers |
489
+ | `ConfirmDialog` + `useConfirm` | Programmatic async confirmation dialog |
490
+ | `CommandPalette` + `useCommandPalette` | ⌘K-style command palette with groups and keyboard navigation, portal-rendered |
169
491
 
170
- # Build library
171
- npm run build
492
+ ```tsx
493
+ import { useConfirm, ConfirmDialogProvider } from 'react-18-ui-library'
172
494
 
173
- # Run tests
174
- npm test
495
+ // Wrap app root
496
+ <ConfirmDialogProvider>
497
+ <App />
498
+ </ConfirmDialogProvider>
499
+
500
+ // In any component
501
+ const confirm = useConfirm()
502
+ const ok = await confirm({
503
+ title: 'Delete record?',
504
+ description: 'This action cannot be undone.',
505
+ confirmLabel: 'Delete',
506
+ variant: 'destructive',
507
+ })
508
+ if (ok) deleteRecord()
175
509
  ```
176
510
 
511
+ ```tsx
512
+ import { CommandPalette, useCommandPalette } from 'react-18-ui-library'
513
+
514
+ const { open, close, isOpen } = useCommandPalette()
515
+
516
+ // Bind ⌘K
517
+ useKeyboard([{ key: 'k', meta: true, handler: open }])
518
+
519
+ <CommandPalette
520
+ open={isOpen}
521
+ onClose={close}
522
+ groups={[
523
+ {
524
+ id: 'nav',
525
+ label: 'Navigation',
526
+ items: [
527
+ { id: 'dashboard', label: 'Dashboard', icon: <LayoutDashboard size={14} />, onSelect: () => router.push('/') },
528
+ { id: 'settings', label: 'Settings', icon: <Settings size={14} />, onSelect: () => router.push('/settings') },
529
+ ],
530
+ },
531
+ ]}
532
+ />
533
+ ```
534
+
535
+ ---
536
+
537
+ ### Typography
538
+
539
+ | Component | Description |
540
+ |---|---|
541
+ | `Heading` | `h1`–`h6` with independent `size` (`xs`–`4xl`) and `weight` props |
542
+ | `Text` | Paragraph / span with `size`, `weight`, `color`, and polymorphic `as` prop |
543
+ | `Label` | Accessible form label |
544
+ | `Code` | Inline code or syntax-highlighted fenced code block (Prism) |
545
+ | `Link` | Anchor with `none`/`hover`/`always` underline variants |
546
+ | `Kbd` | Keyboard shortcut key display |
547
+
548
+ ```tsx
549
+ import { Heading, Text, Code, Kbd, Link } from 'react-18-ui-library'
550
+
551
+ <Heading level="h1" size="3xl" weight="bold">Welcome back</Heading>
552
+ <Text color="muted" size="sm">Last updated 2 minutes ago</Text>
553
+ <Text>
554
+ Press <Kbd>⌘</Kbd> + <Kbd>K</Kbd> to open the command palette.
555
+ </Text>
556
+ <Code block language="tsx">{`const x: number = 42`}</Code>
557
+ <Link href="/docs" underline="hover">Read the docs</Link>
558
+ ```
559
+
560
+ ---
561
+
562
+ ### Actions
563
+
564
+ | Component | Description |
565
+ |---|---|
566
+ | `CopyButton` | One-click copy to clipboard with animated feedback state |
567
+
568
+ ---
569
+
570
+ ## Hooks
571
+
572
+ | Hook | Signature | Description |
573
+ |---|---|---|
574
+ | `useToast` | `() => { toast, dismiss, toasts }` | Trigger and dismiss toast notifications |
575
+ | `useTheme` | `() => { tokens, setToken }` | Read and update CSS token values at runtime |
576
+ | `useMediaQuery` | `(query: string) => boolean` | Reactive media query boolean |
577
+ | `useClickOutside` | `(ref, handler)` | Fire handler when clicking outside a ref |
578
+ | `useDebounce` | `(value, delay) => value` | Debounce any value |
579
+ | `useLocalStorage` | `(key, initial) => [value, setter]` | Persistent state backed by `localStorage` |
580
+ | `useClipboard` | `() => { copy, copied }` | Copy text with `copied` feedback state |
581
+ | `useWindowSize` | `() => { width, height }` | Reactive window dimensions |
582
+ | `useIntersectionObserver` | `(ref, options) => entry` | Intersection Observer hook |
583
+ | `useKeyboard` | `(shortcuts[]) => void` | Bind keyboard shortcuts declaratively |
584
+ | `useConfirm` | `() => confirmFn` | Programmatic confirm dialog (needs `ConfirmDialogProvider`) |
585
+ | `useCommandPalette` | `() => { open, close, isOpen }` | Control the command palette |
586
+ | `useFullScreenLoader` | `() => { show, hide, isVisible }` | Show/hide the full-screen loading overlay |
587
+
588
+ ```tsx
589
+ import { useDebounce, useLocalStorage, useKeyboard, useClipboard } from 'react-18-ui-library'
590
+
591
+ const debouncedQuery = useDebounce(searchQuery, 300)
592
+ const [theme, setTheme] = useLocalStorage('theme', 'light')
593
+ const { copy, copied } = useClipboard()
594
+
595
+ useKeyboard([
596
+ { key: 'k', meta: true, handler: () => openPalette() },
597
+ { key: 'Escape', handler: () => closeModal() },
598
+ ])
599
+ ```
600
+
601
+ ---
602
+
177
603
  ## CSS Token Reference
178
604
 
179
605
  | Token | Default | Purpose |
180
606
  |---|---|---|
181
607
  | `--color-primary` | `#6366f1` | Primary brand color |
608
+ | `--color-primary-hover` | `#4f46e5` | Primary hover state |
609
+ | `--color-primary-foreground` | `#ffffff` | Text on primary background |
182
610
  | `--color-background` | `#f8fafc` | Page background |
183
- | `--color-surface` | `#ffffff` | Card/panel background |
611
+ | `--color-surface` | `#ffffff` | Card / panel background |
184
612
  | `--color-text` | `#0f172a` | Primary text |
185
- | `--color-text-muted` | `#64748b` | Secondary text |
186
- | `--color-border` | `#e2e8f0` | Border color |
187
- | `--color-error` | `#ef4444` | Error state |
188
- | `--color-success` | `#22c55e` | Success state |
613
+ | `--color-text-muted` | `#64748b` | Secondary / helper text |
614
+ | `--color-border` | `#e2e8f0` | Default border color |
615
+ | `--color-error` | `#ef4444` | Error / destructive state |
616
+ | `--color-success` | `#22c55e` | Success / positive state |
617
+ | `--color-warning` | `#f59e0b` | Warning / caution state |
618
+ | `--radius-sm` | `0.25rem` | Small border radius |
189
619
  | `--radius-md` | `0.375rem` | Default border radius |
190
- | `--font-family-base` | system-ui | Base font |
620
+ | `--radius-lg` | `0.5rem` | Large border radius |
621
+ | `--font-family-base` | `system-ui` | Base font family |
191
622
  | `--navbar-height` | `64px` | Navbar height |
192
623
  | `--sidebar-width` | `260px` | Sidebar expanded width |
193
624
  | `--sidebar-collapsed-width` | `64px` | Sidebar collapsed width |
194
625
 
626
+ ---
627
+
628
+ ## Security — Snyk
629
+
630
+ This library uses [Snyk](https://snyk.io) for dependency vulnerability scanning. Snyk runs automatically as a `prebuild` hook — the build is blocked if any **high** or **critical** severity vulnerabilities are found.
631
+
632
+ ### Setup (one-time)
633
+
634
+ ```bash
635
+ # Authenticate with Snyk (opens browser)
636
+ npx snyk auth
637
+ ```
638
+
639
+ ### Available security scripts
640
+
641
+ | Script | Description |
642
+ |---|---|
643
+ | `npm run snyk:test` | Scan for high + critical vulnerabilities (used in `prebuild`) |
644
+ | `npm run snyk:test:all` | Scan for all severities including low and medium |
645
+ | `npm run snyk:monitor` | Upload snapshot to Snyk dashboard for continuous monitoring |
646
+ | `npm run snyk:report` | Run scan and generate `reports/snyk-report.html` |
647
+ | `npm run snyk:report:html` | Save raw JSON results then generate HTML report |
648
+
649
+ ### How the build gate works
650
+
651
+ ```
652
+ npm run build
653
+ └─ prebuild → snyk test --severity-threshold=high
654
+ ├─ PASS → build proceeds normally
655
+ └─ FAIL → build aborted (exit code 1)
656
+ ```
657
+
658
+ The `.snyk` policy file at the project root can be used to suppress known/accepted vulnerabilities:
659
+
660
+ ```yaml
661
+ # .snyk
662
+ ignore:
663
+ SNYK-JS-EXAMPLE-12345:
664
+ - '*':
665
+ reason: Not exploitable in this context
666
+ expires: 2026-12-31T00:00:00.000Z
667
+ ```
668
+
669
+ ---
670
+
671
+ ## Development
672
+
673
+ ```bash
674
+ # Install dependencies
675
+ npm install
676
+
677
+ # Authenticate Snyk (first time only)
678
+ npx snyk auth
679
+
680
+ # Start Storybook dev server (port 6006)
681
+ npm run dev
682
+
683
+ # Type check
684
+ npm run type-check
685
+
686
+ # Run tests
687
+ npm test
688
+
689
+ # Run tests with coverage
690
+ npm run test:coverage
691
+
692
+ # Lint
693
+ npm run lint
694
+
695
+ # Build library (runs snyk:test first via prebuild hook)
696
+ npm run build
697
+
698
+ # Build Storybook static site
699
+ npm run build-storybook
700
+
701
+ # Run Snyk vulnerability scan
702
+ npm run snyk:test
703
+
704
+ # Generate HTML vulnerability report
705
+ npm run snyk:report:html
706
+ # → opens reports/snyk-report.html
707
+ ```
708
+
709
+ ---
710
+
195
711
  ## Peer Dependencies
196
712
 
197
- - `react >= 18.0.0`
198
- - `react-dom >= 18.0.0`
713
+ | Package | Version |
714
+ |---|---|
715
+ | `react` | `>= 18.0.0` |
716
+ | `react-dom` | `>= 18.0.0` |
717
+
718
+ > TailwindCSS is **not** a peer dependency — the library ships pre-compiled CSS. You do not need Tailwind in your consuming app.
719
+
720
+ ---
199
721
 
200
722
  ## License
201
723
 
202
- MIT
724
+ MIT © react-18-ui-library contributors
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "react-18-ui-library",
3
- "version": "0.1.0",
3
+ "version": "0.2.0",
4
4
  "description": "A fully customizable, theme-aware React 18 enterprise UI component library",
5
5
  "main": "dist/index.cjs.js",
6
6
  "module": "dist/index.esm.js",