@humain/ui 2.4.2 → 2.4.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.
- package/dist/index194.js +6 -8
- package/dist/index194.js.map +1 -1
- package/dist/index24.js +1 -1
- package/dist/index24.js.map +1 -1
- package/dist/styles.css +1 -1
- package/dist/wc/AIClarificationCard.js +1 -1
- package/dist/wc/AIContainer.js +1 -1
- package/dist/wc/AIForm.js +17 -17
- package/dist/wc/AIInput.js +1 -1
- package/dist/wc/AIMermaidDiagram.js +1 -1
- package/dist/wc/AIMessage.js +1 -1
- package/dist/wc/AIScrollButton.js +4 -4
- package/dist/wc/AIToolCall.js +5 -5
- package/dist/wc/AppSidebar.constants.js +1 -1
- package/dist/wc/AvatarFallback.js +5 -5
- package/dist/wc/CheckboxIndicator.js +7 -7
- package/dist/wc/CollapsiblePanel.js +1 -1
- package/dist/wc/DialogTrigger.js +9 -9
- package/dist/wc/DropdownMenu.js +16 -16
- package/dist/wc/MenuSubmenuTrigger.js +31 -31
- package/dist/wc/PopoverDescription.js +30 -30
- package/dist/wc/PrehydrationScript.js +1 -1
- package/dist/wc/Select.js +18 -18
- package/dist/wc/SelectSeparator.js +72 -72
- package/dist/wc/SelectSeparator.js.map +1 -1
- package/dist/wc/Tabs.js +18 -18
- package/dist/wc/TooltipProvider.js +9 -9
- package/dist/wc/chart.js +1 -1
- package/dist/wc/chunk-75Z2AOVW.js +39 -39
- package/dist/wc/chunk-OSK3NFVY.js +32 -32
- package/dist/wc/command.js +4 -4
- package/dist/wc/form-field.js +1 -1
- package/dist/wc/form-fieldset.js +5 -5
- package/dist/wc/hf-accordion-card.js +4 -4
- package/dist/wc/hf-accordion.js +6 -6
- package/dist/wc/hf-ai-feedback-bar.js +5 -5
- package/dist/wc/hf-ai-reasoning-block.js +6 -6
- package/dist/wc/hf-ai-system-message.js +1 -1
- package/dist/wc/hf-ai-tool-run.js +1 -1
- package/dist/wc/hf-area-chart.js +15 -15
- package/dist/wc/hf-autocomplete.js +36 -36
- package/dist/wc/hf-bar-chart.js +4 -4
- package/dist/wc/hf-calendar.js +4 -4
- package/dist/wc/hf-carousel.js +1 -1
- package/dist/wc/hf-context-menu.js +8 -8
- package/dist/wc/hf-donut-chart.js +10 -10
- package/dist/wc/hf-empty-state.js +87 -88
- package/dist/wc/hf-empty-state.js.map +1 -1
- package/dist/wc/hf-history.js +4 -4
- package/dist/wc/hf-horizontal-bar-chart.js +7 -7
- package/dist/wc/hf-hover-card.js +6 -6
- package/dist/wc/hf-line-chart.js +4 -4
- package/dist/wc/hf-metric-card.js +5 -5
- package/dist/wc/hf-metric-item.js +8 -8
- package/dist/wc/hf-metric-item.js.map +1 -1
- package/dist/wc/hf-nav-account-menu.js +4 -4
- package/dist/wc/hf-notification-panel.js +2 -2
- package/dist/wc/hf-pie-chart.js +17 -17
- package/dist/wc/hf-radar-chart.js +16 -16
- package/dist/wc/hf-section-header.js +6 -6
- package/dist/wc/hf-sheet.js +1 -1
- package/dist/wc/hf-sparkline-chart.js +5 -5
- package/dist/wc/hf-steps.js +6 -6
- package/dist/wc/journeyDiagram-3NMN7TZE.js +10 -10
- package/dist/wc/pieDiagram-E7YTZNPT.js +16 -16
- package/dist/wc/popupStateMapping.js +53 -53
- package/dist/wc/popupStateMapping.js.map +1 -1
- package/dist/wc/selection-group.js +1 -1
- package/dist/wc/selection-group.js.map +1 -1
- package/dist/wc/{useOpenChangeComplete.js → stateAttributesMapping.js} +21 -21
- package/dist/wc/stateAttributesMapping.js.map +1 -0
- package/dist/wc/stateDiagram-D77RDMKH.js +3 -3
- package/dist/wc/timeline-definition-24CTP7MA.js +19 -19
- package/dist/wc/useCollapsiblePanel.js +3 -3
- package/dist/wc/usePopupHandleStore.js +4 -4
- package/dist/wc/useScrollLock.js +1 -1
- package/dist/wc/vendor/recharts.js +525 -524
- package/dist/wc/vendor/recharts.js.map +1 -1
- package/dist/wc/xychartDiagram-S5SC5T6Z.js +6 -6
- package/dist/wc-react/AIClarificationCard.js +1 -1
- package/dist/wc-react/AIContainer.js +1 -1
- package/dist/wc-react/AIForm.js +17 -17
- package/dist/wc-react/AIInput.js +1 -1
- package/dist/wc-react/AIMermaidDiagram.js +1 -1
- package/dist/wc-react/AIMessage.js +1 -1
- package/dist/wc-react/AIScrollButton.js +4 -4
- package/dist/wc-react/AIToolCall.js +5 -5
- package/dist/wc-react/AppSidebar.constants.js +1 -1
- package/dist/wc-react/AvatarFallback.js +5 -5
- package/dist/wc-react/CheckboxIndicator.js +7 -7
- package/dist/wc-react/CollapsiblePanel.js +1 -1
- package/dist/wc-react/DialogTrigger.js +9 -9
- package/dist/wc-react/DropdownMenu.js +16 -16
- package/dist/wc-react/FloatingPortalLite.js +3 -3
- package/dist/wc-react/MenuSubmenuTrigger.js +31 -31
- package/dist/wc-react/PopoverDescription.js +31 -31
- package/dist/wc-react/PrehydrationScript.js +1 -1
- package/dist/wc-react/Select.js +18 -18
- package/dist/wc-react/SelectSeparator.js +71 -70
- package/dist/wc-react/SelectSeparator.js.map +1 -1
- package/dist/wc-react/Tabs.js +18 -18
- package/dist/wc-react/TooltipProvider.js +9 -9
- package/dist/wc-react/chart.js +1 -1
- package/dist/wc-react/chunk-75Z2AOVW.js +39 -39
- package/dist/wc-react/chunk-OSK3NFVY.js +32 -32
- package/dist/wc-react/command.js +4 -4
- package/dist/wc-react/form-field.js +1 -1
- package/dist/wc-react/form-fieldset.js +77 -77
- package/dist/wc-react/hf-accordion-card.js +4 -4
- package/dist/wc-react/hf-accordion.js +6 -6
- package/dist/wc-react/hf-ai-feedback-bar.js +5 -5
- package/dist/wc-react/hf-ai-reasoning-block.js +6 -6
- package/dist/wc-react/hf-ai-system-message.js +1 -1
- package/dist/wc-react/hf-ai-tool-run.js +1 -1
- package/dist/wc-react/hf-autocomplete.js +37 -37
- package/dist/wc-react/hf-calendar.js +4 -4
- package/dist/wc-react/hf-carousel.js +1 -1
- package/dist/wc-react/hf-context-menu.js +8 -8
- package/dist/wc-react/hf-data-table.js +1 -1
- package/dist/wc-react/hf-empty-state.js +87 -88
- package/dist/wc-react/hf-empty-state.js.map +1 -1
- package/dist/wc-react/hf-history.js +4 -4
- package/dist/wc-react/hf-hover-card.js +6 -6
- package/dist/wc-react/hf-metric-item.js +6 -6
- package/dist/wc-react/hf-metric-item.js.map +1 -1
- package/dist/wc-react/hf-nav-account-menu.js +4 -4
- package/dist/wc-react/hf-notification-panel.js +2 -2
- package/dist/wc-react/hf-section-header.js +6 -6
- package/dist/wc-react/hf-sheet.js +1 -1
- package/dist/wc-react/hf-steps.js +5 -5
- package/dist/wc-react/journeyDiagram-3NMN7TZE.js +10 -10
- package/dist/wc-react/pieDiagram-E7YTZNPT.js +16 -16
- package/dist/wc-react/popupStateMapping.js +54 -54
- package/dist/wc-react/popupStateMapping.js.map +1 -1
- package/dist/wc-react/selection-group.js +1 -1
- package/dist/wc-react/selection-group.js.map +1 -1
- package/dist/wc-react/{useOpenChangeComplete.js → stateAttributesMapping.js} +19 -19
- package/dist/wc-react/stateAttributesMapping.js.map +1 -0
- package/dist/wc-react/stateDiagram-D77RDMKH.js +3 -3
- package/dist/wc-react/timeline-definition-24CTP7MA.js +19 -19
- package/dist/wc-react/useCollapsiblePanel.js +3 -3
- package/dist/wc-react/usePopupHandleStore.js +3 -3
- package/dist/wc-react/useScrollLock.js +1 -1
- package/dist/wc-react/vendor/recharts.js +525 -524
- package/dist/wc-react/vendor/recharts.js.map +1 -1
- package/dist/wc-react/xychartDiagram-S5SC5T6Z.js +6 -6
- package/package.json +1 -1
- package/skills/humain-ui/SKILL.md +1 -1
- package/skills/humain-ui-wc/SKILL.md +1 -1
- package/skills/humain-ui-wc.skill +0 -0
- package/skills/humain-ui.skill +0 -0
- package/dist/wc/useOpenChangeComplete.js.map +0 -1
- package/dist/wc-react/useOpenChangeComplete.js.map +0 -1
package/dist/index194.js
CHANGED
|
@@ -47,12 +47,6 @@ var iconGlyphSizeClass = {
|
|
|
47
47
|
md: "size-4",
|
|
48
48
|
lg: "size-5"
|
|
49
49
|
};
|
|
50
|
-
var illustrationIconCenterClass = {
|
|
51
|
-
cloud: "top-[58%]",
|
|
52
|
-
box: "top-[58%]",
|
|
53
|
-
documents: "top-[60%]",
|
|
54
|
-
"credit-card": "top-[60%]"
|
|
55
|
-
};
|
|
56
50
|
var illustrationCircleSizeClass = {
|
|
57
51
|
sm: "size-[104px]",
|
|
58
52
|
md: "size-32",
|
|
@@ -191,6 +185,7 @@ function DecorativeDots({ tone }) {
|
|
|
191
185
|
}
|
|
192
186
|
function CloudShape({ accentId, shadeId, tone }) {
|
|
193
187
|
return /* @__PURE__ */ jsxs("g", {
|
|
188
|
+
transform: "translate(10.5 14.5)",
|
|
194
189
|
className: "drop-shadow-[0_8px_16px_var(--shadow-soft-3-color)]",
|
|
195
190
|
children: [/* @__PURE__ */ jsx("path", {
|
|
196
191
|
d: "M54 110c-21 0-38-14-38-32 0-16 14-30 33-32 8-19 27-31 49-31 27 0 50 19 55 43 17 3 30 16 30 32 0 19-18 34-40 34H55c-1 0-1-14-1-14Z",
|
|
@@ -204,6 +199,7 @@ function CloudShape({ accentId, shadeId, tone }) {
|
|
|
204
199
|
}
|
|
205
200
|
function BoxShape({ accentId, shadeId }) {
|
|
206
201
|
return /* @__PURE__ */ jsxs("g", {
|
|
202
|
+
transform: "translate(-19.5)",
|
|
207
203
|
className: "drop-shadow-[0_8px_16px_var(--shadow-soft-3-color)]",
|
|
208
204
|
children: [
|
|
209
205
|
/* @__PURE__ */ jsx("path", {
|
|
@@ -233,6 +229,7 @@ function BoxShape({ accentId, shadeId }) {
|
|
|
233
229
|
}
|
|
234
230
|
function DocumentsShape({ accentId, shadeId }) {
|
|
235
231
|
return /* @__PURE__ */ jsxs("g", {
|
|
232
|
+
transform: "translate(0 -0.5)",
|
|
236
233
|
className: "drop-shadow-[0_8px_16px_var(--shadow-soft-3-color)]",
|
|
237
234
|
children: [
|
|
238
235
|
/* @__PURE__ */ jsxs("g", {
|
|
@@ -282,6 +279,7 @@ function DocumentsShape({ accentId, shadeId }) {
|
|
|
282
279
|
}
|
|
283
280
|
function CreditCardShape({ accentId, shadeId }) {
|
|
284
281
|
return /* @__PURE__ */ jsxs("g", {
|
|
282
|
+
transform: "translate(0 -5)",
|
|
285
283
|
className: "drop-shadow-[0_8px_16px_var(--shadow-soft-3-color)]",
|
|
286
284
|
children: [
|
|
287
285
|
/* @__PURE__ */ jsx("rect", {
|
|
@@ -355,7 +353,7 @@ var EmptyStateIllustration = React$1.forwardRef(({ className, size = "sm", varia
|
|
|
355
353
|
"data-slot": "empty-state-illustration-background",
|
|
356
354
|
"data-testid": "empty-state-illustration-background",
|
|
357
355
|
"data-centered": "true",
|
|
358
|
-
className: cn("absolute left-1/2 -translate-x-1/2 -translate-y-1/2 rounded-full", isPrimary ? "bg-primary/20" : "bg-muted/80", illustrationCircleSizeClass[size]
|
|
356
|
+
className: cn("absolute left-1/2 top-1/2 -translate-x-1/2 -translate-y-1/2 rounded-full", isPrimary ? "bg-primary/20" : "bg-muted/80", illustrationCircleSizeClass[size])
|
|
359
357
|
}),
|
|
360
358
|
/* @__PURE__ */ jsx(DecorativeDots, { tone }),
|
|
361
359
|
/* @__PURE__ */ jsxs("svg", {
|
|
@@ -411,7 +409,7 @@ var EmptyStateIllustration = React$1.forwardRef(({ className, size = "sm", varia
|
|
|
411
409
|
"data-slot": "empty-state-illustration-icon",
|
|
412
410
|
"data-testid": "empty-state-illustration-icon",
|
|
413
411
|
"data-centered": "true",
|
|
414
|
-
className: cn("absolute left-1/2 flex -translate-x-1/2 -translate-y-1/2 items-center justify-center rounded-xl bg-primary/10 text-primary shadow-xs backdrop-blur-md supports-backdrop-filter:backdrop-blur-md [&>svg]:shrink-0", !isPrimary && "bg-muted text-muted-foreground", illustrationIconSizeClass[size]
|
|
412
|
+
className: cn("absolute left-1/2 top-1/2 flex -translate-x-1/2 -translate-y-1/2 items-center justify-center rounded-xl bg-primary/10 text-primary shadow-xs backdrop-blur-md supports-backdrop-filter:backdrop-blur-md [&>svg]:shrink-0", !isPrimary && "bg-muted text-muted-foreground", illustrationIconSizeClass[size]),
|
|
415
413
|
children: /* @__PURE__ */ jsx(EmptyStateIconGlyph, {
|
|
416
414
|
icon,
|
|
417
415
|
size
|
package/dist/index194.js.map
CHANGED
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"index194.js","names":[],"sources":["../src/components/organisms/content/EmptyState/EmptyState.tsx"],"sourcesContent":["import { cva } from 'class-variance-authority';\nimport { Heart, Search } from 'lucide-react';\nimport * as React from 'react';\nimport { Button } from '@/components/atoms/buttons/Button';\nimport { FeaturedIcon } from '@/components/molecules/data/FeaturedIcon';\nimport {\n type FileExtension,\n FileTypeIcon,\n type SimpleFileType,\n} from '@/components/molecules/files/FileTypeIcon';\nimport { cn } from '@/lib/utils';\n\n// ============================================================================\n// Types\n// ============================================================================\n\nexport type EmptyStateSize = 'sm' | 'md' | 'lg';\nexport type EmptyStateMedia =\n | 'featured-icon'\n | 'illustration'\n | 'file-type-icon'\n | 'none';\nexport type EmptyStateBackgroundPatternVariant =\n | 'circles'\n | 'grid'\n | 'grid-dot'\n | 'squares'\n | 'none';\nexport type EmptyStateIllustrationVariant =\n | 'cloud'\n | 'box'\n | 'documents'\n | 'credit-card';\nexport type EmptyStateTone = 'primary' | 'gray';\n\nexport interface EmptyStateActionConfig {\n label: React.ReactNode;\n onClick?: React.MouseEventHandler<HTMLButtonElement>;\n startIcon?: React.ReactNode;\n disabled?: boolean;\n loading?: boolean;\n 'aria-label'?: string;\n}\n\n// ============================================================================\n// Shared maps\n// ============================================================================\n\nconst patternSizeClass: Record<EmptyStateSize, string> = {\n sm: 'size-[336px]',\n md: 'size-[480px]',\n lg: 'size-[768px]',\n};\n\nconst patternGridSize: Record<EmptyStateSize, string> = {\n sm: '24px 24px',\n md: '32px 32px',\n lg: '48px 48px',\n};\n\nconst illustrationSizeClass: Record<\n EmptyStateSize,\n Record<EmptyStateIllustrationVariant, string>\n> = {\n sm: {\n cloud: 'h-[118px] w-[152px]',\n box: 'h-[124px] w-[152px]',\n documents: 'h-[118px] w-[152px]',\n 'credit-card': 'h-[118px] w-[152px]',\n },\n md: {\n cloud: 'h-32 w-[172px]',\n box: 'h-[136px] w-[172px]',\n documents: 'h-32 w-[172px]',\n 'credit-card': 'h-[134px] w-[172px]',\n },\n lg: {\n cloud: 'h-40 w-[220px]',\n box: 'h-[168px] w-[220px]',\n documents: 'h-40 w-[220px]',\n 'credit-card': 'h-40 w-[220px]',\n },\n};\n\nconst illustrationIconSizeClass: Record<EmptyStateSize, string> = {\n sm: 'p-2',\n md: 'p-2.5',\n lg: 'p-2.5',\n};\n\nconst iconGlyphSizeClass: Record<EmptyStateSize, string> = {\n sm: 'size-4',\n md: 'size-4',\n lg: 'size-5',\n};\n\nconst illustrationIconCenterClass: Record<\n EmptyStateIllustrationVariant,\n string\n> = {\n cloud: 'top-[58%]',\n box: 'top-[58%]',\n documents: 'top-[60%]',\n 'credit-card': 'top-[60%]',\n};\n\nconst illustrationCircleSizeClass: Record<EmptyStateSize, string> = {\n sm: 'size-[104px]',\n md: 'size-32',\n lg: 'size-40',\n};\n\nconst fileIconWrapSizeClass: Record<EmptyStateSize, string> = {\n sm: 'size-20',\n md: 'size-24',\n lg: 'size-28',\n};\n\nconst textGapClass: Record<EmptyStateSize, string> = {\n sm: 'gap-1',\n md: 'gap-2',\n lg: 'gap-2',\n};\n\nconst mediaGapClass: Record<EmptyStateSize, string> = {\n sm: 'gap-4',\n md: 'gap-5',\n lg: 'gap-5',\n};\n\nconst contentGapClass: Record<EmptyStateSize, string> = {\n sm: 'gap-6',\n md: 'gap-8',\n lg: 'gap-8',\n};\n\nconst featuredIconSize: Record<EmptyStateSize, 'sm' | 'md' | 'lg'> = {\n sm: 'sm',\n md: 'md',\n lg: 'lg',\n};\n\nconst fileIconSize: Record<EmptyStateSize, 'sm' | 'md' | 'lg'> = {\n sm: 'md',\n md: 'md',\n lg: 'md',\n};\n\nconst headingTag = {\n 2: 'h2',\n 3: 'h3',\n 4: 'h4',\n} as const;\n\nfunction EmptyStateIconGlyph({\n icon,\n size,\n}: {\n icon: React.ReactNode;\n size: EmptyStateSize;\n}) {\n return (\n <span\n data-slot=\"empty-state-icon-glyph\"\n data-testid=\"empty-state-icon-glyph\"\n data-centered=\"true\"\n aria-hidden=\"true\"\n className={cn(\n 'inline-flex shrink-0 items-center justify-center leading-none [line-height:0] [&>svg]:block [&>svg]:size-full [&>svg]:shrink-0',\n iconGlyphSizeClass[size],\n )}\n >\n {icon}\n </span>\n );\n}\n\n// ============================================================================\n// Background Pattern\n// ============================================================================\n\nexport interface EmptyStateBackgroundPatternProps\n extends Omit<React.HTMLAttributes<HTMLDivElement>, 'children'> {\n size?: EmptyStateSize;\n variant?: EmptyStateBackgroundPatternVariant;\n}\n\nconst gridPatternStyle = (\n size: EmptyStateSize,\n dot = false,\n): React.CSSProperties => ({\n backgroundImage: dot\n ? 'radial-gradient(circle, color-mix(in oklch, var(--border) 70%, transparent) 1px, transparent 1px)'\n : [\n 'linear-gradient(to right, color-mix(in oklch, var(--border) 54%, transparent) 1px, transparent 1px)',\n 'linear-gradient(to bottom, color-mix(in oklch, var(--border) 54%, transparent) 1px, transparent 1px)',\n ].join(', '),\n backgroundSize: patternGridSize[size],\n});\n\nconst squaresBySize: Record<EmptyStateSize, number[]> = {\n sm: [96, 144, 192, 240, 288, 336],\n md: [96, 160, 224, 288, 352, 416, 480],\n lg: [96, 192, 288, 384, 480, 576, 672, 768],\n};\n\nexport const EmptyStateBackgroundPattern = React.forwardRef<\n HTMLDivElement,\n EmptyStateBackgroundPatternProps\n>(({ className, size = 'sm', variant = 'circles', style, ...props }, ref) => {\n if (variant === 'none') {\n return null;\n }\n\n return (\n <div\n ref={ref}\n data-slot=\"empty-state-background-pattern\"\n data-testid=\"empty-state-pattern\"\n data-size={size}\n data-variant={variant}\n aria-hidden=\"true\"\n className={cn(\n 'pointer-events-none absolute left-1/2 top-1/2 -translate-x-1/2 -translate-y-1/2 overflow-hidden opacity-75',\n patternSizeClass[size],\n className,\n )}\n style={style}\n {...props}\n >\n <div className=\"absolute inset-0 bg-[radial-gradient(circle_at_center,var(--background)_0%,transparent_68%)]\" />\n\n {variant === 'circles' && (\n <div className=\"absolute inset-0\">\n {Array.from({ length: 7 }, (_, index) => (\n <span\n key={index}\n className=\"absolute left-1/2 top-1/2 rounded-full border border-border/60\"\n style={{\n width: `${(index + 1) * 14}%`,\n height: `${(index + 1) * 14}%`,\n transform: 'translate(-50%, -50%)',\n }}\n />\n ))}\n </div>\n )}\n\n {(variant === 'grid' || variant === 'grid-dot') && (\n <div\n className=\"absolute inset-0 opacity-70 [mask-image:radial-gradient(circle_at_center,black_0%,black_48%,transparent_76%)]\"\n style={gridPatternStyle(size, variant === 'grid-dot')}\n />\n )}\n\n {variant === 'squares' && (\n <div className=\"absolute inset-0\">\n {squaresBySize[size].map((squareSize) => (\n <span\n key={squareSize}\n className=\"absolute left-1/2 top-1/2 rounded-xl border border-border/55\"\n style={{\n width: squareSize,\n height: squareSize,\n transform: 'translate(-50%, -50%) rotate(-12.5deg)',\n }}\n />\n ))}\n </div>\n )}\n </div>\n );\n});\n\nEmptyStateBackgroundPattern.displayName = 'EmptyStateBackgroundPattern';\n\n// ============================================================================\n// Illustration\n// ============================================================================\n\nexport interface EmptyStateIllustrationProps\n extends Omit<React.HTMLAttributes<HTMLDivElement>, 'children'> {\n size?: EmptyStateSize;\n variant?: EmptyStateIllustrationVariant;\n tone?: EmptyStateTone;\n icon?: React.ReactNode;\n}\n\nfunction DecorativeDots({ tone }: { tone: EmptyStateTone }) {\n const dotClassName =\n tone === 'primary' ? 'bg-primary/70' : 'bg-muted-foreground/10';\n\n return (\n <>\n <span\n className={cn(\n 'absolute left-[7%] top-[8%] size-2 rounded-full',\n dotClassName,\n )}\n />\n <span\n className={cn(\n 'absolute right-[6%] top-[18%] size-3 rounded-full',\n dotClassName,\n )}\n />\n <span\n className={cn(\n 'absolute bottom-[10%] left-[8%] size-3 rounded-full',\n dotClassName,\n )}\n />\n <span\n className={cn(\n 'absolute bottom-[18%] right-[13%] size-2 rounded-full',\n dotClassName,\n )}\n />\n </>\n );\n}\n\nfunction CloudShape({\n accentId,\n shadeId,\n tone,\n}: {\n accentId: string;\n shadeId: string;\n tone: EmptyStateTone;\n}) {\n return (\n <g className=\"drop-shadow-[0_8px_16px_var(--shadow-soft-3-color)]\">\n <path\n d=\"M54 110c-21 0-38-14-38-32 0-16 14-30 33-32 8-19 27-31 49-31 27 0 50 19 55 43 17 3 30 16 30 32 0 19-18 34-40 34H55c-1 0-1-14-1-14Z\"\n fill={`url(#${shadeId})`}\n />\n <path\n d=\"M68 106c-18 0-32-12-32-27 0-13 11-24 27-26 7-16 23-26 42-26 23 0 42 16 46 36 15 3 26 14 26 28 0 16-15 29-34 29H68v-14Z\"\n fill={`url(#${accentId})`}\n opacity={tone === 'primary' ? 0.78 : 0.36}\n />\n </g>\n );\n}\n\nfunction BoxShape({\n accentId,\n shadeId,\n}: {\n accentId: string;\n shadeId: string;\n}) {\n return (\n <g className=\"drop-shadow-[0_8px_16px_var(--shadow-soft-3-color)]\">\n <path d=\"M72 42 132 20l55 31-62 24-53-33Z\" fill={`url(#${accentId})`} />\n <path d=\"M72 42v72l53 34V75L72 42Z\" fill={`url(#${shadeId})`} />\n <path d=\"M125 75v73l62-35V51l-62 24Z\" fill=\"var(--card)\" />\n <path\n d=\"M132 20v33l24 14V34l-24-14Z\"\n fill=\"currentColor\"\n opacity=\"0.34\"\n />\n <path\n d=\"M72 42 132 20l55 31-62 24-53-33Z\"\n fill=\"none\"\n stroke=\"var(--border)\"\n />\n </g>\n );\n}\n\nfunction DocumentsShape({\n accentId,\n shadeId,\n}: {\n accentId: string;\n shadeId: string;\n}) {\n return (\n <g className=\"drop-shadow-[0_8px_16px_var(--shadow-soft-3-color)]\">\n <g transform=\"translate(44 48) rotate(-18)\">\n <rect\n width=\"58\"\n height=\"78\"\n rx=\"7\"\n fill={`url(#${shadeId})`}\n stroke=\"var(--border)\"\n />\n <path\n d=\"M15 21h28M15 35h21M15 49h28\"\n stroke=\"currentColor\"\n strokeOpacity=\"0.28\"\n />\n </g>\n <g transform=\"translate(83 32)\">\n <rect\n width=\"58\"\n height=\"88\"\n rx=\"7\"\n fill=\"var(--card)\"\n stroke=\"var(--border)\"\n />\n <path\n d=\"M16 26h28M16 41h22M16 56h28\"\n stroke=\"currentColor\"\n strokeOpacity=\"0.32\"\n />\n </g>\n <g transform=\"translate(121 47) rotate(18)\">\n <rect\n width=\"58\"\n height=\"78\"\n rx=\"7\"\n fill={`url(#${accentId})`}\n stroke=\"var(--border)\"\n />\n <path\n d=\"M15 21h28M15 35h21M15 49h28\"\n stroke=\"currentColor\"\n strokeOpacity=\"0.32\"\n />\n </g>\n </g>\n );\n}\n\nfunction CreditCardShape({\n accentId,\n shadeId,\n}: {\n accentId: string;\n shadeId: string;\n}) {\n return (\n <g className=\"drop-shadow-[0_8px_16px_var(--shadow-soft-3-color)]\">\n <rect\n x=\"42\"\n y=\"48\"\n width=\"136\"\n height=\"82\"\n rx=\"12\"\n fill={`url(#${shadeId})`}\n stroke=\"var(--border)\"\n />\n <rect\n x=\"42\"\n y=\"70\"\n width=\"136\"\n height=\"16\"\n fill={`url(#${accentId})`}\n opacity=\"0.72\"\n />\n <rect\n x=\"58\"\n y=\"104\"\n width=\"28\"\n height=\"8\"\n rx=\"2\"\n fill=\"currentColor\"\n opacity=\"0.28\"\n />\n <rect\n x=\"58\"\n y=\"116\"\n width=\"58\"\n height=\"5\"\n rx=\"2.5\"\n fill=\"currentColor\"\n opacity=\"0.18\"\n />\n <circle cx=\"146\" cy=\"112\" r=\"10\" fill=\"currentColor\" opacity=\"0.24\" />\n <circle cx=\"158\" cy=\"112\" r=\"10\" fill=\"currentColor\" opacity=\"0.38\" />\n </g>\n );\n}\n\nexport const EmptyStateIllustration = React.forwardRef<\n HTMLDivElement,\n EmptyStateIllustrationProps\n>(\n (\n {\n className,\n size = 'sm',\n variant = 'cloud',\n tone = 'primary',\n icon = <Heart aria-hidden=\"true\" />,\n ...props\n },\n ref,\n ) => {\n const accentId = React.useId();\n const shadeId = React.useId();\n const isPrimary = tone === 'primary';\n\n return (\n <div\n ref={ref}\n data-slot=\"empty-state-illustration\"\n data-testid=\"empty-state-illustration\"\n data-size={size}\n data-variant={variant}\n data-tone={tone}\n aria-hidden=\"true\"\n className={cn(\n 'relative shrink-0 text-primary',\n !isPrimary && 'text-muted-foreground',\n illustrationSizeClass[size][variant],\n className,\n )}\n {...props}\n >\n <div\n data-slot=\"empty-state-illustration-background\"\n data-testid=\"empty-state-illustration-background\"\n data-centered=\"true\"\n className={cn(\n 'absolute left-1/2 -translate-x-1/2 -translate-y-1/2 rounded-full',\n isPrimary ? 'bg-primary/20' : 'bg-muted/80',\n illustrationCircleSizeClass[size],\n illustrationIconCenterClass[variant],\n )}\n />\n <DecorativeDots tone={tone} />\n <svg\n viewBox=\"0 0 220 168\"\n className=\"absolute inset-0 size-full overflow-visible\"\n fill=\"none\"\n aria-hidden=\"true\"\n >\n <defs>\n <linearGradient id={accentId} x1=\"25\" y1=\"12\" x2=\"190\" y2=\"148\">\n <stop\n stopColor={isPrimary ? 'var(--primary)' : 'var(--muted)'}\n stopOpacity={isPrimary ? 0.34 : 0.74}\n />\n <stop stopColor=\"var(--card)\" stopOpacity={0.95} />\n </linearGradient>\n <linearGradient id={shadeId} x1=\"54\" y1=\"18\" x2=\"165\" y2=\"140\">\n <stop stopColor=\"var(--card)\" />\n <stop\n stopColor={\n isPrimary ? 'var(--primary)' : 'var(--muted-foreground)'\n }\n stopOpacity={isPrimary ? 0.18 : 0.14}\n />\n </linearGradient>\n </defs>\n\n {variant === 'cloud' && (\n <CloudShape accentId={accentId} shadeId={shadeId} tone={tone} />\n )}\n {variant === 'box' && (\n <BoxShape accentId={accentId} shadeId={shadeId} />\n )}\n {variant === 'documents' && (\n <DocumentsShape accentId={accentId} shadeId={shadeId} />\n )}\n {variant === 'credit-card' && (\n <CreditCardShape accentId={accentId} shadeId={shadeId} />\n )}\n </svg>\n <div\n data-slot=\"empty-state-illustration-icon\"\n data-testid=\"empty-state-illustration-icon\"\n data-centered=\"true\"\n className={cn(\n 'absolute left-1/2 flex -translate-x-1/2 -translate-y-1/2 items-center justify-center rounded-xl bg-primary/10 text-primary shadow-xs backdrop-blur-md supports-backdrop-filter:backdrop-blur-md [&>svg]:shrink-0',\n !isPrimary && 'bg-muted text-muted-foreground',\n illustrationIconSizeClass[size],\n illustrationIconCenterClass[variant],\n )}\n >\n <EmptyStateIconGlyph icon={icon} size={size} />\n </div>\n </div>\n );\n },\n);\n\nEmptyStateIllustration.displayName = 'EmptyStateIllustration';\n\n// ============================================================================\n// EmptyState\n// ============================================================================\n\nconst emptyStateVariants = cva(\n 'relative isolate mx-auto flex w-full max-w-[512px] items-center justify-center overflow-visible py-8 text-center',\n {\n variants: {\n size: {\n sm: 'min-h-[212px]',\n md: 'min-h-[280px]',\n lg: 'min-h-[360px]',\n },\n },\n defaultVariants: {\n size: 'sm',\n },\n },\n);\n\nexport interface EmptyStateProps\n extends Omit<React.HTMLAttributes<HTMLElement>, 'title'> {\n title: React.ReactNode;\n description?: React.ReactNode;\n size?: EmptyStateSize;\n media?: EmptyStateMedia;\n pattern?: EmptyStateBackgroundPatternVariant | 'auto';\n icon?: React.ReactNode;\n iconLabel?: string;\n illustrationVariant?: EmptyStateIllustrationVariant;\n illustrationTone?: EmptyStateTone;\n fileExtension?: FileExtension;\n fileType?: SimpleFileType;\n primaryAction?: EmptyStateActionConfig;\n secondaryAction?: EmptyStateActionConfig;\n actions?: React.ReactNode;\n headingLevel?: 2 | 3 | 4;\n}\n\nfunction resolvePattern(\n pattern: EmptyStateProps['pattern'],\n media: EmptyStateMedia,\n): EmptyStateBackgroundPatternVariant {\n if (!pattern || pattern === 'auto') {\n if (media === 'illustration') return 'grid';\n if (media === 'none') return 'none';\n return 'circles';\n }\n return pattern;\n}\n\nfunction renderEmptyStateAction(\n action: EmptyStateActionConfig,\n intent: 'primary' | 'secondary',\n) {\n const {\n label,\n onClick,\n startIcon,\n disabled,\n loading,\n 'aria-label': ariaLabel,\n } = action;\n\n return (\n <Button\n appearance={intent === 'primary' ? 'solid' : 'outline'}\n variant={intent === 'primary' ? 'primary' : 'secondary'}\n size=\"sm\"\n shape=\"rounded\"\n onClick={onClick}\n disabled={disabled}\n loading={loading}\n startIcon={startIcon}\n aria-label={ariaLabel}\n type=\"button\"\n >\n {label}\n </Button>\n );\n}\n\nexport const EmptyState = React.forwardRef<HTMLElement, EmptyStateProps>(\n (\n {\n className,\n title,\n description,\n size = 'sm',\n media = 'featured-icon',\n pattern = 'auto',\n icon,\n iconLabel,\n illustrationVariant = 'cloud',\n illustrationTone = 'gray',\n fileExtension,\n fileType = 'document',\n primaryAction,\n secondaryAction,\n actions,\n headingLevel = 3,\n ...props\n },\n ref,\n ) => {\n const Heading = headingTag[headingLevel];\n const resolvedPattern = resolvePattern(pattern, media);\n const defaultIcon = icon ?? <Search aria-hidden=\"true\" />;\n const hasActions = actions || primaryAction || secondaryAction;\n\n return (\n <section\n ref={ref}\n data-slot=\"empty-state\"\n aria-label={typeof title === 'string' ? title : 'Empty state'}\n className={cn(emptyStateVariants({ size }), className)}\n {...props}\n >\n <div\n data-slot=\"empty-state-content\"\n className={cn(\n 'relative z-10 flex min-w-0 flex-1 flex-col items-center',\n contentGapClass[size],\n )}\n >\n <div\n data-slot=\"empty-state-body\"\n className={cn(\n 'flex w-full flex-col items-center',\n mediaGapClass[size],\n )}\n >\n {media !== 'none' && (\n <div\n data-slot=\"empty-state-media\"\n data-testid=\"empty-state-media\"\n data-media={media}\n data-centered=\"true\"\n className=\"relative flex w-full min-w-0 justify-center\"\n >\n <EmptyStateBackgroundPattern\n size={size}\n variant={resolvedPattern}\n data-centered=\"true\"\n className=\"z-0\"\n />\n\n {media === 'featured-icon' && (\n <FeaturedIcon\n data-slot=\"empty-state-featured-icon\"\n size={featuredIconSize[size]}\n shape=\"rounded\"\n intent=\"default\"\n icon={\n <EmptyStateIconGlyph icon={defaultIcon} size={size} />\n }\n aria-label={iconLabel}\n className=\"relative z-10 delight-stagger motion-reduce:animate-none\"\n />\n )}\n\n {media === 'illustration' && (\n <EmptyStateIllustration\n size={size}\n variant={illustrationVariant}\n tone={illustrationTone}\n icon={defaultIcon}\n className=\"relative z-10 delight-stagger motion-reduce:animate-none\"\n />\n )}\n\n {media === 'file-type-icon' && (\n <div\n data-slot=\"empty-state-file-icon-wrap\"\n data-testid=\"empty-state-file-icon-wrap\"\n data-centered=\"true\"\n className={cn(\n 'relative z-10 flex items-center justify-center rounded-full bg-linear-[104deg,color-mix(in_oklch,var(--card)_60%,transparent),color-mix(in_oklch,var(--muted)_55%,transparent)] delight-stagger motion-reduce:animate-none',\n fileIconWrapSizeClass[size],\n )}\n >\n <div\n data-slot=\"empty-state-file-icon-optical-center\"\n data-testid=\"empty-state-file-icon-optical-center\"\n data-centered=\"true\"\n >\n <FileTypeIcon\n extension={fileExtension}\n fileType={fileExtension ? undefined : fileType}\n size={fileIconSize[size]}\n className=\"drop-shadow-[0_1px_2px_var(--shadow-xs-1-color)]\"\n />\n </div>\n </div>\n )}\n </div>\n )}\n\n <div\n data-slot=\"empty-state-text\"\n className={cn(\n 'flex w-full max-w-[352px] flex-col items-center text-center',\n textGapClass[size],\n )}\n >\n <Heading className=\"w-full text-base font-semibold leading-6 text-foreground\">\n {title}\n </Heading>\n {description && (\n <p className=\"w-full text-sm leading-5 text-secondary-foreground\">\n {description}\n </p>\n )}\n </div>\n </div>\n\n {hasActions && (\n <div\n data-slot=\"empty-state-actions\"\n className=\"flex flex-wrap items-center justify-center gap-3\"\n >\n {actions ?? (\n <>\n {secondaryAction &&\n renderEmptyStateAction(secondaryAction, 'secondary')}\n {primaryAction &&\n renderEmptyStateAction(primaryAction, 'primary')}\n </>\n )}\n </div>\n )}\n </div>\n </section>\n );\n },\n);\n\nEmptyState.displayName = 'EmptyState';\n"],"mappings":"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"}
|
|
1
|
+
{"version":3,"file":"index194.js","names":[],"sources":["../src/components/organisms/content/EmptyState/EmptyState.tsx"],"sourcesContent":["import { cva } from 'class-variance-authority';\nimport { Heart, Search } from 'lucide-react';\nimport * as React from 'react';\nimport { Button } from '@/components/atoms/buttons/Button';\nimport { FeaturedIcon } from '@/components/molecules/data/FeaturedIcon';\nimport {\n type FileExtension,\n FileTypeIcon,\n type SimpleFileType,\n} from '@/components/molecules/files/FileTypeIcon';\nimport { cn } from '@/lib/utils';\n\n// ============================================================================\n// Types\n// ============================================================================\n\nexport type EmptyStateSize = 'sm' | 'md' | 'lg';\nexport type EmptyStateMedia =\n | 'featured-icon'\n | 'illustration'\n | 'file-type-icon'\n | 'none';\nexport type EmptyStateBackgroundPatternVariant =\n | 'circles'\n | 'grid'\n | 'grid-dot'\n | 'squares'\n | 'none';\nexport type EmptyStateIllustrationVariant =\n | 'cloud'\n | 'box'\n | 'documents'\n | 'credit-card';\nexport type EmptyStateTone = 'primary' | 'gray';\n\nexport interface EmptyStateActionConfig {\n label: React.ReactNode;\n onClick?: React.MouseEventHandler<HTMLButtonElement>;\n startIcon?: React.ReactNode;\n disabled?: boolean;\n loading?: boolean;\n 'aria-label'?: string;\n}\n\n// ============================================================================\n// Shared maps\n// ============================================================================\n\nconst patternSizeClass: Record<EmptyStateSize, string> = {\n sm: 'size-[336px]',\n md: 'size-[480px]',\n lg: 'size-[768px]',\n};\n\nconst patternGridSize: Record<EmptyStateSize, string> = {\n sm: '24px 24px',\n md: '32px 32px',\n lg: '48px 48px',\n};\n\nconst illustrationSizeClass: Record<\n EmptyStateSize,\n Record<EmptyStateIllustrationVariant, string>\n> = {\n sm: {\n cloud: 'h-[118px] w-[152px]',\n box: 'h-[124px] w-[152px]',\n documents: 'h-[118px] w-[152px]',\n 'credit-card': 'h-[118px] w-[152px]',\n },\n md: {\n cloud: 'h-32 w-[172px]',\n box: 'h-[136px] w-[172px]',\n documents: 'h-32 w-[172px]',\n 'credit-card': 'h-[134px] w-[172px]',\n },\n lg: {\n cloud: 'h-40 w-[220px]',\n box: 'h-[168px] w-[220px]',\n documents: 'h-40 w-[220px]',\n 'credit-card': 'h-40 w-[220px]',\n },\n};\n\nconst illustrationIconSizeClass: Record<EmptyStateSize, string> = {\n sm: 'p-2',\n md: 'p-2.5',\n lg: 'p-2.5',\n};\n\nconst iconGlyphSizeClass: Record<EmptyStateSize, string> = {\n sm: 'size-4',\n md: 'size-4',\n lg: 'size-5',\n};\n\nconst illustrationCircleSizeClass: Record<EmptyStateSize, string> = {\n sm: 'size-[104px]',\n md: 'size-32',\n lg: 'size-40',\n};\n\nconst fileIconWrapSizeClass: Record<EmptyStateSize, string> = {\n sm: 'size-20',\n md: 'size-24',\n lg: 'size-28',\n};\n\nconst textGapClass: Record<EmptyStateSize, string> = {\n sm: 'gap-1',\n md: 'gap-2',\n lg: 'gap-2',\n};\n\nconst mediaGapClass: Record<EmptyStateSize, string> = {\n sm: 'gap-4',\n md: 'gap-5',\n lg: 'gap-5',\n};\n\nconst contentGapClass: Record<EmptyStateSize, string> = {\n sm: 'gap-6',\n md: 'gap-8',\n lg: 'gap-8',\n};\n\nconst featuredIconSize: Record<EmptyStateSize, 'sm' | 'md' | 'lg'> = {\n sm: 'sm',\n md: 'md',\n lg: 'lg',\n};\n\nconst fileIconSize: Record<EmptyStateSize, 'sm' | 'md' | 'lg'> = {\n sm: 'md',\n md: 'md',\n lg: 'md',\n};\n\nconst headingTag = {\n 2: 'h2',\n 3: 'h3',\n 4: 'h4',\n} as const;\n\nfunction EmptyStateIconGlyph({\n icon,\n size,\n}: {\n icon: React.ReactNode;\n size: EmptyStateSize;\n}) {\n return (\n <span\n data-slot=\"empty-state-icon-glyph\"\n data-testid=\"empty-state-icon-glyph\"\n data-centered=\"true\"\n aria-hidden=\"true\"\n className={cn(\n 'inline-flex shrink-0 items-center justify-center leading-none [line-height:0] [&>svg]:block [&>svg]:size-full [&>svg]:shrink-0',\n iconGlyphSizeClass[size],\n )}\n >\n {icon}\n </span>\n );\n}\n\n// ============================================================================\n// Background Pattern\n// ============================================================================\n\nexport interface EmptyStateBackgroundPatternProps\n extends Omit<React.HTMLAttributes<HTMLDivElement>, 'children'> {\n size?: EmptyStateSize;\n variant?: EmptyStateBackgroundPatternVariant;\n}\n\nconst gridPatternStyle = (\n size: EmptyStateSize,\n dot = false,\n): React.CSSProperties => ({\n backgroundImage: dot\n ? 'radial-gradient(circle, color-mix(in oklch, var(--border) 70%, transparent) 1px, transparent 1px)'\n : [\n 'linear-gradient(to right, color-mix(in oklch, var(--border) 54%, transparent) 1px, transparent 1px)',\n 'linear-gradient(to bottom, color-mix(in oklch, var(--border) 54%, transparent) 1px, transparent 1px)',\n ].join(', '),\n backgroundSize: patternGridSize[size],\n});\n\nconst squaresBySize: Record<EmptyStateSize, number[]> = {\n sm: [96, 144, 192, 240, 288, 336],\n md: [96, 160, 224, 288, 352, 416, 480],\n lg: [96, 192, 288, 384, 480, 576, 672, 768],\n};\n\nexport const EmptyStateBackgroundPattern = React.forwardRef<\n HTMLDivElement,\n EmptyStateBackgroundPatternProps\n>(({ className, size = 'sm', variant = 'circles', style, ...props }, ref) => {\n if (variant === 'none') {\n return null;\n }\n\n return (\n <div\n ref={ref}\n data-slot=\"empty-state-background-pattern\"\n data-testid=\"empty-state-pattern\"\n data-size={size}\n data-variant={variant}\n aria-hidden=\"true\"\n className={cn(\n 'pointer-events-none absolute left-1/2 top-1/2 -translate-x-1/2 -translate-y-1/2 overflow-hidden opacity-75',\n patternSizeClass[size],\n className,\n )}\n style={style}\n {...props}\n >\n <div className=\"absolute inset-0 bg-[radial-gradient(circle_at_center,var(--background)_0%,transparent_68%)]\" />\n\n {variant === 'circles' && (\n <div className=\"absolute inset-0\">\n {Array.from({ length: 7 }, (_, index) => (\n <span\n key={index}\n className=\"absolute left-1/2 top-1/2 rounded-full border border-border/60\"\n style={{\n width: `${(index + 1) * 14}%`,\n height: `${(index + 1) * 14}%`,\n transform: 'translate(-50%, -50%)',\n }}\n />\n ))}\n </div>\n )}\n\n {(variant === 'grid' || variant === 'grid-dot') && (\n <div\n className=\"absolute inset-0 opacity-70 [mask-image:radial-gradient(circle_at_center,black_0%,black_48%,transparent_76%)]\"\n style={gridPatternStyle(size, variant === 'grid-dot')}\n />\n )}\n\n {variant === 'squares' && (\n <div className=\"absolute inset-0\">\n {squaresBySize[size].map((squareSize) => (\n <span\n key={squareSize}\n className=\"absolute left-1/2 top-1/2 rounded-xl border border-border/55\"\n style={{\n width: squareSize,\n height: squareSize,\n transform: 'translate(-50%, -50%) rotate(-12.5deg)',\n }}\n />\n ))}\n </div>\n )}\n </div>\n );\n});\n\nEmptyStateBackgroundPattern.displayName = 'EmptyStateBackgroundPattern';\n\n// ============================================================================\n// Illustration\n// ============================================================================\n\nexport interface EmptyStateIllustrationProps\n extends Omit<React.HTMLAttributes<HTMLDivElement>, 'children'> {\n size?: EmptyStateSize;\n variant?: EmptyStateIllustrationVariant;\n tone?: EmptyStateTone;\n icon?: React.ReactNode;\n}\n\nfunction DecorativeDots({ tone }: { tone: EmptyStateTone }) {\n const dotClassName =\n tone === 'primary' ? 'bg-primary/70' : 'bg-muted-foreground/10';\n\n return (\n <>\n <span\n className={cn(\n 'absolute left-[7%] top-[8%] size-2 rounded-full',\n dotClassName,\n )}\n />\n <span\n className={cn(\n 'absolute right-[6%] top-[18%] size-3 rounded-full',\n dotClassName,\n )}\n />\n <span\n className={cn(\n 'absolute bottom-[10%] left-[8%] size-3 rounded-full',\n dotClassName,\n )}\n />\n <span\n className={cn(\n 'absolute bottom-[18%] right-[13%] size-2 rounded-full',\n dotClassName,\n )}\n />\n </>\n );\n}\n\n// Keep every artwork bbox centered on the shared 220 × 168 viewBox center (110, 84).\nfunction CloudShape({\n accentId,\n shadeId,\n tone,\n}: {\n accentId: string;\n shadeId: string;\n tone: EmptyStateTone;\n}) {\n return (\n <g\n transform=\"translate(10.5 14.5)\"\n className=\"drop-shadow-[0_8px_16px_var(--shadow-soft-3-color)]\"\n >\n <path\n d=\"M54 110c-21 0-38-14-38-32 0-16 14-30 33-32 8-19 27-31 49-31 27 0 50 19 55 43 17 3 30 16 30 32 0 19-18 34-40 34H55c-1 0-1-14-1-14Z\"\n fill={`url(#${shadeId})`}\n />\n <path\n d=\"M68 106c-18 0-32-12-32-27 0-13 11-24 27-26 7-16 23-26 42-26 23 0 42 16 46 36 15 3 26 14 26 28 0 16-15 29-34 29H68v-14Z\"\n fill={`url(#${accentId})`}\n opacity={tone === 'primary' ? 0.78 : 0.36}\n />\n </g>\n );\n}\n\nfunction BoxShape({\n accentId,\n shadeId,\n}: {\n accentId: string;\n shadeId: string;\n}) {\n return (\n <g\n transform=\"translate(-19.5)\"\n className=\"drop-shadow-[0_8px_16px_var(--shadow-soft-3-color)]\"\n >\n <path d=\"M72 42 132 20l55 31-62 24-53-33Z\" fill={`url(#${accentId})`} />\n <path d=\"M72 42v72l53 34V75L72 42Z\" fill={`url(#${shadeId})`} />\n <path d=\"M125 75v73l62-35V51l-62 24Z\" fill=\"var(--card)\" />\n <path\n d=\"M132 20v33l24 14V34l-24-14Z\"\n fill=\"currentColor\"\n opacity=\"0.34\"\n />\n <path\n d=\"M72 42 132 20l55 31-62 24-53-33Z\"\n fill=\"none\"\n stroke=\"var(--border)\"\n />\n </g>\n );\n}\n\nfunction DocumentsShape({\n accentId,\n shadeId,\n}: {\n accentId: string;\n shadeId: string;\n}) {\n return (\n <g\n transform=\"translate(0 -0.5)\"\n className=\"drop-shadow-[0_8px_16px_var(--shadow-soft-3-color)]\"\n >\n <g transform=\"translate(44 48) rotate(-18)\">\n <rect\n width=\"58\"\n height=\"78\"\n rx=\"7\"\n fill={`url(#${shadeId})`}\n stroke=\"var(--border)\"\n />\n <path\n d=\"M15 21h28M15 35h21M15 49h28\"\n stroke=\"currentColor\"\n strokeOpacity=\"0.28\"\n />\n </g>\n <g transform=\"translate(83 32)\">\n <rect\n width=\"58\"\n height=\"88\"\n rx=\"7\"\n fill=\"var(--card)\"\n stroke=\"var(--border)\"\n />\n <path\n d=\"M16 26h28M16 41h22M16 56h28\"\n stroke=\"currentColor\"\n strokeOpacity=\"0.32\"\n />\n </g>\n <g transform=\"translate(121 47) rotate(18)\">\n <rect\n width=\"58\"\n height=\"78\"\n rx=\"7\"\n fill={`url(#${accentId})`}\n stroke=\"var(--border)\"\n />\n <path\n d=\"M15 21h28M15 35h21M15 49h28\"\n stroke=\"currentColor\"\n strokeOpacity=\"0.32\"\n />\n </g>\n </g>\n );\n}\n\nfunction CreditCardShape({\n accentId,\n shadeId,\n}: {\n accentId: string;\n shadeId: string;\n}) {\n return (\n <g\n transform=\"translate(0 -5)\"\n className=\"drop-shadow-[0_8px_16px_var(--shadow-soft-3-color)]\"\n >\n <rect\n x=\"42\"\n y=\"48\"\n width=\"136\"\n height=\"82\"\n rx=\"12\"\n fill={`url(#${shadeId})`}\n stroke=\"var(--border)\"\n />\n <rect\n x=\"42\"\n y=\"70\"\n width=\"136\"\n height=\"16\"\n fill={`url(#${accentId})`}\n opacity=\"0.72\"\n />\n <rect\n x=\"58\"\n y=\"104\"\n width=\"28\"\n height=\"8\"\n rx=\"2\"\n fill=\"currentColor\"\n opacity=\"0.28\"\n />\n <rect\n x=\"58\"\n y=\"116\"\n width=\"58\"\n height=\"5\"\n rx=\"2.5\"\n fill=\"currentColor\"\n opacity=\"0.18\"\n />\n <circle cx=\"146\" cy=\"112\" r=\"10\" fill=\"currentColor\" opacity=\"0.24\" />\n <circle cx=\"158\" cy=\"112\" r=\"10\" fill=\"currentColor\" opacity=\"0.38\" />\n </g>\n );\n}\n\nexport const EmptyStateIllustration = React.forwardRef<\n HTMLDivElement,\n EmptyStateIllustrationProps\n>(\n (\n {\n className,\n size = 'sm',\n variant = 'cloud',\n tone = 'primary',\n icon = <Heart aria-hidden=\"true\" />,\n ...props\n },\n ref,\n ) => {\n const accentId = React.useId();\n const shadeId = React.useId();\n const isPrimary = tone === 'primary';\n\n return (\n <div\n ref={ref}\n data-slot=\"empty-state-illustration\"\n data-testid=\"empty-state-illustration\"\n data-size={size}\n data-variant={variant}\n data-tone={tone}\n aria-hidden=\"true\"\n className={cn(\n 'relative shrink-0 text-primary',\n !isPrimary && 'text-muted-foreground',\n illustrationSizeClass[size][variant],\n className,\n )}\n {...props}\n >\n <div\n data-slot=\"empty-state-illustration-background\"\n data-testid=\"empty-state-illustration-background\"\n data-centered=\"true\"\n className={cn(\n 'absolute left-1/2 top-1/2 -translate-x-1/2 -translate-y-1/2 rounded-full',\n isPrimary ? 'bg-primary/20' : 'bg-muted/80',\n illustrationCircleSizeClass[size],\n )}\n />\n <DecorativeDots tone={tone} />\n <svg\n viewBox=\"0 0 220 168\"\n className=\"absolute inset-0 size-full overflow-visible\"\n fill=\"none\"\n aria-hidden=\"true\"\n >\n <defs>\n <linearGradient id={accentId} x1=\"25\" y1=\"12\" x2=\"190\" y2=\"148\">\n <stop\n stopColor={isPrimary ? 'var(--primary)' : 'var(--muted)'}\n stopOpacity={isPrimary ? 0.34 : 0.74}\n />\n <stop stopColor=\"var(--card)\" stopOpacity={0.95} />\n </linearGradient>\n <linearGradient id={shadeId} x1=\"54\" y1=\"18\" x2=\"165\" y2=\"140\">\n <stop stopColor=\"var(--card)\" />\n <stop\n stopColor={\n isPrimary ? 'var(--primary)' : 'var(--muted-foreground)'\n }\n stopOpacity={isPrimary ? 0.18 : 0.14}\n />\n </linearGradient>\n </defs>\n\n {variant === 'cloud' && (\n <CloudShape accentId={accentId} shadeId={shadeId} tone={tone} />\n )}\n {variant === 'box' && (\n <BoxShape accentId={accentId} shadeId={shadeId} />\n )}\n {variant === 'documents' && (\n <DocumentsShape accentId={accentId} shadeId={shadeId} />\n )}\n {variant === 'credit-card' && (\n <CreditCardShape accentId={accentId} shadeId={shadeId} />\n )}\n </svg>\n <div\n data-slot=\"empty-state-illustration-icon\"\n data-testid=\"empty-state-illustration-icon\"\n data-centered=\"true\"\n className={cn(\n 'absolute left-1/2 top-1/2 flex -translate-x-1/2 -translate-y-1/2 items-center justify-center rounded-xl bg-primary/10 text-primary shadow-xs backdrop-blur-md supports-backdrop-filter:backdrop-blur-md [&>svg]:shrink-0',\n !isPrimary && 'bg-muted text-muted-foreground',\n illustrationIconSizeClass[size],\n )}\n >\n <EmptyStateIconGlyph icon={icon} size={size} />\n </div>\n </div>\n );\n },\n);\n\nEmptyStateIllustration.displayName = 'EmptyStateIllustration';\n\n// ============================================================================\n// EmptyState\n// ============================================================================\n\nconst emptyStateVariants = cva(\n 'relative isolate mx-auto flex w-full max-w-[512px] items-center justify-center overflow-visible py-8 text-center',\n {\n variants: {\n size: {\n sm: 'min-h-[212px]',\n md: 'min-h-[280px]',\n lg: 'min-h-[360px]',\n },\n },\n defaultVariants: {\n size: 'sm',\n },\n },\n);\n\nexport interface EmptyStateProps\n extends Omit<React.HTMLAttributes<HTMLElement>, 'title'> {\n title: React.ReactNode;\n description?: React.ReactNode;\n size?: EmptyStateSize;\n media?: EmptyStateMedia;\n pattern?: EmptyStateBackgroundPatternVariant | 'auto';\n icon?: React.ReactNode;\n iconLabel?: string;\n illustrationVariant?: EmptyStateIllustrationVariant;\n illustrationTone?: EmptyStateTone;\n fileExtension?: FileExtension;\n fileType?: SimpleFileType;\n primaryAction?: EmptyStateActionConfig;\n secondaryAction?: EmptyStateActionConfig;\n actions?: React.ReactNode;\n headingLevel?: 2 | 3 | 4;\n}\n\nfunction resolvePattern(\n pattern: EmptyStateProps['pattern'],\n media: EmptyStateMedia,\n): EmptyStateBackgroundPatternVariant {\n if (!pattern || pattern === 'auto') {\n if (media === 'illustration') return 'grid';\n if (media === 'none') return 'none';\n return 'circles';\n }\n return pattern;\n}\n\nfunction renderEmptyStateAction(\n action: EmptyStateActionConfig,\n intent: 'primary' | 'secondary',\n) {\n const {\n label,\n onClick,\n startIcon,\n disabled,\n loading,\n 'aria-label': ariaLabel,\n } = action;\n\n return (\n <Button\n appearance={intent === 'primary' ? 'solid' : 'outline'}\n variant={intent === 'primary' ? 'primary' : 'secondary'}\n size=\"sm\"\n shape=\"rounded\"\n onClick={onClick}\n disabled={disabled}\n loading={loading}\n startIcon={startIcon}\n aria-label={ariaLabel}\n type=\"button\"\n >\n {label}\n </Button>\n );\n}\n\nexport const EmptyState = React.forwardRef<HTMLElement, EmptyStateProps>(\n (\n {\n className,\n title,\n description,\n size = 'sm',\n media = 'featured-icon',\n pattern = 'auto',\n icon,\n iconLabel,\n illustrationVariant = 'cloud',\n illustrationTone = 'gray',\n fileExtension,\n fileType = 'document',\n primaryAction,\n secondaryAction,\n actions,\n headingLevel = 3,\n ...props\n },\n ref,\n ) => {\n const Heading = headingTag[headingLevel];\n const resolvedPattern = resolvePattern(pattern, media);\n const defaultIcon = icon ?? <Search aria-hidden=\"true\" />;\n const hasActions = actions || primaryAction || secondaryAction;\n\n return (\n <section\n ref={ref}\n data-slot=\"empty-state\"\n aria-label={typeof title === 'string' ? title : 'Empty state'}\n className={cn(emptyStateVariants({ size }), className)}\n {...props}\n >\n <div\n data-slot=\"empty-state-content\"\n className={cn(\n 'relative z-10 flex min-w-0 flex-1 flex-col items-center',\n contentGapClass[size],\n )}\n >\n <div\n data-slot=\"empty-state-body\"\n className={cn(\n 'flex w-full flex-col items-center',\n mediaGapClass[size],\n )}\n >\n {media !== 'none' && (\n <div\n data-slot=\"empty-state-media\"\n data-testid=\"empty-state-media\"\n data-media={media}\n data-centered=\"true\"\n className=\"relative flex w-full min-w-0 justify-center\"\n >\n <EmptyStateBackgroundPattern\n size={size}\n variant={resolvedPattern}\n data-centered=\"true\"\n className=\"z-0\"\n />\n\n {media === 'featured-icon' && (\n <FeaturedIcon\n data-slot=\"empty-state-featured-icon\"\n size={featuredIconSize[size]}\n shape=\"rounded\"\n intent=\"default\"\n icon={\n <EmptyStateIconGlyph icon={defaultIcon} size={size} />\n }\n aria-label={iconLabel}\n className=\"relative z-10 delight-stagger motion-reduce:animate-none\"\n />\n )}\n\n {media === 'illustration' && (\n <EmptyStateIllustration\n size={size}\n variant={illustrationVariant}\n tone={illustrationTone}\n icon={defaultIcon}\n className=\"relative z-10 delight-stagger motion-reduce:animate-none\"\n />\n )}\n\n {media === 'file-type-icon' && (\n <div\n data-slot=\"empty-state-file-icon-wrap\"\n data-testid=\"empty-state-file-icon-wrap\"\n data-centered=\"true\"\n className={cn(\n 'relative z-10 flex items-center justify-center rounded-full bg-linear-[104deg,color-mix(in_oklch,var(--card)_60%,transparent),color-mix(in_oklch,var(--muted)_55%,transparent)] delight-stagger motion-reduce:animate-none',\n fileIconWrapSizeClass[size],\n )}\n >\n <div\n data-slot=\"empty-state-file-icon-optical-center\"\n data-testid=\"empty-state-file-icon-optical-center\"\n data-centered=\"true\"\n >\n <FileTypeIcon\n extension={fileExtension}\n fileType={fileExtension ? undefined : fileType}\n size={fileIconSize[size]}\n className=\"drop-shadow-[0_1px_2px_var(--shadow-xs-1-color)]\"\n />\n </div>\n </div>\n )}\n </div>\n )}\n\n <div\n data-slot=\"empty-state-text\"\n className={cn(\n 'flex w-full max-w-[352px] flex-col items-center text-center',\n textGapClass[size],\n )}\n >\n <Heading className=\"w-full text-base font-semibold leading-6 text-foreground\">\n {title}\n </Heading>\n {description && (\n <p className=\"w-full text-sm leading-5 text-secondary-foreground\">\n {description}\n </p>\n )}\n </div>\n </div>\n\n {hasActions && (\n <div\n data-slot=\"empty-state-actions\"\n className=\"flex flex-wrap items-center justify-center gap-3\"\n >\n {actions ?? (\n <>\n {secondaryAction &&\n renderEmptyStateAction(secondaryAction, 'secondary')}\n {primaryAction &&\n renderEmptyStateAction(primaryAction, 'primary')}\n </>\n )}\n </div>\n )}\n </div>\n </section>\n );\n },\n);\n\nEmptyState.displayName = 'EmptyState';\n"],"mappings":"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"}
|
package/dist/index24.js
CHANGED
|
@@ -216,7 +216,7 @@ var FeaturedIcon = React$1.forwardRef(({ children, size = "sm", className }, ref
|
|
|
216
216
|
className: cn("shrink-0 rounded-md border border-border bg-card/60", "flex items-center justify-center", "dark:border-border", containerSize, className),
|
|
217
217
|
style: { boxShadow: "var(--shadow-inset-ring)" },
|
|
218
218
|
children: /* @__PURE__ */ jsx("div", {
|
|
219
|
-
className: cn("text-secondary-foreground", innerSize),
|
|
219
|
+
className: cn("text-secondary-foreground [&>svg]:block [&>svg]:size-full", innerSize),
|
|
220
220
|
children
|
|
221
221
|
})
|
|
222
222
|
});
|
package/dist/index24.js.map
CHANGED
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"index24.js","names":[],"sources":["../src/components/ui/selection-group.tsx"],"sourcesContent":["'use client';\n\nimport { cva } from 'class-variance-authority';\nimport { Minus } from 'lucide-react';\nimport * as React from 'react';\nimport { cn } from '@/lib/utils';\n\n// =============================================================================\n// Types\n// =============================================================================\n\nexport type SelectionColor =\n | 'primary'\n | 'secondary'\n | 'success'\n | 'warning'\n | 'info'\n | 'destructive';\n\nexport type SelectionSize = 'sm' | 'md' | 'lg';\n\nexport type SelectionVariant =\n | 'default'\n | 'card'\n | 'pill'\n | 'stacked'\n | 'icon-simple'\n | 'icon-card'\n | 'avatar'\n | 'payment'\n | 'simple'\n | 'chip';\n\nexport interface SelectionItem {\n /** Unique value for the option */\n value: string;\n /** Display label */\n label: string;\n /** Whether this option is disabled */\n disabled?: boolean;\n /** Secondary text (e.g., \"$10/month\") */\n subtext?: string;\n /** Supporting description text */\n description?: string;\n /** Leading icon component */\n icon?: React.ReactNode;\n /** Avatar element */\n avatar?: React.ReactNode;\n /** Image URL */\n image?: string;\n /** Alt text for the image (defaults to \"\" if omitted) */\n imageAlt?: string;\n /** Position of the image */\n imagePosition?: 'top' | 'left' | 'trailing';\n /** Badge element */\n badge?: React.ReactNode;\n /** Dot color for chip variant (named color or hex) */\n dotColor?: string;\n /** Price display (e.g., \"$10\") */\n price?: string;\n /** Price period (e.g., \"per month\") */\n pricePeriod?: string;\n /** Payment icon element */\n paymentIcon?: React.ReactNode;\n /** Action buttons */\n actions?: React.ReactNode;\n}\n\n// =============================================================================\n// Hooks\n// =============================================================================\n\ninterface UseSelectionStateOptions {\n /** Controlled value */\n value?: string;\n /** Default value for uncontrolled mode */\n defaultValue?: string;\n /** Callback when value changes */\n onValueChange?: (value: string) => void;\n}\n\n/**\n * Hook for managing single selection state (radio behavior).\n * Supports both controlled and uncontrolled modes.\n */\nexport function useSelectionState(\n options: UseSelectionStateOptions = {},\n): [string | undefined, (value: string) => void] {\n const { value: controlledValue, defaultValue, onValueChange } = options;\n\n const [internalValue, setInternalValue] = React.useState<string | undefined>(\n defaultValue,\n );\n\n const isControlled = controlledValue !== undefined;\n const selectedValue = isControlled ? controlledValue : internalValue;\n\n const setValue = React.useCallback(\n (newValue: string) => {\n if (!isControlled) {\n setInternalValue(newValue);\n }\n onValueChange?.(newValue);\n },\n [isControlled, onValueChange],\n );\n\n return [selectedValue, setValue];\n}\n\ninterface UseMultiSelectionStateOptions {\n /** Controlled value */\n value?: string[];\n /** Default value for uncontrolled mode */\n defaultValue?: string[];\n /** Callback when value changes */\n onValueChange?: (value: string[]) => void;\n}\n\n/**\n * Hook for managing multi selection state (checkbox behavior).\n * Supports both controlled and uncontrolled modes.\n */\nexport function useMultiSelectionState(\n options: UseMultiSelectionStateOptions = {},\n): [string[], (value: string, checked: boolean) => void] {\n const { value: controlledValue, defaultValue = [], onValueChange } = options;\n\n const [internalValue, setInternalValue] =\n React.useState<string[]>(defaultValue);\n\n const isControlled = controlledValue !== undefined;\n const selectedValues = isControlled ? controlledValue : internalValue;\n\n const setValue = React.useCallback(\n (itemValue: string, checked: boolean) => {\n const newValue = checked\n ? [...selectedValues, itemValue]\n : selectedValues.filter((v) => v !== itemValue);\n\n if (!isControlled) {\n setInternalValue(newValue);\n }\n onValueChange?.(newValue);\n },\n [isControlled, selectedValues, onValueChange],\n );\n\n return [selectedValues, setValue];\n}\n\n// =============================================================================\n// Color Mappings\n// =============================================================================\n\nexport const selectionColorClasses: Record<\n SelectionColor,\n {\n indicator: string;\n indicatorChecked: string;\n border: string;\n bg: string;\n text: string;\n }\n> = {\n primary: {\n indicator: 'border-primary',\n indicatorChecked: 'bg-primary',\n border: 'border-primary',\n bg: 'bg-primary',\n text: 'text-primary-foreground',\n },\n secondary: {\n indicator: 'border-secondary',\n indicatorChecked: 'bg-secondary-foreground',\n border: 'border-secondary',\n bg: 'bg-secondary',\n text: 'text-secondary-foreground',\n },\n success: {\n indicator: 'border-success',\n indicatorChecked: 'bg-success',\n border: 'border-success',\n bg: 'bg-success',\n text: 'text-primary-foreground',\n },\n warning: {\n indicator: 'border-warning',\n indicatorChecked: 'bg-warning',\n border: 'border-warning',\n bg: 'bg-warning',\n text: 'text-primary-foreground',\n },\n info: {\n indicator: 'border-info',\n indicatorChecked: 'bg-info',\n border: 'border-info',\n bg: 'bg-info',\n text: 'text-primary-foreground',\n },\n destructive: {\n indicator: 'border-destructive',\n indicatorChecked: 'bg-destructive',\n border: 'border-destructive',\n bg: 'bg-destructive',\n text: 'text-primary-foreground',\n },\n};\n\n// =============================================================================\n// CVA Variants\n// =============================================================================\n\n/**\n * Selection group container variants.\n * Used for the outer wrapper of a group of selection items.\n */\nexport const selectionGroupVariants = cva('flex', {\n variants: {\n orientation: {\n horizontal: 'flex-row flex-wrap',\n vertical: 'flex-col',\n },\n gap: {\n sm: 'gap-2',\n md: 'gap-3',\n lg: 'gap-4',\n },\n },\n defaultVariants: {\n orientation: 'horizontal',\n gap: 'md',\n },\n});\n\n/**\n * Selection indicator variants (for both radio and checkbox).\n * Renders as a rounded indicator with border.\n */\nexport const selectionIndicatorVariants = cva(\n 'shrink-0 rounded-full border shadow-xs transition-all flex items-center justify-center',\n {\n variants: {\n size: {\n sm: 'size-4',\n md: 'size-5',\n lg: 'size-6',\n },\n },\n defaultVariants: {\n size: 'sm',\n },\n },\n);\n\n/**\n * Checkbox indicator variants (square with rounded corners).\n */\nexport const checkboxIndicatorVariants = cva(\n 'shrink-0 border shadow-xs transition-[border-color,background-color,color,box-shadow] duration-200 ease-out motion-reduce:transition-none flex items-center justify-center',\n {\n variants: {\n size: {\n sm: 'size-4 rounded-[4px]',\n md: 'size-5 rounded-[5px]',\n lg: 'size-6 rounded-[6px]',\n },\n },\n defaultVariants: {\n size: 'sm',\n },\n },\n);\n\n/**\n * Inner dot sizes for radio indicators when checked.\n */\nexport const innerDotSizes: Record<SelectionSize, string> = {\n sm: 'size-2',\n md: 'size-3',\n lg: 'size-4',\n};\n\n/**\n * Text size classes for selection labels.\n */\nexport const textSizeClasses: Record<SelectionSize, string> = {\n sm: 'text-sm',\n md: 'text-sm',\n lg: 'text-sm',\n};\n\n/**\n * Icon size classes for checkbox indicators.\n */\nexport const iconSizeClasses: Record<SelectionSize, string> = {\n sm: 'size-3',\n md: 'size-3.5',\n lg: 'size-5',\n};\n\n// =============================================================================\n// Draw-on checkmark SVG (shared delight animation)\n// =============================================================================\n\nexport const CHECKMARK_PATH = 'M4 12l5 5L20 6';\n\nexport function DrawCheck({ className }: { className?: string }) {\n return (\n <svg\n viewBox=\"0 0 24 24\"\n fill=\"none\"\n stroke=\"currentColor\"\n strokeWidth={3}\n strokeLinecap=\"round\"\n strokeLinejoin=\"round\"\n className={cn(className, 'delight-check-draw')}\n >\n <path d={CHECKMARK_PATH} />\n </svg>\n );\n}\n\n// =============================================================================\n// SelectionIndicator Component\n// =============================================================================\n\nexport interface SelectionIndicatorProps {\n /** Type of indicator to render */\n type: 'checkbox' | 'radio';\n /** Whether the indicator is checked */\n checked?: boolean;\n /** Whether the indicator is disabled */\n disabled?: boolean;\n /** Size of the indicator */\n size?: SelectionSize;\n /** Color of the indicator */\n color?: SelectionColor;\n /** Additional CSS classes */\n className?: string;\n /** Whether the checkbox is in indeterminate state (checkbox only) */\n indeterminate?: boolean;\n}\n\n/**\n * SelectionIndicator renders either a checkbox or radio indicator based on type.\n * For checkbox: renders a check icon when checked.\n * For radio: renders an inner dot when checked.\n */\nconst SelectionIndicator = React.forwardRef<\n HTMLSpanElement,\n SelectionIndicatorProps\n>(\n (\n {\n type,\n checked = false,\n disabled = false,\n size = 'sm',\n color = 'primary',\n className,\n indeterminate = false,\n },\n ref,\n ) => {\n const colors = selectionColorClasses[color];\n\n if (type === 'checkbox') {\n return (\n <span\n ref={ref}\n data-slot=\"selection-indicator\"\n data-type=\"checkbox\"\n data-checked={checked}\n data-indeterminate={indeterminate || undefined}\n className={cn(\n checkboxIndicatorVariants({ size }),\n checked || indeterminate\n ? cn(\n colors.indicatorChecked,\n colors.border,\n colors.text,\n 'border',\n 'delight-check-bounce',\n )\n : 'border-input bg-background',\n disabled && 'opacity-50',\n className,\n )}\n aria-hidden=\"true\"\n >\n {(checked || indeterminate) &&\n (indeterminate ? (\n <Minus\n className={cn(\n iconSizeClasses[size],\n 'animate-[scale-in_150ms_ease-out] motion-reduce:animate-none',\n )}\n strokeWidth={3}\n />\n ) : (\n <DrawCheck className={iconSizeClasses[size]} />\n ))}\n </span>\n );\n }\n\n // Radio type\n return (\n <span\n ref={ref}\n data-slot=\"selection-indicator\"\n data-type=\"radio\"\n data-checked={checked}\n className={cn(\n selectionIndicatorVariants({ size }),\n 'transition-[background-color,border-color] duration-150 motion-reduce:transition-none',\n 'border-input bg-transparent',\n disabled && 'opacity-50',\n className,\n )}\n aria-hidden=\"true\"\n >\n <span\n className={cn(\n 'rounded-full transition-transform duration-150 ease-out motion-reduce:transition-none',\n colors.indicatorChecked,\n innerDotSizes[size],\n checked ? 'scale-100' : 'scale-0',\n )}\n />\n </span>\n );\n },\n);\n\nSelectionIndicator.displayName = 'SelectionIndicator';\n\n// =============================================================================\n// FeaturedIcon Component\n// =============================================================================\n\nexport interface FeaturedIconProps {\n /** The icon content to display */\n children: React.ReactNode;\n /** Size of the featured icon container */\n size?: SelectionSize;\n /** Additional CSS classes */\n className?: string;\n}\n\n// Hoisted outside component to avoid recreation on every render\nconst featuredIconContainerSizes: Record<SelectionSize, string> = {\n sm: 'size-8',\n md: 'size-10',\n lg: 'size-12',\n};\n\nconst featuredIconInnerSizes: Record<SelectionSize, string> = {\n sm: 'size-4',\n md: 'size-5',\n lg: 'size-6',\n};\n\n/**\n * FeaturedIcon is a container for icons with border and shadow.\n * Used in icon-simple and icon-card variants.\n */\nconst FeaturedIcon = React.forwardRef<HTMLDivElement, FeaturedIconProps>(\n ({ children, size = 'sm', className }, ref) => {\n const containerSize = featuredIconContainerSizes[size];\n const innerSize = featuredIconInnerSizes[size];\n\n return (\n <div\n ref={ref}\n data-slot=\"featured-icon\"\n className={cn(\n 'shrink-0 rounded-md border border-border bg-card/60',\n 'flex items-center justify-center',\n 'dark:border-border',\n containerSize,\n className,\n )}\n style={{\n boxShadow: 'var(--shadow-inset-ring)',\n }}\n >\n <div className={cn('text-secondary-foreground', innerSize)}>\n {children}\n </div>\n </div>\n );\n },\n);\n\nFeaturedIcon.displayName = 'FeaturedIcon';\n\n// =============================================================================\n// ColorDot Component\n// =============================================================================\n\nexport type ColorDotColor =\n | 'gray'\n | 'orange'\n | 'red'\n | 'darkRed'\n | 'brand'\n | 'success'\n | 'warning'\n | 'error'\n | string; // Allow custom hex colors\n\nconst dotColorMap: Record<string, string> = {\n gray: 'bg-muted',\n orange: 'bg-warning',\n red: 'bg-destructive',\n darkRed: 'bg-destructive-hover',\n brand: 'bg-primary/10',\n success: 'bg-success/10',\n warning: 'bg-warning/10',\n error: 'bg-destructive/10',\n};\n\nconst dotSizeMap: Record<SelectionSize, string> = {\n sm: 'size-[10px]',\n md: 'size-3',\n lg: 'size-3.5',\n};\n\nexport interface ColorDotProps {\n /** Color of the dot (named color or hex) */\n color?: ColorDotColor;\n /** Size of the dot */\n size?: SelectionSize;\n /** Additional CSS classes */\n className?: string;\n}\n\n/**\n * ColorDot renders a colored dot for chip variant.\n * Supports named colors (gray, orange, red, etc.) and hex colors.\n */\nconst ColorDot = React.forwardRef<HTMLSpanElement, ColorDotProps>(\n ({ color, size = 'sm', className }, ref) => {\n if (!color) return null;\n\n const colorClass = dotColorMap[color];\n const isHexColor = color.startsWith('#');\n\n return (\n <span\n ref={ref}\n data-slot=\"color-dot\"\n className={cn(\n 'shrink-0 rounded-full',\n dotSizeMap[size],\n !isHexColor && colorClass,\n className,\n )}\n style={isHexColor ? { backgroundColor: color } : undefined}\n aria-hidden=\"true\"\n />\n );\n },\n);\n\nColorDot.displayName = 'ColorDot';\n\n// =============================================================================\n// Exports\n// =============================================================================\n\nexport { ColorDot, FeaturedIcon, SelectionIndicator };\n"],"mappings":"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"}
|
|
1
|
+
{"version":3,"file":"index24.js","names":[],"sources":["../src/components/ui/selection-group.tsx"],"sourcesContent":["'use client';\n\nimport { cva } from 'class-variance-authority';\nimport { Minus } from 'lucide-react';\nimport * as React from 'react';\nimport { cn } from '@/lib/utils';\n\n// =============================================================================\n// Types\n// =============================================================================\n\nexport type SelectionColor =\n | 'primary'\n | 'secondary'\n | 'success'\n | 'warning'\n | 'info'\n | 'destructive';\n\nexport type SelectionSize = 'sm' | 'md' | 'lg';\n\nexport type SelectionVariant =\n | 'default'\n | 'card'\n | 'pill'\n | 'stacked'\n | 'icon-simple'\n | 'icon-card'\n | 'avatar'\n | 'payment'\n | 'simple'\n | 'chip';\n\nexport interface SelectionItem {\n /** Unique value for the option */\n value: string;\n /** Display label */\n label: string;\n /** Whether this option is disabled */\n disabled?: boolean;\n /** Secondary text (e.g., \"$10/month\") */\n subtext?: string;\n /** Supporting description text */\n description?: string;\n /** Leading icon component */\n icon?: React.ReactNode;\n /** Avatar element */\n avatar?: React.ReactNode;\n /** Image URL */\n image?: string;\n /** Alt text for the image (defaults to \"\" if omitted) */\n imageAlt?: string;\n /** Position of the image */\n imagePosition?: 'top' | 'left' | 'trailing';\n /** Badge element */\n badge?: React.ReactNode;\n /** Dot color for chip variant (named color or hex) */\n dotColor?: string;\n /** Price display (e.g., \"$10\") */\n price?: string;\n /** Price period (e.g., \"per month\") */\n pricePeriod?: string;\n /** Payment icon element */\n paymentIcon?: React.ReactNode;\n /** Action buttons */\n actions?: React.ReactNode;\n}\n\n// =============================================================================\n// Hooks\n// =============================================================================\n\ninterface UseSelectionStateOptions {\n /** Controlled value */\n value?: string;\n /** Default value for uncontrolled mode */\n defaultValue?: string;\n /** Callback when value changes */\n onValueChange?: (value: string) => void;\n}\n\n/**\n * Hook for managing single selection state (radio behavior).\n * Supports both controlled and uncontrolled modes.\n */\nexport function useSelectionState(\n options: UseSelectionStateOptions = {},\n): [string | undefined, (value: string) => void] {\n const { value: controlledValue, defaultValue, onValueChange } = options;\n\n const [internalValue, setInternalValue] = React.useState<string | undefined>(\n defaultValue,\n );\n\n const isControlled = controlledValue !== undefined;\n const selectedValue = isControlled ? controlledValue : internalValue;\n\n const setValue = React.useCallback(\n (newValue: string) => {\n if (!isControlled) {\n setInternalValue(newValue);\n }\n onValueChange?.(newValue);\n },\n [isControlled, onValueChange],\n );\n\n return [selectedValue, setValue];\n}\n\ninterface UseMultiSelectionStateOptions {\n /** Controlled value */\n value?: string[];\n /** Default value for uncontrolled mode */\n defaultValue?: string[];\n /** Callback when value changes */\n onValueChange?: (value: string[]) => void;\n}\n\n/**\n * Hook for managing multi selection state (checkbox behavior).\n * Supports both controlled and uncontrolled modes.\n */\nexport function useMultiSelectionState(\n options: UseMultiSelectionStateOptions = {},\n): [string[], (value: string, checked: boolean) => void] {\n const { value: controlledValue, defaultValue = [], onValueChange } = options;\n\n const [internalValue, setInternalValue] =\n React.useState<string[]>(defaultValue);\n\n const isControlled = controlledValue !== undefined;\n const selectedValues = isControlled ? controlledValue : internalValue;\n\n const setValue = React.useCallback(\n (itemValue: string, checked: boolean) => {\n const newValue = checked\n ? [...selectedValues, itemValue]\n : selectedValues.filter((v) => v !== itemValue);\n\n if (!isControlled) {\n setInternalValue(newValue);\n }\n onValueChange?.(newValue);\n },\n [isControlled, selectedValues, onValueChange],\n );\n\n return [selectedValues, setValue];\n}\n\n// =============================================================================\n// Color Mappings\n// =============================================================================\n\nexport const selectionColorClasses: Record<\n SelectionColor,\n {\n indicator: string;\n indicatorChecked: string;\n border: string;\n bg: string;\n text: string;\n }\n> = {\n primary: {\n indicator: 'border-primary',\n indicatorChecked: 'bg-primary',\n border: 'border-primary',\n bg: 'bg-primary',\n text: 'text-primary-foreground',\n },\n secondary: {\n indicator: 'border-secondary',\n indicatorChecked: 'bg-secondary-foreground',\n border: 'border-secondary',\n bg: 'bg-secondary',\n text: 'text-secondary-foreground',\n },\n success: {\n indicator: 'border-success',\n indicatorChecked: 'bg-success',\n border: 'border-success',\n bg: 'bg-success',\n text: 'text-primary-foreground',\n },\n warning: {\n indicator: 'border-warning',\n indicatorChecked: 'bg-warning',\n border: 'border-warning',\n bg: 'bg-warning',\n text: 'text-primary-foreground',\n },\n info: {\n indicator: 'border-info',\n indicatorChecked: 'bg-info',\n border: 'border-info',\n bg: 'bg-info',\n text: 'text-primary-foreground',\n },\n destructive: {\n indicator: 'border-destructive',\n indicatorChecked: 'bg-destructive',\n border: 'border-destructive',\n bg: 'bg-destructive',\n text: 'text-primary-foreground',\n },\n};\n\n// =============================================================================\n// CVA Variants\n// =============================================================================\n\n/**\n * Selection group container variants.\n * Used for the outer wrapper of a group of selection items.\n */\nexport const selectionGroupVariants = cva('flex', {\n variants: {\n orientation: {\n horizontal: 'flex-row flex-wrap',\n vertical: 'flex-col',\n },\n gap: {\n sm: 'gap-2',\n md: 'gap-3',\n lg: 'gap-4',\n },\n },\n defaultVariants: {\n orientation: 'horizontal',\n gap: 'md',\n },\n});\n\n/**\n * Selection indicator variants (for both radio and checkbox).\n * Renders as a rounded indicator with border.\n */\nexport const selectionIndicatorVariants = cva(\n 'shrink-0 rounded-full border shadow-xs transition-all flex items-center justify-center',\n {\n variants: {\n size: {\n sm: 'size-4',\n md: 'size-5',\n lg: 'size-6',\n },\n },\n defaultVariants: {\n size: 'sm',\n },\n },\n);\n\n/**\n * Checkbox indicator variants (square with rounded corners).\n */\nexport const checkboxIndicatorVariants = cva(\n 'shrink-0 border shadow-xs transition-[border-color,background-color,color,box-shadow] duration-200 ease-out motion-reduce:transition-none flex items-center justify-center',\n {\n variants: {\n size: {\n sm: 'size-4 rounded-[4px]',\n md: 'size-5 rounded-[5px]',\n lg: 'size-6 rounded-[6px]',\n },\n },\n defaultVariants: {\n size: 'sm',\n },\n },\n);\n\n/**\n * Inner dot sizes for radio indicators when checked.\n */\nexport const innerDotSizes: Record<SelectionSize, string> = {\n sm: 'size-2',\n md: 'size-3',\n lg: 'size-4',\n};\n\n/**\n * Text size classes for selection labels.\n */\nexport const textSizeClasses: Record<SelectionSize, string> = {\n sm: 'text-sm',\n md: 'text-sm',\n lg: 'text-sm',\n};\n\n/**\n * Icon size classes for checkbox indicators.\n */\nexport const iconSizeClasses: Record<SelectionSize, string> = {\n sm: 'size-3',\n md: 'size-3.5',\n lg: 'size-5',\n};\n\n// =============================================================================\n// Draw-on checkmark SVG (shared delight animation)\n// =============================================================================\n\nexport const CHECKMARK_PATH = 'M4 12l5 5L20 6';\n\nexport function DrawCheck({ className }: { className?: string }) {\n return (\n <svg\n viewBox=\"0 0 24 24\"\n fill=\"none\"\n stroke=\"currentColor\"\n strokeWidth={3}\n strokeLinecap=\"round\"\n strokeLinejoin=\"round\"\n className={cn(className, 'delight-check-draw')}\n >\n <path d={CHECKMARK_PATH} />\n </svg>\n );\n}\n\n// =============================================================================\n// SelectionIndicator Component\n// =============================================================================\n\nexport interface SelectionIndicatorProps {\n /** Type of indicator to render */\n type: 'checkbox' | 'radio';\n /** Whether the indicator is checked */\n checked?: boolean;\n /** Whether the indicator is disabled */\n disabled?: boolean;\n /** Size of the indicator */\n size?: SelectionSize;\n /** Color of the indicator */\n color?: SelectionColor;\n /** Additional CSS classes */\n className?: string;\n /** Whether the checkbox is in indeterminate state (checkbox only) */\n indeterminate?: boolean;\n}\n\n/**\n * SelectionIndicator renders either a checkbox or radio indicator based on type.\n * For checkbox: renders a check icon when checked.\n * For radio: renders an inner dot when checked.\n */\nconst SelectionIndicator = React.forwardRef<\n HTMLSpanElement,\n SelectionIndicatorProps\n>(\n (\n {\n type,\n checked = false,\n disabled = false,\n size = 'sm',\n color = 'primary',\n className,\n indeterminate = false,\n },\n ref,\n ) => {\n const colors = selectionColorClasses[color];\n\n if (type === 'checkbox') {\n return (\n <span\n ref={ref}\n data-slot=\"selection-indicator\"\n data-type=\"checkbox\"\n data-checked={checked}\n data-indeterminate={indeterminate || undefined}\n className={cn(\n checkboxIndicatorVariants({ size }),\n checked || indeterminate\n ? cn(\n colors.indicatorChecked,\n colors.border,\n colors.text,\n 'border',\n 'delight-check-bounce',\n )\n : 'border-input bg-background',\n disabled && 'opacity-50',\n className,\n )}\n aria-hidden=\"true\"\n >\n {(checked || indeterminate) &&\n (indeterminate ? (\n <Minus\n className={cn(\n iconSizeClasses[size],\n 'animate-[scale-in_150ms_ease-out] motion-reduce:animate-none',\n )}\n strokeWidth={3}\n />\n ) : (\n <DrawCheck className={iconSizeClasses[size]} />\n ))}\n </span>\n );\n }\n\n // Radio type\n return (\n <span\n ref={ref}\n data-slot=\"selection-indicator\"\n data-type=\"radio\"\n data-checked={checked}\n className={cn(\n selectionIndicatorVariants({ size }),\n 'transition-[background-color,border-color] duration-150 motion-reduce:transition-none',\n 'border-input bg-transparent',\n disabled && 'opacity-50',\n className,\n )}\n aria-hidden=\"true\"\n >\n <span\n className={cn(\n 'rounded-full transition-transform duration-150 ease-out motion-reduce:transition-none',\n colors.indicatorChecked,\n innerDotSizes[size],\n checked ? 'scale-100' : 'scale-0',\n )}\n />\n </span>\n );\n },\n);\n\nSelectionIndicator.displayName = 'SelectionIndicator';\n\n// =============================================================================\n// FeaturedIcon Component\n// =============================================================================\n\nexport interface FeaturedIconProps {\n /** The icon content to display */\n children: React.ReactNode;\n /** Size of the featured icon container */\n size?: SelectionSize;\n /** Additional CSS classes */\n className?: string;\n}\n\n// Hoisted outside component to avoid recreation on every render\nconst featuredIconContainerSizes: Record<SelectionSize, string> = {\n sm: 'size-8',\n md: 'size-10',\n lg: 'size-12',\n};\n\nconst featuredIconInnerSizes: Record<SelectionSize, string> = {\n sm: 'size-4',\n md: 'size-5',\n lg: 'size-6',\n};\n\n/**\n * FeaturedIcon is a container for icons with border and shadow.\n * Used in icon-simple and icon-card variants.\n */\nconst FeaturedIcon = React.forwardRef<HTMLDivElement, FeaturedIconProps>(\n ({ children, size = 'sm', className }, ref) => {\n const containerSize = featuredIconContainerSizes[size];\n const innerSize = featuredIconInnerSizes[size];\n\n return (\n <div\n ref={ref}\n data-slot=\"featured-icon\"\n className={cn(\n 'shrink-0 rounded-md border border-border bg-card/60',\n 'flex items-center justify-center',\n 'dark:border-border',\n containerSize,\n className,\n )}\n style={{\n boxShadow: 'var(--shadow-inset-ring)',\n }}\n >\n <div\n className={cn(\n 'text-secondary-foreground [&>svg]:block [&>svg]:size-full',\n innerSize,\n )}\n >\n {children}\n </div>\n </div>\n );\n },\n);\n\nFeaturedIcon.displayName = 'FeaturedIcon';\n\n// =============================================================================\n// ColorDot Component\n// =============================================================================\n\nexport type ColorDotColor =\n | 'gray'\n | 'orange'\n | 'red'\n | 'darkRed'\n | 'brand'\n | 'success'\n | 'warning'\n | 'error'\n | string; // Allow custom hex colors\n\nconst dotColorMap: Record<string, string> = {\n gray: 'bg-muted',\n orange: 'bg-warning',\n red: 'bg-destructive',\n darkRed: 'bg-destructive-hover',\n brand: 'bg-primary/10',\n success: 'bg-success/10',\n warning: 'bg-warning/10',\n error: 'bg-destructive/10',\n};\n\nconst dotSizeMap: Record<SelectionSize, string> = {\n sm: 'size-[10px]',\n md: 'size-3',\n lg: 'size-3.5',\n};\n\nexport interface ColorDotProps {\n /** Color of the dot (named color or hex) */\n color?: ColorDotColor;\n /** Size of the dot */\n size?: SelectionSize;\n /** Additional CSS classes */\n className?: string;\n}\n\n/**\n * ColorDot renders a colored dot for chip variant.\n * Supports named colors (gray, orange, red, etc.) and hex colors.\n */\nconst ColorDot = React.forwardRef<HTMLSpanElement, ColorDotProps>(\n ({ color, size = 'sm', className }, ref) => {\n if (!color) return null;\n\n const colorClass = dotColorMap[color];\n const isHexColor = color.startsWith('#');\n\n return (\n <span\n ref={ref}\n data-slot=\"color-dot\"\n className={cn(\n 'shrink-0 rounded-full',\n dotSizeMap[size],\n !isHexColor && colorClass,\n className,\n )}\n style={isHexColor ? { backgroundColor: color } : undefined}\n aria-hidden=\"true\"\n />\n );\n },\n);\n\nColorDot.displayName = 'ColorDot';\n\n// =============================================================================\n// Exports\n// =============================================================================\n\nexport { ColorDot, FeaturedIcon, SelectionIndicator };\n"],"mappings":"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"}
|