@pie-players/pie-default-tool-loaders 0.3.67 → 0.3.69

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.
@@ -0,0 +1,73 @@
1
+ /**
2
+ * Which capabilities appear as actions on the learner's current selection.
3
+ *
4
+ * The one place that pairs a selection gateway to the tools it can open. The gateway
5
+ * renders what it is handed and names nothing; the tools know nothing about
6
+ * selections. Composition is the only layer allowed to know both, which is why this
7
+ * list lives here rather than in either of them.
8
+ *
9
+ * A selection is a shortcut, never the only way in. Chromium does not extend a
10
+ * selection with Shift+Arrow in non-editable content unless caret browsing is on —
11
+ * an OS toggle that does not exist on mobile — so a sighted keyboard-only learner
12
+ * cannot originate one at all. Every tool named here also opens from the toolbar and
13
+ * carries its own term field.
14
+ */
15
+ import { resolveFallbackToolIcon } from "@pie-players/pie-assessment-toolkit/tools/internal";
16
+ function asRequestCapable(coordinator) {
17
+ const candidate = coordinator;
18
+ if (typeof candidate?.canRequestTool !== "function")
19
+ return null;
20
+ if (typeof candidate.requestTool !== "function")
21
+ return null;
22
+ return candidate;
23
+ }
24
+ const SELECTION_ACTION_SPECS = [
25
+ {
26
+ toolId: "dictionary",
27
+ label: "Look up selected text in dictionary",
28
+ tooltip: "Look up",
29
+ icon: "book-open",
30
+ },
31
+ {
32
+ toolId: "pictureDictionary",
33
+ label: "Show pictures for selected text",
34
+ tooltip: "Show pictures",
35
+ icon: "photo",
36
+ },
37
+ ];
38
+ /**
39
+ * Actions for the gateway to render, given the services it was handed.
40
+ *
41
+ * Rebuilt on every sync rather than captured once: a host calling
42
+ * `updateAssessment` mid-session swaps the coordinator without remounting the
43
+ * gateway, and an action closing over the previous one would open a tool in a
44
+ * session the learner has left.
45
+ */
46
+ export function buildSelectionActions(services) {
47
+ const coordinator = asRequestCapable(services.toolkitCoordinator);
48
+ if (!coordinator)
49
+ return [];
50
+ return SELECTION_ACTION_SPECS.map((spec) => {
51
+ const iconSvg = resolveFallbackToolIcon(spec.icon) ?? undefined;
52
+ return {
53
+ id: spec.toolId,
54
+ label: spec.label,
55
+ tooltip: spec.tooltip,
56
+ iconSvg,
57
+ // Asked per selection. A tool the PNP does not grant, or that no toolbar in
58
+ // this section hosts, is absent rather than present and inert.
59
+ isAvailable: () => coordinator.canRequestTool(spec.toolId),
60
+ run: (selection) => {
61
+ const term = selection.text.trim();
62
+ if (!term)
63
+ return;
64
+ // Both panels read the selected text from `term`. No level is named, so the
65
+ // request takes whichever toolbar hosts the tool, preferring section scope.
66
+ coordinator.requestTool({
67
+ toolId: spec.toolId,
68
+ params: { term },
69
+ });
70
+ },
71
+ };
72
+ });
73
+ }
@@ -13,6 +13,7 @@
13
13
  import { hasMathContent, hasScienceContent, } from "@pie-players/pie-assessment-toolkit/tools/internal";
14
14
  import { createToolElement, } from "@pie-players/pie-assessment-toolkit/tools/internal";
15
15
  import { createScopedVisibilityBinding, syncButtonAndOverlayVisibility, } from "@pie-players/pie-assessment-toolkit/tools/internal";
