@webjsdev/ui 0.3.7 → 0.3.9

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 (49) 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 +21 -18
  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 +32 -25
  15. package/packages/registry/components/dropdown-menu.ts +24 -21
  16. package/packages/registry/components/hover-card.ts +20 -11
  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 +17 -13
  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 +16 -10
  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 +12 -9
  35. package/packages/registry/lib/dom.ts +18 -0
  36. package/packages/registry/lib/utils.ts +6 -105
  37. package/packages/registry/registry.json +25 -5
  38. package/src/commands/add.js +78 -14
  39. package/src/commands/diff.js +20 -3
  40. package/src/commands/init.js +41 -25
  41. package/src/commands/list.js +2 -2
  42. package/src/commands/view.js +18 -3
  43. package/src/registry/example.js +120 -0
  44. package/src/registry/extract.js +151 -0
  45. package/src/registry/fetcher.js +60 -2
  46. package/src/registry/local.js +207 -0
  47. package/src/registry/resolver.js +2 -2
  48. package/src/utils/detect-project.js +3 -1
  49. package/src/utils/theme.js +68 -0
@@ -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,9 +27,28 @@
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
- import { ensureId, onBeforeCache } from '../lib/utils.ts';
50
+ import { ensureId } from '../lib/utils.ts';
51
+ import { onBeforeCache } from '../lib/dom.ts';
43
52
  import { positionFloating, type PopoverSide, type PopoverAlign } from './popover.ts';
44
53
 
45
54
  // `fixed m-0` opts out of the UA `[popover]` auto-centering margin so
@@ -8,16 +8,18 @@
8
8
  * shadcn parity:
9
9
  * Input → inputClass()
10
10
  *
11
- * Usage:
12
- * <input class=${inputClass()} type="email" name="email" id="email" required
13
- * aria-describedby="email-hint">
14
- *
15
11
  * Pair with `<label class=${labelClass()} for="...">` and a hint paragraph
16
12
  * (`<p class=${hintClass()} id="...-hint">`). Wrap all three in
17
13
  * `<div class=${fieldClass()}>` for the canonical field rhythm.
18
14
  *
19
15
  * Design tokens used: --input, --background, --primary, --primary-foreground,
20
16
  * --muted-foreground, --foreground, --ring, --destructive.
17
+ *
18
+ * @example
19
+ * ```html
20
+ * <input class=${inputClass()} type="email" name="email" id="email" required
21
+ * aria-describedby="email-hint">
22
+ * ```
21
23
  */
22
24
  import { cn } from '../lib/utils.ts';
23
25
 
@@ -6,17 +6,19 @@
6
6
  * Kbd → kbdClass()
7
7
  * KbdGroup → kbdGroupClass()
8
8
  *
9
- * Usage:
10
- * <kbd class=${kbdClass()}>⌘</kbd>
11
- * <kbd class=${kbdClass()}>K</kbd>
9
+ * Design tokens used: --muted, --muted-foreground, --background.
12
10
  *
13
- * <div class=${kbdGroupClass()}>
14
- * <kbd class=${kbdClass()}>⌘</kbd>
15
- * <kbd class=${kbdClass()}>Shift</kbd>
16
- * <kbd class=${kbdClass()}>P</kbd>
17
- * </div>
11
+ * @example
12
+ * ```html
13
+ * <kbd class=${kbdClass()}>⌘</kbd>
14
+ * <kbd class=${kbdClass()}>K</kbd>
18
15
  *
19
- * Design tokens used: --muted, --muted-foreground, --background.
16
+ * <div class=${kbdGroupClass()}>
17
+ * <kbd class=${kbdClass()}>⌘</kbd>
18
+ * <kbd class=${kbdClass()}>Shift</kbd>
19
+ * <kbd class=${kbdClass()}>P</kbd>
20
+ * </div>
21
+ * ```
20
22
  */
21
23
 
