@humain/ui 2.2.3 → 2.2.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/components/templates/AppShell/AppShell.d.ts +1 -1
- package/dist/components/templates/AppSidebar/AppSidebar.constants.d.ts +1 -1
- package/dist/index152.js +1 -1
- package/dist/index152.js.map +1 -1
- package/dist/index173.js +1 -1
- package/dist/index173.js.map +1 -1
- package/dist/index184.js +1 -1
- package/dist/index184.js.map +1 -1
- package/dist/index217.js +1 -1
- package/dist/index217.js.map +1 -1
- package/dist/index223.js.map +1 -1
- package/dist/index225.js +3 -3
- package/dist/index225.js.map +1 -1
- package/dist/styles.css +1 -1
- package/dist/wc/AISource.js +46 -46
- package/dist/wc/AISource.js.map +1 -1
- package/dist/wc/AIToolCall.js +9 -9
- package/dist/wc/AIToolCall.js.map +1 -1
- package/dist/wc/AppSidebar.constants.js +1 -1
- package/dist/wc/AppSidebar.constants.js.map +1 -1
- package/dist/wc/hf-app-shell.js.map +1 -1
- package/dist/wc/hf-app-sidebar.js +3 -3
- package/dist/wc/hf-app-sidebar.js.map +1 -1
- package/dist/wc/markdown-renderer.js +1 -1
- package/dist/wc/markdown-renderer.js.map +1 -1
- package/dist/wc-react/AISource.js +8 -8
- package/dist/wc-react/AISource.js.map +1 -1
- package/dist/wc-react/AIToolCall.js +42 -42
- package/dist/wc-react/AIToolCall.js.map +1 -1
- package/dist/wc-react/AppSidebar.constants.js +1 -1
- package/dist/wc-react/AppSidebar.constants.js.map +1 -1
- package/dist/wc-react/hf-app-shell.js.map +1 -1
- package/dist/wc-react/hf-app-sidebar.js +3 -3
- package/dist/wc-react/hf-app-sidebar.js.map +1 -1
- package/dist/wc-react/markdown-renderer.js +1 -1
- package/dist/wc-react/markdown-renderer.js.map +1 -1
- 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
|
@@ -54,7 +54,7 @@ export interface AppShellSidebarProps extends React.ComponentProps<'div'> {
|
|
|
54
54
|
width?: string;
|
|
55
55
|
/** Width when sidebar is expanded (auto mode only). @default '280px' */
|
|
56
56
|
expandedWidth?: string;
|
|
57
|
-
/** Width when sidebar is collapsed (auto mode only). @default '
|
|
57
|
+
/** Width when sidebar is collapsed (auto mode only). @default '68px' */
|
|
58
58
|
collapsedWidth?: string;
|
|
59
59
|
}
|
|
60
60
|
/**
|
|
@@ -1,4 +1,4 @@
|
|
|
1
1
|
/** Canonical expanded width shared by AppSidebar and AppShell.Sidebar. */
|
|
2
2
|
export declare const APP_SIDEBAR_EXPANDED_WIDTH = "280px";
|
|
3
3
|
/** Canonical collapsed width shared by AppSidebar and AppShell.Sidebar. */
|
|
4
|
-
export declare const APP_SIDEBAR_COLLAPSED_WIDTH = "
|
|
4
|
+
export declare const APP_SIDEBAR_COLLAPSED_WIDTH = "68px";
|
package/dist/index152.js
CHANGED
|
@@ -106,7 +106,7 @@ function createMarkdownComponents(variant) {
|
|
|
106
106
|
...props
|
|
107
107
|
}),
|
|
108
108
|
table: ({ className, children, ...props }) => /* @__PURE__ */ jsx("section", {
|
|
109
|
-
className: "overflow-x-auto my-4 [overflow-wrap:normal] [&_a]:break-normal [&_a]:[overflow-wrap:normal] [&_code]:break-normal [&_code]:[overflow-wrap:normal] focus-visible:outline-2 focus-visible:outline-offset-2 focus-visible:outline-ring",
|
|
109
|
+
className: "not-prose overflow-x-auto my-4 [overflow-wrap:normal] [&_a]:break-normal [&_a]:[overflow-wrap:normal] [&_code]:break-normal [&_code]:[overflow-wrap:normal] focus-visible:outline-2 focus-visible:outline-offset-2 focus-visible:outline-ring",
|
|
110
110
|
"aria-label": "Data table",
|
|
111
111
|
tabIndex: 0,
|
|
112
112
|
children: /* @__PURE__ */ jsx("table", {
|
package/dist/index152.js.map
CHANGED
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"index152.js","names":[],"sources":["../src/components/organisms/ai/_shared/markdown-renderer.tsx"],"sourcesContent":["'use client';\n\nimport * as React from 'react';\nimport ReactMarkdown, { type Components } from 'react-markdown';\nimport rehypeKatex from 'rehype-katex';\nimport remarkGfm from 'remark-gfm';\nimport remarkMath from 'remark-math';\nimport type { PluggableList } from 'unified';\nimport { cn } from '@/lib/utils';\nimport { createCodeComponent } from './code-handler';\n\nconst remarkPlugins: PluggableList = [remarkGfm, remarkMath];\nconst rehypePlugins: PluggableList = [[rehypeKatex, { output: 'mathml' }]];\nconst markdownOverflowWrapClasses =\n 'min-w-0 max-w-full break-words [overflow-wrap:anywhere]';\n\n// =============================================================================\n// Variant-aware color mapping\n// =============================================================================\n\nimport type { MarkdownVariant } from './types';\n\nexport type { MarkdownVariant } from './types';\n\nconst variantColors = {\n heading: { default: 'text-foreground', inverted: 'text-primary-foreground' },\n body: {\n default: 'text-secondary-foreground',\n inverted: 'text-primary-foreground/90',\n },\n link: { default: 'text-primary', inverted: 'text-primary-foreground' },\n muted: {\n default: 'text-muted-foreground',\n inverted: 'text-primary-foreground/70',\n },\n faint: {\n default: 'text-text-quaternary',\n inverted: 'text-primary-foreground/50',\n },\n border: {\n default: 'border-border',\n inverted: 'border-primary-foreground/25',\n },\n bgMuted: { default: 'bg-muted', inverted: 'bg-primary-foreground/20' },\n} as const;\n\ntype ColorToken = keyof typeof variantColors;\n\nfunction vc(variant: MarkdownVariant, token: ColorToken): string {\n return variantColors[token][variant];\n}\n\n// =============================================================================\n// Create variant-aware component overrides for react-markdown\n// =============================================================================\n\nfunction createMarkdownComponents(\n variant: MarkdownVariant,\n): Partial<Components> {\n return {\n h1: ({ className, children, ...props }) => (\n <h1\n className={cn(\n 'text-display-xs font-bold mt-6 mb-4',\n markdownOverflowWrapClasses,\n vc(variant, 'heading'),\n className,\n )}\n {...props}\n >\n {children}\n </h1>\n ),\n h2: ({ className, children, ...props }) => (\n <h2\n className={cn(\n 'text-xl font-semibold mt-5 mb-3',\n markdownOverflowWrapClasses,\n vc(variant, 'heading'),\n className,\n )}\n {...props}\n >\n {children}\n </h2>\n ),\n h3: ({ className, children, ...props }) => (\n <h3\n className={cn(\n 'text-lg font-semibold mt-4 mb-2',\n markdownOverflowWrapClasses,\n vc(variant, 'heading'),\n className,\n )}\n {...props}\n >\n {children}\n </h3>\n ),\n h4: ({ className, children, ...props }) => (\n <h4\n className={cn(\n 'text-base font-semibold mt-3 mb-2',\n markdownOverflowWrapClasses,\n vc(variant, 'heading'),\n className,\n )}\n {...props}\n >\n {children}\n </h4>\n ),\n p: ({ className, children, ...props }) => (\n <p\n className={cn(\n 'text-base leading-relaxed mb-4',\n markdownOverflowWrapClasses,\n vc(variant, 'body'),\n className,\n )}\n {...props}\n >\n {children}\n </p>\n ),\n ul: ({ className, children, ...props }) => (\n <ul\n className={cn(\n 'list-disc list-inside mb-4 space-y-1',\n markdownOverflowWrapClasses,\n vc(variant, 'body'),\n className,\n )}\n {...props}\n >\n {children}\n </ul>\n ),\n ol: ({ className, children, ...props }) => (\n <ol\n className={cn(\n 'list-decimal list-inside mb-4 space-y-1',\n markdownOverflowWrapClasses,\n vc(variant, 'body'),\n className,\n )}\n {...props}\n >\n {children}\n </ol>\n ),\n li: ({ className, children, ...props }) => (\n <li\n className={cn(\n 'leading-relaxed',\n markdownOverflowWrapClasses,\n className,\n )}\n {...props}\n >\n {children}\n </li>\n ),\n a: ({ className, children, href, ...props }) => (\n <a\n href={href}\n className={cn(\n 'underline underline-offset-2 transition-colors focus-visible:outline-2 focus-visible:outline-offset-2 focus-visible:outline-ring rounded-sm',\n markdownOverflowWrapClasses,\n vc(variant, 'link'),\n variant === 'default' && 'hover:text-primary',\n variant === 'inverted' && 'hover:text-primary-foreground',\n className,\n )}\n target=\"_blank\"\n rel=\"noopener noreferrer\"\n {...props}\n >\n {children}\n </a>\n ),\n blockquote: ({ className, children, ...props }) => (\n <blockquote\n className={cn(\n 'border-s-4 ps-4 py-2 my-4 italic',\n markdownOverflowWrapClasses,\n vc(variant, 'muted'),\n vc(variant, 'border'),\n className,\n )}\n {...props}\n >\n {children}\n </blockquote>\n ),\n code: createCodeComponent(variant),\n pre: ({ children }) => <>{children}</>,\n hr: ({ className, ...props }) => (\n <hr className={cn('my-6', vc(variant, 'border'), className)} {...props} />\n ),\n table: ({ className, children, ...props }) => (\n <section\n className=\"overflow-x-auto my-4 [overflow-wrap:normal] [&_a]:break-normal [&_a]:[overflow-wrap:normal] [&_code]:break-normal [&_code]:[overflow-wrap:normal] focus-visible:outline-2 focus-visible:outline-offset-2 focus-visible:outline-ring\"\n aria-label=\"Data table\"\n // biome-ignore lint/a11y/noNoninteractiveTabindex: Focusable scroll region satisfies axe scrollable-region-focusable.\n tabIndex={0}\n >\n <table\n className={cn(\n 'min-w-full border-collapse border [overflow-wrap:normal]',\n vc(variant, 'border'),\n variant === 'inverted' && '!bg-transparent',\n className,\n )}\n {...props}\n >\n {children}\n </table>\n </section>\n ),\n thead: ({ className, children, ...props }) => (\n <thead\n className={cn(\n variant === 'default' ? vc(variant, 'bgMuted') : '!bg-transparent',\n className,\n )}\n {...props}\n >\n {children}\n </thead>\n ),\n tbody: ({ className, children, ...props }) => (\n <tbody\n className={cn(\n variant === 'default'\n ? 'divide-y divide-border'\n : 'divide-y divide-primary-foreground/20',\n className,\n )}\n {...props}\n >\n {children}\n </tbody>\n ),\n tr: ({ children, ...props }) => <tr {...props}>{children}</tr>,\n th: ({ className, children, ...props }) => (\n <th\n className={cn(\n 'px-4 py-2 text-start text-sm font-semibold border',\n '[overflow-wrap:normal]',\n vc(variant, 'body'),\n vc(variant, 'border'),\n variant === 'inverted' && '!bg-transparent',\n className,\n )}\n {...props}\n >\n {children}\n </th>\n ),\n td: ({ className, children, ...props }) => (\n <td\n className={cn(\n 'px-4 py-2 text-sm border',\n '[overflow-wrap:normal]',\n vc(variant, 'body'),\n vc(variant, 'border'),\n variant === 'inverted' && '!bg-transparent',\n className,\n )}\n {...props}\n >\n {children}\n </td>\n ),\n strong: ({ className, children, ...props }) => (\n <strong\n className={cn(\n 'font-semibold',\n markdownOverflowWrapClasses,\n vc(variant, 'heading'),\n className,\n )}\n {...props}\n >\n {children}\n </strong>\n ),\n em: ({ className, children, ...props }) => (\n <em className={cn(markdownOverflowWrapClasses, className)} {...props}>\n {children}\n </em>\n ),\n del: ({ className, children, ...props }) => (\n <del\n className={cn(\n 'line-through',\n markdownOverflowWrapClasses,\n vc(variant, 'faint'),\n className,\n )}\n {...props}\n >\n {children}\n </del>\n ),\n img: ({ className, alt, src, ...props }) => (\n <img\n src={src}\n alt={alt}\n className={cn('max-w-full h-auto rounded-lg my-4', className)}\n loading=\"lazy\"\n {...props}\n />\n ),\n };\n}\n\n// =============================================================================\n// Component cache (at most 2 entries: 'default' and 'inverted')\n// =============================================================================\n\nconst componentCache = new Map<MarkdownVariant, Partial<Components>>();\n\nfunction getComponents(variant: MarkdownVariant): Partial<Components> {\n let cached = componentCache.get(variant);\n if (!cached) {\n cached = createMarkdownComponents(variant);\n componentCache.set(variant, cached);\n }\n return cached;\n}\n\n// =============================================================================\n// MarkdownRenderer\n// =============================================================================\n\nexport interface MarkdownRendererProps {\n /** Markdown content to render */\n children: string;\n /** Additional class name */\n className?: string;\n /** Color variant — 'inverted' for white text on colored backgrounds */\n variant?: MarkdownVariant;\n}\n\nconst MarkdownRenderer = React.memo(function MarkdownRenderer({\n children,\n className,\n variant = 'default',\n}: MarkdownRendererProps) {\n const components = getComponents(variant);\n\n return (\n <div\n data-slot=\"ai-markdown\"\n className={cn(\n 'prose prose-gray max-w-none',\n markdownOverflowWrapClasses,\n className,\n )}\n >\n <ReactMarkdown\n remarkPlugins={remarkPlugins}\n rehypePlugins={rehypePlugins}\n components={components}\n >\n {children}\n </ReactMarkdown>\n </div>\n );\n});\n\nMarkdownRenderer.displayName = 'MarkdownRenderer';\n\nexport { MarkdownRenderer };\n"],"mappings":"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"}
|
|
1
|
+
{"version":3,"file":"index152.js","names":[],"sources":["../src/components/organisms/ai/_shared/markdown-renderer.tsx"],"sourcesContent":["'use client';\n\nimport * as React from 'react';\nimport ReactMarkdown, { type Components } from 'react-markdown';\nimport rehypeKatex from 'rehype-katex';\nimport remarkGfm from 'remark-gfm';\nimport remarkMath from 'remark-math';\nimport type { PluggableList } from 'unified';\nimport { cn } from '@/lib/utils';\nimport { createCodeComponent } from './code-handler';\n\nconst remarkPlugins: PluggableList = [remarkGfm, remarkMath];\nconst rehypePlugins: PluggableList = [[rehypeKatex, { output: 'mathml' }]];\nconst markdownOverflowWrapClasses =\n 'min-w-0 max-w-full break-words [overflow-wrap:anywhere]';\n\n// =============================================================================\n// Variant-aware color mapping\n// =============================================================================\n\nimport type { MarkdownVariant } from './types';\n\nexport type { MarkdownVariant } from './types';\n\nconst variantColors = {\n heading: { default: 'text-foreground', inverted: 'text-primary-foreground' },\n body: {\n default: 'text-secondary-foreground',\n inverted: 'text-primary-foreground/90',\n },\n link: { default: 'text-primary', inverted: 'text-primary-foreground' },\n muted: {\n default: 'text-muted-foreground',\n inverted: 'text-primary-foreground/70',\n },\n faint: {\n default: 'text-text-quaternary',\n inverted: 'text-primary-foreground/50',\n },\n border: {\n default: 'border-border',\n inverted: 'border-primary-foreground/25',\n },\n bgMuted: { default: 'bg-muted', inverted: 'bg-primary-foreground/20' },\n} as const;\n\ntype ColorToken = keyof typeof variantColors;\n\nfunction vc(variant: MarkdownVariant, token: ColorToken): string {\n return variantColors[token][variant];\n}\n\n// =============================================================================\n// Create variant-aware component overrides for react-markdown\n// =============================================================================\n\nfunction createMarkdownComponents(\n variant: MarkdownVariant,\n): Partial<Components> {\n return {\n h1: ({ className, children, ...props }) => (\n <h1\n className={cn(\n 'text-display-xs font-bold mt-6 mb-4',\n markdownOverflowWrapClasses,\n vc(variant, 'heading'),\n className,\n )}\n {...props}\n >\n {children}\n </h1>\n ),\n h2: ({ className, children, ...props }) => (\n <h2\n className={cn(\n 'text-xl font-semibold mt-5 mb-3',\n markdownOverflowWrapClasses,\n vc(variant, 'heading'),\n className,\n )}\n {...props}\n >\n {children}\n </h2>\n ),\n h3: ({ className, children, ...props }) => (\n <h3\n className={cn(\n 'text-lg font-semibold mt-4 mb-2',\n markdownOverflowWrapClasses,\n vc(variant, 'heading'),\n className,\n )}\n {...props}\n >\n {children}\n </h3>\n ),\n h4: ({ className, children, ...props }) => (\n <h4\n className={cn(\n 'text-base font-semibold mt-3 mb-2',\n markdownOverflowWrapClasses,\n vc(variant, 'heading'),\n className,\n )}\n {...props}\n >\n {children}\n </h4>\n ),\n p: ({ className, children, ...props }) => (\n <p\n className={cn(\n 'text-base leading-relaxed mb-4',\n markdownOverflowWrapClasses,\n vc(variant, 'body'),\n className,\n )}\n {...props}\n >\n {children}\n </p>\n ),\n ul: ({ className, children, ...props }) => (\n <ul\n className={cn(\n 'list-disc list-inside mb-4 space-y-1',\n markdownOverflowWrapClasses,\n vc(variant, 'body'),\n className,\n )}\n {...props}\n >\n {children}\n </ul>\n ),\n ol: ({ className, children, ...props }) => (\n <ol\n className={cn(\n 'list-decimal list-inside mb-4 space-y-1',\n markdownOverflowWrapClasses,\n vc(variant, 'body'),\n className,\n )}\n {...props}\n >\n {children}\n </ol>\n ),\n li: ({ className, children, ...props }) => (\n <li\n className={cn(\n 'leading-relaxed',\n markdownOverflowWrapClasses,\n className,\n )}\n {...props}\n >\n {children}\n </li>\n ),\n a: ({ className, children, href, ...props }) => (\n <a\n href={href}\n className={cn(\n 'underline underline-offset-2 transition-colors focus-visible:outline-2 focus-visible:outline-offset-2 focus-visible:outline-ring rounded-sm',\n markdownOverflowWrapClasses,\n vc(variant, 'link'),\n variant === 'default' && 'hover:text-primary',\n variant === 'inverted' && 'hover:text-primary-foreground',\n className,\n )}\n target=\"_blank\"\n rel=\"noopener noreferrer\"\n {...props}\n >\n {children}\n </a>\n ),\n blockquote: ({ className, children, ...props }) => (\n <blockquote\n className={cn(\n 'border-s-4 ps-4 py-2 my-4 italic',\n markdownOverflowWrapClasses,\n vc(variant, 'muted'),\n vc(variant, 'border'),\n className,\n )}\n {...props}\n >\n {children}\n </blockquote>\n ),\n code: createCodeComponent(variant),\n pre: ({ children }) => <>{children}</>,\n hr: ({ className, ...props }) => (\n <hr className={cn('my-6', vc(variant, 'border'), className)} {...props} />\n ),\n table: ({ className, children, ...props }) => (\n <section\n className=\"not-prose overflow-x-auto my-4 [overflow-wrap:normal] [&_a]:break-normal [&_a]:[overflow-wrap:normal] [&_code]:break-normal [&_code]:[overflow-wrap:normal] focus-visible:outline-2 focus-visible:outline-offset-2 focus-visible:outline-ring\"\n aria-label=\"Data table\"\n // biome-ignore lint/a11y/noNoninteractiveTabindex: Focusable scroll region satisfies axe scrollable-region-focusable.\n tabIndex={0}\n >\n <table\n className={cn(\n 'min-w-full border-collapse border [overflow-wrap:normal]',\n vc(variant, 'border'),\n variant === 'inverted' && '!bg-transparent',\n className,\n )}\n {...props}\n >\n {children}\n </table>\n </section>\n ),\n thead: ({ className, children, ...props }) => (\n <thead\n className={cn(\n variant === 'default' ? vc(variant, 'bgMuted') : '!bg-transparent',\n className,\n )}\n {...props}\n >\n {children}\n </thead>\n ),\n tbody: ({ className, children, ...props }) => (\n <tbody\n className={cn(\n variant === 'default'\n ? 'divide-y divide-border'\n : 'divide-y divide-primary-foreground/20',\n className,\n )}\n {...props}\n >\n {children}\n </tbody>\n ),\n tr: ({ children, ...props }) => <tr {...props}>{children}</tr>,\n th: ({ className, children, ...props }) => (\n <th\n className={cn(\n 'px-4 py-2 text-start text-sm font-semibold border',\n '[overflow-wrap:normal]',\n vc(variant, 'body'),\n vc(variant, 'border'),\n variant === 'inverted' && '!bg-transparent',\n className,\n )}\n {...props}\n >\n {children}\n </th>\n ),\n td: ({ className, children, ...props }) => (\n <td\n className={cn(\n 'px-4 py-2 text-sm border',\n '[overflow-wrap:normal]',\n vc(variant, 'body'),\n vc(variant, 'border'),\n variant === 'inverted' && '!bg-transparent',\n className,\n )}\n {...props}\n >\n {children}\n </td>\n ),\n strong: ({ className, children, ...props }) => (\n <strong\n className={cn(\n 'font-semibold',\n markdownOverflowWrapClasses,\n vc(variant, 'heading'),\n className,\n )}\n {...props}\n >\n {children}\n </strong>\n ),\n em: ({ className, children, ...props }) => (\n <em className={cn(markdownOverflowWrapClasses, className)} {...props}>\n {children}\n </em>\n ),\n del: ({ className, children, ...props }) => (\n <del\n className={cn(\n 'line-through',\n markdownOverflowWrapClasses,\n vc(variant, 'faint'),\n className,\n )}\n {...props}\n >\n {children}\n </del>\n ),\n img: ({ className, alt, src, ...props }) => (\n <img\n src={src}\n alt={alt}\n className={cn('max-w-full h-auto rounded-lg my-4', className)}\n loading=\"lazy\"\n {...props}\n />\n ),\n };\n}\n\n// =============================================================================\n// Component cache (at most 2 entries: 'default' and 'inverted')\n// =============================================================================\n\nconst componentCache = new Map<MarkdownVariant, Partial<Components>>();\n\nfunction getComponents(variant: MarkdownVariant): Partial<Components> {\n let cached = componentCache.get(variant);\n if (!cached) {\n cached = createMarkdownComponents(variant);\n componentCache.set(variant, cached);\n }\n return cached;\n}\n\n// =============================================================================\n// MarkdownRenderer\n// =============================================================================\n\nexport interface MarkdownRendererProps {\n /** Markdown content to render */\n children: string;\n /** Additional class name */\n className?: string;\n /** Color variant — 'inverted' for white text on colored backgrounds */\n variant?: MarkdownVariant;\n}\n\nconst MarkdownRenderer = React.memo(function MarkdownRenderer({\n children,\n className,\n variant = 'default',\n}: MarkdownRendererProps) {\n const components = getComponents(variant);\n\n return (\n <div\n data-slot=\"ai-markdown\"\n className={cn(\n 'prose prose-gray max-w-none',\n markdownOverflowWrapClasses,\n className,\n )}\n >\n <ReactMarkdown\n remarkPlugins={remarkPlugins}\n rehypePlugins={rehypePlugins}\n components={components}\n >\n {children}\n </ReactMarkdown>\n </div>\n );\n});\n\nMarkdownRenderer.displayName = 'MarkdownRenderer';\n\nexport { MarkdownRenderer };\n"],"mappings":"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"}
|
package/dist/index173.js
CHANGED
|
@@ -9,7 +9,7 @@ var sourceVariants = cva("inline-flex items-center gap-1.5 transition-colors cur
|
|
|
9
9
|
variants: { variant: {
|
|
10
10
|
default: "text-sm text-primary hover:text-primary underline underline-offset-2 rounded-sm",
|
|
11
11
|
pill: "px-2.5 py-1 rounded-full bg-accent hover:bg-surface-2 text-xs text-secondary-foreground delight-selection-press",
|
|
12
|
-
minimal: "text-xs text-
|
|
12
|
+
minimal: "text-xs text-secondary-foreground hover:text-foreground rounded-sm"
|
|
13
13
|
} },
|
|
14
14
|
defaultVariants: { variant: "default" }
|
|
15
15
|
});
|
package/dist/index173.js.map
CHANGED
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"index173.js","names":[],"sources":["../src/components/organisms/ai/AISource/AISource.tsx"],"sourcesContent":["import { cva, type VariantProps } from 'class-variance-authority';\nimport { ExternalLink, Globe } from 'lucide-react';\nimport * as React from 'react';\nimport { Tooltip, TooltipPopup, TooltipTrigger } from '@/components/ui/tooltip';\nimport { cn } from '@/lib/utils';\n\n// =============================================================================\n// Variants\n// =============================================================================\n\nconst sourceVariants = cva(\n 'inline-flex items-center gap-1.5 transition-colors cursor-pointer focus-visible:outline-2 focus-visible:outline-offset-2 focus-visible:outline-ring',\n {\n variants: {\n variant: {\n default:\n 'text-sm text-primary hover:text-primary underline underline-offset-2 rounded-sm',\n pill: 'px-2.5 py-1 rounded-full bg-accent hover:bg-surface-2 text-xs text-secondary-foreground delight-selection-press',\n minimal:\n 'text-xs text-text-quaternary hover:text-secondary-foreground rounded-sm',\n },\n },\n defaultVariants: {\n variant: 'default',\n },\n },\n);\n\nconst DEFAULT_MAX_VISIBLE_SOURCES = 3;\n\nfunction getMaxVisibleSources(maxVisible: number): number {\n return Number.isFinite(maxVisible) && maxVisible >= 0\n ? Math.floor(maxVisible)\n : DEFAULT_MAX_VISIBLE_SOURCES;\n}\n\n// =============================================================================\n// Types\n// =============================================================================\n\nexport interface SourceData {\n /** Source URL */\n url: string;\n /** Display title */\n title?: string;\n /** Source description */\n description?: string;\n /** Favicon URL */\n favicon?: string;\n /** Site name */\n siteName?: string;\n}\n\n// =============================================================================\n// Source Favicon\n// =============================================================================\n\ninterface SourceFaviconProps {\n url: string;\n favicon?: string;\n className?: string;\n}\n\nfunction SourceFavicon({ url, favicon, className }: SourceFaviconProps) {\n const [hasError, setHasError] = React.useState(false);\n\n // Generate favicon URL from domain if not provided\n const faviconUrl = React.useMemo(() => {\n if (favicon) return favicon;\n try {\n const domain = new URL(url).hostname;\n return `https://www.google.com/s2/favicons?domain=${domain}&sz=32`;\n } catch {\n return null;\n }\n }, [url, favicon]);\n\n if (!faviconUrl || hasError) {\n return <Globe className={cn('size-4 text-muted-foreground', className)} />;\n }\n\n return (\n <img\n src={faviconUrl}\n alt=\"\"\n className={cn(\n 'size-4 rounded delight-fade-in motion-reduce:!animate-none',\n className,\n )}\n onError={() => setHasError(true)}\n />\n );\n}\n\nSourceFavicon.displayName = 'SourceFavicon';\n\n// =============================================================================\n// Source Trigger (Clickable element)\n// =============================================================================\n\nexport interface AISourceTriggerProps\n extends VariantProps<typeof sourceVariants> {\n /** Source data */\n source: SourceData;\n /** Whether to show favicon */\n showFavicon?: boolean;\n /** Additional class name */\n className?: string;\n /** Click handler */\n onClick?: () => void;\n}\n\nfunction AISourceTrigger({\n source,\n variant,\n showFavicon = true,\n className,\n onClick,\n}: AISourceTriggerProps) {\n const displayText = source.title || source.siteName || source.url;\n\n const sharedClassName = cn(sourceVariants({ variant }), className);\n const sharedChildren = (\n <>\n {showFavicon && (\n <SourceFavicon url={source.url} favicon={source.favicon} />\n )}\n <span className=\"truncate max-w-[200px]\">{displayText}</span>\n {variant === 'default' && (\n <ExternalLink className=\"size-3 shrink-0\" aria-hidden=\"true\" />\n )}\n </>\n );\n\n // Render as <a> when navigating to URL (proper semantics)\n if (!onClick) {\n return (\n <a\n data-slot=\"ai-source-trigger\"\n href={source.url}\n target=\"_blank\"\n rel=\"noopener noreferrer\"\n className={sharedClassName}\n aria-label={`Source: ${displayText}`}\n >\n {sharedChildren}\n </a>\n );\n }\n\n // Render as <button> when custom click handler is provided\n return (\n <button\n type=\"button\"\n data-slot=\"ai-source-trigger\"\n onClick={onClick}\n className={sharedClassName}\n aria-label={`Source: ${displayText}`}\n >\n {sharedChildren}\n </button>\n );\n}\n\nAISourceTrigger.displayName = 'AISourceTrigger';\n\n// =============================================================================\n// Source Content (Tooltip/Popover content)\n// =============================================================================\n\nexport interface AISourceContentProps {\n /** Source data */\n source: SourceData;\n /** Additional class name */\n className?: string;\n}\n\nfunction AISourceContent({ source, className }: AISourceContentProps) {\n const domain = React.useMemo(() => {\n try {\n return new URL(source.url).hostname;\n } catch {\n return source.url;\n }\n }, [source.url]);\n\n return (\n <div className={cn('p-3 max-w-xs space-y-2', className)}>\n <div className=\"flex items-start gap-2\">\n <SourceFavicon\n url={source.url}\n favicon={source.favicon}\n className=\"mt-0.5\"\n />\n <div className=\"flex-1 min-w-0\">\n <p className=\"text-sm font-medium text-foreground truncate\">\n {source.title || domain}\n </p>\n <p className=\"text-xs text-text-quaternary truncate\">{domain}</p>\n </div>\n </div>\n {source.description && (\n <p className=\"text-xs text-muted-foreground line-clamp-2\">\n {source.description}\n </p>\n )}\n <a\n href={source.url}\n target=\"_blank\"\n rel=\"noopener noreferrer\"\n className=\"flex items-center gap-1 text-xs text-primary hover:text-primary\"\n >\n Visit source\n <ExternalLink className=\"size-3\" />\n </a>\n </div>\n );\n}\n\nAISourceContent.displayName = 'AISourceContent';\n\n// =============================================================================\n// Main AISource Component (with built-in tooltip)\n// =============================================================================\n\nexport interface AISourceProps extends VariantProps<typeof sourceVariants> {\n /** Source data */\n source: SourceData;\n /** Whether to show favicon */\n showFavicon?: boolean;\n /** Whether to show tooltip on hover */\n showTooltip?: boolean;\n /** Additional class name */\n className?: string;\n}\n\nfunction AISource({\n source,\n variant,\n showFavicon = true,\n showTooltip = true,\n className,\n}: AISourceProps) {\n if (!showTooltip) {\n return (\n <span data-slot=\"ai-source\">\n <AISourceTrigger\n source={source}\n variant={variant}\n showFavicon={showFavicon}\n className={className}\n />\n </span>\n );\n }\n\n return (\n <Tooltip>\n <TooltipTrigger\n render={\n <span data-slot=\"ai-source\">\n <AISourceTrigger\n source={source}\n variant={variant}\n showFavicon={showFavicon}\n className={className}\n />\n </span>\n }\n />\n <TooltipPopup side=\"top\" className=\"p-0\">\n <AISourceContent source={source} />\n </TooltipPopup>\n </Tooltip>\n );\n}\n\nAISource.displayName = 'AISource';\n\n// =============================================================================\n// Source List Component\n// =============================================================================\n\nexport interface AISourceListProps {\n /** Array of sources */\n sources: SourceData[];\n /** Maximum sources to show before truncating */\n maxVisible?: number;\n /** Whether to show expanded list */\n showAll?: boolean;\n /** Callback when \"show more\" is clicked */\n onShowMore?: () => void;\n /** Additional class name */\n className?: string;\n}\n\nfunction AISourceList({\n sources,\n maxVisible = 3,\n showAll = false,\n onShowMore,\n className,\n}: AISourceListProps) {\n const safeMaxVisible = getMaxVisibleSources(maxVisible);\n const visibleSources = showAll ? sources : sources.slice(0, safeMaxVisible);\n const remainingCount = Math.max(0, sources.length - safeMaxVisible);\n\n return (\n <nav\n data-slot=\"ai-source-list\"\n aria-label=\"Sources\"\n className={cn('flex flex-wrap items-center gap-2', className)}\n >\n <span className=\"text-xs text-text-quaternary\">Sources:</span>\n {visibleSources.map((source, index) => (\n <span\n key={`${source.url}-${index}`}\n className=\"delight-stagger motion-reduce:!animate-none\"\n style={\n { '--delight-delay': `${index * 50}ms` } as React.CSSProperties\n }\n >\n <AISource source={source} variant=\"pill\" />\n </span>\n ))}\n {!showAll && remainingCount > 0 && (\n <button\n type=\"button\"\n onClick={onShowMore}\n aria-label={`Show ${remainingCount} more sources`}\n className=\"px-2.5 py-1 rounded-full bg-accent hover:bg-surface-2 text-xs text-secondary-foreground transition-colors focus-visible:outline-2 focus-visible:outline-offset-2 focus-visible:outline-ring delight-selection-press\"\n >\n +{remainingCount} more\n </button>\n )}\n </nav>\n );\n}\n\nAISourceList.displayName = 'AISourceList';\n\nexport {\n AISource,\n AISourceContent,\n AISourceList,\n AISourceTrigger,\n SourceFavicon,\n sourceVariants,\n};\n"],"mappings":"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"}
|
|
1
|
+
{"version":3,"file":"index173.js","names":[],"sources":["../src/components/organisms/ai/AISource/AISource.tsx"],"sourcesContent":["import { cva, type VariantProps } from 'class-variance-authority';\nimport { ExternalLink, Globe } from 'lucide-react';\nimport * as React from 'react';\nimport { Tooltip, TooltipPopup, TooltipTrigger } from '@/components/ui/tooltip';\nimport { cn } from '@/lib/utils';\n\n// =============================================================================\n// Variants\n// =============================================================================\n\nconst sourceVariants = cva(\n 'inline-flex items-center gap-1.5 transition-colors cursor-pointer focus-visible:outline-2 focus-visible:outline-offset-2 focus-visible:outline-ring',\n {\n variants: {\n variant: {\n default:\n 'text-sm text-primary hover:text-primary underline underline-offset-2 rounded-sm',\n pill: 'px-2.5 py-1 rounded-full bg-accent hover:bg-surface-2 text-xs text-secondary-foreground delight-selection-press',\n minimal:\n 'text-xs text-secondary-foreground hover:text-foreground rounded-sm',\n },\n },\n defaultVariants: {\n variant: 'default',\n },\n },\n);\n\nconst DEFAULT_MAX_VISIBLE_SOURCES = 3;\n\nfunction getMaxVisibleSources(maxVisible: number): number {\n return Number.isFinite(maxVisible) && maxVisible >= 0\n ? Math.floor(maxVisible)\n : DEFAULT_MAX_VISIBLE_SOURCES;\n}\n\n// =============================================================================\n// Types\n// =============================================================================\n\nexport interface SourceData {\n /** Source URL */\n url: string;\n /** Display title */\n title?: string;\n /** Source description */\n description?: string;\n /** Favicon URL */\n favicon?: string;\n /** Site name */\n siteName?: string;\n}\n\n// =============================================================================\n// Source Favicon\n// =============================================================================\n\ninterface SourceFaviconProps {\n url: string;\n favicon?: string;\n className?: string;\n}\n\nfunction SourceFavicon({ url, favicon, className }: SourceFaviconProps) {\n const [hasError, setHasError] = React.useState(false);\n\n // Generate favicon URL from domain if not provided\n const faviconUrl = React.useMemo(() => {\n if (favicon) return favicon;\n try {\n const domain = new URL(url).hostname;\n return `https://www.google.com/s2/favicons?domain=${domain}&sz=32`;\n } catch {\n return null;\n }\n }, [url, favicon]);\n\n if (!faviconUrl || hasError) {\n return <Globe className={cn('size-4 text-muted-foreground', className)} />;\n }\n\n return (\n <img\n src={faviconUrl}\n alt=\"\"\n className={cn(\n 'size-4 rounded delight-fade-in motion-reduce:!animate-none',\n className,\n )}\n onError={() => setHasError(true)}\n />\n );\n}\n\nSourceFavicon.displayName = 'SourceFavicon';\n\n// =============================================================================\n// Source Trigger (Clickable element)\n// =============================================================================\n\nexport interface AISourceTriggerProps\n extends VariantProps<typeof sourceVariants> {\n /** Source data */\n source: SourceData;\n /** Whether to show favicon */\n showFavicon?: boolean;\n /** Additional class name */\n className?: string;\n /** Click handler */\n onClick?: () => void;\n}\n\nfunction AISourceTrigger({\n source,\n variant,\n showFavicon = true,\n className,\n onClick,\n}: AISourceTriggerProps) {\n const displayText = source.title || source.siteName || source.url;\n\n const sharedClassName = cn(sourceVariants({ variant }), className);\n const sharedChildren = (\n <>\n {showFavicon && (\n <SourceFavicon url={source.url} favicon={source.favicon} />\n )}\n <span className=\"truncate max-w-[200px]\">{displayText}</span>\n {variant === 'default' && (\n <ExternalLink className=\"size-3 shrink-0\" aria-hidden=\"true\" />\n )}\n </>\n );\n\n // Render as <a> when navigating to URL (proper semantics)\n if (!onClick) {\n return (\n <a\n data-slot=\"ai-source-trigger\"\n href={source.url}\n target=\"_blank\"\n rel=\"noopener noreferrer\"\n className={sharedClassName}\n aria-label={`Source: ${displayText}`}\n >\n {sharedChildren}\n </a>\n );\n }\n\n // Render as <button> when custom click handler is provided\n return (\n <button\n type=\"button\"\n data-slot=\"ai-source-trigger\"\n onClick={onClick}\n className={sharedClassName}\n aria-label={`Source: ${displayText}`}\n >\n {sharedChildren}\n </button>\n );\n}\n\nAISourceTrigger.displayName = 'AISourceTrigger';\n\n// =============================================================================\n// Source Content (Tooltip/Popover content)\n// =============================================================================\n\nexport interface AISourceContentProps {\n /** Source data */\n source: SourceData;\n /** Additional class name */\n className?: string;\n}\n\nfunction AISourceContent({ source, className }: AISourceContentProps) {\n const domain = React.useMemo(() => {\n try {\n return new URL(source.url).hostname;\n } catch {\n return source.url;\n }\n }, [source.url]);\n\n return (\n <div className={cn('p-3 max-w-xs space-y-2', className)}>\n <div className=\"flex items-start gap-2\">\n <SourceFavicon\n url={source.url}\n favicon={source.favicon}\n className=\"mt-0.5\"\n />\n <div className=\"flex-1 min-w-0\">\n <p className=\"text-sm font-medium text-foreground truncate\">\n {source.title || domain}\n </p>\n <p className=\"text-xs text-text-quaternary truncate\">{domain}</p>\n </div>\n </div>\n {source.description && (\n <p className=\"text-xs text-muted-foreground line-clamp-2\">\n {source.description}\n </p>\n )}\n <a\n href={source.url}\n target=\"_blank\"\n rel=\"noopener noreferrer\"\n className=\"flex items-center gap-1 text-xs text-primary hover:text-primary\"\n >\n Visit source\n <ExternalLink className=\"size-3\" />\n </a>\n </div>\n );\n}\n\nAISourceContent.displayName = 'AISourceContent';\n\n// =============================================================================\n// Main AISource Component (with built-in tooltip)\n// =============================================================================\n\nexport interface AISourceProps extends VariantProps<typeof sourceVariants> {\n /** Source data */\n source: SourceData;\n /** Whether to show favicon */\n showFavicon?: boolean;\n /** Whether to show tooltip on hover */\n showTooltip?: boolean;\n /** Additional class name */\n className?: string;\n}\n\nfunction AISource({\n source,\n variant,\n showFavicon = true,\n showTooltip = true,\n className,\n}: AISourceProps) {\n if (!showTooltip) {\n return (\n <span data-slot=\"ai-source\">\n <AISourceTrigger\n source={source}\n variant={variant}\n showFavicon={showFavicon}\n className={className}\n />\n </span>\n );\n }\n\n return (\n <Tooltip>\n <TooltipTrigger\n render={\n <span data-slot=\"ai-source\">\n <AISourceTrigger\n source={source}\n variant={variant}\n showFavicon={showFavicon}\n className={className}\n />\n </span>\n }\n />\n <TooltipPopup side=\"top\" className=\"p-0\">\n <AISourceContent source={source} />\n </TooltipPopup>\n </Tooltip>\n );\n}\n\nAISource.displayName = 'AISource';\n\n// =============================================================================\n// Source List Component\n// =============================================================================\n\nexport interface AISourceListProps {\n /** Array of sources */\n sources: SourceData[];\n /** Maximum sources to show before truncating */\n maxVisible?: number;\n /** Whether to show expanded list */\n showAll?: boolean;\n /** Callback when \"show more\" is clicked */\n onShowMore?: () => void;\n /** Additional class name */\n className?: string;\n}\n\nfunction AISourceList({\n sources,\n maxVisible = 3,\n showAll = false,\n onShowMore,\n className,\n}: AISourceListProps) {\n const safeMaxVisible = getMaxVisibleSources(maxVisible);\n const visibleSources = showAll ? sources : sources.slice(0, safeMaxVisible);\n const remainingCount = Math.max(0, sources.length - safeMaxVisible);\n\n return (\n <nav\n data-slot=\"ai-source-list\"\n aria-label=\"Sources\"\n className={cn('flex flex-wrap items-center gap-2', className)}\n >\n <span className=\"text-xs text-text-quaternary\">Sources:</span>\n {visibleSources.map((source, index) => (\n <span\n key={`${source.url}-${index}`}\n className=\"delight-stagger motion-reduce:!animate-none\"\n style={\n { '--delight-delay': `${index * 50}ms` } as React.CSSProperties\n }\n >\n <AISource source={source} variant=\"pill\" />\n </span>\n ))}\n {!showAll && remainingCount > 0 && (\n <button\n type=\"button\"\n onClick={onShowMore}\n aria-label={`Show ${remainingCount} more sources`}\n className=\"px-2.5 py-1 rounded-full bg-accent hover:bg-surface-2 text-xs text-secondary-foreground transition-colors focus-visible:outline-2 focus-visible:outline-offset-2 focus-visible:outline-ring delight-selection-press\"\n >\n +{remainingCount} more\n </button>\n )}\n </nav>\n );\n}\n\nAISourceList.displayName = 'AISourceList';\n\nexport {\n AISource,\n AISourceContent,\n AISourceList,\n AISourceTrigger,\n SourceFavicon,\n sourceVariants,\n};\n"],"mappings":"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"}
|
package/dist/index184.js
CHANGED
|
@@ -52,7 +52,7 @@ function AIToolCallHeader({ toolName, status, isOpen, onToggle, className }) {
|
|
|
52
52
|
className: "text-sm font-medium text-foreground",
|
|
53
53
|
children: toolName
|
|
54
54
|
}), /* @__PURE__ */ jsx("span", {
|
|
55
|
-
className: "text-xs text-
|
|
55
|
+
className: "text-xs text-secondary-foreground",
|
|
56
56
|
children: {
|
|
57
57
|
pending: "Pending",
|
|
58
58
|
running: "Running...",
|
package/dist/index184.js.map
CHANGED
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"index184.js","names":[],"sources":["../src/components/organisms/ai/AIToolCall/AIToolCall.tsx"],"sourcesContent":["import { cva, type VariantProps } from 'class-variance-authority';\nimport {\n AlertCircle,\n Check,\n ChevronDown,\n ChevronRight,\n Clock,\n Code,\n Wrench,\n} from 'lucide-react';\nimport { AnimatePresence, motion } from 'motion/react';\nimport * as React from 'react';\nimport { AICodeBlock } from '@/components/organisms/ai/AICodeBlock';\nimport { useControllableState } from '@/hooks/use-controllable-state';\nimport { cn } from '@/lib/utils';\n\n// =============================================================================\n// Variants\n// =============================================================================\n\nconst toolCallVariants = cva(\n 'overflow-hidden rounded-xl border transition-colors',\n {\n variants: {\n status: {\n pending: 'border-border bg-muted',\n running: 'border-primary bg-primary/10',\n success: 'border-success/50 bg-success/10',\n error: 'border-destructive/50 bg-destructive/10',\n },\n },\n defaultVariants: {\n status: 'pending',\n },\n },\n);\n\nconst statusIconVariants = cva('size-4', {\n variants: {\n status: {\n pending: 'text-muted-foreground',\n running: 'text-primary animate-spin motion-reduce:animate-none',\n success: 'text-success',\n error: 'text-destructive',\n },\n },\n defaultVariants: {\n status: 'pending',\n },\n});\n\n// =============================================================================\n// Types\n// =============================================================================\n\nexport type ToolCallStatus = 'pending' | 'running' | 'success' | 'error';\n\nexport interface ToolCallPart {\n /** Unique tool call ID */\n toolCallId: string;\n /** Tool name */\n toolName: string;\n /** Tool input/arguments */\n args?: Record<string, unknown>;\n /** Tool output/result */\n result?: unknown;\n /** Tool status */\n status?: ToolCallStatus;\n /** Error message if status is error */\n error?: string;\n}\n\n// =============================================================================\n// Status Icon Component\n// =============================================================================\n\ninterface StatusIconProps {\n status: ToolCallStatus;\n className?: string;\n}\n\nfunction StatusIcon({ status, className }: StatusIconProps) {\n const iconClass = cn(statusIconVariants({ status }), className);\n\n switch (status) {\n case 'running':\n return <Clock className={iconClass} />;\n case 'success':\n return (\n <Check\n className={cn(\n iconClass,\n 'delight-check-bounce motion-reduce:!animate-none',\n )}\n />\n );\n case 'error':\n return (\n <AlertCircle\n className={cn(iconClass, 'delight-shake motion-reduce:!animate-none')}\n />\n );\n default:\n return <Wrench className={iconClass} />;\n }\n}\n\nStatusIcon.displayName = 'StatusIcon';\n\n// =============================================================================\n// Tool Call Header\n// =============================================================================\n\ninterface AIToolCallHeaderProps {\n toolName: string;\n status: ToolCallStatus;\n isOpen: boolean;\n onToggle: () => void;\n className?: string;\n}\n\nfunction AIToolCallHeader({\n toolName,\n status,\n isOpen,\n onToggle,\n className,\n}: AIToolCallHeaderProps) {\n const statusLabel = {\n pending: 'Pending',\n running: 'Running...',\n success: 'Completed',\n error: 'Failed',\n };\n\n return (\n <button\n type=\"button\"\n onClick={onToggle}\n aria-expanded={isOpen}\n className={cn(\n 'flex items-center justify-between w-full px-4 py-3 transition-colors hover:bg-foreground/5 focus-visible:outline-2 focus-visible:outline-offset-[-2px] focus-visible:outline-ring',\n className,\n )}\n >\n <div className=\"flex items-center gap-3\">\n <StatusIcon status={status} aria-hidden=\"true\" />\n <div className=\"flex flex-col items-start\">\n <span className=\"text-sm font-medium text-foreground\">\n {toolName}\n </span>\n <span className=\"text-xs text-text-quaternary\">\n {statusLabel[status]}\n </span>\n </div>\n </div>\n {isOpen ? (\n <ChevronDown\n className=\"size-4 text-muted-foreground\"\n aria-hidden=\"true\"\n />\n ) : (\n <ChevronRight\n className=\"size-4 text-muted-foreground rtl:rotate-180\"\n aria-hidden=\"true\"\n />\n )}\n </button>\n );\n}\n\nAIToolCallHeader.displayName = 'AIToolCallHeader';\n\n// =============================================================================\n// Tool Call Section\n// =============================================================================\n\ninterface ToolCallSectionProps {\n title: string;\n icon: React.ReactNode;\n children: React.ReactNode;\n className?: string;\n}\n\nfunction ToolCallSection({\n title,\n icon,\n children,\n className,\n}: ToolCallSectionProps) {\n return (\n <div className={cn('space-y-2', className)}>\n <div className=\"flex items-center gap-2 text-xs font-medium text-text-quaternary uppercase tracking-wide\">\n {icon}\n {title}\n </div>\n {children}\n </div>\n );\n}\n\nToolCallSection.displayName = 'ToolCallSection';\n\n// =============================================================================\n// Main AIToolCall Component\n// =============================================================================\n\nexport interface AIToolCallProps extends VariantProps<typeof toolCallVariants> {\n /** Tool call data */\n toolPart: ToolCallPart;\n /** Whether to expand by default */\n defaultOpen?: boolean;\n /** Controlled open state */\n open?: boolean;\n /** Callback when open state changes */\n onOpenChange?: (open: boolean) => void;\n /** Additional class name */\n className?: string;\n}\n\nfunction formatValue(value: unknown): string {\n if (typeof value === 'string') return value;\n return JSON.stringify(value, null, 2);\n}\n\nfunction AIToolCall({\n toolPart,\n defaultOpen = false,\n open: controlledOpen,\n onOpenChange,\n className,\n}: AIToolCallProps) {\n const [isOpen, setIsOpen] = useControllableState({\n value: controlledOpen,\n defaultValue: defaultOpen,\n onChange: onOpenChange,\n });\n\n const status = toolPart.status || 'pending';\n\n const handleToggle = () => {\n setIsOpen(!isOpen);\n };\n\n return (\n <div\n data-slot=\"ai-tool-call\"\n className={cn(toolCallVariants({ status }), className)}\n >\n <AIToolCallHeader\n toolName={toolPart.toolName}\n status={status}\n isOpen={isOpen}\n onToggle={handleToggle}\n />\n\n <AnimatePresence>\n {isOpen && (\n <motion.div\n initial={{ height: 0, opacity: 0 }}\n animate={{ height: 'auto', opacity: 1 }}\n exit={{ height: 0, opacity: 0 }}\n transition={{ duration: 0.2 }}\n className=\"overflow-hidden\"\n >\n <div className=\"px-4 pb-4 space-y-4\">\n {/* Tool Call ID */}\n <div className=\"text-xs text-muted-foreground font-mono\">\n ID: {toolPart.toolCallId}\n </div>\n\n {/* Input Section */}\n {toolPart.args && Object.keys(toolPart.args).length > 0 && (\n <ToolCallSection\n title=\"Input\"\n icon={<Code className=\"size-3\" />}\n >\n <AICodeBlock\n code={formatValue(toolPart.args)}\n language=\"json\"\n showHeader={false}\n showCopyButton={true}\n size=\"sm\"\n />\n </ToolCallSection>\n )}\n\n {/* Output Section */}\n {toolPart.result !== undefined && (\n <ToolCallSection\n title=\"Output\"\n icon={<Code className=\"size-3\" />}\n >\n <AICodeBlock\n code={formatValue(toolPart.result)}\n language=\"json\"\n showHeader={false}\n showCopyButton={true}\n size=\"sm\"\n />\n </ToolCallSection>\n )}\n\n {/* Error Section */}\n {toolPart.error && (\n <div className=\"p-3 rounded-lg bg-destructive/20 border border-destructive/50\">\n <div className=\"flex items-start gap-2\">\n <AlertCircle className=\"size-4 text-destructive mt-0.5 shrink-0\" />\n <p className=\"text-sm text-destructive\">{toolPart.error}</p>\n </div>\n </div>\n )}\n </div>\n </motion.div>\n )}\n </AnimatePresence>\n </div>\n );\n}\n\nAIToolCall.displayName = 'AIToolCall';\n\n// =============================================================================\n// Tool Call List Component\n// =============================================================================\n\nexport interface AIToolCallListProps {\n /** Array of tool calls */\n toolCalls: readonly ToolCallPart[];\n /** Whether to expand all by default */\n defaultAllOpen?: boolean;\n /** Tool-call IDs to expand initially in uncontrolled mode */\n defaultOpenToolCallIds?: readonly string[];\n /** Controlled expanded tool-call IDs */\n openToolCallIds?: readonly string[];\n /** Called with expanded IDs in current tool-call order */\n onOpenToolCallIdsChange?: (ids: readonly string[]) => void;\n /** Additional class name */\n className?: string;\n}\n\nfunction normalizeOpenToolCallIds(\n ids: readonly string[],\n toolCalls: readonly ToolCallPart[],\n): string[] {\n const requested = new Set(ids);\n return toolCalls.flatMap((toolCall) =>\n requested.has(toolCall.toolCallId) ? [toolCall.toolCallId] : [],\n );\n}\n\nfunction areToolCallIdsEqual(\n left: readonly string[],\n right: readonly string[],\n): boolean {\n return (\n left.length === right.length &&\n left.every((id, index) => id === right[index])\n );\n}\n\nfunction AIToolCallList({\n toolCalls,\n defaultAllOpen = false,\n defaultOpenToolCallIds = [],\n openToolCallIds: controlledOpenToolCallIds,\n onOpenToolCallIdsChange,\n className,\n}: AIToolCallListProps) {\n const isControlled = controlledOpenToolCallIds !== undefined;\n const [uncontrolledOpenToolCallIds, setUncontrolledOpenToolCallIds] =\n React.useState<readonly string[]>(() =>\n normalizeOpenToolCallIds(\n defaultAllOpen\n ? toolCalls.map((toolCall) => toolCall.toolCallId)\n : defaultOpenToolCallIds,\n toolCalls,\n ),\n );\n const rawOpenToolCallIds = isControlled\n ? controlledOpenToolCallIds\n : uncontrolledOpenToolCallIds;\n const visibleOpenToolCallIds = normalizeOpenToolCallIds(\n rawOpenToolCallIds,\n toolCalls,\n );\n const openSet = new Set(visibleOpenToolCallIds);\n\n React.useLayoutEffect(() => {\n if (isControlled) return;\n setUncontrolledOpenToolCallIds((current) => {\n const normalized = normalizeOpenToolCallIds(current, toolCalls);\n return areToolCallIdsEqual(current, normalized) ? current : normalized;\n });\n }, [isControlled, toolCalls]);\n\n const setToolCallOpen = (toolCallId: string, open: boolean) => {\n const next = new Set(visibleOpenToolCallIds);\n if (open) next.add(toolCallId);\n else next.delete(toolCallId);\n const normalized = normalizeOpenToolCallIds([...next], toolCalls);\n if (!isControlled) {\n setUncontrolledOpenToolCallIds(normalized);\n }\n onOpenToolCallIdsChange?.([...normalized]);\n };\n\n return (\n <div data-slot=\"ai-tool-call-list\" className={cn('space-y-2', className)}>\n {toolCalls.map((toolCall) => (\n <AIToolCall\n key={toolCall.toolCallId}\n toolPart={toolCall}\n open={openSet.has(toolCall.toolCallId)}\n onOpenChange={(open) => setToolCallOpen(toolCall.toolCallId, open)}\n />\n ))}\n </div>\n );\n}\n\nAIToolCallList.displayName = 'AIToolCallList';\n\nexport {\n AIToolCall,\n AIToolCallHeader,\n AIToolCallList,\n StatusIcon,\n statusIconVariants,\n ToolCallSection,\n toolCallVariants,\n};\n"],"mappings":"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"}
|
|
1
|
+
{"version":3,"file":"index184.js","names":[],"sources":["../src/components/organisms/ai/AIToolCall/AIToolCall.tsx"],"sourcesContent":["import { cva, type VariantProps } from 'class-variance-authority';\nimport {\n AlertCircle,\n Check,\n ChevronDown,\n ChevronRight,\n Clock,\n Code,\n Wrench,\n} from 'lucide-react';\nimport { AnimatePresence, motion } from 'motion/react';\nimport * as React from 'react';\nimport { AICodeBlock } from '@/components/organisms/ai/AICodeBlock';\nimport { useControllableState } from '@/hooks/use-controllable-state';\nimport { cn } from '@/lib/utils';\n\n// =============================================================================\n// Variants\n// =============================================================================\n\nconst toolCallVariants = cva(\n 'overflow-hidden rounded-xl border transition-colors',\n {\n variants: {\n status: {\n pending: 'border-border bg-muted',\n running: 'border-primary bg-primary/10',\n success: 'border-success/50 bg-success/10',\n error: 'border-destructive/50 bg-destructive/10',\n },\n },\n defaultVariants: {\n status: 'pending',\n },\n },\n);\n\nconst statusIconVariants = cva('size-4', {\n variants: {\n status: {\n pending: 'text-muted-foreground',\n running: 'text-primary animate-spin motion-reduce:animate-none',\n success: 'text-success',\n error: 'text-destructive',\n },\n },\n defaultVariants: {\n status: 'pending',\n },\n});\n\n// =============================================================================\n// Types\n// =============================================================================\n\nexport type ToolCallStatus = 'pending' | 'running' | 'success' | 'error';\n\nexport interface ToolCallPart {\n /** Unique tool call ID */\n toolCallId: string;\n /** Tool name */\n toolName: string;\n /** Tool input/arguments */\n args?: Record<string, unknown>;\n /** Tool output/result */\n result?: unknown;\n /** Tool status */\n status?: ToolCallStatus;\n /** Error message if status is error */\n error?: string;\n}\n\n// =============================================================================\n// Status Icon Component\n// =============================================================================\n\ninterface StatusIconProps {\n status: ToolCallStatus;\n className?: string;\n}\n\nfunction StatusIcon({ status, className }: StatusIconProps) {\n const iconClass = cn(statusIconVariants({ status }), className);\n\n switch (status) {\n case 'running':\n return <Clock className={iconClass} />;\n case 'success':\n return (\n <Check\n className={cn(\n iconClass,\n 'delight-check-bounce motion-reduce:!animate-none',\n )}\n />\n );\n case 'error':\n return (\n <AlertCircle\n className={cn(iconClass, 'delight-shake motion-reduce:!animate-none')}\n />\n );\n default:\n return <Wrench className={iconClass} />;\n }\n}\n\nStatusIcon.displayName = 'StatusIcon';\n\n// =============================================================================\n// Tool Call Header\n// =============================================================================\n\ninterface AIToolCallHeaderProps {\n toolName: string;\n status: ToolCallStatus;\n isOpen: boolean;\n onToggle: () => void;\n className?: string;\n}\n\nfunction AIToolCallHeader({\n toolName,\n status,\n isOpen,\n onToggle,\n className,\n}: AIToolCallHeaderProps) {\n const statusLabel = {\n pending: 'Pending',\n running: 'Running...',\n success: 'Completed',\n error: 'Failed',\n };\n\n return (\n <button\n type=\"button\"\n onClick={onToggle}\n aria-expanded={isOpen}\n className={cn(\n 'flex items-center justify-between w-full px-4 py-3 transition-colors hover:bg-foreground/5 focus-visible:outline-2 focus-visible:outline-offset-[-2px] focus-visible:outline-ring',\n className,\n )}\n >\n <div className=\"flex items-center gap-3\">\n <StatusIcon status={status} aria-hidden=\"true\" />\n <div className=\"flex flex-col items-start\">\n <span className=\"text-sm font-medium text-foreground\">\n {toolName}\n </span>\n <span className=\"text-xs text-secondary-foreground\">\n {statusLabel[status]}\n </span>\n </div>\n </div>\n {isOpen ? (\n <ChevronDown\n className=\"size-4 text-muted-foreground\"\n aria-hidden=\"true\"\n />\n ) : (\n <ChevronRight\n className=\"size-4 text-muted-foreground rtl:rotate-180\"\n aria-hidden=\"true\"\n />\n )}\n </button>\n );\n}\n\nAIToolCallHeader.displayName = 'AIToolCallHeader';\n\n// =============================================================================\n// Tool Call Section\n// =============================================================================\n\ninterface ToolCallSectionProps {\n title: string;\n icon: React.ReactNode;\n children: React.ReactNode;\n className?: string;\n}\n\nfunction ToolCallSection({\n title,\n icon,\n children,\n className,\n}: ToolCallSectionProps) {\n return (\n <div className={cn('space-y-2', className)}>\n <div className=\"flex items-center gap-2 text-xs font-medium text-text-quaternary uppercase tracking-wide\">\n {icon}\n {title}\n </div>\n {children}\n </div>\n );\n}\n\nToolCallSection.displayName = 'ToolCallSection';\n\n// =============================================================================\n// Main AIToolCall Component\n// =============================================================================\n\nexport interface AIToolCallProps extends VariantProps<typeof toolCallVariants> {\n /** Tool call data */\n toolPart: ToolCallPart;\n /** Whether to expand by default */\n defaultOpen?: boolean;\n /** Controlled open state */\n open?: boolean;\n /** Callback when open state changes */\n onOpenChange?: (open: boolean) => void;\n /** Additional class name */\n className?: string;\n}\n\nfunction formatValue(value: unknown): string {\n if (typeof value === 'string') return value;\n return JSON.stringify(value, null, 2);\n}\n\nfunction AIToolCall({\n toolPart,\n defaultOpen = false,\n open: controlledOpen,\n onOpenChange,\n className,\n}: AIToolCallProps) {\n const [isOpen, setIsOpen] = useControllableState({\n value: controlledOpen,\n defaultValue: defaultOpen,\n onChange: onOpenChange,\n });\n\n const status = toolPart.status || 'pending';\n\n const handleToggle = () => {\n setIsOpen(!isOpen);\n };\n\n return (\n <div\n data-slot=\"ai-tool-call\"\n className={cn(toolCallVariants({ status }), className)}\n >\n <AIToolCallHeader\n toolName={toolPart.toolName}\n status={status}\n isOpen={isOpen}\n onToggle={handleToggle}\n />\n\n <AnimatePresence>\n {isOpen && (\n <motion.div\n initial={{ height: 0, opacity: 0 }}\n animate={{ height: 'auto', opacity: 1 }}\n exit={{ height: 0, opacity: 0 }}\n transition={{ duration: 0.2 }}\n className=\"overflow-hidden\"\n >\n <div className=\"px-4 pb-4 space-y-4\">\n {/* Tool Call ID */}\n <div className=\"text-xs text-muted-foreground font-mono\">\n ID: {toolPart.toolCallId}\n </div>\n\n {/* Input Section */}\n {toolPart.args && Object.keys(toolPart.args).length > 0 && (\n <ToolCallSection\n title=\"Input\"\n icon={<Code className=\"size-3\" />}\n >\n <AICodeBlock\n code={formatValue(toolPart.args)}\n language=\"json\"\n showHeader={false}\n showCopyButton={true}\n size=\"sm\"\n />\n </ToolCallSection>\n )}\n\n {/* Output Section */}\n {toolPart.result !== undefined && (\n <ToolCallSection\n title=\"Output\"\n icon={<Code className=\"size-3\" />}\n >\n <AICodeBlock\n code={formatValue(toolPart.result)}\n language=\"json\"\n showHeader={false}\n showCopyButton={true}\n size=\"sm\"\n />\n </ToolCallSection>\n )}\n\n {/* Error Section */}\n {toolPart.error && (\n <div className=\"p-3 rounded-lg bg-destructive/20 border border-destructive/50\">\n <div className=\"flex items-start gap-2\">\n <AlertCircle className=\"size-4 text-destructive mt-0.5 shrink-0\" />\n <p className=\"text-sm text-destructive\">{toolPart.error}</p>\n </div>\n </div>\n )}\n </div>\n </motion.div>\n )}\n </AnimatePresence>\n </div>\n );\n}\n\nAIToolCall.displayName = 'AIToolCall';\n\n// =============================================================================\n// Tool Call List Component\n// =============================================================================\n\nexport interface AIToolCallListProps {\n /** Array of tool calls */\n toolCalls: readonly ToolCallPart[];\n /** Whether to expand all by default */\n defaultAllOpen?: boolean;\n /** Tool-call IDs to expand initially in uncontrolled mode */\n defaultOpenToolCallIds?: readonly string[];\n /** Controlled expanded tool-call IDs */\n openToolCallIds?: readonly string[];\n /** Called with expanded IDs in current tool-call order */\n onOpenToolCallIdsChange?: (ids: readonly string[]) => void;\n /** Additional class name */\n className?: string;\n}\n\nfunction normalizeOpenToolCallIds(\n ids: readonly string[],\n toolCalls: readonly ToolCallPart[],\n): string[] {\n const requested = new Set(ids);\n return toolCalls.flatMap((toolCall) =>\n requested.has(toolCall.toolCallId) ? [toolCall.toolCallId] : [],\n );\n}\n\nfunction areToolCallIdsEqual(\n left: readonly string[],\n right: readonly string[],\n): boolean {\n return (\n left.length === right.length &&\n left.every((id, index) => id === right[index])\n );\n}\n\nfunction AIToolCallList({\n toolCalls,\n defaultAllOpen = false,\n defaultOpenToolCallIds = [],\n openToolCallIds: controlledOpenToolCallIds,\n onOpenToolCallIdsChange,\n className,\n}: AIToolCallListProps) {\n const isControlled = controlledOpenToolCallIds !== undefined;\n const [uncontrolledOpenToolCallIds, setUncontrolledOpenToolCallIds] =\n React.useState<readonly string[]>(() =>\n normalizeOpenToolCallIds(\n defaultAllOpen\n ? toolCalls.map((toolCall) => toolCall.toolCallId)\n : defaultOpenToolCallIds,\n toolCalls,\n ),\n );\n const rawOpenToolCallIds = isControlled\n ? controlledOpenToolCallIds\n : uncontrolledOpenToolCallIds;\n const visibleOpenToolCallIds = normalizeOpenToolCallIds(\n rawOpenToolCallIds,\n toolCalls,\n );\n const openSet = new Set(visibleOpenToolCallIds);\n\n React.useLayoutEffect(() => {\n if (isControlled) return;\n setUncontrolledOpenToolCallIds((current) => {\n const normalized = normalizeOpenToolCallIds(current, toolCalls);\n return areToolCallIdsEqual(current, normalized) ? current : normalized;\n });\n }, [isControlled, toolCalls]);\n\n const setToolCallOpen = (toolCallId: string, open: boolean) => {\n const next = new Set(visibleOpenToolCallIds);\n if (open) next.add(toolCallId);\n else next.delete(toolCallId);\n const normalized = normalizeOpenToolCallIds([...next], toolCalls);\n if (!isControlled) {\n setUncontrolledOpenToolCallIds(normalized);\n }\n onOpenToolCallIdsChange?.([...normalized]);\n };\n\n return (\n <div data-slot=\"ai-tool-call-list\" className={cn('space-y-2', className)}>\n {toolCalls.map((toolCall) => (\n <AIToolCall\n key={toolCall.toolCallId}\n toolPart={toolCall}\n open={openSet.has(toolCall.toolCallId)}\n onOpenChange={(open) => setToolCallOpen(toolCall.toolCallId, open)}\n />\n ))}\n </div>\n );\n}\n\nAIToolCallList.displayName = 'AIToolCallList';\n\nexport {\n AIToolCall,\n AIToolCallHeader,\n AIToolCallList,\n StatusIcon,\n statusIconVariants,\n ToolCallSection,\n toolCallVariants,\n};\n"],"mappings":"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"}
|
package/dist/index217.js
CHANGED
|
@@ -2,7 +2,7 @@
|
|
|
2
2
|
/** Canonical expanded width shared by AppSidebar and AppShell.Sidebar. */
|
|
3
3
|
var APP_SIDEBAR_EXPANDED_WIDTH = "280px";
|
|
4
4
|
/** Canonical collapsed width shared by AppSidebar and AppShell.Sidebar. */
|
|
5
|
-
var APP_SIDEBAR_COLLAPSED_WIDTH = "
|
|
5
|
+
var APP_SIDEBAR_COLLAPSED_WIDTH = "68px";
|
|
6
6
|
//#endregion
|
|
7
7
|
export { APP_SIDEBAR_COLLAPSED_WIDTH, APP_SIDEBAR_EXPANDED_WIDTH };
|
|
8
8
|
|
package/dist/index217.js.map
CHANGED
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"index217.js","names":[],"sources":["../src/components/templates/AppSidebar/AppSidebar.constants.ts"],"sourcesContent":["/** Canonical expanded width shared by AppSidebar and AppShell.Sidebar. */\nexport const APP_SIDEBAR_EXPANDED_WIDTH = '280px';\n\n/** Canonical collapsed width shared by AppSidebar and AppShell.Sidebar. */\nexport const APP_SIDEBAR_COLLAPSED_WIDTH = '
|
|
1
|
+
{"version":3,"file":"index217.js","names":[],"sources":["../src/components/templates/AppSidebar/AppSidebar.constants.ts"],"sourcesContent":["/** Canonical expanded width shared by AppSidebar and AppShell.Sidebar. */\nexport const APP_SIDEBAR_EXPANDED_WIDTH = '280px';\n\n/** Canonical collapsed width shared by AppSidebar and AppShell.Sidebar. */\nexport const APP_SIDEBAR_COLLAPSED_WIDTH = '68px';\n"],"mappings":";;AACA,IAAa,6BAA6B;;AAG1C,IAAa,8BAA8B"}
|
package/dist/index223.js.map
CHANGED
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"index223.js","names":[],"sources":["../src/components/templates/AppShell/AppShell.tsx"],"sourcesContent":["'use client';\n\nimport * as React from 'react';\nimport type { GroupImperativeHandle } from 'react-resizable-panels';\nimport {\n ResizableHandle,\n ResizablePanel,\n ResizablePanelGroup,\n} from '@/components/atoms/layout/Resizable';\nimport { AppShell as AppShellPrimitive } from '@/components/ui/app-shell';\n\nimport { Sheet, SheetContent } from '@/components/ui/sheet';\nimport { SidebarContext } from '@/components/ui/sidebar';\nimport { useIsMobile } from '@/hooks/use-mobile';\nimport { cn } from '@/lib/utils';\nimport {\n APP_SIDEBAR_COLLAPSED_WIDTH,\n APP_SIDEBAR_EXPANDED_WIDTH,\n} from '../AppSidebar/AppSidebar.constants';\nimport { AppShellContent } from './AppShellContent';\nimport {\n type AppShellContextValue,\n AppShellProvider,\n PanelIndexContext,\n PanelLayoutContext,\n type PanelLayoutInfo,\n type PanelPosition,\n} from './AppShellContext';\nimport { AppShellMobileTabBar } from './AppShellMobileTabBar';\nimport {\n APPSHELL_PANEL_TYPE,\n AppShellPanel,\n type AppShellPanelComponent,\n type AppShellPanelProps,\n} from './AppShellPanel';\nimport {\n DEFAULT_EXPAND_THRESHOLD,\n getExpandedPanelFromLayout,\n layoutMapToTuple,\n normalizePanelSizes,\n toResizableMinSize,\n toResizablePercentageSize,\n} from './AppShellResize';\n\nconst DEFAULT_APP_SHELL_BACKGROUND = 'var(--app-background)';\n\ninterface AppShellPanelMarker {\n __appShellType?: unknown;\n}\n\nfunction isAppShellPanelComponent(\n type: unknown,\n): type is AppShellPanelComponent {\n return (\n typeof type === 'function' &&\n (type as AppShellPanelMarker).__appShellType === APPSHELL_PANEL_TYPE\n );\n}\n\nfunction isAppShellPanelElement(\n child: React.ReactNode,\n): child is React.ReactElement<AppShellPanelProps, AppShellPanelComponent> {\n return React.isValidElement(child) && isAppShellPanelComponent(child.type);\n}\n\nfunction getAppShellPanelIdentity(\n panel: React.ReactElement<AppShellPanelProps>,\n ariaBaseId: string,\n index: number,\n): React.Key {\n return panel.key ?? panel.props.label ?? `${ariaBaseId}-panel-${index}`;\n}\n\ninterface AppShellPanelWithLayoutProps {\n panel: React.ReactElement<AppShellPanelProps>;\n visible: boolean;\n index: number;\n overrides?: Partial<PanelLayoutInfo>;\n isMobile: boolean;\n activePanel: number;\n hasExpanded: boolean;\n hasTabBar: boolean;\n ariaBaseId: string;\n rootExpansionActive: boolean;\n firstExpandedIndex: number | null;\n onExpandedPanelChange: (panelIndex: number | null) => void;\n}\n\nfunction AppShellPanelWithLayout({\n panel,\n visible,\n index,\n overrides = {},\n isMobile,\n activePanel,\n hasExpanded,\n hasTabBar,\n ariaBaseId,\n rootExpansionActive,\n firstExpandedIndex,\n onExpandedPanelChange,\n}: AppShellPanelWithLayoutProps) {\n if (isMobile && index !== activePanel) return null;\n\n const layoutInfo: PanelLayoutInfo = {\n visible: isMobile ? true : visible,\n collapseMode: hasExpanded ? 'animated' : 'removed',\n isMobile,\n tabId: hasTabBar ? `${ariaBaseId}-tab-${index}` : undefined,\n panelId: hasTabBar ? `${ariaBaseId}-tabpanel-${index}` : undefined,\n expanded: rootExpansionActive\n ? hasExpanded && index === firstExpandedIndex\n : undefined,\n onExpandedChange: rootExpansionActive\n ? (nextExpanded) => onExpandedPanelChange(nextExpanded ? index : null)\n : undefined,\n ...overrides,\n };\n\n return (\n <PanelIndexContext.Provider value={index}>\n <PanelLayoutContext.Provider value={layoutInfo}>\n {panel}\n </PanelLayoutContext.Provider>\n </PanelIndexContext.Provider>\n );\n}\n\n// ============================================\n// AppShell Root\n// ============================================\n\nexport interface AppShellProps extends React.ComponentProps<'div'> {\n /** Any CSS background value (color, gradient, image). Defaults to var(--app-background). */\n background?: string;\n /** Fixed height, supports CSS calc() */\n height?: string;\n /** Spacing around the inner content in pixels or CSS value */\n padding?: number | string;\n /** Padding on mobile viewports. Defaults to 8px. */\n mobilePadding?: number | string;\n /** Gap between panels in pixels or CSS value. Defaults to 12. */\n gap?: number | string;\n /** Joined-edge mode where panels share borders. Defaults to false. */\n connected?: boolean;\n /** ID of the main content element for skip navigation. */\n skipToId?: string;\n /** Controlled active panel index for mobile tab switching. */\n activePanel?: number;\n /** Callback when active panel changes on mobile. */\n onActivePanelChange?: (index: number) => void;\n /** Default active panel on mobile (default: 0). */\n defaultActivePanel?: number;\n /** Controlled expanded panel index. Use null for no expanded panel. */\n expandedPanel?: number | null;\n /** Initial expanded panel index for uncontrolled root-owned expansion. */\n defaultExpandedPanel?: number | null;\n /** Callback when root-owned expansion changes. */\n onExpandedPanelChange?: (panelIndex: number | null) => void;\n /** Enables root-owned two-panel resizing on desktop. Defaults to true for eligible two-panel layouts. */\n resizablePanels?: boolean;\n /** Initial panel size split in percentages. Defaults to [35, 65]. */\n defaultPanelSizes?: [number, number];\n /** Controlled panel size split in percentages. */\n panelSizes?: [number, number];\n /** Called after the user releases the resize handle. */\n onPanelSizesChange?: (sizes: [number, number]) => void;\n /** Percentage threshold that expands the dominant panel on release. */\n expandThreshold?: number;\n}\n\nfunction AppShellRoot({\n background = DEFAULT_APP_SHELL_BACKGROUND,\n height = '100dvh',\n padding = 16,\n mobilePadding,\n gap = 12,\n connected = false,\n skipToId,\n activePanel: activePanelProp,\n onActivePanelChange,\n defaultActivePanel = 0,\n expandedPanel: expandedPanelProp,\n defaultExpandedPanel,\n onExpandedPanelChange,\n resizablePanels,\n defaultPanelSizes,\n panelSizes,\n onPanelSizesChange,\n expandThreshold = DEFAULT_EXPAND_THRESHOLD,\n className,\n children,\n ...props\n}: AppShellProps): React.ReactElement {\n const isMobile = useIsMobile();\n const ariaBaseId = React.useId();\n const [internalActivePanel, setInternalActivePanel] =\n React.useState(defaultActivePanel);\n const [internalExpandedPanel, setInternalExpandedPanel] = React.useState<\n number | null\n >(defaultExpandedPanel ?? null);\n const [internalPanelSizes, setInternalPanelSizes] = React.useState(() =>\n normalizePanelSizes(defaultPanelSizes),\n );\n const [isResizingPanels, setIsResizingPanels] = React.useState(false);\n const [isRestoringResizablePanels, setIsRestoringResizablePanels] =\n React.useState(false);\n const [internalMobileSidebarOpen, setInternalMobileSidebarOpen] =\n React.useState(false);\n const resizableGroupRef = React.useRef<GroupImperativeHandle | null>(null);\n const rootRef = React.useRef<HTMLDivElement>(null);\n const allowResizeReleaseExpansionRef = React.useRef(false);\n const suppressControlledLayoutChangeRef = React.useRef(false);\n const previousResizableExpandedRef = React.useRef(false);\n\n const activePanel = activePanelProp ?? internalActivePanel;\n const handleActivePanelChange = React.useCallback(\n (index: number) => {\n if (activePanelProp === undefined) {\n setInternalActivePanel((prev) => (prev === index ? prev : index));\n }\n onActivePanelChange?.(index);\n },\n [activePanelProp, onActivePanelChange],\n );\n\n const rootExpansionRequested =\n expandedPanelProp !== undefined ||\n defaultExpandedPanel !== undefined ||\n onExpandedPanelChange !== undefined;\n const resolvedExpandedPanel =\n expandedPanelProp !== undefined ? expandedPanelProp : internalExpandedPanel;\n const handleExpandedPanelChange = React.useCallback(\n (panelIndex: number | null) => {\n if (expandedPanelProp === undefined) {\n setInternalExpandedPanel(panelIndex);\n }\n onExpandedPanelChange?.(panelIndex);\n },\n [expandedPanelProp, onExpandedPanelChange],\n );\n\n // Classify children (memoized to stabilize downstream references)\n const { panels, panelInfos, sidebarChild, otherChildren } =\n React.useMemo(() => {\n const p: React.ReactElement<AppShellPanelProps>[] = [];\n const infos: { key?: React.Key; label?: string }[] = [];\n let sidebar: React.ReactNode = null;\n const other: React.ReactNode[] = [];\n\n React.Children.forEach(children, (child) => {\n if (isAppShellPanelElement(child)) {\n infos.push({\n key: child.key ?? child.props.label,\n label: child.props.label,\n });\n p.push(child);\n return;\n }\n\n if (!React.isValidElement(child)) {\n return;\n }\n\n if (child.type === AppShellSidebar) {\n sidebar = child;\n } else {\n other.push(child);\n }\n });\n\n return {\n panels: p,\n panelInfos: infos,\n sidebarChild: sidebar,\n otherChildren: other,\n };\n }, [children]);\n\n const shouldUseResizablePanels = resizablePanels ?? true;\n\n // Determine which panels are visible\n const firstPanelExpandedIndex = panels.findIndex((p) => p.props.expanded);\n const hasPanelExpansionProps = panels.some(\n (panel) =>\n panel.props.expanded !== undefined ||\n panel.props.onExpandedChange !== undefined,\n );\n const canUseResizablePanelPair =\n shouldUseResizablePanels &&\n !connected &&\n !isMobile &&\n panels.length === 2 &&\n (resizablePanels !== undefined || !hasPanelExpansionProps);\n const rootExpansionActive =\n rootExpansionRequested || canUseResizablePanelPair;\n const validRootExpandedPanel =\n typeof resolvedExpandedPanel === 'number' &&\n Number.isInteger(resolvedExpandedPanel) &&\n resolvedExpandedPanel >= 0 &&\n resolvedExpandedPanel < panels.length\n ? resolvedExpandedPanel\n : null;\n let firstExpandedIndex: number | null = firstPanelExpandedIndex;\n if (rootExpansionActive) {\n firstExpandedIndex = validRootExpandedPanel;\n }\n const hasExpanded = firstExpandedIndex !== -1 && firstExpandedIndex !== null;\n const visibleCount = hasExpanded ? 1 : Math.min(panels.length, 2);\n const canRenderResizablePanels = canUseResizablePanelPair;\n const resolvedPanelSizes = React.useMemo(\n () => normalizePanelSizes(panelSizes ?? internalPanelSizes),\n [panelSizes, internalPanelSizes],\n );\n const resizablePanelSizes = React.useMemo<[number, number]>(() => {\n if (hasExpanded && firstExpandedIndex === 0) return [100, 0];\n if (hasExpanded && firstExpandedIndex === 1) return [0, 100];\n return resolvedPanelSizes;\n }, [firstExpandedIndex, hasExpanded, resolvedPanelSizes]);\n const shouldBypassResizableMinSize =\n hasExpanded ||\n isRestoringResizablePanels ||\n (!hasExpanded && previousResizableExpandedRef.current);\n\n // Dev warnings\n if (process.env.NODE_ENV !== 'production') {\n const expandedPanelPropCount = panels.filter(\n (p) => p.props.expanded,\n ).length;\n if (rootExpansionActive && expandedPanelPropCount > 0) {\n console.warn(\n 'AppShell.Root: root-owned expansion props should not be mixed with AppShell.Panel expanded. Root expansion will be used.',\n );\n }\n if (!rootExpansionActive && expandedPanelPropCount > 1) {\n console.warn(\n 'AppShell.Root: multiple panels have expanded={true}. Only the first expanded panel will be shown.',\n );\n }\n if (\n rootExpansionActive &&\n resolvedExpandedPanel !== null &&\n resolvedExpandedPanel !== undefined &&\n validRootExpandedPanel === null\n ) {\n console.warn(\n `AppShell.Root: expandedPanel index ${resolvedExpandedPanel} is out of range. No panel will be expanded.`,\n );\n }\n if (resizablePanels === true && connected) {\n console.warn(\n 'AppShell.Root: resizablePanels is not supported with connected. Rendering non-resizable panels.',\n );\n }\n if (resizablePanels === true && !connected && panels.length !== 2) {\n console.warn(\n `AppShell.Root: resizablePanels requires exactly 2 Panel children, got ${panels.length}. Rendering non-resizable panels.`,\n );\n }\n if (panels.length > 2 && !hasExpanded) {\n console.warn(\n `AppShell.Root: max 2 Panel children allowed, got ${panels.length}. Only the first 2 will be visible.`,\n );\n }\n }\n\n const handleLayoutChange = React.useCallback(\n (layout: Record<string, number>) => {\n if (hasExpanded || suppressControlledLayoutChangeRef.current) {\n return;\n }\n if (panelSizes === undefined) {\n setInternalPanelSizes(layoutMapToTuple(layout));\n }\n },\n [hasExpanded, panelSizes],\n );\n\n const handleLayoutChanged = React.useCallback(\n (layout: Record<string, number>) => {\n if (\n hasExpanded ||\n !allowResizeReleaseExpansionRef.current ||\n suppressControlledLayoutChangeRef.current\n ) {\n return;\n }\n\n const nextSizes = layoutMapToTuple(layout);\n if (panelSizes === undefined) {\n setInternalPanelSizes(nextSizes);\n }\n onPanelSizesChange?.(nextSizes);\n\n const expandedIndex = getExpandedPanelFromLayout(layout, expandThreshold);\n if (expandedIndex !== null) {\n handleExpandedPanelChange(expandedIndex);\n }\n },\n [\n expandThreshold,\n handleExpandedPanelChange,\n hasExpanded,\n onPanelSizesChange,\n panelSizes,\n ],\n );\n\n React.useEffect(() => {\n if (!canRenderResizablePanels) {\n suppressControlledLayoutChangeRef.current = false;\n previousResizableExpandedRef.current = false;\n return;\n }\n\n const ownerWindow = rootRef.current?.ownerDocument.defaultView;\n if (!ownerWindow) return;\n\n const wasExpanded = previousResizableExpandedRef.current;\n previousResizableExpandedRef.current = hasExpanded;\n const shouldApplyLayout =\n hasExpanded || wasExpanded || panelSizes !== undefined;\n if (!shouldApplyLayout) {\n suppressControlledLayoutChangeRef.current = false;\n return;\n }\n\n let restoreFrame: number | undefined;\n const [first, second] = resizablePanelSizes;\n if (wasExpanded && !hasExpanded) {\n restoreFrame = ownerWindow.requestAnimationFrame(() => {\n setIsRestoringResizablePanels(true);\n });\n }\n suppressControlledLayoutChangeRef.current = true;\n const nextLayout = { panel0: first, panel1: second };\n resizableGroupRef.current?.setLayout(nextLayout);\n const frame = ownerWindow.requestAnimationFrame(() => {\n resizableGroupRef.current?.setLayout(nextLayout);\n });\n const timeout = ownerWindow.setTimeout(() => {\n suppressControlledLayoutChangeRef.current = false;\n }, 350);\n return () => {\n if (restoreFrame !== undefined) {\n ownerWindow.cancelAnimationFrame(restoreFrame);\n }\n ownerWindow.cancelAnimationFrame(frame);\n ownerWindow.clearTimeout(timeout);\n suppressControlledLayoutChangeRef.current = false;\n };\n }, [canRenderResizablePanels, hasExpanded, panelSizes, resizablePanelSizes]);\n\n React.useEffect(() => {\n if (!isRestoringResizablePanels) return;\n\n const ownerWindow = rootRef.current?.ownerDocument.defaultView;\n if (!ownerWindow) return;\n\n const timeout = ownerWindow.setTimeout(() => {\n setIsRestoringResizablePanels(false);\n }, 350);\n return () => ownerWindow.clearTimeout(timeout);\n }, [isRestoringResizablePanels]);\n\n React.useEffect(() => {\n if (!canRenderResizablePanels) {\n allowResizeReleaseExpansionRef.current = false;\n suppressControlledLayoutChangeRef.current = false;\n return;\n }\n\n const ownerWindow = rootRef.current?.ownerDocument.defaultView;\n if (!ownerWindow) return;\n\n const frame = ownerWindow.requestAnimationFrame(() => {\n allowResizeReleaseExpansionRef.current = true;\n });\n return () => {\n ownerWindow.cancelAnimationFrame(frame);\n allowResizeReleaseExpansionRef.current = false;\n };\n }, [canRenderResizablePanels]);\n\n React.useEffect(() => {\n if (!isResizingPanels) return;\n const ownerWindow = rootRef.current?.ownerDocument.defaultView;\n if (!ownerWindow) return;\n\n const stopResizing = () => setIsResizingPanels(false);\n ownerWindow.addEventListener('pointerup', stopResizing);\n ownerWindow.addEventListener('pointercancel', stopResizing);\n return () => {\n ownerWindow.removeEventListener('pointerup', stopResizing);\n ownerWindow.removeEventListener('pointercancel', stopResizing);\n };\n }, [isResizingPanels]);\n\n const handleResizablePointerDownCapture = React.useCallback(\n (event: React.PointerEvent<HTMLDivElement>) => {\n const target = event.target;\n if (!(target instanceof Element)) return;\n if (target.closest('[data-slot=\"resizable-handle\"]')) {\n setIsResizingPanels(true);\n }\n },\n [],\n );\n\n // Memoize the visibility map to stabilize downstream context values\n const visiblePanels = React.useMemo(\n () =>\n hasExpanded\n ? panels.map((panel, i) => ({\n panel,\n visible: i === firstExpandedIndex,\n index: i,\n }))\n : panels.map((panel, i) => ({\n panel,\n visible: i < 2,\n index: i,\n })),\n [panels, hasExpanded, firstExpandedIndex],\n );\n\n // Whether the tab bar is active (mobile with 2+ panels)\n const hasTabBar = isMobile && panels.length > 1;\n\n // Build context (derive position from stable scalars, not array reference)\n const getPanelPosition = React.useCallback(\n (index: number): PanelPosition => {\n if (visibleCount === 1) return 'only';\n if (hasExpanded) return index === firstExpandedIndex ? 'only' : 'last';\n return index === 0 ? 'first' : 'last';\n },\n [visibleCount, hasExpanded, firstExpandedIndex],\n );\n\n const contextValue: AppShellContextValue = React.useMemo(\n () => ({\n connected,\n panelCount: visibleCount,\n getPanelPosition,\n }),\n [connected, visibleCount, getPanelPosition],\n );\n\n // Sidebar context for mobile drawer integration\n const sidebarContext = React.useContext(SidebarContext);\n const mobileSidebarOpen =\n sidebarContext?.openMobile ?? internalMobileSidebarOpen;\n const setMobileSidebarOpen =\n sidebarContext?.setOpenMobile ?? setInternalMobileSidebarOpen;\n const handleSidebarOpen = React.useCallback(() => {\n setMobileSidebarOpen(true);\n }, [setMobileSidebarOpen]);\n\n const handleSheetOpenChange = React.useCallback(\n (open: boolean) => {\n setMobileSidebarOpen(open);\n },\n [setMobileSidebarOpen],\n );\n\n // Skip navigation link\n const skipLink = skipToId ? (\n <a\n href={`#${skipToId}`}\n className=\"sr-only focus:not-sr-only focus:fixed focus:left-4 focus:top-4 focus:z-50 focus:rounded-md focus:bg-background focus:px-4 focus:py-2 focus:text-sm focus:font-medium focus:text-foreground focus:shadow-sm focus:ring-2 focus:ring-ring\"\n >\n Skip to content\n </a>\n ) : null;\n\n // Render panels with context providers (no cloneElement — panels self-style)\n const renderedPanels = React.useMemo(\n () =>\n visiblePanels.map(({ panel, visible, index }) => (\n <AppShellPanelWithLayout\n key={getAppShellPanelIdentity(panel, ariaBaseId, index)}\n panel={panel}\n visible={visible}\n index={index}\n isMobile={isMobile}\n activePanel={activePanel}\n hasExpanded={hasExpanded}\n hasTabBar={hasTabBar}\n ariaBaseId={ariaBaseId}\n rootExpansionActive={rootExpansionActive}\n firstExpandedIndex={firstExpandedIndex}\n onExpandedPanelChange={handleExpandedPanelChange}\n />\n )),\n [\n visiblePanels,\n ariaBaseId,\n isMobile,\n activePanel,\n hasExpanded,\n hasTabBar,\n rootExpansionActive,\n firstExpandedIndex,\n handleExpandedPanelChange,\n ],\n );\n\n const renderedResizablePanels = canRenderResizablePanels ? (\n <ResizablePanelGroup\n orientation=\"horizontal\"\n disabled={hasExpanded}\n groupRef={resizableGroupRef}\n onLayoutChange={handleLayoutChange}\n onLayoutChanged={handleLayoutChanged}\n onPointerDownCapture={handleResizablePointerDownCapture}\n className={cn(\n 'min-h-0 min-w-0 flex-1',\n !isResizingPanels &&\n '[&>[data-slot=resizable-panel]]:transition-[flex-grow] [&>[data-slot=resizable-panel]]:duration-300 [&>[data-slot=resizable-panel]]:ease-[cubic-bezier(0.16,1,0.3,1)] motion-reduce:[&>[data-slot=resizable-panel]]:transition-none',\n )}\n >\n <ResizablePanel\n id=\"panel0\"\n defaultSize={toResizablePercentageSize(resizablePanelSizes[0])}\n minSize={\n shouldBypassResizableMinSize\n ? 0\n : toResizableMinSize(panels[0].props.minWidth)\n }\n >\n <AppShellPanelWithLayout\n panel={panels[0]}\n visible={!hasExpanded || firstExpandedIndex === 0}\n index={0}\n overrides={{ sizeManagedByRoot: true }}\n isMobile={isMobile}\n activePanel={activePanel}\n hasExpanded={hasExpanded}\n hasTabBar={hasTabBar}\n ariaBaseId={ariaBaseId}\n rootExpansionActive={rootExpansionActive}\n firstExpandedIndex={firstExpandedIndex}\n onExpandedPanelChange={handleExpandedPanelChange}\n />\n </ResizablePanel>\n <ResizableHandle\n disabled={hasExpanded}\n className={cn(\n 'z-10 min-w-2 shrink-0 cursor-col-resize w-[var(--app-shell-gap,0px)] bg-transparent after:w-2 hover:bg-transparent',\n 'transition-[width,min-width,opacity,background-color] duration-300 ease-[cubic-bezier(0.16,1,0.3,1)] motion-reduce:transition-none',\n hasExpanded && 'min-w-0 w-0 opacity-0 after:w-0 pointer-events-none',\n )}\n />\n <ResizablePanel\n id=\"panel1\"\n defaultSize={toResizablePercentageSize(resizablePanelSizes[1])}\n minSize={\n shouldBypassResizableMinSize\n ? 0\n : toResizableMinSize(panels[1].props.minWidth)\n }\n >\n <AppShellPanelWithLayout\n panel={panels[1]}\n visible={!hasExpanded || firstExpandedIndex === 1}\n index={1}\n overrides={{ sizeManagedByRoot: true }}\n isMobile={isMobile}\n activePanel={activePanel}\n hasExpanded={hasExpanded}\n hasTabBar={hasTabBar}\n ariaBaseId={ariaBaseId}\n rootExpansionActive={rootExpansionActive}\n firstExpandedIndex={firstExpandedIndex}\n onExpandedPanelChange={handleExpandedPanelChange}\n />\n </ResizablePanel>\n </ResizablePanelGroup>\n ) : null;\n\n // Live region for announcing panel changes to screen readers\n const activeLabel =\n hasTabBar && panelInfos[activePanel]\n ? panelInfos[activePanel].label || `Panel ${activePanel + 1}`\n : null;\n\n // Mobile layout\n if (isMobile) {\n return (\n <AppShellProvider value={contextValue}>\n <AppShellPrimitive\n ref={rootRef}\n background={background}\n height={height}\n padding={padding}\n mobilePadding={mobilePadding}\n gap={0}\n connected={connected}\n className={className}\n {...props}\n >\n {skipLink}\n {sidebarChild && (\n <Sheet\n open={mobileSidebarOpen}\n onOpenChange={handleSheetOpenChange}\n >\n <SheetContent\n side=\"left\"\n showCloseButton={false}\n className=\"w-[280px] p-0\"\n aria-label=\"Sidebar navigation\"\n >\n {sidebarChild}\n </SheetContent>\n </Sheet>\n )}\n <div className=\"flex h-full min-w-0 flex-1 flex-col overflow-clip\">\n <AppShellMobileTabBar\n panels={panelInfos}\n activeIndex={activePanel}\n onActiveChange={handleActivePanelChange}\n onSidebarOpen={sidebarChild ? handleSidebarOpen : undefined}\n baseId={ariaBaseId}\n />\n <div className=\"flex min-h-0 flex-1\">{renderedPanels}</div>\n </div>\n {/* Live region for panel switch announcements */}\n {activeLabel && (\n <div className=\"sr-only\" role=\"status\" aria-live=\"polite\">\n {activeLabel} panel active\n </div>\n )}\n {otherChildren}\n </AppShellPrimitive>\n </AppShellProvider>\n );\n }\n\n // Desktop layout\n const effectiveGap = connected || hasExpanded ? 0 : gap;\n\n return (\n <AppShellProvider value={contextValue}>\n <AppShellPrimitive\n ref={rootRef}\n background={background}\n height={height}\n padding={padding}\n mobilePadding={mobilePadding}\n gap={effectiveGap}\n connected={connected}\n className={className}\n {...props}\n >\n {skipLink}\n {sidebarChild}\n {renderedResizablePanels ?? renderedPanels}\n {otherChildren}\n </AppShellPrimitive>\n </AppShellProvider>\n );\n}\n\nAppShellRoot.displayName = 'AppShell';\n\n// ============================================\n// AppShell Sidebar\n// ============================================\n\nexport interface AppShellSidebarProps extends React.ComponentProps<'div'> {\n /**\n * Explicit width override — bypasses auto-detection. Manual widths are\n * protected by AppSidebar's canonical collapsed width to prevent clipping.\n * When omitted, the sidebar auto-sizes based on the child\n * SidebarProvider's expanded/collapsed state.\n */\n width?: string;\n /** Width when sidebar is expanded (auto mode only). @default '280px' */\n expandedWidth?: string;\n /** Width when sidebar is collapsed (auto mode only). @default '116px' */\n collapsedWidth?: string;\n}\n\n/**\n * Layout slot for the sidebar region. Renders a div — the actual aside\n * landmark is provided by AppSidebar/Sidebar primitive inside it.\n *\n * **Auto-detection (default):** When no `width` prop is provided, the sidebar\n * observes the child SidebarProvider's `data-state` attribute via CSS `:has()`\n * and transitions between `collapsedWidth` and `expandedWidth` automatically.\n *\n * **Manual mode:** Pass an explicit `width` to control sizing yourself.\n */\nfunction AppShellSidebar({\n width,\n expandedWidth = APP_SIDEBAR_EXPANDED_WIDTH,\n collapsedWidth = APP_SIDEBAR_COLLAPSED_WIDTH,\n className,\n style,\n children,\n ...props\n}: AppShellSidebarProps) {\n const autoMode = width === undefined;\n\n return (\n <div\n data-slot=\"app-shell-sidebar\"\n style={\n {\n ...(autoMode\n ? {\n '--app-shell-sidebar-collapsed': collapsedWidth,\n '--app-shell-sidebar-expanded': expandedWidth,\n }\n : {\n '--app-shell-sidebar-width': width,\n minWidth: APP_SIDEBAR_COLLAPSED_WIDTH,\n }),\n ...style,\n } as React.CSSProperties\n }\n className={cn(\n 'flex h-full shrink-0 flex-col overflow-clip',\n 'transition-[width] duration-300 ease-[cubic-bezier(0.16,1,0.3,1)]',\n 'motion-reduce:transition-none',\n autoMode\n ? [\n 'w-[var(--app-shell-sidebar-collapsed)]',\n '[&:has([data-state=expanded])]:w-[var(--app-shell-sidebar-expanded)]',\n ]\n : 'w-[var(--app-shell-sidebar-width)]',\n className,\n )}\n {...props}\n >\n {children}\n </div>\n );\n}\n\nAppShellSidebar.displayName = 'AppShell.Sidebar';\n\n// ============================================\n// AppShell Header\n// ============================================\n\nexport interface AppShellHeaderProps extends React.ComponentProps<'div'> {}\n\nfunction AppShellHeader({\n className,\n children,\n ...props\n}: AppShellHeaderProps) {\n return (\n <div\n data-slot=\"app-shell-header\"\n className={cn('shrink-0', className)}\n {...props}\n >\n {children}\n </div>\n );\n}\n\nAppShellHeader.displayName = 'AppShell.Header';\n\n// ============================================\n// Preset Background Variants\n// ============================================\n\nconst appShellBackgrounds = {\n transparent: 'transparent',\n appBg: DEFAULT_APP_SHELL_BACKGROUND,\n neutral: 'var(--muted)',\n brandSubtle: 'linear-gradient(135deg, var(--air-50) 0%, var(--air-100) 100%)',\n brand: 'linear-gradient(135deg, var(--air-400) 0%, var(--primary) 100%)',\n brandDeep: 'linear-gradient(135deg, var(--primary) 0%, var(--air-900) 100%)',\n desertMidnight:\n 'linear-gradient(135deg, var(--slate-500) 0%, var(--slate-700) 100%)',\n aqua: 'linear-gradient(135deg, var(--air-400) 0%, var(--air-600) 100%)',\n} as const;\n\n// ============================================\n// Compound Component (Dot Notation)\n// ============================================\n\nconst AppShell = Object.assign(AppShellRoot, {\n Root: AppShellRoot,\n Sidebar: AppShellSidebar,\n Header: AppShellHeader,\n Panel: AppShellPanel,\n Content: AppShellContent,\n});\n\n// ============================================\n// Exports\n// ============================================\n\nexport type { AppShellContentProps } from './AppShellContent';\nexport type { AppShellPanelProps } from './AppShellPanel';\n\nexport {\n APP_SIDEBAR_COLLAPSED_WIDTH,\n APP_SIDEBAR_EXPANDED_WIDTH,\n AppShell,\n AppShellContent,\n AppShellHeader,\n AppShellPanel,\n AppShellRoot,\n AppShellSidebar,\n appShellBackgrounds,\n};\n"],"mappings":"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"}
|
|
1
|
+
{"version":3,"file":"index223.js","names":[],"sources":["../src/components/templates/AppShell/AppShell.tsx"],"sourcesContent":["'use client';\n\nimport * as React from 'react';\nimport type { GroupImperativeHandle } from 'react-resizable-panels';\nimport {\n ResizableHandle,\n ResizablePanel,\n ResizablePanelGroup,\n} from '@/components/atoms/layout/Resizable';\nimport { AppShell as AppShellPrimitive } from '@/components/ui/app-shell';\n\nimport { Sheet, SheetContent } from '@/components/ui/sheet';\nimport { SidebarContext } from '@/components/ui/sidebar';\nimport { useIsMobile } from '@/hooks/use-mobile';\nimport { cn } from '@/lib/utils';\nimport {\n APP_SIDEBAR_COLLAPSED_WIDTH,\n APP_SIDEBAR_EXPANDED_WIDTH,\n} from '../AppSidebar/AppSidebar.constants';\nimport { AppShellContent } from './AppShellContent';\nimport {\n type AppShellContextValue,\n AppShellProvider,\n PanelIndexContext,\n PanelLayoutContext,\n type PanelLayoutInfo,\n type PanelPosition,\n} from './AppShellContext';\nimport { AppShellMobileTabBar } from './AppShellMobileTabBar';\nimport {\n APPSHELL_PANEL_TYPE,\n AppShellPanel,\n type AppShellPanelComponent,\n type AppShellPanelProps,\n} from './AppShellPanel';\nimport {\n DEFAULT_EXPAND_THRESHOLD,\n getExpandedPanelFromLayout,\n layoutMapToTuple,\n normalizePanelSizes,\n toResizableMinSize,\n toResizablePercentageSize,\n} from './AppShellResize';\n\nconst DEFAULT_APP_SHELL_BACKGROUND = 'var(--app-background)';\n\ninterface AppShellPanelMarker {\n __appShellType?: unknown;\n}\n\nfunction isAppShellPanelComponent(\n type: unknown,\n): type is AppShellPanelComponent {\n return (\n typeof type === 'function' &&\n (type as AppShellPanelMarker).__appShellType === APPSHELL_PANEL_TYPE\n );\n}\n\nfunction isAppShellPanelElement(\n child: React.ReactNode,\n): child is React.ReactElement<AppShellPanelProps, AppShellPanelComponent> {\n return React.isValidElement(child) && isAppShellPanelComponent(child.type);\n}\n\nfunction getAppShellPanelIdentity(\n panel: React.ReactElement<AppShellPanelProps>,\n ariaBaseId: string,\n index: number,\n): React.Key {\n return panel.key ?? panel.props.label ?? `${ariaBaseId}-panel-${index}`;\n}\n\ninterface AppShellPanelWithLayoutProps {\n panel: React.ReactElement<AppShellPanelProps>;\n visible: boolean;\n index: number;\n overrides?: Partial<PanelLayoutInfo>;\n isMobile: boolean;\n activePanel: number;\n hasExpanded: boolean;\n hasTabBar: boolean;\n ariaBaseId: string;\n rootExpansionActive: boolean;\n firstExpandedIndex: number | null;\n onExpandedPanelChange: (panelIndex: number | null) => void;\n}\n\nfunction AppShellPanelWithLayout({\n panel,\n visible,\n index,\n overrides = {},\n isMobile,\n activePanel,\n hasExpanded,\n hasTabBar,\n ariaBaseId,\n rootExpansionActive,\n firstExpandedIndex,\n onExpandedPanelChange,\n}: AppShellPanelWithLayoutProps) {\n if (isMobile && index !== activePanel) return null;\n\n const layoutInfo: PanelLayoutInfo = {\n visible: isMobile ? true : visible,\n collapseMode: hasExpanded ? 'animated' : 'removed',\n isMobile,\n tabId: hasTabBar ? `${ariaBaseId}-tab-${index}` : undefined,\n panelId: hasTabBar ? `${ariaBaseId}-tabpanel-${index}` : undefined,\n expanded: rootExpansionActive\n ? hasExpanded && index === firstExpandedIndex\n : undefined,\n onExpandedChange: rootExpansionActive\n ? (nextExpanded) => onExpandedPanelChange(nextExpanded ? index : null)\n : undefined,\n ...overrides,\n };\n\n return (\n <PanelIndexContext.Provider value={index}>\n <PanelLayoutContext.Provider value={layoutInfo}>\n {panel}\n </PanelLayoutContext.Provider>\n </PanelIndexContext.Provider>\n );\n}\n\n// ============================================\n// AppShell Root\n// ============================================\n\nexport interface AppShellProps extends React.ComponentProps<'div'> {\n /** Any CSS background value (color, gradient, image). Defaults to var(--app-background). */\n background?: string;\n /** Fixed height, supports CSS calc() */\n height?: string;\n /** Spacing around the inner content in pixels or CSS value */\n padding?: number | string;\n /** Padding on mobile viewports. Defaults to 8px. */\n mobilePadding?: number | string;\n /** Gap between panels in pixels or CSS value. Defaults to 12. */\n gap?: number | string;\n /** Joined-edge mode where panels share borders. Defaults to false. */\n connected?: boolean;\n /** ID of the main content element for skip navigation. */\n skipToId?: string;\n /** Controlled active panel index for mobile tab switching. */\n activePanel?: number;\n /** Callback when active panel changes on mobile. */\n onActivePanelChange?: (index: number) => void;\n /** Default active panel on mobile (default: 0). */\n defaultActivePanel?: number;\n /** Controlled expanded panel index. Use null for no expanded panel. */\n expandedPanel?: number | null;\n /** Initial expanded panel index for uncontrolled root-owned expansion. */\n defaultExpandedPanel?: number | null;\n /** Callback when root-owned expansion changes. */\n onExpandedPanelChange?: (panelIndex: number | null) => void;\n /** Enables root-owned two-panel resizing on desktop. Defaults to true for eligible two-panel layouts. */\n resizablePanels?: boolean;\n /** Initial panel size split in percentages. Defaults to [35, 65]. */\n defaultPanelSizes?: [number, number];\n /** Controlled panel size split in percentages. */\n panelSizes?: [number, number];\n /** Called after the user releases the resize handle. */\n onPanelSizesChange?: (sizes: [number, number]) => void;\n /** Percentage threshold that expands the dominant panel on release. */\n expandThreshold?: number;\n}\n\nfunction AppShellRoot({\n background = DEFAULT_APP_SHELL_BACKGROUND,\n height = '100dvh',\n padding = 16,\n mobilePadding,\n gap = 12,\n connected = false,\n skipToId,\n activePanel: activePanelProp,\n onActivePanelChange,\n defaultActivePanel = 0,\n expandedPanel: expandedPanelProp,\n defaultExpandedPanel,\n onExpandedPanelChange,\n resizablePanels,\n defaultPanelSizes,\n panelSizes,\n onPanelSizesChange,\n expandThreshold = DEFAULT_EXPAND_THRESHOLD,\n className,\n children,\n ...props\n}: AppShellProps): React.ReactElement {\n const isMobile = useIsMobile();\n const ariaBaseId = React.useId();\n const [internalActivePanel, setInternalActivePanel] =\n React.useState(defaultActivePanel);\n const [internalExpandedPanel, setInternalExpandedPanel] = React.useState<\n number | null\n >(defaultExpandedPanel ?? null);\n const [internalPanelSizes, setInternalPanelSizes] = React.useState(() =>\n normalizePanelSizes(defaultPanelSizes),\n );\n const [isResizingPanels, setIsResizingPanels] = React.useState(false);\n const [isRestoringResizablePanels, setIsRestoringResizablePanels] =\n React.useState(false);\n const [internalMobileSidebarOpen, setInternalMobileSidebarOpen] =\n React.useState(false);\n const resizableGroupRef = React.useRef<GroupImperativeHandle | null>(null);\n const rootRef = React.useRef<HTMLDivElement>(null);\n const allowResizeReleaseExpansionRef = React.useRef(false);\n const suppressControlledLayoutChangeRef = React.useRef(false);\n const previousResizableExpandedRef = React.useRef(false);\n\n const activePanel = activePanelProp ?? internalActivePanel;\n const handleActivePanelChange = React.useCallback(\n (index: number) => {\n if (activePanelProp === undefined) {\n setInternalActivePanel((prev) => (prev === index ? prev : index));\n }\n onActivePanelChange?.(index);\n },\n [activePanelProp, onActivePanelChange],\n );\n\n const rootExpansionRequested =\n expandedPanelProp !== undefined ||\n defaultExpandedPanel !== undefined ||\n onExpandedPanelChange !== undefined;\n const resolvedExpandedPanel =\n expandedPanelProp !== undefined ? expandedPanelProp : internalExpandedPanel;\n const handleExpandedPanelChange = React.useCallback(\n (panelIndex: number | null) => {\n if (expandedPanelProp === undefined) {\n setInternalExpandedPanel(panelIndex);\n }\n onExpandedPanelChange?.(panelIndex);\n },\n [expandedPanelProp, onExpandedPanelChange],\n );\n\n // Classify children (memoized to stabilize downstream references)\n const { panels, panelInfos, sidebarChild, otherChildren } =\n React.useMemo(() => {\n const p: React.ReactElement<AppShellPanelProps>[] = [];\n const infos: { key?: React.Key; label?: string }[] = [];\n let sidebar: React.ReactNode = null;\n const other: React.ReactNode[] = [];\n\n React.Children.forEach(children, (child) => {\n if (isAppShellPanelElement(child)) {\n infos.push({\n key: child.key ?? child.props.label,\n label: child.props.label,\n });\n p.push(child);\n return;\n }\n\n if (!React.isValidElement(child)) {\n return;\n }\n\n if (child.type === AppShellSidebar) {\n sidebar = child;\n } else {\n other.push(child);\n }\n });\n\n return {\n panels: p,\n panelInfos: infos,\n sidebarChild: sidebar,\n otherChildren: other,\n };\n }, [children]);\n\n const shouldUseResizablePanels = resizablePanels ?? true;\n\n // Determine which panels are visible\n const firstPanelExpandedIndex = panels.findIndex((p) => p.props.expanded);\n const hasPanelExpansionProps = panels.some(\n (panel) =>\n panel.props.expanded !== undefined ||\n panel.props.onExpandedChange !== undefined,\n );\n const canUseResizablePanelPair =\n shouldUseResizablePanels &&\n !connected &&\n !isMobile &&\n panels.length === 2 &&\n (resizablePanels !== undefined || !hasPanelExpansionProps);\n const rootExpansionActive =\n rootExpansionRequested || canUseResizablePanelPair;\n const validRootExpandedPanel =\n typeof resolvedExpandedPanel === 'number' &&\n Number.isInteger(resolvedExpandedPanel) &&\n resolvedExpandedPanel >= 0 &&\n resolvedExpandedPanel < panels.length\n ? resolvedExpandedPanel\n : null;\n let firstExpandedIndex: number | null = firstPanelExpandedIndex;\n if (rootExpansionActive) {\n firstExpandedIndex = validRootExpandedPanel;\n }\n const hasExpanded = firstExpandedIndex !== -1 && firstExpandedIndex !== null;\n const visibleCount = hasExpanded ? 1 : Math.min(panels.length, 2);\n const canRenderResizablePanels = canUseResizablePanelPair;\n const resolvedPanelSizes = React.useMemo(\n () => normalizePanelSizes(panelSizes ?? internalPanelSizes),\n [panelSizes, internalPanelSizes],\n );\n const resizablePanelSizes = React.useMemo<[number, number]>(() => {\n if (hasExpanded && firstExpandedIndex === 0) return [100, 0];\n if (hasExpanded && firstExpandedIndex === 1) return [0, 100];\n return resolvedPanelSizes;\n }, [firstExpandedIndex, hasExpanded, resolvedPanelSizes]);\n const shouldBypassResizableMinSize =\n hasExpanded ||\n isRestoringResizablePanels ||\n (!hasExpanded && previousResizableExpandedRef.current);\n\n // Dev warnings\n if (process.env.NODE_ENV !== 'production') {\n const expandedPanelPropCount = panels.filter(\n (p) => p.props.expanded,\n ).length;\n if (rootExpansionActive && expandedPanelPropCount > 0) {\n console.warn(\n 'AppShell.Root: root-owned expansion props should not be mixed with AppShell.Panel expanded. Root expansion will be used.',\n );\n }\n if (!rootExpansionActive && expandedPanelPropCount > 1) {\n console.warn(\n 'AppShell.Root: multiple panels have expanded={true}. Only the first expanded panel will be shown.',\n );\n }\n if (\n rootExpansionActive &&\n resolvedExpandedPanel !== null &&\n resolvedExpandedPanel !== undefined &&\n validRootExpandedPanel === null\n ) {\n console.warn(\n `AppShell.Root: expandedPanel index ${resolvedExpandedPanel} is out of range. No panel will be expanded.`,\n );\n }\n if (resizablePanels === true && connected) {\n console.warn(\n 'AppShell.Root: resizablePanels is not supported with connected. Rendering non-resizable panels.',\n );\n }\n if (resizablePanels === true && !connected && panels.length !== 2) {\n console.warn(\n `AppShell.Root: resizablePanels requires exactly 2 Panel children, got ${panels.length}. Rendering non-resizable panels.`,\n );\n }\n if (panels.length > 2 && !hasExpanded) {\n console.warn(\n `AppShell.Root: max 2 Panel children allowed, got ${panels.length}. Only the first 2 will be visible.`,\n );\n }\n }\n\n const handleLayoutChange = React.useCallback(\n (layout: Record<string, number>) => {\n if (hasExpanded || suppressControlledLayoutChangeRef.current) {\n return;\n }\n if (panelSizes === undefined) {\n setInternalPanelSizes(layoutMapToTuple(layout));\n }\n },\n [hasExpanded, panelSizes],\n );\n\n const handleLayoutChanged = React.useCallback(\n (layout: Record<string, number>) => {\n if (\n hasExpanded ||\n !allowResizeReleaseExpansionRef.current ||\n suppressControlledLayoutChangeRef.current\n ) {\n return;\n }\n\n const nextSizes = layoutMapToTuple(layout);\n if (panelSizes === undefined) {\n setInternalPanelSizes(nextSizes);\n }\n onPanelSizesChange?.(nextSizes);\n\n const expandedIndex = getExpandedPanelFromLayout(layout, expandThreshold);\n if (expandedIndex !== null) {\n handleExpandedPanelChange(expandedIndex);\n }\n },\n [\n expandThreshold,\n handleExpandedPanelChange,\n hasExpanded,\n onPanelSizesChange,\n panelSizes,\n ],\n );\n\n React.useEffect(() => {\n if (!canRenderResizablePanels) {\n suppressControlledLayoutChangeRef.current = false;\n previousResizableExpandedRef.current = false;\n return;\n }\n\n const ownerWindow = rootRef.current?.ownerDocument.defaultView;\n if (!ownerWindow) return;\n\n const wasExpanded = previousResizableExpandedRef.current;\n previousResizableExpandedRef.current = hasExpanded;\n const shouldApplyLayout =\n hasExpanded || wasExpanded || panelSizes !== undefined;\n if (!shouldApplyLayout) {\n suppressControlledLayoutChangeRef.current = false;\n return;\n }\n\n let restoreFrame: number | undefined;\n const [first, second] = resizablePanelSizes;\n if (wasExpanded && !hasExpanded) {\n restoreFrame = ownerWindow.requestAnimationFrame(() => {\n setIsRestoringResizablePanels(true);\n });\n }\n suppressControlledLayoutChangeRef.current = true;\n const nextLayout = { panel0: first, panel1: second };\n resizableGroupRef.current?.setLayout(nextLayout);\n const frame = ownerWindow.requestAnimationFrame(() => {\n resizableGroupRef.current?.setLayout(nextLayout);\n });\n const timeout = ownerWindow.setTimeout(() => {\n suppressControlledLayoutChangeRef.current = false;\n }, 350);\n return () => {\n if (restoreFrame !== undefined) {\n ownerWindow.cancelAnimationFrame(restoreFrame);\n }\n ownerWindow.cancelAnimationFrame(frame);\n ownerWindow.clearTimeout(timeout);\n suppressControlledLayoutChangeRef.current = false;\n };\n }, [canRenderResizablePanels, hasExpanded, panelSizes, resizablePanelSizes]);\n\n React.useEffect(() => {\n if (!isRestoringResizablePanels) return;\n\n const ownerWindow = rootRef.current?.ownerDocument.defaultView;\n if (!ownerWindow) return;\n\n const timeout = ownerWindow.setTimeout(() => {\n setIsRestoringResizablePanels(false);\n }, 350);\n return () => ownerWindow.clearTimeout(timeout);\n }, [isRestoringResizablePanels]);\n\n React.useEffect(() => {\n if (!canRenderResizablePanels) {\n allowResizeReleaseExpansionRef.current = false;\n suppressControlledLayoutChangeRef.current = false;\n return;\n }\n\n const ownerWindow = rootRef.current?.ownerDocument.defaultView;\n if (!ownerWindow) return;\n\n const frame = ownerWindow.requestAnimationFrame(() => {\n allowResizeReleaseExpansionRef.current = true;\n });\n return () => {\n ownerWindow.cancelAnimationFrame(frame);\n allowResizeReleaseExpansionRef.current = false;\n };\n }, [canRenderResizablePanels]);\n\n React.useEffect(() => {\n if (!isResizingPanels) return;\n const ownerWindow = rootRef.current?.ownerDocument.defaultView;\n if (!ownerWindow) return;\n\n const stopResizing = () => setIsResizingPanels(false);\n ownerWindow.addEventListener('pointerup', stopResizing);\n ownerWindow.addEventListener('pointercancel', stopResizing);\n return () => {\n ownerWindow.removeEventListener('pointerup', stopResizing);\n ownerWindow.removeEventListener('pointercancel', stopResizing);\n };\n }, [isResizingPanels]);\n\n const handleResizablePointerDownCapture = React.useCallback(\n (event: React.PointerEvent<HTMLDivElement>) => {\n const target = event.target;\n if (!(target instanceof Element)) return;\n if (target.closest('[data-slot=\"resizable-handle\"]')) {\n setIsResizingPanels(true);\n }\n },\n [],\n );\n\n // Memoize the visibility map to stabilize downstream context values\n const visiblePanels = React.useMemo(\n () =>\n hasExpanded\n ? panels.map((panel, i) => ({\n panel,\n visible: i === firstExpandedIndex,\n index: i,\n }))\n : panels.map((panel, i) => ({\n panel,\n visible: i < 2,\n index: i,\n })),\n [panels, hasExpanded, firstExpandedIndex],\n );\n\n // Whether the tab bar is active (mobile with 2+ panels)\n const hasTabBar = isMobile && panels.length > 1;\n\n // Build context (derive position from stable scalars, not array reference)\n const getPanelPosition = React.useCallback(\n (index: number): PanelPosition => {\n if (visibleCount === 1) return 'only';\n if (hasExpanded) return index === firstExpandedIndex ? 'only' : 'last';\n return index === 0 ? 'first' : 'last';\n },\n [visibleCount, hasExpanded, firstExpandedIndex],\n );\n\n const contextValue: AppShellContextValue = React.useMemo(\n () => ({\n connected,\n panelCount: visibleCount,\n getPanelPosition,\n }),\n [connected, visibleCount, getPanelPosition],\n );\n\n // Sidebar context for mobile drawer integration\n const sidebarContext = React.useContext(SidebarContext);\n const mobileSidebarOpen =\n sidebarContext?.openMobile ?? internalMobileSidebarOpen;\n const setMobileSidebarOpen =\n sidebarContext?.setOpenMobile ?? setInternalMobileSidebarOpen;\n const handleSidebarOpen = React.useCallback(() => {\n setMobileSidebarOpen(true);\n }, [setMobileSidebarOpen]);\n\n const handleSheetOpenChange = React.useCallback(\n (open: boolean) => {\n setMobileSidebarOpen(open);\n },\n [setMobileSidebarOpen],\n );\n\n // Skip navigation link\n const skipLink = skipToId ? (\n <a\n href={`#${skipToId}`}\n className=\"sr-only focus:not-sr-only focus:fixed focus:left-4 focus:top-4 focus:z-50 focus:rounded-md focus:bg-background focus:px-4 focus:py-2 focus:text-sm focus:font-medium focus:text-foreground focus:shadow-sm focus:ring-2 focus:ring-ring\"\n >\n Skip to content\n </a>\n ) : null;\n\n // Render panels with context providers (no cloneElement — panels self-style)\n const renderedPanels = React.useMemo(\n () =>\n visiblePanels.map(({ panel, visible, index }) => (\n <AppShellPanelWithLayout\n key={getAppShellPanelIdentity(panel, ariaBaseId, index)}\n panel={panel}\n visible={visible}\n index={index}\n isMobile={isMobile}\n activePanel={activePanel}\n hasExpanded={hasExpanded}\n hasTabBar={hasTabBar}\n ariaBaseId={ariaBaseId}\n rootExpansionActive={rootExpansionActive}\n firstExpandedIndex={firstExpandedIndex}\n onExpandedPanelChange={handleExpandedPanelChange}\n />\n )),\n [\n visiblePanels,\n ariaBaseId,\n isMobile,\n activePanel,\n hasExpanded,\n hasTabBar,\n rootExpansionActive,\n firstExpandedIndex,\n handleExpandedPanelChange,\n ],\n );\n\n const renderedResizablePanels = canRenderResizablePanels ? (\n <ResizablePanelGroup\n orientation=\"horizontal\"\n disabled={hasExpanded}\n groupRef={resizableGroupRef}\n onLayoutChange={handleLayoutChange}\n onLayoutChanged={handleLayoutChanged}\n onPointerDownCapture={handleResizablePointerDownCapture}\n className={cn(\n 'min-h-0 min-w-0 flex-1',\n !isResizingPanels &&\n '[&>[data-slot=resizable-panel]]:transition-[flex-grow] [&>[data-slot=resizable-panel]]:duration-300 [&>[data-slot=resizable-panel]]:ease-[cubic-bezier(0.16,1,0.3,1)] motion-reduce:[&>[data-slot=resizable-panel]]:transition-none',\n )}\n >\n <ResizablePanel\n id=\"panel0\"\n defaultSize={toResizablePercentageSize(resizablePanelSizes[0])}\n minSize={\n shouldBypassResizableMinSize\n ? 0\n : toResizableMinSize(panels[0].props.minWidth)\n }\n >\n <AppShellPanelWithLayout\n panel={panels[0]}\n visible={!hasExpanded || firstExpandedIndex === 0}\n index={0}\n overrides={{ sizeManagedByRoot: true }}\n isMobile={isMobile}\n activePanel={activePanel}\n hasExpanded={hasExpanded}\n hasTabBar={hasTabBar}\n ariaBaseId={ariaBaseId}\n rootExpansionActive={rootExpansionActive}\n firstExpandedIndex={firstExpandedIndex}\n onExpandedPanelChange={handleExpandedPanelChange}\n />\n </ResizablePanel>\n <ResizableHandle\n disabled={hasExpanded}\n className={cn(\n 'z-10 min-w-2 shrink-0 cursor-col-resize w-[var(--app-shell-gap,0px)] bg-transparent after:w-2 hover:bg-transparent',\n 'transition-[width,min-width,opacity,background-color] duration-300 ease-[cubic-bezier(0.16,1,0.3,1)] motion-reduce:transition-none',\n hasExpanded && 'min-w-0 w-0 opacity-0 after:w-0 pointer-events-none',\n )}\n />\n <ResizablePanel\n id=\"panel1\"\n defaultSize={toResizablePercentageSize(resizablePanelSizes[1])}\n minSize={\n shouldBypassResizableMinSize\n ? 0\n : toResizableMinSize(panels[1].props.minWidth)\n }\n >\n <AppShellPanelWithLayout\n panel={panels[1]}\n visible={!hasExpanded || firstExpandedIndex === 1}\n index={1}\n overrides={{ sizeManagedByRoot: true }}\n isMobile={isMobile}\n activePanel={activePanel}\n hasExpanded={hasExpanded}\n hasTabBar={hasTabBar}\n ariaBaseId={ariaBaseId}\n rootExpansionActive={rootExpansionActive}\n firstExpandedIndex={firstExpandedIndex}\n onExpandedPanelChange={handleExpandedPanelChange}\n />\n </ResizablePanel>\n </ResizablePanelGroup>\n ) : null;\n\n // Live region for announcing panel changes to screen readers\n const activeLabel =\n hasTabBar && panelInfos[activePanel]\n ? panelInfos[activePanel].label || `Panel ${activePanel + 1}`\n : null;\n\n // Mobile layout\n if (isMobile) {\n return (\n <AppShellProvider value={contextValue}>\n <AppShellPrimitive\n ref={rootRef}\n background={background}\n height={height}\n padding={padding}\n mobilePadding={mobilePadding}\n gap={0}\n connected={connected}\n className={className}\n {...props}\n >\n {skipLink}\n {sidebarChild && (\n <Sheet\n open={mobileSidebarOpen}\n onOpenChange={handleSheetOpenChange}\n >\n <SheetContent\n side=\"left\"\n showCloseButton={false}\n className=\"w-[280px] p-0\"\n aria-label=\"Sidebar navigation\"\n >\n {sidebarChild}\n </SheetContent>\n </Sheet>\n )}\n <div className=\"flex h-full min-w-0 flex-1 flex-col overflow-clip\">\n <AppShellMobileTabBar\n panels={panelInfos}\n activeIndex={activePanel}\n onActiveChange={handleActivePanelChange}\n onSidebarOpen={sidebarChild ? handleSidebarOpen : undefined}\n baseId={ariaBaseId}\n />\n <div className=\"flex min-h-0 flex-1\">{renderedPanels}</div>\n </div>\n {/* Live region for panel switch announcements */}\n {activeLabel && (\n <div className=\"sr-only\" role=\"status\" aria-live=\"polite\">\n {activeLabel} panel active\n </div>\n )}\n {otherChildren}\n </AppShellPrimitive>\n </AppShellProvider>\n );\n }\n\n // Desktop layout\n const effectiveGap = connected || hasExpanded ? 0 : gap;\n\n return (\n <AppShellProvider value={contextValue}>\n <AppShellPrimitive\n ref={rootRef}\n background={background}\n height={height}\n padding={padding}\n mobilePadding={mobilePadding}\n gap={effectiveGap}\n connected={connected}\n className={className}\n {...props}\n >\n {skipLink}\n {sidebarChild}\n {renderedResizablePanels ?? renderedPanels}\n {otherChildren}\n </AppShellPrimitive>\n </AppShellProvider>\n );\n}\n\nAppShellRoot.displayName = 'AppShell';\n\n// ============================================\n// AppShell Sidebar\n// ============================================\n\nexport interface AppShellSidebarProps extends React.ComponentProps<'div'> {\n /**\n * Explicit width override — bypasses auto-detection. Manual widths are\n * protected by AppSidebar's canonical collapsed width to prevent clipping.\n * When omitted, the sidebar auto-sizes based on the child\n * SidebarProvider's expanded/collapsed state.\n */\n width?: string;\n /** Width when sidebar is expanded (auto mode only). @default '280px' */\n expandedWidth?: string;\n /** Width when sidebar is collapsed (auto mode only). @default '68px' */\n collapsedWidth?: string;\n}\n\n/**\n * Layout slot for the sidebar region. Renders a div — the actual aside\n * landmark is provided by AppSidebar/Sidebar primitive inside it.\n *\n * **Auto-detection (default):** When no `width` prop is provided, the sidebar\n * observes the child SidebarProvider's `data-state` attribute via CSS `:has()`\n * and transitions between `collapsedWidth` and `expandedWidth` automatically.\n *\n * **Manual mode:** Pass an explicit `width` to control sizing yourself.\n */\nfunction AppShellSidebar({\n width,\n expandedWidth = APP_SIDEBAR_EXPANDED_WIDTH,\n collapsedWidth = APP_SIDEBAR_COLLAPSED_WIDTH,\n className,\n style,\n children,\n ...props\n}: AppShellSidebarProps) {\n const autoMode = width === undefined;\n\n return (\n <div\n data-slot=\"app-shell-sidebar\"\n style={\n {\n ...(autoMode\n ? {\n '--app-shell-sidebar-collapsed': collapsedWidth,\n '--app-shell-sidebar-expanded': expandedWidth,\n }\n : {\n '--app-shell-sidebar-width': width,\n minWidth: APP_SIDEBAR_COLLAPSED_WIDTH,\n }),\n ...style,\n } as React.CSSProperties\n }\n className={cn(\n 'flex h-full shrink-0 flex-col overflow-clip',\n 'transition-[width] duration-300 ease-[cubic-bezier(0.16,1,0.3,1)]',\n 'motion-reduce:transition-none',\n autoMode\n ? [\n 'w-[var(--app-shell-sidebar-collapsed)]',\n '[&:has([data-state=expanded])]:w-[var(--app-shell-sidebar-expanded)]',\n ]\n : 'w-[var(--app-shell-sidebar-width)]',\n className,\n )}\n {...props}\n >\n {children}\n </div>\n );\n}\n\nAppShellSidebar.displayName = 'AppShell.Sidebar';\n\n// ============================================\n// AppShell Header\n// ============================================\n\nexport interface AppShellHeaderProps extends React.ComponentProps<'div'> {}\n\nfunction AppShellHeader({\n className,\n children,\n ...props\n}: AppShellHeaderProps) {\n return (\n <div\n data-slot=\"app-shell-header\"\n className={cn('shrink-0', className)}\n {...props}\n >\n {children}\n </div>\n );\n}\n\nAppShellHeader.displayName = 'AppShell.Header';\n\n// ============================================\n// Preset Background Variants\n// ============================================\n\nconst appShellBackgrounds = {\n transparent: 'transparent',\n appBg: DEFAULT_APP_SHELL_BACKGROUND,\n neutral: 'var(--muted)',\n brandSubtle: 'linear-gradient(135deg, var(--air-50) 0%, var(--air-100) 100%)',\n brand: 'linear-gradient(135deg, var(--air-400) 0%, var(--primary) 100%)',\n brandDeep: 'linear-gradient(135deg, var(--primary) 0%, var(--air-900) 100%)',\n desertMidnight:\n 'linear-gradient(135deg, var(--slate-500) 0%, var(--slate-700) 100%)',\n aqua: 'linear-gradient(135deg, var(--air-400) 0%, var(--air-600) 100%)',\n} as const;\n\n// ============================================\n// Compound Component (Dot Notation)\n// ============================================\n\nconst AppShell = Object.assign(AppShellRoot, {\n Root: AppShellRoot,\n Sidebar: AppShellSidebar,\n Header: AppShellHeader,\n Panel: AppShellPanel,\n Content: AppShellContent,\n});\n\n// ============================================\n// Exports\n// ============================================\n\nexport type { AppShellContentProps } from './AppShellContent';\nexport type { AppShellPanelProps } from './AppShellPanel';\n\nexport {\n APP_SIDEBAR_COLLAPSED_WIDTH,\n APP_SIDEBAR_EXPANDED_WIDTH,\n AppShell,\n AppShellContent,\n AppShellHeader,\n AppShellPanel,\n AppShellRoot,\n AppShellSidebar,\n appShellBackgrounds,\n};\n"],"mappings":"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"}
|
package/dist/index225.js
CHANGED
|
@@ -27,7 +27,7 @@ function getSidebarBgClass(isCollapsed, sidebarBgColor) {
|
|
|
27
27
|
return isCollapsed ? "bg-transparent" : sidebarBgColor ?? "bg-[var(--sidebar)]";
|
|
28
28
|
}
|
|
29
29
|
function getSidebarSurfaceClass({ isCollapsed, side, rounded, backgroundClass }) {
|
|
30
|
-
return cn("flex h-full min-h-0 flex-col items-center pb-4 pt-6", isCollapsed ? "w-full px-
|
|
30
|
+
return cn("flex h-full min-h-0 flex-col items-center pb-4 pt-6", isCollapsed ? "w-full px-2" : ["w-[calc(100%-0.75rem)] px-3", side === "left" ? "mr-3 self-start" : "ml-3 self-end"], backgroundClass, rounded && (side === "left" ? "rounded-r-lg" : "rounded-l-lg"));
|
|
31
31
|
}
|
|
32
32
|
function getSkeletonCount(count, fallback) {
|
|
33
33
|
return typeof count === "number" && Number.isFinite(count) && count >= 0 ? Math.floor(count) : fallback;
|
|
@@ -676,7 +676,7 @@ function AppSidebarSkeleton({ navCount = 4, chatCount = 5, logo, compactedLogo,
|
|
|
676
676
|
}),
|
|
677
677
|
children: [
|
|
678
678
|
/* @__PURE__ */ jsx(SidebarHeader, {
|
|
679
|
-
className: "h-[68px] w-full p-2",
|
|
679
|
+
className: "h-[68px] w-full p-2 group-data-[collapsible=icon]:p-0",
|
|
680
680
|
children: /* @__PURE__ */ jsx(AppSidebarLogo, {
|
|
681
681
|
logo,
|
|
682
682
|
compactedLogo
|
|
@@ -743,7 +743,7 @@ function AppSidebarRoot({ logo, compactedLogo, logoSubtext, collapsible = "icon"
|
|
|
743
743
|
}),
|
|
744
744
|
children: [
|
|
745
745
|
/* @__PURE__ */ jsx(SidebarHeader, {
|
|
746
|
-
className: "h-[68px] w-full p-2",
|
|
746
|
+
className: "h-[68px] w-full p-2 group-data-[collapsible=icon]:p-0",
|
|
747
747
|
children: /* @__PURE__ */ jsx(AppSidebarLogo, {
|
|
748
748
|
logo,
|
|
749
749
|
compactedLogo,
|