@aparte/core 0.9.0 → 0.11.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/client/aparte-client.d.ts +54 -33
- package/dist/client/aparte-client.d.ts.map +1 -1
- package/dist/client/stream-adapter.d.ts +6 -1
- package/dist/client/stream-adapter.d.ts.map +1 -1
- package/dist/components/bubble/aparte-chat-bubble.d.ts +49 -7
- package/dist/components/bubble/aparte-chat-bubble.d.ts.map +1 -1
- package/dist/components/chat/aparte-chat.d.ts +8 -4
- package/dist/components/chat/aparte-chat.d.ts.map +1 -1
- package/dist/components/composer/aparte-composer-action.d.ts +5 -5
- package/dist/components/composer/aparte-composer-action.d.ts.map +1 -1
- package/dist/components/composer/aparte-composer-add-attachment.d.ts +16 -4
- package/dist/components/composer/aparte-composer-add-attachment.d.ts.map +1 -1
- package/dist/components/composer/aparte-composer-attachments.d.ts +5 -3
- package/dist/components/composer/aparte-composer-attachments.d.ts.map +1 -1
- package/dist/components/composer/aparte-composer-cancel.d.ts +10 -2
- package/dist/components/composer/aparte-composer-cancel.d.ts.map +1 -1
- package/dist/components/composer/aparte-composer-input.d.ts +8 -5
- package/dist/components/composer/aparte-composer-input.d.ts.map +1 -1
- package/dist/components/composer/aparte-composer-send.d.ts +34 -2
- package/dist/components/composer/aparte-composer-send.d.ts.map +1 -1
- package/dist/components/composer/aparte-composer-toolbar.d.ts +3 -3
- package/dist/components/composer/aparte-composer.d.ts +54 -10
- package/dist/components/composer/aparte-composer.d.ts.map +1 -1
- package/dist/components/conversation-list/aparte-conversation-list.d.ts +19 -12
- package/dist/components/conversation-list/aparte-conversation-list.d.ts.map +1 -1
- package/dist/components/elicitation/aparte-elicitation.d.ts +22 -0
- package/dist/components/elicitation/aparte-elicitation.d.ts.map +1 -1
- package/dist/components/status/aparte-chat-status.d.ts +9 -0
- package/dist/components/status/aparte-chat-status.d.ts.map +1 -1
- package/dist/components/viewport/aparte-chat-viewport.d.ts +18 -5
- package/dist/components/viewport/aparte-chat-viewport.d.ts.map +1 -1
- package/dist/config/aparte-config.d.ts +54 -2
- package/dist/config/aparte-config.d.ts.map +1 -1
- package/dist/config/config-subscribe.d.ts +4 -0
- package/dist/config/config-subscribe.d.ts.map +1 -0
- package/dist/config/index.d.ts +1 -0
- package/dist/config/index.d.ts.map +1 -1
- package/dist/config/locale.d.ts +141 -0
- package/dist/config/locale.d.ts.map +1 -1
- package/dist/config/sanitize.d.ts.map +1 -1
- package/dist/custom-elements.json +5905 -4694
- package/dist/elicitation/approval-panel.d.ts +42 -0
- package/dist/elicitation/approval-panel.d.ts.map +1 -0
- package/dist/elicitation/index.d.ts +4 -1
- package/dist/elicitation/index.d.ts.map +1 -1
- package/dist/elicitation/panel.d.ts +14 -1
- package/dist/elicitation/panel.d.ts.map +1 -1
- package/dist/elicitation/types.d.ts +116 -9
- package/dist/elicitation/types.d.ts.map +1 -1
- package/dist/generated/element-attributes.d.ts +173 -0
- package/dist/generated/element-attributes.d.ts.map +1 -0
- package/dist/host/aparte-chat-host.d.ts +3 -1
- package/dist/host/aparte-chat-host.d.ts.map +1 -1
- package/dist/index.css +752 -392
- package/dist/index.d.ts +5 -4
- package/dist/index.d.ts.map +1 -1
- package/dist/index.js +538 -290
- package/dist/index.js.map +1 -1
- package/dist/index.node.d.ts +5 -4
- package/dist/index.node.d.ts.map +1 -1
- package/dist/index.node.js +62 -57
- package/dist/index.node.js.map +1 -1
- package/dist/interop/element-props.d.ts +26 -1
- package/dist/interop/element-props.d.ts.map +1 -1
- package/dist/{index-hQQljwfX.js → is-awaiting-reply-Cb7H3YfN.js} +1159 -972
- package/dist/is-awaiting-reply-Cb7H3YfN.js.map +1 -0
- package/dist/parsers/aparte-stream-parser.d.ts.map +1 -1
- package/dist/primitives/select/aparte-optgroup.d.ts +3 -0
- package/dist/primitives/select/aparte-optgroup.d.ts.map +1 -1
- package/dist/primitives/select/aparte-option.d.ts +1 -0
- package/dist/primitives/select/aparte-option.d.ts.map +1 -1
- package/dist/primitives/select/aparte-select.d.ts +22 -18
- package/dist/primitives/select/aparte-select.d.ts.map +1 -1
- package/dist/renderers/highlight-stream.d.ts +17 -0
- package/dist/renderers/highlight-stream.d.ts.map +1 -0
- package/dist/renderers/segment-renderers.d.ts.map +1 -1
- package/dist/renderers/segments/artifact/binary-file.d.ts.map +1 -1
- package/dist/renderers/segments/artifact/card.d.ts.map +1 -1
- package/dist/renderers/segments/artifact/shared.d.ts +19 -2
- package/dist/renderers/segments/artifact/shared.d.ts.map +1 -1
- package/dist/renderers/segments/code.d.ts.map +1 -1
- package/dist/renderers/segments/error.d.ts.map +1 -1
- package/dist/renderers/segments/pipeline-waiting.d.ts.map +1 -1
- package/dist/renderers/segments/thinking.d.ts.map +1 -1
- package/dist/renderers/segments/tool-call.d.ts.map +1 -1
- package/dist/types/element-attributes.d.ts +42 -0
- package/dist/types/element-attributes.d.ts.map +1 -0
- package/dist/types/event-map.d.ts +2 -4
- package/dist/types/event-map.d.ts.map +1 -1
- package/dist/types/events.d.ts +0 -22
- package/dist/types/events.d.ts.map +1 -1
- package/dist/types/index.d.ts +4 -3
- package/dist/types/index.d.ts.map +1 -1
- package/dist/types/models.d.ts +1 -6
- package/dist/types/models.d.ts.map +1 -1
- package/dist/types/segments.d.ts +87 -74
- package/dist/types/segments.d.ts.map +1 -1
- package/dist/types/tools.d.ts +15 -21
- package/dist/types/tools.d.ts.map +1 -1
- package/dist/utils/segments.d.ts +83 -5
- package/dist/utils/segments.d.ts.map +1 -1
- package/package.json +3 -2
- package/dist/index-hQQljwfX.js.map +0 -1
- package/dist/renderers/segments/file-tree.d.ts +0 -3
- package/dist/renderers/segments/file-tree.d.ts.map +0 -1
- package/dist/renderers/segments/progress.d.ts +0 -3
- package/dist/renderers/segments/progress.d.ts.map +0 -1
- package/dist/renderers/segments/terminal.d.ts +0 -3
- package/dist/renderers/segments/terminal.d.ts.map +0 -1
package/dist/index.js.map
CHANGED
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"index.js","sources":["../src/primitives/select/aparte-option.ts","../src/primitives/select/aparte-optgroup.ts","../src/primitives/select/aparte-select.ts","../src/primitives/progress-spinner/aparte-progress-spinner.ts","../src/components/chat/aparte-chat.ts","../src/components/bubble/aparte-chat-bubble.ts","../src/components/status/aparte-chat-status.ts","../src/components/viewport/aparte-chat-viewport.ts","../src/components/composer/aparte-composer.ts","../src/components/composer/aparte-composer-input.ts","../src/components/composer/aparte-composer-send.ts","../src/components/composer/aparte-composer-cancel.ts","../src/components/composer/aparte-composer-attachments.ts","../src/components/composer/aparte-composer-add-attachment.ts","../src/components/composer/aparte-composer-action.ts","../src/components/composer/aparte-composer-toolbar.ts","../src/components/conversation-list/aparte-conversation-list.ts","../src/components/elicitation/aparte-elicitation.ts","../src/index.ts"],"sourcesContent":["/**\n * AparteOption\n * \n * Option element for aparte-select dropdown.\n * \n * @element aparte-option\n * @attr {string} value - Option value\n * @attr {boolean} disabled - Disabled state\n * @attr {boolean} selected - Selected state\n *\n * @example\n * <aparte-select placeholder=\"Pick a model\">\n * <aparte-option value=\"gpt-4o-mini\" selected>GPT-4o mini</aparte-option>\n * <aparte-option value=\"o3\" disabled>o3 (no access)</aparte-option>\n * </aparte-select>\n */\n\nexport class AparteOption extends HTMLElement {\n static get observedAttributes(): string[] {\n return ['value', 'disabled', 'selected', 'data-status'];\n }\n\n connectedCallback(): void {\n this.setAttribute('role', 'option');\n this._updateAriaSelected();\n this._updateStatusDot();\n }\n\n attributeChangedCallback(name: string): void {\n if (name === 'selected') {\n this._updateAriaSelected();\n }\n if (name === 'disabled') {\n this.setAttribute('aria-disabled', this.hasAttribute('disabled') ? 'true' : 'false');\n }\n if (name === 'data-status') {\n this._updateStatusDot();\n }\n }\n\n get value(): string {\n return this.getAttribute('value') || this.textContent?.trim() || '';\n }\n\n set value(val: string) {\n this.setAttribute('value', val);\n }\n\n get label(): string {\n // Use only the first text node, ignoring injected spans (e.g. status dot)\n const textNode = Array.from(this.childNodes).find(n => n.nodeType === Node.TEXT_NODE);\n return textNode?.textContent?.trim() || this.value;\n }\n\n get disabled(): boolean {\n return this.hasAttribute('disabled');\n }\n\n set disabled(val: boolean) {\n if (val) {\n this.setAttribute('disabled', '');\n } else {\n this.removeAttribute('disabled');\n }\n }\n\n get selected(): boolean {\n return this.hasAttribute('selected');\n }\n\n set selected(val: boolean) {\n if (val) {\n this.setAttribute('selected', '');\n } else {\n this.removeAttribute('selected');\n }\n }\n\n private _updateAriaSelected(): void {\n this.setAttribute('aria-selected', this.selected ? 'true' : 'false');\n }\n\n private _updateStatusDot(): void {\n const status = this.getAttribute('data-status');\n let dot = this.querySelector<HTMLSpanElement>('.aparte-status-dot');\n\n if (!status) {\n dot?.remove();\n return;\n }\n\n if (!dot) {\n dot = document.createElement('span');\n dot.className = 'aparte-status-dot';\n dot.setAttribute('aria-hidden', 'true');\n this.appendChild(dot);\n }\n\n dot.setAttribute('data-status', status);\n }\n}\n\n// Register\nif (!customElements.get('aparte-option')) {\n customElements.define('aparte-option', AparteOption);\n}\n","/**\n * AparteOptgroup\n * \n * Option group element for aparte-select dropdown.\n * \n * @element aparte-optgroup\n * @attr {string} label - Group label\n * @attr {boolean} collapsible - Allow collapse/expand\n * @attr {boolean} collapsed - Collapsed state\n *\n * @example\n * <!-- Collapsed groups keep a long list readable; the label is the group's header. -->\n * <aparte-select grouped placeholder=\"Pick a model\">\n * <aparte-optgroup label=\"Ollama\" collapsible collapsed>\n * <aparte-option value=\"ollama::llama3\">Llama 3</aparte-option>\n * </aparte-optgroup>\n * <aparte-optgroup label=\"OpenRouter\" collapsible>\n * <aparte-option value=\"openrouter::gpt-4o-mini\">GPT-4o mini</aparte-option>\n * </aparte-optgroup>\n * </aparte-select>\n */\n\nexport class AparteOptgroup extends HTMLElement {\n /** Ids for the label span the group points `aria-labelledby` at. */\n private static _labelIdSeq = 0;\n\n static get observedAttributes(): string[] {\n return ['label', 'collapsible', 'collapsed', 'loading'];\n }\n\n connectedCallback(): void {\n this.setAttribute('role', 'group');\n this._render();\n }\n\n attributeChangedCallback(name: string, oldValue: string | null, newValue: string | null): void {\n if (oldValue === newValue) return;\n\n if (name === 'collapsed') {\n this._updateCollapsedState();\n }\n\n if (this.isConnected) {\n this._render();\n }\n }\n\n get label(): string {\n return this.getAttribute('label') || '';\n }\n\n set label(val: string) {\n this.setAttribute('label', val);\n }\n\n get collapsible(): boolean {\n return this.hasAttribute('collapsible');\n }\n\n get collapsed(): boolean {\n return this.hasAttribute('collapsed');\n }\n\n set collapsed(val: boolean) {\n if (val) {\n this.setAttribute('collapsed', '');\n } else {\n this.removeAttribute('collapsed');\n }\n }\n\n get loading(): boolean {\n return this.hasAttribute('loading');\n }\n\n set loading(val: boolean) {\n if (val) this.setAttribute('loading', '');\n else this.removeAttribute('loading');\n }\n\n private _render(): void {\n // Only render header if we have a label\n if (this.label) {\n const existingHeader = this.querySelector('.aparte-optgroup-header');\n if (!existingHeader) {\n const header = document.createElement('div');\n header.className = 'aparte-optgroup-header';\n // The header stays a GENERIC node on purpose: naming it (it used to\n // carry `aria-label`) makes it a real element inside a `listbox`,\n // where only options and groups may live (axe:\n // aria-required-children, critical). The name belongs on the group,\n // via aria-labelledby below.\n // `label` is an attribute value — with the model-selector it carries a\n // provider-supplied name — so it goes through textContent, never\n // innerHTML (a hostile name would otherwise inject here).\n const labelSpan = document.createElement('span');\n labelSpan.className = 'aparte-optgroup-label';\n labelSpan.id = `aparte-optgroup-label-${++AparteOptgroup._labelIdSeq}`;\n labelSpan.textContent = this.label;\n this.setAttribute('aria-labelledby', labelSpan.id);\n header.appendChild(labelSpan);\n\n if (this.collapsible) {\n const chevron = document.createElement('span');\n chevron.className = 'aparte-optgroup-chevron';\n header.appendChild(chevron);\n header.style.cursor = 'pointer';\n header.addEventListener('click', (e) => {\n e.stopPropagation();\n this._toggleCollapse();\n });\n }\n\n this.insertBefore(header, this.firstChild);\n }\n }\n\n // Update loading state\n this._updateLoadingState();\n\n // Update collapsed state\n this._updateCollapsedState();\n }\n\n private _updateLoadingState(): void {\n let loader = this.querySelector('.aparte-optgroup-loader');\n if (this.loading) {\n if (!loader) {\n loader = document.createElement('div');\n loader.className = 'aparte-optgroup-loader';\n loader.innerHTML = '<span class=\"aparte-spinner-small\"></span> Fetching models...';\n this.appendChild(loader);\n }\n } else if (loader) {\n loader.remove();\n }\n }\n\n private _toggleCollapse(): void {\n this.collapsed = !this.collapsed;\n\n // Dispatch event before updating UI to allow parent to react (e.g. fetch data)\n this.dispatchEvent(new CustomEvent<AparteOptgroupToggleEventDetail>('aparte-optgroup-toggle', {\n bubbles: true,\n composed: true,\n detail: {\n label: this.label,\n collapsed: this.collapsed\n }\n }));\n\n this._updateCollapsedState();\n }\n\n private _updateCollapsedState(): void {\n const options = this.querySelectorAll('aparte-option');\n options.forEach(opt => {\n (opt as HTMLElement).style.display = this.collapsed ? 'none' : '';\n });\n }\n}\n\n// Register\nif (!customElements.get('aparte-optgroup')) {\n customElements.define('aparte-optgroup', AparteOptgroup);\n}\n\n/**\n * Detail payload for `aparte-optgroup-toggle`.\n *\n * Named in `types/event-map.ts` as an internal primitive event \"carrying no\n * cross-package detail contract\". `@aparte/plugin-model-selector` reads both of\n * its fields, from another package, through an untyped cast — and the event is\n * published in the generated CEM event table. It is a contract.\n *\n * @event aparte-optgroup-toggle\n */\nexport interface AparteOptgroupToggleEventDetail {\n /** The group's label. */\n label: string;\n /** `true` when the group just collapsed. */\n collapsed: boolean;\n}\n","/**\n * AparteSelect\n * \n * Dropdown select component for AparteCore.\n * Vanilla Web Component with configurable features.\n * \n * @element aparte-select\n * @attr {string} value - Selected value\n * @attr {string} placeholder - Placeholder text\n * @attr {boolean} disabled - Disabled state\n * @attr {boolean} grouped - Enable optgroup mode\n * @attr {boolean} searchable - Enable search filter\n * @attr {boolean} open - Dropdown open state\n * \n * @fires aparte-select-change - Fired when selection changes\n * @fires aparte-select-open - Fired when dropdown opens\n * @fires aparte-select-close - Fired when dropdown closes\n */\n\nimport './aparte-option.js';\nimport './aparte-optgroup.js';\n\nexport interface AparteSelectChangeDetail {\n value: string;\n label: string;\n previousValue: string;\n}\n\n/**\n * @example\n * <aparte-select placeholder=\"Pick a model\" searchable value=\"gpt-4o-mini\">\n * <aparte-option value=\"gpt-4o-mini\">GPT-4o mini</aparte-option>\n * <aparte-option value=\"llama-3.1-8b\">Llama 3.1 8B</aparte-option>\n * </aparte-select>\n *\n * <script>\n * document.querySelector('aparte-select').addEventListener('aparte-select-change', (e) => {\n * console.log(e.detail.value, e.detail.label, e.detail.previousValue);\n * });\n * </script>\n */\nexport class AparteSelect extends HTMLElement {\n private static _optIdSeq = 0;\n /** Fallback ids for the listbox `aria-controls` target when the host has no id. */\n private static _listboxSeq = 0;\n\n private _value = '';\n private _isOpen = false;\n private _activeIndex = -1;\n private _trigger: HTMLElement | null = null;\n private _dropdown: HTMLElement | null = null;\n private _searchInput: HTMLInputElement | null = null;\n private _observer: MutationObserver | null = null;\n\n // Bound handlers for cleanup\n /**\n * Bound, like its two neighbours below — because an inline arrow on `this` can\n * never be removed.\n *\n * `_setupEventListeners()` runs on EVERY `connectedCallback`, and `_render()`'s\n * idempotency guard means the host element survives a re-connect. So each move\n * of the element (a portal, a Vue teleport, any framework re-parent) added\n * another option-click listener: measured, one click fired the change handler\n * FIVE times after five re-connects. `disconnectedCallback` removed the two\n * document-level handlers and could not touch this one.\n *\n * This is verbatim the bug class `aparte-chat-viewport` documents having fixed\n * for its own listeners; a repo sweep found this as the last inline-arrow\n * listener on a persistent node.\n */\n private _boundHandleOptionClick = this._handleOptionClick.bind(this);\n private _boundHandleDocumentClick = this._handleDocumentClick.bind(this);\n private _boundHandleKeydown = this._handleKeydown.bind(this);\n\n static get observedAttributes(): string[] {\n return ['value', 'placeholder', 'disabled', 'grouped', 'searchable', 'open'];\n }\n\n connectedCallback(): void {\n this._value = this.getAttribute('value') || '';\n this._isOpen = this.hasAttribute('open');\n this._render();\n this._setupEventListeners();\n this._setupMutationObserver();\n }\n\n disconnectedCallback(): void {\n this.removeEventListener('click', this._boundHandleOptionClick);\n document.removeEventListener('click', this._boundHandleDocumentClick);\n document.removeEventListener('keydown', this._boundHandleKeydown);\n this._observer?.disconnect();\n }\n\n attributeChangedCallback(name: string, oldValue: string, newValue: string): void {\n if (!this.isConnected) return;\n\n if (name === 'value' && oldValue !== newValue && newValue !== this._value) {\n this._value = newValue || '';\n this._updateTriggerLabel();\n }\n if (name === 'open') {\n this._isOpen = this.hasAttribute('open');\n if (this._isOpen) {\n this._dropdown?.removeAttribute('hidden');\n this._searchInput?.focus();\n } else {\n this._dropdown?.setAttribute('hidden', '');\n }\n }\n }\n\n // ─────────────────────────────────────────────────────────────────────────\n // Public API\n // ─────────────────────────────────────────────────────────────────────────\n\n get value(): string {\n return this._value;\n }\n\n set value(val: string) {\n if (val === this._value) return;\n const previousValue = this._value;\n this._value = val;\n this.setAttribute('value', val);\n this._updateTriggerLabel();\n this._emitChange(previousValue);\n }\n\n get open(): boolean {\n return this._isOpen;\n }\n\n set open(val: boolean) {\n if (val) {\n this.setAttribute('open', '');\n } else {\n this.removeAttribute('open');\n }\n }\n\n // ─────────────────────────────────────────────────────────────────────────\n // Rendering\n // ─────────────────────────────────────────────────────────────────────────\n\n private _render(): void {\n const placeholder = this.getAttribute('placeholder') || 'Select...';\n const searchable = this.hasAttribute('searchable');\n\n // Check if already rendered (has dropdown structure)\n if (this.querySelector('.aparte-select-dropdown')) {\n this._updateTriggerLabel();\n return;\n }\n\n // First render: capture any slotted children before modifying DOM\n const slottedChildren = Array.from(this.children);\n\n // Create wrapper structure\n const trigger = document.createElement('div');\n trigger.className = 'aparte-select-trigger';\n trigger.setAttribute('tabindex', '0');\n trigger.setAttribute('role', 'combobox');\n trigger.setAttribute('aria-haspopup', 'listbox');\n trigger.setAttribute('aria-expanded', 'false');\n // Accessible name (axe aria-input-field-name): the visible label span is\n // the combobox VALUE, not its name — name it from the host's aria-label\n // when provided, else the placeholder (\"Select model…\" etc.).\n trigger.setAttribute('aria-label', this.getAttribute('aria-label') || placeholder);\n // The label is placeholder text (consumer/attribute-supplied) → textContent,\n // same path as _updateTriggerLabel(), never innerHTML. Only the static SVG\n // chevron uses innerHTML.\n const labelSpan = document.createElement('span');\n labelSpan.className = 'aparte-select-label';\n labelSpan.textContent = placeholder;\n const chevronSpan = document.createElement('span');\n chevronSpan.className = 'aparte-select-chevron';\n chevronSpan.innerHTML = `<svg width=\"12\" height=\"12\" viewBox=\"0 0 12 12\" fill=\"currentColor\"><path d=\"M2.5 4.5L6 8L9.5 4.5\" stroke=\"currentColor\" stroke-width=\"1.5\" fill=\"none\" stroke-linecap=\"round\"/></svg>`;\n trigger.append(labelSpan, chevronSpan);\n\n // The dropdown is a plain shell: it also holds the search field, and a\n // `listbox` may only contain options/groups (axe: aria-required-children,\n // critical). The listbox lives on the options container below.\n const dropdown = document.createElement('div');\n dropdown.className = 'aparte-select-dropdown';\n dropdown.hidden = !this._isOpen;\n\n if (searchable) {\n const searchInput = document.createElement('input');\n searchInput.type = 'text';\n searchInput.className = 'aparte-select-search';\n searchInput.placeholder = 'Search...';\n searchInput.setAttribute('aria-label', 'Search options');\n dropdown.appendChild(searchInput);\n }\n\n const optionsContainer = document.createElement('div');\n optionsContainer.className = 'aparte-select-options';\n optionsContainer.setAttribute('role', 'listbox');\n // A listbox is an ARIA input field, so it needs its own name; reuse the\n // combobox's (axe: aria-input-field-name).\n optionsContainer.setAttribute('aria-label', trigger.getAttribute('aria-label') ?? placeholder);\n // `role=\"combobox\"` REQUIRES aria-controls (axe: aria-required-attr).\n optionsContainer.id = this.id ? `${this.id}-listbox` : `aparte-listbox-${++AparteSelect._listboxSeq}`;\n trigger.setAttribute('aria-controls', optionsContainer.id);\n\n // Move slotted children (aparte-option, aparte-optgroup) into options container\n slottedChildren.forEach(child => {\n if (child.tagName === 'APARTE-OPTION' || child.tagName === 'APARTE-OPTGROUP') {\n optionsContainer.appendChild(child);\n }\n });\n\n dropdown.appendChild(optionsContainer);\n\n // Clear and rebuild DOM\n this._observer?.disconnect();\n this.innerHTML = '';\n this.appendChild(trigger);\n this.appendChild(dropdown);\n\n this._trigger = trigger;\n this._dropdown = dropdown;\n this._searchInput = dropdown.querySelector('.aparte-select-search');\n\n if (this.isConnected) {\n this._setupMutationObserver();\n }\n\n // Update label based on current value\n this._updateTriggerLabel();\n }\n\n private _setupMutationObserver(): void {\n this._observer = new MutationObserver(() => {\n this._updateDropdownContent();\n // The options may have just been replaced under an open dropdown —\n // re-assert the keyboard position on the NEW elements. See\n // {@link _restoreActive}.\n this._restoreActive();\n });\n\n // `subtree` matters: a consumer refreshing a live list writes into\n // `.aparte-select-options` (the model selector does exactly that when the\n // provider list settles), which is a DESCENDANT. Watching only our own\n // children missed it entirely — the highlight vanished with the removed\n // elements and nothing here noticed. Our own writes disconnect the observer\n // first, so this cannot loop.\n this._observer.observe(this, { childList: true, subtree: true });\n }\n\n /**\n * Put the roving highlight back after the options changed underneath it.\n *\n * `data-active` lives on an option ELEMENT, so replacing the list throws it\n * away while `_activeIndex` still claims a position: the highlight disappeared,\n * `aria-activedescendant` kept pointing at an id no longer in the document, and\n * the next ArrowDown moved from the stale index — skipping an option. Only when\n * open and only when a position was held, so a refresh never invents one.\n */\n private _restoreActive(): void {\n if (!this._isOpen || this._activeIndex < 0) return;\n if (this.querySelector('aparte-option[data-active]')) return;\n this._setActive(this._activeIndex);\n }\n\n private _updateDropdownContent(): void {\n // If trigger is gone, the component was likely wiped by innerHTML\n if (!this._trigger || !this.contains(this._trigger)) {\n this._render();\n return;\n }\n\n const optionsContainer = this.querySelector('.aparte-select-options');\n if (!optionsContainer) {\n // If internal UI is present but container is gone\n this._render();\n return;\n }\n\n // Collect all potential options from light DOM\n // (those aren't internal UI elements)\n const lightChildren = Array.from(this.children).filter(child =>\n child.className !== 'aparte-select-trigger' &&\n child.className !== 'aparte-select-dropdown'\n );\n\n if (lightChildren.length === 0) return;\n\n // Pause observer to prevent self-triggering loop\n this._observer?.disconnect();\n\n // Clear container (but keep internal stuff if any)\n optionsContainer.innerHTML = '';\n\n // Move/Append children to container\n lightChildren.forEach(child => {\n optionsContainer.appendChild(child);\n });\n\n // Resume observer\n if (this.isConnected) {\n this._observer?.observe(this, { childList: true, subtree: true });\n }\n\n this._updateTriggerLabel();\n this._restoreActive();\n }\n\n private _setupEventListeners(): void {\n // Trigger click\n this._trigger?.addEventListener('click', () => this._toggle());\n\n // Trigger keyboard\n this._trigger?.addEventListener('keydown', (e) => {\n if (e.key === 'Enter' || e.key === ' ') {\n // When open, Enter/Space selects the active option — handled by\n // the document-level nav handler. Only toggle when closed, so we\n // don't close the dropdown on the very keystroke meant to select.\n if (this._isOpen) return;\n e.preventDefault();\n this._toggle();\n }\n if (e.key === 'ArrowDown' && !this._isOpen) {\n e.preventDefault();\n this._openDropdown();\n }\n });\n\n // Option selection. Removed first: `_setupEventListeners` runs on every\n // connect, and adding the same bound reference twice is a no-op per spec —\n // but being explicit costs nothing and survives a future refactor that\n // rebinds.\n this.removeEventListener('click', this._boundHandleOptionClick);\n this.addEventListener('click', this._boundHandleOptionClick);\n\n // Search filter\n this._searchInput?.addEventListener('input', (e) => {\n const query = (e.target as HTMLInputElement).value.toLowerCase();\n this._filterOptions(query);\n });\n\n // Close on outside click\n document.addEventListener('click', this._boundHandleDocumentClick);\n\n // Keyboard navigation\n document.addEventListener('keydown', this._boundHandleKeydown);\n }\n\n private _handleOptionClick(e: Event): void {\n const option = (e.target as HTMLElement).closest('aparte-option');\n if (option && !option.hasAttribute('disabled')) {\n this._selectOption(option as HTMLElement);\n }\n }\n\n private _handleDocumentClick(e: Event): void {\n if (!this.contains(e.target as Node)) {\n this._closeDropdown();\n }\n }\n\n private _handleKeydown(e: KeyboardEvent): void {\n if (!this._isOpen) return;\n\n // Home/End move the caret when typing in the search box; only hijack\n // them for option navigation when focus is not in the search field.\n const inSearch = document.activeElement === this._searchInput;\n\n switch (e.key) {\n case 'Escape':\n e.preventDefault();\n this._closeDropdown();\n this._trigger?.focus();\n break;\n case 'ArrowDown':\n e.preventDefault();\n this._moveActive(1);\n break;\n case 'ArrowUp':\n e.preventDefault();\n this._moveActive(-1);\n break;\n case 'Home':\n if (inSearch) break;\n e.preventDefault();\n this._setActive(0);\n break;\n case 'End':\n if (inSearch) break;\n e.preventDefault();\n this._setActive(this._visibleOptions().length - 1);\n break;\n case 'Enter': {\n const active = this._visibleOptions()[this._activeIndex];\n if (active) {\n e.preventDefault();\n this._selectOption(active);\n }\n break;\n }\n }\n }\n\n /** Non-disabled, non-filtered options in DOM order. */\n private _visibleOptions(): HTMLElement[] {\n return Array.from(this.querySelectorAll<HTMLElement>('aparte-option')).filter(\n opt => !opt.hasAttribute('disabled') && opt.style.display !== 'none',\n );\n }\n\n /** Move the active (keyboard-highlighted) option by `delta`, clamped. */\n private _moveActive(delta: number): void {\n const opts = this._visibleOptions();\n if (opts.length === 0) return;\n const base = this._activeIndex < 0 ? (delta > 0 ? -1 : 0) : this._activeIndex;\n this._setActive(base + delta);\n }\n\n /** Highlight the option at `index` (clamped) and point aria-activedescendant at it. */\n private _setActive(index: number): void {\n const all = this.querySelectorAll<HTMLElement>('aparte-option');\n all.forEach(o => o.removeAttribute('data-active'));\n\n const opts = this._visibleOptions();\n if (opts.length === 0) {\n this._activeIndex = -1;\n this._trigger?.removeAttribute('aria-activedescendant');\n return;\n }\n const clamped = Math.max(0, Math.min(index, opts.length - 1));\n this._activeIndex = clamped;\n\n const active = opts[clamped]!;\n if (!active.id) active.id = `aparte-option-${++AparteSelect._optIdSeq}`;\n active.setAttribute('data-active', '');\n this._trigger?.setAttribute('aria-activedescendant', active.id);\n active.scrollIntoView?.({ block: 'nearest' });\n }\n\n /** Clear the keyboard highlight (on close). */\n private _clearActive(): void {\n this._activeIndex = -1;\n this._trigger?.removeAttribute('aria-activedescendant');\n this.querySelectorAll('aparte-option').forEach(o => o.removeAttribute('data-active'));\n }\n\n // ─────────────────────────────────────────────────────────────────────────\n // Actions\n // ─────────────────────────────────────────────────────────────────────────\n\n private _toggle(): void {\n if (this._isOpen) {\n this._closeDropdown();\n } else {\n this._openDropdown();\n }\n }\n\n private _openDropdown(): void {\n if (this.hasAttribute('disabled')) return;\n\n this._isOpen = true;\n this._dropdown?.removeAttribute('hidden');\n this._trigger?.setAttribute('aria-expanded', 'true');\n this.setAttribute('open', '');\n\n // Smart Positioning\n this._updatePosition();\n\n // Focus search if available\n this._searchInput?.focus();\n\n // Seed the keyboard highlight on the current selection (or the first\n // option) so ArrowUp/Down have an anchor and screen readers announce it.\n const opts = this._visibleOptions();\n const selectedIdx = opts.findIndex(o => o.getAttribute('value') === this._value);\n this._setActive(selectedIdx >= 0 ? selectedIdx : 0);\n\n this.dispatchEvent(new CustomEvent('aparte-select-open', { bubbles: true }));\n }\n\n private _closeDropdown(): void {\n this._isOpen = false;\n this._clearActive();\n this._dropdown?.setAttribute('hidden', '');\n this._trigger?.setAttribute('aria-expanded', 'false');\n this.removeAttribute('open');\n this.removeAttribute('position'); // Reset position attribute\n\n // Clear position styles set by _updatePosition\n if (this._dropdown) {\n this._dropdown.style.top = '';\n this._dropdown.style.bottom = '';\n this._dropdown.style.left = '';\n this._dropdown.style.width = '';\n }\n\n // Clear search\n if (this._searchInput) {\n this._searchInput.value = '';\n this._filterOptions('');\n }\n\n this.dispatchEvent(new CustomEvent('aparte-select-close', { bubbles: true }));\n }\n\n private _updatePosition(): void {\n if (!this._dropdown || !this._trigger) return;\n\n const rect = this._trigger.getBoundingClientRect();\n const dropdownHeight = this._dropdown.offsetHeight || 300;\n const viewportHeight = window.innerHeight;\n const spaceBelow = viewportHeight - rect.bottom;\n const GAP = 4; // px gap between trigger and dropdown\n\n // Always size to trigger width\n this._dropdown.style.left = `${rect.left}px`;\n this._dropdown.style.width = `${rect.width}px`;\n\n // Decide whether to open upward or downward\n if (spaceBelow < dropdownHeight && rect.top > dropdownHeight) {\n // Open upward\n this._dropdown.style.top = '';\n this._dropdown.style.bottom = `${viewportHeight - rect.top + GAP}px`;\n this.setAttribute('position', 'top');\n } else {\n // Open downward\n this._dropdown.style.top = `${rect.bottom + GAP}px`;\n this._dropdown.style.bottom = '';\n this.removeAttribute('position');\n }\n }\n\n private _selectOption(option: HTMLElement): void {\n const value = option.getAttribute('value') || option.textContent?.trim() || '';\n const previousValue = this._value;\n\n this._value = value;\n this.setAttribute('value', value);\n this._updateTriggerLabel();\n this._closeDropdown();\n this._emitChange(previousValue);\n this._trigger?.focus();\n }\n\n private _updateTriggerLabel(): void {\n const labelEl = this._trigger?.querySelector('.aparte-select-label');\n if (labelEl) {\n const selectedLabel = this._getSelectedLabel();\n labelEl.textContent = selectedLabel || this.getAttribute('placeholder') || 'Select...';\n }\n\n // Update selected state on options\n const options = this.querySelectorAll('aparte-option');\n options.forEach(opt => {\n const isSelected = opt.getAttribute('value') === this._value;\n if (isSelected) {\n opt.setAttribute('selected', '');\n } else {\n opt.removeAttribute('selected');\n }\n });\n }\n\n private _getSelectedLabel(): string {\n // Match by property, not an interpolated attribute selector — a value with\n // `\"`/`]` (e.g. a remote model id) would make querySelector throw SyntaxError.\n for (const opt of this.querySelectorAll('aparte-option')) {\n if (opt.getAttribute('value') === this._value) return opt.textContent?.trim() || '';\n }\n return '';\n }\n\n private _filterOptions(query: string): void {\n const options = this.querySelectorAll('aparte-option');\n options.forEach(opt => {\n const label = opt.textContent?.toLowerCase() || '';\n const matches = label.includes(query);\n (opt as HTMLElement).style.display = matches ? '' : 'none';\n });\n // Re-anchor the keyboard highlight on the first still-visible option.\n if (this._isOpen) this._setActive(0);\n }\n\n private _emitChange(previousValue: string): void {\n const detail: AparteSelectChangeDetail = {\n value: this._value,\n label: this._getSelectedLabel(),\n previousValue\n };\n\n this.dispatchEvent(new CustomEvent<AparteSelectChangeDetail>('aparte-select-change', {\n bubbles: true,\n composed: true,\n detail\n }));\n }\n}\n\n// Register\nif (!customElements.get('aparte-select')) {\n customElements.define('aparte-select', AparteSelect);\n}\n","/**\n * AparteProgressSpinner\n *\n * Circular progress spinner web component.\n * - Indeterminate (no `value` attribute): continuous rotation animation\n * - Determinate (`value=\"0–100\"`): fills the arc proportionally\n *\n * @element aparte-progress-spinner\n * @attr {number} value - Progress percentage 0–100 (omit for indeterminate)\n *\n * @cssvar --aparte-spinner-size Size of the spinner. Default: 14px\n * @cssvar --aparte-spinner-stroke Stroke width in SVG units. Default: 2.5\n * @cssvar --aparte-spinner-color Fill arc stroke color. Default: currentColor\n * @cssvar --aparte-spinner-track Track arc stroke color. Default: 15% currentColor\n *\n * @example\n * <!-- Omit `value` for the indeterminate spin; set it to show real progress. -->\n * <aparte-progress-spinner></aparte-progress-spinner>\n * <aparte-progress-spinner value=\"62\"></aparte-progress-spinner>\n */\nexport class AparteProgressSpinner extends HTMLElement {\n static get observedAttributes(): string[] { return ['value']; }\n\n /** Radius of the SVG circle (viewBox is 0 0 24 24, center at 12,12) */\n private readonly _r = 9;\n private get _circ(): number { return 2 * Math.PI * this._r; }\n\n connectedCallback(): void { this._render(); }\n attributeChangedCallback(): void { this._render(); }\n\n private _render(): void {\n const raw = this.getAttribute('value');\n const value = raw !== null\n ? Math.min(100, Math.max(0, parseFloat(raw) || 0))\n : null;\n\n this.setAttribute('role', 'progressbar');\n this.setAttribute('aria-valuemin', '0');\n this.setAttribute('aria-valuemax', '100');\n if (value !== null) {\n this.setAttribute('aria-valuenow', String(value));\n } else {\n this.removeAttribute('aria-valuenow');\n }\n\n // Determinate: dashoffset shrinks from circ→0 as value goes 0→100\n const dashoffset = value !== null ? this._circ * (1 - value / 100) : 0;\n // Indeterminate: fixed partial arc (~72% of circumference)\n const dasharray = value !== null\n ? `${this._circ.toFixed(2)}`\n : `${(this._circ * 0.72).toFixed(2)} ${(this._circ * 0.28).toFixed(2)}`;\n\n this.innerHTML = `<svg viewBox=\"0 0 24 24\" xmlns=\"http://www.w3.org/2000/svg\" aria-hidden=\"true\"><circle class=\"aparte-spinner-track\" cx=\"12\" cy=\"12\" r=\"${this._r}\"/><circle class=\"aparte-spinner-fill\" cx=\"12\" cy=\"12\" r=\"${this._r}\" stroke-dasharray=\"${dasharray}\" stroke-dashoffset=\"${dashoffset.toFixed(2)}\"/></svg>`;\n }\n}\n\nif (!customElements.get('aparte-progress-spinner')) {\n customElements.define('aparte-progress-spinner', AparteProgressSpinner);\n}\n","import type { AparteChatViewport } from '../viewport/aparte-chat-viewport.js';\nimport type { AparteComposer } from '../composer/aparte-composer.js';\nimport { escapeAttr } from '../../utils/escape.js';\n\n/**\n * AparteChat - The Shell\n *\n * The container element for a chat. Wrap a `<aparte-chat-viewport>` and a\n * `<aparte-composer>` in it and it lays them out as a flex column — the viewport\n * grows and scrolls, the composer sits below. Provide your own children for full\n * control (custom composer, extra buttons), or leave it empty and it fills in a\n * sensible default composition. Uses Light DOM for global CSS styling.\n *\n * Being a component (not a bare `<div>`), it also owns behaviour a wrapper div\n * can't: with `center-empty`, it watches its own viewport and keeps the composer\n * centered as a welcome state until the first message, then slides to the normal\n * layout — no external JavaScript.\n *\n * Presentational only: it does NOT wire a transport/client. Attach an\n * `AparteClient`, or handle `aparte-send` yourself, as with the primitives.\n * Size the element via CSS (a height, or let it fill a sized parent).\n *\n * @element aparte-chat\n * @attr placeholder - Placeholder for the composer input (default composition)\n * @attr disabled - Disables the composer\n * @attr center-empty - Center the composer as a welcome state until the first message, then slide to the normal layout\n * @attr attachments - Add the file picker + chips strip to the default composition (opt-in: the host must consume the files — an `AparteClient` does, a hand-rolled loop must read `event.detail.files`)\n *\n * @example\n * <!-- Left empty it fills in a viewport, an input and a send button. -->\n * <aparte-chat center-empty placeholder=\"Say something…\" style=\"height: 600px\"></aparte-chat>\n *\n * <!-- Or compose it yourself; the container still lays it out and runs center-empty. -->\n * <aparte-chat center-empty attachments style=\"height: 600px\">\n * <aparte-chat-viewport></aparte-chat-viewport>\n * <aparte-composer>\n * <div class=\"aparte-composer-shell\">\n * <div class=\"aparte-composer-row\">\n * <aparte-composer-input style=\"flex: 1\"></aparte-composer-input>\n * <aparte-composer-send></aparte-composer-send>\n * </div>\n * </div>\n * </aparte-composer>\n * </aparte-chat>\n */\nexport class AparteChat extends HTMLElement {\n static get observedAttributes(): string[] {\n return ['placeholder', 'disabled', 'center-empty', 'attachments'];\n }\n\n private _observer: MutationObserver | null = null;\n\n /**\n * True only for the composition THIS element injected. An author-provided\n * composer (or a `framework-managed` host) is never edited by the attachments\n * toggle below — those own their own markup.\n */\n private _ownsShell = false;\n\n connectedCallback(): void {\n this._render();\n this._forwardAttr('placeholder');\n this._forwardAttr('disabled');\n this._syncEmptyWatch();\n }\n\n disconnectedCallback(): void {\n this._observer?.disconnect();\n this._observer = null;\n }\n\n attributeChangedCallback(name: string, oldValue: string | null, newValue: string | null): void {\n if (oldValue === newValue) return;\n if (name === 'center-empty') {\n this._syncEmptyWatch();\n return;\n }\n if (name === 'attachments') {\n this._syncAttachments();\n return;\n }\n // placeholder / disabled forward to the inner composer. An explicit removal\n // mirrors through; a never-set attribute is left alone (so a caller-provided\n // composer keeps its own).\n const composer = this.querySelector('aparte-composer');\n if (!composer) return;\n if (newValue !== null) composer.setAttribute(name, newValue);\n else composer.removeAttribute(name);\n }\n\n /** The message viewport (yours or the default), or `null` before connect. */\n get viewport(): AparteChatViewport | null {\n return this.querySelector('aparte-chat-viewport');\n }\n\n /** The composer (yours or the default), or `null` before connect. */\n get composer(): AparteComposer | null {\n return this.querySelector('aparte-composer');\n }\n\n private _render(): void {\n // A framework wrapper renders the composition itself — and its children do not\n // exist yet when this runs (the element is upgraded on insert, before the\n // framework's template renders), so the viewport check below can't see them.\n // `framework-managed` is the wrapper's explicit \"hands off\" signal: without it\n // the default composition below would be injected UNDER the framework's own.\n if (this.hasAttribute('framework-managed')) return;\n\n // Author-provided composition wins — if a viewport is already inside, use the\n // children as given and only lay them out (via CSS). Otherwise fill in a\n // default viewport + composer so the empty tag \"just works\".\n if (this.querySelector('aparte-chat-viewport')) return;\n\n // The composer's `placeholder` is read by its input via `closest()` at upgrade\n // time (no event), so it must be on the element in the initial markup.\n const placeholder = this.getAttribute('placeholder');\n const composerAttrs =\n (placeholder !== null ? ` placeholder=\"${escapeAttr(placeholder)}\"` : '') +\n (this.hasAttribute('disabled') ? ' disabled' : '');\n\n // Attachments are opt-in: the picker only makes sense when the host consumes\n // the files (an `AparteClient` inlines them per `rawFileInject`; a hand-rolled\n // loop must read `event.detail.files`). Offering it unconditionally would show\n // a button that silently drops what the user attached.\n const attachments = this.hasAttribute('attachments');\n\n this.innerHTML = `\n <aparte-chat-viewport></aparte-chat-viewport>\n <aparte-composer${composerAttrs}>\n <div class=\"aparte-composer-shell\">\n ${attachments ? '<aparte-composer-attachments></aparte-composer-attachments>' : ''}\n <div class=\"aparte-composer-row\">\n ${attachments ? '<aparte-composer-add-attachment></aparte-composer-add-attachment>' : ''}\n <aparte-composer-input></aparte-composer-input>\n <aparte-composer-send></aparte-composer-send>\n </div>\n </div>\n </aparte-composer>\n `;\n this._ownsShell = true;\n }\n\n /**\n * Add/remove the two attachment primitives on the composition we injected, so\n * toggling the attribute after mount works like the wrappers' reactive prop\n * (there, a re-render does it). Author-provided markup is left alone.\n */\n private _syncAttachments(): void {\n if (!this._ownsShell) return;\n const composer = this.composer;\n const shell = composer?.querySelector('.aparte-composer-shell');\n const row = shell?.querySelector('.aparte-composer-row');\n if (!composer || !shell || !row) return;\n\n const strip = shell.querySelector('aparte-composer-attachments');\n const picker = row.querySelector('aparte-composer-add-attachment');\n\n if (this.hasAttribute('attachments')) {\n if (!strip) shell.insertBefore(document.createElement('aparte-composer-attachments'), row);\n if (!picker) row.insertBefore(document.createElement('aparte-composer-add-attachment'), row.firstChild);\n return;\n }\n\n strip?.remove();\n picker?.remove();\n // Files picked before the capability was withdrawn would otherwise ride on\n // the next send with nothing in the UI showing them.\n composer.clearAttachments();\n }\n\n /** Set an attribute on the inner composer only when the shell carries it. */\n private _forwardAttr(name: string): void {\n if (!this.hasAttribute(name)) return;\n this.querySelector('aparte-composer')?.setAttribute(name, this.getAttribute(name) ?? '');\n }\n\n /** Start/stop watching the viewport so `center-empty` toggles itself. */\n private _syncEmptyWatch(): void {\n this._observer?.disconnect();\n this._observer = null;\n\n if (!this.hasAttribute('center-empty')) {\n this.removeAttribute('data-empty');\n return;\n }\n\n const viewport = this.querySelector('aparte-chat-viewport');\n if (!viewport) return;\n\n this._updateEmpty();\n // A message is an <aparte-chat-bubble>; watch the viewport for the first one.\n this._observer = new MutationObserver(() => this._updateEmpty());\n this._observer.observe(viewport, { childList: true, subtree: true });\n }\n\n private _updateEmpty(): void {\n const viewport = this.querySelector('aparte-chat-viewport');\n const empty = !viewport || !viewport.querySelector('aparte-chat-bubble');\n this.toggleAttribute('data-empty', empty);\n }\n\n}\n\n// Register the custom element\nif (!customElements.get('aparte-chat')) {\n customElements.define('aparte-chat', AparteChat);\n}\n","import type {\n AparteBubbleRole,\n AparteSegment,\n AparteAttachment,\n AparteBranchNavigateEventDetail,\n AparteRetryEventDetail,\n AparteEditEventDetail,\n AparteFeedbackEventDetail,\n AparteActionEventDetail,\n AparteMessageInfoEventDetail,\n AparteUsage,\n AparteMessage,\n} from '../../types/index.js';\nimport { getSegmentRenderer, installDefaultRenderersOnce } from '../../renderers/index.js';\nimport { AparteConfig } from '../../config/aparte-config.js';\nimport { resolveConfig, runWithConfig } from '../../config/config-context.js';\nimport { cssEscape } from '../../utils/css-escape.js';\nimport type { AparteComposerInput } from '../composer/aparte-composer-input.js';\nimport { escapeAttr, escapeHtml } from '../../utils/escape.js';\n\n/**\n * Warn ONCE when a segment has no renderer — now only for types core has never\n * heard of, since the built-ins install themselves on first use.\n */\nlet _warnedNoRenderer = false;\nfunction warnMissingRenderer(type: string): void {\n if (_warnedNoRenderer) return;\n _warnedNoRenderer = true;\n console.warn(`[aparte] No renderer for segment \"${type}\". Register one with registerSegmentRenderer({ type: '${type}', render }) from @aparte/core — see https://apartejs.dev/guides/customization/#custom-segment-types`);\n}\n\n/**\n * The renderer for `type`, installing core's built-ins the first time a segment\n * finds the registry empty of its type. `registerDefaultRenderers()` therefore\n * becomes optional rather than a call you discover by seeing\n * `[Unknown segment type: text]` on screen (it is still honoured, and\n * `AparteClient({ autoRegister: false })` still keeps the built-ins out).\n */\nfunction resolveSegmentRenderer(\n type: string,\n config: AparteConfig,\n): ReturnType<typeof getSegmentRenderer> {\n // The CONFIG is passed in, not read ambiently.\n //\n // `runWithConfig` wrapped only `render` / `setup` / `update`, so the renderer's\n // OWN work was per-instance while the question \"which renderer is this?\" was\n // answered from a module-level registry. Two chats on a page therefore shared\n // their segment renderers no matter what `config` prop the wrapper was given —\n // half of the promise those props make.\n const renderer = getSegmentRenderer(type, config);\n if (renderer) return renderer;\n installDefaultRenderersOnce(config);\n return getSegmentRenderer(type, config);\n}\n\n/**\n * Normalize a segment renderer's output to a single element. Renderers may return\n * an HTML **string** (parsed via innerHTML — the built-in renderers) or a ready\n * **HTMLElement** (used directly, so custom renderers can wire event listeners /\n * framework nodes with no innerHTML XSS surface). See {@link AparteSegmentRenderer}.\n */\nfunction segmentRenderResultToElement(result: string | HTMLElement): HTMLElement | null {\n if (result instanceof HTMLElement) return result;\n const wrapper = document.createElement('div');\n wrapper.innerHTML = result;\n return wrapper.firstElementChild as HTMLElement | null;\n}\n\n/** Lucide \"info\" glyph — inline so the action bar needs no icon-provider key. */\nconst INFO_ICON_SVG =\n '<svg xmlns=\"http://www.w3.org/2000/svg\" width=\"15\" height=\"15\" viewBox=\"0 0 24 24\" ' +\n 'fill=\"none\" stroke=\"currentColor\" stroke-width=\"2\" stroke-linecap=\"round\" ' +\n 'stroke-linejoin=\"round\"><circle cx=\"12\" cy=\"12\" r=\"10\"/><path d=\"M12 16v-4\"/>' +\n '<path d=\"M12 8h.01\"/></svg>';\n\n/**\n * AparteChatBubble - The Render\n * \n * Message component supporting both simple content and rich segments.\n * Uses Light DOM for global CSS styling.\n *\n * @example\n * <!-- Rendered for you by the viewport. Written by hand only when you drive the DOM\n * yourself: `message-id` is what streaming and the action bar address it by. -->\n * <aparte-chat-bubble\n * message-id=\"a1\"\n * data-role=\"assistant\"\n * name=\"Assistant\"\n * content=\"Hello.\"\n * ></aparte-chat-bubble>\n *\n * <!-- While a reply is in flight: `streaming` hides the action bar and shows the caret. -->\n * <aparte-chat-bubble message-id=\"a2\" data-role=\"assistant\" streaming></aparte-chat-bubble>\n */\nexport class AparteChatBubble extends HTMLElement {\n private _contentEl: HTMLDivElement | null = null;\n private _segmentsEl: HTMLDivElement | null = null;\n private _attachmentsEl: HTMLDivElement | null = null;\n private _actionBarEl: HTMLDivElement | null = null;\n private _branchPickerEl: HTMLDivElement | null = null;\n private _footerEl: HTMLDivElement | null = null;\n private _content = '';\n private _streaming = false;\n private _segments: AparteSegment[] = [];\n private _role: AparteBubbleRole = 'assistant';\n private _attachments: AparteAttachment[] = [];\n private _usage: AparteUsage | null = null;\n /** Cleanup returned by the avatar provider — called on disconnect/re-render. */\n private _avatarCleanup: (() => void) | null = null;\n /** Sibling count for tree-based branch navigation (set by setSiblings()) */\n private _siblingCount = 1;\n /** Sibling index for tree-based branch navigation (set by setSiblings()) */\n private _siblingIndex = 0;\n /** True while the user-message inline editor is open. */\n private _editing = false;\n /** The live inline editor (the composer's contenteditable primitive), present only while `_editing`. */\n private _editInput: AparteComposerInput | null = null;\n\n static get observedAttributes(): string[] {\n // Both `data-role` (preferred, set by Angular wrapper) and `role` (legacy\n // / direct usage) feed into the same _role state. The host element gets\n // its own `role=\"article\"` set in _render() for ARIA compliance — that\n // is filtered in attributeChangedCallback so it doesn't loop back as a\n // bubble role of \"article\".\n return ['role', 'data-role', 'content', 'timestamp', 'message-id', 'streaming', 'name'];\n }\n\n constructor() {\n super();\n }\n\n // Rebuild the action bar when the global config changes (e.g. a live skin\n // switch calling setBubbleActions / setIconProvider) so already-rendered\n // bubbles pick up the new per-role actions + icons without being re-created.\n private _onConfigChange = (e: Event): void => {\n // Only rebuild for OUR config. An instance-scoped change on another chat —\n // or a global change while we resolve to an instance — must not touch us.\n // A bare dispatch (no detail.config) always rebuilds (e.g. manual notify).\n const detail = (e as CustomEvent).detail as { config?: unknown } | undefined;\n if (detail?.config && detail.config !== this._cfg) return;\n this._updateActionBar();\n // Everything else the locale writes. A language switch is documented as live\n // (\"mounted components re-render immediately\"), and rebuilding only the action\n // bar delivered half of it: the labels changed language while the NAME still\n // read \"You\" and the branch arrows kept their old `aria-label` — a bilingual\n // bubble, fixed only by a reload (which rebuilds the element).\n this._updateName();\n this._updateLocalizedLabels();\n this._updateWaiting();\n };\n\n /**\n * Re-apply the locale strings written straight into the markup by `_render()` —\n * the accessible names a screen reader reads, which nothing else refreshes.\n */\n private _updateLocalizedLabels(): void {\n const locale = this._cfg.getLocale();\n const set = (selector: string, label: string): void => {\n this.querySelector(selector)?.setAttribute('aria-label', label);\n };\n set('.aparte-branch-prev', locale.previousResponse ?? 'Previous response');\n set('.aparte-branch-next', locale.nextResponse ?? 'Next response');\n set('.aparte-action-bar', locale.messageActions ?? 'Message actions');\n }\n\n /**\n * Config governing this bubble: the instance config of the nearest\n * `[data-aparte-host]` boundary, else the global singleton. Resolved live\n * (a single `closest()`) rather than cached — the boundary may be attached\n * AFTER this bubble mounts (AparteChatHost.bind() runs post-mount), so a\n * connect-time cache would freeze the wrong config.\n */\n private get _cfg(): AparteConfig {\n return resolveConfig(this);\n }\n\n connectedCallback(): void {\n this._render();\n this._updateContent();\n // Populate the timestamp from the current attribute. Frameworks that set\n // attributes BEFORE the element is connected (e.g. the Svelte wrapper) fire\n // attributeChangedCallback while _render() hasn't created `.aparte-timestamp`\n // yet, so the initial time would otherwise stay blank. No-ops when the\n // attribute is absent (set later → attributeChangedCallback handles it).\n this._updateTimestamp(this.getAttribute('timestamp'));\n window.addEventListener('aparte-config-change', this._onConfigChange);\n // Delegated, so a re-render cannot lose a click on the branch arrows.\n this.addEventListener('click', this._onBranchPickerClick);\n }\n\n disconnectedCallback(): void {\n window.removeEventListener('aparte-config-change', this._onConfigChange);\n this.removeEventListener('click', this._onBranchPickerClick);\n if (this._avatarCleanup) {\n try { this._avatarCleanup(); } catch { /* ignore */ }\n this._avatarCleanup = null;\n }\n }\n\n attributeChangedCallback(name: string, oldValue: string | null, newValue: string | null): void {\n if (oldValue === newValue) return;\n\n switch (name) {\n case 'role':\n case 'data-role':\n // Skip the ARIA-compliance value we set ourselves in _render().\n // Real bubble roles are 'user' or 'assistant'; anything else is\n // either the 'article' we wrote for accessibility or stale.\n if (newValue === 'article') return;\n if (newValue === 'user' || newValue === 'assistant') {\n this._role = newValue as AparteBubbleRole;\n this._updateRole();\n }\n break;\n case 'content':\n this._content = newValue || '';\n this._updateContent();\n break;\n case 'timestamp':\n this._updateTimestamp(newValue);\n break;\n case 'streaming':\n this._updateStreaming(newValue !== null && newValue !== 'false');\n break;\n case 'name':\n this._updateName();\n break;\n }\n }\n\n // ─────────────────────────────────────────────────────────────────────────\n // Public API\n // ─────────────────────────────────────────────────────────────────────────\n\n /** Append a token chunk (for streaming) */\n appendToken(chunk: string): void {\n this._content += chunk;\n this._updateContent();\n }\n\n /** Set content directly */\n setContent(content: string): void {\n this._content = content;\n this.setAttribute('content', content);\n this._updateContent();\n }\n\n /** Get current content */\n getContent(): string {\n return this._content;\n }\n\n /** Set segments for rich content */\n setSegments(segments: AparteSegment[]): void {\n this._segments = segments;\n this._renderSegments();\n this._updateWaiting();\n }\n\n /** Add a segment */\n addSegment(segment: AparteSegment): void {\n this._segments.push(segment);\n this._appendSegmentEl(segment);\n this._updateWaiting();\n }\n\n /** Update a specific segment */\n updateSegment(segmentId: string, updates: Partial<AparteSegment>): void {\n const index = this._segments.findIndex(s => s.id === segmentId);\n if (index !== -1) {\n const updated = { ...this._segments[index], ...updates } as AparteSegment;\n this._segments[index] = updated;\n this._applySegmentUpdate(segmentId, updated, updates);\n }\n }\n\n /** Append content to a segment */\n appendToSegment(segmentId: string, content: string): void {\n const segment = this._segments.find(s => s.id === segmentId);\n if (segment && 'content' in segment) {\n (segment as { content: string }).content += content;\n this._applySegmentUpdate(segmentId, segment, { content: (segment as AparteSegment & { content: string }).content });\n }\n }\n\n /** Get all segments */\n getSegments(): AparteSegment[] {\n return [...this._segments];\n }\n\n /** Remove a segment by id (e.g. to discard a transient waiting indicator) */\n /**\n * Scoped to DIRECT children on purpose.\n *\n * Segments are appended as direct children of the container, but a descendant\n * query returns the first match in document order — and sanitized model\n * markdown renders inside that same container, with `data-*` attributes\n * deliberately preserved (they are inert). So a decoy `data-segment-id` planted\n * in an earlier segment's prose used to win over the real segment element.\n *\n * Parser ids are unguessable UUIDs, but a tool segment is `tool-${toolCallId}`\n * and the MODEL chooses that id — so this was reachable, and pointing an update\n * at a decoy left a rejected tool rendering as still-running: a spoof against\n * the human-in-the-loop control.\n */\n removeSegment(segmentId: string): void {\n const index = this._segments.findIndex(s => s.id === segmentId);\n if (index !== -1) {\n this._segments.splice(index, 1);\n }\n const el = this._segmentsEl?.querySelector(`:scope > [data-segment-id=\"${cssEscape(segmentId)}\"]`);\n el?.remove();\n this._updateWaiting();\n }\n\n /** Set attachments (chips shown above message content, user role only) */\n setAttachments(attachments: AparteAttachment[]): void {\n this._attachments = attachments;\n this._updateAttachments();\n }\n\n /**\n * Set token usage + timing for this message (assistant only).\n *\n * This is the *precondition* for the info (\"i\") action, not the trigger: the\n * button appears only if the app also declared it wants it —\n * `aparteGlobalConfig.setBubbleActions({ info: true })` — because the stats popover it\n * opens (`aparte-message-info`) is the app's, and core has none. Without usage\n * there is nothing to show, so the button never renders either way.\n */\n setUsage(usage: AparteUsage | null | undefined): void {\n this._usage = usage ?? null;\n this._updateActionBar();\n }\n\n /**\n * Update the branch picker UI for tree-based navigation.\n * The viewport calls this after a branch switch or re-render.\n * Prev/Next clicks dispatch `aparte-branch-navigate` (bubbles: true) so\n * the viewport can handle the actual tree switch.\n */\n setSiblings(count: number, index: number): void {\n this._siblingCount = count;\n this._siblingIndex = index;\n this._updateBranchPicker();\n }\n\n /**\n * Atomic update for the message\n */\n updateMessage(updates: Partial<AparteMessage>): void {\n if ('role' in updates) {\n this._role = updates.role!;\n this._updateRole();\n }\n if ('content' in updates) {\n this._content = updates.content!;\n this._updateContent();\n }\n if ('segments' in updates) {\n this._segments = updates.segments!;\n this._renderSegments();\n }\n if ('timestamp' in updates) {\n this._updateTimestamp(updates.timestamp!);\n }\n if ('status' in updates) {\n const isStreaming = updates.status === 'streaming' || updates.status === 'pending';\n this._updateStreaming(isStreaming);\n }\n if ('attachments' in updates) {\n this._attachments = updates.attachments ?? [];\n this._updateAttachments();\n }\n }\n\n // ─────────────────────────────────────────────────────────────────────────\n // Private Methods\n // ─────────────────────────────────────────────────────────────────────────\n\n private _appendSegmentEl(segment: AparteSegment): void {\n if (!this._segmentsEl) {\n console.warn(`[AparteChatBubble] _appendSegmentEl ABORT: _segmentsEl is null`);\n return;\n }\n const renderer = resolveSegmentRenderer(segment.type, this._cfg);\n if (renderer) {\n // Renderers are plain functions with no element to resolve from — expose\n // this bubble's config as the ambient render config for the duration.\n const el = segmentRenderResultToElement(runWithConfig(this._cfg, () => renderer.render(segment)));\n if (el) {\n this._segmentsEl.appendChild(el);\n runWithConfig(this._cfg, () => renderer.setup?.(el, segment));\n }\n } else {\n warnMissingRenderer(segment.type);\n const fallback = document.createElement('div');\n fallback.className = 'segment segment-unknown';\n fallback.textContent = `[Unknown segment type: ${segment.type}]`;\n this._segmentsEl.appendChild(fallback);\n }\n if (this._contentEl) this._contentEl.style.display = 'none';\n this._reflectError();\n }\n\n private _applySegmentUpdate(segmentId: string, segment: AparteSegment, updates: Partial<AparteSegment>): void {\n const el = this._segmentsEl?.querySelector(`:scope > [data-segment-id=\"${cssEscape(segmentId)}\"]`) as HTMLElement | null;\n if (!el) {\n this._renderSegments();\n return;\n }\n const renderer = resolveSegmentRenderer(segment.type, this._cfg);\n if (!renderer) return;\n\n if (renderer.update) {\n runWithConfig(this._cfg, () => renderer.update!(el, segment));\n } else {\n const newEl = segmentRenderResultToElement(runWithConfig(this._cfg, () => renderer.render(segment)));\n if (newEl) {\n el.replaceWith(newEl);\n runWithConfig(this._cfg, () => renderer.setup?.(newEl, segment));\n }\n }\n\n // Handle collapsed state only when explicitly provided in the update —\n // never override a state the user set by clicking <summary>.\n if ('collapsed' in updates) {\n if ((updates as { collapsed?: boolean }).collapsed) {\n el.removeAttribute('open');\n } else {\n el.setAttribute('open', '');\n }\n }\n }\n\n private _getDisplayName(): string {\n const nameAttr = this.getAttribute('name');\n if (nameAttr) return nameAttr;\n const locale = this._cfg.getLocale();\n return this._role === 'user'\n ? (locale.roleNameUser ?? 'You')\n : (locale.roleNameAssistant ?? 'Assistant');\n }\n\n private _getAvatarInitial(): string {\n const name = this._getDisplayName();\n return name.length > 0 ? name[0]! : (this._role === 'user' ? 'U' : 'A');\n }\n\n private _render(): void {\n // Read the bubble's logical role from `data-role` (preferred — written\n // by the Angular wrapper) or the legacy `role` attribute, then set the\n // host's actual `role` attribute to a valid ARIA value. \"user\" and\n // \"assistant\" are NOT valid ARIA roles and would trigger accessibility\n // warnings in browsers / Lighthouse. The role-based styling lives on\n // inner `data-role` markers, so this swap is transparent to CSS.\n const dataRole = this.getAttribute('data-role');\n const legacyRole = this.getAttribute('role');\n const role = (dataRole && dataRole !== 'article') ? dataRole\n : (legacyRole && legacyRole !== 'article') ? legacyRole\n : 'assistant';\n this._role = role as AparteBubbleRole;\n if (this.getAttribute('role') !== 'article') {\n this.setAttribute('role', 'article');\n }\n if (!this.hasAttribute('data-role')) {\n this.setAttribute('data-role', role);\n }\n\n // Ensure we don't overwrite if already rendered (re-entrancy check)\n if (this.querySelector('.aparte-message')) return;\n\n const displayName = this._getDisplayName();\n const initial = this._getAvatarInitial();\n\n // Custom structural shell (aparteGlobalConfig.setBubbleShellRenderer). Must root at\n // .aparte-message + carry the region hooks; the queries below are null-guarded\n // so a partial shell degrades gracefully. See AparteBubbleShellRenderer.\n const shell = this._cfg.getBubbleShellRenderer?.();\n if (shell) {\n const out = runWithConfig(this._cfg, () => shell({ role: this._role, name: displayName, avatarInitial: initial }));\n if (out instanceof HTMLElement) this.replaceChildren(out);\n else this.innerHTML = out;\n } else {\n this.innerHTML = `\n <div class=\"aparte-message\" data-role=\"${escapeAttr(role)}\" role=\"article\" aria-label=\"${escapeAttr(this._getAriaLabel())}\">\n <div class=\"aparte-avatar\" data-role=\"${escapeAttr(role)}\"></div>\n <div class=\"aparte-body\">\n <div class=\"aparte-header\">\n <span class=\"aparte-name\">${escapeHtml(displayName)}</span>\n <span class=\"aparte-timestamp\"></span>\n </div>\n <div class=\"aparte-attachments\" hidden></div>\n <div class=\"aparte-message-content\">\n <div class=\"aparte-segments\"></div>\n <div class=\"aparte-content\"></div>\n <div class=\"aparte-waiting\" hidden>\n <span class=\"aparte-dots\" aria-hidden=\"true\"><span class=\"aparte-dot\"></span><span class=\"aparte-dot\"></span><span class=\"aparte-dot\"></span></span>\n <span class=\"aparte-sr-only\"></span>\n </div>\n </div>\n <div class=\"aparte-footer\">\n <div class=\"aparte-branch-picker\" hidden>\n <button class=\"aparte-branch-prev\" aria-label=\"${escapeAttr(this._cfg.getLocale().previousResponse ?? 'Previous response')}\">‹</button>\n <span class=\"aparte-branch-label\">1 / 1</span>\n <button class=\"aparte-branch-next\" aria-label=\"${escapeAttr(this._cfg.getLocale().nextResponse ?? 'Next response')}\">›</button>\n </div>\n <div class=\"aparte-action-bar\" role=\"toolbar\" aria-label=\"${escapeAttr(this._cfg.getLocale().messageActions ?? 'Message actions')}\"></div>\n </div>\n </div>\n </div>\n `;\n }\n\n this._contentEl = this.querySelector('.aparte-content');\n this._segmentsEl = this.querySelector('.aparte-segments');\n this._attachmentsEl = this.querySelector('.aparte-attachments');\n this._actionBarEl = this.querySelector('.aparte-action-bar');\n this._branchPickerEl = this.querySelector('.aparte-branch-picker');\n this._footerEl = this.querySelector('.aparte-footer');\n\n this._updateActionBar();\n this._renderAvatar();\n // Re-apply the streaming state onto the freshly-built `.aparte-message`.\n // Framework wrappers create the element with its attributes already set, so\n // `streaming` arrives BEFORE this render and `_updateStreaming()` had nothing\n // to write to — leaving a pending assistant bubble without `aria-busy` and\n // with its action bar exposed (copy/retry on an empty, still-streaming reply).\n if (this._streaming) this._updateStreaming(true);\n this._updateWaiting();\n }\n\n /**\n * Show the built-in waiting indicator while this bubble is in flight and has\n * nothing to show yet — the gap between \"user sends\" and the first token, which\n * used to be a bubble with a name and an empty body.\n *\n * The dots are CSS (no per-token work, themable, honours reduced-motion); the\n * accessible name is `locale.typing`, next to the `aria-busy` the streaming state\n * already sets. A custom bubble shell without the region simply has no indicator\n * (same null-guarded degradation as the other region hooks).\n */\n private _updateWaiting(): void {\n const el = this.querySelector('.aparte-waiting') as HTMLElement | null;\n if (!el) return;\n const waiting = this._streaming\n && this._role !== 'user'\n && this._segments.length === 0\n && !this._content.trim();\n el.hidden = !waiting;\n if (!waiting) return;\n const label = this._cfg.getLocale().typing;\n const sr = el.querySelector('.aparte-sr-only');\n if (sr && sr.textContent !== label) sr.textContent = label;\n }\n\n /**\n * Hand the avatar host element off to the registered AvatarProvider, if\n * any. Falls back to the default initial / image rendered by `_render()`\n * when no provider is set.\n */\n private _renderAvatar(): void {\n const avatar = this.querySelector('.aparte-avatar') as HTMLElement | null;\n if (!avatar) return;\n\n // Tear down any previously-mounted live component before re-rendering.\n if (this._avatarCleanup) {\n try { this._avatarCleanup(); } catch { /* ignore */ }\n this._avatarCleanup = null;\n }\n\n const provider = this._cfg.getAvatarProvider();\n if (!provider) return; // keep the default text initial from _render()\n\n avatar.textContent = '';\n const cleanup = provider.render(this._role, avatar);\n if (typeof cleanup === 'function') this._avatarCleanup = cleanup;\n }\n\n private _updateRole(): void {\n const message = this.querySelector('.aparte-message');\n const avatar = this.querySelector('.aparte-avatar');\n const nameEl = this.querySelector('.aparte-name');\n\n if (message) {\n message.setAttribute('data-role', this._role);\n message.setAttribute('aria-label', this._getAriaLabel());\n }\n if (avatar) {\n avatar.setAttribute('data-role', this._role);\n // Default initial — overridden below by the avatar provider if any.\n avatar.textContent = this._getAvatarInitial();\n }\n if (nameEl) {\n nameEl.textContent = this._getDisplayName();\n }\n // Re-render the action bar so buttons match the correct role\n // (critical when the role attribute is set after connectedCallback)\n this._updateActionBar();\n this._renderAvatar();\n }\n\n private _updateName(): void {\n const avatar = this.querySelector('.aparte-avatar') as HTMLElement | null;\n const nameEl = this.querySelector('.aparte-name');\n // Only refresh the initial when no provider owns the avatar — otherwise\n // we'd wipe the live component on every name change.\n if (avatar && !this._cfg.getAvatarProvider()) avatar.textContent = this._getAvatarInitial();\n if (nameEl) nameEl.textContent = this._getDisplayName();\n }\n\n private _updateContent(): void {\n if (!this._contentEl) return;\n\n // If we have segments, don't render simple content\n if (this._segments.length > 0) {\n this._contentEl.style.display = 'none';\n this._updateWaiting();\n return;\n }\n\n this._contentEl.style.display = '';\n this._contentEl.innerHTML = this._cfg.renderMarkdown(this._content);\n // The first token retires the waiting indicator (and a cleared content brings\n // it back, e.g. a retry that resets the bubble before re-streaming).\n this._updateWaiting();\n // The Markdown provider only emits plain <pre><code>; apply the registered\n // syntax highlighter (if any) to those blocks. Skipped while streaming —\n // re-run once on completion (see _updateStreaming) to avoid per-token churn.\n if (!this._streaming) this._highlightContentCode();\n }\n\n /**\n * Apply the registered syntax-highlight provider to the code blocks produced\n * by the Markdown provider in the simple-content path. Provider-agnostic: a\n * full-block provider (e.g. Shiki) returns `<pre>…</pre>` so we replace the\n * element; a token provider (e.g. Prism, highlight.js) returns inner HTML so\n * we fill the existing `<code>`. No-op when no highlighter is installed.\n */\n private _highlightContentCode(): void {\n if (!this._contentEl || !this._cfg.hasHighlightProvider()) return;\n this._contentEl.querySelectorAll('pre > code').forEach((codeEl) => {\n const code = codeEl.textContent ?? '';\n if (!code.trim()) return;\n const match = codeEl.className.match(/language-([\\w+#-]+)/i);\n const lang = match?.[1] ?? '';\n const pre = codeEl.parentElement;\n Promise.resolve(this._cfg.highlightCode(code, lang)).then((html) => {\n const out = (html ?? '').trim();\n if (!out || !pre || !pre.isConnected) return;\n if (/^<pre[\\s>]/i.test(out)) {\n pre.outerHTML = out; // full block (Shiki)\n } else {\n (codeEl as HTMLElement).innerHTML = out; // inner tokens (Prism, hljs)\n }\n }).catch(() => { /* keep the plain block on failure */ });\n });\n }\n\n private _renderSegments(): void {\n if (!this._segmentsEl) return;\n\n // Clear existing segments\n this._segmentsEl.innerHTML = '';\n\n for (const segment of this._segments) {\n const renderer = resolveSegmentRenderer(segment.type, this._cfg);\n if (renderer) {\n const el = segmentRenderResultToElement(runWithConfig(this._cfg, () => renderer.render(segment)));\n if (el) {\n this._segmentsEl.appendChild(el);\n runWithConfig(this._cfg, () => renderer.setup?.(el, segment));\n }\n } else {\n // Fallback for unknown segment types\n warnMissingRenderer(segment.type);\n const fallback = document.createElement('div');\n fallback.className = 'segment segment-unknown';\n fallback.textContent = `[Unknown segment type: ${segment.type}]`;\n this._segmentsEl.appendChild(fallback);\n }\n }\n\n // Hide simple content when segments are present\n if (this._contentEl) {\n this._contentEl.style.display = this._segments.length > 0 ? 'none' : '';\n }\n this._reflectError();\n }\n\n /**\n * Reflect the error state on the bubble: `data-error` on `.aparte-message` while\n * an error segment is present. Derived from segments (not the message `status`\n * attribute) so it works identically in vanilla and in every wrapper — the\n * error segment flows through the reactive list in all of them. CSS themes\n * `.aparte-message[data-error]`; custom error content is via setErrorRenderer.\n */\n private _reflectError(): void {\n const message = this.querySelector('.aparte-message');\n if (!message) return;\n const hasError = this._segments.some(s => s.type === 'error');\n if (hasError) message.setAttribute('data-error', '');\n else message.removeAttribute('data-error');\n }\n\n private _updateTimestamp(value: string | number | null): void {\n const timestampEl = this.querySelector('.aparte-timestamp');\n if (!timestampEl || !value) return;\n\n try {\n const date = new Date(isNaN(Number(value)) ? value : Number(value));\n timestampEl.textContent = date.toLocaleTimeString(undefined, {\n hour: '2-digit',\n minute: '2-digit'\n });\n } catch {\n timestampEl.textContent = '';\n }\n }\n\n private _getAriaLabel(): string {\n const locale = this._cfg.getLocale();\n return this._role === 'user'\n ? (locale.yourMessage ?? 'Your message')\n : (locale.assistantResponse ?? 'Assistant response');\n }\n\n // ─────────────────────────────────────────────────────────────────────────\n // Attachments\n // ─────────────────────────────────────────────────────────────────────────\n\n private _updateAttachments(): void {\n if (!this._attachmentsEl) return;\n\n if (this._role !== 'user' || this._attachments.length === 0) {\n this._attachmentsEl.hidden = true;\n this._attachmentsEl.innerHTML = '';\n return;\n }\n\n this._attachmentsEl.hidden = false;\n\n // Custom attachment chips (aparteGlobalConfig.setAttachmentRenderer) — one node per\n // attachment; the consumer owns markup + interactions (no default preview wiring).\n const customAttachment = this._cfg.getAttachmentRenderer?.();\n if (customAttachment) {\n this._attachmentsEl.replaceChildren();\n for (const a of this._attachments) {\n const el = segmentRenderResultToElement(runWithConfig(this._cfg, () => customAttachment(a)));\n if (el) this._attachmentsEl.appendChild(el);\n }\n return;\n }\n\n this._attachmentsEl.innerHTML = this._attachments.map(a => {\n const name = escapeHtml(a.name);\n if (a.type.startsWith('image/')) {\n return `<div class=\"aparte-thumb aparte-thumb--image\" title=\"${name}\">`\n + `<img class=\"aparte-thumb__img\" src=\"${escapeHtml(a.url)}\" alt=\"${name}\" loading=\"lazy\" />`\n + `<span class=\"aparte-thumb__name\">${name}</span></div>`;\n }\n return `<div class=\"aparte-thumb aparte-thumb--file\" title=\"${name}\">`\n + `<span class=\"aparte-thumb__ext\">${escapeHtml(this._fileExt(a.name))}</span>`\n + `<span class=\"aparte-thumb__name\">${name}</span></div>`;\n }).join('');\n\n // Image tiles ask for a full-size preview — but the lightbox is the app's, so\n // the tile only becomes a button once the app declared it opens one. Otherwise\n // it stays a plain picture: no role, no tab stop, no pointer (see the CSS,\n // which keys the cursor off role=\"button\").\n if (!this._cfg.getHostHandlers().attachmentPreview) return;\n this._attachmentsEl.querySelectorAll('.aparte-thumb--image').forEach(tile => {\n tile.setAttribute('role', 'button');\n tile.setAttribute('tabindex', '0');\n const open = (): void => {\n const img = tile.querySelector('.aparte-thumb__img') as HTMLImageElement | null;\n if (!img) return;\n this.dispatchEvent(new CustomEvent('aparte-attachment-preview', {\n bubbles: true, composed: true,\n detail: { url: img.src, name: tile.getAttribute('title') ?? '' },\n }));\n };\n tile.addEventListener('click', open);\n tile.addEventListener('keydown', (e) => {\n const key = (e as KeyboardEvent).key;\n if (key !== 'Enter' && key !== ' ') return;\n e.preventDefault();\n open();\n });\n });\n }\n\n /** Uppercased file extension (≤4 chars), or 'FILE' when there is none. */\n private _fileExt(filename: string): string {\n const dot = filename.lastIndexOf('.');\n return dot > 0 ? filename.slice(dot + 1).toUpperCase().slice(0, 4) : 'FILE';\n }\n\n // ─────────────────────────────────────────────────────────────────────────\n // Branch Picker\n // ─────────────────────────────────────────────────────────────────────────\n\n /**\n * The branch arrows are handled by DELEGATION, on this element, bound once.\n *\n * They used to get a fresh listener each, attached by `_render()` to the buttons\n * `_render()` had just created. So a click that landed while a re-render was\n * swapping those nodes hit an element about to be discarded, and did nothing at\n * all — not late, nothing. Invisible on a fast machine; reproducible on\n * WebKit-Linux in CI, where `‹` left the picker on \"2 / 2\" and a 20-second\n * assertion watched it stay there.\n *\n * Delegation makes `_render()` irrelevant to it: the listener lives on the host,\n * which is never replaced, and `closest()` finds whichever button exists at the\n * moment of the click. It is also less work — one listener per bubble instead of\n * two per bubble per render.\n *\n * Bound in `connectedCallback` and removed in `disconnectedCallback` as a stable\n * field, because an inline arrow re-added on every re-connect is how this repo has\n * stacked listeners twice before (the viewport, and `aparte-select`).\n */\n private _onBranchPickerClick = (event: Event): void => {\n const target = event.target as HTMLElement | null;\n const button = target?.closest?.('.aparte-branch-prev, .aparte-branch-next');\n if (!button || !this.contains(button)) return;\n const direction = button.classList.contains('aparte-branch-prev') ? 'prev' : 'next';\n const messageId = this.getAttribute('message-id');\n if (!messageId) return;\n const detail: AparteBranchNavigateEventDetail = { messageId, direction };\n // Tree-based navigation: let the viewport handle the branch switch\n this.dispatchEvent(new CustomEvent<AparteBranchNavigateEventDetail>('aparte-branch-navigate', {\n bubbles: true,\n composed: true,\n detail,\n }));\n };\n\n private _updateBranchPicker(): void {\n if (!this._branchPickerEl) return;\n if (this._siblingCount <= 1 || this._role !== 'assistant') {\n this._branchPickerEl.hidden = true;\n this._syncFooterVisibility();\n return;\n }\n this._branchPickerEl.hidden = false;\n this._syncFooterVisibility();\n const label = this._branchPickerEl.querySelector('.aparte-branch-label');\n if (label) {\n // Custom position indicator (aparteGlobalConfig.setSiblingNavRenderer) — e.g. dots —\n // fills the label between the arrows; the arrows keep their behavior.\n const customNav = this._cfg.getSiblingNavRenderer?.();\n if (customNav) {\n const out = runWithConfig(this._cfg, () => customNav({ count: this._siblingCount, index: this._siblingIndex }));\n if (out instanceof HTMLElement) label.replaceChildren(out);\n else label.innerHTML = out;\n } else {\n label.textContent = `${this._siblingIndex + 1} / ${this._siblingCount}`;\n }\n }\n\n const prevBtn = this._branchPickerEl.querySelector('.aparte-branch-prev') as HTMLButtonElement | null;\n const nextBtn = this._branchPickerEl.querySelector('.aparte-branch-next') as HTMLButtonElement | null;\n if (prevBtn) prevBtn.disabled = this._siblingIndex === 0;\n if (nextBtn) nextBtn.disabled = this._siblingIndex === this._siblingCount - 1;\n }\n\n // ─────────────────────────────────────────────────────────────────────────\n // Action Bar\n // ─────────────────────────────────────────────────────────────────────────\n\n private _updateActionBar(): void {\n if (!this._actionBarEl) return;\n // While the inline editor is open the bar shows save (✓) / cancel (✗).\n if (this._editing) {\n this._renderEditActions();\n return;\n }\n const config = this._cfg.getBubbleActions();\n const icons = this._cfg.getIconProvider();\n const locale = this._cfg.getLocale();\n const buttons: string[] = [];\n\n if (this._role === 'user') {\n if (config.user) {\n // Explicit ordered set replaces the flag defaults for user bubbles.\n for (const a of config.user) buttons.push(this._actionButtonHtml(a, icons, locale));\n } else {\n // Flag-driven set. Only `copy` is on by default — see\n // APARTE_DEFAULT_BUBBLE_ACTIONS: edit needs a host to keep the new text.\n if (config.copy) buttons.push(this._actionButtonHtml('copy', icons, locale));\n if (config.edit) buttons.push(this._actionButtonHtml('edit', icons, locale));\n }\n } else if (this._role === 'assistant') {\n if (config.assistant) {\n // Explicit ordered set replaces the flag defaults (incl. the info button).\n for (const a of config.assistant) buttons.push(this._actionButtonHtml(a, icons, locale));\n } else {\n // Flag-driven set. Only `copy` is on by default — retry, feedback and\n // info all need a host or a listener to mean anything.\n if (config.copy) buttons.push(this._actionButtonHtml('copy', icons, locale));\n if (config.retry) buttons.push(this._actionButtonHtml('retry', icons, locale));\n if (config.feedback) {\n buttons.push(this._actionButtonHtml('thumbUp', icons, locale));\n buttons.push(this._actionButtonHtml('thumbDown', icons, locale));\n }\n if (config.info) buttons.push(this._actionButtonHtml('info', icons, locale));\n }\n }\n\n this._actionBarEl.innerHTML = buttons.join('');\n\n // Custom actions registered via aparteGlobalConfig.registerAction — appended\n // after the built-ins, built as DOM (label goes to attributes, never\n // interpolated into innerHTML) so a consumer label can't inject markup.\n this._appendCustomActions(icons);\n\n // Wire up button handlers — messageId read dynamically at click time\n // so it's always correct even when Angular sets the attribute after connectedCallback\n this._actionBarEl.querySelectorAll('.aparte-action-btn').forEach(btn => {\n btn.addEventListener('click', (e) => this._handleActionClick(e as MouseEvent));\n });\n\n this._syncFooterVisibility();\n }\n\n /**\n * An empty action bar is not a bar: with every action off it was still a\n * `role=\"toolbar\"` with nothing in it (announced as such), and it still reserved\n * its fixed height plus the footer's under every bubble. So both follow their\n * contents — the footer stays as long as the branch picker or the bar has\n * something to show.\n */\n private _syncFooterVisibility(): void {\n if (this._actionBarEl) this._actionBarEl.hidden = this._actionBarEl.children.length === 0;\n if (!this._footerEl) return;\n const barEmpty = !this._actionBarEl || this._actionBarEl.hidden;\n const pickerHidden = !this._branchPickerEl || this._branchPickerEl.hidden;\n this._footerEl.hidden = barEmpty && pickerHidden;\n }\n\n /** Append the registered custom action buttons for this bubble's role. */\n private _appendCustomActions(icons: ReturnType<AparteConfig['getIconProvider']>): void {\n if (!this._actionBarEl) return;\n for (const a of this._cfg.getActions('bubble')) {\n const roles = a.bubble?.roles ?? ['user', 'assistant'];\n if (!roles.includes(this._role)) continue;\n const btn = document.createElement('button');\n btn.className = 'aparte-action-btn aparte-action-custom';\n btn.dataset['action'] = `custom:${a.id}`;\n // aria-label/title via setAttribute — safe for consumer-provided strings.\n btn.setAttribute('aria-label', a.label);\n btn.setAttribute('title', a.label);\n // Icon: raw inline SVG/HTML, else an icon-provider key (trusted output).\n const fromProvider = (icons as unknown as Record<string, (() => string) | undefined>)[a.icon];\n btn.innerHTML = a.icon.startsWith('<')\n ? a.icon\n : (typeof fromProvider === 'function' ? fromProvider() : (a.iconFallback ?? ''));\n this._actionBarEl.appendChild(btn);\n }\n }\n\n /** Build the `<button>` HTML for a single named action (shared by flag + per-role rendering). */\n private _actionButtonHtml(\n action: string,\n icons: ReturnType<AparteConfig['getIconProvider']>,\n locale: ReturnType<AparteConfig['getLocale']>,\n ): string {\n switch (action) {\n case 'copy': {\n const l = locale.copy ?? 'Copy';\n return `<button class=\"aparte-action-btn aparte-action-copy\" data-action=\"copy\" aria-label=\"${escapeAttr(l)}\" title=\"${escapeAttr(l)}\">${icons.copy()}</button>`;\n }\n case 'edit': {\n const l = locale.edit ?? 'Edit message';\n return `<button class=\"aparte-action-btn aparte-action-edit\" data-action=\"edit\" aria-label=\"${escapeAttr(l)}\" title=\"${escapeAttr(l)}\">${icons.edit()}</button>`;\n }\n case 'retry': {\n const l = locale.retry ?? 'Retry';\n return `<button class=\"aparte-action-btn aparte-action-retry\" data-action=\"retry\" aria-label=\"${escapeAttr(l)}\" title=\"${escapeAttr(l)}\">${icons.retry()}</button>`;\n }\n case 'thumbUp': {\n const l = locale.feedbackPositive ?? 'Good response';\n return `<button class=\"aparte-action-btn aparte-action-feedback-pos\" data-action=\"feedback-positive\" aria-label=\"${escapeAttr(l)}\" title=\"${escapeAttr(l)}\">${icons.thumbUp()}</button>`;\n }\n case 'thumbDown': {\n const l = locale.feedbackNegative ?? 'Bad response';\n return `<button class=\"aparte-action-btn aparte-action-feedback-neg\" data-action=\"feedback-negative\" aria-label=\"${escapeAttr(l)}\" title=\"${escapeAttr(l)}\">${icons.thumbDown()}</button>`;\n }\n case 'info': {\n // Only when there are numbers to show: a details button over nothing is a\n // dead button. The popover itself is the app's (see `aparte-message-info`).\n if (!this._usage) return '';\n const l = locale.messageInfo ?? 'Details';\n return `<button class=\"aparte-action-btn aparte-action-info\" data-action=\"info\" aria-label=\"${escapeAttr(l)}\" title=\"${escapeAttr(l)}\">${INFO_ICON_SVG}</button>`;\n }\n default:\n return '';\n }\n }\n\n /** Render the edit-mode action bar: ✓ save (green) + ✗ cancel (red). */\n private _renderEditActions(): void {\n if (!this._actionBarEl) return;\n const locale = this._cfg.getLocale();\n const saveLabel = locale.editConfirm ?? 'Save';\n const cancelLabel = locale.editCancel ?? 'Cancel';\n this._actionBarEl.innerHTML =\n `<button class=\"aparte-action-btn aparte-action-edit-save\" data-action=\"edit-save\" ` +\n `aria-label=\"${escapeAttr(saveLabel)}\" title=\"${escapeAttr(saveLabel)}\">${this._cfg.getIcon('check')}</button>` +\n `<button class=\"aparte-action-btn aparte-action-edit-cancel\" data-action=\"edit-cancel\" ` +\n `aria-label=\"${escapeAttr(cancelLabel)}\" title=\"${escapeAttr(cancelLabel)}\">${this._cfg.getIcon('close')}</button>`;\n this._actionBarEl.querySelectorAll('.aparte-action-btn').forEach(btn => {\n btn.addEventListener('click', (e) => this._handleActionClick(e as MouseEvent));\n });\n // Save/cancel must show even when every action flag is off.\n this._syncFooterVisibility();\n }\n\n private _handleActionClick(e: MouseEvent): void {\n const btn = (e.currentTarget as HTMLElement);\n const action = btn.dataset['action'];\n // Read dynamically — attribute may not be set yet at render time\n const messageId = this.getAttribute('message-id');\n\n // Custom actions (aparteGlobalConfig.registerAction) emit a generic aparte-action\n // event carrying the action id — same DOM-event contract as retry/feedback.\n if (action?.startsWith('custom:') && messageId) {\n const actionId = action.slice('custom:'.length);\n const detail: AparteActionEventDetail = {\n actionId,\n zone: 'bubble',\n messageId,\n role: this._role,\n targetId: this._resolveTargetId(),\n };\n this.dispatchEvent(new CustomEvent<AparteActionEventDetail>('aparte-action', {\n bubbles: true, composed: true, detail,\n }));\n this._cfg.getActions('bubble').find(x => x.id === actionId)?.onClick?.(e);\n return;\n }\n\n switch (action) {\n case 'copy': {\n const text = this._content || this._segments.map(s => (s as { content?: string }).content ?? '').join('\\n');\n const icons = this._cfg.getIconProvider();\n const locale = this._cfg.getLocale();\n navigator.clipboard.writeText(text).then(() => {\n btn.innerHTML = icons.check();\n btn.setAttribute('data-copied', '');\n const copiedLabel = locale.copied ?? locale.copy ?? 'Copied';\n btn.setAttribute('title', copiedLabel);\n btn.setAttribute('aria-label', copiedLabel);\n setTimeout(() => {\n btn.removeAttribute('data-copied');\n btn.innerHTML = icons.copy();\n const copyLabel = locale.copy ?? 'Copy';\n btn.setAttribute('title', copyLabel);\n btn.setAttribute('aria-label', copyLabel);\n }, 2000);\n }).catch(() => {\n console.warn('[aparte] Clipboard write failed');\n });\n break;\n }\n case 'retry': {\n if (!messageId) break;\n const targetId = this._resolveTargetId();\n const detail: AparteRetryEventDetail = { messageId, targetId };\n this.dispatchEvent(new CustomEvent<AparteRetryEventDetail>('aparte-retry', {\n bubbles: true, composed: true,\n detail,\n }));\n break;\n }\n case 'edit': {\n this._enterEditMode();\n break;\n }\n case 'edit-save': {\n this._exitEditMode(true);\n break;\n }\n case 'edit-cancel': {\n this._exitEditMode(false);\n break;\n }\n case 'feedback-positive':\n case 'feedback-negative': {\n if (!messageId) break;\n const value: AparteFeedbackEventDetail['value'] = action === 'feedback-positive' ? 'positive' : 'negative';\n btn.setAttribute('data-submitted', '');\n const detail: AparteFeedbackEventDetail = { messageId, value };\n this.dispatchEvent(new CustomEvent<AparteFeedbackEventDetail>('aparte-feedback', {\n bubbles: true, composed: true,\n detail,\n }));\n break;\n }\n case 'info': {\n if (!messageId) break;\n const detail: AparteMessageInfoEventDetail = {\n messageId,\n usage: this._usage ?? undefined,\n };\n this.dispatchEvent(new CustomEvent<AparteMessageInfoEventDetail>('aparte-message-info', {\n bubbles: true, composed: true,\n detail,\n }));\n break;\n }\n }\n }\n\n /**\n * Open the inline editor for a user message. Idempotent — a second `edit`\n * click while already editing is a no-op (no stacked editors).\n *\n * The editor reuses the composer's contenteditable primitive\n * (`<aparte-composer-input>`) so editing is iso with composing: same autosize,\n * IME, paste and styling. With no `<aparte-composer>` root it runs standalone —\n * `Enter` (Shift+Enter = newline) surfaces as `aparte-composer-submit`, which we\n * treat as save; `Esc` cancels.\n */\n private _enterEditMode(): void {\n if (this._editing || !this._contentEl) return;\n this._editing = true;\n this.querySelector('.aparte-message')?.setAttribute('data-editing', '');\n\n const input = document.createElement('aparte-composer-input') as AparteComposerInput;\n input.setAttribute('placeholder', this._cfg.getLocale().edit ?? 'Edit message');\n this._editInput = input;\n\n this._contentEl.style.display = 'none';\n this._contentEl.insertAdjacentElement('afterend', input);\n // `insertAdjacentElement` upgrades + connects synchronously, so the editor is\n // ready — seed it with the current text (autosizes to fit).\n input.setValue(this._content);\n\n // Enter (via the primitive's standalone submit event) saves; Esc cancels.\n input.addEventListener('aparte-composer-submit', () => this._exitEditMode(true));\n input.addEventListener('keydown', (e) => {\n if (e.key === 'Escape' && !e.isComposing) {\n e.preventDefault();\n this._exitEditMode(false);\n }\n });\n\n // Swap the action bar over to ✓ / ✗.\n this._updateActionBar();\n\n input.focusEnd();\n }\n\n /**\n * Leave edit mode. When `save` is true and the text actually changed, emits\n * `aparte-edit`; otherwise restores the original message untouched. Always\n * restores the normal action bar and removes the inline editor.\n */\n private _exitEditMode(save: boolean): void {\n if (!this._editing) return;\n const newContent = this._editInput?.getValue() ?? '';\n const original = this._content;\n\n this._editInput?.remove();\n this._editInput = null;\n if (this._contentEl) this._contentEl.style.display = '';\n this.querySelector('.aparte-message')?.removeAttribute('data-editing');\n this._editing = false;\n this._updateActionBar();\n\n if (save && newContent && newContent !== original) {\n const messageId = this.getAttribute('message-id');\n if (messageId) {\n const detail: AparteEditEventDetail = {\n messageId,\n content: newContent,\n targetId: this._resolveTargetId(),\n };\n this.dispatchEvent(new CustomEvent<AparteEditEventDetail>('aparte-edit', {\n bubbles: true, composed: true,\n detail,\n }));\n }\n }\n }\n\n private _resolveTargetId(): string | undefined {\n // Walk up to the chat host element with an id. Angular's wrapper root IS the\n // `<aparte-chat>` element (its component selector); the plain-root wrappers\n // (React/Vue/Svelte) render a `<div class=\"aparte-chat-container\" data-aparte-chat\n // id=\"…\">` instead — so match `[data-aparte-chat]` too. Without this, retry/edit\n // resolved to `undefined` outside Angular and AparteClient's fallback hit the\n // bare `<aparte-chat-viewport>` (a different message store) → retry regenerated\n // into the void.\n let el: HTMLElement | null = this.parentElement;\n while (el) {\n const tag = el.tagName?.toLowerCase();\n const isHost = tag === 'aparte-chat' || tag === 'aparte-chat-component' || el.hasAttribute?.('data-aparte-chat');\n if (isHost && el.id) return el.id;\n el = el.parentElement;\n }\n return undefined;\n }\n\n // ─────────────────────────────────────────────────────────────────────────\n // Utilities\n // ─────────────────────────────────────────────────────────────────────────\n\n\n private _updateStreaming(streaming: boolean): void {\n const wasStreaming = this._streaming;\n this._streaming = streaming;\n const message = this.querySelector('.aparte-message');\n if (message) {\n message.setAttribute('data-streaming', String(streaming));\n if (streaming) {\n // Signal \"in progress\" to assistive tech; clearing it on completion\n // cues screen readers (via the viewport's aria-live region) to read\n // the finished response.\n message.setAttribute('aria-busy', 'true');\n message.classList.add('aparte-message-streaming');\n } else {\n message.removeAttribute('aria-busy');\n message.classList.remove('aparte-message-streaming');\n }\n }\n this._updateWaiting();\n // Streaming just finished: highlight the final content once (skipped during\n // streaming to avoid re-highlighting on every token).\n if (wasStreaming && !streaming) this._highlightContentCode();\n }\n}\n\n// Register the custom element\nif (!customElements.get('aparte-chat-bubble')) {\n customElements.define('aparte-chat-bubble', AparteChatBubble);\n}\n","/**\n * AparteChatStatus - The Indicator\n * \n * Lightweight typing indicator with elegant animation.\n * Uses Light DOM for global CSS styling.\n * \n * @element aparte-chat-status\n * @attr {boolean} visible - Show/hide the indicator\n * @attr {string} text - Custom text (default: \"Typing...\")\n */\nimport { AparteConfig } from '../../config/aparte-config.js';\nimport { resolveConfig, runWithConfig } from '../../config/config-context.js';\n\n/**\n * @example\n * <!-- The app owns this indicator: core never turns it on by itself, so there is\n * never a second one competing with the bubble's built-in waiting state. -->\n * <aparte-chat-status visible text=\"Searching the docs…\"></aparte-chat-status>\n */\nexport class AparteChatStatus extends HTMLElement {\n static get observedAttributes(): string[] {\n return ['visible', 'text'];\n }\n\n /**\n * Resolved LIVE, not cached. Caching it at connect made this element\n * permanently deaf to its own instance: `_onConfigChange` filters on\n * `detail.config !== this._cfg`, so once `_cfg` had latched the global config no\n * change for the real instance ever matched, and the filter meant to isolate\n * chats became the thing that silenced one.\n */\n private get _cfg(): AparteConfig {\n return resolveConfig(this);\n }\n\n constructor() {\n super();\n }\n\n connectedCallback(): void {\n // Cache the resolved config (instance boundary or global fallback), like the\n // other Aparte elements — so a scoped setStatusRenderer applies here too.\n this._render();\n // Re-render on a live config change (e.g. setStatusRenderer called after this\n // element already upgraded — it self-registers on import, so a persistent\n // <aparte-chat-status> in the page mounts before any config runs). Mirrors the\n // bubble's config-change subscription.\n window.addEventListener('aparte-config-change', this._onConfigChange);\n }\n\n disconnectedCallback(): void {\n window.removeEventListener('aparte-config-change', this._onConfigChange);\n }\n\n private _onConfigChange = (e: Event): void => {\n // Only react to OUR config (an instance-scoped change elsewhere must not touch\n // us). A bare notify (no detail.config) always re-renders.\n const detail = (e as CustomEvent).detail as { config?: unknown } | undefined;\n if (detail?.config && detail.config !== this._cfg) return;\n // Clear so _render's re-entrancy guard doesn't bail; visible/text are read\n // from attributes, so the shown state is preserved across the re-render.\n this.innerHTML = '';\n this._render();\n };\n\n attributeChangedCallback(name: string, oldValue: string | null, newValue: string | null): void {\n if (oldValue === newValue) return;\n\n switch (name) {\n case 'visible':\n this._updateVisibility(newValue !== null);\n break;\n case 'text':\n this._updateText(newValue);\n break;\n }\n }\n\n /**\n * Show the typing indicator\n */\n show(): void {\n this.setAttribute('visible', '');\n }\n\n /**\n * Hide the typing indicator\n */\n hide(): void {\n this.removeAttribute('visible');\n }\n\n /**\n * Toggle visibility\n */\n toggle(): void {\n if (this.hasAttribute('visible')) {\n this.hide();\n } else {\n this.show();\n }\n }\n\n /**\n * Check if visible\n */\n isVisible(): boolean {\n return this.hasAttribute('visible');\n }\n\n private _render(): void {\n const text = this.getAttribute('text') || 'Typing';\n const visible = this.hasAttribute('visible');\n\n // Re-entrancy check\n if (this.querySelector('.aparte-status-container')) return;\n\n // Custom typing indicator (charter §6 render hook): replace the inner markup\n // while the container keeps owning show/hide (data-visible) + accessible name.\n const custom = this._cfg?.getStatusRenderer?.();\n if (custom) {\n this.innerHTML =\n `<div class=\"aparte-message aparte-status-container\" data-visible=\"${visible}\" role=\"status\" aria-live=\"polite\"></div>`;\n const container = this.querySelector('.aparte-status-container') as HTMLElement;\n // `text` set via setAttribute, never interpolated — a `\"` would break out.\n container.setAttribute('aria-label', text);\n const result = runWithConfig(this._cfg, () => custom(text));\n if (result instanceof HTMLElement) container.appendChild(result);\n else container.innerHTML = result;\n return;\n }\n\n this.innerHTML = `\n <div\n class=\"aparte-message aparte-status-container\"\n data-visible=\"${visible}\"\n role=\"status\"\n aria-live=\"polite\"\n >\n <div class=\"aparte-avatar\" data-role=\"assistant\" style=\"visibility: hidden\"></div>\n <div class=\"aparte-body\">\n <div class=\"aparte-status-content\">\n <div class=\"aparte-dots\" aria-hidden=\"true\">\n <span class=\"aparte-dot\"></span>\n </div>\n <span class=\"aparte-status-text\"></span>\n </div>\n </div>\n </div>\n `;\n // Set the (public, attacker-controllable) `text` via setAttribute/textContent\n // rather than interpolating it into the innerHTML template — a `\"` in the\n // attribute would otherwise break out and inject arbitrary attributes.\n this.querySelector('.aparte-status-container')?.setAttribute('aria-label', text);\n // Visible text only when explicitly requested — the default stays dots-only\n // (the aria-label above always carries the accessible name).\n if (this.hasAttribute('text')) {\n const textEl = this.querySelector('.aparte-status-text');\n if (textEl) textEl.textContent = text;\n }\n }\n\n private _updateVisibility(visible: boolean): void {\n const container = this.querySelector('.aparte-status-container');\n if (container) {\n container.setAttribute('data-visible', String(visible));\n }\n }\n\n private _updateText(text: string | null): void {\n const textEl = this.querySelector('.aparte-status-text');\n const container = this.querySelector('.aparte-status-container');\n if (!container) return; // not rendered yet — _render() reads the attribute\n // Removing the attribute restores the dots-only default (empty visible\n // text); the aria-label always keeps an accessible name.\n if (textEl) textEl.textContent = text ?? '';\n container.setAttribute('aria-label', text || 'Typing');\n }\n}\n\n// Register the custom element\nif (!customElements.get('aparte-chat-status')) {\n customElements.define('aparte-chat-status', AparteChatStatus);\n}\n","import type {\n AparteMessage,\n AparteViewportConfig,\n AparteSegment,\n AparteSegmentUpdateEventDetail,\n ApartePathChangedEventDetail,\n AparteSiblingInfo,\n AparteUsage,\n} from '../../types/index.js';\nimport { resolveConfig } from '../../config/index.js';\nimport { AparteMessageRepository } from '../../runtime/message-repository.js';\nimport type { ExportedMessageRepository } from '../../runtime/message-repository.js';\nimport { populateBubbleFromMessage, type SyncableBubble } from '../bubble/bubble-sync.js';\nimport { cssEscape } from '../../utils/css-escape.js';\nimport { isAwaitingReply } from '../../utils/is-awaiting-reply.js';\nimport { revokeAttachmentUrls } from '../../utils/files-to-attachments.js';\nimport { uuid } from '../../utils/uuid.js';\nimport {\n stampSegmentOnInsert,\n stampSegmentOnUpdate,\n renumberSegments,\n openSegmentIds,\n stampSegmentActivity,\n isTerminalStatus,\n} from '../../utils/segments.js';\n\n/**\n * AparteChatViewport - The Core\n * \n * Container component with smart scroll, streaming, and segment support.\n * Uses Light DOM for global CSS styling.\n * \n * @element aparte-chat-viewport\n * \n * Features:\n * - Smart Scroll: Sticks to bottom when user is at bottom, stops on manual scroll up\n * - appendToken(): For simple content streaming\n * - appendToSegment(): For segment-aware streaming (thinking, code, etc.)\n * - Internal message registry for memory management\n *\n * @example\n * // Three calls are a whole streamed turn.\n * const viewport = document.querySelector('aparte-chat-viewport')!;\n *\n * viewport.appendMessage({ id: 'a1', role: 'assistant', content: '', timestamp: Date.now() });\n * for await (const chunk of tokens) viewport.appendToken('a1', chunk);\n * viewport.completeMessage('a1'); // stops the streaming caret\n */\nexport class AparteChatViewport extends HTMLElement {\n // The scroll surface: an internal `.aparte-viewport-container` div (core mode)\n // or the host element itself (framework-managed mode). HTMLElement covers both.\n private _container: HTMLElement | null = null;\n private _scrollBtn: HTMLButtonElement | null = null;\n private _bottomSpacer: HTMLDivElement | null = null;\n /**\n * In framework-managed mode there is no spacer ELEMENT (an extra child would\n * collide with the framework's own DOM reconciliation). The spacer is an\n * additive `padding-bottom` on the host, tracked here so `_recalculateSpacer`\n * can read the current value without measuring an element.\n */\n private _fwSpacerHeight = 0;\n private _spacerRafId: number | null = null;\n private _spacerFrozenUntil: number = 0;\n private _layoutTransitionMs: number = 0;\n private _repo = new AparteMessageRepository();\n private _isAutoScrollEnabled: boolean = true;\n private _scrollThreshold: number = 50;\n /** When true, the next _autoScroll() call uses smooth instead of instant, then resets. */\n private _smoothScrollOnce: boolean = false;\n /**\n * DOM render cap: the max number of `<aparte-chat-bubble>` elements kept in the\n * DOM at once (a perf ceiling for very long conversations). This NEVER evicts\n * messages from the repository — the full conversation tree and its persistence\n * snapshot stay intact; only the oldest rendered bubbles are dropped from view.\n */\n private _maxRenderedBubbles: number = 1000;\n /** One-time guard for the deprecated `maxMessages` warning. */\n private _warnedMaxMessagesDeprecation = false;\n private _resizeObserver: ResizeObserver | null = null;\n private _mutationObserver: MutationObserver | null = null;\n private _boundResetHandler: (() => void) | null = null;\n /**\n * When true, _reRenderActivePath() only dispatches aparte-path-changed without\n * touching the DOM. Set via setFrameworkManagedDOM(true) when a framework\n * (e.g. Angular) owns the bubble elements.\n */\n private _frameworkManagedDOM = false;\n\n static get observedAttributes(): string[] {\n return ['scroll-threshold', 'max-rendered-bubbles', 'max-messages'];\n }\n\n constructor() {\n super();\n this._handleScroll = this._handleScroll.bind(this);\n }\n\n connectedCallback(): void {\n // Framework wrappers set `framework-managed` DECLARATIVELY so the flag is\n // known BEFORE _render() builds the DOM. Otherwise _render()'s child\n // relocation runs at connect — before the host's setFrameworkManagedDOM()\n // call — moving the framework's bubbles into an internal wrapper and\n // breaking its reconciliation (insertBefore NotFoundError on the next\n // append). See _setupFrameworkDOM().\n if (this.hasAttribute('framework-managed')) this._frameworkManagedDOM = true;\n this._render();\n this._setupEventListeners();\n this._setupObservers();\n this._boundResetHandler = () => this.clearAll();\n window.addEventListener('aparte-reset', this._boundResetHandler);\n window.addEventListener('aparte-config-change', this._onConfigChange);\n }\n\n /**\n * A locale switch changes the reading direction, and `dir` was applied once at\n * render — so a chat already on screen never flipped to RTL until a reload.\n * Only OUR config: an instance-scoped change elsewhere must not touch us.\n */\n private _onConfigChange = (e: Event): void => {\n const detail = (e as CustomEvent).detail as { config?: unknown } | undefined;\n if (detail?.config && detail.config !== resolveConfig(this)) return;\n this._applyDirection();\n };\n\n /** Mirror `locale.direction` onto the scroll container. */\n private _applyDirection(): void {\n const container = this.querySelector('.aparte-viewport-container');\n if (!container) return;\n const direction = resolveConfig(this).getLocale().direction;\n if (direction) container.setAttribute('dir', direction);\n else container.removeAttribute('dir');\n }\n\n disconnectedCallback(): void {\n window.removeEventListener('aparte-config-change', this._onConfigChange);\n if (this._boundResetHandler) {\n window.removeEventListener('aparte-reset', this._boundResetHandler);\n this._boundResetHandler = null;\n }\n this._cleanup();\n }\n\n attributeChangedCallback(name: string, oldValue: string | null, newValue: string | null): void {\n if (oldValue === newValue) return;\n\n switch (name) {\n case 'scroll-threshold':\n this._scrollThreshold = parseInt(newValue || '50', 10);\n break;\n case 'max-rendered-bubbles':\n this._maxRenderedBubbles = parseInt(newValue || '1000', 10);\n this._pruneRenderedBubbles();\n break;\n case 'max-messages':\n // Deprecated alias. It used to evict messages from the tree\n // (destructive, silent data loss); it now only caps rendered\n // bubbles in the DOM. Use `max-rendered-bubbles` instead.\n this._warnMaxMessagesDeprecated();\n this._maxRenderedBubbles = parseInt(newValue || '1000', 10);\n this._pruneRenderedBubbles();\n break;\n }\n }\n\n /**\n * Configure viewport with options\n */\n configure(config: AparteViewportConfig): void {\n if (config.scrollThreshold !== undefined) {\n this._scrollThreshold = config.scrollThreshold;\n }\n if (config.maxRenderedBubbles !== undefined) {\n this._maxRenderedBubbles = config.maxRenderedBubbles;\n this._pruneRenderedBubbles();\n }\n if (config.maxMessages !== undefined) {\n // Deprecated alias (see attributeChangedCallback).\n this._warnMaxMessagesDeprecated();\n this._maxRenderedBubbles = config.maxMessages;\n this._pruneRenderedBubbles();\n }\n if (config.layoutTransitionMs !== undefined) {\n this._layoutTransitionMs = config.layoutTransitionMs;\n }\n }\n\n // ─────────────────────────────────────────────────────────────────────────\n // Simple Content Streaming\n // ─────────────────────────────────────────────────────────────────────────\n\n /**\n * Append a token chunk to a message's content (simple text streaming)\n * @param messageId - Unique identifier for the message\n * @param chunk - Token chunk to append\n */\n appendToken(messageId: string, chunk: string): void {\n const message = this._getOrCreateMessage(messageId);\n\n // Append to simple content\n message.content = (message.content || '') + chunk;\n\n // Notify bubble\n this._notifyBubble(messageId, 'appendToken', chunk);\n this._autoScroll();\n this._scheduleSpacerUpdate();\n }\n\n // ─────────────────────────────────────────────────────────────────────────\n // Segment-Aware Streaming\n // ─────────────────────────────────────────────────────────────────────────\n\n /**\n * Append content to a specific segment within a message\n * @param messageId - Message containing the segment\n * @param segmentId - Target segment ID\n * @param chunk - Content to append\n */\n appendToSegment(messageId: string, segmentId: string, chunk: string): void {\n const message = this._getOrCreateMessage(messageId);\n\n // Find or create segment\n if (!message.segments) {\n message.segments = [];\n }\n\n // REPLACE the segment, never mutate it in place. The bubble holds the very\n // same object — `addSegment` handed one object to the repo and to the bubble —\n // and it appends this chunk itself (see `_notifyBubble` below). Mutating here\n // made the two writes land on one object, so every chunk appeared twice, in\n // the model AND on screen (\"BonjourBonjour le le monde\"). Each view now owns\n // the value it advances.\n const index = message.segments.findIndex(s => s.id === segmentId);\n const segment = index === -1 ? undefined : message.segments[index];\n if (segment && 'content' in segment) {\n message.segments[index] = {\n ...segment,\n content: (segment as { content: string }).content + chunk,\n // Content arriving IS the segment's activity, so this is what\n // `endedAt` measures. Without it a thinking block's end would be\n // whenever someone happened to notice it had stopped — the end of\n // the turn, or the start of the next segment — and both of those\n // silently fold the waiting that followed into the duration.\n ...stampSegmentActivity(segment),\n } as AparteSegment;\n }\n\n // Dispatch segment update event\n this.dispatchEvent(new CustomEvent<AparteSegmentUpdateEventDetail>('aparte-segment-update', {\n bubbles: true,\n composed: true,\n detail: { messageId, segmentId, content: chunk, append: true }\n }));\n\n // Notify bubble\n this._notifyBubble(messageId, 'appendToSegment', chunk, segmentId);\n this._autoScroll();\n }\n\n /**\n * The active (head) message id — the target of `AparteClient`'s 1-argument\n * streaming convention (`addSegment(segment)`, `updateSegment(segmentId,\n * updates)`, …) which operates on \"the current message\". Lets a bare\n * `<aparte-chat-viewport>` be a valid `AparteClient` target, exactly like a\n * framework wrapper's host element.\n */\n private _activeMessageId(): string | null {\n // The head, UNLESS a different message is the one actually streaming.\n //\n // The 1-argument convention means \"operate on the message being streamed\",\n // and this resolved it as \"the head\" — but `appendMessage` always moves the\n // head (the repository advances it to any new child). So any message appended\n // mid-stream re-pointed the rest of the reply: measured with the real element,\n // segment two of message A landed on message B, and `updateSegment` for a\n // segment that genuinely lives on A became a silent no-op.\n //\n // `AparteChatHost` has had `_isOrphan` for exactly this, which is why the\n // framework wrappers were protected and the raw viewport — the documented\n // vanilla quick start — was not. Refusing, like the host does, rather than\n // routing: losing the tail is visible, writing it onto someone else's message\n // is not.\n const head = this._repo.headId;\n const streaming = this._streamingMessageId();\n if (streaming !== null && streaming !== head) return null;\n return head;\n }\n\n /** The id of the message currently streaming, if any. */\n private _streamingMessageId(): string | null {\n for (const message of this._repo.getMessages()) {\n if ((message as { isStreaming?: boolean }).isStreaming) return message.id;\n }\n return null;\n }\n\n /**\n * Add a new segment. Two calling conventions are accepted:\n * - `addSegment(segment)` — AparteClient's 1-arg \"operate on the current\n * (head) message\" convention (also what a wrapper host installs);\n * - `addSegment(messageId, segment)` — explicit standalone form.\n * The first argument's type disambiguates (string = messageId, object =\n * segment), so a raw viewport driven by `AparteClient` no longer drops text\n * (the args used to bind one position short, creating a phantom message).\n */\n addSegment(segment: AparteSegment): void;\n addSegment(messageId: string, segment: AparteSegment): void;\n addSegment(messageIdOrSegment: string | AparteSegment, maybeSegment?: AparteSegment): void {\n const messageId = typeof messageIdOrSegment === 'string' ? messageIdOrSegment : this._activeMessageId();\n const segment = typeof messageIdOrSegment === 'string' ? maybeSegment : messageIdOrSegment;\n if (!messageId || !segment) return;\n\n const message = this._getOrCreateMessage(messageId);\n if (!message.segments) {\n message.segments = [];\n }\n // Identity and start time land BEFORE anyone sees the object: the repo and\n // the bubble are handed the same segment, so a later stamp would leave one\n // of the two holding an unstamped copy. This is one of exactly two places\n // that writes those fields (`aparte-chat-host` is the other) — see\n // `utils/segments.ts` for why it is not the parser.\n const stamped = stampSegmentOnInsert(message.segments, segment, messageId);\n message.segments.push(stamped);\n\n // Notify bubble to render the new segment\n this._notifyBubble(messageId, 'addSegment', stamped);\n this._autoScroll();\n }\n\n /**\n * Update a segment. `updateSegment(segmentId, updates)` (1-arg client\n * convention → current message) or `updateSegment(messageId, segmentId,\n * updates)` (explicit). Disambiguated by arity: the 3rd arg is absent and\n * the 2nd is the `updates` object in the 1-arg form.\n */\n updateSegment(segmentId: string, updates: Partial<AparteSegment>): void;\n updateSegment(messageId: string, segmentId: string, updates: Partial<AparteSegment>): void;\n updateSegment(a: string, b: string | Partial<AparteSegment>, c?: Partial<AparteSegment>): void {\n const clientForm = c === undefined && typeof b === 'object';\n const messageId = clientForm ? this._activeMessageId() : a;\n const segmentId = clientForm ? a : (b as string);\n const updates = clientForm ? (b as Partial<AparteSegment>) : (c as Partial<AparteSegment>);\n if (!messageId) return;\n\n const message = this._repo.getMessageById(messageId);\n if (!message?.segments) return;\n\n const segmentIndex = message.segments.findIndex(s => s.id === segmentId);\n if (segmentIndex !== -1) {\n const current = message.segments[segmentIndex]!;\n // An update that settles the segment carries its `endedAt`. Stamped\n // here rather than at each call site, so `completeSegment`, a tool\n // resolution and an app's own `updateSegment` all measure alike.\n const stamped = stampSegmentOnUpdate(current, updates);\n message.segments[segmentIndex] = {\n ...current,\n ...stamped\n } as AparteSegment;\n\n this._notifyBubble(messageId, 'updateSegment', { segmentId, updates: stamped });\n }\n }\n\n /**\n * Remove a segment. `removeSegment(segmentId)` (1-arg client convention →\n * current message) or `removeSegment(messageId, segmentId)` (explicit).\n */\n removeSegment(segmentId: string): void;\n removeSegment(messageId: string, segmentId: string): void;\n removeSegment(a: string, b?: string): void {\n const clientForm = b === undefined;\n const messageId = clientForm ? this._activeMessageId() : a;\n const segmentId = clientForm ? a : b;\n if (!messageId || !segmentId) return;\n\n const message = this._repo.getMessageById(messageId);\n if (message?.segments) {\n const idx = message.segments.findIndex(s => s.id === segmentId);\n if (idx !== -1) {\n message.segments.splice(idx, 1);\n // `index` is a position, so a removal has to close the gap it left.\n renumberSegments(message.segments);\n }\n }\n this._notifyBubble(messageId, 'removeSegment', segmentId);\n }\n\n /**\n * Start a new streaming segment (e.g., thinking or code block)\n * Creates the segment and marks it as streaming\n */\n startSegment(messageId: string, segment: AparteSegment): void {\n const streamingSegment = { ...segment, isStreaming: true };\n this.addSegment(messageId, streamingSegment);\n }\n\n /**\n * Complete a streaming segment\n */\n completeSegment(messageId: string, segmentId: string): void {\n this.updateSegment(messageId, segmentId, { isStreaming: false });\n }\n\n /**\n * Persist token usage on a message and propagate to the live bubble, which is\n * what allows the info (\"i\") action to render — provided the app declared it\n * with `aparteGlobalConfig.setBubbleActions({ info: true })`; it is off by default,\n * since the popover it opens belongs to the app.\n */\n setUsage(messageId: string, usage: AparteUsage): void {\n const message = this._repo.getMessageById(messageId);\n if (message) message.usage = usage;\n this._notifyBubble(messageId, 'setUsage', usage);\n }\n\n // ─────────────────────────────────────────────────────────────────────────\n // Message Management\n // ─────────────────────────────────────────────────────────────────────────\n\n /**\n * Mark a message as finished streaming\n */\n completeMessage(messageId: string): void {\n const message = this._repo.getMessageById(messageId);\n if (message) {\n message.isStreaming = false;\n message.status = 'completed';\n\n // The message's end IS its segments' end: nothing in the stream says a\n // thinking block is over. Routed through `updateSegment` rather than\n // written onto the objects, so the bubble is told as well — a silent\n // mutation stamped the model and left the renderer thinking it was still\n // streaming, which is exactly what a browser run showed.\n this._settleSegments(messageId, message);\n\n this._notifyBubble(messageId, 'complete', { status: 'completed' });\n this._recalculateSpacer();\n }\n }\n\n /**\n * Close a finished message's still-open segments, one `updateSegment` each.\n *\n * Deliberately NOT a loop that writes `isStreaming` onto the objects: that path\n * stamps the model and tells the bubble nothing, so a renderer never learns its\n * segment settled — no `endedAt` in the rendered label, and no final Markdown\n * flush either. Going through `updateSegment` reuses the one path that does\n * both.\n */\n private _settleSegments(messageId: string, message: AparteMessage): void {\n if (!message.segments) return;\n for (const id of openSegmentIds(message.segments)) {\n this.updateSegment(messageId, id, { isStreaming: false });\n }\n }\n\n /**\n * Atomic update for a message by ID\n * Supports updating content, status, segments, and other metadata\n */\n updateMessage(messageId: string, updates: Partial<AparteMessage>): void {\n const message = this._repo.getMessageById(messageId);\n if (!message) return;\n\n // Apply updates to internal state\n Object.assign(message, updates);\n\n // Map AparteStatus to isStreaming for legacy bubble support\n if (updates.status) {\n message.isStreaming = updates.status === 'streaming' || updates.status === 'pending';\n // …and close the segments, because THIS is the path a completed turn\n // takes: both agent loops report the end with\n // `updateMessage({ status: 'completed' })`, and `completeMessage()` is\n // called by nobody. Without this a thinking segment kept `isStreaming`\n // unset forever and never recorded an `endedAt` — the duration only\n // worked for tool calls, which settle by their own status.\n if (isTerminalStatus(updates.status)) this._settleSegments(messageId, message);\n }\n\n // Notify bubble\n this._notifyBubble(messageId, 'update', updates);\n this._autoScroll();\n }\n\n /**\n * Add a complete message to the message registry.\n *\n * @remarks\n * **Framework-managed DOM only.** Records the message in the tree but does NOT\n * paint a bubble on its own (a framework wrapper reconciles the DOM from the\n * list). For standalone / vanilla usage call {@link appendMessage} instead,\n * which both records the message and creates its bubble element.\n */\n addMessage(message: AparteMessage): void {\n this._repo.addOrUpdateMessage(this._repo.headId, { ...message });\n this._pruneRenderedBubbles();\n this._autoScroll();\n }\n\n /**\n * Append a new message and create its bubble in the DOM.\n * Implements the same contract as the Angular wrapper's appendMessage(),\n * making aparte-chat-viewport a fully standalone target for aparte-client.\n * When `_frameworkManagedDOM` is true, only the internal repo is updated —\n * the framework owns the DOM and will create the bubble element itself.\n */\n appendMessage(message: AparteMessage): void {\n this._repo.addOrUpdateMessage(this._repo.headId, { ...message });\n if (!this._frameworkManagedDOM) {\n const wrapper = this.querySelector('.aparte-messages-wrapper');\n if (wrapper) {\n const bubble = document.createElement('aparte-chat-bubble') as HTMLElement;\n bubble.setAttribute('message-id', message.id);\n bubble.setAttribute('role', message.role);\n if (message.timestamp) bubble.setAttribute('timestamp', String(message.timestamp));\n if (message.content) bubble.setAttribute('content', message.content);\n // Also true for an empty assistant message with no status: an\n // imperative \"the reply is coming\" shell, which otherwise rendered\n // as a finished answer (action bar and all) before a single token.\n if (isAwaitingReply(message)) {\n bubble.setAttribute('streaming', '');\n }\n // Insert before spacer so spacer stays last\n if (this._bottomSpacer && this._bottomSpacer.parentNode === wrapper) {\n wrapper.insertBefore(bubble, this._bottomSpacer);\n } else {\n wrapper.appendChild(bubble);\n }\n // Attributes alone can't carry segments / attachments / usage —\n // push them through the same helper the full render path uses,\n // or an imperatively appended message renders text-only.\n populateBubbleFromMessage(bubble as unknown as SyncableBubble, message);\n }\n }\n this._pruneRenderedBubbles();\n this._recalculateSpacer();\n // User sending always anchors to bottom regardless of scroll position.\n if (message.role === 'user') {\n this._isAutoScrollEnabled = true;\n // Smooth scroll for user-initiated sends. Streaming auto-scroll stays\n // instant (via _autoScroll) so it can keep up with rapid token bursts.\n requestAnimationFrame(() => this._smoothScrollToBottom());\n } else {\n this._autoScroll();\n }\n }\n\n /**\n * Update the last message content, optionally appending.\n * Implements the same contract as the Angular wrapper's updateLastMessage(),'\n * making aparte-chat-viewport a fully standalone streaming target for aparte-client.\n */\n updateLastMessage(content: string, options?: { append?: boolean }): void {\n const lastId = this._repo.headId;\n if (!lastId) return;\n if (options?.append) {\n this.appendToken(lastId, content);\n } else {\n const message = this._repo.getMessageById(lastId);\n if (message) message.content = content;\n this._notifyBubble(lastId, 'appendToken', content);\n }\n }\n\n /**\n * Add a new sibling branch to an assistant message (retry flow).\n * Creates a new empty assistant message as a sibling of `messageId`\n * under the same parent, switches the active branch to it, and\n * re-renders the active path.\n * @returns The index of the new branch in the siblings array, or 0 on failure.\n */\n addBranch(messageId: string): number {\n const meta = this._repo.getMessage(messageId);\n if (!meta) return 0;\n\n const newMsg: AparteMessage = {\n id: uuid(),\n role: 'assistant',\n content: '',\n status: 'pending',\n timestamp: Date.now(),\n };\n this._repo.addOrUpdateMessage(meta.parentId, newMsg);\n this._repo.switchToBranch(newMsg.id);\n this._reRenderActivePath();\n\n const siblings = this._repo.getBranches(newMsg.id);\n return siblings.indexOf(newMsg.id);\n }\n\n /**\n * Add a new message relative to `existingId`, switch to it, and re-render.\n *\n * Role-aware semantics:\n * - existingId is an **assistant** message → create a sibling (same parent),\n * so the active path replaces the old response with the new one.\n * - existingId is a **user** message → create a child of that message,\n * so the user message stays on the active path and the new response follows it.\n *\n * Returns the new message's ID, or null if `existingId` is not found.\n */\n addSiblingOf(existingId: string, newMessage: AparteMessage): string | null {\n const meta = this._repo.getMessage(existingId);\n if (!meta) return null;\n\n // User messages: new response is a child (keep user on active path).\n // Assistant messages: new response is a sibling (replace old response).\n const parentId = meta.message.role === 'user'\n ? existingId\n : meta.parentId;\n this._repo.addOrUpdateMessage(parentId, { ...newMessage });\n this._repo.switchToBranch(newMessage.id);\n this._reRenderActivePath();\n return newMessage.id;\n }\n\n /**\n * Navigate to the previous or next sibling branch of a message.\n * Triggers a full re-render of the active path.\n */\n navigateBranch(messageId: string, direction: 'prev' | 'next'): void {\n const siblings = this._repo.getBranches(messageId);\n const currentIdx = siblings.indexOf(messageId);\n if (currentIdx === -1) return;\n\n const targetIdx = direction === 'prev' ? currentIdx - 1 : currentIdx + 1;\n if (targetIdx < 0 || targetIdx >= siblings.length) return;\n\n // Branch navigation is a deliberate user action, so it must not yank a user\n // who is reading mid-transcript: auto-scroll goes off and neither the spacer\n // recalculation nor the MutationObserver callback will scroll them away.\n //\n // But if they were already AT the bottom, staying there IS the expected\n // behaviour — and switching auto-follow off there is what left the\n // scroll-to-bottom button offering to scroll nowhere (bonaparte, React). It\n // also protects the swap itself: a rebuild's height flickers (measured on\n // React: 1730 → 1934 → 1730px as the new bubble renders and settles), so a\n // reader pinned to the bottom would drift up by whatever the flicker was.\n this._isAutoScrollEnabled = this._isAtBottom();\n this._updateScrollButton();\n\n this._repo.switchToBranch(siblings[targetIdx]!);\n this._reRenderActivePath();\n }\n\n /**\n * Remove ALL responses to a user message (every child branch) and set head\n * back to `userMessageId`. Cleaner than `truncateFrom` for edit flows: it\n * discards stale sibling branches so the regenerated response starts alone.\n */\n truncateResponsesAfter(userMessageId: string): void {\n const prevMessages = this._repo.getMessages();\n this._repo.clearChildren(userMessageId);\n\n // In framework-managed mode the host (Angular @for, React, etc.) owns\n // the bubble DOM. Removing nodes from under it triggers\n // `NotFoundError: Failed to execute 'insertBefore'` on the next change\n // detection cycle because the framework's view tree no longer matches\n // the actual DOM. Skip the manual cleanup and let the framework\n // reconcile when the consumer updates its message array.\n if (!this._frameworkManagedDOM) {\n const wrapper = this.querySelector('.aparte-messages-wrapper');\n if (wrapper) {\n const startIdx = prevMessages.findIndex(m => m.id === userMessageId);\n const toRemove = startIdx >= 0 ? prevMessages.slice(startIdx + 1) : [];\n for (const m of toRemove) {\n wrapper.querySelector(`aparte-chat-bubble[message-id=\"${cssEscape(m.id)}\"]`)?.remove();\n }\n }\n }\n }\n\n /**\n * Remove all messages from `messageId` onwards (inclusive) from state and DOM.\n * Used by edit to truncate history before re-generating.\n */\n truncateFrom(messageId: string): void {\n const allMsgs = this._repo.getMessages();\n const startIdx = allMsgs.findIndex(m => m.id === messageId);\n if (startIdx === -1) return;\n\n const toRemove = allMsgs.slice(startIdx).map(m => m.id);\n this._repo.resetHead(messageId);\n\n // See the note in truncateResponsesAfter: skip DOM ops when a framework\n // owns the bubble elements.\n if (!this._frameworkManagedDOM) {\n const wrapper = this.querySelector('.aparte-messages-wrapper');\n for (const id of toRemove) {\n wrapper?.querySelector(`aparte-chat-bubble[message-id=\"${cssEscape(id)}\"]`)?.remove();\n }\n }\n }\n\n /**\n * Get a message by ID\n */\n getMessage(messageId: string): AparteMessage | undefined {\n return this._repo.getMessageById(messageId);\n }\n\n getMessages(): AparteMessage[] {\n return this._repo.getMessages();\n }\n\n /**\n * Export the full conversation tree (all branches, not just the active path).\n * The returned snapshot can be persisted and restored via `importTree()`.\n */\n exportTree(): ExportedMessageRepository {\n return this._repo.export();\n }\n\n /**\n * Import a previously-exported tree snapshot, restoring the full branch\n * topology and the active head. Replaces any existing repo content.\n *\n * Always calls `_reRenderActivePath()`:\n * - In native DOM mode: rebuilds bubble elements.\n * - In framework-managed mode: skips DOM manipulation but dispatches\n * `aparte-path-changed` with sibling metadata so the wrapper can update\n * branch arrows on already-rendered bubbles.\n */\n importTree(tree: ExportedMessageRepository): void {\n // Not `clearAll()`: an import re-populates from a snapshot that may hold the\n // very attachment objects currently in the repo — which is exactly what a\n // conversation load does. See the note in `clearAll`.\n this.clearAll({ revokeAttachments: false });\n this._repo.import(tree);\n this._reRenderActivePath();\n }\n\n /**\n * Clear all messages and remove all bubble elements from the DOM.\n * Also dispatches a aparte-reset-done event.\n *\n * In framework-managed mode the DOM is owned by the host framework\n * (Angular @for, React, etc.) and we must not clear `innerHTML` — doing\n * so desynchronises the framework's view tree from the live DOM and the\n * next change-detection pass throws `NotFoundError` on insertBefore.\n */\n clearAll(options?: { revokeAttachments?: boolean }): void {\n /*\n * Release the attachments' object URLs before dropping the messages: after\n * `_repo.clear()` there is no way left to reach them, and nothing else\n * revoked them — so every `File` a session had sent stayed reachable for\n * the life of the page.\n *\n * UNLESS the caller is about to put the same messages back. Two callers do:\n * `setMessages` and `importTree`, and `ConversationController._load` runs\n * BOTH in sequence over one conversation. `export()` stores live `node.current`\n * references, so `conv.messages` and `conv.tree` share the very same\n * attachment objects — meaning the second clear revoked the object URLs of\n * the conversation being opened. Every image and file chip was dead on load,\n * and re-opening revoked twice.\n *\n * A reset (`aparte-reset`, the public `clearAll()`) still revokes: there the\n * messages really are gone.\n */\n if (options?.revokeAttachments !== false) {\n for (const message of this._repo.getMessages()) {\n revokeAttachmentUrls(message.attachments);\n }\n }\n this._repo.clear();\n if (!this._frameworkManagedDOM) {\n const wrapper = this.querySelector('.aparte-messages-wrapper');\n if (wrapper) {\n // Remove bubbles individually so the spacer div is preserved.\n Array.from(wrapper.querySelectorAll('aparte-chat-bubble')).forEach(b => b.remove());\n }\n }\n // Reset spacer and scroll button regardless of mode\n this._setSpacerHeight(0);\n this._isAutoScrollEnabled = true;\n this._updateScrollButton();\n this.dispatchEvent(new CustomEvent('aparte-reset-done', { bubbles: true, composed: true }));\n }\n\n /**\n * Clear all messages\n * @deprecated Use clearAll() to also remove DOM bubbles\n */\n clearMessages(): void {\n this._repo.clear();\n }\n\n /**\n * Replace the entire message list in one shot. Used when switching\n * conversations: clears existing repo + DOM, then appends each message.\n *\n * In framework-managed mode the framework re-renders the bubble DOM\n * itself; we only update the internal repo (used by aparte-client to\n * build chat history).\n */\n setMessages(messages: AparteMessage[]): void {\n // Same reason as `importTree`: the incoming messages may BE the outgoing\n // ones, and a conversation the user can switch back to still holds them.\n this.clearAll({ revokeAttachments: false });\n for (const m of messages) {\n this.appendMessage(m);\n }\n }\n\n /**\n * Scroll to bottom of viewport\n */\n scrollToBottom(): void {\n this._scrollToBottom();\n }\n\n /**\n * Reset the bottom spacer to 0 height immediately and freeze it for\n * 350 ms so the host-app layout transition (e.g. flex: 0→1 animation)\n * does not trigger a premature recalculation with mid-animation geometry.\n * Call before a full messages swap.\n */\n resetSpacer(): void {\n this._setSpacerHeight(0);\n // Freeze spacer recalculation for the duration of any host layout\n // transition (configured via `layoutTransitionMs`). Without this,\n // ResizeObserver fires on every animation frame while the container\n // is still growing, producing incorrect spacer values.\n if (this._layoutTransitionMs > 0) {\n this._spacerFrozenUntil = Date.now() + this._layoutTransitionMs;\n }\n }\n\n /**\n * Enable or disable auto-scroll\n */\n setAutoScroll(enabled: boolean): void {\n this._isAutoScrollEnabled = enabled;\n }\n\n /**\n * Signal that a framework (e.g. Angular) manages the bubble DOM.\n * When true, branch navigation dispatches `aparte-path-changed` without\n * clearing/rebuilding the messages wrapper — the framework re-renders instead.\n */\n setFrameworkManagedDOM(managed: boolean): void {\n this._frameworkManagedDOM = managed;\n }\n\n // ─────────────────────────────────────────────────────────────────────────\n // Private Helpers\n // ─────────────────────────────────────────────────────────────────────────\n\n private _getOrCreateMessage(messageId: string): AparteMessage {\n const existing = this._repo.getMessageById(messageId);\n if (existing) return existing;\n\n const message: AparteMessage = {\n id: messageId,\n role: 'assistant',\n content: '',\n timestamp: Date.now(),\n isStreaming: true,\n status: 'streaming'\n };\n this._repo.addOrUpdateMessage(this._repo.headId, message);\n return message;\n }\n\n private _notifyBubble(messageId: string, action: string, payload?: unknown, segmentId?: string): void {\n // Find the bubble element — the native `<aparte-chat-bubble>` OR a custom\n // element opting into live streaming via `data-aparte-bubble` (so a raw-core\n // consumer can replace the bubble tag and still receive token/segment\n // pushes, not just a CSS restyle).\n const bubble = this.querySelector(\n `aparte-chat-bubble[message-id=\"${cssEscape(messageId)}\"], [data-aparte-bubble][message-id=\"${cssEscape(messageId)}\"]`,\n ) as HTMLElement & {\n appendToken?: (chunk: string) => void;\n appendToSegment?: (segmentId: string, chunk: string) => void;\n addSegment?: (segment: AparteSegment) => void;\n updateSegment?: (segmentId: string, updates: Partial<AparteSegment>) => void;\n removeSegment?: (segmentId: string) => void;\n setUsage?: (usage: AparteUsage) => void;\n updateMessage?: (updates: Partial<AparteMessage>) => void;\n };\n\n if (!bubble) return;\n\n switch (action) {\n case 'appendToken':\n bubble.appendToken?.(payload as string);\n break;\n case 'appendToSegment':\n bubble.appendToSegment?.(segmentId!, payload as string);\n break;\n case 'addSegment':\n bubble.addSegment?.(payload as AparteSegment);\n break;\n case 'updateSegment': {\n const { segmentId: sid, updates: segUpdates } = payload as { segmentId: string; updates: Partial<AparteSegment> };\n bubble.updateSegment?.(sid, segUpdates);\n break;\n }\n case 'removeSegment':\n bubble.removeSegment?.(payload as string);\n break;\n case 'setUsage':\n bubble.setUsage?.(payload as AparteUsage);\n break;\n case 'update': {\n // Atomic update: forward it when it carries anything the bubble\n // renders. `content` and `attachments` used to be filtered out\n // here, so an edit (which sends `{ content }`) updated the repo —\n // and therefore the history sent to the model — while the bubble\n // kept displaying the old text.\n const updates = payload as Record<string, unknown>;\n const renderable = ['status', 'segments', 'content', 'attachments', 'usage'];\n if (renderable.some((key) => key in updates)) {\n bubble.updateMessage?.(payload as Partial<AparteMessage>);\n }\n break;\n }\n case 'complete':\n bubble.updateMessage?.(payload as Partial<AparteMessage>);\n break;\n }\n }\n\n /**\n * Re-render the active path: clears the messages wrapper and rebuilds bubbles\n * for every message on the current active branch path (root → head).\n * Calls `setSiblings(count, index)` on each bubble that has siblings, and\n * dispatches `aparte-path-changed` so Angular wrapper can sync its signal.\n *\n * When `_frameworkManagedDOM` is true (set via setFrameworkManagedDOM), the DOM\n * manipulation is skipped — only `aparte-path-changed` is dispatched so the\n * framework can re-render from updated signal state.\n */\n private _reRenderActivePath(): void {\n const activeMessages = this._repo.getMessages();\n\n // Compute sibling metadata once and reuse — keeps the event payload\n // identical between framework-managed and default DOM modes.\n const siblingsInfo: AparteSiblingInfo[] = activeMessages.map(m => {\n const sibs = this._repo.getBranches(m.id);\n return { id: m.id, count: sibs.length, index: sibs.indexOf(m.id) };\n });\n\n if (this._frameworkManagedDOM) {\n this._dispatchPathChanged(activeMessages, siblingsInfo);\n return;\n }\n\n const wrapper = this.querySelector('.aparte-messages-wrapper');\n if (!wrapper) return;\n wrapper.innerHTML = '';\n\n // Only materialise the last N messages of the active path (DOM render cap).\n // The repository keeps the full path; this is a perf ceiling, not eviction.\n const startIdx = Math.max(0, activeMessages.length - this._maxRenderedBubbles);\n for (let i = startIdx; i < activeMessages.length; i++) {\n const message = activeMessages[i]!;\n const sibInfo = siblingsInfo[i];\n\n const bubble = document.createElement('aparte-chat-bubble');\n bubble.setAttribute('message-id', message.id);\n bubble.setAttribute('role', message.role);\n if (message.timestamp) bubble.setAttribute('timestamp', String(message.timestamp));\n if (isAwaitingReply(message)) {\n bubble.setAttribute('streaming', '');\n }\n wrapper.appendChild(bubble);\n\n // Reconcile content / segments / attachments / sibling-picker via\n // the shared helper — same code path the framework wrappers use,\n // so the contract stays in lockstep.\n populateBubbleFromMessage(bubble as unknown as SyncableBubble, message, sibInfo);\n }\n\n this._dispatchPathChanged(activeMessages, siblingsInfo);\n this._recalculateSpacer();\n\n // No post-swap re-measure of the auto-scroll INTENT here, deliberately: a\n // rebuild's height flickers, and a one-shot measurement that lands mid-flicker\n // can only get it wrong (it would disarm auto-follow for a reader who is\n // pinned to the bottom). The intent is decided once, in `navigateBranch`, from\n // the position the user was actually in; the button re-derives itself from\n // geometry on every scroll and on every post-mutation frame.\n }\n\n private _dispatchPathChanged(messages: AparteMessage[], siblings: AparteSiblingInfo[]): void {\n const detail: ApartePathChangedEventDetail = { messages, siblings };\n this.dispatchEvent(new CustomEvent<ApartePathChangedEventDetail>('aparte-path-changed', {\n bubbles: true,\n composed: true,\n detail,\n }));\n }\n\n private _autoScroll(): void {\n if (this._isAutoScrollEnabled) {\n if (this._smoothScrollOnce) {\n this._smoothScrollOnce = false;\n requestAnimationFrame(() => this._smoothScrollToBottom());\n } else {\n requestAnimationFrame(() => this._scrollToBottom());\n }\n }\n this._pruneRenderedBubbles();\n }\n\n /**\n * Request that the next auto-scroll triggered by a DOM mutation uses\n * smooth behaviour instead of instant. Call this just before adding a\n * user message bubble so the viewport animates down rather than jumping.\n * Resets automatically after the first auto-scroll fires.\n */\n requestSmoothScroll(): void {\n this._smoothScrollOnce = true;\n }\n\n private _render(): void {\n // Framework-managed: the framework owns the bubble children directly.\n // Do NOT build the internal container/wrapper or relocate children.\n if (this._frameworkManagedDOM) {\n this._setupFrameworkDOM();\n return;\n }\n // Light DOM rendering\n // Preserving existing children in render allows framework composition\n if (!this.querySelector('.aparte-viewport-container')) {\n const container = document.createElement('div');\n container.className = 'aparte-viewport-container';\n\n // Set direction based on current locale\n const locale = resolveConfig(this).getLocale();\n if (locale.direction) {\n container.setAttribute('dir', locale.direction);\n }\n\n container.setAttribute('role', 'log');\n container.setAttribute('aria-live', 'polite');\n container.setAttribute('aria-atomic', 'false');\n container.setAttribute('aria-relevant', 'additions');\n\n const wrapper = document.createElement('div');\n wrapper.className = 'aparte-messages-wrapper';\n\n // Move existing children (bubbles) into wrapper\n while (this.firstChild) {\n wrapper.appendChild(this.firstChild);\n }\n\n // Bottom spacer — always last in wrapper, height driven by _recalculateSpacer()\n this._bottomSpacer = document.createElement('div');\n this._bottomSpacer.className = 'aparte-bottom-spacer';\n this._bottomSpacer.setAttribute('aria-hidden', 'true');\n wrapper.appendChild(this._bottomSpacer);\n\n container.appendChild(wrapper);\n this.appendChild(container);\n\n this._container = container;\n\n // Scroll-to-bottom button — absolutely positioned over the viewport\n this._scrollBtn = document.createElement('button');\n this._scrollBtn.className = 'aparte-scroll-btn aparte-scroll-btn--hidden';\n this._scrollBtn.setAttribute('type', 'button');\n this._scrollBtn.setAttribute('aria-label', 'Scroll to bottom');\n const scrollIcon = resolveConfig(this).getIcon('scrollDown');\n this._scrollBtn.innerHTML = scrollIcon\n || `<svg width=\"16\" height=\"16\" viewBox=\"0 0 24 24\" fill=\"none\" stroke=\"currentColor\" stroke-width=\"2\" stroke-linecap=\"round\" stroke-linejoin=\"round\"><line x1=\"12\" y1=\"5\" x2=\"12\" y2=\"19\"/><polyline points=\"19 12 12 19 5 12\"/></svg>`;\n this.appendChild(this._scrollBtn);\n } else {\n this._container = this.querySelector('.aparte-viewport-container');\n this._scrollBtn = this.querySelector('.aparte-scroll-btn');\n this._bottomSpacer = this.querySelector('.aparte-bottom-spacer');\n }\n }\n\n /**\n * DOM setup for framework-managed mode. The framework (React/Vue/Svelte/\n * Angular) renders the bubble elements as DIRECT children of the host, so we\n * must NOT relocate them into an internal wrapper — that desyncs the\n * framework's virtual DOM from the real DOM and throws NotFoundError on the\n * next append. Instead the HOST itself is the scroll surface, the spacer is\n * additive `padding-bottom` (no element), and the scroll button is a\n * `position: sticky` TRAILING foreign child (kept last by the framework\n * MutationObserver). A present foreign node is still a valid `insertBefore`\n * reference for the framework — the crash came from a RELOCATED node, not a\n * foreign one.\n */\n private _setupFrameworkDOM(): void {\n this._container = this;\n this._bottomSpacer = null;\n if (this.classList.contains('aparte-viewport--framework')) {\n this._scrollBtn = this.querySelector(':scope > .aparte-scroll-btn') as HTMLButtonElement | null;\n return; // already set up (re-entrant _render)\n }\n this.classList.add('aparte-viewport--framework');\n\n const scrollBtn = document.createElement('button');\n scrollBtn.className = 'aparte-scroll-btn aparte-scroll-btn--hidden';\n scrollBtn.setAttribute('type', 'button');\n scrollBtn.setAttribute('aria-label', 'Scroll to bottom');\n const scrollIcon = resolveConfig(this).getIcon('scrollDown');\n scrollBtn.innerHTML = scrollIcon\n || `<svg width=\"16\" height=\"16\" viewBox=\"0 0 24 24\" fill=\"none\" stroke=\"currentColor\" stroke-width=\"2\" stroke-linecap=\"round\" stroke-linejoin=\"round\"><line x1=\"12\" y1=\"5\" x2=\"12\" y2=\"19\"/><polyline points=\"19 12 12 19 5 12\"/></svg>`;\n this.appendChild(scrollBtn);\n this._scrollBtn = scrollBtn;\n }\n\n /**\n * Keep the sticky scroll button as the last child in framework-managed mode.\n * The framework usually inserts bubbles before its own trailing nodes (so the\n * button stays last), but a plain `appendChild` at the very end (e.g. some\n * Angular @for paths) can land a bubble after it — move it back. Idempotent:\n * a no-op when already last, so it never loops the MutationObserver.\n */\n private _keepScrollButtonLast(): void {\n if (!this._scrollBtn) return;\n if (this.lastElementChild !== this._scrollBtn) {\n this.appendChild(this._scrollBtn);\n }\n }\n\n /** Current spacer height — a padding value (framework) or the element's height (core). */\n private _getSpacerHeight(): number {\n if (this._frameworkManagedDOM) return this._fwSpacerHeight;\n return this._bottomSpacer?.offsetHeight ?? 0;\n }\n\n /** Set the spacer — host padding (framework, additive to base padding) or element height (core). */\n private _setSpacerHeight(px: number): void {\n if (this._frameworkManagedDOM) {\n this._fwSpacerHeight = px;\n this.style.setProperty('--aparte-fw-spacer', `${px}px`);\n } else if (this._bottomSpacer) {\n this._bottomSpacer.style.height = `${px}px`;\n }\n }\n\n // Bound fields, not inline arrows: a custom element is re-connected every\n // time it is MOVED in the DOM (a portal, a dialog, a framework re-parenting),\n // so `_setupEventListeners` runs again each time. An inline arrow can never\n // be handed to `removeEventListener`, so it just accumulates — one branch\n // click then ran N handlers, N active-path re-renders and N storage writes\n // through the conversation controller. The window listeners next to these\n // were always removed properly; these two, attached to `this`, were not.\n private readonly _onScrollBtnClick = (): void => {\n this._isAutoScrollEnabled = true;\n this._smoothScrollToBottom();\n this._updateScrollButton();\n };\n\n private readonly _onBranchNavigate = (e: Event): void => {\n const evt = e as CustomEvent<{ messageId: string; direction: 'prev' | 'next' }>;\n evt.stopPropagation();\n this.navigateBranch(evt.detail.messageId, evt.detail.direction);\n };\n\n private _setupEventListeners(): void {\n this._container?.addEventListener('scroll', this._handleScroll, { passive: true });\n this._scrollBtn?.addEventListener('click', this._onScrollBtnClick);\n this.addEventListener('aparte-branch-navigate', this._onBranchNavigate);\n }\n\n private _setupObservers(): void {\n this._resizeObserver = new ResizeObserver(() => {\n if (this._isAutoScrollEnabled) {\n this._scrollToBottom();\n }\n this._recalculateSpacer();\n });\n\n const wrapper = this.querySelector('.aparte-messages-wrapper');\n\n if (this._container) {\n // Fires on window/viewport resize and when the composer grows.\n // NOTE: we intentionally do NOT observe .aparte-messages-wrapper here.\n // The wrapper contains the spacer div — observing it would create a\n // feedback loop: spacer changes → wrapper resizes → ResizeObserver →\n // _recalculateSpacer → spacer changes → … → height grows unbounded.\n // Streaming content growth is handled by direct _scheduleSpacerUpdate()\n // calls from appendToken(). New bubbles are handled by MutationObserver.\n // Framework-managed: _container IS the host, whose `padding-bottom`\n // carries the spacer — observe the BORDER box (fixed host size) so a\n // spacer/padding change does NOT re-trigger _recalculateSpacer and\n // loop. Core mode observes the container (no dynamic padding).\n if (this._frameworkManagedDOM) {\n this._resizeObserver.observe(this._container, { box: 'border-box' });\n } else {\n this._resizeObserver.observe(this._container);\n }\n }\n\n this._mutationObserver = new MutationObserver(() => {\n // Keep the sticky scroll button trailing after framework appends.\n if (this._frameworkManagedDOM) this._keepScrollButtonLast();\n // The gate is tested HERE, when the frame is queued, and moving it\n // inside the callback is not the improvement it looks like.\n //\n // Queue-time looks like a race — the user could scroll up before the\n // frame runs and be dragged back. Testing it at run-time instead was\n // tried and reverted: a branch swap replaces bubbles, the resulting\n // scroll event makes `_isAtBottom()` briefly false, and the deferred\n // check then refuses to re-anchor, leaving a scroll-to-bottom button on\n // a transcript that IS at the bottom (caught by\n // `bubble-actions.spec.ts` on WebKit, 3 runs out of 3).\n //\n // So queue-time is deliberate: it captures the user's intent BEFORE the\n // DOM churn can confuse the \"am I at the bottom?\" heuristic. Reading it\n // correctly in both cases needs a way to tell our own programmatic\n // scroll from a real gesture — see the note in `_handleScroll`.\n if (this._isAutoScrollEnabled) {\n requestAnimationFrame(() => this._scrollToBottom());\n }\n // Recalculate spacer when DOM mutates (new bubble added, Angular re-render).\n this._scheduleSpacerUpdate();\n });\n\n // Framework-managed: bubbles are direct children of the host (no wrapper).\n const observeTarget = this._frameworkManagedDOM ? this : wrapper;\n if (observeTarget) {\n this._mutationObserver.observe(observeTarget, {\n childList: true,\n subtree: true\n });\n }\n }\n\n /** Is the scroll surface within `_scrollThreshold` of its bottom, right now? */\n private _isAtBottom(): boolean {\n if (!this._container) return true;\n const { scrollTop, scrollHeight, clientHeight } = this._container;\n return scrollHeight - scrollTop - clientHeight <= this._scrollThreshold;\n }\n\n private _handleScroll(): void {\n if (!this._container) return;\n // A scroll IS the user's intent: reaching the bottom re-arms auto-follow,\n // leaving it disarms it.\n //\n // `_isAtBottom()` is deliberately generous (`_scrollThreshold`, 50px): a few\n // pixels of drift must NOT read as \"the reader walked away\". That generosity\n // is right here and wrong as a definition of \"anchored\" — which is why\n // `_settleAtBottom()` closes a residual gap instead of this method being\n // tightened. Tightening it would disarm auto-follow on every stray pixel.\n //\n // This handler also cannot tell our own programmatic scroll from a real\n // gesture. Marking them with a counter was tried and reverted: engines\n // coalesce scroll events, so the counter over-counted and started swallowing\n // the USER's scrolls — the browser suite caught it stealing the scroll back.\n // Anything attempted here must identify the scroll by POSITION, not by\n // counting events.\n this._isAutoScrollEnabled = this._isAtBottom();\n this._updateScrollButton();\n }\n\n private _scrollToBottom(): void {\n if (!this._container) return;\n this._container.scrollTop = this._container.scrollHeight;\n this._settleAtBottom(4);\n }\n\n /**\n * Confirm over the next few frames that we actually reached the bottom.\n *\n * One assignment is not enough, and the reason is measured rather than guessed.\n * A timeline of a streamed turn on Safari (framework mode) recorded the content\n * settling in TWO layout passes — 1118 → 1121 → 1152 px. `scrollTop =\n * scrollHeight` ran against the middle one, clamped to that layout's max (603),\n * and nothing ran afterwards: the last 31px never closed. Auto-follow stayed\n * armed the whole time, so the component was not disarmed — it was SATISFIED.\n * `_isAtBottom()` answers \"yes\" for any gap under `_scrollThreshold` (50), which\n * is the right rule for keeping auto-follow armed and the wrong one as a\n * definition of \"anchored\".\n *\n * Ruled out on the way here, so nobody pays for it twice: not a WebKit\n * padding-accounting difference (a probe writing `scrollTop = 1e7` reached\n * exactly `scrollHeight - clientHeight`), not a missing `characterData`\n * mutation, and not a child resize a ResizeObserver could see.\n *\n * A BOUNDED retry, not one corrective frame: a single frame lands on the same\n * stale layout and was measured leaving a wider gap than doing nothing. Bounded\n * so it always terminates; re-reads `_isAutoScrollEnabled` every frame so a\n * reader who scrolls away mid-settle is left alone; stops as soon as the gap is\n * closed, so the common case costs one frame that does nothing.\n */\n private _settleAtBottom(framesLeft: number): void {\n if (framesLeft <= 0) return;\n requestAnimationFrame(() => {\n if (!this._container || !this._isAutoScrollEnabled) return;\n const max = this._container.scrollHeight - this._container.clientHeight;\n if (max - this._container.scrollTop <= 1) return;\n this._container.scrollTop = max;\n this._settleAtBottom(framesLeft - 1);\n });\n }\n\n private _smoothScrollToBottom(): void {\n if (!this._container) return;\n // scrollTo with behavior:'smooth' is not available in all environments (e.g. jsdom).\n // Fall back to instant scroll so tests and SSR environments stay safe.\n // Reduced-motion users get the instant path too — the CSS\n // prefers-reduced-motion block cannot reach a JS-driven smooth scroll.\n if (typeof this._container.scrollTo === 'function' && !this._prefersReducedMotion()) {\n this._container.scrollTo({ top: this._container.scrollHeight, behavior: 'smooth' });\n } else {\n this._container.scrollTop = this._container.scrollHeight;\n }\n }\n\n private _prefersReducedMotion(): boolean {\n return typeof matchMedia === 'function'\n && matchMedia('(prefers-reduced-motion: reduce)').matches;\n }\n\n /**\n * Show/hide the scroll-to-bottom button from the **current geometry**, not from\n * `_isAutoScrollEnabled`.\n *\n * The two answer different questions: the flag is intent (\"should new content\n * pull the view down\"), the button is a fact (\"is there anything below the\n * fold\"). Mirroring the flag made the button lie whenever the two diverged —\n * `navigateBranch` deliberately disarms auto-follow, so swapping a branch while\n * already at the bottom of a scrollable transcript left the button offering to\n * scroll nowhere (reported from bonaparte, React). Re-derived on scroll, on the\n * post-mutation frame and after a path swap, so it converges to the truth\n * whatever a framework's render timing does in between.\n */\n private _updateScrollButton(): void {\n this._scrollBtn?.classList.toggle('aparte-scroll-btn--hidden', this._isAtBottom());\n }\n\n /**\n * Recalculate the bottom spacer height so the last user message is always\n * pinned to the top of the scroll area when a response is being generated.\n *\n * spacer = max(0, viewportHeight - lastUserBubble.offsetHeight - lastAssistantBubble.offsetHeight)\n *\n * The spacer shrinks progressively as the assistant streams content, eventually\n * reaching 0 when the combined height fills the viewport.\n */\n private _recalculateSpacer(): void {\n // Core mode needs the spacer element; framework mode uses host padding\n // (no element) — both need the scroll container.\n if (!this._container) return;\n if (!this._frameworkManagedDOM && !this._bottomSpacer) return;\n // Skip while the host layout is still animating (e.g. the flex transition\n // that moves the composer from the center of the screen to the bottom).\n // Without this guard, every ResizeObserver tick during the transition\n // reads a partially-grown clientHeight and writes an incorrect spacer\n // height that may reach the clientHeight cap and lock the spacer there.\n if (Date.now() < this._spacerFrozenUntil) return;\n\n const allBubbles = Array.from(\n this.querySelectorAll('aparte-chat-bubble')\n ) as HTMLElement[];\n\n if (allBubbles.length === 0) {\n this._setSpacerHeight(0);\n return;\n }\n\n const lastUserBubble = [...allBubbles]\n .reverse()\n .find(b => b.getAttribute('role') === 'user');\n\n if (!lastUserBubble) {\n this._setSpacerHeight(0);\n return;\n }\n\n // Read the current spacer height (may be non-zero during a CSS transition\n // or a previous non-zero value). Subtract it from scrollHeight to get the\n // true content height WITHOUT the spacer — no need to zero-then-reflow,\n // which would both fight the CSS transition and force an extra synchronous\n // layout that could read a stale animated value.\n const currentSpacerH = this._getSpacerHeight();\n\n // Use getBoundingClientRect so gaps, padding, and all children are\n // automatically accounted for — no need to manually sum heights.\n const containerRect = this._container.getBoundingClientRect();\n const userRect = lastUserBubble.getBoundingClientRect();\n\n // Absolute Y position of the user bubble's top within the full scrollable content\n const userTopInContent = userRect.top - containerRect.top + this._container.scrollTop;\n\n // Height of content from user bubble top to end, excluding the spacer\n const scrollHeightWithoutSpacer = this._container.scrollHeight - currentSpacerH;\n\n // If all content already fits in the viewport, no spacer is needed.\n if (scrollHeightWithoutSpacer <= this._container.clientHeight) {\n this._setSpacerHeight(0);\n return;\n }\n\n const contentBelowUserTop = scrollHeightWithoutSpacer - userTopInContent;\n\n const needed = this._container.clientHeight - contentBelowUserTop;\n // Hard cap: the spacer can never exceed the visible viewport height.\n // This acts as a safety net against stale layout reads (e.g. mid-swap)\n // that could produce an astronomical value and push content off-screen.\n const maxSpacer = this._container.clientHeight;\n this._setSpacerHeight(Math.min(Math.max(0, needed), maxSpacer));\n\n // Re-scroll after the spacer height changes so scrollTop is always\n // consistent with the new scrollHeight. Without this, the MutationObserver\n // schedules _scrollToBottom() one RAF *before* _recalculateSpacer() runs,\n // leaving scrollTop based on the pre-spacer scrollHeight. On the next\n // recalculation (e.g. from syncMessagesWithBubbles or a resize) the formula\n // reads a stale scrollTop and may grow the spacer to the clientHeight cap.\n if (this._isAutoScrollEnabled) {\n this._scrollToBottom();\n }\n }\n\n /**\n * Schedule a spacer recalculation on the next animation frame.\n * Batches multiple rapid calls (e.g. during token streaming) into one.\n *\n * Single-RAF intentional: both the scroll-to-bottom queued by MutationObserver\n * and this spacer recalculation must land in the *same* frame so the browser\n * paints exactly once — with the correct scroll position *and* the correct\n * spacer height. A double-RAF would put the spacer shrink one frame after the\n * scroll, causing a 1-frame layout jump during streaming.\n */\n private _scheduleSpacerUpdate(): void {\n if (this._spacerRafId !== null) return;\n this._spacerRafId = requestAnimationFrame(() => {\n this._spacerRafId = null;\n this._recalculateSpacer();\n // The DOM just changed (new bubble, streamed token, framework re-render):\n // whether anything sits below the fold changed with it.\n this._updateScrollButton();\n });\n }\n\n /**\n * Cap the number of rendered bubbles in the DOM (perf ceiling only).\n *\n * Drops the oldest `<aparte-chat-bubble>` elements beyond `_maxRenderedBubbles`\n * from the DOM. It **never** touches the AparteMessageRepository — the conversation\n * model and its persistence snapshot stay complete (retention/eviction is a\n * consumer/persistence concern, not the viewport's). No-op when a framework\n * owns the DOM.\n */\n private _pruneRenderedBubbles(): void {\n if (this._frameworkManagedDOM) return;\n const wrapper = this.querySelector('.aparte-messages-wrapper');\n if (!wrapper) return;\n const bubbles = wrapper.querySelectorAll('aparte-chat-bubble');\n const excess = bubbles.length - this._maxRenderedBubbles;\n for (let i = 0; i < excess; i++) {\n bubbles[i]?.remove();\n }\n }\n\n private _warnMaxMessagesDeprecated(): void {\n if (this._warnedMaxMessagesDeprecation) return;\n this._warnedMaxMessagesDeprecation = true;\n console.warn(\n '[Aparte] `maxMessages` / `max-messages` on aparte-chat-viewport is deprecated: ' +\n 'it used to silently evict messages from the conversation model. It now only ' +\n 'caps rendered bubbles in the DOM — use `maxRenderedBubbles` / `max-rendered-bubbles`. ' +\n 'For actual history retention, configure it on your AparteConversationManager instead.',\n );\n }\n\n private _cleanup(): void {\n this._container?.removeEventListener('scroll', this._handleScroll);\n this._scrollBtn?.removeEventListener('click', this._onScrollBtnClick);\n this.removeEventListener('aparte-branch-navigate', this._onBranchNavigate);\n this._resizeObserver?.disconnect();\n this._mutationObserver?.disconnect();\n this._resizeObserver = null;\n this._mutationObserver = null;\n if (this._spacerRafId !== null) {\n cancelAnimationFrame(this._spacerRafId);\n this._spacerRafId = null;\n }\n }\n}\n\n// Register the custom element\nif (!customElements.get('aparte-chat-viewport')) {\n customElements.define('aparte-chat-viewport', AparteChatViewport);\n}\n","import type { AparteSendEventDetail } from '../../types/index.js';\nimport { type AparteConfig } from '../../config/aparte-config.js';\nimport { resolveConfig } from '../../config/config-context.js';\n\n// ─────────────────────────────────────────────────────────────────────────────\n// Event map for internal pub/sub between primitives\n// ─────────────────────────────────────────────────────────────────────────────\nexport interface AparteComposerEventMap {\n 'value-change': { value: string };\n 'streaming-change': { streaming: boolean };\n 'disabled-change': { disabled: boolean };\n 'attachments-change': { attachments: File[] };\n 'submit': { value: string; attachments: File[] };\n 'cancel': Record<string, never>;\n 'panel-change': { active: boolean; submitEnabled: boolean; mode: 'advance' | 'submit' };\n}\n\nexport type AparteComposerEventType = keyof AparteComposerEventMap;\n\n/**\n * Public snapshot of the composer's observable state. Delivered on every\n * `aparte-composer-change` DOM event and available synchronously via\n * {@link AparteComposer.getState}. Lets an element OUTSIDE the composer package\n * (a custom send button, a footer control) mirror the composer's live state\n * without the internal `_on`/`_emit` bus.\n */\nexport interface AparteComposerState {\n value: string;\n streaming: boolean;\n disabled: boolean;\n attachments: File[];\n /** A panel (e.g. an elicitation form) is showing in place of the input. */\n panelActive: boolean;\n /** Whether the send button should act as \"submit\" while a panel is active. */\n submitEnabled: boolean;\n}\n\n/** Detail of the public `aparte-composer-change` DOM event. */\nexport interface AparteComposerChangeEventDetail {\n state: AparteComposerState;\n composer: AparteComposer;\n}\n\n// ─────────────────────────────────────────────────────────────────────────────\n// AparteComposer — root context provider\n// ─────────────────────────────────────────────────────────────────────────────\n\n/**\n * @element aparte-composer\n *\n * Root context for all `aparte-composer-*` primitives.\n * Does NOT impose any visual layout — the consumer controls structure.\n *\n * @attr placeholder - Forwarded to aparte-composer-input via event\n * @attr disabled - Disables the whole composer\n * @attr target - ID of the <aparte-chat> target element\n *\n * @fires aparte-send - Fired when a message is submitted\n */\nexport class AparteComposer extends HTMLElement {\n private _value = '';\n private _streaming = false;\n private _attachments: File[] = [];\n private _listeners = new Map<string, Set<(payload: unknown) => void>>();\n private _panelActive = false;\n /** What the send button means while a panel is up — see `showPanel`. */\n private _panelMode: 'advance' | 'submit' = 'submit';\n private _panelSubmitEnabled = false;\n private _panelOnSubmit: (() => void) | null = null;\n\n // Internal bus events that represent an observable STATE change — these are\n // mirrored to the public `aparte-composer-change` DOM event. `submit`/`cancel`\n // are actions, not state, and are covered by `aparte-send`/`aparte-cancel`.\n private static readonly _STATE_EVENTS: ReadonlySet<AparteComposerEventType> = new Set([\n 'value-change', 'streaming-change', 'disabled-change', 'attachments-change', 'panel-change',\n ]);\n\n // Window event bindings\n private _onMessageStart = this._handleMessageStart.bind(this);\n private _onMessageDone = this._handleMessageDone.bind(this);\n\n /** Config governing THIS composer (nearest instance boundary, else global). */\n /**\n * Resolved LIVE, not cached at connect.\n *\n * A wrapper runs `AparteChatHost.bind()` — which calls `attachConfig` — from its\n * POST-mount hook, so this element connects BEFORE the boundary exists. Caching\n * here latched the global config forever: an instance `config` carrying an RTL\n * locale flipped the transcript and not the composer, and the\n * `requireModelSelection` gate was read off the wrong object. `aparte-chat-bubble`\n * has always resolved live, and its JSDoc names this exact race.\n */\n private get _cfg(): AparteConfig {\n return resolveConfig(this);\n }\n /** Only OUR config: a change on another chat's instance must not touch us. */\n private _onConfigChangeEvent = (e: Event): void => {\n const detail = (e as CustomEvent).detail as { config?: unknown } | undefined;\n if (detail?.config && detail.config !== this._cfg) return;\n this._onConfigChange();\n };\n /** True while `requireModelSelection` is on AND no model is selected — blocks send. */\n private _modelGated = false;\n private _onConfigChange = (): void => { this._evaluateModelGate(); this._applyDirection(); };\n\n /**\n * Mirror `locale.direction` onto ourselves, so everything inside — input, buttons,\n * the toolbar row and whatever the consumer put in it — inherits it.\n *\n * The direction used to stop at the transcript: only the viewport applied `dir`, so\n * an RTL locale flipped the conversation and left the composer left-to-right. It is\n * also what makes the toolbar's placement idiom real: `margin-inline-start: auto` in\n * a subtree that inherits no direction is just `margin-left`.\n *\n * One attribute on the host rather than a stamp per child: inheritance is the\n * mechanism, so nothing needs to know about the consumer's markup.\n */\n private _applyDirection(): void {\n const direction = (this._cfg ?? resolveConfig(this)).getLocale().direction;\n if (direction) this.setAttribute('dir', direction);\n else this.removeAttribute('dir');\n }\n\n static get observedAttributes(): string[] {\n return ['placeholder', 'disabled', 'target'];\n }\n\n connectedCallback(): void {\n window.addEventListener('aparte-message-start', this._onMessageStart);\n window.addEventListener('aparte-message-done', this._onMessageDone);\n window.addEventListener('aparte-message-error', this._onMessageDone);\n window.addEventListener('aparte-message-aborted', this._onMessageDone);\n // Model-selection gate (opt-in via aparteGlobalConfig.setRequireModelSelection).\n // A window listener rather than `_cfg.subscribe(...)`: subscribing binds to\n // whichever config was resolvable AT CONNECT, which is the bug above wearing\n // a different hat. `_notify()` dispatches `aparte-config-change` with\n // `detail.config`, so the same information arrives without the early binding\n // — and the filter below compares against the LIVE config.\n window.addEventListener('aparte-config-change', this._onConfigChangeEvent);\n this._evaluateModelGate();\n this._applyDirection();\n }\n\n disconnectedCallback(): void {\n window.removeEventListener('aparte-message-start', this._onMessageStart);\n window.removeEventListener('aparte-message-done', this._onMessageDone);\n window.removeEventListener('aparte-message-error', this._onMessageDone);\n window.removeEventListener('aparte-message-aborted', this._onMessageDone);\n window.removeEventListener('aparte-config-change', this._onConfigChangeEvent);\n this._listeners.clear();\n }\n\n attributeChangedCallback(name: string, _old: string | null, value: string | null): void {\n if (name === 'disabled') {\n this._emit('disabled-change', { disabled: value !== null });\n }\n if (name === 'placeholder') {\n // Primitives read this directly via closest() — no event needed\n }\n }\n\n // ── Public API ─────────────────────────────────────────────────────────\n\n get value(): string { return this._value; }\n get streaming(): boolean { return this._streaming; }\n get disabled(): boolean { return this.hasAttribute('disabled'); }\n /**\n * When false, Shift+Enter submits and a bare Enter inserts a newline —\n * the inverse of the default. Driven by the `submit-on-enter` attribute.\n */\n get submitOnEnter(): boolean { return this.getAttribute('submit-on-enter') !== 'false'; }\n get attachments(): File[] { return this._attachments; }\n get placeholder(): string { return this.getAttribute('placeholder') ?? ''; }\n get targetId(): string | null { return this.getAttribute('target'); }\n\n /**\n * Snapshot of the composer's observable state. Pair with the\n * `aparte-composer-change` DOM event to drive a custom send button or footer\n * control that lives outside the composer package:\n *\n * @example\n * // A custom send button. Keep it CLICKABLE while streaming — submit()\n * // routes to cancel() when a response is in flight, so one button is\n * // Send/Stop. Disabling it on `streaming` would make \"stop\" unreachable.\n * composer.addEventListener('aparte-composer-change', (e) => {\n * const { streaming, disabled, value, attachments } = e.detail.state;\n * myButton.textContent = streaming ? 'Stop' : 'Send';\n * myButton.disabled = disabled || (!streaming && !value.trim() && attachments.length === 0);\n * });\n * myButton.addEventListener('click', () => composer.submit()); // send or stop\n */\n getState(): AparteComposerState {\n return {\n value: this._value,\n streaming: this._streaming,\n disabled: this.disabled,\n attachments: [...this._attachments],\n panelActive: this._panelActive,\n submitEnabled: this._panelSubmitEnabled,\n };\n }\n\n setValue(value: string): void {\n this._value = value;\n this._emit('value-change', { value });\n }\n\n addAttachments(files: FileList | File[]): void {\n this._attachments = [...this._attachments, ...Array.from(files)];\n this._emit('attachments-change', { attachments: this._attachments });\n }\n\n removeAttachment(file: File): void {\n this._attachments = this._attachments.filter(f => f !== file);\n this._emit('attachments-change', { attachments: this._attachments });\n }\n\n clearAttachments(): void {\n this._attachments = [];\n this._emit('attachments-change', { attachments: [] });\n }\n\n /**\n * Inject a panel into the composer. The send button calls `onSubmit` when clicked.\n *\n * While a panel is up, the composer is answering a QUESTION, not composing a\n * message — so the affordances that lead nowhere go away with the text input:\n * the attachment picker above all, which stayed clickable while the user was\n * being asked something (\"on voyait encore l'icône de upload\", reported from a\n * real session). Ratified decision #8: an affordance nothing can honour is not\n * rendered.\n *\n * What STAYS, deliberately: the attachments strip, because pending attachments\n * are the user's state and not an action to offer — hiding them would look like\n * losing them; and the toolbar, because switching model still does something.\n *\n * Declared with an attribute + CSS rather than the inline `style.display` this\n * used to set on a child: an attribute is themeable, is visible to a consumer's\n * own rules, and does not clobber a `display` the consumer had set (the restore\n * wrote `''`, not the previous value).\n */\n showPanel(panel: HTMLElement, options?: { submitEnabled?: boolean; onSubmit?: () => void; mode?: 'advance' | 'submit' }): void {\n this.hidePanel();\n const inputEl = this.querySelector('aparte-composer-input') as HTMLElement | null;\n this.setAttribute('data-panel-active', '');\n panel.dataset['apartePanel'] = 'true';\n if (inputEl) {\n inputEl.insertAdjacentElement('afterend', panel);\n } else {\n this.appendChild(panel);\n }\n this._panelActive = true;\n this._panelSubmitEnabled = options?.submitEnabled ?? false;\n this._panelMode = options?.mode ?? 'submit';\n this._panelOnSubmit = options?.onSubmit ?? null;\n this._emit('panel-change', { active: true, submitEnabled: this._panelSubmitEnabled, mode: this._panelMode });\n }\n\n /** Remove the panel and restore the composer's own controls. */\n hidePanel(): void {\n const existing = this.querySelector('[data-aparte-panel]') as HTMLElement | null;\n if (existing) existing.remove();\n this.removeAttribute('data-panel-active');\n this._panelActive = false;\n this._panelSubmitEnabled = false;\n this._panelMode = 'submit';\n this._panelOnSubmit = null;\n this._emit('panel-change', { active: false, submitEnabled: false, mode: 'submit' });\n this.focus();\n }\n\n /**\n * Update the send button's state while a panel is active.\n *\n * `mode` moves with it because both change on the same event — answering the\n * question you are on can enable the button AND turn it from \"advance\" into\n * \"submit\" (when it was the last one), and two separate calls would flash a\n * wrong icon between them.\n */\n setPanelSubmitEnabled(enabled: boolean, mode?: 'advance' | 'submit'): void {\n if (!this._panelActive) return;\n this._panelSubmitEnabled = enabled;\n if (mode) this._panelMode = mode;\n this._emit('panel-change', { active: true, submitEnabled: enabled, mode: this._panelMode });\n }\n\n get panelActive(): boolean { return this._panelActive; }\n\n /**\n * Recompute the model gate from the resolved config. When\n * `requireModelSelection` is on and no model is selected, block sending and\n * reflect `data-model-gated` so the shipped CSS greys the composer. Re-runs on\n * every config change (e.g. the model selector's auto-select firing).\n */\n private _evaluateModelGate(): void {\n const gated = this._cfg.getRequireModelSelection() && !this._cfg.hasSelectedModel();\n if (gated === this._modelGated) return;\n this._modelGated = gated;\n this.toggleAttribute('data-model-gated', gated);\n }\n\n /** Submit the current value. Called by aparte-composer-send or programmatically. */\n submit(): void {\n if (this._panelActive) {\n if (this._panelSubmitEnabled) this._panelOnSubmit?.();\n return;\n }\n if (this._streaming) {\n this.cancel();\n return;\n }\n const value = this._value.trim();\n if (!value && this._attachments.length === 0) return;\n if (this.disabled) return;\n if (this._modelGated) return; // no model selected yet (require-model gate)\n\n this._emit('submit', { value, attachments: this._attachments });\n\n const detail: AparteSendEventDetail = {\n content: value,\n timestamp: Date.now(),\n targetId: this.targetId ?? undefined,\n files: this._attachments.length > 0 ? [...this._attachments] : undefined,\n };\n\n this.dispatchEvent(new CustomEvent<AparteSendEventDetail>('aparte-send', {\n bubbles: true,\n composed: true,\n detail,\n }));\n\n // Clear after send\n this.setValue('');\n this.clearAttachments();\n }\n\n /** Cancel the current streaming response. */\n cancel(): void {\n this._emit('cancel', {});\n // Public, element-scoped signal — symmetric with `aparte-send` on submit,\n // for consumers that want to observe cancel on the composer itself.\n this.dispatchEvent(new CustomEvent('aparte-cancel', { bubbles: true, composed: true }));\n // aparte-abort → tells AparteClient to actually stop the stream\n // aparte-message-aborted → resets the composer's own streaming state\n // Scope the abort to this composer's host so cancelling one chat doesn't\n // abort every scoped client / reset every composer on the page.\n const abortDetail = { targetId: this.targetId ?? undefined };\n window.dispatchEvent(new CustomEvent('aparte-abort', { bubbles: false, detail: abortDetail }));\n window.dispatchEvent(new CustomEvent('aparte-message-aborted', { bubbles: false, detail: abortDetail }));\n }\n\n /**\n * Reset the composer to its initial state.\n * Clears value, attachments, and hides any active panel.\n * Call this when switching conversations.\n */\n reset(): void {\n this.setValue('');\n this.clearAttachments();\n if (this._panelActive) this.hidePanel();\n }\n\n /** Focus the input primitive inside this composer. */\n override focus(): void {\n const input = this.querySelector('aparte-composer-input') as HTMLElement | null;\n input?.focus();\n }\n\n // ── Internal pub/sub ────────────────────────────────────────────────────\n\n _emit<K extends AparteComposerEventType>(event: K, payload: AparteComposerEventMap[K]): void {\n this._listeners.get(event)?.forEach(cb => cb(payload));\n // Mirror state changes to a public DOM event so elements outside the\n // composer package can observe them without the private bus.\n if (AparteComposer._STATE_EVENTS.has(event)) {\n this.dispatchEvent(new CustomEvent<AparteComposerChangeEventDetail>('aparte-composer-change', {\n bubbles: true,\n composed: true,\n detail: { state: this.getState(), composer: this },\n }));\n }\n }\n\n _on<K extends AparteComposerEventType>(event: K, cb: (payload: AparteComposerEventMap[K]) => void): () => void {\n if (!this._listeners.has(event)) this._listeners.set(event, new Set());\n this._listeners.get(event)!.add(cb as unknown as (payload: unknown) => void);\n return () => this._listeners.get(event)?.delete(cb as unknown as (payload: unknown) => void);\n }\n\n // ── Window events ───────────────────────────────────────────────────────\n\n /** A window lifecycle event is for THIS composer when neither side is scoped\n * (single-instance broadcast) or the target ids match (multi-chat page).\n * Without this filter, streaming in one chat flips every composer's state. */\n private _isForThisComposer(e: Event): boolean {\n const evtTargetId = (e as CustomEvent).detail?.targetId as string | undefined;\n return !evtTargetId || !this._ownTargetId() || evtTargetId === this._ownTargetId();\n }\n\n /**\n * Which chat this composer belongs to: its `target` attribute, or the id of the\n * chat host above it.\n *\n * All four wrappers set `target` themselves, so the attribute alone identified a\n * composer there. In RAW core — the documented quick start, where the markup is\n * hand-written — nothing sets it, so `!this.targetId` was true and this composer\n * accepted every chat's lifecycle events: on a two-chat page, one chat's Stop\n * tore down the other's open elicitation panel while its tool call kept waiting,\n * i.e. the question vanished and the turn hung.\n *\n * Found by a two-chat test written for the elicitation presenter, which is the\n * only reason it surfaced: raw core with two chats is a shape nothing exercised.\n * The hosts matched are the ones `aparte-chat-bubble._resolveTargetId()` matches,\n * for the reason written there — Angular's wrapper root IS `<aparte-chat>`, the\n * other three render a `[data-aparte-chat]` div.\n */\n private _ownTargetId(): string | undefined {\n const attr = this.targetId;\n if (attr) return attr;\n let el: HTMLElement | null = this.parentElement;\n while (el) {\n const tag = el.tagName?.toLowerCase();\n const isHost = tag === 'aparte-chat' || tag === 'aparte-chat-component' || el.hasAttribute?.('data-aparte-chat');\n if (isHost && el.id) return el.id;\n el = el.parentElement;\n }\n return undefined;\n }\n\n private _handleMessageStart(e: Event): void {\n if (!this._isForThisComposer(e)) return;\n this._streaming = true;\n this._emit('streaming-change', { streaming: true });\n }\n\n private _handleMessageDone(e: Event): void {\n if (!this._isForThisComposer(e)) return;\n this._streaming = false;\n this._emit('streaming-change', { streaming: false });\n // Always hide any active panel when a message lifecycle ends\n if (this._panelActive) this.hidePanel();\n }\n}\n\nif (!customElements.get('aparte-composer')) {\n customElements.define('aparte-composer', AparteComposer);\n}\n","import { resolveConfig } from '../../config/index.js';\nimport type { AparteComposer } from './aparte-composer.js';\nimport { escapeAttr } from '../../utils/escape.js';\n\n/**\n * @element aparte-composer-input\n *\n * Contenteditable text input primitive.\n * Must be a descendant of <aparte-composer>.\n *\n * Behaviour: Enter submits (calls root.submit()), Shift+Enter inserts newline.\n * Auto-expands up to max-height. Paste strips HTML, handles image paste.\n *\n * @attr placeholder - Placeholder text (fallback: reads from aparte-composer)\n * @attr max-height - Max height in px before scroll (default: 200)\n * @attr min-height - Min height in px. When omitted, the stylesheet's\n * min-height governs (44px in aparte.css) — so themes can\n * resize the editor in pure CSS without being fought by\n * an inline height.\n *\n * @example\n * <aparte-composer>\n * <div class=\"aparte-composer-shell\">\n * <div class=\"aparte-composer-row\">\n * <aparte-composer-input placeholder=\"Ask anything…\" max-height=\"320\" style=\"flex: 1\"></aparte-composer-input>\n * <aparte-composer-send></aparte-composer-send>\n * </div>\n * </div>\n * </aparte-composer>\n */\nexport class AparteComposerInput extends HTMLElement {\n private _editor: HTMLDivElement | null = null;\n private _maxHeight = 200;\n private _minHeight = 44;\n private _unsubscribes: (() => void)[] = [];\n\n // Bound handlers\n private _onInput = this._handleInput.bind(this);\n private _onKeydown = this._handleKeydown.bind(this);\n private _onFocus = this._handleFocus.bind(this);\n private _onBlur = this._handleBlur.bind(this);\n private _onPaste = this._handlePaste.bind(this);\n\n static get observedAttributes(): string[] {\n return ['placeholder', 'max-height', 'min-height', 'disabled'];\n }\n\n connectedCallback(): void {\n this._render();\n this._connectToRoot();\n this._scheduleInitialReflow();\n }\n\n disconnectedCallback(): void {\n this._editor?.removeEventListener('input', this._onInput);\n this._editor?.removeEventListener('keydown', this._onKeydown);\n this._editor?.removeEventListener('focus', this._onFocus);\n this._editor?.removeEventListener('blur', this._onBlur);\n this._editor?.removeEventListener('paste', this._onPaste);\n this._unsubscribes.forEach(fn => fn());\n this._unsubscribes = [];\n }\n\n attributeChangedCallback(name: string, _old: string | null, value: string | null): void {\n if (name === 'placeholder') this._updatePlaceholder();\n if (name === 'max-height') this._maxHeight = parseInt(value || '200', 10);\n if (name === 'min-height') this._minHeight = parseInt(value || '44', 10);\n if (name === 'disabled') this._updateDisabled(value !== null);\n }\n\n // ── Public API ──────────────────────────────────────────────────────────\n\n getValue(): string {\n // `textContent` drops `<br>`, so multi-line content would collapse onto one\n // line. Serialize the editor ourselves: text nodes as-is, `<br>` → newline.\n // We keep the editor flat (text + <br>, see _handleKeydown), but descend into\n // any stray wrapper for safety.\n if (!this._editor) return '';\n let out = '';\n const walk = (node: Node): void => {\n node.childNodes.forEach(child => {\n if (child.nodeType === Node.TEXT_NODE) out += child.textContent ?? '';\n else if (child.nodeName === 'BR') out += '\\n';\n else walk(child);\n });\n };\n walk(this._editor);\n return out.trim();\n }\n\n setValue(value: string): void {\n if (!this._editor) return;\n this._editor.textContent = value;\n this._updatePlaceholderVisibility();\n this._adjustHeight();\n this._getRoot()?.setValue(value);\n }\n\n clear(): void {\n if (!this._editor) return;\n this._editor.innerHTML = '';\n this._updatePlaceholderVisibility();\n this._adjustHeight();\n this._getRoot()?.setValue('');\n }\n\n override focus(): void { this._editor?.focus(); }\n override blur(): void { this._editor?.blur(); }\n\n /** Focus the editor and place the caret at the very end of its content. */\n focusEnd(): void {\n if (!this._editor) return;\n this._editor.focus();\n const sel = this.ownerDocument?.getSelection();\n if (!sel) return;\n const range = this.ownerDocument.createRange();\n range.selectNodeContents(this._editor);\n range.collapse(false);\n sel.removeAllRanges();\n sel.addRange(range);\n }\n\n // ── Private ─────────────────────────────────────────────────────────────\n\n private _getRoot(): AparteComposer | null {\n return this.closest('aparte-composer') as AparteComposer | null;\n }\n\n private _getPlaceholder(): string {\n return this.getAttribute('placeholder')\n || this._getRoot()?.placeholder\n || resolveConfig(this).t('inputPlaceholder')\n || 'Type a message...';\n }\n\n private _render(): void {\n if (this.querySelector('.aparte-ci-editor')) return;\n\n const disabled = this.hasAttribute('disabled') || this._getRoot()?.disabled || false;\n // `placeholder` may come straight from a host attribute (often bound to\n // dynamic/translated text) — escape before it lands in a double-quoted\n // attribute so a stray `\"` can't break out and inject markup.\n const placeholder = escapeAttr(this._getPlaceholder());\n\n this.innerHTML = `<div\n class=\"aparte-ci-editor\"\n contenteditable=\"${!disabled}\"\n role=\"textbox\"\n aria-multiline=\"true\"\n aria-label=\"${placeholder}\"\n tabindex=\"0\"\n aria-disabled=\"${disabled}\"\n data-placeholder=\"${placeholder}\"\n ></div>`;\n\n this._editor = this.querySelector('.aparte-ci-editor');\n this._editor?.addEventListener('input', this._onInput);\n this._editor?.addEventListener('keydown', this._onKeydown);\n this._editor?.addEventListener('focus', this._onFocus);\n this._editor?.addEventListener('blur', this._onBlur);\n this._editor?.addEventListener('paste', this._onPaste);\n\n this._adjustHeight();\n }\n\n private _connectToRoot(): void {\n const root = this._getRoot();\n if (!root) return;\n\n // Sync disabled state from root\n this._unsubscribes.push(\n root._on('disabled-change', ({ disabled }) => this._updateDisabled(disabled))\n );\n\n // When root clears value (after submit), clear our editor\n this._unsubscribes.push(\n root._on('value-change', ({ value }) => {\n if (value === '' && this.getValue() !== '') this.clear();\n })\n );\n\n // Sync streaming state — disable input while streaming\n this._unsubscribes.push(\n root._on('streaming-change', ({ streaming }) => {\n this._updateDisabled(streaming || root.disabled);\n })\n );\n }\n\n private _handleInput(): void {\n this._adjustHeight();\n // After a delete-all, contenteditable leaves residual `<br>` tags\n // (Chromium especially) so the `:empty` CSS pseudo-class no longer\n // matches and the placeholder stays hidden. Force-clear when text\n // content reduces to whitespace so the placeholder reappears.\n if (this._editor && !this._editor.textContent?.trim() && this._editor.innerHTML !== '') {\n this._editor.innerHTML = '';\n }\n this._updatePlaceholderVisibility();\n const value = this.getValue();\n this._getRoot()?.setValue(value);\n }\n\n private _handleKeydown(e: KeyboardEvent): void {\n // During IME composition (CJK/Japanese/Korean), Enter confirms the\n // candidate — it must never submit. `keyCode === 229` is the legacy\n // signal for engines that don't set `isComposing`.\n if (e.isComposing || e.keyCode === 229) return;\n if (e.key !== 'Enter') return;\n // `submit-on-enter` (default true): Enter submits, Shift+Enter inserts\n // a newline. When false the mapping inverts — Shift+Enter submits and\n // a bare Enter inserts a newline (lets the user author multi-line).\n const submitOnEnter = this._getRoot()?.submitOnEnter ?? true;\n const submits = submitOnEnter ? !e.shiftKey : e.shiftKey;\n if (submits) {\n e.preventDefault();\n const root = this._getRoot();\n if (root) {\n root.submit();\n } else {\n // Standalone (no <aparte-composer> parent, e.g. the bubble's inline\n // editor): there is no root to submit to, so surface the intent as a\n // DOM event the host can act on. Keeps this primitive reusable on its\n // own — the IME guard + submitOnEnter mapping above stay the single\n // source of truth for \"when to submit\".\n this.dispatchEvent(new CustomEvent('aparte-composer-submit', { bubbles: true }));\n }\n } else {\n // Newline branch. Take control instead of the browser's contenteditable\n // default, which inserts <div>/<br> wrappers that resist deletion.\n // `insertLineBreak` inserts a single <br> and manages the trailing bogus\n // <br> so backspace removes it cleanly (the \"can't delete the newline\" bug).\n e.preventDefault();\n // Nothing to break on an empty field — don't seed a leading blank line.\n if (!this._editor?.textContent) return;\n this.ownerDocument?.execCommand('insertLineBreak');\n }\n }\n\n private _handleFocus(): void {\n this.classList.add('is-focused');\n }\n\n private _handleBlur(): void {\n this.classList.remove('is-focused');\n }\n\n private _handlePaste(e: ClipboardEvent): void {\n e.preventDefault();\n const cd = e.clipboardData;\n if (!cd) return;\n\n // Image paste → push to root attachments\n const imageFile = Array.from(cd.items).find(i => i.type.startsWith('image/'))?.getAsFile();\n if (imageFile) {\n this._getRoot()?.addAttachments([imageFile]);\n return;\n }\n\n // Plain text paste\n const text = cd.getData('text/plain');\n if (text) {\n document.execCommand('insertText', false, text);\n }\n }\n\n private _adjustHeight(): void {\n if (!this._editor) return;\n // Measure with height:0 (not auto): an explicit height opts the editor\n // OUT of any parent flex `align-items: stretch`, so scrollHeight reflects\n // the real content — not the (taller) row it may be stretched into. With\n // `auto`, a stretching parent inflates scrollHeight and the editor gets\n // stuck tall until the next reflow.\n this._editor.style.height = '0px';\n // Floor: the `min-height` ATTRIBUTE when explicitly set; otherwise defer\n // to the stylesheet (CSS min-height caps an inline height anyway). A\n // hardcoded JS floor would override theme CSS with an inline style and\n // break editor/controls alignment in restyled composers.\n const floor = this.hasAttribute('min-height') ? this._minHeight : 0;\n const contentHeight = this._editor.scrollHeight;\n const h = Math.min(Math.max(contentHeight, floor), this._maxHeight);\n this._editor.style.height = `${h}px`;\n this._editor.style.overflowY = contentHeight > this._maxHeight ? 'auto' : 'hidden';\n }\n\n /**\n * The first `_adjustHeight()` runs synchronously in `_render()` on connect —\n * before the stylesheet, flex layout and web fonts have necessarily settled.\n * On an unstabilized layout `scrollHeight` can read inflated, leaving the\n * editor stuck tall (misaligned with the composer controls) until the first\n * keystroke re-measures it. Re-measure once the layout is ready so it's\n * correct from the first paint.\n */\n private _scheduleInitialReflow(): void {\n if (typeof requestAnimationFrame === 'function') {\n requestAnimationFrame(() => this._adjustHeight());\n }\n const fonts = (document as Document & { fonts?: { ready?: Promise<unknown> } }).fonts;\n fonts?.ready?.then(() => this._adjustHeight()).catch(() => { /* fonts unavailable — rAF path covers it */ });\n }\n\n private _updatePlaceholder(): void {\n if (this._editor) {\n const p = this._getPlaceholder();\n this._editor.setAttribute('data-placeholder', p);\n this._editor.setAttribute('aria-label', p);\n }\n }\n\n private _updatePlaceholderVisibility(): void {\n // Handled by CSS :empty — nothing to do\n }\n\n private _updateDisabled(disabled: boolean): void {\n if (!this._editor) return;\n this._editor.setAttribute('contenteditable', String(!disabled));\n this._editor.setAttribute('aria-disabled', String(disabled));\n }\n\n /** Escape a value before it lands in a double-quoted HTML attribute. */\n}\n\nif (!customElements.get('aparte-composer-input')) {\n customElements.define('aparte-composer-input', AparteComposerInput);\n}\n","import { resolveConfig } from '../../config/index.js';\nimport type { AparteComposer } from './aparte-composer.js';\nimport { escapeAttr } from '../../utils/escape.js';\n\n/**\n * @element aparte-composer-send\n *\n * Submit button primitive for <aparte-composer>.\n * Must be a descendant of <aparte-composer>.\n *\n * - Disabled when composer value is empty, composer is disabled, or streaming\n * - While streaming: shows stop icon and acts as cancel button\n *\n * @example\n * <!-- One button for both halves of the turn: it submits, and while a reply streams it\n * becomes the stop button. Do not disable it on `streaming` or stop is unreachable. -->\n * <aparte-composer>\n * <div class=\"aparte-composer-row\">\n * <aparte-composer-input style=\"flex: 1\"></aparte-composer-input>\n * <aparte-composer-send></aparte-composer-send>\n * </div>\n * </aparte-composer>\n */\nexport class AparteComposerSend extends HTMLElement {\n private _button: HTMLButtonElement | null = null;\n private _unsubscribes: (() => void)[] = [];\n\n // Bound handler\n private _onClick = this._handleClick.bind(this);\n\n connectedCallback(): void {\n this._render();\n this._connectToRoot();\n }\n\n disconnectedCallback(): void {\n this._button?.removeEventListener('click', this._onClick);\n this._unsubscribes.forEach(fn => fn());\n this._unsubscribes = [];\n }\n\n // ── Private ─────────────────────────────────────────────────────────────\n\n private _getRoot(): AparteComposer | null {\n return this.closest('aparte-composer') as AparteComposer | null;\n }\n\n private _render(): void {\n if (this.querySelector('.aparte-cs-button')) return;\n\n const label = resolveConfig(this).t('sendButton') || 'Send';\n const icon = this._getSendIcon();\n const root = this._getRoot();\n const disabled = !root || root.disabled || root.value.trim() === '';\n\n this.innerHTML = `<button\n class=\"aparte-cs-button aparte-send-button\"\n aria-label=\"${escapeAttr(label)}\"\n title=\"${escapeAttr(label)}\"\n ${disabled ? 'disabled' : ''}\n >${icon}</button>`; // safe-text: _getSendIcon() returns the provider's SVG markup — escaping it would print the source\n\n this._button = this.querySelector('.aparte-cs-button');\n this._button?.addEventListener('click', this._onClick);\n }\n\n private _connectToRoot(): void {\n const root = this._getRoot();\n if (!root) return;\n\n this._unsubscribes.push(\n root._on('value-change', () => this._syncState())\n );\n this._unsubscribes.push(\n root._on('disabled-change', () => this._syncState())\n );\n this._unsubscribes.push(\n root._on('streaming-change', ({ streaming }) => {\n // If panel is active, streaming state change doesn't affect the button —\n // the panel controls it (submit answer, not stop stream)\n if (this._getRoot()?.panelActive) return;\n this._syncStreamingState(streaming);\n })\n );\n this._unsubscribes.push(\n root._on('attachments-change', () => this._syncState())\n );\n this._unsubscribes.push(\n root._on('panel-change', ({ active, submitEnabled, mode }) => {\n if (!this._button) return;\n if (active) {\n // Panel is shown — this one button now means \"answer\", and WHICH\n // answer depends on where you are in the form.\n //\n // The icon has to move with the meaning: it drew a paper plane while\n // the label already said \"Submit\", so it read as \"send a message\"\n // while it meant \"answer this question\". And a check on a form with\n // three questions left was just as wrong — hence a chevron while\n // there is more ahead. The visual is what a user reads.\n this._button.disabled = !submitEnabled;\n const cfg = resolveConfig(this);\n const advancing = mode === 'advance';\n this._button.innerHTML = advancing ? cfg.getIcon('nextBranch') : this._getSubmitIcon();\n const label = advancing\n ? (cfg.t('elicitationNext') || 'Next')\n : (cfg.t('submitButton') || 'Submit');\n this._button.setAttribute('aria-label', label);\n this._button.setAttribute('title', label);\n this._button.classList.remove('is-streaming');\n } else {\n // Panel closed — restore state based on current streaming\n const root = this._getRoot();\n if (root?.streaming) {\n this._syncStreamingState(true);\n } else {\n this._syncState();\n }\n }\n })\n );\n }\n\n private _handleClick(e: MouseEvent): void {\n e.preventDefault();\n this._getRoot()?.submit();\n }\n\n private _syncState(): void {\n const root = this._getRoot();\n if (!root || !this._button) return;\n if (root.streaming) return; // streaming state managed separately\n\n const isEmpty = root.value.trim() === '' && root.attachments.length === 0;\n this._button.disabled = root.disabled || isEmpty;\n this._button.innerHTML = this._getSendIcon();\n const label = resolveConfig(this).t('sendButton') || 'Send';\n this._button.setAttribute('aria-label', label);\n this._button.setAttribute('title', label);\n this._button.classList.remove('is-streaming');\n }\n\n private _syncStreamingState(streaming: boolean): void {\n if (!this._button) return;\n if (streaming) {\n this._button.disabled = false;\n this._button.innerHTML = this._getStopIcon();\n this._button.setAttribute('aria-label', 'Stop');\n this._button.setAttribute('title', 'Stop');\n this._button.classList.add('is-streaming');\n } else {\n this._syncState();\n }\n }\n\n /**\n * The icon for submitting an ANSWER, which is not the same act as sending a\n * message — one button, two meanings, and it has to say which one it is.\n */\n private _getSubmitIcon(): string {\n // No fallback chain: `getIcon` already returns a built-in when the consumer's\n // icon set has no entry, so `|| getIcon('send')` was dead code — written on the\n // assumption that it could come back empty, and a test proved it cannot.\n return resolveConfig(this).getIcon('check');\n }\n\n private _getSendIcon(): string {\n return resolveConfig(this).getIcon('send') || 'Send';\n }\n\n private _getStopIcon(): string {\n return resolveConfig(this).getIcon('stop');\n }\n}\n\nif (!customElements.get('aparte-composer-send')) {\n customElements.define('aparte-composer-send', AparteComposerSend);\n}\n","import { resolveConfig } from '../../config/index.js';\nimport type { AparteComposer } from './aparte-composer.js';\nimport { escapeAttr } from '../../utils/escape.js';\n\n/**\n * @element aparte-composer-cancel\n *\n * Cancel/stop streaming button primitive for <aparte-composer>.\n * Must be a descendant of <aparte-composer>.\n *\n * Hidden when not streaming. Visible only during active streaming.\n *\n * @example\n * <!-- Only needed when you want a SEPARATE stop button: <aparte-composer-send> already\n * turns into one while streaming. This stays hidden until then. -->\n * <aparte-composer>\n * <div class=\"aparte-composer-row\">\n * <aparte-composer-input style=\"flex: 1\"></aparte-composer-input>\n * <aparte-composer-cancel></aparte-composer-cancel>\n * <aparte-composer-send></aparte-composer-send>\n * </div>\n * </aparte-composer>\n */\nexport class AparteComposerCancel extends HTMLElement {\n private _button: HTMLButtonElement | null = null;\n private _unsubscribes: (() => void)[] = [];\n\n // Bound handler\n private _onClick = this._handleClick.bind(this);\n\n connectedCallback(): void {\n this._render();\n this._connectToRoot();\n }\n\n disconnectedCallback(): void {\n this._button?.removeEventListener('click', this._onClick);\n this._unsubscribes.forEach(fn => fn());\n this._unsubscribes = [];\n }\n\n // ── Private ─────────────────────────────────────────────────────────────\n\n private _getRoot(): AparteComposer | null {\n return this.closest('aparte-composer') as AparteComposer | null;\n }\n\n private _render(): void {\n if (this.querySelector('.aparte-cc-button')) return;\n\n const label = resolveConfig(this).t('stopButton') || 'Stop';\n const icon = this._getStopIcon();\n\n this.innerHTML = `<button\n class=\"aparte-cc-button\"\n aria-label=\"${escapeAttr(label)}\"\n title=\"${escapeAttr(label)}\"\n hidden\n >${icon}</button>`; // safe-text: _getStopIcon() returns the provider's SVG markup — escaping it would print the source\n\n this._button = this.querySelector('.aparte-cc-button');\n this._button?.addEventListener('click', this._onClick);\n }\n\n private _connectToRoot(): void {\n const root = this._getRoot();\n if (!root) return;\n\n this._unsubscribes.push(\n root._on('streaming-change', ({ streaming }) => {\n if (this._button) this._button.hidden = !streaming;\n })\n );\n\n // Sync initial state\n if (root.streaming && this._button) this._button.hidden = false;\n }\n\n private _handleClick(e: MouseEvent): void {\n e.preventDefault();\n this._getRoot()?.cancel();\n }\n\n private _getStopIcon(): string {\n return resolveConfig(this).getIcon('stop');\n }\n}\n\nif (!customElements.get('aparte-composer-cancel')) {\n customElements.define('aparte-composer-cancel', AparteComposerCancel);\n}\n","import type { AparteComposer } from './aparte-composer.js';\nimport { resolveConfig } from '../../config/config-context.js';\nimport { escapeAttr } from '../../utils/escape.js';\n\n/** ✗ glyph for the hover remove button. */\nconst REMOVE_ICON =\n '<svg width=\"10\" height=\"10\" viewBox=\"0 0 12 12\" fill=\"currentColor\" aria-hidden=\"true\">' +\n '<path d=\"M9.5 3.205 8.795 2.5 6 5.295 3.205 2.5 2.5 3.205 5.295 6 2.5 8.795l.705.705' +\n 'L6 6.705l2.795 2.795.705-.705L6.705 6z\"/></svg>';\n\n/**\n * @element aparte-composer-attachments\n *\n * Renders a square thumbnail tile for each file attached to the root composer.\n * Image files show the actual picture; other files show an extension badge.\n * The filename and a remove (✗) button surface on hover. Clicking an image asks\n * the app to open it full-size (`aparte-attachment-preview`) — only when the app\n * declared `attachmentPreview` via `aparteGlobalConfig.setHostHandlers()`.\n * Automatically hidden when there are no attachments.\n * Must be a descendant of <aparte-composer>.\n *\n * @example\n * <!-- The strip hides itself while nothing is attached. Pair it with the picker, and\n * only if your loop actually reads the files from the send event. -->\n * <aparte-composer>\n * <div class=\"aparte-composer-shell\">\n * <aparte-composer-attachments></aparte-composer-attachments>\n * <div class=\"aparte-composer-row\">\n * <aparte-composer-add-attachment></aparte-composer-add-attachment>\n * <aparte-composer-input style=\"flex: 1\"></aparte-composer-input>\n * <aparte-composer-send></aparte-composer-send>\n * </div>\n * </div>\n * </aparte-composer>\n */\nexport class AparteComposerAttachments extends HTMLElement {\n private _unsubscribes: (() => void)[] = [];\n /** Object URLs minted for image previews — revoked on re-render/disconnect. */\n private _objectUrls: string[] = [];\n\n connectedCallback(): void {\n this._render([]);\n this._connectToRoot();\n }\n\n disconnectedCallback(): void {\n this._unsubscribes.forEach(fn => fn());\n this._unsubscribes = [];\n this._revokeUrls();\n }\n\n // ── Private ─────────────────────────────────────────────────────────────\n\n private _getRoot(): AparteComposer | null {\n return this.closest('aparte-composer') as AparteComposer | null;\n }\n\n private _connectToRoot(): void {\n const root = this._getRoot();\n if (!root) return;\n\n this._unsubscribes.push(\n root._on('attachments-change', ({ attachments }) => this._render(attachments))\n );\n\n // Sync initial state\n this._render(root.attachments);\n }\n\n /** Release the previous render's blob URLs so they don't leak. */\n private _revokeUrls(): void {\n this._objectUrls.forEach(url => URL.revokeObjectURL(url));\n this._objectUrls = [];\n }\n\n private _render(files: File[]): void {\n this.hidden = files.length === 0;\n // Free the previous render's preview URLs before minting new ones.\n this._revokeUrls();\n\n this.innerHTML = files.map((file) => {\n const name = this._escape(file.name);\n const remove =\n `<button class=\"aparte-thumb__remove\" type=\"button\" ` +\n `aria-label=\"Remove ${name}\">${REMOVE_ICON}</button>`;\n\n if (file.type.startsWith('image/')) {\n const url = URL.createObjectURL(file);\n this._objectUrls.push(url);\n return `<div class=\"aparte-thumb aparte-thumb--image\" title=\"${escapeAttr(name)}\">` +\n `<img class=\"aparte-thumb__img\" src=\"${escapeAttr(url)}\" alt=\"${escapeAttr(name)}\" />` +\n `<span class=\"aparte-thumb__name\">${name}</span>${remove}</div>`;\n }\n return `<div class=\"aparte-thumb aparte-thumb--file\" title=\"${escapeAttr(name)}\">` +\n `<span class=\"aparte-thumb__ext\">${this._escape(this._ext(file.name))}</span>` +\n `<span class=\"aparte-thumb__name\">${name}</span>${remove}</div>`;\n }).join('');\n\n // Remove buttons — every file has exactly one tile, so the button\n // index lines up with the attachments index.\n this.querySelectorAll('.aparte-thumb__remove').forEach((btn, i) => {\n btn.addEventListener('click', (e) => {\n e.stopPropagation();\n const root = this._getRoot();\n if (root) root.removeAttachment(root.attachments[i]!);\n });\n });\n\n // Image tiles ask for the full-size preview — only when the app declared it\n // opens one (same rule as the sent-message strip in the bubble).\n if (!resolveConfig(this).getHostHandlers().attachmentPreview) return;\n this.querySelectorAll('.aparte-thumb--image').forEach(tile => {\n tile.setAttribute('role', 'button');\n tile.setAttribute('tabindex', '0');\n const open = (): void => {\n const img = tile.querySelector('.aparte-thumb__img') as HTMLImageElement | null;\n if (!img) return;\n this.dispatchEvent(new CustomEvent('aparte-attachment-preview', {\n bubbles: true,\n composed: true,\n detail: { url: img.src, name: tile.getAttribute('title') ?? '' },\n }));\n };\n tile.addEventListener('click', open);\n tile.addEventListener('keydown', (e) => {\n const key = (e as KeyboardEvent).key;\n if (key !== 'Enter' && key !== ' ') return;\n e.preventDefault();\n open();\n });\n });\n }\n\n /** Uppercased file extension (≤4 chars), or 'FILE' when there is none. */\n private _ext(filename: string): string {\n const dot = filename.lastIndexOf('.');\n return dot > 0 ? filename.slice(dot + 1).toUpperCase().slice(0, 4) : 'FILE';\n }\n\n private _escape(str: string): string {\n return str.replace(/&/g, '&').replace(/</g, '<').replace(/>/g, '>').replace(/\"/g, '"').replace(/'/g, ''');\n }\n}\n\nif (!customElements.get('aparte-composer-attachments')) {\n customElements.define('aparte-composer-attachments', AparteComposerAttachments);\n}\n","import { resolveConfig } from '../../config/index.js';\nimport type { AparteComposer } from './aparte-composer.js';\nimport { escapeAttr } from '../../utils/escape.js';\n\n/**\n * @element aparte-composer-add-attachment\n *\n * File picker button for <aparte-composer>.\n * Opens a native file picker on click, then pushes picked files to root.addAttachments().\n * Also sets up drag & drop on the nearest <aparte-composer> root.\n *\n * @attr accept - MIME types / extensions passed to the file input (e.g. \"image/*,.pdf\")\n * @attr multiple - Allow multiple file selection (default: true)\n *\n * @example\n * <!-- Opt-in: nothing consumes the files unless your host does (an AparteClient, or\n * your own listener reading `event.detail.files` off `aparte-send`). -->\n * <aparte-composer>\n * <div class=\"aparte-composer-row\">\n * <aparte-composer-add-attachment accept=\"image/*,.pdf\"></aparte-composer-add-attachment>\n * <aparte-composer-input style=\"flex: 1\"></aparte-composer-input>\n * <aparte-composer-send></aparte-composer-send>\n * </div>\n * </aparte-composer>\n */\nexport class AparteComposerAddAttachment extends HTMLElement {\n private _button: HTMLButtonElement | null = null;\n private _dragCleanup: (() => void) | null = null;\n private _unsubscribes: (() => void)[] = [];\n\n // Bound handler\n private _onClick = this._handleClick.bind(this);\n\n static get observedAttributes(): string[] {\n return ['accept', 'multiple', 'disabled'];\n }\n\n connectedCallback(): void {\n this._render();\n this._connectToRoot();\n this._setupDragDrop();\n }\n\n disconnectedCallback(): void {\n this._button?.removeEventListener('click', this._onClick);\n this._dragCleanup?.();\n this._unsubscribes.forEach(fn => fn());\n this._unsubscribes = [];\n }\n\n attributeChangedCallback(name: string, _old: string | null, value: string | null): void {\n if (name === 'disabled' && this._button) {\n this._button.disabled = value !== null;\n }\n }\n\n // ── Private ─────────────────────────────────────────────────────────────\n\n private _getRoot(): AparteComposer | null {\n return this.closest('aparte-composer') as AparteComposer | null;\n }\n\n private _render(): void {\n if (this.querySelector('.aparte-caa-button')) return;\n\n const label = resolveConfig(this).t('actionUpload') || 'Attach file';\n const icon = resolveConfig(this).getIcon('paperclip') || this._defaultIcon();\n const disabled = this.hasAttribute('disabled') || this._getRoot()?.disabled || false;\n\n this.innerHTML = `<button\n class=\"aparte-caa-button aparte-action-button\"\n aria-label=\"${escapeAttr(label)}\"\n title=\"${escapeAttr(label)}\"\n type=\"button\"\n ${disabled ? 'disabled' : ''}\n >${icon}</button>`;\n\n this._button = this.querySelector('.aparte-caa-button');\n this._button?.addEventListener('click', this._onClick);\n }\n\n private _connectToRoot(): void {\n const root = this._getRoot();\n if (!root) return;\n\n this._unsubscribes.push(\n root._on('disabled-change', ({ disabled }) => {\n if (this._button) this._button.disabled = disabled;\n })\n );\n this._unsubscribes.push(\n root._on('streaming-change', ({ streaming }) => {\n if (this._button) this._button.disabled = streaming || root.disabled;\n })\n );\n }\n\n private _handleClick(): void {\n const input = document.createElement('input');\n input.type = 'file';\n input.multiple = !this.hasAttribute('multiple') || this.getAttribute('multiple') !== 'false';\n const accept = this.getAttribute('accept');\n if (accept) input.accept = accept;\n input.style.display = 'none';\n\n document.body.appendChild(input);\n input.addEventListener('change', () => {\n if (input.files?.length) this._getRoot()?.addAttachments(input.files);\n document.body.removeChild(input);\n }, { once: true });\n input.click();\n }\n\n private _setupDragDrop(): void {\n const root = this._getRoot();\n if (!root) return;\n\n const prevent = (e: Event) => { e.preventDefault(); e.stopPropagation(); };\n const onDragOver = (e: Event) => {\n if (root.disabled) return; // no drop target while disabled (e.g. streaming)\n prevent(e);\n root.classList.add('is-dragover');\n };\n const onDragLeave = (e: Event) => { prevent(e); root.classList.remove('is-dragover'); };\n const onDrop = (e: DragEvent) => {\n prevent(e); // always block the browser from navigating to the dropped file\n root.classList.remove('is-dragover');\n if (root.disabled) return; // don't attach while disabled (the add button is blocked too)\n const files = e.dataTransfer?.files;\n if (files?.length) this._getRoot()?.addAttachments(files);\n };\n\n root.addEventListener('dragover', onDragOver);\n root.addEventListener('dragleave', onDragLeave);\n root.addEventListener('drop', onDrop);\n\n this._dragCleanup = () => {\n root.removeEventListener('dragover', onDragOver);\n root.removeEventListener('dragleave', onDragLeave);\n root.removeEventListener('drop', onDrop);\n };\n }\n\n private _defaultIcon(): string {\n return `<svg width=\"16\" height=\"16\" viewBox=\"0 0 24 24\" fill=\"none\" stroke=\"currentColor\" stroke-width=\"2\" stroke-linecap=\"round\" stroke-linejoin=\"round\"><path d=\"m21.44 11.05-9.19 9.19a6 6 0 0 1-8.49-8.49l8.57-8.57A4 4 0 1 1 18 8.84l-8.59 8.57a2 2 0 0 1-2.83-2.83l8.49-8.48\"/></svg>`;\n }\n}\n\nif (!customElements.get('aparte-composer-add-attachment')) {\n customElements.define('aparte-composer-add-attachment', AparteComposerAddAttachment);\n}\n","import { resolveConfig, type AparteIconName } from '../../config/index.js';\nimport type { AparteComposer } from './aparte-composer.js';\nimport { escapeAttr } from '../../utils/escape.js';\n\n/**\n * @element aparte-composer-action\n *\n * Generic action button primitive for <aparte-composer>.\n * The consumer declares it directly in markup — no global registration needed.\n *\n * @attr icon - Icon key for aparteGlobalConfig.getIcon(), or raw SVG/HTML starting with `<`\n * @attr label - Accessible label (also used as tooltip)\n * @attr disabled - Disables the button\n *\n * @fires aparte-action-click - Bubbles up when the button is clicked\n * detail: { actionId: string, composer: AparteComposer | null }\n *\n * @slot default - Optional: override button content entirely\n *\n * @example\n * <aparte-composer-action icon=\"star\" label=\"Favourite\"\n * (click)=\"onFavourite()\">\n * </aparte-composer-action>\n */\nexport class AparteComposerAction extends HTMLElement {\n private _button: HTMLButtonElement | null = null;\n private _unsubscribes: (() => void)[] = [];\n\n // Bound handler\n private _onClick = this._handleClick.bind(this);\n\n static get observedAttributes(): string[] {\n return ['icon', 'label', 'disabled'];\n }\n\n connectedCallback(): void {\n this._render();\n this._connectToRoot();\n }\n\n disconnectedCallback(): void {\n this._button?.removeEventListener('click', this._onClick);\n this._unsubscribes.forEach(fn => fn());\n this._unsubscribes = [];\n }\n\n attributeChangedCallback(name: string, _old: string | null, value: string | null): void {\n if (!this._button) return;\n if (name === 'disabled') {\n this._button.disabled = value !== null;\n }\n if (name === 'label') {\n this._button.setAttribute('aria-label', value ?? '');\n this._button.setAttribute('title', value ?? '');\n }\n if (name === 'icon') {\n this._button.innerHTML = this._resolveIcon(value ?? '');\n }\n }\n\n // ── Private ─────────────────────────────────────────────────────────────\n\n private _getRoot(): AparteComposer | null {\n return this.closest('aparte-composer') as AparteComposer | null;\n }\n\n private _render(): void {\n if (this.querySelector('.aparte-cact-button')) return;\n\n // `label` is a host-set attribute (often bound to dynamic/translated\n // text by the consumer) — escape before it lands in a double-quoted\n // attribute so a stray `\"` can't break out and inject markup.\n const label = escapeAttr(this.getAttribute('label') ?? '');\n const icon = this._resolveIcon(this.getAttribute('icon') ?? ''); // safe-text: _resolveIcon returns provider SVG, or the host-set icon attribute verbatim when it starts with < — documented as trusted markup, same contract as AparteIconProvider\n const disabled = this.hasAttribute('disabled') || this._getRoot()?.disabled || false;\n\n this.innerHTML = `<button\n class=\"aparte-cact-button aparte-action-button\"\n aria-label=\"${label}\"\n title=\"${label}\"\n type=\"button\"\n ${disabled ? 'disabled' : ''}\n >${icon}</button>`;\n\n this._button = this.querySelector('.aparte-cact-button');\n this._button?.addEventListener('click', this._onClick);\n }\n\n private _connectToRoot(): void {\n const root = this._getRoot();\n if (!root) return;\n\n this._unsubscribes.push(\n root._on('disabled-change', ({ disabled }) => {\n if (this._button) this._button.disabled = disabled || this.hasAttribute('disabled');\n })\n );\n this._unsubscribes.push(\n root._on('streaming-change', ({ streaming }) => {\n if (this._button) this._button.disabled = streaming || root.disabled || this.hasAttribute('disabled');\n })\n );\n }\n\n private _handleClick(_e: MouseEvent): void {\n this.dispatchEvent(new CustomEvent<AparteActionClickEventDetail>('aparte-action-click', {\n bubbles: true,\n composed: true,\n detail: { actionId: this.getAttribute('action-id') ?? '', composer: this._getRoot() },\n }));\n }\n\n private _resolveIcon(icon: string): string {\n if (!icon) return '';\n if (icon.trimStart().startsWith('<')) return icon;\n return resolveConfig(this).getIcon(icon as AparteIconName) ?? icon;\n }\n\n /** Escape a value before it lands in a double-quoted HTML attribute. */\n}\n\nif (!customElements.get('aparte-composer-action')) {\n customElements.define('aparte-composer-action', AparteComposerAction);\n}\n\n/**\n * Detail payload for `aparte-action-click`.\n *\n * `<aparte-composer-action>` is a publicly exported element whose only purpose is\n * to emit this event, and nothing in core listens for it — so the app IS the\n * consumer, and it had no type to read `e.detail` with. The shape was already\n * published in prose in the generated API reference; this makes it compile.\n *\n * @event aparte-action-click\n */\nexport interface AparteActionClickEventDetail {\n /** The `action-id` attribute of the button that was clicked, or `''`. */\n actionId: string;\n /** The owning composer, or `null` when the button is used outside one. */\n composer: AparteComposer | null;\n}\n","/**\n * @element aparte-composer-toolbar\n *\n * The composer's bottom row — the strip a mode picker, a model selector or a token\n * counter belongs in, rather than a bar of your own floating below the chat. Purely\n * structural: it lays its children out in a row and gets out of the way.\n *\n * **Position is the DOM order.** `margin-inline-start: auto` on a child pushes it (and\n * everything after it) to the end of the row. That is the whole placement API on\n * purpose: there is no `left`/`right` to be wrong about, so the row reads correctly in a\n * right-to-left locale without the author thinking about it.\n *\n * The row is not part of the default `<aparte-chat>` shell — nothing is drawn until you\n * put something in it.\n *\n * @attr data-empty - Reflected BY the element while it holds no element child; the\n * stylesheet hides it then. Read-only, do not set it yourself.\n *\n * @example\n * <aparte-composer>\n * <div class=\"aparte-composer-shell\">\n * <div class=\"aparte-composer-row\">\n * <aparte-composer-input></aparte-composer-input>\n * <aparte-composer-send></aparte-composer-send>\n * </div>\n *\n * <!-- `aparte-model-selector` is NOT part of core: importing\n * `@aparte/plugin-model-selector` is what defines it. Until then the tag\n * renders empty and inert with no error, and upgrades by itself when the\n * definition arrives. Any element of your own works here too. -->\n * <aparte-composer-toolbar>\n * <my-mode-picker></my-mode-picker>\n * <aparte-model-selector style=\"margin-inline-start:auto\"></aparte-model-selector>\n * </aparte-composer-toolbar>\n * </div>\n * </aparte-composer>\n */\nexport class AparteComposerToolbar extends HTMLElement {\n private _observer: MutationObserver | null = null;\n\n connectedCallback(): void {\n this._syncEmpty();\n // Children can arrive after connection — a framework commits the element and its\n // children in whichever order suits it, and a consumer may add a control later.\n this._observer ??= new MutationObserver(() => this._syncEmpty());\n this._observer.observe(this, { childList: true });\n }\n\n disconnectedCallback(): void {\n this._observer?.disconnect();\n this._observer = null;\n }\n\n /**\n * Reflect `data-empty` from the presence of an ELEMENT child.\n *\n * Not `:empty` in CSS: that selector does not match an element holding a whitespace\n * text node, so a template that indents its content keeps the row — separator,\n * padding and all — while it looks empty to the user. Every framework template\n * indents. An empty row must not draw its own separator (the same rule as an empty\n * bubble action bar).\n *\n * Non-whitespace TEXT counts as content, not just an element child: a hand-written\n * row holding a bare token count (`<aparte-composer-toolbar>1 240 tokens</…>`) is\n * not empty, and hiding it would be a twenty-minute mystery for whoever wrote it.\n */\n private _syncEmpty(): void {\n const hasContent = Boolean(this.firstElementChild) || this.textContent?.trim() !== '';\n if (hasContent) this.removeAttribute('data-empty');\n else this.setAttribute('data-empty', '');\n }\n}\n\nif (!customElements.get('aparte-composer-toolbar')) {\n customElements.define('aparte-composer-toolbar', AparteComposerToolbar);\n}\n","/**\n * AparteConversationList — conversation history sidebar primitive\n *\n * Framework-agnostic web component. The host sets the `conversations`\n * JS property and the `active-id` attribute; the component renders the\n * list and fires events for user interactions.\n *\n * @fires {CustomEvent<AparteConversationSelectDetail>} aparte-select-conversation\n * @fires {CustomEvent<AparteConversationDeleteDetail>} aparte-delete-conversation\n * @fires {CustomEvent<AparteConversationArchiveDetail>} aparte-archive-conversation\n * @fires {CustomEvent<AparteConversationArchiveDetail>} aparte-unarchive-conversation\n */\n\nimport { resolveConfig } from '../../config/index.js';\nimport { escapeAttr } from '../../utils/escape.js';\n\nexport interface AparteConversationListItem {\n id: string;\n title: string;\n updatedAt?: number;\n /** When set, the item renders the unarchive action instead of archive. *\n */\n archivedAt?: number;\n}\n\nexport interface AparteConversationSelectDetail {\n id: string;\n}\n\nexport interface AparteConversationDeleteDetail {\n id: string;\n}\n\nexport interface AparteConversationArchiveDetail {\n id: string;\n}\n\n/**\n * @example\n * // The host owns the data: set the `conversations` property, listen for the intent.\n * const list = document.querySelector('aparte-conversation-list')!;\n * list.conversations = [\n * { id: 'c1', title: 'Deploy checklist', updatedAt: Date.now() },\n * { id: 'c2', title: 'Old thread', updatedAt: 0, archivedAt: Date.now() },\n * ];\n * list.setAttribute('active-id', 'c1');\n *\n * list.addEventListener('aparte-select-conversation', (e) => load(e.detail.id));\n * list.addEventListener('aparte-delete-conversation', (e) => remove(e.detail.id));\n */\nexport class AparteConversationList extends HTMLElement {\n private _conversations: AparteConversationListItem[] = [];\n private _activeId: string | null = null;\n\n static get observedAttributes(): string[] {\n return ['active-id'];\n }\n\n // ─── Lifecycle ────────────────────────────────────────────────────────\n\n connectedCallback(): void {\n if (!this.classList.contains('aparte-conv-list')) {\n this.classList.add('aparte-conv-list');\n }\n if (!this.getAttribute('role')) {\n this.setAttribute('role', 'navigation');\n }\n this._render();\n window.addEventListener('aparte-config-change', this._onConfigChange);\n }\n\n disconnectedCallback(): void {\n window.removeEventListener('aparte-config-change', this._onConfigChange);\n }\n\n attributeChangedCallback(name: string, oldValue: string | null, newValue: string | null): void {\n if (oldValue === newValue) return;\n if (name === 'active-id') {\n this._activeId = newValue;\n this._updateActiveState();\n }\n }\n\n /**\n * Re-render on a locale switch: every row's title fallback and both button\n * labels come from the locale, so without this the list stayed in the previous\n * language until something else happened to re-render it. Only OUR config.\n */\n private _onConfigChange = (e: Event): void => {\n const detail = (e as CustomEvent).detail as { config?: unknown } | undefined;\n if (detail?.config && detail.config !== resolveConfig(this)) return;\n this._render();\n };\n\n // ─── Public API ───────────────────────────────────────────────────────\n\n /** Set the list of conversations to display. Triggers a re-render. */\n set conversations(items: AparteConversationListItem[]) {\n this._conversations = Array.isArray(items) ? items : [];\n this._render();\n }\n\n get conversations(): AparteConversationListItem[] {\n return this._conversations;\n }\n\n // ─── Rendering ────────────────────────────────────────────────────────\n\n private _render(): void {\n this.innerHTML = this._conversations\n .map(conv => this._renderItem(conv))\n .join('');\n this._bindEvents();\n }\n\n private _renderItem(conv: AparteConversationListItem): string {\n const locale = resolveConfig(this).getLocale();\n const isActive = conv.id === this._activeId;\n const isArchived = !!conv.archivedAt;\n const activeClass = isActive ? ' aparte-conv-item--active' : '';\n const archivedClass = isArchived ? ' aparte-conv-item--archived' : '';\n const escapedId = this._esc(conv.id);\n const escapedTitle = this._esc(conv.title || locale.newChat);\n const deleteLabel = this._esc(locale.deleteConversation);\n const archiveLabel = this._esc(locale['archiveConversation'] ?? 'Archive conversation');\n const unarchiveLabel = this._esc(locale['unarchiveConversation'] ?? 'Unarchive conversation');\n const archiveAction = isArchived ? 'unarchive' : 'archive';\n const archiveAriaLabel = isArchived ? unarchiveLabel : archiveLabel;\n // Distinct icons: a downward tray for archive, an upward tray for unarchive.\n const archiveIcon = isArchived // safe-text: both branches are literal inline SVG written here — not input\n ? `<svg width=\"12\" height=\"12\" viewBox=\"0 0 24 24\" fill=\"none\" stroke=\"currentColor\" stroke-width=\"2.5\" stroke-linecap=\"round\" stroke-linejoin=\"round\" aria-hidden=\"true\"><polyline points=\"3 8 21 8\"/><path d=\"M5 8v11a2 2 0 0 0 2 2h10a2 2 0 0 0 2-2V8\"/><polyline points=\"9 14 12 11 15 14\"/><line x1=\"12\" y1=\"11\" x2=\"12\" y2=\"19\"/></svg>`\n : `<svg width=\"12\" height=\"12\" viewBox=\"0 0 24 24\" fill=\"none\" stroke=\"currentColor\" stroke-width=\"2.5\" stroke-linecap=\"round\" stroke-linejoin=\"round\" aria-hidden=\"true\"><polyline points=\"3 8 21 8\"/><path d=\"M5 8v11a2 2 0 0 0 2 2h10a2 2 0 0 0 2-2V8\"/><polyline points=\"9 14 12 17 15 14\"/><line x1=\"12\" y1=\"11\" x2=\"12\" y2=\"17\"/></svg>`;\n return `\n<div\n class=\"aparte-conv-item${activeClass}${archivedClass}\"\n role=\"button\"\n tabindex=\"0\"\n data-conv-id=\"${escapedId}\"\n aria-current=\"${isActive ? 'page' : 'false'}\"\n>\n <span class=\"aparte-conv-item__title\">${escapedTitle}</span>\n <button\n class=\"aparte-conv-item__archive\"\n type=\"button\"\n data-archive-id=\"${escapedId}\"\n data-archive-action=\"${escapeAttr(archiveAction)}\"\n aria-label=\"${escapeAttr(archiveAriaLabel)}\"\n tabindex=\"0\"\n >${archiveIcon}</button>\n <button\n class=\"aparte-conv-item__delete\"\n type=\"button\"\n data-delete-id=\"${escapedId}\"\n aria-label=\"${deleteLabel}\"\n tabindex=\"0\"\n >\n <svg width=\"12\" height=\"12\" viewBox=\"0 0 24 24\" fill=\"none\" stroke=\"currentColor\" stroke-width=\"2.5\"\n stroke-linecap=\"round\" stroke-linejoin=\"round\" aria-hidden=\"true\">\n <path d=\"M18 6L6 18M6 6l12 12\"/>\n </svg>\n </button>\n</div>`;\n }\n\n private _bindEvents(): void {\n this.addEventListener('click', this._onClick);\n this.addEventListener('keydown', this._onKeydown);\n }\n\n private _onClick = (e: Event): void => {\n const target = e.target as HTMLElement;\n const archiveBtn = target.closest('[data-archive-id]') as HTMLElement | null;\n if (archiveBtn) {\n e.stopPropagation();\n const id = archiveBtn.dataset['archiveId']!;\n const action = archiveBtn.dataset['archiveAction'];\n const eventName = action === 'unarchive'\n ? 'aparte-unarchive-conversation'\n : 'aparte-archive-conversation';\n this.dispatchEvent(new CustomEvent<AparteConversationArchiveDetail>(\n eventName,\n { detail: { id }, bubbles: true, composed: true }\n ));\n return;\n }\n const deleteBtn = target.closest('[data-delete-id]') as HTMLElement | null;\n if (deleteBtn) {\n e.stopPropagation();\n const id = deleteBtn.dataset['deleteId']!;\n this.dispatchEvent(new CustomEvent<AparteConversationDeleteDetail>(\n 'aparte-delete-conversation',\n { detail: { id }, bubbles: true, composed: true }\n ));\n return;\n }\n const item = target.closest('[data-conv-id]') as HTMLElement | null;\n if (item) {\n const id = item.dataset['convId']!;\n this.dispatchEvent(new CustomEvent<AparteConversationSelectDetail>(\n 'aparte-select-conversation',\n { detail: { id }, bubbles: true, composed: true }\n ));\n }\n };\n\n private _onKeydown = (e: KeyboardEvent): void => {\n if (e.key !== 'Enter' && e.key !== ' ') return;\n const item = (e.target as HTMLElement).closest('[data-conv-id]') as HTMLElement | null;\n if (item) {\n e.preventDefault();\n item.click();\n }\n };\n\n /** Update active class without full re-render (perf optimisation). */\n private _updateActiveState(): void {\n const items = this.querySelectorAll<HTMLElement>('[data-conv-id]');\n items.forEach(el => {\n const isActive = el.dataset['convId'] === this._activeId;\n el.classList.toggle('aparte-conv-item--active', isActive);\n el.setAttribute('aria-current', isActive ? 'page' : 'false');\n });\n }\n\n // ─── Helpers ──────────────────────────────────────────────────────────\n\n private _esc(str: string): string {\n return str\n .replace(/&/g, '&')\n .replace(/\"/g, '"')\n .replace(/</g, '<')\n .replace(/>/g, '>')\n .replace(/'/g, ''');\n }\n}\n\nif (!customElements.get('aparte-conversation-list')) customElements.define('aparte-conversation-list', AparteConversationList);\n","/**\n * <aparte-elicitation> — the default elicitation presenter.\n *\n * Registers itself as the presenter for the config governing its subtree\n * (`resolveConfig(this)`), so `requestUserInput()` from a tool handler is routed\n * here WITHOUT any window events — the typed presenter contract replaces the\n * stringly-typed `aparte-ask-user-*` events that drifted in Phase 1.\n *\n * On a request it builds the schema-appropriate panel (enum / boolean / string /\n * object) and mounts it inside the nearest `<aparte-composer>` via its\n * `showPanel` API, resolving:\n * - accept — the send button (panel submit), when all fields are complete\n * - decline — the inline \"Skip\" affordance\n * - cancel — the assistant turn was stopped/errored while pending\n *\n * Its CSS ships in `@aparte/core/styles.css` like every other component — it used\n * to inject its own <style> from here, which made it the one surface that could not\n * be themed and whose variables were missing from the generated CSS reference.\n *\n * Place anywhere inside the chat (it renders nothing itself):\n * <aparte-elicitation></aparte-elicitation>\n */\n\nimport { resolveConfig, runWithConfig, type AparteConfigAware } from '../../config/config-context.js';\nimport type { AparteConfig } from '../../config/aparte-config.js';\nimport type { AparteComposer } from '../composer/aparte-composer.js';\nimport { buildElicitationPanel, type BuiltElicitationPanel } from '../../elicitation/panel.js';\nimport type { AparteElicitationRequest, AparteElicitationResult, AparteElicitationPresenter } from '../../elicitation/types.js';\n\n/**\n * The slice of the composer this presenter drives.\n *\n * DERIVED from the component rather than re-typed by hand. It used to be a literal\n * copy of the three signatures, which is a twin: adding a parameter to the real\n * `setPanelSubmitEnabled` left this one behind, and the compiler pointed at the\n * CALLER instead of the stale declaration. `import type` is erased, so nothing here\n * pulls the composer element into a runtime import — which is why the copy existed.\n */\ntype ComposerEl = HTMLElement & Pick<AparteComposer, 'showPanel' | 'hidePanel' | 'setPanelSubmitEnabled'>;\n\ninterface Pending {\n settle(result: AparteElicitationResult): void;\n composer: ComposerEl;\n}\n\n/**\n * @example\n * <!-- Renders nothing by itself: it registers as the presenter for its subtree, so a\n * tool handler calling requestUserInput() gets its panel mounted in the composer. -->\n * <aparte-chat>\n * <aparte-chat-viewport></aparte-chat-viewport>\n * <aparte-elicitation></aparte-elicitation>\n * <aparte-composer>\n * <div class=\"aparte-composer-row\">\n * <aparte-composer-input style=\"flex: 1\"></aparte-composer-input>\n * <aparte-composer-send></aparte-composer-send>\n * </div>\n * </aparte-composer>\n * </aparte-chat>\n */\nexport class AparteElicitation extends HTMLElement implements AparteConfigAware {\n private _pending: Pending | null = null;\n /**\n * A turn ended — cancel the open question only if it was OUR turn.\n *\n * These two listeners sit on `window` and had no instance filter at all, so a\n * Stop (or an error) in one chat cancelled the question a DIFFERENT chat was\n * waiting on — and that chat's model was told the user had refused a question\n * the user was still looking at. Same defect as the `compact()` handler that\n * emptied both chats, which its four sibling handlers in `AparteClient` already\n * guarded against.\n *\n * The leniency rule is the composer's, deliberately: an event with no\n * `targetId` is for everyone (a single-chat app never sets one), and a chat we\n * cannot identify accepts everything rather than becoming deaf. Only a\n * MISMATCH is ignored.\n */\n private _onTurnEnd = (e: Event): void => {\n const evtTargetId = (e as CustomEvent).detail?.targetId as string | undefined;\n const own = this._pendingTargetId();\n if (evtTargetId && own && evtTargetId !== own) return;\n this._cancelPending();\n };\n\n connectedCallback(): void {\n this.style.display = 'none';\n // Become the presenter for this instance's config (or the global one).\n resolveConfig(this).setElicitationPresenter(this._present);\n // Safety net: if the turn is stopped/errored while a request is open,\n // resolve it as cancelled so the client loop unblocks and the composer\n // input is restored.\n window.addEventListener('aparte-message-aborted', this._onTurnEnd);\n window.addEventListener('aparte-message-error', this._onTurnEnd);\n }\n\n /**\n * The boundary above us appeared, changed, or went away — move the\n * registration with it.\n *\n * `connectedCallback` alone is not enough and cannot be: registering is a\n * WRITE, and under all four wrappers it happens before `attachConfig` runs, so\n * it lands on the global singleton. `requestUserInput()` then resolves the\n * instance config, finds nothing, and answers the model `cancel` — the model\n * hears the user refuse a question the user never saw.\n *\n * See {@link AparteConfigAware}.\n */\n aparteConfigChanged(next: AparteConfig, previous: AparteConfig): void {\n if (previous.getElicitationPresenter() === this._present) previous.setElicitationPresenter(null);\n next.setElicitationPresenter(this._present);\n }\n\n disconnectedCallback(): void {\n const cfg = resolveConfig(this);\n if (cfg.getElicitationPresenter() === this._present) cfg.setElicitationPresenter(null);\n window.removeEventListener('aparte-message-aborted', this._onTurnEnd);\n window.removeEventListener('aparte-message-error', this._onTurnEnd);\n this._cancelPending();\n }\n\n private _present: AparteElicitationPresenter = (request: AparteElicitationRequest) => {\n // One request at a time — a concurrent request is declined rather than\n // clobbering the open panel.\n if (this._pending) return Promise.resolve<AparteElicitationResult>({ action: 'cancel' });\n const composer = this._getComposer();\n if (!composer) return Promise.resolve<AparteElicitationResult>({ action: 'cancel' });\n\n return new Promise<AparteElicitationResult>((resolve) => {\n let done = false;\n const settle = (result: AparteElicitationResult): void => {\n if (done) return;\n done = true;\n this._pending = null;\n composer.hidePanel();\n resolve(result);\n };\n\n // Caller-side cancellation (tool handler signal: timeout / turn abort).\n if (request.signal) {\n if (request.signal.aborted) { settle({ action: 'cancel' }); return; }\n request.signal.addEventListener('abort', () => settle({ action: 'cancel' }), { once: true });\n }\n\n // Built INSIDE this instance's config, so the panel's own strings come\n // from the locale of the chat that asked — `contextConfig()` reads the\n // ambient render config, and without this it would fall back to the\n // global one on a page where each chat has its own.\n const cfg = resolveConfig(this);\n const panel: BuiltElicitationPanel = runWithConfig(cfg, () =>\n buildElicitationPanel(request.message, request.schema, () => {\n composer.setPanelSubmitEnabled(panel.canProceed(), panel.mode());\n }));\n\n // \"Skip\" → decline (MCP's decline: the user chose not to answer), in the\n // panel's CORNER. It sat beside the button that advances through the form,\n // and that adjacency read as \"skip this question\" while it declines the\n // whole request — see `dismiss` on BuiltElicitationPanel.\n const skip = document.createElement('button');\n skip.type = 'button';\n skip.className = 'aparte-elic-skip';\n skip.textContent = cfg.t('elicitationSkip');\n skip.addEventListener('click', () => settle({ action: 'decline' }));\n panel.dismiss.appendChild(skip);\n\n this._pending = { settle, composer };\n composer.showPanel(panel.el, {\n submitEnabled: panel.canProceed(),\n mode: panel.mode(),\n onSubmit: () => {\n // The same button advances through the form and submits at the end;\n // the panel is what knows which of the two this click is.\n if (panel.mode() === 'advance') {\n panel.proceed();\n composer.setPanelSubmitEnabled(panel.canProceed(), panel.mode());\n return;\n }\n if (panel.isComplete()) settle({ action: 'accept', content: panel.getContent() });\n },\n });\n panel.focus();\n });\n };\n\n private _cancelPending(): void {\n this._pending?.settle({ action: 'cancel' });\n }\n\n /**\n * The host id of the chat whose composer holds the open panel.\n *\n * Walks up from the composer rather than from `this`, because the panel lives in\n * the composer and that is what the turn belongs to. Matches the hosts\n * `aparte-chat-bubble._resolveTargetId()` matches, for the reason written there:\n * Angular's wrapper root IS the `<aparte-chat>` element, while the plain-root\n * wrappers render a `[data-aparte-chat]` div instead, so matching only the tag\n * resolves `undefined` on three wrappers out of four.\n */\n private _pendingTargetId(): string | undefined {\n let el: HTMLElement | null = this._pending?.composer ?? null;\n while (el) {\n const tag = el.tagName?.toLowerCase();\n const isHost = tag === 'aparte-chat' || tag === 'aparte-chat-component' || el.hasAttribute?.('data-aparte-chat');\n if (isHost && el.id) return el.id;\n el = el.parentElement;\n }\n return undefined;\n }\n\n /**\n * The composer to present in: the nearest one in an ancestor subtree, and\n * nothing else.\n *\n * There used to be a `document.querySelector('aparte-composer')` fallback, which\n * is the \"first chat on the page\" bug this repo has now fixed in four other\n * places: on a page with two chats, an elicitation that could not find its own\n * composer mounted its panel in the OTHER chat's — so one conversation's question\n * appeared under the other conversation, and answering it resolved a tool call\n * belonging to a chat the user was not looking at.\n *\n * Returning `null` instead resolves `cancel`, which is honest: nothing was\n * shown, so nothing was answered. The warning names the fix, because this is a\n * setup mistake and only the developer can correct it — the guide's own example\n * puts `<aparte-elicitation>` inside `<aparte-chat>`.\n */\n private _getComposer(): ComposerEl | null {\n let node: Element | null = this.parentElement;\n while (node) {\n const composer = node.querySelector('aparte-composer') as ComposerEl | null;\n if (composer && typeof composer.showPanel === 'function') return composer;\n // Stop AT the chat boundary. Removing the explicit\n // `document.querySelector` fallback was not enough on its own: this walk\n // reached `<body>`, and a `querySelector` from there searches the whole\n // document — so it found another chat's composer anyway, by a longer\n // route. The two-chat test caught exactly that.\n const tag = node.tagName?.toLowerCase();\n const isChatBoundary = tag === 'aparte-chat' || tag === 'aparte-chat-component' || node.hasAttribute?.('data-aparte-chat');\n if (isChatBoundary) break;\n node = node.parentElement;\n }\n console.warn(\n '[aparte-elicitation] No <aparte-composer> in this element\\'s subtree, so the request '\n + 'was cancelled — the model will read that as a refusal. Move <aparte-elicitation> '\n + 'inside the <aparte-chat> it belongs to. It is deliberately NOT borrowing another '\n + 'chat\\'s composer: on a page with two chats that put the question under the wrong one.',\n );\n return null;\n }\n}\n\nif (typeof customElements !== 'undefined' && !customElements.get('aparte-elicitation')) {\n customElements.define('aparte-elicitation', AparteElicitation);\n}\n","/**\n * Aparte\n * High-performance AI conversation engine in Vanilla TypeScript\n * Zero-dependency Web Components for LLM streaming\n *\n * ⚠️ This is the **browser** entry: it defines the custom elements and imports CSS\n * at module scope, so it needs a DOM. **Node resolves `index.node.ts` instead**\n * (via the `node` condition in package.json) — a DOM-free entry with the client,\n * host, transports, the chat handler and every type. This file sits first in the\n * exports map only because of the repo-local `@aparte-workspace/source` condition,\n * which is why reading it can look like \"this package can't run in Node\".\n * See the \"Node / SSR\" section of the README.\n *\n * @packageDocumentation\n */\nimport './styles/aparte.css';\nimport './primitives/select/select.css';\nimport './primitives/progress-spinner/progress-spinner.css';\n\n// Global HTMLElementEventMap augmentation — typed `e.detail` for aparté events.\nimport './types/event-map.js';\n// Global HTMLElementTagNameMap augmentation — `querySelector('aparte-…')` returns\n// the concrete element, not `Element`. Both are DOM-only, hence browser-entry only.\nimport './types/element-map.js';\n\n// Export primitives\nexport { AparteSelect, AparteOption, AparteOptgroup, type AparteSelectChangeDetail, type AparteOptgroupToggleEventDetail, AparteProgressSpinner } from './primitives/index.js';\n\n// Export types\nexport type {\n AparteBubbleRole,\n AparteMessage,\n AparteContentParser,\n AparteSendEventDetail,\n AparteViewportConfig,\n AparteInputConfig,\n AparteThemeVariables,\n AparteStatus,\n AparteAttachment,\n AparteMessageBranch,\n AparteBubbleActionsConfig,\n AparteBubbleActionName,\n AparteSegment,\n AparteSegmentType,\n AparteTextSegment,\n AparteThinkingSegment,\n AparteCodeSegment,\n AparteTerminalSegment,\n AparteSegmentRenderer,\n AparteCustomSegment,\n AparteToolCallSegment,\n AparteArtifactSegment,\n // The detail of the `aparte-segment-update` event. It reached types/index.ts and\n // stopped there — and types/index.ts is not an entry point, so a consumer could\n // bind the event (it is in the published event table) and never name its detail.\n AparteSegmentUpdateEventDetail,\n // AI Provider types (BYORK)\n AparteAIProvider,\n AparteAIModel,\n AparteAIProviderConfigField,\n AparteAIProviderConfigSchema,\n AparteModelConfig,\n ModelStatus,\n ModelLoadProgress,\n AparteModelChangeEventDetail,\n AparteMessageDoneEventDetail,\n AparteMessageStartEventDetail,\n AparteMessageErrorEventDetail,\n AparteMessageAbortedEventDetail,\n AparteAbortEventDetail,\n AparteCompactEventDetail,\n AparteCompactDoneEventDetail,\n AparteCompactErrorEventDetail,\n AparteAttachmentPreviewEventDetail,\n AparteTerminalRunEventDetail,\n AparteFileGenReadyEventDetail,\n AparteFileGenErrorEventDetail,\n AparteMessageInfoEventDetail,\n AparteSiblingInfo,\n AparteBranchNavigateEventDetail,\n ApartePathChangedEventDetail,\n AparteRetryEventDetail,\n AparteEditEventDetail,\n AparteFeedbackEventDetail,\n AparteActionEventDetail,\n AparteArtifactStartEventDetail,\n AparteArtifactDeltaEventDetail,\n AparteArtifactReadyEventDetail,\n AparteArtifactRedownloadEventDetail,\n // Chat types\n AparteChatRequest,\n AparteChatResponse,\n AparteChatMessage,\n AparteContentPart,\n AparteTextPart,\n AparteImagePart,\n AparteFilePart,\n AparteStreamEvent,\n AparteStreamEventMap,\n AparteUsage,\n // Tool types\n AparteTool,\n AparteToolCall,\n AparteToolResult,\n AparteToolHandler,\n AparteToolContext,\n AparteToolRenderer,\n AparteToolDecisionDetail,\n AparteToolApprovalRequestDetail,\n // Canonical imperative surface (aliased by every wrapper's handle type).\n AparteChatImperativeApi\n} from './types/index.js';\n\nexport { AparteErrorCode, AparteError, contentToText } from './types/index.js';\n\n// Export renderers\nexport {\n registerSegmentRenderer,\n unregisterSegmentRenderer,\n getSegmentRenderer,\n collectRendererStyles,\n registerDefaultRenderers,\n // The three the public barrel left behind. `renderers/index.ts` has always\n // exported all eight; this one published five, which made the registry\n // half-public: `declineDefaultRenderers` is the ONLY way to say \"do not install\n // the built-ins on this config\" without constructing an `AparteClient`\n // (`autoRegister: false`), and the bring-your-own-loop guide tells you not to\n // construct one. `installDefaultRenderersOnce` is what a hand-written bubble\n // needs, and `getAllRenderers` is the introspection half — the same reason\n // `hasHighlightProvider` and `renderMarkdown` are public.\n installDefaultRenderersOnce,\n declineDefaultRenderers,\n getAllRenderers\n} from './renderers/index.js';\n\n// Export components\nexport { AparteChat } from './components/index.js';\nexport { AparteChatBubble, populateBubbleFromMessage } from './components/index.js';\nexport type { SyncableBubble } from './components/index.js';\nexport { AparteChatStatus } from './components/index.js';\nexport { AparteChatViewport } from './components/index.js';\n\n// Export composer primitives\nexport { AparteComposer, AparteComposerInput, AparteComposerSend, AparteComposerCancel, AparteComposerAttachments, AparteComposerAddAttachment, AparteComposerAction, AparteComposerToolbar } from './components/index.js';\nexport type { AparteComposerEventMap, AparteComposerEventType, AparteComposerState, AparteComposerChangeEventDetail, AparteActionClickEventDetail } from './components/index.js';\n\n// Export conversation list primitive\nexport { AparteConversationList } from './components/index.js';\nexport type { AparteConversationListItem, AparteConversationSelectDetail, AparteConversationDeleteDetail, AparteConversationArchiveDetail } from './components/index.js';\n\n// Export conversations (types, adapter contract, manager)\nexport type {\n AparteConversation,\n AparteConversationMeta,\n AparteStorageAdapter,\n AparteMemoryFact,\n AparteArtifactRow,\n AparteAttachmentRow,\n} from './conversations/index.js';\nexport { APARTE_CONVERSATION_SCHEMA_VERSION } from './conversations/index.js';\nexport { AparteConversationManager, type ConversationManagerOptions } from './conversations/index.js';\nexport {\n AparteConversationController,\n type AparteChatBinding,\n type AparteConversationControllerOptions,\n} from './conversations/index.js';\n\n// Export the framework-agnostic chat-host orchestrator (streaming/branch/\n// host-method layer that every framework wrapper binds to).\nexport {\n AparteChatHost,\n type AparteChatHostBinding,\n type AparteChatHostOptions,\n} from './host/index.js';\n\n// Export parsers\nexport { AparteStreamParser, parseMarkdownToSegments, deriveArtifactKind } from './parsers/index.js';\nexport type { AparteStreamParserOptions, AparteThinkingDelimiterPair, AparteParserState, AparteParserResult } from './parsers/index.js';\nexport { parseAparteEventStream } from './parsers/index.js';\n\n// Export config\nexport { aparteGlobalConfig, AparteConfig, APARTE_DEFAULT_BUBBLE_ACTIONS, APARTE_DEFAULT_HOST_HANDLERS } from './config/index.js';\nexport type { AparteConfigChangeEventDetail } from './config/index.js';\nexport { resolveConfig, attachConfig, detachConfig, runWithConfig, contextConfig, APARTE_HOST_ATTR } from './config/index.js';\nexport type { AparteConfigAware } from './config/index.js';\nexport type { AparteMarkdownProvider, AparteStreamingMarkdownProvider, AparteStreamingMarkdownRenderer, AparteHighlightProvider, AparteSystemPromptVarsProvider, AparteSkeletonProvider, AparteSkeletonType, AparteLocale, AparteAction, AparteActionZone, AparteIconProvider, AparteIconName, AparteAvatarProvider, AparteStatusRenderer, AparteErrorRenderer, AparteAttachmentRenderer, AparteElicitationFieldRenderer, AparteElicitationFieldContext, AparteElicitationFieldControl, AparteSiblingNavRenderer, AparteBubbleShellRenderer, AparteModelPreference, AparteModelPreferenceProvider, AparteArtifactPreviewBuilder, AparteSanitizer } from './config/index.js';\nexport { APARTE_DEFAULT_ICON_FALLBACKS, APARTE_DEFAULT_SKELETON_FALLBACKS, APARTE_DEFAULT_LOCALE, defaultSanitizer, isSafeUrl } from './config/index.js';\n\n// Export Client\nexport { AparteClient } from './client/aparte-client.js';\n\n// Custom-element interop helpers shared by the framework wrappers' AparteUi.\nexport { applyElementProps, APARTE_DEFAULT_UI_EVENTS } from './interop/element-props.js';\n// Turns the `File[]` an `aparte-send` carries into renderable attachments — the\n// same conversion ConversationController does, for consumers driving the\n// imperative API themselves.\nexport { filesToAttachments, revokeAttachmentUrls } from './utils/files-to-attachments.js';\n// Is a message waiting for a reply? Shared by the viewport, the four wrappers and\n// any consumer rendering its own bubble — one rule, so they can't disagree.\nexport { isAwaitingReply } from './utils/is-awaiting-reply.js';\n\n// HTML escaping — one implementation for the whole scope. Exported because the\n// plugins render their own HTML (they cannot reach into core's internals) and\n// because a consumer writing a render hook needs it for exactly the same reason.\n// Nine private copies existed before this line; three of them had drifted to\n// escape only four of the five characters that matter.\nexport { escapeHtml, escapeAttr } from './utils/escape.js';\n// `cssEscape` belongs beside them: `pnpm check:attr-escaping` tells a renderer\n// author \"in a selector, use cssEscape()\", and the customization guide says the\n// same — while it was not exported at all, so the only way to follow that advice\n// was `CSS.escape`, which over-escapes inside a quoted attribute selector.\nexport { cssEscape } from './utils/css-escape.js';\n// Exported because the same wall is hit outside core: a wrapper naming its host\n// element, a provider tagging a request, or any bring-your-own-loop consumer\n// generating message ids all reach for `crypto.randomUUID`, which does not exist\n// on `http://` — the LAN deployment this library's own audience runs.\nexport { uuid } from './utils/uuid.js';\n// A segment's own completion rule. Exported because a consumer rendering \"thought\n// for 8 s\" from `startedAt`/`endedAt` needs to know when the span closed, and a\n// rule kept private is a rule re-derived slightly differently outside — the tool\n// call is the trap: it settles by `status`, never by `isStreaming`. The stamping\n// functions beside it stay internal: only the two owners of a message's segment\n// array may write those fields.\nexport { isSegmentSettled, segmentDuration } from './utils/segments.js';\n// The PARAMETER types of two documented setters. They existed and were the declared\n// argument types, but were not exported — so anyone typing a settings layer over\n// `setHostHandlers` / `setKeyProvider` had to re-declare the shape by hand.\nexport type { AparteHostHandlersConfig } from './types/models.js';\nexport type { AparteKeyProvider } from './config/aparte-config.js';\nexport type { AparteClientOptions, AparteToolApprovalResolver, AparteCompactionSelector } from './client/aparte-client.js';\n// Structured-stream adapter — DOM half of the runStreamAgent loop (see stream-adapter.ts).\nexport { createStreamAdapter, readableToAsyncIterable } from './client/stream-adapter.js';\nexport type { AparteStreamRunEvent, AparteStreamRunEmitter, StreamAdapterTarget, CreateStreamAdapterOptions, AparteStreamRunner, AparteStreamRunOptions } from './client/stream-adapter.js';\n\n// Export transport seam (where chat requests go + how auth is handled)\nexport { AparteDirectTransport, AparteBackendTransport, createAparteChatHandler, isFormatAdapter } from './transport/index.js';\nexport type { AparteTransport, AparteTransportContext, AparteFormatAdapter, AparteVendorRequest, BackendTransportOptions, DirectTransportOptions, AparteChatHandlerOptions } from './transport/index.js';\n\n// Export runtime utilities\nexport { AparteMessageRepository } from './runtime/message-repository.js';\nexport type { ExportedMessageRepository } from './runtime/message-repository.js';\n\n// Export elicitation (human-in-the-loop typed input)\nexport { requestUserInput, buildElicitationPanel } from './elicitation/index.js';\nexport type {\n AparteElicitationSchema,\n AparteElicitationField,\n AparteElicitationEnumField,\n AparteElicitationBooleanField,\n AparteElicitationStringField,\n AparteElicitationObjectSchema,\n AparteElicitationRequest,\n AparteElicitationResult,\n AparteElicitationPresenter,\n BuiltElicitationPanel,\n} from './elicitation/index.js';\n\n// Export the default elicitation presenter Web Component\nexport { AparteElicitation } from './components/elicitation/aparte-elicitation.js';\n\n// Auto-register components when module is imported\n// Components register themselves in their files\nimport './components/chat/aparte-chat.js';\nimport './components/bubble/aparte-chat-bubble.js';\nimport './components/status/aparte-chat-status.js';\nimport './components/viewport/aparte-chat-viewport.js';\nimport './components/elicitation/aparte-elicitation.js';\n// Import primitives to auto-register\nimport './primitives/select/aparte-select.js';\nimport './primitives/select/aparte-option.js';\nimport './primitives/select/aparte-optgroup.js';\n\n/**\n * Utility to ensure all components are registered\n * Call this if using dynamic imports\n */\nexport function registerAllComponents(): void {\n // Components self-register, but this ensures imports are not tree-shaken\n const _chat = customElements.get('aparte-chat');\n const _viewport = customElements.get('aparte-chat-viewport');\n const _bubble = customElements.get('aparte-chat-bubble');\n const _status = customElements.get('aparte-chat-status');\n\n if (!_chat || !_viewport || !_bubble || !_status) {\n console.warn('[Aparte] Some components may not be registered. Ensure all component files are imported.');\n }\n}\n"],"names":["n","e","o","s","a","l","x","b","c","m","i","f","h","p","root"],"mappings":"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"}
|
|
1
|
+
{"version":3,"file":"index.js","sources":["../src/primitives/select/aparte-option.ts","../src/primitives/select/aparte-optgroup.ts","../src/primitives/select/aparte-select.ts","../src/primitives/progress-spinner/aparte-progress-spinner.ts","../src/components/elicitation/aparte-elicitation.ts","../src/components/chat/aparte-chat.ts","../src/components/bubble/aparte-chat-bubble.ts","../src/components/status/aparte-chat-status.ts","../src/components/viewport/aparte-chat-viewport.ts","../src/components/composer/aparte-composer.ts","../src/components/composer/aparte-composer-input.ts","../src/components/composer/aparte-composer-send.ts","../src/components/composer/aparte-composer-cancel.ts","../src/components/composer/aparte-composer-attachments.ts","../src/components/composer/aparte-composer-add-attachment.ts","../src/components/composer/aparte-composer-action.ts","../src/components/composer/aparte-composer-toolbar.ts","../src/components/conversation-list/aparte-conversation-list.ts","../src/index.ts"],"sourcesContent":["/**\n * AparteOption\n * \n * Option element for aparte-select dropdown.\n * \n * @element aparte-option\n * @attr {string} value - Option value\n * @attr {boolean} disabled - Disabled state\n * @attr {boolean} selected - Selected state\n * @attr {string} data-status - Free-form status the host sets; styled, never read by core.\n *\n * @example\n * <aparte-select placeholder=\"Pick a model\">\n * <aparte-option value=\"gpt-4o-mini\" selected>GPT-4o mini</aparte-option>\n * <aparte-option value=\"o3\" disabled>o3 (no access)</aparte-option>\n * </aparte-select>\n */\n\nexport class AparteOption extends HTMLElement {\n static get observedAttributes(): string[] {\n return ['value', 'disabled', 'selected', 'data-status'];\n }\n\n connectedCallback(): void {\n this.setAttribute('role', 'option');\n this._updateAriaSelected();\n this._updateStatusDot();\n }\n\n attributeChangedCallback(name: string): void {\n if (name === 'selected') {\n this._updateAriaSelected();\n }\n if (name === 'disabled') {\n this.setAttribute('aria-disabled', this.hasAttribute('disabled') ? 'true' : 'false');\n }\n if (name === 'data-status') {\n this._updateStatusDot();\n }\n }\n\n get value(): string {\n return this.getAttribute('value') || this.textContent?.trim() || '';\n }\n\n set value(val: string) {\n this.setAttribute('value', val);\n }\n\n get label(): string {\n // Use only the first text node, ignoring injected spans (e.g. status dot)\n const textNode = Array.from(this.childNodes).find(n => n.nodeType === Node.TEXT_NODE);\n return textNode?.textContent?.trim() || this.value;\n }\n\n get disabled(): boolean {\n return this.hasAttribute('disabled');\n }\n\n set disabled(val: boolean) {\n if (val) {\n this.setAttribute('disabled', '');\n } else {\n this.removeAttribute('disabled');\n }\n }\n\n get selected(): boolean {\n return this.hasAttribute('selected');\n }\n\n set selected(val: boolean) {\n if (val) {\n this.setAttribute('selected', '');\n } else {\n this.removeAttribute('selected');\n }\n }\n\n private _updateAriaSelected(): void {\n this.setAttribute('aria-selected', this.selected ? 'true' : 'false');\n }\n\n private _updateStatusDot(): void {\n const status = this.getAttribute('data-status');\n let dot = this.querySelector<HTMLSpanElement>('.aparte-status-dot');\n\n if (!status) {\n dot?.remove();\n return;\n }\n\n if (!dot) {\n dot = document.createElement('span');\n dot.className = 'aparte-status-dot';\n dot.setAttribute('aria-hidden', 'true');\n this.appendChild(dot);\n }\n\n dot.setAttribute('data-status', status);\n }\n}\n\n// Register\nif (!customElements.get('aparte-option')) {\n customElements.define('aparte-option', AparteOption);\n}\n","/**\n * AparteOptgroup\n * \n * Option group element for aparte-select dropdown.\n * \n * @element aparte-optgroup\n * @attr {string} label - Group label\n * @attr {boolean} collapsible - Allow collapse/expand\n * @attr {boolean} collapsed - Collapsed state\n * @attr {boolean} loading - Shows a spinner in place of the group's options.\n *\n * @fires {CustomEvent<AparteOptgroupToggleEventDetail>} aparte-optgroup-toggle - The group was collapsed or expanded.\n *\n * @example\n * <!-- Collapsed groups keep a long list readable; the label is the group's header. -->\n * <aparte-select grouped placeholder=\"Pick a model\">\n * <aparte-optgroup label=\"Ollama\" collapsible collapsed>\n * <aparte-option value=\"ollama::llama3\">Llama 3</aparte-option>\n * </aparte-optgroup>\n * <aparte-optgroup label=\"OpenRouter\" collapsible>\n * <aparte-option value=\"openrouter::gpt-4o-mini\">GPT-4o mini</aparte-option>\n * </aparte-optgroup>\n * </aparte-select>\n */\n\nexport class AparteOptgroup extends HTMLElement {\n /** Ids for the label span the group points `aria-labelledby` at. */\n private static _labelIdSeq = 0;\n\n static get observedAttributes(): string[] {\n return ['label', 'collapsible', 'collapsed', 'loading'];\n }\n\n connectedCallback(): void {\n this.setAttribute('role', 'group');\n this._render();\n }\n\n attributeChangedCallback(name: string, oldValue: string | null, newValue: string | null): void {\n if (oldValue === newValue) return;\n\n if (name === 'collapsed') {\n this._updateCollapsedState();\n }\n\n if (this.isConnected) {\n this._render();\n }\n }\n\n get label(): string {\n return this.getAttribute('label') || '';\n }\n\n set label(val: string) {\n this.setAttribute('label', val);\n }\n\n get collapsible(): boolean {\n return this.hasAttribute('collapsible');\n }\n\n get collapsed(): boolean {\n return this.hasAttribute('collapsed');\n }\n\n set collapsed(val: boolean) {\n if (val) {\n this.setAttribute('collapsed', '');\n } else {\n this.removeAttribute('collapsed');\n }\n }\n\n get loading(): boolean {\n return this.hasAttribute('loading');\n }\n\n set loading(val: boolean) {\n if (val) this.setAttribute('loading', '');\n else this.removeAttribute('loading');\n }\n\n private _render(): void {\n // Only render header if we have a label\n if (this.label) {\n const existingHeader = this.querySelector('.aparte-optgroup-header');\n if (!existingHeader) {\n const header = document.createElement('div');\n header.className = 'aparte-optgroup-header';\n // The header stays a GENERIC node on purpose: naming it (it used to\n // carry `aria-label`) makes it a real element inside a `listbox`,\n // where only options and groups may live (axe:\n // aria-required-children, critical). The name belongs on the group,\n // via aria-labelledby below.\n // `label` is an attribute value — with the model-selector it carries a\n // provider-supplied name — so it goes through textContent, never\n // innerHTML (a hostile name would otherwise inject here).\n const labelSpan = document.createElement('span');\n labelSpan.className = 'aparte-optgroup-label';\n labelSpan.id = `aparte-optgroup-label-${++AparteOptgroup._labelIdSeq}`;\n labelSpan.textContent = this.label;\n this.setAttribute('aria-labelledby', labelSpan.id);\n header.appendChild(labelSpan);\n\n if (this.collapsible) {\n const chevron = document.createElement('span');\n chevron.className = 'aparte-optgroup-chevron';\n header.appendChild(chevron);\n header.style.cursor = 'pointer';\n header.addEventListener('click', (e) => {\n e.stopPropagation();\n this._toggleCollapse();\n });\n }\n\n this.insertBefore(header, this.firstChild);\n }\n }\n\n // Update loading state\n this._updateLoadingState();\n\n // Update collapsed state\n this._updateCollapsedState();\n }\n\n private _updateLoadingState(): void {\n let loader = this.querySelector('.aparte-optgroup-loader');\n if (this.loading) {\n if (!loader) {\n loader = document.createElement('div');\n loader.className = 'aparte-optgroup-loader';\n loader.innerHTML = '<span class=\"aparte-spinner-small\"></span> Fetching models...';\n this.appendChild(loader);\n }\n } else if (loader) {\n loader.remove();\n }\n }\n\n private _toggleCollapse(): void {\n this.collapsed = !this.collapsed;\n\n // Dispatch event before updating UI to allow parent to react (e.g. fetch data)\n this.dispatchEvent(new CustomEvent<AparteOptgroupToggleEventDetail>('aparte-optgroup-toggle', {\n bubbles: true,\n composed: true,\n detail: {\n label: this.label,\n collapsed: this.collapsed\n }\n }));\n\n this._updateCollapsedState();\n }\n\n private _updateCollapsedState(): void {\n const options = this.querySelectorAll('aparte-option');\n options.forEach(opt => {\n (opt as HTMLElement).style.display = this.collapsed ? 'none' : '';\n });\n }\n}\n\n// Register\nif (!customElements.get('aparte-optgroup')) {\n customElements.define('aparte-optgroup', AparteOptgroup);\n}\n\n/**\n * Detail payload for `aparte-optgroup-toggle`.\n *\n * Named in `types/event-map.ts` as an internal primitive event \"carrying no\n * cross-package detail contract\". `@aparte/plugin-model-selector` reads both of\n * its fields, from another package, through an untyped cast — and the event is\n * published in the generated CEM event table. It is a contract.\n *\n * @event aparte-optgroup-toggle\n */\nexport interface AparteOptgroupToggleEventDetail {\n /** The group's label. */\n label: string;\n /** `true` when the group just collapsed. */\n collapsed: boolean;\n}\n","import './aparte-option.js';\nimport './aparte-optgroup.js';\n\nexport interface AparteSelectChangeDetail {\n value: string;\n label: string;\n previousValue: string;\n}\n\n/**\n * Dropdown select for aparté — a vanilla web component with optional grouping, a\n * search filter and a keyboard-driven listbox.\n *\n * The tags above used to live in a docblock at the top of this file, separated from\n * the class by these imports and the interface. TypeScript associates only the\n * comment PHYSICALLY ADJACENT to a declaration, so the analyser never saw them: the\n * manifest still listed six attributes and three events (it reads\n * `observedAttributes` and `this.dispatchEvent` structurally) but with every\n * description dropped, and the generated CSS-of-record for this element read blank.\n *\n * @element aparte-select\n * @attr {string} value - The selected option's value.\n * @attr {string} placeholder - Shown while nothing is selected.\n * @attr {boolean} disabled - Blocks opening and selection.\n * @attr {boolean} grouped - Renders `<aparte-optgroup>` children as collapsible groups.\n * @attr {boolean} searchable - Adds a filter field above the options.\n * @attr {boolean} open - Reflects (and controls) whether the dropdown is open.\n *\n * @fires {CustomEvent<AparteSelectChangeDetail>} aparte-select-change - The selection changed; carries the new value, its label and the previous value.\n * @fires aparte-select-open - The dropdown opened. No detail.\n * @fires aparte-select-close - The dropdown closed. No detail.\n *\n * @example\n * <aparte-select placeholder=\"Pick a model\" searchable value=\"gpt-4o-mini\">\n * <aparte-option value=\"gpt-4o-mini\">GPT-4o mini</aparte-option>\n * <aparte-option value=\"llama-3.1-8b\">Llama 3.1 8B</aparte-option>\n * </aparte-select>\n *\n * <script>\n * document.querySelector('aparte-select').addEventListener('aparte-select-change', (e) => {\n * console.log(e.detail.value, e.detail.label, e.detail.previousValue);\n * });\n * </script>\n */\nexport class AparteSelect extends HTMLElement {\n private static _optIdSeq = 0;\n /** Fallback ids for the listbox `aria-controls` target when the host has no id. */\n private static _listboxSeq = 0;\n\n private _value = '';\n private _isOpen = false;\n private _activeIndex = -1;\n private _trigger: HTMLElement | null = null;\n private _dropdown: HTMLElement | null = null;\n private _searchInput: HTMLInputElement | null = null;\n private _observer: MutationObserver | null = null;\n\n // Bound handlers for cleanup\n /**\n * Bound, like its two neighbours below — because an inline arrow on `this` can\n * never be removed.\n *\n * `_setupEventListeners()` runs on EVERY `connectedCallback`, and `_render()`'s\n * idempotency guard means the host element survives a re-connect. So each move\n * of the element (a portal, a Vue teleport, any framework re-parent) added\n * another option-click listener: measured, one click fired the change handler\n * FIVE times after five re-connects. `disconnectedCallback` removed the two\n * document-level handlers and could not touch this one.\n *\n * This is verbatim the bug class `aparte-chat-viewport` documents having fixed\n * for its own listeners; a repo sweep found this as the last inline-arrow\n * listener on a persistent node.\n */\n private _boundHandleOptionClick = this._handleOptionClick.bind(this);\n private _boundHandleDocumentClick = this._handleDocumentClick.bind(this);\n private _boundHandleKeydown = this._handleKeydown.bind(this);\n\n static get observedAttributes(): string[] {\n return ['value', 'placeholder', 'disabled', 'grouped', 'searchable', 'open'];\n }\n\n connectedCallback(): void {\n this._value = this.getAttribute('value') || '';\n this._isOpen = this.hasAttribute('open');\n this._render();\n this._setupEventListeners();\n this._setupMutationObserver();\n }\n\n disconnectedCallback(): void {\n this.removeEventListener('click', this._boundHandleOptionClick);\n document.removeEventListener('click', this._boundHandleDocumentClick);\n document.removeEventListener('keydown', this._boundHandleKeydown);\n this._observer?.disconnect();\n }\n\n attributeChangedCallback(name: string, oldValue: string, newValue: string): void {\n if (!this.isConnected) return;\n\n if (name === 'value' && oldValue !== newValue && newValue !== this._value) {\n this._value = newValue || '';\n this._updateTriggerLabel();\n }\n if (name === 'open') {\n this._isOpen = this.hasAttribute('open');\n if (this._isOpen) {\n this._dropdown?.removeAttribute('hidden');\n this._searchInput?.focus();\n } else {\n this._dropdown?.setAttribute('hidden', '');\n }\n }\n }\n\n // ─────────────────────────────────────────────────────────────────────────\n // Public API\n // ─────────────────────────────────────────────────────────────────────────\n\n get value(): string {\n return this._value;\n }\n\n set value(val: string) {\n if (val === this._value) return;\n const previousValue = this._value;\n this._value = val;\n this.setAttribute('value', val);\n this._updateTriggerLabel();\n this._emitChange(previousValue);\n }\n\n get open(): boolean {\n return this._isOpen;\n }\n\n set open(val: boolean) {\n if (val) {\n this.setAttribute('open', '');\n } else {\n this.removeAttribute('open');\n }\n }\n\n // ─────────────────────────────────────────────────────────────────────────\n // Rendering\n // ─────────────────────────────────────────────────────────────────────────\n\n private _render(): void {\n const placeholder = this.getAttribute('placeholder') || 'Select...';\n const searchable = this.hasAttribute('searchable');\n\n // Check if already rendered (has dropdown structure)\n if (this.querySelector('.aparte-select-dropdown')) {\n this._updateTriggerLabel();\n return;\n }\n\n // First render: capture any slotted children before modifying DOM\n const slottedChildren = Array.from(this.children);\n\n // Create wrapper structure\n const trigger = document.createElement('div');\n trigger.className = 'aparte-select-trigger';\n trigger.setAttribute('tabindex', '0');\n trigger.setAttribute('role', 'combobox');\n trigger.setAttribute('aria-haspopup', 'listbox');\n trigger.setAttribute('aria-expanded', 'false');\n // Accessible name (axe aria-input-field-name): the visible label span is\n // the combobox VALUE, not its name — name it from the host's aria-label\n // when provided, else the placeholder (\"Select model…\" etc.).\n trigger.setAttribute('aria-label', this.getAttribute('aria-label') || placeholder);\n // The label is placeholder text (consumer/attribute-supplied) → textContent,\n // same path as _updateTriggerLabel(), never innerHTML. Only the static SVG\n // chevron uses innerHTML.\n const labelSpan = document.createElement('span');\n labelSpan.className = 'aparte-select-label';\n labelSpan.textContent = placeholder;\n const chevronSpan = document.createElement('span');\n chevronSpan.className = 'aparte-select-chevron';\n chevronSpan.innerHTML = `<svg width=\"12\" height=\"12\" viewBox=\"0 0 12 12\" fill=\"currentColor\"><path d=\"M2.5 4.5L6 8L9.5 4.5\" stroke=\"currentColor\" stroke-width=\"1.5\" fill=\"none\" stroke-linecap=\"round\"/></svg>`;\n trigger.append(labelSpan, chevronSpan);\n\n // The dropdown is a plain shell: it also holds the search field, and a\n // `listbox` may only contain options/groups (axe: aria-required-children,\n // critical). The listbox lives on the options container below.\n const dropdown = document.createElement('div');\n dropdown.className = 'aparte-select-dropdown';\n dropdown.hidden = !this._isOpen;\n\n if (searchable) {\n const searchInput = document.createElement('input');\n searchInput.type = 'text';\n searchInput.className = 'aparte-select-search';\n searchInput.placeholder = 'Search...';\n searchInput.setAttribute('aria-label', 'Search options');\n dropdown.appendChild(searchInput);\n }\n\n const optionsContainer = document.createElement('div');\n optionsContainer.className = 'aparte-select-options';\n optionsContainer.setAttribute('role', 'listbox');\n // A listbox is an ARIA input field, so it needs its own name; reuse the\n // combobox's (axe: aria-input-field-name).\n optionsContainer.setAttribute('aria-label', trigger.getAttribute('aria-label') ?? placeholder);\n // `role=\"combobox\"` REQUIRES aria-controls (axe: aria-required-attr).\n optionsContainer.id = this.id ? `${this.id}-listbox` : `aparte-listbox-${++AparteSelect._listboxSeq}`;\n trigger.setAttribute('aria-controls', optionsContainer.id);\n\n // Move slotted children (aparte-option, aparte-optgroup) into options container\n slottedChildren.forEach(child => {\n if (child.tagName === 'APARTE-OPTION' || child.tagName === 'APARTE-OPTGROUP') {\n optionsContainer.appendChild(child);\n }\n });\n\n dropdown.appendChild(optionsContainer);\n\n // Clear and rebuild DOM\n this._observer?.disconnect();\n this.innerHTML = '';\n this.appendChild(trigger);\n this.appendChild(dropdown);\n\n this._trigger = trigger;\n this._dropdown = dropdown;\n this._searchInput = dropdown.querySelector('.aparte-select-search');\n\n if (this.isConnected) {\n this._setupMutationObserver();\n }\n\n // Update label based on current value\n this._updateTriggerLabel();\n }\n\n private _setupMutationObserver(): void {\n this._observer = new MutationObserver(() => {\n this._updateDropdownContent();\n // The options may have just been replaced under an open dropdown —\n // re-assert the keyboard position on the NEW elements. See\n // {@link _restoreActive}.\n this._restoreActive();\n });\n\n // `subtree` matters: a consumer refreshing a live list writes into\n // `.aparte-select-options` (the model selector does exactly that when the\n // provider list settles), which is a DESCENDANT. Watching only our own\n // children missed it entirely — the highlight vanished with the removed\n // elements and nothing here noticed. Our own writes disconnect the observer\n // first, so this cannot loop.\n this._observer.observe(this, { childList: true, subtree: true });\n }\n\n /**\n * Put the roving highlight back after the options changed underneath it.\n *\n * `data-active` lives on an option ELEMENT, so replacing the list throws it\n * away while `_activeIndex` still claims a position: the highlight disappeared,\n * `aria-activedescendant` kept pointing at an id no longer in the document, and\n * the next ArrowDown moved from the stale index — skipping an option. Only when\n * open and only when a position was held, so a refresh never invents one.\n */\n private _restoreActive(): void {\n if (!this._isOpen || this._activeIndex < 0) return;\n if (this.querySelector('aparte-option[data-active]')) return;\n this._setActive(this._activeIndex);\n }\n\n private _updateDropdownContent(): void {\n // If trigger is gone, the component was likely wiped by innerHTML\n if (!this._trigger || !this.contains(this._trigger)) {\n this._render();\n return;\n }\n\n const optionsContainer = this.querySelector('.aparte-select-options');\n if (!optionsContainer) {\n // If internal UI is present but container is gone\n this._render();\n return;\n }\n\n // Collect all potential options from light DOM\n // (those aren't internal UI elements)\n const lightChildren = Array.from(this.children).filter(child =>\n child.className !== 'aparte-select-trigger' &&\n child.className !== 'aparte-select-dropdown'\n );\n\n if (lightChildren.length === 0) return;\n\n // Pause observer to prevent self-triggering loop\n this._observer?.disconnect();\n\n // Clear container (but keep internal stuff if any)\n optionsContainer.innerHTML = '';\n\n // Move/Append children to container\n lightChildren.forEach(child => {\n optionsContainer.appendChild(child);\n });\n\n // Resume observer\n if (this.isConnected) {\n this._observer?.observe(this, { childList: true, subtree: true });\n }\n\n this._updateTriggerLabel();\n this._restoreActive();\n }\n\n private _setupEventListeners(): void {\n // Trigger click\n this._trigger?.addEventListener('click', () => this._toggle());\n\n // Trigger keyboard\n this._trigger?.addEventListener('keydown', (e) => {\n if (e.key === 'Enter' || e.key === ' ') {\n // When open, Enter/Space selects the active option — handled by\n // the document-level nav handler. Only toggle when closed, so we\n // don't close the dropdown on the very keystroke meant to select.\n if (this._isOpen) return;\n e.preventDefault();\n this._toggle();\n }\n if (e.key === 'ArrowDown' && !this._isOpen) {\n e.preventDefault();\n this._openDropdown();\n }\n });\n\n // Option selection. Removed first: `_setupEventListeners` runs on every\n // connect, and adding the same bound reference twice is a no-op per spec —\n // but being explicit costs nothing and survives a future refactor that\n // rebinds.\n this.removeEventListener('click', this._boundHandleOptionClick);\n this.addEventListener('click', this._boundHandleOptionClick);\n\n // Search filter\n this._searchInput?.addEventListener('input', (e) => {\n const query = (e.target as HTMLInputElement).value.toLowerCase();\n this._filterOptions(query);\n });\n\n // Close on outside click\n document.addEventListener('click', this._boundHandleDocumentClick);\n\n // Keyboard navigation\n document.addEventListener('keydown', this._boundHandleKeydown);\n }\n\n private _handleOptionClick(e: Event): void {\n const option = (e.target as HTMLElement).closest('aparte-option');\n if (option && !option.hasAttribute('disabled')) {\n this._selectOption(option as HTMLElement);\n }\n }\n\n private _handleDocumentClick(e: Event): void {\n if (!this.contains(e.target as Node)) {\n this._closeDropdown();\n }\n }\n\n private _handleKeydown(e: KeyboardEvent): void {\n if (!this._isOpen) return;\n\n // Home/End move the caret when typing in the search box; only hijack\n // them for option navigation when focus is not in the search field.\n const inSearch = document.activeElement === this._searchInput;\n\n switch (e.key) {\n case 'Escape':\n e.preventDefault();\n this._closeDropdown();\n this._trigger?.focus();\n break;\n case 'ArrowDown':\n e.preventDefault();\n this._moveActive(1);\n break;\n case 'ArrowUp':\n e.preventDefault();\n this._moveActive(-1);\n break;\n case 'Home':\n if (inSearch) break;\n e.preventDefault();\n this._setActive(0);\n break;\n case 'End':\n if (inSearch) break;\n e.preventDefault();\n this._setActive(this._visibleOptions().length - 1);\n break;\n case 'Enter': {\n const active = this._visibleOptions()[this._activeIndex];\n if (active) {\n e.preventDefault();\n this._selectOption(active);\n }\n break;\n }\n }\n }\n\n /** Non-disabled, non-filtered options in DOM order. */\n private _visibleOptions(): HTMLElement[] {\n return Array.from(this.querySelectorAll<HTMLElement>('aparte-option')).filter(\n opt => !opt.hasAttribute('disabled') && opt.style.display !== 'none',\n );\n }\n\n /** Move the active (keyboard-highlighted) option by `delta`, clamped. */\n private _moveActive(delta: number): void {\n const opts = this._visibleOptions();\n if (opts.length === 0) return;\n const base = this._activeIndex < 0 ? (delta > 0 ? -1 : 0) : this._activeIndex;\n this._setActive(base + delta);\n }\n\n /** Highlight the option at `index` (clamped) and point aria-activedescendant at it. */\n private _setActive(index: number): void {\n const all = this.querySelectorAll<HTMLElement>('aparte-option');\n all.forEach(o => o.removeAttribute('data-active'));\n\n const opts = this._visibleOptions();\n if (opts.length === 0) {\n this._activeIndex = -1;\n this._trigger?.removeAttribute('aria-activedescendant');\n return;\n }\n const clamped = Math.max(0, Math.min(index, opts.length - 1));\n this._activeIndex = clamped;\n\n const active = opts[clamped]!;\n if (!active.id) active.id = `aparte-option-${++AparteSelect._optIdSeq}`;\n active.setAttribute('data-active', '');\n this._trigger?.setAttribute('aria-activedescendant', active.id);\n active.scrollIntoView?.({ block: 'nearest' });\n }\n\n /** Clear the keyboard highlight (on close). */\n private _clearActive(): void {\n this._activeIndex = -1;\n this._trigger?.removeAttribute('aria-activedescendant');\n this.querySelectorAll('aparte-option').forEach(o => o.removeAttribute('data-active'));\n }\n\n // ─────────────────────────────────────────────────────────────────────────\n // Actions\n // ─────────────────────────────────────────────────────────────────────────\n\n private _toggle(): void {\n if (this._isOpen) {\n this._closeDropdown();\n } else {\n this._openDropdown();\n }\n }\n\n private _openDropdown(): void {\n if (this.hasAttribute('disabled')) return;\n\n this._isOpen = true;\n this._dropdown?.removeAttribute('hidden');\n this._trigger?.setAttribute('aria-expanded', 'true');\n this.setAttribute('open', '');\n\n // Smart Positioning\n this._updatePosition();\n\n // Focus search if available\n this._searchInput?.focus();\n\n // Seed the keyboard highlight on the current selection (or the first\n // option) so ArrowUp/Down have an anchor and screen readers announce it.\n const opts = this._visibleOptions();\n const selectedIdx = opts.findIndex(o => o.getAttribute('value') === this._value);\n this._setActive(selectedIdx >= 0 ? selectedIdx : 0);\n\n this.dispatchEvent(new CustomEvent('aparte-select-open', { bubbles: true }));\n }\n\n private _closeDropdown(): void {\n this._isOpen = false;\n this._clearActive();\n this._dropdown?.setAttribute('hidden', '');\n this._trigger?.setAttribute('aria-expanded', 'false');\n this.removeAttribute('open');\n this.removeAttribute('position'); // Reset position attribute\n\n // Clear position styles set by _updatePosition\n if (this._dropdown) {\n this._dropdown.style.top = '';\n this._dropdown.style.bottom = '';\n this._dropdown.style.left = '';\n this._dropdown.style.width = '';\n }\n\n // Clear search\n if (this._searchInput) {\n this._searchInput.value = '';\n this._filterOptions('');\n }\n\n this.dispatchEvent(new CustomEvent('aparte-select-close', { bubbles: true }));\n }\n\n private _updatePosition(): void {\n if (!this._dropdown || !this._trigger) return;\n\n const rect = this._trigger.getBoundingClientRect();\n const dropdownHeight = this._dropdown.offsetHeight || 300;\n const viewportHeight = window.innerHeight;\n const spaceBelow = viewportHeight - rect.bottom;\n const GAP = 4; // px gap between trigger and dropdown\n\n // Always size to trigger width\n this._dropdown.style.left = `${rect.left}px`;\n this._dropdown.style.width = `${rect.width}px`;\n\n // Decide whether to open upward or downward\n if (spaceBelow < dropdownHeight && rect.top > dropdownHeight) {\n // Open upward\n this._dropdown.style.top = '';\n this._dropdown.style.bottom = `${viewportHeight - rect.top + GAP}px`;\n this.setAttribute('position', 'top');\n } else {\n // Open downward\n this._dropdown.style.top = `${rect.bottom + GAP}px`;\n this._dropdown.style.bottom = '';\n this.removeAttribute('position');\n }\n }\n\n private _selectOption(option: HTMLElement): void {\n const value = option.getAttribute('value') || option.textContent?.trim() || '';\n const previousValue = this._value;\n\n this._value = value;\n this.setAttribute('value', value);\n this._updateTriggerLabel();\n this._closeDropdown();\n this._emitChange(previousValue);\n this._trigger?.focus();\n }\n\n private _updateTriggerLabel(): void {\n const labelEl = this._trigger?.querySelector('.aparte-select-label');\n if (labelEl) {\n const selectedLabel = this._getSelectedLabel();\n labelEl.textContent = selectedLabel || this.getAttribute('placeholder') || 'Select...';\n }\n\n // Update selected state on options\n const options = this.querySelectorAll('aparte-option');\n options.forEach(opt => {\n const isSelected = opt.getAttribute('value') === this._value;\n if (isSelected) {\n opt.setAttribute('selected', '');\n } else {\n opt.removeAttribute('selected');\n }\n });\n }\n\n private _getSelectedLabel(): string {\n // Match by property, not an interpolated attribute selector — a value with\n // `\"`/`]` (e.g. a remote model id) would make querySelector throw SyntaxError.\n for (const opt of this.querySelectorAll('aparte-option')) {\n if (opt.getAttribute('value') === this._value) return opt.textContent?.trim() || '';\n }\n return '';\n }\n\n private _filterOptions(query: string): void {\n const options = this.querySelectorAll('aparte-option');\n options.forEach(opt => {\n const label = opt.textContent?.toLowerCase() || '';\n const matches = label.includes(query);\n (opt as HTMLElement).style.display = matches ? '' : 'none';\n });\n // Re-anchor the keyboard highlight on the first still-visible option.\n if (this._isOpen) this._setActive(0);\n }\n\n private _emitChange(previousValue: string): void {\n const detail: AparteSelectChangeDetail = {\n value: this._value,\n label: this._getSelectedLabel(),\n previousValue\n };\n\n this.dispatchEvent(new CustomEvent<AparteSelectChangeDetail>('aparte-select-change', {\n bubbles: true,\n composed: true,\n detail\n }));\n }\n}\n\n// Register\nif (!customElements.get('aparte-select')) {\n customElements.define('aparte-select', AparteSelect);\n}\n","/**\n * AparteProgressSpinner\n *\n * Circular progress spinner web component.\n * - Indeterminate (no `value` attribute): continuous rotation animation\n * - Determinate (`value=\"0–100\"`): fills the arc proportionally\n *\n * @element aparte-progress-spinner\n * @attr {number} value - Progress percentage 0–100 (omit for indeterminate)\n *\n * @cssvar --aparte-spinner-size Size of the spinner. Default: 14px\n * @cssvar --aparte-spinner-stroke Stroke width in SVG units. Default: 2.5\n * @cssvar --aparte-spinner-color Fill arc stroke color. Default: currentColor\n * @cssvar --aparte-spinner-track Track arc stroke color. Default: 15% currentColor\n *\n * @example\n * <!-- Omit `value` for the indeterminate spin; set it to show real progress. -->\n * <aparte-progress-spinner></aparte-progress-spinner>\n * <aparte-progress-spinner value=\"62\"></aparte-progress-spinner>\n */\nexport class AparteProgressSpinner extends HTMLElement {\n static get observedAttributes(): string[] { return ['value']; }\n\n /** Radius of the SVG circle (viewBox is 0 0 24 24, center at 12,12) */\n private readonly _r = 9;\n private get _circ(): number { return 2 * Math.PI * this._r; }\n\n connectedCallback(): void { this._render(); }\n attributeChangedCallback(): void { this._render(); }\n\n private _render(): void {\n const raw = this.getAttribute('value');\n const value = raw !== null\n ? Math.min(100, Math.max(0, parseFloat(raw) || 0))\n : null;\n\n this.setAttribute('role', 'progressbar');\n this.setAttribute('aria-valuemin', '0');\n this.setAttribute('aria-valuemax', '100');\n if (value !== null) {\n this.setAttribute('aria-valuenow', String(value));\n } else {\n this.removeAttribute('aria-valuenow');\n }\n\n // Determinate: dashoffset shrinks from circ→0 as value goes 0→100\n const dashoffset = value !== null ? this._circ * (1 - value / 100) : 0;\n // Indeterminate: fixed partial arc (~72% of circumference)\n const dasharray = value !== null\n ? `${this._circ.toFixed(2)}`\n : `${(this._circ * 0.72).toFixed(2)} ${(this._circ * 0.28).toFixed(2)}`;\n\n this.innerHTML = `<svg viewBox=\"0 0 24 24\" xmlns=\"http://www.w3.org/2000/svg\" aria-hidden=\"true\"><circle class=\"aparte-spinner-track\" cx=\"12\" cy=\"12\" r=\"${this._r}\"/><circle class=\"aparte-spinner-fill\" cx=\"12\" cy=\"12\" r=\"${this._r}\" stroke-dasharray=\"${dasharray}\" stroke-dashoffset=\"${dashoffset.toFixed(2)}\"/></svg>`;\n }\n}\n\nif (!customElements.get('aparte-progress-spinner')) {\n customElements.define('aparte-progress-spinner', AparteProgressSpinner);\n}\n","/**\n * <aparte-elicitation> — the default elicitation presenter.\n *\n * Registers itself as the presenter for the config governing its subtree\n * (`resolveConfig(this)`), so `requestUserInput()` from a tool handler is routed\n * here WITHOUT any window events — the typed presenter contract replaces the\n * stringly-typed `aparte-ask-user-*` events that drifted in Phase 1.\n *\n * On a request it builds the schema-appropriate panel (enum / boolean / string /\n * object) and mounts it inside the nearest `<aparte-composer>` via its\n * `showPanel` API, resolving:\n * - accept — the send button (panel submit), when all fields are complete\n * - decline — the inline \"Skip\" affordance\n * - cancel — the assistant turn was stopped/errored while pending\n *\n * Its CSS ships in `@aparte/core/styles.css` like every other component — it used\n * to inject its own <style> from here, which made it the one surface that could not\n * be themed and whose variables were missing from the generated CSS reference.\n *\n * Place anywhere inside the chat (it renders nothing itself):\n * <aparte-elicitation></aparte-elicitation>\n */\n\nimport { resolveConfig, runWithConfig, type AparteConfigAware } from '../../config/config-context.js';\nimport { subscribeConfigChange } from '../../config/config-subscribe.js';\nimport type { AparteConfig } from '../../config/aparte-config.js';\nimport type { AparteComposer } from '../composer/aparte-composer.js';\nimport { buildElicitationPanel, type BuiltElicitationPanel } from '../../elicitation/panel.js';\nimport { buildApprovalPanel } from '../../elicitation/approval-panel.js';\nimport type { AparteElicitationRequest, AparteElicitationResult, AparteElicitationPresenter } from '../../elicitation/types.js';\nimport { AparteElicitationAbortError } from '../../elicitation/types.js';\n\n/**\n * The slice of the composer this presenter drives.\n *\n * DERIVED from the component rather than re-typed by hand. It used to be a literal\n * copy of the three signatures, which is a twin: adding a parameter to the real\n * `setPanelSubmitEnabled` left this one behind, and the compiler pointed at the\n * CALLER instead of the stale declaration. `import type` is erased, so nothing here\n * pulls the composer element into a runtime import — which is why the copy existed.\n */\ntype ComposerEl = HTMLElement & Pick<AparteComposer, 'showPanel' | 'hidePanel' | 'setPanelSubmitEnabled'>;\n\ninterface Pending {\n /** End the request without an answer — see `AparteElicitationAbortError`. */\n abort(): void;\n composer: ComposerEl;\n /**\n * Re-apply every string this request took from the locale, in place.\n *\n * ONE function, where this used to hold the panel and the skip button separately\n * so the component could relabel each. That only worked because there was one kind\n * of panel; an approval's strings live elsewhere, and a second field per kind is\n * how the two would drift.\n */\n relabel(): void;\n}\n\n/**\n * The default presenter for a request to the human. It renders nothing itself: it\n * registers as the presenter for the config governing its subtree, and mounts a panel\n * inside the nearest `<aparte-composer>` when something asks — a tool handler calling\n * `requestUserInput`, or core's own approval gate.\n *\n * It dispatches no events on purpose. A request is answered through the typed presenter\n * contract, not by listening for one; the `aparte-tool-decision` event this replaced\n * existed only because the buttons used to live in a segment renderer with no reference\n * to the client.\n *\n * @element aparte-elicitation\n *\n * @example\n * <!-- Renders nothing by itself: it registers as the presenter for its subtree, so a\n * tool handler calling requestUserInput() gets its panel mounted in the composer. -->\n * <aparte-chat>\n * <aparte-chat-viewport></aparte-chat-viewport>\n * <aparte-elicitation></aparte-elicitation>\n * <aparte-composer>\n * <div class=\"aparte-composer-row\">\n * <aparte-composer-input style=\"flex: 1\"></aparte-composer-input>\n * <aparte-composer-send></aparte-composer-send>\n * </div>\n * </aparte-composer>\n * </aparte-chat>\n */\nexport class AparteElicitation extends HTMLElement implements AparteConfigAware {\n private _pending: Pending | null = null;\n /**\n * A turn ended — cancel the open question only if it was OUR turn.\n *\n * These two listeners sit on `window` and had no instance filter at all, so a\n * Stop (or an error) in one chat cancelled the question a DIFFERENT chat was\n * waiting on — and that chat's model was told the user had refused a question\n * the user was still looking at. Same defect as the `compact()` handler that\n * emptied both chats, which its four sibling handlers in `AparteClient` already\n * guarded against.\n *\n * The leniency rule is the composer's, deliberately: an event with no\n * `targetId` is for everyone (a single-chat app never sets one), and a chat we\n * cannot identify accepts everything rather than becoming deaf. Only a\n * MISMATCH is ignored.\n */\n private _onTurnEnd = (e: Event): void => {\n const evtTargetId = (e as CustomEvent).detail?.targetId as string | undefined;\n const own = this._pendingTargetId();\n if (evtTargetId && own && evtTargetId !== own) return;\n this._cancelPending();\n };\n\n private _unsubscribeConfig: (() => void) | null = null;\n\n connectedCallback(): void {\n this.style.display = 'none';\n // A language switch while a question is OPEN. Every other live-config\n // consumer in core got this seam; the panel could not use it because it kept\n // no reference to itself — see `Pending.panel`.\n this._unsubscribeConfig = subscribeConfigChange(this, () => this._relabelPending());\n // Become the presenter for this instance's config (or the global one).\n resolveConfig(this).setElicitationPresenter(this._present);\n // Safety net: if the turn is stopped/errored while a request is open,\n // resolve it as cancelled so the client loop unblocks and the composer\n // input is restored.\n window.addEventListener('aparte-message-aborted', this._onTurnEnd);\n window.addEventListener('aparte-message-error', this._onTurnEnd);\n }\n\n /**\n * The boundary above us appeared, changed, or went away — move the\n * registration with it.\n *\n * `connectedCallback` alone is not enough and cannot be: registering is a\n * WRITE, and under all four wrappers it happens before `attachConfig` runs, so\n * it lands on the global singleton. `requestUserInput()` then resolves the\n * instance config, finds nothing, and answers the model `cancel` — the model\n * hears the user refuse a question the user never saw.\n *\n * See {@link AparteConfigAware}.\n */\n aparteConfigChanged(next: AparteConfig, previous: AparteConfig): void {\n if (previous.getElicitationPresenter() === this._present) previous.setElicitationPresenter(null);\n next.setElicitationPresenter(this._present);\n }\n\n disconnectedCallback(): void {\n const cfg = resolveConfig(this);\n if (cfg.getElicitationPresenter() === this._present) cfg.setElicitationPresenter(null);\n window.removeEventListener('aparte-message-aborted', this._onTurnEnd);\n window.removeEventListener('aparte-message-error', this._onTurnEnd);\n this._unsubscribeConfig?.();\n this._unsubscribeConfig = null;\n this._cancelPending();\n }\n\n /**\n * Re-apply the open question's strings, in place.\n *\n * Two owners, and both have to move or the panel goes bilingual: the panel's own\n * defaults (`relabel`), and the Skip button, which this file builds and this file\n * therefore has to re-text. The composer's one button is a third, and it already\n * follows — `aparte-composer-send` remembers the panel state it was given.\n */\n private _relabelPending(): void {\n if (!this._pending) return;\n const cfg = resolveConfig(this);\n runWithConfig(cfg, () => this._pending!.relabel());\n }\n\n private _present: AparteElicitationPresenter = (request: AparteElicitationRequest) => {\n /*\n * No concurrency guard here any more — `AparteConfig.requestUserInput` queues,\n * so a second request arrives only once this one has settled.\n *\n * What was here answered the second request `cancel` immediately: a refusal\n * invented for a question nobody was shown. And it protected only requests\n * that came through THIS presenter, so a consumer's own presenter had nothing.\n * If two ever do overlap, `showPanel` now evicts and NOTIFIES the first, which\n * degrades to a settled request instead of a wedged one.\n */\n const composer = this._getComposer();\n // Mounted outside a chat that has a composer: there is nowhere to put the\n // panel, which is the same situation as no presenter at all.\n if (!composer) return Promise.reject(new AparteElicitationAbortError('no-presenter'));\n\n return new Promise<AparteElicitationResult>((resolve, reject) => {\n let done = false;\n /**\n * The slot this request owns, once `showPanel` has handed it over.\n *\n * `settle` can run BEFORE that — an already-aborted signal settles on the\n * spot — so it starts absent, and `hidePanel(undefined)` then closes whatever\n * is there, which is correct because nothing of ours is open yet.\n *\n * A holder rather than a `let`: `settle` reads it before `showPanel` assigns\n * it, which is exactly the shape `prefer-const` rejects, and the object says\n * \"not handed over yet\" more plainly than an unassigned binding.\n */\n const slot: { token?: symbol } = {};\n const close = (): boolean => {\n if (done) return false;\n done = true;\n this._pending = null;\n // Scoped to our own panel: finishing late must not tear down the panel\n // that replaced ours.\n composer.hidePanel(slot.token);\n return true;\n };\n const settle = (result: AparteElicitationResult): void => {\n if (close()) resolve(result);\n };\n /**\n * End it without an answer.\n *\n * A rejection rather than a third `action`, because a value is easy to\n * mistake for an answer and this one was: the approval gate read the old\n * `cancel` as a refusal and told the model the user had refused a tool they\n * had only stopped.\n */\n const fail = (reason: 'aborted' | 'no-presenter' = 'aborted'): void => {\n if (close()) reject(new AparteElicitationAbortError(reason));\n };\n\n // Caller-side cancellation (tool handler signal: timeout / turn abort).\n if (request.signal) {\n if (request.signal.aborted) { fail(); return; }\n request.signal.addEventListener('abort', () => fail(), { once: true });\n }\n\n // Built INSIDE this instance's config, so the panel's own strings come\n // from the locale of the chat that asked — `contextConfig()` reads the\n // ambient render config, and without this it would fall back to the\n // global one on a page where each chat has its own.\n const cfg = resolveConfig(this);\n\n /*\n * An APPROVAL: a decision, not a value.\n *\n * Same slot, same queue, same teardown — only what goes inside the panel\n * differs, which is the whole claim of one mechanism with two\n * presentations. The options come with the request because only the\n * requester can write them.\n *\n * There is always an exit here without touching the composer's own\n * controls: every option is a button. That matters because a panel takes\n * the send button over, so Stop is unreachable while one is open — for a\n * question the escape is the corner, for an approval it is a refusal.\n */\n if (request.kind === 'approval') {\n const panel = runWithConfig(cfg, () =>\n buildApprovalPanel(request.message, request.options ?? [], () => {\n composer.setPanelSubmitEnabled(panel.isComplete(), 'submit');\n }));\n panel.onSettle((answer) => settle({ action: 'accept', content: answer }));\n this._pending = { abort: () => fail(), composer, relabel: () => panel.relabel() };\n slot.token = composer.showPanel(panel.el, {\n submitEnabled: panel.isComplete(),\n mode: 'submit',\n // The composer's button carries the INSTRUCTION, which is written\n // text — exactly the act that button already means. The options\n // never route through it: a decision is its own click.\n onSubmit: () => { if (panel.isComplete()) settle({ action: 'accept', content: panel.getContent() }); },\n onEvict: () => fail(),\n });\n panel.focus();\n return;\n }\n // A question without a schema has nothing to collect; that is an approval,\n // and it was handled above. The fallback keeps this branch total rather\n // than throwing on a shape the type already forbids.\n const schema = request.schema ?? { type: 'string' as const };\n const panel: BuiltElicitationPanel = runWithConfig(cfg, () =>\n buildElicitationPanel(request.message, schema, () => {\n composer.setPanelSubmitEnabled(panel.canProceed(), panel.mode());\n }));\n\n // \"Skip\" → decline (MCP's decline: the user chose not to answer), in the\n // panel's CORNER. It sat beside the button that advances through the form,\n // and that adjacency read as \"skip this question\" while it declines the\n // whole request — see `dismiss` on BuiltElicitationPanel.\n const skip = document.createElement('button');\n skip.type = 'button';\n skip.className = 'aparte-elic-skip';\n skip.textContent = cfg.t('elicitationSkip');\n skip.addEventListener('click', () => settle({ action: 'decline' }));\n panel.dismiss.appendChild(skip);\n\n this._pending = {\n abort: () => fail(),\n composer,\n relabel: () => { panel.relabel(); skip.textContent = resolveConfig(this).t('elicitationSkip'); },\n };\n slot.token = composer.showPanel(panel.el, {\n submitEnabled: panel.canProceed(),\n mode: panel.mode(),\n /*\n * Something else took the slot — another request, a conversation switch,\n * or a turn ending. The composer tears the panel down either way; only\n * this callback can settle the promise, and without it the request hung\n * AND `_pending` stayed set, so every later question was short-circuited\n * for the life of the page. `cancel`, not `decline`: nobody declined\n * anything, the question was taken away.\n */\n onEvict: () => fail(),\n onSubmit: () => {\n // The same button advances through the form and submits at the end;\n // the panel is what knows which of the two this click is.\n if (panel.mode() === 'advance') {\n panel.proceed();\n composer.setPanelSubmitEnabled(panel.canProceed(), panel.mode());\n return;\n }\n if (panel.isComplete()) settle({ action: 'accept', content: panel.getContent() });\n },\n });\n panel.focus();\n });\n };\n\n private _cancelPending(): void {\n this._pending?.abort();\n }\n\n /**\n * The host id of the chat whose composer holds the open panel.\n *\n * Walks up from the composer rather than from `this`, because the panel lives in\n * the composer and that is what the turn belongs to. Matches the hosts\n * `aparte-chat-bubble._resolveTargetId()` matches, for the reason written there:\n * Angular's wrapper root IS the `<aparte-chat>` element, while the plain-root\n * wrappers render a `[data-aparte-chat]` div instead, so matching only the tag\n * resolves `undefined` on three wrappers out of four.\n */\n private _pendingTargetId(): string | undefined {\n let el: HTMLElement | null = this._pending?.composer ?? null;\n while (el) {\n const tag = el.tagName?.toLowerCase();\n const isHost = tag === 'aparte-chat' || tag === 'aparte-chat-component' || el.hasAttribute?.('data-aparte-chat');\n if (isHost && el.id) return el.id;\n el = el.parentElement;\n }\n return undefined;\n }\n\n /**\n * The composer to present in: the nearest one in an ancestor subtree, and\n * nothing else.\n *\n * There used to be a `document.querySelector('aparte-composer')` fallback, which\n * is the \"first chat on the page\" bug this repo has now fixed in four other\n * places: on a page with two chats, an elicitation that could not find its own\n * composer mounted its panel in the OTHER chat's — so one conversation's question\n * appeared under the other conversation, and answering it resolved a tool call\n * belonging to a chat the user was not looking at.\n *\n * Returning `null` instead resolves `cancel`, which is honest: nothing was\n * shown, so nothing was answered. The warning names the fix, because this is a\n * setup mistake and only the developer can correct it — the guide's own example\n * puts `<aparte-elicitation>` inside `<aparte-chat>`.\n */\n private _getComposer(): ComposerEl | null {\n let node: Element | null = this.parentElement;\n while (node) {\n const composer = node.querySelector('aparte-composer') as ComposerEl | null;\n if (composer && typeof composer.showPanel === 'function') return composer;\n // Stop AT the chat boundary. Removing the explicit\n // `document.querySelector` fallback was not enough on its own: this walk\n // reached `<body>`, and a `querySelector` from there searches the whole\n // document — so it found another chat's composer anyway, by a longer\n // route. The two-chat test caught exactly that.\n const tag = node.tagName?.toLowerCase();\n const isChatBoundary = tag === 'aparte-chat' || tag === 'aparte-chat-component' || node.hasAttribute?.('data-aparte-chat');\n if (isChatBoundary) break;\n node = node.parentElement;\n }\n console.warn(\n '[aparte-elicitation] No <aparte-composer> in this element\\'s subtree, so the request '\n + 'was cancelled — the model will read that as a refusal. Move <aparte-elicitation> '\n + 'inside the <aparte-chat> it belongs to. It is deliberately NOT borrowing another '\n + 'chat\\'s composer: on a page with two chats that put the question under the wrong one.',\n );\n return null;\n }\n}\n\nif (typeof customElements !== 'undefined' && !customElements.get('aparte-elicitation')) {\n customElements.define('aparte-elicitation', AparteElicitation);\n}\n","import type { AparteChatViewport } from '../viewport/aparte-chat-viewport.js';\nimport type { AparteComposer } from '../composer/aparte-composer.js';\n// Defines <aparte-elicitation>, which the default composition below writes. A tag\n// nothing has defined is an inert unknown element, so the import is the difference\n// between a presenter and a placeholder.\nimport '../elicitation/aparte-elicitation.js';\nimport { escapeAttr } from '../../utils/escape.js';\n\n/**\n * AparteChat - The Shell\n *\n * The container element for a chat. Wrap a `<aparte-chat-viewport>` and a\n * `<aparte-composer>` in it and it lays them out as a flex column — the viewport\n * grows and scrolls, the composer sits below. Provide your own children for full\n * control (custom composer, extra buttons), or leave it empty and it fills in a\n * sensible default composition. Uses Light DOM for global CSS styling.\n *\n * Being a component (not a bare `<div>`), it also owns behaviour a wrapper div\n * can't: with `center-empty`, it watches its own viewport and keeps the composer\n * centered as a welcome state until the first message, then slides to the normal\n * layout — no external JavaScript.\n *\n * Presentational only: it does NOT wire a transport/client. Attach an\n * `AparteClient`, or handle `aparte-send` yourself, as with the primitives.\n * Size the element via CSS (a height, or let it fill a sized parent).\n *\n * @element aparte-chat\n * @attr {string} placeholder - Placeholder for the composer input (default composition)\n * @attr {boolean} disabled - Disables the composer\n * @attr {boolean} center-empty - Center the composer as a welcome state until the first message, then slide to the normal layout\n * @attr {boolean} framework-managed - The wrapper's explicit hands-off signal: set it and this\n * element composes none of its own children, because the framework owns them. All four\n * wrappers set it; it was read by this element and declared by nothing until now.\n * @attr {boolean} attachments - Add the file picker + chips strip to the default composition (opt-in: the host must consume the files — an `AparteClient` does, a hand-rolled loop must read `event.detail.files`)\n *\n * @example\n * <!-- Left empty it fills in a viewport, an input and a send button. -->\n * <aparte-chat center-empty placeholder=\"Say something…\" style=\"height: 600px\"></aparte-chat>\n *\n * <!-- Or compose it yourself; the container still lays it out and runs center-empty. -->\n * <aparte-chat center-empty attachments style=\"height: 600px\">\n * <aparte-chat-viewport></aparte-chat-viewport>\n * <aparte-composer>\n * <div class=\"aparte-composer-shell\">\n * <div class=\"aparte-composer-row\">\n * <aparte-composer-input style=\"flex: 1\"></aparte-composer-input>\n * <aparte-composer-send></aparte-composer-send>\n * </div>\n * </div>\n * </aparte-composer>\n * </aparte-chat>\n */\nexport class AparteChat extends HTMLElement {\n static get observedAttributes(): string[] {\n return ['placeholder', 'disabled', 'center-empty', 'attachments'];\n }\n\n private _observer: MutationObserver | null = null;\n\n /**\n * True only for the composition THIS element injected. An author-provided\n * composer (or a `framework-managed` host) is never edited by the attachments\n * toggle below — those own their own markup.\n */\n private _ownsShell = false;\n\n connectedCallback(): void {\n this._render();\n this._forwardAttr('placeholder');\n this._forwardAttr('disabled');\n this._syncEmptyWatch();\n }\n\n disconnectedCallback(): void {\n this._observer?.disconnect();\n this._observer = null;\n }\n\n attributeChangedCallback(name: string, oldValue: string | null, newValue: string | null): void {\n if (oldValue === newValue) return;\n if (name === 'center-empty') {\n this._syncEmptyWatch();\n return;\n }\n if (name === 'attachments') {\n this._syncAttachments();\n return;\n }\n // placeholder / disabled forward to the inner composer. An explicit removal\n // mirrors through; a never-set attribute is left alone (so a caller-provided\n // composer keeps its own).\n const composer = this.querySelector('aparte-composer');\n if (!composer) return;\n if (newValue !== null) composer.setAttribute(name, newValue);\n else composer.removeAttribute(name);\n }\n\n /** The message viewport (yours or the default), or `null` before connect. */\n get viewport(): AparteChatViewport | null {\n return this.querySelector('aparte-chat-viewport');\n }\n\n /** The composer (yours or the default), or `null` before connect. */\n get composer(): AparteComposer | null {\n return this.querySelector('aparte-composer');\n }\n\n private _render(): void {\n // A framework wrapper renders the composition itself — and its children do not\n // exist yet when this runs (the element is upgraded on insert, before the\n // framework's template renders), so the viewport check below can't see them.\n // `framework-managed` is the wrapper's explicit \"hands off\" signal: without it\n // the default composition below would be injected UNDER the framework's own.\n if (this.hasAttribute('framework-managed')) return;\n\n // Author-provided composition wins — if a viewport is already inside, use the\n // children as given and only lay them out (via CSS). Otherwise fill in a\n // default viewport + composer so the empty tag \"just works\".\n if (this.querySelector('aparte-chat-viewport')) return;\n\n // The composer's `placeholder` is read by its input via `closest()` at upgrade\n // time (no event), so it must be on the element in the initial markup.\n const placeholder = this.getAttribute('placeholder');\n const composerAttrs =\n (placeholder !== null ? ` placeholder=\"${escapeAttr(placeholder)}\"` : '') +\n (this.hasAttribute('disabled') ? ' disabled' : '');\n\n // Attachments are opt-in: the picker only makes sense when the host consumes\n // the files (an `AparteClient` inlines them per `rawFileInject`; a hand-rolled\n // loop must read `event.detail.files`). Offering it unconditionally would show\n // a button that silently drops what the user attached.\n const attachments = this.hasAttribute('attachments');\n\n /*\n * The presenter ships in the default composition, and that is a change of tier.\n *\n * It renders nothing by itself — it registers as the presenter for this subtree and\n * mounts a panel in the composer when something asks. It used to be opt-in, which\n * was right while asking the user was a plugin's business. It is not any more: the\n * BUILT-IN approval gate asks through it, so a chat without one cannot honour\n * `needsApproval` at all. An affordance core can honour end to end is on by default\n * (ratified decision #8, tier a); leaving this out would have made the gate depend\n * on a tag nobody was told to write.\n */\n this.innerHTML = `\n <aparte-chat-viewport></aparte-chat-viewport>\n <aparte-elicitation></aparte-elicitation>\n <aparte-composer${composerAttrs}>\n <div class=\"aparte-composer-shell\">\n ${attachments ? '<aparte-composer-attachments></aparte-composer-attachments>' : ''}\n <div class=\"aparte-composer-row\">\n ${attachments ? '<aparte-composer-add-attachment></aparte-composer-add-attachment>' : ''}\n <aparte-composer-input></aparte-composer-input>\n <aparte-composer-send></aparte-composer-send>\n </div>\n </div>\n </aparte-composer>\n `;\n this._ownsShell = true;\n }\n\n /**\n * Add/remove the two attachment primitives on the composition we injected, so\n * toggling the attribute after mount works like the wrappers' reactive prop\n * (there, a re-render does it). Author-provided markup is left alone.\n */\n private _syncAttachments(): void {\n if (!this._ownsShell) return;\n const composer = this.composer;\n const shell = composer?.querySelector('.aparte-composer-shell');\n const row = shell?.querySelector('.aparte-composer-row');\n if (!composer || !shell || !row) return;\n\n const strip = shell.querySelector('aparte-composer-attachments');\n const picker = row.querySelector('aparte-composer-add-attachment');\n\n if (this.hasAttribute('attachments')) {\n if (!strip) shell.insertBefore(document.createElement('aparte-composer-attachments'), row);\n if (!picker) row.insertBefore(document.createElement('aparte-composer-add-attachment'), row.firstChild);\n return;\n }\n\n strip?.remove();\n picker?.remove();\n // Files picked before the capability was withdrawn would otherwise ride on\n // the next send with nothing in the UI showing them.\n composer.clearAttachments();\n }\n\n /** Set an attribute on the inner composer only when the shell carries it. */\n private _forwardAttr(name: string): void {\n if (!this.hasAttribute(name)) return;\n this.querySelector('aparte-composer')?.setAttribute(name, this.getAttribute(name) ?? '');\n }\n\n /** Start/stop watching the viewport so `center-empty` toggles itself. */\n private _syncEmptyWatch(): void {\n this._observer?.disconnect();\n this._observer = null;\n\n if (!this.hasAttribute('center-empty')) {\n this.removeAttribute('data-empty');\n return;\n }\n\n const viewport = this.querySelector('aparte-chat-viewport');\n if (!viewport) return;\n\n this._updateEmpty();\n // A message is an <aparte-chat-bubble>; watch the viewport for the first one.\n this._observer = new MutationObserver(() => this._updateEmpty());\n this._observer.observe(viewport, { childList: true, subtree: true });\n }\n\n private _updateEmpty(): void {\n const viewport = this.querySelector('aparte-chat-viewport');\n const empty = !viewport || !viewport.querySelector('aparte-chat-bubble');\n this.toggleAttribute('data-empty', empty);\n }\n\n}\n\n// Register the custom element\nif (!customElements.get('aparte-chat')) {\n customElements.define('aparte-chat', AparteChat);\n}\n","import type {\n AparteBubbleRole,\n AparteSegment,\n AparteAttachment,\n AparteBranchNavigateEventDetail,\n AparteRetryEventDetail,\n AparteEditEventDetail,\n AparteFeedbackEventDetail,\n AparteActionEventDetail,\n AparteMessageInfoEventDetail,\n AparteUsage,\n AparteMessage,\n} from '../../types/index.js';\nimport { getSegmentRenderer, installDefaultRenderersOnce } from '../../renderers/index.js';\nimport { AparteConfig } from '../../config/aparte-config.js';\nimport { resolveConfig, runWithConfig } from '../../config/config-context.js';\nimport { cssEscape } from '../../utils/css-escape.js';\nimport { mergeSegmentUpdate } from '../../utils/segments.js';\nimport type { AparteComposerInput } from '../composer/aparte-composer-input.js';\nimport { escapeAttr, escapeHtml } from '../../utils/escape.js';\n\n/**\n * Warn ONCE when a segment has no renderer — now only for types core has never\n * heard of, since the built-ins install themselves on first use.\n */\nlet _warnedNoRenderer = false;\nfunction warnMissingRenderer(type: string): void {\n if (_warnedNoRenderer) return;\n _warnedNoRenderer = true;\n console.warn(`[aparte] No renderer for segment \"${type}\". Register one with registerSegmentRenderer({ type: '${type}', render }) from @aparte/core — see https://apartejs.dev/guides/customization/#custom-segment-types`);\n}\n\n/**\n * The renderer for `type`, installing core's built-ins the first time a segment\n * finds the registry empty of its type. `registerDefaultRenderers()` therefore\n * becomes optional rather than a call you discover by seeing\n * `[Unknown segment type: text]` on screen (it is still honoured, and\n * `AparteClient({ autoRegister: false })` still keeps the built-ins out).\n */\nfunction resolveSegmentRenderer(\n type: string,\n config: AparteConfig,\n): ReturnType<typeof getSegmentRenderer> {\n // The CONFIG is passed in, not read ambiently.\n //\n // `runWithConfig` wrapped only `render` / `setup` / `update`, so the renderer's\n // OWN work was per-instance while the question \"which renderer is this?\" was\n // answered from a module-level registry. Two chats on a page therefore shared\n // their segment renderers no matter what `config` prop the wrapper was given —\n // half of the promise those props make.\n const renderer = getSegmentRenderer(type, config);\n if (renderer) return renderer;\n installDefaultRenderersOnce(config);\n return getSegmentRenderer(type, config);\n}\n\n/**\n * Normalize a segment renderer's output to a single element. Renderers may return\n * an HTML **string** (parsed via innerHTML — the built-in renderers) or a ready\n * **HTMLElement** (used directly, so custom renderers can wire event listeners /\n * framework nodes with no innerHTML XSS surface). See {@link AparteSegmentRenderer}.\n */\nfunction segmentRenderResultToElement(result: string | HTMLElement): HTMLElement | null {\n if (result instanceof HTMLElement) return result;\n const wrapper = document.createElement('div');\n wrapper.innerHTML = result;\n return wrapper.firstElementChild as HTMLElement | null;\n}\n\n/** Lucide \"info\" glyph — inline so the action bar needs no icon-provider key. */\nconst INFO_ICON_SVG =\n '<svg xmlns=\"http://www.w3.org/2000/svg\" width=\"15\" height=\"15\" viewBox=\"0 0 24 24\" ' +\n 'fill=\"none\" stroke=\"currentColor\" stroke-width=\"2\" stroke-linecap=\"round\" ' +\n 'stroke-linejoin=\"round\"><circle cx=\"12\" cy=\"12\" r=\"10\"/><path d=\"M12 16v-4\"/>' +\n '<path d=\"M12 8h.01\"/></svg>';\n\n/**\n * One message: plain content or a list of rich segments, in light DOM.\n *\n * All seven events are declared by hand rather than left to the analyser, which\n * found six. `aparte-branch-navigate` is dispatched from the `_onBranchPickerClick`\n * arrow class field, and the auto-detection visits `ts.isMethodDeclaration` only —\n * so the one event belonging to the branch picker was the one missing from the\n * manifest, and from the generated reference, for as long as both existed.\n *\n * @element aparte-chat-bubble\n *\n * @attr {string} role - The message role. `data-role` is the styled mirror of it.\n * @attr {string} data-role - `user` / `assistant` / `system`; what the CSS keys off.\n * @attr {string} content - Plain text content, for a bubble with no segments.\n * @attr {number | string} timestamp - Epoch milliseconds OR a date string: `_updateTimestamp` accepts either and only coerces when the value is numeric.\n * @attr {string} message-id - How streaming and the action bar address this bubble.\n * @attr {boolean} streaming - Hides the action bar and shows the caret while a reply is in flight.\n * @attr {string} name - The display name in the header.\n *\n * @fires {CustomEvent<AparteActionEventDetail>} aparte-action - A custom action-bar button was pressed.\n * @fires {CustomEvent<AparteRetryEventDetail>} aparte-retry - Retry was pressed; the host forks the turn.\n * @fires {CustomEvent<AparteEditEventDetail>} aparte-edit - An edit was saved.\n * @fires {CustomEvent<AparteFeedbackEventDetail>} aparte-feedback - Thumbs up or down.\n * @fires {CustomEvent<AparteMessageInfoEventDetail>} aparte-message-info - The info affordance was pressed.\n * @fires {CustomEvent<AparteBranchNavigateEventDetail>} aparte-branch-navigate - The `‹1/2›` picker moved between sibling versions.\n * @fires {CustomEvent<AparteAttachmentPreviewEventDetail>} aparte-attachment-preview - An attached image was clicked, asking the app to open it full-size.\n *\n * @example\n * <!-- Rendered for you by the viewport. Written by hand only when you drive the DOM\n * yourself: `message-id` is what streaming and the action bar address it by. -->\n * <aparte-chat-bubble\n * message-id=\"a1\"\n * data-role=\"assistant\"\n * name=\"Assistant\"\n * content=\"Hello.\"\n * ></aparte-chat-bubble>\n *\n * <!-- While a reply is in flight: `streaming` hides the action bar and shows the caret. -->\n * <aparte-chat-bubble message-id=\"a2\" data-role=\"assistant\" streaming></aparte-chat-bubble>\n */\nexport class AparteChatBubble extends HTMLElement {\n private _contentEl: HTMLDivElement | null = null;\n private _segmentsEl: HTMLDivElement | null = null;\n private _attachmentsEl: HTMLDivElement | null = null;\n private _actionBarEl: HTMLDivElement | null = null;\n private _branchPickerEl: HTMLDivElement | null = null;\n private _footerEl: HTMLDivElement | null = null;\n private _content = '';\n private _streaming = false;\n private _segments: AparteSegment[] = [];\n private _role: AparteBubbleRole = 'assistant';\n private _attachments: AparteAttachment[] = [];\n private _usage: AparteUsage | null = null;\n /** Cleanup returned by the avatar provider — called on disconnect/re-render. */\n private _avatarCleanup: (() => void) | null = null;\n /** Sibling count for tree-based branch navigation (set by setSiblings()) */\n private _siblingCount = 1;\n /** Sibling index for tree-based branch navigation (set by setSiblings()) */\n private _siblingIndex = 0;\n /** True while the user-message inline editor is open. */\n private _editing = false;\n /** The live inline editor (the composer's contenteditable primitive), present only while `_editing`. */\n private _editInput: AparteComposerInput | null = null;\n\n static get observedAttributes(): string[] {\n // Both `data-role` (preferred, set by Angular wrapper) and `role` (legacy\n // / direct usage) feed into the same _role state. The host element gets\n // its own `role=\"article\"` set in _render() for ARIA compliance — that\n // is filtered in attributeChangedCallback so it doesn't loop back as a\n // bubble role of \"article\".\n return ['role', 'data-role', 'content', 'timestamp', 'message-id', 'streaming', 'name'];\n }\n\n constructor() {\n super();\n }\n\n // Rebuild the action bar when the global config changes (e.g. a live skin\n // switch calling setBubbleActions / setIconProvider) so already-rendered\n // bubbles pick up the new per-role actions + icons without being re-created.\n private _onConfigChange = (e: Event): void => {\n // Only rebuild for OUR config. An instance-scoped change on another chat —\n // or a global change while we resolve to an instance — must not touch us.\n // A bare dispatch (no detail.config) always rebuilds (e.g. manual notify).\n const detail = (e as CustomEvent).detail as { config?: unknown } | undefined;\n if (detail?.config && detail.config !== this._cfg) return;\n this._updateActionBar();\n // Everything else the locale writes. A language switch is documented as live\n // (\"mounted components re-render immediately\"), and rebuilding only the action\n // bar delivered half of it: the labels changed language while the NAME still\n // read \"You\" and the branch arrows kept their old `aria-label` — a bilingual\n // bubble, fixed only by a reload (which rebuilds the element).\n this._updateName();\n this._updateLocalizedLabels();\n this._updateWaiting();\n // An avatar provider is config too, and it was the one provider a live change\n // never reached: swap the set and every bubble already on screen kept the old\n // one. `_renderAvatar` tears down the previous mount before re-mounting, so\n // calling it again is safe, and it no-ops when no provider is registered.\n this._renderAvatar();\n this._relabelSegments();\n // The clock, too. A tag change is a formatting change, so the timestamp has to\n // be re-rendered or the language switches around a 12-hour time that stays.\n this._updateTimestamp(this.getAttribute('timestamp'));\n };\n\n /**\n * Ask every rendered segment to re-read its config-derived text.\n *\n * Not `_renderSegments()`, which wipes the container and rebuilds: that destroys a\n * mounted artifact preview, reverts a reasoning block the reader expanded by\n * clicking `<summary>` (the DOM's real state is never written back to `collapsed`),\n * resets scroll inside long terminal panes, drops focus from an Approve/Reject\n * gate, and throws away the incremental Markdown parser's buffered lookahead\n * mid-stream — for a change that added no content. It also fires container-wide\n * childList mutations, which is what the viewport's observer reads as \"scroll to\n * the bottom\".\n *\n * `relabel` is the narrow alternative, bound by the same no-child-node rule as\n * `update()`. A renderer that has no config-derived text does not implement it,\n * and this loop simply skips it.\n */\n private _relabelSegments(): void {\n if (!this._segmentsEl) return;\n for (const segment of this._segments) {\n const renderer = resolveSegmentRenderer(segment.type, this._cfg);\n if (!renderer?.relabel) continue;\n const el = this._segmentsEl.querySelector(\n `:scope > [data-segment-id=\"${cssEscape(segment.id)}\"]`,\n ) as HTMLElement | null;\n if (!el) continue;\n runWithConfig(this._cfg, () => renderer.relabel!(el, segment));\n }\n }\n\n /**\n * Re-apply the locale strings written straight into the markup by `_render()` —\n * the accessible names a screen reader reads, which nothing else refreshes.\n */\n private _updateLocalizedLabels(): void {\n const locale = this._cfg.getLocale();\n const set = (selector: string, label: string): void => {\n this.querySelector(selector)?.setAttribute('aria-label', label);\n };\n set('.aparte-branch-prev', locale.previousResponse ?? 'Previous response');\n set('.aparte-branch-next', locale.nextResponse ?? 'Next response');\n set('.aparte-action-bar', locale.messageActions ?? 'Message actions');\n }\n\n /**\n * Config governing this bubble: the instance config of the nearest\n * `[data-aparte-host]` boundary, else the global singleton. Resolved live\n * (a single `closest()`) rather than cached — the boundary may be attached\n * AFTER this bubble mounts (AparteChatHost.bind() runs post-mount), so a\n * connect-time cache would freeze the wrong config.\n */\n private get _cfg(): AparteConfig {\n return resolveConfig(this);\n }\n\n connectedCallback(): void {\n this._render();\n this._updateContent();\n // Populate the timestamp from the current attribute. Frameworks that set\n // attributes BEFORE the element is connected (e.g. the Svelte wrapper) fire\n // attributeChangedCallback while _render() hasn't created `.aparte-timestamp`\n // yet, so the initial time would otherwise stay blank. No-ops when the\n // attribute is absent (set later → attributeChangedCallback handles it).\n this._updateTimestamp(this.getAttribute('timestamp'));\n window.addEventListener('aparte-config-change', this._onConfigChange);\n // Delegated, so a re-render cannot lose a click on the branch arrows.\n this.addEventListener('click', this._onBranchPickerClick);\n }\n\n disconnectedCallback(): void {\n window.removeEventListener('aparte-config-change', this._onConfigChange);\n this.removeEventListener('click', this._onBranchPickerClick);\n if (this._avatarCleanup) {\n try { this._avatarCleanup(); } catch { /* ignore */ }\n this._avatarCleanup = null;\n }\n }\n\n attributeChangedCallback(name: string, oldValue: string | null, newValue: string | null): void {\n if (oldValue === newValue) return;\n\n switch (name) {\n case 'role':\n case 'data-role':\n // Skip the ARIA-compliance value we set ourselves in _render().\n // Real bubble roles are 'user' or 'assistant'; anything else is\n // either the 'article' we wrote for accessibility or stale.\n if (newValue === 'article') return;\n if (newValue === 'user' || newValue === 'assistant') {\n this._role = newValue as AparteBubbleRole;\n this._updateRole();\n }\n break;\n case 'content':\n this._content = newValue || '';\n this._updateContent();\n break;\n case 'timestamp':\n this._updateTimestamp(newValue);\n break;\n case 'streaming':\n this._updateStreaming(newValue !== null && newValue !== 'false');\n break;\n case 'name':\n this._updateName();\n break;\n }\n }\n\n // ─────────────────────────────────────────────────────────────────────────\n // Public API\n // ─────────────────────────────────────────────────────────────────────────\n\n /** Append a token chunk (for streaming) */\n appendToken(chunk: string): void {\n this._content += chunk;\n this._updateContent();\n }\n\n /** Set content directly */\n setContent(content: string): void {\n this._content = content;\n this.setAttribute('content', content);\n this._updateContent();\n }\n\n /** Get current content */\n getContent(): string {\n return this._content;\n }\n\n /** Set segments for rich content */\n setSegments(segments: AparteSegment[]): void {\n /*\n * Copy the array IN, the way `getSegments()` already copies it OUT.\n *\n * That asymmetry was the bug: the bubble defended its list on the way out and\n * adopted the caller's on the way in. `populateBubbleFromMessage` hands over\n * `message.segments` — the repository's own array — so the bubble and the model\n * ended up advancing ONE array. `appendToSegment` then wrote each chunk twice:\n * the viewport replaced the slot with `{...segment, content: old + chunk}`, the\n * bubble looked the segment up in what it thought was its own list, found that\n * replacement (chunk already in it) and appended the chunk again. Measured:\n * \"ThatThat deletesdeletes aa filefile\".\n *\n * This is the same failure 3b026bb fixed for `addSegment` — where it does not\n * happen, because the bubble pushes into a list it created itself, so the\n * viewport's replacement decouples the two immediately. A message arriving with\n * its segments already populated went around that fix, exactly as `AparteClient`\n * went around the one before it. One copy here closes the last shared array:\n * `setSegments` has a single production caller, so all three paths through\n * `populateBubbleFromMessage` are covered by this line.\n *\n * The objects stay shared, deliberately — that is the arrangement `addSegment`\n * produces and that `appendToSegment` is written for: the first write on either\n * side replaces its own slot and the two are independent from then on.\n */\n this._segments = [...segments];\n this._renderSegments();\n this._updateWaiting();\n }\n\n /** Add a segment */\n addSegment(segment: AparteSegment): void {\n this._segments.push(segment);\n this._appendSegmentEl(segment);\n this._updateWaiting();\n }\n\n /** Update a specific segment */\n updateSegment(segmentId: string, updates: Partial<AparteSegment>): void {\n const index = this._segments.findIndex(s => s.id === segmentId);\n if (index !== -1) {\n const updated = mergeSegmentUpdate(this._segments[index]!, updates);\n this._segments[index] = updated;\n this._applySegmentUpdate(segmentId, updated, updates);\n }\n }\n\n /** Append content to a segment */\n appendToSegment(segmentId: string, content: string): void {\n const segment = this._segments.find(s => s.id === segmentId);\n if (segment && 'content' in segment) {\n (segment as { content: string }).content += content;\n this._applySegmentUpdate(segmentId, segment, { content: (segment as AparteSegment & { content: string }).content });\n }\n }\n\n /** Get all segments */\n getSegments(): AparteSegment[] {\n return [...this._segments];\n }\n\n /** Remove a segment by id (e.g. to discard a transient waiting indicator) */\n /**\n * Scoped to DIRECT children on purpose.\n *\n * Segments are appended as direct children of the container, but a descendant\n * query returns the first match in document order — and sanitized model\n * markdown renders inside that same container, with `data-*` attributes\n * deliberately preserved (they are inert). So a decoy `data-segment-id` planted\n * in an earlier segment's prose used to win over the real segment element.\n *\n * Parser ids are unguessable UUIDs, but a tool segment is `tool-${toolCallId}`\n * and the MODEL chooses that id — so this was reachable, and pointing an update\n * at a decoy left a rejected tool rendering as still-running: a spoof against\n * the human-in-the-loop control.\n */\n removeSegment(segmentId: string): void {\n const index = this._segments.findIndex(s => s.id === segmentId);\n if (index !== -1) {\n this._segments.splice(index, 1);\n }\n const el = this._segmentsEl?.querySelector(`:scope > [data-segment-id=\"${cssEscape(segmentId)}\"]`);\n el?.remove();\n this._updateWaiting();\n }\n\n /** Set attachments (chips shown above message content, user role only) */\n setAttachments(attachments: AparteAttachment[]): void {\n this._attachments = attachments;\n this._updateAttachments();\n }\n\n /**\n * Set token usage + timing for this message (assistant only).\n *\n * This is the *precondition* for the info (\"i\") action, not the trigger: the\n * button appears only if the app also declared it wants it —\n * `aparteGlobalConfig.setBubbleActions({ info: true })` — because the stats popover it\n * opens (`aparte-message-info`) is the app's, and core has none. Without usage\n * there is nothing to show, so the button never renders either way.\n */\n setUsage(usage: AparteUsage | null | undefined): void {\n this._usage = usage ?? null;\n this._updateActionBar();\n }\n\n /**\n * Update the branch picker UI for tree-based navigation.\n * The viewport calls this after a branch switch or re-render.\n * Prev/Next clicks dispatch `aparte-branch-navigate` (bubbles: true) so\n * the viewport can handle the actual tree switch.\n */\n setSiblings(count: number, index: number): void {\n this._siblingCount = count;\n this._siblingIndex = index;\n this._updateBranchPicker();\n }\n\n /**\n * Atomic update for the message\n */\n updateMessage(updates: Partial<AparteMessage>): void {\n if ('role' in updates) {\n this._role = updates.role!;\n this._updateRole();\n }\n if ('content' in updates) {\n this._content = updates.content!;\n this._updateContent();\n }\n if ('segments' in updates) {\n this._segments = updates.segments!;\n this._renderSegments();\n }\n if ('timestamp' in updates) {\n this._updateTimestamp(updates.timestamp!);\n }\n if ('status' in updates) {\n const isStreaming = updates.status === 'streaming' || updates.status === 'pending';\n this._updateStreaming(isStreaming);\n }\n if ('attachments' in updates) {\n this._attachments = updates.attachments ?? [];\n this._updateAttachments();\n }\n }\n\n // ─────────────────────────────────────────────────────────────────────────\n // Private Methods\n // ─────────────────────────────────────────────────────────────────────────\n\n private _appendSegmentEl(segment: AparteSegment): void {\n if (!this._segmentsEl) {\n console.warn(`[AparteChatBubble] _appendSegmentEl ABORT: _segmentsEl is null`);\n return;\n }\n const renderer = resolveSegmentRenderer(segment.type, this._cfg);\n if (renderer) {\n // Renderers are plain functions with no element to resolve from — expose\n // this bubble's config as the ambient render config for the duration.\n const el = segmentRenderResultToElement(runWithConfig(this._cfg, () => renderer.render(segment)));\n if (el) {\n this._segmentsEl.appendChild(el);\n runWithConfig(this._cfg, () => renderer.setup?.(el, segment));\n }\n } else {\n warnMissingRenderer(segment.type);\n const fallback = document.createElement('div');\n fallback.className = 'segment aparte-segment-unknown';\n fallback.textContent = `[Unknown segment type: ${segment.type}]`;\n this._segmentsEl.appendChild(fallback);\n }\n if (this._contentEl) this._contentEl.style.display = 'none';\n this._reflectError();\n }\n\n private _applySegmentUpdate(segmentId: string, segment: AparteSegment, updates: Partial<AparteSegment>): void {\n const el = this._segmentsEl?.querySelector(`:scope > [data-segment-id=\"${cssEscape(segmentId)}\"]`) as HTMLElement | null;\n if (!el) {\n this._renderSegments();\n return;\n }\n const renderer = resolveSegmentRenderer(segment.type, this._cfg);\n if (!renderer) return;\n\n if (renderer.update) {\n runWithConfig(this._cfg, () => renderer.update!(el, segment));\n } else {\n const newEl = segmentRenderResultToElement(runWithConfig(this._cfg, () => renderer.render(segment)));\n if (newEl) {\n el.replaceWith(newEl);\n runWithConfig(this._cfg, () => renderer.setup?.(newEl, segment));\n }\n }\n\n // Handle collapsed state only when explicitly provided in the update —\n // never override a state the user set by clicking <summary>.\n if ('collapsed' in updates) {\n if ((updates as { collapsed?: boolean }).collapsed) {\n el.removeAttribute('open');\n } else {\n el.setAttribute('open', '');\n }\n }\n }\n\n private _getDisplayName(): string {\n const nameAttr = this.getAttribute('name');\n if (nameAttr) return nameAttr;\n const locale = this._cfg.getLocale();\n return this._role === 'user'\n ? (locale.roleNameUser ?? 'You')\n : (locale.roleNameAssistant ?? 'Assistant');\n }\n\n private _getAvatarInitial(): string {\n const name = this._getDisplayName();\n return name.length > 0 ? name[0]! : (this._role === 'user' ? 'U' : 'A');\n }\n\n private _render(): void {\n // Read the bubble's logical role from `data-role` (preferred — written\n // by the Angular wrapper) or the legacy `role` attribute, then set the\n // host's actual `role` attribute to a valid ARIA value. \"user\" and\n // \"assistant\" are NOT valid ARIA roles and would trigger accessibility\n // warnings in browsers / Lighthouse. The role-based styling lives on\n // inner `data-role` markers, so this swap is transparent to CSS.\n const dataRole = this.getAttribute('data-role');\n const legacyRole = this.getAttribute('role');\n const role = (dataRole && dataRole !== 'article') ? dataRole\n : (legacyRole && legacyRole !== 'article') ? legacyRole\n : 'assistant';\n this._role = role as AparteBubbleRole;\n if (this.getAttribute('role') !== 'article') {\n this.setAttribute('role', 'article');\n }\n if (!this.hasAttribute('data-role')) {\n this.setAttribute('data-role', role);\n }\n\n // Ensure we don't overwrite if already rendered (re-entrancy check)\n if (this.querySelector('.aparte-message')) return;\n\n const displayName = this._getDisplayName();\n const initial = this._getAvatarInitial();\n\n // Custom structural shell (aparteGlobalConfig.setBubbleShellRenderer). Must root at\n // .aparte-message + carry the region hooks; the queries below are null-guarded\n // so a partial shell degrades gracefully. See AparteBubbleShellRenderer.\n const shell = this._cfg.getBubbleShellRenderer?.();\n if (shell) {\n const out = runWithConfig(this._cfg, () => shell({ role: this._role, name: displayName, avatarInitial: initial }));\n if (out instanceof HTMLElement) this.replaceChildren(out);\n else this.innerHTML = out;\n } else {\n this.innerHTML = `\n <div class=\"aparte-message\" data-role=\"${escapeAttr(role)}\" role=\"article\" aria-label=\"${escapeAttr(this._getAriaLabel())}\">\n <div class=\"aparte-avatar\" data-role=\"${escapeAttr(role)}\"></div>\n <div class=\"aparte-body\">\n <div class=\"aparte-header\">\n <span class=\"aparte-name\">${escapeHtml(displayName)}</span>\n <span class=\"aparte-timestamp\"></span>\n </div>\n <div class=\"aparte-attachments\" hidden></div>\n <div class=\"aparte-message-content\">\n <div class=\"aparte-segments\"></div>\n <div class=\"aparte-content\"></div>\n <div class=\"aparte-waiting\" hidden>\n <span class=\"aparte-dots\" aria-hidden=\"true\"><span class=\"aparte-dot\"></span><span class=\"aparte-dot\"></span><span class=\"aparte-dot\"></span></span>\n <span class=\"aparte-sr-only\"></span>\n </div>\n </div>\n <div class=\"aparte-footer\">\n <div class=\"aparte-branch-picker\" hidden>\n <button class=\"aparte-branch-prev\" aria-label=\"${escapeAttr(this._cfg.getLocale().previousResponse ?? 'Previous response')}\">‹</button>\n <span class=\"aparte-branch-label\">1 / 1</span>\n <button class=\"aparte-branch-next\" aria-label=\"${escapeAttr(this._cfg.getLocale().nextResponse ?? 'Next response')}\">›</button>\n </div>\n <div class=\"aparte-action-bar\" role=\"toolbar\" aria-label=\"${escapeAttr(this._cfg.getLocale().messageActions ?? 'Message actions')}\"></div>\n </div>\n </div>\n </div>\n `;\n }\n\n this._contentEl = this.querySelector('.aparte-content');\n this._segmentsEl = this.querySelector('.aparte-segments');\n this._attachmentsEl = this.querySelector('.aparte-attachments');\n this._actionBarEl = this.querySelector('.aparte-action-bar');\n this._branchPickerEl = this.querySelector('.aparte-branch-picker');\n this._footerEl = this.querySelector('.aparte-footer');\n\n this._updateActionBar();\n this._renderAvatar();\n // Re-apply the streaming state onto the freshly-built `.aparte-message`.\n // Framework wrappers create the element with its attributes already set, so\n // `streaming` arrives BEFORE this render and `_updateStreaming()` had nothing\n // to write to — leaving a pending assistant bubble without `aria-busy` and\n // with its action bar exposed (copy/retry on an empty, still-streaming reply).\n if (this._streaming) this._updateStreaming(true);\n this._updateWaiting();\n }\n\n /**\n * Show the built-in waiting indicator while this bubble is in flight and has\n * nothing to show yet — the gap between \"user sends\" and the first token, which\n * used to be a bubble with a name and an empty body.\n *\n * The dots are CSS (no per-token work, themable, honours reduced-motion); the\n * accessible name is `locale.typing`, next to the `aria-busy` the streaming state\n * already sets. A custom bubble shell without the region simply has no indicator\n * (same null-guarded degradation as the other region hooks).\n */\n private _updateWaiting(): void {\n const empty = this._segments.length === 0 && !this._content.trim();\n const waiting = this._streaming && this._role !== 'user' && empty;\n\n // The painted box is hidden when it has nothing to paint. It carries the user\n // bubble's background, padding and radius, so an empty one is a coloured\n // rectangle with nothing in it — which is exactly what a message that is ONLY\n // attachments produced: the chips render ABOVE this box, so the box had no\n // content, no segments and no dots, and still drew itself.\n //\n // `hidden` and not `style.display`, deliberately: nothing sets an explicit\n // `display` on this class, so the UA sheet's rule applies. Where a component\n // DOES set one, `[hidden]` loses — a trap this repo has already paid for.\n const box = this.querySelector('.aparte-message-content') as HTMLElement | null;\n if (box) box.hidden = empty && !waiting;\n\n const el = this.querySelector('.aparte-waiting') as HTMLElement | null;\n if (!el) return;\n el.hidden = !waiting;\n if (!waiting) return;\n const label = this._cfg.getLocale().typing;\n const sr = el.querySelector('.aparte-sr-only');\n if (sr && sr.textContent !== label) sr.textContent = label;\n }\n\n /**\n * Hand the avatar host element off to the registered AvatarProvider, if any.\n *\n * With no provider the slot is left exactly as the shell rendered it — which for\n * the default shell means EMPTY, and hidden by `.aparte-avatar:empty`. This used\n * to claim it \"falls back to the default initial rendered by `_render()`\"; there\n * is no such initial, and believing there was is what made `_updateRole` write\n * one.\n */\n private _renderAvatar(): void {\n const avatar = this.querySelector('.aparte-avatar') as HTMLElement | null;\n if (!avatar) return;\n\n // Tear down any previously-mounted live component before re-rendering.\n if (this._avatarCleanup) {\n try { this._avatarCleanup(); } catch { /* ignore */ }\n this._avatarCleanup = null;\n }\n\n const provider = this._cfg.getAvatarProvider();\n if (!provider) return; // leave the slot as the shell rendered it\n\n avatar.textContent = '';\n const cleanup = provider.render(this._role, avatar);\n if (typeof cleanup === 'function') this._avatarCleanup = cleanup;\n }\n\n private _updateRole(): void {\n const message = this.querySelector('.aparte-message');\n const avatar = this.querySelector('.aparte-avatar');\n const nameEl = this.querySelector('.aparte-name');\n\n if (message) {\n message.setAttribute('data-role', this._role);\n message.setAttribute('aria-label', this._getAriaLabel());\n }\n if (avatar) {\n avatar.setAttribute('data-role', this._role);\n // Refresh an initial that is ALREADY there; never create one — the default\n // shell renders this slot empty and the stylesheet hides it while it stays\n // empty. Same rule as `_updateName`, which is where it was actually costing\n // something; the reasoning is written out there.\n if (avatar.textContent) avatar.textContent = this._getAvatarInitial();\n }\n if (nameEl) {\n nameEl.textContent = this._getDisplayName();\n }\n // Re-render the action bar so buttons match the correct role\n // (critical when the role attribute is set after connectedCallback)\n this._updateActionBar();\n this._renderAvatar();\n }\n\n private _updateName(): void {\n const avatar = this.querySelector('.aparte-avatar') as HTMLElement | null;\n const nameEl = this.querySelector('.aparte-name');\n /*\n * Two conditions, and the second one is the fix.\n *\n * No provider: otherwise a name change would wipe a live avatar component.\n *\n * Already non-empty: the default shell renders this slot EMPTY and the\n * stylesheet hides it while it stays empty — `.aparte-avatar:empty { display:\n * none }`, with the comment \"No message avatar by default — the slot only shows\n * once an AvatarProvider (or a consumer) fills it\". Writing the initial\n * unconditionally contradicted that, and `_onConfigChange` calls this method, so\n * ANY notifying config change filled the slot: `setLocale` (a language switcher\n * is enough), `setBubbleActions`, `setIconProvider`. Avatars appeared across the\n * transcript on a click that had nothing to do with them, and undoing the click\n * did not remove them, because the text was already written.\n *\n * The guard is \"already non-empty\" rather than \"no provider\" on purpose:\n * `avatarInitial` is part of the shell contract, so a CUSTOM shell may render an\n * initial and must still see it refreshed. Empty stays empty; filled stays in\n * sync.\n */\n if (avatar && avatar.textContent && !this._cfg.getAvatarProvider()) {\n avatar.textContent = this._getAvatarInitial();\n }\n if (nameEl) nameEl.textContent = this._getDisplayName();\n }\n\n private _updateContent(): void {\n if (!this._contentEl) return;\n\n // If we have segments, don't render simple content\n if (this._segments.length > 0) {\n this._contentEl.style.display = 'none';\n this._updateWaiting();\n return;\n }\n\n this._contentEl.style.display = '';\n this._contentEl.innerHTML = this._cfg.renderMarkdown(this._content);\n // The first token retires the waiting indicator (and a cleared content brings\n // it back, e.g. a retry that resets the bubble before re-streaming).\n this._updateWaiting();\n // The Markdown provider only emits plain <pre><code>; apply the registered\n // syntax highlighter (if any) to those blocks. Skipped while streaming —\n // re-run once on completion (see _updateStreaming) to avoid per-token churn.\n if (!this._streaming) this._highlightContentCode();\n }\n\n /**\n * Apply the registered syntax-highlight provider to the code blocks produced\n * by the Markdown provider in the simple-content path. Provider-agnostic: a\n * full-block provider (e.g. Shiki) returns `<pre>…</pre>` so we replace the\n * element; a token provider (e.g. Prism, highlight.js) returns inner HTML so\n * we fill the existing `<code>`. No-op when no highlighter is installed.\n */\n private _highlightContentCode(): void {\n if (!this._contentEl || !this._cfg.hasHighlightProvider()) return;\n this._contentEl.querySelectorAll('pre > code').forEach((codeEl) => {\n const code = codeEl.textContent ?? '';\n if (!code.trim()) return;\n const match = codeEl.className.match(/language-([\\w+#-]+)/i);\n const lang = match?.[1] ?? '';\n const pre = codeEl.parentElement;\n Promise.resolve(this._cfg.highlightCode(code, lang)).then((html) => {\n const out = (html ?? '').trim();\n if (!out || !pre || !pre.isConnected) return;\n if (/^<pre[\\s>]/i.test(out)) {\n pre.outerHTML = out; // full block (Shiki)\n } else {\n (codeEl as HTMLElement).innerHTML = out; // inner tokens (Prism, hljs)\n }\n }).catch(() => { /* keep the plain block on failure */ });\n });\n }\n\n private _renderSegments(): void {\n if (!this._segmentsEl) return;\n\n // Clear existing segments\n this._segmentsEl.innerHTML = '';\n\n for (const segment of this._segments) {\n const renderer = resolveSegmentRenderer(segment.type, this._cfg);\n if (renderer) {\n const el = segmentRenderResultToElement(runWithConfig(this._cfg, () => renderer.render(segment)));\n if (el) {\n this._segmentsEl.appendChild(el);\n runWithConfig(this._cfg, () => renderer.setup?.(el, segment));\n }\n } else {\n // Fallback for unknown segment types\n warnMissingRenderer(segment.type);\n const fallback = document.createElement('div');\n fallback.className = 'segment aparte-segment-unknown';\n fallback.textContent = `[Unknown segment type: ${segment.type}]`;\n this._segmentsEl.appendChild(fallback);\n }\n }\n\n // Hide simple content when segments are present\n if (this._contentEl) {\n this._contentEl.style.display = this._segments.length > 0 ? 'none' : '';\n }\n this._reflectError();\n }\n\n /**\n * Reflect the error state on the bubble: `data-error` on `.aparte-message` while\n * an error segment is present. Derived from segments (not the message `status`\n * attribute) so it works identically in vanilla and in every wrapper — the\n * error segment flows through the reactive list in all of them. CSS themes\n * `.aparte-message[data-error]`; custom error content is via setErrorRenderer.\n */\n private _reflectError(): void {\n const message = this.querySelector('.aparte-message');\n if (!message) return;\n const hasError = this._segments.some(s => s.type === 'error');\n if (hasError) message.setAttribute('data-error', '');\n else message.removeAttribute('data-error');\n }\n\n private _updateTimestamp(value: string | number | null): void {\n const timestampEl = this.querySelector('.aparte-timestamp');\n if (!timestampEl || !value) return;\n\n try {\n const date = new Date(isNaN(Number(value)) ? value : Number(value));\n // The locale's own tag, not `undefined`. `undefined` means \"follow the\n // BROWSER\", which is why a French chat on an en-US browser still read\n // `7:32 PM` — the app had chosen a language and the clock had not heard.\n // Still `undefined` when no tag is declared: that is the documented default\n // and the behaviour every consumer has today.\n timestampEl.textContent = date.toLocaleTimeString(this._cfg.getLocale().tag || undefined, {\n hour: '2-digit',\n minute: '2-digit'\n });\n } catch {\n timestampEl.textContent = '';\n }\n }\n\n private _getAriaLabel(): string {\n const locale = this._cfg.getLocale();\n return this._role === 'user'\n ? (locale.yourMessage ?? 'Your message')\n : (locale.assistantResponse ?? 'Assistant response');\n }\n\n // ─────────────────────────────────────────────────────────────────────────\n // Attachments\n // ─────────────────────────────────────────────────────────────────────────\n\n private _updateAttachments(): void {\n if (!this._attachmentsEl) return;\n\n if (this._role !== 'user' || this._attachments.length === 0) {\n this._attachmentsEl.hidden = true;\n this._attachmentsEl.innerHTML = '';\n return;\n }\n\n this._attachmentsEl.hidden = false;\n\n // Custom attachment chips (aparteGlobalConfig.setAttachmentRenderer) — one node per\n // attachment; the consumer owns markup + interactions (no default preview wiring).\n const customAttachment = this._cfg.getAttachmentRenderer?.();\n if (customAttachment) {\n this._attachmentsEl.replaceChildren();\n for (const a of this._attachments) {\n const el = segmentRenderResultToElement(runWithConfig(this._cfg, () => customAttachment(a)));\n if (el) this._attachmentsEl.appendChild(el);\n }\n return;\n }\n\n this._attachmentsEl.innerHTML = this._attachments.map(a => {\n const name = escapeHtml(a.name);\n if (a.type.startsWith('image/')) {\n return `<div class=\"aparte-thumb aparte-thumb--image\" title=\"${name}\">`\n + `<img class=\"aparte-thumb__img\" src=\"${escapeHtml(a.url)}\" alt=\"${name}\" loading=\"lazy\" />`\n + `<span class=\"aparte-thumb__name\">${name}</span></div>`;\n }\n return `<div class=\"aparte-thumb aparte-thumb--file\" title=\"${name}\">`\n + `<span class=\"aparte-thumb__ext\">${escapeHtml(this._fileExt(a.name))}</span>`\n + `<span class=\"aparte-thumb__name\">${name}</span></div>`;\n }).join('');\n\n // Image tiles ask for a full-size preview — but the lightbox is the app's, so\n // the tile only becomes a button once the app declared it opens one. Otherwise\n // it stays a plain picture: no role, no tab stop, no pointer (see the CSS,\n // which keys the cursor off role=\"button\").\n if (!this._cfg.getHostHandlers().attachmentPreview) return;\n this._attachmentsEl.querySelectorAll('.aparte-thumb--image').forEach(tile => {\n tile.setAttribute('role', 'button');\n tile.setAttribute('tabindex', '0');\n const open = (): void => {\n const img = tile.querySelector('.aparte-thumb__img') as HTMLImageElement | null;\n if (!img) return;\n this.dispatchEvent(new CustomEvent('aparte-attachment-preview', {\n bubbles: true, composed: true,\n detail: { url: img.src, name: tile.getAttribute('title') ?? '' },\n }));\n };\n tile.addEventListener('click', open);\n tile.addEventListener('keydown', (e) => {\n const key = (e as KeyboardEvent).key;\n if (key !== 'Enter' && key !== ' ') return;\n e.preventDefault();\n open();\n });\n });\n }\n\n /** Uppercased file extension (≤4 chars), or 'FILE' when there is none. */\n private _fileExt(filename: string): string {\n const dot = filename.lastIndexOf('.');\n return dot > 0 ? filename.slice(dot + 1).toUpperCase().slice(0, 4) : 'FILE';\n }\n\n // ─────────────────────────────────────────────────────────────────────────\n // Branch Picker\n // ─────────────────────────────────────────────────────────────────────────\n\n /**\n * The branch arrows are handled by DELEGATION, on this element, bound once.\n *\n * They used to get a fresh listener each, attached by `_render()` to the buttons\n * `_render()` had just created. So a click that landed while a re-render was\n * swapping those nodes hit an element about to be discarded, and did nothing at\n * all — not late, nothing. Invisible on a fast machine; reproducible on\n * WebKit-Linux in CI, where `‹` left the picker on \"2 / 2\" and a 20-second\n * assertion watched it stay there.\n *\n * Delegation makes `_render()` irrelevant to it: the listener lives on the host,\n * which is never replaced, and `closest()` finds whichever button exists at the\n * moment of the click. It is also less work — one listener per bubble instead of\n * two per bubble per render.\n *\n * Bound in `connectedCallback` and removed in `disconnectedCallback` as a stable\n * field, because an inline arrow re-added on every re-connect is how this repo has\n * stacked listeners twice before (the viewport, and `aparte-select`).\n */\n private _onBranchPickerClick = (event: Event): void => {\n const target = event.target as HTMLElement | null;\n const button = target?.closest?.('.aparte-branch-prev, .aparte-branch-next');\n if (!button || !this.contains(button)) return;\n const direction = button.classList.contains('aparte-branch-prev') ? 'prev' : 'next';\n const messageId = this.getAttribute('message-id');\n if (!messageId) return;\n const detail: AparteBranchNavigateEventDetail = { messageId, direction };\n // Tree-based navigation: let the viewport handle the branch switch\n this.dispatchEvent(new CustomEvent<AparteBranchNavigateEventDetail>('aparte-branch-navigate', {\n bubbles: true,\n composed: true,\n detail,\n }));\n };\n\n private _updateBranchPicker(): void {\n if (!this._branchPickerEl) return;\n if (this._siblingCount <= 1 || this._role !== 'assistant') {\n this._branchPickerEl.hidden = true;\n this._syncFooterVisibility();\n return;\n }\n this._branchPickerEl.hidden = false;\n this._syncFooterVisibility();\n const label = this._branchPickerEl.querySelector('.aparte-branch-label');\n if (label) {\n // Custom position indicator (aparteGlobalConfig.setSiblingNavRenderer) — e.g. dots —\n // fills the label between the arrows; the arrows keep their behavior.\n const customNav = this._cfg.getSiblingNavRenderer?.();\n if (customNav) {\n const out = runWithConfig(this._cfg, () => customNav({ count: this._siblingCount, index: this._siblingIndex }));\n if (out instanceof HTMLElement) label.replaceChildren(out);\n else label.innerHTML = out;\n } else {\n label.textContent = `${this._siblingIndex + 1} / ${this._siblingCount}`;\n }\n }\n\n const prevBtn = this._branchPickerEl.querySelector('.aparte-branch-prev') as HTMLButtonElement | null;\n const nextBtn = this._branchPickerEl.querySelector('.aparte-branch-next') as HTMLButtonElement | null;\n if (prevBtn) prevBtn.disabled = this._siblingIndex === 0;\n if (nextBtn) nextBtn.disabled = this._siblingIndex === this._siblingCount - 1;\n }\n\n // ─────────────────────────────────────────────────────────────────────────\n // Action Bar\n // ─────────────────────────────────────────────────────────────────────────\n\n private _updateActionBar(): void {\n if (!this._actionBarEl) return;\n // While the inline editor is open the bar shows save (✓) / cancel (✗).\n if (this._editing) {\n this._renderEditActions();\n return;\n }\n const config = this._cfg.getBubbleActions();\n const icons = this._cfg.getIconProvider();\n const locale = this._cfg.getLocale();\n const buttons: string[] = [];\n\n if (this._role === 'user') {\n if (config.user) {\n // Explicit ordered set replaces the flag defaults for user bubbles.\n for (const a of config.user) buttons.push(this._actionButtonHtml(a, icons, locale));\n } else {\n // Flag-driven set. Only `copy` is on by default — see\n // APARTE_DEFAULT_BUBBLE_ACTIONS: edit needs a host to keep the new text.\n if (config.copy) buttons.push(this._actionButtonHtml('copy', icons, locale));\n if (config.edit) buttons.push(this._actionButtonHtml('edit', icons, locale));\n }\n } else if (this._role === 'assistant') {\n if (config.assistant) {\n // Explicit ordered set replaces the flag defaults (incl. the info button).\n for (const a of config.assistant) buttons.push(this._actionButtonHtml(a, icons, locale));\n } else {\n // Flag-driven set. Only `copy` is on by default — retry, feedback and\n // info all need a host or a listener to mean anything.\n if (config.copy) buttons.push(this._actionButtonHtml('copy', icons, locale));\n if (config.retry) buttons.push(this._actionButtonHtml('retry', icons, locale));\n if (config.feedback) {\n buttons.push(this._actionButtonHtml('thumbUp', icons, locale));\n buttons.push(this._actionButtonHtml('thumbDown', icons, locale));\n }\n if (config.info) buttons.push(this._actionButtonHtml('info', icons, locale));\n }\n }\n\n this._actionBarEl.innerHTML = buttons.join('');\n\n // Custom actions registered via aparteGlobalConfig.registerAction — appended\n // after the built-ins, built as DOM (label goes to attributes, never\n // interpolated into innerHTML) so a consumer label can't inject markup.\n this._appendCustomActions(icons);\n\n // Wire up button handlers — messageId read dynamically at click time\n // so it's always correct even when Angular sets the attribute after connectedCallback\n this._actionBarEl.querySelectorAll('.aparte-action-btn').forEach(btn => {\n btn.addEventListener('click', (e) => this._handleActionClick(e as MouseEvent));\n });\n\n this._syncFooterVisibility();\n }\n\n /**\n * An empty action bar is not a bar: with every action off it was still a\n * `role=\"toolbar\"` with nothing in it (announced as such), and it still reserved\n * its fixed height plus the footer's under every bubble. So both follow their\n * contents — the footer stays as long as the branch picker or the bar has\n * something to show.\n */\n private _syncFooterVisibility(): void {\n if (this._actionBarEl) this._actionBarEl.hidden = this._actionBarEl.children.length === 0;\n if (!this._footerEl) return;\n const barEmpty = !this._actionBarEl || this._actionBarEl.hidden;\n const pickerHidden = !this._branchPickerEl || this._branchPickerEl.hidden;\n this._footerEl.hidden = barEmpty && pickerHidden;\n }\n\n /** Append the registered custom action buttons for this bubble's role. */\n private _appendCustomActions(icons: ReturnType<AparteConfig['getIconProvider']>): void {\n if (!this._actionBarEl) return;\n for (const a of this._cfg.getActions('bubble')) {\n const roles = a.bubble?.roles ?? ['user', 'assistant'];\n if (!roles.includes(this._role)) continue;\n const btn = document.createElement('button');\n btn.className = 'aparte-action-btn aparte-action-custom';\n btn.dataset['action'] = `custom:${a.id}`;\n // aria-label/title via setAttribute — safe for consumer-provided strings.\n btn.setAttribute('aria-label', a.label);\n btn.setAttribute('title', a.label);\n // Icon: raw inline SVG/HTML, else an icon-provider key (trusted output).\n const fromProvider = (icons as unknown as Record<string, (() => string) | undefined>)[a.icon];\n btn.innerHTML = a.icon.startsWith('<')\n ? a.icon\n : (typeof fromProvider === 'function' ? fromProvider() : (a.iconFallback ?? ''));\n this._actionBarEl.appendChild(btn);\n }\n }\n\n /** Build the `<button>` HTML for a single named action (shared by flag + per-role rendering). */\n private _actionButtonHtml(\n action: string,\n icons: ReturnType<AparteConfig['getIconProvider']>,\n locale: ReturnType<AparteConfig['getLocale']>,\n ): string {\n switch (action) {\n case 'copy': {\n const l = locale.copy ?? 'Copy';\n return `<button class=\"aparte-action-btn aparte-action-copy\" data-action=\"copy\" aria-label=\"${escapeAttr(l)}\" title=\"${escapeAttr(l)}\">${icons.copy()}</button>`;\n }\n case 'edit': {\n const l = locale.edit ?? 'Edit message';\n return `<button class=\"aparte-action-btn aparte-action-edit\" data-action=\"edit\" aria-label=\"${escapeAttr(l)}\" title=\"${escapeAttr(l)}\">${icons.edit()}</button>`;\n }\n case 'retry': {\n const l = locale.retry ?? 'Retry';\n return `<button class=\"aparte-action-btn aparte-action-retry\" data-action=\"retry\" aria-label=\"${escapeAttr(l)}\" title=\"${escapeAttr(l)}\">${icons.retry()}</button>`;\n }\n case 'thumbUp': {\n const l = locale.feedbackPositive ?? 'Good response';\n return `<button class=\"aparte-action-btn aparte-action-feedback-pos\" data-action=\"feedback-positive\" aria-label=\"${escapeAttr(l)}\" title=\"${escapeAttr(l)}\">${icons.thumbUp()}</button>`;\n }\n case 'thumbDown': {\n const l = locale.feedbackNegative ?? 'Bad response';\n return `<button class=\"aparte-action-btn aparte-action-feedback-neg\" data-action=\"feedback-negative\" aria-label=\"${escapeAttr(l)}\" title=\"${escapeAttr(l)}\">${icons.thumbDown()}</button>`;\n }\n case 'info': {\n // Only when there are numbers to show: a details button over nothing is a\n // dead button. The popover itself is the app's (see `aparte-message-info`).\n if (!this._usage) return '';\n const l = locale.messageInfo ?? 'Details';\n return `<button class=\"aparte-action-btn aparte-action-info\" data-action=\"info\" aria-label=\"${escapeAttr(l)}\" title=\"${escapeAttr(l)}\">${INFO_ICON_SVG}</button>`;\n }\n default:\n return '';\n }\n }\n\n /** Render the edit-mode action bar: ✓ save (green) + ✗ cancel (red). */\n private _renderEditActions(): void {\n if (!this._actionBarEl) return;\n const locale = this._cfg.getLocale();\n const saveLabel = locale.editConfirm ?? 'Save';\n const cancelLabel = locale.editCancel ?? 'Cancel';\n this._actionBarEl.innerHTML =\n `<button class=\"aparte-action-btn aparte-action-edit-save\" data-action=\"edit-save\" ` +\n `aria-label=\"${escapeAttr(saveLabel)}\" title=\"${escapeAttr(saveLabel)}\">${this._cfg.getIcon('check')}</button>` +\n `<button class=\"aparte-action-btn aparte-action-edit-cancel\" data-action=\"edit-cancel\" ` +\n `aria-label=\"${escapeAttr(cancelLabel)}\" title=\"${escapeAttr(cancelLabel)}\">${this._cfg.getIcon('close')}</button>`;\n this._actionBarEl.querySelectorAll('.aparte-action-btn').forEach(btn => {\n btn.addEventListener('click', (e) => this._handleActionClick(e as MouseEvent));\n });\n // Save/cancel must show even when every action flag is off.\n this._syncFooterVisibility();\n }\n\n private _handleActionClick(e: MouseEvent): void {\n const btn = (e.currentTarget as HTMLElement);\n const action = btn.dataset['action'];\n // Read dynamically — attribute may not be set yet at render time\n const messageId = this.getAttribute('message-id');\n\n // Custom actions (aparteGlobalConfig.registerAction) emit a generic aparte-action\n // event carrying the action id — same DOM-event contract as retry/feedback.\n if (action?.startsWith('custom:') && messageId) {\n const actionId = action.slice('custom:'.length);\n const detail: AparteActionEventDetail = {\n actionId,\n zone: 'bubble',\n messageId,\n role: this._role,\n targetId: this._resolveTargetId(),\n };\n this.dispatchEvent(new CustomEvent<AparteActionEventDetail>('aparte-action', {\n bubbles: true, composed: true, detail,\n }));\n this._cfg.getActions('bubble').find(x => x.id === actionId)?.onClick?.(e);\n return;\n }\n\n switch (action) {\n case 'copy': {\n const text = this._content || this._segments.map(s => (s as { content?: string }).content ?? '').join('\\n');\n const icons = this._cfg.getIconProvider();\n const locale = this._cfg.getLocale();\n navigator.clipboard.writeText(text).then(() => {\n btn.innerHTML = icons.check();\n btn.setAttribute('data-copied', '');\n const copiedLabel = locale.copied ?? locale.copy ?? 'Copied';\n btn.setAttribute('title', copiedLabel);\n btn.setAttribute('aria-label', copiedLabel);\n setTimeout(() => {\n btn.removeAttribute('data-copied');\n btn.innerHTML = icons.copy();\n const copyLabel = locale.copy ?? 'Copy';\n btn.setAttribute('title', copyLabel);\n btn.setAttribute('aria-label', copyLabel);\n }, 2000);\n }).catch(() => {\n console.warn('[aparte] Clipboard write failed');\n });\n break;\n }\n case 'retry': {\n if (!messageId) break;\n const targetId = this._resolveTargetId();\n const detail: AparteRetryEventDetail = { messageId, targetId };\n this.dispatchEvent(new CustomEvent<AparteRetryEventDetail>('aparte-retry', {\n bubbles: true, composed: true,\n detail,\n }));\n break;\n }\n case 'edit': {\n this._enterEditMode();\n break;\n }\n case 'edit-save': {\n this._exitEditMode(true);\n break;\n }\n case 'edit-cancel': {\n this._exitEditMode(false);\n break;\n }\n case 'feedback-positive':\n case 'feedback-negative': {\n if (!messageId) break;\n const value: AparteFeedbackEventDetail['value'] = action === 'feedback-positive' ? 'positive' : 'negative';\n btn.setAttribute('data-submitted', '');\n const detail: AparteFeedbackEventDetail = { messageId, value };\n this.dispatchEvent(new CustomEvent<AparteFeedbackEventDetail>('aparte-feedback', {\n bubbles: true, composed: true,\n detail,\n }));\n break;\n }\n case 'info': {\n if (!messageId) break;\n const detail: AparteMessageInfoEventDetail = {\n messageId,\n usage: this._usage ?? undefined,\n };\n this.dispatchEvent(new CustomEvent<AparteMessageInfoEventDetail>('aparte-message-info', {\n bubbles: true, composed: true,\n detail,\n }));\n break;\n }\n }\n }\n\n /**\n * Open the inline editor for a user message. Idempotent — a second `edit`\n * click while already editing is a no-op (no stacked editors).\n *\n * The editor reuses the composer's contenteditable primitive\n * (`<aparte-composer-input>`) so editing is iso with composing: same autosize,\n * IME, paste and styling. With no `<aparte-composer>` root it runs standalone —\n * `Enter` (Shift+Enter = newline) surfaces as `aparte-composer-submit`, which we\n * treat as save; `Esc` cancels.\n */\n private _enterEditMode(): void {\n if (this._editing || !this._contentEl) return;\n this._editing = true;\n this.querySelector('.aparte-message')?.setAttribute('data-editing', '');\n\n const input = document.createElement('aparte-composer-input') as AparteComposerInput;\n input.setAttribute('placeholder', this._cfg.getLocale().edit ?? 'Edit message');\n this._editInput = input;\n\n this._contentEl.style.display = 'none';\n this._contentEl.insertAdjacentElement('afterend', input);\n // `insertAdjacentElement` upgrades + connects synchronously, so the editor is\n // ready — seed it with the current text (autosizes to fit).\n input.setValue(this._content);\n\n // Enter (via the primitive's standalone submit event) saves; Esc cancels.\n input.addEventListener('aparte-composer-submit', () => this._exitEditMode(true));\n input.addEventListener('keydown', (e) => {\n if (e.key === 'Escape' && !e.isComposing) {\n e.preventDefault();\n this._exitEditMode(false);\n }\n });\n\n // Swap the action bar over to ✓ / ✗.\n this._updateActionBar();\n\n input.focusEnd();\n }\n\n /**\n * Leave edit mode. When `save` is true and the text actually changed, emits\n * `aparte-edit`; otherwise restores the original message untouched. Always\n * restores the normal action bar and removes the inline editor.\n */\n private _exitEditMode(save: boolean): void {\n if (!this._editing) return;\n const newContent = this._editInput?.getValue() ?? '';\n const original = this._content;\n\n this._editInput?.remove();\n this._editInput = null;\n if (this._contentEl) this._contentEl.style.display = '';\n this.querySelector('.aparte-message')?.removeAttribute('data-editing');\n this._editing = false;\n this._updateActionBar();\n\n if (save && newContent && newContent !== original) {\n const messageId = this.getAttribute('message-id');\n if (messageId) {\n const detail: AparteEditEventDetail = {\n messageId,\n content: newContent,\n targetId: this._resolveTargetId(),\n };\n this.dispatchEvent(new CustomEvent<AparteEditEventDetail>('aparte-edit', {\n bubbles: true, composed: true,\n detail,\n }));\n }\n }\n }\n\n private _resolveTargetId(): string | undefined {\n // Walk up to the chat host element with an id. Angular's wrapper root IS the\n // `<aparte-chat>` element (its component selector); the plain-root wrappers\n // (React/Vue/Svelte) render a `<div class=\"aparte-chat-container\" data-aparte-chat\n // id=\"…\">` instead — so match `[data-aparte-chat]` too. Without this, retry/edit\n // resolved to `undefined` outside Angular and AparteClient's fallback hit the\n // bare `<aparte-chat-viewport>` (a different message store) → retry regenerated\n // into the void.\n let el: HTMLElement | null = this.parentElement;\n while (el) {\n const tag = el.tagName?.toLowerCase();\n const isHost = tag === 'aparte-chat' || tag === 'aparte-chat-component' || el.hasAttribute?.('data-aparte-chat');\n if (isHost && el.id) return el.id;\n el = el.parentElement;\n }\n return undefined;\n }\n\n // ─────────────────────────────────────────────────────────────────────────\n // Utilities\n // ─────────────────────────────────────────────────────────────────────────\n\n\n private _updateStreaming(streaming: boolean): void {\n const wasStreaming = this._streaming;\n this._streaming = streaming;\n const message = this.querySelector('.aparte-message');\n if (message) {\n message.setAttribute('data-streaming', String(streaming));\n if (streaming) {\n // Signal \"in progress\" to assistive tech; clearing it on completion\n // cues screen readers (via the viewport's aria-live region) to read\n // the finished response.\n message.setAttribute('aria-busy', 'true');\n message.classList.add('aparte-message-streaming');\n } else {\n message.removeAttribute('aria-busy');\n message.classList.remove('aparte-message-streaming');\n }\n }\n this._updateWaiting();\n // Streaming just finished: highlight the final content once (skipped during\n // streaming to avoid re-highlighting on every token).\n if (wasStreaming && !streaming) this._highlightContentCode();\n }\n}\n\n// Register the custom element\nif (!customElements.get('aparte-chat-bubble')) {\n customElements.define('aparte-chat-bubble', AparteChatBubble);\n}\n","import { AparteConfig } from '../../config/aparte-config.js';\nimport { resolveConfig, runWithConfig } from '../../config/config-context.js';\n\n/**\n * A standalone status line — a light-DOM typing indicator the APP owns. Core never\n * turns it on by itself, so it can never compete with the bubble's own waiting state.\n *\n * It dispatches nothing, deliberately: it reports, it does not ask.\n *\n * @element aparte-chat-status\n * @attr {boolean} visible - Shows or hides the indicator.\n * @attr {string} text - The line to show. Defaults to the locale's typing string.\n *\n * @example\n * <!-- The app owns this indicator: core never turns it on by itself, so there is\n * never a second one competing with the bubble's built-in waiting state. -->\n * <aparte-chat-status visible text=\"Searching the docs…\"></aparte-chat-status>\n */\nexport class AparteChatStatus extends HTMLElement {\n static get observedAttributes(): string[] {\n return ['visible', 'text'];\n }\n\n /**\n * Resolved LIVE, not cached. Caching it at connect made this element\n * permanently deaf to its own instance: `_onConfigChange` filters on\n * `detail.config !== this._cfg`, so once `_cfg` had latched the global config no\n * change for the real instance ever matched, and the filter meant to isolate\n * chats became the thing that silenced one.\n */\n private get _cfg(): AparteConfig {\n return resolveConfig(this);\n }\n\n constructor() {\n super();\n }\n\n connectedCallback(): void {\n // Cache the resolved config (instance boundary or global fallback), like the\n // other Aparte elements — so a scoped setStatusRenderer applies here too.\n this._render();\n // Re-render on a live config change (e.g. setStatusRenderer called after this\n // element already upgraded — it self-registers on import, so a persistent\n // <aparte-chat-status> in the page mounts before any config runs). Mirrors the\n // bubble's config-change subscription.\n window.addEventListener('aparte-config-change', this._onConfigChange);\n }\n\n disconnectedCallback(): void {\n window.removeEventListener('aparte-config-change', this._onConfigChange);\n }\n\n private _onConfigChange = (e: Event): void => {\n // Only react to OUR config (an instance-scoped change elsewhere must not touch\n // us). A bare notify (no detail.config) always re-renders.\n const detail = (e as CustomEvent).detail as { config?: unknown } | undefined;\n if (detail?.config && detail.config !== this._cfg) return;\n // Clear so _render's re-entrancy guard doesn't bail; visible/text are read\n // from attributes, so the shown state is preserved across the re-render.\n this.innerHTML = '';\n this._render();\n };\n\n attributeChangedCallback(name: string, oldValue: string | null, newValue: string | null): void {\n if (oldValue === newValue) return;\n\n switch (name) {\n case 'visible':\n this._updateVisibility(newValue !== null);\n break;\n case 'text':\n this._updateText(newValue);\n break;\n }\n }\n\n /**\n * Show the typing indicator\n */\n show(): void {\n this.setAttribute('visible', '');\n }\n\n /**\n * Hide the typing indicator\n */\n hide(): void {\n this.removeAttribute('visible');\n }\n\n /**\n * Toggle visibility\n */\n toggle(): void {\n if (this.hasAttribute('visible')) {\n this.hide();\n } else {\n this.show();\n }\n }\n\n /**\n * Check if visible\n */\n isVisible(): boolean {\n return this.hasAttribute('visible');\n }\n\n private _render(): void {\n const text = this.getAttribute('text') || 'Typing';\n const visible = this.hasAttribute('visible');\n\n // Re-entrancy check\n if (this.querySelector('.aparte-status-container')) return;\n\n // Custom typing indicator (charter §6 render hook): replace the inner markup\n // while the container keeps owning show/hide (data-visible) + accessible name.\n const custom = this._cfg?.getStatusRenderer?.();\n if (custom) {\n this.innerHTML =\n `<div class=\"aparte-message aparte-status-container\" data-visible=\"${visible}\" role=\"status\" aria-live=\"polite\"></div>`;\n const container = this.querySelector('.aparte-status-container') as HTMLElement;\n // `text` set via setAttribute, never interpolated — a `\"` would break out.\n container.setAttribute('aria-label', text);\n const result = runWithConfig(this._cfg, () => custom(text));\n if (result instanceof HTMLElement) container.appendChild(result);\n else container.innerHTML = result;\n return;\n }\n\n this.innerHTML = `\n <div\n class=\"aparte-message aparte-status-container\"\n data-visible=\"${visible}\"\n role=\"status\"\n aria-live=\"polite\"\n >\n <div class=\"aparte-avatar\" data-role=\"assistant\" style=\"visibility: hidden\"></div>\n <div class=\"aparte-body\">\n <div class=\"aparte-status-content\">\n <div class=\"aparte-dots\" aria-hidden=\"true\">\n <span class=\"aparte-dot\"></span>\n </div>\n <span class=\"aparte-status-text\"></span>\n </div>\n </div>\n </div>\n `;\n // Set the (public, attacker-controllable) `text` via setAttribute/textContent\n // rather than interpolating it into the innerHTML template — a `\"` in the\n // attribute would otherwise break out and inject arbitrary attributes.\n this.querySelector('.aparte-status-container')?.setAttribute('aria-label', text);\n // Visible text only when explicitly requested — the default stays dots-only\n // (the aria-label above always carries the accessible name).\n if (this.hasAttribute('text')) {\n const textEl = this.querySelector('.aparte-status-text');\n if (textEl) textEl.textContent = text;\n }\n }\n\n private _updateVisibility(visible: boolean): void {\n const container = this.querySelector('.aparte-status-container');\n if (container) {\n container.setAttribute('data-visible', String(visible));\n }\n }\n\n private _updateText(text: string | null): void {\n const textEl = this.querySelector('.aparte-status-text');\n const container = this.querySelector('.aparte-status-container');\n if (!container) return; // not rendered yet — _render() reads the attribute\n // Removing the attribute restores the dots-only default (empty visible\n // text); the aria-label always keeps an accessible name.\n if (textEl) textEl.textContent = text ?? '';\n container.setAttribute('aria-label', text || 'Typing');\n }\n}\n\n// Register the custom element\nif (!customElements.get('aparte-chat-status')) {\n customElements.define('aparte-chat-status', AparteChatStatus);\n}\n","import type {\n AparteMessage,\n AparteViewportConfig,\n AparteSegment,\n AparteSegmentUpdateEventDetail,\n ApartePathChangedEventDetail,\n AparteSiblingInfo,\n AparteUsage,\n} from '../../types/index.js';\nimport { resolveConfig } from '../../config/index.js';\nimport { AparteMessageRepository } from '../../runtime/message-repository.js';\nimport type { ExportedMessageRepository } from '../../runtime/message-repository.js';\nimport { populateBubbleFromMessage, type SyncableBubble } from '../bubble/bubble-sync.js';\nimport { cssEscape } from '../../utils/css-escape.js';\nimport { isAwaitingReply } from '../../utils/is-awaiting-reply.js';\nimport { revokeAttachmentUrls } from '../../utils/files-to-attachments.js';\nimport { uuid } from '../../utils/uuid.js';\nimport {\n stampSegmentOnInsert,\n adoptMessageSegments,\n stampSegmentOnUpdate,\n mergeSegmentUpdate,\n renumberSegments,\n openSegmentIds,\n stampSegmentActivity,\n isTerminalStatus,\n} from '../../utils/segments.js';\n\n/**\n * The transcript surface: a light-DOM container with sticky scrolling, token\n * streaming and segment-aware rendering.\n *\n * @element aparte-chat-viewport\n *\n * @attr {boolean} framework-managed - The wrapper's explicit hands-off signal: set it and this\n * element composes none of its own children, because the framework owns them. All four\n * wrappers set it; it was read by this element and declared by nothing until now.\n * @attr {number} scroll-threshold - How close to the bottom still counts as \"at the bottom\".\n * @attr {number} max-rendered-bubbles - Caps how many bubbles stay in the DOM; older ones are released.\n * @attr {number} max-messages - DEPRECATED. It used to evict messages from the model; it now\n * only caps rendered bubbles, which is what `max-rendered-bubbles` says. For real history\n * retention configure the conversation manager instead.\n *\n * @fires {CustomEvent<AparteSegmentUpdateEventDetail>} aparte-segment-update - A segment grew or settled during a stream.\n * @fires aparte-reset-done - `clearAll()` finished emptying the transcript. No detail.\n * @fires {CustomEvent<ApartePathChangedEventDetail>} aparte-path-changed - The active branch path changed, after a retry fork or a navigation.\n *\n * Features:\n * - Smart Scroll: Sticks to bottom when user is at bottom, stops on manual scroll up\n * - appendToken(): For simple content streaming\n * - appendToSegment(): For segment-aware streaming (thinking, code, etc.)\n * - Internal message registry for memory management\n *\n * @example\n * // Three calls are a whole streamed turn.\n * const viewport = document.querySelector('aparte-chat-viewport')!;\n *\n * viewport.appendMessage({ id: 'a1', role: 'assistant', content: '', timestamp: Date.now() });\n * for await (const chunk of tokens) viewport.appendToken('a1', chunk);\n * viewport.completeMessage('a1'); // stops the streaming caret\n */\nexport class AparteChatViewport extends HTMLElement {\n // The scroll surface: an internal `.aparte-viewport-container` div (core mode)\n // or the host element itself (framework-managed mode). HTMLElement covers both.\n private _container: HTMLElement | null = null;\n private _scrollBtn: HTMLButtonElement | null = null;\n private _bottomSpacer: HTMLDivElement | null = null;\n /**\n * In framework-managed mode there is no spacer ELEMENT (an extra child would\n * collide with the framework's own DOM reconciliation). The spacer is an\n * additive `padding-bottom` on the host, tracked here so `_recalculateSpacer`\n * can read the current value without measuring an element.\n */\n private _fwSpacerHeight = 0;\n private _spacerRafId: number | null = null;\n private _spacerFrozenUntil: number = 0;\n private _layoutTransitionMs: number = 0;\n private _repo = new AparteMessageRepository();\n private _isAutoScrollEnabled: boolean = true;\n private _scrollThreshold: number = 50;\n /** When true, the next _autoScroll() call uses smooth instead of instant, then resets. */\n private _smoothScrollOnce: boolean = false;\n /**\n * DOM render cap: the max number of `<aparte-chat-bubble>` elements kept in the\n * DOM at once (a perf ceiling for very long conversations). This NEVER evicts\n * messages from the repository — the full conversation tree and its persistence\n * snapshot stay intact; only the oldest rendered bubbles are dropped from view.\n */\n private _maxRenderedBubbles: number = 1000;\n /** One-time guard for the deprecated `maxMessages` warning. */\n private _warnedMaxMessagesDeprecation = false;\n private _resizeObserver: ResizeObserver | null = null;\n private _mutationObserver: MutationObserver | null = null;\n private _boundResetHandler: (() => void) | null = null;\n /**\n * When true, _reRenderActivePath() only dispatches aparte-path-changed without\n * touching the DOM. Set via setFrameworkManagedDOM(true) when a framework\n * (e.g. Angular) owns the bubble elements.\n */\n private _frameworkManagedDOM = false;\n\n static get observedAttributes(): string[] {\n return ['scroll-threshold', 'max-rendered-bubbles', 'max-messages'];\n }\n\n constructor() {\n super();\n this._handleScroll = this._handleScroll.bind(this);\n }\n\n connectedCallback(): void {\n // Framework wrappers set `framework-managed` DECLARATIVELY so the flag is\n // known BEFORE _render() builds the DOM. Otherwise _render()'s child\n // relocation runs at connect — before the host's setFrameworkManagedDOM()\n // call — moving the framework's bubbles into an internal wrapper and\n // breaking its reconciliation (insertBefore NotFoundError on the next\n // append). See _setupFrameworkDOM().\n if (this.hasAttribute('framework-managed')) this._frameworkManagedDOM = true;\n this._render();\n this._setupEventListeners();\n this._setupObservers();\n this._boundResetHandler = () => this.clearAll();\n window.addEventListener('aparte-reset', this._boundResetHandler);\n window.addEventListener('aparte-config-change', this._onConfigChange);\n }\n\n /**\n * A locale switch changes the reading direction, and `dir` was applied once at\n * render — so a chat already on screen never flipped to RTL until a reload.\n * Only OUR config: an instance-scoped change elsewhere must not touch us.\n */\n private _onConfigChange = (e: Event): void => {\n const detail = (e as CustomEvent).detail as { config?: unknown } | undefined;\n if (detail?.config && detail.config !== resolveConfig(this)) return;\n this._applyDirection();\n };\n\n /** Mirror `locale.direction` onto the scroll container. */\n private _applyDirection(): void {\n const container = this.querySelector('.aparte-viewport-container');\n if (!container) return;\n const direction = resolveConfig(this).getLocale().direction;\n if (direction) container.setAttribute('dir', direction);\n else container.removeAttribute('dir');\n }\n\n disconnectedCallback(): void {\n window.removeEventListener('aparte-config-change', this._onConfigChange);\n if (this._boundResetHandler) {\n window.removeEventListener('aparte-reset', this._boundResetHandler);\n this._boundResetHandler = null;\n }\n this._cleanup();\n }\n\n attributeChangedCallback(name: string, oldValue: string | null, newValue: string | null): void {\n if (oldValue === newValue) return;\n\n switch (name) {\n case 'scroll-threshold':\n this._scrollThreshold = parseInt(newValue || '50', 10);\n break;\n case 'max-rendered-bubbles':\n this._maxRenderedBubbles = parseInt(newValue || '1000', 10);\n this._pruneRenderedBubbles();\n break;\n case 'max-messages':\n // Deprecated alias. It used to evict messages from the tree\n // (destructive, silent data loss); it now only caps rendered\n // bubbles in the DOM. Use `max-rendered-bubbles` instead.\n this._warnMaxMessagesDeprecated();\n this._maxRenderedBubbles = parseInt(newValue || '1000', 10);\n this._pruneRenderedBubbles();\n break;\n }\n }\n\n /**\n * Configure viewport with options\n */\n configure(config: AparteViewportConfig): void {\n if (config.scrollThreshold !== undefined) {\n this._scrollThreshold = config.scrollThreshold;\n }\n if (config.maxRenderedBubbles !== undefined) {\n this._maxRenderedBubbles = config.maxRenderedBubbles;\n this._pruneRenderedBubbles();\n }\n if (config.maxMessages !== undefined) {\n // Deprecated alias (see attributeChangedCallback).\n this._warnMaxMessagesDeprecated();\n this._maxRenderedBubbles = config.maxMessages;\n this._pruneRenderedBubbles();\n }\n if (config.layoutTransitionMs !== undefined) {\n this._layoutTransitionMs = config.layoutTransitionMs;\n }\n }\n\n // ─────────────────────────────────────────────────────────────────────────\n // Simple Content Streaming\n // ─────────────────────────────────────────────────────────────────────────\n\n /**\n * Append a token chunk to a message's content (simple text streaming)\n * @param messageId - Unique identifier for the message\n * @param chunk - Token chunk to append\n */\n appendToken(messageId: string, chunk: string): void {\n const message = this._getOrCreateMessage(messageId);\n\n // Append to simple content\n message.content = (message.content || '') + chunk;\n\n // Notify bubble\n this._notifyBubble(messageId, 'appendToken', chunk);\n this._autoScroll();\n this._scheduleSpacerUpdate();\n }\n\n // ─────────────────────────────────────────────────────────────────────────\n // Segment-Aware Streaming\n // ─────────────────────────────────────────────────────────────────────────\n\n /**\n * Append content to a specific segment within a message\n * @param messageId - Message containing the segment\n * @param segmentId - Target segment ID\n * @param chunk - Content to append\n */\n appendToSegment(messageId: string, segmentId: string, chunk: string): void {\n const message = this._getOrCreateMessage(messageId);\n\n // Find or create segment\n if (!message.segments) {\n message.segments = [];\n }\n\n // REPLACE the segment, never mutate it in place. The bubble holds the very\n // same object — `addSegment` handed one object to the repo and to the bubble —\n // and it appends this chunk itself (see `_notifyBubble` below). Mutating here\n // made the two writes land on one object, so every chunk appeared twice, in\n // the model AND on screen (\"BonjourBonjour le le monde\"). Each view now owns\n // the value it advances.\n const index = message.segments.findIndex(s => s.id === segmentId);\n const segment = index === -1 ? undefined : message.segments[index];\n if (segment && 'content' in segment) {\n message.segments[index] = {\n ...segment,\n content: (segment as { content: string }).content + chunk,\n // Content arriving IS the segment's activity, so this is what\n // `endedAt` measures. Without it a thinking block's end would be\n // whenever someone happened to notice it had stopped — the end of\n // the turn, or the start of the next segment — and both of those\n // silently fold the waiting that followed into the duration.\n ...stampSegmentActivity(segment),\n } as AparteSegment;\n }\n\n // Dispatch segment update event\n this.dispatchEvent(new CustomEvent<AparteSegmentUpdateEventDetail>('aparte-segment-update', {\n bubbles: true,\n composed: true,\n detail: { messageId, segmentId, content: chunk, append: true }\n }));\n\n // Notify bubble\n this._notifyBubble(messageId, 'appendToSegment', chunk, segmentId);\n this._autoScroll();\n }\n\n /**\n * The active (head) message id — the target of `AparteClient`'s 1-argument\n * streaming convention (`addSegment(segment)`, `updateSegment(segmentId,\n * updates)`, …) which operates on \"the current message\". Lets a bare\n * `<aparte-chat-viewport>` be a valid `AparteClient` target, exactly like a\n * framework wrapper's host element.\n */\n private _activeMessageId(): string | null {\n // The head, UNLESS a different message is the one actually streaming.\n //\n // The 1-argument convention means \"operate on the message being streamed\",\n // and this resolved it as \"the head\" — but `appendMessage` always moves the\n // head (the repository advances it to any new child). So any message appended\n // mid-stream re-pointed the rest of the reply: measured with the real element,\n // segment two of message A landed on message B, and `updateSegment` for a\n // segment that genuinely lives on A became a silent no-op.\n //\n // `AparteChatHost` has had `_isOrphan` for exactly this, which is why the\n // framework wrappers were protected and the raw viewport — the documented\n // vanilla quick start — was not. Refusing, like the host does, rather than\n // routing: losing the tail is visible, writing it onto someone else's message\n // is not.\n const head = this._repo.headId;\n const streaming = this._streamingMessageId();\n if (streaming !== null && streaming !== head) return null;\n return head;\n }\n\n /** The id of the message currently streaming, if any. */\n private _streamingMessageId(): string | null {\n for (const message of this._repo.getMessages()) {\n if ((message as { isStreaming?: boolean }).isStreaming) return message.id;\n }\n return null;\n }\n\n /**\n * Add a new segment. Two calling conventions are accepted:\n * - `addSegment(segment)` — AparteClient's 1-arg \"operate on the current\n * (head) message\" convention (also what a wrapper host installs);\n * - `addSegment(messageId, segment)` — explicit standalone form.\n * The first argument's type disambiguates (string = messageId, object =\n * segment), so a raw viewport driven by `AparteClient` no longer drops text\n * (the args used to bind one position short, creating a phantom message).\n */\n addSegment(segment: AparteSegment): void;\n addSegment(messageId: string, segment: AparteSegment): void;\n addSegment(messageIdOrSegment: string | AparteSegment, maybeSegment?: AparteSegment): void {\n const messageId = typeof messageIdOrSegment === 'string' ? messageIdOrSegment : this._activeMessageId();\n const segment = typeof messageIdOrSegment === 'string' ? maybeSegment : messageIdOrSegment;\n if (!messageId || !segment) return;\n\n const message = this._getOrCreateMessage(messageId);\n if (!message.segments) {\n message.segments = [];\n }\n // Identity and start time land BEFORE anyone sees the object: the repo and\n // the bubble are handed the same segment, so a later stamp would leave one\n // of the two holding an unstamped copy. This is one of exactly two places\n // that writes those fields (`aparte-chat-host` is the other) — see\n // `utils/segments.ts` for why it is not the parser.\n const stamped = stampSegmentOnInsert(\n message.segments, segment, messageId,\n // THIS chat's defaults, not the page's: two chats on one page can be\n // configured differently, and the config seam is per instance.\n resolveConfig(this).getSegmentDefaults(segment.type),\n );\n message.segments.push(stamped);\n\n // Notify bubble to render the new segment\n this._notifyBubble(messageId, 'addSegment', stamped);\n this._autoScroll();\n }\n\n /**\n * Update a segment. `updateSegment(segmentId, updates)` (1-arg client\n * convention → current message) or `updateSegment(messageId, segmentId,\n * updates)` (explicit). Disambiguated by arity: the 3rd arg is absent and\n * the 2nd is the `updates` object in the 1-arg form.\n */\n updateSegment(segmentId: string, updates: Partial<AparteSegment>): void;\n updateSegment(messageId: string, segmentId: string, updates: Partial<AparteSegment>): void;\n updateSegment(a: string, b: string | Partial<AparteSegment>, c?: Partial<AparteSegment>): void {\n const clientForm = c === undefined && typeof b === 'object';\n const messageId = clientForm ? this._activeMessageId() : a;\n const segmentId = clientForm ? a : (b as string);\n const updates = clientForm ? (b as Partial<AparteSegment>) : (c as Partial<AparteSegment>);\n if (!messageId) return;\n\n const message = this._repo.getMessageById(messageId);\n if (!message?.segments) return;\n\n const segmentIndex = message.segments.findIndex(s => s.id === segmentId);\n if (segmentIndex !== -1) {\n const current = message.segments[segmentIndex]!;\n // An update that settles the segment carries its `endedAt`. Stamped\n // here rather than at each call site, so `completeSegment`, a tool\n // resolution and an app's own `updateSegment` all measure alike.\n const stamped = stampSegmentOnUpdate(current, updates);\n message.segments[segmentIndex] = mergeSegmentUpdate(current, stamped);\n\n this._notifyBubble(messageId, 'updateSegment', { segmentId, updates: stamped });\n }\n }\n\n /**\n * Remove a segment. `removeSegment(segmentId)` (1-arg client convention →\n * current message) or `removeSegment(messageId, segmentId)` (explicit).\n */\n removeSegment(segmentId: string): void;\n removeSegment(messageId: string, segmentId: string): void;\n removeSegment(a: string, b?: string): void {\n const clientForm = b === undefined;\n const messageId = clientForm ? this._activeMessageId() : a;\n const segmentId = clientForm ? a : b;\n if (!messageId || !segmentId) return;\n\n const message = this._repo.getMessageById(messageId);\n if (message?.segments) {\n const idx = message.segments.findIndex(s => s.id === segmentId);\n if (idx !== -1) {\n message.segments.splice(idx, 1);\n // `index` is a position, so a removal has to close the gap it left.\n renumberSegments(message.segments);\n }\n }\n this._notifyBubble(messageId, 'removeSegment', segmentId);\n }\n\n /**\n * Start a new streaming segment (e.g., thinking or code block)\n * Creates the segment and marks it as streaming\n */\n startSegment(messageId: string, segment: AparteSegment): void {\n const streamingSegment = { ...segment, isStreaming: true };\n this.addSegment(messageId, streamingSegment);\n }\n\n /**\n * Complete a streaming segment\n */\n completeSegment(messageId: string, segmentId: string): void {\n this.updateSegment(messageId, segmentId, { isStreaming: false });\n }\n\n /**\n * Persist token usage on a message and propagate to the live bubble, which is\n * what allows the info (\"i\") action to render — provided the app declared it\n * with `aparteGlobalConfig.setBubbleActions({ info: true })`; it is off by default,\n * since the popover it opens belongs to the app.\n */\n setUsage(messageId: string, usage: AparteUsage): void {\n const message = this._repo.getMessageById(messageId);\n if (message) message.usage = usage;\n this._notifyBubble(messageId, 'setUsage', usage);\n }\n\n // ─────────────────────────────────────────────────────────────────────────\n // Message Management\n // ─────────────────────────────────────────────────────────────────────────\n\n /**\n * Mark a message as finished streaming\n */\n completeMessage(messageId: string): void {\n const message = this._repo.getMessageById(messageId);\n if (message) {\n message.isStreaming = false;\n message.status = 'completed';\n\n // The message's end IS its segments' end: nothing in the stream says a\n // thinking block is over. Routed through `updateSegment` rather than\n // written onto the objects, so the bubble is told as well — a silent\n // mutation stamped the model and left the renderer thinking it was still\n // streaming, which is exactly what a browser run showed.\n this._settleSegments(messageId, message);\n\n this._notifyBubble(messageId, 'complete', { status: 'completed' });\n this._recalculateSpacer();\n }\n }\n\n /**\n * Close a finished message's still-open segments, one `updateSegment` each.\n *\n * Deliberately NOT a loop that writes `isStreaming` onto the objects: that path\n * stamps the model and tells the bubble nothing, so a renderer never learns its\n * segment settled — no `endedAt` in the rendered label, and no final Markdown\n * flush either. Going through `updateSegment` reuses the one path that does\n * both.\n */\n private _settleSegments(messageId: string, message: AparteMessage): void {\n if (!message.segments) return;\n for (const id of openSegmentIds(message.segments)) {\n this.updateSegment(messageId, id, { isStreaming: false });\n }\n }\n\n /**\n * Atomic update for a message by ID\n * Supports updating content, status, segments, and other metadata\n */\n updateMessage(messageId: string, updates: Partial<AparteMessage>): void {\n const message = this._repo.getMessageById(messageId);\n if (!message) return;\n\n // Apply updates to internal state\n Object.assign(message, updates);\n\n // Map AparteStatus to isStreaming for legacy bubble support\n if (updates.status) {\n message.isStreaming = updates.status === 'streaming' || updates.status === 'pending';\n // …and close the segments, because THIS is the path a completed turn\n // takes: both agent loops report the end with\n // `updateMessage({ status: 'completed' })`, and `completeMessage()` is\n // called by nobody. Without this a thinking segment kept `isStreaming`\n // unset forever and never recorded an `endedAt` — the duration only\n // worked for tool calls, which settle by their own status.\n if (isTerminalStatus(updates.status)) this._settleSegments(messageId, message);\n }\n\n // Notify bubble\n this._notifyBubble(messageId, 'update', updates);\n this._autoScroll();\n }\n\n /**\n * Add a complete message to the message registry.\n *\n * @remarks\n * **Framework-managed DOM only.** Records the message in the tree but does NOT\n * paint a bubble on its own (a framework wrapper reconciles the DOM from the\n * list). For standalone / vanilla usage call {@link appendMessage} instead,\n * which both records the message and creates its bubble element.\n */\n addMessage(message: AparteMessage): void {\n // Adopted, not stamped: this writes straight to the repository, so it is the\n // caller handing over a message they already hold rather than a turn starting.\n this._repo.addOrUpdateMessage(this._repo.headId, adoptMessageSegments({ ...message }));\n this._pruneRenderedBubbles();\n this._autoScroll();\n }\n\n /**\n * Append a new message and create its bubble in the DOM.\n * Implements the same contract as the Angular wrapper's appendMessage(),\n * making aparte-chat-viewport a fully standalone target for aparte-client.\n * When `_frameworkManagedDOM` is true, only the internal repo is updated —\n * the framework owns the DOM and will create the bubble element itself.\n */\n appendMessage(message: AparteMessage, options?: { historical?: boolean }): void {\n /*\n * A message may arrive with its segments already populated, and the two reasons\n * are not the same act: an app injecting a prefix or the client's own error\n * fallback is producing something NOW, while `setMessages` is handing back\n * something that happened. Both used to take the live path, so reloading a\n * three-week-old conversation stamped every one of its segments with `Date.now()`.\n *\n * Provenance is a parameter and not a guess. \"Arrived with its segments\" cannot\n * mean \"historical\" — `AparteClient` appends a message with a ready-made error\n * segment live, and a consumer streaming into a seeded segment is doing the same\n * thing. Defaulting to live keeps every existing caller's behaviour.\n *\n * Either way the segments go through a seam and into a NEW array, so `index`\n * follows the position and the caller's array is not retained.\n */\n const stored: AparteMessage = options?.historical\n ? adoptMessageSegments(message)\n : message.segments?.length\n ? { ...message, segments: message.segments.reduce<AparteSegment[]>(\n (acc, segment) => {\n acc.push(stampSegmentOnInsert(\n acc, segment, message.id,\n resolveConfig(this).getSegmentDefaults(segment.type),\n ));\n return acc;\n },\n [],\n ) }\n : { ...message };\n this._repo.addOrUpdateMessage(this._repo.headId, stored);\n if (!this._frameworkManagedDOM) {\n const wrapper = this.querySelector('.aparte-messages-wrapper');\n if (wrapper) {\n const bubble = document.createElement('aparte-chat-bubble') as HTMLElement;\n bubble.setAttribute('message-id', message.id);\n bubble.setAttribute('role', message.role);\n if (message.timestamp) bubble.setAttribute('timestamp', String(message.timestamp));\n if (message.content) bubble.setAttribute('content', message.content);\n // Also true for an empty assistant message with no status: an\n // imperative \"the reply is coming\" shell, which otherwise rendered\n // as a finished answer (action bar and all) before a single token.\n if (isAwaitingReply(message)) {\n bubble.setAttribute('streaming', '');\n }\n // Insert before spacer so spacer stays last\n if (this._bottomSpacer && this._bottomSpacer.parentNode === wrapper) {\n wrapper.insertBefore(bubble, this._bottomSpacer);\n } else {\n wrapper.appendChild(bubble);\n }\n // Attributes alone can't carry segments / attachments / usage —\n // push them through the same helper the full render path uses,\n // or an imperatively appended message renders text-only.\n //\n // `stored`, not `message`: the bubble has to see the STAMPED segments\n // the repository holds. Handed the caller's object it rendered ones\n // with no `index` or `startedAt`, so the same segment was stamped in\n // the model and bare on screen — and an app reading them back off the\n // bubble got the bare ones.\n populateBubbleFromMessage(bubble as unknown as SyncableBubble, stored);\n }\n }\n this._pruneRenderedBubbles();\n this._recalculateSpacer();\n // User sending always anchors to bottom regardless of scroll position.\n if (message.role === 'user') {\n this._isAutoScrollEnabled = true;\n // Smooth scroll for user-initiated sends. Streaming auto-scroll stays\n // instant (via _autoScroll) so it can keep up with rapid token bursts.\n requestAnimationFrame(() => this._smoothScrollToBottom());\n } else {\n this._autoScroll();\n }\n }\n\n /**\n * Update the last message content, optionally appending.\n * Implements the same contract as the Angular wrapper's updateLastMessage(),'\n * making aparte-chat-viewport a fully standalone streaming target for aparte-client.\n */\n updateLastMessage(content: string, options?: { append?: boolean }): void {\n const lastId = this._repo.headId;\n if (!lastId) return;\n if (options?.append) {\n this.appendToken(lastId, content);\n } else {\n const message = this._repo.getMessageById(lastId);\n if (message) message.content = content;\n this._notifyBubble(lastId, 'appendToken', content);\n }\n }\n\n /**\n * Add a new sibling branch to an assistant message (retry flow).\n * Creates a new empty assistant message as a sibling of `messageId`\n * under the same parent, switches the active branch to it, and\n * re-renders the active path.\n * @returns The index of the new branch in the siblings array, or 0 on failure.\n */\n addBranch(messageId: string): number {\n const meta = this._repo.getMessage(messageId);\n if (!meta) return 0;\n\n const newMsg: AparteMessage = {\n id: uuid(),\n role: 'assistant',\n content: '',\n status: 'pending',\n timestamp: Date.now(),\n };\n this._repo.addOrUpdateMessage(meta.parentId, newMsg);\n this._repo.switchToBranch(newMsg.id);\n this._reRenderActivePath();\n\n const siblings = this._repo.getBranches(newMsg.id);\n return siblings.indexOf(newMsg.id);\n }\n\n /**\n * Add a new message relative to `existingId`, switch to it, and re-render.\n *\n * Role-aware semantics:\n * - existingId is an **assistant** message → create a sibling (same parent),\n * so the active path replaces the old response with the new one.\n * - existingId is a **user** message → create a child of that message,\n * so the user message stays on the active path and the new response follows it.\n *\n * Returns the new message's ID, or null if `existingId` is not found.\n */\n addSiblingOf(existingId: string, newMessage: AparteMessage): string | null {\n const meta = this._repo.getMessage(existingId);\n if (!meta) return null;\n\n // User messages: new response is a child (keep user on active path).\n // Assistant messages: new response is a sibling (replace old response).\n const parentId = meta.message.role === 'user'\n ? existingId\n : meta.parentId;\n this._repo.addOrUpdateMessage(parentId, { ...newMessage });\n this._repo.switchToBranch(newMessage.id);\n this._reRenderActivePath();\n return newMessage.id;\n }\n\n /**\n * Navigate to the previous or next sibling branch of a message.\n * Triggers a full re-render of the active path.\n */\n navigateBranch(messageId: string, direction: 'prev' | 'next'): void {\n const siblings = this._repo.getBranches(messageId);\n const currentIdx = siblings.indexOf(messageId);\n if (currentIdx === -1) return;\n\n const targetIdx = direction === 'prev' ? currentIdx - 1 : currentIdx + 1;\n if (targetIdx < 0 || targetIdx >= siblings.length) return;\n\n // Branch navigation is a deliberate user action, so it must not yank a user\n // who is reading mid-transcript: auto-scroll goes off and neither the spacer\n // recalculation nor the MutationObserver callback will scroll them away.\n //\n // But if they were already AT the bottom, staying there IS the expected\n // behaviour — and switching auto-follow off there is what left the\n // scroll-to-bottom button offering to scroll nowhere (bonaparte, React). It\n // also protects the swap itself: a rebuild's height flickers (measured on\n // React: 1730 → 1934 → 1730px as the new bubble renders and settles), so a\n // reader pinned to the bottom would drift up by whatever the flicker was.\n this._isAutoScrollEnabled = this._isAtBottom();\n this._updateScrollButton();\n\n this._repo.switchToBranch(siblings[targetIdx]!);\n this._reRenderActivePath();\n }\n\n /**\n * Remove ALL responses to a user message (every child branch) and set head\n * back to `userMessageId`. Cleaner than `truncateFrom` for edit flows: it\n * discards stale sibling branches so the regenerated response starts alone.\n */\n truncateResponsesAfter(userMessageId: string): void {\n const prevMessages = this._repo.getMessages();\n this._repo.clearChildren(userMessageId);\n\n // In framework-managed mode the host (Angular @for, React, etc.) owns\n // the bubble DOM. Removing nodes from under it triggers\n // `NotFoundError: Failed to execute 'insertBefore'` on the next change\n // detection cycle because the framework's view tree no longer matches\n // the actual DOM. Skip the manual cleanup and let the framework\n // reconcile when the consumer updates its message array.\n if (!this._frameworkManagedDOM) {\n const wrapper = this.querySelector('.aparte-messages-wrapper');\n if (wrapper) {\n const startIdx = prevMessages.findIndex(m => m.id === userMessageId);\n const toRemove = startIdx >= 0 ? prevMessages.slice(startIdx + 1) : [];\n for (const m of toRemove) {\n wrapper.querySelector(`aparte-chat-bubble[message-id=\"${cssEscape(m.id)}\"]`)?.remove();\n }\n }\n }\n }\n\n /**\n * Remove all messages from `messageId` onwards (inclusive) from state and DOM.\n * Used by edit to truncate history before re-generating.\n */\n truncateFrom(messageId: string): void {\n const allMsgs = this._repo.getMessages();\n const startIdx = allMsgs.findIndex(m => m.id === messageId);\n if (startIdx === -1) return;\n\n const toRemove = allMsgs.slice(startIdx).map(m => m.id);\n this._repo.resetHead(messageId);\n\n // See the note in truncateResponsesAfter: skip DOM ops when a framework\n // owns the bubble elements.\n if (!this._frameworkManagedDOM) {\n const wrapper = this.querySelector('.aparte-messages-wrapper');\n for (const id of toRemove) {\n wrapper?.querySelector(`aparte-chat-bubble[message-id=\"${cssEscape(id)}\"]`)?.remove();\n }\n }\n }\n\n /**\n * Get a message by ID\n */\n getMessage(messageId: string): AparteMessage | undefined {\n return this._repo.getMessageById(messageId);\n }\n\n getMessages(): AparteMessage[] {\n return this._repo.getMessages();\n }\n\n /**\n * Export the full conversation tree (all branches, not just the active path).\n * The returned snapshot can be persisted and restored via `importTree()`.\n */\n exportTree(): ExportedMessageRepository {\n return this._repo.export();\n }\n\n /**\n * Import a previously-exported tree snapshot, restoring the full branch\n * topology and the active head. Replaces any existing repo content.\n *\n * Always calls `_reRenderActivePath()`:\n * - In native DOM mode: rebuilds bubble elements.\n * - In framework-managed mode: skips DOM manipulation but dispatches\n * `aparte-path-changed` with sibling metadata so the wrapper can update\n * branch arrows on already-rendered bubbles.\n */\n importTree(tree: ExportedMessageRepository): void {\n // Not `clearAll()`: an import re-populates from a snapshot that may hold the\n // very attachment objects currently in the repo — which is exactly what a\n // conversation load does. See the note in `clearAll`.\n this.clearAll({ revokeAttachments: false });\n // A snapshot is history by definition, and this is the path that used to write\n // it to the repository RAW — so `messageId`/`index` stayed whatever the storage\n // held, and a tree saved before those fields existed came back without them.\n // It also runs AFTER `setMessages` on a conversation load, so whatever that\n // stamped was being replaced by this anyway: two paths, one of them silent.\n this._repo.import({\n ...tree,\n messages: tree.messages.map((entry) => ({\n ...entry,\n message: adoptMessageSegments(entry.message),\n })),\n });\n this._reRenderActivePath();\n }\n\n /**\n * Clear all messages and remove all bubble elements from the DOM.\n * Also dispatches a aparte-reset-done event.\n *\n * In framework-managed mode the DOM is owned by the host framework\n * (Angular @for, React, etc.) and we must not clear `innerHTML` — doing\n * so desynchronises the framework's view tree from the live DOM and the\n * next change-detection pass throws `NotFoundError` on insertBefore.\n */\n clearAll(options?: { revokeAttachments?: boolean }): void {\n /*\n * Release the attachments' object URLs before dropping the messages: after\n * `_repo.clear()` there is no way left to reach them, and nothing else\n * revoked them — so every `File` a session had sent stayed reachable for\n * the life of the page.\n *\n * UNLESS the caller is about to put the same messages back. Two callers do:\n * `setMessages` and `importTree`, and `ConversationController._load` runs\n * BOTH in sequence over one conversation. `export()` stores live `node.current`\n * references, so `conv.messages` and `conv.tree` share the very same\n * attachment objects — meaning the second clear revoked the object URLs of\n * the conversation being opened. Every image and file chip was dead on load,\n * and re-opening revoked twice.\n *\n * A reset (`aparte-reset`, the public `clearAll()`) still revokes: there the\n * messages really are gone.\n */\n if (options?.revokeAttachments !== false) {\n for (const message of this._repo.getMessages()) {\n revokeAttachmentUrls(message.attachments);\n }\n }\n this._repo.clear();\n if (!this._frameworkManagedDOM) {\n const wrapper = this.querySelector('.aparte-messages-wrapper');\n if (wrapper) {\n // Remove bubbles individually so the spacer div is preserved.\n Array.from(wrapper.querySelectorAll('aparte-chat-bubble')).forEach(b => b.remove());\n }\n }\n // Reset spacer and scroll button regardless of mode\n this._setSpacerHeight(0);\n this._isAutoScrollEnabled = true;\n this._updateScrollButton();\n this.dispatchEvent(new CustomEvent('aparte-reset-done', { bubbles: true, composed: true }));\n }\n\n /**\n * Clear all messages\n * @deprecated Use clearAll() to also remove DOM bubbles\n */\n clearMessages(): void {\n this._repo.clear();\n }\n\n /**\n * Replace the entire message list in one shot. Used when switching\n * conversations: clears existing repo + DOM, then appends each message.\n *\n * In framework-managed mode the framework re-renders the bubble DOM\n * itself; we only update the internal repo (used by aparte-client to\n * build chat history).\n */\n setMessages(messages: AparteMessage[]): void {\n // Same reason as `importTree`: the incoming messages may BE the outgoing\n // ones, and a conversation the user can switch back to still holds them.\n this.clearAll({ revokeAttachments: false });\n for (const m of messages) {\n // Historical by definition: this replaces the transcript with a list the\n // caller already had. Nothing here is starting now.\n this.appendMessage(m, { historical: true });\n }\n }\n\n /**\n * Scroll to bottom of viewport\n */\n scrollToBottom(): void {\n this._scrollToBottom();\n }\n\n /**\n * Reset the bottom spacer to 0 height immediately and freeze it for\n * 350 ms so the host-app layout transition (e.g. flex: 0→1 animation)\n * does not trigger a premature recalculation with mid-animation geometry.\n * Call before a full messages swap.\n */\n resetSpacer(): void {\n this._setSpacerHeight(0);\n // Freeze spacer recalculation for the duration of any host layout\n // transition (configured via `layoutTransitionMs`). Without this,\n // ResizeObserver fires on every animation frame while the container\n // is still growing, producing incorrect spacer values.\n if (this._layoutTransitionMs > 0) {\n this._spacerFrozenUntil = Date.now() + this._layoutTransitionMs;\n }\n }\n\n /**\n * Enable or disable auto-scroll\n */\n setAutoScroll(enabled: boolean): void {\n this._isAutoScrollEnabled = enabled;\n }\n\n /**\n * Signal that a framework (e.g. Angular) manages the bubble DOM.\n * When true, branch navigation dispatches `aparte-path-changed` without\n * clearing/rebuilding the messages wrapper — the framework re-renders instead.\n */\n setFrameworkManagedDOM(managed: boolean): void {\n this._frameworkManagedDOM = managed;\n }\n\n // ─────────────────────────────────────────────────────────────────────────\n // Private Helpers\n // ─────────────────────────────────────────────────────────────────────────\n\n private _getOrCreateMessage(messageId: string): AparteMessage {\n const existing = this._repo.getMessageById(messageId);\n if (existing) return existing;\n\n const message: AparteMessage = {\n id: messageId,\n role: 'assistant',\n content: '',\n timestamp: Date.now(),\n isStreaming: true,\n status: 'streaming'\n };\n this._repo.addOrUpdateMessage(this._repo.headId, message);\n return message;\n }\n\n private _notifyBubble(messageId: string, action: string, payload?: unknown, segmentId?: string): void {\n // Find the bubble element — the native `<aparte-chat-bubble>` OR a custom\n // element opting into live streaming via `data-aparte-bubble` (so a raw-core\n // consumer can replace the bubble tag and still receive token/segment\n // pushes, not just a CSS restyle).\n const bubble = this.querySelector(\n `aparte-chat-bubble[message-id=\"${cssEscape(messageId)}\"], [data-aparte-bubble][message-id=\"${cssEscape(messageId)}\"]`,\n ) as HTMLElement & {\n appendToken?: (chunk: string) => void;\n appendToSegment?: (segmentId: string, chunk: string) => void;\n addSegment?: (segment: AparteSegment) => void;\n updateSegment?: (segmentId: string, updates: Partial<AparteSegment>) => void;\n removeSegment?: (segmentId: string) => void;\n setUsage?: (usage: AparteUsage) => void;\n updateMessage?: (updates: Partial<AparteMessage>) => void;\n };\n\n if (!bubble) return;\n\n switch (action) {\n case 'appendToken':\n bubble.appendToken?.(payload as string);\n break;\n case 'appendToSegment':\n bubble.appendToSegment?.(segmentId!, payload as string);\n break;\n case 'addSegment':\n bubble.addSegment?.(payload as AparteSegment);\n break;\n case 'updateSegment': {\n const { segmentId: sid, updates: segUpdates } = payload as { segmentId: string; updates: Partial<AparteSegment> };\n bubble.updateSegment?.(sid, segUpdates);\n break;\n }\n case 'removeSegment':\n bubble.removeSegment?.(payload as string);\n break;\n case 'setUsage':\n bubble.setUsage?.(payload as AparteUsage);\n break;\n case 'update': {\n // Atomic update: forward it when it carries anything the bubble\n // renders. `content` and `attachments` used to be filtered out\n // here, so an edit (which sends `{ content }`) updated the repo —\n // and therefore the history sent to the model — while the bubble\n // kept displaying the old text.\n const updates = payload as Record<string, unknown>;\n const renderable = ['status', 'segments', 'content', 'attachments', 'usage'];\n if (renderable.some((key) => key in updates)) {\n bubble.updateMessage?.(payload as Partial<AparteMessage>);\n }\n break;\n }\n case 'complete':\n bubble.updateMessage?.(payload as Partial<AparteMessage>);\n break;\n }\n }\n\n /**\n * Re-render the active path: clears the messages wrapper and rebuilds bubbles\n * for every message on the current active branch path (root → head).\n * Calls `setSiblings(count, index)` on each bubble that has siblings, and\n * dispatches `aparte-path-changed` so Angular wrapper can sync its signal.\n *\n * When `_frameworkManagedDOM` is true (set via setFrameworkManagedDOM), the DOM\n * manipulation is skipped — only `aparte-path-changed` is dispatched so the\n * framework can re-render from updated signal state.\n */\n private _reRenderActivePath(): void {\n const activeMessages = this._repo.getMessages();\n\n // Compute sibling metadata once and reuse — keeps the event payload\n // identical between framework-managed and default DOM modes.\n const siblingsInfo: AparteSiblingInfo[] = activeMessages.map(m => {\n const sibs = this._repo.getBranches(m.id);\n return { id: m.id, count: sibs.length, index: sibs.indexOf(m.id) };\n });\n\n if (this._frameworkManagedDOM) {\n this._dispatchPathChanged(activeMessages, siblingsInfo);\n return;\n }\n\n const wrapper = this.querySelector('.aparte-messages-wrapper');\n if (!wrapper) return;\n wrapper.innerHTML = '';\n\n // Only materialise the last N messages of the active path (DOM render cap).\n // The repository keeps the full path; this is a perf ceiling, not eviction.\n const startIdx = Math.max(0, activeMessages.length - this._maxRenderedBubbles);\n for (let i = startIdx; i < activeMessages.length; i++) {\n const message = activeMessages[i]!;\n const sibInfo = siblingsInfo[i];\n\n const bubble = document.createElement('aparte-chat-bubble');\n bubble.setAttribute('message-id', message.id);\n bubble.setAttribute('role', message.role);\n if (message.timestamp) bubble.setAttribute('timestamp', String(message.timestamp));\n if (isAwaitingReply(message)) {\n bubble.setAttribute('streaming', '');\n }\n wrapper.appendChild(bubble);\n\n // Reconcile content / segments / attachments / sibling-picker via\n // the shared helper — same code path the framework wrappers use,\n // so the contract stays in lockstep.\n populateBubbleFromMessage(bubble as unknown as SyncableBubble, message, sibInfo);\n }\n\n this._dispatchPathChanged(activeMessages, siblingsInfo);\n this._recalculateSpacer();\n\n // No post-swap re-measure of the auto-scroll INTENT here, deliberately: a\n // rebuild's height flickers, and a one-shot measurement that lands mid-flicker\n // can only get it wrong (it would disarm auto-follow for a reader who is\n // pinned to the bottom). The intent is decided once, in `navigateBranch`, from\n // the position the user was actually in; the button re-derives itself from\n // geometry on every scroll and on every post-mutation frame.\n }\n\n private _dispatchPathChanged(messages: AparteMessage[], siblings: AparteSiblingInfo[]): void {\n const detail: ApartePathChangedEventDetail = { messages, siblings };\n this.dispatchEvent(new CustomEvent<ApartePathChangedEventDetail>('aparte-path-changed', {\n bubbles: true,\n composed: true,\n detail,\n }));\n }\n\n private _autoScroll(): void {\n if (this._isAutoScrollEnabled) {\n if (this._smoothScrollOnce) {\n this._smoothScrollOnce = false;\n requestAnimationFrame(() => this._smoothScrollToBottom());\n } else {\n requestAnimationFrame(() => this._scrollToBottom());\n }\n }\n this._pruneRenderedBubbles();\n }\n\n /**\n * Request that the next auto-scroll triggered by a DOM mutation uses\n * smooth behaviour instead of instant. Call this just before adding a\n * user message bubble so the viewport animates down rather than jumping.\n * Resets automatically after the first auto-scroll fires.\n */\n requestSmoothScroll(): void {\n this._smoothScrollOnce = true;\n }\n\n private _render(): void {\n // Framework-managed: the framework owns the bubble children directly.\n // Do NOT build the internal container/wrapper or relocate children.\n if (this._frameworkManagedDOM) {\n this._setupFrameworkDOM();\n return;\n }\n // Light DOM rendering\n // Preserving existing children in render allows framework composition\n if (!this.querySelector('.aparte-viewport-container')) {\n const container = document.createElement('div');\n container.className = 'aparte-viewport-container';\n\n // Set direction based on current locale\n const locale = resolveConfig(this).getLocale();\n if (locale.direction) {\n container.setAttribute('dir', locale.direction);\n }\n\n container.setAttribute('role', 'log');\n container.setAttribute('aria-live', 'polite');\n container.setAttribute('aria-atomic', 'false');\n container.setAttribute('aria-relevant', 'additions');\n\n const wrapper = document.createElement('div');\n wrapper.className = 'aparte-messages-wrapper';\n\n // Move existing children (bubbles) into wrapper\n while (this.firstChild) {\n wrapper.appendChild(this.firstChild);\n }\n\n // Bottom spacer — always last in wrapper, height driven by _recalculateSpacer()\n this._bottomSpacer = document.createElement('div');\n this._bottomSpacer.className = 'aparte-bottom-spacer';\n this._bottomSpacer.setAttribute('aria-hidden', 'true');\n wrapper.appendChild(this._bottomSpacer);\n\n container.appendChild(wrapper);\n this.appendChild(container);\n\n this._container = container;\n\n // Scroll-to-bottom button — absolutely positioned over the viewport\n this._scrollBtn = document.createElement('button');\n this._scrollBtn.className = 'aparte-scroll-btn aparte-scroll-btn--hidden';\n this._scrollBtn.setAttribute('type', 'button');\n this._scrollBtn.setAttribute('aria-label', 'Scroll to bottom');\n const scrollIcon = resolveConfig(this).getIcon('scrollDown');\n this._scrollBtn.innerHTML = scrollIcon\n || `<svg width=\"16\" height=\"16\" viewBox=\"0 0 24 24\" fill=\"none\" stroke=\"currentColor\" stroke-width=\"2\" stroke-linecap=\"round\" stroke-linejoin=\"round\"><line x1=\"12\" y1=\"5\" x2=\"12\" y2=\"19\"/><polyline points=\"19 12 12 19 5 12\"/></svg>`;\n this.appendChild(this._scrollBtn);\n } else {\n this._container = this.querySelector('.aparte-viewport-container');\n this._scrollBtn = this.querySelector('.aparte-scroll-btn');\n this._bottomSpacer = this.querySelector('.aparte-bottom-spacer');\n }\n }\n\n /**\n * DOM setup for framework-managed mode. The framework (React/Vue/Svelte/\n * Angular) renders the bubble elements as DIRECT children of the host, so we\n * must NOT relocate them into an internal wrapper — that desyncs the\n * framework's virtual DOM from the real DOM and throws NotFoundError on the\n * next append. Instead the HOST itself is the scroll surface, the spacer is\n * additive `padding-bottom` (no element), and the scroll button is a\n * `position: sticky` TRAILING foreign child (kept last by the framework\n * MutationObserver). A present foreign node is still a valid `insertBefore`\n * reference for the framework — the crash came from a RELOCATED node, not a\n * foreign one.\n */\n private _setupFrameworkDOM(): void {\n this._container = this;\n this._bottomSpacer = null;\n if (this.classList.contains('aparte-viewport--framework')) {\n this._scrollBtn = this.querySelector(':scope > .aparte-scroll-btn') as HTMLButtonElement | null;\n return; // already set up (re-entrant _render)\n }\n this.classList.add('aparte-viewport--framework');\n\n const scrollBtn = document.createElement('button');\n scrollBtn.className = 'aparte-scroll-btn aparte-scroll-btn--hidden';\n scrollBtn.setAttribute('type', 'button');\n scrollBtn.setAttribute('aria-label', 'Scroll to bottom');\n const scrollIcon = resolveConfig(this).getIcon('scrollDown');\n scrollBtn.innerHTML = scrollIcon\n || `<svg width=\"16\" height=\"16\" viewBox=\"0 0 24 24\" fill=\"none\" stroke=\"currentColor\" stroke-width=\"2\" stroke-linecap=\"round\" stroke-linejoin=\"round\"><line x1=\"12\" y1=\"5\" x2=\"12\" y2=\"19\"/><polyline points=\"19 12 12 19 5 12\"/></svg>`;\n this.appendChild(scrollBtn);\n this._scrollBtn = scrollBtn;\n }\n\n /**\n * Keep the sticky scroll button as the last child in framework-managed mode.\n * The framework usually inserts bubbles before its own trailing nodes (so the\n * button stays last), but a plain `appendChild` at the very end (e.g. some\n * Angular @for paths) can land a bubble after it — move it back. Idempotent:\n * a no-op when already last, so it never loops the MutationObserver.\n */\n private _keepScrollButtonLast(): void {\n if (!this._scrollBtn) return;\n if (this.lastElementChild !== this._scrollBtn) {\n this.appendChild(this._scrollBtn);\n }\n }\n\n /** Current spacer height — a padding value (framework) or the element's height (core). */\n private _getSpacerHeight(): number {\n if (this._frameworkManagedDOM) return this._fwSpacerHeight;\n return this._bottomSpacer?.offsetHeight ?? 0;\n }\n\n /** Set the spacer — host padding (framework, additive to base padding) or element height (core). */\n private _setSpacerHeight(px: number): void {\n if (this._frameworkManagedDOM) {\n this._fwSpacerHeight = px;\n this.style.setProperty('--aparte-fw-spacer', `${px}px`);\n } else if (this._bottomSpacer) {\n this._bottomSpacer.style.height = `${px}px`;\n }\n }\n\n // Bound fields, not inline arrows: a custom element is re-connected every\n // time it is MOVED in the DOM (a portal, a dialog, a framework re-parenting),\n // so `_setupEventListeners` runs again each time. An inline arrow can never\n // be handed to `removeEventListener`, so it just accumulates — one branch\n // click then ran N handlers, N active-path re-renders and N storage writes\n // through the conversation controller. The window listeners next to these\n // were always removed properly; these two, attached to `this`, were not.\n private readonly _onScrollBtnClick = (): void => {\n this._isAutoScrollEnabled = true;\n this._smoothScrollToBottom();\n this._updateScrollButton();\n };\n\n private readonly _onBranchNavigate = (e: Event): void => {\n const evt = e as CustomEvent<{ messageId: string; direction: 'prev' | 'next' }>;\n evt.stopPropagation();\n this.navigateBranch(evt.detail.messageId, evt.detail.direction);\n };\n\n private _setupEventListeners(): void {\n this._container?.addEventListener('scroll', this._handleScroll, { passive: true });\n this._scrollBtn?.addEventListener('click', this._onScrollBtnClick);\n this.addEventListener('aparte-branch-navigate', this._onBranchNavigate);\n }\n\n private _setupObservers(): void {\n this._resizeObserver = new ResizeObserver(() => {\n if (this._isAutoScrollEnabled) {\n this._scrollToBottom();\n }\n this._recalculateSpacer();\n });\n\n const wrapper = this.querySelector('.aparte-messages-wrapper');\n\n if (this._container) {\n // Fires on window/viewport resize and when the composer grows.\n // NOTE: we intentionally do NOT observe .aparte-messages-wrapper here.\n // The wrapper contains the spacer div — observing it would create a\n // feedback loop: spacer changes → wrapper resizes → ResizeObserver →\n // _recalculateSpacer → spacer changes → … → height grows unbounded.\n // Streaming content growth is handled by direct _scheduleSpacerUpdate()\n // calls from appendToken(). New bubbles are handled by MutationObserver.\n // Framework-managed: _container IS the host, whose `padding-bottom`\n // carries the spacer — observe the BORDER box (fixed host size) so a\n // spacer/padding change does NOT re-trigger _recalculateSpacer and\n // loop. Core mode observes the container (no dynamic padding).\n if (this._frameworkManagedDOM) {\n this._resizeObserver.observe(this._container, { box: 'border-box' });\n } else {\n this._resizeObserver.observe(this._container);\n }\n }\n\n this._mutationObserver = new MutationObserver(() => {\n // Keep the sticky scroll button trailing after framework appends.\n if (this._frameworkManagedDOM) this._keepScrollButtonLast();\n // The gate is tested HERE, when the frame is queued, and moving it\n // inside the callback is not the improvement it looks like.\n //\n // Queue-time looks like a race — the user could scroll up before the\n // frame runs and be dragged back. Testing it at run-time instead was\n // tried and reverted: a branch swap replaces bubbles, the resulting\n // scroll event makes `_isAtBottom()` briefly false, and the deferred\n // check then refuses to re-anchor, leaving a scroll-to-bottom button on\n // a transcript that IS at the bottom (caught by\n // `bubble-actions.spec.ts` on WebKit, 3 runs out of 3).\n //\n // So queue-time is deliberate: it captures the user's intent BEFORE the\n // DOM churn can confuse the \"am I at the bottom?\" heuristic. Reading it\n // correctly in both cases needs a way to tell our own programmatic\n // scroll from a real gesture — see the note in `_handleScroll`.\n if (this._isAutoScrollEnabled) {\n requestAnimationFrame(() => this._scrollToBottom());\n }\n // Recalculate spacer when DOM mutates (new bubble added, Angular re-render).\n this._scheduleSpacerUpdate();\n });\n\n // Framework-managed: bubbles are direct children of the host (no wrapper).\n const observeTarget = this._frameworkManagedDOM ? this : wrapper;\n if (observeTarget) {\n this._mutationObserver.observe(observeTarget, {\n childList: true,\n subtree: true\n });\n }\n }\n\n /** Is the scroll surface within `_scrollThreshold` of its bottom, right now? */\n private _isAtBottom(): boolean {\n if (!this._container) return true;\n const { scrollTop, scrollHeight, clientHeight } = this._container;\n return scrollHeight - scrollTop - clientHeight <= this._scrollThreshold;\n }\n\n private _handleScroll(): void {\n if (!this._container) return;\n // A scroll IS the user's intent: reaching the bottom re-arms auto-follow,\n // leaving it disarms it.\n //\n // `_isAtBottom()` is deliberately generous (`_scrollThreshold`, 50px): a few\n // pixels of drift must NOT read as \"the reader walked away\". That generosity\n // is right here and wrong as a definition of \"anchored\" — which is why\n // `_settleAtBottom()` closes a residual gap instead of this method being\n // tightened. Tightening it would disarm auto-follow on every stray pixel.\n //\n // This handler also cannot tell our own programmatic scroll from a real\n // gesture. Marking them with a counter was tried and reverted: engines\n // coalesce scroll events, so the counter over-counted and started swallowing\n // the USER's scrolls — the browser suite caught it stealing the scroll back.\n // Anything attempted here must identify the scroll by POSITION, not by\n // counting events.\n this._isAutoScrollEnabled = this._isAtBottom();\n this._updateScrollButton();\n }\n\n private _scrollToBottom(): void {\n if (!this._container) return;\n this._container.scrollTop = this._container.scrollHeight;\n this._settleAtBottom(4);\n }\n\n /**\n * Confirm over the next few frames that we actually reached the bottom.\n *\n * One assignment is not enough, and the reason is measured rather than guessed.\n * A timeline of a streamed turn on Safari (framework mode) recorded the content\n * settling in TWO layout passes — 1118 → 1121 → 1152 px. `scrollTop =\n * scrollHeight` ran against the middle one, clamped to that layout's max (603),\n * and nothing ran afterwards: the last 31px never closed. Auto-follow stayed\n * armed the whole time, so the component was not disarmed — it was SATISFIED.\n * `_isAtBottom()` answers \"yes\" for any gap under `_scrollThreshold` (50), which\n * is the right rule for keeping auto-follow armed and the wrong one as a\n * definition of \"anchored\".\n *\n * Ruled out on the way here, so nobody pays for it twice: not a WebKit\n * padding-accounting difference (a probe writing `scrollTop = 1e7` reached\n * exactly `scrollHeight - clientHeight`), not a missing `characterData`\n * mutation, and not a child resize a ResizeObserver could see.\n *\n * A BOUNDED retry, not one corrective frame: a single frame lands on the same\n * stale layout and was measured leaving a wider gap than doing nothing. Bounded\n * so it always terminates; re-reads `_isAutoScrollEnabled` every frame so a\n * reader who scrolls away mid-settle is left alone; stops as soon as the gap is\n * closed, so the common case costs one frame that does nothing.\n */\n private _settleAtBottom(framesLeft: number): void {\n if (framesLeft <= 0) return;\n requestAnimationFrame(() => {\n if (!this._container || !this._isAutoScrollEnabled) return;\n const max = this._container.scrollHeight - this._container.clientHeight;\n if (max - this._container.scrollTop <= 1) return;\n this._container.scrollTop = max;\n this._settleAtBottom(framesLeft - 1);\n });\n }\n\n private _smoothScrollToBottom(): void {\n if (!this._container) return;\n // scrollTo with behavior:'smooth' is not available in all environments (e.g. jsdom).\n // Fall back to instant scroll so tests and SSR environments stay safe.\n // Reduced-motion users get the instant path too — the CSS\n // prefers-reduced-motion block cannot reach a JS-driven smooth scroll.\n if (typeof this._container.scrollTo === 'function' && !this._prefersReducedMotion()) {\n this._container.scrollTo({ top: this._container.scrollHeight, behavior: 'smooth' });\n } else {\n this._container.scrollTop = this._container.scrollHeight;\n }\n }\n\n private _prefersReducedMotion(): boolean {\n return typeof matchMedia === 'function'\n && matchMedia('(prefers-reduced-motion: reduce)').matches;\n }\n\n /**\n * Show/hide the scroll-to-bottom button from the **current geometry**, not from\n * `_isAutoScrollEnabled`.\n *\n * The two answer different questions: the flag is intent (\"should new content\n * pull the view down\"), the button is a fact (\"is there anything below the\n * fold\"). Mirroring the flag made the button lie whenever the two diverged —\n * `navigateBranch` deliberately disarms auto-follow, so swapping a branch while\n * already at the bottom of a scrollable transcript left the button offering to\n * scroll nowhere (reported from bonaparte, React). Re-derived on scroll, on the\n * post-mutation frame and after a path swap, so it converges to the truth\n * whatever a framework's render timing does in between.\n */\n private _updateScrollButton(): void {\n this._scrollBtn?.classList.toggle('aparte-scroll-btn--hidden', this._isAtBottom());\n }\n\n /**\n * Recalculate the bottom spacer height so the last user message is always\n * pinned to the top of the scroll area when a response is being generated.\n *\n * spacer = max(0, viewportHeight - lastUserBubble.offsetHeight - lastAssistantBubble.offsetHeight)\n *\n * The spacer shrinks progressively as the assistant streams content, eventually\n * reaching 0 when the combined height fills the viewport.\n */\n private _recalculateSpacer(): void {\n // Core mode needs the spacer element; framework mode uses host padding\n // (no element) — both need the scroll container.\n if (!this._container) return;\n if (!this._frameworkManagedDOM && !this._bottomSpacer) return;\n // Skip while the host layout is still animating (e.g. the flex transition\n // that moves the composer from the center of the screen to the bottom).\n // Without this guard, every ResizeObserver tick during the transition\n // reads a partially-grown clientHeight and writes an incorrect spacer\n // height that may reach the clientHeight cap and lock the spacer there.\n if (Date.now() < this._spacerFrozenUntil) return;\n\n const allBubbles = Array.from(\n this.querySelectorAll('aparte-chat-bubble')\n ) as HTMLElement[];\n\n if (allBubbles.length === 0) {\n this._setSpacerHeight(0);\n return;\n }\n\n const lastUserBubble = [...allBubbles]\n .reverse()\n .find(b => b.getAttribute('role') === 'user');\n\n if (!lastUserBubble) {\n this._setSpacerHeight(0);\n return;\n }\n\n // Read the current spacer height (may be non-zero during a CSS transition\n // or a previous non-zero value). Subtract it from scrollHeight to get the\n // true content height WITHOUT the spacer — no need to zero-then-reflow,\n // which would both fight the CSS transition and force an extra synchronous\n // layout that could read a stale animated value.\n const currentSpacerH = this._getSpacerHeight();\n\n // Use getBoundingClientRect so gaps, padding, and all children are\n // automatically accounted for — no need to manually sum heights.\n const containerRect = this._container.getBoundingClientRect();\n const userRect = lastUserBubble.getBoundingClientRect();\n\n // Absolute Y position of the user bubble's top within the full scrollable content\n const userTopInContent = userRect.top - containerRect.top + this._container.scrollTop;\n\n // Height of content from user bubble top to end, excluding the spacer\n const scrollHeightWithoutSpacer = this._container.scrollHeight - currentSpacerH;\n\n // If all content already fits in the viewport, no spacer is needed.\n if (scrollHeightWithoutSpacer <= this._container.clientHeight) {\n this._setSpacerHeight(0);\n return;\n }\n\n const contentBelowUserTop = scrollHeightWithoutSpacer - userTopInContent;\n\n const needed = this._container.clientHeight - contentBelowUserTop;\n // Hard cap: the spacer can never exceed the visible viewport height.\n // This acts as a safety net against stale layout reads (e.g. mid-swap)\n // that could produce an astronomical value and push content off-screen.\n const maxSpacer = this._container.clientHeight;\n this._setSpacerHeight(Math.min(Math.max(0, needed), maxSpacer));\n\n // Re-scroll after the spacer height changes so scrollTop is always\n // consistent with the new scrollHeight. Without this, the MutationObserver\n // schedules _scrollToBottom() one RAF *before* _recalculateSpacer() runs,\n // leaving scrollTop based on the pre-spacer scrollHeight. On the next\n // recalculation (e.g. from syncMessagesWithBubbles or a resize) the formula\n // reads a stale scrollTop and may grow the spacer to the clientHeight cap.\n if (this._isAutoScrollEnabled) {\n this._scrollToBottom();\n }\n }\n\n /**\n * Schedule a spacer recalculation on the next animation frame.\n * Batches multiple rapid calls (e.g. during token streaming) into one.\n *\n * Single-RAF intentional: both the scroll-to-bottom queued by MutationObserver\n * and this spacer recalculation must land in the *same* frame so the browser\n * paints exactly once — with the correct scroll position *and* the correct\n * spacer height. A double-RAF would put the spacer shrink one frame after the\n * scroll, causing a 1-frame layout jump during streaming.\n */\n private _scheduleSpacerUpdate(): void {\n if (this._spacerRafId !== null) return;\n this._spacerRafId = requestAnimationFrame(() => {\n this._spacerRafId = null;\n this._recalculateSpacer();\n // The DOM just changed (new bubble, streamed token, framework re-render):\n // whether anything sits below the fold changed with it.\n this._updateScrollButton();\n });\n }\n\n /**\n * Cap the number of rendered bubbles in the DOM (perf ceiling only).\n *\n * Drops the oldest `<aparte-chat-bubble>` elements beyond `_maxRenderedBubbles`\n * from the DOM. It **never** touches the AparteMessageRepository — the conversation\n * model and its persistence snapshot stay complete (retention/eviction is a\n * consumer/persistence concern, not the viewport's). No-op when a framework\n * owns the DOM.\n */\n private _pruneRenderedBubbles(): void {\n if (this._frameworkManagedDOM) return;\n const wrapper = this.querySelector('.aparte-messages-wrapper');\n if (!wrapper) return;\n const bubbles = wrapper.querySelectorAll('aparte-chat-bubble');\n const excess = bubbles.length - this._maxRenderedBubbles;\n for (let i = 0; i < excess; i++) {\n bubbles[i]?.remove();\n }\n }\n\n private _warnMaxMessagesDeprecated(): void {\n if (this._warnedMaxMessagesDeprecation) return;\n this._warnedMaxMessagesDeprecation = true;\n console.warn(\n '[Aparte] `maxMessages` / `max-messages` on aparte-chat-viewport is deprecated: ' +\n 'it used to silently evict messages from the conversation model. It now only ' +\n 'caps rendered bubbles in the DOM — use `maxRenderedBubbles` / `max-rendered-bubbles`. ' +\n 'For actual history retention, configure it on your AparteConversationManager instead.',\n );\n }\n\n private _cleanup(): void {\n this._container?.removeEventListener('scroll', this._handleScroll);\n this._scrollBtn?.removeEventListener('click', this._onScrollBtnClick);\n this.removeEventListener('aparte-branch-navigate', this._onBranchNavigate);\n this._resizeObserver?.disconnect();\n this._mutationObserver?.disconnect();\n this._resizeObserver = null;\n this._mutationObserver = null;\n if (this._spacerRafId !== null) {\n cancelAnimationFrame(this._spacerRafId);\n this._spacerRafId = null;\n }\n }\n}\n\n// Register the custom element\nif (!customElements.get('aparte-chat-viewport')) {\n customElements.define('aparte-chat-viewport', AparteChatViewport);\n}\n","import type { AparteSendEventDetail } from '../../types/index.js';\nimport { type AparteConfig } from '../../config/aparte-config.js';\nimport { resolveConfig } from '../../config/config-context.js';\n\n// ─────────────────────────────────────────────────────────────────────────────\n// Event map for internal pub/sub between primitives\n// ─────────────────────────────────────────────────────────────────────────────\nexport interface AparteComposerEventMap {\n 'value-change': { value: string };\n 'streaming-change': { streaming: boolean };\n 'disabled-change': { disabled: boolean };\n 'attachments-change': { attachments: File[] };\n 'submit': { value: string; attachments: File[] };\n 'cancel': Record<string, never>;\n 'panel-change': { active: boolean; submitEnabled: boolean; mode: 'advance' | 'submit' };\n}\n\nexport type AparteComposerEventType = keyof AparteComposerEventMap;\n\n/**\n * Public snapshot of the composer's observable state. Delivered on every\n * `aparte-composer-change` DOM event and available synchronously via\n * {@link AparteComposer.getState}. Lets an element OUTSIDE the composer package\n * (a custom send button, a footer control) mirror the composer's live state\n * without the internal `_on`/`_emit` bus.\n */\nexport interface AparteComposerState {\n value: string;\n streaming: boolean;\n disabled: boolean;\n attachments: File[];\n /** A panel (e.g. an elicitation form) is showing in place of the input. */\n panelActive: boolean;\n /** Whether the send button should act as \"submit\" while a panel is active. */\n submitEnabled: boolean;\n}\n\n/** Detail of the public `aparte-composer-change` DOM event. */\nexport interface AparteComposerChangeEventDetail {\n state: AparteComposerState;\n composer: AparteComposer;\n}\n\n// ─────────────────────────────────────────────────────────────────────────────\n// AparteComposer — root context provider\n// ─────────────────────────────────────────────────────────────────────────────\n\n/**\n * The root context for every `aparte-composer-*` primitive. It imposes no visual\n * layout — the consumer owns the structure — and holds the shared state the parts\n * read: the value, the streaming flag, pending attachments, the panel slot.\n *\n * Prose first, on purpose: when `@element` opens a docblock there is no free text\n * left for the analyser to use, and this component's description came out empty in\n * the manifest and blank on the generated reference page.\n *\n * `aparte-abort` and `aparte-message-aborted` have to be declared by hand and always\n * will: they go out through `window.dispatchEvent` (they concern the whole page, not\n * this subtree), and the analyser's fallback only recognises `this.dispatchEvent`.\n *\n * @element aparte-composer\n *\n * @attr {string} placeholder - Forwarded to `<aparte-composer-input>` through the internal bus.\n * @attr {boolean} disabled - Disables the whole composer, every part included.\n * @attr {string} target - The id of the `<aparte-chat>` this composer drives.\n *\n * @fires {CustomEvent<AparteSendEventDetail>} aparte-send - A message was submitted: the text, its attachments and the target.\n * @fires aparte-cancel - The stop button was pressed. No detail; the two window events below carry the target.\n * @fires {CustomEvent<AparteAbortEventDetail>} aparte-abort - Dispatched on `window`: stop the run for this target.\n * @fires {CustomEvent<AparteMessageAbortedEventDetail>} aparte-message-aborted - Dispatched on `window`: the run for this target ended early.\n * @fires {CustomEvent<AparteComposerChangeEventDetail>} aparte-composer-change - Any of value / streaming / disabled / attachments / panel changed, folded into one event.\n */\nexport class AparteComposer extends HTMLElement {\n private _value = '';\n private _streaming = false;\n private _attachments: File[] = [];\n private _listeners = new Map<string, Set<(payload: unknown) => void>>();\n private _panelActive = false;\n /** What the send button means while a panel is up — see `showPanel`. */\n private _panelMode: 'advance' | 'submit' = 'submit';\n private _panelSubmitEnabled = false;\n private _panelOnSubmit: (() => void) | null = null;\n /**\n * Who owns the one panel slot, and how to tell them they lost it.\n *\n * There is exactly one slot, `showPanel` empties it unconditionally, and nothing\n * used to say whose it was. Three paths therefore closed a panel whose owner was\n * still awaiting an answer, and none of them told the owner: a second `showPanel`,\n * the owner-of-record's own `hidePanel`, and — the one that actually bit —\n * `_handleMessageDone`, which fires on EVERY turn end. A question still open when a\n * turn finished lost its panel while `<aparte-elicitation>` kept `_pending` set,\n * so the request never settled AND every later request was short-circuited for the\n * life of the page.\n */\n private _panelToken: symbol | null = null;\n private _panelOnEvict: (() => void) | null = null;\n\n // Internal bus events that represent an observable STATE change — these are\n // mirrored to the public `aparte-composer-change` DOM event. `submit`/`cancel`\n // are actions, not state, and are covered by `aparte-send`/`aparte-cancel`.\n private static readonly _STATE_EVENTS: ReadonlySet<AparteComposerEventType> = new Set([\n 'value-change', 'streaming-change', 'disabled-change', 'attachments-change', 'panel-change',\n ]);\n\n // Window event bindings\n private _onMessageStart = this._handleMessageStart.bind(this);\n private _onMessageDone = this._handleMessageDone.bind(this);\n\n /** Config governing THIS composer (nearest instance boundary, else global). */\n /**\n * Resolved LIVE, not cached at connect.\n *\n * A wrapper runs `AparteChatHost.bind()` — which calls `attachConfig` — from its\n * POST-mount hook, so this element connects BEFORE the boundary exists. Caching\n * here latched the global config forever: an instance `config` carrying an RTL\n * locale flipped the transcript and not the composer, and the\n * `requireModelSelection` gate was read off the wrong object. `aparte-chat-bubble`\n * has always resolved live, and its JSDoc names this exact race.\n */\n private get _cfg(): AparteConfig {\n return resolveConfig(this);\n }\n /** Only OUR config: a change on another chat's instance must not touch us. */\n private _onConfigChangeEvent = (e: Event): void => {\n const detail = (e as CustomEvent).detail as { config?: unknown } | undefined;\n if (detail?.config && detail.config !== this._cfg) return;\n this._onConfigChange();\n };\n /** True while `requireModelSelection` is on AND no model is selected — blocks send. */\n private _modelGated = false;\n private _onConfigChange = (): void => { this._evaluateModelGate(); this._applyDirection(); };\n\n /**\n * Mirror `locale.direction` onto ourselves, so everything inside — input, buttons,\n * the toolbar row and whatever the consumer put in it — inherits it.\n *\n * The direction used to stop at the transcript: only the viewport applied `dir`, so\n * an RTL locale flipped the conversation and left the composer left-to-right. It is\n * also what makes the toolbar's placement idiom real: `margin-inline-start: auto` in\n * a subtree that inherits no direction is just `margin-left`.\n *\n * One attribute on the host rather than a stamp per child: inheritance is the\n * mechanism, so nothing needs to know about the consumer's markup.\n */\n private _applyDirection(): void {\n const direction = (this._cfg ?? resolveConfig(this)).getLocale().direction;\n if (direction) this.setAttribute('dir', direction);\n else this.removeAttribute('dir');\n }\n\n static get observedAttributes(): string[] {\n return ['placeholder', 'disabled', 'target'];\n }\n\n connectedCallback(): void {\n window.addEventListener('aparte-message-start', this._onMessageStart);\n window.addEventListener('aparte-message-done', this._onMessageDone);\n window.addEventListener('aparte-message-error', this._onMessageDone);\n window.addEventListener('aparte-message-aborted', this._onMessageDone);\n // Model-selection gate (opt-in via aparteGlobalConfig.setRequireModelSelection).\n // A window listener rather than `_cfg.subscribe(...)`: subscribing binds to\n // whichever config was resolvable AT CONNECT, which is the bug above wearing\n // a different hat. `_notify()` dispatches `aparte-config-change` with\n // `detail.config`, so the same information arrives without the early binding\n // — and the filter below compares against the LIVE config.\n window.addEventListener('aparte-config-change', this._onConfigChangeEvent);\n this._evaluateModelGate();\n this._applyDirection();\n }\n\n disconnectedCallback(): void {\n window.removeEventListener('aparte-message-start', this._onMessageStart);\n window.removeEventListener('aparte-message-done', this._onMessageDone);\n window.removeEventListener('aparte-message-error', this._onMessageDone);\n window.removeEventListener('aparte-message-aborted', this._onMessageDone);\n window.removeEventListener('aparte-config-change', this._onConfigChangeEvent);\n this._listeners.clear();\n }\n\n attributeChangedCallback(name: string, _old: string | null, value: string | null): void {\n if (name === 'disabled') {\n this._emit('disabled-change', { disabled: value !== null });\n }\n if (name === 'placeholder') {\n // Primitives read this directly via closest() — no event needed\n }\n }\n\n // ── Public API ─────────────────────────────────────────────────────────\n\n get value(): string { return this._value; }\n get streaming(): boolean { return this._streaming; }\n get disabled(): boolean { return this.hasAttribute('disabled'); }\n /**\n * When false, Shift+Enter submits and a bare Enter inserts a newline —\n * the inverse of the default. Driven by the `submit-on-enter` attribute.\n */\n get submitOnEnter(): boolean { return this.getAttribute('submit-on-enter') !== 'false'; }\n get attachments(): File[] { return this._attachments; }\n get placeholder(): string { return this.getAttribute('placeholder') ?? ''; }\n get targetId(): string | null { return this.getAttribute('target'); }\n\n /**\n * Snapshot of the composer's observable state. Pair with the\n * `aparte-composer-change` DOM event to drive a custom send button or footer\n * control that lives outside the composer package:\n *\n * @example\n * // A custom send button. Keep it CLICKABLE while streaming — submit()\n * // routes to cancel() when a response is in flight, so one button is\n * // Send/Stop. Disabling it on `streaming` would make \"stop\" unreachable.\n * composer.addEventListener('aparte-composer-change', (e) => {\n * const { streaming, disabled, value, attachments } = e.detail.state;\n * myButton.textContent = streaming ? 'Stop' : 'Send';\n * myButton.disabled = disabled || (!streaming && !value.trim() && attachments.length === 0);\n * });\n * myButton.addEventListener('click', () => composer.submit()); // send or stop\n */\n getState(): AparteComposerState {\n return {\n value: this._value,\n streaming: this._streaming,\n disabled: this.disabled,\n attachments: [...this._attachments],\n panelActive: this._panelActive,\n submitEnabled: this._panelSubmitEnabled,\n };\n }\n\n setValue(value: string): void {\n this._value = value;\n this._emit('value-change', { value });\n }\n\n addAttachments(files: FileList | File[]): void {\n this._attachments = [...this._attachments, ...Array.from(files)];\n this._emit('attachments-change', { attachments: this._attachments });\n }\n\n removeAttachment(file: File): void {\n this._attachments = this._attachments.filter(f => f !== file);\n this._emit('attachments-change', { attachments: this._attachments });\n }\n\n clearAttachments(): void {\n this._attachments = [];\n this._emit('attachments-change', { attachments: [] });\n }\n\n /**\n * Inject a panel into the composer. The send button calls `onSubmit` when clicked.\n *\n * While a panel is up, the composer is answering a QUESTION, not composing a\n * message — so the affordances that lead nowhere go away with the text input:\n * the attachment picker above all, which stayed clickable while the user was\n * being asked something (\"on voyait encore l'icône de upload\", reported from a\n * real session). Ratified decision #8: an affordance nothing can honour is not\n * rendered.\n *\n * What STAYS, deliberately: the attachments strip, because pending attachments\n * are the user's state and not an action to offer — hiding them would look like\n * losing them; and the toolbar, because switching model still does something.\n *\n * Declared with an attribute + CSS rather than the inline `style.display` this\n * used to set on a child: an attribute is themeable, is visible to a consumer's\n * own rules, and does not clobber a `display` the consumer had set (the restore\n * wrote `''`, not the previous value).\n *\n * Returns the TOKEN for this panel. Pass it back to `hidePanel` so a presenter\n * that has already lost the slot cannot close the panel that replaced it, and\n * supply `onEvict` to be told when that happens — an owner that is not told is an\n * owner whose promise nobody can settle.\n */\n showPanel(\n panel: HTMLElement,\n options?: {\n submitEnabled?: boolean;\n onSubmit?: () => void;\n mode?: 'advance' | 'submit';\n /** Called when something other than this owner closes the panel. */\n onEvict?: () => void;\n },\n ): symbol {\n // Evict rather than hide: the previous owner is awaiting an answer it will\n // never get, and it is the only thing that can settle its own promise.\n this._evictPanel();\n const inputEl = this.querySelector('aparte-composer-input') as HTMLElement | null;\n this.setAttribute('data-panel-active', '');\n panel.dataset['apartePanel'] = 'true';\n if (inputEl) {\n inputEl.insertAdjacentElement('afterend', panel);\n } else {\n this.appendChild(panel);\n }\n this._panelActive = true;\n this._panelSubmitEnabled = options?.submitEnabled ?? false;\n this._panelMode = options?.mode ?? 'submit';\n this._panelOnSubmit = options?.onSubmit ?? null;\n this._panelOnEvict = options?.onEvict ?? null;\n const token = Symbol('aparte-composer-panel');\n this._panelToken = token;\n this._emit('panel-change', { active: true, submitEnabled: this._panelSubmitEnabled, mode: this._panelMode });\n return token;\n }\n\n /**\n * Remove the panel and restore the composer's own controls.\n *\n * With a `token`, this closes the panel only if that token still owns the slot —\n * so a presenter settling late cannot tear down the panel that replaced it. With\n * no token it closes whatever is there, which is what a consumer driving the\n * composer directly means, and what `reset()` needs.\n */\n hidePanel(token?: symbol): void {\n if (token !== undefined && token !== this._panelToken) return;\n this._teardownPanel();\n }\n\n /** Close the panel AND tell its owner, so a pending request never orphans. */\n private _evictPanel(): void {\n const onEvict = this._panelOnEvict;\n // State first, callback second: the owner's settle path calls `hidePanel` with\n // its own token, which must find the slot already empty rather than recurse.\n this._teardownPanel();\n onEvict?.();\n }\n\n private _teardownPanel(): void {\n const existing = this.querySelector('[data-aparte-panel]') as HTMLElement | null;\n if (existing) existing.remove();\n this.removeAttribute('data-panel-active');\n this._panelActive = false;\n this._panelSubmitEnabled = false;\n this._panelMode = 'submit';\n this._panelOnSubmit = null;\n this._panelOnEvict = null;\n this._panelToken = null;\n this._emit('panel-change', { active: false, submitEnabled: false, mode: 'submit' });\n this.focus();\n }\n\n /**\n * Update the send button's state while a panel is active.\n *\n * `mode` moves with it because both change on the same event — answering the\n * question you are on can enable the button AND turn it from \"advance\" into\n * \"submit\" (when it was the last one), and two separate calls would flash a\n * wrong icon between them.\n */\n setPanelSubmitEnabled(enabled: boolean, mode?: 'advance' | 'submit'): void {\n if (!this._panelActive) return;\n this._panelSubmitEnabled = enabled;\n if (mode) this._panelMode = mode;\n this._emit('panel-change', { active: true, submitEnabled: enabled, mode: this._panelMode });\n }\n\n get panelActive(): boolean { return this._panelActive; }\n\n /**\n * Recompute the model gate from the resolved config. When\n * `requireModelSelection` is on and no model is selected, block sending and\n * reflect `data-model-gated` so the shipped CSS greys the composer. Re-runs on\n * every config change (e.g. the model selector's auto-select firing).\n */\n private _evaluateModelGate(): void {\n const gated = this._cfg.getRequireModelSelection() && !this._cfg.hasSelectedModel();\n if (gated === this._modelGated) return;\n this._modelGated = gated;\n this.toggleAttribute('data-model-gated', gated);\n }\n\n /** Submit the current value. Called by aparte-composer-send or programmatically. */\n submit(): void {\n if (this._panelActive) {\n if (this._panelSubmitEnabled) this._panelOnSubmit?.();\n return;\n }\n if (this._streaming) {\n this.cancel();\n return;\n }\n const value = this._value.trim();\n if (!value && this._attachments.length === 0) return;\n if (this.disabled) return;\n if (this._modelGated) return; // no model selected yet (require-model gate)\n\n this._emit('submit', { value, attachments: this._attachments });\n\n const detail: AparteSendEventDetail = {\n content: value,\n timestamp: Date.now(),\n targetId: this.targetId ?? undefined,\n files: this._attachments.length > 0 ? [...this._attachments] : undefined,\n };\n\n this.dispatchEvent(new CustomEvent<AparteSendEventDetail>('aparte-send', {\n bubbles: true,\n composed: true,\n detail,\n }));\n\n // Clear after send\n this.setValue('');\n this.clearAttachments();\n }\n\n /** Cancel the current streaming response. */\n cancel(): void {\n this._emit('cancel', {});\n // Public, element-scoped signal — symmetric with `aparte-send` on submit,\n // for consumers that want to observe cancel on the composer itself.\n this.dispatchEvent(new CustomEvent('aparte-cancel', { bubbles: true, composed: true }));\n // aparte-abort → tells AparteClient to actually stop the stream\n // aparte-message-aborted → resets the composer's own streaming state\n // Scope the abort to this composer's host so cancelling one chat doesn't\n // abort every scoped client / reset every composer on the page.\n const abortDetail = { targetId: this.targetId ?? undefined };\n window.dispatchEvent(new CustomEvent('aparte-abort', { bubbles: false, detail: abortDetail }));\n window.dispatchEvent(new CustomEvent('aparte-message-aborted', { bubbles: false, detail: abortDetail }));\n }\n\n /**\n * Reset the composer to its initial state.\n * Clears value, attachments, and hides any active panel.\n * Call this when switching conversations.\n */\n reset(): void {\n this.setValue('');\n this.clearAttachments();\n if (this._panelActive) this._evictPanel();\n }\n\n /** Focus the input primitive inside this composer. */\n override focus(): void {\n const input = this.querySelector('aparte-composer-input') as HTMLElement | null;\n input?.focus();\n }\n\n // ── Internal pub/sub ────────────────────────────────────────────────────\n\n _emit<K extends AparteComposerEventType>(event: K, payload: AparteComposerEventMap[K]): void {\n this._listeners.get(event)?.forEach(cb => cb(payload));\n // Mirror state changes to a public DOM event so elements outside the\n // composer package can observe them without the private bus.\n if (AparteComposer._STATE_EVENTS.has(event)) {\n this.dispatchEvent(new CustomEvent<AparteComposerChangeEventDetail>('aparte-composer-change', {\n bubbles: true,\n composed: true,\n detail: { state: this.getState(), composer: this },\n }));\n }\n }\n\n _on<K extends AparteComposerEventType>(event: K, cb: (payload: AparteComposerEventMap[K]) => void): () => void {\n if (!this._listeners.has(event)) this._listeners.set(event, new Set());\n this._listeners.get(event)!.add(cb as unknown as (payload: unknown) => void);\n return () => this._listeners.get(event)?.delete(cb as unknown as (payload: unknown) => void);\n }\n\n // ── Window events ───────────────────────────────────────────────────────\n\n /** A window lifecycle event is for THIS composer when neither side is scoped\n * (single-instance broadcast) or the target ids match (multi-chat page).\n * Without this filter, streaming in one chat flips every composer's state. */\n private _isForThisComposer(e: Event): boolean {\n const evtTargetId = (e as CustomEvent).detail?.targetId as string | undefined;\n return !evtTargetId || !this._ownTargetId() || evtTargetId === this._ownTargetId();\n }\n\n /**\n * Which chat this composer belongs to: its `target` attribute, or the id of the\n * chat host above it.\n *\n * All four wrappers set `target` themselves, so the attribute alone identified a\n * composer there. In RAW core — the documented quick start, where the markup is\n * hand-written — nothing sets it, so `!this.targetId` was true and this composer\n * accepted every chat's lifecycle events: on a two-chat page, one chat's Stop\n * tore down the other's open elicitation panel while its tool call kept waiting,\n * i.e. the question vanished and the turn hung.\n *\n * Found by a two-chat test written for the elicitation presenter, which is the\n * only reason it surfaced: raw core with two chats is a shape nothing exercised.\n * The hosts matched are the ones `aparte-chat-bubble._resolveTargetId()` matches,\n * for the reason written there — Angular's wrapper root IS `<aparte-chat>`, the\n * other three render a `[data-aparte-chat]` div.\n */\n private _ownTargetId(): string | undefined {\n const attr = this.targetId;\n if (attr) return attr;\n let el: HTMLElement | null = this.parentElement;\n while (el) {\n const tag = el.tagName?.toLowerCase();\n const isHost = tag === 'aparte-chat' || tag === 'aparte-chat-component' || el.hasAttribute?.('data-aparte-chat');\n if (isHost && el.id) return el.id;\n el = el.parentElement;\n }\n return undefined;\n }\n\n private _handleMessageStart(e: Event): void {\n if (!this._isForThisComposer(e)) return;\n this._streaming = true;\n this._emit('streaming-change', { streaming: true });\n }\n\n private _handleMessageDone(e: Event): void {\n if (!this._isForThisComposer(e)) return;\n this._streaming = false;\n this._emit('streaming-change', { streaming: false });\n // Always hide any active panel when a message lifecycle ends\n if (this._panelActive) this._evictPanel();\n }\n}\n\nif (!customElements.get('aparte-composer')) {\n customElements.define('aparte-composer', AparteComposer);\n}\n","import { resolveConfig } from '../../config/index.js';\nimport type { AparteComposer } from './aparte-composer.js';\nimport { escapeAttr } from '../../utils/escape.js';\nimport { subscribeConfigChange } from '../../config/config-subscribe.js';\n\n/**\n * Contenteditable text input primitive.\n *\n * @element aparte-composer-input\n * Must be a descendant of <aparte-composer>.\n *\n * @fires aparte-composer-submit - Enter was pressed with content. No detail; the composer reads its own value.\n *\n * Behaviour: Enter submits (calls root.submit()), Shift+Enter inserts newline.\n * Auto-expands up to max-height. Paste strips HTML, handles image paste.\n *\n * @attr {boolean} disabled - Makes the field non-editable; the composer's own `disabled` also reaches it.\n * @attr {string} placeholder - Placeholder text (fallback: reads from aparte-composer)\n * @attr {number} max-height - Max height in px before scroll (default: 200)\n * @attr {number} min-height - Min height in px. When omitted, the stylesheet's\n * min-height governs (44px in aparte.css) — so themes can\n * resize the editor in pure CSS without being fought by\n * an inline height.\n *\n * @example\n * <aparte-composer>\n * <div class=\"aparte-composer-shell\">\n * <div class=\"aparte-composer-row\">\n * <aparte-composer-input placeholder=\"Ask anything…\" max-height=\"320\" style=\"flex: 1\"></aparte-composer-input>\n * <aparte-composer-send></aparte-composer-send>\n * </div>\n * </div>\n * </aparte-composer>\n */\nexport class AparteComposerInput extends HTMLElement {\n private _editor: HTMLDivElement | null = null;\n private _maxHeight = 200;\n private _minHeight = 44;\n private _unsubscribes: (() => void)[] = [];\n\n // Bound handlers\n private _onInput = this._handleInput.bind(this);\n private _onKeydown = this._handleKeydown.bind(this);\n private _onFocus = this._handleFocus.bind(this);\n private _onBlur = this._handleBlur.bind(this);\n private _onPaste = this._handlePaste.bind(this);\n\n static get observedAttributes(): string[] {\n return ['placeholder', 'max-height', 'min-height', 'disabled'];\n }\n\n connectedCallback(): void {\n this._render();\n this._connectToRoot();\n this._scheduleInitialReflow();\n // The placeholder is the one string in this composer a sighted user can\n // actually read, and it was frozen at the language of the first render.\n // `_updatePlaceholder` already exists for the attribute path — a locale\n // change is the same refresh, from a different trigger.\n this._unsubscribes.push(subscribeConfigChange(this, () => this._updatePlaceholder()));\n }\n\n disconnectedCallback(): void {\n this._editor?.removeEventListener('input', this._onInput);\n this._editor?.removeEventListener('keydown', this._onKeydown);\n this._editor?.removeEventListener('focus', this._onFocus);\n this._editor?.removeEventListener('blur', this._onBlur);\n this._editor?.removeEventListener('paste', this._onPaste);\n this._unsubscribes.forEach(fn => fn());\n this._unsubscribes = [];\n }\n\n attributeChangedCallback(name: string, _old: string | null, value: string | null): void {\n if (name === 'placeholder') this._updatePlaceholder();\n if (name === 'max-height') this._maxHeight = parseInt(value || '200', 10);\n if (name === 'min-height') this._minHeight = parseInt(value || '44', 10);\n if (name === 'disabled') this._updateDisabled(value !== null);\n }\n\n // ── Public API ──────────────────────────────────────────────────────────\n\n getValue(): string {\n // `textContent` drops `<br>`, so multi-line content would collapse onto one\n // line. Serialize the editor ourselves: text nodes as-is, `<br>` → newline.\n // We keep the editor flat (text + <br>, see _handleKeydown), but descend into\n // any stray wrapper for safety.\n if (!this._editor) return '';\n let out = '';\n const walk = (node: Node): void => {\n node.childNodes.forEach(child => {\n if (child.nodeType === Node.TEXT_NODE) out += child.textContent ?? '';\n else if (child.nodeName === 'BR') out += '\\n';\n else walk(child);\n });\n };\n walk(this._editor);\n return out.trim();\n }\n\n setValue(value: string): void {\n if (!this._editor) return;\n this._editor.textContent = value;\n this._updatePlaceholderVisibility();\n this._adjustHeight();\n this._getRoot()?.setValue(value);\n }\n\n clear(): void {\n if (!this._editor) return;\n this._editor.innerHTML = '';\n this._updatePlaceholderVisibility();\n this._adjustHeight();\n this._getRoot()?.setValue('');\n }\n\n override focus(): void { this._editor?.focus(); }\n override blur(): void { this._editor?.blur(); }\n\n /** Focus the editor and place the caret at the very end of its content. */\n focusEnd(): void {\n if (!this._editor) return;\n this._editor.focus();\n const sel = this.ownerDocument?.getSelection();\n if (!sel) return;\n const range = this.ownerDocument.createRange();\n range.selectNodeContents(this._editor);\n range.collapse(false);\n sel.removeAllRanges();\n sel.addRange(range);\n }\n\n // ── Private ─────────────────────────────────────────────────────────────\n\n private _getRoot(): AparteComposer | null {\n return this.closest('aparte-composer') as AparteComposer | null;\n }\n\n private _getPlaceholder(): string {\n return this.getAttribute('placeholder')\n || this._getRoot()?.placeholder\n || resolveConfig(this).t('inputPlaceholder')\n || 'Type a message...';\n }\n\n private _render(): void {\n if (this.querySelector('.aparte-ci-editor')) return;\n\n const disabled = this.hasAttribute('disabled') || this._getRoot()?.disabled || false;\n // `placeholder` may come straight from a host attribute (often bound to\n // dynamic/translated text) — escape before it lands in a double-quoted\n // attribute so a stray `\"` can't break out and inject markup.\n const placeholder = escapeAttr(this._getPlaceholder());\n\n this.innerHTML = `<div\n class=\"aparte-ci-editor\"\n contenteditable=\"${!disabled}\"\n role=\"textbox\"\n aria-multiline=\"true\"\n aria-label=\"${placeholder}\"\n tabindex=\"0\"\n aria-disabled=\"${disabled}\"\n data-placeholder=\"${placeholder}\"\n ></div>`;\n\n this._editor = this.querySelector('.aparte-ci-editor');\n this._editor?.addEventListener('input', this._onInput);\n this._editor?.addEventListener('keydown', this._onKeydown);\n this._editor?.addEventListener('focus', this._onFocus);\n this._editor?.addEventListener('blur', this._onBlur);\n this._editor?.addEventListener('paste', this._onPaste);\n\n this._adjustHeight();\n }\n\n private _connectToRoot(): void {\n const root = this._getRoot();\n if (!root) return;\n\n // Sync disabled state from root\n this._unsubscribes.push(\n root._on('disabled-change', ({ disabled }) => this._updateDisabled(disabled))\n );\n\n // When root clears value (after submit), clear our editor\n this._unsubscribes.push(\n root._on('value-change', ({ value }) => {\n if (value === '' && this.getValue() !== '') this.clear();\n })\n );\n\n // Sync streaming state — disable input while streaming\n this._unsubscribes.push(\n root._on('streaming-change', ({ streaming }) => {\n this._updateDisabled(streaming || root.disabled);\n })\n );\n }\n\n private _handleInput(): void {\n this._adjustHeight();\n // After a delete-all, contenteditable leaves residual `<br>` tags\n // (Chromium especially) so the `:empty` CSS pseudo-class no longer\n // matches and the placeholder stays hidden. Force-clear when text\n // content reduces to whitespace so the placeholder reappears.\n if (this._editor && !this._editor.textContent?.trim() && this._editor.innerHTML !== '') {\n this._editor.innerHTML = '';\n }\n this._updatePlaceholderVisibility();\n const value = this.getValue();\n this._getRoot()?.setValue(value);\n }\n\n private _handleKeydown(e: KeyboardEvent): void {\n // During IME composition (CJK/Japanese/Korean), Enter confirms the\n // candidate — it must never submit. `keyCode === 229` is the legacy\n // signal for engines that don't set `isComposing`.\n if (e.isComposing || e.keyCode === 229) return;\n if (e.key !== 'Enter') return;\n // `submit-on-enter` (default true): Enter submits, Shift+Enter inserts\n // a newline. When false the mapping inverts — Shift+Enter submits and\n // a bare Enter inserts a newline (lets the user author multi-line).\n const submitOnEnter = this._getRoot()?.submitOnEnter ?? true;\n const submits = submitOnEnter ? !e.shiftKey : e.shiftKey;\n if (submits) {\n e.preventDefault();\n const root = this._getRoot();\n if (root) {\n root.submit();\n } else {\n // Standalone (no <aparte-composer> parent, e.g. the bubble's inline\n // editor): there is no root to submit to, so surface the intent as a\n // DOM event the host can act on. Keeps this primitive reusable on its\n // own — the IME guard + submitOnEnter mapping above stay the single\n // source of truth for \"when to submit\".\n this.dispatchEvent(new CustomEvent('aparte-composer-submit', { bubbles: true }));\n }\n } else {\n // Newline branch. Take control instead of the browser's contenteditable\n // default, which inserts <div>/<br> wrappers that resist deletion.\n // `insertLineBreak` inserts a single <br> and manages the trailing bogus\n // <br> so backspace removes it cleanly (the \"can't delete the newline\" bug).\n e.preventDefault();\n // Nothing to break on an empty field — don't seed a leading blank line.\n if (!this._editor?.textContent) return;\n this.ownerDocument?.execCommand('insertLineBreak');\n }\n }\n\n private _handleFocus(): void {\n this.classList.add('aparte-is-focused');\n }\n\n private _handleBlur(): void {\n this.classList.remove('aparte-is-focused');\n }\n\n private _handlePaste(e: ClipboardEvent): void {\n e.preventDefault();\n const cd = e.clipboardData;\n if (!cd) return;\n\n // Image paste → push to root attachments\n const imageFile = Array.from(cd.items).find(i => i.type.startsWith('image/'))?.getAsFile();\n if (imageFile) {\n this._getRoot()?.addAttachments([imageFile]);\n return;\n }\n\n // Plain text paste\n const text = cd.getData('text/plain');\n if (text) {\n document.execCommand('insertText', false, text);\n }\n }\n\n private _adjustHeight(): void {\n if (!this._editor) return;\n // Measure with height:0 (not auto): an explicit height opts the editor\n // OUT of any parent flex `align-items: stretch`, so scrollHeight reflects\n // the real content — not the (taller) row it may be stretched into. With\n // `auto`, a stretching parent inflates scrollHeight and the editor gets\n // stuck tall until the next reflow.\n this._editor.style.height = '0px';\n // Floor: the `min-height` ATTRIBUTE when explicitly set; otherwise defer\n // to the stylesheet (CSS min-height caps an inline height anyway). A\n // hardcoded JS floor would override theme CSS with an inline style and\n // break editor/controls alignment in restyled composers.\n const floor = this.hasAttribute('min-height') ? this._minHeight : 0;\n const contentHeight = this._editor.scrollHeight;\n const h = Math.min(Math.max(contentHeight, floor), this._maxHeight);\n this._editor.style.height = `${h}px`;\n this._editor.style.overflowY = contentHeight > this._maxHeight ? 'auto' : 'hidden';\n }\n\n /**\n * The first `_adjustHeight()` runs synchronously in `_render()` on connect —\n * before the stylesheet, flex layout and web fonts have necessarily settled.\n * On an unstabilized layout `scrollHeight` can read inflated, leaving the\n * editor stuck tall (misaligned with the composer controls) until the first\n * keystroke re-measures it. Re-measure once the layout is ready so it's\n * correct from the first paint.\n */\n private _scheduleInitialReflow(): void {\n if (typeof requestAnimationFrame === 'function') {\n requestAnimationFrame(() => this._adjustHeight());\n }\n const fonts = (document as Document & { fonts?: { ready?: Promise<unknown> } }).fonts;\n fonts?.ready?.then(() => this._adjustHeight()).catch(() => { /* fonts unavailable — rAF path covers it */ });\n }\n\n private _updatePlaceholder(): void {\n if (this._editor) {\n const p = this._getPlaceholder();\n this._editor.setAttribute('data-placeholder', p);\n this._editor.setAttribute('aria-label', p);\n }\n }\n\n private _updatePlaceholderVisibility(): void {\n // Handled by CSS :empty — nothing to do\n }\n\n private _updateDisabled(disabled: boolean): void {\n if (!this._editor) return;\n this._editor.setAttribute('contenteditable', String(!disabled));\n this._editor.setAttribute('aria-disabled', String(disabled));\n }\n\n /** Escape a value before it lands in a double-quoted HTML attribute. */\n}\n\nif (!customElements.get('aparte-composer-input')) {\n customElements.define('aparte-composer-input', AparteComposerInput);\n}\n","import { resolveConfig } from '../../config/index.js';\nimport type { AparteComposer } from './aparte-composer.js';\nimport { escapeAttr } from '../../utils/escape.js';\nimport { subscribeConfigChange } from '../../config/config-subscribe.js';\n\n/**\n * Submit button primitive for <aparte-composer>.\n *\n * @element aparte-composer-send\n * Must be a descendant of <aparte-composer>.\n *\n * - Disabled when composer value is empty, composer is disabled, or streaming\n * - While streaming: shows stop icon and acts as cancel button\n *\n * @example\n * <!-- One button for both halves of the turn: it submits, and while a reply streams it\n * becomes the stop button. Do not disable it on `streaming` or stop is unreachable. -->\n * <aparte-composer>\n * <div class=\"aparte-composer-row\">\n * <aparte-composer-input style=\"flex: 1\"></aparte-composer-input>\n * <aparte-composer-send></aparte-composer-send>\n * </div>\n * </aparte-composer>\n */\nexport class AparteComposerSend extends HTMLElement {\n private _button: HTMLButtonElement | null = null;\n private _unsubscribes: (() => void)[] = [];\n /**\n * The last `panel-change` payload.\n *\n * This button has four meanings — send, stop, submit an answer, advance to the\n * next question — and three of them are decided by state it does not own: the\n * root's `streaming`, and this payload. It was read straight out of the event's\n * arguments and thrown away, so nothing could recompute the button's chrome\n * afterwards; a config change had no way to know which of the four to write.\n */\n private _panel: { active: boolean; submitEnabled: boolean; mode: 'advance' | 'submit' } | null = null;\n\n // Bound handler\n private _onClick = this._handleClick.bind(this);\n\n connectedCallback(): void {\n this._render();\n this._connectToRoot();\n }\n\n disconnectedCallback(): void {\n this._button?.removeEventListener('click', this._onClick);\n this._unsubscribes.forEach(fn => fn());\n this._unsubscribes = [];\n }\n\n // ── Private ─────────────────────────────────────────────────────────────\n\n private _getRoot(): AparteComposer | null {\n return this.closest('aparte-composer') as AparteComposer | null;\n }\n\n private _render(): void {\n if (this.querySelector('.aparte-cs-button')) return;\n\n const label = resolveConfig(this).t('sendButton') || 'Send';\n const icon = this._getSendIcon();\n const root = this._getRoot();\n const disabled = !root || root.disabled || root.value.trim() === '';\n\n this.innerHTML = `<button\n class=\"aparte-cs-button aparte-send-button\"\n aria-label=\"${escapeAttr(label)}\"\n title=\"${escapeAttr(label)}\"\n ${disabled ? 'disabled' : ''}\n >${icon}</button>`; // safe-text: _getSendIcon() returns the provider's SVG markup — escaping it would print the source\n\n this._button = this.querySelector('.aparte-cs-button');\n this._button?.addEventListener('click', this._onClick);\n }\n\n private _connectToRoot(): void {\n const root = this._getRoot();\n if (!root) return;\n\n this._unsubscribes.push(\n root._on('value-change', () => this._syncState())\n );\n this._unsubscribes.push(\n root._on('disabled-change', () => this._syncState())\n );\n this._unsubscribes.push(\n root._on('streaming-change', ({ streaming }) => {\n // If panel is active, streaming state change doesn't affect the button —\n // the panel controls it (submit answer, not stop stream)\n if (this._getRoot()?.panelActive) return;\n this._syncStreamingState(streaming);\n })\n );\n this._unsubscribes.push(\n root._on('attachments-change', () => this._syncState())\n );\n this._unsubscribes.push(\n root._on('panel-change', (payload) => {\n this._panel = payload;\n this._refreshChrome();\n })\n );\n // A config change — a new icon set, another language — has to write the\n // chrome for whichever of the four meanings the button currently carries.\n this._unsubscribes.push(subscribeConfigChange(this, () => this._refreshChrome()));\n }\n\n /**\n * Write the chrome for the mode the button is IN, deciding before writing.\n *\n * Never `_render()`: it returns early once the button exists, and its own\n * disabled/icon computation consults neither `root.streaming` nor the panel — so\n * rebuilding mid-turn would put a paper plane back while a reply was still\n * streaming, and rebuilding with the question panel open would silently drop out\n * of answer mode. It would also take the focus off the one control in this\n * composer most likely to be holding it.\n */\n private _refreshChrome(): void {\n if (!this._button) return;\n if (this._panel?.active) { this._syncPanelState(); return; }\n if (this._getRoot()?.streaming) { this._syncStreamingState(true); return; }\n this._syncState();\n }\n\n /**\n * Panel open: this one button now means \"answer\", and WHICH answer depends on\n * where you are in the form.\n *\n * The icon has to move with the meaning: it drew a paper plane while the label\n * already said \"Submit\", so it read as \"send a message\" while it meant \"answer\n * this question\". And a check on a form with three questions left was just as\n * wrong — hence a chevron while there is more ahead. The visual is what a user\n * reads.\n */\n private _syncPanelState(): void {\n const panel = this._panel;\n if (!this._button || !panel?.active) return;\n const cfg = resolveConfig(this);\n const advancing = panel.mode === 'advance';\n this._button.disabled = !panel.submitEnabled;\n this._button.innerHTML = advancing ? cfg.getIcon('nextBranch') : this._getSubmitIcon();\n const label = advancing\n ? (cfg.t('elicitationNext') || 'Next')\n : (cfg.t('submitButton') || 'Submit');\n this._button.setAttribute('aria-label', label);\n this._button.setAttribute('title', label);\n this._button.classList.remove('aparte-is-streaming');\n }\n\n private _handleClick(e: MouseEvent): void {\n e.preventDefault();\n this._getRoot()?.submit();\n }\n\n private _syncState(): void {\n const root = this._getRoot();\n if (!root || !this._button) return;\n if (root.streaming) return; // streaming state managed separately\n\n const isEmpty = root.value.trim() === '' && root.attachments.length === 0;\n this._button.disabled = root.disabled || isEmpty;\n this._button.innerHTML = this._getSendIcon();\n const label = resolveConfig(this).t('sendButton') || 'Send';\n this._button.setAttribute('aria-label', label);\n this._button.setAttribute('title', label);\n this._button.classList.remove('aparte-is-streaming');\n }\n\n private _syncStreamingState(streaming: boolean): void {\n if (!this._button) return;\n if (streaming) {\n this._button.disabled = false;\n this._button.innerHTML = this._getStopIcon();\n // Was the bare literal 'Stop', so no locale could reach it — the same\n // gap `aparte-composer-cancel` had, on a second element. The key is\n // declared now.\n const label = resolveConfig(this).t('stopButton') || 'Stop';\n this._button.setAttribute('aria-label', label);\n this._button.setAttribute('title', label);\n this._button.classList.add('aparte-is-streaming');\n } else {\n this._syncState();\n }\n }\n\n /**\n * The icon for submitting an ANSWER, which is not the same act as sending a\n * message — one button, two meanings, and it has to say which one it is.\n */\n private _getSubmitIcon(): string {\n // No fallback chain: `getIcon` already returns a built-in when the consumer's\n // icon set has no entry, so `|| getIcon('send')` was dead code — written on the\n // assumption that it could come back empty, and a test proved it cannot.\n return resolveConfig(this).getIcon('check');\n }\n\n private _getSendIcon(): string {\n return resolveConfig(this).getIcon('send') || 'Send';\n }\n\n private _getStopIcon(): string {\n return resolveConfig(this).getIcon('stop');\n }\n}\n\nif (!customElements.get('aparte-composer-send')) {\n customElements.define('aparte-composer-send', AparteComposerSend);\n}\n","import { resolveConfig } from '../../config/index.js';\nimport type { AparteComposer } from './aparte-composer.js';\nimport { escapeAttr } from '../../utils/escape.js';\nimport { subscribeConfigChange } from '../../config/config-subscribe.js';\n\n/**\n * Cancel/stop streaming button primitive for <aparte-composer>.\n *\n * @element aparte-composer-cancel\n * Must be a descendant of <aparte-composer>.\n *\n * Hidden when not streaming. Visible only during active streaming.\n *\n * @example\n * <!-- Only needed when you want a SEPARATE stop button: <aparte-composer-send> already\n * turns into one while streaming. This stays hidden until then. -->\n * <aparte-composer>\n * <div class=\"aparte-composer-row\">\n * <aparte-composer-input style=\"flex: 1\"></aparte-composer-input>\n * <aparte-composer-cancel></aparte-composer-cancel>\n * <aparte-composer-send></aparte-composer-send>\n * </div>\n * </aparte-composer>\n */\nexport class AparteComposerCancel extends HTMLElement {\n private _button: HTMLButtonElement | null = null;\n private _unsubscribes: (() => void)[] = [];\n\n // Bound handler\n private _onClick = this._handleClick.bind(this);\n\n connectedCallback(): void {\n this._render();\n this._connectToRoot();\n this._unsubscribes.push(subscribeConfigChange(this, () => this._refreshChrome()));\n }\n\n disconnectedCallback(): void {\n this._button?.removeEventListener('click', this._onClick);\n this._unsubscribes.forEach(fn => fn());\n this._unsubscribes = [];\n }\n\n // ── Private ─────────────────────────────────────────────────────────────\n\n private _getRoot(): AparteComposer | null {\n return this.closest('aparte-composer') as AparteComposer | null;\n }\n\n private _render(): void {\n if (this.querySelector('.aparte-cc-button')) return;\n\n const label = resolveConfig(this).t('stopButton') || 'Stop';\n const icon = this._getStopIcon();\n\n this.innerHTML = `<button\n class=\"aparte-cc-button\"\n aria-label=\"${escapeAttr(label)}\"\n title=\"${escapeAttr(label)}\"\n hidden\n >${icon}</button>`; // safe-text: _getStopIcon() returns the provider's SVG markup — escaping it would print the source\n\n this._button = this.querySelector('.aparte-cc-button');\n this._button?.addEventListener('click', this._onClick);\n }\n\n private _connectToRoot(): void {\n const root = this._getRoot();\n if (!root) return;\n\n this._unsubscribes.push(\n root._on('streaming-change', ({ streaming }) => {\n if (this._button) this._button.hidden = !streaming;\n })\n );\n\n // Sync initial state\n if (root.streaming && this._button) this._button.hidden = false;\n }\n\n private _handleClick(e: MouseEvent): void {\n e.preventDefault();\n this._getRoot()?.cancel();\n }\n\n /**\n * Re-read the accessible name and the icon in place.\n *\n * `hidden` is NOT touched: `_render()` always renders this button hidden and only\n * the root's `streaming-change` listener ever un-hides it, so a rebuild would make\n * the stop button vanish in the middle of a turn.\n */\n private _refreshChrome(): void {\n if (!this._button) return;\n const label = resolveConfig(this).t('stopButton') || 'Stop';\n this._button.setAttribute('aria-label', label);\n this._button.setAttribute('title', label);\n this._button.innerHTML = this._getStopIcon();\n }\n\n private _getStopIcon(): string {\n return resolveConfig(this).getIcon('stop');\n }\n}\n\nif (!customElements.get('aparte-composer-cancel')) {\n customElements.define('aparte-composer-cancel', AparteComposerCancel);\n}\n","import type { AparteComposer } from './aparte-composer.js';\nimport { resolveConfig } from '../../config/config-context.js';\nimport { escapeAttr } from '../../utils/escape.js';\n\n/** ✗ glyph for the hover remove button. */\nconst REMOVE_ICON =\n '<svg width=\"10\" height=\"10\" viewBox=\"0 0 12 12\" fill=\"currentColor\" aria-hidden=\"true\">' +\n '<path d=\"M9.5 3.205 8.795 2.5 6 5.295 3.205 2.5 2.5 3.205 5.295 6 2.5 8.795l.705.705' +\n 'L6 6.705l2.795 2.795.705-.705L6.705 6z\"/></svg>';\n\n/**\n * Renders a square thumbnail tile for each file attached to the root composer.\n *\n * @element aparte-composer-attachments\n * Image files show the actual picture; other files show an extension badge.\n * The filename and a remove (✗) button surface on hover. Clicking an image asks\n * the app to open it full-size (`aparte-attachment-preview`) — only when the app\n * declared `attachmentPreview` via `aparteGlobalConfig.setHostHandlers()`.\n * Automatically hidden when there are no attachments.\n * Must be a descendant of <aparte-composer>.\n *\n * @fires {CustomEvent<AparteAttachmentPreviewEventDetail>} aparte-attachment-preview - An attached image was clicked; the app opens it full-size, and only if it declared `attachmentPreview`.\n *\n * @example\n * <!-- The strip hides itself while nothing is attached. Pair it with the picker, and\n * only if your loop actually reads the files from the send event. -->\n * <aparte-composer>\n * <div class=\"aparte-composer-shell\">\n * <aparte-composer-attachments></aparte-composer-attachments>\n * <div class=\"aparte-composer-row\">\n * <aparte-composer-add-attachment></aparte-composer-add-attachment>\n * <aparte-composer-input style=\"flex: 1\"></aparte-composer-input>\n * <aparte-composer-send></aparte-composer-send>\n * </div>\n * </div>\n * </aparte-composer>\n */\nexport class AparteComposerAttachments extends HTMLElement {\n private _unsubscribes: (() => void)[] = [];\n /** Object URLs minted for image previews — revoked on re-render/disconnect. */\n private _objectUrls: string[] = [];\n\n connectedCallback(): void {\n this._render([]);\n this._connectToRoot();\n }\n\n disconnectedCallback(): void {\n this._unsubscribes.forEach(fn => fn());\n this._unsubscribes = [];\n this._revokeUrls();\n }\n\n // ── Private ─────────────────────────────────────────────────────────────\n\n private _getRoot(): AparteComposer | null {\n return this.closest('aparte-composer') as AparteComposer | null;\n }\n\n private _connectToRoot(): void {\n const root = this._getRoot();\n if (!root) return;\n\n this._unsubscribes.push(\n root._on('attachments-change', ({ attachments }) => this._render(attachments))\n );\n\n // Sync initial state\n this._render(root.attachments);\n }\n\n /** Release the previous render's blob URLs so they don't leak. */\n private _revokeUrls(): void {\n this._objectUrls.forEach(url => URL.revokeObjectURL(url));\n this._objectUrls = [];\n }\n\n private _render(files: File[]): void {\n this.hidden = files.length === 0;\n // Free the previous render's preview URLs before minting new ones.\n this._revokeUrls();\n\n this.innerHTML = files.map((file) => {\n const name = this._escape(file.name);\n const remove =\n `<button class=\"aparte-thumb__remove\" type=\"button\" ` +\n `aria-label=\"Remove ${name}\">${REMOVE_ICON}</button>`;\n\n if (file.type.startsWith('image/')) {\n const url = URL.createObjectURL(file);\n this._objectUrls.push(url);\n return `<div class=\"aparte-thumb aparte-thumb--image\" title=\"${escapeAttr(name)}\">` +\n `<img class=\"aparte-thumb__img\" src=\"${escapeAttr(url)}\" alt=\"${escapeAttr(name)}\" />` +\n `<span class=\"aparte-thumb__name\">${name}</span>${remove}</div>`;\n }\n return `<div class=\"aparte-thumb aparte-thumb--file\" title=\"${escapeAttr(name)}\">` +\n `<span class=\"aparte-thumb__ext\">${this._escape(this._ext(file.name))}</span>` +\n `<span class=\"aparte-thumb__name\">${name}</span>${remove}</div>`;\n }).join('');\n\n // Remove buttons — every file has exactly one tile, so the button\n // index lines up with the attachments index.\n this.querySelectorAll('.aparte-thumb__remove').forEach((btn, i) => {\n btn.addEventListener('click', (e) => {\n e.stopPropagation();\n const root = this._getRoot();\n if (root) root.removeAttachment(root.attachments[i]!);\n });\n });\n\n // Image tiles ask for the full-size preview — only when the app declared it\n // opens one (same rule as the sent-message strip in the bubble).\n if (!resolveConfig(this).getHostHandlers().attachmentPreview) return;\n this.querySelectorAll('.aparte-thumb--image').forEach(tile => {\n tile.setAttribute('role', 'button');\n tile.setAttribute('tabindex', '0');\n const open = (): void => {\n const img = tile.querySelector('.aparte-thumb__img') as HTMLImageElement | null;\n if (!img) return;\n this.dispatchEvent(new CustomEvent('aparte-attachment-preview', {\n bubbles: true,\n composed: true,\n detail: { url: img.src, name: tile.getAttribute('title') ?? '' },\n }));\n };\n tile.addEventListener('click', open);\n tile.addEventListener('keydown', (e) => {\n const key = (e as KeyboardEvent).key;\n if (key !== 'Enter' && key !== ' ') return;\n e.preventDefault();\n open();\n });\n });\n }\n\n /** Uppercased file extension (≤4 chars), or 'FILE' when there is none. */\n private _ext(filename: string): string {\n const dot = filename.lastIndexOf('.');\n return dot > 0 ? filename.slice(dot + 1).toUpperCase().slice(0, 4) : 'FILE';\n }\n\n private _escape(str: string): string {\n return str.replace(/&/g, '&').replace(/</g, '<').replace(/>/g, '>').replace(/\"/g, '"').replace(/'/g, ''');\n }\n}\n\nif (!customElements.get('aparte-composer-attachments')) {\n customElements.define('aparte-composer-attachments', AparteComposerAttachments);\n}\n","import { resolveConfig } from '../../config/index.js';\nimport type { AparteComposer } from './aparte-composer.js';\nimport { escapeAttr } from '../../utils/escape.js';\nimport { subscribeConfigChange } from '../../config/config-subscribe.js';\n\n/**\n * File picker button for <aparte-composer>.\n *\n * @element aparte-composer-add-attachment\n * Opens a native file picker on click, then pushes picked files to root.addAttachments().\n * Also sets up drag & drop on the nearest <aparte-composer> root.\n *\n * @attr {string} accept - MIME types / extensions passed to the file input (e.g. \"image/*,.pdf\")\n * @attr {boolean} multiple - Allow multiple file selection (default: true)\n * @attr {boolean} disabled - Greys out the picker and ignores drops.\n *\n * @example\n * <!-- Opt-in: nothing consumes the files unless your host does (an AparteClient, or\n * your own listener reading `event.detail.files` off `aparte-send`). -->\n * <aparte-composer>\n * <div class=\"aparte-composer-row\">\n * <aparte-composer-add-attachment accept=\"image/*,.pdf\"></aparte-composer-add-attachment>\n * <aparte-composer-input style=\"flex: 1\"></aparte-composer-input>\n * <aparte-composer-send></aparte-composer-send>\n * </div>\n * </aparte-composer>\n */\nexport class AparteComposerAddAttachment extends HTMLElement {\n private _button: HTMLButtonElement | null = null;\n private _dragCleanup: (() => void) | null = null;\n private _unsubscribes: (() => void)[] = [];\n\n // Bound handler\n private _onClick = this._handleClick.bind(this);\n\n static get observedAttributes(): string[] {\n return ['accept', 'multiple', 'disabled'];\n }\n\n connectedCallback(): void {\n this._render();\n this._connectToRoot();\n this._setupDragDrop();\n this._unsubscribes.push(subscribeConfigChange(this, () => this._refreshChrome()));\n }\n\n disconnectedCallback(): void {\n this._button?.removeEventListener('click', this._onClick);\n this._dragCleanup?.();\n this._unsubscribes.forEach(fn => fn());\n this._unsubscribes = [];\n }\n\n attributeChangedCallback(name: string, _old: string | null, value: string | null): void {\n if (name === 'disabled' && this._button) {\n this._button.disabled = value !== null;\n }\n }\n\n // ── Private ─────────────────────────────────────────────────────────────\n\n private _getRoot(): AparteComposer | null {\n return this.closest('aparte-composer') as AparteComposer | null;\n }\n\n /**\n * Re-read the label and the icon on the button that already exists.\n *\n * Deliberately not a re-render: `_render()` returns early once the button is\n * there, and its `disabled` computation ignores `root.streaming` while the\n * streaming listener sets `disabled` directly — so rebuilding would silently\n * re-enable the attach button mid-turn, and drop focus if the user were on it.\n * The native file input and the drag listeners live outside this element\n * (on `document.body` and on the composer root), so they are untouched either way.\n */\n private _refreshChrome(): void {\n if (!this._button) return;\n const cfg = resolveConfig(this);\n const label = cfg.t('actionUpload') || 'Attach file';\n this._button.setAttribute('aria-label', label);\n this._button.setAttribute('title', label);\n this._button.innerHTML = cfg.getIcon('paperclip') || this._defaultIcon();\n }\n\n private _render(): void {\n if (this.querySelector('.aparte-caa-button')) return;\n\n const label = resolveConfig(this).t('actionUpload') || 'Attach file';\n const icon = resolveConfig(this).getIcon('paperclip') || this._defaultIcon();\n const disabled = this.hasAttribute('disabled') || this._getRoot()?.disabled || false;\n\n this.innerHTML = `<button\n class=\"aparte-caa-button aparte-action-button\"\n aria-label=\"${escapeAttr(label)}\"\n title=\"${escapeAttr(label)}\"\n type=\"button\"\n ${disabled ? 'disabled' : ''}\n >${icon}</button>`;\n\n this._button = this.querySelector('.aparte-caa-button');\n this._button?.addEventListener('click', this._onClick);\n }\n\n private _connectToRoot(): void {\n const root = this._getRoot();\n if (!root) return;\n\n this._unsubscribes.push(\n root._on('disabled-change', ({ disabled }) => {\n if (this._button) this._button.disabled = disabled;\n })\n );\n this._unsubscribes.push(\n root._on('streaming-change', ({ streaming }) => {\n if (this._button) this._button.disabled = streaming || root.disabled;\n })\n );\n }\n\n private _handleClick(): void {\n const input = document.createElement('input');\n input.type = 'file';\n input.multiple = !this.hasAttribute('multiple') || this.getAttribute('multiple') !== 'false';\n const accept = this.getAttribute('accept');\n if (accept) input.accept = accept;\n input.style.display = 'none';\n\n document.body.appendChild(input);\n input.addEventListener('change', () => {\n if (input.files?.length) this._getRoot()?.addAttachments(input.files);\n document.body.removeChild(input);\n }, { once: true });\n input.click();\n }\n\n private _setupDragDrop(): void {\n const root = this._getRoot();\n if (!root) return;\n\n const prevent = (e: Event) => { e.preventDefault(); e.stopPropagation(); };\n const onDragOver = (e: Event) => {\n if (root.disabled) return; // no drop target while disabled (e.g. streaming)\n prevent(e);\n root.classList.add('aparte-is-dragover');\n };\n const onDragLeave = (e: Event) => { prevent(e); root.classList.remove('aparte-is-dragover'); };\n const onDrop = (e: DragEvent) => {\n prevent(e); // always block the browser from navigating to the dropped file\n root.classList.remove('aparte-is-dragover');\n if (root.disabled) return; // don't attach while disabled (the add button is blocked too)\n const files = e.dataTransfer?.files;\n if (files?.length) this._getRoot()?.addAttachments(files);\n };\n\n root.addEventListener('dragover', onDragOver);\n root.addEventListener('dragleave', onDragLeave);\n root.addEventListener('drop', onDrop);\n\n this._dragCleanup = () => {\n root.removeEventListener('dragover', onDragOver);\n root.removeEventListener('dragleave', onDragLeave);\n root.removeEventListener('drop', onDrop);\n };\n }\n\n private _defaultIcon(): string {\n return `<svg width=\"16\" height=\"16\" viewBox=\"0 0 24 24\" fill=\"none\" stroke=\"currentColor\" stroke-width=\"2\" stroke-linecap=\"round\" stroke-linejoin=\"round\"><path d=\"m21.44 11.05-9.19 9.19a6 6 0 0 1-8.49-8.49l8.57-8.57A4 4 0 1 1 18 8.84l-8.59 8.57a2 2 0 0 1-2.83-2.83l8.49-8.48\"/></svg>`;\n }\n}\n\nif (!customElements.get('aparte-composer-add-attachment')) {\n customElements.define('aparte-composer-add-attachment', AparteComposerAddAttachment);\n}\n","import { resolveConfig, type AparteIconName } from '../../config/index.js';\nimport type { AparteComposer } from './aparte-composer.js';\nimport { escapeAttr } from '../../utils/escape.js';\nimport { subscribeConfigChange } from '../../config/config-subscribe.js';\n\n/**\n * Generic action button primitive for <aparte-composer>.\n *\n * @element aparte-composer-action\n * The consumer declares it directly in markup — no global registration needed.\n *\n * @attr {string} icon - Icon key for aparteGlobalConfig.getIcon(), or raw SVG/HTML starting with `<`\n * @attr {string} label - Accessible label (also used as tooltip)\n * @attr {boolean} disabled - Disables the button\n *\n * @fires aparte-action-click - Bubbles up when the button is clicked\n * detail: { actionId: string, composer: AparteComposer | null }\n *\n * @slot default - Optional: override button content entirely\n *\n * @example\n * <aparte-composer-action icon=\"star\" label=\"Favourite\"\n * (click)=\"onFavourite()\">\n * </aparte-composer-action>\n */\nexport class AparteComposerAction extends HTMLElement {\n private _button: HTMLButtonElement | null = null;\n private _unsubscribes: (() => void)[] = [];\n\n // Bound handler\n private _onClick = this._handleClick.bind(this);\n\n static get observedAttributes(): string[] {\n return ['icon', 'label', 'disabled'];\n }\n\n connectedCallback(): void {\n this._render();\n this._connectToRoot();\n // Icon only, and no locale: this element's label is the consumer's `label`\n // ATTRIBUTE, so the app owns that string and a locale change is correctly a\n // no-op here. The write is the same one `attributeChangedCallback` does for\n // the `icon` attribute — `_resolveIcon` already decides between a provider\n // key and raw markup, so calling it again is idempotent.\n this._unsubscribes.push(subscribeConfigChange(this, () => {\n if (this._button) this._button.innerHTML = this._resolveIcon(this.getAttribute('icon') ?? '');\n }));\n }\n\n disconnectedCallback(): void {\n this._button?.removeEventListener('click', this._onClick);\n this._unsubscribes.forEach(fn => fn());\n this._unsubscribes = [];\n }\n\n attributeChangedCallback(name: string, _old: string | null, value: string | null): void {\n if (!this._button) return;\n if (name === 'disabled') {\n this._button.disabled = value !== null;\n }\n if (name === 'label') {\n this._button.setAttribute('aria-label', value ?? '');\n this._button.setAttribute('title', value ?? '');\n }\n if (name === 'icon') {\n this._button.innerHTML = this._resolveIcon(value ?? '');\n }\n }\n\n // ── Private ─────────────────────────────────────────────────────────────\n\n private _getRoot(): AparteComposer | null {\n return this.closest('aparte-composer') as AparteComposer | null;\n }\n\n private _render(): void {\n if (this.querySelector('.aparte-cact-button')) return;\n\n // `label` is a host-set attribute (often bound to dynamic/translated\n // text by the consumer) — escape before it lands in a double-quoted\n // attribute so a stray `\"` can't break out and inject markup.\n const label = escapeAttr(this.getAttribute('label') ?? '');\n const icon = this._resolveIcon(this.getAttribute('icon') ?? ''); // safe-text: _resolveIcon returns provider SVG, or the host-set icon attribute verbatim when it starts with < — documented as trusted markup, same contract as AparteIconProvider\n const disabled = this.hasAttribute('disabled') || this._getRoot()?.disabled || false;\n\n this.innerHTML = `<button\n class=\"aparte-cact-button aparte-action-button\"\n aria-label=\"${label}\"\n title=\"${label}\"\n type=\"button\"\n ${disabled ? 'disabled' : ''}\n >${icon}</button>`;\n\n this._button = this.querySelector('.aparte-cact-button');\n this._button?.addEventListener('click', this._onClick);\n }\n\n private _connectToRoot(): void {\n const root = this._getRoot();\n if (!root) return;\n\n this._unsubscribes.push(\n root._on('disabled-change', ({ disabled }) => {\n if (this._button) this._button.disabled = disabled || this.hasAttribute('disabled');\n })\n );\n this._unsubscribes.push(\n root._on('streaming-change', ({ streaming }) => {\n if (this._button) this._button.disabled = streaming || root.disabled || this.hasAttribute('disabled');\n })\n );\n }\n\n private _handleClick(_e: MouseEvent): void {\n this.dispatchEvent(new CustomEvent<AparteActionClickEventDetail>('aparte-action-click', {\n bubbles: true,\n composed: true,\n detail: { actionId: this.getAttribute('action-id') ?? '', composer: this._getRoot() },\n }));\n }\n\n private _resolveIcon(icon: string): string {\n if (!icon) return '';\n if (icon.trimStart().startsWith('<')) return icon;\n return resolveConfig(this).getIcon(icon as AparteIconName) ?? icon;\n }\n\n /** Escape a value before it lands in a double-quoted HTML attribute. */\n}\n\nif (!customElements.get('aparte-composer-action')) {\n customElements.define('aparte-composer-action', AparteComposerAction);\n}\n\n/**\n * Detail payload for `aparte-action-click`.\n *\n * `<aparte-composer-action>` is a publicly exported element whose only purpose is\n * to emit this event, and nothing in core listens for it — so the app IS the\n * consumer, and it had no type to read `e.detail` with. The shape was already\n * published in prose in the generated API reference; this makes it compile.\n *\n * @event aparte-action-click\n */\nexport interface AparteActionClickEventDetail {\n /** The `action-id` attribute of the button that was clicked, or `''`. */\n actionId: string;\n /** The owning composer, or `null` when the button is used outside one. */\n composer: AparteComposer | null;\n}\n","/**\n * The composer's bottom row — the strip a mode picker, a model selector or a token\n * counter belongs in, rather than a bar of your own floating below the chat. Purely\n * structural: it lays its children out in a row and gets out of the way.\n *\n * @element aparte-composer-toolbar\n *\n * **Position is the DOM order.** `margin-inline-start: auto` on a child pushes it (and\n * everything after it) to the end of the row. That is the whole placement API on\n * purpose: there is no `left`/`right` to be wrong about, so the row reads correctly in a\n * right-to-left locale without the author thinking about it.\n *\n * The row is not part of the default `<aparte-chat>` shell — nothing is drawn until you\n * put something in it.\n *\n * @attr {boolean} data-empty - Reflected BY the element while it holds no element child; the\n * stylesheet hides it then. Read-only, do not set it yourself.\n *\n * @example\n * <aparte-composer>\n * <div class=\"aparte-composer-shell\">\n * <div class=\"aparte-composer-row\">\n * <aparte-composer-input></aparte-composer-input>\n * <aparte-composer-send></aparte-composer-send>\n * </div>\n *\n * <!-- `aparte-model-selector` is NOT part of core: importing\n * `@aparte/plugin-model-selector` is what defines it. Until then the tag\n * renders empty and inert with no error, and upgrades by itself when the\n * definition arrives. Any element of your own works here too. -->\n * <aparte-composer-toolbar>\n * <my-mode-picker></my-mode-picker>\n * <aparte-model-selector style=\"margin-inline-start:auto\"></aparte-model-selector>\n * </aparte-composer-toolbar>\n * </div>\n * </aparte-composer>\n */\nexport class AparteComposerToolbar extends HTMLElement {\n private _observer: MutationObserver | null = null;\n\n connectedCallback(): void {\n this._syncEmpty();\n // Children can arrive after connection — a framework commits the element and its\n // children in whichever order suits it, and a consumer may add a control later.\n this._observer ??= new MutationObserver(() => this._syncEmpty());\n this._observer.observe(this, { childList: true });\n }\n\n disconnectedCallback(): void {\n this._observer?.disconnect();\n this._observer = null;\n }\n\n /**\n * Reflect `data-empty` from the presence of an ELEMENT child.\n *\n * Not `:empty` in CSS: that selector does not match an element holding a whitespace\n * text node, so a template that indents its content keeps the row — separator,\n * padding and all — while it looks empty to the user. Every framework template\n * indents. An empty row must not draw its own separator (the same rule as an empty\n * bubble action bar).\n *\n * Non-whitespace TEXT counts as content, not just an element child: a hand-written\n * row holding a bare token count (`<aparte-composer-toolbar>1 240 tokens</…>`) is\n * not empty, and hiding it would be a twenty-minute mystery for whoever wrote it.\n */\n private _syncEmpty(): void {\n const hasContent = Boolean(this.firstElementChild) || this.textContent?.trim() !== '';\n if (hasContent) this.removeAttribute('data-empty');\n else this.setAttribute('data-empty', '');\n }\n}\n\nif (!customElements.get('aparte-composer-toolbar')) {\n customElements.define('aparte-composer-toolbar', AparteComposerToolbar);\n}\n","import { resolveConfig } from '../../config/index.js';\nimport { escapeAttr } from '../../utils/escape.js';\n\nexport interface AparteConversationListItem {\n id: string;\n title: string;\n updatedAt?: number;\n /** When set, the item renders the unarchive action instead of archive. *\n */\n archivedAt?: number;\n}\n\nexport interface AparteConversationSelectDetail {\n id: string;\n}\n\nexport interface AparteConversationDeleteDetail {\n id: string;\n}\n\nexport interface AparteConversationArchiveDetail {\n id: string;\n}\n\n/**\n * Conversation-history sidebar — a framework-agnostic web component. The host sets\n * the `conversations` JS property and the `active-id` attribute; this renders the\n * list and fires the user's intent, never acting on it itself.\n *\n * These four `@fires` reached the manifest through neither of its two paths, which\n * is why this element had no `events` key at all. The tag block was in a docblock at\n * the top of the file, separated from the class by imports and four interfaces — and\n * TypeScript attaches only the adjacent comment. The fallback could not save it\n * either: the analyser's auto-detection visits `ts.isMethodDeclaration` only, and\n * every dispatch here happens inside the `_onClick` arrow class field.\n *\n * @element aparte-conversation-list\n * @attr {string} active-id - The id of the conversation to render as selected.\n *\n * @fires {CustomEvent<AparteConversationSelectDetail>} aparte-select-conversation - A row was activated; the host loads that conversation.\n * @fires {CustomEvent<AparteConversationDeleteDetail>} aparte-delete-conversation - The delete action was pressed. Nothing is removed here.\n * @fires {CustomEvent<AparteConversationArchiveDetail>} aparte-archive-conversation - The archive action was pressed on a live conversation.\n * @fires {CustomEvent<AparteConversationArchiveDetail>} aparte-unarchive-conversation - The same action on an already-archived one; same detail shape, opposite intent.\n *\n * @example\n * // The host owns the data: set the `conversations` property, listen for the intent.\n * const list = document.querySelector('aparte-conversation-list')!;\n * list.conversations = [\n * { id: 'c1', title: 'Deploy checklist', updatedAt: Date.now() },\n * { id: 'c2', title: 'Old thread', updatedAt: 0, archivedAt: Date.now() },\n * ];\n * list.setAttribute('active-id', 'c1');\n *\n * list.addEventListener('aparte-select-conversation', (e) => load(e.detail.id));\n * list.addEventListener('aparte-delete-conversation', (e) => remove(e.detail.id));\n */\nexport class AparteConversationList extends HTMLElement {\n private _conversations: AparteConversationListItem[] = [];\n private _activeId: string | null = null;\n\n static get observedAttributes(): string[] {\n return ['active-id'];\n }\n\n // ─── Lifecycle ────────────────────────────────────────────────────────\n\n connectedCallback(): void {\n if (!this.classList.contains('aparte-conv-list')) {\n this.classList.add('aparte-conv-list');\n }\n if (!this.getAttribute('role')) {\n this.setAttribute('role', 'navigation');\n }\n this._render();\n window.addEventListener('aparte-config-change', this._onConfigChange);\n }\n\n disconnectedCallback(): void {\n window.removeEventListener('aparte-config-change', this._onConfigChange);\n }\n\n attributeChangedCallback(name: string, oldValue: string | null, newValue: string | null): void {\n if (oldValue === newValue) return;\n if (name === 'active-id') {\n this._activeId = newValue;\n this._updateActiveState();\n }\n }\n\n /**\n * Re-render on a locale switch: every row's title fallback and both button\n * labels come from the locale, so without this the list stayed in the previous\n * language until something else happened to re-render it. Only OUR config.\n */\n private _onConfigChange = (e: Event): void => {\n const detail = (e as CustomEvent).detail as { config?: unknown } | undefined;\n if (detail?.config && detail.config !== resolveConfig(this)) return;\n this._render();\n };\n\n // ─── Public API ───────────────────────────────────────────────────────\n\n /** Set the list of conversations to display. Triggers a re-render. */\n set conversations(items: AparteConversationListItem[]) {\n this._conversations = Array.isArray(items) ? items : [];\n this._render();\n }\n\n get conversations(): AparteConversationListItem[] {\n return this._conversations;\n }\n\n // ─── Rendering ────────────────────────────────────────────────────────\n\n private _render(): void {\n this.innerHTML = this._conversations\n .map(conv => this._renderItem(conv))\n .join('');\n this._bindEvents();\n }\n\n private _renderItem(conv: AparteConversationListItem): string {\n const locale = resolveConfig(this).getLocale();\n const isActive = conv.id === this._activeId;\n const isArchived = !!conv.archivedAt;\n const activeClass = isActive ? ' aparte-conv-item--active' : '';\n const archivedClass = isArchived ? ' aparte-conv-item--archived' : '';\n const escapedId = this._esc(conv.id);\n const escapedTitle = this._esc(conv.title || locale.newChat);\n const deleteLabel = this._esc(locale.deleteConversation);\n const archiveLabel = this._esc(locale['archiveConversation'] ?? 'Archive conversation');\n const unarchiveLabel = this._esc(locale['unarchiveConversation'] ?? 'Unarchive conversation');\n const archiveAction = isArchived ? 'unarchive' : 'archive';\n const archiveAriaLabel = isArchived ? unarchiveLabel : archiveLabel;\n // Distinct icons: a downward tray for archive, an upward tray for unarchive.\n const archiveIcon = isArchived // safe-text: both branches are literal inline SVG written here — not input\n ? `<svg width=\"12\" height=\"12\" viewBox=\"0 0 24 24\" fill=\"none\" stroke=\"currentColor\" stroke-width=\"2.5\" stroke-linecap=\"round\" stroke-linejoin=\"round\" aria-hidden=\"true\"><polyline points=\"3 8 21 8\"/><path d=\"M5 8v11a2 2 0 0 0 2 2h10a2 2 0 0 0 2-2V8\"/><polyline points=\"9 14 12 11 15 14\"/><line x1=\"12\" y1=\"11\" x2=\"12\" y2=\"19\"/></svg>`\n : `<svg width=\"12\" height=\"12\" viewBox=\"0 0 24 24\" fill=\"none\" stroke=\"currentColor\" stroke-width=\"2.5\" stroke-linecap=\"round\" stroke-linejoin=\"round\" aria-hidden=\"true\"><polyline points=\"3 8 21 8\"/><path d=\"M5 8v11a2 2 0 0 0 2 2h10a2 2 0 0 0 2-2V8\"/><polyline points=\"9 14 12 17 15 14\"/><line x1=\"12\" y1=\"11\" x2=\"12\" y2=\"17\"/></svg>`;\n return `\n<div\n class=\"aparte-conv-item${activeClass}${archivedClass}\"\n role=\"button\"\n tabindex=\"0\"\n data-conv-id=\"${escapedId}\"\n aria-current=\"${isActive ? 'page' : 'false'}\"\n>\n <span class=\"aparte-conv-item__title\">${escapedTitle}</span>\n <button\n class=\"aparte-conv-item__archive\"\n type=\"button\"\n data-archive-id=\"${escapedId}\"\n data-archive-action=\"${escapeAttr(archiveAction)}\"\n aria-label=\"${escapeAttr(archiveAriaLabel)}\"\n tabindex=\"0\"\n >${archiveIcon}</button>\n <button\n class=\"aparte-conv-item__delete\"\n type=\"button\"\n data-delete-id=\"${escapedId}\"\n aria-label=\"${deleteLabel}\"\n tabindex=\"0\"\n >\n <svg width=\"12\" height=\"12\" viewBox=\"0 0 24 24\" fill=\"none\" stroke=\"currentColor\" stroke-width=\"2.5\"\n stroke-linecap=\"round\" stroke-linejoin=\"round\" aria-hidden=\"true\">\n <path d=\"M18 6L6 18M6 6l12 12\"/>\n </svg>\n </button>\n</div>`;\n }\n\n private _bindEvents(): void {\n this.addEventListener('click', this._onClick);\n this.addEventListener('keydown', this._onKeydown);\n }\n\n private _onClick = (e: Event): void => {\n const target = e.target as HTMLElement;\n const archiveBtn = target.closest('[data-archive-id]') as HTMLElement | null;\n if (archiveBtn) {\n e.stopPropagation();\n const id = archiveBtn.dataset['archiveId']!;\n const action = archiveBtn.dataset['archiveAction'];\n const eventName = action === 'unarchive'\n ? 'aparte-unarchive-conversation'\n : 'aparte-archive-conversation';\n this.dispatchEvent(new CustomEvent<AparteConversationArchiveDetail>(\n eventName,\n { detail: { id }, bubbles: true, composed: true }\n ));\n return;\n }\n const deleteBtn = target.closest('[data-delete-id]') as HTMLElement | null;\n if (deleteBtn) {\n e.stopPropagation();\n const id = deleteBtn.dataset['deleteId']!;\n this.dispatchEvent(new CustomEvent<AparteConversationDeleteDetail>(\n 'aparte-delete-conversation',\n { detail: { id }, bubbles: true, composed: true }\n ));\n return;\n }\n const item = target.closest('[data-conv-id]') as HTMLElement | null;\n if (item) {\n const id = item.dataset['convId']!;\n this.dispatchEvent(new CustomEvent<AparteConversationSelectDetail>(\n 'aparte-select-conversation',\n { detail: { id }, bubbles: true, composed: true }\n ));\n }\n };\n\n private _onKeydown = (e: KeyboardEvent): void => {\n if (e.key !== 'Enter' && e.key !== ' ') return;\n const item = (e.target as HTMLElement).closest('[data-conv-id]') as HTMLElement | null;\n if (item) {\n e.preventDefault();\n item.click();\n }\n };\n\n /** Update active class without full re-render (perf optimisation). */\n private _updateActiveState(): void {\n const items = this.querySelectorAll<HTMLElement>('[data-conv-id]');\n items.forEach(el => {\n const isActive = el.dataset['convId'] === this._activeId;\n el.classList.toggle('aparte-conv-item--active', isActive);\n el.setAttribute('aria-current', isActive ? 'page' : 'false');\n });\n }\n\n // ─── Helpers ──────────────────────────────────────────────────────────\n\n private _esc(str: string): string {\n return str\n .replace(/&/g, '&')\n .replace(/\"/g, '"')\n .replace(/</g, '<')\n .replace(/>/g, '>')\n .replace(/'/g, ''');\n }\n}\n\nif (!customElements.get('aparte-conversation-list')) customElements.define('aparte-conversation-list', AparteConversationList);\n","/**\n * Aparte\n * High-performance AI conversation engine in Vanilla TypeScript\n * Zero-dependency Web Components for LLM streaming\n *\n * ⚠️ This is the **browser** entry: it defines the custom elements and imports CSS\n * at module scope, so it needs a DOM. **Node resolves `index.node.ts` instead**\n * (via the `node` condition in package.json) — a DOM-free entry with the client,\n * host, transports, the chat handler and every type. This file sits first in the\n * exports map only because of the repo-local `@aparte-workspace/source` condition,\n * which is why reading it can look like \"this package can't run in Node\".\n * See the \"Node / SSR\" section of the README.\n *\n * @packageDocumentation\n */\nimport './styles/aparte.css';\nimport './primitives/select/select.css';\nimport './primitives/progress-spinner/progress-spinner.css';\n\n// Global HTMLElementEventMap augmentation — typed `e.detail` for aparté events.\nimport './types/event-map.js';\n// Global HTMLElementTagNameMap augmentation — `querySelector('aparte-…')` returns\n// the concrete element, not `Element`. Both are DOM-only, hence browser-entry only.\nimport './types/element-map.js';\n\n// Export primitives\nexport { AparteSelect, AparteOption, AparteOptgroup, type AparteSelectChangeDetail, type AparteOptgroupToggleEventDetail, AparteProgressSpinner } from './primitives/index.js';\n\n// Export types\nexport type {\n AparteBubbleRole,\n AparteMessage,\n AparteContentParser,\n AparteSendEventDetail,\n AparteViewportConfig,\n AparteInputConfig,\n AparteThemeVariables,\n AparteStatus,\n AparteAttachment,\n AparteMessageBranch,\n AparteBubbleActionsConfig,\n AparteBubbleActionName,\n AparteSegment,\n AparteSegmentType,\n AparteTextSegment,\n AparteThinkingSegment,\n AparteCodeSegment,\n AparteSegmentRenderer,\n AparteCustomSegment,\n AparteToolCallSegment,\n AparteArtifactSegment,\n // The detail of the `aparte-segment-update` event. It reached types/index.ts and\n // stopped there — and types/index.ts is not an entry point, so a consumer could\n // bind the event (it is in the published event table) and never name its detail.\n AparteSegmentUpdateEventDetail,\n // AI Provider types (BYORK)\n AparteAIProvider,\n AparteAIModel,\n AparteAIProviderConfigField,\n AparteAIProviderConfigSchema,\n AparteModelConfig,\n ModelStatus,\n ModelLoadProgress,\n AparteModelChangeEventDetail,\n AparteMessageDoneEventDetail,\n AparteMessageStartEventDetail,\n AparteMessageErrorEventDetail,\n AparteMessageAbortedEventDetail,\n AparteAbortEventDetail,\n AparteCompactEventDetail,\n AparteCompactDoneEventDetail,\n AparteCompactErrorEventDetail,\n AparteAttachmentPreviewEventDetail,\n AparteFileGenReadyEventDetail,\n AparteFileGenErrorEventDetail,\n AparteMessageInfoEventDetail,\n AparteSiblingInfo,\n AparteBranchNavigateEventDetail,\n ApartePathChangedEventDetail,\n AparteRetryEventDetail,\n AparteEditEventDetail,\n AparteFeedbackEventDetail,\n AparteActionEventDetail,\n AparteArtifactStartEventDetail,\n AparteArtifactDeltaEventDetail,\n AparteArtifactReadyEventDetail,\n AparteArtifactRedownloadEventDetail,\n // Chat types\n AparteChatRequest,\n AparteChatResponse,\n AparteChatMessage,\n AparteContentPart,\n AparteTextPart,\n AparteImagePart,\n AparteFilePart,\n AparteStreamEvent,\n AparteStreamEventMap,\n AparteUsage,\n // Tool types\n AparteTool,\n AparteToolCall,\n AparteToolResult,\n AparteToolHandler,\n AparteToolContext,\n AparteToolRenderer,\n AparteToolApprovalRequestDetail,\n // Canonical imperative surface (aliased by every wrapper's handle type).\n AparteChatImperativeApi,\n // The attribute surface of every element, for the wrappers to map over.\n AparteElementAttributes,\n AparteElementTagName,\n AparteAttrValue,\n AparteTemplateAttrs,\n AparteNoAttributes,\n AparteChatAttributes,\n AparteChatViewportAttributes,\n AparteChatBubbleAttributes,\n AparteChatStatusAttributes,\n AparteComposerAttributes,\n AparteComposerInputAttributes,\n AparteComposerActionAttributes,\n AparteComposerAddAttachmentAttributes,\n AparteComposerToolbarAttributes,\n AparteConversationListAttributes,\n AparteSelectAttributes,\n AparteOptionAttributes,\n AparteOptgroupAttributes,\n AparteProgressSpinnerAttributes,\n} from './types/index.js';\n\nexport { AparteErrorCode, AparteError, contentToText } from './types/index.js';\n\n// Export renderers\nexport {\n registerSegmentRenderer,\n unregisterSegmentRenderer,\n getSegmentRenderer,\n collectRendererStyles,\n registerDefaultRenderers,\n // The three the public barrel left behind. `renderers/index.ts` has always\n // exported all eight; this one published five, which made the registry\n // half-public: `declineDefaultRenderers` is the ONLY way to say \"do not install\n // the built-ins on this config\" without constructing an `AparteClient`\n // (`autoRegister: false`), and the bring-your-own-loop guide tells you not to\n // construct one. `installDefaultRenderersOnce` is what a hand-written bubble\n // needs, and `getAllRenderers` is the introspection half — the same reason\n // `hasHighlightProvider` and `renderMarkdown` are public.\n installDefaultRenderersOnce,\n declineDefaultRenderers,\n getAllRenderers\n} from './renderers/index.js';\n\n// Export components\nexport { AparteChat } from './components/index.js';\nexport { AparteChatBubble, populateBubbleFromMessage } from './components/index.js';\nexport type { SyncableBubble } from './components/index.js';\nexport { AparteChatStatus } from './components/index.js';\nexport { AparteChatViewport } from './components/index.js';\n\n// Export composer primitives\nexport { AparteComposer, AparteComposerInput, AparteComposerSend, AparteComposerCancel, AparteComposerAttachments, AparteComposerAddAttachment, AparteComposerAction, AparteComposerToolbar } from './components/index.js';\nexport type { AparteComposerEventMap, AparteComposerEventType, AparteComposerState, AparteComposerChangeEventDetail, AparteActionClickEventDetail } from './components/index.js';\n\n// Export conversation list primitive\nexport { AparteConversationList } from './components/index.js';\nexport type { AparteConversationListItem, AparteConversationSelectDetail, AparteConversationDeleteDetail, AparteConversationArchiveDetail } from './components/index.js';\n\n// Export conversations (types, adapter contract, manager)\nexport type {\n AparteConversation,\n AparteConversationMeta,\n AparteStorageAdapter,\n AparteMemoryFact,\n AparteArtifactRow,\n AparteAttachmentRow,\n} from './conversations/index.js';\nexport { APARTE_CONVERSATION_SCHEMA_VERSION } from './conversations/index.js';\nexport { AparteConversationManager, type ConversationManagerOptions } from './conversations/index.js';\nexport {\n AparteConversationController,\n type AparteChatBinding,\n type AparteConversationControllerOptions,\n} from './conversations/index.js';\n\n// Export the framework-agnostic chat-host orchestrator (streaming/branch/\n// host-method layer that every framework wrapper binds to).\nexport {\n AparteChatHost,\n type AparteChatHostBinding,\n type AparteChatHostOptions,\n} from './host/index.js';\n\n// Export parsers\nexport { AparteStreamParser, parseMarkdownToSegments, deriveArtifactKind } from './parsers/index.js';\nexport type { AparteStreamParserOptions, AparteThinkingDelimiterPair, AparteParserState, AparteParserResult } from './parsers/index.js';\nexport { parseAparteEventStream } from './parsers/index.js';\n\n// Export config\nexport { aparteGlobalConfig, AparteConfig, APARTE_DEFAULT_BUBBLE_ACTIONS, APARTE_DEFAULT_HOST_HANDLERS } from './config/index.js';\nexport type { AparteConfigChangeEventDetail } from './config/index.js';\nexport { resolveConfig, attachConfig, detachConfig, runWithConfig, contextConfig, APARTE_HOST_ATTR } from './config/index.js';\nexport { subscribeConfigChange, APARTE_CONFIG_CHANGE } from './config/index.js';\nexport type { AparteConfigAware } from './config/index.js';\nexport type { AparteMarkdownProvider, AparteStreamingMarkdownProvider, AparteStreamingMarkdownRenderer, AparteHighlightProvider, AparteSystemPromptVarsProvider, AparteSkeletonProvider, AparteSkeletonType, AparteLocale, AparteAction, AparteActionZone, AparteIconProvider, AparteIconName, AparteAvatarProvider, AparteStatusRenderer, AparteErrorRenderer, AparteAttachmentRenderer, AparteElicitationFieldRenderer, AparteElicitationFieldContext, AparteElicitationFieldControl, AparteSiblingNavRenderer, AparteBubbleShellRenderer, AparteModelPreference, AparteModelPreferenceProvider, AparteArtifactPreviewBuilder, AparteSanitizer } from './config/index.js';\nexport { APARTE_DEFAULT_ICON_FALLBACKS, APARTE_DEFAULT_SKELETON_FALLBACKS, APARTE_DEFAULT_LOCALE, defaultSanitizer, isSafeUrl } from './config/index.js';\n\n// Export Client\nexport { AparteClient } from './client/aparte-client.js';\n\n// Custom-element interop helpers shared by the framework wrappers' AparteUi.\nexport { applyElementProps, APARTE_DEFAULT_UI_EVENTS } from './interop/element-props.js';\n// Turns the `File[]` an `aparte-send` carries into renderable attachments — the\n// same conversion ConversationController does, for consumers driving the\n// imperative API themselves.\nexport { filesToAttachments, revokeAttachmentUrls } from './utils/files-to-attachments.js';\n// Is a message waiting for a reply? Shared by the viewport, the four wrappers and\n// any consumer rendering its own bubble — one rule, so they can't disagree.\nexport { isAwaitingReply } from './utils/is-awaiting-reply.js';\n\n// HTML escaping — one implementation for the whole scope. Exported because the\n// plugins render their own HTML (they cannot reach into core's internals) and\n// because a consumer writing a render hook needs it for exactly the same reason.\n// Nine private copies existed before this line; three of them had drifted to\n// escape only four of the five characters that matter.\nexport { escapeHtml, escapeAttr } from './utils/escape.js';\n// `cssEscape` belongs beside them: `pnpm check:attr-escaping` tells a renderer\n// author \"in a selector, use cssEscape()\", and the customization guide says the\n// same — while it was not exported at all, so the only way to follow that advice\n// was `CSS.escape`, which over-escapes inside a quoted attribute selector.\nexport { cssEscape } from './utils/css-escape.js';\n// Exported because the same wall is hit outside core: a wrapper naming its host\n// element, a provider tagging a request, or any bring-your-own-loop consumer\n// generating message ids all reach for `crypto.randomUUID`, which does not exist\n// on `http://` — the LAN deployment this library's own audience runs.\nexport { uuid } from './utils/uuid.js';\n// A segment's own completion rule, and the two readers of what core measured.\n// Exported because a consumer rendering \"thought for 8 s\" needs to know when the span\n// closed, and a rule kept private is a rule re-derived slightly differently outside —\n// the tool call is the trap: it settles by `status`, never by `isStreaming`.\n//\n// `segmentTiming` joins them because the measurements moved into `meta.aparte`, and\n// `segment.meta?.aparte` spelled at each call site is the same rule re-derived by hand\n// — exactly what the other two are exported to prevent.\n//\n// The WRITERS stay internal: only the two owners of a message's segment array may\n// stamp those fields, which `pnpm check:segment-stamp` enforces.\nexport { isSegmentSettled, segmentDuration, segmentTiming } from './utils/segments.js';\n// The PARAMETER types of two documented setters. They existed and were the declared\n// argument types, but were not exported — so anyone typing a settings layer over\n// `setHostHandlers` / `setKeyProvider` had to re-declare the shape by hand.\nexport type { AparteHostHandlersConfig } from './types/models.js';\nexport type { AparteKeyProvider } from './config/aparte-config.js';\nexport type { AparteClientOptions, AparteToolApprovalResolver, AparteCompactionSelector } from './client/aparte-client.js';\n// Structured-stream adapter — DOM half of the runStreamAgent loop (see stream-adapter.ts).\nexport { createStreamAdapter, readableToAsyncIterable } from './client/stream-adapter.js';\nexport type { AparteStreamRunEvent, AparteStreamRunEmitter, StreamAdapterTarget, CreateStreamAdapterOptions, AparteStreamRunner, AparteStreamRunOptions } from './client/stream-adapter.js';\n\n// Export transport seam (where chat requests go + how auth is handled)\nexport { AparteDirectTransport, AparteBackendTransport, createAparteChatHandler, isFormatAdapter } from './transport/index.js';\nexport type { AparteTransport, AparteTransportContext, AparteFormatAdapter, AparteVendorRequest, BackendTransportOptions, DirectTransportOptions, AparteChatHandlerOptions } from './transport/index.js';\n\n// Export runtime utilities\nexport { AparteMessageRepository } from './runtime/message-repository.js';\nexport type { ExportedMessageRepository } from './runtime/message-repository.js';\n\n// Export elicitation (human-in-the-loop typed input)\nexport { requestUserInput, buildElicitationPanel, buildApprovalPanel, AparteElicitationAbortError } from './elicitation/index.js';\nexport type {\n AparteElicitationSchema,\n AparteElicitationField,\n AparteElicitationEnumField,\n AparteElicitationBooleanField,\n AparteElicitationStringField,\n AparteElicitationObjectSchema,\n AparteElicitationRequest,\n AparteElicitationResult,\n AparteElicitationPresenter,\n AparteApprovalOption,\n AparteApprovalAnswer,\n BuiltApprovalPanel,\n BuiltElicitationPanel,\n} from './elicitation/index.js';\n\n// Export the default elicitation presenter Web Component\nexport { AparteElicitation } from './components/elicitation/aparte-elicitation.js';\n\n// Auto-register components when module is imported\n// Components register themselves in their files\nimport './components/chat/aparte-chat.js';\nimport './components/bubble/aparte-chat-bubble.js';\nimport './components/status/aparte-chat-status.js';\nimport './components/viewport/aparte-chat-viewport.js';\nimport './components/elicitation/aparte-elicitation.js';\n// Import primitives to auto-register\nimport './primitives/select/aparte-select.js';\nimport './primitives/select/aparte-option.js';\nimport './primitives/select/aparte-optgroup.js';\n\n/**\n * Utility to ensure all components are registered\n * Call this if using dynamic imports\n */\nexport function registerAllComponents(): void {\n // Components self-register, but this ensures imports are not tree-shaken\n const _chat = customElements.get('aparte-chat');\n const _viewport = customElements.get('aparte-chat-viewport');\n const _bubble = customElements.get('aparte-chat-bubble');\n const _status = customElements.get('aparte-chat-status');\n\n if (!_chat || !_viewport || !_bubble || !_status) {\n console.warn('[Aparte] Some components may not be registered. Ensure all component files are imported.');\n }\n}\n"],"names":["n","e","o","panel","a","l","b","c","m","i","f","h"],"mappings":"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"}
|