@adea-ai/ui 0.65.1 → 0.66.1

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.
@@ -1 +1 @@
1
- {"version":3,"file":"split-layout.js","names":["Resizable","For","createMemo","createComputed","createUniqueId","createSignal","onCleanup","on","Accessor","JSX","X","GripVertical","Button","cn","computeLayoutFrames","LayoutRect","paneDropIntent","PaneDropIntent","PANE_DRAG_TYPE","listLeaves","MIN_SPLIT_RATIO","MAX_SPLIT_RATIO","SplitLayoutBranch","SplitLayoutLeaf","SplitLayoutState","SplitLayoutProps","state","L","label","labelForLeaf","leaf","renderLeaf","Element","renderPaneLabel","paneTabIndex","labelForSeparator","branch","onResize","splitId","ratio","onFocus","leafId","onClose","onMove","targetId","intent","renderPaneActions","class","rectStyle","rect","CSSProperties","left","x","top","y","width","height","SplitLayout","props","root","HTMLDivElement","pendingFrame","refs","Map","HTMLElement","domIds","prefix","nextDomId","nextDragId","drag","setDrag","id","token","drop","setDrop","clearDrag","undefined","domId","existing","get","created","set","leaves","center","leafMap","map","frames","branches","Array","from","values","flatMap","frame","node","kind","current","has","target","allowedTarget","transfer","DataTransfer","types","includes","dropLabel","placement","branchMap","schedule","action","cancelAnimationFrame","requestAnimationFrame","active","ownerDocument","activeElement","contains","field","HTMLTextAreaElement","HTMLInputElement","selection","start","selectionStart","end","selectionEnd","direction","selectionDirection","isConnected","body","focus","preventScroll","setSelectionRange","clear","close","next","_el$","_tmpl$","_el$2","firstChild","_$use","el","_$insert","_$createComponent","each","children","initial","content","paneLabel","actions","delete","_el$3","_tmpl$2","_el$4","_el$5","_el$6","_el$7","nextSibling","$$focusin","addEventListener","event","dataTransfer","clientX","clientY","currentTarget","getBoundingClientRect","accepted","getData","preventDefault","relatedTarget","Node","dropEffect","_$setAttribute","setData","effectAllowed","_c$","_$memo","_c$2","variant","size","aria-label","onClick","_c$3","_el$8","_tmpl$3","_$effect","_$className","_p$","_v$3","_v$4","_v$5","_v$6","focusedLeafId","_v$7","_v$8","_v$9","_v$0","Boolean","_v$1","e","t","a","o","i","n","s","_$style","h","r","orientation","sizes","keyboardDelta","onSizesChange","Math","abs","style","Panel","minSize","maxSize","Handle","aria-orientation","aria-controls","join","aria-valuenow","round","_v$","_v$2","_$delegateEvents","_$createComponent","_$memo","_$className","_$setAttribute","_$style","_$delegateEvents"],"sources":["../../../../src/components/layout/split-layout/split-layout.tsx"],"sourcesContent":["import Resizable from '@corvu/resizable'\nimport {\n For,\n createMemo,\n createComputed,\n createUniqueId,\n createSignal,\n onCleanup,\n on,\n type Accessor,\n type JSX,\n} from 'solid-js'\nimport { X, GripVertical } from 'lucide-solid'\nimport { Button } from '../../ui/button'\nimport { cn } from '#lib/utils'\nimport { computeLayoutFrames, type LayoutRect } from './geometry'\nimport { paneDropIntent, type PaneDropIntent } from './drop'\nexport type { PaneDropIntent } from './drop'\nconst PANE_DRAG_TYPE = 'application/x-adea-pane-move'\nimport {\n listLeaves,\n MIN_SPLIT_RATIO,\n MAX_SPLIT_RATIO,\n type SplitLayoutBranch,\n type SplitLayoutLeaf,\n type SplitLayoutState,\n} from './model'\n\nexport type SplitLayoutProps<L extends SplitLayoutLeaf> = {\n state: SplitLayoutState<L>\n label: string\n /** Accessible name for a pane region and its close button. */\n labelForLeaf: (leaf: L) => string\n /** Called once per stable leaf owner; the accessor tracks opaque payload replacement. */\n renderLeaf: (leaf: Accessor<L>) => JSX.Element\n /** Inline visible header composition, separate from the region and close-button name. */\n renderPaneLabel?: (leaf: Accessor<L>) => JSX.Element\n /** Whether pane regions participate in sequential keyboard navigation; defaults to programmatic focus only. */\n paneTabIndex?: 0 | -1\n /** Accessible splitter name; defaults to the current orientation-specific label. */\n labelForSeparator?: (branch: SplitLayoutBranch<L>) => string\n onResize: (splitId: string, ratio: number) => void\n onFocus?: (leafId: string) => void\n /** Host performs the model transition and returns the surviving focus destination. */\n onClose?: (leafId: string) => string | undefined\n /** Pointer placement only; the host supplies keyboard commands and performs the model transition. */\n onMove?: (leafId: string, targetId: string, intent: PaneDropIntent) => void\n /** Stable header composition for host-owned keyboard actions/capability feedback. */\n renderPaneActions?: (leaf: Accessor<L>) => JSX.Element\n class?: string\n}\nfunction rectStyle(rect: LayoutRect): JSX.CSSProperties {\n return {\n left: `${rect.x * 100}%`,\n top: `${rect.y * 100}%`,\n width: `${rect.width * 100}%`,\n height: `${rect.height * 100}%`,\n }\n}\n/** Muxy frame geometry keeps leaf owners stable; Corvu owns constrained separator interactions. */\nexport function SplitLayout<L extends SplitLayoutLeaf>(props: SplitLayoutProps<L>) {\n let root: HTMLDivElement | undefined\n let pendingFrame: number | undefined\n const refs = new Map<string, HTMLElement>()\n const domIds = new Map<string, string>()\n const prefix = createUniqueId()\n let nextDomId = 0\n let nextDragId = 0\n const [drag, setDrag] = createSignal<{ id: string; token: string }>()\n const [drop, setDrop] = createSignal<{ id: string; intent: PaneDropIntent }>()\n const clearDrag = () => {\n setDrag(undefined)\n setDrop(undefined)\n }\n const domId = (id: string) => {\n const existing = domIds.get(id)\n if (existing) return existing\n const created = `${prefix}-pane-${nextDomId++}`\n domIds.set(id, created)\n return created\n }\n const leaves = createMemo(() => listLeaves(props.state.center))\n const leafMap = createMemo(() => new Map(leaves().map((leaf) => [leaf.id, leaf])))\n const frames = createMemo(() => computeLayoutFrames(props.state.center))\n const branches = createMemo(() =>\n Array.from(frames().values()).flatMap((frame) =>\n frame.node.kind === 'split' ? [frame.node] : []\n )\n )\n createComputed(() => {\n const current = drag()\n if (current && (!props.onMove || !leafMap().has(current.id))) clearDrag()\n const target = drop()\n if (target && !leafMap().has(target.id)) setDrop(undefined)\n })\n const allowedTarget = (id: string, transfer: DataTransfer | null) => {\n const current = drag()\n return props.onMove &&\n current &&\n current.id !== id &&\n leafMap().has(current.id) &&\n leafMap().has(id) &&\n transfer?.types.includes(PANE_DRAG_TYPE)\n ? current\n : undefined\n }\n const dropLabel = createMemo(() => {\n const target = drop()\n const leaf = target ? leafMap().get(target.id) : undefined\n return target && leaf\n ? `Drop to place pane ${target.intent.placement} ${props.labelForLeaf(leaf)}`\n : ''\n })\n const branchMap = createMemo(() => new Map(branches().map((branch) => [branch.id, branch])))\n const schedule = (action: () => void) => {\n if (pendingFrame !== undefined) cancelAnimationFrame(pendingFrame)\n pendingFrame = requestAnimationFrame(() => {\n pendingFrame = undefined\n action()\n })\n }\n // Register before keyed children update: capture a focused editor before an\n // ordered DOM move can blur it. Never override a newer focus outside this root.\n createComputed(\n on(\n () => props.state.center,\n () => {\n const active = root?.ownerDocument.activeElement\n if (!root || !(active instanceof HTMLElement) || !root.contains(active)) return\n const field =\n active instanceof HTMLTextAreaElement || active instanceof HTMLInputElement\n ? active\n : undefined\n const selection = field\n ? {\n start: field.selectionStart,\n end: field.selectionEnd,\n direction: field.selectionDirection,\n }\n : undefined\n schedule(() => {\n if (!active.isConnected || !root?.contains(active)) return\n const current = active.ownerDocument.activeElement\n if (current !== active && current !== active.ownerDocument.body) return\n active.focus({ preventScroll: true })\n if (field && selection?.start !== null && selection?.end !== null && selection)\n field.setSelectionRange(\n selection.start,\n selection.end,\n selection.direction ?? undefined\n )\n })\n }\n )\n )\n onCleanup(() => {\n if (pendingFrame !== undefined) cancelAnimationFrame(pendingFrame)\n clearDrag()\n refs.clear()\n domIds.clear()\n })\n const close = (id: string) => {\n const next = props.onClose?.(id)\n if (next) schedule(() => refs.get(next)?.focus({ preventScroll: true }))\n }\n return (\n <div\n ref={(el) => {\n root = el\n }}\n role=\"group\"\n aria-label={props.label}\n data-slot=\"split-layout\"\n class={cn('relative size-full min-h-0 min-w-0', props.class)}\n >\n <For each={leaves().map((leaf) => leaf.id)}>\n {(id) => {\n const initial = leafMap().get(id)!\n const leaf = () => leafMap().get(id) ?? initial\n const content = props.renderLeaf(leaf)\n const paneLabel = props.renderPaneLabel?.(leaf)\n const actions = props.renderPaneActions?.(leaf)\n const intent = () => (drop()?.id === id ? drop()?.intent : undefined)\n onCleanup(() => {\n refs.delete(id)\n domIds.delete(id)\n })\n return (\n <section\n ref={(el) => refs.set(id, el)}\n id={domId(id)}\n role=\"region\"\n aria-label={props.labelForLeaf(leaf())}\n tabIndex={props.paneTabIndex ?? -1}\n data-pane-id={id}\n data-focused={props.state.focusedLeafId === id ? '' : undefined}\n data-drop-direction={intent()?.direction}\n data-drop-placement={intent()?.placement}\n onDragOver={(event) => {\n if (!allowedTarget(id, event.dataTransfer)) return\n const next = paneDropIntent(\n event.clientX,\n event.clientY,\n event.currentTarget.getBoundingClientRect()\n )\n if (!next) {\n setDrop(undefined)\n return\n }\n event.preventDefault()\n if (event.dataTransfer) event.dataTransfer.dropEffect = 'move'\n setDrop({ id, intent: next })\n }}\n onDragLeave={(event) => {\n if (\n event.relatedTarget instanceof Node &&\n event.currentTarget.contains(event.relatedTarget)\n )\n return\n if (drop()?.id === id) setDrop(undefined)\n }}\n onDrop={(event) => {\n const current = allowedTarget(id, event.dataTransfer)\n const next = paneDropIntent(\n event.clientX,\n event.clientY,\n event.currentTarget.getBoundingClientRect()\n )\n const accepted =\n current && next && event.dataTransfer?.getData(PANE_DRAG_TYPE) === current.token\n clearDrag()\n if (!accepted) return\n event.preventDefault()\n props.onMove?.(current.id, id, next)\n }}\n style={rectStyle(frames().get(id)?.rect ?? { x: 0, y: 0, width: 0, height: 0 })}\n class=\"absolute flex min-h-0 min-w-0 flex-col overflow-hidden border border-border data-[focused]:border-primary bg-background text-foreground focus-visible:outline focus-visible:outline-2 focus-visible:outline-ring\"\n onFocusIn={() => props.onFocus?.(id)}\n >\n <header class=\"flex min-w-0 shrink-0 items-center gap-2 bg-surface px-2\">\n <span\n data-pane-drag-handle=\"\"\n draggable={Boolean(props.onMove)}\n class=\"flex min-w-0 flex-1 items-center gap-2 truncate text-sm\"\n title={props.onMove ? `Drag ${props.labelForLeaf(leaf())} to move` : undefined}\n onDragStart={(event) => {\n if (!props.onMove || !event.dataTransfer) {\n event.preventDefault()\n return\n }\n const token = `${prefix}-${++nextDragId}`\n setDrag({ id, token })\n event.dataTransfer.setData(PANE_DRAG_TYPE, token)\n event.dataTransfer.effectAllowed = 'move'\n }}\n onDragEnd={clearDrag}\n >\n {props.onMove ? (\n <GripVertical class=\"size-3 shrink-0\" aria-hidden=\"true\" />\n ) : null}\n <span class=\"min-w-0 flex-1 truncate\">\n {paneLabel ?? props.labelForLeaf(leaf())}\n </span>\n </span>\n {actions}\n {props.onClose ? (\n <Button\n variant=\"ghost\"\n size=\"icon-xs\"\n aria-label={`Close ${props.labelForLeaf(leaf())}`}\n onClick={() => close(id)}\n >\n <X />\n </Button>\n ) : null}\n </header>\n <div class=\"min-h-0 min-w-0 flex-1 overflow-auto\">{content}</div>\n {intent() ? (\n <div\n aria-hidden=\"true\"\n class={cn('pointer-events-none absolute border-2 border-primary bg-primary/10', {\n 'inset-y-0 left-0 w-1/2':\n intent()?.direction === 'row' && intent()?.placement === 'before',\n 'inset-y-0 right-0 w-1/2':\n intent()?.direction === 'row' && intent()?.placement === 'after',\n 'inset-x-0 top-0 h-1/2':\n intent()?.direction === 'column' && intent()?.placement === 'before',\n 'inset-x-0 bottom-0 h-1/2':\n intent()?.direction === 'column' && intent()?.placement === 'after',\n })}\n />\n ) : null}\n </section>\n )\n }}\n </For>\n <span class=\"sr-only\" role=\"status\">\n {dropLabel()}\n </span>\n <For each={branches().map((branch) => branch.id)}>\n {(id) => {\n const initial = branchMap().get(id)!\n const branch: Accessor<SplitLayoutBranch<L>> = () => branchMap().get(id) ?? initial\n return (\n <Resizable\n orientation={branch().direction === 'row' ? 'horizontal' : 'vertical'}\n sizes={[branch().ratio, 1 - branch().ratio]}\n keyboardDelta={0.05}\n onSizesChange={(sizes) => {\n if (sizes[0] !== undefined && Math.abs(sizes[0] - branch().ratio) > 0.000001)\n props.onResize(id, sizes[0])\n }}\n style={rectStyle(frames().get(id)?.rect ?? { x: 0, y: 0, width: 0, height: 0 })}\n class=\"pointer-events-none absolute flex min-h-0 min-w-0 data-[orientation=vertical]:flex-col\"\n >\n <Resizable.Panel\n minSize={MIN_SPLIT_RATIO}\n maxSize={MAX_SPLIT_RATIO}\n aria-hidden=\"true\"\n />\n <Resizable.Handle\n aria-label={\n props.labelForSeparator?.(branch()) ??\n (branch().direction === 'row' ? 'Resize pane columns' : 'Resize pane rows')\n }\n aria-orientation={branch().direction === 'row' ? 'vertical' : 'horizontal'}\n aria-controls={listLeaves(branch())\n .map((leaf) => domId(leaf.id))\n .join(' ')}\n aria-valuemin={10}\n aria-valuemax={90}\n aria-valuenow={Math.round(branch().ratio * 100)}\n class=\"pointer-events-auto relative w-px shrink-0 bg-border after:absolute after:inset-y-0 after:-inset-x-1 after:w-3 focus-visible:bg-primary focus-visible:outline-none hover:bg-primary data-[orientation=vertical]:h-px data-[orientation=vertical]:w-full data-[orientation=vertical]:after:inset-x-0 data-[orientation=vertical]:after:-inset-y-1 data-[orientation=vertical]:after:h-3 data-[orientation=vertical]:after:w-full\"\n />\n <Resizable.Panel\n minSize={MIN_SPLIT_RATIO}\n maxSize={MAX_SPLIT_RATIO}\n aria-hidden=\"true\"\n />\n </Resizable>\n )\n }}\n </For>\n </div>\n )\n}\n"],"mappings":"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"}
1
+ {"version":3,"file":"split-layout.js","names":["Resizable","For","createMemo","createComputed","createUniqueId","createSignal","onCleanup","on","Accessor","JSX","X","GripVertical","Button","cn","computeLayoutFrames","LayoutRect","paneDropIntent","PaneDropIntent","PANE_DRAG_TYPE","listLeaves","MIN_SPLIT_RATIO","MAX_SPLIT_RATIO","SplitLayoutBranch","SplitLayoutLeaf","SplitLayoutState","SplitLayoutProps","state","L","label","labelForLeaf","leaf","renderLeaf","Element","renderPaneLabel","paneTabIndex","labelForSeparator","branch","onResize","splitId","ratio","onFocus","leafId","onClose","onMove","targetId","intent","renderPaneActions","class","rectStyle","rect","CSSProperties","left","x","top","y","width","height","SplitLayout","props","root","HTMLDivElement","pendingFrame","refs","Map","HTMLElement","domIds","prefix","nextDomId","nextDragId","drag","setDrag","id","token","drop","setDrop","clearDrag","undefined","domId","existing","get","created","set","leaves","center","leafMap","map","frames","branches","Array","from","values","flatMap","frame","node","kind","current","has","target","allowedTarget","transfer","DataTransfer","types","includes","dropLabel","placement","branchMap","schedule","action","cancelAnimationFrame","requestAnimationFrame","active","ownerDocument","activeElement","contains","field","HTMLTextAreaElement","HTMLInputElement","selection","start","selectionStart","end","selectionEnd","direction","selectionDirection","isConnected","body","focus","preventScroll","setSelectionRange","clear","close","next","_el$","_tmpl$","_el$2","firstChild","_$use","el","_$insert","_$createComponent","each","children","initial","content","paneLabel","actions","delete","_el$3","_tmpl$2","_el$4","_el$5","_el$6","_el$7","nextSibling","$$focusin","addEventListener","event","dataTransfer","clientX","clientY","currentTarget","getBoundingClientRect","accepted","getData","preventDefault","relatedTarget","Node","dropEffect","_$setAttribute","setData","effectAllowed","_c$","_$memo","_c$2","variant","size","aria-label","onClick","_c$3","_el$8","_tmpl$3","_$effect","_$className","_p$","_v$3","_v$4","_v$5","_v$6","focusedLeafId","_v$7","_v$8","_v$9","_v$0","Boolean","_v$1","e","t","a","o","i","n","s","_$style","h","r","orientation","sizes","keyboardDelta","onSizesChange","getClientRects","length","some","Number","isFinite","Math","abs","style","Panel","minSize","maxSize","Handle","aria-orientation","aria-controls","join","aria-valuenow","round","_v$","_v$2","_$delegateEvents","_$createComponent","_$memo","_$className","_$setAttribute","_$style","_$delegateEvents"],"sources":["../../../../src/components/layout/split-layout/split-layout.tsx"],"sourcesContent":["import Resizable from '@corvu/resizable'\nimport {\n For,\n createMemo,\n createComputed,\n createUniqueId,\n createSignal,\n onCleanup,\n on,\n type Accessor,\n type JSX,\n} from 'solid-js'\nimport { X, GripVertical } from 'lucide-solid'\nimport { Button } from '../../ui/button'\nimport { cn } from '#lib/utils'\nimport { computeLayoutFrames, type LayoutRect } from './geometry'\nimport { paneDropIntent, type PaneDropIntent } from './drop'\nexport type { PaneDropIntent } from './drop'\nconst PANE_DRAG_TYPE = 'application/x-adea-pane-move'\nimport {\n listLeaves,\n MIN_SPLIT_RATIO,\n MAX_SPLIT_RATIO,\n type SplitLayoutBranch,\n type SplitLayoutLeaf,\n type SplitLayoutState,\n} from './model'\n\nexport type SplitLayoutProps<L extends SplitLayoutLeaf> = {\n state: SplitLayoutState<L>\n label: string\n /** Accessible name for a pane region and its close button. */\n labelForLeaf: (leaf: L) => string\n /** Called once per stable leaf owner; the accessor tracks opaque payload replacement. */\n renderLeaf: (leaf: Accessor<L>) => JSX.Element\n /** Inline visible header composition, separate from the region and close-button name. */\n renderPaneLabel?: (leaf: Accessor<L>) => JSX.Element\n /** Whether pane regions participate in sequential keyboard navigation; defaults to programmatic focus only. */\n paneTabIndex?: 0 | -1\n /** Accessible splitter name; defaults to the current orientation-specific label. */\n labelForSeparator?: (branch: SplitLayoutBranch<L>) => string\n onResize: (splitId: string, ratio: number) => void\n onFocus?: (leafId: string) => void\n /** Host performs the model transition and returns the surviving focus destination. */\n onClose?: (leafId: string) => string | undefined\n /** Pointer placement only; the host supplies keyboard commands and performs the model transition. */\n onMove?: (leafId: string, targetId: string, intent: PaneDropIntent) => void\n /** Stable header composition for host-owned keyboard actions/capability feedback. */\n renderPaneActions?: (leaf: Accessor<L>) => JSX.Element\n class?: string\n}\nfunction rectStyle(rect: LayoutRect): JSX.CSSProperties {\n return {\n left: `${rect.x * 100}%`,\n top: `${rect.y * 100}%`,\n width: `${rect.width * 100}%`,\n height: `${rect.height * 100}%`,\n }\n}\n/** Muxy frame geometry keeps leaf owners stable; Corvu owns constrained separator interactions. */\nexport function SplitLayout<L extends SplitLayoutLeaf>(props: SplitLayoutProps<L>) {\n let root: HTMLDivElement | undefined\n let pendingFrame: number | undefined\n const refs = new Map<string, HTMLElement>()\n const domIds = new Map<string, string>()\n const prefix = createUniqueId()\n let nextDomId = 0\n let nextDragId = 0\n const [drag, setDrag] = createSignal<{ id: string; token: string }>()\n const [drop, setDrop] = createSignal<{ id: string; intent: PaneDropIntent }>()\n const clearDrag = () => {\n setDrag(undefined)\n setDrop(undefined)\n }\n const domId = (id: string) => {\n const existing = domIds.get(id)\n if (existing) return existing\n const created = `${prefix}-pane-${nextDomId++}`\n domIds.set(id, created)\n return created\n }\n const leaves = createMemo(() => listLeaves(props.state.center))\n const leafMap = createMemo(() => new Map(leaves().map((leaf) => [leaf.id, leaf])))\n const frames = createMemo(() => computeLayoutFrames(props.state.center))\n const branches = createMemo(() =>\n Array.from(frames().values()).flatMap((frame) =>\n frame.node.kind === 'split' ? [frame.node] : []\n )\n )\n createComputed(() => {\n const current = drag()\n if (current && (!props.onMove || !leafMap().has(current.id))) clearDrag()\n const target = drop()\n if (target && !leafMap().has(target.id)) setDrop(undefined)\n })\n const allowedTarget = (id: string, transfer: DataTransfer | null) => {\n const current = drag()\n return props.onMove &&\n current &&\n current.id !== id &&\n leafMap().has(current.id) &&\n leafMap().has(id) &&\n transfer?.types.includes(PANE_DRAG_TYPE)\n ? current\n : undefined\n }\n const dropLabel = createMemo(() => {\n const target = drop()\n const leaf = target ? leafMap().get(target.id) : undefined\n return target && leaf\n ? `Drop to place pane ${target.intent.placement} ${props.labelForLeaf(leaf)}`\n : ''\n })\n const branchMap = createMemo(() => new Map(branches().map((branch) => [branch.id, branch])))\n const schedule = (action: () => void) => {\n if (pendingFrame !== undefined) cancelAnimationFrame(pendingFrame)\n pendingFrame = requestAnimationFrame(() => {\n pendingFrame = undefined\n action()\n })\n }\n // Register before keyed children update: capture a focused editor before an\n // ordered DOM move can blur it. Never override a newer focus outside this root.\n createComputed(\n on(\n () => props.state.center,\n () => {\n const active = root?.ownerDocument.activeElement\n if (!root || !(active instanceof HTMLElement) || !root.contains(active)) return\n const field =\n active instanceof HTMLTextAreaElement || active instanceof HTMLInputElement\n ? active\n : undefined\n const selection = field\n ? {\n start: field.selectionStart,\n end: field.selectionEnd,\n direction: field.selectionDirection,\n }\n : undefined\n schedule(() => {\n if (!active.isConnected || !root?.contains(active)) return\n const current = active.ownerDocument.activeElement\n if (current !== active && current !== active.ownerDocument.body) return\n active.focus({ preventScroll: true })\n if (field && selection?.start !== null && selection?.end !== null && selection)\n field.setSelectionRange(\n selection.start,\n selection.end,\n selection.direction ?? undefined\n )\n })\n }\n )\n )\n onCleanup(() => {\n if (pendingFrame !== undefined) cancelAnimationFrame(pendingFrame)\n clearDrag()\n refs.clear()\n domIds.clear()\n })\n const close = (id: string) => {\n const next = props.onClose?.(id)\n if (next) schedule(() => refs.get(next)?.focus({ preventScroll: true }))\n }\n return (\n <div\n ref={(el) => {\n root = el\n }}\n role=\"group\"\n aria-label={props.label}\n data-slot=\"split-layout\"\n class={cn('relative size-full min-h-0 min-w-0', props.class)}\n >\n <For each={leaves().map((leaf) => leaf.id)}>\n {(id) => {\n const initial = leafMap().get(id)!\n const leaf = () => leafMap().get(id) ?? initial\n const content = props.renderLeaf(leaf)\n const paneLabel = props.renderPaneLabel?.(leaf)\n const actions = props.renderPaneActions?.(leaf)\n const intent = () => (drop()?.id === id ? drop()?.intent : undefined)\n onCleanup(() => {\n refs.delete(id)\n domIds.delete(id)\n })\n return (\n <section\n ref={(el) => refs.set(id, el)}\n id={domId(id)}\n role=\"region\"\n aria-label={props.labelForLeaf(leaf())}\n tabIndex={props.paneTabIndex ?? -1}\n data-pane-id={id}\n data-focused={props.state.focusedLeafId === id ? '' : undefined}\n data-drop-direction={intent()?.direction}\n data-drop-placement={intent()?.placement}\n onDragOver={(event) => {\n if (!allowedTarget(id, event.dataTransfer)) return\n const next = paneDropIntent(\n event.clientX,\n event.clientY,\n event.currentTarget.getBoundingClientRect()\n )\n if (!next) {\n setDrop(undefined)\n return\n }\n event.preventDefault()\n if (event.dataTransfer) event.dataTransfer.dropEffect = 'move'\n setDrop({ id, intent: next })\n }}\n onDragLeave={(event) => {\n if (\n event.relatedTarget instanceof Node &&\n event.currentTarget.contains(event.relatedTarget)\n )\n return\n if (drop()?.id === id) setDrop(undefined)\n }}\n onDrop={(event) => {\n const current = allowedTarget(id, event.dataTransfer)\n const next = paneDropIntent(\n event.clientX,\n event.clientY,\n event.currentTarget.getBoundingClientRect()\n )\n const accepted =\n current && next && event.dataTransfer?.getData(PANE_DRAG_TYPE) === current.token\n clearDrag()\n if (!accepted) return\n event.preventDefault()\n props.onMove?.(current.id, id, next)\n }}\n style={rectStyle(frames().get(id)?.rect ?? { x: 0, y: 0, width: 0, height: 0 })}\n class=\"absolute flex min-h-0 min-w-0 flex-col overflow-hidden border border-border data-[focused]:border-primary bg-background text-foreground focus-visible:outline focus-visible:outline-2 focus-visible:outline-ring\"\n onFocusIn={() => props.onFocus?.(id)}\n >\n <header class=\"flex min-w-0 shrink-0 items-center gap-2 bg-surface px-2\">\n <span\n data-pane-drag-handle=\"\"\n draggable={Boolean(props.onMove)}\n class=\"flex min-w-0 flex-1 items-center gap-2 truncate text-sm\"\n title={props.onMove ? `Drag ${props.labelForLeaf(leaf())} to move` : undefined}\n onDragStart={(event) => {\n if (!props.onMove || !event.dataTransfer) {\n event.preventDefault()\n return\n }\n const token = `${prefix}-${++nextDragId}`\n setDrag({ id, token })\n event.dataTransfer.setData(PANE_DRAG_TYPE, token)\n event.dataTransfer.effectAllowed = 'move'\n }}\n onDragEnd={clearDrag}\n >\n {props.onMove ? (\n <GripVertical class=\"size-3 shrink-0\" aria-hidden=\"true\" />\n ) : null}\n <span class=\"min-w-0 flex-1 truncate\">\n {paneLabel ?? props.labelForLeaf(leaf())}\n </span>\n </span>\n {actions}\n {props.onClose ? (\n <Button\n variant=\"ghost\"\n size=\"icon-xs\"\n aria-label={`Close ${props.labelForLeaf(leaf())}`}\n onClick={() => close(id)}\n >\n <X />\n </Button>\n ) : null}\n </header>\n <div class=\"min-h-0 min-w-0 flex-1 overflow-auto\">{content}</div>\n {intent() ? (\n <div\n aria-hidden=\"true\"\n class={cn('pointer-events-none absolute border-2 border-primary bg-primary/10', {\n 'inset-y-0 left-0 w-1/2':\n intent()?.direction === 'row' && intent()?.placement === 'before',\n 'inset-y-0 right-0 w-1/2':\n intent()?.direction === 'row' && intent()?.placement === 'after',\n 'inset-x-0 top-0 h-1/2':\n intent()?.direction === 'column' && intent()?.placement === 'before',\n 'inset-x-0 bottom-0 h-1/2':\n intent()?.direction === 'column' && intent()?.placement === 'after',\n })}\n />\n ) : null}\n </section>\n )\n }}\n </For>\n <span class=\"sr-only\" role=\"status\">\n {dropLabel()}\n </span>\n <For each={branches().map((branch) => branch.id)}>\n {(id) => {\n const initial = branchMap().get(id)!\n const branch: Accessor<SplitLayoutBranch<L>> = () => branchMap().get(id) ?? initial\n return (\n <Resizable\n orientation={branch().direction === 'row' ? 'horizontal' : 'vertical'}\n sizes={[branch().ratio, 1 - branch().ratio]}\n keyboardDelta={0.05}\n onSizesChange={(sizes) => {\n // Corvu also reports panel registration/unregistration while\n // mounting or disposing a controller. Those incomplete or\n // hidden-host sizes are not user resize intent.\n if (!root?.isConnected || root.getClientRects().length === 0) return\n if (\n sizes.length !== 2 ||\n sizes.some((size) => !Number.isFinite(size)) ||\n Math.abs(sizes[0]! + sizes[1]! - 1) > 0.000001\n )\n return\n if (sizes[0] !== undefined && Math.abs(sizes[0] - branch().ratio) > 0.000001)\n props.onResize(id, sizes[0])\n }}\n style={rectStyle(frames().get(id)?.rect ?? { x: 0, y: 0, width: 0, height: 0 })}\n class=\"pointer-events-none absolute flex min-h-0 min-w-0 data-[orientation=vertical]:flex-col\"\n >\n <Resizable.Panel\n minSize={MIN_SPLIT_RATIO}\n maxSize={MAX_SPLIT_RATIO}\n aria-hidden=\"true\"\n />\n <Resizable.Handle\n aria-label={\n props.labelForSeparator?.(branch()) ??\n (branch().direction === 'row' ? 'Resize pane columns' : 'Resize pane rows')\n }\n aria-orientation={branch().direction === 'row' ? 'vertical' : 'horizontal'}\n aria-controls={listLeaves(branch())\n .map((leaf) => domId(leaf.id))\n .join(' ')}\n aria-valuemin={10}\n aria-valuemax={90}\n aria-valuenow={Math.round(branch().ratio * 100)}\n class=\"pointer-events-auto relative w-px shrink-0 bg-border after:absolute after:inset-y-0 after:-inset-x-1 after:w-3 focus-visible:bg-primary focus-visible:outline-none hover:bg-primary data-[orientation=vertical]:h-px data-[orientation=vertical]:w-full data-[orientation=vertical]:after:inset-x-0 data-[orientation=vertical]:after:-inset-y-1 data-[orientation=vertical]:after:h-3 data-[orientation=vertical]:after:w-full\"\n />\n <Resizable.Panel\n minSize={MIN_SPLIT_RATIO}\n maxSize={MAX_SPLIT_RATIO}\n aria-hidden=\"true\"\n />\n </Resizable>\n )\n }}\n </For>\n </div>\n )\n}\n"],"mappings":"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"}
package/dist/index.js CHANGED
@@ -71,6 +71,7 @@ import { SidebarNav, SidebarNavButton, SidebarNavContent, SidebarNavFooter, Side
71
71
  import { StatusBar, StatusBarItem, StatusBarSpacer } from "./components/layout/status-bar/status-bar.js";
72
72
  import { TopBar, TopBarBreadcrumb, TopBarPill, TopBarSearch, TopBarSection, TopBarTitle } from "./components/layout/top-bar/top-bar.js";
73
73
  import { BusySendButton } from "./components/conversation/busy-send-button.js";
74
+ import { ChatComposer } from "./components/conversation/chat-composer.js";
74
75
  import { ConversationAvatar } from "./components/conversation/conversation-avatar.js";
75
76
  import { ConversationSurface } from "./components/conversation/conversation-surface.js";
76
77
  import { ComposerAttachmentButton, ComposerHint, MessageComposer } from "./components/conversation/message-composer.js";
@@ -92,4 +93,4 @@ import { formatBytes, formatReleaseDate, plainTextFromMarkdown } from "./lib/ver
92
93
  import { UpdateDialog } from "./components/composites/update-dialog/update-dialog.js";
93
94
  import { WorkspaceMark } from "./components/composites/workspace-mark/workspace-mark.js";
94
95
  import { keyedRows } from "./lib/keyed-rows.js";
95
- export { Accordion, AccordionContent, AccordionItem, AccordionTrigger, AccountMenu, Alert, AlertDescription, AlertDialog, AlertDialogAction, AlertDialogCancel, AlertDialogContent, AlertDialogDescription, AlertDialogFooter, AlertDialogHeader, AlertDialogOverlay, AlertDialogPortal, AlertDialogTitle, AlertDialogTrigger, AlertTitle, AppShell, AppShellBody, AppShellContent, AppShellMain, AppearanceEditor, AppearancePanel, AppearancePopover, AspectRatio, AttachmentCard, Avatar, AvatarFallback, AvatarImage, Badge, Board, BoardCardBody, BoardCardTitle, Breadcrumb, BreadcrumbEllipsis, BreadcrumbItem, BreadcrumbLink, BreadcrumbList, BreadcrumbSeparator, BusySendButton, Button, ButtonGroup, ButtonGroupSeparator, ButtonGroupText, CalendarSurface, Card, CardAction, CardContent, CardDescription, CardFooter, CardHeader, CardTitle, Checkbox, CheckboxDescription, CheckboxLabel, CodeBlock, Collapsible, CollapsibleContent, CollapsibleTrigger, Combobox, ComboboxClear, ComboboxContent, ComboboxControl, ComboboxInput, ComboboxItem, ComboboxSection, ComboboxTrigger, Command, CommandDialog, CommandEmpty, CommandGroup, CommandInput, CommandItem, CommandList, CommandLoading, CommandSeparator, CommandShortcut, ComposerAttachmentButton, ComposerHint, ContextMenu, ContextMenuCheckboxItem, ContextMenuContent, ContextMenuGroup, ContextMenuItem, ContextMenuLabel, ContextMenuRadioGroup, ContextMenuRadioItem, ContextMenuSeparator, ContextMenuSub, ContextMenuSubContent, ContextMenuSubTrigger, ContextMenuTrigger, ConversationAvatar, ConversationSurface, DatePicker, DetailPanel, DetailPanelBody, DetailPanelField, DetailPanelHeader, DetailPanelSection, Dialog, DialogClose, DialogCloseButton, DialogContent, DialogDescription, DialogFooter, DialogHeader, DialogOverlay, DialogPortal, DialogTitle, DialogTrigger, DiffBlock, DiffSummary, Drawer, DrawerBody, DrawerCloseButton, DrawerContent, DrawerDescription, DrawerFooter, DrawerHeader, DrawerOverlay, DrawerTitle, DrawerTrigger, DropdownMenu, DropdownMenuCheckboxItem, DropdownMenuContent, DropdownMenuGroup, DropdownMenuItem, DropdownMenuLabel, DropdownMenuPortal, DropdownMenuRadioGroup, DropdownMenuRadioItem, DropdownMenuSeparator, DropdownMenuShortcut, DropdownMenuSub, DropdownMenuSubContent, DropdownMenuSubTrigger, DropdownMenuTrigger, Empty, EmptyContent, EmptyDescription, EmptyHeader, EmptyMedia, EmptyTitle, EntityIcon, Field, FieldDescription, FieldError, FieldInput, FieldLabel, FieldLegend, FieldSeparator, FieldSet, FieldTextArea, HoverCard, HoverCardContent, HoverCardTrigger, InlineCode, Input, InputGroup, InputGroupAddon, InputGroupButton, InputGroupInput, InputGroupText, InputOtp, InputOtpCaret, Item, ItemDescription, ItemEmpty, ItemGroup, ItemGroupEntry, ItemTitle, Kbd, KbdGroup, Label, ListGroup, ListRow, MAX_LAYOUT_DEPTH, MAX_LAYOUT_LEAVES, MAX_SPLIT_RATIO, MIN_SPLIT_RATIO, Menubar, MenubarCheckboxItem, MenubarContent, MenubarGroup, MenubarItem, MenubarLabel, MenubarMenu, MenubarRadioGroup, MenubarRadioItem, MenubarSeparator, MenubarSub, MenubarSubContent, MenubarSubTrigger, MenubarTrigger, MessageBody, MessageComposer, MessageDayDivider, MessageGroup, MessageRow, ModalDialog, Motion, NavigationMenu, NavigationMenuContent, NavigationMenuGroup, NavigationMenuGroupLabel, NavigationMenuItem, NavigationMenuMenu, NavigationMenuSeparator, NavigationMenuTrigger, NavigationMenuViewport, Page, PageHeader, PageHeaderActions, PageHeaderContent, PageHeaderDescription, PageHeaderTitle, PageSection, Pagination, PaginationEllipsis, PaginationItem, PaginationNext, PaginationPrevious, PalettePreview, Panel, PanelActions, PanelBody, PanelCard, PanelDescription, PanelFooter, PanelHeader, PanelPlaceholder, PanelTitle, PanelToolbar, Popover, PopoverAnchor, PopoverCloseButton, PopoverContent, PopoverDescription, PopoverTitle, PopoverTrigger, Presence, Progress, PropertyList, PropertyRow, PropertyTerm, PropertyValue, RadioGroup, RadioGroupItem, ResizableHandle, ResizablePanel, ResizablePanelGroup, ScrollArea, Select, SelectChevronsUpDown, SelectContent, SelectItem, SelectLabel, SelectSection, SelectTrigger, SelectValue, Separator, SettingsField, SettingsPage, SettingsRow, SettingsSection, Sheet, SheetBody, SheetCloseButton, SheetContent, SheetDescription, SheetFooter, SheetHeader, SheetTitle, SheetTrigger, SideRail, SideRailButton, SideRailContent, SideRailFooter, SideRailHeader, SideRailItem, SideRailSection, SidebarNav, SidebarNavButton, SidebarNavContent, SidebarNavFooter, SidebarNavHeader, SidebarNavItem, SidebarNavSection, SidebarNavTitle, Skeleton, Slider, Spinner, SplitLayout, Stat, StatGroup, StatusBar, StatusBarItem, StatusBarSpacer, StatusChip, StatusList, Switch, SwitchDescription, SwitchLabel, TALL_CODE_BLOCK_PX, Table, TableBody, TableCaption, TableCell, TableFooter, TableHead, TableHeader, TableNumericCell, TableRow, Tabs, TabsContent, TabsList, TabsTrigger, Textarea, ThemeMiniature, ThemeMiniatureSplit, ThemePicker, ThemePreview, ThemeProvider, ThemeSwatch, ThemeToggle, ThreadPanel, Toaster, Toggle, ToggleGroup, ToggleGroupItem, Tooltip, TooltipContent, TooltipProvider, TooltipTrigger, TopBar, TopBarBreadcrumb, TopBarPill, TopBarSearch, TopBarSection, TopBarTitle, UpdateDialog, WorkspaceMark, accentPresets, alertVariants, allTokens, badgeVariants, boardCardTitleVariants, builtinThemes, buttonVariants, closePane, cn, colorTokens, computeLayoutFrames, contrastRatio, controlInteractive, controlSize, controlSizeIcon, controlSizes, countLeaves, createLayoutState, cva, defaultDarkThemeId, defaultLightThemeId, defaultThemeSelection, densityTokens, designTokens, diffLineVariants, diffStats, diffTargetPath, elevationTokens, entityIconVariants, focusPane, fontOptions, formatBytes, formatReleaseDate, initialsFrom, inlineScriptLiteral, itemVariants, keyedRows, layoutDepth, listLeaves, monogram, motionTokens, movePane, neighborLeaf, normalizeLayout, parseDiff, plainTextFromMarkdown, radiusTokens, resizeSplit, resolvedDensity, sheetVariants, sidebarNavItemClass, sidebarNavItemStateClass, splitPane, statusDotVariants, surfaceInteractive, swapPanes, themeById, themeCssVariables, themeFamilies, themeScript, themesForAppearance, toast, toaster, toggleVariants, typographyTokens, undoClosePane, undocumentedTokenAliases, useSideRail, useTheme, validateTheme, validateThemeRegistry, zIndexTokens };
96
+ export { Accordion, AccordionContent, AccordionItem, AccordionTrigger, AccountMenu, Alert, AlertDescription, AlertDialog, AlertDialogAction, AlertDialogCancel, AlertDialogContent, AlertDialogDescription, AlertDialogFooter, AlertDialogHeader, AlertDialogOverlay, AlertDialogPortal, AlertDialogTitle, AlertDialogTrigger, AlertTitle, AppShell, AppShellBody, AppShellContent, AppShellMain, AppearanceEditor, AppearancePanel, AppearancePopover, AspectRatio, AttachmentCard, Avatar, AvatarFallback, AvatarImage, Badge, Board, BoardCardBody, BoardCardTitle, Breadcrumb, BreadcrumbEllipsis, BreadcrumbItem, BreadcrumbLink, BreadcrumbList, BreadcrumbSeparator, BusySendButton, Button, ButtonGroup, ButtonGroupSeparator, ButtonGroupText, CalendarSurface, Card, CardAction, CardContent, CardDescription, CardFooter, CardHeader, CardTitle, ChatComposer, Checkbox, CheckboxDescription, CheckboxLabel, CodeBlock, Collapsible, CollapsibleContent, CollapsibleTrigger, Combobox, ComboboxClear, ComboboxContent, ComboboxControl, ComboboxInput, ComboboxItem, ComboboxSection, ComboboxTrigger, Command, CommandDialog, CommandEmpty, CommandGroup, CommandInput, CommandItem, CommandList, CommandLoading, CommandSeparator, CommandShortcut, ComposerAttachmentButton, ComposerHint, ContextMenu, ContextMenuCheckboxItem, ContextMenuContent, ContextMenuGroup, ContextMenuItem, ContextMenuLabel, ContextMenuRadioGroup, ContextMenuRadioItem, ContextMenuSeparator, ContextMenuSub, ContextMenuSubContent, ContextMenuSubTrigger, ContextMenuTrigger, ConversationAvatar, ConversationSurface, DatePicker, DetailPanel, DetailPanelBody, DetailPanelField, DetailPanelHeader, DetailPanelSection, Dialog, DialogClose, DialogCloseButton, DialogContent, DialogDescription, DialogFooter, DialogHeader, DialogOverlay, DialogPortal, DialogTitle, DialogTrigger, DiffBlock, DiffSummary, Drawer, DrawerBody, DrawerCloseButton, DrawerContent, DrawerDescription, DrawerFooter, DrawerHeader, DrawerOverlay, DrawerTitle, DrawerTrigger, DropdownMenu, DropdownMenuCheckboxItem, DropdownMenuContent, DropdownMenuGroup, DropdownMenuItem, DropdownMenuLabel, DropdownMenuPortal, DropdownMenuRadioGroup, DropdownMenuRadioItem, DropdownMenuSeparator, DropdownMenuShortcut, DropdownMenuSub, DropdownMenuSubContent, DropdownMenuSubTrigger, DropdownMenuTrigger, Empty, EmptyContent, EmptyDescription, EmptyHeader, EmptyMedia, EmptyTitle, EntityIcon, Field, FieldDescription, FieldError, FieldInput, FieldLabel, FieldLegend, FieldSeparator, FieldSet, FieldTextArea, HoverCard, HoverCardContent, HoverCardTrigger, InlineCode, Input, InputGroup, InputGroupAddon, InputGroupButton, InputGroupInput, InputGroupText, InputOtp, InputOtpCaret, Item, ItemDescription, ItemEmpty, ItemGroup, ItemGroupEntry, ItemTitle, Kbd, KbdGroup, Label, ListGroup, ListRow, MAX_LAYOUT_DEPTH, MAX_LAYOUT_LEAVES, MAX_SPLIT_RATIO, MIN_SPLIT_RATIO, Menubar, MenubarCheckboxItem, MenubarContent, MenubarGroup, MenubarItem, MenubarLabel, MenubarMenu, MenubarRadioGroup, MenubarRadioItem, MenubarSeparator, MenubarSub, MenubarSubContent, MenubarSubTrigger, MenubarTrigger, MessageBody, MessageComposer, MessageDayDivider, MessageGroup, MessageRow, ModalDialog, Motion, NavigationMenu, NavigationMenuContent, NavigationMenuGroup, NavigationMenuGroupLabel, NavigationMenuItem, NavigationMenuMenu, NavigationMenuSeparator, NavigationMenuTrigger, NavigationMenuViewport, Page, PageHeader, PageHeaderActions, PageHeaderContent, PageHeaderDescription, PageHeaderTitle, PageSection, Pagination, PaginationEllipsis, PaginationItem, PaginationNext, PaginationPrevious, PalettePreview, Panel, PanelActions, PanelBody, PanelCard, PanelDescription, PanelFooter, PanelHeader, PanelPlaceholder, PanelTitle, PanelToolbar, Popover, PopoverAnchor, PopoverCloseButton, PopoverContent, PopoverDescription, PopoverTitle, PopoverTrigger, Presence, Progress, PropertyList, PropertyRow, PropertyTerm, PropertyValue, RadioGroup, RadioGroupItem, ResizableHandle, ResizablePanel, ResizablePanelGroup, ScrollArea, Select, SelectChevronsUpDown, SelectContent, SelectItem, SelectLabel, SelectSection, SelectTrigger, SelectValue, Separator, SettingsField, SettingsPage, SettingsRow, SettingsSection, Sheet, SheetBody, SheetCloseButton, SheetContent, SheetDescription, SheetFooter, SheetHeader, SheetTitle, SheetTrigger, SideRail, SideRailButton, SideRailContent, SideRailFooter, SideRailHeader, SideRailItem, SideRailSection, SidebarNav, SidebarNavButton, SidebarNavContent, SidebarNavFooter, SidebarNavHeader, SidebarNavItem, SidebarNavSection, SidebarNavTitle, Skeleton, Slider, Spinner, SplitLayout, Stat, StatGroup, StatusBar, StatusBarItem, StatusBarSpacer, StatusChip, StatusList, Switch, SwitchDescription, SwitchLabel, TALL_CODE_BLOCK_PX, Table, TableBody, TableCaption, TableCell, TableFooter, TableHead, TableHeader, TableNumericCell, TableRow, Tabs, TabsContent, TabsList, TabsTrigger, Textarea, ThemeMiniature, ThemeMiniatureSplit, ThemePicker, ThemePreview, ThemeProvider, ThemeSwatch, ThemeToggle, ThreadPanel, Toaster, Toggle, ToggleGroup, ToggleGroupItem, Tooltip, TooltipContent, TooltipProvider, TooltipTrigger, TopBar, TopBarBreadcrumb, TopBarPill, TopBarSearch, TopBarSection, TopBarTitle, UpdateDialog, WorkspaceMark, accentPresets, alertVariants, allTokens, badgeVariants, boardCardTitleVariants, builtinThemes, buttonVariants, closePane, cn, colorTokens, computeLayoutFrames, contrastRatio, controlInteractive, controlSize, controlSizeIcon, controlSizes, countLeaves, createLayoutState, cva, defaultDarkThemeId, defaultLightThemeId, defaultThemeSelection, densityTokens, designTokens, diffLineVariants, diffStats, diffTargetPath, elevationTokens, entityIconVariants, focusPane, fontOptions, formatBytes, formatReleaseDate, initialsFrom, inlineScriptLiteral, itemVariants, keyedRows, layoutDepth, listLeaves, monogram, motionTokens, movePane, neighborLeaf, normalizeLayout, parseDiff, plainTextFromMarkdown, radiusTokens, resizeSplit, resolvedDensity, sheetVariants, sidebarNavItemClass, sidebarNavItemStateClass, splitPane, statusDotVariants, surfaceInteractive, swapPanes, themeById, themeCssVariables, themeFamilies, themeScript, themesForAppearance, toast, toaster, toggleVariants, typographyTokens, undoClosePane, undocumentedTokenAliases, useSideRail, useTheme, validateTheme, validateThemeRegistry, zIndexTokens };
@@ -22,6 +22,11 @@
22
22
  "type": "registry:ui",
23
23
  "target": "components/conversation/busy-send-button.tsx"
24
24
  },
