@adea-ai/ui 0.116.0 → 0.117.0

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (30) hide show
  1. package/dist/components/conversation/transcript-composition.d.ts +6 -0
  2. package/dist/components/conversation/transcript-composition.d.ts.map +1 -1
  3. package/dist/components/conversation/transcript-composition.js +9 -4
  4. package/dist/components/conversation/transcript-composition.js.map +1 -1
  5. package/dist/components/layout/contextual-sidebar/contextual-sidebar.d.ts +2 -0
  6. package/dist/components/layout/contextual-sidebar/contextual-sidebar.d.ts.map +1 -1
  7. package/dist/components/layout/contextual-sidebar/contextual-sidebar.js +3 -0
  8. package/dist/components/layout/contextual-sidebar/contextual-sidebar.js.map +1 -1
  9. package/dist/components/layout/contextual-sidebar/mobile-contextual-sidebar.d.ts.map +1 -1
  10. package/dist/components/layout/contextual-sidebar/mobile-contextual-sidebar.js +1 -1
  11. package/dist/components/layout/contextual-sidebar/mobile-contextual-sidebar.js.map +1 -1
  12. package/dist/components/layout/pixel-resize-handle/pixel-resize-handle.d.ts +2 -0
  13. package/dist/components/layout/pixel-resize-handle/pixel-resize-handle.d.ts.map +1 -1
  14. package/dist/components/layout/pixel-resize-handle/pixel-resize-handle.js +3 -1
  15. package/dist/components/layout/pixel-resize-handle/pixel-resize-handle.js.map +1 -1
  16. package/dist/components/ui/resizable/resizable.d.ts +7 -2
  17. package/dist/components/ui/resizable/resizable.d.ts.map +1 -1
  18. package/dist/components/ui/resizable/resizable.js +7 -6
  19. package/dist/components/ui/resizable/resizable.js.map +1 -1
  20. package/dist/r/src/components/conversation/transcript-composition.tsx +14 -2
  21. package/dist/r/src/components/layout/contextual-sidebar/contextual-sidebar.tsx +3 -0
  22. package/dist/r/src/components/layout/contextual-sidebar/mobile-contextual-sidebar.tsx +6 -1
  23. package/dist/r/src/components/layout/pixel-resize-handle/pixel-resize-handle.tsx +3 -1
  24. package/dist/r/src/components/ui/resizable/resizable.tsx +15 -4
  25. package/package.json +1 -1
  26. package/src/components/conversation/transcript-composition.tsx +14 -2
  27. package/src/components/layout/contextual-sidebar/contextual-sidebar.tsx +3 -0
  28. package/src/components/layout/contextual-sidebar/mobile-contextual-sidebar.tsx +6 -1
  29. package/src/components/layout/pixel-resize-handle/pixel-resize-handle.tsx +3 -1
  30. package/src/components/ui/resizable/resizable.tsx +15 -4
@@ -53,6 +53,12 @@ export type TranscriptCompositionProps<T> = Omit<ComponentProps<'div'>, 'childre
53
53
  /** Optional controlled disclosure map keyed by `transcriptDisclosureKey`. */
54
54
  disclosure?: ReadonlyMap<string, boolean>;
55
55
  onDisclosureChange?: (key: string, expanded: boolean) => void;
56
+ /**
57
+ * Row rhythm. `compact` (default) packs rows 4px apart; `comfortable` spaces
58
+ * them 12px apart and stacks each row's rendered parts, for a chat stream
59
+ * whose rows are separate messages rather than one running log.
60
+ */
61
+ density?: 'compact' | 'comfortable';
56
62
  };
57
63
  /** Stable, transcript-scoped key for host-owned disclosure restoration. */
58
64
  export declare function transcriptDisclosureKey(resetKey: string | number | null | undefined, mode: TranscriptFoldMode, firstRowId: string): string;
@@ -1 +1 @@
1
- {"version":3,"file":"transcript-composition.d.ts","sourceRoot":"","sources":["../../../src/components/conversation/transcript-composition.tsx"],"names":[],"mappings":"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"}
1
+ {"version":3,"file":"transcript-composition.d.ts","sourceRoot":"","sources":["../../../src/components/conversation/transcript-composition.tsx"],"names":[],"mappings":"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"}
@@ -2,14 +2,14 @@ import { cn } from "../../lib/utils.js";
2
2
  import { Button } from "../ui/button/button.js";
3
3
  import { applyTranscriptRunningState, createTranscriptGrouper } from "./transcript-grouping.js";
4
4
  import { planTranscriptFold } from "./transcript-folding.js";
5
- import { createComponent, effect, insert, memo, mergeProps, setAttribute, spread, template } from "solid-js/web";
5
+ import { className, createComponent, effect, insert, memo, mergeProps, setAttribute, spread, template } from "solid-js/web";
6
6
  import { ChevronDown } from "lucide-solid";
7
7
  import { For, Show, createComponent as createComponent$1, createMemo, createSignal, createUniqueId, splitProps } from "solid-js";
8
8
  //#region src/components/conversation/transcript-composition.tsx
9
- var _tmpl$ = /*#__PURE__*/ template(`<div data-slot=transcript-row class="flex min-w-0 flex-col gap-1"><div data-slot=transcript-row-content>`);
9
+ var _tmpl$ = /*#__PURE__*/ template(`<div data-slot=transcript-row class="flex min-w-0 flex-col gap-1"><div data-slot=transcript-row-content class="group-data-[density=comfortable]/transcript:flex group-data-[density=comfortable]/transcript:flex-col">`);
10
10
  var _tmpl$2 = /*#__PURE__*/ template(`<span>`);
11
11
  var _tmpl$3 = /*#__PURE__*/ template(`<div class="flex justify-end">`);
12
- var _tmpl$4 = /*#__PURE__*/ template(`<div data-slot=transcript-composition><div data-slot=transcript-rows class="flex min-w-0 flex-col gap-1">`);
12
+ var _tmpl$4 = /*#__PURE__*/ template(`<div data-slot=transcript-composition><div data-slot=transcript-rows>`);
13
13
  var encodeId = (value) => encodeURIComponent(value);
14
14
  /** Stable, transcript-scoped key for host-owned disclosure restoration. */
15
15
  function transcriptDisclosureKey(resetKey, mode, firstRowId) {
@@ -240,6 +240,7 @@ function TranscriptComposition(props) {
240
240
  "foldMode",
241
241
  "foldState",
242
242
  "onFoldStateChange",
243
+ "density",
243
244
  "disclosure",
244
245
  "onDisclosureChange"
245
246
  ]);
@@ -338,8 +339,11 @@ function TranscriptComposition(props) {
338
339
  get ["data-fold-state"]() {
339
340
  return foldState();
340
341
  },
342
+ get ["data-density"]() {
343
+ return local.density ?? "compact";
344
+ },
341
345
  get ["class"]() {
342
- return cn("flex w-full min-w-0 flex-col gap-1", local.class);
346
+ return cn("group/transcript flex w-full min-w-0 flex-col gap-1", local.class);
343
347
  }
344
348
  }, rest), false, true);
345
349
  insert(_el$4, createComponent(Show, {
@@ -386,6 +390,7 @@ function TranscriptComposition(props) {
386
390
  onToggle: updateDisclosure
387
391
  })
388
392
  }));
393
+ effect(() => className(_el$6, cn("flex min-w-0 flex-col", local.density === "comfortable" ? "gap-3" : "gap-1")));
389
394
  return _el$4;
390
395
  })();
391
396
  }
