@dashnex/ui 0.5.2

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 (75) hide show
  1. package/README.md +522 -0
  2. package/dashnex.json +1 -0
  3. package/dist/client.d.ts +10 -0
  4. package/dist/client.js +12 -0
  5. package/dist/components/Loading.d.ts +3 -0
  6. package/dist/components/Loading.js +4 -0
  7. package/dist/components/tailwind/alert.d.ts +28 -0
  8. package/dist/components/tailwind/alert.js +30 -0
  9. package/dist/components/tailwind/auth-layout.d.ts +4 -0
  10. package/dist/components/tailwind/auth-layout.js +4 -0
  11. package/dist/components/tailwind/avatar.d.ts +14 -0
  12. package/dist/components/tailwind/avatar.js +18 -0
  13. package/dist/components/tailwind/badge.d.ts +33 -0
  14. package/dist/components/tailwind/badge.js +33 -0
  15. package/dist/components/tailwind/button.d.ts +58 -0
  16. package/dist/components/tailwind/button.js +169 -0
  17. package/dist/components/tailwind/checkbox.d.ts +36 -0
  18. package/dist/components/tailwind/checkbox.js +83 -0
  19. package/dist/components/tailwind/combobox.d.ts +19 -0
  20. package/dist/components/tailwind/combobox.js +86 -0
  21. package/dist/components/tailwind/description-list.d.ts +3 -0
  22. package/dist/components/tailwind/description-list.js +11 -0
  23. package/dist/components/tailwind/dialog.d.ts +28 -0
  24. package/dist/components/tailwind/dialog.js +30 -0
  25. package/dist/components/tailwind/divider.d.ts +3 -0
  26. package/dist/components/tailwind/divider.js +5 -0
  27. package/dist/components/tailwind/dropdown.d.ts +32 -0
  28. package/dist/components/tailwind/dropdown.js +78 -0
  29. package/dist/components/tailwind/fieldset.d.ts +21 -0
  30. package/dist/components/tailwind/fieldset.js +24 -0
  31. package/dist/components/tailwind/heading.d.ts +6 -0
  32. package/dist/components/tailwind/heading.js +10 -0
  33. package/dist/components/tailwind/index.d.ts +27 -0
  34. package/dist/components/tailwind/index.js +28 -0
  35. package/dist/components/tailwind/input.d.ts +10 -0
  36. package/dist/components/tailwind/input.js +58 -0
  37. package/dist/components/tailwind/link.d.ts +11 -0
  38. package/dist/components/tailwind/link.js +13 -0
  39. package/dist/components/tailwind/listbox.d.ts +15 -0
  40. package/dist/components/tailwind/listbox.js +84 -0
  41. package/dist/components/tailwind/navbar.d.ts +14 -0
  42. package/dist/components/tailwind/navbar.js +42 -0
  43. package/dist/components/tailwind/pagination.d.ts +17 -0
  44. package/dist/components/tailwind/pagination.js +21 -0
  45. package/dist/components/tailwind/radio.d.ts +37 -0
  46. package/dist/components/tailwind/radio.js +86 -0
  47. package/dist/components/tailwind/select.d.ts +5 -0
  48. package/dist/components/tailwind/select.js +40 -0
  49. package/dist/components/tailwind/sidebar-layout.d.ts +5 -0
  50. package/dist/components/tailwind/sidebar-layout.js +18 -0
  51. package/dist/components/tailwind/sidebar.d.ts +18 -0
  52. package/dist/components/tailwind/sidebar.js +56 -0
  53. package/dist/components/tailwind/stacked-layout.d.ts +5 -0
  54. package/dist/components/tailwind/stacked-layout.js +18 -0
  55. package/dist/components/tailwind/switch.d.ts +36 -0
  56. package/dist/components/tailwind/switch.js +146 -0
  57. package/dist/components/tailwind/table.d.ts +16 -0
  58. package/dist/components/tailwind/table.js +40 -0
  59. package/dist/components/tailwind/text.d.ts +5 -0
  60. package/dist/components/tailwind/text.js +15 -0
  61. package/dist/components/tailwind/textarea.d.ts +6 -0
  62. package/dist/components/tailwind/textarea.js +36 -0
  63. package/dist/components/theme/index.d.ts +2 -0
  64. package/dist/components/theme/index.js +2 -0
  65. package/dist/components/theme/theme-provider.d.ts +14 -0
  66. package/dist/components/theme/theme-provider.js +83 -0
  67. package/dist/components/theme/theme-switcher.d.ts +1 -0
  68. package/dist/components/theme/theme-switcher.js +12 -0
  69. package/dist/pages/index.d.ts +2 -0
  70. package/dist/pages/index.js +1 -0
  71. package/dist/server.d.ts +8 -0
  72. package/dist/server.js +10 -0
  73. package/dist/tailwind.d.ts +1 -0
  74. package/dist/tailwind.js +1 -0
  75. package/package.json +73 -0