25
+ {
26
+ "path": "src/components/conversation/chat-composer.tsx",
27
+ "type": "registry:ui",
28
+ "target": "components/conversation/chat-composer.tsx"
29
+ },
25
30
  {
26
31
  "path": "src/components/conversation/conversation-avatar.tsx",
27
32
  "type": "registry:ui",
@@ -1836,6 +1836,11 @@
1836
1836
  "type": "registry:ui",
1837
1837
  "target": "components/conversation/busy-send-button.tsx"
1838
1838
  },
1839
+ {
1840
+ "path": "src/components/conversation/chat-composer.tsx",
1841
+ "type": "registry:ui",
1842
+ "target": "components/conversation/chat-composer.tsx"
1843
+ },
1839
1844
  {
1840
1845
  "path": "src/components/conversation/conversation-avatar.tsx",
1841
1846
  "type": "registry:ui",
@@ -0,0 +1,378 @@
1
+ /*
2
+ * Substantially translated from KiroCrew website/src/components/ChatInput.tsx
3
+ * at 283e136c0f902e965a535a7c9548c57c7504fed0.
4
+ * Copyright Amazon.com, Inc. or its affiliates. All Rights Reserved.
5
+ * Licensed under Apache-2.0; see LICENSE and NOTICE.
6
+ */
7
+ import { ChevronsDownUp, ChevronsUpDown, MoreHorizontal, ArrowUp } from 'lucide-solid'
8
+ import { Show, createEffect, createSignal, on, onCleanup, onMount, type JSX } from 'solid-js'
9
+ import { Button } from '../ui/button/button'
10
+ import {
11
+ DropdownMenu,
12
+ DropdownMenuContent,
13
+ DropdownMenuItem,
14
+ DropdownMenuTrigger,
15
+ } from '../ui/dropdown-menu/dropdown-menu'
16
+ import { Spinner } from '../ui/spinner/spinner'
17
+ import { BusySendButton, type BusySendButtonProps, type BusySendMode } from './busy-send-button'
18
+ import { createComposerImeGuard } from './ime-guard'
19
+
20
+ export type ChatComposerControl = {
21
+ /** Focus this instance; false when it is unavailable or collapsed. */
22
+ focus: () => boolean
23
+ /** A typing intent, unlike merely navigating to a conversation. */
24
+ expandAndFocus: () => boolean
25
+ }
26
+ export type ChatComposerProps = {
27
+ value: string
28
+ onValueChange: (value: string) => void
29
+ /** The host owns attachments and delivery; text/action are captured at the gesture. */
30
+ onSubmit: (input: { text: string; action: 'send' | BusySendMode }) => void | Promise<void>
31
+ /** Host scope fence; changes discard local feedback, not the host draft. */
32
+ resetKey?: unknown
33
+ disabled?: boolean
34
+ readOnly?: boolean
35
+ /** A visible capability or connectivity reason. */
36
+ blockedReason?: string
37
+ placeholder?: string
38
+ inputLabel?: string
39
+ /** Opt-in and controlled: the library neither persists nor broadcasts it. */
40
+ collapse?: { value: boolean; onChange: (value: boolean) => void }
41
+ controlRef?: (control: ChatComposerControl | undefined) => void
42
+ /** Host payload eligibility by action; explicit false refuses even a nonempty draft. */
43
+ sendableActions?: Partial<Record<'send' | BusySendMode, boolean>>
44
+ busy?: Omit<BusySendButtonProps, 'onFire' | 'disabled' | 'alternateActionHint'>
45
+ knowledge?: JSX.Element
46
+ followUps?: JSX.Element
47
+ band?: JSX.Element
48
+ approval?: JSX.Element
49
+ notices?: JSX.Element
50
+ attachments?: JSX.Element
51
+ leadingActions?: JSX.Element
52
+ trailingActions?: JSX.Element
53
+ /** Host-contributed menu items; no upload, skill or permission services here. */
54
+ menuItems?: JSX.Element
55
+ context?: JSX.Element
56
+ /** Host derives this from the pending approval presentation, not UI policy. */
57
+ approvalFocus?: boolean
58
+ }
59
+
60
+ /**
61
+ * Kiro's composer assembly: context/options, adjacent band, approval/notices,
62
+ * staged content, input/action groups and a context shelf. Reading collapse
63
+ * really unmounts the input and shelf and offers a labeled way back with draft
64
+ * preview. The host retains the only draft, identities, preferences and services.
65
+ *
66
+ * Kobalte owns the options menu. Scoped imperative typing intent replaces the
67
+ * donor global lookup/broadcast so a second composer cannot receive this draft
68
+ * or focus. No animation starts from hidden geometry, no global shortcut, and no
69
+ * runtime/permission/voice/optimizer authority is copied. More specific chips,
70
+ * approval decisions and staged-content semantics are supplied by their owners.
71
+ */
72
+ export function ChatComposer(props: ChatComposerProps) {
73
+ const ime = createComposerImeGuard()
74
+ const [pending, setPending] = createSignal(false)
75
+ const [error, setError] = createSignal<string | null>(null)
76
+ let field: HTMLTextAreaElement | undefined
77
+ let restoreBar: HTMLButtonElement | undefined
78
+ let focusFrame: number | undefined
79
+ let focusTarget: 'input' | 'bar' | undefined
80
+ let selection:
81
+ | { start: number; end: number; direction: 'forward' | 'backward' | 'none' }
82
+ | undefined
83
+ let generation = 0
84
+ let active = true
85
+ const collapsed = () => props.collapse?.value === true
86
+ const unavailable = () => props.disabled || props.readOnly || !!props.blockedReason
87
+ const cancelFocus = () => {
88
+ if (focusFrame !== undefined) cancelAnimationFrame(focusFrame)
89
+ focusFrame = undefined
90
+ }
91
+ const requestFocus = (target: 'input' | 'bar') => {
92
+ cancelFocus()
93
+ focusTarget = target
94
+ focusFrame = requestAnimationFrame(() => {
95
+ focusFrame = undefined
96
+ if (!active || props.approvalFocus) return
97
+ if (target === 'bar' && collapsed()) restoreBar?.focus()
98
+ if (target === 'input' && !collapsed() && !props.disabled && field) {
99
+ field.focus()
100
+ if (selection)
101
+ field.setSelectionRange(
102
+ Math.min(selection.start, field.value.length),
103
+ Math.min(selection.end, field.value.length),
104
+ selection.direction
105
+ )
106
+ }
107
+ focusTarget = undefined
108
+ })
109
+ }
110
+ const changeCollapsed = (value: boolean) => {
111
+ if (!props.collapse || props.approvalFocus) return
112
+ if (value && field)
113
+ selection = {
114
+ start: field.selectionStart,
115
+ end: field.selectionEnd,
116
+ direction: field.selectionDirection,
117
+ }
118
+ props.collapse.onChange(value)
119
+ requestFocus(value ? 'bar' : 'input')
120
+ }
121
+ const control: ChatComposerControl = {
122
+ focus() {
123
+ if (collapsed() || props.approvalFocus || props.disabled || !field) return false
124
+ field.focus()
125
+ return true
126
+ },
127
+ expandAndFocus() {
128
+ if (props.approvalFocus || props.disabled) return false
129
+ if (collapsed()) changeCollapsed(false)
130
+ else requestFocus('input')
131
+ return true
132
+ },
133
+ }
134
+ onMount(() => props.controlRef?.(control))
135
+ createEffect(
136
+ on(
137
+ () => props.resetKey,
138
+ () => {
139
+ generation += 1
140
+ selection = undefined
141
+ cancelFocus()
142
+ focusTarget = undefined
143
+ setPending(false)
144
+ setError(null)
145
+ ime.onBlur()
146
+ },
147
+ { defer: true }
148
+ )
149
+ )
150
+ onCleanup(() => {
151
+ active = false
152
+ generation += 1
153
+ cancelFocus()
154
+ props.controlRef?.(undefined)
155
+ })
156
+ const action = (): 'send' | BusySendMode => props.busy?.mode ?? 'send'
157
+ const canSend = (selected: 'send' | BusySendMode = action()) =>
158
+ !unavailable() &&
159
+ !pending() &&
160
+ (props.sendableActions?.[selected] ?? props.value.trim().length > 0) &&
161
+ !(selected !== 'send' && props.busy?.unavailable?.[selected])
162
+ const submit = async (selected: 'send' | BusySendMode = action()) => {
163
+ if (!canSend(selected)) return
164
+ const started = generation
165
+ const input = { text: props.value, action: selected }
166
+ setPending(true)
167
+ setError(null)
168
+ try {
169
+ await props.onSubmit(input)
170
+ } catch {
171
+ if (active && started === generation)
172
+ setError('Message not sent. Check your draft and retry when the connection recovers.')
173
+ } finally {
174
+ if (active && started === generation) setPending(false)
175
+ }
176
+ }
177
+ const preview = () => {
178
+ const first =
179
+ props.value
180
+ .split('\n')
181
+ .find((line) => line.trim().length > 0)
182
+ ?.trim() ?? ''
183
+ return first.length > 120 ? `${first.slice(0, 120)}…` : first
184
+ }
185
+ return (
186
+ <div data-slot="chat-composer" class="mx-auto flex w-full max-w-4xl flex-col px-4 pb-1">
187
+ <Show when={!props.approvalFocus}>
188
+ <Show when={props.knowledge}>
189
+ <div data-slot="composer-knowledge">{props.knowledge}</div>
190
+ </Show>
191
+ <Show when={props.followUps}>
192
+ <div data-slot="composer-follow-ups">{props.followUps}</div>
193
+ </Show>
194
+ </Show>
195
+ <Show when={props.band}>
196
+ <div data-slot="composer-band">{props.band}</div>
197
+ </Show>
198
+ <div aria-hidden="true" class="h-1.5 shrink-0" />
199
+ <Show when={props.approval}>
200
+ <div data-slot="composer-approval">{props.approval}</div>
201
+ </Show>
202
+ <Show when={props.notices}>
203
+ <div data-slot="composer-notices">{props.notices}</div>
204
+ </Show>
205
+ <Show when={props.blockedReason}>
206
+ <p role="status" class="text-muted-foreground mb-1 text-xs">
207
+ {props.blockedReason}
208
+ </p>
209
+ </Show>
210
+ <Show when={error()}>
211
+ {(message) => (
212
+ <p role="alert" class="text-destructive mb-1 text-xs">
213
+ {message()}
214
+ </p>
215
+ )}
216
+ </Show>
217
+ <Show when={!props.approvalFocus}>
218
+ <Show
219
+ when={!collapsed()}
220
+ fallback={
221
+ <Button
222
+ ref={(element) => {
223
+ restoreBar = element
224
+ onCleanup(() => {
225
+ if (restoreBar === element) restoreBar = undefined
226
+ })
227
+ }}
228
+ type="button"
229
+ variant="outline"
230
+ size="sm"
231
+ class="w-full justify-start"
232
+ aria-expanded={false}
233
+ aria-label="Show the message input"
234
+ onClick={() => changeCollapsed(false)}
235
+ >
236
+ <ChevronsUpDown />
237
+ <span aria-hidden="true" class="shrink-0">
238
+ Show the message input
239
+ </span>
240
+ <Show when={preview()}>
241
+ <span aria-hidden="true" class="min-w-0 flex-1 truncate">
242
+ {preview()}
243
+ </span>
244
+ </Show>
245
+ </Button>
246
+ }
247
+ >
248
+ <form
249
+ data-slot="composer-input-box"
250
+ class="border-input bg-card flex flex-col overflow-hidden rounded-2xl border transition-colors focus-within:border-ring"
251
+ onSubmit={(event) => {
252
+ event.preventDefault()
253
+ void submit()
254
+ }}
255
+ >
256
+ <Show when={props.attachments}>
257
+ <div data-slot="composer-staged-content">{props.attachments}</div>
258
+ </Show>
259
+ <textarea
260
+ ref={(element) => {
261
+ field = element
262
+ onCleanup(() => {
263
+ if (field === element) field = undefined
264
+ })
265
+ }}
266
+ data-slot="composer-input"
267
+ aria-label={props.inputLabel ?? 'Message'}
268
+ class="field-sizing-content text-foreground placeholder:text-muted-foreground min-h-11 max-h-36 w-full resize-none border-0 bg-transparent px-4 py-3 text-sm outline-none disabled:opacity-50"
269
+ value={props.value}
270
+ onInput={(event) => props.onValueChange(event.currentTarget.value)}
271
+ disabled={props.disabled}
272
+ readOnly={props.readOnly || pending()}
273
+ placeholder={props.placeholder ?? 'Write a message…'}
274
+ rows={1}
275
+ onCompositionStart={ime.onCompositionStart}
276
+ onCompositionEnd={ime.onCompositionEnd}
277
+ onFocus={ime.onFocus}
278
+ onBlur={ime.onBlur}
279
+ onKeyDown={(event) => {
280
+ if (event.key === 'Escape' && error()) {
281
+ setError(null)
282
+ return
283
+ }
284
+ if (event.key !== 'Enter' || event.shiftKey || event.defaultPrevented) return
285
+ if (ime.claimEnter(event)) {
286
+ const selected =
287
+ props.busy && (event.metaKey || event.ctrlKey)
288
+ ? props.busy.mode === 'steer'
289
+ ? 'queue'
290
+ : 'steer'
291
+ : action()
292
+ void submit(selected)
293
+ }
294
+ }}
295
+ />
296
+ <div
297
+ data-slot="composer-action-row"
298
+ class="flex items-center justify-between gap-2 px-2.5 pb-2 pt-0.5"
299
+ >
300
+ <div class="flex min-w-0 items-center gap-1">
301
+ <Show when={props.collapse || props.menuItems}>
302
+ <DropdownMenu placement="top-start">
303
+ <DropdownMenuTrigger
304
+ as={Button}
305
+ type="button"
306
+ variant="ghost"
307
+ size="icon-sm"
308
+ aria-label="Message input options"
309
+ >
310
+ <MoreHorizontal />
311
+ </DropdownMenuTrigger>
312
+ <DropdownMenuContent
313
+ onCloseAutoFocus={(event) => {
314
+ if (focusTarget) event.preventDefault()
315
+ }}
316
+ >
317
+ {props.menuItems}
318
+ <Show when={props.collapse}>
319
+ <DropdownMenuItem onSelect={() => changeCollapsed(true)}>
320
+ <ChevronsDownUp />
321
+ <div class="flex min-w-0 flex-col">
322
+ <span>Collapse the message input</span>
323
+ <span class="text-muted-foreground text-xs">
324
+ Make room to read; keep your draft
325
+ </span>
326
+ </div>
327
+ </DropdownMenuItem>
328
+ </Show>
329
+ </DropdownMenuContent>
330
+ </DropdownMenu>
331
+ </Show>
332
+ {props.leadingActions}
333
+ </div>
334
+ <div class="flex shrink-0 items-center gap-1">
335
+ {props.trailingActions}
336
+ <Show
337
+ when={props.busy}
338
+ fallback={
339
+ <Button
340
+ type="submit"
341
+ size="icon-sm"
342
+ disabled={!canSend()}
343
+ aria-label={pending() ? 'Sending message' : 'Send message'}
344
+ >
345
+ <Show when={pending()} fallback={<ArrowUp />}>
346
+ <Spinner size="sm" label={false} />
347
+ </Show>
348
+ </Button>
349
+ }
350
+ >
351
+ {(busy) => (
352
+ <BusySendButton
353
+ {...busy()}
354
+ alternateActionHint={
355
+ canSend(busy().mode === 'steer' ? 'queue' : 'steer')
356
+ ? 'Ctrl/Cmd+Enter uses the other action'
357
+ : undefined
358
+ }
359
+ disabled={!canSend()}
360
+ onFire={() => {
361
+ void submit()
362
+ }}
363
+ />
364
+ )}
365
+ </Show>
366
+ </div>
367
+ </div>
368
+ </form>
369
+ <Show when={props.context}>
370
+ <div data-slot="composer-context" class="flex min-w-0 items-center gap-2 pt-1">
371
+ {props.context}
372
+ </div>
373
+ </Show>
374
+ </Show>
375
+ </Show>
376
+ </div>
377
+ )
378
+ }
@@ -1,3 +1,4 @@
1
+ export { ChatComposer, type ChatComposerProps, type ChatComposerControl } from './chat-composer'
1
2
  export { BusySendButton, type BusySendMode, type BusySendButtonProps } from './busy-send-button'
2
3
  export {
3
4
  ConversationAvatar,
@@ -307,6 +307,16 @@ export function SplitLayout<L extends SplitLayoutLeaf>(props: SplitLayoutProps<L
307
307
  sizes={[branch().ratio, 1 - branch().ratio]}
308
308
  keyboardDelta={0.05}
309
309
  onSizesChange={(sizes) => {
310
+ // Corvu also reports panel registration/unregistration while
311
+ // mounting or disposing a controller. Those incomplete or
312
+ // hidden-host sizes are not user resize intent.
313
+ if (!root?.isConnected || root.getClientRects().length === 0) return
314
+ if (
315
+ sizes.length !== 2 ||
316
+ sizes.some((size) => !Number.isFinite(size)) ||
317
+ Math.abs(sizes[0]! + sizes[1]! - 1) > 0.000001
318
+ )
319
+ return
310
320
  if (sizes[0] !== undefined && Math.abs(sizes[0] - branch().ratio) > 0.000001)
311
321
  props.onResize(id, sizes[0])
312
322
  }}
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@adea-ai/ui",
3
- "version": "0.65.1",
3
+ "version": "0.66.1",
4
4
  "description": "The Adea design system: Kobalte-backed Solid components, semantic OKLCH tokens, and the app-shell layout primitives shared by Adea and Cortana.",
5
5
  "keywords": [
6
6
  "adea",
@@ -86,6 +86,7 @@
86
86
  "theme:check": "bun scripts/build-default-theme.ts --check",
87
87
  "check:packed-layout": "node scripts/check-packed-layout.mjs",
88
88
  "check:packed-consumer": "bun scripts/check-packed-consumer.ts",
89
+ "check:packed-conversation": "bun scripts/check-packed-conversation.ts",
89
90
  "check:packed-layout-renderer": "bun scripts/check-packed-layout-renderer.ts",
90
91
  "check:packed-appearance": "bun scripts/check-packed-appearance.ts"
91
92
  },
package/registry.json CHANGED
@@ -1836,6 +1836,11 @@
1836
1836
  "type": "registry:ui",
1837
1837
  "target": "components/conversation/busy-send-button.tsx"
1838
1838
  },
1839
+ {
1840
+ "path": "src/components/conversation/chat-composer.tsx",
1841
+ "type": "registry:ui",
1842
+ "target": "components/conversation/chat-composer.tsx"
1843
+ },
1839
1844
  {
1840
1845
  "path": "src/components/conversation/conversation-avatar.tsx",
1841
1846
  "type": "registry:ui",