@pie-players/pie-default-tool-loaders 0.3.74 → 1.0.0-beta.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.
Files changed (37) hide show
  1. package/README.md +116 -107
  2. package/dist/calculator-providers/CortexToolProvider.d.ts +0 -3
  3. package/dist/calculator-providers/CortexToolProvider.js +0 -14
  4. package/dist/calculator-providers/DesmosToolProvider.d.ts +0 -3
  5. package/dist/calculator-providers/DesmosToolProvider.js +0 -14
  6. package/dist/calculator-providers/GeoGebraToolProvider.d.ts +0 -3
  7. package/dist/calculator-providers/GeoGebraToolProvider.js +0 -14
  8. package/dist/calculator-providers/LazyCalculatorToolProvider.d.ts +3 -5
  9. package/dist/calculator-providers/LazyCalculatorToolProvider.js +1 -1
  10. package/dist/content-alternates.d.ts +1 -1
  11. package/dist/index.d.ts +3 -3
  12. package/dist/index.js +2 -2
  13. package/dist/packaged-capability-composition.d.ts +22 -50
  14. package/dist/packaged-capability-composition.js +61 -266
  15. package/dist/registrations/accessibility-tools.d.ts +1 -5
  16. package/dist/registrations/accessibility-tools.js +11 -49
  17. package/dist/registrations/audio-transcript.d.ts +8 -7
  18. package/dist/registrations/audio-transcript.js +12 -8
  19. package/dist/registrations/calculator.d.ts +2 -6
  20. package/dist/registrations/calculator.js +17 -39
  21. package/dist/registrations/dictionary-tools.d.ts +6 -5
  22. package/dist/registrations/dictionary-tools.js +21 -26
  23. package/dist/registrations/interaction-tools.d.ts +1 -7
  24. package/dist/registrations/interaction-tools.js +22 -30
  25. package/dist/registrations/measurement-tools.d.ts +1 -5
  26. package/dist/registrations/measurement-tools.js +1 -17
  27. package/dist/registrations/overlay-element-cache.d.ts +3 -1
  28. package/dist/registrations/overlay-element-cache.js +2 -1
  29. package/dist/registrations/overlay-toolbar-render.d.ts +9 -19
  30. package/dist/registrations/overlay-toolbar-render.js +9 -16
  31. package/dist/registrations/selection-actions.d.ts +1 -1
  32. package/dist/registrations/selection-actions.js +1 -1
  33. package/dist/registrations/subject-specific-tools.d.ts +1 -5
  34. package/dist/registrations/subject-specific-tools.js +1 -15
  35. package/dist/registrations/tts.d.ts +2 -8
  36. package/dist/registrations/tts.js +28 -99
  37. package/package.json +22 -23
@@ -2,49 +2,26 @@
2
2
  * The one authored description of PIE's packaged capability composition.
3
3
  *
4
4
  * Registrations describe what a capability can do. This module owns the
5
- * deployment decisions around them: element tags, lazy module bootstrap sets,
6
- * placement presets, toolbar order and the explicit universal-support policy.
5
+ * deployment decisions around them: element tags, lazy module loaders, the
6
+ * section-player placement preset and the explicit universal-support policy.
7
7
  * Public constants are projections of this composition so adding a capability
8
8
  * cannot leave a second hand-maintained catalogue silently behind.
9
9
  */
10
- import { ToolRegistry, } from "@pie-players/pie-assessment-toolkit/tools/internal";
10
+ import { ToolRegistry, } from "@pie-players/pie-assessment-toolkit/tools/registration";
11
11
  import { annotationToolbarRegistration, lineReaderToolRegistration, themeToolRegistration, } from "./registrations/accessibility-tools.js";
12
12
  import { audioTranscriptRegistration } from "./registrations/audio-transcript.js";
13
- import { calculatorToolRegistration, resolveCalculatorProviderId, } from "./registrations/calculator.js";
13
+ import { calculatorToolRegistration } from "./registrations/calculator.js";
14
14
  import { dictionaryToolRegistration, pictureDictionaryToolRegistration, spanishDictionaryToolRegistration, spanishPictureDictionaryToolRegistration, } from "./registrations/dictionary-tools.js";
15
15
  import { answerEliminatorToolRegistration } from "./registrations/interaction-tools.js";
16
16
  import { protractorToolRegistration, rulerToolRegistration, } from "./registrations/measurement-tools.js";
17
17
  import { graphToolRegistration, periodicTableToolRegistration, } from "./registrations/subject-specific-tools.js";
18
18
  import { ttsToolRegistration } from "./registrations/tts.js";
19
19
  const loadSideEffectModule = (load) => load().then(() => undefined);
