@pie-players/pie-default-tool-loaders 0.3.63 → 0.3.65
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 +80 -7
- package/dist/index.d.ts +11 -0
- package/dist/index.js +12 -0
- package/dist/packaged-tool-registry.d.ts +52 -0
- package/dist/packaged-tool-registry.js +96 -0
- package/dist/registrations/accessibility-tools.d.ts +34 -0
- package/dist/registrations/accessibility-tools.js +256 -0
- package/dist/registrations/calculator.d.ts +20 -0
- package/dist/registrations/calculator.js +228 -0
- package/dist/registrations/interaction-tools.d.ts +27 -0
- package/dist/registrations/interaction-tools.js +143 -0
- package/dist/registrations/measurement-tools.d.ts +24 -0
- package/dist/registrations/measurement-tools.js +130 -0
- package/dist/registrations/subject-specific-tools.d.ts +27 -0
- package/dist/registrations/subject-specific-tools.js +158 -0
- package/dist/registrations/tts.d.ts +21 -0
- package/dist/registrations/tts.js +184 -0
- package/dist/tool-placement.d.ts +29 -0
- package/dist/tool-placement.js +52 -0
- package/dist/tool-tag-map.d.ts +16 -0
- package/dist/tool-tag-map.js +27 -0
- package/dist/universal-supports.d.ts +33 -0
- package/dist/universal-supports.js +77 -0
- package/package.json +15 -13
package/README.md
CHANGED
|
@@ -1,24 +1,97 @@
|
|
|
1
1
|
# PIE Default Tool Loaders
|
|
2
2
|
|
|
3
|
-
|
|
3
|
+
Composition layer for the packaged PIE assessment tools: which capabilities exist
|
|
4
|
+
in a deployment, and how a program tiers them.
|
|
4
5
|
|
|
5
|
-
|
|
6
|
+
It owns the concrete `pie-tool-*` dependencies so toolkit core can stay
|
|
7
|
+
dependency-light and cycle-safe, and it is the layer above core — core knows
|
|
8
|
+
`featureId`, placement levels, activation kinds and precedence rules, and knows
|
|
9
|
+
no capability ids.
|
|
10
|
+
|
|
11
|
+
It owns four things, all answers to "which capabilities does this deployment have
|
|
12
|
+
and how does the program tier them":
|
|
13
|
+
|
|
14
|
+
| Export | What it decides |
|
|
15
|
+
| --- | --- |
|
|
16
|
+
| `PACKAGED_TOOL_REGISTRATIONS`, `createPackagedToolRegistry`, `registerPackagedTools` | Which capabilities exist, and their toolbar and surface contracts |
|
|
17
|
+
| `PACKAGED_TOOL_TAG_MAP` | Which custom element each one renders as |
|
|
18
|
+
| `PACKAGED_TOOL_PLACEMENT`, `SECTION_PLAYER_PREFERRED_TOOL_PLACEMENT`, `PACKAGED_TOOL_ORDER` | Where they appear and in what order |
|
|
19
|
+
| `UNIVERSAL_SUPPORTS_PRESET`, `createUniversalPersonalNeedsProfile` | Which of their support ids the program grants to everyone |
|
|
20
|
+
| `DEFAULT_TOOL_MODULE_LOADERS`, `registerSectionToolModuleLoaders` | When each one's bundle loads |
|
|
21
|
+
|
|
22
|
+
The individual registrations are exported too, so a host can compose its own set
|
|
23
|
+
rather than take the packaged one whole.
|
|
6
24
|
|
|
7
25
|
## Usage
|
|
8
26
|
|
|
9
27
|
```ts
|
|
10
|
-
import { createDefaultToolRegistry } from "@pie-players/pie-assessment-toolkit";
|
|
11
28
|
import {
|
|
29
|
+
createPackagedToolRegistry,
|
|
12
30
|
DEFAULT_TOOL_MODULE_LOADERS,
|
|
13
|
-
registerSectionToolModuleLoaders,
|
|
14
31
|
} from "@pie-players/pie-default-tool-loaders";
|
|
15
32
|
|
|
16
|
-
//
|
|
17
|
-
const registry =
|
|
33
|
+
// The packaged capability set, lazily loaded.
|
|
34
|
+
const registry = createPackagedToolRegistry({
|
|
18
35
|
toolModuleLoaders: DEFAULT_TOOL_MODULE_LOADERS,
|
|
19
36
|
});
|
|
37
|
+
```
|
|
38
|
+
|
|
39
|
+
`createDefaultToolRegistry()` in the toolkit is the other end of that choice: it
|
|
40
|
+
builds an empty registry, and a host composing its own set registers into it.
|
|
20
41
|
|
|
21
|
-
|
|
42
|
+
```ts
|
|
43
|
+
import { createDefaultToolRegistry } from "@pie-players/pie-assessment-toolkit";
|
|
44
|
+
import {
|
|
45
|
+
calculatorToolRegistration,
|
|
46
|
+
registerSectionToolModuleLoaders,
|
|
47
|
+
ttsToolRegistration,
|
|
48
|
+
} from "@pie-players/pie-default-tool-loaders";
|
|
49
|
+
|
|
50
|
+
const registry = createDefaultToolRegistry({
|
|
51
|
+
registrations: [calculatorToolRegistration, ttsToolRegistration],
|
|
52
|
+
});
|
|
53
|
+
// Section-only loaders, for section toolbar bootstrap points.
|
|
22
54
|
registerSectionToolModuleLoaders(registry);
|
|
23
55
|
```
|
|
24
56
|
|
|
57
|
+
## Accommodations are not in the packaged set
|
|
58
|
+
|
|
59
|
+
A capability declaring `requiresAuthoredContent` is absent from
|
|
60
|
+
`PACKAGED_TOOL_REGISTRATIONS` and its support ids from
|
|
61
|
+
`UNIVERSAL_SUPPORTS_PRESET`. Signing is the shipped example: install
|
|
62
|
+
`@pie-players/pie-tool-sign-language` and register it, which is the same two lines
|
|
63
|
+
a host writes for a capability of its own.
|
|
64
|
+
|
|
65
|
+
```ts
|
|
66
|
+
import { signLanguageRegistration } from "@pie-players/pie-tool-sign-language";
|
|
67
|
+
|
|
68
|
+
registry.register(signLanguageRegistration);
|
|
69
|
+
```
|
|
70
|
+
|
|
71
|
+
## Universal supports preset
|
|
72
|
+
|
|
73
|
+
`createUniversalPersonalNeedsProfile()` builds a `PersonalNeedsProfile` granting
|
|
74
|
+
`UNIVERSAL_SUPPORTS_PRESET` — the support ids the packaged tool set treats as
|
|
75
|
+
universal features.
|
|
76
|
+
|
|
77
|
+
```ts
|
|
78
|
+
import { createUniversalPersonalNeedsProfile } from "@pie-players/pie-default-tool-loaders";
|
|
79
|
+
|
|
80
|
+
const section = {
|
|
81
|
+
...authoredSection,
|
|
82
|
+
personalNeedsProfile: createUniversalPersonalNeedsProfile(),
|
|
83
|
+
};
|
|
84
|
+
```
|
|
85
|
+
|
|
86
|
+
The core ships no populated default — `createEmptyPersonalNeedsProfile()` in
|
|
87
|
+
`@pie-players/pie-assessment-toolkit` grants nothing. Which capabilities a
|
|
88
|
+
deployment grants by default is a property of the program, not of a capability:
|
|
89
|
+
TTS is a universal feature in one program and a documented accommodation in
|
|
90
|
+
another. So the preset is data to adopt, extend or replace alongside the district
|
|
91
|
+
and test-administration configuration, and it deliberately excludes any
|
|
92
|
+
capability that declares a content dependency.
|
|
93
|
+
|
|
94
|
+
A section carrying no profile is left alone. `pnpEnforcement` auto-detection
|
|
95
|
+
engages on real host policy material, so supplying no profile means placement
|
|
96
|
+
alone decides which tools appear.
|
|
97
|
+
|
package/dist/index.d.ts
CHANGED
|
@@ -1,3 +1,14 @@
|
|
|
1
|
+
export { UNIVERSAL_SUPPORTS_PRESET, createUniversalPersonalNeedsProfile, } from "./universal-supports.js";
|
|
2
|
+
export type { PackagedToolRegistryOptions, RegisterPackagedToolsOptions, } from "./packaged-tool-registry.js";
|
|
3
|
+
export { createPackagedToolRegistry, PACKAGED_TOOL_ORDER, PACKAGED_TOOL_REGISTRATIONS, registerPackagedTools, } from "./packaged-tool-registry.js";
|
|
4
|
+
export { PACKAGED_TOOL_TAG_MAP } from "./tool-tag-map.js";
|
|
5
|
+
export { PACKAGED_TOOL_PLACEMENT, SECTION_PLAYER_PREFERRED_TOOL_PLACEMENT, } from "./tool-placement.js";
|
|
6
|
+
export { annotationToolbarRegistration, lineReaderToolRegistration, themeToolRegistration, } from "./registrations/accessibility-tools.js";
|
|
7
|
+
export { calculatorToolRegistration } from "./registrations/calculator.js";
|
|
8
|
+
export { answerEliminatorToolRegistration, highlighterToolRegistration, } from "./registrations/interaction-tools.js";
|
|
9
|
+
export { protractorToolRegistration, rulerToolRegistration, } from "./registrations/measurement-tools.js";
|
|
10
|
+
export { graphToolRegistration, periodicTableToolRegistration, } from "./registrations/subject-specific-tools.js";
|
|
11
|
+
export { ttsToolRegistration } from "./registrations/tts.js";
|
|
1
12
|
export type ToolModuleLoader = () => Promise<unknown>;
|
|
2
13
|
export interface ToolRegistryLike {
|
|
3
14
|
setToolModuleLoaders(loaders: Partial<Record<string, ToolModuleLoader>>): void;
|
package/dist/index.js
CHANGED
|
@@ -1,3 +1,15 @@
|
|
|
1
|
+
export { UNIVERSAL_SUPPORTS_PRESET, createUniversalPersonalNeedsProfile, } from "./universal-supports.js";
|
|
2
|
+
export { createPackagedToolRegistry, PACKAGED_TOOL_ORDER, PACKAGED_TOOL_REGISTRATIONS, registerPackagedTools, } from "./packaged-tool-registry.js";
|
|
3
|
+
export { PACKAGED_TOOL_TAG_MAP } from "./tool-tag-map.js";
|
|
4
|
+
export { PACKAGED_TOOL_PLACEMENT, SECTION_PLAYER_PREFERRED_TOOL_PLACEMENT, } from "./tool-placement.js";
|
|
5
|
+
// Individual registrations, for a host composing a subset rather than the whole
|
|
6
|
+
// packaged set.
|
|
7
|
+
export { annotationToolbarRegistration, lineReaderToolRegistration, themeToolRegistration, } from "./registrations/accessibility-tools.js";
|
|
8
|
+
export { calculatorToolRegistration } from "./registrations/calculator.js";
|
|
9
|
+
export { answerEliminatorToolRegistration, highlighterToolRegistration, } from "./registrations/interaction-tools.js";
|
|
10
|
+
export { protractorToolRegistration, rulerToolRegistration, } from "./registrations/measurement-tools.js";
|
|
11
|
+
export { graphToolRegistration, periodicTableToolRegistration, } from "./registrations/subject-specific-tools.js";
|
|
12
|
+
export { ttsToolRegistration } from "./registrations/tts.js";
|
|
1
13
|
const loadSideEffectModule = (load) => load().then(() => undefined);
|
|
2
14
|
function loadCalculatorModule() {
|
|
3
15
|
if (typeof globalThis !== "undefined" &&
|
|
@@ -0,0 +1,52 @@
|
|
|
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, 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"];
|
|
@@ -0,0 +1,96 @@
|
|
|
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
|
+
];
|
|
@@ -0,0 +1,34 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Accessibility Tools Registrations
|
|
3
|
+
*
|
|
4
|
+
* Registers tools for visual accessibility and reading support:
|
|
5
|
+
* - Line Reader (reading guide)
|
|
6
|
+
* - Color Scheme (theme/contrast)
|
|
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
|
+
*/
|
|
13
|
+
import type { ToolRegistration } from "@pie-players/pie-assessment-toolkit/tools/internal";
|
|
14
|
+
/**
|
|
15
|
+
* Line Reader tool registration
|
|
16
|
+
*
|
|
17
|
+
* Provides a reading guide overlay to help track reading position.
|
|
18
|
+
* Useful for text-heavy passages and questions.
|
|
19
|
+
*/
|
|
20
|
+
export declare const lineReaderToolRegistration: ToolRegistration;
|
|
21
|
+
/**
|
|
22
|
+
* Theme tool registration
|
|
23
|
+
*
|
|
24
|
+
* Provides accessible theme and contrast controls.
|
|
25
|
+
* Global tool that affects entire assessment.
|
|
26
|
+
*/
|
|
27
|
+
export declare const themeToolRegistration: ToolRegistration;
|
|
28
|
+
/**
|
|
29
|
+
* Annotation Toolbar registration
|
|
30
|
+
*
|
|
31
|
+
* Text highlighting with CSS Custom Highlight API.
|
|
32
|
+
* Zero DOM mutation, optimal performance.
|
|
33
|
+
*/
|
|
34
|
+
export declare const annotationToolbarRegistration: ToolRegistration;
|
|
@@ -0,0 +1,256 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Accessibility Tools Registrations
|
|
3
|
+
*
|
|
4
|
+
* Registers tools for visual accessibility and reading support:
|
|
5
|
+
* - Line Reader (reading guide)
|
|
6
|
+
* - Color Scheme (theme/contrast)
|
|
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
|
+
*/
|
|
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";
|
|
16
|
+
/**
|
|
17
|
+
* Line Reader tool registration
|
|
18
|
+
*
|
|
19
|
+
* Provides a reading guide overlay to help track reading position.
|
|
20
|
+
* Useful for text-heavy passages and questions.
|
|
21
|
+
*/
|
|
22
|
+
export const lineReaderToolRegistration = {
|
|
23
|
+
toolId: "lineReader",
|
|
24
|
+
name: "Line Reader",
|
|
25
|
+
description: "Reading guide overlay",
|
|
26
|
+
icon: "bars-3",
|
|
27
|
+
// Line reader appears where there's text to read
|
|
28
|
+
supportedLevels: ["section", "passage", "rubric", "item"],
|
|
29
|
+
// PNP support IDs
|
|
30
|
+
// Maps to QTI 3.0 standard features: readingMask, readingGuide, readingRuler
|
|
31
|
+
pnpSupportIds: [
|
|
32
|
+
"readingMask", // QTI 3.0 standard (reading.readingMask)
|
|
33
|
+
"readingGuide", // QTI 3.0 standard (reading.readingGuide)
|
|
34
|
+
"readingRuler", // QTI 3.0 standard (reading.readingRuler)
|
|
35
|
+
"lineReader", // Common variant
|
|
36
|
+
"trackingGuide", // Common variant
|
|
37
|
+
],
|
|
38
|
+
/**
|
|
39
|
+
* Pass 2: Line reader is relevant when readable text is present
|
|
40
|
+
*/
|
|
41
|
+
isVisibleInContext(context) {
|
|
42
|
+
return hasReadableText(context);
|
|
43
|
+
},
|
|
44
|
+
renderToolbar(context, toolbarContext) {
|
|
45
|
+
const visibility = createScopedVisibilityBinding(this.toolId, toolbarContext);
|
|
46
|
+
const button = {
|
|
47
|
+
toolId: this.toolId,
|
|
48
|
+
label: this.name,
|
|
49
|
+
icon: typeof this.icon === "function" ? this.icon(context) : this.icon,
|
|
50
|
+
disabled: false,
|
|
51
|
+
ariaLabel: "Line reader - Reading guide",
|
|
52
|
+
tooltip: "Line Reader",
|
|
53
|
+
onClick: () => toolbarContext.toggleTool(this.toolId),
|
|
54
|
+
active: visibility.isActive(),
|
|
55
|
+
};
|
|
56
|
+
const componentOverrides = toolbarContext.componentOverrides ?? {};
|
|
57
|
+
const overlay = createToolElement(this.toolId, context, toolbarContext, componentOverrides);
|
|
58
|
+
overlay.setAttribute("tool-id", visibility.fullToolId);
|
|
59
|
+
applyOverlaySurface(overlay, "frameless");
|
|
60
|
+
return {
|
|
61
|
+
toolId: this.toolId,
|
|
62
|
+
button,
|
|
63
|
+
elements: [{ element: overlay, mount: "after-buttons" }],
|
|
64
|
+
sync: () => {
|
|
65
|
+
syncButtonAndOverlayVisibility({
|
|
66
|
+
button,
|
|
67
|
+
overlay,
|
|
68
|
+
isActive: visibility.isActive,
|
|
69
|
+
});
|
|
70
|
+
if (toolbarContext.toolkitCoordinator) {
|
|
71
|
+
overlay.toolkitCoordinator = toolbarContext.toolkitCoordinator;
|
|
72
|
+
}
|
|
73
|
+
},
|
|
74
|
+
subscribeActive: visibility.subscribeActive,
|
|
75
|
+
};
|
|
76
|
+
},
|
|
77
|
+
};
|
|
78
|
+
/**
|
|
79
|
+
* Theme tool registration
|
|
80
|
+
*
|
|
81
|
+
* Provides accessible theme and contrast controls.
|
|
82
|
+
* Global tool that affects entire assessment.
|
|
83
|
+
*/
|
|
84
|
+
export const themeToolRegistration = {
|
|
85
|
+
toolId: "theme",
|
|
86
|
+
name: "Theme",
|
|
87
|
+
description: "Accessible themes and contrast",
|
|
88
|
+
icon: "swatch",
|
|
89
|
+
// Color scheme is assessment-wide
|
|
90
|
+
supportedLevels: ["assessment", "section"],
|
|
91
|
+
// PNP support IDs
|
|
92
|
+
// Maps to QTI 3.0 standard features: highContrastDisplay, colorContrast, invertColors
|
|
93
|
+
pnpSupportIds: [
|
|
94
|
+
"highContrastDisplay", // QTI 3.0 standard (visual.highContrastDisplay)
|
|
95
|
+
"colorContrast", // QTI 3.0 standard (visual.colorContrast)
|
|
96
|
+
"invertColors", // QTI 3.0 standard (visual.invertColors)
|
|
97
|
+
"theme", // Canonical id
|
|
98
|
+
"highContrast", // Common variant
|
|
99
|
+
"customColors", // Common variant
|
|
100
|
+
],
|
|
101
|
+
/**
|
|
102
|
+
* Pass 2: Color scheme is always relevant when allowed
|
|
103
|
+
*/
|
|
104
|
+
isVisibleInContext(context) {
|
|
105
|
+
return true; // Always show if allowed by orchestrator
|
|
106
|
+
},
|
|
107
|
+
renderToolbar(context, toolbarContext) {
|
|
108
|
+
const visibility = createScopedVisibilityBinding(this.toolId, toolbarContext);
|
|
109
|
+
const button = {
|
|
110
|
+
toolId: this.toolId,
|
|
111
|
+
label: this.name,
|
|
112
|
+
icon: typeof this.icon === "function" ? this.icon(context) : this.icon,
|
|
113
|
+
disabled: false,
|
|
114
|
+
ariaLabel: "Theme - Change colors and contrast",
|
|
115
|
+
tooltip: "Theme",
|
|
116
|
+
onClick: () => toolbarContext.toggleTool(this.toolId),
|
|
117
|
+
active: visibility.isActive(),
|
|
118
|
+
};
|
|
119
|
+
const componentOverrides = toolbarContext.componentOverrides ?? {};
|
|
120
|
+
const overlay = createToolElement(this.toolId, context, toolbarContext, componentOverrides);
|
|
121
|
+
overlay.setAttribute("tool-id", visibility.fullToolId);
|
|
122
|
+
return {
|
|
123
|
+
toolId: this.toolId,
|
|
124
|
+
button,
|
|
125
|
+
elements: [
|
|
126
|
+
{
|
|
127
|
+
element: overlay,
|
|
128
|
+
mount: "after-buttons",
|
|
129
|
+
shell: {
|
|
130
|
+
title: this.name,
|
|
131
|
+
draggable: true,
|
|
132
|
+
resizable: false,
|
|
133
|
+
closeable: true,
|
|
134
|
+
initialWidth: 520,
|
|
135
|
+
initialHeight: 380,
|
|
136
|
+
minWidth: 420,
|
|
137
|
+
minHeight: 300,
|
|
138
|
+
},
|
|
139
|
+
},
|
|
140
|
+
],
|
|
141
|
+
sync: () => {
|
|
142
|
+
syncButtonAndOverlayVisibility({
|
|
143
|
+
button,
|
|
144
|
+
overlay,
|
|
145
|
+
isActive: visibility.isActive,
|
|
146
|
+
});
|
|
147
|
+
if (toolbarContext.toolkitCoordinator) {
|
|
148
|
+
overlay.toolkitCoordinator = toolbarContext.toolkitCoordinator;
|
|
149
|
+
}
|
|
150
|
+
},
|
|
151
|
+
subscribeActive: visibility.subscribeActive,
|
|
152
|
+
};
|
|
153
|
+
},
|
|
154
|
+
};
|
|
155
|
+
/**
|
|
156
|
+
* Annotation Toolbar registration
|
|
157
|
+
*
|
|
158
|
+
* Text highlighting with CSS Custom Highlight API.
|
|
159
|
+
* Zero DOM mutation, optimal performance.
|
|
160
|
+
*/
|
|
161
|
+
export const annotationToolbarRegistration = {
|
|
162
|
+
toolId: "annotationToolbar",
|
|
163
|
+
name: "Highlighter",
|
|
164
|
+
description: "Highlight and annotate text",
|
|
165
|
+
icon: "highlighter",
|
|
166
|
+
activation: "selection-gateway",
|
|
167
|
+
singletonScope: "section",
|
|
168
|
+
/**
|
|
169
|
+
* Section-scoped singleton surface. The gateway used to be mounted by
|
|
170
|
+
* `PieSectionPlayerBaseElement.svelte`, which named this tool id in three
|
|
171
|
+
* places — the policy check, the module load and the element — so no host
|
|
172
|
+
* could contribute a second section-scoped capability. Declaring the surface
|
|
173
|
+
* moves that wiring into this registration, and the renderer discovers it
|
|
174
|
+
* through `ToolRegistry.getToolsBySurface("section-overlay")`.
|
|
175
|
+
*/
|
|
176
|
+
surfaces: ["section-overlay"],
|
|
177
|
+
// Annotation appears where there's text content
|
|
178
|
+
supportedLevels: ["passage", "rubric", "item", "element"],
|
|
179
|
+
// PNP support IDs
|
|
180
|
+
// Maps to QTI 3.0 standard features: highlighting, annotations
|
|
181
|
+
pnpSupportIds: [
|
|
182
|
+
"highlighting", // QTI 3.0 standard (cognitive.highlighting / reading.wordHighlighting)
|
|
183
|
+
"annotations", // QTI 3.0 standard (cognitive.annotations)
|
|
184
|
+
"highlighter", // Common variant
|
|
185
|
+
"textHighlight", // Common variant
|
|
186
|
+
"annotation", // Common variant
|
|
187
|
+
],
|
|
188
|
+
/**
|
|
189
|
+
* Pass 2: Annotation is relevant when readable text is present
|
|
190
|
+
*/
|
|
191
|
+
isVisibleInContext(context) {
|
|
192
|
+
return hasReadableText(context);
|
|
193
|
+
},
|
|
194
|
+
/**
|
|
195
|
+
* Mount the section-scoped gateway. The element positions itself (`position:
|
|
196
|
+
* fixed` inside its shadow root) and finds its scope through the toolkit's
|
|
197
|
+
* context, which bubbles from wherever the host mounted it, so this needs to
|
|
198
|
+
* know nothing about the host's layout.
|
|
199
|
+
*/
|
|
200
|
+
renderSurface(context) {
|
|
201
|
+
const componentOverrides = context.componentOverrides ?? {};
|
|
202
|
+
const tagName = resolveToolTag(context.toolId, componentOverrides);
|
|
203
|
+
if (typeof customElements !== "undefined" && !customElements.get(tagName)) {
|
|
204
|
+
// The host loads the module before mounting, so reaching here means the
|
|
205
|
+
// optional package is absent. Declining is the right answer: mounting an
|
|
206
|
+
// undefined element would render an empty box the learner cannot use.
|
|
207
|
+
return null;
|
|
208
|
+
}
|
|
209
|
+
const element = document.createElement(tagName);
|
|
210
|
+
// Reads the context it is handed. These were reactive props before the
|
|
211
|
+
// gateway moved behind `renderSurface`, and a host calling
|
|
212
|
+
// `updateAssessment(...)` mid-session swaps the coordinator without
|
|
213
|
+
// remounting — closing over the render-time services would leave the gateway
|
|
214
|
+
// highlighting into the previous session's coordinator.
|
|
215
|
+
const applyServices = (current) => {
|
|
216
|
+
element.enabled = true;
|
|
217
|
+
element.ttsService = current.services.ttsService;
|
|
218
|
+
element.highlightCoordinator =
|
|
219
|
+
current.services.toolkitCoordinator?.highlightCoordinator ?? null;
|
|
220
|
+
};
|
|
221
|
+
applyServices(context);
|
|
222
|
+
return { element, sync: applyServices };
|
|
223
|
+
},
|
|
224
|
+
renderToolbar(context, toolbarContext) {
|
|
225
|
+
const visibility = createScopedVisibilityBinding(this.toolId, toolbarContext);
|
|
226
|
+
const button = {
|
|
227
|
+
toolId: this.toolId,
|
|
228
|
+
label: this.name,
|
|
229
|
+
icon: typeof this.icon === "function" ? this.icon(context) : this.icon,
|
|
230
|
+
disabled: false,
|
|
231
|
+
ariaLabel: "Annotation toolbar - Highlight text",
|
|
232
|
+
tooltip: "Highlight",
|
|
233
|
+
onClick: () => toolbarContext.toggleTool(this.toolId),
|
|
234
|
+
active: visibility.isActive(),
|
|
235
|
+
};
|
|
236
|
+
const componentOverrides = toolbarContext.componentOverrides ?? {};
|
|
237
|
+
const overlay = createToolElement(this.toolId, context, toolbarContext, componentOverrides);
|
|
238
|
+
overlay.setAttribute("tool-id", visibility.fullToolId);
|
|
239
|
+
return {
|
|
240
|
+
toolId: this.toolId,
|
|
241
|
+
button,
|
|
242
|
+
elements: [{ element: overlay, mount: "after-buttons" }],
|
|
243
|
+
sync: () => {
|
|
244
|
+
syncButtonAndOverlayVisibility({
|
|
245
|
+
button,
|
|
246
|
+
overlay,
|
|
247
|
+
isActive: visibility.isActive,
|
|
248
|
+
});
|
|
249
|
+
if (toolbarContext.toolkitCoordinator) {
|
|
250
|
+
overlay.toolkitCoordinator = toolbarContext.toolkitCoordinator;
|
|
251
|
+
}
|
|
252
|
+
},
|
|
253
|
+
subscribeActive: visibility.subscribeActive,
|
|
254
|
+
};
|
|
255
|
+
},
|
|
256
|
+
};
|
|
@@ -0,0 +1,20 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Calculator Tool Registration
|
|
3
|
+
*
|
|
4
|
+
* Registers the calculator tool with support for multiple calculator types
|
|
5
|
+
* (basic, scientific, graphing) via Desmos provider.
|
|
6
|
+
*
|
|
7
|
+
* Maps to QTI 3.0 standard access features:
|
|
8
|
+
* - calculator (cognitive support)
|
|
9
|
+
* - graphingCalculator (assessment tool)
|
|
10
|
+
*/
|
|
11
|
+
import type { ToolRegistration } from "@pie-players/pie-assessment-toolkit/tools/internal";
|
|
12
|
+
/**
|
|
13
|
+
* Calculator tool registration
|
|
14
|
+
*
|
|
15
|
+
* Supports:
|
|
16
|
+
* - Basic, scientific, and graphing calculators via Desmos
|
|
17
|
+
* - Context-aware visibility (shows only when math content is detected)
|
|
18
|
+
* - Item level only
|
|
19
|
+
*/
|
|
20
|
+
export declare const calculatorToolRegistration: ToolRegistration;
|