@noodleseed/assistant 1.21.0 → 1.22.0

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
package/dist/index.cjs CHANGED
@@ -31596,6 +31596,33 @@ var AssistantElementPageContextController = class {
31596
31596
  }
31597
31597
  };
31598
31598
 
31599
+ // src/element-presentation-gate.ts
31600
+ var AssistantElementPresentationGate = class {
31601
+ #host;
31602
+ #primeSession;
31603
+ #focusComposer;
31604
+ constructor(host, primeSession, focusComposer) {
31605
+ this.#host = host;
31606
+ this.#primeSession = primeSession;
31607
+ this.#focusComposer = focusComposer;
31608
+ }
31609
+ syncOpenState() {
31610
+ const open = this.#host.hasAttribute("open");
31611
+ const presentationReady = this.#host.hasAttribute("data-presentation-ready");
31612
+ const launcher = this.#host.shadowRoot?.querySelector(".launcher");
31613
+ launcher?.setAttribute("aria-expanded", String(open && presentationReady));
31614
+ launcher?.setAttribute("aria-busy", String(open && !presentationReady));
31615
+ if (launcher) launcher.disabled = open && !presentationReady;
31616
+ if (open && this.#host.isConnected) this.#primeSession();
31617
+ }
31618
+ reveal() {
31619
+ if (this.#host.hasAttribute("data-presentation-ready")) return;
31620
+ this.#host.setAttribute("data-presentation-ready", "");
31621
+ this.syncOpenState();
31622
+ if (this.#host.hasAttribute("open")) queueMicrotask(this.#focusComposer);
31623
+ }
31624
+ };
31625
+
31599
31626
  // src/element-scroll-controller.ts
31600
31627
  var AssistantElementScrollController = class {
31601
31628
  #region;
@@ -31711,9 +31738,10 @@ var ASSISTANT_ELEMENT_STYLES = `<style>
31711
31738
  .launcher:hover { transform: translateY(-2px) scale(1.03); box-shadow: 0 8px 26px rgba(0,0,0,.16); }
31712
31739
  .launcher img { width: 28px; height: 28px; border-radius: 50%; object-fit: contain; }
31713
31740
  .panel { display: none; flex-direction: column; width: min(var(--ns-assistant-panel-width, var(--ns-assistant-default-panel-width)), calc(100vw - 40px)); min-height: var(--ns-assistant-min-height, var(--ns-assistant-default-min-height)); max-height: min(var(--ns-assistant-max-height, var(--ns-assistant-default-max-height)), calc(100vh - 40px)); overflow: hidden; color: var(--ns-assistant-panel-text, var(--ns-assistant-text, var(--ns-assistant-default-text))); background: var(--ns-assistant-panel, var(--ns-assistant-default-panel)); border: 1px solid var(--ns-assistant-panel-border, var(--ns-assistant-divider, var(--ns-assistant-default-divider))); border-radius: var(--ns-assistant-panel-radius, var(--ns-assistant-default-panel-radius)); box-shadow: var(--ns-assistant-shadow, var(--ns-assistant-default-shadow)); transform-origin: bottom right; isolation: isolate; animation: halo-panel-in .28s cubic-bezier(.23,1,.32,1) both; }
31714
- :host([open]) .panel { display: flex; }
31741
+ :host([open][data-presentation-ready]) .panel { display: flex; }
31715
31742
  .panel { position: relative; }
31716
- :host([open]) .launcher { display: none; }
31743
+ :host([open][data-presentation-ready]) .launcher { display: none; }
31744
+ :host([open]:not([data-presentation-ready])) .launcher { cursor: progress; opacity: .72; transform: none; }
31717
31745
  header { display: flex; flex: 0 0 auto; gap: 10px; align-items: center; min-height: 64px; padding: 12px 18px; color: var(--ns-assistant-header-text, inherit); background: var(--ns-assistant-header, transparent); border-bottom: 1px solid color-mix(in srgb, var(--ns-assistant-header-border, var(--ns-assistant-divider, var(--ns-assistant-default-divider))) 78%, transparent); }
31718
31746
  header strong { flex: 1; font-size: 16px; font-weight: 600; letter-spacing: 0; }
31719
31747
  .brand-logo { display: block; max-width: 120px; max-height: 28px; object-fit: contain; }
@@ -32339,6 +32367,11 @@ var NoodleAssistantElement = class extends HTMLElementBase {
32339
32367
  #automaticPageContext = new AssistantElementPageContextController(
32340
32368
  () => !this.#pageContext
32341
32369
  );
32370
+ #presentationGate = new AssistantElementPresentationGate(
32371
+ this,
32372
+ () => this.#primeSession(),
32373
+ () => this.focusComposer()
32374
+ );
32342
32375
  #pendingUserEcho;
32343
32376
  #sessionState = "idle";
32344
32377
  #startOpenApplied = false;
@@ -32409,6 +32442,7 @@ var NoodleAssistantElement = class extends HTMLElementBase {
32409
32442
  if (!this.sessionEndpoint) this.sessionEndpoint = this.getAttribute("session-endpoint") ?? "";
32410
32443
  if (!this.embedId) this.embedId = this.getAttribute("embed-id") ?? "";
32411
32444
  if (!this.serviceUrl) this.serviceUrl = this.getAttribute("service-url") ?? "";
32445
+ if (!this.sessionEndpoint && !this.embedId) this.#presentationGate.reveal();
32412
32446
  this.#media = globalThis.matchMedia?.("(prefers-color-scheme: dark)");
32413
32447
  this.#media?.addEventListener("change", this.#handleSystemTheme);
32414
32448
  document.addEventListener("keydown", this.#handleDocumentKeydown);
@@ -32425,7 +32459,7 @@ var NoodleAssistantElement = class extends HTMLElementBase {
32425
32459
  } else if (!this.embedId) {
32426
32460
  this.#primeSession();
32427
32461
  }
32428
- this.#syncOpenState();
32462
+ this.#presentationGate.syncOpenState();
32429
32463
  }
32430
32464
  disconnectedCallback() {
32431
32465
  this.#conversationGeneration += 1;
@@ -32443,7 +32477,7 @@ var NoodleAssistantElement = class extends HTMLElementBase {
32443
32477
  }
32444
32478
  attributeChangedCallback(name21) {
32445
32479
  if (name21 === "theme") this.#applyTheme();
32446
- if (name21 === "open") this.#syncOpenState();
32480
+ if (name21 === "open") this.#presentationGate.syncOpenState();
32447
32481
  }
32448
32482
  open() {
32449
32483
  this.setAttribute("open", "");
@@ -32633,6 +32667,7 @@ var NoodleAssistantElement = class extends HTMLElementBase {
32633
32667
  const bootstrap = client.connect().catch((error51) => {
32634
32668
  if (generation !== this.#conversationGeneration || this.#client !== client) return;
32635
32669
  this.#dispatchClientError(error51, "session_failed");
32670
+ this.#presentationGate.reveal();
32636
32671
  }).finally(() => {
32637
32672
  if (this.#sessionBootstrap === bootstrap) this.#sessionBootstrap = void 0;
32638
32673
  });
@@ -32642,6 +32677,7 @@ var NoodleAssistantElement = class extends HTMLElementBase {
32642
32677
  this.dispatchEvent(new CustomEvent("assistant-event", { detail: event }));
32643
32678
  this.#events.handle(event);
32644
32679
  if (event.event === "session_started") {
32680
+ this.#presentationGate.reveal();
32645
32681
  this.#setSessionState("ready");
32646
32682
  this.#messages?.querySelector(".conversation-error")?.remove();
32647
32683
  }
@@ -32811,11 +32847,6 @@ var NoodleAssistantElement = class extends HTMLElementBase {
32811
32847
  this.#sessionState = state;
32812
32848
  syncAssistantSessionVisualState(this, this.shadowRoot, state, this.#appearance);
32813
32849
  }
32814
- #syncOpenState() {
32815
- const open = this.hasAttribute("open");
32816
- this.shadowRoot?.querySelector(".launcher")?.setAttribute("aria-expanded", String(open));
32817
- if (open && this.isConnected) this.#primeSession();
32818
- }
32819
32850
  #closeAndRestoreFocus() {
32820
32851
  this.close();
32821
32852
  this.shadowRoot?.querySelector(".launcher")?.focus();