20
- function loadCalculatorElement(tagName, load) {
21
- if (typeof globalThis !== "undefined" &&
22
- "customElements" in globalThis &&
23
- globalThis.customElements?.get(tagName)) {
24
- return Promise.resolve();
25
- }
26
- return loadSideEffectModule(load);
27
- }
28
- const loadDesmosCalculatorModule = () => loadCalculatorElement("pie-tool-calculator", () => import("@pie-players/pie-tool-calculator-shared/calculator-element"));
29
- const loadGeoGebraCalculatorModule = () => loadCalculatorElement("pie-tool-calculator-geogebra", () => import("@pie-players/pie-tool-calculator-geogebra"));
30
- const loadCortexCalculatorModule = () => loadCalculatorElement("pie-tool-calculator-cortex", () => import("@pie-players/pie-tool-calculator-cortex"));
31
- const CALCULATOR_DELIVERY = {
32
- "calculator-desmos": {
33
- tagName: "pie-tool-calculator",
34
- loadModule: loadDesmosCalculatorModule,
35
- },
36
- "calculator-geogebra": {
37
- tagName: "pie-tool-calculator-geogebra",
38
- loadModule: loadGeoGebraCalculatorModule,
39
- },
40
- "calculator-cortex": {
41
- tagName: "pie-tool-calculator-cortex",
42
- loadModule: loadCortexCalculatorModule,
43
- },
44
- };
45
- function resolveCalculatorDelivery(config) {
46
- return CALCULATOR_DELIVERY[resolveCalculatorProviderId(config)];
47
- }
20
+ // One element serves every calculator provider; the toolkit picks the provider
21
+ // from `tools.providers.calculator` when the element mounts.
22
+ const loadCalculatorModule = () => globalThis.customElements?.get("pie-tool-calculator")
23
+ ? Promise.resolve()
24
+ : loadSideEffectModule(() => import("@pie-players/pie-tool-calculator-shared/calculator-element"));
48
25
  const loadTtsModule = () => loadSideEffectModule(() => import("@pie-players/pie-tool-tts-inline"));
49
26
  const loadRulerModule = () => loadSideEffectModule(() => import("@pie-players/pie-tool-ruler"));
50
27
  const loadProtractorModule = () => loadSideEffectModule(() => import("@pie-players/pie-tool-protractor"));
