@mathscan/math-exercise-engine 1.1.17 → 1.2.1

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 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?.reset(); // Clear all inputs
100
- exerciseRef.current?.focusFirstInput(); // Focus first input field
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 and returns `ValidationResult` (also triggers `onSubmit` callback)
106
- - **`getValues()`**: Returns `Record<string, string>` of all current input values
107
- - **`reset()`**: Clears all input fields to empty state
108
- - **`focusFirstInput()`**: Automatically focuses the first input element
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; // Perform validation & return result
232
- getValues: () => Record<string, string>; // Get current values
233
- reset: () => void; // Clear all inputs
234
- focusFirstInput: () => void; // Focus first input
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