@create-ui/cli 0.5.8 → 0.5.9
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-RMTTHCB3.js → chunk-2ELKDGGM.js} +3 -3
- package/dist/{chunk-RMTTHCB3.js.map → chunk-2ELKDGGM.js.map} +1 -1
- package/dist/chunk-643QI2I2.js +102 -0
- package/dist/chunk-643QI2I2.js.map +1 -0
- package/dist/{chunk-NQFMXHMH.js → chunk-KQTXDVKV.js} +3 -3
- package/dist/chunk-KQTXDVKV.js.map +1 -0
- package/dist/index.d.ts +360 -360
- package/dist/index.js +2 -2
- package/dist/index.js.map +1 -1
- package/dist/mcp/index.js +1 -1
- package/dist/registry/index.d.ts +2 -2
- package/dist/registry/index.js +1 -1
- package/dist/schema/index.d.ts +715 -715
- package/dist/skills/createui/SKILL.md +201 -177
- package/dist/skills/createui/agents/openai.yml +1 -1
- package/dist/skills/createui/cli.md +42 -42
- package/dist/skills/createui/customization.md +20 -15
- package/dist/skills/createui/evals/evals.json +68 -5
- package/dist/skills/createui/mcp.md +14 -5
- package/dist/skills/createui/reference/accordion.md +127 -0
- package/dist/skills/createui/reference/app-store-badge.md +88 -0
- package/dist/skills/createui/reference/aspect-ratio.md +52 -0
- package/dist/skills/createui/reference/avatar.md +230 -0
- package/dist/skills/createui/reference/badge.md +110 -0
- package/dist/skills/createui/reference/breadcrumb.md +153 -0
- package/dist/skills/createui/reference/button-group.md +116 -0
- package/dist/skills/createui/reference/button.md +104 -0
- package/dist/skills/createui/reference/checkbox-group.md +118 -0
- package/dist/skills/createui/reference/checkbox.md +79 -0
- package/dist/skills/createui/reference/chip.md +115 -0
- package/dist/skills/createui/reference/close-button.md +83 -0
- package/dist/skills/createui/reference/command.md +69 -0
- package/dist/skills/createui/reference/country-flag.md +109 -0
- package/dist/skills/createui/reference/credit-card-input.md +76 -0
- package/dist/skills/createui/reference/date-input.md +71 -0
- package/dist/skills/createui/reference/dropdown-menu.md +164 -0
- package/dist/skills/createui/reference/field.md +186 -0
- package/dist/skills/createui/reference/info-tooltip.md +110 -0
- package/dist/skills/createui/reference/inline-alert.md +146 -0
- package/dist/skills/createui/reference/input-group.md +171 -0
- package/dist/skills/createui/reference/input-otp.md +130 -0
- package/dist/skills/createui/reference/input-stepper.md +120 -0
- package/dist/skills/createui/reference/input.md +118 -0
- package/dist/skills/createui/reference/label.md +121 -0
- package/dist/skills/createui/reference/pagination.md +157 -0
- package/dist/skills/createui/reference/password-strength.md +70 -0
- package/dist/skills/createui/reference/phone-input.md +77 -0
- package/dist/skills/createui/reference/progress.md +158 -0
- package/dist/skills/createui/reference/radio-group.md +133 -0
- package/dist/skills/createui/reference/radio.md +79 -0
- package/dist/skills/createui/reference/scroll-area.md +212 -0
- package/dist/skills/createui/reference/segmented-control.md +146 -0
- package/dist/skills/createui/reference/select.md +204 -0
- package/dist/skills/createui/reference/separator.md +99 -0
- package/dist/skills/createui/reference/social-login-button.md +130 -0
- package/dist/skills/createui/reference/spinner.md +68 -0
- package/dist/skills/createui/reference/status-badge.md +89 -0
- package/dist/skills/createui/reference/switch-group.md +122 -0
- package/dist/skills/createui/reference/switch.md +75 -0
- package/dist/skills/createui/reference/tab-menu.md +165 -0
- package/dist/skills/createui/reference/text-link.md +84 -0
- package/dist/skills/createui/reference/textarea.md +50 -0
- package/dist/skills/createui/reference/toast.md +162 -0
- package/dist/skills/createui/reference/tooltip.md +63 -0
- package/dist/skills/createui/rules/composition.md +41 -25
- package/dist/skills/createui/rules/design.md +266 -0
- package/dist/skills/createui/rules/forms.md +44 -15
- package/dist/skills/createui/rules/icons.md +64 -18
- package/dist/skills/createui/rules/styling.md +53 -14
- package/dist/utils/index.js +1 -1
- package/package.json +1 -1
- package/dist/chunk-M5DYT2NE.js +0 -64
- package/dist/chunk-M5DYT2NE.js.map +0 -1
- package/dist/chunk-NQFMXHMH.js.map +0 -1
|
@@ -0,0 +1,164 @@
|
|
|
1
|
+
<!-- GENERATED FILE - do not edit. Source: registry/ui/dropdown-menu.tsx. Regenerate with `pnpm skill:build`. Curated notes: apps/v4/scripts/skill-reference/notes/dropdown-menu.md -->
|
|
2
|
+
|
|
3
|
+
# dropdown-menu
|
|
4
|
+
|
|
5
|
+
Radix action menu opened from a trigger; size xs/sm/md cascades to items, items support selected check marks
|
|
6
|
+
|
|
7
|
+
Install: `npx @create-ui/cli add dropdown-menu`
|
|
8
|
+
|
|
9
|
+
## Import
|
|
10
|
+
|
|
11
|
+
```tsx
|
|
12
|
+
import { DropdownMenu, DropdownMenuPortal, DropdownMenuTrigger, DropdownMenuContent, DropdownMenuGroup, DropdownMenuLabel, DropdownMenuItem, DropdownMenuSeparator } from "@/components/ui/dropdown-menu"
|
|
13
|
+
```
|
|
14
|
+
|
|
15
|
+
Also exported: `MENU_CONTENT_RADIUS`, `MENU_ITEM_CONTENT_GAP_CLASSES`, `MENU_ITEM_SIZE_CLASSES`, `MENU_LABEL_SIZE_CLASSES`
|
|
16
|
+
|
|
17
|
+
## DropdownMenu props
|
|
18
|
+
|
|
19
|
+
| Prop | Type | Default |
|
|
20
|
+
| --- | --- | --- |
|
|
21
|
+
| size | `xs \| sm \| md` | `sm` |
|
|
22
|
+
|
|
23
|
+
Extends `React.ComponentProps<typeof DropdownMenuPrimitive.Root>`.
|
|
24
|
+
|
|
25
|
+
## DropdownMenuItem props
|
|
26
|
+
|
|
27
|
+
| Prop | Type | Default |
|
|
28
|
+
| --- | --- | --- |
|
|
29
|
+
| selected | `boolean` (marks the active value: data-selected attr, body text color, trailing primary-tinted check) | - |
|
|
30
|
+
| showCheck | `boolean` (renders the trailing check glyph only, without selected styling or primary tint) | - |
|
|
31
|
+
|
|
32
|
+
Extends `React.ComponentProps<typeof DropdownMenuPrimitive.Item>`.
|
|
33
|
+
|
|
34
|
+
## Examples
|
|
35
|
+
|
|
36
|
+
From `dropdown-menu-demo`:
|
|
37
|
+
|
|
38
|
+
```tsx
|
|
39
|
+
"use client"
|
|
40
|
+
|
|
41
|
+
import { Button } from "@/components/ui/button"
|
|
42
|
+
import {
|
|
43
|
+
DropdownMenu,
|
|
44
|
+
DropdownMenuContent,
|
|
45
|
+
DropdownMenuGroup,
|
|
46
|
+
DropdownMenuItem,
|
|
47
|
+
DropdownMenuLabel,
|
|
48
|
+
DropdownMenuSeparator,
|
|
49
|
+
DropdownMenuTrigger,
|
|
50
|
+
} from "@/components/ui/dropdown-menu"
|
|
51
|
+
|
|
52
|
+
export default function DropdownMenuDemo() {
|
|
53
|
+
return (
|
|
54
|
+
<DropdownMenu>
|
|
55
|
+
<DropdownMenuTrigger asChild>
|
|
56
|
+
<Button
|
|
57
|
+
variant="neutral-solid"
|
|
58
|
+
appearance="outline"
|
|
59
|
+
size="sm"
|
|
60
|
+
className="w-fit"
|
|
61
|
+
>
|
|
62
|
+
Open
|
|
63
|
+
</Button>
|
|
64
|
+
</DropdownMenuTrigger>
|
|
65
|
+
<DropdownMenuContent>
|
|
66
|
+
<DropdownMenuGroup>
|
|
67
|
+
<DropdownMenuLabel>My Account</DropdownMenuLabel>
|
|
68
|
+
<DropdownMenuItem>Profile</DropdownMenuItem>
|
|
69
|
+
<DropdownMenuItem>Billing</DropdownMenuItem>
|
|
70
|
+
<DropdownMenuItem>Settings</DropdownMenuItem>
|
|
71
|
+
</DropdownMenuGroup>
|
|
72
|
+
<DropdownMenuSeparator />
|
|
73
|
+
<DropdownMenuGroup>
|
|
74
|
+
<DropdownMenuItem>GitHub</DropdownMenuItem>
|
|
75
|
+
<DropdownMenuItem>Support</DropdownMenuItem>
|
|
76
|
+
<DropdownMenuItem disabled>API</DropdownMenuItem>
|
|
77
|
+
</DropdownMenuGroup>
|
|
78
|
+
</DropdownMenuContent>
|
|
79
|
+
</DropdownMenu>
|
|
80
|
+
)
|
|
81
|
+
}
|
|
82
|
+
```
|
|
83
|
+
|
|
84
|
+
From `dropdown-menu-with-avatar`:
|
|
85
|
+
|
|
86
|
+
```tsx
|
|
87
|
+
"use client"
|
|
88
|
+
|
|
89
|
+
import {
|
|
90
|
+
RiBankCardLine,
|
|
91
|
+
RiCheckboxCircleLine,
|
|
92
|
+
RiLogoutBoxLine,
|
|
93
|
+
RiNotificationLine,
|
|
94
|
+
} from "@create-ui/assets/icons"
|
|
95
|
+
|
|
96
|
+
import { Avatar, AvatarImage } from "@/components/ui/avatar"
|
|
97
|
+
import { Button } from "@/components/ui/button"
|
|
98
|
+
import {
|
|
99
|
+
DropdownMenu,
|
|
100
|
+
DropdownMenuContent,
|
|
101
|
+
DropdownMenuGroup,
|
|
102
|
+
DropdownMenuItem,
|
|
103
|
+
DropdownMenuSeparator,
|
|
104
|
+
DropdownMenuTrigger,
|
|
105
|
+
} from "@/components/ui/dropdown-menu"
|
|
106
|
+
|
|
107
|
+
export default function DropdownMenuWithAvatar() {
|
|
108
|
+
return (
|
|
109
|
+
<DropdownMenu>
|
|
110
|
+
<DropdownMenuTrigger asChild>
|
|
111
|
+
<Button
|
|
112
|
+
variant="neutral-solid"
|
|
113
|
+
appearance="ghost"
|
|
114
|
+
size="xl"
|
|
115
|
+
shape="pill"
|
|
116
|
+
iconOnly
|
|
117
|
+
aria-label="Open account menu"
|
|
118
|
+
>
|
|
119
|
+
<Avatar size="lg">
|
|
120
|
+
<AvatarImage
|
|
121
|
+
src="https://createui.co/avatars/luca-moretti.webp"
|
|
122
|
+
alt="Luca Moretti"
|
|
123
|
+
/>
|
|
124
|
+
</Avatar>
|
|
125
|
+
</Button>
|
|
126
|
+
</DropdownMenuTrigger>
|
|
127
|
+
<DropdownMenuContent align="end">
|
|
128
|
+
<DropdownMenuGroup>
|
|
129
|
+
<DropdownMenuItem>
|
|
130
|
+
<RiCheckboxCircleLine />
|
|
131
|
+
Account
|
|
132
|
+
</DropdownMenuItem>
|
|
133
|
+
<DropdownMenuItem>
|
|
134
|
+
<RiBankCardLine />
|
|
135
|
+
Billing
|
|
136
|
+
</DropdownMenuItem>
|
|
137
|
+
<DropdownMenuItem>
|
|
138
|
+
<RiNotificationLine />
|
|
139
|
+
Notifications
|
|
140
|
+
</DropdownMenuItem>
|
|
141
|
+
</DropdownMenuGroup>
|
|
142
|
+
<DropdownMenuSeparator />
|
|
143
|
+
<DropdownMenuItem>
|
|
144
|
+
<RiLogoutBoxLine />
|
|
145
|
+
Sign Out
|
|
146
|
+
</DropdownMenuItem>
|
|
147
|
+
</DropdownMenuContent>
|
|
148
|
+
</DropdownMenu>
|
|
149
|
+
)
|
|
150
|
+
}
|
|
151
|
+
```
|
|
152
|
+
|
|
153
|
+
More: `npx @create-ui/cli view dropdown-menu` or MCP `get_item_examples_from_registries` with "dropdown-menu-demo" / "dropdown-menu-example".
|
|
154
|
+
|
|
155
|
+
## When to use
|
|
156
|
+
DropdownMenu is a trigger-attached action menu for account controls, row actions, and overflow commands; attach via `DropdownMenuTrigger asChild` wrapping a `Button`. Do not use it to bind a form value (use `Select`) and there is no popover component for arbitrary non-menu content - keep menus to menu items.
|
|
157
|
+
## Gotchas
|
|
158
|
+
- Smaller surface than shadcn: there is no `DropdownMenuCheckboxItem`, `RadioGroup`/`RadioItem`, `Sub*`, or `Shortcut`; importing those names fails. Active-value menus use plain `DropdownMenuItem` with `selected`/`showCheck`.
|
|
159
|
+
- `size` lives only on the `DropdownMenu` root and cascades via context to content radius, item height, label, and icon size; `DropdownMenuContent`/`Item`/`Label` accept no size prop. `Content` has a Field-context fallback, but it is unreachable because the menu context always supplies a size, so a surrounding `Field` never resizes the menu.
|
|
160
|
+
- Item children are auto-laid-out: bare string/number children get wrapped in `px-1` spans, and icons are auto-sized per menu size via `[&_svg]:size-*`. Pass a bare icon then text; do not add size classes to icons or wrap icon + text yourself.
|
|
161
|
+
- With `asChild`, the item clones the child (e.g. `<a>` or router `Link`), keeps its props (href, target), but replaces its children with the rebuilt label-span + check layout; put icon + text directly inside the child, no extra wrappers.
|
|
162
|
+
- `DropdownMenuContent` portals itself (no `DropdownMenuPortal` needed) and defaults `align="start"`, not Radix's `"center"`; pass `align="end"` for trigger-right menus like avatar/account.
|
|
163
|
+
- `DropdownMenuGroup` is an unstyled semantic passthrough; the visible break between groups comes from `DropdownMenuSeparator`, not the group.
|
|
164
|
+
- Avatar-in-button triggers: an iconOnly Button is 48px (size-12) at size="xl" while Avatar xl is 56px (size-14); the button's overflow-hidden crops the avatar and clips its stroke. Pair the avatar one size DOWN from the button (Button xl + Avatar lg). If the trigger avatar carries an AvatarText fallback, also give it a variant (e.g. weak-neutral) so the initials get a background.
|
|
@@ -0,0 +1,186 @@
|
|
|
1
|
+
<!-- GENERATED FILE - do not edit. Source: registry/ui/field.tsx. Regenerate with `pnpm skill:build`. Curated notes: apps/v4/scripts/skill-reference/notes/field.md -->
|
|
2
|
+
|
|
3
|
+
# field
|
|
4
|
+
|
|
5
|
+
Form field wrapper that owns the xs/sm/md size cascade; Input, Select and Textarea inherit size and state via context
|
|
6
|
+
|
|
7
|
+
Install: `npx @create-ui/cli add field`
|
|
8
|
+
|
|
9
|
+
## Import
|
|
10
|
+
|
|
11
|
+
```tsx
|
|
12
|
+
import { Field, FieldLabel, FieldTitle, FieldContent, FieldDescription, FieldError, FieldFooter, FieldGroup, FieldHelper, FieldLegend, FieldSeparator, FieldSet } from "@/components/ui/field"
|
|
13
|
+
```
|
|
14
|
+
|
|
15
|
+
Also exported: `LabelDescription`, `fieldVariants`, `fieldLabelVariants`, `fieldTitleVariants`, `fieldDescriptionVariants`, `fieldHelperVariants`, `fieldErrorVariants`, `fieldFooterVariants`, `fieldLegendVariants`, `useFieldContext`, `useOptionalFieldContext`
|
|
16
|
+
|
|
17
|
+
## Field props
|
|
18
|
+
|
|
19
|
+
| Prop | Type | Default |
|
|
20
|
+
| --- | --- | --- |
|
|
21
|
+
| size | `xs \| sm \| md` (cascades via context to Input/Select/Textarea/labels; set it ONCE here) | `sm` |
|
|
22
|
+
| orientation | `vertical \| horizontal \| responsive` (horizontal puts the label beside the control (settings rows); responsive only inlines inside a FieldGroup) | `vertical` |
|
|
23
|
+
| invalid | `boolean` | - |
|
|
24
|
+
| disabled | `boolean` | - |
|
|
25
|
+
| loading | `boolean` | - |
|
|
26
|
+
|
|
27
|
+
Extends `React.ComponentProps<"div">`.
|
|
28
|
+
|
|
29
|
+
## FieldTitle props
|
|
30
|
+
|
|
31
|
+
| Prop | Type | Default |
|
|
32
|
+
| --- | --- | --- |
|
|
33
|
+
| size | `xs \| sm \| md` (cascades via context to Input/Select/Textarea/labels; set it ONCE here) | `sm` |
|
|
34
|
+
|
|
35
|
+
Extends `React.ComponentProps<"div">`.
|
|
36
|
+
|
|
37
|
+
## FieldDescription props
|
|
38
|
+
|
|
39
|
+
| Prop | Type | Default |
|
|
40
|
+
| --- | --- | --- |
|
|
41
|
+
| size | `xs \| sm \| md` (cascades via context to Input/Select/Textarea/labels; set it ONCE here) | `sm` |
|
|
42
|
+
|
|
43
|
+
Extends `React.ComponentProps<"p">`.
|
|
44
|
+
|
|
45
|
+
## FieldError props
|
|
46
|
+
|
|
47
|
+
| Prop | Type | Default |
|
|
48
|
+
| --- | --- | --- |
|
|
49
|
+
| size | `xs \| sm \| md` (cascades via context to Input/Select/Textarea/labels; set it ONCE here) | `sm` |
|
|
50
|
+
| errors | `Array<{ message?: string } \| undefined>` (deduped by message; bulleted list when >1; renders nothing when empty) | - |
|
|
51
|
+
|
|
52
|
+
Extends `React.ComponentProps<"div">`.
|
|
53
|
+
|
|
54
|
+
## FieldFooter props
|
|
55
|
+
|
|
56
|
+
| Prop | Type | Default |
|
|
57
|
+
| --- | --- | --- |
|
|
58
|
+
| size | `xs \| sm \| md` (cascades via context to Input/Select/Textarea/labels; set it ONCE here) | `sm` |
|
|
59
|
+
|
|
60
|
+
Extends `React.ComponentProps<"div">`.
|
|
61
|
+
|
|
62
|
+
## FieldHelper props
|
|
63
|
+
|
|
64
|
+
| Prop | Type | Default |
|
|
65
|
+
| --- | --- | --- |
|
|
66
|
+
| size | `xs \| sm \| md` (cascades via context to Input/Select/Textarea/labels; set it ONCE here) | `sm` |
|
|
67
|
+
| tone | `neutral \| error` (auto-defaults to error when the Field is invalid) | `neutral` |
|
|
68
|
+
| icon | `ReactNode` (the only Field part that takes its icon as a prop, not a child slot) | - |
|
|
69
|
+
|
|
70
|
+
Extends `React.ComponentProps<"div">`.
|
|
71
|
+
|
|
72
|
+
## FieldLegend props
|
|
73
|
+
|
|
74
|
+
| Prop | Type | Default |
|
|
75
|
+
| --- | --- | --- |
|
|
76
|
+
| variant | `legend \| label` (label downsizes the legend to match a default (sm) FieldLabel; FieldLegend ignores Field size context) | `legend` |
|
|
77
|
+
|
|
78
|
+
Extends `React.ComponentProps<"legend">`.
|
|
79
|
+
|
|
80
|
+
## FieldSeparator props
|
|
81
|
+
|
|
82
|
+
| Prop | Type | Default |
|
|
83
|
+
| --- | --- | --- |
|
|
84
|
+
| children | `ReactNode` | - |
|
|
85
|
+
|
|
86
|
+
Extends `React.ComponentProps<"div">`.
|
|
87
|
+
|
|
88
|
+
## Examples
|
|
89
|
+
|
|
90
|
+
From `field-demo`:
|
|
91
|
+
|
|
92
|
+
```tsx
|
|
93
|
+
import { Field, FieldDescription, FieldLabel } from "@/components/ui/field"
|
|
94
|
+
import { Input } from "@/components/ui/input"
|
|
95
|
+
|
|
96
|
+
export default function FieldDemo() {
|
|
97
|
+
return (
|
|
98
|
+
<Field className="w-full max-w-sm">
|
|
99
|
+
<FieldLabel htmlFor="field-demo-email">Email Address</FieldLabel>
|
|
100
|
+
<Input id="field-demo-email" type="email" placeholder="you@example.com" />
|
|
101
|
+
<FieldDescription>
|
|
102
|
+
We'll never share your email with anyone.
|
|
103
|
+
</FieldDescription>
|
|
104
|
+
</Field>
|
|
105
|
+
)
|
|
106
|
+
}
|
|
107
|
+
```
|
|
108
|
+
|
|
109
|
+
From `field-composition`:
|
|
110
|
+
|
|
111
|
+
```tsx
|
|
112
|
+
import {
|
|
113
|
+
Field,
|
|
114
|
+
FieldContent,
|
|
115
|
+
FieldDescription,
|
|
116
|
+
FieldGroup,
|
|
117
|
+
FieldLabel,
|
|
118
|
+
} from "@/components/ui/field"
|
|
119
|
+
import { Input } from "@/components/ui/input"
|
|
120
|
+
import {
|
|
121
|
+
Select,
|
|
122
|
+
SelectContent,
|
|
123
|
+
SelectGroup,
|
|
124
|
+
SelectItem,
|
|
125
|
+
SelectTrigger,
|
|
126
|
+
SelectValue,
|
|
127
|
+
} from "@/components/ui/select"
|
|
128
|
+
import { Switch } from "@/components/ui/switch"
|
|
129
|
+
import { Textarea } from "@/components/ui/textarea"
|
|
130
|
+
|
|
131
|
+
export default function FieldComposition() {
|
|
132
|
+
return (
|
|
133
|
+
<FieldGroup className="w-full max-w-sm">
|
|
134
|
+
<Field size="md">
|
|
135
|
+
<FieldLabel htmlFor="field-compose-name">Full Name</FieldLabel>
|
|
136
|
+
<Input id="field-compose-name" placeholder="Jane Doe" />
|
|
137
|
+
</Field>
|
|
138
|
+
<Field size="md">
|
|
139
|
+
<FieldLabel htmlFor="field-compose-country">Country</FieldLabel>
|
|
140
|
+
<Select>
|
|
141
|
+
<SelectTrigger id="field-compose-country">
|
|
142
|
+
<SelectValue placeholder="Select your country" />
|
|
143
|
+
</SelectTrigger>
|
|
144
|
+
<SelectContent>
|
|
145
|
+
<SelectGroup>
|
|
146
|
+
<SelectItem value="us">United States</SelectItem>
|
|
147
|
+
<SelectItem value="uk">United Kingdom</SelectItem>
|
|
148
|
+
<SelectItem value="ca">Canada</SelectItem>
|
|
149
|
+
</SelectGroup>
|
|
150
|
+
</SelectContent>
|
|
151
|
+
</Select>
|
|
152
|
+
</Field>
|
|
153
|
+
<Field size="md">
|
|
154
|
+
<FieldLabel htmlFor="field-compose-bio">Bio</FieldLabel>
|
|
155
|
+
<Textarea id="field-compose-bio" placeholder="A few sentences" />
|
|
156
|
+
</Field>
|
|
157
|
+
<Field size="md" orientation="horizontal">
|
|
158
|
+
<FieldContent>
|
|
159
|
+
<FieldLabel htmlFor="field-compose-marketing">
|
|
160
|
+
Marketing Emails
|
|
161
|
+
</FieldLabel>
|
|
162
|
+
<FieldDescription>
|
|
163
|
+
Receive product news and occasional offers.
|
|
164
|
+
</FieldDescription>
|
|
165
|
+
</FieldContent>
|
|
166
|
+
<Switch id="field-compose-marketing" />
|
|
167
|
+
</Field>
|
|
168
|
+
</FieldGroup>
|
|
169
|
+
)
|
|
170
|
+
}
|
|
171
|
+
```
|
|
172
|
+
|
|
173
|
+
More: `npx @create-ui/cli view field` or MCP `get_item_examples_from_registries` with "field-demo" / "field-example".
|
|
174
|
+
|
|
175
|
+
## When to use
|
|
176
|
+
|
|
177
|
+
Layout and context wrapper for every labeled form control: forms are `FieldGroup` > `Field`(s), never raw divs with `space-y-*`. The control inside is `Input`/`Select`/`Textarea`/`Checkbox`/`Switch`; a multi-option group that is one logical control should be `RadioGroup` or `CheckboxGroup` instead. Group related fields with `FieldSet` + `FieldLegend`, not a heading div.
|
|
178
|
+
|
|
179
|
+
## Gotchas
|
|
180
|
+
|
|
181
|
+
- Set `size`/`invalid`/`disabled`/`loading` once on `Field`; nested controls and `Field*` parts resolve explicit prop ?? context ?? default - never re-set them on children. `Field` also derives state from `data-invalid`/`data-disabled`/`data-loading` attributes when the boolean props are absent.
|
|
182
|
+
- `orientation="responsive"` switches via a container query that only `FieldGroup` provides (`@container/field-group`); a responsive `Field` without a `FieldGroup` ancestor stays stacked forever.
|
|
183
|
+
- Horizontal checkbox/switch rows: stack `FieldLabel` + `FieldDescription` inside `FieldContent` as a DIRECT child of `Field` - the alignment switch keys off `has-[>[data-slot=field-content]]`. Rich choice cards use `Label` + `LabelDescription` inside `LabelMain` there, not `FieldLabel` + `FieldDescription`.
|
|
184
|
+
- Render `FieldError` unconditionally; it returns null when it has no `children` and no `errors`, and `children` take precedence over `errors`. It ships with `role="alert"`.
|
|
185
|
+
- `FieldTitle` renders a `<div>` with no `htmlFor` association, but it shares `data-slot="field-label"`, so horizontal layout treats it like a label; use it for non-labelable controls such as a segmented control.
|
|
186
|
+
- Vertical (default) Field forces every direct child to full width via [&>*]:w-full; self-start does NOT stop the stretch. For intrinsic-width controls (SegmentedControl, a lone Button), use orientation="horizontal" or wrap the control in a plain div.
|
|
@@ -0,0 +1,110 @@
|
|
|
1
|
+
<!-- GENERATED FILE - do not edit. Source: registry/ui/info-tooltip.tsx. Regenerate with `pnpm skill:build`. Curated notes: apps/v4/scripts/skill-reference/notes/info-tooltip.md -->
|
|
2
|
+
|
|
3
|
+
# info-tooltip
|
|
4
|
+
|
|
5
|
+
Tooltip with a built-in info icon trigger for field hints; pass variant/size on the root for the simplified API
|
|
6
|
+
|
|
7
|
+
Install: `npx @create-ui/cli add info-tooltip`
|
|
8
|
+
|
|
9
|
+
## Import
|
|
10
|
+
|
|
11
|
+
```tsx
|
|
12
|
+
import { InfoTooltip, InfoTooltipContent, InfoTooltipProvider, InfoTooltipTrigger } from "@/components/ui/info-tooltip"
|
|
13
|
+
```
|
|
14
|
+
|
|
15
|
+
Also exported: `infoTooltipContentVariants`
|
|
16
|
+
|
|
17
|
+
## InfoTooltip props
|
|
18
|
+
|
|
19
|
+
| Prop | Type | Default |
|
|
20
|
+
| --- | --- | --- |
|
|
21
|
+
| variant | `primary \| neutral \| inverse \| danger \| info` | - |
|
|
22
|
+
| size | `sm \| md \| lg` | - |
|
|
23
|
+
| side | `top \| bottom \| left \| right` | - |
|
|
24
|
+
| align | `start \| center \| end` | - |
|
|
25
|
+
| showArrow | `boolean` (When false, sideOffset is auto-increased by 7 so the gap matches the arrow version) | - |
|
|
26
|
+
| className | `string` | - |
|
|
27
|
+
|
|
28
|
+
Extends `React.ComponentProps< typeof TooltipPrimitive.Root >`.
|
|
29
|
+
|
|
30
|
+
## InfoTooltipContent props
|
|
31
|
+
|
|
32
|
+
| Prop | Type | Default |
|
|
33
|
+
| --- | --- | --- |
|
|
34
|
+
| variant | `primary \| neutral \| inverse \| danger \| info` | `primary` |
|
|
35
|
+
| size | `sm \| md \| lg` | `sm` |
|
|
36
|
+
| children | `ReactNode` | - |
|
|
37
|
+
| className | `string` | - |
|
|
38
|
+
| showArrow | `boolean` (When false, sideOffset is auto-increased by 7 so the gap matches the arrow version) | `true` |
|
|
39
|
+
| side | `top \| bottom \| left \| right` | `bottom` |
|
|
40
|
+
| align | `start \| center \| end` | `center` |
|
|
41
|
+
| sideOffset | `number` | `2.5` |
|
|
42
|
+
| alignOffset | `number` (Auto-resolves for align start/end to -12 (sm/md) or -16 (lg); center gets 0) | - |
|
|
43
|
+
|
|
44
|
+
Extends `React.ComponentProps<typeof TooltipPrimitive.Content>`.
|
|
45
|
+
|
|
46
|
+
## InfoTooltipTrigger props
|
|
47
|
+
|
|
48
|
+
| Prop | Type | Default |
|
|
49
|
+
| --- | --- | --- |
|
|
50
|
+
| children | `ReactNode` | - |
|
|
51
|
+
| asChild | `boolean` | - |
|
|
52
|
+
| variant | `primary \| neutral \| inverse \| danger \| info` | - |
|
|
53
|
+
| size | `sm \| md \| lg` | - |
|
|
54
|
+
| className | `string` | - |
|
|
55
|
+
|
|
56
|
+
Extends `React.ComponentProps<typeof TooltipPrimitive.Trigger>`.
|
|
57
|
+
|
|
58
|
+
## Examples
|
|
59
|
+
|
|
60
|
+
From `label-info-tooltip`:
|
|
61
|
+
|
|
62
|
+
```tsx
|
|
63
|
+
import { RiKey2Line } from "@create-ui/assets/icons"
|
|
64
|
+
|
|
65
|
+
import { Field } from "@/components/ui/field"
|
|
66
|
+
import { InfoTooltip } from "@/components/ui/info-tooltip"
|
|
67
|
+
import { Input } from "@/components/ui/input"
|
|
68
|
+
import { Label, LabelIcon, LabelInfoSlot } from "@/components/ui/label"
|
|
69
|
+
|
|
70
|
+
export default function LabelInfoTooltip() {
|
|
71
|
+
return (
|
|
72
|
+
<Field className="w-full max-w-xs">
|
|
73
|
+
<Label htmlFor="label-info">
|
|
74
|
+
<LabelIcon>
|
|
75
|
+
<RiKey2Line />
|
|
76
|
+
</LabelIcon>
|
|
77
|
+
API token
|
|
78
|
+
<LabelInfoSlot>
|
|
79
|
+
<InfoTooltip variant="inverse" size="sm" side="top">
|
|
80
|
+
Used to authenticate API requests. Keep it secret, treat it like a
|
|
81
|
+
password, and rotate it right away if it ever leaks or shows up in a
|
|
82
|
+
commit.
|
|
83
|
+
</InfoTooltip>
|
|
84
|
+
</LabelInfoSlot>
|
|
85
|
+
</Label>
|
|
86
|
+
<Input id="label-info" placeholder="sk-…" />
|
|
87
|
+
</Field>
|
|
88
|
+
)
|
|
89
|
+
}
|
|
90
|
+
```
|
|
91
|
+
|
|
92
|
+
More: `npx @create-ui/cli view info-tooltip` or MCP `get_item_examples_from_registries` with "info-tooltip-demo" / "info-tooltip-example".
|
|
93
|
+
|
|
94
|
+
## When to use
|
|
95
|
+
A "what is this?" helper with a built-in info-circle icon trigger, typically next to a field label (canonical placement: inside `LabelInfoSlot` within `Label`, see label-info-tooltip). Do NOT use it for hover hints on arbitrary elements like buttons; that is `Tooltip`. There is no popover component for click-to-open rich content - surface that content inline.
|
|
96
|
+
|
|
97
|
+
## Gotchas
|
|
98
|
+
- The root has two modes. Setting `variant` OR `size` on `InfoTooltip` activates the simplified API: children become the tooltip TEXT and the icon trigger plus content are auto-rendered. With neither prop set it is a bare Radix Root: compose `InfoTooltipTrigger` + `InfoTooltipContent` yourself, and `side`/`align`/`showArrow`/`className` on the root do nothing.
|
|
99
|
+
- In composed mode there is no context cascade: pass the same `variant`/`size` to BOTH `InfoTooltipTrigger` (icon color/size) and `InfoTooltipContent` (bubble styling). The arrow fill is derived by Content from its own `variant`.
|
|
100
|
+
- `InfoTooltipTrigger` with no children renders a built-in inline info SVG; passing children replaces it entirely and the trigger's `variant`/`size` stop doing anything. The trigger always carries the `group` class, so custom children can style via `group-hover:` and `group-data-[state=open]:`.
|
|
101
|
+
- Placement defaults to bottom (shadcn/Radix tooltips default to top). An AI trained on shadcn will also reach for `TooltipProvider` + `Trigger asChild` + `Content`; the intended common form is the one-liner:
|
|
102
|
+
|
|
103
|
+
```tsx
|
|
104
|
+
<InfoTooltip variant="inverse" size="sm" side="top">
|
|
105
|
+
Helper text
|
|
106
|
+
</InfoTooltip>
|
|
107
|
+
```
|
|
108
|
+
|
|
109
|
+
- It does not read Field context; set `size` explicitly even inside a `Field`/`Label`.
|
|
110
|
+
- The icon is hardcoded inline in the component, not imported from `@create-ui/assets/icons`; do not "fix" it to a Remix icon.
|
|
@@ -0,0 +1,146 @@
|
|
|
1
|
+
<!-- GENERATED FILE - do not edit. Source: registry/ui/inline-alert.tsx. Regenerate with `pnpm skill:build`. Curated notes: apps/v4/scripts/skill-reference/notes/inline-alert.md -->
|
|
2
|
+
|
|
3
|
+
# inline-alert
|
|
4
|
+
|
|
5
|
+
Dismissible callout for in-page messages; seven variants by four appearances with horizontal or vertical layout
|
|
6
|
+
|
|
7
|
+
Install: `npx @create-ui/cli add inline-alert`
|
|
8
|
+
|
|
9
|
+
## Import
|
|
10
|
+
|
|
11
|
+
```tsx
|
|
12
|
+
import { InlineAlert, InlineAlertIcon, InlineAlertContent, InlineAlertHeading, InlineAlertTitle, InlineAlertDescription, InlineAlertActions, InlineAlertClose } from "@/components/ui/inline-alert"
|
|
13
|
+
```
|
|
14
|
+
|
|
15
|
+
Also exported: `inlineAlertVariants`, `useInlineAlertContext`
|
|
16
|
+
|
|
17
|
+
## InlineAlert props
|
|
18
|
+
|
|
19
|
+
| Prop | Type | Default |
|
|
20
|
+
| --- | --- | --- |
|
|
21
|
+
| variant | `primary \| neutral \| danger \| success \| warning \| info \| away` | `primary` |
|
|
22
|
+
| appearance | `solid \| soft \| outline \| default` (default = neutral card (border + shadow; variant tints only the icon); soft = tinted fill; solid = filled high-emphasis; outline = tinted text + colored border) | `default` |
|
|
23
|
+
| layout | `horizontal \| vertical` (horizontal nowraps the title and clamps description to 2 lines; vertical clamps at 5 - use vertical for longer copy) | `horizontal` |
|
|
24
|
+
| onDismiss | `() => void` (fires when the 300ms exit transition ends, not on close click) | - |
|
|
25
|
+
|
|
26
|
+
Extends `React.ComponentProps<"div">`.
|
|
27
|
+
|
|
28
|
+
## Examples
|
|
29
|
+
|
|
30
|
+
From `inline-alert-demo`:
|
|
31
|
+
|
|
32
|
+
```tsx
|
|
33
|
+
import { RiInformationFill } from "@create-ui/assets/icons"
|
|
34
|
+
|
|
35
|
+
import {
|
|
36
|
+
InlineAlert,
|
|
37
|
+
InlineAlertContent,
|
|
38
|
+
InlineAlertDescription,
|
|
39
|
+
InlineAlertHeading,
|
|
40
|
+
InlineAlertIcon,
|
|
41
|
+
InlineAlertTitle,
|
|
42
|
+
} from "@/components/ui/inline-alert"
|
|
43
|
+
|
|
44
|
+
export default function InlineAlertDemo() {
|
|
45
|
+
return (
|
|
46
|
+
<InlineAlert>
|
|
47
|
+
<InlineAlertIcon>
|
|
48
|
+
<RiInformationFill />
|
|
49
|
+
</InlineAlertIcon>
|
|
50
|
+
<InlineAlertContent>
|
|
51
|
+
<InlineAlertHeading>
|
|
52
|
+
<InlineAlertTitle>Heads up</InlineAlertTitle>
|
|
53
|
+
<InlineAlertDescription>
|
|
54
|
+
Your changes have been saved to the draft.
|
|
55
|
+
</InlineAlertDescription>
|
|
56
|
+
</InlineAlertHeading>
|
|
57
|
+
</InlineAlertContent>
|
|
58
|
+
</InlineAlert>
|
|
59
|
+
)
|
|
60
|
+
}
|
|
61
|
+
```
|
|
62
|
+
|
|
63
|
+
From `inline-alert-dismissible`:
|
|
64
|
+
|
|
65
|
+
```tsx
|
|
66
|
+
"use client"
|
|
67
|
+
|
|
68
|
+
import * as React from "react"
|
|
69
|
+
import { RiCheckboxCircleFill } from "@create-ui/assets/icons"
|
|
70
|
+
|
|
71
|
+
import { Button } from "@/components/ui/button"
|
|
72
|
+
import {
|
|
73
|
+
InlineAlert,
|
|
74
|
+
InlineAlertClose,
|
|
75
|
+
InlineAlertContent,
|
|
76
|
+
InlineAlertDescription,
|
|
77
|
+
InlineAlertHeading,
|
|
78
|
+
InlineAlertIcon,
|
|
79
|
+
InlineAlertTitle,
|
|
80
|
+
} from "@/components/ui/inline-alert"
|
|
81
|
+
|
|
82
|
+
export default function InlineAlertDismissible() {
|
|
83
|
+
const [visible, setVisible] = React.useState(true)
|
|
84
|
+
|
|
85
|
+
if (!visible) {
|
|
86
|
+
return (
|
|
87
|
+
<Button
|
|
88
|
+
variant="neutral-light"
|
|
89
|
+
appearance="outline"
|
|
90
|
+
size="md"
|
|
91
|
+
onClick={() => setVisible(true)}
|
|
92
|
+
>
|
|
93
|
+
Show alert again
|
|
94
|
+
</Button>
|
|
95
|
+
)
|
|
96
|
+
}
|
|
97
|
+
|
|
98
|
+
return (
|
|
99
|
+
<InlineAlert variant="success" onDismiss={() => setVisible(false)}>
|
|
100
|
+
<InlineAlertIcon>
|
|
101
|
+
<RiCheckboxCircleFill />
|
|
102
|
+
</InlineAlertIcon>
|
|
103
|
+
<InlineAlertContent>
|
|
104
|
+
<InlineAlertHeading>
|
|
105
|
+
<InlineAlertTitle>Saved</InlineAlertTitle>
|
|
106
|
+
<InlineAlertDescription>
|
|
107
|
+
Your settings are up to date. Dismiss this banner to remove it from
|
|
108
|
+
the page.
|
|
109
|
+
</InlineAlertDescription>
|
|
110
|
+
</InlineAlertHeading>
|
|
111
|
+
</InlineAlertContent>
|
|
112
|
+
<InlineAlertClose />
|
|
113
|
+
</InlineAlert>
|
|
114
|
+
)
|
|
115
|
+
}
|
|
116
|
+
```
|
|
117
|
+
|
|
118
|
+
More: `npx @create-ui/cli view inline-alert` or MCP `get_item_examples_from_registries` with "inline-alert-demo" / "inline-alert-example".
|
|
119
|
+
|
|
120
|
+
## When to use
|
|
121
|
+
|
|
122
|
+
In-flow status callouts anchored to content: form-level validation summaries, plan notices, saved confirmations. There is no page-banner component; build a top-of-page announcement from semantic-token markup rather than stretching an InlineAlert. Ephemeral screen-level feedback is `Toast`; per-field validation is `Field` error/helper text.
|
|
123
|
+
|
|
124
|
+
## Gotchas
|
|
125
|
+
|
|
126
|
+
- Nesting is strict and deeper than shadcn's flat Alert: `InlineAlertTitle` + `InlineAlertDescription` go inside `InlineAlertHeading`, which sits next to `InlineAlertActions` inside `InlineAlertContent`. In horizontal layout Content is a flex row, so an unwrapped Title/Description render side by side instead of stacked.
|
|
127
|
+
|
|
128
|
+
```tsx
|
|
129
|
+
<InlineAlert variant="warning" appearance="soft" onDismiss={removeFromState}>
|
|
130
|
+
<InlineAlertIcon><RiErrorWarningFill /></InlineAlertIcon>
|
|
131
|
+
<InlineAlertContent>
|
|
132
|
+
<InlineAlertHeading>
|
|
133
|
+
<InlineAlertTitle>Storage almost full</InlineAlertTitle>
|
|
134
|
+
<InlineAlertDescription>Upgrade to keep receiving uploads.</InlineAlertDescription>
|
|
135
|
+
</InlineAlertHeading>
|
|
136
|
+
<InlineAlertActions>{/* Button / TextLink */}</InlineAlertActions>
|
|
137
|
+
</InlineAlertContent>
|
|
138
|
+
<InlineAlertClose />
|
|
139
|
+
</InlineAlert>
|
|
140
|
+
```
|
|
141
|
+
|
|
142
|
+
- `InlineAlertClose` always renders absolutely at the alert's top-right corner (the root is its only positioned ancestor), and the root auto-reserves clearance for it (`pr-12` horizontal, title right-padding vertical). Keep it a direct child of the root; nesting it inside `InlineAlertActions` does not put it in flow, it still jumps to the corner.
|
|
143
|
+
- Dismissal is self-contained: Close triggers a fade/scale exit, then the component unmounts itself (returns null). Sync external state in `onDismiss`, not in your own Close `onClick`, or the exit transition is cut off.
|
|
144
|
+
- `InlineAlertClose` auto-adapts its CloseButton to context (inverse on solid appearance, neutral otherwise); leave its variant unset.
|
|
145
|
+
- `InlineAlertIcon` sizes (`[&_svg]:size-5`) and colors the glyph from variant/appearance context; pass a bare `Ri*` icon with no size or color classes.
|
|
146
|
+
- Unlike shadcn's Alert, the default variant is `primary`, so an unconfigured alert's icon reads brand-tinted, not gray; use `variant="neutral"` for a plain note.
|