@@ -59,133 +36,89 @@ const loadPictureDictionaryModule = () => loadSideEffectModule(() => import("@pi
59
36
  const PACKAGED_CAPABILITY_DEFINITIONS = [
60
37
  {
61
38
  registration: calculatorToolRegistration,
62
- tagName: CALCULATOR_DELIVERY["calculator-desmos"].tagName,
63
- loadModule: CALCULATOR_DELIVERY["calculator-desmos"].loadModule,
64
- loaderTargets: ["item", "section"],
65
- placementOrder: { element: 10 },
39
+ tagName: "pie-tool-calculator",
40
+ loadModule: loadCalculatorModule,
66
41
  preferredPlacementOrder: { item: 10 },
67
- toolbarOrder: 20,
68
- universalSupportIds: ["calculator", "graphingCalculator"],
42
+ universal: true,
69
43
  },
70
44
  {
71
45
  registration: ttsToolRegistration,
72
46
  tagName: "pie-tool-tts-inline",
73
47
  loadModule: loadTtsModule,
74
- loaderTargets: ["item"],
75
- placementOrder: { item: 10, passage: 10, rubric: 10, element: 30 },
76
48
  preferredPlacementOrder: { item: 20, passage: 10 },
77
- toolbarOrder: 30,
78
- universalSupportIds: ["textToSpeech", "readAloud"],
49
+ universal: true,
79
50
  },
80
51
  {
81
52
  registration: rulerToolRegistration,
82
53
  tagName: "pie-tool-ruler",
83
54
  loadModule: loadRulerModule,
84
- loaderTargets: ["section"],
85
- placementOrder: { element: 40 },
86
55
  preferredPlacementOrder: { section: 50 },
87
- toolbarOrder: 80,
88
- universalSupportIds: ["ruler"],
56
+ universal: true,
89
57
  },
90
58
  {
91
59
  registration: protractorToolRegistration,
92
60
  tagName: "pie-tool-protractor",
93
61
  loadModule: loadProtractorModule,
94
- loaderTargets: ["section"],
95
- placementOrder: { element: 50 },
96
62
  preferredPlacementOrder: { section: 60 },
97
- toolbarOrder: 90,
98
- universalSupportIds: ["protractor"],
63
+ universal: true,
99
64
  },
100
65
  {
101
66
  registration: answerEliminatorToolRegistration,
102
67
  tagName: "pie-tool-answer-eliminator",
103
68
  loadModule: loadAnswerEliminatorModule,
104
- loaderTargets: ["item"],
105
- placementOrder: { element: 20 },
106
69
  preferredPlacementOrder: { item: 30 },
107
- toolbarOrder: 70,
108
- universalSupportIds: ["answerMasking", "answerEliminator", "strikethrough"],
70
+ universal: true,
109
71
  },
110
72
  {
111
73
  registration: lineReaderToolRegistration,
112
74
  tagName: "pie-tool-line-reader",
113
75
  loadModule: loadLineReaderModule,
114
- loaderTargets: ["section"],
115
- placementOrder: { passage: 40, rubric: 40 },
116
76
  preferredPlacementOrder: { section: 40 },
117
- toolbarOrder: 40,
118
- universalSupportIds: ["readingMask", "readingGuide", "readingRuler"],
77
+ universal: true,
119
78
  },
120
79
  {
121
80
  registration: themeToolRegistration,
122
81
  tagName: "pie-tool-theme",
123
82
  loadModule: loadThemeModule,
124
- loaderTargets: ["item"],
125
- placementOrder: { assessment: 10, section: 10 },
126
83
  preferredPlacementOrder: { section: 10 },
127
- toolbarOrder: 10,
128
- universalSupportIds: [
129
- "highContrastDisplay",
130
- "colorContrast",
131
- "invertColors",
132
- "theme",
133
- ],
84
+ universal: true,
134
85
  },
135
86
  {
136
87
  registration: annotationToolbarRegistration,
137
88
  tagName: "pie-tool-annotation-toolbar",
138
89
  loadModule: loadAnnotationToolbarModule,
139
- loaderTargets: ["item"],
140
- placementOrder: { item: 30, passage: 30, rubric: 30, element: 70 },
141
90
  preferredPlacementOrder: { item: 40, passage: 20 },
142
- toolbarOrder: 50,
143
- // The last three came from the `highlighter` capability, which mounted this
144
- // same element behind a second identically-labelled button. Kept here so a
145
- // profile granted one of the older ids still gets highlighting.
146
- universalSupportIds: ["highlighting", "annotations"],
91
+ universal: true,
147
92
  },
148
93
  {
149
94
  registration: graphToolRegistration,
150
95
  tagName: "pie-tool-graph",
151
96
  loadModule: loadGraphModule,
152
- loaderTargets: ["section"],
153
- placementOrder: { item: 40, element: 80 },
154
97
  preferredPlacementOrder: { section: 20 },
155
- toolbarOrder: 100,
156
- universalSupportIds: ["graph"],
98
+ universal: true,
157
99
  },
158
100
  {
159
101
  registration: periodicTableToolRegistration,
160
102
  tagName: "pie-tool-periodic-table",
161
103
  loadModule: loadPeriodicTableModule,
162
- loaderTargets: ["section"],
163
- placementOrder: { item: 50, element: 90 },
164
104
  preferredPlacementOrder: { section: 30 },
165
- toolbarOrder: 110,
166
- universalSupportIds: ["periodicTable"],
105
+ universal: true,
167
106
  },
168
107
  {
169
108
  registration: dictionaryToolRegistration,
170
109
  tagName: "pie-tool-dictionary",
171
110
  loadModule: loadDictionaryModule,
172
- loaderTargets: ["section"],
173
- placementOrder: { item: 60, element: 100 },
174
111
  preferredPlacementOrder: { section: 70 },
175
- toolbarOrder: 120,
176
- // Deliberately empty: a dictionary is a granted accommodation, and on a
177
- // vocabulary item it is construct-relevant, so it is never universal.
178
- universalSupportIds: [],
112
+ // A dictionary is a granted accommodation, and on a vocabulary item it is
113
+ // construct-relevant, so it is never universal.
114
+ universal: false,
179
115
  },
180
116
  {
181
117
  registration: pictureDictionaryToolRegistration,
182
118
  tagName: "pie-tool-picture-dictionary",
183
119
  loadModule: loadPictureDictionaryModule,
184
- loaderTargets: ["section"],
185
- placementOrder: { item: 70, element: 110 },
186
120
  preferredPlacementOrder: { section: 80 },
187
- toolbarOrder: 130,
188
- universalSupportIds: [],
121
+ universal: false,
189
122
  },
190
123
  // The Spanish variants render the same elements under their own capability ids, so a
191
124
  // programme can grant a Spanish gloss beside the content-following dictionary or
@@ -194,35 +127,21 @@ const PACKAGED_CAPABILITY_DEFINITIONS = [
194
127
  registration: spanishDictionaryToolRegistration,
195
128
  tagName: "pie-tool-dictionary",
196
129
  loadModule: loadDictionaryModule,
197
- loaderTargets: ["section"],
198
- placementOrder: { item: 80, element: 120 },
199
130
  preferredPlacementOrder: { section: 90 },
200
- toolbarOrder: 140,
201
- universalSupportIds: [],
131
+ universal: false,
202
132
  },
203
133
  {
204
134
  registration: spanishPictureDictionaryToolRegistration,
205
135
  tagName: "pie-tool-picture-dictionary",
206
136
  loadModule: loadPictureDictionaryModule,
207
- loaderTargets: ["section"],
208
- placementOrder: { item: 90, element: 130 },
209
137
  preferredPlacementOrder: { section: 100 },
210
- toolbarOrder: 150,
211
- universalSupportIds: [],
138
+ universal: false,
212
139
  },
213
140
  {
214
141
  registration: audioTranscriptRegistration,
215
- universalSupportIds: [],
142
+ universal: false,
216
143
  },
217
144
  ];
218
- const PACKAGED_PLACEMENT_LEVELS = [
219
- "assessment",
220
- "section",
221
- "item",
222
- "passage",
223
- "rubric",
224
- "element",
225
- ];
226
145
  const PREFERRED_PLACEMENT_LEVELS = ["section", "item", "passage"];
227
146
  function assertUniqueWeights(definitions, levels, read, field) {
228
147
  for (const level of levels) {
@@ -243,8 +162,6 @@ function assertUniqueWeights(definitions, levels, read, field) {
243
162
  }
244
163
  function assertComposition(definitions) {
245
164
  const toolIds = new Set();
246
- const universalSupportIds = new Set();
247
- const toolbarOrders = new Set();
248
165
  for (const definition of definitions) {
249
166
  const { registration } = definition;
250
167
  if (!registration.toolId.trim()) {
@@ -258,9 +175,6 @@ function assertComposition(definitions) {
258
175
  if (isRegion) {
259
176
  if (definition.tagName !== undefined ||
260
177
  definition.loadModule !== undefined ||
261
- definition.loaderTargets !== undefined ||
262
- definition.toolbarOrder !== undefined ||
263
- Object.keys(definition.placementOrder ?? {}).length > 0 ||
264
178
  Object.keys(definition.preferredPlacementOrder ?? {}).length > 0) {
265
179
  throw new Error(`Invalid packaged capability "${registration.toolId}": a region capability is surface-hosted and cannot declare element delivery or toolbar placement.`);
266
180
  }
@@ -269,44 +183,12 @@ function assertComposition(definitions) {
269
183
  if (!definition.tagName?.includes("-")) {
270
184
  throw new Error(`Invalid packaged capability "${registration.toolId}": element-backed capabilities need a custom-element tag.`);
271
185
  }
272
- if (typeof definition.loadModule !== "function" ||
273
- !definition.loaderTargets?.length) {
274
- throw new Error(`Invalid packaged capability "${registration.toolId}": element-backed capabilities need a lazy loader and at least one bootstrap target.`);
275
- }
276
- if (new Set(definition.loaderTargets).size !==
277
- definition.loaderTargets.length) {
278
- throw new Error(`Invalid packaged capability "${registration.toolId}": loader bootstrap targets must be unique.`);
186
+ if (typeof definition.loadModule !== "function") {
187
+ throw new Error(`Invalid packaged capability "${registration.toolId}": element-backed capabilities need a lazy loader.`);
279
188
  }
280
- if (definition.toolbarOrder === undefined) {
281
- throw new Error(`Invalid packaged capability "${registration.toolId}": toolbar capabilities need an order.`);
282
- }
283
- }
284
- if (definition.toolbarOrder !== undefined) {
285
- if (!Number.isSafeInteger(definition.toolbarOrder) ||
286
- definition.toolbarOrder < 0) {
287
- throw new Error(`Invalid packaged capability "${registration.toolId}": toolbar order must be a non-negative integer.`);
288
- }
289
- if (toolbarOrders.has(definition.toolbarOrder)) {
290
- throw new Error(`Invalid packaged capability composition: duplicate toolbar order ${definition.toolbarOrder}.`);
291
- }
292
- toolbarOrders.add(definition.toolbarOrder);
293
189
  }
294
- const registrationSupportIds = new Set(registration.pnpSupportIds ?? [registration.toolId]);
295
- if (registration.requiresAuthoredContent &&
296
- definition.universalSupportIds.length > 0) {
297
- throw new Error(`Invalid packaged capability "${registration.toolId}": content-dependent support ids cannot be universally granted.`);
298
- }
299
- for (const supportId of definition.universalSupportIds) {
300
- if (!supportId.trim()) {
301
- throw new Error(`Invalid packaged capability "${registration.toolId}": universal support ids must be non-empty.`);
302
- }
303
- if (!registrationSupportIds.has(supportId)) {
304
- throw new Error(`Invalid packaged capability "${registration.toolId}": universal support id "${supportId}" is not declared by its registration.`);
305
- }
306
- if (universalSupportIds.has(supportId)) {
307
- throw new Error(`Invalid packaged capability composition: universal support id "${supportId}" has more than one owner.`);
308
- }
309
- universalSupportIds.add(supportId);
190
+ if (registration.requiresAuthoredContent && definition.universal) {
191
+ throw new Error(`Invalid packaged capability "${registration.toolId}": a content-dependent capability cannot be universally granted.`);
310
192
  }
311
193
  for (const level of PREFERRED_PLACEMENT_LEVELS) {
312
194
  if (definition.preferredPlacementOrder?.[level] !== undefined &&
@@ -315,7 +197,6 @@ function assertComposition(definitions) {
315
197
  }
316
198
  }
317
199
  }
318
- assertUniqueWeights(definitions, PACKAGED_PLACEMENT_LEVELS, (definition) => definition.placementOrder, "placementOrder");
319
200
  assertUniqueWeights(definitions, PREFERRED_PLACEMENT_LEVELS, (definition) => definition.preferredPlacementOrder, "preferredPlacementOrder");
320
201
  }
321
202
  function orderedToolIds(definitions, level, read) {
@@ -331,12 +212,8 @@ class PackagedCapabilityComposition {
331
212
  definitions;
332
213
  registrations;
333
214
  toolTagMap;
334
- itemModuleLoaders;
335
- sectionModuleLoaders;
336
- defaultModuleLoaders;
337
- placement;
215
+ moduleLoaders;
338
216
  preferredPlacement;
339
- toolbarOrder;
340
217
  universalSupportIds;
341
218
  constructor(definitions) {
342
219
  this.definitions = definitions;
@@ -344,34 +221,20 @@ class PackagedCapabilityComposition {
344
221
  this.toolTagMap = Object.freeze(Object.fromEntries(definitions.flatMap((definition) => definition.tagName
345
222
  ? [[definition.registration.toolId, definition.tagName]]
346
223
  : [])));
347
- this.itemModuleLoaders = this.projectModuleLoaders("item");
348
- this.sectionModuleLoaders = this.projectModuleLoaders("section");
349
- this.defaultModuleLoaders = Object.freeze({
350
- ...this.itemModuleLoaders,
351
- ...this.sectionModuleLoaders,
224
+ this.moduleLoaders = Object.freeze(Object.fromEntries(definitions.flatMap((definition) => definition.loadModule
225
+ ? [[definition.registration.toolId, definition.loadModule]]
226
+ : [])));
227
+ const preferredIds = (level) => Object.freeze(orderedToolIds(definitions, level, ({ preferredPlacementOrder }) => preferredPlacementOrder));
228
+ this.preferredPlacement = Object.freeze({
229
+ section: preferredIds("section"),
230
+ item: preferredIds("item"),
231
+ passage: preferredIds("passage"),
352
232
  });
353
- this.placement = Object.freeze(Object.fromEntries(PACKAGED_PLACEMENT_LEVELS.map((level) => [
354
- level,
355
- Object.freeze(orderedToolIds(definitions, level, (definition) => definition.placementOrder)),
356
- ])));
357
- this.preferredPlacement = Object.freeze(Object.fromEntries(PREFERRED_PLACEMENT_LEVELS.map((level) => [
358
- level,
359
- Object.freeze(orderedToolIds(definitions, level, (definition) => definition.preferredPlacementOrder)),
360
- ])));
361
- this.toolbarOrder = Object.freeze(definitions
362
- .filter((definition) => definition.toolbarOrder !== undefined)
363
- .slice()
364
- .sort((left, right) => left.toolbarOrder - right.toolbarOrder)
365
- .map(({ registration }) => registration.toolId));
366
233
  this.universalSupportIds = Object.freeze(definitions
367
- .flatMap(({ universalSupportIds }) => [...universalSupportIds])
234
+ .filter((definition) => definition.universal)
235
+ .map(({ registration }) => registration.toolId)
368
236
  .sort());
369
237
  }
370
- projectModuleLoaders(target) {
371
- return Object.freeze(Object.fromEntries(this.definitions.flatMap((definition) => definition.loadModule && definition.loaderTargets?.includes(target)
372
- ? [[definition.registration.toolId, definition.loadModule]]
373
- : [])));
374
- }
375
238
  selectRegistrations(toolIds) {
376
239
  // Preserve the established fail-soft host behavior: no selection means all,
377
240
  // and unknown ids are ignored rather than preventing known tools from loading.
@@ -380,46 +243,19 @@ class PackagedCapabilityComposition {
380
243
  const selected = new Set(toolIds);
381
244
  return this.registrations.filter(({ toolId }) => selected.has(toolId));
382
245
  }
383
- registerTools(registry, options = {}) {
384
- const applyOverrides = options.applyOverrides ??
385
- ((registration) => registration);
386
- for (const registration of this.selectRegistrations(options.toolIds)) {
387
- registry.register(applyOverrides(registration));
388
- }
389
- }
390
246
  createRegistry(options = {}) {
391
247
  const registry = new ToolRegistry();
392
- this.registerTools(registry, {
393
- toolIds: options.toolIds,
394
- applyOverrides: (registration) => options.overrides?.[registration.toolId] ?? registration,
395
- });
396
- // Loader installation remains opt-in. Some hosts preload tool elements or
397
- // provide their own tags; silently adding package loads here would change
398
- // their bundle/runtime behavior.
399
- if (options.toolModuleLoaders &&
400
- Object.keys(options.toolModuleLoaders).length > 0) {
401
- const toolModuleLoaders = { ...options.toolModuleLoaders };
402
- const calculatorDelivery = resolveCalculatorDelivery(options.calculatorProviderConfig);
403
- // A host using the packaged default map gets a coherent provider-specific
404
- // loader. A genuinely custom calculator loader remains the host's override.
405
- if (options.calculatorProviderConfig &&
406
- toolModuleLoaders.calculator === this.defaultModuleLoaders.calculator) {
407
- toolModuleLoaders.calculator = calculatorDelivery.loadModule;
408
- }
409
- registry.setToolModuleLoaders(toolModuleLoaders);
248
+ for (const registration of this.selectRegistrations(options.toolIds)) {
249
+ registry.register(options.overrides?.[registration.toolId] ?? registration);
410
250
  }
411
- const calculatorTagMap = options.calculatorProviderConfig
412
- ? {
413
- calculator: resolveCalculatorDelivery(options.calculatorProviderConfig).tagName,
414
- }
415
- : {};
251
+ registry.setToolModuleLoaders({
252
+ ...(options.toolModuleLoaders ?? this.moduleLoaders),
253
+ });
416
254
  registry.setComponentOverrides({
417
255
  toolTagMap: {
418
256
  ...this.toolTagMap,
419
- ...calculatorTagMap,
420
257
  ...(options.toolTagMap ?? {}),
421
258
  },
422
- toolComponentFactory: options.toolComponentFactory,
423
259
  toolComponentFactories: options.toolComponentFactories,
424
260
  });
425
261
  return registry;
@@ -428,7 +264,6 @@ class PackagedCapabilityComposition {
428
264
  return {
429
265
  supports: [...this.universalSupportIds],
430
266
  prohibitedSupports: [],
431
- activateAtInit: [],
432
267
  };
433
268
  }
434
269
  }
@@ -450,71 +285,31 @@ export const PACKAGED_TOOL_REGISTRATIONS = [
450
285
  export const PACKAGED_TOOL_TAG_MAP = {
451
286
  ...packagedCapabilityComposition.toolTagMap,
452
287
  };
453
- export const ITEM_TOOL_MODULE_LOADERS = {
454
- ...packagedCapabilityComposition.itemModuleLoaders,
455
- };
456
- export const SECTION_TOOL_MODULE_LOADERS = {
457
- ...packagedCapabilityComposition.sectionModuleLoaders,
458
- };
459
288
  export const DEFAULT_TOOL_MODULE_LOADERS = {
460
- ...packagedCapabilityComposition.defaultModuleLoaders,
461
- };
462
- /** Build the packaged loader map for a selected calculator provider. */
463
- export function createDefaultToolModuleLoaders(options = {}) {
464
- return {
465
- ...DEFAULT_TOOL_MODULE_LOADERS,
466
- calculator: resolveCalculatorDelivery(options.calculatorProviderConfig)
467
- .loadModule,
468
- };
469
- }
470
- /** Build the section-bootstrap loader subset for a selected calculator provider. */
471
- export function createSectionToolModuleLoaders(options = {}) {
472
- return {
473
- ...SECTION_TOOL_MODULE_LOADERS,
474
- calculator: resolveCalculatorDelivery(options.calculatorProviderConfig)
475
- .loadModule,
476
- };
477
- }
478
- export const PACKAGED_TOOL_PLACEMENT = {
479
- assessment: [...packagedCapabilityComposition.placement.assessment],
480
- section: [...packagedCapabilityComposition.placement.section],
481
- item: [...packagedCapabilityComposition.placement.item],
482
- passage: [...packagedCapabilityComposition.placement.passage],
483
- rubric: [...packagedCapabilityComposition.placement.rubric],
484
- element: [...packagedCapabilityComposition.placement.element],
289
+ ...packagedCapabilityComposition.moduleLoaders,
485
290
  };
486
291
  export const SECTION_PLAYER_PREFERRED_TOOL_PLACEMENT = {
487
292
  section: [...packagedCapabilityComposition.preferredPlacement.section],
488
293
  item: [...packagedCapabilityComposition.preferredPlacement.item],
489
294
  passage: [...packagedCapabilityComposition.preferredPlacement.passage],
490
295
  };
491
- export const PACKAGED_TOOL_ORDER = [
492
- ...packagedCapabilityComposition.toolbarOrder,
493
- ];
494
- export const UNIVERSAL_SUPPORTS_PRESET = packagedCapabilityComposition.universalSupportIds;
495
- /** Register packaged PIE capabilities onto an existing registry. */
496
- export function registerPackagedTools(registry, options = {}) {
497
- packagedCapabilityComposition.registerTools(registry, options);
498
- }
499
296
  /** Create a registry holding the packaged PIE capabilities. */
500
297
  export function createPackagedToolRegistry(options = {}) {
501
298
  return packagedCapabilityComposition.createRegistry(options);
502
299
  }
503
- /** Build a fresh profile granting the explicit universal-support preset. */
300
+ /**
301
+ * A fresh profile granting the packaged set's universal capabilities, sorted by
302
+ * tool id. Which capabilities are universal is program policy declared on each
303
+ * definition; registry membership never implies it.
304
+ */
504
305
  export function createUniversalPersonalNeedsProfile() {
505
306
  return packagedCapabilityComposition.createUniversalPersonalNeedsProfile();
506
307
  }
507
- /** Register packaged lazy module loaders, followed by host overrides. */
508
- export function registerDefaultToolModuleLoaders(registry, options = {}) {
509
- registry.setToolModuleLoaders({
510
- ...createDefaultToolModuleLoaders(options),
511
- ...(options.loaders ?? {}),
512
- });
513
- }
514
- /** Register only the section-bootstrap loader subset, then host overrides. */
515
- export function registerSectionToolModuleLoaders(registry, options = {}) {
516
- registry.setToolModuleLoaders({
517
- ...createSectionToolModuleLoaders(options),
518
- ...(options.loaders ?? {}),
519
- });
308
+ /**
309
+ * A fresh profile granting and prohibiting nothing. The toolkit ships no
310
+ * populated default: a deployment's universal set is program policy, which
311
+ * `createUniversalPersonalNeedsProfile` carries as data for hosts that adopt it.
312
+ */
313
+ export function createEmptyPersonalNeedsProfile() {
314
+ return { supports: [], prohibitedSupports: [] };
520
315
  }
@@ -5,12 +5,8 @@
5
5
  * - Line Reader (reading guide)
6
6
  * - Color Scheme (theme/contrast)
7
7
  * - Annotation Toolbar (text highlighting)
8
- *
9
- * Maps to QTI 3.0 standard access features from:
10
- * - visual category: highContrastDisplay, colorContrast
11
- * - reading category: readingMask, readingGuide, highlighting
12
8
  */
13
- import type { ToolRegistration } from "@pie-players/pie-assessment-toolkit/tools/internal";
9
+ import type { ToolRegistration } from "@pie-players/pie-assessment-toolkit/tools/registration";
14
10
  /**
15
11
  * Line Reader tool registration
16
12
  *
@@ -5,13 +5,9 @@
5
5
  * - Line Reader (reading guide)
6
6
  * - Color Scheme (theme/contrast)
7
7
  * - Annotation Toolbar (text highlighting)
8
- *
9
- * Maps to QTI 3.0 standard access features from:
10
- * - visual category: highContrastDisplay, colorContrast
11
- * - reading category: readingMask, readingGuide, highlighting
12
8
  */
13
- import { hasReadableText } from "@pie-players/pie-assessment-toolkit/tools/internal";
14
- import { resolveToolTag, } from "@pie-players/pie-assessment-toolkit/tools/internal";
9
+ import { hasReadableText } from "@pie-players/pie-assessment-toolkit/tools/registration";
10
+ import { resolveToolTag, } from "@pie-players/pie-assessment-toolkit/tools/registration";
15
11
  import { buildSelectionActions } from "./selection-actions.js";
16
12
  import { renderOverlayToolbar } from "./overlay-toolbar-render.js";
17
13
  /**
@@ -27,15 +23,7 @@ export const lineReaderToolRegistration = {
27
23
  nameKey: "tools.lineReader.name",
28
24
  descriptionKey: "tools.lineReader.description",
29
25
  icon: "bars-3",
30
- // Line reader appears where there's text to read
31
26
  supportedLevels: ["section", "passage", "rubric", "item"],
32
- // PNP support IDs
33
- // Maps to QTI 3.0 standard features: readingMask, readingGuide, readingRuler
34
- pnpSupportIds: [
35
- "readingMask", // QTI 3.0 standard (reading.readingMask)
36
- "readingGuide", // QTI 3.0 standard (reading.readingGuide)
37
- "readingRuler", // QTI 3.0 standard (reading.readingRuler)
38
- ],
39
27
  /**
40
28
  * Pass 2: Line reader is relevant when readable text is present
41
29
  */
@@ -45,7 +33,6 @@ export const lineReaderToolRegistration = {
45
33
  renderToolbar(context, toolbarContext) {
46
34
  return renderOverlayToolbar(this, context, toolbarContext, {
47
35
  surface: "frameless",
48
- handsOverCoordinator: true,
49
36
  });
50
37
  },
51
38
  };
@@ -64,19 +51,11 @@ export const themeToolRegistration = {
64
51
  icon: "swatch",
65
52
  // Color scheme is assessment-wide
66
53
  supportedLevels: ["assessment", "section"],
67
- // PNP support IDs
68
- // Maps to QTI 3.0 standard features: highContrastDisplay, colorContrast, invertColors
69
- pnpSupportIds: [
70
- "highContrastDisplay", // QTI 3.0 standard (visual.highContrastDisplay)
71
- "colorContrast", // QTI 3.0 standard (visual.colorContrast)
72
- "invertColors", // QTI 3.0 standard (visual.invertColors)
73
- "theme", // Canonical id, and this registration's toolId
74
- ],
75
54
  /**
76
55
  * Pass 2: Color scheme is always relevant when allowed
77
56
  */
78
57
  isVisibleInContext(context) {
79
- return true; // Always show if allowed by orchestrator
58
+ return true;
80
59
  },
81
60
  renderToolbar(context, toolbarContext) {
82
61
  return renderOverlayToolbar(this, context, toolbarContext, {
@@ -87,7 +66,6 @@ export const themeToolRegistration = {
87
66
  minWidth: 420,
88
67
  minHeight: 300,
89
68
  },
90
- handsOverCoordinator: true,
91
69
  });
92
70
  },
93
71
  };
@@ -107,22 +85,13 @@ export const annotationToolbarRegistration = {
107
85
  activation: "selection-gateway",
108
86
  singletonScope: "section",
109
87
  /**
110
- * Section-scoped singleton surface. The gateway used to be mounted by
111
- * `PieSectionPlayerBaseElement.svelte`, which named this tool id in three
112
- * places — the policy check, the module load and the element — so no host
113
- * could contribute a second section-scoped capability. Declaring the surface
114
- * moves that wiring into this registration, and the renderer discovers it
115
- * through `ToolRegistry.getToolsBySurface("section-overlay")`.
88
+ * Section-scoped singleton surface. The renderer discovers it through
89
+ * `ToolRegistry.getToolsBySurface("section-overlay")`, so the section player
90
+ * names no tool id and a host can contribute another section-scoped
91
+ * capability.
116
92
  */
117
93
  surfaces: ["section-overlay"],
118
- // Annotation appears where there's text content
119
94
  supportedLevels: ["passage", "rubric", "item", "element"],
120
- // PNP support IDs
121
- // Maps to QTI 3.0 standard features: highlighting, annotations
122
- pnpSupportIds: [
123
- "highlighting", // QTI 3.0 standard (cognitive.highlighting / reading.wordHighlighting)
124
- "annotations", // QTI 3.0 standard (cognitive.annotations)
125
- ],
126
95
  /**
127
96
  * Pass 2: Annotation is relevant when readable text is present
128
97
  */
@@ -145,16 +114,11 @@ export const annotationToolbarRegistration = {
145
114
  return null;
146
115
  }
147
116
  const element = document.createElement(tagName);
148
- // Reads the context it is handed. These were reactive props before the
149
- // gateway moved behind `renderSurface`, and a host calling
150
- // `updateAssessment(...)` mid-session swaps the coordinator without
151
- // remounting — closing over the render-time services would leave the gateway
152
- // highlighting into the previous session's coordinator.
117
+ // The gateway reads its services from the toolkit runtime context. What it
118
+ // takes from here is the action list, rebuilt from the current services on
119
+ // every sync so a mid-session `updateAssessment(...)` reaches it.
153
120
  const applyServices = (current) => {
154
121
  element.enabled = true;
155
- element.ttsService = current.services.ttsService;
156
- element.highlightCoordinator =
157
- current.services.toolkitCoordinator?.highlightCoordinator ?? null;
158
122
  // The second door onto the dictionaries. The gateway renders these and
159
123
  // knows nothing of what they open; the pairing is composition's, which is
160
124
  // why the list is built in `selection-actions.ts` and not here.
@@ -164,8 +128,6 @@ export const annotationToolbarRegistration = {
164
128
  return { element, sync: applyServices };
165
129
  },
166
130
  renderToolbar(context, toolbarContext) {
167
- return renderOverlayToolbar(this, context, toolbarContext, {
168
- handsOverCoordinator: true,
169
- });
131
+ return renderOverlayToolbar(this, context, toolbarContext);
170
132
  },
171
133
  };