@pie-players/pie-assessment-toolkit 0.3.73 → 0.3.75
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/README.md +469 -318
- package/dist/attempt/AssessmentSession.d.ts +1 -5
- package/dist/attempt/AssessmentSession.js +0 -29
- package/dist/attempt/TestSession.d.ts +1 -20
- package/dist/attempt/TestSession.js +8 -99
- package/dist/components/ItemScope.custom-element.d.ts +1 -0
- package/dist/components/ItemScope.custom-element.js +1 -0
- package/dist/components/ItemToolBar.custom-element.d.ts +1 -0
- package/dist/components/ItemToolBar.custom-element.js +1 -1
- package/dist/components/PieAssessmentToolkit.custom-element.d.ts +1 -0
- package/dist/components/PieAssessmentToolkit.custom-element.js +13 -13
- package/dist/components/SectionToolBar.custom-element.d.ts +1 -0
- package/dist/components/SectionToolBar.custom-element.js +1 -1
- package/dist/components/chunks/ItemToolBar-7tt7v2xp.js +4 -0
- package/dist/components/chunks/ItemToolBar-97hx60z4.js +2 -0
- package/dist/components/chunks/ItemToolBar-bxwyhr5p.js +2 -0
- package/dist/components/chunks/ItemToolBar-jx38w99s.js +2 -0
- package/dist/components/chunks/ItemToolBar-rd2bb4p6.js +40 -0
- package/dist/components/chunks/ItemToolBar-vdkyn9f3.js +2 -0
- package/dist/components/chunks/sre-engine-jd8cc08x.js +1 -0
- package/dist/components/item-scope-element.d.ts +2 -0
- package/dist/components/item-scope-element.js +2 -0
- package/dist/context/assessment-toolkit-context.d.ts +32 -6
- package/dist/index.d.ts +23 -48
- package/dist/index.js +12 -37
- package/dist/policy/core/PolicySource.d.ts +1 -1
- package/dist/policy/core/ToolPolicyEngine.d.ts +85 -34
- package/dist/policy/core/ToolPolicyEngine.js +148 -46
- package/dist/policy/core/compose-decision.d.ts +28 -7
- package/dist/policy/core/compose-decision.js +75 -54
- package/dist/policy/core/decision-types.d.ts +65 -34
- package/dist/policy/core/feature-decision.d.ts +16 -9
- package/dist/policy/core/feature-decision.js +14 -8
- package/dist/policy/core/pnp-policy-inputs.d.ts +24 -33
- package/dist/policy/core/pnp-policy-inputs.js +28 -56
- package/dist/policy/core/provenance.d.ts +9 -4
- package/dist/policy/core/provenance.js +1 -1
- package/dist/policy/engine.d.ts +7 -23
- package/dist/policy/engine.js +5 -20
- package/dist/policy/sources/PnpPolicySource.d.ts +44 -61
- package/dist/policy/sources/PnpPolicySource.js +117 -118
- package/dist/runtime/SectionControllerBinding.d.ts +279 -0
- package/dist/runtime/SectionControllerBinding.js +450 -0
- package/dist/runtime/SectionRuntimeEngine.d.ts +26 -289
- package/dist/runtime/SectionRuntimeEngine.js +30 -372
- package/dist/runtime/adapter/SectionEngineAdapter.d.ts +19 -80
- package/dist/runtime/adapter/SectionEngineAdapter.js +19 -92
- package/dist/runtime/adapter/dom-event-bridge.d.ts +15 -30
- package/dist/runtime/adapter/dom-event-bridge.js +17 -44
- package/dist/runtime/adapter/subscriber-fanout.d.ts +1 -2
- package/dist/runtime/adapter/subscriber-fanout.js +1 -2
- package/dist/runtime/catalog-context.d.ts +19 -0
- package/dist/runtime/catalog-context.js +28 -0
- package/dist/runtime/composition-emit-scheduler.d.ts +9 -15
- package/dist/runtime/composition-emit-scheduler.js +9 -15
- package/dist/runtime/content-language.d.ts +32 -0
- package/dist/runtime/content-language.js +46 -0
- package/dist/runtime/content-region.d.ts +17 -0
- package/dist/runtime/content-region.js +29 -0
- package/dist/runtime/content-registration.d.ts +13 -0
- package/dist/runtime/content-registration.js +25 -0
- package/dist/runtime/core/SectionEngineCore.d.ts +2 -2
- package/dist/runtime/core/SectionEngineCore.js +2 -2
- package/dist/runtime/core/cohort.d.ts +1 -1
- package/dist/runtime/core/cohort.js +1 -1
- package/dist/runtime/core/engine-input.d.ts +18 -30
- package/dist/runtime/core/engine-input.js +11 -12
- package/dist/runtime/core/engine-output.d.ts +16 -40
- package/dist/runtime/core/engine-output.js +9 -21
- package/dist/runtime/core/engine-readiness.d.ts +5 -37
- package/dist/runtime/core/engine-readiness.js +8 -41
- package/dist/runtime/core/engine-resolver.d.ts +46 -74
- package/dist/runtime/core/engine-resolver.js +18 -43
- package/dist/runtime/core/engine-state.d.ts +28 -36
- package/dist/runtime/core/engine-state.js +18 -21
- package/dist/runtime/core/engine-transition.d.ts +14 -19
- package/dist/runtime/core/engine-transition.js +71 -51
- package/dist/runtime/engine.d.ts +16 -19
- package/dist/runtime/engine.js +12 -19
- package/dist/runtime/page-warnings.d.ts +13 -0
- package/dist/runtime/page-warnings.js +22 -0
- package/dist/runtime/policy-input-forwarding.d.ts +25 -0
- package/dist/runtime/policy-input-forwarding.js +25 -0
- package/dist/runtime/registration-events.d.ts +14 -0
- package/dist/runtime/runtime-event-claim.d.ts +8 -0
- package/dist/runtime/runtime-event-claim.js +15 -0
- package/dist/runtime/shell-event-bridge.d.ts +45 -0
- package/dist/runtime/shell-event-bridge.js +127 -0
- package/dist/runtime/shell-registration.d.ts +73 -0
- package/dist/runtime/shell-registration.js +95 -0
- package/dist/runtime/shell-scope.d.ts +68 -0
- package/dist/runtime/shell-scope.js +188 -0
- package/dist/runtime/tool-host-contract.d.ts +28 -10
- package/dist/runtime/tool-host-contract.js +31 -10
- package/dist/runtime/unclaimed-registration-watch.d.ts +7 -0
- package/dist/runtime/unclaimed-registration-watch.js +23 -0
- package/dist/services/ElementToolStateStore.d.ts +14 -10
- package/dist/services/ElementToolStateStore.js +37 -13
- package/dist/services/HighlightCoordinator.d.ts +22 -28
- package/dist/services/HighlightCoordinator.js +431 -327
- package/dist/services/RangeSerializer.d.ts +10 -1
- package/dist/services/RangeSerializer.js +87 -14
- package/dist/services/TTSService.d.ts +130 -69
- package/dist/services/TTSService.js +713 -570
- package/dist/services/ToolCoordinator.d.ts +43 -66
- package/dist/services/ToolCoordinator.js +164 -208
- package/dist/services/ToolRegistry.d.ts +78 -54
- package/dist/services/ToolRegistry.js +107 -105
- package/dist/services/ToolkitCoordinator.d.ts +261 -175
- package/dist/services/ToolkitCoordinator.js +667 -433
- package/dist/services/audio-handoff.d.ts +6 -7
- package/dist/services/audio-handoff.js +20 -14
- package/dist/services/catalog-owner.d.ts +11 -1
- package/dist/services/catalog-owner.js +25 -0
- package/dist/services/create-tools-config.d.ts +2 -2
- package/dist/services/framework-error-bus.d.ts +3 -6
- package/dist/services/framework-error-bus.js +3 -6
- package/dist/services/framework-error.d.ts +30 -8
- package/dist/services/framework-error.js +9 -7
- package/dist/services/interfaces.d.ts +158 -129
- package/dist/services/section-controller-types.d.ts +15 -0
- package/dist/services/section-session-assignment.d.ts +21 -0
- package/dist/services/section-session-assignment.js +82 -0
- package/dist/services/spoken-audio-cards.d.ts +0 -2
- package/dist/services/spoken-audio-cards.js +1 -3
- package/dist/services/tool-config-defaults.d.ts +3 -3
- package/dist/services/tool-config-defaults.js +3 -3
- package/dist/services/tool-config-validation.d.ts +14 -4
- package/dist/services/tool-config-validation.js +63 -71
- package/dist/services/tool-context.d.ts +0 -8
- package/dist/services/tool-context.js +29 -25
- package/dist/services/tool-icons.d.ts +4 -3
- package/dist/services/tool-icons.js +4 -3
- package/dist/services/tool-instance-id.d.ts +0 -1
- package/dist/services/tool-instance-id.js +0 -6
- package/dist/services/tool-providers/TTSToolProvider.d.ts +41 -80
- package/dist/services/tool-providers/TTSToolProvider.js +81 -40
- package/dist/services/tool-providers/ToolProviderApi.d.ts +10 -4
- package/dist/services/tool-providers/ToolProviderRegistry.d.ts +32 -28
- package/dist/services/tool-providers/ToolProviderRegistry.js +121 -107
- package/dist/services/tool-providers/index.d.ts +0 -9
- package/dist/services/tool-providers/index.js +2 -4
- package/dist/services/tool-request.d.ts +27 -12
- package/dist/services/tool-request.js +24 -14
- package/dist/services/toolbar-decided-tools.d.ts +15 -0
- package/dist/services/toolbar-decided-tools.js +28 -0
- package/dist/services/tools-config-normalizer.d.ts +37 -23
- package/dist/services/tools-config-normalizer.js +2 -10
- package/dist/services/tts/browser-provider.d.ts +38 -2
- package/dist/services/tts/browser-provider.js +276 -140
- package/dist/services/tts/catalog-span-alignment.d.ts +2 -17
- package/dist/services/tts/catalog-span-alignment.js +17 -142
- package/dist/services/tts/flat-tree.d.ts +71 -0
- package/dist/services/tts/flat-tree.js +269 -0
- package/dist/services/tts/generated-speech/assemble-plan.d.ts +3 -1
- package/dist/services/tts/generated-speech/assemble-plan.js +3 -1
- package/dist/services/tts/generated-speech/dom/build-dom-plan.d.ts +2 -0
- package/dist/services/tts/generated-speech/dom/build-dom-plan.js +1 -1
- package/dist/services/tts/generated-speech/math-speech-cache.d.ts +3 -1
- package/dist/services/tts/generated-speech/math-speech-cache.js +5 -1
- package/dist/services/tts/generated-speech/types.d.ts +0 -12
- package/dist/services/tts/highlight-pipeline/boundary-normalizer.js +12 -62
- package/dist/services/tts/highlight-pipeline/create-highlight-plan.js +38 -5
- package/dist/services/tts/highlight-pipeline/normalize-speech-chunks.js +3 -6
- package/dist/services/tts/highlight-pipeline/prose-boundary-resolver.js +6 -4
- package/dist/services/tts/highlight-pipeline/readable-region.js +3 -2
- package/dist/services/tts/highlight-pipeline/types.d.ts +5 -0
- package/dist/services/tts/highlight-pipeline/visible-map-range.d.ts +12 -0
- package/dist/services/tts/highlight-pipeline/visible-map-range.js +73 -7
- package/dist/services/tts/math-alignment/index.d.ts +0 -5
- package/dist/services/tts/math-alignment/index.js +5 -25
- package/dist/services/tts/math-alignment/speech-tokenizer.d.ts +9 -1
- package/dist/services/tts/math-alignment/speech-tokenizer.js +38 -36
- package/dist/services/tts/math-alignment/types.d.ts +4 -2
- package/dist/services/tts/math-aware-text-processing.d.ts +5 -1
- package/dist/services/tts/math-aware-text-processing.js +74 -18
- package/dist/services/tts/math-control-names.d.ts +21 -0
- package/dist/services/tts/math-control-names.js +142 -0
- package/dist/services/tts/math-speech.d.ts +16 -1
- package/dist/services/tts/math-speech.js +55 -19
- package/dist/services/tts/provider-options.d.ts +41 -0
- package/dist/services/tts/provider-options.js +1 -0
- package/dist/services/tts/sre-engine.d.ts +7 -0
- package/dist/services/tts/sre-engine.js +11 -0
- package/dist/services/tts/sre-locales.d.ts +14 -0
- package/dist/services/tts/sre-locales.js +57 -0
- package/dist/services/tts/ssml/spoken-text.d.ts +2 -26
- package/dist/services/tts/ssml/spoken-text.js +29 -0
- package/dist/services/tts/start-failure.d.ts +11 -0
- package/dist/services/tts/start-failure.js +19 -0
- package/dist/services/tts/text-processing.d.ts +9 -1
- package/dist/services/tts/text-processing.js +46 -34
- package/dist/services/tts/text-segmentation.d.ts +7 -0
- package/dist/services/tts/text-segmentation.js +47 -0
- package/dist/services/tts-runtime-config.d.ts +44 -18
- package/dist/services/tts-runtime-config.js +22 -93
- package/dist/tools/content-capability-resolution.d.ts +7 -9
- package/dist/tools/content-capability-resolution.js +8 -45
- package/dist/tools/registration.d.ts +58 -0
- package/dist/tools/registration.js +54 -0
- package/dist/tools/registrations/toolbar-registration-helpers.js +2 -2
- package/dist/tools/tool-surface-host.d.ts +6 -10
- package/dist/tools/tool-surface-host.js +44 -42
- package/dist/tools/tool-tag-map.d.ts +5 -15
- package/dist/tools/tool-tag-map.js +6 -20
- package/dist/utils/structural-equality.d.ts +11 -0
- package/dist/utils/structural-equality.js +47 -0
- package/package.json +24 -59
- package/dist/attempt/adapters/activity-to-test-attempt-session.d.ts +0 -49
- package/dist/attempt/adapters/activity-to-test-attempt-session.js +0 -138
- package/dist/components/chunks/ItemToolBar-byq80z42.js +0 -40
- package/dist/components/chunks/ItemToolBar-d36g3aw4.js +0 -49
- package/dist/context/runtime-context-consumer.d.ts +0 -13
- package/dist/context/runtime-context-consumer.js +0 -51
- package/dist/item-loader.d.ts +0 -44
- package/dist/item-loader.js +0 -61
- package/dist/policy/core/engine-context.d.ts +0 -29
- package/dist/policy/core/engine-context.js +0 -27
- package/dist/policy/core/policy-source-tag.d.ts +0 -31
- package/dist/policy/core/policy-source-tag.js +0 -28
- package/dist/policy/internal.d.ts +0 -25
- package/dist/policy/internal.js +0 -25
- package/dist/runtime/adapter/coordinator-bridge.d.ts +0 -92
- package/dist/runtime/adapter/coordinator-bridge.js +0 -126
- package/dist/runtime/adapter/framework-error-bridge.d.ts +0 -36
- package/dist/runtime/adapter/framework-error-bridge.js +0 -46
- package/dist/runtime/adapter/instrumentation-bridge.d.ts +0 -31
- package/dist/runtime/adapter/instrumentation-bridge.js +0 -38
- package/dist/runtime/core/engine-stage-derivation.d.ts +0 -18
- package/dist/runtime/core/engine-stage-derivation.js +0 -29
- package/dist/runtime/engine-context.d.ts +0 -39
- package/dist/runtime/engine-context.js +0 -31
- package/dist/runtime/internal.d.ts +0 -43
- package/dist/runtime/internal.js +0 -45
- package/dist/runtime/section-runtime-engine-host-context.d.ts +0 -80
- package/dist/runtime/section-runtime-engine-host-context.js +0 -95
- package/dist/runtime/stage-emit-gate.d.ts +0 -92
- package/dist/runtime/stage-emit-gate.js +0 -82
- package/dist/services/I18nService.d.ts +0 -47
- package/dist/services/I18nService.js +0 -84
- package/dist/services/ThemeProvider.d.ts +0 -95
- package/dist/services/ThemeProvider.js +0 -334
- package/dist/services/ToolConfigResolver.d.ts +0 -161
- package/dist/services/ToolConfigResolver.js +0 -229
- package/dist/services/catalog-media.d.ts +0 -56
- package/dist/services/catalog-media.js +0 -190
- package/dist/services/createDefaultToolRegistry.d.ts +0 -53
- package/dist/services/createDefaultToolRegistry.js +0 -45
- package/dist/services/defaultPersonalNeedsProfile.d.ts +0 -21
- package/dist/services/defaultPersonalNeedsProfile.js +0 -26
- package/dist/services/pnp-standard-features.d.ts +0 -238
- package/dist/services/pnp-standard-features.js +0 -338
- package/dist/services/tool-providers/CortexToolProvider.d.ts +0 -13
- package/dist/services/tool-providers/CortexToolProvider.js +0 -32
- package/dist/services/tool-providers/DesmosToolProvider.d.ts +0 -14
- package/dist/services/tool-providers/DesmosToolProvider.js +0 -32
- package/dist/services/tool-providers/GeoGebraToolProvider.d.ts +0 -16
- package/dist/services/tool-providers/GeoGebraToolProvider.js +0 -32
- package/dist/services/tool-providers/LazyCalculatorToolProvider.d.ts +0 -35
- package/dist/services/tool-providers/LazyCalculatorToolProvider.js +0 -95
- package/dist/services/tts/visual-line-ranges.d.ts +0 -18
- package/dist/services/tts/visual-line-ranges.js +0 -226
- package/dist/tools/client.d.ts +0 -12
- package/dist/tools/client.js +0 -14
- package/dist/tools/index.d.ts +0 -8
- package/dist/tools/index.js +0 -10
- package/dist/tools/internal.d.ts +0 -43
- package/dist/tools/internal.js +0 -41
- package/dist/tools/response-discovery.d.ts +0 -61
- package/dist/tools/response-discovery.js +0 -113
- package/dist/tools/types.d.ts +0 -337
- package/dist/tools/types.js +0 -12
- package/dist/tools/variant-resolver.d.ts +0 -41
- package/dist/tools/variant-resolver.js +0 -207
|
@@ -1,18 +1,18 @@
|
|
|
1
1
|
/**
|
|
2
2
|
* ToolCoordinator
|
|
3
3
|
*
|
|
4
|
-
*
|
|
5
|
-
* Prevents conflicts between calculator, ruler, protractor, etc.
|
|
4
|
+
* Holds the visibility state of floating tools and stacks their elements.
|
|
6
5
|
*
|
|
7
|
-
*
|
|
8
|
-
*
|
|
9
|
-
*
|
|
10
|
-
*
|
|
11
|
-
*
|
|
6
|
+
* Visibility is state: the coordinator records it and notifies subscribers, and
|
|
7
|
+
* whoever renders a tool shows or hides it from that state. Stacking is the
|
|
8
|
+
* coordinator's alone: an element bound to a tool (`registerTool` with an
|
|
9
|
+
* element, or `updateToolElement`) takes a z-index in the tool's layer and comes
|
|
10
|
+
* to the front of that layer when shown or pressed.
|
|
12
11
|
*
|
|
13
12
|
* Part of PIE Assessment Toolkit.
|
|
14
13
|
*/
|
|
15
14
|
import { createLogger } from "../utils/logger.js";
|
|
15
|
+
import { parseScopedToolId } from "./tool-instance-id.js";
|
|
16
16
|
const log = createLogger("ToolCoordinator");
|
|
17
17
|
/**
|
|
18
18
|
* Z-index layers for assessment components
|
|
@@ -25,29 +25,23 @@ export var ZIndexLayer;
|
|
|
25
25
|
ZIndexLayer[ZIndexLayer["CONTROL"] = 3000] = "CONTROL";
|
|
26
26
|
ZIndexLayer[ZIndexLayer["HIGHLIGHT"] = 4000] = "HIGHLIGHT";
|
|
27
27
|
})(ZIndexLayer || (ZIndexLayer = {}));
|
|
28
|
+
function matchesFilter(id, filter) {
|
|
29
|
+
if (!filter?.baseId)
|
|
30
|
+
return true;
|
|
31
|
+
return (parseScopedToolId(id)?.baseToolId ?? id) === filter.baseId;
|
|
32
|
+
}
|
|
33
|
+
function toToolState(entry) {
|
|
34
|
+
return {
|
|
35
|
+
id: entry.id,
|
|
36
|
+
name: entry.name,
|
|
37
|
+
isVisible: entry.isVisible,
|
|
38
|
+
element: entry.element,
|
|
39
|
+
layer: entry.layer,
|
|
40
|
+
};
|
|
41
|
+
}
|
|
28
42
|
export class ToolCoordinator {
|
|
29
|
-
config;
|
|
30
43
|
tools = new Map();
|
|
31
|
-
layerCounters = new Map();
|
|
32
44
|
listeners = new Set();
|
|
33
|
-
/**
|
|
34
|
-
* Activation (on/off) state keyed by tool id, kept independent of the
|
|
35
|
-
* element registration lifecycle. A tool's DOM element can be unregistered
|
|
36
|
-
* and re-registered as the item re-renders (e.g. a model change re-mounts
|
|
37
|
-
* the toolbar overlay); when that happens the on/off state must survive so
|
|
38
|
-
* that only an explicit toggle — the toolbar button — turns a tool off.
|
|
39
|
-
* Cleared on genuine teardown via {@link releaseTool}.
|
|
40
|
-
*/
|
|
41
|
-
visibilityState = new Map();
|
|
42
|
-
constructor(config = {}) {
|
|
43
|
-
this.config = config;
|
|
44
|
-
// Initialize layer counters
|
|
45
|
-
this.layerCounters.set(ZIndexLayer.BASE, 0);
|
|
46
|
-
this.layerCounters.set(ZIndexLayer.TOOL, 0);
|
|
47
|
-
this.layerCounters.set(ZIndexLayer.MODAL, 0);
|
|
48
|
-
this.layerCounters.set(ZIndexLayer.CONTROL, 0);
|
|
49
|
-
this.layerCounters.set(ZIndexLayer.HIGHLIGHT, 0);
|
|
50
|
-
}
|
|
51
45
|
/**
|
|
52
46
|
* Subscribe to tool state changes
|
|
53
47
|
* Returns unsubscribe function
|
|
@@ -58,99 +52,89 @@ export class ToolCoordinator {
|
|
|
58
52
|
this.listeners.delete(listener);
|
|
59
53
|
};
|
|
60
54
|
}
|
|
61
|
-
/**
|
|
62
|
-
* Notify all listeners of state change
|
|
63
|
-
*/
|
|
64
55
|
notifyListeners() {
|
|
65
|
-
this.listeners
|
|
56
|
+
for (const listener of this.listeners) {
|
|
57
|
+
try {
|
|
58
|
+
listener();
|
|
59
|
+
}
|
|
60
|
+
catch (error) {
|
|
61
|
+
console.warn("[ToolCoordinator] listener failed:", error);
|
|
62
|
+
}
|
|
63
|
+
}
|
|
66
64
|
}
|
|
67
65
|
/**
|
|
68
|
-
* Register a tool with the coordinator
|
|
66
|
+
* Register a tool with the coordinator. Registering a known id keeps its
|
|
67
|
+
* on/off state and takes the name, the element when one is given, and the
|
|
68
|
+
* layer when none was declared before.
|
|
69
69
|
*
|
|
70
70
|
* @param id Unique tool identifier
|
|
71
71
|
* @param name Display name
|
|
72
|
-
* @param element DOM element
|
|
73
|
-
* @param layer Z-index layer
|
|
72
|
+
* @param element DOM element to stack (optional)
|
|
73
|
+
* @param layer Z-index layer. Without one the tool stacks on TOOL until a
|
|
74
|
+
* registration names one.
|
|
74
75
|
*/
|
|
75
|
-
registerTool(id, name, element, layer
|
|
76
|
+
registerTool(id, name, element, layer) {
|
|
76
77
|
log("registerTool called:", { id, name, hasElement: !!element, layer });
|
|
77
|
-
|
|
78
|
-
|
|
79
|
-
|
|
78
|
+
let entry = this.tools.get(id);
|
|
79
|
+
if (entry) {
|
|
80
|
+
entry.name = name;
|
|
81
|
+
const wasRegistered = entry.registered;
|
|
82
|
+
entry.registered = true;
|
|
83
|
+
if (layer !== undefined && !entry.layerDeclared) {
|
|
84
|
+
entry.layer = layer;
|
|
85
|
+
entry.layerDeclared = true;
|
|
86
|
+
this.stackOnTop(entry);
|
|
87
|
+
}
|
|
88
|
+
else if (!wasRegistered) {
|
|
89
|
+
this.stackOnTop(entry);
|
|
90
|
+
}
|
|
80
91
|
}
|
|
81
|
-
|
|
82
|
-
|
|
83
|
-
// tool's activation state so only an explicit toggle can turn it off.
|
|
84
|
-
const isVisible = this.visibilityState.get(id) ?? false;
|
|
85
|
-
// If no element provided, create a placeholder registration
|
|
86
|
-
if (!element) {
|
|
87
|
-
this.tools.set(id, {
|
|
92
|
+
else {
|
|
93
|
+
entry = {
|
|
88
94
|
id,
|
|
89
95
|
name,
|
|
96
|
+
registered: true,
|
|
90
97
|
element: null,
|
|
91
|
-
layer,
|
|
92
|
-
|
|
93
|
-
|
|
94
|
-
|
|
95
|
-
|
|
96
|
-
|
|
98
|
+
layer: layer ?? ZIndexLayer.TOOL,
|
|
99
|
+
layerDeclared: layer !== undefined,
|
|
100
|
+
isVisible: false,
|
|
101
|
+
baseZIndex: 0,
|
|
102
|
+
};
|
|
103
|
+
this.tools.set(id, entry);
|
|
104
|
+
this.stackOnTop(entry);
|
|
97
105
|
}
|
|
98
|
-
|
|
99
|
-
|
|
100
|
-
// Apply z-index
|
|
101
|
-
element.style.zIndex = String(baseZIndex);
|
|
102
|
-
// Reflect restored visibility onto the freshly registered element.
|
|
103
|
-
element.style.display = isVisible ? "" : "none";
|
|
104
|
-
// Create and store event handler to enable proper cleanup
|
|
105
|
-
const mouseDownHandler = () => this.bringToFront(element);
|
|
106
|
-
element.addEventListener("mousedown", mouseDownHandler);
|
|
107
|
-
// Register tool with handler reference
|
|
108
|
-
this.tools.set(id, {
|
|
109
|
-
id,
|
|
110
|
-
name,
|
|
111
|
-
element,
|
|
112
|
-
layer,
|
|
113
|
-
isVisible,
|
|
114
|
-
baseZIndex,
|
|
115
|
-
mouseDownHandler,
|
|
116
|
-
});
|
|
117
|
-
if (isVisible) {
|
|
118
|
-
this.bringToFront(element);
|
|
119
|
-
}
|
|
120
|
-
log("Tool registered with element:", id);
|
|
106
|
+
if (element)
|
|
107
|
+
this.updateToolElement(id, element);
|
|
121
108
|
}
|
|
122
109
|
/**
|
|
123
|
-
* Unregister a tool
|
|
124
|
-
*
|
|
125
|
-
*
|
|
126
|
-
* preserves the tool's activation state in {@link visibilityState}, so a
|
|
127
|
-
* subsequent re-registration of the same id (e.g. after an item re-render)
|
|
128
|
-
* restores whether the tool was on or off. Use {@link releaseTool} to also
|
|
129
|
-
* discard the activation state on genuine teardown.
|
|
110
|
+
* Unregister a tool's element binding, keeping its on/off state so a
|
|
111
|
+
* re-registration of the same id (an item re-render) restores it. Use
|
|
112
|
+
* {@link releaseTool} on genuine teardown.
|
|
130
113
|
*
|
|
131
114
|
* @param id Tool identifier
|
|
132
115
|
*/
|
|
133
116
|
unregisterTool(id) {
|
|
134
|
-
const
|
|
135
|
-
if (!
|
|
117
|
+
const entry = this.tools.get(id);
|
|
118
|
+
if (!entry?.registered)
|
|
136
119
|
return;
|
|
137
|
-
|
|
138
|
-
|
|
139
|
-
tool.element.removeEventListener("mousedown", tool.mouseDownHandler);
|
|
140
|
-
}
|
|
141
|
-
this.tools.delete(id);
|
|
120
|
+
this.detachElement(entry);
|
|
121
|
+
entry.registered = false;
|
|
142
122
|
}
|
|
143
123
|
/**
|
|
144
|
-
* Fully release a tool: unregister its element binding
|
|
145
|
-
*
|
|
146
|
-
*
|
|
147
|
-
* which keeps the on/off state alive across element re-registration.
|
|
124
|
+
* Fully release a tool: unregister its element binding and discard its
|
|
125
|
+
* on/off state. Call this on genuine teardown (leaving the item or section
|
|
126
|
+
* that owns the tool).
|
|
148
127
|
*
|
|
149
128
|
* @param id Tool identifier
|
|
150
129
|
*/
|
|
151
130
|
releaseTool(id) {
|
|
152
|
-
this.
|
|
153
|
-
|
|
131
|
+
const entry = this.tools.get(id);
|
|
132
|
+
if (!entry)
|
|
133
|
+
return;
|
|
134
|
+
this.detachElement(entry);
|
|
135
|
+
this.tools.delete(id);
|
|
136
|
+
if (entry.isVisible)
|
|
137
|
+
this.notifyListeners();
|
|
154
138
|
}
|
|
155
139
|
/**
|
|
156
140
|
* Show a tool
|
|
@@ -158,18 +142,14 @@ export class ToolCoordinator {
|
|
|
158
142
|
* @param id Tool identifier
|
|
159
143
|
*/
|
|
160
144
|
showTool(id) {
|
|
161
|
-
const
|
|
162
|
-
if (!
|
|
145
|
+
const entry = this.tools.get(id);
|
|
146
|
+
if (!entry) {
|
|
163
147
|
log(`Tool ${id} not found`);
|
|
164
148
|
return;
|
|
165
149
|
}
|
|
166
|
-
if (
|
|
167
|
-
|
|
168
|
-
|
|
169
|
-
}
|
|
170
|
-
tool.isVisible = true;
|
|
171
|
-
this.visibilityState.set(id, true);
|
|
172
|
-
this.notifyListeners();
|
|
150
|
+
if (entry.element)
|
|
151
|
+
this.bringToFront(entry.element);
|
|
152
|
+
this.setVisible(entry, true);
|
|
173
153
|
}
|
|
174
154
|
/**
|
|
175
155
|
* Hide a tool
|
|
@@ -177,17 +157,12 @@ export class ToolCoordinator {
|
|
|
177
157
|
* @param id Tool identifier
|
|
178
158
|
*/
|
|
179
159
|
hideTool(id) {
|
|
180
|
-
const
|
|
181
|
-
if (!
|
|
160
|
+
const entry = this.tools.get(id);
|
|
161
|
+
if (!entry) {
|
|
182
162
|
log(`Tool ${id} not found`);
|
|
183
163
|
return;
|
|
184
164
|
}
|
|
185
|
-
|
|
186
|
-
tool.element.style.display = "none";
|
|
187
|
-
}
|
|
188
|
-
tool.isVisible = false;
|
|
189
|
-
this.visibilityState.set(id, false);
|
|
190
|
-
this.notifyListeners();
|
|
165
|
+
this.setVisible(entry, false);
|
|
191
166
|
}
|
|
192
167
|
/**
|
|
193
168
|
* Toggle tool visibility
|
|
@@ -195,14 +170,12 @@ export class ToolCoordinator {
|
|
|
195
170
|
* @param id Tool identifier
|
|
196
171
|
*/
|
|
197
172
|
toggleTool(id) {
|
|
198
|
-
|
|
199
|
-
|
|
200
|
-
|
|
201
|
-
log(`Tool ${id} not found. Registered tools:`, Array.from(this.tools.keys()));
|
|
173
|
+
const entry = this.tools.get(id);
|
|
174
|
+
if (!entry) {
|
|
175
|
+
log(`Tool ${id} not found`);
|
|
202
176
|
return;
|
|
203
177
|
}
|
|
204
|
-
|
|
205
|
-
if (tool.isVisible) {
|
|
178
|
+
if (entry.isVisible) {
|
|
206
179
|
this.hideTool(id);
|
|
207
180
|
}
|
|
208
181
|
else {
|
|
@@ -213,39 +186,29 @@ export class ToolCoordinator {
|
|
|
213
186
|
* Check if tool is visible
|
|
214
187
|
*
|
|
215
188
|
* @param id Tool identifier
|
|
216
|
-
* @returns true if tool is visible
|
|
217
189
|
*/
|
|
218
190
|
isToolVisible(id) {
|
|
219
|
-
|
|
220
|
-
if (tool)
|
|
221
|
-
return tool.isVisible;
|
|
222
|
-
// No live element registration (e.g. mid re-render, between unmount and
|
|
223
|
-
// re-mount): fall back to the preserved activation state so the tool
|
|
224
|
-
// doesn't read as "off" during the gap.
|
|
225
|
-
return this.visibilityState.get(id) ?? false;
|
|
191
|
+
return this.tools.get(id)?.isVisible ?? false;
|
|
226
192
|
}
|
|
227
193
|
/**
|
|
228
|
-
* Bring element to front of its layer
|
|
194
|
+
* Bring a bound element to the front of its tool's layer. An element no tool
|
|
195
|
+
* is bound to is left alone.
|
|
229
196
|
*
|
|
230
197
|
* @param element DOM element to bring forward
|
|
231
198
|
*/
|
|
232
199
|
bringToFront(element) {
|
|
233
|
-
|
|
234
|
-
|
|
235
|
-
if (!tool)
|
|
200
|
+
const entry = Array.from(this.tools.values()).find((t) => t.element === element);
|
|
201
|
+
if (!entry)
|
|
236
202
|
return;
|
|
237
|
-
|
|
238
|
-
const maxZIndexInLayer = this.getMaxZIndexInLayer(tool.layer);
|
|
239
|
-
const newZIndex = Math.max(maxZIndexInLayer + 1, tool.layer + 1);
|
|
240
|
-
// Update z-index
|
|
241
|
-
element.style.zIndex = String(newZIndex);
|
|
242
|
-
tool.baseZIndex = newZIndex;
|
|
203
|
+
this.stackOnTop(entry);
|
|
243
204
|
}
|
|
244
205
|
/**
|
|
245
|
-
*
|
|
206
|
+
* Ids of the tools an element registration currently holds.
|
|
246
207
|
*/
|
|
247
208
|
getRegisteredTools() {
|
|
248
|
-
return Array.from(this.tools.
|
|
209
|
+
return Array.from(this.tools.values())
|
|
210
|
+
.filter((entry) => entry.registered)
|
|
211
|
+
.map((entry) => entry.id);
|
|
249
212
|
}
|
|
250
213
|
/**
|
|
251
214
|
* Get tool element by ID
|
|
@@ -253,108 +216,101 @@ export class ToolCoordinator {
|
|
|
253
216
|
getToolElement(id) {
|
|
254
217
|
return this.tools.get(id)?.element ?? null;
|
|
255
218
|
}
|
|
256
|
-
|
|
257
|
-
|
|
258
|
-
|
|
259
|
-
|
|
260
|
-
|
|
261
|
-
this.layerCounters.set(layer, current + 1);
|
|
262
|
-
return current;
|
|
219
|
+
setVisible(entry, visible) {
|
|
220
|
+
if (entry.isVisible === visible)
|
|
221
|
+
return;
|
|
222
|
+
entry.isVisible = visible;
|
|
223
|
+
this.notifyListeners();
|
|
263
224
|
}
|
|
264
|
-
|
|
265
|
-
|
|
266
|
-
|
|
267
|
-
getMaxZIndexInLayer(layer) {
|
|
268
|
-
let max = layer;
|
|
269
|
-
for (const tool of this.tools.values()) {
|
|
270
|
-
if (tool.layer === layer) {
|
|
271
|
-
max = Math.max(max, tool.baseZIndex);
|
|
272
|
-
}
|
|
225
|
+
detachElement(entry) {
|
|
226
|
+
if (entry.element && entry.mouseDownHandler) {
|
|
227
|
+
entry.element.removeEventListener("mousedown", entry.mouseDownHandler);
|
|
273
228
|
}
|
|
274
|
-
|
|
229
|
+
entry.element = null;
|
|
230
|
+
entry.mouseDownHandler = undefined;
|
|
275
231
|
}
|
|
276
232
|
/**
|
|
277
|
-
*
|
|
233
|
+
* Put `entry` in front of its layer. The layer is renumbered from its base on
|
|
234
|
+
* every move, so its z-indices stay within it however often tools are raised.
|
|
278
235
|
*/
|
|
279
|
-
|
|
280
|
-
|
|
281
|
-
|
|
282
|
-
|
|
283
|
-
|
|
236
|
+
stackOnTop(entry) {
|
|
237
|
+
const others = Array.from(this.tools.values())
|
|
238
|
+
.filter((other) => other.registered && other.layer === entry.layer && other !== entry)
|
|
239
|
+
.sort((a, b) => a.baseZIndex - b.baseZIndex);
|
|
240
|
+
const top = entry.layer + others.length + 1;
|
|
241
|
+
if (entry.baseZIndex === top &&
|
|
242
|
+
others.every((other) => other.baseZIndex < top)) {
|
|
243
|
+
return;
|
|
284
244
|
}
|
|
245
|
+
[...others, entry].forEach((stacked, index) => {
|
|
246
|
+
stacked.baseZIndex = entry.layer + 1 + index;
|
|
247
|
+
if (stacked.element) {
|
|
248
|
+
stacked.element.style.zIndex = String(stacked.baseZIndex);
|
|
249
|
+
}
|
|
250
|
+
});
|
|
285
251
|
}
|
|
286
252
|
/**
|
|
287
|
-
*
|
|
253
|
+
* Bind the element a tool stacks by. It takes the tool's z-index and comes to
|
|
254
|
+
* the front of the layer when pressed, and when bound while the tool is shown.
|
|
255
|
+
*
|
|
256
|
+
* The outermost element stacks: binding an element inside the bound one keeps
|
|
257
|
+
* the binding, so a tool rendered inside a toolbar's floating window stacks
|
|
258
|
+
* by that window whichever binds first.
|
|
288
259
|
*
|
|
289
260
|
* @param id Tool identifier
|
|
290
261
|
* @param element New DOM element
|
|
291
262
|
*/
|
|
292
263
|
updateToolElement(id, element) {
|
|
293
|
-
const
|
|
294
|
-
if (!
|
|
264
|
+
const entry = this.tools.get(id);
|
|
265
|
+
if (!entry?.registered) {
|
|
295
266
|
log(`Tool ${id} not found`);
|
|
296
267
|
return;
|
|
297
268
|
}
|
|
298
|
-
|
|
299
|
-
|
|
300
|
-
|
|
301
|
-
|
|
302
|
-
|
|
269
|
+
if (entry.element === element)
|
|
270
|
+
return;
|
|
271
|
+
if (entry.element?.isConnected && entry.element.contains(element))
|
|
272
|
+
return;
|
|
273
|
+
this.detachElement(entry);
|
|
303
274
|
const mouseDownHandler = () => this.bringToFront(element);
|
|
304
275
|
element.addEventListener("mousedown", mouseDownHandler);
|
|
305
|
-
|
|
306
|
-
|
|
307
|
-
|
|
308
|
-
|
|
309
|
-
|
|
310
|
-
if (tool.isVisible) {
|
|
311
|
-
element.style.display = "";
|
|
312
|
-
}
|
|
313
|
-
else {
|
|
314
|
-
element.style.display = "none";
|
|
315
|
-
}
|
|
276
|
+
entry.element = element;
|
|
277
|
+
entry.mouseDownHandler = mouseDownHandler;
|
|
278
|
+
element.style.zIndex = String(entry.baseZIndex);
|
|
279
|
+
if (entry.isVisible)
|
|
280
|
+
this.bringToFront(element);
|
|
316
281
|
}
|
|
317
282
|
/**
|
|
318
|
-
* Hide
|
|
283
|
+
* Hide every visible tool, or every instance of one tool with
|
|
284
|
+
* `{ baseId }`, notifying subscribers once.
|
|
319
285
|
*/
|
|
320
|
-
hideAllTools() {
|
|
321
|
-
|
|
322
|
-
|
|
286
|
+
hideAllTools(filter) {
|
|
287
|
+
let changed = false;
|
|
288
|
+
for (const entry of this.tools.values()) {
|
|
289
|
+
if (!entry.isVisible || !matchesFilter(entry.id, filter))
|
|
290
|
+
continue;
|
|
291
|
+
entry.isVisible = false;
|
|
292
|
+
changed = true;
|
|
323
293
|
}
|
|
324
|
-
|
|
294
|
+
if (changed)
|
|
295
|
+
this.notifyListeners();
|
|
325
296
|
}
|
|
326
297
|
/**
|
|
327
|
-
*
|
|
298
|
+
* State of a tool an element registration holds.
|
|
328
299
|
*
|
|
329
300
|
* @param id Tool identifier
|
|
330
|
-
* @returns Tool state or undefined
|
|
331
301
|
*/
|
|
332
302
|
getToolState(id) {
|
|
333
|
-
const
|
|
334
|
-
|
|
335
|
-
return undefined;
|
|
336
|
-
return {
|
|
337
|
-
id: tool.id,
|
|
338
|
-
name: tool.name,
|
|
339
|
-
isVisible: tool.isVisible,
|
|
340
|
-
element: tool.element ?? null,
|
|
341
|
-
layer: tool.layer,
|
|
342
|
-
};
|
|
303
|
+
const entry = this.tools.get(id);
|
|
304
|
+
return entry?.registered ? toToolState(entry) : undefined;
|
|
343
305
|
}
|
|
344
306
|
/**
|
|
345
|
-
*
|
|
346
|
-
*
|
|
347
|
-
* @
|
|
307
|
+
* Every visible tool, or every visible instance of one tool with
|
|
308
|
+
* `{ baseId }`. A tool shown while its element re-renders counts, as
|
|
309
|
+
* {@link isToolVisible} counts it.
|
|
348
310
|
*/
|
|
349
|
-
getVisibleTools() {
|
|
311
|
+
getVisibleTools(filter) {
|
|
350
312
|
return Array.from(this.tools.values())
|
|
351
|
-
.filter((
|
|
352
|
-
.map(
|
|
353
|
-
id: tool.id,
|
|
354
|
-
name: tool.name,
|
|
355
|
-
isVisible: tool.isVisible,
|
|
356
|
-
element: tool.element ?? null,
|
|
357
|
-
layer: tool.layer,
|
|
358
|
-
}));
|
|
313
|
+
.filter((entry) => entry.isVisible && matchesFilter(entry.id, filter))
|
|
314
|
+
.map(toToolState);
|
|
359
315
|
}
|
|
360
316
|
}
|