@aparte/core 0.2.0-alpha.0 → 0.4.0-alpha.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.
Files changed (42) hide show
  1. package/README.md +21 -0
  2. package/dist/client/aparte-client.d.ts +21 -0
  3. package/dist/client/aparte-client.d.ts.map +1 -1
  4. package/dist/components/bubble/aparte-chat-bubble.d.ts +11 -0
  5. package/dist/components/bubble/aparte-chat-bubble.d.ts.map +1 -1
  6. package/dist/components/chat/aparte-chat.d.ts +13 -0
  7. package/dist/components/chat/aparte-chat.d.ts.map +1 -1
  8. package/dist/components/viewport/aparte-chat-viewport.d.ts +13 -2
  9. package/dist/components/viewport/aparte-chat-viewport.d.ts.map +1 -1
  10. package/dist/config/aparte-config.d.ts +16 -2
  11. package/dist/config/aparte-config.d.ts.map +1 -1
  12. package/dist/config/icon-provider.d.ts +21 -21
  13. package/dist/config/icon-provider.d.ts.map +1 -1
  14. package/dist/conversations/conversation-controller.d.ts.map +1 -1
  15. package/dist/custom-elements.json +3658 -3385
  16. package/dist/host/aparte-chat-host.d.ts +47 -1
  17. package/dist/host/aparte-chat-host.d.ts.map +1 -1
  18. package/dist/{index-D89k-n2Q.js → index-BBg6dsYx.js} +193 -43
  19. package/dist/index-BBg6dsYx.js.map +1 -0
  20. package/dist/index.css +60 -6
  21. package/dist/index.d.ts +10 -0
  22. package/dist/index.d.ts.map +1 -1
  23. package/dist/index.js +123 -26
  24. package/dist/index.js.map +1 -1
  25. package/dist/index.node.d.ts +2 -0
  26. package/dist/index.node.d.ts.map +1 -1
  27. package/dist/index.node.js +16 -14
  28. package/dist/index.node.js.map +1 -1
  29. package/dist/primitives/select/aparte-optgroup.d.ts +2 -0
  30. package/dist/primitives/select/aparte-optgroup.d.ts.map +1 -1
  31. package/dist/primitives/select/aparte-select.d.ts +2 -0
  32. package/dist/primitives/select/aparte-select.d.ts.map +1 -1
  33. package/dist/types/imperative-api.d.ts +27 -0
  34. package/dist/types/imperative-api.d.ts.map +1 -1
  35. package/dist/types/model-provider.d.ts +9 -3
  36. package/dist/types/model-provider.d.ts.map +1 -1
  37. package/dist/utils/files-to-attachments.d.ts +27 -0
  38. package/dist/utils/files-to-attachments.d.ts.map +1 -0
  39. package/dist/utils/is-awaiting-reply.d.ts +22 -0
  40. package/dist/utils/is-awaiting-reply.d.ts.map +1 -0
  41. package/package.json +8 -1
  42. package/dist/index-D89k-n2Q.js.map +0 -1
package/dist/index.css CHANGED
@@ -216,6 +216,10 @@
216
216
  --aparte-status-bg: transparent;
217
217
  --aparte-status-dot-size: 6px;
218
218
 
219
+ /* Waiting Indicator (the bubble's own dots, before the first token) */
220
+ --aparte-waiting-height: 1.5em;
221
+ --aparte-waiting-dot-gap: 4px;
222
+
219
223
  /* Thinking Segment */
220
224
  --aparte-thinking-border: var(--aparte-border);
221
225
  --aparte-thinking-bg: var(--aparte-surface-2);
@@ -712,8 +716,8 @@ aparte-chat-bubble {
712
716
  min-width: 0;
713
717
  }
714
718
 
715
- /* The message bubble — the surface fills ONLY the content (attachments +
716
- segments + text). The sender name (above) and the action bar (below) are
719
+ /* The message bubble — the surface fills ONLY the content (segments + text).
720
+ The sender name and attachment strip (above) and the action bar (below) are
717
721
  siblings in .aparte-body, so they stay OUTSIDE the coloured surface. */
