@humain/ui 2.4.2 → 2.4.4
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/index225.js +1 -1
- package/dist/index225.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-app-sidebar.js +1 -1
- package/dist/wc/hf-app-sidebar.js.map +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-app-sidebar.js +1 -1
- package/dist/wc-react/hf-app-sidebar.js.map +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/index225.js
CHANGED
|
@@ -342,7 +342,7 @@ function AppSidebarNavItem({ icon, label, isActive = false, badge, onClick, href
|
|
|
342
342
|
"aria-hidden": "true",
|
|
343
343
|
className: cn("size-4 shrink-0 text-muted-foreground transition-transform duration-200 ease-smooth group-data-[collapsible=icon]:hidden motion-reduce:transition-none", isOpen ? "rotate-90" : "rtl:rotate-180", isHighlighted && isOpen && "text-primary")
|
|
344
344
|
});
|
|
345
|
-
const itemClassName = cn(navItemVariants({ state: isHighlighted ? "active" : "default" }), "focus-visible:outline-2 focus-visible:outline-offset-
|
|
345
|
+
const itemClassName = cn(navItemVariants({ state: isHighlighted ? "active" : "default" }), "focus-visible:outline-2 focus-visible:outline-offset-[-2px] focus-visible:outline-ring", "min-h-11 group-data-[collapsible=icon]:justify-center group-data-[collapsible=icon]:px-0 group-data-[collapsible=icon]:py-2 group-data-[collapsible=icon]:w-11 group-data-[collapsible=icon]:h-11", className);
|
|
346
346
|
const ariaProps = isActive ? { "aria-current": "page" } : {};
|
|
347
347
|
if (isCollapsed) {
|
|
348
348
|
const collapsedIconElement = /* @__PURE__ */ jsx("span", {
|
package/dist/index225.js.map
CHANGED
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"index225.js","names":[],"sources":["../src/components/templates/AppSidebar/AppSidebar.tsx"],"sourcesContent":["/** biome-ignore-all lint/a11y/noNoninteractiveTabindex: ChatList uses tabIndex on scrollable div for keyboard scrolling */\n/** biome-ignore-all lint/a11y/useSemanticElements: NavSection uses role=\"separator\" on inner <div>; ChatList uses role=\"list\" on scrollable div */\n/** biome-ignore-all lint/a11y/useFocusableInteractive: Non-focusable separator per WAI-ARIA spec for decorative separators */\n/** biome-ignore-all lint/a11y/useAriaPropsForRole: Non-focusable separators don't require aria-valuenow per WAI-ARIA spec */\n/** biome-ignore-all lint/a11y/noNoninteractiveElementToInteractiveRole: role=\"separator\" on <div> inside list items for semantic section boundaries */\n\n'use client';\n\nimport { cva, type VariantProps } from 'class-variance-authority';\nimport {\n ChevronRight,\n MessageCircle,\n PanelLeftClose,\n PanelLeftOpen,\n} from 'lucide-react';\nimport * as React from 'react';\nimport { Badge } from '@/components/atoms/display/Badge';\nimport { Separator } from '@/components/atoms/layout/Separator';\nimport { Avatar } from '@/components/molecules/data/Avatar';\nimport { BrandIcon } from '@/components/molecules/data/BrandIcon';\nimport {\n PopoverPopup,\n PopoverRoot,\n PopoverTrigger,\n} from '@/components/organisms/overlays/Popover';\nimport {\n Sidebar,\n SidebarAccountSkeleton,\n SidebarContent,\n SidebarFooter,\n SidebarGroup,\n SidebarGroupContent,\n SidebarGroupLabel,\n SidebarHeader,\n SidebarInset,\n SidebarMenu,\n SidebarMenuButton,\n SidebarMenuItem,\n SidebarMenuSkeleton,\n SidebarNavSkeleton,\n SidebarProvider,\n SidebarTrigger,\n useSidebar,\n} from '@/components/ui/sidebar';\nimport { Tooltip, TooltipPopup, TooltipTrigger } from '@/components/ui/tooltip';\nimport { cn } from '@/lib/utils';\nimport {\n APP_SIDEBAR_COLLAPSED_WIDTH,\n APP_SIDEBAR_EXPANDED_WIDTH,\n} from './AppSidebar.constants';\n\nfunction formatAccessibleLabel(\n label: string,\n badge?: string | number | null,\n): string {\n if (badge == null) return label;\n return `${label}, ${typeof badge === 'number' ? `${badge} ${badge === 1 ? 'item' : 'items'}` : badge}`;\n}\n\nfunction getSidebarBgClass(\n isCollapsed: boolean,\n sidebarBgColor?: string,\n): string {\n return isCollapsed\n ? 'bg-transparent'\n : (sidebarBgColor ?? 'bg-[var(--sidebar)]');\n}\n\nfunction getSidebarSurfaceClass({\n isCollapsed,\n side,\n rounded,\n backgroundClass,\n}: {\n isCollapsed: boolean;\n side: AppSidebarSide;\n rounded: boolean;\n backgroundClass: string;\n}): string {\n return cn(\n 'flex h-full min-h-0 flex-col items-center pb-4 pt-6',\n isCollapsed\n ? 'w-full px-2'\n : [\n 'w-[calc(100%-0.75rem)] px-3',\n side === 'left' ? 'mr-3 self-start' : 'ml-3 self-end',\n ],\n backgroundClass,\n rounded && (side === 'left' ? 'rounded-r-lg' : 'rounded-l-lg'),\n );\n}\n\nfunction getSkeletonCount(count: number | undefined, fallback: number): number {\n return typeof count === 'number' && Number.isFinite(count) && count >= 0\n ? Math.floor(count)\n : fallback;\n}\n\n// ============================================\n// Slot Distribution Hook\n// ============================================\n\nconst APP_SIDEBAR_IMPLICIT_SLOT = Symbol('AppSidebarImplicitSlot');\n\ntype AppSidebarImplicitSlot = 'header' | 'content' | 'footer';\n\ninterface AppSidebarImplicitSlotComponent {\n [APP_SIDEBAR_IMPLICIT_SLOT]: AppSidebarImplicitSlot;\n}\n\ninterface AppSidebarWrappedComponent {\n type?: unknown;\n render?: unknown;\n}\n\nfunction markAppSidebarImplicitSlot<Component extends object>(\n component: Component,\n slot: AppSidebarImplicitSlot,\n): Component & AppSidebarImplicitSlotComponent {\n const slottedComponent = component as Component &\n AppSidebarImplicitSlotComponent;\n slottedComponent[APP_SIDEBAR_IMPLICIT_SLOT] = slot;\n return slottedComponent;\n}\n\nfunction isAppSidebarImplicitSlotComponent(\n value: unknown,\n): value is AppSidebarImplicitSlotComponent {\n return (\n (typeof value === 'function' ||\n (typeof value === 'object' && value !== null)) &&\n APP_SIDEBAR_IMPLICIT_SLOT in value\n );\n}\n\nfunction getAppSidebarImplicitSlot(\n childType: unknown,\n): AppSidebarImplicitSlot | undefined {\n if (isAppSidebarImplicitSlotComponent(childType)) {\n return childType[APP_SIDEBAR_IMPLICIT_SLOT];\n }\n\n if (typeof childType === 'object' && childType !== null) {\n const wrappedComponent = childType as AppSidebarWrappedComponent;\n return (\n getAppSidebarImplicitSlot(wrappedComponent.type) ??\n getAppSidebarImplicitSlot(wrappedComponent.render)\n );\n }\n\n return undefined;\n}\n\ntype SlotResult = {\n header: React.ReactNode[];\n content: React.ReactNode[];\n footer: React.ReactNode[];\n explicitHeader: React.ReactElement | null;\n explicitContent: React.ReactElement | null;\n explicitFooter: React.ReactElement | null;\n};\n\nfunction useSlotChildren(children: React.ReactNode): SlotResult {\n return React.useMemo(() => {\n const result: SlotResult = {\n header: [],\n content: [],\n footer: [],\n explicitHeader: null,\n explicitContent: null,\n explicitFooter: null,\n };\n\n React.Children.forEach(children, (child) => {\n if (!React.isValidElement(child)) return;\n\n const childType = child.type;\n\n // Check for explicit slot components\n if (childType === AppSidebarHeader) {\n result.explicitHeader = child;\n return;\n }\n if (childType === AppSidebarContent) {\n result.explicitContent = child;\n return;\n }\n if (childType === AppSidebarFooter) {\n result.explicitFooter = child;\n return;\n }\n\n // Distribute to slots based on explicit component-owned slot markers.\n const implicitSlot = getAppSidebarImplicitSlot(childType);\n if (implicitSlot === 'header') {\n result.header.push(child);\n } else if (implicitSlot === 'content') {\n result.content.push(child);\n } else if (implicitSlot === 'footer') {\n result.footer.push(child);\n } else {\n // Unknown children go to content by default\n result.content.push(child);\n }\n });\n\n return result;\n }, [children]);\n}\n\ntype AppSidebarSide = 'left' | 'right';\ntype AppSidebarDirection = 'ltr' | 'rtl';\n\nconst AppSidebarLayoutContext = React.createContext<{ side: AppSidebarSide }>({\n side: 'left',\n});\n\nfunction useAppSidebarLayout() {\n return React.useContext(AppSidebarLayoutContext);\n}\n\nfunction getAppSidebarDirection(\n element: HTMLElement | null,\n): AppSidebarDirection {\n const win = element?.ownerDocument.defaultView;\n if (!element || !win) return 'ltr';\n return win.getComputedStyle(element).direction === 'rtl' ? 'rtl' : 'ltr';\n}\n\nfunction normalizeAppSidebarDirection(\n dir: string | undefined,\n): AppSidebarDirection | undefined {\n return dir === 'rtl' || dir === 'ltr' ? dir : undefined;\n}\n\nfunction getAppSidebarSideFromDirection(\n direction: AppSidebarDirection,\n): AppSidebarSide {\n return direction === 'rtl' ? 'right' : 'left';\n}\n\nfunction getAppSidebarDirectionTargets(element: HTMLElement): Element[] {\n const targets = new Set<Element>();\n let current: Element | null = element;\n\n while (current) {\n targets.add(current);\n if (current === element.ownerDocument.documentElement) break;\n current = current.parentElement;\n }\n\n targets.add(element.ownerDocument.documentElement);\n if (element.ownerDocument.body) targets.add(element.ownerDocument.body);\n\n return Array.from(targets);\n}\n\nfunction useResolvedAppSidebarSide({\n containerRef,\n explicitDir,\n explicitSide,\n}: {\n containerRef: React.RefObject<HTMLDivElement | null>;\n explicitDir?: string;\n explicitSide?: AppSidebarSide;\n}): AppSidebarSide {\n const [detectedDirection, setDetectedDirection] =\n React.useState<AppSidebarDirection>(\n () => normalizeAppSidebarDirection(explicitDir) ?? 'ltr',\n );\n\n React.useEffect(() => {\n if (explicitSide) return;\n\n const normalizedExplicitDir = normalizeAppSidebarDirection(explicitDir);\n if (normalizedExplicitDir) {\n setDetectedDirection((current) =>\n current === normalizedExplicitDir ? current : normalizedExplicitDir,\n );\n return;\n }\n\n const container = containerRef.current;\n const win = container?.ownerDocument.defaultView;\n if (!container || !win) return;\n\n const detectDirection = () => {\n const nextDirection = getAppSidebarDirection(container);\n setDetectedDirection((current) =>\n current === nextDirection ? current : nextDirection,\n );\n };\n\n detectDirection();\n\n const Observer = win.MutationObserver;\n if (!Observer) return;\n\n const observer = new Observer(detectDirection);\n for (const target of getAppSidebarDirectionTargets(container)) {\n observer.observe(target, {\n attributes: true,\n attributeFilter: ['dir', 'class', 'style'],\n });\n }\n\n return () => observer.disconnect();\n }, [containerRef, explicitDir, explicitSide]);\n\n return explicitSide ?? getAppSidebarSideFromDirection(detectedDirection);\n}\n\n// ============================================\n// Sidebar Logo\n// ============================================\n\nexport interface AppSidebarLogoProps\n extends React.HTMLAttributes<HTMLDivElement> {\n /** Logo image or element */\n logo?: React.ReactNode;\n /** Icon to show when sidebar is compacted. Defaults to Humain logomark. */\n compactedLogo?: React.ReactNode;\n /** Subtext displayed below the logo (e.g., \"Dashboard\"). Hidden when collapsed. */\n subtext?: string;\n}\n\nconst DEFAULT_COMPACTED_LOGO = (\n <span className=\"flex size-9 items-center justify-center rounded-lg bg-primary text-primary-foreground\">\n <BrandIcon icon=\"mark\" size=\"sm\" />\n </span>\n);\n\nfunction AppSidebarLogo({\n logo,\n compactedLogo,\n subtext,\n className,\n ...props\n}: AppSidebarLogoProps) {\n const { state, toggleSidebar } = useSidebar();\n const isCollapsed = state === 'collapsed';\n const effectiveCompactedLogo = compactedLogo ?? DEFAULT_COMPACTED_LOGO;\n\n if (isCollapsed) {\n return (\n <div\n data-slot=\"app-sidebar-logo\"\n className={cn('flex items-center justify-center', className)}\n style={{ fontFamily: \"'Optician Sans', Inter, sans-serif\" }}\n {...props}\n dir=\"ltr\"\n >\n <button\n type=\"button\"\n onClick={toggleSidebar}\n className=\"group/logo relative flex size-[52px] items-center justify-center rounded-md p-2 transition-colors duration-200 ease-smooth hover:bg-sidebar-accent focus-visible:outline-2 focus-visible:outline-offset-2 focus-visible:outline-ring motion-reduce:transition-none\"\n aria-label=\"Expand sidebar\"\n >\n <span className=\"transition-opacity duration-200 ease-smooth group-hover/logo:opacity-0 motion-reduce:transition-none\">\n {effectiveCompactedLogo}\n </span>\n <PanelLeftOpen className=\"absolute size-5 opacity-0 transition-opacity duration-200 ease-smooth group-hover/logo:opacity-100 motion-reduce:transition-none\" />\n </button>\n </div>\n );\n }\n\n return (\n <div\n data-slot=\"app-sidebar-logo\"\n className={cn(\n 'flex h-[52px] items-center justify-between gap-2 rounded-md p-2',\n className,\n )}\n style={{ fontFamily: \"'Optician Sans', Inter, sans-serif\" }}\n {...props}\n dir=\"ltr\"\n >\n {logo ? (\n <div className=\"flex min-w-0 flex-col gap-0\">\n <div className=\"flex items-center\">{logo}</div>\n {subtext && (\n <p className=\"ps-11 text-sm text-sidebar-foreground\">\n <span data-slot=\"app-sidebar-logo-subtext\">{subtext}</span>\n </p>\n )}\n </div>\n ) : (\n <div className=\"flex min-w-0 items-center gap-2\">\n {DEFAULT_COMPACTED_LOGO}\n <div\n data-slot=\"app-sidebar-logo-text\"\n className=\"flex min-w-0 flex-col justify-center gap-0.5\"\n >\n <span\n data-slot=\"app-sidebar-logo-title\"\n className=\"text-lg font-semibold leading-tight tracking-tight text-foreground\"\n >\n HUMAIN\n </span>\n {subtext && (\n <span\n data-slot=\"app-sidebar-logo-subtext\"\n className=\"text-sm leading-none text-sidebar-foreground\"\n >\n {subtext}\n </span>\n )}\n </div>\n </div>\n )}\n <button\n type=\"button\"\n onClick={toggleSidebar}\n className=\"relative flex size-9 items-center justify-center rounded-lg text-sidebar-foreground transition-colors duration-200 ease-smooth hover:bg-sidebar-accent hover:text-foreground focus-visible:outline-2 focus-visible:outline-offset-2 focus-visible:outline-ring motion-reduce:transition-none after:absolute after:-inset-1\"\n aria-label=\"Collapse sidebar\"\n >\n <PanelLeftClose aria-hidden=\"true\" className=\"size-5\" />\n </button>\n </div>\n );\n}\n\nAppSidebarLogo.displayName = 'AppSidebar.Logo';\n\n// ============================================\n// Slot Components (Header, Content, Footer)\n// ============================================\n\nexport interface AppSidebarSlotProps {\n children?: React.ReactNode;\n className?: string;\n}\n\nfunction AppSidebarHeader({ children, className }: AppSidebarSlotProps) {\n return (\n <div data-slot=\"app-sidebar-header\" className={className}>\n {children}\n </div>\n );\n}\nAppSidebarHeader.displayName = 'AppSidebar.Header';\n\nfunction AppSidebarContent({ children, className }: AppSidebarSlotProps) {\n return (\n <div data-slot=\"app-sidebar-content\" className={className}>\n {children}\n </div>\n );\n}\nAppSidebarContent.displayName = 'AppSidebar.Content';\n\nfunction AppSidebarFooter({ children, className }: AppSidebarSlotProps) {\n return (\n <div data-slot=\"app-sidebar-footer\" className={className}>\n {children}\n </div>\n );\n}\nAppSidebarFooter.displayName = 'AppSidebar.Footer';\n\n// ============================================\n// Nav Component\n// ============================================\n\nexport interface AppSidebarNavProps {\n children?: React.ReactNode;\n /** Accessible label for the nav landmark (useful when multiple Nav instances exist) */\n 'aria-label'?: string;\n className?: string;\n}\n\nfunction AppSidebarNav({\n children,\n 'aria-label': ariaLabel = 'Sidebar navigation',\n className,\n}: AppSidebarNavProps) {\n const menuContent = (\n <SidebarMenu className=\"gap-0.5 group-data-[collapsible=icon]:items-center group-data-[collapsible=icon]:gap-1\">\n {React.Children.map(children, (child) => (\n <SidebarMenuItem>{child}</SidebarMenuItem>\n ))}\n </SidebarMenu>\n );\n\n return (\n <SidebarGroup\n data-slot=\"app-sidebar-nav\"\n className={cn(\n 'shrink-0 p-0 group-data-[collapsible=icon]:w-auto',\n className,\n )}\n >\n <SidebarGroupContent>\n <nav aria-label={ariaLabel}>{menuContent}</nav>\n </SidebarGroupContent>\n </SidebarGroup>\n );\n}\n\nAppSidebarNav.displayName = 'AppSidebar.Nav';\nmarkAppSidebarImplicitSlot(AppSidebarNav, 'content');\n\n// ============================================\n// Nav Section (Group Label / Divider)\n// ============================================\n\nexport interface AppSidebarNavSectionProps {\n /** Section label shown when sidebar is expanded */\n label: string;\n /** Additional className */\n className?: string;\n}\n\nfunction AppSidebarNavSection({ label, className }: AppSidebarNavSectionProps) {\n return (\n <div\n data-slot=\"app-sidebar-nav-section\"\n role=\"separator\"\n aria-label={label}\n className={cn('py-2 group-data-[collapsible=icon]:w-[52px]', className)}\n >\n <div className=\"flex h-8 items-center px-2 group-data-[collapsible=icon]:hidden\">\n <span className=\"text-xs font-medium text-sidebar-foreground/80\">\n {label}\n </span>\n </div>\n <div className=\"hidden py-2 group-data-[collapsible=icon]:block\">\n <span className=\"sr-only\">{label}</span>\n <Separator className=\"mx-auto w-full\" />\n </div>\n </div>\n );\n}\n\nAppSidebarNavSection.displayName = 'AppSidebar.NavSection';\n\n// ============================================\n// Nav Item Component\n// ============================================\n\nconst navItemVariants = cva(\n 'relative flex w-full items-center gap-1.5 rounded-lg px-2 py-2 text-sm font-normal transition-[color,background-color] duration-200 ease-smooth motion-reduce:transition-none',\n {\n variants: {\n state: {\n default: 'text-sidebar-foreground hover:bg-sidebar-accent',\n active: 'bg-primary/10 text-sidebar-foreground',\n },\n },\n defaultVariants: {\n state: 'default',\n },\n },\n);\n\nexport interface AppSidebarNavItemProps {\n icon: React.ReactNode;\n label: string;\n isActive?: boolean;\n badge?: string | number;\n onClick?: () => void;\n href?: string;\n className?: string;\n /** Sub-navigation children (AppSidebar.NavSub items). When present, renders as collapsible parent. */\n children?: React.ReactNode;\n}\n\nfunction AppSidebarNavItem({\n icon,\n label,\n isActive = false,\n badge,\n onClick,\n href,\n className,\n children,\n}: AppSidebarNavItemProps) {\n const { state, containerRef } = useSidebar();\n const { side: sidebarSide } = useAppSidebarLayout();\n const isCollapsed = state === 'collapsed';\n const hasChildren = React.Children.count(children) > 0;\n const hasActiveChild = React.Children.toArray(children).some(\n (child) =>\n React.isValidElement<{ isActive?: boolean }>(child) &&\n child.props.isActive === true,\n );\n const isHighlighted = isActive || hasActiveChild;\n const [isOpen, setIsOpen] = React.useState(isHighlighted && hasChildren);\n const subNavId = React.useId();\n const floatingSide = sidebarSide === 'right' ? 'left' : 'right';\n const flyoutPanelBackground =\n 'linear-gradient(108deg, var(--opacity-white-87) 0.5219%, var(--opacity-white-75) 98.419%)';\n const flyoutFrameEdgeClassName =\n sidebarSide === 'right'\n ? 'justify-end rounded-l-xl rounded-r-none'\n : 'justify-start rounded-r-xl rounded-l-none';\n const flyoutPanelEdgeClassName =\n sidebarSide === 'right' ? 'rounded-l-xl' : 'rounded-r-xl';\n const flyoutAnchor = React.useMemo(\n () => ({\n getBoundingClientRect: () => {\n const container = containerRef.current;\n const rect = container?.getBoundingClientRect();\n const win = container?.ownerDocument.defaultView;\n const viewportHeight = win?.innerHeight ?? rect?.height ?? 0;\n const x = rect ? (sidebarSide === 'right' ? rect.left : rect.right) : 0;\n\n return {\n x,\n y: 0,\n top: 0,\n right: x,\n bottom: viewportHeight,\n left: x,\n width: 0,\n height: viewportHeight,\n };\n },\n }),\n [containerRef, sidebarSide],\n );\n\n React.useEffect(() => {\n if (isHighlighted && hasChildren) setIsOpen(true);\n }, [isHighlighted, hasChildren]);\n\n const accessibleLabel = formatAccessibleLabel(label, badge);\n\n const iconElement = (\n <span\n data-slot=\"nav-icon\"\n className=\"flex shrink-0 items-center p-0.5 [&>svg]:size-4\"\n >\n {icon}\n </span>\n );\n\n const labelElement = (\n <span className=\"flex-1 text-start group-data-[collapsible=icon]:hidden\">\n {label}\n </span>\n );\n\n const badgeElement = badge != null && (\n <Badge\n size=\"sm\"\n variant=\"soft\"\n color=\"primary\"\n className=\"px-1.5 group-data-[collapsible=icon]:hidden\"\n aria-hidden=\"true\"\n >\n {badge}\n </Badge>\n );\n\n const chevronElement = hasChildren && (\n <ChevronRight\n aria-hidden=\"true\"\n className={cn(\n 'size-4 shrink-0 text-muted-foreground transition-transform duration-200 ease-smooth group-data-[collapsible=icon]:hidden motion-reduce:transition-none',\n isOpen ? 'rotate-90' : 'rtl:rotate-180',\n isHighlighted && isOpen && 'text-primary',\n )}\n />\n );\n\n const itemClassName = cn(\n navItemVariants({ state: isHighlighted ? 'active' : 'default' }),\n 'focus-visible:outline-2 focus-visible:outline-offset-2 focus-visible:outline-ring',\n 'min-h-11 group-data-[collapsible=icon]:justify-center group-data-[collapsible=icon]:px-0 group-data-[collapsible=icon]:py-2 group-data-[collapsible=icon]:w-11 group-data-[collapsible=icon]:h-11',\n className,\n );\n\n const ariaProps = isActive ? { 'aria-current': 'page' as const } : {};\n\n // --- Collapsed: icon-only with tooltip, flyout popover for children ---\n if (isCollapsed) {\n const collapsedIconElement = (\n <span\n data-slot=\"nav-icon\"\n className=\"flex shrink-0 items-center justify-center p-0.5 [&>svg]:size-4\"\n >\n {icon}\n </span>\n );\n\n const triggerElement = href ? (\n <a\n href={href}\n className={cn(itemClassName)}\n aria-label={accessibleLabel}\n {...ariaProps}\n data-slot=\"app-sidebar-nav-item\"\n >\n {collapsedIconElement}\n </a>\n ) : (\n <button\n type=\"button\"\n onClick={hasChildren ? () => setIsOpen(!isOpen) : onClick}\n className={cn(itemClassName, 'cursor-pointer')}\n aria-label={accessibleLabel}\n {...ariaProps}\n data-slot=\"app-sidebar-nav-item\"\n >\n {collapsedIconElement}\n </button>\n );\n\n if (!hasChildren) {\n if (!label) return triggerElement;\n return (\n <Tooltip>\n <TooltipTrigger render={triggerElement} />\n <TooltipPopup side={floatingSide} sideOffset={8}>\n {label}\n </TooltipPopup>\n </Tooltip>\n );\n }\n\n return (\n <PopoverRoot>\n <PopoverTrigger\n className={cn(itemClassName, 'cursor-pointer')}\n aria-label={accessibleLabel}\n data-slot=\"app-sidebar-nav-item\"\n >\n {collapsedIconElement}\n </PopoverTrigger>\n <PopoverPopup\n side={floatingSide}\n align=\"start\"\n sideOffset={0}\n alignOffset={0}\n anchor={flyoutAnchor}\n collisionAvoidance={{\n side: 'none',\n align: 'none',\n fallbackAxisSide: 'none',\n }}\n positionMethod=\"fixed\"\n aria-label={`${label} sub-navigation`}\n style={\n {\n '--app-sidebar-flyout-panel-bg': flyoutPanelBackground,\n } as React.CSSProperties\n }\n className={cn(\n 'flex h-[var(--anchor-height)] w-[276px] border-0 bg-transparent p-0 ring-0 shadow-none',\n 'overflow-clip',\n flyoutFrameEdgeClassName,\n )}\n >\n <div\n className={cn(\n 'flex h-full w-64 flex-col gap-0.5 overflow-y-auto p-3 shadow-[var(--shadow-hover-card)]',\n 'supports-backdrop-filter:backdrop-blur-[60px] [background-image:var(--app-sidebar-flyout-panel-bg)] delight-tooltip-stagger',\n flyoutPanelEdgeClassName,\n )}\n data-slot=\"app-sidebar-nav-flyout-panel\"\n role=\"group\"\n aria-label={label}\n >\n <p\n className=\"px-2 pb-2 pt-1 text-xs font-semibold text-primary opacity-70\"\n aria-hidden=\"true\"\n >\n {label}\n </p>\n {children}\n </div>\n </PopoverPopup>\n </PopoverRoot>\n );\n }\n\n // --- Expanded: full item with optional inline sub-nav ---\n const handleClick = () => {\n if (hasChildren) {\n setIsOpen(!isOpen);\n }\n onClick?.();\n };\n\n const mainElement =\n href && !hasChildren ? (\n <a\n href={href}\n className={itemClassName}\n aria-label={accessibleLabel}\n {...ariaProps}\n data-slot=\"app-sidebar-nav-item\"\n >\n {iconElement}\n {labelElement}\n {badgeElement}\n {chevronElement}\n </a>\n ) : (\n <button\n type=\"button\"\n onClick={handleClick}\n className={cn(itemClassName, 'cursor-pointer')}\n aria-label={accessibleLabel}\n aria-expanded={hasChildren ? isOpen : undefined}\n aria-controls={hasChildren ? subNavId : undefined}\n {...ariaProps}\n data-slot=\"app-sidebar-nav-item\"\n >\n {iconElement}\n {labelElement}\n {badgeElement}\n {chevronElement}\n </button>\n );\n\n if (!hasChildren) return mainElement;\n\n return (\n <>\n {mainElement}\n {isOpen && (\n <ul\n id={subNavId}\n role=\"group\"\n aria-label={`${label} sub-navigation`}\n className=\"ms-4 flex flex-col items-start border-s border-sidebar-border py-1 ps-2\"\n >\n {children}\n </ul>\n )}\n </>\n );\n}\n\nAppSidebarNavItem.displayName = 'AppSidebar.NavItem';\n\n// ============================================\n// Nav Sub Component\n// ============================================\n\nexport interface AppSidebarNavSubProps {\n label: string;\n badge?: string | number;\n isActive?: boolean;\n href?: string;\n onClick?: () => void;\n className?: string;\n}\n\nfunction AppSidebarNavSub({\n label,\n badge,\n isActive = false,\n href,\n onClick,\n className,\n}: AppSidebarNavSubProps) {\n const accessibleLabel = formatAccessibleLabel(label, badge);\n\n const itemClassName = cn(\n navItemVariants({ state: isActive ? 'active' : 'default' }),\n 'min-h-11 focus-visible:outline-2 focus-visible:outline-offset-2 focus-visible:outline-ring',\n 'transition-[color,background-color,transform] ltr:hover:translate-x-0.5 rtl:hover:-translate-x-0.5 motion-reduce:ltr:hover:translate-x-0 motion-reduce:rtl:hover:translate-x-0',\n className,\n );\n\n const ariaProps = isActive ? { 'aria-current': 'page' as const } : {};\n\n const content = (\n <>\n <span className=\"flex-1 text-start\">{label}</span>\n {badge != null && (\n <Badge\n size=\"sm\"\n variant=\"soft\"\n color=\"primary\"\n className=\"px-1.5\"\n aria-hidden=\"true\"\n >\n {badge}\n </Badge>\n )}\n </>\n );\n\n if (href) {\n return (\n <a\n href={href}\n className={itemClassName}\n aria-label={accessibleLabel}\n {...ariaProps}\n data-slot=\"app-sidebar-nav-sub\"\n >\n {content}\n </a>\n );\n }\n\n return (\n <button\n type=\"button\"\n onClick={onClick}\n className={cn(itemClassName, 'cursor-pointer delight-selection-press')}\n aria-label={accessibleLabel}\n {...ariaProps}\n data-slot=\"app-sidebar-nav-sub\"\n >\n {content}\n </button>\n );\n}\nAppSidebarNavSub.displayName = 'AppSidebar.NavSub';\n\n// ============================================\n// Nav Skeleton\n// ============================================\n\nexport interface AppSidebarNavSkeletonProps {\n /** Number of skeleton items to show */\n count?: number;\n className?: string;\n}\n\nfunction AppSidebarNavSkeleton({\n count = 3,\n className,\n}: AppSidebarNavSkeletonProps) {\n const skeletonCount = getSkeletonCount(count, 3);\n\n return (\n <SidebarGroup\n className={cn(\n 'shrink-0 p-0 group-data-[collapsible=icon]:w-auto',\n className,\n )}\n >\n <SidebarGroupContent>\n <SidebarMenu className=\"gap-0.5 group-data-[collapsible=icon]:items-center group-data-[collapsible=icon]:gap-2\">\n {Array.from({ length: skeletonCount }).map((_, i) => (\n <SidebarMenuItem key={`nav-skeleton-${i}`}>\n <SidebarNavSkeleton />\n </SidebarMenuItem>\n ))}\n </SidebarMenu>\n </SidebarGroupContent>\n </SidebarGroup>\n );\n}\n\nAppSidebarNavSkeleton.displayName = 'AppSidebar.NavSkeleton';\nmarkAppSidebarImplicitSlot(AppSidebarNavSkeleton, 'content');\n\n// ============================================\n// Chat List Component\n// ============================================\n\nexport interface AppSidebarChatListProps {\n /** Section label */\n label?: string;\n children?: React.ReactNode;\n className?: string;\n}\n\nfunction AppSidebarChatList({\n label = 'Recent Chats',\n children,\n className,\n}: AppSidebarChatListProps) {\n const { state } = useSidebar();\n const isCollapsed = state === 'collapsed';\n\n // Collapsed state doesn't show chat list\n if (isCollapsed) {\n return null;\n }\n\n return (\n <SidebarGroup\n data-slot=\"app-sidebar-chat-list\"\n className={cn('mt-4 flex min-h-0 flex-1 flex-col p-0', className)}\n >\n <SidebarGroupLabel className=\"shrink-0 px-3 py-1 text-xs font-bold text-muted-foreground\">\n {label}\n </SidebarGroupLabel>\n <SidebarGroupContent className=\"flex-1 overflow-hidden\">\n <div\n className=\"flex h-full flex-col overflow-y-auto pb-5 rounded-md focus-visible:outline-2 focus-visible:outline-offset-2 focus-visible:outline-ring\"\n tabIndex={0}\n role=\"list\"\n aria-label={label}\n >\n {children}\n </div>\n </SidebarGroupContent>\n </SidebarGroup>\n );\n}\n\nAppSidebarChatList.displayName = 'AppSidebar.ChatList';\nmarkAppSidebarImplicitSlot(AppSidebarChatList, 'content');\n\n// ============================================\n// Chat Item Component\n// ============================================\n\nconst chatItemVariants = cva(\n 'flex w-full items-center justify-between gap-2 rounded-md px-3 py-2 min-h-11 transition-[color,background-color,transform] duration-200 ease-smooth cursor-pointer motion-reduce:transition-none ltr:hover:translate-x-0.5 rtl:hover:-translate-x-0.5 motion-reduce:ltr:hover:translate-x-0 motion-reduce:rtl:hover:translate-x-0',\n {\n variants: {\n state: {\n default: 'hover:bg-muted',\n hover: 'bg-muted',\n selected: 'bg-primary/10',\n },\n },\n defaultVariants: {\n state: 'default',\n },\n },\n);\n\nexport interface AppSidebarChatItemProps\n extends VariantProps<typeof chatItemVariants> {\n /** Chat title */\n title: string;\n /** Time indicator (e.g., \"12h ago\") */\n time?: string;\n /** Icon for collapsed view (defaults to chat bubble) */\n icon?: React.ReactNode;\n /** Whether this chat is selected */\n isSelected?: boolean;\n /** Click handler */\n onClick?: () => void;\n /** Context menu handler (right-click) */\n onContextMenu?: (event: React.MouseEvent) => void;\n /** Additional className */\n className?: string;\n}\n\nfunction AppSidebarChatItem({\n title,\n time,\n icon,\n isSelected = false,\n onClick,\n onContextMenu,\n className,\n}: AppSidebarChatItemProps) {\n const { state } = useSidebar();\n const { side: sidebarSide } = useAppSidebarLayout();\n const isCollapsed = state === 'collapsed';\n const tooltipSide = sidebarSide === 'right' ? 'left' : 'right';\n\n if (isCollapsed) {\n const collapsedButton = (\n <button\n type=\"button\"\n onClick={onClick}\n onContextMenu={onContextMenu}\n data-slot=\"app-sidebar-chat-item\"\n aria-label={title || undefined}\n className={cn(\n 'flex size-11 items-center justify-center rounded-md transition-colors duration-200 ease-smooth motion-reduce:transition-none focus-visible:outline-2 focus-visible:outline-offset-2 focus-visible:outline-ring',\n isSelected ? 'bg-primary/10' : 'hover:bg-muted',\n className,\n )}\n >\n {icon || <MessageCircle className=\"size-5 text-secondary-foreground\" />}\n </button>\n );\n\n if (!title && !time) {\n return collapsedButton;\n }\n\n return (\n <Tooltip>\n <TooltipTrigger render={collapsedButton} />\n <TooltipPopup side={tooltipSide} sideOffset={8}>\n <div className=\"flex flex-col\">\n <span className=\"font-medium\">{title}</span>\n {time && (\n <span className=\"text-xs text-muted-foreground\">{time}</span>\n )}\n </div>\n </TooltipPopup>\n </Tooltip>\n );\n }\n\n return (\n <div role=\"listitem\">\n <button\n type=\"button\"\n onClick={onClick}\n onContextMenu={onContextMenu}\n data-slot=\"app-sidebar-chat-item\"\n aria-label={title}\n className={cn(\n chatItemVariants({ state: isSelected ? 'selected' : 'default' }),\n 'focus-visible:outline-2 focus-visible:outline-offset-2 focus-visible:outline-ring',\n className,\n )}\n >\n <span className=\"text-base font-semibold text-secondary-foreground truncate\">\n {title}\n </span>\n {time && (\n <span className=\"text-xs font-normal text-muted-foreground shrink-0\">\n {time}\n </span>\n )}\n </button>\n </div>\n );\n}\n\nAppSidebarChatItem.displayName = 'AppSidebar.ChatItem';\n\n// ============================================\n// Chat List Skeleton\n// ============================================\n\nexport interface AppSidebarChatListSkeletonProps {\n /** Number of skeleton items to show */\n count?: number;\n /** Section label */\n label?: string;\n className?: string;\n}\n\nfunction AppSidebarChatListSkeleton({\n count = 5,\n label = 'Recent Chats',\n className,\n}: AppSidebarChatListSkeletonProps) {\n const skeletonCount = getSkeletonCount(count, 5);\n\n return (\n <SidebarGroup\n className={cn(\n 'mt-4 flex min-h-0 flex-1 flex-col p-0 group-data-[collapsible=icon]:hidden',\n className,\n )}\n >\n <SidebarGroupLabel className=\"shrink-0 px-3 py-1 text-xs font-bold text-muted-foreground\">\n {label}\n </SidebarGroupLabel>\n <SidebarGroupContent className=\"flex-1 overflow-hidden\">\n <div className=\"flex h-full flex-col overflow-y-auto pb-5\">\n {Array.from({ length: skeletonCount }).map((_, i) => (\n <SidebarMenuSkeleton key={`chat-skeleton-${i}`} />\n ))}\n </div>\n </SidebarGroupContent>\n </SidebarGroup>\n );\n}\n\nAppSidebarChatListSkeleton.displayName = 'AppSidebar.ChatListSkeleton';\nmarkAppSidebarImplicitSlot(AppSidebarChatListSkeleton, 'content');\n\n// ============================================\n// Account Component\n// ============================================\n\nexport interface AppSidebarAccountProps\n extends React.HTMLAttributes<HTMLDivElement> {\n /** User's name */\n name: string;\n /** Subtitle text (e.g., email, role) */\n subtitle?: string;\n /** User's avatar URL */\n avatarSrc?: string;\n /** Whether user is online */\n isOnline?: boolean;\n /** Click handler for the expand button */\n onExpand?: () => void;\n}\n\nfunction AppSidebarAccount({\n name,\n subtitle,\n avatarSrc,\n isOnline = false,\n onExpand,\n className,\n}: AppSidebarAccountProps) {\n const { state } = useSidebar();\n const { side: sidebarSide } = useAppSidebarLayout();\n const isCollapsed = state === 'collapsed';\n const tooltipSide = sidebarSide === 'right' ? 'left' : 'right';\n\n if (isCollapsed) {\n const avatarButton = (\n <button\n type=\"button\"\n onClick={onExpand}\n data-slot=\"app-sidebar-account\"\n aria-label={name ? `${name} account menu` : 'Account menu'}\n aria-haspopup=\"true\"\n className={cn(\n 'flex min-h-11 min-w-11 items-center justify-center rounded-lg transition-opacity duration-200 ease-smooth hover:opacity-80 focus-visible:outline-2 focus-visible:outline-offset-2 focus-visible:outline-ring motion-reduce:transition-none',\n className,\n )}\n >\n <Avatar\n src={avatarSrc}\n alt={name}\n fallback={name}\n size=\"sm\"\n className=\"size-[42px]\"\n indicator={isOnline ? 'online' : undefined}\n />\n </button>\n );\n\n if (!name && !subtitle) return avatarButton;\n\n return (\n <Tooltip>\n <TooltipTrigger render={avatarButton} />\n <TooltipPopup side={tooltipSide} sideOffset={8}>\n <div className=\"flex flex-col\">\n {name && <span className=\"font-medium\">{name}</span>}\n {subtitle && (\n <span className=\"text-xs text-muted-foreground\">{subtitle}</span>\n )}\n </div>\n </TooltipPopup>\n </Tooltip>\n );\n }\n\n return (\n <button\n type=\"button\"\n onClick={onExpand}\n data-slot=\"app-sidebar-account\"\n aria-label={name ? `${name} account menu` : 'Account menu'}\n aria-haspopup=\"true\"\n className={cn(\n 'flex w-full items-center gap-1.5 rounded-lg px-1 py-2 transition-colors duration-200 ease-smooth hover:bg-sidebar-accent focus-visible:outline-2 focus-visible:outline-offset-2 focus-visible:outline-ring motion-reduce:transition-none',\n className,\n )}\n >\n <Avatar\n src={avatarSrc}\n alt={name}\n fallback={name}\n size=\"sm\"\n className=\"size-[42px]\"\n indicator={isOnline ? 'online' : undefined}\n />\n <div className=\"flex flex-1 flex-col items-start overflow-hidden\">\n <span className=\"w-full truncate text-start text-sm font-medium text-sidebar-foreground\">\n {name}\n </span>\n {subtitle && (\n <span className=\"w-full truncate text-start text-xs font-light text-sidebar-foreground\">\n {subtitle}\n </span>\n )}\n </div>\n </button>\n );\n}\n\nAppSidebarAccount.displayName = 'AppSidebar.Account';\nmarkAppSidebarImplicitSlot(AppSidebarAccount, 'footer');\n\n// ============================================\n// Account Skeleton\n// ============================================\n\nfunction AppSidebarAccountSkeleton({ className }: { className?: string }) {\n return <SidebarAccountSkeleton className={className} />;\n}\n\nAppSidebarAccountSkeleton.displayName = 'AppSidebar.AccountSkeleton';\nmarkAppSidebarImplicitSlot(AppSidebarAccountSkeleton, 'footer');\n\n// ============================================\n// Full Sidebar Skeleton\n// ============================================\n\nexport interface AppSidebarSkeletonProps {\n /** Number of nav skeleton items */\n navCount?: number;\n /** Number of chat skeleton items */\n chatCount?: number;\n /** Logo element */\n logo?: React.ReactNode;\n /** Icon to show when sidebar is compacted. Defaults to Humain logomark. */\n compactedLogo?: React.ReactNode;\n /** Collapsible mode */\n collapsible?: 'offcanvas' | 'icon' | 'none';\n /** Side of the screen */\n side?: 'left' | 'right';\n /** Whether to round sidebar corners */\n rounded?: boolean;\n /** Custom background color class for the sidebar (e.g., 'bg-card') */\n sidebarBgColor?: string;\n className?: string;\n}\n\nfunction AppSidebarSkeleton({\n navCount = 4,\n chatCount = 5,\n logo,\n compactedLogo,\n collapsible = 'icon',\n side,\n rounded = false,\n sidebarBgColor,\n className,\n}: AppSidebarSkeletonProps) {\n const { state, containerRef } = useSidebar();\n const isCollapsed = state === 'collapsed';\n const resolvedSide = useResolvedAppSidebarSide({\n containerRef,\n explicitSide: side,\n });\n\n const bgClass = getSidebarBgClass(isCollapsed, sidebarBgColor);\n\n return (\n <Sidebar\n collapsible={collapsible}\n side={resolvedSide}\n data-side={resolvedSide}\n width={APP_SIDEBAR_EXPANDED_WIDTH}\n collapsedWidth={APP_SIDEBAR_COLLAPSED_WIDTH}\n className={cn('bg-transparent', className)}\n >\n <div\n data-slot=\"app-sidebar-surface\"\n className={getSidebarSurfaceClass({\n isCollapsed,\n side: resolvedSide,\n rounded,\n backgroundClass: bgClass,\n })}\n >\n <SidebarHeader className=\"h-[68px] w-full p-2 group-data-[collapsible=icon]:p-0\">\n <AppSidebarLogo logo={logo} compactedLogo={compactedLogo} />\n </SidebarHeader>\n\n <SidebarContent className=\"flex w-full flex-col gap-0 overflow-hidden pt-3 group-data-[collapsible=icon]:items-center\">\n <AppSidebarNavSkeleton count={navCount} />\n <AppSidebarChatListSkeleton count={chatCount} />\n </SidebarContent>\n\n <SidebarFooter className=\"w-full gap-0 p-0 group-data-[collapsible=icon]:items-center\">\n <AppSidebarAccountSkeleton />\n </SidebarFooter>\n </div>\n </Sidebar>\n );\n}\n\nAppSidebarSkeleton.displayName = 'AppSidebar.Skeleton';\n\n// ============================================\n// Main App Sidebar\n// ============================================\n\nexport interface AppSidebarProps extends React.HTMLAttributes<HTMLDivElement> {\n /** Logo element or configuration */\n logo?: React.ReactNode;\n /** Icon to show when sidebar is compacted. Defaults to Humain logomark. */\n compactedLogo?: React.ReactNode;\n /** Subtext displayed below the logo (e.g., \"Dashboard\"). Hidden when collapsed. */\n logoSubtext?: string;\n /** Collapsible mode - 'icon' shows only icons when collapsed, 'none' disables collapsing */\n collapsible?: 'offcanvas' | 'icon' | 'none';\n /** Side of the screen. When omitted, resolves from the nearest DOM direction. */\n side?: 'left' | 'right';\n /** Whether to round sidebar corners */\n rounded?: boolean;\n /** Custom background color class for the sidebar (e.g., 'bg-card'). Defaults to the sidebar token when expanded, bg-transparent when collapsed. */\n sidebarBgColor?: string;\n /** Children (compound components) */\n children?: React.ReactNode;\n}\n\n/**\n * AppSidebar is a full-featured application sidebar with navigation, chat list, and account sections.\n * Supports collapsible modes with a unified logo toggle and loading skeletons.\n *\n * @llms Full-featured app sidebar with nav, chat list, account, collapsible modes\n * @example\n * ```tsx\n * <AppSidebar logo={<Logo />} collapsible=\"icon\">\n * <AppSidebar.Nav>\n * <AppSidebar.NavItem icon={<Home />} label=\"Home\" isActive />\n * </AppSidebar.Nav>\n * <AppSidebar.ChatList>\n * <AppSidebar.ChatItem title=\"Chat 1\" />\n * </AppSidebar.ChatList>\n * <AppSidebar.Account name=\"User\" subtitle=\"user@example.com\" />\n * </AppSidebar>\n * ```\n */\nfunction AppSidebarRoot({\n logo,\n compactedLogo,\n logoSubtext,\n collapsible = 'icon',\n side,\n rounded = false,\n sidebarBgColor,\n className,\n children,\n dir,\n ...props\n}: AppSidebarProps) {\n const { state, containerRef } = useSidebar();\n const isCollapsed = state === 'collapsed';\n const resolvedSide = useResolvedAppSidebarSide({\n containerRef,\n explicitDir: dir,\n explicitSide: side,\n });\n\n const bgClass = getSidebarBgClass(isCollapsed, sidebarBgColor);\n\n const slots = useSlotChildren(children);\n\n return (\n <AppSidebarLayoutContext.Provider value={{ side: resolvedSide }}>\n <Sidebar\n collapsible={collapsible}\n side={resolvedSide}\n data-side={resolvedSide}\n width={APP_SIDEBAR_EXPANDED_WIDTH}\n collapsedWidth={APP_SIDEBAR_COLLAPSED_WIDTH}\n dir={dir}\n className={cn('bg-transparent', className)}\n {...props}\n >\n <div\n data-slot=\"app-sidebar-surface\"\n className={getSidebarSurfaceClass({\n isCollapsed,\n side: resolvedSide,\n rounded,\n backgroundClass: bgClass,\n })}\n >\n <SidebarHeader className=\"h-[68px] w-full p-2 group-data-[collapsible=icon]:p-0\">\n <AppSidebarLogo\n logo={logo}\n compactedLogo={compactedLogo}\n subtext={logoSubtext}\n />\n </SidebarHeader>\n\n <SidebarContent className=\"flex w-full flex-col gap-0 overflow-hidden pt-3 group-data-[collapsible=icon]:items-center\">\n {slots.explicitContent\n ? (slots.explicitContent.props as AppSidebarSlotProps).children\n : slots.content}\n </SidebarContent>\n\n <SidebarFooter className=\"w-full gap-0 p-0 group-data-[collapsible=icon]:items-center\">\n {slots.explicitFooter\n ? (slots.explicitFooter.props as AppSidebarSlotProps).children\n : slots.footer}\n </SidebarFooter>\n </div>\n </Sidebar>\n </AppSidebarLayoutContext.Provider>\n );\n}\n\nAppSidebarRoot.displayName = 'AppSidebar';\n\n// ============================================\n// Compound Component Export\n// ============================================\n\nexport const AppSidebar = Object.assign(AppSidebarRoot, {\n Header: AppSidebarHeader,\n Content: AppSidebarContent,\n Footer: AppSidebarFooter,\n Nav: AppSidebarNav,\n NavSection: AppSidebarNavSection,\n NavItem: AppSidebarNavItem,\n NavSub: AppSidebarNavSub,\n NavSkeleton: AppSidebarNavSkeleton,\n ChatList: AppSidebarChatList,\n ChatItem: AppSidebarChatItem,\n ChatListSkeleton: AppSidebarChatListSkeleton,\n Account: AppSidebarAccount,\n AccountSkeleton: AppSidebarAccountSkeleton,\n Skeleton: AppSidebarSkeleton,\n});\n\n// ============================================\n// Type Exports\n// ============================================\n\n// Re-export mobile detection utilities for client use\nexport { MOBILE_BREAKPOINT, useIsMobile } from '@/hooks/use-mobile';\nexport {\n APP_SIDEBAR_COLLAPSED_WIDTH,\n APP_SIDEBAR_EXPANDED_WIDTH,\n} from './AppSidebar.constants';\nexport type {\n AppSidebarAccountProps as AccountProps,\n AppSidebarChatItemProps as ChatItemProps,\n AppSidebarChatListProps as ChatListProps,\n AppSidebarChatListSkeletonProps as ChatListSkeletonProps,\n AppSidebarNavItemProps as NavItemProps,\n AppSidebarNavProps as NavProps,\n AppSidebarNavSectionProps as NavSectionProps,\n AppSidebarNavSkeletonProps as NavSkeletonProps,\n AppSidebarNavSubProps as NavSubProps,\n AppSidebarSkeletonProps as SkeletonProps,\n AppSidebarSlotProps as SlotProps,\n};\n// Re-export sidebar primitives for custom compositions\nexport {\n chatItemVariants,\n navItemVariants,\n // Re-export base components for advanced usage\n Sidebar,\n SidebarAccountSkeleton,\n SidebarContent,\n SidebarFooter,\n SidebarGroup,\n SidebarGroupContent,\n SidebarGroupLabel,\n SidebarHeader,\n SidebarInset,\n SidebarMenu,\n SidebarMenuButton,\n SidebarMenuItem,\n SidebarMenuSkeleton,\n SidebarNavSkeleton,\n SidebarProvider,\n SidebarTrigger,\n useSidebar,\n};\n"],"mappings":";;;;;;;;;;;;;;;;;;;;;AAmDA,SAAS,sBACP,OACA,OACQ;CACR,IAAI,SAAS,MAAM,OAAO;CAC1B,OAAO,GAAG,MAAM,IAAI,OAAO,UAAU,WAAW,GAAG,MAAM,GAAG,UAAU,IAAI,SAAS,YAAY;AACjG;AAEA,SAAS,kBACP,aACA,gBACQ;CACR,OAAO,cACH,mBACC,kBAAkB;AACzB;AAEA,SAAS,uBAAuB,EAC9B,aACA,MACA,SACA,mBAMS;CACT,OAAO,GACL,uDACA,cACI,gBACA,CACE,+BACA,SAAS,SAAS,oBAAoB,eACxC,GACJ,iBACA,YAAY,SAAS,SAAS,iBAAiB,eACjD;AACF;AAEA,SAAS,iBAAiB,OAA2B,UAA0B;CAC7E,OAAO,OAAO,UAAU,YAAY,OAAO,SAAS,KAAK,KAAK,SAAS,IACnE,KAAK,MAAM,KAAK,IAChB;AACN;AAMA,IAAM,4BAA4B,OAAO,wBAAwB;AAajE,SAAS,2BACP,WACA,MAC6C;CAC7C,MAAM,mBAAmB;CAEzB,iBAAiB,6BAA6B;CAC9C,OAAO;AACT;AAEA,SAAS,kCACP,OAC0C;CAC1C,QACG,OAAO,UAAU,cACf,OAAO,UAAU,YAAY,UAAU,SAC1C,6BAA6B;AAEjC;AAEA,SAAS,0BACP,WACoC;CACpC,IAAI,kCAAkC,SAAS,GAC7C,OAAO,UAAU;CAGnB,IAAI,OAAO,cAAc,YAAY,cAAc,MAAM;EACvD,MAAM,mBAAmB;EACzB,OACE,0BAA0B,iBAAiB,IAAI,KAC/C,0BAA0B,iBAAiB,MAAM;CAErD;AAGF;AAWA,SAAS,gBAAgB,UAAuC;CAC9D,OAAO,QAAM,cAAc;EACzB,MAAM,SAAqB;GACzB,QAAQ,CAAC;GACT,SAAS,CAAC;GACV,QAAQ,CAAC;GACT,gBAAgB;GAChB,iBAAiB;GACjB,gBAAgB;EAClB;EAEA,QAAM,SAAS,QAAQ,WAAW,UAAU;GAC1C,IAAI,CAAC,QAAM,eAAe,KAAK,GAAG;GAElC,MAAM,YAAY,MAAM;GAGxB,IAAI,cAAc,kBAAkB;IAClC,OAAO,iBAAiB;IACxB;GACF;GACA,IAAI,cAAc,mBAAmB;IACnC,OAAO,kBAAkB;IACzB;GACF;GACA,IAAI,cAAc,kBAAkB;IAClC,OAAO,iBAAiB;IACxB;GACF;GAGA,MAAM,eAAe,0BAA0B,SAAS;GACxD,IAAI,iBAAiB,UACnB,OAAO,OAAO,KAAK,KAAK;QACnB,IAAI,iBAAiB,WAC1B,OAAO,QAAQ,KAAK,KAAK;QACpB,IAAI,iBAAiB,UAC1B,OAAO,OAAO,KAAK,KAAK;QAGxB,OAAO,QAAQ,KAAK,KAAK;EAE7B,CAAC;EAED,OAAO;CACT,GAAG,CAAC,QAAQ,CAAC;AACf;AAKA,IAAM,0BAA0B,QAAM,cAAwC,EAC5E,MAAM,OACR,CAAC;AAED,SAAS,sBAAsB;CAC7B,OAAO,QAAM,WAAW,uBAAuB;AACjD;AAEA,SAAS,uBACP,SACqB;CACrB,MAAM,MAAM,SAAS,cAAc;CACnC,IAAI,CAAC,WAAW,CAAC,KAAK,OAAO;CAC7B,OAAO,IAAI,iBAAiB,OAAO,CAAC,CAAC,cAAc,QAAQ,QAAQ;AACrE;AAEA,SAAS,6BACP,KACiC;CACjC,OAAO,QAAQ,SAAS,QAAQ,QAAQ,MAAM,KAAA;AAChD;AAEA,SAAS,+BACP,WACgB;CAChB,OAAO,cAAc,QAAQ,UAAU;AACzC;AAEA,SAAS,8BAA8B,SAAiC;CACtE,MAAM,0BAAU,IAAI,IAAa;CACjC,IAAI,UAA0B;CAE9B,OAAO,SAAS;EACd,QAAQ,IAAI,OAAO;EACnB,IAAI,YAAY,QAAQ,cAAc,iBAAiB;EACvD,UAAU,QAAQ;CACpB;CAEA,QAAQ,IAAI,QAAQ,cAAc,eAAe;CACjD,IAAI,QAAQ,cAAc,MAAM,QAAQ,IAAI,QAAQ,cAAc,IAAI;CAEtE,OAAO,MAAM,KAAK,OAAO;AAC3B;AAEA,SAAS,0BAA0B,EACjC,cACA,aACA,gBAKiB;CACjB,MAAM,CAAC,mBAAmB,wBACxB,QAAM,eACE,6BAA6B,WAAW,KAAK,KACrD;CAEF,QAAM,gBAAgB;EACpB,IAAI,cAAc;EAElB,MAAM,wBAAwB,6BAA6B,WAAW;EACtE,IAAI,uBAAuB;GACzB,sBAAsB,YACpB,YAAY,wBAAwB,UAAU,qBAChD;GACA;EACF;EAEA,MAAM,YAAY,aAAa;EAC/B,MAAM,MAAM,WAAW,cAAc;EACrC,IAAI,CAAC,aAAa,CAAC,KAAK;EAExB,MAAM,wBAAwB;GAC5B,MAAM,gBAAgB,uBAAuB,SAAS;GACtD,sBAAsB,YACpB,YAAY,gBAAgB,UAAU,aACxC;EACF;EAEA,gBAAgB;EAEhB,MAAM,WAAW,IAAI;EACrB,IAAI,CAAC,UAAU;EAEf,MAAM,WAAW,IAAI,SAAS,eAAe;EAC7C,KAAK,MAAM,UAAU,8BAA8B,SAAS,GAC1D,SAAS,QAAQ,QAAQ;GACvB,YAAY;GACZ,iBAAiB;IAAC;IAAO;IAAS;GAAO;EAC3C,CAAC;EAGH,aAAa,SAAS,WAAW;CACnC,GAAG;EAAC;EAAc;EAAa;CAAY,CAAC;CAE5C,OAAO,gBAAgB,+BAA+B,iBAAiB;AACzE;AAgBA,IAAM,yBACJ,oBAAC,QAAD;CAAM,WAAU;CACd,UAAA,oBAAC,WAAD;EAAW,MAAK;EAAO,MAAK;CAAM,CAAA;AAC9B,CAAA;AAGR,SAAS,eAAe,EACtB,MACA,eACA,SACA,WACA,GAAG,SACmB;CACtB,MAAM,EAAE,OAAO,kBAAkB,WAAW;CAC5C,MAAM,cAAc,UAAU;CAC9B,MAAM,yBAAyB,iBAAiB;CAEhD,IAAI,aACF,OACE,oBAAC,OAAD;EACE,aAAU;EACV,WAAW,GAAG,oCAAoC,SAAS;EAC3D,OAAO,EAAE,YAAY,qCAAqC;EAC1D,GAAI;EACJ,KAAI;EAEJ,UAAA,qBAAC,UAAD;GACE,MAAK;GACL,SAAS;GACT,WAAU;GACV,cAAW;GAJb,UAAA,CAME,oBAAC,QAAD;IAAM,WAAU;IACb,UAAA;GACG,CAAA,GACN,oBAAC,eAAD,EAAe,WAAU,mIAAoI,CAAA,CACvJ;;CACL,CAAA;CAIT,OACE,qBAAC,OAAD;EACE,aAAU;EACV,WAAW,GACT,mEACA,SACF;EACA,OAAO,EAAE,YAAY,qCAAqC;EAC1D,GAAI;EACJ,KAAI;EARN,UAAA,CAUG,OACC,qBAAC,OAAD;GAAK,WAAU;GAAf,UAAA,CACE,oBAAC,OAAD;IAAK,WAAU;IAAqB,UAAA;GAAU,CAAA,GAC7C,WACC,oBAAC,KAAD;IAAG,WAAU;IACX,UAAA,oBAAC,QAAD;KAAM,aAAU;KAA4B,UAAA;IAAc,CAAA;GACzD,CAAA,CAEF;EAEL,CAAA,IAAA,qBAAC,OAAD;GAAK,WAAU;GAAf,UAAA,CACG,wBACD,qBAAC,OAAD;IACE,aAAU;IACV,WAAU;IAFZ,UAAA,CAIE,oBAAC,QAAD;KACE,aAAU;KACV,WAAU;KACX,UAAA;IAEK,CAAA,GACL,WACC,oBAAC,QAAD;KACE,aAAU;KACV,WAAU;KAET,UAAA;IACG,CAAA,CAEL;GACF,CAAA,CAAA;EAEP,CAAA,GAAA,oBAAC,UAAD;GACE,MAAK;GACL,SAAS;GACT,WAAU;GACV,cAAW;GAEX,UAAA,oBAAC,gBAAD;IAAgB,eAAY;IAAO,WAAU;GAAU,CAAA;EACjD,CAAA,CACL;;AAET;AAEA,eAAe,cAAc;AAW7B,SAAS,iBAAiB,EAAE,UAAU,aAAkC;CACtE,OACE,oBAAC,OAAD;EAAK,aAAU;EAAgC;EAC5C;CACE,CAAA;AAET;AACA,iBAAiB,cAAc;AAE/B,SAAS,kBAAkB,EAAE,UAAU,aAAkC;CACvE,OACE,oBAAC,OAAD;EAAK,aAAU;EAAiC;EAC7C;CACE,CAAA;AAET;AACA,kBAAkB,cAAc;AAEhC,SAAS,iBAAiB,EAAE,UAAU,aAAkC;CACtE,OACE,oBAAC,OAAD;EAAK,aAAU;EAAgC;EAC5C;CACE,CAAA;AAET;AACA,iBAAiB,cAAc;AAa/B,SAAS,cAAc,EACrB,UACA,cAAc,YAAY,sBAC1B,aACqB;CACrB,MAAM,cACJ,oBAAC,aAAD;EAAa,WAAU;EACpB,UAAA,QAAM,SAAS,IAAI,WAAW,UAC7B,oBAAC,iBAAD,EAAA,UAAkB,MAAuB,CAAA,CAC1C;CACU,CAAA;CAGf,OACE,oBAAC,cAAD;EACE,aAAU;EACV,WAAW,GACT,qDACA,SACF;EAEA,UAAA,oBAAC,qBAAD,EAAA,UACE,oBAAC,OAAD;GAAK,cAAY;GAAY,UAAA;EAAiB,CAAA,EAC3B,CAAA;CACT,CAAA;AAElB;AAEA,cAAc,cAAc;AAC5B,2BAA2B,eAAe,SAAS;AAanD,SAAS,qBAAqB,EAAE,OAAO,aAAwC;CAC7E,OACE,qBAAC,OAAD;EACE,aAAU;EACV,MAAK;EACL,cAAY;EACZ,WAAW,GAAG,+CAA+C,SAAS;EAJxE,UAAA,CAME,oBAAC,OAAD;GAAK,WAAU;GACb,UAAA,oBAAC,QAAD;IAAM,WAAU;IACb,UAAA;GACG,CAAA;EACH,CAAA,GACL,qBAAC,OAAD;GAAK,WAAU;GAAf,UAAA,CACE,oBAAC,QAAD;IAAM,WAAU;IAAW,UAAA;GAAY,CAAA,GACvC,oBAAC,WAAD,EAAW,WAAU,iBAAkB,CAAA,CACpC;EACF,CAAA,CAAA;;AAET;AAEA,qBAAqB,cAAc;AAMnC,IAAM,kBAAkB,IACtB,iLACA;CACE,UAAU,EACR,OAAO;EACL,SAAS;EACT,QAAQ;CACV,EACF;CACA,iBAAiB,EACf,OAAO,UACT;AACF,CACF;AAcA,SAAS,kBAAkB,EACzB,MACA,OACA,WAAW,OACX,OACA,SACA,MACA,WACA,YACyB;CACzB,MAAM,EAAE,OAAO,iBAAiB,WAAW;CAC3C,MAAM,EAAE,MAAM,gBAAgB,oBAAoB;CAClD,MAAM,cAAc,UAAU;CAC9B,MAAM,cAAc,QAAM,SAAS,MAAM,QAAQ,IAAI;CACrD,MAAM,iBAAiB,QAAM,SAAS,QAAQ,QAAQ,CAAC,CAAC,MACrD,UACC,QAAM,eAAuC,KAAK,KAClD,MAAM,MAAM,aAAa,IAC7B;CACA,MAAM,gBAAgB,YAAY;CAClC,MAAM,CAAC,QAAQ,aAAa,QAAM,SAAS,iBAAiB,WAAW;CACvE,MAAM,WAAW,QAAM,MAAM;CAC7B,MAAM,eAAe,gBAAgB,UAAU,SAAS;CACxD,MAAM,wBACJ;CACF,MAAM,2BACJ,gBAAgB,UACZ,4CACA;CACN,MAAM,2BACJ,gBAAgB,UAAU,iBAAiB;CAC7C,MAAM,eAAe,QAAM,eAClB,EACL,6BAA6B;EAC3B,MAAM,YAAY,aAAa;EAC/B,MAAM,OAAO,WAAW,sBAAsB;EAE9C,MAAM,kBADM,WAAW,cAAc,YAAA,EACT,eAAe,MAAM,UAAU;EAC3D,MAAM,IAAI,OAAQ,gBAAgB,UAAU,KAAK,OAAO,KAAK,QAAS;EAEtE,OAAO;GACL;GACA,GAAG;GACH,KAAK;GACL,OAAO;GACP,QAAQ;GACR,MAAM;GACN,OAAO;GACP,QAAQ;EACV;CACF,EACF,IACA,CAAC,cAAc,WAAW,CAC5B;CAEA,QAAM,gBAAgB;EACpB,IAAI,iBAAiB,aAAa,UAAU,IAAI;CAClD,GAAG,CAAC,eAAe,WAAW,CAAC;CAE/B,MAAM,kBAAkB,sBAAsB,OAAO,KAAK;CAE1D,MAAM,cACJ,oBAAC,QAAD;EACE,aAAU;EACV,WAAU;EAET,UAAA;CACG,CAAA;CAGR,MAAM,eACJ,oBAAC,QAAD;EAAM,WAAU;EACb,UAAA;CACG,CAAA;CAGR,MAAM,eAAe,SAAS,QAC5B,oBAAC,OAAD;EACE,MAAK;EACL,SAAQ;EACR,OAAM;EACN,WAAU;EACV,eAAY;EAEX,UAAA;CACI,CAAA;CAGT,MAAM,iBAAiB,eACrB,oBAAC,cAAD;EACE,eAAY;EACZ,WAAW,GACT,0JACA,SAAS,cAAc,kBACvB,iBAAiB,UAAU,cAC7B;CACD,CAAA;CAGH,MAAM,gBAAgB,GACpB,gBAAgB,EAAE,OAAO,gBAAgB,WAAW,UAAU,CAAC,GAC/D,qFACA,qMACA,SACF;CAEA,MAAM,YAAY,WAAW,EAAE,gBAAgB,OAAgB,IAAI,CAAC;CAGpE,IAAI,aAAa;EACf,MAAM,uBACJ,oBAAC,QAAD;GACE,aAAU;GACV,WAAU;GAET,UAAA;EACG,CAAA;EAGR,MAAM,iBAAiB,OACrB,oBAAC,KAAD;GACQ;GACN,WAAW,GAAG,aAAa;GAC3B,cAAY;GACZ,GAAI;GACJ,aAAU;GAET,UAAA;EACA,CAAA,IAEH,oBAAC,UAAD;GACE,MAAK;GACL,SAAS,oBAAoB,UAAU,CAAC,MAAM,IAAI;GAClD,WAAW,GAAG,eAAe,gBAAgB;GAC7C,cAAY;GACZ,GAAI;GACJ,aAAU;GAET,UAAA;EACK,CAAA;EAGV,IAAI,CAAC,aAAa;GAChB,IAAI,CAAC,OAAO,OAAO;GACnB,OACE,qBAAC,SAAD,EAAA,UAAA,CACE,oBAAC,gBAAD,EAAgB,QAAQ,eAAiB,CAAA,GACzC,oBAAC,cAAD;IAAc,MAAM;IAAc,YAAY;IAC3C,UAAA;GACW,CAAA,CACP,EAAA,CAAA;EAEb;EAEA,OACE,qBAAC,aAAD,EAAA,UAAA,CACE,oBAAC,gBAAD;GACE,WAAW,GAAG,eAAe,gBAAgB;GAC7C,cAAY;GACZ,aAAU;GAET,UAAA;EACa,CAAA,GAChB,oBAAC,cAAD;GACE,MAAM;GACN,OAAM;GACN,YAAY;GACZ,aAAa;GACb,QAAQ;GACR,oBAAoB;IAClB,MAAM;IACN,OAAO;IACP,kBAAkB;GACpB;GACA,gBAAe;GACf,cAAY,GAAG,MAAM;GACrB,OACE,EACE,iCAAiC,sBACnC;GAEF,WAAW,GACT,0FACA,iBACA,wBACF;GAEA,UAAA,qBAAC,OAAD;IACE,WAAW,GACT,2FACA,+HACA,wBACF;IACA,aAAU;IACV,MAAK;IACL,cAAY;IARd,UAAA,CAUE,oBAAC,KAAD;KACE,WAAU;KACV,eAAY;KAEX,UAAA;IACA,CAAA,GACF,QACE;;EACO,CAAA,CACH,EAAA,CAAA;CAEjB;CAGA,MAAM,oBAAoB;EACxB,IAAI,aACF,UAAU,CAAC,MAAM;EAEnB,UAAU;CACZ;CAEA,MAAM,cACJ,QAAQ,CAAC,cACP,qBAAC,KAAD;EACQ;EACN,WAAW;EACX,cAAY;EACZ,GAAI;EACJ,aAAU;EALZ,UAAA;GAOG;GACA;GACA;GACA;EACA;CAEH,CAAA,IAAA,qBAAC,UAAD;EACE,MAAK;EACL,SAAS;EACT,WAAW,GAAG,eAAe,gBAAgB;EAC7C,cAAY;EACZ,iBAAe,cAAc,SAAS,KAAA;EACtC,iBAAe,cAAc,WAAW,KAAA;EACxC,GAAI;EACJ,aAAU;EARZ,UAAA;GAUG;GACA;GACA;GACA;EACK;;CAGZ,IAAI,CAAC,aAAa,OAAO;CAEzB,OACE,qBAAA,UAAA,EAAA,UAAA,CACG,aACA,UACC,oBAAC,MAAD;EACE,IAAI;EACJ,MAAK;EACL,cAAY,GAAG,MAAM;EACrB,WAAU;EAET;CACC,CAAA,CAEN,EAAA,CAAA;AAEN;AAEA,kBAAkB,cAAc;AAehC,SAAS,iBAAiB,EACxB,OACA,OACA,WAAW,OACX,MACA,SACA,aACwB;CACxB,MAAM,kBAAkB,sBAAsB,OAAO,KAAK;CAE1D,MAAM,gBAAgB,GACpB,gBAAgB,EAAE,OAAO,WAAW,WAAW,UAAU,CAAC,GAC1D,8FACA,kLACA,SACF;CAEA,MAAM,YAAY,WAAW,EAAE,gBAAgB,OAAgB,IAAI,CAAC;CAEpE,MAAM,UACJ,qBAAA,UAAA,EAAA,UAAA,CACE,oBAAC,QAAD;EAAM,WAAU;EAAqB,UAAA;CAAY,CAAA,GAChD,SAAS,QACR,oBAAC,OAAD;EACE,MAAK;EACL,SAAQ;EACR,OAAM;EACN,WAAU;EACV,eAAY;EAEX,UAAA;CACI,CAAA,CAET,EAAA,CAAA;CAGJ,IAAI,MACF,OACE,oBAAC,KAAD;EACQ;EACN,WAAW;EACX,cAAY;EACZ,GAAI;EACJ,aAAU;EAET,UAAA;CACA,CAAA;CAIP,OACE,oBAAC,UAAD;EACE,MAAK;EACI;EACT,WAAW,GAAG,eAAe,wCAAwC;EACrE,cAAY;EACZ,GAAI;EACJ,aAAU;EAET,UAAA;CACK,CAAA;AAEZ;AACA,iBAAiB,cAAc;AAY/B,SAAS,sBAAsB,EAC7B,QAAQ,GACR,aAC6B;CAC7B,MAAM,gBAAgB,iBAAiB,OAAO,CAAC;CAE/C,OACE,oBAAC,cAAD;EACE,WAAW,GACT,qDACA,SACF;EAEA,UAAA,oBAAC,qBAAD,EAAA,UACE,oBAAC,aAAD;GAAa,WAAU;GACpB,UAAA,MAAM,KAAK,EAAE,QAAQ,cAAc,CAAC,CAAC,CAAC,KAAK,GAAG,MAC7C,oBAAC,iBAAD,EAAA,UACE,oBAAC,oBAAD,CAAqB,CAAA,EACN,GAFK,gBAAgB,GAErB,CAClB;EACU,CAAA,EACM,CAAA;CACT,CAAA;AAElB;AAEA,sBAAsB,cAAc;AACpC,2BAA2B,uBAAuB,SAAS;AAa3D,SAAS,mBAAmB,EAC1B,QAAQ,gBACR,UACA,aAC0B;CAC1B,MAAM,EAAE,UAAU,WAAW;CAI7B,IAHoB,UAAU,aAI5B,OAAO;CAGT,OACE,qBAAC,cAAD;EACE,aAAU;EACV,WAAW,GAAG,yCAAyC,SAAS;EAFlE,UAAA,CAIE,oBAAC,mBAAD;GAAmB,WAAU;GAC1B,UAAA;EACgB,CAAA,GACnB,oBAAC,qBAAD;GAAqB,WAAU;GAC7B,UAAA,oBAAC,OAAD;IACE,WAAU;IACV,UAAU;IACV,MAAK;IACL,cAAY;IAEX;GACE,CAAA;EACc,CAAA,CACT;;AAElB;AAEA,mBAAmB,cAAc;AACjC,2BAA2B,oBAAoB,SAAS;AAMxD,IAAM,mBAAmB,IACvB,qUACA;CACE,UAAU,EACR,OAAO;EACL,SAAS;EACT,OAAO;EACP,UAAU;CACZ,EACF;CACA,iBAAiB,EACf,OAAO,UACT;AACF,CACF;AAoBA,SAAS,mBAAmB,EAC1B,OACA,MACA,MACA,aAAa,OACb,SACA,eACA,aAC0B;CAC1B,MAAM,EAAE,UAAU,WAAW;CAC7B,MAAM,EAAE,MAAM,gBAAgB,oBAAoB;CAClD,MAAM,cAAc,UAAU;CAC9B,MAAM,cAAc,gBAAgB,UAAU,SAAS;CAEvD,IAAI,aAAa;EACf,MAAM,kBACJ,oBAAC,UAAD;GACE,MAAK;GACI;GACM;GACf,aAAU;GACV,cAAY,SAAS,KAAA;GACrB,WAAW,GACT,kNACA,aAAa,kBAAkB,kBAC/B,SACF;GAEC,UAAA,QAAQ,oBAAC,eAAD,EAAe,WAAU,mCAAoC,CAAA;EAChE,CAAA;EAGV,IAAI,CAAC,SAAS,CAAC,MACb,OAAO;EAGT,OACE,qBAAC,SAAD,EAAA,UAAA,CACE,oBAAC,gBAAD,EAAgB,QAAQ,gBAAkB,CAAA,GAC1C,oBAAC,cAAD;GAAc,MAAM;GAAa,YAAY;GAC3C,UAAA,qBAAC,OAAD;IAAK,WAAU;IAAf,UAAA,CACE,oBAAC,QAAD;KAAM,WAAU;KAAe,UAAA;IAAY,CAAA,GAC1C,QACC,oBAAC,QAAD;KAAM,WAAU;KAAiC,UAAA;IAAW,CAAA,CAE3D;;EACO,CAAA,CACP,EAAA,CAAA;CAEb;CAEA,OACE,oBAAC,OAAD;EAAK,MAAK;EACR,UAAA,qBAAC,UAAD;GACE,MAAK;GACI;GACM;GACf,aAAU;GACV,cAAY;GACZ,WAAW,GACT,iBAAiB,EAAE,OAAO,aAAa,aAAa,UAAU,CAAC,GAC/D,qFACA,SACF;GAVF,UAAA,CAYE,oBAAC,QAAD;IAAM,WAAU;IACb,UAAA;GACG,CAAA,GACL,QACC,oBAAC,QAAD;IAAM,WAAU;IACb,UAAA;GACG,CAAA,CAEF;;CACL,CAAA;AAET;AAEA,mBAAmB,cAAc;AAcjC,SAAS,2BAA2B,EAClC,QAAQ,GACR,QAAQ,gBACR,aACkC;CAClC,MAAM,gBAAgB,iBAAiB,OAAO,CAAC;CAE/C,OACE,qBAAC,cAAD;EACE,WAAW,GACT,8EACA,SACF;EAJF,UAAA,CAME,oBAAC,mBAAD;GAAmB,WAAU;GAC1B,UAAA;EACgB,CAAA,GACnB,oBAAC,qBAAD;GAAqB,WAAU;GAC7B,UAAA,oBAAC,OAAD;IAAK,WAAU;IACZ,UAAA,MAAM,KAAK,EAAE,QAAQ,cAAc,CAAC,CAAC,CAAC,KAAK,GAAG,MAC7C,oBAAC,qBAAD,CAAiD,GAAvB,iBAAiB,GAAM,CAClD;GACE,CAAA;EACc,CAAA,CACT;;AAElB;AAEA,2BAA2B,cAAc;AACzC,2BAA2B,4BAA4B,SAAS;AAoBhE,SAAS,kBAAkB,EACzB,MACA,UACA,WACA,WAAW,OACX,UACA,aACyB;CACzB,MAAM,EAAE,UAAU,WAAW;CAC7B,MAAM,EAAE,MAAM,gBAAgB,oBAAoB;CAClD,MAAM,cAAc,UAAU;CAC9B,MAAM,cAAc,gBAAgB,UAAU,SAAS;CAEvD,IAAI,aAAa;EACf,MAAM,eACJ,oBAAC,UAAD;GACE,MAAK;GACL,SAAS;GACT,aAAU;GACV,cAAY,OAAO,GAAG,KAAK,iBAAiB;GAC5C,iBAAc;GACd,WAAW,GACT,8OACA,SACF;GAEA,UAAA,oBAAC,QAAD;IACE,KAAK;IACL,KAAK;IACL,UAAU;IACV,MAAK;IACL,WAAU;IACV,WAAW,WAAW,WAAW,KAAA;GAClC,CAAA;EACK,CAAA;EAGV,IAAI,CAAC,QAAQ,CAAC,UAAU,OAAO;EAE/B,OACE,qBAAC,SAAD,EAAA,UAAA,CACE,oBAAC,gBAAD,EAAgB,QAAQ,aAAe,CAAA,GACvC,oBAAC,cAAD;GAAc,MAAM;GAAa,YAAY;GAC3C,UAAA,qBAAC,OAAD;IAAK,WAAU;IAAf,UAAA,CACG,QAAQ,oBAAC,QAAD;KAAM,WAAU;KAAe,UAAA;IAAW,CAAA,GAClD,YACC,oBAAC,QAAD;KAAM,WAAU;KAAiC,UAAA;IAAe,CAAA,CAE/D;;EACO,CAAA,CACP,EAAA,CAAA;CAEb;CAEA,OACE,qBAAC,UAAD;EACE,MAAK;EACL,SAAS;EACT,aAAU;EACV,cAAY,OAAO,GAAG,KAAK,iBAAiB;EAC5C,iBAAc;EACd,WAAW,GACT,4OACA,SACF;EATF,UAAA,CAWE,oBAAC,QAAD;GACE,KAAK;GACL,KAAK;GACL,UAAU;GACV,MAAK;GACL,WAAU;GACV,WAAW,WAAW,WAAW,KAAA;EAClC,CAAA,GACD,qBAAC,OAAD;GAAK,WAAU;GAAf,UAAA,CACE,oBAAC,QAAD;IAAM,WAAU;IACb,UAAA;GACG,CAAA,GACL,YACC,oBAAC,QAAD;IAAM,WAAU;IACb,UAAA;GACG,CAAA,CAEL;EACC,CAAA,CAAA;;AAEZ;AAEA,kBAAkB,cAAc;AAChC,2BAA2B,mBAAmB,QAAQ;AAMtD,SAAS,0BAA0B,EAAE,aAAqC;CACxE,OAAO,oBAAC,wBAAD,EAAmC,UAAY,CAAA;AACxD;AAEA,0BAA0B,cAAc;AACxC,2BAA2B,2BAA2B,QAAQ;AA0B9D,SAAS,mBAAmB,EAC1B,WAAW,GACX,YAAY,GACZ,MACA,eACA,cAAc,QACd,MACA,UAAU,OACV,gBACA,aAC0B;CAC1B,MAAM,EAAE,OAAO,iBAAiB,WAAW;CAC3C,MAAM,cAAc,UAAU;CAC9B,MAAM,eAAe,0BAA0B;EAC7C;EACA,cAAc;CAChB,CAAC;CAED,MAAM,UAAU,kBAAkB,aAAa,cAAc;CAE7D,OACE,oBAAC,iBAAD;EACe;EACb,MAAM;EACN,aAAW;EACX,OAAO;EACP,gBAAgB;EAChB,WAAW,GAAG,kBAAkB,SAAS;EAEzC,UAAA,qBAAC,OAAD;GACE,aAAU;GACV,WAAW,uBAAuB;IAChC;IACA,MAAM;IACN;IACA,iBAAiB;GACnB,CAAC;GAPH,UAAA;IASE,oBAAC,eAAD;KAAe,WAAU;KACvB,UAAA,oBAAC,gBAAD;MAAsB;MAAqB;KAAgB,CAAA;IAC9C,CAAA;IAEf,qBAAC,gBAAD;KAAgB,WAAU;KAA1B,UAAA,CACE,oBAAC,uBAAD,EAAuB,OAAO,SAAW,CAAA,GACzC,oBAAC,4BAAD,EAA4B,OAAO,UAAY,CAAA,CACjC;;IAEhB,oBAAC,eAAD;KAAe,WAAU;KACvB,UAAA,oBAAC,2BAAD,CAA4B,CAAA;IACf,CAAA;GACZ;;CACE,CAAA;AAEb;AAEA,mBAAmB,cAAc;;;;;;;;;;;;;;;;;;;AA2CjC,SAAS,eAAe,EACtB,MACA,eACA,aACA,cAAc,QACd,MACA,UAAU,OACV,gBACA,WACA,UACA,KACA,GAAG,SACe;CAClB,MAAM,EAAE,OAAO,iBAAiB,WAAW;CAC3C,MAAM,cAAc,UAAU;CAC9B,MAAM,eAAe,0BAA0B;EAC7C;EACA,aAAa;EACb,cAAc;CAChB,CAAC;CAED,MAAM,UAAU,kBAAkB,aAAa,cAAc;CAE7D,MAAM,QAAQ,gBAAgB,QAAQ;CAEtC,OACE,oBAAC,wBAAwB,UAAzB;EAAkC,OAAO,EAAE,MAAM,aAAa;EAC5D,UAAA,oBAAC,iBAAD;GACe;GACb,MAAM;GACN,aAAW;GACX,OAAO;GACP,gBAAgB;GACX;GACL,WAAW,GAAG,kBAAkB,SAAS;GACzC,GAAI;GAEJ,UAAA,qBAAC,OAAD;IACE,aAAU;IACV,WAAW,uBAAuB;KAChC;KACA,MAAM;KACN;KACA,iBAAiB;IACnB,CAAC;IAPH,UAAA;KASE,oBAAC,eAAD;MAAe,WAAU;MACvB,UAAA,oBAAC,gBAAD;OACQ;OACS;OACf,SAAS;MACV,CAAA;KACY,CAAA;KAEf,oBAAC,gBAAD;MAAgB,WAAU;MACvB,UAAA,MAAM,kBACF,MAAM,gBAAgB,MAA8B,WACrD,MAAM;KACI,CAAA;KAEhB,oBAAC,eAAD;MAAe,WAAU;MACtB,UAAA,MAAM,iBACF,MAAM,eAAe,MAA8B,WACpD,MAAM;KACG,CAAA;IACZ;;EACE,CAAA;CACuB,CAAA;AAEtC;AAEA,eAAe,cAAc;AAM7B,IAAa,aAAa,OAAO,OAAO,gBAAgB;CACtD,QAAQ;CACR,SAAS;CACT,QAAQ;CACR,KAAK;CACL,YAAY;CACZ,SAAS;CACT,QAAQ;CACR,aAAa;CACb,UAAU;CACV,UAAU;CACV,kBAAkB;CAClB,SAAS;CACT,iBAAiB;CACjB,UAAU;AACZ,CAAC"}
|
|
1
|
+
{"version":3,"file":"index225.js","names":[],"sources":["../src/components/templates/AppSidebar/AppSidebar.tsx"],"sourcesContent":["/** biome-ignore-all lint/a11y/noNoninteractiveTabindex: ChatList uses tabIndex on scrollable div for keyboard scrolling */\n/** biome-ignore-all lint/a11y/useSemanticElements: NavSection uses role=\"separator\" on inner <div>; ChatList uses role=\"list\" on scrollable div */\n/** biome-ignore-all lint/a11y/useFocusableInteractive: Non-focusable separator per WAI-ARIA spec for decorative separators */\n/** biome-ignore-all lint/a11y/useAriaPropsForRole: Non-focusable separators don't require aria-valuenow per WAI-ARIA spec */\n/** biome-ignore-all lint/a11y/noNoninteractiveElementToInteractiveRole: role=\"separator\" on <div> inside list items for semantic section boundaries */\n\n'use client';\n\nimport { cva, type VariantProps } from 'class-variance-authority';\nimport {\n ChevronRight,\n MessageCircle,\n PanelLeftClose,\n PanelLeftOpen,\n} from 'lucide-react';\nimport * as React from 'react';\nimport { Badge } from '@/components/atoms/display/Badge';\nimport { Separator } from '@/components/atoms/layout/Separator';\nimport { Avatar } from '@/components/molecules/data/Avatar';\nimport { BrandIcon } from '@/components/molecules/data/BrandIcon';\nimport {\n PopoverPopup,\n PopoverRoot,\n PopoverTrigger,\n} from '@/components/organisms/overlays/Popover';\nimport {\n Sidebar,\n SidebarAccountSkeleton,\n SidebarContent,\n SidebarFooter,\n SidebarGroup,\n SidebarGroupContent,\n SidebarGroupLabel,\n SidebarHeader,\n SidebarInset,\n SidebarMenu,\n SidebarMenuButton,\n SidebarMenuItem,\n SidebarMenuSkeleton,\n SidebarNavSkeleton,\n SidebarProvider,\n SidebarTrigger,\n useSidebar,\n} from '@/components/ui/sidebar';\nimport { Tooltip, TooltipPopup, TooltipTrigger } from '@/components/ui/tooltip';\nimport { cn } from '@/lib/utils';\nimport {\n APP_SIDEBAR_COLLAPSED_WIDTH,\n APP_SIDEBAR_EXPANDED_WIDTH,\n} from './AppSidebar.constants';\n\nfunction formatAccessibleLabel(\n label: string,\n badge?: string | number | null,\n): string {\n if (badge == null) return label;\n return `${label}, ${typeof badge === 'number' ? `${badge} ${badge === 1 ? 'item' : 'items'}` : badge}`;\n}\n\nfunction getSidebarBgClass(\n isCollapsed: boolean,\n sidebarBgColor?: string,\n): string {\n return isCollapsed\n ? 'bg-transparent'\n : (sidebarBgColor ?? 'bg-[var(--sidebar)]');\n}\n\nfunction getSidebarSurfaceClass({\n isCollapsed,\n side,\n rounded,\n backgroundClass,\n}: {\n isCollapsed: boolean;\n side: AppSidebarSide;\n rounded: boolean;\n backgroundClass: string;\n}): string {\n return cn(\n 'flex h-full min-h-0 flex-col items-center pb-4 pt-6',\n isCollapsed\n ? 'w-full px-2'\n : [\n 'w-[calc(100%-0.75rem)] px-3',\n side === 'left' ? 'mr-3 self-start' : 'ml-3 self-end',\n ],\n backgroundClass,\n rounded && (side === 'left' ? 'rounded-r-lg' : 'rounded-l-lg'),\n );\n}\n\nfunction getSkeletonCount(count: number | undefined, fallback: number): number {\n return typeof count === 'number' && Number.isFinite(count) && count >= 0\n ? Math.floor(count)\n : fallback;\n}\n\n// ============================================\n// Slot Distribution Hook\n// ============================================\n\nconst APP_SIDEBAR_IMPLICIT_SLOT = Symbol('AppSidebarImplicitSlot');\n\ntype AppSidebarImplicitSlot = 'header' | 'content' | 'footer';\n\ninterface AppSidebarImplicitSlotComponent {\n [APP_SIDEBAR_IMPLICIT_SLOT]: AppSidebarImplicitSlot;\n}\n\ninterface AppSidebarWrappedComponent {\n type?: unknown;\n render?: unknown;\n}\n\nfunction markAppSidebarImplicitSlot<Component extends object>(\n component: Component,\n slot: AppSidebarImplicitSlot,\n): Component & AppSidebarImplicitSlotComponent {\n const slottedComponent = component as Component &\n AppSidebarImplicitSlotComponent;\n slottedComponent[APP_SIDEBAR_IMPLICIT_SLOT] = slot;\n return slottedComponent;\n}\n\nfunction isAppSidebarImplicitSlotComponent(\n value: unknown,\n): value is AppSidebarImplicitSlotComponent {\n return (\n (typeof value === 'function' ||\n (typeof value === 'object' && value !== null)) &&\n APP_SIDEBAR_IMPLICIT_SLOT in value\n );\n}\n\nfunction getAppSidebarImplicitSlot(\n childType: unknown,\n): AppSidebarImplicitSlot | undefined {\n if (isAppSidebarImplicitSlotComponent(childType)) {\n return childType[APP_SIDEBAR_IMPLICIT_SLOT];\n }\n\n if (typeof childType === 'object' && childType !== null) {\n const wrappedComponent = childType as AppSidebarWrappedComponent;\n return (\n getAppSidebarImplicitSlot(wrappedComponent.type) ??\n getAppSidebarImplicitSlot(wrappedComponent.render)\n );\n }\n\n return undefined;\n}\n\ntype SlotResult = {\n header: React.ReactNode[];\n content: React.ReactNode[];\n footer: React.ReactNode[];\n explicitHeader: React.ReactElement | null;\n explicitContent: React.ReactElement | null;\n explicitFooter: React.ReactElement | null;\n};\n\nfunction useSlotChildren(children: React.ReactNode): SlotResult {\n return React.useMemo(() => {\n const result: SlotResult = {\n header: [],\n content: [],\n footer: [],\n explicitHeader: null,\n explicitContent: null,\n explicitFooter: null,\n };\n\n React.Children.forEach(children, (child) => {\n if (!React.isValidElement(child)) return;\n\n const childType = child.type;\n\n // Check for explicit slot components\n if (childType === AppSidebarHeader) {\n result.explicitHeader = child;\n return;\n }\n if (childType === AppSidebarContent) {\n result.explicitContent = child;\n return;\n }\n if (childType === AppSidebarFooter) {\n result.explicitFooter = child;\n return;\n }\n\n // Distribute to slots based on explicit component-owned slot markers.\n const implicitSlot = getAppSidebarImplicitSlot(childType);\n if (implicitSlot === 'header') {\n result.header.push(child);\n } else if (implicitSlot === 'content') {\n result.content.push(child);\n } else if (implicitSlot === 'footer') {\n result.footer.push(child);\n } else {\n // Unknown children go to content by default\n result.content.push(child);\n }\n });\n\n return result;\n }, [children]);\n}\n\ntype AppSidebarSide = 'left' | 'right';\ntype AppSidebarDirection = 'ltr' | 'rtl';\n\nconst AppSidebarLayoutContext = React.createContext<{ side: AppSidebarSide }>({\n side: 'left',\n});\n\nfunction useAppSidebarLayout() {\n return React.useContext(AppSidebarLayoutContext);\n}\n\nfunction getAppSidebarDirection(\n element: HTMLElement | null,\n): AppSidebarDirection {\n const win = element?.ownerDocument.defaultView;\n if (!element || !win) return 'ltr';\n return win.getComputedStyle(element).direction === 'rtl' ? 'rtl' : 'ltr';\n}\n\nfunction normalizeAppSidebarDirection(\n dir: string | undefined,\n): AppSidebarDirection | undefined {\n return dir === 'rtl' || dir === 'ltr' ? dir : undefined;\n}\n\nfunction getAppSidebarSideFromDirection(\n direction: AppSidebarDirection,\n): AppSidebarSide {\n return direction === 'rtl' ? 'right' : 'left';\n}\n\nfunction getAppSidebarDirectionTargets(element: HTMLElement): Element[] {\n const targets = new Set<Element>();\n let current: Element | null = element;\n\n while (current) {\n targets.add(current);\n if (current === element.ownerDocument.documentElement) break;\n current = current.parentElement;\n }\n\n targets.add(element.ownerDocument.documentElement);\n if (element.ownerDocument.body) targets.add(element.ownerDocument.body);\n\n return Array.from(targets);\n}\n\nfunction useResolvedAppSidebarSide({\n containerRef,\n explicitDir,\n explicitSide,\n}: {\n containerRef: React.RefObject<HTMLDivElement | null>;\n explicitDir?: string;\n explicitSide?: AppSidebarSide;\n}): AppSidebarSide {\n const [detectedDirection, setDetectedDirection] =\n React.useState<AppSidebarDirection>(\n () => normalizeAppSidebarDirection(explicitDir) ?? 'ltr',\n );\n\n React.useEffect(() => {\n if (explicitSide) return;\n\n const normalizedExplicitDir = normalizeAppSidebarDirection(explicitDir);\n if (normalizedExplicitDir) {\n setDetectedDirection((current) =>\n current === normalizedExplicitDir ? current : normalizedExplicitDir,\n );\n return;\n }\n\n const container = containerRef.current;\n const win = container?.ownerDocument.defaultView;\n if (!container || !win) return;\n\n const detectDirection = () => {\n const nextDirection = getAppSidebarDirection(container);\n setDetectedDirection((current) =>\n current === nextDirection ? current : nextDirection,\n );\n };\n\n detectDirection();\n\n const Observer = win.MutationObserver;\n if (!Observer) return;\n\n const observer = new Observer(detectDirection);\n for (const target of getAppSidebarDirectionTargets(container)) {\n observer.observe(target, {\n attributes: true,\n attributeFilter: ['dir', 'class', 'style'],\n });\n }\n\n return () => observer.disconnect();\n }, [containerRef, explicitDir, explicitSide]);\n\n return explicitSide ?? getAppSidebarSideFromDirection(detectedDirection);\n}\n\n// ============================================\n// Sidebar Logo\n// ============================================\n\nexport interface AppSidebarLogoProps\n extends React.HTMLAttributes<HTMLDivElement> {\n /** Logo image or element */\n logo?: React.ReactNode;\n /** Icon to show when sidebar is compacted. Defaults to Humain logomark. */\n compactedLogo?: React.ReactNode;\n /** Subtext displayed below the logo (e.g., \"Dashboard\"). Hidden when collapsed. */\n subtext?: string;\n}\n\nconst DEFAULT_COMPACTED_LOGO = (\n <span className=\"flex size-9 items-center justify-center rounded-lg bg-primary text-primary-foreground\">\n <BrandIcon icon=\"mark\" size=\"sm\" />\n </span>\n);\n\nfunction AppSidebarLogo({\n logo,\n compactedLogo,\n subtext,\n className,\n ...props\n}: AppSidebarLogoProps) {\n const { state, toggleSidebar } = useSidebar();\n const isCollapsed = state === 'collapsed';\n const effectiveCompactedLogo = compactedLogo ?? DEFAULT_COMPACTED_LOGO;\n\n if (isCollapsed) {\n return (\n <div\n data-slot=\"app-sidebar-logo\"\n className={cn('flex items-center justify-center', className)}\n style={{ fontFamily: \"'Optician Sans', Inter, sans-serif\" }}\n {...props}\n dir=\"ltr\"\n >\n <button\n type=\"button\"\n onClick={toggleSidebar}\n className=\"group/logo relative flex size-[52px] items-center justify-center rounded-md p-2 transition-colors duration-200 ease-smooth hover:bg-sidebar-accent focus-visible:outline-2 focus-visible:outline-offset-2 focus-visible:outline-ring motion-reduce:transition-none\"\n aria-label=\"Expand sidebar\"\n >\n <span className=\"transition-opacity duration-200 ease-smooth group-hover/logo:opacity-0 motion-reduce:transition-none\">\n {effectiveCompactedLogo}\n </span>\n <PanelLeftOpen className=\"absolute size-5 opacity-0 transition-opacity duration-200 ease-smooth group-hover/logo:opacity-100 motion-reduce:transition-none\" />\n </button>\n </div>\n );\n }\n\n return (\n <div\n data-slot=\"app-sidebar-logo\"\n className={cn(\n 'flex h-[52px] items-center justify-between gap-2 rounded-md p-2',\n className,\n )}\n style={{ fontFamily: \"'Optician Sans', Inter, sans-serif\" }}\n {...props}\n dir=\"ltr\"\n >\n {logo ? (\n <div className=\"flex min-w-0 flex-col gap-0\">\n <div className=\"flex items-center\">{logo}</div>\n {subtext && (\n <p className=\"ps-11 text-sm text-sidebar-foreground\">\n <span data-slot=\"app-sidebar-logo-subtext\">{subtext}</span>\n </p>\n )}\n </div>\n ) : (\n <div className=\"flex min-w-0 items-center gap-2\">\n {DEFAULT_COMPACTED_LOGO}\n <div\n data-slot=\"app-sidebar-logo-text\"\n className=\"flex min-w-0 flex-col justify-center gap-0.5\"\n >\n <span\n data-slot=\"app-sidebar-logo-title\"\n className=\"text-lg font-semibold leading-tight tracking-tight text-foreground\"\n >\n HUMAIN\n </span>\n {subtext && (\n <span\n data-slot=\"app-sidebar-logo-subtext\"\n className=\"text-sm leading-none text-sidebar-foreground\"\n >\n {subtext}\n </span>\n )}\n </div>\n </div>\n )}\n <button\n type=\"button\"\n onClick={toggleSidebar}\n className=\"relative flex size-9 items-center justify-center rounded-lg text-sidebar-foreground transition-colors duration-200 ease-smooth hover:bg-sidebar-accent hover:text-foreground focus-visible:outline-2 focus-visible:outline-offset-2 focus-visible:outline-ring motion-reduce:transition-none after:absolute after:-inset-1\"\n aria-label=\"Collapse sidebar\"\n >\n <PanelLeftClose aria-hidden=\"true\" className=\"size-5\" />\n </button>\n </div>\n );\n}\n\nAppSidebarLogo.displayName = 'AppSidebar.Logo';\n\n// ============================================\n// Slot Components (Header, Content, Footer)\n// ============================================\n\nexport interface AppSidebarSlotProps {\n children?: React.ReactNode;\n className?: string;\n}\n\nfunction AppSidebarHeader({ children, className }: AppSidebarSlotProps) {\n return (\n <div data-slot=\"app-sidebar-header\" className={className}>\n {children}\n </div>\n );\n}\nAppSidebarHeader.displayName = 'AppSidebar.Header';\n\nfunction AppSidebarContent({ children, className }: AppSidebarSlotProps) {\n return (\n <div data-slot=\"app-sidebar-content\" className={className}>\n {children}\n </div>\n );\n}\nAppSidebarContent.displayName = 'AppSidebar.Content';\n\nfunction AppSidebarFooter({ children, className }: AppSidebarSlotProps) {\n return (\n <div data-slot=\"app-sidebar-footer\" className={className}>\n {children}\n </div>\n );\n}\nAppSidebarFooter.displayName = 'AppSidebar.Footer';\n\n// ============================================\n// Nav Component\n// ============================================\n\nexport interface AppSidebarNavProps {\n children?: React.ReactNode;\n /** Accessible label for the nav landmark (useful when multiple Nav instances exist) */\n 'aria-label'?: string;\n className?: string;\n}\n\nfunction AppSidebarNav({\n children,\n 'aria-label': ariaLabel = 'Sidebar navigation',\n className,\n}: AppSidebarNavProps) {\n const menuContent = (\n <SidebarMenu className=\"gap-0.5 group-data-[collapsible=icon]:items-center group-data-[collapsible=icon]:gap-1\">\n {React.Children.map(children, (child) => (\n <SidebarMenuItem>{child}</SidebarMenuItem>\n ))}\n </SidebarMenu>\n );\n\n return (\n <SidebarGroup\n data-slot=\"app-sidebar-nav\"\n className={cn(\n 'shrink-0 p-0 group-data-[collapsible=icon]:w-auto',\n className,\n )}\n >\n <SidebarGroupContent>\n <nav aria-label={ariaLabel}>{menuContent}</nav>\n </SidebarGroupContent>\n </SidebarGroup>\n );\n}\n\nAppSidebarNav.displayName = 'AppSidebar.Nav';\nmarkAppSidebarImplicitSlot(AppSidebarNav, 'content');\n\n// ============================================\n// Nav Section (Group Label / Divider)\n// ============================================\n\nexport interface AppSidebarNavSectionProps {\n /** Section label shown when sidebar is expanded */\n label: string;\n /** Additional className */\n className?: string;\n}\n\nfunction AppSidebarNavSection({ label, className }: AppSidebarNavSectionProps) {\n return (\n <div\n data-slot=\"app-sidebar-nav-section\"\n role=\"separator\"\n aria-label={label}\n className={cn('py-2 group-data-[collapsible=icon]:w-[52px]', className)}\n >\n <div className=\"flex h-8 items-center px-2 group-data-[collapsible=icon]:hidden\">\n <span className=\"text-xs font-medium text-sidebar-foreground/80\">\n {label}\n </span>\n </div>\n <div className=\"hidden py-2 group-data-[collapsible=icon]:block\">\n <span className=\"sr-only\">{label}</span>\n <Separator className=\"mx-auto w-full\" />\n </div>\n </div>\n );\n}\n\nAppSidebarNavSection.displayName = 'AppSidebar.NavSection';\n\n// ============================================\n// Nav Item Component\n// ============================================\n\nconst navItemVariants = cva(\n 'relative flex w-full items-center gap-1.5 rounded-lg px-2 py-2 text-sm font-normal transition-[color,background-color] duration-200 ease-smooth motion-reduce:transition-none',\n {\n variants: {\n state: {\n default: 'text-sidebar-foreground hover:bg-sidebar-accent',\n active: 'bg-primary/10 text-sidebar-foreground',\n },\n },\n defaultVariants: {\n state: 'default',\n },\n },\n);\n\nexport interface AppSidebarNavItemProps {\n icon: React.ReactNode;\n label: string;\n isActive?: boolean;\n badge?: string | number;\n onClick?: () => void;\n href?: string;\n className?: string;\n /** Sub-navigation children (AppSidebar.NavSub items). When present, renders as collapsible parent. */\n children?: React.ReactNode;\n}\n\nfunction AppSidebarNavItem({\n icon,\n label,\n isActive = false,\n badge,\n onClick,\n href,\n className,\n children,\n}: AppSidebarNavItemProps) {\n const { state, containerRef } = useSidebar();\n const { side: sidebarSide } = useAppSidebarLayout();\n const isCollapsed = state === 'collapsed';\n const hasChildren = React.Children.count(children) > 0;\n const hasActiveChild = React.Children.toArray(children).some(\n (child) =>\n React.isValidElement<{ isActive?: boolean }>(child) &&\n child.props.isActive === true,\n );\n const isHighlighted = isActive || hasActiveChild;\n const [isOpen, setIsOpen] = React.useState(isHighlighted && hasChildren);\n const subNavId = React.useId();\n const floatingSide = sidebarSide === 'right' ? 'left' : 'right';\n const flyoutPanelBackground =\n 'linear-gradient(108deg, var(--opacity-white-87) 0.5219%, var(--opacity-white-75) 98.419%)';\n const flyoutFrameEdgeClassName =\n sidebarSide === 'right'\n ? 'justify-end rounded-l-xl rounded-r-none'\n : 'justify-start rounded-r-xl rounded-l-none';\n const flyoutPanelEdgeClassName =\n sidebarSide === 'right' ? 'rounded-l-xl' : 'rounded-r-xl';\n const flyoutAnchor = React.useMemo(\n () => ({\n getBoundingClientRect: () => {\n const container = containerRef.current;\n const rect = container?.getBoundingClientRect();\n const win = container?.ownerDocument.defaultView;\n const viewportHeight = win?.innerHeight ?? rect?.height ?? 0;\n const x = rect ? (sidebarSide === 'right' ? rect.left : rect.right) : 0;\n\n return {\n x,\n y: 0,\n top: 0,\n right: x,\n bottom: viewportHeight,\n left: x,\n width: 0,\n height: viewportHeight,\n };\n },\n }),\n [containerRef, sidebarSide],\n );\n\n React.useEffect(() => {\n if (isHighlighted && hasChildren) setIsOpen(true);\n }, [isHighlighted, hasChildren]);\n\n const accessibleLabel = formatAccessibleLabel(label, badge);\n\n const iconElement = (\n <span\n data-slot=\"nav-icon\"\n className=\"flex shrink-0 items-center p-0.5 [&>svg]:size-4\"\n >\n {icon}\n </span>\n );\n\n const labelElement = (\n <span className=\"flex-1 text-start group-data-[collapsible=icon]:hidden\">\n {label}\n </span>\n );\n\n const badgeElement = badge != null && (\n <Badge\n size=\"sm\"\n variant=\"soft\"\n color=\"primary\"\n className=\"px-1.5 group-data-[collapsible=icon]:hidden\"\n aria-hidden=\"true\"\n >\n {badge}\n </Badge>\n );\n\n const chevronElement = hasChildren && (\n <ChevronRight\n aria-hidden=\"true\"\n className={cn(\n 'size-4 shrink-0 text-muted-foreground transition-transform duration-200 ease-smooth group-data-[collapsible=icon]:hidden motion-reduce:transition-none',\n isOpen ? 'rotate-90' : 'rtl:rotate-180',\n isHighlighted && isOpen && 'text-primary',\n )}\n />\n );\n\n const itemClassName = cn(\n navItemVariants({ state: isHighlighted ? 'active' : 'default' }),\n 'focus-visible:outline-2 focus-visible:outline-offset-[-2px] focus-visible:outline-ring',\n 'min-h-11 group-data-[collapsible=icon]:justify-center group-data-[collapsible=icon]:px-0 group-data-[collapsible=icon]:py-2 group-data-[collapsible=icon]:w-11 group-data-[collapsible=icon]:h-11',\n className,\n );\n\n const ariaProps = isActive ? { 'aria-current': 'page' as const } : {};\n\n // --- Collapsed: icon-only with tooltip, flyout popover for children ---\n if (isCollapsed) {\n const collapsedIconElement = (\n <span\n data-slot=\"nav-icon\"\n className=\"flex shrink-0 items-center justify-center p-0.5 [&>svg]:size-4\"\n >\n {icon}\n </span>\n );\n\n const triggerElement = href ? (\n <a\n href={href}\n className={cn(itemClassName)}\n aria-label={accessibleLabel}\n {...ariaProps}\n data-slot=\"app-sidebar-nav-item\"\n >\n {collapsedIconElement}\n </a>\n ) : (\n <button\n type=\"button\"\n onClick={hasChildren ? () => setIsOpen(!isOpen) : onClick}\n className={cn(itemClassName, 'cursor-pointer')}\n aria-label={accessibleLabel}\n {...ariaProps}\n data-slot=\"app-sidebar-nav-item\"\n >\n {collapsedIconElement}\n </button>\n );\n\n if (!hasChildren) {\n if (!label) return triggerElement;\n return (\n <Tooltip>\n <TooltipTrigger render={triggerElement} />\n <TooltipPopup side={floatingSide} sideOffset={8}>\n {label}\n </TooltipPopup>\n </Tooltip>\n );\n }\n\n return (\n <PopoverRoot>\n <PopoverTrigger\n className={cn(itemClassName, 'cursor-pointer')}\n aria-label={accessibleLabel}\n data-slot=\"app-sidebar-nav-item\"\n >\n {collapsedIconElement}\n </PopoverTrigger>\n <PopoverPopup\n side={floatingSide}\n align=\"start\"\n sideOffset={0}\n alignOffset={0}\n anchor={flyoutAnchor}\n collisionAvoidance={{\n side: 'none',\n align: 'none',\n fallbackAxisSide: 'none',\n }}\n positionMethod=\"fixed\"\n aria-label={`${label} sub-navigation`}\n style={\n {\n '--app-sidebar-flyout-panel-bg': flyoutPanelBackground,\n } as React.CSSProperties\n }\n className={cn(\n 'flex h-[var(--anchor-height)] w-[276px] border-0 bg-transparent p-0 ring-0 shadow-none',\n 'overflow-clip',\n flyoutFrameEdgeClassName,\n )}\n >\n <div\n className={cn(\n 'flex h-full w-64 flex-col gap-0.5 overflow-y-auto p-3 shadow-[var(--shadow-hover-card)]',\n 'supports-backdrop-filter:backdrop-blur-[60px] [background-image:var(--app-sidebar-flyout-panel-bg)] delight-tooltip-stagger',\n flyoutPanelEdgeClassName,\n )}\n data-slot=\"app-sidebar-nav-flyout-panel\"\n role=\"group\"\n aria-label={label}\n >\n <p\n className=\"px-2 pb-2 pt-1 text-xs font-semibold text-primary opacity-70\"\n aria-hidden=\"true\"\n >\n {label}\n </p>\n {children}\n </div>\n </PopoverPopup>\n </PopoverRoot>\n );\n }\n\n // --- Expanded: full item with optional inline sub-nav ---\n const handleClick = () => {\n if (hasChildren) {\n setIsOpen(!isOpen);\n }\n onClick?.();\n };\n\n const mainElement =\n href && !hasChildren ? (\n <a\n href={href}\n className={itemClassName}\n aria-label={accessibleLabel}\n {...ariaProps}\n data-slot=\"app-sidebar-nav-item\"\n >\n {iconElement}\n {labelElement}\n {badgeElement}\n {chevronElement}\n </a>\n ) : (\n <button\n type=\"button\"\n onClick={handleClick}\n className={cn(itemClassName, 'cursor-pointer')}\n aria-label={accessibleLabel}\n aria-expanded={hasChildren ? isOpen : undefined}\n aria-controls={hasChildren ? subNavId : undefined}\n {...ariaProps}\n data-slot=\"app-sidebar-nav-item\"\n >\n {iconElement}\n {labelElement}\n {badgeElement}\n {chevronElement}\n </button>\n );\n\n if (!hasChildren) return mainElement;\n\n return (\n <>\n {mainElement}\n {isOpen && (\n <ul\n id={subNavId}\n role=\"group\"\n aria-label={`${label} sub-navigation`}\n className=\"ms-4 flex flex-col items-start border-s border-sidebar-border py-1 ps-2\"\n >\n {children}\n </ul>\n )}\n </>\n );\n}\n\nAppSidebarNavItem.displayName = 'AppSidebar.NavItem';\n\n// ============================================\n// Nav Sub Component\n// ============================================\n\nexport interface AppSidebarNavSubProps {\n label: string;\n badge?: string | number;\n isActive?: boolean;\n href?: string;\n onClick?: () => void;\n className?: string;\n}\n\nfunction AppSidebarNavSub({\n label,\n badge,\n isActive = false,\n href,\n onClick,\n className,\n}: AppSidebarNavSubProps) {\n const accessibleLabel = formatAccessibleLabel(label, badge);\n\n const itemClassName = cn(\n navItemVariants({ state: isActive ? 'active' : 'default' }),\n 'min-h-11 focus-visible:outline-2 focus-visible:outline-offset-2 focus-visible:outline-ring',\n 'transition-[color,background-color,transform] ltr:hover:translate-x-0.5 rtl:hover:-translate-x-0.5 motion-reduce:ltr:hover:translate-x-0 motion-reduce:rtl:hover:translate-x-0',\n className,\n );\n\n const ariaProps = isActive ? { 'aria-current': 'page' as const } : {};\n\n const content = (\n <>\n <span className=\"flex-1 text-start\">{label}</span>\n {badge != null && (\n <Badge\n size=\"sm\"\n variant=\"soft\"\n color=\"primary\"\n className=\"px-1.5\"\n aria-hidden=\"true\"\n >\n {badge}\n </Badge>\n )}\n </>\n );\n\n if (href) {\n return (\n <a\n href={href}\n className={itemClassName}\n aria-label={accessibleLabel}\n {...ariaProps}\n data-slot=\"app-sidebar-nav-sub\"\n >\n {content}\n </a>\n );\n }\n\n return (\n <button\n type=\"button\"\n onClick={onClick}\n className={cn(itemClassName, 'cursor-pointer delight-selection-press')}\n aria-label={accessibleLabel}\n {...ariaProps}\n data-slot=\"app-sidebar-nav-sub\"\n >\n {content}\n </button>\n );\n}\nAppSidebarNavSub.displayName = 'AppSidebar.NavSub';\n\n// ============================================\n// Nav Skeleton\n// ============================================\n\nexport interface AppSidebarNavSkeletonProps {\n /** Number of skeleton items to show */\n count?: number;\n className?: string;\n}\n\nfunction AppSidebarNavSkeleton({\n count = 3,\n className,\n}: AppSidebarNavSkeletonProps) {\n const skeletonCount = getSkeletonCount(count, 3);\n\n return (\n <SidebarGroup\n className={cn(\n 'shrink-0 p-0 group-data-[collapsible=icon]:w-auto',\n className,\n )}\n >\n <SidebarGroupContent>\n <SidebarMenu className=\"gap-0.5 group-data-[collapsible=icon]:items-center group-data-[collapsible=icon]:gap-2\">\n {Array.from({ length: skeletonCount }).map((_, i) => (\n <SidebarMenuItem key={`nav-skeleton-${i}`}>\n <SidebarNavSkeleton />\n </SidebarMenuItem>\n ))}\n </SidebarMenu>\n </SidebarGroupContent>\n </SidebarGroup>\n );\n}\n\nAppSidebarNavSkeleton.displayName = 'AppSidebar.NavSkeleton';\nmarkAppSidebarImplicitSlot(AppSidebarNavSkeleton, 'content');\n\n// ============================================\n// Chat List Component\n// ============================================\n\nexport interface AppSidebarChatListProps {\n /** Section label */\n label?: string;\n children?: React.ReactNode;\n className?: string;\n}\n\nfunction AppSidebarChatList({\n label = 'Recent Chats',\n children,\n className,\n}: AppSidebarChatListProps) {\n const { state } = useSidebar();\n const isCollapsed = state === 'collapsed';\n\n // Collapsed state doesn't show chat list\n if (isCollapsed) {\n return null;\n }\n\n return (\n <SidebarGroup\n data-slot=\"app-sidebar-chat-list\"\n className={cn('mt-4 flex min-h-0 flex-1 flex-col p-0', className)}\n >\n <SidebarGroupLabel className=\"shrink-0 px-3 py-1 text-xs font-bold text-muted-foreground\">\n {label}\n </SidebarGroupLabel>\n <SidebarGroupContent className=\"flex-1 overflow-hidden\">\n <div\n className=\"flex h-full flex-col overflow-y-auto pb-5 rounded-md focus-visible:outline-2 focus-visible:outline-offset-2 focus-visible:outline-ring\"\n tabIndex={0}\n role=\"list\"\n aria-label={label}\n >\n {children}\n </div>\n </SidebarGroupContent>\n </SidebarGroup>\n );\n}\n\nAppSidebarChatList.displayName = 'AppSidebar.ChatList';\nmarkAppSidebarImplicitSlot(AppSidebarChatList, 'content');\n\n// ============================================\n// Chat Item Component\n// ============================================\n\nconst chatItemVariants = cva(\n 'flex w-full items-center justify-between gap-2 rounded-md px-3 py-2 min-h-11 transition-[color,background-color,transform] duration-200 ease-smooth cursor-pointer motion-reduce:transition-none ltr:hover:translate-x-0.5 rtl:hover:-translate-x-0.5 motion-reduce:ltr:hover:translate-x-0 motion-reduce:rtl:hover:translate-x-0',\n {\n variants: {\n state: {\n default: 'hover:bg-muted',\n hover: 'bg-muted',\n selected: 'bg-primary/10',\n },\n },\n defaultVariants: {\n state: 'default',\n },\n },\n);\n\nexport interface AppSidebarChatItemProps\n extends VariantProps<typeof chatItemVariants> {\n /** Chat title */\n title: string;\n /** Time indicator (e.g., \"12h ago\") */\n time?: string;\n /** Icon for collapsed view (defaults to chat bubble) */\n icon?: React.ReactNode;\n /** Whether this chat is selected */\n isSelected?: boolean;\n /** Click handler */\n onClick?: () => void;\n /** Context menu handler (right-click) */\n onContextMenu?: (event: React.MouseEvent) => void;\n /** Additional className */\n className?: string;\n}\n\nfunction AppSidebarChatItem({\n title,\n time,\n icon,\n isSelected = false,\n onClick,\n onContextMenu,\n className,\n}: AppSidebarChatItemProps) {\n const { state } = useSidebar();\n const { side: sidebarSide } = useAppSidebarLayout();\n const isCollapsed = state === 'collapsed';\n const tooltipSide = sidebarSide === 'right' ? 'left' : 'right';\n\n if (isCollapsed) {\n const collapsedButton = (\n <button\n type=\"button\"\n onClick={onClick}\n onContextMenu={onContextMenu}\n data-slot=\"app-sidebar-chat-item\"\n aria-label={title || undefined}\n className={cn(\n 'flex size-11 items-center justify-center rounded-md transition-colors duration-200 ease-smooth motion-reduce:transition-none focus-visible:outline-2 focus-visible:outline-offset-2 focus-visible:outline-ring',\n isSelected ? 'bg-primary/10' : 'hover:bg-muted',\n className,\n )}\n >\n {icon || <MessageCircle className=\"size-5 text-secondary-foreground\" />}\n </button>\n );\n\n if (!title && !time) {\n return collapsedButton;\n }\n\n return (\n <Tooltip>\n <TooltipTrigger render={collapsedButton} />\n <TooltipPopup side={tooltipSide} sideOffset={8}>\n <div className=\"flex flex-col\">\n <span className=\"font-medium\">{title}</span>\n {time && (\n <span className=\"text-xs text-muted-foreground\">{time}</span>\n )}\n </div>\n </TooltipPopup>\n </Tooltip>\n );\n }\n\n return (\n <div role=\"listitem\">\n <button\n type=\"button\"\n onClick={onClick}\n onContextMenu={onContextMenu}\n data-slot=\"app-sidebar-chat-item\"\n aria-label={title}\n className={cn(\n chatItemVariants({ state: isSelected ? 'selected' : 'default' }),\n 'focus-visible:outline-2 focus-visible:outline-offset-2 focus-visible:outline-ring',\n className,\n )}\n >\n <span className=\"text-base font-semibold text-secondary-foreground truncate\">\n {title}\n </span>\n {time && (\n <span className=\"text-xs font-normal text-muted-foreground shrink-0\">\n {time}\n </span>\n )}\n </button>\n </div>\n );\n}\n\nAppSidebarChatItem.displayName = 'AppSidebar.ChatItem';\n\n// ============================================\n// Chat List Skeleton\n// ============================================\n\nexport interface AppSidebarChatListSkeletonProps {\n /** Number of skeleton items to show */\n count?: number;\n /** Section label */\n label?: string;\n className?: string;\n}\n\nfunction AppSidebarChatListSkeleton({\n count = 5,\n label = 'Recent Chats',\n className,\n}: AppSidebarChatListSkeletonProps) {\n const skeletonCount = getSkeletonCount(count, 5);\n\n return (\n <SidebarGroup\n className={cn(\n 'mt-4 flex min-h-0 flex-1 flex-col p-0 group-data-[collapsible=icon]:hidden',\n className,\n )}\n >\n <SidebarGroupLabel className=\"shrink-0 px-3 py-1 text-xs font-bold text-muted-foreground\">\n {label}\n </SidebarGroupLabel>\n <SidebarGroupContent className=\"flex-1 overflow-hidden\">\n <div className=\"flex h-full flex-col overflow-y-auto pb-5\">\n {Array.from({ length: skeletonCount }).map((_, i) => (\n <SidebarMenuSkeleton key={`chat-skeleton-${i}`} />\n ))}\n </div>\n </SidebarGroupContent>\n </SidebarGroup>\n );\n}\n\nAppSidebarChatListSkeleton.displayName = 'AppSidebar.ChatListSkeleton';\nmarkAppSidebarImplicitSlot(AppSidebarChatListSkeleton, 'content');\n\n// ============================================\n// Account Component\n// ============================================\n\nexport interface AppSidebarAccountProps\n extends React.HTMLAttributes<HTMLDivElement> {\n /** User's name */\n name: string;\n /** Subtitle text (e.g., email, role) */\n subtitle?: string;\n /** User's avatar URL */\n avatarSrc?: string;\n /** Whether user is online */\n isOnline?: boolean;\n /** Click handler for the expand button */\n onExpand?: () => void;\n}\n\nfunction AppSidebarAccount({\n name,\n subtitle,\n avatarSrc,\n isOnline = false,\n onExpand,\n className,\n}: AppSidebarAccountProps) {\n const { state } = useSidebar();\n const { side: sidebarSide } = useAppSidebarLayout();\n const isCollapsed = state === 'collapsed';\n const tooltipSide = sidebarSide === 'right' ? 'left' : 'right';\n\n if (isCollapsed) {\n const avatarButton = (\n <button\n type=\"button\"\n onClick={onExpand}\n data-slot=\"app-sidebar-account\"\n aria-label={name ? `${name} account menu` : 'Account menu'}\n aria-haspopup=\"true\"\n className={cn(\n 'flex min-h-11 min-w-11 items-center justify-center rounded-lg transition-opacity duration-200 ease-smooth hover:opacity-80 focus-visible:outline-2 focus-visible:outline-offset-2 focus-visible:outline-ring motion-reduce:transition-none',\n className,\n )}\n >\n <Avatar\n src={avatarSrc}\n alt={name}\n fallback={name}\n size=\"sm\"\n className=\"size-[42px]\"\n indicator={isOnline ? 'online' : undefined}\n />\n </button>\n );\n\n if (!name && !subtitle) return avatarButton;\n\n return (\n <Tooltip>\n <TooltipTrigger render={avatarButton} />\n <TooltipPopup side={tooltipSide} sideOffset={8}>\n <div className=\"flex flex-col\">\n {name && <span className=\"font-medium\">{name}</span>}\n {subtitle && (\n <span className=\"text-xs text-muted-foreground\">{subtitle}</span>\n )}\n </div>\n </TooltipPopup>\n </Tooltip>\n );\n }\n\n return (\n <button\n type=\"button\"\n onClick={onExpand}\n data-slot=\"app-sidebar-account\"\n aria-label={name ? `${name} account menu` : 'Account menu'}\n aria-haspopup=\"true\"\n className={cn(\n 'flex w-full items-center gap-1.5 rounded-lg px-1 py-2 transition-colors duration-200 ease-smooth hover:bg-sidebar-accent focus-visible:outline-2 focus-visible:outline-offset-2 focus-visible:outline-ring motion-reduce:transition-none',\n className,\n )}\n >\n <Avatar\n src={avatarSrc}\n alt={name}\n fallback={name}\n size=\"sm\"\n className=\"size-[42px]\"\n indicator={isOnline ? 'online' : undefined}\n />\n <div className=\"flex flex-1 flex-col items-start overflow-hidden\">\n <span className=\"w-full truncate text-start text-sm font-medium text-sidebar-foreground\">\n {name}\n </span>\n {subtitle && (\n <span className=\"w-full truncate text-start text-xs font-light text-sidebar-foreground\">\n {subtitle}\n </span>\n )}\n </div>\n </button>\n );\n}\n\nAppSidebarAccount.displayName = 'AppSidebar.Account';\nmarkAppSidebarImplicitSlot(AppSidebarAccount, 'footer');\n\n// ============================================\n// Account Skeleton\n// ============================================\n\nfunction AppSidebarAccountSkeleton({ className }: { className?: string }) {\n return <SidebarAccountSkeleton className={className} />;\n}\n\nAppSidebarAccountSkeleton.displayName = 'AppSidebar.AccountSkeleton';\nmarkAppSidebarImplicitSlot(AppSidebarAccountSkeleton, 'footer');\n\n// ============================================\n// Full Sidebar Skeleton\n// ============================================\n\nexport interface AppSidebarSkeletonProps {\n /** Number of nav skeleton items */\n navCount?: number;\n /** Number of chat skeleton items */\n chatCount?: number;\n /** Logo element */\n logo?: React.ReactNode;\n /** Icon to show when sidebar is compacted. Defaults to Humain logomark. */\n compactedLogo?: React.ReactNode;\n /** Collapsible mode */\n collapsible?: 'offcanvas' | 'icon' | 'none';\n /** Side of the screen */\n side?: 'left' | 'right';\n /** Whether to round sidebar corners */\n rounded?: boolean;\n /** Custom background color class for the sidebar (e.g., 'bg-card') */\n sidebarBgColor?: string;\n className?: string;\n}\n\nfunction AppSidebarSkeleton({\n navCount = 4,\n chatCount = 5,\n logo,\n compactedLogo,\n collapsible = 'icon',\n side,\n rounded = false,\n sidebarBgColor,\n className,\n}: AppSidebarSkeletonProps) {\n const { state, containerRef } = useSidebar();\n const isCollapsed = state === 'collapsed';\n const resolvedSide = useResolvedAppSidebarSide({\n containerRef,\n explicitSide: side,\n });\n\n const bgClass = getSidebarBgClass(isCollapsed, sidebarBgColor);\n\n return (\n <Sidebar\n collapsible={collapsible}\n side={resolvedSide}\n data-side={resolvedSide}\n width={APP_SIDEBAR_EXPANDED_WIDTH}\n collapsedWidth={APP_SIDEBAR_COLLAPSED_WIDTH}\n className={cn('bg-transparent', className)}\n >\n <div\n data-slot=\"app-sidebar-surface\"\n className={getSidebarSurfaceClass({\n isCollapsed,\n side: resolvedSide,\n rounded,\n backgroundClass: bgClass,\n })}\n >\n <SidebarHeader className=\"h-[68px] w-full p-2 group-data-[collapsible=icon]:p-0\">\n <AppSidebarLogo logo={logo} compactedLogo={compactedLogo} />\n </SidebarHeader>\n\n <SidebarContent className=\"flex w-full flex-col gap-0 overflow-hidden pt-3 group-data-[collapsible=icon]:items-center\">\n <AppSidebarNavSkeleton count={navCount} />\n <AppSidebarChatListSkeleton count={chatCount} />\n </SidebarContent>\n\n <SidebarFooter className=\"w-full gap-0 p-0 group-data-[collapsible=icon]:items-center\">\n <AppSidebarAccountSkeleton />\n </SidebarFooter>\n </div>\n </Sidebar>\n );\n}\n\nAppSidebarSkeleton.displayName = 'AppSidebar.Skeleton';\n\n// ============================================\n// Main App Sidebar\n// ============================================\n\nexport interface AppSidebarProps extends React.HTMLAttributes<HTMLDivElement> {\n /** Logo element or configuration */\n logo?: React.ReactNode;\n /** Icon to show when sidebar is compacted. Defaults to Humain logomark. */\n compactedLogo?: React.ReactNode;\n /** Subtext displayed below the logo (e.g., \"Dashboard\"). Hidden when collapsed. */\n logoSubtext?: string;\n /** Collapsible mode - 'icon' shows only icons when collapsed, 'none' disables collapsing */\n collapsible?: 'offcanvas' | 'icon' | 'none';\n /** Side of the screen. When omitted, resolves from the nearest DOM direction. */\n side?: 'left' | 'right';\n /** Whether to round sidebar corners */\n rounded?: boolean;\n /** Custom background color class for the sidebar (e.g., 'bg-card'). Defaults to the sidebar token when expanded, bg-transparent when collapsed. */\n sidebarBgColor?: string;\n /** Children (compound components) */\n children?: React.ReactNode;\n}\n\n/**\n * AppSidebar is a full-featured application sidebar with navigation, chat list, and account sections.\n * Supports collapsible modes with a unified logo toggle and loading skeletons.\n *\n * @llms Full-featured app sidebar with nav, chat list, account, collapsible modes\n * @example\n * ```tsx\n * <AppSidebar logo={<Logo />} collapsible=\"icon\">\n * <AppSidebar.Nav>\n * <AppSidebar.NavItem icon={<Home />} label=\"Home\" isActive />\n * </AppSidebar.Nav>\n * <AppSidebar.ChatList>\n * <AppSidebar.ChatItem title=\"Chat 1\" />\n * </AppSidebar.ChatList>\n * <AppSidebar.Account name=\"User\" subtitle=\"user@example.com\" />\n * </AppSidebar>\n * ```\n */\nfunction AppSidebarRoot({\n logo,\n compactedLogo,\n logoSubtext,\n collapsible = 'icon',\n side,\n rounded = false,\n sidebarBgColor,\n className,\n children,\n dir,\n ...props\n}: AppSidebarProps) {\n const { state, containerRef } = useSidebar();\n const isCollapsed = state === 'collapsed';\n const resolvedSide = useResolvedAppSidebarSide({\n containerRef,\n explicitDir: dir,\n explicitSide: side,\n });\n\n const bgClass = getSidebarBgClass(isCollapsed, sidebarBgColor);\n\n const slots = useSlotChildren(children);\n\n return (\n <AppSidebarLayoutContext.Provider value={{ side: resolvedSide }}>\n <Sidebar\n collapsible={collapsible}\n side={resolvedSide}\n data-side={resolvedSide}\n width={APP_SIDEBAR_EXPANDED_WIDTH}\n collapsedWidth={APP_SIDEBAR_COLLAPSED_WIDTH}\n dir={dir}\n className={cn('bg-transparent', className)}\n {...props}\n >\n <div\n data-slot=\"app-sidebar-surface\"\n className={getSidebarSurfaceClass({\n isCollapsed,\n side: resolvedSide,\n rounded,\n backgroundClass: bgClass,\n })}\n >\n <SidebarHeader className=\"h-[68px] w-full p-2 group-data-[collapsible=icon]:p-0\">\n <AppSidebarLogo\n logo={logo}\n compactedLogo={compactedLogo}\n subtext={logoSubtext}\n />\n </SidebarHeader>\n\n <SidebarContent className=\"flex w-full flex-col gap-0 overflow-hidden pt-3 group-data-[collapsible=icon]:items-center\">\n {slots.explicitContent\n ? (slots.explicitContent.props as AppSidebarSlotProps).children\n : slots.content}\n </SidebarContent>\n\n <SidebarFooter className=\"w-full gap-0 p-0 group-data-[collapsible=icon]:items-center\">\n {slots.explicitFooter\n ? (slots.explicitFooter.props as AppSidebarSlotProps).children\n : slots.footer}\n </SidebarFooter>\n </div>\n </Sidebar>\n </AppSidebarLayoutContext.Provider>\n );\n}\n\nAppSidebarRoot.displayName = 'AppSidebar';\n\n// ============================================\n// Compound Component Export\n// ============================================\n\nexport const AppSidebar = Object.assign(AppSidebarRoot, {\n Header: AppSidebarHeader,\n Content: AppSidebarContent,\n Footer: AppSidebarFooter,\n Nav: AppSidebarNav,\n NavSection: AppSidebarNavSection,\n NavItem: AppSidebarNavItem,\n NavSub: AppSidebarNavSub,\n NavSkeleton: AppSidebarNavSkeleton,\n ChatList: AppSidebarChatList,\n ChatItem: AppSidebarChatItem,\n ChatListSkeleton: AppSidebarChatListSkeleton,\n Account: AppSidebarAccount,\n AccountSkeleton: AppSidebarAccountSkeleton,\n Skeleton: AppSidebarSkeleton,\n});\n\n// ============================================\n// Type Exports\n// ============================================\n\n// Re-export mobile detection utilities for client use\nexport { MOBILE_BREAKPOINT, useIsMobile } from '@/hooks/use-mobile';\nexport {\n APP_SIDEBAR_COLLAPSED_WIDTH,\n APP_SIDEBAR_EXPANDED_WIDTH,\n} from './AppSidebar.constants';\nexport type {\n AppSidebarAccountProps as AccountProps,\n AppSidebarChatItemProps as ChatItemProps,\n AppSidebarChatListProps as ChatListProps,\n AppSidebarChatListSkeletonProps as ChatListSkeletonProps,\n AppSidebarNavItemProps as NavItemProps,\n AppSidebarNavProps as NavProps,\n AppSidebarNavSectionProps as NavSectionProps,\n AppSidebarNavSkeletonProps as NavSkeletonProps,\n AppSidebarNavSubProps as NavSubProps,\n AppSidebarSkeletonProps as SkeletonProps,\n AppSidebarSlotProps as SlotProps,\n};\n// Re-export sidebar primitives for custom compositions\nexport {\n chatItemVariants,\n navItemVariants,\n // Re-export base components for advanced usage\n Sidebar,\n SidebarAccountSkeleton,\n SidebarContent,\n SidebarFooter,\n SidebarGroup,\n SidebarGroupContent,\n SidebarGroupLabel,\n SidebarHeader,\n SidebarInset,\n SidebarMenu,\n SidebarMenuButton,\n SidebarMenuItem,\n SidebarMenuSkeleton,\n SidebarNavSkeleton,\n SidebarProvider,\n SidebarTrigger,\n useSidebar,\n};\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
|
});
|