anentrypoint-design 0.0.330 → 0.0.331

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/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "anentrypoint-design",
3
- "version": "0.0.330",
3
+ "version": "0.0.331",
4
4
  "description": "247420 design system SDK — webjsx + modified ripple-ui, single-file ESM bundle for reproducible use of the AnEntrypoint design.",
5
5
  "type": "module",
6
6
  "main": "./dist/247420.js",
@@ -130,6 +130,15 @@ export function injectCodeCopy(container) {
130
130
  const MD_STREAM_THROTTLE_MS = 120;
131
131
  const MD_STREAM_MIN_DELTA_CHARS = 40;
132
132
 
133
+ // requestIdleCallback with a setTimeout fallback (Safari/non-browser test
134
+ // contexts lack the real API). A settled historical message's parse is not
135
+ // latency-critical the way a streaming turn's is — deferring it off the
136
+ // critical path keeps a session-load burst of N historical bubbles from
137
+ // racing N synchronous parses on the same tick.
138
+ const scheduleIdle = typeof requestIdleCallback === 'function'
139
+ ? (fn) => requestIdleCallback(fn, { timeout: 500 })
140
+ : (fn) => setTimeout(fn, 0);
141
+
133
142
  function MdNode(p) {
134
143
  const refSink = (el) => {
135
144
  if (!el) return;
@@ -164,19 +173,34 @@ function MdNode(p) {
164
173
  // arrive (an empty bubble until the CDN import resolves reads as a
165
174
  // hang); the resolved render swaps in sanitized markdown in place.
166
175
  if (isMarkdownDegraded()) el.textContent = p.text || '';
167
- renderMarkdownCached(p.text || '').then((html) => {
168
- const swap = () => { el.innerHTML = html; injectCodeCopy(el); };
169
- // Don't blow away an active text selection inside this bubble mid-swap
170
- // (e.g. the user is mid-copy while a stream tick settles). Defer the
171
- // swap once, until the selection changes (cleared or moved elsewhere).
172
- const sel = typeof window !== 'undefined' ? window.getSelection() : null;
173
- if (sel && sel.anchorNode && el.contains(sel.anchorNode)) {
174
- const onSelChange = () => { document.removeEventListener('selectionchange', onSelChange); swap(); };
175
- document.addEventListener('selectionchange', onSelChange, { once: true });
176
- return;
177
- }
178
- swap();
179
- });
176
+ function doParse() {
177
+ renderMarkdownCached(p.text || '').then((html) => {
178
+ // The element may have been recycled (webjsx applyDiff reused this
179
+ // DOM node for a different message) or detached by the time an
180
+ // idle-deferred parse resolves -- re-check the source key still
181
+ // matches before swapping innerHTML into what could now be a
182
+ // completely different message's bubble.
183
+ if (el.dataset.mdSrc !== srcKey) return;
184
+ const swap = () => { el.innerHTML = html; injectCodeCopy(el); };
185
+ // Don't blow away an active text selection inside this bubble mid-swap
186
+ // (e.g. the user is mid-copy while a stream tick settles). Defer the
187
+ // swap once, until the selection changes (cleared or moved elsewhere).
188
+ const sel = typeof window !== 'undefined' ? window.getSelection() : null;
189
+ if (sel && sel.anchorNode && el.contains(sel.anchorNode)) {
190
+ const onSelChange = () => { document.removeEventListener('selectionchange', onSelChange); swap(); };
191
+ document.addEventListener('selectionchange', onSelChange, { once: true });
192
+ return;
193
+ }
194
+ swap();
195
+ });
196
+ }
197
+ // Streaming turns parse immediately (latency-critical: the user is
198
+ // watching this bubble grow). A settled historical message (no
199
+ // streamingCaret) is deferred to an idle slot -- not on the critical
200
+ // render path, so a page mounting many historical bubbles at once
201
+ // (session load) doesn't burst-parse them all synchronously.
202
+ if (p.streamingCaret) doParse();
203
+ else scheduleIdle(doParse);
180
204
  };
181
205
  return h('div', { class: 'chat-bubble chat-md', ref: refSink });
182
206
  }