718
722
  .aparte-message-content {
719
723
  border-radius: var(--aparte-message-content-radius, 0);
@@ -782,8 +786,11 @@ aparte-chat-bubble {
782
786
  .aparte-attachments {
783
787
  display: flex;
784
788
  flex-wrap: wrap;
785
- /* Bubble attachments only ever render for user messages anchor right. */
786
- justify-content: flex-end;
789
+ /* The strip sits directly above the message bubble and belongs to it, so it
790
+ must share the bubble's edge. The user bubble hugs its text on the LEADING
791
+ edge (AI-chat convention, see .aparte-message-content below), so anchoring
792
+ the strip to the trailing edge would split one message across both sides. */
793
+ justify-content: flex-start;
787
794
  gap: var(--aparte-space-3, 6px);
788
795
  margin-bottom: var(--aparte-space-4, 8px);
789
796
  /* Really small tiles inside the conversation. */
@@ -1320,6 +1327,47 @@ aparte-chat-status:not([visible]) {
1320
1327
  align-items: center;
1321
1328
  }
1322
1329
 
1330
+ /* Screen-reader-only text. Used by the bubble's waiting indicator, whose dots are
1331
+ decorative: the state is conveyed by aria-busy + this localized label. */
1332
+ .aparte-sr-only {
1333
+ position: absolute;
1334
+ width: 1px;
1335
+ height: 1px;
1336
+ padding: 0;
1337
+ margin: -1px;
1338
+ overflow: hidden;
1339
+ clip: rect(0, 0, 0, 0);
1340
+ white-space: nowrap;
1341
+ border: 0;
1342
+ }
1343
+
1344
+ /* The waiting indicator: between "user sends" and the first token. Built into the
1345
+ bubble, so it needs no wiring and behaves the same in core and every wrapper.
1346
+ Sits in the content region and disappears as soon as there is anything to show. */
1347
+ .aparte-waiting {
1348
+ display: flex;
1349
+ align-items: center;
1350
+ min-height: var(--aparte-waiting-height, 1.5em);
1351
+ }
1352
+
1353
+ .aparte-waiting[hidden] {
1354
+ display: none;
1355
+ }
1356
+
1357
+ .aparte-waiting .aparte-dots {
1358
+ gap: var(--aparte-waiting-dot-gap, 4px);
1359
+ }
1360
+
1361
+ /* Staggered so it reads as "working", not as three synchronized blobs. Scoped to
1362
+ the waiting region — the status element keeps its single-dot pulse. */
1363
+ .aparte-waiting .aparte-dot:nth-child(2) {
1364
+ animation-delay: 0.15s;
1365
+ }
1366
+
1367
+ .aparte-waiting .aparte-dot:nth-child(3) {
1368
+ animation-delay: 0.3s;
1369
+ }
1370
+
1323
1371
  .aparte-dot {
1324
1372
  width: var(--aparte-status-dot-size, 6px);
1325
1373
  height: var(--aparte-status-dot-size, 6px);
@@ -2409,9 +2457,15 @@ aparte-option[data-active] {
2409
2457
  box-shadow: inset 0 0 0 2px var(--aparte-primary, #3b82f6);
2410
2458
  }
2411
2459
 
2460
+ /* Selected option: an accent TINT plus an accent bar, keeping the theme's own
2461
+ text colour. A solid `--aparte-primary` fill with white text failed WCAG AA in
2462
+ both themes (the brass accent is mid-luminance, so white sits around 3.4:1),
2463
+ and an unreadable selected row is the one row that must be readable. Both
2464
+ tokens stay overridable for a design that wants the solid fill back. */
2412
2465
  aparte-option[selected] {
2413
- background: var(--aparte-select-option-selected, var(--aparte-primary, #3b82f6));
2414
- color: var(--aparte-select-option-selected-text, #fff);
2466
+ background: var(--aparte-select-option-selected, color-mix(in srgb, var(--aparte-primary, #3b82f6) 18%, transparent));
2467
+ color: var(--aparte-select-option-selected-text, var(--aparte-select-text, var(--aparte-text, #1e293b)));
2468
+ box-shadow: inset 2px 0 0 var(--aparte-primary, #3b82f6);
2415
2469
  }
2416
2470
 
2417
2471
  aparte-option[disabled] {
package/dist/index.d.ts CHANGED
@@ -3,6 +3,14 @@
3
3
  * High-performance AI conversation engine in Vanilla TypeScript
4
4
  * Zero-dependency Web Components for LLM streaming
5
5
  *
6
+ * ⚠️ This is the **browser** entry: it defines the custom elements and imports CSS
7
+ * at module scope, so it needs a DOM. **Node resolves `index.node.ts` instead**
8
+ * (via the `node` condition in package.json) — a DOM-free entry with the client,
9
+ * host, transports, the chat handler and every type. This file sits first in the
10
+ * exports map only because of the repo-local `@aparte-workspace/source` condition,
11
+ * which is why reading it can look like "this package can't run in Node".
12
+ * See the "Node / SSR" section of the README.
13
+ *
6
14
  * @packageDocumentation
7
15
  */
8
16
 
@@ -36,6 +44,8 @@ export type { AparteMarkdownProvider, AparteStreamingMarkdownProvider, AparteStr
36
44
  export { DEFAULT_ICON_FALLBACKS, DEFAULT_SKELETON_FALLBACKS, DEFAULT_LOCALE, defaultSanitizer, isSafeUrl } from './config/index.js';
37
45
  export { AparteClient } from './client/aparte-client.js';
38
46
  export { applyElementProps, DEFAULT_UI_EVENTS } from './interop/element-props.js';
47
+ export { filesToAttachments } from './utils/files-to-attachments.js';
48
+ export { isAwaitingReply } from './utils/is-awaiting-reply.js';
39
49
  export type { AparteClientOptions, AparteToolApprovalResolver, AparteCompactionSelector } from './client/aparte-client.js';
40
50
  export { createStreamAdapter, readableToAsyncIterable } from './client/stream-adapter.js';
41
51
  export type { AparteStreamRunEvent, AparteStreamRunEmitter, StreamAdapterTarget, CreateStreamAdapterOptions, AparteStreamRunner, AparteStreamRunOptions } from './client/stream-adapter.js';
@@ -1 +1 @@
1
- {"version":3,"file":"index.d.ts","sourceRoot":"","sources":["../src/index.ts"],"names":[],"mappings":"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"}
1
+ {"version":3,"file":"index.d.ts","sourceRoot":"","sources":["../src/index.ts"],"names":[],"mappings":"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"}
package/dist/index.js CHANGED
@@ -1,5 +1,5 @@
1
- import { N as resolveConfig, y as getSegmentRenderer, O as runWithConfig, M as MessageRepository, H as populateBubbleFromMessage, d as AparteConfig, p as buildElicitationPanel } from "./index-D89k-n2Q.js";
2
- import { A, a, b, c, e, f, g, h, i, B, C, D, j, k, l, m, n, o, q, r, s, t, u, v, w, x, z, E, F, G, I, J, K, L, P } from "./index-D89k-n2Q.js";
1
+ import { P as resolveConfig, z as getSegmentRenderer, Q as runWithConfig, M as MessageRepository, E as isAwaitingReply, J as populateBubbleFromMessage, d as AparteConfig, p as buildElicitationPanel } from "./index-BBg6dsYx.js";
2
+ import { A, a, b, c, e, f, g, h, i, B, C, D, j, k, l, m, n, o, q, r, s, t, u, v, w, x, y, F, G, H, I, K, L, N, O, R } from "./index-BBg6dsYx.js";
3
3
  class AparteOption extends HTMLElement {
4
4
  static get observedAttributes() {
5
5
  return ["value", "disabled", "selected", "data-status"];
@@ -73,6 +73,8 @@ if (!customElements.get("aparte-option")) {
73
73
  customElements.define("aparte-option", AparteOption);
74
74
  }
75
75
  class AparteOptgroup extends HTMLElement {
76
+ /** Ids for the label span the group points `aria-labelledby` at. */
77
+ static _labelIdSeq = 0;
76
78
  static get observedAttributes() {
77
79
  return ["label", "collapsible", "collapsed", "loading"];
78
80
  }
@@ -121,10 +123,11 @@ class AparteOptgroup extends HTMLElement {
121
123
  if (!existingHeader) {
122
124
  const header = document.createElement("div");
123
125
  header.className = "aparte-optgroup-header";
124
- header.setAttribute("aria-label", this.label);
125
126
  const labelSpan = document.createElement("span");
126
127
  labelSpan.className = "aparte-optgroup-label";
128
+ labelSpan.id = `aparte-optgroup-label-${++AparteOptgroup._labelIdSeq}`;
127
129
  labelSpan.textContent = this.label;
130
+ this.setAttribute("aria-labelledby", labelSpan.id);
128
131
  header.appendChild(labelSpan);
129
132
  if (this.collapsible) {
130
133
  const chevron = document.createElement("span");
@@ -179,6 +182,8 @@ if (!customElements.get("aparte-optgroup")) {
179
182
  }
180
183
  class AparteSelect extends HTMLElement {
181
184
  static _optIdSeq = 0;
185
+ /** Fallback ids for the listbox `aria-controls` target when the host has no id. */
186
+ static _listboxSeq = 0;
182
187
  _value = "";
183
188
  _isOpen = false;
184
189
  _activeIndex = -1;
@@ -261,6 +266,7 @@ class AparteSelect extends HTMLElement {
261
266
  trigger.setAttribute("role", "combobox");
262
267
  trigger.setAttribute("aria-haspopup", "listbox");
263
268
  trigger.setAttribute("aria-expanded", "false");
269
+ trigger.setAttribute("aria-label", this.getAttribute("aria-label") || placeholder);
264
270
  const labelSpan = document.createElement("span");
265
271
  labelSpan.className = "aparte-select-label";
266
272
  labelSpan.textContent = placeholder;
@@ -270,17 +276,21 @@ class AparteSelect extends HTMLElement {
270
276
  trigger.append(labelSpan, chevronSpan);
271
277
  const dropdown = document.createElement("div");
272
278
  dropdown.className = "aparte-select-dropdown";
273
- dropdown.setAttribute("role", "listbox");
274
279
  dropdown.hidden = !this._isOpen;
275
280
  if (searchable) {
276
281
  const searchInput = document.createElement("input");
277
282
  searchInput.type = "text";
278
283
  searchInput.className = "aparte-select-search";
279
284
  searchInput.placeholder = "Search...";
285
+ searchInput.setAttribute("aria-label", "Search options");
280
286
  dropdown.appendChild(searchInput);
281
287
  }
282
288
  const optionsContainer = document.createElement("div");
283
289
  optionsContainer.className = "aparte-select-options";
290
+ optionsContainer.setAttribute("role", "listbox");
291
+ optionsContainer.setAttribute("aria-label", trigger.getAttribute("aria-label") ?? placeholder);
292
+ optionsContainer.id = this.id ? `${this.id}-listbox` : `aparte-listbox-${++AparteSelect._listboxSeq}`;
293
+ trigger.setAttribute("aria-controls", optionsContainer.id);
284
294
  slottedChildren.forEach((child) => {
285
295
  if (child.tagName === "APARTE-OPTION" || child.tagName === "APARTE-OPTGROUP") {
286
296
  optionsContainer.appendChild(child);
@@ -588,9 +598,15 @@ if (!customElements.get("aparte-progress-spinner")) {
588
598
  }
589
599
  class AparteChat extends HTMLElement {
590
600
  static get observedAttributes() {
591
- return ["placeholder", "disabled", "center-empty"];
601
+ return ["placeholder", "disabled", "center-empty", "attachments"];
592
602
  }
593
603
  _observer = null;
604
+ /**
605
+ * True only for the composition THIS element injected. An author-provided
606
+ * composer (or a `framework-managed` host) is never edited by the attachments
607
+ * toggle below — those own their own markup.
608
+ */
609
+ _ownsShell = false;
594
610
  connectedCallback() {
595
611
  this._render();
596
612
  this._forwardAttr("placeholder");
@@ -607,6 +623,10 @@ class AparteChat extends HTMLElement {
607
623
  this._syncEmptyWatch();
608
624
  return;
609
625
  }
626
+ if (name === "attachments") {
627
+ this._syncAttachments();
628
+ return;
629
+ }
610
630
  const composer = this.querySelector("aparte-composer");
611
631
  if (!composer) return;
612
632
  if (newValue !== null) composer.setAttribute(name, newValue);
@@ -625,17 +645,43 @@ class AparteChat extends HTMLElement {
625
645
  if (this.querySelector("aparte-chat-viewport")) return;
626
646
  const placeholder = this.getAttribute("placeholder");
627
647
  const composerAttrs = (placeholder !== null ? ` placeholder="${this._escapeAttr(placeholder)}"` : "") + (this.hasAttribute("disabled") ? " disabled" : "");
648
+ const attachments = this.hasAttribute("attachments");
628
649
  this.innerHTML = `
629
650
  <aparte-chat-viewport></aparte-chat-viewport>
630
651
  <aparte-composer${composerAttrs}>
631
652
  <div class="aparte-composer-shell">
653
+ ${attachments ? "<aparte-composer-attachments></aparte-composer-attachments>" : ""}
632
654
  <div class="aparte-composer-row">
655
+ ${attachments ? "<aparte-composer-add-attachment></aparte-composer-add-attachment>" : ""}
633
656
  <aparte-composer-input></aparte-composer-input>
634
657
  <aparte-composer-send></aparte-composer-send>
635
658
  </div>
636
659
  </div>
637
660
  </aparte-composer>
638
661
  `;
662
+ this._ownsShell = true;
663
+ }
664
+ /**
665
+ * Add/remove the two attachment primitives on the composition we injected, so
666
+ * toggling the attribute after mount works like the wrappers' reactive prop
667
+ * (there, a re-render does it). Author-provided markup is left alone.
668
+ */
669
+ _syncAttachments() {
670
+ if (!this._ownsShell) return;
671
+ const composer = this.composer;
672
+ const shell = composer?.querySelector(".aparte-composer-shell");
673
+ const row = shell?.querySelector(".aparte-composer-row");
674
+ if (!composer || !shell || !row) return;
675
+ const strip = shell.querySelector("aparte-composer-attachments");
676
+ const picker = row.querySelector("aparte-composer-add-attachment");
677
+ if (this.hasAttribute("attachments")) {
678
+ if (!strip) shell.insertBefore(document.createElement("aparte-composer-attachments"), row);
679
+ if (!picker) row.insertBefore(document.createElement("aparte-composer-add-attachment"), row.firstChild);
680
+ return;
681
+ }
682
+ strip?.remove();
683
+ picker?.remove();
684
+ composer.clearAttachments();
639
685
  }
640
686
  /** Set an attribute on the inner composer only when the shell carries it. */
641
687
  _forwardAttr(name) {
@@ -794,11 +840,13 @@ class AparteChatBubble extends HTMLElement {
794
840
  setSegments(segments) {
795
841
  this._segments = segments;
796
842
  this._renderSegments();
843
+ this._updateWaiting();
797
844
  }
798
845
  /** Add a segment */
799
846
  addSegment(segment) {
800
847
  this._segments.push(segment);
801
848
  this._appendSegmentEl(segment);
849
+ this._updateWaiting();
802
850
  }
803
851
  /** Update a specific segment */
804
852
  updateSegment(segmentId, updates) {
@@ -829,6 +877,7 @@ class AparteChatBubble extends HTMLElement {
829
877
  }
830
878
  const el = this._segmentsEl?.querySelector(`[data-segment-id="${cssEscape(segmentId)}"]`);
831
879
  el?.remove();
880
+ this._updateWaiting();
832
881
  }
833
882
  /** Set attachments (chips shown above message content, user role only) */
834
883
  setAttachments(attachments) {
@@ -975,6 +1024,10 @@ class AparteChatBubble extends HTMLElement {
975
1024
  <div class="aparte-message-content">
976
1025
  <div class="aparte-segments"></div>
977
1026
  <div class="aparte-content"></div>
1027
+ <div class="aparte-waiting" hidden>
1028
+ <span class="aparte-dots" aria-hidden="true"><span class="aparte-dot"></span><span class="aparte-dot"></span><span class="aparte-dot"></span></span>
1029
+ <span class="aparte-sr-only"></span>
1030
+ </div>
978
1031
  </div>
979
1032
  <div class="aparte-footer">
980
1033
  <div class="aparte-branch-picker" hidden>
@@ -996,6 +1049,28 @@ class AparteChatBubble extends HTMLElement {
996
1049
  this._setupBranchPickerListeners();
997
1050
  this._updateActionBar();
998
1051
  this._renderAvatar();
1052
+ if (this._streaming) this._updateStreaming(true);
1053
+ this._updateWaiting();
1054
+ }
1055
+ /**
1056
+ * Show the built-in waiting indicator while this bubble is in flight and has
1057
+ * nothing to show yet — the gap between "user sends" and the first token, which
1058
+ * used to be a bubble with a name and an empty body.
1059
+ *
1060
+ * The dots are CSS (no per-token work, themable, honours reduced-motion); the
1061
+ * accessible name is `locale.typing`, next to the `aria-busy` the streaming state
1062
+ * already sets. A custom bubble shell without the region simply has no indicator
1063
+ * (same null-guarded degradation as the other region hooks).
1064
+ */
1065
+ _updateWaiting() {
1066
+ const el = this.querySelector(".aparte-waiting");
1067
+ if (!el) return;
1068
+ const waiting = this._streaming && this._role !== "user" && this._segments.length === 0 && !this._content.trim();
1069
+ el.hidden = !waiting;
1070
+ if (!waiting) return;
1071
+ const label = this._cfg.getLocale().typing;
1072
+ const sr = el.querySelector(".aparte-sr-only");
1073
+ if (sr && sr.textContent !== label) sr.textContent = label;
999
1074
  }
1000
1075
  /**
1001
1076
  * Hand the avatar host element off to the registered AvatarProvider, if
@@ -1046,10 +1121,12 @@ class AparteChatBubble extends HTMLElement {
1046
1121
  if (!this._contentEl) return;
1047
1122
  if (this._segments.length > 0) {
1048
1123
  this._contentEl.style.display = "none";
1124
+ this._updateWaiting();
1049
1125
  return;
1050
1126
  }
1051
1127
  this._contentEl.style.display = "";
1052
1128
  this._contentEl.innerHTML = this._cfg.renderMarkdown(this._content);
1129
+ this._updateWaiting();
1053
1130
  if (!this._streaming) this._highlightContentCode();
1054
1131
  }
1055
1132
  /**
@@ -1504,6 +1581,7 @@ class AparteChatBubble extends HTMLElement {
1504
1581
  message.classList.remove("aparte-message-streaming");
1505
1582
  }
1506
1583
  }
1584
+ this._updateWaiting();
1507
1585
  if (wasStreaming && !streaming) this._highlightContentCode();
1508
1586
  }
1509
1587
  }
@@ -1902,7 +1980,7 @@ class AparteChatViewport extends HTMLElement {
1902
1980
  bubble.setAttribute("role", message.role);
1903
1981
  if (message.timestamp) bubble.setAttribute("timestamp", String(message.timestamp));
1904
1982
  if (message.content) bubble.setAttribute("content", message.content);
1905
- if (message.status === "streaming" || message.status === "pending") {
1983
+ if (isAwaitingReply(message)) {
1906
1984
  bubble.setAttribute("streaming", "");
1907
1985
  }
1908
1986
  if (this._bottomSpacer && this._bottomSpacer.parentNode === wrapper) {
@@ -1910,6 +1988,7 @@ class AparteChatViewport extends HTMLElement {
1910
1988
  } else {
1911
1989
  wrapper.appendChild(bubble);
1912
1990
  }
1991
+ populateBubbleFromMessage(bubble, message);
1913
1992
  }
1914
1993
  }
1915
1994
  this._pruneRenderedBubbles();
@@ -1990,7 +2069,7 @@ class AparteChatViewport extends HTMLElement {
1990
2069
  if (currentIdx === -1) return;
1991
2070
  const targetIdx = direction === "prev" ? currentIdx - 1 : currentIdx + 1;
1992
2071
  if (targetIdx < 0 || targetIdx >= siblings.length) return;
1993
- this._isAutoScrollEnabled = false;
2072
+ this._isAutoScrollEnabled = this._isAtBottom();
1994
2073
  this._updateScrollButton();
1995
2074
  this._repo.switchToBranch(siblings[targetIdx]);
1996
2075
  this._reRenderActivePath();
@@ -2180,11 +2259,14 @@ class AparteChatViewport extends HTMLElement {
2180
2259
  case "setUsage":
2181
2260
  bubble.setUsage?.(payload);
2182
2261
  break;
2183
- case "update":
2184
- if ("status" in payload || "segments" in payload) {
2262
+ case "update": {
2263
+ const updates = payload;
2264
+ const renderable = ["status", "segments", "content", "attachments", "usage"];
2265
+ if (renderable.some((key) => key in updates)) {
2185
2266
  bubble.updateMessage?.(payload);
2186
2267
  }
2187
2268
  break;
2269
+ }
2188
2270
  case "complete":
2189
2271
  bubble.updateMessage?.(payload);
2190
2272
  break;
@@ -2221,7 +2303,7 @@ class AparteChatViewport extends HTMLElement {
2221
2303
  bubble.setAttribute("message-id", message.id);
2222
2304
  bubble.setAttribute("role", message.role);
2223
2305
  if (message.timestamp) bubble.setAttribute("timestamp", String(message.timestamp));
2224
- if (message.status === "streaming" || message.status === "pending") {
2306
+ if (isAwaitingReply(message)) {
2225
2307
  bubble.setAttribute("streaming", "");
2226
2308
  }
2227
2309
  wrapper.appendChild(bubble);
@@ -2229,7 +2311,6 @@ class AparteChatViewport extends HTMLElement {
2229
2311
  }
2230
2312
  this._dispatchPathChanged(activeMessages, siblingsInfo);
2231
2313
  this._recalculateSpacer();
2232
- requestAnimationFrame(() => this._handleScroll());
2233
2314
  }
2234
2315
  _dispatchPathChanged(messages, siblings) {
2235
2316
  const detail = { messages, siblings };
@@ -2399,11 +2480,15 @@ class AparteChatViewport extends HTMLElement {
2399
2480
  });
2400
2481
  }
2401
2482
  }
2483
+ /** Is the scroll surface within `_scrollThreshold` of its bottom, right now? */
2484
+ _isAtBottom() {
2485
+ if (!this._container) return true;
2486
+ const { scrollTop, scrollHeight, clientHeight } = this._container;
2487
+ return scrollHeight - scrollTop - clientHeight <= this._scrollThreshold;
2488
+ }
2402
2489
  _handleScroll() {
2403
2490
  if (!this._container) return;
2404
- const { scrollTop, scrollHeight, clientHeight } = this._container;
2405
- const distanceFromBottom = scrollHeight - scrollTop - clientHeight;
2406
- this._isAutoScrollEnabled = distanceFromBottom <= this._scrollThreshold;
2491
+ this._isAutoScrollEnabled = this._isAtBottom();
2407
2492
  this._updateScrollButton();
2408
2493
  }
2409
2494
  _scrollToBottom() {
@@ -2422,11 +2507,20 @@ class AparteChatViewport extends HTMLElement {
2422
2507
  return typeof matchMedia === "function" && matchMedia("(prefers-reduced-motion: reduce)").matches;
2423
2508
  }
2424
2509
  /**
2425
- * Show/hide the scroll-to-bottom button based on the current auto-scroll state.
2426
- * Hidden when already at bottom (_isAutoScrollEnabled = true).
2510
+ * Show/hide the scroll-to-bottom button from the **current geometry**, not from
2511
+ * `_isAutoScrollEnabled`.
2512
+ *
2513
+ * The two answer different questions: the flag is intent ("should new content
2514
+ * pull the view down"), the button is a fact ("is there anything below the
2515
+ * fold"). Mirroring the flag made the button lie whenever the two diverged —
2516
+ * `navigateBranch` deliberately disarms auto-follow, so swapping a branch while
2517
+ * already at the bottom of a scrollable transcript left the button offering to
2518
+ * scroll nowhere (reported from bonaparte, React). Re-derived on scroll, on the
2519
+ * post-mutation frame and after a path swap, so it converges to the truth
2520
+ * whatever a framework's render timing does in between.
2427
2521
  */
2428
2522
  _updateScrollButton() {
2429
- this._scrollBtn?.classList.toggle("aparte-scroll-btn--hidden", this._isAutoScrollEnabled);
2523
+ this._scrollBtn?.classList.toggle("aparte-scroll-btn--hidden", this._isAtBottom());
2430
2524
  }
2431
2525
  /**
2432
2526
  * Recalculate the bottom spacer height so the last user message is always
@@ -2485,6 +2579,7 @@ class AparteChatViewport extends HTMLElement {
2485
2579
  this._spacerRafId = requestAnimationFrame(() => {
2486
2580
  this._spacerRafId = null;
2487
2581
  this._recalculateSpacer();
2582
+ this._updateScrollButton();
2488
2583
  });
2489
2584
  }
2490
2585
  /**
@@ -3745,19 +3840,21 @@ export {
3745
3840
  v as defaultSanitizer,
3746
3841
  w as deriveArtifactKind,
3747
3842
  x as detachConfig,
3843
+ y as filesToAttachments,
3748
3844
  getSegmentRenderer,
3749
- z as isFormatAdapter,
3750
- E as isSafeUrl,
3751
- F as parseAparteEventStream,
3752
- G as parseMarkdownToSegments,
3845
+ isAwaitingReply,
3846
+ F as isFormatAdapter,
3847
+ G as isSafeUrl,
3848
+ H as parseAparteEventStream,
3849
+ I as parseMarkdownToSegments,
3753
3850
  populateBubbleFromMessage,
3754
- I as readableToAsyncIterable,
3851
+ K as readableToAsyncIterable,
3755
3852
  registerAllComponents,
3756
- J as registerDefaultRenderers,
3757
- K as registerSegmentRenderer,
3758
- L as requestUserInput,
3853
+ L as registerDefaultRenderers,
3854
+ N as registerSegmentRenderer,
3855
+ O as requestUserInput,
3759
3856
  resolveConfig,
3760
3857
  runWithConfig,
3761
- P as unregisterSegmentRenderer
3858
+ R as unregisterSegmentRenderer
3762
3859
  };
3763
3860
  //# sourceMappingURL=index.js.map