@pie-players/pie-default-tool-loaders 1.0.0-beta.0 → 1.0.0-beta.10

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 (30) hide show
  1. package/LICENSE +21 -0
  2. package/README.md +116 -12
  3. package/dist/afa-profile.d.ts +65 -0
  4. package/dist/afa-profile.js +135 -0
  5. package/dist/calculator-providers/LazyCalculatorToolProvider.d.ts +32 -18
  6. package/dist/calculator-providers/LazyCalculatorToolProvider.js +24 -12
  7. package/dist/calculator-providers/packaged-calculator-providers.js +26 -0
  8. package/dist/index.d.ts +7 -5
  9. package/dist/index.js +10 -5
  10. package/dist/packaged-capability-composition.js +11 -1
  11. package/dist/registrations/accessibility-tools.d.ts +8 -0
  12. package/dist/registrations/accessibility-tools.js +38 -0
  13. package/dist/registrations/audio-transcript.d.ts +0 -7
  14. package/dist/registrations/audio-transcript.js +1 -7
  15. package/dist/registrations/calculator.d.ts +16 -5
  16. package/dist/registrations/calculator.js +171 -176
  17. package/dist/registrations/interaction-tools.d.ts +15 -2
  18. package/dist/registrations/interaction-tools.js +110 -13
  19. package/dist/registrations/tts.d.ts +23 -2
  20. package/dist/registrations/tts.js +121 -93
  21. package/package.json +27 -25
  22. package/dist/calculator-providers/CortexToolProvider.d.ts +0 -10
  23. package/dist/calculator-providers/CortexToolProvider.js +0 -18
  24. package/dist/calculator-providers/DesmosToolProvider.d.ts +0 -11
  25. package/dist/calculator-providers/DesmosToolProvider.js +0 -18
  26. package/dist/calculator-providers/GeoGebraToolProvider.d.ts +0 -13
  27. package/dist/calculator-providers/GeoGebraToolProvider.js +0 -18
  28. package/dist/registrations/overlay-element-cache.d.ts +0 -23
  29. package/dist/registrations/overlay-toolbar-render.d.ts +0 -33
  30. package/dist/registrations/selection-actions.d.ts +0 -24
@@ -4,12 +4,100 @@
4
4
  * Registers tools for interacting with question content:
5
5
  * - Answer Eliminator (strike through answer choices)
6
6
  */
7
- import { hasChoiceInteraction } from "@pie-players/pie-assessment-toolkit/tools/registration";
7
+ import { elementSupports } from "@pie-players/pie-assessment-toolkit/tools/registration";
8
8
  import { createToolElement, } from "@pie-players/pie-assessment-toolkit/tools/registration";
9
9
  import { createScopedVisibilityBinding, syncButtonAndOverlayVisibility, } from "@pie-players/pie-assessment-toolkit/tools/registration";
10
10
  import { resolveOverlayElement } from "./overlay-element-cache.js";
11
11
  /** The policy parameters' `strategy`, defaulting to strikethrough. */
12
12
  const normalizeEliminationStrategy = (value) => value === "mask" ? "mask" : "strikethrough";
