@mathscan/math-exercise-engine 1.2.4 → 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 +18 -0
- package/dist/index.js +28 -9
- package/dist/index.js.map +1 -1
- package/dist/index.mjs +28 -9
- package/dist/index.mjs.map +1 -1
- package/dist/style.css +59 -46
- package/package.json +1 -1
package/dist/index.d.ts
CHANGED
|
@@ -30416,6 +30416,8 @@ export declare interface ExerciseRendererProps {
|
|
|
30416
30416
|
soundEnabled?: boolean;
|
|
30417
30417
|
/** Maps sound events → URL or callback. Omitted events stay silent. */
|
|
30418
30418
|
sounds?: SoundConfig;
|
|
30419
|
+
/** Overrides for validation state colors. */
|
|
30420
|
+
theme?: ExerciseTheme;
|
|
30419
30421
|
}
|
|
30420
30422
|
|
|
30421
30423
|
export declare interface ExerciseRendererRef {
|
|
@@ -30429,6 +30431,22 @@ export declare interface ExerciseRendererRef {
|
|
|
30429
30431
|
revealAnswers: () => void;
|
|
30430
30432
|
}
|
|
30431
30433
|
|
|
30434
|
+
/**
|
|
30435
|
+
* Validation state colors, applied as inline CSS variables on the renderer root.
|
|
30436
|
+
* Inline beats any stylesheet, so this is the reliable way for a host to recolor
|
|
30437
|
+
* per attempt (e.g. orange on the 1st wrong answer, red on the 2nd) — a
|
|
30438
|
+
* `--exercise-incorrect` set on a wrapper is shadowed by variables.css.
|
|
30439
|
+
* Background tints derive from these via color-mix. Omitted keys keep the defaults.
|
|
30440
|
+
* Values must be valid CSS colors: an invalid one does NOT fall back to the
|
|
30441
|
+
* default, it leaves the affected styles uncolored (dev builds log a warning).
|
|
30442
|
+
* Change the color when a retry starts, not in onSubmit — otherwise the result
|
|
30443
|
+
* still on screen recolors immediately.
|
|
30444
|
+
*/
|
|
30445
|
+
export declare interface ExerciseTheme {
|
|
30446
|
+
correct?: string;
|
|
30447
|
+
incorrect?: string;
|
|
30448
|
+
}
|
|
30449
|
+
|
|
30432
30450
|
export declare type ExpressionValidation = z.infer<typeof ExpressionValidationSchema>;
|
|
30433
30451
|
|
|
30434
30452
|
/**
|
package/dist/index.js
CHANGED
|
@@ -11918,7 +11918,7 @@ function getEventCoordinates(event) {
|
|
|
11918
11918
|
}
|
|
11919
11919
|
return null;
|
|
11920
11920
|
}
|
|
11921
|
-
const CSS = /* @__PURE__ */ Object.freeze({
|
|
11921
|
+
const CSS$1 = /* @__PURE__ */ Object.freeze({
|
|
11922
11922
|
Translate: {
|
|
11923
11923
|
toString(transform) {
|
|
11924
11924
|
if (!transform) {
|
|
@@ -11948,7 +11948,7 @@ const CSS = /* @__PURE__ */ Object.freeze({
|
|
|
11948
11948
|
if (!transform) {
|
|
11949
11949
|
return;
|
|
11950
11950
|
}
|
|
11951
|
-
return [CSS.Translate.toString(transform), CSS.Scale.toString(transform)].join(" ");
|
|
11951
|
+
return [CSS$1.Translate.toString(transform), CSS$1.Scale.toString(transform)].join(" ");
|
|
11952
11952
|
}
|
|
11953
11953
|
},
|
|
11954
11954
|
Transition: {
|
|
@@ -15067,7 +15067,7 @@ const PositionedOverlay = /* @__PURE__ */ React.forwardRef((_ref, ref) => {
|
|
|
15067
15067
|
height: rect.height,
|
|
15068
15068
|
top: rect.top,
|
|
15069
15069
|
left: rect.left,
|
|
15070
|
-
transform: CSS.Transform.toString(scaleAdjustedTransform),
|
|
15070
|
+
transform: CSS$1.Transform.toString(scaleAdjustedTransform),
|
|
15071
15071
|
transformOrigin: adjustScale2 && activatorEvent ? getRelativeTransformOrigin(activatorEvent, rect) : void 0,
|
|
15072
15072
|
transition: typeof transition === "function" ? transition(activatorEvent) : transition,
|
|
15073
15073
|
...style
|
|
@@ -15128,9 +15128,9 @@ const defaultKeyframeResolver = (_ref2) => {
|
|
|
15128
15128
|
}
|
|
15129
15129
|
} = _ref2;
|
|
15130
15130
|
return [{
|
|
15131
|
-
transform: CSS.Transform.toString(initial)
|
|
15131
|
+
transform: CSS$1.Transform.toString(initial)
|
|
15132
15132
|
}, {
|
|
15133
|
-
transform: CSS.Transform.toString(final)
|
|
15133
|
+
transform: CSS$1.Transform.toString(final)
|
|
15134
15134
|
}];
|
|
15135
15135
|
};
|
|
15136
15136
|
const defaultDropAnimationConfiguration = {
|
|
@@ -15563,7 +15563,7 @@ const Draggable = ({
|
|
|
15563
15563
|
disabled
|
|
15564
15564
|
});
|
|
15565
15565
|
const style = {
|
|
15566
|
-
transform: CSS.Translate.toString(transform),
|
|
15566
|
+
transform: CSS$1.Translate.toString(transform),
|
|
15567
15567
|
cursor: disabled ? "default" : "grab",
|
|
15568
15568
|
touchAction: "none"
|
|
15569
15569
|
};
|
|
@@ -17923,7 +17923,7 @@ const CHART_TYPE_COMPONENTS = {
|
|
|
17923
17923
|
const Chart = (props) => {
|
|
17924
17924
|
const ChartComponent = CHART_TYPE_COMPONENTS[props.item.chartType];
|
|
17925
17925
|
if (!ChartComponent) {
|
|
17926
|
-
return /* @__PURE__ */ jsxRuntime.jsx("div", { className: "chart chart--unsupported", children: /* @__PURE__ */ jsxRuntime.jsx("span", { style: { color: "var(--exercise-
|
|
17926
|
+
return /* @__PURE__ */ jsxRuntime.jsx("div", { className: "chart chart--unsupported", children: /* @__PURE__ */ jsxRuntime.jsx("span", { style: { color: "var(--exercise-error, #ef4444)", fontSize: "0.85rem" }, children: `Chart type "${props.item.chartType}" is not yet supported.` }) });
|
|
17927
17927
|
}
|
|
17928
17928
|
return /* @__PURE__ */ jsxRuntime.jsx(ChartComponent, { ...props });
|
|
17929
17929
|
};
|
|
@@ -20843,6 +20843,15 @@ const TOOL_ASPECT_RATIO = {
|
|
|
20843
20843
|
"set-square": SET_SQUARE_ASPECT_RATIO
|
|
20844
20844
|
};
|
|
20845
20845
|
const FLIP_BTN_EXTRA = 44;
|
|
20846
|
+
function warnOnInvalidThemeColors(theme) {
|
|
20847
|
+
if (process.env.NODE_ENV === "production" || !theme) return;
|
|
20848
|
+
if (typeof CSS === "undefined" || typeof CSS.supports !== "function") return;
|
|
20849
|
+
for (const [key2, value] of Object.entries(theme)) {
|
|
20850
|
+
if (value && !CSS.supports("color", value)) {
|
|
20851
|
+
console.warn(`[ExerciseRenderer] theme.${key2} is not a valid CSS color: "${value}"`);
|
|
20852
|
+
}
|
|
20853
|
+
}
|
|
20854
|
+
}
|
|
20846
20855
|
function buildInitialValues(json) {
|
|
20847
20856
|
const initial = {};
|
|
20848
20857
|
for (const [id, widget] of Object.entries(json.widgets)) {
|
|
@@ -20915,7 +20924,8 @@ const ExerciseRenderer = React.forwardRef(({
|
|
|
20915
20924
|
showSubmitButton = false,
|
|
20916
20925
|
className = "",
|
|
20917
20926
|
soundEnabled = true,
|
|
20918
|
-
sounds
|
|
20927
|
+
sounds,
|
|
20928
|
+
theme
|
|
20919
20929
|
}, ref) => {
|
|
20920
20930
|
const initialValuesSignature = React.useMemo(() => buildInitialValuesSignature(json), [json]);
|
|
20921
20931
|
const [values, setValues] = React.useState(() => buildInitialValues(json));
|
|
@@ -20929,6 +20939,15 @@ const ExerciseRenderer = React.forwardRef(({
|
|
|
20929
20939
|
const rootRef = React.useRef(null);
|
|
20930
20940
|
const [resetKey, setResetKey] = React.useState(0);
|
|
20931
20941
|
const [revealed, setRevealed] = React.useState(false);
|
|
20942
|
+
const themeStyle = React.useMemo(() => {
|
|
20943
|
+
const style = {};
|
|
20944
|
+
if (theme?.correct) style["--exercise-correct"] = theme.correct;
|
|
20945
|
+
if (theme?.incorrect) style["--exercise-incorrect"] = theme.incorrect;
|
|
20946
|
+
return Object.keys(style).length > 0 ? style : void 0;
|
|
20947
|
+
}, [theme?.correct, theme?.incorrect]);
|
|
20948
|
+
React.useEffect(() => {
|
|
20949
|
+
warnOnInvalidThemeColors({ correct: theme?.correct, incorrect: theme?.incorrect });
|
|
20950
|
+
}, [theme?.correct, theme?.incorrect]);
|
|
20932
20951
|
const playSound = useSoundPlayer(soundEnabled, sounds);
|
|
20933
20952
|
const externallyLocked = useExerciseLocked();
|
|
20934
20953
|
React.useLayoutEffect(() => {
|
|
@@ -21185,7 +21204,7 @@ const ExerciseRenderer = React.forwardRef(({
|
|
|
21185
21204
|
if (setSquareWidget) add2("set-square-1", "set-square", Math.round(getSize(setSquareWidget) * 160));
|
|
21186
21205
|
return { tools: list, toolsMinHeight: maxH };
|
|
21187
21206
|
}, [rulerWidget, protractorWidget, setSquareWidget]);
|
|
21188
|
-
return /* @__PURE__ */ jsxRuntime.jsx(SoundPlayerProvider, { play: playSound, children: /* @__PURE__ */ jsxRuntime.jsx(ExerciseLockProvider, { locked, children: /* @__PURE__ */ jsxRuntime.jsx(ExerciseDndProvider, { droppedSources, children: /* @__PURE__ */ jsxRuntime.jsxs("div", { ref: rootRef, className: `math-exercise-renderer ${revealed ? "revealed" : ""} ${locked ? "locked" : ""} ${className}`, children: [
|
|
21207
|
+
return /* @__PURE__ */ jsxRuntime.jsx(SoundPlayerProvider, { play: playSound, children: /* @__PURE__ */ jsxRuntime.jsx(ExerciseLockProvider, { locked, children: /* @__PURE__ */ jsxRuntime.jsx(ExerciseDndProvider, { droppedSources, children: /* @__PURE__ */ jsxRuntime.jsxs("div", { ref: rootRef, className: `math-exercise-renderer ${revealed ? "revealed" : ""} ${locked ? "locked" : ""} ${className}`, style: themeStyle, children: [
|
|
21189
21208
|
/* @__PURE__ */ jsxRuntime.jsxs(
|
|
21190
21209
|
"div",
|
|
21191
21210
|
{
|