@adea-ai/ui 0.117.0 → 0.118.0

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (193) hide show
  1. package/dist/components/composites/action-button/action-button.d.ts.map +1 -1
  2. package/dist/components/composites/action-button/action-button.js +1 -0
  3. package/dist/components/composites/action-button/action-button.js.map +1 -1
  4. package/dist/components/composites/list-row/list-row-control.d.ts.map +1 -1
  5. package/dist/components/composites/list-row/list-row-control.js +1 -0
  6. package/dist/components/composites/list-row/list-row-control.js.map +1 -1
  7. package/dist/components/composites/list-row/list-row.d.ts.map +1 -1
  8. package/dist/components/composites/list-row/list-row.js +16 -9
  9. package/dist/components/composites/list-row/list-row.js.map +1 -1
  10. package/dist/components/composites/settings/settings-navigation.d.ts.map +1 -1
  11. package/dist/components/composites/settings/settings-navigation.js +15 -6
  12. package/dist/components/composites/settings/settings-navigation.js.map +1 -1
  13. package/dist/components/composites/settings/settings.d.ts +3 -2
  14. package/dist/components/composites/settings/settings.d.ts.map +1 -1
  15. package/dist/components/composites/settings/settings.js +3 -2
  16. package/dist/components/composites/settings/settings.js.map +1 -1
  17. package/dist/components/ui/alert/alert.d.ts +7 -0
  18. package/dist/components/ui/alert/alert.d.ts.map +1 -1
  19. package/dist/components/ui/alert/alert.js +18 -1
  20. package/dist/components/ui/alert/alert.js.map +1 -1
  21. package/dist/components/ui/alert/index.d.ts +1 -1
  22. package/dist/components/ui/alert/index.d.ts.map +1 -1
  23. package/dist/components/ui/alert/index.js +2 -2
  24. package/dist/components/ui/badge/badge.d.ts.map +1 -1
  25. package/dist/components/ui/badge/badge.js +1 -0
  26. package/dist/components/ui/badge/badge.js.map +1 -1
  27. package/dist/components/ui/breadcrumb/breadcrumb.d.ts +6 -0
  28. package/dist/components/ui/breadcrumb/breadcrumb.d.ts.map +1 -1
  29. package/dist/components/ui/breadcrumb/breadcrumb.js +19 -8
  30. package/dist/components/ui/breadcrumb/breadcrumb.js.map +1 -1
  31. package/dist/components/ui/breadcrumb/index.d.ts +1 -1
  32. package/dist/components/ui/breadcrumb/index.d.ts.map +1 -1
  33. package/dist/components/ui/breadcrumb/index.js +2 -2
  34. package/dist/components/ui/button/button.d.ts.map +1 -1
  35. package/dist/components/ui/button/button.js +1 -0
  36. package/dist/components/ui/button/button.js.map +1 -1
  37. package/dist/components/ui/card/card.d.ts +19 -9
  38. package/dist/components/ui/card/card.d.ts.map +1 -1
  39. package/dist/components/ui/card/card.js +21 -3
  40. package/dist/components/ui/card/card.js.map +1 -1
  41. package/dist/components/ui/card/index.d.ts +1 -1
  42. package/dist/components/ui/card/index.d.ts.map +1 -1
  43. package/dist/components/ui/card/index.js +2 -2
  44. package/dist/components/ui/checkbox/checkbox.d.ts.map +1 -1
  45. package/dist/components/ui/checkbox/checkbox.js +1 -0
  46. package/dist/components/ui/checkbox/checkbox.js.map +1 -1
  47. package/dist/components/ui/dialog/dialog.d.ts +15 -0
  48. package/dist/components/ui/dialog/dialog.d.ts.map +1 -1
  49. package/dist/components/ui/dialog/dialog.js +11 -3
  50. package/dist/components/ui/dialog/dialog.js.map +1 -1
  51. package/dist/components/ui/dialog/index.d.ts +1 -1
  52. package/dist/components/ui/dialog/index.d.ts.map +1 -1
  53. package/dist/components/ui/entity-icon/entity-icon.d.ts +10 -0
  54. package/dist/components/ui/entity-icon/entity-icon.d.ts.map +1 -1
  55. package/dist/components/ui/entity-icon/entity-icon.js +11 -2
  56. package/dist/components/ui/entity-icon/entity-icon.js.map +1 -1
  57. package/dist/components/ui/field/field.d.ts +11 -1
  58. package/dist/components/ui/field/field.d.ts.map +1 -1
  59. package/dist/components/ui/field/field.js +2 -2
  60. package/dist/components/ui/field/field.js.map +1 -1
  61. package/dist/components/ui/field/index.d.ts +1 -1
  62. package/dist/components/ui/field/index.d.ts.map +1 -1
  63. package/dist/components/ui/input-group/index.d.ts +1 -1
  64. package/dist/components/ui/input-group/index.d.ts.map +1 -1
  65. package/dist/components/ui/input-group/input-group.d.ts +8 -1
  66. package/dist/components/ui/input-group/input-group.d.ts.map +1 -1
  67. package/dist/components/ui/input-group/input-group.js +16 -20
  68. package/dist/components/ui/input-group/input-group.js.map +1 -1
  69. package/dist/components/ui/native-select/native-select.d.ts +8 -1
  70. package/dist/components/ui/native-select/native-select.d.ts.map +1 -1
  71. package/dist/components/ui/native-select/native-select.js +9 -2
  72. package/dist/components/ui/native-select/native-select.js.map +1 -1
  73. package/dist/components/ui/progress/progress.d.ts.map +1 -1
  74. package/dist/components/ui/progress/progress.js +6 -3
  75. package/dist/components/ui/progress/progress.js.map +1 -1
  76. package/dist/components/ui/radio-group/radio-group.d.ts +18 -3
  77. package/dist/components/ui/radio-group/radio-group.d.ts.map +1 -1
  78. package/dist/components/ui/radio-group/radio-group.js +32 -7
  79. package/dist/components/ui/radio-group/radio-group.js.map +1 -1
  80. package/dist/components/ui/select/select.d.ts.map +1 -1
  81. package/dist/components/ui/select/select.js +10 -7
  82. package/dist/components/ui/select/select.js.map +1 -1
  83. package/dist/components/ui/sheet/sheet.d.ts +1 -0
  84. package/dist/components/ui/sheet/sheet.d.ts.map +1 -1
  85. package/dist/components/ui/sheet/sheet.js +27 -2
  86. package/dist/components/ui/sheet/sheet.js.map +1 -1
  87. package/dist/components/ui/slider/slider.d.ts.map +1 -1
  88. package/dist/components/ui/slider/slider.js +6 -3
  89. package/dist/components/ui/slider/slider.js.map +1 -1
  90. package/dist/components/ui/status-chip/status-chip.d.ts.map +1 -1
  91. package/dist/components/ui/status-chip/status-chip.js +1 -1
  92. package/dist/components/ui/status-chip/status-chip.js.map +1 -1
  93. package/dist/components/ui/switch/switch.d.ts.map +1 -1
  94. package/dist/components/ui/switch/switch.js +1 -0
  95. package/dist/components/ui/switch/switch.js.map +1 -1
  96. package/dist/components/ui/tabs/tabs.d.ts +18 -0
  97. package/dist/components/ui/tabs/tabs.d.ts.map +1 -1
  98. package/dist/components/ui/tabs/tabs.js +22 -4
  99. package/dist/components/ui/tabs/tabs.js.map +1 -1
  100. package/dist/components/ui/toggle/toggle.d.ts.map +1 -1
  101. package/dist/components/ui/toggle/toggle.js +9 -6
  102. package/dist/components/ui/toggle/toggle.js.map +1 -1
  103. package/dist/components/ui/toggle-group/toggle-group.d.ts.map +1 -1
  104. package/dist/components/ui/toggle-group/toggle-group.js +2 -0
  105. package/dist/components/ui/toggle-group/toggle-group.js.map +1 -1
  106. package/dist/components/ui/typography/typography.d.ts +12 -1
  107. package/dist/components/ui/typography/typography.d.ts.map +1 -1
  108. package/dist/components/ui/typography/typography.js +16 -2
  109. package/dist/components/ui/typography/typography.js.map +1 -1
  110. package/dist/index.js +4 -4
  111. package/dist/lib/cn-tables.generated.js +5 -5
  112. package/dist/lib/cn-tables.generated.js.map +1 -1
  113. package/dist/lib/tokens.d.ts.map +1 -1
  114. package/dist/lib/tokens.js +7 -2
  115. package/dist/lib/tokens.js.map +1 -1
  116. package/dist/r/list-row.json +1 -0
  117. package/dist/r/registry.json +1 -0
  118. package/dist/r/src/components/composites/action-button/action-button.tsx +3 -0
  119. package/dist/r/src/components/composites/list-row/list-row-control.tsx +1 -0
  120. package/dist/r/src/components/composites/list-row/list-row.tsx +3 -2
  121. package/dist/r/src/components/composites/settings/settings-navigation.tsx +7 -3
  122. package/dist/r/src/components/composites/settings/settings.tsx +3 -2
  123. package/dist/r/src/components/ui/alert/alert.tsx +17 -0
  124. package/dist/r/src/components/ui/alert/index.ts +8 -1
  125. package/dist/r/src/components/ui/badge/badge.tsx +1 -0
  126. package/dist/r/src/components/ui/breadcrumb/breadcrumb.tsx +18 -8
  127. package/dist/r/src/components/ui/breadcrumb/index.ts +1 -0
  128. package/dist/r/src/components/ui/button/button.tsx +1 -0
  129. package/dist/r/src/components/ui/card/card.tsx +30 -13
  130. package/dist/r/src/components/ui/card/index.ts +1 -0
  131. package/dist/r/src/components/ui/checkbox/checkbox.tsx +1 -0
  132. package/dist/r/src/components/ui/dialog/dialog.tsx +26 -2
  133. package/dist/r/src/components/ui/dialog/index.ts +1 -0
  134. package/dist/r/src/components/ui/entity-icon/entity-icon.tsx +15 -0
  135. package/dist/r/src/components/ui/field/field.tsx +23 -3
  136. package/dist/r/src/components/ui/field/index.ts +1 -0
  137. package/dist/r/src/components/ui/input-group/index.ts +1 -0
  138. package/dist/r/src/components/ui/input-group/input-group.tsx +28 -5
  139. package/dist/r/src/components/ui/native-select/native-select.tsx +20 -3
  140. package/dist/r/src/components/ui/progress/progress.tsx +5 -1
  141. package/dist/r/src/components/ui/radio-group/radio-group.tsx +40 -3
  142. package/dist/r/src/components/ui/select/select.tsx +1 -0
  143. package/dist/r/src/components/ui/sheet/sheet.tsx +20 -2
  144. package/dist/r/src/components/ui/slider/slider.tsx +1 -0
  145. package/dist/r/src/components/ui/status-chip/status-chip.tsx +1 -0
  146. package/dist/r/src/components/ui/switch/switch.tsx +1 -0
  147. package/dist/r/src/components/ui/tabs/tabs.tsx +33 -4
  148. package/dist/r/src/components/ui/toggle/toggle.tsx +1 -0
  149. package/dist/r/src/components/ui/toggle-group/toggle-group.tsx +2 -0
  150. package/dist/r/src/components/ui/typography/typography.tsx +20 -1
  151. package/dist/r/src/lib/cn-tables.generated.ts +5 -5
  152. package/dist/r/src/lib/tokens.ts +7 -2
  153. package/dist/r/src/styles/base.css +4 -1
  154. package/dist/r/src/styles/theme.css +4 -0
  155. package/package.json +1 -1
  156. package/registry.json +1 -0
  157. package/src/components/composites/action-button/action-button.tsx +3 -0
  158. package/src/components/composites/list-row/list-row-control.tsx +1 -0
  159. package/src/components/composites/list-row/list-row.tsx +3 -2
  160. package/src/components/composites/settings/settings-navigation.tsx +7 -3
  161. package/src/components/composites/settings/settings.tsx +3 -2
  162. package/src/components/ui/alert/alert.tsx +17 -0
  163. package/src/components/ui/alert/index.ts +8 -1
  164. package/src/components/ui/badge/badge.tsx +1 -0
  165. package/src/components/ui/breadcrumb/breadcrumb.tsx +18 -8
  166. package/src/components/ui/breadcrumb/index.ts +1 -0
  167. package/src/components/ui/button/button.tsx +1 -0
  168. package/src/components/ui/card/card.tsx +30 -13
  169. package/src/components/ui/card/index.ts +1 -0
  170. package/src/components/ui/checkbox/checkbox.tsx +1 -0
  171. package/src/components/ui/dialog/dialog.tsx +26 -2
  172. package/src/components/ui/dialog/index.ts +1 -0
  173. package/src/components/ui/entity-icon/entity-icon.tsx +15 -0
  174. package/src/components/ui/field/field.tsx +23 -3
  175. package/src/components/ui/field/index.ts +1 -0
  176. package/src/components/ui/input-group/index.ts +1 -0
  177. package/src/components/ui/input-group/input-group.tsx +28 -5
  178. package/src/components/ui/native-select/native-select.tsx +20 -3
  179. package/src/components/ui/progress/progress.tsx +5 -1
  180. package/src/components/ui/radio-group/radio-group.tsx +40 -3
  181. package/src/components/ui/select/select.tsx +1 -0
  182. package/src/components/ui/sheet/sheet.tsx +20 -2
  183. package/src/components/ui/slider/slider.tsx +1 -0
  184. package/src/components/ui/status-chip/status-chip.tsx +1 -0
  185. package/src/components/ui/switch/switch.tsx +1 -0
  186. package/src/components/ui/tabs/tabs.tsx +33 -4
  187. package/src/components/ui/toggle/toggle.tsx +1 -0
  188. package/src/components/ui/toggle-group/toggle-group.tsx +2 -0
  189. package/src/components/ui/typography/typography.tsx +20 -1
  190. package/src/lib/cn-tables.generated.ts +5 -5
  191. package/src/lib/tokens.ts +7 -2
  192. package/src/styles/base.css +4 -1
  193. package/src/styles/theme.css +4 -0
