@pie-players/pie-default-tool-loaders 0.3.73 → 0.3.75

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 (45) hide show
  1. package/README.md +56 -58
  2. package/dist/calculator-providers/CortexToolProvider.d.ts +12 -0
  3. package/dist/calculator-providers/CortexToolProvider.js +31 -0
  4. package/dist/calculator-providers/DesmosToolProvider.d.ts +13 -0
  5. package/dist/calculator-providers/DesmosToolProvider.js +31 -0
  6. package/dist/calculator-providers/GeoGebraToolProvider.d.ts +15 -0
  7. package/dist/calculator-providers/GeoGebraToolProvider.js +31 -0
  8. package/dist/calculator-providers/LazyCalculatorToolProvider.d.ts +34 -0
  9. package/dist/calculator-providers/LazyCalculatorToolProvider.js +95 -0
  10. package/dist/content-alternates.d.ts +1 -1
  11. package/dist/index.d.ts +2 -2
  12. package/dist/index.js +1 -1
  13. package/dist/packaged-capability-composition.d.ts +17 -49
  14. package/dist/packaged-capability-composition.js +61 -262
  15. package/dist/registrations/accessibility-tools.d.ts +1 -5
  16. package/dist/registrations/accessibility-tools.js +6 -41
  17. package/dist/registrations/audio-transcript.d.ts +1 -1
  18. package/dist/registrations/audio-transcript.js +0 -1
  19. package/dist/registrations/calculator.d.ts +2 -6
  20. package/dist/registrations/calculator.js +18 -73
  21. package/dist/registrations/dictionary-tools.d.ts +6 -5
  22. package/dist/registrations/dictionary-tools.js +23 -27
  23. package/dist/registrations/interaction-tools.d.ts +1 -7
  24. package/dist/registrations/interaction-tools.js +24 -28
  25. package/dist/registrations/measurement-tools.d.ts +1 -5
  26. package/dist/registrations/measurement-tools.js +1 -19
  27. package/dist/registrations/overlay-element-cache.d.ts +23 -0
  28. package/dist/registrations/overlay-element-cache.js +48 -0
  29. package/dist/registrations/overlay-toolbar-render.d.ts +3 -10
  30. package/dist/registrations/overlay-toolbar-render.js +5 -8
  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 +3 -8
  34. package/dist/registrations/subject-specific-tools.js +10 -26
  35. package/dist/registrations/tts.d.ts +1 -6
  36. package/dist/registrations/tts.js +41 -90
  37. package/package.json +24 -21
  38. package/dist/packaged-tool-registry.d.ts +0 -2
  39. package/dist/packaged-tool-registry.js +0 -1
  40. package/dist/tool-placement.d.ts +0 -1
  41. package/dist/tool-placement.js +0 -1
  42. package/dist/tool-tag-map.d.ts +0 -1
  43. package/dist/tool-tag-map.js +0 -1
  44. package/dist/universal-supports.d.ts +0 -1
  45. package/dist/universal-supports.js +0 -1
@@ -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
- tagName: "pie-tool-text-to-speech",
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,23 @@ 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
- });
248
+ for (const registration of this.selectRegistrations(options.toolIds)) {
249
+ registry.register(options.overrides?.[registration.toolId] ?? registration);
250
+ }
396
251
  // Loader installation remains opt-in. Some hosts preload tool elements or
397
252
  // provide their own tags; silently adding package loads here would change
398
253
  // their bundle/runtime behavior.
399
254
  if (options.toolModuleLoaders &&
400
255
  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);
256
+ registry.setToolModuleLoaders({ ...options.toolModuleLoaders });
410
257
  }
411
- const calculatorTagMap = options.calculatorProviderConfig
412
- ? {
413
- calculator: resolveCalculatorDelivery(options.calculatorProviderConfig).tagName,
414
- }
415
- : {};
416
258
  registry.setComponentOverrides({
417
259
  toolTagMap: {
418
260
  ...this.toolTagMap,
419
- ...calculatorTagMap,
420
261
  ...(options.toolTagMap ?? {}),
421
262
  },
422
- toolComponentFactory: options.toolComponentFactory,
423
263
  toolComponentFactories: options.toolComponentFactories,
424
264
  });
425
265
  return registry;