22
24
  export const kbdClass = (): string =>
@@ -6,15 +6,17 @@
6
6
  * shadcn parity:
7
7
  * Label → labelClass()
8
8
  *
9
- * Usage:
10
- * <label class=${labelClass()} for="email">Email</label>
11
- * <input class=${inputClass()} id="email" name="email" type="email">
12
- *
13
9
  * Disabled-state inheritance: when the label is inside a container with
14
10
  * `data-disabled="true"` (the "field" pattern), or next to a peer-disabled
15
11
  * control, it dims automatically.
16
12
  *
17
13
  * Design tokens used: none (typography only).
14
+ *
15
+ * @example
16
+ * ```html
17
+ * <label class=${labelClass()} for="email">Email</label>
18
+ * <input class=${inputClass()} id="email" name="email" type="email">
19
+ * ```
18
20
  */
19
21
 
20
22
  /** Compose Tailwind classes for a native `<label>`. */
@@ -13,16 +13,6 @@
13
13
  * stylesheet sets Canvas / CanvasText on
14
14
  * every <option> automatically)
15
15
  *
16
- * Usage:
17
- * <div class=${nativeSelectWrapperClass()}>
18
- * <select class=${nativeSelectClass()} name="plan">
19
- * <option>Basic</option>
20
- * <option>Pro</option>
21
- * </select>
22
- * <!-- chevron icon, decorative -->
23
- * <svg class="${nativeSelectIconClass()}" aria-hidden="true">…</svg>
24
- * </div>
25
- *
26
16
  * Importing this module installs a stylesheet that forces Canvas /
27
17
  * CanvasText on every <option> inside the wrapper so the dropdown reads
28
18
  * in both light and dark themes regardless of OS preference; advanced
@@ -30,6 +20,18 @@
30
20
  *
31
21
  * Design tokens used: --input, --background, --primary, --primary-foreground,
32
22
  * --muted-foreground, --ring, --destructive.
23
+ *
24
+ * @example
25
+ * ```html
26
+ * <div class=${nativeSelectWrapperClass()}>
27
+ * <select class=${nativeSelectClass()} name="plan">
28
+ * <option>Basic</option>
29
+ * <option>Pro</option>
30
+ * </select>
31
+ * <!-- chevron icon, decorative -->
32
+ * <svg class="${nativeSelectIconClass()}" viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2" aria-hidden="true"><path d="m6 9 6 6 6-6" /></svg>
33
+ * </div>
34
+ * ```
33
35
  */
34
36
  import { cn } from '../lib/utils.ts';
35
37
 
@@ -12,23 +12,27 @@
12
12
  * PaginationNext → paginationNextClass()
13
13
  * PaginationEllipsis → paginationEllipsisClass()
14
14
  *
15
- * Usage:
16
- * <nav role="navigation" aria-label="pagination" class=${paginationClass()}>
17
- * <ul class=${paginationContentClass()}>
18
- * <li><a class=${paginationPreviousClass()} href="?page=1">‹ Previous</a></li>
19
- * <li><a class=${paginationLinkClass({ isActive: false })} href="?page=2">2</a></li>
20
- * <li><a class=${paginationLinkClass({ isActive: true })} aria-current="page">3</a></li>
21
- * <li class=${paginationEllipsisClass()} aria-hidden="true">…</li>
22
- * <li><a class=${paginationNextClass()} href="?page=4">Next ›</a></li>
23
- * </ul>
24
- * </nav>
25
- *
26
15
  * A11y (required for accessible output): wrap the list in <nav
27
16
  * aria-label="pagination">, set aria-current="page" on the active page
28
17
  * link, give an icon-only Previous / Next control an aria-label, and mark
29
18
  * the ellipsis aria-hidden="true". The class helpers emit none of these.
30
19
  *
31
20
  * Design tokens used: inherited from buttonClass.
