@create-ui/cli 0.5.8 → 0.6.0

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (72) hide show
  1. package/dist/{chunk-RMTTHCB3.js → chunk-2ELKDGGM.js} +3 -3
  2. package/dist/{chunk-RMTTHCB3.js.map → chunk-2ELKDGGM.js.map} +1 -1
  3. package/dist/chunk-643QI2I2.js +102 -0
  4. package/dist/chunk-643QI2I2.js.map +1 -0
  5. package/dist/{chunk-NQFMXHMH.js → chunk-KQTXDVKV.js} +3 -3
  6. package/dist/chunk-KQTXDVKV.js.map +1 -0
  7. package/dist/index.d.ts +360 -360
  8. package/dist/index.js +26 -26
  9. package/dist/index.js.map +1 -1
  10. package/dist/mcp/index.js +1 -1
  11. package/dist/registry/index.d.ts +2 -2
  12. package/dist/registry/index.js +1 -1
  13. package/dist/schema/index.d.ts +715 -715
  14. package/dist/skills/createui/SKILL.md +199 -177
  15. package/dist/skills/createui/agents/openai.yml +1 -1
  16. package/dist/skills/createui/cli.md +42 -42
  17. package/dist/skills/createui/customization.md +20 -15
  18. package/dist/skills/createui/evals/evals.json +68 -5
  19. package/dist/skills/createui/mcp.md +14 -5
  20. package/dist/skills/createui/reference/accordion.md +127 -0
  21. package/dist/skills/createui/reference/app-store-badge.md +88 -0
  22. package/dist/skills/createui/reference/aspect-ratio.md +52 -0
  23. package/dist/skills/createui/reference/avatar.md +230 -0
  24. package/dist/skills/createui/reference/badge.md +110 -0
  25. package/dist/skills/createui/reference/breadcrumb.md +153 -0
  26. package/dist/skills/createui/reference/button-group.md +116 -0
  27. package/dist/skills/createui/reference/button.md +104 -0
  28. package/dist/skills/createui/reference/checkbox-group.md +118 -0
  29. package/dist/skills/createui/reference/checkbox.md +79 -0
  30. package/dist/skills/createui/reference/chip.md +115 -0
  31. package/dist/skills/createui/reference/close-button.md +83 -0
  32. package/dist/skills/createui/reference/country-flag.md +109 -0
  33. package/dist/skills/createui/reference/credit-card-input.md +76 -0
  34. package/dist/skills/createui/reference/date-input.md +71 -0
  35. package/dist/skills/createui/reference/dropdown-menu.md +164 -0
  36. package/dist/skills/createui/reference/field.md +186 -0
  37. package/dist/skills/createui/reference/info-tooltip.md +110 -0
  38. package/dist/skills/createui/reference/inline-alert.md +146 -0
  39. package/dist/skills/createui/reference/input-group.md +171 -0
  40. package/dist/skills/createui/reference/input-otp.md +130 -0
  41. package/dist/skills/createui/reference/input-stepper.md +120 -0
  42. package/dist/skills/createui/reference/input.md +118 -0
  43. package/dist/skills/createui/reference/label.md +121 -0
  44. package/dist/skills/createui/reference/pagination.md +157 -0
  45. package/dist/skills/createui/reference/phone-input.md +77 -0
  46. package/dist/skills/createui/reference/progress.md +158 -0
  47. package/dist/skills/createui/reference/radio-group.md +133 -0
  48. package/dist/skills/createui/reference/radio.md +79 -0
  49. package/dist/skills/createui/reference/scroll-area.md +212 -0
  50. package/dist/skills/createui/reference/segmented-control.md +146 -0
  51. package/dist/skills/createui/reference/select.md +204 -0
  52. package/dist/skills/createui/reference/separator.md +99 -0
  53. package/dist/skills/createui/reference/social-login-button.md +130 -0
  54. package/dist/skills/createui/reference/spinner.md +68 -0
  55. package/dist/skills/createui/reference/status-badge.md +89 -0
  56. package/dist/skills/createui/reference/switch-group.md +122 -0
  57. package/dist/skills/createui/reference/switch.md +75 -0
  58. package/dist/skills/createui/reference/tab-menu.md +165 -0
  59. package/dist/skills/createui/reference/text-link.md +84 -0
  60. package/dist/skills/createui/reference/textarea.md +50 -0
  61. package/dist/skills/createui/reference/toast.md +162 -0
  62. package/dist/skills/createui/reference/tooltip.md +63 -0
  63. package/dist/skills/createui/rules/composition.md +41 -25
  64. package/dist/skills/createui/rules/design.md +266 -0
  65. package/dist/skills/createui/rules/forms.md +44 -15
  66. package/dist/skills/createui/rules/icons.md +64 -18
  67. package/dist/skills/createui/rules/styling.md +53 -14
  68. package/dist/utils/index.js +1 -1
  69. package/package.json +1 -1
  70. package/dist/chunk-M5DYT2NE.js +0 -64
  71. package/dist/chunk-M5DYT2NE.js.map +0 -1
  72. package/dist/chunk-NQFMXHMH.js.map +0 -1