@@ -428,7 +268,6 @@ class PackagedCapabilityComposition {
428
268
  return {
429
269
  supports: [...this.universalSupportIds],
430
270
  prohibitedSupports: [],
431
- activateAtInit: [],
432
271
  };
433
272
  }
434
273
  }
@@ -450,71 +289,31 @@ export const PACKAGED_TOOL_REGISTRATIONS = [
450
289
  export const PACKAGED_TOOL_TAG_MAP = {
451
290
  ...packagedCapabilityComposition.toolTagMap,
452
291
  };
453
- export const ITEM_TOOL_MODULE_LOADERS = {
454
- ...packagedCapabilityComposition.itemModuleLoaders,
455
- };
456
- export const SECTION_TOOL_MODULE_LOADERS = {
457
- ...packagedCapabilityComposition.sectionModuleLoaders,
458
- };
459
292
  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],
293
+ ...packagedCapabilityComposition.moduleLoaders,
485
294
  };
486
295
  export const SECTION_PLAYER_PREFERRED_TOOL_PLACEMENT = {
487
296
  section: [...packagedCapabilityComposition.preferredPlacement.section],
488
297
  item: [...packagedCapabilityComposition.preferredPlacement.item],
489
298
  passage: [...packagedCapabilityComposition.preferredPlacement.passage],
490
299
  };
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
300
  /** Create a registry holding the packaged PIE capabilities. */
500
301
  export function createPackagedToolRegistry(options = {}) {
501
302
  return packagedCapabilityComposition.createRegistry(options);
502
303
  }
503
- /** Build a fresh profile granting the explicit universal-support preset. */
304
+ /**
305
+ * A fresh profile granting the packaged set's universal capabilities, sorted by
306
+ * tool id. Which capabilities are universal is program policy declared on each
307
+ * definition; registry membership never implies it.
308
+ */
504
309
  export function createUniversalPersonalNeedsProfile() {
505
310
  return packagedCapabilityComposition.createUniversalPersonalNeedsProfile();
506
311
  }
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
- });
312
+ /**
313
+ * A fresh profile granting and prohibiting nothing. The toolkit ships no
314
+ * populated default: a deployment's universal set is program policy, which
315
+ * `createUniversalPersonalNeedsProfile` carries as data for hosts that adopt it.
316
+ */
317
+ export function createEmptyPersonalNeedsProfile() {
318
+ return { supports: [], prohibitedSupports: [] };
520
319
  }
@@ -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,14 +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 { createToolElement, resolveToolTag, } from "@pie-players/pie-assessment-toolkit/tools/internal";
15
- import { applyOverlaySurface, createScopedVisibilityBinding, syncButtonAndOverlayVisibility, } 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";
16
11
  import { buildSelectionActions } from "./selection-actions.js";
17
12
  import { renderOverlayToolbar } from "./overlay-toolbar-render.js";
18
13
  /**
@@ -30,13 +25,6 @@ export const lineReaderToolRegistration = {
30
25
  icon: "bars-3",
31
26
  // Line reader appears where there's text to read
32
27
  supportedLevels: ["section", "passage", "rubric", "item"],
33
- // PNP support IDs
34
- // Maps to QTI 3.0 standard features: readingMask, readingGuide, readingRuler
35
- pnpSupportIds: [
36
- "readingMask", // QTI 3.0 standard (reading.readingMask)
37
- "readingGuide", // QTI 3.0 standard (reading.readingGuide)
38
- "readingRuler", // QTI 3.0 standard (reading.readingRuler)
39
- ],
40
28
  /**
41
29
  * Pass 2: Line reader is relevant when readable text is present
42
30
  */
@@ -46,7 +34,6 @@ export const lineReaderToolRegistration = {
46
34
  renderToolbar(context, toolbarContext) {
47
35
  return renderOverlayToolbar(this, context, toolbarContext, {
48
36
  surface: "frameless",
49
- handsOverCoordinator: true,
50
37
  });
51
38
  },
52
39
  };
