@syntrologie/adapt-faq 2.8.0-canary.365 → 2.8.0-canary.367

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.
@@ -105,6 +105,7 @@ export declare const baseStyles: {
105
105
  readonly flexDirection: "column";
106
106
  readonly gap: "12px";
107
107
  readonly minHeight: "0";
108
+ readonly padding: "var(--sc-content-item-padding, 12px 16px)";
108
109
  };
109
110
  readonly detailBack: {
110
111
  readonly display: "inline-flex";
@@ -1 +1 @@
1
- {"version":3,"file":"faq-styles.d.ts","sourceRoot":"","sources":["../src/faq-styles.ts"],"names":[],"mappings":"AAAA;;;;;GAKG;AAQH,eAAO,MAAM,UAAU;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;CA4Ib,CAAC;AAMX,eAAO,MAAM,WAAW;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;CAqFvB,CAAC"}
1
+ {"version":3,"file":"faq-styles.d.ts","sourceRoot":"","sources":["../src/faq-styles.ts"],"names":[],"mappings":"AAAA;;;;;GAKG;AAQH,eAAO,MAAM,UAAU;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;CA+Ib,CAAC;AAMX,eAAO,MAAM,WAAW;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;CAqFvB,CAAC"}
package/dist/runtime.js CHANGED
@@ -217,7 +217,10 @@ var baseStyles = {
217
217
  display: "flex",
218
218
  flexDirection: "column",
219
219
  gap: "12px",
220
- minHeight: "0"
220
+ minHeight: "0",
221
+ // Inset the master→detail takeover to match the list questions' padding so
222
+ // a single Q&A taking over the tile doesn't render flush to the edges.
223
+ padding: "var(--sc-content-item-padding, 12px 16px)"
221
224
  },
222
225
  detailBack: {
223
226
  display: "inline-flex",
@@ -1,7 +1,7 @@
1
1
  {
2
2
  "version": 3,
3
3
  "sources": ["../src/executors.ts", "../src/FAQWidgetLit.ts", "../src/faq-styles.ts", "../src/runtime.ts"],
4
- "sourcesContent": ["/**\n * Adaptive FAQ - Action Executors\n *\n * Three executors that operate on the FAQStore:\n * - executeScrollToFaq: scroll to a FAQ item and optionally expand it\n * - executeToggleFaqItem: open / close / toggle a FAQ item\n * - executeUpdateFaq: add, remove, reorder, or replace FAQ items\n */\n\nimport type { FAQStore } from './state';\nimport type {\n ExecutorContext,\n ExecutorResult,\n FAQQuestionAction,\n ScrollToFaqAction,\n ToggleFaqItemAction,\n UpdateFaqAction,\n} from './types';\n\n// ============================================================================\n// Helpers\n// ============================================================================\n\n/**\n * Resolve a FAQ item by direct ID or by fuzzy question text match.\n * Throws if neither yields a result.\n */\nfunction resolveItem(store: FAQStore, itemId?: string, itemQuestion?: string): FAQQuestionAction {\n if (itemId) {\n const found = store.getState().items.find((i) => i.config.id === itemId);\n if (found) return found;\n }\n\n if (itemQuestion) {\n const found = store.findByQuestion(itemQuestion);\n if (found) return found;\n }\n\n throw new Error('FAQ item not found');\n}\n\n// ============================================================================\n// executeScrollToFaq\n// ============================================================================\n\n/**\n * Scroll to a FAQ item in the DOM and optionally expand it.\n *\n * Looks up the item by `itemId` or `itemQuestion`, scrolls the matching\n * `[data-faq-item-id]` element into view, and expands it unless\n * `expand` is explicitly set to `false`.\n */\nexport async function executeScrollToFaq(\n action: ScrollToFaqAction,\n context: ExecutorContext,\n store: FAQStore\n): Promise<ExecutorResult> {\n const item = resolveItem(store, action.itemId, action.itemQuestion);\n const { id } = item.config;\n\n // Expand the item unless explicitly told not to\n if (action.expand !== false) {\n store.expand(id);\n }\n\n // Scroll the DOM element into view (may be absent in test environments)\n const el = document.querySelector(`[data-faq-item-id=\"${id}\"]`);\n if (el) {\n el.scrollIntoView({\n behavior: action.behavior ?? 'smooth',\n });\n }\n\n // Publish analytics event\n context.publishEvent('faq:scroll_to', { itemId: id });\n\n return {\n cleanup: () => {\n // Optionally collapse on revert\n },\n };\n}\n\n// ============================================================================\n// executeToggleFaqItem\n// ============================================================================\n\n/**\n * Open, close, or toggle a FAQ item's expanded state.\n */\nexport async function executeToggleFaqItem(\n action: ToggleFaqItemAction,\n context: ExecutorContext,\n store: FAQStore\n): Promise<ExecutorResult> {\n const item = resolveItem(store, action.itemId, action.itemQuestion);\n const { id } = item.config;\n const desiredState = action.state ?? 'toggle';\n\n let newState: 'open' | 'closed';\n\n switch (desiredState) {\n case 'open':\n store.expand(id);\n newState = 'open';\n break;\n case 'closed':\n store.collapse(id);\n newState = 'closed';\n break;\n default: {\n const wasExpanded = store.getState().expandedItems.has(id);\n store.toggle(id);\n newState = wasExpanded ? 'closed' : 'open';\n break;\n }\n }\n\n context.publishEvent('faq:toggle', { itemId: id, newState });\n\n return {\n cleanup: () => {\n // Revert toggle on cleanup\n },\n };\n}\n\n// ============================================================================\n// executeUpdateFaq\n// ============================================================================\n\n/**\n * Add, remove, reorder, or replace FAQ items in the store.\n */\nexport async function executeUpdateFaq(\n action: UpdateFaqAction,\n context: ExecutorContext,\n store: FAQStore\n): Promise<ExecutorResult> {\n switch (action.operation) {\n case 'add': {\n const items = action.items ?? [];\n const position = action.position === 'prepend' ? 'prepend' : 'append';\n store.addItems(items, position);\n break;\n }\n\n case 'remove': {\n if (!action.itemId) {\n throw new Error('FAQ item not found');\n }\n // Verify the item exists before removing\n const exists = store.getState().items.some((i) => i.config.id === action.itemId);\n if (!exists) {\n throw new Error('FAQ item not found');\n }\n store.removeItem(action.itemId);\n break;\n }\n\n case 'reorder': {\n const order = action.order ?? [];\n store.reorderItems(order);\n break;\n }\n\n case 'replace': {\n const items = action.items ?? [];\n store.replaceItems(items);\n break;\n }\n }\n\n context.publishEvent('faq:update', { operation: action.operation });\n\n return {\n cleanup: () => {\n // Could snapshot previous state for undo\n },\n };\n}\n\n// ============================================================================\n// Executor Definitions for Registration\n// ============================================================================\n\n/**\n * All executors provided by adaptive-faq.\n * These are registered with the runtime's ExecutorRegistry.\n */\nexport const executorDefinitions = [\n { kind: 'faq:scroll_to', executor: executeScrollToFaq },\n { kind: 'faq:toggle_item', executor: executeToggleFaqItem },\n { kind: 'faq:update', executor: executeUpdateFaq },\n] as const;\n", "/**\n * Adaptive FAQ - FAQWidgetLit\n *\n * Lit web component equivalent of FAQWidget.tsx.\n * Renders a collapsible Q&A accordion with search, category grouping,\n * feedback, and markdown rendering \u2014 all as a custom element with no\n * Shadow DOM (light DOM via createRenderRoot).\n *\n * Tag name: <syntro-faq-accordion>\n *\n * Decorator-free: uses `static override properties` (tsconfig has no\n * experimentalDecorators).\n */\n\nimport { purple } from '@syntro/design-system/tokens';\nimport { html, LitElement, nothing } from 'lit';\nimport { styleMap } from 'lit/directives/style-map.js';\nimport { unsafeHTML } from 'lit/directives/unsafe-html.js';\nimport { getAnswerText, renderAnswerHtml } from './answerRendering';\nimport { baseStyles, themeStyles } from './faq-styles';\nimport type { FAQWidgetRuntime } from './faq-types';\nimport type {\n FAQAnswer,\n FAQConfig,\n FAQQuestionAction,\n FeedbackConfig,\n FeedbackValue,\n} from './types';\n\n// ============================================================================\n// Utility \u2014 styleMap accepts Record<string, string | number | undefined>\n// but its TypeScript signature is overly narrow in some Lit versions.\n// Cast through unknown to avoid false positives when style values include\n// numeric CSS properties (fontWeight, lineHeight, etc.).\n// ============================================================================\n\nfunction sm(styles: Record<string, unknown>): Record<string, string> {\n return styles as unknown as Record<string, string>;\n}\n\nfunction resolveFeedbackConfig(\n feedback: boolean | FeedbackConfig | undefined\n): FeedbackConfig | null {\n if (!feedback) return null;\n if (feedback === true) return { style: 'thumbs' };\n return feedback;\n}\n\nfunction getFeedbackPrompt(feedbackConfig: FeedbackConfig): string {\n return feedbackConfig.prompt ?? 'Was this helpful?';\n}\n\n/**\n * Small deterministic string hash (djb2, base36) for content-derived atomic\n * FAQ row ids \u2014 stable per question across re-mounts so expand/feedback state\n * keyed by id sticks to the right row even if the list reorders.\n */\nfunction hashFaqId(text: string): string {\n let h = 5381;\n for (let i = 0; i < text.length; i++) {\n h = (Math.imul(h, 33) ^ text.charCodeAt(i)) >>> 0;\n }\n return h.toString(36);\n}\n\nfunction resolveTheme(theme: FAQConfig['theme'] | undefined): 'light' | 'dark' {\n if (theme && theme !== 'auto') return theme;\n if (typeof window !== 'undefined') {\n return window.matchMedia?.('(prefers-color-scheme: dark)').matches ? 'dark' : 'light';\n }\n return 'light';\n}\n\n// ============================================================================\n// FAQAccordionElement \u2014 Lit element\n// ============================================================================\n\n/**\n * <syntro-faq-accordion> \u2014 light-DOM Lit web component.\n *\n * Set properties imperatively (no attribute serialisation for objects):\n * el.faqConfig = { expandBehavior: 'single', ... };\n * el.runtime = runtimeInstance;\n * el.instanceId = 'my-faq';\n */\nexport class FAQAccordionElement extends LitElement {\n // -----------------------------------------------------------------------\n // Reactive properties (no decorators \u2014 tsconfig forbids experimentalDecorators)\n // -----------------------------------------------------------------------\n\n static override properties = {\n // Public API \u2014 set from the outside\n faqConfig: { attribute: false },\n runtime: { attribute: false },\n instanceId: { type: String },\n\n // Internal reactive state (prefixed with _ to signal \"private\")\n // _openId: currently-open question id for the master\u2192detail takeover.\n // null = LIST view; a value = DETAIL view showing only that single Q&A.\n _openId: { state: true },\n _highlightId: { state: true },\n _searchQuery: { state: true },\n _feedbackState: { state: true },\n _hoveredId: { state: true },\n };\n\n // -----------------------------------------------------------------------\n // Property declarations\n // -----------------------------------------------------------------------\n\n faqConfig: FAQConfig = {\n expandBehavior: 'single',\n searchable: false,\n theme: 'auto',\n actions: [],\n };\n\n runtime: FAQWidgetRuntime | null = null;\n\n instanceId: string = 'faq-widget';\n\n // Internal state\n // The currently-open question id (null = list view, value = detail view).\n // The master\u2192detail takeover swaps the whole widget to a single Q&A so a\n // long answer never overflows the bounded velvet tile.\n _openId: string | null = null;\n _highlightId: string | null = null;\n _searchQuery: string = '';\n _feedbackState: Map<string, FeedbackValue> = new Map();\n _hoveredId: string | null = null;\n\n // Subscription cleanup handles\n private _unsubContext: (() => void) | null = null;\n private _unsubAccumulator: (() => void) | null = null;\n private _unsubCta: (() => void) | null = null;\n private _unsubDeepLink: (() => void) | null = null;\n private _unsubSessionMetrics: (() => void) | null = null;\n private _highlightTimer: ReturnType<typeof setTimeout> | null = null;\n\n // Compositional-child wiring \u2014 faq:question items the LLM mounts into this\n // accordion's tile arrive as `element.compositional_append` events (see\n // adaptive-chatbot's ItemHandler). Without this subscription the questions\n // are published into the void and the accordion renders empty.\n private _unsubCompositional: (() => void) | null = null;\n private _tileId: string | null = null;\n /** Instance ids already appended via the compositional bus \u2014 dedups\n * the subscribe-then-replay path (and re-subscribes on runtime change). */\n private _llmAppendedIds: Set<string> = new Set();\n\n // -----------------------------------------------------------------------\n // Light DOM \u2014 no Shadow DOM so CSS variables from the host page apply\n // -----------------------------------------------------------------------\n\n override createRenderRoot() {\n return this;\n }\n\n // -----------------------------------------------------------------------\n // Lifecycle\n // -----------------------------------------------------------------------\n\n override connectedCallback() {\n super.connectedCallback();\n this._subscribeAll();\n }\n\n override disconnectedCallback() {\n super.disconnectedCallback();\n this._unsubscribeAll();\n if (this._highlightTimer !== null) {\n clearTimeout(this._highlightTimer);\n this._highlightTimer = null;\n }\n }\n\n // Re-subscribe when runtime changes (property may be set after connectedCallback)\n override updated(changedProps: Map<string, unknown>) {\n if (changedProps.has('runtime')) {\n this._unsubscribeAll();\n this._subscribeAll();\n }\n }\n\n // -----------------------------------------------------------------------\n // Subscription management\n // -----------------------------------------------------------------------\n\n private _subscribeAll() {\n if (!this.runtime) return;\n\n // Context changes \u2192 force re-render\n this._unsubContext = this.runtime.context.subscribe(() => {\n this.requestUpdate();\n });\n\n // Accumulator changes \u2192 force re-render (for event_count triggerWhen)\n if (this.runtime.accumulator?.subscribe) {\n this._unsubAccumulator = this.runtime.accumulator.subscribe(() => {\n this.requestUpdate();\n });\n }\n\n // Session metric changes \u2192 force re-render (for session_metric triggerWhen)\n if (this.runtime.sessionMetrics?.subscribe) {\n this._unsubSessionMetrics = this.runtime.sessionMetrics.subscribe(() => {\n this.requestUpdate();\n });\n }\n\n // faq:open:* events from overlay CTA clicks\n if (this.runtime.events.subscribe) {\n // Check EventBus history for pending faq:open events\n if (this.runtime.events.getRecent) {\n const recentEvents = this.runtime.events.getRecent(\n { patterns: ['^action\\\\.tooltip_cta_clicked$', '^action\\\\.modal_cta_clicked$'] },\n 10\n );\n const pendingEvent = recentEvents\n .filter((e) => {\n const actionId = e.props?.actionId;\n return typeof actionId === 'string' && actionId.startsWith('faq:open:');\n })\n .pop();\n\n if (pendingEvent && Date.now() - pendingEvent.ts < 10000) {\n const questionId = (pendingEvent.props!.actionId as string).replace('faq:open:', '');\n // Takeover: put the widget into DETAIL view for that question\n // (previously this expanded the row inline).\n this._openId = questionId;\n }\n }\n\n this._unsubCta = this.runtime.events.subscribe(\n { patterns: ['^action\\\\.tooltip_cta_clicked$', '^action\\\\.modal_cta_clicked$'] },\n (event) => {\n // Same staleness guard as the history scan above: some EventBus\n // implementations replay recent history into new subscribers. Without\n // this guard the history scan AND this live handler both fire for the\n // same old event \u2014 a spurious second `canvas.requestOpen`. Skip any\n // event older than ~10s (a fresh click always has ts\u2248now).\n const ts = (event as { ts?: number }).ts;\n if (typeof ts === 'number' && Date.now() - ts >= 10000) return;\n const actionId = event.props?.actionId;\n if (typeof actionId !== 'string' || !actionId.startsWith('faq:open:')) return;\n const questionId = actionId.replace('faq:open:', '');\n // Takeover: open the question's detail view instead of inline expand.\n this._openId = questionId;\n this.runtime?.events.publish('canvas.requestOpen');\n }\n );\n }\n\n // notification.deep_link events\n if (this.runtime.events.subscribe) {\n const handleDeepLink = (event: { name: string; props?: Record<string, unknown> }) => {\n const tileId = event.props?.tileId as string | undefined;\n const itemId = event.props?.itemId as string | undefined;\n if (tileId !== this.instanceId) return;\n if (!itemId) return;\n\n // Takeover: open the question's detail view (previously inline expand).\n this._openId = itemId;\n this._highlightId = itemId;\n\n if (this._highlightTimer !== null) clearTimeout(this._highlightTimer);\n this._highlightTimer = setTimeout(() => {\n this._highlightId = null;\n this._highlightTimer = null;\n }, 1500);\n };\n\n // Check recent events (may have fired before widget mounted)\n if (this.runtime.events.getRecent) {\n const recent = this.runtime.events.getRecent({ names: ['notification.deep_link'] }, 5);\n const pending = recent\n .filter((e) => (e.props?.tileId as string) === this.instanceId && e.props?.itemId)\n .pop();\n if (pending && Date.now() - pending.ts < 10000) {\n handleDeepLink(pending);\n }\n }\n\n this._unsubDeepLink = this.runtime.events.subscribe(\n { names: ['notification.deep_link'] },\n (event) => {\n // Mirror the history-scan staleness guard: skip replayed events older\n // than ~10s so a bus that replays history into new subscribers doesn't\n // double-handle the same deep link (history scan + live handler).\n const ts = (event as { ts?: number }).ts;\n if (typeof ts === 'number' && Date.now() - ts >= 10000) return;\n handleDeepLink(event);\n }\n );\n }\n\n // Compositional children: faq:question items mounted into this\n // accordion's tile. The ItemHandler publishes one event per kind-\n // agnostic item mount; we filter to our tile and route into\n // `faqConfig.actions`. Mirrors AdaptiveChipsStrip's CompositionalContainer.\n this._subscribeCompositional();\n }\n\n /**\n * Subscribe to `element.compositional_*` events targeting this accordion's\n * tile, and ask the element store to replay any items it already holds for\n * us (covers the case where the accordion mounts AFTER the item did \u2014 the\n * inline-slot hydration race that otherwise silently drops the question).\n */\n private _subscribeCompositional() {\n const bus = this.runtime?.events;\n if (!bus?.subscribe) return;\n this._tileId = this._resolveTileId();\n if (!this._tileId) return;\n const tileId = this._tileId;\n this._unsubCompositional = bus.subscribe((event) => {\n const props = event.props ?? {};\n if (props.tile_id !== tileId) return;\n const instanceId = String(props.instance_id ?? '');\n if (event.name === 'element.compositional_append') {\n this._insertItem(\n instanceId,\n props.item as FAQQuestionAction,\n (props.position as 'append' | 'prepend') ?? 'append'\n );\n } else if (event.name === 'element.compositional_patch') {\n this._patchItem(instanceId, props.item as FAQQuestionAction);\n } else if (event.name === 'element.compositional_remove') {\n this._removeItem(instanceId);\n }\n });\n bus.publish('element.compositional_replay_request', { tile_id: tileId });\n }\n\n /** Tile id for compositional filtering: the enclosing tile card's\n * `data-tile-id` (set by SyntroTileCard), falling back to `instanceId`\n * when the accordion is mounted outside a tile card. */\n private _resolveTileId(): string | null {\n const anchor = this.closest<HTMLElement>('[data-tile-id]');\n const fromDom = anchor?.getAttribute('data-tile-id');\n if (fromDom) return fromDom;\n return this.instanceId && this.instanceId !== 'faq-widget' ? this.instanceId : null;\n }\n\n /** Append (or prepend) a faq:question the LLM mounted. The wire shape is a\n * fully-formed `{kind, config}` envelope, so we store it verbatim. */\n private _insertItem(\n instanceId: string,\n item: FAQQuestionAction,\n position: 'append' | 'prepend'\n ): void {\n if (!instanceId || !item?.config?.id) return;\n if (this._llmAppendedIds.has(instanceId)) return; // dedup replay / re-subscribe\n this._llmAppendedIds.add(instanceId);\n const actions = this.faqConfig.actions ?? [];\n const next = position === 'prepend' ? [item, ...actions] : [...actions, item];\n // Reassign so Lit sees the change (faqConfig is attribute:false).\n this.faqConfig = { ...this.faqConfig, actions: next };\n }\n\n /** Replace an existing question's content (full replacement). */\n private _patchItem(instanceId: string, item: FAQQuestionAction): void {\n if (!instanceId || !item?.config) return;\n const actions = this.faqConfig.actions ?? [];\n const idx = actions.findIndex((a) => a.config.id === instanceId);\n if (idx < 0) return;\n const next = [...actions];\n next[idx] = item;\n // If the patch changes the open question's id, our `_openId` would point at\n // a gone id and the detail view would fall back to the list. Re-point it at\n // the replacement's new id so the open question stays open through a patch.\n if (this._openId === instanceId && item.config.id !== instanceId) {\n this._openId = item.config.id;\n }\n this.faqConfig = { ...this.faqConfig, actions: next };\n }\n\n /** Remove a question by instance id. */\n private _removeItem(instanceId: string): void {\n if (!instanceId) return;\n const actions = this.faqConfig.actions ?? [];\n const next = actions.filter((a) => a.config.id !== instanceId);\n if (next.length === actions.length) return;\n this._llmAppendedIds.delete(instanceId);\n // Removing the currently-open question would leave `_openId` pointing at a\n // gone id. Return to the list view instead of resolving to an empty detail.\n if (this._openId === instanceId) this._openId = null;\n this.faqConfig = { ...this.faqConfig, actions: next };\n }\n\n private _unsubscribeAll() {\n this._unsubContext?.();\n this._unsubAccumulator?.();\n this._unsubSessionMetrics?.();\n this._unsubCta?.();\n this._unsubDeepLink?.();\n this._unsubCompositional?.();\n this._unsubContext = null;\n this._unsubAccumulator = null;\n this._unsubSessionMetrics = null;\n this._unsubCta = null;\n this._unsubDeepLink = null;\n this._unsubCompositional = null;\n }\n\n // -----------------------------------------------------------------------\n // Handlers\n // -----------------------------------------------------------------------\n\n /**\n * Master\u2192detail takeover: tapping a list row opens its single-Q&A detail\n * view (the whole widget swaps), so a long answer fills \u2014 and never\n * overflows \u2014 the bounded velvet tile. There is no simultaneous multi-expand;\n * one question owns the tile at a time.\n */\n private _handleOpen(id: string) {\n this._openId = id;\n\n this.runtime?.events.publish('faq:toggled', {\n instanceId: this.instanceId,\n questionId: id,\n expanded: true,\n timestamp: Date.now(),\n });\n }\n\n /** Back affordance: return from the detail view to the full list. */\n private _handleBack() {\n const id = this._openId;\n this._openId = null;\n\n if (id !== null) {\n this.runtime?.events.publish('faq:toggled', {\n instanceId: this.instanceId,\n questionId: id,\n expanded: false,\n timestamp: Date.now(),\n });\n }\n }\n\n private _handleFeedback(itemId: string, question: string, value: FeedbackValue) {\n const next = new Map(this._feedbackState);\n next.set(itemId, value);\n this._feedbackState = next;\n\n this.runtime?.events.publish('faq:feedback', { itemId, question, value });\n }\n\n // -----------------------------------------------------------------------\n // Computed helpers\n // -----------------------------------------------------------------------\n\n /**\n * Unified render list. Merges compositionally-appended rows\n * (`faqConfig.actions`, the container-then-stream path) with atomically\n * authored rows (`faqConfig.questions`, the struct_list path) normalized\n * into the same `FAQQuestionAction` shape. The atomic path is how the LLM\n * mounts a complete FAQ in one call \u2014 so it renders whole, never empty.\n */\n private _allQuestions(): FAQQuestionAction[] {\n const compositional = this.faqConfig.actions ?? [];\n // Content-derived id (not positional). Expand/feedback state is keyed by id;\n // if the LLM re-mounts the FAQ with a reordered or shortened list, a\n // positional `atomic-${i}` would re-point that state at a different\n // question. Hashing the question text keeps the id stable per question\n // across re-mounts. A `-N` suffix disambiguates same-text rows (including\n // empty strings, which all hash to the same value) so they never share\n // expand/feedback state \u2014 stable as long as their relative order is.\n const seen = new Map<string, number>();\n const atomic = (this.faqConfig.questions ?? []).map((q): FAQQuestionAction => {\n let id = `atomic-${hashFaqId(q.question)}`;\n const dup = seen.get(id) ?? 0;\n seen.set(id, dup + 1);\n if (dup > 0) id = `${id}-${dup}`;\n return {\n kind: 'faq:question',\n config: {\n id,\n question: q.question,\n answer: q.answer,\n category: q.category,\n },\n };\n });\n return [...atomic, ...compositional];\n }\n\n private _visibleQuestions(): FAQQuestionAction[] {\n return this._allQuestions().filter((q) => {\n if (!q.triggerWhen) return true;\n if (!this.runtime) return true;\n const result = this.runtime.evaluateSync<boolean>(q.triggerWhen);\n return result.value;\n });\n }\n\n private _orderedQuestions(visible: FAQQuestionAction[]): FAQQuestionAction[] {\n if (this.faqConfig.ordering === 'priority') {\n return [...visible].sort((a, b) => (b.config.priority ?? 0) - (a.config.priority ?? 0));\n }\n return visible;\n }\n\n private _filteredQuestions(ordered: FAQQuestionAction[]): FAQQuestionAction[] {\n const q = this._searchQuery.trim().toLowerCase();\n if (!this.faqConfig.searchable || !q) return ordered;\n return ordered.filter(\n (item) =>\n item.config.question.toLowerCase().includes(q) ||\n getAnswerText(item.config.answer).toLowerCase().includes(q) ||\n item.config.category?.toLowerCase().includes(q)\n );\n }\n\n private _categoryGroups(\n filtered: FAQQuestionAction[]\n ): Map<string | undefined, FAQQuestionAction[]> {\n const groups = new Map<string | undefined, FAQQuestionAction[]>();\n for (const item of filtered) {\n const cat = item.config.category;\n if (!groups.has(cat)) groups.set(cat, []);\n groups.get(cat)!.push(item);\n }\n return groups;\n }\n\n // -----------------------------------------------------------------------\n // Render helpers\n // -----------------------------------------------------------------------\n\n private _renderAnswer(answer: FAQAnswer) {\n const html_str = renderAnswerHtml(answer);\n return html`<div style=\"margin:0\" data-faq-markdown=\"\">${unsafeHTML(html_str)}</div>`;\n }\n\n private _renderFeedback(\n item: FAQQuestionAction,\n feedbackConfig: FeedbackConfig,\n feedbackValue: FeedbackValue | undefined,\n theme: 'light' | 'dark'\n ) {\n const colors = themeStyles[theme];\n const feedbackStyle = { ...baseStyles.feedback, ...colors.feedbackPrompt };\n\n return html`\n <div style=${styleMap(sm(feedbackStyle))}>\n <span>${getFeedbackPrompt(feedbackConfig)}</span>\n <button\n type=\"button\"\n style=${styleMap(\n sm({\n ...baseStyles.feedbackButton,\n ...(feedbackValue === 'up' ? baseStyles.feedbackButtonSelected : {}),\n })\n )}\n aria-label=\"Thumbs up\"\n @click=${() => this._handleFeedback(item.config.id, item.config.question, 'up')}\n >\\uD83D\\uDC4D</button>\n <button\n type=\"button\"\n style=${styleMap(\n sm({\n ...baseStyles.feedbackButton,\n ...(feedbackValue === 'down' ? baseStyles.feedbackButtonSelected : {}),\n })\n )}\n aria-label=\"Thumbs down\"\n @click=${() => this._handleFeedback(item.config.id, item.config.question, 'down')}\n >\\uD83D\\uDC4E</button>\n </div>\n `;\n }\n\n /**\n * LIST-view row. A tappable question with its chevron \\u2014 but NO inline answer\n * body. Tapping it takes over the tile with the question's detail view (see\n * {@link _renderDetail}). Keeps the per-row look/markers/highlight from the\n * old accordion minus the inline-expanded answer that overflowed the tile.\n */\n private _renderItem(item: FAQQuestionAction, isLast: boolean, theme: 'light' | 'dark') {\n const colors = themeStyles[theme];\n const isHighlighted = this._highlightId === item.config.id;\n const isHovered = this._hoveredId === item.config.id;\n\n const itemStyle = {\n ...baseStyles.item,\n ...colors.item,\n ...(isHighlighted\n ? {\n boxShadow: `0 0 0 2px ${purple[4]}, 0 0 12px rgba(106, 89, 206, 0.4)`,\n transition: 'box-shadow 0.3s ease',\n }\n : {}),\n ...(!isLast ? { borderBottom: 'var(--sc-content-item-divider, none)' } : {}),\n };\n\n const questionStyle = {\n ...baseStyles.question,\n ...colors.question,\n ...(isHovered ? colors.questionHover : {}),\n };\n\n const chevronStyle = {\n ...baseStyles.chevron,\n transform: 'rotate(0deg)',\n };\n\n return html`\n <div\n style=${styleMap(sm(itemStyle))}\n data-faq-item-id=${item.config.id}\n >\n <button\n type=\"button\"\n style=${styleMap(sm(questionStyle))}\n aria-expanded=${false}\n @click=${() => this._handleOpen(item.config.id)}\n @mouseenter=${() => {\n this._hoveredId = item.config.id;\n }}\n @mouseleave=${() => {\n this._hoveredId = null;\n }}\n >\n <span>${item.config.question}</span>\n <span style=${styleMap(sm(chevronStyle))}>\\u203A</span>\n </button>\n </div>\n `;\n }\n\n private _renderItems(items: FAQQuestionAction[], theme: 'light' | 'dark') {\n return items.map((item, index) => this._renderItem(item, index === items.length - 1, theme));\n }\n\n /**\n * DETAIL view \\u2014 the master\\u2192detail takeover. Renders ONLY the open question:\n * a back affordance, the question prominently, and its full answer via the\n * SAME {@link _renderAnswer}/`renderAnswerHtml` path (all answer formats still\n * work). The answer area scrolls if extremely long, so a single answer fills\n * the bounded velvet tile and never pushes content past the `overflow:hidden`\n * clip.\n */\n private _renderDetail(\n item: FAQQuestionAction,\n theme: 'light' | 'dark',\n feedbackConfig: FeedbackConfig | null\n ) {\n const colors = themeStyles[theme];\n\n const backStyle = {\n ...baseStyles.detailBack,\n ...colors.question,\n };\n const detailQuestionStyle = {\n ...baseStyles.detailQuestion,\n ...colors.question,\n };\n const detailAnswerStyle = {\n ...baseStyles.detailAnswer,\n ...colors.answer,\n };\n\n return html`\n <div style=${styleMap(sm(baseStyles.detail))} data-faq-detail=${item.config.id}>\n <button\n type=\"button\"\n style=${styleMap(sm(backStyle))}\n data-faq-back=\"\"\n aria-label=\"Back to questions\"\n @click=${() => this._handleBack()}\n >\n \\u2039 Back to questions\n </button>\n\n <div style=${styleMap(sm(detailQuestionStyle))}>${item.config.question}</div>\n\n <div style=${styleMap(sm(detailAnswerStyle))} aria-hidden=${false}>\n ${this._renderAnswer(item.config.answer)}\n ${\n feedbackConfig\n ? this._renderFeedback(\n item,\n feedbackConfig,\n this._feedbackState.get(item.config.id),\n theme\n )\n : nothing\n }\n </div>\n </div>\n `;\n }\n\n // -----------------------------------------------------------------------\n // Render\n // -----------------------------------------------------------------------\n\n override render() {\n const theme = resolveTheme(this.faqConfig.theme);\n const colors = themeStyles[theme];\n const feedbackConfig = resolveFeedbackConfig(this.faqConfig.feedback);\n\n const visible = this._visibleQuestions();\n const ordered = this._orderedQuestions(visible);\n const filtered = this._filteredQuestions(ordered);\n const hasCategories = filtered.some((q) => q.config.category);\n const groups = hasCategories ? this._categoryGroups(filtered) : null;\n\n const containerStyle = {\n ...baseStyles.container,\n ...colors.container,\n };\n\n const emptyStateStyle = {\n ...baseStyles.emptyState,\n ...colors.emptyState,\n };\n\n const categoryHeaderStyle = {\n ...baseStyles.categoryHeader,\n ...colors.categoryHeader,\n };\n\n const searchInputStyle = {\n ...baseStyles.searchInput,\n ...colors.searchInput,\n };\n\n // Empty state \u2014 no visible questions at all.\n //\n // A runtime-backed FAQ is a compositional container: its `faq:question`\n // items stream in as `element.compositional_append` events after mount\n // (and a replay request). Rendering the \"all set\" reassurance box while\n // we're still empty flashes an empty shell on every mount \u2014 and leaves\n // an orphaned empty box if the agent mounted a container it never filled\n // (the recurring \"empty FAQ showed up then disappeared\" bug). Render\n // nothing until the first question lands. The reassurance copy is only\n // for a standalone (runtime-less) FAQ configured directly with no items.\n if (visible.length === 0) {\n if (this.runtime) return nothing;\n return html`\n <div\n style=${styleMap(sm(containerStyle))}\n data-adaptive-id=${this.instanceId}\n data-adaptive-type=\"adaptive-faq\"\n >\n <div style=${styleMap(sm(emptyStateStyle))}>\n You're all set for now! We'll surface answers here when they're relevant to what\n you're doing.\n </div>\n </div>\n `;\n }\n\n // DETAIL view (master\u2192detail takeover). When a question is open, the whole\n // widget swaps to that single Q&A so it fills \u2014 and never overflows \u2014 the\n // bounded velvet tile. We resolve `_openId` against the *visible/ordered*\n // list (`ordered`), NOT the search-filtered list (`filtered`) \u2014 search is a\n // list-view concern only, so a `faq:open` for a question that doesn't match\n // an active `_searchQuery` must still open its detail. A genuinely stale id\n // (e.g. a question that gated out via triggerWhen, or was removed) is absent\n // from `ordered` and falls back to the list instead of a blank detail.\n if (this._openId !== null) {\n const openItem = ordered.find((q) => q.config.id === this._openId);\n if (openItem) {\n return html`\n <div\n style=${styleMap(sm(containerStyle))}\n data-adaptive-id=${this.instanceId}\n data-adaptive-type=\"adaptive-faq\"\n >\n ${this._renderDetail(openItem, theme, feedbackConfig)}\n </div>\n `;\n }\n }\n\n return html`\n <div\n style=${styleMap(sm(containerStyle))}\n data-adaptive-id=${this.instanceId}\n data-adaptive-type=\"adaptive-faq\"\n >\n ${\n this.faqConfig.searchable\n ? html`\n <div style=${styleMap(sm(baseStyles.searchWrapper))}>\n <style>\n [data-adaptive-id=\"${this.instanceId}\"] input::placeholder {\n color: var(--sc-content-search-color, inherit);\n opacity: 0.7;\n }\n </style>\n <input\n type=\"text\"\n placeholder=\"Search questions...\"\n .value=${this._searchQuery}\n style=${styleMap(sm(searchInputStyle))}\n @input=${(e: InputEvent) => {\n this._searchQuery = (e.target as HTMLInputElement).value;\n }}\n />\n </div>\n `\n : nothing\n }\n\n <div style=${styleMap(sm(baseStyles.accordion))}>\n ${\n groups\n ? Array.from(groups.entries()).map(\n ([category, items]) => html`\n ${\n category\n ? html`\n <div\n style=${styleMap(sm(categoryHeaderStyle))}\n data-category-header=${category}\n >\n ${category}\n </div>\n `\n : nothing\n }\n ${this._renderItems(items, theme)}\n `\n )\n : this._renderItems(filtered, theme)\n }\n </div>\n\n ${\n this.faqConfig.searchable && filtered.length === 0 && this._searchQuery\n ? html`\n <div\n style=${styleMap(sm({ ...baseStyles.noResults, ...colors.emptyState }))}\n >\n No questions found matching &quot;${this._searchQuery}&quot;\n </div>\n `\n : nothing\n }\n </div>\n `;\n }\n}\n\n// ============================================================================\n// Custom element registration\n// ============================================================================\n\nif (!customElements.get('syntro-faq-accordion')) {\n customElements.define('syntro-faq-accordion', FAQAccordionElement);\n}\n\nexport default FAQAccordionElement;\n", "/**\n * Adaptive FAQ - Styles\n *\n * BaseStyles object (font, layout, colors, animations) and theme integration\n * for the FAQWidget component.\n */\n\nimport { purple, slateGrey } from '@syntro/design-system/tokens';\n\n// ============================================================================\n// Base Styles\n// ============================================================================\n\nexport const baseStyles = {\n container: {\n fontFamily: 'var(--sc-font-family, system-ui, -apple-system, sans-serif)',\n maxWidth: '800px',\n margin: '0 auto',\n },\n searchWrapper: {\n marginBottom: '8px',\n },\n searchInput: {\n width: '100%',\n padding: '12px 16px',\n borderRadius: '8px',\n fontSize: '14px',\n outline: 'none',\n transition: 'border-color 0.15s ease',\n backgroundColor: 'var(--sc-content-search-background)',\n color: 'var(--sc-content-search-color)',\n },\n accordion: {\n display: 'flex',\n flexDirection: 'column' as const,\n gap: 'var(--sc-content-item-gap, 6px)',\n },\n item: {\n borderRadius: 'var(--sc-content-item-border-radius, 10px)',\n border: 'var(--sc-content-item-border, 1px solid rgba(0, 0, 0, 0.08))',\n background: 'var(--sc-content-item-background, rgba(255, 255, 255, 0.5))',\n overflow: 'hidden',\n transition: 'box-shadow 0.15s ease',\n },\n question: {\n width: '100%',\n padding: 'var(--sc-content-item-padding, 12px 16px)',\n display: 'flex',\n alignItems: 'center',\n justifyContent: 'space-between',\n border: 'none',\n cursor: 'pointer',\n fontSize: 'var(--sc-content-item-font-size, 15px)',\n fontWeight: 500,\n textAlign: 'left' as const,\n transition: 'background-color 0.15s ease',\n },\n chevron: {\n fontSize: '20px',\n transition: 'transform 0.2s ease',\n color: 'var(--sc-content-chevron-color, currentColor)',\n },\n answer: {\n padding: 'var(--sc-content-body-padding, 0 16px 12px 16px)',\n fontSize: 'var(--sc-content-body-font-size, 14px)',\n lineHeight: 1.6,\n overflow: 'hidden',\n transition: 'max-height 0.2s ease, padding 0.2s ease',\n },\n category: {\n display: 'inline-block',\n fontSize: '11px',\n fontWeight: 600,\n textTransform: 'uppercase' as const,\n letterSpacing: '0.05em',\n padding: '4px 8px',\n borderRadius: '4px',\n marginBottom: '8px',\n },\n categoryHeader: {\n fontSize: 'var(--sc-content-category-font-size, 12px)',\n fontWeight: 700,\n textTransform: 'uppercase' as const,\n letterSpacing: '0.05em',\n padding: 'var(--sc-content-category-padding, 8px 4px 4px 4px)',\n marginTop: 'var(--sc-content-category-gap, 4px)',\n },\n feedback: {\n display: 'flex',\n alignItems: 'center',\n gap: '8px',\n marginTop: '12px',\n paddingTop: '10px',\n borderTop: '1px solid rgba(0, 0, 0, 0.08)',\n fontSize: '13px',\n },\n feedbackButton: {\n background: 'none',\n border: '1px solid transparent',\n cursor: 'pointer',\n fontSize: '16px',\n padding: '4px 8px',\n borderRadius: '4px',\n transition: 'background-color 0.15s ease, border-color 0.15s ease',\n },\n feedbackButtonSelected: {\n borderColor: 'rgba(0, 0, 0, 0.2)',\n backgroundColor: 'rgba(0, 0, 0, 0.04)',\n },\n // \u2500\u2500 Master\u2192detail takeover \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 // The detail view fills the tile; the answer area scrolls if extremely long\n // so a single answer never pushes content past the tile's overflow clip.\n detail: {\n display: 'flex',\n flexDirection: 'column' as const,\n gap: '12px',\n minHeight: '0',\n },\n detailBack: {\n display: 'inline-flex',\n alignItems: 'center',\n gap: '4px',\n alignSelf: 'flex-start',\n background: 'none',\n border: 'none',\n padding: '4px 0',\n cursor: 'pointer',\n fontSize: '13px',\n fontWeight: 600,\n opacity: 0.85,\n },\n detailQuestion: {\n fontSize: 'var(--sc-content-item-font-size, 16px)',\n fontWeight: 600,\n lineHeight: 1.4,\n },\n detailAnswer: {\n fontSize: 'var(--sc-content-body-font-size, 14px)',\n lineHeight: 1.6,\n overflowY: 'auto' as const,\n flex: '1 1 auto',\n minHeight: '0',\n },\n emptyState: {\n textAlign: 'center' as const,\n padding: '48px 24px',\n fontSize: '14px',\n },\n noResults: {\n textAlign: 'center' as const,\n padding: '32px 16px',\n fontSize: '14px',\n },\n} as const;\n\n// ============================================================================\n// Theme Styles\n// ============================================================================\n\nexport const themeStyles = {\n light: {\n container: {\n backgroundColor: 'transparent',\n color: 'inherit',\n },\n searchInput: {\n border: `1px solid ${slateGrey[11]}`,\n },\n item: {\n backgroundColor: 'var(--sc-content-background)',\n borderTop: 'var(--sc-content-border)',\n borderRight: 'var(--sc-content-border)',\n borderBottom: 'var(--sc-content-border)',\n borderLeft: 'var(--sc-content-border)',\n },\n itemExpanded: {\n boxShadow: '0 4px 12px rgba(0, 0, 0, 0.08)',\n },\n question: {\n backgroundColor: 'transparent',\n color: 'var(--sc-content-text-color)',\n },\n questionHover: {\n backgroundColor: 'var(--sc-content-background-hover)',\n },\n answer: {\n color: 'var(--sc-content-text-secondary-color)',\n },\n category: {\n backgroundColor: purple[8],\n color: purple[2],\n },\n categoryHeader: {\n color: slateGrey[7],\n },\n emptyState: {\n color: slateGrey[8],\n },\n feedbackPrompt: {\n color: slateGrey[7],\n },\n },\n dark: {\n container: {\n backgroundColor: 'transparent',\n color: 'inherit',\n },\n searchInput: {\n border: `1px solid ${slateGrey[5]}`,\n },\n item: {\n backgroundColor: 'var(--sc-content-background)',\n borderTop: 'var(--sc-content-border)',\n borderRight: 'var(--sc-content-border)',\n borderBottom: 'var(--sc-content-border)',\n borderLeft: 'var(--sc-content-border)',\n },\n itemExpanded: {\n boxShadow: '0 4px 12px rgba(0, 0, 0, 0.15)',\n },\n question: {\n backgroundColor: 'transparent',\n color: 'var(--sc-content-text-color)',\n },\n questionHover: {\n backgroundColor: 'var(--sc-content-background-hover)',\n },\n answer: {\n color: 'var(--sc-content-text-secondary-color)',\n },\n category: {\n backgroundColor: purple[0],\n color: purple[6],\n },\n categoryHeader: {\n color: slateGrey[8],\n },\n emptyState: {\n color: slateGrey[7],\n },\n feedbackPrompt: {\n color: slateGrey[8],\n },\n },\n};\n", "/**\n * Adaptive FAQ - Runtime Module\n *\n * Runtime manifest for the FAQ accordion adaptive.\n * Mounts the Lit web component <syntro-faq-accordion>.\n * Provides action executors and widget registration.\n */\n\nimport { type MountPlumbing, stripMountPlumbing } from '@syntrologie/sdk-contracts';\nimport { executorDefinitions } from './executors';\nimport './FAQWidgetLit'; // registers <syntro-faq-accordion> custom element\nimport type { FAQWidgetRuntime } from './faq-types';\nimport type { FAQConfig, FAQQuestionAction } from './types';\n\n// ============================================================================\n// Lit Mountable Widget\n// ============================================================================\n\nconst DEFAULT_FAQ_CONFIG: FAQConfig = {\n expandBehavior: 'single',\n searchable: false,\n theme: 'auto',\n actions: [],\n};\n\n/**\n * Mountable widget interface for <syntro-faq-accordion> (Lit web component).\n */\nexport const FAQWidgetLitMountable = {\n mount(\n container: HTMLElement,\n config?: (FAQConfig & MountPlumbing & { runtime?: FAQWidgetRuntime }) | null\n ) {\n const incoming = config ?? null;\n const stripped = stripMountPlumbing<FAQConfig & { runtime?: FAQWidgetRuntime }>(incoming);\n // stripMountPlumbing does NOT strip the non-canonical `runtime` consumer key\n // on this widget because `runtime` is a canonical plumbing key. Pull the\n // explicit references back out for the element wiring.\n const runtime = incoming?.runtime as FAQWidgetRuntime | undefined;\n const instanceId = incoming?.instanceId ?? 'faq-widget';\n const faqConfig: FAQConfig = incoming ? (stripped as FAQConfig) : { ...DEFAULT_FAQ_CONFIG };\n\n const el = document.createElement('syntro-faq-accordion') as HTMLElement & {\n faqConfig: FAQConfig;\n runtime: FAQWidgetRuntime | null;\n instanceId: string;\n };\n\n Object.assign(el, {\n faqConfig,\n runtime: runtime ?? null,\n instanceId,\n });\n\n container.appendChild(el);\n return () => el.remove();\n },\n};\n\n// ============================================================================\n// App Runtime Manifest\n// ============================================================================\n\n/**\n * Runtime manifest for adaptive-faq.\n *\n * Provides:\n * - FAQ action executors (scroll_to, toggle_item, update)\n * - Widget-based accordion using the Lit web component\n */\nexport const runtime = {\n id: 'adaptive-faq',\n version: '2.0.0',\n name: 'FAQ Accordion',\n description:\n 'Collapsible Q&A accordion with actions, rich content, feedback, and personalization',\n\n /**\n * Action executors for programmatic FAQ interaction.\n */\n executors: executorDefinitions,\n\n /**\n * Widget definitions for the runtime's WidgetRegistry.\n */\n widgets: [\n {\n id: 'adaptive-faq:accordion',\n component: FAQWidgetLitMountable,\n metadata: {\n name: 'FAQ Accordion',\n description: 'Collapsible Q&A accordion with search, categories, and feedback',\n icon: '\u2753',\n subtitle: 'Curated just for you.',\n },\n },\n ],\n\n /**\n * Extract notify watcher entries from tile config props.\n * The runtime evaluates these continuously (even with drawer closed)\n * and publishes faq:question_revealed when triggerWhen transitions false \u2192 true.\n */\n notifyWatchers(props: Record<string, unknown>) {\n const actions = (props.actions ?? []) as FAQQuestionAction[];\n return actions\n .filter((a) => a.notify && a.triggerWhen)\n .map((a) => ({\n id: `faq:${a.config.id}`,\n strategy: a.triggerWhen!,\n eventName: 'faq:question_revealed',\n eventProps: {\n questionId: a.config.id,\n question: a.config.question,\n title: a.notify!.title,\n body: a.notify!.body,\n icon: a.notify!.icon,\n },\n }));\n },\n};\n\nexport default runtime;\n"],
5
- "mappings": "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",
4
+ "sourcesContent": ["/**\n * Adaptive FAQ - Action Executors\n *\n * Three executors that operate on the FAQStore:\n * - executeScrollToFaq: scroll to a FAQ item and optionally expand it\n * - executeToggleFaqItem: open / close / toggle a FAQ item\n * - executeUpdateFaq: add, remove, reorder, or replace FAQ items\n */\n\nimport type { FAQStore } from './state';\nimport type {\n ExecutorContext,\n ExecutorResult,\n FAQQuestionAction,\n ScrollToFaqAction,\n ToggleFaqItemAction,\n UpdateFaqAction,\n} from './types';\n\n// ============================================================================\n// Helpers\n// ============================================================================\n\n/**\n * Resolve a FAQ item by direct ID or by fuzzy question text match.\n * Throws if neither yields a result.\n */\nfunction resolveItem(store: FAQStore, itemId?: string, itemQuestion?: string): FAQQuestionAction {\n if (itemId) {\n const found = store.getState().items.find((i) => i.config.id === itemId);\n if (found) return found;\n }\n\n if (itemQuestion) {\n const found = store.findByQuestion(itemQuestion);\n if (found) return found;\n }\n\n throw new Error('FAQ item not found');\n}\n\n// ============================================================================\n// executeScrollToFaq\n// ============================================================================\n\n/**\n * Scroll to a FAQ item in the DOM and optionally expand it.\n *\n * Looks up the item by `itemId` or `itemQuestion`, scrolls the matching\n * `[data-faq-item-id]` element into view, and expands it unless\n * `expand` is explicitly set to `false`.\n */\nexport async function executeScrollToFaq(\n action: ScrollToFaqAction,\n context: ExecutorContext,\n store: FAQStore\n): Promise<ExecutorResult> {\n const item = resolveItem(store, action.itemId, action.itemQuestion);\n const { id } = item.config;\n\n // Expand the item unless explicitly told not to\n if (action.expand !== false) {\n store.expand(id);\n }\n\n // Scroll the DOM element into view (may be absent in test environments)\n const el = document.querySelector(`[data-faq-item-id=\"${id}\"]`);\n if (el) {\n el.scrollIntoView({\n behavior: action.behavior ?? 'smooth',\n });\n }\n\n // Publish analytics event\n context.publishEvent('faq:scroll_to', { itemId: id });\n\n return {\n cleanup: () => {\n // Optionally collapse on revert\n },\n };\n}\n\n// ============================================================================\n// executeToggleFaqItem\n// ============================================================================\n\n/**\n * Open, close, or toggle a FAQ item's expanded state.\n */\nexport async function executeToggleFaqItem(\n action: ToggleFaqItemAction,\n context: ExecutorContext,\n store: FAQStore\n): Promise<ExecutorResult> {\n const item = resolveItem(store, action.itemId, action.itemQuestion);\n const { id } = item.config;\n const desiredState = action.state ?? 'toggle';\n\n let newState: 'open' | 'closed';\n\n switch (desiredState) {\n case 'open':\n store.expand(id);\n newState = 'open';\n break;\n case 'closed':\n store.collapse(id);\n newState = 'closed';\n break;\n default: {\n const wasExpanded = store.getState().expandedItems.has(id);\n store.toggle(id);\n newState = wasExpanded ? 'closed' : 'open';\n break;\n }\n }\n\n context.publishEvent('faq:toggle', { itemId: id, newState });\n\n return {\n cleanup: () => {\n // Revert toggle on cleanup\n },\n };\n}\n\n// ============================================================================\n// executeUpdateFaq\n// ============================================================================\n\n/**\n * Add, remove, reorder, or replace FAQ items in the store.\n */\nexport async function executeUpdateFaq(\n action: UpdateFaqAction,\n context: ExecutorContext,\n store: FAQStore\n): Promise<ExecutorResult> {\n switch (action.operation) {\n case 'add': {\n const items = action.items ?? [];\n const position = action.position === 'prepend' ? 'prepend' : 'append';\n store.addItems(items, position);\n break;\n }\n\n case 'remove': {\n if (!action.itemId) {\n throw new Error('FAQ item not found');\n }\n // Verify the item exists before removing\n const exists = store.getState().items.some((i) => i.config.id === action.itemId);\n if (!exists) {\n throw new Error('FAQ item not found');\n }\n store.removeItem(action.itemId);\n break;\n }\n\n case 'reorder': {\n const order = action.order ?? [];\n store.reorderItems(order);\n break;\n }\n\n case 'replace': {\n const items = action.items ?? [];\n store.replaceItems(items);\n break;\n }\n }\n\n context.publishEvent('faq:update', { operation: action.operation });\n\n return {\n cleanup: () => {\n // Could snapshot previous state for undo\n },\n };\n}\n\n// ============================================================================\n// Executor Definitions for Registration\n// ============================================================================\n\n/**\n * All executors provided by adaptive-faq.\n * These are registered with the runtime's ExecutorRegistry.\n */\nexport const executorDefinitions = [\n { kind: 'faq:scroll_to', executor: executeScrollToFaq },\n { kind: 'faq:toggle_item', executor: executeToggleFaqItem },\n { kind: 'faq:update', executor: executeUpdateFaq },\n] as const;\n", "/**\n * Adaptive FAQ - FAQWidgetLit\n *\n * Lit web component equivalent of FAQWidget.tsx.\n * Renders a collapsible Q&A accordion with search, category grouping,\n * feedback, and markdown rendering \u2014 all as a custom element with no\n * Shadow DOM (light DOM via createRenderRoot).\n *\n * Tag name: <syntro-faq-accordion>\n *\n * Decorator-free: uses `static override properties` (tsconfig has no\n * experimentalDecorators).\n */\n\nimport { purple } from '@syntro/design-system/tokens';\nimport { html, LitElement, nothing } from 'lit';\nimport { styleMap } from 'lit/directives/style-map.js';\nimport { unsafeHTML } from 'lit/directives/unsafe-html.js';\nimport { getAnswerText, renderAnswerHtml } from './answerRendering';\nimport { baseStyles, themeStyles } from './faq-styles';\nimport type { FAQWidgetRuntime } from './faq-types';\nimport type {\n FAQAnswer,\n FAQConfig,\n FAQQuestionAction,\n FeedbackConfig,\n FeedbackValue,\n} from './types';\n\n// ============================================================================\n// Utility \u2014 styleMap accepts Record<string, string | number | undefined>\n// but its TypeScript signature is overly narrow in some Lit versions.\n// Cast through unknown to avoid false positives when style values include\n// numeric CSS properties (fontWeight, lineHeight, etc.).\n// ============================================================================\n\nfunction sm(styles: Record<string, unknown>): Record<string, string> {\n return styles as unknown as Record<string, string>;\n}\n\nfunction resolveFeedbackConfig(\n feedback: boolean | FeedbackConfig | undefined\n): FeedbackConfig | null {\n if (!feedback) return null;\n if (feedback === true) return { style: 'thumbs' };\n return feedback;\n}\n\nfunction getFeedbackPrompt(feedbackConfig: FeedbackConfig): string {\n return feedbackConfig.prompt ?? 'Was this helpful?';\n}\n\n/**\n * Small deterministic string hash (djb2, base36) for content-derived atomic\n * FAQ row ids \u2014 stable per question across re-mounts so expand/feedback state\n * keyed by id sticks to the right row even if the list reorders.\n */\nfunction hashFaqId(text: string): string {\n let h = 5381;\n for (let i = 0; i < text.length; i++) {\n h = (Math.imul(h, 33) ^ text.charCodeAt(i)) >>> 0;\n }\n return h.toString(36);\n}\n\nfunction resolveTheme(theme: FAQConfig['theme'] | undefined): 'light' | 'dark' {\n if (theme && theme !== 'auto') return theme;\n if (typeof window !== 'undefined') {\n return window.matchMedia?.('(prefers-color-scheme: dark)').matches ? 'dark' : 'light';\n }\n return 'light';\n}\n\n// ============================================================================\n// FAQAccordionElement \u2014 Lit element\n// ============================================================================\n\n/**\n * <syntro-faq-accordion> \u2014 light-DOM Lit web component.\n *\n * Set properties imperatively (no attribute serialisation for objects):\n * el.faqConfig = { expandBehavior: 'single', ... };\n * el.runtime = runtimeInstance;\n * el.instanceId = 'my-faq';\n */\nexport class FAQAccordionElement extends LitElement {\n // -----------------------------------------------------------------------\n // Reactive properties (no decorators \u2014 tsconfig forbids experimentalDecorators)\n // -----------------------------------------------------------------------\n\n static override properties = {\n // Public API \u2014 set from the outside\n faqConfig: { attribute: false },\n runtime: { attribute: false },\n instanceId: { type: String },\n\n // Internal reactive state (prefixed with _ to signal \"private\")\n // _openId: currently-open question id for the master\u2192detail takeover.\n // null = LIST view; a value = DETAIL view showing only that single Q&A.\n _openId: { state: true },\n _highlightId: { state: true },\n _searchQuery: { state: true },\n _feedbackState: { state: true },\n _hoveredId: { state: true },\n };\n\n // -----------------------------------------------------------------------\n // Property declarations\n // -----------------------------------------------------------------------\n\n faqConfig: FAQConfig = {\n expandBehavior: 'single',\n searchable: false,\n theme: 'auto',\n actions: [],\n };\n\n runtime: FAQWidgetRuntime | null = null;\n\n instanceId: string = 'faq-widget';\n\n // Internal state\n // The currently-open question id (null = list view, value = detail view).\n // The master\u2192detail takeover swaps the whole widget to a single Q&A so a\n // long answer never overflows the bounded velvet tile.\n _openId: string | null = null;\n _highlightId: string | null = null;\n _searchQuery: string = '';\n _feedbackState: Map<string, FeedbackValue> = new Map();\n _hoveredId: string | null = null;\n\n // Subscription cleanup handles\n private _unsubContext: (() => void) | null = null;\n private _unsubAccumulator: (() => void) | null = null;\n private _unsubCta: (() => void) | null = null;\n private _unsubDeepLink: (() => void) | null = null;\n private _unsubSessionMetrics: (() => void) | null = null;\n private _highlightTimer: ReturnType<typeof setTimeout> | null = null;\n\n // Compositional-child wiring \u2014 faq:question items the LLM mounts into this\n // accordion's tile arrive as `element.compositional_append` events (see\n // adaptive-chatbot's ItemHandler). Without this subscription the questions\n // are published into the void and the accordion renders empty.\n private _unsubCompositional: (() => void) | null = null;\n private _tileId: string | null = null;\n /** Instance ids already appended via the compositional bus \u2014 dedups\n * the subscribe-then-replay path (and re-subscribes on runtime change). */\n private _llmAppendedIds: Set<string> = new Set();\n\n // -----------------------------------------------------------------------\n // Light DOM \u2014 no Shadow DOM so CSS variables from the host page apply\n // -----------------------------------------------------------------------\n\n override createRenderRoot() {\n return this;\n }\n\n // -----------------------------------------------------------------------\n // Lifecycle\n // -----------------------------------------------------------------------\n\n override connectedCallback() {\n super.connectedCallback();\n this._subscribeAll();\n }\n\n override disconnectedCallback() {\n super.disconnectedCallback();\n this._unsubscribeAll();\n if (this._highlightTimer !== null) {\n clearTimeout(this._highlightTimer);\n this._highlightTimer = null;\n }\n }\n\n // Re-subscribe when runtime changes (property may be set after connectedCallback)\n override updated(changedProps: Map<string, unknown>) {\n if (changedProps.has('runtime')) {\n this._unsubscribeAll();\n this._subscribeAll();\n }\n }\n\n // -----------------------------------------------------------------------\n // Subscription management\n // -----------------------------------------------------------------------\n\n private _subscribeAll() {\n if (!this.runtime) return;\n\n // Context changes \u2192 force re-render\n this._unsubContext = this.runtime.context.subscribe(() => {\n this.requestUpdate();\n });\n\n // Accumulator changes \u2192 force re-render (for event_count triggerWhen)\n if (this.runtime.accumulator?.subscribe) {\n this._unsubAccumulator = this.runtime.accumulator.subscribe(() => {\n this.requestUpdate();\n });\n }\n\n // Session metric changes \u2192 force re-render (for session_metric triggerWhen)\n if (this.runtime.sessionMetrics?.subscribe) {\n this._unsubSessionMetrics = this.runtime.sessionMetrics.subscribe(() => {\n this.requestUpdate();\n });\n }\n\n // faq:open:* events from overlay CTA clicks\n if (this.runtime.events.subscribe) {\n // Check EventBus history for pending faq:open events\n if (this.runtime.events.getRecent) {\n const recentEvents = this.runtime.events.getRecent(\n { patterns: ['^action\\\\.tooltip_cta_clicked$', '^action\\\\.modal_cta_clicked$'] },\n 10\n );\n const pendingEvent = recentEvents\n .filter((e) => {\n const actionId = e.props?.actionId;\n return typeof actionId === 'string' && actionId.startsWith('faq:open:');\n })\n .pop();\n\n if (pendingEvent && Date.now() - pendingEvent.ts < 10000) {\n const questionId = (pendingEvent.props!.actionId as string).replace('faq:open:', '');\n // Takeover: put the widget into DETAIL view for that question\n // (previously this expanded the row inline).\n this._openId = questionId;\n }\n }\n\n this._unsubCta = this.runtime.events.subscribe(\n { patterns: ['^action\\\\.tooltip_cta_clicked$', '^action\\\\.modal_cta_clicked$'] },\n (event) => {\n // Same staleness guard as the history scan above: some EventBus\n // implementations replay recent history into new subscribers. Without\n // this guard the history scan AND this live handler both fire for the\n // same old event \u2014 a spurious second `canvas.requestOpen`. Skip any\n // event older than ~10s (a fresh click always has ts\u2248now).\n const ts = (event as { ts?: number }).ts;\n if (typeof ts === 'number' && Date.now() - ts >= 10000) return;\n const actionId = event.props?.actionId;\n if (typeof actionId !== 'string' || !actionId.startsWith('faq:open:')) return;\n const questionId = actionId.replace('faq:open:', '');\n // Takeover: open the question's detail view instead of inline expand.\n this._openId = questionId;\n this.runtime?.events.publish('canvas.requestOpen');\n }\n );\n }\n\n // notification.deep_link events\n if (this.runtime.events.subscribe) {\n const handleDeepLink = (event: { name: string; props?: Record<string, unknown> }) => {\n const tileId = event.props?.tileId as string | undefined;\n const itemId = event.props?.itemId as string | undefined;\n if (tileId !== this.instanceId) return;\n if (!itemId) return;\n\n // Takeover: open the question's detail view (previously inline expand).\n this._openId = itemId;\n this._highlightId = itemId;\n\n if (this._highlightTimer !== null) clearTimeout(this._highlightTimer);\n this._highlightTimer = setTimeout(() => {\n this._highlightId = null;\n this._highlightTimer = null;\n }, 1500);\n };\n\n // Check recent events (may have fired before widget mounted)\n if (this.runtime.events.getRecent) {\n const recent = this.runtime.events.getRecent({ names: ['notification.deep_link'] }, 5);\n const pending = recent\n .filter((e) => (e.props?.tileId as string) === this.instanceId && e.props?.itemId)\n .pop();\n if (pending && Date.now() - pending.ts < 10000) {\n handleDeepLink(pending);\n }\n }\n\n this._unsubDeepLink = this.runtime.events.subscribe(\n { names: ['notification.deep_link'] },\n (event) => {\n // Mirror the history-scan staleness guard: skip replayed events older\n // than ~10s so a bus that replays history into new subscribers doesn't\n // double-handle the same deep link (history scan + live handler).\n const ts = (event as { ts?: number }).ts;\n if (typeof ts === 'number' && Date.now() - ts >= 10000) return;\n handleDeepLink(event);\n }\n );\n }\n\n // Compositional children: faq:question items mounted into this\n // accordion's tile. The ItemHandler publishes one event per kind-\n // agnostic item mount; we filter to our tile and route into\n // `faqConfig.actions`. Mirrors AdaptiveChipsStrip's CompositionalContainer.\n this._subscribeCompositional();\n }\n\n /**\n * Subscribe to `element.compositional_*` events targeting this accordion's\n * tile, and ask the element store to replay any items it already holds for\n * us (covers the case where the accordion mounts AFTER the item did \u2014 the\n * inline-slot hydration race that otherwise silently drops the question).\n */\n private _subscribeCompositional() {\n const bus = this.runtime?.events;\n if (!bus?.subscribe) return;\n this._tileId = this._resolveTileId();\n if (!this._tileId) return;\n const tileId = this._tileId;\n this._unsubCompositional = bus.subscribe((event) => {\n const props = event.props ?? {};\n if (props.tile_id !== tileId) return;\n const instanceId = String(props.instance_id ?? '');\n if (event.name === 'element.compositional_append') {\n this._insertItem(\n instanceId,\n props.item as FAQQuestionAction,\n (props.position as 'append' | 'prepend') ?? 'append'\n );\n } else if (event.name === 'element.compositional_patch') {\n this._patchItem(instanceId, props.item as FAQQuestionAction);\n } else if (event.name === 'element.compositional_remove') {\n this._removeItem(instanceId);\n }\n });\n bus.publish('element.compositional_replay_request', { tile_id: tileId });\n }\n\n /** Tile id for compositional filtering: the enclosing tile card's\n * `data-tile-id` (set by SyntroTileCard), falling back to `instanceId`\n * when the accordion is mounted outside a tile card. */\n private _resolveTileId(): string | null {\n const anchor = this.closest<HTMLElement>('[data-tile-id]');\n const fromDom = anchor?.getAttribute('data-tile-id');\n if (fromDom) return fromDom;\n return this.instanceId && this.instanceId !== 'faq-widget' ? this.instanceId : null;\n }\n\n /** Append (or prepend) a faq:question the LLM mounted. The wire shape is a\n * fully-formed `{kind, config}` envelope, so we store it verbatim. */\n private _insertItem(\n instanceId: string,\n item: FAQQuestionAction,\n position: 'append' | 'prepend'\n ): void {\n if (!instanceId || !item?.config?.id) return;\n if (this._llmAppendedIds.has(instanceId)) return; // dedup replay / re-subscribe\n this._llmAppendedIds.add(instanceId);\n const actions = this.faqConfig.actions ?? [];\n const next = position === 'prepend' ? [item, ...actions] : [...actions, item];\n // Reassign so Lit sees the change (faqConfig is attribute:false).\n this.faqConfig = { ...this.faqConfig, actions: next };\n }\n\n /** Replace an existing question's content (full replacement). */\n private _patchItem(instanceId: string, item: FAQQuestionAction): void {\n if (!instanceId || !item?.config) return;\n const actions = this.faqConfig.actions ?? [];\n const idx = actions.findIndex((a) => a.config.id === instanceId);\n if (idx < 0) return;\n const next = [...actions];\n next[idx] = item;\n // If the patch changes the open question's id, our `_openId` would point at\n // a gone id and the detail view would fall back to the list. Re-point it at\n // the replacement's new id so the open question stays open through a patch.\n if (this._openId === instanceId && item.config.id !== instanceId) {\n this._openId = item.config.id;\n }\n this.faqConfig = { ...this.faqConfig, actions: next };\n }\n\n /** Remove a question by instance id. */\n private _removeItem(instanceId: string): void {\n if (!instanceId) return;\n const actions = this.faqConfig.actions ?? [];\n const next = actions.filter((a) => a.config.id !== instanceId);\n if (next.length === actions.length) return;\n this._llmAppendedIds.delete(instanceId);\n // Removing the currently-open question would leave `_openId` pointing at a\n // gone id. Return to the list view instead of resolving to an empty detail.\n if (this._openId === instanceId) this._openId = null;\n this.faqConfig = { ...this.faqConfig, actions: next };\n }\n\n private _unsubscribeAll() {\n this._unsubContext?.();\n this._unsubAccumulator?.();\n this._unsubSessionMetrics?.();\n this._unsubCta?.();\n this._unsubDeepLink?.();\n this._unsubCompositional?.();\n this._unsubContext = null;\n this._unsubAccumulator = null;\n this._unsubSessionMetrics = null;\n this._unsubCta = null;\n this._unsubDeepLink = null;\n this._unsubCompositional = null;\n }\n\n // -----------------------------------------------------------------------\n // Handlers\n // -----------------------------------------------------------------------\n\n /**\n * Master\u2192detail takeover: tapping a list row opens its single-Q&A detail\n * view (the whole widget swaps), so a long answer fills \u2014 and never\n * overflows \u2014 the bounded velvet tile. There is no simultaneous multi-expand;\n * one question owns the tile at a time.\n */\n private _handleOpen(id: string) {\n this._openId = id;\n\n this.runtime?.events.publish('faq:toggled', {\n instanceId: this.instanceId,\n questionId: id,\n expanded: true,\n timestamp: Date.now(),\n });\n }\n\n /** Back affordance: return from the detail view to the full list. */\n private _handleBack() {\n const id = this._openId;\n this._openId = null;\n\n if (id !== null) {\n this.runtime?.events.publish('faq:toggled', {\n instanceId: this.instanceId,\n questionId: id,\n expanded: false,\n timestamp: Date.now(),\n });\n }\n }\n\n private _handleFeedback(itemId: string, question: string, value: FeedbackValue) {\n const next = new Map(this._feedbackState);\n next.set(itemId, value);\n this._feedbackState = next;\n\n this.runtime?.events.publish('faq:feedback', { itemId, question, value });\n }\n\n // -----------------------------------------------------------------------\n // Computed helpers\n // -----------------------------------------------------------------------\n\n /**\n * Unified render list. Merges compositionally-appended rows\n * (`faqConfig.actions`, the container-then-stream path) with atomically\n * authored rows (`faqConfig.questions`, the struct_list path) normalized\n * into the same `FAQQuestionAction` shape. The atomic path is how the LLM\n * mounts a complete FAQ in one call \u2014 so it renders whole, never empty.\n */\n private _allQuestions(): FAQQuestionAction[] {\n const compositional = this.faqConfig.actions ?? [];\n // Content-derived id (not positional). Expand/feedback state is keyed by id;\n // if the LLM re-mounts the FAQ with a reordered or shortened list, a\n // positional `atomic-${i}` would re-point that state at a different\n // question. Hashing the question text keeps the id stable per question\n // across re-mounts. A `-N` suffix disambiguates same-text rows (including\n // empty strings, which all hash to the same value) so they never share\n // expand/feedback state \u2014 stable as long as their relative order is.\n const seen = new Map<string, number>();\n const atomic = (this.faqConfig.questions ?? []).map((q): FAQQuestionAction => {\n let id = `atomic-${hashFaqId(q.question)}`;\n const dup = seen.get(id) ?? 0;\n seen.set(id, dup + 1);\n if (dup > 0) id = `${id}-${dup}`;\n return {\n kind: 'faq:question',\n config: {\n id,\n question: q.question,\n answer: q.answer,\n category: q.category,\n },\n };\n });\n return [...atomic, ...compositional];\n }\n\n private _visibleQuestions(): FAQQuestionAction[] {\n return this._allQuestions().filter((q) => {\n if (!q.triggerWhen) return true;\n if (!this.runtime) return true;\n const result = this.runtime.evaluateSync<boolean>(q.triggerWhen);\n return result.value;\n });\n }\n\n private _orderedQuestions(visible: FAQQuestionAction[]): FAQQuestionAction[] {\n if (this.faqConfig.ordering === 'priority') {\n return [...visible].sort((a, b) => (b.config.priority ?? 0) - (a.config.priority ?? 0));\n }\n return visible;\n }\n\n private _filteredQuestions(ordered: FAQQuestionAction[]): FAQQuestionAction[] {\n const q = this._searchQuery.trim().toLowerCase();\n if (!this.faqConfig.searchable || !q) return ordered;\n return ordered.filter(\n (item) =>\n item.config.question.toLowerCase().includes(q) ||\n getAnswerText(item.config.answer).toLowerCase().includes(q) ||\n item.config.category?.toLowerCase().includes(q)\n );\n }\n\n private _categoryGroups(\n filtered: FAQQuestionAction[]\n ): Map<string | undefined, FAQQuestionAction[]> {\n const groups = new Map<string | undefined, FAQQuestionAction[]>();\n for (const item of filtered) {\n const cat = item.config.category;\n if (!groups.has(cat)) groups.set(cat, []);\n groups.get(cat)!.push(item);\n }\n return groups;\n }\n\n // -----------------------------------------------------------------------\n // Render helpers\n // -----------------------------------------------------------------------\n\n private _renderAnswer(answer: FAQAnswer) {\n const html_str = renderAnswerHtml(answer);\n return html`<div style=\"margin:0\" data-faq-markdown=\"\">${unsafeHTML(html_str)}</div>`;\n }\n\n private _renderFeedback(\n item: FAQQuestionAction,\n feedbackConfig: FeedbackConfig,\n feedbackValue: FeedbackValue | undefined,\n theme: 'light' | 'dark'\n ) {\n const colors = themeStyles[theme];\n const feedbackStyle = { ...baseStyles.feedback, ...colors.feedbackPrompt };\n\n return html`\n <div style=${styleMap(sm(feedbackStyle))}>\n <span>${getFeedbackPrompt(feedbackConfig)}</span>\n <button\n type=\"button\"\n style=${styleMap(\n sm({\n ...baseStyles.feedbackButton,\n ...(feedbackValue === 'up' ? baseStyles.feedbackButtonSelected : {}),\n })\n )}\n aria-label=\"Thumbs up\"\n @click=${() => this._handleFeedback(item.config.id, item.config.question, 'up')}\n >\\uD83D\\uDC4D</button>\n <button\n type=\"button\"\n style=${styleMap(\n sm({\n ...baseStyles.feedbackButton,\n ...(feedbackValue === 'down' ? baseStyles.feedbackButtonSelected : {}),\n })\n )}\n aria-label=\"Thumbs down\"\n @click=${() => this._handleFeedback(item.config.id, item.config.question, 'down')}\n >\\uD83D\\uDC4E</button>\n </div>\n `;\n }\n\n /**\n * LIST-view row. A tappable question with its chevron \\u2014 but NO inline answer\n * body. Tapping it takes over the tile with the question's detail view (see\n * {@link _renderDetail}). Keeps the per-row look/markers/highlight from the\n * old accordion minus the inline-expanded answer that overflowed the tile.\n */\n private _renderItem(item: FAQQuestionAction, isLast: boolean, theme: 'light' | 'dark') {\n const colors = themeStyles[theme];\n const isHighlighted = this._highlightId === item.config.id;\n const isHovered = this._hoveredId === item.config.id;\n\n const itemStyle = {\n ...baseStyles.item,\n ...colors.item,\n ...(isHighlighted\n ? {\n boxShadow: `0 0 0 2px ${purple[4]}, 0 0 12px rgba(106, 89, 206, 0.4)`,\n transition: 'box-shadow 0.3s ease',\n }\n : {}),\n ...(!isLast ? { borderBottom: 'var(--sc-content-item-divider, none)' } : {}),\n };\n\n const questionStyle = {\n ...baseStyles.question,\n ...colors.question,\n ...(isHovered ? colors.questionHover : {}),\n };\n\n const chevronStyle = {\n ...baseStyles.chevron,\n transform: 'rotate(0deg)',\n };\n\n return html`\n <div\n style=${styleMap(sm(itemStyle))}\n data-faq-item-id=${item.config.id}\n >\n <button\n type=\"button\"\n style=${styleMap(sm(questionStyle))}\n aria-expanded=${false}\n @click=${() => this._handleOpen(item.config.id)}\n @mouseenter=${() => {\n this._hoveredId = item.config.id;\n }}\n @mouseleave=${() => {\n this._hoveredId = null;\n }}\n >\n <span>${item.config.question}</span>\n <span style=${styleMap(sm(chevronStyle))}>\\u203A</span>\n </button>\n </div>\n `;\n }\n\n private _renderItems(items: FAQQuestionAction[], theme: 'light' | 'dark') {\n return items.map((item, index) => this._renderItem(item, index === items.length - 1, theme));\n }\n\n /**\n * DETAIL view \\u2014 the master\\u2192detail takeover. Renders ONLY the open question:\n * a back affordance, the question prominently, and its full answer via the\n * SAME {@link _renderAnswer}/`renderAnswerHtml` path (all answer formats still\n * work). The answer area scrolls if extremely long, so a single answer fills\n * the bounded velvet tile and never pushes content past the `overflow:hidden`\n * clip.\n */\n private _renderDetail(\n item: FAQQuestionAction,\n theme: 'light' | 'dark',\n feedbackConfig: FeedbackConfig | null\n ) {\n const colors = themeStyles[theme];\n\n const backStyle = {\n ...baseStyles.detailBack,\n ...colors.question,\n };\n const detailQuestionStyle = {\n ...baseStyles.detailQuestion,\n ...colors.question,\n };\n const detailAnswerStyle = {\n ...baseStyles.detailAnswer,\n ...colors.answer,\n };\n\n return html`\n <div style=${styleMap(sm(baseStyles.detail))} data-faq-detail=${item.config.id}>\n <button\n type=\"button\"\n style=${styleMap(sm(backStyle))}\n data-faq-back=\"\"\n aria-label=\"Back to questions\"\n @click=${() => this._handleBack()}\n >\n \\u2039 Back to questions\n </button>\n\n <div style=${styleMap(sm(detailQuestionStyle))}>${item.config.question}</div>\n\n <div style=${styleMap(sm(detailAnswerStyle))} aria-hidden=${false}>\n ${this._renderAnswer(item.config.answer)}\n ${\n feedbackConfig\n ? this._renderFeedback(\n item,\n feedbackConfig,\n this._feedbackState.get(item.config.id),\n theme\n )\n : nothing\n }\n </div>\n </div>\n `;\n }\n\n // -----------------------------------------------------------------------\n // Render\n // -----------------------------------------------------------------------\n\n override render() {\n const theme = resolveTheme(this.faqConfig.theme);\n const colors = themeStyles[theme];\n const feedbackConfig = resolveFeedbackConfig(this.faqConfig.feedback);\n\n const visible = this._visibleQuestions();\n const ordered = this._orderedQuestions(visible);\n const filtered = this._filteredQuestions(ordered);\n const hasCategories = filtered.some((q) => q.config.category);\n const groups = hasCategories ? this._categoryGroups(filtered) : null;\n\n const containerStyle = {\n ...baseStyles.container,\n ...colors.container,\n };\n\n const emptyStateStyle = {\n ...baseStyles.emptyState,\n ...colors.emptyState,\n };\n\n const categoryHeaderStyle = {\n ...baseStyles.categoryHeader,\n ...colors.categoryHeader,\n };\n\n const searchInputStyle = {\n ...baseStyles.searchInput,\n ...colors.searchInput,\n };\n\n // Empty state \u2014 no visible questions at all.\n //\n // A runtime-backed FAQ is a compositional container: its `faq:question`\n // items stream in as `element.compositional_append` events after mount\n // (and a replay request). Rendering the \"all set\" reassurance box while\n // we're still empty flashes an empty shell on every mount \u2014 and leaves\n // an orphaned empty box if the agent mounted a container it never filled\n // (the recurring \"empty FAQ showed up then disappeared\" bug). Render\n // nothing until the first question lands. The reassurance copy is only\n // for a standalone (runtime-less) FAQ configured directly with no items.\n if (visible.length === 0) {\n if (this.runtime) return nothing;\n return html`\n <div\n style=${styleMap(sm(containerStyle))}\n data-adaptive-id=${this.instanceId}\n data-adaptive-type=\"adaptive-faq\"\n >\n <div style=${styleMap(sm(emptyStateStyle))}>\n You're all set for now! We'll surface answers here when they're relevant to what\n you're doing.\n </div>\n </div>\n `;\n }\n\n // DETAIL view (master\u2192detail takeover). When a question is open, the whole\n // widget swaps to that single Q&A so it fills \u2014 and never overflows \u2014 the\n // bounded velvet tile. We resolve `_openId` against the *visible/ordered*\n // list (`ordered`), NOT the search-filtered list (`filtered`) \u2014 search is a\n // list-view concern only, so a `faq:open` for a question that doesn't match\n // an active `_searchQuery` must still open its detail. A genuinely stale id\n // (e.g. a question that gated out via triggerWhen, or was removed) is absent\n // from `ordered` and falls back to the list instead of a blank detail.\n if (this._openId !== null) {\n const openItem = ordered.find((q) => q.config.id === this._openId);\n if (openItem) {\n return html`\n <div\n style=${styleMap(sm(containerStyle))}\n data-adaptive-id=${this.instanceId}\n data-adaptive-type=\"adaptive-faq\"\n >\n ${this._renderDetail(openItem, theme, feedbackConfig)}\n </div>\n `;\n }\n }\n\n return html`\n <div\n style=${styleMap(sm(containerStyle))}\n data-adaptive-id=${this.instanceId}\n data-adaptive-type=\"adaptive-faq\"\n >\n ${\n this.faqConfig.searchable\n ? html`\n <div style=${styleMap(sm(baseStyles.searchWrapper))}>\n <style>\n [data-adaptive-id=\"${this.instanceId}\"] input::placeholder {\n color: var(--sc-content-search-color, inherit);\n opacity: 0.7;\n }\n </style>\n <input\n type=\"text\"\n placeholder=\"Search questions...\"\n .value=${this._searchQuery}\n style=${styleMap(sm(searchInputStyle))}\n @input=${(e: InputEvent) => {\n this._searchQuery = (e.target as HTMLInputElement).value;\n }}\n />\n </div>\n `\n : nothing\n }\n\n <div style=${styleMap(sm(baseStyles.accordion))}>\n ${\n groups\n ? Array.from(groups.entries()).map(\n ([category, items]) => html`\n ${\n category\n ? html`\n <div\n style=${styleMap(sm(categoryHeaderStyle))}\n data-category-header=${category}\n >\n ${category}\n </div>\n `\n : nothing\n }\n ${this._renderItems(items, theme)}\n `\n )\n : this._renderItems(filtered, theme)\n }\n </div>\n\n ${\n this.faqConfig.searchable && filtered.length === 0 && this._searchQuery\n ? html`\n <div\n style=${styleMap(sm({ ...baseStyles.noResults, ...colors.emptyState }))}\n >\n No questions found matching &quot;${this._searchQuery}&quot;\n </div>\n `\n : nothing\n }\n </div>\n `;\n }\n}\n\n// ============================================================================\n// Custom element registration\n// ============================================================================\n\nif (!customElements.get('syntro-faq-accordion')) {\n customElements.define('syntro-faq-accordion', FAQAccordionElement);\n}\n\nexport default FAQAccordionElement;\n", "/**\n * Adaptive FAQ - Styles\n *\n * BaseStyles object (font, layout, colors, animations) and theme integration\n * for the FAQWidget component.\n */\n\nimport { purple, slateGrey } from '@syntro/design-system/tokens';\n\n// ============================================================================\n// Base Styles\n// ============================================================================\n\nexport const baseStyles = {\n container: {\n fontFamily: 'var(--sc-font-family, system-ui, -apple-system, sans-serif)',\n maxWidth: '800px',\n margin: '0 auto',\n },\n searchWrapper: {\n marginBottom: '8px',\n },\n searchInput: {\n width: '100%',\n padding: '12px 16px',\n borderRadius: '8px',\n fontSize: '14px',\n outline: 'none',\n transition: 'border-color 0.15s ease',\n backgroundColor: 'var(--sc-content-search-background)',\n color: 'var(--sc-content-search-color)',\n },\n accordion: {\n display: 'flex',\n flexDirection: 'column' as const,\n gap: 'var(--sc-content-item-gap, 6px)',\n },\n item: {\n borderRadius: 'var(--sc-content-item-border-radius, 10px)',\n border: 'var(--sc-content-item-border, 1px solid rgba(0, 0, 0, 0.08))',\n background: 'var(--sc-content-item-background, rgba(255, 255, 255, 0.5))',\n overflow: 'hidden',\n transition: 'box-shadow 0.15s ease',\n },\n question: {\n width: '100%',\n padding: 'var(--sc-content-item-padding, 12px 16px)',\n display: 'flex',\n alignItems: 'center',\n justifyContent: 'space-between',\n border: 'none',\n cursor: 'pointer',\n fontSize: 'var(--sc-content-item-font-size, 15px)',\n fontWeight: 500,\n textAlign: 'left' as const,\n transition: 'background-color 0.15s ease',\n },\n chevron: {\n fontSize: '20px',\n transition: 'transform 0.2s ease',\n color: 'var(--sc-content-chevron-color, currentColor)',\n },\n answer: {\n padding: 'var(--sc-content-body-padding, 0 16px 12px 16px)',\n fontSize: 'var(--sc-content-body-font-size, 14px)',\n lineHeight: 1.6,\n overflow: 'hidden',\n transition: 'max-height 0.2s ease, padding 0.2s ease',\n },\n category: {\n display: 'inline-block',\n fontSize: '11px',\n fontWeight: 600,\n textTransform: 'uppercase' as const,\n letterSpacing: '0.05em',\n padding: '4px 8px',\n borderRadius: '4px',\n marginBottom: '8px',\n },\n categoryHeader: {\n fontSize: 'var(--sc-content-category-font-size, 12px)',\n fontWeight: 700,\n textTransform: 'uppercase' as const,\n letterSpacing: '0.05em',\n padding: 'var(--sc-content-category-padding, 8px 4px 4px 4px)',\n marginTop: 'var(--sc-content-category-gap, 4px)',\n },\n feedback: {\n display: 'flex',\n alignItems: 'center',\n gap: '8px',\n marginTop: '12px',\n paddingTop: '10px',\n borderTop: '1px solid rgba(0, 0, 0, 0.08)',\n fontSize: '13px',\n },\n feedbackButton: {\n background: 'none',\n border: '1px solid transparent',\n cursor: 'pointer',\n fontSize: '16px',\n padding: '4px 8px',\n borderRadius: '4px',\n transition: 'background-color 0.15s ease, border-color 0.15s ease',\n },\n feedbackButtonSelected: {\n borderColor: 'rgba(0, 0, 0, 0.2)',\n backgroundColor: 'rgba(0, 0, 0, 0.04)',\n },\n // \u2500\u2500 Master\u2192detail takeover \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 // The detail view fills the tile; the answer area scrolls if extremely long\n // so a single answer never pushes content past the tile's overflow clip.\n detail: {\n display: 'flex',\n flexDirection: 'column' as const,\n gap: '12px',\n minHeight: '0',\n // Inset the master\u2192detail takeover to match the list questions' padding so\n // a single Q&A taking over the tile doesn't render flush to the edges.\n padding: 'var(--sc-content-item-padding, 12px 16px)',\n },\n detailBack: {\n display: 'inline-flex',\n alignItems: 'center',\n gap: '4px',\n alignSelf: 'flex-start',\n background: 'none',\n border: 'none',\n padding: '4px 0',\n cursor: 'pointer',\n fontSize: '13px',\n fontWeight: 600,\n opacity: 0.85,\n },\n detailQuestion: {\n fontSize: 'var(--sc-content-item-font-size, 16px)',\n fontWeight: 600,\n lineHeight: 1.4,\n },\n detailAnswer: {\n fontSize: 'var(--sc-content-body-font-size, 14px)',\n lineHeight: 1.6,\n overflowY: 'auto' as const,\n flex: '1 1 auto',\n minHeight: '0',\n },\n emptyState: {\n textAlign: 'center' as const,\n padding: '48px 24px',\n fontSize: '14px',\n },\n noResults: {\n textAlign: 'center' as const,\n padding: '32px 16px',\n fontSize: '14px',\n },\n} as const;\n\n// ============================================================================\n// Theme Styles\n// ============================================================================\n\nexport const themeStyles = {\n light: {\n container: {\n backgroundColor: 'transparent',\n color: 'inherit',\n },\n searchInput: {\n border: `1px solid ${slateGrey[11]}`,\n },\n item: {\n backgroundColor: 'var(--sc-content-background)',\n borderTop: 'var(--sc-content-border)',\n borderRight: 'var(--sc-content-border)',\n borderBottom: 'var(--sc-content-border)',\n borderLeft: 'var(--sc-content-border)',\n },\n itemExpanded: {\n boxShadow: '0 4px 12px rgba(0, 0, 0, 0.08)',\n },\n question: {\n backgroundColor: 'transparent',\n color: 'var(--sc-content-text-color)',\n },\n questionHover: {\n backgroundColor: 'var(--sc-content-background-hover)',\n },\n answer: {\n color: 'var(--sc-content-text-secondary-color)',\n },\n category: {\n backgroundColor: purple[8],\n color: purple[2],\n },\n categoryHeader: {\n color: slateGrey[7],\n },\n emptyState: {\n color: slateGrey[8],\n },\n feedbackPrompt: {\n color: slateGrey[7],\n },\n },\n dark: {\n container: {\n backgroundColor: 'transparent',\n color: 'inherit',\n },\n searchInput: {\n border: `1px solid ${slateGrey[5]}`,\n },\n item: {\n backgroundColor: 'var(--sc-content-background)',\n borderTop: 'var(--sc-content-border)',\n borderRight: 'var(--sc-content-border)',\n borderBottom: 'var(--sc-content-border)',\n borderLeft: 'var(--sc-content-border)',\n },\n itemExpanded: {\n boxShadow: '0 4px 12px rgba(0, 0, 0, 0.15)',\n },\n question: {\n backgroundColor: 'transparent',\n color: 'var(--sc-content-text-color)',\n },\n questionHover: {\n backgroundColor: 'var(--sc-content-background-hover)',\n },\n answer: {\n color: 'var(--sc-content-text-secondary-color)',\n },\n category: {\n backgroundColor: purple[0],\n color: purple[6],\n },\n categoryHeader: {\n color: slateGrey[8],\n },\n emptyState: {\n color: slateGrey[7],\n },\n feedbackPrompt: {\n color: slateGrey[8],\n },\n },\n};\n", "/**\n * Adaptive FAQ - Runtime Module\n *\n * Runtime manifest for the FAQ accordion adaptive.\n * Mounts the Lit web component <syntro-faq-accordion>.\n * Provides action executors and widget registration.\n */\n\nimport { type MountPlumbing, stripMountPlumbing } from '@syntrologie/sdk-contracts';\nimport { executorDefinitions } from './executors';\nimport './FAQWidgetLit'; // registers <syntro-faq-accordion> custom element\nimport type { FAQWidgetRuntime } from './faq-types';\nimport type { FAQConfig, FAQQuestionAction } from './types';\n\n// ============================================================================\n// Lit Mountable Widget\n// ============================================================================\n\nconst DEFAULT_FAQ_CONFIG: FAQConfig = {\n expandBehavior: 'single',\n searchable: false,\n theme: 'auto',\n actions: [],\n};\n\n/**\n * Mountable widget interface for <syntro-faq-accordion> (Lit web component).\n */\nexport const FAQWidgetLitMountable = {\n mount(\n container: HTMLElement,\n config?: (FAQConfig & MountPlumbing & { runtime?: FAQWidgetRuntime }) | null\n ) {\n const incoming = config ?? null;\n const stripped = stripMountPlumbing<FAQConfig & { runtime?: FAQWidgetRuntime }>(incoming);\n // stripMountPlumbing does NOT strip the non-canonical `runtime` consumer key\n // on this widget because `runtime` is a canonical plumbing key. Pull the\n // explicit references back out for the element wiring.\n const runtime = incoming?.runtime as FAQWidgetRuntime | undefined;\n const instanceId = incoming?.instanceId ?? 'faq-widget';\n const faqConfig: FAQConfig = incoming ? (stripped as FAQConfig) : { ...DEFAULT_FAQ_CONFIG };\n\n const el = document.createElement('syntro-faq-accordion') as HTMLElement & {\n faqConfig: FAQConfig;\n runtime: FAQWidgetRuntime | null;\n instanceId: string;\n };\n\n Object.assign(el, {\n faqConfig,\n runtime: runtime ?? null,\n instanceId,\n });\n\n container.appendChild(el);\n return () => el.remove();\n },\n};\n\n// ============================================================================\n// App Runtime Manifest\n// ============================================================================\n\n/**\n * Runtime manifest for adaptive-faq.\n *\n * Provides:\n * - FAQ action executors (scroll_to, toggle_item, update)\n * - Widget-based accordion using the Lit web component\n */\nexport const runtime = {\n id: 'adaptive-faq',\n version: '2.0.0',\n name: 'FAQ Accordion',\n description:\n 'Collapsible Q&A accordion with actions, rich content, feedback, and personalization',\n\n /**\n * Action executors for programmatic FAQ interaction.\n */\n executors: executorDefinitions,\n\n /**\n * Widget definitions for the runtime's WidgetRegistry.\n */\n widgets: [\n {\n id: 'adaptive-faq:accordion',\n component: FAQWidgetLitMountable,\n metadata: {\n name: 'FAQ Accordion',\n description: 'Collapsible Q&A accordion with search, categories, and feedback',\n icon: '\u2753',\n subtitle: 'Curated just for you.',\n },\n },\n ],\n\n /**\n * Extract notify watcher entries from tile config props.\n * The runtime evaluates these continuously (even with drawer closed)\n * and publishes faq:question_revealed when triggerWhen transitions false \u2192 true.\n */\n notifyWatchers(props: Record<string, unknown>) {\n const actions = (props.actions ?? []) as FAQQuestionAction[];\n return actions\n .filter((a) => a.notify && a.triggerWhen)\n .map((a) => ({\n id: `faq:${a.config.id}`,\n strategy: a.triggerWhen!,\n eventName: 'faq:question_revealed',\n eventProps: {\n questionId: a.config.id,\n question: a.config.question,\n title: a.notify!.title,\n body: a.notify!.body,\n icon: a.notify!.icon,\n },\n }));\n },\n};\n\nexport default runtime;\n"],
5
+ "mappings": "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",
6
6
  "names": ["runtime"]
7
7
  }
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@syntrologie/adapt-faq",
3
- "version": "2.8.0-canary.365",
3
+ "version": "2.8.0-canary.367",
4
4
  "description": "Adaptive FAQ - Collapsible Q&A accordion with per-item conditional visibility",
5
5
  "license": "Proprietary",
6
6
  "private": false,