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