@glyphjs/components 0.1.0 → 0.2.0
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/dist/index.cjs +2347 -351
- package/dist/index.cjs.map +1 -1
- package/dist/index.d.cts +184 -11
- package/dist/index.d.ts +184 -11
- package/dist/index.js +2333 -353
- package/dist/index.js.map +1 -1
- package/package.json +4 -4
package/dist/index.js
CHANGED
|
@@ -1,4 +1,4 @@
|
|
|
1
|
-
import { accordionSchema, architectureSchema, calloutSchema, cardSchema, chartSchema, codediffSchema, comparisonSchema, equationSchema, filetreeSchema, flowchartSchema, graphSchema, infographicSchema, kpiSchema, mindmapSchema, quizSchema, relationSchema, sequenceSchema, stepsSchema, tableSchema, tabsSchema, timelineSchema } from '@glyphjs/schemas';
|
|
1
|
+
import { accordionSchema, annotateSchema, architectureSchema, calloutSchema, cardSchema, chartSchema, codediffSchema, comparisonSchema, equationSchema, filetreeSchema, flowchartSchema, formSchema, graphSchema, infographicSchema, kanbanSchema, kpiSchema, matrixSchema, mindmapSchema, pollSchema, quizSchema, rankerSchema, ratingSchema, relationSchema, sequenceSchema, sliderSchema, stepsSchema, tableSchema, tabsSchema, timelineSchema } from '@glyphjs/schemas';
|
|
2
2
|
import { jsxs, jsx } from 'react/jsx-runtime';
|
|
3
3
|
import { useRef, useState, useEffect, useCallback, useMemo } from 'react';
|
|
4
4
|
import * as d32 from 'd3';
|
|
@@ -21,7 +21,7 @@ var CALLOUT_LABELS = {
|
|
|
21
21
|
};
|
|
22
22
|
function Callout({ data }) {
|
|
23
23
|
const { type, title, content } = data;
|
|
24
|
-
const
|
|
24
|
+
const containerStyle11 = {
|
|
25
25
|
backgroundColor: `var(--glyph-callout-${type}-bg)`,
|
|
26
26
|
borderLeft: `4px solid var(--glyph-callout-${type}-border)`,
|
|
27
27
|
borderRadius: "var(--glyph-radius-md, 0.1875rem)",
|
|
@@ -38,7 +38,7 @@ function Callout({ data }) {
|
|
|
38
38
|
fontSize: "1.25em",
|
|
39
39
|
lineHeight: 1
|
|
40
40
|
};
|
|
41
|
-
const
|
|
41
|
+
const bodyStyle3 = {
|
|
42
42
|
flex: 1,
|
|
43
43
|
minWidth: 0
|
|
44
44
|
};
|
|
@@ -46,9 +46,9 @@ function Callout({ data }) {
|
|
|
46
46
|
fontWeight: 700,
|
|
47
47
|
marginBottom: "var(--glyph-spacing-xs, 0.25rem)"
|
|
48
48
|
};
|
|
49
|
-
return /* @__PURE__ */ jsxs("div", { role: "note", "aria-label": CALLOUT_LABELS[type], style:
|
|
49
|
+
return /* @__PURE__ */ jsxs("div", { role: "note", "aria-label": CALLOUT_LABELS[type], style: containerStyle11, children: [
|
|
50
50
|
/* @__PURE__ */ jsx("span", { style: iconStyle, "aria-hidden": "true", children: CALLOUT_ICONS[type] }),
|
|
51
|
-
/* @__PURE__ */ jsxs("div", { style:
|
|
51
|
+
/* @__PURE__ */ jsxs("div", { style: bodyStyle3, children: [
|
|
52
52
|
title && /* @__PURE__ */ jsx("div", { style: titleStyle2, children: title }),
|
|
53
53
|
/* @__PURE__ */ jsx("div", { children: content })
|
|
54
54
|
] })
|
|
@@ -253,9 +253,104 @@ function computeScales(width, height, type, series, xKey, yKey, margin) {
|
|
|
253
253
|
const yScale = d32.scaleLinear().domain([yMin, yMax]).nice().range([innerHeight, 0]);
|
|
254
254
|
return { xScale, xScalePoint, yScale, innerWidth, innerHeight };
|
|
255
255
|
}
|
|
256
|
+
function renderAllSeries(g, type, series, scales, xKey, yKey, showTooltip, hideTooltip) {
|
|
257
|
+
const { xScale, xScalePoint, yScale, innerHeight } = scales;
|
|
258
|
+
series.forEach((s, i) => {
|
|
259
|
+
const color3 = COLOR_SCHEME[i % COLOR_SCHEME.length] ?? "#333";
|
|
260
|
+
switch (type) {
|
|
261
|
+
case "line":
|
|
262
|
+
renderLineSeries(
|
|
263
|
+
g,
|
|
264
|
+
s.data,
|
|
265
|
+
xScalePoint,
|
|
266
|
+
yScale,
|
|
267
|
+
yKey,
|
|
268
|
+
xKey,
|
|
269
|
+
color3,
|
|
270
|
+
i,
|
|
271
|
+
s.name,
|
|
272
|
+
showTooltip,
|
|
273
|
+
hideTooltip
|
|
274
|
+
);
|
|
275
|
+
break;
|
|
276
|
+
case "area":
|
|
277
|
+
renderAreaSeries(
|
|
278
|
+
g,
|
|
279
|
+
s.data,
|
|
280
|
+
xScalePoint,
|
|
281
|
+
yScale,
|
|
282
|
+
yKey,
|
|
283
|
+
xKey,
|
|
284
|
+
innerHeight,
|
|
285
|
+
color3,
|
|
286
|
+
i,
|
|
287
|
+
s.name,
|
|
288
|
+
showTooltip,
|
|
289
|
+
hideTooltip
|
|
290
|
+
);
|
|
291
|
+
break;
|
|
292
|
+
case "bar":
|
|
293
|
+
renderBarSeries(
|
|
294
|
+
g,
|
|
295
|
+
s.data,
|
|
296
|
+
xScale,
|
|
297
|
+
yScale,
|
|
298
|
+
yKey,
|
|
299
|
+
xKey,
|
|
300
|
+
color3,
|
|
301
|
+
i,
|
|
302
|
+
series.length,
|
|
303
|
+
innerHeight,
|
|
304
|
+
s.name,
|
|
305
|
+
showTooltip,
|
|
306
|
+
hideTooltip
|
|
307
|
+
);
|
|
308
|
+
break;
|
|
309
|
+
case "ohlc":
|
|
310
|
+
renderOHLCSeries(
|
|
311
|
+
g,
|
|
312
|
+
s.data,
|
|
313
|
+
xScale,
|
|
314
|
+
xScalePoint,
|
|
315
|
+
yScale,
|
|
316
|
+
scales.innerWidth,
|
|
317
|
+
s.name,
|
|
318
|
+
showTooltip,
|
|
319
|
+
hideTooltip
|
|
320
|
+
);
|
|
321
|
+
break;
|
|
322
|
+
}
|
|
323
|
+
});
|
|
324
|
+
}
|
|
325
|
+
function attachChartInteraction(g, type, series, xKey, yKey, block, onInteraction) {
|
|
326
|
+
if (!onInteraction) return;
|
|
327
|
+
series.forEach((s, seriesIdx) => {
|
|
328
|
+
const className = type === "bar" ? `bar-${String(seriesIdx)}` : `dot-${String(seriesIdx)}`;
|
|
329
|
+
g.selectAll(`.${className}`).on(
|
|
330
|
+
"click",
|
|
331
|
+
(_event, d) => {
|
|
332
|
+
const dataIdx = s.data.indexOf(d);
|
|
333
|
+
onInteraction({
|
|
334
|
+
kind: "chart-select",
|
|
335
|
+
timestamp: (/* @__PURE__ */ new Date()).toISOString(),
|
|
336
|
+
blockId: block.id,
|
|
337
|
+
blockType: block.type,
|
|
338
|
+
payload: {
|
|
339
|
+
seriesIndex: seriesIdx,
|
|
340
|
+
dataIndex: dataIdx >= 0 ? dataIdx : 0,
|
|
341
|
+
label: String(d[xKey] ?? ""),
|
|
342
|
+
value: getNumericValue(d, yKey)
|
|
343
|
+
}
|
|
344
|
+
});
|
|
345
|
+
}
|
|
346
|
+
);
|
|
347
|
+
});
|
|
348
|
+
}
|
|
256
349
|
function Chart({
|
|
257
350
|
data,
|
|
258
|
-
|
|
351
|
+
block,
|
|
352
|
+
container: containerCtx,
|
|
353
|
+
onInteraction
|
|
259
354
|
}) {
|
|
260
355
|
const containerRef = useRef(null);
|
|
261
356
|
const svgRef = useRef(null);
|
|
@@ -308,76 +403,19 @@ function Chart({
|
|
|
308
403
|
if (!svg || series.length === 0) return;
|
|
309
404
|
const sel = d32.select(svg);
|
|
310
405
|
sel.selectAll("*").remove();
|
|
311
|
-
const { xScale, xScalePoint, yScale, innerWidth, innerHeight } = scales;
|
|
312
406
|
const g = sel.append("g").attr("transform", `translate(${String(margin.left)},${String(margin.top)})`);
|
|
313
|
-
renderAxes(
|
|
314
|
-
|
|
315
|
-
|
|
316
|
-
|
|
317
|
-
|
|
318
|
-
|
|
319
|
-
|
|
320
|
-
|
|
321
|
-
|
|
322
|
-
|
|
323
|
-
|
|
324
|
-
|
|
325
|
-
xKey,
|
|
326
|
-
color3,
|
|
327
|
-
i,
|
|
328
|
-
s.name,
|
|
329
|
-
showTooltip,
|
|
330
|
-
hideTooltip
|
|
331
|
-
);
|
|
332
|
-
break;
|
|
333
|
-
case "area":
|
|
334
|
-
renderAreaSeries(
|
|
335
|
-
g,
|
|
336
|
-
s.data,
|
|
337
|
-
xScalePoint,
|
|
338
|
-
yScale,
|
|
339
|
-
yKey,
|
|
340
|
-
xKey,
|
|
341
|
-
innerHeight,
|
|
342
|
-
color3,
|
|
343
|
-
i,
|
|
344
|
-
s.name,
|
|
345
|
-
showTooltip,
|
|
346
|
-
hideTooltip
|
|
347
|
-
);
|
|
348
|
-
break;
|
|
349
|
-
case "bar":
|
|
350
|
-
renderBarSeries(
|
|
351
|
-
g,
|
|
352
|
-
s.data,
|
|
353
|
-
xScale,
|
|
354
|
-
yScale,
|
|
355
|
-
yKey,
|
|
356
|
-
xKey,
|
|
357
|
-
color3,
|
|
358
|
-
i,
|
|
359
|
-
series.length,
|
|
360
|
-
innerHeight,
|
|
361
|
-
s.name,
|
|
362
|
-
showTooltip,
|
|
363
|
-
hideTooltip
|
|
364
|
-
);
|
|
365
|
-
break;
|
|
366
|
-
case "ohlc":
|
|
367
|
-
renderOHLCSeries(
|
|
368
|
-
g,
|
|
369
|
-
s.data,
|
|
370
|
-
xScale,
|
|
371
|
-
xScalePoint,
|
|
372
|
-
yScale,
|
|
373
|
-
innerWidth,
|
|
374
|
-
s.name,
|
|
375
|
-
showTooltip,
|
|
376
|
-
hideTooltip
|
|
377
|
-
);
|
|
378
|
-
break;
|
|
379
|
-
}
|
|
380
|
-
});
|
|
407
|
+
renderAxes(
|
|
408
|
+
g,
|
|
409
|
+
scales.xScale,
|
|
410
|
+
scales.yScale,
|
|
411
|
+
xAxis,
|
|
412
|
+
yAxis,
|
|
413
|
+
scales.innerWidth,
|
|
414
|
+
scales.innerHeight
|
|
415
|
+
);
|
|
416
|
+
renderGridLines(g, scales.yScale, scales.innerWidth);
|
|
417
|
+
renderAllSeries(g, type, series, scales, xKey, yKey, showTooltip, hideTooltip);
|
|
418
|
+
attachChartInteraction(g, type, series, xKey, yKey, block, onInteraction);
|
|
381
419
|
if (legend) {
|
|
382
420
|
renderLegend(sel, series, margin.left, margin.top, isCompact ? "10px" : void 0);
|
|
383
421
|
}
|
|
@@ -393,7 +431,9 @@ function Chart({
|
|
|
393
431
|
margin,
|
|
394
432
|
isCompact,
|
|
395
433
|
showTooltip,
|
|
396
|
-
hideTooltip
|
|
434
|
+
hideTooltip,
|
|
435
|
+
onInteraction,
|
|
436
|
+
block
|
|
397
437
|
]);
|
|
398
438
|
const ariaLabel = `${type} chart with ${String(series.length)} series: ${series.map((s) => s.name).join(", ")}`;
|
|
399
439
|
return /* @__PURE__ */ jsxs(
|
|
@@ -467,14 +507,14 @@ var STATUS_LABELS = {
|
|
|
467
507
|
};
|
|
468
508
|
function Steps({ data }) {
|
|
469
509
|
const { steps } = data;
|
|
470
|
-
const
|
|
510
|
+
const listStyle2 = {
|
|
471
511
|
listStyle: "none",
|
|
472
512
|
padding: 0,
|
|
473
513
|
margin: "var(--glyph-spacing-sm, 0.5rem) 0",
|
|
474
514
|
fontFamily: "var(--glyph-font-body, system-ui, sans-serif)",
|
|
475
515
|
color: "var(--glyph-text, #1a2035)"
|
|
476
516
|
};
|
|
477
|
-
return /* @__PURE__ */ jsx("ol", { role: "list", style:
|
|
517
|
+
return /* @__PURE__ */ jsx("ol", { role: "list", style: listStyle2, children: steps.map((step, index) => {
|
|
478
518
|
const status = step.status ?? "pending";
|
|
479
519
|
const isLast = index === steps.length - 1;
|
|
480
520
|
return /* @__PURE__ */ jsxs(
|
|
@@ -621,7 +661,95 @@ function TableAggregationFooter({
|
|
|
621
661
|
);
|
|
622
662
|
}) }) });
|
|
623
663
|
}
|
|
624
|
-
function
|
|
664
|
+
function TableHead({
|
|
665
|
+
columns,
|
|
666
|
+
sort,
|
|
667
|
+
hasFilters,
|
|
668
|
+
filters,
|
|
669
|
+
onSort,
|
|
670
|
+
onHeaderKeyDown,
|
|
671
|
+
onFilterChange
|
|
672
|
+
}) {
|
|
673
|
+
return /* @__PURE__ */ jsxs("thead", { children: [
|
|
674
|
+
/* @__PURE__ */ jsx("tr", { children: columns.map((col) => {
|
|
675
|
+
const isSorted = sort.column === col.key;
|
|
676
|
+
const direction = isSorted ? sort.direction : "none";
|
|
677
|
+
return /* @__PURE__ */ jsxs(
|
|
678
|
+
"th",
|
|
679
|
+
{
|
|
680
|
+
scope: "col",
|
|
681
|
+
"aria-sort": col.sortable ? direction : void 0,
|
|
682
|
+
tabIndex: col.sortable ? 0 : void 0,
|
|
683
|
+
role: col.sortable ? "columnheader" : void 0,
|
|
684
|
+
onClick: col.sortable ? () => onSort(col.key) : void 0,
|
|
685
|
+
onKeyDown: col.sortable ? (e) => onHeaderKeyDown(e, col.key) : void 0,
|
|
686
|
+
style: {
|
|
687
|
+
padding: "var(--glyph-table-cell-padding, 8px 12px)",
|
|
688
|
+
textAlign: "left",
|
|
689
|
+
borderBottom: "2px solid var(--glyph-table-border, #d0d8e4)",
|
|
690
|
+
background: "var(--glyph-table-header-bg, #e8ecf3)",
|
|
691
|
+
color: "var(--glyph-table-header-color, inherit)",
|
|
692
|
+
cursor: col.sortable ? "pointer" : "default",
|
|
693
|
+
userSelect: col.sortable ? "none" : void 0,
|
|
694
|
+
whiteSpace: "nowrap"
|
|
695
|
+
},
|
|
696
|
+
children: [
|
|
697
|
+
col.label,
|
|
698
|
+
col.sortable ? sortIndicator(direction) : ""
|
|
699
|
+
]
|
|
700
|
+
},
|
|
701
|
+
col.key
|
|
702
|
+
);
|
|
703
|
+
}) }),
|
|
704
|
+
hasFilters && /* @__PURE__ */ jsx("tr", { children: columns.map((col) => /* @__PURE__ */ jsx(
|
|
705
|
+
"th",
|
|
706
|
+
{
|
|
707
|
+
scope: "col",
|
|
708
|
+
style: { padding: "4px 8px", fontWeight: "normal" },
|
|
709
|
+
children: col.filterable ? /* @__PURE__ */ jsx(
|
|
710
|
+
"input",
|
|
711
|
+
{
|
|
712
|
+
type: "text",
|
|
713
|
+
"aria-label": `Filter ${col.label}`,
|
|
714
|
+
placeholder: `Filter ${col.label}...`,
|
|
715
|
+
value: filters[col.key] ?? "",
|
|
716
|
+
onChange: (e) => onFilterChange(col.key, e.target.value),
|
|
717
|
+
style: {
|
|
718
|
+
width: "100%",
|
|
719
|
+
padding: "4px 6px",
|
|
720
|
+
border: "1px solid var(--glyph-table-border, #d0d8e4)",
|
|
721
|
+
borderRadius: "3px",
|
|
722
|
+
fontSize: "inherit",
|
|
723
|
+
boxSizing: "border-box",
|
|
724
|
+
background: "var(--glyph-surface, #e8ecf3)",
|
|
725
|
+
color: "var(--glyph-text, inherit)"
|
|
726
|
+
}
|
|
727
|
+
}
|
|
728
|
+
) : /* @__PURE__ */ jsx(
|
|
729
|
+
"span",
|
|
730
|
+
{
|
|
731
|
+
style: {
|
|
732
|
+
position: "absolute",
|
|
733
|
+
width: "1px",
|
|
734
|
+
height: "1px",
|
|
735
|
+
overflow: "hidden",
|
|
736
|
+
clip: "rect(0,0,0,0)",
|
|
737
|
+
whiteSpace: "nowrap"
|
|
738
|
+
},
|
|
739
|
+
children: `No filter for ${col.label}`
|
|
740
|
+
}
|
|
741
|
+
)
|
|
742
|
+
},
|
|
743
|
+
`filter-${col.key}`
|
|
744
|
+
)) })
|
|
745
|
+
] });
|
|
746
|
+
}
|
|
747
|
+
function Table({
|
|
748
|
+
data,
|
|
749
|
+
block,
|
|
750
|
+
container,
|
|
751
|
+
onInteraction
|
|
752
|
+
}) {
|
|
625
753
|
const { columns, rows, aggregation } = data;
|
|
626
754
|
const [sort, setSort] = useState({ column: "", direction: "none" });
|
|
627
755
|
const [filters, setFilters] = useState({});
|
|
@@ -654,12 +782,27 @@ function Table({ data, container }) {
|
|
|
654
782
|
});
|
|
655
783
|
}, [filteredRows, sort]);
|
|
656
784
|
const handleSort = (columnKey) => {
|
|
657
|
-
|
|
658
|
-
|
|
659
|
-
|
|
660
|
-
|
|
661
|
-
|
|
662
|
-
|
|
785
|
+
const newDirection = sort.column === columnKey ? nextDirection(sort.direction) : "ascending";
|
|
786
|
+
setSort({ column: columnKey, direction: newDirection });
|
|
787
|
+
if (onInteraction) {
|
|
788
|
+
const eventDir = newDirection === "ascending" ? "asc" : newDirection === "descending" ? "desc" : "none";
|
|
789
|
+
onInteraction({
|
|
790
|
+
kind: "table-sort",
|
|
791
|
+
timestamp: (/* @__PURE__ */ new Date()).toISOString(),
|
|
792
|
+
blockId: block.id,
|
|
793
|
+
blockType: block.type,
|
|
794
|
+
payload: {
|
|
795
|
+
column: columnKey,
|
|
796
|
+
direction: eventDir,
|
|
797
|
+
state: {
|
|
798
|
+
sort: newDirection === "none" ? null : { column: columnKey, direction: eventDir },
|
|
799
|
+
filters,
|
|
800
|
+
visibleRowCount: filteredRows.length,
|
|
801
|
+
totalRowCount: rows.length
|
|
802
|
+
}
|
|
803
|
+
}
|
|
804
|
+
});
|
|
805
|
+
}
|
|
663
806
|
};
|
|
664
807
|
const handleHeaderKeyDown = (e, columnKey) => {
|
|
665
808
|
if (e.key === "Enter" || e.key === " ") {
|
|
@@ -668,7 +811,38 @@ function Table({ data, container }) {
|
|
|
668
811
|
}
|
|
669
812
|
};
|
|
670
813
|
const handleFilterChange = (columnKey, value) => {
|
|
671
|
-
|
|
814
|
+
const newFilters = { ...filters, [columnKey]: value };
|
|
815
|
+
setFilters(newFilters);
|
|
816
|
+
if (onInteraction) {
|
|
817
|
+
const newVisibleCount = rows.filter(
|
|
818
|
+
(row) => columns.every((col) => {
|
|
819
|
+
if (!col.filterable) return true;
|
|
820
|
+
const fv = newFilters[col.key];
|
|
821
|
+
if (!fv) return true;
|
|
822
|
+
return String(row[col.key] ?? "").toLowerCase().includes(fv.toLowerCase());
|
|
823
|
+
})
|
|
824
|
+
).length;
|
|
825
|
+
const eventSort = sort.direction === "none" || !sort.column ? null : {
|
|
826
|
+
column: sort.column,
|
|
827
|
+
direction: sort.direction === "ascending" ? "asc" : "desc"
|
|
828
|
+
};
|
|
829
|
+
onInteraction({
|
|
830
|
+
kind: "table-filter",
|
|
831
|
+
timestamp: (/* @__PURE__ */ new Date()).toISOString(),
|
|
832
|
+
blockId: block.id,
|
|
833
|
+
blockType: block.type,
|
|
834
|
+
payload: {
|
|
835
|
+
column: columnKey,
|
|
836
|
+
value,
|
|
837
|
+
state: {
|
|
838
|
+
sort: eventSort,
|
|
839
|
+
filters: newFilters,
|
|
840
|
+
visibleRowCount: newVisibleCount,
|
|
841
|
+
totalRowCount: rows.length
|
|
842
|
+
}
|
|
843
|
+
}
|
|
844
|
+
});
|
|
845
|
+
}
|
|
672
846
|
};
|
|
673
847
|
const hasFilters = columns.some((c) => c.filterable);
|
|
674
848
|
const aggMap = useMemo(() => {
|
|
@@ -692,79 +866,18 @@ function Table({ data, container }) {
|
|
|
692
866
|
fontSize: isCompact ? "0.8125rem" : "var(--glyph-table-font-size, 0.9rem)"
|
|
693
867
|
},
|
|
694
868
|
children: [
|
|
695
|
-
/* @__PURE__ */
|
|
696
|
-
|
|
697
|
-
|
|
698
|
-
|
|
699
|
-
|
|
700
|
-
|
|
701
|
-
|
|
702
|
-
|
|
703
|
-
|
|
704
|
-
|
|
705
|
-
|
|
706
|
-
|
|
707
|
-
onKeyDown: col.sortable ? (e) => handleHeaderKeyDown(e, col.key) : void 0,
|
|
708
|
-
style: {
|
|
709
|
-
padding: "var(--glyph-table-cell-padding, 8px 12px)",
|
|
710
|
-
textAlign: "left",
|
|
711
|
-
borderBottom: "2px solid var(--glyph-table-border, #d0d8e4)",
|
|
712
|
-
background: "var(--glyph-table-header-bg, #e8ecf3)",
|
|
713
|
-
color: "var(--glyph-table-header-color, inherit)",
|
|
714
|
-
cursor: col.sortable ? "pointer" : "default",
|
|
715
|
-
userSelect: col.sortable ? "none" : void 0,
|
|
716
|
-
whiteSpace: "nowrap"
|
|
717
|
-
},
|
|
718
|
-
children: [
|
|
719
|
-
col.label,
|
|
720
|
-
col.sortable ? sortIndicator(direction) : ""
|
|
721
|
-
]
|
|
722
|
-
},
|
|
723
|
-
col.key
|
|
724
|
-
);
|
|
725
|
-
}) }),
|
|
726
|
-
hasFilters && /* @__PURE__ */ jsx("tr", { children: columns.map((col) => /* @__PURE__ */ jsx(
|
|
727
|
-
"th",
|
|
728
|
-
{
|
|
729
|
-
scope: "col",
|
|
730
|
-
style: { padding: "4px 8px", fontWeight: "normal" },
|
|
731
|
-
children: col.filterable ? /* @__PURE__ */ jsx(
|
|
732
|
-
"input",
|
|
733
|
-
{
|
|
734
|
-
type: "text",
|
|
735
|
-
"aria-label": `Filter ${col.label}`,
|
|
736
|
-
placeholder: `Filter ${col.label}...`,
|
|
737
|
-
value: filters[col.key] ?? "",
|
|
738
|
-
onChange: (e) => handleFilterChange(col.key, e.target.value),
|
|
739
|
-
style: {
|
|
740
|
-
width: "100%",
|
|
741
|
-
padding: "4px 6px",
|
|
742
|
-
border: "1px solid var(--glyph-table-border, #d0d8e4)",
|
|
743
|
-
borderRadius: "3px",
|
|
744
|
-
fontSize: "inherit",
|
|
745
|
-
boxSizing: "border-box",
|
|
746
|
-
background: "var(--glyph-surface, #e8ecf3)",
|
|
747
|
-
color: "var(--glyph-text, inherit)"
|
|
748
|
-
}
|
|
749
|
-
}
|
|
750
|
-
) : /* @__PURE__ */ jsx(
|
|
751
|
-
"span",
|
|
752
|
-
{
|
|
753
|
-
style: {
|
|
754
|
-
position: "absolute",
|
|
755
|
-
width: "1px",
|
|
756
|
-
height: "1px",
|
|
757
|
-
overflow: "hidden",
|
|
758
|
-
clip: "rect(0,0,0,0)",
|
|
759
|
-
whiteSpace: "nowrap"
|
|
760
|
-
},
|
|
761
|
-
children: `No filter for ${col.label}`
|
|
762
|
-
}
|
|
763
|
-
)
|
|
764
|
-
},
|
|
765
|
-
`filter-${col.key}`
|
|
766
|
-
)) })
|
|
767
|
-
] }),
|
|
869
|
+
/* @__PURE__ */ jsx(
|
|
870
|
+
TableHead,
|
|
871
|
+
{
|
|
872
|
+
columns,
|
|
873
|
+
sort,
|
|
874
|
+
hasFilters,
|
|
875
|
+
filters,
|
|
876
|
+
onSort: handleSort,
|
|
877
|
+
onHeaderKeyDown: handleHeaderKeyDown,
|
|
878
|
+
onFilterChange: handleFilterChange
|
|
879
|
+
}
|
|
880
|
+
),
|
|
768
881
|
/* @__PURE__ */ jsx("tbody", { children: sortedRows.map((row, rowIdx) => /* @__PURE__ */ jsx(
|
|
769
882
|
"tr",
|
|
770
883
|
{
|
|
@@ -802,18 +915,28 @@ var tableDefinition = {
|
|
|
802
915
|
schema: tableSchema,
|
|
803
916
|
render: Table
|
|
804
917
|
};
|
|
805
|
-
function Tabs({ data, block }) {
|
|
918
|
+
function Tabs({ data, block, onInteraction }) {
|
|
806
919
|
const [activeIndex, setActiveIndex] = useState(0);
|
|
807
920
|
const tabRefs = useRef([]);
|
|
808
921
|
const tabs = data.tabs;
|
|
809
922
|
const baseId = `glyph-tabs-${block.id}`;
|
|
810
|
-
const
|
|
923
|
+
const selectTab = useCallback(
|
|
811
924
|
(index) => {
|
|
812
925
|
const clampedIndex = Math.max(0, Math.min(index, tabs.length - 1));
|
|
813
926
|
setActiveIndex(clampedIndex);
|
|
814
927
|
tabRefs.current[clampedIndex]?.focus();
|
|
928
|
+
const tab = tabs[clampedIndex];
|
|
929
|
+
if (tab) {
|
|
930
|
+
onInteraction?.({
|
|
931
|
+
kind: "tab-select",
|
|
932
|
+
timestamp: (/* @__PURE__ */ new Date()).toISOString(),
|
|
933
|
+
blockId: block.id,
|
|
934
|
+
blockType: block.type,
|
|
935
|
+
payload: { tabIndex: clampedIndex, tabLabel: tab.label }
|
|
936
|
+
});
|
|
937
|
+
}
|
|
815
938
|
},
|
|
816
|
-
[tabs.
|
|
939
|
+
[tabs, block.id, block.type, onInteraction]
|
|
817
940
|
);
|
|
818
941
|
const handleKeyDown = useCallback(
|
|
819
942
|
(e) => {
|
|
@@ -821,28 +944,28 @@ function Tabs({ data, block }) {
|
|
|
821
944
|
case "ArrowRight": {
|
|
822
945
|
e.preventDefault();
|
|
823
946
|
const next = (activeIndex + 1) % tabs.length;
|
|
824
|
-
|
|
947
|
+
selectTab(next);
|
|
825
948
|
break;
|
|
826
949
|
}
|
|
827
950
|
case "ArrowLeft": {
|
|
828
951
|
e.preventDefault();
|
|
829
952
|
const prev = (activeIndex - 1 + tabs.length) % tabs.length;
|
|
830
|
-
|
|
953
|
+
selectTab(prev);
|
|
831
954
|
break;
|
|
832
955
|
}
|
|
833
956
|
case "Home": {
|
|
834
957
|
e.preventDefault();
|
|
835
|
-
|
|
958
|
+
selectTab(0);
|
|
836
959
|
break;
|
|
837
960
|
}
|
|
838
961
|
case "End": {
|
|
839
962
|
e.preventDefault();
|
|
840
|
-
|
|
963
|
+
selectTab(tabs.length - 1);
|
|
841
964
|
break;
|
|
842
965
|
}
|
|
843
966
|
}
|
|
844
967
|
},
|
|
845
|
-
[activeIndex,
|
|
968
|
+
[activeIndex, selectTab, tabs.length]
|
|
846
969
|
);
|
|
847
970
|
return /* @__PURE__ */ jsxs(
|
|
848
971
|
"div",
|
|
@@ -881,7 +1004,7 @@ function Tabs({ data, block }) {
|
|
|
881
1004
|
"aria-selected": isActive,
|
|
882
1005
|
"aria-controls": panelId,
|
|
883
1006
|
tabIndex: isActive ? 0 : -1,
|
|
884
|
-
onClick: () =>
|
|
1007
|
+
onClick: () => selectTab(index),
|
|
885
1008
|
onKeyDown: handleKeyDown,
|
|
886
1009
|
style: {
|
|
887
1010
|
padding: "10px 18px",
|
|
@@ -993,7 +1116,7 @@ function Timeline({ data }) {
|
|
|
993
1116
|
position: dates.length === 1 ? totalLength / 2 : timeScale(e._parsed),
|
|
994
1117
|
side: isVertical ? i % 2 === 0 ? "left" : "right" : i % 2 === 0 ? "top" : "bottom"
|
|
995
1118
|
}));
|
|
996
|
-
const
|
|
1119
|
+
const containerStyle11 = {
|
|
997
1120
|
position: "relative",
|
|
998
1121
|
fontFamily: "var(--glyph-font-body, system-ui, sans-serif)",
|
|
999
1122
|
color: "var(--glyph-text, #1a2035)",
|
|
@@ -1020,7 +1143,7 @@ function Timeline({ data }) {
|
|
|
1020
1143
|
"div",
|
|
1021
1144
|
{
|
|
1022
1145
|
ref: containerRef,
|
|
1023
|
-
style:
|
|
1146
|
+
style: containerStyle11,
|
|
1024
1147
|
role: "img",
|
|
1025
1148
|
"aria-label": `Timeline with ${events.length} events`,
|
|
1026
1149
|
children: [
|
|
@@ -1348,7 +1471,7 @@ function getThemeVar(container, varName, fallback) {
|
|
|
1348
1471
|
return getComputedStyle(container).getPropertyValue(varName).trim() || fallback;
|
|
1349
1472
|
}
|
|
1350
1473
|
var ARROW_MARKER_ID = "glyph-graph-arrowhead";
|
|
1351
|
-
function renderGraph(svgElement, layout, groupIndex, outgoingRefs, onNavigate) {
|
|
1474
|
+
function renderGraph(svgElement, layout, groupIndex, outgoingRefs, onNavigate, onNodeClick) {
|
|
1352
1475
|
const svg = d32.select(svgElement);
|
|
1353
1476
|
svg.selectAll("*").remove();
|
|
1354
1477
|
const width = Math.max(layout.width, 200);
|
|
@@ -1399,19 +1522,24 @@ function renderGraph(svgElement, layout, groupIndex, outgoingRefs, onNavigate) {
|
|
|
1399
1522
|
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);
|
|
1400
1523
|
}
|
|
1401
1524
|
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);
|
|
1402
|
-
if (isNavigable) {
|
|
1525
|
+
if (isNavigable || onNodeClick) {
|
|
1403
1526
|
nodeG.attr("cursor", "pointer");
|
|
1404
1527
|
nodeG.on("click", () => {
|
|
1405
|
-
|
|
1406
|
-
|
|
1528
|
+
if (isNavigable) {
|
|
1529
|
+
const ref = refByAnchor.get(node.id);
|
|
1530
|
+
if (ref) onNavigate(ref);
|
|
1531
|
+
}
|
|
1532
|
+
onNodeClick?.(node.id, node.label);
|
|
1407
1533
|
});
|
|
1408
1534
|
}
|
|
1409
1535
|
}
|
|
1410
1536
|
}
|
|
1411
1537
|
function Graph({
|
|
1412
1538
|
data,
|
|
1539
|
+
block,
|
|
1413
1540
|
outgoingRefs,
|
|
1414
1541
|
onNavigate,
|
|
1542
|
+
onInteraction,
|
|
1415
1543
|
container
|
|
1416
1544
|
}) {
|
|
1417
1545
|
const svgRef = useRef(null);
|
|
@@ -1423,10 +1551,29 @@ function Graph({
|
|
|
1423
1551
|
}
|
|
1424
1552
|
return computeDagreLayout(data.nodes, data.edges, direction);
|
|
1425
1553
|
}, [data]);
|
|
1554
|
+
const handleNodeClick = useMemo(() => {
|
|
1555
|
+
if (!onInteraction) return void 0;
|
|
1556
|
+
return (nodeId, nodeLabel) => {
|
|
1557
|
+
onInteraction({
|
|
1558
|
+
kind: "graph-node-click",
|
|
1559
|
+
timestamp: (/* @__PURE__ */ new Date()).toISOString(),
|
|
1560
|
+
blockId: block.id,
|
|
1561
|
+
blockType: block.type,
|
|
1562
|
+
payload: { nodeId, nodeLabel }
|
|
1563
|
+
});
|
|
1564
|
+
};
|
|
1565
|
+
}, [onInteraction, block.id, block.type]);
|
|
1426
1566
|
useEffect(() => {
|
|
1427
1567
|
if (!svgRef.current) return;
|
|
1428
|
-
renderGraph(
|
|
1429
|
-
|
|
1568
|
+
renderGraph(
|
|
1569
|
+
svgRef.current,
|
|
1570
|
+
layoutResult,
|
|
1571
|
+
groupIndex.current,
|
|
1572
|
+
outgoingRefs,
|
|
1573
|
+
onNavigate,
|
|
1574
|
+
handleNodeClick
|
|
1575
|
+
);
|
|
1576
|
+
}, [layoutResult, outgoingRefs, onNavigate, handleNodeClick]);
|
|
1430
1577
|
const ariaLabel = `${data.type} graph with ${data.nodes.length} nodes and ${data.edges.length} edges`;
|
|
1431
1578
|
return /* @__PURE__ */ jsxs("div", { className: "glyph-graph-container", children: [
|
|
1432
1579
|
/* @__PURE__ */ jsx(
|
|
@@ -1770,7 +1917,7 @@ function Kpi({ data, block, container }) {
|
|
|
1770
1917
|
default:
|
|
1771
1918
|
colCount = authorCols;
|
|
1772
1919
|
}
|
|
1773
|
-
const
|
|
1920
|
+
const containerStyle11 = {
|
|
1774
1921
|
fontFamily: "var(--glyph-font-body, system-ui, sans-serif)",
|
|
1775
1922
|
color: "var(--glyph-text, #1a2035)"
|
|
1776
1923
|
};
|
|
@@ -1780,13 +1927,13 @@ function Kpi({ data, block, container }) {
|
|
|
1780
1927
|
gridTemplateColumns: `repeat(auto-fill, minmax(max(120px, calc((100% - ${String(gapCount)}rem) / ${String(colCount)})), 1fr))`,
|
|
1781
1928
|
gap: "var(--glyph-spacing-md, 1rem)"
|
|
1782
1929
|
};
|
|
1783
|
-
const
|
|
1930
|
+
const cardStyle2 = {
|
|
1784
1931
|
background: "var(--glyph-surface-raised, #f4f6fa)",
|
|
1785
1932
|
border: "1px solid var(--glyph-border, #d0d8e4)",
|
|
1786
1933
|
borderRadius: "var(--glyph-radius-md, 0.5rem)",
|
|
1787
1934
|
padding: "var(--glyph-spacing-md, 1rem)"
|
|
1788
1935
|
};
|
|
1789
|
-
const
|
|
1936
|
+
const labelStyle4 = {
|
|
1790
1937
|
fontSize: "0.8125rem",
|
|
1791
1938
|
color: "var(--glyph-text-muted, #6b7a94)",
|
|
1792
1939
|
marginBottom: "var(--glyph-spacing-xs, 0.25rem)"
|
|
@@ -1797,7 +1944,7 @@ function Kpi({ data, block, container }) {
|
|
|
1797
1944
|
color: "var(--glyph-heading, #0a0e1a)",
|
|
1798
1945
|
lineHeight: 1.2
|
|
1799
1946
|
};
|
|
1800
|
-
return /* @__PURE__ */ jsxs("div", { id: baseId, role: "region", "aria-label": title ?? "Key metrics", style:
|
|
1947
|
+
return /* @__PURE__ */ jsxs("div", { id: baseId, role: "region", "aria-label": title ?? "Key metrics", style: containerStyle11, children: [
|
|
1801
1948
|
title && /* @__PURE__ */ jsx(
|
|
1802
1949
|
"div",
|
|
1803
1950
|
{
|
|
@@ -1817,8 +1964,8 @@ function Kpi({ data, block, container }) {
|
|
|
1817
1964
|
marginTop: "var(--glyph-spacing-xs, 0.25rem)",
|
|
1818
1965
|
color: `var(--glyph-kpi-${sentiment}, inherit)`
|
|
1819
1966
|
};
|
|
1820
|
-
return /* @__PURE__ */ jsxs("div", { role: "group", "aria-label": buildAriaLabel(metric), style:
|
|
1821
|
-
/* @__PURE__ */ jsx("div", { style:
|
|
1967
|
+
return /* @__PURE__ */ jsxs("div", { role: "group", "aria-label": buildAriaLabel(metric), style: cardStyle2, children: [
|
|
1968
|
+
/* @__PURE__ */ jsx("div", { style: labelStyle4, children: metric.label }),
|
|
1822
1969
|
/* @__PURE__ */ jsxs("div", { style: valueStyle, children: [
|
|
1823
1970
|
metric.value,
|
|
1824
1971
|
metric.unit && /* @__PURE__ */ jsx("span", { style: { fontSize: "0.875rem", fontWeight: 400, marginLeft: "0.25rem" }, children: metric.unit })
|
|
@@ -1838,25 +1985,41 @@ var kpiDefinition = {
|
|
|
1838
1985
|
schema: kpiSchema,
|
|
1839
1986
|
render: Kpi
|
|
1840
1987
|
};
|
|
1841
|
-
function Accordion({
|
|
1988
|
+
function Accordion({
|
|
1989
|
+
data,
|
|
1990
|
+
block,
|
|
1991
|
+
onInteraction
|
|
1992
|
+
}) {
|
|
1842
1993
|
const { title, sections, defaultOpen = [], multiple = true } = data;
|
|
1843
1994
|
const baseId = `glyph-accordion-${block.id}`;
|
|
1844
1995
|
const containerRef = useRef(null);
|
|
1845
1996
|
const handleToggle = useCallback(
|
|
1846
|
-
(e) => {
|
|
1847
|
-
if (multiple) return;
|
|
1997
|
+
(e, sectionIndex) => {
|
|
1848
1998
|
const target = e.currentTarget;
|
|
1849
|
-
|
|
1850
|
-
|
|
1851
|
-
|
|
1852
|
-
|
|
1853
|
-
details.open
|
|
1999
|
+
const expanded = target.open;
|
|
2000
|
+
if (!multiple && expanded && containerRef.current) {
|
|
2001
|
+
const allDetails = containerRef.current.querySelectorAll("details");
|
|
2002
|
+
for (const details of allDetails) {
|
|
2003
|
+
if (details !== target && details.open) {
|
|
2004
|
+
details.open = false;
|
|
2005
|
+
}
|
|
1854
2006
|
}
|
|
1855
2007
|
}
|
|
2008
|
+
onInteraction?.({
|
|
2009
|
+
kind: "accordion-toggle",
|
|
2010
|
+
timestamp: (/* @__PURE__ */ new Date()).toISOString(),
|
|
2011
|
+
blockId: block.id,
|
|
2012
|
+
blockType: block.type,
|
|
2013
|
+
payload: {
|
|
2014
|
+
sectionIndex,
|
|
2015
|
+
sectionTitle: sections[sectionIndex]?.title ?? "",
|
|
2016
|
+
expanded
|
|
2017
|
+
}
|
|
2018
|
+
});
|
|
1856
2019
|
},
|
|
1857
|
-
[multiple]
|
|
2020
|
+
[multiple, sections, block.id, block.type, onInteraction]
|
|
1858
2021
|
);
|
|
1859
|
-
const
|
|
2022
|
+
const containerStyle11 = {
|
|
1860
2023
|
fontFamily: "var(--glyph-font-body, system-ui, sans-serif)",
|
|
1861
2024
|
color: "var(--glyph-text, #1a2035)",
|
|
1862
2025
|
border: "1px solid var(--glyph-border, #d0d8e4)",
|
|
@@ -1890,7 +2053,7 @@ function Accordion({ data, block }) {
|
|
|
1890
2053
|
ref: containerRef,
|
|
1891
2054
|
role: "region",
|
|
1892
2055
|
"aria-label": title ?? "Accordion",
|
|
1893
|
-
style:
|
|
2056
|
+
style: containerStyle11,
|
|
1894
2057
|
children: [
|
|
1895
2058
|
title && /* @__PURE__ */ jsx(
|
|
1896
2059
|
"div",
|
|
@@ -1909,7 +2072,7 @@ function Accordion({ data, block }) {
|
|
|
1909
2072
|
"details",
|
|
1910
2073
|
{
|
|
1911
2074
|
open: defaultOpen.includes(i),
|
|
1912
|
-
onToggle: handleToggle,
|
|
2075
|
+
onToggle: (e) => handleToggle(e, i),
|
|
1913
2076
|
style: sectionStyle(i === sections.length - 1),
|
|
1914
2077
|
children: [
|
|
1915
2078
|
/* @__PURE__ */ jsxs("summary", { style: summaryStyle, children: [
|
|
@@ -1978,17 +2141,18 @@ function renderValue(value) {
|
|
|
1978
2141
|
function Comparison({
|
|
1979
2142
|
data,
|
|
1980
2143
|
block,
|
|
1981
|
-
container
|
|
2144
|
+
container,
|
|
2145
|
+
onInteraction
|
|
1982
2146
|
}) {
|
|
1983
2147
|
const { title, options, features } = data;
|
|
1984
2148
|
const baseId = `glyph-comparison-${block.id}`;
|
|
1985
2149
|
const isCompact = container.tier === "compact";
|
|
1986
2150
|
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)";
|
|
1987
|
-
const
|
|
2151
|
+
const containerStyle11 = {
|
|
1988
2152
|
fontFamily: "var(--glyph-font-body, system-ui, sans-serif)",
|
|
1989
2153
|
color: "var(--glyph-text, #1a2035)"
|
|
1990
2154
|
};
|
|
1991
|
-
const
|
|
2155
|
+
const tableStyle2 = {
|
|
1992
2156
|
width: "100%",
|
|
1993
2157
|
borderCollapse: "collapse",
|
|
1994
2158
|
border: "1px solid var(--glyph-table-border, #d0d8e4)",
|
|
@@ -1996,7 +2160,7 @@ function Comparison({
|
|
|
1996
2160
|
overflow: "hidden",
|
|
1997
2161
|
fontSize: isCompact ? "0.8125rem" : "0.875rem"
|
|
1998
2162
|
};
|
|
1999
|
-
const
|
|
2163
|
+
const thStyle2 = {
|
|
2000
2164
|
padding: cellPadding,
|
|
2001
2165
|
textAlign: "center",
|
|
2002
2166
|
fontWeight: 600,
|
|
@@ -2005,7 +2169,7 @@ function Comparison({
|
|
|
2005
2169
|
color: "var(--glyph-heading, #0a0e1a)"
|
|
2006
2170
|
};
|
|
2007
2171
|
const featureThStyle = {
|
|
2008
|
-
...
|
|
2172
|
+
...thStyle2,
|
|
2009
2173
|
textAlign: "left"
|
|
2010
2174
|
};
|
|
2011
2175
|
const rowThStyle = {
|
|
@@ -2015,13 +2179,13 @@ function Comparison({
|
|
|
2015
2179
|
borderBottom: "1px solid var(--glyph-table-border, #d0d8e4)",
|
|
2016
2180
|
fontSize: "0.8125rem"
|
|
2017
2181
|
};
|
|
2018
|
-
const
|
|
2182
|
+
const cellStyle2 = (rowIndex) => ({
|
|
2019
2183
|
padding: cellPadding,
|
|
2020
2184
|
textAlign: "center",
|
|
2021
2185
|
borderBottom: "1px solid var(--glyph-table-border, #d0d8e4)",
|
|
2022
2186
|
background: rowIndex % 2 === 1 ? "var(--glyph-table-row-alt-bg, transparent)" : "transparent"
|
|
2023
2187
|
});
|
|
2024
|
-
return /* @__PURE__ */ jsxs("div", { id: baseId, role: "region", "aria-label": title ?? "Comparison", style:
|
|
2188
|
+
return /* @__PURE__ */ jsxs("div", { id: baseId, role: "region", "aria-label": title ?? "Comparison", style: containerStyle11, children: [
|
|
2025
2189
|
title && /* @__PURE__ */ jsx(
|
|
2026
2190
|
"div",
|
|
2027
2191
|
{
|
|
@@ -2034,23 +2198,46 @@ function Comparison({
|
|
|
2034
2198
|
children: title
|
|
2035
2199
|
}
|
|
2036
2200
|
),
|
|
2037
|
-
/* @__PURE__ */ jsx("div", { style: { overflowX: "auto" }, children: /* @__PURE__ */ jsxs("table", { role: "grid", style:
|
|
2201
|
+
/* @__PURE__ */ jsx("div", { style: { overflowX: "auto" }, children: /* @__PURE__ */ jsxs("table", { role: "grid", style: tableStyle2, children: [
|
|
2038
2202
|
/* @__PURE__ */ jsx("thead", { children: /* @__PURE__ */ jsxs("tr", { children: [
|
|
2039
2203
|
/* @__PURE__ */ jsx("th", { style: featureThStyle, scope: "col", children: "Feature" }),
|
|
2040
|
-
options.map((option, i) => /* @__PURE__ */ jsxs(
|
|
2041
|
-
|
|
2042
|
-
|
|
2043
|
-
|
|
2044
|
-
|
|
2045
|
-
|
|
2046
|
-
|
|
2047
|
-
|
|
2048
|
-
|
|
2049
|
-
|
|
2050
|
-
|
|
2051
|
-
|
|
2052
|
-
|
|
2053
|
-
|
|
2204
|
+
options.map((option, i) => /* @__PURE__ */ jsxs(
|
|
2205
|
+
"th",
|
|
2206
|
+
{
|
|
2207
|
+
style: {
|
|
2208
|
+
...thStyle2,
|
|
2209
|
+
...onInteraction ? { cursor: "pointer" } : {}
|
|
2210
|
+
},
|
|
2211
|
+
scope: "col",
|
|
2212
|
+
onClick: onInteraction ? () => {
|
|
2213
|
+
onInteraction({
|
|
2214
|
+
kind: "comparison-select",
|
|
2215
|
+
timestamp: (/* @__PURE__ */ new Date()).toISOString(),
|
|
2216
|
+
blockId: block.id,
|
|
2217
|
+
blockType: block.type,
|
|
2218
|
+
payload: {
|
|
2219
|
+
optionIndex: i,
|
|
2220
|
+
optionName: option.name
|
|
2221
|
+
}
|
|
2222
|
+
});
|
|
2223
|
+
} : void 0,
|
|
2224
|
+
children: [
|
|
2225
|
+
/* @__PURE__ */ jsx("div", { children: option.name }),
|
|
2226
|
+
option.description && /* @__PURE__ */ jsx(
|
|
2227
|
+
"div",
|
|
2228
|
+
{
|
|
2229
|
+
style: {
|
|
2230
|
+
fontWeight: 400,
|
|
2231
|
+
fontSize: "0.75rem",
|
|
2232
|
+
color: "var(--glyph-text-muted, #6b7a94)"
|
|
2233
|
+
},
|
|
2234
|
+
children: option.description
|
|
2235
|
+
}
|
|
2236
|
+
)
|
|
2237
|
+
]
|
|
2238
|
+
},
|
|
2239
|
+
i
|
|
2240
|
+
))
|
|
2054
2241
|
] }) }),
|
|
2055
2242
|
/* @__PURE__ */ jsx("tbody", { children: features.map((feature, rowIndex) => /* @__PURE__ */ jsxs("tr", { children: [
|
|
2056
2243
|
/* @__PURE__ */ jsx(
|
|
@@ -2066,7 +2253,7 @@ function Comparison({
|
|
|
2066
2253
|
),
|
|
2067
2254
|
options.map((_, colIndex) => {
|
|
2068
2255
|
const value = feature.values[colIndex] ?? "";
|
|
2069
|
-
return /* @__PURE__ */ jsx("td", { style:
|
|
2256
|
+
return /* @__PURE__ */ jsx("td", { style: cellStyle2(rowIndex), children: value ? renderValue(value) : null }, colIndex);
|
|
2070
2257
|
})
|
|
2071
2258
|
] }, rowIndex)) })
|
|
2072
2259
|
] }) })
|
|
@@ -2144,7 +2331,7 @@ function CodeDiff({ data, block }) {
|
|
|
2144
2331
|
const baseId = `glyph-codediff-${block.id}`;
|
|
2145
2332
|
const diffLines = useMemo(() => computeDiff(before, after), [before, after]);
|
|
2146
2333
|
const summary = useMemo(() => summarizeDiff(diffLines), [diffLines]);
|
|
2147
|
-
const
|
|
2334
|
+
const containerStyle11 = {
|
|
2148
2335
|
fontFamily: 'var(--glyph-font-mono, ui-monospace, "Cascadia Code", "Fira Code", monospace)',
|
|
2149
2336
|
fontSize: "0.8125rem",
|
|
2150
2337
|
lineHeight: 1.5,
|
|
@@ -2163,7 +2350,7 @@ function CodeDiff({ data, block }) {
|
|
|
2163
2350
|
fontWeight: 600,
|
|
2164
2351
|
color: "var(--glyph-text-muted, #6b7a94)"
|
|
2165
2352
|
};
|
|
2166
|
-
const
|
|
2353
|
+
const tableStyle2 = {
|
|
2167
2354
|
width: "100%",
|
|
2168
2355
|
borderCollapse: "collapse",
|
|
2169
2356
|
tableLayout: "fixed"
|
|
@@ -2202,13 +2389,13 @@ function CodeDiff({ data, block }) {
|
|
|
2202
2389
|
if (kind === "del") return "var(--glyph-codediff-del-color, inherit)";
|
|
2203
2390
|
return void 0;
|
|
2204
2391
|
}
|
|
2205
|
-
return /* @__PURE__ */ jsxs("div", { id: baseId, role: "region", "aria-label": summary, style:
|
|
2392
|
+
return /* @__PURE__ */ jsxs("div", { id: baseId, role: "region", "aria-label": summary, style: containerStyle11, children: [
|
|
2206
2393
|
(beforeLabel || afterLabel) && /* @__PURE__ */ jsxs("div", { style: labelBarStyle, children: [
|
|
2207
2394
|
beforeLabel && /* @__PURE__ */ jsx("span", { children: beforeLabel }),
|
|
2208
2395
|
beforeLabel && afterLabel && /* @__PURE__ */ jsx("span", { children: "\u2192" }),
|
|
2209
2396
|
afterLabel && /* @__PURE__ */ jsx("span", { children: afterLabel })
|
|
2210
2397
|
] }),
|
|
2211
|
-
/* @__PURE__ */ jsx("div", { style: { overflowX: "auto" }, children: /* @__PURE__ */ jsx("table", { role: "grid", style:
|
|
2398
|
+
/* @__PURE__ */ jsx("div", { style: { overflowX: "auto" }, children: /* @__PURE__ */ jsx("table", { role: "grid", style: tableStyle2, children: /* @__PURE__ */ jsx("tbody", { children: diffLines.map((line6, i) => /* @__PURE__ */ jsxs(
|
|
2212
2399
|
"tr",
|
|
2213
2400
|
{
|
|
2214
2401
|
"aria-label": ARIA_LABELS[line6.kind],
|
|
@@ -2474,15 +2661,25 @@ function TreeItem({
|
|
|
2474
2661
|
setSize,
|
|
2475
2662
|
posInSet,
|
|
2476
2663
|
onFocusChange,
|
|
2477
|
-
flatItems
|
|
2664
|
+
flatItems,
|
|
2665
|
+
parentPath,
|
|
2666
|
+
onSelect
|
|
2478
2667
|
}) {
|
|
2479
2668
|
const [expanded, setExpanded] = useState(defaultExpanded);
|
|
2480
2669
|
const itemRef = useRef(null);
|
|
2481
2670
|
const isDir = Array.isArray(node.children) && node.children.length > 0;
|
|
2482
2671
|
const isFocused = flatIndex === focusedIndex;
|
|
2672
|
+
const path = parentPath ? `${parentPath}/${node.name}` : node.name;
|
|
2483
2673
|
const handleToggle = useCallback(() => {
|
|
2484
|
-
if (isDir)
|
|
2485
|
-
|
|
2674
|
+
if (isDir) {
|
|
2675
|
+
setExpanded((prev) => {
|
|
2676
|
+
onSelect?.(path, "directory", !prev);
|
|
2677
|
+
return !prev;
|
|
2678
|
+
});
|
|
2679
|
+
} else {
|
|
2680
|
+
onSelect?.(path, "file");
|
|
2681
|
+
}
|
|
2682
|
+
}, [isDir, path, onSelect]);
|
|
2486
2683
|
const handleKeyDown = useCallback(
|
|
2487
2684
|
(e) => {
|
|
2488
2685
|
let handled = true;
|
|
@@ -2614,7 +2811,9 @@ function TreeItem({
|
|
|
2614
2811
|
setSize: node.children?.length ?? 0,
|
|
2615
2812
|
posInSet: childIdx + 1,
|
|
2616
2813
|
onFocusChange,
|
|
2617
|
-
flatItems
|
|
2814
|
+
flatItems,
|
|
2815
|
+
parentPath: path,
|
|
2816
|
+
onSelect
|
|
2618
2817
|
},
|
|
2619
2818
|
child.name
|
|
2620
2819
|
);
|
|
@@ -2647,7 +2846,11 @@ function getChildFlatIndex(flatItems, parentFlatIndex, childIdx, children) {
|
|
|
2647
2846
|
}
|
|
2648
2847
|
return parentFlatIndex + childIdx + 1;
|
|
2649
2848
|
}
|
|
2650
|
-
function FileTree({
|
|
2849
|
+
function FileTree({
|
|
2850
|
+
data,
|
|
2851
|
+
block,
|
|
2852
|
+
onInteraction
|
|
2853
|
+
}) {
|
|
2651
2854
|
const [focusedIndex, setFocusedIndex] = useState(0);
|
|
2652
2855
|
const containerRef = useRef(null);
|
|
2653
2856
|
const flatItems = flattenTree(data.tree, data.root ? 1 : 0);
|
|
@@ -2658,6 +2861,18 @@ function FileTree({ data }) {
|
|
|
2658
2861
|
const el = container.querySelector(`[data-flat-index="${String(index)}"]`);
|
|
2659
2862
|
el?.focus();
|
|
2660
2863
|
}, []);
|
|
2864
|
+
const handleSelect = useCallback(
|
|
2865
|
+
(path, type, expanded) => {
|
|
2866
|
+
onInteraction?.({
|
|
2867
|
+
kind: "filetree-select",
|
|
2868
|
+
timestamp: (/* @__PURE__ */ new Date()).toISOString(),
|
|
2869
|
+
blockId: block.id,
|
|
2870
|
+
blockType: block.type,
|
|
2871
|
+
payload: { path, type, expanded }
|
|
2872
|
+
});
|
|
2873
|
+
},
|
|
2874
|
+
[onInteraction, block.id, block.type]
|
|
2875
|
+
);
|
|
2661
2876
|
return /* @__PURE__ */ jsx(
|
|
2662
2877
|
"div",
|
|
2663
2878
|
{
|
|
@@ -2714,7 +2929,9 @@ function FileTree({ data }) {
|
|
|
2714
2929
|
setSize: data.tree.length,
|
|
2715
2930
|
posInSet: idx + 1,
|
|
2716
2931
|
onFocusChange: handleFocusChange,
|
|
2717
|
-
flatItems
|
|
2932
|
+
flatItems,
|
|
2933
|
+
parentPath: data.root ?? "",
|
|
2934
|
+
onSelect: handleSelect
|
|
2718
2935
|
},
|
|
2719
2936
|
node.name
|
|
2720
2937
|
);
|
|
@@ -2735,7 +2952,9 @@ function FileTree({ data }) {
|
|
|
2735
2952
|
setSize: data.tree.length,
|
|
2736
2953
|
posInSet: idx + 1,
|
|
2737
2954
|
onFocusChange: handleFocusChange,
|
|
2738
|
-
flatItems
|
|
2955
|
+
flatItems,
|
|
2956
|
+
parentPath: "",
|
|
2957
|
+
onSelect: handleSelect
|
|
2739
2958
|
},
|
|
2740
2959
|
node.name
|
|
2741
2960
|
);
|
|
@@ -3983,7 +4202,115 @@ function isCorrect(question, selected) {
|
|
|
3983
4202
|
}
|
|
3984
4203
|
}
|
|
3985
4204
|
}
|
|
3986
|
-
function
|
|
4205
|
+
function renderMultipleChoice(question, qIndex, state, updateState, baseId) {
|
|
4206
|
+
const selected = typeof state.selected === "number" ? state.selected : null;
|
|
4207
|
+
return /* @__PURE__ */ jsx("div", { role: "radiogroup", "aria-label": question.question, children: question.options.map((option, oIndex) => {
|
|
4208
|
+
const isSelected = selected === oIndex;
|
|
4209
|
+
const isCorrectOption = state.submitted && oIndex === question.answer;
|
|
4210
|
+
const isIncorrectSelection = state.submitted && isSelected && oIndex !== question.answer;
|
|
4211
|
+
return /* @__PURE__ */ jsxs(
|
|
4212
|
+
"label",
|
|
4213
|
+
{
|
|
4214
|
+
style: optionLabelStyle(
|
|
4215
|
+
isSelected,
|
|
4216
|
+
state.submitted,
|
|
4217
|
+
isCorrectOption,
|
|
4218
|
+
isIncorrectSelection
|
|
4219
|
+
),
|
|
4220
|
+
children: [
|
|
4221
|
+
/* @__PURE__ */ jsx(
|
|
4222
|
+
"input",
|
|
4223
|
+
{
|
|
4224
|
+
type: "radio",
|
|
4225
|
+
role: "radio",
|
|
4226
|
+
name: `${baseId}-q${String(qIndex)}`,
|
|
4227
|
+
checked: isSelected,
|
|
4228
|
+
disabled: state.submitted,
|
|
4229
|
+
onChange: () => updateState(qIndex, { selected: oIndex }),
|
|
4230
|
+
"aria-checked": isSelected
|
|
4231
|
+
}
|
|
4232
|
+
),
|
|
4233
|
+
option
|
|
4234
|
+
]
|
|
4235
|
+
},
|
|
4236
|
+
oIndex
|
|
4237
|
+
);
|
|
4238
|
+
}) });
|
|
4239
|
+
}
|
|
4240
|
+
function renderTrueFalse(question, qIndex, state, updateState, baseId) {
|
|
4241
|
+
const selected = typeof state.selected === "boolean" ? state.selected : null;
|
|
4242
|
+
return /* @__PURE__ */ jsx("div", { role: "radiogroup", "aria-label": question.question, children: [true, false].map((value) => {
|
|
4243
|
+
const isSelected = selected === value;
|
|
4244
|
+
const isCorrectOption = state.submitted && value === question.answer;
|
|
4245
|
+
const isIncorrectSelection = state.submitted && isSelected && value !== question.answer;
|
|
4246
|
+
return /* @__PURE__ */ jsxs(
|
|
4247
|
+
"label",
|
|
4248
|
+
{
|
|
4249
|
+
style: optionLabelStyle(
|
|
4250
|
+
isSelected,
|
|
4251
|
+
state.submitted,
|
|
4252
|
+
isCorrectOption,
|
|
4253
|
+
isIncorrectSelection
|
|
4254
|
+
),
|
|
4255
|
+
children: [
|
|
4256
|
+
/* @__PURE__ */ jsx(
|
|
4257
|
+
"input",
|
|
4258
|
+
{
|
|
4259
|
+
type: "radio",
|
|
4260
|
+
role: "radio",
|
|
4261
|
+
name: `${baseId}-q${String(qIndex)}`,
|
|
4262
|
+
checked: isSelected,
|
|
4263
|
+
disabled: state.submitted,
|
|
4264
|
+
onChange: () => updateState(qIndex, { selected: value }),
|
|
4265
|
+
"aria-checked": isSelected
|
|
4266
|
+
}
|
|
4267
|
+
),
|
|
4268
|
+
value ? "True" : "False"
|
|
4269
|
+
]
|
|
4270
|
+
},
|
|
4271
|
+
String(value)
|
|
4272
|
+
);
|
|
4273
|
+
}) });
|
|
4274
|
+
}
|
|
4275
|
+
function renderMultiSelect(question, qIndex, state, updateState) {
|
|
4276
|
+
const selected = Array.isArray(state.selected) ? state.selected : [];
|
|
4277
|
+
const toggleOption = (oIndex) => {
|
|
4278
|
+
const next = selected.includes(oIndex) ? selected.filter((v) => v !== oIndex) : [...selected, oIndex];
|
|
4279
|
+
updateState(qIndex, { selected: next });
|
|
4280
|
+
};
|
|
4281
|
+
return /* @__PURE__ */ jsx("div", { children: question.options.map((option, oIndex) => {
|
|
4282
|
+
const isSelected = selected.includes(oIndex);
|
|
4283
|
+
const isCorrectOption = state.submitted && question.answer.includes(oIndex);
|
|
4284
|
+
const isIncorrectSelection = state.submitted && isSelected && !question.answer.includes(oIndex);
|
|
4285
|
+
return /* @__PURE__ */ jsxs(
|
|
4286
|
+
"label",
|
|
4287
|
+
{
|
|
4288
|
+
style: optionLabelStyle(
|
|
4289
|
+
isSelected,
|
|
4290
|
+
state.submitted,
|
|
4291
|
+
isCorrectOption,
|
|
4292
|
+
isIncorrectSelection
|
|
4293
|
+
),
|
|
4294
|
+
children: [
|
|
4295
|
+
/* @__PURE__ */ jsx(
|
|
4296
|
+
"input",
|
|
4297
|
+
{
|
|
4298
|
+
type: "checkbox",
|
|
4299
|
+
role: "checkbox",
|
|
4300
|
+
checked: isSelected,
|
|
4301
|
+
disabled: state.submitted,
|
|
4302
|
+
onChange: () => toggleOption(oIndex),
|
|
4303
|
+
"aria-checked": isSelected
|
|
4304
|
+
}
|
|
4305
|
+
),
|
|
4306
|
+
option
|
|
4307
|
+
]
|
|
4308
|
+
},
|
|
4309
|
+
oIndex
|
|
4310
|
+
);
|
|
4311
|
+
}) });
|
|
4312
|
+
}
|
|
4313
|
+
function Quiz({ data, block, onInteraction }) {
|
|
3987
4314
|
const { questions, showScore = true, title } = data;
|
|
3988
4315
|
const baseId = `glyph-quiz-${block.id}`;
|
|
3989
4316
|
const [states, setStates] = useState(
|
|
@@ -4001,114 +4328,6 @@ function Quiz({ data, block }) {
|
|
|
4001
4328
|
return acc + (isCorrect(q, s.selected) ? 1 : 0);
|
|
4002
4329
|
}, 0);
|
|
4003
4330
|
const submittedCount = states.filter((s) => s.submitted).length;
|
|
4004
|
-
function renderMultipleChoice(question, qIndex, state) {
|
|
4005
|
-
const selected = typeof state.selected === "number" ? state.selected : null;
|
|
4006
|
-
return /* @__PURE__ */ jsx("div", { role: "radiogroup", "aria-label": question.question, children: question.options.map((option, oIndex) => {
|
|
4007
|
-
const isSelected = selected === oIndex;
|
|
4008
|
-
const isCorrectOption = state.submitted && oIndex === question.answer;
|
|
4009
|
-
const isIncorrectSelection = state.submitted && isSelected && oIndex !== question.answer;
|
|
4010
|
-
return /* @__PURE__ */ jsxs(
|
|
4011
|
-
"label",
|
|
4012
|
-
{
|
|
4013
|
-
style: optionLabelStyle(
|
|
4014
|
-
isSelected,
|
|
4015
|
-
state.submitted,
|
|
4016
|
-
isCorrectOption,
|
|
4017
|
-
isIncorrectSelection
|
|
4018
|
-
),
|
|
4019
|
-
children: [
|
|
4020
|
-
/* @__PURE__ */ jsx(
|
|
4021
|
-
"input",
|
|
4022
|
-
{
|
|
4023
|
-
type: "radio",
|
|
4024
|
-
role: "radio",
|
|
4025
|
-
name: `${baseId}-q${String(qIndex)}`,
|
|
4026
|
-
checked: isSelected,
|
|
4027
|
-
disabled: state.submitted,
|
|
4028
|
-
onChange: () => updateState(qIndex, { selected: oIndex }),
|
|
4029
|
-
"aria-checked": isSelected
|
|
4030
|
-
}
|
|
4031
|
-
),
|
|
4032
|
-
option
|
|
4033
|
-
]
|
|
4034
|
-
},
|
|
4035
|
-
oIndex
|
|
4036
|
-
);
|
|
4037
|
-
}) });
|
|
4038
|
-
}
|
|
4039
|
-
function renderTrueFalse(question, qIndex, state) {
|
|
4040
|
-
const selected = typeof state.selected === "boolean" ? state.selected : null;
|
|
4041
|
-
return /* @__PURE__ */ jsx("div", { role: "radiogroup", "aria-label": question.question, children: [true, false].map((value) => {
|
|
4042
|
-
const isSelected = selected === value;
|
|
4043
|
-
const isCorrectOption = state.submitted && value === question.answer;
|
|
4044
|
-
const isIncorrectSelection = state.submitted && isSelected && value !== question.answer;
|
|
4045
|
-
return /* @__PURE__ */ jsxs(
|
|
4046
|
-
"label",
|
|
4047
|
-
{
|
|
4048
|
-
style: optionLabelStyle(
|
|
4049
|
-
isSelected,
|
|
4050
|
-
state.submitted,
|
|
4051
|
-
isCorrectOption,
|
|
4052
|
-
isIncorrectSelection
|
|
4053
|
-
),
|
|
4054
|
-
children: [
|
|
4055
|
-
/* @__PURE__ */ jsx(
|
|
4056
|
-
"input",
|
|
4057
|
-
{
|
|
4058
|
-
type: "radio",
|
|
4059
|
-
role: "radio",
|
|
4060
|
-
name: `${baseId}-q${String(qIndex)}`,
|
|
4061
|
-
checked: isSelected,
|
|
4062
|
-
disabled: state.submitted,
|
|
4063
|
-
onChange: () => updateState(qIndex, { selected: value }),
|
|
4064
|
-
"aria-checked": isSelected
|
|
4065
|
-
}
|
|
4066
|
-
),
|
|
4067
|
-
value ? "True" : "False"
|
|
4068
|
-
]
|
|
4069
|
-
},
|
|
4070
|
-
String(value)
|
|
4071
|
-
);
|
|
4072
|
-
}) });
|
|
4073
|
-
}
|
|
4074
|
-
function renderMultiSelect(question, qIndex, state) {
|
|
4075
|
-
const selected = Array.isArray(state.selected) ? state.selected : [];
|
|
4076
|
-
const toggleOption = (oIndex) => {
|
|
4077
|
-
const next = selected.includes(oIndex) ? selected.filter((v) => v !== oIndex) : [...selected, oIndex];
|
|
4078
|
-
updateState(qIndex, { selected: next });
|
|
4079
|
-
};
|
|
4080
|
-
return /* @__PURE__ */ jsx("div", { children: question.options.map((option, oIndex) => {
|
|
4081
|
-
const isSelected = selected.includes(oIndex);
|
|
4082
|
-
const isCorrectOption = state.submitted && question.answer.includes(oIndex);
|
|
4083
|
-
const isIncorrectSelection = state.submitted && isSelected && !question.answer.includes(oIndex);
|
|
4084
|
-
return /* @__PURE__ */ jsxs(
|
|
4085
|
-
"label",
|
|
4086
|
-
{
|
|
4087
|
-
style: optionLabelStyle(
|
|
4088
|
-
isSelected,
|
|
4089
|
-
state.submitted,
|
|
4090
|
-
isCorrectOption,
|
|
4091
|
-
isIncorrectSelection
|
|
4092
|
-
),
|
|
4093
|
-
children: [
|
|
4094
|
-
/* @__PURE__ */ jsx(
|
|
4095
|
-
"input",
|
|
4096
|
-
{
|
|
4097
|
-
type: "checkbox",
|
|
4098
|
-
role: "checkbox",
|
|
4099
|
-
checked: isSelected,
|
|
4100
|
-
disabled: state.submitted,
|
|
4101
|
-
onChange: () => toggleOption(oIndex),
|
|
4102
|
-
"aria-checked": isSelected
|
|
4103
|
-
}
|
|
4104
|
-
),
|
|
4105
|
-
option
|
|
4106
|
-
]
|
|
4107
|
-
},
|
|
4108
|
-
oIndex
|
|
4109
|
-
);
|
|
4110
|
-
}) });
|
|
4111
|
-
}
|
|
4112
4331
|
function renderQuestion(question, qIndex) {
|
|
4113
4332
|
const state = states[qIndex] ?? { selected: null, submitted: false };
|
|
4114
4333
|
const isLast = qIndex === questions.length - 1;
|
|
@@ -4125,16 +4344,52 @@ function Quiz({ data, block }) {
|
|
|
4125
4344
|
questions.length > 1 ? `${String(qIndex + 1)}. ` : "",
|
|
4126
4345
|
question.question
|
|
4127
4346
|
] }),
|
|
4128
|
-
question.type === "multiple-choice" && renderMultipleChoice(question, qIndex, state),
|
|
4129
|
-
question.type === "true-false" && renderTrueFalse(question, qIndex, state),
|
|
4130
|
-
question.type === "multi-select" && renderMultiSelect(question, qIndex, state),
|
|
4347
|
+
question.type === "multiple-choice" && renderMultipleChoice(question, qIndex, state, updateState, baseId),
|
|
4348
|
+
question.type === "true-false" && renderTrueFalse(question, qIndex, state, updateState, baseId),
|
|
4349
|
+
question.type === "multi-select" && renderMultiSelect(question, qIndex, state, updateState),
|
|
4131
4350
|
!state.submitted && /* @__PURE__ */ jsx(
|
|
4132
4351
|
"button",
|
|
4133
4352
|
{
|
|
4134
4353
|
type: "button",
|
|
4135
4354
|
disabled: !hasSelection,
|
|
4136
4355
|
style: buttonStyle(!hasSelection),
|
|
4137
|
-
onClick: () =>
|
|
4356
|
+
onClick: () => {
|
|
4357
|
+
updateState(qIndex, { submitted: true });
|
|
4358
|
+
if (onInteraction) {
|
|
4359
|
+
const correct2 = isCorrect(question, state.selected);
|
|
4360
|
+
const newScore = states.reduce((acc, s, i) => {
|
|
4361
|
+
if (i === qIndex) return acc + (correct2 ? 1 : 0);
|
|
4362
|
+
const q = questions[i];
|
|
4363
|
+
if (!q || !s.submitted) return acc;
|
|
4364
|
+
return acc + (isCorrect(q, s.selected) ? 1 : 0);
|
|
4365
|
+
}, 0);
|
|
4366
|
+
let selected;
|
|
4367
|
+
switch (question.type) {
|
|
4368
|
+
case "multiple-choice":
|
|
4369
|
+
selected = typeof state.selected === "number" ? [question.options[state.selected] ?? String(state.selected)] : [];
|
|
4370
|
+
break;
|
|
4371
|
+
case "true-false":
|
|
4372
|
+
selected = typeof state.selected === "boolean" ? [state.selected ? "True" : "False"] : [];
|
|
4373
|
+
break;
|
|
4374
|
+
case "multi-select":
|
|
4375
|
+
selected = Array.isArray(state.selected) ? state.selected.map((idx) => question.options[idx] ?? String(idx)) : [];
|
|
4376
|
+
break;
|
|
4377
|
+
}
|
|
4378
|
+
onInteraction({
|
|
4379
|
+
kind: "quiz-submit",
|
|
4380
|
+
timestamp: (/* @__PURE__ */ new Date()).toISOString(),
|
|
4381
|
+
blockId: block.id,
|
|
4382
|
+
blockType: block.type,
|
|
4383
|
+
payload: {
|
|
4384
|
+
questionIndex: qIndex,
|
|
4385
|
+
question: question.question,
|
|
4386
|
+
selected,
|
|
4387
|
+
correct: correct2,
|
|
4388
|
+
score: { correct: newScore, total: questions.length }
|
|
4389
|
+
}
|
|
4390
|
+
});
|
|
4391
|
+
}
|
|
4392
|
+
},
|
|
4138
4393
|
children: "Submit"
|
|
4139
4394
|
}
|
|
4140
4395
|
),
|
|
@@ -4197,7 +4452,7 @@ function Card({ data, block, container }) {
|
|
|
4197
4452
|
default:
|
|
4198
4453
|
colCount = authorCols;
|
|
4199
4454
|
}
|
|
4200
|
-
const
|
|
4455
|
+
const containerStyle11 = {
|
|
4201
4456
|
fontFamily: "var(--glyph-font-body, system-ui, sans-serif)",
|
|
4202
4457
|
color: "var(--glyph-text, #1a2035)"
|
|
4203
4458
|
};
|
|
@@ -4242,7 +4497,7 @@ function Card({ data, block, container }) {
|
|
|
4242
4497
|
color: "var(--glyph-text-muted, #6b7a94)",
|
|
4243
4498
|
marginTop: "var(--glyph-spacing-xs, 0.25rem)"
|
|
4244
4499
|
};
|
|
4245
|
-
const
|
|
4500
|
+
const bodyStyle3 = {
|
|
4246
4501
|
fontSize: "0.875rem",
|
|
4247
4502
|
lineHeight: 1.6,
|
|
4248
4503
|
marginTop: "var(--glyph-spacing-sm, 0.5rem)",
|
|
@@ -4260,7 +4515,7 @@ function Card({ data, block, container }) {
|
|
|
4260
4515
|
color: "var(--glyph-link, #0a9d7c)",
|
|
4261
4516
|
textDecoration: "none"
|
|
4262
4517
|
};
|
|
4263
|
-
return /* @__PURE__ */ jsxs("div", { id: baseId, role: "region", "aria-label": title ?? "Cards", style:
|
|
4518
|
+
return /* @__PURE__ */ jsxs("div", { id: baseId, role: "region", "aria-label": title ?? "Cards", style: containerStyle11, children: [
|
|
4264
4519
|
title && /* @__PURE__ */ jsx(
|
|
4265
4520
|
"div",
|
|
4266
4521
|
{
|
|
@@ -4279,7 +4534,7 @@ function Card({ data, block, container }) {
|
|
|
4279
4534
|
card.icon && /* @__PURE__ */ jsx("div", { style: iconStyle, children: card.icon }),
|
|
4280
4535
|
/* @__PURE__ */ jsx("h3", { style: titleStyle2, children: card.title }),
|
|
4281
4536
|
card.subtitle && /* @__PURE__ */ jsx("div", { style: subtitleStyle, children: card.subtitle }),
|
|
4282
|
-
card.body && /* @__PURE__ */ jsx("div", { style:
|
|
4537
|
+
card.body && /* @__PURE__ */ jsx("div", { style: bodyStyle3, children: card.body }),
|
|
4283
4538
|
card.actions && card.actions.length > 0 && /* @__PURE__ */ jsx("div", { style: actionsStyle, children: card.actions.map((action, j) => /* @__PURE__ */ jsx(
|
|
4284
4539
|
"a",
|
|
4285
4540
|
{
|
|
@@ -4369,7 +4624,7 @@ function renderStatGroup(items, keyPrefix) {
|
|
|
4369
4624
|
color: "var(--glyph-infographic-value-color, #1d4ed8)",
|
|
4370
4625
|
lineHeight: 1.2
|
|
4371
4626
|
};
|
|
4372
|
-
const
|
|
4627
|
+
const labelStyle4 = {
|
|
4373
4628
|
fontSize: "0.8125rem",
|
|
4374
4629
|
color: "var(--glyph-infographic-label-color, #475569)",
|
|
4375
4630
|
marginTop: "var(--glyph-spacing-xs, 0.25rem)",
|
|
@@ -4385,7 +4640,7 @@ function renderStatGroup(items, keyPrefix) {
|
|
|
4385
4640
|
};
|
|
4386
4641
|
return /* @__PURE__ */ jsx("div", { style: rowStyle, "data-group": "stat", children: items.map((item, i) => /* @__PURE__ */ jsxs("div", { style: statStyle, children: [
|
|
4387
4642
|
/* @__PURE__ */ jsx("div", { style: valueStyle, children: item.value }),
|
|
4388
|
-
/* @__PURE__ */ jsx("div", { style:
|
|
4643
|
+
/* @__PURE__ */ jsx("div", { style: labelStyle4, children: item.label }),
|
|
4389
4644
|
item.description && /* @__PURE__ */ jsx("div", { style: descStyle, children: item.description })
|
|
4390
4645
|
] }, `${keyPrefix}-${String(i)}`)) }, keyPrefix);
|
|
4391
4646
|
}
|
|
@@ -4456,18 +4711,18 @@ function renderProgressGroup(items, keyPrefix, colorOffset) {
|
|
|
4456
4711
|
}) }, keyPrefix);
|
|
4457
4712
|
}
|
|
4458
4713
|
function renderFactGroup(items, keyPrefix) {
|
|
4459
|
-
const
|
|
4714
|
+
const listStyle2 = {
|
|
4460
4715
|
listStyle: "none",
|
|
4461
4716
|
margin: 0,
|
|
4462
4717
|
padding: 0
|
|
4463
4718
|
};
|
|
4464
|
-
const
|
|
4719
|
+
const itemStyle4 = {
|
|
4465
4720
|
padding: "var(--glyph-spacing-xs, 0.25rem) 0",
|
|
4466
4721
|
fontSize: "0.875rem",
|
|
4467
4722
|
color: "var(--glyph-text, #1a2035)",
|
|
4468
4723
|
fontWeight: 500
|
|
4469
4724
|
};
|
|
4470
|
-
return /* @__PURE__ */ jsx("ul", { style:
|
|
4725
|
+
return /* @__PURE__ */ jsx("ul", { style: listStyle2, "data-group": "fact", children: items.map((item, i) => /* @__PURE__ */ jsxs("li", { style: itemStyle4, children: [
|
|
4471
4726
|
item.icon && /* @__PURE__ */ jsx(
|
|
4472
4727
|
"span",
|
|
4473
4728
|
{
|
|
@@ -4744,7 +4999,7 @@ function Infographic({
|
|
|
4744
4999
|
const baseId = `glyph-infographic-${block.id}`;
|
|
4745
5000
|
const useGrid = sections.length >= 2 && container.tier !== "compact";
|
|
4746
5001
|
const sectionLayouts = useMemo(() => computeSectionLayout(sections), [sections]);
|
|
4747
|
-
const
|
|
5002
|
+
const containerStyle11 = {
|
|
4748
5003
|
fontFamily: "var(--glyph-font-body, system-ui, sans-serif)",
|
|
4749
5004
|
color: "var(--glyph-text, #1a2035)",
|
|
4750
5005
|
background: "var(--glyph-surface, #e8ecf3)",
|
|
@@ -4789,7 +5044,7 @@ function Infographic({
|
|
|
4789
5044
|
};
|
|
4790
5045
|
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; } }` : "";
|
|
4791
5046
|
let progressColorOffset = 0;
|
|
4792
|
-
return /* @__PURE__ */ jsxs("div", { id: baseId, role: "region", "aria-label": title ?? "Infographic", style:
|
|
5047
|
+
return /* @__PURE__ */ jsxs("div", { id: baseId, role: "region", "aria-label": title ?? "Infographic", style: containerStyle11, children: [
|
|
4793
5048
|
printCss && /* @__PURE__ */ jsx("style", { children: printCss }),
|
|
4794
5049
|
/* @__PURE__ */ jsxs("div", { "data-layout": useGrid ? "grid" : "stack", style: useGrid ? sectionsGridStyle : void 0, children: [
|
|
4795
5050
|
title && /* @__PURE__ */ jsx("div", { style: titleStyle2, children: title }),
|
|
@@ -4850,6 +5105,1731 @@ var infographicDefinition = {
|
|
|
4850
5105
|
render: Infographic
|
|
4851
5106
|
};
|
|
4852
5107
|
|
|
4853
|
-
|
|
5108
|
+
// src/poll/styles.ts
|
|
5109
|
+
var containerStyle3 = {
|
|
5110
|
+
fontFamily: "var(--glyph-font-body, system-ui, sans-serif)",
|
|
5111
|
+
color: "var(--glyph-text, #1a2035)",
|
|
5112
|
+
border: "1px solid var(--glyph-border, #d0d8e4)",
|
|
5113
|
+
borderRadius: "var(--glyph-radius-md, 0.5rem)",
|
|
5114
|
+
overflow: "hidden"
|
|
5115
|
+
};
|
|
5116
|
+
var headerStyle2 = {
|
|
5117
|
+
fontWeight: 700,
|
|
5118
|
+
fontSize: "1.125rem",
|
|
5119
|
+
padding: "var(--glyph-spacing-md, 1rem)",
|
|
5120
|
+
borderBottom: "1px solid var(--glyph-border, #d0d8e4)",
|
|
5121
|
+
color: "var(--glyph-heading, #0a0e1a)"
|
|
5122
|
+
};
|
|
5123
|
+
var questionStyle = {
|
|
5124
|
+
fontWeight: 600,
|
|
5125
|
+
fontSize: "0.9375rem",
|
|
5126
|
+
padding: "var(--glyph-spacing-md, 1rem)",
|
|
5127
|
+
paddingBottom: "0.5rem"
|
|
5128
|
+
};
|
|
5129
|
+
var optionsStyle = {
|
|
5130
|
+
padding: "0 var(--glyph-spacing-md, 1rem)",
|
|
5131
|
+
paddingBottom: "var(--glyph-spacing-md, 1rem)"
|
|
5132
|
+
};
|
|
5133
|
+
function optionLabelStyle2(selected) {
|
|
5134
|
+
return {
|
|
5135
|
+
display: "flex",
|
|
5136
|
+
alignItems: "center",
|
|
5137
|
+
gap: "0.5rem",
|
|
5138
|
+
padding: "0.5rem 0.75rem",
|
|
5139
|
+
marginBottom: "0.375rem",
|
|
5140
|
+
borderRadius: "var(--glyph-radius-md, 0.5rem)",
|
|
5141
|
+
cursor: "pointer",
|
|
5142
|
+
background: selected ? "var(--glyph-surface, #e8ecf3)" : "transparent",
|
|
5143
|
+
border: "1px solid",
|
|
5144
|
+
borderColor: selected ? "var(--glyph-border, #d0d8e4)" : "transparent",
|
|
5145
|
+
fontSize: "0.875rem",
|
|
5146
|
+
lineHeight: 1.6
|
|
5147
|
+
};
|
|
5148
|
+
}
|
|
5149
|
+
var voteButtonStyle = {
|
|
5150
|
+
margin: "0 var(--glyph-spacing-md, 1rem) var(--glyph-spacing-md, 1rem)",
|
|
5151
|
+
padding: "0.5rem 1.25rem",
|
|
5152
|
+
borderRadius: "var(--glyph-radius-md, 0.5rem)",
|
|
5153
|
+
border: "1px solid var(--glyph-border, #d0d8e4)",
|
|
5154
|
+
background: "var(--glyph-surface, #e8ecf3)",
|
|
5155
|
+
color: "var(--glyph-text, #1a2035)",
|
|
5156
|
+
cursor: "pointer",
|
|
5157
|
+
fontWeight: 600,
|
|
5158
|
+
fontSize: "0.875rem"
|
|
5159
|
+
};
|
|
5160
|
+
var resultsStyle = {
|
|
5161
|
+
padding: "var(--glyph-spacing-md, 1rem)",
|
|
5162
|
+
borderTop: "1px solid var(--glyph-border, #d0d8e4)"
|
|
5163
|
+
};
|
|
5164
|
+
var resultRowStyle = {
|
|
5165
|
+
marginBottom: "0.5rem"
|
|
5166
|
+
};
|
|
5167
|
+
var resultLabelStyle = {
|
|
5168
|
+
display: "flex",
|
|
5169
|
+
justifyContent: "space-between",
|
|
5170
|
+
fontSize: "0.8125rem",
|
|
5171
|
+
marginBottom: "0.25rem"
|
|
5172
|
+
};
|
|
5173
|
+
var barTrackStyle = {
|
|
5174
|
+
height: "0.5rem",
|
|
5175
|
+
borderRadius: "0.25rem",
|
|
5176
|
+
background: "var(--glyph-poll-bar-bg, var(--glyph-surface, #e8ecf3))",
|
|
5177
|
+
overflow: "hidden"
|
|
5178
|
+
};
|
|
5179
|
+
function barFillStyle(percentage) {
|
|
5180
|
+
return {
|
|
5181
|
+
height: "100%",
|
|
5182
|
+
width: `${String(percentage)}%`,
|
|
5183
|
+
borderRadius: "0.25rem",
|
|
5184
|
+
background: "var(--glyph-poll-bar-fill, var(--glyph-accent, #0a9d7c))",
|
|
5185
|
+
transition: "width 0.3s ease"
|
|
5186
|
+
};
|
|
5187
|
+
}
|
|
5188
|
+
function Poll({ data, block, onInteraction }) {
|
|
5189
|
+
const { question, options, multiple = false, showResults = true, title } = data;
|
|
5190
|
+
const baseId = `glyph-poll-${block.id}`;
|
|
5191
|
+
const [selected, setSelected] = useState([]);
|
|
5192
|
+
const [votes, setVotes] = useState(() => options.map(() => 0));
|
|
5193
|
+
const [hasVoted, setHasVoted] = useState(false);
|
|
5194
|
+
const toggleOption = (index) => {
|
|
5195
|
+
if (hasVoted) return;
|
|
5196
|
+
if (multiple) {
|
|
5197
|
+
setSelected(
|
|
5198
|
+
(prev) => prev.includes(index) ? prev.filter((i) => i !== index) : [...prev, index]
|
|
5199
|
+
);
|
|
5200
|
+
} else {
|
|
5201
|
+
setSelected([index]);
|
|
5202
|
+
}
|
|
5203
|
+
};
|
|
5204
|
+
const handleVote = () => {
|
|
5205
|
+
if (selected.length === 0 || hasVoted) return;
|
|
5206
|
+
const newVotes = [...votes];
|
|
5207
|
+
for (const idx of selected) {
|
|
5208
|
+
newVotes[idx] = (newVotes[idx] ?? 0) + 1;
|
|
5209
|
+
}
|
|
5210
|
+
setVotes(newVotes);
|
|
5211
|
+
setHasVoted(true);
|
|
5212
|
+
if (onInteraction) {
|
|
5213
|
+
onInteraction({
|
|
5214
|
+
kind: "poll-vote",
|
|
5215
|
+
timestamp: (/* @__PURE__ */ new Date()).toISOString(),
|
|
5216
|
+
blockId: block.id,
|
|
5217
|
+
blockType: block.type,
|
|
5218
|
+
payload: {
|
|
5219
|
+
selectedOptions: selected.map((i) => options[i] ?? String(i)),
|
|
5220
|
+
selectedIndices: [...selected]
|
|
5221
|
+
}
|
|
5222
|
+
});
|
|
5223
|
+
}
|
|
5224
|
+
};
|
|
5225
|
+
const totalVotes = votes.reduce((a, b) => a + b, 0);
|
|
5226
|
+
return /* @__PURE__ */ jsxs("div", { id: baseId, role: "region", "aria-label": title ?? "Poll", style: containerStyle3, children: [
|
|
5227
|
+
title && /* @__PURE__ */ jsx("div", { style: headerStyle2, children: title }),
|
|
5228
|
+
/* @__PURE__ */ jsx("div", { style: questionStyle, children: question }),
|
|
5229
|
+
/* @__PURE__ */ jsx("div", { role: "group", "aria-label": question, style: optionsStyle, children: options.map((option, index) => /* @__PURE__ */ jsxs("label", { style: optionLabelStyle2(selected.includes(index)), children: [
|
|
5230
|
+
/* @__PURE__ */ jsx(
|
|
5231
|
+
"input",
|
|
5232
|
+
{
|
|
5233
|
+
type: multiple ? "checkbox" : "radio",
|
|
5234
|
+
name: `${baseId}-option`,
|
|
5235
|
+
checked: selected.includes(index),
|
|
5236
|
+
disabled: hasVoted,
|
|
5237
|
+
onChange: () => toggleOption(index),
|
|
5238
|
+
"aria-checked": selected.includes(index)
|
|
5239
|
+
}
|
|
5240
|
+
),
|
|
5241
|
+
option
|
|
5242
|
+
] }, index)) }),
|
|
5243
|
+
!hasVoted && /* @__PURE__ */ jsx(
|
|
5244
|
+
"button",
|
|
5245
|
+
{
|
|
5246
|
+
type: "button",
|
|
5247
|
+
disabled: selected.length === 0,
|
|
5248
|
+
style: {
|
|
5249
|
+
...voteButtonStyle,
|
|
5250
|
+
opacity: selected.length === 0 ? 0.5 : 1,
|
|
5251
|
+
cursor: selected.length === 0 ? "not-allowed" : "pointer"
|
|
5252
|
+
},
|
|
5253
|
+
onClick: handleVote,
|
|
5254
|
+
children: "Vote"
|
|
5255
|
+
}
|
|
5256
|
+
),
|
|
5257
|
+
showResults && hasVoted && /* @__PURE__ */ jsx("div", { role: "status", "aria-live": "polite", style: resultsStyle, children: options.map((option, index) => {
|
|
5258
|
+
const count = votes[index] ?? 0;
|
|
5259
|
+
const percentage = totalVotes > 0 ? count / totalVotes * 100 : 0;
|
|
5260
|
+
return /* @__PURE__ */ jsxs("div", { style: resultRowStyle, children: [
|
|
5261
|
+
/* @__PURE__ */ jsxs("div", { style: resultLabelStyle, children: [
|
|
5262
|
+
/* @__PURE__ */ jsx("span", { children: option }),
|
|
5263
|
+
/* @__PURE__ */ jsxs("span", { children: [
|
|
5264
|
+
String(count),
|
|
5265
|
+
" vote",
|
|
5266
|
+
count !== 1 ? "s" : "",
|
|
5267
|
+
" (",
|
|
5268
|
+
String(Math.round(percentage)),
|
|
5269
|
+
"%)"
|
|
5270
|
+
] })
|
|
5271
|
+
] }),
|
|
5272
|
+
/* @__PURE__ */ jsx(
|
|
5273
|
+
"div",
|
|
5274
|
+
{
|
|
5275
|
+
style: barTrackStyle,
|
|
5276
|
+
role: "progressbar",
|
|
5277
|
+
"aria-valuenow": percentage,
|
|
5278
|
+
"aria-valuemin": 0,
|
|
5279
|
+
"aria-valuemax": 100,
|
|
5280
|
+
"aria-label": `${option}: ${String(Math.round(percentage))}%`,
|
|
5281
|
+
children: /* @__PURE__ */ jsx("div", { style: barFillStyle(percentage) })
|
|
5282
|
+
}
|
|
5283
|
+
)
|
|
5284
|
+
] }, index);
|
|
5285
|
+
}) })
|
|
5286
|
+
] });
|
|
5287
|
+
}
|
|
5288
|
+
|
|
5289
|
+
// src/poll/index.ts
|
|
5290
|
+
var pollDefinition = {
|
|
5291
|
+
type: "ui:poll",
|
|
5292
|
+
schema: pollSchema,
|
|
5293
|
+
render: Poll
|
|
5294
|
+
};
|
|
5295
|
+
|
|
5296
|
+
// src/rating/styles.ts
|
|
5297
|
+
var containerStyle4 = {
|
|
5298
|
+
fontFamily: "var(--glyph-font-body, system-ui, sans-serif)",
|
|
5299
|
+
color: "var(--glyph-text, #1a2035)",
|
|
5300
|
+
border: "1px solid var(--glyph-border, #d0d8e4)",
|
|
5301
|
+
borderRadius: "var(--glyph-radius-md, 0.5rem)",
|
|
5302
|
+
overflow: "hidden"
|
|
5303
|
+
};
|
|
5304
|
+
var headerStyle3 = {
|
|
5305
|
+
fontWeight: 700,
|
|
5306
|
+
fontSize: "1.125rem",
|
|
5307
|
+
padding: "var(--glyph-spacing-md, 1rem)",
|
|
5308
|
+
borderBottom: "1px solid var(--glyph-border, #d0d8e4)",
|
|
5309
|
+
color: "var(--glyph-heading, #0a0e1a)"
|
|
5310
|
+
};
|
|
5311
|
+
function itemStyle2(isLast) {
|
|
5312
|
+
return {
|
|
5313
|
+
padding: "var(--glyph-spacing-md, 1rem)",
|
|
5314
|
+
borderBottom: isLast ? "none" : "1px solid var(--glyph-border, #d0d8e4)"
|
|
5315
|
+
};
|
|
5316
|
+
}
|
|
5317
|
+
var itemLabelStyle = {
|
|
5318
|
+
fontWeight: 600,
|
|
5319
|
+
fontSize: "0.9375rem",
|
|
5320
|
+
marginBottom: "0.25rem"
|
|
5321
|
+
};
|
|
5322
|
+
var itemDescriptionStyle = {
|
|
5323
|
+
fontSize: "0.8125rem",
|
|
5324
|
+
color: "var(--glyph-text-muted, #6b7a94)",
|
|
5325
|
+
marginBottom: "0.5rem"
|
|
5326
|
+
};
|
|
5327
|
+
var starsContainerStyle = {
|
|
5328
|
+
display: "flex",
|
|
5329
|
+
gap: "0.25rem",
|
|
5330
|
+
alignItems: "center"
|
|
5331
|
+
};
|
|
5332
|
+
function starButtonStyle(filled, hovered) {
|
|
5333
|
+
return {
|
|
5334
|
+
background: "none",
|
|
5335
|
+
border: "none",
|
|
5336
|
+
padding: "0.125rem",
|
|
5337
|
+
cursor: "pointer",
|
|
5338
|
+
fontSize: "1.25rem",
|
|
5339
|
+
lineHeight: 1,
|
|
5340
|
+
color: filled || hovered ? "var(--glyph-rating-star-fill, #f59e0b)" : "var(--glyph-rating-star-empty, var(--glyph-border, #d0d8e4))",
|
|
5341
|
+
transition: "color 0.15s ease"
|
|
5342
|
+
};
|
|
5343
|
+
}
|
|
5344
|
+
function numberButtonStyle(selected) {
|
|
5345
|
+
return {
|
|
5346
|
+
minWidth: "2rem",
|
|
5347
|
+
height: "2rem",
|
|
5348
|
+
display: "flex",
|
|
5349
|
+
alignItems: "center",
|
|
5350
|
+
justifyContent: "center",
|
|
5351
|
+
borderRadius: "var(--glyph-radius-sm, 0.375rem)",
|
|
5352
|
+
border: "1px solid var(--glyph-border, #d0d8e4)",
|
|
5353
|
+
background: selected ? "var(--glyph-accent, #0a9d7c)" : "transparent",
|
|
5354
|
+
color: selected ? "#fff" : "var(--glyph-text, #1a2035)",
|
|
5355
|
+
cursor: "pointer",
|
|
5356
|
+
fontWeight: 600,
|
|
5357
|
+
fontSize: "0.875rem",
|
|
5358
|
+
transition: "background 0.15s ease, color 0.15s ease"
|
|
5359
|
+
};
|
|
5360
|
+
}
|
|
5361
|
+
var scaleLabelsStyle = {
|
|
5362
|
+
display: "flex",
|
|
5363
|
+
justifyContent: "space-between",
|
|
5364
|
+
fontSize: "0.75rem",
|
|
5365
|
+
color: "var(--glyph-text-muted, #6b7a94)",
|
|
5366
|
+
marginTop: "0.375rem"
|
|
5367
|
+
};
|
|
5368
|
+
function Rating({
|
|
5369
|
+
data,
|
|
5370
|
+
block,
|
|
5371
|
+
onInteraction
|
|
5372
|
+
}) {
|
|
5373
|
+
const { title, scale = 5, mode = "star", labels, items } = data;
|
|
5374
|
+
const baseId = `glyph-rating-${block.id}`;
|
|
5375
|
+
const [ratings, setRatings] = useState(() => items.map(() => null));
|
|
5376
|
+
const [hoveredStar, setHoveredStar] = useState(null);
|
|
5377
|
+
const handleRate = (itemIndex, value) => {
|
|
5378
|
+
const newRatings = [...ratings];
|
|
5379
|
+
newRatings[itemIndex] = value;
|
|
5380
|
+
setRatings(newRatings);
|
|
5381
|
+
if (onInteraction) {
|
|
5382
|
+
onInteraction({
|
|
5383
|
+
kind: "rating-change",
|
|
5384
|
+
timestamp: (/* @__PURE__ */ new Date()).toISOString(),
|
|
5385
|
+
blockId: block.id,
|
|
5386
|
+
blockType: block.type,
|
|
5387
|
+
payload: {
|
|
5388
|
+
itemIndex,
|
|
5389
|
+
itemLabel: items[itemIndex]?.label ?? "",
|
|
5390
|
+
value,
|
|
5391
|
+
allRatings: items.map((item, i) => ({
|
|
5392
|
+
label: item.label,
|
|
5393
|
+
value: i === itemIndex ? value : newRatings[i] ?? null
|
|
5394
|
+
}))
|
|
5395
|
+
}
|
|
5396
|
+
});
|
|
5397
|
+
}
|
|
5398
|
+
};
|
|
5399
|
+
return /* @__PURE__ */ jsxs("div", { id: baseId, role: "region", "aria-label": title ?? "Rating", style: containerStyle4, children: [
|
|
5400
|
+
title && /* @__PURE__ */ jsx("div", { style: headerStyle3, children: title }),
|
|
5401
|
+
items.map((item, itemIndex) => {
|
|
5402
|
+
const currentRating = ratings[itemIndex] ?? null;
|
|
5403
|
+
const isLast = itemIndex === items.length - 1;
|
|
5404
|
+
return /* @__PURE__ */ jsxs("div", { style: itemStyle2(isLast), children: [
|
|
5405
|
+
/* @__PURE__ */ jsx("div", { style: itemLabelStyle, children: item.label }),
|
|
5406
|
+
item.description && /* @__PURE__ */ jsx("div", { style: itemDescriptionStyle, children: item.description }),
|
|
5407
|
+
/* @__PURE__ */ jsx("div", { role: "radiogroup", "aria-label": `Rate ${item.label}`, style: starsContainerStyle, children: Array.from({ length: scale }, (_, starIndex) => {
|
|
5408
|
+
const value = starIndex + 1;
|
|
5409
|
+
const isHovered = hoveredStar !== null && hoveredStar.itemIndex === itemIndex && value <= hoveredStar.value;
|
|
5410
|
+
const isFilled = currentRating !== null && value <= currentRating;
|
|
5411
|
+
if (mode === "number") {
|
|
5412
|
+
return /* @__PURE__ */ jsx(
|
|
5413
|
+
"button",
|
|
5414
|
+
{
|
|
5415
|
+
type: "button",
|
|
5416
|
+
role: "radio",
|
|
5417
|
+
"aria-checked": currentRating === value,
|
|
5418
|
+
"aria-label": `${String(value)} out of ${String(scale)}`,
|
|
5419
|
+
style: numberButtonStyle(currentRating === value),
|
|
5420
|
+
onClick: () => handleRate(itemIndex, value),
|
|
5421
|
+
children: String(value)
|
|
5422
|
+
},
|
|
5423
|
+
starIndex
|
|
5424
|
+
);
|
|
5425
|
+
}
|
|
5426
|
+
return /* @__PURE__ */ jsx(
|
|
5427
|
+
"button",
|
|
5428
|
+
{
|
|
5429
|
+
type: "button",
|
|
5430
|
+
role: "radio",
|
|
5431
|
+
"aria-checked": currentRating === value,
|
|
5432
|
+
"aria-label": `${String(value)} out of ${String(scale)} stars`,
|
|
5433
|
+
style: starButtonStyle(isFilled, isHovered),
|
|
5434
|
+
onClick: () => handleRate(itemIndex, value),
|
|
5435
|
+
onMouseEnter: () => setHoveredStar({ itemIndex, value }),
|
|
5436
|
+
onMouseLeave: () => setHoveredStar(null),
|
|
5437
|
+
children: "\u2605"
|
|
5438
|
+
},
|
|
5439
|
+
starIndex
|
|
5440
|
+
);
|
|
5441
|
+
}) }),
|
|
5442
|
+
labels && /* @__PURE__ */ jsxs("div", { style: scaleLabelsStyle, children: [
|
|
5443
|
+
/* @__PURE__ */ jsx("span", { children: labels.low }),
|
|
5444
|
+
/* @__PURE__ */ jsx("span", { children: labels.high })
|
|
5445
|
+
] }),
|
|
5446
|
+
/* @__PURE__ */ jsx(
|
|
5447
|
+
"div",
|
|
5448
|
+
{
|
|
5449
|
+
"aria-live": "polite",
|
|
5450
|
+
style: {
|
|
5451
|
+
position: "absolute",
|
|
5452
|
+
width: "1px",
|
|
5453
|
+
height: "1px",
|
|
5454
|
+
padding: 0,
|
|
5455
|
+
margin: "-1px",
|
|
5456
|
+
overflow: "hidden",
|
|
5457
|
+
clip: "rect(0,0,0,0)",
|
|
5458
|
+
whiteSpace: "nowrap",
|
|
5459
|
+
border: 0
|
|
5460
|
+
},
|
|
5461
|
+
children: currentRating !== null && `${item.label} rated ${String(currentRating)} out of ${String(scale)}`
|
|
5462
|
+
}
|
|
5463
|
+
)
|
|
5464
|
+
] }, itemIndex);
|
|
5465
|
+
})
|
|
5466
|
+
] });
|
|
5467
|
+
}
|
|
5468
|
+
|
|
5469
|
+
// src/rating/index.ts
|
|
5470
|
+
var ratingDefinition = {
|
|
5471
|
+
type: "ui:rating",
|
|
5472
|
+
schema: ratingSchema,
|
|
5473
|
+
render: Rating
|
|
5474
|
+
};
|
|
5475
|
+
|
|
5476
|
+
// src/ranker/styles.ts
|
|
5477
|
+
var containerStyle5 = {
|
|
5478
|
+
fontFamily: "var(--glyph-font-body, system-ui, sans-serif)",
|
|
5479
|
+
color: "var(--glyph-text, #1a2035)",
|
|
5480
|
+
border: "1px solid var(--glyph-border, #d0d8e4)",
|
|
5481
|
+
borderRadius: "var(--glyph-radius-md, 0.5rem)",
|
|
5482
|
+
overflow: "hidden"
|
|
5483
|
+
};
|
|
5484
|
+
var headerStyle4 = {
|
|
5485
|
+
fontWeight: 700,
|
|
5486
|
+
fontSize: "1.125rem",
|
|
5487
|
+
padding: "var(--glyph-spacing-md, 1rem)",
|
|
5488
|
+
borderBottom: "1px solid var(--glyph-border, #d0d8e4)",
|
|
5489
|
+
color: "var(--glyph-heading, #0a0e1a)"
|
|
5490
|
+
};
|
|
5491
|
+
var listStyle = {
|
|
5492
|
+
listStyle: "none",
|
|
5493
|
+
margin: 0,
|
|
5494
|
+
padding: 0
|
|
5495
|
+
};
|
|
5496
|
+
function itemStyle3(isDragging, isGrabbed) {
|
|
5497
|
+
return {
|
|
5498
|
+
display: "flex",
|
|
5499
|
+
alignItems: "center",
|
|
5500
|
+
gap: "0.75rem",
|
|
5501
|
+
padding: "0.75rem var(--glyph-spacing-md, 1rem)",
|
|
5502
|
+
borderBottom: "1px solid var(--glyph-border, #d0d8e4)",
|
|
5503
|
+
background: isDragging ? "var(--glyph-accent-subtle, #e6f6f2)" : "transparent",
|
|
5504
|
+
cursor: isGrabbed ? "grabbing" : "grab",
|
|
5505
|
+
userSelect: "none",
|
|
5506
|
+
transition: "background 0.15s ease",
|
|
5507
|
+
outline: isGrabbed ? "2px solid var(--glyph-accent, #0a9d7c)" : "none",
|
|
5508
|
+
outlineOffset: "-2px"
|
|
5509
|
+
};
|
|
5510
|
+
}
|
|
5511
|
+
var rankBadgeStyle = {
|
|
5512
|
+
minWidth: "1.75rem",
|
|
5513
|
+
height: "1.75rem",
|
|
5514
|
+
display: "flex",
|
|
5515
|
+
alignItems: "center",
|
|
5516
|
+
justifyContent: "center",
|
|
5517
|
+
borderRadius: "50%",
|
|
5518
|
+
background: "var(--glyph-surface, #e8ecf3)",
|
|
5519
|
+
fontWeight: 700,
|
|
5520
|
+
fontSize: "0.8125rem",
|
|
5521
|
+
color: "var(--glyph-text-muted, #6b7a94)",
|
|
5522
|
+
flexShrink: 0
|
|
5523
|
+
};
|
|
5524
|
+
var itemContentStyle = {
|
|
5525
|
+
flex: 1,
|
|
5526
|
+
minWidth: 0
|
|
5527
|
+
};
|
|
5528
|
+
var itemLabelStyle2 = {
|
|
5529
|
+
fontWeight: 600,
|
|
5530
|
+
fontSize: "0.9375rem"
|
|
5531
|
+
};
|
|
5532
|
+
var itemDescriptionStyle2 = {
|
|
5533
|
+
fontSize: "0.8125rem",
|
|
5534
|
+
color: "var(--glyph-text-muted, #6b7a94)",
|
|
5535
|
+
marginTop: "0.125rem"
|
|
5536
|
+
};
|
|
5537
|
+
var gripStyle = {
|
|
5538
|
+
color: "var(--glyph-text-muted, #6b7a94)",
|
|
5539
|
+
fontSize: "1rem",
|
|
5540
|
+
flexShrink: 0
|
|
5541
|
+
};
|
|
5542
|
+
function Ranker({
|
|
5543
|
+
data,
|
|
5544
|
+
block,
|
|
5545
|
+
onInteraction
|
|
5546
|
+
}) {
|
|
5547
|
+
const { title, items: initialItems } = data;
|
|
5548
|
+
const baseId = `glyph-ranker-${block.id}`;
|
|
5549
|
+
const [items, setItems] = useState(initialItems);
|
|
5550
|
+
const [grabbedIndex, setGrabbedIndex] = useState(null);
|
|
5551
|
+
const moveItem = useCallback(
|
|
5552
|
+
(fromIndex, toIndex) => {
|
|
5553
|
+
if (fromIndex === toIndex) return;
|
|
5554
|
+
setItems((prevItems) => {
|
|
5555
|
+
const newItems = [...prevItems];
|
|
5556
|
+
const [moved] = newItems.splice(fromIndex, 1);
|
|
5557
|
+
if (!moved) return prevItems;
|
|
5558
|
+
newItems.splice(toIndex, 0, moved);
|
|
5559
|
+
if (onInteraction) {
|
|
5560
|
+
onInteraction({
|
|
5561
|
+
kind: "ranker-reorder",
|
|
5562
|
+
timestamp: (/* @__PURE__ */ new Date()).toISOString(),
|
|
5563
|
+
blockId: block.id,
|
|
5564
|
+
blockType: block.type,
|
|
5565
|
+
payload: {
|
|
5566
|
+
orderedItems: newItems.map((item, i) => ({
|
|
5567
|
+
id: item.id,
|
|
5568
|
+
label: item.label,
|
|
5569
|
+
rank: i + 1
|
|
5570
|
+
})),
|
|
5571
|
+
movedItem: {
|
|
5572
|
+
id: moved.id,
|
|
5573
|
+
label: moved.label,
|
|
5574
|
+
fromRank: fromIndex + 1,
|
|
5575
|
+
toRank: toIndex + 1
|
|
5576
|
+
}
|
|
5577
|
+
}
|
|
5578
|
+
});
|
|
5579
|
+
}
|
|
5580
|
+
return newItems;
|
|
5581
|
+
});
|
|
5582
|
+
},
|
|
5583
|
+
[block.id, block.type, onInteraction]
|
|
5584
|
+
);
|
|
5585
|
+
const handleKeyDown = (e, index) => {
|
|
5586
|
+
if (e.key === " " || e.key === "Enter") {
|
|
5587
|
+
e.preventDefault();
|
|
5588
|
+
if (grabbedIndex === null) {
|
|
5589
|
+
setGrabbedIndex(index);
|
|
5590
|
+
} else {
|
|
5591
|
+
setGrabbedIndex(null);
|
|
5592
|
+
}
|
|
5593
|
+
} else if (e.key === "Escape") {
|
|
5594
|
+
setGrabbedIndex(null);
|
|
5595
|
+
} else if (e.key === "ArrowUp" && grabbedIndex !== null) {
|
|
5596
|
+
e.preventDefault();
|
|
5597
|
+
if (grabbedIndex > 0) {
|
|
5598
|
+
moveItem(grabbedIndex, grabbedIndex - 1);
|
|
5599
|
+
setGrabbedIndex(grabbedIndex - 1);
|
|
5600
|
+
}
|
|
5601
|
+
} else if (e.key === "ArrowDown" && grabbedIndex !== null) {
|
|
5602
|
+
e.preventDefault();
|
|
5603
|
+
if (grabbedIndex < items.length - 1) {
|
|
5604
|
+
moveItem(grabbedIndex, grabbedIndex + 1);
|
|
5605
|
+
setGrabbedIndex(grabbedIndex + 1);
|
|
5606
|
+
}
|
|
5607
|
+
}
|
|
5608
|
+
};
|
|
5609
|
+
return /* @__PURE__ */ jsxs("div", { id: baseId, role: "region", "aria-label": title ?? "Ranker", style: containerStyle5, children: [
|
|
5610
|
+
title && /* @__PURE__ */ jsx("div", { style: headerStyle4, children: title }),
|
|
5611
|
+
/* @__PURE__ */ jsx("ul", { role: "list", "aria-label": title ?? "Rank items", style: listStyle, children: items.map((item, index) => /* @__PURE__ */ jsxs(
|
|
5612
|
+
"li",
|
|
5613
|
+
{
|
|
5614
|
+
role: "listitem",
|
|
5615
|
+
"aria-grabbed": grabbedIndex === index,
|
|
5616
|
+
"aria-label": `${item.label}, rank ${String(index + 1)}`,
|
|
5617
|
+
tabIndex: 0,
|
|
5618
|
+
style: itemStyle3(false, grabbedIndex === index),
|
|
5619
|
+
onKeyDown: (e) => handleKeyDown(e, index),
|
|
5620
|
+
children: [
|
|
5621
|
+
/* @__PURE__ */ jsx("span", { style: gripStyle, "aria-hidden": "true", children: "\u283F" }),
|
|
5622
|
+
/* @__PURE__ */ jsx("span", { style: rankBadgeStyle, children: String(index + 1) }),
|
|
5623
|
+
/* @__PURE__ */ jsxs("div", { style: itemContentStyle, children: [
|
|
5624
|
+
/* @__PURE__ */ jsx("div", { style: itemLabelStyle2, children: item.label }),
|
|
5625
|
+
item.description && /* @__PURE__ */ jsx("div", { style: itemDescriptionStyle2, children: item.description })
|
|
5626
|
+
] })
|
|
5627
|
+
]
|
|
5628
|
+
},
|
|
5629
|
+
item.id
|
|
5630
|
+
)) }),
|
|
5631
|
+
/* @__PURE__ */ jsx(
|
|
5632
|
+
"div",
|
|
5633
|
+
{
|
|
5634
|
+
"aria-live": "assertive",
|
|
5635
|
+
style: {
|
|
5636
|
+
position: "absolute",
|
|
5637
|
+
width: "1px",
|
|
5638
|
+
height: "1px",
|
|
5639
|
+
padding: 0,
|
|
5640
|
+
margin: "-1px",
|
|
5641
|
+
overflow: "hidden",
|
|
5642
|
+
clip: "rect(0,0,0,0)",
|
|
5643
|
+
whiteSpace: "nowrap",
|
|
5644
|
+
border: 0
|
|
5645
|
+
},
|
|
5646
|
+
children: grabbedIndex !== null && `${items[grabbedIndex]?.label ?? ""} grabbed, rank ${String(grabbedIndex + 1)} of ${String(items.length)}. Use arrow keys to move.`
|
|
5647
|
+
}
|
|
5648
|
+
)
|
|
5649
|
+
] });
|
|
5650
|
+
}
|
|
5651
|
+
|
|
5652
|
+
// src/ranker/index.ts
|
|
5653
|
+
var rankerDefinition = {
|
|
5654
|
+
type: "ui:ranker",
|
|
5655
|
+
schema: rankerSchema,
|
|
5656
|
+
render: Ranker
|
|
5657
|
+
};
|
|
5658
|
+
|
|
5659
|
+
// src/slider/styles.ts
|
|
5660
|
+
var containerStyle6 = {
|
|
5661
|
+
fontFamily: "var(--glyph-font-body, system-ui, sans-serif)",
|
|
5662
|
+
color: "var(--glyph-text, #1a2035)",
|
|
5663
|
+
border: "1px solid var(--glyph-border, #d0d8e4)",
|
|
5664
|
+
borderRadius: "var(--glyph-radius-md, 0.5rem)",
|
|
5665
|
+
overflow: "hidden"
|
|
5666
|
+
};
|
|
5667
|
+
var headerStyle5 = {
|
|
5668
|
+
fontWeight: 700,
|
|
5669
|
+
fontSize: "1.125rem",
|
|
5670
|
+
padding: "var(--glyph-spacing-md, 1rem)",
|
|
5671
|
+
borderBottom: "1px solid var(--glyph-border, #d0d8e4)",
|
|
5672
|
+
color: "var(--glyph-heading, #0a0e1a)"
|
|
5673
|
+
};
|
|
5674
|
+
function parameterStyle(isLast) {
|
|
5675
|
+
return {
|
|
5676
|
+
padding: "var(--glyph-spacing-md, 1rem)",
|
|
5677
|
+
borderBottom: isLast ? "none" : "1px solid var(--glyph-border, #d0d8e4)"
|
|
5678
|
+
};
|
|
5679
|
+
}
|
|
5680
|
+
var parameterHeaderStyle = {
|
|
5681
|
+
display: "flex",
|
|
5682
|
+
justifyContent: "space-between",
|
|
5683
|
+
alignItems: "center",
|
|
5684
|
+
marginBottom: "0.5rem"
|
|
5685
|
+
};
|
|
5686
|
+
var parameterLabelStyle = {
|
|
5687
|
+
fontWeight: 600,
|
|
5688
|
+
fontSize: "0.9375rem"
|
|
5689
|
+
};
|
|
5690
|
+
var parameterValueStyle = {
|
|
5691
|
+
fontSize: "0.9375rem",
|
|
5692
|
+
fontWeight: 600,
|
|
5693
|
+
color: "var(--glyph-accent, #0a9d7c)",
|
|
5694
|
+
fontVariantNumeric: "tabular-nums"
|
|
5695
|
+
};
|
|
5696
|
+
var rangeInputStyle = {
|
|
5697
|
+
width: "100%",
|
|
5698
|
+
margin: 0,
|
|
5699
|
+
accentColor: "var(--glyph-slider-fill, var(--glyph-accent, #0a9d7c))"
|
|
5700
|
+
};
|
|
5701
|
+
var rangeLabelsStyle = {
|
|
5702
|
+
display: "flex",
|
|
5703
|
+
justifyContent: "space-between",
|
|
5704
|
+
fontSize: "0.75rem",
|
|
5705
|
+
color: "var(--glyph-text-muted, #6b7a94)",
|
|
5706
|
+
marginTop: "0.25rem"
|
|
5707
|
+
};
|
|
5708
|
+
function Slider({
|
|
5709
|
+
data,
|
|
5710
|
+
block,
|
|
5711
|
+
onInteraction
|
|
5712
|
+
}) {
|
|
5713
|
+
const { title, parameters } = data;
|
|
5714
|
+
const baseId = `glyph-slider-${block.id}`;
|
|
5715
|
+
const [values, setValues] = useState(
|
|
5716
|
+
() => parameters.map((p) => p.value ?? p.min ?? 0)
|
|
5717
|
+
);
|
|
5718
|
+
const handleChange = (paramIndex, newValue) => {
|
|
5719
|
+
const newValues = [...values];
|
|
5720
|
+
newValues[paramIndex] = newValue;
|
|
5721
|
+
setValues(newValues);
|
|
5722
|
+
const param = parameters[paramIndex];
|
|
5723
|
+
if (!param) return;
|
|
5724
|
+
if (onInteraction) {
|
|
5725
|
+
onInteraction({
|
|
5726
|
+
kind: "slider-change",
|
|
5727
|
+
timestamp: (/* @__PURE__ */ new Date()).toISOString(),
|
|
5728
|
+
blockId: block.id,
|
|
5729
|
+
blockType: block.type,
|
|
5730
|
+
payload: {
|
|
5731
|
+
parameterId: param.id,
|
|
5732
|
+
parameterLabel: param.label,
|
|
5733
|
+
value: newValue,
|
|
5734
|
+
allValues: parameters.map((p, i) => ({
|
|
5735
|
+
id: p.id,
|
|
5736
|
+
label: p.label,
|
|
5737
|
+
value: i === paramIndex ? newValue : newValues[i] ?? 0
|
|
5738
|
+
}))
|
|
5739
|
+
}
|
|
5740
|
+
});
|
|
5741
|
+
}
|
|
5742
|
+
};
|
|
5743
|
+
const formatValue = (value, unit) => {
|
|
5744
|
+
return unit ? `${String(value)}${unit}` : String(value);
|
|
5745
|
+
};
|
|
5746
|
+
return /* @__PURE__ */ jsxs("div", { id: baseId, role: "region", "aria-label": title ?? "Slider", style: containerStyle6, children: [
|
|
5747
|
+
title && /* @__PURE__ */ jsx("div", { style: headerStyle5, children: title }),
|
|
5748
|
+
parameters.map((param, index) => {
|
|
5749
|
+
const min2 = param.min ?? 0;
|
|
5750
|
+
const max2 = param.max ?? 100;
|
|
5751
|
+
const step = param.step ?? 1;
|
|
5752
|
+
const currentValue = values[index] ?? min2;
|
|
5753
|
+
const isLast = index === parameters.length - 1;
|
|
5754
|
+
return /* @__PURE__ */ jsxs("div", { style: parameterStyle(isLast), children: [
|
|
5755
|
+
/* @__PURE__ */ jsxs("div", { style: parameterHeaderStyle, children: [
|
|
5756
|
+
/* @__PURE__ */ jsx("label", { htmlFor: `${baseId}-${param.id}`, style: parameterLabelStyle, children: param.label }),
|
|
5757
|
+
/* @__PURE__ */ jsx("span", { style: parameterValueStyle, "aria-live": "polite", children: formatValue(currentValue, param.unit) })
|
|
5758
|
+
] }),
|
|
5759
|
+
/* @__PURE__ */ jsx(
|
|
5760
|
+
"input",
|
|
5761
|
+
{
|
|
5762
|
+
id: `${baseId}-${param.id}`,
|
|
5763
|
+
type: "range",
|
|
5764
|
+
min: min2,
|
|
5765
|
+
max: max2,
|
|
5766
|
+
step,
|
|
5767
|
+
value: currentValue,
|
|
5768
|
+
onChange: (e) => handleChange(index, Number(e.target.value)),
|
|
5769
|
+
"aria-valuemin": min2,
|
|
5770
|
+
"aria-valuemax": max2,
|
|
5771
|
+
"aria-valuenow": currentValue,
|
|
5772
|
+
"aria-valuetext": formatValue(currentValue, param.unit),
|
|
5773
|
+
style: rangeInputStyle
|
|
5774
|
+
}
|
|
5775
|
+
),
|
|
5776
|
+
/* @__PURE__ */ jsxs("div", { style: rangeLabelsStyle, children: [
|
|
5777
|
+
/* @__PURE__ */ jsx("span", { children: formatValue(min2, param.unit) }),
|
|
5778
|
+
/* @__PURE__ */ jsx("span", { children: formatValue(max2, param.unit) })
|
|
5779
|
+
] })
|
|
5780
|
+
] }, param.id);
|
|
5781
|
+
})
|
|
5782
|
+
] });
|
|
5783
|
+
}
|
|
5784
|
+
|
|
5785
|
+
// src/slider/index.ts
|
|
5786
|
+
var sliderDefinition = {
|
|
5787
|
+
type: "ui:slider",
|
|
5788
|
+
schema: sliderSchema,
|
|
5789
|
+
render: Slider
|
|
5790
|
+
};
|
|
5791
|
+
|
|
5792
|
+
// src/matrix/styles.ts
|
|
5793
|
+
var containerStyle7 = {
|
|
5794
|
+
fontFamily: "var(--glyph-font-body, system-ui, sans-serif)",
|
|
5795
|
+
color: "var(--glyph-text, #1a2035)",
|
|
5796
|
+
border: "1px solid var(--glyph-border, #d0d8e4)",
|
|
5797
|
+
borderRadius: "var(--glyph-radius-md, 0.5rem)",
|
|
5798
|
+
overflow: "auto"
|
|
5799
|
+
};
|
|
5800
|
+
var headerStyle6 = {
|
|
5801
|
+
fontWeight: 700,
|
|
5802
|
+
fontSize: "1.125rem",
|
|
5803
|
+
padding: "var(--glyph-spacing-md, 1rem)",
|
|
5804
|
+
borderBottom: "1px solid var(--glyph-border, #d0d8e4)",
|
|
5805
|
+
color: "var(--glyph-heading, #0a0e1a)"
|
|
5806
|
+
};
|
|
5807
|
+
var tableStyle = {
|
|
5808
|
+
width: "100%",
|
|
5809
|
+
borderCollapse: "collapse",
|
|
5810
|
+
fontSize: "0.875rem"
|
|
5811
|
+
};
|
|
5812
|
+
var thStyle = {
|
|
5813
|
+
padding: "0.625rem 0.75rem",
|
|
5814
|
+
textAlign: "center",
|
|
5815
|
+
fontWeight: 600,
|
|
5816
|
+
borderBottom: "2px solid var(--glyph-border, #d0d8e4)",
|
|
5817
|
+
background: "var(--glyph-table-header-bg, var(--glyph-surface, #e8ecf3))",
|
|
5818
|
+
whiteSpace: "nowrap"
|
|
5819
|
+
};
|
|
5820
|
+
var rowHeaderStyle = {
|
|
5821
|
+
padding: "0.625rem 0.75rem",
|
|
5822
|
+
textAlign: "left",
|
|
5823
|
+
fontWeight: 600,
|
|
5824
|
+
borderBottom: "1px solid var(--glyph-border, #d0d8e4)",
|
|
5825
|
+
borderRight: "1px solid var(--glyph-border, #d0d8e4)",
|
|
5826
|
+
whiteSpace: "nowrap"
|
|
5827
|
+
};
|
|
5828
|
+
var cellStyle = {
|
|
5829
|
+
padding: "0.375rem 0.5rem",
|
|
5830
|
+
textAlign: "center",
|
|
5831
|
+
borderBottom: "1px solid var(--glyph-border, #d0d8e4)"
|
|
5832
|
+
};
|
|
5833
|
+
var inputStyle = {
|
|
5834
|
+
width: "3.5rem",
|
|
5835
|
+
padding: "0.25rem 0.375rem",
|
|
5836
|
+
textAlign: "center",
|
|
5837
|
+
border: "1px solid var(--glyph-border, #d0d8e4)",
|
|
5838
|
+
borderRadius: "var(--glyph-radius-sm, 0.375rem)",
|
|
5839
|
+
background: "transparent",
|
|
5840
|
+
color: "var(--glyph-text, #1a2035)",
|
|
5841
|
+
fontSize: "0.875rem",
|
|
5842
|
+
fontVariantNumeric: "tabular-nums"
|
|
5843
|
+
};
|
|
5844
|
+
var weightStyle = {
|
|
5845
|
+
fontSize: "0.6875rem",
|
|
5846
|
+
color: "var(--glyph-text-muted, #6b7a94)",
|
|
5847
|
+
fontWeight: 400
|
|
5848
|
+
};
|
|
5849
|
+
var totalCellStyle = {
|
|
5850
|
+
padding: "0.625rem 0.75rem",
|
|
5851
|
+
textAlign: "center",
|
|
5852
|
+
fontWeight: 700,
|
|
5853
|
+
borderBottom: "1px solid var(--glyph-border, #d0d8e4)",
|
|
5854
|
+
background: "var(--glyph-surface, #e8ecf3)",
|
|
5855
|
+
fontVariantNumeric: "tabular-nums"
|
|
5856
|
+
};
|
|
5857
|
+
var totalHeaderStyle = {
|
|
5858
|
+
...thStyle,
|
|
5859
|
+
borderLeft: "2px solid var(--glyph-border, #d0d8e4)"
|
|
5860
|
+
};
|
|
5861
|
+
function computeWeightedTotals(rows, columns, values) {
|
|
5862
|
+
return rows.map((row) => {
|
|
5863
|
+
let total = 0;
|
|
5864
|
+
for (const col of columns) {
|
|
5865
|
+
const score = values[row.id]?.[col.id] ?? 0;
|
|
5866
|
+
const weight = col.weight ?? 1;
|
|
5867
|
+
total += score * weight;
|
|
5868
|
+
}
|
|
5869
|
+
return { rowId: row.id, rowLabel: row.label, total: Math.round(total * 100) / 100 };
|
|
5870
|
+
});
|
|
5871
|
+
}
|
|
5872
|
+
function Matrix({
|
|
5873
|
+
data,
|
|
5874
|
+
block,
|
|
5875
|
+
onInteraction
|
|
5876
|
+
}) {
|
|
5877
|
+
const { title, scale = 5, showTotals = true, columns, rows } = data;
|
|
5878
|
+
const baseId = `glyph-matrix-${block.id}`;
|
|
5879
|
+
const [values, setValues] = useState(() => {
|
|
5880
|
+
const init = {};
|
|
5881
|
+
for (const row of rows) {
|
|
5882
|
+
const rowMap = {};
|
|
5883
|
+
for (const col of columns) {
|
|
5884
|
+
rowMap[col.id] = 0;
|
|
5885
|
+
}
|
|
5886
|
+
init[row.id] = rowMap;
|
|
5887
|
+
}
|
|
5888
|
+
return init;
|
|
5889
|
+
});
|
|
5890
|
+
const handleChange = useCallback(
|
|
5891
|
+
(rowId, columnId, value) => {
|
|
5892
|
+
const clamped = Math.max(0, Math.min(scale, value));
|
|
5893
|
+
setValues((prevValues) => {
|
|
5894
|
+
const newValues = Object.fromEntries(
|
|
5895
|
+
Object.entries(prevValues).map(([k, v]) => [k, { ...v }])
|
|
5896
|
+
);
|
|
5897
|
+
if (!newValues[rowId]) newValues[rowId] = {};
|
|
5898
|
+
newValues[rowId] = { ...newValues[rowId], [columnId]: clamped };
|
|
5899
|
+
const row = rows.find((r) => r.id === rowId);
|
|
5900
|
+
const col = columns.find((c) => c.id === columnId);
|
|
5901
|
+
if (onInteraction && row && col) {
|
|
5902
|
+
const payloadValues = Object.fromEntries(
|
|
5903
|
+
Object.entries(newValues).map(([k, v]) => [k, { ...v }])
|
|
5904
|
+
);
|
|
5905
|
+
onInteraction({
|
|
5906
|
+
kind: "matrix-change",
|
|
5907
|
+
timestamp: (/* @__PURE__ */ new Date()).toISOString(),
|
|
5908
|
+
blockId: block.id,
|
|
5909
|
+
blockType: block.type,
|
|
5910
|
+
payload: {
|
|
5911
|
+
rowId,
|
|
5912
|
+
rowLabel: row.label,
|
|
5913
|
+
columnId,
|
|
5914
|
+
columnLabel: col.label,
|
|
5915
|
+
value: clamped,
|
|
5916
|
+
allValues: payloadValues,
|
|
5917
|
+
weightedTotals: computeWeightedTotals(rows, columns, newValues)
|
|
5918
|
+
}
|
|
5919
|
+
});
|
|
5920
|
+
}
|
|
5921
|
+
return newValues;
|
|
5922
|
+
});
|
|
5923
|
+
},
|
|
5924
|
+
[scale, rows, columns, block.id, block.type, onInteraction]
|
|
5925
|
+
);
|
|
5926
|
+
const totals = computeWeightedTotals(rows, columns, values);
|
|
5927
|
+
return /* @__PURE__ */ jsxs("div", { id: baseId, role: "region", "aria-label": title ?? "Decision Matrix", style: containerStyle7, children: [
|
|
5928
|
+
title && /* @__PURE__ */ jsx("div", { style: headerStyle6, children: title }),
|
|
5929
|
+
/* @__PURE__ */ jsxs("table", { role: "grid", style: tableStyle, children: [
|
|
5930
|
+
/* @__PURE__ */ jsx("thead", { children: /* @__PURE__ */ jsxs("tr", { children: [
|
|
5931
|
+
/* @__PURE__ */ jsx("th", { style: thStyle }),
|
|
5932
|
+
columns.map((col) => /* @__PURE__ */ jsxs("th", { style: thStyle, children: [
|
|
5933
|
+
col.label,
|
|
5934
|
+
(col.weight ?? 1) !== 1 && /* @__PURE__ */ jsxs("div", { style: weightStyle, children: [
|
|
5935
|
+
"\xD7",
|
|
5936
|
+
String(col.weight)
|
|
5937
|
+
] })
|
|
5938
|
+
] }, col.id)),
|
|
5939
|
+
showTotals && /* @__PURE__ */ jsx("th", { style: totalHeaderStyle, children: "Total" })
|
|
5940
|
+
] }) }),
|
|
5941
|
+
/* @__PURE__ */ jsx("tbody", { children: rows.map((row) => {
|
|
5942
|
+
const rowTotal = totals.find((t) => t.rowId === row.id)?.total ?? 0;
|
|
5943
|
+
return /* @__PURE__ */ jsxs("tr", { children: [
|
|
5944
|
+
/* @__PURE__ */ jsx("th", { scope: "row", style: rowHeaderStyle, children: row.label }),
|
|
5945
|
+
columns.map((col) => {
|
|
5946
|
+
const cellValue = values[row.id]?.[col.id] ?? 0;
|
|
5947
|
+
return /* @__PURE__ */ jsx("td", { style: cellStyle, children: /* @__PURE__ */ jsx(
|
|
5948
|
+
"input",
|
|
5949
|
+
{
|
|
5950
|
+
type: "number",
|
|
5951
|
+
min: 0,
|
|
5952
|
+
max: scale,
|
|
5953
|
+
value: cellValue,
|
|
5954
|
+
onChange: (e) => handleChange(row.id, col.id, Number(e.target.value)),
|
|
5955
|
+
"aria-label": `Score for ${row.label} on ${col.label}`,
|
|
5956
|
+
style: inputStyle
|
|
5957
|
+
}
|
|
5958
|
+
) }, col.id);
|
|
5959
|
+
}),
|
|
5960
|
+
showTotals && /* @__PURE__ */ jsx("td", { style: totalCellStyle, children: String(rowTotal) })
|
|
5961
|
+
] }, row.id);
|
|
5962
|
+
}) })
|
|
5963
|
+
] })
|
|
5964
|
+
] });
|
|
5965
|
+
}
|
|
5966
|
+
|
|
5967
|
+
// src/matrix/index.ts
|
|
5968
|
+
var matrixDefinition = {
|
|
5969
|
+
type: "ui:matrix",
|
|
5970
|
+
schema: matrixSchema,
|
|
5971
|
+
render: Matrix
|
|
5972
|
+
};
|
|
5973
|
+
|
|
5974
|
+
// src/form/styles.ts
|
|
5975
|
+
var containerStyle8 = {
|
|
5976
|
+
fontFamily: "var(--glyph-font-body, system-ui, sans-serif)",
|
|
5977
|
+
color: "var(--glyph-text, #1a2035)",
|
|
5978
|
+
border: "1px solid var(--glyph-border, #d0d8e4)",
|
|
5979
|
+
borderRadius: "var(--glyph-radius-md, 0.5rem)",
|
|
5980
|
+
overflow: "hidden"
|
|
5981
|
+
};
|
|
5982
|
+
var headerStyle7 = {
|
|
5983
|
+
fontWeight: 700,
|
|
5984
|
+
fontSize: "1.125rem",
|
|
5985
|
+
padding: "var(--glyph-spacing-md, 1rem)",
|
|
5986
|
+
paddingBottom: "0.25rem",
|
|
5987
|
+
color: "var(--glyph-heading, #0a0e1a)"
|
|
5988
|
+
};
|
|
5989
|
+
var descriptionStyle = {
|
|
5990
|
+
fontSize: "0.875rem",
|
|
5991
|
+
color: "var(--glyph-text-muted, #6b7a94)",
|
|
5992
|
+
padding: "0 var(--glyph-spacing-md, 1rem)",
|
|
5993
|
+
paddingBottom: "var(--glyph-spacing-sm, 0.5rem)"
|
|
5994
|
+
};
|
|
5995
|
+
var formStyle = {
|
|
5996
|
+
padding: "var(--glyph-spacing-md, 1rem)"
|
|
5997
|
+
};
|
|
5998
|
+
var fieldStyle = {
|
|
5999
|
+
marginBottom: "var(--glyph-spacing-md, 1rem)"
|
|
6000
|
+
};
|
|
6001
|
+
var labelStyle3 = {
|
|
6002
|
+
display: "block",
|
|
6003
|
+
fontWeight: 600,
|
|
6004
|
+
fontSize: "0.875rem",
|
|
6005
|
+
marginBottom: "0.375rem"
|
|
6006
|
+
};
|
|
6007
|
+
var requiredStyle = {
|
|
6008
|
+
color: "var(--glyph-form-error, #dc2626)",
|
|
6009
|
+
marginLeft: "0.25rem"
|
|
6010
|
+
};
|
|
6011
|
+
var textInputStyle = {
|
|
6012
|
+
width: "100%",
|
|
6013
|
+
padding: "0.5rem 0.75rem",
|
|
6014
|
+
border: "1px solid var(--glyph-border, #d0d8e4)",
|
|
6015
|
+
borderRadius: "var(--glyph-radius-sm, 0.375rem)",
|
|
6016
|
+
background: "transparent",
|
|
6017
|
+
color: "var(--glyph-text, #1a2035)",
|
|
6018
|
+
fontSize: "0.875rem",
|
|
6019
|
+
fontFamily: "inherit",
|
|
6020
|
+
boxSizing: "border-box"
|
|
6021
|
+
};
|
|
6022
|
+
var selectInputStyle = {
|
|
6023
|
+
...textInputStyle,
|
|
6024
|
+
appearance: "auto"
|
|
6025
|
+
};
|
|
6026
|
+
var checkboxLabelStyle = {
|
|
6027
|
+
display: "flex",
|
|
6028
|
+
alignItems: "center",
|
|
6029
|
+
gap: "0.5rem",
|
|
6030
|
+
fontSize: "0.875rem",
|
|
6031
|
+
cursor: "pointer"
|
|
6032
|
+
};
|
|
6033
|
+
var rangeValueStyle = {
|
|
6034
|
+
fontSize: "0.875rem",
|
|
6035
|
+
fontWeight: 600,
|
|
6036
|
+
color: "var(--glyph-accent, #0a9d7c)",
|
|
6037
|
+
marginLeft: "0.5rem",
|
|
6038
|
+
fontVariantNumeric: "tabular-nums"
|
|
6039
|
+
};
|
|
6040
|
+
var submitButtonStyle = {
|
|
6041
|
+
padding: "0.625rem 1.5rem",
|
|
6042
|
+
borderRadius: "var(--glyph-radius-md, 0.5rem)",
|
|
6043
|
+
border: "1px solid var(--glyph-accent, #0a9d7c)",
|
|
6044
|
+
background: "var(--glyph-accent, #0a9d7c)",
|
|
6045
|
+
color: "#fff",
|
|
6046
|
+
cursor: "pointer",
|
|
6047
|
+
fontWeight: 600,
|
|
6048
|
+
fontSize: "0.875rem",
|
|
6049
|
+
marginTop: "var(--glyph-spacing-sm, 0.5rem)"
|
|
6050
|
+
};
|
|
6051
|
+
function invalidStyle(isInvalid) {
|
|
6052
|
+
if (!isInvalid) return {};
|
|
6053
|
+
return {
|
|
6054
|
+
borderColor: "var(--glyph-form-error, #dc2626)"
|
|
6055
|
+
};
|
|
6056
|
+
}
|
|
6057
|
+
function renderField({
|
|
6058
|
+
field,
|
|
6059
|
+
baseId,
|
|
6060
|
+
values,
|
|
6061
|
+
validation,
|
|
6062
|
+
submitted,
|
|
6063
|
+
updateValue
|
|
6064
|
+
}) {
|
|
6065
|
+
const isInvalid = validation[field.id] === true;
|
|
6066
|
+
const fieldId = `${baseId}-${field.id}`;
|
|
6067
|
+
switch (field.type) {
|
|
6068
|
+
case "text":
|
|
6069
|
+
return /* @__PURE__ */ jsxs("div", { style: fieldStyle, children: [
|
|
6070
|
+
/* @__PURE__ */ jsxs("label", { htmlFor: fieldId, style: labelStyle3, children: [
|
|
6071
|
+
field.label,
|
|
6072
|
+
field.required && /* @__PURE__ */ jsx("span", { style: requiredStyle, "aria-hidden": "true", children: "*" })
|
|
6073
|
+
] }),
|
|
6074
|
+
/* @__PURE__ */ jsx(
|
|
6075
|
+
"input",
|
|
6076
|
+
{
|
|
6077
|
+
id: fieldId,
|
|
6078
|
+
type: "text",
|
|
6079
|
+
value: values[field.id] ?? "",
|
|
6080
|
+
onChange: (e) => updateValue(field.id, e.target.value),
|
|
6081
|
+
placeholder: field.placeholder,
|
|
6082
|
+
disabled: submitted,
|
|
6083
|
+
"aria-required": field.required,
|
|
6084
|
+
"aria-invalid": isInvalid,
|
|
6085
|
+
style: { ...textInputStyle, ...invalidStyle(isInvalid) }
|
|
6086
|
+
}
|
|
6087
|
+
)
|
|
6088
|
+
] }, field.id);
|
|
6089
|
+
case "textarea":
|
|
6090
|
+
return /* @__PURE__ */ jsxs("div", { style: fieldStyle, children: [
|
|
6091
|
+
/* @__PURE__ */ jsxs("label", { htmlFor: fieldId, style: labelStyle3, children: [
|
|
6092
|
+
field.label,
|
|
6093
|
+
field.required && /* @__PURE__ */ jsx("span", { style: requiredStyle, "aria-hidden": "true", children: "*" })
|
|
6094
|
+
] }),
|
|
6095
|
+
/* @__PURE__ */ jsx(
|
|
6096
|
+
"textarea",
|
|
6097
|
+
{
|
|
6098
|
+
id: fieldId,
|
|
6099
|
+
value: values[field.id] ?? "",
|
|
6100
|
+
onChange: (e) => updateValue(field.id, e.target.value),
|
|
6101
|
+
placeholder: field.placeholder,
|
|
6102
|
+
rows: field.rows ?? 4,
|
|
6103
|
+
disabled: submitted,
|
|
6104
|
+
"aria-required": field.required,
|
|
6105
|
+
"aria-invalid": isInvalid,
|
|
6106
|
+
style: {
|
|
6107
|
+
...textInputStyle,
|
|
6108
|
+
...invalidStyle(isInvalid),
|
|
6109
|
+
resize: "vertical",
|
|
6110
|
+
fontFamily: "inherit"
|
|
6111
|
+
}
|
|
6112
|
+
}
|
|
6113
|
+
)
|
|
6114
|
+
] }, field.id);
|
|
6115
|
+
case "select":
|
|
6116
|
+
return /* @__PURE__ */ jsxs("div", { style: fieldStyle, children: [
|
|
6117
|
+
/* @__PURE__ */ jsxs("label", { htmlFor: fieldId, style: labelStyle3, children: [
|
|
6118
|
+
field.label,
|
|
6119
|
+
field.required && /* @__PURE__ */ jsx("span", { style: requiredStyle, "aria-hidden": "true", children: "*" })
|
|
6120
|
+
] }),
|
|
6121
|
+
/* @__PURE__ */ jsx(
|
|
6122
|
+
"select",
|
|
6123
|
+
{
|
|
6124
|
+
id: fieldId,
|
|
6125
|
+
value: values[field.id] ?? "",
|
|
6126
|
+
onChange: (e) => updateValue(field.id, e.target.value),
|
|
6127
|
+
disabled: submitted,
|
|
6128
|
+
"aria-required": field.required,
|
|
6129
|
+
style: selectInputStyle,
|
|
6130
|
+
children: field.options.map((opt) => /* @__PURE__ */ jsx("option", { value: opt, children: opt }, opt))
|
|
6131
|
+
}
|
|
6132
|
+
)
|
|
6133
|
+
] }, field.id);
|
|
6134
|
+
case "checkbox":
|
|
6135
|
+
return /* @__PURE__ */ jsx("div", { style: fieldStyle, children: /* @__PURE__ */ jsxs("label", { style: checkboxLabelStyle, children: [
|
|
6136
|
+
/* @__PURE__ */ jsx(
|
|
6137
|
+
"input",
|
|
6138
|
+
{
|
|
6139
|
+
id: fieldId,
|
|
6140
|
+
type: "checkbox",
|
|
6141
|
+
checked: values[field.id] ?? false,
|
|
6142
|
+
onChange: (e) => updateValue(field.id, e.target.checked),
|
|
6143
|
+
disabled: submitted
|
|
6144
|
+
}
|
|
6145
|
+
),
|
|
6146
|
+
field.label
|
|
6147
|
+
] }) }, field.id);
|
|
6148
|
+
case "range": {
|
|
6149
|
+
const min2 = field.min ?? 0;
|
|
6150
|
+
const max2 = field.max ?? 100;
|
|
6151
|
+
const step = field.step ?? 1;
|
|
6152
|
+
const currentValue = values[field.id] ?? min2;
|
|
6153
|
+
const displayValue = field.unit ? `${String(currentValue)}${field.unit}` : String(currentValue);
|
|
6154
|
+
return /* @__PURE__ */ jsxs("div", { style: fieldStyle, children: [
|
|
6155
|
+
/* @__PURE__ */ jsxs("label", { htmlFor: fieldId, style: labelStyle3, children: [
|
|
6156
|
+
field.label,
|
|
6157
|
+
/* @__PURE__ */ jsx("span", { style: rangeValueStyle, children: displayValue })
|
|
6158
|
+
] }),
|
|
6159
|
+
/* @__PURE__ */ jsx(
|
|
6160
|
+
"input",
|
|
6161
|
+
{
|
|
6162
|
+
id: fieldId,
|
|
6163
|
+
type: "range",
|
|
6164
|
+
min: min2,
|
|
6165
|
+
max: max2,
|
|
6166
|
+
step,
|
|
6167
|
+
value: currentValue,
|
|
6168
|
+
onChange: (e) => updateValue(field.id, Number(e.target.value)),
|
|
6169
|
+
disabled: submitted,
|
|
6170
|
+
"aria-valuemin": min2,
|
|
6171
|
+
"aria-valuemax": max2,
|
|
6172
|
+
"aria-valuenow": currentValue,
|
|
6173
|
+
"aria-valuetext": displayValue,
|
|
6174
|
+
style: { width: "100%", accentColor: "var(--glyph-accent, #0a9d7c)" }
|
|
6175
|
+
}
|
|
6176
|
+
)
|
|
6177
|
+
] }, field.id);
|
|
6178
|
+
}
|
|
6179
|
+
}
|
|
6180
|
+
}
|
|
6181
|
+
function Form({ data, block, onInteraction }) {
|
|
6182
|
+
const { title, description, submitLabel = "Submit", fields } = data;
|
|
6183
|
+
const baseId = `glyph-form-${block.id}`;
|
|
6184
|
+
const [values, setValues] = useState(() => {
|
|
6185
|
+
const init = {};
|
|
6186
|
+
for (const field of fields) {
|
|
6187
|
+
switch (field.type) {
|
|
6188
|
+
case "text":
|
|
6189
|
+
case "textarea":
|
|
6190
|
+
init[field.id] = field.default ?? "";
|
|
6191
|
+
break;
|
|
6192
|
+
case "select":
|
|
6193
|
+
init[field.id] = field.default ?? field.options[0] ?? "";
|
|
6194
|
+
break;
|
|
6195
|
+
case "checkbox":
|
|
6196
|
+
init[field.id] = field.default ?? false;
|
|
6197
|
+
break;
|
|
6198
|
+
case "range":
|
|
6199
|
+
init[field.id] = field.default ?? field.min ?? 0;
|
|
6200
|
+
break;
|
|
6201
|
+
}
|
|
6202
|
+
}
|
|
6203
|
+
return init;
|
|
6204
|
+
});
|
|
6205
|
+
const [submitted, setSubmitted] = useState(false);
|
|
6206
|
+
const [validation, setValidation] = useState({});
|
|
6207
|
+
const updateValue = (fieldId, value) => {
|
|
6208
|
+
setValues((prev) => ({ ...prev, [fieldId]: value }));
|
|
6209
|
+
if (validation[fieldId]) {
|
|
6210
|
+
setValidation((prev) => ({ ...prev, [fieldId]: false }));
|
|
6211
|
+
}
|
|
6212
|
+
};
|
|
6213
|
+
const handleSubmit = (e) => {
|
|
6214
|
+
e.preventDefault();
|
|
6215
|
+
const errors = {};
|
|
6216
|
+
for (const field of fields) {
|
|
6217
|
+
if ("required" in field && field.required) {
|
|
6218
|
+
const val = values[field.id];
|
|
6219
|
+
if (val === "" || val === void 0) {
|
|
6220
|
+
errors[field.id] = true;
|
|
6221
|
+
}
|
|
6222
|
+
}
|
|
6223
|
+
}
|
|
6224
|
+
if (Object.keys(errors).length > 0) {
|
|
6225
|
+
setValidation(errors);
|
|
6226
|
+
return;
|
|
6227
|
+
}
|
|
6228
|
+
setSubmitted(true);
|
|
6229
|
+
if (onInteraction) {
|
|
6230
|
+
onInteraction({
|
|
6231
|
+
kind: "form-submit",
|
|
6232
|
+
timestamp: (/* @__PURE__ */ new Date()).toISOString(),
|
|
6233
|
+
blockId: block.id,
|
|
6234
|
+
blockType: block.type,
|
|
6235
|
+
payload: {
|
|
6236
|
+
values: { ...values },
|
|
6237
|
+
fields: fields.map((f) => ({
|
|
6238
|
+
id: f.id,
|
|
6239
|
+
label: f.label,
|
|
6240
|
+
type: f.type,
|
|
6241
|
+
value: values[f.id] !== void 0 ? values[f.id] : ""
|
|
6242
|
+
}))
|
|
6243
|
+
}
|
|
6244
|
+
});
|
|
6245
|
+
}
|
|
6246
|
+
};
|
|
6247
|
+
return /* @__PURE__ */ jsxs("div", { id: baseId, role: "region", "aria-label": title ?? "Form", style: containerStyle8, children: [
|
|
6248
|
+
title && /* @__PURE__ */ jsx("div", { style: headerStyle7, children: title }),
|
|
6249
|
+
description && /* @__PURE__ */ jsx("div", { style: descriptionStyle, children: description }),
|
|
6250
|
+
/* @__PURE__ */ jsxs("form", { onSubmit: handleSubmit, style: formStyle, noValidate: true, children: [
|
|
6251
|
+
fields.map(
|
|
6252
|
+
(field) => renderField({ field, baseId, values, validation, submitted, updateValue })
|
|
6253
|
+
),
|
|
6254
|
+
/* @__PURE__ */ jsx(
|
|
6255
|
+
"button",
|
|
6256
|
+
{
|
|
6257
|
+
type: "submit",
|
|
6258
|
+
disabled: submitted,
|
|
6259
|
+
style: {
|
|
6260
|
+
...submitButtonStyle,
|
|
6261
|
+
opacity: submitted ? 0.5 : 1,
|
|
6262
|
+
cursor: submitted ? "default" : "pointer"
|
|
6263
|
+
},
|
|
6264
|
+
children: submitted ? "Submitted" : submitLabel
|
|
6265
|
+
}
|
|
6266
|
+
)
|
|
6267
|
+
] })
|
|
6268
|
+
] });
|
|
6269
|
+
}
|
|
6270
|
+
|
|
6271
|
+
// src/form/index.ts
|
|
6272
|
+
var formDefinition = {
|
|
6273
|
+
type: "ui:form",
|
|
6274
|
+
schema: formSchema,
|
|
6275
|
+
render: Form
|
|
6276
|
+
};
|
|
6277
|
+
|
|
6278
|
+
// src/kanban/styles.ts
|
|
6279
|
+
var containerStyle9 = {
|
|
6280
|
+
fontFamily: "var(--glyph-font-body, system-ui, sans-serif)",
|
|
6281
|
+
color: "var(--glyph-text, #1a2035)",
|
|
6282
|
+
border: "1px solid var(--glyph-border, #d0d8e4)",
|
|
6283
|
+
borderRadius: "var(--glyph-radius-md, 0.5rem)",
|
|
6284
|
+
overflow: "hidden"
|
|
6285
|
+
};
|
|
6286
|
+
var headerStyle8 = {
|
|
6287
|
+
fontWeight: 700,
|
|
6288
|
+
fontSize: "1.125rem",
|
|
6289
|
+
padding: "var(--glyph-spacing-md, 1rem)",
|
|
6290
|
+
borderBottom: "1px solid var(--glyph-border, #d0d8e4)",
|
|
6291
|
+
color: "var(--glyph-heading, #0a0e1a)"
|
|
6292
|
+
};
|
|
6293
|
+
var boardStyle = {
|
|
6294
|
+
display: "flex",
|
|
6295
|
+
gap: "var(--glyph-spacing-sm, 0.5rem)",
|
|
6296
|
+
padding: "var(--glyph-spacing-md, 1rem)",
|
|
6297
|
+
overflowX: "auto",
|
|
6298
|
+
minHeight: "200px"
|
|
6299
|
+
};
|
|
6300
|
+
function columnStyle(isOver) {
|
|
6301
|
+
return {
|
|
6302
|
+
flex: "1 1 0",
|
|
6303
|
+
minWidth: "180px",
|
|
6304
|
+
background: isOver ? "var(--glyph-accent-subtle, #e6f6f2)" : "var(--glyph-kanban-column-bg, var(--glyph-surface, #e8ecf3))",
|
|
6305
|
+
borderRadius: "var(--glyph-radius-md, 0.5rem)",
|
|
6306
|
+
padding: "var(--glyph-spacing-sm, 0.5rem)",
|
|
6307
|
+
display: "flex",
|
|
6308
|
+
flexDirection: "column",
|
|
6309
|
+
transition: "background 0.15s ease"
|
|
6310
|
+
};
|
|
6311
|
+
}
|
|
6312
|
+
var columnHeaderStyle = {
|
|
6313
|
+
fontWeight: 700,
|
|
6314
|
+
fontSize: "0.8125rem",
|
|
6315
|
+
textTransform: "uppercase",
|
|
6316
|
+
letterSpacing: "0.5px",
|
|
6317
|
+
padding: "0.375rem 0.5rem",
|
|
6318
|
+
marginBottom: "0.375rem",
|
|
6319
|
+
display: "flex",
|
|
6320
|
+
justifyContent: "space-between",
|
|
6321
|
+
alignItems: "center"
|
|
6322
|
+
};
|
|
6323
|
+
var columnCountStyle = {
|
|
6324
|
+
fontSize: "0.6875rem",
|
|
6325
|
+
fontWeight: 400,
|
|
6326
|
+
color: "var(--glyph-text-muted, #6b7a94)"
|
|
6327
|
+
};
|
|
6328
|
+
function cardStyle(isGrabbed, priority) {
|
|
6329
|
+
const priorityColors = {
|
|
6330
|
+
high: "var(--glyph-kanban-priority-high, #dc2626)",
|
|
6331
|
+
medium: "var(--glyph-kanban-priority-medium, #f59e0b)",
|
|
6332
|
+
low: "var(--glyph-kanban-priority-low, #22c55e)"
|
|
6333
|
+
};
|
|
6334
|
+
return {
|
|
6335
|
+
background: "var(--glyph-kanban-card-bg, var(--glyph-surface-raised, #f4f6fa))",
|
|
6336
|
+
border: `1px solid var(--glyph-kanban-card-border, var(--glyph-border, #d0d8e4))`,
|
|
6337
|
+
borderRadius: "var(--glyph-radius-sm, 0.375rem)",
|
|
6338
|
+
padding: "0.625rem 0.75rem",
|
|
6339
|
+
marginBottom: "0.375rem",
|
|
6340
|
+
cursor: isGrabbed ? "grabbing" : "grab",
|
|
6341
|
+
userSelect: "none",
|
|
6342
|
+
boxShadow: isGrabbed ? "var(--glyph-kanban-drag-shadow, var(--glyph-shadow-md, 0 4px 12px rgba(0,0,0,0.15)))" : "none",
|
|
6343
|
+
borderLeft: priority && priorityColors[priority] ? `3px solid ${priorityColors[priority]}` : void 0,
|
|
6344
|
+
outline: isGrabbed ? "2px solid var(--glyph-accent, #0a9d7c)" : "none",
|
|
6345
|
+
outlineOffset: "-2px"
|
|
6346
|
+
};
|
|
6347
|
+
}
|
|
6348
|
+
var cardTitleStyle = {
|
|
6349
|
+
fontWeight: 600,
|
|
6350
|
+
fontSize: "0.875rem",
|
|
6351
|
+
marginBottom: "0.25rem"
|
|
6352
|
+
};
|
|
6353
|
+
var cardDescStyle = {
|
|
6354
|
+
fontSize: "0.75rem",
|
|
6355
|
+
color: "var(--glyph-text-muted, #6b7a94)",
|
|
6356
|
+
lineHeight: 1.4
|
|
6357
|
+
};
|
|
6358
|
+
var tagContainerStyle = {
|
|
6359
|
+
display: "flex",
|
|
6360
|
+
flexWrap: "wrap",
|
|
6361
|
+
gap: "0.25rem",
|
|
6362
|
+
marginTop: "0.375rem"
|
|
6363
|
+
};
|
|
6364
|
+
var tagStyle = {
|
|
6365
|
+
fontSize: "0.625rem",
|
|
6366
|
+
fontWeight: 600,
|
|
6367
|
+
padding: "0.125rem 0.375rem",
|
|
6368
|
+
borderRadius: "9999px",
|
|
6369
|
+
background: "var(--glyph-accent-subtle, #e6f6f2)",
|
|
6370
|
+
color: "var(--glyph-accent, #0a9d7c)"
|
|
6371
|
+
};
|
|
6372
|
+
var limitStyle = {
|
|
6373
|
+
fontSize: "0.625rem",
|
|
6374
|
+
color: "var(--glyph-text-muted, #6b7a94)"
|
|
6375
|
+
};
|
|
6376
|
+
function Kanban({
|
|
6377
|
+
data,
|
|
6378
|
+
block,
|
|
6379
|
+
onInteraction
|
|
6380
|
+
}) {
|
|
6381
|
+
const { title } = data;
|
|
6382
|
+
const baseId = `glyph-kanban-${block.id}`;
|
|
6383
|
+
const [columns, setColumns] = useState(
|
|
6384
|
+
() => data.columns.map((col) => ({ ...col, cards: [...col.cards] }))
|
|
6385
|
+
);
|
|
6386
|
+
const [grabbed, setGrabbed] = useState(null);
|
|
6387
|
+
const moveCard = (cardId, sourceColId, destColId, destIndex) => {
|
|
6388
|
+
const newColumns = columns.map((col) => ({
|
|
6389
|
+
...col,
|
|
6390
|
+
cards: [...col.cards]
|
|
6391
|
+
}));
|
|
6392
|
+
const sourceCol = newColumns.find((c) => c.id === sourceColId);
|
|
6393
|
+
const destCol = newColumns.find((c) => c.id === destColId);
|
|
6394
|
+
if (!sourceCol || !destCol) return;
|
|
6395
|
+
const cardIndex = sourceCol.cards.findIndex((c) => c.id === cardId);
|
|
6396
|
+
if (cardIndex === -1) return;
|
|
6397
|
+
const [card] = sourceCol.cards.splice(cardIndex, 1);
|
|
6398
|
+
if (!card) return;
|
|
6399
|
+
destCol.cards.splice(destIndex, 0, card);
|
|
6400
|
+
setColumns(newColumns);
|
|
6401
|
+
if (onInteraction) {
|
|
6402
|
+
onInteraction({
|
|
6403
|
+
kind: "kanban-move",
|
|
6404
|
+
timestamp: (/* @__PURE__ */ new Date()).toISOString(),
|
|
6405
|
+
blockId: block.id,
|
|
6406
|
+
blockType: block.type,
|
|
6407
|
+
payload: {
|
|
6408
|
+
cardId: card.id,
|
|
6409
|
+
cardTitle: card.title,
|
|
6410
|
+
sourceColumnId: sourceColId,
|
|
6411
|
+
sourceColumnTitle: sourceCol.title,
|
|
6412
|
+
destinationColumnId: destColId,
|
|
6413
|
+
destinationColumnTitle: destCol.title,
|
|
6414
|
+
position: destIndex,
|
|
6415
|
+
allColumns: newColumns.map((c) => ({
|
|
6416
|
+
id: c.id,
|
|
6417
|
+
title: c.title,
|
|
6418
|
+
cardIds: c.cards.map((card2) => card2.id)
|
|
6419
|
+
}))
|
|
6420
|
+
}
|
|
6421
|
+
});
|
|
6422
|
+
}
|
|
6423
|
+
};
|
|
6424
|
+
const handleCardKeyDown = (e, cardId, columnId, cardIndex) => {
|
|
6425
|
+
if (e.key === " " || e.key === "Enter") {
|
|
6426
|
+
e.preventDefault();
|
|
6427
|
+
if (grabbed === null) {
|
|
6428
|
+
setGrabbed({ cardId, columnId, cardIndex });
|
|
6429
|
+
} else {
|
|
6430
|
+
setGrabbed(null);
|
|
6431
|
+
}
|
|
6432
|
+
} else if (e.key === "Escape") {
|
|
6433
|
+
setGrabbed(null);
|
|
6434
|
+
} else if (grabbed && grabbed.cardId === cardId) {
|
|
6435
|
+
const colIndex = columns.findIndex((c) => c.id === grabbed.columnId);
|
|
6436
|
+
const col = columns[colIndex];
|
|
6437
|
+
if (!col) return;
|
|
6438
|
+
if (e.key === "ArrowUp") {
|
|
6439
|
+
e.preventDefault();
|
|
6440
|
+
if (grabbed.cardIndex > 0) {
|
|
6441
|
+
moveCard(cardId, grabbed.columnId, grabbed.columnId, grabbed.cardIndex - 1);
|
|
6442
|
+
setGrabbed({ ...grabbed, cardIndex: grabbed.cardIndex - 1 });
|
|
6443
|
+
}
|
|
6444
|
+
} else if (e.key === "ArrowDown") {
|
|
6445
|
+
e.preventDefault();
|
|
6446
|
+
if (grabbed.cardIndex < col.cards.length - 1) {
|
|
6447
|
+
moveCard(cardId, grabbed.columnId, grabbed.columnId, grabbed.cardIndex + 1);
|
|
6448
|
+
setGrabbed({ ...grabbed, cardIndex: grabbed.cardIndex + 1 });
|
|
6449
|
+
}
|
|
6450
|
+
} else if (e.key === "ArrowLeft") {
|
|
6451
|
+
e.preventDefault();
|
|
6452
|
+
if (colIndex > 0) {
|
|
6453
|
+
const prevCol = columns[colIndex - 1];
|
|
6454
|
+
if (!prevCol) return;
|
|
6455
|
+
const newIndex = prevCol.cards.length;
|
|
6456
|
+
moveCard(cardId, grabbed.columnId, prevCol.id, newIndex);
|
|
6457
|
+
setGrabbed({ cardId, columnId: prevCol.id, cardIndex: newIndex });
|
|
6458
|
+
}
|
|
6459
|
+
} else if (e.key === "ArrowRight") {
|
|
6460
|
+
e.preventDefault();
|
|
6461
|
+
if (colIndex < columns.length - 1) {
|
|
6462
|
+
const nextCol = columns[colIndex + 1];
|
|
6463
|
+
if (!nextCol) return;
|
|
6464
|
+
const newIndex = nextCol.cards.length;
|
|
6465
|
+
moveCard(cardId, grabbed.columnId, nextCol.id, newIndex);
|
|
6466
|
+
setGrabbed({ cardId, columnId: nextCol.id, cardIndex: newIndex });
|
|
6467
|
+
}
|
|
6468
|
+
}
|
|
6469
|
+
}
|
|
6470
|
+
};
|
|
6471
|
+
return /* @__PURE__ */ jsxs("div", { id: baseId, role: "region", "aria-label": title ?? "Kanban Board", style: containerStyle9, children: [
|
|
6472
|
+
title && /* @__PURE__ */ jsx("div", { style: headerStyle8, children: title }),
|
|
6473
|
+
/* @__PURE__ */ jsx("div", { style: boardStyle, children: columns.map((col) => /* @__PURE__ */ jsxs("div", { style: columnStyle(false), children: [
|
|
6474
|
+
/* @__PURE__ */ jsxs("div", { style: columnHeaderStyle, children: [
|
|
6475
|
+
/* @__PURE__ */ jsx("span", { children: col.title }),
|
|
6476
|
+
/* @__PURE__ */ jsxs("span", { style: columnCountStyle, children: [
|
|
6477
|
+
String(col.cards.length),
|
|
6478
|
+
col.limit !== void 0 && /* @__PURE__ */ jsxs("span", { style: limitStyle, children: [
|
|
6479
|
+
" / ",
|
|
6480
|
+
String(col.limit)
|
|
6481
|
+
] })
|
|
6482
|
+
] })
|
|
6483
|
+
] }),
|
|
6484
|
+
/* @__PURE__ */ jsx("div", { role: "list", "aria-label": col.title, children: col.cards.map((card, cardIndex) => {
|
|
6485
|
+
const isGrabbed = grabbed !== null && grabbed.cardId === card.id;
|
|
6486
|
+
return /* @__PURE__ */ jsxs(
|
|
6487
|
+
"div",
|
|
6488
|
+
{
|
|
6489
|
+
role: "listitem",
|
|
6490
|
+
"aria-grabbed": isGrabbed,
|
|
6491
|
+
"aria-label": `${card.title}${card.priority ? `, ${card.priority} priority` : ""}`,
|
|
6492
|
+
tabIndex: 0,
|
|
6493
|
+
style: cardStyle(isGrabbed, card.priority),
|
|
6494
|
+
onKeyDown: (e) => handleCardKeyDown(e, card.id, col.id, cardIndex),
|
|
6495
|
+
children: [
|
|
6496
|
+
/* @__PURE__ */ jsx("div", { style: cardTitleStyle, children: card.title }),
|
|
6497
|
+
card.description && /* @__PURE__ */ jsx("div", { style: cardDescStyle, children: card.description }),
|
|
6498
|
+
card.tags && card.tags.length > 0 && /* @__PURE__ */ jsx("div", { style: tagContainerStyle, children: card.tags.map((tag) => /* @__PURE__ */ jsx("span", { style: tagStyle, children: tag }, tag)) })
|
|
6499
|
+
]
|
|
6500
|
+
},
|
|
6501
|
+
card.id
|
|
6502
|
+
);
|
|
6503
|
+
}) })
|
|
6504
|
+
] }, col.id)) }),
|
|
6505
|
+
/* @__PURE__ */ jsx(
|
|
6506
|
+
"div",
|
|
6507
|
+
{
|
|
6508
|
+
"aria-live": "assertive",
|
|
6509
|
+
style: {
|
|
6510
|
+
position: "absolute",
|
|
6511
|
+
width: "1px",
|
|
6512
|
+
height: "1px",
|
|
6513
|
+
padding: 0,
|
|
6514
|
+
margin: "-1px",
|
|
6515
|
+
overflow: "hidden",
|
|
6516
|
+
clip: "rect(0,0,0,0)",
|
|
6517
|
+
whiteSpace: "nowrap",
|
|
6518
|
+
border: 0
|
|
6519
|
+
},
|
|
6520
|
+
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.`
|
|
6521
|
+
}
|
|
6522
|
+
)
|
|
6523
|
+
] });
|
|
6524
|
+
}
|
|
6525
|
+
|
|
6526
|
+
// src/kanban/index.ts
|
|
6527
|
+
var kanbanDefinition = {
|
|
6528
|
+
type: "ui:kanban",
|
|
6529
|
+
schema: kanbanSchema,
|
|
6530
|
+
render: Kanban
|
|
6531
|
+
};
|
|
6532
|
+
|
|
6533
|
+
// src/annotate/styles.ts
|
|
6534
|
+
var containerStyle10 = {
|
|
6535
|
+
fontFamily: "var(--glyph-font-body, system-ui, sans-serif)",
|
|
6536
|
+
color: "var(--glyph-text, #1a2035)",
|
|
6537
|
+
border: "1px solid var(--glyph-border, #d0d8e4)",
|
|
6538
|
+
borderRadius: "var(--glyph-radius-md, 0.5rem)",
|
|
6539
|
+
overflow: "hidden"
|
|
6540
|
+
};
|
|
6541
|
+
var headerStyle9 = {
|
|
6542
|
+
fontWeight: 700,
|
|
6543
|
+
fontSize: "1.125rem",
|
|
6544
|
+
padding: "var(--glyph-spacing-md, 1rem)",
|
|
6545
|
+
borderBottom: "1px solid var(--glyph-border, #d0d8e4)",
|
|
6546
|
+
color: "var(--glyph-heading, #0a0e1a)"
|
|
6547
|
+
};
|
|
6548
|
+
var bodyStyle2 = {
|
|
6549
|
+
display: "flex",
|
|
6550
|
+
minHeight: "200px"
|
|
6551
|
+
};
|
|
6552
|
+
var textPaneStyle = {
|
|
6553
|
+
flex: 1,
|
|
6554
|
+
padding: "var(--glyph-spacing-md, 1rem)",
|
|
6555
|
+
fontFamily: "var(--glyph-font-mono, ui-monospace, monospace)",
|
|
6556
|
+
fontSize: "0.8125rem",
|
|
6557
|
+
lineHeight: 1.8,
|
|
6558
|
+
whiteSpace: "pre-wrap",
|
|
6559
|
+
wordBreak: "break-word",
|
|
6560
|
+
position: "relative",
|
|
6561
|
+
cursor: "text"
|
|
6562
|
+
};
|
|
6563
|
+
var labelPickerStyle = {
|
|
6564
|
+
position: "absolute",
|
|
6565
|
+
zIndex: 10,
|
|
6566
|
+
background: "var(--glyph-surface-raised, #f4f6fa)",
|
|
6567
|
+
border: "1px solid var(--glyph-border, #d0d8e4)",
|
|
6568
|
+
borderRadius: "var(--glyph-radius-sm, 0.375rem)",
|
|
6569
|
+
boxShadow: "var(--glyph-shadow-md, 0 4px 12px rgba(0,0,0,0.15))",
|
|
6570
|
+
padding: "0.25rem 0",
|
|
6571
|
+
minWidth: "120px"
|
|
6572
|
+
};
|
|
6573
|
+
function labelOptionStyle() {
|
|
6574
|
+
return {
|
|
6575
|
+
display: "flex",
|
|
6576
|
+
alignItems: "center",
|
|
6577
|
+
gap: "0.5rem",
|
|
6578
|
+
padding: "0.375rem 0.75rem",
|
|
6579
|
+
cursor: "pointer",
|
|
6580
|
+
fontSize: "0.8125rem",
|
|
6581
|
+
background: "transparent",
|
|
6582
|
+
border: "none",
|
|
6583
|
+
width: "100%",
|
|
6584
|
+
textAlign: "left",
|
|
6585
|
+
color: "var(--glyph-text, #1a2035)"
|
|
6586
|
+
};
|
|
6587
|
+
}
|
|
6588
|
+
function colorDotStyle(color3) {
|
|
6589
|
+
return {
|
|
6590
|
+
width: "0.625rem",
|
|
6591
|
+
height: "0.625rem",
|
|
6592
|
+
borderRadius: "50%",
|
|
6593
|
+
background: color3,
|
|
6594
|
+
flexShrink: 0
|
|
6595
|
+
};
|
|
6596
|
+
}
|
|
6597
|
+
var sidebarStyle = {
|
|
6598
|
+
width: "220px",
|
|
6599
|
+
borderLeft: "1px solid var(--glyph-border, #d0d8e4)",
|
|
6600
|
+
background: "var(--glyph-annotate-sidebar-bg, var(--glyph-surface, #e8ecf3))",
|
|
6601
|
+
overflow: "auto"
|
|
6602
|
+
};
|
|
6603
|
+
var sidebarHeaderStyle = {
|
|
6604
|
+
fontWeight: 700,
|
|
6605
|
+
fontSize: "0.75rem",
|
|
6606
|
+
textTransform: "uppercase",
|
|
6607
|
+
letterSpacing: "0.5px",
|
|
6608
|
+
padding: "0.75rem",
|
|
6609
|
+
borderBottom: "1px solid var(--glyph-border, #d0d8e4)",
|
|
6610
|
+
color: "var(--glyph-text-muted, #6b7a94)"
|
|
6611
|
+
};
|
|
6612
|
+
function annotationItemStyle(color3) {
|
|
6613
|
+
return {
|
|
6614
|
+
padding: "0.5rem 0.75rem",
|
|
6615
|
+
borderBottom: "1px solid var(--glyph-border, #d0d8e4)",
|
|
6616
|
+
borderLeft: `3px solid ${color3}`,
|
|
6617
|
+
fontSize: "0.75rem"
|
|
6618
|
+
};
|
|
6619
|
+
}
|
|
6620
|
+
var annotationTextStyle = {
|
|
6621
|
+
fontFamily: "var(--glyph-font-mono, ui-monospace, monospace)",
|
|
6622
|
+
fontSize: "0.6875rem",
|
|
6623
|
+
color: "var(--glyph-text-muted, #6b7a94)",
|
|
6624
|
+
marginTop: "0.25rem",
|
|
6625
|
+
overflow: "hidden",
|
|
6626
|
+
textOverflow: "ellipsis",
|
|
6627
|
+
whiteSpace: "nowrap"
|
|
6628
|
+
};
|
|
6629
|
+
var annotationNoteStyle = {
|
|
6630
|
+
fontSize: "0.6875rem",
|
|
6631
|
+
fontStyle: "italic",
|
|
6632
|
+
color: "var(--glyph-text-muted, #6b7a94)",
|
|
6633
|
+
marginTop: "0.125rem"
|
|
6634
|
+
};
|
|
6635
|
+
function computeSegments(text, annotations) {
|
|
6636
|
+
if (annotations.length === 0) {
|
|
6637
|
+
return [{ text, start: 0, annotation: null }];
|
|
6638
|
+
}
|
|
6639
|
+
const sorted = [...annotations].sort((a, b) => a.start - b.start);
|
|
6640
|
+
const segments = [];
|
|
6641
|
+
let cursor = 0;
|
|
6642
|
+
for (const ann of sorted) {
|
|
6643
|
+
if (ann.start > cursor) {
|
|
6644
|
+
segments.push({ text: text.slice(cursor, ann.start), start: cursor, annotation: null });
|
|
6645
|
+
}
|
|
6646
|
+
segments.push({
|
|
6647
|
+
text: text.slice(ann.start, ann.end),
|
|
6648
|
+
start: ann.start,
|
|
6649
|
+
annotation: ann
|
|
6650
|
+
});
|
|
6651
|
+
cursor = ann.end;
|
|
6652
|
+
}
|
|
6653
|
+
if (cursor < text.length) {
|
|
6654
|
+
segments.push({ text: text.slice(cursor), start: cursor, annotation: null });
|
|
6655
|
+
}
|
|
6656
|
+
return segments;
|
|
6657
|
+
}
|
|
6658
|
+
function Annotate({
|
|
6659
|
+
data,
|
|
6660
|
+
block,
|
|
6661
|
+
onInteraction
|
|
6662
|
+
}) {
|
|
6663
|
+
const { title, labels, text } = data;
|
|
6664
|
+
const baseId = `glyph-annotate-${block.id}`;
|
|
6665
|
+
const [annotations, setAnnotations] = useState(data.annotations ?? []);
|
|
6666
|
+
const [pickerPos, setPickerPos] = useState(null);
|
|
6667
|
+
const [pendingSelection, setPendingSelection] = useState(null);
|
|
6668
|
+
const textRef = useRef(null);
|
|
6669
|
+
const handleMouseUp = useCallback(() => {
|
|
6670
|
+
const selection = window.getSelection();
|
|
6671
|
+
if (!selection || selection.isCollapsed || !textRef.current) return;
|
|
6672
|
+
const range = selection.getRangeAt(0);
|
|
6673
|
+
if (!range || !textRef.current.contains(range.commonAncestorContainer)) return;
|
|
6674
|
+
const selectedText = selection.toString();
|
|
6675
|
+
if (!selectedText.trim()) return;
|
|
6676
|
+
const preCaretRange = document.createRange();
|
|
6677
|
+
preCaretRange.selectNodeContents(textRef.current);
|
|
6678
|
+
preCaretRange.setEnd(range.startContainer, range.startOffset);
|
|
6679
|
+
const startOffset = preCaretRange.toString().length;
|
|
6680
|
+
const endOffset = startOffset + selectedText.length;
|
|
6681
|
+
const rect = range.getBoundingClientRect();
|
|
6682
|
+
const containerRect = textRef.current.getBoundingClientRect();
|
|
6683
|
+
setPendingSelection({ start: startOffset, end: endOffset, text: selectedText });
|
|
6684
|
+
setPickerPos({
|
|
6685
|
+
x: rect.left - containerRect.left,
|
|
6686
|
+
y: rect.bottom - containerRect.top + 4
|
|
6687
|
+
});
|
|
6688
|
+
}, []);
|
|
6689
|
+
const selectLabel = (labelName) => {
|
|
6690
|
+
if (!pendingSelection) return;
|
|
6691
|
+
const newAnnotation = {
|
|
6692
|
+
start: pendingSelection.start,
|
|
6693
|
+
end: pendingSelection.end,
|
|
6694
|
+
label: labelName
|
|
6695
|
+
};
|
|
6696
|
+
const newAnnotations = [...annotations, newAnnotation];
|
|
6697
|
+
setAnnotations(newAnnotations);
|
|
6698
|
+
setPickerPos(null);
|
|
6699
|
+
setPendingSelection(null);
|
|
6700
|
+
window.getSelection()?.removeAllRanges();
|
|
6701
|
+
if (onInteraction) {
|
|
6702
|
+
onInteraction({
|
|
6703
|
+
kind: "annotate-create",
|
|
6704
|
+
timestamp: (/* @__PURE__ */ new Date()).toISOString(),
|
|
6705
|
+
blockId: block.id,
|
|
6706
|
+
blockType: block.type,
|
|
6707
|
+
payload: {
|
|
6708
|
+
start: newAnnotation.start,
|
|
6709
|
+
end: newAnnotation.end,
|
|
6710
|
+
selectedText: pendingSelection.text,
|
|
6711
|
+
label: labelName,
|
|
6712
|
+
allAnnotations: newAnnotations.map((a) => ({
|
|
6713
|
+
start: a.start,
|
|
6714
|
+
end: a.end,
|
|
6715
|
+
text: text.slice(a.start, a.end),
|
|
6716
|
+
label: a.label
|
|
6717
|
+
}))
|
|
6718
|
+
}
|
|
6719
|
+
});
|
|
6720
|
+
}
|
|
6721
|
+
};
|
|
6722
|
+
const closePicker = (e) => {
|
|
6723
|
+
if (e.target.closest("[data-label-picker]")) return;
|
|
6724
|
+
setPickerPos(null);
|
|
6725
|
+
setPendingSelection(null);
|
|
6726
|
+
};
|
|
6727
|
+
const segments = computeSegments(text, annotations);
|
|
6728
|
+
const labelColorMap = new Map(labels.map((l) => [l.name, l.color]));
|
|
6729
|
+
return /* @__PURE__ */ jsxs(
|
|
6730
|
+
"div",
|
|
6731
|
+
{
|
|
6732
|
+
id: baseId,
|
|
6733
|
+
role: "region",
|
|
6734
|
+
"aria-label": title ?? "Annotate",
|
|
6735
|
+
style: containerStyle10,
|
|
6736
|
+
onClick: closePicker,
|
|
6737
|
+
children: [
|
|
6738
|
+
title && /* @__PURE__ */ jsx("div", { style: headerStyle9, children: title }),
|
|
6739
|
+
/* @__PURE__ */ jsxs("div", { style: bodyStyle2, children: [
|
|
6740
|
+
/* @__PURE__ */ jsxs("div", { ref: textRef, role: "document", style: textPaneStyle, onMouseUp: handleMouseUp, children: [
|
|
6741
|
+
segments.map((seg, i) => {
|
|
6742
|
+
if (seg.annotation) {
|
|
6743
|
+
const color3 = labelColorMap.get(seg.annotation.label) ?? "#888";
|
|
6744
|
+
return /* @__PURE__ */ jsx(
|
|
6745
|
+
"mark",
|
|
6746
|
+
{
|
|
6747
|
+
style: {
|
|
6748
|
+
backgroundColor: `${color3}33`,
|
|
6749
|
+
borderBottom: `2px solid ${color3}`,
|
|
6750
|
+
padding: "0 1px"
|
|
6751
|
+
},
|
|
6752
|
+
title: `${seg.annotation.label}${seg.annotation.note ? `: ${seg.annotation.note}` : ""}`,
|
|
6753
|
+
children: seg.text
|
|
6754
|
+
},
|
|
6755
|
+
i
|
|
6756
|
+
);
|
|
6757
|
+
}
|
|
6758
|
+
return /* @__PURE__ */ jsx("span", { children: seg.text }, i);
|
|
6759
|
+
}),
|
|
6760
|
+
pickerPos && /* @__PURE__ */ jsx(
|
|
6761
|
+
"div",
|
|
6762
|
+
{
|
|
6763
|
+
role: "menu",
|
|
6764
|
+
"data-label-picker": true,
|
|
6765
|
+
style: {
|
|
6766
|
+
...labelPickerStyle,
|
|
6767
|
+
left: `${String(pickerPos.x)}px`,
|
|
6768
|
+
top: `${String(pickerPos.y)}px`
|
|
6769
|
+
},
|
|
6770
|
+
children: labels.map((label) => /* @__PURE__ */ jsxs(
|
|
6771
|
+
"button",
|
|
6772
|
+
{
|
|
6773
|
+
role: "menuitem",
|
|
6774
|
+
style: labelOptionStyle(),
|
|
6775
|
+
onClick: (e) => {
|
|
6776
|
+
e.stopPropagation();
|
|
6777
|
+
selectLabel(label.name);
|
|
6778
|
+
},
|
|
6779
|
+
children: [
|
|
6780
|
+
/* @__PURE__ */ jsx("span", { style: colorDotStyle(label.color) }),
|
|
6781
|
+
label.name
|
|
6782
|
+
]
|
|
6783
|
+
},
|
|
6784
|
+
label.name
|
|
6785
|
+
))
|
|
6786
|
+
}
|
|
6787
|
+
)
|
|
6788
|
+
] }),
|
|
6789
|
+
/* @__PURE__ */ jsxs("div", { style: sidebarStyle, role: "complementary", "aria-label": "Annotations", children: [
|
|
6790
|
+
/* @__PURE__ */ jsxs("div", { style: sidebarHeaderStyle, children: [
|
|
6791
|
+
"Annotations (",
|
|
6792
|
+
String(annotations.length),
|
|
6793
|
+
")"
|
|
6794
|
+
] }),
|
|
6795
|
+
/* @__PURE__ */ jsxs("div", { role: "list", children: [
|
|
6796
|
+
annotations.map((ann, i) => {
|
|
6797
|
+
const color3 = labelColorMap.get(ann.label) ?? "#888";
|
|
6798
|
+
return /* @__PURE__ */ jsxs("div", { role: "listitem", style: annotationItemStyle(color3), children: [
|
|
6799
|
+
/* @__PURE__ */ jsxs("div", { style: { display: "flex", alignItems: "center", gap: "0.375rem" }, children: [
|
|
6800
|
+
/* @__PURE__ */ jsx("span", { style: colorDotStyle(color3) }),
|
|
6801
|
+
/* @__PURE__ */ jsx("strong", { style: { fontSize: "0.75rem" }, children: ann.label })
|
|
6802
|
+
] }),
|
|
6803
|
+
/* @__PURE__ */ jsx("div", { style: annotationTextStyle, children: text.slice(ann.start, ann.end) }),
|
|
6804
|
+
ann.note && /* @__PURE__ */ jsx("div", { style: annotationNoteStyle, children: ann.note })
|
|
6805
|
+
] }, i);
|
|
6806
|
+
}),
|
|
6807
|
+
annotations.length === 0 && /* @__PURE__ */ jsx(
|
|
6808
|
+
"div",
|
|
6809
|
+
{
|
|
6810
|
+
style: {
|
|
6811
|
+
padding: "0.75rem",
|
|
6812
|
+
fontSize: "0.75rem",
|
|
6813
|
+
color: "var(--glyph-text-muted, #6b7a94)"
|
|
6814
|
+
},
|
|
6815
|
+
children: "Select text to add annotations."
|
|
6816
|
+
}
|
|
6817
|
+
)
|
|
6818
|
+
] })
|
|
6819
|
+
] })
|
|
6820
|
+
] })
|
|
6821
|
+
]
|
|
6822
|
+
}
|
|
6823
|
+
);
|
|
6824
|
+
}
|
|
6825
|
+
|
|
6826
|
+
// src/annotate/index.ts
|
|
6827
|
+
var annotateDefinition = {
|
|
6828
|
+
type: "ui:annotate",
|
|
6829
|
+
schema: annotateSchema,
|
|
6830
|
+
render: Annotate
|
|
6831
|
+
};
|
|
6832
|
+
|
|
6833
|
+
export { Accordion, Annotate, Architecture, Callout, Card, Chart, CodeDiff, Comparison, Equation, FileTree, Flowchart, Form, Graph, Infographic, Kanban, Kpi, Matrix, MindMap, Poll, Quiz, Ranker, Rating, Relation, Sequence, Slider, Steps, Table, Tabs, Timeline, accordionDefinition, annotateDefinition, architectureDefinition, calloutDefinition, cardDefinition, chartDefinition, codeDiffDefinition, comparisonDefinition, computeArchitectureLayout, computeDagreLayout, computeDiff, computeForceLayout, equationDefinition, fileTreeDefinition, flowchartDefinition, formDefinition, graphDefinition, infographicDefinition, kanbanDefinition, kpiDefinition, matrixDefinition, mindMapDefinition, pollDefinition, quizDefinition, rankerDefinition, ratingDefinition, relationDefinition, sequenceDefinition, sliderDefinition, stepsDefinition, tableDefinition, tabsDefinition, timelineDefinition };
|
|
4854
6834
|
//# sourceMappingURL=index.js.map
|
|
4855
6835
|
//# sourceMappingURL=index.js.map
|