21
+ *
22
+ * @example
23
+ * ```html
24
+ * <nav role="navigation" aria-label="pagination" class=${paginationClass()}>
25
+ * <ul class=${paginationContentClass()}>
26
+ * <li><a class=${paginationPreviousClass()} href="?page=1">‹ Previous</a></li>
27
+ * <li><a class=${paginationLinkClass({ isActive: false })} href="?page=2">2</a></li>
28
+ * <li><a class=${paginationLinkClass({ isActive: true })} aria-current="page">3</a></li>
29
+ * <li class=${paginationEllipsisClass()} aria-hidden="true">
30
+ * <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="1" /><circle cx="19" cy="12" r="1" /><circle cx="5" cy="12" r="1" /></svg>
31
+ * </li>
32
+ * <li><a class=${paginationNextClass()} href="?page=4">Next ›</a></li>
33
+ * </ul>
34
+ * </nav>
35
+ * ```
32
36
  */
33
37
  import { cn } from '../lib/utils.ts';
34
38
  import { buttonClass, type ButtonSize } from './button.ts';
@@ -18,28 +18,36 @@
18
18
  * PopoverTitle → popoverTitleClass()
19
19
  * PopoverDescription → popoverDescriptionClass()
20
20
  *
21
- * Usage (single invoker, implicit anchor, zero inline style):
22
- * <button popovertarget="filter" class=${buttonClass({ variant: 'outline' })}>Filter</button>
23
- * <div id="filter" popover
24
- * class=${popoverContentClass({ side: 'bottom', align: 'start', sideOffset: 4 })}>
25
- * <div class=${popoverHeaderClass()}>
26
- * <h3 class=${popoverTitleClass()}>Filter posts</h3>
27
- * <p class=${popoverDescriptionClass()}>By tag and status.</p>
28
- * </div>
29
- * </div>
30
- *
31
- * <!-- Explicit anchor (multiple invokers / anchoring to a different element): -->
32
- * <span style="anchor-name: --picker">@vivek</span>
33
- * <button popovertarget="profile">Show</button>
34
- * <div id="profile" popover style="position-anchor: --picker"
35
- * class=${popoverContentClass({ side: 'bottom' })}>…</div>
36
- *
37
21
  * The `positionFloating` helper is also exported (used by the Tier-2
38
22
  * tooltip / hover-card / dropdown-menu components for imperative
39
23
  * positioning where CSS Anchor Positioning isn't enough). Migrated from
40
24
  * the prior <ui-popover> custom element set.
41
25
  *
42
26
  * Design tokens used: --popover, --popover-foreground, --border.
27
+ *
28
+ * @example
29
+ * ```html
30
+ * <!-- Single invoker, implicit anchor, zero inline style. -->
31
+ * <button popovertarget="filter" class=${buttonClass({ variant: 'outline' })}>Filter</button>
32
+ * <div id="filter" popover
33
+ * class=${popoverContentClass({ side: 'bottom', align: 'start', sideOffset: 4 })}>
34
+ * <div class=${popoverHeaderClass()}>
35
+ * <h3 class=${popoverTitleClass()}>Filter posts</h3>
36
+ * <p class=${popoverDescriptionClass()}>By tag and status.</p>
37
+ * </div>
38
+ * </div>
39
+ *
40
+ * <!-- Explicit anchor, for multiple invokers or anchoring to a different element. -->
41
+ * <span style="anchor-name: --picker">@vivek</span>
42
+ * <button popovertarget="profile">Show</button>
43
+ * <div id="profile" popover style="position-anchor: --picker"
44
+ * class=${popoverContentClass({ side: 'bottom' })}>
45
+ * <div class=${popoverHeaderClass()}>
46
+ * <h3 class=${popoverTitleClass()}>Vivek Khandelwal</h3>
47
+ * <p class=${popoverDescriptionClass()}>@vivek</p>
48
+ * </div>
49
+ * </div>
50
+ * ```
43
51
  */
44
52
 
45
53
  // --------------------------------------------------------------------------
@@ -10,18 +10,20 @@
10
10
  * `::-webkit-progress-value`, and
11
11
  * `::-moz-progress-bar`)
