@carbon/ai-chat 1.16.0-rc.0 → 1.16.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.
@@ -266,6 +266,17 @@ let ChatCustomElement = ChatCustomElement_1 = class ChatCustomElement extends Fl
266
266
  this._pluginSlotNames = [ ...this._pluginSlotNames, detail.slotName ];
267
267
  }
268
268
  event.preventDefault();
269
+ if (detail.element) {
270
+ const element = detail.element;
271
+ element.setAttribute("slot", detail.slotName);
272
+ if (!detail.isInline) {
273
+ element.style.marginBlockStart = "1rem";
274
+ }
275
+ if (element.parentElement !== this) {
276
+ this.appendChild(element);
277
+ }
278
+ return;
279
+ }
269
280
  let host = this._pluginHosts.get(detail.slotName);
270
281
  if (!host) {
271
282
  host = document.createElement(detail.isInline ? "span" : "div");
@@ -276,8 +287,8 @@ let ChatCustomElement = ChatCustomElement_1 = class ChatCustomElement extends Fl
276
287
  this._pluginHosts.set(detail.slotName, host);
277
288
  this.appendChild(host);
278
289
  }
279
- if (host.innerHTML !== detail.html) {
280
- host.innerHTML = detail.html;
290
+ if (host.innerHTML !== (detail.html ?? "")) {
291
+ host.innerHTML = detail.html ?? "";
281
292
  }
282
293
  };
