@mathscan/math-exercise-engine 1.0.1 → 1.0.3
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/README.md +56 -41
- package/dist/index.d.ts +228 -159
- package/dist/index.js +413 -222
- package/dist/index.js.map +1 -1
- package/dist/index.mjs +413 -222
- package/dist/index.mjs.map +1 -1
- package/dist/style.css +241 -60
- package/package.json +9 -4
package/dist/index.js
CHANGED
|
@@ -6,6 +6,87 @@ const mathjs = require("mathjs");
|
|
|
6
6
|
const jsxRuntime = require("react/jsx-runtime");
|
|
7
7
|
const React = require("react");
|
|
8
8
|
const require$$0 = require("react-dom");
|
|
9
|
+
const AST_TYPES = {
|
|
10
|
+
// ═══════════════════════════════════════════════════════════════════════════
|
|
11
|
+
// Inline Elements
|
|
12
|
+
// ═══════════════════════════════════════════════════════════════════════════
|
|
13
|
+
/** Regular text without special formatting */
|
|
14
|
+
FREE_TEXT: "FreeText",
|
|
15
|
+
/** Explicit spacing element */
|
|
16
|
+
SPACE: "Space",
|
|
17
|
+
/** Text with optional character-range highlighting */
|
|
18
|
+
HIGHLIGHTED_TEXT: "HighlightedText",
|
|
19
|
+
/** Inline input widget (string or numeric) */
|
|
20
|
+
INLINE_INPUT: "InlineInput",
|
|
21
|
+
// ═══════════════════════════════════════════════════════════════════════════
|
|
22
|
+
// Blocks
|
|
23
|
+
// ═══════════════════════════════════════════════════════════════════════════
|
|
24
|
+
/** Question/instruction text block */
|
|
25
|
+
TEXT_BLOCK: "TextBlock",
|
|
26
|
+
/** Line containing inline elements */
|
|
27
|
+
LINE_BLOCK: "LineBlock",
|
|
28
|
+
// ═══════════════════════════════════════════════════════════════════════════
|
|
29
|
+
// Tools
|
|
30
|
+
// ═══════════════════════════════════════════════════════════════════════════
|
|
31
|
+
/** Drag-and-drop options tool */
|
|
32
|
+
DRAG_OPTIONS: "DragOptions",
|
|
33
|
+
/** Numeric keypad input tool */
|
|
34
|
+
NUMERIC_KEYPAD: "NumericKeypad",
|
|
35
|
+
// ═══════════════════════════════════════════════════════════════════════════
|
|
36
|
+
// Validation
|
|
37
|
+
// ═══════════════════════════════════════════════════════════════════════════
|
|
38
|
+
/** Simple answer matching validation */
|
|
39
|
+
SIMPLE_VALIDATION: "SimpleValidation",
|
|
40
|
+
/** Expression-based validation */
|
|
41
|
+
EXPRESSION_VALIDATION: "ExpressionValidation",
|
|
42
|
+
// ═══════════════════════════════════════════════════════════════════════════
|
|
43
|
+
// Document
|
|
44
|
+
// ═══════════════════════════════════════════════════════════════════════════
|
|
45
|
+
/** Root exercise document */
|
|
46
|
+
EXERCISE_DOCUMENT: "ExerciseDocument"
|
|
47
|
+
};
|
|
48
|
+
const JSON_TYPES = {
|
|
49
|
+
// ═══════════════════════════════════════════════════════════════════════════
|
|
50
|
+
// Layout Items
|
|
51
|
+
// ═══════════════════════════════════════════════════════════════════════════
|
|
52
|
+
/** Question/instruction text */
|
|
53
|
+
QUESTION_TEXT: "question-text",
|
|
54
|
+
/** Regular text element */
|
|
55
|
+
TEXT: "text",
|
|
56
|
+
/** Spacing element */
|
|
57
|
+
SPACE: "space",
|
|
58
|
+
/** Text with optional highlighting */
|
|
59
|
+
HIGHLIGHTED_TEXT: "highlighted-text",
|
|
60
|
+
/** Reference to a widget */
|
|
61
|
+
WIDGET_REF: "widget-ref",
|
|
62
|
+
/** Line break element */
|
|
63
|
+
LINEBREAK: "linebreak",
|
|
64
|
+
/** Grouped layout items */
|
|
65
|
+
GROUP: "group",
|
|
66
|
+
/** Operator symbol */
|
|
67
|
+
OPERATOR: "operator",
|
|
68
|
+
// ═══════════════════════════════════════════════════════════════════════════
|
|
69
|
+
// Widget Types
|
|
70
|
+
// ═══════════════════════════════════════════════════════════════════════════
|
|
71
|
+
/** Inline input widget (string or numeric) */
|
|
72
|
+
INLINE_INPUT: "inline-input",
|
|
73
|
+
/** Drag-and-drop options widget */
|
|
74
|
+
DRAG_OPTIONS: "drag-options",
|
|
75
|
+
/** Numeric keypad widget */
|
|
76
|
+
NUMERIC_KEYPAD: "numeric-keypad"
|
|
77
|
+
};
|
|
78
|
+
const VALIDATION_MODES = {
|
|
79
|
+
/** Simple answer matching validation */
|
|
80
|
+
SIMPLE: "simple",
|
|
81
|
+
/** Expression-based validation using JavaScript expressions */
|
|
82
|
+
EXPRESSION: "expression"
|
|
83
|
+
};
|
|
84
|
+
const INPUT_TYPES = {
|
|
85
|
+
/** String/text input */
|
|
86
|
+
STRING: "string",
|
|
87
|
+
/** Numeric input (digits only) */
|
|
88
|
+
NUMERIC: "numeric"
|
|
89
|
+
};
|
|
9
90
|
const Newline = chevrotain.createToken({
|
|
10
91
|
name: "Newline",
|
|
11
92
|
pattern: /\r?\n/,
|
|
@@ -31,14 +112,18 @@ const QUESTION_TEXT = chevrotain.createToken({
|
|
|
31
112
|
name: "QUESTION_TEXT",
|
|
32
113
|
pattern: /QUESTION_TEXT/
|
|
33
114
|
});
|
|
34
|
-
const
|
|
35
|
-
name: "
|
|
36
|
-
pattern: /
|
|
115
|
+
const TEXT_HIGHLIGHTER = chevrotain.createToken({
|
|
116
|
+
name: "TEXT_HIGHLIGHTER",
|
|
117
|
+
pattern: /TEXT_HIGHLIGHTER/
|
|
37
118
|
});
|
|
38
119
|
const W_S_I = chevrotain.createToken({
|
|
39
120
|
name: "W_S_I",
|
|
40
121
|
pattern: /W_S_I/
|
|
41
122
|
});
|
|
123
|
+
const STRING_INPUT = chevrotain.createToken({
|
|
124
|
+
name: "STRING_INPUT",
|
|
125
|
+
pattern: /STRING_INPUT/
|
|
126
|
+
});
|
|
42
127
|
const DRAGABLE_BUTTONS_OPTIONS = chevrotain.createToken({
|
|
43
128
|
name: "DRAGABLE_BUTTONS_OPTIONS",
|
|
44
129
|
pattern: /DRAGABLE_BUTTONS_OPTIONS/
|
|
@@ -55,6 +140,10 @@ const W_N_I = chevrotain.createToken({
|
|
|
55
140
|
name: "W_N_I",
|
|
56
141
|
pattern: /W_N_I/
|
|
57
142
|
});
|
|
143
|
+
const NUMERIC_INPUT = chevrotain.createToken({
|
|
144
|
+
name: "NUMERIC_INPUT",
|
|
145
|
+
pattern: /NUMERIC_INPUT/
|
|
146
|
+
});
|
|
58
147
|
const NumberLiteral = chevrotain.createToken({
|
|
59
148
|
name: "NumberLiteral",
|
|
60
149
|
pattern: /-?\d+(\.\d+)?/
|
|
@@ -124,7 +213,7 @@ const Comma = chevrotain.createToken({
|
|
|
124
213
|
});
|
|
125
214
|
const FreeText = chevrotain.createToken({
|
|
126
215
|
name: "FreeText",
|
|
127
|
-
pattern: /(?:[^A-Z\n\r]|(?![A-Z_]+\[)[A-Z])+/,
|
|
216
|
+
pattern: /(?:[^A-Z\n\r \t+\-−×*÷/=<>?()\[\],]|(?![A-Z_]+\[)[A-Z])+/,
|
|
128
217
|
line_breaks: false
|
|
129
218
|
});
|
|
130
219
|
const allTokens = [
|
|
@@ -137,13 +226,14 @@ const allTokens = [
|
|
|
137
226
|
Comment,
|
|
138
227
|
// Component keywords (before Identifier!)
|
|
139
228
|
QUESTION_TEXT,
|
|
140
|
-
|
|
229
|
+
TEXT_HIGHLIGHTER,
|
|
141
230
|
W_S_I,
|
|
231
|
+
STRING_INPUT,
|
|
142
232
|
DRAGABLE_BUTTONS_OPTIONS,
|
|
143
233
|
NUMERIC_KEYPAD,
|
|
144
234
|
WIDGET_ANSWER,
|
|
145
|
-
// Legacy keywords
|
|
146
235
|
W_N_I,
|
|
236
|
+
NUMERIC_INPUT,
|
|
147
237
|
// Literals
|
|
148
238
|
NumberLiteral,
|
|
149
239
|
StringLiteral,
|
|
@@ -321,14 +411,14 @@ class MathExerciseParser extends chevrotain.CstParser {
|
|
|
321
411
|
// Parentheses (for grouping)
|
|
322
412
|
{ ALT: () => this.CONSUME(LParen) },
|
|
323
413
|
{ ALT: () => this.CONSUME(RParen) },
|
|
324
|
-
//
|
|
325
|
-
{ ALT: () => this.SUBRULE(this.
|
|
414
|
+
// TEXT_HIGHLIGHTER (for highlighting)
|
|
415
|
+
{ ALT: () => this.SUBRULE(this.textHighlighter) },
|
|
326
416
|
// W_S_I (inline input widget)
|
|
327
417
|
{ ALT: () => this.SUBRULE(this.inlineInput) }
|
|
328
418
|
]);
|
|
329
419
|
});
|
|
330
|
-
this.
|
|
331
|
-
this.CONSUME(
|
|
420
|
+
this.textHighlighter = this.RULE("textHighlighter", () => {
|
|
421
|
+
this.CONSUME(TEXT_HIGHLIGHTER);
|
|
332
422
|
this.CONSUME(LBracket);
|
|
333
423
|
this.SUBRULE(this.parameterList);
|
|
334
424
|
this.CONSUME(RBracket);
|
|
@@ -336,7 +426,9 @@ class MathExerciseParser extends chevrotain.CstParser {
|
|
|
336
426
|
this.inlineInput = this.RULE("inlineInput", () => {
|
|
337
427
|
this.OR([
|
|
338
428
|
{ ALT: () => this.CONSUME(W_S_I, { LABEL: "stringInput" }) },
|
|
339
|
-
{ ALT: () => this.CONSUME(
|
|
429
|
+
{ ALT: () => this.CONSUME(STRING_INPUT, { LABEL: "stringInput" }) },
|
|
430
|
+
{ ALT: () => this.CONSUME(W_N_I, { LABEL: "numericInput" }) },
|
|
431
|
+
{ ALT: () => this.CONSUME(NUMERIC_INPUT, { LABEL: "numericInput" }) }
|
|
340
432
|
]);
|
|
341
433
|
this.CONSUME(LBracket);
|
|
342
434
|
this.SUBRULE(this.parameterList);
|
|
@@ -363,7 +455,9 @@ class MathExerciseParser extends chevrotain.CstParser {
|
|
|
363
455
|
this.numericKeypad = this.RULE("numericKeypad", () => {
|
|
364
456
|
this.CONSUME(NUMERIC_KEYPAD);
|
|
365
457
|
this.CONSUME(LBracket);
|
|
366
|
-
this.
|
|
458
|
+
this.OPTION(() => {
|
|
459
|
+
this.SUBRULE(this.parameterList);
|
|
460
|
+
});
|
|
367
461
|
this.CONSUME(RBracket);
|
|
368
462
|
this.MANY(() => {
|
|
369
463
|
this.OR([
|
|
@@ -460,29 +554,29 @@ class MathExerciseParser extends chevrotain.CstParser {
|
|
|
460
554
|
}
|
|
461
555
|
const parser = new MathExerciseParser();
|
|
462
556
|
const FreeTextInlineSchema = zod.z.object({
|
|
463
|
-
type: zod.z.literal(
|
|
557
|
+
type: zod.z.literal(AST_TYPES.FREE_TEXT),
|
|
464
558
|
value: zod.z.string()
|
|
465
559
|
});
|
|
466
560
|
const SpaceInlineSchema = zod.z.object({
|
|
467
|
-
type: zod.z.literal(
|
|
561
|
+
type: zod.z.literal(AST_TYPES.SPACE)
|
|
468
562
|
});
|
|
469
|
-
const
|
|
470
|
-
type: zod.z.literal(
|
|
563
|
+
const HighlightedTextInlineSchema = zod.z.object({
|
|
564
|
+
type: zod.z.literal(AST_TYPES.HIGHLIGHTED_TEXT),
|
|
471
565
|
value: zod.z.string(),
|
|
472
566
|
highlight: zod.z.tuple([zod.z.number(), zod.z.number()]).optional()
|
|
473
567
|
});
|
|
474
568
|
const InlineInputWidgetSchema = zod.z.discriminatedUnion("inputType", [
|
|
475
569
|
zod.z.object({
|
|
476
|
-
type: zod.z.literal(
|
|
570
|
+
type: zod.z.literal(AST_TYPES.INLINE_INPUT),
|
|
477
571
|
name: zod.z.string(),
|
|
478
|
-
inputType: zod.z.literal(
|
|
572
|
+
inputType: zod.z.literal(INPUT_TYPES.STRING),
|
|
479
573
|
length: zod.z.number().int().positive(),
|
|
480
574
|
answer: zod.z.union([zod.z.string(), zod.z.number()]).optional()
|
|
481
575
|
}),
|
|
482
576
|
zod.z.object({
|
|
483
|
-
type: zod.z.literal(
|
|
577
|
+
type: zod.z.literal(AST_TYPES.INLINE_INPUT),
|
|
484
578
|
name: zod.z.string(),
|
|
485
|
-
inputType: zod.z.literal(
|
|
579
|
+
inputType: zod.z.literal(INPUT_TYPES.NUMERIC),
|
|
486
580
|
digits: zod.z.number().int().positive(),
|
|
487
581
|
answer: zod.z.union([zod.z.string(), zod.z.number()]).optional()
|
|
488
582
|
})
|
|
@@ -490,52 +584,45 @@ const InlineInputWidgetSchema = zod.z.discriminatedUnion("inputType", [
|
|
|
490
584
|
const InlineNodeSchema = zod.z.union([
|
|
491
585
|
FreeTextInlineSchema,
|
|
492
586
|
SpaceInlineSchema,
|
|
493
|
-
|
|
587
|
+
HighlightedTextInlineSchema,
|
|
494
588
|
InlineInputWidgetSchema
|
|
495
589
|
]);
|
|
496
590
|
function createFreeText(value) {
|
|
497
591
|
return FreeTextInlineSchema.parse({
|
|
498
|
-
type:
|
|
592
|
+
type: AST_TYPES.FREE_TEXT,
|
|
499
593
|
value
|
|
500
594
|
});
|
|
501
595
|
}
|
|
502
596
|
function createSpace() {
|
|
503
597
|
return SpaceInlineSchema.parse({
|
|
504
|
-
type:
|
|
598
|
+
type: AST_TYPES.SPACE
|
|
505
599
|
});
|
|
506
600
|
}
|
|
507
|
-
function
|
|
508
|
-
return
|
|
509
|
-
type:
|
|
601
|
+
function createHighlightedText(value, highlight) {
|
|
602
|
+
return HighlightedTextInlineSchema.parse({
|
|
603
|
+
type: AST_TYPES.HIGHLIGHTED_TEXT,
|
|
510
604
|
value,
|
|
511
605
|
highlight
|
|
512
606
|
});
|
|
513
607
|
}
|
|
514
608
|
function createStringInput(name, length, answer) {
|
|
515
609
|
return InlineInputWidgetSchema.parse({
|
|
516
|
-
type:
|
|
610
|
+
type: AST_TYPES.INLINE_INPUT,
|
|
517
611
|
name,
|
|
518
|
-
inputType:
|
|
612
|
+
inputType: INPUT_TYPES.STRING,
|
|
519
613
|
length,
|
|
520
614
|
answer
|
|
521
615
|
});
|
|
522
616
|
}
|
|
523
617
|
function createNumericInput(name, digits, answer) {
|
|
524
618
|
return InlineInputWidgetSchema.parse({
|
|
525
|
-
type:
|
|
619
|
+
type: AST_TYPES.INLINE_INPUT,
|
|
526
620
|
name,
|
|
527
|
-
inputType:
|
|
621
|
+
inputType: INPUT_TYPES.NUMERIC,
|
|
528
622
|
digits,
|
|
529
623
|
answer
|
|
530
624
|
});
|
|
531
625
|
}
|
|
532
|
-
function createInlineInput(name, inputType, lengthOrDigits, answer) {
|
|
533
|
-
if (inputType === "string") {
|
|
534
|
-
return createStringInput(name, lengthOrDigits, answer);
|
|
535
|
-
} else {
|
|
536
|
-
return createNumericInput(name, lengthOrDigits, answer);
|
|
537
|
-
}
|
|
538
|
-
}
|
|
539
626
|
function isFreeText(value) {
|
|
540
627
|
return FreeTextInlineSchema.safeParse(value).success;
|
|
541
628
|
}
|
|
@@ -549,22 +636,22 @@ function isInlineNode(value) {
|
|
|
549
636
|
return InlineNodeSchema.safeParse(value).success;
|
|
550
637
|
}
|
|
551
638
|
const TextBlockSchema = zod.z.object({
|
|
552
|
-
type: zod.z.literal(
|
|
639
|
+
type: zod.z.literal(AST_TYPES.TEXT_BLOCK),
|
|
553
640
|
value: zod.z.string()
|
|
554
641
|
});
|
|
555
642
|
const LineBlockSchema = zod.z.object({
|
|
556
|
-
type: zod.z.literal(
|
|
643
|
+
type: zod.z.literal(AST_TYPES.LINE_BLOCK),
|
|
557
644
|
inlines: zod.z.array(InlineNodeSchema)
|
|
558
645
|
});
|
|
559
646
|
function createTextBlock(value) {
|
|
560
647
|
return TextBlockSchema.parse({
|
|
561
|
-
type:
|
|
648
|
+
type: AST_TYPES.TEXT_BLOCK,
|
|
562
649
|
value
|
|
563
650
|
});
|
|
564
651
|
}
|
|
565
652
|
function createLineBlock(inlines) {
|
|
566
653
|
return LineBlockSchema.parse({
|
|
567
|
-
type:
|
|
654
|
+
type: AST_TYPES.LINE_BLOCK,
|
|
568
655
|
inlines
|
|
569
656
|
});
|
|
570
657
|
}
|
|
@@ -575,13 +662,13 @@ function isLineBlock(value) {
|
|
|
575
662
|
return LineBlockSchema.safeParse(value).success;
|
|
576
663
|
}
|
|
577
664
|
const DragOptionsToolSchema = zod.z.object({
|
|
578
|
-
type: zod.z.literal(
|
|
665
|
+
type: zod.z.literal(AST_TYPES.DRAG_OPTIONS),
|
|
579
666
|
options: zod.z.array(zod.z.string()).min(1)
|
|
580
667
|
});
|
|
581
668
|
const NumericKeypadToolSchema = zod.z.object({
|
|
582
|
-
type: zod.z.literal(
|
|
583
|
-
|
|
584
|
-
|
|
669
|
+
type: zod.z.literal(AST_TYPES.NUMERIC_KEYPAD),
|
|
670
|
+
includeOperators: zod.z.boolean().optional(),
|
|
671
|
+
includeDecimal: zod.z.boolean().optional()
|
|
585
672
|
});
|
|
586
673
|
const ToolNodeSchema = zod.z.discriminatedUnion("type", [
|
|
587
674
|
DragOptionsToolSchema,
|
|
@@ -589,15 +676,15 @@ const ToolNodeSchema = zod.z.discriminatedUnion("type", [
|
|
|
589
676
|
]);
|
|
590
677
|
function createDragOptions(options) {
|
|
591
678
|
return DragOptionsToolSchema.parse({
|
|
592
|
-
type:
|
|
679
|
+
type: AST_TYPES.DRAG_OPTIONS,
|
|
593
680
|
options
|
|
594
681
|
});
|
|
595
682
|
}
|
|
596
|
-
function createNumericKeypad(
|
|
683
|
+
function createNumericKeypad(includeOperators, includeDecimal) {
|
|
597
684
|
return NumericKeypadToolSchema.parse({
|
|
598
|
-
type:
|
|
599
|
-
|
|
600
|
-
|
|
685
|
+
type: AST_TYPES.NUMERIC_KEYPAD,
|
|
686
|
+
includeOperators,
|
|
687
|
+
includeDecimal
|
|
601
688
|
});
|
|
602
689
|
}
|
|
603
690
|
function isDragOptions(value) {
|
|
@@ -610,10 +697,10 @@ function isToolNode(value) {
|
|
|
610
697
|
return ToolNodeSchema.safeParse(value).success;
|
|
611
698
|
}
|
|
612
699
|
const SimpleValidationSchema = zod.z.object({
|
|
613
|
-
type: zod.z.literal(
|
|
700
|
+
type: zod.z.literal(AST_TYPES.SIMPLE_VALIDATION)
|
|
614
701
|
});
|
|
615
702
|
const ExpressionValidationSchema = zod.z.object({
|
|
616
|
-
type: zod.z.literal(
|
|
703
|
+
type: zod.z.literal(AST_TYPES.EXPRESSION_VALIDATION),
|
|
617
704
|
expression: zod.z.string()
|
|
618
705
|
});
|
|
619
706
|
const ValidationNodeSchema = zod.z.discriminatedUnion("type", [
|
|
@@ -622,12 +709,12 @@ const ValidationNodeSchema = zod.z.discriminatedUnion("type", [
|
|
|
622
709
|
]);
|
|
623
710
|
function createSimpleValidation() {
|
|
624
711
|
return SimpleValidationSchema.parse({
|
|
625
|
-
type:
|
|
712
|
+
type: AST_TYPES.SIMPLE_VALIDATION
|
|
626
713
|
});
|
|
627
714
|
}
|
|
628
715
|
function createExpressionValidation(expression) {
|
|
629
716
|
return ExpressionValidationSchema.parse({
|
|
630
|
-
type:
|
|
717
|
+
type: AST_TYPES.EXPRESSION_VALIDATION,
|
|
631
718
|
expression
|
|
632
719
|
});
|
|
633
720
|
}
|
|
@@ -641,7 +728,7 @@ function isValidationNode(value) {
|
|
|
641
728
|
return ValidationNodeSchema.safeParse(value).success;
|
|
642
729
|
}
|
|
643
730
|
const ExerciseDocumentSchema = zod.z.object({
|
|
644
|
-
type: zod.z.literal(
|
|
731
|
+
type: zod.z.literal(AST_TYPES.EXERCISE_DOCUMENT),
|
|
645
732
|
question: TextBlockSchema.optional(),
|
|
646
733
|
lines: zod.z.array(LineBlockSchema),
|
|
647
734
|
tools: zod.z.array(ToolNodeSchema).optional(),
|
|
@@ -649,7 +736,7 @@ const ExerciseDocumentSchema = zod.z.object({
|
|
|
649
736
|
});
|
|
650
737
|
function createExerciseDocument(question, lines, validation, tools) {
|
|
651
738
|
return ExerciseDocumentSchema.parse({
|
|
652
|
-
type:
|
|
739
|
+
type: AST_TYPES.EXERCISE_DOCUMENT,
|
|
653
740
|
question,
|
|
654
741
|
lines,
|
|
655
742
|
tools,
|
|
@@ -754,19 +841,22 @@ class NaturalDSLVisitor extends BaseCstVisitor {
|
|
|
754
841
|
const token = ctx.RParen[0];
|
|
755
842
|
return createFreeText(token.image);
|
|
756
843
|
}
|
|
757
|
-
if (ctx.
|
|
758
|
-
return this.visit(ctx.
|
|
844
|
+
if (ctx.textHighlighter) {
|
|
845
|
+
return this.visit(ctx.textHighlighter);
|
|
759
846
|
}
|
|
760
847
|
if (ctx.inlineInput) {
|
|
761
848
|
return this.visit(ctx.inlineInput);
|
|
762
849
|
}
|
|
763
850
|
throw new Error("Unknown inline element");
|
|
764
851
|
}
|
|
765
|
-
|
|
852
|
+
textHighlighter(ctx) {
|
|
766
853
|
const params = this.visit(ctx.parameterList);
|
|
767
854
|
const value = params.value;
|
|
768
|
-
|
|
769
|
-
|
|
855
|
+
let highlight = void 0;
|
|
856
|
+
if (params.start !== void 0 && params.end !== void 0) {
|
|
857
|
+
highlight = [params.start, params.end];
|
|
858
|
+
}
|
|
859
|
+
return createHighlightedText(value, highlight);
|
|
770
860
|
}
|
|
771
861
|
inlineInput(ctx) {
|
|
772
862
|
const params = this.visit(ctx.parameterList);
|
|
@@ -796,9 +886,10 @@ class NaturalDSLVisitor extends BaseCstVisitor {
|
|
|
796
886
|
return createDragOptions(strings);
|
|
797
887
|
}
|
|
798
888
|
numericKeypad(ctx) {
|
|
799
|
-
const params = this.visit(ctx.parameterList);
|
|
889
|
+
const params = ctx.parameterList ? this.visit(ctx.parameterList) : {};
|
|
890
|
+
const includeOperators = params.includeOperators === true || params.includeOperators === "true";
|
|
800
891
|
const includeDecimal = params.includeDecimal === true || params.includeDecimal === "true";
|
|
801
|
-
return createNumericKeypad(includeDecimal);
|
|
892
|
+
return createNumericKeypad(includeOperators || void 0, includeDecimal || void 0);
|
|
802
893
|
}
|
|
803
894
|
// ═══════════════════════════════════════════════════════════════════════════
|
|
804
895
|
// Validation
|
|
@@ -890,33 +981,33 @@ function toAST(cst) {
|
|
|
890
981
|
}
|
|
891
982
|
const TextItemSchema = zod.z.object({
|
|
892
983
|
id: zod.z.string(),
|
|
893
|
-
type: zod.z.literal(
|
|
984
|
+
type: zod.z.literal(JSON_TYPES.TEXT),
|
|
894
985
|
value: zod.z.string()
|
|
895
986
|
});
|
|
896
987
|
const QuestionTextSchema = zod.z.object({
|
|
897
988
|
id: zod.z.string(),
|
|
898
|
-
type: zod.z.literal(
|
|
989
|
+
type: zod.z.literal(JSON_TYPES.QUESTION_TEXT),
|
|
899
990
|
value: zod.z.string()
|
|
900
991
|
});
|
|
901
992
|
const WidgetRefSchema = zod.z.object({
|
|
902
993
|
id: zod.z.string(),
|
|
903
|
-
type: zod.z.literal(
|
|
994
|
+
type: zod.z.literal(JSON_TYPES.WIDGET_REF),
|
|
904
995
|
widgetId: zod.z.string()
|
|
905
996
|
});
|
|
906
|
-
const
|
|
997
|
+
const HighlightedTextSchema = zod.z.object({
|
|
907
998
|
id: zod.z.string(),
|
|
908
|
-
type: zod.z.literal(
|
|
999
|
+
type: zod.z.literal(JSON_TYPES.HIGHLIGHTED_TEXT),
|
|
909
1000
|
value: zod.z.string(),
|
|
910
1001
|
highlight: zod.z.tuple([zod.z.number(), zod.z.number()]).optional()
|
|
911
1002
|
});
|
|
912
1003
|
const LinebreakSchema = zod.z.object({
|
|
913
1004
|
id: zod.z.string(),
|
|
914
|
-
type: zod.z.literal(
|
|
1005
|
+
type: zod.z.literal(JSON_TYPES.LINEBREAK)
|
|
915
1006
|
});
|
|
916
1007
|
const OperatorSchema = zod.z.enum(["+", "-", "×", "÷", "=", "<", ">", "?"]);
|
|
917
1008
|
const OperatorItemSchema = zod.z.object({
|
|
918
1009
|
id: zod.z.string(),
|
|
919
|
-
type: zod.z.literal(
|
|
1010
|
+
type: zod.z.literal(JSON_TYPES.OPERATOR),
|
|
920
1011
|
operator: OperatorSchema
|
|
921
1012
|
});
|
|
922
1013
|
const LayoutItemSchema = zod.z.lazy(
|
|
@@ -924,7 +1015,7 @@ const LayoutItemSchema = zod.z.lazy(
|
|
|
924
1015
|
QuestionTextSchema,
|
|
925
1016
|
TextItemSchema,
|
|
926
1017
|
WidgetRefSchema,
|
|
927
|
-
|
|
1018
|
+
HighlightedTextSchema,
|
|
928
1019
|
LinebreakSchema,
|
|
929
1020
|
GroupItemSchema,
|
|
930
1021
|
OperatorItemSchema
|
|
@@ -932,17 +1023,17 @@ const LayoutItemSchema = zod.z.lazy(
|
|
|
932
1023
|
);
|
|
933
1024
|
const GroupItemSchema = zod.z.object({
|
|
934
1025
|
id: zod.z.string(),
|
|
935
|
-
type: zod.z.literal(
|
|
1026
|
+
type: zod.z.literal(JSON_TYPES.GROUP),
|
|
936
1027
|
items: zod.z.array(LayoutItemSchema)
|
|
937
1028
|
});
|
|
938
1029
|
const StringInputJSONSchema = zod.z.object({
|
|
939
|
-
type: zod.z.literal(
|
|
940
|
-
inputType: zod.z.literal(
|
|
1030
|
+
type: zod.z.literal(JSON_TYPES.INLINE_INPUT),
|
|
1031
|
+
inputType: zod.z.literal(INPUT_TYPES.STRING),
|
|
941
1032
|
length: zod.z.number().int().positive()
|
|
942
1033
|
});
|
|
943
1034
|
const NumericInputJSONSchema = zod.z.object({
|
|
944
|
-
type: zod.z.literal(
|
|
945
|
-
inputType: zod.z.literal(
|
|
1035
|
+
type: zod.z.literal(JSON_TYPES.INLINE_INPUT),
|
|
1036
|
+
inputType: zod.z.literal(INPUT_TYPES.NUMERIC),
|
|
946
1037
|
digits: zod.z.number().int().positive()
|
|
947
1038
|
});
|
|
948
1039
|
const InlineInputJSONSchema = zod.z.discriminatedUnion("inputType", [
|
|
@@ -950,12 +1041,13 @@ const InlineInputJSONSchema = zod.z.discriminatedUnion("inputType", [
|
|
|
950
1041
|
NumericInputJSONSchema
|
|
951
1042
|
]);
|
|
952
1043
|
const DragOptionsJSONSchema = zod.z.object({
|
|
953
|
-
type: zod.z.literal(
|
|
1044
|
+
type: zod.z.literal(JSON_TYPES.DRAG_OPTIONS),
|
|
954
1045
|
options: zod.z.array(zod.z.string())
|
|
955
1046
|
});
|
|
956
1047
|
const NumericKeypadJSONSchema = zod.z.object({
|
|
957
|
-
type: zod.z.literal(
|
|
958
|
-
|
|
1048
|
+
type: zod.z.literal(JSON_TYPES.NUMERIC_KEYPAD),
|
|
1049
|
+
includeOperators: zod.z.boolean().optional(),
|
|
1050
|
+
includeDecimal: zod.z.boolean().optional()
|
|
959
1051
|
});
|
|
960
1052
|
const WidgetJSONSchema = zod.z.union([
|
|
961
1053
|
InlineInputJSONSchema,
|
|
@@ -963,7 +1055,7 @@ const WidgetJSONSchema = zod.z.union([
|
|
|
963
1055
|
NumericKeypadJSONSchema
|
|
964
1056
|
]);
|
|
965
1057
|
const ValidationJSONSchema = zod.z.object({
|
|
966
|
-
mode: zod.z.enum([
|
|
1058
|
+
mode: zod.z.enum([VALIDATION_MODES.SIMPLE, VALIDATION_MODES.EXPRESSION]),
|
|
967
1059
|
answers: zod.z.record(zod.z.union([zod.z.string(), zod.z.number()])).optional(),
|
|
968
1060
|
expression: zod.z.string().optional(),
|
|
969
1061
|
variables: zod.z.array(zod.z.string()).optional()
|
|
@@ -995,40 +1087,34 @@ function validateWidgetJSONSafe(data) {
|
|
|
995
1087
|
return WidgetJSONSchema.safeParse(data);
|
|
996
1088
|
}
|
|
997
1089
|
function isQuestionText(item) {
|
|
998
|
-
return item.type ===
|
|
1090
|
+
return item.type === JSON_TYPES.QUESTION_TEXT;
|
|
999
1091
|
}
|
|
1000
|
-
function isTextItem(item) {
|
|
1001
|
-
return item.type ===
|
|
1092
|
+
function isTextItem$1(item) {
|
|
1093
|
+
return item.type === JSON_TYPES.TEXT;
|
|
1002
1094
|
}
|
|
1003
1095
|
function isWidgetRef(item) {
|
|
1004
|
-
return item.type ===
|
|
1096
|
+
return item.type === JSON_TYPES.WIDGET_REF;
|
|
1005
1097
|
}
|
|
1006
|
-
function
|
|
1007
|
-
return item.type ===
|
|
1098
|
+
function isHighlightedText(item) {
|
|
1099
|
+
return item.type === JSON_TYPES.HIGHLIGHTED_TEXT;
|
|
1008
1100
|
}
|
|
1009
1101
|
function isLinebreak(item) {
|
|
1010
|
-
return item.type ===
|
|
1102
|
+
return item.type === JSON_TYPES.LINEBREAK;
|
|
1011
1103
|
}
|
|
1012
1104
|
function isGroupItem(item) {
|
|
1013
|
-
return item.type ===
|
|
1105
|
+
return item.type === JSON_TYPES.GROUP;
|
|
1014
1106
|
}
|
|
1015
1107
|
function isOperatorItem(item) {
|
|
1016
|
-
return item.type ===
|
|
1108
|
+
return item.type === JSON_TYPES.OPERATOR;
|
|
1017
1109
|
}
|
|
1018
1110
|
function isInlineInputJSON(widget) {
|
|
1019
|
-
return widget.type ===
|
|
1111
|
+
return widget.type === JSON_TYPES.INLINE_INPUT;
|
|
1020
1112
|
}
|
|
1021
1113
|
function isDragOptionsJSON(widget) {
|
|
1022
|
-
return widget.type ===
|
|
1114
|
+
return widget.type === JSON_TYPES.DRAG_OPTIONS;
|
|
1023
1115
|
}
|
|
1024
1116
|
function isNumericKeypadJSON(widget) {
|
|
1025
|
-
return widget.type ===
|
|
1026
|
-
}
|
|
1027
|
-
function isWidgetPlaceholder(item) {
|
|
1028
|
-
return item.type === "widget-ref";
|
|
1029
|
-
}
|
|
1030
|
-
function isNumericInputJSON(widget) {
|
|
1031
|
-
return widget.type === "inline-input";
|
|
1117
|
+
return widget.type === JSON_TYPES.NUMERIC_KEYPAD;
|
|
1032
1118
|
}
|
|
1033
1119
|
class LayoutIdGenerator {
|
|
1034
1120
|
constructor() {
|
|
@@ -1046,8 +1132,8 @@ function toJSON(ast) {
|
|
|
1046
1132
|
const layout = [];
|
|
1047
1133
|
if (ast.question) {
|
|
1048
1134
|
layout.push({
|
|
1049
|
-
id: idGenerator.generate(
|
|
1050
|
-
type:
|
|
1135
|
+
id: idGenerator.generate(JSON_TYPES.QUESTION_TEXT),
|
|
1136
|
+
type: JSON_TYPES.QUESTION_TEXT,
|
|
1051
1137
|
value: ast.question.value
|
|
1052
1138
|
});
|
|
1053
1139
|
}
|
|
@@ -1059,17 +1145,17 @@ function toJSON(ast) {
|
|
|
1059
1145
|
const answers = {};
|
|
1060
1146
|
for (const line of ast.lines) {
|
|
1061
1147
|
for (const inline of line.inlines) {
|
|
1062
|
-
if (inline.type ===
|
|
1063
|
-
if (inline.inputType ===
|
|
1148
|
+
if (inline.type === AST_TYPES.INLINE_INPUT) {
|
|
1149
|
+
if (inline.inputType === INPUT_TYPES.STRING) {
|
|
1064
1150
|
widgets[inline.name] = {
|
|
1065
|
-
type:
|
|
1066
|
-
inputType:
|
|
1151
|
+
type: JSON_TYPES.INLINE_INPUT,
|
|
1152
|
+
inputType: INPUT_TYPES.STRING,
|
|
1067
1153
|
length: inline.length
|
|
1068
1154
|
};
|
|
1069
1155
|
} else {
|
|
1070
1156
|
widgets[inline.name] = {
|
|
1071
|
-
type:
|
|
1072
|
-
inputType:
|
|
1157
|
+
type: JSON_TYPES.INLINE_INPUT,
|
|
1158
|
+
inputType: INPUT_TYPES.NUMERIC,
|
|
1073
1159
|
digits: inline.digits
|
|
1074
1160
|
};
|
|
1075
1161
|
}
|
|
@@ -1081,14 +1167,15 @@ function toJSON(ast) {
|
|
|
1081
1167
|
}
|
|
1082
1168
|
if (ast.tools) {
|
|
1083
1169
|
for (const tool of ast.tools) {
|
|
1084
|
-
if (tool.type ===
|
|
1170
|
+
if (tool.type === AST_TYPES.DRAG_OPTIONS) {
|
|
1085
1171
|
widgets["_drag_options"] = {
|
|
1086
|
-
type:
|
|
1172
|
+
type: JSON_TYPES.DRAG_OPTIONS,
|
|
1087
1173
|
options: tool.options
|
|
1088
1174
|
};
|
|
1089
|
-
} else if (tool.type ===
|
|
1175
|
+
} else if (tool.type === AST_TYPES.NUMERIC_KEYPAD) {
|
|
1090
1176
|
widgets["_numeric_keypad"] = {
|
|
1091
|
-
type:
|
|
1177
|
+
type: JSON_TYPES.NUMERIC_KEYPAD,
|
|
1178
|
+
includeOperators: tool.includeOperators,
|
|
1092
1179
|
includeDecimal: tool.includeDecimal
|
|
1093
1180
|
};
|
|
1094
1181
|
}
|
|
@@ -1109,35 +1196,44 @@ function transformLine(line, idGenerator) {
|
|
|
1109
1196
|
items.push(transformInline(inline, idGenerator));
|
|
1110
1197
|
}
|
|
1111
1198
|
items.push({
|
|
1112
|
-
id: idGenerator.generate(
|
|
1113
|
-
type:
|
|
1199
|
+
id: idGenerator.generate(JSON_TYPES.LINEBREAK),
|
|
1200
|
+
type: JSON_TYPES.LINEBREAK
|
|
1114
1201
|
});
|
|
1115
1202
|
return items;
|
|
1116
1203
|
}
|
|
1117
1204
|
function transformInline(inline, idGenerator) {
|
|
1118
1205
|
switch (inline.type) {
|
|
1119
|
-
case
|
|
1206
|
+
case AST_TYPES.FREE_TEXT:
|
|
1207
|
+
const trimmed = inline.value.trim();
|
|
1208
|
+
const operators = ["+", "-", "×", "÷", "=", "<", ">", "?"];
|
|
1209
|
+
if (operators.includes(trimmed) && inline.value.trim() === inline.value) {
|
|
1210
|
+
return {
|
|
1211
|
+
id: idGenerator.generate("operator"),
|
|
1212
|
+
type: "operator",
|
|
1213
|
+
operator: trimmed
|
|
1214
|
+
};
|
|
1215
|
+
}
|
|
1120
1216
|
return {
|
|
1121
|
-
id: idGenerator.generate(
|
|
1122
|
-
type:
|
|
1217
|
+
id: idGenerator.generate(JSON_TYPES.TEXT),
|
|
1218
|
+
type: JSON_TYPES.TEXT,
|
|
1123
1219
|
value: inline.value
|
|
1124
1220
|
};
|
|
1125
|
-
case
|
|
1221
|
+
case AST_TYPES.SPACE:
|
|
1126
1222
|
return {
|
|
1127
|
-
id: idGenerator.generate(
|
|
1128
|
-
type:
|
|
1223
|
+
id: idGenerator.generate(JSON_TYPES.SPACE),
|
|
1224
|
+
type: JSON_TYPES.SPACE
|
|
1129
1225
|
};
|
|
1130
|
-
case
|
|
1226
|
+
case AST_TYPES.HIGHLIGHTED_TEXT:
|
|
1131
1227
|
return {
|
|
1132
|
-
id: idGenerator.generate(
|
|
1133
|
-
type:
|
|
1228
|
+
id: idGenerator.generate(JSON_TYPES.HIGHLIGHTED_TEXT),
|
|
1229
|
+
type: JSON_TYPES.HIGHLIGHTED_TEXT,
|
|
1134
1230
|
value: inline.value,
|
|
1135
1231
|
highlight: inline.highlight
|
|
1136
1232
|
};
|
|
1137
|
-
case
|
|
1233
|
+
case AST_TYPES.INLINE_INPUT:
|
|
1138
1234
|
return {
|
|
1139
|
-
id: idGenerator.generate(
|
|
1140
|
-
type:
|
|
1235
|
+
id: idGenerator.generate(JSON_TYPES.WIDGET_REF),
|
|
1236
|
+
type: JSON_TYPES.WIDGET_REF,
|
|
1141
1237
|
widgetId: inline.name
|
|
1142
1238
|
};
|
|
1143
1239
|
default:
|
|
@@ -1145,16 +1241,16 @@ function transformInline(inline, idGenerator) {
|
|
|
1145
1241
|
}
|
|
1146
1242
|
}
|
|
1147
1243
|
function transformValidation(validation, answers, widgets) {
|
|
1148
|
-
if (validation.type ===
|
|
1244
|
+
if (validation.type === AST_TYPES.SIMPLE_VALIDATION) {
|
|
1149
1245
|
return {
|
|
1150
|
-
mode:
|
|
1246
|
+
mode: VALIDATION_MODES.SIMPLE,
|
|
1151
1247
|
answers
|
|
1152
1248
|
};
|
|
1153
|
-
} else if (validation.type ===
|
|
1249
|
+
} else if (validation.type === AST_TYPES.EXPRESSION_VALIDATION) {
|
|
1154
1250
|
const validVariableNames = Object.keys(widgets);
|
|
1155
1251
|
const variables = extractVariables$1(validation.expression, validVariableNames);
|
|
1156
1252
|
return {
|
|
1157
|
-
mode:
|
|
1253
|
+
mode: VALIDATION_MODES.EXPRESSION,
|
|
1158
1254
|
expression: validation.expression,
|
|
1159
1255
|
variables
|
|
1160
1256
|
};
|
|
@@ -1480,9 +1576,9 @@ function findValidCombination(expression, ranges) {
|
|
|
1480
1576
|
}
|
|
1481
1577
|
function validate(exercise, userInputs) {
|
|
1482
1578
|
switch (exercise.validation.mode) {
|
|
1483
|
-
case
|
|
1579
|
+
case VALIDATION_MODES.SIMPLE:
|
|
1484
1580
|
return validateSimple(exercise, userInputs);
|
|
1485
|
-
case
|
|
1581
|
+
case VALIDATION_MODES.EXPRESSION:
|
|
1486
1582
|
return validateExpression(exercise, userInputs);
|
|
1487
1583
|
default:
|
|
1488
1584
|
return {
|
|
@@ -1494,13 +1590,13 @@ function validate(exercise, userInputs) {
|
|
|
1494
1590
|
}
|
|
1495
1591
|
function getMissingInputs(exercise, userInputs) {
|
|
1496
1592
|
const missing = [];
|
|
1497
|
-
if (exercise.validation.mode ===
|
|
1593
|
+
if (exercise.validation.mode === VALIDATION_MODES.SIMPLE && exercise.validation.answers) {
|
|
1498
1594
|
for (const widgetId of Object.keys(exercise.validation.answers)) {
|
|
1499
1595
|
if (!(widgetId in userInputs) || userInputs[widgetId] === "") {
|
|
1500
1596
|
missing.push(widgetId);
|
|
1501
1597
|
}
|
|
1502
1598
|
}
|
|
1503
|
-
} else if (exercise.validation.mode ===
|
|
1599
|
+
} else if (exercise.validation.mode === VALIDATION_MODES.EXPRESSION && exercise.validation.variables) {
|
|
1504
1600
|
for (const varName of exercise.validation.variables) {
|
|
1505
1601
|
if (!(varName in userInputs) || userInputs[varName] === "") {
|
|
1506
1602
|
missing.push(varName);
|
|
@@ -1516,7 +1612,7 @@ function validateInputFormats(exercise, userInputs) {
|
|
|
1516
1612
|
if (value === void 0 || value === "") {
|
|
1517
1613
|
continue;
|
|
1518
1614
|
}
|
|
1519
|
-
if (widget.type ===
|
|
1615
|
+
if (widget.type === JSON_TYPES.INLINE_INPUT && widget.inputType === INPUT_TYPES.NUMERIC) {
|
|
1520
1616
|
const numValue = typeof value === "number" ? value : parseFloat(String(value));
|
|
1521
1617
|
if (!Number.isFinite(numValue)) {
|
|
1522
1618
|
errors[widgetId] = "Must be a valid number";
|
|
@@ -5546,7 +5642,8 @@ const InlineInput = ({
|
|
|
5546
5642
|
inputType,
|
|
5547
5643
|
length,
|
|
5548
5644
|
digits,
|
|
5549
|
-
onChange
|
|
5645
|
+
onChange,
|
|
5646
|
+
onFocus
|
|
5550
5647
|
}) => {
|
|
5551
5648
|
const handleChange = React.useCallback((newValue, fromDrop = false) => {
|
|
5552
5649
|
onChange(widgetId, newValue, fromDrop);
|
|
@@ -5587,6 +5684,7 @@ const InlineInput = ({
|
|
|
5587
5684
|
className: "inline-input",
|
|
5588
5685
|
value,
|
|
5589
5686
|
onChange: (e) => handleChange(e.target.value, false),
|
|
5687
|
+
onFocus: () => onFocus?.(widgetId),
|
|
5590
5688
|
maxLength: expectedLength,
|
|
5591
5689
|
style: { width: dynamicWidth }
|
|
5592
5690
|
}
|
|
@@ -5631,6 +5729,7 @@ const DragOptions = ({
|
|
|
5631
5729
|
};
|
|
5632
5730
|
const NumericKeypad = ({
|
|
5633
5731
|
value,
|
|
5732
|
+
includeOperators = false,
|
|
5634
5733
|
includeDecimal = false,
|
|
5635
5734
|
onChange
|
|
5636
5735
|
}) => {
|
|
@@ -5640,32 +5739,23 @@ const NumericKeypad = ({
|
|
|
5640
5739
|
const handleBackspace = () => {
|
|
5641
5740
|
onChange(value.slice(0, -1));
|
|
5642
5741
|
};
|
|
5643
|
-
return /* @__PURE__ */ jsxRuntime.jsxs("div", { className: "numeric-keypad"
|
|
5644
|
-
|
|
5645
|
-
|
|
5646
|
-
|
|
5647
|
-
|
|
5648
|
-
|
|
5649
|
-
|
|
5650
|
-
|
|
5651
|
-
|
|
5652
|
-
)),
|
|
5653
|
-
|
|
5654
|
-
|
|
5655
|
-
|
|
5656
|
-
|
|
5657
|
-
|
|
5658
|
-
|
|
5659
|
-
|
|
5660
|
-
),
|
|
5661
|
-
/* @__PURE__ */ jsxRuntime.jsx(
|
|
5662
|
-
"button",
|
|
5663
|
-
{
|
|
5664
|
-
className: "keypad-btn",
|
|
5665
|
-
onClick: handleBackspace,
|
|
5666
|
-
children: "⌫"
|
|
5667
|
-
}
|
|
5668
|
-
)
|
|
5742
|
+
return /* @__PURE__ */ jsxRuntime.jsxs("div", { className: `numeric-keypad ${includeOperators ? "numeric-keypad-with-operators" : ""}`, children: [
|
|
5743
|
+
/* @__PURE__ */ jsxRuntime.jsx("button", { className: "keypad-btn keypad-btn-digit", onClick: () => handleDigit("1"), children: "1" }),
|
|
5744
|
+
/* @__PURE__ */ jsxRuntime.jsx("button", { className: "keypad-btn keypad-btn-digit", onClick: () => handleDigit("2"), children: "2" }),
|
|
5745
|
+
/* @__PURE__ */ jsxRuntime.jsx("button", { className: "keypad-btn keypad-btn-digit", onClick: () => handleDigit("3"), children: "3" }),
|
|
5746
|
+
includeOperators && /* @__PURE__ */ jsxRuntime.jsx("button", { className: "keypad-btn keypad-btn-operator", onClick: () => handleDigit("+"), children: "+" }),
|
|
5747
|
+
/* @__PURE__ */ jsxRuntime.jsx("button", { className: "keypad-btn keypad-btn-digit", onClick: () => handleDigit("4"), children: "4" }),
|
|
5748
|
+
/* @__PURE__ */ jsxRuntime.jsx("button", { className: "keypad-btn keypad-btn-digit", onClick: () => handleDigit("5"), children: "5" }),
|
|
5749
|
+
/* @__PURE__ */ jsxRuntime.jsx("button", { className: "keypad-btn keypad-btn-digit", onClick: () => handleDigit("6"), children: "6" }),
|
|
5750
|
+
includeOperators && /* @__PURE__ */ jsxRuntime.jsx("button", { className: "keypad-btn keypad-btn-operator", onClick: () => handleDigit("-"), children: "-" }),
|
|
5751
|
+
/* @__PURE__ */ jsxRuntime.jsx("button", { className: "keypad-btn keypad-btn-digit", onClick: () => handleDigit("7"), children: "7" }),
|
|
5752
|
+
/* @__PURE__ */ jsxRuntime.jsx("button", { className: "keypad-btn keypad-btn-digit", onClick: () => handleDigit("8"), children: "8" }),
|
|
5753
|
+
/* @__PURE__ */ jsxRuntime.jsx("button", { className: "keypad-btn keypad-btn-digit", onClick: () => handleDigit("9"), children: "9" }),
|
|
5754
|
+
includeOperators && /* @__PURE__ */ jsxRuntime.jsx("button", { className: "keypad-btn keypad-btn-operator", onClick: () => handleDigit("×"), children: "×" }),
|
|
5755
|
+
includeDecimal ? /* @__PURE__ */ jsxRuntime.jsx("button", { className: "keypad-btn keypad-btn-decimal", onClick: () => handleDigit(","), children: "," }) : /* @__PURE__ */ jsxRuntime.jsx("div", {}),
|
|
5756
|
+
/* @__PURE__ */ jsxRuntime.jsx("button", { className: "keypad-btn keypad-btn-digit", onClick: () => handleDigit("0"), children: "0" }),
|
|
5757
|
+
/* @__PURE__ */ jsxRuntime.jsx("button", { className: "keypad-btn keypad-btn-backspace", onClick: handleBackspace, children: "⌫" }),
|
|
5758
|
+
includeOperators && /* @__PURE__ */ jsxRuntime.jsx("button", { className: "keypad-btn keypad-btn-operator", onClick: () => handleDigit("÷"), children: "÷" })
|
|
5669
5759
|
] });
|
|
5670
5760
|
};
|
|
5671
5761
|
function isInlineInputWidget(widget) {
|
|
@@ -5682,11 +5772,10 @@ const WidgetRenderer = ({
|
|
|
5682
5772
|
widgetId,
|
|
5683
5773
|
value,
|
|
5684
5774
|
isDropped = false,
|
|
5685
|
-
onChange
|
|
5775
|
+
onChange,
|
|
5776
|
+
onInputFocus,
|
|
5777
|
+
onKeypadChange
|
|
5686
5778
|
}) => {
|
|
5687
|
-
const handleChange = React.useCallback((newValue, fromDrop = false) => {
|
|
5688
|
-
onChange(widgetId, newValue, fromDrop);
|
|
5689
|
-
}, [onChange, widgetId]);
|
|
5690
5779
|
if (isInlineInputWidget(widget)) {
|
|
5691
5780
|
return /* @__PURE__ */ jsxRuntime.jsx(
|
|
5692
5781
|
InlineInput,
|
|
@@ -5697,7 +5786,8 @@ const WidgetRenderer = ({
|
|
|
5697
5786
|
inputType: widget.inputType,
|
|
5698
5787
|
length: widget.inputType === "string" ? widget.length : void 0,
|
|
5699
5788
|
digits: widget.inputType === "numeric" ? widget.digits : void 0,
|
|
5700
|
-
onChange
|
|
5789
|
+
onChange,
|
|
5790
|
+
onFocus: onInputFocus
|
|
5701
5791
|
}
|
|
5702
5792
|
);
|
|
5703
5793
|
}
|
|
@@ -5716,41 +5806,102 @@ const WidgetRenderer = ({
|
|
|
5716
5806
|
NumericKeypad,
|
|
5717
5807
|
{
|
|
5718
5808
|
value,
|
|
5809
|
+
includeOperators: widget.includeOperators,
|
|
5719
5810
|
includeDecimal: widget.includeDecimal,
|
|
5720
|
-
onChange:
|
|
5811
|
+
onChange: onKeypadChange || (() => {
|
|
5812
|
+
})
|
|
5721
5813
|
}
|
|
5722
5814
|
);
|
|
5723
5815
|
}
|
|
5724
5816
|
return null;
|
|
5725
5817
|
};
|
|
5726
|
-
function isArabic
|
|
5818
|
+
function isArabic(text) {
|
|
5727
5819
|
return /[\u0600-\u06FF\u0750-\u077F\u08A0-\u08FF\uFB50-\uFDFF\uFE70-\uFEFF]/.test(text);
|
|
5728
5820
|
}
|
|
5821
|
+
function hasLatinChars(text) {
|
|
5822
|
+
return /[A-Za-z]/.test(text);
|
|
5823
|
+
}
|
|
5824
|
+
function itemContainsArabic(item) {
|
|
5825
|
+
if (item.type === JSON_TYPES.TEXT && "value" in item) {
|
|
5826
|
+
return isArabic(item.value);
|
|
5827
|
+
}
|
|
5828
|
+
if (item.type === JSON_TYPES.HIGHLIGHTED_TEXT && "value" in item) {
|
|
5829
|
+
return isArabic(item.value);
|
|
5830
|
+
}
|
|
5831
|
+
if (item.type === JSON_TYPES.GROUP && "items" in item) {
|
|
5832
|
+
return item.items.some((subItem) => itemContainsArabic(subItem));
|
|
5833
|
+
}
|
|
5834
|
+
return false;
|
|
5835
|
+
}
|
|
5836
|
+
function itemContainsLatin(item) {
|
|
5837
|
+
if (item.type === JSON_TYPES.TEXT && "value" in item) {
|
|
5838
|
+
return hasLatinChars(item.value);
|
|
5839
|
+
}
|
|
5840
|
+
if (item.type === JSON_TYPES.HIGHLIGHTED_TEXT && "value" in item) {
|
|
5841
|
+
return hasLatinChars(item.value);
|
|
5842
|
+
}
|
|
5843
|
+
if (item.type === JSON_TYPES.GROUP && "items" in item) {
|
|
5844
|
+
return item.items.some((subItem) => itemContainsLatin(subItem));
|
|
5845
|
+
}
|
|
5846
|
+
return false;
|
|
5847
|
+
}
|
|
5848
|
+
function isTextItem(item) {
|
|
5849
|
+
return item.type === JSON_TYPES.TEXT || item.type === JSON_TYPES.HIGHLIGHTED_TEXT || item.type === JSON_TYPES.OPERATOR || item.type === JSON_TYPES.SPACE || item.type === JSON_TYPES.GROUP;
|
|
5850
|
+
}
|
|
5851
|
+
function groupLineItems(items) {
|
|
5852
|
+
const groups = [];
|
|
5853
|
+
let currentTextGroup = [];
|
|
5854
|
+
for (const item of items) {
|
|
5855
|
+
if (isTextItem(item)) {
|
|
5856
|
+
currentTextGroup.push(item);
|
|
5857
|
+
} else {
|
|
5858
|
+
if (currentTextGroup.length > 0) {
|
|
5859
|
+
const hasArabic = currentTextGroup.some(itemContainsArabic);
|
|
5860
|
+
const hasLatin = currentTextGroup.some(itemContainsLatin);
|
|
5861
|
+
const shouldApplyRTL = hasArabic && !hasLatin;
|
|
5862
|
+
groups.push({ items: currentTextGroup, isTextGroup: true, hasArabic, hasLatin, shouldApplyRTL });
|
|
5863
|
+
currentTextGroup = [];
|
|
5864
|
+
}
|
|
5865
|
+
groups.push({ items: [item], isTextGroup: false, hasArabic: false, hasLatin: false, shouldApplyRTL: false });
|
|
5866
|
+
}
|
|
5867
|
+
}
|
|
5868
|
+
if (currentTextGroup.length > 0) {
|
|
5869
|
+
const hasArabic = currentTextGroup.some(itemContainsArabic);
|
|
5870
|
+
const hasLatin = currentTextGroup.some(itemContainsLatin);
|
|
5871
|
+
const shouldApplyRTL = hasArabic && !hasLatin;
|
|
5872
|
+
groups.push({ items: currentTextGroup, isTextGroup: true, hasArabic, hasLatin, shouldApplyRTL });
|
|
5873
|
+
}
|
|
5874
|
+
return groups;
|
|
5875
|
+
}
|
|
5729
5876
|
const LayoutRenderer = ({
|
|
5730
5877
|
item,
|
|
5731
5878
|
widgets,
|
|
5732
5879
|
values,
|
|
5733
5880
|
droppedInputs,
|
|
5734
|
-
onChange
|
|
5881
|
+
onChange,
|
|
5882
|
+
onInputFocus
|
|
5735
5883
|
}) => {
|
|
5736
5884
|
switch (item.type) {
|
|
5737
|
-
case
|
|
5738
|
-
const hasArabic = isArabic
|
|
5885
|
+
case JSON_TYPES.QUESTION_TEXT: {
|
|
5886
|
+
const hasArabic = isArabic(item.value);
|
|
5739
5887
|
return /* @__PURE__ */ jsxRuntime.jsx("span", { className: `question-text ${hasArabic ? "question-text-arabic" : ""}`, children: item.value });
|
|
5740
5888
|
}
|
|
5741
|
-
case
|
|
5742
|
-
return /* @__PURE__ */ jsxRuntime.jsx("span", { className: `text-item ${isArabic
|
|
5743
|
-
case
|
|
5889
|
+
case JSON_TYPES.TEXT:
|
|
5890
|
+
return /* @__PURE__ */ jsxRuntime.jsx("span", { className: `text-item ${isArabic(item.value) ? "text-item-arabic" : "text-item-not-arabic"}`, children: item.value });
|
|
5891
|
+
case JSON_TYPES.HIGHLIGHTED_TEXT: {
|
|
5892
|
+
const hasArabic = isArabic(item.value);
|
|
5893
|
+
const dirAttr = !hasArabic ? "ltr" : void 0;
|
|
5744
5894
|
if (item.highlight) {
|
|
5745
5895
|
const [start, end] = item.highlight;
|
|
5746
|
-
return /* @__PURE__ */ jsxRuntime.jsxs("span", { className: "
|
|
5896
|
+
return /* @__PURE__ */ jsxRuntime.jsxs("span", { className: "highlighted-text", dir: dirAttr, children: [
|
|
5747
5897
|
item.value.slice(0, start),
|
|
5748
|
-
/* @__PURE__ */ jsxRuntime.jsx("
|
|
5898
|
+
/* @__PURE__ */ jsxRuntime.jsx("span", { className: "highlight", children: item.value.slice(start, end) }),
|
|
5749
5899
|
item.value.slice(end)
|
|
5750
5900
|
] });
|
|
5751
5901
|
}
|
|
5752
|
-
return /* @__PURE__ */ jsxRuntime.jsx("span", { className: "
|
|
5753
|
-
|
|
5902
|
+
return /* @__PURE__ */ jsxRuntime.jsx("span", { className: "highlighted-text", dir: dirAttr, children: item.value });
|
|
5903
|
+
}
|
|
5904
|
+
case JSON_TYPES.WIDGET_REF: {
|
|
5754
5905
|
const widget = widgets[item.widgetId];
|
|
5755
5906
|
if (!widget) return null;
|
|
5756
5907
|
return /* @__PURE__ */ jsxRuntime.jsx(
|
|
@@ -5760,15 +5911,18 @@ const LayoutRenderer = ({
|
|
|
5760
5911
|
widgetId: item.widgetId,
|
|
5761
5912
|
value: values[item.widgetId] || "",
|
|
5762
5913
|
isDropped: droppedInputs.has(item.widgetId),
|
|
5763
|
-
onChange
|
|
5914
|
+
onChange,
|
|
5915
|
+
onInputFocus
|
|
5764
5916
|
}
|
|
5765
5917
|
);
|
|
5766
5918
|
}
|
|
5767
|
-
case
|
|
5919
|
+
case JSON_TYPES.SPACE:
|
|
5920
|
+
return /* @__PURE__ */ jsxRuntime.jsx("span", { className: "space", children: " " });
|
|
5921
|
+
case JSON_TYPES.LINEBREAK:
|
|
5768
5922
|
return null;
|
|
5769
|
-
case
|
|
5923
|
+
case JSON_TYPES.OPERATOR:
|
|
5770
5924
|
return /* @__PURE__ */ jsxRuntime.jsx("span", { className: "operator", children: item.operator });
|
|
5771
|
-
case
|
|
5925
|
+
case JSON_TYPES.GROUP:
|
|
5772
5926
|
return /* @__PURE__ */ jsxRuntime.jsx("span", { className: "group", children: item.items.map((subItem) => /* @__PURE__ */ jsxRuntime.jsx(
|
|
5773
5927
|
LayoutRenderer,
|
|
5774
5928
|
{
|
|
@@ -5776,7 +5930,8 @@ const LayoutRenderer = ({
|
|
|
5776
5930
|
widgets,
|
|
5777
5931
|
values,
|
|
5778
5932
|
droppedInputs,
|
|
5779
|
-
onChange
|
|
5933
|
+
onChange,
|
|
5934
|
+
onInputFocus
|
|
5780
5935
|
},
|
|
5781
5936
|
subItem.id
|
|
5782
5937
|
)) });
|
|
@@ -5793,21 +5948,6 @@ const DEFAULT_RULER_TOOL = {
|
|
|
5793
5948
|
width: 300,
|
|
5794
5949
|
allowRotate: true
|
|
5795
5950
|
};
|
|
5796
|
-
function isArabic(text) {
|
|
5797
|
-
return /[\u0600-\u06FF\u0750-\u077F\u08A0-\u08FF\uFB50-\uFDFF\uFE70-\uFEFF]/.test(text);
|
|
5798
|
-
}
|
|
5799
|
-
function itemContainsArabic(item) {
|
|
5800
|
-
if (item.type === "text" && "value" in item) {
|
|
5801
|
-
return isArabic(item.value);
|
|
5802
|
-
}
|
|
5803
|
-
if (item.type === "number-text" && "value" in item) {
|
|
5804
|
-
return isArabic(item.value);
|
|
5805
|
-
}
|
|
5806
|
-
if (item.type === "group" && "items" in item) {
|
|
5807
|
-
return item.items.some((subItem) => itemContainsArabic(subItem));
|
|
5808
|
-
}
|
|
5809
|
-
return false;
|
|
5810
|
-
}
|
|
5811
5951
|
const ExerciseRenderer = React.forwardRef(({
|
|
5812
5952
|
json,
|
|
5813
5953
|
onSubmit,
|
|
@@ -5817,6 +5957,7 @@ const ExerciseRenderer = React.forwardRef(({
|
|
|
5817
5957
|
}, ref) => {
|
|
5818
5958
|
const [values, setValues] = React.useState({});
|
|
5819
5959
|
const [droppedInputs, setDroppedInputs] = React.useState(/* @__PURE__ */ new Set());
|
|
5960
|
+
const [focusedInputId, setFocusedInputId] = React.useState(null);
|
|
5820
5961
|
React.useImperativeHandle(ref, () => ({
|
|
5821
5962
|
submit: () => {
|
|
5822
5963
|
const result = validate(json, values);
|
|
@@ -5827,6 +5968,7 @@ const ExerciseRenderer = React.forwardRef(({
|
|
|
5827
5968
|
reset: () => {
|
|
5828
5969
|
setValues({});
|
|
5829
5970
|
setDroppedInputs(/* @__PURE__ */ new Set());
|
|
5971
|
+
setFocusedInputId(null);
|
|
5830
5972
|
},
|
|
5831
5973
|
focusFirstInput: () => {
|
|
5832
5974
|
const container = document.querySelector(".math-exercise-renderer");
|
|
@@ -5857,10 +5999,20 @@ const ExerciseRenderer = React.forwardRef(({
|
|
|
5857
5999
|
const groups = [];
|
|
5858
6000
|
let currentGroup = [];
|
|
5859
6001
|
for (const item of json.layout) {
|
|
5860
|
-
if (item.type ===
|
|
6002
|
+
if (item.type === JSON_TYPES.QUESTION_TEXT) {
|
|
6003
|
+
groups.push({
|
|
6004
|
+
items: [item],
|
|
6005
|
+
hasArabic: itemContainsArabic(item),
|
|
6006
|
+
subGroups: []
|
|
6007
|
+
// Question text doesn't need sub-grouping
|
|
6008
|
+
});
|
|
6009
|
+
continue;
|
|
6010
|
+
}
|
|
6011
|
+
if (item.type === JSON_TYPES.LINEBREAK) {
|
|
5861
6012
|
if (currentGroup.length > 0) {
|
|
5862
6013
|
const hasArabic = currentGroup.some((item2) => itemContainsArabic(item2));
|
|
5863
|
-
|
|
6014
|
+
const subGroups = groupLineItems(currentGroup);
|
|
6015
|
+
groups.push({ items: currentGroup, hasArabic, subGroups });
|
|
5864
6016
|
currentGroup = [];
|
|
5865
6017
|
}
|
|
5866
6018
|
} else {
|
|
@@ -5869,7 +6021,8 @@ const ExerciseRenderer = React.forwardRef(({
|
|
|
5869
6021
|
}
|
|
5870
6022
|
if (currentGroup.length > 0) {
|
|
5871
6023
|
const hasArabic = currentGroup.some((item) => itemContainsArabic(item));
|
|
5872
|
-
|
|
6024
|
+
const subGroups = groupLineItems(currentGroup);
|
|
6025
|
+
groups.push({ items: currentGroup, hasArabic, subGroups });
|
|
5873
6026
|
}
|
|
5874
6027
|
return groups;
|
|
5875
6028
|
}, [json.layout]);
|
|
@@ -5890,17 +6043,52 @@ const ExerciseRenderer = React.forwardRef(({
|
|
|
5890
6043
|
"div",
|
|
5891
6044
|
{
|
|
5892
6045
|
className: `exercise-line ${group.hasArabic ? "exercise-line-arabic" : ""}`,
|
|
5893
|
-
children: group.
|
|
5894
|
-
|
|
5895
|
-
|
|
5896
|
-
|
|
5897
|
-
|
|
5898
|
-
|
|
5899
|
-
|
|
5900
|
-
|
|
5901
|
-
|
|
5902
|
-
|
|
5903
|
-
|
|
6046
|
+
children: group.subGroups.length > 0 ? (
|
|
6047
|
+
// Render sub-groups for regular lines
|
|
6048
|
+
group.subGroups.map((subGroup, subIdx) => subGroup.isTextGroup ? (
|
|
6049
|
+
// Text group - only apply RTL for pure Arabic (no mixed languages)
|
|
6050
|
+
/* @__PURE__ */ jsxRuntime.jsx("span", { className: "text-group", dir: subGroup.shouldApplyRTL ? "rtl" : void 0, children: subGroup.items.map((item) => /* @__PURE__ */ jsxRuntime.jsx(
|
|
6051
|
+
LayoutRenderer,
|
|
6052
|
+
{
|
|
6053
|
+
item,
|
|
6054
|
+
widgets: json.widgets,
|
|
6055
|
+
values,
|
|
6056
|
+
droppedInputs,
|
|
6057
|
+
onChange: handleChange,
|
|
6058
|
+
onInputFocus: setFocusedInputId
|
|
6059
|
+
},
|
|
6060
|
+
item.id
|
|
6061
|
+
)) }, subIdx)
|
|
6062
|
+
) : (
|
|
6063
|
+
// Widget group - no dir wrapper, render directly
|
|
6064
|
+
subGroup.items.map((item) => /* @__PURE__ */ jsxRuntime.jsx(
|
|
6065
|
+
LayoutRenderer,
|
|
6066
|
+
{
|
|
6067
|
+
item,
|
|
6068
|
+
widgets: json.widgets,
|
|
6069
|
+
values,
|
|
6070
|
+
droppedInputs,
|
|
6071
|
+
onChange: handleChange,
|
|
6072
|
+
onInputFocus: setFocusedInputId
|
|
6073
|
+
},
|
|
6074
|
+
item.id
|
|
6075
|
+
))
|
|
6076
|
+
))
|
|
6077
|
+
) : (
|
|
6078
|
+
// For QUESTION_TEXT items (no sub-groups)
|
|
6079
|
+
group.items.map((item) => /* @__PURE__ */ jsxRuntime.jsx(
|
|
6080
|
+
LayoutRenderer,
|
|
6081
|
+
{
|
|
6082
|
+
item,
|
|
6083
|
+
widgets: json.widgets,
|
|
6084
|
+
values,
|
|
6085
|
+
droppedInputs,
|
|
6086
|
+
onChange: handleChange,
|
|
6087
|
+
onInputFocus: setFocusedInputId
|
|
6088
|
+
},
|
|
6089
|
+
item.id
|
|
6090
|
+
))
|
|
6091
|
+
)
|
|
5904
6092
|
},
|
|
5905
6093
|
groupIdx
|
|
5906
6094
|
)) }),
|
|
@@ -5909,9 +6097,13 @@ const ExerciseRenderer = React.forwardRef(({
|
|
|
5909
6097
|
{
|
|
5910
6098
|
widget: numericKeypadWidget,
|
|
5911
6099
|
widgetId: "_numeric_keypad",
|
|
5912
|
-
value: "",
|
|
5913
|
-
onChange: (
|
|
5914
|
-
|
|
6100
|
+
value: focusedInputId ? values[focusedInputId] || "" : "",
|
|
6101
|
+
onChange: () => {
|
|
6102
|
+
},
|
|
6103
|
+
onKeypadChange: (newValue) => {
|
|
6104
|
+
if (focusedInputId) {
|
|
6105
|
+
handleChange(focusedInputId, newValue, false);
|
|
6106
|
+
}
|
|
5915
6107
|
}
|
|
5916
6108
|
}
|
|
5917
6109
|
) })
|
|
@@ -5981,6 +6173,7 @@ function compileWithAST(dsl) {
|
|
|
5981
6173
|
const json = toJSON(ast);
|
|
5982
6174
|
return { ast, json };
|
|
5983
6175
|
}
|
|
6176
|
+
exports.AST_TYPES = AST_TYPES;
|
|
5984
6177
|
exports.DragOptionsJSONSchema = DragOptionsJSONSchema;
|
|
5985
6178
|
exports.DragOptionsToolSchema = DragOptionsToolSchema;
|
|
5986
6179
|
exports.EngineError = EngineError;
|
|
@@ -5991,16 +6184,17 @@ exports.ExerciseRenderer = ExerciseRenderer;
|
|
|
5991
6184
|
exports.ExpressionValidationSchema = ExpressionValidationSchema;
|
|
5992
6185
|
exports.FreeTextInlineSchema = FreeTextInlineSchema;
|
|
5993
6186
|
exports.GroupItemSchema = GroupItemSchema;
|
|
6187
|
+
exports.HighlightedTextInlineSchema = HighlightedTextInlineSchema;
|
|
6188
|
+
exports.HighlightedTextSchema = HighlightedTextSchema;
|
|
5994
6189
|
exports.InlineInputJSONSchema = InlineInputJSONSchema;
|
|
5995
6190
|
exports.InlineInputWidgetSchema = InlineInputWidgetSchema;
|
|
5996
6191
|
exports.InlineNodeSchema = InlineNodeSchema;
|
|
6192
|
+
exports.JSON_TYPES = JSON_TYPES;
|
|
5997
6193
|
exports.LayoutItemSchema = LayoutItemSchema;
|
|
5998
6194
|
exports.LayoutRenderer = LayoutRenderer;
|
|
5999
6195
|
exports.LexerError = LexerError;
|
|
6000
6196
|
exports.LineBlockSchema = LineBlockSchema;
|
|
6001
6197
|
exports.LinebreakSchema = LinebreakSchema;
|
|
6002
|
-
exports.NumberTextInlineSchema = NumberTextInlineSchema;
|
|
6003
|
-
exports.NumberTextSchema = NumberTextSchema;
|
|
6004
6198
|
exports.NumericKeypadJSONSchema = NumericKeypadJSONSchema;
|
|
6005
6199
|
exports.NumericKeypadToolSchema = NumericKeypadToolSchema;
|
|
6006
6200
|
exports.OperatorItemSchema = OperatorItemSchema;
|
|
@@ -6025,9 +6219,8 @@ exports.createDragOptions = createDragOptions;
|
|
|
6025
6219
|
exports.createExerciseDocument = createExerciseDocument;
|
|
6026
6220
|
exports.createExpressionValidation = createExpressionValidation;
|
|
6027
6221
|
exports.createFreeText = createFreeText;
|
|
6028
|
-
exports.
|
|
6222
|
+
exports.createHighlightedText = createHighlightedText;
|
|
6029
6223
|
exports.createLineBlock = createLineBlock;
|
|
6030
|
-
exports.createNumberText = createNumberText;
|
|
6031
6224
|
exports.createNumericInput = createNumericInput;
|
|
6032
6225
|
exports.createNumericKeypad = createNumericKeypad;
|
|
6033
6226
|
exports.createSimpleValidation = createSimpleValidation;
|
|
@@ -6044,13 +6237,12 @@ exports.isExerciseDocument = isExerciseDocument;
|
|
|
6044
6237
|
exports.isExpressionValidation = isExpressionValidation;
|
|
6045
6238
|
exports.isFreeText = isFreeText;
|
|
6046
6239
|
exports.isGroupItem = isGroupItem;
|
|
6240
|
+
exports.isHighlightedText = isHighlightedText;
|
|
6047
6241
|
exports.isInlineInput = isInlineInput;
|
|
6048
6242
|
exports.isInlineInputJSON = isInlineInputJSON;
|
|
6049
6243
|
exports.isInlineNode = isInlineNode;
|
|
6050
6244
|
exports.isLineBlock = isLineBlock;
|
|
6051
6245
|
exports.isLinebreak = isLinebreak;
|
|
6052
|
-
exports.isNumberText = isNumberText;
|
|
6053
|
-
exports.isNumericInputJSON = isNumericInputJSON;
|
|
6054
6246
|
exports.isNumericKeypad = isNumericKeypad;
|
|
6055
6247
|
exports.isNumericKeypadJSON = isNumericKeypadJSON;
|
|
6056
6248
|
exports.isOperatorItem = isOperatorItem;
|
|
@@ -6058,11 +6250,10 @@ exports.isQuestionText = isQuestionText;
|
|
|
6058
6250
|
exports.isSimpleValidation = isSimpleValidation;
|
|
6059
6251
|
exports.isSpace = isSpace;
|
|
6060
6252
|
exports.isTextBlock = isTextBlock;
|
|
6061
|
-
exports.isTextItem = isTextItem;
|
|
6253
|
+
exports.isTextItem = isTextItem$1;
|
|
6062
6254
|
exports.isToolNode = isToolNode;
|
|
6063
6255
|
exports.isValidExpression = isValidExpression;
|
|
6064
6256
|
exports.isValidationNode = isValidationNode;
|
|
6065
|
-
exports.isWidgetPlaceholder = isWidgetPlaceholder;
|
|
6066
6257
|
exports.isWidgetRef = isWidgetRef;
|
|
6067
6258
|
exports.parse = parse;
|
|
6068
6259
|
exports.parseSafe = parseSafe;
|