@justanarthur/modo-ui 0.6.0-canary.7 → 0.6.0-canary.8
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/DESIGN.md +8 -2
- package/README.md +2 -1
- package/components/AI/input-message/examples.mdx +34 -28
- package/components/AI/input-message/index.tsx +2 -0
- package/components/accordion/examples.mdx +41 -35
- package/components/badge/examples.mdx +30 -26
- package/components/button/examples.mdx +47 -43
- package/components/card/examples.mdx +135 -129
- package/components/copy/examples.mdx +50 -44
- package/components/inputs/checkbox/examples.mdx +34 -30
- package/components/inputs/color-picker/examples.mdx +39 -31
- package/components/inputs/combobox/examples.mdx +135 -125
- package/components/inputs/date-time/date-picker/examples.mdx +107 -97
- package/components/inputs/date-time/date-range-picker/examples.mdx +37 -33
- package/components/inputs/field/examples.mdx +58 -54
- package/components/inputs/file-dropzone/examples.mdx +15 -13
- package/components/inputs/input/examples.mdx +44 -13
- package/components/inputs/number-input/examples.mdx +18 -14
- package/components/inputs/select/examples.mdx +94 -84
- package/components/inputs/slider/examples.mdx +13 -11
- package/components/inputs/switch/examples.mdx +33 -31
- package/components/inputs/textarea/examples.mdx +39 -33
- package/components/navigation/pagination/examples.mdx +22 -16
- package/components/navigation/sidebar/examples.mdx +14 -8
- package/components/navigation/tabs/index.tsx +1 -1
- package/components/overlays/dropdown/examples.mdx +176 -168
- package/components/overlays/popover/examples.mdx +46 -40
- package/components/table/examples.mdx +45 -41
- package/dist/base.css +44 -0
- package/dist/blocks/sidebar-app/index.js +12 -11
- package/dist/components/AI/input-message/index.js +5 -4
- package/dist/components/accordion/index.js +3 -2
- package/dist/components/avatar/index.js +3 -2
- package/dist/components/badge/index.js +3 -2
- package/dist/components/button/index.js +3 -2
- package/dist/components/card/index.js +3 -2
- package/dist/components/copy/index.js +4 -3
- package/dist/components/inputs/checkbox/index.js +3 -2
- package/dist/components/inputs/color-picker/index.js +5 -4
- package/dist/components/inputs/combobox/index.js +5 -4
- package/dist/components/inputs/date-time/calendar/index.js +4 -3
- package/dist/components/inputs/date-time/date-picker/index.js +12 -11
- package/dist/components/inputs/date-time/date-range-picker/index.js +12 -11
- package/dist/components/inputs/date-time/duration-picker/index.js +11 -10
- package/dist/components/inputs/date-time/month-picker/index.js +10 -9
- package/dist/components/inputs/date-time/time-picker/index.js +11 -10
- package/dist/components/inputs/field/index.js +5 -4
- package/dist/components/inputs/file-dropzone/index.js +5 -4
- package/dist/components/inputs/input/index.js +4 -3
- package/dist/components/inputs/number-input/index.js +5 -4
- package/dist/components/inputs/radio/index.js +3 -2
- package/dist/components/inputs/search/index.js +7 -6
- package/dist/components/inputs/select/index.js +5 -4
- package/dist/components/inputs/slider/index.js +3 -2
- package/dist/components/inputs/switch/index.js +3 -2
- package/dist/components/inputs/textarea/index.js +4 -3
- package/dist/components/navigation/navigation-menu/index.js +4 -3
- package/dist/components/navigation/pagination/index.js +9 -8
- package/dist/components/navigation/sidebar/index.js +9 -8
- package/dist/components/navigation/tabs/index.js +3 -2
- package/dist/components/navigation/tabs-subtle/index.js +3 -2
- package/dist/components/overlays/alert-dialog/index.js +5 -4
- package/dist/components/overlays/command/index.js +6 -5
- package/dist/components/overlays/context-menu/index.js +6 -5
- package/dist/components/overlays/dialog/index.js +4 -3
- package/dist/components/overlays/dropdown/index.js +5 -4
- package/dist/components/overlays/popover/index.js +3 -2
- package/dist/components/overlays/preview-card/index.js +3 -2
- package/dist/components/overlays/sheet/index.js +5 -4
- package/dist/components/overlays/toast/index.js +4 -3
- package/dist/components/overlays/tooltip/index.js +3 -2
- package/dist/docs/index.js +11 -10
- package/dist/index.js +56 -55
- package/dist/lib/field-classes.d.ts +6 -1
- package/dist/lib/field-classes.js +3 -2
- package/dist/lib/focus-ring.js +3 -2
- package/dist/lib/scroll-column.js +3 -2
- package/dist/lib/shape-context.js +2 -1
- package/dist/lib/shape-radius.d.ts +19 -0
- package/dist/lib/shape-radius.js +6 -0
- package/dist/preset.d.ts +1 -0
- package/dist/preset.js +1 -0
- package/dist/primitives/code/index.js +4 -3
- package/dist/primitives/craft/index.js +4 -3
- package/dist/primitives/fluid-hover/index.js +3 -2
- package/dist/primitives/morph/index.js +4 -3
- package/dist/primitives/motion/index.js +4 -3
- package/dist/primitives/scroll-area/index.js +3 -2
- package/dist/primitives/skeleton/index.js +3 -2
- package/dist/shared/{components-59my5pwr.js → components-1kab3j44.js} +4 -4
- package/dist/shared/{components-47226105.js → components-2c64r8c9.js} +5 -5
- package/dist/shared/{components-vbh98t9d.js → components-2syq4mwc.js} +3 -3
- package/dist/shared/{components-dg6s5gjg.js → components-3ydr2fqe.js} +3 -3
- package/dist/shared/{components-z9n19fyk.js → components-4nck8acq.js} +1 -1
- package/dist/shared/{components-q4z71n18.js → components-5012r6gr.js} +2 -2
- package/dist/shared/{components-621xezcz.js → components-5sxjeh6h.js} +2 -2
- package/dist/shared/{components-pmfszv7a.js → components-5tzhqbcw.js} +2 -2
- package/dist/shared/{components-60atskhp.js → components-5y5shqfd.js} +1 -1
- package/dist/shared/{components-kr40s3z0.js → components-6b0zb8z3.js} +1 -1
- package/dist/shared/{components-c96k4gfs.js → components-6gk118w3.js} +2 -2
- package/dist/shared/{components-78x40gee.js → components-71nbt03m.js} +14 -1
- package/dist/shared/{components-52ngsgca.js → components-7zkhz3r8.js} +1 -1
- package/dist/shared/{components-02c81nsv.js → components-8mt5bsv6.js} +1 -1
- package/dist/shared/{components-nd1baxp1.js → components-8rb25gbe.js} +2 -2
- package/dist/shared/{components-ep3d57kp.js → components-8v644a0s.js} +4 -4
- package/dist/shared/{components-1edyddfg.js → components-9j9abkct.js} +3 -3
- package/dist/shared/{components-4swzve2d.js → components-9sttq78t.js} +1 -1
- package/dist/shared/{components-2c0qcfx4.js → components-av5t26rc.js} +1 -1
- package/dist/shared/{components-k57dtvgp.js → components-b94t6qtj.js} +3 -3
- package/dist/shared/{components-2z48g4fp.js → components-ctqmge8t.js} +2 -1
- package/dist/shared/{components-vqqapw72.js → components-cwg1d0w6.js} +1 -1
- package/dist/shared/{components-mpw667rb.js → components-dyae0y7h.js} +1 -1
- package/dist/shared/{components-35tmfjtw.js → components-ej4r7wmj.js} +2 -2
- package/dist/shared/{components-bwy8775y.js → components-eqze3y30.js} +5 -3
- package/dist/shared/{components-3qssegme.js → components-fejdzvqc.js} +5 -5
- package/dist/shared/{components-pd42emw3.js → components-ft3zdc79.js} +2 -2
- package/dist/shared/components-gx4h5rbb.js +40 -0
- package/dist/shared/{components-c6cz9nw6.js → components-gyt7my41.js} +3 -3
- package/dist/shared/{components-6zng858q.js → components-hdzrqqpx.js} +3 -1
- package/dist/shared/{components-zj640a90.js → components-jymmaevv.js} +3 -3
- package/dist/shared/{components-aj7f4v4v.js → components-khspp26b.js} +2 -2
- package/dist/shared/{components-b92nqk44.js → components-km7fhgbk.js} +1 -1
- package/dist/shared/{components-y1w3a6wx.js → components-mattt5jp.js} +2 -2
- package/dist/shared/{components-43brg0gv.js → components-mpa2y6x8.js} +4 -4
- package/dist/shared/{components-wktrrb4m.js → components-pt5ftm4p.js} +1 -1
- package/dist/shared/{components-t7c6c4t4.js → components-px2zm7dc.js} +1 -1
- package/dist/shared/{components-v0nz1m4t.js → components-qqcmtrbv.js} +1 -1
- package/dist/shared/{components-0rpek9d8.js → components-r7q1zm7r.js} +2 -2
- package/dist/shared/{components-n155gkhr.js → components-rpw4md2b.js} +2 -2
- package/dist/shared/{components-72w4ge68.js → components-rtadhd9j.js} +1 -1
- package/dist/shared/{components-nv4awn05.js → components-s8yqk2dc.js} +1 -1
- package/dist/shared/{components-wwd363me.js → components-skfd7kff.js} +1 -1
- package/dist/shared/{components-daqy7ydp.js → components-t2a3qmy9.js} +2 -2
- package/dist/shared/{components-030n1m1v.js → components-t50hrswb.js} +2 -2
- package/dist/shared/{components-jkctvwz9.js → components-t5pk5nmc.js} +1 -1
- package/dist/shared/{components-49bsynbw.js → components-vc864c51.js} +1 -1
- package/dist/shared/{components-d7nhksd0.js → components-vkwq2k96.js} +1 -1
- package/dist/shared/{components-64c8kvmt.js → components-w0xq6q9k.js} +3 -3
- package/dist/shared/{components-8nwsqjn8.js → components-wbbckbw8.js} +1 -1
- package/dist/shared/{components-hx4a4cvm.js → components-wqrvqq5p.js} +3 -3
- package/dist/shared/{components-96sd8h9m.js → components-xjkdvnbg.js} +1 -1
- package/dist/shared/{components-hpe3avtw.js → components-xqszvkj4.js} +3 -3
- package/dist/shared/{components-tjtjmjjr.js → components-y1qvbawa.js} +1 -1
- package/dist/shared/{components-9n43qf8y.js → components-z0bqtvcp.js} +5 -5
- package/dist/shared/{components-khcnzj3g.js → components-z6dfqtyt.js} +3 -3
- package/dist/styles.css +46 -1
- package/dist/tailwind.css +1 -0
- package/dist/tokens/colors.css +6 -0
- package/dist/tokens.css +6 -0
- package/lib/field-classes.ts +7 -1
- package/lib/shape-context.tsx +16 -2
- package/lib/shape-radius.ts +67 -0
- package/package.json +8 -2
- package/preset.ts +1 -0
- package/primitives/craft/examples.mdx +22 -18
- package/primitives/morph/examples.mdx +11 -7
- package/primitives/scroll-area/index.tsx +4 -0
package/DESIGN.md
CHANGED
|
@@ -67,6 +67,8 @@ colors:
|
|
|
67
67
|
image-edge-dark: "rgb(255 255 255 / 0.1)"
|
|
68
68
|
progress-track: "color-mix(in oklab, oklch(0.205 0 0) 10%, transparent)"
|
|
69
69
|
progress-track-dark: "color-mix(in oklab, oklch(0.97 0 0) 10%, transparent)"
|
|
70
|
+
well: "oklch(0.967 0.001 286.375)"
|
|
71
|
+
well-dark: "oklch(0 0 0 / 0.25)"
|
|
70
72
|
surface-1: "oklch(0.985 0 0)"
|
|
71
73
|
surface-2: "oklch(0.991 0 0)"
|
|
72
74
|
surface-3: "oklch(1 0 0)"
|
|
@@ -284,7 +286,7 @@ components:
|
|
|
284
286
|
padding: 24px
|
|
285
287
|
width: 400px
|
|
286
288
|
tabs-list:
|
|
287
|
-
backgroundColor: "{colors.
|
|
289
|
+
backgroundColor: "{colors.well}"
|
|
288
290
|
rounded: "{rounded.xl}"
|
|
289
291
|
height: "{spacing.control}"
|
|
290
292
|
padding: 4px
|
|
@@ -357,7 +359,11 @@ Two text colors, a greyscale ground, one blue.
|
|
|
357
359
|
button (until `--primary-foreground` is re-pointed) and the tooltip (`text-background`).
|
|
358
360
|
- **Surfaces (`bg-surface-1` … `bg-surface-8`)** — the elevation ladder (see Elevation & Depth). Prefer a
|
|
359
361
|
surface level over `card`/`background` for anything that floats or nests.
|
|
360
|
-
- **Muted (`bg-muted`)** — a
|
|
362
|
+
- **Muted (`bg-muted`)** — a sunken fill: a field's hover wash, a queued row. In dark it is surface 2, so
|
|
363
|
+
it never carries a track: it would vanish on a card or the inset.
|
|
364
|
+
- **Well (`bg-well`)** — the recessed track under a segmented control's indicator (the tabs list). Light is
|
|
365
|
+
muted; dark is black at 25%, which darkens whatever it sits on, so the track reads on the page, a card
|
|
366
|
+
and the inset alike.
|
|
361
367
|
- **Accent (`bg-accent`)** — the secondary button and the switch's off track. `selected` is a firmer
|
|
362
368
|
grey for persistent selection fills.
|
|
363
369
|
- **Hover / Active (`bg-hover`, `bg-active`)** — translucent overlays (black 4% / 7% in light, white 6% /
|
package/README.md
CHANGED
|
@@ -158,7 +158,8 @@ positioning) are ported.
|
|
|
158
158
|
| `lib/springs.ts` | `lib/springs.ts` | `goo` tier added (the morph engine's goo: 250ms to land, bounce 0.15, a 200ms spring back); `exitFallbackMs` also reads a spring exit's `visualDuration` |
|
|
159
159
|
| `lib/font-weight.ts` | — | not ported: its `fontWeights` became the `--weight-*` tokens in `tokens/typography.css` (the `weight-*` utilities) |
|
|
160
160
|
| `lib/popup.ts` | `lib/popup.ts` | `popupMotionClass` dropped (unused since the popups morph) |
|
|
161
|
-
| `lib/shape-context.tsx` | `lib/shape-context.tsx` | `"use client"` dropped |
|
|
161
|
+
| `lib/shape-context.tsx` | `lib/shape-context.tsx` | `"use client"` dropped; `--shape-input-radius` is published through `claimShapeRadius` and given back on unmount |
|
|
162
|
+
| — (new) | `lib/shape-radius.ts` | Local addition: the stack of `ShapeProvider` claims on `--shape-input-radius` (`<html>`), so an unmounting provider restores the one below it or the page's own value; plain data, tested without a DOM |
|
|
162
163
|
| `lib/size-context.tsx` | `lib/size-context.tsx` | `"use client"` dropped; `SizeProvider` moved to `primitives/sizes` (the documented item), with `SizeContext` exported for it; `sizeMap`, `typeScale` and their types moved to `size-scale.ts` and re-exported |
|
|
163
164
|
| `lib/size-context.tsx` (`sizeMap`, `typeScale`) | `lib/size-scale.ts` | The ladder's plain data, split out so server code can read it (no JSX, hooks or contexts); `sizeMap` text classes → `text-body` / `text-body-compact` |
|
|
164
165
|
| `lib/icon-context.tsx` | `lib/icon-context.tsx` | `"use client"` dropped; `size`/`strokeWidth` widened to `number \| string` for lucide v1 + React 18 types |
|
|
@@ -2,7 +2,9 @@ import InputMessage from './index'
|
|
|
2
2
|
import Button from '../../button'
|
|
3
3
|
import { ChevronDown, Plus } from 'lucide-react'
|
|
4
4
|
|
|
5
|
-
#
|
|
5
|
+
# Basics
|
|
6
|
+
|
|
7
|
+
## Basic
|
|
6
8
|
|
|
7
9
|
No props at all: the composer keeps its own draft, grows as you type and
|
|
8
10
|
clears itself on Enter.
|
|
@@ -11,7 +13,31 @@ clears itself on Enter.
|
|
|
11
13
|
<InputMessage />
|
|
12
14
|
</div>
|
|
13
15
|
|
|
14
|
-
|
|
16
|
+
## Send Handler
|
|
17
|
+
|
|
18
|
+
`onSend` receives the trimmed text and the attached files; an uncontrolled
|
|
19
|
+
composer clears its own draft afterwards. The handler here is an empty
|
|
20
|
+
arrow — in an app it is where the message joins the transcript.
|
|
21
|
+
|
|
22
|
+
<div className="w-full max-w-xl">
|
|
23
|
+
<InputMessage
|
|
24
|
+
onSend={() => {}}
|
|
25
|
+
placeholder="Press Enter to send. Shift+Enter for newline."
|
|
26
|
+
/>
|
|
27
|
+
</div>
|
|
28
|
+
|
|
29
|
+
## Disabled
|
|
30
|
+
|
|
31
|
+
Dims the panel to 50% and drops pointer events — textarea, send button and
|
|
32
|
+
drag-and-drop all go inert.
|
|
33
|
+
|
|
34
|
+
<div className="w-full max-w-xl">
|
|
35
|
+
<InputMessage defaultValue="This composer is disabled" disabled />
|
|
36
|
+
</div>
|
|
37
|
+
|
|
38
|
+
# Content
|
|
39
|
+
|
|
40
|
+
## Suggestions
|
|
15
41
|
|
|
16
42
|
The ghost placeholder renders with a Tab keycap — Tab fills it into the
|
|
17
43
|
composer. ArrowDown/ArrowUp walk the list below (focus stays in the
|
|
@@ -30,7 +56,7 @@ shows a ↓ hint until a row is highlighted. Typing collapses the list.
|
|
|
30
56
|
/>
|
|
31
57
|
</div>
|
|
32
58
|
|
|
33
|
-
|
|
59
|
+
## Attachments
|
|
34
60
|
|
|
35
61
|
`defaultFiles` seeds the composer and turns attachment behavior on: drop a
|
|
36
62
|
PNG, JPEG or PDF anywhere on the panel, or use the render-fn slot's
|
|
@@ -52,7 +78,7 @@ for its × button.
|
|
|
52
78
|
/>
|
|
53
79
|
</div>
|
|
54
80
|
|
|
55
|
-
|
|
81
|
+
## Queued messages
|
|
56
82
|
|
|
57
83
|
`defaultStatus="streaming"` plus `defaultQueue` runs the composer as if a
|
|
58
84
|
response were in flight: the send button is a Queue action, so a typed
|
|
@@ -71,7 +97,9 @@ response, and that streaming→idle edge dispatches the row at the top.
|
|
|
71
97
|
/>
|
|
72
98
|
</div>
|
|
73
99
|
|
|
74
|
-
#
|
|
100
|
+
# Slots
|
|
101
|
+
|
|
102
|
+
## Left Slot Only
|
|
75
103
|
|
|
76
104
|
`leftSlot` takes the bottom-left action area — an attach button, a model
|
|
77
105
|
switcher, a mode toggle.
|
|
@@ -86,7 +114,7 @@ switcher, a mode toggle.
|
|
|
86
114
|
/>
|
|
87
115
|
</div>
|
|
88
116
|
|
|
89
|
-
|
|
117
|
+
## Right Slot Only
|
|
90
118
|
|
|
91
119
|
`rightSlot` sits in the bottom-right, just before the built-in send
|
|
92
120
|
button.
|
|
@@ -100,25 +128,3 @@ button.
|
|
|
100
128
|
}
|
|
101
129
|
/>
|
|
102
130
|
</div>
|
|
103
|
-
|
|
104
|
-
# Send Handler
|
|
105
|
-
|
|
106
|
-
`onSend` receives the trimmed text and the attached files; an uncontrolled
|
|
107
|
-
composer clears its own draft afterwards. The handler here is an empty
|
|
108
|
-
arrow — in an app it is where the message joins the transcript.
|
|
109
|
-
|
|
110
|
-
<div className="w-full max-w-xl">
|
|
111
|
-
<InputMessage
|
|
112
|
-
onSend={() => {}}
|
|
113
|
-
placeholder="Press Enter to send. Shift+Enter for newline."
|
|
114
|
-
/>
|
|
115
|
-
</div>
|
|
116
|
-
|
|
117
|
-
# Disabled
|
|
118
|
-
|
|
119
|
-
Dims the panel to 50% and drops pointer events — textarea, send button and
|
|
120
|
-
drag-and-drop all go inert.
|
|
121
|
-
|
|
122
|
-
<div className="w-full max-w-xl">
|
|
123
|
-
<InputMessage defaultValue="This composer is disabled" disabled />
|
|
124
|
-
</div>
|
|
@@ -924,6 +924,8 @@ const InputMessage = forwardRef<HTMLDivElement, InputMessageProps>(
|
|
|
924
924
|
if (!clickToFocus || disabled) return
|
|
925
925
|
const target = e.target as HTMLElement
|
|
926
926
|
if (target === textareaRef.current) return
|
|
927
|
+
// A press in a popup portalled out of the box reaches it through the React tree only.
|
|
928
|
+
if (!e.currentTarget.contains(target)) return
|
|
927
929
|
if (target.closest('button, a, input, select, textarea, [contenteditable], [role="button"], [data-im-queue]')) {
|
|
928
930
|
return
|
|
929
931
|
}
|
|
@@ -2,7 +2,9 @@ import Accordion from './index'
|
|
|
2
2
|
import Button from '../button'
|
|
3
3
|
import { ArrowRight } from 'lucide-react'
|
|
4
4
|
|
|
5
|
-
#
|
|
5
|
+
# Basics
|
|
6
|
+
|
|
7
|
+
## Standalone
|
|
6
8
|
|
|
7
9
|
A single collapsible item with its own hover state.
|
|
8
10
|
|
|
@@ -15,7 +17,7 @@ A single collapsible item with its own hover state.
|
|
|
15
17
|
</Accordion.Item>
|
|
16
18
|
</Accordion>
|
|
17
19
|
|
|
18
|
-
|
|
20
|
+
## Single Expand
|
|
19
21
|
|
|
20
22
|
Multiple items with fluid hover — only one can be expanded at a time.
|
|
21
23
|
|
|
@@ -50,7 +52,7 @@ Multiple items with fluid hover — only one can be expanded at a time.
|
|
|
50
52
|
</Accordion.Item>
|
|
51
53
|
</Accordion.Group>
|
|
52
54
|
|
|
53
|
-
|
|
55
|
+
## Multi Expand
|
|
54
56
|
|
|
55
57
|
Multiple items with fluid hover — several can be expanded at once.
|
|
56
58
|
|
|
@@ -75,34 +77,7 @@ Multiple items with fluid hover — several can be expanded at once.
|
|
|
75
77
|
</Accordion.Item>
|
|
76
78
|
</Accordion.Group>
|
|
77
79
|
|
|
78
|
-
|
|
79
|
-
|
|
80
|
-
With `highlight="trigger"` an expanded item holds no tint — the fill
|
|
81
|
-
scopes to the row and waits for hover. Suits dense panels, where a block
|
|
82
|
-
per open item reads as a second layer.
|
|
83
|
-
|
|
84
|
-
<Accordion.Group type="single" collapsible defaultValue="item-1" highlight="trigger">
|
|
85
|
-
<Accordion.Item value="item-1" index={0}>
|
|
86
|
-
<Accordion.Trigger>Expanded, but not tinted</Accordion.Trigger>
|
|
87
|
-
<Accordion.Content>
|
|
88
|
-
The panel reads as part of the page rather than a filled block.
|
|
89
|
-
</Accordion.Content>
|
|
90
|
-
</Accordion.Item>
|
|
91
|
-
<Accordion.Item value="item-2" index={1}>
|
|
92
|
-
<Accordion.Trigger>Hover any row</Accordion.Trigger>
|
|
93
|
-
<Accordion.Content>
|
|
94
|
-
The fill follows your cursor instead of marking a state.
|
|
95
|
-
</Accordion.Content>
|
|
96
|
-
</Accordion.Item>
|
|
97
|
-
<Accordion.Item value="item-3" index={2}>
|
|
98
|
-
<Accordion.Trigger>Compare with the sections above</Accordion.Trigger>
|
|
99
|
-
<Accordion.Content>
|
|
100
|
-
Those hold a block across the row and its panel while open.
|
|
101
|
-
</Accordion.Content>
|
|
102
|
-
</Accordion.Item>
|
|
103
|
-
</Accordion.Group>
|
|
104
|
-
|
|
105
|
-
# Morph
|
|
80
|
+
## Morph
|
|
106
81
|
|
|
107
82
|
Each panel drips out of the row where it was pressed (its middle, from the keyboard) and widens into the item, its content revealed by the same shape; closing folds it back into the row. The rows below ride its bottom edge.
|
|
108
83
|
|
|
@@ -130,7 +105,36 @@ Each panel drips out of the row where it was pressed (its middle, from the keybo
|
|
|
130
105
|
</Accordion.Item>
|
|
131
106
|
</Accordion.Group>
|
|
132
107
|
|
|
133
|
-
#
|
|
108
|
+
# Variants
|
|
109
|
+
|
|
110
|
+
## Row highlight
|
|
111
|
+
|
|
112
|
+
With `highlight="trigger"` an expanded item holds no tint — the fill
|
|
113
|
+
scopes to the row and waits for hover. Suits dense panels, where a block
|
|
114
|
+
per open item reads as a second layer.
|
|
115
|
+
|
|
116
|
+
<Accordion.Group type="single" collapsible defaultValue="item-1" highlight="trigger">
|
|
117
|
+
<Accordion.Item value="item-1" index={0}>
|
|
118
|
+
<Accordion.Trigger>Expanded, but not tinted</Accordion.Trigger>
|
|
119
|
+
<Accordion.Content>
|
|
120
|
+
The panel reads as part of the page rather than a filled block.
|
|
121
|
+
</Accordion.Content>
|
|
122
|
+
</Accordion.Item>
|
|
123
|
+
<Accordion.Item value="item-2" index={1}>
|
|
124
|
+
<Accordion.Trigger>Hover any row</Accordion.Trigger>
|
|
125
|
+
<Accordion.Content>
|
|
126
|
+
The fill follows your cursor instead of marking a state.
|
|
127
|
+
</Accordion.Content>
|
|
128
|
+
</Accordion.Item>
|
|
129
|
+
<Accordion.Item value="item-3" index={2}>
|
|
130
|
+
<Accordion.Trigger>Compare with the sections above</Accordion.Trigger>
|
|
131
|
+
<Accordion.Content>
|
|
132
|
+
Those hold a block across the row and its panel while open.
|
|
133
|
+
</Accordion.Content>
|
|
134
|
+
</Accordion.Item>
|
|
135
|
+
</Accordion.Group>
|
|
136
|
+
|
|
137
|
+
## Without the goo
|
|
134
138
|
|
|
135
139
|
`effect="morph"` grows the same shape with no liquid neck to its row; `tier="moderate"` runs the goo on the quicker, critically damped spring.
|
|
136
140
|
|
|
@@ -149,7 +153,7 @@ Each panel drips out of the row where it was pressed (its middle, from the keybo
|
|
|
149
153
|
</Accordion.Item>
|
|
150
154
|
</Accordion.Group>
|
|
151
155
|
|
|
152
|
-
|
|
156
|
+
## Without the chevron
|
|
153
157
|
|
|
154
158
|
`icon={false}` drops the glyph at the row's end, for a row whose own content says it opens. A component passed as `icon` replaces the chevron and turns a quarter turn on open, so give it a right-pointing glyph.
|
|
155
159
|
|
|
@@ -174,7 +178,9 @@ Each panel drips out of the row where it was pressed (its middle, from the keybo
|
|
|
174
178
|
</Accordion.Item>
|
|
175
179
|
</Accordion.Group>
|
|
176
180
|
|
|
177
|
-
#
|
|
181
|
+
# Composition
|
|
182
|
+
|
|
183
|
+
## Rich headers
|
|
178
184
|
|
|
179
185
|
By default the trigger renders its label twice: a hidden semibold copy reserves the width, so the label gets heavier on open without moving. A header made of components would be duplicated in the DOM, so `weightShift={false}` renders it once and leaves the weight to its content. `contentClassName` is merged over the inner row's inset, padding and muted body text: the first panel below turns its text to full strength, the second takes a wider inset and the caption size. The label lives inside the trigger `<button>`, so build it from phrasing content (spans, as below), never a `div`-based header. Text that fixes its own colour stays that colour when the item opens: the chevron, the highlight and the open tint are what signal the state.
|
|
180
186
|
|
|
@@ -203,7 +209,7 @@ By default the trigger renders its label twice: a hidden semibold copy reserves
|
|
|
203
209
|
</Accordion.Item>
|
|
204
210
|
</Accordion.Group>
|
|
205
211
|
|
|
206
|
-
|
|
212
|
+
## Your own trigger
|
|
207
213
|
|
|
208
214
|
`asChild` (or `render`) makes your element the trigger, so a Button, a link-styled control or anything else can open the item. It is rendered as it is: the row's label copy, the chevron and the row padding are not added, so the element brings its own content and look. Base UI still wires `aria-expanded`, `aria-controls`, `data-panel-open` and the keys onto it, so style the open state with `data-[panel-open]`.
|
|
209
215
|
|
|
@@ -1,7 +1,9 @@
|
|
|
1
1
|
import Badge from './index'
|
|
2
2
|
import ChangeDemo from './change-demo'
|
|
3
3
|
|
|
4
|
-
#
|
|
4
|
+
# Variants
|
|
5
|
+
|
|
6
|
+
## Solid
|
|
5
7
|
|
|
6
8
|
The default variant: a tinted background in the badge's color.
|
|
7
9
|
|
|
@@ -13,7 +15,7 @@ The default variant: a tinted background in the badge's color.
|
|
|
13
15
|
<Badge color="rose">Poetry</Badge>
|
|
14
16
|
</div>
|
|
15
17
|
|
|
16
|
-
|
|
18
|
+
## Dot
|
|
17
19
|
|
|
18
20
|
`variant="dot"` keeps a neutral bordered badge and shows the color as an
|
|
19
21
|
indicator dot.
|
|
@@ -26,7 +28,7 @@ indicator dot.
|
|
|
26
28
|
<Badge variant="dot" color="rose">Poetry</Badge>
|
|
27
29
|
</div>
|
|
28
30
|
|
|
29
|
-
|
|
31
|
+
## Outline
|
|
30
32
|
|
|
31
33
|
`variant="outline"` is the dot badge's neutral frame without the dot: a label
|
|
32
34
|
that carries no status.
|
|
@@ -37,22 +39,7 @@ that carries no status.
|
|
|
37
39
|
<Badge variant="outline" size="compact">Archived</Badge>
|
|
38
40
|
</div>
|
|
39
41
|
|
|
40
|
-
|
|
41
|
-
|
|
42
|
-
Hosts with a shadcn-style badge map its variants onto a hue: default and
|
|
43
|
-
secondary → `gray`, destructive → `red`, success → `green`, outline →
|
|
44
|
-
`variant="outline"`. The tint stays a wash with foreground text, never a solid
|
|
45
|
-
fill.
|
|
46
|
-
|
|
47
|
-
<div className="flex flex-wrap items-center gap-2">
|
|
48
|
-
<Badge color="gray">Default</Badge>
|
|
49
|
-
<Badge color="gray">Secondary</Badge>
|
|
50
|
-
<Badge color="red">Destructive</Badge>
|
|
51
|
-
<Badge color="green">Success</Badge>
|
|
52
|
-
<Badge variant="outline">Outline</Badge>
|
|
53
|
-
</div>
|
|
54
|
-
|
|
55
|
-
# Colors
|
|
42
|
+
## Colors
|
|
56
43
|
|
|
57
44
|
All seventeen palette colors, solid and dot.
|
|
58
45
|
|
|
@@ -73,18 +60,24 @@ All seventeen palette colors, solid and dot.
|
|
|
73
60
|
</div>
|
|
74
61
|
</div>
|
|
75
62
|
|
|
76
|
-
#
|
|
63
|
+
# Usage
|
|
77
64
|
|
|
78
|
-
|
|
79
|
-
|
|
65
|
+
## Status mapping
|
|
66
|
+
|
|
67
|
+
Hosts with a shadcn-style badge map its variants onto a hue: default and
|
|
68
|
+
secondary → `gray`, destructive → `red`, success → `green`, outline →
|
|
69
|
+
`variant="outline"`. The tint stays a wash with foreground text, never a solid
|
|
70
|
+
fill.
|
|
80
71
|
|
|
81
72
|
<div className="flex flex-wrap items-center gap-2">
|
|
82
|
-
<Badge
|
|
83
|
-
<Badge
|
|
84
|
-
<Badge
|
|
73
|
+
<Badge color="gray">Default</Badge>
|
|
74
|
+
<Badge color="gray">Secondary</Badge>
|
|
75
|
+
<Badge color="red">Destructive</Badge>
|
|
76
|
+
<Badge color="green">Success</Badge>
|
|
77
|
+
<Badge variant="outline">Outline</Badge>
|
|
85
78
|
</div>
|
|
86
79
|
|
|
87
|
-
|
|
80
|
+
## Changes
|
|
88
81
|
|
|
89
82
|
Press a button. A new label springs the badge to its new width while the
|
|
90
83
|
text crossfades, a new color fades in, and the dot slides in or out with
|
|
@@ -118,3 +111,14 @@ the variant. `ChangeDemo` is a docs stage: a Badge that steps through its
|
|
|
118
111
|
]}
|
|
119
112
|
/>
|
|
120
113
|
</div>
|
|
114
|
+
|
|
115
|
+
## Compact
|
|
116
|
+
|
|
117
|
+
`size="compact"` steps the badge down the size ladder (20px tall, 11px
|
|
118
|
+
text) for dense rows and table cells.
|
|
119
|
+
|
|
120
|
+
<div className="flex flex-wrap items-center gap-2">
|
|
121
|
+
<Badge size="compact" color="blue">History</Badge>
|
|
122
|
+
<Badge size="compact" variant="dot" color="green">Philosophy</Badge>
|
|
123
|
+
<Badge size="compact">Draft</Badge>
|
|
124
|
+
</div>
|
|
@@ -22,7 +22,7 @@ to its container.
|
|
|
22
22
|
</div>
|
|
23
23
|
</div>
|
|
24
24
|
|
|
25
|
-
|
|
25
|
+
## Destructive and success
|
|
26
26
|
|
|
27
27
|
A status as an action: its hue as the label on a wash of itself, deepening on
|
|
28
28
|
hover and press. Never a solid fill, so the view keeps one primary.
|
|
@@ -34,7 +34,7 @@ hover and press. Never a solid fill, so the view keeps one primary.
|
|
|
34
34
|
<Button variant="success" size="compact">Accept</Button>
|
|
35
35
|
</div>
|
|
36
36
|
|
|
37
|
-
|
|
37
|
+
## Outline and link
|
|
38
38
|
|
|
39
39
|
`outline` is `tertiary` under its shadcn name. `link` is text on the control
|
|
40
40
|
height: its underline fades in on hover, so the label never moves, and it
|
|
@@ -46,20 +46,36 @@ lines up with the buttons beside it.
|
|
|
46
46
|
<Button variant="link" trailingIcon={ArrowRight}>View all</Button>
|
|
47
47
|
</div>
|
|
48
48
|
|
|
49
|
-
#
|
|
49
|
+
# Sizes
|
|
50
50
|
|
|
51
|
-
`
|
|
52
|
-
|
|
51
|
+
The size ladder: `default` (36px) and `compact` (28px), plus square
|
|
52
|
+
icon-only steps. There is no third height: `xs` and `sm` resolve to `compact`. Icon-only buttons take the icon as their child and need
|
|
53
|
+
an `aria-label`.
|
|
53
54
|
|
|
54
|
-
<div className="flex flex-
|
|
55
|
-
<
|
|
56
|
-
|
|
57
|
-
|
|
58
|
-
|
|
59
|
-
|
|
55
|
+
<div className="flex flex-col gap-3">
|
|
56
|
+
<div className="flex flex-wrap items-center gap-2">
|
|
57
|
+
<Button leadingIcon={Plus}>Default</Button>
|
|
58
|
+
<Button variant="secondary" size="icon" aria-label="Add">
|
|
59
|
+
<Plus />
|
|
60
|
+
</Button>
|
|
61
|
+
<Button variant="ghost" size="icon" aria-label="Settings">
|
|
62
|
+
<Settings />
|
|
63
|
+
</Button>
|
|
64
|
+
</div>
|
|
65
|
+
<div className="flex flex-wrap items-center gap-2">
|
|
66
|
+
<Button size="compact" leadingIcon={Plus}>Compact</Button>
|
|
67
|
+
<Button variant="secondary" size="icon-compact" aria-label="Add">
|
|
68
|
+
<Plus />
|
|
69
|
+
</Button>
|
|
70
|
+
<Button variant="ghost" size="icon-compact" aria-label="Settings">
|
|
71
|
+
<Settings />
|
|
72
|
+
</Button>
|
|
73
|
+
</div>
|
|
60
74
|
</div>
|
|
61
75
|
|
|
62
|
-
#
|
|
76
|
+
# States
|
|
77
|
+
|
|
78
|
+
## Loading & Disabled
|
|
63
79
|
|
|
64
80
|
`loading` folds the surface into a circle around a spinner and disables
|
|
65
81
|
the button; the hidden label keeps its width.
|
|
@@ -70,7 +86,7 @@ the button; the hidden label keeps its width.
|
|
|
70
86
|
<Button disabled>Disabled</Button>
|
|
71
87
|
</div>
|
|
72
88
|
|
|
73
|
-
|
|
89
|
+
## Loading morph
|
|
74
90
|
|
|
75
91
|
Press one. The surface folds into a circle around the spinner while the
|
|
76
92
|
button keeps its box, so its neighbors never move, and springs back when
|
|
@@ -91,34 +107,7 @@ Button whose `loading` holds for two seconds after a press.
|
|
|
91
107
|
<LoadingDemo className="w-full">Create account</LoadingDemo>
|
|
92
108
|
</div>
|
|
93
109
|
|
|
94
|
-
|
|
95
|
-
|
|
96
|
-
The size ladder: `default` (36px) and `compact` (28px), plus square
|
|
97
|
-
icon-only steps. There is no third height: `xs` and `sm` resolve to `compact`. Icon-only buttons take the icon as their child and need
|
|
98
|
-
an `aria-label`.
|
|
99
|
-
|
|
100
|
-
<div className="flex flex-col gap-3">
|
|
101
|
-
<div className="flex flex-wrap items-center gap-2">
|
|
102
|
-
<Button leadingIcon={Plus}>Default</Button>
|
|
103
|
-
<Button variant="secondary" size="icon" aria-label="Add">
|
|
104
|
-
<Plus />
|
|
105
|
-
</Button>
|
|
106
|
-
<Button variant="ghost" size="icon" aria-label="Settings">
|
|
107
|
-
<Settings />
|
|
108
|
-
</Button>
|
|
109
|
-
</div>
|
|
110
|
-
<div className="flex flex-wrap items-center gap-2">
|
|
111
|
-
<Button size="compact" leadingIcon={Plus}>Compact</Button>
|
|
112
|
-
<Button variant="secondary" size="icon-compact" aria-label="Add">
|
|
113
|
-
<Plus />
|
|
114
|
-
</Button>
|
|
115
|
-
<Button variant="ghost" size="icon-compact" aria-label="Settings">
|
|
116
|
-
<Settings />
|
|
117
|
-
</Button>
|
|
118
|
-
</div>
|
|
119
|
-
</div>
|
|
120
|
-
|
|
121
|
-
# Active
|
|
110
|
+
## Active
|
|
122
111
|
|
|
123
112
|
`active` forces the pressed visual — for a button whose dropdown or
|
|
124
113
|
popover is currently open.
|
|
@@ -130,7 +119,22 @@ popover is currently open.
|
|
|
130
119
|
<Button variant="ghost" active>Ghost</Button>
|
|
131
120
|
</div>
|
|
132
121
|
|
|
133
|
-
#
|
|
122
|
+
# Composition
|
|
123
|
+
|
|
124
|
+
## With Icons
|
|
125
|
+
|
|
126
|
+
`leadingIcon` and `trailingIcon` take an icon component; it sits 4px
|
|
127
|
+
closer to its edge than the label would.
|
|
128
|
+
|
|
129
|
+
<div className="flex flex-wrap items-center gap-2">
|
|
130
|
+
<Button leadingIcon={Plus}>Create</Button>
|
|
131
|
+
<Button variant="secondary" trailingIcon={ArrowRight}>Next</Button>
|
|
132
|
+
<Button variant="tertiary" leadingIcon={Search} trailingIcon={ArrowRight}>
|
|
133
|
+
Search
|
|
134
|
+
</Button>
|
|
135
|
+
</div>
|
|
136
|
+
|
|
137
|
+
## As child
|
|
134
138
|
|
|
135
139
|
`asChild` merges the button's styling onto its single child element —
|
|
136
140
|
here a link — instead of rendering a `<button>`.
|
|
@@ -141,7 +145,7 @@ here a link — instead of rendering a `<button>`.
|
|
|
141
145
|
</a>
|
|
142
146
|
</Button>
|
|
143
147
|
|
|
144
|
-
|
|
148
|
+
## Surface classes
|
|
145
149
|
|
|
146
150
|
For an element you can't render through `asChild` (a router's link that
|
|
147
151
|
builds its own anchor, markup from a server template), `buttonVariants`
|