Skip to content

Latest commit

 

History

History
56 lines (36 loc) · 6.37 KB

ADDING_WORKSHEETS.md

File metadata and controls

56 lines (36 loc) · 6.37 KB

Adding worksheet types

A worksheet is a registered generator and editor definition. Each type owns its content schema, defaults, validation, educational presets, controls, question data and layout. Subtraction number lines are the first shipped type. Multiplication is currently an executable test fixture, not a published worksheet option.

Shared settings and inheritance

packages/core/src/worksheet-settings.ts provides reusable educational context, page, font and presentation schemas, plus detail, font and answer-sheet control groups. Compose those with the new type's content and presentation extensions. A multiplication schema can contain tables, multiplier bounds, random ordering and column count without including a number line or subtraction bounds.

defineWorksheet binds a typed generator to its typed editor rules. The editor explicitly lists which common preferences it inherits. Supported inheritance keys are country, education system, year group, minimum and maximum ages, paper size, orientation and font family. Omitted keys retain that worksheet's own defaults. Difficulty, numeric bounds, question count and layout choices remain owned by the worksheet and its preset rules.

Configuration creation follows this order:

  1. Clone the target worksheet's defaults.
  2. Apply its educational preset if it defines one.
  3. Apply its allowlisted shared preferences.
  4. If current-setting inheritance was requested, use the source worksheet's values for those same allowlisted settings.
  5. Run the worksheet's preparation, validation and schema parsing.

Content settings are never copied between different worksheet types. Shared defaults are not a global mutable configuration, and inheriting presentation choices does not change an existing worksheet's questions or seed. Starting a new worksheet creates a fresh seed. The complete resulting configuration is saved, so later preference changes do not alter earlier generations.

For example, a multiplication worksheet can inherit paper and font while retaining its own year group and portrait orientation:

const multiplicationWorksheet = defineWorksheet(multiplicationGenerator, {
  inherit: ['pageSize', 'fontFamily'],
  versions: () => ({ configurationSchemaVersion: 1, layoutVersion: 1, rendererVersion: 1 }),
  summary: (config) => `${config.content.questionCount} multiplication questions`,
});

This example assumes a separately implemented and validated multiplicationGenerator. See tests/fixtures/multiplication-plugin.ts for an executable version with a different question structure and configuration schema.

Register a worksheet

  1. Create its module in packages/generators/src. Compose the shared schemas with its own content schema, and supply complete defaults and control metadata.
  2. Implement ResourceGenerator<Config, Content, Question>. Question data need only extend ResourceQuestion with an ID and sequence number; multiplication need not use subtraction's start, amount or result fields. Keep content generation deterministic and separate from layout.
  3. Call defineWorksheet with the generator and its editor rules. Use change for dependent setting updates, preset for educational defaults, prepare for a deliberate active-layout policy, and controlValue for derived display values. These rules belong to the plugin, not the shared store.
  4. Add the definition to the central createGeneratorRegistry call in packages/generators/src/index.ts.
  5. The route, discovery preview, common workspace, history, draft restore, reset actions, favourites and API resolve the registered definition. The API accepts the selected plugin's versions rather than a global list of subtraction versions.
  6. Controls render from metadata by default. Mark straightforward controls simple: true; advanced mode exposes the full set, grouped by section. If the type needs a richer editor, add its React component under apps/web/src/worksheets and register it in that folder's registry.tsx. Subtraction's learner presets and number-line shortcuts are an example of this isolated richer editor.

Every control path should identify a setting in that type's configuration. Reuse shared controls by composition; use different labels, bounds or sections in a new control definition where the worksheet needs them. Add a custom editor for a setting that cannot be expressed with the existing scalar controls. Avoid adding worksheet-specific branches to navigation, export or persistence.

Workspace and persistence

The workspace state carries generator ID and version beside configuration and seed. Switching routes selects the corresponding worksheet definition; resets and editing use that definition. newResource(id, true) requests allowlisted inheritance from the current worksheet. Ordinary creation uses saved teacher preferences and the selected type's defaults. Invalid or unsaved configurations block a type change until they can be saved or reset, so switching does not discard the current draft. New navigation cancels an outstanding type switch.

History and templates carry their generator identity and full configuration. The history reader resolves that generator, parses its schema and checks its configuration, layout and renderer versions. Drafts also include generator identity, so a multiplication draft cannot be restored as a subtraction configuration. Storage adapters remain behind repository interfaces.

Renderer and export receive semantic pages. They do not need to know whether the questions describe subtraction or multiplication. New visual primitives should be added to the shared semantic model and renderer when existing text, rules, rectangles, answer spaces and number lines are insufficient.

Verification

Run npm run typecheck, npm test, npm run test:e2e, npm run build and then npm run test:production for a change across these boundaries. Inspect representative exports visually when introducing a layout.

tests/worksheet-plugins.test.ts registers subtraction with the multiplication fixture in a separate test registry. It checks selective inheritance, independent defaults and controls, different question structures, type switching, resets, draft restore, mixed saved-resource handling and a real PDF export through the shared API. The fixture uses generator version 3 and schema version 17 to detect hidden assumptions about subtraction's version numbers. Keep fixtures out of the application registry until a production generator is complete.