@devalok/shilp-sutra 0.42.1 → 0.44.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 (130) hide show
  1. package/MIGRATION.md +78 -0
  2. package/dist/_chunks/chat.js +164 -163
  3. package/dist/_chunks/chat.js.map +1 -1
  4. package/dist/_chunks/mention-suggestion.js +35 -33
  5. package/dist/_chunks/mention-suggestion.js.map +1 -1
  6. package/dist/_chunks/oauth-button.js +102 -97
  7. package/dist/_chunks/oauth-button.js.map +1 -1
  8. package/dist/_chunks/popover.js +1 -1
  9. package/dist/_chunks/popover.js.map +1 -1
  10. package/dist/_chunks/shared.js +1 -1
  11. package/dist/_chunks/shared.js.map +1 -1
  12. package/dist/_chunks/tree-view.js +1 -1
  13. package/dist/_chunks/tree-view.js.map +1 -1
  14. package/dist/ai/command-bar.js +1 -1
  15. package/dist/ai/command-bar.js.map +1 -1
  16. package/dist/composed/bulk-action-bar.js +1 -1
  17. package/dist/composed/bulk-action-bar.js.map +1 -1
  18. package/dist/composed/command-palette.js +4 -4
  19. package/dist/composed/command-palette.js.map +1 -1
  20. package/dist/composed/content-card.d.ts +6 -0
  21. package/dist/composed/content-card.d.ts.map +1 -1
  22. package/dist/composed/content-card.js +1 -1
  23. package/dist/composed/content-card.js.map +1 -1
  24. package/dist/composed/error-boundary.js +1 -1
  25. package/dist/composed/error-boundary.js.map +1 -1
  26. package/dist/composed/extensions/emoji-suggestion.js +1 -1
  27. package/dist/composed/extensions/emoji-suggestion.js.map +1 -1
  28. package/dist/composed/extensions/file-attachment.d.ts.map +1 -1
  29. package/dist/composed/file-preview/audio-preview.d.ts.map +1 -1
  30. package/dist/composed/file-preview.d.ts.map +1 -1
  31. package/dist/composed/file-preview.js +147 -143
  32. package/dist/composed/file-preview.js.map +1 -1
  33. package/dist/composed/filter-bar.js +5 -2
  34. package/dist/composed/filter-bar.js.map +1 -1
  35. package/dist/composed/master-detail.js +1 -1
  36. package/dist/composed/master-detail.js.map +1 -1
  37. package/dist/composed/page-header.js +1 -1
  38. package/dist/composed/page-header.js.map +1 -1
  39. package/dist/composed/rich-chat-input/attachment-strip.d.ts.map +1 -1
  40. package/dist/composed/rich-chat-input/audio-player.d.ts.map +1 -1
  41. package/dist/composed/rich-chat-input/schedule-send.d.ts.map +1 -1
  42. package/dist/composed/rich-chat-input.js +600 -591
  43. package/dist/composed/rich-chat-input.js.map +1 -1
  44. package/dist/composed/rich-text-editor.d.ts.map +1 -1
  45. package/dist/composed/rich-text-editor.js +166 -164
  46. package/dist/composed/rich-text-editor.js.map +1 -1
  47. package/dist/hooks/index.d.ts +2 -2
  48. package/dist/hooks/index.d.ts.map +1 -1
  49. package/dist/shell/notification-center.d.ts.map +1 -1
  50. package/dist/shell/notification-center.js +102 -98
  51. package/dist/shell/notification-center.js.map +1 -1
  52. package/dist/shell/sidebar.d.ts +6 -0
  53. package/dist/shell/sidebar.d.ts.map +1 -1
  54. package/dist/shell/sidebar.js +142 -118
  55. package/dist/shell/sidebar.js.map +1 -1
  56. package/dist/shell/top-bar.d.ts.map +1 -1
  57. package/dist/shell/top-bar.js +87 -84
  58. package/dist/shell/top-bar.js.map +1 -1
  59. package/dist/tokens/semantic.css +9 -2
  60. package/dist/ui/alert-dialog.js +1 -1
  61. package/dist/ui/alert-dialog.js.map +1 -1
  62. package/dist/ui/autocomplete.js +1 -1
  63. package/dist/ui/autocomplete.js.map +1 -1
  64. package/dist/ui/avatar.js +1 -1
  65. package/dist/ui/avatar.js.map +1 -1
  66. package/dist/ui/breadcrumb.js +2 -2
  67. package/dist/ui/breadcrumb.js.map +1 -1
  68. package/dist/ui/button.js.map +1 -1
  69. package/dist/ui/card.d.ts +82 -7
  70. package/dist/ui/card.d.ts.map +1 -1
  71. package/dist/ui/card.js +76 -110
  72. package/dist/ui/card.js.map +1 -1
  73. package/dist/ui/chat/message.d.ts.map +1 -1
  74. package/dist/ui/color-input.js +1 -1
  75. package/dist/ui/color-input.js.map +1 -1
  76. package/dist/ui/combobox.js +3 -3
  77. package/dist/ui/combobox.js.map +1 -1
  78. package/dist/ui/context-menu.js +2 -2
  79. package/dist/ui/context-menu.js.map +1 -1
  80. package/dist/ui/data-table-bulk-actions.js +1 -1
  81. package/dist/ui/data-table-bulk-actions.js.map +1 -1
  82. package/dist/ui/dialog.js +1 -1
  83. package/dist/ui/dialog.js.map +1 -1
  84. package/dist/ui/dropdown-menu.js +11 -5
  85. package/dist/ui/dropdown-menu.js.map +1 -1
  86. package/dist/ui/hover-card.js +1 -1
  87. package/dist/ui/hover-card.js.map +1 -1
  88. package/dist/ui/index.d.ts +3 -1
  89. package/dist/ui/index.d.ts.map +1 -1
  90. package/dist/ui/index.js +58 -56
  91. package/dist/ui/index.js.map +1 -1
  92. package/dist/ui/input-otp.js +1 -1
  93. package/dist/ui/input-otp.js.map +1 -1
  94. package/dist/ui/menubar.js +12 -6
  95. package/dist/ui/menubar.js.map +1 -1
  96. package/dist/ui/navigation-menu.js +1 -1
  97. package/dist/ui/navigation-menu.js.map +1 -1
  98. package/dist/ui/oauth-button/oauth-button.d.ts.map +1 -1
  99. package/dist/ui/select.js +6 -3
  100. package/dist/ui/select.js.map +1 -1
  101. package/dist/ui/sidebar.js +74 -74
  102. package/dist/ui/sidebar.js.map +1 -1
  103. package/dist/ui/split-button.js +1 -1
  104. package/dist/ui/split-button.js.map +1 -1
  105. package/dist/ui/stat-card.d.ts +26 -3
  106. package/dist/ui/stat-card.d.ts.map +1 -1
  107. package/dist/ui/stat-card.js +183 -150
  108. package/dist/ui/stat-card.js.map +1 -1
  109. package/dist/ui/stat-flash.d.ts +46 -0
  110. package/dist/ui/stat-flash.d.ts.map +1 -0
  111. package/dist/ui/stat-flash.js +114 -0
  112. package/dist/ui/stat-flash.js.map +1 -0
  113. package/dist/ui/tabs.d.ts.map +1 -1
  114. package/dist/ui/tabs.js +5 -2
  115. package/dist/ui/tabs.js.map +1 -1
  116. package/dist/ui/toast.js +2 -2
  117. package/dist/ui/toast.js.map +1 -1
  118. package/dist/ui/truncated-text.d.ts +37 -0
  119. package/dist/ui/truncated-text.d.ts.map +1 -0
  120. package/dist/ui/truncated-text.js +53 -0
  121. package/dist/ui/truncated-text.js.map +1 -0
  122. package/docs/components/ui/card.md +13 -4
  123. package/docs/components/ui/stat-card.md +18 -3
  124. package/docs/components/ui/stat-flash.md +44 -0
  125. package/docs/components/ui/truncated-text.md +49 -0
  126. package/llms-full.txt +125 -8
  127. package/make-kit/components/card.md +14 -4
  128. package/package.json +1 -1
  129. package/skill/SKILL.md +1 -1
  130. package/skill/references/components-full.md +125 -8
@@ -224,7 +224,7 @@ var S = s.forwardRef(function({ children: S, onClick: C, dropdownContent: w, ope
224
224
  scale: .95
225
225
  },
226
226
  transition: { duration: a.moderate01 },
227
- className: "rounded-overlay border border-surface-border-strong bg-surface-overlay shadow-floating",
227
+ className: "rounded-overlay bg-surface-overlay shadow-floating",
228
228
  children: w
229
229
  })