@@ -62,6 +62,7 @@ export function Tabs(props: ComponentProps<typeof KobalteTabs>) {
62
62
  return (
63
63
  <TabsIdContext.Provider value={tabs}>
64
64
  <KobalteTabs
65
+ data-slot="tabs"
65
66
  id={id()}
66
67
  class={cn(
67
68
  'flex min-h-0 min-w-0 flex-col gap-2 data-[orientation=vertical]:flex-row',
@@ -75,6 +76,18 @@ export function Tabs(props: ComponentProps<typeof KobalteTabs>) {
75
76
 
76
77
  export type TabsListProps = ComponentProps<typeof KobalteTabs.List> & {
77
78
  appearance?: 'underline' | 'segmented'
79
+ /**
80
+ * Span the container, with the triggers at the start. For a row of tabs that
81
+ * heads a pane: the underline's rule then runs the pane's full width, the
82
+ * way the pane's other header rules do, instead of stopping at the last tab.
83
+ */
84
+ fill?: boolean
85
+ /**
86
+ * Scroll sideways when the triggers outgrow the row, with no visible
87
+ * scrollbar, instead of overflowing it. Implies `fill`. The underline's rule
88
+ * is drawn inside the scroller so the selected mark still sits on it.
89
+ */
90
+ scrollable?: boolean
78
91
  }
79
92
 
80
93
  /**
@@ -82,17 +95,31 @@ export type TabsListProps = ComponentProps<typeof KobalteTabs.List> & {
82
95
  * on. A vertical list has no baseline — its triggers stack — so the rule is
83
96
  * dropped there; otherwise it draws as a stray line under the last trigger,
84
97
  * spanning only the list's width (the SettingsLayout rail showed exactly that).
98
+ *
99
+ * A scrolling list cannot draw that rule as its border: a scroller clips at its
100
+ * padding edge, and the selected trigger's mark overlaps the border by a pixel
101
+ * (`-mb-px`), so the mark would be cut off and the list would scroll vertically
102
+ * by that pixel. It reserves the pixel as padding instead and paints the rule
103
+ * there with an inset shadow, which lands exactly where the border was.
85
104
  */
86
105
  export function TabsList(props: TabsListProps) {
87
- const [local, rest] = splitProps(props, ['class', 'appearance'])
106
+ const [local, rest] = splitProps(props, ['class', 'appearance', 'fill', 'scrollable'])
107
+ const underline = () => local.appearance !== 'segmented'
88
108
 
89
109
  return (
90
110
  <KobalteTabs.List
111
+ data-slot="tabs-list"
91
112
  class={cn(
92
- 'inline-flex w-fit shrink-0 items-center justify-center',
93
- local.appearance === 'segmented'
113
+ 'shrink-0 items-center',
114
+ local.fill || local.scrollable
115
+ ? 'flex w-full justify-start'
116
+ : 'inline-flex w-fit justify-center',
117
+ local.scrollable && 'no-scrollbar overflow-x-auto overflow-y-hidden',
118
+ !underline()
94
119
  ? 'gap-0.5 rounded-lg bg-surface-hover p-0.5'
95
- : 'gap-1 rounded-none border-b border-border data-[orientation=vertical]:border-b-0',
120
+ : local.scrollable
121
+ ? 'gap-1 rounded-none pb-px shadow-[inset_0_-1px_0_var(--border)] data-[orientation=vertical]:pb-0 data-[orientation=vertical]:shadow-none'
122
+ : 'gap-1 rounded-none border-b border-border data-[orientation=vertical]:border-b-0',
96
123
  'data-[orientation=vertical]:flex-col data-[orientation=vertical]:items-stretch',
97
124
  local.class
98
125
  )}
@@ -133,6 +160,7 @@ export function TabsTrigger(props: TabsTriggerProps) {
133
160
 
134
161
  return (
135
162
  <KobalteTabs.Trigger
163
+ data-slot="tabs-trigger"
136
164
  id={triggerId()}
137
165
  class={cn(
138
166
  'inline-flex shrink-0 items-center justify-center gap-1.5 whitespace-nowrap text-sm font-medium',
@@ -158,6 +186,7 @@ export function TabsContent(props: ComponentProps<typeof KobalteTabs.Content>) {
158
186
  const tabs = useTabsId()
159
187
  return (
160
188
  <KobalteTabs.Content
189
+ data-slot="tabs-content"
161
190
  aria-labelledby={
162
191
  local['aria-labelledby'] ??
163
192
  tabs.triggerIds().get(rest.value) ??
@@ -58,6 +58,7 @@ export function Toggle(props: ToggleProps) {
58
58
 
59
59
  return (
60
60
  <ToggleButton
61
+ data-slot="toggle"
61
62
  class={cn(toggleVariants({ variant: local.variant, size: local.size }), local.class)}
62
63
  {...rest}
63
64
  />
@@ -38,6 +38,7 @@ export function ToggleGroup(props: ToggleGroupProps) {
38
38
 
39
39
  return (
40
40
  <KobalteToggleGroup
41
+ data-slot="toggle-group"
41
42
  multiple={local.multiple ?? false}
42
43
  class={cn(
43
44
  'flex w-fit flex-row items-center',
@@ -68,6 +69,7 @@ export function ToggleGroupItem(props: ToggleGroupItemProps) {
68
69
 
69
70
  return (
70
71
  <KobalteToggleGroup.Item
72
+ data-slot="toggle-group-item"
71
73
  class={cn(toggleVariants({ variant: local.variant, size: local.size }), local.class)}
72
74
  onKeyDown={(event) => {
73
75
  invokeEventHandler(local.onKeyDown, event)
@@ -130,6 +130,13 @@ export function Heading<T extends ValidComponent = 'h2'>(props: HeadingProps<T>)
130
130
  * foreground without the caller restating it.
131
131
  *
132
132
  * Defaults: `body` renders a `p`, `code` a `code`, every other variant a `span`.
133
+ *
134
+ * `overline` is the small uppercase label above a group — a list group's
135
+ * heading, a settings navigation group, an eyebrow over a page title. It is the
136
+ * one variant whose tone defaults to `muted` rather than inheriting, because an
137
+ * overline in the body foreground competes with the heading it introduces. Pass
138
+ * `tone` to override. It labels a group; it is not a heading, so it renders a
139
+ * `span` and stays out of the document outline.
133
140
  */
134
141
  export const textVariants = /* @__PURE__ */ cva('', {
135
142
  variants: {
@@ -144,6 +151,8 @@ export const textVariants = /* @__PURE__ */ cva('', {
144
151
  caption: 'text-xs',
145
152
  /** 11px / 500. The floor: keyboard keys, the status bar. */
146
153
  micro: 'text-2xs font-medium',
154
+ /** 11px / 500, uppercase and tracked. A group label or eyebrow; muted by default. */
155
+ overline: 'text-2xs font-medium tracking-wide uppercase',
147
156
  /** 12px mono. Ids, paths, hashes, inline code. */
148
157
  code: 'font-code text-code',
149
158
  },
@@ -168,9 +177,15 @@ export const textElement = {
168
177
  strong: 'span',
169
178
  caption: 'span',
170
179
  micro: 'span',
180
+ overline: 'span',
171
181
  code: 'code',
172
182
  } as const
173
183
 
184
+ /** The tone a variant takes when the caller names none: muted for `overline`, else inherit. */
185
+ export function textDefaultTone(variant: TextVariant | null | undefined) {
186
+ return variant === 'overline' ? 'muted' : undefined
187
+ }
188
+
174
189
  type TextVariantProps = VariantProps<typeof textVariants>
175
190
  type TextVariant = keyof typeof textElement
176
191
 
@@ -195,7 +210,11 @@ export function Text<T extends ValidComponent = 'p'>(props: TextProps<T>) {
195
210
  as={local.as ?? textElement[(local.variant ?? 'body') as TextVariant]}
196
211
  data-slot="text"
197
212
  class={cn(
198
- textVariants({ variant: local.variant, tone: local.tone, numeric: local.numeric }),
213
+ textVariants({
214
+ variant: local.variant,
215
+ tone: local.tone ?? textDefaultTone(local.variant),
216
+ numeric: local.numeric,
217
+ }),
199
218
  local.class
200
219
  )}
201
220
  {...(rest as ComponentProps<'p'>)}
@@ -91,7 +91,7 @@ const nodeVlist = (() => {
91
91
  for (let i = 0; i < A.length; i++) out[A[i]!] = V[i]!
92
92
  return out
93
93
  })()
94
- const SETS = "container |break-after- all auto avoid avoid-page column left page right|break-before- all auto avoid avoid-page column left page right|break-inside-a uto void void-column void-page|box-decoration- clone slice|box- border content| contents flow-root hidden table table-caption table-cell table-column table-column-group table-footer-group table-header-group table-row table-row-group| not-sr-only sr-only|float- end left none right start|clear- both end left none right start|isolat e ion-auto|overflow- auto clip hidden scroll visible|overflow-x- auto clip hidden scroll visible|overflow-y- auto clip hidden scroll visible|overscroll- auto contain none|overscroll-x- auto contain none|overscroll-y- auto contain none| absolute fixed relative static sticky| collapse invisible visible|justify- around baseline between center center-safe end end-safe evenly normal start stretch|justify-items- center center-safe end end-safe normal start stretch|justify-self- auto center center-safe end end-safe start stretch|items- baseline baseline-last center center-safe end end-safe start stretch|self- auto baseline baseline-last center center-safe end end-safe start stretch|place-content- around baseline between center center-safe end end-safe evenly start stretch|place-items- baseline center center-safe end end-safe start stretch|place-self- auto center center-safe end end-safe start stretch| antialiased subpixel-antialiased| italic not-italic|normal-nums |ordinal |slashed-zero | lining-nums oldstyle-nums| proportional-nums tabular-nums| diagonal-fractions stacked-fractions| no-underline overline| capitalize lowercase normal-case uppercase|truncate |whitespace- break-spaces normal nowrap pre pre-line pre-wrap|break- all keep normal words|wrap- anywhere break-word normal|hyphens- auto manual none|mix-blend- color color-burn color-dodge darken difference exclusion hard-light hue lighten luminosity multiply normal overlay plus-darker plus-lighter saturation screen soft-light|table- auto fixed|caption- bottom top|backface- hidden visible|appearance- auto none|scheme- dark light light-dark normal only-dark only-light|field-sizing- content fixed|pointer-events- auto none|resize -none -x -y|snap- align-none center end start|snap- always normal|snap- both none x y|snap- mandatory proximity|touch- auto manipulation none|touch-pan- left right x|touch-pan- down up y|touch-pinch-zoom |select- all auto none text|forced-color-adjust- auto none| normal size| baseline bottom middle sub super text-bottom text-top top| bounce none ping pulse spin| auto square video| auto control-2xl control-2xs control-lg control-md control-sm control-xl control-xs fr max min px|none | auto control-2xl control-2xs control-lg control-md control-sm control-xl control-xs full px| fixed local scroll|clip- border content padding text|origin- border content padding| bottom bottom-left bottom-right center left left-bottom left-top right right-bottom right-top top top-left top-right| no-repeat repeat repeat-round repeat-space repeat-x repeat-y| auto contain cover| gradient-to-b gradient-to-bl gradient-to-br gradient-to-l gradient-to-r gradient-to-t gradient-to-tl gradient-to-tr none|blend- color color-burn color-dodge darken difference exclusion hard-light hue lighten luminosity multiply normal overlay saturation screen soft-light|to- b bl br l r t tl tr| auto control-2xl control-2xs control-lg control-md control-sm control-xl control-xs dvh fit full lh lvh max min px screen svh| dashed dotted double hidden none solid| collapse separate| control-2xl control-2xs control-lg control-md control-sm control-xl control-xs px|auto |full | content none strict| inline-size size|layout |paint |style | around baseline between center center-safe end end-safe evenly normal start stretch| alias all-scroll auto cell col-resize context-menu copy crosshair default e-resize ew-resize grab grabbing help move n-resize ne-resize nesw-resize no-drop none not-allowed ns-resize nw-resize nwse-resize pointer progress row-resize s-resize se-resize sw-resize text vertical-text w-resize wait zoom-in zoom-out| dashed dotted double solid wavy| auto from-font|reverse |initial | in in-out initial linear out| col col-reverse row row-reverse| nowrap wrap wrap-reverse| auto initial none| black bold extrabold extralight light medium normal semibold thin| condensed expanded extra-condensed extra-expanded normal semi-condensed semi-expanded ultra-condensed ultra-expanded|flow- col col-dense dense row row-dense| none subgrid| auto control-2xl control-2xs control-lg control-md control-sm control-xl control-xs dvh dvw fit full lh lvh lvw max min px rail-item row-lg row-md row-sm screen statusbar svh svw topbar| block flex grid table| auto control-2xl control-2xs control-lg control-md control-sm control-xl control-xs dvw fit full lvw max min px screen svw| control-2xl control-2xs control-lg control-md control-sm control-xl control-xs loose none normal px relaxed snug tight|through |item | inside outside| decimal disc none| auto control-2xl control-2xs control-lg control-md control-sm control-xl control-xs px| clip-border clip-content clip-fill clip-padding clip-stroke clip-view no-clip| add exclude intersect subtract| alpha luminance match|origin- border content fill padding stroke view|type- alpha luminance| circle ellipse| closest-corner closest-side farthest-corner farthest-side|at- bottom bottom-left bottom-right center left left-bottom left-top right right-bottom right-top top top-left top-right| control-2xl control-2xs control-lg control-md control-sm control-xl control-xs dvh fit full lh lvh max min none px screen svh| auto control-2xl control-2xs control-lg control-md control-sm control-xl control-xs dvh dvw fit full lh lvh lvw max min none px rail-item row-lg row-md row-sm screen statusbar svh svw topbar| control-2xl control-2xs control-lg control-md control-sm control-xl control-xs dvw fit full lvw max min none px screen svw| auto control-2xl control-2xs control-lg control-md control-sm control-xl control-xs dvh dvw fit full lvh lvw max min none prose px rail rail-expanded sidebar sidebar-compact svh svw| auto control-2xl control-2xs control-lg control-md control-sm control-xl control-xs dvh dvw fit full lvh lvw max min none px rail rail-expanded screen sidebar sidebar-compact svh svw| contain cover fill none scale-down| first last none| distant dramatic midrange near none normal|inset | full none|3d | auto smooth|gutter- auto both stable| auto none thin| inner none| auto control-2xl control-2xs control-lg control-md control-sm control-xl control-xs dvh dvw fit full lvh lvw max min px rail-item svh svw|base | center end justify left right start| clip ellipsis| balance nowrap pretty wrap| normal tight tighter wide wider widest| cpu gpu none| 3d flat| all colors none opacity shadow transform| discrete normal| control-2xl control-2xs control-lg control-md control-sm control-xl control-xs full px| auto control-2xl control-2xs control-lg control-md control-sm control-xl control-xs dvh dvw fit full lvh lvw max min px rail rail-expanded screen sidebar sidebar-compact svh svw| auto contents scroll transform".split('|').map((s) => {
94
+ const SETS = "container |break-after- all auto avoid avoid-page column left page right|break-before- all auto avoid avoid-page column left page right|break-inside-a uto void void-column void-page|box-decoration- clone slice|box- border content| contents flow-root hidden table table-caption table-cell table-column table-column-group table-footer-group table-header-group table-row table-row-group| not-sr-only sr-only|float- end left none right start|clear- both end left none right start|isolat e ion-auto|overflow- auto clip hidden scroll visible|overflow-x- auto clip hidden scroll visible|overflow-y- auto clip hidden scroll visible|overscroll- auto contain none|overscroll-x- auto contain none|overscroll-y- auto contain none| absolute fixed relative static sticky| collapse invisible visible|justify- around baseline between center center-safe end end-safe evenly normal start stretch|justify-items- center center-safe end end-safe normal start stretch|justify-self- auto center center-safe end end-safe start stretch|items- baseline baseline-last center center-safe end end-safe start stretch|self- auto baseline baseline-last center center-safe end end-safe start stretch|place-content- around baseline between center center-safe end end-safe evenly start stretch|place-items- baseline center center-safe end end-safe start stretch|place-self- auto center center-safe end end-safe start stretch| antialiased subpixel-antialiased| italic not-italic|normal-nums |ordinal |slashed-zero | lining-nums oldstyle-nums| proportional-nums tabular-nums| diagonal-fractions stacked-fractions| no-underline overline| capitalize lowercase normal-case uppercase|truncate |whitespace- break-spaces normal nowrap pre pre-line pre-wrap|break- all keep normal words|wrap- anywhere break-word normal|hyphens- auto manual none|mix-blend- color color-burn color-dodge darken difference exclusion hard-light hue lighten luminosity multiply normal overlay plus-darker plus-lighter saturation screen soft-light|table- auto fixed|caption- bottom top|backface- hidden visible|appearance- auto none|scheme- dark light light-dark normal only-dark only-light|field-sizing- content fixed|pointer-events- auto none|resize -none -x -y|snap- align-none center end start|snap- always normal|snap- both none x y|snap- mandatory proximity|touch- auto manipulation none|touch-pan- left right x|touch-pan- down up y|touch-pinch-zoom |select- all auto none text|forced-color-adjust- auto none| normal size| baseline bottom middle sub super text-bottom text-top top| bounce none ping pulse spin| auto square video| auto control-2xl control-2xs control-lg control-md control-sm control-xl control-xs fr max min px|none | auto control-2xl control-2xs control-lg control-md control-sm control-xl control-xs full px| fixed local scroll|clip- border content padding text|origin- border content padding| bottom bottom-left bottom-right center left left-bottom left-top right right-bottom right-top top top-left top-right| no-repeat repeat repeat-round repeat-space repeat-x repeat-y| auto contain cover| gradient-to-b gradient-to-bl gradient-to-br gradient-to-l gradient-to-r gradient-to-t gradient-to-tl gradient-to-tr none|blend- color color-burn color-dodge darken difference exclusion hard-light hue lighten luminosity multiply normal overlay saturation screen soft-light|to- b bl br l r t tl tr| auto control-2xl control-2xs control-lg control-md control-sm control-xl control-xs dvh fit full lh lvh max min px screen svh| dashed dotted double hidden none solid| collapse separate| control-2xl control-2xs control-lg control-md control-sm control-xl control-xs px|auto |full | content none strict| inline-size size|layout |paint |style | around baseline between center center-safe end end-safe evenly normal start stretch| alias all-scroll auto cell col-resize context-menu copy crosshair default e-resize ew-resize grab grabbing help move n-resize ne-resize nesw-resize no-drop none not-allowed ns-resize nw-resize nwse-resize pointer progress row-resize s-resize se-resize sw-resize text vertical-text w-resize wait zoom-in zoom-out| dashed dotted double solid wavy| auto from-font|reverse |initial | in in-out initial linear out| col col-reverse row row-reverse| nowrap wrap wrap-reverse| auto initial none| black bold extrabold extralight light medium normal semibold thin| condensed expanded extra-condensed extra-expanded normal semi-condensed semi-expanded ultra-condensed ultra-expanded|flow- col col-dense dense row row-dense| none subgrid| auto control-2xl control-2xs control-lg control-md control-sm control-xl control-xs dvh dvw fit full lh lvh lvw max min px rail-item row-lg row-md row-sm screen statusbar svh svw topbar| block flex grid table| auto control-2xl control-2xs control-lg control-md control-sm control-xl control-xs dvw fit full lvw max min px screen svw| control-2xl control-2xs control-lg control-md control-sm control-xl control-xs loose none normal px relaxed snug tight|through |item | inside outside| decimal disc none| auto control-2xl control-2xs control-lg control-md control-sm control-xl control-xs px| clip-border clip-content clip-fill clip-padding clip-stroke clip-view no-clip| add exclude intersect subtract| alpha luminance match|origin- border content fill padding stroke view|type- alpha luminance| circle ellipse| closest-corner closest-side farthest-corner farthest-side|at- bottom bottom-left bottom-right center left left-bottom left-top right right-bottom right-top top top-left top-right| control-2xl control-2xs control-lg control-md control-sm control-xl control-xs dvh fit full lh lvh max min none px screen svh| auto control-2xl control-2xs control-lg control-md control-sm control-xl control-xs dvh dvw fit full lh lvh lvw max min none px rail-item row-lg row-md row-sm screen statusbar svh svw topbar| control-2xl control-2xs control-lg control-md control-sm control-xl control-xs dvw fit full lvw max min none px screen svw| auto control-2xl control-2xs control-lg control-md control-sm control-xl control-xs dvh dvw fit full lvh lvw max min none panel prose px rail rail-expanded sidebar sidebar-compact svh svw| auto control-2xl control-2xs control-lg control-md control-sm control-xl control-xs dvh dvw fit full lvh lvw max min none panel px rail rail-expanded screen sidebar sidebar-compact svh svw| contain cover fill none scale-down| first last none| distant dramatic midrange near none normal|inset | full none|3d | auto smooth|gutter- auto both stable| auto none thin| inner none| auto control-2xl control-2xs control-lg control-md control-sm control-xl control-xs dvh dvw fit full lvh lvw max min px rail-item svh svw|base | center end justify left right start| clip ellipsis| balance nowrap pretty wrap| normal tight tighter wide wider widest| cpu gpu none| 3d flat| all colors none opacity shadow transform| discrete normal| control-2xl control-2xs control-lg control-md control-sm control-xl control-xs full px| auto control-2xl control-2xs control-lg control-md control-sm control-xl control-xs dvh dvw fit full lvh lvw max min panel px rail rail-expanded screen sidebar sidebar-compact svh svw| auto contents scroll transform".split('|').map((s) => {
95
95
  const tails = s.split(' ')
96
96
  const prefix = tails.shift()!
97
97
  for (let i = 0; i < tails.length; i++) {
@@ -102,11 +102,11 @@ const SETS = "container |break-after- all auto avoid avoid-page column left page
102
102
  const AA = DZ("0000000000000000000000000000000000000000000000000000000000000262242:6@200000006:240B428:4422400002046044222426220026642642462026224222824220022400000000\\00N222422242222222224062242222222422226264222422222222222222442804222422222222222222222222220<4<0204260002444020204224422")
103
103
  const AG = DZ("ɠ222222222222222222222222222222222222222222222222222222222222˕4222226>ʶ22ʷʺʷ2ʸʷ42ʴ2ʓ22>621422ɶ222ɹɼɷɺɷɺ22ɱ42222ɨ2ɧ26622ɘɓ244ƸƵ222]d24242ǖǓƚÄȫ2263ȨȥȨ2222222ǣ222222222222222222ǂƽ2ƾƵ2222222422222ƜƑ22222222222222222222144Ŧţ22Ţş222222222222222222222ĸ2ı68ĦģĦɡŰ4Ġ«®ĝ822ĔđĔ2ē2222622")
104
104
  const AS = DZ("02222222222222222222222222222222222222222222222222222222222222222202022222222222EH2200IL021042222Y\\222IL0cf2e10j2222U00X202[^2y0000120|{~‚22…ˆ‡:22|22222222222G000q†OVI00000}š2›>40000ŒB00000I¨©000¬00000000000000021M®­00°“000000000000000000000–222›HGHa1º222¿2À2222ÉÌ000­°2±")
105
- const litAnchor = new Int32Array(1635)
106
- const litGroup = new Int32Array(1635)
107
- const litPool = new Int32Array(1635)
105
+ const litAnchor = new Int32Array(1638)
106
+ const litGroup = new Int32Array(1638)
107
+ const litPool = new Int32Array(1638)
108
108
  let poolText = ''
109
- const poolOffsets = new Int32Array(1072)
109
+ const poolOffsets = new Int32Array(1074)
110
110
  {
111
111
  const tailRef = new Map()
112
112
  let nextRef = 0
@@ -379,11 +379,11 @@ export const radiusTokens: TokenDefinition[] = [
379
379
  description:
380
380
  '10px — cards and panels. Also the knob: move this one value to re-round the whole system.',
381
381
  },
382
- { name: 'radius-sm', kind: 'dimension', description: '6px — badges, keyboard keys, menu items.' },
382
+ { name: 'radius-sm', kind: 'dimension', description: '6px — keyboard keys, menu items.' },
383
383
  {
384
384
  name: 'radius-md',
385
385
  kind: 'dimension',
386
- description: '8px — every control: buttons, inputs, selects.',
386
+ description: '8px — every control: buttons, inputs, selects; and badges.',
387
387
  },
388
388
  { name: 'radius-xl', kind: 'dimension', description: '14px — dialogs, menus, sheets.' },
389
389
  { name: 'radius-2xl', kind: 'dimension', description: '18px — full-window surfaces and media.' },
@@ -597,6 +597,11 @@ export const densityTokens: TokenDefinition[] = [
597
597
  kind: 'dimension',
598
598
  description: '48px — the collapsed secondary column.',
599
599
  },
600
+ {
601
+ name: 'panel-width',
602
+ kind: 'dimension',
603
+ description: '390px — a side pane beside the work, and the same pane as a sheet.',
604
+ },
600
605
  { name: 'topbar-height', kind: 'dimension', description: '48px — the window title row.' },
601
606
  { name: 'statusbar-height', kind: 'dimension', description: '28px — the bottom readout strip.' },
602
607
  {
@@ -712,11 +712,14 @@
712
712
  background: transparent;
713
713
  }
714
714
 
715
+ /* The code role, as the `font-code` utility reads it: an appearance setting
716
+ that picks a code face sets `--font-code`, and bare `code`/`pre` follow it
717
+ instead of staying on the theme's mono face. */
715
718
  code,
716
719
  kbd,
717
720
  pre,
718
721
  samp {
719
- font-family: var(--font-mono);
722
+ font-family: var(--font-code, var(--font-mono));
720
723
  font-feature-settings: 'liga' 0;
721
724
  }
722
725
  }
@@ -591,6 +591,9 @@
591
591
  --rail-item-height: 2.25rem;
592
592
  --sidebar-width: 16rem; /* 256px */
593
593
  --sidebar-width-compact: 3rem;
594
+ /* A side pane's width — a source list or a context panel beside the work, and
595
+ the same pane when a narrow window moves it into a sheet. */
596
+ --panel-width: 24.375rem; /* 390px */
594
597
  --topbar-height: 3rem;
595
598
  --statusbar-height: 1.75rem;
596
599
  /* A tip wraps before it can overflow the window carrying it: the 16rem
@@ -850,6 +853,7 @@
850
853
  --width-rail-expanded: var(--rail-width-expanded);
851
854
  --width-sidebar: var(--sidebar-width);
852
855
  --width-sidebar-compact: var(--sidebar-width-compact);
856
+ --width-panel: var(--panel-width);
853
857
 
854
858
  --z-docked: var(--z-docked);
855
859
  --z-sticky: var(--z-sticky);
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@adea-ai/ui",
3
- "version": "0.117.0",
3
+ "version": "0.118.0",
4
4
  "description": "The Adea design system: Kobalte-backed Solid components, semantic OKLCH tokens, and the app-shell layout primitives shared by Adea and Cortana.",
5
5
  "keywords": [
6
6
  "adea",
package/registry.json CHANGED
@@ -2136,6 +2136,7 @@
2136
2136
  ],
2137
2137
  "registryDependencies": [
2138
2138
  "@adea-ai/ui/tooltip",
2139
+ "@adea-ai/ui/typography",
2139
2140
  "lib"
2140
2141
  ],
2141
2142
  "files": [
@@ -115,6 +115,9 @@ export function ActionButton<T extends ValidComponent = 'button'>(props: ActionB
115
115
 
116
116
  const buttonProps = () => ({
117
117
  ...rest,
118
+ // The inner Button would otherwise announce itself as a plain `button`; a
119
+ // caller's own slot still wins.
120
+ 'data-slot': (rest as { 'data-slot'?: string })['data-slot'] ?? 'action-button',
118
121
  variant: local.variant,
119
122
  size: local.size,
120
123
  touchTarget: local.touchTarget,
@@ -54,6 +54,7 @@ export function ListRowControl<T extends ValidComponent = 'div'>(props: ListRowC
54
54
  return (
55
55
  <Polymorphic
56
56
  as={rowAs()}
57
+ data-slot="list-row"
57
58
  type={rowAs() === 'button' ? (local.type ?? 'button') : local.type}
58
59
  tabIndex={local.tabIndex ?? (rowAs() === 'button' || rowAs() === 'a' ? 0 : undefined)}
59
60
  aria-current={local.selected ? 'true' : undefined}
@@ -2,6 +2,7 @@ import type { PolymorphicProps } from '@kobalte/core/polymorphic'
2
2
  import type { ComponentProps, ValidComponent } from 'solid-js'
3
3
  import { createSignal, createUniqueId, Show, splitProps } from 'solid-js'
4
4
  import { Tooltip, TooltipContent, TooltipTrigger } from '../../ui/tooltip'
5
+ import { Text } from '../../ui/typography'
5
6
  import { cn } from '#lib/utils'
6
7
  import { ListRowControl, type ListRowControlProps } from './list-row-control'
7
8
 
@@ -106,9 +107,9 @@ export function ListGroup(
106
107
  <div data-slot="list-group" class={cn('flex flex-col gap-0.5', local.class)} {...rest}>
107
108
  <Show when={local.label}>
108
109
  <div class="group/list-header flex items-center gap-1 px-2 py-1">
109
- <span class="min-w-0 flex-1 truncate text-2xs font-medium tracking-wide text-muted-foreground uppercase">
110
+ <Text variant="overline" class="min-w-0 flex-1 truncate">
110
111
  {local.label}
111
- </span>
112
+ </Text>
112
113
  <Show when={local.action}>
113
114
  <span class="shrink-0 opacity-0 transition-opacity ease-out group-hover/list-header:opacity-100 focus-within:opacity-100">
114
115
  {local.action}
@@ -3,6 +3,7 @@ import { createEffect, createUniqueId, onCleanup, splitProps } from 'solid-js'
3
3
  import { cn } from '#lib/utils'
4
4
  import { sidebarNavItemClass, sidebarNavItemStateClass } from '../../layout/sidebar-nav/sidebar-nav'
5
5
  import { TabsList, TabsTrigger, type TabsListProps } from '../../ui/tabs'
6
+ import { Text } from '../../ui/typography'
6
7
 
7
8
  /** One host-owned destination in a settings tab list. Values must be unique. */
8
9
  export type SettingsNavigationItem = {
@@ -128,12 +129,15 @@ export function SettingsNavigation(props: SettingsNavigationProps) {
128
129
  <span id={groupId} class="sr-only">
129
130
  {group.label}
130
131
  </span>
131
- <span
132
+ {/* The overline role on the sidebar's own muted foreground. */}
133
+ <Text
134
+ variant="overline"
135
+ tone="inherit"
132
136
  aria-hidden="true"
133
- class="px-2 py-1.5 text-2xs font-medium tracking-wide text-sidebar-muted-foreground uppercase"
137
+ class="px-2 py-1.5 text-sidebar-muted-foreground"
134
138
  >
135
139
  {group.label}
136
- </span>
140
+ </Text>
137
141
  {group.items.map((item) => (
138
142
  <TabsTrigger
139
143
  data-slot="settings-navigation-trigger"
@@ -11,8 +11,9 @@ import { Heading } from '../../ui/typography'
11
11
  * one where drift is most visible: label sizes, control widths and description
12
12
  * placement all wander unless something fixes them.
13
13
  *
14
- * The row is a two-column layout at a fixed label width, so controls line up
15
- * down the page regardless of how long the labels are. `SettingsRow` also
14
+ * The row puts the label and description at the start and the control at the
15
+ * end (stacked on a narrow window), so controls line up down the page's end
16
+ * edge regardless of how long the labels are. `SettingsRow` also
16
17
  * exposes its label and description through the shared form-field context to
17
18
  * the first control inside it. `SettingsField` is the visual stacked layout;
18
19
  * use `FormField` when the control needs label, help, or validation wiring.
@@ -105,4 +105,21 @@ export function AlertDescription(props: ComponentProps<'div'>) {
105
105
  )
106
106
  }
107
107
 
108
+ /**
109
+ * The alert's own actions — a Retry, an Open settings, a Cancel — on a row
110
+ * under the text, aligned with the title rather than the glyph. Buttons here
111
+ * are `size="xs" variant="outline"` by convention, so an alert's action reads
112
+ * as part of the message rather than as the page's primary action.
113
+ */
114
+ export function AlertAction(props: ComponentProps<'div'>) {
115
+ const [local, rest] = splitProps(props, ['class'])
116
+ return (
117
+ <div
118
+ data-slot="alert-action"
119
+ class={cn('col-start-2 mt-1 flex flex-wrap items-center gap-2', local.class)}
120
+ {...rest}
121
+ />
122
+ )
123
+ }
124
+
108
125
  export { alertVariants }
@@ -1 +1,8 @@
1
- export { Alert, AlertDescription, AlertTitle, alertVariants, type AlertProps } from './alert'
1
+ export {
2
+ Alert,
3
+ AlertAction,
4
+ AlertDescription,
5
+ AlertTitle,
6
+ alertVariants,
7
+ type AlertProps,
8
+ } from './alert'
@@ -63,6 +63,7 @@ export function Badge<T extends ValidComponent = 'span'>(props: BadgeProps<T>) {
63
63
  return (
64
64
  <Polymorphic
65
65
  as="span"
66
+ data-slot="badge"
66
67
  class={cn(badgeVariants({ variant: local.variant, size: local.size }), local.class)}
67
68
  {...(rest as ComponentProps<'span'>)}
68
69
  />
@@ -61,14 +61,7 @@ export function BreadcrumbLink(props: BreadcrumbLinkProps) {
61
61
  return (
62
62
  <Show
63
63
  when={!local.current}
64
- fallback={
65
- <span
66
- data-slot="breadcrumb-page"
67
- aria-current="page"
68
- class={cn('font-medium text-foreground', local.class)}
69
- {...(rest as ComponentProps<'span'>)}
70
- />
71
- }
64
+ fallback={<BreadcrumbPage class={local.class} {...(rest as ComponentProps<'span'>)} />}
72
65
  >
73
66
  <a
74
67
  data-slot="breadcrumb-link"
@@ -83,6 +76,23 @@ export function BreadcrumbLink(props: BreadcrumbLinkProps) {
83
76
  )
84
77
  }
85
78
 
79
+ /**
80
+ * The current page: the last crumb, as text rather than a link to itself, and
81
+ * marked `aria-current="page"`. The same element `BreadcrumbLink current`
82
+ * renders, for a trail whose last crumb is never a link.
83
+ */
84
+ export function BreadcrumbPage(props: ComponentProps<'span'>) {
85
+ const [local, rest] = splitProps(props, ['class'])
86
+ return (
87
+ <span
88
+ data-slot="breadcrumb-page"
89
+ aria-current="page"
90
+ class={cn('font-medium text-foreground', local.class)}
91
+ {...rest}
92
+ />
93
+ )
94
+ }
95
+
86
96
  export function BreadcrumbSeparator(props: ComponentProps<'li'>) {
87
97
  const [local, rest] = splitProps(props, ['class', 'children'])
88
98
 
@@ -4,6 +4,7 @@ export {
4
4
  BreadcrumbItem,
5
5
  BreadcrumbLink,
6
6
  BreadcrumbList,
7
+ BreadcrumbPage,
7
8
  BreadcrumbSeparator,
8
9
  type BreadcrumbLinkProps,
9
10
  } from './breadcrumb'
@@ -93,6 +93,7 @@ export function Button<T extends ValidComponent = 'button'>(props: ButtonProps<T
93
93
  <Polymorphic
94
94
  as="button"
95
95
  type="button"
96
+ data-slot="button"
96
97
  class={cn(
97
98
  buttonVariants({
98
99
  variant: local.variant,
@@ -1,5 +1,6 @@
1
- import type { ComponentProps, JSX } from 'solid-js'
1
+ import type { ComponentProps } from 'solid-js'
2
2
  import { splitProps } from 'solid-js'
3
+ import { cva, type VariantProps } from '#lib/variants'
3
4
  import { cn } from '#lib/utils'
4
5
  import { headingVariants } from '../typography'
5
6
 
@@ -15,18 +16,36 @@ import { headingVariants } from '../typography'
15
16
  * The parts are separate components rather than a template because a card's
16
17
  * header, content and footer have different padding on purpose: the header and
17
18
  * footer are tight, the content breathes.
19
+ *
20
+ * `size` is the card's padding rung, so a caller never sets `p-*` or `gap-*` on
21
+ * a card to make it denser. `sm` tightens the card and its header, content and
22
+ * footer together (the parts' inline padding follows the card, so they stay
23
+ * aligned with each other); `flush` removes the block padding and gap for a
24
+ * card whose body is a list of rows or a scroll area that runs edge to edge.
18
25
  */
19
- export function Card(props: ComponentProps<'div'>) {
20
- const [local, rest] = splitProps(props, ['class'])
26
+ export const cardVariants = cva(
27
+ 'bg-card text-card-foreground flex flex-col rounded-xl border border-border shadow-xs',
28
+ {
29
+ variants: {
30
+ size: {
31
+ /** 16px block padding and gap; the parts carry 16px inline padding. */
32
+ default: 'gap-4 py-4',
33
+ /** 12px everywhere: a dense settings or status card. */
34
+ sm: 'gap-3 py-3 *:data-[slot=card-content]:px-3 *:data-[slot=card-footer]:px-3 *:data-[slot=card-header]:px-3',
35
+ /** No block padding or gap: the card hosts a row list or a scroller. */
36
+ flush: 'gap-0 py-0',
37
+ },
38
+ },
39
+ defaultVariants: { size: 'default' },
40
+ }
41
+ )
42
+
43
+ export type CardProps = ComponentProps<'div'> & VariantProps<typeof cardVariants>
44
+
45
+ export function Card(props: CardProps) {
46
+ const [local, rest] = splitProps(props, ['class', 'size'])
21
47
  return (
22
- <div
23
- data-slot="card"
24
- class={cn(
25
- 'bg-card text-card-foreground flex flex-col gap-4 rounded-xl border border-border py-4 shadow-xs',
26
- local.class
27
- )}
28
- {...rest}
29
- />
48
+ <div data-slot="card" class={cn(cardVariants({ size: local.size }), local.class)} {...rest} />
30
49
  )
31
50
  }
32
51
 
@@ -79,5 +98,3 @@ export function CardFooter(props: ComponentProps<'div'>) {
79
98
  const [local, rest] = splitProps(props, ['class'])
80
99
  return <div data-slot="card-footer" class={cn('flex items-center px-4', local.class)} {...rest} />
81
100
  }
82
-
83
- export type CardProps = ComponentProps<'div'> & JSX.HTMLAttributes<HTMLDivElement>
@@ -1,5 +1,6 @@
1
1
  export {
2
2
  Card,
3
+ cardVariants,
3
4
  CardAction,
4
5
  CardContent,
5
6
  CardDescription,
@@ -64,6 +64,7 @@ export function Checkbox(props: CheckboxProps) {
64
64
 
65
65
  return (
66
66
  <KobalteCheckbox
67
+ data-slot="checkbox"
67
68
  id={field ? undefined : local.id}
68
69
  title={local.title}
69
70
  class={cn('group/checkbox flex items-start gap-2.5', local.class)}
@@ -271,10 +271,33 @@ export type DialogContentProps = ComponentProps<typeof KobalteDialogContent> & {
271
271
  closeButton?: JSX.Element | false
272
272
  /** Use a 1rem inset as the positioner bounds for tall, viewport-filling surfaces. */
273
273
  positioner?: 'default' | 'inset'
274
+ /**
275
+ * The panel's maximum width. `md` (32rem) is the default and right for a
276
+ * confirmation or a short form; `sm` (28rem) for a single question; `lg`
277
+ * (42rem) for a picker or a form with two columns; `xl` (48rem) for a
278
+ * multi-step flow that needs a table or a preview beside its fields.
279
+ */
280
+ size?: DialogContentSize
274
281
  }
275
282
 
283
+ /** The dialog width ladder, so a caller picks a rung instead of a `max-w-*`. */
284
+ export const dialogContentSizes = {
285
+ sm: 'max-w-md',
286
+ md: 'max-w-lg',
287
+ lg: 'max-w-2xl',
288
+ xl: 'max-w-3xl',
289
+ } as const
290
+
291
+ export type DialogContentSize = keyof typeof dialogContentSizes
292
+
276
293
  export function DialogContent(props: DialogContentProps) {
277
- const [local, rest] = splitProps(props, ['class', 'children', 'closeButton', 'positioner'])
294
+ const [local, rest] = splitProps(props, [
295
+ 'class',
296
+ 'children',
297
+ 'closeButton',
298
+ 'positioner',
299
+ 'size',
300
+ ])
278
301
 
279
302
  return (
280
303
  <KobalteDialog.Portal>
@@ -284,7 +307,8 @@ export function DialogContent(props: DialogContentProps) {
284
307
  class={cn(
285
308
  dialogSurface,
286
309
  overlayMotion,
287
- 'relative grid w-full max-w-lg gap-4 p-5',
310
+ 'relative grid w-full gap-4 p-5',
311
+ dialogContentSizes[local.size ?? 'md'],
288
312
  local.class
289
313
  )}
290
314
  {...rest}
@@ -11,4 +11,5 @@ export {
11
11
  DialogTitle,
12
12
  DialogTrigger,
13
13
  type DialogContentProps,
14
+ type DialogContentSize,
14
15
  } from './dialog'