@@ -65,14 +52,6 @@ export const themeToolRegistration = {
65
52
  icon: "swatch",
66
53
  // Color scheme is assessment-wide
67
54
  supportedLevels: ["assessment", "section"],
68
- // PNP support IDs
69
- // Maps to QTI 3.0 standard features: highContrastDisplay, colorContrast, invertColors
70
- pnpSupportIds: [
71
- "highContrastDisplay", // QTI 3.0 standard (visual.highContrastDisplay)
72
- "colorContrast", // QTI 3.0 standard (visual.colorContrast)
73
- "invertColors", // QTI 3.0 standard (visual.invertColors)
74
- "theme", // Canonical id, and this registration's toolId
75
- ],
76
55
  /**
77
56
  * Pass 2: Color scheme is always relevant when allowed
78
57
  */
@@ -88,7 +67,6 @@ export const themeToolRegistration = {
88
67
  minWidth: 420,
89
68
  minHeight: 300,
90
69
  },
91
- handsOverCoordinator: true,
92
70
  });
93
71
  },
94
72
  };
@@ -118,12 +96,6 @@ export const annotationToolbarRegistration = {
118
96
  surfaces: ["section-overlay"],
119
97
  // Annotation appears where there's text content
120
98
  supportedLevels: ["passage", "rubric", "item", "element"],
121
- // PNP support IDs
122
- // Maps to QTI 3.0 standard features: highlighting, annotations
123
- pnpSupportIds: [
124
- "highlighting", // QTI 3.0 standard (cognitive.highlighting / reading.wordHighlighting)
125
- "annotations", // QTI 3.0 standard (cognitive.annotations)
126
- ],
127
99
  /**
128
100
  * Pass 2: Annotation is relevant when readable text is present
129
101
  */
@@ -146,16 +118,11 @@ export const annotationToolbarRegistration = {
146
118
  return null;
147
119
  }
148
120
  const element = document.createElement(tagName);
149
- // Reads the context it is handed. These were reactive props before the
150
- // gateway moved behind `renderSurface`, and a host calling
151
- // `updateAssessment(...)` mid-session swaps the coordinator without
152
- // remounting — closing over the render-time services would leave the gateway
153
- // highlighting into the previous session's coordinator.
121
+ // The gateway reads its services from the toolkit runtime context. What it
122
+ // takes from here is the action list, rebuilt from the current services on
123
+ // every sync so a mid-session `updateAssessment(...)` reaches it.
154
124
  const applyServices = (current) => {
155
125
  element.enabled = true;
156
- element.ttsService = current.services.ttsService;
157
- element.highlightCoordinator =
158
- current.services.toolkitCoordinator?.highlightCoordinator ?? null;
159
126
  // The second door onto the dictionaries. The gateway renders these and
160
127
  // knows nothing of what they open; the pairing is composition's, which is
161
128
  // why the list is built in `selection-actions.ts` and not here.
@@ -165,8 +132,6 @@ export const annotationToolbarRegistration = {
165
132
  return { element, sync: applyServices };
166
133
  },
167
134
  renderToolbar(context, toolbarContext) {
168
- return renderOverlayToolbar(this, context, toolbarContext, {
169
- handsOverCoordinator: true,
170
- });
135
+ return renderOverlayToolbar(this, context, toolbarContext);
171
136
  },
172
137
  };
@@ -35,7 +35,7 @@
35
35
  * absent from the universal preset — a content-dependent support never belongs in
36
36
  * a wholesale grant.
37
37
  */
38
- import type { ToolContentDependencyContext, ToolRegistration } from "@pie-players/pie-assessment-toolkit/tools/internal";
38
+ import type { ToolContentDependencyContext, ToolRegistration } from "@pie-players/pie-assessment-toolkit/tools/registration";
39
39
  /** QTI 3.0 / AfA support id gating an audio transcript. */
40
40
  export declare const AUDIO_TRANSCRIPT_FEATURE_ID = "transcript";
41
41
  /** Catalog type carrying the transcript text. */
@@ -147,7 +147,6 @@ export const audioTranscriptRegistration = {
147
147
  nameKey: "tools.audioTranscript.name",
148
148
  descriptionKey: "tools.audioTranscript.description",
149
149
  supportedLevels: ["item", "passage"],
150
- pnpSupportIds: [AUDIO_TRANSCRIPT_FEATURE_ID],
151
150
  // No button to press: a transcript is either authored-visible, or granted and
152
151
  // present, or absent. `region` is the activation for a capability with no
153
152
  // toolbar presence, and tools-config validation reports a `tools.placement`