230
230
  }) })] });
@@ -1 +1 @@
1
- {"version":3,"file":"split-button.js","names":[],"sources":["../../src/ui/split-button.tsx"],"sourcesContent":["'use client'\n\nimport { autoUpdate, computePosition, flip, offset, type Placement,shift } from '@floating-ui/dom'\nimport { type VariantProps } from 'class-variance-authority'\nimport { AnimatePresence, motion } from 'framer-motion'\nimport * as React from 'react'\n\nimport { buttonVariants } from './button'\nimport { durations } from './lib/motion'\nimport { cn } from './lib/utils'\n\n// ── Types ───────────────────────────────────────────────────────\n\ntype SplitButtonVariant = 'solid' | 'soft' | 'outline'\ntype SplitButtonColor = NonNullable<VariantProps<typeof buttonVariants>['color']>\ntype SplitButtonSize = 'xs' | 'sm' | 'md' | 'icon-xs' | 'icon-sm' | 'icon-md'\n\nexport interface SplitButtonProps {\n /** Primary action content (left side). */\n children: React.ReactNode\n /** Primary click handler (left side). */\n onClick: (e: React.MouseEvent<HTMLButtonElement>) => void\n /** Content rendered inside the floating dropdown panel. */\n dropdownContent?: React.ReactNode\n /** Controlled open state. */\n open?: boolean\n /** Called when open state changes. Uncontrolled if omitted. */\n onOpenChange?: (open: boolean) => void\n /** @default 'solid' */\n variant?: SplitButtonVariant\n /** @default 'accent' */\n color?: SplitButtonColor\n /** @default 'md' */\n size?: SplitButtonSize\n /** Disable both halves. */\n disabled?: boolean\n /** aria-label for the primary button. */\n 'aria-label'?: string\n /** aria-label for the dropdown trigger. @default 'More options' */\n dropdownLabel?: string\n /** Custom icon for the dropdown trigger. Defaults to chevron-down. */\n dropdownIcon?: React.ReactNode\n /** Which side the dropdown trigger sits on. @default 'right' */\n triggerSide?: 'left' | 'right'\n /** Preferred placement for the dropdown panel. @default 'top-end' */\n placement?: Placement\n /** Width of the trigger (chevron) half. @default 'auto' */\n triggerWidth?: number | string\n className?: string\n}\n\n// ── Styling maps ────────────────────────────────────────────────\n\nconst dividerColor: Record<SplitButtonVariant, Record<string, string>> = {\n solid: {\n accent: 'bg-accent-11/20', error: 'bg-error-11/20', success: 'bg-success-11/20',\n warning: 'bg-warning-11/20', neutral: 'bg-neutral-8/30',\n },\n soft: {\n accent: 'bg-accent-6', error: 'bg-error-6', success: 'bg-success-6',\n warning: 'bg-warning-6', neutral: 'bg-surface-border',\n },\n outline: {\n accent: 'bg-accent-7', error: 'bg-error-7', success: 'bg-success-7',\n warning: 'bg-warning-7', neutral: 'bg-surface-border-strong',\n },\n}\n\nconst heightClass: Record<SplitButtonSize, string> = {\n xs: 'h-ds-xs-plus', sm: 'h-ds-sm', md: 'h-ds-md',\n 'icon-xs': 'h-ds-xs-plus', 'icon-sm': 'h-ds-sm', 'icon-md': 'h-ds-md',\n}\n\nconst textClass: Record<SplitButtonSize, string> = {\n xs: 'text-ds-sm', sm: 'text-ds-sm', md: 'text-ds-md',\n 'icon-xs': 'text-ds-sm', 'icon-sm': 'text-ds-sm', 'icon-md': 'text-ds-md',\n}\n\nconst primaryPadding: Record<SplitButtonSize, string> = {\n xs: 'px-ds-03 gap-1', sm: 'px-ds-04 gap-1.5', md: 'px-ds-05 gap-2',\n 'icon-xs': 'px-ds-02', 'icon-sm': 'px-ds-03', 'icon-md': 'px-ds-04',\n}\n\nconst triggerPadding: Record<SplitButtonSize, string> = {\n xs: 'px-ds-02', sm: 'px-ds-02', md: 'px-ds-03',\n 'icon-xs': 'px-ds-01', 'icon-sm': 'px-ds-02', 'icon-md': 'px-ds-02',\n}\n\nconst radiusClass: Record<SplitButtonSize, string> = {\n xs: 'rounded-control', sm: 'rounded-control', md: 'rounded-control',\n 'icon-xs': 'rounded-control', 'icon-sm': 'rounded-control', 'icon-md': 'rounded-control',\n}\n\nfunction getHalfClasses(variant: SplitButtonVariant, color: string): string {\n const map: Record<SplitButtonVariant, Record<string, string>> = {\n solid: {\n accent: 'bg-accent-9 text-accent-fg hover:bg-accent-10 active:bg-accent-11',\n error: 'bg-error-9 text-error-fg hover:bg-error-10 active:bg-error-11',\n success: 'bg-success-9 text-success-fg hover:bg-success-10 active:bg-success-11',\n warning: 'bg-warning-9 text-warning-fg hover:bg-warning-10 active:bg-warning-11',\n neutral: 'bg-neutral-5 text-surface-fg hover:bg-neutral-7 active:bg-neutral-8',\n },\n soft: {\n accent: 'bg-accent-3 text-accent-11 hover:bg-accent-4 active:bg-accent-5',\n error: 'bg-error-3 text-error-11 hover:bg-error-4 active:bg-error-5',\n success: 'bg-success-3 text-success-11 hover:bg-success-4 active:bg-success-5',\n warning: 'bg-warning-3 text-warning-11 hover:bg-warning-4 active:bg-warning-5',\n neutral: 'bg-surface-raised-hover text-surface-fg-muted hover:bg-surface-raised-active active:bg-neutral-5',\n },\n outline: {\n accent: 'bg-transparent text-accent-11 hover:bg-accent-3 active:bg-accent-4',\n error: 'bg-transparent text-error-11 hover:bg-error-3 active:bg-error-4',\n success: 'bg-transparent text-success-11 hover:bg-success-3 active:bg-success-4',\n warning: 'bg-transparent text-warning-11 hover:bg-warning-3 active:bg-warning-4',\n neutral: 'bg-transparent text-surface-fg hover:bg-surface-raised-hover active:bg-surface-raised-active',\n },\n }\n return map[variant][color] ?? map[variant].accent\n}\n\nfunction getOutlineBorderColor(color: string): string {\n const map: Record<string, string> = {\n accent: 'border-accent-7', error: 'border-error-7', success: 'border-success-7',\n warning: 'border-warning-7', neutral: 'border-surface-border-strong',\n }\n return map[color] ?? map.accent\n}\n\n// ── Chevron SVG ─────────────────────────────────────────────────\n\nfunction ChevronDown({ className }: { className?: string }) {\n return (\n <svg width=\"12\" height=\"12\" viewBox=\"0 0 12 12\" fill=\"none\" className={className} aria-hidden=\"true\">\n <path d=\"M3 4.5L6 7.5L9 4.5\" stroke=\"currentColor\" strokeWidth=\"1.5\" strokeLinecap=\"round\" strokeLinejoin=\"round\" />\n </svg>\n )\n}\n\n// ── Component ───────────────────────────────────────────────────\n\nconst SplitButton = React.forwardRef<HTMLDivElement, SplitButtonProps>(\n function SplitButton(\n {\n children,\n onClick,\n dropdownContent,\n open: openProp,\n onOpenChange,\n variant = 'solid',\n color = 'accent',\n size = 'md',\n disabled = false,\n 'aria-label': ariaLabel,\n dropdownLabel = 'More options',\n dropdownIcon,\n triggerSide = 'right',\n placement: placementProp = 'top-end',\n triggerWidth,\n className,\n },\n ref,\n ) {\n const [internalOpen, setInternalOpen] = React.useState(false)\n const isControlled = openProp !== undefined\n const isOpen = isControlled ? openProp : internalOpen\n\n const anchorRef = React.useRef<HTMLDivElement>(null)\n const floatingRef = React.useRef<HTMLDivElement>(null)\n const menuId = React.useId()\n\n const setOpen = React.useCallback(\n (value: boolean) => {\n if (onOpenChange) onOpenChange(value)\n if (!isControlled) setInternalOpen(value)\n },\n [onOpenChange, isControlled],\n )\n\n // ── Floating UI positioning ──\n React.useEffect(() => {\n if (!isOpen || !anchorRef.current || !floatingRef.current) return\n\n const anchor = anchorRef.current\n const floating = floatingRef.current\n\n const update = () => {\n computePosition(anchor, floating, {\n placement: placementProp,\n middleware: [\n offset(8),\n flip({ fallbackPlacements: ['bottom-end', 'top-start', 'bottom-start'] }),\n shift({ padding: 8 }),\n ],\n }).then(({ x, y }) => {\n Object.assign(floating.style, { left: `${x}px`, top: `${y}px` })\n })\n }\n\n const cleanup = autoUpdate(anchor, floating, update)\n return cleanup\n }, [isOpen, placementProp])\n\n // ── Close on outside click ──\n React.useEffect(() => {\n if (!isOpen) return\n const handleClick = (e: MouseEvent) => {\n const target = e.target as Node\n if (\n anchorRef.current?.contains(target) ||\n floatingRef.current?.contains(target)\n ) return\n setOpen(false)\n }\n document.addEventListener('mousedown', handleClick)\n return () => document.removeEventListener('mousedown', handleClick)\n }, [isOpen, setOpen])\n\n // ── Close on Escape ──\n React.useEffect(() => {\n if (!isOpen) return\n const handleKey = (e: KeyboardEvent) => {\n if (e.key === 'Escape') setOpen(false)\n }\n document.addEventListener('keydown', handleKey)\n return () => document.removeEventListener('keydown', handleKey)\n }, [isOpen, setOpen])\n\n const halfClasses = getHalfClasses(variant, color)\n const divider = dividerColor[variant][color] ?? dividerColor[variant].accent\n\n const triggerStyle = triggerWidth != null\n ? { width: typeof triggerWidth === 'number' ? `${triggerWidth}px` : triggerWidth }\n : undefined\n\n return (\n <>\n {/* Button group */}\n <div\n ref={ref}\n role=\"group\"\n aria-label={ariaLabel ?? undefined}\n className={cn('relative inline-flex', className)}\n >\n <div\n ref={anchorRef}\n className={cn(\n 'inline-flex items-stretch overflow-hidden',\n radiusClass[size],\n variant === 'solid' && 'shadow-raised',\n variant === 'outline' && `border ${getOutlineBorderColor(color)}`,\n )}\n >\n {triggerSide === 'left' && (\n <>\n {/* Dropdown trigger (left) */}\n <button\n type=\"button\"\n onClick={() => setOpen(!isOpen)}\n disabled={disabled}\n aria-label={dropdownLabel}\n aria-haspopup=\"menu\"\n aria-expanded={isOpen}\n aria-controls={isOpen ? menuId : undefined}\n className={cn(\n 'inline-flex items-center justify-center select-none',\n 'transition-colors duration-fast-01 ease-productive-standard',\n 'focus-visible:outline-hidden focus-visible:ring-2 focus-visible:ring-accent-9 focus-visible:ring-inset',\n 'disabled:pointer-events-none disabled:opacity-action-disabled',\n halfClasses,\n heightClass[size],\n triggerPadding[size],\n )}\n style={triggerStyle}\n >\n {dropdownIcon ?? <ChevronDown />}\n </button>\n <div className={cn('w-px self-stretch', divider)} />\n </>\n )}\n\n {/* Primary action */}\n <button\n type=\"button\"\n onClick={onClick}\n disabled={disabled}\n aria-label={ariaLabel}\n className={cn(\n 'inline-flex items-center justify-center font-semibold select-none whitespace-nowrap',\n 'transition-[colors,transform] duration-fast-01 ease-productive-standard',\n 'active:scale-[0.97]',\n 'focus-visible:outline-hidden focus-visible:ring-2 focus-visible:ring-accent-9 focus-visible:ring-inset',\n 'disabled:pointer-events-none disabled:opacity-action-disabled',\n halfClasses,\n heightClass[size],\n textClass[size],\n primaryPadding[size],\n )}\n >\n {children}\n </button>\n\n {triggerSide === 'right' && (\n <>\n <div className={cn('w-px self-stretch', divider)} />\n {/* Dropdown trigger (right) */}\n <button\n type=\"button\"\n onClick={() => setOpen(!isOpen)}\n disabled={disabled}\n aria-label={dropdownLabel}\n aria-haspopup=\"menu\"\n aria-expanded={isOpen}\n aria-controls={isOpen ? menuId : undefined}\n className={cn(\n 'inline-flex items-center justify-center select-none',\n 'transition-colors duration-fast-01 ease-productive-standard',\n 'focus-visible:outline-hidden focus-visible:ring-2 focus-visible:ring-accent-9 focus-visible:ring-inset',\n 'disabled:pointer-events-none disabled:opacity-action-disabled',\n halfClasses,\n heightClass[size],\n triggerPadding[size],\n )}\n style={triggerStyle}\n >\n {dropdownIcon ?? <ChevronDown />}\n </button>\n </>\n )}\n </div>\n </div>\n\n {/* Floating dropdown panel */}\n <AnimatePresence>\n {isOpen && dropdownContent && (\n <div\n ref={floatingRef}\n id={menuId}\n role=\"menu\"\n className=\"fixed z-popover\"\n style={{ top: 0, left: 0 }}\n >\n <motion.div\n initial={{ opacity: 0, scale: 0.95 }}\n animate={{ opacity: 1, scale: 1 }}\n exit={{ opacity: 0, scale: 0.95 }}\n transition={{ duration: durations.moderate01 }}\n className=\"rounded-overlay border border-surface-border-strong bg-surface-overlay shadow-floating\"\n >\n {dropdownContent}\n </motion.div>\n </div>\n )}\n </AnimatePresence>\n </>\n )\n },\n)\n\nSplitButton.displayName = 'SplitButton'\n\nexport { SplitButton }\nexport type { SplitButtonColor, SplitButtonSize,SplitButtonVariant }\n"],"mappings":"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"}
1
+ {"version":3,"file":"split-button.js","names":[],"sources":["../../src/ui/split-button.tsx"],"sourcesContent":["'use client'\n\nimport { autoUpdate, computePosition, flip, offset, type Placement,shift } from '@floating-ui/dom'\nimport { type VariantProps } from 'class-variance-authority'\nimport { AnimatePresence, motion } from 'framer-motion'\nimport * as React from 'react'\n\nimport { buttonVariants } from './button'\nimport { durations } from './lib/motion'\nimport { cn } from './lib/utils'\n\n// ── Types ───────────────────────────────────────────────────────\n\ntype SplitButtonVariant = 'solid' | 'soft' | 'outline'\ntype SplitButtonColor = NonNullable<VariantProps<typeof buttonVariants>['color']>\ntype SplitButtonSize = 'xs' | 'sm' | 'md' | 'icon-xs' | 'icon-sm' | 'icon-md'\n\nexport interface SplitButtonProps {\n /** Primary action content (left side). */\n children: React.ReactNode\n /** Primary click handler (left side). */\n onClick: (e: React.MouseEvent<HTMLButtonElement>) => void\n /** Content rendered inside the floating dropdown panel. */\n dropdownContent?: React.ReactNode\n /** Controlled open state. */\n open?: boolean\n /** Called when open state changes. Uncontrolled if omitted. */\n onOpenChange?: (open: boolean) => void\n /** @default 'solid' */\n variant?: SplitButtonVariant\n /** @default 'accent' */\n color?: SplitButtonColor\n /** @default 'md' */\n size?: SplitButtonSize\n /** Disable both halves. */\n disabled?: boolean\n /** aria-label for the primary button. */\n 'aria-label'?: string\n /** aria-label for the dropdown trigger. @default 'More options' */\n dropdownLabel?: string\n /** Custom icon for the dropdown trigger. Defaults to chevron-down. */\n dropdownIcon?: React.ReactNode\n /** Which side the dropdown trigger sits on. @default 'right' */\n triggerSide?: 'left' | 'right'\n /** Preferred placement for the dropdown panel. @default 'top-end' */\n placement?: Placement\n /** Width of the trigger (chevron) half. @default 'auto' */\n triggerWidth?: number | string\n className?: string\n}\n\n// ── Styling maps ────────────────────────────────────────────────\n\nconst dividerColor: Record<SplitButtonVariant, Record<string, string>> = {\n solid: {\n accent: 'bg-accent-11/20', error: 'bg-error-11/20', success: 'bg-success-11/20',\n warning: 'bg-warning-11/20', neutral: 'bg-neutral-8/30',\n },\n soft: {\n accent: 'bg-accent-6', error: 'bg-error-6', success: 'bg-success-6',\n warning: 'bg-warning-6', neutral: 'bg-surface-border',\n },\n outline: {\n accent: 'bg-accent-7', error: 'bg-error-7', success: 'bg-success-7',\n warning: 'bg-warning-7', neutral: 'bg-surface-border-strong',\n },\n}\n\nconst heightClass: Record<SplitButtonSize, string> = {\n xs: 'h-ds-xs-plus', sm: 'h-ds-sm', md: 'h-ds-md',\n 'icon-xs': 'h-ds-xs-plus', 'icon-sm': 'h-ds-sm', 'icon-md': 'h-ds-md',\n}\n\nconst textClass: Record<SplitButtonSize, string> = {\n xs: 'text-ds-sm', sm: 'text-ds-sm', md: 'text-ds-md',\n 'icon-xs': 'text-ds-sm', 'icon-sm': 'text-ds-sm', 'icon-md': 'text-ds-md',\n}\n\nconst primaryPadding: Record<SplitButtonSize, string> = {\n xs: 'px-ds-03 gap-1', sm: 'px-ds-04 gap-1.5', md: 'px-ds-05 gap-2',\n 'icon-xs': 'px-ds-02', 'icon-sm': 'px-ds-03', 'icon-md': 'px-ds-04',\n}\n\nconst triggerPadding: Record<SplitButtonSize, string> = {\n xs: 'px-ds-02', sm: 'px-ds-02', md: 'px-ds-03',\n 'icon-xs': 'px-ds-01', 'icon-sm': 'px-ds-02', 'icon-md': 'px-ds-02',\n}\n\nconst radiusClass: Record<SplitButtonSize, string> = {\n xs: 'rounded-control', sm: 'rounded-control', md: 'rounded-control',\n 'icon-xs': 'rounded-control', 'icon-sm': 'rounded-control', 'icon-md': 'rounded-control',\n}\n\nfunction getHalfClasses(variant: SplitButtonVariant, color: string): string {\n const map: Record<SplitButtonVariant, Record<string, string>> = {\n solid: {\n accent: 'bg-accent-9 text-accent-fg hover:bg-accent-10 active:bg-accent-11',\n error: 'bg-error-9 text-error-fg hover:bg-error-10 active:bg-error-11',\n success: 'bg-success-9 text-success-fg hover:bg-success-10 active:bg-success-11',\n warning: 'bg-warning-9 text-warning-fg hover:bg-warning-10 active:bg-warning-11',\n neutral: 'bg-neutral-5 text-surface-fg hover:bg-neutral-7 active:bg-neutral-8',\n },\n soft: {\n accent: 'bg-accent-3 text-accent-11 hover:bg-accent-4 active:bg-accent-5',\n error: 'bg-error-3 text-error-11 hover:bg-error-4 active:bg-error-5',\n success: 'bg-success-3 text-success-11 hover:bg-success-4 active:bg-success-5',\n warning: 'bg-warning-3 text-warning-11 hover:bg-warning-4 active:bg-warning-5',\n neutral: 'bg-surface-raised-hover text-surface-fg-muted hover:bg-surface-raised-active active:bg-neutral-5',\n },\n outline: {\n accent: 'bg-transparent text-accent-11 hover:bg-accent-3 active:bg-accent-4',\n error: 'bg-transparent text-error-11 hover:bg-error-3 active:bg-error-4',\n success: 'bg-transparent text-success-11 hover:bg-success-3 active:bg-success-4',\n warning: 'bg-transparent text-warning-11 hover:bg-warning-3 active:bg-warning-4',\n neutral: 'bg-transparent text-surface-fg hover:bg-surface-raised-hover active:bg-surface-raised-active',\n },\n }\n return map[variant][color] ?? map[variant].accent\n}\n\nfunction getOutlineBorderColor(color: string): string {\n const map: Record<string, string> = {\n accent: 'border-accent-7', error: 'border-error-7', success: 'border-success-7',\n warning: 'border-warning-7', neutral: 'border-surface-border-strong',\n }\n return map[color] ?? map.accent\n}\n\n// ── Chevron SVG ─────────────────────────────────────────────────\n\nfunction ChevronDown({ className }: { className?: string }) {\n return (\n <svg width=\"12\" height=\"12\" viewBox=\"0 0 12 12\" fill=\"none\" className={className} aria-hidden=\"true\">\n <path d=\"M3 4.5L6 7.5L9 4.5\" stroke=\"currentColor\" strokeWidth=\"1.5\" strokeLinecap=\"round\" strokeLinejoin=\"round\" />\n </svg>\n )\n}\n\n// ── Component ───────────────────────────────────────────────────\n\nconst SplitButton = React.forwardRef<HTMLDivElement, SplitButtonProps>(\n function SplitButton(\n {\n children,\n onClick,\n dropdownContent,\n open: openProp,\n onOpenChange,\n variant = 'solid',\n color = 'accent',\n size = 'md',\n disabled = false,\n 'aria-label': ariaLabel,\n dropdownLabel = 'More options',\n dropdownIcon,\n triggerSide = 'right',\n placement: placementProp = 'top-end',\n triggerWidth,\n className,\n },\n ref,\n ) {\n const [internalOpen, setInternalOpen] = React.useState(false)\n const isControlled = openProp !== undefined\n const isOpen = isControlled ? openProp : internalOpen\n\n const anchorRef = React.useRef<HTMLDivElement>(null)\n const floatingRef = React.useRef<HTMLDivElement>(null)\n const menuId = React.useId()\n\n const setOpen = React.useCallback(\n (value: boolean) => {\n if (onOpenChange) onOpenChange(value)\n if (!isControlled) setInternalOpen(value)\n },\n [onOpenChange, isControlled],\n )\n\n // ── Floating UI positioning ──\n React.useEffect(() => {\n if (!isOpen || !anchorRef.current || !floatingRef.current) return\n\n const anchor = anchorRef.current\n const floating = floatingRef.current\n\n const update = () => {\n computePosition(anchor, floating, {\n placement: placementProp,\n middleware: [\n offset(8),\n flip({ fallbackPlacements: ['bottom-end', 'top-start', 'bottom-start'] }),\n shift({ padding: 8 }),\n ],\n }).then(({ x, y }) => {\n Object.assign(floating.style, { left: `${x}px`, top: `${y}px` })\n })\n }\n\n const cleanup = autoUpdate(anchor, floating, update)\n return cleanup\n }, [isOpen, placementProp])\n\n // ── Close on outside click ──\n React.useEffect(() => {\n if (!isOpen) return\n const handleClick = (e: MouseEvent) => {\n const target = e.target as Node\n if (\n anchorRef.current?.contains(target) ||\n floatingRef.current?.contains(target)\n ) return\n setOpen(false)\n }\n document.addEventListener('mousedown', handleClick)\n return () => document.removeEventListener('mousedown', handleClick)\n }, [isOpen, setOpen])\n\n // ── Close on Escape ──\n React.useEffect(() => {\n if (!isOpen) return\n const handleKey = (e: KeyboardEvent) => {\n if (e.key === 'Escape') setOpen(false)\n }\n document.addEventListener('keydown', handleKey)\n return () => document.removeEventListener('keydown', handleKey)\n }, [isOpen, setOpen])\n\n const halfClasses = getHalfClasses(variant, color)\n const divider = dividerColor[variant][color] ?? dividerColor[variant].accent\n\n const triggerStyle = triggerWidth != null\n ? { width: typeof triggerWidth === 'number' ? `${triggerWidth}px` : triggerWidth }\n : undefined\n\n return (\n <>\n {/* Button group */}\n <div\n ref={ref}\n role=\"group\"\n aria-label={ariaLabel ?? undefined}\n className={cn('relative inline-flex', className)}\n >\n <div\n ref={anchorRef}\n className={cn(\n 'inline-flex items-stretch overflow-hidden',\n radiusClass[size],\n variant === 'solid' && 'shadow-raised',\n variant === 'outline' && `border ${getOutlineBorderColor(color)}`,\n )}\n >\n {triggerSide === 'left' && (\n <>\n {/* Dropdown trigger (left) */}\n <button\n type=\"button\"\n onClick={() => setOpen(!isOpen)}\n disabled={disabled}\n aria-label={dropdownLabel}\n aria-haspopup=\"menu\"\n aria-expanded={isOpen}\n aria-controls={isOpen ? menuId : undefined}\n className={cn(\n 'inline-flex items-center justify-center select-none',\n 'transition-colors duration-fast-01 ease-productive-standard',\n 'focus-visible:outline-hidden focus-visible:ring-2 focus-visible:ring-accent-9 focus-visible:ring-inset',\n 'disabled:pointer-events-none disabled:opacity-action-disabled',\n halfClasses,\n heightClass[size],\n triggerPadding[size],\n )}\n style={triggerStyle}\n >\n {dropdownIcon ?? <ChevronDown />}\n </button>\n <div className={cn('w-px self-stretch', divider)} />\n </>\n )}\n\n {/* Primary action */}\n <button\n type=\"button\"\n onClick={onClick}\n disabled={disabled}\n aria-label={ariaLabel}\n className={cn(\n 'inline-flex items-center justify-center font-semibold select-none whitespace-nowrap',\n 'transition-[colors,transform] duration-fast-01 ease-productive-standard',\n 'active:scale-[0.97]',\n 'focus-visible:outline-hidden focus-visible:ring-2 focus-visible:ring-accent-9 focus-visible:ring-inset',\n 'disabled:pointer-events-none disabled:opacity-action-disabled',\n halfClasses,\n heightClass[size],\n textClass[size],\n primaryPadding[size],\n )}\n >\n {children}\n </button>\n\n {triggerSide === 'right' && (\n <>\n <div className={cn('w-px self-stretch', divider)} />\n {/* Dropdown trigger (right) */}\n <button\n type=\"button\"\n onClick={() => setOpen(!isOpen)}\n disabled={disabled}\n aria-label={dropdownLabel}\n aria-haspopup=\"menu\"\n aria-expanded={isOpen}\n aria-controls={isOpen ? menuId : undefined}\n className={cn(\n 'inline-flex items-center justify-center select-none',\n 'transition-colors duration-fast-01 ease-productive-standard',\n 'focus-visible:outline-hidden focus-visible:ring-2 focus-visible:ring-accent-9 focus-visible:ring-inset',\n 'disabled:pointer-events-none disabled:opacity-action-disabled',\n halfClasses,\n heightClass[size],\n triggerPadding[size],\n )}\n style={triggerStyle}\n >\n {dropdownIcon ?? <ChevronDown />}\n </button>\n </>\n )}\n </div>\n </div>\n\n {/* Floating dropdown panel */}\n <AnimatePresence>\n {isOpen && dropdownContent && (\n <div\n ref={floatingRef}\n id={menuId}\n role=\"menu\"\n className=\"fixed z-popover\"\n style={{ top: 0, left: 0 }}\n >\n <motion.div\n initial={{ opacity: 0, scale: 0.95 }}\n animate={{ opacity: 1, scale: 1 }}\n exit={{ opacity: 0, scale: 0.95 }}\n transition={{ duration: durations.moderate01 }}\n className=\"rounded-overlay bg-surface-overlay shadow-floating\"\n >\n {dropdownContent}\n </motion.div>\n </div>\n )}\n </AnimatePresence>\n </>\n )\n },\n)\n\nSplitButton.displayName = 'SplitButton'\n\nexport { SplitButton }\nexport type { SplitButtonColor, SplitButtonSize,SplitButtonVariant }\n"],"mappings":"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"}
@@ -1,10 +1,19 @@
1
1
  "use client";