13
+ /** The AfA PNP 3.0 support term an element declares to take the eliminator. */
14
+ const ANSWER_MASKING = "answer-masking";
15
+ /**
16
+ * pie-item contract compatibility: legacy pie-elements, and pie-elements-ng
17
+ * releases from before elements declared their supports, render the markup the
18
+ * eliminator's built-in adapters read for these two. An element that declares
19
+ * its supports is decided by its declaration, these two included.
20
+ */
21
+ const UNDECLARED_ANSWER_MASKING_ELEMENTS = new Set(["multiple-choice", "ebsr"]);
22
+ function elementName(tag) {
23
+ return tag
24
+ .toLowerCase()
25
+ .replace(/--version-[0-9a-z-]+$/, "")
26
+ .replace(/^pie-(element-)?/, "");
27
+ }
28
+ // Content names one element several ways: `multiple-choice`,
29
+ // `pie-multiple-choice`, `pie-element-multiple-choice`, a runtime `--version-*`
30
+ // tag, or any tag the item's `elements` map binds to `@pie-element/multiple-choice`.
31
+ function elementNames(tag, packageSpec) {
32
+ const names = [elementName(tag)];
33
+ const packageName = pieElementPackageName(packageSpec);
34
+ if (packageName)
35
+ names.push(packageName);
36
+ return names;
37
+ }
38
+ function pieElementPackageName(packageSpec) {
39
+ return packageSpec?.match(/^@pie-element\/([^@]+)/)?.[1]?.toLowerCase() ?? null;
40
+ }
41
+ /**
42
+ * The name an `elements` list matches: the `@pie-element/<name>` package the
43
+ * item binds the tag to, else the tag's own name. A tag bound to another
44
+ * package matches no name, whatever the tag says.
45
+ */
46
+ function listedName(tag, packageSpec) {
47
+ return packageSpec ? pieElementPackageName(packageSpec) : elementName(tag);
48
+ }
49
+ /**
50
+ * The element names `config.elements` allows, or `null` for every element. An
51
+ * `elements` that is not a list allows none: validation reports it, and an
52
+ * element a host has not vetted stays without the eliminator.
53
+ */
54
+ function allowedElementNames(config) {
55
+ const elements = config
56
+ ?.elements;
57
+ if (elements === undefined)
58
+ return null;
59
+ if (!Array.isArray(elements))
60
+ return new Set();
61
+ return new Set(elements
62
+ .filter((name) => typeof name === "string")
63
+ .map(elementName));
64
+ }
65
+ /**
66
+ * The model ids of the context's elements that support answer masking and the
67
+ * host config allows.
68
+ */
69
+ function answerMaskingElementIds(context, config) {
70
+ const allowed = allowedElementNames(config);
71
+ return elementSupports(context)
72
+ .filter(({ supports, tag, packageSpec }) => {
73
+ if (allowed) {
74
+ const name = listedName(tag, packageSpec);
75
+ if (name === null || !allowed.has(name))
76
+ return false;
77
+ }
78
+ return supports
79
+ ? supports.includes(ANSWER_MASKING)
80
+ : elementNames(tag, packageSpec).some((name) => UNDECLARED_ANSWER_MASKING_ELEMENTS.has(name));
81
+ })
82
+ .flatMap(({ elementId }) => (elementId ? [elementId] : []));
83
+ }
84
+ function validateAnswerEliminatorConfig(config) {
85
+ const { elements } = config;
86
+ if (elements === undefined)
87
+ return [];
88
+ if (Array.isArray(elements) &&
89
+ elements.every((name) => typeof name === "string" && name.trim() !== "")) {
90
+ return [];
91
+ }
92
+ return [
93
+ {
94
+ code: "tools.invalidProviderConfig",
95
+ severity: "error",
96
+ path: "providers.answerEliminator.elements",
97
+ message: '`elements` must be a list of element names, such as ["multiple-choice"].',
98
+ },
99
+ ];
100
+ }
13
101
  /** The state-store key of each PIE element in the item, by model id. */
