@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.
- 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 +26 -26
- 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 +199 -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/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/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,162 @@
|
|
|
1
|
+
<!-- GENERATED FILE - do not edit. Source: registry/ui/toast.tsx. Regenerate with `pnpm skill:build`. Curated notes: apps/v4/scripts/skill-reference/notes/toast.md -->
|
|
2
|
+
|
|
3
|
+
# toast
|
|
4
|
+
|
|
5
|
+
Notification card with icon, action and close slots plus ToastProgress countdown; seven variants by four appearances
|
|
6
|
+
|
|
7
|
+
Install: `npx @create-ui/cli add toast`
|
|
8
|
+
|
|
9
|
+
## Import
|
|
10
|
+
|
|
11
|
+
```tsx
|
|
12
|
+
import { Toast, ToastBody, ToastIcon, ToastContent, ToastTitle, ToastDescription, ToastAction, ToastClose, ToastProgress } from "@/components/ui/toast"
|
|
13
|
+
```
|
|
14
|
+
|
|
15
|
+
Also exported: `toastVariants`, `useToastContext`
|
|
16
|
+
|
|
17
|
+
## Toast props
|
|
18
|
+
|
|
19
|
+
| Prop | Type | Default |
|
|
20
|
+
| --- | --- | --- |
|
|
21
|
+
| variant | `primary \| neutral \| danger \| success \| warning \| info \| away` | `primary` |
|
|
22
|
+
| appearance | `solid \| soft \| outline \| default` (solid = filled, soft/outline/default = quieter surfaces) | `solid` |
|
|
23
|
+
|
|
24
|
+
Extends `React.ComponentProps<"div">`.
|
|
25
|
+
|
|
26
|
+
## ToastProgress props
|
|
27
|
+
|
|
28
|
+
| Prop | Type | Default |
|
|
29
|
+
| --- | --- | --- |
|
|
30
|
+
| value | `number` | - |
|
|
31
|
+
| duration | `number` (CSS tween duration per value change (default 150ms); for a lifetime countdown set it to the toast's full lifetime in ms) | `150` |
|
|
32
|
+
|
|
33
|
+
Extends `React.ComponentProps<"div">`.
|
|
34
|
+
|
|
35
|
+
## Examples
|
|
36
|
+
|
|
37
|
+
From `toast-demo`:
|
|
38
|
+
|
|
39
|
+
```tsx
|
|
40
|
+
import { RiInformationFill } from "@create-ui/assets/icons"
|
|
41
|
+
|
|
42
|
+
import {
|
|
43
|
+
Toast,
|
|
44
|
+
ToastBody,
|
|
45
|
+
ToastContent,
|
|
46
|
+
ToastDescription,
|
|
47
|
+
ToastIcon,
|
|
48
|
+
ToastTitle,
|
|
49
|
+
} from "@/components/ui/toast"
|
|
50
|
+
|
|
51
|
+
export default function ToastDemo() {
|
|
52
|
+
return (
|
|
53
|
+
<Toast>
|
|
54
|
+
<ToastBody>
|
|
55
|
+
<ToastIcon>
|
|
56
|
+
<RiInformationFill />
|
|
57
|
+
</ToastIcon>
|
|
58
|
+
<ToastContent>
|
|
59
|
+
<ToastTitle>New update available</ToastTitle>
|
|
60
|
+
<ToastDescription>Version 2.1 is ready to install.</ToastDescription>
|
|
61
|
+
</ToastContent>
|
|
62
|
+
</ToastBody>
|
|
63
|
+
</Toast>
|
|
64
|
+
)
|
|
65
|
+
}
|
|
66
|
+
```
|
|
67
|
+
|
|
68
|
+
From `toast-with-progress`:
|
|
69
|
+
|
|
70
|
+
```tsx
|
|
71
|
+
"use client"
|
|
72
|
+
|
|
73
|
+
import * as React from "react"
|
|
74
|
+
import { RiInformationFill } from "@create-ui/assets/icons"
|
|
75
|
+
|
|
76
|
+
import { Button } from "@/components/ui/button"
|
|
77
|
+
import {
|
|
78
|
+
Toast,
|
|
79
|
+
ToastBody,
|
|
80
|
+
ToastContent,
|
|
81
|
+
ToastDescription,
|
|
82
|
+
ToastIcon,
|
|
83
|
+
ToastProgress,
|
|
84
|
+
ToastTitle,
|
|
85
|
+
} from "@/components/ui/toast"
|
|
86
|
+
|
|
87
|
+
const DURATION_MS = 5000
|
|
88
|
+
|
|
89
|
+
export default function ToastWithProgress() {
|
|
90
|
+
const [visible, setVisible] = React.useState(true)
|
|
91
|
+
const [progress, setProgress] = React.useState(0)
|
|
92
|
+
|
|
93
|
+
React.useEffect(() => {
|
|
94
|
+
if (!visible) return
|
|
95
|
+
|
|
96
|
+
const raf = requestAnimationFrame(() => setProgress(100))
|
|
97
|
+
const timeout = setTimeout(() => setVisible(false), DURATION_MS)
|
|
98
|
+
|
|
99
|
+
return () => {
|
|
100
|
+
cancelAnimationFrame(raf)
|
|
101
|
+
clearTimeout(timeout)
|
|
102
|
+
}
|
|
103
|
+
}, [visible])
|
|
104
|
+
|
|
105
|
+
if (!visible) {
|
|
106
|
+
return (
|
|
107
|
+
<Button
|
|
108
|
+
variant="neutral-light"
|
|
109
|
+
appearance="outline"
|
|
110
|
+
onClick={() => {
|
|
111
|
+
setProgress(0)
|
|
112
|
+
setVisible(true)
|
|
113
|
+
}}
|
|
114
|
+
>
|
|
115
|
+
Show toast again
|
|
116
|
+
</Button>
|
|
117
|
+
)
|
|
118
|
+
}
|
|
119
|
+
|
|
120
|
+
return (
|
|
121
|
+
<Toast variant="info" appearance="soft">
|
|
122
|
+
<ToastBody>
|
|
123
|
+
<ToastIcon>
|
|
124
|
+
<RiInformationFill />
|
|
125
|
+
</ToastIcon>
|
|
126
|
+
<ToastContent>
|
|
127
|
+
<ToastTitle>Auto-dismissing in 5s</ToastTitle>
|
|
128
|
+
<ToastDescription>
|
|
129
|
+
The progress bar tracks the remaining lifetime of this toast.
|
|
130
|
+
</ToastDescription>
|
|
131
|
+
</ToastContent>
|
|
132
|
+
</ToastBody>
|
|
133
|
+
<ToastProgress value={progress} duration={DURATION_MS} />
|
|
134
|
+
</Toast>
|
|
135
|
+
)
|
|
136
|
+
}
|
|
137
|
+
```
|
|
138
|
+
|
|
139
|
+
More: `npx @create-ui/cli view toast` or MCP `get_item_examples_from_registries` with "toast-demo" / "toast-example".
|
|
140
|
+
|
|
141
|
+
## When to use
|
|
142
|
+
|
|
143
|
+
Ephemeral, floating confirmation of an action ("Draft saved", "Copied"); render it in a screen-level fixed container. Not for status that belongs to a section (use `InlineAlert`), blocking confirm/cancel decisions (use `Dialog`), or per-field validation (use `Field` helper/error text).
|
|
144
|
+
|
|
145
|
+
## Gotchas
|
|
146
|
+
|
|
147
|
+
- There is no `toast()` function, no `Toaster`, no app-level provider, no portal, no queue or positioning system. `Toast` is just the card; render active toasts from your own state into a fixed container. Do NOT install or import `sonner`.
|
|
148
|
+
- Dismiss lifecycle: `ToastClose` starts a 300ms fade/scale exit; the root's `onDismiss` fires only after the transition ends, then the component renders `null`. Remove the toast from your list in `onDismiss`, not in `ToastClose`'s `onClick`. Once dismissed it stays hidden; re-showing requires a remount (state toggle or new `key`).
|
|
149
|
+
- `ToastProgress` never ticks by itself and is `aria-hidden` (purely visual). For an auto-dismissing toast, set `duration` to the lifetime, flip `value` from 0 to 100 inside `requestAnimationFrame`, and pair it with a `setTimeout` that actually hides the toast:
|
|
150
|
+
|
|
151
|
+
```tsx
|
|
152
|
+
React.useEffect(() => {
|
|
153
|
+
const raf = requestAnimationFrame(() => setProgress(100))
|
|
154
|
+
const timeout = setTimeout(() => setVisible(false), DURATION_MS)
|
|
155
|
+
return () => { cancelAnimationFrame(raf); clearTimeout(timeout) }
|
|
156
|
+
}, [])
|
|
157
|
+
// <ToastProgress value={progress} duration={DURATION_MS} />
|
|
158
|
+
```
|
|
159
|
+
|
|
160
|
+
- `ToastIcon`, `ToastDescription`, `ToastAction`, `ToastClose`, and `ToastProgress` read the Toast context, so they only style correctly inside `<Toast>`. Don't hand-set Button variants on `ToastAction`/`ToastClose` (the appearance-matched pairing is automatic) or color/size classes on the icon (the svg is auto-sized `size-5` and colored per variant/appearance).
|
|
161
|
+
- The root is hard-coded `w-[410px] min-w-[300px]`; override the width via `className` for narrow viewports.
|
|
162
|
+
- The root renders `role="status"` (polite live region); pass `role="alert"` for urgent messages. No Escape-key handling is wired; dismissal happens only through `ToastClose` (or `useToastContext().dismiss`).
|
|
@@ -0,0 +1,63 @@
|
|
|
1
|
+
<!-- GENERATED FILE - do not edit. Source: registry/ui/tooltip.tsx. Regenerate with `pnpm skill:build`. Curated notes: apps/v4/scripts/skill-reference/notes/tooltip.md -->
|
|
2
|
+
|
|
3
|
+
# tooltip
|
|
4
|
+
|
|
5
|
+
Radix hover tooltip for any trigger element; five color variants, optional arrow, side and offset control
|
|
6
|
+
|
|
7
|
+
Install: `npx @create-ui/cli add tooltip`
|
|
8
|
+
|
|
9
|
+
## Import
|
|
10
|
+
|
|
11
|
+
```tsx
|
|
12
|
+
import { Tooltip, TooltipContent, TooltipProvider, TooltipTrigger } from "@/components/ui/tooltip"
|
|
13
|
+
```
|
|
14
|
+
|
|
15
|
+
Also exported: `tooltipContentVariants`
|
|
16
|
+
|
|
17
|
+
## TooltipContent props
|
|
18
|
+
|
|
19
|
+
| Prop | Type | Default |
|
|
20
|
+
| --- | --- | --- |
|
|
21
|
+
| children | `ReactNode` | - |
|
|
22
|
+
| className | `string` | - |
|
|
23
|
+
| variant | `primary \| neutral \| inverse \| danger \| info` | `primary` |
|
|
24
|
+
| showArrow | `boolean` (effective offset = sideOffset when true; sideOffset + 5 when false, so the chip keeps a visible gap without the caret) | `false` |
|
|
25
|
+
| side | `top \| bottom \| left \| right` (defaults to bottom; shadcn/Radix default to top, do not assume top) | `bottom` |
|
|
26
|
+
| sideOffset | `number` | `2.5` |
|
|
27
|
+
|
|
28
|
+
Extends `React.ComponentProps<typeof TooltipPrimitive.Content>`.
|
|
29
|
+
|
|
30
|
+
## Examples
|
|
31
|
+
|
|
32
|
+
From `tooltip-demo`:
|
|
33
|
+
|
|
34
|
+
```tsx
|
|
35
|
+
"use client"
|
|
36
|
+
|
|
37
|
+
import { Button } from "@/components/ui/button"
|
|
38
|
+
import { Tooltip, TooltipContent, TooltipTrigger } from "@/components/ui/tooltip"
|
|
39
|
+
|
|
40
|
+
export default function TooltipDemo() {
|
|
41
|
+
return (
|
|
42
|
+
<Tooltip defaultOpen>
|
|
43
|
+
<TooltipTrigger asChild>
|
|
44
|
+
<Button appearance="outline" size="sm">
|
|
45
|
+
Hover me
|
|
46
|
+
</Button>
|
|
47
|
+
</TooltipTrigger>
|
|
48
|
+
<TooltipContent showArrow>Add to library</TooltipContent>
|
|
49
|
+
</Tooltip>
|
|
50
|
+
)
|
|
51
|
+
}
|
|
52
|
+
```
|
|
53
|
+
|
|
54
|
+
More: `npx @create-ui/cli view tooltip` or MCP `get_item_examples_from_registries` with "tooltip-demo" / "tooltip-example".
|
|
55
|
+
|
|
56
|
+
## When to use
|
|
57
|
+
Tooltip is a short hover/focus hint for icon-only buttons, truncated labels, and similar read-only context. Content must stay brief: the chip caps at max-w-[200px] and wraps. For content with links, buttons, or inputs there is no popover component - put it inline; for a help icon next to a label use InfoTooltip; for post-action messages use Toast; for a persistent in-flow note use InlineAlert.
|
|
58
|
+
## Gotchas
|
|
59
|
+
- Tooltip self-provides its Radix Provider and passes delayDuration (default 0) explicitly to both Provider and Root, so an ancestor TooltipProvider's delayDuration never reaches it. Set delay per instance: `<Tooltip delayDuration={400}>`. The exported TooltipProvider only matters for raw TooltipPrimitive.Root subtrees.
|
|
60
|
+
- align is hardcoded to "center" and Omit-ed from the passthrough type; it cannot be overridden.
|
|
61
|
+
- TooltipTrigger should use asChild wrapping a focusable registry element (Button, link); the trigger always gets an `inline-flex` class so the wrapped child lays out consistently.
|
|
62
|
+
- TooltipArrow is internal and not exported; the only way to render the caret is `showArrow` on TooltipContent, and its fill auto-matches the chosen variant. Never try to style or compose the arrow separately.
|
|
63
|
+
- InfoTooltip is a separate ready-made component for inline "what is this" affordances; do not hand-compose Tooltip around an info icon.
|
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
# Component Composition
|
|
2
2
|
|
|
3
|
-
How Create UI components fit together. Compose primitives
|
|
3
|
+
How Create UI components fit together. Compose primitives - never reroll a `<select>`, a custom callout, or a hand-styled loading button when a component already exists. Every component name below is in the `@createui` registry; add any of them with `npx @create-ui/cli add <name>`.
|
|
4
4
|
|
|
5
5
|
## Contents
|
|
6
6
|
|
|
@@ -8,16 +8,16 @@ How Create UI components fit together. Compose primitives — never reroll a `<s
|
|
|
8
8
|
- Callouts use InlineAlert
|
|
9
9
|
- Toasts use the Toast component
|
|
10
10
|
- Choosing between overlay components
|
|
11
|
-
- Button has a `loading` prop
|
|
11
|
+
- Button has a `loading` prop - never hand-build a spinner button
|
|
12
12
|
- Tabbed navigation uses TabMenu
|
|
13
|
-
- Avatar
|
|
13
|
+
- Avatar composition (AvatarText, not AvatarFallback)
|
|
14
14
|
- Use existing components instead of custom markup
|
|
15
15
|
|
|
16
16
|
---
|
|
17
17
|
|
|
18
18
|
## Items always inside their Group component
|
|
19
19
|
|
|
20
|
-
Never render menu/list items directly inside the content container
|
|
20
|
+
Never render menu/list items directly inside the content container - always wrap them in the matching `*Group`.
|
|
21
21
|
|
|
22
22
|
**Incorrect:**
|
|
23
23
|
|
|
@@ -42,17 +42,17 @@ Never render menu/list items directly inside the content container — always wr
|
|
|
42
42
|
|
|
43
43
|
This applies to every group-based component:
|
|
44
44
|
|
|
45
|
-
| Item | Group |
|
|
46
|
-
|
|
47
|
-
| `SelectItem`, `SelectLabel` | `SelectGroup` |
|
|
48
|
-
| `
|
|
49
|
-
| `
|
|
45
|
+
| Item | Group | Requirement |
|
|
46
|
+
|------|-------|-------------|
|
|
47
|
+
| `SelectItem`, `SelectLabel` | `SelectGroup` | Structural - always wrap |
|
|
48
|
+
| `CommandItem` | `CommandGroup` | Structural - always wrap |
|
|
49
|
+
| `DropdownMenuItem`, `DropdownMenuLabel` | `DropdownMenuGroup` | Semantic - group related items (with `DropdownMenuLabel` / `DropdownMenuSeparator`); a lone item may sit directly in `DropdownMenuContent` |
|
|
50
50
|
|
|
51
51
|
---
|
|
52
52
|
|
|
53
53
|
## Callouts use InlineAlert
|
|
54
54
|
|
|
55
|
-
Use `InlineAlert` for callouts. Don't hand-roll a styled `<div>`
|
|
55
|
+
Use `InlineAlert` for callouts. Don't hand-roll a styled `<div>` - and don't look for a shadcn-style generic alert (or a page-banner) component; `InlineAlert` is the callout primitive.
|
|
56
56
|
|
|
57
57
|
**Incorrect:**
|
|
58
58
|
|
|
@@ -94,13 +94,13 @@ import {
|
|
|
94
94
|
</InlineAlert>
|
|
95
95
|
```
|
|
96
96
|
|
|
97
|
-
`InlineAlert` takes `variant` (`primary` | `neutral` | `danger` | `success` | `warning` | `info` | `away`) and `appearance` (`default` | `solid` | `soft` | `outline`). For a dismissible callout, add `<InlineAlertClose />` as a direct child and handle `onDismiss` on the root. For a full-width page banner, place an `InlineAlert` in a full-width container
|
|
97
|
+
`InlineAlert` takes `variant` (`primary` | `neutral` | `danger` | `success` | `warning` | `info` | `away`) and `appearance` (`default` | `solid` | `soft` | `outline`). For a dismissible callout, add `<InlineAlertClose />` as a direct child and handle `onDismiss` on the root. For a full-width page banner, place an `InlineAlert` in a full-width container - there is no separate banner component.
|
|
98
98
|
|
|
99
99
|
---
|
|
100
100
|
|
|
101
101
|
## Toasts use the Toast component
|
|
102
102
|
|
|
103
|
-
Toasts are the registry's own `toast` component
|
|
103
|
+
Toasts are the registry's own `toast` component - **not `sonner`**. There is no `toast()` function to import; compose the `Toast` parts and render it from your notification state.
|
|
104
104
|
|
|
105
105
|
**Incorrect:**
|
|
106
106
|
|
|
@@ -140,7 +140,7 @@ import {
|
|
|
140
140
|
|
|
141
141
|
`Toast` takes `variant` (`primary` | `neutral` | `danger` | `success` | `warning` | `info` | `away`) and `appearance` (`solid` | `soft` | `outline` | `default`), plus an `onDismiss` callback. Add `<ToastClose />` for an explicit close affordance and `<ToastProgress />` for an auto-dismiss countdown bar.
|
|
142
142
|
|
|
143
|
-
There is no provider, queue, or stacking system
|
|
143
|
+
There is no provider, queue, or stacking system - you own the notification state and the placement. Render active toasts from your state into a fixed container:
|
|
144
144
|
|
|
145
145
|
```tsx
|
|
146
146
|
const [toasts, setToasts] = React.useState<AppToast[]>([])
|
|
@@ -168,7 +168,7 @@ const [toasts, setToasts] = React.useState<AppToast[]>([])
|
|
|
168
168
|
|
|
169
169
|
## Choosing between overlay components
|
|
170
170
|
|
|
171
|
-
Pick the overlay that matches the interaction
|
|
171
|
+
Pick the overlay that matches the interaction - these are the overlays that exist.
|
|
172
172
|
|
|
173
173
|
| Use case | Component |
|
|
174
174
|
|----------|-----------|
|
|
@@ -177,13 +177,13 @@ Pick the overlay that matches the interaction — these are the overlays that ex
|
|
|
177
177
|
| Action menu on a trigger | `DropdownMenu` |
|
|
178
178
|
| Command palette / quick switcher | `Command` (inline) / `CommandDialog` (modal) |
|
|
179
179
|
|
|
180
|
-
There is **no dialog, popover, sheet, drawer, alert-dialog, or hover-card component**. The only modal surface is `CommandDialog` (shipped with `command`). For other modal or contextual-panel needs, don't invent a lookalike from raw markup
|
|
180
|
+
There is **no dialog, popover, sheet, drawer, alert-dialog, or hover-card component**. The only modal surface is `CommandDialog` (shipped with `command`). For other modal or contextual-panel needs, don't invent a lookalike from raw markup - surface the flow inline (e.g. an expanding section, a dedicated route, or an `InlineAlert` confirmation) or ask the user before hand-rolling an overlay.
|
|
181
181
|
|
|
182
182
|
---
|
|
183
183
|
|
|
184
|
-
## Button has a `loading` prop
|
|
184
|
+
## Button has a `loading` prop - never hand-build a spinner button
|
|
185
185
|
|
|
186
|
-
`Button` ships a real `loading` prop. It renders the `Spinner` and disables interaction for you
|
|
186
|
+
`Button` ships a real `loading` prop. It renders the `Spinner` and disables interaction for you - do not compose a `Spinner` + `disabled` button by hand.
|
|
187
187
|
|
|
188
188
|
**Incorrect:**
|
|
189
189
|
|
|
@@ -200,7 +200,7 @@ There is **no dialog, popover, sheet, drawer, alert-dialog, or hover-card compon
|
|
|
200
200
|
<Button loading>Saving…</Button>
|
|
201
201
|
```
|
|
202
202
|
|
|
203
|
-
For icons, use the `leadingIcon` / `trailingIcon` props (or `iconOnly` for an icon-only button)
|
|
203
|
+
For icons, use the `leadingIcon` / `trailingIcon` props (or `iconOnly` for an icon-only button) - never wrap raw `<svg>` children or add sizing classes; the component sizes the icon per `size`.
|
|
204
204
|
|
|
205
205
|
```tsx
|
|
206
206
|
import { RiSearchLine } from "@create-ui/assets/icons"
|
|
@@ -209,13 +209,13 @@ import { RiSearchLine } from "@create-ui/assets/icons"
|
|
|
209
209
|
<Button iconOnly aria-label="Search" leadingIcon={<RiSearchLine />} />
|
|
210
210
|
```
|
|
211
211
|
|
|
212
|
-
Remember the Button API: `variant` is `primary | neutral-solid | neutral-light | danger | success | inverse-solid | inverse-light`, and the outlined/ghost looks come from `appearance` (`solid | outline | ghost | soft`). There is no outline or destructive `variant` value
|
|
212
|
+
Remember the Button API: `variant` is `primary | neutral-solid | neutral-light | danger | success | inverse-solid | inverse-light`, and the outlined/ghost looks come from `appearance` (`solid | outline | ghost | soft`). There is no outline or destructive `variant` value - use `appearance="outline"` for the outlined look and `variant="danger"` for destructive actions. See `rules/styling.md` for the full variant/appearance reference.
|
|
213
213
|
|
|
214
214
|
---
|
|
215
215
|
|
|
216
216
|
## Tabbed navigation uses TabMenu
|
|
217
217
|
|
|
218
|
-
Tabs are the `tab-menu` component
|
|
218
|
+
Tabs are the `tab-menu` component - there is no shadcn-style tabs / tabs-list / tabs-trigger set. `TabMenu` wraps `TabMenuItem`s and owns the selection (`defaultValue`, or controlled `value` / `onValueChange`). It renders the menu only - render the active panel yourself from the value; there is no content component.
|
|
219
219
|
|
|
220
220
|
```tsx
|
|
221
221
|
import { TabMenu, TabMenuItem } from "@/components/ui/tab-menu"
|
|
@@ -234,27 +234,43 @@ const [tab, setTab] = React.useState("overview")
|
|
|
234
234
|
|
|
235
235
|
---
|
|
236
236
|
|
|
237
|
-
## Avatar
|
|
237
|
+
## Avatar composition (AvatarText, not AvatarFallback)
|
|
238
238
|
|
|
239
|
-
|
|
239
|
+
**`AvatarFallback` does not exist in Create UI** - the fallback/initials slot is `AvatarText`. It renders only while the sibling `AvatarImage` has not loaded (or when there is no image), so an image avatar should always carry one:
|
|
240
240
|
|
|
241
241
|
```tsx
|
|
242
|
+
import { Avatar, AvatarImage, AvatarText } from "@/components/ui/avatar"
|
|
243
|
+
|
|
244
|
+
<Avatar>
|
|
245
|
+
<AvatarImage src="/avatar.png" alt="User" />
|
|
246
|
+
<AvatarText>JD</AvatarText>
|
|
247
|
+
</Avatar>
|
|
248
|
+
```
|
|
249
|
+
|
|
250
|
+
Initials-only avatars pick a real color `variant`; presence comes from `AvatarBadge` + `AvatarBadgeStatus`; stacks are `AvatarGroup` (+ `AvatarGroupAction` for the "+5" affordance):
|
|
251
|
+
|
|
252
|
+
```tsx
|
|
253
|
+
<Avatar variant="weak-blue"><AvatarText>YT</AvatarText></Avatar>
|
|
254
|
+
|
|
242
255
|
<Avatar>
|
|
243
256
|
<AvatarImage src="/avatar.png" alt="User" />
|
|
244
|
-
<
|
|
257
|
+
<AvatarText>JD</AvatarText>
|
|
258
|
+
<AvatarBadge><AvatarBadgeStatus variant="online" /></AvatarBadge>
|
|
245
259
|
</Avatar>
|
|
246
260
|
```
|
|
247
261
|
|
|
262
|
+
See `reference/avatar.md` for the full prop tables (`size` `2xs`–`2xl`, `shape`, 55 color variants, `AvatarIcon`, `AvatarRing`).
|
|
263
|
+
|
|
248
264
|
---
|
|
249
265
|
|
|
250
266
|
## Use existing components instead of custom markup
|
|
251
267
|
|
|
252
|
-
If a primitive already covers the job, use it
|
|
268
|
+
If a primitive already covers the job, use it - don't reach for raw elements or utility-class fakes.
|
|
253
269
|
|
|
254
270
|
| Instead of | Use |
|
|
255
271
|
|---|---|
|
|
256
272
|
| `<hr>` or `<div className="border-t">` | `<Separator />` |
|
|
257
273
|
| `<span className="rounded-full bg-green-100 …">` | `<Badge variant="success">Active</Badge>` |
|
|
258
|
-
| A status dot built from a styled `<span>` | `<StatusBadge variant="success" />` (it renders the dot only
|
|
274
|
+
| A status dot built from a styled `<span>` | `<StatusBadge variant="success" />` (it renders the dot only - put the label next to it). `variant`: `primary`, `danger`, `success`, `warning`, `info`, `highlighted`, `away`, `verified`, `cyan`, `lime`, `neutral`, `white` - note `danger`, not `error` |
|
|
259
275
|
| A removable tag built from `<span>` + `<button>` | `<Chip onClose={…}>…</Chip>` |
|
|
260
276
|
| A hand-rolled `animate-spin` loading indicator | `<Spinner />` |
|