2
2
  import { IconInput } from './lib/icon-input';
3
+ import { FlashPreset, FlashSpec, FlashSpeed } from './stat-flash';
3
4
  import * as React from 'react';
4
5
  /**
5
6
  * Props for StatCard — a dashboard metric tile displaying a label, a large numeric value,
6
7
  * an optional trend delta (with directional arrow icon), and an optional header icon.
7
8
  *
9
+ * **Surface:** delegated to `Card` via `variant` — `default` (ring-in-shadow, no border) |
10
+ * `elevated` | `outline` (border, no shadow) | `flat`. StatCard composes `<Card>`, so the surface,
11
+ * padding (gap model), and elevation all live in one place.
12
+ *
13
+ * **Accent:** `accentStyle="none"` (default) is neutral; `"icon"` wraps `icon` in an accent chip
14
+ * (`iconFill="soft" | "solid"`); `"tint"` applies a subtle accent surface wash + accent value.
15
+ * (Replaces the removed `accent` left-rail prop — see CHANGELOG migration.)
16
+ *
8
17
  * **Delta direction:** `'up'` renders a green trending-up arrow, `'down'` renders a red
9
18
  * trending-down arrow, `'neutral'` renders a grey dash. The `delta.value` is a formatted
10
19
  * string (e.g. `"+8%"` or `"−120"`).
@@ -41,7 +50,7 @@ import * as React from 'react';
41
50
  * />
42
51
  * // These are just a few ways — feel free to combine props creatively!
43
52
  */
