@webjsdev/ui 0.3.8 → 0.3.10

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 (47) hide show
  1. package/README.md +14 -5
  2. package/package.json +2 -1
  3. package/packages/registry/components/accordion.ts +20 -15
  4. package/packages/registry/components/alert-dialog.ts +19 -17
  5. package/packages/registry/components/alert.ts +20 -18
  6. package/packages/registry/components/aspect-ratio.ts +11 -9
  7. package/packages/registry/components/avatar.ts +20 -12
  8. package/packages/registry/components/badge.ts +7 -5
  9. package/packages/registry/components/breadcrumb.ts +17 -15
  10. package/packages/registry/components/button.ts +8 -6
  11. package/packages/registry/components/card.ts +18 -14
  12. package/packages/registry/components/checkbox.ts +6 -4
  13. package/packages/registry/components/collapsible.ts +14 -12
  14. package/packages/registry/components/dialog.ts +30 -24
  15. package/packages/registry/components/dropdown-menu.ts +22 -20
  16. package/packages/registry/components/hover-card.ts +18 -10
  17. package/packages/registry/components/input.ts +6 -4
  18. package/packages/registry/components/kbd.ts +11 -9
  19. package/packages/registry/components/label.ts +6 -4
  20. package/packages/registry/components/native-select.ts +12 -10
  21. package/packages/registry/components/pagination.ts +15 -11
  22. package/packages/registry/components/popover.ts +24 -16
  23. package/packages/registry/components/progress.ts +8 -6
  24. package/packages/registry/components/radio-group.ts +14 -12
  25. package/packages/registry/components/separator.ts +8 -6
  26. package/packages/registry/components/skeleton.ts +6 -4
  27. package/packages/registry/components/sonner.ts +16 -12
  28. package/packages/registry/components/switch.ts +13 -11
  29. package/packages/registry/components/table.ts +21 -19
  30. package/packages/registry/components/tabs.ts +30 -12
  31. package/packages/registry/components/textarea.ts +6 -4
  32. package/packages/registry/components/toggle-group.ts +15 -13
  33. package/packages/registry/components/toggle.ts +17 -14
  34. package/packages/registry/components/tooltip.ts +10 -8
  35. package/packages/registry/lib/utils.ts +34 -8
  36. package/packages/registry/themes/index.css +11 -0
  37. package/src/commands/add.js +45 -1
  38. package/src/commands/diff.js +20 -3
  39. package/src/commands/init.js +17 -25
  40. package/src/commands/list.js +2 -2
  41. package/src/commands/view.js +18 -3
  42. package/src/registry/example.js +120 -0
  43. package/src/registry/extract.js +145 -0
  44. package/src/registry/fetcher.js +60 -2
  45. package/src/registry/local.js +207 -0
  46. package/src/registry/resolver.js +2 -2
  47. package/src/utils/theme.js +68 -0
package/README.md CHANGED
@@ -94,17 +94,26 @@ and picks sensible defaults.
94
94
 
95
95
  Copies the component's `.ts` source into `components/ui/<name>.ts` (or your
96
96
  configured alias). Resolves transitive deps via `registryDependencies` and
97
- auto-installs npm deps like `@floating-ui/dom` for popover-style components.
97
+ auto-installs npm deps like `@floating-ui/dom` for popover-style components. For
98
+ a Tier-1 class-helper component it copies the helpers plus a lean header and a
99
+ one-line pointer, and leaves the worked structural example OUT of the file (get
100
+ it on demand with `webjsui view <name>`). It also self-heals the theme tokens if
101
+ they are missing.
102
+
103
+ Resolution is LOCAL-FIRST: `init` / `add` / `list` / `view` read the registry
104
+ that ships inside the installed `@webjsdev/ui` package, so they work with no
105
+ network. Point at a custom registry with `--registry <url>`; `webjsui diff`
106
+ always compares against the live upstream.
98
107
 
99
108
  ## Commands
100
109
 
101
110
  | Command | Effect |
102
111
  |---|---|
103
- | `webjsui init` | Initialize a project (writes `components.json`, theme CSS, `lib/utils.ts`) |
104
- | `webjsui add <names...>` | Add components to your project |
112
+ | `webjsui init` | Initialize a project (writes `components.json`, `lib/utils.ts`, the theme tokens). Exits non-zero if the tokens cannot be written. |
113
+ | `webjsui add <names...>` | Add components (copies helpers + a pointer for Tier-1, self-heals theme tokens) |
105
114
  | `webjsui list` | List all available components |
