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