@nebutra/ui 0.2.1 → 0.2.3

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 (56) hide show
  1. package/LICENSE +21 -676
  2. package/README.md +81 -86
  3. package/dist/agent/index.d.ts +119 -0
  4. package/dist/agent/index.js +135 -0
  5. package/dist/agent/index.js.map +1 -0
  6. package/dist/canonical-Drca5UMj.d.ts +4309 -0
  7. package/dist/components/index.d.ts +51 -56
  8. package/dist/components/index.js +1696 -1203
  9. package/dist/components/index.js.map +1 -1
  10. package/dist/hooks/index.d.ts +62 -15
  11. package/dist/hooks/index.js +56 -34
  12. package/dist/hooks/index.js.map +1 -1
  13. package/dist/index-CKLIGfiU.d.ts +19 -0
  14. package/dist/index-Dg4jRJV2.d.ts +57 -0
  15. package/dist/layout/index.d.ts +7 -3
  16. package/dist/layout/index.js +525 -542
  17. package/dist/layout/index.js.map +1 -1
  18. package/dist/layouts/index.d.ts +80 -2
  19. package/dist/layouts/index.js +32 -19
  20. package/dist/layouts/index.js.map +1 -1
  21. package/dist/patterns/index.d.ts +131 -5
  22. package/dist/patterns/index.js +1594 -806
  23. package/dist/patterns/index.js.map +1 -1
  24. package/dist/primitives/canonical.d.ts +25 -0
  25. package/dist/primitives/canonical.js +12269 -0
  26. package/dist/primitives/canonical.js.map +1 -0
  27. package/dist/primitives/index.d.ts +694 -3544
  28. package/dist/primitives/index.js +8994 -6583
  29. package/dist/primitives/index.js.map +1 -1
  30. package/dist/shared/animation/css/index.d.ts +1 -0
  31. package/dist/shared/animation/css/index.js +14 -0
  32. package/dist/shared/animation/css/index.js.map +1 -0
  33. package/dist/shared/animation/index.d.ts +6 -0
  34. package/dist/shared/animation/index.js +272 -0
  35. package/dist/shared/animation/index.js.map +1 -0
  36. package/dist/shared/animation/motion/index.d.ts +4 -0
  37. package/dist/shared/animation/motion/index.js +205 -0
  38. package/dist/shared/animation/motion/index.js.map +1 -0
  39. package/dist/styles/brand-override.css +11 -11
  40. package/dist/tailwind.preset.d.ts +10 -10
  41. package/dist/tailwind.preset.js +7 -4
  42. package/dist/tailwind.preset.js.map +1 -1
  43. package/dist/theme/index.d.ts +2 -2
  44. package/dist/tokens-EAC6uPem.d.ts +302 -0
  45. package/dist/typography/fonts.css +51 -37
  46. package/dist/typography/index.d.ts +27 -27
  47. package/dist/typography/index.js +24 -4
  48. package/dist/typography/index.js.map +1 -1
  49. package/dist/utils/index.d.ts +66 -14
  50. package/dist/utils/index.js +53 -10
  51. package/dist/utils/index.js.map +1 -1
  52. package/package.json +56 -14
  53. package/src/styles/brand-override.css +61 -0
  54. package/src/styles/preset.css +29 -0
  55. package/src/styles/sources.css +37 -0
  56. package/src/typography/fonts.css +124 -0
@@ -1,6 +1,6 @@
1
1
  "use client";
2
- import { Cross, Warning, External, Menu } from '@nebutra/icons';
3
- import * as React from 'react';
2
+ import { Menu, Cross, Warning } from '@nebutra/icons';
3
+ import * as React4 from 'react';
4
4
  import { createContext, useState, useEffect, useMemo, useCallback } from 'react';
5
5
  import { Dialog } from '@base-ui/react/dialog';
6
6
  import { cva } from 'class-variance-authority';
@@ -95,13 +95,34 @@ var primitiveFontWeight = {
95
95
  semibold: 600};
96
96
  var primitiveTransition = {
97
97
  duration: {
98
- // standard state transitions (default)
99
- reveal: 300},
98
+ // hover, focus, small state changes
99
+ flow: 200},
100
100
  easing: {
101
- inOut: "cubic-bezier(0.4, 0, 0.2, 1)"
102
- }
101
+ default: "ease-out"}
103
102
  };
104
103
 
104
+ // src/tokens/components/overlay.ts
105
+ var overlayFocusRingClassName = "outline-none";
106
+ var overlayZIndex = {
107
+ backdrop: 1040,
108
+ modal: 1050};
109
+ var overlayTokens = {
110
+ motion: {
111
+ duration: primitiveTransition.duration.flow,
112
+ easing: primitiveTransition.easing.default}};
113
+ var overlayClassNames = {
114
+ focusRing: overlayFocusRingClassName,
115
+ sheetBackdrop: [
116
+ "fixed inset-0 bg-[var(--sheet-overlay-background)] backdrop-blur-[var(--sheet-overlay-blur)]",
117
+ "transition-[opacity,backdrop-filter,display] duration-[var(--motion-duration-flow)] ease-[var(--ease-out)]",
118
+ "data-ending-style:opacity-0 data-starting-style:opacity-0 motion-reduce:transition-none"
119
+ ].join(" "),
120
+ sheetSurface: [
121
+ "fixed flex flex-col overflow-hidden border border-border bg-[var(--sheet-background)] text-foreground shadow-[var(--sheet-shadow)]",
122
+ "outline-none transition-[opacity,transform,display] duration-[var(--motion-duration-flow)] ease-[var(--ease-out)]",
123
+ "data-ending-style:opacity-0 data-starting-style:opacity-0 motion-reduce:transition-none"
124
+ ].join(" ")};
125
+
105
126
  // src/tokens/components/sheet.ts
106
127
  var sheetTokens = {
107
128
  inset: primitiveSpacing[3],
@@ -129,15 +150,16 @@ var sheetTokens = {
129
150
  surface: {
130
151
  background: "hsl(var(--popover))",
131
152
  shadow: "var(--elevation-xl)"
132
- },
133
- motion: {
134
- duration: primitiveTransition.duration.reveal,
135
- easing: primitiveTransition.easing.inOut
136
- }
137
- };
153
+ }};
138
154
  function cn(...inputs) {
139
155
  return twMerge(clsx(inputs));
140
156
  }