12
12
  *
13
- * Usage:
14
- * <progress value="42" max="100" class=${progressClass()}></progress>
15
- *
16
- * <!-- Indeterminate (no `value` attribute): -->
17
- * <progress class=${progressClass()}></progress>
18
- *
19
13
  * A11y (required for accessible output): give the <progress> an accessible
20
14
  * name with aria-label (or a <label for>), e.g. aria-label="Upload
21
15
  * progress". The native element supplies the role and value; only the name
22
16
  * is the author's responsibility.
23
17
  *
24
18
  * Design tokens used: --primary.
19
+ *
20
+ * @example
21
+ * ```html
22
+ * <progress value="42" max="100" class=${progressClass()}></progress>
23
+ *
24
+ * <!-- Indeterminate state, with no value attribute. -->
25
+ * <progress class=${progressClass()}></progress>
26
+ * ```
25
27
  */
26
28
 
27
29
  /**
@@ -9,19 +9,21 @@
9
9
  * → radioGroupClass({ orientation }) on a <div role="radiogroup">
10
10
  * RadioGroupItem → radioClass() on a native <input type="radio">
11
11
  *
12
- * Usage:
13
- * <div role="radiogroup" class=${radioGroupClass()}>
14
- * <div class="flex items-center gap-2">
15
- * <input type="radio" name="plan" value="basic" id="plan-basic" class=${radioClass()}>
16
- * <label class=${labelClass()} for="plan-basic">Basic</label>
17
- * </div>
18
- * <div class="flex items-center gap-2">
19
- * <input type="radio" name="plan" value="pro" id="plan-pro" class=${radioClass()}>
20
- * <label class=${labelClass()} for="plan-pro">Pro</label>
21
- * </div>
22
- * </div>
23
- *
24
12
  * Design tokens used: --input, --primary, --ring, --destructive.
13
+ *
14
+ * @example
15
+ * ```html
16
+ * <div role="radiogroup" class=${radioGroupClass()}>
17
+ * <div class="flex items-center gap-2">
18
+ * <input type="radio" name="plan" value="basic" id="plan-basic" class=${radioClass()}>
19
+ * <label class=${labelClass()} for="plan-basic">Basic</label>
20
+ * </div>
21
+ * <div class="flex items-center gap-2">
22
+ * <input type="radio" name="plan" value="pro" id="plan-pro" class=${radioClass()}>
23
+ * <label class=${labelClass()} for="plan-pro">Pro</label>
24
+ * </div>
25
+ * </div>
26
+ * ```
25
27
  */
26
28
  import { cn } from '../lib/utils.ts';
27
29
 
@@ -7,18 +7,20 @@
7
7
  * Separator (orientation: horizontal | vertical, decorative: bool)
8
8
  * → separatorClass({ orientation }) + role + data-orientation
9
9
  *
10
- * Usage:
11
- * <div role="none" class=${separatorClass()} data-orientation="horizontal"></div>
12
- * <div role="separator" aria-orientation="vertical"
13
- * class=${separatorClass({ orientation: 'vertical' })}
14
- * data-orientation="vertical"></div>
15
- *
16
10
  * A11y (required for accessible output): a meaningful divider needs
17
11
  * role="separator" plus aria-orientation. A purely decorative one needs
18
12
  * role="none" (or aria-hidden="true") so assistive tech does not announce
19
13
  * an empty separator.
20
14
  *
21
15
  * Design tokens used: --border.
16
+ *
17
+ * @example
18
+ * ```html
19
+ * <div role="none" class=${separatorClass()} data-orientation="horizontal"></div>
20
+ * <div role="separator" aria-orientation="vertical"
21
+ * class=${separatorClass({ orientation: 'vertical' })}
22
+ * data-orientation="vertical"></div>
23
+ * ```
22
24
  */
