@mathscan/math-exercise-engine 1.2.3 → 1.2.5
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.d.ts +38 -0
- package/dist/index.js +45 -12
- package/dist/index.js.map +1 -1
- package/dist/index.mjs +45 -12
- package/dist/index.mjs.map +1 -1
- package/dist/style.css +69 -50
- package/package.json +1 -1
package/dist/index.mjs
CHANGED
|
@@ -265,6 +265,10 @@ const HEX_COLOR_REGEX = /^#([0-9A-Fa-f]{3}|[0-9A-Fa-f]{6})$/;
|
|
|
265
265
|
const isNumberLineHighlightColor = (value) => NUMBER_LINE_HIGHLIGHT_COLORS.includes(value) || HEX_COLOR_REGEX.test(value);
|
|
266
266
|
const highlightColorMessage = (block) => `${block}: color must be one of ${NUMBER_LINE_HIGHLIGHT_COLORS.join(", ")} or a hex value (e.g. "#3B82F6")`;
|
|
267
267
|
const NUMBER_LINE_DRAG_MODES = ["axis", "inputs"];
|
|
268
|
+
const DEFAULT_TABLE_BORDER_COLOR = "#7c6cf2";
|
|
269
|
+
const isTableBorderColor = (value) => value.toLowerCase() === "transparent" || HEX_COLOR_REGEX.test(value);
|
|
270
|
+
const TABLE_BORDER_COLOR_ERROR = 'TABLE: bordercolor must be "transparent" or a hex value (e.g. "#E67E22" or "#F00")';
|
|
271
|
+
const TableBorderColorSchema = z.string({ message: TABLE_BORDER_COLOR_ERROR }).refine(isTableBorderColor, { message: TABLE_BORDER_COLOR_ERROR }).default(DEFAULT_TABLE_BORDER_COLOR);
|
|
268
272
|
function getFractionKey(widgetId, part) {
|
|
269
273
|
return `${widgetId}__${part}`;
|
|
270
274
|
}
|
|
@@ -2534,12 +2538,14 @@ function createTableRow(cells, backgroundColor) {
|
|
|
2534
2538
|
const TableBlockSchema = z.object({
|
|
2535
2539
|
type: z.literal(AST_TYPES.TABLE_BLOCK),
|
|
2536
2540
|
cols: z.number().int().positive(),
|
|
2541
|
+
borderColor: TableBorderColorSchema,
|
|
2537
2542
|
rows: z.array(TableRowSchema).min(1)
|
|
2538
2543
|
});
|
|
2539
|
-
function createTableBlock(cols, rows) {
|
|
2544
|
+
function createTableBlock(cols, rows, borderColor) {
|
|
2540
2545
|
return TableBlockSchema.parse({
|
|
2541
2546
|
type: AST_TYPES.TABLE_BLOCK,
|
|
2542
2547
|
cols,
|
|
2548
|
+
borderColor,
|
|
2543
2549
|
rows
|
|
2544
2550
|
});
|
|
2545
2551
|
}
|
|
@@ -3484,8 +3490,10 @@ class NaturalDSLVisitor extends BaseCstVisitor {
|
|
|
3484
3490
|
table(ctx) {
|
|
3485
3491
|
const params = this.visit(ctx.parameterList);
|
|
3486
3492
|
const cols = params.cols;
|
|
3493
|
+
const borderColorParam = params.bordercolor;
|
|
3494
|
+
const borderColor = borderColorParam === void 0 ? void 0 : String(borderColorParam);
|
|
3487
3495
|
const rows = ctx.row.map((r) => this.visit(r));
|
|
3488
|
-
return createTableBlock(cols, rows);
|
|
3496
|
+
return createTableBlock(cols, rows, borderColor);
|
|
3489
3497
|
}
|
|
3490
3498
|
row(ctx) {
|
|
3491
3499
|
const params = ctx.parameterList ? this.visit(ctx.parameterList) : {};
|
|
@@ -4280,6 +4288,7 @@ const TableItemSchema = z.object({
|
|
|
4280
4288
|
id: z.string(),
|
|
4281
4289
|
type: z.literal(JSON_TYPES.TABLE),
|
|
4282
4290
|
cols: z.number().int().positive(),
|
|
4291
|
+
borderColor: TableBorderColorSchema,
|
|
4283
4292
|
rows: z.array(TableRowItemSchema)
|
|
4284
4293
|
});
|
|
4285
4294
|
const NumberLinePositionItemSchema = z.object({
|
|
@@ -10864,6 +10873,7 @@ function transformTable(table, idGenerator, inlineDragIds) {
|
|
|
10864
10873
|
id: idGenerator.generate(JSON_TYPES.TABLE),
|
|
10865
10874
|
type: JSON_TYPES.TABLE,
|
|
10866
10875
|
cols: table.cols,
|
|
10876
|
+
borderColor: table.borderColor,
|
|
10867
10877
|
rows
|
|
10868
10878
|
};
|
|
10869
10879
|
}
|
|
@@ -11906,7 +11916,7 @@ function getEventCoordinates(event) {
|
|
|
11906
11916
|
}
|
|
11907
11917
|
return null;
|
|
11908
11918
|
}
|
|
11909
|
-
const CSS = /* @__PURE__ */ Object.freeze({
|
|
11919
|
+
const CSS$1 = /* @__PURE__ */ Object.freeze({
|
|
11910
11920
|
Translate: {
|
|
11911
11921
|
toString(transform) {
|
|
11912
11922
|
if (!transform) {
|
|
@@ -11936,7 +11946,7 @@ const CSS = /* @__PURE__ */ Object.freeze({
|
|
|
11936
11946
|
if (!transform) {
|
|
11937
11947
|
return;
|
|
11938
11948
|
}
|
|
11939
|
-
return [CSS.Translate.toString(transform), CSS.Scale.toString(transform)].join(" ");
|
|
11949
|
+
return [CSS$1.Translate.toString(transform), CSS$1.Scale.toString(transform)].join(" ");
|
|
11940
11950
|
}
|
|
11941
11951
|
},
|
|
11942
11952
|
Transition: {
|
|
@@ -15055,7 +15065,7 @@ const PositionedOverlay = /* @__PURE__ */ forwardRef((_ref, ref) => {
|
|
|
15055
15065
|
height: rect.height,
|
|
15056
15066
|
top: rect.top,
|
|
15057
15067
|
left: rect.left,
|
|
15058
|
-
transform: CSS.Transform.toString(scaleAdjustedTransform),
|
|
15068
|
+
transform: CSS$1.Transform.toString(scaleAdjustedTransform),
|
|
15059
15069
|
transformOrigin: adjustScale2 && activatorEvent ? getRelativeTransformOrigin(activatorEvent, rect) : void 0,
|
|
15060
15070
|
transition: typeof transition === "function" ? transition(activatorEvent) : transition,
|
|
15061
15071
|
...style
|
|
@@ -15116,9 +15126,9 @@ const defaultKeyframeResolver = (_ref2) => {
|
|
|
15116
15126
|
}
|
|
15117
15127
|
} = _ref2;
|
|
15118
15128
|
return [{
|
|
15119
|
-
transform: CSS.Transform.toString(initial)
|
|
15129
|
+
transform: CSS$1.Transform.toString(initial)
|
|
15120
15130
|
}, {
|
|
15121
|
-
transform: CSS.Transform.toString(final)
|
|
15131
|
+
transform: CSS$1.Transform.toString(final)
|
|
15122
15132
|
}];
|
|
15123
15133
|
};
|
|
15124
15134
|
const defaultDropAnimationConfiguration = {
|
|
@@ -15551,7 +15561,7 @@ const Draggable = ({
|
|
|
15551
15561
|
disabled
|
|
15552
15562
|
});
|
|
15553
15563
|
const style = {
|
|
15554
|
-
transform: CSS.Translate.toString(transform),
|
|
15564
|
+
transform: CSS$1.Translate.toString(transform),
|
|
15555
15565
|
cursor: disabled ? "default" : "grab",
|
|
15556
15566
|
touchAction: "none"
|
|
15557
15567
|
};
|
|
@@ -17911,7 +17921,7 @@ const CHART_TYPE_COMPONENTS = {
|
|
|
17911
17921
|
const Chart = (props) => {
|
|
17912
17922
|
const ChartComponent = CHART_TYPE_COMPONENTS[props.item.chartType];
|
|
17913
17923
|
if (!ChartComponent) {
|
|
17914
|
-
return /* @__PURE__ */ jsx("div", { className: "chart chart--unsupported", children: /* @__PURE__ */ jsx("span", { style: { color: "var(--exercise-
|
|
17924
|
+
return /* @__PURE__ */ jsx("div", { className: "chart chart--unsupported", children: /* @__PURE__ */ jsx("span", { style: { color: "var(--exercise-error, #ef4444)", fontSize: "0.85rem" }, children: `Chart type "${props.item.chartType}" is not yet supported.` }) });
|
|
17915
17925
|
}
|
|
17916
17926
|
return /* @__PURE__ */ jsx(ChartComponent, { ...props });
|
|
17917
17927
|
};
|
|
@@ -20625,7 +20635,10 @@ const LayoutRenderer = ({
|
|
|
20625
20635
|
)) });
|
|
20626
20636
|
case JSON_TYPES.TABLE: {
|
|
20627
20637
|
const totalRows = item.rows.length;
|
|
20628
|
-
|
|
20638
|
+
const tableStyle = {
|
|
20639
|
+
"--exercise-table-border-color": item.borderColor ?? DEFAULT_TABLE_BORDER_COLOR
|
|
20640
|
+
};
|
|
20641
|
+
return /* @__PURE__ */ jsx("div", { className: "exercise-table-container", style: tableStyle, children: /* @__PURE__ */ jsx("table", { className: "exercise-table", children: /* @__PURE__ */ jsx("tbody", { children: item.rows.map((row, rowIndex) => /* @__PURE__ */ jsx("tr", { className: "exercise-table-row", style: { backgroundColor: row.backgroundColor }, children: row.cells.map((cell) => {
|
|
20629
20642
|
const rowspan = cell.rowspan || 1;
|
|
20630
20643
|
const isLastRow = rowIndex + rowspan - 1 >= totalRows - 1;
|
|
20631
20644
|
return /* @__PURE__ */ jsx(
|
|
@@ -20828,6 +20841,15 @@ const TOOL_ASPECT_RATIO = {
|
|
|
20828
20841
|
"set-square": SET_SQUARE_ASPECT_RATIO
|
|
20829
20842
|
};
|
|
20830
20843
|
const FLIP_BTN_EXTRA = 44;
|
|
20844
|
+
function warnOnInvalidThemeColors(theme) {
|
|
20845
|
+
if (process.env.NODE_ENV === "production" || !theme) return;
|
|
20846
|
+
if (typeof CSS === "undefined" || typeof CSS.supports !== "function") return;
|
|
20847
|
+
for (const [key2, value] of Object.entries(theme)) {
|
|
20848
|
+
if (value && !CSS.supports("color", value)) {
|
|
20849
|
+
console.warn(`[ExerciseRenderer] theme.${key2} is not a valid CSS color: "${value}"`);
|
|
20850
|
+
}
|
|
20851
|
+
}
|
|
20852
|
+
}
|
|
20831
20853
|
function buildInitialValues(json) {
|
|
20832
20854
|
const initial = {};
|
|
20833
20855
|
for (const [id, widget] of Object.entries(json.widgets)) {
|
|
@@ -20900,7 +20922,8 @@ const ExerciseRenderer = forwardRef(({
|
|
|
20900
20922
|
showSubmitButton = false,
|
|
20901
20923
|
className = "",
|
|
20902
20924
|
soundEnabled = true,
|
|
20903
|
-
sounds
|
|
20925
|
+
sounds,
|
|
20926
|
+
theme
|
|
20904
20927
|
}, ref) => {
|
|
20905
20928
|
const initialValuesSignature = useMemo(() => buildInitialValuesSignature(json), [json]);
|
|
20906
20929
|
const [values, setValues] = useState(() => buildInitialValues(json));
|
|
@@ -20914,6 +20937,15 @@ const ExerciseRenderer = forwardRef(({
|
|
|
20914
20937
|
const rootRef = useRef(null);
|
|
20915
20938
|
const [resetKey, setResetKey] = useState(0);
|
|
20916
20939
|
const [revealed, setRevealed] = useState(false);
|
|
20940
|
+
const themeStyle = useMemo(() => {
|
|
20941
|
+
const style = {};
|
|
20942
|
+
if (theme?.correct) style["--exercise-correct"] = theme.correct;
|
|
20943
|
+
if (theme?.incorrect) style["--exercise-incorrect"] = theme.incorrect;
|
|
20944
|
+
return Object.keys(style).length > 0 ? style : void 0;
|
|
20945
|
+
}, [theme?.correct, theme?.incorrect]);
|
|
20946
|
+
useEffect(() => {
|
|
20947
|
+
warnOnInvalidThemeColors({ correct: theme?.correct, incorrect: theme?.incorrect });
|
|
20948
|
+
}, [theme?.correct, theme?.incorrect]);
|
|
20917
20949
|
const playSound = useSoundPlayer(soundEnabled, sounds);
|
|
20918
20950
|
const externallyLocked = useExerciseLocked();
|
|
20919
20951
|
useLayoutEffect(() => {
|
|
@@ -21170,7 +21202,7 @@ const ExerciseRenderer = forwardRef(({
|
|
|
21170
21202
|
if (setSquareWidget) add2("set-square-1", "set-square", Math.round(getSize(setSquareWidget) * 160));
|
|
21171
21203
|
return { tools: list, toolsMinHeight: maxH };
|
|
21172
21204
|
}, [rulerWidget, protractorWidget, setSquareWidget]);
|
|
21173
|
-
return /* @__PURE__ */ jsx(SoundPlayerProvider, { play: playSound, children: /* @__PURE__ */ jsx(ExerciseLockProvider, { locked, children: /* @__PURE__ */ jsx(ExerciseDndProvider, { droppedSources, children: /* @__PURE__ */ jsxs("div", { ref: rootRef, className: `math-exercise-renderer ${revealed ? "revealed" : ""} ${locked ? "locked" : ""} ${className}`, children: [
|
|
21205
|
+
return /* @__PURE__ */ jsx(SoundPlayerProvider, { play: playSound, children: /* @__PURE__ */ jsx(ExerciseLockProvider, { locked, children: /* @__PURE__ */ jsx(ExerciseDndProvider, { droppedSources, children: /* @__PURE__ */ jsxs("div", { ref: rootRef, className: `math-exercise-renderer ${revealed ? "revealed" : ""} ${locked ? "locked" : ""} ${className}`, style: themeStyle, children: [
|
|
21174
21206
|
/* @__PURE__ */ jsxs(
|
|
21175
21207
|
"div",
|
|
21176
21208
|
{
|
|
@@ -21332,6 +21364,7 @@ export {
|
|
|
21332
21364
|
ColorTextInlineSchema,
|
|
21333
21365
|
ColorTextSchema,
|
|
21334
21366
|
ContentBlockSchema,
|
|
21367
|
+
DEFAULT_TABLE_BORDER_COLOR,
|
|
21335
21368
|
DisplayInlineNodeSchema,
|
|
21336
21369
|
DragOptionsJSONSchema,
|
|
21337
21370
|
DragOptionsToolSchema,
|