@pie-players/pie-default-tool-loaders 0.3.65 → 0.3.66
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 +29 -8
- package/dist/index.d.ts +3 -21
- package/dist/index.js +2 -49
- package/dist/packaged-capability-composition.d.ts +73 -0
- package/dist/packaged-capability-composition.js +447 -0
- package/dist/packaged-tool-registry.d.ts +2 -52
- package/dist/packaged-tool-registry.js +1 -96
- package/dist/registrations/audio-transcript.d.ts +75 -0
- package/dist/registrations/audio-transcript.js +183 -0
- package/dist/tool-placement.d.ts +1 -29
- package/dist/tool-placement.js +1 -52
- package/dist/tool-tag-map.d.ts +1 -16
- package/dist/tool-tag-map.js +1 -27
- package/dist/universal-supports.d.ts +1 -33
- package/dist/universal-supports.js +1 -77
- package/package.json +15 -14
|
@@ -0,0 +1,447 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* The one authored description of PIE's packaged capability composition.
|
|
3
|
+
*
|
|
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.
|
|
7
|
+
* Public constants are projections of this composition so adding a capability
|
|
8
|
+
* cannot leave a second hand-maintained catalogue silently behind.
|
|
9
|
+
*/
|
|
10
|
+
import { ToolRegistry, } from "@pie-players/pie-assessment-toolkit/tools/internal";
|
|
11
|
+
import { annotationToolbarRegistration, lineReaderToolRegistration, themeToolRegistration, } from "./registrations/accessibility-tools.js";
|
|
12
|
+
import { audioTranscriptRegistration } from "./registrations/audio-transcript.js";
|
|
13
|
+
import { calculatorToolRegistration } from "./registrations/calculator.js";
|
|
14
|
+
import { answerEliminatorToolRegistration, highlighterToolRegistration, } from "./registrations/interaction-tools.js";
|
|
15
|
+
import { protractorToolRegistration, rulerToolRegistration, } from "./registrations/measurement-tools.js";
|
|
16
|
+
import { graphToolRegistration, periodicTableToolRegistration, } from "./registrations/subject-specific-tools.js";
|
|
17
|
+
import { ttsToolRegistration } from "./registrations/tts.js";
|
|
18
|
+
const loadSideEffectModule = (load) => load().then(() => undefined);
|
|
19
|
+
function loadCalculatorModule() {
|
|
20
|
+
if (typeof globalThis !== "undefined" &&
|
|
21
|
+
"customElements" in globalThis &&
|
|
22
|
+
globalThis.customElements?.get("pie-tool-calculator")) {
|
|
23
|
+
return Promise.resolve();
|
|
24
|
+
}
|
|
25
|
+
return loadSideEffectModule(() => import("@pie-players/pie-tool-calculator-desmos"));
|
|
26
|
+
}
|
|
27
|
+
const loadTtsModule = () => loadSideEffectModule(() => import("@pie-players/pie-tool-tts-inline"));
|
|
28
|
+
const loadRulerModule = () => loadSideEffectModule(() => import("@pie-players/pie-tool-ruler"));
|
|
29
|
+
const loadProtractorModule = () => loadSideEffectModule(() => import("@pie-players/pie-tool-protractor"));
|
|
30
|
+
const loadAnswerEliminatorModule = () => loadSideEffectModule(() => import("@pie-players/pie-tool-answer-eliminator"));
|
|
31
|
+
const loadAnnotationToolbarModule = () => loadSideEffectModule(() => import("@pie-players/pie-tool-annotation-toolbar"));
|
|
32
|
+
const loadLineReaderModule = () => loadSideEffectModule(() => import("@pie-players/pie-tool-line-reader"));
|
|
33
|
+
const loadThemeModule = () => loadSideEffectModule(() => import("@pie-players/pie-tool-theme"));
|
|
34
|
+
const loadGraphModule = () => loadSideEffectModule(() => import("@pie-players/pie-tool-graph"));
|
|
35
|
+
const loadPeriodicTableModule = () => loadSideEffectModule(() => import("@pie-players/pie-tool-periodic-table"));
|
|
36
|
+
const PACKAGED_CAPABILITY_DEFINITIONS = [
|
|
37
|
+
{
|
|
38
|
+
registration: calculatorToolRegistration,
|
|
39
|
+
tagName: "pie-tool-calculator",
|
|
40
|
+
loadModule: loadCalculatorModule,
|
|
41
|
+
loaderTargets: ["item", "section"],
|
|
42
|
+
placementOrder: { element: 10 },
|
|
43
|
+
preferredPlacementOrder: { item: 10 },
|
|
44
|
+
toolbarOrder: 20,
|
|
45
|
+
universalSupportIds: [
|
|
46
|
+
"calculator",
|
|
47
|
+
"graphingCalculator",
|
|
48
|
+
"basicCalculator",
|
|
49
|
+
"scientificCalculator",
|
|
50
|
+
],
|
|
51
|
+
},
|
|
52
|
+
{
|
|
53
|
+
registration: ttsToolRegistration,
|
|
54
|
+
tagName: "pie-tool-text-to-speech",
|
|
55
|
+
loadModule: loadTtsModule,
|
|
56
|
+
loaderTargets: ["item"],
|
|
57
|
+
placementOrder: { item: 10, passage: 10, rubric: 10, element: 30 },
|
|
58
|
+
preferredPlacementOrder: { item: 20, passage: 10 },
|
|
59
|
+
toolbarOrder: 30,
|
|
60
|
+
universalSupportIds: ["textToSpeech", "readAloud", "tts", "speechOutput"],
|
|
61
|
+
},
|
|
62
|
+
{
|
|
63
|
+
registration: rulerToolRegistration,
|
|
64
|
+
tagName: "pie-tool-ruler",
|
|
65
|
+
loadModule: loadRulerModule,
|
|
66
|
+
loaderTargets: ["section"],
|
|
67
|
+
placementOrder: { element: 40 },
|
|
68
|
+
preferredPlacementOrder: { section: 50 },
|
|
69
|
+
toolbarOrder: 80,
|
|
70
|
+
universalSupportIds: ["ruler", "measurement"],
|
|
71
|
+
},
|
|
72
|
+
{
|
|
73
|
+
registration: protractorToolRegistration,
|
|
74
|
+
tagName: "pie-tool-protractor",
|
|
75
|
+
loadModule: loadProtractorModule,
|
|
76
|
+
loaderTargets: ["section"],
|
|
77
|
+
placementOrder: { element: 50 },
|
|
78
|
+
preferredPlacementOrder: { section: 60 },
|
|
79
|
+
toolbarOrder: 90,
|
|
80
|
+
universalSupportIds: ["protractor", "angleMeasurement"],
|
|
81
|
+
},
|
|
82
|
+
{
|
|
83
|
+
registration: answerEliminatorToolRegistration,
|
|
84
|
+
tagName: "pie-tool-answer-eliminator",
|
|
85
|
+
loadModule: loadAnswerEliminatorModule,
|
|
86
|
+
loaderTargets: ["item"],
|
|
87
|
+
placementOrder: { element: 20 },
|
|
88
|
+
preferredPlacementOrder: { item: 30 },
|
|
89
|
+
toolbarOrder: 70,
|
|
90
|
+
universalSupportIds: [
|
|
91
|
+
"answerMasking",
|
|
92
|
+
"answerEliminator",
|
|
93
|
+
"strikethrough",
|
|
94
|
+
"choiceMasking",
|
|
95
|
+
],
|
|
96
|
+
},
|
|
97
|
+
{
|
|
98
|
+
registration: highlighterToolRegistration,
|
|
99
|
+
tagName: "pie-tool-annotation-toolbar",
|
|
100
|
+
loadModule: loadAnnotationToolbarModule,
|
|
101
|
+
loaderTargets: ["item"],
|
|
102
|
+
placementOrder: { item: 20, passage: 20, rubric: 20, element: 60 },
|
|
103
|
+
toolbarOrder: 60,
|
|
104
|
+
universalSupportIds: ["highlighter", "textHighlight", "annotation"],
|
|
105
|
+
},
|
|
106
|
+
{
|
|
107
|
+
registration: lineReaderToolRegistration,
|
|
108
|
+
tagName: "pie-tool-line-reader",
|
|
109
|
+
loadModule: loadLineReaderModule,
|
|
110
|
+
loaderTargets: ["section"],
|
|
111
|
+
placementOrder: { passage: 40, rubric: 40 },
|
|
112
|
+
preferredPlacementOrder: { section: 40 },
|
|
113
|
+
toolbarOrder: 40,
|
|
114
|
+
universalSupportIds: [
|
|
115
|
+
"readingMask",
|
|
116
|
+
"readingGuide",
|
|
117
|
+
"readingRuler",
|
|
118
|
+
"lineReader",
|
|
119
|
+
"trackingGuide",
|
|
120
|
+
],
|
|
121
|
+
},
|
|
122
|
+
{
|
|
123
|
+
registration: themeToolRegistration,
|
|
124
|
+
tagName: "pie-tool-theme",
|
|
125
|
+
loadModule: loadThemeModule,
|
|
126
|
+
loaderTargets: ["item"],
|
|
127
|
+
placementOrder: { assessment: 10, section: 10 },
|
|
128
|
+
preferredPlacementOrder: { section: 10 },
|
|
129
|
+
toolbarOrder: 10,
|
|
130
|
+
universalSupportIds: [
|
|
131
|
+
"highContrastDisplay",
|
|
132
|
+
"colorContrast",
|
|
133
|
+
"invertColors",
|
|
134
|
+
"theme",
|
|
135
|
+
"highContrast",
|
|
136
|
+
"customColors",
|
|
137
|
+
],
|
|
138
|
+
},
|
|
139
|
+
{
|
|
140
|
+
registration: annotationToolbarRegistration,
|
|
141
|
+
tagName: "pie-tool-annotation-toolbar",
|
|
142
|
+
loadModule: loadAnnotationToolbarModule,
|
|
143
|
+
loaderTargets: ["item"],
|
|
144
|
+
placementOrder: { item: 30, passage: 30, rubric: 30, element: 70 },
|
|
145
|
+
preferredPlacementOrder: { item: 40, passage: 20 },
|
|
146
|
+
toolbarOrder: 50,
|
|
147
|
+
universalSupportIds: ["highlighting", "annotations"],
|
|
148
|
+
},
|
|
149
|
+
{
|
|
150
|
+
registration: graphToolRegistration,
|
|
151
|
+
tagName: "pie-tool-graph",
|
|
152
|
+
loadModule: loadGraphModule,
|
|
153
|
+
loaderTargets: ["section"],
|
|
154
|
+
placementOrder: { item: 40, element: 80 },
|
|
155
|
+
preferredPlacementOrder: { section: 20 },
|
|
156
|
+
toolbarOrder: 100,
|
|
157
|
+
universalSupportIds: ["graph", "coordinatePlane", "graphingTool"],
|
|
158
|
+
},
|
|
159
|
+
{
|
|
160
|
+
registration: periodicTableToolRegistration,
|
|
161
|
+
tagName: "pie-tool-periodic-table",
|
|
162
|
+
loadModule: loadPeriodicTableModule,
|
|
163
|
+
loaderTargets: ["section"],
|
|
164
|
+
placementOrder: { item: 50, element: 90 },
|
|
165
|
+
preferredPlacementOrder: { section: 30 },
|
|
166
|
+
toolbarOrder: 110,
|
|
167
|
+
universalSupportIds: [
|
|
168
|
+
"periodicTable",
|
|
169
|
+
"chemistryReference",
|
|
170
|
+
"elementReference",
|
|
171
|
+
],
|
|
172
|
+
},
|
|
173
|
+
{
|
|
174
|
+
registration: audioTranscriptRegistration,
|
|
175
|
+
universalSupportIds: [],
|
|
176
|
+
},
|
|
177
|
+
];
|
|
178
|
+
const PACKAGED_PLACEMENT_LEVELS = [
|
|
179
|
+
"assessment",
|
|
180
|
+
"section",
|
|
181
|
+
"item",
|
|
182
|
+
"passage",
|
|
183
|
+
"rubric",
|
|
184
|
+
"element",
|
|
185
|
+
];
|
|
186
|
+
const PREFERRED_PLACEMENT_LEVELS = ["section", "item", "passage"];
|
|
187
|
+
function assertUniqueWeights(definitions, levels, read, field) {
|
|
188
|
+
for (const level of levels) {
|
|
189
|
+
const seen = new Set();
|
|
190
|
+
for (const definition of definitions) {
|
|
191
|
+
const weight = read(definition)?.[level];
|
|
192
|
+
if (weight === undefined)
|
|
193
|
+
continue;
|
|
194
|
+
if (!Number.isSafeInteger(weight) || weight < 0) {
|
|
195
|
+
throw new Error(`Invalid packaged capability "${definition.registration.toolId}": ${field}.${level} must be a non-negative integer.`);
|
|
196
|
+
}
|
|
197
|
+
if (seen.has(weight)) {
|
|
198
|
+
throw new Error(`Invalid packaged capability composition: duplicate ${field}.${level} order ${weight}.`);
|
|
199
|
+
}
|
|
200
|
+
seen.add(weight);
|
|
201
|
+
}
|
|
202
|
+
}
|
|
203
|
+
}
|
|
204
|
+
function assertComposition(definitions) {
|
|
205
|
+
const toolIds = new Set();
|
|
206
|
+
const universalSupportIds = new Set();
|
|
207
|
+
const toolbarOrders = new Set();
|
|
208
|
+
for (const definition of definitions) {
|
|
209
|
+
const { registration } = definition;
|
|
210
|
+
if (!registration.toolId.trim()) {
|
|
211
|
+
throw new Error("Invalid packaged capability composition: tool ids must be non-empty.");
|
|
212
|
+
}
|
|
213
|
+
if (toolIds.has(registration.toolId)) {
|
|
214
|
+
throw new Error(`Invalid packaged capability composition: duplicate tool id "${registration.toolId}".`);
|
|
215
|
+
}
|
|
216
|
+
toolIds.add(registration.toolId);
|
|
217
|
+
const isRegion = registration.activation === "region";
|
|
218
|
+
if (isRegion) {
|
|
219
|
+
if (definition.tagName !== undefined ||
|
|
220
|
+
definition.loadModule !== undefined ||
|
|
221
|
+
definition.loaderTargets !== undefined ||
|
|
222
|
+
definition.toolbarOrder !== undefined ||
|
|
223
|
+
Object.keys(definition.placementOrder ?? {}).length > 0 ||
|
|
224
|
+
Object.keys(definition.preferredPlacementOrder ?? {}).length > 0) {
|
|
225
|
+
throw new Error(`Invalid packaged capability "${registration.toolId}": a region capability is surface-hosted and cannot declare element delivery or toolbar placement.`);
|
|
226
|
+
}
|
|
227
|
+
}
|
|
228
|
+
else {
|
|
229
|
+
if (!definition.tagName?.includes("-")) {
|
|
230
|
+
throw new Error(`Invalid packaged capability "${registration.toolId}": element-backed capabilities need a custom-element tag.`);
|
|
231
|
+
}
|
|
232
|
+
if (typeof definition.loadModule !== "function" ||
|
|
233
|
+
!definition.loaderTargets?.length) {
|
|
234
|
+
throw new Error(`Invalid packaged capability "${registration.toolId}": element-backed capabilities need a lazy loader and at least one bootstrap target.`);
|
|
235
|
+
}
|
|
236
|
+
if (new Set(definition.loaderTargets).size !==
|
|
237
|
+
definition.loaderTargets.length) {
|
|
238
|
+
throw new Error(`Invalid packaged capability "${registration.toolId}": loader bootstrap targets must be unique.`);
|
|
239
|
+
}
|
|
240
|
+
if (definition.toolbarOrder === undefined) {
|
|
241
|
+
throw new Error(`Invalid packaged capability "${registration.toolId}": toolbar capabilities need an order.`);
|
|
242
|
+
}
|
|
243
|
+
}
|
|
244
|
+
if (definition.toolbarOrder !== undefined) {
|
|
245
|
+
if (!Number.isSafeInteger(definition.toolbarOrder) ||
|
|
246
|
+
definition.toolbarOrder < 0) {
|
|
247
|
+
throw new Error(`Invalid packaged capability "${registration.toolId}": toolbar order must be a non-negative integer.`);
|
|
248
|
+
}
|
|
249
|
+
if (toolbarOrders.has(definition.toolbarOrder)) {
|
|
250
|
+
throw new Error(`Invalid packaged capability composition: duplicate toolbar order ${definition.toolbarOrder}.`);
|
|
251
|
+
}
|
|
252
|
+
toolbarOrders.add(definition.toolbarOrder);
|
|
253
|
+
}
|
|
254
|
+
const registrationSupportIds = new Set(registration.pnpSupportIds ?? [registration.toolId]);
|
|
255
|
+
if (registration.requiresAuthoredContent &&
|
|
256
|
+
definition.universalSupportIds.length > 0) {
|
|
257
|
+
throw new Error(`Invalid packaged capability "${registration.toolId}": content-dependent support ids cannot be universally granted.`);
|
|
258
|
+
}
|
|
259
|
+
for (const supportId of definition.universalSupportIds) {
|
|
260
|
+
if (!supportId.trim()) {
|
|
261
|
+
throw new Error(`Invalid packaged capability "${registration.toolId}": universal support ids must be non-empty.`);
|
|
262
|
+
}
|
|
263
|
+
if (!registrationSupportIds.has(supportId)) {
|
|
264
|
+
throw new Error(`Invalid packaged capability "${registration.toolId}": universal support id "${supportId}" is not declared by its registration.`);
|
|
265
|
+
}
|
|
266
|
+
if (universalSupportIds.has(supportId)) {
|
|
267
|
+
throw new Error(`Invalid packaged capability composition: universal support id "${supportId}" has more than one owner.`);
|
|
268
|
+
}
|
|
269
|
+
universalSupportIds.add(supportId);
|
|
270
|
+
}
|
|
271
|
+
for (const level of PREFERRED_PLACEMENT_LEVELS) {
|
|
272
|
+
if (definition.preferredPlacementOrder?.[level] !== undefined &&
|
|
273
|
+
!registration.supportedLevels.includes(level)) {
|
|
274
|
+
throw new Error(`Invalid packaged capability "${registration.toolId}": preferred placement "${level}" is not supported by its registration.`);
|
|
275
|
+
}
|
|
276
|
+
}
|
|
277
|
+
}
|
|
278
|
+
assertUniqueWeights(definitions, PACKAGED_PLACEMENT_LEVELS, (definition) => definition.placementOrder, "placementOrder");
|
|
279
|
+
assertUniqueWeights(definitions, PREFERRED_PLACEMENT_LEVELS, (definition) => definition.preferredPlacementOrder, "preferredPlacementOrder");
|
|
280
|
+
}
|
|
281
|
+
function orderedToolIds(definitions, level, read) {
|
|
282
|
+
return definitions
|
|
283
|
+
.flatMap((definition) => {
|
|
284
|
+
const order = read(definition)?.[level];
|
|
285
|
+
return order === undefined ? [] : [{ definition, order }];
|
|
286
|
+
})
|
|
287
|
+
.sort((left, right) => left.order - right.order)
|
|
288
|
+
.map(({ definition }) => definition.registration.toolId);
|
|
289
|
+
}
|
|
290
|
+
class PackagedCapabilityComposition {
|
|
291
|
+
definitions;
|
|
292
|
+
registrations;
|
|
293
|
+
toolTagMap;
|
|
294
|
+
itemModuleLoaders;
|
|
295
|
+
sectionModuleLoaders;
|
|
296
|
+
defaultModuleLoaders;
|
|
297
|
+
placement;
|
|
298
|
+
preferredPlacement;
|
|
299
|
+
toolbarOrder;
|
|
300
|
+
universalSupportIds;
|
|
301
|
+
constructor(definitions) {
|
|
302
|
+
this.definitions = definitions;
|
|
303
|
+
this.registrations = Object.freeze(definitions.map(({ registration }) => registration));
|
|
304
|
+
this.toolTagMap = Object.freeze(Object.fromEntries(definitions.flatMap((definition) => definition.tagName
|
|
305
|
+
? [[definition.registration.toolId, definition.tagName]]
|
|
306
|
+
: [])));
|
|
307
|
+
this.itemModuleLoaders = this.projectModuleLoaders("item");
|
|
308
|
+
this.sectionModuleLoaders = this.projectModuleLoaders("section");
|
|
309
|
+
this.defaultModuleLoaders = Object.freeze({
|
|
310
|
+
...this.itemModuleLoaders,
|
|
311
|
+
...this.sectionModuleLoaders,
|
|
312
|
+
});
|
|
313
|
+
this.placement = Object.freeze(Object.fromEntries(PACKAGED_PLACEMENT_LEVELS.map((level) => [
|
|
314
|
+
level,
|
|
315
|
+
Object.freeze(orderedToolIds(definitions, level, (definition) => definition.placementOrder)),
|
|
316
|
+
])));
|
|
317
|
+
this.preferredPlacement = Object.freeze(Object.fromEntries(PREFERRED_PLACEMENT_LEVELS.map((level) => [
|
|
318
|
+
level,
|
|
319
|
+
Object.freeze(orderedToolIds(definitions, level, (definition) => definition.preferredPlacementOrder)),
|
|
320
|
+
])));
|
|
321
|
+
this.toolbarOrder = Object.freeze(definitions
|
|
322
|
+
.filter((definition) => definition.toolbarOrder !== undefined)
|
|
323
|
+
.slice()
|
|
324
|
+
.sort((left, right) => left.toolbarOrder - right.toolbarOrder)
|
|
325
|
+
.map(({ registration }) => registration.toolId));
|
|
326
|
+
this.universalSupportIds = Object.freeze(definitions
|
|
327
|
+
.flatMap(({ universalSupportIds }) => [...universalSupportIds])
|
|
328
|
+
.sort());
|
|
329
|
+
}
|
|
330
|
+
projectModuleLoaders(target) {
|
|
331
|
+
return Object.freeze(Object.fromEntries(this.definitions.flatMap((definition) => definition.loadModule && definition.loaderTargets?.includes(target)
|
|
332
|
+
? [[definition.registration.toolId, definition.loadModule]]
|
|
333
|
+
: [])));
|
|
334
|
+
}
|
|
335
|
+
selectRegistrations(toolIds) {
|
|
336
|
+
// Preserve the established fail-soft host behavior: no selection means all,
|
|
337
|
+
// and unknown ids are ignored rather than preventing known tools from loading.
|
|
338
|
+
if (!toolIds?.length)
|
|
339
|
+
return this.registrations;
|
|
340
|
+
const selected = new Set(toolIds);
|
|
341
|
+
return this.registrations.filter(({ toolId }) => selected.has(toolId));
|
|
342
|
+
}
|
|
343
|
+
registerTools(registry, options = {}) {
|
|
344
|
+
const applyOverrides = options.applyOverrides ??
|
|
345
|
+
((registration) => registration);
|
|
346
|
+
for (const registration of this.selectRegistrations(options.toolIds)) {
|
|
347
|
+
registry.register(applyOverrides(registration));
|
|
348
|
+
}
|
|
349
|
+
}
|
|
350
|
+
createRegistry(options = {}) {
|
|
351
|
+
const registry = new ToolRegistry();
|
|
352
|
+
this.registerTools(registry, {
|
|
353
|
+
toolIds: options.toolIds,
|
|
354
|
+
applyOverrides: (registration) => options.overrides?.[registration.toolId] ?? registration,
|
|
355
|
+
});
|
|
356
|
+
// Loader installation remains opt-in. Some hosts preload tool elements or
|
|
357
|
+
// provide their own tags; silently adding package loads here would change
|
|
358
|
+
// their bundle/runtime behavior.
|
|
359
|
+
if (options.toolModuleLoaders &&
|
|
360
|
+
Object.keys(options.toolModuleLoaders).length > 0) {
|
|
361
|
+
registry.setToolModuleLoaders(options.toolModuleLoaders);
|
|
362
|
+
}
|
|
363
|
+
registry.setComponentOverrides({
|
|
364
|
+
toolTagMap: { ...this.toolTagMap, ...(options.toolTagMap ?? {}) },
|
|
365
|
+
toolComponentFactory: options.toolComponentFactory,
|
|
366
|
+
toolComponentFactories: options.toolComponentFactories,
|
|
367
|
+
});
|
|
368
|
+
return registry;
|
|
369
|
+
}
|
|
370
|
+
createUniversalPersonalNeedsProfile() {
|
|
371
|
+
return {
|
|
372
|
+
supports: [...this.universalSupportIds],
|
|
373
|
+
prohibitedSupports: [],
|
|
374
|
+
activateAtInit: [],
|
|
375
|
+
};
|
|
376
|
+
}
|
|
377
|
+
}
|
|
378
|
+
/**
|
|
379
|
+
* Release/build gate for PIE-authored composition data.
|
|
380
|
+
*
|
|
381
|
+
* Deliberately not called by the browser runtime: an invariant regression must
|
|
382
|
+
* stop the package before publication, not turn into an import-time exception
|
|
383
|
+
* that prevents an otherwise usable assessment from rendering.
|
|
384
|
+
*/
|
|
385
|
+
export function assertPackagedCapabilityComposition() {
|
|
386
|
+
assertComposition(PACKAGED_CAPABILITY_DEFINITIONS);
|
|
387
|
+
}
|
|
388
|
+
/** Internal deep-module instance. Root exports below are its stable facade. */
|
|
389
|
+
const packagedCapabilityComposition = new PackagedCapabilityComposition(PACKAGED_CAPABILITY_DEFINITIONS);
|
|
390
|
+
export const PACKAGED_TOOL_REGISTRATIONS = [
|
|
391
|
+
...packagedCapabilityComposition.registrations,
|
|
392
|
+
];
|
|
393
|
+
export const PACKAGED_TOOL_TAG_MAP = {
|
|
394
|
+
...packagedCapabilityComposition.toolTagMap,
|
|
395
|
+
};
|
|
396
|
+
export const ITEM_TOOL_MODULE_LOADERS = {
|
|
397
|
+
...packagedCapabilityComposition.itemModuleLoaders,
|
|
398
|
+
};
|
|
399
|
+
export const SECTION_TOOL_MODULE_LOADERS = {
|
|
400
|
+
...packagedCapabilityComposition.sectionModuleLoaders,
|
|
401
|
+
};
|
|
402
|
+
export const DEFAULT_TOOL_MODULE_LOADERS = {
|
|
403
|
+
...packagedCapabilityComposition.defaultModuleLoaders,
|
|
404
|
+
};
|
|
405
|
+
export const PACKAGED_TOOL_PLACEMENT = {
|
|
406
|
+
assessment: [...packagedCapabilityComposition.placement.assessment],
|
|
407
|
+
section: [...packagedCapabilityComposition.placement.section],
|
|
408
|
+
item: [...packagedCapabilityComposition.placement.item],
|
|
409
|
+
passage: [...packagedCapabilityComposition.placement.passage],
|
|
410
|
+
rubric: [...packagedCapabilityComposition.placement.rubric],
|
|
411
|
+
element: [...packagedCapabilityComposition.placement.element],
|
|
412
|
+
};
|
|
413
|
+
export const SECTION_PLAYER_PREFERRED_TOOL_PLACEMENT = {
|
|
414
|
+
section: [...packagedCapabilityComposition.preferredPlacement.section],
|
|
415
|
+
item: [...packagedCapabilityComposition.preferredPlacement.item],
|
|
416
|
+
passage: [...packagedCapabilityComposition.preferredPlacement.passage],
|
|
417
|
+
};
|
|
418
|
+
export const PACKAGED_TOOL_ORDER = [
|
|
419
|
+
...packagedCapabilityComposition.toolbarOrder,
|
|
420
|
+
];
|
|
421
|
+
export const UNIVERSAL_SUPPORTS_PRESET = packagedCapabilityComposition.universalSupportIds;
|
|
422
|
+
/** Register packaged PIE capabilities onto an existing registry. */
|
|
423
|
+
export function registerPackagedTools(registry, options = {}) {
|
|
424
|
+
packagedCapabilityComposition.registerTools(registry, options);
|
|
425
|
+
}
|
|
426
|
+
/** Create a registry holding the packaged PIE capabilities. */
|
|
427
|
+
export function createPackagedToolRegistry(options = {}) {
|
|
428
|
+
return packagedCapabilityComposition.createRegistry(options);
|
|
429
|
+
}
|
|
430
|
+
/** Build a fresh profile granting the explicit universal-support preset. */
|
|
431
|
+
export function createUniversalPersonalNeedsProfile() {
|
|
432
|
+
return packagedCapabilityComposition.createUniversalPersonalNeedsProfile();
|
|
433
|
+
}
|
|
434
|
+
/** Register packaged lazy module loaders, followed by host overrides. */
|
|
435
|
+
export function registerDefaultToolModuleLoaders(registry, options = {}) {
|
|
436
|
+
registry.setToolModuleLoaders({
|
|
437
|
+
...DEFAULT_TOOL_MODULE_LOADERS,
|
|
438
|
+
...(options.loaders ?? {}),
|
|
439
|
+
});
|
|
440
|
+
}
|
|
441
|
+
/** Register only the section-bootstrap loader subset, then host overrides. */
|
|
442
|
+
export function registerSectionToolModuleLoaders(registry, options = {}) {
|
|
443
|
+
registry.setToolModuleLoaders({
|
|
444
|
+
...SECTION_TOOL_MODULE_LOADERS,
|
|
445
|
+
...(options.loaders ?? {}),
|
|
446
|
+
});
|
|
447
|
+
}
|
|
@@ -1,52 +1,2 @@
|
|
|
1
|
-
|
|
2
|
-
|
|
3
|
-
*
|
|
4
|
-
* This is the composition layer: which capabilities exist in a deployment. It
|
|
5
|
-
* lived in `@pie-players/pie-assessment-toolkit`, where eleven concrete
|
|
6
|
-
* registrations inside the generic package meant the policy and registry core
|
|
7
|
-
* knew every capability by name and a host could not contribute one without a PR
|
|
8
|
-
* against that package.
|
|
9
|
-
*
|
|
10
|
-
* The toolkit still owns `ToolRegistry`, `createDefaultToolRegistry` (which
|
|
11
|
-
* builds an empty registry), the registration contract and the toolbar helpers.
|
|
12
|
-
* It knows `featureId`, placement levels, activation kinds and precedence rules,
|
|
13
|
-
* and knows no capability ids.
|
|
14
|
-
*/
|
|
15
|
-
import { ToolRegistry, type ToolComponentFactory, type ToolComponentFactoryMap, type ToolModuleLoader, type ToolRegistration, type ToolTagMap } from "@pie-players/pie-assessment-toolkit/tools/internal";
|
|
16
|
-
export declare const PACKAGED_TOOL_REGISTRATIONS: readonly [ToolRegistration, ToolRegistration, ToolRegistration, ToolRegistration, ToolRegistration, ToolRegistration, ToolRegistration, ToolRegistration, ToolRegistration, ToolRegistration, ToolRegistration];
|
|
17
|
-
export interface PackagedToolRegistryOptions {
|
|
18
|
-
/**
|
|
19
|
-
* Override packaged registrations by toolId. Highest-precedence extension
|
|
20
|
-
* point.
|
|
21
|
-
*/
|
|
22
|
-
overrides?: Partial<Record<string, ToolRegistration>>;
|
|
23
|
-
/** Override or extend the packaged element tag mapping. */
|
|
24
|
-
toolTagMap?: Partial<ToolTagMap>;
|
|
25
|
-
/** Override the component factory globally or per tool. */
|
|
26
|
-
toolComponentFactory?: ToolComponentFactory;
|
|
27
|
-
toolComponentFactories?: Partial<ToolComponentFactoryMap>;
|
|
28
|
-
/** Lazy module loaders keyed by toolId. */
|
|
29
|
-
toolModuleLoaders?: Partial<Record<string, ToolModuleLoader>>;
|
|
30
|
-
/** Restrict registration to specific packaged tool ids. */
|
|
31
|
-
toolIds?: string[];
|
|
32
|
-
}
|
|
33
|
-
export interface RegisterPackagedToolsOptions {
|
|
34
|
-
toolIds?: string[];
|
|
35
|
-
applyOverrides?: (registration: ToolRegistration) => ToolRegistration;
|
|
36
|
-
}
|
|
37
|
-
/**
|
|
38
|
-
* Register packaged PIE capabilities onto an existing registry.
|
|
39
|
-
*/
|
|
40
|
-
export declare function registerPackagedTools(registry: ToolRegistry, options?: RegisterPackagedToolsOptions): void;
|
|
41
|
-
/**
|
|
42
|
-
* Create a registry holding the packaged PIE capabilities.
|
|
43
|
-
*
|
|
44
|
-
* The tag map is installed through `setComponentOverrides` rather than read from
|
|
45
|
-
* a core default, so a registry composed without it resolves no packaged tags —
|
|
46
|
-
* which is the point: core no longer carries the catalogue.
|
|
47
|
-
*/
|
|
48
|
-
export declare function createPackagedToolRegistry(options?: PackagedToolRegistryOptions): ToolRegistry;
|
|
49
|
-
/**
|
|
50
|
-
* Render order when several capabilities are visible at once.
|
|
51
|
-
*/
|
|
52
|
-
export declare const PACKAGED_TOOL_ORDER: readonly ["theme", "calculator", "textToSpeech", "lineReader", "annotationToolbar", "highlighter", "answerEliminator", "ruler", "protractor", "graph", "periodicTable"];
|
|
1
|
+
export type { PackagedToolRegistryOptions, RegisterPackagedToolsOptions, } from "./packaged-capability-composition.js";
|
|
2
|
+
export { createPackagedToolRegistry, PACKAGED_TOOL_ORDER, PACKAGED_TOOL_REGISTRATIONS, registerPackagedTools, } from "./packaged-capability-composition.js";
|
|
@@ -1,96 +1 @@
|
|
|
1
|
-
|
|
2
|
-
* The packaged PIE capability set, and the registry factory that composes it.
|
|
3
|
-
*
|
|
4
|
-
* This is the composition layer: which capabilities exist in a deployment. It
|
|
5
|
-
* lived in `@pie-players/pie-assessment-toolkit`, where eleven concrete
|
|
6
|
-
* registrations inside the generic package meant the policy and registry core
|
|
7
|
-
* knew every capability by name and a host could not contribute one without a PR
|
|
8
|
-
* against that package.
|
|
9
|
-
*
|
|
10
|
-
* The toolkit still owns `ToolRegistry`, `createDefaultToolRegistry` (which
|
|
11
|
-
* builds an empty registry), the registration contract and the toolbar helpers.
|
|
12
|
-
* It knows `featureId`, placement levels, activation kinds and precedence rules,
|
|
13
|
-
* and knows no capability ids.
|
|
14
|
-
*/
|
|
15
|
-
import { ToolRegistry, } from "@pie-players/pie-assessment-toolkit/tools/internal";
|
|
16
|
-
import { annotationToolbarRegistration, lineReaderToolRegistration, themeToolRegistration, } from "./registrations/accessibility-tools.js";
|
|
17
|
-
import { calculatorToolRegistration } from "./registrations/calculator.js";
|
|
18
|
-
import { answerEliminatorToolRegistration, highlighterToolRegistration, } from "./registrations/interaction-tools.js";
|
|
19
|
-
import { protractorToolRegistration, rulerToolRegistration, } from "./registrations/measurement-tools.js";
|
|
20
|
-
import { graphToolRegistration, periodicTableToolRegistration, } from "./registrations/subject-specific-tools.js";
|
|
21
|
-
import { ttsToolRegistration } from "./registrations/tts.js";
|
|
22
|
-
import { PACKAGED_TOOL_TAG_MAP } from "./tool-tag-map.js";
|
|
23
|
-
export const PACKAGED_TOOL_REGISTRATIONS = [
|
|
24
|
-
calculatorToolRegistration,
|
|
25
|
-
ttsToolRegistration,
|
|
26
|
-
rulerToolRegistration,
|
|
27
|
-
protractorToolRegistration,
|
|
28
|
-
answerEliminatorToolRegistration,
|
|
29
|
-
highlighterToolRegistration,
|
|
30
|
-
lineReaderToolRegistration,
|
|
31
|
-
themeToolRegistration,
|
|
32
|
-
annotationToolbarRegistration,
|
|
33
|
-
graphToolRegistration,
|
|
34
|
-
periodicTableToolRegistration,
|
|
35
|
-
];
|
|
36
|
-
/**
|
|
37
|
-
* Register packaged PIE capabilities onto an existing registry.
|
|
38
|
-
*/
|
|
39
|
-
export function registerPackagedTools(registry, options = {}) {
|
|
40
|
-
const selectedToolIds = options.toolIds && options.toolIds.length > 0
|
|
41
|
-
? new Set(options.toolIds)
|
|
42
|
-
: null;
|
|
43
|
-
const applyOverrides = options.applyOverrides ??
|
|
44
|
-
((registration) => registration);
|
|
45
|
-
for (const registration of PACKAGED_TOOL_REGISTRATIONS) {
|
|
46
|
-
if (selectedToolIds && !selectedToolIds.has(registration.toolId))
|
|
47
|
-
continue;
|
|
48
|
-
registry.register(applyOverrides(registration));
|
|
49
|
-
}
|
|
50
|
-
}
|
|
51
|
-
/**
|
|
52
|
-
* Create a registry holding the packaged PIE capabilities.
|
|
53
|
-
*
|
|
54
|
-
* The tag map is installed through `setComponentOverrides` rather than read from
|
|
55
|
-
* a core default, so a registry composed without it resolves no packaged tags —
|
|
56
|
-
* which is the point: core no longer carries the catalogue.
|
|
57
|
-
*/
|
|
58
|
-
export function createPackagedToolRegistry(options = {}) {
|
|
59
|
-
const registry = new ToolRegistry();
|
|
60
|
-
registerPackagedTools(registry, {
|
|
61
|
-
toolIds: options.toolIds,
|
|
62
|
-
applyOverrides: (registration) => options.overrides?.[registration.toolId] ?? registration,
|
|
63
|
-
});
|
|
64
|
-
if (options.toolModuleLoaders &&
|
|
65
|
-
Object.keys(options.toolModuleLoaders).length > 0) {
|
|
66
|
-
registry.setToolModuleLoaders(options.toolModuleLoaders);
|
|
67
|
-
}
|
|
68
|
-
registry.setComponentOverrides({
|
|
69
|
-
toolTagMap: { ...PACKAGED_TOOL_TAG_MAP, ...(options.toolTagMap ?? {}) },
|
|
70
|
-
toolComponentFactory: options.toolComponentFactory,
|
|
71
|
-
toolComponentFactories: options.toolComponentFactories,
|
|
72
|
-
});
|
|
73
|
-
return registry;
|
|
74
|
-
}
|
|
75
|
-
/**
|
|
76
|
-
* Render order when several capabilities are visible at once.
|
|
77
|
-
*/
|
|
78
|
-
export const PACKAGED_TOOL_ORDER = [
|
|
79
|
-
// Global accessibility first
|
|
80
|
-
"theme",
|
|
81
|
-
// Common tools
|
|
82
|
-
"calculator",
|
|
83
|
-
"textToSpeech",
|
|
84
|
-
// Reading aids
|
|
85
|
-
"lineReader",
|
|
86
|
-
"annotationToolbar",
|
|
87
|
-
"highlighter",
|
|
88
|
-
// Interaction tools
|
|
89
|
-
"answerEliminator",
|
|
90
|
-
// Measurement tools
|
|
91
|
-
"ruler",
|
|
92
|
-
"protractor",
|
|
93
|
-
// Subject-specific
|
|
94
|
-
"graph",
|
|
95
|
-
"periodicTable",
|
|
96
|
-
];
|
|
1
|
+
export { createPackagedToolRegistry, PACKAGED_TOOL_ORDER, PACKAGED_TOOL_REGISTRATIONS, registerPackagedTools, } from "./packaged-capability-composition.js";
|
|
@@ -0,0 +1,75 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Audio transcript: the text of an audio prompt, rendered for the learners
|
|
3
|
+
* entitled to it.
|
|
4
|
+
*
|
|
5
|
+
* Two kinds of content wear the same shape, and the card says which:
|
|
6
|
+
*
|
|
7
|
+
* - `visibility: "always"` is authored presentation. The item family was
|
|
8
|
+
* designed to be delivered with its transcript on screen — Star Early
|
|
9
|
+
* Literacy sentence items, for instance — so no profile grants it and none
|
|
10
|
+
* revokes it.
|
|
11
|
+
* - anything else, `"onGrant"` included, is the accommodation. Policy decides
|
|
12
|
+
* against the `transcript` support id, and silence means no. For the three
|
|
13
|
+
* Star families where a visible transcript turns the item into a reading
|
|
14
|
+
* task, that gate is the whole point.
|
|
15
|
+
*
|
|
16
|
+
* The toolkit renders the text, not the element. Before this, the transcript rode
|
|
17
|
+
* on `model.audioTranscript` and `mc-populated-blank` revealed its own copy when
|
|
18
|
+
* an ancestor carried `.rli-with-audio-transcript` — which made delivering an
|
|
19
|
+
* accommodation the host's job, required every element carrying audio to
|
|
20
|
+
* reimplement the reveal, and put an element-specific CSS class in the contract.
|
|
21
|
+
* Rendering here is the same shape signing already has, and it is what makes one
|
|
22
|
+
* mechanism serve braille, simplified-language and the rest.
|
|
23
|
+
*
|
|
24
|
+
* No `aria-describedby` back to the element's audio control, deliberately. A
|
|
25
|
+
* description is announced as a flat string when a control takes focus, so
|
|
26
|
+
* pointing one at a multi-sentence transcript is worse to listen to than reading
|
|
27
|
+
* order: this renders a labelled region immediately before the content, where a
|
|
28
|
+
* screen-reader user meets it on the way to the control it belongs to.
|
|
29
|
+
*
|
|
30
|
+
* It ships in the packaged set, unlike signing, because its presentation half has
|
|
31
|
+
* to work with no host opt-in: an item authored to show its transcript must show
|
|
32
|
+
* it in every player, and a deployment that forgot an import would silently
|
|
33
|
+
* deliver a designed-for reading support as nothing. The accommodation half is
|
|
34
|
+
* still policy-gated exactly as signing is, and `transcript` is deliberately
|
|
35
|
+
* absent from the universal preset — a content-dependent support never belongs in
|
|
36
|
+
* a wholesale grant.
|
|
37
|
+
*/
|
|
38
|
+
import type { ToolContentDependencyContext, ToolRegistration } from "@pie-players/pie-assessment-toolkit/tools/internal";
|
|
39
|
+
/** QTI 3.0 / AfA support id gating an audio transcript. */
|
|
40
|
+
export declare const AUDIO_TRANSCRIPT_FEATURE_ID = "transcript";
|
|
41
|
+
/** Catalog type carrying the transcript text. */
|
|
42
|
+
export declare const AUDIO_TRANSCRIPT_CATALOG_TYPE = "transcript";
|
|
43
|
+
/** Accessible name of the rendered region, and its class hook for themes. */
|
|
44
|
+
export declare const AUDIO_TRANSCRIPT_REGION_LABEL = "Transcript";
|
|
45
|
+
export declare const AUDIO_TRANSCRIPT_REGION_CLASS = "pie-tool-audio-transcript";
|
|
46
|
+
/** The transcript to render, and why it is being rendered. */
|
|
47
|
+
export interface ResolvedAudioTranscript {
|
|
48
|
+
catalogId: string;
|
|
49
|
+
text: string;
|
|
50
|
+
language?: string;
|
|
51
|
+
/** True when the card declares itself authored presentation. */
|
|
52
|
+
always: boolean;
|
|
53
|
+
}
|
|
54
|
+
/**
|
|
55
|
+
* The transcript an entity carries, or `null`.
|
|
56
|
+
*
|
|
57
|
+
* Read from the owner snapshot the resolver produced. Item/passage/model
|
|
58
|
+
* traversal and registration precedence have already been applied, so this
|
|
59
|
+
* capability owns only transcript interpretation.
|
|
60
|
+
*
|
|
61
|
+
* The cards are read directly rather than through `AccessibilityCatalogResolver`,
|
|
62
|
+
* which flattens a card to type/language/content and so cannot carry
|
|
63
|
+
* `visibility` — the one attribute this decision turns on. Nothing is lost by it:
|
|
64
|
+
* the resolver's value is choosing between languages of the same alternate, and a
|
|
65
|
+
* transcript is in the language of the audio it transcribes, one per prompt.
|
|
66
|
+
*/
|
|
67
|
+
export declare function resolveAudioTranscript(context: ToolContentDependencyContext): ResolvedAudioTranscript | null;
|
|
68
|
+
/**
|
|
69
|
+
* Host surface this capability fills: the full-width slot above a card's content.
|
|
70
|
+
*
|
|
71
|
+
* Item cards and passage cards open the same surface, so declaring it once
|
|
72
|
+
* reaches both — a passage can carry an audio prompt as an item can.
|
|
73
|
+
*/
|
|
74
|
+
export declare const CONTENT_LEAD_SURFACE = "content-lead";
|
|
75
|
+
export declare const audioTranscriptRegistration: ToolRegistration;
|