23
25
  import { cn } from '../lib/utils.ts';
24
26
 
@@ -6,16 +6,18 @@
6
6
  * shadcn parity:
7
7
  * Skeleton → skeletonClass() (visual: animated rounded muted block)
8
8
  *
9
- * Usage:
10
- * <div class=${cn(skeletonClass(), 'h-4 w-32')}></div>
11
- * <div class=${cn(skeletonClass(), 'h-12 w-12 rounded-full')}></div>
12
- *
13
9
  * A11y (required for accessible output): a skeleton is a decorative
14
10
  * placeholder, so hide it from assistive tech with aria-hidden="true" (or
15
11
  * mark the loading region aria-busy="true"). Announce the real content
16
12
  * once it replaces the skeleton.
17
13
  *
18
14
  * Design tokens used: --accent.
15
+ *
16
+ * @example
17
+ * ```html
18
+ * <div class=${cn(skeletonClass(), 'h-4 w-32')}></div>
19
+ * <div class=${cn(skeletonClass(), 'h-12 w-12 rounded-full')}></div>
20
+ * ```
19
21
  */
20
22
 
21
23
  export const skeletonClass = (): string => 'animate-pulse rounded-md bg-accent';
@@ -12,18 +12,6 @@
12
12
  * → toast() (plus toast.success / .error / .info / .warning /
13
13
  * .loading / .promise / .dismiss)
14
14
  *
15
- * Usage:
16
- * <!-- Mount once at the root of your app (typically in layout.ts): -->
17
- * <ui-sonner position="bottom-right"></ui-sonner>
18
- *
19
- * // Then from anywhere (server or client component):
20
- * import { toast } from '@/components/ui/sonner.ts';
21
- * toast('Saved!');
22
- * toast.success('Account created');
23
- * toast.error('Failed to save', { description: 'Try again' });
24
- * toast.promise(savePost(), { loading: 'Saving…', success: 'Saved', error: 'Failed' });
25
- * toast.dismiss(id);
26
- *
27
15
  * Attributes on <ui-sonner>:
28
16
  * `position`: "top-left" | "top-center" | "top-right" |
29
17
  * "bottom-left" | "bottom-center" | "bottom-right" (default).
@@ -42,9 +30,25 @@
42
30
  * uses); typically only needed when mounting multiple viewports.
43
31
  *
44
32
  * Design tokens used: --popover, --popover-foreground, --border, --radius.
33
+ *
34
+ * @example
35
+ * ```html
36
+ * <!-- Mount once at the root of your app, typically in layout.ts. -->
37
+ * <ui-sonner position="bottom-right"></ui-sonner>
38
+ *
39
+ * <!-- Then from anywhere, in a server or client component, call the API. -->
40
+ * <script type="module">
41
+ * import { toast } from '@/components/ui/sonner.ts';
42
+ * toast('Saved!');
43
+ * toast.success('Account created');
44
+ * toast.error('Failed to save', { description: 'Try again' });
45
+ * toast.promise(savePost(), { loading: 'Saving', success: 'Saved', error: 'Failed' });
46
+ * toast.dismiss(id);
47
+ * </script>
48
+ * ```
45
49
  */
46
50
  import { WebComponent, html, repeat, unsafeHTML, signal, prop } from '@webjsdev/core';
47
- import { onBeforeCache } from '../lib/utils.ts';
51
+ import { onBeforeCache } from '../lib/dom.ts';
48
52
 
49
53
  type ToastType = 'default' | 'success' | 'error' | 'info' | 'warning' | 'loading';
50
54
 
@@ -8,19 +8,21 @@
8
8
  * Switch (size: default | sm) → switchInputClass() on a hidden <input> +
9
9
  * switchTrackClass({ size }) on a sibling <span>
10
10
  *
