@mathscan/math-exercise-engine 1.0.16 → 1.0.17
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 +228 -0
- package/dist/index.js +84 -35
- package/dist/index.js.map +1 -1
- package/dist/index.mjs +84 -35
- package/dist/index.mjs.map +1 -1
- package/dist/style.css +15 -12
- package/package.json +1 -1
package/dist/index.mjs
CHANGED
|
@@ -158,6 +158,7 @@ const SIDE_PAD = 7;
|
|
|
158
158
|
const CSS_VAR_SIDE_PAD = "--nl-side-pad";
|
|
159
159
|
const NUMBER_LINE_LABELS = ["all", "extremes", "min-only", "max-only", "none"];
|
|
160
160
|
const NUMBER_LINE_HIGHLIGHT_COLORS = ["blue", "red", "green", "orange", "purple", "yellow"];
|
|
161
|
+
const NUMBER_LINE_DRAG_MODES = ["axis", "inputs"];
|
|
161
162
|
function getFractionKey(widgetId, part) {
|
|
162
163
|
return `${widgetId}__${part}`;
|
|
163
164
|
}
|
|
@@ -1154,7 +1155,8 @@ const FractionInlineSchema = z.object({
|
|
|
1154
1155
|
numerator: z.number().optional(),
|
|
1155
1156
|
denominator: z.number().optional(),
|
|
1156
1157
|
answer: z.string().optional(),
|
|
1157
|
-
simplified: z.boolean().default(true)
|
|
1158
|
+
simplified: z.boolean().default(true),
|
|
1159
|
+
placeholder: z.string().max(32).optional()
|
|
1158
1160
|
});
|
|
1159
1161
|
const IMAGE_SRC_SCHEME_RE$1 = /^(https?:\/\/|data:image\/)/i;
|
|
1160
1162
|
const ImageInlineSchema = z.object({
|
|
@@ -1436,6 +1438,11 @@ const NumberLineBlockSchema = z.object({
|
|
|
1436
1438
|
}).optional(),
|
|
1437
1439
|
counter: NumberLineCounterSchema.optional(),
|
|
1438
1440
|
highlights: z.array(NumberLineHighlightSchema).optional(),
|
|
1441
|
+
dragMode: z.enum(NUMBER_LINE_DRAG_MODES, {
|
|
1442
|
+
errorMap: () => ({
|
|
1443
|
+
message: `NUMBER_LINE: dragMode must be one of ${NUMBER_LINE_DRAG_MODES.join(", ")}`
|
|
1444
|
+
})
|
|
1445
|
+
}).optional(),
|
|
1439
1446
|
positions: z.array(NumberLinePositionSchema)
|
|
1440
1447
|
}).refine((data) => data.min < data.max, {
|
|
1441
1448
|
message: "NUMBER_LINE: min must be less than max"
|
|
@@ -1473,7 +1480,7 @@ const NumberLineBlockSchema = z.object({
|
|
|
1473
1480
|
}
|
|
1474
1481
|
}
|
|
1475
1482
|
});
|
|
1476
|
-
function createNumberLineBlock(min, max, positions, step, minorTicks, style, labelVisibility, counter, highlights) {
|
|
1483
|
+
function createNumberLineBlock(min, max, positions, step, minorTicks, style, labelVisibility, counter, highlights, dragMode) {
|
|
1477
1484
|
return NumberLineBlockSchema.parse({
|
|
1478
1485
|
type: AST_TYPES.NUMBER_LINE_BLOCK,
|
|
1479
1486
|
min,
|
|
@@ -1484,6 +1491,7 @@ function createNumberLineBlock(min, max, positions, step, minorTicks, style, lab
|
|
|
1484
1491
|
labelVisibility,
|
|
1485
1492
|
counter,
|
|
1486
1493
|
highlights,
|
|
1494
|
+
dragMode,
|
|
1487
1495
|
positions
|
|
1488
1496
|
});
|
|
1489
1497
|
}
|
|
@@ -1848,6 +1856,7 @@ class NaturalDSLVisitor extends BaseCstVisitor {
|
|
|
1848
1856
|
const minorTicks = params.minorTicks !== void 0 ? Number(params.minorTicks) : void 0;
|
|
1849
1857
|
const style = params.style;
|
|
1850
1858
|
const labelVisibility = params.labelVisibility;
|
|
1859
|
+
const dragMode = params.dragMode;
|
|
1851
1860
|
const positions = ctx.position ? ctx.position.map((p) => this.visit(p)) : [];
|
|
1852
1861
|
const rawCounters = ctx.counter;
|
|
1853
1862
|
if (rawCounters && rawCounters.length > 1) {
|
|
@@ -1855,7 +1864,7 @@ class NaturalDSLVisitor extends BaseCstVisitor {
|
|
|
1855
1864
|
}
|
|
1856
1865
|
const counter = rawCounters ? this.visit(rawCounters) : void 0;
|
|
1857
1866
|
const highlights = ctx.highlight ? ctx.highlight.map((h) => this.visit(h)) : [];
|
|
1858
|
-
return createNumberLineBlock(min, max, positions, step, minorTicks, style, labelVisibility, counter, highlights);
|
|
1867
|
+
return createNumberLineBlock(min, max, positions, step, minorTicks, style, labelVisibility, counter, highlights, dragMode);
|
|
1859
1868
|
}
|
|
1860
1869
|
position(ctx) {
|
|
1861
1870
|
const params = this.visit(ctx.parameterList);
|
|
@@ -2048,7 +2057,8 @@ class NaturalDSLVisitor extends BaseCstVisitor {
|
|
|
2048
2057
|
const denominator = params.denominator;
|
|
2049
2058
|
const answer = params.answer;
|
|
2050
2059
|
const simplified = params.simplified !== void 0 ? params.simplified : void 0;
|
|
2051
|
-
|
|
2060
|
+
const placeholder = params.placeholder;
|
|
2061
|
+
return createFraction(name, { numerator, denominator, answer, simplified, placeholder });
|
|
2052
2062
|
}
|
|
2053
2063
|
image(ctx) {
|
|
2054
2064
|
const params = this.visit(ctx.parameterList);
|
|
@@ -2332,6 +2342,7 @@ const NumberLineItemSchema = z.object({
|
|
|
2332
2342
|
labelVisibility: z.enum(NUMBER_LINE_LABELS).optional(),
|
|
2333
2343
|
counter: NumberLineCounterItemSchema.optional(),
|
|
2334
2344
|
highlights: z.array(NumberLineHighlightItemSchema).optional(),
|
|
2345
|
+
dragMode: z.enum(NUMBER_LINE_DRAG_MODES).optional(),
|
|
2335
2346
|
positions: z.array(NumberLinePositionItemSchema)
|
|
2336
2347
|
});
|
|
2337
2348
|
const MatcherItemContentSchema = z.object({
|
|
@@ -2381,7 +2392,8 @@ const FractionJSONSchema = z.object({
|
|
|
2381
2392
|
type: z.literal(JSON_TYPES.FRACTION),
|
|
2382
2393
|
numerator: z.number().nullable(),
|
|
2383
2394
|
denominator: z.number().nullable(),
|
|
2384
|
-
simplified: z.boolean()
|
|
2395
|
+
simplified: z.boolean(),
|
|
2396
|
+
placeholder: z.string().max(32).optional()
|
|
2385
2397
|
});
|
|
2386
2398
|
const MatcherWidgetJSONSchema = z.object({
|
|
2387
2399
|
type: z.literal(JSON_TYPES.MATCHER),
|
|
@@ -2599,7 +2611,8 @@ function toJSON(ast) {
|
|
|
2599
2611
|
type: JSON_TYPES.FRACTION,
|
|
2600
2612
|
numerator: inline.numerator ?? null,
|
|
2601
2613
|
denominator: inline.denominator ?? null,
|
|
2602
|
-
simplified: inline.simplified ?? true
|
|
2614
|
+
simplified: inline.simplified ?? true,
|
|
2615
|
+
placeholder: inline.placeholder
|
|
2603
2616
|
};
|
|
2604
2617
|
if (inline.answer !== void 0) {
|
|
2605
2618
|
answers[inline.name] = inline.answer;
|
|
@@ -2730,6 +2743,7 @@ function transformNumberLine(numberLine, idGenerator) {
|
|
|
2730
2743
|
...numberLine.labelVisibility !== void 0 && { labelVisibility: numberLine.labelVisibility },
|
|
2731
2744
|
...counterItem !== void 0 && { counter: counterItem },
|
|
2732
2745
|
...highlights !== void 0 && { highlights },
|
|
2746
|
+
...numberLine.dragMode !== void 0 && { dragMode: numberLine.dragMode },
|
|
2733
2747
|
positions
|
|
2734
2748
|
};
|
|
2735
2749
|
return item;
|
|
@@ -13090,8 +13104,11 @@ const FractionInput = ({
|
|
|
13090
13104
|
values,
|
|
13091
13105
|
droppedInputs,
|
|
13092
13106
|
validationStatus = null,
|
|
13107
|
+
numValidationStatus = null,
|
|
13108
|
+
denValidationStatus = null,
|
|
13093
13109
|
onChange,
|
|
13094
|
-
onFocus
|
|
13110
|
+
onFocus,
|
|
13111
|
+
placeholder
|
|
13095
13112
|
}) => {
|
|
13096
13113
|
const numKey = getFractionKey(widgetId, "num");
|
|
13097
13114
|
const denKey = getFractionKey(widgetId, "den");
|
|
@@ -13104,11 +13121,12 @@ const FractionInput = ({
|
|
|
13104
13121
|
onChange(subKey, data.value, true, String(item.id));
|
|
13105
13122
|
}
|
|
13106
13123
|
}, [onChange]);
|
|
13107
|
-
const renderSlot = (subKey, fixedValue, currentValue, label) => {
|
|
13124
|
+
const renderSlot = (subKey, fixedValue, currentValue, label, slotStatus) => {
|
|
13108
13125
|
if (fixedValue !== null) {
|
|
13109
13126
|
return /* @__PURE__ */ jsx("span", { className: "fraction-fixed", children: fixedValue });
|
|
13110
13127
|
}
|
|
13111
13128
|
const isDroppedHere = droppedInputs.has(subKey);
|
|
13129
|
+
const slotClass = slotStatus ? ` widget--${slotStatus}` : statusClass;
|
|
13112
13130
|
return /* @__PURE__ */ jsx(
|
|
13113
13131
|
Droppable,
|
|
13114
13132
|
{
|
|
@@ -13119,7 +13137,7 @@ const FractionInput = ({
|
|
|
13119
13137
|
children: isDroppedHere && currentValue !== "" ? /* @__PURE__ */ jsx(
|
|
13120
13138
|
"button",
|
|
13121
13139
|
{
|
|
13122
|
-
className: `inline-input-chip fraction-chip${
|
|
13140
|
+
className: `inline-input-chip fraction-chip${slotClass}`,
|
|
13123
13141
|
onClick: () => onChange(subKey, "", false),
|
|
13124
13142
|
title: "Click to remove",
|
|
13125
13143
|
children: currentValue
|
|
@@ -13129,21 +13147,23 @@ const FractionInput = ({
|
|
|
13129
13147
|
{
|
|
13130
13148
|
id: `${subKey}-input`,
|
|
13131
13149
|
type: "text",
|
|
13132
|
-
className: `inline-input fraction-input${
|
|
13150
|
+
className: `inline-input fraction-input${slotClass}`,
|
|
13133
13151
|
value: currentValue,
|
|
13134
13152
|
onChange: (e) => onChange(subKey, e.target.value, false),
|
|
13135
13153
|
onFocus: () => onFocus?.(subKey),
|
|
13136
|
-
maxLength: 4,
|
|
13137
|
-
|
|
13154
|
+
maxLength: placeholder ? Math.max(20, placeholder.length) : 4,
|
|
13155
|
+
size: placeholder ? placeholder.length : void 0,
|
|
13156
|
+
"aria-label": label,
|
|
13157
|
+
placeholder
|
|
13138
13158
|
}
|
|
13139
13159
|
)
|
|
13140
13160
|
}
|
|
13141
13161
|
);
|
|
13142
13162
|
};
|
|
13143
13163
|
return /* @__PURE__ */ jsxs("span", { className: "fraction", role: "math", "aria-label": `fraction ${widgetId}`, children: [
|
|
13144
|
-
/* @__PURE__ */ jsx("span", { className: "fraction-numerator", children: renderSlot(numKey, numerator, numValue, "numerator") }),
|
|
13164
|
+
/* @__PURE__ */ jsx("span", { className: "fraction-numerator", children: renderSlot(numKey, numerator, numValue, "numerator", numValidationStatus) }),
|
|
13145
13165
|
/* @__PURE__ */ jsx("span", { className: "fraction-bar", "aria-hidden": "true" }),
|
|
13146
|
-
/* @__PURE__ */ jsx("span", { className: "fraction-denominator", children: renderSlot(denKey, denominator, denValue, "denominator") })
|
|
13166
|
+
/* @__PURE__ */ jsx("span", { className: "fraction-denominator", children: renderSlot(denKey, denominator, denValue, "denominator", denValidationStatus) })
|
|
13147
13167
|
] });
|
|
13148
13168
|
};
|
|
13149
13169
|
function isLightColor(hex) {
|
|
@@ -13415,7 +13435,9 @@ const GridShape = ({
|
|
|
13415
13435
|
className: "visual-fraction-widget__parts visual-fraction-widget__parts--horizontal",
|
|
13416
13436
|
style: {
|
|
13417
13437
|
"--visual-fraction-divisions": divisions,
|
|
13418
|
-
"--visual-fraction-grid-cols": getGridColumnCount(divisions)
|
|
13438
|
+
"--visual-fraction-grid-cols": getGridColumnCount(divisions),
|
|
13439
|
+
// Safe integer division: zod schema enforces divisions = perfect square.
|
|
13440
|
+
"--visual-fraction-grid-rows": divisions / getGridColumnCount(divisions)
|
|
13419
13441
|
},
|
|
13420
13442
|
children: parts.map((part) => /* @__PURE__ */ jsx(
|
|
13421
13443
|
"div",
|
|
@@ -13565,7 +13587,7 @@ const VisualFraction = ({
|
|
|
13565
13587
|
[divisions, filledCount, filledPartGroups, partAssignments, answer, filledPalette, answerPalette]
|
|
13566
13588
|
);
|
|
13567
13589
|
const statusClass = validationStatus ? ` visual-fraction-widget--${validationStatus} widget--${validationStatus}` : "";
|
|
13568
|
-
const rootStyle = useMemo(() => getSizeStyle(widget.size
|
|
13590
|
+
const rootStyle = useMemo(() => getSizeStyle(widget.size), [widget.size, shape]);
|
|
13569
13591
|
const ShapeComponent = SHAPE_COMPONENTS[shape];
|
|
13570
13592
|
return /* @__PURE__ */ jsxs(
|
|
13571
13593
|
"div",
|
|
@@ -13590,15 +13612,10 @@ const VisualFraction = ({
|
|
|
13590
13612
|
);
|
|
13591
13613
|
};
|
|
13592
13614
|
VisualFraction.displayName = "VisualFraction";
|
|
13593
|
-
function getSizeStyle(size,
|
|
13615
|
+
function getSizeStyle(size, _shape) {
|
|
13594
13616
|
if (size === void 0) return void 0;
|
|
13595
|
-
if (shape === "circle" || shape === "triangle") {
|
|
13596
|
-
return {
|
|
13597
|
-
"--visual-fraction-size": `${size * VISUAL_FRACTION_SVG_SIZE_SCALE}rem`
|
|
13598
|
-
};
|
|
13599
|
-
}
|
|
13600
13617
|
return {
|
|
13601
|
-
"--visual-fraction-
|
|
13618
|
+
"--visual-fraction-size": `${size * VISUAL_FRACTION_SVG_SIZE_SCALE}rem`
|
|
13602
13619
|
};
|
|
13603
13620
|
}
|
|
13604
13621
|
const RadioOptions = ({
|
|
@@ -13800,6 +13817,8 @@ const WidgetRenderer = ({
|
|
|
13800
13817
|
values = {},
|
|
13801
13818
|
isDropped = false,
|
|
13802
13819
|
validationStatus = null,
|
|
13820
|
+
numValidationStatus = null,
|
|
13821
|
+
denValidationStatus = null,
|
|
13803
13822
|
droppedInputs = /* @__PURE__ */ new Set(),
|
|
13804
13823
|
widgets,
|
|
13805
13824
|
onChange,
|
|
@@ -13878,8 +13897,11 @@ const WidgetRenderer = ({
|
|
|
13878
13897
|
values,
|
|
13879
13898
|
droppedInputs,
|
|
13880
13899
|
validationStatus,
|
|
13900
|
+
numValidationStatus,
|
|
13901
|
+
denValidationStatus,
|
|
13881
13902
|
onChange,
|
|
13882
|
-
onFocus: onInputFocus
|
|
13903
|
+
onFocus: onInputFocus,
|
|
13904
|
+
placeholder: widget.placeholder
|
|
13883
13905
|
}
|
|
13884
13906
|
);
|
|
13885
13907
|
}
|
|
@@ -13929,7 +13951,7 @@ const getMajorTicks = (min, max, step) => {
|
|
|
13929
13951
|
const count = Math.floor((max - min) / step);
|
|
13930
13952
|
const ticks = Array.from({ length: count + 1 }, (_, i) => cleanFloat(min + i * step));
|
|
13931
13953
|
const lastTick = ticks[ticks.length - 1];
|
|
13932
|
-
if (
|
|
13954
|
+
if (roundTick(lastTick) !== roundTick(max)) {
|
|
13933
13955
|
ticks.push(max);
|
|
13934
13956
|
} else {
|
|
13935
13957
|
ticks[ticks.length - 1] = max;
|
|
@@ -14540,7 +14562,7 @@ const NumberLineRenderer = ({
|
|
|
14540
14562
|
return step;
|
|
14541
14563
|
}, [counter, counterCount, min, max, step]);
|
|
14542
14564
|
const majorTicks = useMemo(
|
|
14543
|
-
() => getMajorTicks(min, max, effectiveStep).map(roundTick),
|
|
14565
|
+
() => [...new Set(getMajorTicks(min, max, effectiveStep).map(roundTick))],
|
|
14544
14566
|
[min, max, effectiveStep]
|
|
14545
14567
|
);
|
|
14546
14568
|
const minorValues = useMemo(
|
|
@@ -14549,16 +14571,17 @@ const NumberLineRenderer = ({
|
|
|
14549
14571
|
);
|
|
14550
14572
|
const showArrowRight = lineStyle === "arrow-right" || lineStyle === "arrow-both";
|
|
14551
14573
|
const showArrowLeft = lineStyle === "arrow-left" || lineStyle === "arrow-both";
|
|
14552
|
-
const
|
|
14574
|
+
const hasDragOptions = Boolean(widgets[DRAG_OPTIONS_WIDGET_ID]);
|
|
14575
|
+
const isAxisDragMode = hasDragOptions && item.dragMode === "axis";
|
|
14553
14576
|
const inputTickSet = useMemo(() => {
|
|
14554
|
-
if (
|
|
14577
|
+
if (isAxisDragMode) return /* @__PURE__ */ new Set();
|
|
14555
14578
|
return new Set(
|
|
14556
14579
|
positions.filter((pos) => getPositionWidgetId(pos.content) !== null).map((pos) => roundTick(pos.value))
|
|
14557
14580
|
);
|
|
14558
|
-
}, [
|
|
14581
|
+
}, [isAxisDragMode, positions]);
|
|
14559
14582
|
const visiblePositions = useMemo(
|
|
14560
|
-
() => positions.filter((pos) => !
|
|
14561
|
-
[
|
|
14583
|
+
() => positions.filter((pos) => !isAxisDragMode || getPositionWidgetId(pos.content) === null),
|
|
14584
|
+
[isAxisDragMode, positions]
|
|
14562
14585
|
);
|
|
14563
14586
|
const visiblePositionIds = useMemo(
|
|
14564
14587
|
() => visiblePositions.map((pos) => pos.id),
|
|
@@ -14568,7 +14591,7 @@ const NumberLineRenderer = ({
|
|
|
14568
14591
|
return /* @__PURE__ */ jsxs(
|
|
14569
14592
|
"div",
|
|
14570
14593
|
{
|
|
14571
|
-
className: `number-line${
|
|
14594
|
+
className: `number-line${isAxisDragMode ? " number-line--drag-mode" : ""}${lineStyle === "line" ? " number-line--style-line" : ""}`,
|
|
14572
14595
|
style: {
|
|
14573
14596
|
[CSS_VAR_SIDE_PAD]: `${SIDE_PAD}%`,
|
|
14574
14597
|
...positionContentHeight && { "--nl-position-content-height": positionContentHeight }
|
|
@@ -14598,7 +14621,7 @@ const NumberLineRenderer = ({
|
|
|
14598
14621
|
},
|
|
14599
14622
|
pos.id
|
|
14600
14623
|
)) }),
|
|
14601
|
-
|
|
14624
|
+
isAxisDragMode ? /* @__PURE__ */ jsx(
|
|
14602
14625
|
FreeDragAxis,
|
|
14603
14626
|
{
|
|
14604
14627
|
axisDropId: `${item.id}--nl-axis`,
|
|
@@ -14709,6 +14732,7 @@ function groupLineItems(items) {
|
|
|
14709
14732
|
}
|
|
14710
14733
|
return groups;
|
|
14711
14734
|
}
|
|
14735
|
+
const toValidationStatus = (v) => v === true ? "correct" : v === false ? "incorrect" : null;
|
|
14712
14736
|
const LayoutRenderer = ({
|
|
14713
14737
|
item,
|
|
14714
14738
|
widgets,
|
|
@@ -14724,8 +14748,10 @@ const LayoutRenderer = ({
|
|
|
14724
14748
|
const hasArabic = isArabic(item.value);
|
|
14725
14749
|
return /* @__PURE__ */ jsx("span", { className: `question-text ${hasArabic ? "question-text-arabic" : ""}`, children: item.value });
|
|
14726
14750
|
}
|
|
14727
|
-
case JSON_TYPES.TEXT:
|
|
14728
|
-
|
|
14751
|
+
case JSON_TYPES.TEXT: {
|
|
14752
|
+
const isNum = /^[\d.,\s]+$/.test(item.value);
|
|
14753
|
+
return /* @__PURE__ */ jsx("span", { className: `text-item ${isNum ? "text-item-number" : ""} ${isArabic(item.value) ? "text-item-arabic" : "text-item-not-arabic"}`, children: item.value });
|
|
14754
|
+
}
|
|
14729
14755
|
case JSON_TYPES.HIGHLIGHTED_TEXT: {
|
|
14730
14756
|
const hasArabic = isArabic(item.value);
|
|
14731
14757
|
const dirAttr = !hasArabic ? "ltr" : void 0;
|
|
@@ -14792,6 +14818,8 @@ const LayoutRenderer = ({
|
|
|
14792
14818
|
values,
|
|
14793
14819
|
isDropped: droppedInputs.has(item.widgetId),
|
|
14794
14820
|
validationStatus,
|
|
14821
|
+
numValidationStatus: toValidationStatus(validationDetails?.[`${item.widgetId}__num`]),
|
|
14822
|
+
denValidationStatus: toValidationStatus(validationDetails?.[`${item.widgetId}__den`]),
|
|
14795
14823
|
droppedInputs,
|
|
14796
14824
|
widgets,
|
|
14797
14825
|
onChange,
|
|
@@ -14897,6 +14925,27 @@ const ExerciseRenderer = forwardRef(({
|
|
|
14897
14925
|
for (const [id, v] of Object.entries(result.details)) {
|
|
14898
14926
|
details[id] = v.isCorrect;
|
|
14899
14927
|
}
|
|
14928
|
+
for (const [widgetId, widget] of Object.entries(json.widgets)) {
|
|
14929
|
+
if (widget.type !== JSON_TYPES.FRACTION) continue;
|
|
14930
|
+
if (!(widgetId in details)) continue;
|
|
14931
|
+
const answer = json.validation?.answers?.[widgetId];
|
|
14932
|
+
if (!answer) continue;
|
|
14933
|
+
const [expectedNum, expectedDen] = answer.split("/", 2);
|
|
14934
|
+
if (!expectedNum || !expectedDen) continue;
|
|
14935
|
+
if (details[widgetId]) {
|
|
14936
|
+
if (widget.numerator === null) details[`${widgetId}__num`] = true;
|
|
14937
|
+
if (widget.denominator === null) details[`${widgetId}__den`] = true;
|
|
14938
|
+
} else {
|
|
14939
|
+
if (widget.numerator === null) {
|
|
14940
|
+
const u = values[`${widgetId}__num`];
|
|
14941
|
+
details[`${widgetId}__num`] = typeof u === "string" && u !== "" && normalize(u) === normalize(expectedNum);
|
|
14942
|
+
}
|
|
14943
|
+
if (widget.denominator === null) {
|
|
14944
|
+
const u = values[`${widgetId}__den`];
|
|
14945
|
+
details[`${widgetId}__den`] = typeof u === "string" && u !== "" && normalize(u) === normalize(expectedDen);
|
|
14946
|
+
}
|
|
14947
|
+
}
|
|
14948
|
+
}
|
|
14900
14949
|
setValidationDetails(details);
|
|
14901
14950
|
onSubmit?.(values);
|
|
14902
14951
|
return result;
|