14
102
  function resolveElementStateKeys(context, toolbarContext) {
15
103
  const keys = {};
@@ -29,7 +117,7 @@ function resolveElementStateKeys(context, toolbarContext) {
29
117
  * Answer Eliminator tool registration
30
118
  *
31
119
  * Allows students to strike through incorrect answer choices.
32
- * Only appears on multiple-choice style questions.
120
+ * Only appears on items with an element that supports answer masking.
33
121
  */
34
122
  export const answerEliminatorToolRegistration = {
35
123
  toolId: "answerEliminator",
@@ -39,22 +127,25 @@ export const answerEliminatorToolRegistration = {
39
127
  descriptionKey: "tools.answerEliminator.description",
40
128
  icon: "strikethrough",
41
129
  supportedLevels: ["item"],
130
+ validateConfig: validateAnswerEliminatorConfig,
42
131
  /**
43
- * Pass 2: Answer eliminator is relevant only for choice-based questions
132
+ * Pass 2: relevant where an element supports answer masking. An element
133
+ * declares it on its class, and the answer eliminator's README says what the
134
+ * element then supplies.
44
135
  */
45
136
  isVisibleInContext(context) {
46
- return hasChoiceInteraction(context);
137
+ return answerMaskingElementIds(context, null).length > 0;
47
138
  },
48
139
  /**
49
- * Pass 3: the same question, asked as a capability. Elimination controls are
50
- * rendered per choice, so an item with no choice interaction gives this tool
51
- * nothing to act on — `placement-ordering`, `categorize` and
52
- * `drag-in-the-blank` included, whose `choices` hold draggables the
53
- * eliminator cannot reach. Answering the relevance gate alone left the button
54
- * on those items for any learner whose profile grants answer masking.
140
+ * Pass 3: the same question, asked as a capability and narrowed to the
141
+ * elements the host config allows. Elimination controls are rendered per
142
+ * choice, so an item none of whose allowed elements supports answer masking
143
+ * gives this tool nothing to act on. Answering the relevance gate alone left
144
+ * the button on such items for any learner whose profile grants answer
145
+ * masking.
55
146
  */
56
- isApplicableToContent(context) {
57
- return hasChoiceInteraction(context);
147
+ isApplicableToContent(context, config) {
148
+ return answerMaskingElementIds(context, config).length > 0;
58
149
  },
59
150
  renderToolbar(context, toolbarContext) {
60
151
  const visibility = createScopedVisibilityBinding(this.toolId, toolbarContext);
@@ -65,7 +156,7 @@ export const answerEliminatorToolRegistration = {
65
156
  const button = {
66
157
  toolId: this.toolId,
67
158
  label: this.name,
68
- icon: '<svg xmlns="http://www.w3.org/2000/svg" viewBox="0 0 24 24" width="20" height="20" fill="currentColor" aria-hidden="true"><path d="M19,3H16.3H7.7H5A2,2 0 0,0 3,5V7.7V16.4V19A2,2 0 0,0 5,21H7.7H16.4H19A2,2 0 0,0 21,19V16.3V7.7V5A2,2 0 0,0 19,3M15.6,17L12,13.4L8.4,17L7,15.6L10.6,12L7,8.4L8.4,7L12,10.6L15.6,7L17,8.4L13.4,12L17,15.6L15.6,17Z"/></svg>',
159
+ icon: typeof this.icon === "function" ? this.icon(context) : this.icon,
69
160
  disabled: false,
70
161
  ariaLabel: toolbarContext.i18n.t("tools.answerEliminator.buttonA11y"),
71
162
  tooltip: toolbarContext.i18n.t("tools.answerEliminator.tooltip"),
@@ -83,6 +174,12 @@ export const answerEliminatorToolRegistration = {
83
174
  isActive: visibility.isActive,
84
175
  });
85
176
  overlay.elementStateKeys = resolveElementStateKeys(context, toolbarContext);
177
+ const config = toolbarContext.toolkitCoordinator?.getToolConfig(this.toolId) ??
178
+ null;
179
+ overlay.elementIds =
180
+ allowedElementNames(config) === null
181
+ ? undefined
182
+ : answerMaskingElementIds(context, config);
86
183
  },
87
184
  subscribeActive: visibility.subscribeActive,
88
185
  };
@@ -4,12 +4,33 @@
4
4
  * Registers the TTS tool for reading content aloud.
5
5
  */
6
6
  import type { ToolRegistration } from "@pie-players/pie-assessment-toolkit/tools/registration";
7
+ import { TTSToolProvider } from "@pie-players/pie-assessment-toolkit/tools/registration";
8
+ type TTSToolProviderOptions = NonNullable<ConstructorParameters<typeof TTSToolProvider>[1]>;
9
+ /** A host's own text-to-speech provider, selected by `provider.id`. */
10
+ export interface TTSHostProviderDescriptor {
11
+ /** Resolves the host's `ITTSProvider` class; imported only when selected. */
12
+ load: NonNullable<TTSToolProviderOptions["loadHostProvider"]>;
13
+ /** Wait on `provider.runtime.authFetcher` before initializing. Default `false`. */
14
+ requiresAuth?: boolean;
15
+ }
16
+ export interface TTSRegistrationOptions {
17
+ /**
18
+ * Host providers by `provider.id`. A `textToSpeech` config whose
19
+ * `provider.id` names none of them, or names none at all, keeps the browser
20
+ * or server backend its settings select.
21
+ */
22
+ providers?: Readonly<Record<string, TTSHostProviderDescriptor>>;
23
+ }
7
24
  /**
8
- * Text-to-Speech tool registration
25
+ * Builds the text-to-speech registration over the browser and server backends
26
+ * plus any host providers, so a host bundles its provider only by naming it.
9
27
  *
10
28
  * Supports:
11
- * - Reading content aloud using browser TTS or external providers
29
+ * - Reading content aloud using browser TTS, a TTS server or a host provider
12
30
  * - Context-aware visibility (shows when readable text is available)
13
31
  * - Item and passage levels
14
32
  */
33
+ export declare function createTTSToolRegistration(options?: TTSRegistrationOptions): ToolRegistration;
34
+ /** The text-to-speech registration with the browser and server backends only. */
15
35
  export declare const ttsToolRegistration: ToolRegistration;
36
+ export {};
@@ -11,107 +11,135 @@ import { resolveOverlayElement } from "./overlay-element-cache.js";
11
11
  // This package owns the server adapter's import, so the toolkit never names it
12
12
  // and a bundler building the toolkit alone has nothing to resolve.
13
13
  const loadServerTTSProvider = async () => (await import("@pie-players/tts-client-server")).ServerTTSProvider;
14
+ const numberOrUndefined = (value) => typeof value === "number" ? value : undefined;
15
+ /** The host-provider path, with the descriptor's auth requirement. */
16
+ class HostTTSToolProvider extends TTSToolProvider {
17
+ constructor(descriptor) {
18
+ super("browser", { loadHostProvider: descriptor.load });
19
+ this.requiresAuth = descriptor.requiresAuth === true;
20
+ }
21
+ }
22
+ const selectHostProvider = (config, providers) => {
23
+ const id = config?.provider?.id;
24
+ return typeof id === "string" && Object.hasOwn(providers, id)
25
+ ? providers[id]
26
+ : undefined;
27
+ };
14
28
  /**
15
- * Text-to-Speech tool registration
29
+ * Builds the text-to-speech registration over the browser and server backends
30
+ * plus any host providers, so a host bundles its provider only by naming it.
16
31
  *
17
32
  * Supports:
18
- * - Reading content aloud using browser TTS or external providers
33
+ * - Reading content aloud using browser TTS, a TTS server or a host provider
19
34
  * - Context-aware visibility (shows when readable text is available)
20
35
  * - Item and passage levels
21
36
  */
22
- export const ttsToolRegistration = {
23
- toolId: "textToSpeech",
24
- name: "Text to Speech",
25
- description: "Read content aloud",
26
- nameKey: "tools.textToSpeech.name",
27
- descriptionKey: "tools.textToSpeech.description",
28
- icon: "volume-up",
29
- provider: {
30
- createProvider: (config) => {
31
- return new TTSToolProvider(resolveTTSRuntimeSettings(config).backend, {
32
- loadServerProvider: loadServerTTSProvider,
33
- });
37
+ export function createTTSToolRegistration(options = {}) {
38
+ const providers = { ...options.providers };
39
+ return {
40
+ toolId: "textToSpeech",
41
+ name: "Text to Speech",
42
+ description: "Read content aloud",
43
+ nameKey: "tools.textToSpeech.name",
44
+ descriptionKey: "tools.textToSpeech.description",
45
+ icon: "volume-up",
46
+ provider: {
47
+ createProvider: (config) => {
48
+ const hostProvider = selectHostProvider(config, providers);
49
+ if (hostProvider)
50
+ return new HostTTSToolProvider(hostProvider);
51
+ return new TTSToolProvider(resolveTTSRuntimeSettings(config).backend, {
52
+ loadServerProvider: loadServerTTSProvider,
53
+ });
54
+ },
55
+ getInitConfig: (config) => buildRuntimeTTSConfig(resolveTTSRuntimeSettings(config)),
56
+ getAuthFetcher: (config) => {
57
+ const runtimeAuthFetcher = config?.provider?.runtime?.authFetcher;
58
+ return typeof runtimeAuthFetcher === "function"
59
+ ? runtimeAuthFetcher
60
+ : undefined;
61
+ },
62
+ lazy: true,
34
63
  },
35
- getInitConfig: (config) => buildRuntimeTTSConfig(resolveTTSRuntimeSettings(config)),
36
- getAuthFetcher: (config) => {
37
- const runtimeAuthFetcher = config?.provider?.runtime?.authFetcher;
38
- return typeof runtimeAuthFetcher === "function"
39
- ? runtimeAuthFetcher
40
- : undefined;
64
+ sanitizeConfig: (config) => {
65
+ const normalizedConfig = {
66
+ ...config,
67
+ };
68
+ if ("speedOptions" in normalizedConfig) {
69
+ normalizedConfig.speedOptions = normalizeTTSSpeedControlOptions(normalizedConfig.speedOptions);
70
+ }
71
+ return normalizedConfig;
41
72
  },
42
- lazy: true,
43
- },
44
- sanitizeConfig: (config) => {
45
- const normalizedConfig = {
46
- ...config,
47
- };
48
- if ("speedOptions" in normalizedConfig) {
49
- normalizedConfig.speedOptions = normalizeTTSSpeedControlOptions(normalizedConfig.speedOptions);
50
- }
51
- return normalizedConfig;
52
- },
53
- // TTS is inline-only and scoped to item/passage contexts.
54
- supportedLevels: ["item", "passage"],
55
- /**
56
- * Pass 2: Determine if TTS is relevant in this context
57
- *
58
- * TTS is relevant when the context holds readable text or a catalog idref.
59
- */
60
- isVisibleInContext(context) {
61
- return hasSpokenContent(context);
62
- },
63
- renderToolbar(context, toolbarContext) {
64
- const resolveRuntimeSettings = () => resolveTTSRuntimeSettings(toolbarContext.toolkitCoordinator?.getToolConfig(this.toolId) ||
65
- undefined);
66
- const resolveElementSpeedOptions = () => {
67
- const runtimeSettings = resolveRuntimeSettings();
68
- return normalizeTTSSpeedControlOptions(runtimeSettings.speedOptions);
69
- };
70
- const fullToolId = createScopedToolId(this.toolId, toolbarContext.scope.level, toolbarContext.scope.scopeId);
71
- const resolveControlSize = () => {
72
- const raw = toolbarContext.ui?.size;
73
- return raw === "sm" || raw === "lg" ? raw : "md";
74
- };
75
- const element = resolveOverlayElement(toolbarContext, fullToolId, () => createToolElement(this.toolId, context, toolbarContext, toolbarContext.componentOverrides));
76
- const applyAttributes = () => {
77
- element.setAttribute("catalog-id", toolbarContext.catalogId || toolbarContext.itemId);
78
- element.setAttribute("size", resolveControlSize());
79
- element.setAttribute("layout-mode", resolveRuntimeSettings().layoutMode);
80
- element.speedOptions = resolveElementSpeedOptions();
81
- element.showSingleSpeedOption =
82
- resolveRuntimeSettings().showSingleSpeedOption === true;
83
- };
84
- applyAttributes();
85
- const hostLayout = resolveTTSHostToolbarLayout(resolveRuntimeSettings());
86
- return {
87
- toolId: this.toolId,
88
- button: null,
89
- elements: [
90
- {
91
- element,
92
- mount: "before-buttons",
93
- layoutHints: {
94
- controlsRow: {
95
- reserveSpace: hostLayout.controlsRow.reserveSpace,
96
- showWhenToolActive: hostLayout.controlsRow.expandWhenToolActive,
97
- },
98
- headerOverlay: {
99
- showWhenToolActive: hostLayout.headerOverlay.expandWhenToolActive,
73
+ // TTS is inline-only and scoped to item/passage contexts.
74
+ supportedLevels: ["item", "passage"],
75
+ /**
76
+ * Pass 2: Determine if TTS is relevant in this context
77
+ *
78
+ * TTS is relevant when the context holds readable text or a catalog idref.
79
+ */
80
+ isVisibleInContext(context) {
81
+ return hasSpokenContent(context);
82
+ },
83
+ renderToolbar(context, toolbarContext) {
84
+ const resolveRuntimeSettings = () => resolveTTSRuntimeSettings(toolbarContext.toolkitCoordinator?.getToolConfig(this.toolId) ||
85
+ undefined);
86
+ const resolveElementSpeedOptions = () => {
87
+ const runtimeSettings = resolveRuntimeSettings();
88
+ return normalizeTTSSpeedControlOptions(runtimeSettings.speedOptions);
89
+ };
90
+ const fullToolId = createScopedToolId(this.toolId, toolbarContext.scope.level, toolbarContext.scope.scopeId);
91
+ const resolveControlSize = () => {
92
+ const raw = toolbarContext.ui?.size;
93
+ return raw === "sm" || raw === "lg" ? raw : "md";
94
+ };
95
+ const element = resolveOverlayElement(toolbarContext, fullToolId, () => createToolElement(this.toolId, context, toolbarContext, toolbarContext.componentOverrides));
96
+ const applyAttributes = () => {
97
+ element.setAttribute("catalog-id", toolbarContext.catalogId || toolbarContext.itemId);
98
+ element.setAttribute("size", resolveControlSize());
99
+ element.setAttribute("layout-mode", resolveRuntimeSettings().layoutMode);
100
+ element.speedOptions = resolveElementSpeedOptions();
101
+ element.showSingleSpeedOption =
102
+ resolveRuntimeSettings().showSingleSpeedOption === true;
103
+ // The element range-checks these; a non-number means the default.
104
+ const speech = toolbarContext.getToolParameters?.("textToSpeech");
105
+ element.baseRate = numberOrUndefined(speech?.rate);
106
+ element.pitch = numberOrUndefined(speech?.pitch);
107
+ element.volume = numberOrUndefined(speech?.volume);
108
+ };
109
+ applyAttributes();
110
+ const hostLayout = resolveTTSHostToolbarLayout(resolveRuntimeSettings());
111
+ return {
112
+ toolId: this.toolId,
113
+ button: null,
114
+ elements: [
115
+ {
116
+ element,
117
+ mount: "before-buttons",
118
+ layoutHints: {
119
+ controlsRow: {
120
+ reserveSpace: hostLayout.controlsRow.reserveSpace,
121
+ showWhenToolActive: hostLayout.controlsRow.expandWhenToolActive,
122
+ },
123
+ headerOverlay: {
124
+ showWhenToolActive: hostLayout.headerOverlay.expandWhenToolActive,
125
+ },
100
126
  },
101
127
  },
128
+ ],
129
+ subscribeActive: (callback) => {
130
+ const handler = (event) => {
131
+ const detail = event.detail;
132
+ callback(detail?.active === true);
133
+ };
134
+ element.addEventListener(TOOL_ACTIVE_CHANGE_EVENT, handler);
135
+ return () => {
136
+ element.removeEventListener(TOOL_ACTIVE_CHANGE_EVENT, handler);
137
+ };
102
138
  },
103
- ],
104
- subscribeActive: (callback) => {
105
- const handler = (event) => {
106
- const detail = event.detail;
107
- callback(detail?.active === true);
108
- };
109
- element.addEventListener(TOOL_ACTIVE_CHANGE_EVENT, handler);
110
- return () => {
111
- element.removeEventListener(TOOL_ACTIVE_CHANGE_EVENT, handler);
112
- };
113
- },
114
- sync: applyAttributes,
115
- };
116
- },
117
- };
139
+ sync: applyAttributes,
140
+ };
141
+ },
142
+ };
143
+ }
144
+ /** The text-to-speech registration with the browser and server backends only. */
145
+ export const ttsToolRegistration = createTTSToolRegistration();
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@pie-players/pie-default-tool-loaders",
3
- "version": "1.0.0-beta.0",
3
+ "version": "1.0.0-beta.10",
4
4
  "type": "module",
5
5
  "description": "Composition layer for the packaged PIE assessment tools: registrations, tag map, placement preset, universal and empty profiles, and lazy module loaders",
6
6
  "repository": {
@@ -17,15 +17,17 @@
17
17
  "exports": {
18
18
  ".": {
19
19
  "types": "./dist/index.d.ts",
20
- "import": "./dist/index.js"
21
- }
20
+ "import": "./dist/index.js",
21
+ "default": "./dist/index.js"
22
+ },
23
+ "./package.json": "./package.json"
22
24
  },
23
25
  "files": [
24
26
  "dist",
25
27
  "README.md"
26
28
  ],
27
29
  "scripts": {
28
- "build": "bun run check:composition && tsc -p tsconfig.json",
30
+ "build": "bun run check:composition && tsc -p tsconfig.json && bun ../../scripts/prune-unreachable-declarations.mjs",
29
31
  "check:composition": "bun test tests/packaged-capability-composition.test.ts",
30
32
  "dev": "tsc -p tsconfig.json --watch",
31
33
  "typecheck": "tsc -p tsconfig.json --noEmit",
@@ -33,29 +35,29 @@
33
35
  "test": "bun test"
34
36
  },
35
37
  "dependencies": {
36
- "@pie-players/pie-assessment-toolkit": "1.0.0-beta.0",
37
- "@pie-players/pie-calculator": "1.0.0-beta.0",
38
- "@pie-players/pie-calculator-cortex": "1.0.0-beta.0",
39
- "@pie-players/pie-calculator-desmos": "1.0.0-beta.0",
40
- "@pie-players/pie-calculator-geogebra": "1.0.0-beta.0",
41
- "@pie-players/pie-players-shared": "1.0.0-beta.0",
42
- "@pie-players/pie-tool-annotation-toolbar": "1.0.0-beta.0",
43
- "@pie-players/pie-tool-answer-eliminator": "1.0.0-beta.0",
44
- "@pie-players/pie-tool-calculator-shared": "1.0.0-beta.0",
45
- "@pie-players/pie-tool-dictionary": "1.0.0-beta.0",
46
- "@pie-players/pie-tool-graph": "1.0.0-beta.0",
47
- "@pie-players/pie-tool-line-reader": "1.0.0-beta.0",
48
- "@pie-players/pie-tool-periodic-table": "1.0.0-beta.0",
49
- "@pie-players/pie-tool-picture-dictionary": "1.0.0-beta.0",
50
- "@pie-players/pie-tool-protractor": "1.0.0-beta.0",
51
- "@pie-players/pie-tool-ruler": "1.0.0-beta.0",
52
- "@pie-players/pie-tool-theme": "1.0.0-beta.0",
53
- "@pie-players/pie-tool-tts-inline": "1.0.0-beta.0",
54
- "@pie-players/tts-client-server": "1.0.0-beta.0"
38
+ "@pie-players/pie-assessment-toolkit": "1.0.0-beta.10",
39
+ "@pie-players/pie-calculator": "1.0.0-beta.10",
40
+ "@pie-players/pie-calculator-desmos": "1.0.0-beta.10",
41
+ "@pie-players/pie-calculator-geogebra": "1.0.0-beta.10",
42
+ "@pie-players/pie-players-shared": "1.0.0-beta.10",
43
+ "@pie-players/pie-tool-annotation-toolbar": "1.0.0-beta.10",
44
+ "@pie-players/pie-tool-answer-eliminator": "1.0.0-beta.10",
45
+ "@pie-players/pie-tool-calculator-shared": "1.0.0-beta.10",
46
+ "@pie-players/pie-tool-dictionary": "1.0.0-beta.10",
47
+ "@pie-players/pie-tool-graph": "1.0.0-beta.10",
48
+ "@pie-players/pie-tool-line-reader": "1.0.0-beta.10",
49
+ "@pie-players/pie-tool-magnifier": "1.0.0-beta.10",
50
+ "@pie-players/pie-tool-periodic-table": "1.0.0-beta.10",
51
+ "@pie-players/pie-tool-picture-dictionary": "1.0.0-beta.10",
52
+ "@pie-players/pie-tool-protractor": "1.0.0-beta.10",
53
+ "@pie-players/pie-tool-ruler": "1.0.0-beta.10",
54
+ "@pie-players/pie-tool-theme": "1.0.0-beta.10",
55
+ "@pie-players/pie-tool-tts-inline": "1.0.0-beta.10",
56
+ "@pie-players/tts-client-server": "1.0.0-beta.10"
55
57
  },
56
58
  "devDependencies": {
57
- "@biomejs/biome": "^2.5.15",
58
- "@happy-dom/global-registrator": "^20.14.5",
59
+ "@biomejs/biome": "^2.6.4",
60
+ "@happy-dom/global-registrator": "^21.0.4",
59
61
  "typescript": "^5.9.3"
60
62
  },
61
63
  "homepage": "https://github.com/pie-framework/pie-players/tree/master/packages/default-tool-loaders#readme",
@@ -1,10 +0,0 @@
1
- /** Fully bundled open-source calculator adapter for the tool-provider registry. */
2
- import type { CalculatorToolProviderInitConfig, LazyCalculatorProviderDefinition } from "./LazyCalculatorToolProvider.js";
3
- import { LazyCalculatorToolProvider } from "./LazyCalculatorToolProvider.js";
4
- export type CortexToolProviderConfig = CalculatorToolProviderInitConfig;
5
- export declare class CortexToolProvider extends LazyCalculatorToolProvider<CortexToolProviderConfig> {
6
- readonly providerName = "PIE Open-Source Calculator";
7
- readonly version = "1";
8
- readonly requiresAuth = false;
9
- protected getDefinition(): LazyCalculatorProviderDefinition<CortexToolProviderConfig>;
10
- }
@@ -1,18 +0,0 @@
1
- /** Fully bundled open-source calculator adapter for the tool-provider registry. */
2
- import { LazyCalculatorToolProvider } from "./LazyCalculatorToolProvider.js";
3
- export class CortexToolProvider extends LazyCalculatorToolProvider {
4
- providerName = "PIE Open-Source Calculator";
5
- version = "1";
6
- requiresAuth = false;
7
- getDefinition() {
8
- return {
9
- backend: "cortex",
10
- moduleImportOperation: "cortex-provider-module-import",
11
- loadProvider: async () => {
12
- const module = await import("@pie-players/pie-calculator-cortex");
13
- return module.CortexCalculatorProvider;
14
- },
15
- initializationErrorMessage: "Failed to initialize the PIE open-source calculator provider. Confirm that this browser supports module workers and that the bundled worker assets are available.",
16
- };
17
- }
18
- }
@@ -1,11 +0,0 @@
1
- /** Desmos calculator adapter for the generic tool-provider registry. */
2
- import type { CalculatorProviderInit } from "@pie-players/pie-calculator";
3
- import { LazyCalculatorToolProvider, type LazyCalculatorProviderDefinition } from "./LazyCalculatorToolProvider.js";
4
- /** Provider initialization is the provider-neutral calculator contract. */
5
- export type DesmosToolProviderConfig = CalculatorProviderInit;
6
- export declare class DesmosToolProvider extends LazyCalculatorToolProvider<DesmosToolProviderConfig> {
7
- readonly providerName = "Desmos Calculator";
8
- readonly version = "1.12";
9
- readonly requiresAuth = true;
10
- protected getDefinition(): LazyCalculatorProviderDefinition<DesmosToolProviderConfig>;
11
- }
@@ -1,18 +0,0 @@
1
- /** Desmos calculator adapter for the generic tool-provider registry. */
2
- import { LazyCalculatorToolProvider, } from "./LazyCalculatorToolProvider.js";
3
- export class DesmosToolProvider extends LazyCalculatorToolProvider {
4
- providerName = "Desmos Calculator";
5
- version = "1.12";
6
- requiresAuth = true;
7
- getDefinition() {
8
- return {
9
- backend: "desmos",
10
- moduleImportOperation: "desmos-provider-module-import",
11
- loadProvider: async () => {
12
- const module = await import("@pie-players/pie-calculator-desmos");
13
- return module.DesmosCalculatorProvider;
14
- },
15
- initializationErrorMessage: "Failed to initialize Desmos calculator provider. Check the application key, preloaded API, runtime endpoint, or network access.",
16
- };
17
- }
18
- }
@@ -1,13 +0,0 @@
1
- /** GeoGebra calculator adapter for the generic tool-provider registry. */
2
- import type { CalculatorToolProviderInitConfig, LazyCalculatorProviderDefinition } from "./LazyCalculatorToolProvider.js";
3
- import { LazyCalculatorToolProvider } from "./LazyCalculatorToolProvider.js";
4
- export interface GeoGebraToolProviderConfig extends CalculatorToolProviderInitConfig {
5
- scriptUrl?: string;
6
- appletTimeoutMs?: number;
7
- }
8
- export declare class GeoGebraToolProvider extends LazyCalculatorToolProvider<GeoGebraToolProviderConfig> {
9
- readonly providerName = "GeoGebra Calculator";
10
- readonly version = "6";
11
- readonly requiresAuth = false;
12
- protected getDefinition(): LazyCalculatorProviderDefinition<GeoGebraToolProviderConfig>;
13
- }
@@ -1,18 +0,0 @@
1
- /** GeoGebra calculator adapter for the generic tool-provider registry. */
2
- import { LazyCalculatorToolProvider } from "./LazyCalculatorToolProvider.js";
3
- export class GeoGebraToolProvider extends LazyCalculatorToolProvider {
4
- providerName = "GeoGebra Calculator";
5
- version = "6";
6
- requiresAuth = false;
7
- getDefinition() {
8
- return {
9
- backend: "geogebra",
10
- moduleImportOperation: "geogebra-provider-module-import",
11
- loadProvider: async () => {
12
- const module = await import("@pie-players/pie-calculator-geogebra");
13
- return module.GeoGebraCalculatorProvider;
14
- },
15
- initializationErrorMessage: "Failed to initialize GeoGebra calculator provider. Confirm that the deployment may load GeoGebra and that its script URL is reachable.",
16
- };
17
- }
18
- }
@@ -1,23 +0,0 @@
1
- /**
2
- * One overlay element per coordinator and scoped tool id, reused across renders.
3
- *
4
- * The toolbar re-derives its rendered tools whenever an input moves — a policy
5
- * emit, a tool-config update, the interface locale — and mounts whichever
6
- * element each render returns, swapping out one it has not seen. A registration
7
- * that creates its overlay on every render therefore remounts it, and the
8
- * learner loses the ruler's position, the graph's points or the eliminated
9
- * choices while the tool stays open. Reusing the element keeps the mount a
10
- * no-op, so per-render attributes are the registration's to re-apply.
11
- *
12
- * A Svelte custom element tears its component down once it leaves the document,
13
- * so a cached element found disconnected is dropped and recreated.
14
- */
15
- import type { ToolbarContext } from "@pie-players/pie-assessment-toolkit/tools/registration";
16
- /** The property the toolbar calls as it unmounts a tool element. */
17
- export declare const TOOL_ELEMENT_UNMOUNT_CALLBACK_PROP = "__pieToolElementUnmount";
18
- /**
19
- * The element cached for `fullToolId` under this toolbar's coordinator, or the
20
- * one `create` returns, which is then cached. Without a coordinator there is no
21
- * session to key by, and every render creates.
22
- */
23
- export declare function resolveOverlayElement<T extends HTMLElement>(toolbarContext: ToolbarContext, fullToolId: string, create: () => T): T;