raft-ui 0.0.1

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 (134) hide show
  1. package/README.md +24 -0
  2. package/dist/cn.d.mts +2 -0
  3. package/dist/cn.mjs +2 -0
  4. package/dist/index.d.mts +2710 -0
  5. package/dist/index.mjs +4821 -0
  6. package/dist/label-DWq4ia5I.mjs +115 -0
  7. package/dist/styled-props-B3SNekJg.d.mts +16 -0
  8. package/dist/wip.d.mts +1238 -0
  9. package/dist/wip.mjs +1416 -0
  10. package/package.json +70 -0
  11. package/src/components/avatar/avatar.tsx +375 -0
  12. package/src/components/avatar/index.ts +17 -0
  13. package/src/components/badge/badge.tsx +393 -0
  14. package/src/components/badge/index.ts +2 -0
  15. package/src/components/banner/banner.tsx +269 -0
  16. package/src/components/banner/index.ts +8 -0
  17. package/src/components/bottom-sheet/bottom-sheet.tsx +152 -0
  18. package/src/components/bottom-sheet/index.ts +22 -0
  19. package/src/components/button/button.tsx +497 -0
  20. package/src/components/button/index.ts +2 -0
  21. package/src/components/checkbox/checkbox-indicator.tsx +128 -0
  22. package/src/components/checkbox/checkbox.tsx +350 -0
  23. package/src/components/checkbox/index.ts +2 -0
  24. package/src/components/combobox/combobox.tsx +603 -0
  25. package/src/components/combobox/index.ts +52 -0
  26. package/src/components/context-menu/context-menu.tsx +380 -0
  27. package/src/components/context-menu/index.ts +34 -0
  28. package/src/components/conversation-preview-card/conversation-preview-card.tsx +336 -0
  29. package/src/components/conversation-preview-card/index.ts +32 -0
  30. package/src/components/description-list/description-list.tsx +116 -0
  31. package/src/components/description-list/index.ts +14 -0
  32. package/src/components/dropdown-menu/dropdown-menu.tsx +405 -0
  33. package/src/components/dropdown-menu/index.ts +38 -0
  34. package/src/components/empty-state/empty-state.tsx +177 -0
  35. package/src/components/empty-state/index.ts +16 -0
  36. package/src/components/field/field.tsx +125 -0
  37. package/src/components/field/index.ts +18 -0
  38. package/src/components/inline-code/index.ts +2 -0
  39. package/src/components/inline-code/inline-code.tsx +33 -0
  40. package/src/components/input/index.ts +2 -0
  41. package/src/components/input/input.tsx +76 -0
  42. package/src/components/input-group/index.ts +7 -0
  43. package/src/components/input-group/input-group.tsx +215 -0
  44. package/src/components/kbd/index.ts +2 -0
  45. package/src/components/kbd/kbd.tsx +43 -0
  46. package/src/components/label/index.ts +7 -0
  47. package/src/components/label/label.tsx +99 -0
  48. package/src/components/lightbox/index.ts +24 -0
  49. package/src/components/lightbox/lightbox.tsx +245 -0
  50. package/src/components/list-item/index.ts +20 -0
  51. package/src/components/list-item/list-item.tsx +263 -0
  52. package/src/components/media-list-item/index.ts +20 -0
  53. package/src/components/media-list-item/media-list-item.tsx +169 -0
  54. package/src/components/notification-center/index.ts +39 -0
  55. package/src/components/notification-center/notification-center.tsx +558 -0
  56. package/src/components/panel-header/index.ts +22 -0
  57. package/src/components/panel-header/panel-header.tsx +199 -0
  58. package/src/components/popover/index.ts +30 -0
  59. package/src/components/popover/popover.tsx +248 -0
  60. package/src/components/preview-shell/index.ts +2 -0
  61. package/src/components/preview-shell/preview-shell.tsx +51 -0
  62. package/src/components/quoted-message-card/index.ts +36 -0
  63. package/src/components/quoted-message-card/quoted-message-card.tsx +391 -0
  64. package/src/components/radio-group/index.ts +6 -0
  65. package/src/components/radio-group/radio-group.tsx +119 -0
  66. package/src/components/section-header/index.ts +16 -0
  67. package/src/components/section-header/section-header.tsx +117 -0
  68. package/src/components/section-label/index.ts +2 -0
  69. package/src/components/section-label/section-label.tsx +38 -0
  70. package/src/components/segmented-control/index.ts +12 -0
  71. package/src/components/segmented-control/segmented-control.tsx +129 -0
  72. package/src/components/select/index.ts +40 -0
  73. package/src/components/select/select.tsx +382 -0
  74. package/src/components/spinner/index.ts +2 -0
  75. package/src/components/spinner/spinner.tsx +228 -0
  76. package/src/components/status/index.ts +2 -0
  77. package/src/components/status/status.tsx +152 -0
  78. package/src/components/tabs/index.ts +24 -0
  79. package/src/components/tabs/tabs.tsx +417 -0
  80. package/src/components/text/index.ts +2 -0
  81. package/src/components/text/text.tsx +130 -0
  82. package/src/components/textarea/index.ts +2 -0
  83. package/src/components/textarea/textarea.tsx +136 -0
  84. package/src/components/toggle-group/index.ts +12 -0
  85. package/src/components/toggle-group/toggle-group.tsx +111 -0
  86. package/src/components/tooltip/index.ts +14 -0
  87. package/src/components/tooltip/tooltip.tsx +186 -0
  88. package/src/fonts/brutal.css +2 -0
  89. package/src/index.ts +404 -0
  90. package/src/legacy/AttentionDot.tsx +28 -0
  91. package/src/legacy/AvatarListRow.tsx +87 -0
  92. package/src/legacy/AvatarSlot.tsx +157 -0
  93. package/src/legacy/Badge.tsx +95 -0
  94. package/src/legacy/Banner.tsx +74 -0
  95. package/src/legacy/BottomSheet.tsx +76 -0
  96. package/src/legacy/CheckMarker.tsx +72 -0
  97. package/src/legacy/Checkbox.tsx +81 -0
  98. package/src/legacy/ConversationPreviewCard.tsx +169 -0
  99. package/src/legacy/DismissBackdrop.tsx +68 -0
  100. package/src/legacy/EmptyState.tsx +63 -0
  101. package/src/legacy/ExperimentalBadge.tsx +19 -0
  102. package/src/legacy/FormField.tsx +106 -0
  103. package/src/legacy/KeyValueRow.tsx +67 -0
  104. package/src/legacy/Lightbox.tsx +119 -0
  105. package/src/legacy/NotificationCenter.tsx +217 -0
  106. package/src/legacy/PanelHeader.tsx +94 -0
  107. package/src/legacy/PreviewShell.tsx +40 -0
  108. package/src/legacy/QuotedMessageCard.tsx +181 -0
  109. package/src/legacy/ReorderablePanelTabs.tsx +151 -0
  110. package/src/legacy/SandboxedPreviewFrame.tsx +59 -0
  111. package/src/legacy/SearchInput.tsx +23 -0
  112. package/src/legacy/SectionEyebrow.tsx +60 -0
  113. package/src/legacy/SectionHeader.tsx +68 -0
  114. package/src/legacy/SegmentedControl.tsx +74 -0
  115. package/src/legacy/SlugInput.tsx +29 -0
  116. package/src/legacy/Spinner.tsx +89 -0
  117. package/src/legacy/StatusDot.tsx +51 -0
  118. package/src/legacy/SurfaceListItem.tsx +32 -0
  119. package/src/legacy/Textarea.tsx +137 -0
  120. package/src/legacy/button.tsx +100 -0
  121. package/src/legacy/context-menu-divider.tsx +12 -0
  122. package/src/legacy/menu-item.tsx +66 -0
  123. package/src/legacy/selection-popover.tsx +212 -0
  124. package/src/legacy/server-switcher-menu.tsx +203 -0
  125. package/src/legacy/source.css +240 -0
  126. package/src/lib/cn.ts +1 -0
  127. package/src/lib/styled-props.ts +11 -0
  128. package/src/lib/theme/theme-context.ts +28 -0
  129. package/src/lib/theme/theme-provider.tsx +181 -0
  130. package/src/lib/theme/use-theme.ts +12 -0
  131. package/src/lib/tv.ts +29 -0
  132. package/src/lib/without-children.ts +6 -0
  133. package/src/styles.css +467 -0
  134. package/src/wip.ts +255 -0
