@aparte/core 0.3.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 (39) hide show
  1. package/README.md +21 -0
  2. package/dist/client/aparte-client.d.ts.map +1 -1
  3. package/dist/components/bubble/aparte-chat-bubble.d.ts +11 -0
  4. package/dist/components/bubble/aparte-chat-bubble.d.ts.map +1 -1
  5. package/dist/components/chat/aparte-chat.d.ts +13 -0
  6. package/dist/components/chat/aparte-chat.d.ts.map +1 -1
  7. package/dist/components/viewport/aparte-chat-viewport.d.ts +13 -2
  8. package/dist/components/viewport/aparte-chat-viewport.d.ts.map +1 -1
  9. package/dist/config/aparte-config.d.ts +10 -2
  10. package/dist/config/aparte-config.d.ts.map +1 -1
  11. package/dist/config/icon-provider.d.ts +21 -21
  12. package/dist/config/icon-provider.d.ts.map +1 -1
  13. package/dist/conversations/conversation-controller.d.ts.map +1 -1
  14. package/dist/custom-elements.json +7604 -7360
  15. package/dist/host/aparte-chat-host.d.ts +47 -1
  16. package/dist/host/aparte-chat-host.d.ts.map +1 -1
  17. package/dist/{index-CW2BCAqn.js → index-BBg6dsYx.js} +164 -41
  18. package/dist/index-BBg6dsYx.js.map +1 -0
  19. package/dist/index.css +60 -6
  20. package/dist/index.d.ts +10 -0
  21. package/dist/index.d.ts.map +1 -1
  22. package/dist/index.js +122 -26
  23. package/dist/index.js.map +1 -1
  24. package/dist/index.node.d.ts +2 -0
  25. package/dist/index.node.d.ts.map +1 -1
  26. package/dist/index.node.js +16 -14
  27. package/dist/index.node.js.map +1 -1
  28. package/dist/primitives/select/aparte-optgroup.d.ts +2 -0
  29. package/dist/primitives/select/aparte-optgroup.d.ts.map +1 -1
  30. package/dist/primitives/select/aparte-select.d.ts +2 -0
  31. package/dist/primitives/select/aparte-select.d.ts.map +1 -1
  32. package/dist/types/imperative-api.d.ts +13 -0
  33. package/dist/types/imperative-api.d.ts.map +1 -1
  34. package/dist/utils/files-to-attachments.d.ts +27 -0
  35. package/dist/utils/files-to-attachments.d.ts.map +1 -0
  36. package/dist/utils/is-awaiting-reply.d.ts +22 -0
  37. package/dist/utils/is-awaiting-reply.d.ts.map +1 -0
  38. package/package.json +8 -1
  39. package/dist/index-CW2BCAqn.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-CW2BCAqn.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-CW2BCAqn.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;