44
- export interface StatCardProps extends React.HTMLAttributes<HTMLDivElement> {
53
+ export interface StatCardProps extends Omit<React.HTMLAttributes<HTMLDivElement>, 'color'> {
45
54
  /** Heading text for the metric. `title` is an alias for `label`. */
46
55
  label?: string;
47
56
  /** Alias for `label` — use whichever feels natural. */
@@ -55,6 +64,8 @@ export interface StatCardProps extends React.HTMLAttributes<HTMLDivElement> {
55
64
  value: string;
56
65
  direction: 'up' | 'down' | 'neutral';
57
66
  };
67
+ /** Where the delta sits relative to the value: `block` (below — default) or `inline` (on the value's baseline, to its right). @default 'block' */
68
+ deltaPlacement?: 'block' | 'inline';
58
69
  icon?: IconInput;
59
70
  loading?: boolean;
60
71
  /** Comparison period label shown after delta, e.g. "vs last month" */
@@ -63,8 +74,20 @@ export interface StatCardProps extends React.HTMLAttributes<HTMLDivElement> {
63
74
  secondaryLabel?: string;
64
75
  /** Progress toward a target (0-100). Renders a thin progress bar below the value. */
65
76
  progress?: number;
66
- /** Color accent for the left border decoration */
67
- accent?: 'default' | 'success' | 'warning' | 'error' | 'info';
77
+ /** Surface variant, delegated to Card: `default` (ring-in-shadow) | `elevated` | `outline` (border, no shadow) | `flat`. @default 'default' */
78
+ variant?: 'default' | 'elevated' | 'outline' | 'flat';
79
+ /** How the brand accent reads: `none` (neutral — default), `icon` (accent chip around `icon`), or `tint` (subtle accent surface wash + accent value). */
80
+ accentStyle?: 'none' | 'icon' | 'tint';
81
+ /** When `accentStyle="icon"`: `soft` (tinted chip) or `solid` (filled accent chip). @default 'soft' */
82
+ iconFill?: 'soft' | 'solid';
83
+ /**
84
+ * Opt-in entrance flash: the icon chip mounts showing a transient state (e.g. a green up-arrow)
85
+ * then settles to `icon`. A preset (`'up' | 'down' | 'goal' | 'record' | 'alert' | 'live'`) or an
86
+ * explicit `{ tone, icon }`. Requires `icon`; implies the icon chip. Off by default.
87
+ */
88
+ flash?: FlashPreset | FlashSpec;
89
+ /** Speed of the entrance flash: `fast` | `normal` | `slow`. @default 'normal' */
90
+ flashSpeed?: FlashSpeed;
68
91
  /** Sparkline data points. Renders a mini SVG line chart in the card. */
69
92
  sparkline?: number[];
70
93
  /** Make the card clickable with hover state */
@@ -1 +1 @@
1
- {"version":3,"file":"stat-card.d.ts","sourceRoot":"","sources":["../../src/ui/stat-card.tsx"],"names":[],"mappings":"AAIA,OAAO,KAAK,KAAK,MAAM,OAAO,CAAA;AAI9B,OAAO,KAAK,EAAE,SAAS,EAAE,MAAM,kBAAkB,CAAA;AAMjD;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;GAuCG;AACH,MAAM,WAAW,aAAc,SAAQ,KAAK,CAAC,cAAc,CAAC,cAAc,CAAC;IACzE,oEAAoE;IACpE,KAAK,CAAC,EAAE,MAAM,CAAA;IACd,uDAAuD;IACvD,KAAK,CAAC,EAAE,MAAM,CAAA;IACd,KAAK,EAAE,MAAM,GAAG,MAAM,CAAA;IACtB,oCAAoC;IACpC,MAAM,CAAC,EAAE,MAAM,CAAA;IACf,uCAAuC;IACvC,MAAM,CAAC,EAAE,MAAM,CAAA;IACf,KAAK,CAAC,EAAE;QACN,KAAK,EAAE,MAAM,CAAA;QACb,SAAS,EAAE,IAAI,GAAG,MAAM,GAAG,SAAS,CAAA;KACrC,CAAA;IACD,IAAI,CAAC,EAAE,SAAS,CAAA;IAChB,OAAO,CAAC,EAAE,OAAO,CAAA;IACjB,sEAAsE;IACtE,eAAe,CAAC,EAAE,MAAM,CAAA;IACxB,kEAAkE;IAClE,cAAc,CAAC,EAAE,MAAM,CAAA;IACvB,qFAAqF;IACrF,QAAQ,CAAC,EAAE,MAAM,CAAA;IACjB,kDAAkD;IAClD,MAAM,CAAC,EAAE,SAAS,GAAG,SAAS,GAAG,SAAS,GAAG,OAAO,GAAG,MAAM,CAAA;IAC7D,wEAAwE;IACxE,SAAS,CAAC,EAAE,MAAM,EAAE,CAAA;IACpB,+CAA+C;IAC/C,OAAO,CAAC,EAAE,MAAM,IAAI,CAAA;IACpB,yEAAyE;IACzE,IAAI,CAAC,EAAE,MAAM,CAAA;IACb,yEAAyE;IACzE,MAAM,CAAC,EAAE,KAAK,CAAC,SAAS,CAAA;CACzB;AAuGD,QAAA,MAAM,QAAQ,sFAwNb,CAAA;AAID,OAAO,EAAE,QAAQ,EAAE,CAAA"}
1
+ {"version":3,"file":"stat-card.d.ts","sourceRoot":"","sources":["../../src/ui/stat-card.tsx"],"names":[],"mappings":"AAIA,OAAO,KAAK,KAAK,MAAM,OAAO,CAAA;AAK9B,OAAO,KAAK,EAAE,SAAS,EAAE,MAAM,kBAAkB,CAAA;AAKjD,OAAO,EAAE,KAAK,WAAW,EAAE,KAAK,SAAS,EAAE,KAAK,UAAU,EAAY,MAAM,cAAc,CAAA;AAE1F;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;GA+CG;AACH,MAAM,WAAW,aAAc,SAAQ,IAAI,CAAC,KAAK,CAAC,cAAc,CAAC,cAAc,CAAC,EAAE,OAAO,CAAC;IACxF,oEAAoE;IACpE,KAAK,CAAC,EAAE,MAAM,CAAA;IACd,uDAAuD;IACvD,KAAK,CAAC,EAAE,MAAM,CAAA;IACd,KAAK,EAAE,MAAM,GAAG,MAAM,CAAA;IACtB,oCAAoC;IACpC,MAAM,CAAC,EAAE,MAAM,CAAA;IACf,uCAAuC;IACvC,MAAM,CAAC,EAAE,MAAM,CAAA;IACf,KAAK,CAAC,EAAE;QACN,KAAK,EAAE,MAAM,CAAA;QACb,SAAS,EAAE,IAAI,GAAG,MAAM,GAAG,SAAS,CAAA;KACrC,CAAA;IACD,kJAAkJ;IAClJ,cAAc,CAAC,EAAE,OAAO,GAAG,QAAQ,CAAA;IACnC,IAAI,CAAC,EAAE,SAAS,CAAA;IAChB,OAAO,CAAC,EAAE,OAAO,CAAA;IACjB,sEAAsE;IACtE,eAAe,CAAC,EAAE,MAAM,CAAA;IACxB,kEAAkE;IAClE,cAAc,CAAC,EAAE,MAAM,CAAA;IACvB,qFAAqF;IACrF,QAAQ,CAAC,EAAE,MAAM,CAAA;IACjB,+IAA+I;IAC/I,OAAO,CAAC,EAAE,SAAS,GAAG,UAAU,GAAG,SAAS,GAAG,MAAM,CAAA;IACrD,yJAAyJ;IACzJ,WAAW,CAAC,EAAE,MAAM,GAAG,MAAM,GAAG,MAAM,CAAA;IACtC,uGAAuG;IACvG,QAAQ,CAAC,EAAE,MAAM,GAAG,OAAO,CAAA;IAC3B;;;;OAIG;IACH,KAAK,CAAC,EAAE,WAAW,GAAG,SAAS,CAAA;IAC/B,iFAAiF;IACjF,UAAU,CAAC,EAAE,UAAU,CAAA;IACvB,wEAAwE;IACxE,SAAS,CAAC,EAAE,MAAM,EAAE,CAAA;IACpB,+CAA+C;IAC/C,OAAO,CAAC,EAAE,MAAM,IAAI,CAAA;IACpB,yEAAyE;IACzE,IAAI,CAAC,EAAE,MAAM,CAAA;IACb,yEAAyE;IACzE,MAAM,CAAC,EAAE,KAAK,CAAC,SAAS,CAAA;CACzB;AA+FD,QAAA,MAAM,QAAQ,sFA2Pb,CAAA;AAID,OAAO,EAAE,QAAQ,EAAE,CAAA"}
@@ -4,20 +4,15 @@ import { springs as t, tweens as n } from "./lib/motion.js";
4
4
  import { cn as r } from "./lib/utils.js";
5
5
  import { Icon as i } from "./icon.js";
6
6
  import { t as a } from "../_chunks/normalize-icon.js";
7
- import { n as o } from "../_chunks/link-context.js";
8
- import * as s from "react";
9
- import { Fragment as c, jsx as l, jsxs as u } from "react/jsx-runtime";
10
- import { IconMinus as d, IconTrendingDown as f, IconTrendingUp as p } from "@tabler/icons-react";
11
- import { motion as m } from "framer-motion";
7
+ import { Card as o, CardContent as s } from "./card.js";
8
+ import { n as c } from "../_chunks/link-context.js";
9
+ import { StatFlash as l } from "./stat-flash.js";
10
+ import * as u from "react";
11
+ import { Fragment as d, jsx as f, jsxs as p } from "react/jsx-runtime";
12
+ import { IconMinus as m, IconTrendingDown as h, IconTrendingUp as g } from "@tabler/icons-react";
13
+ import { motion as _ } from "framer-motion";
12
14
  //#region src/ui/stat-card.tsx
13
- var h = {
14
- default: "border-l-accent-9",
15
- success: "border-l-success-9",
16
- warning: "border-l-warning-9",
17
- error: "border-l-error-9",
18
- info: "border-l-info-9"
19
- };
20
- function g(e, t, n) {
15
+ function v(e, t, n) {
21
16
  let r = e.filter((e) => Number.isFinite(e));
22
17
  if (r.length < 2) return "";
23
18
  let i = Math.min(...r), a = Math.max(...r) - i || 1, o = t / (r.length - 1);
@@ -26,43 +21,43 @@ function g(e, t, n) {
26
21
  return `${t === 0 ? "M" : "L"}${r.toFixed(1)},${s.toFixed(1)}`;
27
22
  }).join(" ");
28
23
  }
29
- function _({ data: e, colorClass: t }) {
30
- let n = s.useId(), i = s.useRef(null), [a, o] = s.useState(0), c = g(e, 80, 32);
31
- if (s.useEffect(() => {
24
+ function y({ data: e, colorClass: t }) {
25
+ let n = u.useId(), i = u.useRef(null), [a, o] = u.useState(0), s = v(e, 80, 32);
26
+ if (u.useEffect(() => {
32
27
  i.current && o(i.current.getTotalLength());
33
- }, [c]), !c) return null;
34
- let d = `${c} L${80 .toFixed(1)},${32 .toFixed(1)} L0,${32 .toFixed(1)} Z`;
35
- return /* @__PURE__ */ u("div", {
28
+ }, [s]), !s) return null;
29
+ let c = `${s} L${80 .toFixed(1)},${32 .toFixed(1)} L0,${32 .toFixed(1)} Z`;
30
+ return /* @__PURE__ */ p("div", {
36
31
  className: r("w-20 h-8", t),
37
32
  "aria-hidden": "true",
38
- children: [/* @__PURE__ */ u("svg", {
33
+ children: [/* @__PURE__ */ p("svg", {
39
34
  viewBox: "0 0 80 32",
40
35
  className: "w-full h-full overflow-visible",
41
36
  preserveAspectRatio: "none",
42
37
  children: [
43
- /* @__PURE__ */ l("defs", { children: /* @__PURE__ */ u("linearGradient", {
38
+ /* @__PURE__ */ f("defs", { children: /* @__PURE__ */ p("linearGradient", {
44
39
  id: `sparkline-fill-${n}`,
45
40
  x1: "0",
46
41
  y1: "0",
47
42
  x2: "0",
48
43
  y2: "1",
49
- children: [/* @__PURE__ */ l("stop", {
44
+ children: [/* @__PURE__ */ f("stop", {
50
45
  offset: "0%",
51
46
  stopColor: "currentColor",
52
47
  stopOpacity: "0.1"
53
- }), /* @__PURE__ */ l("stop", {
48
+ }), /* @__PURE__ */ f("stop", {
54
49
  offset: "100%",
55
50
  stopColor: "currentColor",
56
51
  stopOpacity: "0"
57
52
  })]
58
53
  }) }),
59
- /* @__PURE__ */ l("path", {
60
- d,
54
+ /* @__PURE__ */ f("path", {
55
+ d: c,
61
56
  fill: `url(#sparkline-fill-${n})`
62
57
  }),
63
- /* @__PURE__ */ l("path", {
58
+ /* @__PURE__ */ f("path", {
64
59
  ref: i,
65
- d: c,
60
+ d: s,
66
61
  fill: "none",
67
62
  stroke: "currentColor",
68
63
  strokeWidth: "1.5",
@@ -76,51 +71,110 @@ function _({ data: e, colorClass: t }) {
76
71
  }
77
72
  })
78
73
  ]
79
- }), a > 0 && /* @__PURE__ */ l("style", { children: `@keyframes sparkline-draw-${n.replace(/:/g, "")} { to { stroke-dashoffset: 0; } }` })]
74
+ }), a > 0 && /* @__PURE__ */ f("style", { children: `@keyframes sparkline-draw-${n.replace(/:/g, "")} { to { stroke-dashoffset: 0; } }` })]
80
75
  });
81
76
  }
82
- function v({ progress: e, label: t }) {
77
+ function b({ progress: e, label: t }) {
83
78
  let n = Math.max(0, Math.min(100, e)), i = n >= 90 ? "bg-success-9" : n >= 70 ? "bg-warning-9" : "bg-accent-9";
84
- return /* @__PURE__ */ l("div", {
79
+ return /* @__PURE__ */ f("div", {
85
80
  className: "h-1 w-full rounded-pill bg-surface-raised mt-ds-04",
86
81
  role: "progressbar",
87
82
  "aria-label": `${t} progress`,
88
83
  "aria-valuenow": n,
89
84
  "aria-valuemin": 0,
90
85
  "aria-valuemax": 100,
91
- children: /* @__PURE__ */ l("div", {
86
+ children: /* @__PURE__ */ f("div", {
92
87
  className: r("h-full rounded-pill transition-[width] duration-moderate-02 ease-productive-standard", i),
93
88
  style: { width: `${n}%` }
94
89
  })
95
90
  });
96
91
  }
97
- var y = s.forwardRef(({ className: s, label: g, title: y, value: b, prefix: x, suffix: S, delta: C, icon: w, loading: T, comparisonLabel: E, secondaryLabel: D, progress: O, accent: k, sparkline: A, onClick: j, href: M, footer: N, ...P }, F) => {
98
- let I = o(), L = y ?? g ?? "", R = !!(j || M), z = R && !P["aria-label"] ? `View ${L}` : P["aria-label"];
99
- if (T) return /* @__PURE__ */ u("div", {
100
- ref: F,
101
- className: r("rounded-surface border border-surface-border bg-surface-raised shadow-raised p-ds-05b", k && `border-l-[3px] ${h[k]}`, s),
102
- ...P,
92
+ var x = u.forwardRef(({ className: u, label: v, title: x, value: S, prefix: C, suffix: w, delta: T, deltaPlacement: E = "block", icon: D, loading: O, comparisonLabel: k, secondaryLabel: A, progress: j, variant: M = "default", accentStyle: N = "none", iconFill: P = "soft", flash: F, flashSpeed: I, sparkline: L, onClick: R, href: z, footer: B, ...V }, H) => {
93
+ let U = c(), W = x ?? v ?? "", G = (R || z) && !V["aria-label"] ? `View ${W}` : V["aria-label"];
94
+ if (O) return /* @__PURE__ */ f(o, {
95
+ ref: H,
96
+ variant: M,
97
+ className: u,
98
+ ...V,
99
+ children: /* @__PURE__ */ p(s, { children: [
100
+ /* @__PURE__ */ f("div", { className: "h-ds-04 w-24 rounded-control-inner bg-skeleton-base animate-pulse mb-ds-05" }),
101
+ /* @__PURE__ */ f("div", { className: "h-ds-sm w-32 rounded-control bg-skeleton-base animate-pulse mb-ds-03" }),
102
+ /* @__PURE__ */ f("div", { className: "h-3 w-16 rounded-control-inner bg-skeleton-base animate-pulse" })
103
+ ] })
104
+ });
105
+ let K = T?.direction === "up" ? g : T?.direction === "down" ? h : m, q = T?.direction === "up" ? "text-success-11" : T?.direction === "down" ? "text-error-11" : "text-surface-fg-muted", J = T?.direction === "up" ? "text-success-11" : T?.direction === "down" ? "text-error-11" : "text-accent-11", Y = T ? /* @__PURE__ */ p(_.div, {
106
+ className: r("flex items-center gap-ds-02 text-ds-sm font-medium", q, E === "block" && "mt-ds-03"),
107
+ initial: {
108
+ opacity: 0,
109
+ y: 8
110
+ },
111
+ animate: {
112
+ opacity: 1,
113
+ y: 0
114
+ },
115
+ transition: {
116
+ ...t.smooth,
117
+ delay: .2
118
+ },
103
119
  children: [
104
- /* @__PURE__ */ l("div", { className: "h-ds-04 w-24 rounded-control-inner bg-skeleton-base animate-pulse mb-ds-05" }),
105
- /* @__PURE__ */ l("div", { className: "h-ds-sm w-32 rounded-control bg-skeleton-base animate-pulse mb-ds-03" }),
106
- /* @__PURE__ */ l("div", { className: "h-3 w-16 rounded-control-inner bg-skeleton-base animate-pulse" })
120
+ /* @__PURE__ */ f(_.span, {
121
+ className: "inline-flex",
122
+ initial: {
123
+ opacity: .5,
124
+ scale: 1.4
125
+ },
126
+ animate: {
127
+ opacity: 1,
128
+ scale: 1
129
+ },
130
+ transition: t.bouncy,
131
+ children: /* @__PURE__ */ f(i, {
132
+ icon: K,
133
+ size: "sm"
134
+ })
135
+ }),
136
+ /* @__PURE__ */ f("span", { children: T.value }),
137
+ k && /* @__PURE__ */ f("span", {
138
+ className: "text-surface-fg-subtle font-normal",
139
+ children: k
140
+ })
107
141
  ]
108
- });
109
- let B = C?.direction === "up" ? p : C?.direction === "down" ? f : d, V = C?.direction === "up" ? "text-success-11" : C?.direction === "down" ? "text-error-11" : "text-surface-fg-muted", H = C?.direction === "up" ? "text-success-11" : C?.direction === "down" ? "text-error-11" : "text-accent-11", U = /* @__PURE__ */ u(c, { children: [
110
- /* @__PURE__ */ u("div", {
142
+ }) : null, X = /* @__PURE__ */ p(d, { children: [
143
+ /* @__PURE__ */ p("div", {
111
144
  className: "flex items-center justify-between mb-ds-04",
112
- children: [/* @__PURE__ */ l(m.p, {
145
+ children: [/* @__PURE__ */ f(_.p, {
113
146
  className: "text-ds-md font-medium text-surface-fg-muted",
114
147
  initial: { opacity: 0 },
115
148
  animate: { opacity: 1 },
116
149
  transition: n.fade,
117
- children: L
118
- }), /* @__PURE__ */ u("div", {
150
+ children: W
151
+ }), /* @__PURE__ */ p("div", {
119
152
  className: "flex items-center gap-ds-03",
120
- children: [A && A.length >= 2 && /* @__PURE__ */ l(_, {
121
- data: A,
122
- colorClass: H
123
- }), w && /* @__PURE__ */ l(m.span, {
153
+ children: [L && L.length >= 2 && /* @__PURE__ */ f(y, {
154
+ data: L,
155
+ colorClass: J
156
+ }), D && F ? /* @__PURE__ */ f(l, {
157
+ icon: D,
158
+ flash: F,
159
+ fill: P,
160
+ speed: I
161
+ }) : D ? N === "icon" ? /* @__PURE__ */ f(_.span, {
162
+ className: r("inline-flex items-center justify-center rounded-control p-ds-02", P === "solid" ? "bg-accent-9 text-accent-fg" : "bg-accent-3 text-accent-11"),
163
+ initial: {
164
+ opacity: 0,
165
+ scale: .96
166
+ },
167
+ animate: {
168
+ opacity: 1,
169
+ scale: 1
170
+ },
171
+ transition: t.snappy,
172
+ "aria-hidden": "true",
173
+ children: /* @__PURE__ */ f(e, {
174
+ size: "md",
175
+ children: a(D, "md")
176
+ })
177
+ }) : /* @__PURE__ */ f(_.span, {
124
178
  className: "text-surface-fg-muted",
125
179
  initial: {
126
180
  opacity: 0,
@@ -132,43 +186,46 @@ var y = s.forwardRef(({ className: s, label: g, title: y, value: b, prefix: x, s
132
186
  },
133
187
  transition: t.snappy,
134
188
  "aria-hidden": "true",
135
- children: /* @__PURE__ */ l(e, {
189
+ children: /* @__PURE__ */ f(e, {
136
190
  size: "lg",
137
- children: a(w, "lg")
191
+ children: a(D, "lg")
138
192
  })
139
- })]
193
+ }) : null]
140
194
  })]
141
195
  }),
142
- /* @__PURE__ */ l("div", {
143
- className: "overflow-hidden",
144
- children: /* @__PURE__ */ u(m.p, {
145
- className: "inline-block text-ds-3xl font-semibold text-surface-fg",
146
- initial: {
147
- opacity: 0,
148
- y: "100%"
149
- },
150
- animate: {
151
- opacity: 1,
152
- y: 0
153
- },
154
- transition: t.smooth,
155
- children: [
156
- x && /* @__PURE__ */ l("span", {
157
- className: "text-surface-fg-muted text-ds-lg",
158
- children: x
159
- }),
160
- /* @__PURE__ */ l("span", {
161
- className: "tabular-nums",
162
- children: b
163
- }),
164
- S && /* @__PURE__ */ l("span", {
165
- className: "text-surface-fg-muted text-ds-lg",
166
- children: S
167
- })
168
- ]
169
- })
196
+ /* @__PURE__ */ p("div", {
197
+ className: r(E === "inline" && T && "flex items-baseline gap-ds-03"),
198
+ children: [/* @__PURE__ */ f("div", {
199
+ className: "overflow-hidden",
200
+ children: /* @__PURE__ */ p(_.p, {
201
+ className: r("inline-block text-ds-3xl font-semibold", N === "tint" ? "text-accent-11" : "text-surface-fg"),
202
+ initial: {
203
+ opacity: 0,
204
+ y: "100%"
205
+ },
206
+ animate: {
207
+ opacity: 1,
208
+ y: 0
209
+ },
210
+ transition: t.smooth,
211
+ children: [
212
+ C && /* @__PURE__ */ f("span", {
213
+ className: "text-surface-fg-muted text-ds-lg",
214
+ children: C
215
+ }),
216
+ /* @__PURE__ */ f("span", {
217
+ className: "tabular-nums",
218
+ children: S
219
+ }),
220
+ w && /* @__PURE__ */ f("span", {
221
+ className: "text-surface-fg-muted text-ds-lg",
222
+ children: w
223
+ })
224
+ ]
225
+ })
226
+ }), E === "inline" && Y]
170
227
  }),
171
- D && /* @__PURE__ */ l(m.p, {
228
+ A && /* @__PURE__ */ f(_.p, {
172
229
  className: "text-ds-sm text-surface-fg-subtle mt-ds-01",
173
230
  initial: { opacity: 0 },
174
231
  animate: { opacity: 1 },
@@ -176,59 +233,22 @@ var y = s.forwardRef(({ className: s, label: g, title: y, value: b, prefix: x, s
176
233
  ...n.fade,
177
234
  delay: .1
178
235
  },
179
- children: D
236
+ children: A
180
237
  }),
181
- O != null && /* @__PURE__ */ l(m.div, {
238
+ j != null && /* @__PURE__ */ f(_.div, {
182
239
  initial: { opacity: 0 },
183
240
  animate: { opacity: 1 },
184
241
  transition: {
185
242
  ...n.fade,
186
243
  delay: .15
187
244
  },
188
- children: /* @__PURE__ */ l(v, {
189
- progress: O,
190
- label: L
245
+ children: /* @__PURE__ */ f(b, {
246
+ progress: j,
247
+ label: W
191
248
  })
192
249
  }),
193
- C && /* @__PURE__ */ u(m.div, {
194
- className: r("mt-ds-03 flex items-center gap-ds-02 text-ds-sm font-medium", V),
195
- initial: {
196
- opacity: 0,
197
- y: 8
198
- },
199
- animate: {
200
- opacity: 1,
201
- y: 0
202
- },
203
- transition: {
204
- ...t.smooth,
205
- delay: .2
206
- },
207
- children: [
208
- /* @__PURE__ */ l(m.span, {
209
- className: "inline-flex",
210
- initial: {
211
- opacity: .5,
212
- scale: 1.4
213
- },
214
- animate: {
215
- opacity: 1,
216
- scale: 1
217
- },
218
- transition: t.bouncy,
219
- children: /* @__PURE__ */ l(i, {
220
- icon: B,
221
- size: "sm"
222
- })
223
- }),
224
- /* @__PURE__ */ l("span", { children: C.value }),
225
- E && /* @__PURE__ */ l("span", {
226
- className: "text-surface-fg-subtle font-normal",
227
- children: E
228
- })
229
- ]
230
- }),
231
- N && /* @__PURE__ */ l(m.div, {
250
+ E === "block" && Y,
251
+ B && /* @__PURE__ */ f(_.div, {
232
252
  className: "mt-ds-04 pt-ds-04 border-t border-surface-border text-ds-sm",
233
253
  initial: { opacity: 0 },
234
254
  animate: { opacity: 1 },
@@ -236,31 +256,44 @@ var y = s.forwardRef(({ className: s, label: g, title: y, value: b, prefix: x, s
236
256
  ...n.fade,
237
257
  delay: .25
238
258
  },
239
- children: N
259
+ children: B
260
+ })
261
+ ] }), Z = N === "tint" ? "bg-linear-to-t from-accent-2 to-surface-raised" : void 0, Q = /* @__PURE__ */ f(s, { children: X });
262
+ return z ? /* @__PURE__ */ f(U, {
263
+ ref: H,
264
+ href: z,
265
+ onClick: R,
266
+ className: "block no-underline",
267
+ "aria-label": G,
268
+ ...V,
269
+ children: /* @__PURE__ */ f(o, {
270
+ variant: M,
271
+ interactive: !0,
272
+ className: Z,
273
+ children: Q
240
274
  })
241
- ] }), W = r("rounded-surface border border-surface-border bg-surface-raised shadow-raised p-ds-05b", k && `border-l-[3px] ${h[k]}`, R && "cursor-pointer hover:shadow-raised-hover hover:border-surface-border-strong transition-[box-shadow,border-color] duration-fast-02 ease-productive-standard group", s);
242
- return M ? /* @__PURE__ */ l(I, {
243
- ref: F,
244
- href: M,
245
- onClick: j,
246
- className: r(W, "block no-underline"),
247
- "aria-label": z,
248
- ...P,
249
- children: U
250
- }) : /* @__PURE__ */ l("div", {
251
- ref: F,
252
- className: W,
253
- onClick: j,
254
- role: j ? "button" : void 0,
255
- tabIndex: j ? 0 : void 0,
256
- "aria-label": z,
257
- onKeyDown: j ? (e) => {
258
- (e.key === "Enter" || e.key === " ") && (e.preventDefault(), j());
259
- } : void 0,
260
- ...P,
261
- children: U
275
+ }) : R ? /* @__PURE__ */ f(o, {
276
+ ref: H,
277
+ variant: M,
278
+ interactive: !0,
279
+ className: r(Z, u),
280
+ role: "button",
281
+ tabIndex: 0,
282
+ "aria-label": G,
283
+ onClick: R,
284
+ onKeyDown: (e) => {
285
+ (e.key === "Enter" || e.key === " ") && (e.preventDefault(), R());
286
+ },
287
+ ...V,
288
+ children: Q
289
+ }) : /* @__PURE__ */ f(o, {
290
+ ref: H,
291
+ variant: M,
292
+ className: r(Z, u),
293
+ ...V,
294
+ children: Q
262
295
  });
263
296
  });
264
- y.displayName = "StatCard";
297
+ x.displayName = "StatCard";
265
298
  //#endregion
266
- export { y as StatCard };
299
+ export { x as StatCard };