@glyphjs/components 0.2.0 → 0.4.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
@@ -1,6 +1,7 @@
1
1
  'use strict';
2
2
 
3
3
  var schemas = require('@glyphjs/schemas');
4
+ var runtime = require('@glyphjs/runtime');
4
5
  var jsxRuntime = require('react/jsx-runtime');
5
6
  var react = require('react');
6
7
  var d32 = require('d3');
@@ -74,8 +75,8 @@ function Callout({ data }) {
74
75
  return /* @__PURE__ */ jsxRuntime.jsxs("div", { role: "note", "aria-label": CALLOUT_LABELS[type], style: containerStyle11, children: [
75
76
  /* @__PURE__ */ jsxRuntime.jsx("span", { style: iconStyle, "aria-hidden": "true", children: CALLOUT_ICONS[type] }),
76
77
  /* @__PURE__ */ jsxRuntime.jsxs("div", { style: bodyStyle3, children: [
77
- title && /* @__PURE__ */ jsxRuntime.jsx("div", { style: titleStyle2, children: title }),
78
- /* @__PURE__ */ jsxRuntime.jsx("div", { children: content })
78
+ title && /* @__PURE__ */ jsxRuntime.jsx("div", { style: titleStyle2, children: /* @__PURE__ */ jsxRuntime.jsx(runtime.RichText, { content: title }) }),
79
+ /* @__PURE__ */ jsxRuntime.jsx("div", { children: /* @__PURE__ */ jsxRuntime.jsx(runtime.RichText, { content }) })
79
80
  ] })
80
81
  ] });
81
82
  }
@@ -553,7 +554,7 @@ function Steps({ data }) {
553
554
  /* @__PURE__ */ jsxRuntime.jsx("span", { "aria-hidden": "true", style: indicatorStyle(status), children: status === "completed" ? "\u2713" : "" }),
554
555
  /* @__PURE__ */ jsxRuntime.jsxs("div", { style: bodyStyle, children: [
555
556
  /* @__PURE__ */ jsxRuntime.jsx("div", { style: titleStyle(status), children: step.title }),
556
- /* @__PURE__ */ jsxRuntime.jsx("div", { style: contentStyle(status), children: step.content })
557
+ /* @__PURE__ */ jsxRuntime.jsx("div", { style: contentStyle(status), children: /* @__PURE__ */ jsxRuntime.jsx(runtime.RichText, { content: step.content }) })
557
558
  ] })
558
559
  ]
559
560
  },
@@ -1212,7 +1213,7 @@ function Timeline({ data }) {
1212
1213
  fontWeight: 700,
1213
1214
  marginTop: 2
1214
1215
  },
1215
- children: pe.event.title
1216
+ children: /* @__PURE__ */ jsxRuntime.jsx(runtime.RichText, { content: pe.event.title })
1216
1217
  }
1217
1218
  ),
1218
1219
  pe.event.description && /* @__PURE__ */ jsxRuntime.jsx(
@@ -1223,7 +1224,7 @@ function Timeline({ data }) {
1223
1224
  color: "var(--glyph-timeline-desc-color, #7a8599)",
1224
1225
  marginTop: 2
1225
1226
  },
1226
- children: pe.event.description
1227
+ children: /* @__PURE__ */ jsxRuntime.jsx(runtime.RichText, { content: pe.event.description })
1227
1228
  }
1228
1229
  )
1229
1230
  ] })
@@ -1241,12 +1242,16 @@ function Timeline({ data }) {
1241
1242
  clipPath: "inset(50%)",
1242
1243
  whiteSpace: "nowrap"
1243
1244
  },
1244
- children: sorted.map((e, idx) => /* @__PURE__ */ jsxRuntime.jsxs("li", { children: [
1245
- /* @__PURE__ */ jsxRuntime.jsx("time", { dateTime: isoDate(e.date), children: formatDate(e.date) }),
1246
- " \u2014 ",
1247
- /* @__PURE__ */ jsxRuntime.jsx("strong", { children: e.title }),
1248
- e.description ? `: ${e.description}` : ""
1249
- ] }, idx))
1245
+ children: sorted.map((e, idx) => {
1246
+ const titleText = typeof e.title === "string" ? e.title : "Event";
1247
+ const descText = typeof e.description === "string" ? e.description : "";
1248
+ return /* @__PURE__ */ jsxRuntime.jsxs("li", { children: [
1249
+ /* @__PURE__ */ jsxRuntime.jsx("time", { dateTime: isoDate(e.date), children: formatDate(e.date) }),
1250
+ " \u2014 ",
1251
+ /* @__PURE__ */ jsxRuntime.jsx("strong", { children: titleText }),
1252
+ descText ? `: ${descText}` : ""
1253
+ ] }, idx);
1254
+ })
1250
1255
  }
1251
1256
  )
1252
1257
  ]
@@ -1450,6 +1455,326 @@ function computeForceLayout(nodes, edges) {
1450
1455
  height: maxY + LAYOUT_PADDING
1451
1456
  };
1452
1457
  }