@@ -271,17 +276,21 @@ class AparteSelect extends HTMLElement {
271
276
  trigger.append(labelSpan, chevronSpan);
272
277
  const dropdown = document.createElement("div");
273
278
  dropdown.className = "aparte-select-dropdown";
274
- dropdown.setAttribute("role", "listbox");
275
279
  dropdown.hidden = !this._isOpen;
276
280
  if (searchable) {
277
281
  const searchInput = document.createElement("input");
278
282
  searchInput.type = "text";
279
283
  searchInput.className = "aparte-select-search";
280
284
  searchInput.placeholder = "Search...";
285
+ searchInput.setAttribute("aria-label", "Search options");
281
286
  dropdown.appendChild(searchInput);
282
287
  }
283
288
  const optionsContainer = document.createElement("div");
284
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);
285
294
  slottedChildren.forEach((child) => {
286
295
  if (child.tagName === "APARTE-OPTION" || child.tagName === "APARTE-OPTGROUP") {
287
296
  optionsContainer.appendChild(child);
@@ -589,9 +598,15 @@ if (!customElements.get("aparte-progress-spinner")) {
589
598
  }
590
599
  class AparteChat extends HTMLElement {
591
600
  static get observedAttributes() {
592
- return ["placeholder", "disabled", "center-empty"];
601
+ return ["placeholder", "disabled", "center-empty", "attachments"];
593
602
  }
594
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;
595
610
  connectedCallback() {
596
611
  this._render();
597
612
  this._forwardAttr("placeholder");
@@ -608,6 +623,10 @@ class AparteChat extends HTMLElement {
608
623
  this._syncEmptyWatch();
609
624
  return;
610
625
  }
626
+ if (name === "attachments") {
627
+ this._syncAttachments();
628
+ return;
629
+ }
611
630
  const composer = this.querySelector("aparte-composer");
612
631
  if (!composer) return;
613
632
  if (newValue !== null) composer.setAttribute(name, newValue);
@@ -626,17 +645,43 @@ class AparteChat extends HTMLElement {
626
645
  if (this.querySelector("aparte-chat-viewport")) return;
627
646
  const placeholder = this.getAttribute("placeholder");
628
647
  const composerAttrs = (placeholder !== null ? ` placeholder="${this._escapeAttr(placeholder)}"` : "") + (this.hasAttribute("disabled") ? " disabled" : "");
648
+ const attachments = this.hasAttribute("attachments");
629
649
  this.innerHTML = `
630
650
  <aparte-chat-viewport></aparte-chat-viewport>
631
651
  <aparte-composer${composerAttrs}>
632
652
  <div class="aparte-composer-shell">
653
+ ${attachments ? "<aparte-composer-attachments></aparte-composer-attachments>" : ""}
633
654
  <div class="aparte-composer-row">
655
+ ${attachments ? "<aparte-composer-add-attachment></aparte-composer-add-attachment>" : ""}
634
656
  <aparte-composer-input></aparte-composer-input>
635
657
  <aparte-composer-send></aparte-composer-send>
636
658
  </div>
637
659
  </div>
638
660
  </aparte-composer>
639
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();
640
685
  }
641
686
  /** Set an attribute on the inner composer only when the shell carries it. */
642
687
  _forwardAttr(name) {
@@ -795,11 +840,13 @@ class AparteChatBubble extends HTMLElement {
795
840
  setSegments(segments) {
796
841
  this._segments = segments;
797
842
  this._renderSegments();
843
+ this._updateWaiting();
798
844
  }
799
845
  /** Add a segment */
800
846
  addSegment(segment) {
801
847
  this._segments.push(segment);
802
848
  this._appendSegmentEl(segment);
849
+ this._updateWaiting();
803
850
  }
804
851
  /** Update a specific segment */
805
852
  updateSegment(segmentId, updates) {
@@ -830,6 +877,7 @@ class AparteChatBubble extends HTMLElement {
830
877
  }
831
878
  const el = this._segmentsEl?.querySelector(`[data-segment-id="${cssEscape(segmentId)}"]`);
832
879
  el?.remove();
880
+ this._updateWaiting();
833
881
  }
834
882
  /** Set attachments (chips shown above message content, user role only) */
835
883
  setAttachments(attachments) {
@@ -976,6 +1024,10 @@ class AparteChatBubble extends HTMLElement {
976
1024
  <div class="aparte-message-content">
977
1025
  <div class="aparte-segments"></div>
978
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>
979
1031
  </div>
980
1032
  <div class="aparte-footer">
981
1033
  <div class="aparte-branch-picker" hidden>
@@ -997,6 +1049,28 @@ class AparteChatBubble extends HTMLElement {
997
1049
  this._setupBranchPickerListeners();
998
1050
  this._updateActionBar();
999
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;
1000
1074
  }
1001
1075
  /**
1002
1076
  * Hand the avatar host element off to the registered AvatarProvider, if
@@ -1047,10 +1121,12 @@ class AparteChatBubble extends HTMLElement {
1047
1121
  if (!this._contentEl) return;
1048
1122
  if (this._segments.length > 0) {
1049
1123
  this._contentEl.style.display = "none";
1124
+ this._updateWaiting();
1050
1125
  return;
1051
1126
  }
1052
1127
  this._contentEl.style.display = "";
1053
1128
  this._contentEl.innerHTML = this._cfg.renderMarkdown(this._content);
1129
+ this._updateWaiting();
1054
1130
  if (!this._streaming) this._highlightContentCode();
1055
1131
  }
1056
1132
  /**
@@ -1505,6 +1581,7 @@ class AparteChatBubble extends HTMLElement {
1505
1581
  message.classList.remove("aparte-message-streaming");
1506
1582
  }
1507
1583
  }
1584
+ this._updateWaiting();
1508
1585
  if (wasStreaming && !streaming) this._highlightContentCode();
1509
1586
  }
1510
1587
  }
@@ -1903,7 +1980,7 @@ class AparteChatViewport extends HTMLElement {
1903
1980
  bubble.setAttribute("role", message.role);
1904
1981
  if (message.timestamp) bubble.setAttribute("timestamp", String(message.timestamp));
1905
1982
  if (message.content) bubble.setAttribute("content", message.content);
1906
- if (message.status === "streaming" || message.status === "pending") {
1983
+ if (isAwaitingReply(message)) {
1907
1984
  bubble.setAttribute("streaming", "");
1908
1985
  }
1909
1986
  if (this._bottomSpacer && this._bottomSpacer.parentNode === wrapper) {
@@ -1911,6 +1988,7 @@ class AparteChatViewport extends HTMLElement {
1911
1988
  } else {
1912
1989
  wrapper.appendChild(bubble);
1913
1990
  }
1991
+ populateBubbleFromMessage(bubble, message);
1914
1992
  }
1915
1993
  }
1916
1994
  this._pruneRenderedBubbles();
@@ -1991,7 +2069,7 @@ class AparteChatViewport extends HTMLElement {
1991
2069
  if (currentIdx === -1) return;
1992
2070
  const targetIdx = direction === "prev" ? currentIdx - 1 : currentIdx + 1;
1993
2071
  if (targetIdx < 0 || targetIdx >= siblings.length) return;
1994
- this._isAutoScrollEnabled = false;
2072
+ this._isAutoScrollEnabled = this._isAtBottom();
1995
2073
  this._updateScrollButton();
1996
2074
  this._repo.switchToBranch(siblings[targetIdx]);
1997
2075
  this._reRenderActivePath();
@@ -2181,11 +2259,14 @@ class AparteChatViewport extends HTMLElement {
2181
2259
  case "setUsage":
2182
2260
  bubble.setUsage?.(payload);
2183
2261
  break;
2184
- case "update":
2185
- 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)) {
2186
2266
  bubble.updateMessage?.(payload);
2187
2267
  }
2188
2268
  break;
2269
+ }
2189
2270
  case "complete":
2190
2271
  bubble.updateMessage?.(payload);
2191
2272
  break;
@@ -2222,7 +2303,7 @@ class AparteChatViewport extends HTMLElement {
2222
2303
  bubble.setAttribute("message-id", message.id);
2223
2304
  bubble.setAttribute("role", message.role);
2224
2305
  if (message.timestamp) bubble.setAttribute("timestamp", String(message.timestamp));
2225
- if (message.status === "streaming" || message.status === "pending") {
2306
+ if (isAwaitingReply(message)) {
2226
2307
  bubble.setAttribute("streaming", "");
2227
2308
  }
2228
2309
  wrapper.appendChild(bubble);
@@ -2230,7 +2311,6 @@ class AparteChatViewport extends HTMLElement {
2230
2311
  }
2231
2312
  this._dispatchPathChanged(activeMessages, siblingsInfo);
2232
2313
  this._recalculateSpacer();
2233
- requestAnimationFrame(() => this._handleScroll());
2234
2314
  }
2235
2315
  _dispatchPathChanged(messages, siblings) {
2236
2316
  const detail = { messages, siblings };
@@ -2400,11 +2480,15 @@ class AparteChatViewport extends HTMLElement {
2400
2480
  });
2401
2481
  }
2402
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
+ }
2403
2489
  _handleScroll() {
2404
2490
  if (!this._container) return;
2405
- const { scrollTop, scrollHeight, clientHeight } = this._container;
2406
- const distanceFromBottom = scrollHeight - scrollTop - clientHeight;
2407
- this._isAutoScrollEnabled = distanceFromBottom <= this._scrollThreshold;
2491
+ this._isAutoScrollEnabled = this._isAtBottom();
2408
2492
  this._updateScrollButton();
2409
2493
  }
2410
2494
  _scrollToBottom() {
@@ -2423,11 +2507,20 @@ class AparteChatViewport extends HTMLElement {
2423
2507
  return typeof matchMedia === "function" && matchMedia("(prefers-reduced-motion: reduce)").matches;
2424
2508
  }
2425
2509
  /**
2426
- * Show/hide the scroll-to-bottom button based on the current auto-scroll state.
2427
- * 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.
2428
2521
  */
2429
2522
  _updateScrollButton() {
2430
- this._scrollBtn?.classList.toggle("aparte-scroll-btn--hidden", this._isAutoScrollEnabled);
2523
+ this._scrollBtn?.classList.toggle("aparte-scroll-btn--hidden", this._isAtBottom());
2431
2524
  }
2432
2525
  /**
2433
2526
  * Recalculate the bottom spacer height so the last user message is always
@@ -2486,6 +2579,7 @@ class AparteChatViewport extends HTMLElement {
2486
2579
  this._spacerRafId = requestAnimationFrame(() => {
2487
2580
  this._spacerRafId = null;
2488
2581
  this._recalculateSpacer();
2582
+ this._updateScrollButton();
2489
2583
  });
2490
2584
  }
2491
2585
  /**
@@ -3746,19 +3840,21 @@ export {
3746
3840
  v as defaultSanitizer,
3747
3841
  w as deriveArtifactKind,
3748
3842
  x as detachConfig,
3843
+ y as filesToAttachments,
3749
3844
  getSegmentRenderer,
3750
- z as isFormatAdapter,
3751
- E as isSafeUrl,
3752
- F as parseAparteEventStream,
3753
- G as parseMarkdownToSegments,
3845
+ isAwaitingReply,
3846
+ F as isFormatAdapter,
3847
+ G as isSafeUrl,
3848
+ H as parseAparteEventStream,
3849
+ I as parseMarkdownToSegments,
3754
3850
  populateBubbleFromMessage,
3755
- I as readableToAsyncIterable,
3851
+ K as readableToAsyncIterable,
3756
3852
  registerAllComponents,
3757
- J as registerDefaultRenderers,
3758
- K as registerSegmentRenderer,
3759
- L as requestUserInput,
3853
+ L as registerDefaultRenderers,
3854
+ N as registerSegmentRenderer,
3855
+ O as requestUserInput,
3760
3856
  resolveConfig,
3761
3857
  runWithConfig,
3762
- P as unregisterSegmentRenderer
3858
+ R as unregisterSegmentRenderer
3763
3859
  };
3764
3860
  //# sourceMappingURL=index.js.map