@justanarthur/modo-ui 0.6.0-canary.7 → 0.6.0-canary.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.
Files changed (172) hide show
  1. package/DESIGN.md +8 -2
  2. package/README.md +2 -1
  3. package/components/AI/input-message/examples.mdx +34 -28
  4. package/components/AI/input-message/index.tsx +2 -0
  5. package/components/accordion/examples.mdx +41 -35
  6. package/components/badge/examples.mdx +30 -26
  7. package/components/button/examples.mdx +47 -43
  8. package/components/card/examples.mdx +135 -129
  9. package/components/copy/examples.mdx +50 -44
  10. package/components/inputs/checkbox/examples.mdx +34 -30
  11. package/components/inputs/color-picker/examples.mdx +39 -31
  12. package/components/inputs/combobox/examples.mdx +135 -125
  13. package/components/inputs/date-time/date-picker/examples.mdx +107 -97
  14. package/components/inputs/date-time/date-range-picker/examples.mdx +37 -33
  15. package/components/inputs/field/examples.mdx +58 -54
  16. package/components/inputs/file-dropzone/examples.mdx +15 -13
  17. package/components/inputs/input/examples.mdx +44 -13
  18. package/components/inputs/number-input/examples.mdx +18 -14
  19. package/components/inputs/select/examples.mdx +94 -84
  20. package/components/inputs/slider/examples.mdx +13 -11
  21. package/components/inputs/switch/examples.mdx +33 -31
  22. package/components/inputs/textarea/examples.mdx +39 -33
  23. package/components/navigation/pagination/examples.mdx +22 -16
  24. package/components/navigation/sidebar/examples.mdx +14 -8
  25. package/components/navigation/tabs/index.tsx +1 -1
  26. package/components/overlays/dropdown/examples.mdx +176 -168
  27. package/components/overlays/popover/examples.mdx +46 -40
  28. package/components/table/examples.mdx +45 -41
  29. package/dist/base.css +44 -0
  30. package/dist/blocks/sidebar-app/index.js +17 -16
  31. package/dist/components/AI/input-message/index.js +9 -8
  32. package/dist/components/AI/thinking-indicator/index.js +3 -3
  33. package/dist/components/accordion/index.js +7 -6
  34. package/dist/components/avatar/index.js +3 -2
  35. package/dist/components/badge/index.js +3 -2
  36. package/dist/components/button/index.js +3 -2
  37. package/dist/components/card/index.js +6 -5
  38. package/dist/components/copy/index.js +6 -5
  39. package/dist/components/inputs/checkbox/index.js +7 -6
  40. package/dist/components/inputs/color-picker/index.js +9 -8
  41. package/dist/components/inputs/combobox/index.js +10 -9
  42. package/dist/components/inputs/date-time/calendar/index.js +7 -6
  43. package/dist/components/inputs/date-time/date-picker/index.js +16 -15
  44. package/dist/components/inputs/date-time/date-range-picker/index.js +16 -15
  45. package/dist/components/inputs/date-time/duration-picker/index.js +15 -14
  46. package/dist/components/inputs/date-time/month-picker/index.js +14 -13
  47. package/dist/components/inputs/date-time/time-picker/index.js +15 -14
  48. package/dist/components/inputs/field/index.js +5 -4
  49. package/dist/components/inputs/file-dropzone/index.js +5 -4
  50. package/dist/components/inputs/input/index.js +4 -3
  51. package/dist/components/inputs/number-input/index.js +5 -4
  52. package/dist/components/inputs/radio/index.js +6 -5
  53. package/dist/components/inputs/search/index.js +11 -10
  54. package/dist/components/inputs/select/index.js +9 -8
  55. package/dist/components/inputs/slider/index.js +3 -2
  56. package/dist/components/inputs/switch/index.js +6 -5
  57. package/dist/components/inputs/textarea/index.js +4 -3
  58. package/dist/components/navigation/navigation-menu/index.js +8 -7
  59. package/dist/components/navigation/pagination/index.js +13 -12
  60. package/dist/components/navigation/sidebar/index.js +13 -12
  61. package/dist/components/navigation/tabs/index.js +5 -4
  62. package/dist/components/navigation/tabs-subtle/index.js +5 -4
  63. package/dist/components/overlays/alert-dialog/index.js +7 -6
  64. package/dist/components/overlays/command/index.js +10 -9
  65. package/dist/components/overlays/context-menu/index.js +11 -10
  66. package/dist/components/overlays/dialog/index.js +6 -5
  67. package/dist/components/overlays/dropdown/index.js +10 -9
  68. package/dist/components/overlays/popover/index.js +5 -4
  69. package/dist/components/overlays/preview-card/index.js +5 -4
  70. package/dist/components/overlays/sheet/index.js +7 -6
  71. package/dist/components/overlays/toast/index.js +6 -5
  72. package/dist/components/overlays/tooltip/index.js +5 -4
  73. package/dist/components/table/index.js +4 -4
  74. package/dist/docs/index.js +15 -14
  75. package/dist/index.js +63 -62
  76. package/dist/lib/field-classes.d.ts +6 -1
  77. package/dist/lib/field-classes.js +3 -2
  78. package/dist/lib/fluid-hover-highlight.js +3 -3
  79. package/dist/lib/focus-ring.js +3 -2
  80. package/dist/lib/goo-indicator.js +2 -2
  81. package/dist/lib/morph-layers.js +2 -2
  82. package/dist/lib/scroll-column.js +6 -5
  83. package/dist/lib/shape-context.js +2 -1
  84. package/dist/lib/shape-radius.d.ts +19 -0
  85. package/dist/lib/shape-radius.js +6 -0
  86. package/dist/lib/use-merge-split.js +3 -3
  87. package/dist/lib/use-morph.js +1 -1
  88. package/dist/preset.d.ts +1 -0
  89. package/dist/preset.js +1 -0
  90. package/dist/primitives/code/index.js +4 -3
  91. package/dist/primitives/craft/index.js +4 -3
  92. package/dist/primitives/fluid-hover/index.js +6 -5
  93. package/dist/primitives/morph/index.js +6 -5
  94. package/dist/primitives/motion/index.js +4 -3
  95. package/dist/primitives/scroll-area/index.js +3 -2
  96. package/dist/primitives/skeleton/index.js +3 -2
  97. package/dist/shared/{components-q4z71n18.js → components-005jt2nz.js} +4 -4
  98. package/dist/shared/{components-43brg0gv.js → components-01w9qcfa.js} +4 -4
  99. package/dist/shared/{components-v0nz1m4t.js → components-0h78g3b5.js} +2 -2
  100. package/dist/shared/{components-47226105.js → components-1e64t8aj.js} +5 -5
  101. package/dist/shared/{components-nd1baxp1.js → components-2a7hcand.js} +4 -4
  102. package/dist/shared/{components-vqqapw72.js → components-2krsc300.js} +3 -3
  103. package/dist/shared/{components-khcnzj3g.js → components-2qbqqpgq.js} +7 -7
  104. package/dist/shared/{components-vbh98t9d.js → components-303jf96s.js} +6 -6
  105. package/dist/shared/{components-c96k4gfs.js → components-4j3t39dd.js} +4 -4
  106. package/dist/shared/{components-z9n19fyk.js → components-4nck8acq.js} +1 -1
  107. package/dist/shared/{components-78x40gee.js → components-71nbt03m.js} +14 -1
  108. package/dist/shared/{components-pmfszv7a.js → components-7qx17na9.js} +3 -3
  109. package/dist/shared/{components-52ngsgca.js → components-868v7scv.js} +3 -3
  110. package/dist/shared/{components-3qssegme.js → components-8jrk5eye.js} +7 -7
  111. package/dist/shared/{components-1edyddfg.js → components-91zw3d9f.js} +3 -3
  112. package/dist/shared/{components-02c81nsv.js → components-9jmjnkqd.js} +2 -2
  113. package/dist/shared/{components-4swzve2d.js → components-9sttq78t.js} +1 -1
  114. package/dist/shared/{components-k57dtvgp.js → components-b94t6qtj.js} +3 -3
  115. package/dist/shared/{components-qs4rkqsj.js → components-bae8sbjx.js} +2 -2
  116. package/dist/shared/{components-n155gkhr.js → components-bsqynhaj.js} +2 -2
  117. package/dist/shared/{components-dg6s5gjg.js → components-c5w5zk0s.js} +6 -6
  118. package/dist/shared/{components-daqy7ydp.js → components-c74gf16d.js} +2 -2
  119. package/dist/shared/{components-4y816hwp.js → components-c7rwx0ap.js} +1 -1
  120. package/dist/shared/{components-aj7f4v4v.js → components-cet3jpa0.js} +4 -4
  121. package/dist/shared/{components-b92nqk44.js → components-cnead5qm.js} +3 -3
  122. package/dist/shared/{components-2z48g4fp.js → components-ctqmge8t.js} +2 -1
  123. package/dist/shared/{components-030n1m1v.js → components-czdvj1a8.js} +4 -4
  124. package/dist/shared/{components-qdm3yh26.js → components-dc5q749x.js} +1 -1
  125. package/dist/shared/{components-0rpek9d8.js → components-dtca4s6b.js} +4 -4
  126. package/dist/shared/{components-pd42emw3.js → components-ft3zdc79.js} +2 -2
  127. package/dist/shared/{components-59my5pwr.js → components-g3eafs70.js} +4 -4
  128. package/dist/shared/components-gx4h5rbb.js +40 -0
  129. package/dist/shared/{components-c6cz9nw6.js → components-gyt7my41.js} +3 -3
  130. package/dist/shared/{components-6zng858q.js → components-hdzrqqpx.js} +3 -1
  131. package/dist/shared/{components-bwy8775y.js → components-hgv6tygd.js} +6 -4
  132. package/dist/shared/{components-8tt3xbb5.js → components-kz5q11pp.js} +2 -2
  133. package/dist/shared/{components-awra5sff.js → components-m06yq8wk.js} +14 -7
  134. package/dist/shared/{components-y1w3a6wx.js → components-mattt5jp.js} +2 -2
  135. package/dist/shared/{components-35tmfjtw.js → components-mhza2wdn.js} +6 -6
  136. package/dist/shared/{components-64c8kvmt.js → components-p0fm0bab.js} +7 -7
  137. package/dist/shared/{components-wktrrb4m.js → components-pt5ftm4p.js} +1 -1
  138. package/dist/shared/{components-d7nhksd0.js → components-pv1dyrtn.js} +4 -4
  139. package/dist/shared/{components-pw06rbxq.js → components-pwayrkw9.js} +1 -1
  140. package/dist/shared/{components-t7c6c4t4.js → components-px2zm7dc.js} +1 -1
  141. package/dist/shared/{components-2c0qcfx4.js → components-qh1cvj6p.js} +2 -2
  142. package/dist/shared/{components-kr40s3z0.js → components-qx27excf.js} +1 -1
  143. package/dist/shared/{components-72w4ge68.js → components-rtadhd9j.js} +1 -1
  144. package/dist/shared/{components-nv4awn05.js → components-s8yqk2dc.js} +1 -1
  145. package/dist/shared/{components-wwd363me.js → components-svkt577j.js} +3 -3
  146. package/dist/shared/{components-tjtjmjjr.js → components-syynwm1r.js} +3 -3
  147. package/dist/shared/{components-jkctvwz9.js → components-t5pk5nmc.js} +1 -1
  148. package/dist/shared/{components-a4evvq8h.js → components-tv7b8tet.js} +1 -1
  149. package/dist/shared/{components-49bsynbw.js → components-vc864c51.js} +1 -1
  150. package/dist/shared/{components-mpw667rb.js → components-w2jqa6hx.js} +3 -3
  151. package/dist/shared/{components-8nwsqjn8.js → components-wbbckbw8.js} +1 -1
  152. package/dist/shared/{components-hpe3avtw.js → components-wgtjt2af.js} +4 -4
  153. package/dist/shared/{components-ep3d57kp.js → components-wknae3m4.js} +6 -6
  154. package/dist/shared/{components-9n43qf8y.js → components-xd3emmy4.js} +7 -7
  155. package/dist/shared/{components-96sd8h9m.js → components-xjkdvnbg.js} +1 -1
  156. package/dist/shared/{components-hx4a4cvm.js → components-y0kfy2g4.js} +6 -6
  157. package/dist/shared/{components-621xezcz.js → components-yxmxn2jp.js} +2 -2
  158. package/dist/shared/{components-60atskhp.js → components-z8fedth5.js} +2 -2
  159. package/dist/shared/{components-zj640a90.js → components-zkk3fmw8.js} +3 -3
  160. package/dist/styles.css +46 -1
  161. package/dist/tailwind.css +1 -0
  162. package/dist/tokens/colors.css +6 -0
  163. package/dist/tokens.css +6 -0
  164. package/lib/field-classes.ts +7 -1
  165. package/lib/shape-context.tsx +16 -2
  166. package/lib/shape-radius.ts +67 -0
  167. package/lib/use-morph.ts +25 -7
  168. package/package.json +8 -2
  169. package/preset.ts +1 -0
  170. package/primitives/craft/examples.mdx +22 -18
  171. package/primitives/morph/examples.mdx +11 -7
  172. 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.muted}"
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 recessed track: the segmented tabs' well, a sunken field at rest.
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
- # Basic
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
- # Suggestions
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
- # Attachments
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
- # Queued messages
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
- # Left Slot Only
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
- # Right Slot Only
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
- # Standalone
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
- # Single Expand
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
- # Multi Expand
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
- # Row highlight
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
- # Without the goo
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
- # Without the chevron
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
- # Rich headers
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
- # Your own trigger
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
- # Solid
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
- # Dot
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
- # Outline
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
- # Status mapping
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
- # Compact
63
+ # Usage
77
64
 
78
- `size="compact"` steps the badge down the size ladder (20px tall, 11px
79
- text) for dense rows and table cells.
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 size="compact" color="blue">History</Badge>
83
- <Badge size="compact" variant="dot" color="green">Philosophy</Badge>
84
- <Badge size="compact">Draft</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
- # Changes
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
- # Destructive and success
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
- # Outline and link
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
- # With Icons
49
+ # Sizes
50
50
 
51
- `leadingIcon` and `trailingIcon` take an icon component; it sits 4px
52
- closer to its edge than the label would.
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-wrap items-center gap-2">
55
- <Button leadingIcon={Plus}>Create</Button>
56
- <Button variant="secondary" trailingIcon={ArrowRight}>Next</Button>
57
- <Button variant="tertiary" leadingIcon={Search} trailingIcon={ArrowRight}>
58
- Search
59
- </Button>
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
- # Loading & Disabled
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
- # Loading morph
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
- # Sizes
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
- # As child
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
- # Surface classes
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`