@@ -1 +1 @@
1
- {"version":3,"file":"transcript-composition.js","names":["Accessor","Component","ComponentProps","For","Show","createComponent","createMemo","createSignal","createUniqueId","splitProps","ChevronDown","cn","Button","applyTranscriptRunningState","createTranscriptGrouper","TranscriptDisplayItem","TranscriptRow","TranscriptTurnItem","planTranscriptFold","TranscriptFoldMode","TranscriptMounting","TranscriptFoldState","TranscriptDisplayKind","GroupedTranscript","TranscriptFoldPlan","TranscriptCompositionFold","Readonly","key","mode","mounting","callCount","TranscriptCompositionRowContext","index","displayKind","group","size","turn","id","complete","interim","fold","TranscriptCompositionRendererProps","row","T","context","TranscriptCompositionProps","Omit","rows","renderRow","running","resetKey","foldMode","foldState","onFoldStateChange","state","disclosure","ReadonlyMap","onDisclosureChange","expanded","TurnPresentation","NonNullable","GroupPresentation","FoldGroup","RowRecord","foldControl","TranscriptLayout","controls","RowHandle","get","set","next","last","DisclosureSignal","encodeId","value","encodeURIComponent","transcriptDisclosureKey","firstRowId","String","panelId","instanceId","rowId","buttonId","segmentKey","sameGroup","a","b","sameTurn","sameFold","sameFoldGroup","length","every","sameRecord","firstRow","item","kind","appendTurnItem","indices","into","push","forEach","startIndex","appendDisplayItem","undefined","turnId","items","map","find","child","buildDisclosures","records","defaultMode","scope","flushScope","record","hasInterimTurn","some","hasConclusion","conclusion","plan","settled","foldable","entries","flatMap","entry","anchorId","control","opensTurn","foldLabel","count","subject","TranscriptRowEntry","props","prefix","onToggle","current","disclosureKey","collapsed","disabled","groupIndex","groupSize","renderable","renderHostRow","controlLabel","controlRows","join","_el$","_tmpl$","_el$2","firstChild","_$insert","_$createComponent","when","children","type","variant","aria-label","aria-controls","aria-expanded","aria-disabled","onClick","_el$3","_tmpl$2","_$memo","_$effect","_p$","_v$","_v$2","_v$3","_v$4","_v$5","_v$6","e","_$setAttribute","t","o","i","hidden","n","TranscriptComposition","local","rest","grouper","internalFoldState","setInternalFoldState","rowHandles","Map","disclosureSignals","lastResetKey","localDisclosure","signal","disclosureExpanded","grouped","layout","identity","clear","indexByRow","display","handles","live","Set","result","add","handle","keys","has","delete","allControlIds","updateFoldState","updateDisclosure","_el$4","_tmpl$4","_el$6","_$spread","_$mergeProps","data-fold-state","class","_el$5","_tmpl$3","each","createComponent","_$createComponent","_$memo","_$setAttribute","_$mergeProps"],"sources":["../../../src/components/conversation/transcript-composition.tsx"],"sourcesContent":["import type { Accessor, Component, ComponentProps } from 'solid-js'\nimport {\n For,\n Show,\n createComponent,\n createMemo,\n createSignal,\n createUniqueId,\n splitProps,\n} from 'solid-js'\nimport { ChevronDown } from 'lucide-solid'\nimport { cn } from '#lib/utils'\nimport { Button } from '../ui/button/button'\nimport {\n applyTranscriptRunningState,\n createTranscriptGrouper,\n type TranscriptDisplayItem,\n type TranscriptRow,\n type TranscriptTurnItem,\n} from './transcript-grouping'\nimport {\n planTranscriptFold,\n type TranscriptFoldMode,\n type TranscriptMounting,\n} from './transcript-folding'\n\nexport type TranscriptFoldState = 'default' | 'collapsed' | 'expanded'\nexport type TranscriptDisplayKind = 'single' | 'group' | 'turn'\n\nexport type {\n GroupedTranscript,\n TranscriptDisplayItem,\n TranscriptRow,\n TranscriptTurnItem,\n} from './transcript-grouping'\nexport type {\n TranscriptFoldMode,\n TranscriptFoldPlan,\n TranscriptMounting,\n} from './transcript-folding'\n\nexport type TranscriptCompositionFold = Readonly<{\n /** Stable host persistence key. Use with `transcriptDisclosureKey` to seed a store. */\n key: string\n mode: TranscriptFoldMode\n mounting: TranscriptMounting\n /** Distinct host-classified request IDs in this contiguous fold segment. */\n callCount: number\n}>\n\nexport type TranscriptCompositionRowContext = Readonly<{\n /** Original index in the caller's row array, including rows hidden by the host. */\n index: number\n /** The row's current position in the generic display composition. */\n displayKind: TranscriptDisplayKind\n group?: Readonly<{ index: number; size: number }>\n turn?: Readonly<{\n /** Derived from the first stable row ID; presentation bookkeeping only. */\n id: string\n /** A presentation state, never proof of successful runtime completion. */\n complete: boolean\n interim: boolean\n }>\n fold?: TranscriptCompositionFold\n}>\n\nexport type TranscriptCompositionRendererProps<T> = Readonly<{\n /** Reactive Solid prop; a row component keeps its DOM owner stable as values update. */\n row: TranscriptRow<T>\n context: TranscriptCompositionRowContext\n}>\n\nexport type TranscriptCompositionProps<T> = Omit<ComponentProps<'div'>, 'children'> & {\n /** Ordered, already redacted rows with host-supplied semantic classifications. */\n rows: readonly TranscriptRow<T>[]\n /** Render one host row. Permission, session, event and protocol authority stay outside this component. */\n renderRow: Component<TranscriptCompositionRendererProps<T>>\n /** The host's current run state. Live rows stay mounted and expanded until settled. */\n running?: boolean\n /** Reset scope for row identity and disclosure. It is not inferred from display content. */\n resetKey?: string | number | null\n /** Default settled fold policy. `tools` keeps prose visible; `prose` retains a proven conclusion. */\n foldMode?: TranscriptFoldMode\n /** Global command state. `collapsed` keeps hidden content mounted; prose folds only before a host-marked conclusion. */\n foldState?: TranscriptFoldState\n onFoldStateChange?: (state: TranscriptFoldState) => void\n /** Optional controlled disclosure map keyed by `transcriptDisclosureKey`. */\n disclosure?: ReadonlyMap<string, boolean>\n onDisclosureChange?: (key: string, expanded: boolean) => void\n}\n\ntype TurnPresentation = NonNullable<TranscriptCompositionRowContext['turn']>\ntype GroupPresentation = NonNullable<TranscriptCompositionRowContext['group']>\n\ntype FoldGroup<T> = Readonly<{\n key: string\n mode: TranscriptFoldMode\n callCount: number\n rows: readonly TranscriptRow<T>[]\n}>\n\ntype RowRecord<T> = {\n row: TranscriptRow<T>\n index: number\n displayKind: TranscriptDisplayKind\n group?: GroupPresentation\n turn?: TurnPresentation\n fold?: TranscriptCompositionFold\n foldControl?: FoldGroup<T>\n}\n\ntype TranscriptLayout<T> = Readonly<{\n rows: readonly RowRecord<T>[]\n controls: readonly FoldGroup<T>[]\n}>\n\ntype RowHandle<T> = {\n key: string\n get: Accessor<RowRecord<T>>\n set: (next: RowRecord<T>) => void\n last: RowRecord<T>\n}\n\ntype DisclosureSignal = Readonly<{\n get: Accessor<boolean | undefined>\n set: (next: boolean | undefined) => void\n}>\n\nconst encodeId = (value: string): string => encodeURIComponent(value)\n\n/** Stable, transcript-scoped key for host-owned disclosure restoration. */\nexport function transcriptDisclosureKey(\n resetKey: string | number | null | undefined,\n mode: TranscriptFoldMode,\n firstRowId: string\n): string {\n return `transcript:${encodeId(String(resetKey ?? ''))}:${mode}:${encodeId(firstRowId)}`\n}\n\nfunction panelId(instanceId: string, resetKey: string, rowId: string): string {\n return `${instanceId}-row-${encodeId(resetKey)}-${encodeId(rowId)}`\n}\n\nfunction buttonId(instanceId: string, resetKey: string, segmentKey: string): string {\n return `${instanceId}-fold-${encodeId(resetKey)}-${encodeId(segmentKey)}`\n}\n\nfunction sameGroup(a?: GroupPresentation, b?: GroupPresentation): boolean {\n return a === b || (!!a && !!b && a.index === b.index && a.size === b.size)\n}\n\nfunction sameTurn(a?: TurnPresentation, b?: TurnPresentation): boolean {\n return (\n a === b || (!!a && !!b && a.id === b.id && a.complete === b.complete && a.interim === b.interim)\n )\n}\n\nfunction sameFold(a?: TranscriptCompositionFold, b?: TranscriptCompositionFold): boolean {\n return (\n a === b ||\n (!!a &&\n !!b &&\n a.key === b.key &&\n a.mode === b.mode &&\n a.mounting === b.mounting &&\n a.callCount === b.callCount)\n )\n}\n\nfunction sameFoldGroup<T>(a?: FoldGroup<T>, b?: FoldGroup<T>): boolean {\n return (\n a === b ||\n (!!a &&\n !!b &&\n a.key === b.key &&\n a.callCount === b.callCount &&\n a.rows.length === b.rows.length &&\n a.rows.every((row, index) => row === b.rows[index]))\n )\n}\n\nfunction sameRecord<T>(a: RowRecord<T>, b: RowRecord<T>): boolean {\n return (\n a.row === b.row &&\n a.index === b.index &&\n a.displayKind === b.displayKind &&\n sameGroup(a.group, b.group) &&\n sameTurn(a.turn, b.turn) &&\n sameFold(a.fold, b.fold) &&\n sameFoldGroup(a.foldControl, b.foldControl)\n )\n}\n\nfunction firstRow<T>(item: TranscriptTurnItem<T>): TranscriptRow<T> | undefined {\n return item.kind === 'single' ? item.row : item.rows[0]\n}\n\nfunction appendTurnItem<T>(\n item: TranscriptTurnItem<T>,\n displayKind: 'single' | 'group' | 'turn',\n turn: TurnPresentation | undefined,\n indices: ReadonlyMap<TranscriptRow<T>, number>,\n into: RowRecord<T>[]\n): void {\n if (item.kind === 'single') {\n into.push({\n row: item.row,\n index: indices.get(item.row) ?? item.index,\n displayKind,\n turn,\n })\n return\n }\n item.rows.forEach((row, index) => {\n into.push({\n row,\n index: indices.get(row) ?? item.startIndex + index,\n displayKind,\n group: { index, size: item.rows.length },\n turn,\n })\n })\n}\n\nfunction appendDisplayItem<T>(\n item: TranscriptDisplayItem<T>,\n indices: ReadonlyMap<TranscriptRow<T>, number>,\n into: RowRecord<T>[]\n): void {\n if (item.kind !== 'turn') {\n appendTurnItem(item, item.kind, undefined, indices, into)\n return\n }\n const turnId = item.items.map(firstRow).find((row) => row)?.id ?? 'empty-turn'\n const turn: TurnPresentation = {\n id: turnId,\n complete: item.complete,\n interim: !!item.interim,\n }\n for (const child of item.items) appendTurnItem(child, 'turn', turn, indices, into)\n}\n\nfunction buildDisclosures<T>(\n records: readonly RowRecord<T>[],\n defaultMode: TranscriptFoldMode,\n foldState: TranscriptFoldState,\n resetKey: string\n): FoldGroup<T>[] {\n const controls: FoldGroup<T>[] = []\n let scope: RowRecord<T>[] = []\n const flushScope = () => {\n if (!scope.length) return\n const rows = scope.map((record) => record.row)\n const hasInterimTurn = scope.some((record) => record.turn?.interim)\n const hasConclusion = scope.some((record) => record.row.conclusion)\n const mode: TranscriptFoldMode = hasInterimTurn\n ? 'interim'\n : foldState === 'default'\n ? defaultMode\n : foldState === 'collapsed'\n ? hasConclusion\n ? 'prose'\n : 'tools'\n : 'interim'\n const plan = planTranscriptFold(rows, { mode, settled: true })\n const foldable = plan.entries.flatMap((entry, index) =>\n entry.mounting === 'always' ? [] : [{ record: scope[index]!, mounting: entry.mounting }]\n )\n if (foldable.length) {\n const anchorId = scope[0]?.row.id ?? foldable[0]!.record.row.id\n const control: FoldGroup<T> = {\n key: transcriptDisclosureKey(resetKey, mode, anchorId),\n mode,\n callCount: plan.callCount,\n rows: foldable.map(({ record }) => record.row),\n }\n controls.push(control)\n foldable.forEach(({ record, mounting }, index) => {\n record.fold = {\n key: control.key,\n mode: control.mode,\n mounting: foldState === 'collapsed' ? 'hide-when-collapsed' : mounting,\n callCount: control.callCount,\n }\n if (index === 0) record.foldControl = control\n })\n }\n scope = []\n }\n\n for (const record of records) {\n if (record.row.opensTurn && scope.length) flushScope()\n scope.push(record)\n }\n flushScope()\n return controls\n}\n\nfunction foldLabel(mode: TranscriptFoldMode, count: number, expanded: boolean): string {\n const subject =\n mode === 'tools'\n ? count === 1\n ? '1 tool call'\n : count > 1\n ? `${count} tool calls`\n : 'tool details'\n : mode === 'prose'\n ? 'earlier activity'\n : 'interim activity'\n return `${expanded ? 'Hide' : 'Show'} ${subject}`\n}\n\nfunction TranscriptRowEntry<T>(props: {\n record: Accessor<RowRecord<T>>\n renderRow: Component<TranscriptCompositionRendererProps<T>>\n prefix: string\n resetKey: Accessor<string>\n expanded: (key: string) => Accessor<boolean>\n running: Accessor<boolean>\n foldState: Accessor<TranscriptFoldState>\n onToggle: (key: string, expanded: boolean) => void\n}) {\n const current = props.record\n const id = () => panelId(props.prefix, props.resetKey(), current().row.id)\n const foldControl = () => current().foldControl\n const disclosureKey = () => current().fold?.key\n const expanded = () => {\n const key = disclosureKey()\n return key ? props.expanded(key)() : true\n }\n const collapsed = () => !!current().fold && !expanded()\n const disabled = () => props.running() || props.foldState() !== 'default'\n const context = (): TranscriptCompositionRowContext => ({\n index: current().index,\n displayKind: current().displayKind,\n group: current().group,\n turn: current().turn,\n fold: current().fold,\n })\n const groupIndex = () => current().group?.index\n const groupSize = () => current().group?.size\n const renderable = () => current().fold?.mounting !== 'unmount-when-collapsed' || !collapsed()\n const renderHostRow = () =>\n createComponent(props.renderRow, {\n get row() {\n return current().row\n },\n get context() {\n return context()\n },\n })\n const controlLabel = () => {\n const control = foldControl()\n return control ? foldLabel(control.mode, control.callCount, expanded()) : ''\n }\n const controlRows = () =>\n foldControl()\n ?.rows.map((row) => panelId(props.prefix, props.resetKey(), row.id))\n .join(' ')\n\n return (\n <div\n data-slot=\"transcript-row\"\n data-display-kind={current().displayKind}\n data-group-index={groupIndex()}\n data-group-size={groupSize()}\n class=\"flex min-w-0 flex-col gap-1\"\n >\n <Show when={foldControl()}>\n {(control) => (\n <Button\n id={buttonId(props.prefix, props.resetKey(), control().key)}\n type=\"button\"\n variant=\"ghost\"\n size=\"sm\"\n class=\"w-full justify-start\"\n aria-label={controlLabel()}\n aria-controls={controlRows()}\n aria-expanded={expanded()}\n aria-disabled={disabled() || undefined}\n onClick={() => props.onToggle(control().key, !expanded())}\n >\n <ChevronDown aria-hidden=\"true\" class=\"size-4 shrink-0\" />\n <span>{controlLabel()}</span>\n </Button>\n )}\n </Show>\n <div\n id={id()}\n data-slot=\"transcript-row-content\"\n hidden={collapsed()}\n aria-hidden={collapsed() || undefined}\n >\n <Show when={renderable() ? current() : undefined}>\n {(record) => {\n record()\n return renderHostRow()\n }}\n </Show>\n </div>\n </div>\n )\n}\n\n/**\n * Compose host-classified rows into stable turns, contiguous groups and disclosures.\n * Row render owners are keyed by `id` in a single list, so loose rows keep their DOM\n * owners when the grouping threshold promotes them into a turn. The caller owns row\n * identity, protocol meaning, redaction, permissions and durable conversation state.\n */\nexport function TranscriptComposition<T>(props: TranscriptCompositionProps<T>) {\n const [local, rest] = splitProps(props, [\n 'class',\n 'rows',\n 'renderRow',\n 'running',\n 'resetKey',\n 'foldMode',\n 'foldState',\n 'onFoldStateChange',\n 'disclosure',\n 'onDisclosureChange',\n ])\n const instanceId = createUniqueId()\n const grouper = createTranscriptGrouper<T>()\n const [internalFoldState, setInternalFoldState] = createSignal<TranscriptFoldState>('default')\n const rowHandles = new Map<string, RowHandle<T>>()\n const disclosureSignals = new Map<string, DisclosureSignal>()\n let lastResetKey = String(local.resetKey ?? '')\n\n const resetKey = () => String(local.resetKey ?? '')\n const foldState = () => local.foldState ?? internalFoldState()\n const running = () => !!local.running\n const localDisclosure = (key: string): DisclosureSignal => {\n let signal = disclosureSignals.get(key)\n if (!signal) {\n const [get, set] = createSignal<boolean | undefined>(undefined)\n signal = { get, set }\n disclosureSignals.set(key, signal)\n }\n return signal\n }\n const disclosureExpanded = (key: string): Accessor<boolean> => {\n const signal = localDisclosure(key)\n return () => {\n if (running()) return true\n if (foldState() === 'collapsed') return false\n if (foldState() === 'expanded') return true\n return local.disclosure?.get(key) ?? signal.get() ?? false\n }\n }\n const grouped = createMemo(() => grouper(local.rows))\n const layout = createMemo<TranscriptLayout<T>>(() => {\n const identity = resetKey()\n if (identity !== lastResetKey) {\n rowHandles.clear()\n disclosureSignals.clear()\n lastResetKey = identity\n }\n const indexByRow = new Map(local.rows.map((row, index) => [row, index]))\n const display = applyTranscriptRunningState(grouped(), running())\n const records: RowRecord<T>[] = []\n display.forEach((item) => appendDisplayItem(item, indexByRow, records))\n const controls = buildDisclosures(records, local.foldMode ?? 'tools', foldState(), identity)\n return { rows: records, controls }\n })\n const handles = createMemo(() => {\n const live = new Set<string>()\n const identity = resetKey()\n const result = layout().rows.map((record) => {\n const key = `${identity}\\u001f${record.row.id}`\n live.add(key)\n let handle = rowHandles.get(key)\n if (!handle) {\n const [get, set] = createSignal(record)\n handle = { key, get, set, last: record }\n rowHandles.set(key, handle)\n } else if (!sameRecord(handle.last, record)) {\n handle.last = record\n handle.set(record)\n }\n return handle\n })\n for (const key of rowHandles.keys()) if (!live.has(key)) rowHandles.delete(key)\n return result\n })\n const allControlIds = () =>\n layout()\n .controls.flatMap((control) =>\n control.rows.map((row) => panelId(instanceId, resetKey(), row.id))\n )\n .join(' ')\n const updateFoldState = () => {\n if (running()) return\n const current = foldState()\n const next: TranscriptFoldState =\n current === 'default' ? 'collapsed' : current === 'collapsed' ? 'expanded' : 'default'\n if (local.foldState === undefined) setInternalFoldState(next)\n local.onFoldStateChange?.(next)\n }\n const updateDisclosure = (key: string, expanded: boolean) => {\n if (running() || foldState() !== 'default') return\n if (local.disclosure) {\n local.onDisclosureChange?.(key, expanded)\n return\n }\n localDisclosure(key).set(expanded)\n local.onDisclosureChange?.(key, expanded)\n }\n\n return (\n <div\n data-slot=\"transcript-composition\"\n data-fold-state={foldState()}\n class={cn('flex w-full min-w-0 flex-col gap-1', local.class)}\n {...rest}\n >\n <Show when={local.onFoldStateChange}>\n <div class=\"flex justify-end\">\n <Button\n id={`${instanceId}-fold-all`}\n type=\"button\"\n variant=\"ghost\"\n size=\"sm\"\n aria-controls={allControlIds() || undefined}\n aria-disabled={running() || undefined}\n onClick={updateFoldState}\n >\n {foldState() === 'default'\n ? 'Collapse all activity'\n : foldState() === 'collapsed'\n ? 'Expand all activity'\n : 'Restore default folding'}\n </Button>\n </div>\n </Show>\n <div data-slot=\"transcript-rows\" class=\"flex min-w-0 flex-col gap-1\">\n <For each={handles()}>\n {(handle) => (\n <TranscriptRowEntry\n record={handle.get}\n renderRow={local.renderRow}\n prefix={instanceId}\n resetKey={resetKey}\n expanded={disclosureExpanded}\n running={running}\n foldState={foldState}\n onToggle={updateDisclosure}\n />\n )}\n </For>\n </div>\n </div>\n )\n}\n"],"mappings":"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"}
1
+ {"version":3,"file":"transcript-composition.js","names":["Accessor","Component","ComponentProps","For","Show","createComponent","createMemo","createSignal","createUniqueId","splitProps","ChevronDown","cn","Button","applyTranscriptRunningState","createTranscriptGrouper","TranscriptDisplayItem","TranscriptRow","TranscriptTurnItem","planTranscriptFold","TranscriptFoldMode","TranscriptMounting","TranscriptFoldState","TranscriptDisplayKind","GroupedTranscript","TranscriptFoldPlan","TranscriptCompositionFold","Readonly","key","mode","mounting","callCount","TranscriptCompositionRowContext","index","displayKind","group","size","turn","id","complete","interim","fold","TranscriptCompositionRendererProps","row","T","context","TranscriptCompositionProps","Omit","rows","renderRow","running","resetKey","foldMode","foldState","onFoldStateChange","state","disclosure","ReadonlyMap","onDisclosureChange","expanded","density","TurnPresentation","NonNullable","GroupPresentation","FoldGroup","RowRecord","foldControl","TranscriptLayout","controls","RowHandle","get","set","next","last","DisclosureSignal","encodeId","value","encodeURIComponent","transcriptDisclosureKey","firstRowId","String","panelId","instanceId","rowId","buttonId","segmentKey","sameGroup","a","b","sameTurn","sameFold","sameFoldGroup","length","every","sameRecord","firstRow","item","kind","appendTurnItem","indices","into","push","forEach","startIndex","appendDisplayItem","undefined","turnId","items","map","find","child","buildDisclosures","records","defaultMode","scope","flushScope","record","hasInterimTurn","some","hasConclusion","conclusion","plan","settled","foldable","entries","flatMap","entry","anchorId","control","opensTurn","foldLabel","count","subject","TranscriptRowEntry","props","prefix","onToggle","current","disclosureKey","collapsed","disabled","groupIndex","groupSize","renderable","renderHostRow","controlLabel","controlRows","join","_el$","_tmpl$","_el$2","firstChild","_$insert","_$createComponent","when","children","type","variant","aria-label","aria-controls","aria-expanded","aria-disabled","onClick","_el$3","_tmpl$2","_$memo","_$effect","_p$","_v$","_v$2","_v$3","_v$4","_v$5","_v$6","e","_$setAttribute","t","o","i","hidden","n","TranscriptComposition","local","rest","grouper","internalFoldState","setInternalFoldState","rowHandles","Map","disclosureSignals","lastResetKey","localDisclosure","signal","disclosureExpanded","grouped","layout","identity","clear","indexByRow","display","handles","live","Set","result","add","handle","keys","has","delete","allControlIds","updateFoldState","updateDisclosure","_el$4","_tmpl$4","_el$6","_$spread","_$mergeProps","data-fold-state","data-density","class","_el$5","_tmpl$3","each","_$className","createComponent","_$createComponent","_$memo","_$setAttribute","_$mergeProps","_$className"],"sources":["../../../src/components/conversation/transcript-composition.tsx"],"sourcesContent":["import type { Accessor, Component, ComponentProps } from 'solid-js'\nimport {\n For,\n Show,\n createComponent,\n createMemo,\n createSignal,\n createUniqueId,\n splitProps,\n} from 'solid-js'\nimport { ChevronDown } from 'lucide-solid'\nimport { cn } from '#lib/utils'\nimport { Button } from '../ui/button/button'\nimport {\n applyTranscriptRunningState,\n createTranscriptGrouper,\n type TranscriptDisplayItem,\n type TranscriptRow,\n type TranscriptTurnItem,\n} from './transcript-grouping'\nimport {\n planTranscriptFold,\n type TranscriptFoldMode,\n type TranscriptMounting,\n} from './transcript-folding'\n\nexport type TranscriptFoldState = 'default' | 'collapsed' | 'expanded'\nexport type TranscriptDisplayKind = 'single' | 'group' | 'turn'\n\nexport type {\n GroupedTranscript,\n TranscriptDisplayItem,\n TranscriptRow,\n TranscriptTurnItem,\n} from './transcript-grouping'\nexport type {\n TranscriptFoldMode,\n TranscriptFoldPlan,\n TranscriptMounting,\n} from './transcript-folding'\n\nexport type TranscriptCompositionFold = Readonly<{\n /** Stable host persistence key. Use with `transcriptDisclosureKey` to seed a store. */\n key: string\n mode: TranscriptFoldMode\n mounting: TranscriptMounting\n /** Distinct host-classified request IDs in this contiguous fold segment. */\n callCount: number\n}>\n\nexport type TranscriptCompositionRowContext = Readonly<{\n /** Original index in the caller's row array, including rows hidden by the host. */\n index: number\n /** The row's current position in the generic display composition. */\n displayKind: TranscriptDisplayKind\n group?: Readonly<{ index: number; size: number }>\n turn?: Readonly<{\n /** Derived from the first stable row ID; presentation bookkeeping only. */\n id: string\n /** A presentation state, never proof of successful runtime completion. */\n complete: boolean\n interim: boolean\n }>\n fold?: TranscriptCompositionFold\n}>\n\nexport type TranscriptCompositionRendererProps<T> = Readonly<{\n /** Reactive Solid prop; a row component keeps its DOM owner stable as values update. */\n row: TranscriptRow<T>\n context: TranscriptCompositionRowContext\n}>\n\nexport type TranscriptCompositionProps<T> = Omit<ComponentProps<'div'>, 'children'> & {\n /** Ordered, already redacted rows with host-supplied semantic classifications. */\n rows: readonly TranscriptRow<T>[]\n /** Render one host row. Permission, session, event and protocol authority stay outside this component. */\n renderRow: Component<TranscriptCompositionRendererProps<T>>\n /** The host's current run state. Live rows stay mounted and expanded until settled. */\n running?: boolean\n /** Reset scope for row identity and disclosure. It is not inferred from display content. */\n resetKey?: string | number | null\n /** Default settled fold policy. `tools` keeps prose visible; `prose` retains a proven conclusion. */\n foldMode?: TranscriptFoldMode\n /** Global command state. `collapsed` keeps hidden content mounted; prose folds only before a host-marked conclusion. */\n foldState?: TranscriptFoldState\n onFoldStateChange?: (state: TranscriptFoldState) => void\n /** Optional controlled disclosure map keyed by `transcriptDisclosureKey`. */\n disclosure?: ReadonlyMap<string, boolean>\n onDisclosureChange?: (key: string, expanded: boolean) => void\n /**\n * Row rhythm. `compact` (default) packs rows 4px apart; `comfortable` spaces\n * them 12px apart and stacks each row's rendered parts, for a chat stream\n * whose rows are separate messages rather than one running log.\n */\n density?: 'compact' | 'comfortable'\n}\n\ntype TurnPresentation = NonNullable<TranscriptCompositionRowContext['turn']>\ntype GroupPresentation = NonNullable<TranscriptCompositionRowContext['group']>\n\ntype FoldGroup<T> = Readonly<{\n key: string\n mode: TranscriptFoldMode\n callCount: number\n rows: readonly TranscriptRow<T>[]\n}>\n\ntype RowRecord<T> = {\n row: TranscriptRow<T>\n index: number\n displayKind: TranscriptDisplayKind\n group?: GroupPresentation\n turn?: TurnPresentation\n fold?: TranscriptCompositionFold\n foldControl?: FoldGroup<T>\n}\n\ntype TranscriptLayout<T> = Readonly<{\n rows: readonly RowRecord<T>[]\n controls: readonly FoldGroup<T>[]\n}>\n\ntype RowHandle<T> = {\n key: string\n get: Accessor<RowRecord<T>>\n set: (next: RowRecord<T>) => void\n last: RowRecord<T>\n}\n\ntype DisclosureSignal = Readonly<{\n get: Accessor<boolean | undefined>\n set: (next: boolean | undefined) => void\n}>\n\nconst encodeId = (value: string): string => encodeURIComponent(value)\n\n/** Stable, transcript-scoped key for host-owned disclosure restoration. */\nexport function transcriptDisclosureKey(\n resetKey: string | number | null | undefined,\n mode: TranscriptFoldMode,\n firstRowId: string\n): string {\n return `transcript:${encodeId(String(resetKey ?? ''))}:${mode}:${encodeId(firstRowId)}`\n}\n\nfunction panelId(instanceId: string, resetKey: string, rowId: string): string {\n return `${instanceId}-row-${encodeId(resetKey)}-${encodeId(rowId)}`\n}\n\nfunction buttonId(instanceId: string, resetKey: string, segmentKey: string): string {\n return `${instanceId}-fold-${encodeId(resetKey)}-${encodeId(segmentKey)}`\n}\n\nfunction sameGroup(a?: GroupPresentation, b?: GroupPresentation): boolean {\n return a === b || (!!a && !!b && a.index === b.index && a.size === b.size)\n}\n\nfunction sameTurn(a?: TurnPresentation, b?: TurnPresentation): boolean {\n return (\n a === b || (!!a && !!b && a.id === b.id && a.complete === b.complete && a.interim === b.interim)\n )\n}\n\nfunction sameFold(a?: TranscriptCompositionFold, b?: TranscriptCompositionFold): boolean {\n return (\n a === b ||\n (!!a &&\n !!b &&\n a.key === b.key &&\n a.mode === b.mode &&\n a.mounting === b.mounting &&\n a.callCount === b.callCount)\n )\n}\n\nfunction sameFoldGroup<T>(a?: FoldGroup<T>, b?: FoldGroup<T>): boolean {\n return (\n a === b ||\n (!!a &&\n !!b &&\n a.key === b.key &&\n a.callCount === b.callCount &&\n a.rows.length === b.rows.length &&\n a.rows.every((row, index) => row === b.rows[index]))\n )\n}\n\nfunction sameRecord<T>(a: RowRecord<T>, b: RowRecord<T>): boolean {\n return (\n a.row === b.row &&\n a.index === b.index &&\n a.displayKind === b.displayKind &&\n sameGroup(a.group, b.group) &&\n sameTurn(a.turn, b.turn) &&\n sameFold(a.fold, b.fold) &&\n sameFoldGroup(a.foldControl, b.foldControl)\n )\n}\n\nfunction firstRow<T>(item: TranscriptTurnItem<T>): TranscriptRow<T> | undefined {\n return item.kind === 'single' ? item.row : item.rows[0]\n}\n\nfunction appendTurnItem<T>(\n item: TranscriptTurnItem<T>,\n displayKind: 'single' | 'group' | 'turn',\n turn: TurnPresentation | undefined,\n indices: ReadonlyMap<TranscriptRow<T>, number>,\n into: RowRecord<T>[]\n): void {\n if (item.kind === 'single') {\n into.push({\n row: item.row,\n index: indices.get(item.row) ?? item.index,\n displayKind,\n turn,\n })\n return\n }\n item.rows.forEach((row, index) => {\n into.push({\n row,\n index: indices.get(row) ?? item.startIndex + index,\n displayKind,\n group: { index, size: item.rows.length },\n turn,\n })\n })\n}\n\nfunction appendDisplayItem<T>(\n item: TranscriptDisplayItem<T>,\n indices: ReadonlyMap<TranscriptRow<T>, number>,\n into: RowRecord<T>[]\n): void {\n if (item.kind !== 'turn') {\n appendTurnItem(item, item.kind, undefined, indices, into)\n return\n }\n const turnId = item.items.map(firstRow).find((row) => row)?.id ?? 'empty-turn'\n const turn: TurnPresentation = {\n id: turnId,\n complete: item.complete,\n interim: !!item.interim,\n }\n for (const child of item.items) appendTurnItem(child, 'turn', turn, indices, into)\n}\n\nfunction buildDisclosures<T>(\n records: readonly RowRecord<T>[],\n defaultMode: TranscriptFoldMode,\n foldState: TranscriptFoldState,\n resetKey: string\n): FoldGroup<T>[] {\n const controls: FoldGroup<T>[] = []\n let scope: RowRecord<T>[] = []\n const flushScope = () => {\n if (!scope.length) return\n const rows = scope.map((record) => record.row)\n const hasInterimTurn = scope.some((record) => record.turn?.interim)\n const hasConclusion = scope.some((record) => record.row.conclusion)\n const mode: TranscriptFoldMode = hasInterimTurn\n ? 'interim'\n : foldState === 'default'\n ? defaultMode\n : foldState === 'collapsed'\n ? hasConclusion\n ? 'prose'\n : 'tools'\n : 'interim'\n const plan = planTranscriptFold(rows, { mode, settled: true })\n const foldable = plan.entries.flatMap((entry, index) =>\n entry.mounting === 'always' ? [] : [{ record: scope[index]!, mounting: entry.mounting }]\n )\n if (foldable.length) {\n const anchorId = scope[0]?.row.id ?? foldable[0]!.record.row.id\n const control: FoldGroup<T> = {\n key: transcriptDisclosureKey(resetKey, mode, anchorId),\n mode,\n callCount: plan.callCount,\n rows: foldable.map(({ record }) => record.row),\n }\n controls.push(control)\n foldable.forEach(({ record, mounting }, index) => {\n record.fold = {\n key: control.key,\n mode: control.mode,\n mounting: foldState === 'collapsed' ? 'hide-when-collapsed' : mounting,\n callCount: control.callCount,\n }\n if (index === 0) record.foldControl = control\n })\n }\n scope = []\n }\n\n for (const record of records) {\n if (record.row.opensTurn && scope.length) flushScope()\n scope.push(record)\n }\n flushScope()\n return controls\n}\n\nfunction foldLabel(mode: TranscriptFoldMode, count: number, expanded: boolean): string {\n const subject =\n mode === 'tools'\n ? count === 1\n ? '1 tool call'\n : count > 1\n ? `${count} tool calls`\n : 'tool details'\n : mode === 'prose'\n ? 'earlier activity'\n : 'interim activity'\n return `${expanded ? 'Hide' : 'Show'} ${subject}`\n}\n\nfunction TranscriptRowEntry<T>(props: {\n record: Accessor<RowRecord<T>>\n renderRow: Component<TranscriptCompositionRendererProps<T>>\n prefix: string\n resetKey: Accessor<string>\n expanded: (key: string) => Accessor<boolean>\n running: Accessor<boolean>\n foldState: Accessor<TranscriptFoldState>\n onToggle: (key: string, expanded: boolean) => void\n}) {\n const current = props.record\n const id = () => panelId(props.prefix, props.resetKey(), current().row.id)\n const foldControl = () => current().foldControl\n const disclosureKey = () => current().fold?.key\n const expanded = () => {\n const key = disclosureKey()\n return key ? props.expanded(key)() : true\n }\n const collapsed = () => !!current().fold && !expanded()\n const disabled = () => props.running() || props.foldState() !== 'default'\n const context = (): TranscriptCompositionRowContext => ({\n index: current().index,\n displayKind: current().displayKind,\n group: current().group,\n turn: current().turn,\n fold: current().fold,\n })\n const groupIndex = () => current().group?.index\n const groupSize = () => current().group?.size\n const renderable = () => current().fold?.mounting !== 'unmount-when-collapsed' || !collapsed()\n const renderHostRow = () =>\n createComponent(props.renderRow, {\n get row() {\n return current().row\n },\n get context() {\n return context()\n },\n })\n const controlLabel = () => {\n const control = foldControl()\n return control ? foldLabel(control.mode, control.callCount, expanded()) : ''\n }\n const controlRows = () =>\n foldControl()\n ?.rows.map((row) => panelId(props.prefix, props.resetKey(), row.id))\n .join(' ')\n\n return (\n <div\n data-slot=\"transcript-row\"\n data-display-kind={current().displayKind}\n data-group-index={groupIndex()}\n data-group-size={groupSize()}\n class=\"flex min-w-0 flex-col gap-1\"\n >\n <Show when={foldControl()}>\n {(control) => (\n <Button\n id={buttonId(props.prefix, props.resetKey(), control().key)}\n type=\"button\"\n variant=\"ghost\"\n size=\"sm\"\n class=\"w-full justify-start\"\n aria-label={controlLabel()}\n aria-controls={controlRows()}\n aria-expanded={expanded()}\n aria-disabled={disabled() || undefined}\n onClick={() => props.onToggle(control().key, !expanded())}\n >\n <ChevronDown aria-hidden=\"true\" class=\"size-4 shrink-0\" />\n <span>{controlLabel()}</span>\n </Button>\n )}\n </Show>\n <div\n id={id()}\n data-slot=\"transcript-row-content\"\n class=\"group-data-[density=comfortable]/transcript:flex group-data-[density=comfortable]/transcript:flex-col\"\n hidden={collapsed()}\n aria-hidden={collapsed() || undefined}\n >\n <Show when={renderable() ? current() : undefined}>\n {(record) => {\n record()\n return renderHostRow()\n }}\n </Show>\n </div>\n </div>\n )\n}\n\n/**\n * Compose host-classified rows into stable turns, contiguous groups and disclosures.\n * Row render owners are keyed by `id` in a single list, so loose rows keep their DOM\n * owners when the grouping threshold promotes them into a turn. The caller owns row\n * identity, protocol meaning, redaction, permissions and durable conversation state.\n */\nexport function TranscriptComposition<T>(props: TranscriptCompositionProps<T>) {\n const [local, rest] = splitProps(props, [\n 'class',\n 'rows',\n 'renderRow',\n 'running',\n 'resetKey',\n 'foldMode',\n 'foldState',\n 'onFoldStateChange',\n 'density',\n 'disclosure',\n 'onDisclosureChange',\n ])\n const instanceId = createUniqueId()\n const grouper = createTranscriptGrouper<T>()\n const [internalFoldState, setInternalFoldState] = createSignal<TranscriptFoldState>('default')\n const rowHandles = new Map<string, RowHandle<T>>()\n const disclosureSignals = new Map<string, DisclosureSignal>()\n let lastResetKey = String(local.resetKey ?? '')\n\n const resetKey = () => String(local.resetKey ?? '')\n const foldState = () => local.foldState ?? internalFoldState()\n const running = () => !!local.running\n const localDisclosure = (key: string): DisclosureSignal => {\n let signal = disclosureSignals.get(key)\n if (!signal) {\n const [get, set] = createSignal<boolean | undefined>(undefined)\n signal = { get, set }\n disclosureSignals.set(key, signal)\n }\n return signal\n }\n const disclosureExpanded = (key: string): Accessor<boolean> => {\n const signal = localDisclosure(key)\n return () => {\n if (running()) return true\n if (foldState() === 'collapsed') return false\n if (foldState() === 'expanded') return true\n return local.disclosure?.get(key) ?? signal.get() ?? false\n }\n }\n const grouped = createMemo(() => grouper(local.rows))\n const layout = createMemo<TranscriptLayout<T>>(() => {\n const identity = resetKey()\n if (identity !== lastResetKey) {\n rowHandles.clear()\n disclosureSignals.clear()\n lastResetKey = identity\n }\n const indexByRow = new Map(local.rows.map((row, index) => [row, index]))\n const display = applyTranscriptRunningState(grouped(), running())\n const records: RowRecord<T>[] = []\n display.forEach((item) => appendDisplayItem(item, indexByRow, records))\n const controls = buildDisclosures(records, local.foldMode ?? 'tools', foldState(), identity)\n return { rows: records, controls }\n })\n const handles = createMemo(() => {\n const live = new Set<string>()\n const identity = resetKey()\n const result = layout().rows.map((record) => {\n const key = `${identity}\\u001f${record.row.id}`\n live.add(key)\n let handle = rowHandles.get(key)\n if (!handle) {\n const [get, set] = createSignal(record)\n handle = { key, get, set, last: record }\n rowHandles.set(key, handle)\n } else if (!sameRecord(handle.last, record)) {\n handle.last = record\n handle.set(record)\n }\n return handle\n })\n for (const key of rowHandles.keys()) if (!live.has(key)) rowHandles.delete(key)\n return result\n })\n const allControlIds = () =>\n layout()\n .controls.flatMap((control) =>\n control.rows.map((row) => panelId(instanceId, resetKey(), row.id))\n )\n .join(' ')\n const updateFoldState = () => {\n if (running()) return\n const current = foldState()\n const next: TranscriptFoldState =\n current === 'default' ? 'collapsed' : current === 'collapsed' ? 'expanded' : 'default'\n if (local.foldState === undefined) setInternalFoldState(next)\n local.onFoldStateChange?.(next)\n }\n const updateDisclosure = (key: string, expanded: boolean) => {\n if (running() || foldState() !== 'default') return\n if (local.disclosure) {\n local.onDisclosureChange?.(key, expanded)\n return\n }\n localDisclosure(key).set(expanded)\n local.onDisclosureChange?.(key, expanded)\n }\n\n return (\n <div\n data-slot=\"transcript-composition\"\n data-fold-state={foldState()}\n data-density={local.density ?? 'compact'}\n class={cn('group/transcript flex w-full min-w-0 flex-col gap-1', local.class)}\n {...rest}\n >\n <Show when={local.onFoldStateChange}>\n <div class=\"flex justify-end\">\n <Button\n id={`${instanceId}-fold-all`}\n type=\"button\"\n variant=\"ghost\"\n size=\"sm\"\n aria-controls={allControlIds() || undefined}\n aria-disabled={running() || undefined}\n onClick={updateFoldState}\n >\n {foldState() === 'default'\n ? 'Collapse all activity'\n : foldState() === 'collapsed'\n ? 'Expand all activity'\n : 'Restore default folding'}\n </Button>\n </div>\n </Show>\n <div\n data-slot=\"transcript-rows\"\n class={cn('flex min-w-0 flex-col', local.density === 'comfortable' ? 'gap-3' : 'gap-1')}\n >\n <For each={handles()}>\n {(handle) => (\n <TranscriptRowEntry\n record={handle.get}\n renderRow={local.renderRow}\n prefix={instanceId}\n resetKey={resetKey}\n expanded={disclosureExpanded}\n running={running}\n foldState={foldState}\n onToggle={updateDisclosure}\n />\n )}\n </For>\n </div>\n </div>\n )\n}\n"],"mappings":"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"}
@@ -30,6 +30,8 @@ export type ContextualSidebarProps = {
30
30
  /** Pass the host's initial viewport seed to distinguish stale desktop state. */
31
31
  wideViewportAtLoad?: boolean;
32
32
  resizeLabel?: string;
33
+ /** The resize edge's grip: the default bordered chip, or the quieter rung. */
34
+ resizeGrip?: 'chip' | 'rung';
33
35
  /** Stable external opener used when the modal mobile sheet closes. */
34
36
  restoreFocusRef?: Accessor<HTMLElement | undefined>;
35
37
  /** Called with the nav node so a host can project width onto its layout root. */
@@ -1 +1 @@
1
- {"version":3,"file":"contextual-sidebar.d.ts","sourceRoot":"","sources":["../../../../src/components/layout/contextual-sidebar/contextual-sidebar.tsx"],"names":[],"mappings":"AAAA,OAAO,KAAK,EAAE,QAAQ,EAAE,GAAG,EAAE,MAAM,UAAU,CAAA;AAe7C,MAAM,MAAM,8BAA8B,GAAG;IAC3C,wEAAwE;IACxE,MAAM,EAAE,OAAO,CAAA;IACf,qFAAqF;IACrF,WAAW,IAAI,WAAW,GAAG,SAAS,CAAA;CACvC,CAAA;AAED,MAAM,MAAM,sBAAsB,GAAG;IACnC,qDAAqD;IACrD,EAAE,CAAC,EAAE,MAAM,CAAA;IACX,iEAAiE;IACjE,KAAK,EAAE,MAAM,CAAA;IACb,wDAAwD;IACxD,KAAK,EAAE,MAAM,CAAA;IACb;;;;;OAKG;IACH,eAAe,CAAC,EAAE,QAAQ,GAAG,QAAQ,CAAA;IACrC,8EAA8E;IAC9E,IAAI,EAAE,OAAO,CAAA;IACb,YAAY,CAAC,IAAI,EAAE,OAAO,GAAG,IAAI,CAAA;IACjC,sEAAsE;IACtE,KAAK,EAAE,MAAM,CAAA;IACb,OAAO,EAAE,MAAM,CAAA;IACf,OAAO,EAAE,MAAM,CAAA;IACf,IAAI,CAAC,EAAE,MAAM,CAAA;IACb,gFAAgF;IAChF,kBAAkB,CAAC,EAAE,OAAO,CAAA;IAC5B,WAAW,CAAC,EAAE,MAAM,CAAA;IACpB,sEAAsE;IACtE,eAAe,CAAC,EAAE,QAAQ,CAAC,WAAW,GAAG,SAAS,CAAC,CAAA;IACnD,iFAAiF;IACjF,gBAAgB,CAAC,EAAE,CAAC,OAAO,EAAE,WAAW,GAAG,SAAS,EAAE,MAAM,EAAE,OAAO,KAAK,IAAI,CAAA;IAC9E,+DAA+D;IAC/D,YAAY,CAAC,EAAE,MAAM,CAAA;IACrB,6DAA6D;IAC7D,UAAU,CAAC,EAAE,MAAM,CAAA;IACnB,WAAW,CAAC,EAAE,MAAM,CAAA;IACpB,YAAY,CAAC,EAAE,MAAM,CAAA;IACrB,WAAW,CAAC,EAAE,MAAM,CAAA;IACpB,SAAS,CAAC,EAAE,IAAI,GAAG,IAAI,GAAG,IAAI,GAAG,IAAI,GAAG,IAAI,GAAG,IAAI,CAAA;IACnD,iEAAiE;IACjE,MAAM,CAAC,CAAC,OAAO,EAAE,8BAA8B,GAAG,GAAG,CAAC,OAAO,CAAA;IAC7D,0EAA0E;IAC1E,OAAO,CAAC,OAAO,EAAE,8BAA8B,GAAG,GAAG,CAAC,OAAO,CAAA;IAC7D,oEAAoE;IACpE,MAAM,CAAC,CAAC,OAAO,EAAE,8BAA8B,GAAG,GAAG,CAAC,OAAO,CAAA;IAC7D,aAAa,CAAC,KAAK,EAAE,MAAM,GAAG,IAAI,CAAA;IAClC,aAAa,CAAC,CAAC,KAAK,EAAE,MAAM,GAAG,IAAI,CAAA;CACpC,CAAA;AAED;;;;;;GAMG;AACH,wBAAgB,iBAAiB,CAAC,KAAK,EAAE,sBAAsB,eAmJ9D"}
1
+ {"version":3,"file":"contextual-sidebar.d.ts","sourceRoot":"","sources":["../../../../src/components/layout/contextual-sidebar/contextual-sidebar.tsx"],"names":[],"mappings":"AAAA,OAAO,KAAK,EAAE,QAAQ,EAAE,GAAG,EAAE,MAAM,UAAU,CAAA;AAe7C,MAAM,MAAM,8BAA8B,GAAG;IAC3C,wEAAwE;IACxE,MAAM,EAAE,OAAO,CAAA;IACf,qFAAqF;IACrF,WAAW,IAAI,WAAW,GAAG,SAAS,CAAA;CACvC,CAAA;AAED,MAAM,MAAM,sBAAsB,GAAG;IACnC,qDAAqD;IACrD,EAAE,CAAC,EAAE,MAAM,CAAA;IACX,iEAAiE;IACjE,KAAK,EAAE,MAAM,CAAA;IACb,wDAAwD;IACxD,KAAK,EAAE,MAAM,CAAA;IACb;;;;;OAKG;IACH,eAAe,CAAC,EAAE,QAAQ,GAAG,QAAQ,CAAA;IACrC,8EAA8E;IAC9E,IAAI,EAAE,OAAO,CAAA;IACb,YAAY,CAAC,IAAI,EAAE,OAAO,GAAG,IAAI,CAAA;IACjC,sEAAsE;IACtE,KAAK,EAAE,MAAM,CAAA;IACb,OAAO,EAAE,MAAM,CAAA;IACf,OAAO,EAAE,MAAM,CAAA;IACf,IAAI,CAAC,EAAE,MAAM,CAAA;IACb,gFAAgF;IAChF,kBAAkB,CAAC,EAAE,OAAO,CAAA;IAC5B,WAAW,CAAC,EAAE,MAAM,CAAA;IACpB,8EAA8E;IAC9E,UAAU,CAAC,EAAE,MAAM,GAAG,MAAM,CAAA;IAC5B,sEAAsE;IACtE,eAAe,CAAC,EAAE,QAAQ,CAAC,WAAW,GAAG,SAAS,CAAC,CAAA;IACnD,iFAAiF;IACjF,gBAAgB,CAAC,EAAE,CAAC,OAAO,EAAE,WAAW,GAAG,SAAS,EAAE,MAAM,EAAE,OAAO,KAAK,IAAI,CAAA;IAC9E,+DAA+D;IAC/D,YAAY,CAAC,EAAE,MAAM,CAAA;IACrB,6DAA6D;IAC7D,UAAU,CAAC,EAAE,MAAM,CAAA;IACnB,WAAW,CAAC,EAAE,MAAM,CAAA;IACpB,YAAY,CAAC,EAAE,MAAM,CAAA;IACrB,WAAW,CAAC,EAAE,MAAM,CAAA;IACpB,SAAS,CAAC,EAAE,IAAI,GAAG,IAAI,GAAG,IAAI,GAAG,IAAI,GAAG,IAAI,GAAG,IAAI,CAAA;IACnD,iEAAiE;IACjE,MAAM,CAAC,CAAC,OAAO,EAAE,8BAA8B,GAAG,GAAG,CAAC,OAAO,CAAA;IAC7D,0EAA0E;IAC1E,OAAO,CAAC,OAAO,EAAE,8BAA8B,GAAG,GAAG,CAAC,OAAO,CAAA;IAC7D,oEAAoE;IACpE,MAAM,CAAC,CAAC,OAAO,EAAE,8BAA8B,GAAG,GAAG,CAAC,OAAO,CAAA;IAC7D,aAAa,CAAC,KAAK,EAAE,MAAM,GAAG,IAAI,CAAA;IAClC,aAAa,CAAC,CAAC,KAAK,EAAE,MAAM,GAAG,IAAI,CAAA;CACpC,CAAA;AAED;;;;;;GAMG;AACH,wBAAgB,iBAAiB,CAAC,KAAK,EAAE,sBAAsB,eAoJ9D"}
@@ -119,6 +119,9 @@ function ContextualSidebar(props) {
119
119
  get label() {
120
120
  return resizeLabel();
121
121
  },
122
+ get grip() {
123
+ return props.resizeGrip;
124
+ },
122
125
  controls: navigationId,
123
126
  get onChange() {
124
127
  return props.onWidthChange;
@@ -1 +1 @@
1
- {"version":3,"file":"contextual-sidebar.js","names":["Accessor","JSX","Show","createSignal","createUniqueId","onCleanup","onMount","cn","SidebarNav","SidebarNavContent","SidebarNavFooter","SidebarNavHeader","SidebarNavTitle","PixelResizeHandle","MobileModule","MobileLoad","error","ContextualSidebarRenderContext","mobile","portalMount","HTMLElement","ContextualSidebarProps","id","label","title","titleVisibility","open","onOpenChange","width","minimum","maximum","step","wideViewportAtLoad","resizeLabel","restoreFocusRef","onSidebarElement","element","sidebarClass","sheetClass","headerClass","contentClass","footerClass","headingAs","header","context","Element","content","footer","onWidthChange","onWidthCommit","ContextualSidebar","props","isNarrowViewport","setIsNarrowViewport","mobileLoad","setMobileLoad","mobileRequested","loadMobile","then","module","mobileMount","setMobileMount","connected","mount","isConnected","undefined","media","window","matchMedia","updateViewport","wasNarrow","matches","addEventListener","removeEventListener","renderSidebar","navigationId","_$createComponent","as","aria-label","aria-hidden","inert","data-open","String","ref","node","queueMicrotask","class","children","when","side","value","controls","onChange","onCommit","fallback","_$memo","_wide","keyed","loaded","MobileSidebar","_$createComponent","_$memo"],"sources":["../../../../src/components/layout/contextual-sidebar/contextual-sidebar.tsx"],"sourcesContent":["import type { Accessor, JSX } from 'solid-js'\nimport { Show, createSignal, createUniqueId, onCleanup, onMount } from 'solid-js'\nimport { cn } from '#lib/utils'\nimport {\n SidebarNav,\n SidebarNavContent,\n SidebarNavFooter,\n SidebarNavHeader,\n SidebarNavTitle,\n} from '../sidebar-nav/sidebar-nav'\nimport { PixelResizeHandle } from '../pixel-resize-handle/pixel-resize-handle'\n\ntype MobileModule = typeof import('./mobile-contextual-sidebar')\ntype MobileLoad = MobileModule | { error: unknown }\n\nexport type ContextualSidebarRenderContext = {\n /** Whether the slot is being rendered inside the modal mobile sheet. */\n mobile: boolean\n /** Mount nested popovers and menus inside the mobile dialog's accessibility tree. */\n portalMount(): HTMLElement | undefined\n}\n\nexport type ContextualSidebarProps = {\n /** Stable host id prefix; generated when omitted. */\n id?: string\n /** Landmark name shared by the desktop and mobile navigation. */\n label: string\n /** Visible navigation title and mobile dialog title. */\n title: string\n /**\n * Where the title row shows. `always` (default) draws it on desktop and in\n * the mobile sheet; `mobile` keeps the desktop title for assistive\n * technology only and drops the desktop row, for hosts whose top bar\n * already names the context. A `header` slot keeps the row visible.\n */\n titleVisibility?: 'always' | 'mobile'\n /** Host-controlled expanded state for the desktop panel and mobile dialog. */\n open: boolean\n onOpenChange(open: boolean): void\n /** Current host-owned pixel width, reflected by the resize handle. */\n width: number\n minimum: number\n maximum: number\n step?: number\n /** Pass the host's initial viewport seed to distinguish stale desktop state. */\n wideViewportAtLoad?: boolean\n resizeLabel?: string\n /** Stable external opener used when the modal mobile sheet closes. */\n restoreFocusRef?: Accessor<HTMLElement | undefined>\n /** Called with the nav node so a host can project width onto its layout root. */\n onSidebarElement?: (element: HTMLElement | undefined, mobile: boolean) => void\n /** Host-owned layout classes applied to both nav instances. */\n sidebarClass?: string\n /** Host-owned responsive constraints for the modal sheet. */\n sheetClass?: string\n headerClass?: string\n contentClass?: string\n footerClass?: string\n headingAs?: 'h1' | 'h2' | 'h3' | 'h4' | 'h5' | 'h6'\n /** Optional action/content slot alongside the shared heading. */\n header?(context: ContextualSidebarRenderContext): JSX.Element\n /** View-specific navigation rows, projects, rooms, files, or sessions. */\n content(context: ContextualSidebarRenderContext): JSX.Element\n /** Optional view-specific footer, such as an archive affordance. */\n footer?(context: ContextualSidebarRenderContext): JSX.Element\n onWidthChange(width: number): void\n onWidthCommit?(width: number): void\n}\n\n/**\n * ContextualSidebar.\n *\n * Shared navigation geometry and interaction policy for an application's\n * contextual sidebar. The host keeps ownership of the actual grid width,\n * persisted preference, open state, and view-specific navigation content.\n */\nexport function ContextualSidebar(props: ContextualSidebarProps) {\n const [isNarrowViewport, setIsNarrowViewport] = createSignal(false)\n const [mobileLoad, setMobileLoad] = createSignal<MobileLoad>()\n let mobileRequested = false\n // Keep the resolved component mounted across viewport changes for Sheet cleanup.\n const loadMobile = () => {\n if (mobileRequested) return\n mobileRequested = true\n // Native module caching shares successful loads without keeping a rejected promise.\n void import('./mobile-contextual-sidebar').then(\n (module) => {\n if (mobileRequested) setMobileLoad(module)\n },\n (error: unknown) => {\n if (mobileRequested) setMobileLoad({ error })\n }\n )\n }\n const [mobileMount, setMobileMount] = createSignal<\n { element: HTMLElement; connected: boolean } | undefined\n >()\n const id = props.id ?? `contextual-sidebar-${createUniqueId()}`\n const resizeLabel = () => props.resizeLabel ?? `Resize ${props.label}`\n const portalMount = () => {\n const mount = mobileMount()\n return mount?.connected && mount.element.isConnected ? mount.element : undefined\n }\n\n onMount(() => {\n const media = window.matchMedia('(max-width: 48rem)')\n const updateViewport = () => {\n const wasNarrow = isNarrowViewport()\n if (media.matches) loadMobile()\n // Close before mounting a modal. A desktop-expanded host state is not\n // mobile intent, and opening the Sheet for one frame can steal focus.\n if (media.matches && !wasNarrow) props.onOpenChange(false)\n setIsNarrowViewport(media.matches)\n }\n\n // A route can mount after a wide-loaded host crosses into mobile. Clear\n // that stale seed, but preserve a sidebar intentionally opened at a\n // narrow boot viewport.\n if (media.matches) loadMobile()\n if (media.matches && props.wideViewportAtLoad && props.open) props.onOpenChange(false)\n setIsNarrowViewport(media.matches)\n media.addEventListener('change', updateViewport)\n onCleanup(() => {\n mobileRequested = false\n media.removeEventListener('change', updateViewport)\n })\n })\n\n const renderSidebar = (mobile: boolean) => {\n let element: HTMLElement | undefined\n const context: ContextualSidebarRenderContext = {\n mobile,\n portalMount: () => (mobile ? portalMount() : undefined),\n }\n const navigationId = `${id}-${mobile ? 'mobile' : 'desktop'}`\n\n onCleanup(() => {\n if (mobile && mobileMount()?.element === element) setMobileMount(undefined)\n element = undefined\n props.onSidebarElement?.(undefined, mobile)\n })\n\n return (\n <SidebarNav\n as=\"aside\"\n id={navigationId}\n aria-label={props.label}\n aria-hidden={!mobile && !props.open ? 'true' : undefined}\n inert={!mobile && !props.open}\n data-contextual-sidebar={mobile ? 'mobile' : 'desktop'}\n data-open={mobile ? undefined : String(props.open)}\n ref={(node) => {\n element = node\n if (mobile) {\n setMobileMount({ element: node, connected: node.isConnected })\n queueMicrotask(() => {\n if (node.isConnected && mobileMount()?.element === node)\n setMobileMount({ element: node, connected: true })\n })\n }\n props.onSidebarElement?.(node, mobile)\n }}\n class={cn('relative h-full w-full max-w-full', props.sidebarClass)}\n >\n <Show when={!mobile && props.open}>\n <PixelResizeHandle\n // The ruler spans the sidebar as a pointer-events-none overlay; lift\n // it above the neighbouring pane so the edge stays grabbable.\n class=\"z-(--z-docked)\"\n side=\"left\"\n value={props.width}\n minimum={props.minimum}\n maximum={props.maximum}\n step={props.step}\n label={resizeLabel()}\n controls={navigationId}\n onChange={props.onWidthChange}\n onCommit={props.onWidthCommit}\n />\n </Show>\n <Show when={!mobile || mobileMount()?.connected}>\n <Show\n when={mobile || props.titleVisibility !== 'mobile' || props.header}\n fallback={\n <SidebarNavTitle as={props.headingAs ?? 'h2'} class=\"sr-only\">\n {props.title}\n </SidebarNavTitle>\n }\n >\n <SidebarNavHeader class={cn(mobile && 'pe-12', props.headerClass)}>\n <SidebarNavTitle as={props.headingAs ?? 'h2'}>{props.title}</SidebarNavTitle>\n {props.header?.(context)}\n </SidebarNavHeader>\n </Show>\n <SidebarNavContent class={props.contentClass}>{props.content(context)}</SidebarNavContent>\n {props.footer ? (\n <SidebarNavFooter class={props.footerClass}>{props.footer(context)}</SidebarNavFooter>\n ) : null}\n </Show>\n </SidebarNav>\n )\n }\n\n return (\n <>\n <Show when={!isNarrowViewport()}>{(_wide) => renderSidebar(false)}</Show>\n <Show when={mobileLoad()} keyed>\n {(loaded) => {\n if ('error' in loaded) throw loaded.error\n return (\n <loaded.MobileSidebar\n open={isNarrowViewport() && props.open}\n onOpenChange={props.onOpenChange}\n label={props.label}\n sheetClass={props.sheetClass}\n restoreFocusRef={props.restoreFocusRef}\n renderSidebar={() => renderSidebar(true)}\n />\n )\n }}\n </Show>\n </>\n )\n}\n"],"mappings":"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"}
1
+ {"version":3,"file":"contextual-sidebar.js","names":["Accessor","JSX","Show","createSignal","createUniqueId","onCleanup","onMount","cn","SidebarNav","SidebarNavContent","SidebarNavFooter","SidebarNavHeader","SidebarNavTitle","PixelResizeHandle","MobileModule","MobileLoad","error","ContextualSidebarRenderContext","mobile","portalMount","HTMLElement","ContextualSidebarProps","id","label","title","titleVisibility","open","onOpenChange","width","minimum","maximum","step","wideViewportAtLoad","resizeLabel","resizeGrip","restoreFocusRef","onSidebarElement","element","sidebarClass","sheetClass","headerClass","contentClass","footerClass","headingAs","header","context","Element","content","footer","onWidthChange","onWidthCommit","ContextualSidebar","props","isNarrowViewport","setIsNarrowViewport","mobileLoad","setMobileLoad","mobileRequested","loadMobile","then","module","mobileMount","setMobileMount","connected","mount","isConnected","undefined","media","window","matchMedia","updateViewport","wasNarrow","matches","addEventListener","removeEventListener","renderSidebar","navigationId","_$createComponent","as","aria-label","aria-hidden","inert","data-open","String","ref","node","queueMicrotask","class","children","when","side","value","grip","controls","onChange","onCommit","fallback","_$memo","_wide","keyed","loaded","MobileSidebar","_$createComponent","_$memo"],"sources":["../../../../src/components/layout/contextual-sidebar/contextual-sidebar.tsx"],"sourcesContent":["import type { Accessor, JSX } from 'solid-js'\nimport { Show, createSignal, createUniqueId, onCleanup, onMount } from 'solid-js'\nimport { cn } from '#lib/utils'\nimport {\n SidebarNav,\n SidebarNavContent,\n SidebarNavFooter,\n SidebarNavHeader,\n SidebarNavTitle,\n} from '../sidebar-nav/sidebar-nav'\nimport { PixelResizeHandle } from '../pixel-resize-handle/pixel-resize-handle'\n\ntype MobileModule = typeof import('./mobile-contextual-sidebar')\ntype MobileLoad = MobileModule | { error: unknown }\n\nexport type ContextualSidebarRenderContext = {\n /** Whether the slot is being rendered inside the modal mobile sheet. */\n mobile: boolean\n /** Mount nested popovers and menus inside the mobile dialog's accessibility tree. */\n portalMount(): HTMLElement | undefined\n}\n\nexport type ContextualSidebarProps = {\n /** Stable host id prefix; generated when omitted. */\n id?: string\n /** Landmark name shared by the desktop and mobile navigation. */\n label: string\n /** Visible navigation title and mobile dialog title. */\n title: string\n /**\n * Where the title row shows. `always` (default) draws it on desktop and in\n * the mobile sheet; `mobile` keeps the desktop title for assistive\n * technology only and drops the desktop row, for hosts whose top bar\n * already names the context. A `header` slot keeps the row visible.\n */\n titleVisibility?: 'always' | 'mobile'\n /** Host-controlled expanded state for the desktop panel and mobile dialog. */\n open: boolean\n onOpenChange(open: boolean): void\n /** Current host-owned pixel width, reflected by the resize handle. */\n width: number\n minimum: number\n maximum: number\n step?: number\n /** Pass the host's initial viewport seed to distinguish stale desktop state. */\n wideViewportAtLoad?: boolean\n resizeLabel?: string\n /** The resize edge's grip: the default bordered chip, or the quieter rung. */\n resizeGrip?: 'chip' | 'rung'\n /** Stable external opener used when the modal mobile sheet closes. */\n restoreFocusRef?: Accessor<HTMLElement | undefined>\n /** Called with the nav node so a host can project width onto its layout root. */\n onSidebarElement?: (element: HTMLElement | undefined, mobile: boolean) => void\n /** Host-owned layout classes applied to both nav instances. */\n sidebarClass?: string\n /** Host-owned responsive constraints for the modal sheet. */\n sheetClass?: string\n headerClass?: string\n contentClass?: string\n footerClass?: string\n headingAs?: 'h1' | 'h2' | 'h3' | 'h4' | 'h5' | 'h6'\n /** Optional action/content slot alongside the shared heading. */\n header?(context: ContextualSidebarRenderContext): JSX.Element\n /** View-specific navigation rows, projects, rooms, files, or sessions. */\n content(context: ContextualSidebarRenderContext): JSX.Element\n /** Optional view-specific footer, such as an archive affordance. */\n footer?(context: ContextualSidebarRenderContext): JSX.Element\n onWidthChange(width: number): void\n onWidthCommit?(width: number): void\n}\n\n/**\n * ContextualSidebar.\n *\n * Shared navigation geometry and interaction policy for an application's\n * contextual sidebar. The host keeps ownership of the actual grid width,\n * persisted preference, open state, and view-specific navigation content.\n */\nexport function ContextualSidebar(props: ContextualSidebarProps) {\n const [isNarrowViewport, setIsNarrowViewport] = createSignal(false)\n const [mobileLoad, setMobileLoad] = createSignal<MobileLoad>()\n let mobileRequested = false\n // Keep the resolved component mounted across viewport changes for Sheet cleanup.\n const loadMobile = () => {\n if (mobileRequested) return\n mobileRequested = true\n // Native module caching shares successful loads without keeping a rejected promise.\n void import('./mobile-contextual-sidebar').then(\n (module) => {\n if (mobileRequested) setMobileLoad(module)\n },\n (error: unknown) => {\n if (mobileRequested) setMobileLoad({ error })\n }\n )\n }\n const [mobileMount, setMobileMount] = createSignal<\n { element: HTMLElement; connected: boolean } | undefined\n >()\n const id = props.id ?? `contextual-sidebar-${createUniqueId()}`\n const resizeLabel = () => props.resizeLabel ?? `Resize ${props.label}`\n const portalMount = () => {\n const mount = mobileMount()\n return mount?.connected && mount.element.isConnected ? mount.element : undefined\n }\n\n onMount(() => {\n const media = window.matchMedia('(max-width: 48rem)')\n const updateViewport = () => {\n const wasNarrow = isNarrowViewport()\n if (media.matches) loadMobile()\n // Close before mounting a modal. A desktop-expanded host state is not\n // mobile intent, and opening the Sheet for one frame can steal focus.\n if (media.matches && !wasNarrow) props.onOpenChange(false)\n setIsNarrowViewport(media.matches)\n }\n\n // A route can mount after a wide-loaded host crosses into mobile. Clear\n // that stale seed, but preserve a sidebar intentionally opened at a\n // narrow boot viewport.\n if (media.matches) loadMobile()\n if (media.matches && props.wideViewportAtLoad && props.open) props.onOpenChange(false)\n setIsNarrowViewport(media.matches)\n media.addEventListener('change', updateViewport)\n onCleanup(() => {\n mobileRequested = false\n media.removeEventListener('change', updateViewport)\n })\n })\n\n const renderSidebar = (mobile: boolean) => {\n let element: HTMLElement | undefined\n const context: ContextualSidebarRenderContext = {\n mobile,\n portalMount: () => (mobile ? portalMount() : undefined),\n }\n const navigationId = `${id}-${mobile ? 'mobile' : 'desktop'}`\n\n onCleanup(() => {\n if (mobile && mobileMount()?.element === element) setMobileMount(undefined)\n element = undefined\n props.onSidebarElement?.(undefined, mobile)\n })\n\n return (\n <SidebarNav\n as=\"aside\"\n id={navigationId}\n aria-label={props.label}\n aria-hidden={!mobile && !props.open ? 'true' : undefined}\n inert={!mobile && !props.open}\n data-contextual-sidebar={mobile ? 'mobile' : 'desktop'}\n data-open={mobile ? undefined : String(props.open)}\n ref={(node) => {\n element = node\n if (mobile) {\n setMobileMount({ element: node, connected: node.isConnected })\n queueMicrotask(() => {\n if (node.isConnected && mobileMount()?.element === node)\n setMobileMount({ element: node, connected: true })\n })\n }\n props.onSidebarElement?.(node, mobile)\n }}\n class={cn('relative h-full w-full max-w-full', props.sidebarClass)}\n >\n <Show when={!mobile && props.open}>\n <PixelResizeHandle\n // The ruler spans the sidebar as a pointer-events-none overlay; lift\n // it above the neighbouring pane so the edge stays grabbable.\n class=\"z-(--z-docked)\"\n side=\"left\"\n value={props.width}\n minimum={props.minimum}\n maximum={props.maximum}\n step={props.step}\n label={resizeLabel()}\n grip={props.resizeGrip}\n controls={navigationId}\n onChange={props.onWidthChange}\n onCommit={props.onWidthCommit}\n />\n </Show>\n <Show when={!mobile || mobileMount()?.connected}>\n <Show\n when={mobile || props.titleVisibility !== 'mobile' || props.header}\n fallback={\n <SidebarNavTitle as={props.headingAs ?? 'h2'} class=\"sr-only\">\n {props.title}\n </SidebarNavTitle>\n }\n >\n <SidebarNavHeader class={cn(mobile && 'pe-12', props.headerClass)}>\n <SidebarNavTitle as={props.headingAs ?? 'h2'}>{props.title}</SidebarNavTitle>\n {props.header?.(context)}\n </SidebarNavHeader>\n </Show>\n <SidebarNavContent class={props.contentClass}>{props.content(context)}</SidebarNavContent>\n {props.footer ? (\n <SidebarNavFooter class={props.footerClass}>{props.footer(context)}</SidebarNavFooter>\n ) : null}\n </Show>\n </SidebarNav>\n )\n }\n\n return (\n <>\n <Show when={!isNarrowViewport()}>{(_wide) => renderSidebar(false)}</Show>\n <Show when={mobileLoad()} keyed>\n {(loaded) => {\n if ('error' in loaded) throw loaded.error\n return (\n <loaded.MobileSidebar\n open={isNarrowViewport() && props.open}\n onOpenChange={props.onOpenChange}\n label={props.label}\n sheetClass={props.sheetClass}\n restoreFocusRef={props.restoreFocusRef}\n renderSidebar={() => renderSidebar(true)}\n />\n )\n }}\n </Show>\n </>\n )\n}\n"],"mappings":"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"}
@@ -1 +1 @@
1
- {"version":3,"file":"mobile-contextual-sidebar.d.ts","sourceRoot":"","sources":["../../../../src/components/layout/contextual-sidebar/mobile-contextual-sidebar.tsx"],"names":[],"mappings":"AAAA,OAAO,KAAK,EAAE,QAAQ,EAAE,GAAG,EAAE,MAAM,UAAU,CAAA;AAI7C,MAAM,MAAM,4BAA4B,GAAG;IACzC,IAAI,EAAE,OAAO,CAAA;IACb,YAAY,CAAC,IAAI,EAAE,OAAO,GAAG,IAAI,CAAA;IACjC,KAAK,EAAE,MAAM,CAAA;IACb,UAAU,CAAC,EAAE,MAAM,CAAA;IACnB,eAAe,CAAC,EAAE,QAAQ,CAAC,WAAW,GAAG,SAAS,CAAC,CAAA;IACnD,aAAa,IAAI,GAAG,CAAC,OAAO,CAAA;CAC7B,CAAA;AAED,mFAAmF;AACnF,wBAAgB,aAAa,CAAC,KAAK,EAAE,4BAA4B,eAahE"}
1
+ {"version":3,"file":"mobile-contextual-sidebar.d.ts","sourceRoot":"","sources":["../../../../src/components/layout/contextual-sidebar/mobile-contextual-sidebar.tsx"],"names":[],"mappings":"AAAA,OAAO,KAAK,EAAE,QAAQ,EAAE,GAAG,EAAE,MAAM,UAAU,CAAA;AAI7C,MAAM,MAAM,4BAA4B,GAAG;IACzC,IAAI,EAAE,OAAO,CAAA;IACb,YAAY,CAAC,IAAI,EAAE,OAAO,GAAG,IAAI,CAAA;IACjC,KAAK,EAAE,MAAM,CAAA;IACb,UAAU,CAAC,EAAE,MAAM,CAAA;IACnB,eAAe,CAAC,EAAE,QAAQ,CAAC,WAAW,GAAG,SAAS,CAAC,CAAA;IACnD,aAAa,IAAI,GAAG,CAAC,OAAO,CAAA;CAC7B,CAAA;AAED,mFAAmF;AACnF,wBAAgB,aAAa,CAAC,KAAK,EAAE,4BAA4B,eAkBhE"}
@@ -18,7 +18,7 @@ function MobileSidebar(props) {
18
18
  return props.label;
19
19
  },
20
20
  get ["class"]() {
21
- return cn("gap-0 p-0", props.sheetClass);
21
+ return cn("w-[min(19rem,max(9rem,calc(100vw-var(--rail-width,3.5rem))))] max-w-[min(19rem,max(9rem,calc(100vw-var(--rail-width,3.5rem))))] gap-0 p-0", props.sheetClass);
22
22
  },
23
23
  get restoreFocusRef() {
24
24
  return props.restoreFocusRef;
@@ -1 +1 @@
1
- {"version":3,"file":"mobile-contextual-sidebar.js","names":["Accessor","JSX","cn","Sheet","SheetContent","MobileContextualSidebarProps","open","onOpenChange","label","sheetClass","restoreFocusRef","HTMLElement","renderSidebar","Element","MobileSidebar","props","_$createComponent","children","side","aria-label","class","_$createComponent"],"sources":["../../../../src/components/layout/contextual-sidebar/mobile-contextual-sidebar.tsx"],"sourcesContent":["import type { Accessor, JSX } from 'solid-js'\nimport { cn } from '#lib/utils'\nimport { Sheet, SheetContent } from '../../ui/sheet'\n\nexport type MobileContextualSidebarProps = {\n open: boolean\n onOpenChange(open: boolean): void\n label: string\n sheetClass?: string\n restoreFocusRef?: Accessor<HTMLElement | undefined>\n renderSidebar(): JSX.Element\n}\n\n/** Sheet wrappers are loaded only when a contextual sidebar enters mobile mode. */\nexport function MobileSidebar(props: MobileContextualSidebarProps) {\n return (\n <Sheet open={props.open} onOpenChange={props.onOpenChange}>\n <SheetContent\n side=\"start\"\n aria-label={props.label}\n class={cn('gap-0 p-0', props.sheetClass)}\n restoreFocusRef={props.restoreFocusRef}\n >\n {props.renderSidebar()}\n </SheetContent>\n </Sheet>\n )\n}\n"],"mappings":";;;;;AAcA,SAAgBc,cAAcC,OAAqC;CACjE,OAAAC,gBACGb,OAAK;EAAA,IAACG,OAAI;GAAA,OAAES,MAAMT;EAAI;EAAA,IAAEC,eAAY;GAAA,OAAEQ,MAAMR;EAAY;EAAA,IAAAU,WAAA;GAAA,OAAAD,gBACtDZ,cAAY;IACXc,MAAI;IAAA,KAAA,gBAAA;KAAA,OACQH,MAAMP;IAAK;IAAA,KAAA,WAAA;KAAA,OAChBN,GAAG,aAAaa,MAAMN,UAAU;IAAC;IAAA,IACxCC,kBAAe;KAAA,OAAEK,MAAML;IAAe;IAAA,IAAAO,WAAA;KAAA,OAErCF,MAAMH,cAAc;IAAC;GAAA,CAAA;EAAA;CAAA,CAAA;AAI9B"}
1
+ {"version":3,"file":"mobile-contextual-sidebar.js","names":["Accessor","JSX","cn","Sheet","SheetContent","MobileContextualSidebarProps","open","onOpenChange","label","sheetClass","restoreFocusRef","HTMLElement","renderSidebar","Element","MobileSidebar","props","_$createComponent","children","side","aria-label","class","_$createComponent"],"sources":["../../../../src/components/layout/contextual-sidebar/mobile-contextual-sidebar.tsx"],"sourcesContent":["import type { Accessor, JSX } from 'solid-js'\nimport { cn } from '#lib/utils'\nimport { Sheet, SheetContent } from '../../ui/sheet'\n\nexport type MobileContextualSidebarProps = {\n open: boolean\n onOpenChange(open: boolean): void\n label: string\n sheetClass?: string\n restoreFocusRef?: Accessor<HTMLElement | undefined>\n renderSidebar(): JSX.Element\n}\n\n/** Sheet wrappers are loaded only when a contextual sidebar enters mobile mode. */\nexport function MobileSidebar(props: MobileContextualSidebarProps) {\n return (\n <Sheet open={props.open} onOpenChange={props.onOpenChange}>\n <SheetContent\n side=\"start\"\n aria-label={props.label}\n // The sheet leaves the app rail visible beside it: at most 19rem, never\n // under 9rem, and otherwise the viewport less the rail's width.\n class={cn(\n 'w-[min(19rem,max(9rem,calc(100vw-var(--rail-width,3.5rem))))] max-w-[min(19rem,max(9rem,calc(100vw-var(--rail-width,3.5rem))))] gap-0 p-0',\n props.sheetClass\n )}\n restoreFocusRef={props.restoreFocusRef}\n >\n {props.renderSidebar()}\n </SheetContent>\n </Sheet>\n )\n}\n"],"mappings":";;;;;AAcA,SAAgBc,cAAcC,OAAqC;CACjE,OAAAC,gBACGb,OAAK;EAAA,IAACG,OAAI;GAAA,OAAES,MAAMT;EAAI;EAAA,IAAEC,eAAY;GAAA,OAAEQ,MAAMR;EAAY;EAAA,IAAAU,WAAA;GAAA,OAAAD,gBACtDZ,cAAY;IACXc,MAAI;IAAA,KAAA,gBAAA;KAAA,OACQH,MAAMP;IAAK;IAAA,KAAA,WAAA;KAAA,OAGhBN,GACL,6IACAa,MAAMN,UACR;IAAC;IAAA,IACDC,kBAAe;KAAA,OAAEK,MAAML;IAAe;IAAA,IAAAO,WAAA;KAAA,OAErCF,MAAMH,cAAc;IAAC;GAAA,CAAA;EAAA;CAAA,CAAA;AAI9B"}
@@ -9,6 +9,8 @@ export type PixelResizeHandleProps = {
9
9
  label?: string;
10
10
  controls?: string;
11
11
  class?: string;
12
+ /** The grip drawn on the edge: the default bordered chip, or the quieter rung. */
13
+ grip?: 'chip' | 'rung';
12
14
  onChange(value: number): void;
13
15
  onCommit?(value: number): void;
14
16
  };
@@ -1 +1 @@
1
- {"version":3,"file":"pixel-resize-handle.d.ts","sourceRoot":"","sources":["../../../../src/components/layout/pixel-resize-handle/pixel-resize-handle.tsx"],"names":[],"mappings":"AAIA,MAAM,MAAM,sBAAsB,GAAG;IACnC,6EAA6E;IAC7E,IAAI,EAAE,MAAM,GAAG,OAAO,CAAA;IACtB,mCAAmC;IACnC,KAAK,EAAE,MAAM,CAAA;IACb,OAAO,EAAE,MAAM,CAAA;IACf,OAAO,EAAE,MAAM,CAAA;IACf,IAAI,CAAC,EAAE,MAAM,CAAA;IACb,KAAK,CAAC,EAAE,MAAM,CAAA;IACd,QAAQ,CAAC,EAAE,MAAM,CAAA;IACjB,KAAK,CAAC,EAAE,MAAM,CAAA;IACd,QAAQ,CAAC,KAAK,EAAE,MAAM,GAAG,IAAI,CAAA;IAC7B,QAAQ,CAAC,CAAC,KAAK,EAAE,MAAM,GAAG,IAAI,CAAA;CAC/B,CAAA;AAED;;;;;;;;;;;;GAYG;AACH,wBAAgB,iBAAiB,CAAC,KAAK,EAAE,sBAAsB,kCAgJ9D"}
1
+ {"version":3,"file":"pixel-resize-handle.d.ts","sourceRoot":"","sources":["../../../../src/components/layout/pixel-resize-handle/pixel-resize-handle.tsx"],"names":[],"mappings":"AAIA,MAAM,MAAM,sBAAsB,GAAG;IACnC,6EAA6E;IAC7E,IAAI,EAAE,MAAM,GAAG,OAAO,CAAA;IACtB,mCAAmC;IACnC,KAAK,EAAE,MAAM,CAAA;IACb,OAAO,EAAE,MAAM,CAAA;IACf,OAAO,EAAE,MAAM,CAAA;IACf,IAAI,CAAC,EAAE,MAAM,CAAA;IACb,KAAK,CAAC,EAAE,MAAM,CAAA;IACd,QAAQ,CAAC,EAAE,MAAM,CAAA;IACjB,KAAK,CAAC,EAAE,MAAM,CAAA;IACd,kFAAkF;IAClF,IAAI,CAAC,EAAE,MAAM,GAAG,MAAM,CAAA;IACtB,QAAQ,CAAC,KAAK,EAAE,MAAM,GAAG,IAAI,CAAA;IAC7B,QAAQ,CAAC,CAAC,KAAK,EAAE,MAAM,GAAG,IAAI,CAAA;CAC/B,CAAA;AAED;;;;;;;;;;;;GAYG;AACH,wBAAgB,iBAAiB,CAAC,KAAK,EAAE,sBAAsB,kCAgJ9D"}
@@ -76,7 +76,9 @@ function PixelResizeHandle(props) {
76
76
  "aria-hidden": "true"
77
77
  }),
78
78
  createComponent(ResizableHandle, {
79
- withHandle: true,
79
+ get withHandle() {
80
+ return props.grip === "rung" ? "rung" : true;
81
+ },
80
82
  get label() {
81
83
  return props.label ?? `Resize ${props.side} pane`;
82
84
  },
@@ -1 +1 @@
1
- {"version":3,"file":"pixel-resize-handle.js","names":["ResizableHandle","ResizablePanel","ResizablePanelGroup","createSignal","onCleanup","cn","PixelResizeHandleProps","side","value","minimum","maximum","step","label","controls","class","onChange","onCommit","PixelResizeHandle","props","Math","max","min","round","ratio","isRight","rulerSizes","commit","interacting","drag","setDrag","pointerId","startX","startValue","handle","HTMLElement","endPointer","shouldCommit","current","undefined","hasPointerCapture","releasePointerCapture","endKeyboard","wasInteracting","_$createComponent","orientation","dir","sizes","keyboardDelta","style","width","onSizesChange","length","next","bounded","children","minSize","_$memo","maxSize","withHandle","aria-controls","aria-valuemin","aria-valuemax","aria-valuenow","aria-valuetext","data-dragging","onHandleDragStart","event","preventDefault","button","isPrimary","currentTarget","focus","setPointerCapture","clientX","onPointerMove","PointerEvent","delta","onPointerUp","onPointerCancel","onLostPointerCapture","onBlur","onKeyDown","includes","key","onKeyUp","_$createComponent","_$memo"],"sources":["../../../../src/components/layout/pixel-resize-handle/pixel-resize-handle.tsx"],"sourcesContent":["import { ResizableHandle, ResizablePanel, ResizablePanelGroup } from '../../ui/resizable'\nimport { createSignal, onCleanup } from 'solid-js'\nimport { cn } from '#lib/utils'\n\nexport type PixelResizeHandleProps = {\n /** Which physical edge of the ruler the resizable surface is attached to. */\n side: 'left' | 'right'\n /** Current width in CSS pixels. */\n value: number\n minimum: number\n maximum: number\n step?: number\n label?: string\n controls?: string\n class?: string\n onChange(value: number): void\n onCommit?(value: number): void\n}\n\n/**\n * PixelResizeHandle.\n *\n * A keyboard- and pointer-operable edge ruler for a host-owned pane. Keep the\n * pane's actual width and any persistence in its layout owner; this component\n * reports a bounded pixel value and places the shared resizable grip at the\n * matching left or right edge.\n *\n * Corvu 0.2.5 supplies geometry, keyboard resizing, ARIA and the shared grip,\n * but its global drag handler does not end on pointer cancellation. Prevent\n * that handler through its public start hook and use local pointer capture\n * for bounded pixel gestures, including cancellation and lost capture.\n */\nexport function PixelResizeHandle(props: PixelResizeHandleProps) {\n const maximum = () => Math.max(1, props.maximum)\n const minimum = () => Math.min(maximum(), Math.max(0, props.minimum))\n const value = () => Math.min(maximum(), Math.max(minimum(), Math.round(props.value)))\n const ratio = () => value() / maximum()\n const isRight = () => props.side === 'right'\n const rulerSizes = () => (isRight() ? [1 - ratio(), ratio()] : [ratio(), 1 - ratio()])\n const commit = () => props.onCommit?.(value())\n let interacting = false\n const [drag, setDrag] = createSignal<{\n pointerId: number\n startX: number\n startValue: number\n handle: HTMLElement\n }>()\n const endPointer = (shouldCommit: boolean) => {\n const current = drag()\n if (!current) return\n setDrag(undefined)\n if (current.handle.hasPointerCapture(current.pointerId))\n current.handle.releasePointerCapture(current.pointerId)\n if (shouldCommit) commit()\n }\n const endKeyboard = () => {\n const wasInteracting = interacting\n interacting = false\n if (wasInteracting) commit()\n }\n onCleanup(() => {\n endKeyboard()\n endPointer(false)\n })\n\n return (\n <ResizablePanelGroup\n orientation=\"horizontal\"\n dir=\"ltr\"\n sizes={rulerSizes()}\n keyboardDelta={`${props.step ?? 16}px`}\n style={{ width: `${maximum()}px` }}\n class={cn(\n 'pointer-events-none absolute inset-y-0 flex',\n {\n 'left-0': props.side === 'left',\n 'right-0': props.side === 'right',\n },\n props.class\n )}\n onSizesChange={(sizes) => {\n // Panel registration and teardown also emit sizes. Only user resizing\n // may update the host preference; collapsing must preserve its width.\n if (!interacting || sizes.length !== 2) return\n const next = Math.round((sizes[isRight() ? 1 : 0] ?? ratio()) * maximum())\n const bounded = Math.min(maximum(), Math.max(minimum(), next))\n if (bounded !== value()) props.onChange(bounded)\n }}\n >\n <ResizablePanel\n minSize={isRight() ? 0 : minimum() / maximum()}\n maxSize={1}\n aria-hidden=\"true\"\n />\n <ResizableHandle\n withHandle\n label={props.label ?? `Resize ${props.side} pane`}\n aria-controls={props.controls}\n aria-valuemin={minimum()}\n aria-valuemax={maximum()}\n aria-valuenow={value()}\n aria-valuetext={`${value()} pixels`}\n data-dragging={drag() ? '' : undefined}\n onHandleDragStart={(event) => {\n // Corvu checks defaultPrevented before starting its global handler.\n event.preventDefault()\n if (event.button !== 0 || !event.isPrimary) return\n const handle = event.currentTarget\n if (!(handle instanceof HTMLElement)) return\n endPointer(false)\n interacting = false\n handle.focus()\n handle.setPointerCapture(event.pointerId)\n setDrag({\n pointerId: event.pointerId,\n startX: event.clientX,\n startValue: value(),\n handle,\n })\n }}\n onPointerMove={(event: PointerEvent) => {\n const current = drag()\n if (!current || event.pointerId !== current.pointerId) return\n if (!current.handle.hasPointerCapture(current.pointerId)) {\n endPointer(false)\n return\n }\n const delta = (event.clientX - current.startX) * (isRight() ? -1 : 1)\n const next = Math.min(\n maximum(),\n Math.max(minimum(), Math.round(current.startValue + delta))\n )\n if (next !== value()) props.onChange(next)\n }}\n onPointerUp={(event: PointerEvent) => {\n if (event.pointerId === drag()?.pointerId) endPointer(true)\n }}\n onPointerCancel={(event: PointerEvent) => {\n if (event.pointerId === drag()?.pointerId) endPointer(false)\n }}\n onLostPointerCapture={(event: PointerEvent) => {\n if (event.pointerId === drag()?.pointerId) endPointer(false)\n }}\n onBlur={() => {\n endKeyboard()\n endPointer(false)\n }}\n onKeyDown={(event) => {\n const current = drag()\n if (current && !current.handle.hasPointerCapture(current.pointerId)) endPointer(false)\n if (drag()) {\n event.preventDefault()\n return\n }\n if (['ArrowLeft', 'ArrowRight', 'Home', 'End'].includes(event.key)) interacting = true\n // Corvu operates on physical panel order. Home/End here describe\n // the controlled pane width, including a pane after the separator.\n if (event.key === 'Home' || event.key === 'End') {\n event.preventDefault()\n props.onChange(event.key === 'Home' ? minimum() : maximum())\n }\n }}\n onKeyUp={(event) => {\n if (['ArrowLeft', 'ArrowRight', 'Home', 'End'].includes(event.key)) {\n endKeyboard()\n }\n }}\n class=\"pointer-events-auto\"\n />\n <ResizablePanel\n minSize={isRight() ? minimum() / maximum() : 0}\n maxSize={1}\n aria-hidden=\"true\"\n />\n </ResizablePanelGroup>\n )\n}\n"],"mappings":"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"}
1
+ {"version":3,"file":"pixel-resize-handle.js","names":["ResizableHandle","ResizablePanel","ResizablePanelGroup","createSignal","onCleanup","cn","PixelResizeHandleProps","side","value","minimum","maximum","step","label","controls","class","grip","onChange","onCommit","PixelResizeHandle","props","Math","max","min","round","ratio","isRight","rulerSizes","commit","interacting","drag","setDrag","pointerId","startX","startValue","handle","HTMLElement","endPointer","shouldCommit","current","undefined","hasPointerCapture","releasePointerCapture","endKeyboard","wasInteracting","_$createComponent","orientation","dir","sizes","keyboardDelta","style","width","onSizesChange","length","next","bounded","children","minSize","_$memo","maxSize","withHandle","aria-controls","aria-valuemin","aria-valuemax","aria-valuenow","aria-valuetext","data-dragging","onHandleDragStart","event","preventDefault","button","isPrimary","currentTarget","focus","setPointerCapture","clientX","onPointerMove","PointerEvent","delta","onPointerUp","onPointerCancel","onLostPointerCapture","onBlur","onKeyDown","includes","key","onKeyUp","_$createComponent","_$memo"],"sources":["../../../../src/components/layout/pixel-resize-handle/pixel-resize-handle.tsx"],"sourcesContent":["import { ResizableHandle, ResizablePanel, ResizablePanelGroup } from '../../ui/resizable'\nimport { createSignal, onCleanup } from 'solid-js'\nimport { cn } from '#lib/utils'\n\nexport type PixelResizeHandleProps = {\n /** Which physical edge of the ruler the resizable surface is attached to. */\n side: 'left' | 'right'\n /** Current width in CSS pixels. */\n value: number\n minimum: number\n maximum: number\n step?: number\n label?: string\n controls?: string\n class?: string\n /** The grip drawn on the edge: the default bordered chip, or the quieter rung. */\n grip?: 'chip' | 'rung'\n onChange(value: number): void\n onCommit?(value: number): void\n}\n\n/**\n * PixelResizeHandle.\n *\n * A keyboard- and pointer-operable edge ruler for a host-owned pane. Keep the\n * pane's actual width and any persistence in its layout owner; this component\n * reports a bounded pixel value and places the shared resizable grip at the\n * matching left or right edge.\n *\n * Corvu 0.2.5 supplies geometry, keyboard resizing, ARIA and the shared grip,\n * but its global drag handler does not end on pointer cancellation. Prevent\n * that handler through its public start hook and use local pointer capture\n * for bounded pixel gestures, including cancellation and lost capture.\n */\nexport function PixelResizeHandle(props: PixelResizeHandleProps) {\n const maximum = () => Math.max(1, props.maximum)\n const minimum = () => Math.min(maximum(), Math.max(0, props.minimum))\n const value = () => Math.min(maximum(), Math.max(minimum(), Math.round(props.value)))\n const ratio = () => value() / maximum()\n const isRight = () => props.side === 'right'\n const rulerSizes = () => (isRight() ? [1 - ratio(), ratio()] : [ratio(), 1 - ratio()])\n const commit = () => props.onCommit?.(value())\n let interacting = false\n const [drag, setDrag] = createSignal<{\n pointerId: number\n startX: number\n startValue: number\n handle: HTMLElement\n }>()\n const endPointer = (shouldCommit: boolean) => {\n const current = drag()\n if (!current) return\n setDrag(undefined)\n if (current.handle.hasPointerCapture(current.pointerId))\n current.handle.releasePointerCapture(current.pointerId)\n if (shouldCommit) commit()\n }\n const endKeyboard = () => {\n const wasInteracting = interacting\n interacting = false\n if (wasInteracting) commit()\n }\n onCleanup(() => {\n endKeyboard()\n endPointer(false)\n })\n\n return (\n <ResizablePanelGroup\n orientation=\"horizontal\"\n dir=\"ltr\"\n sizes={rulerSizes()}\n keyboardDelta={`${props.step ?? 16}px`}\n style={{ width: `${maximum()}px` }}\n class={cn(\n 'pointer-events-none absolute inset-y-0 flex',\n {\n 'left-0': props.side === 'left',\n 'right-0': props.side === 'right',\n },\n props.class\n )}\n onSizesChange={(sizes) => {\n // Panel registration and teardown also emit sizes. Only user resizing\n // may update the host preference; collapsing must preserve its width.\n if (!interacting || sizes.length !== 2) return\n const next = Math.round((sizes[isRight() ? 1 : 0] ?? ratio()) * maximum())\n const bounded = Math.min(maximum(), Math.max(minimum(), next))\n if (bounded !== value()) props.onChange(bounded)\n }}\n >\n <ResizablePanel\n minSize={isRight() ? 0 : minimum() / maximum()}\n maxSize={1}\n aria-hidden=\"true\"\n />\n <ResizableHandle\n withHandle={props.grip === 'rung' ? 'rung' : true}\n label={props.label ?? `Resize ${props.side} pane`}\n aria-controls={props.controls}\n aria-valuemin={minimum()}\n aria-valuemax={maximum()}\n aria-valuenow={value()}\n aria-valuetext={`${value()} pixels`}\n data-dragging={drag() ? '' : undefined}\n onHandleDragStart={(event) => {\n // Corvu checks defaultPrevented before starting its global handler.\n event.preventDefault()\n if (event.button !== 0 || !event.isPrimary) return\n const handle = event.currentTarget\n if (!(handle instanceof HTMLElement)) return\n endPointer(false)\n interacting = false\n handle.focus()\n handle.setPointerCapture(event.pointerId)\n setDrag({\n pointerId: event.pointerId,\n startX: event.clientX,\n startValue: value(),\n handle,\n })\n }}\n onPointerMove={(event: PointerEvent) => {\n const current = drag()\n if (!current || event.pointerId !== current.pointerId) return\n if (!current.handle.hasPointerCapture(current.pointerId)) {\n endPointer(false)\n return\n }\n const delta = (event.clientX - current.startX) * (isRight() ? -1 : 1)\n const next = Math.min(\n maximum(),\n Math.max(minimum(), Math.round(current.startValue + delta))\n )\n if (next !== value()) props.onChange(next)\n }}\n onPointerUp={(event: PointerEvent) => {\n if (event.pointerId === drag()?.pointerId) endPointer(true)\n }}\n onPointerCancel={(event: PointerEvent) => {\n if (event.pointerId === drag()?.pointerId) endPointer(false)\n }}\n onLostPointerCapture={(event: PointerEvent) => {\n if (event.pointerId === drag()?.pointerId) endPointer(false)\n }}\n onBlur={() => {\n endKeyboard()\n endPointer(false)\n }}\n onKeyDown={(event) => {\n const current = drag()\n if (current && !current.handle.hasPointerCapture(current.pointerId)) endPointer(false)\n if (drag()) {\n event.preventDefault()\n return\n }\n if (['ArrowLeft', 'ArrowRight', 'Home', 'End'].includes(event.key)) interacting = true\n // Corvu operates on physical panel order. Home/End here describe\n // the controlled pane width, including a pane after the separator.\n if (event.key === 'Home' || event.key === 'End') {\n event.preventDefault()\n props.onChange(event.key === 'Home' ? minimum() : maximum())\n }\n }}\n onKeyUp={(event) => {\n if (['ArrowLeft', 'ArrowRight', 'Home', 'End'].includes(event.key)) {\n endKeyboard()\n }\n }}\n class=\"pointer-events-auto\"\n />\n <ResizablePanel\n minSize={isRight() ? minimum() / maximum() : 0}\n maxSize={1}\n aria-hidden=\"true\"\n />\n </ResizablePanelGroup>\n )\n}\n"],"mappings":"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"}
@@ -8,8 +8,13 @@ export declare function ResizablePanel(props: ComponentProps<typeof Resizable.Pa
8
8
  }): import("solid-js").JSX.Element;
9
9
  export type ResizableHandleProps = ComponentProps<typeof Resizable.Handle> & {
10
10
  class?: string;
11
- /** Draw a visible grip in the middle of the divider. */
12
- withHandle?: boolean;
11
+ /**
12
+ * Draw a visible grip in the middle of the divider: `true` is the bordered
13
+ * chip with its grip icon; `'rung'` is a quieter translucent bar with no
14
+ * icon, for edges that should read as barely there. Either way the divider
15
+ * keeps its full 24px hit target.
16
+ */
17
+ withHandle?: boolean | 'rung';
13
18
  /**
14
19
  * The divider's accessible name. It is a focusable control — arrow keys move
15
20
  * the split — so it needs one; without it a screen reader announces an
@@ -1 +1 @@
1
- {"version":3,"file":"resizable.d.ts","sourceRoot":"","sources":["../../../../src/components/ui/resizable/resizable.tsx"],"names":[],"mappings":"AAAA,OAAO,SAAS,MAAM,kBAAkB,CAAA;AAExC,OAAO,KAAK,EAAE,cAAc,EAAE,MAAM,UAAU,CAAA;AAuB9C,wBAAgB,mBAAmB,CAAC,KAAK,EAAE,cAAc,CAAC,OAAO,SAAS,CAAC,GAAG;IAAE,KAAK,CAAC,EAAE,MAAM,CAAA;CAAE,kCAa/F;AAgBD,wBAAgB,cAAc,CAAC,KAAK,EAAE,cAAc,CAAC,OAAO,SAAS,CAAC,KAAK,CAAC,GAAG;IAAE,KAAK,CAAC,EAAE,MAAM,CAAA;CAAE,kCAchG;AAED,MAAM,MAAM,oBAAoB,GAAG,cAAc,CAAC,OAAO,SAAS,CAAC,MAAM,CAAC,GAAG;IAC3E,KAAK,CAAC,EAAE,MAAM,CAAA;IACd,wDAAwD;IACxD,UAAU,CAAC,EAAE,OAAO,CAAA;IACpB;;;;OAIG;IACH,KAAK,CAAC,EAAE,MAAM,CAAA;CACf,CAAA;AAED,wBAAgB,eAAe,CAAC,KAAK,EAAE,oBAAoB,kCAgC1D"}
1
+ {"version":3,"file":"resizable.d.ts","sourceRoot":"","sources":["../../../../src/components/ui/resizable/resizable.tsx"],"names":[],"mappings":"AAAA,OAAO,SAAS,MAAM,kBAAkB,CAAA;AAExC,OAAO,KAAK,EAAE,cAAc,EAAE,MAAM,UAAU,CAAA;AAuB9C,wBAAgB,mBAAmB,CAAC,KAAK,EAAE,cAAc,CAAC,OAAO,SAAS,CAAC,GAAG;IAAE,KAAK,CAAC,EAAE,MAAM,CAAA;CAAE,kCAa/F;AAgBD,wBAAgB,cAAc,CAAC,KAAK,EAAE,cAAc,CAAC,OAAO,SAAS,CAAC,KAAK,CAAC,GAAG;IAAE,KAAK,CAAC,EAAE,MAAM,CAAA;CAAE,kCAchG;AAED,MAAM,MAAM,oBAAoB,GAAG,cAAc,CAAC,OAAO,SAAS,CAAC,MAAM,CAAC,GAAG;IAC3E,KAAK,CAAC,EAAE,MAAM,CAAA;IACd;;;;;OAKG;IACH,UAAU,CAAC,EAAE,OAAO,GAAG,MAAM,CAAA;IAC7B;;;;OAIG;IACH,KAAK,CAAC,EAAE,MAAM,CAAA;CACf,CAAA;AAED,wBAAgB,eAAe,CAAC,KAAK,EAAE,oBAAoB,kCAsC1D"}
@@ -4,7 +4,8 @@ import { GripVertical } from "lucide-solid";
4
4
  import { createContext, splitProps, useContext } from "solid-js";
5
5
  import Resizable from "@corvu/resizable";
6
6
  //#region src/components/ui/resizable/resizable.tsx
7
- var _tmpl$ = /*#__PURE__*/ template(`<div class="bg-border z-(--z-docked) flex h-4 w-2.5 items-center justify-center rounded-sm border border-border">`);
7
+ var _tmpl$ = /*#__PURE__*/ template(`<div data-slot=resizable-grip class="z-(--z-docked) h-11 w-1.5 flex-none rounded-full bg-border/55 group-data-[orientation=vertical]/resize:h-1.5 group-data-[orientation=vertical]/resize:w-11">`);
8
+ var _tmpl$2 = /*#__PURE__*/ template(`<div class="bg-border z-(--z-docked) flex h-4 w-2.5 items-center justify-center rounded-sm border border-border">`);
8
9
  /**
9
10
  * Resizable.
10
11
  *
@@ -75,13 +76,13 @@ function ResizableHandle(props) {
75
76
  return group.orientation() === "horizontal" ? "vertical" : "horizontal";
76
77
  },
77
78
  get ["class"]() {
78
- return cn("group/resize bg-border relative flex w-px shrink-0 items-center justify-center", "after:absolute after:inset-y-0 after:-inset-x-3 after:w-6", "transition-colors ease-out hover:bg-primary", "focus-visible:bg-primary focus-visible:outline-none", "data-[orientation=vertical]:h-px data-[orientation=vertical]:w-full", "data-[orientation=vertical]:after:inset-x-0 data-[orientation=vertical]:after:-inset-y-3 data-[orientation=vertical]:after:h-6 data-[orientation=vertical]:after:w-full", local.class);
79
+ return cn("group/resize bg-border relative flex w-px shrink-0 items-center justify-center", "after:absolute after:inset-y-0 after:-inset-x-3 after:w-6", "transition-colors ease-out", local.withHandle === "rung" ? "hover:bg-primary/45" : "hover:bg-primary", "focus-visible:bg-primary focus-visible:outline-none", "data-[orientation=vertical]:h-px data-[orientation=vertical]:w-full", "data-[orientation=vertical]:after:inset-x-0 data-[orientation=vertical]:after:-inset-y-3 data-[orientation=vertical]:after:h-6 data-[orientation=vertical]:after:w-full", local.class);
79
80
  }
80
81
  }, rest, { get children() {
81
- return memo(() => !!local.withHandle)() ? (() => {
82
- var _el$ = _tmpl$();
83
- insert(_el$, createComponent(GripVertical, { "class": "size-2.5 text-muted-foreground" }));
84
- return _el$;
82
+ return memo(() => local.withHandle === "rung")() ? _tmpl$() : memo(() => !!local.withHandle)() ? (() => {
83
+ var _el$2 = _tmpl$2();
84
+ insert(_el$2, createComponent(GripVertical, { "class": "size-2.5 text-muted-foreground" }));
85
+ return _el$2;
85
86
  })() : null;
86
87
  } }));
87
88
  }
@@ -1 +1 @@
1
- {"version":3,"file":"resizable.js","names":["Resizable","GripVertical","ComponentProps","createContext","splitProps","useContext","cn","GroupSizesContext","ResizablePanelGroup","props","class","local","rest","_$createComponent","Provider","value","initialSizes","undefined","sizes","children","_$mergeProps","remainingSize","left","reduce","total","size","length","ResizablePanel","Panel","group","contextId","groupHasSizes","initialSize","ResizableHandleProps","Handle","withHandle","label","ResizableHandle","aria-label","aria-orientation","orientation","_$memo","_el$","_tmpl$","_$insert","_$createComponent","_$mergeProps","_$memo"],"sources":["../../../../src/components/ui/resizable/resizable.tsx"],"sourcesContent":["import Resizable from '@corvu/resizable'\nimport { GripVertical } from 'lucide-solid'\nimport type { ComponentProps } from 'solid-js'\nimport { createContext, splitProps, useContext } from 'solid-js'\nimport { cn } from '#lib/utils'\n\n/**\n * Resizable.\n *\n * A split layout: panels the user can resize, with a handle between them. This\n * is the shape of every IDE-like surface — rail, file tree, editor, terminal —\n * and the reason it is a primitive rather than something each view improvises.\n *\n * corvu supplies the pointer capture, the min/max constraints and the keyboard\n * resizing, which is what makes a divider operable without a mouse. The handle\n * is a real focusable element with an accessible role, so a split pane can be\n * adjusted from the keyboard; a bare `cursor-col-resize` div cannot.\n */\n/**\n * Whether the group was given `initialSizes` or controlled `sizes`. Those are corvu's to apply, and a\n * panel's own `initialSize` overrides them — so an unsized panel must not invent\n * one when the group already has an answer.\n */\nconst GroupSizesContext = createContext<() => boolean>(() => false)\n\nexport function ResizablePanelGroup(props: ComponentProps<typeof Resizable> & { class?: string }) {\n const [local, rest] = splitProps(props, ['class'])\n\n return (\n <GroupSizesContext.Provider\n value={() => rest.initialSizes !== undefined || rest.sizes !== undefined}\n >\n <Resizable\n class={cn('flex size-full data-[orientation=vertical]:flex-col', local.class)}\n {...rest}\n />\n </GroupSizesContext.Provider>\n )\n}\n\n/**\n * The size an unsized panel registers with: whatever its earlier siblings left.\n *\n * corvu registers a panel without `initialSize` at a flat 50%, so `0.28` beside\n * an unsized panel summed to 78% and left a gap. Panels register in document\n * order, so at registration `sizes` holds exactly the panels before this one.\n * When nothing is left — a second unsized panel — it takes an equal share, and\n * corvu shrinks the earlier panels by that share to keep the total at 100%.\n */\nfunction remainingSize(sizes: readonly number[]): number {\n const left = 1 - sizes.reduce((total, size) => total + size, 0)\n return left > 0.001 ? left : 1 / (sizes.length + 1)\n}\n\nexport function ResizablePanel(props: ComponentProps<typeof Resizable.Panel> & { class?: string }) {\n const [local, rest] = splitProps(props, ['class', 'initialSize'])\n const group = Resizable.useContext(rest.contextId)\n const groupHasSizes = useContext(GroupSizesContext)\n\n return (\n <Resizable.Panel\n initialSize={\n local.initialSize ?? (groupHasSizes() ? undefined : remainingSize(group.sizes()))\n }\n class={cn('min-h-0 min-w-0 overflow-hidden', local.class)}\n {...rest}\n />\n )\n}\n\nexport type ResizableHandleProps = ComponentProps<typeof Resizable.Handle> & {\n class?: string\n /** Draw a visible grip in the middle of the divider. */\n withHandle?: boolean\n /**\n * The divider's accessible name. It is a focusable control — arrow keys move\n * the split — so it needs one; without it a screen reader announces an\n * unlabelled button between the two panels.\n */\n label?: string\n}\n\nexport function ResizableHandle(props: ResizableHandleProps) {\n const [local, rest] = splitProps(props, ['class', 'withHandle', 'label'])\n const group = Resizable.useContext(rest.contextId)\n\n return (\n <Resizable.Handle\n aria-label={local.label ?? 'Resize panels'}\n // A separator's orientation is the line's own, which runs across the\n // group: a row of panels is divided by a vertical line, a column by a\n // horizontal one. corvu reports the group's orientation instead.\n aria-orientation={group.orientation() === 'horizontal' ? 'vertical' : 'horizontal'}\n class={cn(\n 'group/resize bg-border relative flex w-px shrink-0 items-center justify-center',\n /* Widen the hit target without moving the visual line: the divider is\n a hairline, but a hairline is far too small to grab. 24px on the\n drag axis meets WCAG 2.5.8's minimum target. */\n 'after:absolute after:inset-y-0 after:-inset-x-3 after:w-6',\n 'transition-colors ease-out hover:bg-primary',\n 'focus-visible:bg-primary focus-visible:outline-none',\n 'data-[orientation=vertical]:h-px data-[orientation=vertical]:w-full',\n 'data-[orientation=vertical]:after:inset-x-0 data-[orientation=vertical]:after:-inset-y-3 data-[orientation=vertical]:after:h-6 data-[orientation=vertical]:after:w-full',\n local.class\n )}\n {...rest}\n >\n {local.withHandle ? (\n <div class=\"bg-border z-(--z-docked) flex h-4 w-2.5 items-center justify-center rounded-sm border border-border\">\n <GripVertical class=\"size-2.5 text-muted-foreground\" />\n </div>\n ) : null}\n </Resizable.Handle>\n )\n}\n"],"mappings":";;;;;;;;;;;;;;;;;;;;;;;;AAuBA,IAAMO,oBAAoBJ,oBAAmC,KAAK;AAElE,SAAgBK,oBAAoBC,OAA8D;CAChG,MAAM,CAACE,OAAOC,QAAQR,WAAWK,OAAO,CAAC,OAAO,CAAC;CAEjD,OAAAI,gBACGN,kBAAkBO,UAAQ;EACzBC,aAAaH,KAAKI,iBAAiBC,KAAAA,KAAaL,KAAKM,UAAUD,KAAAA;EAAS,IAAAE,WAAA;GAAA,OAAAN,gBAEvEb,WAASoB,WAAA,EAAA,KAAA,WAAA;IAAA,OACDd,GAAG,uDAAuDK,MAAMD,KAAK;GAAC,EAAA,GACzEE,IAAI,CAAA;EAAA;CAAA,CAAA;AAIhB;;;;;;;;;;AAWA,SAASS,cAAcH,OAAkC;CACvD,MAAMI,OAAO,IAAIJ,MAAMK,QAAQC,OAAOC,SAASD,QAAQC,MAAM,CAAC;CAC9D,OAAOH,OAAO,OAAQA,OAAO,KAAKJ,MAAMQ,SAAS;AACnD;AAEA,SAAgBC,eAAelB,OAAoE;CACjG,MAAM,CAACE,OAAOC,QAAQR,WAAWK,OAAO,CAAC,SAAS,aAAa,CAAC;CAChE,MAAMoB,QAAQ7B,UAAUK,WAAWO,KAAKkB,SAAS;CACjD,MAAMC,gBAAgB1B,WAAWE,iBAAiB;CAElD,OAAAM,gBACGb,UAAU4B,OAAKR,WAAA;EAAA,IACdY,cAAW;GAAA,OACTrB,MAAMqB,gBAAgBD,cAAc,IAAId,KAAAA,IAAYI,cAAcQ,MAAMX,MAAM,CAAC;EAAE;EAAA,KAAA,WAAA;GAAA,OAE5EZ,GAAG,mCAAmCK,MAAMD,KAAK;EAAC;CAAA,GACrDE,IAAI,CAAA;AAGd;AAcA,SAAgByB,gBAAgB5B,OAA6B;CAC3D,MAAM,CAACE,OAAOC,QAAQR,WAAWK,OAAO;EAAC;EAAS;EAAc;CAAO,CAAC;CACxE,MAAMoB,QAAQ7B,UAAUK,WAAWO,KAAKkB,SAAS;CAEjD,OAAAjB,gBACGb,UAAUkC,QAAMd,WAAA;EAAA,KAAA,gBAAA;GAAA,OACHT,MAAMyB,SAAS;EAAe;EAAA,KAAA,sBAAA;GAAA,OAIxBP,MAAMW,YAAY,MAAM,eAAe,aAAa;EAAY;EAAA,KAAA,WAAA;GAAA,OAC3ElC,GACL,kFAIA,6DACA,+CACA,uDACA,uEACA,2KACAK,MAAMD,KACR;EAAC;CAAA,GACGE,MAAI,EAAA,IAAAO,WAAA;EAAA,OAEPsB,WAAA,CAAA,CAAA9B,MAAMwB,UAAU,CAAA,CAAA,WAAA;GAAA,IAAAO,OAAAC,OAAA;GAAAC,OAAAF,MAAA7B,gBAEZZ,cAAY,EAAA,SAAA,iCAAA,CAAA,CAAA;GAAA,OAAAyC;EAAA,EAAA,CAAA,IAEb;CAAI,EAAA,CAAA,CAAA;AAGd"}
1
+ {"version":3,"file":"resizable.js","names":["Resizable","GripVertical","ComponentProps","createContext","splitProps","useContext","cn","GroupSizesContext","ResizablePanelGroup","props","class","local","rest","_$createComponent","Provider","value","initialSizes","undefined","sizes","children","_$mergeProps","remainingSize","left","reduce","total","size","length","ResizablePanel","Panel","group","contextId","groupHasSizes","initialSize","ResizableHandleProps","Handle","withHandle","label","ResizableHandle","aria-label","aria-orientation","orientation","_$memo","_tmpl$","_el$2","_tmpl$2","_$insert","_$createComponent","_$mergeProps","_$memo"],"sources":["../../../../src/components/ui/resizable/resizable.tsx"],"sourcesContent":["import Resizable from '@corvu/resizable'\nimport { GripVertical } from 'lucide-solid'\nimport type { ComponentProps } from 'solid-js'\nimport { createContext, splitProps, useContext } from 'solid-js'\nimport { cn } from '#lib/utils'\n\n/**\n * Resizable.\n *\n * A split layout: panels the user can resize, with a handle between them. This\n * is the shape of every IDE-like surface — rail, file tree, editor, terminal —\n * and the reason it is a primitive rather than something each view improvises.\n *\n * corvu supplies the pointer capture, the min/max constraints and the keyboard\n * resizing, which is what makes a divider operable without a mouse. The handle\n * is a real focusable element with an accessible role, so a split pane can be\n * adjusted from the keyboard; a bare `cursor-col-resize` div cannot.\n */\n/**\n * Whether the group was given `initialSizes` or controlled `sizes`. Those are corvu's to apply, and a\n * panel's own `initialSize` overrides them — so an unsized panel must not invent\n * one when the group already has an answer.\n */\nconst GroupSizesContext = createContext<() => boolean>(() => false)\n\nexport function ResizablePanelGroup(props: ComponentProps<typeof Resizable> & { class?: string }) {\n const [local, rest] = splitProps(props, ['class'])\n\n return (\n <GroupSizesContext.Provider\n value={() => rest.initialSizes !== undefined || rest.sizes !== undefined}\n >\n <Resizable\n class={cn('flex size-full data-[orientation=vertical]:flex-col', local.class)}\n {...rest}\n />\n </GroupSizesContext.Provider>\n )\n}\n\n/**\n * The size an unsized panel registers with: whatever its earlier siblings left.\n *\n * corvu registers a panel without `initialSize` at a flat 50%, so `0.28` beside\n * an unsized panel summed to 78% and left a gap. Panels register in document\n * order, so at registration `sizes` holds exactly the panels before this one.\n * When nothing is left — a second unsized panel — it takes an equal share, and\n * corvu shrinks the earlier panels by that share to keep the total at 100%.\n */\nfunction remainingSize(sizes: readonly number[]): number {\n const left = 1 - sizes.reduce((total, size) => total + size, 0)\n return left > 0.001 ? left : 1 / (sizes.length + 1)\n}\n\nexport function ResizablePanel(props: ComponentProps<typeof Resizable.Panel> & { class?: string }) {\n const [local, rest] = splitProps(props, ['class', 'initialSize'])\n const group = Resizable.useContext(rest.contextId)\n const groupHasSizes = useContext(GroupSizesContext)\n\n return (\n <Resizable.Panel\n initialSize={\n local.initialSize ?? (groupHasSizes() ? undefined : remainingSize(group.sizes()))\n }\n class={cn('min-h-0 min-w-0 overflow-hidden', local.class)}\n {...rest}\n />\n )\n}\n\nexport type ResizableHandleProps = ComponentProps<typeof Resizable.Handle> & {\n class?: string\n /**\n * Draw a visible grip in the middle of the divider: `true` is the bordered\n * chip with its grip icon; `'rung'` is a quieter translucent bar with no\n * icon, for edges that should read as barely there. Either way the divider\n * keeps its full 24px hit target.\n */\n withHandle?: boolean | 'rung'\n /**\n * The divider's accessible name. It is a focusable control — arrow keys move\n * the split — so it needs one; without it a screen reader announces an\n * unlabelled button between the two panels.\n */\n label?: string\n}\n\nexport function ResizableHandle(props: ResizableHandleProps) {\n const [local, rest] = splitProps(props, ['class', 'withHandle', 'label'])\n const group = Resizable.useContext(rest.contextId)\n\n return (\n <Resizable.Handle\n aria-label={local.label ?? 'Resize panels'}\n // A separator's orientation is the line's own, which runs across the\n // group: a row of panels is divided by a vertical line, a column by a\n // horizontal one. corvu reports the group's orientation instead.\n aria-orientation={group.orientation() === 'horizontal' ? 'vertical' : 'horizontal'}\n class={cn(\n 'group/resize bg-border relative flex w-px shrink-0 items-center justify-center',\n /* Widen the hit target without moving the visual line: the divider is\n a hairline, but a hairline is far too small to grab. 24px on the\n drag axis meets WCAG 2.5.8's minimum target. */\n 'after:absolute after:inset-y-0 after:-inset-x-3 after:w-6',\n 'transition-colors ease-out',\n local.withHandle === 'rung' ? 'hover:bg-primary/45' : 'hover:bg-primary',\n 'focus-visible:bg-primary focus-visible:outline-none',\n 'data-[orientation=vertical]:h-px data-[orientation=vertical]:w-full',\n 'data-[orientation=vertical]:after:inset-x-0 data-[orientation=vertical]:after:-inset-y-3 data-[orientation=vertical]:after:h-6 data-[orientation=vertical]:after:w-full',\n local.class\n )}\n {...rest}\n >\n {local.withHandle === 'rung' ? (\n <div\n data-slot=\"resizable-grip\"\n class=\"z-(--z-docked) h-11 w-1.5 flex-none rounded-full bg-border/55 group-data-[orientation=vertical]/resize:h-1.5 group-data-[orientation=vertical]/resize:w-11\"\n />\n ) : local.withHandle ? (\n <div class=\"bg-border z-(--z-docked) flex h-4 w-2.5 items-center justify-center rounded-sm border border-border\">\n <GripVertical class=\"size-2.5 text-muted-foreground\" />\n </div>\n ) : null}\n </Resizable.Handle>\n )\n}\n"],"mappings":";;;;;;;;;;;;;;;;;;;;;;;;;AAuBA,IAAMO,oBAAoBJ,oBAAmC,KAAK;AAElE,SAAgBK,oBAAoBC,OAA8D;CAChG,MAAM,CAACE,OAAOC,QAAQR,WAAWK,OAAO,CAAC,OAAO,CAAC;CAEjD,OAAAI,gBACGN,kBAAkBO,UAAQ;EACzBC,aAAaH,KAAKI,iBAAiBC,KAAAA,KAAaL,KAAKM,UAAUD,KAAAA;EAAS,IAAAE,WAAA;GAAA,OAAAN,gBAEvEb,WAASoB,WAAA,EAAA,KAAA,WAAA;IAAA,OACDd,GAAG,uDAAuDK,MAAMD,KAAK;GAAC,EAAA,GACzEE,IAAI,CAAA;EAAA;CAAA,CAAA;AAIhB;;;;;;;;;;AAWA,SAASS,cAAcH,OAAkC;CACvD,MAAMI,OAAO,IAAIJ,MAAMK,QAAQC,OAAOC,SAASD,QAAQC,MAAM,CAAC;CAC9D,OAAOH,OAAO,OAAQA,OAAO,KAAKJ,MAAMQ,SAAS;AACnD;AAEA,SAAgBC,eAAelB,OAAoE;CACjG,MAAM,CAACE,OAAOC,QAAQR,WAAWK,OAAO,CAAC,SAAS,aAAa,CAAC;CAChE,MAAMoB,QAAQ7B,UAAUK,WAAWO,KAAKkB,SAAS;CACjD,MAAMC,gBAAgB1B,WAAWE,iBAAiB;CAElD,OAAAM,gBACGb,UAAU4B,OAAKR,WAAA;EAAA,IACdY,cAAW;GAAA,OACTrB,MAAMqB,gBAAgBD,cAAc,IAAId,KAAAA,IAAYI,cAAcQ,MAAMX,MAAM,CAAC;EAAE;EAAA,KAAA,WAAA;GAAA,OAE5EZ,GAAG,mCAAmCK,MAAMD,KAAK;EAAC;CAAA,GACrDE,IAAI,CAAA;AAGd;AAmBA,SAAgByB,gBAAgB5B,OAA6B;CAC3D,MAAM,CAACE,OAAOC,QAAQR,WAAWK,OAAO;EAAC;EAAS;EAAc;CAAO,CAAC;CACxE,MAAMoB,QAAQ7B,UAAUK,WAAWO,KAAKkB,SAAS;CAEjD,OAAAjB,gBACGb,UAAUkC,QAAMd,WAAA;EAAA,KAAA,gBAAA;GAAA,OACHT,MAAMyB,SAAS;EAAe;EAAA,KAAA,sBAAA;GAAA,OAIxBP,MAAMW,YAAY,MAAM,eAAe,aAAa;EAAY;EAAA,KAAA,WAAA;GAAA,OAC3ElC,GACL,kFAIA,6DACA,8BACAK,MAAMwB,eAAe,SAAS,wBAAwB,oBACtD,uDACA,uEACA,2KACAxB,MAAMD,KACR;EAAC;CAAA,GACGE,MAAI,EAAA,IAAAO,WAAA;EAAA,OAEPsB,WAAA9B,MAAMwB,eAAe,MAAM,CAAA,CAAA,IAAAO,OAAA,IAKxBD,WAAA,CAAA,CAAA9B,MAAMwB,UAAU,CAAA,CAAA,WAAA;GAAA,IAAAQ,QAAAC,QAAA;GAAAC,OAAAF,OAAA9B,gBAEfZ,cAAY,EAAA,SAAA,iCAAA,CAAA,CAAA;GAAA,OAAA0C;EAAA,EAAA,CAAA,IAEb;CAAI,EAAA,CAAA,CAAA;AAGd"}
@@ -87,6 +87,12 @@ export type TranscriptCompositionProps<T> = Omit<ComponentProps<'div'>, 'childre
87
87
  /** Optional controlled disclosure map keyed by `transcriptDisclosureKey`. */
88
88
  disclosure?: ReadonlyMap<string, boolean>
89
89
  onDisclosureChange?: (key: string, expanded: boolean) => void
90
+ /**
91
+ * Row rhythm. `compact` (default) packs rows 4px apart; `comfortable` spaces
92
+ * them 12px apart and stacks each row's rendered parts, for a chat stream
93
+ * whose rows are separate messages rather than one running log.
94
+ */
95
+ density?: 'compact' | 'comfortable'
90
96
  }
91
97
 
92
98
  type TurnPresentation = NonNullable<TranscriptCompositionRowContext['turn']>
@@ -388,6 +394,7 @@ function TranscriptRowEntry<T>(props: {
388
394
  <div
389
395
  id={id()}
390
396
  data-slot="transcript-row-content"
397
+ class="group-data-[density=comfortable]/transcript:flex group-data-[density=comfortable]/transcript:flex-col"
391
398
  hidden={collapsed()}
392
399
  aria-hidden={collapsed() || undefined}
393
400
  >
@@ -418,6 +425,7 @@ export function TranscriptComposition<T>(props: TranscriptCompositionProps<T>) {
418
425
  'foldMode',
419
426
  'foldState',
420
427
  'onFoldStateChange',
428
+ 'density',
421
429
  'disclosure',
422
430
  'onDisclosureChange',
423
431
  ])
@@ -512,7 +520,8 @@ export function TranscriptComposition<T>(props: TranscriptCompositionProps<T>) {
512
520
  <div
513
521
  data-slot="transcript-composition"
514
522
  data-fold-state={foldState()}
515
- class={cn('flex w-full min-w-0 flex-col gap-1', local.class)}
523
+ data-density={local.density ?? 'compact'}
524
+ class={cn('group/transcript flex w-full min-w-0 flex-col gap-1', local.class)}
516
525
  {...rest}
517
526
  >
518
527
  <Show when={local.onFoldStateChange}>
@@ -534,7 +543,10 @@ export function TranscriptComposition<T>(props: TranscriptCompositionProps<T>) {
534
543
  </Button>
535
544
  </div>
536
545
  </Show>
537
- <div data-slot="transcript-rows" class="flex min-w-0 flex-col gap-1">
546
+ <div
547
+ data-slot="transcript-rows"
548
+ class={cn('flex min-w-0 flex-col', local.density === 'comfortable' ? 'gap-3' : 'gap-1')}
549
+ >
538
550
  <For each={handles()}>
539
551
  {(handle) => (
540
552
  <TranscriptRowEntry
@@ -45,6 +45,8 @@ export type ContextualSidebarProps = {
45
45
  /** Pass the host's initial viewport seed to distinguish stale desktop state. */
46
46
  wideViewportAtLoad?: boolean
47
47
  resizeLabel?: string
48
+ /** The resize edge's grip: the default bordered chip, or the quieter rung. */
49
+ resizeGrip?: 'chip' | 'rung'
48
50
  /** Stable external opener used when the modal mobile sheet closes. */
49
51
  restoreFocusRef?: Accessor<HTMLElement | undefined>
50
52
  /** Called with the nav node so a host can project width onto its layout root. */
@@ -173,6 +175,7 @@ export function ContextualSidebar(props: ContextualSidebarProps) {
173
175
  maximum={props.maximum}
174
176
  step={props.step}
175
177
  label={resizeLabel()}
178
+ grip={props.resizeGrip}
176
179
  controls={navigationId}
177
180
  onChange={props.onWidthChange}
178
181
  onCommit={props.onWidthCommit}
@@ -18,7 +18,12 @@ export function MobileSidebar(props: MobileContextualSidebarProps) {
18
18
  <SheetContent
19
19
  side="start"
20
20
  aria-label={props.label}
21
- class={cn('gap-0 p-0', props.sheetClass)}
21
+ // The sheet leaves the app rail visible beside it: at most 19rem, never
22
+ // under 9rem, and otherwise the viewport less the rail's width.
23
+ class={cn(
24
+ 'w-[min(19rem,max(9rem,calc(100vw-var(--rail-width,3.5rem))))] max-w-[min(19rem,max(9rem,calc(100vw-var(--rail-width,3.5rem))))] gap-0 p-0',
25
+ props.sheetClass
26
+ )}
22
27
  restoreFocusRef={props.restoreFocusRef}
23
28
  >
24
29
  {props.renderSidebar()}
@@ -13,6 +13,8 @@ export type PixelResizeHandleProps = {
13
13
  label?: string
14
14
  controls?: string
15
15
  class?: string
16
+ /** The grip drawn on the edge: the default bordered chip, or the quieter rung. */
17
+ grip?: 'chip' | 'rung'
16
18
  onChange(value: number): void
17
19
  onCommit?(value: number): void
18
20
  }
@@ -93,7 +95,7 @@ export function PixelResizeHandle(props: PixelResizeHandleProps) {
93
95
  aria-hidden="true"
94
96
  />
95
97
  <ResizableHandle
96
- withHandle
98
+ withHandle={props.grip === 'rung' ? 'rung' : true}
97
99
  label={props.label ?? `Resize ${props.side} pane`}
98
100
  aria-controls={props.controls}
99
101
  aria-valuemin={minimum()}
@@ -70,8 +70,13 @@ export function ResizablePanel(props: ComponentProps<typeof Resizable.Panel> & {
70
70
 
71
71
  export type ResizableHandleProps = ComponentProps<typeof Resizable.Handle> & {
72
72
  class?: string
73
- /** Draw a visible grip in the middle of the divider. */
74
- withHandle?: boolean
73
+ /**
74
+ * Draw a visible grip in the middle of the divider: `true` is the bordered
75
+ * chip with its grip icon; `'rung'` is a quieter translucent bar with no
76
+ * icon, for edges that should read as barely there. Either way the divider
77
+ * keeps its full 24px hit target.
78
+ */
79
+ withHandle?: boolean | 'rung'
75
80
  /**
76
81
  * The divider's accessible name. It is a focusable control — arrow keys move
77
82
  * the split — so it needs one; without it a screen reader announces an
@@ -97,7 +102,8 @@ export function ResizableHandle(props: ResizableHandleProps) {
97
102
  a hairline, but a hairline is far too small to grab. 24px on the
98
103
  drag axis meets WCAG 2.5.8's minimum target. */
99
104
  'after:absolute after:inset-y-0 after:-inset-x-3 after:w-6',
100
- 'transition-colors ease-out hover:bg-primary',
105
+ 'transition-colors ease-out',
106
+ local.withHandle === 'rung' ? 'hover:bg-primary/45' : 'hover:bg-primary',
101
107
  'focus-visible:bg-primary focus-visible:outline-none',
102
108
  'data-[orientation=vertical]:h-px data-[orientation=vertical]:w-full',
103
109
  'data-[orientation=vertical]:after:inset-x-0 data-[orientation=vertical]:after:-inset-y-3 data-[orientation=vertical]:after:h-6 data-[orientation=vertical]:after:w-full',
@@ -105,7 +111,12 @@ export function ResizableHandle(props: ResizableHandleProps) {
105
111
  )}
106
112
  {...rest}
107
113
  >
108
- {local.withHandle ? (
114
+ {local.withHandle === 'rung' ? (
115
+ <div
116
+ data-slot="resizable-grip"
117
+ class="z-(--z-docked) h-11 w-1.5 flex-none rounded-full bg-border/55 group-data-[orientation=vertical]/resize:h-1.5 group-data-[orientation=vertical]/resize:w-11"
118
+ />
119
+ ) : local.withHandle ? (
109
120
  <div class="bg-border z-(--z-docked) flex h-4 w-2.5 items-center justify-center rounded-sm border border-border">
110
121
  <GripVertical class="size-2.5 text-muted-foreground" />
111
122
  </div>
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@adea-ai/ui",
3
- "version": "0.116.0",
3
+ "version": "0.117.0",
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",
@@ -87,6 +87,12 @@ export type TranscriptCompositionProps<T> = Omit<ComponentProps<'div'>, 'childre
87
87
  /** Optional controlled disclosure map keyed by `transcriptDisclosureKey`. */
88
88
  disclosure?: ReadonlyMap<string, boolean>
89
89
  onDisclosureChange?: (key: string, expanded: boolean) => void
90
+ /**
91
+ * Row rhythm. `compact` (default) packs rows 4px apart; `comfortable` spaces
92
+ * them 12px apart and stacks each row's rendered parts, for a chat stream
93
+ * whose rows are separate messages rather than one running log.
94
+ */
95
+ density?: 'compact' | 'comfortable'
90
96
  }
91
97
 
92
98
  type TurnPresentation = NonNullable<TranscriptCompositionRowContext['turn']>
@@ -388,6 +394,7 @@ function TranscriptRowEntry<T>(props: {
388
394
  <div
389
395
  id={id()}
390
396
  data-slot="transcript-row-content"
397
+ class="group-data-[density=comfortable]/transcript:flex group-data-[density=comfortable]/transcript:flex-col"
391
398
  hidden={collapsed()}
392
399
  aria-hidden={collapsed() || undefined}
393
400
  >
@@ -418,6 +425,7 @@ export function TranscriptComposition<T>(props: TranscriptCompositionProps<T>) {
418
425
  'foldMode',
419
426
  'foldState',
420
427
  'onFoldStateChange',
428
+ 'density',
421
429
  'disclosure',
422
430
  'onDisclosureChange',
423
431
  ])
@@ -512,7 +520,8 @@ export function TranscriptComposition<T>(props: TranscriptCompositionProps<T>) {
512
520
  <div
513
521
  data-slot="transcript-composition"
514
522
  data-fold-state={foldState()}
515
- class={cn('flex w-full min-w-0 flex-col gap-1', local.class)}
523
+ data-density={local.density ?? 'compact'}
524
+ class={cn('group/transcript flex w-full min-w-0 flex-col gap-1', local.class)}
516
525
  {...rest}
517
526
  >
518
527
  <Show when={local.onFoldStateChange}>
@@ -534,7 +543,10 @@ export function TranscriptComposition<T>(props: TranscriptCompositionProps<T>) {
534
543
  </Button>
535
544
  </div>
536
545
  </Show>
537
- <div data-slot="transcript-rows" class="flex min-w-0 flex-col gap-1">
546
+ <div
547
+ data-slot="transcript-rows"
548
+ class={cn('flex min-w-0 flex-col', local.density === 'comfortable' ? 'gap-3' : 'gap-1')}
549
+ >
538
550
  <For each={handles()}>
539
551
  {(handle) => (
540
552
  <TranscriptRowEntry
@@ -45,6 +45,8 @@ export type ContextualSidebarProps = {
45
45
  /** Pass the host's initial viewport seed to distinguish stale desktop state. */
46
46
  wideViewportAtLoad?: boolean
47
47
  resizeLabel?: string
48
+ /** The resize edge's grip: the default bordered chip, or the quieter rung. */
49
+ resizeGrip?: 'chip' | 'rung'
48
50
  /** Stable external opener used when the modal mobile sheet closes. */
49
51
  restoreFocusRef?: Accessor<HTMLElement | undefined>
50
52
  /** Called with the nav node so a host can project width onto its layout root. */
@@ -173,6 +175,7 @@ export function ContextualSidebar(props: ContextualSidebarProps) {
173
175
  maximum={props.maximum}
174
176
  step={props.step}
175
177
  label={resizeLabel()}
178
+ grip={props.resizeGrip}
176
179
  controls={navigationId}
177
180
  onChange={props.onWidthChange}
178
181
  onCommit={props.onWidthCommit}
@@ -18,7 +18,12 @@ export function MobileSidebar(props: MobileContextualSidebarProps) {
18
18
  <SheetContent
19
19
  side="start"
20
20
  aria-label={props.label}
21
- class={cn('gap-0 p-0', props.sheetClass)}
21
+ // The sheet leaves the app rail visible beside it: at most 19rem, never
22
+ // under 9rem, and otherwise the viewport less the rail's width.
23
+ class={cn(
24
+ 'w-[min(19rem,max(9rem,calc(100vw-var(--rail-width,3.5rem))))] max-w-[min(19rem,max(9rem,calc(100vw-var(--rail-width,3.5rem))))] gap-0 p-0',
25
+ props.sheetClass
26
+ )}
22
27
  restoreFocusRef={props.restoreFocusRef}
23
28
  >
24
29
  {props.renderSidebar()}
@@ -13,6 +13,8 @@ export type PixelResizeHandleProps = {
13
13
  label?: string
14
14
  controls?: string
15
15
  class?: string
16
+ /** The grip drawn on the edge: the default bordered chip, or the quieter rung. */
17
+ grip?: 'chip' | 'rung'
16
18
  onChange(value: number): void
17
19
  onCommit?(value: number): void
18
20
  }
@@ -93,7 +95,7 @@ export function PixelResizeHandle(props: PixelResizeHandleProps) {
93
95
  aria-hidden="true"
94
96
  />
95
97
  <ResizableHandle
96
- withHandle
98
+ withHandle={props.grip === 'rung' ? 'rung' : true}
97
99
  label={props.label ?? `Resize ${props.side} pane`}
98
100
  aria-controls={props.controls}
99
101
  aria-valuemin={minimum()}
@@ -70,8 +70,13 @@ export function ResizablePanel(props: ComponentProps<typeof Resizable.Panel> & {
70
70
 
71
71
  export type ResizableHandleProps = ComponentProps<typeof Resizable.Handle> & {
72
72
  class?: string
73
- /** Draw a visible grip in the middle of the divider. */
74
- withHandle?: boolean
73
+ /**
74
+ * Draw a visible grip in the middle of the divider: `true` is the bordered
75
+ * chip with its grip icon; `'rung'` is a quieter translucent bar with no
76
+ * icon, for edges that should read as barely there. Either way the divider
77
+ * keeps its full 24px hit target.
78
+ */
79
+ withHandle?: boolean | 'rung'
75
80
  /**
76
81
  * The divider's accessible name. It is a focusable control — arrow keys move
77
82
  * the split — so it needs one; without it a screen reader announces an
@@ -97,7 +102,8 @@ export function ResizableHandle(props: ResizableHandleProps) {
97
102
  a hairline, but a hairline is far too small to grab. 24px on the
98
103
  drag axis meets WCAG 2.5.8's minimum target. */
99
104
  'after:absolute after:inset-y-0 after:-inset-x-3 after:w-6',
100
- 'transition-colors ease-out hover:bg-primary',
105
+ 'transition-colors ease-out',
106
+ local.withHandle === 'rung' ? 'hover:bg-primary/45' : 'hover:bg-primary',
101
107
  'focus-visible:bg-primary focus-visible:outline-none',
102
108
  'data-[orientation=vertical]:h-px data-[orientation=vertical]:w-full',
103
109
  'data-[orientation=vertical]:after:inset-x-0 data-[orientation=vertical]:after:-inset-y-3 data-[orientation=vertical]:after:h-6 data-[orientation=vertical]:after:w-full',
@@ -105,7 +111,12 @@ export function ResizableHandle(props: ResizableHandleProps) {
105
111
  )}
106
112
  {...rest}
107
113
  >
108
- {local.withHandle ? (
114
+ {local.withHandle === 'rung' ? (
115
+ <div
116
+ data-slot="resizable-grip"
117
+ class="z-(--z-docked) h-11 w-1.5 flex-none rounded-full bg-border/55 group-data-[orientation=vertical]/resize:h-1.5 group-data-[orientation=vertical]/resize:w-11"
118
+ />
119
+ ) : local.withHandle ? (
109
120
  <div class="bg-border z-(--z-docked) flex h-4 w-2.5 items-center justify-center rounded-sm border border-border">
110
121
  <GripVertical class="size-2.5 text-muted-foreground" />
111
122
  </div>