11
- * Usage:
12
- * <label class="inline-flex items-center gap-2">
13
- * <input type="checkbox" role="switch" name="notify" class=${switchInputClass()}>
14
- * <span class=${switchTrackClass()}></span>
15
- * <span class=${labelClass()}>Notifications</span>
16
- * </label>
17
- *
18
- * <!-- Small size: -->
19
- * <input type="checkbox" role="switch" name="x" class=${cn(switchInputClass(), 'peer/sm')}>
20
- * <span class=${switchTrackClass({ size: 'sm' })}></span>
21
- *
22
11
  * Design tokens used: --primary, --input, --background, --foreground, --ring,
23
12
  * --primary-foreground.
13
+ *
14
+ * @example
15
+ * ```html
16
+ * <label class="inline-flex items-center gap-2">
17
+ * <input type="checkbox" role="switch" name="notify" class=${switchInputClass()}>
18
+ * <span class=${switchTrackClass()}></span>
19
+ * <span class=${labelClass()}>Notifications</span>
20
+ * </label>
21
+ *
22
+ * <!-- Small size. -->
23
+ * <input type="checkbox" role="switch" name="x" class=${cn(switchInputClass(), 'peer/sm')}>
24
+ * <span class=${switchTrackClass({ size: 'sm' })}></span>
25
+ * ```
24
26
  */
25
27
  import { cn } from '../lib/utils.ts';
26
28
 
@@ -13,31 +13,33 @@
13
13
  * TableHead / TableCell / TableCaption
14
14
  * → tableHeadClass() / tableCellClass() / tableCaptionClass()
15
15
  *
16
- * Usage:
17
- * <div class=${tableContainerClass()}>
18
- * <table class=${tableClass()}>
19
- * <thead class=${tableHeaderClass()}>
20
- * <tr class=${tableRowClass()}>
21
- * <th scope="col" class=${tableHeadClass()}>Name</th>
22
- * <th scope="col" class=${tableHeadClass()}>Status</th>
23
- * </tr>
24
- * </thead>
25
- * <tbody class=${tableBodyClass()}>
26
- * <tr class=${tableRowClass()}>
27
- * <td class=${tableCellClass()}>Vivek</td>
28
- * <td class=${tableCellClass()}>Active</td>
29
- * </tr>
30
- * </tbody>
31
- * <caption class=${tableCaptionClass()}>Users</caption>
32
- * </table>
33
- * </div>
34
- *
35
16
  * A11y (required for accessible output): every header cell needs a scope
36
17
  * (scope="col" on a column header, scope="row" on a row header) so screen
37
18
  * readers map cells to their headers. Add a <caption> naming the table's
38
19
  * purpose (it can be visually hidden if a heading already names it).
39
20
  *
40
21
  * Design tokens used: --muted, --muted-foreground, --foreground.
22
+ *
23
+ * @example
24
+ * ```html
25
+ * <div class=${tableContainerClass()}>
26
+ * <table class=${tableClass()}>
27
+ * <thead class=${tableHeaderClass()}>
28
+ * <tr class=${tableRowClass()}>
29
+ * <th scope="col" class=${tableHeadClass()}>Name</th>
30
+ * <th scope="col" class=${tableHeadClass()}>Status</th>
31
+ * </tr>
32
+ * </thead>
33
+ * <tbody class=${tableBodyClass()}>
34
+ * <tr class=${tableRowClass()}>
35
+ * <td class=${tableCellClass()}>Vivek</td>
36
+ * <td class=${tableCellClass()}>Active</td>
37
+ * </tr>
38
+ * </tbody>
39
+ * <caption class=${tableCaptionClass()}>Users</caption>
40
+ * </table>
41
+ * </div>
42
+ * ```
41
43
  */
42
44
 
43
45
  export const tableContainerClass = (): string => 'relative w-full overflow-x-auto';
@@ -11,16 +11,6 @@
11
11
  * TabsTrigger → <ui-tabs-trigger value>
