@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.
- package/README.md +14 -5
- package/package.json +2 -1
- package/packages/registry/components/accordion.ts +20 -15
- package/packages/registry/components/alert-dialog.ts +19 -17
- package/packages/registry/components/alert.ts +20 -18
- package/packages/registry/components/aspect-ratio.ts +11 -9
- package/packages/registry/components/avatar.ts +20 -12
- package/packages/registry/components/badge.ts +7 -5
- package/packages/registry/components/breadcrumb.ts +17 -15
- package/packages/registry/components/button.ts +8 -6
- package/packages/registry/components/card.ts +18 -14
- package/packages/registry/components/checkbox.ts +6 -4
- package/packages/registry/components/collapsible.ts +14 -12
- package/packages/registry/components/dialog.ts +30 -24
- package/packages/registry/components/dropdown-menu.ts +22 -20
- package/packages/registry/components/hover-card.ts +18 -10
- package/packages/registry/components/input.ts +6 -4
- package/packages/registry/components/kbd.ts +11 -9
- package/packages/registry/components/label.ts +6 -4
- package/packages/registry/components/native-select.ts +12 -10
- package/packages/registry/components/pagination.ts +15 -11
- package/packages/registry/components/popover.ts +24 -16
- package/packages/registry/components/progress.ts +8 -6
- package/packages/registry/components/radio-group.ts +14 -12
- package/packages/registry/components/separator.ts +8 -6
- package/packages/registry/components/skeleton.ts +6 -4
- package/packages/registry/components/sonner.ts +16 -12
- package/packages/registry/components/switch.ts +13 -11
- package/packages/registry/components/table.ts +21 -19
- package/packages/registry/components/tabs.ts +30 -12
- package/packages/registry/components/textarea.ts +6 -4
- package/packages/registry/components/toggle-group.ts +15 -13
- package/packages/registry/components/toggle.ts +17 -14
- package/packages/registry/components/tooltip.ts +10 -8
- package/packages/registry/lib/utils.ts +34 -8
- package/packages/registry/themes/index.css +11 -0
- package/src/commands/add.js +45 -1
- package/src/commands/diff.js +20 -3
- package/src/commands/init.js +17 -25
- package/src/commands/list.js +2 -2
- package/src/commands/view.js +18 -3
- package/src/registry/example.js +120 -0
- package/src/registry/extract.js +145 -0
- package/src/registry/fetcher.js +60 -2
- package/src/registry/local.js +207 -0
- package/src/registry/resolver.js +2 -2
- 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`,
|
|
104
|
-
| `webjsui add <names...>` | Add components
|
|
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
|
|
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.
|
|
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
|
-
*
|
|
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
|
-
*
|
|
15
|
-
*
|
|
16
|
-
*
|
|
17
|
-
*
|
|
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
|
-
*
|
|
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
|
-
*
|
|
15
|
-
*
|
|
16
|
-
*
|
|
17
|
-
*
|
|
18
|
-
*
|
|
19
|
-
*
|
|
20
|
-
*
|
|
21
|
-
*
|
|
22
|
-
*
|
|
23
|
-
*
|
|
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
|
-
*
|
|
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';
|