@mathscan/math-exercise-engine 1.1.17 → 1.2.0
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/README.md +44 -11
- package/dist/index.d.ts +17 -0
- package/dist/index.js +230 -152
- package/dist/index.js.map +1 -1
- package/dist/index.mjs +230 -152
- package/dist/index.mjs.map +1 -1
- package/dist/style.css +40 -0
- package/package.json +19 -20
package/README.md
CHANGED
|
@@ -94,18 +94,49 @@ import type { ExerciseRendererRef } from '@mathscan/math-exercise-engine';
|
|
|
94
94
|
const exerciseRef = useRef<ExerciseRendererRef>(null);
|
|
95
95
|
|
|
96
96
|
// Available methods:
|
|
97
|
-
const result = exerciseRef.current?.submit(); // Returns ValidationResult
|
|
97
|
+
const result = exerciseRef.current?.submit(); // Returns ValidationResult — LOCKS the exercise
|
|
98
98
|
exerciseRef.current?.getValues(); // Get current input values
|
|
99
|
-
exerciseRef.current?.
|
|
100
|
-
exerciseRef.current?.
|
|
99
|
+
exerciseRef.current?.getCompletion(); // How many answerable inputs are filled
|
|
100
|
+
exerciseRef.current?.revealAnswers(); // Fill in the correct answers — also LOCKS
|
|
101
|
+
exerciseRef.current?.reset(); // Clear all inputs and unlock
|
|
102
|
+
exerciseRef.current?.focusFirstInput(); // Focus first editable input field
|
|
101
103
|
```
|
|
102
104
|
|
|
103
105
|
### Method Details
|
|
104
106
|
|
|
105
|
-
- **`submit()`**: Performs validation
|
|
106
|
-
- **`getValues()`**: Returns `Record<string,
|
|
107
|
-
- **`
|
|
108
|
-
- **`
|
|
107
|
+
- **`submit()`**: Performs validation, returns `ValidationResult`, triggers `onSubmit`, and **locks the exercise** (see below). Calling it again while locked is a no-op that replays the same `ValidationResult` — no sound, no `onSubmit`
|
|
108
|
+
- **`getValues()`**: Returns `Record<string, UserAnswerValue>` of all current input values
|
|
109
|
+
- **`getCompletion()`**: Returns `{ total, filled, missing, filledIds, isComplete, isAnyFilled }` — use it to decide when to enable your submit button
|
|
110
|
+
- **`revealAnswers()`**: Fills every widget with its correct answer and **locks the exercise**. No-op for display-only exercises
|
|
111
|
+
- **`reset()`**: Clears all input fields and **unlocks** the exercise
|
|
112
|
+
- **`focusFirstInput()`**: Focuses the first editable input of *this* renderer. Skips read-only/disabled fields, so it does nothing while the exercise is locked
|
|
113
|
+
|
|
114
|
+
## 🔒 Locking After a Check
|
|
115
|
+
|
|
116
|
+
Once the answer is checked, the exercise becomes read-only until it is reset. This is the default and cannot be turned off.
|
|
117
|
+
|
|
118
|
+
**What locks it:** `submit()`, the built-in `showSubmitButton` button, and `revealAnswers()`.
|
|
119
|
+
**What unlocks it:** `reset()` — nothing else.
|
|
120
|
+
|
|
121
|
+
While locked, every widget refuses input: text inputs go `readOnly`, option/card widgets get `aria-disabled`, keypad and counter buttons get `disabled`, the built-in Check Answer button is `disabled`, drag-and-drop is disabled, and clock hands / number-line cursors stop responding. The root element gets a `.locked` class so you can style the state:
|
|
122
|
+
|
|
123
|
+
```css
|
|
124
|
+
.math-exercise-renderer.locked { /* your read-only styling */ }
|
|
125
|
+
```
|
|
126
|
+
|
|
127
|
+
Floating geometry tools (ruler, protractor, set square) stay draggable — they are instruments, not answers.
|
|
128
|
+
|
|
129
|
+
If your app shows an exercise in review mode (correction, teacher preview) and wants it read-only from the start, wrap it in your own provider:
|
|
130
|
+
|
|
131
|
+
```tsx
|
|
132
|
+
import { ExerciseLockProvider } from '@mathscan/math-exercise-engine';
|
|
133
|
+
|
|
134
|
+
<ExerciseLockProvider locked>
|
|
135
|
+
<ExerciseRenderer json={json} />
|
|
136
|
+
</ExerciseLockProvider>
|
|
137
|
+
```
|
|
138
|
+
|
|
139
|
+
The renderer ORs your value with its own state, so an outer lock is never overridden by an un-submitted exercise. Custom widgets of your own can read the same state with the `useExerciseLocked()` hook.
|
|
109
140
|
|
|
110
141
|
## 📝 DSL Syntax
|
|
111
142
|
|
|
@@ -228,10 +259,12 @@ import type {
|
|
|
228
259
|
|
|
229
260
|
// ExerciseRendererRef interface:
|
|
230
261
|
interface ExerciseRendererRef {
|
|
231
|
-
submit: () => ValidationResult; //
|
|
232
|
-
getValues: () => Record<string,
|
|
233
|
-
|
|
234
|
-
|
|
262
|
+
submit: () => ValidationResult; // Validate, return result, lock the exercise
|
|
263
|
+
getValues: () => Record<string, UserAnswerValue>; // Get current values
|
|
264
|
+
getCompletion: () => InputCompletion; // Fill status of the answerable inputs
|
|
265
|
+
revealAnswers: () => void; // Fill in correct answers, lock the exercise
|
|
266
|
+
reset: () => void; // Clear all inputs and unlock
|
|
267
|
+
focusFirstInput: () => void; // Focus first editable input
|
|
235
268
|
}
|
|
236
269
|
```
|
|
237
270
|
|
package/dist/index.d.ts
CHANGED
|
@@ -16149,6 +16149,20 @@ export declare const ExerciseJSONSchema: z.ZodObject<{
|
|
|
16149
16149
|
} | undefined;
|
|
16150
16150
|
}>;
|
|
16151
16151
|
|
|
16152
|
+
/**
|
|
16153
|
+
* Broadcasts the exercise lock to every widget.
|
|
16154
|
+
*
|
|
16155
|
+
* A context (rather than a prop threaded through LayoutRenderer → WidgetRenderer)
|
|
16156
|
+
* because interactive elements sit 3–4 levels deep (number-line arcs, matcher
|
|
16157
|
+
* cards, DnD chips rendered into a body portal).
|
|
16158
|
+
*/
|
|
16159
|
+
export declare const ExerciseLockProvider: default_2.FC<ExerciseLockProviderProps>;
|
|
16160
|
+
|
|
16161
|
+
export declare interface ExerciseLockProviderProps {
|
|
16162
|
+
locked: boolean;
|
|
16163
|
+
children: default_2.ReactNode;
|
|
16164
|
+
}
|
|
16165
|
+
|
|
16152
16166
|
export declare type ExerciseMeta = z.infer<typeof ExerciseMetaSchema>;
|
|
16153
16167
|
|
|
16154
16168
|
export declare const ExerciseMetaSchema: z.ZodObject<{
|
|
@@ -26727,6 +26741,9 @@ export declare class TransformError extends EngineError {
|
|
|
26727
26741
|
constructor(message: string, position?: SourcePosition);
|
|
26728
26742
|
}
|
|
26729
26743
|
|
|
26744
|
+
/** true once the exercise was checked/revealed — widgets must refuse input until reset(). */
|
|
26745
|
+
export declare const useExerciseLocked: () => boolean;
|
|
26746
|
+
|
|
26730
26747
|
/** User answers keyed by widget ID. */
|
|
26731
26748
|
export declare type UserAnswers = Record<string, UserAnswerValue>;
|
|
26732
26749
|
|