package/README.md ADDED
@@ -0,0 +1,522 @@
1
+ # @dashnex/ui
2
+
3
+ React UI component library for the Dashnex framework. Provides accessible Tailwind-based components (Headless UI), theme (light/dark/system), Heroicons re-export, and layout primitives for admin and app UIs.
4
+
5
+ ## Installation
6
+
7
+ <details>
8
+ <summary>pnpm</summary>
9
+
10
+ ```bash
11
+ pnpm add @dashnex/ui
12
+ ```
13
+
14
+ </details>
15
+
16
+ <details>
17
+ <summary>npm</summary>
18
+
19
+ ```bash
20
+ npm install @dashnex/ui
21
+ ```
22
+
23
+ </details>
24
+
25
+ <details>
26
+ <summary>yarn</summary>
27
+
28
+ ```bash
29
+ yarn add @dashnex/ui
30
+ ```
31
+
32
+ </details>
33
+
34
+ **Usage in code**
35
+
36
+ - **Client (pages, client components):** `import { Button, ThemeProvider } from '@dashnex/ui/client'`
37
+ - **Server or tailwind-only:** `import { Button } from '@dashnex/ui'` or `import { Button } from '@dashnex/ui/tailwind'`
38
+
39
+ ## Exported client functions, types, services
40
+
41
+ - **useTheme()** — hook; returns `{ theme, isDark, setTheme, toggleTheme, mounted }`. Use only inside `ThemeProvider`.
42
+
43
+ ## Exported UI components
44
+
45
+ **Layout:** `AuthLayout`, `StackedLayout`, `SidebarLayout`, `Sidebar`, `SidebarHeader`, `SidebarBody`, `SidebarFooter`, `SidebarSection`, `SidebarDivider`, `SidebarSpacer`, `SidebarHeading`, `SidebarItem`, `SidebarLabel`, `Navbar`, `NavbarDivider`, `NavbarSection`, `NavbarSpacer`, `NavbarItem`, `NavbarLabel`, `StackedLayout`, `SidebarLayout`.
46
+
47
+ **Forms / controls:** `Input`, `InputGroup`, `Select`, `Textarea`, `Checkbox`, `CheckboxGroup`, `CheckboxField`, `Radio`, `RadioGroup`, `RadioField`, `Switch`, `SwitchGroup`, `SwitchField`, `Fieldset`, `Legend`, `FieldGroup`, `Field`, `Label`, `Description`, `ErrorMessage`, `Combobox`, `ComboboxOption`, `ComboboxLabel`, `ComboboxDescription`, `Listbox`, `ListboxOption`, `ListboxLabel`, `ListboxDescription`.
48
+
49
+ **Overlays / feedback:** `Dialog`, `DialogTitle`, `DialogDescription`, `DialogBody`, `DialogActions`, `Alert`, `AlertTitle`, `AlertDescription`, `AlertBody`, `AlertActions`, `Dropdown`, `DropdownButton`, `DropdownMenu`, `DropdownItem`, `DropdownHeader`, `DropdownSection`, `DropdownHeading`, `DropdownDivider`, `DropdownLabel`, `DropdownDescription`, `DropdownShortcut`.
50
+
51
+ **Display:** `Button`, `TouchTarget`, `Link`, `Badge`, `BadgeButton`, `Avatar`, `AvatarButton`, `Text`, `TextLink`, `Strong`, `Code`, `Heading`, `Subheading`, `Divider`, `DescriptionList`, `DescriptionTerm`, `DescriptionDetails`, `Table`, `TableHead`, `TableBody`, `TableRow`, `TableHeader`, `TableCell`, `Pagination`, `PaginationPrevious`, `PaginationNext`, `PaginationList`, `PaginationPage`, `PaginationGap`.
52
+
53
+ **Theme:** `ThemeProvider`, `ThemeSwitcher`.
54
+
55
+ **Other:** `Loading`.
56
+
57
+ <details>
58
+ <summary>Link</summary>
59
+
60
+ ```tsx
61
+ import { Link } from '@dashnex/ui/client'
62
+
63
+ <Link href="/page">Go to page</Link>
64
+ ```
65
+
66
+ </details>
67
+
68
+ <details>
69
+ <summary>Button — solid, outline, plain, link</summary>
70
+
71
+ ```tsx
72
+ import { Button } from '@dashnex/ui/client'
73
+
74
+ // Solid (default). Optional: color (e.g. 'blue', 'red', 'zinc')
75
+ <Button color="blue">Save</Button>
76
+
77
+ // Outline
78
+ <Button outline>Cancel</Button>
79
+
80
+ // Plain (minimal)
81
+ <Button plain>Skip</Button>
82
+
83
+ // As link (pass href)
84
+ <Button href="/dashboard">Dashboard</Button>
85
+ ```
86
+
87
+ </details>
88
+
89
+ <details>
90
+ <summary>Input and InputGroup</summary>
91
+
92
+ ```tsx
93
+ import { Input, InputGroup } from '@dashnex/ui/client'
94
+
95
+ <Input type="email" placeholder="Email" />
96
+
97
+ // With leading icon (use data-slot="icon" on the icon element)
98
+ <InputGroup>
99
+ <span data-slot="icon">…</span>
100
+ <Input type="search" placeholder="Search" />
101
+ </InputGroup>
102
+ ```
103
+
104
+ </details>
105
+
106
+ <details>
107
+ <summary>Dialog</summary>
108
+
109
+ ```tsx
110
+ import { Dialog, DialogTitle, DialogDescription, DialogBody, DialogActions } from '@dashnex/ui/client'
111
+
112
+ <Dialog open={open} onClose={() => setOpen(false)} size="lg">
113
+ <DialogTitle>Title</DialogTitle>
114
+ <DialogDescription>Description text.</DialogDescription>
115
+ <DialogBody>Content here.</DialogBody>
116
+ <DialogActions>
117
+ <Button plain onClick={() => setOpen(false)}>Cancel</Button>
118
+ <Button color="blue">Confirm</Button>
119
+ </DialogActions>
120
+ </Dialog>
121
+ ```
122
+
123
+ `size` is optional: `'xs' | 'sm' | 'md' | 'lg' | 'xl' | '2xl' | '3xl' | '4xl' | '5xl'` (default `'lg'`).
124
+
125
+ </details>
126
+
127
+ <details>
128
+ <summary>Alert (modal dialog style)</summary>
129
+
130
+ ```tsx
131
+ import { Alert, AlertTitle, AlertDescription, AlertBody, AlertActions } from '@dashnex/ui/client'
132
+
133
+ <Alert open={open} onClose={() => setOpen(false)} size="md">
134
+ <AlertTitle>Alert</AlertTitle>
135
+ <AlertDescription>Message.</AlertDescription>
136
+ <AlertBody>Extra content.</AlertBody>
137
+ <AlertActions>
138
+ <Button color="blue" onClick={() => setOpen(false)}>OK</Button>
139
+ </AlertActions>
140
+ </Alert>
141
+ ```
142
+
143
+ `size` optional, same as Dialog.
144
+
145
+ </details>
146
+
147
+ <details>
148
+ <summary>Select</summary>
149
+
150
+ ```tsx
151
+ import { Select } from '@dashnex/ui/client'
152
+
153
+ <Select value={value} onChange={(e) => setValue(e.target.value)}>
154
+ <option value="a">Option A</option>
155
+ <option value="b">Option B</option>
156
+ </Select>
157
+ ```
158
+
159
+ Optional: `multiple` for multi-select.
160
+
161
+ </details>
162
+
163
+ <details>
164
+ <summary>Table (optional striped, dense, grid, clickable row)</summary>
165
+
166
+ ```tsx
167
+ import { Table, TableHead, TableBody, TableRow, TableHeader, TableCell } from '@dashnex/ui/client'
168
+
169
+ <Table striped dense grid>
170
+ <TableHead>
171
+ <TableRow>
172
+ <TableHeader>Name</TableHeader>
173
+ <TableHeader>Status</TableHeader>
174
+ </TableRow>
175
+ </TableHead>
176
+ <TableBody>
177
+ <TableRow href="/item/1" title="View">
178
+ <TableCell>Item 1</TableCell>
179
+ <TableCell>Active</TableCell>
180
+ </TableRow>
181
+ </TableBody>
182
+ </Table>
183
+ ```
184
+
185
+ Optional props on `Table`: `bleed`, `dense`, `grid`, `striped`. Optional on `TableRow`: `href`, `target`, `title` for clickable rows.
186
+
187
+ </details>
188
+
189
+ <details>
190
+ <summary>Badge and BadgeButton</summary>
191
+
192
+ ```tsx
193
+ import { Badge, BadgeButton } from '@dashnex/ui/client'
194
+
195
+ <Badge color="green">Active</Badge>
196
+
197
+ <BadgeButton color="zinc" onClick={handleClick}>Tag</BadgeButton>
198
+ <BadgeButton href="/tags/1" color="blue">Tag link</BadgeButton>
199
+ ```
200
+
201
+ `color` optional (e.g. `'red'`, `'green'`, `'zinc'`), default `'zinc'`.
202
+
203
+ </details>
204
+
205
+ <details>
206
+ <summary>Avatar and AvatarButton</summary>
207
+
208
+ ```tsx
209
+ import { Avatar, AvatarButton } from '@dashnex/ui/client'
210
+
211
+ <Avatar src="/photo.jpg" alt="User" />
212
+ <Avatar initials="JD" alt="John Doe" />
213
+ <Avatar square initials="AB" />
214
+
215
+ <AvatarButton src="/photo.jpg" onClick={handleClick} />
216
+ <AvatarButton href="/profile" initials="JD" />
217
+ ```
218
+
219
+ Optional: `src`, `square`, `initials`, `alt`. As link use `href`.
220
+
221
+ </details>
222
+
223
+ <details>
224
+ <summary>Dropdown</summary>
225
+
226
+ ```tsx
227
+ import { Dropdown, DropdownButton, DropdownMenu, DropdownItem } from '@dashnex/ui/client'
228
+
229
+ <Dropdown>
230
+ <DropdownButton>Actions</DropdownButton>
231
+ <DropdownMenu anchor="bottom">
232
+ <DropdownItem onClick={handleEdit}>Edit</DropdownItem>
233
+ <DropdownItem href="/view">View</DropdownItem>
234
+ </DropdownMenu>
235
+ </Dropdown>
236
+ ```
237
+
238
+ `DropdownMenu` optional `anchor`: `'bottom'` (default) or other Headless anchor values. `DropdownItem` can be button (onClick) or link (href).
239
+
240
+ </details>
241
+
242
+ <details>
243
+ <summary>Combobox (searchable select)</summary>
244
+
245
+ ```tsx
246
+ import { Combobox, ComboboxOption, ComboboxLabel } from '@dashnex/ui/client'
247
+
248
+ const options = [{ id: '1', name: 'Alpha' }, { id: '2', name: 'Beta' }]
249
+
250
+ <Combobox
251
+ value={selected}
252
+ onChange={setSelected}
253
+ options={options}
254
+ displayValue={(v) => v?.name}
255
+ filter={(opt, q) => opt.name.toLowerCase().includes(q.toLowerCase())}
256
+ placeholder="Search…"
257
+ aria-label="Choose option"
258
+ >
259
+ {(option) => (
260
+ <ComboboxOption key={option.id} value={option}>
261
+ <ComboboxLabel>{option.name}</ComboboxLabel>
262
+ </ComboboxOption>
263
+ )}
264
+ </Combobox>
265
+ ```
266
+
267
+ `filter` is optional; default is case-insensitive match on `displayValue(option)`. `anchor` optional `'top' | 'bottom'`.
268
+
269
+ </details>
270
+
271
+ <details>
272
+ <summary>Listbox (single select)</summary>
273
+
274
+ ```tsx
275
+ import { Listbox, ListboxOption, ListboxLabel } from '@dashnex/ui/client'
276
+
277
+ const options = [{ id: '1', name: 'One' }, { id: '2', name: 'Two' }]
278
+
279
+ <Listbox value={selected} onChange={setSelected} placeholder="Select" aria-label="Choose">
280
+ <ListboxOption value={options[0]}>
281
+ <ListboxLabel>{options[0].name}</ListboxLabel>
282
+ </ListboxOption>
283
+ <ListboxOption value={options[1]}>
284
+ <ListboxLabel>{options[1].name}</ListboxLabel>
285
+ </ListboxOption>
286
+ </Listbox>
287
+ ```
288
+
289
+ </details>
290
+
291
+ <details>
292
+ <summary>Navbar and NavbarItem</summary>
293
+
294
+ ```tsx
295
+ import { Navbar, NavbarItem, NavbarSpacer } from '@dashnex/ui/client'
296
+
297
+ <Navbar>
298
+ <NavbarItem href="/" current>Home</NavbarItem>
299
+ <NavbarItem href="/settings">Settings</NavbarItem>
300
+ <NavbarSpacer />
301
+ <NavbarItem onClick={logout}>Log out</NavbarItem>
302
+ </Navbar>
303
+ ```
304
+
305
+ `current` optional; shows current-indicator. Use `href` for link or `onClick` for button.
306
+
307
+ </details>
308
+
309
+ <details>
310
+ <summary>Pagination</summary>
311
+
312
+ ```tsx
313
+ import { Pagination, PaginationPrevious, PaginationNext, PaginationList, PaginationPage, PaginationGap } from '@dashnex/ui/client'
314
+
315
+ <Pagination aria-label="Page navigation">
316
+ <PaginationPrevious href={prevUrl} />
317
+ <PaginationList>
318
+ <PaginationPage href="/?p=1" current>1</PaginationPage>
319
+ <PaginationGap />
320
+ <PaginationPage href="/?p=5">5</PaginationPage>
321
+ </PaginationList>
322
+ <PaginationNext href={nextUrl} />
323
+ </Pagination>
324
+ ```
325
+
326
+ Use `href={null}` for disabled Previous/Next.
327
+
328
+ </details>
329
+
330
+ <details>
331
+ <summary>Heading, Subheading, Text</summary>
332
+
333
+ ```tsx
334
+ import { Heading, Subheading, Text, TextLink, Strong, Code } from '@dashnex/ui/client'
335
+
336
+ <Heading level={1}>Page title</Heading>
337
+ <Subheading level={2}>Section</Subheading>
338
+
339
+ <Text>Body text.</Text>
340
+ <TextLink href="/more">Link</TextLink>
341
+ <Strong>Bold</Strong>
342
+ <Code>code</Code>
343
+ ```
344
+
345
+ `level` optional: 1–6 (Heading default 1, Subheading default 2).
346
+
347
+ </details>
348
+
349
+ <details>
350
+ <summary>AuthLayout</summary>
351
+
352
+ ```tsx
353
+ import { AuthLayout } from '@dashnex/ui/client'
354
+
355
+ <AuthLayout>
356
+ <form>…</form>
357
+ </AuthLayout>
358
+ ```
359
+
360
+ </details>
361
+
362
+ <details>
363
+ <summary>StackedLayout and SidebarLayout</summary>
364
+
365
+ ```tsx
366
+ import { StackedLayout, SidebarLayout, Navbar, Sidebar } from '@dashnex/ui/client'
367
+
368
+ // Stacked: navbar on top, sidebar in drawer on mobile
369
+ <StackedLayout
370
+ navbar={<Navbar>…</Navbar>}
371
+ sidebar={<Sidebar>…</Sidebar>}
372
+ >
373
+ Page content
374
+ </StackedLayout>
375
+
376
+ // SidebarLayout: fixed sidebar on desktop, drawer on mobile
377
+ <SidebarLayout navbar={…} sidebar={…}>
378
+ Page content
379
+ </SidebarLayout>
380
+ ```
381
+
382
+ </details>
383
+
384
+ <details>
385
+ <summary>Sidebar and SidebarItem</summary>
386
+
387
+ ```tsx
388
+ import { Sidebar, SidebarHeader, SidebarBody, SidebarFooter, SidebarSection, SidebarItem, SidebarLabel } from '@dashnex/ui/client'
389
+
390
+ <Sidebar>
391
+ <SidebarHeader>…</SidebarHeader>
392
+ <SidebarBody>
393
+ <SidebarSection>
394
+ <SidebarItem href="/" current><SidebarLabel>Home</SidebarLabel></SidebarItem>
395
+ </SidebarSection>
396
+ </SidebarBody>
397
+ <SidebarFooter>…</SidebarFooter>
398
+ </Sidebar>
399
+ ```
400
+
401
+ </details>
402
+
403
+ <details>
404
+ <summary>Divider, Fieldset, DescriptionList</summary>
405
+
406
+ ```tsx
407
+ import { Divider, Fieldset, Legend, FieldGroup, Field, Label, Description, ErrorMessage } from '@dashnex/ui/client'
408
+ import { DescriptionList, DescriptionTerm, DescriptionDetails } from '@dashnex/ui/client'
409
+
410
+ <Divider soft />
411
+
412
+ <Fieldset disabled={false}>
413
+ <Legend>Form section</Legend>
414
+ <FieldGroup>
415
+ <Field>
416
+ <Label>Name</Label>
417
+ <Input />
418
+ <Description>Helper text.</Description>
419
+ <ErrorMessage>Error text.</ErrorMessage>
420
+ </Field>
421
+ </FieldGroup>
422
+ </Fieldset>
423
+
424
+ <DescriptionList>
425
+ <DescriptionTerm>Label</DescriptionTerm>
426
+ <DescriptionDetails>Value</DescriptionDetails>
427
+ </DescriptionList>
428
+ ```
429
+
430
+ `Divider` optional `soft` (lighter border).
431
+
432
+ </details>
433
+
434
+ <details>
435
+ <summary>Checkbox, Radio, Switch</summary>
436
+
437
+ ```tsx
438
+ import { Checkbox, CheckboxField, CheckboxGroup, Label, Description } from '@dashnex/ui/client'
439
+ import { Radio, RadioGroup, RadioField } from '@dashnex/ui/client'
440
+ import { Switch, SwitchGroup, SwitchField } from '@dashnex/ui/client'
441
+
442
+ <CheckboxGroup>
443
+ <CheckboxField>
444
+ <Checkbox color="dark/zinc" checked={v} onChange={setV} />
445
+ <Label>Option</Label>
446
+ <Description>Optional description.</Description>
447
+ </CheckboxField>
448
+ </CheckboxGroup>
449
+
450
+ <RadioGroup value={v} onChange={setV} name="choice">
451
+ <RadioField>
452
+ <Radio value="a" color="dark/zinc" />
453
+ <Label>A</Label>
454
+ </RadioField>
455
+ </RadioGroup>
456
+
457
+ <SwitchField>
458
+ <Switch color="dark/zinc" checked={on} onChange={setOn} />
459
+ <Label>Toggle</Label>
460
+ </SwitchField>
461
+ ```
462
+
463
+ `color` optional on Checkbox, Radio, Switch (e.g. `'dark/zinc'`, `'blue'`).
464
+
465
+ </details>
466
+
467
+ <details>
468
+ <summary>Textarea</summary>
469
+
470
+ ```tsx
471
+ import { Textarea } from '@dashnex/ui/client'
472
+
473
+ <Textarea placeholder="Message" resizable />
474
+ ```
475
+
476
+ `resizable` optional (default `true`).
477
+
478
+ </details>
479
+
480
+ <details>
481
+ <summary>ThemeProvider and ThemeSwitcher</summary>
482
+
483
+ ```tsx
484
+ import { ThemeProvider, ThemeSwitcher, useTheme } from '@dashnex/ui/client'
485
+
486
+ <ThemeProvider>
487
+ <ThemeSwitcher />
488
+ <App />
489
+ </ThemeProvider>
490
+
491
+ // Anywhere under ThemeProvider
492
+ const { theme, setTheme, toggleTheme, isDark, mounted } = useTheme()
493
+ ```
494
+
495
+ </details>
496
+
497
+ <details>
498
+ <summary>Loading</summary>
499
+
500
+ ```tsx
501
+ import { Loading } from '@dashnex/ui/client'
502
+
503
+ <Loading />
504
+ <Loading>Loading message…</Loading>
505
+ ```
506
+
507
+ `children` optional; shows under the spinner.
508
+
509
+ </details>
510
+
511
+ ## Exported server exports
512
+
513
+ Same UI components and default export as client. Import from `@dashnex/ui` (or `@dashnex/ui/tailwind` for components only). No server-only functions or singletons.
514
+
515
+ ## External libraries used
516
+
517
+ | Package | Purpose |
518
+ |--------|----------|
519
+ | `@headlessui/react` | Accessible unstyled primitives (Dialog, Menu, Listbox, Combobox, etc.) |
520
+ | `@heroicons/react` | Icons (re-exported from `@dashnex/ui/client` as 20/solid) |
521
+ | `clsx` | Conditional class names |
522
+ | `framer-motion` | Layout and transition animations (e.g. NavbarItem, SidebarItem) |
package/dashnex.json ADDED
@@ -0,0 +1 @@
1
+ {}
@@ -0,0 +1,10 @@
1
+ export * from './components/tailwind/index.js';
2
+ export * from './components/theme/index.js';
3
+ export { Loading } from './components/Loading.js';
4
+ export * from '@heroicons/react/20/solid';
5
+ declare const _default: {
6
+ name: string;
7
+ version: string;
8
+ description: string;
9
+ };
10
+ export default _default;
package/dist/client.js ADDED
@@ -0,0 +1,12 @@
1
+ import packageJson from '../package.json' with { type: "json" };
2
+ import dashnexConfig from '../dashnex.json' with { type: "json" };
3
+ export * from './components/tailwind/index.js';
4
+ export * from './components/theme/index.js';
5
+ export { Loading } from './components/Loading.js';
6
+ export * from '@heroicons/react/20/solid';
7
+ export default {
8
+ name: packageJson.name,
9
+ version: packageJson.version,
10
+ description: packageJson.description,
11
+ ...dashnexConfig,
12
+ };
@@ -0,0 +1,3 @@
1
+ export declare function Loading({ children }: {
2
+ children?: React.ReactNode;
3
+ }): import("react/jsx-runtime").JSX.Element;
@@ -0,0 +1,4 @@
1
+ import { jsx as _jsx, jsxs as _jsxs } from "react/jsx-runtime";
2
+ export function Loading({ children }) {
3
+ return (_jsx("div", { className: "flex h-screen w-screen items-center justify-center", children: _jsxs("div", { className: "flex flex-col items-center gap-4", children: [_jsx("div", { className: "h-10 w-10 animate-spin rounded-full border-4 border-gray-300 border-t-blue-600 dark:border-gray-600 dark:border-t-blue-400" }), children] }) }));
4
+ }
@@ -0,0 +1,28 @@
1
+ import { DialogProps, DialogTitleProps, DescriptionProps } from '@headlessui/react';
2
+ import type React from 'react';
3
+ import { Text } from './text.js';
4
+ declare const sizes: {
5
+ xs: string;
6
+ sm: string;
7
+ md: string;
8
+ lg: string;
9
+ xl: string;
10
+ '2xl': string;
11
+ '3xl': string;
12
+ '4xl': string;
13
+ '5xl': string;
14
+ };
15
+ export declare function Alert({ size, className, children, ...props }: {
16
+ size?: keyof typeof sizes;
17
+ className?: string;
18
+ children: React.ReactNode;
19
+ } & Omit<DialogProps, 'as' | 'className'>): import("react/jsx-runtime").JSX.Element;
20
+ export declare function AlertTitle({ className, ...props }: {
21
+ className?: string;
22
+ } & Omit<DialogTitleProps, 'as' | 'className'>): import("react/jsx-runtime").JSX.Element;
23
+ export declare function AlertDescription({ className, ...props }: {
24
+ className?: string;
25
+ } & Omit<DescriptionProps<typeof Text>, 'as' | 'className'>): import("react/jsx-runtime").JSX.Element;
26
+ export declare function AlertBody({ className, ...props }: React.ComponentPropsWithoutRef<'div'>): import("react/jsx-runtime").JSX.Element;
27
+ export declare function AlertActions({ className, ...props }: React.ComponentPropsWithoutRef<'div'>): import("react/jsx-runtime").JSX.Element;
28
+ export {};
@@ -0,0 +1,30 @@
1
+ import { jsx as _jsx, jsxs as _jsxs } from "react/jsx-runtime";
2
+ import { Dialog, DialogBackdrop, DialogPanel, DialogTitle, Description } from '@headlessui/react';
3
+ import clsx from 'clsx';
4
+ import { Text } from './text.js';
5
+ const sizes = {
6
+ xs: 'sm:max-w-xs',
7
+ sm: 'sm:max-w-sm',
8
+ md: 'sm:max-w-md',
9
+ lg: 'sm:max-w-lg',
10
+ xl: 'sm:max-w-xl',
11
+ '2xl': 'sm:max-w-2xl',
12
+ '3xl': 'sm:max-w-3xl',
13
+ '4xl': 'sm:max-w-4xl',
14
+ '5xl': 'sm:max-w-5xl',
15
+ };
16
+ export function Alert({ size = 'md', className, children, ...props }) {
17
+ return (_jsxs(Dialog, { ...props, children: [_jsx(DialogBackdrop, { transition: true, className: "fixed inset-0 flex w-screen justify-center overflow-y-auto bg-zinc-950/15 px-2 py-2 transition duration-100 focus:outline-0 data-closed:opacity-0 data-enter:ease-out data-leave:ease-in sm:px-6 sm:py-8 lg:px-8 lg:py-16 dark:bg-zinc-950/50" }), _jsx("div", { className: "fixed inset-0 w-screen overflow-y-auto pt-6 sm:pt-0", children: _jsx("div", { className: "grid min-h-full grid-rows-[1fr_auto_1fr] justify-items-center p-8 sm:grid-rows-[1fr_auto_3fr] sm:p-4", children: _jsx(DialogPanel, { transition: true, className: clsx(className, sizes[size], 'row-start-2 w-full rounded-2xl bg-white p-8 shadow-lg ring-1 ring-zinc-950/10 sm:rounded-2xl sm:p-6 dark:bg-zinc-900 dark:ring-white/10 forced-colors:outline', 'transition duration-100 will-change-transform data-closed:opacity-0 data-enter:ease-out data-closed:data-enter:scale-95 data-leave:ease-in'), children: children }) }) })] }));
18
+ }
19
+ export function AlertTitle({ className, ...props }) {
20
+ return (_jsx(DialogTitle, { ...props, className: clsx(className, 'text-center text-base/6 font-semibold text-balance text-zinc-950 sm:text-left sm:text-sm/6 sm:text-wrap dark:text-white') }));
21
+ }
22
+ export function AlertDescription({ className, ...props }) {
23
+ return (_jsx(Description, { as: Text, ...props, className: clsx(className, 'mt-2 text-center text-pretty sm:text-left') }));
24
+ }
25
+ export function AlertBody({ className, ...props }) {
26
+ return _jsx("div", { ...props, className: clsx(className, 'mt-4') });
27
+ }
28
+ export function AlertActions({ className, ...props }) {
29
+ return (_jsx("div", { ...props, className: clsx(className, 'mt-6 flex flex-col-reverse items-center justify-end gap-3 *:w-full sm:mt-4 sm:flex-row sm:*:w-auto') }));
30
+ }
@@ -0,0 +1,4 @@
1
+ import type React from 'react';
2
+ export declare function AuthLayout({ children }: {
3
+ children: React.ReactNode;
4
+ }): import("react/jsx-runtime").JSX.Element;
@@ -0,0 +1,4 @@
1
+ import { jsx as _jsx } from "react/jsx-runtime";
2
+ export function AuthLayout({ children }) {
3
+ return (_jsx("main", { className: "flex min-h-dvh flex-col p-2", children: _jsx("div", { className: "flex grow items-center justify-center p-6 lg:rounded-lg lg:bg-white lg:p-10 lg:shadow-xs lg:ring-1 lg:ring-zinc-950/5 dark:lg:bg-zinc-900 dark:lg:ring-white/10", children: children }) }));
4
+ }
@@ -0,0 +1,14 @@
1
+ import * as Headless from '@headlessui/react';
2
+ import React from 'react';
3
+ type AvatarProps = {
4
+ src?: string | null;
5
+ square?: boolean;
6
+ initials?: string;
7
+ alt?: string;
8
+ className?: string;
9
+ };
10
+ export declare function Avatar({ src, square, initials, alt, className, ...props }: AvatarProps & React.ComponentPropsWithoutRef<'span'>): import("react/jsx-runtime").JSX.Element;
11
+ export declare const AvatarButton: React.ForwardRefExoticComponent<(AvatarProps & (Omit<Headless.ButtonProps<"button">, "className" | "as"> | Omit<Omit<{
12
+ href: string;
13
+ } & Omit<React.DetailedHTMLProps<React.AnchorHTMLAttributes<HTMLAnchorElement>, HTMLAnchorElement>, "ref"> & React.RefAttributes<HTMLAnchorElement>, "ref">, "className">)) & React.RefAttributes<HTMLElement>>;
14
+ export {};
@@ -0,0 +1,18 @@
1
+ import { jsx as _jsx, jsxs as _jsxs } from "react/jsx-runtime";
2
+ import * as Headless from '@headlessui/react';
3
+ import clsx from 'clsx';
4
+ import { forwardRef } from 'react';
5
+ import Image from 'next/image.js';
6
+ import { TouchTarget } from './button.js';
7
+ import { Link } from './link.js';
8
+ export function Avatar({ src = null, square = false, initials, alt = '', className, ...props }) {
9
+ return (_jsxs("span", { "data-slot": "avatar", ...props, className: clsx(className,
10
+ // Basic layout
11
+ 'inline-grid shrink-0 align-middle [--avatar-radius:20%] *:col-start-1 *:row-start-1', 'outline -outline-offset-1 outline-black/10 dark:outline-white/10', 'overflow-hidden',
12
+ // Border radius
13
+ square ? 'rounded-(--avatar-radius) *:rounded-(--avatar-radius)' : 'rounded-full *:rounded-full'), children: [initials && (_jsxs("svg", { className: "size-full fill-current p-[5%] text-[48px] font-medium uppercase select-none", viewBox: "0 0 100 100", "aria-hidden": alt ? undefined : 'true', children: [alt && _jsx("title", { children: alt }), _jsx("text", { x: "50%", y: "50%", alignmentBaseline: "middle", dominantBaseline: "middle", textAnchor: "middle", dy: ".125em", children: initials })] })), src && _jsx(Image, { className: "size-full", src: src, alt: alt, width: 100, height: 100 })] }));
14
+ }
15
+ export const AvatarButton = forwardRef(function AvatarButton({ src, square = false, initials, alt, className, ...props }, ref) {
16
+ const classes = clsx(className, square ? 'rounded-[20%]' : 'rounded-full', 'relative inline-grid focus:not-data-focus:outline-hidden data-focus:outline-2 data-focus:outline-offset-2 data-focus:outline-blue-500');
17
+ return 'href' in props ? (_jsx(Link, { ...props, className: classes, ref: ref, children: _jsx(TouchTarget, { children: _jsx(Avatar, { src: src, square: square, initials: initials, alt: alt }) }) })) : (_jsx(Headless.Button, { ...props, className: classes, ref: ref, children: _jsx(TouchTarget, { children: _jsx(Avatar, { src: src, square: square, initials: initials, alt: alt }) }) }));
18
+ });