16
+ import { renderOverlayToolbar } from "./overlay-toolbar-render.js";
16
17
  /**
17
18
  * Graph tool registration
18
19
  *
@@ -23,6 +24,8 @@ export const graphToolRegistration = {
23
24
  toolId: "graph",
24
25
  name: "Graph",
25
26
  description: "Graphing calculator and coordinate plane",
27
+ nameKey: "tools.graph.name",
28
+ descriptionKey: "tools.graph.description",
26
29
  icon: "chart-bar",
27
30
  // Graph is a section-level floating tool.
28
31
  supportedLevels: ["section"],
@@ -31,8 +34,6 @@ export const graphToolRegistration = {
31
34
  pnpSupportIds: [
32
35
  "graph", // QTI 3.0 standard (assessment.graph)
33
36
  "graphingCalculator", // QTI 3.0 standard (assessment.graphingCalculator)
34
- "coordinatePlane", // Common variant
35
- "graphingTool", // Common variant
36
37
  ],
37
38
  /**
38
39
  * Pass 2: Graph is relevant when math content is present
@@ -41,48 +42,15 @@ export const graphToolRegistration = {
41
42
  return hasMathContent(context);
42
43
  },
43
44
  renderToolbar(context, toolbarContext) {
44
- const visibility = createScopedVisibilityBinding(this.toolId, toolbarContext);
45
- const button = {
46
- toolId: this.toolId,
47
- label: this.name,
48
- icon: typeof this.icon === "function" ? this.icon(context) : this.icon,
49
- disabled: false,
50
- ariaLabel: "Graph - Graphing calculator",
51
- tooltip: "Graph",
52
- onClick: () => toolbarContext.toggleTool(this.toolId),
53
- active: visibility.isActive(),
54
- };
55
- const componentOverrides = toolbarContext.componentOverrides ?? {};
56
- const overlay = createToolElement(this.toolId, context, toolbarContext, componentOverrides);
57
- overlay.setAttribute("tool-id", visibility.fullToolId);
58
- return {
59
- toolId: this.toolId,
60
- button,
61
- elements: [
62
- {
63
- element: overlay,
64
- mount: "after-buttons",
65
- shell: {
66
- title: this.name,
67
- draggable: true,
68
- resizable: true,
69
- closeable: true,
70
- initialWidth: 920,
71
- initialHeight: 680,
72
- minWidth: 640,
73
- minHeight: 500,
74
- },
75
- },
76
- ],
77
- sync: () => {
78
- syncButtonAndOverlayVisibility({
79
- button,
80
- overlay,
81
- isActive: visibility.isActive,
82
- });
45
+ return renderOverlayToolbar(this, context, toolbarContext, {
46
+ shell: {
47
+ resizable: true,
48
+ initialWidth: 920,
49
+ initialHeight: 680,
50
+ minWidth: 640,
51
+ minHeight: 500,
83
52
  },
84
- subscribeActive: visibility.subscribeActive,
85
- };
53
+ });
86
54
  },
87
55
  };
88
56
  /**
@@ -95,6 +63,8 @@ export const periodicTableToolRegistration = {
95
63
  toolId: "periodicTable",
96
64
  name: "Periodic Table",
97
65
  description: "Chemistry periodic table reference",
66
+ nameKey: "tools.periodicTable.name",
67
+ descriptionKey: "tools.periodicTable.description",
98
68
  icon: "beaker",
99
69
  // Periodic table is a section-level floating tool.
100
70
  supportedLevels: ["section"],
@@ -102,8 +72,6 @@ export const periodicTableToolRegistration = {
102
72
  // Maps to QTI 3.0 standard feature: periodicTable
103
73
  pnpSupportIds: [
104
74
  "periodicTable", // QTI 3.0 standard (assessment.periodicTable)
105
- "chemistryReference", // Common variant
106
- "elementReference", // Common variant
107
75
  ],
108
76
  /**
109
77
  * Pass 2: Periodic table is relevant when science content is present
@@ -112,47 +80,14 @@ export const periodicTableToolRegistration = {
112
80
  return hasScienceContent(context);
113
81
  },
114
82
  renderToolbar(context, toolbarContext) {
115
- const visibility = createScopedVisibilityBinding(this.toolId, toolbarContext);
116
- const button = {
117
- toolId: this.toolId,
118
- label: this.name,
119
- icon: typeof this.icon === "function" ? this.icon(context) : this.icon,
120
- disabled: false,
121
- ariaLabel: "Periodic table - Chemistry reference",
122
- tooltip: "Periodic Table",
123
- onClick: () => toolbarContext.toggleTool(this.toolId),
124
- active: visibility.isActive(),
125
- };
126
- const componentOverrides = toolbarContext.componentOverrides ?? {};
127
- const overlay = createToolElement(this.toolId, context, toolbarContext, componentOverrides);
128
- overlay.setAttribute("tool-id", visibility.fullToolId);
129
- return {
130
- toolId: this.toolId,
131
- button,
132
- elements: [
133
- {
134
- element: overlay,
135
- mount: "after-buttons",
136
- shell: {
137
- title: this.name,
138
- draggable: true,
139
- resizable: true,
140
- closeable: true,
141
- initialWidth: 1160,
142
- initialHeight: 760,
143
- minWidth: 920,
144
- minHeight: 620,
145
- },
146
- },
147
- ],
148
- sync: () => {
149
- syncButtonAndOverlayVisibility({
150
- button,
151
- overlay,
152
- isActive: visibility.isActive,
153
- });
83
+ return renderOverlayToolbar(this, context, toolbarContext, {
84
+ shell: {
85
+ resizable: true,
86
+ initialWidth: 1160,
87
+ initialHeight: 760,
88
+ minWidth: 920,
89
+ minHeight: 620,
154
90
  },
155
- subscribeActive: visibility.subscribeActive,
156
- };
91
+ });
157
92
  },
158
93
  };
@@ -26,6 +26,8 @@ export const ttsToolRegistration = {
26
26
  toolId: "textToSpeech",
27
27
  name: "Text to Speech",
28
28
  description: "Read content aloud",
29
+ nameKey: "tools.textToSpeech.name",
30
+ descriptionKey: "tools.textToSpeech.description",
29
31
  icon: "volume-up",
30
32
  provider: {
31
33
  getProviderId: () => "tts",
@@ -84,8 +86,6 @@ export const ttsToolRegistration = {
84
86
  pnpSupportIds: [
85
87
  "textToSpeech", // QTI 3.0 standard (auditory.textToSpeech)
86
88
  "readAloud", // QTI 3.0 standard (auditory.readAloud)
87
- "tts", // Common abbreviation
88
- "speechOutput", // Common variant
89
89
  ],
90
90
  /**
91
91
  * Pass 2: Determine if TTS is relevant in this context
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@pie-players/pie-default-tool-loaders",
3
- "version": "0.3.67",
3
+ "version": "0.3.69",
4
4
  "type": "module",
5
5
  "description": "Composition layer for the packaged PIE assessment tools: registrations, tag map, placement presets, universal supports and lazy module loaders",
6
6
  "repository": {
@@ -33,21 +33,26 @@
33
33
  "test": "bun test"
34
34
  },
35
35
  "dependencies": {
36
- "@pie-players/pie-assessment-toolkit": "0.3.67",
37
- "@pie-players/pie-players-shared": "0.3.67",
38
- "@pie-players/pie-tool-annotation-toolbar": "0.3.67",
39
- "@pie-players/pie-tool-answer-eliminator": "0.3.67",
40
- "@pie-players/pie-tool-calculator-desmos": "0.3.67",
41
- "@pie-players/pie-tool-graph": "0.3.67",
42
- "@pie-players/pie-tool-line-reader": "0.3.67",
43
- "@pie-players/pie-tool-periodic-table": "0.3.67",
44
- "@pie-players/pie-tool-protractor": "0.3.67",
45
- "@pie-players/pie-tool-ruler": "0.3.67",
46
- "@pie-players/pie-tool-theme": "0.3.67",
47
- "@pie-players/pie-tool-tts-inline": "0.3.67"
36
+ "@pie-players/pie-assessment-toolkit": "0.3.69",
37
+ "@pie-players/pie-players-shared": "0.3.69",
38
+ "@pie-players/pie-tool-annotation-toolbar": "0.3.69",
39
+ "@pie-players/pie-tool-answer-eliminator": "0.3.69",
40
+ "@pie-players/pie-tool-calculator-desmos": "0.3.69",
41
+ "@pie-players/pie-tool-calculator-cortex": "0.3.69",
42
+ "@pie-players/pie-tool-calculator-geogebra": "0.3.69",
43
+ "@pie-players/pie-tool-calculator-shared": "0.3.69",
44
+ "@pie-players/pie-tool-dictionary": "0.3.69",
45
+ "@pie-players/pie-tool-graph": "0.3.69",
46
+ "@pie-players/pie-tool-line-reader": "0.3.69",
47
+ "@pie-players/pie-tool-periodic-table": "0.3.69",
48
+ "@pie-players/pie-tool-picture-dictionary": "0.3.69",
49
+ "@pie-players/pie-tool-protractor": "0.3.69",
50
+ "@pie-players/pie-tool-ruler": "0.3.69",
51
+ "@pie-players/pie-tool-theme": "0.3.69",
52
+ "@pie-players/pie-tool-tts-inline": "0.3.69"
48
53
  },
49
54
  "devDependencies": {
50
- "@biomejs/biome": "^2.5.7",
55
+ "@biomejs/biome": "^2.5.10",
51
56
  "typescript": "^5.9.3"
52
57
  },
53
58
  "homepage": "https://github.com/pie-framework/pie-players/tree/master/packages/default-tool-loaders#readme",