@create-ui/cli 0.6.0 → 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 +16 -16
- 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 -52
- 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/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/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,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.
|
|
@@ -1,212 +0,0 @@
|
|
|
1
|
-
<!-- GENERATED FILE - do not edit. Source: registry/ui/scroll-area.tsx. Regenerate with `pnpm skill:build`. Curated notes: apps/v4/scripts/skill-reference/notes/scroll-area.md -->
|
|
2
|
-
|
|
3
|
-
# scroll-area
|
|
4
|
-
|
|
5
|
-
Custom-scrollbar viewport; vertical, horizontal or both, filled/ghost scrollbar styles and optional edge fade
|
|
6
|
-
|
|
7
|
-
Install: `npx @create-ui/cli add scroll-area`
|
|
8
|
-
|
|
9
|
-
## Import
|
|
10
|
-
|
|
11
|
-
```tsx
|
|
12
|
-
import { ScrollArea, ScrollBar } from "@/components/ui/scroll-area"
|
|
13
|
-
```
|
|
14
|
-
|
|
15
|
-
Also exported: `scrollBarVariants`
|
|
16
|
-
|
|
17
|
-
## ScrollArea props
|
|
18
|
-
|
|
19
|
-
| Prop | Type | Default |
|
|
20
|
-
| --- | --- | --- |
|
|
21
|
-
| appearance | `filled \| ghost` (filled adds a bg-weak track behind the thumb; ghost shows only the thumb; forwarded to all auto-rendered scrollbars) | `filled` |
|
|
22
|
-
| size | `sm \| md \| lg` (Set once on ScrollArea; forwarded to every auto-rendered scrollbar) | `md` |
|
|
23
|
-
| orientation | `vertical \| horizontal \| both` (Auto-renders the matching scrollbar(s); a Corner is always rendered, so 'both' needs no extra children) | `vertical` |
|
|
24
|
-
| fade | `boolean` (End-of-scroll gradient only (bottom / right edge); hides at scroll end or when content fits, re-checked on scroll, resize, and DOM mutations) | `false` |
|
|
25
|
-
|
|
26
|
-
Extends `React.ComponentProps<typeof ScrollAreaPrimitive.Root>`.
|
|
27
|
-
|
|
28
|
-
## ScrollBar props
|
|
29
|
-
|
|
30
|
-
| Prop | Type | Default |
|
|
31
|
-
| --- | --- | --- |
|
|
32
|
-
| appearance | `filled \| ghost` (filled adds a bg-weak track behind the thumb; ghost shows only the thumb; forwarded to all auto-rendered scrollbars) | `filled` |
|
|
33
|
-
| size | `sm \| md \| lg` (Set once on ScrollArea; forwarded to every auto-rendered scrollbar) | `md` |
|
|
34
|
-
|
|
35
|
-
Extends `React.ComponentProps<typeof ScrollAreaPrimitive.ScrollAreaScrollbar>`.
|
|
36
|
-
|
|
37
|
-
## Examples
|
|
38
|
-
|
|
39
|
-
From `scroll-area-demo`:
|
|
40
|
-
|
|
41
|
-
```tsx
|
|
42
|
-
import * as React from "react"
|
|
43
|
-
|
|
44
|
-
import { ScrollArea } from "@/components/ui/scroll-area"
|
|
45
|
-
import { Separator } from "@/components/ui/separator"
|
|
46
|
-
|
|
47
|
-
const components = [
|
|
48
|
-
"Accordion",
|
|
49
|
-
"Alert Banner",
|
|
50
|
-
"App Store Badge",
|
|
51
|
-
"Aspect Ratio",
|
|
52
|
-
"Avatar",
|
|
53
|
-
"Badge",
|
|
54
|
-
"Breadcrumb",
|
|
55
|
-
"Button",
|
|
56
|
-
"Button Group",
|
|
57
|
-
"Checkbox",
|
|
58
|
-
"Checkbox Group",
|
|
59
|
-
"Chip",
|
|
60
|
-
"Close Button",
|
|
61
|
-
"Command",
|
|
62
|
-
"Country Flag",
|
|
63
|
-
"Credit Card Input",
|
|
64
|
-
"Date Input",
|
|
65
|
-
"Dialog",
|
|
66
|
-
"Dropdown Menu",
|
|
67
|
-
"Field",
|
|
68
|
-
"Info Tooltip",
|
|
69
|
-
"Inline Alert",
|
|
70
|
-
"Input",
|
|
71
|
-
"Input Group",
|
|
72
|
-
"Input OTP",
|
|
73
|
-
"Input Stepper",
|
|
74
|
-
"Label",
|
|
75
|
-
"Modal",
|
|
76
|
-
"Pagination",
|
|
77
|
-
"Password Strength",
|
|
78
|
-
"Phone Input",
|
|
79
|
-
"Popover",
|
|
80
|
-
"Progress",
|
|
81
|
-
"Radio",
|
|
82
|
-
"Radio Group",
|
|
83
|
-
"Scroll Area",
|
|
84
|
-
"Segmented Control",
|
|
85
|
-
"Select",
|
|
86
|
-
"Separator",
|
|
87
|
-
"Social Login Button",
|
|
88
|
-
"Spinner",
|
|
89
|
-
"Status Badge",
|
|
90
|
-
"Switch",
|
|
91
|
-
"Switch Group",
|
|
92
|
-
"Tab Menu",
|
|
93
|
-
"Text Link",
|
|
94
|
-
"Textarea",
|
|
95
|
-
"Toast",
|
|
96
|
-
"Tooltip",
|
|
97
|
-
]
|
|
98
|
-
|
|
99
|
-
export default function ScrollAreaDemo() {
|
|
100
|
-
return (
|
|
101
|
-
<ScrollArea className="bg-weakest text-strong h-72 w-48 rounded-md">
|
|
102
|
-
<div className="p-4">
|
|
103
|
-
<h4 className="mb-4 text-sm leading-none font-medium">Components</h4>
|
|
104
|
-
{components.map((component) => (
|
|
105
|
-
<React.Fragment key={component}>
|
|
106
|
-
<div className="text-sm">{component}</div>
|
|
107
|
-
<Separator className="my-2" />
|
|
108
|
-
</React.Fragment>
|
|
109
|
-
))}
|
|
110
|
-
</div>
|
|
111
|
-
</ScrollArea>
|
|
112
|
-
)
|
|
113
|
-
}
|
|
114
|
-
```
|
|
115
|
-
|
|
116
|
-
From `scroll-area-fade`:
|
|
117
|
-
|
|
118
|
-
```tsx
|
|
119
|
-
import * as React from "react"
|
|
120
|
-
|
|
121
|
-
import { ScrollArea } from "@/components/ui/scroll-area"
|
|
122
|
-
import { Separator } from "@/components/ui/separator"
|
|
123
|
-
|
|
124
|
-
const components = [
|
|
125
|
-
"Accordion",
|
|
126
|
-
"Alert Banner",
|
|
127
|
-
"App Store Badge",
|
|
128
|
-
"Aspect Ratio",
|
|
129
|
-
"Avatar",
|
|
130
|
-
"Badge",
|
|
131
|
-
"Breadcrumb",
|
|
132
|
-
"Button",
|
|
133
|
-
"Button Group",
|
|
134
|
-
"Checkbox",
|
|
135
|
-
"Checkbox Group",
|
|
136
|
-
"Chip",
|
|
137
|
-
"Close Button",
|
|
138
|
-
"Command",
|
|
139
|
-
"Country Flag",
|
|
140
|
-
"Credit Card Input",
|
|
141
|
-
"Date Input",
|
|
142
|
-
"Dialog",
|
|
143
|
-
"Dropdown Menu",
|
|
144
|
-
"Field",
|
|
145
|
-
"Info Tooltip",
|
|
146
|
-
"Inline Alert",
|
|
147
|
-
"Input",
|
|
148
|
-
"Input Group",
|
|
149
|
-
"Input OTP",
|
|
150
|
-
"Input Stepper",
|
|
151
|
-
"Label",
|
|
152
|
-
"Modal",
|
|
153
|
-
"Pagination",
|
|
154
|
-
"Password Strength",
|
|
155
|
-
"Phone Input",
|
|
156
|
-
"Popover",
|
|
157
|
-
"Progress",
|
|
158
|
-
"Radio",
|
|
159
|
-
"Radio Group",
|
|
160
|
-
"Scroll Area",
|
|
161
|
-
"Segmented Control",
|
|
162
|
-
"Select",
|
|
163
|
-
"Separator",
|
|
164
|
-
"Social Login Button",
|
|
165
|
-
"Spinner",
|
|
166
|
-
"Status Badge",
|
|
167
|
-
"Switch",
|
|
168
|
-
"Switch Group",
|
|
169
|
-
"Tab Menu",
|
|
170
|
-
"Text Link",
|
|
171
|
-
"Textarea",
|
|
172
|
-
"Toast",
|
|
173
|
-
"Tooltip",
|
|
174
|
-
]
|
|
175
|
-
|
|
176
|
-
export default function ScrollAreaFade() {
|
|
177
|
-
return (
|
|
178
|
-
<ScrollArea fade className="bg-weakest text-strong h-72 w-48 rounded-md">
|
|
179
|
-
<div className="p-4">
|
|
180
|
-
<h4 className="mb-4 text-sm leading-none font-medium">Components</h4>
|
|
181
|
-
{components.map((component) => (
|
|
182
|
-
<React.Fragment key={component}>
|
|
183
|
-
<div className="text-sm">{component}</div>
|
|
184
|
-
<Separator className="my-2" />
|
|
185
|
-
</React.Fragment>
|
|
186
|
-
))}
|
|
187
|
-
</div>
|
|
188
|
-
</ScrollArea>
|
|
189
|
-
)
|
|
190
|
-
}
|
|
191
|
-
```
|
|
192
|
-
|
|
193
|
-
More: `npx @create-ui/cli view scroll-area` or MCP `get_item_examples_from_registries` with "scroll-area-demo" / "scroll-area-example".
|
|
194
|
-
|
|
195
|
-
## When to use
|
|
196
|
-
Styled overlay-scrollbar viewport for content that overflows a fixed-size surface: lists in panels, image rows, wide grids. Do not use it for full-page scrolling (let the browser handle that). DropdownMenu and Select content panels already scroll on their own; do not wrap them in ScrollArea.
|
|
197
|
-
|
|
198
|
-
## Gotchas
|
|
199
|
-
- Unlike shadcn, you never add a `<ScrollBar>` child. `ScrollArea` renders viewport, scrollbar(s), and corner itself from `orientation`; horizontal scrolling is `orientation="horizontal"`, not an extra child. A `<ScrollBar>` child would land inside the scrolled viewport content; the export exists only for fully custom setups.
|
|
200
|
-
- Width/height constraints go on the root `className` (e.g. `h-72 w-48`); the internal viewport is `size-full` and inherits the root's radius. Without a fixed dimension on the enabled axis nothing scrolls.
|
|
201
|
-
- Horizontal content must actually overflow: a non-wrapping flex row with `shrink-0` children inside a width-constrained root, e.g.
|
|
202
|
-
|
|
203
|
-
```tsx
|
|
204
|
-
<ScrollArea orientation="horizontal" className="w-full max-w-96 rounded-md p-4">
|
|
205
|
-
<div className="flex gap-4">{items /* each child shrink-0 */}</div>
|
|
206
|
-
</ScrollArea>
|
|
207
|
-
```
|
|
208
|
-
|
|
209
|
-
- `fade` overlays mark only the scroll END of each enabled axis (bottom for vertical, right for horizontal); there is no top/left start fade. They are `aria-hidden` and `pointer-events-none`, and dynamic content is handled automatically (scroll listener + ResizeObserver + MutationObserver).
|
|
210
|
-
- The fade gradient ends in the `static-white` token (white in light mode, black in dark), not the container's own background. On a tinted container (e.g. `bg-weakest`) the fade edge will not exactly match the surface color.
|
|
211
|
-
- Scrollbars are `forceMount`ed and toggle via opacity (`data-[state=hidden/visible]`); show/hide timing comes from the Radix root's `type` and `scrollHideDelay` props, which pass through `ScrollArea` untouched.
|
|
212
|
-
- The `cn-scroll-area*` classes are intentional style-less hooks for consumer CSS targeting; do not strip them as dead code.
|