1458
+ function useZoomInteraction({
1459
+ svgRef,
1460
+ rootRef,
1461
+ interactionMode
1462
+ }) {
1463
+ const [isActive, setIsActive] = react.useState(interactionMode === "always");
1464
+ const [hasAttemptedScroll, setHasAttemptedScroll] = react.useState(false);
1465
+ const containerRef = react.useRef(null);
1466
+ react.useEffect(() => {
1467
+ setIsActive(interactionMode === "always");
1468
+ setHasAttemptedScroll(false);
1469
+ }, [interactionMode]);
1470
+ const filterFunction = react.useCallback(
1471
+ (event) => {
1472
+ if (interactionMode === "always") {
1473
+ return true;
1474
+ }
1475
+ if (interactionMode === "modifier-key") {
1476
+ if (event.type === "mousedown") return true;
1477
+ if (event.type === "wheel") {
1478
+ const wheelEvent = event;
1479
+ const hasModifier = wheelEvent.altKey;
1480
+ if (!hasModifier && !hasAttemptedScroll) {
1481
+ setHasAttemptedScroll(true);
1482
+ setTimeout(() => setHasAttemptedScroll(false), 3e3);
1483
+ }
1484
+ return hasModifier;
1485
+ }
1486
+ return true;
1487
+ }
1488
+ if (interactionMode === "click-to-activate") {
1489
+ return isActive;
1490
+ }
1491
+ return true;
1492
+ },
1493
+ [interactionMode, isActive, hasAttemptedScroll]
1494
+ );
1495
+ react.useEffect(() => {
1496
+ if (interactionMode !== "modifier-key" || !svgRef.current) return;
1497
+ const svg = svgRef.current;
1498
+ const container = svg.parentElement;
1499
+ if (!container) return;
1500
+ const handleWheel = (event) => {
1501
+ const target = event.target;
1502
+ if (event.altKey && svg.contains(target)) {
1503
+ event.preventDefault();
1504
+ event.stopPropagation();
1505
+ }
1506
+ };
1507
+ container.addEventListener("wheel", handleWheel, { passive: false, capture: true });
1508
+ return () => {
1509
+ container.removeEventListener("wheel", handleWheel, { capture: true });
1510
+ };
1511
+ }, [interactionMode, svgRef]);
1512
+ const zoomBehavior = react.useMemo(() => {
1513
+ const zoom3 = d32__namespace.zoom().scaleExtent([0.1, 4]);
1514
+ if (typeof zoom3.filter === "function") {
1515
+ zoom3.filter(filterFunction);
1516
+ }
1517
+ zoom3.on("zoom", (event) => {
1518
+ if (rootRef.current) {
1519
+ d32__namespace.select(rootRef.current).attr("transform", event.transform.toString());
1520
+ }
1521
+ });
1522
+ return zoom3;
1523
+ }, [filterFunction, rootRef]);
1524
+ const handleActivate = react.useCallback(() => {
1525
+ if (interactionMode === "click-to-activate") {
1526
+ setIsActive(true);
1527
+ }
1528
+ }, [interactionMode]);
1529
+ react.useEffect(() => {
1530
+ if (interactionMode !== "click-to-activate" || !isActive) return;
1531
+ const handleKeyDown = (e) => {
1532
+ if (e.key === "Escape") {
1533
+ setIsActive(false);
1534
+ }
1535
+ };
1536
+ document.addEventListener("keydown", handleKeyDown);
1537
+ return () => document.removeEventListener("keydown", handleKeyDown);
1538
+ }, [interactionMode, isActive]);
1539
+ react.useEffect(() => {
1540
+ if (interactionMode !== "click-to-activate" || !isActive) return;
1541
+ const handleClickOutside = (e) => {
1542
+ const container = svgRef.current?.parentElement;
1543
+ if (container && !container.contains(e.target)) {
1544
+ setIsActive(false);
1545
+ }
1546
+ };
1547
+ document.addEventListener("click", handleClickOutside, true);
1548
+ return () => document.removeEventListener("click", handleClickOutside, true);
1549
+ }, [interactionMode, isActive, svgRef]);
1550
+ react.useEffect(() => {
1551
+ if (svgRef.current) {
1552
+ containerRef.current = svgRef.current.parentElement;
1553
+ }
1554
+ }, [svgRef]);
1555
+ const overlayProps = react.useMemo(() => {
1556
+ if (interactionMode === "always") return null;
1557
+ if (interactionMode === "modifier-key" && !hasAttemptedScroll) return null;
1558
+ if (interactionMode === "click-to-activate" && isActive) return null;
1559
+ return {
1560
+ mode: interactionMode,
1561
+ isActive,
1562
+ onActivate: handleActivate,
1563
+ width: "100%",
1564
+ height: "100%"
1565
+ };
1566
+ }, [interactionMode, isActive, hasAttemptedScroll, handleActivate]);
1567
+ const zoomIn = react.useCallback(() => {
1568
+ if (!svgRef.current) return;
1569
+ d32__namespace.select(svgRef.current).transition().duration(300).call(zoomBehavior.scaleBy, 1.3);
1570
+ }, [svgRef, zoomBehavior]);
1571
+ const zoomOut = react.useCallback(() => {
1572
+ if (!svgRef.current) return;
1573
+ d32__namespace.select(svgRef.current).transition().duration(300).call(zoomBehavior.scaleBy, 1 / 1.3);
1574
+ }, [svgRef, zoomBehavior]);
1575
+ const resetZoom = react.useCallback(() => {
1576
+ if (!svgRef.current) return;
1577
+ d32__namespace.select(svgRef.current).transition().duration(300).call(zoomBehavior.transform, d32__namespace.zoomIdentity);
1578
+ }, [svgRef, zoomBehavior]);
1579
+ return {
1580
+ isActive,
1581
+ overlayProps,
1582
+ zoomBehavior,
1583
+ zoomIn,
1584
+ zoomOut,
1585
+ resetZoom
1586
+ };
1587
+ }
1588
+ function InteractionOverlay({
1589
+ mode,
1590
+ isActive,
1591
+ onActivate,
1592
+ width,
1593
+ height
1594
+ }) {
1595
+ if (mode === "modifier-key") {
1596
+ return /* @__PURE__ */ jsxRuntime.jsx(
1597
+ "div",
1598
+ {
1599
+ className: "glyph-interaction-overlay",
1600
+ style: {
1601
+ ...OVERLAY_BASE_STYLE,
1602
+ width,
1603
+ height,
1604
+ pointerEvents: "none"
1605
+ },
1606
+ "aria-hidden": "true",
1607
+ children: /* @__PURE__ */ jsxRuntime.jsx("div", { style: TOOLTIP_STYLE, children: /* @__PURE__ */ jsxRuntime.jsx("span", { style: TOOLTIP_TEXT_STYLE, children: "Alt + scroll to zoom" }) })
1608
+ }
1609
+ );
1610
+ }
1611
+ if (mode === "click-to-activate" && !isActive) {
1612
+ return /* @__PURE__ */ jsxRuntime.jsxs(jsxRuntime.Fragment, { children: [
1613
+ /* @__PURE__ */ jsxRuntime.jsx(
1614
+ "div",
1615
+ {
1616
+ className: "glyph-interaction-overlay",
1617
+ style: {
1618
+ ...OVERLAY_BASE_STYLE,
1619
+ ...ACTIVATION_OVERLAY_STYLE,
1620
+ width,
1621
+ height
1622
+ },
1623
+ onClick: onActivate,
1624
+ role: "button",
1625
+ tabIndex: 0,
1626
+ "aria-label": "Click to activate graph interaction",
1627
+ onKeyDown: (e) => {
1628
+ if (e.key === "Enter" || e.key === " ") {
1629
+ e.preventDefault();
1630
+ onActivate();
1631
+ }
1632
+ },
1633
+ children: /* @__PURE__ */ jsxRuntime.jsx("div", { style: ACTIVATION_TEXT_STYLE, children: "Click to interact" })
1634
+ }
1635
+ ),
1636
+ /* @__PURE__ */ jsxRuntime.jsx("div", { style: SR_ONLY_STYLE, role: "status", "aria-live": "polite", "aria-atomic": "true", children: "Graph interaction inactive. Click to activate." })
1637
+ ] });
1638
+ }
1639
+ if (mode === "click-to-activate" && isActive) {
1640
+ return /* @__PURE__ */ jsxRuntime.jsxs(jsxRuntime.Fragment, { children: [
1641
+ /* @__PURE__ */ jsxRuntime.jsx(
1642
+ "div",
1643
+ {
1644
+ style: {
1645
+ ...OVERLAY_BASE_STYLE,
1646
+ width,
1647
+ height,
1648
+ pointerEvents: "none",
1649
+ border: "2px solid var(--glyph-interaction-active-border, #0a9d7c)",
1650
+ borderRadius: "4px"
1651
+ },
1652
+ "aria-hidden": "true"
1653
+ }
1654
+ ),
1655
+ /* @__PURE__ */ jsxRuntime.jsx("div", { style: SR_ONLY_STYLE, role: "status", "aria-live": "polite", "aria-atomic": "true", children: "Graph interaction active. Press Escape to deactivate." })
1656
+ ] });
1657
+ }
1658
+ return /* @__PURE__ */ jsxRuntime.jsx(jsxRuntime.Fragment, {});
1659
+ }
1660
+ var OVERLAY_BASE_STYLE = {
1661
+ position: "absolute",
1662
+ top: 0,
1663
+ left: 0,
1664
+ display: "flex",
1665
+ alignItems: "center",
1666
+ justifyContent: "center",
1667
+ zIndex: 10
1668
+ };
1669
+ var TOOLTIP_STYLE = {
1670
+ position: "absolute",
1671
+ bottom: "12px",
1672
+ right: "12px",
1673
+ padding: "6px 10px",
1674
+ backgroundColor: "var(--glyph-interaction-tooltip-bg, rgba(26, 32, 53, 0.9))",
1675
+ color: "var(--glyph-interaction-tooltip-text, #f4f6fa)",
1676
+ borderRadius: "4px",
1677
+ fontSize: "12px",
1678
+ fontFamily: "Inter, system-ui, sans-serif",
1679
+ fontWeight: 500,
1680
+ boxShadow: "0 2px 8px rgba(0, 0, 0, 0.15)",
1681
+ pointerEvents: "none"
1682
+ };
1683
+ var TOOLTIP_TEXT_STYLE = {
1684
+ display: "flex",
1685
+ alignItems: "center",
1686
+ gap: "4px"
1687
+ };
1688
+ var ACTIVATION_OVERLAY_STYLE = {
1689
+ backgroundColor: "var(--glyph-interaction-overlay-bg, rgba(244, 246, 250, 0.8))",
1690
+ cursor: "pointer",
1691
+ transition: "background-color 0.2s ease"
1692
+ };
1693
+ var ACTIVATION_TEXT_STYLE = {
1694
+ padding: "12px 20px",
1695
+ backgroundColor: "var(--glyph-interaction-tooltip-bg, rgba(26, 32, 53, 0.9))",
1696
+ color: "var(--glyph-interaction-tooltip-text, #f4f6fa)",
1697
+ borderRadius: "6px",
1698
+ fontSize: "14px",
1699
+ fontFamily: "Inter, system-ui, sans-serif",
1700
+ fontWeight: 500,
1701
+ boxShadow: "0 4px 12px rgba(0, 0, 0, 0.2)"
1702
+ };
1703
+ var SR_ONLY_STYLE = {
1704
+ position: "absolute",
1705
+ width: "1px",
1706
+ height: "1px",
1707
+ padding: 0,
1708
+ margin: "-1px",
1709
+ overflow: "hidden",
1710
+ clip: "rect(0, 0, 0, 0)",
1711
+ whiteSpace: "nowrap",
1712
+ border: 0
1713
+ };
1714
+ function ZoomControls({ onZoomIn, onZoomOut, onReset }) {
1715
+ return /* @__PURE__ */ jsxRuntime.jsxs("div", { style: CONTROLS_CONTAINER_STYLE, children: [
1716
+ /* @__PURE__ */ jsxRuntime.jsx(
1717
+ "button",
1718
+ {
1719
+ onClick: onZoomIn,
1720
+ style: BUTTON_STYLE,
1721
+ "aria-label": "Zoom in",
1722
+ title: "Zoom in",
1723
+ type: "button",
1724
+ children: /* @__PURE__ */ jsxRuntime.jsxs("svg", { width: "16", height: "16", viewBox: "0 0 16 16", fill: "none", stroke: "currentColor", children: [
1725
+ /* @__PURE__ */ jsxRuntime.jsx("line", { x1: "8", y1: "4", x2: "8", y2: "12", strokeWidth: "2" }),
1726
+ /* @__PURE__ */ jsxRuntime.jsx("line", { x1: "4", y1: "8", x2: "12", y2: "8", strokeWidth: "2" })
1727
+ ] })
1728
+ }
1729
+ ),
1730
+ /* @__PURE__ */ jsxRuntime.jsx(
1731
+ "button",
1732
+ {
1733
+ onClick: onZoomOut,
1734
+ style: BUTTON_STYLE,
1735
+ "aria-label": "Zoom out",
1736
+ title: "Zoom out",
1737
+ type: "button",
1738
+ children: /* @__PURE__ */ jsxRuntime.jsx("svg", { width: "16", height: "16", viewBox: "0 0 16 16", fill: "none", stroke: "currentColor", children: /* @__PURE__ */ jsxRuntime.jsx("line", { x1: "4", y1: "8", x2: "12", y2: "8", strokeWidth: "2" }) })
1739
+ }
1740
+ ),
1741
+ /* @__PURE__ */ jsxRuntime.jsx(
1742
+ "button",
1743
+ {
1744
+ onClick: onReset,
1745
+ style: BUTTON_STYLE,
1746
+ "aria-label": "Reset zoom",
1747
+ title: "Reset zoom",
1748
+ type: "button",
1749
+ children: /* @__PURE__ */ jsxRuntime.jsx("svg", { width: "16", height: "16", viewBox: "0 0 16 16", fill: "none", stroke: "currentColor", children: /* @__PURE__ */ jsxRuntime.jsx("rect", { x: "3", y: "3", width: "10", height: "10", strokeWidth: "2", rx: "1" }) })
1750
+ }
1751
+ )
1752
+ ] });
1753
+ }
1754
+ var CONTROLS_CONTAINER_STYLE = {
1755
+ position: "absolute",
1756
+ top: "12px",
1757
+ right: "12px",
1758
+ display: "flex",
1759
+ flexDirection: "column",
1760
+ gap: "4px",
1761
+ zIndex: 10
1762
+ };
1763
+ var BUTTON_STYLE = {
1764
+ width: "32px",
1765
+ height: "32px",
1766
+ padding: "0",
1767
+ display: "flex",
1768
+ alignItems: "center",
1769
+ justifyContent: "center",
1770
+ backgroundColor: "var(--glyph-surface-raised, #f4f6fa)",
1771
+ border: "1px solid var(--glyph-border, #d0d8e4)",
1772
+ borderRadius: "4px",
1773
+ color: "var(--glyph-text, #1a2035)",
1774
+ cursor: "pointer",
1775
+ transition: "all 0.2s ease",
1776
+ boxShadow: "0 2px 4px rgba(0, 0, 0, 0.1)"
1777
+ };
1453
1778
  var GROUP_PALETTE = [
1454
1779
  "#00d4aa",
1455
1780
  // cyan-green
@@ -1496,7 +1821,7 @@ function getThemeVar(container, varName, fallback) {
1496
1821
  return getComputedStyle(container).getPropertyValue(varName).trim() || fallback;
1497
1822
  }
1498
1823
  var ARROW_MARKER_ID = "glyph-graph-arrowhead";
1499
- function renderGraph(svgElement, layout, groupIndex, outgoingRefs, onNavigate, onNodeClick) {
1824
+ function renderGraph(svgElement, layout, groupIndex, outgoingRefs, onNavigate, zoomBehavior, onNodeClick) {
1500
1825
  const svg = d32__namespace.select(svgElement);
1501
1826
  svg.selectAll("*").remove();
1502
1827
  const width = Math.max(layout.width, 200);
@@ -1509,9 +1834,6 @@ function renderGraph(svgElement, layout, groupIndex, outgoingRefs, onNavigate, o
1509
1834
  const nodeStrokeWidth = getThemeVar(container, "--glyph-node-stroke-width", "1.5");
1510
1835
  const nodeFillOpacity = getThemeVar(container, "--glyph-node-fill-opacity", "0.85");
1511
1836
  const root = svg.append("g").attr("class", "glyph-graph-root");
1512
- const zoomBehavior = d32__namespace.zoom().scaleExtent([0.1, 4]).on("zoom", (event) => {
1513
- root.attr("transform", event.transform.toString());
1514
- });
1515
1837
  svg.call(zoomBehavior);
1516
1838
  const navigableNodes = /* @__PURE__ */ new Set();
1517
1839
  const refByAnchor = /* @__PURE__ */ new Map();
@@ -1568,6 +1890,7 @@ function Graph({
1568
1890
  container
1569
1891
  }) {
1570
1892
  const svgRef = react.useRef(null);
1893
+ const rootRef = react.useRef(null);
1571
1894
  const groupIndex = react.useRef(/* @__PURE__ */ new Map());
1572
1895
  const layoutResult = react.useMemo(() => {
1573
1896
  const direction = resolveLayout(data);
@@ -1576,6 +1899,12 @@ function Graph({
1576
1899
  }
1577
1900
  return computeDagreLayout(data.nodes, data.edges, direction);
1578
1901
  }, [data]);
1902
+ const { overlayProps, zoomBehavior, zoomIn, zoomOut, resetZoom } = useZoomInteraction({
1903
+ svgRef,
1904
+ rootRef,
1905
+ interactionMode: data.interactionMode ?? "modifier-key",
1906
+ blockId: block.id
1907
+ });
1579
1908
  const handleNodeClick = react.useMemo(() => {
1580
1909
  if (!onInteraction) return void 0;
1581
1910
  return (nodeId, nodeLabel) => {
@@ -1596,27 +1925,36 @@ function Graph({
1596
1925
  groupIndex.current,
1597
1926
  outgoingRefs,
1598
1927
  onNavigate,
1928
+ zoomBehavior,
1599
1929
  handleNodeClick
1600
1930
  );
1601
- }, [layoutResult, outgoingRefs, onNavigate, handleNodeClick]);
1931
+ const rootElement = svgRef.current.querySelector(".glyph-graph-root");
1932
+ if (rootElement) {
1933
+ rootRef.current = rootElement;
1934
+ }
1935
+ }, [layoutResult, outgoingRefs, onNavigate, zoomBehavior, handleNodeClick]);
1602
1936
  const ariaLabel = `${data.type} graph with ${data.nodes.length} nodes and ${data.edges.length} edges`;
1603
1937
  return /* @__PURE__ */ jsxRuntime.jsxs("div", { className: "glyph-graph-container", children: [
1604
- /* @__PURE__ */ jsxRuntime.jsx(
1605
- "svg",
1606
- {
1607
- ref: svgRef,
1608
- role: "img",
1609
- "aria-label": ariaLabel,
1610
- width: "100%",
1611
- height: "100%",
1612
- style: {
1613
- minHeight: container.tier === "compact" ? 200 : 300,
1614
- maxHeight: container.tier === "compact" ? 500 : 700,
1615
- display: "block"
1938
+ /* @__PURE__ */ jsxRuntime.jsxs("div", { style: { position: "relative" }, children: [
1939
+ /* @__PURE__ */ jsxRuntime.jsx(
1940
+ "svg",
1941
+ {
1942
+ ref: svgRef,
1943
+ role: "img",
1944
+ "aria-label": ariaLabel,
1945
+ width: "100%",
1946
+ height: "100%",
1947
+ style: {
1948
+ minHeight: container.tier === "compact" ? 200 : 300,
1949
+ maxHeight: container.tier === "compact" ? 500 : 700,
1950
+ display: "block"
1951
+ }
1616
1952
  }
1617
- }
1618
- ),
1619
- /* @__PURE__ */ jsxRuntime.jsxs("table", { className: "sr-only", "aria-label": "Graph data", style: SR_ONLY_STYLE, children: [
1953
+ ),
1954
+ overlayProps && /* @__PURE__ */ jsxRuntime.jsx(InteractionOverlay, { ...overlayProps }),
1955
+ /* @__PURE__ */ jsxRuntime.jsx(ZoomControls, { onZoomIn: zoomIn, onZoomOut: zoomOut, onReset: resetZoom })
1956
+ ] }),
1957
+ /* @__PURE__ */ jsxRuntime.jsxs("table", { className: "sr-only", "aria-label": "Graph data", style: SR_ONLY_STYLE2, children: [
1620
1958
  /* @__PURE__ */ jsxRuntime.jsx("caption", { children: "Graph nodes and connections" }),
1621
1959
  /* @__PURE__ */ jsxRuntime.jsx("thead", { children: /* @__PURE__ */ jsxRuntime.jsxs("tr", { children: [
1622
1960
  /* @__PURE__ */ jsxRuntime.jsx("th", { scope: "col", children: "Node" }),
@@ -1638,7 +1976,7 @@ function Graph({
1638
1976
  ] })
1639
1977
  ] });
1640
1978
  }
1641
- var SR_ONLY_STYLE = {
1979
+ var SR_ONLY_STYLE2 = {
1642
1980
  position: "absolute",
1643
1981
  width: "1px",
1644
1982
  height: "1px",
@@ -1762,16 +2100,13 @@ function drawCrowsFoot(g, x, y, angle, symbol) {
1762
2100
  g.append("line").attr("x1", tx - Math.cos(perpAngle) * halfLen).attr("y1", ty - Math.sin(perpAngle) * halfLen).attr("x2", tx + Math.cos(perpAngle) * halfLen).attr("y2", ty + Math.sin(perpAngle) * halfLen).attr("stroke", "var(--glyph-relation-line, #6b7a94)").attr("stroke-width", "var(--glyph-node-stroke-width, 1.5)");
1763
2101
  }
1764
2102
  }
1765
- function renderRelation(svgElement, layout) {
2103
+ function renderRelation(svgElement, layout, zoomBehavior) {
1766
2104
  const svg = d32__namespace.select(svgElement);
1767
2105
  svg.selectAll("*").remove();
1768
2106
  const width = Math.max(layout.width, 200);
1769
2107
  const height = Math.max(layout.height, 200);
1770
2108
  svg.attr("viewBox", `0 0 ${width} ${height}`);
1771
2109
  const root = svg.append("g").attr("class", "glyph-relation-root");
1772
- const zoomBehavior = d32__namespace.zoom().scaleExtent([0.1, 4]).on("zoom", (event) => {
1773
- root.attr("transform", event.transform.toString());
1774
- });
1775
2110
  svg.call(zoomBehavior);
1776
2111
  const entityMap = /* @__PURE__ */ new Map();
1777
2112
  for (const entity of layout.entities) {
@@ -1843,29 +2178,44 @@ function renderRelation(svgElement, layout) {
1843
2178
  }
1844
2179
  }
1845
2180
  }
1846
- function Relation({ data }) {
2181
+ function Relation({ data, block }) {
1847
2182
  const svgRef = react.useRef(null);
2183
+ const rootRef = react.useRef(null);
1848
2184
  const layoutResult = react.useMemo(() => {
1849
2185
  return computeRelationLayout(data);
1850
2186
  }, [data]);
2187
+ const { overlayProps, zoomBehavior, zoomIn, zoomOut, resetZoom } = useZoomInteraction({
2188
+ svgRef,
2189
+ rootRef,
2190
+ interactionMode: data.interactionMode ?? "modifier-key",
2191
+ blockId: block.id
2192
+ });
1851
2193
  react.useEffect(() => {
1852
2194
  if (!svgRef.current) return;
1853
- renderRelation(svgRef.current, layoutResult);
1854
- }, [layoutResult]);
2195
+ renderRelation(svgRef.current, layoutResult, zoomBehavior);
2196
+ const rootElement = svgRef.current.querySelector(".glyph-relation-root");
2197
+ if (rootElement) {
2198
+ rootRef.current = rootElement;
2199
+ }
2200
+ }, [layoutResult, zoomBehavior]);
1855
2201
  const ariaLabel = `Entity-relationship diagram with ${data.entities.length} entities and ${data.relationships.length} relationships`;
1856
2202
  return /* @__PURE__ */ jsxRuntime.jsxs("div", { className: "glyph-relation-container", children: [
1857
- /* @__PURE__ */ jsxRuntime.jsx(
1858
- "svg",
1859
- {
1860
- ref: svgRef,
1861
- role: "img",
1862
- "aria-label": ariaLabel,
1863
- width: "100%",
1864
- height: "100%",
1865
- style: { minHeight: 300, maxHeight: 700, display: "block" }
1866
- }
1867
- ),
1868
- /* @__PURE__ */ jsxRuntime.jsxs("table", { className: "sr-only", "aria-label": "Entity-relationship data", style: SR_ONLY_STYLE2, children: [
2203
+ /* @__PURE__ */ jsxRuntime.jsxs("div", { style: { position: "relative" }, children: [
2204
+ /* @__PURE__ */ jsxRuntime.jsx(
2205
+ "svg",
2206
+ {
2207
+ ref: svgRef,
2208
+ role: "img",
2209
+ "aria-label": ariaLabel,
2210
+ width: "100%",
2211
+ height: "100%",
2212
+ style: { minHeight: 300, maxHeight: 700, display: "block" }
2213
+ }
2214
+ ),
2215
+ overlayProps && /* @__PURE__ */ jsxRuntime.jsx(InteractionOverlay, { ...overlayProps }),
2216
+ /* @__PURE__ */ jsxRuntime.jsx(ZoomControls, { onZoomIn: zoomIn, onZoomOut: zoomOut, onReset: resetZoom })
2217
+ ] }),
2218
+ /* @__PURE__ */ jsxRuntime.jsxs("table", { className: "sr-only", "aria-label": "Entity-relationship data", style: SR_ONLY_STYLE3, children: [
1869
2219
  /* @__PURE__ */ jsxRuntime.jsx("caption", { children: "Entities and relationships" }),
1870
2220
  /* @__PURE__ */ jsxRuntime.jsx("thead", { children: /* @__PURE__ */ jsxRuntime.jsxs("tr", { children: [
1871
2221
  /* @__PURE__ */ jsxRuntime.jsx("th", { scope: "col", children: "Entity" }),
@@ -1888,7 +2238,7 @@ function Relation({ data }) {
1888
2238
  ] })
1889
2239
  ] });
1890
2240
  }
1891
- var SR_ONLY_STYLE2 = {
2241
+ var SR_ONLY_STYLE3 = {
1892
2242
  position: "absolute",
1893
2243
  width: "1px",
1894
2244
  height: "1px",
@@ -1918,7 +2268,8 @@ function resolveSentiment(metric) {
1918
2268
  return "neutral";
1919
2269
  }
1920
2270
  function buildAriaLabel(metric) {
1921
- let label = `${metric.label}: ${metric.value}`;
2271
+ const labelText = typeof metric.label === "string" ? metric.label : "Metric";
2272
+ let label = `${labelText}: ${metric.value}`;
1922
2273
  if (metric.unit) label += ` ${metric.unit}`;
1923
2274
  if (metric.delta && metric.trend) {
1924
2275
  label += `, ${metric.trend} ${metric.delta}`;
@@ -1990,7 +2341,7 @@ function Kpi({ data, block, container }) {
1990
2341
  color: `var(--glyph-kpi-${sentiment}, inherit)`
1991
2342
  };
1992
2343
  return /* @__PURE__ */ jsxRuntime.jsxs("div", { role: "group", "aria-label": buildAriaLabel(metric), style: cardStyle2, children: [
1993
- /* @__PURE__ */ jsxRuntime.jsx("div", { style: labelStyle4, children: metric.label }),
2344
+ /* @__PURE__ */ jsxRuntime.jsx("div", { style: labelStyle4, children: /* @__PURE__ */ jsxRuntime.jsx(runtime.RichText, { content: metric.label }) }),
1994
2345
  /* @__PURE__ */ jsxRuntime.jsxs("div", { style: valueStyle, children: [
1995
2346
  metric.value,
1996
2347
  metric.unit && /* @__PURE__ */ jsxRuntime.jsx("span", { style: { fontSize: "0.875rem", fontWeight: 400, marginLeft: "0.25rem" }, children: metric.unit })
@@ -2104,7 +2455,7 @@ function Accordion({
2104
2455
  /* @__PURE__ */ jsxRuntime.jsx("span", { "aria-hidden": "true", style: { fontSize: "0.75rem", width: "1rem", flexShrink: 0 }, children: "\u25B8" }),
2105
2456
  section.title
2106
2457
  ] }),
2107
- /* @__PURE__ */ jsxRuntime.jsx("div", { style: contentStyle2, children: section.content })
2458
+ /* @__PURE__ */ jsxRuntime.jsx("div", { style: contentStyle2, children: /* @__PURE__ */ jsxRuntime.jsx(runtime.RichText, { content: section.content }) })
2108
2459
  ]
2109
2460
  },
2110
2461
  i
@@ -2123,6 +2474,7 @@ var accordionDefinition = {
2123
2474
  var YES_VALUES = /* @__PURE__ */ new Set(["yes", "true", "full"]);
2124
2475
  var NO_VALUES = /* @__PURE__ */ new Set(["no", "false", "none"]);
2125
2476
  function classifyValue(value) {
2477
+ if (typeof value !== "string") return "text";
2126
2478
  const lower = value.toLowerCase().trim();
2127
2479
  if (YES_VALUES.has(lower)) return "yes";
2128
2480
  if (NO_VALUES.has(lower)) return "no";
@@ -2160,7 +2512,7 @@ function renderValue(value) {
2160
2512
  }
2161
2513
  );
2162
2514
  default:
2163
- return /* @__PURE__ */ jsxRuntime.jsx("span", { children: value });
2515
+ return /* @__PURE__ */ jsxRuntime.jsx("span", { children: /* @__PURE__ */ jsxRuntime.jsx(runtime.RichText, { content: value }) });
2164
2516
  }
2165
2517
  }
2166
2518
  function Comparison({
@@ -2256,7 +2608,7 @@ function Comparison({
2256
2608
  fontSize: "0.75rem",
2257
2609
  color: "var(--glyph-text-muted, #6b7a94)"
2258
2610
  },
2259
- children: option.description
2611
+ children: /* @__PURE__ */ jsxRuntime.jsx(runtime.RichText, { content: option.description })
2260
2612
  }
2261
2613
  )
2262
2614
  ]
@@ -2277,8 +2629,8 @@ function Comparison({
2277
2629
  }
2278
2630
  ),
2279
2631
  options.map((_, colIndex) => {
2280
- const value = feature.values[colIndex] ?? "";
2281
- return /* @__PURE__ */ jsxRuntime.jsx("td", { style: cellStyle2(rowIndex), children: value ? renderValue(value) : null }, colIndex);
2632
+ const value = feature.values[colIndex];
2633
+ return /* @__PURE__ */ jsxRuntime.jsx("td", { style: cellStyle2(rowIndex), children: value !== void 0 && value !== "" ? renderValue(value) : null }, colIndex);
2282
2634
  })
2283
2635
  ] }, rowIndex)) })
2284
2636
  ] }) })
@@ -2522,7 +2874,7 @@ function renderNodeShape(nodeG, node, fillOpacity, strokeWidth) {
2522
2874
  }
2523
2875
  }
2524
2876
  }
2525
- function renderFlowchart(svgElement, layout) {
2877
+ function renderFlowchart(svgElement, layout, zoomBehavior) {
2526
2878
  const svg = d32__namespace.select(svgElement);
2527
2879
  svg.selectAll("*").remove();
2528
2880
  const width = Math.max(layout.width, 200);
@@ -2534,9 +2886,6 @@ function renderFlowchart(svgElement, layout) {
2534
2886
  const nodeStrokeWidth = getThemeVar2(container, "--glyph-node-stroke-width", "1.5");
2535
2887
  const nodeFillOpacity = getThemeVar2(container, "--glyph-node-fill-opacity", "0.85");
2536
2888
  const root = svg.append("g").attr("class", "glyph-flowchart-root");
2537
- const zoomBehavior = d32__namespace.zoom().scaleExtent([0.1, 4]).on("zoom", (event) => {
2538
- root.attr("transform", event.transform.toString());
2539
- });
2540
2889
  svg.call(zoomBehavior);
2541
2890
  const lineGen = d32__namespace.line().x((d) => d.x).y((d) => d.y).curve(d32__namespace.curveBasis);
2542
2891
  const edgeGroup = root.append("g").attr("class", "glyph-flowchart-edges");
@@ -2557,13 +2906,28 @@ function renderFlowchart(svgElement, layout) {
2557
2906
  nodeG.append("text").attr("x", node.x).attr("y", node.y).attr("dy", "0.35em").attr("text-anchor", "middle").attr("font-size", "13px").attr("font-family", "Inter, system-ui, sans-serif").attr("fill", "var(--glyph-node-label-color, #fff)").attr("pointer-events", "none").text(node.label);
2558
2907
  }
2559
2908
  }
2560
- function Flowchart({ data, container }) {
2909
+ function Flowchart({
2910
+ data,
2911
+ block,
2912
+ container
2913
+ }) {
2561
2914
  const svgRef = react.useRef(null);
2915
+ const rootRef = react.useRef(null);
2562
2916
  const layoutResult = react.useMemo(() => computeLayout(data.nodes, data.edges, data.direction), [data]);
2917
+ const { overlayProps, zoomBehavior, zoomIn, zoomOut, resetZoom } = useZoomInteraction({
2918
+ svgRef,
2919
+ rootRef,
2920
+ interactionMode: data.interactionMode ?? "modifier-key",
2921
+ blockId: block.id
2922
+ });
2563
2923
  react.useEffect(() => {
2564
2924
  if (!svgRef.current) return;
2565
- renderFlowchart(svgRef.current, layoutResult);
2566
- }, [layoutResult]);
2925
+ renderFlowchart(svgRef.current, layoutResult, zoomBehavior);
2926
+ const rootElement = svgRef.current.querySelector(".glyph-flowchart-root");
2927
+ if (rootElement) {
2928
+ rootRef.current = rootElement;
2929
+ }
2930
+ }, [layoutResult, zoomBehavior]);
2567
2931
  const nodeCount = data.nodes.length;
2568
2932
  const edgeCount = data.edges.length;
2569
2933
  const ariaLabel = data.title ? `${data.title}: flowchart with ${nodeCount} nodes and ${edgeCount} edges` : `Flowchart with ${nodeCount} nodes and ${edgeCount} edges`;
@@ -2581,22 +2945,26 @@ function Flowchart({ data, container }) {
2581
2945
  children: data.title
2582
2946
  }
2583
2947
  ),
2584
- /* @__PURE__ */ jsxRuntime.jsx(
2585
- "svg",
2586
- {
2587
- ref: svgRef,
2588
- role: "img",
2589
- "aria-label": ariaLabel,
2590
- width: "100%",
2591
- height: "100%",
2592
- style: {
2593
- minHeight: container.tier === "compact" ? 200 : 300,
2594
- maxHeight: container.tier === "compact" ? 500 : 700,
2595
- display: "block"
2948
+ /* @__PURE__ */ jsxRuntime.jsxs("div", { style: { position: "relative" }, children: [
2949
+ /* @__PURE__ */ jsxRuntime.jsx(
2950
+ "svg",
2951
+ {
2952
+ ref: svgRef,
2953
+ role: "img",
2954
+ "aria-label": ariaLabel,
2955
+ width: "100%",
2956
+ height: "100%",
2957
+ style: {
2958
+ minHeight: container.tier === "compact" ? 200 : 300,
2959
+ maxHeight: container.tier === "compact" ? 500 : 700,
2960
+ display: "block"
2961
+ }
2596
2962
  }
2597
- }
2598
- ),
2599
- /* @__PURE__ */ jsxRuntime.jsxs("table", { className: "sr-only", "aria-label": "Flowchart data", style: SR_ONLY_STYLE3, children: [
2963
+ ),
2964
+ overlayProps && /* @__PURE__ */ jsxRuntime.jsx(InteractionOverlay, { ...overlayProps }),
2965
+ /* @__PURE__ */ jsxRuntime.jsx(ZoomControls, { onZoomIn: zoomIn, onZoomOut: zoomOut, onReset: resetZoom })
2966
+ ] }),
2967
+ /* @__PURE__ */ jsxRuntime.jsxs("table", { className: "sr-only", "aria-label": "Flowchart data", style: SR_ONLY_STYLE4, children: [
2600
2968
  /* @__PURE__ */ jsxRuntime.jsx("caption", { children: "Flowchart nodes and connections" }),
2601
2969
  /* @__PURE__ */ jsxRuntime.jsx("thead", { children: /* @__PURE__ */ jsxRuntime.jsxs("tr", { children: [
2602
2970
  /* @__PURE__ */ jsxRuntime.jsx("th", { scope: "col", children: "Node" }),
@@ -2618,7 +2986,7 @@ function Flowchart({ data, container }) {
2618
2986
  ] })
2619
2987
  ] });
2620
2988
  }
2621
- var SR_ONLY_STYLE3 = {
2989
+ var SR_ONLY_STYLE4 = {
2622
2990
  position: "absolute",
2623
2991
  width: "1px",
2624
2992
  height: "1px",
@@ -3240,7 +3608,7 @@ function Sequence({ data, container }) {
3240
3608
  ]
3241
3609
  }
3242
3610
  ),
3243
- /* @__PURE__ */ jsxRuntime.jsxs("table", { className: "sr-only", "aria-label": "Sequence data", style: SR_ONLY_STYLE4, children: [
3611
+ /* @__PURE__ */ jsxRuntime.jsxs("table", { className: "sr-only", "aria-label": "Sequence data", style: SR_ONLY_STYLE5, children: [
3244
3612
  /* @__PURE__ */ jsxRuntime.jsx("caption", { children: "Sequence messages in order" }),
3245
3613
  /* @__PURE__ */ jsxRuntime.jsx("thead", { children: /* @__PURE__ */ jsxRuntime.jsxs("tr", { children: [
3246
3614
  /* @__PURE__ */ jsxRuntime.jsx("th", { scope: "col", children: "#" }),
@@ -3263,7 +3631,7 @@ function Sequence({ data, container }) {
3263
3631
  ] })
3264
3632
  ] });
3265
3633
  }
3266
- var SR_ONLY_STYLE4 = {
3634
+ var SR_ONLY_STYLE5 = {
3267
3635
  position: "absolute",
3268
3636
  width: "1px",
3269
3637
  height: "1px",
@@ -3669,7 +4037,7 @@ function Architecture({
3669
4037
  }
3670
4038
  }
3671
4039
  ),
3672
- /* @__PURE__ */ jsxRuntime.jsxs("table", { className: "sr-only", "aria-label": "Architecture data", style: SR_ONLY_STYLE5, children: [
4040
+ /* @__PURE__ */ jsxRuntime.jsxs("table", { className: "sr-only", "aria-label": "Architecture data", style: SR_ONLY_STYLE6, children: [
3673
4041
  /* @__PURE__ */ jsxRuntime.jsx("caption", { children: "Architecture nodes and connections" }),
3674
4042
  /* @__PURE__ */ jsxRuntime.jsx("thead", { children: /* @__PURE__ */ jsxRuntime.jsxs("tr", { children: [
3675
4043
  /* @__PURE__ */ jsxRuntime.jsx("th", { scope: "col", children: "Node" }),
@@ -3713,7 +4081,7 @@ function countLeafNodes(children) {
3713
4081
  }
3714
4082
  return count;
3715
4083
  }
3716
- var SR_ONLY_STYLE5 = {
4084
+ var SR_ONLY_STYLE6 = {
3717
4085
  position: "absolute",
3718
4086
  width: "1px",
3719
4087
  height: "1px",
@@ -3901,7 +4269,7 @@ function layoutTree(data) {
3901
4269
  };
3902
4270
  }
3903
4271
  function renderAccessibleList(root, children) {
3904
- return /* @__PURE__ */ jsxRuntime.jsx("ul", { style: SR_ONLY_STYLE6, role: "list", "aria-label": "Mind map structure", children: /* @__PURE__ */ jsxRuntime.jsxs("li", { children: [
4272
+ return /* @__PURE__ */ jsxRuntime.jsx("ul", { style: SR_ONLY_STYLE7, role: "list", "aria-label": "Mind map structure", children: /* @__PURE__ */ jsxRuntime.jsxs("li", { children: [
3905
4273
  root,
3906
4274
  children.length > 0 && renderAccessibleChildren(children)
3907
4275
  ] }) });
@@ -4028,7 +4396,7 @@ function MindMap({ data, container }) {
4028
4396
  renderAccessibleList(data.root, data.children)
4029
4397
  ] });
4030
4398
  }
4031
- var SR_ONLY_STYLE6 = {
4399
+ var SR_ONLY_STYLE7 = {
4032
4400
  position: "absolute",
4033
4401
  width: "1px",
4034
4402
  height: "1px",
@@ -4229,7 +4597,8 @@ function isCorrect(question, selected) {
4229
4597
  }
4230
4598
  function renderMultipleChoice(question, qIndex, state, updateState, baseId) {
4231
4599
  const selected = typeof state.selected === "number" ? state.selected : null;
4232
- return /* @__PURE__ */ jsxRuntime.jsx("div", { role: "radiogroup", "aria-label": question.question, children: question.options.map((option, oIndex) => {
4600
+ const ariaLabel = typeof question.question === "string" ? question.question : "Question";
4601
+ return /* @__PURE__ */ jsxRuntime.jsx("div", { role: "radiogroup", "aria-label": ariaLabel, children: question.options.map((option, oIndex) => {
4233
4602
  const isSelected = selected === oIndex;
4234
4603
  const isCorrectOption = state.submitted && oIndex === question.answer;
4235
4604
  const isIncorrectSelection = state.submitted && isSelected && oIndex !== question.answer;
@@ -4255,7 +4624,7 @@ function renderMultipleChoice(question, qIndex, state, updateState, baseId) {
4255
4624
  "aria-checked": isSelected
4256
4625
  }
4257
4626
  ),
4258
- option
4627
+ /* @__PURE__ */ jsxRuntime.jsx(runtime.RichText, { content: option })
4259
4628
  ]
4260
4629
  },
4261
4630
  oIndex
@@ -4264,7 +4633,8 @@ function renderMultipleChoice(question, qIndex, state, updateState, baseId) {
4264
4633
  }
4265
4634
  function renderTrueFalse(question, qIndex, state, updateState, baseId) {
4266
4635
  const selected = typeof state.selected === "boolean" ? state.selected : null;
4267
- return /* @__PURE__ */ jsxRuntime.jsx("div", { role: "radiogroup", "aria-label": question.question, children: [true, false].map((value) => {
4636
+ const ariaLabel = typeof question.question === "string" ? question.question : "Question";
4637
+ return /* @__PURE__ */ jsxRuntime.jsx("div", { role: "radiogroup", "aria-label": ariaLabel, children: [true, false].map((value) => {
4268
4638
  const isSelected = selected === value;
4269
4639
  const isCorrectOption = state.submitted && value === question.answer;
4270
4640
  const isIncorrectSelection = state.submitted && isSelected && value !== question.answer;
@@ -4328,7 +4698,7 @@ function renderMultiSelect(question, qIndex, state, updateState) {
4328
4698
  "aria-checked": isSelected
4329
4699
  }
4330
4700
  ),
4331
- option
4701
+ /* @__PURE__ */ jsxRuntime.jsx(runtime.RichText, { content: option })
4332
4702
  ]
4333
4703
  },
4334
4704
  oIndex
@@ -4367,7 +4737,7 @@ function Quiz({ data, block, onInteraction }) {
4367
4737
  children: [
4368
4738
  /* @__PURE__ */ jsxRuntime.jsxs("div", { style: questionTextStyle, children: [
4369
4739
  questions.length > 1 ? `${String(qIndex + 1)}. ` : "",
4370
- question.question
4740
+ /* @__PURE__ */ jsxRuntime.jsx(runtime.RichText, { content: question.question })
4371
4741
  ] }),
4372
4742
  question.type === "multiple-choice" && renderMultipleChoice(question, qIndex, state, updateState, baseId),
4373
4743
  question.type === "true-false" && renderTrueFalse(question, qIndex, state, updateState, baseId),
@@ -4391,15 +4761,24 @@ function Quiz({ data, block, onInteraction }) {
4391
4761
  let selected;
4392
4762
  switch (question.type) {
4393
4763
  case "multiple-choice":
4394
- selected = typeof state.selected === "number" ? [question.options[state.selected] ?? String(state.selected)] : [];
4764
+ if (typeof state.selected === "number") {
4765
+ const opt = question.options[state.selected];
4766
+ selected = [typeof opt === "string" ? opt : String(state.selected)];
4767
+ } else {
4768
+ selected = [];
4769
+ }
4395
4770
  break;
4396
4771
  case "true-false":
4397
4772
  selected = typeof state.selected === "boolean" ? [state.selected ? "True" : "False"] : [];
4398
4773
  break;
4399
4774
  case "multi-select":
4400
- selected = Array.isArray(state.selected) ? state.selected.map((idx) => question.options[idx] ?? String(idx)) : [];
4775
+ selected = Array.isArray(state.selected) ? state.selected.map((idx) => {
4776
+ const opt = question.options[idx];
4777
+ return typeof opt === "string" ? opt : String(idx);
4778
+ }) : [];
4401
4779
  break;
4402
4780
  }
4781
+ const questionText = typeof question.question === "string" ? question.question : "Question";
4403
4782
  onInteraction({
4404
4783
  kind: "quiz-submit",
4405
4784
  timestamp: (/* @__PURE__ */ new Date()).toISOString(),
@@ -4407,7 +4786,7 @@ function Quiz({ data, block, onInteraction }) {
4407
4786
  blockType: block.type,
4408
4787
  payload: {
4409
4788
  questionIndex: qIndex,
4410
- question: question.question,
4789
+ question: questionText,
4411
4790
  selected,
4412
4791
  correct: correct2,
4413
4792
  score: { correct: newScore, total: questions.length }
@@ -4420,7 +4799,7 @@ function Quiz({ data, block, onInteraction }) {
4420
4799
  ),
4421
4800
  /* @__PURE__ */ jsxRuntime.jsxs("div", { "aria-live": "polite", children: [
4422
4801
  state.submitted && /* @__PURE__ */ jsxRuntime.jsx("div", { style: feedbackStyle(correct), children: correct ? "Correct!" : "Incorrect" }),
4423
- state.submitted && question.explanation && /* @__PURE__ */ jsxRuntime.jsx("div", { style: explanationStyle, children: question.explanation })
4802
+ state.submitted && question.explanation && /* @__PURE__ */ jsxRuntime.jsx("div", { style: explanationStyle, children: /* @__PURE__ */ jsxRuntime.jsx(runtime.RichText, { content: question.explanation }) })
4424
4803
  ] })
4425
4804
  ]
4426
4805
  },
@@ -4558,8 +4937,8 @@ function Card({ data, block, container }) {
4558
4937
  /* @__PURE__ */ jsxRuntime.jsxs("div", { style: cardBodyStyle, children: [
4559
4938
  card.icon && /* @__PURE__ */ jsxRuntime.jsx("div", { style: iconStyle, children: card.icon }),
4560
4939
  /* @__PURE__ */ jsxRuntime.jsx("h3", { style: titleStyle2, children: card.title }),
4561
- card.subtitle && /* @__PURE__ */ jsxRuntime.jsx("div", { style: subtitleStyle, children: card.subtitle }),
4562
- card.body && /* @__PURE__ */ jsxRuntime.jsx("div", { style: bodyStyle3, children: card.body }),
4940
+ card.subtitle && /* @__PURE__ */ jsxRuntime.jsx("div", { style: subtitleStyle, children: /* @__PURE__ */ jsxRuntime.jsx(runtime.RichText, { content: card.subtitle }) }),
4941
+ card.body && /* @__PURE__ */ jsxRuntime.jsx("div", { style: bodyStyle3, children: /* @__PURE__ */ jsxRuntime.jsx(runtime.RichText, { content: card.body }) }),
4563
4942
  card.actions && card.actions.length > 0 && /* @__PURE__ */ jsxRuntime.jsx("div", { style: actionsStyle, children: card.actions.map((action, j) => /* @__PURE__ */ jsxRuntime.jsx(
4564
4943
  "a",
4565
4944
  {
@@ -4666,7 +5045,7 @@ function renderStatGroup(items, keyPrefix) {
4666
5045
  return /* @__PURE__ */ jsxRuntime.jsx("div", { style: rowStyle, "data-group": "stat", children: items.map((item, i) => /* @__PURE__ */ jsxRuntime.jsxs("div", { style: statStyle, children: [
4667
5046
  /* @__PURE__ */ jsxRuntime.jsx("div", { style: valueStyle, children: item.value }),
4668
5047
  /* @__PURE__ */ jsxRuntime.jsx("div", { style: labelStyle4, children: item.label }),
4669
- item.description && /* @__PURE__ */ jsxRuntime.jsx("div", { style: descStyle, children: item.description })
5048
+ item.description && /* @__PURE__ */ jsxRuntime.jsx("div", { style: descStyle, children: /* @__PURE__ */ jsxRuntime.jsx(runtime.RichText, { content: item.description }) })
4670
5049
  ] }, `${keyPrefix}-${String(i)}`)) }, keyPrefix);
4671
5050
  }
4672
5051
  function renderProgressGroup(items, keyPrefix, colorOffset) {
@@ -4759,7 +5138,7 @@ function renderFactGroup(items, keyPrefix) {
4759
5138
  children: item.icon
4760
5139
  }
4761
5140
  ),
4762
- item.text
5141
+ /* @__PURE__ */ jsxRuntime.jsx(runtime.RichText, { content: item.text })
4763
5142
  ] }, `${keyPrefix}-${String(i)}`)) }, keyPrefix);
4764
5143
  }
4765
5144
  function renderTextGroup(items, keyPrefix) {
@@ -5241,17 +5620,21 @@ function Poll({ data, block, onInteraction }) {
5241
5620
  blockId: block.id,
5242
5621
  blockType: block.type,
5243
5622
  payload: {
5244
- selectedOptions: selected.map((i) => options[i] ?? String(i)),
5623
+ selectedOptions: selected.map((i) => {
5624
+ const opt = options[i];
5625
+ return typeof opt === "string" ? opt : String(i);
5626
+ }),
5245
5627
  selectedIndices: [...selected]
5246
5628
  }
5247
5629
  });
5248
5630
  }
5249
5631
  };
5250
5632
  const totalVotes = votes.reduce((a, b) => a + b, 0);
5633
+ const questionAriaLabel = typeof question === "string" ? question : "Poll question";
5251
5634
  return /* @__PURE__ */ jsxRuntime.jsxs("div", { id: baseId, role: "region", "aria-label": title ?? "Poll", style: containerStyle3, children: [
5252
5635
  title && /* @__PURE__ */ jsxRuntime.jsx("div", { style: headerStyle2, children: title }),
5253
- /* @__PURE__ */ jsxRuntime.jsx("div", { style: questionStyle, children: question }),
5254
- /* @__PURE__ */ jsxRuntime.jsx("div", { role: "group", "aria-label": question, style: optionsStyle, children: options.map((option, index) => /* @__PURE__ */ jsxRuntime.jsxs("label", { style: optionLabelStyle2(selected.includes(index)), children: [
5636
+ /* @__PURE__ */ jsxRuntime.jsx("div", { style: questionStyle, children: /* @__PURE__ */ jsxRuntime.jsx(runtime.RichText, { content: question }) }),
5637
+ /* @__PURE__ */ jsxRuntime.jsx("div", { role: "group", "aria-label": questionAriaLabel, style: optionsStyle, children: options.map((option, index) => /* @__PURE__ */ jsxRuntime.jsxs("label", { style: optionLabelStyle2(selected.includes(index)), children: [
5255
5638
  /* @__PURE__ */ jsxRuntime.jsx(
5256
5639
  "input",
5257
5640
  {
@@ -5263,7 +5646,7 @@ function Poll({ data, block, onInteraction }) {
5263
5646
  "aria-checked": selected.includes(index)
5264
5647
  }
5265
5648
  ),
5266
- option
5649
+ /* @__PURE__ */ jsxRuntime.jsx(runtime.RichText, { content: option })
5267
5650
  ] }, index)) }),
5268
5651
  !hasVoted && /* @__PURE__ */ jsxRuntime.jsx(
5269
5652
  "button",
@@ -5282,9 +5665,10 @@ function Poll({ data, block, onInteraction }) {
5282
5665
  showResults && hasVoted && /* @__PURE__ */ jsxRuntime.jsx("div", { role: "status", "aria-live": "polite", style: resultsStyle, children: options.map((option, index) => {
5283
5666
  const count = votes[index] ?? 0;
5284
5667
  const percentage = totalVotes > 0 ? count / totalVotes * 100 : 0;
5668
+ const optionLabel = typeof option === "string" ? option : "Option";
5285
5669
  return /* @__PURE__ */ jsxRuntime.jsxs("div", { style: resultRowStyle, children: [
5286
5670
  /* @__PURE__ */ jsxRuntime.jsxs("div", { style: resultLabelStyle, children: [
5287
- /* @__PURE__ */ jsxRuntime.jsx("span", { children: option }),
5671
+ /* @__PURE__ */ jsxRuntime.jsx("span", { children: /* @__PURE__ */ jsxRuntime.jsx(runtime.RichText, { content: option }) }),
5288
5672
  /* @__PURE__ */ jsxRuntime.jsxs("span", { children: [
5289
5673
  String(count),
5290
5674
  " vote",
@@ -5302,7 +5686,7 @@ function Poll({ data, block, onInteraction }) {
5302
5686
  "aria-valuenow": percentage,
5303
5687
  "aria-valuemin": 0,
5304
5688
  "aria-valuemax": 100,
5305
- "aria-label": `${option}: ${String(Math.round(percentage))}%`,
5689
+ "aria-label": `${optionLabel}: ${String(Math.round(percentage))}%`,
5306
5690
  children: /* @__PURE__ */ jsxRuntime.jsx("div", { style: barFillStyle(percentage) })
5307
5691
  }
5308
5692
  )
@@ -5404,6 +5788,8 @@ function Rating({
5404
5788
  newRatings[itemIndex] = value;
5405
5789
  setRatings(newRatings);
5406
5790
  if (onInteraction) {
5791
+ const item = items[itemIndex];
5792
+ const itemLabel = item ? typeof item.label === "string" ? item.label : "Item" : "";
5407
5793
  onInteraction({
5408
5794
  kind: "rating-change",
5409
5795
  timestamp: (/* @__PURE__ */ new Date()).toISOString(),
@@ -5411,10 +5797,10 @@ function Rating({
5411
5797
  blockType: block.type,
5412
5798
  payload: {
5413
5799
  itemIndex,
5414
- itemLabel: items[itemIndex]?.label ?? "",
5800
+ itemLabel,
5415
5801
  value,
5416
- allRatings: items.map((item, i) => ({
5417
- label: item.label,
5802
+ allRatings: items.map((item2, i) => ({
5803
+ label: typeof item2.label === "string" ? item2.label : "Item",
5418
5804
  value: i === itemIndex ? value : newRatings[i] ?? null
5419
5805
  }))
5420
5806
  }
@@ -5426,10 +5812,11 @@ function Rating({
5426
5812
  items.map((item, itemIndex) => {
5427
5813
  const currentRating = ratings[itemIndex] ?? null;
5428
5814
  const isLast = itemIndex === items.length - 1;
5815
+ const itemLabelText = typeof item.label === "string" ? item.label : "Item";
5429
5816
  return /* @__PURE__ */ jsxRuntime.jsxs("div", { style: itemStyle2(isLast), children: [
5430
- /* @__PURE__ */ jsxRuntime.jsx("div", { style: itemLabelStyle, children: item.label }),
5431
- item.description && /* @__PURE__ */ jsxRuntime.jsx("div", { style: itemDescriptionStyle, children: item.description }),
5432
- /* @__PURE__ */ jsxRuntime.jsx("div", { role: "radiogroup", "aria-label": `Rate ${item.label}`, style: starsContainerStyle, children: Array.from({ length: scale }, (_, starIndex) => {
5817
+ /* @__PURE__ */ jsxRuntime.jsx("div", { style: itemLabelStyle, children: /* @__PURE__ */ jsxRuntime.jsx(runtime.RichText, { content: item.label }) }),
5818
+ item.description && /* @__PURE__ */ jsxRuntime.jsx("div", { style: itemDescriptionStyle, children: /* @__PURE__ */ jsxRuntime.jsx(runtime.RichText, { content: item.description }) }),
5819
+ /* @__PURE__ */ jsxRuntime.jsx("div", { role: "radiogroup", "aria-label": `Rate ${itemLabelText}`, style: starsContainerStyle, children: Array.from({ length: scale }, (_, starIndex) => {
5433
5820
  const value = starIndex + 1;
5434
5821
  const isHovered = hoveredStar !== null && hoveredStar.itemIndex === itemIndex && value <= hoveredStar.value;
5435
5822
  const isFilled = currentRating !== null && value <= currentRating;
@@ -5483,7 +5870,7 @@ function Rating({
5483
5870
  whiteSpace: "nowrap",
5484
5871
  border: 0
5485
5872
  },
5486
- children: currentRating !== null && `${item.label} rated ${String(currentRating)} out of ${String(scale)}`
5873
+ children: currentRating !== null && `${itemLabelText} rated ${String(currentRating)} out of ${String(scale)}`
5487
5874
  }
5488
5875
  )
5489
5876
  ] }, itemIndex);
@@ -5590,12 +5977,12 @@ function Ranker({
5590
5977
  payload: {
5591
5978
  orderedItems: newItems.map((item, i) => ({
5592
5979
  id: item.id,
5593
- label: item.label,
5980
+ label: typeof item.label === "string" ? item.label : "Item",
5594
5981
  rank: i + 1
5595
5982
  })),
5596
5983
  movedItem: {
5597
5984
  id: moved.id,
5598
- label: moved.label,
5985
+ label: typeof moved.label === "string" ? moved.label : "Item",
5599
5986
  fromRank: fromIndex + 1,
5600
5987
  toRank: toIndex + 1
5601
5988
  }
@@ -5633,26 +6020,29 @@ function Ranker({
5633
6020
  };
5634
6021
  return /* @__PURE__ */ jsxRuntime.jsxs("div", { id: baseId, role: "region", "aria-label": title ?? "Ranker", style: containerStyle5, children: [
5635
6022
  title && /* @__PURE__ */ jsxRuntime.jsx("div", { style: headerStyle4, children: title }),
5636
- /* @__PURE__ */ jsxRuntime.jsx("ul", { role: "list", "aria-label": title ?? "Rank items", style: listStyle, children: items.map((item, index) => /* @__PURE__ */ jsxRuntime.jsxs(
5637
- "li",
5638
- {
5639
- role: "listitem",
5640
- "aria-grabbed": grabbedIndex === index,
5641
- "aria-label": `${item.label}, rank ${String(index + 1)}`,
5642
- tabIndex: 0,
5643
- style: itemStyle3(false, grabbedIndex === index),
5644
- onKeyDown: (e) => handleKeyDown(e, index),
5645
- children: [
5646
- /* @__PURE__ */ jsxRuntime.jsx("span", { style: gripStyle, "aria-hidden": "true", children: "\u283F" }),
5647
- /* @__PURE__ */ jsxRuntime.jsx("span", { style: rankBadgeStyle, children: String(index + 1) }),
5648
- /* @__PURE__ */ jsxRuntime.jsxs("div", { style: itemContentStyle, children: [
5649
- /* @__PURE__ */ jsxRuntime.jsx("div", { style: itemLabelStyle2, children: item.label }),
5650
- item.description && /* @__PURE__ */ jsxRuntime.jsx("div", { style: itemDescriptionStyle2, children: item.description })
5651
- ] })
5652
- ]
5653
- },
5654
- item.id
5655
- )) }),
6023
+ /* @__PURE__ */ jsxRuntime.jsx("ul", { role: "list", "aria-label": title ?? "Rank items", style: listStyle, children: items.map((item, index) => {
6024
+ const itemLabelText = typeof item.label === "string" ? item.label : "Item";
6025
+ return /* @__PURE__ */ jsxRuntime.jsxs(
6026
+ "li",
6027
+ {
6028
+ role: "listitem",
6029
+ "aria-grabbed": grabbedIndex === index,
6030
+ "aria-label": `${itemLabelText}, rank ${String(index + 1)}`,
6031
+ tabIndex: 0,
6032
+ style: itemStyle3(false, grabbedIndex === index),
6033
+ onKeyDown: (e) => handleKeyDown(e, index),
6034
+ children: [
6035
+ /* @__PURE__ */ jsxRuntime.jsx("span", { style: gripStyle, "aria-hidden": "true", children: "\u283F" }),
6036
+ /* @__PURE__ */ jsxRuntime.jsx("span", { style: rankBadgeStyle, children: String(index + 1) }),
6037
+ /* @__PURE__ */ jsxRuntime.jsxs("div", { style: itemContentStyle, children: [
6038
+ /* @__PURE__ */ jsxRuntime.jsx("div", { style: itemLabelStyle2, children: /* @__PURE__ */ jsxRuntime.jsx(runtime.RichText, { content: item.label }) }),
6039
+ item.description && /* @__PURE__ */ jsxRuntime.jsx("div", { style: itemDescriptionStyle2, children: item.description })
6040
+ ] })
6041
+ ]
6042
+ },
6043
+ item.id
6044
+ );
6045
+ }) }),
5656
6046
  /* @__PURE__ */ jsxRuntime.jsx(
5657
6047
  "div",
5658
6048
  {
@@ -5668,7 +6058,7 @@ function Ranker({
5668
6058
  whiteSpace: "nowrap",
5669
6059
  border: 0
5670
6060
  },
5671
- children: grabbedIndex !== null && `${items[grabbedIndex]?.label ?? ""} grabbed, rank ${String(grabbedIndex + 1)} of ${String(items.length)}. Use arrow keys to move.`
6061
+ children: grabbedIndex !== null && items[grabbedIndex] !== void 0 ? `${typeof items[grabbedIndex].label === "string" ? items[grabbedIndex].label : "Item"} grabbed, rank ${String(grabbedIndex + 1)} of ${String(items.length)}. Use arrow keys to move.` : ""
5672
6062
  }
5673
6063
  )
5674
6064
  ] });
@@ -5754,11 +6144,11 @@ function Slider({
5754
6144
  blockType: block.type,
5755
6145
  payload: {
5756
6146
  parameterId: param.id,
5757
- parameterLabel: param.label,
6147
+ parameterLabel: typeof param.label === "string" ? param.label : "Parameter",
5758
6148
  value: newValue,
5759
6149
  allValues: parameters.map((p, i) => ({
5760
6150
  id: p.id,
5761
- label: p.label,
6151
+ label: typeof p.label === "string" ? p.label : "Parameter",
5762
6152
  value: i === paramIndex ? newValue : newValues[i] ?? 0
5763
6153
  }))
5764
6154
  }
@@ -5778,7 +6168,7 @@ function Slider({
5778
6168
  const isLast = index === parameters.length - 1;
5779
6169
  return /* @__PURE__ */ jsxRuntime.jsxs("div", { style: parameterStyle(isLast), children: [
5780
6170
  /* @__PURE__ */ jsxRuntime.jsxs("div", { style: parameterHeaderStyle, children: [
5781
- /* @__PURE__ */ jsxRuntime.jsx("label", { htmlFor: `${baseId}-${param.id}`, style: parameterLabelStyle, children: param.label }),
6171
+ /* @__PURE__ */ jsxRuntime.jsx("label", { htmlFor: `${baseId}-${param.id}`, style: parameterLabelStyle, children: /* @__PURE__ */ jsxRuntime.jsx(runtime.RichText, { content: param.label }) }),
5782
6172
  /* @__PURE__ */ jsxRuntime.jsx("span", { style: parameterValueStyle, "aria-live": "polite", children: formatValue(currentValue, param.unit) })
5783
6173
  ] }),
5784
6174
  /* @__PURE__ */ jsxRuntime.jsx(
@@ -5891,7 +6281,8 @@ function computeWeightedTotals(rows, columns, values) {
5891
6281
  const weight = col.weight ?? 1;
5892
6282
  total += score * weight;
5893
6283
  }
5894
- return { rowId: row.id, rowLabel: row.label, total: Math.round(total * 100) / 100 };
6284
+ const rowLabel = typeof row.label === "string" ? row.label : "Row";
6285
+ return { rowId: row.id, rowLabel, total: Math.round(total * 100) / 100 };
5895
6286
  });
5896
6287
  }
5897
6288
  function Matrix({
@@ -5934,9 +6325,9 @@ function Matrix({
5934
6325
  blockType: block.type,
5935
6326
  payload: {
5936
6327
  rowId,
5937
- rowLabel: row.label,
6328
+ rowLabel: typeof row.label === "string" ? row.label : "Row",
5938
6329
  columnId,
5939
- columnLabel: col.label,
6330
+ columnLabel: typeof col.label === "string" ? col.label : "Column",
5940
6331
  value: clamped,
5941
6332
  allValues: payloadValues,
5942
6333
  weightedTotals: computeWeightedTotals(rows, columns, newValues)
@@ -5955,7 +6346,7 @@ function Matrix({
5955
6346
  /* @__PURE__ */ jsxRuntime.jsx("thead", { children: /* @__PURE__ */ jsxRuntime.jsxs("tr", { children: [
5956
6347
  /* @__PURE__ */ jsxRuntime.jsx("th", { style: thStyle }),
5957
6348
  columns.map((col) => /* @__PURE__ */ jsxRuntime.jsxs("th", { style: thStyle, children: [
5958
- col.label,
6349
+ /* @__PURE__ */ jsxRuntime.jsx(runtime.RichText, { content: col.label }),
5959
6350
  (col.weight ?? 1) !== 1 && /* @__PURE__ */ jsxRuntime.jsxs("div", { style: weightStyle, children: [
5960
6351
  "\xD7",
5961
6352
  String(col.weight)
@@ -5965,10 +6356,12 @@ function Matrix({
5965
6356
  ] }) }),
5966
6357
  /* @__PURE__ */ jsxRuntime.jsx("tbody", { children: rows.map((row) => {
5967
6358
  const rowTotal = totals.find((t) => t.rowId === row.id)?.total ?? 0;
6359
+ const rowLabelText = typeof row.label === "string" ? row.label : "Row";
5968
6360
  return /* @__PURE__ */ jsxRuntime.jsxs("tr", { children: [
5969
- /* @__PURE__ */ jsxRuntime.jsx("th", { scope: "row", style: rowHeaderStyle, children: row.label }),
6361
+ /* @__PURE__ */ jsxRuntime.jsx("th", { scope: "row", style: rowHeaderStyle, children: /* @__PURE__ */ jsxRuntime.jsx(runtime.RichText, { content: row.label }) }),
5970
6362
  columns.map((col) => {
5971
6363
  const cellValue = values[row.id]?.[col.id] ?? 0;
6364
+ const colLabelText = typeof col.label === "string" ? col.label : "Column";
5972
6365
  return /* @__PURE__ */ jsxRuntime.jsx("td", { style: cellStyle, children: /* @__PURE__ */ jsxRuntime.jsx(
5973
6366
  "input",
5974
6367
  {
@@ -5977,7 +6370,7 @@ function Matrix({
5977
6370
  max: scale,
5978
6371
  value: cellValue,
5979
6372
  onChange: (e) => handleChange(row.id, col.id, Number(e.target.value)),
5980
- "aria-label": `Score for ${row.label} on ${col.label}`,
6373
+ "aria-label": `Score for ${rowLabelText} on ${colLabelText}`,
5981
6374
  style: inputStyle
5982
6375
  }
5983
6376
  ) }, col.id);
@@ -6271,7 +6664,7 @@ function Form({ data, block, onInteraction }) {
6271
6664
  };
6272
6665
  return /* @__PURE__ */ jsxRuntime.jsxs("div", { id: baseId, role: "region", "aria-label": title ?? "Form", style: containerStyle8, children: [
6273
6666
  title && /* @__PURE__ */ jsxRuntime.jsx("div", { style: headerStyle7, children: title }),
6274
- description && /* @__PURE__ */ jsxRuntime.jsx("div", { style: descriptionStyle, children: description }),
6667
+ description && /* @__PURE__ */ jsxRuntime.jsx("div", { style: descriptionStyle, children: /* @__PURE__ */ jsxRuntime.jsx(runtime.RichText, { content: description }) }),
6275
6668
  /* @__PURE__ */ jsxRuntime.jsxs("form", { onSubmit: handleSubmit, style: formStyle, noValidate: true, children: [
6276
6669
  fields.map(
6277
6670
  (field) => renderField({ field, baseId, values, validation, submitted, updateValue })
@@ -6658,6 +7051,9 @@ var annotationNoteStyle = {
6658
7051
  marginTop: "0.125rem"
6659
7052
  };
6660
7053
  function computeSegments(text, annotations) {
7054
+ if (typeof text !== "string") {
7055
+ return [{ text: "", start: 0, annotation: null }];
7056
+ }
6661
7057
  if (annotations.length === 0) {
6662
7058
  return [{ text, start: 0, annotation: null }];
6663
7059
  }
@@ -6737,7 +7133,7 @@ function Annotate({
6737
7133
  allAnnotations: newAnnotations.map((a) => ({
6738
7134
  start: a.start,
6739
7135
  end: a.end,
6740
- text: text.slice(a.start, a.end),
7136
+ text: typeof text === "string" ? text.slice(a.start, a.end) : "",
6741
7137
  label: a.label
6742
7138
  }))
6743
7139
  }
@@ -6763,7 +7159,7 @@ function Annotate({
6763
7159
  title && /* @__PURE__ */ jsxRuntime.jsx("div", { style: headerStyle9, children: title }),
6764
7160
  /* @__PURE__ */ jsxRuntime.jsxs("div", { style: bodyStyle2, children: [
6765
7161
  /* @__PURE__ */ jsxRuntime.jsxs("div", { ref: textRef, role: "document", style: textPaneStyle, onMouseUp: handleMouseUp, children: [
6766
- segments.map((seg, i) => {
7162
+ typeof text === "string" ? segments.map((seg, i) => {
6767
7163
  if (seg.annotation) {
6768
7164
  const color3 = labelColorMap.get(seg.annotation.label) ?? "#888";
6769
7165
  return /* @__PURE__ */ jsxRuntime.jsx(
@@ -6781,7 +7177,7 @@ function Annotate({
6781
7177
  );
6782
7178
  }
6783
7179
  return /* @__PURE__ */ jsxRuntime.jsx("span", { children: seg.text }, i);
6784
- }),
7180
+ }) : /* @__PURE__ */ jsxRuntime.jsx(runtime.RichText, { content: text }),
6785
7181
  pickerPos && /* @__PURE__ */ jsxRuntime.jsx(
6786
7182
  "div",
6787
7183
  {
@@ -6820,12 +7216,13 @@ function Annotate({
6820
7216
  /* @__PURE__ */ jsxRuntime.jsxs("div", { role: "list", children: [
6821
7217
  annotations.map((ann, i) => {
6822
7218
  const color3 = labelColorMap.get(ann.label) ?? "#888";
7219
+ const annotatedText = typeof text === "string" ? text.slice(ann.start, ann.end) : "";
6823
7220
  return /* @__PURE__ */ jsxRuntime.jsxs("div", { role: "listitem", style: annotationItemStyle(color3), children: [
6824
7221
  /* @__PURE__ */ jsxRuntime.jsxs("div", { style: { display: "flex", alignItems: "center", gap: "0.375rem" }, children: [
6825
7222
  /* @__PURE__ */ jsxRuntime.jsx("span", { style: colorDotStyle(color3) }),
6826
7223
  /* @__PURE__ */ jsxRuntime.jsx("strong", { style: { fontSize: "0.75rem" }, children: ann.label })
6827
7224
  ] }),
6828
- /* @__PURE__ */ jsxRuntime.jsx("div", { style: annotationTextStyle, children: text.slice(ann.start, ann.end) }),
7225
+ /* @__PURE__ */ jsxRuntime.jsx("div", { style: annotationTextStyle, children: annotatedText }),
6829
7226
  ann.note && /* @__PURE__ */ jsxRuntime.jsx("div", { style: annotationNoteStyle, children: ann.note })
6830
7227
  ] }, i);
6831
7228
  }),