157
+
158
+ // src/utils/primitive-props.ts
159
+ function asPlainStyle(style) {
160
+ if (style == null || typeof style === "function") return {};
161
+ return style;
162
+ }
141
163
  function getSheetStyle(style) {
142
164
  return {
143
165
  "--sheet-inset": `${sheetTokens.inset}px`,
@@ -158,9 +180,9 @@ function getSheetStyle(style) {
158
180
  "--sheet-overlay-blur": sheetTokens.overlay.blur,
159
181
  "--sheet-background": sheetTokens.surface.background,
160
182
  "--sheet-shadow": sheetTokens.surface.shadow,
161
- "--sheet-duration": `${sheetTokens.motion.duration}ms`,
162
- "--sheet-easing": sheetTokens.motion.easing,
163
- ...style
183
+ "--sheet-duration": `${overlayTokens.motion.duration}ms`,
184
+ "--sheet-easing": overlayTokens.motion.easing,
185
+ ...asPlainStyle(style)
164
186
  };
165
187
  }
166
188
  function Sheet({ modal = "trap-focus", disablePointerDismissal = true, ...props }) {
@@ -175,199 +197,107 @@ function Sheet({ modal = "trap-focus", disablePointerDismissal = true, ...props
175
197
  );
176
198
  }
177
199
  Sheet.displayName = "Sheet";
178
- var SheetTrigger = React.forwardRef(
179
- ({ asChild, children, ...props }, ref) => {
180
- if (asChild && React.isValidElement(children)) {
181
- return /* @__PURE__ */ jsx(
182
- Dialog.Trigger,
183
- {
184
- ref,
185
- "data-slot": "sheet-trigger",
186
- ...props,
187
- render: children
188
- }
189
- );
190
- }
191
- return /* @__PURE__ */ jsx(Dialog.Trigger, { ref, "data-slot": "sheet-trigger", ...props, children });
192
- }
193
- );
194
- SheetTrigger.displayName = "SheetTrigger";
195
- var SheetClose = React.forwardRef(
196
- ({ asChild, children, ...props }, ref) => {
197
- if (asChild && React.isValidElement(children)) {
198
- return /* @__PURE__ */ jsx(
199
- Dialog.Close,
200
- {
201
- ref,
202
- "data-slot": "sheet-close",
203
- ...props,
204
- render: children
205
- }
206
- );
207
- }
208
- return /* @__PURE__ */ jsx(Dialog.Close, { ref, "data-slot": "sheet-close", ...props, children });
200
+ var SheetClose = ({
201
+ asChild,
202
+ children,
203
+ ref,
204
+ ...props
205
+ }) => {
206
+ if (asChild && React4.isValidElement(children)) {
207
+ return /* @__PURE__ */ jsx(
208
+ Dialog.Close,
209
+ {
210
+ ref,
211
+ "data-slot": "sheet-close",
212
+ ...props,
213
+ render: children
214
+ }
215
+ );
209
216
  }
210
- );
217
+ return /* @__PURE__ */ jsx(Dialog.Close, { ref, "data-slot": "sheet-close", ...props, children });
218
+ };
211
219
  SheetClose.displayName = "SheetClose";
212
220
  function SheetPortal(props) {
213
221
  return /* @__PURE__ */ jsx(Dialog.Portal, { "data-slot": "sheet-portal", ...props });
214
222
  }
215
223
  SheetPortal.displayName = "SheetPortal";
216
- var SheetOverlay = React.forwardRef(
217
- ({ className, style, ...props }, ref) => /* @__PURE__ */ jsx(
218
- Dialog.Backdrop,
219
- {
220
- ref,
221
- "data-slot": "sheet-overlay",
222
- className: cn(
223
- "fixed inset-0 z-50 bg-[var(--sheet-overlay-background)] backdrop-blur-[var(--sheet-overlay-blur)]",
224
- "transition-[opacity,backdrop-filter,display] duration-[var(--sheet-duration)] ease-[var(--sheet-easing)]",
225
- "data-ending-style:opacity-0 data-starting-style:opacity-0 motion-reduce:transition-none",
226
- className
227
- ),
228
- style: getSheetStyle(style),
229
- ...props
230
- }
231
- )
232
- );
233
- SheetOverlay.displayName = "SheetOverlay";
234
- var sheetVariants = cva(
235
- [
236
- "fixed z-50 flex flex-col overflow-hidden border border-border bg-[var(--sheet-background)] text-foreground shadow-[var(--sheet-shadow)] outline-none",
237
- "transition-[opacity,transform,display] duration-[var(--sheet-duration)] ease-[var(--sheet-easing)]",
238
- "data-ending-style:opacity-0 data-starting-style:opacity-0 motion-reduce:transition-none"
239
- ].join(" "),
224
+ var SheetOverlay = ({
225
+ className,
226
+ style,
227
+ ref,
228
+ ...props
229
+ }) => /* @__PURE__ */ jsx(
230
+ Dialog.Backdrop,
240
231
  {
241
- variants: {
242
- side: {
243
- top: "inset-x-[var(--sheet-inset)] top-[var(--sheet-inset)] max-h-[min(var(--sheet-edge-height),calc(100dvh_-_var(--sheet-inset)_-_var(--sheet-inset)))] rounded-[var(--sheet-radius)] data-ending-style:-translate-y-full data-starting-style:-translate-y-full",
244
- bottom: "inset-x-[var(--sheet-inset)] bottom-[var(--sheet-inset)] max-h-[min(var(--sheet-edge-height),calc(100dvh_-_var(--sheet-inset)_-_var(--sheet-inset)))] rounded-[var(--sheet-radius)] data-ending-style:translate-y-full data-starting-style:translate-y-full",
245
- left: "inset-y-[var(--sheet-inset)] left-[var(--sheet-inset)] h-[calc(100dvh_-_var(--sheet-inset)_-_var(--sheet-inset))] w-[min(var(--sheet-side-width),calc(100vw_-_var(--sheet-inset)_-_var(--sheet-inset)))] rounded-[var(--sheet-radius)] data-ending-style:-translate-x-full data-starting-style:-translate-x-full",
246
- right: "inset-y-[var(--sheet-inset)] right-[var(--sheet-inset)] h-[calc(100dvh_-_var(--sheet-inset)_-_var(--sheet-inset))] w-[min(var(--sheet-side-width),calc(100vw_-_var(--sheet-inset)_-_var(--sheet-inset)))] rounded-[var(--sheet-radius)] data-ending-style:translate-x-full data-starting-style:translate-x-full"
247
- }
248
- },
249
- defaultVariants: {
250
- side: "right"
251
- }
252
- }
253
- );
254
- var SheetContent = React.forwardRef(
255
- ({
256
- side = "right",
257
- className,
258
- children,
259
- overlay = true,
260
- noOverlay = false,
261
- showClose,
262
- close,
263
- style,
232
+ ref,
233
+ "data-slot": "sheet-overlay",
234
+ className: cn(overlayClassNames.sheetBackdrop, className),
235
+ style: { zIndex: overlayZIndex.backdrop, ...getSheetStyle(style) },
264
236
  ...props
265
- }, ref) => {
266
- const shouldRenderClose = close ?? showClose ?? true;
267
- const shouldRenderOverlay = overlay && !noOverlay;
268
- return /* @__PURE__ */ jsxs(SheetPortal, { children: [
269
- shouldRenderOverlay ? /* @__PURE__ */ jsx(SheetOverlay, {}) : null,
270
- /* @__PURE__ */ jsxs(
271
- Dialog.Popup,
272
- {
273
- ref,
274
- "data-slot": "sheet-content",
275
- className: cn(sheetVariants({ side }), className),
276
- style: getSheetStyle(style),
277
- ...props,
278
- children: [
279
- children,
280
- shouldRenderClose ? /* @__PURE__ */ jsxs(
281
- SheetClose,
282
- {
283
- "aria-label": "Close",
284
- className: cn(
285
- "absolute right-[var(--sheet-close-offset)] top-[var(--sheet-close-offset)] inline-flex size-[var(--sheet-close-size)] items-center justify-center rounded-[var(--sheet-close-radius)] text-muted-foreground",
286
- "transition-[background-color,color,box-shadow] duration-[var(--sheet-duration)] ease-[var(--sheet-easing)] hover:bg-muted hover:text-foreground",
287
- "focus:outline-none focus-visible:ring-2 focus-visible:ring-ring focus-visible:ring-offset-2 disabled:pointer-events-none motion-reduce:transition-none"
288
- ),
289
- children: [
290
- /* @__PURE__ */ jsx(Cross, { "aria-hidden": "true", className: "size-[var(--sheet-close-icon-size)]" }),
291
- /* @__PURE__ */ jsx("span", { className: "sr-only", children: "Close" })
292
- ]
293
- }
294
- ) : null
295
- ]
296
- }
297
- )
298
- ] });
299
237
  }
300
238
  );
301
- SheetContent.displayName = "SheetContent";
302
- var SheetHeader = React.forwardRef(
303
- ({ className, ...props }, ref) => /* @__PURE__ */ jsx(
304
- "div",
305
- {
306
- ref,
307
- "data-slot": "sheet-header",
308
- className: cn(
309
- "grid gap-[var(--sheet-header-gap)] border-b border-border px-[var(--sheet-padding-x)] py-[var(--sheet-padding-y)] pr-[calc(var(--sheet-padding-x)_+_var(--sheet-close-size))] text-left",
310
- className
311
- ),
312
- ...props
313
- }
314
- )
315
- );
316
- SheetHeader.displayName = "SheetHeader";
317
- var SheetBody = React.forwardRef(
318
- ({ className, ...props }, ref) => /* @__PURE__ */ jsx(
319
- "div",
320
- {
321
- ref,
322
- "data-slot": "sheet-body",
323
- className: cn(
324
- "min-h-0 flex-1 overflow-y-auto overscroll-contain px-[var(--sheet-padding-x)] py-[var(--sheet-body-padding-y)]",
325
- className
326
- ),
327
- ...props
328
- }
329
- )
330
- );
331
- SheetBody.displayName = "SheetBody";
332
- var SheetFooter = React.forwardRef(
333
- ({ className, ...props }, ref) => /* @__PURE__ */ jsx(
334
- "div",
335
- {
336
- ref,
337
- "data-slot": "sheet-footer",
338
- className: cn(
339
- "mt-auto flex flex-col-reverse gap-[var(--sheet-footer-gap)] border-t border-border px-[var(--sheet-padding-x)] py-[var(--sheet-padding-y)] sm:flex-row sm:justify-end",
340
- className
341
- ),
342
- ...props
343
- }
344
- )
345
- );
346
- SheetFooter.displayName = "SheetFooter";
347
- var SheetTitle = React.forwardRef(
348
- ({ className, ...props }, ref) => /* @__PURE__ */ jsx(
349
- Dialog.Title,
350
- {
351
- ref,
352
- "data-slot": "sheet-title",
353
- className: cn("font-semibold text-base leading-6 text-foreground", className),
354
- ...props
355
- }
356
- )
357
- );
358
- SheetTitle.displayName = "SheetTitle";
359
- var SheetDescription = React.forwardRef(
360
- ({ className, ...props }, ref) => /* @__PURE__ */ jsx(
361
- Dialog.Description,
362
- {
363
- ref,
364
- "data-slot": "sheet-description",
365
- className: cn("text-muted-foreground text-sm leading-5", className),
366
- ...props
239
+ SheetOverlay.displayName = "SheetOverlay";
240
+ var sheetVariants = cva(overlayClassNames.sheetSurface, {
241
+ variants: {
242
+ side: {
243
+ top: "inset-x-[var(--sheet-inset)] top-[var(--sheet-inset)] max-h-[min(var(--sheet-edge-height),calc(100dvh_-_var(--sheet-inset)_-_var(--sheet-inset)))] rounded-[var(--sheet-radius)] data-ending-style:-translate-y-full data-starting-style:-translate-y-full",
244
+ bottom: "inset-x-[var(--sheet-inset)] bottom-[var(--sheet-inset)] max-h-[min(var(--sheet-edge-height),calc(100dvh_-_var(--sheet-inset)_-_var(--sheet-inset)))] rounded-[var(--sheet-radius)] data-ending-style:translate-y-full data-starting-style:translate-y-full",
245
+ left: "inset-y-[var(--sheet-inset)] left-[var(--sheet-inset)] h-[calc(100dvh_-_var(--sheet-inset)_-_var(--sheet-inset))] w-[min(var(--sheet-side-width),calc(100vw_-_var(--sheet-inset)_-_var(--sheet-inset)))] rounded-[var(--sheet-radius)] data-ending-style:-translate-x-full data-starting-style:-translate-x-full",
246
+ right: "inset-y-[var(--sheet-inset)] right-[var(--sheet-inset)] h-[calc(100dvh_-_var(--sheet-inset)_-_var(--sheet-inset))] w-[min(var(--sheet-side-width),calc(100vw_-_var(--sheet-inset)_-_var(--sheet-inset)))] rounded-[var(--sheet-radius)] data-ending-style:translate-x-full data-starting-style:translate-x-full"
367
247
  }
368
- )
369
- );
370
- SheetDescription.displayName = "SheetDescription";
248
+ },
249
+ defaultVariants: {
250
+ side: "right"
251
+ }
252
+ });
253
+ var SheetContent = ({
254
+ side = "right",
255
+ className,
256
+ children,
257
+ overlay = true,
258
+ noOverlay = false,
259
+ showClose,
260
+ close,
261
+ style,
262
+ ref,
263
+ ...props
264
+ }) => {
265
+ const shouldRenderClose = close ?? showClose ?? true;
266
+ const shouldRenderOverlay = overlay && !noOverlay;
267
+ return /* @__PURE__ */ jsxs(SheetPortal, { children: [
268
+ shouldRenderOverlay ? /* @__PURE__ */ jsx(SheetOverlay, {}) : null,
269
+ /* @__PURE__ */ jsxs(
270
+ Dialog.Popup,
271
+ {
272
+ ref,
273
+ "data-slot": "sheet-content",
274
+ className: cn(sheetVariants({ side }), className),
275
+ style: { zIndex: overlayZIndex.modal, ...getSheetStyle(style) },
276
+ ...props,
277
+ children: [
278
+ children,
279
+ shouldRenderClose ? /* @__PURE__ */ jsxs(
280
+ SheetClose,
281
+ {
282
+ "aria-label": "Close",
283
+ className: cn(
284
+ "absolute right-[var(--sheet-close-offset)] top-[var(--sheet-close-offset)] inline-flex size-[var(--sheet-close-size)] items-center justify-center rounded-[var(--sheet-close-radius)] text-muted-foreground",
285
+ "transition-[background-color,color,box-shadow] duration-[var(--motion-duration-micro)] ease-[var(--ease-out)] hover:bg-muted hover:text-foreground",
286
+ overlayClassNames.focusRing,
287
+ "disabled:pointer-events-none motion-reduce:transition-none"
288
+ ),
289
+ children: [
290
+ /* @__PURE__ */ jsx(Cross, { "aria-hidden": "true", className: "size-[var(--sheet-close-icon-size)]" }),
291
+ /* @__PURE__ */ jsx("span", { className: "sr-only", children: "Close" })
292
+ ]
293
+ }
294
+ ) : null
295
+ ]
296
+ }
297
+ )
298
+ ] });
299
+ };
300
+ SheetContent.displayName = "SheetContent";
371
301
  var DEFAULT_SIDEBAR_WIDTH = 224;
372
302
  var DEFAULT_COLLAPSED_WIDTH = 52;
373
303
  var DEFAULT_HEADER_HEIGHT = 48;
@@ -382,32 +312,33 @@ function AppShell({
382
312
  onCollapsedChange,
383
313
  headerHeight = DEFAULT_HEADER_HEIGHT,
384
314
  contentClassName,
385
- className
315
+ className,
316
+ overlay = false
386
317
  }) {
387
318
  const isControlled = collapsed !== void 0;
388
- const [internalCollapsed] = React.useState(defaultCollapsed);
319
+ const [internalCollapsed] = React4.useState(defaultCollapsed);
389
320
  const isCollapsed = isControlled ? collapsed : internalCollapsed;
390
- const lastReportedRef = React.useRef(isCollapsed);
391
- React.useEffect(() => {
392
- if (lastReportedRef.current !== isCollapsed) {
393
- lastReportedRef.current = isCollapsed;
394
- onCollapsedChange?.(isCollapsed);
395
- }
396
- }, [isCollapsed, onCollapsedChange]);
397
- const [mobileOpen, setMobileOpen] = React.useState(false);
321
+ const [mobileOpen, setMobileOpen] = React4.useState(false);
398
322
  const railWidth = isCollapsed ? sidebarCollapsedWidth : sidebarWidth;
399
323
  return /* @__PURE__ */ jsxs(
400
324
  "div",
401
325
  {
402
- className: cn("relative flex min-h-screen w-full bg-background text-foreground", className),
326
+ "data-ui": "nebutra-app-shell",
327
+ className: cn(
328
+ "relative flex h-screen w-full overflow-hidden bg-background text-foreground",
329
+ className
330
+ ),
403
331
  children: [
404
332
  /* @__PURE__ */ jsx(
405
333
  "aside",
406
334
  {
407
335
  "aria-label": "Primary",
408
336
  className: cn(
409
- "hidden shrink-0 overflow-hidden border-r border-neutral-4 bg-neutral-2/80 md:block",
410
- "transition-[width] duration-200 ease-out"
337
+ "hidden h-screen overflow-hidden bg-sidebar text-sidebar-foreground md:block",
338
+ "transition-[width] duration-flow ease-out",
339
+ overlay ? "absolute inset-y-0 left-0 z-40" : "shrink-0",
340
+ railWidth > 0 && "border-r border-sidebar-border",
341
+ overlay && railWidth > 0 && "shadow-2xl"
411
342
  ),
412
343
  style: { width: railWidth },
413
344
  children: /* @__PURE__ */ jsx(
@@ -420,14 +351,23 @@ function AppShell({
420
351
  )
421
352
  }
422
353
  ),
423
- /* @__PURE__ */ jsx(Sheet, { open: mobileOpen, onOpenChange: setMobileOpen, children: /* @__PURE__ */ jsx(SheetContent, { side: "left", className: "w-72 border-r border-neutral-4 bg-neutral-2 p-0", children: /* @__PURE__ */ jsx("div", { className: "h-full overflow-y-auto", children: sidebar }) }) }),
424
- /* @__PURE__ */ jsxs("div", { className: "flex min-w-0 flex-1 flex-col", children: [
354
+ overlay && !isCollapsed ? /* @__PURE__ */ jsx(
355
+ "button",
356
+ {
357
+ type: "button",
358
+ "aria-label": "Collapse navigation",
359
+ onClick: () => onCollapsedChange?.(true),
360
+ className: "absolute inset-0 z-30 hidden cursor-default bg-foreground/20 backdrop-blur-[1px] md:block"
361
+ }
362
+ ) : null,
363
+ /* @__PURE__ */ jsx(Sheet, { open: mobileOpen, onOpenChange: setMobileOpen, children: /* @__PURE__ */ jsx(SheetContent, { side: "left", className: "w-72 border-r border-sidebar-border bg-sidebar p-0", children: /* @__PURE__ */ jsx("div", { className: "h-full overflow-y-auto", children: sidebar }) }) }),
364
+ /* @__PURE__ */ jsxs("div", { className: "flex min-h-0 min-w-0 flex-1 flex-col", children: [
425
365
  header !== void 0 && /* @__PURE__ */ jsxs(
426
366
  "header",
427
367
  {
428
368
  className: cn(
429
- "sticky top-0 z-30 flex items-center gap-2 border-b border-border",
430
- "bg-background/85 px-3 backdrop-blur supports-[backdrop-filter]:bg-background/70 sm:px-4"
369
+ "sticky top-0 z-30 flex shrink-0 items-center gap-2 border-b border-border",
370
+ "bg-background/90 px-3 backdrop-blur-xl supports-[backdrop-filter]:bg-background/80 sm:px-4"
431
371
  ),
432
372
  style: { height: headerHeight },
433
373
  children: [
@@ -438,9 +378,9 @@ function AppShell({
438
378
  "aria-label": "Open navigation menu",
439
379
  onClick: () => setMobileOpen(true),
440
380
  className: cn(
441
- "relative inline-flex size-8 items-center justify-center rounded-md text-foreground/80 after:absolute after:-inset-1.5 after:content-['']",
381
+ "relative inline-flex size-8 items-center justify-center rounded-[var(--radius-md)] text-foreground/80 after:absolute after:-inset-1.5 after:content-['']",
442
382
  "hover:bg-muted hover:text-foreground md:hidden",
443
- "focus:outline-none focus:ring-2 focus:ring-offset-1"
383
+ "focus-visible:outline-none"
444
384
  ),
445
385
  children: /* @__PURE__ */ jsx(Menu, { className: "size-4", "aria-hidden": "true" })
446
386
  }
@@ -449,16 +389,16 @@ function AppShell({
449
389
  ]
450
390
  }
451
391
  ),
452
- header === void 0 && /* @__PURE__ */ jsx("div", { className: "flex items-center border-b border-border bg-background px-4 py-2 md:hidden", children: /* @__PURE__ */ jsx(
392
+ header === void 0 && /* @__PURE__ */ jsx("div", { className: "flex shrink-0 items-center border-b border-border bg-background px-4 py-2 md:hidden", children: /* @__PURE__ */ jsx(
453
393
  "button",
454
394
  {
455
395
  type: "button",
456
396
  "aria-label": "Open navigation menu",
457
397
  onClick: () => setMobileOpen(true),
458
398
  className: cn(
459
- "relative inline-flex size-8 items-center justify-center rounded-md text-foreground/80 after:absolute after:-inset-1.5 after:content-['']",
399
+ "relative inline-flex size-8 items-center justify-center rounded-[var(--radius-md)] text-foreground/80 after:absolute after:-inset-1.5 after:content-['']",
460
400
  "hover:bg-muted hover:text-foreground",
461
- "focus:outline-none focus:ring-2 focus:ring-offset-1"
401
+ "focus-visible:outline-none"
462
402
  ),
463
403
  children: /* @__PURE__ */ jsx(Menu, { className: "size-4", "aria-hidden": "true" })
464
404
  }
@@ -466,7 +406,10 @@ function AppShell({
466
406
  /* @__PURE__ */ jsx(
467
407
  "main",
468
408
  {
469
- className: cn("w-full max-w-none px-3 py-4 sm:px-4 md:px-5 2xl:px-6", contentClassName),
409
+ className: cn(
410
+ "min-h-0 flex-1 overflow-y-auto w-full max-w-none px-3 py-4 sm:px-4 md:px-5 2xl:px-6",
411
+ contentClassName
412
+ ),
470
413
  children
471
414
  }
472
415
  )
@@ -480,7 +423,7 @@ function Card({ children, isInteractive = false, className }) {
480
423
  "div",
481
424
  {
482
425
  className: cn(
483
- "rounded-lg border border-[color:var(--neutral-7)] bg-[color:var(--neutral-1)] p-4 text-[color:var(--neutral-12)] shadow-sm dark:border-white/10 dark:bg-black/40 dark:text-white",
426
+ "rounded-[var(--radius-lg)] border border-border bg-background p-4 text-foreground shadow-sm dark:bg-black/40",
484
427
  isInteractive && "cursor-pointer transition-shadow hover:shadow-md",
485
428
  className
486
429
  ),
@@ -579,23 +522,21 @@ function BrandMark({
579
522
  {
580
523
  "aria-hidden": "true",
581
524
  className: cn(
582
- "pointer-events-none absolute rounded-full opacity-30 blur-2xl",
525
+ "pointer-events-none absolute rounded-full bg-brand-mark opacity-30 blur-2xl",
583
526
  sizes.halo
584
- ),
585
- style: { background: "var(--brand-gradient)" }
527
+ )
586
528
  }
587
529
  ),
588
530
  /* @__PURE__ */ jsx(
589
531
  "span",
590
532
  {
591
533
  className: cn(
592
- "relative inline-flex items-center justify-center rounded-2xl",
534
+ "relative inline-flex items-center justify-center rounded-[var(--radius-2xl)]",
593
535
  sizes.box,
594
- variant === "gradient" && "text-white shadow-sm",
595
- variant === "soft" && "bg-blue-2 text-blue-11 dark:bg-blue-2/20 dark:text-blue-9",
596
- variant === "outline" && "border border-neutral-7 bg-neutral-1 text-neutral-12 dark:border-white/10 dark:bg-white/[0.04] dark:text-white"
536
+ variant === "gradient" && "bg-brand-mark text-brand-mark-foreground shadow-sm",
537
+ variant === "soft" && "bg-brand-mark/10 text-brand-mark dark:bg-brand-mark/20",
538
+ variant === "outline" && "border border-border bg-background text-foreground"
597
539
  ),
598
- style: variant === "gradient" ? { background: "var(--brand-gradient)" } : void 0,
599
540
  children: children ?? /* @__PURE__ */ jsx(DefaultGlyph, { className: sizes.glyph })
600
541
  }
601
542
  )
@@ -705,83 +646,85 @@ var emptyStateCssVars = (size) => ({
705
646
  "--empty-state-title-line-height": `${emptyStateTokens.typography.titleLineHeight}px`,
706
647
  "--empty-state-description-line-height": `${emptyStateTokens.typography.descriptionLineHeight}px`
707
648
  });
708
- var EmptyStateIcon = React.forwardRef(
709
- ({ className, icon, ...props }, ref) => /* @__PURE__ */ jsx(
710
- "div",
649
+ var EmptyStateIcon = ({
650
+ className,
651
+ icon,
652
+ ref,
653
+ ...props
654
+ }) => /* @__PURE__ */ jsx(
655
+ "div",
656
+ {
657
+ ref,
658
+ "aria-hidden": "true",
659
+ className: cn(
660
+ "flex size-[var(--empty-state-icon-size)] shrink-0 items-center justify-center rounded-[var(--empty-state-icon-radius)] bg-muted",
661
+ className
662
+ ),
663
+ ...props,
664
+ children: icon
665
+ }
666
+ );
667
+ EmptyStateIcon.displayName = "EmptyState.Icon";
668
+ var EmptyStateRoot = ({
669
+ className,
670
+ title,
671
+ description,
672
+ icon,
673
+ children,
674
+ action,
675
+ link,
676
+ style,
677
+ variant = "blank-slate",
678
+ size = "md",
679
+ align = "center",
680
+ live = false,
681
+ ref,
682
+ ...props
683
+ }) => {
684
+ const actions = children ?? [action, link].filter(Boolean);
685
+ const hasActions = React4.Children.toArray(actions).length > 0;
686
+ return /* @__PURE__ */ jsx(
687
+ "section",
711
688
  {
712
689
  ref,
713
- "aria-hidden": "true",
690
+ "aria-live": live ? "polite" : void 0,
714
691
  className: cn(
715
- "flex size-[var(--empty-state-icon-size)] shrink-0 items-center justify-center rounded-[var(--empty-state-icon-radius)] bg-muted",
692
+ "flex min-h-[var(--empty-state-min-height)] w-full flex-col justify-center rounded-[var(--empty-state-radius)] px-[var(--empty-state-padding-x)] py-[var(--empty-state-padding-y)]",
693
+ variantClassName[variant],
694
+ align === "center" ? "items-center text-center" : "items-start text-left",
716
695
  className
717
696
  ),
697
+ style: { ...emptyStateCssVars(size), ...style },
718
698
  ...props,
719
- children: icon
699
+ children: /* @__PURE__ */ jsxs(
700
+ "div",
701
+ {
702
+ className: cn(
703
+ "flex max-w-[var(--empty-state-content-max-width)] flex-col gap-[var(--empty-state-stack-gap)]",
704
+ align === "center" ? "items-center" : "items-start"
705
+ ),
706
+ children: [
707
+ icon ? /* @__PURE__ */ jsx("div", { className: cn("[&>div]:bg-muted", iconToneClassName[variant]), children: icon }) : null,
708
+ /* @__PURE__ */ jsxs("div", { className: "space-y-[var(--empty-state-copy-gap)]", children: [
709
+ /* @__PURE__ */ jsx("h3", { className: "font-[var(--empty-state-title-weight)] text-[length:var(--empty-state-title-size)] leading-[var(--empty-state-title-line-height)] text-foreground", children: title }),
710
+ description ? /* @__PURE__ */ jsx("p", { className: "max-w-[var(--empty-state-description-max-width)] text-[length:var(--empty-state-description-size)] leading-[var(--empty-state-description-line-height)] text-muted-foreground", children: description }) : null
711
+ ] }),
712
+ hasActions ? /* @__PURE__ */ jsx(
713
+ "div",
714
+ {
715
+ className: cn(
716
+ "flex flex-wrap gap-[var(--empty-state-actions-gap)]",
717
+ align === "center" ? "justify-center" : "justify-start"
718
+ ),
719
+ children: actions
720
+ }
721
+ ) : null
722
+ ]
723
+ }
724
+ )
720
725
  }
721
- )
722
- );
723
- EmptyStateIcon.displayName = "EmptyState.Icon";
724
- var EmptyStateRoot = React.forwardRef(
725
- ({
726
- className,
727
- title,
728
- description,
729
- icon,
730
- children,
731
- action,
732
- link,
733
- style,
734
- variant = "blank-slate",
735
- size = "md",
736
- align = "center",
737
- live = false,
738
- ...props
739
- }, ref) => {
740
- const actions = children ?? [action, link].filter(Boolean);
741
- const hasActions = React.Children.toArray(actions).length > 0;
742
- return /* @__PURE__ */ jsx(
743
- "section",
744
- {
745
- ref,
746
- "aria-live": live ? "polite" : void 0,
747
- className: cn(
748
- "flex min-h-[var(--empty-state-min-height)] w-full flex-col justify-center rounded-[var(--empty-state-radius)] px-[var(--empty-state-padding-x)] py-[var(--empty-state-padding-y)]",
749
- variantClassName[variant],
750
- align === "center" ? "items-center text-center" : "items-start text-left",
751
- className
752
- ),
753
- style: { ...emptyStateCssVars(size), ...style },
754
- ...props,
755
- children: /* @__PURE__ */ jsxs(
756
- "div",
757
- {
758
- className: cn(
759
- "flex max-w-[var(--empty-state-content-max-width)] flex-col gap-[var(--empty-state-stack-gap)]",
760
- align === "center" ? "items-center" : "items-start"
761
- ),
762
- children: [
763
- icon ? /* @__PURE__ */ jsx("div", { className: cn("[&>div]:bg-muted", iconToneClassName[variant]), children: icon }) : null,
764
- /* @__PURE__ */ jsxs("div", { className: "space-y-[var(--empty-state-copy-gap)]", children: [
765
- /* @__PURE__ */ jsx("h3", { className: "font-[var(--empty-state-title-weight)] text-[length:var(--empty-state-title-size)] leading-[var(--empty-state-title-line-height)] text-foreground", children: title }),
766
- description ? /* @__PURE__ */ jsx("p", { className: "max-w-[var(--empty-state-description-max-width)] text-[length:var(--empty-state-description-size)] leading-[var(--empty-state-description-line-height)] text-muted-foreground", children: description }) : null
767
- ] }),
768
- hasActions ? /* @__PURE__ */ jsx(
769
- "div",
770
- {
771
- className: cn(
772
- "flex flex-wrap gap-[var(--empty-state-actions-gap)]",
773
- align === "center" ? "justify-center" : "justify-start"
774
- ),
775
- children: actions
776
- }
777
- ) : null
778
- ]
779
- }
780
- )
781
- }
782
- );
783
- }
784
- );
726
+ );
727
+ };
785
728
  EmptyStateRoot.displayName = "EmptyState.Root";
786
729
  var EmptyState = {
787
730
  Root: EmptyStateRoot,
@@ -818,18 +761,18 @@ function EmptyState2({
818
761
  }
819
762
  );
820
763
  }
821
- var Slot = React.forwardRef(
764
+ var Slot = React4.forwardRef(
822
765
  ({ children, className, style, ...props }, ref) => {
823
- const childArray = React.Children.toArray(children);
766
+ const childArray = React4.Children.toArray(children);
824
767
  const child = childArray.length === 1 ? childArray[0] : null;
825
- if (child == null || !React.isValidElement(child)) {
768
+ if (child == null || !React4.isValidElement(child)) {
826
769
  return /* @__PURE__ */ jsx("span", { ref, className, style, ...props, children });
827
770
  }
828
771
  const childProps = child.props;
829
772
  const mergedRef = (node) => {
830
773
  if (typeof ref === "function") ref(node);
831
774
  else if (ref) ref.current = node;
832
- const childRef = child.ref;
775
+ const childRef = childProps.ref;
833
776
  if (typeof childRef === "function") childRef(node);
834
777
  else if (childRef && "current" in childRef) {
835
778
  childRef.current = node;
@@ -843,7 +786,7 @@ var Slot = React.forwardRef(
843
786
  className: mergedClass,
844
787
  style: { ...childProps.style, ...style }
845
788
  };
846
- return React.cloneElement(
789
+ return React4.cloneElement(
847
790
  child,
848
791
  merged
849
792
  );
@@ -853,17 +796,18 @@ Slot.displayName = "Slot";
853
796
  var buttonVariants = cva(
854
797
  [
855
798
  "inline-flex items-center justify-center gap-2 whitespace-nowrap",
856
- "rounded-[var(--radius-md)] text-sm font-medium",
857
- "transition-colors duration-150 ease-out",
858
- "focus-visible:outline-none focus-visible:ring-2 focus-visible:ring-ring focus-visible:ring-offset-2",
799
+ "rounded-[var(--btn-default-radius,var(--radius-md))]",
800
+ "text-[length:var(--control-font-size-md,0.875rem)] font-[number:var(--font-weight-medium,500)]",
801
+ "transition-colors duration-micro ease-out",
859
802
  "disabled:pointer-events-none disabled:opacity-50",
860
803
  "aria-busy:cursor-wait"
861
804
  ].join(" "),
862
805
  {
863
806
  variants: {
864
807
  variant: {
865
- default: "bg-primary text-primary-foreground hover:bg-primary/90",
866
- ink: "bg-[var(--neutral-12)] text-[var(--neutral-1)] ring-1 ring-inset ring-white/[0.04] hover:bg-[var(--neutral-11)] hover:-translate-y-px active:translate-y-0 transition-[transform,background-color] duration-150",
808
+ // Recipe-driven via packages/design/tokens/recipe.css (.btn-brand-default)
809
+ default: "btn-brand-default",
810
+ ink: "bg-[var(--neutral-12)] text-[var(--neutral-1)] ring-1 ring-inset ring-[color:var(--neutral-1)]/5 hover:bg-[var(--neutral-11)] hover:-translate-y-px active:translate-y-0 transition-[transform,background-color] duration-micro",
867
811
  destructive: "bg-destructive text-destructive-foreground hover:bg-destructive/90",
868
812
  outline: "border border-input bg-background hover:bg-accent hover:text-accent-foreground",
869
813
  secondary: "bg-secondary text-secondary-foreground hover:bg-secondary/80",
@@ -873,34 +817,99 @@ var buttonVariants = cva(
873
817
  warning: "bg-warning text-warning-foreground hover:bg-warning/90"
874
818
  },
875
819
  size: {
876
- tiny: "h-6 rounded-[var(--radius-sm)] px-2 text-[11px]",
877
- // 24px
878
- sm: "h-8 rounded-[var(--radius-sm)] px-3 text-xs",
879
- // 32px
880
- default: "h-10 px-4 py-2",
881
- // 40px
882
- lg: "h-12 rounded-[var(--radius-lg)] px-5 text-base",
883
- // 48px
884
- icon: "h-10 w-10"
885
- // 40×40px (kept for backward compat)
820
+ tiny: "h-[var(--control-height-tiny,1.5rem)] rounded-[var(--radius-sm)] px-2 text-[length:var(--control-font-size-tiny,0.6875rem)]",
821
+ sm: "h-[var(--control-height-sm,2rem)] rounded-[var(--radius-sm)] px-3 text-[length:var(--control-font-size-sm,0.75rem)]",
822
+ default: "h-[var(--control-height-md,2.5rem)] px-[var(--btn-default-padding-x,1rem)] py-[var(--btn-default-padding-y,0.5rem)]",
823
+ lg: "h-[var(--control-height-lg,3rem)] rounded-[var(--radius-lg)] px-5 text-[length:var(--control-font-size-lg,1rem)]",
824
+ icon: "h-[var(--control-height-md,2.5rem)] w-[var(--control-height-md,2.5rem)]"
886
825
  },
887
826
  shape: {
888
827
  default: "",
889
- square: "",
890
- circle: ""
828
+ // Radius from --btn-default-radius / --radius-md — brand-switchable.
829
+ // Do not hardcode rounded-md here; a language must be able to retarget
830
+ // the corner treatment of every icon trigger at once.
831
+ square: "rounded-[var(--btn-default-radius,var(--radius-md))]",
832
+ // Pill radius token, not Tailwind rounded-full — same 9999px default,
833
+ // but a brand that ships a softer "circle" can override --radius-pill.
834
+ circle: "rounded-[var(--radius-pill,9999px)]",
835
+ pill: "rounded-[var(--radius-pill,9999px)]"
836
+ },
837
+ // Icon-only box size — orthogonal to `size` (which tunes text-button
838
+ // height/padding/font together) and to `shape` (which picks the
839
+ // corner treatment). Only takes effect combined with shape="square"
840
+ // or shape="circle" (see compoundVariants below); every other
841
+ // combination ignores it. 28/32/36 cover the icon-trigger sizes that
842
+ // actually occur in the app — 24/40/48 are already reachable via
843
+ // shape + size (tiny/default/lg). Heights read --control-height-icon-*
844
+ // so density-aware Brand Packages can scale them with the ladder.
845
+ iconSize: {
846
+ sm: "",
847
+ // 28px default
848
+ md: "",
849
+ // 32px default
850
+ lg: ""
851
+ // 36px default
891
852
  }
892
853
  },
893
854
  compoundVariants: [
894
- // shape="square" — width = height, no horizontal padding
895
- { shape: "square", size: "tiny", className: "w-6 px-0" },
896
- { shape: "square", size: "sm", className: "w-8 px-0" },
897
- { shape: "square", size: "default", className: "w-10 px-0" },
898
- { shape: "square", size: "lg", className: "w-12 px-0" },
899
- // shape="circle" — width = height + rounded-full
900
- { shape: "circle", size: "tiny", className: "w-6 px-0 rounded-full" },
901
- { shape: "circle", size: "sm", className: "w-8 px-0 rounded-full" },
902
- { shape: "circle", size: "default", className: "w-10 px-0 rounded-full" },
903
- { shape: "circle", size: "lg", className: "w-12 px-0 rounded-full" }
855
+ { shape: "square", size: "tiny", className: "w-[var(--control-height-tiny,1.5rem)] px-0" },
856
+ { shape: "square", size: "sm", className: "w-[var(--control-height-sm,2rem)] px-0" },
857
+ { shape: "square", size: "default", className: "w-[var(--control-height-md,2.5rem)] px-0" },
858
+ { shape: "square", size: "lg", className: "w-[var(--control-height-lg,3rem)] px-0" },
859
+ {
860
+ shape: "circle",
861
+ size: "tiny",
862
+ className: "w-[var(--control-height-tiny,1.5rem)] px-0"
863
+ },
864
+ {
865
+ shape: "circle",
866
+ size: "sm",
867
+ className: "w-[var(--control-height-sm,2rem)] px-0"
868
+ },
869
+ {
870
+ shape: "circle",
871
+ size: "default",
872
+ className: "w-[var(--control-height-md,2.5rem)] px-0"
873
+ },
874
+ {
875
+ shape: "circle",
876
+ size: "lg",
877
+ className: "w-[var(--control-height-lg,3rem)] px-0"
878
+ },
879
+ // iconSize wins over the size-driven box above — matched on shape +
880
+ // iconSize only, so it applies regardless of whatever `size` was
881
+ // passed (or left at its "default" fallback). Corner treatment stays
882
+ // on the shape variant (token-backed); only the box is set here.
883
+ {
884
+ shape: "square",
885
+ iconSize: "sm",
886
+ className: "h-[var(--control-height-icon-sm,1.75rem)] w-[var(--control-height-icon-sm,1.75rem)] px-0"
887
+ },
888
+ {
889
+ shape: "square",
890
+ iconSize: "md",
891
+ className: "h-[var(--control-height-icon-md,2rem)] w-[var(--control-height-icon-md,2rem)] px-0"
892
+ },
893
+ {
894
+ shape: "square",
895
+ iconSize: "lg",
896
+ className: "h-[var(--control-height-icon-lg,2.25rem)] w-[var(--control-height-icon-lg,2.25rem)] px-0"
897
+ },
898
+ {
899
+ shape: "circle",
900
+ iconSize: "sm",
901
+ className: "h-[var(--control-height-icon-sm,1.75rem)] w-[var(--control-height-icon-sm,1.75rem)] px-0"
902
+ },
903
+ {
904
+ shape: "circle",
905
+ iconSize: "md",
906
+ className: "h-[var(--control-height-icon-md,2rem)] w-[var(--control-height-icon-md,2rem)] px-0"
907
+ },
908
+ {
909
+ shape: "circle",
910
+ iconSize: "lg",
911
+ className: "h-[var(--control-height-icon-lg,2.25rem)] w-[var(--control-height-icon-lg,2.25rem)] px-0"
912
+ }
904
913
  ],
905
914
  defaultVariants: {
906
915
  variant: "default",
@@ -921,7 +930,10 @@ function Spinner({ className }) {
921
930
  }
922
931
  );
923
932
  }
924
- function getIconSizeClass(size) {
933
+ function getIconSizeClass(size, iconSize2) {
934
+ if (iconSize2 === "sm") return "[&>svg]:size-3.5";
935
+ if (iconSize2 === "md") return "[&>svg]:size-3.5";
936
+ if (iconSize2 === "lg") return "[&>svg]:size-4";
925
937
  switch (size) {
926
938
  case "tiny":
927
939
  return "[&>svg]:size-3";
@@ -936,7 +948,10 @@ function getIconSizeClass(size) {
936
948
  return "[&>svg]:size-4";
937
949
  }
938
950
  }
939
- function getSpinnerSizeClass(size) {
951
+ function getSpinnerSizeClass(size, iconSize2) {
952
+ if (iconSize2 === "sm") return "size-3.5";
953
+ if (iconSize2 === "md") return "size-3.5";
954
+ if (iconSize2 === "lg") return "size-4";
940
955
  switch (size) {
941
956
  case "tiny":
942
957
  return "size-3";
@@ -954,101 +969,111 @@ function getSpinnerSizeClass(size) {
954
969
  var SHADOW_CLASSES = {
955
970
  sm: "shadow-sm",
956
971
  md: "shadow-md",
957
- lg: "shadow-lg"
972
+ lg: "shadow-md"
958
973
  };
959
974
  function resolveShadowClass(shadow) {
960
975
  if (!shadow) return void 0;
961
976
  const level = shadow === true ? "md" : shadow;
962
977
  return SHADOW_CLASSES[level];
963
978
  }
964
- function ButtonContent({ loading, prefix, suffix, size, children }) {
965
- const iconSizeClass = getIconSizeClass(size);
979
+ function ButtonContent({ loading, prefix, suffix, size, iconSize: iconSize2, children }) {
980
+ const iconSizeClass = getIconSizeClass(size, iconSize2);
966
981
  return /* @__PURE__ */ jsxs(Fragment, { children: [
967
- loading && /* @__PURE__ */ jsx(Spinner, { className: getSpinnerSizeClass(size) }),
982
+ loading && /* @__PURE__ */ jsx(Spinner, { className: getSpinnerSizeClass(size, iconSize2) }),
968
983
  prefix != null && /* @__PURE__ */ jsx("span", { "aria-hidden": "true", className: cn("shrink-0", iconSizeClass), children: prefix }),
969
984
  children,
970
985
  suffix != null && /* @__PURE__ */ jsx("span", { "aria-hidden": "true", className: cn("shrink-0", iconSizeClass), children: suffix })
971
986
  ] });
972
987
  }
973
- var Button = React.forwardRef(
974
- ({
975
- className,
976
- variant,
977
- size,
978
- shape,
979
- asChild = false,
980
- loading = false,
981
- disabled,
982
- prefix,
983
- suffix,
984
- shadow,
985
- children,
986
- ...props
987
- }, ref) => {
988
- const Comp = asChild ? Slot : "button";
989
- const isDisabled = disabled ?? loading;
990
- const shadowClass = resolveShadowClass(shadow);
991
- return /* @__PURE__ */ jsx(
992
- Comp,
993
- {
994
- ref,
995
- className: cn(buttonVariants({ variant, size, shape }), shadowClass, className),
996
- disabled: isDisabled,
997
- "aria-busy": loading || void 0,
998
- ...props,
999
- children: asChild ? children : /* @__PURE__ */ jsx(ButtonContent, { loading, prefix, suffix, size, children })
1000
- }
1001
- );
1002
- }
1003
- );
1004
- Button.displayName = "Button";
1005
- var ButtonLink = React.forwardRef(
1006
- ({
1007
- className,
1008
- variant,
1009
- size,
1010
- shape,
1011
- prefix,
1012
- suffix,
1013
- shadow,
1014
- loading = false,
1015
- children,
1016
- ...props
1017
- }, ref) => {
1018
- const shadowClass = resolveShadowClass(shadow);
1019
- const loadingProps = loading ? {
1020
- "aria-busy": "true",
1021
- "aria-disabled": "true",
1022
- tabIndex: -1
1023
- } : {};
1024
- return /* @__PURE__ */ jsx(
1025
- "a",
1026
- {
1027
- ref,
1028
- className: cn(
1029
- buttonVariants({ variant, size, shape }),
1030
- shadowClass,
1031
- loading && "pointer-events-none opacity-50",
1032
- className
1033
- ),
1034
- ...loadingProps,
1035
- ...props,
1036
- children: /* @__PURE__ */ jsx(ButtonContent, { loading, prefix, suffix, size, children })
1037
- }
1038
- );
1039
- }
1040
- );
1041
- ButtonLink.displayName = "ButtonLink";
1042
- var textSize = {
1043
- small: "text-xs",
1044
- medium: "text-sm",
1045
- large: "text-base"
988
+ var Button = ({
989
+ className,
990
+ variant,
991
+ size,
992
+ shape,
993
+ iconSize: iconSize2,
994
+ asChild = false,
995
+ loading = false,
996
+ disabled,
997
+ prefix,
998
+ suffix,
999
+ shadow,
1000
+ children,
1001
+ ref,
1002
+ ...props
1003
+ }) => {
1004
+ const Comp = asChild ? Slot : "button";
1005
+ const isDisabled = Boolean(disabled || loading);
1006
+ const shadowClass = resolveShadowClass(shadow);
1007
+ return /* @__PURE__ */ jsx(
1008
+ Comp,
1009
+ {
1010
+ ref,
1011
+ className: cn(buttonVariants({ variant, size, shape, iconSize: iconSize2 }), shadowClass, className),
1012
+ disabled: isDisabled,
1013
+ "aria-busy": loading || void 0,
1014
+ ...props,
1015
+ children: asChild ? children : /* @__PURE__ */ jsx(
1016
+ ButtonContent,
1017
+ {
1018
+ loading,
1019
+ prefix,
1020
+ suffix,
1021
+ size,
1022
+ iconSize: iconSize2,
1023
+ children
1024
+ }
1025
+ )
1026
+ }
1027
+ );
1046
1028
  };
1047
- var iconSize = {
1048
- small: 12,
1049
- medium: 14,
1050
- large: 16
1029
+ Button.displayName = "Button";
1030
+ var ButtonLink = ({
1031
+ className,
1032
+ variant,
1033
+ size,
1034
+ shape,
1035
+ iconSize: iconSize2,
1036
+ prefix,
1037
+ suffix,
1038
+ shadow,
1039
+ loading = false,
1040
+ children,
1041
+ ref,
1042
+ ...props
1043
+ }) => {
1044
+ const shadowClass = resolveShadowClass(shadow);
1045
+ const loadingProps = loading ? {
1046
+ "aria-busy": "true",
1047
+ "aria-disabled": "true",
1048
+ tabIndex: -1
1049
+ } : {};
1050
+ return /* @__PURE__ */ jsx(
1051
+ "a",
1052
+ {
1053
+ ref,
1054
+ className: cn(
1055
+ buttonVariants({ variant, size, shape, iconSize: iconSize2 }),
1056
+ shadowClass,
1057
+ loading && "pointer-events-none opacity-50",
1058
+ className
1059
+ ),
1060
+ ...loadingProps,
1061
+ ...props,
1062
+ children: /* @__PURE__ */ jsx(
1063
+ ButtonContent,
1064
+ {
1065
+ loading,
1066
+ prefix,
1067
+ suffix,
1068
+ size,
1069
+ iconSize: iconSize2,
1070
+ children
1071
+ }
1072
+ )
1073
+ }
1074
+ );
1051
1075
  };
1076
+ ButtonLink.displayName = "ButtonLink";
1052
1077
  var surfaceSize = {
1053
1078
  small: "gap-2 rounded-[var(--radius-md)] p-3 text-sm",
1054
1079
  medium: "gap-3 rounded-[var(--radius-lg)] p-4 text-sm",
@@ -1065,133 +1090,91 @@ function getActionTarget(link) {
1065
1090
  }
1066
1091
  return {};
1067
1092
  }
1068
- var ErrorMessage = React.forwardRef(
1069
- ({ children, label, size = "medium", error, className }, ref) => {
1070
- const sz = size;
1071
- const message = error?.message ?? children;
1072
- return /* @__PURE__ */ jsxs(
1073
- "span",
1074
- {
1075
- ref,
1076
- role: "alert",
1077
- className: cn("inline-flex items-center gap-1.5 text-destructive", textSize[sz], className),
1078
- children: [
1079
- /* @__PURE__ */ jsx(Warning, { size: iconSize[sz], "aria-hidden": "true", className: "shrink-0" }),
1080
- /* @__PURE__ */ jsxs("span", { children: [
1081
- label && /* @__PURE__ */ jsxs("span", { className: "font-medium", children: [
1082
- label,
1083
- ":\xA0"
1084
- ] }),
1085
- message,
1086
- error?.action && error.link && /* @__PURE__ */ jsxs(Fragment, { children: [
1087
- " ",
1088
- /* @__PURE__ */ jsxs(
1089
- "a",
1090
- {
1091
- href: error.link,
1092
- className: "underline underline-offset-2 hover:no-underline",
1093
- target: "_blank",
1094
- rel: "noopener noreferrer",
1095
- children: [
1096
- error.action,
1097
- /* @__PURE__ */ jsx(External, { size: 10, "aria-hidden": "true", className: "ml-0.5 inline" })
1098
- ]
1099
- }
1100
- )
1101
- ] })
1102
- ] })
1103
- ]
1104
- }
1105
- );
1106
- }
1107
- );
1108
- ErrorMessage.displayName = "ErrorMessage";
1109
- var ErrorSurface = React.forwardRef(
1110
- ({
1111
- children,
1112
- label,
1113
- showLabel = true,
1114
- title,
1115
- size = "medium",
1116
- error,
1117
- errorId,
1118
- errorIdLabel = "Request ID",
1119
- live = "polite",
1120
- action,
1121
- link,
1122
- onAction,
1123
- actionLoading = false,
1124
- className,
1125
- role,
1126
- ...props
1127
- }, ref) => {
1128
- const message = error?.message ?? children;
1129
- const resolvedTitle = title ?? error?.title;
1130
- const resolvedAction = action ?? error?.action;
1131
- const resolvedLink = link ?? error?.link;
1132
- const resolvedErrorId = errorId ?? error?.id;
1133
- const resolvedRole = role ?? (live === "assertive" ? "alert" : "status");
1134
- const ariaLive = live === "off" ? void 0 : live;
1135
- return /* @__PURE__ */ jsxs(
1136
- "div",
1137
- {
1138
- ref,
1139
- role: resolvedRole,
1140
- "aria-live": ariaLive,
1141
- className: cn(
1142
- "flex w-full border border-destructive/25 bg-destructive/5 text-foreground",
1143
- surfaceSize[size],
1144
- className
1093
+ var ErrorSurface = ({
1094
+ children,
1095
+ label,
1096
+ showLabel = true,
1097
+ title,
1098
+ size = "medium",
1099
+ error,
1100
+ errorId,
1101
+ errorIdLabel = "Request ID",
1102
+ live = "polite",
1103
+ action,
1104
+ link,
1105
+ onAction,
1106
+ actionLoading = false,
1107
+ className,
1108
+ role,
1109
+ ref,
1110
+ ...props
1111
+ }) => {
1112
+ const message = error?.message ?? children;
1113
+ const resolvedTitle = title ?? error?.title;
1114
+ const resolvedAction = action ?? error?.action;
1115
+ const resolvedLink = link ?? error?.link;
1116
+ const resolvedErrorId = errorId ?? error?.id;
1117
+ const resolvedRole = role ?? (live === "assertive" ? "alert" : "status");
1118
+ const ariaLive = live === "off" ? void 0 : live;
1119
+ return /* @__PURE__ */ jsxs(
1120
+ "div",
1121
+ {
1122
+ ref,
1123
+ role: resolvedRole,
1124
+ "aria-live": ariaLive,
1125
+ className: cn(
1126
+ "flex w-full border border-destructive/25 bg-destructive/5 text-foreground",
1127
+ surfaceSize[size],
1128
+ className
1129
+ ),
1130
+ ...props,
1131
+ children: [
1132
+ /* @__PURE__ */ jsx(
1133
+ "span",
1134
+ {
1135
+ "aria-hidden": "true",
1136
+ className: "mt-0.5 flex size-7 shrink-0 items-center justify-center rounded-[var(--radius-sm)] border border-destructive/20 bg-background text-destructive",
1137
+ children: /* @__PURE__ */ jsx(Warning, { size: surfaceIconSize[size] })
1138
+ }
1145
1139
  ),
1146
- ...props,
1147
- children: [
1148
- /* @__PURE__ */ jsx(
1149
- "span",
1140
+ /* @__PURE__ */ jsxs("div", { className: "min-w-0 flex-1", children: [
1141
+ label && showLabel ? /* @__PURE__ */ jsx("p", { className: "mb-1 text-xs font-medium uppercase tracking-normal text-destructive", children: label }) : null,
1142
+ resolvedTitle ? /* @__PURE__ */ jsx("p", { className: "font-semibold leading-6 text-foreground", children: resolvedTitle }) : null,
1143
+ message ? /* @__PURE__ */ jsx("p", { className: cn("leading-5 text-muted-foreground", resolvedTitle && "mt-1"), children: message }) : null,
1144
+ resolvedErrorId ? /* @__PURE__ */ jsxs("details", { className: "mt-3 text-xs text-muted-foreground", children: [
1145
+ /* @__PURE__ */ jsx("summary", { className: "cursor-pointer select-none text-foreground", children: "Diagnostic details" }),
1146
+ /* @__PURE__ */ jsxs("code", { className: "mt-2 block overflow-x-auto rounded-[var(--radius-sm)] border bg-background px-2 py-1 font-mono text-xs text-muted-foreground", children: [
1147
+ errorIdLabel,
1148
+ ": ",
1149
+ resolvedErrorId,
1150
+ error?.code ? ` (${error.code})` : ""
1151
+ ] })
1152
+ ] }) : null,
1153
+ resolvedAction ? /* @__PURE__ */ jsx("div", { className: "mt-4 flex flex-wrap gap-2", children: resolvedLink ? /* @__PURE__ */ jsx(
1154
+ ButtonLink,
1150
1155
  {
1151
- "aria-hidden": "true",
1152
- className: "mt-0.5 flex size-7 shrink-0 items-center justify-center rounded-[var(--radius-sm)] border border-destructive/20 bg-background text-destructive",
1153
- children: /* @__PURE__ */ jsx(Warning, { size: surfaceIconSize[size] })
1156
+ href: resolvedLink,
1157
+ size: "sm",
1158
+ variant: "outline",
1159
+ ...getActionTarget(resolvedLink),
1160
+ children: resolvedAction
1154
1161
  }
1155
- ),
1156
- /* @__PURE__ */ jsxs("div", { className: "min-w-0 flex-1", children: [
1157
- label && showLabel ? /* @__PURE__ */ jsx("p", { className: "mb-1 text-xs font-medium uppercase tracking-normal text-destructive", children: label }) : null,
1158
- resolvedTitle ? /* @__PURE__ */ jsx("p", { className: "font-semibold leading-6 text-foreground", children: resolvedTitle }) : null,
1159
- message ? /* @__PURE__ */ jsx("p", { className: cn("leading-5 text-muted-foreground", resolvedTitle && "mt-1"), children: message }) : null,
1160
- resolvedErrorId ? /* @__PURE__ */ jsxs("details", { className: "mt-3 text-xs text-muted-foreground", children: [
1161
- /* @__PURE__ */ jsx("summary", { className: "cursor-pointer select-none text-foreground", children: "Diagnostic details" }),
1162
- /* @__PURE__ */ jsxs("code", { className: "mt-2 block overflow-x-auto rounded-[var(--radius-sm)] border bg-background px-2 py-1 font-mono text-xs text-muted-foreground", children: [
1163
- errorIdLabel,
1164
- ": ",
1165
- resolvedErrorId,
1166
- error?.code ? ` (${error.code})` : ""
1167
- ] })
1168
- ] }) : null,
1169
- resolvedAction ? /* @__PURE__ */ jsx("div", { className: "mt-4 flex flex-wrap gap-2", children: resolvedLink ? /* @__PURE__ */ jsx(
1170
- ButtonLink,
1171
- {
1172
- href: resolvedLink,
1173
- size: "sm",
1174
- variant: "outline",
1175
- ...getActionTarget(resolvedLink),
1176
- children: resolvedAction
1177
- }
1178
- ) : /* @__PURE__ */ jsx(
1179
- Button,
1180
- {
1181
- type: "button",
1182
- size: "sm",
1183
- variant: "outline",
1184
- loading: actionLoading,
1185
- onClick: onAction,
1186
- children: resolvedAction
1187
- }
1188
- ) }) : null
1189
- ] })
1190
- ]
1191
- }
1192
- );
1193
- }
1194
- );
1162
+ ) : /* @__PURE__ */ jsx(
1163
+ Button,
1164
+ {
1165
+ type: "button",
1166
+ size: "sm",
1167
+ variant: "outline",
1168
+ loading: actionLoading,
1169
+ onClick: onAction,
1170
+ children: resolvedAction
1171
+ }
1172
+ ) }) : null
1173
+ ] })
1174
+ ]
1175
+ }
1176
+ );
1177
+ };
1195
1178
  ErrorSurface.displayName = "Error";
1196
1179
  function ErrorState({
1197
1180
  title = "Couldn\u2019t Load Resource",
@@ -1266,14 +1249,14 @@ function LoadingState({ message, size = "large" }) {
1266
1249
  "span",
1267
1250
  {
1268
1251
  className: cn(
1269
- "inline-block animate-spin rounded-full border-solid border-[color:var(--blue-9)] border-r-transparent align-[-0.125em]",
1252
+ "inline-block animate-spin rounded-full border-solid border-primary border-r-transparent align-[-0.125em]",
1270
1253
  spinnerSize[size]
1271
1254
  ),
1272
1255
  role: "status",
1273
1256
  "aria-label": message ?? "Loading"
1274
1257
  }
1275
1258
  ),
1276
- message && /* @__PURE__ */ jsx("p", { className: "mt-3 text-sm text-[color:var(--neutral-11)] dark:text-white/70", children: message })
1259
+ message && /* @__PURE__ */ jsx("p", { className: "mt-3 text-sm text-muted-foreground", children: message })
1277
1260
  ] });
1278
1261
  }
1279
1262
  function PageHeader({ title, description, actions, className }) {
@@ -1286,8 +1269,8 @@ function PageHeader({ title, description, actions, className }) {
1286
1269
  ),
1287
1270
  children: [
1288
1271
  /* @__PURE__ */ jsxs("div", { className: "flex-1", children: [
1289
- /* @__PURE__ */ jsx("h1", { className: "text-2xl font-semibold tracking-tight text-[color:var(--neutral-12)] dark:text-white", children: title }),
1290
- description && /* @__PURE__ */ jsx("p", { className: "mt-1 text-sm text-[color:var(--neutral-11)] dark:text-white/70", children: description })
1272
+ /* @__PURE__ */ jsx("h1", { className: "text-2xl font-semibold tracking-tight text-foreground", children: title }),
1273
+ description && /* @__PURE__ */ jsx("p", { className: "mt-1 text-sm text-muted-foreground", children: description })
1291
1274
  ] }),
1292
1275
  actions && /* @__PURE__ */ jsx("div", { className: "mt-2 flex shrink-0 gap-2 sm:mt-0", children: actions })
1293
1276
  ]