@supersuit/artifacts 0.44.1 → 0.44.3

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/CHANGELOG.md CHANGED
@@ -3,6 +3,30 @@
3
3
  `@supersuit/artifacts`. One entry per version, newest first. Each entry says what changed, how a
4
4
  host can tell whether it is affected (DETECTOR), what a host does about it (REMEDY), and the tests.
5
5
 
6
+ ## 0.44.2
7
+
8
+ **An embed's caption no longer throws the read-along out of step.** The caption under a
9
+ ` ```simulator ` or ` ```messages ` block was wrapped as read-along words, but the narration skips
10
+ every fenced block, so each caption added words the voice never says and every word after it lit
11
+ early. A page carrying four embeds ran about sixty words ahead by its end. The embed's figure is now
12
+ `data-nospeak`: the caption still shows, and the highlighter skips it as the voice does.
13
+
14
+ - DETECTOR: on a narrated page with a simulator or messages block, play past the block. Before, the
15
+ highlight ran ahead of the voice; now it stays on the spoken word.
16
+ - REMEDY: update the dependency. Nothing to change on a page.
17
+ - Tests: "an embed block is not read aloud" in render.test.tsx, both kinds, with and without a
18
+ player, the wrapped words equal the narrated words.
19
+
20
+ ## 0.44.3
21
+
22
+ **Escape closes a comment card.** Pressing Escape cancels the comment being written (nothing is
23
+ saved), or closes the open thread, or the comments panel, topmost first. It ignores an Escape
24
+ another layer already handled, so the definition popover and page menu keep theirs.
25
+
26
+ - DETECTOR: select text, press Comment, press Escape. Before, the card stayed open.
27
+ - REMEDY: update the dependency.
28
+ - Tests: comment-layer.test.tsx, "Escape cancels the comment being written, saving nothing".
29
+
6
30
  ## 0.44.1
7
31
 
8
32
  **Highlighting text works like any page again.** A press in the gap between paragraphs, in a line's
@@ -134,7 +134,10 @@ function EmbedFence({ kind, source, ctx }) {
134
134
  return null;
135
135
  const src = ctx ? embedSrc(kind, ctx.embed, r.block.value) : null;
136
136
  const wide = kind === 'simulator' && src != null;
137
- return (_jsxs("figure", { "data-artifact-embed": kind, ...(kind === 'simulator' ? { 'data-artifact-simulator': '' } : {}), ...(wide ? { 'data-wide': '' } : {}), className: "my-8", children: [wide ? _jsx("style", { children: WIDE_EMBED_CSS }) : null, src ? _jsx(EmbedFrame, { src: src, title: r.block.caption, height: r.block.height }) : null, _jsx("figcaption", { className: "mt-2 text-sm opacity-80", children: r.block.caption })] }));
137
+ return (
138
+ // data-nospeak: the narration skips every fenced block (narration.ts), so the caption must not
139
+ // be a read-along word either, or every word after it lights out of step with the voice.
140
+ _jsxs("figure", { "data-artifact-embed": kind, "data-nospeak": true, ...(kind === 'simulator' ? { 'data-artifact-simulator': '' } : {}), ...(wide ? { 'data-wide': '' } : {}), className: "my-8", children: [wide ? _jsx("style", { children: WIDE_EMBED_CSS }) : null, src ? _jsx(EmbedFrame, { src: src, title: r.block.caption, height: r.block.height }) : null, _jsx("figcaption", { className: "mt-2 text-sm opacity-80", children: r.block.caption })] }));
138
141
  }
139
142
  /** The one image a paragraph holds and nothing else (whitespace aside), or null. */
140
143
  function soleImage(node) {
@@ -251,6 +251,27 @@ export function CommentLayer({ artifactId, rootId, ownerName, comments, canShare
251
251
  ro.observe(root);
252
252
  return () => { live = false; window.removeEventListener('resize', relayout); ro?.disconnect(); };
253
253
  }, [artifactId, comments, signedIn, stateUrl, personalUrl, rootId, call, refreshDevice, host, audioDb]);
254
+ // Escape closes the top card: the comment being written, else the open thread, else the panel.
255
+ // Writing a comment is a draft nobody has saved, so Escape is its Cancel.
256
+ useEffect(() => {
257
+ if (!draft && !thread && !panel)
258
+ return;
259
+ const onKey = (e) => {
260
+ if (e.key !== 'Escape' || e.defaultPrevented)
261
+ return;
262
+ e.preventDefault();
263
+ if (draft)
264
+ setDraft(null);
265
+ else if (thread) {
266
+ setThread(null);
267
+ setExpanded(null);
268
+ }
269
+ else
270
+ setPanel(false);
271
+ };
272
+ document.addEventListener('keydown', onKey);
273
+ return () => document.removeEventListener('keydown', onKey);
274
+ }, [draft, thread, panel]);
254
275
  // Text selection inside the page shows the Comment chip.
255
276
  useEffect(() => {
256
277
  const root = document.getElementById(rootId);
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@supersuit/artifacts",
3
- "version": "0.44.1",
3
+ "version": "0.44.3",
4
4
  "description": "Publish markdown as branded, read-aloud pages from a Next.js app: the artifacts store, the route factory, the read-along reader, brand packs, password and confidential pages, and share cards.",
5
5
  "license": "MIT",
6
6
  "type": "module",