@@ -0,0 +1,89 @@
1
+ <!-- GENERATED FILE - do not edit. Source: registry/ui/status-badge.tsx. Regenerate with `pnpm skill:build`. Curated notes: apps/v4/scripts/skill-reference/notes/status-badge.md -->
2
+
3
+ # status-badge
4
+
5
+ Tiny presence dot only, no built-in label; 12 status colors and xs/sm/md sizes, place text beside it yourself
6
+
7
+ Install: `npx @create-ui/cli add status-badge`
8
+
9
+ ## Import
10
+
11
+ ```tsx
12
+ import { StatusBadge } from "@/components/ui/status-badge"
13
+ ```
14
+
15
+ Also exported: `statusBadgeVariants`
16
+
17
+ ## StatusBadge props
18
+
19
+ | Prop | Type | Default |
20
+ | --- | --- | --- |
21
+ | variant | `primary \| danger \| success \| warning \| info \| highlighted \| away \| verified \| cyan \| lime \| neutral \| white` (Error tone is \"danger\" (there is no \"error\" or \"destructive\" key); \"white\" is the only variant that drops the built-in outline ring, for use on dark surfaces) | `primary` |
22
+ | size | `xs \| sm \| md` (Fixed pixel diameters (xs 4px, sm 6px, md 8px); standalone, no Field/InputGroup size cascade) | `md` |
23
+
24
+ Extends `React.ComponentProps<"span">`.
25
+
26
+ ## Examples
27
+
28
+ From `status-badge-demo`:
29
+
30
+ ```tsx
31
+ import { StatusBadge } from "@/components/ui/status-badge"
32
+
33
+ export default function StatusBadgeDemo() {
34
+ return (
35
+ <div className="flex flex-wrap items-center gap-4">
36
+ <div className="flex items-center gap-2">
37
+ <StatusBadge variant="success" />
38
+ <span className="text-body text-sm">Online</span>
39
+ </div>
40
+ <div className="flex items-center gap-2">
41
+ <StatusBadge variant="away" />
42
+ <span className="text-body text-sm">Away</span>
43
+ </div>
44
+ <div className="flex items-center gap-2">
45
+ <StatusBadge variant="danger" />
46
+ <span className="text-body text-sm">Offline</span>
47
+ </div>
48
+ </div>
49
+ )
50
+ }
51
+ ```
52
+
53
+ From `status-badge-in-avatar`:
54
+
55
+ ```tsx
56
+ import { StatusBadge } from "@/components/ui/status-badge"
57
+
58
+ export default function StatusBadgeInAvatar() {
59
+ return (
60
+ <div className="flex flex-wrap items-center gap-6">
61
+ <div className="relative">
62
+ <div className="from-light to-weak size-10 rounded-full bg-gradient-to-br" />
63
+ <StatusBadge variant="success" className="absolute right-0 bottom-0" />
64
+ </div>
65
+ <div className="relative">
66
+ <div className="from-light to-weak size-10 rounded-full bg-gradient-to-br" />
67
+ <StatusBadge variant="away" className="absolute right-0 bottom-0" />
68
+ </div>
69
+ <div className="relative">
70
+ <div className="from-light to-weak size-10 rounded-full bg-gradient-to-br" />
71
+ <StatusBadge variant="neutral" className="absolute right-0 bottom-0" />
72
+ </div>
73
+ </div>
74
+ )
75
+ }
76
+ ```
77
+
78
+ More: `npx @create-ui/cli view status-badge` or MCP `get_item_examples_from_registries` with "status-badge-demo" / "status-badge-example".
79
+
80
+ ## When to use
81
+ StatusBadge is a dot-only presence/state indicator (a single `<span role="status">` circle): online dots on avatars, live markers on rows, status legends. It carries no text; a sibling label or the host element gives it meaning. If the indicator needs a label or count use Badge, for transient events use Toast, and for loading use Spinner.
82
+
83
+ ## Gotchas
84
+ - Do not pass children; the component renders a fixed-size dot (`size-1`/`1.5`/`2`, i.e. 4-8px) and any content would overflow the box. Render the label as a sibling in a flex row: `<StatusBadge variant="success" /> <span>Online</span>`.
85
+ - A white outline ring (`outline-static-white outline`) is built into every variant so the dot stays legible layered over avatars; only the `white` variant removes it (`outline-0`). Do not re-add `ring-*` or borders to fake this.
86
+ - Avatar pinning is manual composition: wrap the avatar in `relative` and position the badge with `className="absolute right-0 bottom-0"`. There is no `position`/anchor prop.
87
+ - This is not shadcn's `Badge`: no text slot and no `asChild`.
88
+ - `role="status"` is hardcoded, but the dot has no announced content, so pair it with a visible text label or put `aria-label` on the surrounding element.
89
+ - No `data-variant`/`data-size` attributes are emitted; CSS targeting goes through `data-slot="status-badge"` plus classes. `shrink-0` is built in, so it will not squash in tight flex rows.
@@ -0,0 +1,122 @@
1
+ <!-- GENERATED FILE - do not edit. Source: registry/ui/switch-group.tsx. Regenerate with `pnpm skill:build`. Curated notes: apps/v4/scripts/skill-reference/notes/switch-group.md -->
2
+
3
+ # switch-group
4
+
5
+ Field wrapper that labels a Switch and cascades variant, size, shape, thumbType and ioTrigger; placement left or right
6
+
7
+ Install: `npx @create-ui/cli add switch-group`
8
+
9
+ ## Import
10
+
11
+ ```tsx
12
+ import { SwitchGroup } from "@/components/ui/switch-group"
13
+ ```
14
+
15
+ Also exported: `switchGroupVariants`
16
+
17
+ ## SwitchGroup props
18
+
19
+ | Prop | Type | Default |
20
+ | --- | --- | --- |
21
+ | variant | `SwitchVariant` | `primary` |
22
+ | size | `xs \| sm \| md` (Sets the Field label scale and the child Switch size via context; Field's own size and orientation props are stripped from the API (orientation is locked horizontal)) | `md` |
23
+ | shape | `SwitchShape` | `pill` |
24
+ | thumbType | `SwitchThumbType` | `short` |
25
+ | ioTrigger | `boolean` | `false` |
26
+ | placement | `left \| right` (right is a CSS-only flip (flex-row-reverse); keep the Switch first in the DOM either way) | `left` |
27
+
28
+ Extends `React.ComponentProps<typeof Field>`.
29
+
30
+ ## Examples
31
+
32
+ From `switch-group-demo`:
33
+
34
+ ```tsx
35
+ import { FieldContent } from "@/components/ui/field"
36
+ import { Label, LabelDescription, LabelMain } from "@/components/ui/label"
37
+ import { Switch } from "@/components/ui/switch"
38
+ import { SwitchGroup } from "@/components/ui/switch-group"
39
+
40
+ export default function SwitchGroupDemo() {
41
+ return (
42
+ <SwitchGroup className="w-[340px]">
43
+ <Switch id="sw-demo" defaultChecked />
44
+ <FieldContent>
45
+ <LabelMain>
46
+ <Label htmlFor="sw-demo">Push notifications</Label>
47
+ <LabelDescription>
48
+ Get alerts the moment something happens on your account.
49
+ </LabelDescription>
50
+ </LabelMain>
51
+ </FieldContent>
52
+ </SwitchGroup>
53
+ )
54
+ }
55
+ ```
56
+
57
+ From `switch-group-disabled`:
58
+
59
+ ```tsx
60
+ import { FieldContent } from "@/components/ui/field"
61
+ import { Label, LabelDescription, LabelMain } from "@/components/ui/label"
62
+ import { Switch } from "@/components/ui/switch"
63
+ import { SwitchGroup } from "@/components/ui/switch-group"
64
+
65
+ export default function SwitchGroupDisabled() {
66
+ return (
67
+ <div className="flex flex-col gap-6">
68
+ <SwitchGroup disabled className="w-[340px]">
69
+ <Switch id="sw-disabled-on" checked disabled />
70
+ <FieldContent>
71
+ <LabelMain>
72
+ <Label htmlFor="sw-disabled-on">Push notifications</Label>
73
+ <LabelDescription>
74
+ Disabled state cascades to label and description.
75
+ </LabelDescription>
76
+ </LabelMain>
77
+ </FieldContent>
78
+ </SwitchGroup>
79
+
80
+ <SwitchGroup disabled className="w-[340px]">
81
+ <Switch id="sw-disabled-off" checked={false} disabled />
82
+ <FieldContent>
83
+ <LabelMain>
84
+ <Label htmlFor="sw-disabled-off">Marketing emails</Label>
85
+ <LabelDescription>
86
+ The unchecked row reads muted too.
87
+ </LabelDescription>
88
+ </LabelMain>
89
+ </FieldContent>
90
+ </SwitchGroup>
91
+ </div>
92
+ )
93
+ }
94
+ ```
95
+
96
+ More: `npx @create-ui/cli view switch-group` or MCP `get_item_examples_from_registries` with "switch-group-demo" / "switch-group-example".
97
+
98
+ ## When to use
99
+ One labelled switch row for settings that apply the moment they flip: notification preferences, feature flags, privacy toggles. Stack several SwitchGroups in a column for a settings panel. Do NOT use it inside a submit-to-save form (use CheckboxGroup), for one-of-many selection (use RadioGroup), or for a bare unlabelled toggle in a toolbar or table cell (use Switch directly).
100
+
101
+ ## Gotchas
102
+ - Despite the name, SwitchGroup is a single row, not a multi-switch container, and it renders no Switch of its own. There is no SwitchGroupItem; you compose the anatomy yourself:
103
+
104
+ ```tsx
105
+ <SwitchGroup>
106
+ <Switch id="x" />
107
+ <FieldContent>
108
+ <LabelMain>
109
+ <Label htmlFor="x">Title</Label>
110
+ <LabelDescription>Optional helper.</LabelDescription>
111
+ </LabelMain>
112
+ <FieldFooter>{/* optional, e.g. TextLink */}</FieldFooter>
113
+ </FieldContent>
114
+ </SwitchGroup>
115
+ ```
116
+
117
+ - The child Switch resolves each look prop as explicit prop ?? SwitchContext ?? default, so any prop set directly on the Switch silently overrides the group; configure looks on the group and keep the Switch bare except id/checked/disabled.
118
+ - The context the group provides carries variant, size, shape, thumbType, ioTrigger only. SwitchGroup has no thumbIcon prop and never forwards one; set thumbIcon on the Switch itself.
119
+ - Label association is manual: the Field root is a role="group" div, not a label, so always pair Switch id with Label htmlFor.
120
+ - For a disabled row, set disabled on BOTH the group (label/description fade via Field) and the child Switch (the actual control), as in switch-group-disabled.
121
+ - The label block must sit inside FieldContent: Field only top-aligns the switch when a direct [data-slot=field-content] child exists (has-[] selector), so loose Label siblings sit in a row and break the stacking.
122
+ - SwitchGroup is a Field, so its root is full-width: placed inline (e.g. the right side of a justify-between header or toolbar) it wraps onto its own full-width line unless you constrain it with an explicit width (className="w-auto", max-w-*, or a fixed width).
@@ -0,0 +1,75 @@
1
+ <!-- GENERATED FILE - do not edit. Source: registry/ui/switch.tsx. Regenerate with `pnpm skill:build`. Curated notes: apps/v4/scripts/skill-reference/notes/switch.md -->
2
+
3
+ # switch
4
+
5
+ Toggle switch; variant primary/info/neutral/inverse/semantic, thumbType short/long, ioTrigger and thumbIcon options
6
+
7
+ Install: `npx @create-ui/cli add switch`
8
+
9
+ ## Import
10
+
11
+ ```tsx
12
+ import { Switch } from "@/components/ui/switch"
13
+ ```
14
+
15
+ Also exported: `SwitchContext`, `switchVariants`
16
+
17
+ ## Switch props
18
+
19
+ | Prop | Type | Default |
20
+ | --- | --- | --- |
21
+ | variant | `primary \| info \| neutral \| inverse \| semantic` (semantic = red when off, green when on (accept/reject patterns)) | `primary` |
22
+ | size | `md \| sm \| xs` | `md` |
23
+ | shape | `pill \| rounded` | `pill` |
24
+ | thumbType | `short \| long` (long is a statically wider thumb and track; checked travel distance is unchanged) | `short` |
25
+ | ioTrigger | `boolean` (aria-hidden I/O glyphs in the track: line when on, circle when off) | `false` |
26
+ | thumbIcon | `boolean` (aria-hidden check/close icons inside the thumb) | `false` |
27
+
28
+ Extends `React.ComponentProps<typeof SwitchPrimitive.Root>`.
29
+
30
+ ## Examples
31
+
32
+ From `switch-demo`:
33
+
34
+ ```tsx
35
+ import { Switch } from "@/components/ui/switch"
36
+
37
+ export default function SwitchDemo() {
38
+ return (
39
+ <div className="flex items-center gap-3">
40
+ <Switch defaultChecked />
41
+ <Switch />
42
+ </div>
43
+ )
44
+ }
45
+ ```
46
+
47
+ From `switch-thumb-icon`:
48
+
49
+ ```tsx
50
+ import { Switch } from "@/components/ui/switch"
51
+
52
+ export default function SwitchThumbIcon() {
53
+ return (
54
+ <div className="flex items-center gap-4">
55
+ <Switch thumbIcon defaultChecked />
56
+ <Switch thumbIcon />
57
+ </div>
58
+ )
59
+ }
60
+ ```
61
+
62
+ More: `npx @create-ui/cli view switch` or MCP `get_item_examples_from_registries` with "switch-demo" / "switch-example".
63
+
64
+ ## When to use
65
+
66
+ A single standalone on/off control. A boolean that only commits on form submit is `Checkbox`. A switch with a label and description in one apply-immediately row is `SwitchGroup` (it wraps `Field orientation="horizontal"` and feeds `SwitchContext`); do not hand-roll that row from `Field` + `Switch`. Exception: inside a submit-to-save form that deliberately uses toggles, `SwitchGroup` is wrong - compose `Field size="md" orientation="horizontal"` + `FieldContent` (`FieldLabel` + `FieldDescription`) + `Switch`, as in the field-composition example.
67
+
68
+ ## Gotchas
69
+
70
+ - Every visual prop resolves `prop ?? SwitchContext ?? default`. `SwitchGroup` provides context for `variant`/`size`/`shape`/`thumbType`/`ioTrigger`, so set those on the group, not the inner Switch. `thumbIcon` is NOT in the group context; set it on the Switch itself. For an ad-hoc cluster, wrap in the exported `SwitchContext.Provider`.
71
+ - `Field` size does NOT cascade here: Switch reads only `SwitchContext`, never Field's context. In a plain `Field` row, set `size` on the Switch itself.
72
+ - Do not pass children to `<Switch>`; it renders its own thumb/icon internals and silently replaces anything you pass. The label lives outside (`Label htmlFor` + `id`, or `aria-label`).
73
+ - Track width is a fixed pixel value per `size` x `thumbType`, and the checked `translate-x` is fixed per `size` (22/18/14px). Overriding width via `className` desyncs the thumb travel; change `size`/`thumbType` instead.
74
+ - The clickable area is silently enlarged by an `after:` pseudo-element (12px horizontally, 8px vertically past the track); keep other clickable controls clear of that zone.
75
+ - Error state comes from passing `aria-invalid` (persistent red outline), not from a variant.
@@ -0,0 +1,165 @@
1
+ <!-- GENERATED FILE - do not edit. Source: registry/ui/tab-menu.tsx. Regenerate with `pnpm skill:build`. Curated notes: apps/v4/scripts/skill-reference/notes/tab-menu.md -->
2
+
3
+ # tab-menu
4
+
5
+ Navigation tab list with no content panels; vertical/horizontal button and line variants, leadingIcon/trailingIcon items
6
+
7
+ Install: `npx @create-ui/cli add tab-menu`
8
+
9
+ ## Import
10
+
11
+ ```tsx
12
+ import { TabMenu, TabMenuItem } from "@/components/ui/tab-menu"
13
+ ```
14
+
15
+ Also exported: `tabMenuVariants`, `tabMenuItemVariants`
16
+
17
+ ## TabMenu props
18
+
19
+ | Prop | Type | Default |
20
+ | --- | --- | --- |
21
+ | variant | `vertical-button \| vertical-line \| horizontal-line \| horizontal-button` | `vertical-button` |
22
+ | size | `sm \| md \| lg` | `md` |
23
+ | indicator | `left \| top \| bottom` (line variants render no active line without it; designed pairings: vertical-button+left, vertical-line/horizontal-line+top|bottom; horizontal-button takes none) | - |
24
+ | value | `string` | - |
25
+ | defaultValue | `string` | - |
26
+ | onValueChange | `(value: string) => void` | - |
27
+
28
+ Extends `React.ComponentProps<"div">`.
29
+
30
+ ## TabMenuItem props
31
+
32
+ | Prop | Type | Default |
33
+ | --- | --- | --- |
34
+ | asChild | `boolean` | `false` |
35
+ | value | `string` | - |
36
+ | selected | `boolean` (overrides value matching; use for route-driven tabs where the pathname decides) | - |
37
+ | leadingIcon | `ReactNode` | - |
38
+ | trailingIcon | `ReactNode` | - |
39
+ | label | `ReactNode` (the label slot; bare children are NOT the label (they render as extra content next to it, e.g. a Badge)) | - |
40
+
41
+ Extends `React.ComponentProps<"button">`.
42
+
43
+ ## Icons
44
+
45
+ Icons go through icon props - never as children next to text, and never with sizing classes (the component sizes icons per `size`): `TabMenuItem` (`leadingIcon` / `trailingIcon`). Import icons from `@create-ui/assets/icons` (Remix `Ri*`).
46
+
47
+ ## Examples
48
+
49
+ From `tab-menu-demo`:
50
+
51
+ ```tsx
52
+ import {
53
+ RiBankCardFill,
54
+ RiInboxLine,
55
+ RiInformationFill,
56
+ RiSettings6Fill,
57
+ } from "@create-ui/assets/icons"
58
+
59
+ import { TabMenu, TabMenuItem } from "@/components/ui/tab-menu"
60
+
61
+ export default function TabMenuDemo() {
62
+ return (
63
+ <TabMenu
64
+ variant="horizontal-line"
65
+ indicator="bottom"
66
+ size="lg"
67
+ defaultValue="activity"
68
+ >
69
+ <TabMenuItem
70
+ value="overview"
71
+ leadingIcon={<RiInformationFill />}
72
+ label="Overview"
73
+ />
74
+ <TabMenuItem
75
+ value="activity"
76
+ leadingIcon={<RiInboxLine />}
77
+ label="Activity"
78
+ />
79
+ <TabMenuItem
80
+ value="billing"
81
+ leadingIcon={<RiBankCardFill />}
82
+ label="Billing"
83
+ />
84
+ <TabMenuItem
85
+ value="settings"
86
+ leadingIcon={<RiSettings6Fill />}
87
+ label="Settings"
88
+ />
89
+ </TabMenu>
90
+ )
91
+ }
92
+ ```
93
+
94
+ From `tab-menu-with-badge`:
95
+
96
+ ```tsx
97
+ import {
98
+ RiBankCardFill,
99
+ RiInboxLine,
100
+ RiSettings6Fill,
101
+ } from "@create-ui/assets/icons"
102
+
103
+ import { Badge } from "@/components/ui/badge"
104
+ import { StatusBadge } from "@/components/ui/status-badge"
105
+ import { TabMenu, TabMenuItem } from "@/components/ui/tab-menu"
106
+
107
+ export default function TabMenuWithBadge() {
108
+ return (
109
+ <TabMenu
110
+ className="w-[320px]"
111
+ variant="vertical-button"
112
+ size="lg"
113
+ defaultValue="activity"
114
+ >
115
+ <TabMenuItem
116
+ value="activity"
117
+ leadingIcon={<RiInboxLine />}
118
+ label="Activity"
119
+ >
120
+ <Badge variant="info" appearance="soft" size="sm">
121
+ 12
122
+ </Badge>
123
+ </TabMenuItem>
124
+ <TabMenuItem
125
+ value="billing"
126
+ leadingIcon={<RiBankCardFill />}
127
+ label="Billing"
128
+ >
129
+ <Badge variant="success" appearance="soft" size="sm">
130
+ New
131
+ </Badge>
132
+ </TabMenuItem>
133
+ <TabMenuItem
134
+ value="settings"
135
+ leadingIcon={<RiSettings6Fill />}
136
+ label="Settings"
137
+ >
138
+ <StatusBadge variant="primary" size="md" />
139
+ </TabMenuItem>
140
+ </TabMenu>
141
+ )
142
+ }
143
+ ```
144
+
145
+ More: `npx @create-ui/cli view tab-menu` or MCP `get_item_examples_from_registries` with "tab-menu-demo" / "tab-menu-example".
146
+
147
+ ## When to use
148
+
149
+ Tab-style navigation: settings sidebars, section switchers, routed nav as links. TabMenu renders the tab list only; there are no content-panel components, so render panels yourself keyed by the active value (`{tab === "billing" && <BillingPanel />}`). For 2-5 inline mutually exclusive options without rich item content, use SegmentedControl instead.
150
+
151
+ ## Gotchas
152
+
153
+ - There is no shadcn-style `Tabs` / `TabsList` / `TabsTrigger` / `TabsContent` set; do not invent one. `TabMenu` itself owns the value (`defaultValue`, or controlled `value` + `onValueChange`) and that is the whole API.
154
+ - Text goes in the `label` prop; bare children are NOT the label, they render as extra content beside it (the badge slot, see tab-menu-with-badge). Icons only via `leadingIcon` / `trailingIcon`, never as children.
155
+ - `asChild` needs exactly one non-Fragment element child or it silently falls back to a plain `<button>`. The child's own text becomes the label (`label` is only a fallback when the child has no children) and the extra-children badge slot is unavailable; icons stay as props on `TabMenuItem`:
156
+
157
+ ```tsx
158
+ <TabMenuItem asChild value="billing" leadingIcon={<RiBankCardFill />}>
159
+ <Link href="/billing">Billing</Link>
160
+ </TabMenuItem>
161
+ ```
162
+
163
+ - Line variants show no active marker beyond text color unless `indicator` is set; button variants (`vertical-button`, `horizontal-button`) get the sliding `bg-weak` pill automatically.
164
+ - This is not ARIA tabs: a `role="group"` of `aria-pressed` buttons where every item is its own Tab stop; there is no arrow-key roving like Radix Tabs. asChild items get no `aria-pressed`; their `disabled` maps to `aria-disabled` + `tabIndex={-1}`.
165
+ - An item `onClick` that calls `event.preventDefault()` blocks the value commit; `disabled` items skip both `onClick` and `onValueChange`.
@@ -0,0 +1,84 @@
1
+ <!-- GENERATED FILE - do not edit. Source: registry/ui/text-link.tsx. Regenerate with `pnpm skill:build`. Curated notes: apps/v4/scripts/skill-reference/notes/text-link.md -->
2
+
3
+ # text-link
4
+
5
+ Inline anchor link with six color variants; underline, visited and disabled states, leadingIcon/trailingIcon, asChild
6
+
7
+ Install: `npx @create-ui/cli add text-link`
8
+
9
+ ## Import
10
+
11
+ ```tsx
12
+ import { TextLink } from "@/components/ui/text-link"
13
+ ```
14
+
15
+ Also exported: `textLinkVariants`
16
+
17
+ ## TextLink props
18
+
19
+ | Prop | Type | Default |
20
+ | --- | --- | --- |
21
+ | variant | `primary \| neutral \| inverse \| danger \| success \| info` | `primary` |
22
+ | size | `xs \| sm \| md \| lg` | `md` |
23
+ | visited | `boolean` (Prop-controlled only (purple-500 text, violet underline); the component never reacts to the CSS :visited pseudo-class) | `false` |
24
+ | disabled | `boolean` (Sets aria-disabled, tabIndex=-1 and pointer-events-none but keeps href; remove href yourself if the target is meaningless) | `false` |
25
+ | asChild | `boolean` (The child's own children become the label; TextLink clones the child and re-injects the label wrapped in its content/underline/icon spans) | `false` |
26
+ | leadingIcon | `ReactNode` | - |
27
+ | trailingIcon | `ReactNode` | - |
28
+ | underline | `boolean` (Renders a hairline span (data-slot=text-link-underline), not text-decoration; base forces no-underline, so use this prop, never the Tailwind underline class) | `false` |
29
+
30
+ Extends `React.ComponentProps<"a">`.
31
+
32
+ ## Icons
33
+
34
+ Icons go through icon props - never as children next to text, and never with sizing classes (the component sizes icons per `size`): `TextLink` (`leadingIcon` / `trailingIcon`). Import icons from `@create-ui/assets/icons` (Remix `Ri*`).
35
+
36
+ ## Examples
37
+
38
+ From `text-link-demo`:
39
+
40
+ ```tsx
41
+ import { TextLink } from "@/components/ui/text-link"
42
+
43
+ export default function TextLinkDemo() {
44
+ return <TextLink href="#">Read the documentation</TextLink>
45
+ }
46
+ ```
47
+
48
+ From `text-link-in-prose`:
49
+
50
+ ```tsx
51
+ import { TextLink } from "@/components/ui/text-link"
52
+
53
+ export default function TextLinkInProse() {
54
+ return (
55
+ <p className="text-paragraph-md text-body max-w-prose">
56
+ Create UI ships components as source files you copy into your project.
57
+ Start with the{" "}
58
+ <TextLink href="#" underline>
59
+ installation guide
60
+ </TextLink>{" "}
61
+ to scaffold a new app, then browse the{" "}
62
+ <TextLink href="#">component reference</TextLink> to see every primitive
63
+ in one place.
64
+ </p>
65
+ )
66
+ }
67
+ ```
68
+
69
+ More: `npx @create-ui/cli view text-link` or MCP `get_item_examples_from_registries` with "text-link-demo" / "text-link-example".
70
+
71
+ ## When to use
72
+ Inline link inside body copy, list items, table cells, and helper text, where the control must read as text in the line, not as a button. Renders a native `<a>` by default, or slots a router link (`next/link` etc.) via `asChild`. Do not use it when the control needs a filled hit area (use `Button`, optionally `asChild` over an `<a>`), for menu rows (`DropdownMenuItem`), or for breadcrumb trails (`BreadcrumbItem`).
73
+
74
+ ## Gotchas
75
+ - There is no `as` prop: the root is always `<a>` unless `asChild` swaps in the child element. For a non-navigation click action, slot a `<button>` via `asChild`.
76
+ - `asChild` is smarter than a plain shadcn Slot: icons and `underline` still work because TextLink extracts the child's children as the label and clones the child with its own internal spans. The child must be a single valid element:
77
+ ```tsx
78
+ <TextLink asChild underline trailingIcon={<RiArrowRightSLine />}>
79
+ <Link href="/docs">Continue</Link>
80
+ </TextLink>
81
+ ```
82
+ - The label span is `whitespace-nowrap`: a multi-word link mid-sentence never wraps and can overflow narrow prose containers; keep labels short or override on `[data-slot=text-link-content]`.
83
+ - Focus is an `outline-*` treatment (transparent at rest, colored on focus-visible) per the system-wide outline rule; do not add `ring-*` via className.
84
+ - The label span carries small per-size horizontal padding (`px-0.5` to `px-1.5`), so the link text never sits perfectly flush with adjacent prose.
@@ -0,0 +1,50 @@
1
+ <!-- GENERATED FILE - do not edit. Source: registry/ui/textarea.tsx. Regenerate with `pnpm skill:build`. Curated notes: apps/v4/scripts/skill-reference/notes/textarea.md -->
2
+
3
+ # textarea
4
+
5
+ Multi-line text input; size and state inherit from Field, resizable x/y/both with custom grip, loading spinner overlay
6
+
7
+ Install: `npx @create-ui/cli add textarea`
8
+
9
+ ## Import
10
+
11
+ ```tsx
12
+ import { Textarea } from "@/components/ui/textarea"
13
+ ```
14
+
15
+ Also exported: `textareaVariants`
16
+
17
+ ## Textarea props
18
+
19
+ | Prop | Type | Default |
20
+ | --- | --- | --- |
21
+ | size | `xs \| sm \| md` | `sm` |
22
+ | resizable | `x \| y \| both` (Use this prop, never resize-x/resize-y classes; base is resize-none and the prop hides the webkit grip and overlays the custom corner glyph.) | - |
23
+ | loading | `boolean` (Makes the textarea readOnly + aria-busy with pointer-events-none, NOT disabled; it stays in the tab order and its value still submits.) | - |
24
+
25
+ Extends `React.ComponentProps<"textarea">`.
26
+
27
+ ## Examples
28
+
29
+ From `textarea-demo`:
30
+
31
+ ```tsx
32
+ import { Textarea } from "@/components/ui/textarea"
33
+
34
+ export default function TextareaDemo() {
35
+ return <Textarea placeholder="Write something..." />
36
+ }
37
+ ```
38
+
39
+ More: `npx @create-ui/cli view textarea` or MCP `get_item_examples_from_registries` with "textarea-demo" / "textarea-example".
40
+
41
+ ## When to use
42
+ Multi-line free text: bios, messages, feedback, descriptions, comments. For single-line input use `Input`. Never place a raw `Textarea` inside an `InputGroup`; use `InputGroupTextarea` there, since the group manages size and state through its own context.
43
+
44
+ ## Gotchas
45
+ - Field cascade: `size`, `loading`, and `disabled` resolve as explicit prop ?? Field context ?? default, so explicit props win. `invalid` is OR-combined instead: `<Field invalid>` alone flips the error styling, sets `aria-invalid`, and renders the warning icon, and `aria-invalid={false}` on the textarea cannot cancel it.
46
+ - The DOM shape changes with state: a `data-slot="textarea-wrapper"` div only exists when `resizable` is set or a status icon (loading/invalid) is showing; otherwise the bare `<textarea>` is returned. `className` always lands on the textarea itself, but parent-selector CSS can break across states.
47
+ - `loading` is not `disabled`: it sets `readOnly`, `aria-busy`, and `pointer-events-none`. If you need the field skipped on submit, set `disabled` too. When `loading` and invalid are both true, the spinner wins over the warning icon.
48
+ - Resize must go through the `resizable` prop. Adding `resize-y` via `className` shows the native browser grip with no design-system glyph; the prop hides the webkit resizer and grid-stacks the custom corner icon.
49
+ - The status icon (spinner / `RiErrorWarningLine`) renders bottom-LEFT inside the textarea and is `aria-hidden`; spinner size auto-pairs with the textarea size. Communicate the actual error text via `FieldHelper`, not the icon.
50
+ - Base height is `min-h-[132px]`, so small `rows` values have no visible effect; override height with a `min-h-*` class.