@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,146 @@
1
+ <!-- GENERATED FILE - do not edit. Source: registry/ui/segmented-control.tsx. Regenerate with `pnpm skill:build`. Curated notes: apps/v4/scripts/skill-reference/notes/segmented-control.md -->
2
+
3
+ # segmented-control
4
+
5
+ Single-select between 2-7 options with an animated sliding indicator; value/onValueChange, flat or grouped appearance
6
+
7
+ Install: `npx @create-ui/cli add segmented-control`
8
+
9
+ ## Import
10
+
11
+ ```tsx
12
+ import { SegmentedControl, SegmentedControlItem } from "@/components/ui/segmented-control"
13
+ ```
14
+
15
+ Also exported: `segmentedControlVariants`, `segmentedControlItemVariants`, `segmentedControlIndicatorVariants`
16
+
17
+ ## SegmentedControl props
18
+
19
+ | Prop | Type | Default |
20
+ | --- | --- | --- |
21
+ | variant | `primary \| neutral` | `primary` |
22
+ | shape | `rounded \| pill` | `rounded` |
23
+ | size | `xs \| sm \| md \| lg \| xl` | `md` |
24
+ | appearance | `flat \| grouped` (flat = independent-looking buttons, grouped = padded bg-weak container (pricing-toggle look); the active pill slides in BOTH) | `flat` |
25
+ | value | `string` | - |
26
+ | defaultValue | `string` | - |
27
+ | onValueChange | `(value: string) => void` | - |
28
+
29
+ Extends `React.ComponentProps<"div">`.
30
+
31
+ ## SegmentedControlItem props
32
+
33
+ | Prop | Type | Default |
34
+ | --- | --- | --- |
35
+ | variant | `primary \| neutral` | `primary` |
36
+ | shape | `rounded \| pill` | `rounded` |
37
+ | size | `xs \| sm \| md \| lg \| xl` | `md` |
38
+ | appearance | `flat \| grouped` (flat = independent-looking buttons, grouped = padded bg-weak container (pricing-toggle look); the active pill slides in BOTH) | `flat` |
39
+ | iconOnly | `boolean` (renders children as a single centered icon (like Button); leadingIcon/trailingIcon are ignored; add aria-label (the text label is gone)) | `false` |
40
+ | asChild | `boolean` (skips aria-pressed and type=button; disabled becomes aria-disabled + tabIndex=-1 instead of the native attribute) | `false` |
41
+ | value | `string` | - |
42
+ | selected | `boolean` (forces the active state without binding value on the root; the sliding indicator still moves to it) | - |
43
+ | leadingIcon | `ReactNode` | - |
44
+ | trailingIcon | `ReactNode` | - |
45
+
46
+ Extends `React.ComponentProps<"button">`.
47
+
48
+ ## Icons
49
+
50
+ Icons go through icon props - never as children next to text, and never with sizing classes (the component sizes icons per `size`): `SegmentedControlItem` (`leadingIcon` / `trailingIcon`). Import icons from `@create-ui/assets/icons` (Remix `Ri*`).
51
+
52
+ ## Examples
53
+
54
+ From `segmented-control-demo`:
55
+
56
+ ```tsx
57
+ import {
58
+ RiLayoutGridFill,
59
+ RiLineChartLine,
60
+ RiListUnordered,
61
+ } from "@create-ui/assets/icons"
62
+
63
+ import {
64
+ SegmentedControl,
65
+ SegmentedControlItem,
66
+ } from "@/components/ui/segmented-control"
67
+
68
+ export default function SegmentedControlDemo() {
69
+ return (
70
+ <SegmentedControl
71
+ variant="neutral"
72
+ appearance="grouped"
73
+ defaultValue="list"
74
+ >
75
+ <SegmentedControlItem value="grid" leadingIcon={<RiLayoutGridFill />}>
76
+ Grid
77
+ </SegmentedControlItem>
78
+ <SegmentedControlItem value="list" leadingIcon={<RiListUnordered />}>
79
+ List
80
+ </SegmentedControlItem>
81
+ <SegmentedControlItem value="chart" leadingIcon={<RiLineChartLine />}>
82
+ Chart
83
+ </SegmentedControlItem>
84
+ </SegmentedControl>
85
+ )
86
+ }
87
+ ```
88
+
89
+ From `segmented-control-appearance`:
90
+
91
+ ```tsx
92
+ import {
93
+ RiInbox2Line,
94
+ RiSettings6Fill,
95
+ RiUser3Line,
96
+ } from "@create-ui/assets/icons"
97
+
98
+ import {
99
+ SegmentedControl,
100
+ SegmentedControlItem,
101
+ } from "@/components/ui/segmented-control"
102
+
103
+ export default function SegmentedControlAppearance() {
104
+ return (
105
+ <div className="flex flex-col items-start gap-4">
106
+ <SegmentedControl variant="neutral" appearance="flat" className="gap-2">
107
+ <SegmentedControlItem leadingIcon={<RiInbox2Line />}>
108
+ Inbox
109
+ </SegmentedControlItem>
110
+ <SegmentedControlItem selected leadingIcon={<RiUser3Line />}>
111
+ Mine
112
+ </SegmentedControlItem>
113
+ <SegmentedControlItem leadingIcon={<RiSettings6Fill />}>
114
+ Archived
115
+ </SegmentedControlItem>
116
+ </SegmentedControl>
117
+
118
+ <SegmentedControl
119
+ variant="neutral"
120
+ appearance="grouped"
121
+ defaultValue="week"
122
+ >
123
+ <SegmentedControlItem value="day">Day</SegmentedControlItem>
124
+ <SegmentedControlItem value="week">Week</SegmentedControlItem>
125
+ <SegmentedControlItem value="month">Month</SegmentedControlItem>
126
+ </SegmentedControl>
127
+ </div>
128
+ )
129
+ }
130
+ ```
131
+
132
+ More: `npx @create-ui/cli view segmented-control` or MCP `get_item_examples_from_registries` with "segmented-control-demo" / "segmented-control-example".
133
+
134
+ ## When to use
135
+
136
+ Single-select between 2-7 mutually exclusive options that benefit from being visible at once: view mode, time range, billing period. Drive it with `value`/`onValueChange` or `defaultValue`; never hand-roll it as a row of `Button`s with manual active state. Wrong tool for: multi-select (`CheckboxGroup`), route or section navigation (`TabMenu`), lists past ~7 (`Select`), a boolean (`Switch`), or form-style radio choices (`RadioGroup`).
137
+
138
+ ## Gotchas
139
+
140
+ - This is NOT Radix ToggleGroup: there is no `type` prop (single-select only), clicking the active item does not deselect it, and every item is its own Tab stop (`role="group"` + `aria-pressed` per button, no arrow-key roving).
141
+ - An item without `value` never commits a selection; its `onClick` still fires, and calling `event.preventDefault()` inside `onClick` blocks the commit even when `value` is set.
142
+ - The visible active background is a separate floating element (`data-slot="segmented-control-indicator"`) measured from the `data-state="on"` item; in `flat` appearance the selected item's own bg/shadow turn transparent once the indicator mounts. Style the indicator for active background/shadow; active text color stays on the item.
143
+ - `flat` items sit flush with no gap; add spacing on the root yourself (`className="gap-2"`), as the appearance example does.
144
+ - `variant`/`shape`/`size`/`appearance` cascade from the root via context; set them once on `SegmentedControl`, not per item (per-item props exist only as overrides).
145
+ - `appearance="grouped"` adds container padding on top of the item height (xs/sm +4px, md/lg +8px, xl +16px), so a grouped control is taller than its `size` suggests: grouped xs/sm = 28/32px, md = 40px, lg = 48px, xl = 64px. Next to a `Button` in a toolbar, pair by rendered height, not by size name (e.g. grouped sm = 32px aligns with Button md).
146
+ - `iconOnly` gives the item a FIXED square (`size-N`). Adding `flex-1` / `w-full` / `grow` via `className` makes the flex layout override that fixed width and stretch the square into a wide rectangle. For a compact icon toggle, add NO width class and let the square stand. Only stretch deliberately (e.g. a full-width 2-up mobile switcher) - and then accept it is no longer square.
@@ -0,0 +1,204 @@
1
+ <!-- GENERATED FILE - do not edit. Source: registry/ui/select.tsx. Regenerate with `pnpm skill:build`. Curated notes: apps/v4/scripts/skill-reference/notes/select.md -->
2
+
3
+ # select
4
+
5
+ Radix select for picking one option from a dropdown list; size and state inherit from Field, compact width variant
6
+
7
+ Install: `npx @create-ui/cli add select`
8
+
9
+ ## Import
10
+
11
+ ```tsx
12
+ import { Select, SelectProvider, SelectShell, SelectContent, SelectGroup, SelectItem, SelectLabel, SelectSeparator, SelectTrigger, SelectValue } from "@/components/ui/select"
13
+ ```
14
+
15
+ Also exported: `selectShellVariants`, `selectTriggerVariants`, `useSelectContext`
16
+
17
+ ## Select props
18
+
19
+ | Prop | Type | Default |
20
+ | --- | --- | --- |
21
+ | size | `xs \| sm \| md` | - |
22
+ | variant | `default \| compact` (compact = width-fits-content (shell w-fit, trigger flex-none) for toolbars/inline pickers; NOT auto-applied inside InputGroup, pass it explicitly) | `default` |
23
+ | loading | `boolean` (also hard-disables the whole root (disabled || loading) and swaps the chevron for a Spinner; the shell goes pointer-events-none) | `false` |
24
+ | invalid | `boolean` | `false` |
25
+
26
+ Extends `React.ComponentProps<typeof SelectPrimitive.Root>`.
27
+
28
+ ## SelectProvider props
29
+
30
+ | Prop | Type | Default |
31
+ | --- | --- | --- |
32
+ | size | `xs \| sm \| md` | `sm` |
33
+ | variant | `default \| compact` (compact = width-fits-content (shell w-fit, trigger flex-none) for toolbars/inline pickers; NOT auto-applied inside InputGroup, pass it explicitly) | `default` |
34
+ | invalid | `boolean` | `false` |
35
+ | disabled | `boolean` | `false` |
36
+ | loading | `boolean` (also hard-disables the whole root (disabled || loading) and swaps the chevron for a Spinner; the shell goes pointer-events-none) | `false` |
37
+ | children | `ReactNode` | - |
38
+
39
+ ## SelectTrigger props
40
+
41
+ | Prop | Type | Default |
42
+ | --- | --- | --- |
43
+ | size | `xs \| sm \| md` | `sm` |
44
+ | variant | `default \| compact` (compact = width-fits-content (shell w-fit, trigger flex-none) for toolbars/inline pickers; NOT auto-applied inside InputGroup, pass it explicitly) | `default` |
45
+
46
+ Extends `React.ComponentProps<typeof SelectPrimitive.Trigger>`.
47
+
48
+ ## Examples
49
+
50
+ From `select-demo`:
51
+
52
+ ```tsx
53
+ "use client"
54
+
55
+ import * as React from "react"
56
+ import {
57
+ France,
58
+ Germany,
59
+ Japan,
60
+ Turkey,
61
+ UnitedStates,
62
+ } from "@create-ui/assets/flags"
63
+
64
+ import {
65
+ Select,
66
+ SelectContent,
67
+ SelectGroup,
68
+ SelectItem,
69
+ SelectTrigger,
70
+ SelectValue,
71
+ } from "@/components/ui/select"
72
+
73
+ const COUNTRIES = [
74
+ {
75
+ value: "de",
76
+ label: "Germany",
77
+ flag: <Germany className="size-5 shrink-0" />,
78
+ },
79
+ {
80
+ value: "us",
81
+ label: "United States",
82
+ flag: <UnitedStates className="size-5 shrink-0" />,
83
+ },
84
+ { value: "jp", label: "Japan", flag: <Japan className="size-5 shrink-0" /> },
85
+ {
86
+ value: "fr",
87
+ label: "France",
88
+ flag: <France className="size-5 shrink-0" />,
89
+ },
90
+ {
91
+ value: "tr",
92
+ label: "Türkiye",
93
+ flag: <Turkey className="size-5 shrink-0" />,
94
+ },
95
+ ]
96
+
97
+ export default function SelectDemo() {
98
+ const [value, setValue] = React.useState<string | undefined>("de")
99
+ const selected = COUNTRIES.find((c) => c.value === value)
100
+
101
+ return (
102
+ <div className="w-full max-w-xs">
103
+ <Select size="md" value={value} onValueChange={setValue}>
104
+ <SelectTrigger>
105
+ {selected?.flag}
106
+ <SelectValue placeholder="Select country">
107
+ {selected?.label}
108
+ </SelectValue>
109
+ </SelectTrigger>
110
+ <SelectContent>
111
+ <SelectGroup>
112
+ <SelectItem value="de">
113
+ <Germany className="size-5 shrink-0" />
114
+ Germany
115
+ </SelectItem>
116
+ <SelectItem value="us">
117
+ <UnitedStates className="size-5 shrink-0" />
118
+ United States
119
+ </SelectItem>
120
+ <SelectItem value="jp">
121
+ <Japan className="size-5 shrink-0" />
122
+ Japan
123
+ </SelectItem>
124
+ <SelectItem value="fr">
125
+ <France className="size-5 shrink-0" />
126
+ France
127
+ </SelectItem>
128
+ <SelectItem value="tr">
129
+ <Turkey className="size-5 shrink-0" />
130
+ Türkiye
131
+ </SelectItem>
132
+ </SelectGroup>
133
+ </SelectContent>
134
+ </Select>
135
+ </div>
136
+ )
137
+ }
138
+ ```
139
+
140
+ From `select-in-input-group`:
141
+
142
+ ```tsx
143
+ "use client"
144
+
145
+ import * as React from "react"
146
+
147
+ import {
148
+ InputGroup,
149
+ InputGroupControl,
150
+ InputGroupSlot,
151
+ } from "@/components/ui/input-group"
152
+ import {
153
+ Select,
154
+ SelectContent,
155
+ SelectGroup,
156
+ SelectItem,
157
+ SelectTrigger,
158
+ SelectValue,
159
+ } from "@/components/ui/select"
160
+
161
+ export default function SelectInInputGroup() {
162
+ const [currency, setCurrency] = React.useState("usd")
163
+
164
+ return (
165
+ <div className="w-full max-w-xs">
166
+ <InputGroup size="md">
167
+ <Select variant="compact" value={currency} onValueChange={setCurrency}>
168
+ <SelectTrigger aria-label="Currency">
169
+ <SelectValue />
170
+ </SelectTrigger>
171
+ <SelectContent>
172
+ <SelectGroup>
173
+ <SelectItem value="usd">USD</SelectItem>
174
+ <SelectItem value="eur">EUR</SelectItem>
175
+ <SelectItem value="jpy">JPY</SelectItem>
176
+ <SelectItem value="try">TRY</SelectItem>
177
+ </SelectGroup>
178
+ </SelectContent>
179
+ </Select>
180
+ <InputGroupSlot>
181
+ <InputGroupControl placeholder="0.00" inputMode="decimal" />
182
+ </InputGroupSlot>
183
+ </InputGroup>
184
+ </div>
185
+ )
186
+ }
187
+ ```
188
+
189
+ More: `npx @create-ui/cli view select` or MCP `get_item_examples_from_registries` with "select-demo" / "select-example".
190
+
191
+ ## When to use
192
+ Select picks one value from a short predefined list (country, currency, role, plan). Wrap it in Field for the label and the size/state cascade. Long or searchable lists are Command territory; a single boolean is Switch (settings row) or Checkbox (form); a few always-visible options are SegmentedControl.
193
+ ## Gotchas
194
+ - SelectTrigger auto-wraps itself in SelectShell when standalone, and renders bare when it detects an InputShell (from InputGroup) or explicit SelectShell ancestor. Border, focus, and state chrome live on the shell, so overrides belong there, not on the trigger.
195
+ - Inside InputGroup you must pass variant="compact" yourself; the default variant's trigger is flex-1 w-full and squeezes the sibling Input.
196
+ - Size resolves explicit prop > InputGroup context > Field context > "sm"; invalid/disabled/loading on the root fall back to Field. Set them once on Field, never re-set per part.
197
+ - The chevron (and the trailing primary check indicator on items) is auto-rendered; never append your own caret.
198
+ - SelectItem auto-detects a leading icon: with multiple children whose first is an element, that first child becomes the leading slot and the rest becomes truncating text. Pass icon and label as plain siblings:
199
+ ```tsx
200
+ <SelectItem value="de">
201
+ <Germany className="size-5 shrink-0" />
202
+ Germany
203
+ </SelectItem>
204
+ ```
@@ -0,0 +1,99 @@
1
+ <!-- GENERATED FILE - do not edit. Source: registry/ui/separator.tsx. Regenerate with `pnpm skill:build`. Curated notes: apps/v4/scripts/skill-reference/notes/separator.md -->
2
+
3
+ # separator
4
+
5
+ Horizontal divider line; optional inline label or icon content aligned start, center or end
6
+
7
+ Install: `npx @create-ui/cli add separator`
8
+
9
+ ## Import
10
+
11
+ ```tsx
12
+ import { Separator } from "@/components/ui/separator"
13
+ ```
14
+
15
+ ## Separator props
16
+
17
+ | Prop | Type | Default |
18
+ | --- | --- | --- |
19
+ | align | `start \| center \| end` (Labeled mode only: drops the flanking line on that side so the label sits flush. Ignored when there are no children.) | `center` |
20
+
21
+ Extends `React.ComponentProps<"div">`.
22
+
23
+ ## Examples
24
+
25
+ From `separator-demo`:
26
+
27
+ ```tsx
28
+ import { Separator } from "@/components/ui/separator"
29
+
30
+ export default function SeparatorDemo() {
31
+ return (
32
+ <div className="text-body text-ui-control-md flex w-[420px] flex-col gap-4">
33
+ <p>
34
+ Workspace settings are scoped to the current organization and apply to
35
+ every member.
36
+ </p>
37
+ <Separator />
38
+ <p>
39
+ Personal preferences only affect your account and follow you across
40
+ workspaces.
41
+ </p>
42
+ </div>
43
+ )
44
+ }
45
+ ```
46
+
47
+ From `separator-with-label`:
48
+
49
+ ```tsx
50
+ import { Button } from "@/components/ui/button"
51
+ import { Separator } from "@/components/ui/separator"
52
+
53
+ export default function SeparatorWithLabel() {
54
+ return (
55
+ <div className="flex w-[360px] flex-col gap-4">
56
+ <Button variant="primary" appearance="solid">
57
+ Continue with email
58
+ </Button>
59
+ <Separator>OR</Separator>
60
+ <Button variant="neutral-solid" appearance="outline">
61
+ Create a free account
62
+ </Button>
63
+ </div>
64
+ )
65
+ }
66
+ ```
67
+
68
+ More: `npx @create-ui/cli view separator` or MCP `get_item_examples_from_registries` with "separator-demo" / "separator-example".
69
+
70
+ ## When to use
71
+ Horizontal rule between related-but-distinct content, and the labeled "OR" divider
72
+ (pass children). Do not hand-roll `<hr>` or `<div className="border-t">`. It is
73
+ horizontal-only: for vertical dividers between adjacent controls use ButtonGroup,
74
+ which draws its own borders between items. Inside forms prefer `FieldSeparator`
75
+ from field.tsx, which wraps this same Separator with vertical padding and a
76
+ background-backed centered label.
77
+
78
+ ## Gotchas
79
+ - Not the Radix/shadcn separator: no `orientation`, no `decorative` prop, so the
80
+ shadcn habit `orientation="vertical"` is a type error. `role="separator"` is
81
+ hardcoded, but props spread after it, so pass `role="presentation"` to make it
82
+ purely decorative.
83
+ - The line is a border, not a background bar: `h-0 border-t border-light` (shadcn
84
+ uses `h-px bg-border`). `bg-*` classes change nothing visible; recolor with
85
+ `border-*` classes.
86
+ - `className` lands on different elements per mode. Plain: on the line itself, so
87
+ `className="border-strong"` recolors it directly. Labeled: on the outer flex
88
+ wrapper while the two lines keep internal classes, so recolor them via a
89
+ descendant selector:
90
+
91
+ ```tsx
92
+ <Separator className="[&>span[aria-hidden]]:border-strong">OR</Separator>
93
+ ```
94
+
95
+ - Any truthy `children` switches the render entirely: flex row with two flanking
96
+ `aria-hidden` line spans and a fixed `gap-3`.
97
+ - The label slot styling is fixed: `text-placeholder`, `text-ui-control-md`, and
98
+ every nested `<svg>` is forced to `size-6`. Drop in a bare icon as children;
99
+ manual icon size classes are overridden.
@@ -0,0 +1,130 @@
1
+ <!-- GENERATED FILE - do not edit. Source: registry/ui/social-login-button.tsx. Regenerate with `pnpm skill:build`. Curated notes: apps/v4/scripts/skill-reference/notes/social-login-button.md -->
2
+
3
+ # social-login-button
4
+
5
+ OAuth sign-in button for 13 brands like Google, Apple and GitHub plus custom; colorful/black/white appearance, iconOnly
6
+
7
+ Install: `npx @create-ui/cli add social-login-button`
8
+
9
+ ## Import
10
+
11
+ ```tsx
12
+ import { SocialLoginButton } from "@/components/ui/social-login-button"
13
+ ```
14
+
15
+ Also exported: `socialLoginButtonVariants`
16
+
17
+ ## SocialLoginButton props
18
+
19
+ | Prop | Type | Default |
20
+ | --- | --- | --- |
21
+ | size | `lg \| md` | `lg` |
22
+ | shape | `rounded \| pill \| square` | `rounded` |
23
+ | iconOnly | `boolean` (Removes the visible label, leaving no accessible name; always pass aria-label) | `false` |
24
+ | appearance | `colorful \| black \| white` (Defaults to colorful (literal brand-colored background); the generated table misses this default) | - |
25
+ | asChild | `boolean` (The slotted child's own children are REPLACED by the injected icon+label; slot an empty <a> carrying href/aria-label) | - |
26
+ | brand | `apple \| behance \| discord \| dribbble \| facebook \| github \| gitlab \| google \| linkedin \| microsoft \| slack \| sso \| x \| custom` (Also fixes the copy: rendered text is always 'Continue with {label}'; custom wording only via brand=\"custom\" config.label, and only the brand-name part (the 'Continue with' prefix is hard-coded)) | - |
27
+ | config | `{ icon: IconComponent label?: string color?: string }` (Only accepted with brand=\"custom\" (discriminated union). The icon gets no fill, just the appearance text color (white on colorful, theme text on black/white), so draw it with currentColor) | - |
28
+
29
+ Extends `React.ComponentProps<"button">`.
30
+
31
+ ## Icons
32
+
33
+ Icons go through icon props - never as children next to text, and never with sizing classes (the component sizes icons per `size`): `SocialLoginButton` (). Import icons from `@create-ui/assets/icons` (Remix `Ri*`).
34
+
35
+ ## Examples
36
+
37
+ From `social-login-button-demo`:
38
+
39
+ ```tsx
40
+ import { SocialLoginButton } from "@/components/ui/social-login-button"
41
+
42
+ export default function SocialLoginButtonDemo() {
43
+ return (
44
+ <div className="flex w-full flex-col items-center justify-center gap-3">
45
+ <div className="flex flex-wrap items-center justify-center gap-2">
46
+ <SocialLoginButton brand="google" appearance="white" />
47
+ <SocialLoginButton brand="apple" appearance="white" />
48
+ </div>
49
+ <div className="flex flex-wrap items-center justify-center gap-2">
50
+ <SocialLoginButton brand="dribbble" shape="pill" />
51
+ <SocialLoginButton brand="x" shape="pill" />
52
+ </div>
53
+ <div className="flex flex-wrap items-center justify-center gap-2">
54
+ <SocialLoginButton
55
+ brand="google"
56
+ iconOnly
57
+ aria-label="Continue with Google"
58
+ />
59
+ <SocialLoginButton
60
+ brand="apple"
61
+ appearance="black"
62
+ iconOnly
63
+ aria-label="Continue with Apple"
64
+ />
65
+ <SocialLoginButton
66
+ brand="github"
67
+ appearance="white"
68
+ iconOnly
69
+ aria-label="Continue with Github"
70
+ />
71
+ <SocialLoginButton
72
+ brand="dribbble"
73
+ shape="pill"
74
+ iconOnly
75
+ aria-label="Continue with Dribbble"
76
+ />
77
+ <SocialLoginButton
78
+ brand="x"
79
+ shape="pill"
80
+ iconOnly
81
+ aria-label="Continue with X"
82
+ />
83
+ </div>
84
+ </div>
85
+ )
86
+ }
87
+ ```
88
+
89
+ From `social-login-button-as-child`:
90
+
91
+ ```tsx
92
+ "use client"
93
+
94
+ import { SocialLoginButton } from "@/components/ui/social-login-button"
95
+
96
+ export default function SocialLoginButtonAsChild() {
97
+ return (
98
+ <div className="flex flex-wrap justify-center gap-2">
99
+ <SocialLoginButton asChild brand="google">
100
+ <a href="#" aria-label="Continue with Google" />
101
+ </SocialLoginButton>
102
+ <SocialLoginButton asChild brand="apple" appearance="black">
103
+ <a href="#" aria-label="Continue with Apple" />
104
+ </SocialLoginButton>
105
+ <SocialLoginButton asChild brand="github" appearance="white">
106
+ <a href="#" aria-label="Continue with Github" />
107
+ </SocialLoginButton>
108
+ </div>
109
+ )
110
+ }
111
+ ```
112
+
113
+ More: `npx @create-ui/cli view social-login-button` or MCP `get_item_examples_from_registries` with "social-login-button-demo" / "social-login-button-example".
114
+
115
+ ## When to use
116
+ Branded "Continue with X" buttons for OAuth/SSO sign-in and sign-up flows: preset brands plus brand="custom" with a config object. Do NOT use it for generic CTAs (use Button), app/extension store links (use AppStoreBadge), or passive brand chips (use Badge).
117
+
118
+ ## Gotchas
119
+ - Children are ignored unless asChild: `<SocialLoginButton brand="google">Sign in</SocialLoginButton>` silently drops "Sign in" (children are destructured out and never rendered); the label always comes from the brand config.
120
+ - Ignore the generated Icons section: there are NO leadingIcon/trailingIcon/icon props. The glyph is auto-picked per brand AND appearance: white glyph on colorful; under black/white appearances most brands keep their full-color glyph, and only brands with a theme-aware mono asset (apple, github, x) swap. Custom icons go through config.icon only.
121
+ - asChild is not shadcn-Button-style Slot passthrough: the component clones the slotted child and REPLACES its children with the icon+label content:
122
+
123
+ ```tsx
124
+ <SocialLoginButton asChild brand="google">
125
+ <a href="/auth/google" aria-label="Continue with Google" />
126
+ </SocialLoginButton>
127
+ ```
128
+
129
+ - Non-iconOnly buttons have fixed widths (w-[300px] at lg, w-[250px] at md) so provider stacks align. For full-width auth forms pass className="w-full"; cn() merges it over the CVA width.
130
+ - appearance="colorful" pins the literal brand color and static black/white tokens, so it does NOT flip in dark mode; only the sso preset defines a dark variant. black/white appearances use semantic tokens and do flip with the theme.
@@ -0,0 +1,68 @@
1
+ <!-- GENERATED FILE - do not edit. Source: registry/ui/spinner.tsx. Regenerate with `pnpm skill:build`. Curated notes: apps/v4/scripts/skill-reference/notes/spinner.md -->
2
+
3
+ # spinner
4
+
5
+ Loading indicator with a conic-gradient arc; 12 color variants, solid/gradient appearance, spin/pulse/tick animations
6
+
7
+ Install: `npx @create-ui/cli add spinner`
8
+
9
+ ## Import
10
+
11
+ ```tsx
12
+ import { Spinner } from "@/components/ui/spinner"
13
+ ```
14
+
15
+ Also exported: `spinnerVariants`
16
+
17
+ ## Spinner props
18
+
19
+ | Prop | Type | Default |
20
+ | --- | --- | --- |
21
+ | variant | `primary \| info \| success \| warning \| danger \| away \| neutral \| neutral-static \| neutral-soft \| inverse \| inverse-static \| inverse-soft` | `primary` |
22
+ | appearance | `solid \| gradient` | `gradient` |
23
+ | cap | `sharp \| rounded` (Visual effect only with appearance=\"solid\" (rounded caps render as separate dot elements); with gradient appearance the prop only sets the data-cap attribute.) | `rounded` |
24
+ | line | `short \| long` | `long` |
25
+ | animation | `spin \| pulse \| tick` | `pulse` |
26
+ | size | `xs \| sm \| md \| lg` (Also scales the arc stroke width via inline styles (1px at xs up to 2px at lg); the stroke cannot be restyled through className.) | `sm` |
27
+
28
+ Extends `React.ComponentProps<"div">`.
29
+
30
+ ## Examples
31
+
32
+ From `spinner-demo`:
33
+
34
+ ```tsx
35
+ import { Spinner } from "@/components/ui/spinner"
36
+
37
+ export default function SpinnerDemo() {
38
+ return <Spinner size="lg" />
39
+ }
40
+ ```
41
+
42
+ From `spinner-appearance`:
43
+
44
+ ```tsx
45
+ import { Spinner } from "@/components/ui/spinner"
46
+
47
+ export default function SpinnerAppearance() {
48
+ return (
49
+ <div className="flex flex-wrap items-center gap-6">
50
+ <Spinner appearance="gradient" animation="spin" size="lg" />
51
+ <Spinner appearance="solid" animation="spin" size="lg" />
52
+ </div>
53
+ )
54
+ }
55
+ ```
56
+
57
+ More: `npx @create-ui/cli view spinner` or MCP `get_item_examples_from_registries` with "spinner-demo" / "spinner-example".
58
+
59
+ ## When to use
60
+ Indeterminate in-flight work: saves, network calls, slow validation, page bootstrapping. Do NOT use it when progress is measurable (use Progress) or for a loading button (use Button's `loading` prop, which renders the Spinner, blocks interaction, and sets `aria-busy` for you - never compose `<Spinner />` + `disabled` by hand).
61
+
62
+ ## Gotchas
63
+ - This is NOT the shadcn `Loader2` + `animate-spin` pattern. It is a pure-CSS `<div>` (conic-gradient + mask, zero SVG). Never reach for lucide icons or `animate-spin` utilities; render `<Spinner />`.
64
+ - `children` is excluded at the type level (`Omit<..., "children">`). It draws its own arc; put visible copy ("Saving...") next to it, not inside it.
65
+ - The arc and caps track `currentColor`: `variant` applies a `text-*` token class, so `className="text-emerald-500"` (merged last via `cn()`) recolors them. The solid track ring does NOT follow `currentColor` - its `bg-*` color always comes from `variant`.
66
+ - The background track ring only renders when `appearance="solid"`; the default `gradient` has no track and its arc tail fades to transparent.
67
+ - Sets `role="status"` and `aria-label="Loading"` automatically; pass your own `aria-label` for specific operations.
68
+ - The exported `spinnerVariants` CVA defaults `size` to `lg`, but the `Spinner` component prop defaults to `sm`. Calling `spinnerVariants()` directly yields a different size than `<Spinner />`.