@syntrologie/adapt-chatbot 2.28.0 → 2.29.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/AdaptiveChatBar.composer.test.d.ts +2 -0
- package/dist/AdaptiveChatBar.composer.test.d.ts.map +1 -0
- package/dist/AdaptiveChatBar.d.ts +140 -4
- package/dist/AdaptiveChatBar.d.ts.map +1 -1
- package/dist/AdaptiveChatBar.js +4 -3
- package/dist/AdaptiveChatBarMountable.d.ts +47 -0
- package/dist/AdaptiveChatBarMountable.d.ts.map +1 -1
- package/dist/AdaptiveChatTrail.anchor-scroll.test.d.ts +2 -0
- package/dist/AdaptiveChatTrail.anchor-scroll.test.d.ts.map +1 -0
- package/dist/AdaptiveChatTrail.d.ts +397 -5
- package/dist/AdaptiveChatTrail.d.ts.map +1 -1
- package/dist/AdaptiveChatTrail.js +6 -4
- package/dist/AdaptiveChatTrail.test.d.ts +2 -0
- package/dist/AdaptiveChatTrail.test.d.ts.map +1 -0
- package/dist/AdaptiveChipsStrip.d.ts +17 -11
- package/dist/AdaptiveChipsStrip.d.ts.map +1 -1
- package/dist/AdaptiveChipsStrip.js +2 -2
- package/dist/ChatAssistantLit.d.ts.map +1 -1
- package/dist/ChatAssistantLit.js +4 -3
- package/dist/ChatSession.d.ts +66 -5
- package/dist/ChatSession.d.ts.map +1 -1
- package/dist/ChatTransport.d.ts +107 -0
- package/dist/ChatTransport.d.ts.map +1 -1
- package/dist/InlineRegistryWidgetMount.test.d.ts +2 -0
- package/dist/InlineRegistryWidgetMount.test.d.ts.map +1 -0
- package/dist/InlineWidgetLiveMount.test.d.ts +2 -0
- package/dist/InlineWidgetLiveMount.test.d.ts.map +1 -0
- package/dist/NavLinkMountable.d.ts.map +1 -1
- package/dist/TextAnswerMountable.test.d.ts +2 -0
- package/dist/TextAnswerMountable.test.d.ts.map +1 -0
- package/dist/Turnstile.d.ts.map +1 -1
- package/dist/chunk-A7RBZLIX.js +1678 -0
- package/dist/chunk-A7RBZLIX.js.map +7 -0
- package/dist/{chunk-435KJD27.js → chunk-EACGDSJI.js} +46 -1
- package/dist/chunk-EACGDSJI.js.map +7 -0
- package/dist/chunk-EWPPVPJ4.js +14 -0
- package/dist/chunk-EWPPVPJ4.js.map +7 -0
- package/dist/chunk-FXHYE6FY.js +632 -0
- package/dist/chunk-FXHYE6FY.js.map +7 -0
- package/dist/{chunk-AUER7ZCK.js → chunk-OIGVZGSX.js} +11 -4
- package/dist/chunk-OIGVZGSX.js.map +7 -0
- package/dist/{chunk-UC4XU6GH.js → chunk-VZIUXXAM.js} +761 -52
- package/dist/chunk-VZIUXXAM.js.map +7 -0
- package/dist/{chunk-KUO67E2W.js → chunk-ZXV4GXMO.js} +715 -227
- package/dist/chunk-ZXV4GXMO.js.map +7 -0
- package/dist/elements/ActionHandler.d.ts +1 -1
- package/dist/elements/ActionHandler.d.ts.map +1 -1
- package/dist/elements/ElementInstanceStore.d.ts +62 -0
- package/dist/elements/ElementInstanceStore.d.ts.map +1 -1
- package/dist/elements/TileHandler.d.ts.map +1 -1
- package/dist/elements/TileHandler.test.d.ts +2 -0
- package/dist/elements/TileHandler.test.d.ts.map +1 -0
- package/dist/elements/__tests__/ElementInstanceStore.recall.test.d.ts +2 -0
- package/dist/elements/__tests__/ElementInstanceStore.recall.test.d.ts.map +1 -0
- package/dist/elements/fetcher.d.ts +3 -3
- package/dist/elements/fetcher.d.ts.map +1 -1
- package/dist/elements/index.d.ts +1 -0
- package/dist/elements/index.d.ts.map +1 -1
- package/dist/elements/store-singleton.d.ts +4 -0
- package/dist/elements/store-singleton.d.ts.map +1 -0
- package/dist/elements/types.d.ts +4 -0
- package/dist/elements/types.d.ts.map +1 -1
- package/dist/observer/__tests__/bus-translate.test.d.ts +16 -0
- package/dist/observer/__tests__/bus-translate.test.d.ts.map +1 -0
- package/dist/observer/__tests__/lifecycle.test.d.ts +2 -0
- package/dist/observer/__tests__/lifecycle.test.d.ts.map +1 -0
- package/dist/observer/__tests__/observer-enrich.test.d.ts +10 -0
- package/dist/observer/__tests__/observer-enrich.test.d.ts.map +1 -0
- package/dist/observer/allowlist.d.ts +5 -7
- package/dist/observer/allowlist.d.ts.map +1 -1
- package/dist/observer/bus-translate.d.ts +33 -0
- package/dist/observer/bus-translate.d.ts.map +1 -0
- package/dist/observer/index.d.ts +10 -1
- package/dist/observer/index.d.ts.map +1 -1
- package/dist/observer/queue.d.ts +6 -0
- package/dist/observer/queue.d.ts.map +1 -1
- package/dist/observer/transport.d.ts +1 -0
- package/dist/observer/transport.d.ts.map +1 -1
- package/dist/personas.d.ts +30 -0
- package/dist/personas.d.ts.map +1 -0
- package/dist/runtime.d.ts +2 -0
- package/dist/runtime.d.ts.map +1 -1
- package/dist/runtime.js +856 -129
- package/dist/runtime.js.map +4 -4
- package/dist/schema.d.ts +363 -67
- package/dist/schema.d.ts.map +1 -1
- package/dist/schema.js +176 -3
- package/dist/schema.js.map +2 -2
- package/dist/test/setup.d.ts +1 -0
- package/dist/test/setup.d.ts.map +1 -0
- package/dist/types.d.ts +16 -0
- package/dist/types.d.ts.map +1 -1
- package/package.json +5 -1
- package/dist/chunk-435KJD27.js.map +0 -7
- package/dist/chunk-AUER7ZCK.js.map +0 -7
- package/dist/chunk-DOMEUJR7.js +0 -382
- package/dist/chunk-DOMEUJR7.js.map +0 -7
- package/dist/chunk-KUO67E2W.js.map +0 -7
- package/dist/chunk-QELVKBQV.js +0 -214
- package/dist/chunk-QELVKBQV.js.map +0 -7
- package/dist/chunk-UC4XU6GH.js.map +0 -7
|
@@ -0,0 +1,7 @@
|
|
|
1
|
+
{
|
|
2
|
+
"version": 3,
|
|
3
|
+
"sources": ["../src/AdaptiveChatBar.ts", "../src/personas.ts"],
|
|
4
|
+
"sourcesContent": ["/**\n * AdaptiveChatBar \u2014 the canvas lid composition for the chat-canvas\n * experience. Renders the bubble-up trail on top and an always-visible\n * input row below.\n *\n * Wiring contract (events out):\n * - `chat-message-sent` ({ text }): the user submitted text via Enter\n * or the send button. The owning code is responsible for pushing\n * this into the conversation history and producing a reply.\n *\n * Wiring contract (props in):\n * - `messages`: the conversation trail, passed straight through to\n * `<adaptive-chat-trail>`.\n * - `placeholder`: input placeholder copy. Defaults to a generic\n * \"Ask, find, or navigate\u2026\" \u2014 the host (typically the slot's lid\n * widget mount) can override to a context-specific string.\n *\n * Light DOM. Glassmorphism is applied at the input-row level so the\n * trail above floats over the host page without chrome. See PRD \u00A74.4.\n */\n\nimport { createDictation, type DictationController, isDictationSupported } from '@syntrologie/chat';\nimport { html, LitElement, nothing, svg } from 'lit';\nimport { styleMap } from 'lit/directives/style-map.js';\nimport { type ChatPersona, pickPersona } from './personas.js';\n\nimport './AdaptiveChatTrail.js';\nimport type {\n InlineTrailWidget,\n InlineWidgetMounter,\n TileReceipt,\n TrailMessage,\n} from './AdaptiveChatTrail.js';\nimport { getElementInstanceStore } from './elements/store-singleton.js';\n\nconst DEFAULT_PLACEHOLDER = 'Ask, find, or navigate\u2026';\nconst DEFAULT_ASSISTANT_NAME = 'Assistant';\n\nexport class AdaptiveChatBar extends LitElement {\n static override properties = {\n personas: { attribute: false },\n _persona: { state: true },\n messages: { attribute: false },\n placeholder: { type: String },\n assistantName: { type: String },\n greeting: { type: String },\n inFlight: { type: Boolean, reflect: true },\n thinkingText: { attribute: false },\n introSuggestion: { attribute: false },\n forceExpanded: { type: Boolean, reflect: true },\n maximized: { type: Boolean },\n tileReceipts: { attribute: false },\n inlineWidgets: { attribute: false },\n mountInlineWidget: { attribute: false },\n voiceInput: { type: Boolean },\n _input: { state: true },\n _composerFocused: { state: true },\n _micListening: { state: true },\n _micDisabled: { state: true },\n };\n\n messages: TrailMessage[] = [];\n maximized = false;\n tileReceipts: TileReceipt[] = [];\n /** Widgets rendered inline in the trail (reco carousel), sourced from\n * the store's `chat-inline` slot mounts. Forwarded to the trail. */\n inlineWidgets: InlineTrailWidget[] = [];\n /** Registry-backed mounter for inline widgets whose id is not their\n * custom-element tag (product card, comparison, FAQ). Set by the\n * mountable from `runtime.widgets`; forwarded to the trail. */\n mountInlineWidget: InlineWidgetMounter | undefined = undefined;\n\n /**\n * Live reasoning narration from the model \u2014 streamed in via\n * AG-UI THINKING_TEXT_MESSAGE_CONTENT events and forwarded by\n * the ChatSession subscription on the host (mountable).\n * Forwarded verbatim to the trail, which renders it in place of\n * the silent loading dots between turns. Empty string when no\n * thinking turn is active.\n */\n thinkingText = '';\n /**\n * Pre-conversation suggestion button \u2014 forwarded to the trail's\n * empty-state pane. When the visitor clicks it the trail emits\n * `trail-intro-suggestion`; we catch that here and submit the\n * configured prompt through the normal send path.\n */\n introSuggestion: { label: string; prompt: string } | undefined = undefined;\n\n /** Pass-through to {@link AdaptiveChatTrail}'s ``forceExpanded`` prop.\n * Hosts that mount the chat-bar in a full-screen surface (mobile\n * panel, agent app, etc.) set this to skip the collapse affordance\n * \u2014 there is no smaller state to fall back to. */\n forceExpanded = false;\n placeholder = DEFAULT_PLACEHOLDER;\n /**\n * Name shown in the (forceExpanded) header. Defaults to a generic\n * \"Assistant\". Hosts can override per-workspace (e.g. Vela sets\n * \"Vela Concierge\") without inventing new SDK surface \u2014 it threads\n * through the same mount config the placeholder does.\n */\n assistantName = DEFAULT_ASSISTANT_NAME;\n /** Persona roster from config (FEAT-1784917430); one is sticky-assigned. */\n personas: ChatPersona[] | null = null;\n /** @internal \u2014 the visitor's sticky persona, resolved from the roster. */\n _persona: ChatPersona | null = null;\n\n /**\n * Initial assistant message shown before any real conversation\n * starts. Renders inside the trail as a phantom assistant chip\n * when messages.length === 0; auto-disappears as soon as the\n * first user message lands. Mirrors ChatAssistantLit's greeting.\n */\n greeting: string | undefined = undefined;\n /**\n * Whether a chat round-trip is in flight (request sent, awaiting\n * reply). The single send/stop button morphs accordingly: \u2191 when\n * ready, \u23F9 when in-flight. Parent owns this state \u2014 set true after\n * `chat-message-sent` fires, false when the reply lands or the\n * request is aborted. Enter is inert while in-flight.\n */\n inFlight = false;\n /** Show a dictation mic when the Web Speech API is available. Config-gated, default off. */\n voiceInput = false;\n _input = '';\n _micListening = false;\n _micDisabled = false;\n private _micBase = '';\n private _micNetworkErrors = 0;\n private _dictation: DictationController | null = null;\n /** True while focus is inside the composer row \u2014 drives the accent\n * focus ring so the active text-entry surface is unmistakable on any\n * theme (the idle pill is deliberately subtle). */\n _composerFocused = false;\n\n override createRenderRoot(): HTMLElement {\n return this;\n }\n\n override connectedCallback(): void {\n super.connectedCallback();\n // Listen on the host element so that `tile-receipt-activate` events\n // dispatched directly on this element (as well as bubbling up from the\n // trail child) are handled in one place.\n this.addEventListener('tile-receipt-activate', this._onTileReceiptActivate);\n this.addEventListener('alert-receipt-activate', this._onAlertReceiptActivate);\n }\n\n override disconnectedCallback(): void {\n super.disconnectedCallback();\n this.removeEventListener('tile-receipt-activate', this._onTileReceiptActivate);\n this.removeEventListener('alert-receipt-activate', this._onAlertReceiptActivate);\n }\n\n // Host-level styling (display, width, height, flex, etc.) is owned\n // by the container \u2014 SDK shadow root provides default rules, panel\n // overrides via design tokens (--sc-chat-bar-host-*). This adaptive\n // never sets inline styles on itself. See SmartCanvasElementLit's\n // static styles for the rule.\n\n private _onInput = (e: Event): void => {\n // Typing wins: the user taking over the input ends dictation so a\n // late transcript can't clobber their edit.\n if (this._micListening) this._dictation?.stop();\n this._input = (e.target as HTMLInputElement).value;\n };\n\n private _onMicClick = (): void => {\n if (this._micListening) {\n this._dictation?.stop();\n return;\n }\n this._micBase = this._input;\n this._dictation = createDictation({\n onTranscript: (text) => {\n this._micNetworkErrors = 0;\n this._input = this._micBase + (this._micBase ? ' ' : '') + text;\n },\n onEnd: () => {\n this._micListening = false;\n },\n onError: (code) => {\n this._micListening = false;\n if (code === 'not-allowed') this._micDisabled = true;\n if (code === 'network' && ++this._micNetworkErrors >= 2) this._micDisabled = true;\n },\n });\n this._dictation.start();\n // Mirror the controller: if start() bailed (support vanished, engine\n // threw), don't paint a listening state that can never end.\n this._micListening = this._dictation.listening;\n };\n\n private _onKeyDown = (e: KeyboardEvent): void => {\n if (e.key === 'Enter' && !e.shiftKey) {\n e.preventDefault();\n // Enter is the send affordance \u2014 while in-flight there's nothing\n // to send, so it's a no-op. Interrupt requires the explicit\n // \u23F9 click to avoid surprise-aborting on a stray keystroke.\n if (this.inFlight) return;\n this._send();\n }\n };\n\n // Single button. Click delegates to send-or-interrupt based on\n // current state. Same DOM node, different behavior \u2014 discoverability\n // wins from the user not having to scan for which control is active.\n private _onSendOrInterrupt = (): void => {\n if (this.inFlight) {\n // Stop means stop: discard any chip tap queued during this run \u2014\n // otherwise the interrupt flips inFlight false and the queue flush\n // would fire a NEW turn the instant the user pressed stop.\n this._queuedSuggestedReply = null;\n this.dispatchEvent(new CustomEvent('chat-interrupt', { bubbles: true, composed: true }));\n return;\n }\n this._send();\n };\n\n private _onTileReceiptActivate = (e: Event): void => {\n const { instanceId } = (e as CustomEvent<{ instanceId: string }>).detail;\n getElementInstanceStore()?.recreate(instanceId);\n this.dispatchEvent(\n new CustomEvent('tile-recall', { detail: { instanceId }, bubbles: true, composed: true })\n );\n };\n\n private _onAlertReceiptActivate = (e: Event): void => {\n const { instanceId } = (e as CustomEvent<{ instanceId: string }>).detail;\n this.dispatchEvent(\n new CustomEvent('alert-recall', { detail: { instanceId }, bubbles: true, composed: true })\n );\n };\n\n private _onComposerFocusIn = (): void => {\n this._composerFocused = true;\n };\n\n private _onComposerFocusOut = (): void => {\n this._composerFocused = false;\n };\n\n private _onMaximizeToggle = (): void => {\n this.dispatchEvent(new CustomEvent('chat-maximize-toggle', { bubbles: true, composed: true }));\n };\n\n private _send(): void {\n // Sending supersedes dictation \u2014 stop first so a late final transcript\n // can't resurrect the just-sent text into the emptied input.\n if (this._micListening) this._dictation?.stop();\n const text = this._input.trim();\n if (!text) return;\n // A typed message is the user's NEWEST intent \u2014 it supersedes any chip\n // tap still queued from the run tail (defense: Enter is currently inert\n // while inFlight, but this guard must not depend on that staying true).\n this._queuedSuggestedReply = null;\n this.dispatchEvent(\n new CustomEvent<{ text: string }>('chat-message-sent', {\n detail: { text },\n bubbles: true,\n composed: true,\n })\n );\n this._input = '';\n // Drop the input value too \u2014 the input's bound value is `this._input`\n // via the render, but jsdom's two-way binding via property only takes\n // effect after the next render, so set it imperatively for the test\n // and for browser symmetry (most browsers do the right thing here\n // anyway because Lit re-renders on the state change).\n const input = this.querySelector<HTMLInputElement>('input[data-chat-input]');\n if (input) input.value = '';\n }\n\n /**\n * Visitor tapped the intro suggestion button in the empty-state\n * trail. Submit the configured prompt through the same channel as\n * a typed message so listeners (mountable \u2192 chatSession.send) see\n * a uniform shape \u2014 no need for a parallel \"suggestion-sent\" path.\n * The trail's intro pane auto-disappears the moment the first\n * message lands, so this also closes the empty state in one go.\n */\n private _onIntroSuggestion = (e: Event): void => {\n const detail = (e as CustomEvent<{ prompt: string }>).detail;\n if (!detail?.prompt) return;\n e.stopPropagation();\n if (this.inFlight) return;\n // Latch in-flight optimistically. `inFlight` is owned by the parent\n // mountable and only pushed back down after it handles\n // `chat-message-sent` + a Lit render cycle. Two taps in the same frame\n // both see inFlight===false otherwise, double-dispatching one intended\n // reply (C3). Set it true synchronously here; the parent confirms/owns\n // it from the next render and clears it when the reply lands.\n this.inFlight = true;\n this.dispatchEvent(\n new CustomEvent<{ text: string }>('chat-message-sent', {\n detail: { text: detail.prompt },\n bubbles: true,\n composed: true,\n })\n );\n };\n\n /**\n * Reply-chip tap that arrived during the run TAIL. Chips render the\n * moment the reply text lands, but `inFlight` (which includes\n * `runActive` \u2014 typing events, tool tail, RUN_FINISHED) can lag for\n * seconds. The old `if (this.inFlight) return;` guard silently ATE\n * those taps \u2014 the visitor's chosen reply never appeared as their\n * message (live repro, deployed vela 2026-07-08). Now the tap queues\n * (latest wins) and dispatches when `inFlight` clears.\n */\n private _queuedSuggestedReply: string | null = null;\n\n protected override willUpdate(changed: Map<string, unknown>): void {\n super.willUpdate?.(changed);\n if (changed.has('personas')) {\n this._persona = pickPersona(this.personas);\n }\n if (\n changed.has('inFlight') &&\n changed.get('inFlight') === true &&\n !this.inFlight &&\n this._queuedSuggestedReply\n ) {\n const text = this._queuedSuggestedReply;\n this._queuedSuggestedReply = null;\n // Same latch + channel as a direct tap.\n this.inFlight = true;\n this.dispatchEvent(\n new CustomEvent<{ text: string }>('chat-message-sent', {\n detail: { text },\n bubbles: true,\n composed: true,\n })\n );\n }\n }\n\n /**\n * Visitor tapped an inline `suggest_replies` chip in the trail. Submit\n * the chip text through the SAME `chat-message-sent` channel a typed\n * message uses, so the reply rides the existing send path (mountable \u2192\n * chatSession.send \u2192 transport) \u2014 no fabricated AG-UI events. The\n * trail clears the chips on its own once the reply lands and a newer\n * assistant turn becomes the latest.\n *\n * A tap while the previous run is still closing is QUEUED, never\n * dropped \u2014 see `_queuedSuggestedReply`.\n */\n private _onSuggestedReply = (e: Event): void => {\n const detail = (e as CustomEvent<{ text: string }>).detail;\n if (!detail?.text) return;\n e.stopPropagation();\n if (this.inFlight) {\n this._queuedSuggestedReply = detail.text;\n return;\n }\n // Latch in-flight optimistically \u2014 same race as `_onIntroSuggestion`\n // (C3). The parent owns `inFlight` and only re-asserts it after a render\n // cycle, so a same-frame double tap would otherwise fire two\n // `chat-message-sent` events for one chip.\n this.inFlight = true;\n this.dispatchEvent(\n new CustomEvent<{ text: string }>('chat-message-sent', {\n detail: { text: detail.text },\n bubbles: true,\n composed: true,\n })\n );\n };\n\n override render() {\n return html`\n <div style=${styleMap(rootStyles(this.forceExpanded))}>\n ${this.forceExpanded ? renderHeader(this.assistantName, this._persona) : nothing}\n <adaptive-chat-trail\n .messages=${this.messages}\n .greeting=${this._persona?.intro_line ?? this.greeting}\n .forceExpanded=${this.forceExpanded}\n .inFlight=${this.inFlight}\n .thinkingText=${this.thinkingText}\n .personaName=${this._persona?.name ?? ''}\n .personaAvatarSm=${this._persona?.avatar?.sm ?? ''}\n .introSuggestion=${this.introSuggestion}\n .tileReceipts=${this.tileReceipts}\n .inlineWidgets=${this.inlineWidgets}\n .mountInlineWidget=${this.mountInlineWidget}\n @trail-intro-suggestion=${this._onIntroSuggestion}\n @trail-suggested-reply=${this._onSuggestedReply}\n ></adaptive-chat-trail>\n <div\n style=${styleMap(rowStyles(this.forceExpanded, this._composerFocused))}\n data-chat-row\n @focusin=${this._onComposerFocusIn}\n @focusout=${this._onComposerFocusOut}\n >\n <button\n type=\"button\"\n data-chat-maximize\n @click=${this._onMaximizeToggle}\n aria-label=${this.maximized ? 'Exit full screen' : 'Maximize chat'}\n title=${this.maximized ? 'Exit full screen' : 'Maximize'}\n aria-pressed=${this.maximized ? 'true' : 'false'}\n style=${styleMap(maximizeStyles(this.maximized))}\n >${this.maximized ? MINIMIZE_ICON : MAXIMIZE_ICON}</button>\n <input\n data-chat-input\n type=\"text\"\n placeholder=${this._micListening ? 'Listening \u2014 tap the mic to stop' : this.placeholder}\n .value=${this._input}\n @input=${this._onInput}\n @keydown=${this._onKeyDown}\n style=${styleMap(inputStyles())}\n aria-label=\"Chat input\"\n />\n ${\n this.voiceInput && isDictationSupported()\n ? html`${MIC_RING_STYLES}<button\n type=\"button\"\n data-chat-mic\n data-listening=${this._micListening ? 'true' : 'false'}\n ?disabled=${this._micDisabled}\n @click=${this._onMicClick}\n aria-pressed=${this._micListening ? 'true' : 'false'}\n aria-label=${this._micListening ? 'Stop dictation' : 'Start dictation'}\n title=${this._micDisabled ? 'Microphone blocked' : this._micListening ? 'Stop dictation' : 'Dictate'}\n style=${styleMap(micStyles(this._micListening, this._micDisabled))}\n >${MIC_ICON}</button>`\n : nothing\n }\n <button\n type=\"button\"\n data-chat-send\n data-state=${this.inFlight ? 'in-flight' : 'ready'}\n @click=${this._onSendOrInterrupt}\n aria-label=${this.inFlight ? 'Stop' : 'Send message'}\n title=${this.inFlight ? 'Interrupt' : 'Send'}\n style=${styleMap(sendStyles(this.inFlight))}\n >${this.inFlight ? '\u25A0' : '\u2191'}</button>\n </div>\n </div>\n `;\n }\n}\n\n// ---------------------------------------------------------------------------\n// Styles \u2014 kept inline (Lit styleMap) so they participate in light-DOM\n// rendering and pick up host CSS variables (e.g. --sc-tile-background).\n// ---------------------------------------------------------------------------\n\nfunction rootStyles(forceExpanded: boolean): Record<string, string> {\n // When the host expects the chat to fill its container (full-screen\n // panel, agent app), we grow vertically AND wrap the whole widget in\n // its own chrome card \u2014 trail + input read as one cohesive surface\n // instead of a naked trail above a chrome'd input. Floating mounts\n // (bottom-right pinned, etc.) stay chrome-less here because their\n // chrome is owned by the host's positioned wrapper.\n if (!forceExpanded) {\n return {\n display: 'flex',\n flexDirection: 'column',\n gap: '6px',\n width: '100%',\n pointerEvents: 'auto',\n };\n }\n // Input is ABSOLUTELY positioned at the bottom of this chrome card\n // (see rowStyles forceExpanded mode). That guarantees the input is\n // always visible \u2014 even when the lid region is tighter than the\n // chat-bar would naturally want. The flex column above holds\n // header + trail; padding-bottom reserves the input's footprint so\n // trail content can never overlap.\n //\n // Priority of \"what disappears when space is tight\":\n // Trail (shrinks to 0 first via flex: 1 1 0)\n // Header (can shrink via default flex: 0 1 auto)\n // Input (NEVER \u2014 it's positioned absolute, always at the bottom)\n return {\n position: 'relative',\n display: 'flex',\n flexDirection: 'column',\n gap: '8px',\n width: '100%',\n height: '100%',\n boxSizing: 'border-box',\n flex: '1 1 auto',\n minHeight: '0',\n overflow: 'hidden',\n pointerEvents: 'auto',\n background: 'var(--sc-tile-background, rgba(255, 255, 255, 0.92))',\n border: 'var(--sc-tile-border, 1px solid rgba(0, 0, 0, 0.06))',\n borderRadius: 'var(--sc-tile-border-radius, 14px)',\n boxShadow: 'var(--sc-tile-shadow, 0 12px 32px -16px rgba(0, 0, 0, 0.18))',\n // Reserves room for the absolute-positioned input pill (36px high\n // + 12px from bottom) plus a 16px visual gap above the input.\n padding: '0.75rem 0.75rem calc(36px + 1.75rem)',\n color: 'var(--sc-tile-title-color, inherit)',\n fontFamily: 'var(--sc-font-family, inherit)',\n // Override the trail's host-layout tokens so the trail (a flex item\n // of this column) fills a definite-height parent AND contributes its\n // content height in an indefinite one. basis AUTO (not 0) is\n // load-bearing: grow:1 still fills a full-screen panel, but basis auto\n // also lets the trail's content height propagate up the fill chain so a\n // SHRINK-WRAP host (velvet's bottom sheet) hugs the content with no void.\n // A basis-0 layer anywhere in the chain reports 0 min-content and\n // collapses the sheet to header+input. shrink:1 + min-height:0 still lets\n // the trail yield first when space is tight (input is absolute-pinned).\n // The SDK-level rule in SmartCanvasElementLit consumes these tokens on\n // adaptive-chat-trail's host element. Containers OWN host styling\n // via tokens; the adaptive never sets inline styles on its host.\n ['--sc-chat-trail-host-display']: 'flex',\n ['--sc-chat-trail-host-flex-direction']: 'column',\n ['--sc-chat-trail-host-flex']: '1 1 auto',\n ['--sc-chat-trail-host-min-height']: '0',\n ['--sc-chat-trail-host-overflow']: 'hidden',\n };\n}\n\n// Focus ring shared by both composer variants: while focus is inside the\n// row, the border switches to the accent so the active text-entry surface\n// is unmistakable regardless of theme.\nconst COMPOSER_FOCUS_BORDER = '1px solid hsl(var(--sc-accent-color) / 0.6)';\n\nfunction rowStyles(forceExpanded: boolean, focused: boolean): Record<string, string> {\n // forceExpanded \u2014 root container already carries the chrome; row\n // becomes a flat input-pill inside that chrome (subtle border + soft\n // background, no shadow/blur).\n if (forceExpanded) {\n // Absolute-pinned to the chrome card's bottom edge so it never\n // disappears under any container size. The chrome reserves\n // padding-bottom equal to this row's footprint so flex content\n // above (header + trail) can't overlap.\n //\n // The pill's tint derives from currentColor (the theme's text color),\n // NOT a hardcoded black alpha: rgba(0,0,0,.04) over a near-black card\n // is invisible \u2014 on dark themes visitors couldn't find the text entry\n // at all. color-mix keeps one declaration correct on every theme, and\n // the --sc-chat-composer-* tokens let a workspace override the tint.\n return {\n position: 'absolute',\n left: '0.75rem',\n right: '0.75rem',\n bottom: '0.75rem',\n display: 'flex',\n alignItems: 'center',\n gap: '8px',\n padding: '6px 14px',\n borderRadius: '9999px',\n background:\n 'var(--sc-chat-composer-background, color-mix(in srgb, currentColor 8%, transparent))',\n border: focused\n ? COMPOSER_FOCUS_BORDER\n : '1px solid var(--sc-chat-composer-border, color-mix(in srgb, currentColor 22%, transparent))',\n color: 'var(--sc-content-text-color, inherit)',\n fontFamily: 'var(--sc-font-family, inherit)',\n minHeight: '36px',\n };\n }\n // Floating mount \u2014 keeps the original tile-chrome look.\n return {\n display: 'flex',\n alignItems: 'center',\n gap: '8px',\n padding: '10px 12px',\n borderRadius: 'var(--sc-tile-border-radius, 14px)',\n background: 'var(--sc-tile-background, rgba(15, 19, 24, 0.6))',\n backdropFilter: 'var(--sc-chat-bar-blur, blur(24px) saturate(140%))',\n WebkitBackdropFilter: 'var(--sc-chat-bar-blur, blur(24px) saturate(140%))',\n border: focused\n ? COMPOSER_FOCUS_BORDER\n : 'var(--sc-tile-border, 1px solid rgba(255, 255, 255, 0.08))',\n boxShadow: 'var(--sc-tile-shadow, 0 2px 12px rgba(0, 0, 0, 0.3))',\n color: 'var(--sc-tile-title-color, #fafafa)',\n fontFamily: 'var(--sc-font-family, inherit)',\n };\n}\n\n// Maximize / restore toggle in the chat bar. Two hard-won legibility rules\n// live here:\n// 1. The glyph is an inline SVG, never a Unicode arrow (`\u2922`/`\u2921`): glyph\n// metrics vary per platform font, so the character rendered small and\n// visibly off-center inside the circular chip.\n// 2. The chip mirrors the send button's filled-accent language but at\n// 32px, so the expand/collapse control reads as a control \u2014 the ACTIVE\n// (maximized) state is a filled chip, idle is a ringed chip.\n// Expand: arrows pointing out to opposite corners (Lucide maximize-2).\nconst MIC_ICON = svg`<svg viewBox=\"0 0 16 16\" width=\"16\" height=\"16\" fill=\"none\" aria-hidden=\"true\"><rect x=\"6\" y=\"1.5\" width=\"4\" height=\"8\" rx=\"2\" stroke=\"currentColor\" stroke-width=\"1.6\"></rect><path d=\"M3.5 7.5a4.5 4.5 0 0 0 9 0M8 12v2.5\" stroke=\"currentColor\" stroke-width=\"1.6\" stroke-linecap=\"round\"></path></svg>`;\n\nfunction micStyles(listening: boolean, disabled: boolean): Record<string, string> {\n return {\n display: 'inline-flex',\n 'align-items': 'center',\n 'justify-content': 'center',\n width: '32px',\n height: '32px',\n border: 'none',\n 'border-radius': '50%',\n // Listening is a MODE: the mic flips to a filled primary chip with a\n // ripple ring (MIC_RING_STYLES) so recording is unmissable, and the\n // input placeholder says how to end it.\n background: listening ? 'var(--sc-color-primary, #6a59ce)' : 'transparent',\n color: listening ? 'var(--sc-color-primary-text, #ffffff)' : 'currentColor',\n opacity: disabled ? '0.3' : listening ? '1' : '0.65',\n cursor: disabled ? 'not-allowed' : 'pointer',\n transition: 'color 150ms ease, background 150ms ease, opacity 150ms ease',\n 'flex-shrink': '0',\n };\n}\n\n// Ripple keyframes can't ride styleMap (light DOM, no stylesheet of our\n// own) \u2014 rendered once next to the mic button. Scoped to [data-chat-mic]\n// inside the canvas shadow root, so nothing leaks to the host page.\nconst MIC_RING_STYLES = html`<style>\n [data-chat-mic][data-listening='true'] {\n animation: sc-chatbar-mic-ring 1.5s ease-out infinite;\n }\n @keyframes sc-chatbar-mic-ring {\n 0% {\n box-shadow: 0 0 0 0 color-mix(in srgb, var(--sc-color-primary, #6a59ce) 45%, transparent);\n transform: scale(1);\n }\n 50% { transform: scale(1.08); }\n 70% { box-shadow: 0 0 0 12px transparent; }\n 100% {\n box-shadow: 0 0 0 0 transparent;\n transform: scale(1);\n }\n }\n @media (prefers-reduced-motion: reduce) {\n [data-chat-mic][data-listening='true'] {\n animation: none;\n box-shadow: 0 0 0 3px color-mix(in srgb, var(--sc-color-primary, #6a59ce) 35%, transparent);\n }\n }\n</style>`;\n\nconst MAXIMIZE_ICON = svg`<svg viewBox=\"0 0 24 24\" width=\"16\" height=\"16\" fill=\"none\" stroke=\"currentColor\" stroke-width=\"2.25\" stroke-linecap=\"round\" stroke-linejoin=\"round\" aria-hidden=\"true\"><polyline points=\"15 3 21 3 21 9\"></polyline><polyline points=\"9 21 3 21 3 15\"></polyline><line x1=\"21\" y1=\"3\" x2=\"14\" y2=\"10\"></line><line x1=\"3\" y1=\"21\" x2=\"10\" y2=\"14\"></line></svg>`;\n\n// Collapse: arrows pointing in toward the center (Lucide minimize-2).\nconst MINIMIZE_ICON = svg`<svg viewBox=\"0 0 24 24\" width=\"16\" height=\"16\" fill=\"none\" stroke=\"currentColor\" stroke-width=\"2.25\" stroke-linecap=\"round\" stroke-linejoin=\"round\" aria-hidden=\"true\"><polyline points=\"4 14 10 14 10 20\"></polyline><polyline points=\"20 10 14 10 14 4\"></polyline><line x1=\"14\" y1=\"10\" x2=\"21\" y2=\"3\"></line><line x1=\"3\" y1=\"21\" x2=\"10\" y2=\"14\"></line></svg>`;\n\nfunction maximizeStyles(maximized: boolean): Record<string, string> {\n return {\n display: 'inline-flex',\n alignItems: 'center',\n justifyContent: 'center',\n width: '32px',\n height: '32px',\n borderRadius: '9999px',\n // Active (maximized): filled accent chip. Idle: subtle accent chip with a\n // visible ring. Colour is full-opacity in both states (no 0.95 ghosting).\n background: maximized\n ? 'hsl(var(--sc-accent-color) / 0.85)'\n : 'hsl(var(--sc-accent-color) / 0.15)',\n border: maximized ? 'none' : '1px solid hsl(var(--sc-accent-color) / 0.45)',\n color: maximized ? 'var(--sc-accent-foreground, #fff)' : 'hsl(var(--sc-accent-color))',\n flexShrink: '0',\n lineHeight: '1',\n padding: '0',\n cursor: 'pointer',\n transition: 'background 150ms ease, color 150ms ease, border-color 150ms ease',\n };\n}\n\nfunction inputStyles(): Record<string, string> {\n return {\n flex: '1',\n minWidth: '0',\n background: 'transparent',\n border: 'none',\n outline: 'none',\n color: 'inherit',\n // MUST be >= 16px. iOS Safari auto-zooms the page when a focused input has a\n // font-size below 16px, then does NOT zoom back out on blur \u2014 so the composer\n // zoomed in, the input ended up behind the keyboard (the zoom breaks the\n // visualViewport keyboard-lift math), and tapping \"Done\" left the whole site\n // stuck zoomed in. 16px is the standard, accessibility-safe fix (no\n // user-scalable=no / maximum-scale hacks that would kill pinch-zoom).\n fontSize: '16px',\n };\n}\n\nfunction sendStyles(inFlight: boolean): Record<string, string> {\n return {\n width: '28px',\n height: '28px',\n display: 'inline-flex',\n alignItems: 'center',\n justifyContent: 'center',\n borderRadius: '9999px',\n // Ready: filled accent (send is the affordance). In-flight: hollow\n // ring + accent ring (stop is a one-of-a-kind disruptive action,\n // styled differently so the user reads \"this isn't just send\").\n background: inFlight ? 'transparent' : 'hsl(var(--sc-accent-color) / 0.85)',\n color: inFlight ? 'hsl(var(--sc-accent-color) / 0.95)' : 'var(--sc-accent-foreground, #fff)',\n border: inFlight ? '1px solid hsl(var(--sc-accent-color) / 0.55)' : 'none',\n cursor: 'pointer',\n flexShrink: '0',\n transition: 'background 150ms ease, color 150ms ease, border-color 150ms ease',\n };\n}\n\n/**\n * Compact single-line chat header. Prior version stacked the name over a\n * two-line status block inside a flex-column wrapper with a 28px avatar and\n * `padding: 4px 4px 12px`, which wasted a lot of vertical space (user\n * feedback: \"bad use of vertical space\"). This is now ONE inline row \u2014\n * small avatar dot \u00B7 name \u00B7 live-status dot \u00B7 short status \u2014 at roughly half\n * the height. All surfaces share this chrome.\n */\nfunction renderHeader(assistantName: string, persona: ChatPersona | null) {\n const headerStyles: Record<string, string> = {\n display: 'flex',\n alignItems: 'center',\n gap: '7px',\n // Halved vertical footprint: 6px total block padding vs the old 16px\n // (4px top + 12px bottom). Horizontal padding unchanged.\n padding: '3px 4px',\n borderBottom: '1px solid var(--sc-content-divider-color, rgba(0, 0, 0, 0.08))',\n flex: '0 0 auto',\n };\n // Small brand dot \u2014 shrunk from a 28px avatar to a 16px chip so the\n // whole header collapses to a single text line. Still tracks the\n // workspace brand primary so it matches the rest of the canvas chrome.\n const avatar: Record<string, string> = {\n display: 'inline-flex',\n alignItems: 'center',\n justifyContent: 'center',\n width: '16px',\n height: '16px',\n borderRadius: '9999px',\n background:\n 'var(--sc-tile-icon-background, linear-gradient(135deg, var(--sc-color-primary, #5faf7d) 0%, var(--sc-color-primary-hover, #3d8a5e) 100%))',\n color: '#fff',\n flexShrink: '0',\n fontSize: '9px',\n lineHeight: '1',\n };\n const name: Record<string, string> = {\n fontSize: '0.8rem',\n fontWeight: '600',\n color: 'var(--sc-content-text-color, inherit)',\n lineHeight: '1.2',\n flexShrink: '0',\n };\n // No status line or presence dot (\"Online \u00B7 understands your session\") \u2014\n // user feedback: that's chrome a visitor doesn't need. Avatar + name only.\n // Persona mode (FEAT-1784917430): the brand dot becomes the persona's face,\n // the name becomes the persona's name, and an explicit \"AI concierge\"\n // microline rides alongside \u2014 a photoreal face + human name must never\n // imply a human agent (Moffatt/R-001 lineage, CA B.O.T./EU AI Act).\n const personaImg: Record<string, string> = {\n width: '22px',\n height: '22px',\n borderRadius: '9999px',\n objectFit: 'cover',\n flexShrink: '0',\n };\n const disclosure: Record<string, string> = {\n fontSize: '0.62rem',\n fontWeight: '500',\n color: 'var(--sc-content-text-color, inherit)',\n opacity: '0.55',\n lineHeight: '1.2',\n flexShrink: '0',\n };\n return html`\n <div style=${styleMap(headerStyles)} data-chat-header>\n ${\n persona?.avatar?.md || persona?.avatar?.sm\n ? html`<img\n style=${styleMap(personaImg)}\n src=${persona.avatar.md ?? persona.avatar.sm ?? ''}\n alt=\"\"\n data-persona-avatar\n />`\n : html`<span style=${styleMap(avatar)} aria-hidden=\"true\">\u2726</span>`\n }\n <span style=${styleMap(name)} data-persona-name>${persona?.name ?? assistantName}</span>\n ${persona ? html`<span style=${styleMap(disclosure)} data-persona-disclosure>\u00B7 AI concierge</span>` : nothing}\n </div>\n `;\n}\n\nif (!customElements.get('adaptive-chat-bar')) {\n customElements.define('adaptive-chat-bar', AdaptiveChatBar);\n}\n\ndeclare global {\n interface HTMLElementTagNameMap {\n 'adaptive-chat-bar': AdaptiveChatBar;\n }\n}\n", "/**\n * Chat personas \u2014 the \"human face\" of the concierge (FEAT-1784917430).\n *\n * A workspace ships a persona ROSTER in the chat-bar's props (plain config,\n * like assistantName). Assignment is 50:50 sticky-random per visitor: first\n * visit picks uniformly, the pick persists in localStorage, and every later\n * session reuses it \u2014 consistency reads as a real team member, not a slot\n * machine. An invalid/vanished persisted id re-picks (roster changes are\n * config changes; visitors must never be stranded on a ghost).\n *\n * The persona never claims to be human: the header carries an explicit\n * \"AI concierge\" microline (see renderHeader) and the server threads the\n * no-human-claim rule into the prompt (Moffatt/R-001 lineage).\n */\n\nexport interface PersonaAvatar {\n sm?: string;\n md?: string;\n lg?: string;\n}\n\nexport interface ChatPersona {\n id: string;\n name: string;\n role_title?: string;\n pronouns?: string;\n avatar?: PersonaAvatar;\n intro_line?: string;\n}\n\nconst STORAGE_KEY = 'syntro:persona';\n\n/** Pick (or recall) the visitor's sticky persona from the roster. */\nexport function pickPersona(roster: ChatPersona[] | undefined | null): ChatPersona | null {\n if (!Array.isArray(roster) || roster.length === 0) return null;\n let storedId: string | null = null;\n try {\n storedId = localStorage.getItem(STORAGE_KEY);\n } catch {\n // Storage unavailable (private mode) \u2014 session-scoped random pick.\n }\n const stored = storedId ? roster.find((p) => p.id === storedId) : undefined;\n if (stored) return stored;\n const pick = roster[Math.floor(Math.random() * roster.length)]!;\n try {\n localStorage.setItem(STORAGE_KEY, pick.id);\n } catch {\n /* non-persistent pick is fine */\n }\n return pick;\n}\n"],
|
|
5
|
+
"mappings": "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",
|
|
6
|
+
"names": []
|
|
7
|
+
}
|
|
@@ -2,7 +2,7 @@ import {
|
|
|
2
2
|
AuthoringFieldsZ,
|
|
3
3
|
NotifyZ,
|
|
4
4
|
TriggerWhenZ
|
|
5
|
-
} from "./chunk-
|
|
5
|
+
} from "./chunk-EACGDSJI.js";
|
|
6
6
|
|
|
7
7
|
// src/AdaptiveChipsStrip.ts
|
|
8
8
|
import { html, LitElement, nothing } from "lit";
|
|
@@ -173,8 +173,12 @@ var AdaptiveChipsStrip = class extends LitElement {
|
|
|
173
173
|
insertItem(instanceId, item, position) {
|
|
174
174
|
if (!instanceId) return;
|
|
175
175
|
if (this._llmAppendedIds.has(instanceId)) return;
|
|
176
|
-
const
|
|
177
|
-
if (!
|
|
176
|
+
const incoming = item;
|
|
177
|
+
if (!incoming?.config?.id) return;
|
|
178
|
+
const chip = {
|
|
179
|
+
...incoming,
|
|
180
|
+
config: { ...incoming.config, id: instanceId }
|
|
181
|
+
};
|
|
178
182
|
this._llmAppendedIds.add(instanceId);
|
|
179
183
|
this.chips = position === "prepend" ? [chip, ...this.chips] : [...this.chips, chip];
|
|
180
184
|
}
|
|
@@ -278,6 +282,9 @@ var AdaptiveChipsStrip = class extends LitElement {
|
|
|
278
282
|
if (!container) {
|
|
279
283
|
requestAnimationFrame(() => {
|
|
280
284
|
if (this._openId !== chip.config.id) return;
|
|
285
|
+
if (this._payloadMount?.chipId === chip.config.id && this._payloadMount.widgetId === nextWidget) {
|
|
286
|
+
return;
|
|
287
|
+
}
|
|
281
288
|
const retry = this.querySelector("[data-chip-payload-mount]");
|
|
282
289
|
if (!retry) return;
|
|
283
290
|
const handle2 = widgets.mount(nextWidget, retry, nextProps);
|
|
@@ -631,4 +638,4 @@ export {
|
|
|
631
638
|
SuggestionChipSchema,
|
|
632
639
|
AdaptiveChipsStrip
|
|
633
640
|
};
|
|
634
|
-
//# sourceMappingURL=chunk-
|
|
641
|
+
//# sourceMappingURL=chunk-OIGVZGSX.js.map
|
|
@@ -0,0 +1,7 @@
|
|
|
1
|
+
{
|
|
2
|
+
"version": 3,
|
|
3
|
+
"sources": ["../src/AdaptiveChipsStrip.ts"],
|
|
4
|
+
"sourcesContent": ["/**\n * AdaptiveChipsStrip \u2014 the suggested-chips tile kind.\n *\n * A horizontally scrollable strip of chips. Each chip carries a title\n * and a typed payload. Clicking a chip mounts its payload widget in a\n * chromed drawer directly below the strip; clicking again (or the\n * payload's close button) collapses it. Only one chip is open at a\n * time per strip.\n *\n * Payload rendering goes through the runtime widget registry \u2014 the\n * payload is a `{ widget, props? }` reference (same shape as\n * `slots.drawer.lid`). Click \u2192 strip looks the widget id up in\n * `runtime.widgets`, mounts it into the drawer body, unmounts on\n * close. No resolver map, no per-customer JS \u2014 the same registry\n * that mounts tile widgets handles chip payloads.\n *\n * Built-in payload widgets (registered by this adaptive):\n * - `adaptive-chatbot:text-answer` \u2014 single paragraph of text\n *\n * Customers ship their own widgets through the standard adaptive\n * registration path (each adaptive's `runtime.widgets` list). LLM-\n * authored configs reference them by id; the widget owns its props\n * schema. No new vocabulary per chip \u2014 same as every other widget\n * in the SDK.\n *\n * Light DOM. The strip itself is chromeless per the PRD; the payload\n * drawer below is *always* chromed (PRD \u00A76.7) \u2014 the chromed boundary\n * is what visually links the open chip to its content.\n *\n * See PRD \u00A74.5 (the suggested-chips pattern) for the canonical UX.\n */\n\nimport { AuthoringFieldsZ, NotifyZ, TriggerWhenZ } from '@syntrologie/sdk-contracts';\nimport { html, LitElement, nothing, type TemplateResult } from 'lit';\nimport { styleMap } from 'lit/directives/style-map.js';\nimport { z } from 'zod';\n\n/**\n * Structural type for just the runtime surfaces this strip uses.\n * Avoids a hard dependency on @syntrologie/runtime-sdk while staying\n * compatible with the real `SmartCanvasRuntime` shape.\n *\n * `events.subscribe` is optional \u2014 present when running inside the full\n * canvas runtime where the chips strip wants to receive LLM-authored\n * chips via `element.compositional_append`. Absent in standalone test\n * harnesses; the strip falls back to hand-authored chips only.\n */\ninterface ChipsStripRuntime {\n widgets: {\n has: (id: string) => boolean;\n mount: (\n id: string,\n container: HTMLElement,\n props?: Record<string, unknown>\n ) => { unmount: () => void; update?: (props?: Record<string, unknown>) => void };\n };\n events?: {\n /** Used to ping the store with a replay request when the chip strip\n * (re)mounts \u2014 see `_subscribeCompositional`. */\n publish?: (name: string, props?: Record<string, unknown>) => void;\n subscribe?: (\n handler: (event: { name: string; props?: Record<string, unknown> }) => void\n ) => () => void;\n };\n}\n\n// ---------------------------------------------------------------------------\n// Schema \u2014 `suggestions:chip` follows the compositional-action pattern\n// used by `faq:question`. Each chip is a discriminated-union action\n// envelope (`kind`, `config`, optional `triggerWhen` + `notify`) so it\n// inherits the SDK's validation, conditional-gating, authoring-metadata,\n// and LLM-authoring vocabulary for free.\n//\n// The chip's `payload` is a widget reference \u2014 same `{ widget, props }`\n// shape used by `slots.drawer.lid` and tile configs. The strip mounts\n// the widget via the runtime widget registry. LLMs author payloads by\n// picking from the catalog of registered widget ids \u2014 same closed\n// vocabulary they use everywhere else in the SDK. No per-customer JS,\n// no resolver maps.\n// ---------------------------------------------------------------------------\n\nconst ChipPayloadZ = z\n .object({\n widget: z\n .string()\n .min(1)\n .describe(\n \"Widget id from the runtime registry \u2014 same vocabulary as a tile's `widget` field. Click \u2192 strip mounts this widget into the chip drawer. Built-ins shipped by adaptive-chatbot: `adaptive-chatbot:text-answer`. Other adaptives register their own (e.g. `adaptive-faq:question-card`, `adaptive-product:mini`).\"\n ),\n props: z\n .record(z.unknown())\n .optional()\n .describe('Props passed to the mounted widget. The widget owns its own props schema.'),\n })\n .strict()\n .describe(\n \"The content that mounts in the chip's drawer when it opens. Same { widget, props } shape used by slots.lid and tile configs \u2014 chips are tiles by another name.\"\n );\n\n/**\n * Schema for a single suggestion chip (compositional action).\n *\n * Mirrors the `faq:question` pattern: discriminated by `kind`, body in\n * `config`, optional `triggerWhen` for per-chip conditional visibility,\n * optional `notify` for a toast when the chip first becomes relevant,\n * plus the standard `AuthoringFieldsZ` (id/title/description/validation \u2014\n * stripped server-side before serving to the runtime).\n */\nexport const SuggestionChipSchema = z\n .object({\n ...AuthoringFieldsZ,\n kind: z\n .literal('suggestions:chip')\n .describe(\n 'Compositional action type for a single chip in the AdaptiveChipsStrip. Rendered by the strip widget; not executed by the runtime action engine.'\n ),\n config: z\n .object({\n id: z.string().min(1).describe('Stable identity for keyed rendering and event payloads.'),\n title: z\n .string()\n .min(1)\n .describe('Chip label \u2014 single line, ~32ch typical, ellipsis-truncates beyond.'),\n payload: ChipPayloadZ,\n })\n .describe(\n 'Per-chip configuration: identity, label, and the payload that opens in the drawer.'\n ),\n triggerWhen: TriggerWhenZ.describe(\n 'Conditional visibility strategy. When null or omitted, the chip is always shown. Use a rules strategy to show/hide based on page URL, event counts, or session metrics \u2014 same evaluator that powers tile activation.'\n ),\n notify: NotifyZ.describe(\n 'Toast notification shown when triggerWhen transitions false \u2192 true. Required when triggerWhen is set \u2014 pass null to opt out of the toast.'\n ),\n })\n .refine((data) => !data.triggerWhen || data.notify !== undefined, {\n message:\n 'notify is required when triggerWhen is present (use null to opt out of notifications)',\n })\n .describe(\n 'A single suggestion chip in the chips strip. Same authoring shape as faq:question \u2014 discriminator + config body + optional conditional gating + optional proactive notification.'\n );\n\n// ---------------------------------------------------------------------------\n// Types (inferred from schema \u2014 single source of truth)\n// ---------------------------------------------------------------------------\n\n/** A widget-reference payload that mounts in the drawer when its chip is opened. */\nexport type ChipPayload = z.infer<typeof ChipPayloadZ>;\n\n/** Declarative chip data. Inferred from `SuggestionChipSchema`. */\nexport type SuggestionChip = z.infer<typeof SuggestionChipSchema>;\n\n// ---------------------------------------------------------------------------\n// Component\n// ---------------------------------------------------------------------------\n\nexport class AdaptiveChipsStrip extends LitElement {\n static override properties = {\n chips: { attribute: false },\n runtimeRef: { attribute: false },\n chromeless: { type: Boolean, reflect: true },\n _openId: { state: true },\n _canScrollLeft: { state: true },\n _canScrollRight: { state: true },\n };\n\n chips: SuggestionChip[] = [];\n /**\n * Runtime reference \u2014 provides `widgets.has(id)` and\n * `widgets.mount(id, container, props)` so the strip can render\n * chip payloads through the same registry that mounts tile widgets.\n * Null until the host wires it (the AdaptiveChipsStripMountable\n * passes it in from the runtime).\n */\n runtimeRef: ChipsStripRuntime | null = null;\n /**\n * Strip-level chrome toggle \u2014 applies uniformly to all chips +\n * the payload drawer. Resolved upstream from `tile.chromeless`\n * (which itself defaults from `slot.theme.chromeless`). Per-chip\n * inconsistency would break the mini-canvas visual rhythm so\n * there's no per-chip flag \u2014 one strip, one style.\n */\n chromeless = false;\n _openId: string | null = null;\n /**\n * Horizontal-scroll affordance state. The strip is a single row that\n * overflows horizontally when there are more chips than the panel\n * width can hold; the left/right chevron buttons are visible only\n * when the user can actually scroll in that direction. ResizeObserver\n * + scroll listener keep these in sync.\n */\n _canScrollLeft = false;\n _canScrollRight = false;\n private _stripResizeObserver: ResizeObserver | null = null;\n /** Unsubscribe handle for the compositional-append/patch/remove event\n * subscription on `runtime.events`. Null when the strip hasn't yet\n * resolved its tile id (no parent container yet) or the runtime\n * doesn't expose an event bus. */\n private _compositionalUnsub: (() => void) | null = null;\n /** Tile id this strip occupies. Resolved on first `updated()` pass by\n * walking the DOM ancestor chain for `data-tile-id`. Cached because\n * the lookup is stable for the lifetime of the mount. Null while\n * unresolved (or when not running inside a SyntroTileCard, e.g.\n * in standalone test fixtures). */\n private _tileId: string | null = null;\n /** Instance ids of chips appended by LLM mounts (vs. authored chip\n * configs from `props.chips`). Tracked so `removeItem(instance_id)`\n * can find and prune by id. */\n private _llmAppendedIds: Set<string> = new Set();\n\n /**\n * Tracks the currently-mounted payload widget so we can swap on chip\n * change + unmount on close. Same lifecycle pattern as\n * `SyntroCanvasOverlay._lidMountHandle`.\n */\n private _payloadMount: {\n chipId: string;\n widgetId: string;\n handle: { unmount: () => void; update?: (props?: Record<string, unknown>) => void };\n } | null = null;\n\n override createRenderRoot(): HTMLElement {\n return this;\n }\n\n override disconnectedCallback(): void {\n super.disconnectedCallback();\n this._unmountPayload();\n this._stripResizeObserver?.disconnect();\n this._stripResizeObserver = null;\n this._compositionalUnsub?.();\n this._compositionalUnsub = null;\n }\n\n override updated(changed: Map<string, unknown>): void {\n super.updated(changed);\n // Reconcile the payload mount whenever the open chip, the chip\n // data (props could have changed), or the runtime changes.\n if (changed.has('_openId') || changed.has('chips') || changed.has('runtimeRef')) {\n this._syncPayloadMount();\n }\n // Wire scroll affordances every render in case the strip DOM was\n // recreated. Idempotent: re-attaching to the same node is a no-op.\n this._syncStripObserver();\n this._updateScrollAffordances();\n // Re-resolve the tile id + (re)attach the compositional-append\n // subscription whenever the runtime ref changes. The tile id is\n // looked up from the closest `[data-tile-id]` ancestor \u2014 set by\n // SyntroTileCard's render.\n if (changed.has('runtimeRef')) {\n this._compositionalUnsub?.();\n this._compositionalUnsub = null;\n this._tileId = this._resolveTileId();\n }\n // Lazy-subscribe: the runtime may not have `events.subscribe`\n // resolved at first `updated()` pass (the chips strip mounts before\n // the runtime finishes wiring its event bus). Re-attempt on every\n // updated() pass while we're still unsubscribed \u2014 idempotent once\n // the subscription lands.\n if (!this._compositionalUnsub && this._tileId == null) {\n this._tileId = this._resolveTileId();\n }\n if (!this._compositionalUnsub) {\n this._subscribeCompositional();\n }\n }\n\n private _resolveTileId(): string | null {\n const anchor = this.closest<HTMLElement>('[data-tile-id]');\n return anchor?.getAttribute('data-tile-id') ?? null;\n }\n\n /**\n * Subscribe to the runtime's event bus for compositional-item events\n * targeting this strip's tile id. The subscription survives until\n * disconnect; when an event arrives with a non-matching tile_id, it's\n * a no-op (the same subscription handles all strips on the page \u2014\n * filter is just per-event check).\n */\n private _subscribeCompositional(): void {\n // Call via the bus object so `this` stays bound to the EventBus\n // instance \u2014 extracting the method to a local would lose its\n // `this.subscriptions` and throw at the first call.\n const bus = this.runtimeRef?.events;\n if (!bus?.subscribe || !this._tileId) return;\n const tileId = this._tileId;\n this._compositionalUnsub = bus.subscribe((event) => {\n const props = event.props ?? {};\n // Filter to events targeting THIS strip's tile.\n if (props.tile_id !== tileId) return;\n if (event.name === 'element.compositional_append') {\n this.insertItem(\n String(props.instance_id ?? ''),\n props.item as Record<string, unknown>,\n (props.position as 'append' | 'prepend') ?? 'append'\n );\n } else if (event.name === 'element.compositional_patch') {\n this.patchItem(String(props.instance_id ?? ''), props.item as Record<string, unknown>);\n } else if (event.name === 'element.compositional_remove') {\n this.removeItem(String(props.instance_id ?? ''));\n }\n });\n // Ask the store to replay any items it already has for our tile.\n // The store is a module-singleton that survives chat-bar unmount/\n // remount, so SPA-navigating away and back leaves persisted items\n // in memory; the replay re-publishes append events the subscription\n // above picks up. Dedup on `insertItem` keeps it idempotent if a\n // fresh hydrate is also in flight.\n bus.publish?.('element.compositional_replay_request', { tile_id: tileId });\n }\n\n // \u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\n // CompositionalContainer contract \u2014 `ItemHandler` translates wire\n // mutations into events that call these methods. The wire `item`\n // shape is fully formed (`{kind, config: {id, title, payload, \u2026}}`);\n // the strip just appends, patches, or removes by `instance_id`.\n // `instance_id` is the canonical id; chip.config.id is set to it by\n // the backend, so they're the same value. We store the id on\n // `chip.config.id` and use that as the lookup key.\n // \u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\n\n /** Append (or prepend) a new chip authored by the LLM. */\n insertItem(\n instanceId: string,\n item: Record<string, unknown>,\n position: 'append' | 'prepend'\n ): void {\n if (!instanceId) return;\n if (this._llmAppendedIds.has(instanceId)) return; // dedup\n // The wire shape is `{kind: 'suggestions:chip', config: {\u2026}}`. We\n // accept it as-is \u2014 fully-formed chip envelope from the backend.\n const incoming = item as unknown as SuggestionChip;\n if (!incoming?.config?.id) return;\n // instanceId is the wire address used by every later patch/remove event.\n // Normalize a stale embedded id so the item cannot become unreachable.\n const chip: SuggestionChip = {\n ...incoming,\n config: { ...incoming.config, id: instanceId },\n };\n this._llmAppendedIds.add(instanceId);\n this.chips = position === 'prepend' ? [chip, ...this.chips] : [...this.chips, chip];\n }\n\n /** Replace the existing chip's content. v1: full replacement (no\n * in-place merge); the chip widget already re-renders on chip data\n * changes. */\n patchItem(instanceId: string, item: Record<string, unknown>): void {\n if (!instanceId) return;\n const idx = this.chips.findIndex((c) => c.config.id === instanceId);\n if (idx < 0) return;\n const next = [...this.chips];\n next[idx] = item as unknown as SuggestionChip;\n this.chips = next;\n }\n\n /** Remove a chip by instance id. Closes the payload drawer if the\n * removed chip was the open one. */\n removeItem(instanceId: string): void {\n if (!instanceId) return;\n const next = this.chips.filter((c) => c.config.id !== instanceId);\n if (next.length === this.chips.length) return;\n this.chips = next;\n this._llmAppendedIds.delete(instanceId);\n if (this._openId === instanceId) this._openId = null;\n }\n\n /**\n * Attach a ResizeObserver to the scroll container so we recompute\n * left/right arrow visibility when chips are added/removed or the\n * panel width changes. The scroll listener on the strip element\n * handles user-driven scrolls.\n */\n private _syncStripObserver(): void {\n const strip = this.querySelector<HTMLElement>('[data-chips-strip]');\n if (!strip) {\n this._stripResizeObserver?.disconnect();\n this._stripResizeObserver = null;\n return;\n }\n // JSDOM (component tests) doesn't ship ResizeObserver. The strip\n // still functions without it \u2014 _updateScrollAffordances runs on\n // every `updated()` pass and on scroll events, so the only thing\n // missing is the \"external width change while no chip data changed\"\n // sync, which can't be exercised in a JSDOM unit test anyway.\n if (typeof ResizeObserver === 'undefined') return;\n if (!this._stripResizeObserver) {\n this._stripResizeObserver = new ResizeObserver(() => this._updateScrollAffordances());\n }\n // disconnect+observe is cheap and avoids dangling observation when\n // Lit recycles the DOM node for whatever reason.\n this._stripResizeObserver.disconnect();\n this._stripResizeObserver.observe(strip);\n }\n\n /**\n * Recompute whether the left/right scroll arrows should be visible.\n * Left arrow \u21D0 scrollLeft > 0. Right arrow \u21D0 there are more chips\n * to the right (scrollLeft + clientWidth < scrollWidth). Threshold\n * of 1px tolerance handles sub-pixel rounding on scaled displays.\n */\n private _updateScrollAffordances(): void {\n const strip = this.querySelector<HTMLElement>('[data-chips-strip]');\n if (!strip) return;\n const canLeft = strip.scrollLeft > 1;\n const canRight = strip.scrollLeft + strip.clientWidth < strip.scrollWidth - 1;\n if (canLeft !== this._canScrollLeft) this._canScrollLeft = canLeft;\n if (canRight !== this._canScrollRight) this._canScrollRight = canRight;\n }\n\n private _onStripScroll = (): void => {\n this._updateScrollAffordances();\n };\n\n /**\n * Scroll the strip by ~80% of its visible width, so each arrow click\n * advances the user past most-but-not-all of the current chips\n * (a small overlap helps the user keep their place in the row).\n */\n private _scrollBy(direction: 'left' | 'right'): void {\n const strip = this.querySelector<HTMLElement>('[data-chips-strip]');\n if (!strip) return;\n const delta = strip.clientWidth * 0.8 * (direction === 'left' ? -1 : 1);\n strip.scrollBy({ left: delta, behavior: 'smooth' });\n }\n\n private _unmountPayload(): void {\n if (this._payloadMount) {\n try {\n this._payloadMount.handle.unmount();\n } catch (err) {\n console.warn('[adaptive-chips-strip] payload widget unmount threw:', err);\n }\n this._payloadMount = null;\n }\n }\n\n /**\n * Reconcile the payload mount with the current `_openId`:\n * - drawer closed / no runtime / widget id unknown \u2192 tear down\n * - same chip + same widget id \u2192 no-op (or props update)\n * - different chip \u2192 unmount old, mount new\n */\n private _syncPayloadMount(): void {\n const chip = this.chips.find((c) => c.config.id === this._openId) ?? null;\n const widgets = this.runtimeRef?.widgets;\n if (!chip || !widgets || !widgets.has(chip.config.payload.widget)) {\n this._unmountPayload();\n return;\n }\n const nextWidget = chip.config.payload.widget;\n const nextProps = chip.config.payload.props ?? {};\n if (\n this._payloadMount?.chipId === chip.config.id &&\n this._payloadMount.widgetId === nextWidget\n ) {\n // Same chip + same widget \u2014 update props in-place if the widget\n // supports it; otherwise leave untouched (no-op covers the\n // common no-change render case).\n this._payloadMount.handle.update?.(nextProps);\n return;\n }\n this._unmountPayload();\n const container = this.querySelector<HTMLElement>('[data-chip-payload-mount]');\n if (!container) {\n // Template hasn't laid down the mount target yet (Lit microtask\n // race). Retry after paint \u2014 without this, fast chip clicks can\n // land on a render where _openId changes but the conditional\n // template branch hasn't committed, and the payload silently\n // never mounts.\n requestAnimationFrame(() => {\n if (this._openId !== chip.config.id) return;\n if (\n this._payloadMount?.chipId === chip.config.id &&\n this._payloadMount.widgetId === nextWidget\n ) {\n return;\n }\n const retry = this.querySelector<HTMLElement>('[data-chip-payload-mount]');\n if (!retry) return;\n const handle = widgets.mount(nextWidget, retry, nextProps);\n this._payloadMount = { chipId: chip.config.id, widgetId: nextWidget, handle };\n });\n return;\n }\n const handle = widgets.mount(nextWidget, container, nextProps);\n this._payloadMount = { chipId: chip.config.id, widgetId: nextWidget, handle };\n }\n\n private _onChipClick(chip: SuggestionChip): void {\n if (this._openId === chip.config.id) {\n // Toggle closed.\n this._openId = null;\n return;\n }\n this._openId = chip.config.id;\n this.dispatchEvent(\n new CustomEvent<{ id: string; payload: ChipPayload }>('chip-revealed', {\n detail: { id: chip.config.id, payload: chip.config.payload },\n bubbles: true,\n composed: true,\n })\n );\n }\n\n private _onChipDismiss(chip: SuggestionChip, e: Event): void {\n // Don't let the dismiss click bubble up to the chip's own click\n // handler \u2014 the user is removing the chip, not opening it.\n e.stopPropagation();\n // If the dismissed chip was the open one, close the drawer first\n // so the payload region doesn't briefly point at nothing.\n if (this._openId === chip.config.id) this._openId = null;\n this.dispatchEvent(\n new CustomEvent<{ id: string }>('chip-dismissed', {\n detail: { id: chip.config.id },\n bubbles: true,\n composed: true,\n })\n );\n }\n\n private _onPayloadClose = (): void => {\n this._openId = null;\n };\n\n override render(): TemplateResult {\n const open = this.chips.find((c) => c.config.id === this._openId) ?? null;\n\n return html`\n <div data-syntro-chips-tile style=${styleMap(rootStyles())}>\n <div data-chips-strip-frame style=${styleMap(stripFrameStyles())}>\n ${\n this._canScrollLeft\n ? html`<button\n type=\"button\"\n data-chips-scroll=\"left\"\n aria-label=\"Scroll suggestions left\"\n @click=${() => this._scrollBy('left')}\n style=${styleMap(scrollButtonStyles('left'))}\n >\u2039</button>`\n : nothing\n }\n <div\n data-chips-strip\n style=${styleMap(stripStyles())}\n @scroll=${this._onStripScroll}\n >\n ${this.chips.map(\n (chip) => html`<button\n type=\"button\"\n data-chip-id=${chip.config.id}\n data-syntro-element-id=${chip.config.id}\n data-state=${this._openId === chip.config.id ? 'open' : 'closed'}\n data-chromeless=${this.chromeless ? 'true' : 'false'}\n style=${styleMap(chipStyles(this._openId === chip.config.id, this.chromeless))}\n @click=${() => this._onChipClick(chip)}\n >\n <span style=${styleMap(chipTitleStyles())}>${chip.config.title}</span>\n <span style=${styleMap(chipGlyphStyles())}>\n ${this._openId === chip.config.id ? '\u25BC' : '\u203A'}\n </span>\n ${\n // Per-chip dismiss \u00D7 is suppressed when the strip is\n // chromeless \u2014 LLM-curated suggestions in a mini-\n // canvas surface shouldn't be user-dismissible (the\n // model picks them; the user can't \"remove\" them\n // any more than they can remove a paragraph of\n // prose). Also suppressed on the open chip in any\n // mode (the chip's button-toggle handles close).\n this.chromeless || this._openId === chip.config.id\n ? nothing\n : html`<span\n role=\"button\"\n tabindex=\"0\"\n data-chip-dismiss=${chip.config.id}\n aria-label=\"Dismiss suggestion\"\n title=\"Dismiss\"\n style=${styleMap(chipDismissStyles())}\n @click=${(e: Event) => this._onChipDismiss(chip, e)}\n @keydown=${(e: KeyboardEvent) => {\n if (e.key === 'Enter' || e.key === ' ') {\n e.preventDefault();\n this._onChipDismiss(chip, e);\n }\n }}\n >\u00D7</span>`\n }\n </button>`\n )}\n </div>\n ${\n this._canScrollRight\n ? html`<button\n type=\"button\"\n data-chips-scroll=\"right\"\n aria-label=\"Scroll suggestions right\"\n @click=${() => this._scrollBy('right')}\n style=${styleMap(scrollButtonStyles('right'))}\n >\u203A</button>`\n : nothing\n }\n </div>\n ${\n open\n ? html`<div\n data-chip-payload\n data-for-chip=${open.config.id}\n data-chromeless=${this.chromeless ? 'true' : 'false'}\n style=${styleMap(payloadStyles(this.chromeless))}\n >\n <!--\n Drawer header \u2014 title (the Q in Q&A) ALWAYS renders\n because it's the actual content of the answer\n pairing, not chrome. Chromeless mode drops the\n surrounding chrome (border, background, \u2303 close)\n but the title stays so the chip \u2192 answer link is\n visible above the body. User closes by re-clicking\n the chip.\n -->\n <div\n data-chip-payload-header\n style=${styleMap(payloadHeaderStyles(this.chromeless))}\n >\n <span>${open.config.title}</span>\n ${\n this.chromeless\n ? nothing\n : html`<button\n type=\"button\"\n data-chip-payload-close\n aria-label=\"Collapse\"\n @click=${this._onPayloadClose}\n style=${styleMap(payloadCloseStyles())}\n >\u2303</button>`\n }\n </div>\n <div style=${styleMap(payloadBodyStyles(this.chromeless))}>\n <!--\n Payload widget mounts here imperatively in updated().\n The mount container is a stable element across renders so\n the runtime registry can track + update + unmount\n properly. If the widget id is unknown to the registry,\n we leave a labeled placeholder so the gap is visible\n in development rather than silently empty.\n -->\n ${\n this.runtimeRef?.widgets?.has(open.config.payload.widget)\n ? html`<div data-chip-payload-mount></div>`\n : html`<p style=${styleMap(unresolvedStyles())}>\n Widget <code>${open.config.payload.widget}</code> not registered.\n </p>`\n }\n </div>\n </div>`\n : nothing\n }\n </div>\n `;\n }\n}\n\n// ---------------------------------------------------------------------------\n// Styles\n// ---------------------------------------------------------------------------\n\nfunction rootStyles(): Record<string, string> {\n return {\n display: 'flex',\n flexDirection: 'column',\n gap: '10px',\n width: '100%',\n };\n}\n\nfunction stripFrameStyles(): Record<string, string> {\n return {\n position: 'relative',\n display: 'flex',\n alignItems: 'center',\n width: '100%',\n };\n}\n\nfunction stripStyles(): Record<string, string> {\n return {\n display: 'flex',\n flexDirection: 'row',\n // Single row \u2014 chips never wrap. Horizontal overflow becomes\n // a scrollable region with left/right arrow affordances on either\n // side of the frame. `flex-wrap: wrap` (the old behavior) packed\n // chips into multiple rows, which broke the mini-canvas surface's\n // visual rhythm \u2014 chat-bar above, ONE row of chips, payload below.\n flexWrap: 'nowrap',\n gap: '8px',\n width: '100%',\n overflowX: 'auto',\n overflowY: 'hidden',\n // Hide the native scrollbar \u2014 the chevron buttons are the\n // affordance. Firefox: `scrollbarWidth: 'none'`. WebKit: the\n // global `::-webkit-scrollbar { display: none }` rule in\n // chatTrailGlobalStyles.ts (which is shared chat-surface CSS) is\n // what hides it across all our scroll surfaces.\n scrollbarWidth: 'none',\n scrollSnapType: 'x proximity',\n scrollBehavior: 'smooth',\n // Don't let touch scroll bubble up to the page when the strip\n // can scroll horizontally \u2014 keeps wheel scroll on the canvas\n // intact while letting the strip move under the cursor.\n overscrollBehavior: 'contain',\n };\n}\n\n/**\n * Left/right scroll arrows. Absolute-positioned on either edge of the\n * frame so they overlay the chips at the edge \u2014 combined with the\n * frame's relative positioning, they sit on top of the chip pills at\n * the boundary, with a small backdrop blur so the underlying chip is\n * still legible. Visible only when there's more content in that\n * direction (controlled by `_canScrollLeft` / `_canScrollRight`).\n */\nfunction scrollButtonStyles(side: 'left' | 'right'): Record<string, string> {\n return {\n position: 'absolute',\n [side]: '0',\n top: '50%',\n transform: 'translateY(-50%)',\n zIndex: '2',\n width: '24px',\n height: '24px',\n display: 'inline-flex',\n alignItems: 'center',\n justifyContent: 'center',\n padding: '0',\n borderRadius: '9999px',\n border: '1px solid hsl(var(--sc-tile-border-color, 0 0% 100%) / 0.18)',\n background: 'hsl(var(--sc-accent-color) / 0.18)',\n backdropFilter: 'blur(6px)',\n WebkitBackdropFilter: 'blur(6px)',\n color: 'var(--sc-tile-title-color, currentColor)',\n fontSize: '14px',\n lineHeight: '1',\n cursor: 'pointer',\n opacity: '0.85',\n transition: 'opacity 150ms ease, background 150ms ease',\n };\n}\n\nfunction chipStyles(isOpen: boolean, _chromeless: boolean): Record<string, string> {\n // The chip itself ALWAYS renders as a pill with title. Chromeless\n // is about dropping wrapping chrome (tile-card, drawer chrome,\n // per-chip dismiss \u00D7), not about turning the chip into raw text \u2014\n // mixed-style chips inside a single strip looked bad and lost the\n // affordance. Keep the pill, drop the surroundings.\n return {\n display: 'inline-flex',\n alignItems: 'center',\n gap: '6px',\n // Flex to text width up to a sane cap. The title span inside owns\n // the ellipsis safety net for genuinely-long titles.\n maxWidth: '32ch',\n color: isOpen\n ? 'var(--sc-tile-title-color, currentColor)'\n : 'var(--sc-tile-text-color, currentColor)',\n fontSize: '12px',\n fontWeight: '600',\n cursor: 'pointer',\n transition: 'background 180ms ease, border-color 180ms ease, color 180ms ease',\n padding: '6px 12px',\n borderRadius: '9999px',\n border: isOpen\n ? '1px solid hsl(var(--sc-accent-color) / 0.45)'\n : '1px solid hsl(var(--sc-tile-border-color, 0 0% 100%) / 0.18)',\n background: isOpen ? 'hsl(var(--sc-accent-color) / 0.10)' : 'transparent',\n };\n}\n\nfunction chipTitleStyles(): Record<string, string> {\n return {\n whiteSpace: 'nowrap',\n overflow: 'hidden',\n textOverflow: 'ellipsis',\n minWidth: '0',\n };\n}\n\n// Small \u2715 inside each closed chip. Uses a span+role=\"button\" so it\n// nests inside the chip's <button> without violating \"no interactive\n// inside interactive\" \u2014 the click handler stopPropagation-s so it\n// doesn't open the chip.\nfunction chipDismissStyles(): Record<string, string> {\n return {\n display: 'inline-flex',\n alignItems: 'center',\n justifyContent: 'center',\n width: '16px',\n height: '16px',\n marginLeft: '2px',\n borderRadius: '9999px',\n color: 'inherit',\n fontSize: '12px',\n lineHeight: '1',\n cursor: 'pointer',\n opacity: '0.45',\n flexShrink: '0',\n transition: 'opacity 150ms ease, background 150ms ease',\n };\n}\n\nfunction chipGlyphStyles(): Record<string, string> {\n return {\n fontSize: '10px',\n opacity: '0.7',\n flexShrink: '0',\n };\n}\n\nfunction payloadStyles(chromeless: boolean): Record<string, string> {\n const base: Record<string, string> = {\n display: 'flex',\n flexDirection: 'column',\n gap: '6px',\n color: 'var(--sc-tile-title-color, currentColor)',\n };\n if (chromeless) {\n // No drawer chrome \u2014 the payload sits flush with the strip\n // above it. Visual separation comes from typography (the chip's\n // underline) and slight spacing, not borders/backgrounds.\n return {\n ...base,\n padding: '4px 0 0',\n borderRadius: '0',\n border: 'none',\n background: 'transparent',\n };\n }\n return {\n ...base,\n padding: '10px 12px',\n borderRadius: 'var(--sc-tile-border-radius, 12px)',\n border: '1px solid hsl(var(--sc-accent-color) / 0.18)',\n background: 'hsl(var(--sc-accent-color) / 0.04)',\n };\n}\n\nfunction payloadHeaderStyles(chromeless: boolean): Record<string, string> {\n return {\n display: 'flex',\n alignItems: 'center',\n justifyContent: 'space-between',\n gap: '8px',\n fontSize: '12px',\n fontWeight: '600',\n // In chromeless mode the header is the only visible heading for\n // the answer below (no surrounding box/border). Use the accent\n // color so the Q reads distinctly as the prompt for the A.\n ...(chromeless ? { color: 'hsl(var(--sc-accent-color) / 0.95)' } : {}),\n };\n}\n\nfunction payloadCloseStyles(): Record<string, string> {\n return {\n width: '22px',\n height: '22px',\n display: 'inline-flex',\n alignItems: 'center',\n justifyContent: 'center',\n borderRadius: '9999px',\n background: 'transparent',\n border: '1px solid hsl(var(--sc-tile-border-color, 0 0% 100%) / 0.18)',\n color: 'inherit',\n fontSize: '11px',\n cursor: 'pointer',\n opacity: '0.65',\n };\n}\n\nfunction payloadBodyStyles(chromeless: boolean): Record<string, string> {\n return {\n fontSize: '12px',\n lineHeight: '1.55',\n color: 'var(--sc-tile-text-color, currentColor)',\n // No top divider needed when the header is suppressed.\n ...(chromeless ? {} : {}),\n };\n}\n\nfunction unresolvedStyles(): Record<string, string> {\n return {\n margin: '0',\n fontStyle: 'italic',\n opacity: '0.7',\n };\n}\n\nif (!customElements.get('adaptive-chips-strip')) {\n customElements.define('adaptive-chips-strip', AdaptiveChipsStrip);\n}\n\ndeclare global {\n interface HTMLElementTagNameMap {\n 'adaptive-chips-strip': AdaptiveChipsStrip;\n }\n}\n"],
|
|
5
|
+
"mappings": "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",
|
|
6
|
+
"names": ["handle"]
|
|
7
|
+
}
|