@lovett/ui 0.0.11 → 0.1.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.
- package/dist/chunk-RBYWGBQ2.js +2752 -0
- package/dist/chunk-RBYWGBQ2.js.map +1 -0
- package/dist/index.d.ts +5402 -71
- package/dist/index.js +21992 -11618
- package/dist/index.js.map +1 -1
- package/dist/rich-composer-impl-5NO443A6.js +1859 -0
- package/dist/rich-composer-impl-5NO443A6.js.map +1 -0
- package/dist/styles.css +1570 -0
- package/dist/tokens.css +112 -0
- package/package.json +8 -1
- package/src/__tests__/avatar.test.tsx +272 -0
- package/src/__tests__/bar-chart.test.tsx +809 -0
- package/src/__tests__/board.test.tsx +420 -0
- package/src/__tests__/chart-math.test.ts +922 -0
- package/src/__tests__/chart-series.test.ts +339 -0
- package/src/__tests__/code-block.test.tsx +134 -0
- package/src/__tests__/display-popover.test.tsx +195 -0
- package/src/__tests__/display-store.test.tsx +208 -0
- package/src/__tests__/donut-chart.test.tsx +397 -0
- package/src/__tests__/dropdown-menu.test.tsx +156 -2
- package/src/__tests__/filter-menu.test.tsx +175 -0
- package/src/__tests__/gauge-ring.test.tsx +233 -0
- package/src/__tests__/line-chart.test.tsx +612 -0
- package/src/__tests__/ranked-bars.test.tsx +343 -0
- package/src/__tests__/remark-underline.test.ts +194 -0
- package/src/__tests__/sparkline.test.tsx +368 -0
- package/src/__tests__/stat-layer.test.tsx +271 -0
- package/src/__tests__/stat-strip.test.tsx +175 -0
- package/src/__tests__/status.test.tsx +293 -0
- package/src/__tests__/tabs.test.tsx +303 -0
- package/src/__tests__/token-shape.test.ts +132 -2
- package/src/avatar.tsx +352 -0
- package/src/bar-chart.tsx +1214 -0
- package/src/board.tsx +658 -0
- package/src/chart-frame.tsx +960 -0
- package/src/chart-legend.tsx +304 -0
- package/src/chart-tooltip.tsx +267 -0
- package/src/code-block.tsx +62 -8
- package/src/delta-chip.tsx +263 -0
- package/src/detail/__tests__/activity-pane.test.tsx +186 -0
- package/src/detail/__tests__/detail-chrome.test.tsx +134 -0
- package/src/detail/__tests__/detail-surface.test.tsx +529 -0
- package/src/detail/__tests__/field-row.test.tsx +357 -0
- package/src/detail/activity-pane.tsx +507 -0
- package/src/detail/calendar.tsx +355 -0
- package/src/detail/detail-divider.tsx +261 -0
- package/src/detail/detail-header.tsx +287 -0
- package/src/detail/detail-menu.tsx +254 -0
- package/src/detail/detail-surface.tsx +1110 -0
- package/src/detail/field-list.tsx +196 -0
- package/src/detail/field-row.tsx +1131 -0
- package/src/detail/index.ts +58 -0
- package/src/detail/segmented-choice.tsx +94 -0
- package/src/detail/types.ts +129 -0
- package/src/display-popover.tsx +487 -0
- package/src/display-store.tsx +242 -0
- package/src/donut-chart.tsx +988 -0
- package/src/dropdown-menu.tsx +290 -19
- package/src/filter-core/EXPORTS.md +85 -0
- package/src/filter-core/__tests__/columns.test.ts +159 -0
- package/src/filter-core/__tests__/faceting.test.ts +193 -0
- package/src/filter-core/__tests__/filter-fns.test.ts +519 -0
- package/src/filter-core/__tests__/operators.test.ts +235 -0
- package/src/filter-core/__tests__/state.test.ts +268 -0
- package/src/filter-core/__tests__/url.test.ts +350 -0
- package/src/filter-core/columns.ts +134 -0
- package/src/filter-core/date-utils.ts +38 -0
- package/src/filter-core/examples/task-filter-columns.ts +121 -0
- package/src/filter-core/faceting.ts +120 -0
- package/src/filter-core/filter-fns.ts +335 -0
- package/src/filter-core/index.ts +105 -0
- package/src/filter-core/operators.ts +433 -0
- package/src/filter-core/state.ts +280 -0
- package/src/filter-core/types.ts +247 -0
- package/src/filter-core/url.ts +261 -0
- package/src/filter-dropdown.tsx +12 -0
- package/src/filter-menu.tsx +649 -0
- package/src/floating-drawer.tsx +19 -1
- package/src/gauge-ring.tsx +435 -0
- package/src/hue.ts +52 -0
- package/src/index.ts +296 -0
- package/src/kbd.tsx +27 -4
- package/src/lib/chart.ts +866 -0
- package/src/lib/focus.ts +43 -1
- package/src/lib/layer-stack.ts +30 -3
- package/src/lib/remark-underline.ts +443 -0
- package/src/lib/series.ts +169 -0
- package/src/line-chart.tsx +1176 -0
- package/src/markdown.tsx +26 -7
- package/src/modal.tsx +42 -18
- package/src/progress-ledger.tsx +304 -0
- package/src/ranked-bars.tsx +386 -0
- package/src/segmented-pill.tsx +32 -9
- package/src/sortable.tsx +315 -1
- package/src/sparkline.tsx +416 -0
- package/src/stat-card.tsx +376 -0
- package/src/stat-strip.tsx +327 -0
- package/src/status.tsx +215 -0
- package/src/styles.css +1570 -0
- package/src/tabs.tsx +206 -25
- package/src/task-card.tsx +610 -0
- package/src/thread/__tests__/comment-body-hostile.test.tsx +331 -0
- package/src/thread/__tests__/comment-tree.test.ts +151 -0
- package/src/thread/__tests__/emoji.test.ts +187 -0
- package/src/thread/__tests__/fixtures/thread-fixture.ts +235 -0
- package/src/thread/__tests__/link-preview-source.test.ts +120 -0
- package/src/thread/__tests__/link-preview.test.tsx +600 -0
- package/src/thread/__tests__/markdown-format.test.ts +82 -0
- package/src/thread/__tests__/markdown-spec.test.ts +469 -0
- package/src/thread/__tests__/relative-time.test.ts +71 -0
- package/src/thread/__tests__/rich-composer.test.tsx +799 -0
- package/src/thread/__tests__/scroll-caret.test.ts +58 -0
- package/src/thread/__tests__/suggestion-list.test.tsx +648 -0
- package/src/thread/__tests__/thread-scroll-ownership.test.tsx +88 -0
- package/src/thread/__tests__/thread.test.tsx +662 -0
- package/src/thread/__tests__/use-attachments.test.tsx +679 -0
- package/src/thread/actions.tsx +196 -0
- package/src/thread/attachments.tsx +1071 -0
- package/src/thread/comment-body.tsx +148 -0
- package/src/thread/comment-tree.ts +182 -0
- package/src/thread/comment.tsx +915 -0
- package/src/thread/composer-footer.tsx +125 -0
- package/src/thread/composer.tsx +319 -0
- package/src/thread/emoji.ts +283 -0
- package/src/thread/index.ts +153 -0
- package/src/thread/link-preview.tsx +341 -0
- package/src/thread/markdown-format.ts +155 -0
- package/src/thread/markdown-spec.ts +754 -0
- package/src/thread/rail.tsx +372 -0
- package/src/thread/reactions.tsx +415 -0
- package/src/thread/relative-time.tsx +94 -0
- package/src/thread/rich-composer-impl.tsx +1601 -0
- package/src/thread/rich-composer.tsx +195 -0
- package/src/thread/scroll-caret.ts +37 -0
- package/src/thread/suggestion-list.tsx +182 -0
- package/src/thread/thread.tsx +718 -0
- package/src/thread/types.ts +218 -0
- package/src/thread/use-attachments.ts +598 -0
- package/src/thread/use-now.ts +73 -0
- package/src/thread/use-thread.ts +316 -0
- package/src/tokens.css +112 -0
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"sources":["../src/lib/utils.ts","../src/button.tsx","../src/input.tsx","../src/lib/layer-stack.ts","../src/lib/anchor.ts","../src/lib/refs.ts","../src/lib/focus.ts","../src/popover.tsx","../src/code-block.tsx","../src/lib/remark-underline.ts","../src/markdown.tsx","../src/kbd.tsx","../src/thread/comment-body.tsx","../src/thread/composer-footer.tsx","../src/thread/markdown-format.ts","../src/thread/composer.tsx","../src/thread/use-attachments.ts","../src/thread/attachments.tsx","../src/thread/rich-composer.tsx"],"names":["Button","SIZE_CLASS","forwardRef","Input","jsxs","side","useRef","useState","useEffect","useCallback","useMemo","jsx","PopoverTrigger","PopoverContent","SyntaxHighlighter","createContext","useContext","ReactMarkdown","Fragment","LinkIcon","useLayoutEffect","ImageIcon","useId"],"mappings":"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","file":"chunk-RBYWGBQ2.js","sourcesContent":["import { clsx, type ClassValue } from 'clsx'\nimport { twMerge } from 'tailwind-merge'\n\nexport function cn(...inputs: ClassValue[]) {\n return twMerge(clsx(inputs))\n}\n","/**\n * Button — typed primitive over the .btn CSS classes in styles.css.\n *\n * variants: primary | secondary | outline | ghost | destructive |\n * destructive-soft | icon | toolbar\n * sizes: sm (32) | md (40) — default | lg (48)\n * shape: default | circle (use with variant=\"icon\" — ADR-026 D3)\n * states: loading, disabled — both forwarded to the CSS class\n */\nimport { forwardRef, type ButtonHTMLAttributes, type ReactNode } from 'react'\nimport { cn } from './lib/utils'\n\nexport type ButtonVariant =\n | 'primary'\n | 'secondary'\n | 'outline'\n | 'ghost'\n | 'destructive'\n | 'destructive-soft'\n | 'icon'\n | 'toolbar'\n\nexport type ButtonSize = 'sm' | 'md' | 'lg'\n\nexport type ButtonShape = 'default' | 'circle'\n\nconst VARIANT_CLASS: Record<ButtonVariant, string> = {\n primary: 'btn-primary',\n secondary: 'btn-secondary',\n outline: 'btn-outline',\n ghost: 'btn-ghost',\n destructive: 'btn-destructive',\n 'destructive-soft': 'btn-destructive-soft',\n icon: 'btn-icon',\n toolbar: 'btn-toolbar',\n}\n\nconst SIZE_CLASS: Record<ButtonSize, string> = {\n sm: 'size-sm',\n md: '',\n lg: 'size-lg',\n}\n\nexport interface ButtonProps extends ButtonHTMLAttributes<HTMLButtonElement> {\n variant?: ButtonVariant\n size?: ButtonSize\n /** ADR-026 D3 — `circle` only takes effect when `variant=\"icon\"`. */\n shape?: ButtonShape\n /** Show the loading spinner overlay; auto-disables the button. */\n loading?: boolean\n /** Optional left-side icon. Forces icon-text gap from .btn. */\n leadingIcon?: ReactNode\n /** Optional right-side icon. */\n trailingIcon?: ReactNode\n}\n\nexport const Button = forwardRef<HTMLButtonElement, ButtonProps>(function Button(\n {\n variant = 'primary',\n size = 'md',\n shape = 'default',\n loading,\n leadingIcon,\n trailingIcon,\n disabled,\n className,\n children,\n type = 'button',\n ...rest\n },\n ref,\n) {\n return (\n <button\n ref={ref}\n type={type}\n disabled={disabled || loading}\n className={cn(\n 'btn',\n VARIANT_CLASS[variant],\n SIZE_CLASS[size],\n shape === 'circle' && variant === 'icon' && 'is-circle',\n loading && 'is-loading',\n className,\n )}\n {...rest}\n >\n {leadingIcon}\n {children}\n {trailingIcon}\n </button>\n )\n})\n","/**\n * Input — typed text input wrapped in the .input-shell from styles.css.\n * Supports leading/trailing affixes (icon, badge, action button), three\n * sizes (sm 32 / md 40 / lg 48), and the standard error/disabled states.\n *\n * <Input value={v} onChange={e => setV(e.target.value)} placeholder=\"Search…\" />\n *\n * <Input\n * leadingAffix={<Search className=\"h-4 w-4\" />}\n * trailingAffix={<KeyboardShortcut keys=\"⌘K\" />}\n * placeholder=\"Type to search\"\n * />\n *\n * <Input error placeholder=\"Invalid\" />\n *\n * <Input\n * type=\"password\"\n * showPasswordToggle\n * autoComplete=\"current-password\"\n * />\n */\nimport {\n forwardRef,\n useState,\n type InputHTMLAttributes,\n type ReactNode,\n} from 'react'\nimport { Eye, EyeOff } from 'lucide-react'\nimport { cn } from './lib/utils'\n\nexport type InputSize = 'sm' | 'md' | 'lg'\n\nexport interface InputProps extends Omit<InputHTMLAttributes<HTMLInputElement>, 'size' | 'prefix'> {\n inputSize?: InputSize\n error?: boolean\n /** Element rendered before the input — typically an icon. Static, no interaction. */\n leadingAffix?: ReactNode\n /** Element rendered after the input. Pass an `<button class=\"affix action\">` for clickable. */\n trailingAffix?: ReactNode\n /** Override classes on the .input-shell wrapper. */\n shellClassName?: string\n /**\n * Show/hide affordance for `type=\"password\"`. Manages visibility state\n * internally and renders an Eye/EyeOff toggle in the trailing affix slot.\n * No-op when `type !== \"password\"`. Caller-supplied `trailingAffix`\n * wins — the toggle is only injected when the slot is otherwise empty.\n */\n showPasswordToggle?: boolean\n /**\n * Numeric variant (ADR-076 D8) — renders the field in the monospace\n * face with `tabular-nums` so digits align as the value changes.\n * Pair with the existing `leadingAffix` (e.g. a `$`) / `trailingAffix`\n * (e.g. a unit suffix) for calculator inputs. No new prefix/suffix\n * props — affixes are the canonical adornment slots.\n */\n numeric?: boolean\n}\n\nconst SIZE_CLASS: Record<InputSize, string> = {\n sm: 'size-sm',\n md: '',\n lg: 'size-lg',\n}\n\nexport const Input = forwardRef<HTMLInputElement, InputProps>(function Input(\n {\n inputSize = 'md',\n error,\n leadingAffix,\n trailingAffix,\n shellClassName,\n className,\n disabled,\n type,\n showPasswordToggle,\n numeric,\n ...rest\n },\n ref,\n) {\n const [revealed, setRevealed] = useState(false)\n const isPasswordToggle =\n showPasswordToggle === true && type === 'password' && !trailingAffix\n const resolvedType = isPasswordToggle && revealed ? 'text' : type\n const resolvedTrailingAffix = isPasswordToggle ? (\n <button\n type=\"button\"\n onClick={() => setRevealed((v) => !v)}\n aria-label={revealed ? 'Hide password' : 'Show password'}\n aria-pressed={revealed}\n className=\"affix action\"\n tabIndex={-1}\n >\n {revealed ? (\n <EyeOff className=\"h-4 w-4\" aria-hidden />\n ) : (\n <Eye className=\"h-4 w-4\" aria-hidden />\n )}\n </button>\n ) : (\n trailingAffix\n )\n\n return (\n <div\n className={cn(\n 'input-shell',\n SIZE_CLASS[inputSize],\n numeric && 'is-numeric',\n leadingAffix && 'has-leading',\n resolvedTrailingAffix && 'has-trailing',\n error && 'is-error',\n disabled && 'is-disabled',\n shellClassName,\n )}\n >\n {leadingAffix && <span className=\"affix\">{leadingAffix}</span>}\n <input\n ref={ref}\n type={resolvedType}\n disabled={disabled}\n className={className}\n {...rest}\n />\n {resolvedTrailingAffix && (\n <span className=\"affix\">{resolvedTrailingAffix}</span>\n )}\n </div>\n )\n})\n","/**\n * Dismiss-layer stack — the ONE \"topmost layer wins\" registry shared by\n * Modal, DropdownMenu and Popover (and, next, ContextMenu / Select /\n * Combobox / Tooltip / CommandPalette).\n *\n * Extracted from modal.tsx's module-level `openPanels` array so every\n * dismissable surface participates in the same order. Before this, a\n * DropdownMenu opened from inside a Modal answered Escape at the same time\n * the Modal did — two document listeners, one keypress, both closed. Now a\n * single document `keydown` listener dispatches Escape to the top of the\n * stack ONLY, then stops propagation so window-level handlers (the chat\n * conversation drawer's Escape, lens hotkey maps) do not treat a consumed\n * Escape as theirs — which is what DropdownMenu's own listener already did.\n *\n * Promoted per ADR-0030 Decision G (meta-ads-audit-dashboard task manager:\n * every picker, sheet and palette needs one dismiss order). First consumer\n * is the workspace app: Modal (51 files), DropdownMenu (137 call sites) and\n * Popover all register here.\n *\n * Two kinds. A `modal` layer also owns a focus trap, and that trap must not\n * switch off because a `popover` opened above it — so Modal asks\n * `isTopOfKind()` for Tab handling while Escape always goes to `isTop()`.\n * Order is push order, which under React is effect order: a surface that\n * mounts or opens later sits above one that opened earlier.\n *\n * Usage (a dismissable surface):\n *\n * const layer = useLayer({\n * enabled: open,\n * kind: 'popover',\n * elementRef: contentRef,\n * onEscape: () => setOpen(false),\n * })\n * useOutsideClick([triggerRef, contentRef], () => setOpen(false), {\n * enabled: open,\n * layer, // clicks inside a layer stacked ABOVE this one are not \"outside\"\n * })\n *\n * `useEscapeKey(handler, { enabled })` is the one-liner for anything that\n * only needs Escape.\n */\n\nimport { useEffect, useMemo, useRef, type RefObject } from 'react'\n\nexport type LayerKind = 'modal' | 'popover'\n\nexport interface LayerHandle {\n /** True while no layer of ANY kind sits above this one. */\n isTop(): boolean\n /** True while no layer of the SAME kind sits above this one. */\n isTopOfKind(): boolean\n /**\n * True when `node` is inside the element of a layer stacked above this\n * one — a nested Select's listbox, a Combobox inside a Popover. Outside-\n * click handlers treat those as inside.\n */\n containsInLayerAbove(node: Node): boolean\n}\n\ninterface LayerRecord {\n /**\n * MUTABLE, and the one field that is.\n *\n * A surface whose kind CHANGES while it is open must not lose its place in\n * the stack over it. The item detail is the case that found this: its three\n * modes are one element tree, and `panel` is non-modal while `full` and\n * `modal` are, so switching mode flips this from 'modal' to 'popover'. When\n * `kind` was an effect dependency, that flip popped and re-pushed the\n * layer — landing the detail ABOVE a dropdown menu that was already open,\n * so the next Escape closed the whole detail instead of the menu inside it.\n * (Switching mode is done FROM that menu, so it was the common path, not an\n * edge case.)\n *\n * Updating in place keeps push order meaning what it says: the order things\n * OPENED, not the order they last changed shape.\n */\n kind: LayerKind\n readonly element: () => HTMLElement | null\n readonly onEscape: (event: KeyboardEvent) => void\n}\n\nconst stack: LayerRecord[] = []\nlet listening = false\n\nfunction onDocumentKeyDown(event: KeyboardEvent): void {\n if (event.key !== 'Escape') return\n const top = stack[stack.length - 1]\n if (!top) return\n // Consumed here. Window-level listeners (hotkey maps, drawers) must not\n // see an Escape that closed a layer — same contract DropdownMenu's own\n // listener had before the stack existed.\n event.stopPropagation()\n top.onEscape(event)\n}\n\nfunction pushLayer(record: LayerRecord): () => void {\n stack.push(record)\n if (!listening) {\n document.addEventListener('keydown', onDocumentKeyDown)\n listening = true\n }\n return () => {\n const at = stack.lastIndexOf(record)\n if (at !== -1) stack.splice(at, 1)\n if (stack.length === 0 && listening) {\n document.removeEventListener('keydown', onDocumentKeyDown)\n listening = false\n }\n }\n}\n\nexport interface UseLayerOptions {\n /** Register while true; pop when it turns false or the owner unmounts. */\n enabled: boolean\n kind: LayerKind\n /**\n * The surface's root element. Read lazily, so a ref that is filled in\n * after the layer registers (portal content) still resolves.\n */\n elementRef?: RefObject<HTMLElement | null>\n /** Called when this layer is topmost and Escape is pressed. */\n onEscape: (event: KeyboardEvent) => void\n}\n\n/**\n * Register a dismiss layer for as long as `enabled` holds. `onEscape` is\n * read through a ref, so an inline arrow does not re-register the layer\n * (and does not reorder it) on every render.\n */\nexport function useLayer(options: UseLayerOptions): LayerHandle {\n const { enabled, kind, elementRef, onEscape } = options\n\n const onEscapeRef = useRef(onEscape)\n useEffect(() => {\n onEscapeRef.current = onEscape\n })\n\n // Read through a ref for the same reason `onEscape` is: so that changing it\n // updates the layer rather than reordering the stack. See `LayerRecord.kind`.\n const kindRef = useRef(kind)\n kindRef.current = kind\n\n const recordRef = useRef<LayerRecord | null>(null)\n\n useEffect(() => {\n if (!enabled) return\n const record: LayerRecord = {\n kind: kindRef.current,\n element: () => elementRef?.current ?? null,\n onEscape: (event) => onEscapeRef.current(event),\n }\n recordRef.current = record\n const pop = pushLayer(record)\n return () => {\n pop()\n if (recordRef.current === record) recordRef.current = null\n }\n }, [enabled, elementRef])\n\n // A kind change updates the record IN PLACE, keeping its position.\n useEffect(() => {\n const record = recordRef.current\n if (record !== null) record.kind = kind\n }, [kind])\n\n return useMemo<LayerHandle>(\n () => ({\n isTop: () => {\n const record = recordRef.current\n return record !== null && stack[stack.length - 1] === record\n },\n isTopOfKind: () => {\n const record = recordRef.current\n if (!record) return false\n for (let i = stack.length - 1; i >= 0; i--) {\n const layer = stack[i]\n if (layer === record) return true\n if (layer?.kind === record.kind) return false\n }\n return false\n },\n containsInLayerAbove: (node) => {\n const record = recordRef.current\n if (!record) return false\n const at = stack.indexOf(record)\n if (at === -1) return false\n for (let i = at + 1; i < stack.length; i++) {\n if (stack[i]?.element()?.contains(node)) return true\n }\n return false\n },\n }),\n [],\n )\n}\n\nexport interface UseEscapeKeyOptions {\n /** Default true. */\n enabled?: boolean\n /** Default `popover`. */\n kind?: LayerKind\n}\n\n/**\n * Escape-only participant in the layer stack. Fires `onEscape` only while\n * this is the topmost layer; a layer that opens later takes over until it\n * closes.\n */\nexport function useEscapeKey(\n onEscape: (event: KeyboardEvent) => void,\n options: UseEscapeKeyOptions = {},\n): LayerHandle {\n const { enabled = true, kind = 'popover' } = options\n return useLayer({ enabled, kind, onEscape })\n}\n","/**\n * Anchored positioning — the ONE measure / flip / clamp routine behind every\n * floating surface in @lovett/ui.\n *\n * Four primitives (DropdownMenu, FilterDropdown, FolderTreePicker,\n * TagChipInput) each hand-rolled the same `useLayoutEffect` +\n * `getBoundingClientRect` + clamp + resize/scroll-listener block, with four\n * slightly different gaps: no flip at a viewport edge; no clamp; measuring in\n * a passive effect so the first paint was wrong; `top`/`bottom` only. This\n * module is the single implementation. DropdownMenu is rebuilt on it in the\n * same change; the other three keep their local copies for now (follow-up).\n *\n * Promoted per ADR-0030 Decision G (meta-ads-audit-dashboard task manager)\n * with the workspace app as the first consumer — DropdownMenu and Popover\n * position through this hook, so every menu in the app is on it. Select /\n * Combobox / Tooltip / ContextMenu build on it next.\n *\n * No Floating UI, no Popper (CLAUDE.md §1 allowed deps). Three pieces:\n * • `computeAnchoredPosition` — pure math, unit-tested without a DOM.\n * • `useAnchoredPosition` — measures, positions, tracks resize / scroll /\n * size changes. Anchor is an element (`anchorRef`) OR a virtual rect\n * (`anchorRect`) — ContextMenu passes the right-click point as\n * `{ left: e.clientX, top: e.clientY, width: 0, height: 0 }`.\n * • `useOutsideClick` — pointerdown outside a set of targets, aware of\n * layers stacked above (a nested Select's listbox is not \"outside\").\n *\n * Two-phase render, unchanged from the DropdownMenu it replaces: the first\n * paint measures the content parked at (-99999, -99999) with\n * `visibility: hidden`, the layout effect computes the real coordinates, and\n * the second paint reveals it. Components gate their entry animation on\n * `positioned` so `.ds-enter-pop` never plays from the parked location.\n *\n * Token discipline: the hook emits geometry only (`position: fixed` +\n * `left` / `top` in px). Surface colour, radius, shadow, padding and the\n * motion class stay with the component.\n *\n * Usage:\n *\n * const { ref, style, placement, positioned } =\n * useAnchoredPosition<HTMLDivElement>({\n * anchorRef: triggerRef,\n * side: 'bottom',\n * align: 'start',\n * offset: 6,\n * enabled: open,\n * })\n * return createPortal(\n * <div\n * ref={ref}\n * style={style}\n * data-side={placement?.side}\n * className={cn(positioned && 'ds-enter-pop')}\n * >\n * …\n * </div>,\n * document.body,\n * )\n */\n\nimport {\n useCallback,\n useEffect,\n useLayoutEffect,\n useRef,\n useState,\n type CSSProperties,\n type RefObject,\n} from 'react'\nimport type { LayerHandle } from './layer-stack'\n\nexport type AnchorSide = 'top' | 'bottom' | 'left' | 'right'\nexport type AnchorAlign = 'start' | 'center' | 'end'\n\n/** Viewport-relative rect. `DOMRect` satisfies it; so does a point. */\nexport interface AnchorRect {\n readonly left: number\n readonly top: number\n readonly width: number\n readonly height: number\n}\n\nexport interface AnchorSize {\n readonly width: number\n readonly height: number\n}\n\n/** The side and alignment actually used after flipping. */\nexport interface AnchorPlacement {\n readonly side: AnchorSide\n readonly align: AnchorAlign\n}\n\nexport interface AnchoredPositionOptions {\n /** Preferred side of the anchor. Default `bottom`. */\n side?: AnchorSide\n /** Alignment along the anchor's cross axis. Default `start`. */\n align?: AnchorAlign\n /** Gap between anchor and floating element along `side`, px. Default 6. */\n offset?: number\n /** Shift along the alignment axis, px. Default 0. */\n alignOffset?: number\n /**\n * Flip to the opposite side when the preferred side cannot fit and the\n * opposite side fits — or simply has more room. Default true.\n */\n flip?: boolean\n /** Keep the floating element inside the viewport, `gutter` px in. Default true. */\n clampToViewport?: boolean\n /** Viewport inset used by both flip and clamp, px. Default 8. */\n gutter?: number\n}\n\nexport interface AnchoredPosition {\n readonly left: number\n readonly top: number\n readonly placement: AnchorPlacement\n}\n\nconst OPPOSITE: Record<AnchorSide, AnchorSide> = {\n top: 'bottom',\n bottom: 'top',\n left: 'right',\n right: 'left',\n}\n\nfunction isVertical(side: AnchorSide): boolean {\n return side === 'top' || side === 'bottom'\n}\n\nfunction clampNumber(value: number, min: number, max: number): number {\n return Math.max(min, Math.min(value, max))\n}\n\n/**\n * Pure placement math. Given the anchor rect, the floating element's size\n * and the viewport size, returns fixed-position coordinates plus the\n * placement actually used. No DOM — this is what the tests pin.\n */\nexport function computeAnchoredPosition(\n anchor: AnchorRect,\n floating: AnchorSize,\n viewport: AnchorSize,\n options: AnchoredPositionOptions = {},\n): AnchoredPosition {\n const {\n side: preferred = 'bottom',\n align = 'start',\n offset = 6,\n alignOffset = 0,\n flip = true,\n clampToViewport = true,\n gutter = 8,\n } = options\n\n const anchorRight = anchor.left + anchor.width\n const anchorBottom = anchor.top + anchor.height\n\n // Room on each side of the anchor, inside the gutter.\n const room: Record<AnchorSide, number> = {\n top: anchor.top - gutter,\n bottom: viewport.height - anchorBottom - gutter,\n left: anchor.left - gutter,\n right: viewport.width - anchorRight - gutter,\n }\n const needed = (side: AnchorSide): number =>\n (isVertical(side) ? floating.height : floating.width) + offset\n\n let side = preferred\n if (flip && room[preferred] < needed(preferred)) {\n const opposite = OPPOSITE[preferred]\n if (room[opposite] >= needed(opposite) || room[opposite] > room[preferred]) {\n side = opposite\n }\n }\n\n let left: number\n let top: number\n\n if (isVertical(side)) {\n top =\n side === 'bottom'\n ? anchorBottom + offset\n : anchor.top - floating.height - offset\n switch (align) {\n case 'start':\n left = anchor.left + alignOffset\n break\n case 'center':\n left = anchor.left + anchor.width / 2 - floating.width / 2 + alignOffset\n break\n case 'end':\n left = anchorRight - floating.width - alignOffset\n break\n }\n } else {\n left =\n side === 'right'\n ? anchorRight + offset\n : anchor.left - floating.width - offset\n switch (align) {\n case 'start':\n top = anchor.top + alignOffset\n break\n case 'center':\n top = anchor.top + anchor.height / 2 - floating.height / 2 + alignOffset\n break\n case 'end':\n top = anchorBottom - floating.height - alignOffset\n break\n }\n }\n\n if (clampToViewport) {\n // `max` first: when the element is wider than the viewport the upper\n // bound is below the gutter, and the gutter wins.\n left = clampNumber(left, gutter, viewport.width - floating.width - gutter)\n top = clampNumber(top, gutter, viewport.height - floating.height - gutter)\n }\n\n return {\n left: Math.round(left),\n top: Math.round(top),\n placement: { side, align },\n }\n}\n\nexport interface UseAnchoredPositionOptions extends AnchoredPositionOptions {\n /** Element to anchor to. Ignored while `anchorRect` is non-null. */\n anchorRef?: RefObject<Element | null>\n /** Virtual anchor (a right-click point, a text caret). Wins over `anchorRef`. */\n anchorRect?: AnchorRect | null\n /** Measure and track while true. Default true. */\n enabled?: boolean\n}\n\nexport interface UseAnchoredPositionResult<T extends HTMLElement> {\n /** Attach to the floating element. */\n ref: (node: T | null) => void\n /** The same node as a ref object — for `contains()` checks. */\n floatingRef: RefObject<T | null>\n /** `position: fixed` + coordinates; hidden and parked off-screen until measured. */\n style: CSSProperties\n /** Side / align actually used, or null until measured. */\n placement: AnchorPlacement | null\n /** True once real coordinates are applied. Gate entry motion on this. */\n positioned: boolean\n /** Re-measure now (after content you know changed size, for example). */\n update: () => void\n}\n\nconst PARKED_STYLE: CSSProperties = {\n position: 'fixed',\n // Parked far off-screen, not at (0, 0): if a renderer paints the\n // unpositioned frame despite `visibility: hidden`, nothing flashes at the\n // viewport's top-left corner.\n left: -99999,\n top: -99999,\n visibility: 'hidden',\n opacity: 0,\n pointerEvents: 'none',\n}\n\nfunction viewportSize(): AnchorSize {\n // `clientWidth` excludes a vertical scrollbar, which `innerWidth` includes;\n // an end-aligned menu would otherwise sit under the scrollbar. jsdom\n // reports 0 for clientWidth, hence the fallback.\n const root = document.documentElement\n return {\n width: root.clientWidth || window.innerWidth,\n height: root.clientHeight || window.innerHeight,\n }\n}\n\nfunction samePosition(a: AnchoredPosition | null, b: AnchoredPosition): boolean {\n return (\n a !== null &&\n a.left === b.left &&\n a.top === b.top &&\n a.placement.side === b.placement.side &&\n a.placement.align === b.placement.align\n )\n}\n\nexport function useAnchoredPosition<T extends HTMLElement = HTMLElement>(\n options: UseAnchoredPositionOptions,\n): UseAnchoredPositionResult<T> {\n const {\n anchorRef,\n anchorRect = null,\n enabled = true,\n side = 'bottom',\n align = 'start',\n offset = 6,\n alignOffset = 0,\n flip = true,\n clampToViewport = true,\n gutter = 8,\n } = options\n\n // The floating node lives in state as well as a ref so the measuring\n // effect re-runs when the element mounts — a RefObject alone cannot\n // signal that.\n const floatingRef = useRef<T | null>(null)\n const [floating, setFloating] = useState<T | null>(null)\n const ref = useCallback((node: T | null) => {\n floatingRef.current = node\n setFloating(node)\n }, [])\n\n const [position, setPosition] = useState<AnchoredPosition | null>(null)\n\n // Latest virtual rect, read at measure time. Keyed by value (not object\n // identity) so a caller passing a fresh literal each render does not\n // re-subscribe the listeners.\n const anchorRectRef = useRef<AnchorRect | null>(anchorRect)\n useLayoutEffect(() => {\n anchorRectRef.current = anchorRect\n })\n const rectKey = anchorRect\n ? `${anchorRect.left}|${anchorRect.top}|${anchorRect.width}|${anchorRect.height}`\n : ''\n\n const measure = useCallback(() => {\n const node = floatingRef.current\n if (!node) return\n const rect =\n anchorRectRef.current ?? anchorRef?.current?.getBoundingClientRect() ?? null\n if (!rect) return\n // offsetWidth/Height are layout sizes, untouched by the entry animation's\n // transform. getBoundingClientRect() would read a 0.95-scaled box mid-\n // `.ds-enter-pop` and shift an end-aligned menu by 5% of its width.\n const next = computeAnchoredPosition(\n rect,\n { width: node.offsetWidth, height: node.offsetHeight },\n viewportSize(),\n { side, align, offset, alignOffset, flip, clampToViewport, gutter },\n )\n setPosition((prev) => (samePosition(prev, next) ? prev : next))\n }, [anchorRef, side, align, offset, alignOffset, flip, clampToViewport, gutter])\n\n useLayoutEffect(() => {\n if (!enabled || !floating) {\n setPosition((prev) => (prev === null ? prev : null))\n return\n }\n measure()\n window.addEventListener('resize', measure)\n // Capture phase: scrolls inside nested containers do not bubble, and a\n // menu anchored inside one must follow its trigger.\n window.addEventListener('scroll', measure, true)\n let observer: ResizeObserver | null = null\n if (typeof ResizeObserver !== 'undefined') {\n observer = new ResizeObserver(() => measure())\n observer.observe(floating)\n const anchorEl = anchorRef?.current\n if (anchorEl) observer.observe(anchorEl)\n }\n return () => {\n window.removeEventListener('resize', measure)\n window.removeEventListener('scroll', measure, true)\n observer?.disconnect()\n }\n }, [enabled, floating, measure, anchorRef, rectKey])\n\n const positioned = position !== null\n const style: CSSProperties = positioned\n ? { position: 'fixed', left: position.left, top: position.top }\n : PARKED_STYLE\n\n return {\n ref,\n floatingRef,\n style,\n placement: position?.placement ?? null,\n positioned,\n update: measure,\n }\n}\n\nexport type OutsideClickTarget = RefObject<Element | null> | Element | null | undefined\n\nexport interface UseOutsideClickOptions {\n /** Default true. */\n enabled?: boolean\n /**\n * This surface's dismiss layer. When given, a pointerdown inside any layer\n * stacked ABOVE it (a Select opened from inside a Popover) is treated as\n * inside, not outside.\n */\n layer?: LayerHandle\n}\n\n/**\n * Calls `onOutside` on a `pointerdown` whose target is inside none of\n * `targets`. Handler and targets are read through refs, so inline arrays\n * and arrows do not re-subscribe the listener.\n */\nexport function useOutsideClick(\n targets: ReadonlyArray<OutsideClickTarget>,\n onOutside: (event: PointerEvent) => void,\n options: UseOutsideClickOptions = {},\n): void {\n const { enabled = true, layer } = options\n\n const targetsRef = useRef(targets)\n const handlerRef = useRef(onOutside)\n useEffect(() => {\n targetsRef.current = targets\n handlerRef.current = onOutside\n })\n\n useEffect(() => {\n if (!enabled) return\n const onPointerDown = (event: PointerEvent) => {\n const target = event.target\n if (!(target instanceof Node)) return\n for (const candidate of targetsRef.current) {\n const el = candidate instanceof Node ? candidate : candidate?.current\n if (el?.contains(target)) return\n }\n if (layer?.containsInLayerAbove(target)) return\n handlerRef.current(event)\n }\n document.addEventListener('pointerdown', onPointerDown)\n return () => document.removeEventListener('pointerdown', onPointerDown)\n }, [enabled, layer])\n}\n","/**\n * Ref plumbing for primitives that must hand one DOM node to several\n * owners — the caller's forwarded ref, the component's own ref, and a\n * positioning hook's callback ref.\n *\n * `assignRef` writes a node into any React ref shape. `composeRefs` returns\n * ONE callback ref that fans out to all of them; memoize the result\n * (`useMemo` on the inputs) so React does not detach/re-attach on every\n * render.\n */\n\nimport type { Ref, RefCallback } from 'react'\n\nexport function assignRef<T>(ref: Ref<T> | undefined, node: T | null): void {\n if (!ref) return\n if (typeof ref === 'function') {\n // React 19 callback refs may return a cleanup; we call with `null` on\n // detach instead, which every consumer of this package already handles.\n ref(node)\n return\n }\n ref.current = node\n}\n\nexport function composeRefs<T>(\n ...refs: ReadonlyArray<Ref<T> | undefined>\n): RefCallback<T> {\n return (node) => {\n for (const ref of refs) assignRef(ref, node)\n }\n}\n","/**\n * Tabbable-element query shared by the focus-managing surfaces (Modal's\n * trap, Popover's focus-on-open). Extracted from modal.tsx.\n *\n * Deliberately attribute-only — no geometry check. `offsetWidth` /\n * `getClientRects()` are always zero in jsdom, so a visibility filter would\n * empty this list under test and silently disable the trap in exactly the\n * environment that verifies it.\n */\n\nconst FOCUSABLE_SELECTOR = [\n 'a[href]',\n 'area[href]',\n 'button:not([disabled])',\n 'input:not([disabled]):not([type=\"hidden\"])',\n 'select:not([disabled])',\n 'textarea:not([disabled])',\n 'iframe',\n 'summary',\n '[contenteditable=\"true\"]',\n '[tabindex]',\n].join(',')\n\nexport function tabbablesWithin(root: HTMLElement): HTMLElement[] {\n return Array.from(root.querySelectorAll<HTMLElement>(FOCUSABLE_SELECTOR)).filter(\n (el) =>\n el.tabIndex >= 0 &&\n !el.hasAttribute('inert') &&\n el.getAttribute('aria-hidden') !== 'true' &&\n !el.closest('[hidden]') &&\n // `inert` is INHERITED by the subtree in a browser, so a control inside\n // an inert ancestor cannot take focus — a trap that hands it focus\n // anyway simply stops moving. The detail surface collapses a pane by\n // making it inert rather than unmounting it (its scroll and its drafts\n // have to survive), which is the case that made this ancestor check\n // load-bearing rather than tidy.\n !el.closest('[inert]'),\n )\n}\n\n/**\n * Keep Tab inside `container`.\n *\n * `Popover` is non-modal by design: it moves focus in and hands it back, but\n * Tab walks straight out of it into the page behind. For a surface that is a\n * self-contained panel of controls — the Display popover, the filter picker —\n * that reads as the panel losing focus mid-use, so those surfaces wrap the\n * cycle themselves. Call from a `keydown` handler on the container.\n *\n * Does nothing unless the key is Tab, and nothing when the container holds\n * fewer than two tabbables (a single control has nowhere to cycle to and\n * preventing default there would trap the user on it).\n */\nexport function handleTabTrap(\n event: { key: string; shiftKey: boolean; preventDefault: () => void },\n container: HTMLElement | null,\n): void {\n if (event.key !== 'Tab' || !container) return\n const tabbables = tabbablesWithin(container)\n if (tabbables.length < 2) return\n const first = tabbables[0]\n const last = tabbables[tabbables.length - 1]\n if (!first || !last) return\n const active = document.activeElement\n if (event.shiftKey && (active === first || !container.contains(active))) {\n event.preventDefault()\n last.focus()\n return\n }\n if (!event.shiftKey && active === last) {\n event.preventDefault()\n first.focus()\n }\n}\n","/**\n * Popover — an anchored, non-modal floating surface with focus management.\n *\n * Compound: `<Popover>` (state) + `<Popover.Trigger>` + `<Popover.Content>`.\n * Controlled (`open` + `onOpenChange`) or uncontrolled (`defaultOpen`).\n * Content portals to `document.body`, positions through\n * `useAnchoredPosition` (flip + clamp), enters with `.ds-enter-pop` once\n * positioned, and registers on the shared dismiss-layer stack — so Escape\n * closes ONLY the topmost surface (a Popover inside a Modal closes before\n * the Modal does) and an outside pointerdown closes it unless the pointer\n * landed in a layer stacked above (a Select opened from inside it).\n *\n * Focus: opening moves focus into the content — the `[data-autofocus]`\n * control if one is marked, else the first tabbable, else the content\n * itself (`tabIndex={-1}`) — once the content is POSITIONED, not on the\n * first frame: that frame is parked off-screen with `visibility: hidden`,\n * and no browser will focus into a hidden subtree (the call is a silent\n * no-op). Closing returns focus to the trigger, EXCEPT\n * after an outside click, where the user has already put focus where they\n * want it and yanking it back to the trigger would be wrong.\n *\n * Promoted per ADR-0030 Decision G (meta-ads-audit-dashboard task manager:\n * the row / card / context-menu / palette pickers all sit in a popover with\n * search + live counts). Second consumer is the workspace app, which has\n * three hand-rolled popovers today (sidebar user menu, group-settings\n * colour and icon pickers, CalculatorShell's AssumptionsPopover) — each a\n * migration target. DropdownMenu stays a sibling on the same hook and stack\n * rather than a Popover child: a menu does NOT move focus into itself on\n * open, and 137 call sites depend on that.\n *\n * Trigger is an unstyled `<button type=\"button\">` by default — Popover is a\n * generic surface, the caller chooses the trigger's look. Pass `asChild` to\n * make the single child element the trigger instead (a `<Button>`, a table\n * cell, a chip): it receives the ref, the click handler and the ARIA\n * attributes, and the DOM stays one element. The child must be keyboard-\n * operable ON ITS OWN: Trigger adds ARIA + click only, no role, tabIndex or\n * key handler. A native `<button>` / `<a href>` already is; a `<td>` or\n * `<span>` needs `role=\"button\"`, `tabIndex={0}` and its own Enter / Space\n * handling, or only mouse users can open the popover.\n *\n * Content is `role=\"dialog\"` (non-modal — no `aria-modal`) and needs a name\n * from the caller (`aria-label` / `aria-labelledby`). Pass `role=\"none\"`\n * when the content IS the widget (a listbox, a menu) and would otherwise\n * nest roles.\n *\n * Token discipline: the surface reads the INTERNAL `--popover` /\n * `--popover-foreground` (allowed in packages/ui, ESLint-enforced elsewhere)\n * plus public `--border`, `--shadow-lg`, `--radius-lg`. Geometry comes from\n * the hook; motion from `.ds-enter-pop` (`--dur-fast` / `--ease-out`, honours\n * prefers-reduced-motion in styles.css). No hex, no raw px in classes.\n *\n * Usage:\n *\n * <Popover>\n * <Popover.Trigger asChild>\n * <Button variant=\"secondary\">Assignee</Button>\n * </Popover.Trigger>\n * <Popover.Content aria-label=\"Pick an assignee\" align=\"start\">\n * <input data-autofocus placeholder=\"Search people…\" />\n * …\n * </Popover.Content>\n * </Popover>\n *\n * // Virtual anchor (ContextMenu later): no Trigger, position at a point.\n * <Popover open={!!point} onOpenChange={…} anchorRect={point}>\n * <Popover.Content role=\"none\">…</Popover.Content>\n * </Popover>\n */\n\nimport {\n cloneElement,\n createContext,\n forwardRef,\n isValidElement,\n useCallback,\n useContext,\n useEffect,\n useId,\n useMemo,\n useRef,\n useState,\n type ButtonHTMLAttributes,\n type CSSProperties,\n type HTMLAttributes,\n type MouseEvent as ReactMouseEvent,\n type ReactNode,\n type Ref,\n type RefObject,\n} from 'react'\nimport { createPortal } from 'react-dom'\nimport { cn } from './lib/utils'\nimport { composeRefs } from './lib/refs'\nimport { tabbablesWithin } from './lib/focus'\nimport { useLayer } from './lib/layer-stack'\nimport {\n useAnchoredPosition,\n useOutsideClick,\n type AnchorAlign,\n type AnchorRect,\n type AnchorSide,\n} from './lib/anchor'\n\n/**\n * The popover surface chrome, shared with DropdownMenuContent so a menu and\n * a popover read as the same family. Inline rather than a stylesheet class\n * because the surface tokens are internal and the primitives already own\n * them here (Kbd, DropdownMenu follow the same pattern).\n */\nexport const POPOVER_SURFACE_STYLE: CSSProperties = {\n background: 'rgb(var(--popover))',\n color: 'rgb(var(--popover-foreground))',\n border: '1px solid rgb(var(--border))',\n boxShadow: 'var(--shadow-lg)',\n}\n\ninterface PopoverContextValue {\n open: boolean\n setOpen: (next: boolean) => void\n triggerRef: RefObject<HTMLElement | null>\n contentId: string\n anchorRect: AnchorRect | null\n /** Set when the close came from an outside pointerdown; skips focus return. */\n interactedOutsideRef: RefObject<boolean>\n}\n\nconst PopoverCtx = createContext<PopoverContextValue | null>(null)\n\nfunction usePopoverCtx(consumer: string): PopoverContextValue {\n const ctx = useContext(PopoverCtx)\n if (!ctx) {\n throw new Error(\n `${consumer} must be rendered inside <Popover>. ` +\n `Wrap your trigger + content with the Popover root component.`,\n )\n }\n return ctx\n}\n\nexport interface PopoverProps {\n /** Controlled open state. Omit for internal state. */\n open?: boolean\n defaultOpen?: boolean\n /** Fires whenever open transitions. */\n onOpenChange?: (open: boolean) => void\n /**\n * Virtual anchor. When non-null, Content positions against this rect\n * instead of the Trigger — a right-click point, a caret, a cell.\n */\n anchorRect?: AnchorRect | null\n children: ReactNode\n}\n\nfunction PopoverRoot({\n open: controlledOpen,\n defaultOpen,\n onOpenChange,\n anchorRect = null,\n children,\n}: PopoverProps) {\n const [uncontrolledOpen, setUncontrolledOpen] = useState(Boolean(defaultOpen))\n const isControlled = controlledOpen !== undefined\n const open = isControlled ? Boolean(controlledOpen) : uncontrolledOpen\n const triggerRef = useRef<HTMLElement | null>(null)\n const interactedOutsideRef = useRef(false)\n const generatedId = useId()\n const contentId = `popover-${generatedId.replace(/:/g, '')}`\n\n const setOpen = useCallback(\n (next: boolean) => {\n if (!isControlled) setUncontrolledOpen(next)\n onOpenChange?.(next)\n },\n [isControlled, onOpenChange],\n )\n\n const value = useMemo<PopoverContextValue>(\n () => ({ open, setOpen, triggerRef, contentId, anchorRect, interactedOutsideRef }),\n [open, setOpen, contentId, anchorRect],\n )\n\n return <PopoverCtx.Provider value={value}>{children}</PopoverCtx.Provider>\n}\n\nexport interface PopoverTriggerProps extends ButtonHTMLAttributes<HTMLButtonElement> {\n /**\n * Render the single child element as the trigger instead of a `<button>`.\n * The child receives the ref, click handler and ARIA attributes; the DOM\n * stays one element. It must be focusable and keyboard-operable on its\n * own (a `<button>`, an `<a href>`, or `role=\"button\"` + `tabIndex={0}` +\n * Enter / Space handling): Trigger adds no role, tabIndex or key handler.\n */\n asChild?: boolean\n}\n\ntype TriggerChildProps = HTMLAttributes<HTMLElement> & {\n ref?: Ref<HTMLElement>\n 'data-state'?: string\n}\n\nconst PopoverTrigger = forwardRef<HTMLButtonElement, PopoverTriggerProps>(\n function PopoverTrigger({ asChild, onClick, children, ...rest }, forwardedRef) {\n const { open, setOpen, triggerRef, contentId } = usePopoverCtx('Popover.Trigger')\n\n const ariaProps = {\n 'aria-haspopup': 'dialog',\n 'aria-expanded': open,\n 'aria-controls': open ? contentId : undefined,\n 'data-state': open ? 'open' : 'closed',\n } as const\n\n if (asChild) {\n if (!isValidElement<TriggerChildProps>(children)) {\n throw new Error('Popover.Trigger with `asChild` expects exactly one element child.')\n }\n const child = children\n const childOnClick = child.props.onClick\n return cloneElement(child, {\n ...rest,\n ...ariaProps,\n ref: composeRefs<HTMLElement>(child.props.ref, forwardedRef, triggerRef),\n onClick: (event: ReactMouseEvent<HTMLElement>) => {\n childOnClick?.(event)\n onClick?.(event as ReactMouseEvent<HTMLButtonElement>)\n if (!event.defaultPrevented) setOpen(!open)\n },\n })\n }\n\n return (\n <button\n ref={composeRefs<HTMLElement>(forwardedRef, triggerRef)}\n type=\"button\"\n {...ariaProps}\n onClick={(event) => {\n onClick?.(event)\n if (!event.defaultPrevented) setOpen(!open)\n }}\n {...rest}\n >\n {children}\n </button>\n )\n },\n)\n\nexport interface PopoverContentProps\n extends Omit<HTMLAttributes<HTMLDivElement>, 'role' | 'children'> {\n children: ReactNode\n /** Preferred side of the anchor. Default `bottom`. Flips when it cannot fit. */\n side?: AnchorSide\n /** Alignment along the anchor's cross axis. Default `start`. */\n align?: AnchorAlign\n /** Gap from the anchor, px. Default 6. */\n offset?: number\n /** Shift along the alignment axis, px. Default 0. */\n alignOffset?: number\n /** Default true. */\n flip?: boolean\n /** Default true. */\n clampToViewport?: boolean\n /**\n * `dialog` (default) — a named, non-modal dialog; give it `aria-label` or\n * `aria-labelledby`. `none` — no role attribute, for content that is\n * itself the widget.\n */\n role?: 'dialog' | 'none'\n /** Skip the surface chrome (background / border / shadow / radius / padding). */\n unstyled?: boolean\n}\n\nconst PopoverContent = forwardRef<HTMLDivElement, PopoverContentProps>(\n function PopoverContent(\n {\n children,\n side = 'bottom',\n align = 'start',\n offset = 6,\n alignOffset = 0,\n flip = true,\n clampToViewport = true,\n role = 'dialog',\n unstyled,\n className,\n style,\n ...rest\n },\n forwardedRef,\n ) {\n const { open, setOpen, triggerRef, contentId, anchorRect, interactedOutsideRef } =\n usePopoverCtx('Popover.Content')\n const contentRef = useRef<HTMLDivElement | null>(null)\n\n const {\n ref: positionRef,\n style: positionStyle,\n placement,\n positioned,\n } = useAnchoredPosition<HTMLDivElement>({\n anchorRef: triggerRef,\n anchorRect,\n side,\n align,\n offset,\n alignOffset,\n flip,\n clampToViewport,\n enabled: open,\n })\n\n const layer = useLayer({\n enabled: open,\n kind: 'popover',\n elementRef: contentRef,\n onEscape: () => setOpen(false),\n })\n\n useOutsideClick(\n [triggerRef, contentRef],\n () => {\n interactedOutsideRef.current = true\n setOpen(false)\n },\n { enabled: open, layer },\n )\n\n // Focus in once the content is POSITIONED, back to the trigger on close.\n // Not on `open`: the first open frame is the parked one (off-screen,\n // `visibility: hidden`), and Chromium, Firefox and WebKit all refuse to\n // focus into a visibility:hidden subtree, so a focus() there is a silent\n // no-op and focus stays on the trigger. `positioned` flips true in the\n // re-render the measuring layout effect triggers, after the parked frame\n // has already flushed its passive effects. jsdom does not enforce the\n // rule, which is why the test records `data-positioned` at focus time.\n // Keyed on state, not an inline callback, so `onOpenChange` identity\n // churn never re-runs it mid-interaction.\n useEffect(() => {\n if (!open || !positioned) return\n const node = contentRef.current\n if (!node) return\n interactedOutsideRef.current = false\n // Captured now, not in the cleanup: the trigger does not change while\n // the popover is open, and a remounted one would be disconnected.\n const trigger = triggerRef.current\n const previous =\n document.activeElement instanceof HTMLElement &&\n document.activeElement !== document.body\n ? document.activeElement\n : null\n const initial =\n node.querySelector<HTMLElement>('[data-autofocus]') ??\n tabbablesWithin(node)[0] ??\n node\n initial.focus()\n\n return () => {\n if (interactedOutsideRef.current) return\n // The content is gone by now, so a focus that was inside it has\n // already fallen to <body>. Anything else means the user moved on.\n const active = document.activeElement\n if (active !== null && active !== document.body && !node.contains(active)) return\n const target = trigger ?? previous\n if (target?.isConnected) target.focus()\n }\n }, [open, positioned, triggerRef, interactedOutsideRef])\n\n const ref = useMemo(\n () => composeRefs<HTMLDivElement>(forwardedRef, contentRef, positionRef),\n [forwardedRef, positionRef],\n )\n\n if (!open || typeof document === 'undefined') return null\n\n return createPortal(\n <div\n ref={ref}\n id={contentId}\n role={role === 'none' ? undefined : role}\n tabIndex={-1}\n data-slot=\"popover-content\"\n data-state=\"open\"\n data-side={placement?.side}\n data-align={placement?.align}\n data-positioned={positioned ? 'true' : 'false'}\n className={cn(\n 'fixed z-[100] outline-none',\n !unstyled && 'rounded-[var(--radius-lg)] p-3',\n positioned && 'ds-enter-pop',\n className,\n )}\n style={{\n ...positionStyle,\n ...(unstyled ? undefined : POPOVER_SURFACE_STYLE),\n ...style,\n }}\n {...rest}\n >\n {children}\n </div>,\n document.body,\n )\n },\n)\n\nexport const Popover = Object.assign(PopoverRoot, {\n Trigger: PopoverTrigger,\n Content: PopoverContent,\n})\n","/**\n * CodeBlock — syntax-highlighted code block with language label + copy button.\n * MarkdownCode — react-markdown `code` element adapter (inline + fenced).\n *\n * Uses PrismLight (synchronous, tree-shakeable) so only registered languages\n * are bundled. Theme follows the html data-theme attribute via a local\n * MutationObserver hook.\n *\n * Promoted from brand-ai-extension (ADR-036 D20).\n */\n\nimport { createContext, useContext, useEffect, useState, type HTMLAttributes, type ReactNode } from 'react'\nimport { Check, Copy } from 'lucide-react'\nimport { PrismLight as SyntaxHighlighter } from 'react-syntax-highlighter'\nimport { vscDarkPlus, oneLight } from 'react-syntax-highlighter/dist/esm/styles/prism'\n\nimport bash from 'react-syntax-highlighter/dist/esm/languages/prism/bash'\nimport css from 'react-syntax-highlighter/dist/esm/languages/prism/css'\nimport diff from 'react-syntax-highlighter/dist/esm/languages/prism/diff'\nimport javascript from 'react-syntax-highlighter/dist/esm/languages/prism/javascript'\nimport json from 'react-syntax-highlighter/dist/esm/languages/prism/json'\nimport jsx from 'react-syntax-highlighter/dist/esm/languages/prism/jsx'\nimport markdown from 'react-syntax-highlighter/dist/esm/languages/prism/markdown'\nimport markup from 'react-syntax-highlighter/dist/esm/languages/prism/markup'\nimport python from 'react-syntax-highlighter/dist/esm/languages/prism/python'\nimport sql from 'react-syntax-highlighter/dist/esm/languages/prism/sql'\nimport tsx from 'react-syntax-highlighter/dist/esm/languages/prism/tsx'\nimport typescript from 'react-syntax-highlighter/dist/esm/languages/prism/typescript'\nimport yaml from 'react-syntax-highlighter/dist/esm/languages/prism/yaml'\n\nimport { cn } from './lib/utils'\n\n/**\n * Reads the html data-theme attribute and re-fires whenever it changes.\n * Kept local until a workspace-wide useTheme hook is promoted.\n */\nfunction useDataTheme(): 'light' | 'dark' {\n const read = (): 'light' | 'dark' => {\n if (typeof document === 'undefined') return 'dark'\n const attr = document.documentElement.getAttribute('data-theme')\n return attr === 'light' ? 'light' : 'dark'\n }\n\n const [theme, setTheme] = useState<'light' | 'dark'>(read)\n\n useEffect(() => {\n if (typeof window === 'undefined') return\n const observer = new MutationObserver(() => setTheme(read()))\n observer.observe(document.documentElement, {\n attributes: true,\n attributeFilter: ['data-theme'],\n })\n return () => observer.disconnect()\n }, [])\n\n return theme\n}\n\n// Register the language allowlist once at module scope.\nconst LANGUAGES: Record<string, unknown> = {\n bash,\n shell: bash,\n sh: bash,\n css,\n diff,\n javascript,\n js: javascript,\n json,\n jsx,\n markdown,\n md: markdown,\n html: markup,\n xml: markup,\n python,\n py: python,\n sql,\n tsx,\n typescript,\n ts: typescript,\n yaml,\n yml: yaml,\n}\n\nfor (const [name, lang] of Object.entries(LANGUAGES)) {\n SyntaxHighlighter.registerLanguage(name, lang as never)\n}\n\nconst LANGUAGE_LABELS: Record<string, string> = {\n bash: 'bash',\n sh: 'shell',\n css: 'css',\n diff: 'diff',\n html: 'html',\n javascript: 'javascript',\n js: 'javascript',\n json: 'json',\n jsx: 'jsx',\n markdown: 'markdown',\n md: 'markdown',\n python: 'python',\n py: 'python',\n shell: 'shell',\n sql: 'sql',\n tsx: 'tsx',\n ts: 'typescript',\n typescript: 'typescript',\n xml: 'xml',\n yaml: 'yaml',\n yml: 'yaml',\n}\n\nexport interface CodeBlockProps {\n /** Lowercased language identifier, e.g. \"typescript\" or \"json\". */\n language?: string\n /** Raw source text. */\n children: string\n}\n\nexport function CodeBlock({ language, children }: CodeBlockProps) {\n const [copied, setCopied] = useState(false)\n const theme = useDataTheme()\n const syntaxStyle = theme === 'light' ? oneLight : vscDarkPlus\n const lang = (language ?? '').toLowerCase()\n const supported = lang in LANGUAGES\n const label = (LANGUAGE_LABELS[lang] ?? lang) || 'plaintext'\n const source = String(children).replace(/\\n$/, '')\n\n const handleCopy = async () => {\n try {\n await navigator.clipboard.writeText(source)\n setCopied(true)\n setTimeout(() => setCopied(false), 2000)\n } catch {\n // Clipboard can fail in insecure contexts — silently no-op.\n }\n }\n\n return (\n <div\n className=\"my-4 overflow-hidden text-sm\"\n style={{\n background: 'rgb(var(--bg-elevated))',\n border: '1px solid rgb(var(--border))',\n borderRadius: 'var(--radius-md)',\n }}\n >\n {/* Header: language label + copy button */}\n <div\n className=\"flex items-center justify-between px-3 py-1.5 text-xs\"\n style={{\n background: 'rgb(var(--muted))',\n borderBottom: '1px solid rgb(var(--border))',\n color: 'rgb(var(--muted-foreground))',\n }}\n >\n <span className=\"font-mono lowercase\">{label}</span>\n <button\n type=\"button\"\n onClick={handleCopy}\n className={cn(\n 'flex items-center gap-1 rounded-md px-2 py-1 text-xs transition-colors',\n !copied && 'hover:text-[rgb(var(--foreground))]',\n )}\n style={copied ? { color: 'rgb(var(--success))' } : undefined}\n aria-label={copied ? 'Copied' : 'Copy code'}\n >\n {copied ? (\n <>\n <Check className=\"h-3.5 w-3.5\" /> Copied\n </>\n ) : (\n <>\n <Copy className=\"h-3.5 w-3.5\" /> Copy\n </>\n )}\n </button>\n </div>\n\n {/* Body */}\n {supported ? (\n <SyntaxHighlighter\n language={lang}\n style={syntaxStyle}\n customStyle={{\n margin: 0,\n padding: '0.875rem 1rem',\n background: 'transparent',\n fontSize: '0.8125rem',\n lineHeight: 1.6,\n }}\n codeTagProps={{\n style: { fontFamily: 'ui-monospace, SFMono-Regular, Menlo, monospace' },\n }}\n >\n {source}\n </SyntaxHighlighter>\n ) : (\n <pre\n className=\"overflow-x-auto px-4 py-3.5 font-mono text-[0.8125rem] leading-relaxed\"\n style={{ color: 'rgb(var(--foreground))' }}\n >\n {source}\n </pre>\n )}\n </div>\n )\n}\n\n/**\n * Whether the code being rendered sits inside react-markdown's `pre` element,\n * i.e. is a fenced or indented code BLOCK.\n *\n * The signal is structural, not textual. `remark-rehype` always emits block\n * code as `<pre><code>` (its `code` handler wraps unconditionally) and inline\n * code as a bare `<code>` (its `inlineCode` handler never wraps). react-markdown\n * 10 hands every component the hast `node`, but a hast Element carries no\n * parent link, so the `code` component cannot see `pre` from `node` alone —\n * and react-markdown exposes `parent` only to `allowElement` / `urlTransform`,\n * never to components. So the `pre` component announces itself here and\n * `MarkdownCode` reads it.\n *\n * The previous discriminator was \"has a className\", which is only set when\n * the fence names a language. That made every language-less fence — the rich\n * composer's default (ADR-148 D3) — render as an inline chip. This is right\n * for a bare fence, an empty fence, and a code span that wraps onto a second\n * line (CommonMark folds its newline to a space, but nothing here relies on\n * that).\n */\nconst PreContext = createContext(false)\n\n/**\n * MarkdownPre — react-markdown `pre` element adapter.\n *\n * Renders no element of its own: `CodeBlock` owns its container, and a real\n * `<pre>` here would double-wrap every fenced block. Its only job is to tell\n * the `code` inside it that it is a block. Register together with\n * `MarkdownCode` (as `markdownComponents` does).\n */\nexport function MarkdownPre({ children }: HTMLAttributes<HTMLElement>) {\n return <PreContext.Provider value={true}>{children}</PreContext.Provider>\n}\n\n/**\n * MarkdownCode — react-markdown `code` element adapter.\n *\n * A BLOCK is a `code` inside react-markdown's `pre` (see `PreContext`) — or one\n * handed a className, which is how `<MarkdownCode className=\"language-json\">`\n * is used directly outside react-markdown. Blocks delegate to `CodeBlock`: a\n * `language-*` capture picks the highlighter; no capture (a bare fence, or a\n * class that is not a language) gets the plain preformatted surface with the\n * same header and copy button. Everything else is inline code and renders as\n * a small chip.\n */\nexport function MarkdownCode({ className, children }: HTMLAttributes<HTMLElement>) {\n const inPre = useContext(PreContext)\n const block = inPre || Boolean(className)\n if (!block) {\n return (\n <code\n className=\"rounded px-1.5 py-0.5 font-mono text-[0.85em]\"\n style={{\n background: 'rgb(var(--muted))',\n color: 'rgb(var(--foreground))',\n borderRadius: 'var(--radius-xs)',\n }}\n >\n {children}\n </code>\n )\n }\n\n const match = className === undefined ? null : /language-([\\w-]+)/.exec(className)\n const language = match?.[1]\n return <CodeBlock {...(language !== undefined ? { language } : {})}>{sourceOf(children)}</CodeBlock>\n}\n\n/**\n * The code text react-markdown hands a block: one string for a fence with\n * content, and NOTHING for an empty fence — `hast-util-to-jsx-runtime`'s\n * `addChildren` only sets `props.children` when the child is truthy, so the\n * empty-string text node never arrives and `String(children)` would render\n * the word \"undefined\".\n */\nfunction sourceOf(children: ReactNode): string {\n if (typeof children === 'string') return children\n if (typeof children === 'number') return String(children)\n if (children === undefined || children === null || typeof children === 'boolean') return ''\n return String(children)\n}\n","/**\n * remark-underline — `++text++` renders as `<u>` (ADR-148 D13).\n *\n * Markdown has no underline. The rich composer serialises TipTap's\n * `underline` mark as `++text++` — a dialect several Markdown flavours use\n * for insert/underline, and one CommonMark cannot misread because `+` has no\n * inline meaning. This is the RENDERER half: a micromark text construct that\n * tokenizes `++` runs, a resolver that pairs openers with closers, and an\n * mdast handler that emits an `underline` node carrying `data.hName = 'u'`,\n * which `remark-rehype` turns into a `<u>` element for the component map in\n * `markdown.tsx` to style.\n *\n * ZERO DEPENDENCIES, ON PURPOSE. `remark-gfm` already pulls every utility this\n * would want into the lockfile (`micromark-util-classify-character`,\n * `micromark-util-resolve-all`, `micromark-util-chunked`,\n * `mdast-util-from-markdown`, `micromark-util-types`) — but pnpm's strict\n * layout keeps transitives out of `packages/ui/node_modules`, so none of them\n * is importable here without becoming a direct dependency, which D13 forbids.\n * The three helpers are re-derived below (each is under fifteen lines in the\n * original) and the types are local structural mirrors of\n * `micromark-util-types` / `mdast-util-from-markdown`. The runtime contract is\n * plain objects and functions that micromark calls by shape, so a mirror is\n * exactly as safe as the import would be. The construct is modelled line for\n * line on `micromark-extension-gfm-strikethrough` (`~~` → `<del>`), its\n * closest cousin.\n *\n * THE RULES — agreed with the composer's serializer (ADR-148 D13):\n *\n * • A `++` run may OPEN / CLOSE by exactly GFM strikethrough's flanking\n * rule (`micromark-extension-gfm-strikethrough`, which is CommonMark's\n * `*` rule without the underscore exception): classify the character on\n * each side as whitespace, punctuation, or other, then\n *\n * open = after is not whitespace and (after is not punctuation or before is whitespace/punctuation)\n * close = before is not whitespace and (before is not punctuation or after is whitespace/punctuation)\n *\n * So `++text++` behaves the way `~~text~~` and `**text**` already do:\n * `i++; j++;` and `C++` stay literal (a run before punctuation after a\n * letter cannot open), `word++x++word` DOES underline (intraword, like\n * `~~`), `see ++(note)++ here` underlines but `a++(note)++b` does not.\n * Whitespace = end of input, line endings, tabs, spaces, Unicode\n * whitespace; punctuation = Unicode P and S. micromark hands over UTF-16\n * code units, so an astral character (an emoji) arrives as two surrogates\n * and classifies as \"other\", exactly as it does for `~~`.\n * • Exactly two markers. A lone `+`, a `+++` run, an unclosed `++text`, a\n * closer with no opener, spaces just inside the markers — all stay\n * literal text. Nothing is dropped and nothing throws (D3 rule 3).\n * • Code spans and fences are untouched: micromark never runs text\n * constructs inside them, so `` `++x++` `` shows the plus signs.\n * • `\\++` is an ordinary character escape and stays literal.\n * • Registered as an `insideSpan` resolver AND an attention marker — the\n * same two hooks strikethrough uses — so `**++x++**`, `++**x**++`,\n * `~~++x++~~` and the intraword `a**++x++**b` all nest correctly.\n * • Two pairs CAN nest structurally (`++a ++b++ c++` → `<u>a <u>b</u> c</u>`),\n * exactly as `~~` does. The composer never emits that (a mark cannot\n * nest in ProseMirror) and it renders as one underline, so it is pinned\n * rather than prevented.\n */\n\n// ---------------------------------------------------------------------------\n// Local structural types — mirrors of `micromark-util-types` (see header).\n// Only the members this construct touches are declared.\n// ---------------------------------------------------------------------------\n\n/**\n * A character code. `null` is end of input; negative values are micromark's\n * virtual characters (line endings, tab expansion); everything else is a\n * Unicode code point.\n */\ntype Code = number | null\n\ninterface Point {\n line: number\n column: number\n offset: number\n _index: number\n _bufferIndex: number\n}\n\ninterface Token {\n type: string\n start: Point\n end: Point\n _open?: boolean\n _close?: boolean\n}\n\ninterface Resolvable {\n readonly resolveAll?: Resolver | undefined\n}\n\ninterface TokenizeContext {\n readonly previous: Code\n readonly events: Event[]\n readonly parser: {\n readonly constructs: {\n readonly insideSpan: { readonly null?: readonly Resolvable[] | undefined }\n }\n }\n}\n\ntype Event = ['enter' | 'exit', Token, TokenizeContext]\ntype State = (code: Code) => State | undefined\ntype Resolver = (events: Event[], context: TokenizeContext) => Event[]\ntype Tokenizer = (this: TokenizeContext, effects: Effects, ok: State, nok: State) => State\n\ninterface Effects {\n enter(type: string): Token\n exit(type: string): Token\n consume(code: Code): undefined\n}\n\ninterface Construct extends Resolvable {\n readonly name: string\n readonly tokenize: Tokenizer\n readonly resolveAll: Resolver\n}\n\n/** The three hooks a micromark syntax extension may register for an inline construct. */\ninterface MicromarkExtension {\n readonly text: Readonly<Record<number, Construct>>\n readonly insideSpan: { readonly null: readonly Construct[] }\n readonly attentionMarkers: { readonly null: readonly Code[] }\n}\n\n// Mirrors of `mdast-util-from-markdown` — the compile side.\n\n/**\n * The mdast node. `data.hName` is the documented `mdast-util-to-hast` hook:\n * an unknown node type with an `hName` becomes an element of that name, so\n * no rehype plugin of any kind is involved and the raw-HTML ban is untouched.\n */\ninterface UnderlineNode {\n type: 'underline'\n children: unknown[]\n data: { hName: 'u' }\n}\n\ninterface CompileContext {\n enter(node: UnderlineNode, token: Token): undefined\n exit(token: Token): undefined\n}\n\ntype Handle = (this: CompileContext, token: Token) => undefined\n\ninterface FromMarkdownExtension {\n readonly canContainEols: readonly string[]\n readonly enter: Readonly<Record<string, Handle>>\n readonly exit: Readonly<Record<string, Handle>>\n}\n\n// The slice of a unified processor the plugin touches. `settings` is listed\n// so the type is not \"weak\" (all-optional) and unified's `Data` — which has\n// `settings` — is assignable to it whether or not remark-parse's augmentation\n// (`micromarkExtensions` / `fromMarkdownExtensions`) is loaded in a consumer.\ninterface RemarkData {\n settings?: unknown\n micromarkExtensions?: unknown[]\n fromMarkdownExtensions?: unknown[]\n}\n\ninterface RemarkProcessorLike {\n data(): RemarkData\n}\n\n// ---------------------------------------------------------------------------\n// Constants\n// ---------------------------------------------------------------------------\n\n/** U+002B PLUS SIGN. */\nconst PLUS = 43\n/** U+0020 SPACE. */\nconst SPACE = 32\n\nconst SEQUENCE_TEMPORARY = 'underlineSequenceTemporary'\nconst SEQUENCE = 'underlineSequence'\nconst UNDERLINE = 'underline'\nconst UNDERLINE_TEXT = 'underlineText'\n/** micromark's own token types this construct reads. */\nconst CHARACTER_ESCAPE = 'characterEscape'\nconst DATA = 'data'\n\n/** `Array#splice` spreads its items as arguments; past this many V8 overflows the stack. */\nconst SPLICE_CHUNK = 10_000\n\n/** `micromark-util-character`'s `unicodeWhitespace` / `unicodePunctuation`. */\nconst UNICODE_WHITESPACE = /\\s/\nconst UNICODE_PUNCTUATION = /\\p{P}|\\p{S}/u\n\n/** `micromark-util-symbol`'s character groups. */\nconst GROUP_WHITESPACE = 1\nconst GROUP_PUNCTUATION = 2\ntype CharacterGroup = typeof GROUP_WHITESPACE | typeof GROUP_PUNCTUATION | undefined\n\n// ---------------------------------------------------------------------------\n// Re-derived helpers (see header for why these are not imports)\n// ---------------------------------------------------------------------------\n\n/**\n * `micromark-util-classify-character`: whitespace (end of input, any virtual\n * character — all line endings and tab parts are negative codes — the space,\n * Unicode whitespace), punctuation (Unicode P and S), or other. Codes are\n * UTF-16 units and are stringified with `fromCharCode` exactly as micromark's\n * `regexCheck` does, so surrogate halves classify as \"other\" here too.\n */\nfunction classifyCharacter(code: Code): CharacterGroup {\n if (code === null || code < 0 || code === SPACE) return GROUP_WHITESPACE\n const character = String.fromCharCode(code)\n if (UNICODE_WHITESPACE.test(character)) return GROUP_WHITESPACE\n if (UNICODE_PUNCTUATION.test(character)) return GROUP_PUNCTUATION\n return undefined\n}\n\n/** `micromark-util-chunked`'s `splice`: `Array#splice` that survives huge item lists. */\nfunction spliceChunked<T>(list: T[], start: number, remove: number, items: readonly T[]): void {\n const end = list.length\n let at = start < 0 ? (-start > end ? 0 : end + start) : start > end ? end : start\n const count = remove > 0 ? remove : 0\n\n if (items.length < SPLICE_CHUNK) {\n list.splice(at, count, ...items)\n return\n }\n\n if (count > 0) list.splice(at, count)\n let from = 0\n while (from < items.length) {\n list.splice(at, 0, ...items.slice(from, from + SPLICE_CHUNK))\n from += SPLICE_CHUNK\n at += SPLICE_CHUNK\n }\n}\n\n/** `micromark-util-resolve-all`: run each distinct `resolveAll` once, in order. */\nfunction resolveAll(\n constructs: readonly Resolvable[],\n events: Event[],\n context: TokenizeContext,\n): Event[] {\n const called: Resolver[] = []\n let result = events\n for (const construct of constructs) {\n const resolve = construct.resolveAll\n if (resolve !== undefined && !called.includes(resolve)) {\n result = resolve(result, context)\n called.push(resolve)\n }\n }\n return result\n}\n\n// ---------------------------------------------------------------------------\n// The micromark construct\n// ---------------------------------------------------------------------------\n\n/**\n * Tokenize one `++` run. Runs whenever the text tokenizer meets a `+`.\n * Emits a temporary sequence token flagged with whether it may open and/or\n * close; the resolver pairs them afterwards.\n */\nfunction tokenizeUnderline(\n this: TokenizeContext,\n effects: Effects,\n ok: State,\n nok: State,\n): State {\n const previous = this.previous\n const events = this.events\n let size = 0\n\n return start\n\n function start(code: Code): State | undefined {\n // A `+` directly after another `+` that was not an escape means we are\n // inside a run an earlier attempt already rejected (`+++`): stay literal.\n if (previous === PLUS && events[events.length - 1]?.[1].type !== CHARACTER_ESCAPE) {\n return nok(code)\n }\n effects.enter(SEQUENCE_TEMPORARY)\n return more(code)\n }\n\n function more(code: Code): State | undefined {\n if (code === PLUS) {\n // A third marker is not this syntax.\n if (size > 1) return nok(code)\n effects.consume(code)\n size++\n return more\n }\n if (size < 2) return nok(code)\n\n const token = effects.exit(SEQUENCE_TEMPORARY)\n // GFM strikethrough's flanking rule, verbatim (see header).\n const before = classifyCharacter(previous)\n const after = classifyCharacter(code)\n token._open = after === undefined || (after === GROUP_PUNCTUATION && before !== undefined)\n token._close = before === undefined || (before === GROUP_PUNCTUATION && after !== undefined)\n return ok(code)\n }\n}\n\n/**\n * Pair closers with the nearest earlier opener, wrapping the events between\n * in `underline` / `underlineText`, and demote every sequence that did not\n * pair to plain `data` so its characters render as typed.\n */\nfunction resolveAllUnderline(events: Event[], context: TokenizeContext): Event[] {\n let index = -1\n\n while (++index < events.length) {\n const closer = events[index]\n if (\n closer === undefined ||\n closer[0] !== 'enter' ||\n closer[1].type !== SEQUENCE_TEMPORARY ||\n closer[1]._close !== true\n ) {\n continue\n }\n\n let open = index\n while (open--) {\n const opener = events[open]\n if (\n opener === undefined ||\n opener[0] !== 'exit' ||\n opener[1].type !== SEQUENCE_TEMPORARY ||\n opener[1]._open !== true ||\n // Sizes must match — always two here, kept for parity with the model.\n closer[1].end.offset - closer[1].start.offset !==\n opener[1].end.offset - opener[1].start.offset\n ) {\n continue\n }\n\n closer[1].type = SEQUENCE\n opener[1].type = SEQUENCE\n\n const underline: Token = {\n type: UNDERLINE,\n start: { ...opener[1].start },\n end: { ...closer[1].end },\n }\n const text: Token = {\n type: UNDERLINE_TEXT,\n start: { ...opener[1].end },\n end: { ...closer[1].start },\n }\n\n // Opening.\n const next: Event[] = [\n ['enter', underline, context],\n ['enter', opener[1], context],\n ['exit', opener[1], context],\n ['enter', text, context],\n ]\n\n // Between — let every other span construct (emphasis, strong,\n // strikethrough, this one again) resolve inside the pair.\n const insideSpan = context.parser.constructs.insideSpan.null\n if (insideSpan !== undefined) {\n spliceChunked(\n next,\n next.length,\n 0,\n resolveAll(insideSpan, events.slice(open + 1, index), context),\n )\n }\n\n // Closing.\n spliceChunked(next, next.length, 0, [\n ['exit', text, context],\n ['enter', closer[1], context],\n ['exit', closer[1], context],\n ['exit', underline, context],\n ])\n\n spliceChunked(events, open - 1, index - open + 3, next)\n index = open + next.length - 2\n break\n }\n }\n\n // Whatever did not pair is text. Never dropped, never thrown (D3 rule 3).\n for (const event of events) {\n if (event[1].type === SEQUENCE_TEMPORARY) event[1].type = DATA\n }\n\n return events\n}\n\nfunction underlineSyntax(): MicromarkExtension {\n const construct: Construct = {\n name: 'underline',\n tokenize: tokenizeUnderline,\n resolveAll: resolveAllUnderline,\n }\n return {\n text: { [PLUS]: construct },\n insideSpan: { null: [construct] },\n attentionMarkers: { null: [PLUS] },\n }\n}\n\n// ---------------------------------------------------------------------------\n// The mdast compile extension\n// ---------------------------------------------------------------------------\n\nfunction enterUnderline(this: CompileContext, token: Token): undefined {\n this.enter({ type: UNDERLINE, children: [], data: { hName: 'u' } }, token)\n}\n\nfunction exitUnderline(this: CompileContext, token: Token): undefined {\n this.exit(token)\n}\n\nfunction underlineFromMarkdown(): FromMarkdownExtension {\n return {\n // A soft line break inside `++a\\nb++` is kept as text, like `delete`.\n canContainEols: [UNDERLINE],\n enter: { [UNDERLINE]: enterUnderline },\n exit: { [UNDERLINE]: exitUnderline },\n }\n}\n\n// ---------------------------------------------------------------------------\n// The remark plugin\n// ---------------------------------------------------------------------------\n\n/**\n * remark plugin: `++text++` → `<u>`. Register after `remarkGfm` in a\n * `remarkPlugins` list. Same shape as `remark-gfm` itself — it appends one\n * micromark syntax extension and one mdast compile extension to the\n * processor's data and returns nothing.\n */\nexport function remarkUnderline(this: RemarkProcessorLike): undefined {\n const data = this.data()\n const micromark = data.micromarkExtensions ?? (data.micromarkExtensions = [])\n const fromMarkdown = data.fromMarkdownExtensions ?? (data.fromMarkdownExtensions = [])\n micromark.push(underlineSyntax())\n fromMarkdown.push(underlineFromMarkdown())\n}\n","/**\n * MarkdownRenderer — renders a markdown string using react-markdown + remark-gfm.\n * Component overrides match the chat-message.tsx config from brand-ai-extension.\n *\n * Promoted from brand-ai-extension (ADR-036 D20).\n * Extracted from components/chat/chat-message.tsx (lines 15-110 — the\n * MARKDOWN_COMPONENTS and REMARK_PLUGINS constants + renderMarkdown helper).\n *\n * Token note: the source referenced --primary for blockquote border, link\n * colour, and ordered-list marker accent. --primary is an internal token.\n * Replaced with the public --accent token throughout.\n */\n\nimport type {\n InputHTMLAttributes,\n HTMLAttributes,\n AnchorHTMLAttributes,\n} from 'react'\nimport ReactMarkdown, { type Components } from 'react-markdown'\nimport remarkGfm from 'remark-gfm'\nimport { MarkdownCode, MarkdownPre } from './code-block'\nimport { remarkUnderline } from './lib/remark-underline'\n\ntype NodeProps = HTMLAttributes<HTMLElement>\ntype AnchorProps = AnchorHTMLAttributes<HTMLAnchorElement>\n\nconst MARKDOWN_COMPONENTS: Components = {\n h1: ({ children }: NodeProps) => (\n <h1\n className=\"mt-6 mb-3 text-xl font-bold first:mt-0\"\n style={{ color: 'rgb(var(--foreground))' }}\n >\n {children}\n </h1>\n ),\n h2: ({ children }: NodeProps) => (\n <h2\n className=\"mt-5 mb-2 text-lg font-bold first:mt-0\"\n style={{ color: 'rgb(var(--foreground))' }}\n >\n {children}\n </h2>\n ),\n h3: ({ children }: NodeProps) => (\n <h3\n className=\"mt-4 mb-2 text-base font-semibold first:mt-0\"\n style={{ color: 'rgb(var(--foreground))' }}\n >\n {children}\n </h3>\n ),\n p: ({ children }: NodeProps) => (\n <p\n className=\"mb-4 leading-relaxed last:mb-0\"\n style={{ color: 'rgb(var(--foreground))' }}\n >\n {children}\n </p>\n ),\n // list-outside + left padding so wrapped lines indent under the text (not the\n // marker). Bullets use text-tertiary; ordered markers use --accent + bold so\n // the numbering reads as deliberate hierarchy rather than browser-default grey.\n ul: ({ children }: NodeProps) => (\n <ul\n className=\"mb-4 list-disc list-outside space-y-2 pl-6\"\n style={{ color: 'rgb(var(--text-tertiary))' }}\n >\n {children}\n </ul>\n ),\n ol: ({ children }: NodeProps) => (\n <ol\n className=\"mb-4 list-decimal list-outside space-y-2 pl-6 marker:font-semibold\"\n style={{ color: 'rgb(var(--foreground))' }}\n >\n {children}\n </ol>\n ),\n li: ({ children }: NodeProps) => (\n <li\n className=\"pl-1 leading-relaxed\"\n style={{ color: 'rgb(var(--foreground))' }}\n >\n {children}\n </li>\n ),\n strong: ({ children }: NodeProps) => (\n <strong className=\"font-semibold\" style={{ color: 'rgb(var(--foreground))' }}>\n {children}\n </strong>\n ),\n em: ({ children }: NodeProps) => (\n <em className=\"italic\" style={{ color: 'rgb(var(--foreground))' }}>\n {children}\n </em>\n ),\n // code: inline chip or code block (CodeBlock via MarkdownCode). pre renders\n // no element — CodeBlock owns its container — but it is what tells the code\n // inside it that it is a block, language or not (see PreContext).\n code: MarkdownCode,\n pre: MarkdownPre,\n blockquote: ({ children }: NodeProps) => (\n <blockquote\n className=\"my-4 border-l-4 py-1 pl-4 italic\"\n style={{\n borderColor: 'rgb(var(--accent))',\n color: 'rgb(var(--muted-foreground))',\n }}\n >\n {children}\n </blockquote>\n ),\n hr: () => (\n <hr className=\"my-6\" style={{ borderColor: 'rgb(var(--border))' }} />\n ),\n a: ({ href, children }: AnchorProps) => (\n <a\n href={href}\n className=\"hover:underline\"\n style={{ color: 'rgb(var(--accent))' }}\n target=\"_blank\"\n rel=\"noopener noreferrer\"\n >\n {children}\n </a>\n ),\n // GFM additions — tables, task lists, strikethrough.\n table: ({ children }: NodeProps) => (\n <div\n className=\"my-4 overflow-x-auto\"\n style={{\n borderRadius: 'var(--radius-md)',\n border: '1px solid rgb(var(--border))',\n }}\n >\n <table className=\"w-full border-collapse text-sm\">{children}</table>\n </div>\n ),\n thead: ({ children }: NodeProps) => (\n <thead\n style={{\n background: 'rgb(var(--muted))',\n color: 'rgb(var(--muted-foreground))',\n }}\n >\n {children}\n </thead>\n ),\n tbody: ({ children }: NodeProps) => <tbody>{children}</tbody>,\n tr: ({ children }: NodeProps) => (\n <tr\n className=\"first:border-t-0\"\n style={{ borderTop: '1px solid rgb(var(--border))' }}\n >\n {children}\n </tr>\n ),\n th: ({ children }: NodeProps) => (\n <th className=\"px-3 py-2 text-left font-medium\">{children}</th>\n ),\n td: ({ children }: NodeProps) => (\n <td\n className=\"px-3 py-2 align-top\"\n style={{ color: 'rgb(var(--foreground))' }}\n >\n {children}\n </td>\n ),\n del: ({ children }: NodeProps) => (\n <del className=\"line-through\" style={{ color: 'rgb(var(--muted-foreground))' }}>\n {children}\n </del>\n ),\n // Underline — `++text++` via remarkUnderline (ADR-148 D13). The line is a\n // step softer than the ink so it reads as a deliberate underline, not a link.\n u: ({ children }: NodeProps) => (\n <u\n className=\"underline-offset-2\"\n style={{\n color: 'rgb(var(--foreground))',\n textDecorationColor: 'rgb(var(--text-tertiary))',\n }}\n >\n {children}\n </u>\n ),\n // Task-list checkboxes rendered by remark-gfm for \"- [ ] ...\" / \"- [x] ...\".\n input: (props: InputHTMLAttributes<HTMLInputElement>) =>\n props.type === 'checkbox' ? (\n <input\n {...props}\n disabled\n className=\"mr-1.5 -translate-y-px\"\n style={{ accentColor: 'rgb(var(--accent))' }}\n />\n ) : (\n <input {...props} />\n ),\n}\n\n// THE remark plugin list. Every markdown surface in the package parses with\n// this — `CommentBody` imports it rather than keeping its own, so GFM and the\n// `++text++` underline (ADR-148 D13) cannot drift between surfaces.\nconst REMARK_PLUGINS = [remarkGfm, remarkUnderline]\n\nexport interface MarkdownRendererProps {\n /** Raw markdown string to render. */\n children: string\n /** Optional className applied to the wrapping div. */\n className?: string\n}\n\n/**\n * MarkdownRenderer — drop-in markdown surface with GFM support.\n * Renders headings, lists, code (via CodeBlock), tables, task lists,\n * strikethrough, blockquotes, and links with workspace token styling.\n */\nexport function MarkdownRenderer({ children, className }: MarkdownRendererProps) {\n return (\n <div className={className}>\n <ReactMarkdown\n components={MARKDOWN_COMPONENTS}\n remarkPlugins={REMARK_PLUGINS}\n >\n {children}\n </ReactMarkdown>\n </div>\n )\n}\n\n// Re-export for callers that drive ReactMarkdown themselves (CommentBody):\n// the raw component map and the plugin list, so both surfaces stay one.\nexport { MARKDOWN_COMPONENTS as markdownComponents, REMARK_PLUGINS as markdownRemarkPlugins }\n","/**\n * Kbd — semantic keyboard-input chip.\n *\n * Promoted from the Chat lens's inline title-chip markup per ADR-050 D11.\n * Committed consumers (ADR-008 D3 promotion gate):\n * • Chat lens title-bar chip (apps/workspace/src/lenses/chat/index.tsx) —\n * first migrated consumer, lands in this phase.\n * • Command palette body / footer hints (ADR-050 Phases B–E).\n * • Sidebar switcher-popout Esc hint (ADR-049 Phase C).\n *\n * Renders a `<kbd>` semantic element (screen readers announce as keyboard\n * input). Token-driven styling — no hex literals, all colors flow through\n * public tokens.\n */\n\nimport type { ReactNode, CSSProperties } from 'react'\n\nexport interface KbdProps {\n /** Child text — typically a single key glyph or short string. */\n children: ReactNode\n /** Optional size — defaults to 'md'. */\n size?: 'sm' | 'md'\n /**\n * Which surface this sits on. `neutral` is a normal page/card surface;\n * `on-accent` is inside a filled accent control (a primary button's shortcut\n * hint).\n *\n * This exists because the neutral palette is illegible on an accent fill and\n * fails quietly rather than loudly. `--text-tertiary` ink and a `--border`\n * hairline are tuned for a light-neutral ground; dropped onto `--accent` they\n * read as grey-on-red mush, which is exactly what shipped in the thread\n * composer before this prop existed — and it forked this primitive inline to\n * do it, so the bug was invisible here.\n */\n tone?: 'neutral' | 'on-accent'\n}\n\nexport function Kbd({ children, size = 'md', tone = 'neutral' }: KbdProps) {\n const onAccent = tone === 'on-accent'\n const style: CSSProperties = {\n display: 'inline-flex',\n alignItems: 'center',\n justifyContent: 'center',\n gap: '0.125rem',\n // On an accent fill the INK stays at full strength and the container does\n // the quieting. Fading the text instead is the tempting move and it is\n // wrong: white at 85% over --accent measures 4.33:1, under AA, while full\n // white is 5.64:1. The translucent fill also lightens the local ground, so\n // it raises the text's contrast rather than lowering it.\n background: onAccent\n ? 'rgb(var(--accent-foreground) / 0.16)'\n : 'rgb(var(--surface-overlay-soft))',\n border: `1px solid ${\n onAccent ? 'rgb(var(--accent-foreground) / 0.4)' : 'rgb(var(--border))'\n }`,\n color: onAccent ? 'rgb(var(--accent-foreground))' : 'rgb(var(--text-tertiary))',\n fontFamily: 'var(--font-mono)',\n fontSize: size === 'sm' ? '10.5px' : '11.5px',\n padding: size === 'sm' ? '1px 6px' : '2px 8px',\n borderRadius: 'var(--radius-xs)',\n lineHeight: 1,\n }\n return <kbd style={style}>{children}</kbd>\n}\n","/**\n * CommentBody — the stored markdown, rendered.\n *\n * ADR-147 D7 and D11.\n *\n * SECURITY, stated once and permanently: `rehype-raw` is NEVER enabled on this\n * surface, and no `rehypePlugins` are passed at all. `react-markdown` does not\n * execute raw HTML unless it is turned on, so the safe state is the default\n * state and this file's job is to not leave it. Comment bodies are user input\n * and will quote LLM output; the repo has zero `rehype-*` packages and zero\n * `dangerouslySetInnerHTML`, and this decision protects that rather than\n * repairing it. Adding either here is a security change requiring its own ADR.\n *\n * MENTIONS (D11) are ordinary markdown links with a scheme:\n *\n * @[Marcus Webb](user:usr_9f2) @[Slice B migration](task_item:tit_44a)\n *\n * Two things follow that are easy to get wrong:\n *\n * • `react-markdown`'s default `urlTransform` drops any protocol it does not\n * recognise, so `user:usr_9f2` would silently become `href=\"\"` and the\n * mention would render as inert text. The transform below preserves\n * exactly the three mention schemes and hands everything else to the\n * default sanitiser unchanged — the allowlist is the point; widening it is\n * how `javascript:` gets back in.\n * • The component map comes from the existing `MarkdownRenderer`\n * (`markdownComponents`) rather than being rewritten. `MarkdownRenderer`\n * itself takes no component overrides, so a mention-aware surface has to\n * drive `ReactMarkdown` with that same map plus one `a` override; forking\n * the map is what puts two markdown looks in one product. The remark\n * plugin list (`markdownRemarkPlugins` — GFM plus ADR-148 D13's underline)\n * is shared the same way, so the two surfaces cannot parse differently.\n */\n\nimport type { AnchorHTMLAttributes, ImgHTMLAttributes, ReactNode } from 'react'\nimport ReactMarkdown, { defaultUrlTransform } from 'react-markdown'\nimport { markdownComponents, markdownRemarkPlugins } from '../markdown'\nimport { cn } from '../lib/utils'\n\nconst MENTION_SCHEMES = ['user', 'task_item', 'task_board'] as const\nexport type MentionTargetType = (typeof MENTION_SCHEMES)[number]\n\nexport interface MentionTarget {\n readonly type: MentionTargetType\n readonly id: string\n}\n\nconst MENTION_PATTERN = new RegExp(`^(${MENTION_SCHEMES.join('|')}):(.+)$`)\n\n/** Narrows without a cast — the scheme list is the allowlist, in one place. */\nfunction isMentionScheme(value: string): value is MentionTargetType {\n return MENTION_SCHEMES.some((scheme) => scheme === value)\n}\n\n/** Parse `user:usr_9f2` into a target. Returns null for anything else. */\nexport function parseMentionHref(href: string | undefined): MentionTarget | null {\n if (href === undefined) return null\n const match = MENTION_PATTERN.exec(href)\n if (match === null) return null\n const type = match[1]\n const id = match[2]\n if (type === undefined || id === undefined) return null\n if (!isMentionScheme(type)) return null\n return { type, id }\n}\n\nfunction urlTransform(value: string): string {\n return parseMentionHref(value) === null ? defaultUrlTransform(value) : value\n}\n\nexport interface CommentBodyProps {\n readonly bodyMd: string\n /** Called when a mention chip is activated. Omitted renders an inert chip. */\n readonly onSelectMention?: ((target: MentionTarget) => void) | undefined\n readonly className?: string | undefined\n}\n\nexport function CommentBody({ bodyMd, onSelectMention, className }: CommentBodyProps) {\n const components = {\n ...markdownComponents,\n // Paragraph spacing inside a comment is tighter than the document default\n // the shared map assumes — a comment is a remark, not an article.\n p: ({ children }: { children?: ReactNode }) => (\n <p className=\"mb-[var(--space-2)] leading-[1.55] last:mb-0\" style={{ color: 'rgb(var(--foreground))' }}>\n {children}\n </p>\n ),\n // Images are outside the composer's subset — ADR-148 D3: \"images-by-markdown\n // out; ADR-151 owns attachments\" — but `` is still typeable. It\n // renders as its alt text and nothing else: no `<img>`, so no request to a\n // user-supplied URL and no empty-`src` element when the transform strips a\n // dangerous one. ADR-151: this is the entry to revisit when attachments land.\n img: ({ alt }: ImgHTMLAttributes<HTMLImageElement>) =>\n alt === undefined || alt === '' ? null : <span>{alt}</span>,\n a: ({ href, children }: AnchorHTMLAttributes<HTMLAnchorElement>) => {\n const mention = parseMentionHref(href)\n if (mention === null) {\n return (\n <a\n href={href}\n className=\"underline-offset-2 hover:underline\"\n style={{ color: 'rgb(var(--accent-ink))' }}\n target=\"_blank\"\n rel=\"noopener noreferrer\"\n >\n {children}\n </a>\n )\n }\n const interactive = onSelectMention !== undefined\n const Tag = interactive ? 'button' : 'span'\n return (\n <Tag\n {...(interactive ? { type: 'button' as const, onClick: () => { onSelectMention(mention) } } : {})}\n className={cn(\n 'inline-flex items-center align-baseline text-[12.5px] font-semibold',\n 'transition-[background-color,border-color] duration-[var(--dur-fast)] ease-[var(--ease-out)]',\n 'motion-reduce:transition-none',\n 'border border-[rgb(var(--border))] bg-[rgb(var(--surface-inset))] text-[rgb(var(--accent-ink))]',\n interactive &&\n 'hover:border-[rgb(var(--accent))] hover:bg-[rgb(var(--surface-hover))] focus-visible:outline-none focus-visible:[box-shadow:var(--ring-focus)]',\n )}\n style={{\n borderRadius: 'var(--radius-sm)',\n paddingInline: 'var(--space-1)',\n }}\n >\n {children}\n </Tag>\n )\n },\n }\n\n return (\n <div\n className={cn('text-[13px]', className)}\n style={{ color: 'rgb(var(--foreground))' }}\n >\n <ReactMarkdown\n components={components}\n remarkPlugins={markdownRemarkPlugins}\n urlTransform={urlTransform}\n >\n {bodyMd}\n </ReactMarkdown>\n </div>\n )\n}\n","/**\n * The composer's action row, shared by the plain and rich composers.\n *\n * It exists because both footers were the same shape written twice, and the\n * two things the owner asked for on 2026-09-07 both live here:\n *\n * 1. a plain/rich switcher at the inline-start, behind a thin vertical rule;\n * 2. the row must not STACK on a narrow screen. It used to be `flex-wrap`,\n * so the formatting buttons pushed Cancel and Comment onto a second line\n * and the composer grew a row taller the narrower it got — the opposite\n * of what a small screen wants.\n *\n * At a phone width even that is not enough: the fixed cluster (switcher,\n * counter, Cancel, Comment) is wider than 390px on its own, so `flex-nowrap`\n * simply overflowed sideways and cut the send button in half — trading a stack\n * for a clip. Two things drop out below `--composer-narrow`, chosen because\n * neither means anything on a touch device: the character counter, and the\n * `⌘↵` keycap on the send button. A CONTAINER query, not a media query, since\n * the composer also lives in a narrow drawer on a wide screen (interface\n * standards §3).\n *\n * The layout rule: exactly one thing may shrink, and it is the toolbar. The\n * switcher, the counter and the send cluster are `shrink-0` and always whole;\n * the toolbar sits in a `min-w-0` track that scrolls horizontally once it runs\n * out of room. Scrolling rather than hiding, because a hidden formatting\n * button is unreachable, and rather than wrapping, because the send button\n * moving is what makes a composer feel unstable.\n */\n\nimport type { ReactNode } from 'react'\nimport { PencilLine, Type } from 'lucide-react'\nimport { Button } from '../button'\nimport { cn } from '../lib/utils'\n\nexport type ComposerMode = 'plain' | 'rich'\n\nexport interface ComposerFooterProps {\n /** The formatting controls. Rendered in the one track that may shrink. */\n readonly toolbar?: ReactNode | undefined\n /** Current editor mode. Omit `onModeChange` to hide the switcher entirely. */\n readonly mode?: ComposerMode | undefined\n readonly onModeChange?: ((mode: ComposerMode) => void) | undefined\n readonly modeDisabled?: boolean | undefined\n /** Rendered between the toolbar and the send cluster (the character counter). */\n readonly meta?: ReactNode | undefined\n /** Cancel + submit. Never shrinks, never wraps. */\n readonly actions: ReactNode\n}\n\nexport function ComposerFooter({\n toolbar,\n mode,\n onModeChange,\n modeDisabled = false,\n meta,\n actions,\n}: ComposerFooterProps) {\n const showSwitcher = onModeChange !== undefined && mode !== undefined\n const next: ComposerMode = mode === 'rich' ? 'plain' : 'rich'\n\n return (\n <div\n // NOT `flex-wrap`. See the file header — wrapping is the defect.\n className=\"ds-composer-footer flex min-w-0 flex-nowrap items-center gap-[var(--space-1)]\"\n style={{ padding: '0 var(--space-2) var(--space-2)' }}\n >\n {showSwitcher ? (\n <>\n <Button\n variant=\"icon\"\n size=\"sm\"\n className=\"shrink-0\"\n aria-label={`Switch to the ${next} editor`}\n title={`Switch to the ${next} editor`}\n disabled={modeDisabled}\n onMouseDown={(event) => {\n event.preventDefault()\n }}\n onClick={() => {\n onModeChange(next)\n }}\n >\n {mode === 'rich' ? (\n <PencilLine size={12} strokeWidth={1.75} aria-hidden=\"true\" />\n ) : (\n <Type size={12} strokeWidth={1.75} aria-hidden=\"true\" />\n )}\n </Button>\n {/* The thin vertical rule the owner asked for: it separates \"which\n editor\" from \"what this editor can do\", which are different\n questions about the same box. `--space-4` tall so it reads as a\n rule beside a 24px control rather than a full-height divider. */}\n <span\n aria-hidden=\"true\"\n className=\"shrink-0\"\n style={{\n inlineSize: '1px',\n blockSize: 'var(--space-4)',\n marginInline: 'var(--space-1)',\n background: 'rgb(var(--border))',\n }}\n />\n </>\n ) : null}\n\n {/* The ONE thing that may shrink. `min-w-0` lets it actually do so\n inside a flex row, and the horizontal scroll keeps every control\n reachable instead of clipping it out of existence. */}\n <div\n className={cn(\n 'flex min-w-0 flex-1 items-center gap-[var(--space-1)]',\n 'overflow-x-auto overscroll-x-contain',\n // A scrollbar in a 24px-tall control strip is louder than the\n // controls; the row is short enough to drag or shift-wheel.\n '[scrollbar-width:none] [&::-webkit-scrollbar]:hidden',\n )}\n >\n {toolbar}\n </div>\n\n <span className=\"ds-composer-meta contents\">{meta}</span>\n {actions}\n </div>\n )\n}\n","/**\n * markdown-format — what the composer's toolbar actually DOES.\n *\n * ADR-147 D7. The reference this port replaces (`post-modal.tsx`'s\n * `RichComposer`) rendered a toolbar of buttons wired to nothing — fake\n * chrome, and the named anti-pattern of this slice. So the transform is a pure\n * function with its own tests: given the textarea's value and selection, it\n * returns the new value and the new selection. The component's only job is to\n * call it and restore the caret.\n *\n * Toggling is symmetric on purpose. A bold button that can only ever add `**`\n * is a button that punishes a misclick, and \"select it again and press it\n * again\" is the behaviour every editor has trained people to expect.\n */\n\nexport type MarkdownFormat = 'bold' | 'italic' | 'code' | 'link' | 'list'\n\nexport interface MarkdownEdit {\n readonly value: string\n readonly selectionStart: number\n readonly selectionEnd: number\n}\n\nconst WRAPPERS: Readonly<Record<'bold' | 'italic' | 'code', string>> = {\n bold: '**',\n italic: '_',\n code: '`',\n}\n\nconst LIST_PREFIX = '- '\nconst LINK_PLACEHOLDER = 'url'\n\nfunction clamp(n: number, min: number, max: number): number {\n return Math.min(Math.max(n, min), max)\n}\n\nfunction applyWrapper(\n value: string,\n start: number,\n end: number,\n marker: string,\n): MarkdownEdit {\n const selected = value.slice(start, end)\n const width = marker.length\n\n // Case 1 — the markers are INSIDE the selection: \"**bold**\" selected whole.\n if (selected.length >= width * 2 && selected.startsWith(marker) && selected.endsWith(marker)) {\n const inner = selected.slice(width, selected.length - width)\n return {\n value: value.slice(0, start) + inner + value.slice(end),\n selectionStart: start,\n selectionEnd: start + inner.length,\n }\n }\n\n // Case 2 — the markers are OUTSIDE the selection: only \"bold\" selected\n // inside \"**bold**\". Same intent, different selection; unwrap either way.\n if (\n start >= width &&\n value.slice(start - width, start) === marker &&\n value.slice(end, end + width) === marker\n ) {\n return {\n value: value.slice(0, start - width) + selected + value.slice(end + width),\n selectionStart: start - width,\n selectionEnd: start - width + selected.length,\n }\n }\n\n // Case 3 — wrap. With an empty selection this leaves the caret between the\n // markers, which is what \"press bold then type\" has to do.\n return {\n value: value.slice(0, start) + marker + selected + marker + value.slice(end),\n selectionStart: start + width,\n selectionEnd: end + width,\n }\n}\n\nfunction applyLink(value: string, start: number, end: number): MarkdownEdit {\n const selected = value.slice(start, end)\n const inserted = `[${selected}](${LINK_PLACEHOLDER})`\n const next = value.slice(0, start) + inserted + value.slice(end)\n\n if (selected === '') {\n // Nothing selected: caret goes between the brackets so the label is typed\n // first. The url placeholder is still there to be tabbed/clicked into.\n return { value: next, selectionStart: start + 1, selectionEnd: start + 1 }\n }\n // Text selected: it becomes the label and the url placeholder is selected,\n // so pasting a link immediately replaces it.\n const urlStart = start + selected.length + 3\n return {\n value: next,\n selectionStart: urlStart,\n selectionEnd: urlStart + LINK_PLACEHOLDER.length,\n }\n}\n\nfunction applyList(value: string, start: number, end: number): MarkdownEdit {\n // Lists are a LINE operation, so the selection is grown to whole lines\n // first — otherwise selecting three words in the middle of a paragraph\n // inserts a bullet mid-sentence.\n const lineStart = value.lastIndexOf('\\n', Math.max(start - 1, 0)) + 1\n const nextBreak = value.indexOf('\\n', end)\n const lineEnd = nextBreak === -1 ? value.length : nextBreak\n\n const block = value.slice(lineStart, lineEnd)\n const lines = block.split('\\n')\n const meaningful = lines.filter((line) => line.trim() !== '')\n const allPrefixed =\n meaningful.length > 0 && meaningful.every((line) => line.startsWith(LIST_PREFIX))\n\n const next = lines\n .map((line) => {\n if (allPrefixed) return line.startsWith(LIST_PREFIX) ? line.slice(LIST_PREFIX.length) : line\n return line.trim() === '' ? line : LIST_PREFIX + line\n })\n .join('\\n')\n\n return {\n value: value.slice(0, lineStart) + next + value.slice(lineEnd),\n selectionStart: lineStart,\n selectionEnd: lineStart + next.length,\n }\n}\n\n/**\n * Pure. Deterministic. No DOM.\n *\n * Out-of-range selections are clamped rather than trusted — a stale\n * `selectionStart` after a controlled re-render is a real thing, and slicing a\n * string with a negative index fails silently instead of loudly.\n */\nexport function applyMarkdownFormat(\n value: string,\n selectionStart: number,\n selectionEnd: number,\n format: MarkdownFormat,\n): MarkdownEdit {\n const start = clamp(Math.min(selectionStart, selectionEnd), 0, value.length)\n const end = clamp(Math.max(selectionStart, selectionEnd), 0, value.length)\n\n switch (format) {\n case 'bold':\n return applyWrapper(value, start, end, WRAPPERS.bold)\n case 'italic':\n return applyWrapper(value, start, end, WRAPPERS.italic)\n case 'code':\n return applyWrapper(value, start, end, WRAPPERS.code)\n case 'link':\n return applyLink(value, start, end)\n case 'list':\n return applyList(value, start, end)\n }\n}\n","/**\n * ThreadComposer — a textarea, a toolbar that actually formats, and a send.\n *\n * ADR-147 D7. Markdown over a `<textarea>`; not TipTap, not contenteditable.\n * A textarea gets undo, spellcheck, IME and mobile keyboards right for free,\n * and markdown survives into an email digest, a notification preview, an\n * agent's context window and a CSV export — none of which a ProseMirror\n * document survives without a renderer.\n *\n * Every toolbar button wires real behaviour (see markdown-format.ts). The\n * decorative toolbar in the source this replaces is the anti-pattern, and a\n * button that does nothing is worse than no button: it teaches people the\n * surface is broken.\n *\n * Keyboard: Cmd/Ctrl+Enter sends. Cmd/Ctrl+B / I / K format. Escape cancels a\n * nested reply composer when one is open.\n */\n\nimport { useCallback, useLayoutEffect, useRef } from 'react'\nimport type { KeyboardEvent, ReactNode } from 'react'\nimport { Bold, Code, CornerDownRight, Italic, Link as LinkIcon, List } from 'lucide-react'\nimport { Button } from '../button'\nimport { ComposerFooter, type ComposerMode } from './composer-footer'\nimport { Kbd } from '../kbd'\nimport { cn } from '../lib/utils'\nimport { applyMarkdownFormat, type MarkdownFormat } from './markdown-format'\n\n/**\n * The send shortcut, spelled the way the platform spells it.\n *\n * Read once at module scope from the UA rather than per render: it cannot\n * change while the page is open, and a value that is stable for the life of the\n * document must not be a render-time branch. Guarded for a non-DOM environment\n * (SSR, the test runner), where it resolves to the Ctrl form.\n */\nconst SEND_KEYCAP: string =\n typeof navigator !== 'undefined' && /Mac|iPhone|iPad/.test(navigator.userAgent)\n ? '⌘↵'\n : 'Ctrl ↵'\n\ninterface ToolbarAction {\n readonly format: MarkdownFormat\n readonly label: string\n readonly icon: typeof Bold\n readonly shortcut?: string\n}\n\nconst TOOLBAR: readonly ToolbarAction[] = [\n { format: 'bold', label: 'Bold', icon: Bold, shortcut: 'b' },\n { format: 'italic', label: 'Italic', icon: Italic, shortcut: 'i' },\n { format: 'code', label: 'Code', icon: Code },\n { format: 'link', label: 'Link', icon: LinkIcon, shortcut: 'k' },\n { format: 'list', label: 'Bulleted list', icon: List },\n]\n\nexport interface ThreadComposerProps {\n readonly value: string\n readonly onChange: (value: string) => void\n /**\n * The rich composer supplies verified attachment ticket ids. The plain\n * composer calls this with no argument, preserving its original contract.\n */\n readonly onSubmit: (attachmentIds?: readonly string[]) => void\n readonly onCancel?: (() => void) | undefined\n readonly placeholder?: string | undefined\n /** Sentence case, and it names what happens (interface standards §7). */\n readonly submitLabel?: string | undefined\n readonly cancelLabel?: string | undefined\n readonly sending?: boolean | undefined\n readonly disabled?: boolean | undefined\n /**\n * Display name of the comment being answered. Renders a \"Replying to <name>\"\n * line above the field — without it a nested composer is a naked textarea\n * some distance down a long thread, and which comment it is aimed at is\n * carried only by where it happens to sit on screen.\n */\n readonly replyingTo?: string | undefined\n readonly avatar?: ReactNode | undefined\n readonly rows?: number | undefined\n readonly autoFocus?: boolean | undefined\n /** Hide the formatting row on a cramped nested composer. */\n readonly toolbar?: boolean | undefined\n readonly maxLength?: number | undefined\n /**\n * Which editor is active, and how to change it. Both composers render the\n * switcher so a reader can get back from plain; omit `onModeChange` and no\n * switcher appears at all (a host that offers only one editor).\n */\n readonly mode?: ComposerMode | undefined\n readonly onModeChange?: ((mode: ComposerMode) => void) | undefined\n readonly label: string\n readonly className?: string | undefined\n}\n\nexport function ThreadComposer({\n value,\n onChange,\n onSubmit,\n onCancel,\n placeholder = 'Add a comment…',\n submitLabel = 'Comment',\n cancelLabel = 'Cancel',\n sending = false,\n disabled = false,\n replyingTo,\n avatar,\n rows = 3,\n autoFocus = false,\n toolbar = true,\n maxLength,\n mode,\n onModeChange,\n label,\n className,\n}: ThreadComposerProps) {\n const textareaRef = useRef<HTMLTextAreaElement>(null)\n const pendingSelection = useRef<{ start: number; end: number } | null>(null)\n\n // The textarea is controlled, so a format applied through React lands one\n // render later — the caret has to be restored after that render or every\n // toolbar press dumps the cursor at the end of the field.\n useLayoutEffect(() => {\n const selection = pendingSelection.current\n const element = textareaRef.current\n if (selection === null || element === null) return\n pendingSelection.current = null\n element.focus()\n element.setSelectionRange(selection.start, selection.end)\n }, [value])\n\n const format = useCallback(\n (next: MarkdownFormat) => {\n const element = textareaRef.current\n if (element === null) return\n const edit = applyMarkdownFormat(\n value,\n element.selectionStart,\n element.selectionEnd,\n next,\n )\n pendingSelection.current = { start: edit.selectionStart, end: edit.selectionEnd }\n onChange(edit.value)\n },\n [onChange, value],\n )\n\n const onKeyDown = useCallback(\n (event: KeyboardEvent<HTMLTextAreaElement>) => {\n const mod = event.metaKey || event.ctrlKey\n if (mod && event.key === 'Enter') {\n event.preventDefault()\n onSubmit()\n return\n }\n if (event.key === 'Escape' && onCancel !== undefined) {\n event.preventDefault()\n onCancel()\n return\n }\n if (!mod) return\n const action = TOOLBAR.find((entry) => entry.shortcut === event.key.toLowerCase())\n if (action === undefined) return\n event.preventDefault()\n format(action.format)\n },\n [format, onCancel, onSubmit],\n )\n\n const canSend = value.trim() !== '' && !sending && !disabled\n\n return (\n <div className={cn('flex flex-col gap-[var(--space-1)]', className)}>\n {replyingTo === undefined ? null : (\n <p\n className=\"flex items-center gap-[var(--space-1)] text-[12px]\"\n style={{ color: 'rgb(var(--text-tertiary))' }}\n >\n <CornerDownRight size={10} strokeWidth={1.5} aria-hidden=\"true\" />\n Replying to{' '}\n <span className=\"font-semibold\" style={{ color: 'rgb(var(--text-secondary))' }}>\n {replyingTo}\n </span>\n </p>\n )}\n <div className=\"flex items-start gap-[var(--space-2)]\">\n {avatar}\n <div\n className={cn(\n 'min-w-0 flex-1 overflow-hidden border',\n 'transition-[border-color,box-shadow] duration-[var(--dur-fast)] ease-[var(--ease-out)]',\n 'motion-reduce:transition-none',\n 'focus-within:border-[rgb(var(--accent))] focus-within:[box-shadow:var(--ring-focus)]',\n )}\n style={{\n // Concentric: the host panel declares --thread-inner-radius as its\n // own radius minus its padding (interface standards §1). Nothing\n // here eyeballs a corner.\n borderRadius: 'var(--thread-inner-radius, var(--radius-sm))',\n borderColor: 'rgb(var(--border))',\n background: 'rgb(var(--surface-card))',\n }}\n >\n <textarea\n ref={textareaRef}\n aria-label={label}\n className=\"block w-full resize-none bg-transparent outline-none\"\n placeholder={placeholder}\n rows={rows}\n value={value}\n disabled={disabled}\n autoFocus={autoFocus}\n onChange={(event) => {\n onChange(event.target.value)\n }}\n onKeyDown={onKeyDown}\n {...(maxLength === undefined ? {} : { maxLength })}\n style={{\n // Optical: vertical is a step tighter than horizontal, because the\n // line box already carries space the glyphs do not fill.\n padding: 'var(--space-2) var(--space-3)',\n color: 'rgb(var(--foreground))',\n fontFamily: 'var(--font-sans)',\n fontSize: '13px',\n lineHeight: 1.55,\n }}\n />\n <ComposerFooter\n {...(mode === undefined ? {} : { mode })}\n {...(onModeChange === undefined ? {} : { onModeChange })}\n modeDisabled={disabled}\n toolbar={\n <>\n {toolbar\n ? TOOLBAR.map((action) => {\n const Icon = action.icon\n return (\n <Button\n key={action.format}\n variant=\"icon\"\n size=\"sm\"\n aria-label={action.label}\n title={action.label}\n disabled={disabled || sending}\n onClick={() => {\n format(action.format)\n }}\n >\n <Icon size={12} strokeWidth={1.75} aria-hidden=\"true\" />\n </Button>\n )\n })\n : null}\n </>\n }\n meta={\n <>\n {maxLength === undefined ? null : (\n <span\n className=\"tabular-nums text-right\"\n // Reserved slot so the counter cannot push the buttons around.\n style={{\n minInlineSize: '7ch',\n fontSize: '11.5px',\n color:\n value.length > maxLength * 0.9\n ? 'rgb(var(--warning-ink))'\n : 'rgb(var(--text-tertiary))',\n }}\n >\n {value.length}/{maxLength}\n </span>\n )}\n </>\n }\n actions={\n <>\n {onCancel === undefined ? null : (\n <Button\n variant=\"secondary\"\n size=\"sm\"\n onClick={onCancel}\n disabled={disabled || sending}\n >\n {cancelLabel}\n </Button>\n )}\n <Button\n variant=\"primary\"\n size=\"sm\"\n onClick={() => {\n onSubmit()\n }}\n disabled={!canSend}\n // The visible keycap must not end up in the accessible name — a\n // screen reader saying \"Reply Cmd Return button\" is noise, and the\n // shortcut is announced by the field's own instructions instead.\n aria-label={sending ? 'Sending…' : submitLabel}\n // The Kbd primitive, not a fork of it. The inline version this\n // replaces carried `--text-tertiary` ink and a `--border` hairline\n // — neutral-surface tokens sitting on an accent fill, which is\n // why the shortcut read as grey mush on red.\n trailingIcon={\n <span aria-hidden=\"true\" className=\"ds-composer-keycap\">\n <Kbd size=\"sm\" tone=\"on-accent\">\n {SEND_KEYCAP}\n </Kbd>\n </span>\n }\n >\n {sending ? 'Sending…' : submitLabel}\n </Button>\n </>\n }\n />\n </div>\n </div>\n </div>\n )\n}\n","/**\n * Composer attachments — the headless half (ADR-151 D1 and D5).\n *\n * The primitive owns no fetch client and no base URL (ADR-147 D5's rule for\n * this whole package), so the host injects two functions: one that puts a\n * `Blob` somewhere and comes back with a verified ticket, and one that turns a\n * Giphy id into the same thing. Everything else — per-file progress, cancel,\n * the count and byte ceilings, the paste threshold, the undo — is here.\n *\n * ## D1: each file is its own unit\n *\n * An upload starts the moment a file lands and carries its own progress and its\n * own cancel. Send stays enabled and waits for whatever is still in flight,\n * rather than being greyed out while a 20 MB file finishes — the person is\n * usually still typing, and disabling send is how a composer starts feeling\n * like it is having a conversation with itself.\n *\n * ## D5: a large paste is an OFFER, not a seizure\n *\n * A paste of 2,500 characters or more becomes a `.txt` attachment through the\n * exact same path a dropped file takes — `new Blob([text], …)` is the whole\n * mechanism, which is why D5 is cheap once D1 exists.\n *\n * **The original string is kept verbatim on the chip**, so \"Insert as text\n * instead\" restores it byte for byte. That is not a nicety: a paste silently\n * becoming a file the person did not want is worse than a long comment, and it\n * is the first thing to get wrong. The undo lives as long as the composer does.\n *\n * The threshold is checked on the RAW pasted string, before any markdown\n * parsing — parsing 200 KB only to throw the AST away is work nobody asked for.\n */\n\nimport { useCallback, useEffect, useRef, useState } from 'react'\n\n/**\n * ADR-151 D5. Long enough that a normal paragraph, a stack trace or a pasted\n * list is never intercepted; short enough that the thing which would have\n * drowned the comment does not. Recorded here with the reasoning rather than\n * scattered as a magic number.\n */\nexport const PASTE_ATTACHMENT_THRESHOLD = 2_500\n\n/**\n * ADR-151 D4. Giphy's free tier is 100 requests/hour, and a type-as-you-search\n * picker burns that in about a minute. This debounce and the worker's\n * five-minute cache are the two halves of keeping the picker affordable;\n * neither is optional.\n */\nexport const GIF_SEARCH_DEBOUNCE_MS = 300\n\n/** Mirrors the worker's D3 caps so the composer can refuse before uploading. */\nexport const ATTACHMENT_LIMITS = {\n fileMaxBytes: 25 * 1024 * 1024,\n commentMaxBytes: 50 * 1024 * 1024,\n maxPerComment: 10,\n} as const\n\nexport type ComposerAttachmentKind = 'image' | 'gif' | 'file'\n\nexport type ComposerAttachmentState = 'uploading' | 'ready' | 'failed'\n\n/** One chip in the tray. */\nexport interface ComposerAttachment {\n /** Stable for the life of the chip, including before a ticket exists. */\n readonly localId: string\n readonly name: string\n readonly sizeBytes: number\n readonly kind: ComposerAttachmentKind\n readonly state: ComposerAttachmentState\n /** 0..1. Meaningful only while `state === 'uploading'`. */\n readonly progress: number\n /** The server's ticket. Present once `state === 'ready'`. */\n readonly ticketId?: string | undefined\n /** A message already in the product's voice, straight from the server. */\n readonly error?: string | undefined\n /** A local object URL (or a GIF still). Never a stored URL. */\n readonly previewUrl?: string | undefined\n readonly aspectRatio?: number | undefined\n /**\n * D5 — the exact text this chip was made from, kept so \"Insert as text\n * instead\" restores it byte for byte. Present only for a pasted-text chip.\n */\n readonly pastedText?: string | undefined\n /**\n * D5 — \"the character count shown on the chip\". Present only for a paste,\n * and it is the count of CHARACTERS, not of bytes: the person pasted\n * characters, and for anything non-ASCII the two differ enough that showing\n * bytes under a character label would be a small lie.\n */\n readonly charCount?: number | undefined\n}\n\n/** What the host's uploader hands back. Mirrors the worker's ticket shape. */\nexport interface AttachmentTicketLike {\n id: string\n kind: string\n name: string\n sizeBytes: number\n mime: string\n aspectRatio: number | null\n}\n\nexport interface UseAttachmentsOptions {\n /**\n * Put the bytes somewhere and come back with a verified ticket.\n *\n * The host is expected to run the upload AND the server-side verification;\n * this hook only tracks the result. `signal` must genuinely abort the\n * transfer — a cancel that only hides the chip leaves the bytes uploading.\n */\n readonly upload?: (\n file: Blob,\n opts: {\n filename: string\n signal: AbortSignal\n onProgress: (fraction: number) => void\n },\n ) => Promise<AttachmentTicketLike>\n /** Turn a Giphy id into a ticket. Omit to disable the GIF path entirely. */\n readonly attachGif?: ((giphyId: string) => Promise<AttachmentTicketLike>) | undefined\n /** Told about a refusal so the surface can say it once, in its own voice. */\n readonly onError?: ((message: string) => void) | undefined\n readonly maxPerComment?: number | undefined\n readonly maxFileBytes?: number | undefined\n readonly maxTotalBytes?: number | undefined\n}\n\nexport interface UseAttachmentsResult {\n readonly attachments: readonly ComposerAttachment[]\n /** Ready tickets in render order — what the comment POST carries. */\n readonly ticketIds: readonly string[]\n /** True while anything is still in flight. Send WAITS on this; it is not disabled by it. */\n readonly isUploading: boolean\n readonly addFiles: (files: Iterable<File>) => void\n /**\n * D5. Returns `true` when the paste was intercepted, so the caller can\n * `preventDefault()` — and `false` when it was not, so a short paste keeps\n * ADR-148 D8's existing behaviour untouched.\n */\n readonly addPastedText: (text: string) => boolean\n readonly addGif: (gif: { id: string; title: string; stillUrl: string; width: number; height: number }) => void\n /** Cancels an in-flight upload as well as dropping the chip. */\n readonly remove: (localId: string) => void\n /** D5's undo. Returns the original text and drops the chip; `null` if not a paste. */\n readonly insertAsText: (localId: string) => string | null\n readonly clear: () => void\n}\n\nlet localIdCounter = 0\nfunction nextLocalId(): string {\n localIdCounter += 1\n return `att-local-${String(localIdCounter)}`\n}\n\n/** D5: derived and honest. Never a fabricated filename. */\nexport function pastedTextFilename(index: number): string {\n return `pasted-text-${String(index)}.txt`\n}\n\n/** The threshold check, on the RAW string, before any parse. */\nexport function shouldAttachPaste(text: string): boolean {\n return text.length >= PASTE_ATTACHMENT_THRESHOLD\n}\n\nfunction kindOf(ticketKind: string): ComposerAttachmentKind {\n if (ticketKind === 'image' || ticketKind === 'gif') return ticketKind\n return 'file'\n}\n\n/** An image preview costs one object URL and no round trip. */\nfunction previewFor(file: File): string | undefined {\n if (!file.type.startsWith('image/')) return undefined\n try {\n return URL.createObjectURL(file)\n } catch {\n return undefined\n }\n}\n\nexport function useAttachments(options: UseAttachmentsOptions): UseAttachmentsResult {\n const {\n upload,\n attachGif,\n onError,\n maxPerComment = ATTACHMENT_LIMITS.maxPerComment,\n maxFileBytes = ATTACHMENT_LIMITS.fileMaxBytes,\n maxTotalBytes = ATTACHMENT_LIMITS.commentMaxBytes,\n } = options\n\n const [attachments, setAttachments] = useState<readonly ComposerAttachment[]>([])\n\n /**\n * A synchronous mirror of the list.\n *\n * The ceiling checks have to run BEFORE an upload starts, and they have to\n * see files added earlier in the same batch — drop eleven at once and the\n * eleventh must be refused, not started against a list that has not\n * re-rendered. Reading that from a `setState` updater would mean doing the\n * work inside it, which React is explicitly allowed to run twice. So the\n * mirror is the read path and `setAttachments` stays a pure write.\n */\n const listRef = useRef<readonly ComposerAttachment[]>([])\n\n const commit = useCallback(\n (next: (current: readonly ComposerAttachment[]) => readonly ComposerAttachment[]) => {\n const value = next(listRef.current)\n listRef.current = value\n setAttachments(value)\n },\n [],\n )\n\n // Live handles the render never reads. Keeping them in refs is what lets a\n // cancel reach an upload that started three renders ago.\n const controllers = useRef(new Map<string, AbortController>())\n const objectUrls = useRef(new Set<string>())\n const pasteCount = useRef(0)\n // The uploader and the error sink change identity on most renders in a\n // typical host; reading them through a ref keeps `addFiles` stable so the\n // composer's own memoized handlers do not churn.\n const uploadRef = useRef(upload)\n const errorRef = useRef(onError)\n uploadRef.current = upload\n errorRef.current = onError\n const gifRef = useRef(attachGif)\n gifRef.current = attachGif\n\n // Revoke every object URL that is still outstanding, on unmount. Individual\n // URLs are released by `releasePreview` as their chips go — see there for why\n // that release is deferred rather than immediate.\n useEffect(() => {\n const urls = objectUrls.current\n const inFlight = controllers.current\n return () => {\n for (const url of urls) URL.revokeObjectURL(url)\n urls.clear()\n for (const controller of inFlight.values()) controller.abort()\n inFlight.clear()\n }\n }, [])\n\n /**\n * Release one preview's object URL, a beat after its chip is gone.\n *\n * Revoking immediately is wrong: a chip can be removed while its `<img>` is\n * still painting the very frame being torn down, and pulling the URL out from\n * under it turns the preview into a broken icon on the way out. Never\n * revoking is also wrong, and was the previous behaviour — `clear()` runs\n * after every successful send, so a long-lived composer accumulated the File\n * blob of every image ever attached until it unmounted.\n *\n * A macrotask is enough: React has committed the removal by then, so nothing\n * is left holding the URL.\n */\n const releasePreview = useCallback((url: string | undefined) => {\n if (url === undefined || !objectUrls.current.has(url)) return\n objectUrls.current.delete(url)\n setTimeout(() => {\n URL.revokeObjectURL(url)\n }, 0)\n }, [])\n\n const patch = useCallback(\n (localId: string, next: Partial<ComposerAttachment>) => {\n commit((current) => current.map((a) => (a.localId === localId ? { ...a, ...next } : a)))\n },\n [commit],\n )\n\n const fail = useCallback((message: string) => {\n errorRef.current?.(message)\n }, [])\n\n /**\n * The one path every attachment takes — a dropped file, a pasted string, a\n * GIF. D5's \"there is no second upload mechanism\" is this function having\n * exactly one caller shape.\n */\n const start = useCallback(\n (\n blob: Blob,\n meta: {\n name: string\n kind: ComposerAttachmentKind\n previewUrl?: string | undefined\n pastedText?: string | undefined\n charCount?: number | undefined\n },\n ) => {\n const uploader = uploadRef.current\n // A rich composer can exist without a host upload seam. In that case\n // files and long text stay in their native paths rather than becoming\n // chips that can never finish.\n if (uploader === undefined) return\n const localId = nextLocalId()\n const controller = new AbortController()\n controllers.current.set(localId, controller)\n if (meta.previewUrl !== undefined) objectUrls.current.add(meta.previewUrl)\n\n commit((current) => [\n ...current,\n {\n localId,\n name: meta.name,\n sizeBytes: blob.size,\n kind: meta.kind,\n state: 'uploading',\n progress: 0,\n previewUrl: meta.previewUrl,\n pastedText: meta.pastedText,\n charCount: meta.charCount,\n },\n ])\n\n void uploader(blob, {\n filename: meta.name,\n signal: controller.signal,\n onProgress: (fraction) => {\n patch(localId, { progress: Math.max(0, Math.min(1, fraction)) })\n },\n })\n .then((ticket) => {\n controllers.current.delete(localId)\n patch(localId, {\n state: 'ready',\n progress: 1,\n ticketId: ticket.id,\n // The server's own account wins over the local guess: it read the\n // magic number and we read a filename.\n name: ticket.name,\n sizeBytes: ticket.sizeBytes,\n kind: kindOf(ticket.kind),\n ...(ticket.aspectRatio === null ? {} : { aspectRatio: ticket.aspectRatio }),\n })\n })\n .catch((err: unknown) => {\n controllers.current.delete(localId)\n // A cancel is not a failure and must not leave a red chip behind —\n // `remove` has already dropped it.\n if (err instanceof DOMException && err.name === 'AbortError') return\n const message =\n err instanceof Error && err.message.length > 0\n ? err.message\n : \"That file couldn't be attached.\"\n patch(localId, { state: 'failed', error: message })\n fail(message)\n })\n\n return localId\n },\n [commit, fail, patch],\n )\n\n /**\n * The two ceilings, checked before an upload starts.\n *\n * A courtesy, never the check: the worker re-measures both against the bytes\n * R2 actually holds, so a client that skipped this entirely is refused all\n * the same. What it buys is that a 30 MB file is refused in front of the\n * person instead of two minutes later.\n */\n const admits = useCallback(\n (size: number, label: string): boolean => {\n const current = listRef.current\n if (current.length >= maxPerComment) {\n fail(`You can attach up to ${String(maxPerComment)} files to a comment.`)\n return false\n }\n if (size > maxFileBytes) {\n fail(`${label} is too large. Files can be up to 25 MB.`)\n return false\n }\n const total = current.reduce((sum, a) => sum + a.sizeBytes, 0)\n if (total + size > maxTotalBytes) {\n fail('That would put this comment over 50 MB of attachments.')\n return false\n }\n return true\n },\n [fail, maxFileBytes, maxPerComment, maxTotalBytes],\n )\n\n const addFiles = useCallback(\n (files: Iterable<File>) => {\n if (uploadRef.current === undefined) return\n // `start` writes through `commit`, which updates the mirror synchronously\n // — so the ceiling check on the second file already counts the first.\n //\n // `continue`, NOT `break`. An earlier version stopped at the first\n // refusal, so dropping five files where the second was 30 MB uploaded\n // the first, reported the second, and made the last three vanish with no\n // message at all. D3 requires every refusal be named and shown; three\n // files disappearing silently is the exact failure that rule exists to\n // prevent. Skipping the oversized one and carrying on is also what a\n // person means by dropping a folder.\n for (const file of files) {\n if (!admits(file.size, file.name)) continue\n const preview = previewFor(file)\n start(file, {\n name: file.name,\n kind: file.type.startsWith('image/') ? 'image' : 'file',\n previewUrl: preview,\n })\n }\n },\n [admits, start],\n )\n\n const addPastedText = useCallback(\n (text: string): boolean => {\n if (uploadRef.current === undefined) return false\n if (!shouldAttachPaste(text)) return false\n pasteCount.current += 1\n const name = pastedTextFilename(pasteCount.current)\n const blob = new Blob([text], { type: 'text/plain' })\n if (!admits(blob.size, 'That paste')) {\n // Refused for size or count: it stays PROSE rather than vanishing. The\n // caller does not preventDefault, so the paste lands in the body.\n pasteCount.current -= 1\n return false\n }\n start(blob, { name, kind: 'file', pastedText: text, charCount: text.length })\n return true\n },\n [admits, start],\n )\n\n const addGif = useCallback(\n (gif: { id: string; title: string; stillUrl: string; width: number; height: number }) => {\n const attach = gifRef.current\n if (attach === undefined) return\n if (listRef.current.length >= maxPerComment) {\n fail(`You can attach up to ${String(maxPerComment)} files to a comment.`)\n return\n }\n const localId = nextLocalId()\n commit((current) => [\n ...current,\n {\n localId,\n name: gif.title.length > 0 ? gif.title : 'GIF',\n sizeBytes: 0,\n kind: 'gif',\n state: 'uploading',\n progress: 0,\n previewUrl: gif.stillUrl,\n ...(gif.height > 0 ? { aspectRatio: gif.width / gif.height } : {}),\n },\n ])\n\n void attach(gif.id)\n .then((ticket) => {\n patch(localId, {\n state: 'ready',\n progress: 1,\n ticketId: ticket.id,\n name: ticket.name,\n sizeBytes: ticket.sizeBytes,\n kind: 'gif',\n ...(ticket.aspectRatio === null ? {} : { aspectRatio: ticket.aspectRatio }),\n })\n })\n .catch((err: unknown) => {\n const message =\n err instanceof Error && err.message.length > 0\n ? err.message\n : \"That GIF couldn't be attached.\"\n patch(localId, { state: 'failed', error: message })\n fail(message)\n })\n },\n [commit, fail, maxPerComment, patch],\n )\n\n const remove = useCallback(\n (localId: string) => {\n // Abort FIRST. A chip that disappears while its bytes keep uploading is a\n // cancel that cancelled nothing.\n controllers.current.get(localId)?.abort()\n controllers.current.delete(localId)\n releasePreview(listRef.current.find((a) => a.localId === localId)?.previewUrl)\n commit((current) => current.filter((a) => a.localId !== localId))\n },\n [commit, releasePreview],\n )\n\n const insertAsText = useCallback(\n (localId: string): string | null => {\n const found = listRef.current.find((a) => a.localId === localId)\n const text = found?.pastedText ?? null\n if (text === null) return null\n controllers.current.get(localId)?.abort()\n controllers.current.delete(localId)\n releasePreview(found?.previewUrl)\n commit((current) => current.filter((a) => a.localId !== localId))\n return text\n },\n [commit, releasePreview],\n )\n\n const clear = useCallback(() => {\n for (const controller of controllers.current.values()) controller.abort()\n controllers.current.clear()\n for (const attachment of listRef.current) releasePreview(attachment.previewUrl)\n commit(() => [])\n }, [commit, releasePreview])\n\n return {\n attachments,\n ticketIds: attachments\n .filter((a) => a.state === 'ready' && a.ticketId !== undefined)\n .map((a) => a.ticketId ?? ''),\n isUploading: attachments.some((a) => a.state === 'uploading'),\n addFiles,\n addPastedText,\n addGif,\n remove,\n insertAsText,\n clear,\n }\n}\n\n/**\n * Resolve a posted attachment's short-lived URL, once, lazily (ADR-151 D6).\n *\n * The wire carries no URL — the storage key never leaves the worker — so a\n * renderer is handed the SHAPE of the slot and asks for the bytes separately.\n * The box is already reserved from the declared aspect ratio by the time this\n * runs, which is the whole point of the ordering: nothing reflows when the\n * picture lands, or fails to.\n *\n * `null` means \"asked and could not have it\", and the caller renders the\n * placeholder — never a collapsed box.\n */\nexport function useAttachmentUrl(\n attachmentId: string,\n resolve: ((attachmentId: string) => Promise<string | null>) | undefined,\n): { url: string | null; failed: boolean; loading: boolean } {\n const [url, setUrl] = useState<string | null>(null)\n const [failed, setFailed] = useState(false)\n /**\n * Distinct from `failed`, and the distinction is the whole point.\n *\n * An earlier version rendered the broken-image placeholder whenever there was\n * no URL — which meant every attachment showed the failure treatment for the\n * whole time it was resolving. D6 asks for a placeholder when an image is\n * BROKEN; showing it while the answer is still on its way tells the reader\n * something untrue about their own comment.\n */\n const [loading, setLoading] = useState(resolve !== undefined)\n\n /**\n * The resolver is read through a ref and is NOT a dependency.\n *\n * This is deliberate and it is load-bearing. The resolver arrives from the\n * host, through `ThreadProps` and the render context, and a host that writes\n * `resolveAttachmentUrl={(id) => api.attachmentUrl(brandId, …, id)}` — which\n * is the obvious and correct-looking way to write it — hands over a NEW\n * function identity on every render. With that in the dependency array the\n * effect re-runs, sets state, re-renders, and re-runs: an infinite fetch loop\n * that presents as a hung tab or an out-of-memory test, not as an error.\n *\n * So the effect keys on the attachment id, which is the thing that actually\n * identifies what to fetch, plus whether a resolver exists at all (so a host\n * that supplies one late still resolves). A resolver whose BEHAVIOUR changes\n * without the id changing is not a case that occurs: a different brand or a\n * different thread brings different attachment ids with it.\n */\n const resolveRef = useRef(resolve)\n resolveRef.current = resolve\n const enabled = resolve !== undefined\n\n useEffect(() => {\n const current = resolveRef.current\n if (current === undefined) return\n let live = true\n setUrl(null)\n setFailed(false)\n setLoading(true)\n void current(attachmentId)\n .then((next) => {\n if (!live) return\n if (next === null || next.length === 0) setFailed(true)\n else setUrl(next)\n setLoading(false)\n })\n .catch(() => {\n if (!live) return\n setFailed(true)\n setLoading(false)\n })\n return () => {\n live = false\n }\n }, [attachmentId, enabled])\n\n return { url, failed, loading }\n}\n","/**\n * Composer attachments — the rendered half (ADR-151 D1, D4, D5, D6).\n *\n * Four things live here, and they are together because they are one feature\n * seen from four places: the tray of chips under the composer, the button and\n * drop target that fill it, the GIF picker that fills it a different way, and\n * the renderers a posted comment uses.\n *\n * ## Reserve the slot, always\n *\n * Every surface below declares its box before it has anything to put in it —\n * the chip has a fixed height, the progress bar occupies its row whether or not\n * it is moving, the thumbnail uses the declared `aspectRatio`, and a broken\n * image becomes a placeholder inside the same box rather than a collapse. The\n * layout is not allowed to depend on whether bytes arrived.\n *\n * ## Motion\n *\n * `prefers-reduced-motion` is not decoration here. An autoplaying wall of GIFs\n * is the single most reduced-motion-hostile thing this product could ship\n * (ADR-151 D4), so under that preference a GIF renders as a still frame with an\n * explicit play control, and pressing play is a choice the person made. A\n * Giphy pick stores an **mp4**, so its `<video>` can genuinely hold the first\n * frame. An uploaded GIF stays `kind: 'image'`; its renderer snapshots the\n * loaded `<img>` to a canvas once and shows that still until the person elects\n * to swap the live image back in.\n *\n * ## \"Powered by GIPHY\"\n *\n * Rendered in the picker. `TODO(legal):` required by Giphy's terms; noted once\n * here and in ADR-151 D4, not litigated.\n *\n * ## Why this is not `packages/ui/src/file-upload/*`\n *\n * That family already ships — `FileUploadButton`, `FileDropZone`,\n * `FilePreviewGrid`, `useFileUpload` — and CLAUDE.md §2 is explicit that\n * forking a primitive is a defect. This is a deliberate exception, and the\n * reasons are specific rather than aesthetic:\n *\n * - **`useFileUpload` allows what ADR-151 D3 forbids.** Its accept list\n * includes `text/html`, `application/javascript` and Office documents; D3\n * enumerates nine formats and refuses everything else by name.\n * - **It uploads directly.** It drives its own XHR to a destination; D1\n * requires the two-step dance — bytes to the engine, then a server-verified\n * ticket — and the tray's states are `uploading | ready | failed` against\n * that ticket, not against a transfer.\n * - **Its 20 MB cap is hardcoded** and disagrees with D3's 25 MB, and it has\n * no per-comment total at all.\n * - **It calls `toast` internally**, so a refusal is announced by the\n * primitive rather than reported to the surface, and this composer needs\n * the message inline on the chip.\n * - Nothing in it has a concept of a pasted-text chip, an \"Insert as text\n * instead\" undo, or a GIF.\n *\n * **What that fork costs, stated rather than discovered later:** `FileDropZone`\n * recurses into dropped FOLDERS via `FileSystemEntry`; `AttachmentDropZone`\n * takes `dataTransfer.files` only, so dropping a folder attaches nothing. If\n * folder drop is wanted here, lift that traversal out of `file-upload/` into a\n * shared helper rather than copying it a second time.\n *\n * Recorded in `docs/follow-ups/_pending/adr-151-attachments-open-edges.md` §8\n * as well, because a fork that is only justified in a file header is a fork\n * nobody finds.\n */\n\nimport {\n useCallback,\n useEffect,\n useId,\n useRef,\n useState,\n type DragEvent,\n type ReactNode,\n} from 'react'\nimport { FileText, Image as ImageIcon, ImageOff, Paperclip, Play, Search, X } from 'lucide-react'\nimport { Button } from '../button'\nimport { Input } from '../input'\nimport { cn } from '../lib/utils'\nimport {\n GIF_SEARCH_DEBOUNCE_MS,\n useAttachmentUrl,\n type ComposerAttachment,\n} from './use-attachments'\nimport type { ThreadAttachment } from './types'\n\n/* ── shared bits ────────────────────────────────────────────────────────── */\n\n/**\n * The same quiet icon button `actions.tsx` uses, for the same reason.\n *\n * Exported (module-level, NOT from the package barrel) because `link-preview.tsx`\n * needs the identical treatment for the identical reason: a 12px dismiss cross\n * sitting inside an already-bordered card. Sharing the constant is what keeps\n * \"pick one hover treatment and use it for every interactive surface\" true;\n * `actions.tsx` holds a second, older copy of this pair, and a FOURTH consumer\n * should promote the three of them into one module rather than copy it again.\n *\n * CLAUDE.md §2 bans `ghost` as the DEFAULT lesser button — \"buttons must read\n * as buttons\" — with the exception it names being \"genuinely chrome-dense\n * contexts … inline icon toolbars\". A 12px remove-cross inside a chip is that\n * exception: a bordered button inside a bordered chip is two borders 4px apart,\n * and the chip already reads as a button-shaped thing. The primary action of\n * this whole surface is the composer's send, and it stays the only filled one.\n */\nexport const QUIET_ICON = cn(\n 'inline-flex shrink-0 items-center justify-center border-0 bg-transparent',\n 'text-[rgb(var(--text-tertiary))]',\n 'transition-[background-color,color] duration-[var(--dur-fast)] ease-[var(--ease-out)]',\n 'motion-reduce:transition-none',\n 'hover:bg-[rgb(var(--surface-overlay))] hover:text-[rgb(var(--foreground))]',\n 'focus-visible:outline-none focus-visible:[box-shadow:var(--ring-focus)]',\n 'disabled:cursor-default disabled:opacity-60',\n)\n\n/** The 24px hit-area floor from the interface standards §6, met by padding. */\nexport const QUIET_ICON_BOX = {\n minBlockSize: 'var(--space-6)',\n minInlineSize: 'var(--space-6)',\n borderRadius: 'var(--radius-xs)',\n} as const\n\n/**\n * \"2,500 characters\" — grouped, because the whole reason this chip exists is\n * that the number is large, and an ungrouped five-digit run is the one shape a\n * reader cannot size at a glance.\n */\nexport function formatCharacterCount(count: number): string {\n const n = Math.max(0, Math.round(count))\n return `${n.toLocaleString('en-US')} ${n === 1 ? 'character' : 'characters'}`\n}\n\nexport function formatAttachmentSize(bytes: number): string {\n if (!Number.isFinite(bytes) || bytes <= 0) return ''\n if (bytes < 1024) return `${String(bytes)} B`\n if (bytes < 1024 * 1024) return `${String(Math.round(bytes / 1024))} KB`\n return `${(bytes / (1024 * 1024)).toFixed(1)} MB`\n}\n\n/**\n * Does this viewer want less motion?\n *\n * Read as state and subscribed to, not read once: the preference can change\n * while the page is open, and a GIF that keeps playing after someone turns\n * reduced motion on has ignored them at the moment they asked.\n */\nexport function usePrefersReducedMotion(): boolean {\n const [reduced, setReduced] = useState(false)\n useEffect(() => {\n if (typeof window === 'undefined' || typeof window.matchMedia !== 'function') return\n const query = window.matchMedia('(prefers-reduced-motion: reduce)')\n setReduced(query.matches)\n const onChange = (event: MediaQueryListEvent) => {\n setReduced(event.matches)\n }\n query.addEventListener('change', onChange)\n return () => {\n query.removeEventListener('change', onChange)\n }\n }, [])\n return reduced\n}\n\n/* ── the tray (D1, D5) ──────────────────────────────────────────────────── */\n\nexport interface AttachmentTrayProps {\n readonly attachments: readonly ComposerAttachment[]\n readonly onRemove: (localId: string) => void\n /**\n * D5's undo. Given only for pasted-text chips; the action does not render on\n * anything else, because there is nothing to restore.\n */\n readonly onInsertAsText?: ((localId: string) => void) | undefined\n readonly className?: string | undefined\n}\n\n/**\n * The chips under the composer.\n *\n * Nothing here is a pill: chips are lightly-rounded bars, per the data-display\n * recipe. The row reserves its own height so adding the first attachment does\n * not shove the editor upward, and the progress bar keeps its track whether or\n * not it is moving.\n */\nexport function AttachmentTray({\n attachments,\n onRemove,\n onInsertAsText,\n className,\n}: AttachmentTrayProps) {\n if (attachments.length === 0) return null\n return (\n <ul\n className={cn('flex list-none flex-wrap gap-[var(--space-2)] p-0', className)}\n style={{ marginBlockStart: 'var(--space-2)' }}\n >\n {attachments.map((attachment) => (\n <AttachmentChip\n key={attachment.localId}\n attachment={attachment}\n onRemove={onRemove}\n {...(onInsertAsText === undefined ? {} : { onInsertAsText })}\n />\n ))}\n </ul>\n )\n}\n\nfunction AttachmentChip({\n attachment,\n onRemove,\n onInsertAsText,\n}: {\n attachment: ComposerAttachment\n onRemove: (localId: string) => void\n onInsertAsText?: ((localId: string) => void) | undefined\n}) {\n const uploading = attachment.state === 'uploading'\n const failed = attachment.state === 'failed'\n const restorable = onInsertAsText !== undefined && attachment.pastedText !== undefined\n\n return (\n <li\n className={cn(\n 'flex min-w-0 items-center gap-[var(--space-2)] border px-[var(--space-2)] py-[var(--space-1)]',\n 'text-[12px]',\n )}\n style={{\n borderRadius: 'var(--radius-sm)',\n borderColor: failed ? 'rgb(var(--destructive))' : 'rgb(var(--border))',\n // `--muted`, not `--surface-overlay*`. CLAUDE.md §2 names chips as\n // exactly what the flat opaque grey is for; the translucent overlay\n // tints wash out when they stack on another layer, and a chip inside a\n // composer inside a card is two layers deep already.\n background: 'rgb(var(--muted))',\n // The chip's height cannot depend on whether it holds a thumbnail, a\n // progress bar or an error, or the composer would jump on every state\n // change. One declared minimum, three contents.\n minBlockSize: 'var(--ctrl-md)',\n maxInlineSize: 'calc(var(--space-12) * 5)',\n }}\n >\n <AttachmentChipThumb attachment={attachment} />\n\n <span className=\"flex min-w-0 flex-col\">\n <span className=\"truncate\" style={{ color: 'rgb(var(--foreground))' }}>\n {attachment.name}\n </span>\n <span\n className=\"flex items-center gap-[var(--space-2)] tabular-nums\"\n style={{\n color: failed ? 'rgb(var(--destructive))' : 'rgb(var(--text-tertiary))',\n // Reserved so the second line exists before there is anything on it.\n minBlockSize: 'var(--space-4)',\n }}\n >\n {failed ? (\n <span className=\"truncate\">{attachment.error ?? 'Upload failed'}</span>\n ) : uploading ? (\n <AttachmentProgress value={attachment.progress} label={attachment.name} />\n ) : attachment.charCount === undefined ? (\n <span>{formatAttachmentSize(attachment.sizeBytes)}</span>\n ) : (\n // D5, verbatim: \"the character count shown on the chip\". A byte\n // size would be the wrong unit here — the person pasted characters,\n // and for anything non-ASCII the two numbers differ.\n <span>{formatCharacterCount(attachment.charCount)}</span>\n )}\n </span>\n </span>\n\n {restorable ? (\n <Button\n type=\"button\"\n variant=\"secondary\"\n size=\"sm\"\n onClick={() => {\n onInsertAsText?.(attachment.localId)\n }}\n >\n Insert as text instead\n </Button>\n ) : null}\n\n <button\n type=\"button\"\n aria-label={uploading ? `Cancel ${attachment.name}` : `Remove ${attachment.name}`}\n className={QUIET_ICON}\n style={QUIET_ICON_BOX}\n onClick={() => {\n onRemove(attachment.localId)\n }}\n >\n <X size={12} strokeWidth={1.75} aria-hidden=\"true\" />\n </button>\n </li>\n )\n}\n\n/** A square thumbnail slot that exists whether or not there is an image in it. */\nfunction AttachmentChipThumb({ attachment }: { attachment: ComposerAttachment }) {\n const visual = attachment.kind === 'image' || attachment.kind === 'gif'\n return (\n <span\n className=\"flex shrink-0 items-center justify-center overflow-hidden border\"\n style={{\n inlineSize: 'var(--space-6)',\n blockSize: 'var(--space-6)',\n borderRadius: 'var(--radius-xs)',\n borderColor: 'rgb(var(--border))',\n background: 'rgb(var(--muted))',\n color: 'rgb(var(--text-tertiary))',\n }}\n >\n {visual && attachment.previewUrl !== undefined ? (\n <img src={attachment.previewUrl} alt=\"\" className=\"h-full w-full object-cover\" />\n ) : visual ? (\n <ImageIcon size={12} strokeWidth={1.5} aria-hidden=\"true\" />\n ) : (\n <FileText size={12} strokeWidth={1.5} aria-hidden=\"true\" />\n )}\n </span>\n )\n}\n\n/**\n * A determinate bar in a track that is always there.\n *\n * `role=\"progressbar\"` with the real values, so a screen reader gets the number\n * rather than a decorative div. The transition is on `inline-size` alone and\n * drops out under reduced motion — this is a data change, and D-principles say\n * data settles with ease-out and never springs.\n */\nfunction AttachmentProgress({ value, label }: { value: number; label: string }) {\n const percent = Math.round(Math.max(0, Math.min(1, value)) * 100)\n return (\n <span\n role=\"progressbar\"\n aria-label={`Uploading ${label}`}\n aria-valuemin={0}\n aria-valuemax={100}\n aria-valuenow={percent}\n className=\"block overflow-hidden\"\n style={{\n inlineSize: 'calc(var(--space-12) * 2)',\n blockSize: 'var(--space-1)',\n borderRadius: 'var(--radius-full)',\n background: 'rgb(var(--muted))',\n }}\n >\n <span\n className=\"block transition-[inline-size] duration-[var(--dur-base)] ease-[var(--ease-out)] motion-reduce:transition-none\"\n style={{\n inlineSize: `${String(percent)}%`,\n blockSize: '100%',\n background: 'rgb(var(--accent))',\n }}\n />\n </span>\n )\n}\n\n/* ── the button + the drop target (D1) ──────────────────────────────────── */\n\nexport interface AttachmentButtonProps {\n readonly onFiles: (files: FileList) => void\n /** `accept` for the file input. Mirrors the server's extension allowlist. */\n readonly accept?: string | undefined\n readonly disabled?: boolean | undefined\n readonly label?: string | undefined\n}\n\n/** The paperclip. A real `<input type=\"file\">` behind a labelled button. */\nexport function AttachmentButton({\n onFiles,\n accept,\n disabled = false,\n label = 'Attach a file',\n}: AttachmentButtonProps) {\n const inputRef = useRef<HTMLInputElement>(null)\n const inputId = useId()\n return (\n <>\n <input\n ref={inputRef}\n id={inputId}\n type=\"file\"\n multiple\n hidden\n {...(accept === undefined ? {} : { accept })}\n onChange={(event) => {\n const { files } = event.currentTarget\n if (files !== null && files.length > 0) onFiles(files)\n // Reset so re-choosing the SAME file fires `change` again.\n event.currentTarget.value = ''\n }}\n />\n <button\n type=\"button\"\n aria-label={label}\n className={QUIET_ICON}\n style={QUIET_ICON_BOX}\n disabled={disabled}\n onClick={() => {\n inputRef.current?.click()\n }}\n >\n <Paperclip size={14} strokeWidth={1.75} aria-hidden=\"true\" />\n </button>\n </>\n )\n}\n\nexport interface AttachmentDropZoneProps {\n readonly onFiles: (files: FileList) => void\n readonly disabled?: boolean | undefined\n readonly children: ReactNode\n readonly className?: string | undefined\n}\n\n/**\n * Wrap the composer to accept a drop.\n *\n * The overlay is `visibility`-toggled inside a slot that is always present, so\n * a drag does not resize the composer — same reserve-the-slot rule as\n * everything else here. The drag counter exists because `dragleave` fires when\n * the pointer crosses a CHILD boundary, and a naive boolean flickers the\n * overlay every time the cursor passes over the toolbar.\n */\nexport function AttachmentDropZone({\n onFiles,\n disabled = false,\n children,\n className,\n}: AttachmentDropZoneProps) {\n const depth = useRef(0)\n const [over, setOver] = useState(false)\n\n const onDragEnter = useCallback(\n (event: DragEvent<HTMLDivElement>) => {\n if (disabled || !Array.from(event.dataTransfer.types).includes('Files')) return\n depth.current += 1\n setOver(true)\n },\n [disabled],\n )\n\n const onDragLeave = useCallback(() => {\n depth.current = Math.max(0, depth.current - 1)\n if (depth.current === 0) setOver(false)\n }, [])\n\n return (\n <div\n className={cn('relative', className)}\n onDragEnter={onDragEnter}\n onDragOver={(event) => {\n if (!disabled && Array.from(event.dataTransfer.types).includes('Files')) {\n event.preventDefault()\n }\n }}\n onDragLeave={onDragLeave}\n onDrop={(event) => {\n depth.current = 0\n setOver(false)\n if (disabled) return\n const { files } = event.dataTransfer\n if (files.length === 0) return\n event.preventDefault()\n onFiles(files)\n }}\n >\n {children}\n <div\n aria-hidden=\"true\"\n className=\"pointer-events-none absolute inset-0 flex items-center justify-center border border-dashed transition-opacity duration-[var(--dur-fast)] ease-[var(--ease-out)] motion-reduce:transition-none\"\n style={{\n visibility: over ? 'visible' : 'hidden',\n opacity: over ? 1 : 0,\n borderRadius: 'var(--radius-md)',\n borderColor: 'rgb(var(--accent))',\n background: 'rgb(var(--accent-subtle))',\n color: 'rgb(var(--accent-ink))',\n }}\n >\n Drop to attach\n </div>\n </div>\n )\n}\n\n/* ── the GIF picker (D4) ────────────────────────────────────────────────── */\n\nexport interface GifPickerResult {\n readonly id: string\n readonly title: string\n readonly previewUrl: string\n readonly stillUrl: string\n readonly width: number\n readonly height: number\n}\n\nexport interface GifPickerProps {\n /** Injected by the host — the primitive owns no fetch client (ADR-147 D5). */\n readonly search: (query: string) => Promise<readonly GifPickerResult[]>\n readonly onPick: (gif: GifPickerResult) => void\n readonly className?: string | undefined\n}\n\n/**\n * Type-to-search, debounced, with the still frame under reduced motion.\n *\n * The debounce is `GIF_SEARCH_DEBOUNCE_MS` and it is load-bearing rather than\n * polish: Giphy's free tier is 100 requests/hour and an undebounced picker\n * spends it in a minute.\n *\n * The grid reserves its own height so results appearing does not shove the\n * composer, and every tile declares its aspect ratio so the grid does not\n * reflow as renditions load at different sizes.\n */\nexport function GifPicker({ search, onPick, className }: GifPickerProps) {\n const [query, setQuery] = useState('')\n const [results, setResults] = useState<readonly GifPickerResult[]>([])\n const [state, setState] = useState<'idle' | 'searching' | 'error'>('idle')\n const reduced = usePrefersReducedMotion()\n const listId = useId()\n\n /**\n * `search` is read through a ref and is NOT a dependency — the same hazard\n * `useAttachmentUrl` documents. A host writing\n * `search={(q) => api.searchGifs(brandId, q)}` hands over a new identity every\n * render; with that in the dependency array this effect would re-run, call\n * `setState('searching')`, re-render, and re-run forever. The query is what\n * identifies a search, and it is the only thing that should restart one.\n */\n const searchRef = useRef(search)\n searchRef.current = search\n\n useEffect(() => {\n const trimmed = query.trim()\n if (trimmed.length === 0) {\n setResults([])\n setState('idle')\n return\n }\n let live = true\n setState('searching')\n const timer = setTimeout(() => {\n void searchRef\n .current(trimmed)\n .then((next) => {\n if (!live) return\n setResults(next)\n setState('idle')\n })\n .catch(() => {\n if (!live) return\n setResults([])\n setState('error')\n })\n }, GIF_SEARCH_DEBOUNCE_MS)\n return () => {\n live = false\n clearTimeout(timer)\n }\n }, [query])\n\n return (\n <div className={cn('flex flex-col gap-[var(--space-3)]', className)}>\n <Input\n value={query}\n onChange={(event) => {\n setQuery(event.currentTarget.value)\n }}\n placeholder=\"Search GIFs\"\n aria-label=\"Search GIFs\"\n aria-controls={listId}\n leadingAffix={<Search size={14} strokeWidth={1.75} aria-hidden=\"true\" />}\n />\n\n <div\n id={listId}\n className=\"grid grid-cols-3 gap-[var(--space-2)] overflow-y-auto\"\n style={{\n // Declared, so the panel is the same size empty, searching and full.\n blockSize: 'calc(var(--space-12) * 6)',\n }}\n >\n {results.map((gif) => (\n <button\n key={gif.id}\n type=\"button\"\n onClick={() => {\n onPick(gif)\n }}\n className=\"block overflow-hidden border transition-[border-color] duration-[var(--dur-fast)] ease-[var(--ease-out)] hover:border-[rgb(var(--border-strong))] focus-visible:outline-none focus-visible:[box-shadow:var(--ring-focus)] motion-reduce:transition-none\"\n style={{\n borderRadius: 'var(--radius-sm)',\n borderColor: 'rgb(var(--border))',\n background: 'rgb(var(--muted))',\n aspectRatio: gif.height > 0 ? String(gif.width / gif.height) : '1',\n }}\n >\n {reduced ? (\n <img src={gif.stillUrl} alt={gif.title} className=\"h-full w-full object-cover\" />\n ) : (\n <video\n src={gif.previewUrl}\n poster={gif.stillUrl}\n autoPlay\n loop\n muted\n playsInline\n aria-label={gif.title}\n className=\"h-full w-full object-cover\"\n />\n )}\n </button>\n ))}\n {results.length === 0 ? (\n <p\n className=\"col-span-3 self-center text-center text-[12px]\"\n style={{ color: 'rgb(var(--text-tertiary))' }}\n >\n {state === 'error'\n ? \"GIF search isn't available right now.\"\n : state === 'searching'\n ? 'Searching…'\n : query.trim().length === 0\n ? 'Type to search.'\n : 'No GIFs matched.'}\n </p>\n ) : null}\n </div>\n\n {/* TODO(legal): \"Powered by GIPHY\" attribution is required by Giphy's\n terms of service. Noted here and in ADR-151 D4. */}\n <p\n className=\"text-[11px] uppercase\"\n style={{ color: 'rgb(var(--text-tertiary))', letterSpacing: '0.06em' }}\n >\n Powered by GIPHY\n </p>\n </div>\n )\n}\n\n/* ── posted-comment rendering (D6) ──────────────────────────────────────── */\n\nexport interface AttachmentGifProps {\n readonly attachment: ThreadAttachment\n /** Resolves the short-lived URL. Omit and the placeholder renders instead. */\n readonly resolveUrl?: ((attachmentId: string) => Promise<string | null>) | undefined\n readonly className?: string | undefined\n}\n\n/**\n * A GIF in a posted comment, under `prefers-reduced-motion`.\n *\n * The stored rendition is an mp4, so \"still frame with a play control\" is a\n * `<video>` that has not been told to play: it paints its poster frame and sits\n * there. Pressing play is an explicit choice, and the control disappears once\n * it is playing because at that point the video's own affordances take over.\n *\n * Without the preference it autoplays muted and looping, which is what a GIF\n * is. With it, nothing moves until asked.\n */\nexport function AttachmentGif({ attachment, resolveUrl, className }: AttachmentGifProps) {\n const reduced = usePrefersReducedMotion()\n const { url, failed, loading } = useAttachmentUrl(attachment.id, resolveUrl)\n const [playing, setPlaying] = useState(false)\n const videoRef = useRef<HTMLVideoElement>(null)\n\n // The preference can flip while the comment is on screen. Honouring it only\n // at mount would leave a GIF looping at exactly the moment someone asked for\n // less motion.\n useEffect(() => {\n if (reduced) setPlaying(false)\n }, [reduced])\n\n const shouldPlay = !reduced || playing\n\n if (url === null || failed) {\n return (\n <AttachmentPlaceholder\n attachment={attachment}\n state={loading && !failed ? 'loading' : 'broken'}\n className={className}\n />\n )\n }\n\n return (\n <span\n className={cn('relative block overflow-hidden border', className)}\n style={{\n aspectRatio: String(attachment.aspectRatio ?? 16 / 10),\n borderRadius: 'var(--thread-inner-radius, var(--radius-sm))',\n borderColor: 'rgb(var(--border))',\n background: 'rgb(var(--surface-inset))',\n inlineSize: 'calc(var(--space-12) * 3)',\n minInlineSize: 'calc(var(--space-12) * 3)',\n }}\n >\n <video\n ref={videoRef}\n src={url}\n loop\n muted\n playsInline\n autoPlay={shouldPlay}\n aria-label={attachment.name}\n className=\"h-full w-full object-cover\"\n />\n {shouldPlay ? null : (\n <button\n type=\"button\"\n aria-label={`Play ${attachment.name}`}\n onClick={() => {\n setPlaying(true)\n void videoRef.current?.play()\n }}\n className=\"absolute inset-0 flex items-center justify-center focus-visible:outline-none focus-visible:[box-shadow:var(--ring-focus)]\"\n style={{ background: 'rgb(var(--media-scrim-mid))', color: 'rgb(var(--media-on-scrim))' }}\n >\n <Play size={20} strokeWidth={1.75} aria-hidden=\"true\" />\n </button>\n )}\n </span>\n )\n}\n\n/**\n * The box an image keeps when it has nothing to show.\n *\n * D6: \"a broken image is a placeholder with a small icon, never a collapsed\n * box\". The dimensions come from the DECLARED aspect ratio, which is why this\n * is the same size as the image would have been.\n */\nexport function AttachmentPlaceholder({\n attachment,\n state = 'broken',\n className,\n}: {\n attachment: ThreadAttachment\n /**\n * `loading` while the URL is still being resolved, `broken` once it is known\n * not to be coming. Same BOX either way — the layout must not depend on which\n * — but not the same picture: the broken icon is a statement about the file,\n * and saying it while the answer is still in flight is saying something\n * untrue about someone's own comment.\n */\n state?: 'loading' | 'broken'\n className?: string | undefined\n}) {\n return (\n <span\n className={cn('flex items-center justify-center overflow-hidden border', className)}\n style={{\n aspectRatio: String(attachment.aspectRatio ?? 16 / 10),\n borderRadius: 'var(--thread-inner-radius, var(--radius-sm))',\n borderColor: 'rgb(var(--border))',\n background: 'rgb(var(--surface-inset))',\n color: 'rgb(var(--text-tertiary))',\n inlineSize: 'calc(var(--space-12) * 3)',\n minInlineSize: 'calc(var(--space-12) * 3)',\n }}\n aria-label={state === 'loading' ? `Loading ${attachment.name}` : undefined}\n >\n {state === 'broken' ? <ImageOff size={14} strokeWidth={1.5} aria-hidden=\"true\" /> : null}\n </span>\n )\n}\n\nexport interface AttachmentImageProps {\n readonly attachment: ThreadAttachment\n readonly onOpen?: ((attachment: ThreadAttachment) => void) | undefined\n /** Resolves the short-lived URL. Omit and the placeholder renders instead. */\n readonly resolveUrl?: ((attachmentId: string) => Promise<string | null>) | undefined\n readonly className?: string | undefined\n}\n\n/**\n * A posted image with a stable reserved box and a real reduced-motion path for\n * uploaded GIFs.\n *\n * Uploaded GIFs intentionally remain `kind: 'image'`: unlike a Giphy mp4, the\n * stored file cannot be paused. Its MIME type lets this renderer capture the\n * loaded image into a canvas once. Under reduced motion the live image is\n * hidden behind that still; the labelled play button swaps it back only after\n * an explicit choice.\n */\nexport function AttachmentImage({\n attachment,\n onOpen,\n resolveUrl,\n className,\n}: AttachmentImageProps) {\n const reduced = usePrefersReducedMotion()\n const [broken, setBroken] = useState(false)\n const [playing, setPlaying] = useState(false)\n const [capturedSrc, setCapturedSrc] = useState<string | null>(null)\n const imageRef = useRef<HTMLImageElement>(null)\n const canvasRef = useRef<HTMLCanvasElement>(null)\n const capturedSrcRef = useRef<string | null>(null)\n\n // Two ways a picture can be absent, and they are NOT the same: `url` on the\n // attachment (a host that already has one) versus a lazy resolve. Both end at\n // the same placeholder, which is why the box is declared above either.\n const resolved = useAttachmentUrl(attachment.id, attachment.url === undefined ? resolveUrl : undefined)\n const src = attachment.url ?? resolved.url ?? undefined\n const uploadedGif = attachment.mime?.toLowerCase() === 'image/gif'\n\n const captureStill = useCallback(\n (image: HTMLImageElement) => {\n if (!uploadedGif || src === undefined || capturedSrcRef.current === src) return\n const canvas = canvasRef.current\n const width = image.naturalWidth\n const height = image.naturalHeight\n if (canvas === null || width <= 0 || height <= 0) return\n canvas.width = width\n canvas.height = height\n const context = canvas.getContext('2d')\n if (context === null) return\n context.drawImage(image, 0, 0, width, height)\n capturedSrcRef.current = src\n setCapturedSrc(src)\n },\n [src, uploadedGif],\n )\n\n // The preference can flip while the comment is mounted. Capture normally\n // happens on load; the complete check also covers a cached image whose load\n // event preceded the preference change.\n useEffect(() => {\n if (!reduced) return\n setPlaying(false)\n const image = imageRef.current\n if (image?.complete === true) captureStill(image)\n }, [captureStill, reduced])\n\n const missing = broken || resolved.failed || src === undefined\n // Still resolving is NOT the same as broken. Both keep the reserved box; only\n // one of them says the file is gone.\n const pending = resolved.loading && !broken && !resolved.failed\n const interactive = onOpen !== undefined && !missing\n const showStill = uploadedGif && reduced && !playing && !missing\n\n const body = pending ? null : missing ? (\n <span\n className=\"flex h-full w-full items-center justify-center\"\n style={{ color: 'rgb(var(--text-tertiary))' }}\n >\n <ImageOff size={14} strokeWidth={1.5} aria-hidden=\"true\" />\n </span>\n ) : (\n <span className=\"relative block h-full w-full\">\n <img\n ref={imageRef}\n src={src}\n alt={attachment.name}\n loading=\"lazy\"\n className=\"h-full w-full object-cover\"\n style={{ visibility: showStill ? 'hidden' : 'visible' }}\n onLoad={(event) => {\n captureStill(event.currentTarget)\n }}\n onError={() => {\n setBroken(true)\n }}\n />\n {uploadedGif ? (\n <canvas\n ref={canvasRef}\n aria-hidden=\"true\"\n hidden={!showStill || capturedSrc !== src}\n className=\"absolute inset-0 h-full w-full object-cover\"\n />\n ) : null}\n </span>\n )\n\n return (\n <span\n className={cn(\n 'relative block overflow-hidden border',\n 'transition-[border-color] duration-[var(--dur-fast)] ease-[var(--ease-out)] motion-reduce:transition-none',\n interactive && !showStill && 'hover:border-[rgb(var(--border-strong))]',\n (interactive || showStill) &&\n 'focus-within:outline-none focus-within:[box-shadow:var(--ring-focus)]',\n className,\n )}\n style={{\n // Declared up front so the row cannot reflow when the bytes land.\n aspectRatio: String(attachment.aspectRatio ?? 16 / 10),\n borderRadius: 'var(--thread-inner-radius, var(--radius-sm))',\n borderColor: 'rgb(var(--border))',\n background: 'rgb(var(--surface-inset))',\n inlineSize: 'calc(var(--space-12) * 3)',\n minInlineSize: 'calc(var(--space-12) * 3)',\n }}\n >\n {interactive ? (\n <button\n type=\"button\"\n aria-label={`Open ${attachment.name}`}\n aria-hidden={showStill ? true : undefined}\n disabled={showStill}\n onClick={() => {\n onOpen?.(attachment)\n }}\n className=\"block h-full w-full focus-visible:outline-none\"\n >\n {body}\n </button>\n ) : (\n body\n )}\n {showStill ? (\n <button\n type=\"button\"\n aria-label={`Play ${attachment.name}`}\n onClick={() => {\n setPlaying(true)\n }}\n className=\"absolute inset-0 flex items-center justify-center focus-visible:outline-none\"\n style={{ background: 'rgb(var(--media-scrim-mid))', color: 'rgb(var(--media-on-scrim))' }}\n >\n <Play size={20} strokeWidth={1.75} aria-hidden=\"true\" />\n </button>\n ) : null}\n </span>\n )\n}\n\n/* ── the lightbox (D6) ──────────────────────────────────────────────────── */\n\nexport interface AttachmentLightboxProps {\n readonly attachment: ThreadAttachment | null\n readonly onClose: () => void\n readonly resolveUrl?: ((attachmentId: string) => Promise<string | null>) | undefined\n}\n\n/**\n * Full-size view of one attachment.\n *\n * Deliberately small: a scrim, the image, a close button, and `Escape`. It is\n * not a gallery — ADR-151 says \"click opens a lightbox\", and a carousel with\n * keyboard paging is a different feature with a different accessibility\n * surface.\n *\n * Focus moves to the close button on open, because otherwise `Escape` is the\n * only way out for a keyboard and the focus ring is somewhere behind the scrim.\n */\nexport function AttachmentLightbox({ attachment, onClose, resolveUrl }: AttachmentLightboxProps) {\n const closeRef = useRef<HTMLButtonElement>(null)\n const id = attachment?.id ?? ''\n const { url, failed } = useAttachmentUrl(id, attachment === null ? undefined : resolveUrl)\n\n const surfaceRef = useRef<HTMLDivElement>(null)\n\n useEffect(() => {\n if (attachment === null) return\n closeRef.current?.focus()\n\n /**\n * `aria-modal=\"true\"` asserts that nothing behind the scrim is reachable.\n * Without a trap that assertion is false — Tab walks straight out into a\n * page a sighted user can see is covered and a screen-reader user has been\n * told is not there. Focus is therefore wrapped rather than merely placed.\n *\n * The dialog holds two focusables at most (the close button, and a video's\n * controls), so a full focus-trap library would be more machinery than the\n * problem: collect what is focusable at the moment Tab is pressed, and\n * wrap at the ends.\n */\n const onKey = (event: KeyboardEvent) => {\n if (event.key === 'Escape') {\n onClose()\n return\n }\n if (event.key !== 'Tab') return\n const root = surfaceRef.current\n if (root === null) return\n const focusable = Array.from(\n root.querySelectorAll<HTMLElement>(\n 'a[href], button:not([disabled]), video[controls], [tabindex]:not([tabindex=\"-1\"])',\n ),\n )\n if (focusable.length === 0) {\n event.preventDefault()\n return\n }\n const first = focusable[0]\n const last = focusable[focusable.length - 1]\n const active = document.activeElement\n if (event.shiftKey && (active === first || !root.contains(active))) {\n event.preventDefault()\n last?.focus()\n } else if (!event.shiftKey && (active === last || !root.contains(active))) {\n event.preventDefault()\n first?.focus()\n }\n }\n document.addEventListener('keydown', onKey)\n return () => {\n document.removeEventListener('keydown', onKey)\n }\n }, [attachment, onClose])\n\n if (attachment === null) return null\n\n return (\n <div\n role=\"dialog\"\n aria-modal=\"true\"\n aria-label={attachment.name}\n className=\"fixed inset-0 z-50 flex items-center justify-center p-[var(--space-6)]\"\n style={{ background: 'rgb(var(--media-scrim-strong))' }}\n onClick={onClose}\n >\n <div\n ref={surfaceRef}\n className=\"relative flex max-h-full max-w-full items-center justify-center\"\n onClick={(event) => {\n event.stopPropagation()\n }}\n >\n {url === null || failed ? (\n <p style={{ color: 'rgb(var(--media-on-scrim))' }}>\n {failed ? \"This file isn't available.\" : 'Loading…'}\n </p>\n ) : attachment.kind === 'gif' ? (\n <video\n src={url}\n controls\n loop\n muted\n playsInline\n aria-label={attachment.name}\n className=\"max-h-full max-w-full\"\n />\n ) : (\n <img src={url} alt={attachment.name} className=\"max-h-full max-w-full object-contain\" />\n )}\n <span className=\"absolute\" style={{ insetBlockStart: 0, insetInlineEnd: 0 }}>\n <button\n ref={closeRef}\n type=\"button\"\n aria-label=\"Close\"\n className={QUIET_ICON}\n style={{ ...QUIET_ICON_BOX, color: 'rgb(var(--media-on-scrim))' }}\n onClick={onClose}\n >\n <X size={14} strokeWidth={1.75} aria-hidden=\"true\" />\n </button>\n </span>\n </div>\n </div>\n )\n}\n\n/**\n * The `accept` string for the file input, mirroring the extension allowlist the\n * server enforces (ADR-151 D3). Exported so a host does not re-type the list\n * and drift from it.\n *\n * It is a filter, never a check: the worker reads the MAGIC NUMBER, so a\n * renamed file sails past `accept` and is refused there. What this buys is that\n * the file chooser shows the right files.\n */\nexport const ATTACHMENT_ACCEPT = '.png,.jpg,.jpeg,.webp,.gif,.pdf,.txt,.md,.csv,.json'\n","/**\n * RichThreadComposer — the shell around the TipTap composer.\n *\n * ADR-148 D5 / D6. This file satisfies `ThreadComposerProps` exactly, so\n * `<Thread composer=\"rich\">` cannot tell it from `ThreadComposer`, and it is\n * the ONLY thing the package barrel exports for the rich editor. It imports\n * no TipTap: the editor lives in `rich-composer-impl.tsx` behind the single\n * `lazy()` boundary below, which is what keeps ProseMirror out of every\n * consumer that renders a thread LIST (AC#10). The chunk is requested when a\n * composer MOUNTS — not on focus, which would need a placeholder control, a\n * swap and a caret restore for the bytes it would save.\n *\n * Three states, and a dead composer is never one of them (D6):\n *\n * loading — the plain composer, disabled, holding the draft. Same `rows`,\n * same padding, and the editor reserves the same height, so the\n * swap moves nothing.\n * ready — the editor (the impl decides, before it mounts anything, whether\n * the draft is even rich-editable — D3 rule 2 — and if not,\n * renders the plain composer with the source untouched).\n * failed — the import rejected (offline, a chunk that 404s after a deploy,\n * a CSP block): the plain composer with the same draft, and a\n * one-line notice. Nothing is lost, because the draft is markdown\n * (D1). Reported once, politely, never with a modal.\n *\n * The live region here is the composer's own. `ThreadComposerProps` carries no\n * `announce` seam to the thread's single region, and adding one means editing\n * composer.tsx and comment.tsx, which this ADR's scope left alone — noted in\n * the completion report as the two-line follow-up it is.\n */\n\nimport { Component, Suspense, lazy, useCallback, useState } from 'react'\nimport type { ErrorInfo, ReactNode } from 'react'\nimport { Info } from 'lucide-react'\nimport { ThreadComposer, type ThreadComposerProps } from './composer'\nimport type { GifPickerResult } from './attachments'\nimport type { MentionSuggestionItem } from './types'\nimport type { UseAttachmentsOptions } from './use-attachments'\n\nconst RichThreadComposerImpl = lazy(() => import('./rich-composer-impl'))\n\n/** D6, in the words the live region speaks. */\nexport const RICH_FALLBACK_NOTICE = 'Rich editor unavailable, plain editor loaded'\n\n/** The one-line notice above a plain composer that stands in for the rich one. */\nexport function ComposerNotice({ children }: { readonly children: ReactNode }) {\n return (\n <p\n className=\"flex items-center gap-[var(--space-1)] text-[12px]\"\n style={{ color: 'rgb(var(--text-tertiary))' }}\n >\n <Info size={12} strokeWidth={1.75} aria-hidden=\"true\" />\n <span>{children}</span>\n </p>\n )\n}\n\ninterface ChunkBoundaryProps {\n readonly fallback: ReactNode\n readonly onError: (error: unknown) => void\n readonly children: ReactNode\n}\n\n/**\n * `lazy()` reports a rejected import by throwing during render; a boundary is\n * the only place React lets that be caught. It renders the plain composer in\n * place and tells the shell, which then owns the failed state for good — a\n * rejected `lazy` stays rejected for the life of the page anyway.\n */\nclass ChunkBoundary extends Component<ChunkBoundaryProps, { readonly failed: boolean }> {\n override state = { failed: false }\n\n static getDerivedStateFromError(): { failed: boolean } {\n return { failed: true }\n }\n\n override componentDidCatch(error: unknown, _info: ErrorInfo): void {\n this.props.onError(error)\n }\n\n override render(): ReactNode {\n return this.state.failed ? this.props.fallback : this.props.children\n }\n}\n\n/**\n * `ThreadComposerProps` plus the optional host capabilities added by ADR-149\n * and ADR-151: mention lookup, upload + ticket verification, GIF search, and\n * the worker's attachment limits. `<Thread composer=\"rich\">` can still hand\n * this component a bare `ThreadComposerProps`; absent capabilities simply do\n * not render controls that cannot work.\n *\n * They stop here rather than continuing down to `ThreadComposer`: the plain\n * textarea has neither a suggestion layer nor attachment state, so fallback\n * paths deliberately drop them without offering inert controls.\n */\nexport interface RichComposerAttachmentProps {\n /** Upload bytes and return the worker-verified `tup_...` ticket. */\n readonly uploadAttachment?: NonNullable<UseAttachmentsOptions['upload']> | undefined\n /** Turn a Giphy id into the same verified ticket shape. */\n readonly attachGif?: NonNullable<UseAttachmentsOptions['attachGif']> | undefined\n /** Search results stay host-owned so no API URL or key enters this package. */\n readonly searchGifs?: ((query: string) => Promise<readonly GifPickerResult[]>) | undefined\n /** Mirrors the worker's extension allowlist for the native file chooser. */\n readonly attachmentAccept?: string | undefined\n readonly attachmentMaxPerComment?: number | undefined\n readonly attachmentMaxFileBytes?: number | undefined\n readonly attachmentMaxTotalBytes?: number | undefined\n}\n\nexport interface RichThreadComposerProps\n extends ThreadComposerProps,\n RichComposerAttachmentProps {\n readonly mentionItems?: ((query: string) => readonly MentionSuggestionItem[]) | undefined\n}\n\nexport function RichThreadComposer({\n mentionItems,\n uploadAttachment,\n attachGif,\n searchGifs,\n attachmentAccept,\n attachmentMaxPerComment,\n attachmentMaxFileBytes,\n attachmentMaxTotalBytes,\n ...props\n}: RichThreadComposerProps) {\n const [failed, setFailed] = useState(false)\n\n // Same shape as the thread's region: a live region speaks when its text\n // CHANGES, so the sequence alternates a trailing NBSP that screen readers\n // trim and the DOM counts as a change.\n const [announcement, setAnnouncement] = useState<{\n readonly text: string\n readonly seq: number\n }>({ text: '', seq: 0 })\n\n const announce = useCallback((text: string) => {\n setAnnouncement((prev) => ({ text, seq: prev.seq + 1 }))\n }, [])\n\n const onError = useCallback(\n (error: unknown) => {\n console.warn(\n 'rich composer: the editor chunk could not load; the plain composer is rendered instead',\n error,\n )\n setFailed(true)\n announce(RICH_FALLBACK_NOTICE)\n },\n [announce],\n )\n\n const spoken =\n announcement.text === ''\n ? ''\n : announcement.seq % 2 === 0\n ? `${announcement.text}\\u{00A0}`\n : announcement.text\n\n return (\n <div className=\"flex flex-col gap-[var(--space-1)]\">\n {/* Rendered empty on mount and kept for the life of the composer: an AT\n has to be observing the node before the text lands. */}\n <div role=\"status\" aria-live=\"polite\" aria-atomic=\"true\" className=\"sr-only\">\n {spoken}\n </div>\n {failed ? (\n <>\n <ComposerNotice>{RICH_FALLBACK_NOTICE}</ComposerNotice>\n <ThreadComposer {...props} />\n </>\n ) : (\n <ChunkBoundary onError={onError} fallback={<ThreadComposer {...props} />}>\n <Suspense fallback={<ThreadComposer {...props} disabled />}>\n <RichThreadComposerImpl\n {...props}\n announce={announce}\n {...(mentionItems === undefined ? {} : { mentionItems })}\n {...(uploadAttachment === undefined ? {} : { uploadAttachment })}\n {...(attachGif === undefined ? {} : { attachGif })}\n {...(searchGifs === undefined ? {} : { searchGifs })}\n {...(attachmentAccept === undefined ? {} : { attachmentAccept })}\n {...(attachmentMaxPerComment === undefined\n ? {}\n : { attachmentMaxPerComment })}\n {...(attachmentMaxFileBytes === undefined ? {} : { attachmentMaxFileBytes })}\n {...(attachmentMaxTotalBytes === undefined ? {} : { attachmentMaxTotalBytes })}\n />\n </Suspense>\n </ChunkBoundary>\n )}\n </div>\n )\n}\n"]}
|