12
12
  * TabsContent → <ui-tabs-content value>
13
13
  *
14
- * Usage:
15
- * <ui-tabs value="account">
16
- * <ui-tabs-list>
17
- * <ui-tabs-trigger value="account">Account</ui-tabs-trigger>
18
- * <ui-tabs-trigger value="password">Password</ui-tabs-trigger>
19
- * </ui-tabs-list>
20
- * <ui-tabs-content value="account">…</ui-tabs-content>
21
- * <ui-tabs-content value="password">…</ui-tabs-content>
22
- * </ui-tabs>
23
- *
24
14
  * Attributes on <ui-tabs>:
25
15
  * `value`: string (reflected, controlled). Active tab value.
26
16
  * `orientation`: "horizontal" (default) | "vertical".
@@ -42,6 +32,22 @@
42
32
  *
43
33
  * Design tokens used: --muted, --muted-foreground, --foreground, --background,
44
34
  * --input, --ring.
35
+ *
36
+ * @example
37
+ * ```html
38
+ * <ui-tabs value="account">
39
+ * <ui-tabs-list>
40
+ * <ui-tabs-trigger value="account">Account</ui-tabs-trigger>
41
+ * <ui-tabs-trigger value="password">Password</ui-tabs-trigger>
42
+ * </ui-tabs-list>
43
+ * <ui-tabs-content value="account">
44
+ * <p class="text-sm">Update your name and email here.</p>
45
+ * </ui-tabs-content>
46
+ * <ui-tabs-content value="password">
47
+ * <p class="text-sm">Change your password here.</p>
48
+ * </ui-tabs-content>
49
+ * </ui-tabs>
50
+ * ```
45
51
  */
46
52
  import { WebComponent, html, prop } from '@webjsdev/core';
47
53
  import { cn, ensureId } from '../lib/utils.ts';
@@ -6,15 +6,17 @@
6
6
  * shadcn parity:
7
7
  * Textarea → textareaClass()
8
8
  *
9
- * Usage:
10
- * <textarea class=${textareaClass()} name="message" rows="4" placeholder="Your message…">
11
- * </textarea>
12
- *
13
9
  * Pair with `<label class=${labelClass()} for="...">` and wrap in
14
10
  * `<div class=${fieldClass()}>` for the canonical field rhythm.
15
11
  *
16
12
  * Design tokens used: --input, --background, --muted-foreground, --ring,
17
13
  * --destructive.
14
+ *
15
+ * @example
16
+ * ```html
17
+ * <textarea class=${textareaClass()} name="message" rows="4" placeholder="Your message">
18
+ * </textarea>
19
+ * ```
18
20
  */
19
21
  import { cn } from '../lib/utils.ts';
20
22
 
@@ -12,19 +12,6 @@
12
12
  * → <ui-toggle-group type variant size value>
13
13
  * ToggleGroupItem → <ui-toggle-group-item value>
14
14
  *
15
- * Usage:
16
- * <ui-toggle-group type="single" value="bold">
17
- * <ui-toggle-group-item value="bold" aria-label="Bold"><b>B</b></ui-toggle-group-item>
18
- * <ui-toggle-group-item value="italic" aria-label="Italic"><i>I</i></ui-toggle-group-item>
19
- * <ui-toggle-group-item value="underline" aria-label="Underline"><u>U</u></ui-toggle-group-item>
20
- * </ui-toggle-group>
21
- *
22
- * <!-- Multiple selection (comma-separated value): -->
23
- * <ui-toggle-group type="multiple" value="bold,italic">
24
- * <ui-toggle-group-item value="bold">B</ui-toggle-group-item>
25
- * <ui-toggle-group-item value="italic">I</ui-toggle-group-item>
26
- * </ui-toggle-group>
27
- *
28
15
  * Attributes on <ui-toggle-group>:
29
16
  * `type`: "single" (default) | "multiple".
30
17
  * `value`: string. Selected value(s). Single: a single value;
@@ -47,6 +34,21 @@
47
34
  *
48
35
  * Design tokens used: inherited from toggleClass (--muted, --accent, --ring,
49
36
  * --input, --destructive).
37
+ *
38
+ * @example
39
+ * ```html
40
+ * <ui-toggle-group type="single" value="bold">
41
+ * <ui-toggle-group-item value="bold" aria-label="Bold"><b>B</b></ui-toggle-group-item>
42
+ * <ui-toggle-group-item value="italic" aria-label="Italic"><i>I</i></ui-toggle-group-item>
43
+ * <ui-toggle-group-item value="underline" aria-label="Underline"><u>U</u></ui-toggle-group-item>
44
+ * </ui-toggle-group>
45
+ *
46
+ * <!-- Multiple selection, with a comma-separated value. -->
47
+ * <ui-toggle-group type="multiple" value="bold,italic">
48
+ * <ui-toggle-group-item value="bold">B</ui-toggle-group-item>
49
+ * <ui-toggle-group-item value="italic">I</ui-toggle-group-item>
50
+ * </ui-toggle-group>
51
+ * ```
50
52
  */
51
53
  import { WebComponent, html, prop } from '@webjsdev/core';
52
54
  import { cn } from '../lib/utils.ts';
@@ -10,20 +10,6 @@
10
10
  * → toggleClass({ variant, size }) (class helper)
11
11
  * → <ui-toggle pressed variant size> (custom element)
12
12
  *
13
- * Usage (Tier-1 class helper, caller owns state):
14
- * <button class=${toggleClass()} data-state="off" aria-pressed="false"
15
- * onclick="this.dataset.state = this.dataset.state==='on'?'off':'on'">
16
- * <svg>…</svg>
17
- * </button>
18
- *
19
- * Usage (Tier-2 custom element, state managed):
20
- * <ui-toggle aria-label="Toggle bold">
21
- * <svg>…</svg>
22
- * </ui-toggle>
23
- *
24
- * <!-- Controlled / initial: -->
25
- * <ui-toggle variant="outline" size="sm" pressed>B</ui-toggle>
26
- *
27
13
  * Attributes on <ui-toggle>:
28
14
  * `pressed`: boolean (reflected). Active state.
29
15
  * `variant`: "default" (default) | "outline".
@@ -37,6 +23,23 @@
37
23
  *
38
24
  * Design tokens used: --muted, --muted-foreground, --accent, --accent-foreground,
39
25
  * --input, --background, --ring, --destructive.
26
+ *
27
+ * @example
28
+ * ```html
29
+ * <!-- Tier-1 class helper, caller owns state. -->
30
+ * <button class=${toggleClass()} data-state="off" aria-pressed="false"
31
+ * onclick="this.dataset.state = this.dataset.state==='on'?'off':'on'">
32
+ * <svg class="size-4" viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2" aria-hidden="true"><path d="M14 12a4 4 0 0 0 0-8H6v8" /><path d="M15 20a4 4 0 0 0 0-8H6v8Z" /></svg>
33
+ * </button>
34
+ *
35
+ * <!-- Tier-2 custom element, state managed. -->
36
+ * <ui-toggle aria-label="Toggle bold">
37
+ * <svg class="size-4" viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2" aria-hidden="true"><path d="M14 12a4 4 0 0 0 0-8H6v8" /><path d="M15 20a4 4 0 0 0 0-8H6v8Z" /></svg>
38
+ * </ui-toggle>
39
+ *
40
+ * <!-- Controlled or initial state. -->
41
+ * <ui-toggle variant="outline" size="sm" pressed>B</ui-toggle>
42
+ * ```
40
43
  */
41
44
  import { WebComponent, html, prop } from '@webjsdev/core';
42
45
  import { cn } from '../lib/utils.ts';