106
- | `webjsui view <name>` | Print a component's source to stdout |
107
- | `webjsui diff [name]` | Show diff between your local copy and the registry |
115
+ | `webjsui view <name>` | Print a component's projected view (helpers + paste-ready example) and full source |
116
+ | `webjsui diff [name]` | Show diff between your local copy and the live registry |
108
117
  | `webjsui info` | Print project diagnostics |
109
118
  | `webjsui build` | (For registry authors) Compile a custom registry |
110
119
 
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@webjsdev/ui",
3
- "version": "0.3.8",
3
+ "version": "0.3.10",
4
4
  "type": "module",
5
5
  "description": "An AI-first component library - class-helper functions for visuals, custom elements only where state matters. Source-copied into your repo, you own it. Works with any Tailwind v4 project.",
6
6
  "bin": {
@@ -10,6 +10,7 @@
10
10
  "exports": {
11
11
  ".": "./src/index.js",
12
12
  "./registry/schema": "./src/registry/schema.js",
13
+ "./registry/extract": "./src/registry/extract.js",
13
14
  "./utils": "./src/utils/index.js"
14
15
  },
15
16
  "files": [
@@ -15,21 +15,6 @@
15
15
  * <AccordionTrigger> → <summary class=${accordionTriggerClass()}>
16
16
  * <AccordionContent> → <div class=${accordionContentClass()}>
17
17
  *
18
- * Usage (single-open, exclusive):
19
- * <div class=${accordionClass()}>
20
- * <details name="faq" class=${accordionItemClass()}>
21
- * <summary class=${accordionTriggerClass()}>
22
- * <span>Is it accessible?</span>
23
- * <svg class="size-4 transition-transform group-open:rotate-180">…</svg>
24
- * </summary>
25
- * <div class=${accordionContentClass()}>Yes, native disclosure widget.</div>
26
- * </details>
27
- * <details name="faq" class=${accordionItemClass()} open>
28
- * <summary class=${accordionTriggerClass()}>Is it styled?</summary>
29
- * <div class=${accordionContentClass()}>Yes, shadcn design tokens.</div>
30
- * </details>
31
- * </div>
32
- *
33
18
  * Initial state: add `open` on the <details> that should render expanded
34
19
  * on first paint. Programmatic toggling: `el.open = true | false`.
35
20
  *
@@ -38,6 +23,26 @@
38
23
  * <ui-accordion> custom element set.
39
24
  *
40
25
  * Design tokens used: --border, --ring, --foreground.
26
+ *
27
+ * @example
28
+ * ```html
29
+ * <div class=${accordionClass()}>
30
+ * <details name="faq" class=${accordionItemClass()} open>
31
+ * <summary class=${accordionTriggerClass()}>
32
+ * <span>Is it accessible?</span>
33
+ * <svg class="size-4 shrink-0 transition-transform group-open:rotate-180" viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2" aria-hidden="true"><path d="m6 9 6 6 6-6" /></svg>
34
+ * </summary>
35
+ * <div class=${accordionContentClass()}>Yes, it uses a native disclosure widget.</div>
36
+ * </details>
37
+ * <details name="faq" class=${accordionItemClass()}>
38
+ * <summary class=${accordionTriggerClass()}>
39
+ * <span>Is it styled?</span>
40
+ * <svg class="size-4 shrink-0 transition-transform group-open:rotate-180" viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2" aria-hidden="true"><path d="m6 9 6 6 6-6" /></svg>
41
+ * </summary>
42
+ * <div class=${accordionContentClass()}>Yes, with the shadcn design tokens.</div>
43
+ * </details>
44
+ * </div>
45
+ * ```
41
46
  */
42
47
 
43
48
  /** Root wrapper. Holds the column-of-items rhythm; no display: rules. */
@@ -25,23 +25,6 @@
25
25
  * AlertDialogAction → <ui-alert-dialog-action variant size>
26
26
  * AlertDialogCancel → <ui-alert-dialog-cancel variant size>
27
27
  *
28
- * Usage:
29
- * <ui-alert-dialog>
30
- * <ui-alert-dialog-trigger>
31
- * <button class=${buttonClass({ variant: 'destructive' })}>Delete</button>
32
- * </ui-alert-dialog-trigger>
33
- * <ui-alert-dialog-content>
34
- * <div class=${alertDialogHeaderClass()}>
35
- * <h2 data-slot="alert-dialog-title" class=${alertDialogTitleClass()}>Delete account?</h2>
36
- * <p data-slot="alert-dialog-description" class=${alertDialogDescriptionClass()}>This cannot be undone.</p>
37
- * </div>
38
- * <div class=${alertDialogFooterClass()}>
39
- * <ui-alert-dialog-cancel>Cancel</ui-alert-dialog-cancel>
40
- * <ui-alert-dialog-action variant="destructive">Delete</ui-alert-dialog-action>
41
- * </div>
42
- * </ui-alert-dialog-content>
43
- * </ui-alert-dialog>
44
- *
45
28
  * Attributes on <ui-alert-dialog>:
46
29
  * `open`: boolean (reflected). Presence shows the dialog.
47
30
  *
@@ -62,6 +45,25 @@
62
45
  * Tab cycles trapped within the dialog (native focus trap).
63
46
  *
64
47
  * Design tokens used: --background, --border, --muted-foreground.
48
+ *
49
+ * @example
50
+ * ```html
51
+ * <ui-alert-dialog>
52
+ * <ui-alert-dialog-trigger>
53
+ * <button class=${buttonClass({ variant: 'destructive' })}>Delete</button>
54
+ * </ui-alert-dialog-trigger>
55
+ * <ui-alert-dialog-content>
56
+ * <div class=${alertDialogHeaderClass()}>
57
+ * <h2 data-slot="alert-dialog-title" class=${alertDialogTitleClass()}>Delete account?</h2>
58
+ * <p data-slot="alert-dialog-description" class=${alertDialogDescriptionClass()}>This cannot be undone.</p>
59
+ * </div>
60
+ * <div class=${alertDialogFooterClass()}>
61
+ * <ui-alert-dialog-cancel>Cancel</ui-alert-dialog-cancel>
62
+ * <ui-alert-dialog-action variant="destructive">Delete</ui-alert-dialog-action>
63
+ * </div>
64
+ * </ui-alert-dialog-content>
65
+ * </ui-alert-dialog>
66
+ * ```
65
67
  */
66
68
  import { WebComponent, html, prop } from '@webjsdev/core';
67
69
  import { ref, createRef } from '@webjsdev/core/directives';
@@ -7,30 +7,32 @@
7
7
  * AlertTitle → alertTitleClass()
8
8
  * AlertDescription → alertDescriptionClass()
9
9
  *
10
- * Usage:
11
- * <div role="alert" class=${alertClass()}>
12
- * <svg>…</svg>
13
- * <div data-slot="alert-title" class=${alertTitleClass()}>Heads up</div>
14
- * <div data-slot="alert-description" class=${alertDescriptionClass()}>
15
- * Something happened. Probably fine.
16
- * </div>
17
- * </div>
18
- *
19
- * <!-- Destructive variant: accent stripe + colored title/description. -->
20
- * <div role="alert" class=${alertClass({ variant: 'destructive' })}>
21
- * <svg>…</svg>
22
- * <div data-slot="alert-title" class=${alertTitleClass()}>Failed</div>
23
- * <div data-slot="alert-description" class=${alertDescriptionClass()}>
24
- * Couldn't save your changes.
25
- * </div>
26
- * </div>
27
- *
28
10
  * A11y (required for accessible output): put role="alert" on the container
29
11
  * for an urgent, interrupting message, or role="status" for a polite,
30
12
  * non-urgent update. The class helper sets no role, so without one the
31
13
  * banner is silent to assistive tech.
32
14
  *
33
15
  * Design tokens used: --card, --card-foreground, --destructive, --muted-foreground.
16
+ *
17
+ * @example
18
+ * ```html
19
+ * <div role="alert" class=${alertClass()}>
20
+ * <svg class="size-4" viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2" aria-hidden="true"><circle cx="12" cy="12" r="10" /><path d="M12 16v-4M12 8h.01" /></svg>
21
+ * <div data-slot="alert-title" class=${alertTitleClass()}>Heads up</div>
22
+ * <div data-slot="alert-description" class=${alertDescriptionClass()}>
23
+ * Something happened. Probably fine.
24
+ * </div>
25
+ * </div>
26
+ *
27
+ * <!-- Destructive variant: accent stripe plus colored title and description. -->
28
+ * <div role="alert" class=${alertClass({ variant: 'destructive' })}>
29
+ * <svg class="size-4" viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2" aria-hidden="true"><path d="m21.73 18-8-14a2 2 0 0 0-3.48 0l-8 14A2 2 0 0 0 4 21h16a2 2 0 0 0 1.73-3Z" /><path d="M12 9v4M12 17h.01" /></svg>
30
+ * <div data-slot="alert-title" class=${alertTitleClass()}>Failed</div>
31
+ * <div data-slot="alert-description" class=${alertDescriptionClass()}>
32
+ * Couldn't save your changes.
33
+ * </div>
34
+ * </div>
35
+ * ```
34
36
  */
35
37
  import { cn } from '../lib/utils.ts';
36
38
 
@@ -6,17 +6,19 @@
6
6
  * shadcn parity:
7
7
  * AspectRatio (Radix primitive) → aspectRatioClass() + inline `aspect-ratio` style
8
8
  *
9
- * Usage:
10
- * <div style="aspect-ratio: 16/9;" class="${aspectRatioClass()}">
11
- * <img src="…" class="h-full w-full object-cover rounded-md">
12
- * </div>
9
+ * Design tokens used: none (layout only).
13
10
  *
14
- * <!-- Or with Tailwind's arbitrary aspect-ratio (no helper needed): -->
15
- * <div class="aspect-[16/9]">
16
- * <img …>
17
- * </div>
11
+ * @example
12
+ * ```html
13
+ * <div style="aspect-ratio: 16/9;" class="${aspectRatioClass()}">
14
+ * <img src="/hero.jpg" alt="Team offsite" class="h-full w-full object-cover rounded-md">
15
+ * </div>
18
16
  *
19
- * Design tokens used: none (layout only).
17
+ * <!-- Or with Tailwind's arbitrary aspect-ratio (no helper needed): -->
18
+ * <div class="aspect-[16/9]">
19
+ * <img src="/hero.jpg" alt="Team offsite" class="h-full w-full object-cover rounded-md">
20
+ * </div>
21
+ * ```
20
22
  */
21
23
 
22
24
  export const aspectRatioClass = (): string => 'relative w-full';
@@ -11,24 +11,32 @@
11
11
  * AvatarGroup → avatarGroupClass()
12
12
  * AvatarGroupCount → avatarGroupCountClass()
13
13
  *
14
- * Usage:
15
- * <span class=${avatarClass()} data-size="default" data-slot="avatar">
16
- * <img class=${avatarImageClass()} src="…" alt="…">
17
- * <span class=${avatarFallbackClass()}>VK</span>
18
- * </span>
19
- *
20
- * <div class=${avatarGroupClass()}>
21
- * <span class=${avatarClass()} data-size="default" data-slot="avatar">…</span>
22
- * <span class=${avatarClass()} data-size="default" data-slot="avatar">…</span>
23
- * <div class=${avatarGroupCountClass()}>+3</div>
24
- * </div>
25
- *
26
14
  * A11y (required for accessible output): the <img> MUST have an alt that
27
15
  * names the person (alt="Vivek Khandelwal"), or alt="" when a visible text
28
16
  * fallback already names them. Always provide the fallback <span> so the
29
17
  * avatar is still named if the image fails to load.
30
18
  *
31
19
  * Design tokens used: --muted, --muted-foreground, --primary, --background.
20
+ *
21
+ * @example
22
+ * ```html
23
+ * <span class=${avatarClass()} data-size="default" data-slot="avatar">
24
+ * <img class=${avatarImageClass()} src="/avatars/vivek.jpg" alt="Vivek Khandelwal">
25
+ * <span class=${avatarFallbackClass()}>VK</span>
26
+ * </span>
27
+ *
28
+ * <div class=${avatarGroupClass()}>
29
+ * <span class=${avatarClass()} data-size="default" data-slot="avatar">
30
+ * <img class=${avatarImageClass()} src="/avatars/vivek.jpg" alt="Vivek Khandelwal">
31
+ * <span class=${avatarFallbackClass()}>VK</span>
32
+ * </span>
33
+ * <span class=${avatarClass()} data-size="default" data-slot="avatar">
34
+ * <img class=${avatarImageClass()} src="/avatars/amir.jpg" alt="Amir Rao">
35
+ * <span class=${avatarFallbackClass()}>AR</span>
36
+ * </span>
37
+ * <div class=${avatarGroupCountClass()}>+3</div>
38
+ * </div>
39
+ * ```
32
40
  */
33
41
  import { cn } from '../lib/utils.ts';
34
42
 
@@ -6,11 +6,6 @@
6
6
  * Badge (variant: default | secondary | destructive | outline | ghost | link)
7
7
  * → badgeClass({ variant })
8
8
  *
9
- * Usage:
10
- * <span class=${badgeClass()}>New</span>
11
- * <span class=${badgeClass({ variant: 'destructive' })}>Error</span>
12
- * <a class=${badgeClass({ variant: 'link' })} href="/profile">@vivek</a>
13
- *
14
9
  * The `[a&]:hover:...` hover styles only apply when the element is an `<a>`,
15
10
  * so a static `<span>` doesn't pick up an unwanted hover.
16
11
  *
@@ -20,6 +15,13 @@
20
15
  *
21
16
  * Design tokens used: --primary, --secondary, --destructive, --foreground,
22
17
  * --accent, --border, --ring.
18
+ *
19
+ * @example
20
+ * ```html
21
+ * <span class=${badgeClass()}>New</span>
22
+ * <span class=${badgeClass({ variant: 'destructive' })}>Error</span>
23
+ * <a class=${badgeClass({ variant: 'link' })} href="/profile">@vivek</a>
24
+ * ```
23
25
  */
24
26
  import { cn } from '../lib/utils.ts';
25
27
 
@@ -11,27 +11,29 @@
11
11
  * BreadcrumbSeparator → breadcrumbSeparatorClass() (aria-hidden + role="presentation")
12
12
  * BreadcrumbEllipsis → breadcrumbEllipsisClass()
13
13
  *
14
- * Usage:
15
- * <nav aria-label="breadcrumb" data-slot="breadcrumb">
16
- * <ol class=${breadcrumbListClass()}>
17
- * <li class=${breadcrumbItemClass()}>
18
- * <a class=${breadcrumbLinkClass()} href="/">Home</a>
19
- * </li>
20
- * <li class=${breadcrumbSeparatorClass()} role="presentation" aria-hidden="true">
21
- * <svg>›</svg>
22
- * </li>
23
- * <li class=${breadcrumbItemClass()}>
24
- * <span class=${breadcrumbPageClass()} aria-current="page">Posts</span>
25
- * </li>
26
- * </ol>
27
- * </nav>
28
- *
29
14
  * A11y (required for accessible output): wrap the list in <nav
30
15
  * aria-label="breadcrumb">, set aria-current="page" on the current-page
31
16
  * element, and mark each separator role="presentation" aria-hidden="true".
32
17
  * The class helpers emit none of these.
33
18
  *
34
19
  * Design tokens used: --muted-foreground, --foreground.
20
+ *
21
+ * @example
22
+ * ```html
23
+ * <nav aria-label="breadcrumb" data-slot="breadcrumb">
24
+ * <ol class=${breadcrumbListClass()}>
25
+ * <li class=${breadcrumbItemClass()}>
26
+ * <a class=${breadcrumbLinkClass()} href="/">Home</a>
27
+ * </li>
28
+ * <li class=${breadcrumbSeparatorClass()} role="presentation" aria-hidden="true">
29
+ * <svg class="size-3.5" viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2" aria-hidden="true"><path d="m9 18 6-6-6-6" /></svg>
30
+ * </li>
31
+ * <li class=${breadcrumbItemClass()}>
32
+ * <span class=${breadcrumbPageClass()} aria-current="page">Posts</span>
33
+ * </li>
34
+ * </ol>
35
+ * </nav>
36
+ * ```
35
37
  */
36
38
 
37
39
  export const breadcrumbListClass = (): string =>
@@ -8,12 +8,6 @@
8
8
  * (size: default | xs | sm | lg | icon | icon-xs | icon-sm | icon-lg)
9
9
  * → buttonClass({ variant, size })
10
10
  *
11
- * Usage:
12
- * <button class=${buttonClass()} type="submit">Save</button>
13
- * <button class=${buttonClass({ variant: 'outline', size: 'sm' })}>Cancel</button>
14
- * <button class=${buttonClass({ size: 'icon' })} aria-label="Settings">⚙</button>
15
- * <a class=${buttonClass({ variant: 'link' })} href="/about">About</a>
16
- *
17
11
  * shadcn React's `asChild` (Slot) prop has no equivalent here: just call
18
12
  * `buttonClass(...)` and spread the classes onto whatever element you want.
19
13
  *
@@ -26,6 +20,14 @@
26
20
  * Design tokens used: --primary, --primary-foreground, --destructive,
27
21
  * --secondary, --secondary-foreground, --accent, --accent-foreground,
28
22
  * --background, --input, --ring.
23
+ *
24
+ * @example
25
+ * ```html
26
+ * <button class=${buttonClass()} type="submit">Save</button>
27
+ * <button class=${buttonClass({ variant: 'outline', size: 'sm' })}>Cancel</button>
28
+ * <button class=${buttonClass({ size: 'icon' })} aria-label="Settings">⚙</button>
29
+ * <a class=${buttonClass({ variant: 'link' })} href="/about">About</a>
30
+ * ```
29
31
  */
30
32
  import { cn } from '../lib/utils.ts';
31
33
 
@@ -11,22 +11,26 @@
11
11
  * CardContent → cardContentClass()
12
12
  * CardFooter → cardFooterClass()
13
13
  *
14
- * Usage:
15
- * <div class=${cardClass()}>
16
- * <div class=${cardHeaderClass()}>
17
- * <div class=${cardTitleClass()}>Notifications</div>
18
- * <div class=${cardDescriptionClass()}>You have 3 unread messages.</div>
19
- * <div class=${cardActionClass()}>
20
- * <button class=${buttonClass({ variant: 'ghost', size: 'sm' })}>Mark all read</button>
21
- * </div>
22
- * </div>
23
- * <div class=${cardContentClass()}>…</div>
24
- * <div class=${cardFooterClass()}>
25
- * <button class=${buttonClass()}>Save</button>
14
+ * Design tokens used: --card, --card-foreground, --muted-foreground, --border.
15
+ *
16
+ * @example
17
+ * ```html
18
+ * <div class=${cardClass()}>
19
+ * <div class=${cardHeaderClass()}>
20
+ * <div class=${cardTitleClass()}>Notifications</div>
21
+ * <div class=${cardDescriptionClass()}>You have 3 unread messages.</div>
22
+ * <div class=${cardActionClass()}>
23
+ * <button class=${buttonClass({ variant: 'ghost', size: 'sm' })}>Mark all read</button>
26
24
  * </div>
27
25
  * </div>
28
- *
29
- * Design tokens used: --card, --card-foreground, --muted-foreground, --border.
26
+ * <div class=${cardContentClass()}>
27
+ * <p class="text-sm">Your weekly digest is ready to review.</p>
28
+ * </div>
29
+ * <div class=${cardFooterClass()}>
30
+ * <button class=${buttonClass()}>Save</button>
31
+ * </div>
32
+ * </div>
33
+ * ```
30
34
  */
31
35
 
32
36
  export type CardSize = 'default' | 'sm';
@@ -9,12 +9,14 @@
9
9
  * when checked, inset shadow, focus ring;
10
10
  * bypasses Radix)
11
11
  *
12
- * Usage:
13
- * <input type="checkbox" name="terms" id="terms" class=${checkboxClass()}>
14
- * <label class=${labelClass()} for="terms">I accept the terms</label>
15
- *
16
12
  * Design tokens used: --input, --primary, --primary-foreground, --background,
17
13
  * --ring, --destructive.
14
+ *
15
+ * @example
16
+ * ```html
17
+ * <input type="checkbox" name="terms" id="terms" class=${checkboxClass()}>
18
+ * <label class=${labelClass()} for="terms">I accept the terms</label>
19
+ * ```
18
20
  */
19
21
  import { cn } from '../lib/utils.ts';
20
22
 
@@ -10,24 +10,26 @@
10
10
  * CollapsibleTrigger → <summary class=${collapsibleTriggerClass()}>
11
11
  * CollapsibleContent → <div class=${collapsibleContentClass()}>
12
12
  *
13
- * Usage:
14
- * <details class=${collapsibleClass()}>
15
- * <summary class=${collapsibleTriggerClass()}>
16
- * Show details
17
- * <svg class="size-4 transition-transform group-open:rotate-180">…</svg>
18
- * </summary>
19
- * <div class=${collapsibleContentClass()}>
20
- * Hidden until <summary> is clicked, Enter / Space pressed, or the
21
- * <details> element's `open` property is set via JS.
22
- * </div>
23
- * </details>
24
- *
25
13
  * Initial state: add `open` on <details> to render expanded on first
26
14
  * paint. Programmatic toggling: `el.open = true | false`. Migrated from
27
15
  * the prior <ui-collapsible> custom element; the trigger class hides
28
16
  * the native disclosure marker so callers can render their own chevron.
29
17
  *
30
18
  * Design tokens used: --border, --ring, --foreground.
19
+ *
20
+ * @example
21
+ * ```html
22
+ * <details class=${collapsibleClass()}>
23
+ * <summary class=${collapsibleTriggerClass()}>
24
+ * Show details
25
+ * <svg class="size-4 transition-transform group-open:rotate-180" viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2" aria-hidden="true"><path d="m6 9 6 6 6-6" /></svg>
26
+ * </summary>
27
+ * <div class=${collapsibleContentClass()}>
28
+ * Hidden until <summary> is clicked, Enter / Space pressed, or the
29
+ * <details> element's `open` property is set via JS.
30
+ * </div>
31
+ * </details>
32
+ * ```
31
33
  */
32
34
 
33
35
  /**
@@ -22,30 +22,6 @@
22
22
  * DialogDescription → <p class=${dialogDescriptionClass()}>
23
23
  * DialogFooter → <div class=${dialogFooterClass()}>
24
24
  *
25
- * Usage:
26
- * <ui-dialog>
27
- * <ui-dialog-trigger>
28
- * <button class=${buttonClass({ variant: 'outline' })}>Edit profile</button>
29
- * </ui-dialog-trigger>
30
- * <ui-dialog-content>
31
- * <div class=${dialogHeaderClass()}>
32
- * <h2 data-slot="dialog-title" class=${dialogTitleClass()}>Edit profile</h2>
33
- * <p data-slot="dialog-description" class=${dialogDescriptionClass()}>Make changes and click save.</p>
34
- * </div>
35
- * <div class="grid gap-3">
36
- * <label class=${labelClass()} for="dlg-name">Name</label>
37
- * <input class=${inputClass()} id="dlg-name" placeholder="Your name">
38
- * </div>
39
- * <div class=${dialogFooterClass()}>
40
- * <ui-dialog-close><button class=${buttonClass({ variant: 'outline' })}>Cancel</button></ui-dialog-close>
41
- * <button class=${buttonClass()}>Save</button>
42
- * </div>
43
- * </ui-dialog-content>
44
- * </ui-dialog>
45
- *
46
- * <!-- Suppress the auto-injected top-right X close: -->
47
- * <ui-dialog-content show-close-button="false">…</ui-dialog-content>
48
- *
49
25
  * Attributes on <ui-dialog>:
50
26
  * `open`: boolean (reflected). Presence shows the dialog.
51
27
  *
@@ -62,6 +38,36 @@
62
38
  * within the dialog (native focus trap).
63
39
  *
64
40
  * Design tokens used: --background, --border, --muted-foreground.
41
+ *
42
+ * @example
43
+ * ```html
44
+ * <ui-dialog>
45
+ * <ui-dialog-trigger>
46
+ * <button class=${buttonClass({ variant: 'outline' })}>Edit profile</button>
47
+ * </ui-dialog-trigger>
48
+ * <ui-dialog-content>
49
+ * <div class=${dialogHeaderClass()}>
50
+ * <h2 data-slot="dialog-title" class=${dialogTitleClass()}>Edit profile</h2>
51
+ * <p data-slot="dialog-description" class=${dialogDescriptionClass()}>Make changes and click save.</p>
52
+ * </div>
53
+ * <div class="grid gap-3">
54
+ * <label class=${labelClass()} for="dlg-name">Name</label>
55
+ * <input class=${inputClass()} id="dlg-name" placeholder="Your name">
56
+ * </div>
57
+ * <div class=${dialogFooterClass()}>
58
+ * <ui-dialog-close><button class=${buttonClass({ variant: 'outline' })}>Cancel</button></ui-dialog-close>
59
+ * <button class=${buttonClass()}>Save</button>
60
+ * </div>
61
+ * </ui-dialog-content>
62
+ * </ui-dialog>
63
+ *
64
+ * <!-- Suppress the auto-injected top-right X close button. -->
65
+ * <ui-dialog-content show-close-button="false">
66
+ * <div class=${dialogHeaderClass()}>
67
+ * <h2 data-slot="dialog-title" class=${dialogTitleClass()}>Quiet dialog</h2>
68
+ * </div>
69
+ * </ui-dialog-content>
70
+ * ```
65
71
  */
66
72
  import { WebComponent, html, unsafeHTML, prop } from '@webjsdev/core';
67
73
  import { ref, createRef } from '@webjsdev/core/directives';
@@ -20,26 +20,6 @@
20
20
  * DropdownMenuSubTrigger → <ui-dropdown-menu-sub-trigger inset>
21
21
  * DropdownMenuSubContent → <ui-dropdown-menu-sub-content>
22
22
  *
23
- * Usage:
24
- * <ui-dropdown-menu>
25
- * <ui-dropdown-menu-trigger>
26
- * <button class=${buttonClass({ variant: 'outline' })}>Options</button>
27
- * </ui-dropdown-menu-trigger>
28
- * <ui-dropdown-menu-content align="end">
29
- * <ui-dropdown-menu-label>My Account</ui-dropdown-menu-label>
30
- * <ui-dropdown-menu-separator></ui-dropdown-menu-separator>
31
- * <ui-dropdown-menu-item>Profile</ui-dropdown-menu-item>
32
- * <ui-dropdown-menu-sub>
33
- * <ui-dropdown-menu-sub-trigger>Invite users</ui-dropdown-menu-sub-trigger>
34
- * <ui-dropdown-menu-sub-content>
35
- * <ui-dropdown-menu-item>Email</ui-dropdown-menu-item>
36
- * </ui-dropdown-menu-sub-content>
37
- * </ui-dropdown-menu-sub>
38
- * <ui-dropdown-menu-separator></ui-dropdown-menu-separator>
39
- * <ui-dropdown-menu-item variant="destructive">Sign out</ui-dropdown-menu-item>
40
- * </ui-dropdown-menu-content>
41
- * </ui-dropdown-menu>
42
- *
43
23
  * Attributes on <ui-dropdown-menu>:
44
24
  * `open`: boolean (reflected). Open state.
45
25
  *
@@ -76,6 +56,28 @@
76
56
  *
77
57
  * Design tokens used: --popover, --popover-foreground, --accent,
78
58
  * --accent-foreground, --destructive, --muted-foreground, --border.
59
+ *
60
+ * @example
61
+ * ```html
62
+ * <ui-dropdown-menu>
63
+ * <ui-dropdown-menu-trigger>
64
+ * <button class=${buttonClass({ variant: 'outline' })}>Options</button>
65
+ * </ui-dropdown-menu-trigger>
66
+ * <ui-dropdown-menu-content align="end">
67
+ * <ui-dropdown-menu-label>My Account</ui-dropdown-menu-label>
68
+ * <ui-dropdown-menu-separator></ui-dropdown-menu-separator>
69
+ * <ui-dropdown-menu-item>Profile</ui-dropdown-menu-item>
70
+ * <ui-dropdown-menu-sub>
71
+ * <ui-dropdown-menu-sub-trigger>Invite users</ui-dropdown-menu-sub-trigger>
72
+ * <ui-dropdown-menu-sub-content>
73
+ * <ui-dropdown-menu-item>Email</ui-dropdown-menu-item>
74
+ * </ui-dropdown-menu-sub-content>
75
+ * </ui-dropdown-menu-sub>
76
+ * <ui-dropdown-menu-separator></ui-dropdown-menu-separator>
77
+ * <ui-dropdown-menu-item variant="destructive">Sign out</ui-dropdown-menu-item>
78
+ * </ui-dropdown-menu-content>
79
+ * </ui-dropdown-menu>
80
+ * ```
79
81
  */
80
82
  import { WebComponent, html, unsafeHTML, signal, prop } from '@webjsdev/core';
81
83
  import { ensureId } from '../lib/utils.ts';
@@ -9,16 +9,6 @@
9
9
  * HoverCardTrigger → <ui-hover-card-trigger>
10
10
  * HoverCardContent → <ui-hover-card-content side align side-offset align-offset>
11
11
  *
12
- * Usage:
13
- * <ui-hover-card open-delay="700" close-delay="300">
14
- * <ui-hover-card-trigger>
15
- * <a href="/user/vivek">@vivek</a>
16
- * </ui-hover-card-trigger>
17
- * <ui-hover-card-content>
18
- * <div class="flex gap-3">…</div>
19
- * </ui-hover-card-content>
20
- * </ui-hover-card>
21
- *
22
12
  * Attributes on <ui-hover-card>:
23
13
  * `open`: boolean (reflected). Open state.
24
14
  * `open-delay`: ms, default 700. Hover delay before opening.
@@ -37,6 +27,24 @@
37
27
  * Programmatic API on <ui-hover-card>: `.show()` · `.hide()`.
38
28
  *
39
29
  * Design tokens used: --popover, --popover-foreground, --border.
30
+ *
31
+ * @example
32
+ * ```html
33
+ * <ui-hover-card open-delay="700" close-delay="300">
34
+ * <ui-hover-card-trigger>
35
+ * <a href="/user/vivek">@vivek</a>
36
+ * </ui-hover-card-trigger>
37
+ * <ui-hover-card-content>
38
+ * <div class="flex gap-3">
39
+ * <img class="size-10 rounded-full" src="/avatars/vivek.jpg" alt="Vivek Khandelwal">
40
+ * <div>
41
+ * <div class="text-sm font-semibold">Vivek Khandelwal</div>
42
+ * <p class="text-sm text-muted-foreground">Builds the platform, not against it.</p>
43
+ * </div>
44
+ * </div>
45
+ * </ui-hover-card-content>
46
+ * </ui-hover-card>
47
+ * ```
40
48
  */
41
49
  import { WebComponent, html, prop } from '@webjsdev/core';
42
50
  import { ensureId } from '../lib/utils.ts';