@glyphjs/components 0.1.0 → 0.2.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
@@ -46,7 +46,7 @@ var CALLOUT_LABELS = {
46
46
  };
47
47
  function Callout({ data }) {
48
48
  const { type, title, content } = data;
49
- const containerStyle3 = {
49
+ const containerStyle11 = {
50
50
  backgroundColor: `var(--glyph-callout-${type}-bg)`,
51
51
  borderLeft: `4px solid var(--glyph-callout-${type}-border)`,
52
52
  borderRadius: "var(--glyph-radius-md, 0.1875rem)",
@@ -63,7 +63,7 @@ function Callout({ data }) {
63
63
  fontSize: "1.25em",
64
64
  lineHeight: 1
65
65
  };
66
- const bodyStyle2 = {
66
+ const bodyStyle3 = {
67
67
  flex: 1,
68
68
  minWidth: 0
69
69
  };
@@ -71,9 +71,9 @@ function Callout({ data }) {
71
71
  fontWeight: 700,
72
72
  marginBottom: "var(--glyph-spacing-xs, 0.25rem)"
73
73
  };
74
- return /* @__PURE__ */ jsxRuntime.jsxs("div", { role: "note", "aria-label": CALLOUT_LABELS[type], style: containerStyle3, children: [
74
+ return /* @__PURE__ */ jsxRuntime.jsxs("div", { role: "note", "aria-label": CALLOUT_LABELS[type], style: containerStyle11, children: [
75
75
  /* @__PURE__ */ jsxRuntime.jsx("span", { style: iconStyle, "aria-hidden": "true", children: CALLOUT_ICONS[type] }),
76
- /* @__PURE__ */ jsxRuntime.jsxs("div", { style: bodyStyle2, children: [
76
+ /* @__PURE__ */ jsxRuntime.jsxs("div", { style: bodyStyle3, children: [
77
77
  title && /* @__PURE__ */ jsxRuntime.jsx("div", { style: titleStyle2, children: title }),
78
78
  /* @__PURE__ */ jsxRuntime.jsx("div", { children: content })
79
79
  ] })
@@ -278,9 +278,104 @@ function computeScales(width, height, type, series, xKey, yKey, margin) {
278
278
  const yScale = d32__namespace.scaleLinear().domain([yMin, yMax]).nice().range([innerHeight, 0]);
279
279
  return { xScale, xScalePoint, yScale, innerWidth, innerHeight };
280
280
  }
281
+ function renderAllSeries(g, type, series, scales, xKey, yKey, showTooltip, hideTooltip) {
282
+ const { xScale, xScalePoint, yScale, innerHeight } = scales;
283
+ series.forEach((s, i) => {
284
+ const color3 = COLOR_SCHEME[i % COLOR_SCHEME.length] ?? "#333";
285
+ switch (type) {
286
+ case "line":
287
+ renderLineSeries(
288
+ g,
289
+ s.data,
290
+ xScalePoint,
291
+ yScale,
292
+ yKey,
293
+ xKey,
294
+ color3,
295
+ i,
296
+ s.name,
297
+ showTooltip,
298
+ hideTooltip
299
+ );
300
+ break;
301
+ case "area":
302
+ renderAreaSeries(
303
+ g,
304
+ s.data,
305
+ xScalePoint,
306
+ yScale,
307
+ yKey,
308
+ xKey,
309
+ innerHeight,
310
+ color3,
311
+ i,
312
+ s.name,
313
+ showTooltip,
314
+ hideTooltip
315
+ );
316
+ break;
317
+ case "bar":
318
+ renderBarSeries(
319
+ g,
320
+ s.data,
321
+ xScale,
322
+ yScale,
323
+ yKey,
324
+ xKey,
325
+ color3,
326
+ i,
327
+ series.length,
328
+ innerHeight,
329
+ s.name,
330
+ showTooltip,
331
+ hideTooltip
332
+ );
333
+ break;
334
+ case "ohlc":
335
+ renderOHLCSeries(
336
+ g,
337
+ s.data,
338
+ xScale,
339
+ xScalePoint,
340
+ yScale,
341
+ scales.innerWidth,
342
+ s.name,
343
+ showTooltip,
344
+ hideTooltip
345
+ );
346
+ break;
347
+ }
348
+ });
349
+ }
350
+ function attachChartInteraction(g, type, series, xKey, yKey, block, onInteraction) {
351
+ if (!onInteraction) return;
352
+ series.forEach((s, seriesIdx) => {
353
+ const className = type === "bar" ? `bar-${String(seriesIdx)}` : `dot-${String(seriesIdx)}`;
354
+ g.selectAll(`.${className}`).on(
355
+ "click",
356
+ (_event, d) => {
357
+ const dataIdx = s.data.indexOf(d);
358
+ onInteraction({
359
+ kind: "chart-select",
360
+ timestamp: (/* @__PURE__ */ new Date()).toISOString(),
361
+ blockId: block.id,
362
+ blockType: block.type,
363
+ payload: {
364
+ seriesIndex: seriesIdx,
365
+ dataIndex: dataIdx >= 0 ? dataIdx : 0,
366
+ label: String(d[xKey] ?? ""),
367
+ value: getNumericValue(d, yKey)
368
+ }
369
+ });
370
+ }
371
+ );
372
+ });
373
+ }
281
374
  function Chart({
282
375
  data,
283
- container: containerCtx
376
+ block,
377
+ container: containerCtx,
378
+ onInteraction
284
379
  }) {
285
380
  const containerRef = react.useRef(null);
286
381
  const svgRef = react.useRef(null);
@@ -333,76 +428,19 @@ function Chart({
333
428
  if (!svg || series.length === 0) return;
334
429
  const sel = d32__namespace.select(svg);
335
430
  sel.selectAll("*").remove();
336
- const { xScale, xScalePoint, yScale, innerWidth, innerHeight } = scales;
337
431
  const g = sel.append("g").attr("transform", `translate(${String(margin.left)},${String(margin.top)})`);
338
- renderAxes(g, xScale, yScale, xAxis, yAxis, innerWidth, innerHeight);
339
- renderGridLines(g, yScale, innerWidth);
340
- series.forEach((s, i) => {
341
- const color3 = COLOR_SCHEME[i % COLOR_SCHEME.length] ?? "#333";
342
- switch (type) {
343
- case "line":
344
- renderLineSeries(
345
- g,
346
- s.data,
347
- xScalePoint,
348
- yScale,
349
- yKey,
350
- xKey,
351
- color3,
352
- i,
353
- s.name,
354
- showTooltip,
355
- hideTooltip
356
- );
357
- break;
358
- case "area":
359
- renderAreaSeries(
360
- g,
361
- s.data,
362
- xScalePoint,
363
- yScale,
364
- yKey,
365
- xKey,
366
- innerHeight,
367
- color3,
368
- i,
369
- s.name,
370
- showTooltip,
371
- hideTooltip
372
- );
373
- break;
374
- case "bar":
375
- renderBarSeries(
376
- g,
377
- s.data,
378
- xScale,
379
- yScale,
380
- yKey,
381
- xKey,
382
- color3,
383
- i,
384
- series.length,
385
- innerHeight,
386
- s.name,
387
- showTooltip,
388
- hideTooltip
389
- );
390
- break;
391
- case "ohlc":
392
- renderOHLCSeries(
393
- g,
394
- s.data,
395
- xScale,
396
- xScalePoint,
397
- yScale,
398
- innerWidth,
399
- s.name,
400
- showTooltip,
401
- hideTooltip
402
- );
403
- break;
404
- }
405
- });
432
+ renderAxes(
433
+ g,
434
+ scales.xScale,
435
+ scales.yScale,
436
+ xAxis,
437
+ yAxis,
438
+ scales.innerWidth,
439
+ scales.innerHeight
440
+ );
441
+ renderGridLines(g, scales.yScale, scales.innerWidth);
442
+ renderAllSeries(g, type, series, scales, xKey, yKey, showTooltip, hideTooltip);
443
+ attachChartInteraction(g, type, series, xKey, yKey, block, onInteraction);
406
444
  if (legend) {
407
445
  renderLegend(sel, series, margin.left, margin.top, isCompact ? "10px" : void 0);
408
446
  }
@@ -418,7 +456,9 @@ function Chart({
418
456
  margin,
419
457
  isCompact,
420
458
  showTooltip,
421
- hideTooltip
459
+ hideTooltip,
460
+ onInteraction,
461
+ block
422
462
  ]);
423
463
  const ariaLabel = `${type} chart with ${String(series.length)} series: ${series.map((s) => s.name).join(", ")}`;
424
464
  return /* @__PURE__ */ jsxRuntime.jsxs(
@@ -492,14 +532,14 @@ var STATUS_LABELS = {
492
532
  };
493
533
  function Steps({ data }) {
494
534
  const { steps } = data;
495
- const listStyle = {
535
+ const listStyle2 = {
496
536
  listStyle: "none",
497
537
  padding: 0,
498
538
  margin: "var(--glyph-spacing-sm, 0.5rem) 0",
499
539
  fontFamily: "var(--glyph-font-body, system-ui, sans-serif)",
500
540
  color: "var(--glyph-text, #1a2035)"
501
541
  };
502
- return /* @__PURE__ */ jsxRuntime.jsx("ol", { role: "list", style: listStyle, children: steps.map((step, index) => {
542
+ return /* @__PURE__ */ jsxRuntime.jsx("ol", { role: "list", style: listStyle2, children: steps.map((step, index) => {
503
543
  const status = step.status ?? "pending";
504
544
  const isLast = index === steps.length - 1;
505
545
  return /* @__PURE__ */ jsxRuntime.jsxs(
@@ -646,7 +686,95 @@ function TableAggregationFooter({
646
686
  );
647
687
  }) }) });
648
688
  }
649
- function Table({ data, container }) {
689
+ function TableHead({
690
+ columns,
691
+ sort,
692
+ hasFilters,
693
+ filters,
694
+ onSort,
695
+ onHeaderKeyDown,
696
+ onFilterChange
697
+ }) {
698
+ return /* @__PURE__ */ jsxRuntime.jsxs("thead", { children: [
699
+ /* @__PURE__ */ jsxRuntime.jsx("tr", { children: columns.map((col) => {
700
+ const isSorted = sort.column === col.key;
701
+ const direction = isSorted ? sort.direction : "none";
702
+ return /* @__PURE__ */ jsxRuntime.jsxs(
703
+ "th",
704
+ {
705
+ scope: "col",
706
+ "aria-sort": col.sortable ? direction : void 0,
707
+ tabIndex: col.sortable ? 0 : void 0,
708
+ role: col.sortable ? "columnheader" : void 0,
709
+ onClick: col.sortable ? () => onSort(col.key) : void 0,
710
+ onKeyDown: col.sortable ? (e) => onHeaderKeyDown(e, col.key) : void 0,
711
+ style: {
712
+ padding: "var(--glyph-table-cell-padding, 8px 12px)",
713
+ textAlign: "left",
714
+ borderBottom: "2px solid var(--glyph-table-border, #d0d8e4)",
715
+ background: "var(--glyph-table-header-bg, #e8ecf3)",
716
+ color: "var(--glyph-table-header-color, inherit)",
717
+ cursor: col.sortable ? "pointer" : "default",
718
+ userSelect: col.sortable ? "none" : void 0,
719
+ whiteSpace: "nowrap"
720
+ },
721
+ children: [
722
+ col.label,
723
+ col.sortable ? sortIndicator(direction) : ""
724
+ ]
725
+ },
726
+ col.key
727
+ );
728
+ }) }),
729
+ hasFilters && /* @__PURE__ */ jsxRuntime.jsx("tr", { children: columns.map((col) => /* @__PURE__ */ jsxRuntime.jsx(
730
+ "th",
731
+ {
732
+ scope: "col",
733
+ style: { padding: "4px 8px", fontWeight: "normal" },
734
+ children: col.filterable ? /* @__PURE__ */ jsxRuntime.jsx(
735
+ "input",
736
+ {
737
+ type: "text",
738
+ "aria-label": `Filter ${col.label}`,
739
+ placeholder: `Filter ${col.label}...`,
740
+ value: filters[col.key] ?? "",
741
+ onChange: (e) => onFilterChange(col.key, e.target.value),
742
+ style: {
743
+ width: "100%",
744
+ padding: "4px 6px",
745
+ border: "1px solid var(--glyph-table-border, #d0d8e4)",
746
+ borderRadius: "3px",
747
+ fontSize: "inherit",
748
+ boxSizing: "border-box",
749
+ background: "var(--glyph-surface, #e8ecf3)",
750
+ color: "var(--glyph-text, inherit)"
751
+ }
752
+ }
753
+ ) : /* @__PURE__ */ jsxRuntime.jsx(
754
+ "span",
755
+ {
756
+ style: {
757
+ position: "absolute",
758
+ width: "1px",
759
+ height: "1px",
760
+ overflow: "hidden",
761
+ clip: "rect(0,0,0,0)",
762
+ whiteSpace: "nowrap"
763
+ },
764
+ children: `No filter for ${col.label}`
765
+ }
766
+ )
767
+ },
768
+ `filter-${col.key}`
769
+ )) })
770
+ ] });
771
+ }
772
+ function Table({
773
+ data,
774
+ block,
775
+ container,
776
+ onInteraction
777
+ }) {
650
778
  const { columns, rows, aggregation } = data;
651
779
  const [sort, setSort] = react.useState({ column: "", direction: "none" });
652
780
  const [filters, setFilters] = react.useState({});
@@ -679,12 +807,27 @@ function Table({ data, container }) {
679
807
  });
680
808
  }, [filteredRows, sort]);
681
809
  const handleSort = (columnKey) => {
682
- setSort((prev) => {
683
- if (prev.column === columnKey) {
684
- return { column: columnKey, direction: nextDirection(prev.direction) };
685
- }
686
- return { column: columnKey, direction: "ascending" };
687
- });
810
+ const newDirection = sort.column === columnKey ? nextDirection(sort.direction) : "ascending";
811
+ setSort({ column: columnKey, direction: newDirection });
812
+ if (onInteraction) {
813
+ const eventDir = newDirection === "ascending" ? "asc" : newDirection === "descending" ? "desc" : "none";
814
+ onInteraction({
815
+ kind: "table-sort",
816
+ timestamp: (/* @__PURE__ */ new Date()).toISOString(),
817
+ blockId: block.id,
818
+ blockType: block.type,
819
+ payload: {
820
+ column: columnKey,
821
+ direction: eventDir,
822
+ state: {
823
+ sort: newDirection === "none" ? null : { column: columnKey, direction: eventDir },
824
+ filters,
825
+ visibleRowCount: filteredRows.length,
826
+ totalRowCount: rows.length
827
+ }
828
+ }
829
+ });
830
+ }
688
831
  };
689
832
  const handleHeaderKeyDown = (e, columnKey) => {
690
833
  if (e.key === "Enter" || e.key === " ") {
@@ -693,7 +836,38 @@ function Table({ data, container }) {
693
836
  }
694
837
  };
695
838
  const handleFilterChange = (columnKey, value) => {
696
- setFilters((prev) => ({ ...prev, [columnKey]: value }));
839
+ const newFilters = { ...filters, [columnKey]: value };
840
+ setFilters(newFilters);
841
+ if (onInteraction) {
842
+ const newVisibleCount = rows.filter(
843
+ (row) => columns.every((col) => {
844
+ if (!col.filterable) return true;
845
+ const fv = newFilters[col.key];
846
+ if (!fv) return true;
847
+ return String(row[col.key] ?? "").toLowerCase().includes(fv.toLowerCase());
848
+ })
849
+ ).length;
850
+ const eventSort = sort.direction === "none" || !sort.column ? null : {
851
+ column: sort.column,
852
+ direction: sort.direction === "ascending" ? "asc" : "desc"
853
+ };
854
+ onInteraction({
855
+ kind: "table-filter",
856
+ timestamp: (/* @__PURE__ */ new Date()).toISOString(),
857
+ blockId: block.id,
858
+ blockType: block.type,
859
+ payload: {
860
+ column: columnKey,
861
+ value,
862
+ state: {
863
+ sort: eventSort,
864
+ filters: newFilters,
865
+ visibleRowCount: newVisibleCount,
866
+ totalRowCount: rows.length
867
+ }
868
+ }
869
+ });
870
+ }
697
871
  };
698
872
  const hasFilters = columns.some((c) => c.filterable);
699
873
  const aggMap = react.useMemo(() => {
@@ -717,79 +891,18 @@ function Table({ data, container }) {
717
891
  fontSize: isCompact ? "0.8125rem" : "var(--glyph-table-font-size, 0.9rem)"
718
892
  },
719
893
  children: [
720
- /* @__PURE__ */ jsxRuntime.jsxs("thead", { children: [
721
- /* @__PURE__ */ jsxRuntime.jsx("tr", { children: columns.map((col) => {
722
- const isSorted = sort.column === col.key;
723
- const direction = isSorted ? sort.direction : "none";
724
- return /* @__PURE__ */ jsxRuntime.jsxs(
725
- "th",
726
- {
727
- scope: "col",
728
- "aria-sort": col.sortable ? direction : void 0,
729
- tabIndex: col.sortable ? 0 : void 0,
730
- role: col.sortable ? "columnheader" : void 0,
731
- onClick: col.sortable ? () => handleSort(col.key) : void 0,
732
- onKeyDown: col.sortable ? (e) => handleHeaderKeyDown(e, col.key) : void 0,
733
- style: {
734
- padding: "var(--glyph-table-cell-padding, 8px 12px)",
735
- textAlign: "left",
736
- borderBottom: "2px solid var(--glyph-table-border, #d0d8e4)",
737
- background: "var(--glyph-table-header-bg, #e8ecf3)",
738
- color: "var(--glyph-table-header-color, inherit)",
739
- cursor: col.sortable ? "pointer" : "default",
740
- userSelect: col.sortable ? "none" : void 0,
741
- whiteSpace: "nowrap"
742
- },
743
- children: [
744
- col.label,
745
- col.sortable ? sortIndicator(direction) : ""
746
- ]
747
- },
748
- col.key
749
- );
750
- }) }),
751
- hasFilters && /* @__PURE__ */ jsxRuntime.jsx("tr", { children: columns.map((col) => /* @__PURE__ */ jsxRuntime.jsx(
752
- "th",
753
- {
754
- scope: "col",
755
- style: { padding: "4px 8px", fontWeight: "normal" },
756
- children: col.filterable ? /* @__PURE__ */ jsxRuntime.jsx(
757
- "input",
758
- {
759
- type: "text",
760
- "aria-label": `Filter ${col.label}`,
761
- placeholder: `Filter ${col.label}...`,
762
- value: filters[col.key] ?? "",
763
- onChange: (e) => handleFilterChange(col.key, e.target.value),
764
- style: {
765
- width: "100%",
766
- padding: "4px 6px",
767
- border: "1px solid var(--glyph-table-border, #d0d8e4)",
768
- borderRadius: "3px",
769
- fontSize: "inherit",
770
- boxSizing: "border-box",
771
- background: "var(--glyph-surface, #e8ecf3)",
772
- color: "var(--glyph-text, inherit)"
773
- }
774
- }
775
- ) : /* @__PURE__ */ jsxRuntime.jsx(
776
- "span",
777
- {
778
- style: {
779
- position: "absolute",
780
- width: "1px",
781
- height: "1px",
782
- overflow: "hidden",
783
- clip: "rect(0,0,0,0)",
784
- whiteSpace: "nowrap"
785
- },
786
- children: `No filter for ${col.label}`
787
- }
788
- )
789
- },
790
- `filter-${col.key}`
791
- )) })
792
- ] }),
894
+ /* @__PURE__ */ jsxRuntime.jsx(
895
+ TableHead,
896
+ {
897
+ columns,
898
+ sort,
899
+ hasFilters,
900
+ filters,
901
+ onSort: handleSort,
902
+ onHeaderKeyDown: handleHeaderKeyDown,
903
+ onFilterChange: handleFilterChange
904
+ }
905
+ ),
793
906
  /* @__PURE__ */ jsxRuntime.jsx("tbody", { children: sortedRows.map((row, rowIdx) => /* @__PURE__ */ jsxRuntime.jsx(
794
907
  "tr",
795
908
  {
@@ -827,18 +940,28 @@ var tableDefinition = {
827
940
  schema: schemas.tableSchema,
828
941
  render: Table
829
942
  };
830
- function Tabs({ data, block }) {
943
+ function Tabs({ data, block, onInteraction }) {
831
944
  const [activeIndex, setActiveIndex] = react.useState(0);
832
945
  const tabRefs = react.useRef([]);
833
946
  const tabs = data.tabs;
834
947
  const baseId = `glyph-tabs-${block.id}`;
835
- const focusTab = react.useCallback(
948
+ const selectTab = react.useCallback(
836
949
  (index) => {
837
950
  const clampedIndex = Math.max(0, Math.min(index, tabs.length - 1));
838
951
  setActiveIndex(clampedIndex);
839
952
  tabRefs.current[clampedIndex]?.focus();
953
+ const tab = tabs[clampedIndex];
954
+ if (tab) {
955
+ onInteraction?.({
956
+ kind: "tab-select",
957
+ timestamp: (/* @__PURE__ */ new Date()).toISOString(),
958
+ blockId: block.id,
959
+ blockType: block.type,
960
+ payload: { tabIndex: clampedIndex, tabLabel: tab.label }
961
+ });
962
+ }
840
963
  },
841
- [tabs.length]
964
+ [tabs, block.id, block.type, onInteraction]
842
965
  );
843
966
  const handleKeyDown = react.useCallback(
844
967
  (e) => {
@@ -846,28 +969,28 @@ function Tabs({ data, block }) {
846
969
  case "ArrowRight": {
847
970
  e.preventDefault();
848
971
  const next = (activeIndex + 1) % tabs.length;
849
- focusTab(next);
972
+ selectTab(next);
850
973
  break;
851
974
  }
852
975
  case "ArrowLeft": {
853
976
  e.preventDefault();
854
977
  const prev = (activeIndex - 1 + tabs.length) % tabs.length;
855
- focusTab(prev);
978
+ selectTab(prev);
856
979
  break;
857
980
  }
858
981
  case "Home": {
859
982
  e.preventDefault();
860
- focusTab(0);
983
+ selectTab(0);
861
984
  break;
862
985
  }
863
986
  case "End": {
864
987
  e.preventDefault();
865
- focusTab(tabs.length - 1);
988
+ selectTab(tabs.length - 1);
866
989
  break;
867
990
  }
868
991
  }
869
992
  },
870
- [activeIndex, focusTab, tabs.length]
993
+ [activeIndex, selectTab, tabs.length]
871
994
  );
872
995
  return /* @__PURE__ */ jsxRuntime.jsxs(
873
996
  "div",
@@ -906,7 +1029,7 @@ function Tabs({ data, block }) {
906
1029
  "aria-selected": isActive,
907
1030
  "aria-controls": panelId,
908
1031
  tabIndex: isActive ? 0 : -1,
909
- onClick: () => setActiveIndex(index),
1032
+ onClick: () => selectTab(index),
910
1033
  onKeyDown: handleKeyDown,
911
1034
  style: {
912
1035
  padding: "10px 18px",
@@ -1018,7 +1141,7 @@ function Timeline({ data }) {
1018
1141
  position: dates.length === 1 ? totalLength / 2 : timeScale(e._parsed),
1019
1142
  side: isVertical ? i % 2 === 0 ? "left" : "right" : i % 2 === 0 ? "top" : "bottom"
1020
1143
  }));
1021
- const containerStyle3 = {
1144
+ const containerStyle11 = {
1022
1145
  position: "relative",
1023
1146
  fontFamily: "var(--glyph-font-body, system-ui, sans-serif)",
1024
1147
  color: "var(--glyph-text, #1a2035)",
@@ -1045,7 +1168,7 @@ function Timeline({ data }) {
1045
1168
  "div",
1046
1169
  {
1047
1170
  ref: containerRef,
1048
- style: containerStyle3,
1171
+ style: containerStyle11,
1049
1172
  role: "img",
1050
1173
  "aria-label": `Timeline with ${events.length} events`,
1051
1174
  children: [
@@ -1373,7 +1496,7 @@ function getThemeVar(container, varName, fallback) {
1373
1496
  return getComputedStyle(container).getPropertyValue(varName).trim() || fallback;
1374
1497
  }
1375
1498
  var ARROW_MARKER_ID = "glyph-graph-arrowhead";
1376
- function renderGraph(svgElement, layout, groupIndex, outgoingRefs, onNavigate) {
1499
+ function renderGraph(svgElement, layout, groupIndex, outgoingRefs, onNavigate, onNodeClick) {
1377
1500
  const svg = d32__namespace.select(svgElement);
1378
1501
  svg.selectAll("*").remove();
1379
1502
  const width = Math.max(layout.width, 200);
@@ -1424,19 +1547,24 @@ function renderGraph(svgElement, layout, groupIndex, outgoingRefs, onNavigate) {
1424
1547
  nodeG.append("rect").attr("x", nodeX).attr("y", nodeY).attr("width", node.width).attr("height", node.height).attr("rx", nodeRadius).attr("ry", nodeRadius).attr("fill", node.style?.["fill"] ?? color3).attr("stroke", node.style?.["stroke"] ?? defaultStroke).attr("stroke-width", node.style?.["stroke-width"] ?? nodeStrokeWidth).attr("opacity", nodeFillOpacity);
1425
1548
  }
1426
1549
  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);
1427
- if (isNavigable) {
1550
+ if (isNavigable || onNodeClick) {
1428
1551
  nodeG.attr("cursor", "pointer");
1429
1552
  nodeG.on("click", () => {
1430
- const ref = refByAnchor.get(node.id);
1431
- if (ref) onNavigate(ref);
1553
+ if (isNavigable) {
1554
+ const ref = refByAnchor.get(node.id);
1555
+ if (ref) onNavigate(ref);
1556
+ }
1557
+ onNodeClick?.(node.id, node.label);
1432
1558
  });
1433
1559
  }
1434
1560
  }
1435
1561
  }
1436
1562
  function Graph({
1437
1563
  data,
1564
+ block,
1438
1565
  outgoingRefs,
1439
1566
  onNavigate,
1567
+ onInteraction,
1440
1568
  container
1441
1569
  }) {
1442
1570
  const svgRef = react.useRef(null);
@@ -1448,10 +1576,29 @@ function Graph({
1448
1576
  }
1449
1577
  return computeDagreLayout(data.nodes, data.edges, direction);
1450
1578
  }, [data]);
1579
+ const handleNodeClick = react.useMemo(() => {
1580
+ if (!onInteraction) return void 0;
1581
+ return (nodeId, nodeLabel) => {
1582
+ onInteraction({
1583
+ kind: "graph-node-click",
1584
+ timestamp: (/* @__PURE__ */ new Date()).toISOString(),
1585
+ blockId: block.id,
1586
+ blockType: block.type,
1587
+ payload: { nodeId, nodeLabel }
1588
+ });
1589
+ };
1590
+ }, [onInteraction, block.id, block.type]);
1451
1591
  react.useEffect(() => {
1452
1592
  if (!svgRef.current) return;
1453
- renderGraph(svgRef.current, layoutResult, groupIndex.current, outgoingRefs, onNavigate);
1454
- }, [layoutResult, outgoingRefs, onNavigate]);
1593
+ renderGraph(
1594
+ svgRef.current,
1595
+ layoutResult,
1596
+ groupIndex.current,
1597
+ outgoingRefs,
1598
+ onNavigate,
1599
+ handleNodeClick
1600
+ );
1601
+ }, [layoutResult, outgoingRefs, onNavigate, handleNodeClick]);
1455
1602
  const ariaLabel = `${data.type} graph with ${data.nodes.length} nodes and ${data.edges.length} edges`;
1456
1603
  return /* @__PURE__ */ jsxRuntime.jsxs("div", { className: "glyph-graph-container", children: [
1457
1604
  /* @__PURE__ */ jsxRuntime.jsx(
@@ -1795,7 +1942,7 @@ function Kpi({ data, block, container }) {
1795
1942
  default:
1796
1943
  colCount = authorCols;
1797
1944
  }
1798
- const containerStyle3 = {
1945
+ const containerStyle11 = {
1799
1946
  fontFamily: "var(--glyph-font-body, system-ui, sans-serif)",
1800
1947
  color: "var(--glyph-text, #1a2035)"
1801
1948
  };
@@ -1805,13 +1952,13 @@ function Kpi({ data, block, container }) {
1805
1952
  gridTemplateColumns: `repeat(auto-fill, minmax(max(120px, calc((100% - ${String(gapCount)}rem) / ${String(colCount)})), 1fr))`,
1806
1953
  gap: "var(--glyph-spacing-md, 1rem)"
1807
1954
  };
1808
- const cardStyle = {
1955
+ const cardStyle2 = {
1809
1956
  background: "var(--glyph-surface-raised, #f4f6fa)",
1810
1957
  border: "1px solid var(--glyph-border, #d0d8e4)",
1811
1958
  borderRadius: "var(--glyph-radius-md, 0.5rem)",
1812
1959
  padding: "var(--glyph-spacing-md, 1rem)"
1813
1960
  };
1814
- const labelStyle3 = {
1961
+ const labelStyle4 = {
1815
1962
  fontSize: "0.8125rem",
1816
1963
  color: "var(--glyph-text-muted, #6b7a94)",
1817
1964
  marginBottom: "var(--glyph-spacing-xs, 0.25rem)"
@@ -1822,7 +1969,7 @@ function Kpi({ data, block, container }) {
1822
1969
  color: "var(--glyph-heading, #0a0e1a)",
1823
1970
  lineHeight: 1.2
1824
1971
  };
1825
- return /* @__PURE__ */ jsxRuntime.jsxs("div", { id: baseId, role: "region", "aria-label": title ?? "Key metrics", style: containerStyle3, children: [
1972
+ return /* @__PURE__ */ jsxRuntime.jsxs("div", { id: baseId, role: "region", "aria-label": title ?? "Key metrics", style: containerStyle11, children: [
1826
1973
  title && /* @__PURE__ */ jsxRuntime.jsx(
1827
1974
  "div",
1828
1975
  {
@@ -1842,8 +1989,8 @@ function Kpi({ data, block, container }) {
1842
1989
  marginTop: "var(--glyph-spacing-xs, 0.25rem)",
1843
1990
  color: `var(--glyph-kpi-${sentiment}, inherit)`
1844
1991
  };
1845
- return /* @__PURE__ */ jsxRuntime.jsxs("div", { role: "group", "aria-label": buildAriaLabel(metric), style: cardStyle, children: [
1846
- /* @__PURE__ */ jsxRuntime.jsx("div", { style: labelStyle3, children: metric.label }),
1992
+ return /* @__PURE__ */ jsxRuntime.jsxs("div", { role: "group", "aria-label": buildAriaLabel(metric), style: cardStyle2, children: [
1993
+ /* @__PURE__ */ jsxRuntime.jsx("div", { style: labelStyle4, children: metric.label }),
1847
1994
  /* @__PURE__ */ jsxRuntime.jsxs("div", { style: valueStyle, children: [
1848
1995
  metric.value,
1849
1996
  metric.unit && /* @__PURE__ */ jsxRuntime.jsx("span", { style: { fontSize: "0.875rem", fontWeight: 400, marginLeft: "0.25rem" }, children: metric.unit })
@@ -1863,25 +2010,41 @@ var kpiDefinition = {
1863
2010
  schema: schemas.kpiSchema,
1864
2011
  render: Kpi
1865
2012
  };
1866
- function Accordion({ data, block }) {
2013
+ function Accordion({
2014
+ data,
2015
+ block,
2016
+ onInteraction
2017
+ }) {
1867
2018
  const { title, sections, defaultOpen = [], multiple = true } = data;
1868
2019
  const baseId = `glyph-accordion-${block.id}`;
1869
2020
  const containerRef = react.useRef(null);
1870
2021
  const handleToggle = react.useCallback(
1871
- (e) => {
1872
- if (multiple) return;
2022
+ (e, sectionIndex) => {
1873
2023
  const target = e.currentTarget;
1874
- if (!target.open || !containerRef.current) return;
1875
- const allDetails = containerRef.current.querySelectorAll("details");
1876
- for (const details of allDetails) {
1877
- if (details !== target && details.open) {
1878
- details.open = false;
2024
+ const expanded = target.open;
2025
+ if (!multiple && expanded && containerRef.current) {
2026
+ const allDetails = containerRef.current.querySelectorAll("details");
2027
+ for (const details of allDetails) {
2028
+ if (details !== target && details.open) {
2029
+ details.open = false;
2030
+ }
1879
2031
  }
1880
2032
  }
2033
+ onInteraction?.({
2034
+ kind: "accordion-toggle",
2035
+ timestamp: (/* @__PURE__ */ new Date()).toISOString(),
2036
+ blockId: block.id,
2037
+ blockType: block.type,
2038
+ payload: {
2039
+ sectionIndex,
2040
+ sectionTitle: sections[sectionIndex]?.title ?? "",
2041
+ expanded
2042
+ }
2043
+ });
1881
2044
  },
1882
- [multiple]
2045
+ [multiple, sections, block.id, block.type, onInteraction]
1883
2046
  );
1884
- const containerStyle3 = {
2047
+ const containerStyle11 = {
1885
2048
  fontFamily: "var(--glyph-font-body, system-ui, sans-serif)",
1886
2049
  color: "var(--glyph-text, #1a2035)",
1887
2050
  border: "1px solid var(--glyph-border, #d0d8e4)",
@@ -1915,7 +2078,7 @@ function Accordion({ data, block }) {
1915
2078
  ref: containerRef,
1916
2079
  role: "region",
1917
2080
  "aria-label": title ?? "Accordion",
1918
- style: containerStyle3,
2081
+ style: containerStyle11,
1919
2082
  children: [
1920
2083
  title && /* @__PURE__ */ jsxRuntime.jsx(
1921
2084
  "div",
@@ -1934,7 +2097,7 @@ function Accordion({ data, block }) {
1934
2097
  "details",
1935
2098
  {
1936
2099
  open: defaultOpen.includes(i),
1937
- onToggle: handleToggle,
2100
+ onToggle: (e) => handleToggle(e, i),
1938
2101
  style: sectionStyle(i === sections.length - 1),
1939
2102
  children: [
1940
2103
  /* @__PURE__ */ jsxRuntime.jsxs("summary", { style: summaryStyle, children: [
@@ -2003,17 +2166,18 @@ function renderValue(value) {
2003
2166
  function Comparison({
2004
2167
  data,
2005
2168
  block,
2006
- container
2169
+ container,
2170
+ onInteraction
2007
2171
  }) {
2008
2172
  const { title, options, features } = data;
2009
2173
  const baseId = `glyph-comparison-${block.id}`;
2010
2174
  const isCompact = container.tier === "compact";
2011
2175
  const cellPadding = isCompact ? "var(--glyph-spacing-xs, 0.25rem) var(--glyph-spacing-sm, 0.5rem)" : "var(--glyph-spacing-sm, 0.5rem) var(--glyph-spacing-md, 1rem)";
2012
- const containerStyle3 = {
2176
+ const containerStyle11 = {
2013
2177
  fontFamily: "var(--glyph-font-body, system-ui, sans-serif)",
2014
2178
  color: "var(--glyph-text, #1a2035)"
2015
2179
  };
2016
- const tableStyle = {
2180
+ const tableStyle2 = {
2017
2181
  width: "100%",
2018
2182
  borderCollapse: "collapse",
2019
2183
  border: "1px solid var(--glyph-table-border, #d0d8e4)",
@@ -2021,7 +2185,7 @@ function Comparison({
2021
2185
  overflow: "hidden",
2022
2186
  fontSize: isCompact ? "0.8125rem" : "0.875rem"
2023
2187
  };
2024
- const thStyle = {
2188
+ const thStyle2 = {
2025
2189
  padding: cellPadding,
2026
2190
  textAlign: "center",
2027
2191
  fontWeight: 600,
@@ -2030,7 +2194,7 @@ function Comparison({
2030
2194
  color: "var(--glyph-heading, #0a0e1a)"
2031
2195
  };
2032
2196
  const featureThStyle = {
2033
- ...thStyle,
2197
+ ...thStyle2,
2034
2198
  textAlign: "left"
2035
2199
  };
2036
2200
  const rowThStyle = {
@@ -2040,13 +2204,13 @@ function Comparison({
2040
2204
  borderBottom: "1px solid var(--glyph-table-border, #d0d8e4)",
2041
2205
  fontSize: "0.8125rem"
2042
2206
  };
2043
- const cellStyle = (rowIndex) => ({
2207
+ const cellStyle2 = (rowIndex) => ({
2044
2208
  padding: cellPadding,
2045
2209
  textAlign: "center",
2046
2210
  borderBottom: "1px solid var(--glyph-table-border, #d0d8e4)",
2047
2211
  background: rowIndex % 2 === 1 ? "var(--glyph-table-row-alt-bg, transparent)" : "transparent"
2048
2212
  });
2049
- return /* @__PURE__ */ jsxRuntime.jsxs("div", { id: baseId, role: "region", "aria-label": title ?? "Comparison", style: containerStyle3, children: [
2213
+ return /* @__PURE__ */ jsxRuntime.jsxs("div", { id: baseId, role: "region", "aria-label": title ?? "Comparison", style: containerStyle11, children: [
2050
2214
  title && /* @__PURE__ */ jsxRuntime.jsx(
2051
2215
  "div",
2052
2216
  {
@@ -2059,23 +2223,46 @@ function Comparison({
2059
2223
  children: title
2060
2224
  }
2061
2225
  ),
2062
- /* @__PURE__ */ jsxRuntime.jsx("div", { style: { overflowX: "auto" }, children: /* @__PURE__ */ jsxRuntime.jsxs("table", { role: "grid", style: tableStyle, children: [
2226
+ /* @__PURE__ */ jsxRuntime.jsx("div", { style: { overflowX: "auto" }, children: /* @__PURE__ */ jsxRuntime.jsxs("table", { role: "grid", style: tableStyle2, children: [
2063
2227
  /* @__PURE__ */ jsxRuntime.jsx("thead", { children: /* @__PURE__ */ jsxRuntime.jsxs("tr", { children: [
2064
2228
  /* @__PURE__ */ jsxRuntime.jsx("th", { style: featureThStyle, scope: "col", children: "Feature" }),
2065
- options.map((option, i) => /* @__PURE__ */ jsxRuntime.jsxs("th", { style: thStyle, scope: "col", children: [
2066
- /* @__PURE__ */ jsxRuntime.jsx("div", { children: option.name }),
2067
- option.description && /* @__PURE__ */ jsxRuntime.jsx(
2068
- "div",
2069
- {
2070
- style: {
2071
- fontWeight: 400,
2072
- fontSize: "0.75rem",
2073
- color: "var(--glyph-text-muted, #6b7a94)"
2074
- },
2075
- children: option.description
2076
- }
2077
- )
2078
- ] }, i))
2229
+ options.map((option, i) => /* @__PURE__ */ jsxRuntime.jsxs(
2230
+ "th",
2231
+ {
2232
+ style: {
2233
+ ...thStyle2,
2234
+ ...onInteraction ? { cursor: "pointer" } : {}
2235
+ },
2236
+ scope: "col",
2237
+ onClick: onInteraction ? () => {
2238
+ onInteraction({
2239
+ kind: "comparison-select",
2240
+ timestamp: (/* @__PURE__ */ new Date()).toISOString(),
2241
+ blockId: block.id,
2242
+ blockType: block.type,
2243
+ payload: {
2244
+ optionIndex: i,
2245
+ optionName: option.name
2246
+ }
2247
+ });
2248
+ } : void 0,
2249
+ children: [
2250
+ /* @__PURE__ */ jsxRuntime.jsx("div", { children: option.name }),
2251
+ option.description && /* @__PURE__ */ jsxRuntime.jsx(
2252
+ "div",
2253
+ {
2254
+ style: {
2255
+ fontWeight: 400,
2256
+ fontSize: "0.75rem",
2257
+ color: "var(--glyph-text-muted, #6b7a94)"
2258
+ },
2259
+ children: option.description
2260
+ }
2261
+ )
2262
+ ]
2263
+ },
2264
+ i
2265
+ ))
2079
2266
  ] }) }),
2080
2267
  /* @__PURE__ */ jsxRuntime.jsx("tbody", { children: features.map((feature, rowIndex) => /* @__PURE__ */ jsxRuntime.jsxs("tr", { children: [
2081
2268
  /* @__PURE__ */ jsxRuntime.jsx(
@@ -2091,7 +2278,7 @@ function Comparison({
2091
2278
  ),
2092
2279
  options.map((_, colIndex) => {
2093
2280
  const value = feature.values[colIndex] ?? "";
2094
- return /* @__PURE__ */ jsxRuntime.jsx("td", { style: cellStyle(rowIndex), children: value ? renderValue(value) : null }, colIndex);
2281
+ return /* @__PURE__ */ jsxRuntime.jsx("td", { style: cellStyle2(rowIndex), children: value ? renderValue(value) : null }, colIndex);
2095
2282
  })
2096
2283
  ] }, rowIndex)) })
2097
2284
  ] }) })
@@ -2169,7 +2356,7 @@ function CodeDiff({ data, block }) {
2169
2356
  const baseId = `glyph-codediff-${block.id}`;
2170
2357
  const diffLines = react.useMemo(() => computeDiff(before, after), [before, after]);
2171
2358
  const summary = react.useMemo(() => summarizeDiff(diffLines), [diffLines]);
2172
- const containerStyle3 = {
2359
+ const containerStyle11 = {
2173
2360
  fontFamily: 'var(--glyph-font-mono, ui-monospace, "Cascadia Code", "Fira Code", monospace)',
2174
2361
  fontSize: "0.8125rem",
2175
2362
  lineHeight: 1.5,
@@ -2188,7 +2375,7 @@ function CodeDiff({ data, block }) {
2188
2375
  fontWeight: 600,
2189
2376
  color: "var(--glyph-text-muted, #6b7a94)"
2190
2377
  };
2191
- const tableStyle = {
2378
+ const tableStyle2 = {
2192
2379
  width: "100%",
2193
2380
  borderCollapse: "collapse",
2194
2381
  tableLayout: "fixed"
@@ -2227,13 +2414,13 @@ function CodeDiff({ data, block }) {
2227
2414
  if (kind === "del") return "var(--glyph-codediff-del-color, inherit)";
2228
2415
  return void 0;
2229
2416
  }
2230
- return /* @__PURE__ */ jsxRuntime.jsxs("div", { id: baseId, role: "region", "aria-label": summary, style: containerStyle3, children: [
2417
+ return /* @__PURE__ */ jsxRuntime.jsxs("div", { id: baseId, role: "region", "aria-label": summary, style: containerStyle11, children: [
2231
2418
  (beforeLabel || afterLabel) && /* @__PURE__ */ jsxRuntime.jsxs("div", { style: labelBarStyle, children: [
2232
2419
  beforeLabel && /* @__PURE__ */ jsxRuntime.jsx("span", { children: beforeLabel }),
2233
2420
  beforeLabel && afterLabel && /* @__PURE__ */ jsxRuntime.jsx("span", { children: "\u2192" }),
2234
2421
  afterLabel && /* @__PURE__ */ jsxRuntime.jsx("span", { children: afterLabel })
2235
2422
  ] }),
2236
- /* @__PURE__ */ jsxRuntime.jsx("div", { style: { overflowX: "auto" }, children: /* @__PURE__ */ jsxRuntime.jsx("table", { role: "grid", style: tableStyle, children: /* @__PURE__ */ jsxRuntime.jsx("tbody", { children: diffLines.map((line6, i) => /* @__PURE__ */ jsxRuntime.jsxs(
2423
+ /* @__PURE__ */ jsxRuntime.jsx("div", { style: { overflowX: "auto" }, children: /* @__PURE__ */ jsxRuntime.jsx("table", { role: "grid", style: tableStyle2, children: /* @__PURE__ */ jsxRuntime.jsx("tbody", { children: diffLines.map((line6, i) => /* @__PURE__ */ jsxRuntime.jsxs(
2237
2424
  "tr",
2238
2425
  {
2239
2426
  "aria-label": ARIA_LABELS[line6.kind],
@@ -2499,15 +2686,25 @@ function TreeItem({
2499
2686
  setSize,
2500
2687
  posInSet,
2501
2688
  onFocusChange,
2502
- flatItems
2689
+ flatItems,
2690
+ parentPath,
2691
+ onSelect
2503
2692
  }) {
2504
2693
  const [expanded, setExpanded] = react.useState(defaultExpanded);
2505
2694
  const itemRef = react.useRef(null);
2506
2695
  const isDir = Array.isArray(node.children) && node.children.length > 0;
2507
2696
  const isFocused = flatIndex === focusedIndex;
2697
+ const path = parentPath ? `${parentPath}/${node.name}` : node.name;
2508
2698
  const handleToggle = react.useCallback(() => {
2509
- if (isDir) setExpanded((prev) => !prev);
2510
- }, [isDir]);
2699
+ if (isDir) {
2700
+ setExpanded((prev) => {
2701
+ onSelect?.(path, "directory", !prev);
2702
+ return !prev;
2703
+ });
2704
+ } else {
2705
+ onSelect?.(path, "file");
2706
+ }
2707
+ }, [isDir, path, onSelect]);
2511
2708
  const handleKeyDown = react.useCallback(
2512
2709
  (e) => {
2513
2710
  let handled = true;
@@ -2639,7 +2836,9 @@ function TreeItem({
2639
2836
  setSize: node.children?.length ?? 0,
2640
2837
  posInSet: childIdx + 1,
2641
2838
  onFocusChange,
2642
- flatItems
2839
+ flatItems,
2840
+ parentPath: path,
2841
+ onSelect
2643
2842
  },
2644
2843
  child.name
2645
2844
  );
@@ -2672,7 +2871,11 @@ function getChildFlatIndex(flatItems, parentFlatIndex, childIdx, children) {
2672
2871
  }
2673
2872
  return parentFlatIndex + childIdx + 1;
2674
2873
  }
2675
- function FileTree({ data }) {
2874
+ function FileTree({
2875
+ data,
2876
+ block,
2877
+ onInteraction
2878
+ }) {
2676
2879
  const [focusedIndex, setFocusedIndex] = react.useState(0);
2677
2880
  const containerRef = react.useRef(null);
2678
2881
  const flatItems = flattenTree(data.tree, data.root ? 1 : 0);
@@ -2683,6 +2886,18 @@ function FileTree({ data }) {
2683
2886
  const el = container.querySelector(`[data-flat-index="${String(index)}"]`);
2684
2887
  el?.focus();
2685
2888
  }, []);
2889
+ const handleSelect = react.useCallback(
2890
+ (path, type, expanded) => {
2891
+ onInteraction?.({
2892
+ kind: "filetree-select",
2893
+ timestamp: (/* @__PURE__ */ new Date()).toISOString(),
2894
+ blockId: block.id,
2895
+ blockType: block.type,
2896
+ payload: { path, type, expanded }
2897
+ });
2898
+ },
2899
+ [onInteraction, block.id, block.type]
2900
+ );
2686
2901
  return /* @__PURE__ */ jsxRuntime.jsx(
2687
2902
  "div",
2688
2903
  {
@@ -2739,7 +2954,9 @@ function FileTree({ data }) {
2739
2954
  setSize: data.tree.length,
2740
2955
  posInSet: idx + 1,
2741
2956
  onFocusChange: handleFocusChange,
2742
- flatItems
2957
+ flatItems,
2958
+ parentPath: data.root ?? "",
2959
+ onSelect: handleSelect
2743
2960
  },
2744
2961
  node.name
2745
2962
  );
@@ -2760,7 +2977,9 @@ function FileTree({ data }) {
2760
2977
  setSize: data.tree.length,
2761
2978
  posInSet: idx + 1,
2762
2979
  onFocusChange: handleFocusChange,
2763
- flatItems
2980
+ flatItems,
2981
+ parentPath: "",
2982
+ onSelect: handleSelect
2764
2983
  },
2765
2984
  node.name
2766
2985
  );
@@ -4008,7 +4227,115 @@ function isCorrect(question, selected) {
4008
4227
  }
4009
4228
  }
4010
4229
  }
4011
- function Quiz({ data, block }) {
4230
+ function renderMultipleChoice(question, qIndex, state, updateState, baseId) {
4231
+ 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) => {
4233
+ const isSelected = selected === oIndex;
4234
+ const isCorrectOption = state.submitted && oIndex === question.answer;
4235
+ const isIncorrectSelection = state.submitted && isSelected && oIndex !== question.answer;
4236
+ return /* @__PURE__ */ jsxRuntime.jsxs(
4237
+ "label",
4238
+ {
4239
+ style: optionLabelStyle(
4240
+ isSelected,
4241
+ state.submitted,
4242
+ isCorrectOption,
4243
+ isIncorrectSelection
4244
+ ),
4245
+ children: [
4246
+ /* @__PURE__ */ jsxRuntime.jsx(
4247
+ "input",
4248
+ {
4249
+ type: "radio",
4250
+ role: "radio",
4251
+ name: `${baseId}-q${String(qIndex)}`,
4252
+ checked: isSelected,
4253
+ disabled: state.submitted,
4254
+ onChange: () => updateState(qIndex, { selected: oIndex }),
4255
+ "aria-checked": isSelected
4256
+ }
4257
+ ),
4258
+ option
4259
+ ]
4260
+ },
4261
+ oIndex
4262
+ );
4263
+ }) });
4264
+ }
4265
+ function renderTrueFalse(question, qIndex, state, updateState, baseId) {
4266
+ 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) => {
4268
+ const isSelected = selected === value;
4269
+ const isCorrectOption = state.submitted && value === question.answer;
4270
+ const isIncorrectSelection = state.submitted && isSelected && value !== question.answer;
4271
+ return /* @__PURE__ */ jsxRuntime.jsxs(
4272
+ "label",
4273
+ {
4274
+ style: optionLabelStyle(
4275
+ isSelected,
4276
+ state.submitted,
4277
+ isCorrectOption,
4278
+ isIncorrectSelection
4279
+ ),
4280
+ children: [
4281
+ /* @__PURE__ */ jsxRuntime.jsx(
4282
+ "input",
4283
+ {
4284
+ type: "radio",
4285
+ role: "radio",
4286
+ name: `${baseId}-q${String(qIndex)}`,
4287
+ checked: isSelected,
4288
+ disabled: state.submitted,
4289
+ onChange: () => updateState(qIndex, { selected: value }),
4290
+ "aria-checked": isSelected
4291
+ }
4292
+ ),
4293
+ value ? "True" : "False"
4294
+ ]
4295
+ },
4296
+ String(value)
4297
+ );
4298
+ }) });
4299
+ }
4300
+ function renderMultiSelect(question, qIndex, state, updateState) {
4301
+ const selected = Array.isArray(state.selected) ? state.selected : [];
4302
+ const toggleOption = (oIndex) => {
4303
+ const next = selected.includes(oIndex) ? selected.filter((v) => v !== oIndex) : [...selected, oIndex];
4304
+ updateState(qIndex, { selected: next });
4305
+ };
4306
+ return /* @__PURE__ */ jsxRuntime.jsx("div", { children: question.options.map((option, oIndex) => {
4307
+ const isSelected = selected.includes(oIndex);
4308
+ const isCorrectOption = state.submitted && question.answer.includes(oIndex);
4309
+ const isIncorrectSelection = state.submitted && isSelected && !question.answer.includes(oIndex);
4310
+ return /* @__PURE__ */ jsxRuntime.jsxs(
4311
+ "label",
4312
+ {
4313
+ style: optionLabelStyle(
4314
+ isSelected,
4315
+ state.submitted,
4316
+ isCorrectOption,
4317
+ isIncorrectSelection
4318
+ ),
4319
+ children: [
4320
+ /* @__PURE__ */ jsxRuntime.jsx(
4321
+ "input",
4322
+ {
4323
+ type: "checkbox",
4324
+ role: "checkbox",
4325
+ checked: isSelected,
4326
+ disabled: state.submitted,
4327
+ onChange: () => toggleOption(oIndex),
4328
+ "aria-checked": isSelected
4329
+ }
4330
+ ),
4331
+ option
4332
+ ]
4333
+ },
4334
+ oIndex
4335
+ );
4336
+ }) });
4337
+ }
4338
+ function Quiz({ data, block, onInteraction }) {
4012
4339
  const { questions, showScore = true, title } = data;
4013
4340
  const baseId = `glyph-quiz-${block.id}`;
4014
4341
  const [states, setStates] = react.useState(
@@ -4026,114 +4353,6 @@ function Quiz({ data, block }) {
4026
4353
  return acc + (isCorrect(q, s.selected) ? 1 : 0);
4027
4354
  }, 0);
4028
4355
  const submittedCount = states.filter((s) => s.submitted).length;
4029
- function renderMultipleChoice(question, qIndex, state) {
4030
- const selected = typeof state.selected === "number" ? state.selected : null;
4031
- return /* @__PURE__ */ jsxRuntime.jsx("div", { role: "radiogroup", "aria-label": question.question, children: question.options.map((option, oIndex) => {
4032
- const isSelected = selected === oIndex;
4033
- const isCorrectOption = state.submitted && oIndex === question.answer;
4034
- const isIncorrectSelection = state.submitted && isSelected && oIndex !== question.answer;
4035
- return /* @__PURE__ */ jsxRuntime.jsxs(
4036
- "label",
4037
- {
4038
- style: optionLabelStyle(
4039
- isSelected,
4040
- state.submitted,
4041
- isCorrectOption,
4042
- isIncorrectSelection
4043
- ),
4044
- children: [
4045
- /* @__PURE__ */ jsxRuntime.jsx(
4046
- "input",
4047
- {
4048
- type: "radio",
4049
- role: "radio",
4050
- name: `${baseId}-q${String(qIndex)}`,
4051
- checked: isSelected,
4052
- disabled: state.submitted,
4053
- onChange: () => updateState(qIndex, { selected: oIndex }),
4054
- "aria-checked": isSelected
4055
- }
4056
- ),
4057
- option
4058
- ]
4059
- },
4060
- oIndex
4061
- );
4062
- }) });
4063
- }
4064
- function renderTrueFalse(question, qIndex, state) {
4065
- const selected = typeof state.selected === "boolean" ? state.selected : null;
4066
- return /* @__PURE__ */ jsxRuntime.jsx("div", { role: "radiogroup", "aria-label": question.question, children: [true, false].map((value) => {
4067
- const isSelected = selected === value;
4068
- const isCorrectOption = state.submitted && value === question.answer;
4069
- const isIncorrectSelection = state.submitted && isSelected && value !== question.answer;
4070
- return /* @__PURE__ */ jsxRuntime.jsxs(
4071
- "label",
4072
- {
4073
- style: optionLabelStyle(
4074
- isSelected,
4075
- state.submitted,
4076
- isCorrectOption,
4077
- isIncorrectSelection
4078
- ),
4079
- children: [
4080
- /* @__PURE__ */ jsxRuntime.jsx(
4081
- "input",
4082
- {
4083
- type: "radio",
4084
- role: "radio",
4085
- name: `${baseId}-q${String(qIndex)}`,
4086
- checked: isSelected,
4087
- disabled: state.submitted,
4088
- onChange: () => updateState(qIndex, { selected: value }),
4089
- "aria-checked": isSelected
4090
- }
4091
- ),
4092
- value ? "True" : "False"
4093
- ]
4094
- },
4095
- String(value)
4096
- );
4097
- }) });
4098
- }
4099
- function renderMultiSelect(question, qIndex, state) {
4100
- const selected = Array.isArray(state.selected) ? state.selected : [];
4101
- const toggleOption = (oIndex) => {
4102
- const next = selected.includes(oIndex) ? selected.filter((v) => v !== oIndex) : [...selected, oIndex];
4103
- updateState(qIndex, { selected: next });
4104
- };
4105
- return /* @__PURE__ */ jsxRuntime.jsx("div", { children: question.options.map((option, oIndex) => {
4106
- const isSelected = selected.includes(oIndex);
4107
- const isCorrectOption = state.submitted && question.answer.includes(oIndex);
4108
- const isIncorrectSelection = state.submitted && isSelected && !question.answer.includes(oIndex);
4109
- return /* @__PURE__ */ jsxRuntime.jsxs(
4110
- "label",
4111
- {
4112
- style: optionLabelStyle(
4113
- isSelected,
4114
- state.submitted,
4115
- isCorrectOption,
4116
- isIncorrectSelection
4117
- ),
4118
- children: [
4119
- /* @__PURE__ */ jsxRuntime.jsx(
4120
- "input",
4121
- {
4122
- type: "checkbox",
4123
- role: "checkbox",
4124
- checked: isSelected,
4125
- disabled: state.submitted,
4126
- onChange: () => toggleOption(oIndex),
4127
- "aria-checked": isSelected
4128
- }
4129
- ),
4130
- option
4131
- ]
4132
- },
4133
- oIndex
4134
- );
4135
- }) });
4136
- }
4137
4356
  function renderQuestion(question, qIndex) {
4138
4357
  const state = states[qIndex] ?? { selected: null, submitted: false };
4139
4358
  const isLast = qIndex === questions.length - 1;
@@ -4150,16 +4369,52 @@ function Quiz({ data, block }) {
4150
4369
  questions.length > 1 ? `${String(qIndex + 1)}. ` : "",
4151
4370
  question.question
4152
4371
  ] }),
4153
- question.type === "multiple-choice" && renderMultipleChoice(question, qIndex, state),
4154
- question.type === "true-false" && renderTrueFalse(question, qIndex, state),
4155
- question.type === "multi-select" && renderMultiSelect(question, qIndex, state),
4372
+ question.type === "multiple-choice" && renderMultipleChoice(question, qIndex, state, updateState, baseId),
4373
+ question.type === "true-false" && renderTrueFalse(question, qIndex, state, updateState, baseId),
4374
+ question.type === "multi-select" && renderMultiSelect(question, qIndex, state, updateState),
4156
4375
  !state.submitted && /* @__PURE__ */ jsxRuntime.jsx(
4157
4376
  "button",
4158
4377
  {
4159
4378
  type: "button",
4160
4379
  disabled: !hasSelection,
4161
4380
  style: buttonStyle(!hasSelection),
4162
- onClick: () => updateState(qIndex, { submitted: true }),
4381
+ onClick: () => {
4382
+ updateState(qIndex, { submitted: true });
4383
+ if (onInteraction) {
4384
+ const correct2 = isCorrect(question, state.selected);
4385
+ const newScore = states.reduce((acc, s, i) => {
4386
+ if (i === qIndex) return acc + (correct2 ? 1 : 0);
4387
+ const q = questions[i];
4388
+ if (!q || !s.submitted) return acc;
4389
+ return acc + (isCorrect(q, s.selected) ? 1 : 0);
4390
+ }, 0);
4391
+ let selected;
4392
+ switch (question.type) {
4393
+ case "multiple-choice":
4394
+ selected = typeof state.selected === "number" ? [question.options[state.selected] ?? String(state.selected)] : [];
4395
+ break;
4396
+ case "true-false":
4397
+ selected = typeof state.selected === "boolean" ? [state.selected ? "True" : "False"] : [];
4398
+ break;
4399
+ case "multi-select":
4400
+ selected = Array.isArray(state.selected) ? state.selected.map((idx) => question.options[idx] ?? String(idx)) : [];
4401
+ break;
4402
+ }
4403
+ onInteraction({
4404
+ kind: "quiz-submit",
4405
+ timestamp: (/* @__PURE__ */ new Date()).toISOString(),
4406
+ blockId: block.id,
4407
+ blockType: block.type,
4408
+ payload: {
4409
+ questionIndex: qIndex,
4410
+ question: question.question,
4411
+ selected,
4412
+ correct: correct2,
4413
+ score: { correct: newScore, total: questions.length }
4414
+ }
4415
+ });
4416
+ }
4417
+ },
4163
4418
  children: "Submit"
4164
4419
  }
4165
4420
  ),
@@ -4222,7 +4477,7 @@ function Card({ data, block, container }) {
4222
4477
  default:
4223
4478
  colCount = authorCols;
4224
4479
  }
4225
- const containerStyle3 = {
4480
+ const containerStyle11 = {
4226
4481
  fontFamily: "var(--glyph-font-body, system-ui, sans-serif)",
4227
4482
  color: "var(--glyph-text, #1a2035)"
4228
4483
  };
@@ -4267,7 +4522,7 @@ function Card({ data, block, container }) {
4267
4522
  color: "var(--glyph-text-muted, #6b7a94)",
4268
4523
  marginTop: "var(--glyph-spacing-xs, 0.25rem)"
4269
4524
  };
4270
- const bodyStyle2 = {
4525
+ const bodyStyle3 = {
4271
4526
  fontSize: "0.875rem",
4272
4527
  lineHeight: 1.6,
4273
4528
  marginTop: "var(--glyph-spacing-sm, 0.5rem)",
@@ -4285,7 +4540,7 @@ function Card({ data, block, container }) {
4285
4540
  color: "var(--glyph-link, #0a9d7c)",
4286
4541
  textDecoration: "none"
4287
4542
  };
4288
- return /* @__PURE__ */ jsxRuntime.jsxs("div", { id: baseId, role: "region", "aria-label": title ?? "Cards", style: containerStyle3, children: [
4543
+ return /* @__PURE__ */ jsxRuntime.jsxs("div", { id: baseId, role: "region", "aria-label": title ?? "Cards", style: containerStyle11, children: [
4289
4544
  title && /* @__PURE__ */ jsxRuntime.jsx(
4290
4545
  "div",
4291
4546
  {
@@ -4304,7 +4559,7 @@ function Card({ data, block, container }) {
4304
4559
  card.icon && /* @__PURE__ */ jsxRuntime.jsx("div", { style: iconStyle, children: card.icon }),
4305
4560
  /* @__PURE__ */ jsxRuntime.jsx("h3", { style: titleStyle2, children: card.title }),
4306
4561
  card.subtitle && /* @__PURE__ */ jsxRuntime.jsx("div", { style: subtitleStyle, children: card.subtitle }),
4307
- card.body && /* @__PURE__ */ jsxRuntime.jsx("div", { style: bodyStyle2, children: card.body }),
4562
+ card.body && /* @__PURE__ */ jsxRuntime.jsx("div", { style: bodyStyle3, children: card.body }),
4308
4563
  card.actions && card.actions.length > 0 && /* @__PURE__ */ jsxRuntime.jsx("div", { style: actionsStyle, children: card.actions.map((action, j) => /* @__PURE__ */ jsxRuntime.jsx(
4309
4564
  "a",
4310
4565
  {
@@ -4394,7 +4649,7 @@ function renderStatGroup(items, keyPrefix) {
4394
4649
  color: "var(--glyph-infographic-value-color, #1d4ed8)",
4395
4650
  lineHeight: 1.2
4396
4651
  };
4397
- const labelStyle3 = {
4652
+ const labelStyle4 = {
4398
4653
  fontSize: "0.8125rem",
4399
4654
  color: "var(--glyph-infographic-label-color, #475569)",
4400
4655
  marginTop: "var(--glyph-spacing-xs, 0.25rem)",
@@ -4410,7 +4665,7 @@ function renderStatGroup(items, keyPrefix) {
4410
4665
  };
4411
4666
  return /* @__PURE__ */ jsxRuntime.jsx("div", { style: rowStyle, "data-group": "stat", children: items.map((item, i) => /* @__PURE__ */ jsxRuntime.jsxs("div", { style: statStyle, children: [
4412
4667
  /* @__PURE__ */ jsxRuntime.jsx("div", { style: valueStyle, children: item.value }),
4413
- /* @__PURE__ */ jsxRuntime.jsx("div", { style: labelStyle3, children: item.label }),
4668
+ /* @__PURE__ */ jsxRuntime.jsx("div", { style: labelStyle4, children: item.label }),
4414
4669
  item.description && /* @__PURE__ */ jsxRuntime.jsx("div", { style: descStyle, children: item.description })
4415
4670
  ] }, `${keyPrefix}-${String(i)}`)) }, keyPrefix);
4416
4671
  }
@@ -4481,18 +4736,18 @@ function renderProgressGroup(items, keyPrefix, colorOffset) {
4481
4736
  }) }, keyPrefix);
4482
4737
  }
4483
4738
  function renderFactGroup(items, keyPrefix) {
4484
- const listStyle = {
4739
+ const listStyle2 = {
4485
4740
  listStyle: "none",
4486
4741
  margin: 0,
4487
4742
  padding: 0
4488
4743
  };
4489
- const itemStyle2 = {
4744
+ const itemStyle4 = {
4490
4745
  padding: "var(--glyph-spacing-xs, 0.25rem) 0",
4491
4746
  fontSize: "0.875rem",
4492
4747
  color: "var(--glyph-text, #1a2035)",
4493
4748
  fontWeight: 500
4494
4749
  };
4495
- return /* @__PURE__ */ jsxRuntime.jsx("ul", { style: listStyle, "data-group": "fact", children: items.map((item, i) => /* @__PURE__ */ jsxRuntime.jsxs("li", { style: itemStyle2, children: [
4750
+ return /* @__PURE__ */ jsxRuntime.jsx("ul", { style: listStyle2, "data-group": "fact", children: items.map((item, i) => /* @__PURE__ */ jsxRuntime.jsxs("li", { style: itemStyle4, children: [
4496
4751
  item.icon && /* @__PURE__ */ jsxRuntime.jsx(
4497
4752
  "span",
4498
4753
  {
@@ -4769,7 +5024,7 @@ function Infographic({
4769
5024
  const baseId = `glyph-infographic-${block.id}`;
4770
5025
  const useGrid = sections.length >= 2 && container.tier !== "compact";
4771
5026
  const sectionLayouts = react.useMemo(() => computeSectionLayout(sections), [sections]);
4772
- const containerStyle3 = {
5027
+ const containerStyle11 = {
4773
5028
  fontFamily: "var(--glyph-font-body, system-ui, sans-serif)",
4774
5029
  color: "var(--glyph-text, #1a2035)",
4775
5030
  background: "var(--glyph-surface, #e8ecf3)",
@@ -4814,7 +5069,7 @@ function Infographic({
4814
5069
  };
4815
5070
  const printCss = useGrid ? `@media print { #${CSS.escape(baseId)} [data-layout="grid"] { display: grid !important; grid-template-columns: repeat(2, 1fr) !important; gap: 0.5rem !important; } #${CSS.escape(baseId)} [data-layout="grid"] > div { break-inside: avoid; } }` : "";
4816
5071
  let progressColorOffset = 0;
4817
- return /* @__PURE__ */ jsxRuntime.jsxs("div", { id: baseId, role: "region", "aria-label": title ?? "Infographic", style: containerStyle3, children: [
5072
+ return /* @__PURE__ */ jsxRuntime.jsxs("div", { id: baseId, role: "region", "aria-label": title ?? "Infographic", style: containerStyle11, children: [
4818
5073
  printCss && /* @__PURE__ */ jsxRuntime.jsx("style", { children: printCss }),
4819
5074
  /* @__PURE__ */ jsxRuntime.jsxs("div", { "data-layout": useGrid ? "grid" : "stack", style: useGrid ? sectionsGridStyle : void 0, children: [
4820
5075
  title && /* @__PURE__ */ jsxRuntime.jsx("div", { style: titleStyle2, children: title }),
@@ -4875,7 +5130,1733 @@ var infographicDefinition = {
4875
5130
  render: Infographic
4876
5131
  };
4877
5132
 
5133
+ // src/poll/styles.ts
5134
+ var containerStyle3 = {
5135
+ fontFamily: "var(--glyph-font-body, system-ui, sans-serif)",
5136
+ color: "var(--glyph-text, #1a2035)",
5137
+ border: "1px solid var(--glyph-border, #d0d8e4)",
5138
+ borderRadius: "var(--glyph-radius-md, 0.5rem)",
5139
+ overflow: "hidden"
5140
+ };
5141
+ var headerStyle2 = {
5142
+ fontWeight: 700,
5143
+ fontSize: "1.125rem",
5144
+ padding: "var(--glyph-spacing-md, 1rem)",
5145
+ borderBottom: "1px solid var(--glyph-border, #d0d8e4)",
5146
+ color: "var(--glyph-heading, #0a0e1a)"
5147
+ };
5148
+ var questionStyle = {
5149
+ fontWeight: 600,
5150
+ fontSize: "0.9375rem",
5151
+ padding: "var(--glyph-spacing-md, 1rem)",
5152
+ paddingBottom: "0.5rem"
5153
+ };
5154
+ var optionsStyle = {
5155
+ padding: "0 var(--glyph-spacing-md, 1rem)",
5156
+ paddingBottom: "var(--glyph-spacing-md, 1rem)"
5157
+ };
5158
+ function optionLabelStyle2(selected) {
5159
+ return {
5160
+ display: "flex",
5161
+ alignItems: "center",
5162
+ gap: "0.5rem",
5163
+ padding: "0.5rem 0.75rem",
5164
+ marginBottom: "0.375rem",
5165
+ borderRadius: "var(--glyph-radius-md, 0.5rem)",
5166
+ cursor: "pointer",
5167
+ background: selected ? "var(--glyph-surface, #e8ecf3)" : "transparent",
5168
+ border: "1px solid",
5169
+ borderColor: selected ? "var(--glyph-border, #d0d8e4)" : "transparent",
5170
+ fontSize: "0.875rem",
5171
+ lineHeight: 1.6
5172
+ };
5173
+ }
5174
+ var voteButtonStyle = {
5175
+ margin: "0 var(--glyph-spacing-md, 1rem) var(--glyph-spacing-md, 1rem)",
5176
+ padding: "0.5rem 1.25rem",
5177
+ borderRadius: "var(--glyph-radius-md, 0.5rem)",
5178
+ border: "1px solid var(--glyph-border, #d0d8e4)",
5179
+ background: "var(--glyph-surface, #e8ecf3)",
5180
+ color: "var(--glyph-text, #1a2035)",
5181
+ cursor: "pointer",
5182
+ fontWeight: 600,
5183
+ fontSize: "0.875rem"
5184
+ };
5185
+ var resultsStyle = {
5186
+ padding: "var(--glyph-spacing-md, 1rem)",
5187
+ borderTop: "1px solid var(--glyph-border, #d0d8e4)"
5188
+ };
5189
+ var resultRowStyle = {
5190
+ marginBottom: "0.5rem"
5191
+ };
5192
+ var resultLabelStyle = {
5193
+ display: "flex",
5194
+ justifyContent: "space-between",
5195
+ fontSize: "0.8125rem",
5196
+ marginBottom: "0.25rem"
5197
+ };
5198
+ var barTrackStyle = {
5199
+ height: "0.5rem",
5200
+ borderRadius: "0.25rem",
5201
+ background: "var(--glyph-poll-bar-bg, var(--glyph-surface, #e8ecf3))",
5202
+ overflow: "hidden"
5203
+ };
5204
+ function barFillStyle(percentage) {
5205
+ return {
5206
+ height: "100%",
5207
+ width: `${String(percentage)}%`,
5208
+ borderRadius: "0.25rem",
5209
+ background: "var(--glyph-poll-bar-fill, var(--glyph-accent, #0a9d7c))",
5210
+ transition: "width 0.3s ease"
5211
+ };
5212
+ }
5213
+ function Poll({ data, block, onInteraction }) {
5214
+ const { question, options, multiple = false, showResults = true, title } = data;
5215
+ const baseId = `glyph-poll-${block.id}`;
5216
+ const [selected, setSelected] = react.useState([]);
5217
+ const [votes, setVotes] = react.useState(() => options.map(() => 0));
5218
+ const [hasVoted, setHasVoted] = react.useState(false);
5219
+ const toggleOption = (index) => {
5220
+ if (hasVoted) return;
5221
+ if (multiple) {
5222
+ setSelected(
5223
+ (prev) => prev.includes(index) ? prev.filter((i) => i !== index) : [...prev, index]
5224
+ );
5225
+ } else {
5226
+ setSelected([index]);
5227
+ }
5228
+ };
5229
+ const handleVote = () => {
5230
+ if (selected.length === 0 || hasVoted) return;
5231
+ const newVotes = [...votes];
5232
+ for (const idx of selected) {
5233
+ newVotes[idx] = (newVotes[idx] ?? 0) + 1;
5234
+ }
5235
+ setVotes(newVotes);
5236
+ setHasVoted(true);
5237
+ if (onInteraction) {
5238
+ onInteraction({
5239
+ kind: "poll-vote",
5240
+ timestamp: (/* @__PURE__ */ new Date()).toISOString(),
5241
+ blockId: block.id,
5242
+ blockType: block.type,
5243
+ payload: {
5244
+ selectedOptions: selected.map((i) => options[i] ?? String(i)),
5245
+ selectedIndices: [...selected]
5246
+ }
5247
+ });
5248
+ }
5249
+ };
5250
+ const totalVotes = votes.reduce((a, b) => a + b, 0);
5251
+ return /* @__PURE__ */ jsxRuntime.jsxs("div", { id: baseId, role: "region", "aria-label": title ?? "Poll", style: containerStyle3, children: [
5252
+ 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: [
5255
+ /* @__PURE__ */ jsxRuntime.jsx(
5256
+ "input",
5257
+ {
5258
+ type: multiple ? "checkbox" : "radio",
5259
+ name: `${baseId}-option`,
5260
+ checked: selected.includes(index),
5261
+ disabled: hasVoted,
5262
+ onChange: () => toggleOption(index),
5263
+ "aria-checked": selected.includes(index)
5264
+ }
5265
+ ),
5266
+ option
5267
+ ] }, index)) }),
5268
+ !hasVoted && /* @__PURE__ */ jsxRuntime.jsx(
5269
+ "button",
5270
+ {
5271
+ type: "button",
5272
+ disabled: selected.length === 0,
5273
+ style: {
5274
+ ...voteButtonStyle,
5275
+ opacity: selected.length === 0 ? 0.5 : 1,
5276
+ cursor: selected.length === 0 ? "not-allowed" : "pointer"
5277
+ },
5278
+ onClick: handleVote,
5279
+ children: "Vote"
5280
+ }
5281
+ ),
5282
+ showResults && hasVoted && /* @__PURE__ */ jsxRuntime.jsx("div", { role: "status", "aria-live": "polite", style: resultsStyle, children: options.map((option, index) => {
5283
+ const count = votes[index] ?? 0;
5284
+ const percentage = totalVotes > 0 ? count / totalVotes * 100 : 0;
5285
+ return /* @__PURE__ */ jsxRuntime.jsxs("div", { style: resultRowStyle, children: [
5286
+ /* @__PURE__ */ jsxRuntime.jsxs("div", { style: resultLabelStyle, children: [
5287
+ /* @__PURE__ */ jsxRuntime.jsx("span", { children: option }),
5288
+ /* @__PURE__ */ jsxRuntime.jsxs("span", { children: [
5289
+ String(count),
5290
+ " vote",
5291
+ count !== 1 ? "s" : "",
5292
+ " (",
5293
+ String(Math.round(percentage)),
5294
+ "%)"
5295
+ ] })
5296
+ ] }),
5297
+ /* @__PURE__ */ jsxRuntime.jsx(
5298
+ "div",
5299
+ {
5300
+ style: barTrackStyle,
5301
+ role: "progressbar",
5302
+ "aria-valuenow": percentage,
5303
+ "aria-valuemin": 0,
5304
+ "aria-valuemax": 100,
5305
+ "aria-label": `${option}: ${String(Math.round(percentage))}%`,
5306
+ children: /* @__PURE__ */ jsxRuntime.jsx("div", { style: barFillStyle(percentage) })
5307
+ }
5308
+ )
5309
+ ] }, index);
5310
+ }) })
5311
+ ] });
5312
+ }
5313
+
5314
+ // src/poll/index.ts
5315
+ var pollDefinition = {
5316
+ type: "ui:poll",
5317
+ schema: schemas.pollSchema,
5318
+ render: Poll
5319
+ };
5320
+
5321
+ // src/rating/styles.ts
5322
+ var containerStyle4 = {
5323
+ fontFamily: "var(--glyph-font-body, system-ui, sans-serif)",
5324
+ color: "var(--glyph-text, #1a2035)",
5325
+ border: "1px solid var(--glyph-border, #d0d8e4)",
5326
+ borderRadius: "var(--glyph-radius-md, 0.5rem)",
5327
+ overflow: "hidden"
5328
+ };
5329
+ var headerStyle3 = {
5330
+ fontWeight: 700,
5331
+ fontSize: "1.125rem",
5332
+ padding: "var(--glyph-spacing-md, 1rem)",
5333
+ borderBottom: "1px solid var(--glyph-border, #d0d8e4)",
5334
+ color: "var(--glyph-heading, #0a0e1a)"
5335
+ };
5336
+ function itemStyle2(isLast) {
5337
+ return {
5338
+ padding: "var(--glyph-spacing-md, 1rem)",
5339
+ borderBottom: isLast ? "none" : "1px solid var(--glyph-border, #d0d8e4)"
5340
+ };
5341
+ }
5342
+ var itemLabelStyle = {
5343
+ fontWeight: 600,
5344
+ fontSize: "0.9375rem",
5345
+ marginBottom: "0.25rem"
5346
+ };
5347
+ var itemDescriptionStyle = {
5348
+ fontSize: "0.8125rem",
5349
+ color: "var(--glyph-text-muted, #6b7a94)",
5350
+ marginBottom: "0.5rem"
5351
+ };
5352
+ var starsContainerStyle = {
5353
+ display: "flex",
5354
+ gap: "0.25rem",
5355
+ alignItems: "center"
5356
+ };
5357
+ function starButtonStyle(filled, hovered) {
5358
+ return {
5359
+ background: "none",
5360
+ border: "none",
5361
+ padding: "0.125rem",
5362
+ cursor: "pointer",
5363
+ fontSize: "1.25rem",
5364
+ lineHeight: 1,
5365
+ color: filled || hovered ? "var(--glyph-rating-star-fill, #f59e0b)" : "var(--glyph-rating-star-empty, var(--glyph-border, #d0d8e4))",
5366
+ transition: "color 0.15s ease"
5367
+ };
5368
+ }
5369
+ function numberButtonStyle(selected) {
5370
+ return {
5371
+ minWidth: "2rem",
5372
+ height: "2rem",
5373
+ display: "flex",
5374
+ alignItems: "center",
5375
+ justifyContent: "center",
5376
+ borderRadius: "var(--glyph-radius-sm, 0.375rem)",
5377
+ border: "1px solid var(--glyph-border, #d0d8e4)",
5378
+ background: selected ? "var(--glyph-accent, #0a9d7c)" : "transparent",
5379
+ color: selected ? "#fff" : "var(--glyph-text, #1a2035)",
5380
+ cursor: "pointer",
5381
+ fontWeight: 600,
5382
+ fontSize: "0.875rem",
5383
+ transition: "background 0.15s ease, color 0.15s ease"
5384
+ };
5385
+ }
5386
+ var scaleLabelsStyle = {
5387
+ display: "flex",
5388
+ justifyContent: "space-between",
5389
+ fontSize: "0.75rem",
5390
+ color: "var(--glyph-text-muted, #6b7a94)",
5391
+ marginTop: "0.375rem"
5392
+ };
5393
+ function Rating({
5394
+ data,
5395
+ block,
5396
+ onInteraction
5397
+ }) {
5398
+ const { title, scale = 5, mode = "star", labels, items } = data;
5399
+ const baseId = `glyph-rating-${block.id}`;
5400
+ const [ratings, setRatings] = react.useState(() => items.map(() => null));
5401
+ const [hoveredStar, setHoveredStar] = react.useState(null);
5402
+ const handleRate = (itemIndex, value) => {
5403
+ const newRatings = [...ratings];
5404
+ newRatings[itemIndex] = value;
5405
+ setRatings(newRatings);
5406
+ if (onInteraction) {
5407
+ onInteraction({
5408
+ kind: "rating-change",
5409
+ timestamp: (/* @__PURE__ */ new Date()).toISOString(),
5410
+ blockId: block.id,
5411
+ blockType: block.type,
5412
+ payload: {
5413
+ itemIndex,
5414
+ itemLabel: items[itemIndex]?.label ?? "",
5415
+ value,
5416
+ allRatings: items.map((item, i) => ({
5417
+ label: item.label,
5418
+ value: i === itemIndex ? value : newRatings[i] ?? null
5419
+ }))
5420
+ }
5421
+ });
5422
+ }
5423
+ };
5424
+ return /* @__PURE__ */ jsxRuntime.jsxs("div", { id: baseId, role: "region", "aria-label": title ?? "Rating", style: containerStyle4, children: [
5425
+ title && /* @__PURE__ */ jsxRuntime.jsx("div", { style: headerStyle3, children: title }),
5426
+ items.map((item, itemIndex) => {
5427
+ const currentRating = ratings[itemIndex] ?? null;
5428
+ const isLast = itemIndex === items.length - 1;
5429
+ 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) => {
5433
+ const value = starIndex + 1;
5434
+ const isHovered = hoveredStar !== null && hoveredStar.itemIndex === itemIndex && value <= hoveredStar.value;
5435
+ const isFilled = currentRating !== null && value <= currentRating;
5436
+ if (mode === "number") {
5437
+ return /* @__PURE__ */ jsxRuntime.jsx(
5438
+ "button",
5439
+ {
5440
+ type: "button",
5441
+ role: "radio",
5442
+ "aria-checked": currentRating === value,
5443
+ "aria-label": `${String(value)} out of ${String(scale)}`,
5444
+ style: numberButtonStyle(currentRating === value),
5445
+ onClick: () => handleRate(itemIndex, value),
5446
+ children: String(value)
5447
+ },
5448
+ starIndex
5449
+ );
5450
+ }
5451
+ return /* @__PURE__ */ jsxRuntime.jsx(
5452
+ "button",
5453
+ {
5454
+ type: "button",
5455
+ role: "radio",
5456
+ "aria-checked": currentRating === value,
5457
+ "aria-label": `${String(value)} out of ${String(scale)} stars`,
5458
+ style: starButtonStyle(isFilled, isHovered),
5459
+ onClick: () => handleRate(itemIndex, value),
5460
+ onMouseEnter: () => setHoveredStar({ itemIndex, value }),
5461
+ onMouseLeave: () => setHoveredStar(null),
5462
+ children: "\u2605"
5463
+ },
5464
+ starIndex
5465
+ );
5466
+ }) }),
5467
+ labels && /* @__PURE__ */ jsxRuntime.jsxs("div", { style: scaleLabelsStyle, children: [
5468
+ /* @__PURE__ */ jsxRuntime.jsx("span", { children: labels.low }),
5469
+ /* @__PURE__ */ jsxRuntime.jsx("span", { children: labels.high })
5470
+ ] }),
5471
+ /* @__PURE__ */ jsxRuntime.jsx(
5472
+ "div",
5473
+ {
5474
+ "aria-live": "polite",
5475
+ style: {
5476
+ position: "absolute",
5477
+ width: "1px",
5478
+ height: "1px",
5479
+ padding: 0,
5480
+ margin: "-1px",
5481
+ overflow: "hidden",
5482
+ clip: "rect(0,0,0,0)",
5483
+ whiteSpace: "nowrap",
5484
+ border: 0
5485
+ },
5486
+ children: currentRating !== null && `${item.label} rated ${String(currentRating)} out of ${String(scale)}`
5487
+ }
5488
+ )
5489
+ ] }, itemIndex);
5490
+ })
5491
+ ] });
5492
+ }
5493
+
5494
+ // src/rating/index.ts
5495
+ var ratingDefinition = {
5496
+ type: "ui:rating",
5497
+ schema: schemas.ratingSchema,
5498
+ render: Rating
5499
+ };
5500
+
5501
+ // src/ranker/styles.ts
5502
+ var containerStyle5 = {
5503
+ fontFamily: "var(--glyph-font-body, system-ui, sans-serif)",
5504
+ color: "var(--glyph-text, #1a2035)",
5505
+ border: "1px solid var(--glyph-border, #d0d8e4)",
5506
+ borderRadius: "var(--glyph-radius-md, 0.5rem)",
5507
+ overflow: "hidden"
5508
+ };
5509
+ var headerStyle4 = {
5510
+ fontWeight: 700,
5511
+ fontSize: "1.125rem",
5512
+ padding: "var(--glyph-spacing-md, 1rem)",
5513
+ borderBottom: "1px solid var(--glyph-border, #d0d8e4)",
5514
+ color: "var(--glyph-heading, #0a0e1a)"
5515
+ };
5516
+ var listStyle = {
5517
+ listStyle: "none",
5518
+ margin: 0,
5519
+ padding: 0
5520
+ };
5521
+ function itemStyle3(isDragging, isGrabbed) {
5522
+ return {
5523
+ display: "flex",
5524
+ alignItems: "center",
5525
+ gap: "0.75rem",
5526
+ padding: "0.75rem var(--glyph-spacing-md, 1rem)",
5527
+ borderBottom: "1px solid var(--glyph-border, #d0d8e4)",
5528
+ background: isDragging ? "var(--glyph-accent-subtle, #e6f6f2)" : "transparent",
5529
+ cursor: isGrabbed ? "grabbing" : "grab",
5530
+ userSelect: "none",
5531
+ transition: "background 0.15s ease",
5532
+ outline: isGrabbed ? "2px solid var(--glyph-accent, #0a9d7c)" : "none",
5533
+ outlineOffset: "-2px"
5534
+ };
5535
+ }
5536
+ var rankBadgeStyle = {
5537
+ minWidth: "1.75rem",
5538
+ height: "1.75rem",
5539
+ display: "flex",
5540
+ alignItems: "center",
5541
+ justifyContent: "center",
5542
+ borderRadius: "50%",
5543
+ background: "var(--glyph-surface, #e8ecf3)",
5544
+ fontWeight: 700,
5545
+ fontSize: "0.8125rem",
5546
+ color: "var(--glyph-text-muted, #6b7a94)",
5547
+ flexShrink: 0
5548
+ };
5549
+ var itemContentStyle = {
5550
+ flex: 1,
5551
+ minWidth: 0
5552
+ };
5553
+ var itemLabelStyle2 = {
5554
+ fontWeight: 600,
5555
+ fontSize: "0.9375rem"
5556
+ };
5557
+ var itemDescriptionStyle2 = {
5558
+ fontSize: "0.8125rem",
5559
+ color: "var(--glyph-text-muted, #6b7a94)",
5560
+ marginTop: "0.125rem"
5561
+ };
5562
+ var gripStyle = {
5563
+ color: "var(--glyph-text-muted, #6b7a94)",
5564
+ fontSize: "1rem",
5565
+ flexShrink: 0
5566
+ };
5567
+ function Ranker({
5568
+ data,
5569
+ block,
5570
+ onInteraction
5571
+ }) {
5572
+ const { title, items: initialItems } = data;
5573
+ const baseId = `glyph-ranker-${block.id}`;
5574
+ const [items, setItems] = react.useState(initialItems);
5575
+ const [grabbedIndex, setGrabbedIndex] = react.useState(null);
5576
+ const moveItem = react.useCallback(
5577
+ (fromIndex, toIndex) => {
5578
+ if (fromIndex === toIndex) return;
5579
+ setItems((prevItems) => {
5580
+ const newItems = [...prevItems];
5581
+ const [moved] = newItems.splice(fromIndex, 1);
5582
+ if (!moved) return prevItems;
5583
+ newItems.splice(toIndex, 0, moved);
5584
+ if (onInteraction) {
5585
+ onInteraction({
5586
+ kind: "ranker-reorder",
5587
+ timestamp: (/* @__PURE__ */ new Date()).toISOString(),
5588
+ blockId: block.id,
5589
+ blockType: block.type,
5590
+ payload: {
5591
+ orderedItems: newItems.map((item, i) => ({
5592
+ id: item.id,
5593
+ label: item.label,
5594
+ rank: i + 1
5595
+ })),
5596
+ movedItem: {
5597
+ id: moved.id,
5598
+ label: moved.label,
5599
+ fromRank: fromIndex + 1,
5600
+ toRank: toIndex + 1
5601
+ }
5602
+ }
5603
+ });
5604
+ }
5605
+ return newItems;
5606
+ });
5607
+ },
5608
+ [block.id, block.type, onInteraction]
5609
+ );
5610
+ const handleKeyDown = (e, index) => {
5611
+ if (e.key === " " || e.key === "Enter") {
5612
+ e.preventDefault();
5613
+ if (grabbedIndex === null) {
5614
+ setGrabbedIndex(index);
5615
+ } else {
5616
+ setGrabbedIndex(null);
5617
+ }
5618
+ } else if (e.key === "Escape") {
5619
+ setGrabbedIndex(null);
5620
+ } else if (e.key === "ArrowUp" && grabbedIndex !== null) {
5621
+ e.preventDefault();
5622
+ if (grabbedIndex > 0) {
5623
+ moveItem(grabbedIndex, grabbedIndex - 1);
5624
+ setGrabbedIndex(grabbedIndex - 1);
5625
+ }
5626
+ } else if (e.key === "ArrowDown" && grabbedIndex !== null) {
5627
+ e.preventDefault();
5628
+ if (grabbedIndex < items.length - 1) {
5629
+ moveItem(grabbedIndex, grabbedIndex + 1);
5630
+ setGrabbedIndex(grabbedIndex + 1);
5631
+ }
5632
+ }
5633
+ };
5634
+ return /* @__PURE__ */ jsxRuntime.jsxs("div", { id: baseId, role: "region", "aria-label": title ?? "Ranker", style: containerStyle5, children: [
5635
+ 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
+ )) }),
5656
+ /* @__PURE__ */ jsxRuntime.jsx(
5657
+ "div",
5658
+ {
5659
+ "aria-live": "assertive",
5660
+ style: {
5661
+ position: "absolute",
5662
+ width: "1px",
5663
+ height: "1px",
5664
+ padding: 0,
5665
+ margin: "-1px",
5666
+ overflow: "hidden",
5667
+ clip: "rect(0,0,0,0)",
5668
+ whiteSpace: "nowrap",
5669
+ border: 0
5670
+ },
5671
+ children: grabbedIndex !== null && `${items[grabbedIndex]?.label ?? ""} grabbed, rank ${String(grabbedIndex + 1)} of ${String(items.length)}. Use arrow keys to move.`
5672
+ }
5673
+ )
5674
+ ] });
5675
+ }
5676
+
5677
+ // src/ranker/index.ts
5678
+ var rankerDefinition = {
5679
+ type: "ui:ranker",
5680
+ schema: schemas.rankerSchema,
5681
+ render: Ranker
5682
+ };
5683
+
5684
+ // src/slider/styles.ts
5685
+ var containerStyle6 = {
5686
+ fontFamily: "var(--glyph-font-body, system-ui, sans-serif)",
5687
+ color: "var(--glyph-text, #1a2035)",
5688
+ border: "1px solid var(--glyph-border, #d0d8e4)",
5689
+ borderRadius: "var(--glyph-radius-md, 0.5rem)",
5690
+ overflow: "hidden"
5691
+ };
5692
+ var headerStyle5 = {
5693
+ fontWeight: 700,
5694
+ fontSize: "1.125rem",
5695
+ padding: "var(--glyph-spacing-md, 1rem)",
5696
+ borderBottom: "1px solid var(--glyph-border, #d0d8e4)",
5697
+ color: "var(--glyph-heading, #0a0e1a)"
5698
+ };
5699
+ function parameterStyle(isLast) {
5700
+ return {
5701
+ padding: "var(--glyph-spacing-md, 1rem)",
5702
+ borderBottom: isLast ? "none" : "1px solid var(--glyph-border, #d0d8e4)"
5703
+ };
5704
+ }
5705
+ var parameterHeaderStyle = {
5706
+ display: "flex",
5707
+ justifyContent: "space-between",
5708
+ alignItems: "center",
5709
+ marginBottom: "0.5rem"
5710
+ };
5711
+ var parameterLabelStyle = {
5712
+ fontWeight: 600,
5713
+ fontSize: "0.9375rem"
5714
+ };
5715
+ var parameterValueStyle = {
5716
+ fontSize: "0.9375rem",
5717
+ fontWeight: 600,
5718
+ color: "var(--glyph-accent, #0a9d7c)",
5719
+ fontVariantNumeric: "tabular-nums"
5720
+ };
5721
+ var rangeInputStyle = {
5722
+ width: "100%",
5723
+ margin: 0,
5724
+ accentColor: "var(--glyph-slider-fill, var(--glyph-accent, #0a9d7c))"
5725
+ };
5726
+ var rangeLabelsStyle = {
5727
+ display: "flex",
5728
+ justifyContent: "space-between",
5729
+ fontSize: "0.75rem",
5730
+ color: "var(--glyph-text-muted, #6b7a94)",
5731
+ marginTop: "0.25rem"
5732
+ };
5733
+ function Slider({
5734
+ data,
5735
+ block,
5736
+ onInteraction
5737
+ }) {
5738
+ const { title, parameters } = data;
5739
+ const baseId = `glyph-slider-${block.id}`;
5740
+ const [values, setValues] = react.useState(
5741
+ () => parameters.map((p) => p.value ?? p.min ?? 0)
5742
+ );
5743
+ const handleChange = (paramIndex, newValue) => {
5744
+ const newValues = [...values];
5745
+ newValues[paramIndex] = newValue;
5746
+ setValues(newValues);
5747
+ const param = parameters[paramIndex];
5748
+ if (!param) return;
5749
+ if (onInteraction) {
5750
+ onInteraction({
5751
+ kind: "slider-change",
5752
+ timestamp: (/* @__PURE__ */ new Date()).toISOString(),
5753
+ blockId: block.id,
5754
+ blockType: block.type,
5755
+ payload: {
5756
+ parameterId: param.id,
5757
+ parameterLabel: param.label,
5758
+ value: newValue,
5759
+ allValues: parameters.map((p, i) => ({
5760
+ id: p.id,
5761
+ label: p.label,
5762
+ value: i === paramIndex ? newValue : newValues[i] ?? 0
5763
+ }))
5764
+ }
5765
+ });
5766
+ }
5767
+ };
5768
+ const formatValue = (value, unit) => {
5769
+ return unit ? `${String(value)}${unit}` : String(value);
5770
+ };
5771
+ return /* @__PURE__ */ jsxRuntime.jsxs("div", { id: baseId, role: "region", "aria-label": title ?? "Slider", style: containerStyle6, children: [
5772
+ title && /* @__PURE__ */ jsxRuntime.jsx("div", { style: headerStyle5, children: title }),
5773
+ parameters.map((param, index) => {
5774
+ const min2 = param.min ?? 0;
5775
+ const max2 = param.max ?? 100;
5776
+ const step = param.step ?? 1;
5777
+ const currentValue = values[index] ?? min2;
5778
+ const isLast = index === parameters.length - 1;
5779
+ return /* @__PURE__ */ jsxRuntime.jsxs("div", { style: parameterStyle(isLast), children: [
5780
+ /* @__PURE__ */ jsxRuntime.jsxs("div", { style: parameterHeaderStyle, children: [
5781
+ /* @__PURE__ */ jsxRuntime.jsx("label", { htmlFor: `${baseId}-${param.id}`, style: parameterLabelStyle, children: param.label }),
5782
+ /* @__PURE__ */ jsxRuntime.jsx("span", { style: parameterValueStyle, "aria-live": "polite", children: formatValue(currentValue, param.unit) })
5783
+ ] }),
5784
+ /* @__PURE__ */ jsxRuntime.jsx(
5785
+ "input",
5786
+ {
5787
+ id: `${baseId}-${param.id}`,
5788
+ type: "range",
5789
+ min: min2,
5790
+ max: max2,
5791
+ step,
5792
+ value: currentValue,
5793
+ onChange: (e) => handleChange(index, Number(e.target.value)),
5794
+ "aria-valuemin": min2,
5795
+ "aria-valuemax": max2,
5796
+ "aria-valuenow": currentValue,
5797
+ "aria-valuetext": formatValue(currentValue, param.unit),
5798
+ style: rangeInputStyle
5799
+ }
5800
+ ),
5801
+ /* @__PURE__ */ jsxRuntime.jsxs("div", { style: rangeLabelsStyle, children: [
5802
+ /* @__PURE__ */ jsxRuntime.jsx("span", { children: formatValue(min2, param.unit) }),
5803
+ /* @__PURE__ */ jsxRuntime.jsx("span", { children: formatValue(max2, param.unit) })
5804
+ ] })
5805
+ ] }, param.id);
5806
+ })
5807
+ ] });
5808
+ }
5809
+
5810
+ // src/slider/index.ts
5811
+ var sliderDefinition = {
5812
+ type: "ui:slider",
5813
+ schema: schemas.sliderSchema,
5814
+ render: Slider
5815
+ };
5816
+
5817
+ // src/matrix/styles.ts
5818
+ var containerStyle7 = {
5819
+ fontFamily: "var(--glyph-font-body, system-ui, sans-serif)",
5820
+ color: "var(--glyph-text, #1a2035)",
5821
+ border: "1px solid var(--glyph-border, #d0d8e4)",
5822
+ borderRadius: "var(--glyph-radius-md, 0.5rem)",
5823
+ overflow: "auto"
5824
+ };
5825
+ var headerStyle6 = {
5826
+ fontWeight: 700,
5827
+ fontSize: "1.125rem",
5828
+ padding: "var(--glyph-spacing-md, 1rem)",
5829
+ borderBottom: "1px solid var(--glyph-border, #d0d8e4)",
5830
+ color: "var(--glyph-heading, #0a0e1a)"
5831
+ };
5832
+ var tableStyle = {
5833
+ width: "100%",
5834
+ borderCollapse: "collapse",
5835
+ fontSize: "0.875rem"
5836
+ };
5837
+ var thStyle = {
5838
+ padding: "0.625rem 0.75rem",
5839
+ textAlign: "center",
5840
+ fontWeight: 600,
5841
+ borderBottom: "2px solid var(--glyph-border, #d0d8e4)",
5842
+ background: "var(--glyph-table-header-bg, var(--glyph-surface, #e8ecf3))",
5843
+ whiteSpace: "nowrap"
5844
+ };
5845
+ var rowHeaderStyle = {
5846
+ padding: "0.625rem 0.75rem",
5847
+ textAlign: "left",
5848
+ fontWeight: 600,
5849
+ borderBottom: "1px solid var(--glyph-border, #d0d8e4)",
5850
+ borderRight: "1px solid var(--glyph-border, #d0d8e4)",
5851
+ whiteSpace: "nowrap"
5852
+ };
5853
+ var cellStyle = {
5854
+ padding: "0.375rem 0.5rem",
5855
+ textAlign: "center",
5856
+ borderBottom: "1px solid var(--glyph-border, #d0d8e4)"
5857
+ };
5858
+ var inputStyle = {
5859
+ width: "3.5rem",
5860
+ padding: "0.25rem 0.375rem",
5861
+ textAlign: "center",
5862
+ border: "1px solid var(--glyph-border, #d0d8e4)",
5863
+ borderRadius: "var(--glyph-radius-sm, 0.375rem)",
5864
+ background: "transparent",
5865
+ color: "var(--glyph-text, #1a2035)",
5866
+ fontSize: "0.875rem",
5867
+ fontVariantNumeric: "tabular-nums"
5868
+ };
5869
+ var weightStyle = {
5870
+ fontSize: "0.6875rem",
5871
+ color: "var(--glyph-text-muted, #6b7a94)",
5872
+ fontWeight: 400
5873
+ };
5874
+ var totalCellStyle = {
5875
+ padding: "0.625rem 0.75rem",
5876
+ textAlign: "center",
5877
+ fontWeight: 700,
5878
+ borderBottom: "1px solid var(--glyph-border, #d0d8e4)",
5879
+ background: "var(--glyph-surface, #e8ecf3)",
5880
+ fontVariantNumeric: "tabular-nums"
5881
+ };
5882
+ var totalHeaderStyle = {
5883
+ ...thStyle,
5884
+ borderLeft: "2px solid var(--glyph-border, #d0d8e4)"
5885
+ };
5886
+ function computeWeightedTotals(rows, columns, values) {
5887
+ return rows.map((row) => {
5888
+ let total = 0;
5889
+ for (const col of columns) {
5890
+ const score = values[row.id]?.[col.id] ?? 0;
5891
+ const weight = col.weight ?? 1;
5892
+ total += score * weight;
5893
+ }
5894
+ return { rowId: row.id, rowLabel: row.label, total: Math.round(total * 100) / 100 };
5895
+ });
5896
+ }
5897
+ function Matrix({
5898
+ data,
5899
+ block,
5900
+ onInteraction
5901
+ }) {
5902
+ const { title, scale = 5, showTotals = true, columns, rows } = data;
5903
+ const baseId = `glyph-matrix-${block.id}`;
5904
+ const [values, setValues] = react.useState(() => {
5905
+ const init = {};
5906
+ for (const row of rows) {
5907
+ const rowMap = {};
5908
+ for (const col of columns) {
5909
+ rowMap[col.id] = 0;
5910
+ }
5911
+ init[row.id] = rowMap;
5912
+ }
5913
+ return init;
5914
+ });
5915
+ const handleChange = react.useCallback(
5916
+ (rowId, columnId, value) => {
5917
+ const clamped = Math.max(0, Math.min(scale, value));
5918
+ setValues((prevValues) => {
5919
+ const newValues = Object.fromEntries(
5920
+ Object.entries(prevValues).map(([k, v]) => [k, { ...v }])
5921
+ );
5922
+ if (!newValues[rowId]) newValues[rowId] = {};
5923
+ newValues[rowId] = { ...newValues[rowId], [columnId]: clamped };
5924
+ const row = rows.find((r) => r.id === rowId);
5925
+ const col = columns.find((c) => c.id === columnId);
5926
+ if (onInteraction && row && col) {
5927
+ const payloadValues = Object.fromEntries(
5928
+ Object.entries(newValues).map(([k, v]) => [k, { ...v }])
5929
+ );
5930
+ onInteraction({
5931
+ kind: "matrix-change",
5932
+ timestamp: (/* @__PURE__ */ new Date()).toISOString(),
5933
+ blockId: block.id,
5934
+ blockType: block.type,
5935
+ payload: {
5936
+ rowId,
5937
+ rowLabel: row.label,
5938
+ columnId,
5939
+ columnLabel: col.label,
5940
+ value: clamped,
5941
+ allValues: payloadValues,
5942
+ weightedTotals: computeWeightedTotals(rows, columns, newValues)
5943
+ }
5944
+ });
5945
+ }
5946
+ return newValues;
5947
+ });
5948
+ },
5949
+ [scale, rows, columns, block.id, block.type, onInteraction]
5950
+ );
5951
+ const totals = computeWeightedTotals(rows, columns, values);
5952
+ return /* @__PURE__ */ jsxRuntime.jsxs("div", { id: baseId, role: "region", "aria-label": title ?? "Decision Matrix", style: containerStyle7, children: [
5953
+ title && /* @__PURE__ */ jsxRuntime.jsx("div", { style: headerStyle6, children: title }),
5954
+ /* @__PURE__ */ jsxRuntime.jsxs("table", { role: "grid", style: tableStyle, children: [
5955
+ /* @__PURE__ */ jsxRuntime.jsx("thead", { children: /* @__PURE__ */ jsxRuntime.jsxs("tr", { children: [
5956
+ /* @__PURE__ */ jsxRuntime.jsx("th", { style: thStyle }),
5957
+ columns.map((col) => /* @__PURE__ */ jsxRuntime.jsxs("th", { style: thStyle, children: [
5958
+ col.label,
5959
+ (col.weight ?? 1) !== 1 && /* @__PURE__ */ jsxRuntime.jsxs("div", { style: weightStyle, children: [
5960
+ "\xD7",
5961
+ String(col.weight)
5962
+ ] })
5963
+ ] }, col.id)),
5964
+ showTotals && /* @__PURE__ */ jsxRuntime.jsx("th", { style: totalHeaderStyle, children: "Total" })
5965
+ ] }) }),
5966
+ /* @__PURE__ */ jsxRuntime.jsx("tbody", { children: rows.map((row) => {
5967
+ const rowTotal = totals.find((t) => t.rowId === row.id)?.total ?? 0;
5968
+ return /* @__PURE__ */ jsxRuntime.jsxs("tr", { children: [
5969
+ /* @__PURE__ */ jsxRuntime.jsx("th", { scope: "row", style: rowHeaderStyle, children: row.label }),
5970
+ columns.map((col) => {
5971
+ const cellValue = values[row.id]?.[col.id] ?? 0;
5972
+ return /* @__PURE__ */ jsxRuntime.jsx("td", { style: cellStyle, children: /* @__PURE__ */ jsxRuntime.jsx(
5973
+ "input",
5974
+ {
5975
+ type: "number",
5976
+ min: 0,
5977
+ max: scale,
5978
+ value: cellValue,
5979
+ onChange: (e) => handleChange(row.id, col.id, Number(e.target.value)),
5980
+ "aria-label": `Score for ${row.label} on ${col.label}`,
5981
+ style: inputStyle
5982
+ }
5983
+ ) }, col.id);
5984
+ }),
5985
+ showTotals && /* @__PURE__ */ jsxRuntime.jsx("td", { style: totalCellStyle, children: String(rowTotal) })
5986
+ ] }, row.id);
5987
+ }) })
5988
+ ] })
5989
+ ] });
5990
+ }
5991
+
5992
+ // src/matrix/index.ts
5993
+ var matrixDefinition = {
5994
+ type: "ui:matrix",
5995
+ schema: schemas.matrixSchema,
5996
+ render: Matrix
5997
+ };
5998
+
5999
+ // src/form/styles.ts
6000
+ var containerStyle8 = {
6001
+ fontFamily: "var(--glyph-font-body, system-ui, sans-serif)",
6002
+ color: "var(--glyph-text, #1a2035)",
6003
+ border: "1px solid var(--glyph-border, #d0d8e4)",
6004
+ borderRadius: "var(--glyph-radius-md, 0.5rem)",
6005
+ overflow: "hidden"
6006
+ };
6007
+ var headerStyle7 = {
6008
+ fontWeight: 700,
6009
+ fontSize: "1.125rem",
6010
+ padding: "var(--glyph-spacing-md, 1rem)",
6011
+ paddingBottom: "0.25rem",
6012
+ color: "var(--glyph-heading, #0a0e1a)"
6013
+ };
6014
+ var descriptionStyle = {
6015
+ fontSize: "0.875rem",
6016
+ color: "var(--glyph-text-muted, #6b7a94)",
6017
+ padding: "0 var(--glyph-spacing-md, 1rem)",
6018
+ paddingBottom: "var(--glyph-spacing-sm, 0.5rem)"
6019
+ };
6020
+ var formStyle = {
6021
+ padding: "var(--glyph-spacing-md, 1rem)"
6022
+ };
6023
+ var fieldStyle = {
6024
+ marginBottom: "var(--glyph-spacing-md, 1rem)"
6025
+ };
6026
+ var labelStyle3 = {
6027
+ display: "block",
6028
+ fontWeight: 600,
6029
+ fontSize: "0.875rem",
6030
+ marginBottom: "0.375rem"
6031
+ };
6032
+ var requiredStyle = {
6033
+ color: "var(--glyph-form-error, #dc2626)",
6034
+ marginLeft: "0.25rem"
6035
+ };
6036
+ var textInputStyle = {
6037
+ width: "100%",
6038
+ padding: "0.5rem 0.75rem",
6039
+ border: "1px solid var(--glyph-border, #d0d8e4)",
6040
+ borderRadius: "var(--glyph-radius-sm, 0.375rem)",
6041
+ background: "transparent",
6042
+ color: "var(--glyph-text, #1a2035)",
6043
+ fontSize: "0.875rem",
6044
+ fontFamily: "inherit",
6045
+ boxSizing: "border-box"
6046
+ };
6047
+ var selectInputStyle = {
6048
+ ...textInputStyle,
6049
+ appearance: "auto"
6050
+ };
6051
+ var checkboxLabelStyle = {
6052
+ display: "flex",
6053
+ alignItems: "center",
6054
+ gap: "0.5rem",
6055
+ fontSize: "0.875rem",
6056
+ cursor: "pointer"
6057
+ };
6058
+ var rangeValueStyle = {
6059
+ fontSize: "0.875rem",
6060
+ fontWeight: 600,
6061
+ color: "var(--glyph-accent, #0a9d7c)",
6062
+ marginLeft: "0.5rem",
6063
+ fontVariantNumeric: "tabular-nums"
6064
+ };
6065
+ var submitButtonStyle = {
6066
+ padding: "0.625rem 1.5rem",
6067
+ borderRadius: "var(--glyph-radius-md, 0.5rem)",
6068
+ border: "1px solid var(--glyph-accent, #0a9d7c)",
6069
+ background: "var(--glyph-accent, #0a9d7c)",
6070
+ color: "#fff",
6071
+ cursor: "pointer",
6072
+ fontWeight: 600,
6073
+ fontSize: "0.875rem",
6074
+ marginTop: "var(--glyph-spacing-sm, 0.5rem)"
6075
+ };
6076
+ function invalidStyle(isInvalid) {
6077
+ if (!isInvalid) return {};
6078
+ return {
6079
+ borderColor: "var(--glyph-form-error, #dc2626)"
6080
+ };
6081
+ }
6082
+ function renderField({
6083
+ field,
6084
+ baseId,
6085
+ values,
6086
+ validation,
6087
+ submitted,
6088
+ updateValue
6089
+ }) {
6090
+ const isInvalid = validation[field.id] === true;
6091
+ const fieldId = `${baseId}-${field.id}`;
6092
+ switch (field.type) {
6093
+ case "text":
6094
+ return /* @__PURE__ */ jsxRuntime.jsxs("div", { style: fieldStyle, children: [
6095
+ /* @__PURE__ */ jsxRuntime.jsxs("label", { htmlFor: fieldId, style: labelStyle3, children: [
6096
+ field.label,
6097
+ field.required && /* @__PURE__ */ jsxRuntime.jsx("span", { style: requiredStyle, "aria-hidden": "true", children: "*" })
6098
+ ] }),
6099
+ /* @__PURE__ */ jsxRuntime.jsx(
6100
+ "input",
6101
+ {
6102
+ id: fieldId,
6103
+ type: "text",
6104
+ value: values[field.id] ?? "",
6105
+ onChange: (e) => updateValue(field.id, e.target.value),
6106
+ placeholder: field.placeholder,
6107
+ disabled: submitted,
6108
+ "aria-required": field.required,
6109
+ "aria-invalid": isInvalid,
6110
+ style: { ...textInputStyle, ...invalidStyle(isInvalid) }
6111
+ }
6112
+ )
6113
+ ] }, field.id);
6114
+ case "textarea":
6115
+ return /* @__PURE__ */ jsxRuntime.jsxs("div", { style: fieldStyle, children: [
6116
+ /* @__PURE__ */ jsxRuntime.jsxs("label", { htmlFor: fieldId, style: labelStyle3, children: [
6117
+ field.label,
6118
+ field.required && /* @__PURE__ */ jsxRuntime.jsx("span", { style: requiredStyle, "aria-hidden": "true", children: "*" })
6119
+ ] }),
6120
+ /* @__PURE__ */ jsxRuntime.jsx(
6121
+ "textarea",
6122
+ {
6123
+ id: fieldId,
6124
+ value: values[field.id] ?? "",
6125
+ onChange: (e) => updateValue(field.id, e.target.value),
6126
+ placeholder: field.placeholder,
6127
+ rows: field.rows ?? 4,
6128
+ disabled: submitted,
6129
+ "aria-required": field.required,
6130
+ "aria-invalid": isInvalid,
6131
+ style: {
6132
+ ...textInputStyle,
6133
+ ...invalidStyle(isInvalid),
6134
+ resize: "vertical",
6135
+ fontFamily: "inherit"
6136
+ }
6137
+ }
6138
+ )
6139
+ ] }, field.id);
6140
+ case "select":
6141
+ return /* @__PURE__ */ jsxRuntime.jsxs("div", { style: fieldStyle, children: [
6142
+ /* @__PURE__ */ jsxRuntime.jsxs("label", { htmlFor: fieldId, style: labelStyle3, children: [
6143
+ field.label,
6144
+ field.required && /* @__PURE__ */ jsxRuntime.jsx("span", { style: requiredStyle, "aria-hidden": "true", children: "*" })
6145
+ ] }),
6146
+ /* @__PURE__ */ jsxRuntime.jsx(
6147
+ "select",
6148
+ {
6149
+ id: fieldId,
6150
+ value: values[field.id] ?? "",
6151
+ onChange: (e) => updateValue(field.id, e.target.value),
6152
+ disabled: submitted,
6153
+ "aria-required": field.required,
6154
+ style: selectInputStyle,
6155
+ children: field.options.map((opt) => /* @__PURE__ */ jsxRuntime.jsx("option", { value: opt, children: opt }, opt))
6156
+ }
6157
+ )
6158
+ ] }, field.id);
6159
+ case "checkbox":
6160
+ return /* @__PURE__ */ jsxRuntime.jsx("div", { style: fieldStyle, children: /* @__PURE__ */ jsxRuntime.jsxs("label", { style: checkboxLabelStyle, children: [
6161
+ /* @__PURE__ */ jsxRuntime.jsx(
6162
+ "input",
6163
+ {
6164
+ id: fieldId,
6165
+ type: "checkbox",
6166
+ checked: values[field.id] ?? false,
6167
+ onChange: (e) => updateValue(field.id, e.target.checked),
6168
+ disabled: submitted
6169
+ }
6170
+ ),
6171
+ field.label
6172
+ ] }) }, field.id);
6173
+ case "range": {
6174
+ const min2 = field.min ?? 0;
6175
+ const max2 = field.max ?? 100;
6176
+ const step = field.step ?? 1;
6177
+ const currentValue = values[field.id] ?? min2;
6178
+ const displayValue = field.unit ? `${String(currentValue)}${field.unit}` : String(currentValue);
6179
+ return /* @__PURE__ */ jsxRuntime.jsxs("div", { style: fieldStyle, children: [
6180
+ /* @__PURE__ */ jsxRuntime.jsxs("label", { htmlFor: fieldId, style: labelStyle3, children: [
6181
+ field.label,
6182
+ /* @__PURE__ */ jsxRuntime.jsx("span", { style: rangeValueStyle, children: displayValue })
6183
+ ] }),
6184
+ /* @__PURE__ */ jsxRuntime.jsx(
6185
+ "input",
6186
+ {
6187
+ id: fieldId,
6188
+ type: "range",
6189
+ min: min2,
6190
+ max: max2,
6191
+ step,
6192
+ value: currentValue,
6193
+ onChange: (e) => updateValue(field.id, Number(e.target.value)),
6194
+ disabled: submitted,
6195
+ "aria-valuemin": min2,
6196
+ "aria-valuemax": max2,
6197
+ "aria-valuenow": currentValue,
6198
+ "aria-valuetext": displayValue,
6199
+ style: { width: "100%", accentColor: "var(--glyph-accent, #0a9d7c)" }
6200
+ }
6201
+ )
6202
+ ] }, field.id);
6203
+ }
6204
+ }
6205
+ }
6206
+ function Form({ data, block, onInteraction }) {
6207
+ const { title, description, submitLabel = "Submit", fields } = data;
6208
+ const baseId = `glyph-form-${block.id}`;
6209
+ const [values, setValues] = react.useState(() => {
6210
+ const init = {};
6211
+ for (const field of fields) {
6212
+ switch (field.type) {
6213
+ case "text":
6214
+ case "textarea":
6215
+ init[field.id] = field.default ?? "";
6216
+ break;
6217
+ case "select":
6218
+ init[field.id] = field.default ?? field.options[0] ?? "";
6219
+ break;
6220
+ case "checkbox":
6221
+ init[field.id] = field.default ?? false;
6222
+ break;
6223
+ case "range":
6224
+ init[field.id] = field.default ?? field.min ?? 0;
6225
+ break;
6226
+ }
6227
+ }
6228
+ return init;
6229
+ });
6230
+ const [submitted, setSubmitted] = react.useState(false);
6231
+ const [validation, setValidation] = react.useState({});
6232
+ const updateValue = (fieldId, value) => {
6233
+ setValues((prev) => ({ ...prev, [fieldId]: value }));
6234
+ if (validation[fieldId]) {
6235
+ setValidation((prev) => ({ ...prev, [fieldId]: false }));
6236
+ }
6237
+ };
6238
+ const handleSubmit = (e) => {
6239
+ e.preventDefault();
6240
+ const errors = {};
6241
+ for (const field of fields) {
6242
+ if ("required" in field && field.required) {
6243
+ const val = values[field.id];
6244
+ if (val === "" || val === void 0) {
6245
+ errors[field.id] = true;
6246
+ }
6247
+ }
6248
+ }
6249
+ if (Object.keys(errors).length > 0) {
6250
+ setValidation(errors);
6251
+ return;
6252
+ }
6253
+ setSubmitted(true);
6254
+ if (onInteraction) {
6255
+ onInteraction({
6256
+ kind: "form-submit",
6257
+ timestamp: (/* @__PURE__ */ new Date()).toISOString(),
6258
+ blockId: block.id,
6259
+ blockType: block.type,
6260
+ payload: {
6261
+ values: { ...values },
6262
+ fields: fields.map((f) => ({
6263
+ id: f.id,
6264
+ label: f.label,
6265
+ type: f.type,
6266
+ value: values[f.id] !== void 0 ? values[f.id] : ""
6267
+ }))
6268
+ }
6269
+ });
6270
+ }
6271
+ };
6272
+ return /* @__PURE__ */ jsxRuntime.jsxs("div", { id: baseId, role: "region", "aria-label": title ?? "Form", style: containerStyle8, children: [
6273
+ title && /* @__PURE__ */ jsxRuntime.jsx("div", { style: headerStyle7, children: title }),
6274
+ description && /* @__PURE__ */ jsxRuntime.jsx("div", { style: descriptionStyle, children: description }),
6275
+ /* @__PURE__ */ jsxRuntime.jsxs("form", { onSubmit: handleSubmit, style: formStyle, noValidate: true, children: [
6276
+ fields.map(
6277
+ (field) => renderField({ field, baseId, values, validation, submitted, updateValue })
6278
+ ),
6279
+ /* @__PURE__ */ jsxRuntime.jsx(
6280
+ "button",
6281
+ {
6282
+ type: "submit",
6283
+ disabled: submitted,
6284
+ style: {
6285
+ ...submitButtonStyle,
6286
+ opacity: submitted ? 0.5 : 1,
6287
+ cursor: submitted ? "default" : "pointer"
6288
+ },
6289
+ children: submitted ? "Submitted" : submitLabel
6290
+ }
6291
+ )
6292
+ ] })
6293
+ ] });
6294
+ }
6295
+
6296
+ // src/form/index.ts
6297
+ var formDefinition = {
6298
+ type: "ui:form",
6299
+ schema: schemas.formSchema,
6300
+ render: Form
6301
+ };
6302
+
6303
+ // src/kanban/styles.ts
6304
+ var containerStyle9 = {
6305
+ fontFamily: "var(--glyph-font-body, system-ui, sans-serif)",
6306
+ color: "var(--glyph-text, #1a2035)",
6307
+ border: "1px solid var(--glyph-border, #d0d8e4)",
6308
+ borderRadius: "var(--glyph-radius-md, 0.5rem)",
6309
+ overflow: "hidden"
6310
+ };
6311
+ var headerStyle8 = {
6312
+ fontWeight: 700,
6313
+ fontSize: "1.125rem",
6314
+ padding: "var(--glyph-spacing-md, 1rem)",
6315
+ borderBottom: "1px solid var(--glyph-border, #d0d8e4)",
6316
+ color: "var(--glyph-heading, #0a0e1a)"
6317
+ };
6318
+ var boardStyle = {
6319
+ display: "flex",
6320
+ gap: "var(--glyph-spacing-sm, 0.5rem)",
6321
+ padding: "var(--glyph-spacing-md, 1rem)",
6322
+ overflowX: "auto",
6323
+ minHeight: "200px"
6324
+ };
6325
+ function columnStyle(isOver) {
6326
+ return {
6327
+ flex: "1 1 0",
6328
+ minWidth: "180px",
6329
+ background: isOver ? "var(--glyph-accent-subtle, #e6f6f2)" : "var(--glyph-kanban-column-bg, var(--glyph-surface, #e8ecf3))",
6330
+ borderRadius: "var(--glyph-radius-md, 0.5rem)",
6331
+ padding: "var(--glyph-spacing-sm, 0.5rem)",
6332
+ display: "flex",
6333
+ flexDirection: "column",
6334
+ transition: "background 0.15s ease"
6335
+ };
6336
+ }
6337
+ var columnHeaderStyle = {
6338
+ fontWeight: 700,
6339
+ fontSize: "0.8125rem",
6340
+ textTransform: "uppercase",
6341
+ letterSpacing: "0.5px",
6342
+ padding: "0.375rem 0.5rem",
6343
+ marginBottom: "0.375rem",
6344
+ display: "flex",
6345
+ justifyContent: "space-between",
6346
+ alignItems: "center"
6347
+ };
6348
+ var columnCountStyle = {
6349
+ fontSize: "0.6875rem",
6350
+ fontWeight: 400,
6351
+ color: "var(--glyph-text-muted, #6b7a94)"
6352
+ };
6353
+ function cardStyle(isGrabbed, priority) {
6354
+ const priorityColors = {
6355
+ high: "var(--glyph-kanban-priority-high, #dc2626)",
6356
+ medium: "var(--glyph-kanban-priority-medium, #f59e0b)",
6357
+ low: "var(--glyph-kanban-priority-low, #22c55e)"
6358
+ };
6359
+ return {
6360
+ background: "var(--glyph-kanban-card-bg, var(--glyph-surface-raised, #f4f6fa))",
6361
+ border: `1px solid var(--glyph-kanban-card-border, var(--glyph-border, #d0d8e4))`,
6362
+ borderRadius: "var(--glyph-radius-sm, 0.375rem)",
6363
+ padding: "0.625rem 0.75rem",
6364
+ marginBottom: "0.375rem",
6365
+ cursor: isGrabbed ? "grabbing" : "grab",
6366
+ userSelect: "none",
6367
+ boxShadow: isGrabbed ? "var(--glyph-kanban-drag-shadow, var(--glyph-shadow-md, 0 4px 12px rgba(0,0,0,0.15)))" : "none",
6368
+ borderLeft: priority && priorityColors[priority] ? `3px solid ${priorityColors[priority]}` : void 0,
6369
+ outline: isGrabbed ? "2px solid var(--glyph-accent, #0a9d7c)" : "none",
6370
+ outlineOffset: "-2px"
6371
+ };
6372
+ }
6373
+ var cardTitleStyle = {
6374
+ fontWeight: 600,
6375
+ fontSize: "0.875rem",
6376
+ marginBottom: "0.25rem"
6377
+ };
6378
+ var cardDescStyle = {
6379
+ fontSize: "0.75rem",
6380
+ color: "var(--glyph-text-muted, #6b7a94)",
6381
+ lineHeight: 1.4
6382
+ };
6383
+ var tagContainerStyle = {
6384
+ display: "flex",
6385
+ flexWrap: "wrap",
6386
+ gap: "0.25rem",
6387
+ marginTop: "0.375rem"
6388
+ };
6389
+ var tagStyle = {
6390
+ fontSize: "0.625rem",
6391
+ fontWeight: 600,
6392
+ padding: "0.125rem 0.375rem",
6393
+ borderRadius: "9999px",
6394
+ background: "var(--glyph-accent-subtle, #e6f6f2)",
6395
+ color: "var(--glyph-accent, #0a9d7c)"
6396
+ };
6397
+ var limitStyle = {
6398
+ fontSize: "0.625rem",
6399
+ color: "var(--glyph-text-muted, #6b7a94)"
6400
+ };
6401
+ function Kanban({
6402
+ data,
6403
+ block,
6404
+ onInteraction
6405
+ }) {
6406
+ const { title } = data;
6407
+ const baseId = `glyph-kanban-${block.id}`;
6408
+ const [columns, setColumns] = react.useState(
6409
+ () => data.columns.map((col) => ({ ...col, cards: [...col.cards] }))
6410
+ );
6411
+ const [grabbed, setGrabbed] = react.useState(null);
6412
+ const moveCard = (cardId, sourceColId, destColId, destIndex) => {
6413
+ const newColumns = columns.map((col) => ({
6414
+ ...col,
6415
+ cards: [...col.cards]
6416
+ }));
6417
+ const sourceCol = newColumns.find((c) => c.id === sourceColId);
6418
+ const destCol = newColumns.find((c) => c.id === destColId);
6419
+ if (!sourceCol || !destCol) return;
6420
+ const cardIndex = sourceCol.cards.findIndex((c) => c.id === cardId);
6421
+ if (cardIndex === -1) return;
6422
+ const [card] = sourceCol.cards.splice(cardIndex, 1);
6423
+ if (!card) return;
6424
+ destCol.cards.splice(destIndex, 0, card);
6425
+ setColumns(newColumns);
6426
+ if (onInteraction) {
6427
+ onInteraction({
6428
+ kind: "kanban-move",
6429
+ timestamp: (/* @__PURE__ */ new Date()).toISOString(),
6430
+ blockId: block.id,
6431
+ blockType: block.type,
6432
+ payload: {
6433
+ cardId: card.id,
6434
+ cardTitle: card.title,
6435
+ sourceColumnId: sourceColId,
6436
+ sourceColumnTitle: sourceCol.title,
6437
+ destinationColumnId: destColId,
6438
+ destinationColumnTitle: destCol.title,
6439
+ position: destIndex,
6440
+ allColumns: newColumns.map((c) => ({
6441
+ id: c.id,
6442
+ title: c.title,
6443
+ cardIds: c.cards.map((card2) => card2.id)
6444
+ }))
6445
+ }
6446
+ });
6447
+ }
6448
+ };
6449
+ const handleCardKeyDown = (e, cardId, columnId, cardIndex) => {
6450
+ if (e.key === " " || e.key === "Enter") {
6451
+ e.preventDefault();
6452
+ if (grabbed === null) {
6453
+ setGrabbed({ cardId, columnId, cardIndex });
6454
+ } else {
6455
+ setGrabbed(null);
6456
+ }
6457
+ } else if (e.key === "Escape") {
6458
+ setGrabbed(null);
6459
+ } else if (grabbed && grabbed.cardId === cardId) {
6460
+ const colIndex = columns.findIndex((c) => c.id === grabbed.columnId);
6461
+ const col = columns[colIndex];
6462
+ if (!col) return;
6463
+ if (e.key === "ArrowUp") {
6464
+ e.preventDefault();
6465
+ if (grabbed.cardIndex > 0) {
6466
+ moveCard(cardId, grabbed.columnId, grabbed.columnId, grabbed.cardIndex - 1);
6467
+ setGrabbed({ ...grabbed, cardIndex: grabbed.cardIndex - 1 });
6468
+ }
6469
+ } else if (e.key === "ArrowDown") {
6470
+ e.preventDefault();
6471
+ if (grabbed.cardIndex < col.cards.length - 1) {
6472
+ moveCard(cardId, grabbed.columnId, grabbed.columnId, grabbed.cardIndex + 1);
6473
+ setGrabbed({ ...grabbed, cardIndex: grabbed.cardIndex + 1 });
6474
+ }
6475
+ } else if (e.key === "ArrowLeft") {
6476
+ e.preventDefault();
6477
+ if (colIndex > 0) {
6478
+ const prevCol = columns[colIndex - 1];
6479
+ if (!prevCol) return;
6480
+ const newIndex = prevCol.cards.length;
6481
+ moveCard(cardId, grabbed.columnId, prevCol.id, newIndex);
6482
+ setGrabbed({ cardId, columnId: prevCol.id, cardIndex: newIndex });
6483
+ }
6484
+ } else if (e.key === "ArrowRight") {
6485
+ e.preventDefault();
6486
+ if (colIndex < columns.length - 1) {
6487
+ const nextCol = columns[colIndex + 1];
6488
+ if (!nextCol) return;
6489
+ const newIndex = nextCol.cards.length;
6490
+ moveCard(cardId, grabbed.columnId, nextCol.id, newIndex);
6491
+ setGrabbed({ cardId, columnId: nextCol.id, cardIndex: newIndex });
6492
+ }
6493
+ }
6494
+ }
6495
+ };
6496
+ return /* @__PURE__ */ jsxRuntime.jsxs("div", { id: baseId, role: "region", "aria-label": title ?? "Kanban Board", style: containerStyle9, children: [
6497
+ title && /* @__PURE__ */ jsxRuntime.jsx("div", { style: headerStyle8, children: title }),
6498
+ /* @__PURE__ */ jsxRuntime.jsx("div", { style: boardStyle, children: columns.map((col) => /* @__PURE__ */ jsxRuntime.jsxs("div", { style: columnStyle(false), children: [
6499
+ /* @__PURE__ */ jsxRuntime.jsxs("div", { style: columnHeaderStyle, children: [
6500
+ /* @__PURE__ */ jsxRuntime.jsx("span", { children: col.title }),
6501
+ /* @__PURE__ */ jsxRuntime.jsxs("span", { style: columnCountStyle, children: [
6502
+ String(col.cards.length),
6503
+ col.limit !== void 0 && /* @__PURE__ */ jsxRuntime.jsxs("span", { style: limitStyle, children: [
6504
+ " / ",
6505
+ String(col.limit)
6506
+ ] })
6507
+ ] })
6508
+ ] }),
6509
+ /* @__PURE__ */ jsxRuntime.jsx("div", { role: "list", "aria-label": col.title, children: col.cards.map((card, cardIndex) => {
6510
+ const isGrabbed = grabbed !== null && grabbed.cardId === card.id;
6511
+ return /* @__PURE__ */ jsxRuntime.jsxs(
6512
+ "div",
6513
+ {
6514
+ role: "listitem",
6515
+ "aria-grabbed": isGrabbed,
6516
+ "aria-label": `${card.title}${card.priority ? `, ${card.priority} priority` : ""}`,
6517
+ tabIndex: 0,
6518
+ style: cardStyle(isGrabbed, card.priority),
6519
+ onKeyDown: (e) => handleCardKeyDown(e, card.id, col.id, cardIndex),
6520
+ children: [
6521
+ /* @__PURE__ */ jsxRuntime.jsx("div", { style: cardTitleStyle, children: card.title }),
6522
+ card.description && /* @__PURE__ */ jsxRuntime.jsx("div", { style: cardDescStyle, children: card.description }),
6523
+ card.tags && card.tags.length > 0 && /* @__PURE__ */ jsxRuntime.jsx("div", { style: tagContainerStyle, children: card.tags.map((tag) => /* @__PURE__ */ jsxRuntime.jsx("span", { style: tagStyle, children: tag }, tag)) })
6524
+ ]
6525
+ },
6526
+ card.id
6527
+ );
6528
+ }) })
6529
+ ] }, col.id)) }),
6530
+ /* @__PURE__ */ jsxRuntime.jsx(
6531
+ "div",
6532
+ {
6533
+ "aria-live": "assertive",
6534
+ style: {
6535
+ position: "absolute",
6536
+ width: "1px",
6537
+ height: "1px",
6538
+ padding: 0,
6539
+ margin: "-1px",
6540
+ overflow: "hidden",
6541
+ clip: "rect(0,0,0,0)",
6542
+ whiteSpace: "nowrap",
6543
+ border: 0
6544
+ },
6545
+ children: grabbed !== null && `${columns.find((c) => c.id === grabbed.columnId)?.cards[grabbed.cardIndex]?.title ?? "Card"} grabbed in ${columns.find((c) => c.id === grabbed.columnId)?.title ?? "column"}. Use arrow keys to move.`
6546
+ }
6547
+ )
6548
+ ] });
6549
+ }
6550
+
6551
+ // src/kanban/index.ts
6552
+ var kanbanDefinition = {
6553
+ type: "ui:kanban",
6554
+ schema: schemas.kanbanSchema,
6555
+ render: Kanban
6556
+ };
6557
+
6558
+ // src/annotate/styles.ts
6559
+ var containerStyle10 = {
6560
+ fontFamily: "var(--glyph-font-body, system-ui, sans-serif)",
6561
+ color: "var(--glyph-text, #1a2035)",
6562
+ border: "1px solid var(--glyph-border, #d0d8e4)",
6563
+ borderRadius: "var(--glyph-radius-md, 0.5rem)",
6564
+ overflow: "hidden"
6565
+ };
6566
+ var headerStyle9 = {
6567
+ fontWeight: 700,
6568
+ fontSize: "1.125rem",
6569
+ padding: "var(--glyph-spacing-md, 1rem)",
6570
+ borderBottom: "1px solid var(--glyph-border, #d0d8e4)",
6571
+ color: "var(--glyph-heading, #0a0e1a)"
6572
+ };
6573
+ var bodyStyle2 = {
6574
+ display: "flex",
6575
+ minHeight: "200px"
6576
+ };
6577
+ var textPaneStyle = {
6578
+ flex: 1,
6579
+ padding: "var(--glyph-spacing-md, 1rem)",
6580
+ fontFamily: "var(--glyph-font-mono, ui-monospace, monospace)",
6581
+ fontSize: "0.8125rem",
6582
+ lineHeight: 1.8,
6583
+ whiteSpace: "pre-wrap",
6584
+ wordBreak: "break-word",
6585
+ position: "relative",
6586
+ cursor: "text"
6587
+ };
6588
+ var labelPickerStyle = {
6589
+ position: "absolute",
6590
+ zIndex: 10,
6591
+ background: "var(--glyph-surface-raised, #f4f6fa)",
6592
+ border: "1px solid var(--glyph-border, #d0d8e4)",
6593
+ borderRadius: "var(--glyph-radius-sm, 0.375rem)",
6594
+ boxShadow: "var(--glyph-shadow-md, 0 4px 12px rgba(0,0,0,0.15))",
6595
+ padding: "0.25rem 0",
6596
+ minWidth: "120px"
6597
+ };
6598
+ function labelOptionStyle() {
6599
+ return {
6600
+ display: "flex",
6601
+ alignItems: "center",
6602
+ gap: "0.5rem",
6603
+ padding: "0.375rem 0.75rem",
6604
+ cursor: "pointer",
6605
+ fontSize: "0.8125rem",
6606
+ background: "transparent",
6607
+ border: "none",
6608
+ width: "100%",
6609
+ textAlign: "left",
6610
+ color: "var(--glyph-text, #1a2035)"
6611
+ };
6612
+ }
6613
+ function colorDotStyle(color3) {
6614
+ return {
6615
+ width: "0.625rem",
6616
+ height: "0.625rem",
6617
+ borderRadius: "50%",
6618
+ background: color3,
6619
+ flexShrink: 0
6620
+ };
6621
+ }
6622
+ var sidebarStyle = {
6623
+ width: "220px",
6624
+ borderLeft: "1px solid var(--glyph-border, #d0d8e4)",
6625
+ background: "var(--glyph-annotate-sidebar-bg, var(--glyph-surface, #e8ecf3))",
6626
+ overflow: "auto"
6627
+ };
6628
+ var sidebarHeaderStyle = {
6629
+ fontWeight: 700,
6630
+ fontSize: "0.75rem",
6631
+ textTransform: "uppercase",
6632
+ letterSpacing: "0.5px",
6633
+ padding: "0.75rem",
6634
+ borderBottom: "1px solid var(--glyph-border, #d0d8e4)",
6635
+ color: "var(--glyph-text-muted, #6b7a94)"
6636
+ };
6637
+ function annotationItemStyle(color3) {
6638
+ return {
6639
+ padding: "0.5rem 0.75rem",
6640
+ borderBottom: "1px solid var(--glyph-border, #d0d8e4)",
6641
+ borderLeft: `3px solid ${color3}`,
6642
+ fontSize: "0.75rem"
6643
+ };
6644
+ }
6645
+ var annotationTextStyle = {
6646
+ fontFamily: "var(--glyph-font-mono, ui-monospace, monospace)",
6647
+ fontSize: "0.6875rem",
6648
+ color: "var(--glyph-text-muted, #6b7a94)",
6649
+ marginTop: "0.25rem",
6650
+ overflow: "hidden",
6651
+ textOverflow: "ellipsis",
6652
+ whiteSpace: "nowrap"
6653
+ };
6654
+ var annotationNoteStyle = {
6655
+ fontSize: "0.6875rem",
6656
+ fontStyle: "italic",
6657
+ color: "var(--glyph-text-muted, #6b7a94)",
6658
+ marginTop: "0.125rem"
6659
+ };
6660
+ function computeSegments(text, annotations) {
6661
+ if (annotations.length === 0) {
6662
+ return [{ text, start: 0, annotation: null }];
6663
+ }
6664
+ const sorted = [...annotations].sort((a, b) => a.start - b.start);
6665
+ const segments = [];
6666
+ let cursor = 0;
6667
+ for (const ann of sorted) {
6668
+ if (ann.start > cursor) {
6669
+ segments.push({ text: text.slice(cursor, ann.start), start: cursor, annotation: null });
6670
+ }
6671
+ segments.push({
6672
+ text: text.slice(ann.start, ann.end),
6673
+ start: ann.start,
6674
+ annotation: ann
6675
+ });
6676
+ cursor = ann.end;
6677
+ }
6678
+ if (cursor < text.length) {
6679
+ segments.push({ text: text.slice(cursor), start: cursor, annotation: null });
6680
+ }
6681
+ return segments;
6682
+ }
6683
+ function Annotate({
6684
+ data,
6685
+ block,
6686
+ onInteraction
6687
+ }) {
6688
+ const { title, labels, text } = data;
6689
+ const baseId = `glyph-annotate-${block.id}`;
6690
+ const [annotations, setAnnotations] = react.useState(data.annotations ?? []);
6691
+ const [pickerPos, setPickerPos] = react.useState(null);
6692
+ const [pendingSelection, setPendingSelection] = react.useState(null);
6693
+ const textRef = react.useRef(null);
6694
+ const handleMouseUp = react.useCallback(() => {
6695
+ const selection = window.getSelection();
6696
+ if (!selection || selection.isCollapsed || !textRef.current) return;
6697
+ const range = selection.getRangeAt(0);
6698
+ if (!range || !textRef.current.contains(range.commonAncestorContainer)) return;
6699
+ const selectedText = selection.toString();
6700
+ if (!selectedText.trim()) return;
6701
+ const preCaretRange = document.createRange();
6702
+ preCaretRange.selectNodeContents(textRef.current);
6703
+ preCaretRange.setEnd(range.startContainer, range.startOffset);
6704
+ const startOffset = preCaretRange.toString().length;
6705
+ const endOffset = startOffset + selectedText.length;
6706
+ const rect = range.getBoundingClientRect();
6707
+ const containerRect = textRef.current.getBoundingClientRect();
6708
+ setPendingSelection({ start: startOffset, end: endOffset, text: selectedText });
6709
+ setPickerPos({
6710
+ x: rect.left - containerRect.left,
6711
+ y: rect.bottom - containerRect.top + 4
6712
+ });
6713
+ }, []);
6714
+ const selectLabel = (labelName) => {
6715
+ if (!pendingSelection) return;
6716
+ const newAnnotation = {
6717
+ start: pendingSelection.start,
6718
+ end: pendingSelection.end,
6719
+ label: labelName
6720
+ };
6721
+ const newAnnotations = [...annotations, newAnnotation];
6722
+ setAnnotations(newAnnotations);
6723
+ setPickerPos(null);
6724
+ setPendingSelection(null);
6725
+ window.getSelection()?.removeAllRanges();
6726
+ if (onInteraction) {
6727
+ onInteraction({
6728
+ kind: "annotate-create",
6729
+ timestamp: (/* @__PURE__ */ new Date()).toISOString(),
6730
+ blockId: block.id,
6731
+ blockType: block.type,
6732
+ payload: {
6733
+ start: newAnnotation.start,
6734
+ end: newAnnotation.end,
6735
+ selectedText: pendingSelection.text,
6736
+ label: labelName,
6737
+ allAnnotations: newAnnotations.map((a) => ({
6738
+ start: a.start,
6739
+ end: a.end,
6740
+ text: text.slice(a.start, a.end),
6741
+ label: a.label
6742
+ }))
6743
+ }
6744
+ });
6745
+ }
6746
+ };
6747
+ const closePicker = (e) => {
6748
+ if (e.target.closest("[data-label-picker]")) return;
6749
+ setPickerPos(null);
6750
+ setPendingSelection(null);
6751
+ };
6752
+ const segments = computeSegments(text, annotations);
6753
+ const labelColorMap = new Map(labels.map((l) => [l.name, l.color]));
6754
+ return /* @__PURE__ */ jsxRuntime.jsxs(
6755
+ "div",
6756
+ {
6757
+ id: baseId,
6758
+ role: "region",
6759
+ "aria-label": title ?? "Annotate",
6760
+ style: containerStyle10,
6761
+ onClick: closePicker,
6762
+ children: [
6763
+ title && /* @__PURE__ */ jsxRuntime.jsx("div", { style: headerStyle9, children: title }),
6764
+ /* @__PURE__ */ jsxRuntime.jsxs("div", { style: bodyStyle2, children: [
6765
+ /* @__PURE__ */ jsxRuntime.jsxs("div", { ref: textRef, role: "document", style: textPaneStyle, onMouseUp: handleMouseUp, children: [
6766
+ segments.map((seg, i) => {
6767
+ if (seg.annotation) {
6768
+ const color3 = labelColorMap.get(seg.annotation.label) ?? "#888";
6769
+ return /* @__PURE__ */ jsxRuntime.jsx(
6770
+ "mark",
6771
+ {
6772
+ style: {
6773
+ backgroundColor: `${color3}33`,
6774
+ borderBottom: `2px solid ${color3}`,
6775
+ padding: "0 1px"
6776
+ },
6777
+ title: `${seg.annotation.label}${seg.annotation.note ? `: ${seg.annotation.note}` : ""}`,
6778
+ children: seg.text
6779
+ },
6780
+ i
6781
+ );
6782
+ }
6783
+ return /* @__PURE__ */ jsxRuntime.jsx("span", { children: seg.text }, i);
6784
+ }),
6785
+ pickerPos && /* @__PURE__ */ jsxRuntime.jsx(
6786
+ "div",
6787
+ {
6788
+ role: "menu",
6789
+ "data-label-picker": true,
6790
+ style: {
6791
+ ...labelPickerStyle,
6792
+ left: `${String(pickerPos.x)}px`,
6793
+ top: `${String(pickerPos.y)}px`
6794
+ },
6795
+ children: labels.map((label) => /* @__PURE__ */ jsxRuntime.jsxs(
6796
+ "button",
6797
+ {
6798
+ role: "menuitem",
6799
+ style: labelOptionStyle(),
6800
+ onClick: (e) => {
6801
+ e.stopPropagation();
6802
+ selectLabel(label.name);
6803
+ },
6804
+ children: [
6805
+ /* @__PURE__ */ jsxRuntime.jsx("span", { style: colorDotStyle(label.color) }),
6806
+ label.name
6807
+ ]
6808
+ },
6809
+ label.name
6810
+ ))
6811
+ }
6812
+ )
6813
+ ] }),
6814
+ /* @__PURE__ */ jsxRuntime.jsxs("div", { style: sidebarStyle, role: "complementary", "aria-label": "Annotations", children: [
6815
+ /* @__PURE__ */ jsxRuntime.jsxs("div", { style: sidebarHeaderStyle, children: [
6816
+ "Annotations (",
6817
+ String(annotations.length),
6818
+ ")"
6819
+ ] }),
6820
+ /* @__PURE__ */ jsxRuntime.jsxs("div", { role: "list", children: [
6821
+ annotations.map((ann, i) => {
6822
+ const color3 = labelColorMap.get(ann.label) ?? "#888";
6823
+ return /* @__PURE__ */ jsxRuntime.jsxs("div", { role: "listitem", style: annotationItemStyle(color3), children: [
6824
+ /* @__PURE__ */ jsxRuntime.jsxs("div", { style: { display: "flex", alignItems: "center", gap: "0.375rem" }, children: [
6825
+ /* @__PURE__ */ jsxRuntime.jsx("span", { style: colorDotStyle(color3) }),
6826
+ /* @__PURE__ */ jsxRuntime.jsx("strong", { style: { fontSize: "0.75rem" }, children: ann.label })
6827
+ ] }),
6828
+ /* @__PURE__ */ jsxRuntime.jsx("div", { style: annotationTextStyle, children: text.slice(ann.start, ann.end) }),
6829
+ ann.note && /* @__PURE__ */ jsxRuntime.jsx("div", { style: annotationNoteStyle, children: ann.note })
6830
+ ] }, i);
6831
+ }),
6832
+ annotations.length === 0 && /* @__PURE__ */ jsxRuntime.jsx(
6833
+ "div",
6834
+ {
6835
+ style: {
6836
+ padding: "0.75rem",
6837
+ fontSize: "0.75rem",
6838
+ color: "var(--glyph-text-muted, #6b7a94)"
6839
+ },
6840
+ children: "Select text to add annotations."
6841
+ }
6842
+ )
6843
+ ] })
6844
+ ] })
6845
+ ] })
6846
+ ]
6847
+ }
6848
+ );
6849
+ }
6850
+
6851
+ // src/annotate/index.ts
6852
+ var annotateDefinition = {
6853
+ type: "ui:annotate",
6854
+ schema: schemas.annotateSchema,
6855
+ render: Annotate
6856
+ };
6857
+
4878
6858
  exports.Accordion = Accordion;
6859
+ exports.Annotate = Annotate;
4879
6860
  exports.Architecture = Architecture;
4880
6861
  exports.Callout = Callout;
4881
6862
  exports.Card = Card;
@@ -4885,18 +6866,26 @@ exports.Comparison = Comparison;
4885
6866
  exports.Equation = Equation;
4886
6867
  exports.FileTree = FileTree;
4887
6868
  exports.Flowchart = Flowchart;
6869
+ exports.Form = Form;
4888
6870
  exports.Graph = Graph;
4889
6871
  exports.Infographic = Infographic;
6872
+ exports.Kanban = Kanban;
4890
6873
  exports.Kpi = Kpi;
6874
+ exports.Matrix = Matrix;
4891
6875
  exports.MindMap = MindMap;
6876
+ exports.Poll = Poll;
4892
6877
  exports.Quiz = Quiz;
6878
+ exports.Ranker = Ranker;
6879
+ exports.Rating = Rating;
4893
6880
  exports.Relation = Relation;
4894
6881
  exports.Sequence = Sequence;
6882
+ exports.Slider = Slider;
4895
6883
  exports.Steps = Steps;
4896
6884
  exports.Table = Table;
4897
6885
  exports.Tabs = Tabs;
4898
6886
  exports.Timeline = Timeline;
4899
6887
  exports.accordionDefinition = accordionDefinition;
6888
+ exports.annotateDefinition = annotateDefinition;
4900
6889
  exports.architectureDefinition = architectureDefinition;
4901
6890
  exports.calloutDefinition = calloutDefinition;
4902
6891
  exports.cardDefinition = cardDefinition;
@@ -4910,13 +6899,20 @@ exports.computeForceLayout = computeForceLayout;
4910
6899
  exports.equationDefinition = equationDefinition;
4911
6900
  exports.fileTreeDefinition = fileTreeDefinition;
4912
6901
  exports.flowchartDefinition = flowchartDefinition;
6902
+ exports.formDefinition = formDefinition;
4913
6903
  exports.graphDefinition = graphDefinition;
4914
6904
  exports.infographicDefinition = infographicDefinition;
6905
+ exports.kanbanDefinition = kanbanDefinition;
4915
6906
  exports.kpiDefinition = kpiDefinition;
6907
+ exports.matrixDefinition = matrixDefinition;
4916
6908
  exports.mindMapDefinition = mindMapDefinition;
6909
+ exports.pollDefinition = pollDefinition;
4917
6910
  exports.quizDefinition = quizDefinition;
6911
+ exports.rankerDefinition = rankerDefinition;
6912
+ exports.ratingDefinition = ratingDefinition;
4918
6913
  exports.relationDefinition = relationDefinition;
4919
6914
  exports.sequenceDefinition = sequenceDefinition;
6915
+ exports.sliderDefinition = sliderDefinition;
4920
6916
  exports.stepsDefinition = stepsDefinition;
4921
6917
  exports.tableDefinition = tableDefinition;
4922
6918
  exports.tabsDefinition = tabsDefinition;