283
294
  this.handlePluginHostUpdate = event => {
@@ -1 +1 @@
1
- {"version":3,"file":"index.js","sources":["../../../../../../src/web-components/cds-aichat-custom-element/index.ts"],"sourcesContent":["/*\n * Copyright IBM Corp. 2025, 2026\n *\n * This source code is licensed under the Apache-2.0 license found in the\n * LICENSE file in the root directory of this source tree.\n *\n * @license\n */\n\n// Ensure the container custom element is registered whenever the\n// custom element module is imported by re-exporting its exports.\n// This prevents bundlers (and our own multi-entry Rollup build)\n// from pruning the side-effect-only import.\nexport { default as __cds_aichat_container_register } from \"../cds-aichat-container\";\nimport \"../cds-aichat-container\";\n\nimport { html } from \"lit\";\nimport { property, state } from \"lit/decorators.js\";\n\nimport { carbonElement } from \"@carbon/ai-chat-components/es/globals/decorators/index.js\";\nimport { PublicConfig } from \"../../types/config/PublicConfig\";\nimport { FlattenedConfigElement } from \"../shared/FlattenedConfigElement\";\nimport { ChatInstance } from \"../../types/instance/ChatInstance\";\nimport {\n BusEventChunkUserDefinedResponse,\n BusEventCustomFooterSlot,\n BusEventType,\n BusEventUserDefinedResponse,\n BusEventViewChange,\n BusEventViewPreChange,\n} from \"../../types/events/eventBusTypes\";\nimport type {\n WCMarkdown,\n WCRenderCustomMessageFooter,\n WCRenderUserDefinedResponse,\n} from \"../../types/component/ChatContainer\";\n\n/**\n * cds-aichat-custom-element will is a pass through to cds-aichat-container. It takes any user_defined and writeable element\n * slotted content and forwards it to cds-aichat-container. It also will setup the custom element with a default viewChange\n * pattern (e.g. hiding and showing the custom element when the chat should be open/closed) if a onViewChange property is not\n * defined. Finally, it registers the custom element with cds-aichat-container so a default \"floating\" element will not be created.\n *\n * The custom element should be sized using external CSS. When hidden, the 'cds-aichat--hidden' class is added to set dimensions to 0x0.\n */\n@carbonElement(\"cds-aichat-custom-element\")\nclass ChatCustomElement extends FlattenedConfigElement {\n /**\n * Shared stylesheet for hiding styles.\n */\n private static hideSheet = new CSSStyleSheet();\n static {\n // Hide styles that override any external sizing. `replaceSync` is absent\n // in non-browser environments (e.g. the jsdom-based test environment), so\n // skip styling there rather than throwing at module-evaluation time.\n ChatCustomElement.hideSheet.replaceSync?.(`\n :host {\n display: block;\n }\n :host(.cds-aichat--hidden) {\n width: 0 !important;\n height: 0 !important;\n min-width: 0 !important;\n min-height: 0 !important;\n max-width: 0 !important;\n max-height: 0 !important;\n inline-size: 0 !important;\n block-size: 0 !important;\n min-inline-size: 0 !important;\n min-block-size: 0 !important;\n max-inline-size: 0 !important;\n max-block-size: 0 !important;\n overflow: hidden !important;\n display: block !important;\n }\n `);\n }\n\n /**\n * Adopt our stylesheet into every shadowRoot.\n */\n protected createRenderRoot(): ShadowRoot {\n // Lits default createRenderRoot actually returns a ShadowRoot\n const root = super.createRenderRoot() as ShadowRoot;\n\n // now TS knows root.adoptedStyleSheets exists\n root.adoptedStyleSheets = [\n ...root.adoptedStyleSheets,\n ChatCustomElement.hideSheet,\n ];\n return root;\n }\n\n /**\n * This function is called before the render function of Carbon AI Chat is called. This function can return a Promise\n * which will cause Carbon AI Chat to wait for it before rendering.\n *\n * Use it to capture the {@link ChatInstance} so you can call instance methods later.\n *\n * @example\n * ```ts\n * const onBeforeRender = (instance: ChatInstance) => {\n * this.instance = instance;\n * };\n * // <cds-aichat-custom-element .onBeforeRender=${onBeforeRender}></cds-aichat-custom-element>\n * ```\n */\n @property({ attribute: false })\n onBeforeRender?: (instance: ChatInstance) => Promise<void> | void;\n\n /**\n * This function is called after the render function of Carbon AI Chat is called.\n *\n * Like `onBeforeRender`, it receives the {@link ChatInstance}; use it when you need the instance only after the\n * first render has completed.\n */\n @property({ attribute: false })\n onAfterRender?: (instance: ChatInstance) => Promise<void> | void;\n\n /**\n * Called before a view change (chat opening/closing). The chat will hide the chat shell inside your custom element\n * to prevent invisible keyboard stops when the view change is complete.\n *\n * Use this callback to update your CSS class name values on this element before the view change happens if you want to add any open/close\n * animations to your custom element before the chat shell inner contents are hidden. It is async and so you can\n * tie it to native the AnimationEvent and only return when your animations have completed.\n *\n * A common pattern is to use this for when the chat is closing and to use onViewChange for when the chat opens.\n *\n * Note that this function can only be provided before Carbon AI Chat is loaded as it is registered before the\n * chat renders. After Carbon AI Chat is loaded, the callback will not be updated.\n */\n @property()\n onViewPreChange?: (event: BusEventViewPreChange) => Promise<void> | void;\n\n /**\n * Called when the chat view change is complete. If no callback is provided here, the default behavior will be to set\n * the chat shell to 0x0 size and set all inner contents aside from the launcher, if you are using it, to display: none.\n * The inner contents of the chat shell (aside from the launcher if you are using it) are always set to display: none\n * regardless of what is configured with this callback to prevent invisible tab stops and screen reader issues.\n *\n * Use this callback to update your className value when the chat has finished being opened or closed.\n *\n * You can provide a different callback here if you want custom animation behavior when the chat is opened or closed.\n * The animation behavior defined here will run in concert with the chat inside your custom container being hidden.\n *\n * If you want to run animations before the inner contents of the chat shell is shrunk and the inner contents are hidden,\n * make use of onViewPreChange.\n *\n * A common pattern is to use this for when the chat is opening and to use onViewPreChange for when the chat closes.\n *\n * Note that this function can only be provided before Carbon AI Chat is loaded as it is registered before the\n * chat renders. After Carbon AI Chat is loaded, the callback will not be updated.\n */\n @property()\n onViewChange?: (event: BusEventViewChange, instance: ChatInstance) => void;\n\n /**\n * Optional callback to render user defined responses. When provided, the inner cds-aichat-container\n * manages all event listening, slot tracking, and element lifecycle.\n */\n @property({ attribute: false })\n renderUserDefinedResponse?: WCRenderUserDefinedResponse;\n\n /**\n * Optional callback to render custom message footers. When provided, the inner cds-aichat-container\n * manages all event listening, slot tracking, and element lifecycle.\n */\n @property({ attribute: false })\n renderCustomMessageFooter?: WCRenderCustomMessageFooter;\n\n // markdown is declared on the FlattenedConfigElement base; the attributes\n // interface narrows its type.\n\n @state()\n private _userDefinedSlotNames: string[] = [];\n\n @state()\n private _writeableElementSlots: string[] = [];\n\n @state()\n private _customFooterSlotNames: string[] = [];\n\n /**\n * Active slot names for markdown-plugin output hosted at this element.\n * Populated when this element accepts the host-mount event; drained when\n * the matching unmount event fires.\n */\n @state()\n private _pluginSlotNames: string[] = [];\n\n /**\n * Page-level host elements created for plugin-output slots, keyed by slot\n * name. Created in this element's outer light DOM so consumer-loaded\n * stylesheets (e.g. KaTeX) reach the rendered HTML normally.\n */\n private _pluginHosts: Map<string, HTMLElement> = new Map();\n\n @state()\n private _instance!: ChatInstance;\n\n private defaultViewChangeHandler = (event: BusEventViewChange) => {\n if (event.newViewState.mainWindow) {\n this.classList.remove(\"cds-aichat--hidden\");\n } else {\n this.classList.add(\"cds-aichat--hidden\");\n }\n };\n\n private userDefinedHandler = (\n event: BusEventUserDefinedResponse | BusEventChunkUserDefinedResponse,\n ) => {\n const { slot } = event.data;\n if (!this._userDefinedSlotNames.includes(slot)) {\n this._userDefinedSlotNames = [...this._userDefinedSlotNames, slot];\n }\n };\n\n private customFooterHandler = (event: BusEventCustomFooterSlot) => {\n const { slotName } = event.data;\n if (!this._customFooterSlotNames.includes(slotName)) {\n this._customFooterSlotNames = [...this._customFooterSlotNames, slotName];\n }\n };\n\n private handlePluginHostMount = (event: Event) => {\n const detail = (\n event as CustomEvent<{\n slotName: string;\n html: string;\n isInline: boolean;\n }>\n ).detail;\n if (!detail?.slotName) {\n return;\n }\n if (!this._pluginSlotNames.includes(detail.slotName)) {\n this._pluginSlotNames = [...this._pluginSlotNames, detail.slotName];\n }\n // cds-aichat-custom-element is always the outermost chat element in its\n // shadow chain; there is no further chat ancestor to defer to. Take\n // hosting unconditionally.\n event.preventDefault();\n let host = this._pluginHosts.get(detail.slotName);\n if (!host) {\n host = document.createElement(detail.isInline ? \"span\" : \"div\");\n host.setAttribute(\"slot\", detail.slotName);\n // Match `.cds-aichat-markdown-stack > *:not(:first-child)` spacing;\n // shadow CSS doesn't reach this host (it lives in this element's\n // outer light DOM), so apply it inline. Inline output flows with\n // text and gets no extra spacing.\n if (!detail.isInline) {\n host.style.marginBlockStart = \"1rem\";\n }\n this._pluginHosts.set(detail.slotName, host);\n this.appendChild(host);\n }\n if (host.innerHTML !== detail.html) {\n host.innerHTML = detail.html;\n }\n };\n\n private handlePluginHostUpdate = (event: Event) => {\n const detail = (event as CustomEvent<{ slotName: string; html: string }>)\n .detail;\n if (!detail?.slotName) {\n return;\n }\n const host = this._pluginHosts.get(detail.slotName);\n if (host && host.innerHTML !== detail.html) {\n host.innerHTML = detail.html;\n }\n };\n\n private handlePluginHostUnmount = (event: Event) => {\n const detail = (event as CustomEvent<{ slotName: string }>).detail;\n if (!detail?.slotName) {\n return;\n }\n this._pluginSlotNames = this._pluginSlotNames.filter(\n (n) => n !== detail.slotName,\n );\n const host = this._pluginHosts.get(detail.slotName);\n if (host) {\n host.remove();\n this._pluginHosts.delete(detail.slotName);\n }\n };\n\n connectedCallback() {\n super.connectedCallback();\n this.addEventListener(\n \"cds-aichat-markdown-plugin-host-mount\",\n this.handlePluginHostMount,\n );\n this.addEventListener(\n \"cds-aichat-markdown-plugin-host-update\",\n this.handlePluginHostUpdate,\n );\n this.addEventListener(\n \"cds-aichat-markdown-plugin-host-unmount\",\n this.handlePluginHostUnmount,\n );\n }\n\n disconnectedCallback() {\n this.removeEventListener(\n \"cds-aichat-markdown-plugin-host-mount\",\n this.handlePluginHostMount,\n );\n this.removeEventListener(\n \"cds-aichat-markdown-plugin-host-update\",\n this.handlePluginHostUpdate,\n );\n this.removeEventListener(\n \"cds-aichat-markdown-plugin-host-unmount\",\n this.handlePluginHostUnmount,\n );\n for (const host of this._pluginHosts.values()) {\n host.remove();\n }\n this._pluginHosts.clear();\n super.disconnectedCallback();\n }\n\n private onBeforeRenderOverride = async (instance: ChatInstance) => {\n this._instance = instance;\n if (this.onViewPreChange) {\n this._instance.on({\n type: BusEventType.VIEW_PRE_CHANGE,\n handler: this.onViewPreChange,\n });\n }\n this._instance.on({\n type: BusEventType.VIEW_CHANGE,\n handler: this.onViewChange || this.defaultViewChangeHandler,\n });\n\n if (!this.renderUserDefinedResponse) {\n // Legacy path: custom-element tracks slot names for manual slotting.\n // When renderUserDefinedResponse is set, the inner cds-aichat-container handles everything.\n this._instance.on({\n type: BusEventType.USER_DEFINED_RESPONSE,\n handler: this.userDefinedHandler,\n });\n this._instance.on({\n type: BusEventType.CHUNK_USER_DEFINED_RESPONSE,\n handler: this.userDefinedHandler,\n });\n }\n\n if (!this.renderCustomMessageFooter) {\n // Legacy path: custom-element tracks slot names for manual slotting.\n // When renderCustomMessageFooter is set, the inner cds-aichat-container handles everything.\n this._instance.on({\n type: BusEventType.CUSTOM_FOOTER_SLOT,\n handler: this.customFooterHandler,\n });\n }\n this.addWriteableElementSlots();\n await this.onBeforeRender?.(instance);\n };\n\n private addWriteableElementSlots() {\n this._writeableElementSlots = Object.keys(this._instance.writeableElements);\n }\n\n render() {\n return html`\n <cds-aichat-container\n .config=${this.resolvedConfig}\n .header=${this.resolvedConfig.header}\n .onAfterRender=${this.onAfterRender}\n .onBeforeRender=${this.onBeforeRenderOverride}\n .element=${this}\n .renderUserDefinedResponse=${this.renderUserDefinedResponse}\n .renderCustomMessageFooter=${this.renderCustomMessageFooter}\n .markdown=${this.markdown as WCMarkdown | undefined}\n >\n ${this._writeableElementSlots.map(\n (slot) => html`<slot name=${slot} slot=${slot}></slot>`,\n )}\n ${this.renderUserDefinedResponse\n ? null\n : this._userDefinedSlotNames.map(\n (slot) => html`<slot name=${slot} slot=${slot}></slot>`,\n )}\n ${this.renderCustomMessageFooter\n ? null\n : this._customFooterSlotNames.map(\n (slot) =>\n html`<div slot=${slot}><slot name=${slot}></slot></div>`,\n )}\n ${this._pluginSlotNames.map(\n (slot) => html`<slot name=${slot} slot=${slot}></slot>`,\n )}\n </cds-aichat-container>\n `;\n }\n}\n\n/**\n * Attributes interface for the cds-aichat-custom-element web component.\n * This interface extends {@link PublicConfig} with additional component-specific props,\n * flattening all config properties as top-level properties for better TypeScript IntelliSense.\n *\n * @category Web component\n */\ninterface CdsAiChatCustomElementAttributes extends Omit<\n PublicConfig,\n \"markdown\"\n> {\n /**\n * Markdown rendering customization. Extends the framework-neutral\n * `PublicConfig.markdown` with web-component `customRenderers`.\n *\n * @experimental\n */\n markdown?: WCMarkdown;\n\n /**\n * This function is called before the render function of Carbon AI Chat is called. This function can return a Promise\n * which will cause Carbon AI Chat to wait for it before rendering.\n */\n onBeforeRender?: (instance: ChatInstance) => Promise<void> | void;\n\n /**\n * This function is called after the render function of Carbon AI Chat is called.\n */\n onAfterRender?: (instance: ChatInstance) => Promise<void> | void;\n\n /**\n * Called before a view change (the chat opening or closing) and awaited before the change proceeds. Use it to update\n * this element's CSS classes and run open/close animations to completion before the chat shell's inner contents are\n * hidden. A common pattern is to use this when the chat is closing and `onViewChange` when it opens.\n *\n * Note that this function can only be provided before Carbon AI Chat is loaded. After Carbon AI Chat is loaded, the\n * callback will not be updated.\n */\n onViewPreChange?: (event: BusEventViewPreChange) => Promise<void> | void;\n\n /**\n * An optional listener for \"view:change\" events. Such a listener is required when using a custom element in order\n * to control the visibility of the Carbon AI Chat main window. If no callback is provided here, a default one will be\n * used that injects styling into the app that will show and hide the Carbon AI Chat main window and also change the\n * size of the custom element so it doesn't take up space when the main window is closed.\n *\n * You can provide a different callback here if you want custom behavior such as an animation when the main window\n * is opened or closed.\n *\n * Note that this function can only be provided before Carbon AI Chat is loaded. After Carbon AI Chat is loaded, the event\n * handler will not be updated.\n */\n onViewChange?: (event: BusEventViewChange, instance: ChatInstance) => void;\n\n /**\n * Optional callback to render user defined responses. When provided, the inner cds-aichat-container\n * manages all event listening, slot tracking, streaming state, and element lifecycle.\n */\n renderUserDefinedResponse?: WCRenderUserDefinedResponse;\n\n /**\n * Optional callback to render custom message footers. When provided, the inner cds-aichat-container\n * manages all event listening, slot tracking, and element lifecycle.\n */\n renderCustomMessageFooter?: WCRenderCustomMessageFooter;\n}\n\nexport { CdsAiChatCustomElementAttributes };\n\nexport default ChatCustomElement;\n"],"names":["ChatCustomElement","ChatCustomElement_1","FlattenedConfigElement","constructor","this","_userDefinedSlotNames","_writeableElementSlots","_customFooterSlotNames","_pluginSlotNames","_pluginHosts","Map","defaultViewChangeHandler","event","newViewState","mainWindow","classList","remove","add","userDefinedHandler","slot","data","includes","customFooterHandler","slotName","handlePluginHostMount","detail","preventDefault","host","get","document","createElement","isInline","setAttribute","style","marginBlockStart","set","appendChild","innerHTML","html","handlePluginHostUpdate","handlePluginHostUnmount","filter","n","delete","onBeforeRenderOverride","async","instance","_instance","onViewPreChange","on","type","BusEventType","VIEW_PRE_CHANGE","handler","VIEW_CHANGE","onViewChange","renderUserDefinedResponse","USER_DEFINED_RESPONSE","CHUNK_USER_DEFINED_RESPONSE","renderCustomMessageFooter","CUSTOM_FOOTER_SLOT","addWriteableElementSlots","onBeforeRender","createRenderRoot","root","super","adoptedStyleSheets","hideSheet","connectedCallback","addEventListener","disconnectedCallback","removeEventListener","values","clear","Object","keys","writeableElements","render","resolvedConfig","header","onAfterRender","markdown","map","CSSStyleSheet","replaceSync","__decorate","property","attribute","prototype","state","carbonElement","ChatCustomElement_default"],"mappings":"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"}
1
+ {"version":3,"file":"index.js","sources":["../../../../../../src/web-components/cds-aichat-custom-element/index.ts"],"sourcesContent":["/*\n * Copyright IBM Corp. 2025, 2026\n *\n * This source code is licensed under the Apache-2.0 license found in the\n * LICENSE file in the root directory of this source tree.\n *\n * @license\n */\n\n// Ensure the container custom element is registered whenever the\n// custom element module is imported by re-exporting its exports.\n// This prevents bundlers (and our own multi-entry Rollup build)\n// from pruning the side-effect-only import.\nexport { default as __cds_aichat_container_register } from \"../cds-aichat-container\";\nimport \"../cds-aichat-container\";\n\nimport { html } from \"lit\";\nimport { property, state } from \"lit/decorators.js\";\n\nimport { carbonElement } from \"@carbon/ai-chat-components/es/globals/decorators/index.js\";\nimport { PublicConfig } from \"../../types/config/PublicConfig\";\nimport { FlattenedConfigElement } from \"../shared/FlattenedConfigElement\";\nimport { ChatInstance } from \"../../types/instance/ChatInstance\";\nimport {\n BusEventChunkUserDefinedResponse,\n BusEventCustomFooterSlot,\n BusEventType,\n BusEventUserDefinedResponse,\n BusEventViewChange,\n BusEventViewPreChange,\n} from \"../../types/events/eventBusTypes\";\nimport type {\n WCMarkdown,\n WCRenderCustomMessageFooter,\n WCRenderUserDefinedResponse,\n} from \"../../types/component/ChatContainer\";\n\n/**\n * cds-aichat-custom-element will is a pass through to cds-aichat-container. It takes any user_defined and writeable element\n * slotted content and forwards it to cds-aichat-container. It also will setup the custom element with a default viewChange\n * pattern (e.g. hiding and showing the custom element when the chat should be open/closed) if a onViewChange property is not\n * defined. Finally, it registers the custom element with cds-aichat-container so a default \"floating\" element will not be created.\n *\n * The custom element should be sized using external CSS. When hidden, the 'cds-aichat--hidden' class is added to set dimensions to 0x0.\n */\n@carbonElement(\"cds-aichat-custom-element\")\nclass ChatCustomElement extends FlattenedConfigElement {\n /**\n * Shared stylesheet for hiding styles.\n */\n private static hideSheet = new CSSStyleSheet();\n static {\n // Hide styles that override any external sizing. `replaceSync` is absent\n // in non-browser environments (e.g. the jsdom-based test environment), so\n // skip styling there rather than throwing at module-evaluation time.\n ChatCustomElement.hideSheet.replaceSync?.(`\n :host {\n display: block;\n }\n :host(.cds-aichat--hidden) {\n width: 0 !important;\n height: 0 !important;\n min-width: 0 !important;\n min-height: 0 !important;\n max-width: 0 !important;\n max-height: 0 !important;\n inline-size: 0 !important;\n block-size: 0 !important;\n min-inline-size: 0 !important;\n min-block-size: 0 !important;\n max-inline-size: 0 !important;\n max-block-size: 0 !important;\n overflow: hidden !important;\n display: block !important;\n }\n `);\n }\n\n /**\n * Adopt our stylesheet into every shadowRoot.\n */\n protected createRenderRoot(): ShadowRoot {\n // Lits default createRenderRoot actually returns a ShadowRoot\n const root = super.createRenderRoot() as ShadowRoot;\n\n // now TS knows root.adoptedStyleSheets exists\n root.adoptedStyleSheets = [\n ...root.adoptedStyleSheets,\n ChatCustomElement.hideSheet,\n ];\n return root;\n }\n\n /**\n * This function is called before the render function of Carbon AI Chat is called. This function can return a Promise\n * which will cause Carbon AI Chat to wait for it before rendering.\n *\n * Use it to capture the {@link ChatInstance} so you can call instance methods later.\n *\n * @example\n * ```ts\n * const onBeforeRender = (instance: ChatInstance) => {\n * this.instance = instance;\n * };\n * // <cds-aichat-custom-element .onBeforeRender=${onBeforeRender}></cds-aichat-custom-element>\n * ```\n */\n @property({ attribute: false })\n onBeforeRender?: (instance: ChatInstance) => Promise<void> | void;\n\n /**\n * This function is called after the render function of Carbon AI Chat is called.\n *\n * Like `onBeforeRender`, it receives the {@link ChatInstance}; use it when you need the instance only after the\n * first render has completed.\n */\n @property({ attribute: false })\n onAfterRender?: (instance: ChatInstance) => Promise<void> | void;\n\n /**\n * Called before a view change (chat opening/closing). The chat will hide the chat shell inside your custom element\n * to prevent invisible keyboard stops when the view change is complete.\n *\n * Use this callback to update your CSS class name values on this element before the view change happens if you want to add any open/close\n * animations to your custom element before the chat shell inner contents are hidden. It is async and so you can\n * tie it to native the AnimationEvent and only return when your animations have completed.\n *\n * A common pattern is to use this for when the chat is closing and to use onViewChange for when the chat opens.\n *\n * Note that this function can only be provided before Carbon AI Chat is loaded as it is registered before the\n * chat renders. After Carbon AI Chat is loaded, the callback will not be updated.\n */\n @property()\n onViewPreChange?: (event: BusEventViewPreChange) => Promise<void> | void;\n\n /**\n * Called when the chat view change is complete. If no callback is provided here, the default behavior will be to set\n * the chat shell to 0x0 size and set all inner contents aside from the launcher, if you are using it, to display: none.\n * The inner contents of the chat shell (aside from the launcher if you are using it) are always set to display: none\n * regardless of what is configured with this callback to prevent invisible tab stops and screen reader issues.\n *\n * Use this callback to update your className value when the chat has finished being opened or closed.\n *\n * You can provide a different callback here if you want custom animation behavior when the chat is opened or closed.\n * The animation behavior defined here will run in concert with the chat inside your custom container being hidden.\n *\n * If you want to run animations before the inner contents of the chat shell is shrunk and the inner contents are hidden,\n * make use of onViewPreChange.\n *\n * A common pattern is to use this for when the chat is opening and to use onViewPreChange for when the chat closes.\n *\n * Note that this function can only be provided before Carbon AI Chat is loaded as it is registered before the\n * chat renders. After Carbon AI Chat is loaded, the callback will not be updated.\n */\n @property()\n onViewChange?: (event: BusEventViewChange, instance: ChatInstance) => void;\n\n /**\n * Optional callback to render user defined responses. When provided, the inner cds-aichat-container\n * manages all event listening, slot tracking, and element lifecycle.\n */\n @property({ attribute: false })\n renderUserDefinedResponse?: WCRenderUserDefinedResponse;\n\n /**\n * Optional callback to render custom message footers. When provided, the inner cds-aichat-container\n * manages all event listening, slot tracking, and element lifecycle.\n */\n @property({ attribute: false })\n renderCustomMessageFooter?: WCRenderCustomMessageFooter;\n\n // markdown is declared on the FlattenedConfigElement base; the attributes\n // interface narrows its type.\n\n @state()\n private _userDefinedSlotNames: string[] = [];\n\n @state()\n private _writeableElementSlots: string[] = [];\n\n @state()\n private _customFooterSlotNames: string[] = [];\n\n /**\n * Active slot names for markdown-plugin output hosted at this element.\n * Populated when this element accepts the host-mount event; drained when\n * the matching unmount event fires.\n */\n @state()\n private _pluginSlotNames: string[] = [];\n\n /**\n * Page-level host elements created for plugin-output slots, keyed by slot\n * name. Created in this element's outer light DOM so consumer-loaded\n * stylesheets (e.g. KaTeX) reach the rendered HTML normally.\n */\n private _pluginHosts: Map<string, HTMLElement> = new Map();\n\n @state()\n private _instance!: ChatInstance;\n\n private defaultViewChangeHandler = (event: BusEventViewChange) => {\n if (event.newViewState.mainWindow) {\n this.classList.remove(\"cds-aichat--hidden\");\n } else {\n this.classList.add(\"cds-aichat--hidden\");\n }\n };\n\n private userDefinedHandler = (\n event: BusEventUserDefinedResponse | BusEventChunkUserDefinedResponse,\n ) => {\n const { slot } = event.data;\n if (!this._userDefinedSlotNames.includes(slot)) {\n this._userDefinedSlotNames = [...this._userDefinedSlotNames, slot];\n }\n };\n\n private customFooterHandler = (event: BusEventCustomFooterSlot) => {\n const { slotName } = event.data;\n if (!this._customFooterSlotNames.includes(slotName)) {\n this._customFooterSlotNames = [...this._customFooterSlotNames, slotName];\n }\n };\n\n private handlePluginHostMount = (event: Event) => {\n const detail = (\n event as CustomEvent<{\n slotName: string;\n html?: string;\n element?: HTMLElement;\n isInline: boolean;\n }>\n ).detail;\n if (!detail?.slotName) {\n return;\n }\n if (!this._pluginSlotNames.includes(detail.slotName)) {\n this._pluginSlotNames = [...this._pluginSlotNames, detail.slotName];\n }\n // cds-aichat-custom-element is always the outermost chat element in its\n // shadow chain; there is no further chat ancestor to defer to. Take\n // hosting unconditionally.\n event.preventDefault();\n // Custom-renderer hosts (table/codeBlock) forward a live element — the\n // markdown element keeps ownership of its content; we only relocate the\n // node into our outer light DOM so the consumer's global CSS reaches it.\n // Plugin fallbacks forward an HTML string instead.\n if (detail.element) {\n const element = detail.element;\n element.setAttribute(\"slot\", detail.slotName);\n if (!detail.isInline) {\n element.style.marginBlockStart = \"1rem\";\n }\n if (element.parentElement !== this) {\n this.appendChild(element);\n }\n return;\n }\n let host = this._pluginHosts.get(detail.slotName);\n if (!host) {\n host = document.createElement(detail.isInline ? \"span\" : \"div\");\n host.setAttribute(\"slot\", detail.slotName);\n // Match `.cds-aichat-markdown-stack > *:not(:first-child)` spacing;\n // shadow CSS doesn't reach this host (it lives in this element's\n // outer light DOM), so apply it inline. Inline output flows with\n // text and gets no extra spacing.\n if (!detail.isInline) {\n host.style.marginBlockStart = \"1rem\";\n }\n this._pluginHosts.set(detail.slotName, host);\n this.appendChild(host);\n }\n if (host.innerHTML !== (detail.html ?? \"\")) {\n host.innerHTML = detail.html ?? \"\";\n }\n };\n\n private handlePluginHostUpdate = (event: Event) => {\n const detail = (event as CustomEvent<{ slotName: string; html: string }>)\n .detail;\n if (!detail?.slotName) {\n return;\n }\n const host = this._pluginHosts.get(detail.slotName);\n if (host && host.innerHTML !== detail.html) {\n host.innerHTML = detail.html;\n }\n };\n\n private handlePluginHostUnmount = (event: Event) => {\n const detail = (event as CustomEvent<{ slotName: string }>).detail;\n if (!detail?.slotName) {\n return;\n }\n this._pluginSlotNames = this._pluginSlotNames.filter(\n (n) => n !== detail.slotName,\n );\n const host = this._pluginHosts.get(detail.slotName);\n if (host) {\n host.remove();\n this._pluginHosts.delete(detail.slotName);\n }\n };\n\n connectedCallback() {\n super.connectedCallback();\n this.addEventListener(\n \"cds-aichat-markdown-plugin-host-mount\",\n this.handlePluginHostMount,\n );\n this.addEventListener(\n \"cds-aichat-markdown-plugin-host-update\",\n this.handlePluginHostUpdate,\n );\n this.addEventListener(\n \"cds-aichat-markdown-plugin-host-unmount\",\n this.handlePluginHostUnmount,\n );\n }\n\n disconnectedCallback() {\n this.removeEventListener(\n \"cds-aichat-markdown-plugin-host-mount\",\n this.handlePluginHostMount,\n );\n this.removeEventListener(\n \"cds-aichat-markdown-plugin-host-update\",\n this.handlePluginHostUpdate,\n );\n this.removeEventListener(\n \"cds-aichat-markdown-plugin-host-unmount\",\n this.handlePluginHostUnmount,\n );\n for (const host of this._pluginHosts.values()) {\n host.remove();\n }\n this._pluginHosts.clear();\n super.disconnectedCallback();\n }\n\n private onBeforeRenderOverride = async (instance: ChatInstance) => {\n this._instance = instance;\n if (this.onViewPreChange) {\n this._instance.on({\n type: BusEventType.VIEW_PRE_CHANGE,\n handler: this.onViewPreChange,\n });\n }\n this._instance.on({\n type: BusEventType.VIEW_CHANGE,\n handler: this.onViewChange || this.defaultViewChangeHandler,\n });\n\n if (!this.renderUserDefinedResponse) {\n // Legacy path: custom-element tracks slot names for manual slotting.\n // When renderUserDefinedResponse is set, the inner cds-aichat-container handles everything.\n this._instance.on({\n type: BusEventType.USER_DEFINED_RESPONSE,\n handler: this.userDefinedHandler,\n });\n this._instance.on({\n type: BusEventType.CHUNK_USER_DEFINED_RESPONSE,\n handler: this.userDefinedHandler,\n });\n }\n\n if (!this.renderCustomMessageFooter) {\n // Legacy path: custom-element tracks slot names for manual slotting.\n // When renderCustomMessageFooter is set, the inner cds-aichat-container handles everything.\n this._instance.on({\n type: BusEventType.CUSTOM_FOOTER_SLOT,\n handler: this.customFooterHandler,\n });\n }\n this.addWriteableElementSlots();\n await this.onBeforeRender?.(instance);\n };\n\n private addWriteableElementSlots() {\n this._writeableElementSlots = Object.keys(this._instance.writeableElements);\n }\n\n render() {\n return html`\n <cds-aichat-container\n .config=${this.resolvedConfig}\n .header=${this.resolvedConfig.header}\n .onAfterRender=${this.onAfterRender}\n .onBeforeRender=${this.onBeforeRenderOverride}\n .element=${this}\n .renderUserDefinedResponse=${this.renderUserDefinedResponse}\n .renderCustomMessageFooter=${this.renderCustomMessageFooter}\n .markdown=${this.markdown as WCMarkdown | undefined}\n >\n ${this._writeableElementSlots.map(\n (slot) => html`<slot name=${slot} slot=${slot}></slot>`,\n )}\n ${this.renderUserDefinedResponse\n ? null\n : this._userDefinedSlotNames.map(\n (slot) => html`<slot name=${slot} slot=${slot}></slot>`,\n )}\n ${this.renderCustomMessageFooter\n ? null\n : this._customFooterSlotNames.map(\n (slot) =>\n html`<div slot=${slot}><slot name=${slot}></slot></div>`,\n )}\n ${this._pluginSlotNames.map(\n (slot) => html`<slot name=${slot} slot=${slot}></slot>`,\n )}\n </cds-aichat-container>\n `;\n }\n}\n\n/**\n * Attributes interface for the cds-aichat-custom-element web component.\n * This interface extends {@link PublicConfig} with additional component-specific props,\n * flattening all config properties as top-level properties for better TypeScript IntelliSense.\n *\n * @category Web component\n */\ninterface CdsAiChatCustomElementAttributes extends Omit<\n PublicConfig,\n \"markdown\"\n> {\n /**\n * Markdown rendering customization. Extends the framework-neutral\n * `PublicConfig.markdown` with web-component `customRenderers`.\n *\n * @experimental\n */\n markdown?: WCMarkdown;\n\n /**\n * This function is called before the render function of Carbon AI Chat is called. This function can return a Promise\n * which will cause Carbon AI Chat to wait for it before rendering.\n */\n onBeforeRender?: (instance: ChatInstance) => Promise<void> | void;\n\n /**\n * This function is called after the render function of Carbon AI Chat is called.\n */\n onAfterRender?: (instance: ChatInstance) => Promise<void> | void;\n\n /**\n * Called before a view change (the chat opening or closing) and awaited before the change proceeds. Use it to update\n * this element's CSS classes and run open/close animations to completion before the chat shell's inner contents are\n * hidden. A common pattern is to use this when the chat is closing and `onViewChange` when it opens.\n *\n * Note that this function can only be provided before Carbon AI Chat is loaded. After Carbon AI Chat is loaded, the\n * callback will not be updated.\n */\n onViewPreChange?: (event: BusEventViewPreChange) => Promise<void> | void;\n\n /**\n * An optional listener for \"view:change\" events. Such a listener is required when using a custom element in order\n * to control the visibility of the Carbon AI Chat main window. If no callback is provided here, a default one will be\n * used that injects styling into the app that will show and hide the Carbon AI Chat main window and also change the\n * size of the custom element so it doesn't take up space when the main window is closed.\n *\n * You can provide a different callback here if you want custom behavior such as an animation when the main window\n * is opened or closed.\n *\n * Note that this function can only be provided before Carbon AI Chat is loaded. After Carbon AI Chat is loaded, the event\n * handler will not be updated.\n */\n onViewChange?: (event: BusEventViewChange, instance: ChatInstance) => void;\n\n /**\n * Optional callback to render user defined responses. When provided, the inner cds-aichat-container\n * manages all event listening, slot tracking, streaming state, and element lifecycle.\n */\n renderUserDefinedResponse?: WCRenderUserDefinedResponse;\n\n /**\n * Optional callback to render custom message footers. When provided, the inner cds-aichat-container\n * manages all event listening, slot tracking, and element lifecycle.\n */\n renderCustomMessageFooter?: WCRenderCustomMessageFooter;\n}\n\nexport { CdsAiChatCustomElementAttributes };\n\nexport default ChatCustomElement;\n"],"names":["ChatCustomElement","ChatCustomElement_1","FlattenedConfigElement","constructor","this","_userDefinedSlotNames","_writeableElementSlots","_customFooterSlotNames","_pluginSlotNames","_pluginHosts","Map","defaultViewChangeHandler","event","newViewState","mainWindow","classList","remove","add","userDefinedHandler","slot","data","includes","customFooterHandler","slotName","handlePluginHostMount","detail","preventDefault","element","setAttribute","isInline","style","marginBlockStart","parentElement","appendChild","host","get","document","createElement","set","innerHTML","html","handlePluginHostUpdate","handlePluginHostUnmount","filter","n","delete","onBeforeRenderOverride","async","instance","_instance","onViewPreChange","on","type","BusEventType","VIEW_PRE_CHANGE","handler","VIEW_CHANGE","onViewChange","renderUserDefinedResponse","USER_DEFINED_RESPONSE","CHUNK_USER_DEFINED_RESPONSE","renderCustomMessageFooter","CUSTOM_FOOTER_SLOT","addWriteableElementSlots","onBeforeRender","createRenderRoot","root","super","adoptedStyleSheets","hideSheet","connectedCallback","addEventListener","disconnectedCallback","removeEventListener","values","clear","Object","keys","writeableElements","render","resolvedConfig","header","onAfterRender","markdown","map","CSSStyleSheet","replaceSync","__decorate","property","attribute","prototype","state","carbonElement","ChatCustomElement_default"],"mappings":";;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;AA8CA,IAAMA,oBAAiBC,sBAAvB,MAAMD,0BAA0BE;EAAhC,WAAAC;;IAiIUC,KAAAC,wBAAkC;IAGlCD,KAAAE,yBAAmC;IAGnCF,KAAAG,yBAAmC;IAQnCH,KAAAI,mBAA6B;IAO7BJ,KAAAK,eAAyC,IAAIC;IAK7CN,KAAAO,2BAA4BC;MAClC,IAAIA,MAAMC,aAAaC,YAAY;QACjCV,KAAKW,UAAUC,OAAO;AACxB,aAAO;QACLZ,KAAKW,UAAUE,IAAI;AACrB;;IAGMb,KAAAc,qBACNN;MAEA,OAAMO,QAAWP,MAAMQ;MACvB,KAAKhB,KAAKC,sBAAsBgB,SAASF,OAAO;QAC9Cf,KAAKC,wBAAwB,KAAID,KAAKC,uBAAuBc;AAC/D;;IAGMf,KAAAkB,sBAAuBV;MAC7B,OAAMW,YAAeX,MAAMQ;MAC3B,KAAKhB,KAAKG,uBAAuBc,SAASE,WAAW;QACnDnB,KAAKG,yBAAyB,KAAIH,KAAKG,wBAAwBgB;AACjE;;IAGMnB,KAAAoB,wBAAyBZ;MAC/B,MAAMa,SACJb,MAMAa;MACF,KAAKA,QAAQF,UAAU;QACrB;AACF;MACA,KAAKnB,KAAKI,iBAAiBa,SAASI,OAAOF,WAAW;QACpDnB,KAAKI,mBAAmB,KAAIJ,KAAKI,kBAAkBiB,OAAOF;AAC5D;MAIAX,MAAMc;MAKN,IAAID,OAAOE,SAAS;QAClB,MAAMA,UAAUF,OAAOE;QACvBA,QAAQC,aAAa,QAAQH,OAAOF;QACpC,KAAKE,OAAOI,UAAU;UACpBF,QAAQG,MAAMC,mBAAmB;AACnC;QACA,IAAIJ,QAAQK,kBAAkB5B,MAAM;UAClCA,KAAK6B,YAAYN;AACnB;QACA;AACF;MACA,IAAIO,OAAO9B,KAAKK,aAAa0B,IAAIV,OAAOF;MACxC,KAAKW,MAAM;QACTA,OAAOE,SAASC,cAAcZ,OAAOI,WAAW,SAAS;QACzDK,KAAKN,aAAa,QAAQH,OAAOF;QAKjC,KAAKE,OAAOI,UAAU;UACpBK,KAAKJ,MAAMC,mBAAmB;AAChC;QACA3B,KAAKK,aAAa6B,IAAIb,OAAOF,UAAUW;QACvC9B,KAAK6B,YAAYC;AACnB;MACA,IAAIA,KAAKK,eAAed,OAAOe,QAAQ,KAAK;QAC1CN,KAAKK,YAAYd,OAAOe,QAAQ;AAClC;;IAGMpC,KAAAqC,yBAA0B7B;MAChC,MAAMa,SAAUb,MACba;MACH,KAAKA,QAAQF,UAAU;QACrB;AACF;MACA,MAAMW,OAAO9B,KAAKK,aAAa0B,IAAIV,OAAOF;MAC1C,IAAIW,QAAQA,KAAKK,cAAcd,OAAOe,MAAM;QAC1CN,KAAKK,YAAYd,OAAOe;AAC1B;;IAGMpC,KAAAsC,0BAA2B9B;MACjC,MAAMa,SAAUb,MAA4Ca;MAC5D,KAAKA,QAAQF,UAAU;QACrB;AACF;MACAnB,KAAKI,mBAAmBJ,KAAKI,iBAAiBmC,OAC3CC,KAAMA,MAAMnB,OAAOF;MAEtB,MAAMW,OAAO9B,KAAKK,aAAa0B,IAAIV,OAAOF;MAC1C,IAAIW,MAAM;QACRA,KAAKlB;QACLZ,KAAKK,aAAaoC,OAAOpB,OAAOF;AAClC;;IAuCMnB,KAAA0C,yBAAyBC,MAAOC;MACtC5C,KAAK6C,YAAYD;MACjB,IAAI5C,KAAK8C,iBAAiB;QACxB9C,KAAK6C,UAAUE,GAAG;UAChBC,MAAMC,aAAaC;UACnBC,SAASnD,KAAK8C;;AAElB;MACA9C,KAAK6C,UAAUE,GAAG;QAChBC,MAAMC,aAAaG;QACnBD,SAASnD,KAAKqD,gBAAgBrD,KAAKO;;MAGrC,KAAKP,KAAKsD,2BAA2B;QAGnCtD,KAAK6C,UAAUE,GAAG;UAChBC,MAAMC,aAAaM;UACnBJ,SAASnD,KAAKc;;QAEhBd,KAAK6C,UAAUE,GAAG;UAChBC,MAAMC,aAAaO;UACnBL,SAASnD,KAAKc;;AAElB;MAEA,KAAKd,KAAKyD,2BAA2B;QAGnCzD,KAAK6C,UAAUE,GAAG;UAChBC,MAAMC,aAAaS;UACnBP,SAASnD,KAAKkB;;AAElB;MACAlB,KAAK2D;aACC3D,KAAK4D,iBAAiBhB;;AAuChC;EA9UY,gBAAAiB;IAER,MAAMC,OAAOC,MAAMF;IAGnBC,KAAKE,qBAAqB,KACrBF,KAAKE,oBACRnE,oBAAkBoE;IAEpB,OAAOH;AACT;EAsNA,iBAAAI;IACEH,MAAMG;IACNlE,KAAKmE,iBACH,yCACAnE,KAAKoB;IAEPpB,KAAKmE,iBACH,0CACAnE,KAAKqC;IAEPrC,KAAKmE,iBACH,2CACAnE,KAAKsC;AAET;EAEA,oBAAA8B;IACEpE,KAAKqE,oBACH,yCACArE,KAAKoB;IAEPpB,KAAKqE,oBACH,0CACArE,KAAKqC;IAEPrC,KAAKqE,oBACH,2CACArE,KAAKsC;IAEP,KAAK,MAAMR,QAAQ9B,KAAKK,aAAaiE,UAAU;MAC7CxC,KAAKlB;AACP;IACAZ,KAAKK,aAAakE;IAClBR,MAAMK;AACR;EAwCQ,wBAAAT;IACN3D,KAAKE,yBAAyBsE,OAAOC,KAAKzE,KAAK6C,UAAU6B;AAC3D;EAEA,MAAAC;IACE,OAAOvC,IAAI;;kBAEGpC,KAAK4E;kBACL5E,KAAK4E,eAAeC;yBACb7E,KAAK8E;0BACJ9E,KAAK0C;mBACZ1C;qCACkBA,KAAKsD;qCACLtD,KAAKyD;oBACtBzD,KAAK+E;;UAEf/E,KAAKE,uBAAuB8E,IAC3BjE,QAASqB,IAAI,cAAcrB,aAAaA;UAEzCf,KAAKsD,4BACH,OACAtD,KAAKC,sBAAsB+E,IACxBjE,QAASqB,IAAI,cAAcrB,aAAaA;UAE7Cf,KAAKyD,4BACH,OACAzD,KAAKG,uBAAuB6E,IACzBjE,QACCqB,IAAI,aAAarB,mBAAmBA;UAE1Cf,KAAKI,iBAAiB4E,IACrBjE,QAASqB,IAAI,cAAcrB,aAAaA;;;AAIjD;;;AA5WenB,kBAAAqE,YAAY,IAAIgB;;AAC/B;EAIEpF,oBAAkBoE,UAAUiB,cAAc;AAqB3C,EAzBD;;AAyDAC,WAAA,EADCC,SAAS;EAAEC,WAAW;MAC2CzF,kBAAA0F,WAAA;;AASlEH,WAAA,EADCC,SAAS;EAAEC,WAAW;MAC0CzF,kBAAA0F,WAAA;;AAgBjEH,WAAA,EADCC,cACwExF,kBAAA0F,WAAA;;AAsBzEH,WAAA,EADCC,cAC0ExF,kBAAA0F,WAAA;;AAO3EH,WAAA,EADCC,SAAS;EAAEC,WAAW;MACiCzF,kBAAA0F,WAAA;;AAOxDH,WAAA,EADCC,SAAS;EAAEC,WAAW;MACiCzF,kBAAA0F,WAAA;;AAMhDH,WAAA,EADPI,WAC4C3F,kBAAA0F,WAAA;;AAGrCH,WAAA,EADPI,WAC6C3F,kBAAA0F,WAAA;;AAGtCH,WAAA,EADPI,WAC6C3F,kBAAA0F,WAAA;;AAQtCH,WAAA,EADPI,WACuC3F,kBAAA0F,WAAA;;AAUhCH,WAAA,EADPI,WACgC3F,kBAAA0F,WAAA;;AAzJ7B1F,oBAAiBC,sBAAAsF,WAAA,EADtBK,cAAc,gCACT5F;;AAwbN,IAAA6F,4BAAe7F;;"}
@@ -360,6 +360,17 @@ function ChatContainer(props) {
360
360
  return;
361
361
  }
362
362
  event.preventDefault();
363
+ if (detail.element) {
364
+ const element = detail.element;
365
+ element.setAttribute("slot", detail.slotName);
366
+ if (!detail.isInline) {
367
+ element.style.marginBlockStart = "1rem";
368
+ }
369
+ if (element.parentElement !== wrapper) {
370
+ wrapper.appendChild(element);
371
+ }
372
+ return;
373
+ }
363
374
  let host = hosts.get(detail.slotName);
364
375
  if (!host) {
365
376
  host = document.createElement(detail.isInline ? "span" : "div");
@@ -370,8 +381,8 @@ function ChatContainer(props) {
370
381
  hosts.set(detail.slotName, host);
371
382
  wrapper.appendChild(host);
372
383
  }
373
- if (host.innerHTML !== detail.html) {
374
- host.innerHTML = detail.html;
384
+ if (host.innerHTML !== (detail.html ?? "")) {
385
+ host.innerHTML = detail.html ?? "";
375
386
  }
376
387
  };
377
388
  const handleUpdate = event => {
@@ -1 +1 @@
1
- {"version":3,"file":"aiChatEntry.js","sources":["../../../../src/globals/utils/readCarbonChatSession.ts","../../../../src/react/ChatContainer.tsx","../../../../src/react/ChatCustomElement.tsx"],"sourcesContent":["/*\n * Copyright IBM Corp. 2026\n *\n * This source code is licensed under the Apache-2.0 license found in the\n * LICENSE file in the root directory of this source tree.\n *\n * @license\n */\n\nimport { VERSION } from \"../../chat/utils/environmentVariables\";\nimport { PersistedState } from \"../../types/state/AppState\";\nimport { IS_SESSION_STORAGE } from \"../../chat/utils/browserUtils\";\nimport { getSuffix } from \"../../chat/services/NamespaceService\";\n\n/**\n * Reads and validates the Carbon AI Chat session from sessionStorage.\n * Returns null if no session exists, if the data is corrupt, or if the\n * session was written by a different version of the library (version mismatch).\n *\n * Pass the same namespace value as {@link PublicConfig.namespace} (if any).\n *\n * @category Utilities\n *\n * @example\n * const session = readCarbonChatSession();\n * const wasOpen = session?.viewState.mainWindow === true;\n *\n * @example\n * // With a namespace matching PublicConfig.namespace\n * const session = readCarbonChatSession(\"myapp\");\n * const wasOpen = session?.viewState.mainWindow === true;\n */\nfunction readCarbonChatSession(namespace?: string): PersistedState | null {\n try {\n if (!IS_SESSION_STORAGE()) {\n return null;\n }\n const key = `CARBON_CHAT_SESSION${getSuffix(namespace)}`;\n const raw = window.sessionStorage.getItem(key);\n if (!raw) {\n return null;\n }\n const session = JSON.parse(raw) as PersistedState;\n if (session?.version !== VERSION) {\n return null;\n }\n return session;\n } catch {\n return null;\n }\n}\n\nexport { readCarbonChatSession };\n","/*\n * Copyright IBM Corp. 2025, 2026\n *\n * This source code is licensed under the Apache-2.0 license found in the\n * LICENSE file in the root directory of this source tree.\n *\n * @license\n */\n\nimport { createComponent } from \"@lit/react\";\nimport { css, LitElement, PropertyValues } from \"lit\";\nimport React, {\n type HTMLAttributes,\n useCallback,\n useEffect,\n useMemo,\n useRef,\n useState,\n} from \"react\";\nimport { createPortal } from \"react-dom\";\n\nimport ChatAppEntry from \"../chat/ChatAppEntry\";\nimport { carbonElement } from \"@carbon/ai-chat-components/es-custom/globals/decorators/index.js\";\nimport { ChatContainerProps } from \"../types/component/ChatContainer\";\nimport { ChatInstance } from \"../types/instance/ChatInstance\";\nimport { BusEventType } from \"../types/events/eventBusTypes\";\nimport { PublicConfig } from \"../types/config/PublicConfig\";\nimport { isBrowser } from \"../chat/utils/browserUtils\";\n\n/**\n * This component creates a custom element protected by a shadow DOM to render the React application into. It creates\n * slotted elements for user_defined responses and for writable elements.\n *\n * The corresponding slots are defined within the React application and are rendered in place.\n */\n\n/**\n * Create a web component to host the React application. We do this so we can provide custom elements and user_defined responses as\n * slotted content so they maintain their own styling in a safe way.\n */\n@carbonElement(\"cds-custom-aichat-react\")\nclass ChatContainerReact extends LitElement {\n static styles = css`\n :host {\n width: 100%;\n height: 100%;\n }\n `;\n\n /**\n * Dispatch a custom event when the shadow DOM is ready\n * This ensures React can safely access shadowRoot\n */\n firstUpdated(changedProperties: PropertyValues) {\n super.firstUpdated(changedProperties);\n this.dispatchEvent(new CustomEvent(\"shadow-ready\", { bubbles: true }));\n }\n}\n\n// Wrap the custom element as a React component\nconst ReactChatContainer = React.memo(\n createComponent({\n tagName: \"cds-custom-aichat-react\",\n elementClass: ChatContainerReact,\n react: React,\n }),\n);\n\n/**\n * The ChatContainer controls rendering the React application into the shadow DOM of the cds-custom-aichat-react web component.\n * It also injects the writeable element and user_defined response slots into said web component.\n *\n * @category React\n */\nfunction ChatContainer(\n props: ChatContainerProps &\n Omit<HTMLAttributes<HTMLElement>, keyof ChatContainerProps>,\n) {\n const {\n onBeforeRender,\n onAfterRender,\n onViewChange,\n onViewPreChange,\n strings,\n serviceDeskFactory,\n serviceDesk,\n renderUserDefinedResponse,\n renderCustomMessageFooter,\n renderWriteableElements,\n element,\n // Flattened PublicConfig properties\n onError,\n openChatByDefault,\n disclaimer,\n disableCustomElementMobileEnhancements,\n debug,\n exposeServiceManagerForTesting,\n injectCarbonTheme,\n aiEnabled,\n shouldTakeFocusIfOpensAutomatically,\n namespace,\n shouldSanitizeHTML,\n header,\n history,\n layout,\n messaging,\n isReadonly,\n persistFeedback,\n assistantName,\n assistantAvatarUrl,\n locale,\n homescreen,\n launcher,\n input,\n keyboardShortcuts,\n upload,\n markdown,\n ...domProps\n } = props;\n // Reconstruct PublicConfig from flattened props\n const config = useMemo(\n (): PublicConfig => ({\n onError,\n openChatByDefault,\n disclaimer,\n disableCustomElementMobileEnhancements,\n debug,\n exposeServiceManagerForTesting,\n injectCarbonTheme,\n aiEnabled,\n shouldTakeFocusIfOpensAutomatically,\n namespace,\n shouldSanitizeHTML,\n header,\n history,\n layout,\n messaging,\n isReadonly,\n persistFeedback,\n assistantName,\n assistantAvatarUrl,\n locale,\n homescreen,\n launcher,\n input,\n keyboardShortcuts,\n upload,\n }),\n [\n onError,\n openChatByDefault,\n disclaimer,\n disableCustomElementMobileEnhancements,\n debug,\n exposeServiceManagerForTesting,\n injectCarbonTheme,\n aiEnabled,\n shouldTakeFocusIfOpensAutomatically,\n namespace,\n shouldSanitizeHTML,\n header,\n history,\n layout,\n messaging,\n isReadonly,\n persistFeedback,\n assistantName,\n assistantAvatarUrl,\n locale,\n homescreen,\n launcher,\n input,\n keyboardShortcuts,\n upload,\n ],\n );\n\n const wrapperRef = useRef(null); // Ref for the React wrapper component\n const [wrapper, setWrapper] = useState(null);\n const [container, setContainer] = useState<HTMLElement | null>(null); // Actual element we render the React Portal to in the Shadowroot.\n\n const [writeableElementSlots, setWriteableElementSlots] = useState<\n HTMLElement[]\n >([]);\n const [currentInstance, setCurrentInstance] = useState<ChatInstance>(null);\n\n /**\n * Setup the DOM nodes of both the web component to be able to inject slotted content into it, and the element inside the\n * shadow DOM we will inject our React application into.\n */\n useEffect(() => {\n if (!wrapperRef.current) {\n return null; // Early return when there's nothing to set up because the element isn't ready.\n }\n\n let eventListenerAdded = false;\n\n const wrapperElement = wrapperRef.current as unknown as ChatContainerReact;\n\n // We need to check if the element in the shadow DOM we are render the React application to exists.\n // If it doesn't, we need to create and append it.\n\n const handleShadowReady = () => {\n // Now we know shadowRoot is definitely available\n let reactElement = wrapperElement.shadowRoot.querySelector(\n \".cds-custom-aichat--react-app\",\n ) as HTMLElement;\n\n if (!reactElement) {\n reactElement = document.createElement(\"div\");\n reactElement.classList.add(\"cds-custom-aichat--react-app\");\n wrapperElement.shadowRoot.appendChild(reactElement);\n }\n\n if (wrapperElement !== wrapper) {\n setWrapper(wrapperElement);\n }\n if (reactElement !== container) {\n setContainer(reactElement);\n }\n };\n\n if (wrapperElement.shadowRoot) {\n // Already ready\n handleShadowReady();\n } else {\n // Wait for ready event\n eventListenerAdded = true;\n wrapperElement.addEventListener(\"shadow-ready\", handleShadowReady, {\n once: true,\n });\n }\n\n return () => {\n if (eventListenerAdded) {\n wrapperElement.removeEventListener(\"shadow-ready\", handleShadowReady);\n }\n };\n }, [container, wrapper, currentInstance]);\n\n /**\n * Here we write the slotted elements into the wrapper so they are passed into the application to be rendered in their slot.\n */\n useEffect(() => {\n if (wrapper) {\n const combinedNodes: HTMLElement[] = [...writeableElementSlots];\n const currentNodes: HTMLElement[] = Array.from(\n wrapper.childNodes,\n ) as HTMLElement[];\n\n // Append new nodes that aren't already in the container\n combinedNodes.forEach((node) => {\n if (!currentNodes.includes(node)) {\n wrapper.appendChild(node);\n }\n });\n }\n }, [writeableElementSlots, wrapper]);\n\n /**\n * Plugin-fallback slot hosts (e.g. KaTeX rendered by a markdown-it plugin)\n * need to live in the page light DOM so a consumer-loaded stylesheet can\n * reach them — the markdown element's own light DOM sits inside this\n * wrapper's shadow root, where global CSS doesn't apply. The markdown\n * element bubbles a composed `cds-custom-aichat-markdown-plugin-host-mount` event\n * for each new plugin slot; we accept the offer (`preventDefault()`),\n * create the host as a slot-attributed child of the wrapper (= page light\n * DOM, since this is the outermost chat element on the React path), and\n * tear it down when the matching unmount event fires.\n */\n useEffect(() => {\n if (!wrapper) {\n return undefined;\n }\n const hosts = new Map<string, HTMLElement>();\n const handleMount = (event: Event) => {\n const detail = (\n event as CustomEvent<{\n slotName: string;\n html: string;\n isInline: boolean;\n }>\n ).detail;\n if (!detail?.slotName) {\n return;\n }\n event.preventDefault();\n let host = hosts.get(detail.slotName);\n if (!host) {\n host = document.createElement(detail.isInline ? \"span\" : \"div\");\n host.setAttribute(\"slot\", detail.slotName);\n // Match the spacing applied to direct children of\n // `.cds-custom-aichat-markdown-stack`; shadow CSS doesn't reach this host\n // (we mounted it in page light DOM), so apply it inline. Inline\n // plugin output flows with text and gets no extra spacing.\n if (!detail.isInline) {\n host.style.marginBlockStart = \"1rem\";\n }\n hosts.set(detail.slotName, host);\n wrapper.appendChild(host);\n }\n if (host.innerHTML !== detail.html) {\n host.innerHTML = detail.html;\n }\n };\n const handleUpdate = (event: Event) => {\n const detail = (event as CustomEvent<{ slotName: string; html: string }>)\n .detail;\n if (!detail?.slotName) {\n return;\n }\n const host = hosts.get(detail.slotName);\n if (host && host.innerHTML !== detail.html) {\n host.innerHTML = detail.html;\n }\n };\n const handleUnmount = (event: Event) => {\n const detail = (event as CustomEvent<{ slotName: string }>).detail;\n if (!detail?.slotName) {\n return;\n }\n const host = hosts.get(detail.slotName);\n if (host) {\n host.remove();\n hosts.delete(detail.slotName);\n }\n };\n wrapper.addEventListener(\n \"cds-custom-aichat-markdown-plugin-host-mount\",\n handleMount,\n );\n wrapper.addEventListener(\n \"cds-custom-aichat-markdown-plugin-host-update\",\n handleUpdate,\n );\n wrapper.addEventListener(\n \"cds-custom-aichat-markdown-plugin-host-unmount\",\n handleUnmount,\n );\n return () => {\n wrapper.removeEventListener(\n \"cds-custom-aichat-markdown-plugin-host-mount\",\n handleMount,\n );\n wrapper.removeEventListener(\n \"cds-custom-aichat-markdown-plugin-host-update\",\n handleUpdate,\n );\n wrapper.removeEventListener(\n \"cds-custom-aichat-markdown-plugin-host-unmount\",\n handleUnmount,\n );\n for (const host of hosts.values()) {\n host.remove();\n }\n hosts.clear();\n };\n }, [wrapper]);\n\n const onBeforeRenderOverride = useCallback(\n (instance: ChatInstance) => {\n if (instance) {\n const addWriteableElementSlots = () => {\n const slots: HTMLElement[] = Object.entries(\n instance.writeableElements,\n ).map((writeableElement) => {\n const [key, element] = writeableElement;\n element.setAttribute(\"slot\", key); // Assign slot attributes dynamically\n return element;\n });\n setWriteableElementSlots(slots);\n };\n\n addWriteableElementSlots();\n\n // Opt-in view-change observation hooks. The float container manages\n // its own visibility, so there is no default handler — a prop is only\n // subscribed when the consumer provides it.\n if (onViewPreChange) {\n instance.on({\n type: BusEventType.VIEW_PRE_CHANGE,\n handler: onViewPreChange,\n });\n }\n if (onViewChange) {\n instance.on({\n type: BusEventType.VIEW_CHANGE,\n handler: onViewChange,\n });\n }\n\n onBeforeRender?.(instance);\n }\n },\n [onBeforeRender, onViewChange, onViewPreChange],\n );\n\n // If we are in SSR mode, just short circuit here. This prevents all of our window.* and document.* stuff from trying\n // to run and erroring out.\n if (!isBrowser()) {\n return null;\n }\n\n return (\n <>\n <ReactChatContainer ref={wrapperRef} {...domProps} />\n {container &&\n createPortal(\n <ChatAppEntry\n key=\"stable-chat-instance\"\n config={config}\n strings={strings}\n serviceDeskFactory={serviceDeskFactory}\n serviceDesk={serviceDesk}\n renderUserDefinedResponse={renderUserDefinedResponse}\n renderCustomMessageFooter={renderCustomMessageFooter}\n renderWriteableElements={renderWriteableElements}\n markdown={markdown}\n onBeforeRender={onBeforeRenderOverride}\n onAfterRender={onAfterRender}\n container={container}\n setParentInstance={setCurrentInstance}\n element={element}\n chatWrapper={wrapper}\n />,\n container,\n )}\n </>\n );\n}\n\nexport { ChatContainer, ChatContainerProps };\n","/*\n * Copyright IBM Corp. 2025, 2026\n *\n * This source code is licensed under the Apache-2.0 license found in the\n * LICENSE file in the root directory of this source tree.\n *\n * @license\n */\n\nimport React, {\n type HTMLAttributes,\n useCallback,\n useLayoutEffect,\n useRef,\n useState,\n} from \"react\";\n\nimport { ChatInstance } from \"../types/instance/ChatInstance\";\nimport {\n BusEventType,\n BusEventViewChange,\n BusEventViewPreChange,\n} from \"../types/events/eventBusTypes\";\nimport { ChatContainer, ChatContainerProps } from \"./ChatContainer\";\nimport { isBrowser } from \"../chat/utils/browserUtils\";\n\n/**\n * Properties for the ChatContainer React component. This interface extends\n * {@link ChatContainerProps} and {@link PublicConfig} with additional component-specific props, flattening all\n * config properties as top-level props for better TypeScript IntelliSense.\n *\n * @category React\n */\ninterface ChatCustomElementProps extends ChatContainerProps {\n /**\n * A CSS class name that will be added to the custom element. This class must define the size of the\n * your custom element (width and height or using logical inline-size/block-size).\n *\n * You can make use of onViewPreChange and/or onViewChange to mutate this className value so have open/close animations.\n *\n * By default, the chat will just set the chat shell to a 0x0 size and mark everything but the launcher (is you are using it)\n * as display: none; if the chat is set to closed.\n */\n className: string;\n\n /**\n * An optional id that will be added to the custom element.\n */\n id?: string;\n\n /**\n * Called before a view change (chat opening/closing). The chat will hide the chat shell inside your custom element\n * to prevent invisible keyboard stops when the view change is *complete*.\n *\n * Use this callback to update your className value *before* the view change happens if you want to add any open/close\n * animations to your custom element before the chat shell inner contents are hidden. It is async and so you can\n * tie it to native the AnimationEvent and only return when your animations have completed.\n *\n * A common pattern is to use this for when the chat is closing and to use onViewChange for when the chat opens.\n *\n * Note that this function can only be provided before Carbon AI Chat is loaded as it is registered before the\n * chat renders. After Carbon AI Chat is loaded, the callback will not be updated.\n */\n onViewPreChange?: (\n event: BusEventViewPreChange,\n instance: ChatInstance,\n ) => Promise<void> | void;\n\n /**\n * Called when the chat view change is complete. If no callback is provided here, the default behavior will be to set\n * the chat shell to 0x0 size and set all inner contents aside from the launcher, if you are using it, to display: none.\n * The inner contents of the chat shell (aside from the launcher if you are using it) are always set to display: none\n * regardless of what is configured with this callback to prevent invisible tab stops and screen reader issues.\n *\n * Use this callback to update your className value when the chat has finished being opened or closed.\n *\n * You can provide a different callback here if you want custom animation behavior when the chat is opened or closed.\n * The animation behavior defined here will run in concert with the chat inside your custom container being hidden.\n *\n * If you want to run animations before the inner contents of the chat shell is shrunk and the inner contents are hidden,\n * make use of onViewPreChange.\n *\n * A common pattern is to use this for when the chat is opening and to use onViewPreChange for when the chat closes.\n *\n * Note that this function can only be provided before Carbon AI Chat is loaded as it is registered before the\n * chat renders. After Carbon AI Chat is loaded, the callback will not be updated.\n */\n onViewChange?: (event: BusEventViewChange, instance: ChatInstance) => void;\n}\n\nconst customElementStylesheet =\n isBrowser() && typeof CSSStyleSheet !== \"undefined\"\n ? new CSSStyleSheet()\n : null;\n\nconst hideStyles = `\n .cds-custom-aichat--hidden {\n width: 0 !important;\n height: 0 !important;\n min-width: 0 !important;\n min-height: 0 !important;\n max-width: 0 !important;\n max-height: 0 !important;\n inline-size: 0 !important;\n block-size: 0 !important;\n min-inline-size: 0 !important;\n min-block-size: 0 !important;\n max-inline-size: 0 !important;\n max-block-size: 0 !important;\n overflow: hidden !important;\n }\n`;\n\n// Inject styles using adopted stylesheets when available, fallback to style element\nif (\n isBrowser() &&\n !document.getElementById(\"cds-custom-aichat-custom-element-styles\")\n) {\n if (customElementStylesheet && \"replaceSync\" in customElementStylesheet) {\n customElementStylesheet.replaceSync(hideStyles);\n document.adoptedStyleSheets = [\n ...document.adoptedStyleSheets,\n customElementStylesheet,\n ];\n } else {\n // Fallback for when adoptedStyleSheets are not supported\n const style = document.createElement(\"style\");\n style.id = \"cds-custom-aichat-custom-element-styles\";\n style.textContent = hideStyles;\n document.head.appendChild(style);\n }\n}\n\n/**\n * This is the React component for people injecting a Carbon AI Chat with a custom element.\n *\n * It provides said element any class or id defined on itself for styling. It then calls ChatContainer with the custom\n * element passed in as a property to be used instead of generating an element with the default properties for a\n * floating chat.\n *\n * @category React\n */\nfunction ChatCustomElement(\n props: ChatCustomElementProps &\n Omit<HTMLAttributes<HTMLDivElement>, keyof ChatCustomElementProps>,\n) {\n const {\n strings,\n serviceDeskFactory,\n serviceDesk,\n onBeforeRender,\n onAfterRender,\n renderUserDefinedResponse,\n renderCustomMessageFooter,\n renderWriteableElements,\n className,\n id,\n onViewChange,\n onViewPreChange,\n // Flattened PublicConfig properties\n onError,\n openChatByDefault,\n disclaimer,\n disableCustomElementMobileEnhancements,\n debug,\n exposeServiceManagerForTesting,\n injectCarbonTheme,\n aiEnabled,\n shouldTakeFocusIfOpensAutomatically,\n namespace,\n shouldSanitizeHTML,\n header,\n history,\n layout,\n messaging,\n isReadonly,\n persistFeedback,\n assistantName,\n assistantAvatarUrl,\n locale,\n homescreen,\n launcher,\n input,\n keyboardShortcuts,\n upload,\n markdown,\n ...domProps\n } = props;\n\n const containerRef = useRef<HTMLDivElement>(null);\n const [elementReady, setElementReady] = useState(false);\n\n useLayoutEffect(() => {\n setElementReady(true);\n }, []);\n\n const onBeforeRenderOverride = useCallback(\n async (instance: ChatInstance) => {\n /**\n * A default handler for the \"view:change\" event. This will be used to show or hide the Carbon AI Chat main window\n * by adding/removing a CSS class that sets the element size to 0x0 when hidden.\n */\n function defaultViewChangeHandler(event: BusEventViewChange) {\n const el = containerRef.current;\n if (el) {\n if (event.newViewState.mainWindow) {\n // Show: remove the hidden class, let the provided className handle sizing\n el.classList.remove(\"cds-custom-aichat--hidden\");\n } else {\n // Hide: add the hidden class to set size to 0x0\n el.classList.add(\"cds-custom-aichat--hidden\");\n }\n }\n }\n\n if (onViewPreChange) {\n instance.on({\n type: BusEventType.VIEW_PRE_CHANGE,\n handler: onViewPreChange,\n });\n }\n\n instance.on({\n type: BusEventType.VIEW_CHANGE,\n handler: onViewChange || defaultViewChangeHandler,\n });\n\n return onBeforeRender?.(instance);\n },\n [onViewPreChange, onViewChange, onBeforeRender],\n );\n\n return (\n <div className={className} id={id} ref={containerRef} {...domProps}>\n {elementReady && containerRef.current && (\n <ChatContainer\n // Flattened PublicConfig properties\n onError={onError}\n openChatByDefault={openChatByDefault}\n disclaimer={disclaimer}\n disableCustomElementMobileEnhancements={\n disableCustomElementMobileEnhancements\n }\n debug={debug}\n exposeServiceManagerForTesting={exposeServiceManagerForTesting}\n injectCarbonTheme={injectCarbonTheme}\n aiEnabled={aiEnabled}\n shouldTakeFocusIfOpensAutomatically={\n shouldTakeFocusIfOpensAutomatically\n }\n namespace={namespace}\n shouldSanitizeHTML={shouldSanitizeHTML}\n header={header}\n history={history}\n layout={layout}\n messaging={messaging}\n isReadonly={isReadonly}\n persistFeedback={persistFeedback}\n assistantName={assistantName}\n assistantAvatarUrl={assistantAvatarUrl}\n locale={locale}\n homescreen={homescreen}\n launcher={launcher}\n input={input}\n keyboardShortcuts={keyboardShortcuts}\n upload={upload}\n markdown={markdown}\n // Other ChatContainer props\n strings={strings}\n serviceDeskFactory={serviceDeskFactory}\n serviceDesk={serviceDesk}\n onBeforeRender={onBeforeRenderOverride}\n onAfterRender={onAfterRender}\n renderUserDefinedResponse={renderUserDefinedResponse}\n renderCustomMessageFooter={renderCustomMessageFooter}\n renderWriteableElements={renderWriteableElements}\n element={containerRef.current}\n />\n )}\n </div>\n );\n}\n\nexport { ChatCustomElement, ChatCustomElementProps };\n"],"names":["readCarbonChatSession","namespace","IS_SESSION_STORAGE","key","getSuffix","raw","window","sessionStorage","getItem","session","JSON","parse","version","VERSION","ChatContainerReact","LitElement","firstUpdated","changedProperties","super","this","dispatchEvent","CustomEvent","bubbles","styles","css","__decorate","carbonElement","ReactChatContainer","React","memo","createComponent","tagName","elementClass","react","ChatContainer","props","onBeforeRender","onAfterRender","onViewChange","onViewPreChange","strings","serviceDeskFactory","serviceDesk","renderUserDefinedResponse","renderCustomMessageFooter","renderWriteableElements","element","onError","openChatByDefault","disclaimer","disableCustomElementMobileEnhancements","debug","exposeServiceManagerForTesting","injectCarbonTheme","aiEnabled","shouldTakeFocusIfOpensAutomatically","shouldSanitizeHTML","header","history","layout","messaging","isReadonly","persistFeedback","assistantName","assistantAvatarUrl","locale","homescreen","launcher","input","keyboardShortcuts","upload","markdown","domProps","config","useMemo","wrapperRef","useRef","wrapper","setWrapper","useState","container","setContainer","writeableElementSlots","setWriteableElementSlots","currentInstance","setCurrentInstance","useEffect","current","eventListenerAdded","wrapperElement","handleShadowReady","reactElement","shadowRoot","querySelector","document","createElement","classList","add","appendChild","addEventListener","once","removeEventListener","combinedNodes","currentNodes","Array","from","childNodes","forEach","node","includes","undefined","hosts","Map","handleMount","event","detail","slotName","preventDefault","host","get","isInline","setAttribute","style","marginBlockStart","set","innerHTML","html","handleUpdate","handleUnmount","remove","delete","values","clear","onBeforeRenderOverride","useCallback","instance","addWriteableElementSlots","slots","Object","entries","writeableElements","map","writeableElement","on","type","BusEventType","VIEW_PRE_CHANGE","handler","VIEW_CHANGE","isBrowser","Fragment","ref","createPortal","ChatAppEntry","setParentInstance","chatWrapper","customElementStylesheet","CSSStyleSheet","hideStyles","getElementById","replaceSync","adoptedStyleSheets","id","textContent","head","ChatCustomElement","className","containerRef","elementReady","setElementReady","useLayoutEffect","async","defaultViewChangeHandler","el","newViewState","mainWindow"],"mappings":"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"}
1
+ {"version":3,"file":"aiChatEntry.js","sources":["../../../../src/globals/utils/readCarbonChatSession.ts","../../../../src/react/ChatContainer.tsx","../../../../src/react/ChatCustomElement.tsx"],"sourcesContent":["/*\n * Copyright IBM Corp. 2026\n *\n * This source code is licensed under the Apache-2.0 license found in the\n * LICENSE file in the root directory of this source tree.\n *\n * @license\n */\n\nimport { VERSION } from \"../../chat/utils/environmentVariables\";\nimport { PersistedState } from \"../../types/state/AppState\";\nimport { IS_SESSION_STORAGE } from \"../../chat/utils/browserUtils\";\nimport { getSuffix } from \"../../chat/services/NamespaceService\";\n\n/**\n * Reads and validates the Carbon AI Chat session from sessionStorage.\n * Returns null if no session exists, if the data is corrupt, or if the\n * session was written by a different version of the library (version mismatch).\n *\n * Pass the same namespace value as {@link PublicConfig.namespace} (if any).\n *\n * @category Utilities\n *\n * @example\n * const session = readCarbonChatSession();\n * const wasOpen = session?.viewState.mainWindow === true;\n *\n * @example\n * // With a namespace matching PublicConfig.namespace\n * const session = readCarbonChatSession(\"myapp\");\n * const wasOpen = session?.viewState.mainWindow === true;\n */\nfunction readCarbonChatSession(namespace?: string): PersistedState | null {\n try {\n if (!IS_SESSION_STORAGE()) {\n return null;\n }\n const key = `CARBON_CHAT_SESSION${getSuffix(namespace)}`;\n const raw = window.sessionStorage.getItem(key);\n if (!raw) {\n return null;\n }\n const session = JSON.parse(raw) as PersistedState;\n if (session?.version !== VERSION) {\n return null;\n }\n return session;\n } catch {\n return null;\n }\n}\n\nexport { readCarbonChatSession };\n","/*\n * Copyright IBM Corp. 2025, 2026\n *\n * This source code is licensed under the Apache-2.0 license found in the\n * LICENSE file in the root directory of this source tree.\n *\n * @license\n */\n\nimport { createComponent } from \"@lit/react\";\nimport { css, LitElement, PropertyValues } from \"lit\";\nimport React, {\n type HTMLAttributes,\n useCallback,\n useEffect,\n useMemo,\n useRef,\n useState,\n} from \"react\";\nimport { createPortal } from \"react-dom\";\n\nimport ChatAppEntry from \"../chat/ChatAppEntry\";\nimport { carbonElement } from \"@carbon/ai-chat-components/es-custom/globals/decorators/index.js\";\nimport { ChatContainerProps } from \"../types/component/ChatContainer\";\nimport { ChatInstance } from \"../types/instance/ChatInstance\";\nimport { BusEventType } from \"../types/events/eventBusTypes\";\nimport { PublicConfig } from \"../types/config/PublicConfig\";\nimport { isBrowser } from \"../chat/utils/browserUtils\";\n\n/**\n * This component creates a custom element protected by a shadow DOM to render the React application into. It creates\n * slotted elements for user_defined responses and for writable elements.\n *\n * The corresponding slots are defined within the React application and are rendered in place.\n */\n\n/**\n * Create a web component to host the React application. We do this so we can provide custom elements and user_defined responses as\n * slotted content so they maintain their own styling in a safe way.\n */\n@carbonElement(\"cds-custom-aichat-react\")\nclass ChatContainerReact extends LitElement {\n static styles = css`\n :host {\n width: 100%;\n height: 100%;\n }\n `;\n\n /**\n * Dispatch a custom event when the shadow DOM is ready\n * This ensures React can safely access shadowRoot\n */\n firstUpdated(changedProperties: PropertyValues) {\n super.firstUpdated(changedProperties);\n this.dispatchEvent(new CustomEvent(\"shadow-ready\", { bubbles: true }));\n }\n}\n\n// Wrap the custom element as a React component\nconst ReactChatContainer = React.memo(\n createComponent({\n tagName: \"cds-custom-aichat-react\",\n elementClass: ChatContainerReact,\n react: React,\n }),\n);\n\n/**\n * The ChatContainer controls rendering the React application into the shadow DOM of the cds-custom-aichat-react web component.\n * It also injects the writeable element and user_defined response slots into said web component.\n *\n * @category React\n */\nfunction ChatContainer(\n props: ChatContainerProps &\n Omit<HTMLAttributes<HTMLElement>, keyof ChatContainerProps>,\n) {\n const {\n onBeforeRender,\n onAfterRender,\n onViewChange,\n onViewPreChange,\n strings,\n serviceDeskFactory,\n serviceDesk,\n renderUserDefinedResponse,\n renderCustomMessageFooter,\n renderWriteableElements,\n element,\n // Flattened PublicConfig properties\n onError,\n openChatByDefault,\n disclaimer,\n disableCustomElementMobileEnhancements,\n debug,\n exposeServiceManagerForTesting,\n injectCarbonTheme,\n aiEnabled,\n shouldTakeFocusIfOpensAutomatically,\n namespace,\n shouldSanitizeHTML,\n header,\n history,\n layout,\n messaging,\n isReadonly,\n persistFeedback,\n assistantName,\n assistantAvatarUrl,\n locale,\n homescreen,\n launcher,\n input,\n keyboardShortcuts,\n upload,\n markdown,\n ...domProps\n } = props;\n // Reconstruct PublicConfig from flattened props\n const config = useMemo(\n (): PublicConfig => ({\n onError,\n openChatByDefault,\n disclaimer,\n disableCustomElementMobileEnhancements,\n debug,\n exposeServiceManagerForTesting,\n injectCarbonTheme,\n aiEnabled,\n shouldTakeFocusIfOpensAutomatically,\n namespace,\n shouldSanitizeHTML,\n header,\n history,\n layout,\n messaging,\n isReadonly,\n persistFeedback,\n assistantName,\n assistantAvatarUrl,\n locale,\n homescreen,\n launcher,\n input,\n keyboardShortcuts,\n upload,\n }),\n [\n onError,\n openChatByDefault,\n disclaimer,\n disableCustomElementMobileEnhancements,\n debug,\n exposeServiceManagerForTesting,\n injectCarbonTheme,\n aiEnabled,\n shouldTakeFocusIfOpensAutomatically,\n namespace,\n shouldSanitizeHTML,\n header,\n history,\n layout,\n messaging,\n isReadonly,\n persistFeedback,\n assistantName,\n assistantAvatarUrl,\n locale,\n homescreen,\n launcher,\n input,\n keyboardShortcuts,\n upload,\n ],\n );\n\n const wrapperRef = useRef(null); // Ref for the React wrapper component\n const [wrapper, setWrapper] = useState(null);\n const [container, setContainer] = useState<HTMLElement | null>(null); // Actual element we render the React Portal to in the Shadowroot.\n\n const [writeableElementSlots, setWriteableElementSlots] = useState<\n HTMLElement[]\n >([]);\n const [currentInstance, setCurrentInstance] = useState<ChatInstance>(null);\n\n /**\n * Setup the DOM nodes of both the web component to be able to inject slotted content into it, and the element inside the\n * shadow DOM we will inject our React application into.\n */\n useEffect(() => {\n if (!wrapperRef.current) {\n return null; // Early return when there's nothing to set up because the element isn't ready.\n }\n\n let eventListenerAdded = false;\n\n const wrapperElement = wrapperRef.current as unknown as ChatContainerReact;\n\n // We need to check if the element in the shadow DOM we are render the React application to exists.\n // If it doesn't, we need to create and append it.\n\n const handleShadowReady = () => {\n // Now we know shadowRoot is definitely available\n let reactElement = wrapperElement.shadowRoot.querySelector(\n \".cds-custom-aichat--react-app\",\n ) as HTMLElement;\n\n if (!reactElement) {\n reactElement = document.createElement(\"div\");\n reactElement.classList.add(\"cds-custom-aichat--react-app\");\n wrapperElement.shadowRoot.appendChild(reactElement);\n }\n\n if (wrapperElement !== wrapper) {\n setWrapper(wrapperElement);\n }\n if (reactElement !== container) {\n setContainer(reactElement);\n }\n };\n\n if (wrapperElement.shadowRoot) {\n // Already ready\n handleShadowReady();\n } else {\n // Wait for ready event\n eventListenerAdded = true;\n wrapperElement.addEventListener(\"shadow-ready\", handleShadowReady, {\n once: true,\n });\n }\n\n return () => {\n if (eventListenerAdded) {\n wrapperElement.removeEventListener(\"shadow-ready\", handleShadowReady);\n }\n };\n }, [container, wrapper, currentInstance]);\n\n /**\n * Here we write the slotted elements into the wrapper so they are passed into the application to be rendered in their slot.\n */\n useEffect(() => {\n if (wrapper) {\n const combinedNodes: HTMLElement[] = [...writeableElementSlots];\n const currentNodes: HTMLElement[] = Array.from(\n wrapper.childNodes,\n ) as HTMLElement[];\n\n // Append new nodes that aren't already in the container\n combinedNodes.forEach((node) => {\n if (!currentNodes.includes(node)) {\n wrapper.appendChild(node);\n }\n });\n }\n }, [writeableElementSlots, wrapper]);\n\n /**\n * Plugin-fallback slot hosts (e.g. KaTeX rendered by a markdown-it plugin)\n * need to live in the page light DOM so a consumer-loaded stylesheet can\n * reach them — the markdown element's own light DOM sits inside this\n * wrapper's shadow root, where global CSS doesn't apply. The markdown\n * element bubbles a composed `cds-custom-aichat-markdown-plugin-host-mount` event\n * for each new plugin slot; we accept the offer (`preventDefault()`),\n * create the host as a slot-attributed child of the wrapper (= page light\n * DOM, since this is the outermost chat element on the React path), and\n * tear it down when the matching unmount event fires.\n */\n useEffect(() => {\n if (!wrapper) {\n return undefined;\n }\n const hosts = new Map<string, HTMLElement>();\n const handleMount = (event: Event) => {\n const detail = (\n event as CustomEvent<{\n slotName: string;\n html?: string;\n element?: HTMLElement;\n isInline: boolean;\n }>\n ).detail;\n if (!detail?.slotName) {\n return;\n }\n event.preventDefault();\n // Custom-renderer hosts (table/codeBlock) forward a live element — the\n // markdown element keeps ownership of its content; we only relocate the\n // node into page light DOM so the consumer's global CSS reaches it.\n // Plugin fallbacks forward an HTML string instead.\n if (detail.element) {\n const element = detail.element;\n element.setAttribute(\"slot\", detail.slotName);\n if (!detail.isInline) {\n element.style.marginBlockStart = \"1rem\";\n }\n if (element.parentElement !== wrapper) {\n wrapper.appendChild(element);\n }\n return;\n }\n let host = hosts.get(detail.slotName);\n if (!host) {\n host = document.createElement(detail.isInline ? \"span\" : \"div\");\n host.setAttribute(\"slot\", detail.slotName);\n // Match the spacing applied to direct children of\n // `.cds-custom-aichat-markdown-stack`; shadow CSS doesn't reach this host\n // (we mounted it in page light DOM), so apply it inline. Inline\n // plugin output flows with text and gets no extra spacing.\n if (!detail.isInline) {\n host.style.marginBlockStart = \"1rem\";\n }\n hosts.set(detail.slotName, host);\n wrapper.appendChild(host);\n }\n if (host.innerHTML !== (detail.html ?? \"\")) {\n host.innerHTML = detail.html ?? \"\";\n }\n };\n const handleUpdate = (event: Event) => {\n const detail = (event as CustomEvent<{ slotName: string; html: string }>)\n .detail;\n if (!detail?.slotName) {\n return;\n }\n const host = hosts.get(detail.slotName);\n if (host && host.innerHTML !== detail.html) {\n host.innerHTML = detail.html;\n }\n };\n const handleUnmount = (event: Event) => {\n const detail = (event as CustomEvent<{ slotName: string }>).detail;\n if (!detail?.slotName) {\n return;\n }\n const host = hosts.get(detail.slotName);\n if (host) {\n host.remove();\n hosts.delete(detail.slotName);\n }\n };\n wrapper.addEventListener(\n \"cds-custom-aichat-markdown-plugin-host-mount\",\n handleMount,\n );\n wrapper.addEventListener(\n \"cds-custom-aichat-markdown-plugin-host-update\",\n handleUpdate,\n );\n wrapper.addEventListener(\n \"cds-custom-aichat-markdown-plugin-host-unmount\",\n handleUnmount,\n );\n return () => {\n wrapper.removeEventListener(\n \"cds-custom-aichat-markdown-plugin-host-mount\",\n handleMount,\n );\n wrapper.removeEventListener(\n \"cds-custom-aichat-markdown-plugin-host-update\",\n handleUpdate,\n );\n wrapper.removeEventListener(\n \"cds-custom-aichat-markdown-plugin-host-unmount\",\n handleUnmount,\n );\n for (const host of hosts.values()) {\n host.remove();\n }\n hosts.clear();\n };\n }, [wrapper]);\n\n const onBeforeRenderOverride = useCallback(\n (instance: ChatInstance) => {\n if (instance) {\n const addWriteableElementSlots = () => {\n const slots: HTMLElement[] = Object.entries(\n instance.writeableElements,\n ).map((writeableElement) => {\n const [key, element] = writeableElement;\n element.setAttribute(\"slot\", key); // Assign slot attributes dynamically\n return element;\n });\n setWriteableElementSlots(slots);\n };\n\n addWriteableElementSlots();\n\n // Opt-in view-change observation hooks. The float container manages\n // its own visibility, so there is no default handler — a prop is only\n // subscribed when the consumer provides it.\n if (onViewPreChange) {\n instance.on({\n type: BusEventType.VIEW_PRE_CHANGE,\n handler: onViewPreChange,\n });\n }\n if (onViewChange) {\n instance.on({\n type: BusEventType.VIEW_CHANGE,\n handler: onViewChange,\n });\n }\n\n onBeforeRender?.(instance);\n }\n },\n [onBeforeRender, onViewChange, onViewPreChange],\n );\n\n // If we are in SSR mode, just short circuit here. This prevents all of our window.* and document.* stuff from trying\n // to run and erroring out.\n if (!isBrowser()) {\n return null;\n }\n\n return (\n <>\n <ReactChatContainer ref={wrapperRef} {...domProps} />\n {container &&\n createPortal(\n <ChatAppEntry\n key=\"stable-chat-instance\"\n config={config}\n strings={strings}\n serviceDeskFactory={serviceDeskFactory}\n serviceDesk={serviceDesk}\n renderUserDefinedResponse={renderUserDefinedResponse}\n renderCustomMessageFooter={renderCustomMessageFooter}\n renderWriteableElements={renderWriteableElements}\n markdown={markdown}\n onBeforeRender={onBeforeRenderOverride}\n onAfterRender={onAfterRender}\n container={container}\n setParentInstance={setCurrentInstance}\n element={element}\n chatWrapper={wrapper}\n />,\n container,\n )}\n </>\n );\n}\n\nexport { ChatContainer, ChatContainerProps };\n","/*\n * Copyright IBM Corp. 2025, 2026\n *\n * This source code is licensed under the Apache-2.0 license found in the\n * LICENSE file in the root directory of this source tree.\n *\n * @license\n */\n\nimport React, {\n type HTMLAttributes,\n useCallback,\n useLayoutEffect,\n useRef,\n useState,\n} from \"react\";\n\nimport { ChatInstance } from \"../types/instance/ChatInstance\";\nimport {\n BusEventType,\n BusEventViewChange,\n BusEventViewPreChange,\n} from \"../types/events/eventBusTypes\";\nimport { ChatContainer, ChatContainerProps } from \"./ChatContainer\";\nimport { isBrowser } from \"../chat/utils/browserUtils\";\n\n/**\n * Properties for the ChatContainer React component. This interface extends\n * {@link ChatContainerProps} and {@link PublicConfig} with additional component-specific props, flattening all\n * config properties as top-level props for better TypeScript IntelliSense.\n *\n * @category React\n */\ninterface ChatCustomElementProps extends ChatContainerProps {\n /**\n * A CSS class name that will be added to the custom element. This class must define the size of the\n * your custom element (width and height or using logical inline-size/block-size).\n *\n * You can make use of onViewPreChange and/or onViewChange to mutate this className value so have open/close animations.\n *\n * By default, the chat will just set the chat shell to a 0x0 size and mark everything but the launcher (is you are using it)\n * as display: none; if the chat is set to closed.\n */\n className: string;\n\n /**\n * An optional id that will be added to the custom element.\n */\n id?: string;\n\n /**\n * Called before a view change (chat opening/closing). The chat will hide the chat shell inside your custom element\n * to prevent invisible keyboard stops when the view change is *complete*.\n *\n * Use this callback to update your className value *before* the view change happens if you want to add any open/close\n * animations to your custom element before the chat shell inner contents are hidden. It is async and so you can\n * tie it to native the AnimationEvent and only return when your animations have completed.\n *\n * A common pattern is to use this for when the chat is closing and to use onViewChange for when the chat opens.\n *\n * Note that this function can only be provided before Carbon AI Chat is loaded as it is registered before the\n * chat renders. After Carbon AI Chat is loaded, the callback will not be updated.\n */\n onViewPreChange?: (\n event: BusEventViewPreChange,\n instance: ChatInstance,\n ) => Promise<void> | void;\n\n /**\n * Called when the chat view change is complete. If no callback is provided here, the default behavior will be to set\n * the chat shell to 0x0 size and set all inner contents aside from the launcher, if you are using it, to display: none.\n * The inner contents of the chat shell (aside from the launcher if you are using it) are always set to display: none\n * regardless of what is configured with this callback to prevent invisible tab stops and screen reader issues.\n *\n * Use this callback to update your className value when the chat has finished being opened or closed.\n *\n * You can provide a different callback here if you want custom animation behavior when the chat is opened or closed.\n * The animation behavior defined here will run in concert with the chat inside your custom container being hidden.\n *\n * If you want to run animations before the inner contents of the chat shell is shrunk and the inner contents are hidden,\n * make use of onViewPreChange.\n *\n * A common pattern is to use this for when the chat is opening and to use onViewPreChange for when the chat closes.\n *\n * Note that this function can only be provided before Carbon AI Chat is loaded as it is registered before the\n * chat renders. After Carbon AI Chat is loaded, the callback will not be updated.\n */\n onViewChange?: (event: BusEventViewChange, instance: ChatInstance) => void;\n}\n\nconst customElementStylesheet =\n isBrowser() && typeof CSSStyleSheet !== \"undefined\"\n ? new CSSStyleSheet()\n : null;\n\nconst hideStyles = `\n .cds-custom-aichat--hidden {\n width: 0 !important;\n height: 0 !important;\n min-width: 0 !important;\n min-height: 0 !important;\n max-width: 0 !important;\n max-height: 0 !important;\n inline-size: 0 !important;\n block-size: 0 !important;\n min-inline-size: 0 !important;\n min-block-size: 0 !important;\n max-inline-size: 0 !important;\n max-block-size: 0 !important;\n overflow: hidden !important;\n }\n`;\n\n// Inject styles using adopted stylesheets when available, fallback to style element\nif (\n isBrowser() &&\n !document.getElementById(\"cds-custom-aichat-custom-element-styles\")\n) {\n if (customElementStylesheet && \"replaceSync\" in customElementStylesheet) {\n customElementStylesheet.replaceSync(hideStyles);\n document.adoptedStyleSheets = [\n ...document.adoptedStyleSheets,\n customElementStylesheet,\n ];\n } else {\n // Fallback for when adoptedStyleSheets are not supported\n const style = document.createElement(\"style\");\n style.id = \"cds-custom-aichat-custom-element-styles\";\n style.textContent = hideStyles;\n document.head.appendChild(style);\n }\n}\n\n/**\n * This is the React component for people injecting a Carbon AI Chat with a custom element.\n *\n * It provides said element any class or id defined on itself for styling. It then calls ChatContainer with the custom\n * element passed in as a property to be used instead of generating an element with the default properties for a\n * floating chat.\n *\n * @category React\n */\nfunction ChatCustomElement(\n props: ChatCustomElementProps &\n Omit<HTMLAttributes<HTMLDivElement>, keyof ChatCustomElementProps>,\n) {\n const {\n strings,\n serviceDeskFactory,\n serviceDesk,\n onBeforeRender,\n onAfterRender,\n renderUserDefinedResponse,\n renderCustomMessageFooter,\n renderWriteableElements,\n className,\n id,\n onViewChange,\n onViewPreChange,\n // Flattened PublicConfig properties\n onError,\n openChatByDefault,\n disclaimer,\n disableCustomElementMobileEnhancements,\n debug,\n exposeServiceManagerForTesting,\n injectCarbonTheme,\n aiEnabled,\n shouldTakeFocusIfOpensAutomatically,\n namespace,\n shouldSanitizeHTML,\n header,\n history,\n layout,\n messaging,\n isReadonly,\n persistFeedback,\n assistantName,\n assistantAvatarUrl,\n locale,\n homescreen,\n launcher,\n input,\n keyboardShortcuts,\n upload,\n markdown,\n ...domProps\n } = props;\n\n const containerRef = useRef<HTMLDivElement>(null);\n const [elementReady, setElementReady] = useState(false);\n\n useLayoutEffect(() => {\n setElementReady(true);\n }, []);\n\n const onBeforeRenderOverride = useCallback(\n async (instance: ChatInstance) => {\n /**\n * A default handler for the \"view:change\" event. This will be used to show or hide the Carbon AI Chat main window\n * by adding/removing a CSS class that sets the element size to 0x0 when hidden.\n */\n function defaultViewChangeHandler(event: BusEventViewChange) {\n const el = containerRef.current;\n if (el) {\n if (event.newViewState.mainWindow) {\n // Show: remove the hidden class, let the provided className handle sizing\n el.classList.remove(\"cds-custom-aichat--hidden\");\n } else {\n // Hide: add the hidden class to set size to 0x0\n el.classList.add(\"cds-custom-aichat--hidden\");\n }\n }\n }\n\n if (onViewPreChange) {\n instance.on({\n type: BusEventType.VIEW_PRE_CHANGE,\n handler: onViewPreChange,\n });\n }\n\n instance.on({\n type: BusEventType.VIEW_CHANGE,\n handler: onViewChange || defaultViewChangeHandler,\n });\n\n return onBeforeRender?.(instance);\n },\n [onViewPreChange, onViewChange, onBeforeRender],\n );\n\n return (\n <div className={className} id={id} ref={containerRef} {...domProps}>\n {elementReady && containerRef.current && (\n <ChatContainer\n // Flattened PublicConfig properties\n onError={onError}\n openChatByDefault={openChatByDefault}\n disclaimer={disclaimer}\n disableCustomElementMobileEnhancements={\n disableCustomElementMobileEnhancements\n }\n debug={debug}\n exposeServiceManagerForTesting={exposeServiceManagerForTesting}\n injectCarbonTheme={injectCarbonTheme}\n aiEnabled={aiEnabled}\n shouldTakeFocusIfOpensAutomatically={\n shouldTakeFocusIfOpensAutomatically\n }\n namespace={namespace}\n shouldSanitizeHTML={shouldSanitizeHTML}\n header={header}\n history={history}\n layout={layout}\n messaging={messaging}\n isReadonly={isReadonly}\n persistFeedback={persistFeedback}\n assistantName={assistantName}\n assistantAvatarUrl={assistantAvatarUrl}\n locale={locale}\n homescreen={homescreen}\n launcher={launcher}\n input={input}\n keyboardShortcuts={keyboardShortcuts}\n upload={upload}\n markdown={markdown}\n // Other ChatContainer props\n strings={strings}\n serviceDeskFactory={serviceDeskFactory}\n serviceDesk={serviceDesk}\n onBeforeRender={onBeforeRenderOverride}\n onAfterRender={onAfterRender}\n renderUserDefinedResponse={renderUserDefinedResponse}\n renderCustomMessageFooter={renderCustomMessageFooter}\n renderWriteableElements={renderWriteableElements}\n element={containerRef.current}\n />\n )}\n </div>\n );\n}\n\nexport { ChatCustomElement, ChatCustomElementProps };\n"],"names":["readCarbonChatSession","namespace","IS_SESSION_STORAGE","key","getSuffix","raw","window","sessionStorage","getItem","session","JSON","parse","version","VERSION","ChatContainerReact","LitElement","firstUpdated","changedProperties","super","this","dispatchEvent","CustomEvent","bubbles","styles","css","__decorate","carbonElement","ReactChatContainer","React","memo","createComponent","tagName","elementClass","react","ChatContainer","props","onBeforeRender","onAfterRender","onViewChange","onViewPreChange","strings","serviceDeskFactory","serviceDesk","renderUserDefinedResponse","renderCustomMessageFooter","renderWriteableElements","element","onError","openChatByDefault","disclaimer","disableCustomElementMobileEnhancements","debug","exposeServiceManagerForTesting","injectCarbonTheme","aiEnabled","shouldTakeFocusIfOpensAutomatically","shouldSanitizeHTML","header","history","layout","messaging","isReadonly","persistFeedback","assistantName","assistantAvatarUrl","locale","homescreen","launcher","input","keyboardShortcuts","upload","markdown","domProps","config","useMemo","wrapperRef","useRef","wrapper","setWrapper","useState","container","setContainer","writeableElementSlots","setWriteableElementSlots","currentInstance","setCurrentInstance","useEffect","current","eventListenerAdded","wrapperElement","handleShadowReady","reactElement","shadowRoot","querySelector","document","createElement","classList","add","appendChild","addEventListener","once","removeEventListener","combinedNodes","currentNodes","Array","from","childNodes","forEach","node","includes","undefined","hosts","Map","handleMount","event","detail","slotName","preventDefault","setAttribute","isInline","style","marginBlockStart","parentElement","host","get","set","innerHTML","html","handleUpdate","handleUnmount","remove","delete","values","clear","onBeforeRenderOverride","useCallback","instance","addWriteableElementSlots","slots","Object","entries","writeableElements","map","writeableElement","on","type","BusEventType","VIEW_PRE_CHANGE","handler","VIEW_CHANGE","isBrowser","Fragment","ref","createPortal","ChatAppEntry","setParentInstance","chatWrapper","customElementStylesheet","CSSStyleSheet","hideStyles","getElementById","replaceSync","adoptedStyleSheets","id","textContent","head","ChatCustomElement","className","containerRef","elementReady","setElementReady","useLayoutEffect","async","defaultViewChangeHandler","el","newViewState","mainWindow"],"mappings":"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"}