@create-ui/cli 0.5.9 → 0.6.1
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/dist/chunk-KFQXWKJJ.js +19 -0
- package/dist/chunk-KFQXWKJJ.js.map +1 -0
- package/dist/{chunk-2ELKDGGM.js → chunk-OGAWGP7T.js} +3 -3
- package/dist/{chunk-2ELKDGGM.js.map → chunk-OGAWGP7T.js.map} +1 -1
- package/dist/chunk-OITQ46YK.js +99 -0
- package/dist/chunk-OITQ46YK.js.map +1 -0
- package/dist/index.js +28 -28
- package/dist/index.js.map +1 -1
- package/dist/mcp/index.js +1 -1
- package/dist/registry/index.d.ts +3 -1
- package/dist/registry/index.js +1 -1
- package/dist/skills/createui/SKILL.md +81 -54
- package/dist/skills/createui/cli.md +1 -1
- package/dist/skills/createui/customization.md +14 -12
- package/dist/skills/createui/evals/evals.json +77 -0
- package/dist/skills/createui/mcp.md +12 -26
- package/dist/skills/createui/rules/a11y.md +148 -0
- package/dist/skills/createui/rules/composition.md +64 -26
- package/dist/skills/createui/rules/forms.md +2 -2
- package/dist/skills/createui/rules/icons.md +1 -1
- package/dist/skills/createui/rules/styling.md +2 -2
- package/dist/utils/index.js +1 -1
- package/dist/utils/index.js.map +1 -1
- package/package.json +1 -1
- package/dist/chunk-643QI2I2.js +0 -102
- package/dist/chunk-643QI2I2.js.map +0 -1
- package/dist/chunk-KQTXDVKV.js +0 -19
- package/dist/chunk-KQTXDVKV.js.map +0 -1
- package/dist/skills/createui/reference/accordion.md +0 -127
- package/dist/skills/createui/reference/app-store-badge.md +0 -88
- package/dist/skills/createui/reference/aspect-ratio.md +0 -52
- package/dist/skills/createui/reference/avatar.md +0 -230
- package/dist/skills/createui/reference/badge.md +0 -110
- package/dist/skills/createui/reference/breadcrumb.md +0 -153
- package/dist/skills/createui/reference/button-group.md +0 -116
- package/dist/skills/createui/reference/button.md +0 -104
- package/dist/skills/createui/reference/checkbox-group.md +0 -118
- package/dist/skills/createui/reference/checkbox.md +0 -79
- package/dist/skills/createui/reference/chip.md +0 -115
- package/dist/skills/createui/reference/close-button.md +0 -83
- package/dist/skills/createui/reference/command.md +0 -69
- package/dist/skills/createui/reference/country-flag.md +0 -109
- package/dist/skills/createui/reference/credit-card-input.md +0 -76
- package/dist/skills/createui/reference/date-input.md +0 -71
- package/dist/skills/createui/reference/dropdown-menu.md +0 -164
- package/dist/skills/createui/reference/field.md +0 -186
- package/dist/skills/createui/reference/info-tooltip.md +0 -110
- package/dist/skills/createui/reference/inline-alert.md +0 -146
- package/dist/skills/createui/reference/input-group.md +0 -171
- package/dist/skills/createui/reference/input-otp.md +0 -130
- package/dist/skills/createui/reference/input-stepper.md +0 -120
- package/dist/skills/createui/reference/input.md +0 -118
- package/dist/skills/createui/reference/label.md +0 -121
- package/dist/skills/createui/reference/pagination.md +0 -157
- package/dist/skills/createui/reference/password-strength.md +0 -70
- package/dist/skills/createui/reference/phone-input.md +0 -77
- package/dist/skills/createui/reference/progress.md +0 -158
- package/dist/skills/createui/reference/radio-group.md +0 -133
- package/dist/skills/createui/reference/radio.md +0 -79
- package/dist/skills/createui/reference/scroll-area.md +0 -212
- package/dist/skills/createui/reference/segmented-control.md +0 -146
- package/dist/skills/createui/reference/select.md +0 -204
- package/dist/skills/createui/reference/separator.md +0 -99
- package/dist/skills/createui/reference/social-login-button.md +0 -130
- package/dist/skills/createui/reference/spinner.md +0 -68
- package/dist/skills/createui/reference/status-badge.md +0 -89
- package/dist/skills/createui/reference/switch-group.md +0 -122
- package/dist/skills/createui/reference/switch.md +0 -75
- package/dist/skills/createui/reference/tab-menu.md +0 -165
- package/dist/skills/createui/reference/text-link.md +0 -84
- package/dist/skills/createui/reference/textarea.md +0 -50
- package/dist/skills/createui/reference/toast.md +0 -162
- package/dist/skills/createui/reference/tooltip.md +0 -63
|
@@ -1,157 +0,0 @@
|
|
|
1
|
-
<!-- GENERATED FILE - do not edit. Source: registry/ui/pagination.tsx. Regenerate with `pnpm skill:build`. Curated notes: apps/v4/scripts/skill-reference/notes/pagination.md -->
|
|
2
|
-
|
|
3
|
-
# pagination
|
|
4
|
-
|
|
5
|
-
Page navigation with first/prev/next/last actions and ellipsis; compact or ButtonGroup-backed compact-grouped variant
|
|
6
|
-
|
|
7
|
-
Install: `npx @create-ui/cli add pagination`
|
|
8
|
-
|
|
9
|
-
## Import
|
|
10
|
-
|
|
11
|
-
```tsx
|
|
12
|
-
import { Pagination, PaginationContent, PaginationLink, PaginationFirst, PaginationPrevious, PaginationNext, PaginationLast, PaginationEllipsis } from "@/components/ui/pagination"
|
|
13
|
-
```
|
|
14
|
-
|
|
15
|
-
## Pagination props
|
|
16
|
-
|
|
17
|
-
| Prop | Type | Default |
|
|
18
|
-
| --- | --- | --- |
|
|
19
|
-
| variant | `compact \| compact-grouped` (compact-grouped renders PaginationContent as a soft md ButtonGroup (one fused surface); compact renders standalone buttons with gap-1.) | `compact-grouped` |
|
|
20
|
-
| shape | `rounded \| pill` (Settable on the root Pagination only; children have no shape prop and pick it up from context.) | `rounded` |
|
|
21
|
-
|
|
22
|
-
Extends `React.ComponentProps<"nav">`.
|
|
23
|
-
|
|
24
|
-
## PaginationLink props
|
|
25
|
-
|
|
26
|
-
| Prop | Type | Default |
|
|
27
|
-
| --- | --- | --- |
|
|
28
|
-
| asChild | `boolean` | - |
|
|
29
|
-
| isActive | `boolean` (Writes aria-current=page and data-active; in compact-grouped it maps to ButtonGroupItem active with aria-pressed deliberately stripped.) | - |
|
|
30
|
-
|
|
31
|
-
Extends `React.ComponentProps<"button">`.
|
|
32
|
-
|
|
33
|
-
## PaginationFirst props
|
|
34
|
-
|
|
35
|
-
| Prop | Type | Default |
|
|
36
|
-
| --- | --- | --- |
|
|
37
|
-
| asChild | `boolean` | - |
|
|
38
|
-
|
|
39
|
-
Extends `React.ComponentProps<"button">`.
|
|
40
|
-
|
|
41
|
-
## PaginationPrevious props
|
|
42
|
-
|
|
43
|
-
| Prop | Type | Default |
|
|
44
|
-
| --- | --- | --- |
|
|
45
|
-
| asChild | `boolean` | - |
|
|
46
|
-
|
|
47
|
-
Extends `React.ComponentProps<"button">`.
|
|
48
|
-
|
|
49
|
-
## PaginationNext props
|
|
50
|
-
|
|
51
|
-
| Prop | Type | Default |
|
|
52
|
-
| --- | --- | --- |
|
|
53
|
-
| asChild | `boolean` | - |
|
|
54
|
-
|
|
55
|
-
Extends `React.ComponentProps<"button">`.
|
|
56
|
-
|
|
57
|
-
## PaginationLast props
|
|
58
|
-
|
|
59
|
-
| Prop | Type | Default |
|
|
60
|
-
| --- | --- | --- |
|
|
61
|
-
| asChild | `boolean` | - |
|
|
62
|
-
|
|
63
|
-
Extends `React.ComponentProps<"button">`.
|
|
64
|
-
|
|
65
|
-
## Examples
|
|
66
|
-
|
|
67
|
-
From `pagination-demo`:
|
|
68
|
-
|
|
69
|
-
```tsx
|
|
70
|
-
import {
|
|
71
|
-
Pagination,
|
|
72
|
-
PaginationContent,
|
|
73
|
-
PaginationEllipsis,
|
|
74
|
-
PaginationLink,
|
|
75
|
-
PaginationNext,
|
|
76
|
-
PaginationPrevious,
|
|
77
|
-
} from "@/components/ui/pagination"
|
|
78
|
-
|
|
79
|
-
export default function PaginationDemo() {
|
|
80
|
-
return (
|
|
81
|
-
<Pagination>
|
|
82
|
-
<PaginationContent>
|
|
83
|
-
<PaginationPrevious />
|
|
84
|
-
<PaginationLink>1</PaginationLink>
|
|
85
|
-
<PaginationLink>2</PaginationLink>
|
|
86
|
-
<PaginationLink isActive>3</PaginationLink>
|
|
87
|
-
<PaginationEllipsis />
|
|
88
|
-
<PaginationLink>10</PaginationLink>
|
|
89
|
-
<PaginationNext />
|
|
90
|
-
</PaginationContent>
|
|
91
|
-
</Pagination>
|
|
92
|
-
)
|
|
93
|
-
}
|
|
94
|
-
```
|
|
95
|
-
|
|
96
|
-
From `pagination-with-link`:
|
|
97
|
-
|
|
98
|
-
```tsx
|
|
99
|
-
"use client"
|
|
100
|
-
|
|
101
|
-
import {
|
|
102
|
-
Pagination,
|
|
103
|
-
PaginationContent,
|
|
104
|
-
PaginationEllipsis,
|
|
105
|
-
PaginationLink,
|
|
106
|
-
PaginationNext,
|
|
107
|
-
PaginationPrevious,
|
|
108
|
-
} from "@/components/ui/pagination"
|
|
109
|
-
|
|
110
|
-
export default function PaginationWithLink() {
|
|
111
|
-
return (
|
|
112
|
-
<Pagination>
|
|
113
|
-
<PaginationContent>
|
|
114
|
-
<PaginationPrevious asChild>
|
|
115
|
-
<a href="?page=2" />
|
|
116
|
-
</PaginationPrevious>
|
|
117
|
-
<PaginationLink asChild>
|
|
118
|
-
<a href="?page=1">1</a>
|
|
119
|
-
</PaginationLink>
|
|
120
|
-
<PaginationLink asChild>
|
|
121
|
-
<a href="?page=2">2</a>
|
|
122
|
-
</PaginationLink>
|
|
123
|
-
<PaginationLink asChild isActive>
|
|
124
|
-
<a href="?page=3" aria-current="page">
|
|
125
|
-
3
|
|
126
|
-
</a>
|
|
127
|
-
</PaginationLink>
|
|
128
|
-
<PaginationEllipsis />
|
|
129
|
-
<PaginationLink asChild>
|
|
130
|
-
<a href="?page=10">10</a>
|
|
131
|
-
</PaginationLink>
|
|
132
|
-
<PaginationNext asChild>
|
|
133
|
-
<a href="?page=4" />
|
|
134
|
-
</PaginationNext>
|
|
135
|
-
</PaginationContent>
|
|
136
|
-
</Pagination>
|
|
137
|
-
)
|
|
138
|
-
}
|
|
139
|
-
```
|
|
140
|
-
|
|
141
|
-
More: `npx @create-ui/cli view pagination` or MCP `get_item_examples_from_registries` with "pagination-demo" / "pagination-example".
|
|
142
|
-
|
|
143
|
-
## When to use
|
|
144
|
-
Numbered page navigation for long tables, search results, and archives where users jump between page ranges. Do not use it for switching sibling panels in place (use TabMenu), hierarchical trails (use Breadcrumb), or a plain prev/next pair without page numbers (use two Buttons). For a value-picking segmented control, use SegmentedControl or ButtonGroup directly.
|
|
145
|
-
|
|
146
|
-
## Gotchas
|
|
147
|
-
- There is no PaginationItem wrapper (shadcn habit): controls are direct children of PaginationContent. PaginationContent is mandatory; in the default compact-grouped variant it IS the ButtonGroup, so dropping it loses the fused surface and sizing.
|
|
148
|
-
- PaginationLink renders a `<button type="button">` by default, not an `<a>` like shadcn. For URL navigation use asChild with an anchor or router Link; isActive keeps working because aria-current and active styling are forwarded onto the slotted element (see pagination-with-link).
|
|
149
|
-
- First/Previous/Next/Last inject their default arrow icon even with asChild: pass an empty anchor and the icon plus the built-in "Go to ... page" aria-label are supplied automatically; any children of the slotted element are replaced by the icon. Without asChild, `children` replaces the icon instead.
|
|
150
|
-
```tsx
|
|
151
|
-
<PaginationNext asChild>
|
|
152
|
-
<a href="?page=4" />
|
|
153
|
-
</PaginationNext>
|
|
154
|
-
```
|
|
155
|
-
- With asChild, `disabled` is not forwarded as a native attribute; the slotted element gets `aria-disabled` plus `tabIndex={-1}` and pointer-events-none styling, so disabled links stay in the DOM but become inert and unfocusable.
|
|
156
|
-
- No size prop exists anywhere; compact-grouped is hard-wired to ButtonGroup soft/md and compact items to a fixed h-8. Do not try to pass size to the content or items.
|
|
157
|
-
- PaginationEllipsis is presentational (`role="presentation"`, `aria-hidden`) with a built-in sr-only "More pages" hint; `children` only swaps the visible glyph. Render real PaginationLinks for clickable pages (see pagination-controlled for the windowing pattern).
|
|
@@ -1,70 +0,0 @@
|
|
|
1
|
-
<!-- GENERATED FILE - do not edit. Source: registry/ui/password-strength.tsx. Regenerate with `pnpm skill:build`. Curated notes: apps/v4/scripts/skill-reference/notes/password-strength.md -->
|
|
2
|
-
|
|
3
|
-
# password-strength
|
|
4
|
-
|
|
5
|
-
Password meter with five segments driven by a 0-5 strength prop plus an optional checklist of rules
|
|
6
|
-
|
|
7
|
-
Install: `npx @create-ui/cli add password-strength`
|
|
8
|
-
|
|
9
|
-
## Import
|
|
10
|
-
|
|
11
|
-
```tsx
|
|
12
|
-
import { PasswordStrength } from "@/components/ui/password-strength"
|
|
13
|
-
```
|
|
14
|
-
|
|
15
|
-
## PasswordStrength props
|
|
16
|
-
|
|
17
|
-
| Prop | Type | Default |
|
|
18
|
-
| --- | --- | --- |
|
|
19
|
-
| size | `xs \| sm \| md` (Standalone prop - not inherited from Field or InputGroup context; mirror the sibling password field's size manually.) | `md` |
|
|
20
|
-
| strength | `StrengthLevel` (How many of the 5 segments fill (0-5); the component computes nothing - derive the level from the password value yourself.) | `0` |
|
|
21
|
-
| rules | `PasswordStrengthRule[]` (Omit (or pass an empty array) to hide the whole checklist section and its divider; each rule is just { label, met }.) | - |
|
|
22
|
-
|
|
23
|
-
Extends `React.ComponentProps<"div">`.
|
|
24
|
-
|
|
25
|
-
## Examples
|
|
26
|
-
|
|
27
|
-
From `input-group-password`:
|
|
28
|
-
|
|
29
|
-
```tsx
|
|
30
|
-
import { RiLock2Line } from "@create-ui/assets/icons"
|
|
31
|
-
|
|
32
|
-
import { Field, FieldLabel } from "@/components/ui/field"
|
|
33
|
-
import {
|
|
34
|
-
InputGroup,
|
|
35
|
-
InputGroupControl,
|
|
36
|
-
InputGroupSlot,
|
|
37
|
-
} from "@/components/ui/input-group"
|
|
38
|
-
|
|
39
|
-
export default function InputGroupPassword() {
|
|
40
|
-
return (
|
|
41
|
-
<Field className="max-w-100">
|
|
42
|
-
<FieldLabel htmlFor="input-group-password-input">Password</FieldLabel>
|
|
43
|
-
<InputGroup>
|
|
44
|
-
<InputGroupSlot>
|
|
45
|
-
<RiLock2Line />
|
|
46
|
-
<InputGroupControl
|
|
47
|
-
id="input-group-password-input"
|
|
48
|
-
type="password"
|
|
49
|
-
placeholder="••••••••••••"
|
|
50
|
-
defaultValue="mysecretpassword"
|
|
51
|
-
/>
|
|
52
|
-
</InputGroupSlot>
|
|
53
|
-
</InputGroup>
|
|
54
|
-
</Field>
|
|
55
|
-
)
|
|
56
|
-
}
|
|
57
|
-
```
|
|
58
|
-
|
|
59
|
-
More: `npx @create-ui/cli view password-strength` or MCP `get_item_examples_from_registries` with "password-strength-demo" / "password-strength-example".
|
|
60
|
-
|
|
61
|
-
## When to use
|
|
62
|
-
Read-only feedback card shown alongside a password field: a five-segment strength meter plus an optional "Your password must include:" checklist. It contains no input and no scoring algorithm, so pair it with a separate `InputGroup` + `InputGroupControl type="password"` (or `Input type="password"`) and recompute `strength`/`rules` on every change. For a generic completion bar use `Progress`; for the password field itself use `Input`/`InputGroup`, never this.
|
|
63
|
-
|
|
64
|
-
## Gotchas
|
|
65
|
-
- Fully controlled and dumb: no value prop, no onChange, no built-in zxcvbn-style scoring. You own the evaluation (e.g. count met rules) and pass the result in as `strength` and `rules`.
|
|
66
|
-
- All copy is hardcoded English: the checklist heading "Your password must include:", the level labels ("Too Weak" through "Very Strong"), and the per-level meter colors (red/orange/yellow/lime/green). No props exist to relabel, localize, or recolor them.
|
|
67
|
-
- `strength={0}` is the legitimate pristine state: all five segments render unfilled and the level label is omitted (only the "Password Strength" caption shows). Do not conditionally unmount the component to get an empty meter.
|
|
68
|
-
- Rule icons are automatic: `met: true` renders a check (RiCheckFill), `met: false` a cross (RiCloseFill). You supply only `label` and `met`; there is no per-rule icon slot.
|
|
69
|
-
- The checklist renders ABOVE the meter in DOM order (rules, divider, then meter); the meter section always renders, and the divider appears and disappears with the checklist.
|
|
70
|
-
- Met rule rows carry `data-met` (absent when unmet); the root has `data-slot="password-strength"` and `data-size` as external styling hooks.
|
|
@@ -1,77 +0,0 @@
|
|
|
1
|
-
<!-- GENERATED FILE - do not edit. Source: registry/ui/phone-input.tsx. Regenerate with `pnpm skill:build`. Curated notes: apps/v4/scripts/skill-reference/notes/phone-input.md -->
|
|
2
|
-
|
|
3
|
-
# phone-input
|
|
4
|
-
|
|
5
|
-
Phone number input with a country flag select and dial code prefix; onValueChange emits the E.164 value
|
|
6
|
-
|
|
7
|
-
Install: `npx @create-ui/cli add phone-input`
|
|
8
|
-
|
|
9
|
-
## Import
|
|
10
|
-
|
|
11
|
-
```tsx
|
|
12
|
-
import { PhoneInput } from "@/components/ui/phone-input"
|
|
13
|
-
```
|
|
14
|
-
|
|
15
|
-
## PhoneInput props
|
|
16
|
-
|
|
17
|
-
| Prop | Type | Default |
|
|
18
|
-
| --- | --- | --- |
|
|
19
|
-
| defaultValue | `string` (E.164 or national digits; the dial code is stripped only when it matches the active country, so pair it with the matching defaultCountry) | - |
|
|
20
|
-
| defaultCountry | `PhoneCountryCode` | `DE` |
|
|
21
|
-
| country | `PhoneCountryCode` | - |
|
|
22
|
-
| onCountryChange | `(country: PhoneCountryCode) => void` | - |
|
|
23
|
-
| onValueChange | `(value: string, details: PhoneInputDetails) => void` (Emits the full E.164 string ('' when empty) plus { country, dialCode, nationalNumber }; re-fires immediately when the country changes) | - |
|
|
24
|
-
| countries | `PhoneCountryConfig[]` (Subset or reorder the dropdown; build entries from PHONE_COUNTRIES exported by use-phone-input (default: every country, sorted by English name)) | - |
|
|
25
|
-
| size | `xs \| sm \| md` (Omit inside Field; InputGroup resolves it from Field context (falls back to sm)) | - |
|
|
26
|
-
| invalid | `boolean` | - |
|
|
27
|
-
| disabled | `boolean` | - |
|
|
28
|
-
| loading | `boolean` | - |
|
|
29
|
-
| showHelperIcon | `boolean` | `true` |
|
|
30
|
-
| helperIcon | `ReactNode` | - |
|
|
31
|
-
| helperTooltip | `ReactNode` (Pass null to keep the helper icon without a tooltip; hide the icon entirely with showHelperIcon={false}) | `Enter your phone number without the country code.` |
|
|
32
|
-
| className | `string` | - |
|
|
33
|
-
| ref | `React.Ref<HTMLInputElement>` | - |
|
|
34
|
-
|
|
35
|
-
Extends `React.ComponentProps<"input">`.
|
|
36
|
-
|
|
37
|
-
## Examples
|
|
38
|
-
|
|
39
|
-
From `input-group-phone`:
|
|
40
|
-
|
|
41
|
-
```tsx
|
|
42
|
-
"use client"
|
|
43
|
-
|
|
44
|
-
import { Field, FieldLabel } from "@/components/ui/field"
|
|
45
|
-
import { PhoneInput } from "@/components/ui/phone-input"
|
|
46
|
-
|
|
47
|
-
export default function InputGroupPhone() {
|
|
48
|
-
return (
|
|
49
|
-
<Field className="max-w-md">
|
|
50
|
-
<FieldLabel htmlFor="input-group-phone">Phone Number</FieldLabel>
|
|
51
|
-
<PhoneInput
|
|
52
|
-
id="input-group-phone"
|
|
53
|
-
defaultCountry="US"
|
|
54
|
-
onValueChange={(value, { country }) => console.log(value, country)}
|
|
55
|
-
/>
|
|
56
|
-
</Field>
|
|
57
|
-
)
|
|
58
|
-
}
|
|
59
|
-
```
|
|
60
|
-
|
|
61
|
-
More: `npx @create-ui/cli view phone-input` or MCP `get_item_examples_from_registries` with "phone-input-demo" / "phone-input-example".
|
|
62
|
-
|
|
63
|
-
## When to use
|
|
64
|
-
Complete phone-number field: country flag select, display-only dial code prefix, auto-formatting national-digit input, and an E.164 value via onValueChange. Use it whenever a form collects a phone number; do not rebuild it from InputGroup + InputGroupSelect + CountryFlag, because it already is exactly that composition. For other prefix-plus-select combos (amount, currency) compose InputGroup directly, and for plain text use Input.
|
|
65
|
-
|
|
66
|
-
## Gotchas
|
|
67
|
-
- It renders its own InputGroup; never nest it inside another InputGroup. Wrap it in Field for the label, and leave size/invalid/disabled/loading unset there so they cascade from Field context.
|
|
68
|
-
- The text value cannot be controlled: native value/onChange are stripped from the prop type. Seed with defaultValue and read through onValueChange. Only the country supports controlled mode (country + onCountryChange).
|
|
69
|
-
- The country is never auto-detected from the value (unlike react-phone-number-input). The dial code in defaultValue is stripped only when it matches the active country, so an E.164 defaultValue must ship with the matching defaultCountry or the dial digits leak into the national number:
|
|
70
|
-
|
|
71
|
-
```tsx
|
|
72
|
-
<PhoneInput defaultCountry="US" defaultValue="+15551234567" />
|
|
73
|
-
```
|
|
74
|
-
|
|
75
|
-
- The visible input holds national digits only, live-formatted per country by libphonenumber's AsYouType; the dial code is a display-only span. The E.164 string exists solely in the onValueChange payload, and an empty input emits "" rather than the bare dial code.
|
|
76
|
-
- Switching country keeps the typed digits and instantly re-fires onValueChange with the new dial code applied to the same national number.
|
|
77
|
-
- Non-digit keystrokes are stripped on input; do not layer your own masking or formatting on top.
|
|
@@ -1,158 +0,0 @@
|
|
|
1
|
-
<!-- GENERATED FILE - do not edit. Source: registry/ui/progress.tsx. Regenerate with `pnpm skill:build`. Curated notes: apps/v4/scripts/skill-reference/notes/progress.md -->
|
|
2
|
-
|
|
3
|
-
# progress
|
|
4
|
-
|
|
5
|
-
Determinate progress as a line or circle via the type prop; solid or gradient appearance, value/max with animated fill
|
|
6
|
-
|
|
7
|
-
Install: `npx @create-ui/cli add progress`
|
|
8
|
-
|
|
9
|
-
## Import
|
|
10
|
-
|
|
11
|
-
```tsx
|
|
12
|
-
import { Progress } from "@/components/ui/progress"
|
|
13
|
-
```
|
|
14
|
-
|
|
15
|
-
Also exported: `progressLineVariants`
|
|
16
|
-
|
|
17
|
-
## Progress props
|
|
18
|
-
|
|
19
|
-
| Prop | Type | Default |
|
|
20
|
-
| --- | --- | --- |
|
|
21
|
-
| type | `line \| circle` | `line` |
|
|
22
|
-
| variant | `primary \| info \| success \| warning \| danger \| away \| neutral \| neutral-static \| neutral-soft \| inverse \| inverse-static \| inverse-soft` | `primary` |
|
|
23
|
-
| appearance | `solid \| gradient` | `solid` |
|
|
24
|
-
| size | `xs \| sm \| md \| lg` (Line: bar thickness; circle: fixed outer diameter (12/16/20/24px) with matching stroke width) | `md` |
|
|
25
|
-
| shape | `sharp \| pill` (Visual effect on line only; the circle ring renders identically and merely emits data-shape) | `pill` |
|
|
26
|
-
| value | `number` | `0` |
|
|
27
|
-
| max | `number` (Values <= 0 silently fall back to 100; value is clamped to 0..max for both fill width and aria-valuenow) | `100` |
|
|
28
|
-
| duration | `number` (Line only; overrides the default 300ms ease-out width transition. type=circle discards it (the ring has no transition at all)) | - |
|
|
29
|
-
|
|
30
|
-
Extends `React.ComponentProps<"div">`.
|
|
31
|
-
|
|
32
|
-
## Examples
|
|
33
|
-
|
|
34
|
-
From `progress-demo`:
|
|
35
|
-
|
|
36
|
-
```tsx
|
|
37
|
-
import { Progress } from "@/components/ui/progress"
|
|
38
|
-
|
|
39
|
-
export default function ProgressDemo() {
|
|
40
|
-
return (
|
|
41
|
-
<div className="flex items-center gap-8">
|
|
42
|
-
<div className="w-64">
|
|
43
|
-
<Progress value={42} />
|
|
44
|
-
</div>
|
|
45
|
-
<Progress type="circle" size="lg" value={42} />
|
|
46
|
-
</div>
|
|
47
|
-
)
|
|
48
|
-
}
|
|
49
|
-
```
|
|
50
|
-
|
|
51
|
-
From `progress-upload`:
|
|
52
|
-
|
|
53
|
-
```tsx
|
|
54
|
-
"use client"
|
|
55
|
-
|
|
56
|
-
import * as React from "react"
|
|
57
|
-
import {
|
|
58
|
-
RiCheckLine,
|
|
59
|
-
RiRefreshLine,
|
|
60
|
-
RiUploadCloud2Line,
|
|
61
|
-
} from "@create-ui/assets/icons"
|
|
62
|
-
|
|
63
|
-
import { Button } from "@/components/ui/button"
|
|
64
|
-
import { Progress } from "@/components/ui/progress"
|
|
65
|
-
|
|
66
|
-
const DURATION_MS = 2000
|
|
67
|
-
|
|
68
|
-
type Status = "idle" | "uploading" | "done" | "error"
|
|
69
|
-
|
|
70
|
-
export default function ProgressUpload() {
|
|
71
|
-
const [attempt, setAttempt] = React.useState(0)
|
|
72
|
-
const [status, setStatus] = React.useState<Status>("idle")
|
|
73
|
-
const [progress, setProgress] = React.useState(0)
|
|
74
|
-
|
|
75
|
-
React.useEffect(() => {
|
|
76
|
-
if (status !== "uploading") return
|
|
77
|
-
|
|
78
|
-
// First attempt fails to demo the retry flow, later attempts succeed.
|
|
79
|
-
const willFail = attempt === 1
|
|
80
|
-
const target = willFail ? 60 : 100
|
|
81
|
-
|
|
82
|
-
const raf = requestAnimationFrame(() => setProgress(target))
|
|
83
|
-
const timeout = setTimeout(
|
|
84
|
-
() => setStatus(willFail ? "error" : "done"),
|
|
85
|
-
DURATION_MS
|
|
86
|
-
)
|
|
87
|
-
|
|
88
|
-
return () => {
|
|
89
|
-
cancelAnimationFrame(raf)
|
|
90
|
-
clearTimeout(timeout)
|
|
91
|
-
}
|
|
92
|
-
}, [status, attempt])
|
|
93
|
-
|
|
94
|
-
function startUpload() {
|
|
95
|
-
setProgress(0)
|
|
96
|
-
setAttempt((a) => a + 1)
|
|
97
|
-
setStatus("uploading")
|
|
98
|
-
}
|
|
99
|
-
|
|
100
|
-
const isUploading = status === "uploading"
|
|
101
|
-
const isDone = status === "done"
|
|
102
|
-
const isError = status === "error"
|
|
103
|
-
|
|
104
|
-
const variant = isDone ? "success" : isError ? "danger" : "primary"
|
|
105
|
-
|
|
106
|
-
return (
|
|
107
|
-
<div className="flex w-80 items-center gap-4">
|
|
108
|
-
<Progress
|
|
109
|
-
key={attempt}
|
|
110
|
-
value={progress}
|
|
111
|
-
duration={DURATION_MS}
|
|
112
|
-
variant={variant}
|
|
113
|
-
/>
|
|
114
|
-
<Button
|
|
115
|
-
variant={variant}
|
|
116
|
-
loading={isUploading}
|
|
117
|
-
leadingIcon={
|
|
118
|
-
isDone ? (
|
|
119
|
-
<RiCheckLine />
|
|
120
|
-
) : isError ? (
|
|
121
|
-
<RiRefreshLine />
|
|
122
|
-
) : (
|
|
123
|
-
<RiUploadCloud2Line />
|
|
124
|
-
)
|
|
125
|
-
}
|
|
126
|
-
onClick={startUpload}
|
|
127
|
-
className="w-32 shrink-0"
|
|
128
|
-
>
|
|
129
|
-
{isDone
|
|
130
|
-
? "Done"
|
|
131
|
-
: isError
|
|
132
|
-
? "Retry"
|
|
133
|
-
: isUploading
|
|
134
|
-
? "Uploading"
|
|
135
|
-
: "Upload"}
|
|
136
|
-
</Button>
|
|
137
|
-
</div>
|
|
138
|
-
)
|
|
139
|
-
}
|
|
140
|
-
```
|
|
141
|
-
|
|
142
|
-
More: `npx @create-ui/cli view progress` or MCP `get_item_examples_from_registries` with "progress-demo" / "progress-example".
|
|
143
|
-
|
|
144
|
-
## When to use
|
|
145
|
-
Determinate progress against a known total: uploads, multi-step flows, download bars, and compact dashboard stat rings (type="circle"). Do not use it when duration or total is unknown; use Spinner for indeterminate loading. For a passive status or count that does not track completion, use Badge or Status Badge.
|
|
146
|
-
|
|
147
|
-
## Gotchas
|
|
148
|
-
- Single self-closing component built on plain divs, not Radix: there is no Root/Indicator subcomponent and `children` is type-omitted, so the shadcn pattern `<Progress><ProgressIndicator /></Progress>` will not compile. Render labels or percentage text outside the component.
|
|
149
|
-
- `type="line"` is `w-full` and stretches to fill its parent; always wrap it in a width-constrained container. `type="circle"` sets width/height via inline style from `size`, so className width utilities cannot resize the ring.
|
|
150
|
-
- Every `value` change animates the line width. To restart a fill from 0 (e.g. a retry), remount with a `key` and set the target value on the next frame, as progress-upload does; resetting value in place animates the bar backward first.
|
|
151
|
-
|
|
152
|
-
```tsx
|
|
153
|
-
<Progress key={attempt} value={progress} duration={2000} variant={isError ? "danger" : "primary"} />
|
|
154
|
-
```
|
|
155
|
-
|
|
156
|
-
- The root carries `role="progressbar"` and aria-valuemin/max/now automatically but has no accessible name; pass `aria-label` yourself (div props pass through).
|
|
157
|
-
- The circle is pure CSS (conic-gradient arc + radial mask), no SVG, so there are no stroke props. The arc paints with `currentColor`; a `text-*` class on the component recolors it (the inline-styled indicator cannot be themed via `data-slot` CSS).
|
|
158
|
-
- `inverse*` variants render in white/static-white tones for dark surfaces; the examples place them on a `bg-strongest` canvas.
|
|
@@ -1,133 +0,0 @@
|
|
|
1
|
-
<!-- GENERATED FILE - do not edit. Source: registry/ui/radio-group.tsx. Regenerate with `pnpm skill:build`. Curated notes: apps/v4/scripts/skill-reference/notes/radio-group.md -->
|
|
2
|
-
|
|
3
|
-
# radio-group
|
|
4
|
-
|
|
5
|
-
Radix radio group wrapped in a Field; cascades variant and size to Radio items, placement left or right
|
|
6
|
-
|
|
7
|
-
Install: `npx @create-ui/cli add radio-group`
|
|
8
|
-
|
|
9
|
-
## Import
|
|
10
|
-
|
|
11
|
-
```tsx
|
|
12
|
-
import { RadioGroup } from "@/components/ui/radio-group"
|
|
13
|
-
```
|
|
14
|
-
|
|
15
|
-
Also exported: `radioGroupVariants`
|
|
16
|
-
|
|
17
|
-
## RadioGroup props
|
|
18
|
-
|
|
19
|
-
| Prop | Type | Default |
|
|
20
|
-
| --- | --- | --- |
|
|
21
|
-
| variant | `primary \| neutral \| danger` | `primary` |
|
|
22
|
-
| size | `xs \| sm \| md` | `md` |
|
|
23
|
-
| placement | `left \| right` (right only sets flex-row-reverse on the single Field row; in a stacked flex-col layout add flex-row-reverse to each per-option wrapper div instead) | `left` |
|
|
24
|
-
| disabled | `boolean` (Styles the inner Field only; it is NOT forwarded to the Radix root, so also set disabled on each Radio to actually block interaction) | - |
|
|
25
|
-
| invalid | `boolean` (Forwarded to the inner Field; variant='danger' does not set it for you - pass both together for a full error state) | - |
|
|
26
|
-
| fieldClassName | `string` (Layout lives here: fieldClassName='flex-col items-stretch gap-4' is the stacked-list recipe; className only styles the outer Radix root) | - |
|
|
27
|
-
|
|
28
|
-
Extends `React.ComponentProps<typeof RadioGroupPrimitive.Root>`.
|
|
29
|
-
|
|
30
|
-
## Examples
|
|
31
|
-
|
|
32
|
-
From `radio-group-demo`:
|
|
33
|
-
|
|
34
|
-
```tsx
|
|
35
|
-
import { FieldContent } from "@/components/ui/field"
|
|
36
|
-
import { Label, LabelDescription, LabelMain } from "@/components/ui/label"
|
|
37
|
-
import { Radio } from "@/components/ui/radio"
|
|
38
|
-
import { RadioGroup } from "@/components/ui/radio-group"
|
|
39
|
-
|
|
40
|
-
const options = [
|
|
41
|
-
{ value: "free", title: "Free", description: "For personal projects." },
|
|
42
|
-
{
|
|
43
|
-
value: "pro",
|
|
44
|
-
title: "Pro",
|
|
45
|
-
description: "For freelancers and small teams.",
|
|
46
|
-
},
|
|
47
|
-
{
|
|
48
|
-
value: "team",
|
|
49
|
-
title: "Team",
|
|
50
|
-
description: "For larger teams with shared workspaces.",
|
|
51
|
-
},
|
|
52
|
-
]
|
|
53
|
-
|
|
54
|
-
export default function RadioGroupDemo() {
|
|
55
|
-
return (
|
|
56
|
-
<RadioGroup
|
|
57
|
-
defaultValue="pro"
|
|
58
|
-
className="w-[340px]"
|
|
59
|
-
fieldClassName="flex-col items-stretch gap-4"
|
|
60
|
-
>
|
|
61
|
-
{options.map((option) => (
|
|
62
|
-
<div key={option.value} className="flex items-start gap-2">
|
|
63
|
-
<Radio id={`plan-${option.value}`} value={option.value} />
|
|
64
|
-
<FieldContent>
|
|
65
|
-
<LabelMain>
|
|
66
|
-
<Label htmlFor={`plan-${option.value}`}>{option.title}</Label>
|
|
67
|
-
<LabelDescription>{option.description}</LabelDescription>
|
|
68
|
-
</LabelMain>
|
|
69
|
-
</FieldContent>
|
|
70
|
-
</div>
|
|
71
|
-
))}
|
|
72
|
-
</RadioGroup>
|
|
73
|
-
)
|
|
74
|
-
}
|
|
75
|
-
```
|
|
76
|
-
|
|
77
|
-
From `radio-group-controlled`:
|
|
78
|
-
|
|
79
|
-
```tsx
|
|
80
|
-
"use client"
|
|
81
|
-
|
|
82
|
-
import * as React from "react"
|
|
83
|
-
|
|
84
|
-
import { FieldContent } from "@/components/ui/field"
|
|
85
|
-
import { Label, LabelMain } from "@/components/ui/label"
|
|
86
|
-
import { Radio } from "@/components/ui/radio"
|
|
87
|
-
import { RadioGroup } from "@/components/ui/radio-group"
|
|
88
|
-
|
|
89
|
-
const options = ["light", "dark", "system"] as const
|
|
90
|
-
|
|
91
|
-
export default function RadioGroupControlled() {
|
|
92
|
-
const [value, setValue] = React.useState<(typeof options)[number]>("system")
|
|
93
|
-
|
|
94
|
-
return (
|
|
95
|
-
<div className="flex flex-col gap-3">
|
|
96
|
-
<RadioGroup
|
|
97
|
-
value={value}
|
|
98
|
-
onValueChange={(next) => setValue(next as (typeof options)[number])}
|
|
99
|
-
className="w-[280px]"
|
|
100
|
-
fieldClassName="flex-col items-stretch gap-3"
|
|
101
|
-
>
|
|
102
|
-
{options.map((option) => (
|
|
103
|
-
<div key={option} className="flex items-start gap-2">
|
|
104
|
-
<Radio id={`theme-${option}`} value={option} />
|
|
105
|
-
<FieldContent>
|
|
106
|
-
<LabelMain>
|
|
107
|
-
<Label htmlFor={`theme-${option}`}>
|
|
108
|
-
{option.charAt(0).toUpperCase() + option.slice(1)}
|
|
109
|
-
</Label>
|
|
110
|
-
</LabelMain>
|
|
111
|
-
</FieldContent>
|
|
112
|
-
</div>
|
|
113
|
-
))}
|
|
114
|
-
</RadioGroup>
|
|
115
|
-
<p className="text-placeholder text-ui-control-sm">
|
|
116
|
-
Selected: <span className="text-body font-medium">{value}</span>
|
|
117
|
-
</p>
|
|
118
|
-
</div>
|
|
119
|
-
)
|
|
120
|
-
}
|
|
121
|
-
```
|
|
122
|
-
|
|
123
|
-
More: `npx @create-ui/cli view radio-group` or MCP `get_item_examples_from_registries` with "radio-group-demo" / "radio-group-example".
|
|
124
|
-
|
|
125
|
-
## When to use
|
|
126
|
-
Single-select group where all options are visible at once (plan picker, theme, sort order). For multi-select use CheckboxGroup; for long collapsible lists use Select; for a lone on/off use Switch or Checkbox.
|
|
127
|
-
## Gotchas
|
|
128
|
-
- There is no `RadioGroupItem` (shadcn divergence): the item is the separate `Radio` component, and each option is composed manually as a wrapper div with `Radio` plus `FieldContent > LabelMain > Label / LabelDescription` (see radio-group-demo).
|
|
129
|
-
- The component renders ONE `Field` wrapping all children, not a Field per option; `Label`/`LabelDescription` sizing and disabled/invalid styling all cascade from that single Field context.
|
|
130
|
-
- `variant` and `size` cascade to every child `Radio` via `RadioContext`; an explicit prop on a `Radio` wins (`variant ?? ctx ?? default`). Radio's `success`/`inverse` variants cannot be set at group level - pass them per `Radio`.
|
|
131
|
-
- `variant="danger"` recolors every descendant `[data-slot=field-footer]` to `text-error-base`, including per-option footers nested in `FieldContent`.
|
|
132
|
-
- The Radix root sets `orientation="horizontal"` and `display: flex`; a vertical list comes purely from `fieldClassName="flex-col items-stretch ..."`, not from any orientation or layout prop.
|
|
133
|
-
- Group `disabled` never reaches the Radix root, so radios stay interactive unless each `Radio` also gets `disabled` (the disabled demos in radio-group-example set both).
|
|
@@ -1,79 +0,0 @@
|
|
|
1
|
-
<!-- GENERATED FILE - do not edit. Source: registry/ui/radio.tsx. Regenerate with `pnpm skill:build`. Curated notes: apps/v4/scripts/skill-reference/notes/radio.md -->
|
|
2
|
-
|
|
3
|
-
# radio
|
|
4
|
-
|
|
5
|
-
Single radio item for use inside RadioGroup; five variants and xs/sm/md sizes inherit from group context
|
|
6
|
-
|
|
7
|
-
Install: `npx @create-ui/cli add radio`
|
|
8
|
-
|
|
9
|
-
## Import
|
|
10
|
-
|
|
11
|
-
```tsx
|
|
12
|
-
import { Radio } from "@/components/ui/radio"
|
|
13
|
-
```
|
|
14
|
-
|
|
15
|
-
Also exported: `RadioContext`, `radioVariants`, `radioIndicatorVariants`
|
|
16
|
-
|
|
17
|
-
## Radio props
|
|
18
|
-
|
|
19
|
-
| Prop | Type | Default |
|
|
20
|
-
| --- | --- | --- |
|
|
21
|
-
| variant | `primary \| neutral \| danger \| success \| inverse` (Own prop beats RadioGroup context; the only way to get success or inverse inside a group, since RadioGroup's own variant prop offers only primary/neutral/danger) | `primary` |
|
|
22
|
-
| size | `xs \| sm \| md` (Resolved as own prop ?? RadioGroup context ?? md; the CVA defaultVariants sm is dead code because a resolved value is always passed) | `md` |
|
|
23
|
-
|
|
24
|
-
Extends `React.ComponentProps<typeof RadioGroupPrimitive.Item>`.
|
|
25
|
-
|
|
26
|
-
## Examples
|
|
27
|
-
|
|
28
|
-
From `radio-demo`:
|
|
29
|
-
|
|
30
|
-
```tsx
|
|
31
|
-
import { Radio } from "@/components/ui/radio"
|
|
32
|
-
import { RadioGroup } from "@/components/ui/radio-group"
|
|
33
|
-
|
|
34
|
-
export default function RadioDemo() {
|
|
35
|
-
return (
|
|
36
|
-
<RadioGroup defaultValue="a">
|
|
37
|
-
<Radio value="a" aria-label="Option A" />
|
|
38
|
-
<Radio value="b" aria-label="Option B" />
|
|
39
|
-
</RadioGroup>
|
|
40
|
-
)
|
|
41
|
-
}
|
|
42
|
-
```
|
|
43
|
-
|
|
44
|
-
From `radio-in-group`:
|
|
45
|
-
|
|
46
|
-
```tsx
|
|
47
|
-
import { Radio } from "@/components/ui/radio"
|
|
48
|
-
import { RadioGroup } from "@/components/ui/radio-group"
|
|
49
|
-
|
|
50
|
-
export default function RadioInGroup() {
|
|
51
|
-
return (
|
|
52
|
-
<div className="flex flex-col gap-6">
|
|
53
|
-
<RadioGroup variant="neutral" size="md" defaultValue="b">
|
|
54
|
-
<Radio value="a" aria-label="Option A" />
|
|
55
|
-
<Radio value="b" aria-label="Option B" />
|
|
56
|
-
<Radio value="c" aria-label="Option C" />
|
|
57
|
-
</RadioGroup>
|
|
58
|
-
<p className="text-placeholder text-ui-control-sm">
|
|
59
|
-
Children inherit <code>variant</code> and <code>size</code> from the
|
|
60
|
-
group via context — pass them on the group, not each child.
|
|
61
|
-
</p>
|
|
62
|
-
</div>
|
|
63
|
-
)
|
|
64
|
-
}
|
|
65
|
-
```
|
|
66
|
-
|
|
67
|
-
More: `npx @create-ui/cli view radio` or MCP `get_item_examples_from_registries` with "radio-demo" / "radio-example".
|
|
68
|
-
|
|
69
|
-
## When to use
|
|
70
|
-
One item in a mutually-exclusive set of a few always-visible options, always rendered inside `RadioGroup` (it is a Radix RadioGroup.Item and cannot toggle on its own). For long option lists use `Select`; for a binary on/off setting use `Switch`; for standalone or multi-select choices use `Checkbox` / `CheckboxGroup`.
|
|
71
|
-
|
|
72
|
-
## Gotchas
|
|
73
|
-
- `Radio` and `RadioGroup` are separate registry items with separate import paths (`@/components/ui/radio` and `@/components/ui/radio-group`). There is no `RadioGroupItem` export; a shadcn-style `import { RadioGroup, RadioGroupItem } from "@/components/ui/radio-group"` fails.
|
|
74
|
-
- `Radio` renders its indicator dot internally and ignores children. Never nest a `RadioGroupPrimitive.Indicator`, a circle icon, or any content inside it.
|
|
75
|
-
- Styling cascades from the group: `RadioGroup` publishes `variant`/`size` through `RadioContext`, so set them once on the group, not per child. A per-Radio prop overrides the context when one item must differ.
|
|
76
|
-
- `RadioGroup` wraps its children in a horizontal `Field`, so labeled rows use `FieldLabel htmlFor` next to the radio (or `aria-label` when there is no visible label, as in `radio-demo`).
|
|
77
|
-
- `RadioGroup`'s `invalid` and `disabled` props are passed only to the `Field` wrapper, never to the Radix root or the items: `invalid` colors the field footer but does not set `aria-invalid`, and `disabled` styles labels (cursor, pointer-events) while the radios stay interactive. The red outline needs `aria-invalid` on the `Radio` itself, and disabling needs `disabled` on each `Radio`.
|
|
78
|
-
- `variant="danger"` only colors the checked/focus state; it does not mark the field invalid. The error outline comes solely from the item's `aria-invalid` attribute, on any variant.
|
|
79
|
-
- `inverse` is built for dark surfaces: unchecked border and checked dot use light tokens, and focus-visible fills the control with static-black. `radio-example` shows it on a `bg-strongest` panel; on a light surface it is near-invisible.
|