@@ -0,0 +1,393 @@
1
+ import { mergeProps } from "@base-ui/react/merge-props";
2
+ import { useRender } from "@base-ui/react/use-render";
3
+ import { tv, type VariantProps } from "../../lib/tv.ts";
4
+ import { useThemeFamily } from "../../lib/theme/use-theme.ts";
5
+
6
+ export const badge = tv({
7
+ slots: {
8
+ root: [
9
+ "inline-flex h-5 w-fit shrink-0 min-w-0 max-w-full items-center gap-1 px-1.5",
10
+ "overflow-hidden whitespace-nowrap",
11
+ "text-[10px] font-bold leading-none",
12
+ "[&_[data-slot='spinner']]:!size-3 [&_[data-slot='spinner']]:!text-xs",
13
+ ],
14
+ },
15
+ variants: {
16
+ theme: {
17
+ brutal: {
18
+ root: ["border border-line-strong"],
19
+ },
20
+ elegant: {
21
+ root: [
22
+ "gap-1.5 rounded-full border border-transparent px-2.5 py-0.5",
23
+ "[&:has(svg)]:px-2",
24
+ "[&_svg]:shrink-0 [&_svg]:translate-y-[0.5px]",
25
+ "text-[11px] font-medium leading-3 tracking-[0.22px]",
26
+ ],
27
+ },
28
+ },
29
+ appearance: {
30
+ solid: {
31
+ root: "",
32
+ },
33
+ soft: {
34
+ root: "",
35
+ },
36
+ outline: {
37
+ root: "",
38
+ },
39
+ },
40
+ variant: {
41
+ default: {
42
+ root: "bg-layer-panel text-foreground-strong",
43
+ },
44
+ primary: {
45
+ root: "bg-primary-400 text-primary-950",
46
+ },
47
+ information: {
48
+ root: "bg-info-base text-foreground-inverse",
49
+ },
50
+ muted: {
51
+ root: "bg-secondary-400 text-foreground-strong",
52
+ },
53
+ accent: {
54
+ root: "bg-accent-400 text-accent-950",
55
+ },
56
+ success: {
57
+ root: "bg-success-base text-success-dark",
58
+ },
59
+ warning: {
60
+ root: "bg-warning-base text-foreground-inverse",
61
+ },
62
+ danger: {
63
+ root: "bg-[oklch(0.66_0.19_31)] text-foreground-strong",
64
+ },
65
+ },
66
+ // Enables the old brutal casing recipe when a badge should read as a compact
67
+ // label. It defaults off so case-sensitive content stays intact.
68
+ uppercase: {
69
+ true: {
70
+ root: "uppercase tracking-wide",
71
+ },
72
+ false: {
73
+ root: "",
74
+ },
75
+ },
76
+ },
77
+ defaultVariants: {
78
+ appearance: "solid",
79
+ variant: "default",
80
+ uppercase: false,
81
+ },
82
+ compoundVariants: [
83
+ {
84
+ theme: "brutal",
85
+ appearance: "solid",
86
+ variant: "success",
87
+ class: { root: "bg-brutal-lime text-black" },
88
+ },
89
+ {
90
+ theme: "brutal",
91
+ appearance: "solid",
92
+ variant: "danger",
93
+ class: { root: "bg-brutal-red text-black" },
94
+ },
95
+ {
96
+ theme: "brutal",
97
+ appearance: "solid",
98
+ variant: "information",
99
+ class: { root: "bg-info-base text-info-dark" },
100
+ },
101
+ {
102
+ theme: "brutal",
103
+ appearance: "solid",
104
+ variant: "warning",
105
+ class: { root: "bg-warning-base text-black" },
106
+ },
107
+ {
108
+ theme: "brutal",
109
+ appearance: "soft",
110
+ variant: "default",
111
+ class: { root: "bg-layer-muted text-foreground-strong" },
112
+ },
113
+ {
114
+ theme: "brutal",
115
+ appearance: "soft",
116
+ variant: "muted",
117
+ class: { root: "bg-secondary-100 text-secondary-900" },
118
+ },
119
+ {
120
+ theme: "brutal",
121
+ appearance: "soft",
122
+ variant: "primary",
123
+ class: { root: "bg-[oklch(0.958_0.047_86)] text-primary-950" },
124
+ },
125
+ {
126
+ theme: "brutal",
127
+ appearance: "soft",
128
+ variant: "information",
129
+ class: { root: "bg-info-lighter text-info-dark" },
130
+ },
131
+ {
132
+ theme: "brutal",
133
+ appearance: "soft",
134
+ variant: "accent",
135
+ class: { root: "bg-accent-100 text-accent-950" },
136
+ },
137
+ {
138
+ theme: "brutal",
139
+ appearance: "soft",
140
+ variant: "success",
141
+ class: { root: "bg-success-lighter text-success-dark" },
142
+ },
143
+ {
144
+ theme: "brutal",
145
+ appearance: "soft",
146
+ variant: "warning",
147
+ class: { root: "bg-warning-lighter text-warning-dark" },
148
+ },
149
+ {
150
+ theme: "brutal",
151
+ appearance: "soft",
152
+ variant: "danger",
153
+ class: { root: "bg-danger-lighter text-danger-dark" },
154
+ },
155
+ {
156
+ theme: "brutal",
157
+ appearance: "outline",
158
+ variant: "default",
159
+ class: { root: "bg-transparent text-foreground-strong" },
160
+ },
161
+ {
162
+ theme: "brutal",
163
+ appearance: "outline",
164
+ variant: "muted",
165
+ class: { root: "bg-transparent text-secondary-900" },
166
+ },
167
+ {
168
+ theme: "brutal",
169
+ appearance: "outline",
170
+ variant: "primary",
171
+ class: { root: "bg-transparent text-primary-700" },
172
+ },
173
+ {
174
+ theme: "brutal",
175
+ appearance: "outline",
176
+ variant: "information",
177
+ class: { root: "bg-transparent text-info-dark" },
178
+ },
179
+ {
180
+ theme: "brutal",
181
+ appearance: "outline",
182
+ variant: "accent",
183
+ class: { root: "bg-transparent text-accent-700" },
184
+ },
185
+ {
186
+ theme: "brutal",
187
+ appearance: "outline",
188
+ variant: "success",
189
+ class: { root: "bg-transparent text-[oklch(0.48_0.12_153.079)]" },
190
+ },
191
+ {
192
+ theme: "brutal",
193
+ appearance: "outline",
194
+ variant: "warning",
195
+ class: { root: "bg-transparent text-warning-dark" },
196
+ },
197
+ {
198
+ theme: "brutal",
199
+ appearance: "outline",
200
+ variant: "danger",
201
+ class: { root: "bg-transparent text-[oklch(0.54_0.19_31)]" },
202
+ },
203
+ {
204
+ theme: "elegant",
205
+ appearance: "solid",
206
+ variant: "default",
207
+ class: {
208
+ root: "bg-line-muted text-foreground-muted",
209
+ },
210
+ },
211
+ {
212
+ theme: "elegant",
213
+ appearance: "solid",
214
+ variant: "muted",
215
+ class: { root: "bg-[oklch(0.46_0.004_286)] text-[oklch(0.94_0.001_286)]" },
216
+ },
217
+ {
218
+ theme: "elegant",
219
+ appearance: "solid",
220
+ variant: "primary",
221
+ class: { root: "bg-primary-400 text-primary-950" },
222
+ },
223
+ {
224
+ theme: "elegant",
225
+ appearance: "solid",
226
+ variant: "information",
227
+ class: { root: "bg-info-base text-foreground-inverse" },
228
+ },
229
+ {
230
+ theme: "elegant",
231
+ appearance: "solid",
232
+ variant: "accent",
233
+ class: { root: "bg-accent-400 text-foreground-inverse" },
234
+ },
235
+ {
236
+ theme: "elegant",
237
+ appearance: "solid",
238
+ variant: "success",
239
+ class: { root: "bg-success-base text-foreground-inverse" },
240
+ },
241
+ {
242
+ theme: "elegant",
243
+ appearance: "solid",
244
+ variant: "warning",
245
+ class: { root: "bg-warning-base text-foreground-inverse" },
246
+ },
247
+ {
248
+ theme: "elegant",
249
+ appearance: "solid",
250
+ variant: "danger",
251
+ class: { root: "bg-[oklch(0.68_0.22_26.758)] text-foreground-inverse" },
252
+ },
253
+ {
254
+ theme: "elegant",
255
+ appearance: "soft",
256
+ variant: "default",
257
+ class: { root: "border-transparent bg-layer-muted text-foreground-strong" },
258
+ },
259
+ {
260
+ theme: "elegant",
261
+ appearance: "soft",
262
+ variant: "muted",
263
+ class: { root: "border-transparent bg-secondary-100 text-secondary-900" },
264
+ },
265
+ {
266
+ theme: "elegant",
267
+ appearance: "soft",
268
+ variant: "primary",
269
+ class: { root: "border-transparent bg-[oklch(0.958_0.047_86)] text-primary-950" },
270
+ },
271
+ {
272
+ theme: "elegant",
273
+ appearance: "soft",
274
+ variant: "information",
275
+ class: { root: "border-transparent bg-info-lighter text-info-dark" },
276
+ },
277
+ {
278
+ theme: "elegant",
279
+ appearance: "soft",
280
+ variant: "accent",
281
+ class: { root: "border-transparent bg-accent-100 text-accent-950" },
282
+ },
283
+ {
284
+ theme: "elegant",
285
+ appearance: "soft",
286
+ variant: "success",
287
+ class: { root: "border-transparent bg-success-lighter text-success-dark" },
288
+ },
289
+ {
290
+ theme: "elegant",
291
+ appearance: "soft",
292
+ variant: "warning",
293
+ class: { root: "border-transparent bg-warning-lighter text-warning-dark" },
294
+ },
295
+ {
296
+ theme: "elegant",
297
+ appearance: "soft",
298
+ variant: "danger",
299
+ class: { root: "border-transparent bg-danger-lighter text-danger-dark" },
300
+ },
301
+ {
302
+ theme: "elegant",
303
+ appearance: "outline",
304
+ variant: "default",
305
+ class: { root: "border-line-subtle bg-transparent text-foreground-strong" },
306
+ },
307
+ {
308
+ theme: "elegant",
309
+ appearance: "outline",
310
+ variant: "muted",
311
+ class: { root: "border-secondary-500 bg-transparent text-secondary-900" },
312
+ },
313
+ {
314
+ theme: "elegant",
315
+ appearance: "outline",
316
+ variant: "primary",
317
+ class: { root: "border-primary-500 bg-transparent text-primary-800" },
318
+ },
319
+ {
320
+ theme: "elegant",
321
+ appearance: "outline",
322
+ variant: "information",
323
+ class: { root: "border-info-base bg-transparent text-[oklch(0.48_0.09_219.2)]" },
324
+ },
325
+ {
326
+ theme: "elegant",
327
+ appearance: "outline",
328
+ variant: "accent",
329
+ class: { root: "border-accent-500 bg-transparent text-accent-800" },
330
+ },
331
+ {
332
+ theme: "elegant",
333
+ appearance: "outline",
334
+ variant: "success",
335
+ class: { root: "border-success-base bg-transparent text-success-dark" },
336
+ },
337
+ {
338
+ theme: "elegant",
339
+ appearance: "outline",
340
+ variant: "warning",
341
+ class: { root: "border-warning-base bg-transparent text-warning-dark" },
342
+ },
343
+ {
344
+ theme: "elegant",
345
+ appearance: "outline",
346
+ variant: "danger",
347
+ class: { root: "border-danger-base bg-transparent text-danger-dark" },
348
+ },
349
+ ],
350
+ });
351
+
352
+ export type BadgeProps = useRender.ComponentProps<"span"> &
353
+ Omit<VariantProps<typeof badge>, "theme">;
354
+
355
+ function BadgeRoot({ appearance, variant, uppercase, className, render, ...props }: BadgeProps) {
356
+ const theme = useThemeFamily();
357
+ const resolvedAppearance = appearance ?? "solid";
358
+ const resolvedUppercase = uppercase ?? false;
359
+ const { root } = badge({
360
+ theme,
361
+ appearance: resolvedAppearance,
362
+ variant,
363
+ uppercase: resolvedUppercase,
364
+ });
365
+ const defaultProps: useRender.ElementProps<"span"> = {
366
+ className: root({ className }),
367
+ };
368
+
369
+ return useRender({
370
+ defaultTagName: "span",
371
+ render,
372
+ props: mergeProps<"span">(defaultProps, props),
373
+ state: {
374
+ slot: "badge",
375
+ appearance: resolvedAppearance,
376
+ variant,
377
+ uppercase: resolvedUppercase,
378
+ },
379
+ });
380
+ }
381
+
382
+ // Fixed success + uppercase "Experimental" preset. The visual identity lives in
383
+ // Badge, so every experimental surface stays identical. Attached as a static
384
+ // because it only presets props.
385
+ function Experimental(props: Omit<BadgeProps, "appearance" | "variant" | "uppercase">) {
386
+ return (
387
+ <BadgeRoot variant="success" uppercase {...props}>
388
+ Experimental
389
+ </BadgeRoot>
390
+ );
391
+ }
392
+
393
+ export const Badge = Object.assign(BadgeRoot, { Experimental });
@@ -0,0 +1,2 @@
1
+ export { Badge } from "./badge.tsx";
2
+ export type { BadgeProps } from "./badge.tsx";
@@ -0,0 +1,269 @@
1
+ import { mergeProps } from "@base-ui/react/merge-props";
2
+ import { useRender } from "@base-ui/react/use-render";
3
+ import { tv, type VariantProps } from "../../lib/tv.ts";
4
+ import { useThemeFamily } from "../../lib/theme/use-theme.ts";
5
+
6
+ const banner = tv({
7
+ slots: {
8
+ root: [""],
9
+ title: [""],
10
+ description: [""],
11
+ action: [""],
12
+ },
13
+ variants: {
14
+ theme: {
15
+ brutal: {
16
+ root: [
17
+ "group/banner grid grid-cols-[0_minmax(0,1fr)] items-start border-2 border-line-strong",
18
+ "has-[>[data-slot=banner-action]]:grid-cols-[0_minmax(0,1fr)_auto]",
19
+ "has-[>svg]:grid-cols-[18px_minmax(0,1fr)]",
20
+ "[&:has(>svg):has(>[data-slot=banner-action])]:grid-cols-[18px_minmax(0,1fr)_auto]",
21
+ "[&>svg]:col-start-1 [&>svg]:row-span-2 [&>svg]:mt-0.5",
22
+ "[&>svg]:size-[18px] [&>svg]:shrink-0 [&>svg]:text-foreground-strong",
23
+ ],
24
+ title: [
25
+ "col-start-2 mb-0.5 text-sm font-bold text-foreground-strong",
26
+ "group-data-[size=sm]/banner:text-xs",
27
+ ],
28
+ description: [
29
+ "col-start-2 min-w-0 text-sm text-foreground-strong",
30
+ "group-data-[size=sm]/banner:text-xs",
31
+ ],
32
+ action: ["col-start-3 row-span-2 row-start-1 shrink-0"],
33
+ },
34
+ elegant: {
35
+ root: [
36
+ "group/banner grid w-full items-center gap-x-2 gap-y-0 rounded-sm border-0",
37
+ "text-[0.8125rem] leading-5 tracking-[-0.005em] text-foreground-strong",
38
+ "grid-cols-[minmax(0,1fr)]",
39
+ "has-[>svg]:grid-cols-[auto_minmax(0,1fr)]",
40
+ "has-[>[data-slot=banner-action]]:grid-cols-[minmax(0,1fr)_auto]",
41
+ "has-[>svg]:has-[>[data-slot=banner-action]]:grid-cols-[auto_minmax(0,1fr)_auto]",
42
+ "has-[>[data-slot=banner-title]]:has-[>[data-slot=banner-description]]:items-start",
43
+ "has-[>[data-slot=banner-title]]:has-[>[data-slot=banner-description]]:grid-rows-[auto_auto]",
44
+ "has-[>[data-slot=banner-title]]:has-[>[data-slot=banner-description]]:gap-y-1",
45
+ "[&>svg]:col-start-1 [&>svg]:row-start-1 [&>svg]:size-4 [&>svg]:shrink-0 [&>svg]:self-center",
46
+ ],
47
+ title: [
48
+ "col-start-1 row-start-1 flex h-5 min-w-0 items-center text-[0.84375rem] font-medium leading-5 text-foreground-strong",
49
+ "group-has-[>svg]/banner:col-start-2",
50
+ "group-data-[size=sm]/banner:h-4 group-data-[size=sm]/banner:text-[0.8125rem] group-data-[size=sm]/banner:leading-4",
51
+ "group-data-[size=lg]/banner:h-6 group-data-[size=lg]/banner:text-[0.90625rem] group-data-[size=lg]/banner:leading-6",
52
+ "group-data-[status=warning]/banner:text-[oklch(0.476_0.114_61.907)]",
53
+ ],
54
+ description: [
55
+ "col-start-1 row-start-1 min-w-0 font-normal leading-4 text-foreground-muted",
56
+ "group-has-[>svg]/banner:col-start-2",
57
+ "group-has-[>[data-slot=banner-title]]/banner:row-start-2",
58
+ "group-data-[size=sm]/banner:text-xs group-data-[size=sm]/banner:leading-4",
59
+ "group-data-[size=lg]/banner:text-[0.875rem] group-data-[size=lg]/banner:leading-5",
60
+ "group-data-[status=warning]/banner:text-[oklch(0.476_0.114_61.907)]",
61
+ ],
62
+ action: [
63
+ "col-start-2 row-start-1 flex h-5 shrink-0 items-center gap-2",
64
+ "group-has-[>svg]/banner:col-start-3",
65
+ "group-has-[>[data-slot=banner-title]+[data-slot=banner-description]]/banner:row-span-2",
66
+ "[&>button:has(svg):last-child]:size-5 [&>button:has(svg):last-child]:min-h-5 [&>button:has(svg):last-child]:min-w-5",
67
+ "[&>button:has(svg):last-child]:rounded-sm",
68
+ "[&>button:has(svg):last-child]:border-transparent [&>button:has(svg):last-child]:bg-transparent [&>button:has(svg):last-child]:shadow-none",
69
+ "[&>button:has(svg):last-child]:text-current/45",
70
+ "[&>button:has(svg):last-child]:transition-colors [&>button:has(svg):last-child]:duration-200",
71
+ "[&>button:has(svg):last-child]:hover:border-transparent [&>button:has(svg):last-child]:hover:bg-foreground/5",
72
+ "[&>button:has(svg):last-child]:hover:text-current/70",
73
+ "[&>button:has(svg):last-child>svg]:size-4",
74
+ "group-data-[size=sm]/banner:h-4 group-data-[size=sm]/banner:[&>button:has(svg):last-child]:size-4",
75
+ "group-data-[size=sm]/banner:[&>button:has(svg):last-child]:min-h-4 group-data-[size=sm]/banner:[&>button:has(svg):last-child]:min-w-4",
76
+ "group-data-[size=sm]/banner:[&>button:has(svg):last-child>svg]:size-3",
77
+ "group-data-[size=lg]/banner:h-6 group-data-[size=lg]/banner:[&>button:has(svg):last-child]:size-6",
78
+ "group-data-[size=lg]/banner:[&>button:has(svg):last-child]:min-h-6 group-data-[size=lg]/banner:[&>button:has(svg):last-child]:min-w-6",
79
+ ],
80
+ },
81
+ },
82
+ status: {
83
+ default: {},
84
+ destructive: {},
85
+ warning: {},
86
+ info: {},
87
+ success: {},
88
+ },
89
+ size: {
90
+ sm: {},
91
+ md: {},
92
+ lg: {},
93
+ },
94
+ align: {
95
+ top: { action: "self-start" },
96
+ middle: { action: "self-center" },
97
+ },
98
+ },
99
+ defaultVariants: {
100
+ size: "md",
101
+ align: "middle",
102
+ },
103
+ compoundVariants: [
104
+ { theme: "brutal", status: "default", class: { root: "bg-layer-panel" } },
105
+ { theme: "brutal", status: "destructive", class: { root: "bg-danger-base/20" } },
106
+ { theme: "brutal", status: "warning", class: { root: "bg-warning-base/20" } },
107
+ { theme: "brutal", status: "info", class: { root: "bg-primary-400/30" } },
108
+ { theme: "brutal", status: "success", class: { root: "bg-success-base/20" } },
109
+ {
110
+ theme: "brutal",
111
+ size: "sm",
112
+ class: { root: "gap-y-0 p-2 has-[>svg]:gap-x-2 has-[>[data-slot=banner-action]]:gap-x-2" },
113
+ },
114
+ {
115
+ theme: "brutal",
116
+ size: "md",
117
+ class: { root: "gap-y-0 p-3 has-[>svg]:gap-x-3 has-[>[data-slot=banner-action]]:gap-x-3" },
118
+ },
119
+ {
120
+ theme: "brutal",
121
+ size: "lg",
122
+ class: {
123
+ root: "gap-y-0 p-4 shadow-sm has-[>svg]:gap-x-3 has-[>[data-slot=banner-action]]:gap-x-3",
124
+ },
125
+ },
126
+ {
127
+ theme: "elegant",
128
+ status: "default",
129
+ class: {
130
+ root: "bg-layer-muted [&>svg]:text-foreground-muted",
131
+ },
132
+ },
133
+ {
134
+ theme: "elegant",
135
+ status: "success",
136
+ class: {
137
+ root: "bg-[oklch(0.94_0.035_153.079)] [&>svg]:text-success-base",
138
+ },
139
+ },
140
+ {
141
+ theme: "elegant",
142
+ status: "warning",
143
+ class: {
144
+ root: "bg-[oklch(0.973_0.071_103.193)] text-[oklch(0.476_0.114_61.907)] [&>svg]:text-[oklch(0.476_0.114_61.907)]",
145
+ },
146
+ },
147
+ {
148
+ theme: "elegant",
149
+ status: "info",
150
+ class: {
151
+ root: "bg-info-lighter [&>svg]:text-[oklch(0.55_0.11_220)]",
152
+ },
153
+ },
154
+ {
155
+ theme: "elegant",
156
+ status: "destructive",
157
+ class: {
158
+ root: "bg-danger-lighter [&>svg]:text-danger-base",
159
+ },
160
+ },
161
+ {
162
+ theme: "elegant",
163
+ size: "sm",
164
+ class: {
165
+ root: "py-2.5 pl-2.5 pr-2 text-xs leading-4 [&>svg]:size-3.5",
166
+ },
167
+ },
168
+ {
169
+ theme: "elegant",
170
+ size: "md",
171
+ class: {
172
+ root: "px-3 py-3",
173
+ },
174
+ },
175
+ {
176
+ theme: "elegant",
177
+ size: "lg",
178
+ class: {
179
+ root: "gap-x-2 px-3.5 py-3 text-sm leading-5 [&>svg]:size-[18px]",
180
+ },
181
+ },
182
+ ],
183
+ });
184
+
185
+ export type BannerStatus = NonNullable<VariantProps<typeof banner>["status"]>;
186
+
187
+ export type BannerProps = useRender.ComponentProps<"div"> &
188
+ Omit<VariantProps<typeof banner>, "theme" | "align"> & {
189
+ status: BannerStatus;
190
+ };
191
+
192
+ export function Banner({ status, size = "md", className, render, ...props }: BannerProps) {
193
+ const theme = useThemeFamily();
194
+ const { root } = banner({ theme, status, size });
195
+ const defaultProps: useRender.ElementProps<"div"> = {
196
+ className: root({ className }),
197
+ role: "alert",
198
+ };
199
+
200
+ return useRender({
201
+ defaultTagName: "div",
202
+ render,
203
+ props: mergeProps<"div">(defaultProps, props),
204
+ state: {
205
+ slot: "banner",
206
+ size,
207
+ status,
208
+ },
209
+ });
210
+ }
211
+
212
+ export type BannerTitleProps = useRender.ComponentProps<"div">;
213
+
214
+ export function BannerTitle({ render, className, ...props }: BannerTitleProps) {
215
+ const theme = useThemeFamily();
216
+ const { title } = banner({ theme });
217
+ const defaultProps: useRender.ElementProps<"div"> = {
218
+ className: title({ className }),
219
+ };
220
+
221
+ return useRender({
222
+ defaultTagName: "div",
223
+ render,
224
+ props: mergeProps<"div">(defaultProps, props),
225
+ state: {
226
+ slot: "banner-title",
227
+ },
228
+ });
229
+ }
230
+
231
+ export type BannerDescriptionProps = useRender.ComponentProps<"div">;
232
+
233
+ export function BannerDescription({ render, className, ...props }: BannerDescriptionProps) {
234
+ const theme = useThemeFamily();
235
+ const { description } = banner({ theme });
236
+ const defaultProps: useRender.ElementProps<"div"> = {
237
+ className: description({ className }),
238
+ };
239
+
240
+ return useRender({
241
+ defaultTagName: "div",
242
+ render,
243
+ props: mergeProps<"div">(defaultProps, props),
244
+ state: {
245
+ slot: "banner-description",
246
+ },
247
+ });
248
+ }
249
+
250
+ export type BannerActionProps = Omit<useRender.ComponentProps<"div">, "align"> &
251
+ Pick<VariantProps<typeof banner>, "align">;
252
+
253
+ export function BannerAction({ align = "middle", render, className, ...props }: BannerActionProps) {
254
+ const theme = useThemeFamily();
255
+ const { action } = banner({ theme, align });
256
+ const defaultProps: useRender.ElementProps<"div"> = {
257
+ className: action({ className }),
258
+ };
259
+
260
+ return useRender({
261
+ defaultTagName: "div",
262
+ render,
263
+ props: mergeProps<"div">(defaultProps, props),
264
+ state: {
265
+ slot: "banner-action",
266
+ align,
267
+ },
268
+ });
269
+ }
@@ -0,0 +1,8 @@
1
+ export { Banner, BannerAction, BannerDescription, BannerTitle } from "./banner.tsx";
2
+ export type {
3
+ BannerActionProps,
4
+ BannerDescriptionProps,
5
+ BannerProps,
6
+ BannerStatus,
7
+ BannerTitleProps,
8
+ } from "./banner.tsx";