@pie-players/pie-assessment-toolkit 0.3.46 → 0.3.48
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/dist/attempt/AssessmentSession.js +2 -1
- package/dist/attempt/AssessmentSession.js.map +1 -1
- package/dist/attempt/adapters/activity-to-test-attempt-session.js +12 -8
- package/dist/attempt/adapters/activity-to-test-attempt-session.js.map +1 -1
- package/dist/components/ItemToolBar.custom-element.js +60 -21
- package/dist/components/PieAssessmentToolkit.custom-element.js +83 -28
- package/dist/components/SectionToolBar.custom-element.js +59 -21
- package/dist/index.d.ts +1 -1
- package/dist/index.js.map +1 -1
- package/dist/policy/core/pnp-policy-inputs.js +1 -2
- package/dist/policy/core/pnp-policy-inputs.js.map +1 -1
- package/dist/policy/core/provenance.js.map +1 -1
- package/dist/runtime/SectionRuntimeEngine.js +1 -1
- package/dist/runtime/SectionRuntimeEngine.js.map +1 -1
- package/dist/runtime/core/cohort.js.map +1 -1
- package/dist/runtime/core/engine-input.js.map +1 -1
- package/dist/runtime/core/engine-readiness.js.map +1 -1
- package/dist/runtime/core/engine-resolver.js.map +1 -1
- package/dist/runtime/core/engine-transition.js +1 -3
- package/dist/runtime/core/engine-transition.js.map +1 -1
- package/dist/runtime/registration-events.js.map +1 -1
- package/dist/runtime/session-event-emitter-policy.js.map +1 -1
- package/dist/services/HighlightCoordinator.js +2 -1
- package/dist/services/HighlightCoordinator.js.map +1 -1
- package/dist/services/I18nService.d.ts +1 -1
- package/dist/services/I18nService.js.map +1 -1
- package/dist/services/SSMLExtractor.js.map +1 -1
- package/dist/services/TTSService.js +5 -2
- package/dist/services/TTSService.js.map +1 -1
- package/dist/services/ThemeProvider.js.map +1 -1
- package/dist/services/ToolRegistry.d.ts +1 -1
- package/dist/services/ToolRegistry.js.map +1 -1
- package/dist/services/ToolkitCoordinator.js +21 -11
- package/dist/services/ToolkitCoordinator.js.map +1 -1
- package/dist/services/createDefaultToolRegistry.js +4 -2
- package/dist/services/createDefaultToolRegistry.js.map +1 -1
- package/dist/services/framework-error-bus.js.map +1 -1
- package/dist/services/framework-error.js.map +1 -1
- package/dist/services/interfaces.js.map +1 -1
- package/dist/services/section-controller-types.js.map +1 -1
- package/dist/services/tool-config-defaults.js +7 -1
- package/dist/services/tool-config-defaults.js.map +1 -1
- package/dist/services/tool-config-validation.js +3 -1
- package/dist/services/tool-config-validation.js.map +1 -1
- package/dist/services/tool-instance-id.js.map +1 -1
- package/dist/services/tool-providers/DesmosToolProvider.js.map +1 -1
- package/dist/services/tool-providers/TTSToolProvider.js.map +1 -1
- package/dist/services/toolbar-items.js.map +1 -1
- package/dist/services/tools-config-normalizer.js +1 -2
- package/dist/services/tools-config-normalizer.js.map +1 -1
- package/dist/services/tts/browser-provider.js +60 -18
- package/dist/services/tts/browser-provider.js.map +1 -1
- package/dist/services/tts/catalog-span-alignment.js +8 -3
- package/dist/services/tts/catalog-span-alignment.js.map +1 -1
- package/dist/services/tts/generated-speech/assemble-plan.js.map +1 -1
- package/dist/services/tts/generated-speech/index.d.ts +1 -1
- package/dist/services/tts/generated-speech/index.js +1 -1
- package/dist/services/tts/generated-speech/index.js.map +1 -1
- package/dist/services/tts/generated-speech/math-speech-cache.js +3 -1
- package/dist/services/tts/generated-speech/math-speech-cache.js.map +1 -1
- package/dist/services/tts/highlight-pipeline/boundary-normalizer.js.map +1 -1
- package/dist/services/tts/highlight-pipeline/create-highlight-plan.js.map +1 -1
- package/dist/services/tts/math-alignment/mathml-tokenizer.js.map +1 -1
- package/dist/services/tts/math-alignment/sequence-aligner.js.map +1 -1
- package/dist/services/tts/math-alignment/speech-tokenizer.js.map +1 -1
- package/dist/services/tts/math-aware-text-processing.js +6 -3
- package/dist/services/tts/math-aware-text-processing.js.map +1 -1
- package/dist/services/tts/math-speech.js +3 -1
- package/dist/services/tts/math-speech.js.map +1 -1
- package/dist/services/tts/visual-line-ranges.js.map +1 -1
- package/dist/services/tts-runtime-config.js +6 -2
- package/dist/services/tts-runtime-config.js.map +1 -1
- package/dist/tools/calculators/desmos-provider.js.map +1 -1
- package/dist/tools/default-tool-module-loaders.js.map +1 -1
- package/dist/tools/registrations/accessibility-tools.js.map +1 -1
- package/dist/tools/registrations/calculator.js +1 -1
- package/dist/tools/registrations/calculator.js.map +1 -1
- package/dist/tools/registrations/interaction-tools.js.map +1 -1
- package/dist/tools/registrations/measurement-tools.js.map +1 -1
- package/dist/tools/registrations/subject-specific-tools.js +1 -1
- package/dist/tools/registrations/subject-specific-tools.js.map +1 -1
- package/dist/tools/registrations/tts.js +4 -2
- package/dist/tools/registrations/tts.js.map +1 -1
- package/dist/tools/types.js.map +1 -1
- package/dist/tools/variant-resolver.js.map +1 -1
- package/package.json +7 -7
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"engine-readiness.js","sourceRoot":"","sources":["../../../src/runtime/core/engine-readiness.ts"],"names":[],"mappings":"AAAA;;;;;;;;;;;;;;;;;;GAkBG;AAiCH,MAAM,UAAU,qBAAqB,CACpC,OAA+B;IAE/B,IAAI,OAAO,CAAC,YAAY;QAAE,OAAO,OAAO,CAAC;IACzC,IAAI,OAAO,CAAC,kBAAkB;QAAE,OAAO,OAAO,CAAC;IAC/C,IAAI,OAAO,CAAC,gBAAgB;QAAE,OAAO,mBAAmB,CAAC;IACzD,IAAI,OAAO,CAAC,YAAY;QAAE,OAAO,SAAS,CAAC;IAC3C,OAAO,eAAe,CAAC;AACxB,CAAC;AAED,MAAM,UAAU,qBAAqB,CAAC,IAIrC;IACA,8EAA8E;IAC9E,MAAM,UAAU,
|
|
1
|
+
{"version":3,"file":"engine-readiness.js","sourceRoot":"","sources":["../../../src/runtime/core/engine-readiness.ts"],"names":[],"mappings":"AAAA;;;;;;;;;;;;;;;;;;GAkBG;AAiCH,MAAM,UAAU,qBAAqB,CACpC,OAA+B;IAE/B,IAAI,OAAO,CAAC,YAAY;QAAE,OAAO,OAAO,CAAC;IACzC,IAAI,OAAO,CAAC,kBAAkB;QAAE,OAAO,OAAO,CAAC;IAC/C,IAAI,OAAO,CAAC,gBAAgB;QAAE,OAAO,mBAAmB,CAAC;IACzD,IAAI,OAAO,CAAC,YAAY;QAAE,OAAO,SAAS,CAAC;IAC3C,OAAO,eAAe,CAAC;AACxB,CAAC;AAED,MAAM,UAAU,qBAAqB,CAAC,IAIrC;IACA,8EAA8E;IAC9E,MAAM,UAAU,GACf,IAAI,CAAC,OAAO,CAAC,YAAY,IAAI,IAAI,CAAC,OAAO,CAAC,kBAAkB,CAAC;IAC9D,MAAM,gBAAgB,GACrB,IAAI,CAAC,IAAI,KAAK,QAAQ,CAAC,CAAC,CAAC,UAAU,CAAC,CAAC,CAAC,IAAI,CAAC,OAAO,CAAC,gBAAgB,CAAC;IACrE,MAAM,KAAK,GAAG,qBAAqB,CAAC;QACnC,GAAG,IAAI,CAAC,OAAO;QACf,kBAAkB,EAAE,UAAU;QAC9B,gBAAgB;KAChB,CAAC,CAAC;IAEH,OAAO;QACN,KAAK;QACL,gBAAgB;QAChB,kBAAkB,EAAE,UAAU;QAC9B,MAAM,EAAE,IAAI,CAAC,MAAM;KACnB,CAAC;AACH,CAAC","sourcesContent":["/**\n * Readiness derivation for the section runtime engine (M7).\n *\n * Canonical home of `createReadinessDetail` and `resolveReadinessPhase`.\n * As of M7 PR 7 the previous duplicates in\n * `packages/section-player/src/components/shared/section-player-readiness.ts`\n * have been deleted; section-player now consumes these helpers via\n * `@pie-players/pie-assessment-toolkit/runtime/internal`.\n *\n * Type duplication note: the public DOM-event detail aliases\n * (`SectionPlayerReadinessChangeDetail` /\n * `SectionPlayerReadinessPhase`) still live in section-player's\n * `contracts/public-events.ts` because that file is part of section-\n * player's published custom-element contract. The toolkit core defines\n * `EngineReadinessPhase` independently so it has zero section-player\n * imports. The two definitions must stay structurally identical;\n * that invariant is covered by the readiness assertions in this\n * package's tests, which mirror the section-player suite.\n */\n\n/**\n * Coarse readiness phase label, derived from the four readiness\n * signals. Surfaced via the kernel's `selectReadiness()` /\n * `getSnapshot().readiness` selectors; M6 stages own the stage-level\n * transitions on `pie-stage-change` and use this phase as a\n * convenience label only. The `readiness-change` DOM\n * event that used to surface this directly was removed in the broad\n * architecture review compat sweep alongside its\n * event bridge.\n */\nexport type EngineReadinessPhase =\n\t| \"bootstrapping\"\n\t| \"interaction-ready\"\n\t| \"loading\"\n\t| \"ready\"\n\t| \"error\";\n\nexport type EngineReadinessSignals = {\n\tsectionReady: boolean;\n\tinteractionReady: boolean;\n\tallLoadingComplete: boolean;\n\truntimeError: boolean;\n};\n\nexport type EngineReadinessDetail = {\n\tphase: EngineReadinessPhase;\n\tinteractionReady: boolean;\n\tallLoadingComplete: boolean;\n\treason?: string;\n};\n\nexport function resolveReadinessPhase(\n\tsignals: EngineReadinessSignals,\n): EngineReadinessPhase {\n\tif (signals.runtimeError) return \"error\";\n\tif (signals.allLoadingComplete) return \"ready\";\n\tif (signals.interactionReady) return \"interaction-ready\";\n\tif (signals.sectionReady) return \"loading\";\n\treturn \"bootstrapping\";\n}\n\nexport function createReadinessDetail(args: {\n\tmode: \"progressive\" | \"strict\";\n\tsignals: EngineReadinessSignals;\n\treason?: string;\n}): EngineReadinessDetail {\n\t// Final ready must always be gated by section lifecycle and complete loading.\n\tconst finalReady =\n\t\targs.signals.sectionReady && args.signals.allLoadingComplete;\n\tconst interactionReady =\n\t\targs.mode === \"strict\" ? finalReady : args.signals.interactionReady;\n\tconst phase = resolveReadinessPhase({\n\t\t...args.signals,\n\t\tallLoadingComplete: finalReady,\n\t\tinteractionReady,\n\t});\n\n\treturn {\n\t\tphase,\n\t\tinteractionReady,\n\t\tallLoadingComplete: finalReady,\n\t\treason: args.reason,\n\t};\n}\n"]}
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"engine-resolver.js","sourceRoot":"","sources":["../../../src/runtime/core/engine-resolver.ts"],"names":[],"mappings":"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","sourcesContent":["/**\n * Section runtime engine resolver (M7).\n *\n * Canonical home of `resolveRuntime`, `resolveToolsConfig`, and their\n * supporting helpers/types. As of M7 PR 7 the previous duplicates in\n * `packages/section-player/src/components/shared/section-player-runtime.ts`\n * have been deleted; section-player now consumes these helpers via\n * `@pie-players/pie-assessment-toolkit/runtime/internal`.\n *\n * What is NOT absorbed in this module:\n * - `resolvePlayerRuntime` stays in section-player because it depends on\n * `DEFAULT_PLAYER_DEFINITIONS` (which side-effect-imports the\n * item-player package). The toolkit core stays free of that\n * dependency by exposing a parametrized orchestrator —\n * `resolveSectionEngineRuntimeState` — that takes a `resolvePlayerRuntime`\n * callable. The section-player wrapper\n * (`resolveSectionPlayerRuntimeState` in\n * `packages/section-player/src/components/shared/section-player-host-runtime.ts`)\n * hands its local implementation in.\n *\n * Runtime-owned configuration flows through `runtime.<key>`. Layout-only\n * inputs stay on the section-player host elements.\n */\n\nimport type { LoaderConfig } from \"@pie-players/pie-players-shared/loader-config\";\nimport type {\n\tLoadingCompleteDetail,\n\tStageChangeDetail,\n} from \"@pie-players/pie-players-shared/pie\";\nimport type { FrameworkErrorModel } from \"../../services/framework-error.js\";\nimport type { ToolConfigStrictness } from \"../../services/tool-config-validation.js\";\n\nexport const DEFAULT_ASSESSMENT_ID = \"section-demo-direct\";\nexport const DEFAULT_PLAYER_TYPE = \"iife\";\nexport const DEFAULT_LAZY_INIT = true;\nexport const DEFAULT_ISOLATION = \"inherit\";\nexport const DEFAULT_ENV = { mode: \"gather\", role: \"student\" } as Record<\n\tstring,\n\tunknown\n>;\n\nexport type PlayerOverrides = {\n\tloaderConfig?: LoaderConfig;\n\tloaderOptions?: Record<string, unknown>;\n\t[key: string]: unknown;\n};\n\nexport type FrameworkErrorHandler = (model: FrameworkErrorModel) => void;\nexport type StageChangeHandler = (detail: StageChangeDetail) => void;\nexport type LoadingCompleteHandler = (detail: LoadingCompleteDetail) => void;\n\n/**\n * Section runtime config.\n *\n * Documented exceptions (no runtime mirror, by design): identity\n * (`section-id`, `attempt-id`, `section`); layout-only shell knobs\n * (`show-toolbar`, `toolbar-position`, etc.); and layout-shell host\n * data (`policies`, `hooks`, `toolRegistry`, `*HostButtons`). Those\n * surfaces are layout-shell concerns; the runtime engine does not see\n * them. See section-player's ARCHITECTURE.md for the full policy.\n */\nexport type RuntimeConfig = {\n\tassessmentId?: string;\n\tplayerType?: string;\n\tplayer?: PlayerOverrides | null;\n\tlazyInit?: boolean;\n\ttools?: Record<string, unknown> | null;\n\ttoolContextResolvers?: Record<string, unknown> | null;\n\taccessibility?: Record<string, unknown> | null;\n\tcoordinator?: unknown;\n\tcreateSectionController?: unknown;\n\tisolation?: string;\n\tenv?: Record<string, unknown>;\n\ttoolConfigStrictness?: ToolConfigStrictness;\n\n\t// Canonical framework-error callback.\n\tonFrameworkError?: FrameworkErrorHandler;\n\n\t// Canonical stage-change callback. The DOM event\n\t// `pie-stage-change` remains the primary channel; this callback is\n\t// the convenience surface that mirrors the event one-to-one.\n\tonStageChange?: StageChangeHandler;\n\n\t// Canonical loading-complete callback. Mirrors the\n\t// `pie-loading-complete` DOM event, which the engine dispatches\n\t// once per cohort when every item has finished loading.\n\tonLoadingComplete?: LoadingCompleteHandler;\n};\n\nexport type RuntimeInputs = {\n\tassessmentId?: string;\n\ttoolConfigStrictness?: ToolConfigStrictness;\n\tonFrameworkError?: FrameworkErrorHandler;\n\tonStageChange?: StageChangeHandler;\n\tonLoadingComplete?: LoadingCompleteHandler;\n\truntime: RuntimeConfig | null;\n};\n\n/**\n * Pick the runtime-tier value when defined, otherwise the prop/attribute\n * value. The strict mirror rule means every tier-1 surface is resolved\n * with this single helper; per-feature special-casing is forbidden.\n */\nfunction pick<T>(\n\truntimeVal: T | undefined,\n\tattrVal: T | undefined,\n): T | undefined {\n\treturn runtimeVal !== undefined ? runtimeVal : attrVal;\n}\n\n/**\n * Resolve the canonical `onFrameworkError` handler from the two-tier\n * surface. Precedence (highest first): `runtime.onFrameworkError`,\n * then top-level `onFrameworkError`. Layout CEs and the kernel call\n * this so every entry point converges on the same handler.\n */\nexport function resolveOnFrameworkError(args: {\n\truntime: RuntimeConfig | null;\n\tonFrameworkError?: FrameworkErrorHandler;\n}): FrameworkErrorHandler | undefined {\n\tconst r = args.runtime ?? {};\n\tif (r.onFrameworkError !== undefined) return r.onFrameworkError;\n\treturn args.onFrameworkError;\n}\n\nexport function resolveToolsConfig(args: {\n\truntime: RuntimeConfig | null;\n}) {\n\tconst runtimeTools = (args.runtime?.tools || {}) as Record<string, unknown>;\n\tconst placement = (runtimeTools.placement || {}) as Record<string, unknown>;\n\tconst overlayToolsConfig = { ...runtimeTools, placement: { ...placement } };\n\t// Keep host-provided shape intact; framework-owned validation surfaces malformed config.\n\treturn overlayToolsConfig;\n}\n\nexport function resolveRuntime(args: {\n\tassessmentId: string;\n\truntime: RuntimeConfig | null;\n\teffectiveToolsConfig: unknown;\n\ttoolConfigStrictness?: ToolConfigStrictness;\n\tonFrameworkError?: FrameworkErrorHandler;\n\tonStageChange?: StageChangeHandler;\n\tonLoadingComplete?: LoadingCompleteHandler;\n}) {\n\tconst r = args.runtime || {};\n\tconst runtimePlayer = r.player ? { ...r.player } : null;\n\treturn {\n\t\t...r,\n\t\tassessmentId: pick(r.assessmentId, args.assessmentId),\n\t\tplayerType: r.playerType ?? DEFAULT_PLAYER_TYPE,\n\t\tplayer: runtimePlayer,\n\t\tlazyInit: r.lazyInit ?? DEFAULT_LAZY_INIT,\n\t\taccessibility: r.accessibility ?? null,\n\t\tcoordinator: r.coordinator ?? null,\n\t\tcreateSectionController: r.createSectionController,\n\t\tisolation: r.isolation ?? DEFAULT_ISOLATION,\n\t\tenv: r.env ?? DEFAULT_ENV,\n\t\ttoolConfigStrictness:\n\t\t\tpick(r.toolConfigStrictness, args.toolConfigStrictness) ?? \"error\",\n\n\t\t// Runtime callback wins; top-level callback remains a layout CE event\n\t\t// convenience for hosts that do not use DOM listeners.\n\t\tonFrameworkError: resolveOnFrameworkError({\n\t\t\truntime: args.runtime,\n\t\t\tonFrameworkError: args.onFrameworkError,\n\t\t}),\n\n\t\t// Runtime callback wins over the top-level callback prop.\n\t\tonStageChange: pick(r.onStageChange, args.onStageChange),\n\n\t\t// Runtime callback wins over the top-level callback prop.\n\t\tonLoadingComplete: pick(r.onLoadingComplete, args.onLoadingComplete),\n\n\t\ttools: args.effectiveToolsConfig,\n\t};\n}\n\n/**\n * Effective runtime returned by `resolveRuntime`. The shape is exposed\n * as `unknown` at the public boundary because consumers spread it into\n * arbitrary host props; downstream call sites narrow with the specific\n * keys they need.\n */\nexport type EffectiveRuntime = ReturnType<typeof resolveRuntime>;\n\n/**\n * Engine-side orchestrator that powers `resolveSectionPlayerRuntimeState`\n * from section-player and takes\n * `resolvePlayerRuntime` as an injected callable so the toolkit core\n * stays free of host-coupled defaults (`DEFAULT_PLAYER_DEFINITIONS`).\n */\nexport function resolveSectionEngineRuntimeState<P>(\n\targs: RuntimeInputs,\n\tdeps: {\n\t\tresolvePlayerRuntime: (resolverArgs: {\n\t\t\teffectiveRuntime: Record<string, unknown>;\n\t\t\tplayerType: string;\n\t\t\tenv: Record<string, unknown> | null;\n\t\t}) => P;\n\t},\n): {\n\teffectiveToolsConfig: unknown;\n\teffectiveRuntime: EffectiveRuntime;\n\tplayerRuntime: P;\n} {\n\tconst assessmentId = args.assessmentId ?? DEFAULT_ASSESSMENT_ID;\n\n\tconst effectiveToolsConfig = resolveToolsConfig({\n\t\truntime: args.runtime,\n\t});\n\tconst effectiveRuntime = resolveRuntime({\n\t\tassessmentId,\n\t\truntime: args.runtime,\n\t\teffectiveToolsConfig,\n\t\ttoolConfigStrictness: args.toolConfigStrictness,\n\t\tonFrameworkError: args.onFrameworkError,\n\t\tonStageChange: args.onStageChange,\n\t\tonLoadingComplete: args.onLoadingComplete,\n\t});\n\tconst playerRuntime = deps.resolvePlayerRuntime({\n\t\teffectiveRuntime: effectiveRuntime as Record<string, unknown>,\n\t\tplayerType: String(effectiveRuntime.playerType ?? DEFAULT_PLAYER_TYPE),\n\t\tenv: (effectiveRuntime.env as Record<string, unknown> | null) ?? null,\n\t});\n\treturn {\n\t\teffectiveToolsConfig,\n\t\teffectiveRuntime,\n\t\tplayerRuntime,\n\t};\n}\n"]}
|
|
1
|
+
{"version":3,"file":"engine-resolver.js","sourceRoot":"","sources":["../../../src/runtime/core/engine-resolver.ts"],"names":[],"mappings":"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","sourcesContent":["/**\n * Section runtime engine resolver (M7).\n *\n * Canonical home of `resolveRuntime`, `resolveToolsConfig`, and their\n * supporting helpers/types. As of M7 PR 7 the previous duplicates in\n * `packages/section-player/src/components/shared/section-player-runtime.ts`\n * have been deleted; section-player now consumes these helpers via\n * `@pie-players/pie-assessment-toolkit/runtime/internal`.\n *\n * What is NOT absorbed in this module:\n * - `resolvePlayerRuntime` stays in section-player because it depends on\n * `DEFAULT_PLAYER_DEFINITIONS` (which side-effect-imports the\n * item-player package). The toolkit core stays free of that\n * dependency by exposing a parametrized orchestrator —\n * `resolveSectionEngineRuntimeState` — that takes a `resolvePlayerRuntime`\n * callable. The section-player wrapper\n * (`resolveSectionPlayerRuntimeState` in\n * `packages/section-player/src/components/shared/section-player-host-runtime.ts`)\n * hands its local implementation in.\n *\n * Runtime-owned configuration flows through `runtime.<key>`. Layout-only\n * inputs stay on the section-player host elements.\n */\n\nimport type { LoaderConfig } from \"@pie-players/pie-players-shared/loader-config\";\nimport type {\n\tLoadingCompleteDetail,\n\tStageChangeDetail,\n} from \"@pie-players/pie-players-shared/pie\";\nimport type { FrameworkErrorModel } from \"../../services/framework-error.js\";\nimport type { ToolConfigStrictness } from \"../../services/tool-config-validation.js\";\n\nexport const DEFAULT_ASSESSMENT_ID = \"section-demo-direct\";\nexport const DEFAULT_PLAYER_TYPE = \"iife\";\nexport const DEFAULT_LAZY_INIT = true;\nexport const DEFAULT_ISOLATION = \"inherit\";\nexport const DEFAULT_ENV = { mode: \"gather\", role: \"student\" } as Record<\n\tstring,\n\tunknown\n>;\n\nexport type PlayerOverrides = {\n\tloaderConfig?: LoaderConfig;\n\tloaderOptions?: Record<string, unknown>;\n\t[key: string]: unknown;\n};\n\nexport type FrameworkErrorHandler = (model: FrameworkErrorModel) => void;\nexport type StageChangeHandler = (detail: StageChangeDetail) => void;\nexport type LoadingCompleteHandler = (detail: LoadingCompleteDetail) => void;\n\n/**\n * Section runtime config.\n *\n * Documented exceptions (no runtime mirror, by design): identity\n * (`section-id`, `attempt-id`, `section`); layout-only shell knobs\n * (`show-toolbar`, `toolbar-position`, etc.); and layout-shell host\n * data (`policies`, `hooks`, `toolRegistry`, `*HostButtons`). Those\n * surfaces are layout-shell concerns; the runtime engine does not see\n * them. See section-player's ARCHITECTURE.md for the full policy.\n */\nexport type RuntimeConfig = {\n\tassessmentId?: string;\n\tplayerType?: string;\n\tplayer?: PlayerOverrides | null;\n\tlazyInit?: boolean;\n\ttools?: Record<string, unknown> | null;\n\ttoolContextResolvers?: Record<string, unknown> | null;\n\taccessibility?: Record<string, unknown> | null;\n\tcoordinator?: unknown;\n\tcreateSectionController?: unknown;\n\tisolation?: string;\n\tenv?: Record<string, unknown>;\n\ttoolConfigStrictness?: ToolConfigStrictness;\n\n\t// Canonical framework-error callback.\n\tonFrameworkError?: FrameworkErrorHandler;\n\n\t// Canonical stage-change callback. The DOM event\n\t// `pie-stage-change` remains the primary channel; this callback is\n\t// the convenience surface that mirrors the event one-to-one.\n\tonStageChange?: StageChangeHandler;\n\n\t// Canonical loading-complete callback. Mirrors the\n\t// `pie-loading-complete` DOM event, which the engine dispatches\n\t// once per cohort when every item has finished loading.\n\tonLoadingComplete?: LoadingCompleteHandler;\n};\n\nexport type RuntimeInputs = {\n\tassessmentId?: string;\n\ttoolConfigStrictness?: ToolConfigStrictness;\n\tonFrameworkError?: FrameworkErrorHandler;\n\tonStageChange?: StageChangeHandler;\n\tonLoadingComplete?: LoadingCompleteHandler;\n\truntime: RuntimeConfig | null;\n};\n\n/**\n * Pick the runtime-tier value when defined, otherwise the prop/attribute\n * value. The strict mirror rule means every tier-1 surface is resolved\n * with this single helper; per-feature special-casing is forbidden.\n */\nfunction pick<T>(\n\truntimeVal: T | undefined,\n\tattrVal: T | undefined,\n): T | undefined {\n\treturn runtimeVal !== undefined ? runtimeVal : attrVal;\n}\n\n/**\n * Resolve the canonical `onFrameworkError` handler from the two-tier\n * surface. Precedence (highest first): `runtime.onFrameworkError`,\n * then top-level `onFrameworkError`. Layout CEs and the kernel call\n * this so every entry point converges on the same handler.\n */\nexport function resolveOnFrameworkError(args: {\n\truntime: RuntimeConfig | null;\n\tonFrameworkError?: FrameworkErrorHandler;\n}): FrameworkErrorHandler | undefined {\n\tconst r = args.runtime ?? {};\n\tif (r.onFrameworkError !== undefined) return r.onFrameworkError;\n\treturn args.onFrameworkError;\n}\n\nexport function resolveToolsConfig(args: { runtime: RuntimeConfig | null }) {\n\tconst runtimeTools = (args.runtime?.tools || {}) as Record<string, unknown>;\n\tconst placement = (runtimeTools.placement || {}) as Record<string, unknown>;\n\tconst overlayToolsConfig = { ...runtimeTools, placement: { ...placement } };\n\t// Keep host-provided shape intact; framework-owned validation surfaces malformed config.\n\treturn overlayToolsConfig;\n}\n\nexport function resolveRuntime(args: {\n\tassessmentId: string;\n\truntime: RuntimeConfig | null;\n\teffectiveToolsConfig: unknown;\n\ttoolConfigStrictness?: ToolConfigStrictness;\n\tonFrameworkError?: FrameworkErrorHandler;\n\tonStageChange?: StageChangeHandler;\n\tonLoadingComplete?: LoadingCompleteHandler;\n}) {\n\tconst r = args.runtime || {};\n\tconst runtimePlayer = r.player ? { ...r.player } : null;\n\treturn {\n\t\t...r,\n\t\tassessmentId: pick(r.assessmentId, args.assessmentId),\n\t\tplayerType: r.playerType ?? DEFAULT_PLAYER_TYPE,\n\t\tplayer: runtimePlayer,\n\t\tlazyInit: r.lazyInit ?? DEFAULT_LAZY_INIT,\n\t\taccessibility: r.accessibility ?? null,\n\t\tcoordinator: r.coordinator ?? null,\n\t\tcreateSectionController: r.createSectionController,\n\t\tisolation: r.isolation ?? DEFAULT_ISOLATION,\n\t\tenv: r.env ?? DEFAULT_ENV,\n\t\ttoolConfigStrictness:\n\t\t\tpick(r.toolConfigStrictness, args.toolConfigStrictness) ?? \"error\",\n\n\t\t// Runtime callback wins; top-level callback remains a layout CE event\n\t\t// convenience for hosts that do not use DOM listeners.\n\t\tonFrameworkError: resolveOnFrameworkError({\n\t\t\truntime: args.runtime,\n\t\t\tonFrameworkError: args.onFrameworkError,\n\t\t}),\n\n\t\t// Runtime callback wins over the top-level callback prop.\n\t\tonStageChange: pick(r.onStageChange, args.onStageChange),\n\n\t\t// Runtime callback wins over the top-level callback prop.\n\t\tonLoadingComplete: pick(r.onLoadingComplete, args.onLoadingComplete),\n\n\t\ttools: args.effectiveToolsConfig,\n\t};\n}\n\n/**\n * Effective runtime returned by `resolveRuntime`. The shape is exposed\n * as `unknown` at the public boundary because consumers spread it into\n * arbitrary host props; downstream call sites narrow with the specific\n * keys they need.\n */\nexport type EffectiveRuntime = ReturnType<typeof resolveRuntime>;\n\n/**\n * Engine-side orchestrator that powers `resolveSectionPlayerRuntimeState`\n * from section-player and takes\n * `resolvePlayerRuntime` as an injected callable so the toolkit core\n * stays free of host-coupled defaults (`DEFAULT_PLAYER_DEFINITIONS`).\n */\nexport function resolveSectionEngineRuntimeState<P>(\n\targs: RuntimeInputs,\n\tdeps: {\n\t\tresolvePlayerRuntime: (resolverArgs: {\n\t\t\teffectiveRuntime: Record<string, unknown>;\n\t\t\tplayerType: string;\n\t\t\tenv: Record<string, unknown> | null;\n\t\t}) => P;\n\t},\n): {\n\teffectiveToolsConfig: unknown;\n\teffectiveRuntime: EffectiveRuntime;\n\tplayerRuntime: P;\n} {\n\tconst assessmentId = args.assessmentId ?? DEFAULT_ASSESSMENT_ID;\n\n\tconst effectiveToolsConfig = resolveToolsConfig({\n\t\truntime: args.runtime,\n\t});\n\tconst effectiveRuntime = resolveRuntime({\n\t\tassessmentId,\n\t\truntime: args.runtime,\n\t\teffectiveToolsConfig,\n\t\ttoolConfigStrictness: args.toolConfigStrictness,\n\t\tonFrameworkError: args.onFrameworkError,\n\t\tonStageChange: args.onStageChange,\n\t\tonLoadingComplete: args.onLoadingComplete,\n\t});\n\tconst playerRuntime = deps.resolvePlayerRuntime({\n\t\teffectiveRuntime: effectiveRuntime as Record<string, unknown>,\n\t\tplayerType: String(effectiveRuntime.playerType ?? DEFAULT_PLAYER_TYPE),\n\t\tenv: (effectiveRuntime.env as Record<string, unknown> | null) ?? null,\n\t});\n\treturn {\n\t\teffectiveToolsConfig,\n\t\teffectiveRuntime,\n\t\tplayerRuntime,\n\t};\n}\n"]}
|
|
@@ -86,9 +86,7 @@ function applyReadinessUpdate(state, args) {
|
|
|
86
86
|
// Canonical `loading-complete` emission. One-shot per cohort, gated
|
|
87
87
|
// on the readiness signals indicating every item has finished
|
|
88
88
|
// loading.
|
|
89
|
-
if (detail.allLoadingComplete &&
|
|
90
|
-
state.cohort &&
|
|
91
|
-
!loadingCompleteEmitted) {
|
|
89
|
+
if (detail.allLoadingComplete && state.cohort && !loadingCompleteEmitted) {
|
|
92
90
|
loadingCompleteEmitted = true;
|
|
93
91
|
outputs.push({
|
|
94
92
|
kind: "loading-complete",
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"engine-transition.js","sourceRoot":"","sources":["../../../src/runtime/core/engine-transition.ts"],"names":[],"mappings":"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","sourcesContent":["/**\n * Pure transition function for the section runtime engine (M7 — Variant\n * C, layered core).\n *\n * `transition(state, input)` is total over `(state, input)` pairs and\n * returns:\n * - the next `SectionEngineState` (immutable; the input state object\n * is never mutated);\n * - the ordered list of `SectionEngineOutput`s the adapter must\n * dispatch (DOM events, framework-error fan-out, etc.).\n *\n * The function imports nothing from Svelte, the DOM, or the\n * coordinator. The `core/` constraint is enforced by the per-PR audit\n * step in the M7 implementation plan.\n *\n * Phase machine (per `engine-state.ts`):\n * idle → booting-section → engine-ready → interactive → disposed\n * (cohort-change rolls back to booting-section for the new cohort\n * after emitting `disposed` for the outgoing cohort)\n *\n * Output ordering invariants:\n * 1. `stage-change` for stage advancement fires before any\n * `loading-complete` triggered by the same input.\n * 2. `loading-complete` fires once per cohort, gated on\n * `state.loadingCompleteEmitted`.\n * 3. `framework-error` outputs are independent of the stage chain\n * and do not move the phase.\n *\n * Readiness alias output kinds (`readiness-change`,\n * `interaction-ready`, `ready`) and their DOM-event bridge were\n * removed in the broad architecture review compat sweep. Hosts that\n * need the readiness detail read it via the kernel's `selectReadiness`\n * / `getSnapshot` selectors or via `SectionEngineCore.getState()`.\n */\n\nimport { cohortsEqual, type CohortKey } from \"./cohort.js\";\nimport type { SectionEngineInput } from \"./engine-input.js\";\nimport type { SectionEngineOutput } from \"./engine-output.js\";\nimport {\n\tcreateReadinessDetail,\n\ttype EngineReadinessSignals,\n} from \"./engine-readiness.js\";\nimport { phaseToStage } from \"./engine-stage-derivation.js\";\nimport {\n\tcreateInitialEngineState,\n\ttype SectionEnginePhase,\n\ttype SectionEngineState,\n} from \"./engine-state.js\";\n\nexport interface TransitionResult {\n\tstate: SectionEngineState;\n\toutputs: SectionEngineOutput[];\n}\n\nfunction emitStageChange(\n\toutputs: SectionEngineOutput[],\n\tphase: SectionEnginePhase,\n\tcohort: CohortKey | null,\n\tstatus: \"entered\" | \"skipped\" | \"failed\" = \"entered\",\n): void {\n\tconst stage = phaseToStage(phase);\n\tif (!stage) return;\n\toutputs.push({ kind: \"stage-change\", stage, status, cohort });\n}\n\n/**\n * Transition the engine after `initialize` / `cohort-change`. Sets\n * the new cohort, resets latches, stores the resolved runtime/tools,\n * and emits the `composed` stage.\n */\nfunction startCohort(args: {\n\tstate: SectionEngineState;\n\tcohort: CohortKey;\n\teffectiveRuntime: SectionEngineState[\"effectiveRuntime\"];\n\teffectiveToolsConfig: unknown;\n\titemCount: number;\n}): { state: SectionEngineState; outputs: SectionEngineOutput[] } {\n\tconst next: SectionEngineState = {\n\t\t...createInitialEngineState(),\n\t\tphase: \"booting-section\",\n\t\tcohort: args.cohort,\n\t\teffectiveRuntime: args.effectiveRuntime,\n\t\teffectiveToolsConfig: args.effectiveToolsConfig,\n\t\titemCount: args.itemCount,\n\t};\n\tconst outputs: SectionEngineOutput[] = [];\n\temitStageChange(outputs, \"booting-section\", args.cohort);\n\treturn { state: next, outputs };\n}\n\n/**\n * Apply a readiness update: store new signals, derive the detail in\n * the requested mode, advance the phase to `interactive` when gated,\n * and emit `loading-complete` once per cohort.\n */\nfunction applyReadinessUpdate(\n\tstate: SectionEngineState,\n\targs: {\n\t\tsignals: EngineReadinessSignals;\n\t\tmode: \"progressive\" | \"strict\";\n\t\tloadedCount: number;\n\t\titemCount: number;\n\t},\n): TransitionResult {\n\tif (state.phase === \"idle\" || state.phase === \"disposed\") {\n\t\t// No cohort to update; ignore.\n\t\treturn { state, outputs: [] };\n\t}\n\n\tconst detail = createReadinessDetail({\n\t\tmode: args.mode,\n\t\tsignals: args.signals,\n\t});\n\tconst outputs: SectionEngineOutput[] = [];\n\n\tlet phase = state.phase;\n\tlet loadingCompleteEmitted = state.loadingCompleteEmitted;\n\n\t// Stage advancement: engine-ready → interactive when readiness\n\t// satisfies `interactionReady` (mode-aware via `createReadinessDetail`).\n\tif (phase === \"engine-ready\" && detail.interactionReady) {\n\t\tphase = \"interactive\";\n\t\temitStageChange(outputs, phase, state.cohort);\n\t}\n\n\t// Canonical `loading-complete` emission. One-shot per cohort, gated\n\t// on the readiness signals indicating every item has finished\n\t// loading.\n\tif (\n\t\tdetail.allLoadingComplete &&\n\t\tstate.cohort &&\n\t\t!loadingCompleteEmitted\n\t) {\n\t\tloadingCompleteEmitted = true;\n\t\toutputs.push({\n\t\t\tkind: \"loading-complete\",\n\t\t\tcohort: state.cohort,\n\t\t\titemCount: args.itemCount,\n\t\t\tloadedCount: args.loadedCount,\n\t\t});\n\t}\n\n\tconst nextState: SectionEngineState = {\n\t\t...state,\n\t\tphase,\n\t\treadinessSignals: args.signals,\n\t\tloadedCount: args.loadedCount,\n\t\titemCount: args.itemCount,\n\t\tloadingCompleteEmitted,\n\t};\n\treturn { state: nextState, outputs };\n}\n\n/**\n * Pure transition. Total over `(state, input)`; never mutates inputs;\n * never throws. Unhandled inputs after `disposed` fall through to a\n * no-op (the adapter is responsible for not feeding them in, but the\n * core stays safe by design).\n */\nexport function transition(\n\tstate: SectionEngineState,\n\tinput: SectionEngineInput,\n): TransitionResult {\n\tswitch (input.kind) {\n\t\tcase \"initialize\": {\n\t\t\tif (state.phase === \"disposed\") {\n\t\t\t\t// The engine has been disposed; ignore.\n\t\t\t\treturn { state, outputs: [] };\n\t\t\t}\n\t\t\tif (state.phase !== \"idle\") {\n\t\t\t\t// Already initialized. Treat as `update-runtime` for the\n\t\t\t\t// current cohort if the cohort matches; otherwise treat as\n\t\t\t\t// a `cohort-change`.\n\t\t\t\tif (cohortsEqual(state.cohort, input.cohort)) {\n\t\t\t\t\treturn transition(state, {\n\t\t\t\t\t\tkind: \"update-runtime\",\n\t\t\t\t\t\teffectiveRuntime: input.effectiveRuntime,\n\t\t\t\t\t\teffectiveToolsConfig: input.effectiveToolsConfig,\n\t\t\t\t\t});\n\t\t\t\t}\n\t\t\t\treturn transition(state, {\n\t\t\t\t\tkind: \"cohort-change\",\n\t\t\t\t\tcohort: input.cohort,\n\t\t\t\t\teffectiveRuntime: input.effectiveRuntime,\n\t\t\t\t\teffectiveToolsConfig: input.effectiveToolsConfig,\n\t\t\t\t\titemCount: input.itemCount,\n\t\t\t\t});\n\t\t\t}\n\t\t\treturn startCohort({\n\t\t\t\tstate,\n\t\t\t\tcohort: input.cohort,\n\t\t\t\teffectiveRuntime: input.effectiveRuntime,\n\t\t\t\teffectiveToolsConfig: input.effectiveToolsConfig,\n\t\t\t\titemCount: input.itemCount,\n\t\t\t});\n\t\t}\n\n\t\tcase \"update-runtime\": {\n\t\t\tif (state.phase === \"idle\" || state.phase === \"disposed\") {\n\t\t\t\treturn { state, outputs: [] };\n\t\t\t}\n\t\t\treturn {\n\t\t\t\tstate: {\n\t\t\t\t\t...state,\n\t\t\t\t\teffectiveRuntime: input.effectiveRuntime,\n\t\t\t\t\teffectiveToolsConfig: input.effectiveToolsConfig,\n\t\t\t\t},\n\t\t\t\toutputs: [],\n\t\t\t};\n\t\t}\n\n\t\tcase \"cohort-change\": {\n\t\t\tif (state.phase === \"disposed\") {\n\t\t\t\treturn { state, outputs: [] };\n\t\t\t}\n\t\t\tif (cohortsEqual(state.cohort, input.cohort)) {\n\t\t\t\t// No-op cohort change; fall back to a runtime update.\n\t\t\t\treturn transition(state, {\n\t\t\t\t\tkind: \"update-runtime\",\n\t\t\t\t\teffectiveRuntime: input.effectiveRuntime,\n\t\t\t\t\teffectiveToolsConfig: input.effectiveToolsConfig,\n\t\t\t\t});\n\t\t\t}\n\t\t\tconst outputs: SectionEngineOutput[] = [];\n\t\t\tif (state.phase !== \"idle\") {\n\t\t\t\t// Emit `disposed` for the outgoing cohort before we wipe state.\n\t\t\t\toutputs.push({\n\t\t\t\t\tkind: \"stage-change\",\n\t\t\t\t\tstage: \"disposed\",\n\t\t\t\t\tstatus: \"entered\",\n\t\t\t\t\tcohort: state.cohort,\n\t\t\t\t});\n\t\t\t}\n\t\t\tconst started = startCohort({\n\t\t\t\tstate,\n\t\t\t\tcohort: input.cohort,\n\t\t\t\teffectiveRuntime: input.effectiveRuntime,\n\t\t\t\teffectiveToolsConfig: input.effectiveToolsConfig,\n\t\t\t\titemCount: input.itemCount,\n\t\t\t});\n\t\t\treturn {\n\t\t\t\tstate: started.state,\n\t\t\t\toutputs: [...outputs, ...started.outputs],\n\t\t\t};\n\t\t}\n\n\t\tcase \"section-controller-resolved\": {\n\t\t\tif (state.phase !== \"booting-section\") {\n\t\t\t\t// Either too early (idle), too late (interactive / disposed),\n\t\t\t\t// or a duplicate notification; the FSM is monotonic.\n\t\t\t\treturn {\n\t\t\t\t\tstate: { ...state, controllerResolved: true },\n\t\t\t\t\toutputs: [],\n\t\t\t\t};\n\t\t\t}\n\t\t\tconst outputs: SectionEngineOutput[] = [];\n\t\t\temitStageChange(outputs, \"engine-ready\", state.cohort);\n\t\t\treturn {\n\t\t\t\tstate: {\n\t\t\t\t\t...state,\n\t\t\t\t\tphase: \"engine-ready\",\n\t\t\t\t\tcontrollerResolved: true,\n\t\t\t\t},\n\t\t\t\toutputs,\n\t\t\t};\n\t\t}\n\n\t\tcase \"update-readiness-signals\": {\n\t\t\treturn applyReadinessUpdate(state, {\n\t\t\t\tsignals: input.signals,\n\t\t\t\tmode: input.mode,\n\t\t\t\tloadedCount: input.loadedCount,\n\t\t\t\titemCount: input.itemCount,\n\t\t\t});\n\t\t}\n\n\t\tcase \"framework-error\": {\n\t\t\treturn {\n\t\t\t\tstate: {\n\t\t\t\t\t...state,\n\t\t\t\t\tlastFrameworkError: input.error,\n\t\t\t\t\treadinessSignals: {\n\t\t\t\t\t\t...state.readinessSignals,\n\t\t\t\t\t\truntimeError: true,\n\t\t\t\t\t},\n\t\t\t\t},\n\t\t\t\toutputs: [{ kind: \"framework-error\", error: input.error }],\n\t\t\t};\n\t\t}\n\n\t\tcase \"dispose\": {\n\t\t\tif (state.phase === \"disposed\") {\n\t\t\t\treturn { state, outputs: [] };\n\t\t\t}\n\t\t\tconst outputs: SectionEngineOutput[] = [];\n\t\t\tif (state.phase !== \"idle\") {\n\t\t\t\temitStageChange(outputs, \"disposed\", state.cohort);\n\t\t\t}\n\t\t\treturn {\n\t\t\t\tstate: {\n\t\t\t\t\t...state,\n\t\t\t\t\tphase: \"disposed\",\n\t\t\t\t},\n\t\t\t\toutputs,\n\t\t\t};\n\t\t}\n\n\t\tdefault: {\n\t\t\tconst exhaustive: never = input;\n\t\t\tvoid exhaustive;\n\t\t\treturn { state, outputs: [] };\n\t\t}\n\t}\n}\n"]}
|
|
1
|
+
{"version":3,"file":"engine-transition.js","sourceRoot":"","sources":["../../../src/runtime/core/engine-transition.ts"],"names":[],"mappings":"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","sourcesContent":["/**\n * Pure transition function for the section runtime engine (M7 — Variant\n * C, layered core).\n *\n * `transition(state, input)` is total over `(state, input)` pairs and\n * returns:\n * - the next `SectionEngineState` (immutable; the input state object\n * is never mutated);\n * - the ordered list of `SectionEngineOutput`s the adapter must\n * dispatch (DOM events, framework-error fan-out, etc.).\n *\n * The function imports nothing from Svelte, the DOM, or the\n * coordinator. The `core/` constraint is enforced by the per-PR audit\n * step in the M7 implementation plan.\n *\n * Phase machine (per `engine-state.ts`):\n * idle → booting-section → engine-ready → interactive → disposed\n * (cohort-change rolls back to booting-section for the new cohort\n * after emitting `disposed` for the outgoing cohort)\n *\n * Output ordering invariants:\n * 1. `stage-change` for stage advancement fires before any\n * `loading-complete` triggered by the same input.\n * 2. `loading-complete` fires once per cohort, gated on\n * `state.loadingCompleteEmitted`.\n * 3. `framework-error` outputs are independent of the stage chain\n * and do not move the phase.\n *\n * Readiness alias output kinds (`readiness-change`,\n * `interaction-ready`, `ready`) and their DOM-event bridge were\n * removed in the broad architecture review compat sweep. Hosts that\n * need the readiness detail read it via the kernel's `selectReadiness`\n * / `getSnapshot` selectors or via `SectionEngineCore.getState()`.\n */\n\nimport { cohortsEqual, type CohortKey } from \"./cohort.js\";\nimport type { SectionEngineInput } from \"./engine-input.js\";\nimport type { SectionEngineOutput } from \"./engine-output.js\";\nimport {\n\tcreateReadinessDetail,\n\ttype EngineReadinessSignals,\n} from \"./engine-readiness.js\";\nimport { phaseToStage } from \"./engine-stage-derivation.js\";\nimport {\n\tcreateInitialEngineState,\n\ttype SectionEnginePhase,\n\ttype SectionEngineState,\n} from \"./engine-state.js\";\n\nexport interface TransitionResult {\n\tstate: SectionEngineState;\n\toutputs: SectionEngineOutput[];\n}\n\nfunction emitStageChange(\n\toutputs: SectionEngineOutput[],\n\tphase: SectionEnginePhase,\n\tcohort: CohortKey | null,\n\tstatus: \"entered\" | \"skipped\" | \"failed\" = \"entered\",\n): void {\n\tconst stage = phaseToStage(phase);\n\tif (!stage) return;\n\toutputs.push({ kind: \"stage-change\", stage, status, cohort });\n}\n\n/**\n * Transition the engine after `initialize` / `cohort-change`. Sets\n * the new cohort, resets latches, stores the resolved runtime/tools,\n * and emits the `composed` stage.\n */\nfunction startCohort(args: {\n\tstate: SectionEngineState;\n\tcohort: CohortKey;\n\teffectiveRuntime: SectionEngineState[\"effectiveRuntime\"];\n\teffectiveToolsConfig: unknown;\n\titemCount: number;\n}): { state: SectionEngineState; outputs: SectionEngineOutput[] } {\n\tconst next: SectionEngineState = {\n\t\t...createInitialEngineState(),\n\t\tphase: \"booting-section\",\n\t\tcohort: args.cohort,\n\t\teffectiveRuntime: args.effectiveRuntime,\n\t\teffectiveToolsConfig: args.effectiveToolsConfig,\n\t\titemCount: args.itemCount,\n\t};\n\tconst outputs: SectionEngineOutput[] = [];\n\temitStageChange(outputs, \"booting-section\", args.cohort);\n\treturn { state: next, outputs };\n}\n\n/**\n * Apply a readiness update: store new signals, derive the detail in\n * the requested mode, advance the phase to `interactive` when gated,\n * and emit `loading-complete` once per cohort.\n */\nfunction applyReadinessUpdate(\n\tstate: SectionEngineState,\n\targs: {\n\t\tsignals: EngineReadinessSignals;\n\t\tmode: \"progressive\" | \"strict\";\n\t\tloadedCount: number;\n\t\titemCount: number;\n\t},\n): TransitionResult {\n\tif (state.phase === \"idle\" || state.phase === \"disposed\") {\n\t\t// No cohort to update; ignore.\n\t\treturn { state, outputs: [] };\n\t}\n\n\tconst detail = createReadinessDetail({\n\t\tmode: args.mode,\n\t\tsignals: args.signals,\n\t});\n\tconst outputs: SectionEngineOutput[] = [];\n\n\tlet phase = state.phase;\n\tlet loadingCompleteEmitted = state.loadingCompleteEmitted;\n\n\t// Stage advancement: engine-ready → interactive when readiness\n\t// satisfies `interactionReady` (mode-aware via `createReadinessDetail`).\n\tif (phase === \"engine-ready\" && detail.interactionReady) {\n\t\tphase = \"interactive\";\n\t\temitStageChange(outputs, phase, state.cohort);\n\t}\n\n\t// Canonical `loading-complete` emission. One-shot per cohort, gated\n\t// on the readiness signals indicating every item has finished\n\t// loading.\n\tif (detail.allLoadingComplete && state.cohort && !loadingCompleteEmitted) {\n\t\tloadingCompleteEmitted = true;\n\t\toutputs.push({\n\t\t\tkind: \"loading-complete\",\n\t\t\tcohort: state.cohort,\n\t\t\titemCount: args.itemCount,\n\t\t\tloadedCount: args.loadedCount,\n\t\t});\n\t}\n\n\tconst nextState: SectionEngineState = {\n\t\t...state,\n\t\tphase,\n\t\treadinessSignals: args.signals,\n\t\tloadedCount: args.loadedCount,\n\t\titemCount: args.itemCount,\n\t\tloadingCompleteEmitted,\n\t};\n\treturn { state: nextState, outputs };\n}\n\n/**\n * Pure transition. Total over `(state, input)`; never mutates inputs;\n * never throws. Unhandled inputs after `disposed` fall through to a\n * no-op (the adapter is responsible for not feeding them in, but the\n * core stays safe by design).\n */\nexport function transition(\n\tstate: SectionEngineState,\n\tinput: SectionEngineInput,\n): TransitionResult {\n\tswitch (input.kind) {\n\t\tcase \"initialize\": {\n\t\t\tif (state.phase === \"disposed\") {\n\t\t\t\t// The engine has been disposed; ignore.\n\t\t\t\treturn { state, outputs: [] };\n\t\t\t}\n\t\t\tif (state.phase !== \"idle\") {\n\t\t\t\t// Already initialized. Treat as `update-runtime` for the\n\t\t\t\t// current cohort if the cohort matches; otherwise treat as\n\t\t\t\t// a `cohort-change`.\n\t\t\t\tif (cohortsEqual(state.cohort, input.cohort)) {\n\t\t\t\t\treturn transition(state, {\n\t\t\t\t\t\tkind: \"update-runtime\",\n\t\t\t\t\t\teffectiveRuntime: input.effectiveRuntime,\n\t\t\t\t\t\teffectiveToolsConfig: input.effectiveToolsConfig,\n\t\t\t\t\t});\n\t\t\t\t}\n\t\t\t\treturn transition(state, {\n\t\t\t\t\tkind: \"cohort-change\",\n\t\t\t\t\tcohort: input.cohort,\n\t\t\t\t\teffectiveRuntime: input.effectiveRuntime,\n\t\t\t\t\teffectiveToolsConfig: input.effectiveToolsConfig,\n\t\t\t\t\titemCount: input.itemCount,\n\t\t\t\t});\n\t\t\t}\n\t\t\treturn startCohort({\n\t\t\t\tstate,\n\t\t\t\tcohort: input.cohort,\n\t\t\t\teffectiveRuntime: input.effectiveRuntime,\n\t\t\t\teffectiveToolsConfig: input.effectiveToolsConfig,\n\t\t\t\titemCount: input.itemCount,\n\t\t\t});\n\t\t}\n\n\t\tcase \"update-runtime\": {\n\t\t\tif (state.phase === \"idle\" || state.phase === \"disposed\") {\n\t\t\t\treturn { state, outputs: [] };\n\t\t\t}\n\t\t\treturn {\n\t\t\t\tstate: {\n\t\t\t\t\t...state,\n\t\t\t\t\teffectiveRuntime: input.effectiveRuntime,\n\t\t\t\t\teffectiveToolsConfig: input.effectiveToolsConfig,\n\t\t\t\t},\n\t\t\t\toutputs: [],\n\t\t\t};\n\t\t}\n\n\t\tcase \"cohort-change\": {\n\t\t\tif (state.phase === \"disposed\") {\n\t\t\t\treturn { state, outputs: [] };\n\t\t\t}\n\t\t\tif (cohortsEqual(state.cohort, input.cohort)) {\n\t\t\t\t// No-op cohort change; fall back to a runtime update.\n\t\t\t\treturn transition(state, {\n\t\t\t\t\tkind: \"update-runtime\",\n\t\t\t\t\teffectiveRuntime: input.effectiveRuntime,\n\t\t\t\t\teffectiveToolsConfig: input.effectiveToolsConfig,\n\t\t\t\t});\n\t\t\t}\n\t\t\tconst outputs: SectionEngineOutput[] = [];\n\t\t\tif (state.phase !== \"idle\") {\n\t\t\t\t// Emit `disposed` for the outgoing cohort before we wipe state.\n\t\t\t\toutputs.push({\n\t\t\t\t\tkind: \"stage-change\",\n\t\t\t\t\tstage: \"disposed\",\n\t\t\t\t\tstatus: \"entered\",\n\t\t\t\t\tcohort: state.cohort,\n\t\t\t\t});\n\t\t\t}\n\t\t\tconst started = startCohort({\n\t\t\t\tstate,\n\t\t\t\tcohort: input.cohort,\n\t\t\t\teffectiveRuntime: input.effectiveRuntime,\n\t\t\t\teffectiveToolsConfig: input.effectiveToolsConfig,\n\t\t\t\titemCount: input.itemCount,\n\t\t\t});\n\t\t\treturn {\n\t\t\t\tstate: started.state,\n\t\t\t\toutputs: [...outputs, ...started.outputs],\n\t\t\t};\n\t\t}\n\n\t\tcase \"section-controller-resolved\": {\n\t\t\tif (state.phase !== \"booting-section\") {\n\t\t\t\t// Either too early (idle), too late (interactive / disposed),\n\t\t\t\t// or a duplicate notification; the FSM is monotonic.\n\t\t\t\treturn {\n\t\t\t\t\tstate: { ...state, controllerResolved: true },\n\t\t\t\t\toutputs: [],\n\t\t\t\t};\n\t\t\t}\n\t\t\tconst outputs: SectionEngineOutput[] = [];\n\t\t\temitStageChange(outputs, \"engine-ready\", state.cohort);\n\t\t\treturn {\n\t\t\t\tstate: {\n\t\t\t\t\t...state,\n\t\t\t\t\tphase: \"engine-ready\",\n\t\t\t\t\tcontrollerResolved: true,\n\t\t\t\t},\n\t\t\t\toutputs,\n\t\t\t};\n\t\t}\n\n\t\tcase \"update-readiness-signals\": {\n\t\t\treturn applyReadinessUpdate(state, {\n\t\t\t\tsignals: input.signals,\n\t\t\t\tmode: input.mode,\n\t\t\t\tloadedCount: input.loadedCount,\n\t\t\t\titemCount: input.itemCount,\n\t\t\t});\n\t\t}\n\n\t\tcase \"framework-error\": {\n\t\t\treturn {\n\t\t\t\tstate: {\n\t\t\t\t\t...state,\n\t\t\t\t\tlastFrameworkError: input.error,\n\t\t\t\t\treadinessSignals: {\n\t\t\t\t\t\t...state.readinessSignals,\n\t\t\t\t\t\truntimeError: true,\n\t\t\t\t\t},\n\t\t\t\t},\n\t\t\t\toutputs: [{ kind: \"framework-error\", error: input.error }],\n\t\t\t};\n\t\t}\n\n\t\tcase \"dispose\": {\n\t\t\tif (state.phase === \"disposed\") {\n\t\t\t\treturn { state, outputs: [] };\n\t\t\t}\n\t\t\tconst outputs: SectionEngineOutput[] = [];\n\t\t\tif (state.phase !== \"idle\") {\n\t\t\t\temitStageChange(outputs, \"disposed\", state.cohort);\n\t\t\t}\n\t\t\treturn {\n\t\t\t\tstate: {\n\t\t\t\t\t...state,\n\t\t\t\t\tphase: \"disposed\",\n\t\t\t\t},\n\t\t\t\toutputs,\n\t\t\t};\n\t\t}\n\n\t\tdefault: {\n\t\t\tconst exhaustive: never = input;\n\t\t\tvoid exhaustive;\n\t\t\treturn { state, outputs: [] };\n\t\t}\n\t}\n}\n"]}
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"registration-events.js","sourceRoot":"","sources":["../../src/runtime/registration-events.ts"],"names":[],"mappings":"AAAA,MAAM,CAAC,MAAM,kBAAkB,GAAG,cAAc,CAAC;AACjD,MAAM,CAAC,MAAM,oBAAoB,GAAG,gBAAgB,CAAC;AACrD,MAAM,CAAC,MAAM,uCAAuC,
|
|
1
|
+
{"version":3,"file":"registration-events.js","sourceRoot":"","sources":["../../src/runtime/registration-events.ts"],"names":[],"mappings":"AAAA,MAAM,CAAC,MAAM,kBAAkB,GAAG,cAAc,CAAC;AACjD,MAAM,CAAC,MAAM,oBAAoB,GAAG,gBAAgB,CAAC;AACrD,MAAM,CAAC,MAAM,uCAAuC,GACnD,0BAA0B,CAAC;AAC5B,MAAM,CAAC,MAAM,8BAA8B,GAAG,sBAAsB,CAAC;AACrE,MAAM,CAAC,MAAM,iCAAiC,GAAG,oBAAoB,CAAC;AACtE,MAAM,CAAC,MAAM,oCAAoC,GAAG,uBAAuB,CAAC","sourcesContent":["export const PIE_REGISTER_EVENT = \"pie-register\";\nexport const PIE_UNREGISTER_EVENT = \"pie-unregister\";\nexport const PIE_INTERNAL_ITEM_SESSION_CHANGED_EVENT =\n\t\"pie-item-session-changed\";\nexport const PIE_ITEM_SESSION_CHANGED_EVENT = \"item-session-changed\";\nexport const PIE_INTERNAL_CONTENT_LOADED_EVENT = \"pie-content-loaded\";\nexport const PIE_INTERNAL_ITEM_PLAYER_ERROR_EVENT = \"pie-item-player-error\";\n\nexport type RuntimeRegistrationKind = \"item\" | \"passage\";\n\nexport interface RuntimeRegistrationDetail {\n\tkind: RuntimeRegistrationKind;\n\titemId: string;\n\tcanonicalItemId?: string;\n\tcontentKind?: string;\n\titem?: unknown;\n\telement: HTMLElement;\n}\n\nexport interface ItemSessionChangedDetail {\n\titemId: string;\n\tcanonicalItemId?: string;\n\tsession: unknown;\n\tsourceRuntimeId?: string;\n}\n\nexport interface InternalItemSessionChangedDetail {\n\titemId: string;\n\tsession: unknown;\n}\n\nexport interface InternalContentLoadedDetail {\n\titemId: string;\n\tcanonicalItemId?: string;\n\tcontentKind?: string;\n\tdetail?: unknown;\n}\n\nexport interface InternalItemPlayerErrorDetail {\n\titemId: string;\n\tcanonicalItemId?: string;\n\tcontentKind?: string;\n\terror: unknown;\n}\n"]}
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"session-event-emitter-policy.js","sourceRoot":"","sources":["../../src/runtime/session-event-emitter-policy.ts"],"names":[],"mappings":"AAKA,MAAM,UAAU,4BAA4B;IAC3C,OAAO;QACN,iCAAiC,EAAE,IAAI,GAAG,EAAkB;QAC5D,6BAA6B,EAAE,IAAI,GAAG,EAAkB;KACxD,CAAC;AACH,CAAC;AAED,MAAM,UAAU,2BAA2B,
|
|
1
|
+
{"version":3,"file":"session-event-emitter-policy.js","sourceRoot":"","sources":["../../src/runtime/session-event-emitter-policy.ts"],"names":[],"mappings":"AAKA,MAAM,UAAU,4BAA4B;IAC3C,OAAO;QACN,iCAAiC,EAAE,IAAI,GAAG,EAAkB;QAC5D,6BAA6B,EAAE,IAAI,GAAG,EAAkB;KACxD,CAAC;AACH,CAAC;AAED,MAAM,UAAU,2BAA2B,CAC1C,KAA6B;IAE7B,KAAK,CAAC,iCAAiC,CAAC,KAAK,EAAE,CAAC;IAChD,KAAK,CAAC,6BAA6B,CAAC,KAAK,EAAE,CAAC;AAC7C,CAAC;AAED,MAAM,UAAU,+BAA+B,CAAC,IAI/C;IACA,MAAM,EAAE,KAAK,EAAE,MAAM,EAAE,OAAO,EAAE,GAAG,IAAI,CAAC;IACxC,IAAI,mBAAmB,CAAC,OAAO,CAAC,EAAE,CAAC;QAClC,MAAM,iBAAiB,GAAG,wBAAwB,CAAC,OAAO,CAAC,CAAC;QAC5D,MAAM,yBAAyB,GAC9B,KAAK,CAAC,6BAA6B,CAAC,GAAG,CAAC,MAAM,CAAC,CAAC;QACjD,IAAI,yBAAyB,KAAK,iBAAiB,EAAE,CAAC;YACrD,OAAO,KAAK,CAAC;QACd,CAAC;QACD,KAAK,CAAC,6BAA6B,CAAC,GAAG,CAAC,MAAM,EAAE,iBAAiB,CAAC,CAAC;IACpE,CAAC;IACD,MAAM,SAAS,GAAG,gCAAgC,CAAC,OAAO,CAAC,CAAC;IAC5D,MAAM,iBAAiB,GAAG,KAAK,CAAC,iCAAiC,CAAC,GAAG,CAAC,MAAM,CAAC,CAAC;IAC9E,IAAI,iBAAiB,KAAK,SAAS,EAAE,CAAC;QACrC,OAAO,KAAK,CAAC;IACd,CAAC;IACD,KAAK,CAAC,iCAAiC,CAAC,GAAG,CAAC,MAAM,EAAE,SAAS,CAAC,CAAC;IAC/D,OAAO,IAAI,CAAC;AACb,CAAC;AAED,SAAS,gCAAgC,CACxC,OAAgC;IAEhC,MAAM,eAAe,GAAG,EAAE,GAAG,OAAO,EAAE,CAAC;IACvC,OAAO,eAAe,CAAC,SAAS,CAAC;IACjC,OAAO,eAAe,CAAC,eAAe,CAAC;IACvC,IAAI,CAAC;QACJ,OAAO,IAAI,CAAC,SAAS,CAAC,eAAe,CAAC,CAAC;IACxC,CAAC;IAAC,MAAM,CAAC;QACR,OAAO,MAAM,CAAC,eAAe,CAAC,MAAM,IAAI,EAAE,CAAC,CAAC;IAC7C,CAAC;AACF,CAAC;AAED,SAAS,mBAAmB,CAAC,OAAgC;IAC5D,OAAO,OAAO,CAAC,MAAM,KAAK,eAAe,CAAC;AAC3C,CAAC;AAED,SAAS,wBAAwB,CAAC,OAAgC;IACjE,IAAI,CAAC;QACJ,OAAO,IAAI,CAAC,SAAS,CAAC;YACrB,MAAM,EAAE,OAAO,CAAC,MAAM;YACtB,eAAe,EAAE,OAAO,CAAC,eAAe;YACxC,MAAM,EAAE,OAAO,CAAC,MAAM;YACtB,QAAQ,EAAE,OAAO,CAAC,QAAQ,IAAI,IAAI;YAClC,SAAS,EAAE,OAAO,CAAC,SAAS,IAAI,IAAI;SACpC,CAAC,CAAC;IACJ,CAAC;IAAC,MAAM,CAAC;QACR,OAAO,MAAM,CAAC,OAAO,CAAC,MAAM,IAAI,EAAE,CAAC,CAAC;IACrC,CAAC;AACF,CAAC","sourcesContent":["export type SessionEmitPolicyState = {\n\tlastSessionEventSignatureByItemId: Map<string, string>;\n\tlastMetadataSignatureByItemId: Map<string, string>;\n};\n\nexport function createSessionEmitPolicyState(): SessionEmitPolicyState {\n\treturn {\n\t\tlastSessionEventSignatureByItemId: new Map<string, string>(),\n\t\tlastMetadataSignatureByItemId: new Map<string, string>(),\n\t};\n}\n\nexport function resetSessionEmitPolicyState(\n\tstate: SessionEmitPolicyState,\n): void {\n\tstate.lastSessionEventSignatureByItemId.clear();\n\tstate.lastMetadataSignatureByItemId.clear();\n}\n\nexport function shouldEmitCanonicalSessionEvent(args: {\n\tstate: SessionEmitPolicyState;\n\titemId: string;\n\tpayload: Record<string, unknown>;\n}): boolean {\n\tconst { state, itemId, payload } = args;\n\tif (isMetadataOnlyEvent(payload)) {\n\t\tconst metadataSignature = getMetadataOnlySignature(payload);\n\t\tconst previousMetadataSignature =\n\t\t\tstate.lastMetadataSignatureByItemId.get(itemId);\n\t\tif (previousMetadataSignature === metadataSignature) {\n\t\t\treturn false;\n\t\t}\n\t\tstate.lastMetadataSignatureByItemId.set(itemId, metadataSignature);\n\t}\n\tconst signature = getSessionEventSemanticSignature(payload);\n\tconst previousSignature = state.lastSessionEventSignatureByItemId.get(itemId);\n\tif (previousSignature === signature) {\n\t\treturn false;\n\t}\n\tstate.lastSessionEventSignatureByItemId.set(itemId, signature);\n\treturn true;\n}\n\nfunction getSessionEventSemanticSignature(\n\tpayload: Record<string, unknown>,\n): string {\n\tconst semanticPayload = { ...payload };\n\tdelete semanticPayload.timestamp;\n\tdelete semanticPayload.sourceRuntimeId;\n\ttry {\n\t\treturn JSON.stringify(semanticPayload);\n\t} catch {\n\t\treturn String(semanticPayload.itemId || \"\");\n\t}\n}\n\nfunction isMetadataOnlyEvent(payload: Record<string, unknown>): boolean {\n\treturn payload.intent === \"metadata-only\";\n}\n\nfunction getMetadataOnlySignature(payload: Record<string, unknown>): string {\n\ttry {\n\t\treturn JSON.stringify({\n\t\t\titemId: payload.itemId,\n\t\t\tcanonicalItemId: payload.canonicalItemId,\n\t\t\tintent: payload.intent,\n\t\t\tcomplete: payload.complete ?? null,\n\t\t\tcomponent: payload.component ?? null,\n\t\t});\n\t} catch {\n\t\treturn String(payload.itemId || \"\");\n\t}\n}\n"]}
|
|
@@ -185,7 +185,8 @@ export class HighlightCoordinator {
|
|
|
185
185
|
const computed = target && typeof getComputedStyle === "function"
|
|
186
186
|
? getComputedStyle(target)
|
|
187
187
|
: null;
|
|
188
|
-
const background = this.parseColor(computed?.getPropertyValue("--pie-background") ||
|
|
188
|
+
const background = this.parseColor(computed?.getPropertyValue("--pie-background") ||
|
|
189
|
+
computed?.backgroundColor) || fallbackBackground;
|
|
189
190
|
const text = this.parseColor(computed?.getPropertyValue("--pie-text")) || fallbackText;
|
|
190
191
|
const accent = this.explicitTTSColorOverride
|
|
191
192
|
? this.parseColor(this.explicitTTSColorOverride.color) || fallbackMissing
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"HighlightCoordinator.js","sourceRoot":"","sources":["../../src/services/HighlightCoordinator.ts"],"names":[],"mappings":"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","sourcesContent":["/**\n * HighlightCoordinator\n *\n * Manages separate highlight layers for TTS (temporary) and annotations (persistent).\n * Uses CSS Custom Highlight API - zero DOM mutation, preserves accessibility.\n *\n * Features:\n * - Separate layers prevent TTS clearing from removing student annotations\n * - CSS Custom Highlight API (no DOM mutation)\n * - Full accessibility support (screen readers see original text)\n * - Configurable colors and styles\n * - Annotation persistence via RangeSerializer\n *\n * Part of PIE Assessment Toolkit.\n *\n * Browser Support:\n * - Chrome/Edge 105+\n * - Safari 17.2+\n * - Firefox: Behind flag (not recommended for production)\n *\n * @see https://developer.mozilla.org/en-US/docs/Web/API/CSS_Custom_Highlight_API\n */\n\nimport type { HighlightCoordinatorApi } from \"./interfaces.js\";\nimport { RangeSerializer, type SerializedRange } from \"./RangeSerializer.js\";\n\n/**\n * Highlight types\n */\nexport enum HighlightType {\n\tTTS_WORD = \"tts-word\",\n\tTTS_SENTENCE = \"tts-sentence\",\n\tANNOTATION = \"annotation\",\n}\n\n/**\n * Highlight colors for annotations\n */\nexport enum HighlightColor {\n\tYELLOW = \"yellow\",\n\tGREEN = \"green\",\n\tBLUE = \"blue\",\n\tPINK = \"pink\",\n\tORANGE = \"orange\",\n\tUNDERLINE = \"underline\",\n}\n\n/**\n * Annotation data\n */\nexport interface Annotation {\n\tid: string;\n\trange: Range;\n\ttype: HighlightType.ANNOTATION;\n\tcolor: HighlightColor;\n\ttimestamp: number;\n}\n\n/**\n * Configuration for HighlightCoordinator\n * Currently empty but allows future extension without breaking changes\n */\nexport type HighlightCoordinatorConfig = Record<string, never>;\n\nexport class HighlightCoordinator implements HighlightCoordinatorApi {\n\tprivate config: HighlightCoordinatorConfig;\n\tprivate ttsWordHighlight: Highlight | null = null;\n\tprivate ttsSentenceHighlight: Highlight | null = null;\n\tprivate ttsWordElementHighlights = new Set<Element>();\n\tprivate ttsSentenceElementHighlights = new Set<Element>();\n\tprivate annotations = new Map<string, Annotation>();\n\t// Shared highlights per color (one Highlight object per color, contains all ranges)\n\tprivate colorHighlights = new Map<HighlightColor, Highlight>();\n\tprivate nextAnnotationId = 1;\n\tprivate supported = false;\n\tprivate rangeSerializer: RangeSerializer;\n\tprivate themeObserver: MutationObserver | null = null;\n\tprivate explicitTTSColorOverride: { color: string; opacity: number } | null = null;\n\n\tconstructor(config: HighlightCoordinatorConfig = {}) {\n\t\tthis.config = config;\n\t\tthis.rangeSerializer = new RangeSerializer();\n\n\t\t// SSR guard\n\t\tif (typeof CSS === \"undefined\" || !(\"highlights\" in CSS)) {\n\t\t\tconsole.warn(\n\t\t\t\t\"CSS Custom Highlight API not supported (SSR or unsupported browser)\",\n\t\t\t);\n\t\t\treturn;\n\t\t}\n\n\t\tthis.supported = true;\n\t\tthis.initializeHighlights();\n\t\tthis.registerStyles();\n\t\tthis.applyAdaptiveTTSStyle();\n\t\tthis.setupThemeObservation();\n\t}\n\n\tprivate setupThemeObservation(): void {\n\t\tif (typeof document === \"undefined\") return;\n\t\tif (typeof MutationObserver === \"undefined\") return;\n\n\t\tconst refresh = () => this.applyAdaptiveTTSStyle();\n\t\tthis.themeObserver = new MutationObserver(refresh);\n\n\t\tthis.themeObserver.observe(document.documentElement, {\n\t\t\tattributes: true,\n\t\t\tattributeFilter: [\"style\", \"data-theme\", \"data-color-scheme\", \"class\"],\n\t\t});\n\n\t\tfor (const host of document.querySelectorAll(\"pie-theme\")) {\n\t\t\tthis.themeObserver.observe(host, {\n\t\t\t\tattributes: true,\n\t\t\t\tattributeFilter: [\n\t\t\t\t\t\"theme\",\n\t\t\t\t\t\"scheme\",\n\t\t\t\t\t\"provider\",\n\t\t\t\t\t\"variables\",\n\t\t\t\t\t\"style\",\n\t\t\t\t\t\"data-theme\",\n\t\t\t\t\t\"data-color-scheme\",\n\t\t\t\t],\n\t\t\t});\n\t\t}\n\t}\n\n\tprivate parseColor(input: string | null | undefined): [number, number, number] | null {\n\t\tif (!input) return null;\n\t\tconst value = input.trim();\n\t\tif (!value) return null;\n\n\t\tconst hexMatch = /^#([a-f\\d]{3}|[a-f\\d]{6})$/i.exec(value);\n\t\tif (hexMatch) {\n\t\t\tconst hex = hexMatch[1];\n\t\t\tif (hex.length === 3) {\n\t\t\t\treturn [\n\t\t\t\t\tparseInt(hex[0] + hex[0], 16),\n\t\t\t\t\tparseInt(hex[1] + hex[1], 16),\n\t\t\t\t\tparseInt(hex[2] + hex[2], 16),\n\t\t\t\t];\n\t\t\t}\n\t\t\treturn [\n\t\t\t\tparseInt(hex.slice(0, 2), 16),\n\t\t\t\tparseInt(hex.slice(2, 4), 16),\n\t\t\t\tparseInt(hex.slice(4, 6), 16),\n\t\t\t];\n\t\t}\n\n\t\tconst rgbMatch = /^rgba?\\((.+)\\)$/i.exec(value);\n\t\tif (rgbMatch) {\n\t\t\tconst normalized = rgbMatch[1].replace(/\\//g, \",\");\n\t\t\tconst parts = normalized\n\t\t\t\t.split(/[,\\s]+/)\n\t\t\t\t.map((part) => part.trim())\n\t\t\t\t.filter(Boolean);\n\t\t\tconst r = Number(parts[0]);\n\t\t\tconst g = Number(parts[1]);\n\t\t\tconst b = Number(parts[2]);\n\t\t\tif (Number.isFinite(r) && Number.isFinite(g) && Number.isFinite(b)) {\n\t\t\t\treturn [r, g, b];\n\t\t\t}\n\t\t}\n\n\t\t// Browser parser fallback (covers formats like oklch()).\n\t\tif (typeof document !== \"undefined\") {\n\t\t\tconst parserEl = document.createElement(\"span\");\n\t\t\tparserEl.style.color = value;\n\t\t\tif (typeof parserEl.style.color === \"string\" && parserEl.style.color) {\n\t\t\t\tdocument.body?.appendChild(parserEl);\n\t\t\t\tconst resolved =\n\t\t\t\t\ttypeof getComputedStyle === \"function\"\n\t\t\t\t\t\t? getComputedStyle(parserEl).color\n\t\t\t\t\t\t: \"\";\n\t\t\t\tparserEl.remove();\n\t\t\t\tconst normalizedResolved = resolved.trim();\n\t\t\t\t// Guard against recursive loops when computed style returns the same\n\t\t\t\t// unresolved function syntax (observed with certain color formats).\n\t\t\t\tif (normalizedResolved && normalizedResolved !== value) {\n\t\t\t\t\treturn this.parseColor(resolved);\n\t\t\t\t}\n\t\t\t}\n\t\t}\n\n\t\treturn null;\n\t}\n\n\tprivate relativeLuminance([r, g, b]: [number, number, number]): number {\n\t\tconst toLinear = (channel: number) => {\n\t\t\tconst n = channel / 255;\n\t\t\treturn n <= 0.03928 ? n / 12.92 : ((n + 0.055) / 1.055) ** 2.4;\n\t\t};\n\t\tconst lr = toLinear(r);\n\t\tconst lg = toLinear(g);\n\t\tconst lb = toLinear(b);\n\t\treturn 0.2126 * lr + 0.7152 * lg + 0.0722 * lb;\n\t}\n\n\tprivate contrastRatio(\n\t\ta: [number, number, number],\n\t\tb: [number, number, number],\n\t): number {\n\t\tconst la = this.relativeLuminance(a);\n\t\tconst lb = this.relativeLuminance(b);\n\t\tconst lighter = Math.max(la, lb);\n\t\tconst darker = Math.min(la, lb);\n\t\treturn (lighter + 0.05) / (darker + 0.05);\n\t}\n\n\tprivate blend(\n\t\tfg: [number, number, number],\n\t\tbg: [number, number, number],\n\t\talpha: number,\n\t): [number, number, number] {\n\t\treturn [\n\t\t\tMath.round(fg[0] * alpha + bg[0] * (1 - alpha)),\n\t\t\tMath.round(fg[1] * alpha + bg[1] * (1 - alpha)),\n\t\t\tMath.round(fg[2] * alpha + bg[2] * (1 - alpha)),\n\t\t];\n\t}\n\n\tprivate resolveAdaptiveTTSStyle(sourceEl?: Element | null): {\n\t\twordHighlight: string;\n\t\tsentenceHighlight: string;\n\t\twordUnderline: string;\n\t\twordShadow: string;\n\t} {\n\t\tconst fallbackMissing: [number, number, number] = [255, 235, 59];\n\t\tconst fallbackText: [number, number, number] = [17, 24, 39];\n\t\tconst fallbackBackground: [number, number, number] = [255, 255, 255];\n\n\t\tconst target =\n\t\t\tsourceEl ||\n\t\t\t(typeof document !== \"undefined\" ? document.documentElement : null);\n\t\tconst computed =\n\t\t\ttarget && typeof getComputedStyle === \"function\"\n\t\t\t\t? getComputedStyle(target)\n\t\t\t\t: null;\n\n\t\tconst background =\n\t\t\tthis.parseColor(\n\t\t\t\tcomputed?.getPropertyValue(\"--pie-background\") || computed?.backgroundColor,\n\t\t\t) || fallbackBackground;\n\t\tconst text =\n\t\t\tthis.parseColor(computed?.getPropertyValue(\"--pie-text\")) || fallbackText;\n\t\tconst accent = this.explicitTTSColorOverride\n\t\t\t? this.parseColor(this.explicitTTSColorOverride.color) || fallbackMissing\n\t\t\t: this.parseColor(computed?.getPropertyValue(\"--pie-missing\")) ||\n\t\t\t\tfallbackMissing;\n\n\t\tconst opacityCandidates = this.explicitTTSColorOverride\n\t\t\t? [Math.max(0.3, Math.min(0.95, this.explicitTTSColorOverride.opacity))]\n\t\t\t: [0.8, 0.72, 0.68, 0.62, 0.56, 0.5];\n\n\t\tlet selectedOpacity = opacityCandidates[opacityCandidates.length - 1];\n\t\tlet bestScore = -Infinity;\n\n\t\tfor (const opacity of opacityCandidates) {\n\t\t\tconst blended = this.blend(accent, background, opacity);\n\t\t\tconst backgroundDelta = this.contrastRatio(blended, background);\n\t\t\tconst textContrast = this.contrastRatio(blended, text);\n\t\t\tconst score = backgroundDelta * 1.2 + textContrast * 0.8;\n\t\t\tif (backgroundDelta >= 1.25 && textContrast >= 2.4) {\n\t\t\t\tselectedOpacity = opacity;\n\t\t\t\tbreak;\n\t\t\t}\n\t\t\tif (score > bestScore) {\n\t\t\t\tbestScore = score;\n\t\t\t\tselectedOpacity = opacity;\n\t\t\t}\n\t\t}\n\n\t\tconst sentenceOpacity = Math.max(0.24, Math.min(0.85, selectedOpacity * 0.55));\n\t\tconst underlineOpacity = Math.max(0.55, Math.min(0.95, selectedOpacity + 0.2));\n\t\tconst shadowOpacity = Math.max(0.22, Math.min(0.6, selectedOpacity * 0.45));\n\n\t\tconst underlineColor = text;\n\t\tconst underlineBlend = this.blend(underlineColor, background, underlineOpacity);\n\t\tconst underlineDelta = this.contrastRatio(underlineBlend, background);\n\t\tconst fallbackUnderline: [number, number, number] =\n\t\t\tthis.relativeLuminance(background) > 0.45 ? [0, 0, 0] : [255, 255, 255];\n\t\tconst finalUnderline = underlineDelta >= 1.35 ? underlineColor : fallbackUnderline;\n\n\t\tconst wordHighlight = `rgba(${accent[0]}, ${accent[1]}, ${accent[2]}, ${selectedOpacity})`;\n\t\tconst sentenceHighlight = `rgba(${accent[0]}, ${accent[1]}, ${accent[2]}, ${sentenceOpacity})`;\n\t\tconst wordUnderline = `rgba(${finalUnderline[0]}, ${finalUnderline[1]}, ${finalUnderline[2]}, ${underlineOpacity})`;\n\t\tconst wordShadow = `rgba(${finalUnderline[0]}, ${finalUnderline[1]}, ${finalUnderline[2]}, ${shadowOpacity})`;\n\n\t\treturn {\n\t\t\twordHighlight,\n\t\t\tsentenceHighlight,\n\t\t\twordUnderline,\n\t\t\twordShadow,\n\t\t};\n\t}\n\n\tprivate applyAdaptiveTTSStyle(sourceEl?: Element | null): void {\n\t\tif (typeof document === \"undefined\") return;\n\t\tconst vars = this.resolveAdaptiveTTSStyle(sourceEl);\n\t\tdocument.documentElement.style.setProperty(\n\t\t\t\"--pie-tts-word-highlight\",\n\t\t\tvars.wordHighlight,\n\t\t);\n\t\tdocument.documentElement.style.setProperty(\n\t\t\t\"--pie-tts-sentence-highlight\",\n\t\t\tvars.sentenceHighlight,\n\t\t);\n\t\tdocument.documentElement.style.setProperty(\n\t\t\t\"--pie-tts-line-highlight\",\n\t\t\tvars.sentenceHighlight,\n\t\t);\n\t\tdocument.documentElement.style.setProperty(\n\t\t\t\"--pie-tts-word-underline\",\n\t\t\tvars.wordUnderline,\n\t\t);\n\t\tdocument.documentElement.style.setProperty(\n\t\t\t\"--pie-tts-word-shadow\",\n\t\t\tvars.wordShadow,\n\t\t);\n\t}\n\n\t/**\n\t * Initialize CSS Custom Highlights\n\t */\n\tprivate initializeHighlights(): void {\n\t\tif (!this.supported) return;\n\n\t\t// Create highlight registries for TTS\n\t\tthis.ttsWordHighlight = new Highlight();\n\t\tthis.ttsSentenceHighlight = new Highlight();\n\n\t\t// Register TTS highlights with CSS\n\t\tCSS.highlights.set(\"tts-word\", this.ttsWordHighlight);\n\t\tCSS.highlights.set(\"tts-sentence\", this.ttsSentenceHighlight);\n\n\t\t// Create shared highlights for each annotation color\n\t\tfor (const color of Object.values(HighlightColor)) {\n\t\t\tconst highlight = new Highlight();\n\t\t\tthis.colorHighlights.set(color, highlight);\n\t\t\tCSS.highlights.set(`annotation-${color}`, highlight);\n\t\t}\n\t}\n\n\t/**\n\t * Register CSS styles for highlights\n\t */\n\tprivate registerStyles(): void {\n\t\tif (!this.supported) return;\n\t\tif (typeof document === \"undefined\") return; // SSR guard\n\n\t\t// Check if styles already exist\n\t\tif (document.getElementById(\"pie-highlight-styles\")) return;\n\n\t\tconst style = document.createElement(\"style\");\n\t\tstyle.id = \"pie-highlight-styles\";\n\t\tstyle.textContent = `\n /* TTS highlights - temporary */\n ::highlight(tts-word) {\n background-color: var(--pie-tts-word-highlight, color-mix(in srgb, var(--pie-missing, #ffeb3b) 68%, transparent));\n text-decoration: underline 2px solid var(--pie-tts-word-underline, color-mix(in srgb, var(--pie-text, #111827) 70%, transparent));\n text-underline-offset: 2px;\n text-shadow: 0 0 1px var(--pie-tts-word-shadow, color-mix(in srgb, var(--pie-text, #111827) 35%, transparent));\n color: inherit;\n }\n\n /* tts-sentence registry id: coarse read-along band (visual line boxes in layout) */\n ::highlight(tts-sentence) {\n background-color: var(--pie-tts-line-highlight, var(--pie-tts-sentence-highlight, color-mix(in srgb, var(--pie-missing, #ffeb3b) 38%, transparent)));\n color: inherit;\n }\n\n [data-pie-tts-sentence-element=\"true\"] {\n background-color: var(--pie-tts-line-highlight, var(--pie-tts-sentence-highlight, color-mix(in srgb, var(--pie-missing, #ffeb3b) 38%, transparent)));\n border-radius: 0.12em;\n box-decoration-break: clone;\n -webkit-box-decoration-break: clone;\n }\n\n [data-pie-tts-word-element=\"true\"] {\n background-color: var(--pie-tts-word-highlight, color-mix(in srgb, var(--pie-missing, #ffeb3b) 68%, transparent));\n text-decoration: underline 2px solid var(--pie-tts-word-underline, color-mix(in srgb, var(--pie-text, #111827) 70%, transparent));\n text-underline-offset: 2px;\n text-shadow: 0 0 1px var(--pie-tts-word-shadow, color-mix(in srgb, var(--pie-text, #111827) 35%, transparent));\n border-bottom: 2px solid var(--pie-tts-word-underline, color-mix(in srgb, var(--pie-text, #111827) 70%, transparent));\n padding-bottom: 1px;\n border-radius: 0.12em;\n box-decoration-break: clone;\n -webkit-box-decoration-break: clone;\n }\n\n /* Annotation highlights - persistent */\n ::highlight(annotation-yellow) {\n background-color: color-mix(in srgb, var(--pie-missing, #ffff00) 35%, transparent);\n color: inherit;\n }\n\n ::highlight(annotation-green) {\n background-color: color-mix(in srgb, var(--pie-correct, #90ee90) 35%, transparent);\n color: inherit;\n }\n\n ::highlight(annotation-blue) {\n background-color: color-mix(in srgb, var(--pie-tertiary, #add8e6) 35%, transparent);\n color: inherit;\n }\n\n ::highlight(annotation-pink) {\n background-color: color-mix(in srgb, var(--pie-secondary-light, #ffb6c1) 35%, transparent);\n color: inherit;\n }\n\n ::highlight(annotation-orange) {\n background-color: color-mix(in srgb, var(--pie-incorrect, #ffa500) 35%, transparent);\n color: inherit;\n }\n\n ::highlight(annotation-underline) {\n background-color: transparent;\n text-decoration: underline 2px solid var(--pie-primary, #0066cc);\n text-underline-offset: 2px;\n color: inherit;\n }\n `;\n\t\tdocument.head.appendChild(style);\n\t}\n\n\t/**\n\t * Highlight a word for TTS (temporary)\n\t *\n\t * @param textNode Text node containing the word\n\t * @param startOffset Start position in text node\n\t * @param endOffset End position in text node\n\t */\n\thighlightTTSWord(\n\t\ttextNode: Text,\n\t\tstartOffset: number,\n\t\tendOffset: number,\n\t): void {\n\t\tif (!this.ttsWordHighlight) return;\n\t\tthis.applyAdaptiveTTSStyle(textNode.parentElement);\n\n\t\t// Clear previous word highlight\n\t\tthis.clearTTSWord();\n\n\t\t// Create range for word\n\t\tconst range = document.createRange();\n\t\trange.setStart(textNode, startOffset);\n\t\trange.setEnd(textNode, endOffset);\n\n\t\t// Add to highlight\n\t\tthis.ttsWordHighlight.add(range);\n\t}\n\n\t/**\n\t * Highlight a single element as the active TTS word (temporary).\n\t *\n\t * Unlike {@link highlightTTSWord} (which paints a CSS range over a text node)\n\t * this marks the element itself via `data-pie-tts-word-element`. It is used\n\t * for atomic targets that have no direct text node to range over — most\n\t * notably MathJax CHTML tokens (e.g. `<mjx-mi><mjx-c/></mjx-mi>`, whose glyph\n\t * lives in a font-driven pseudo-element a CSS range cannot paint) and\n\t * whole-expression fallbacks.\n\t *\n\t * The supplied element is painted exactly; we deliberately do NOT walk up to\n\t * a containing `<math>` / `<mjx-container>`. That escalation is what made\n\t * MathJax-rendered math highlight as a full block while native MathML tracked\n\t * per-token: a resolved single token must paint as a token, and only a\n\t * genuine expression fallback (where the element already is the container)\n\t * should paint the whole expression.\n\t */\n\thighlightTTSWordElement(element: Element): void {\n\t\tif (!this.ttsWordHighlight) return;\n\t\tthis.applyAdaptiveTTSStyle(element);\n\n\t\t// Clear previous word highlight (CSS range and any element attributes)\n\t\tthis.clearTTSWord();\n\n\t\telement.setAttribute(\"data-pie-tts-word-element\", \"true\");\n\t\tthis.ttsWordElementHighlights.add(element);\n\t}\n\n\t/**\n\t * Highlight the coarse TTS read-along band (temporary).\n\t * Usually one Range per visual line; CSS layer `tts-sentence` for compatibility.\n\t *\n\t * @param ranges Line (or sentence) ranges to paint with `--pie-tts-line-highlight`\n\t */\n\thighlightTTSSentence(ranges: Range[]): void {\n\t\tif (!this.ttsSentenceHighlight) return;\n\t\tconst source = ranges[0]?.startContainer;\n\t\tconst sourceElement =\n\t\t\tsource?.nodeType === Node.ELEMENT_NODE\n\t\t\t\t? (source as Element)\n\t\t\t\t: source?.parentElement;\n\t\tthis.applyAdaptiveTTSStyle(sourceElement);\n\n\t\t// Clear previous sentence highlight\n\t\tthis.clearTTSSentence();\n\n\t\t// Add all ranges\n\t\tfor (const range of ranges) {\n\t\t\tthis.ttsSentenceHighlight.add(range);\n\t\t}\n\t\tthis.highlightTTSElementFallbacks(ranges);\n\t}\n\n\t// The read-along (sentence) band legitimately covers whole equations and\n\t// replaced elements, so it escalates to them.\n\tprivate static readonly SENTENCE_FALLBACK_SELECTOR =\n\t\t\"math, mjx-container, svg, img, canvas, [role='img']\";\n\n\t// The word layer must NOT escalate a multi-node range to the enclosing\n\t// `<math>` / `<mjx-container>`: that is what made an equation flash as a\n\t// whole block whenever a spoken word's visible range crossed several math\n\t// glyph nodes. Math is tracked per token (or held / region) by the highlight\n\t// pipeline instead. Replaced elements (svg/img/canvas) still need the element\n\t// fallback because a CSS range cannot paint them.\n\tprivate static readonly WORD_FALLBACK_SELECTOR =\n\t\t\"svg, img, canvas, [role='img']\";\n\n\tprivate highlightTTSElementFallbacks(ranges: Range[]): void {\n\t\tif (typeof Element === \"undefined\") return;\n\t\tthis.highlightElementFallbacks(\n\t\t\tranges,\n\t\t\t\"data-pie-tts-sentence-element\",\n\t\t\tthis.ttsSentenceElementHighlights,\n\t\t\tHighlightCoordinator.SENTENCE_FALLBACK_SELECTOR,\n\t\t);\n\t}\n\n\tprivate highlightTTSWordElementFallbacks(ranges: Range[]): void {\n\t\tif (typeof Element === \"undefined\") return;\n\t\tthis.highlightElementFallbacks(\n\t\t\tranges,\n\t\t\t\"data-pie-tts-word-element\",\n\t\t\tthis.ttsWordElementHighlights,\n\t\t\tHighlightCoordinator.WORD_FALLBACK_SELECTOR,\n\t\t);\n\t}\n\n\tprivate highlightElementFallbacks(\n\t\tranges: Range[],\n\t\tattributeName: string,\n\t\ttrackedElements: Set<Element>,\n\t\tselector: string,\n\t): void {\n\t\tfor (const range of ranges) {\n\t\t\tconst root =\n\t\t\t\trange.commonAncestorContainer.nodeType === Node.ELEMENT_NODE\n\t\t\t\t\t? (range.commonAncestorContainer as Element)\n\t\t\t\t\t: range.commonAncestorContainer.parentElement;\n\t\t\tif (!root) continue;\n\t\t\tconst candidates: Element[] = [];\n\t\t\tconst rangeStartElement =\n\t\t\t\trange.startContainer.nodeType === Node.ELEMENT_NODE\n\t\t\t\t\t? (range.startContainer as Element)\n\t\t\t\t\t: range.startContainer.parentElement;\n\t\t\tconst rangeEndElement =\n\t\t\t\trange.endContainer.nodeType === Node.ELEMENT_NODE\n\t\t\t\t\t? (range.endContainer as Element)\n\t\t\t\t\t: range.endContainer.parentElement;\n\t\t\tfor (const element of [rangeStartElement, rangeEndElement]) {\n\t\t\t\tlet current: Element | null = element;\n\t\t\t\twhile (current) {\n\t\t\t\t\tif (current.matches?.(selector)) candidates.push(current);\n\t\t\t\t\tcurrent = current.parentElement;\n\t\t\t\t}\n\t\t\t}\n\t\t\tif (root.matches?.(selector)) {\n\t\t\t\tcandidates.push(root);\n\t\t\t}\n\t\t\tcandidates.push(...Array.from(root.querySelectorAll(selector)));\n\t\t\tfor (const element of new Set(candidates)) {\n\t\t\t\ttry {\n\t\t\t\t\tif (\n\t\t\t\t\t\t!range.intersectsNode(element) &&\n\t\t\t\t\t\t!element.contains(rangeStartElement) &&\n\t\t\t\t\t\t!element.contains(rangeEndElement)\n\t\t\t\t\t) {\n\t\t\t\t\t\tcontinue;\n\t\t\t\t\t}\n\t\t\t\t} catch {\n\t\t\t\t\tcontinue;\n\t\t\t\t}\n\t\t\t\telement.setAttribute(attributeName, \"true\");\n\t\t\t\ttrackedElements.add(element);\n\t\t\t}\n\t\t}\n\t}\n\n\t/**\n\t * Clear TTS word highlight\n\t */\n\tclearTTSWord(): void {\n\t\tif (!this.ttsWordHighlight) return;\n\t\tthis.ttsWordHighlight.clear();\n\t\tfor (const element of this.ttsWordElementHighlights) {\n\t\t\telement.removeAttribute(\"data-pie-tts-word-element\");\n\t\t}\n\t\tthis.ttsWordElementHighlights.clear();\n\t}\n\n\t/**\n\t * Clear TTS sentence highlight\n\t */\n\tclearTTSSentence(): void {\n\t\tif (!this.ttsSentenceHighlight) return;\n\t\tthis.ttsSentenceHighlight.clear();\n\t\tfor (const element of this.ttsSentenceElementHighlights) {\n\t\t\telement.removeAttribute(\"data-pie-tts-sentence-element\");\n\t\t}\n\t\tthis.ttsSentenceElementHighlights.clear();\n\t}\n\n\t/**\n\t * Clear all TTS highlights\n\t */\n\tclearTTS(): void {\n\t\tthis.clearTTSWord();\n\t\tthis.clearTTSSentence();\n\t}\n\n\t/**\n\t * Add an annotation highlight (persistent)\n\t *\n\t * @param range Text range to annotate\n\t * @param color Highlight color\n\t * @returns Annotation ID for later removal\n\t */\n\taddAnnotation(\n\t\trange: Range,\n\t\tcolor: HighlightColor = HighlightColor.YELLOW,\n\t): string {\n\t\tconst id = `annotation-${this.nextAnnotationId++}`;\n\n\t\t// Clone the range to store\n\t\tconst clonedRange = range.cloneRange();\n\n\t\t// Store annotation data\n\t\tconst annotation: Annotation = {\n\t\t\tid,\n\t\t\trange: clonedRange,\n\t\t\ttype: HighlightType.ANNOTATION,\n\t\t\tcolor,\n\t\t\ttimestamp: Date.now(),\n\t\t};\n\t\tthis.annotations.set(id, annotation);\n\n\t\t// Add the SAME range object to the shared color highlight\n\t\t// This ensures we can later delete it by reference\n\t\tconst colorHighlight = this.colorHighlights.get(color);\n\t\tif (colorHighlight) {\n\t\t\tcolorHighlight.add(clonedRange);\n\t\t}\n\n\t\treturn id;\n\t}\n\n\t/**\n\t * Remove an annotation\n\t *\n\t * @param id Annotation ID\n\t */\n\tremoveAnnotation(id: string): void {\n\t\tconst annotation = this.annotations.get(id);\n\t\tif (!annotation) {\n\t\t\tconsole.warn(`[HighlightCoordinator] Annotation ${id} not found`);\n\t\t\treturn;\n\t\t}\n\n\t\tconsole.log(\n\t\t\t`[HighlightCoordinator] Removing annotation ${id} (color: ${annotation.color})`,\n\t\t);\n\n\t\t// Remove range from the shared color highlight\n\t\tconst colorHighlight = this.colorHighlights.get(annotation.color);\n\t\tif (colorHighlight) {\n\t\t\tconst deleted = colorHighlight.delete(annotation.range);\n\t\t\tconsole.log(\n\t\t\t\t`[HighlightCoordinator] Highlight.delete() returned:`,\n\t\t\t\tdeleted,\n\t\t\t);\n\t\t}\n\n\t\t// Clean up\n\t\tthis.annotations.delete(id);\n\t\tconsole.log(\n\t\t\t`[HighlightCoordinator] Annotation ${id} removed from map. Remaining:`,\n\t\t\tthis.annotations.size,\n\t\t);\n\t}\n\n\t/**\n\t * Remove all annotations\n\t */\n\tclearAnnotations(): void {\n\t\t// Clear all color highlights\n\t\tfor (const colorHighlight of this.colorHighlights.values()) {\n\t\t\tcolorHighlight.clear();\n\t\t}\n\n\t\t// Clear annotation data\n\t\tthis.annotations.clear();\n\t}\n\n\t/**\n\t * Get all annotations\n\t */\n\tgetAnnotations(): Annotation[] {\n\t\treturn Array.from(this.annotations.values());\n\t}\n\n\t/**\n\t * Get annotation by ID\n\t */\n\tgetAnnotation(id: string): Annotation | null {\n\t\treturn this.annotations.get(id) ?? null;\n\t}\n\n\t/**\n\t * Change annotation color\n\t *\n\t * @param id Annotation ID\n\t * @param newColor New color\n\t */\n\tchangeAnnotationColor(id: string, newColor: HighlightColor): void {\n\t\tconst annotation = this.annotations.get(id);\n\t\tif (!annotation) return;\n\n\t\tconst oldColor = annotation.color;\n\t\tif (oldColor === newColor) return;\n\n\t\t// Remove from old color highlight\n\t\tconst oldColorHighlight = this.colorHighlights.get(oldColor);\n\t\tif (oldColorHighlight) {\n\t\t\toldColorHighlight.delete(annotation.range);\n\t\t}\n\n\t\t// Update color\n\t\tannotation.color = newColor;\n\n\t\t// Add to new color highlight\n\t\tconst newColorHighlight = this.colorHighlights.get(newColor);\n\t\tif (newColorHighlight) {\n\t\t\tnewColorHighlight.add(annotation.range);\n\t\t}\n\t}\n\n\t/**\n\t * Export annotations as serializable data for persistence.\n\t * Uses RangeSerializer for robust DOM range serialization.\n\t *\n\t * @param root Root element for serialization (typically document.body or content container)\n\t * @returns Array of serialized annotations\n\t */\n\texportAnnotations(\n\t\troot: Element = document.body,\n\t): Array<\n\t\tSerializedRange & { id: string; color: HighlightColor; timestamp: number }\n\t> {\n\t\treturn this.getAnnotations().map((annotation) => ({\n\t\t\t...this.rangeSerializer.serialize(annotation.range, root),\n\t\t\tid: annotation.id,\n\t\t\tcolor: annotation.color,\n\t\t\ttimestamp: annotation.timestamp,\n\t\t}));\n\t}\n\n\t/**\n\t * Import annotations from serialized data.\n\t * Restores annotations after page navigation or refresh.\n\t *\n\t * @param data Array of serialized annotations\n\t * @param root Root element for deserialization (same as used in export)\n\t * @returns Number of successfully restored annotations\n\t */\n\timportAnnotations(\n\t\tdata: Array<\n\t\t\tSerializedRange & {\n\t\t\t\tid?: string;\n\t\t\t\tcolor: HighlightColor;\n\t\t\t\ttimestamp?: number;\n\t\t\t}\n\t\t>,\n\t\troot: Element = document.body,\n\t): number {\n\t\tlet restored = 0;\n\n\t\tfor (const item of data) {\n\t\t\tconst range = this.rangeSerializer.deserialize(item, root);\n\t\t\tif (range) {\n\t\t\t\tthis.addAnnotation(range, item.color);\n\t\t\t\trestored++;\n\t\t\t}\n\t\t}\n\n\t\treturn restored;\n\t}\n\n\t// ============================================================================\n\t// HighlightCoordinatorApi interface implementation\n\t// ============================================================================\n\n\t/**\n\t * Highlight a text range (interface method)\n\t *\n\t * Generic method that adapts to the specific highlight type.\n\t * For more control, use the specific methods like highlightTTSWord().\n\t */\n\thighlightRange(\n\t\trange: Range,\n\t\ttype: HighlightType,\n\t\tcolor: HighlightColor = HighlightColor.YELLOW,\n\t): void {\n\t\tif (!this.supported) return;\n\n\t\tswitch (type) {\n\t\t\tcase HighlightType.TTS_WORD:\n\t\t\tcase HighlightType.TTS_SENTENCE: {\n\t\t\t\t// For TTS, add to appropriate highlight\n\t\t\t\tconst highlight =\n\t\t\t\t\ttype === HighlightType.TTS_WORD\n\t\t\t\t\t\t? this.ttsWordHighlight\n\t\t\t\t\t\t: this.ttsSentenceHighlight;\n\t\t\t\tif (highlight) {\n\t\t\t\t\thighlight.clear();\n\t\t\t\t\thighlight.add(range);\n\t\t\t\t\tif (type === HighlightType.TTS_WORD) {\n\t\t\t\t\t\tfor (const element of this.ttsWordElementHighlights) {\n\t\t\t\t\t\t\telement.removeAttribute(\"data-pie-tts-word-element\");\n\t\t\t\t\t\t}\n\t\t\t\t\t\tthis.ttsWordElementHighlights.clear();\n\t\t\t\t\t\tthis.highlightTTSWordElementFallbacks([range]);\n\t\t\t\t\t}\n\t\t\t\t}\n\t\t\t\tbreak;\n\t\t\t}\n\t\t\tcase HighlightType.ANNOTATION:\n\t\t\t\t// For annotations, use the existing method\n\t\t\t\tthis.addAnnotation(range, color);\n\t\t\t\tbreak;\n\t\t}\n\t}\n\n\t/**\n\t * Clear highlights of a specific type (interface method)\n\t */\n\tclearHighlights(type: HighlightType): void {\n\t\tif (!this.supported) return;\n\n\t\tswitch (type) {\n\t\t\tcase HighlightType.TTS_WORD:\n\t\t\t\tthis.clearTTSWord();\n\t\t\t\tbreak;\n\t\t\tcase HighlightType.TTS_SENTENCE:\n\t\t\t\tthis.clearTTSSentence();\n\t\t\t\tbreak;\n\t\t\tcase HighlightType.ANNOTATION:\n\t\t\t\tthis.clearAnnotations();\n\t\t\t\tbreak;\n\t\t}\n\t}\n\n\t/**\n\t * Clear all highlights (interface method)\n\t */\n\tclearAll(): void {\n\t\tif (!this.supported) return;\n\t\tthis.clearTTS();\n\t\tthis.clearAnnotations();\n\t}\n\n\t/**\n\t * Check if CSS Highlight API is supported (interface method)\n\t */\n\tisSupported(): boolean {\n\t\treturn this.supported;\n\t}\n\n\t/**\n\t * Update TTS highlight style dynamically\n\t *\n\t * @param color CSS color value (e.g., '#ffeb3b')\n\t * @param opacity Opacity value (0.0 to 1.0)\n\t */\n\tupdateTTSHighlightStyle(color: string, opacity: number): void {\n\t\tif (!this.supported) return;\n\t\tif (typeof document === \"undefined\") return;\n\n\t\tconst styleEl = document.getElementById(\"pie-highlight-styles\");\n\t\tif (!styleEl) return;\n\n\t\t// Convert hex to rgba\n\t\tconst hexToRgb = (hex: string) => {\n\t\t\tconst result = /^#?([a-f\\d]{2})([a-f\\d]{2})([a-f\\d]{2})$/i.exec(hex);\n\t\t\treturn result\n\t\t\t\t? {\n\t\t\t\t\t\tr: parseInt(result[1], 16),\n\t\t\t\t\t\tg: parseInt(result[2], 16),\n\t\t\t\t\t\tb: parseInt(result[3], 16),\n\t\t\t\t\t}\n\t\t\t\t: null;\n\t\t};\n\n\t\tconst rgb = hexToRgb(color);\n\t\tif (!rgb) return;\n\n\t\tthis.explicitTTSColorOverride = {\n\t\t\tcolor: `rgb(${rgb.r}, ${rgb.g}, ${rgb.b})`,\n\t\t\topacity: Math.max(0.2, Math.min(0.95, opacity)),\n\t\t};\n\t\tthis.applyAdaptiveTTSStyle();\n\t}\n\n\t/**\n\t * Cleanup - remove all highlights\n\t */\n\tdestroy(): void {\n\t\tif (!this.supported) return;\n\n\t\tthis.clearTTS();\n\t\tthis.clearAnnotations();\n\n\t\t// Remove style element\n\t\tif (typeof document !== \"undefined\") {\n\t\t\tconst styleEl = document.getElementById(\"pie-highlight-styles\");\n\t\t\tif (styleEl) {\n\t\t\t\tstyleEl.remove();\n\t\t\t}\n\t\t}\n\t\tthis.themeObserver?.disconnect();\n\t\tthis.themeObserver = null;\n\t}\n}\n"]}
|
|
1
|
+
{"version":3,"file":"HighlightCoordinator.js","sourceRoot":"","sources":["../../src/services/HighlightCoordinator.ts"],"names":[],"mappings":"AAAA;;;;;;;;;;;;;;;;;;;;;GAqBG;AAGH,OAAO,EAAE,eAAe,EAAwB,MAAM,sBAAsB,CAAC;AAE7E;;GAEG;AACH,MAAM,CAAN,IAAY,aAIX;AAJD,WAAY,aAAa;IACxB,sCAAqB,CAAA;IACrB,8CAA6B,CAAA;IAC7B,0CAAyB,CAAA;AAC1B,CAAC,EAJW,aAAa,KAAb,aAAa,QAIxB;AAED;;GAEG;AACH,MAAM,CAAN,IAAY,cAOX;AAPD,WAAY,cAAc;IACzB,mCAAiB,CAAA;IACjB,iCAAe,CAAA;IACf,+BAAa,CAAA;IACb,+BAAa,CAAA;IACb,mCAAiB,CAAA;IACjB,yCAAuB,CAAA;AACxB,CAAC,EAPW,cAAc,KAAd,cAAc,QAOzB;AAmBD,MAAM,OAAO,oBAAoB;IACxB,MAAM,CAA6B;IACnC,gBAAgB,GAAqB,IAAI,CAAC;IAC1C,oBAAoB,GAAqB,IAAI,CAAC;IAC9C,wBAAwB,GAAG,IAAI,GAAG,EAAW,CAAC;IAC9C,4BAA4B,GAAG,IAAI,GAAG,EAAW,CAAC;IAClD,WAAW,GAAG,IAAI,GAAG,EAAsB,CAAC;IACpD,oFAAoF;IAC5E,eAAe,GAAG,IAAI,GAAG,EAA6B,CAAC;IACvD,gBAAgB,GAAG,CAAC,CAAC;IACrB,SAAS,GAAG,KAAK,CAAC;IAClB,eAAe,CAAkB;IACjC,aAAa,GAA4B,IAAI,CAAC;IAC9C,wBAAwB,GAC/B,IAAI,CAAC;IAEN,YAAY,SAAqC,EAAE;QAClD,IAAI,CAAC,MAAM,GAAG,MAAM,CAAC;QACrB,IAAI,CAAC,eAAe,GAAG,IAAI,eAAe,EAAE,CAAC;QAE7C,YAAY;QACZ,IAAI,OAAO,GAAG,KAAK,WAAW,IAAI,CAAC,CAAC,YAAY,IAAI,GAAG,CAAC,EAAE,CAAC;YAC1D,OAAO,CAAC,IAAI,CACX,qEAAqE,CACrE,CAAC;YACF,OAAO;QACR,CAAC;QAED,IAAI,CAAC,SAAS,GAAG,IAAI,CAAC;QACtB,IAAI,CAAC,oBAAoB,EAAE,CAAC;QAC5B,IAAI,CAAC,cAAc,EAAE,CAAC;QACtB,IAAI,CAAC,qBAAqB,EAAE,CAAC;QAC7B,IAAI,CAAC,qBAAqB,EAAE,CAAC;IAC9B,CAAC;IAEO,qBAAqB;QAC5B,IAAI,OAAO,QAAQ,KAAK,WAAW;YAAE,OAAO;QAC5C,IAAI,OAAO,gBAAgB,KAAK,WAAW;YAAE,OAAO;QAEpD,MAAM,OAAO,GAAG,GAAG,EAAE,CAAC,IAAI,CAAC,qBAAqB,EAAE,CAAC;QACnD,IAAI,CAAC,aAAa,GAAG,IAAI,gBAAgB,CAAC,OAAO,CAAC,CAAC;QAEnD,IAAI,CAAC,aAAa,CAAC,OAAO,CAAC,QAAQ,CAAC,eAAe,EAAE;YACpD,UAAU,EAAE,IAAI;YAChB,eAAe,EAAE,CAAC,OAAO,EAAE,YAAY,EAAE,mBAAmB,EAAE,OAAO,CAAC;SACtE,CAAC,CAAC;QAEH,KAAK,MAAM,IAAI,IAAI,QAAQ,CAAC,gBAAgB,CAAC,WAAW,CAAC,EAAE,CAAC;YAC3D,IAAI,CAAC,aAAa,CAAC,OAAO,CAAC,IAAI,EAAE;gBAChC,UAAU,EAAE,IAAI;gBAChB,eAAe,EAAE;oBAChB,OAAO;oBACP,QAAQ;oBACR,UAAU;oBACV,WAAW;oBACX,OAAO;oBACP,YAAY;oBACZ,mBAAmB;iBACnB;aACD,CAAC,CAAC;QACJ,CAAC;IACF,CAAC;IAEO,UAAU,CACjB,KAAgC;QAEhC,IAAI,CAAC,KAAK;YAAE,OAAO,IAAI,CAAC;QACxB,MAAM,KAAK,GAAG,KAAK,CAAC,IAAI,EAAE,CAAC;QAC3B,IAAI,CAAC,KAAK;YAAE,OAAO,IAAI,CAAC;QAExB,MAAM,QAAQ,GAAG,6BAA6B,CAAC,IAAI,CAAC,KAAK,CAAC,CAAC;QAC3D,IAAI,QAAQ,EAAE,CAAC;YACd,MAAM,GAAG,GAAG,QAAQ,CAAC,CAAC,CAAC,CAAC;YACxB,IAAI,GAAG,CAAC,MAAM,KAAK,CAAC,EAAE,CAAC;gBACtB,OAAO;oBACN,QAAQ,CAAC,GAAG,CAAC,CAAC,CAAC,GAAG,GAAG,CAAC,CAAC,CAAC,EAAE,EAAE,CAAC;oBAC7B,QAAQ,CAAC,GAAG,CAAC,CAAC,CAAC,GAAG,GAAG,CAAC,CAAC,CAAC,EAAE,EAAE,CAAC;oBAC7B,QAAQ,CAAC,GAAG,CAAC,CAAC,CAAC,GAAG,GAAG,CAAC,CAAC,CAAC,EAAE,EAAE,CAAC;iBAC7B,CAAC;YACH,CAAC;YACD,OAAO;gBACN,QAAQ,CAAC,GAAG,CAAC,KAAK,CAAC,CAAC,EAAE,CAAC,CAAC,EAAE,EAAE,CAAC;gBAC7B,QAAQ,CAAC,GAAG,CAAC,KAAK,CAAC,CAAC,EAAE,CAAC,CAAC,EAAE,EAAE,CAAC;gBAC7B,QAAQ,CAAC,GAAG,CAAC,KAAK,CAAC,CAAC,EAAE,CAAC,CAAC,EAAE,EAAE,CAAC;aAC7B,CAAC;QACH,CAAC;QAED,MAAM,QAAQ,GAAG,kBAAkB,CAAC,IAAI,CAAC,KAAK,CAAC,CAAC;QAChD,IAAI,QAAQ,EAAE,CAAC;YACd,MAAM,UAAU,GAAG,QAAQ,CAAC,CAAC,CAAC,CAAC,OAAO,CAAC,KAAK,EAAE,GAAG,CAAC,CAAC;YACnD,MAAM,KAAK,GAAG,UAAU;iBACtB,KAAK,CAAC,QAAQ,CAAC;iBACf,GAAG,CAAC,CAAC,IAAI,EAAE,EAAE,CAAC,IAAI,CAAC,IAAI,EAAE,CAAC;iBAC1B,MAAM,CAAC,OAAO,CAAC,CAAC;YAClB,MAAM,CAAC,GAAG,MAAM,CAAC,KAAK,CAAC,CAAC,CAAC,CAAC,CAAC;YAC3B,MAAM,CAAC,GAAG,MAAM,CAAC,KAAK,CAAC,CAAC,CAAC,CAAC,CAAC;YAC3B,MAAM,CAAC,GAAG,MAAM,CAAC,KAAK,CAAC,CAAC,CAAC,CAAC,CAAC;YAC3B,IAAI,MAAM,CAAC,QAAQ,CAAC,CAAC,CAAC,IAAI,MAAM,CAAC,QAAQ,CAAC,CAAC,CAAC,IAAI,MAAM,CAAC,QAAQ,CAAC,CAAC,CAAC,EAAE,CAAC;gBACpE,OAAO,CAAC,CAAC,EAAE,CAAC,EAAE,CAAC,CAAC,CAAC;YAClB,CAAC;QACF,CAAC;QAED,yDAAyD;QACzD,IAAI,OAAO,QAAQ,KAAK,WAAW,EAAE,CAAC;YACrC,MAAM,QAAQ,GAAG,QAAQ,CAAC,aAAa,CAAC,MAAM,CAAC,CAAC;YAChD,QAAQ,CAAC,KAAK,CAAC,KAAK,GAAG,KAAK,CAAC;YAC7B,IAAI,OAAO,QAAQ,CAAC,KAAK,CAAC,KAAK,KAAK,QAAQ,IAAI,QAAQ,CAAC,KAAK,CAAC,KAAK,EAAE,CAAC;gBACtE,QAAQ,CAAC,IAAI,EAAE,WAAW,CAAC,QAAQ,CAAC,CAAC;gBACrC,MAAM,QAAQ,GACb,OAAO,gBAAgB,KAAK,UAAU;oBACrC,CAAC,CAAC,gBAAgB,CAAC,QAAQ,CAAC,CAAC,KAAK;oBAClC,CAAC,CAAC,EAAE,CAAC;gBACP,QAAQ,CAAC,MAAM,EAAE,CAAC;gBAClB,MAAM,kBAAkB,GAAG,QAAQ,CAAC,IAAI,EAAE,CAAC;gBAC3C,qEAAqE;gBACrE,oEAAoE;gBACpE,IAAI,kBAAkB,IAAI,kBAAkB,KAAK,KAAK,EAAE,CAAC;oBACxD,OAAO,IAAI,CAAC,UAAU,CAAC,QAAQ,CAAC,CAAC;gBAClC,CAAC;YACF,CAAC;QACF,CAAC;QAED,OAAO,IAAI,CAAC;IACb,CAAC;IAEO,iBAAiB,CAAC,CAAC,CAAC,EAAE,CAAC,EAAE,CAAC,CAA2B;QAC5D,MAAM,QAAQ,GAAG,CAAC,OAAe,EAAE,EAAE;YACpC,MAAM,CAAC,GAAG,OAAO,GAAG,GAAG,CAAC;YACxB,OAAO,CAAC,IAAI,OAAO,CAAC,CAAC,CAAC,CAAC,GAAG,KAAK,CAAC,CAAC,CAAC,CAAC,CAAC,CAAC,GAAG,KAAK,CAAC,GAAG,KAAK,CAAC,IAAI,GAAG,CAAC;QAChE,CAAC,CAAC;QACF,MAAM,EAAE,GAAG,QAAQ,CAAC,CAAC,CAAC,CAAC;QACvB,MAAM,EAAE,GAAG,QAAQ,CAAC,CAAC,CAAC,CAAC;QACvB,MAAM,EAAE,GAAG,QAAQ,CAAC,CAAC,CAAC,CAAC;QACvB,OAAO,MAAM,GAAG,EAAE,GAAG,MAAM,GAAG,EAAE,GAAG,MAAM,GAAG,EAAE,CAAC;IAChD,CAAC;IAEO,aAAa,CACpB,CAA2B,EAC3B,CAA2B;QAE3B,MAAM,EAAE,GAAG,IAAI,CAAC,iBAAiB,CAAC,CAAC,CAAC,CAAC;QACrC,MAAM,EAAE,GAAG,IAAI,CAAC,iBAAiB,CAAC,CAAC,CAAC,CAAC;QACrC,MAAM,OAAO,GAAG,IAAI,CAAC,GAAG,CAAC,EAAE,EAAE,EAAE,CAAC,CAAC;QACjC,MAAM,MAAM,GAAG,IAAI,CAAC,GAAG,CAAC,EAAE,EAAE,EAAE,CAAC,CAAC;QAChC,OAAO,CAAC,OAAO,GAAG,IAAI,CAAC,GAAG,CAAC,MAAM,GAAG,IAAI,CAAC,CAAC;IAC3C,CAAC;IAEO,KAAK,CACZ,EAA4B,EAC5B,EAA4B,EAC5B,KAAa;QAEb,OAAO;YACN,IAAI,CAAC,KAAK,CAAC,EAAE,CAAC,CAAC,CAAC,GAAG,KAAK,GAAG,EAAE,CAAC,CAAC,CAAC,GAAG,CAAC,CAAC,GAAG,KAAK,CAAC,CAAC;YAC/C,IAAI,CAAC,KAAK,CAAC,EAAE,CAAC,CAAC,CAAC,GAAG,KAAK,GAAG,EAAE,CAAC,CAAC,CAAC,GAAG,CAAC,CAAC,GAAG,KAAK,CAAC,CAAC;YAC/C,IAAI,CAAC,KAAK,CAAC,EAAE,CAAC,CAAC,CAAC,GAAG,KAAK,GAAG,EAAE,CAAC,CAAC,CAAC,GAAG,CAAC,CAAC,GAAG,KAAK,CAAC,CAAC;SAC/C,CAAC;IACH,CAAC;IAEO,uBAAuB,CAAC,QAAyB;QAMxD,MAAM,eAAe,GAA6B,CAAC,GAAG,EAAE,GAAG,EAAE,EAAE,CAAC,CAAC;QACjE,MAAM,YAAY,GAA6B,CAAC,EAAE,EAAE,EAAE,EAAE,EAAE,CAAC,CAAC;QAC5D,MAAM,kBAAkB,GAA6B,CAAC,GAAG,EAAE,GAAG,EAAE,GAAG,CAAC,CAAC;QAErE,MAAM,MAAM,GACX,QAAQ;YACR,CAAC,OAAO,QAAQ,KAAK,WAAW,CAAC,CAAC,CAAC,QAAQ,CAAC,eAAe,CAAC,CAAC,CAAC,IAAI,CAAC,CAAC;QACrE,MAAM,QAAQ,GACb,MAAM,IAAI,OAAO,gBAAgB,KAAK,UAAU;YAC/C,CAAC,CAAC,gBAAgB,CAAC,MAAM,CAAC;YAC1B,CAAC,CAAC,IAAI,CAAC;QAET,MAAM,UAAU,GACf,IAAI,CAAC,UAAU,CACd,QAAQ,EAAE,gBAAgB,CAAC,kBAAkB,CAAC;YAC7C,QAAQ,EAAE,eAAe,CAC1B,IAAI,kBAAkB,CAAC;QACzB,MAAM,IAAI,GACT,IAAI,CAAC,UAAU,CAAC,QAAQ,EAAE,gBAAgB,CAAC,YAAY,CAAC,CAAC,IAAI,YAAY,CAAC;QAC3E,MAAM,MAAM,GAAG,IAAI,CAAC,wBAAwB;YAC3C,CAAC,CAAC,IAAI,CAAC,UAAU,CAAC,IAAI,CAAC,wBAAwB,CAAC,KAAK,CAAC,IAAI,eAAe;YACzE,CAAC,CAAC,IAAI,CAAC,UAAU,CAAC,QAAQ,EAAE,gBAAgB,CAAC,eAAe,CAAC,CAAC;gBAC7D,eAAe,CAAC;QAElB,MAAM,iBAAiB,GAAG,IAAI,CAAC,wBAAwB;YACtD,CAAC,CAAC,CAAC,IAAI,CAAC,GAAG,CAAC,GAAG,EAAE,IAAI,CAAC,GAAG,CAAC,IAAI,EAAE,IAAI,CAAC,wBAAwB,CAAC,OAAO,CAAC,CAAC,CAAC;YACxE,CAAC,CAAC,CAAC,GAAG,EAAE,IAAI,EAAE,IAAI,EAAE,IAAI,EAAE,IAAI,EAAE,GAAG,CAAC,CAAC;QAEtC,IAAI,eAAe,GAAG,iBAAiB,CAAC,iBAAiB,CAAC,MAAM,GAAG,CAAC,CAAC,CAAC;QACtE,IAAI,SAAS,GAAG,CAAC,QAAQ,CAAC;QAE1B,KAAK,MAAM,OAAO,IAAI,iBAAiB,EAAE,CAAC;YACzC,MAAM,OAAO,GAAG,IAAI,CAAC,KAAK,CAAC,MAAM,EAAE,UAAU,EAAE,OAAO,CAAC,CAAC;YACxD,MAAM,eAAe,GAAG,IAAI,CAAC,aAAa,CAAC,OAAO,EAAE,UAAU,CAAC,CAAC;YAChE,MAAM,YAAY,GAAG,IAAI,CAAC,aAAa,CAAC,OAAO,EAAE,IAAI,CAAC,CAAC;YACvD,MAAM,KAAK,GAAG,eAAe,GAAG,GAAG,GAAG,YAAY,GAAG,GAAG,CAAC;YACzD,IAAI,eAAe,IAAI,IAAI,IAAI,YAAY,IAAI,GAAG,EAAE,CAAC;gBACpD,eAAe,GAAG,OAAO,CAAC;gBAC1B,MAAM;YACP,CAAC;YACD,IAAI,KAAK,GAAG,SAAS,EAAE,CAAC;gBACvB,SAAS,GAAG,KAAK,CAAC;gBAClB,eAAe,GAAG,OAAO,CAAC;YAC3B,CAAC;QACF,CAAC;QAED,MAAM,eAAe,GAAG,IAAI,CAAC,GAAG,CAC/B,IAAI,EACJ,IAAI,CAAC,GAAG,CAAC,IAAI,EAAE,eAAe,GAAG,IAAI,CAAC,CACtC,CAAC;QACF,MAAM,gBAAgB,GAAG,IAAI,CAAC,GAAG,CAChC,IAAI,EACJ,IAAI,CAAC,GAAG,CAAC,IAAI,EAAE,eAAe,GAAG,GAAG,CAAC,CACrC,CAAC;QACF,MAAM,aAAa,GAAG,IAAI,CAAC,GAAG,CAAC,IAAI,EAAE,IAAI,CAAC,GAAG,CAAC,GAAG,EAAE,eAAe,GAAG,IAAI,CAAC,CAAC,CAAC;QAE5E,MAAM,cAAc,GAAG,IAAI,CAAC;QAC5B,MAAM,cAAc,GAAG,IAAI,CAAC,KAAK,CAChC,cAAc,EACd,UAAU,EACV,gBAAgB,CAChB,CAAC;QACF,MAAM,cAAc,GAAG,IAAI,CAAC,aAAa,CAAC,cAAc,EAAE,UAAU,CAAC,CAAC;QACtE,MAAM,iBAAiB,GACtB,IAAI,CAAC,iBAAiB,CAAC,UAAU,CAAC,GAAG,IAAI,CAAC,CAAC,CAAC,CAAC,CAAC,EAAE,CAAC,EAAE,CAAC,CAAC,CAAC,CAAC,CAAC,CAAC,GAAG,EAAE,GAAG,EAAE,GAAG,CAAC,CAAC;QACzE,MAAM,cAAc,GACnB,cAAc,IAAI,IAAI,CAAC,CAAC,CAAC,cAAc,CAAC,CAAC,CAAC,iBAAiB,CAAC;QAE7D,MAAM,aAAa,GAAG,QAAQ,MAAM,CAAC,CAAC,CAAC,KAAK,MAAM,CAAC,CAAC,CAAC,KAAK,MAAM,CAAC,CAAC,CAAC,KAAK,eAAe,GAAG,CAAC;QAC3F,MAAM,iBAAiB,GAAG,QAAQ,MAAM,CAAC,CAAC,CAAC,KAAK,MAAM,CAAC,CAAC,CAAC,KAAK,MAAM,CAAC,CAAC,CAAC,KAAK,eAAe,GAAG,CAAC;QAC/F,MAAM,aAAa,GAAG,QAAQ,cAAc,CAAC,CAAC,CAAC,KAAK,cAAc,CAAC,CAAC,CAAC,KAAK,cAAc,CAAC,CAAC,CAAC,KAAK,gBAAgB,GAAG,CAAC;QACpH,MAAM,UAAU,GAAG,QAAQ,cAAc,CAAC,CAAC,CAAC,KAAK,cAAc,CAAC,CAAC,CAAC,KAAK,cAAc,CAAC,CAAC,CAAC,KAAK,aAAa,GAAG,CAAC;QAE9G,OAAO;YACN,aAAa;YACb,iBAAiB;YACjB,aAAa;YACb,UAAU;SACV,CAAC;IACH,CAAC;IAEO,qBAAqB,CAAC,QAAyB;QACtD,IAAI,OAAO,QAAQ,KAAK,WAAW;YAAE,OAAO;QAC5C,MAAM,IAAI,GAAG,IAAI,CAAC,uBAAuB,CAAC,QAAQ,CAAC,CAAC;QACpD,QAAQ,CAAC,eAAe,CAAC,KAAK,CAAC,WAAW,CACzC,0BAA0B,EAC1B,IAAI,CAAC,aAAa,CAClB,CAAC;QACF,QAAQ,CAAC,eAAe,CAAC,KAAK,CAAC,WAAW,CACzC,8BAA8B,EAC9B,IAAI,CAAC,iBAAiB,CACtB,CAAC;QACF,QAAQ,CAAC,eAAe,CAAC,KAAK,CAAC,WAAW,CACzC,0BAA0B,EAC1B,IAAI,CAAC,iBAAiB,CACtB,CAAC;QACF,QAAQ,CAAC,eAAe,CAAC,KAAK,CAAC,WAAW,CACzC,0BAA0B,EAC1B,IAAI,CAAC,aAAa,CAClB,CAAC;QACF,QAAQ,CAAC,eAAe,CAAC,KAAK,CAAC,WAAW,CACzC,uBAAuB,EACvB,IAAI,CAAC,UAAU,CACf,CAAC;IACH,CAAC;IAED;;OAEG;IACK,oBAAoB;QAC3B,IAAI,CAAC,IAAI,CAAC,SAAS;YAAE,OAAO;QAE5B,sCAAsC;QACtC,IAAI,CAAC,gBAAgB,GAAG,IAAI,SAAS,EAAE,CAAC;QACxC,IAAI,CAAC,oBAAoB,GAAG,IAAI,SAAS,EAAE,CAAC;QAE5C,mCAAmC;QACnC,GAAG,CAAC,UAAU,CAAC,GAAG,CAAC,UAAU,EAAE,IAAI,CAAC,gBAAgB,CAAC,CAAC;QACtD,GAAG,CAAC,UAAU,CAAC,GAAG,CAAC,cAAc,EAAE,IAAI,CAAC,oBAAoB,CAAC,CAAC;QAE9D,qDAAqD;QACrD,KAAK,MAAM,KAAK,IAAI,MAAM,CAAC,MAAM,CAAC,cAAc,CAAC,EAAE,CAAC;YACnD,MAAM,SAAS,GAAG,IAAI,SAAS,EAAE,CAAC;YAClC,IAAI,CAAC,eAAe,CAAC,GAAG,CAAC,KAAK,EAAE,SAAS,CAAC,CAAC;YAC3C,GAAG,CAAC,UAAU,CAAC,GAAG,CAAC,cAAc,KAAK,EAAE,EAAE,SAAS,CAAC,CAAC;QACtD,CAAC;IACF,CAAC;IAED;;OAEG;IACK,cAAc;QACrB,IAAI,CAAC,IAAI,CAAC,SAAS;YAAE,OAAO;QAC5B,IAAI,OAAO,QAAQ,KAAK,WAAW;YAAE,OAAO,CAAC,YAAY;QAEzD,gCAAgC;QAChC,IAAI,QAAQ,CAAC,cAAc,CAAC,sBAAsB,CAAC;YAAE,OAAO;QAE5D,MAAM,KAAK,GAAG,QAAQ,CAAC,aAAa,CAAC,OAAO,CAAC,CAAC;QAC9C,KAAK,CAAC,EAAE,GAAG,sBAAsB,CAAC;QAClC,KAAK,CAAC,WAAW,GAAG;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;KAmEjB,CAAC;QACJ,QAAQ,CAAC,IAAI,CAAC,WAAW,CAAC,KAAK,CAAC,CAAC;IAClC,CAAC;IAED;;;;;;OAMG;IACH,gBAAgB,CACf,QAAc,EACd,WAAmB,EACnB,SAAiB;QAEjB,IAAI,CAAC,IAAI,CAAC,gBAAgB;YAAE,OAAO;QACnC,IAAI,CAAC,qBAAqB,CAAC,QAAQ,CAAC,aAAa,CAAC,CAAC;QAEnD,gCAAgC;QAChC,IAAI,CAAC,YAAY,EAAE,CAAC;QAEpB,wBAAwB;QACxB,MAAM,KAAK,GAAG,QAAQ,CAAC,WAAW,EAAE,CAAC;QACrC,KAAK,CAAC,QAAQ,CAAC,QAAQ,EAAE,WAAW,CAAC,CAAC;QACtC,KAAK,CAAC,MAAM,CAAC,QAAQ,EAAE,SAAS,CAAC,CAAC;QAElC,mBAAmB;QACnB,IAAI,CAAC,gBAAgB,CAAC,GAAG,CAAC,KAAK,CAAC,CAAC;IAClC,CAAC;IAED;;;;;;;;;;;;;;;;OAgBG;IACH,uBAAuB,CAAC,OAAgB;QACvC,IAAI,CAAC,IAAI,CAAC,gBAAgB;YAAE,OAAO;QACnC,IAAI,CAAC,qBAAqB,CAAC,OAAO,CAAC,CAAC;QAEpC,uEAAuE;QACvE,IAAI,CAAC,YAAY,EAAE,CAAC;QAEpB,OAAO,CAAC,YAAY,CAAC,2BAA2B,EAAE,MAAM,CAAC,CAAC;QAC1D,IAAI,CAAC,wBAAwB,CAAC,GAAG,CAAC,OAAO,CAAC,CAAC;IAC5C,CAAC;IAED;;;;;OAKG;IACH,oBAAoB,CAAC,MAAe;QACnC,IAAI,CAAC,IAAI,CAAC,oBAAoB;YAAE,OAAO;QACvC,MAAM,MAAM,GAAG,MAAM,CAAC,CAAC,CAAC,EAAE,cAAc,CAAC;QACzC,MAAM,aAAa,GAClB,MAAM,EAAE,QAAQ,KAAK,IAAI,CAAC,YAAY;YACrC,CAAC,CAAE,MAAkB;YACrB,CAAC,CAAC,MAAM,EAAE,aAAa,CAAC;QAC1B,IAAI,CAAC,qBAAqB,CAAC,aAAa,CAAC,CAAC;QAE1C,oCAAoC;QACpC,IAAI,CAAC,gBAAgB,EAAE,CAAC;QAExB,iBAAiB;QACjB,KAAK,MAAM,KAAK,IAAI,MAAM,EAAE,CAAC;YAC5B,IAAI,CAAC,oBAAoB,CAAC,GAAG,CAAC,KAAK,CAAC,CAAC;QACtC,CAAC;QACD,IAAI,CAAC,4BAA4B,CAAC,MAAM,CAAC,CAAC;IAC3C,CAAC;IAED,yEAAyE;IACzE,8CAA8C;IACtC,MAAM,CAAU,0BAA0B,GACjD,qDAAqD,CAAC;IAEvD,uEAAuE;IACvE,yEAAyE;IACzE,0EAA0E;IAC1E,6EAA6E;IAC7E,8EAA8E;IAC9E,kDAAkD;IAC1C,MAAM,CAAU,sBAAsB,GAC7C,gCAAgC,CAAC;IAE1B,4BAA4B,CAAC,MAAe;QACnD,IAAI,OAAO,OAAO,KAAK,WAAW;YAAE,OAAO;QAC3C,IAAI,CAAC,yBAAyB,CAC7B,MAAM,EACN,+BAA+B,EAC/B,IAAI,CAAC,4BAA4B,EACjC,oBAAoB,CAAC,0BAA0B,CAC/C,CAAC;IACH,CAAC;IAEO,gCAAgC,CAAC,MAAe;QACvD,IAAI,OAAO,OAAO,KAAK,WAAW;YAAE,OAAO;QAC3C,IAAI,CAAC,yBAAyB,CAC7B,MAAM,EACN,2BAA2B,EAC3B,IAAI,CAAC,wBAAwB,EAC7B,oBAAoB,CAAC,sBAAsB,CAC3C,CAAC;IACH,CAAC;IAEO,yBAAyB,CAChC,MAAe,EACf,aAAqB,EACrB,eAA6B,EAC7B,QAAgB;QAEhB,KAAK,MAAM,KAAK,IAAI,MAAM,EAAE,CAAC;YAC5B,MAAM,IAAI,GACT,KAAK,CAAC,uBAAuB,CAAC,QAAQ,KAAK,IAAI,CAAC,YAAY;gBAC3D,CAAC,CAAE,KAAK,CAAC,uBAAmC;gBAC5C,CAAC,CAAC,KAAK,CAAC,uBAAuB,CAAC,aAAa,CAAC;YAChD,IAAI,CAAC,IAAI;gBAAE,SAAS;YACpB,MAAM,UAAU,GAAc,EAAE,CAAC;YACjC,MAAM,iBAAiB,GACtB,KAAK,CAAC,cAAc,CAAC,QAAQ,KAAK,IAAI,CAAC,YAAY;gBAClD,CAAC,CAAE,KAAK,CAAC,cAA0B;gBACnC,CAAC,CAAC,KAAK,CAAC,cAAc,CAAC,aAAa,CAAC;YACvC,MAAM,eAAe,GACpB,KAAK,CAAC,YAAY,CAAC,QAAQ,KAAK,IAAI,CAAC,YAAY;gBAChD,CAAC,CAAE,KAAK,CAAC,YAAwB;gBACjC,CAAC,CAAC,KAAK,CAAC,YAAY,CAAC,aAAa,CAAC;YACrC,KAAK,MAAM,OAAO,IAAI,CAAC,iBAAiB,EAAE,eAAe,CAAC,EAAE,CAAC;gBAC5D,IAAI,OAAO,GAAmB,OAAO,CAAC;gBACtC,OAAO,OAAO,EAAE,CAAC;oBAChB,IAAI,OAAO,CAAC,OAAO,EAAE,CAAC,QAAQ,CAAC;wBAAE,UAAU,CAAC,IAAI,CAAC,OAAO,CAAC,CAAC;oBAC1D,OAAO,GAAG,OAAO,CAAC,aAAa,CAAC;gBACjC,CAAC;YACF,CAAC;YACD,IAAI,IAAI,CAAC,OAAO,EAAE,CAAC,QAAQ,CAAC,EAAE,CAAC;gBAC9B,UAAU,CAAC,IAAI,CAAC,IAAI,CAAC,CAAC;YACvB,CAAC;YACD,UAAU,CAAC,IAAI,CAAC,GAAG,KAAK,CAAC,IAAI,CAAC,IAAI,CAAC,gBAAgB,CAAC,QAAQ,CAAC,CAAC,CAAC,CAAC;YAChE,KAAK,MAAM,OAAO,IAAI,IAAI,GAAG,CAAC,UAAU,CAAC,EAAE,CAAC;gBAC3C,IAAI,CAAC;oBACJ,IACC,CAAC,KAAK,CAAC,cAAc,CAAC,OAAO,CAAC;wBAC9B,CAAC,OAAO,CAAC,QAAQ,CAAC,iBAAiB,CAAC;wBACpC,CAAC,OAAO,CAAC,QAAQ,CAAC,eAAe,CAAC,EACjC,CAAC;wBACF,SAAS;oBACV,CAAC;gBACF,CAAC;gBAAC,MAAM,CAAC;oBACR,SAAS;gBACV,CAAC;gBACD,OAAO,CAAC,YAAY,CAAC,aAAa,EAAE,MAAM,CAAC,CAAC;gBAC5C,eAAe,CAAC,GAAG,CAAC,OAAO,CAAC,CAAC;YAC9B,CAAC;QACF,CAAC;IACF,CAAC;IAED;;OAEG;IACH,YAAY;QACX,IAAI,CAAC,IAAI,CAAC,gBAAgB;YAAE,OAAO;QACnC,IAAI,CAAC,gBAAgB,CAAC,KAAK,EAAE,CAAC;QAC9B,KAAK,MAAM,OAAO,IAAI,IAAI,CAAC,wBAAwB,EAAE,CAAC;YACrD,OAAO,CAAC,eAAe,CAAC,2BAA2B,CAAC,CAAC;QACtD,CAAC;QACD,IAAI,CAAC,wBAAwB,CAAC,KAAK,EAAE,CAAC;IACvC,CAAC;IAED;;OAEG;IACH,gBAAgB;QACf,IAAI,CAAC,IAAI,CAAC,oBAAoB;YAAE,OAAO;QACvC,IAAI,CAAC,oBAAoB,CAAC,KAAK,EAAE,CAAC;QAClC,KAAK,MAAM,OAAO,IAAI,IAAI,CAAC,4BAA4B,EAAE,CAAC;YACzD,OAAO,CAAC,eAAe,CAAC,+BAA+B,CAAC,CAAC;QAC1D,CAAC;QACD,IAAI,CAAC,4BAA4B,CAAC,KAAK,EAAE,CAAC;IAC3C,CAAC;IAED;;OAEG;IACH,QAAQ;QACP,IAAI,CAAC,YAAY,EAAE,CAAC;QACpB,IAAI,CAAC,gBAAgB,EAAE,CAAC;IACzB,CAAC;IAED;;;;;;OAMG;IACH,aAAa,CACZ,KAAY,EACZ,QAAwB,cAAc,CAAC,MAAM;QAE7C,MAAM,EAAE,GAAG,cAAc,IAAI,CAAC,gBAAgB,EAAE,EAAE,CAAC;QAEnD,2BAA2B;QAC3B,MAAM,WAAW,GAAG,KAAK,CAAC,UAAU,EAAE,CAAC;QAEvC,wBAAwB;QACxB,MAAM,UAAU,GAAe;YAC9B,EAAE;YACF,KAAK,EAAE,WAAW;YAClB,IAAI,EAAE,aAAa,CAAC,UAAU;YAC9B,KAAK;YACL,SAAS,EAAE,IAAI,CAAC,GAAG,EAAE;SACrB,CAAC;QACF,IAAI,CAAC,WAAW,CAAC,GAAG,CAAC,EAAE,EAAE,UAAU,CAAC,CAAC;QAErC,0DAA0D;QAC1D,mDAAmD;QACnD,MAAM,cAAc,GAAG,IAAI,CAAC,eAAe,CAAC,GAAG,CAAC,KAAK,CAAC,CAAC;QACvD,IAAI,cAAc,EAAE,CAAC;YACpB,cAAc,CAAC,GAAG,CAAC,WAAW,CAAC,CAAC;QACjC,CAAC;QAED,OAAO,EAAE,CAAC;IACX,CAAC;IAED;;;;OAIG;IACH,gBAAgB,CAAC,EAAU;QAC1B,MAAM,UAAU,GAAG,IAAI,CAAC,WAAW,CAAC,GAAG,CAAC,EAAE,CAAC,CAAC;QAC5C,IAAI,CAAC,UAAU,EAAE,CAAC;YACjB,OAAO,CAAC,IAAI,CAAC,qCAAqC,EAAE,YAAY,CAAC,CAAC;YAClE,OAAO;QACR,CAAC;QAED,OAAO,CAAC,GAAG,CACV,8CAA8C,EAAE,YAAY,UAAU,CAAC,KAAK,GAAG,CAC/E,CAAC;QAEF,+CAA+C;QAC/C,MAAM,cAAc,GAAG,IAAI,CAAC,eAAe,CAAC,GAAG,CAAC,UAAU,CAAC,KAAK,CAAC,CAAC;QAClE,IAAI,cAAc,EAAE,CAAC;YACpB,MAAM,OAAO,GAAG,cAAc,CAAC,MAAM,CAAC,UAAU,CAAC,KAAK,CAAC,CAAC;YACxD,OAAO,CAAC,GAAG,CACV,qDAAqD,EACrD,OAAO,CACP,CAAC;QACH,CAAC;QAED,WAAW;QACX,IAAI,CAAC,WAAW,CAAC,MAAM,CAAC,EAAE,CAAC,CAAC;QAC5B,OAAO,CAAC,GAAG,CACV,qCAAqC,EAAE,+BAA+B,EACtE,IAAI,CAAC,WAAW,CAAC,IAAI,CACrB,CAAC;IACH,CAAC;IAED;;OAEG;IACH,gBAAgB;QACf,6BAA6B;QAC7B,KAAK,MAAM,cAAc,IAAI,IAAI,CAAC,eAAe,CAAC,MAAM,EAAE,EAAE,CAAC;YAC5D,cAAc,CAAC,KAAK,EAAE,CAAC;QACxB,CAAC;QAED,wBAAwB;QACxB,IAAI,CAAC,WAAW,CAAC,KAAK,EAAE,CAAC;IAC1B,CAAC;IAED;;OAEG;IACH,cAAc;QACb,OAAO,KAAK,CAAC,IAAI,CAAC,IAAI,CAAC,WAAW,CAAC,MAAM,EAAE,CAAC,CAAC;IAC9C,CAAC;IAED;;OAEG;IACH,aAAa,CAAC,EAAU;QACvB,OAAO,IAAI,CAAC,WAAW,CAAC,GAAG,CAAC,EAAE,CAAC,IAAI,IAAI,CAAC;IACzC,CAAC;IAED;;;;;OAKG;IACH,qBAAqB,CAAC,EAAU,EAAE,QAAwB;QACzD,MAAM,UAAU,GAAG,IAAI,CAAC,WAAW,CAAC,GAAG,CAAC,EAAE,CAAC,CAAC;QAC5C,IAAI,CAAC,UAAU;YAAE,OAAO;QAExB,MAAM,QAAQ,GAAG,UAAU,CAAC,KAAK,CAAC;QAClC,IAAI,QAAQ,KAAK,QAAQ;YAAE,OAAO;QAElC,kCAAkC;QAClC,MAAM,iBAAiB,GAAG,IAAI,CAAC,eAAe,CAAC,GAAG,CAAC,QAAQ,CAAC,CAAC;QAC7D,IAAI,iBAAiB,EAAE,CAAC;YACvB,iBAAiB,CAAC,MAAM,CAAC,UAAU,CAAC,KAAK,CAAC,CAAC;QAC5C,CAAC;QAED,eAAe;QACf,UAAU,CAAC,KAAK,GAAG,QAAQ,CAAC;QAE5B,6BAA6B;QAC7B,MAAM,iBAAiB,GAAG,IAAI,CAAC,eAAe,CAAC,GAAG,CAAC,QAAQ,CAAC,CAAC;QAC7D,IAAI,iBAAiB,EAAE,CAAC;YACvB,iBAAiB,CAAC,GAAG,CAAC,UAAU,CAAC,KAAK,CAAC,CAAC;QACzC,CAAC;IACF,CAAC;IAED;;;;;;OAMG;IACH,iBAAiB,CAChB,OAAgB,QAAQ,CAAC,IAAI;QAI7B,OAAO,IAAI,CAAC,cAAc,EAAE,CAAC,GAAG,CAAC,CAAC,UAAU,EAAE,EAAE,CAAC,CAAC;YACjD,GAAG,IAAI,CAAC,eAAe,CAAC,SAAS,CAAC,UAAU,CAAC,KAAK,EAAE,IAAI,CAAC;YACzD,EAAE,EAAE,UAAU,CAAC,EAAE;YACjB,KAAK,EAAE,UAAU,CAAC,KAAK;YACvB,SAAS,EAAE,UAAU,CAAC,SAAS;SAC/B,CAAC,CAAC,CAAC;IACL,CAAC;IAED;;;;;;;OAOG;IACH,iBAAiB,CAChB,IAMC,EACD,OAAgB,QAAQ,CAAC,IAAI;QAE7B,IAAI,QAAQ,GAAG,CAAC,CAAC;QAEjB,KAAK,MAAM,IAAI,IAAI,IAAI,EAAE,CAAC;YACzB,MAAM,KAAK,GAAG,IAAI,CAAC,eAAe,CAAC,WAAW,CAAC,IAAI,EAAE,IAAI,CAAC,CAAC;YAC3D,IAAI,KAAK,EAAE,CAAC;gBACX,IAAI,CAAC,aAAa,CAAC,KAAK,EAAE,IAAI,CAAC,KAAK,CAAC,CAAC;gBACtC,QAAQ,EAAE,CAAC;YACZ,CAAC;QACF,CAAC;QAED,OAAO,QAAQ,CAAC;IACjB,CAAC;IAED,+EAA+E;IAC/E,mDAAmD;IACnD,+EAA+E;IAE/E;;;;;OAKG;IACH,cAAc,CACb,KAAY,EACZ,IAAmB,EACnB,QAAwB,cAAc,CAAC,MAAM;QAE7C,IAAI,CAAC,IAAI,CAAC,SAAS;YAAE,OAAO;QAE5B,QAAQ,IAAI,EAAE,CAAC;YACd,KAAK,aAAa,CAAC,QAAQ,CAAC;YAC5B,KAAK,aAAa,CAAC,YAAY,CAAC,CAAC,CAAC;gBACjC,wCAAwC;gBACxC,MAAM,SAAS,GACd,IAAI,KAAK,aAAa,CAAC,QAAQ;oBAC9B,CAAC,CAAC,IAAI,CAAC,gBAAgB;oBACvB,CAAC,CAAC,IAAI,CAAC,oBAAoB,CAAC;gBAC9B,IAAI,SAAS,EAAE,CAAC;oBACf,SAAS,CAAC,KAAK,EAAE,CAAC;oBAClB,SAAS,CAAC,GAAG,CAAC,KAAK,CAAC,CAAC;oBACrB,IAAI,IAAI,KAAK,aAAa,CAAC,QAAQ,EAAE,CAAC;wBACrC,KAAK,MAAM,OAAO,IAAI,IAAI,CAAC,wBAAwB,EAAE,CAAC;4BACrD,OAAO,CAAC,eAAe,CAAC,2BAA2B,CAAC,CAAC;wBACtD,CAAC;wBACD,IAAI,CAAC,wBAAwB,CAAC,KAAK,EAAE,CAAC;wBACtC,IAAI,CAAC,gCAAgC,CAAC,CAAC,KAAK,CAAC,CAAC,CAAC;oBAChD,CAAC;gBACF,CAAC;gBACD,MAAM;YACP,CAAC;YACD,KAAK,aAAa,CAAC,UAAU;gBAC5B,2CAA2C;gBAC3C,IAAI,CAAC,aAAa,CAAC,KAAK,EAAE,KAAK,CAAC,CAAC;gBACjC,MAAM;QACR,CAAC;IACF,CAAC;IAED;;OAEG;IACH,eAAe,CAAC,IAAmB;QAClC,IAAI,CAAC,IAAI,CAAC,SAAS;YAAE,OAAO;QAE5B,QAAQ,IAAI,EAAE,CAAC;YACd,KAAK,aAAa,CAAC,QAAQ;gBAC1B,IAAI,CAAC,YAAY,EAAE,CAAC;gBACpB,MAAM;YACP,KAAK,aAAa,CAAC,YAAY;gBAC9B,IAAI,CAAC,gBAAgB,EAAE,CAAC;gBACxB,MAAM;YACP,KAAK,aAAa,CAAC,UAAU;gBAC5B,IAAI,CAAC,gBAAgB,EAAE,CAAC;gBACxB,MAAM;QACR,CAAC;IACF,CAAC;IAED;;OAEG;IACH,QAAQ;QACP,IAAI,CAAC,IAAI,CAAC,SAAS;YAAE,OAAO;QAC5B,IAAI,CAAC,QAAQ,EAAE,CAAC;QAChB,IAAI,CAAC,gBAAgB,EAAE,CAAC;IACzB,CAAC;IAED;;OAEG;IACH,WAAW;QACV,OAAO,IAAI,CAAC,SAAS,CAAC;IACvB,CAAC;IAED;;;;;OAKG;IACH,uBAAuB,CAAC,KAAa,EAAE,OAAe;QACrD,IAAI,CAAC,IAAI,CAAC,SAAS;YAAE,OAAO;QAC5B,IAAI,OAAO,QAAQ,KAAK,WAAW;YAAE,OAAO;QAE5C,MAAM,OAAO,GAAG,QAAQ,CAAC,cAAc,CAAC,sBAAsB,CAAC,CAAC;QAChE,IAAI,CAAC,OAAO;YAAE,OAAO;QAErB,sBAAsB;QACtB,MAAM,QAAQ,GAAG,CAAC,GAAW,EAAE,EAAE;YAChC,MAAM,MAAM,GAAG,2CAA2C,CAAC,IAAI,CAAC,GAAG,CAAC,CAAC;YACrE,OAAO,MAAM;gBACZ,CAAC,CAAC;oBACA,CAAC,EAAE,QAAQ,CAAC,MAAM,CAAC,CAAC,CAAC,EAAE,EAAE,CAAC;oBAC1B,CAAC,EAAE,QAAQ,CAAC,MAAM,CAAC,CAAC,CAAC,EAAE,EAAE,CAAC;oBAC1B,CAAC,EAAE,QAAQ,CAAC,MAAM,CAAC,CAAC,CAAC,EAAE,EAAE,CAAC;iBAC1B;gBACF,CAAC,CAAC,IAAI,CAAC;QACT,CAAC,CAAC;QAEF,MAAM,GAAG,GAAG,QAAQ,CAAC,KAAK,CAAC,CAAC;QAC5B,IAAI,CAAC,GAAG;YAAE,OAAO;QAEjB,IAAI,CAAC,wBAAwB,GAAG;YAC/B,KAAK,EAAE,OAAO,GAAG,CAAC,CAAC,KAAK,GAAG,CAAC,CAAC,KAAK,GAAG,CAAC,CAAC,GAAG;YAC1C,OAAO,EAAE,IAAI,CAAC,GAAG,CAAC,GAAG,EAAE,IAAI,CAAC,GAAG,CAAC,IAAI,EAAE,OAAO,CAAC,CAAC;SAC/C,CAAC;QACF,IAAI,CAAC,qBAAqB,EAAE,CAAC;IAC9B,CAAC;IAED;;OAEG;IACH,OAAO;QACN,IAAI,CAAC,IAAI,CAAC,SAAS;YAAE,OAAO;QAE5B,IAAI,CAAC,QAAQ,EAAE,CAAC;QAChB,IAAI,CAAC,gBAAgB,EAAE,CAAC;QAExB,uBAAuB;QACvB,IAAI,OAAO,QAAQ,KAAK,WAAW,EAAE,CAAC;YACrC,MAAM,OAAO,GAAG,QAAQ,CAAC,cAAc,CAAC,sBAAsB,CAAC,CAAC;YAChE,IAAI,OAAO,EAAE,CAAC;gBACb,OAAO,CAAC,MAAM,EAAE,CAAC;YAClB,CAAC;QACF,CAAC;QACD,IAAI,CAAC,aAAa,EAAE,UAAU,EAAE,CAAC;QACjC,IAAI,CAAC,aAAa,GAAG,IAAI,CAAC;IAC3B,CAAC","sourcesContent":["/**\n * HighlightCoordinator\n *\n * Manages separate highlight layers for TTS (temporary) and annotations (persistent).\n * Uses CSS Custom Highlight API - zero DOM mutation, preserves accessibility.\n *\n * Features:\n * - Separate layers prevent TTS clearing from removing student annotations\n * - CSS Custom Highlight API (no DOM mutation)\n * - Full accessibility support (screen readers see original text)\n * - Configurable colors and styles\n * - Annotation persistence via RangeSerializer\n *\n * Part of PIE Assessment Toolkit.\n *\n * Browser Support:\n * - Chrome/Edge 105+\n * - Safari 17.2+\n * - Firefox: Behind flag (not recommended for production)\n *\n * @see https://developer.mozilla.org/en-US/docs/Web/API/CSS_Custom_Highlight_API\n */\n\nimport type { HighlightCoordinatorApi } from \"./interfaces.js\";\nimport { RangeSerializer, type SerializedRange } from \"./RangeSerializer.js\";\n\n/**\n * Highlight types\n */\nexport enum HighlightType {\n\tTTS_WORD = \"tts-word\",\n\tTTS_SENTENCE = \"tts-sentence\",\n\tANNOTATION = \"annotation\",\n}\n\n/**\n * Highlight colors for annotations\n */\nexport enum HighlightColor {\n\tYELLOW = \"yellow\",\n\tGREEN = \"green\",\n\tBLUE = \"blue\",\n\tPINK = \"pink\",\n\tORANGE = \"orange\",\n\tUNDERLINE = \"underline\",\n}\n\n/**\n * Annotation data\n */\nexport interface Annotation {\n\tid: string;\n\trange: Range;\n\ttype: HighlightType.ANNOTATION;\n\tcolor: HighlightColor;\n\ttimestamp: number;\n}\n\n/**\n * Configuration for HighlightCoordinator\n * Currently empty but allows future extension without breaking changes\n */\nexport type HighlightCoordinatorConfig = Record<string, never>;\n\nexport class HighlightCoordinator implements HighlightCoordinatorApi {\n\tprivate config: HighlightCoordinatorConfig;\n\tprivate ttsWordHighlight: Highlight | null = null;\n\tprivate ttsSentenceHighlight: Highlight | null = null;\n\tprivate ttsWordElementHighlights = new Set<Element>();\n\tprivate ttsSentenceElementHighlights = new Set<Element>();\n\tprivate annotations = new Map<string, Annotation>();\n\t// Shared highlights per color (one Highlight object per color, contains all ranges)\n\tprivate colorHighlights = new Map<HighlightColor, Highlight>();\n\tprivate nextAnnotationId = 1;\n\tprivate supported = false;\n\tprivate rangeSerializer: RangeSerializer;\n\tprivate themeObserver: MutationObserver | null = null;\n\tprivate explicitTTSColorOverride: { color: string; opacity: number } | null =\n\t\tnull;\n\n\tconstructor(config: HighlightCoordinatorConfig = {}) {\n\t\tthis.config = config;\n\t\tthis.rangeSerializer = new RangeSerializer();\n\n\t\t// SSR guard\n\t\tif (typeof CSS === \"undefined\" || !(\"highlights\" in CSS)) {\n\t\t\tconsole.warn(\n\t\t\t\t\"CSS Custom Highlight API not supported (SSR or unsupported browser)\",\n\t\t\t);\n\t\t\treturn;\n\t\t}\n\n\t\tthis.supported = true;\n\t\tthis.initializeHighlights();\n\t\tthis.registerStyles();\n\t\tthis.applyAdaptiveTTSStyle();\n\t\tthis.setupThemeObservation();\n\t}\n\n\tprivate setupThemeObservation(): void {\n\t\tif (typeof document === \"undefined\") return;\n\t\tif (typeof MutationObserver === \"undefined\") return;\n\n\t\tconst refresh = () => this.applyAdaptiveTTSStyle();\n\t\tthis.themeObserver = new MutationObserver(refresh);\n\n\t\tthis.themeObserver.observe(document.documentElement, {\n\t\t\tattributes: true,\n\t\t\tattributeFilter: [\"style\", \"data-theme\", \"data-color-scheme\", \"class\"],\n\t\t});\n\n\t\tfor (const host of document.querySelectorAll(\"pie-theme\")) {\n\t\t\tthis.themeObserver.observe(host, {\n\t\t\t\tattributes: true,\n\t\t\t\tattributeFilter: [\n\t\t\t\t\t\"theme\",\n\t\t\t\t\t\"scheme\",\n\t\t\t\t\t\"provider\",\n\t\t\t\t\t\"variables\",\n\t\t\t\t\t\"style\",\n\t\t\t\t\t\"data-theme\",\n\t\t\t\t\t\"data-color-scheme\",\n\t\t\t\t],\n\t\t\t});\n\t\t}\n\t}\n\n\tprivate parseColor(\n\t\tinput: string | null | undefined,\n\t): [number, number, number] | null {\n\t\tif (!input) return null;\n\t\tconst value = input.trim();\n\t\tif (!value) return null;\n\n\t\tconst hexMatch = /^#([a-f\\d]{3}|[a-f\\d]{6})$/i.exec(value);\n\t\tif (hexMatch) {\n\t\t\tconst hex = hexMatch[1];\n\t\t\tif (hex.length === 3) {\n\t\t\t\treturn [\n\t\t\t\t\tparseInt(hex[0] + hex[0], 16),\n\t\t\t\t\tparseInt(hex[1] + hex[1], 16),\n\t\t\t\t\tparseInt(hex[2] + hex[2], 16),\n\t\t\t\t];\n\t\t\t}\n\t\t\treturn [\n\t\t\t\tparseInt(hex.slice(0, 2), 16),\n\t\t\t\tparseInt(hex.slice(2, 4), 16),\n\t\t\t\tparseInt(hex.slice(4, 6), 16),\n\t\t\t];\n\t\t}\n\n\t\tconst rgbMatch = /^rgba?\\((.+)\\)$/i.exec(value);\n\t\tif (rgbMatch) {\n\t\t\tconst normalized = rgbMatch[1].replace(/\\//g, \",\");\n\t\t\tconst parts = normalized\n\t\t\t\t.split(/[,\\s]+/)\n\t\t\t\t.map((part) => part.trim())\n\t\t\t\t.filter(Boolean);\n\t\t\tconst r = Number(parts[0]);\n\t\t\tconst g = Number(parts[1]);\n\t\t\tconst b = Number(parts[2]);\n\t\t\tif (Number.isFinite(r) && Number.isFinite(g) && Number.isFinite(b)) {\n\t\t\t\treturn [r, g, b];\n\t\t\t}\n\t\t}\n\n\t\t// Browser parser fallback (covers formats like oklch()).\n\t\tif (typeof document !== \"undefined\") {\n\t\t\tconst parserEl = document.createElement(\"span\");\n\t\t\tparserEl.style.color = value;\n\t\t\tif (typeof parserEl.style.color === \"string\" && parserEl.style.color) {\n\t\t\t\tdocument.body?.appendChild(parserEl);\n\t\t\t\tconst resolved =\n\t\t\t\t\ttypeof getComputedStyle === \"function\"\n\t\t\t\t\t\t? getComputedStyle(parserEl).color\n\t\t\t\t\t\t: \"\";\n\t\t\t\tparserEl.remove();\n\t\t\t\tconst normalizedResolved = resolved.trim();\n\t\t\t\t// Guard against recursive loops when computed style returns the same\n\t\t\t\t// unresolved function syntax (observed with certain color formats).\n\t\t\t\tif (normalizedResolved && normalizedResolved !== value) {\n\t\t\t\t\treturn this.parseColor(resolved);\n\t\t\t\t}\n\t\t\t}\n\t\t}\n\n\t\treturn null;\n\t}\n\n\tprivate relativeLuminance([r, g, b]: [number, number, number]): number {\n\t\tconst toLinear = (channel: number) => {\n\t\t\tconst n = channel / 255;\n\t\t\treturn n <= 0.03928 ? n / 12.92 : ((n + 0.055) / 1.055) ** 2.4;\n\t\t};\n\t\tconst lr = toLinear(r);\n\t\tconst lg = toLinear(g);\n\t\tconst lb = toLinear(b);\n\t\treturn 0.2126 * lr + 0.7152 * lg + 0.0722 * lb;\n\t}\n\n\tprivate contrastRatio(\n\t\ta: [number, number, number],\n\t\tb: [number, number, number],\n\t): number {\n\t\tconst la = this.relativeLuminance(a);\n\t\tconst lb = this.relativeLuminance(b);\n\t\tconst lighter = Math.max(la, lb);\n\t\tconst darker = Math.min(la, lb);\n\t\treturn (lighter + 0.05) / (darker + 0.05);\n\t}\n\n\tprivate blend(\n\t\tfg: [number, number, number],\n\t\tbg: [number, number, number],\n\t\talpha: number,\n\t): [number, number, number] {\n\t\treturn [\n\t\t\tMath.round(fg[0] * alpha + bg[0] * (1 - alpha)),\n\t\t\tMath.round(fg[1] * alpha + bg[1] * (1 - alpha)),\n\t\t\tMath.round(fg[2] * alpha + bg[2] * (1 - alpha)),\n\t\t];\n\t}\n\n\tprivate resolveAdaptiveTTSStyle(sourceEl?: Element | null): {\n\t\twordHighlight: string;\n\t\tsentenceHighlight: string;\n\t\twordUnderline: string;\n\t\twordShadow: string;\n\t} {\n\t\tconst fallbackMissing: [number, number, number] = [255, 235, 59];\n\t\tconst fallbackText: [number, number, number] = [17, 24, 39];\n\t\tconst fallbackBackground: [number, number, number] = [255, 255, 255];\n\n\t\tconst target =\n\t\t\tsourceEl ||\n\t\t\t(typeof document !== \"undefined\" ? document.documentElement : null);\n\t\tconst computed =\n\t\t\ttarget && typeof getComputedStyle === \"function\"\n\t\t\t\t? getComputedStyle(target)\n\t\t\t\t: null;\n\n\t\tconst background =\n\t\t\tthis.parseColor(\n\t\t\t\tcomputed?.getPropertyValue(\"--pie-background\") ||\n\t\t\t\t\tcomputed?.backgroundColor,\n\t\t\t) || fallbackBackground;\n\t\tconst text =\n\t\t\tthis.parseColor(computed?.getPropertyValue(\"--pie-text\")) || fallbackText;\n\t\tconst accent = this.explicitTTSColorOverride\n\t\t\t? this.parseColor(this.explicitTTSColorOverride.color) || fallbackMissing\n\t\t\t: this.parseColor(computed?.getPropertyValue(\"--pie-missing\")) ||\n\t\t\t\tfallbackMissing;\n\n\t\tconst opacityCandidates = this.explicitTTSColorOverride\n\t\t\t? [Math.max(0.3, Math.min(0.95, this.explicitTTSColorOverride.opacity))]\n\t\t\t: [0.8, 0.72, 0.68, 0.62, 0.56, 0.5];\n\n\t\tlet selectedOpacity = opacityCandidates[opacityCandidates.length - 1];\n\t\tlet bestScore = -Infinity;\n\n\t\tfor (const opacity of opacityCandidates) {\n\t\t\tconst blended = this.blend(accent, background, opacity);\n\t\t\tconst backgroundDelta = this.contrastRatio(blended, background);\n\t\t\tconst textContrast = this.contrastRatio(blended, text);\n\t\t\tconst score = backgroundDelta * 1.2 + textContrast * 0.8;\n\t\t\tif (backgroundDelta >= 1.25 && textContrast >= 2.4) {\n\t\t\t\tselectedOpacity = opacity;\n\t\t\t\tbreak;\n\t\t\t}\n\t\t\tif (score > bestScore) {\n\t\t\t\tbestScore = score;\n\t\t\t\tselectedOpacity = opacity;\n\t\t\t}\n\t\t}\n\n\t\tconst sentenceOpacity = Math.max(\n\t\t\t0.24,\n\t\t\tMath.min(0.85, selectedOpacity * 0.55),\n\t\t);\n\t\tconst underlineOpacity = Math.max(\n\t\t\t0.55,\n\t\t\tMath.min(0.95, selectedOpacity + 0.2),\n\t\t);\n\t\tconst shadowOpacity = Math.max(0.22, Math.min(0.6, selectedOpacity * 0.45));\n\n\t\tconst underlineColor = text;\n\t\tconst underlineBlend = this.blend(\n\t\t\tunderlineColor,\n\t\t\tbackground,\n\t\t\tunderlineOpacity,\n\t\t);\n\t\tconst underlineDelta = this.contrastRatio(underlineBlend, background);\n\t\tconst fallbackUnderline: [number, number, number] =\n\t\t\tthis.relativeLuminance(background) > 0.45 ? [0, 0, 0] : [255, 255, 255];\n\t\tconst finalUnderline =\n\t\t\tunderlineDelta >= 1.35 ? underlineColor : fallbackUnderline;\n\n\t\tconst wordHighlight = `rgba(${accent[0]}, ${accent[1]}, ${accent[2]}, ${selectedOpacity})`;\n\t\tconst sentenceHighlight = `rgba(${accent[0]}, ${accent[1]}, ${accent[2]}, ${sentenceOpacity})`;\n\t\tconst wordUnderline = `rgba(${finalUnderline[0]}, ${finalUnderline[1]}, ${finalUnderline[2]}, ${underlineOpacity})`;\n\t\tconst wordShadow = `rgba(${finalUnderline[0]}, ${finalUnderline[1]}, ${finalUnderline[2]}, ${shadowOpacity})`;\n\n\t\treturn {\n\t\t\twordHighlight,\n\t\t\tsentenceHighlight,\n\t\t\twordUnderline,\n\t\t\twordShadow,\n\t\t};\n\t}\n\n\tprivate applyAdaptiveTTSStyle(sourceEl?: Element | null): void {\n\t\tif (typeof document === \"undefined\") return;\n\t\tconst vars = this.resolveAdaptiveTTSStyle(sourceEl);\n\t\tdocument.documentElement.style.setProperty(\n\t\t\t\"--pie-tts-word-highlight\",\n\t\t\tvars.wordHighlight,\n\t\t);\n\t\tdocument.documentElement.style.setProperty(\n\t\t\t\"--pie-tts-sentence-highlight\",\n\t\t\tvars.sentenceHighlight,\n\t\t);\n\t\tdocument.documentElement.style.setProperty(\n\t\t\t\"--pie-tts-line-highlight\",\n\t\t\tvars.sentenceHighlight,\n\t\t);\n\t\tdocument.documentElement.style.setProperty(\n\t\t\t\"--pie-tts-word-underline\",\n\t\t\tvars.wordUnderline,\n\t\t);\n\t\tdocument.documentElement.style.setProperty(\n\t\t\t\"--pie-tts-word-shadow\",\n\t\t\tvars.wordShadow,\n\t\t);\n\t}\n\n\t/**\n\t * Initialize CSS Custom Highlights\n\t */\n\tprivate initializeHighlights(): void {\n\t\tif (!this.supported) return;\n\n\t\t// Create highlight registries for TTS\n\t\tthis.ttsWordHighlight = new Highlight();\n\t\tthis.ttsSentenceHighlight = new Highlight();\n\n\t\t// Register TTS highlights with CSS\n\t\tCSS.highlights.set(\"tts-word\", this.ttsWordHighlight);\n\t\tCSS.highlights.set(\"tts-sentence\", this.ttsSentenceHighlight);\n\n\t\t// Create shared highlights for each annotation color\n\t\tfor (const color of Object.values(HighlightColor)) {\n\t\t\tconst highlight = new Highlight();\n\t\t\tthis.colorHighlights.set(color, highlight);\n\t\t\tCSS.highlights.set(`annotation-${color}`, highlight);\n\t\t}\n\t}\n\n\t/**\n\t * Register CSS styles for highlights\n\t */\n\tprivate registerStyles(): void {\n\t\tif (!this.supported) return;\n\t\tif (typeof document === \"undefined\") return; // SSR guard\n\n\t\t// Check if styles already exist\n\t\tif (document.getElementById(\"pie-highlight-styles\")) return;\n\n\t\tconst style = document.createElement(\"style\");\n\t\tstyle.id = \"pie-highlight-styles\";\n\t\tstyle.textContent = `\n /* TTS highlights - temporary */\n ::highlight(tts-word) {\n background-color: var(--pie-tts-word-highlight, color-mix(in srgb, var(--pie-missing, #ffeb3b) 68%, transparent));\n text-decoration: underline 2px solid var(--pie-tts-word-underline, color-mix(in srgb, var(--pie-text, #111827) 70%, transparent));\n text-underline-offset: 2px;\n text-shadow: 0 0 1px var(--pie-tts-word-shadow, color-mix(in srgb, var(--pie-text, #111827) 35%, transparent));\n color: inherit;\n }\n\n /* tts-sentence registry id: coarse read-along band (visual line boxes in layout) */\n ::highlight(tts-sentence) {\n background-color: var(--pie-tts-line-highlight, var(--pie-tts-sentence-highlight, color-mix(in srgb, var(--pie-missing, #ffeb3b) 38%, transparent)));\n color: inherit;\n }\n\n [data-pie-tts-sentence-element=\"true\"] {\n background-color: var(--pie-tts-line-highlight, var(--pie-tts-sentence-highlight, color-mix(in srgb, var(--pie-missing, #ffeb3b) 38%, transparent)));\n border-radius: 0.12em;\n box-decoration-break: clone;\n -webkit-box-decoration-break: clone;\n }\n\n [data-pie-tts-word-element=\"true\"] {\n background-color: var(--pie-tts-word-highlight, color-mix(in srgb, var(--pie-missing, #ffeb3b) 68%, transparent));\n text-decoration: underline 2px solid var(--pie-tts-word-underline, color-mix(in srgb, var(--pie-text, #111827) 70%, transparent));\n text-underline-offset: 2px;\n text-shadow: 0 0 1px var(--pie-tts-word-shadow, color-mix(in srgb, var(--pie-text, #111827) 35%, transparent));\n border-bottom: 2px solid var(--pie-tts-word-underline, color-mix(in srgb, var(--pie-text, #111827) 70%, transparent));\n padding-bottom: 1px;\n border-radius: 0.12em;\n box-decoration-break: clone;\n -webkit-box-decoration-break: clone;\n }\n\n /* Annotation highlights - persistent */\n ::highlight(annotation-yellow) {\n background-color: color-mix(in srgb, var(--pie-missing, #ffff00) 35%, transparent);\n color: inherit;\n }\n\n ::highlight(annotation-green) {\n background-color: color-mix(in srgb, var(--pie-correct, #90ee90) 35%, transparent);\n color: inherit;\n }\n\n ::highlight(annotation-blue) {\n background-color: color-mix(in srgb, var(--pie-tertiary, #add8e6) 35%, transparent);\n color: inherit;\n }\n\n ::highlight(annotation-pink) {\n background-color: color-mix(in srgb, var(--pie-secondary-light, #ffb6c1) 35%, transparent);\n color: inherit;\n }\n\n ::highlight(annotation-orange) {\n background-color: color-mix(in srgb, var(--pie-incorrect, #ffa500) 35%, transparent);\n color: inherit;\n }\n\n ::highlight(annotation-underline) {\n background-color: transparent;\n text-decoration: underline 2px solid var(--pie-primary, #0066cc);\n text-underline-offset: 2px;\n color: inherit;\n }\n `;\n\t\tdocument.head.appendChild(style);\n\t}\n\n\t/**\n\t * Highlight a word for TTS (temporary)\n\t *\n\t * @param textNode Text node containing the word\n\t * @param startOffset Start position in text node\n\t * @param endOffset End position in text node\n\t */\n\thighlightTTSWord(\n\t\ttextNode: Text,\n\t\tstartOffset: number,\n\t\tendOffset: number,\n\t): void {\n\t\tif (!this.ttsWordHighlight) return;\n\t\tthis.applyAdaptiveTTSStyle(textNode.parentElement);\n\n\t\t// Clear previous word highlight\n\t\tthis.clearTTSWord();\n\n\t\t// Create range for word\n\t\tconst range = document.createRange();\n\t\trange.setStart(textNode, startOffset);\n\t\trange.setEnd(textNode, endOffset);\n\n\t\t// Add to highlight\n\t\tthis.ttsWordHighlight.add(range);\n\t}\n\n\t/**\n\t * Highlight a single element as the active TTS word (temporary).\n\t *\n\t * Unlike {@link highlightTTSWord} (which paints a CSS range over a text node)\n\t * this marks the element itself via `data-pie-tts-word-element`. It is used\n\t * for atomic targets that have no direct text node to range over — most\n\t * notably MathJax CHTML tokens (e.g. `<mjx-mi><mjx-c/></mjx-mi>`, whose glyph\n\t * lives in a font-driven pseudo-element a CSS range cannot paint) and\n\t * whole-expression fallbacks.\n\t *\n\t * The supplied element is painted exactly; we deliberately do NOT walk up to\n\t * a containing `<math>` / `<mjx-container>`. That escalation is what made\n\t * MathJax-rendered math highlight as a full block while native MathML tracked\n\t * per-token: a resolved single token must paint as a token, and only a\n\t * genuine expression fallback (where the element already is the container)\n\t * should paint the whole expression.\n\t */\n\thighlightTTSWordElement(element: Element): void {\n\t\tif (!this.ttsWordHighlight) return;\n\t\tthis.applyAdaptiveTTSStyle(element);\n\n\t\t// Clear previous word highlight (CSS range and any element attributes)\n\t\tthis.clearTTSWord();\n\n\t\telement.setAttribute(\"data-pie-tts-word-element\", \"true\");\n\t\tthis.ttsWordElementHighlights.add(element);\n\t}\n\n\t/**\n\t * Highlight the coarse TTS read-along band (temporary).\n\t * Usually one Range per visual line; CSS layer `tts-sentence` for compatibility.\n\t *\n\t * @param ranges Line (or sentence) ranges to paint with `--pie-tts-line-highlight`\n\t */\n\thighlightTTSSentence(ranges: Range[]): void {\n\t\tif (!this.ttsSentenceHighlight) return;\n\t\tconst source = ranges[0]?.startContainer;\n\t\tconst sourceElement =\n\t\t\tsource?.nodeType === Node.ELEMENT_NODE\n\t\t\t\t? (source as Element)\n\t\t\t\t: source?.parentElement;\n\t\tthis.applyAdaptiveTTSStyle(sourceElement);\n\n\t\t// Clear previous sentence highlight\n\t\tthis.clearTTSSentence();\n\n\t\t// Add all ranges\n\t\tfor (const range of ranges) {\n\t\t\tthis.ttsSentenceHighlight.add(range);\n\t\t}\n\t\tthis.highlightTTSElementFallbacks(ranges);\n\t}\n\n\t// The read-along (sentence) band legitimately covers whole equations and\n\t// replaced elements, so it escalates to them.\n\tprivate static readonly SENTENCE_FALLBACK_SELECTOR =\n\t\t\"math, mjx-container, svg, img, canvas, [role='img']\";\n\n\t// The word layer must NOT escalate a multi-node range to the enclosing\n\t// `<math>` / `<mjx-container>`: that is what made an equation flash as a\n\t// whole block whenever a spoken word's visible range crossed several math\n\t// glyph nodes. Math is tracked per token (or held / region) by the highlight\n\t// pipeline instead. Replaced elements (svg/img/canvas) still need the element\n\t// fallback because a CSS range cannot paint them.\n\tprivate static readonly WORD_FALLBACK_SELECTOR =\n\t\t\"svg, img, canvas, [role='img']\";\n\n\tprivate highlightTTSElementFallbacks(ranges: Range[]): void {\n\t\tif (typeof Element === \"undefined\") return;\n\t\tthis.highlightElementFallbacks(\n\t\t\tranges,\n\t\t\t\"data-pie-tts-sentence-element\",\n\t\t\tthis.ttsSentenceElementHighlights,\n\t\t\tHighlightCoordinator.SENTENCE_FALLBACK_SELECTOR,\n\t\t);\n\t}\n\n\tprivate highlightTTSWordElementFallbacks(ranges: Range[]): void {\n\t\tif (typeof Element === \"undefined\") return;\n\t\tthis.highlightElementFallbacks(\n\t\t\tranges,\n\t\t\t\"data-pie-tts-word-element\",\n\t\t\tthis.ttsWordElementHighlights,\n\t\t\tHighlightCoordinator.WORD_FALLBACK_SELECTOR,\n\t\t);\n\t}\n\n\tprivate highlightElementFallbacks(\n\t\tranges: Range[],\n\t\tattributeName: string,\n\t\ttrackedElements: Set<Element>,\n\t\tselector: string,\n\t): void {\n\t\tfor (const range of ranges) {\n\t\t\tconst root =\n\t\t\t\trange.commonAncestorContainer.nodeType === Node.ELEMENT_NODE\n\t\t\t\t\t? (range.commonAncestorContainer as Element)\n\t\t\t\t\t: range.commonAncestorContainer.parentElement;\n\t\t\tif (!root) continue;\n\t\t\tconst candidates: Element[] = [];\n\t\t\tconst rangeStartElement =\n\t\t\t\trange.startContainer.nodeType === Node.ELEMENT_NODE\n\t\t\t\t\t? (range.startContainer as Element)\n\t\t\t\t\t: range.startContainer.parentElement;\n\t\t\tconst rangeEndElement =\n\t\t\t\trange.endContainer.nodeType === Node.ELEMENT_NODE\n\t\t\t\t\t? (range.endContainer as Element)\n\t\t\t\t\t: range.endContainer.parentElement;\n\t\t\tfor (const element of [rangeStartElement, rangeEndElement]) {\n\t\t\t\tlet current: Element | null = element;\n\t\t\t\twhile (current) {\n\t\t\t\t\tif (current.matches?.(selector)) candidates.push(current);\n\t\t\t\t\tcurrent = current.parentElement;\n\t\t\t\t}\n\t\t\t}\n\t\t\tif (root.matches?.(selector)) {\n\t\t\t\tcandidates.push(root);\n\t\t\t}\n\t\t\tcandidates.push(...Array.from(root.querySelectorAll(selector)));\n\t\t\tfor (const element of new Set(candidates)) {\n\t\t\t\ttry {\n\t\t\t\t\tif (\n\t\t\t\t\t\t!range.intersectsNode(element) &&\n\t\t\t\t\t\t!element.contains(rangeStartElement) &&\n\t\t\t\t\t\t!element.contains(rangeEndElement)\n\t\t\t\t\t) {\n\t\t\t\t\t\tcontinue;\n\t\t\t\t\t}\n\t\t\t\t} catch {\n\t\t\t\t\tcontinue;\n\t\t\t\t}\n\t\t\t\telement.setAttribute(attributeName, \"true\");\n\t\t\t\ttrackedElements.add(element);\n\t\t\t}\n\t\t}\n\t}\n\n\t/**\n\t * Clear TTS word highlight\n\t */\n\tclearTTSWord(): void {\n\t\tif (!this.ttsWordHighlight) return;\n\t\tthis.ttsWordHighlight.clear();\n\t\tfor (const element of this.ttsWordElementHighlights) {\n\t\t\telement.removeAttribute(\"data-pie-tts-word-element\");\n\t\t}\n\t\tthis.ttsWordElementHighlights.clear();\n\t}\n\n\t/**\n\t * Clear TTS sentence highlight\n\t */\n\tclearTTSSentence(): void {\n\t\tif (!this.ttsSentenceHighlight) return;\n\t\tthis.ttsSentenceHighlight.clear();\n\t\tfor (const element of this.ttsSentenceElementHighlights) {\n\t\t\telement.removeAttribute(\"data-pie-tts-sentence-element\");\n\t\t}\n\t\tthis.ttsSentenceElementHighlights.clear();\n\t}\n\n\t/**\n\t * Clear all TTS highlights\n\t */\n\tclearTTS(): void {\n\t\tthis.clearTTSWord();\n\t\tthis.clearTTSSentence();\n\t}\n\n\t/**\n\t * Add an annotation highlight (persistent)\n\t *\n\t * @param range Text range to annotate\n\t * @param color Highlight color\n\t * @returns Annotation ID for later removal\n\t */\n\taddAnnotation(\n\t\trange: Range,\n\t\tcolor: HighlightColor = HighlightColor.YELLOW,\n\t): string {\n\t\tconst id = `annotation-${this.nextAnnotationId++}`;\n\n\t\t// Clone the range to store\n\t\tconst clonedRange = range.cloneRange();\n\n\t\t// Store annotation data\n\t\tconst annotation: Annotation = {\n\t\t\tid,\n\t\t\trange: clonedRange,\n\t\t\ttype: HighlightType.ANNOTATION,\n\t\t\tcolor,\n\t\t\ttimestamp: Date.now(),\n\t\t};\n\t\tthis.annotations.set(id, annotation);\n\n\t\t// Add the SAME range object to the shared color highlight\n\t\t// This ensures we can later delete it by reference\n\t\tconst colorHighlight = this.colorHighlights.get(color);\n\t\tif (colorHighlight) {\n\t\t\tcolorHighlight.add(clonedRange);\n\t\t}\n\n\t\treturn id;\n\t}\n\n\t/**\n\t * Remove an annotation\n\t *\n\t * @param id Annotation ID\n\t */\n\tremoveAnnotation(id: string): void {\n\t\tconst annotation = this.annotations.get(id);\n\t\tif (!annotation) {\n\t\t\tconsole.warn(`[HighlightCoordinator] Annotation ${id} not found`);\n\t\t\treturn;\n\t\t}\n\n\t\tconsole.log(\n\t\t\t`[HighlightCoordinator] Removing annotation ${id} (color: ${annotation.color})`,\n\t\t);\n\n\t\t// Remove range from the shared color highlight\n\t\tconst colorHighlight = this.colorHighlights.get(annotation.color);\n\t\tif (colorHighlight) {\n\t\t\tconst deleted = colorHighlight.delete(annotation.range);\n\t\t\tconsole.log(\n\t\t\t\t`[HighlightCoordinator] Highlight.delete() returned:`,\n\t\t\t\tdeleted,\n\t\t\t);\n\t\t}\n\n\t\t// Clean up\n\t\tthis.annotations.delete(id);\n\t\tconsole.log(\n\t\t\t`[HighlightCoordinator] Annotation ${id} removed from map. Remaining:`,\n\t\t\tthis.annotations.size,\n\t\t);\n\t}\n\n\t/**\n\t * Remove all annotations\n\t */\n\tclearAnnotations(): void {\n\t\t// Clear all color highlights\n\t\tfor (const colorHighlight of this.colorHighlights.values()) {\n\t\t\tcolorHighlight.clear();\n\t\t}\n\n\t\t// Clear annotation data\n\t\tthis.annotations.clear();\n\t}\n\n\t/**\n\t * Get all annotations\n\t */\n\tgetAnnotations(): Annotation[] {\n\t\treturn Array.from(this.annotations.values());\n\t}\n\n\t/**\n\t * Get annotation by ID\n\t */\n\tgetAnnotation(id: string): Annotation | null {\n\t\treturn this.annotations.get(id) ?? null;\n\t}\n\n\t/**\n\t * Change annotation color\n\t *\n\t * @param id Annotation ID\n\t * @param newColor New color\n\t */\n\tchangeAnnotationColor(id: string, newColor: HighlightColor): void {\n\t\tconst annotation = this.annotations.get(id);\n\t\tif (!annotation) return;\n\n\t\tconst oldColor = annotation.color;\n\t\tif (oldColor === newColor) return;\n\n\t\t// Remove from old color highlight\n\t\tconst oldColorHighlight = this.colorHighlights.get(oldColor);\n\t\tif (oldColorHighlight) {\n\t\t\toldColorHighlight.delete(annotation.range);\n\t\t}\n\n\t\t// Update color\n\t\tannotation.color = newColor;\n\n\t\t// Add to new color highlight\n\t\tconst newColorHighlight = this.colorHighlights.get(newColor);\n\t\tif (newColorHighlight) {\n\t\t\tnewColorHighlight.add(annotation.range);\n\t\t}\n\t}\n\n\t/**\n\t * Export annotations as serializable data for persistence.\n\t * Uses RangeSerializer for robust DOM range serialization.\n\t *\n\t * @param root Root element for serialization (typically document.body or content container)\n\t * @returns Array of serialized annotations\n\t */\n\texportAnnotations(\n\t\troot: Element = document.body,\n\t): Array<\n\t\tSerializedRange & { id: string; color: HighlightColor; timestamp: number }\n\t> {\n\t\treturn this.getAnnotations().map((annotation) => ({\n\t\t\t...this.rangeSerializer.serialize(annotation.range, root),\n\t\t\tid: annotation.id,\n\t\t\tcolor: annotation.color,\n\t\t\ttimestamp: annotation.timestamp,\n\t\t}));\n\t}\n\n\t/**\n\t * Import annotations from serialized data.\n\t * Restores annotations after page navigation or refresh.\n\t *\n\t * @param data Array of serialized annotations\n\t * @param root Root element for deserialization (same as used in export)\n\t * @returns Number of successfully restored annotations\n\t */\n\timportAnnotations(\n\t\tdata: Array<\n\t\t\tSerializedRange & {\n\t\t\t\tid?: string;\n\t\t\t\tcolor: HighlightColor;\n\t\t\t\ttimestamp?: number;\n\t\t\t}\n\t\t>,\n\t\troot: Element = document.body,\n\t): number {\n\t\tlet restored = 0;\n\n\t\tfor (const item of data) {\n\t\t\tconst range = this.rangeSerializer.deserialize(item, root);\n\t\t\tif (range) {\n\t\t\t\tthis.addAnnotation(range, item.color);\n\t\t\t\trestored++;\n\t\t\t}\n\t\t}\n\n\t\treturn restored;\n\t}\n\n\t// ============================================================================\n\t// HighlightCoordinatorApi interface implementation\n\t// ============================================================================\n\n\t/**\n\t * Highlight a text range (interface method)\n\t *\n\t * Generic method that adapts to the specific highlight type.\n\t * For more control, use the specific methods like highlightTTSWord().\n\t */\n\thighlightRange(\n\t\trange: Range,\n\t\ttype: HighlightType,\n\t\tcolor: HighlightColor = HighlightColor.YELLOW,\n\t): void {\n\t\tif (!this.supported) return;\n\n\t\tswitch (type) {\n\t\t\tcase HighlightType.TTS_WORD:\n\t\t\tcase HighlightType.TTS_SENTENCE: {\n\t\t\t\t// For TTS, add to appropriate highlight\n\t\t\t\tconst highlight =\n\t\t\t\t\ttype === HighlightType.TTS_WORD\n\t\t\t\t\t\t? this.ttsWordHighlight\n\t\t\t\t\t\t: this.ttsSentenceHighlight;\n\t\t\t\tif (highlight) {\n\t\t\t\t\thighlight.clear();\n\t\t\t\t\thighlight.add(range);\n\t\t\t\t\tif (type === HighlightType.TTS_WORD) {\n\t\t\t\t\t\tfor (const element of this.ttsWordElementHighlights) {\n\t\t\t\t\t\t\telement.removeAttribute(\"data-pie-tts-word-element\");\n\t\t\t\t\t\t}\n\t\t\t\t\t\tthis.ttsWordElementHighlights.clear();\n\t\t\t\t\t\tthis.highlightTTSWordElementFallbacks([range]);\n\t\t\t\t\t}\n\t\t\t\t}\n\t\t\t\tbreak;\n\t\t\t}\n\t\t\tcase HighlightType.ANNOTATION:\n\t\t\t\t// For annotations, use the existing method\n\t\t\t\tthis.addAnnotation(range, color);\n\t\t\t\tbreak;\n\t\t}\n\t}\n\n\t/**\n\t * Clear highlights of a specific type (interface method)\n\t */\n\tclearHighlights(type: HighlightType): void {\n\t\tif (!this.supported) return;\n\n\t\tswitch (type) {\n\t\t\tcase HighlightType.TTS_WORD:\n\t\t\t\tthis.clearTTSWord();\n\t\t\t\tbreak;\n\t\t\tcase HighlightType.TTS_SENTENCE:\n\t\t\t\tthis.clearTTSSentence();\n\t\t\t\tbreak;\n\t\t\tcase HighlightType.ANNOTATION:\n\t\t\t\tthis.clearAnnotations();\n\t\t\t\tbreak;\n\t\t}\n\t}\n\n\t/**\n\t * Clear all highlights (interface method)\n\t */\n\tclearAll(): void {\n\t\tif (!this.supported) return;\n\t\tthis.clearTTS();\n\t\tthis.clearAnnotations();\n\t}\n\n\t/**\n\t * Check if CSS Highlight API is supported (interface method)\n\t */\n\tisSupported(): boolean {\n\t\treturn this.supported;\n\t}\n\n\t/**\n\t * Update TTS highlight style dynamically\n\t *\n\t * @param color CSS color value (e.g., '#ffeb3b')\n\t * @param opacity Opacity value (0.0 to 1.0)\n\t */\n\tupdateTTSHighlightStyle(color: string, opacity: number): void {\n\t\tif (!this.supported) return;\n\t\tif (typeof document === \"undefined\") return;\n\n\t\tconst styleEl = document.getElementById(\"pie-highlight-styles\");\n\t\tif (!styleEl) return;\n\n\t\t// Convert hex to rgba\n\t\tconst hexToRgb = (hex: string) => {\n\t\t\tconst result = /^#?([a-f\\d]{2})([a-f\\d]{2})([a-f\\d]{2})$/i.exec(hex);\n\t\t\treturn result\n\t\t\t\t? {\n\t\t\t\t\t\tr: parseInt(result[1], 16),\n\t\t\t\t\t\tg: parseInt(result[2], 16),\n\t\t\t\t\t\tb: parseInt(result[3], 16),\n\t\t\t\t\t}\n\t\t\t\t: null;\n\t\t};\n\n\t\tconst rgb = hexToRgb(color);\n\t\tif (!rgb) return;\n\n\t\tthis.explicitTTSColorOverride = {\n\t\t\tcolor: `rgb(${rgb.r}, ${rgb.g}, ${rgb.b})`,\n\t\t\topacity: Math.max(0.2, Math.min(0.95, opacity)),\n\t\t};\n\t\tthis.applyAdaptiveTTSStyle();\n\t}\n\n\t/**\n\t * Cleanup - remove all highlights\n\t */\n\tdestroy(): void {\n\t\tif (!this.supported) return;\n\n\t\tthis.clearTTS();\n\t\tthis.clearAnnotations();\n\n\t\t// Remove style element\n\t\tif (typeof document !== \"undefined\") {\n\t\t\tconst styleEl = document.getElementById(\"pie-highlight-styles\");\n\t\t\tif (styleEl) {\n\t\t\t\tstyleEl.remove();\n\t\t\t}\n\t\t}\n\t\tthis.themeObserver?.disconnect();\n\t\tthis.themeObserver = null;\n\t}\n}\n"]}
|
|
@@ -15,7 +15,7 @@
|
|
|
15
15
|
* Part of PIE Assessment Toolkit.
|
|
16
16
|
*/
|
|
17
17
|
import type { I18nConfig, I18nServiceApi, PluralTranslation, TranslationBundle } from "@pie-players/pie-players-shared/i18n";
|
|
18
|
-
export type { I18nConfig, I18nServiceApi, PluralTranslation, TranslationBundle };
|
|
18
|
+
export type { I18nConfig, I18nServiceApi, PluralTranslation, TranslationBundle, };
|
|
19
19
|
/**
|
|
20
20
|
* I18nService
|
|
21
21
|
*
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"I18nService.js","sourceRoot":"","sources":["../../src/services/I18nService.ts"],"names":[],"mappings":"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","sourcesContent":["/**\n * I18nService\n *\n * Internationalization service with hybrid loading strategy.\n * Manages translations, locale switching, and RTL/LTR direction.\n *\n * Features:\n * - Subscriber/listener pattern for reactive updates\n * - Hybrid loading: Bundle English, lazy-load other locales\n * - Interpolation: {variable} syntax\n * - Pluralization: ICU-style plural rules\n * - RTL detection: Automatic based on locale\n * - Fallback to English for missing keys\n *\n * Part of PIE Assessment Toolkit.\n */\n\nimport type {\n\tI18nConfig,\n\tI18nServiceApi,\n\tPluralTranslation,\n\tTranslationBundle,\n} from \"@pie-players/pie-players-shared/i18n\";\nimport { createLogger } from \"../utils/logger.js\";\n\nconst log = createLogger(\"I18nService\");\n\n// Re-export types for convenience\nexport type { I18nConfig, I18nServiceApi, PluralTranslation, TranslationBundle };\n\n/**\n * I18nService\n *\n * Manages internationalization with reactive state updates.\n */\nexport class I18nService implements I18nServiceApi {\n\tprivate locale: string = \"en\";\n\tprivate fallbackLocale: string = \"en\";\n\tprivate direction: \"ltr\" | \"rtl\" = \"ltr\";\n\tprivate translations = new Map<string, TranslationBundle>();\n\tprivate listeners = new Set<() => void>();\n\tprivate loadingPromises = new Map<string, Promise<void>>();\n\tprivate config: I18nConfig;\n\n\tconstructor(config: I18nConfig = {}) {\n\t\tthis.config = config;\n\t\tthis.fallbackLocale = config.fallbackLocale || \"en\";\n\n\t\tlog(\"I18nService initialized\", { fallbackLocale: this.fallbackLocale });\n\n\t\t// Load bundled translations (English by default)\n\t\tif (config.bundledTranslations) {\n\t\t\tfor (const [locale, bundle] of Object.entries(\n\t\t\t\tconfig.bundledTranslations,\n\t\t\t)) {\n\t\t\t\tthis.translations.set(locale, bundle);\n\t\t\t\tlog(`Loaded bundled translations for: ${locale}`);\n\t\t\t}\n\t\t}\n\t}\n\n\t/**\n\t * Initialize i18n with locale and loading strategy\n\t */\n\tasync initialize(config: I18nConfig): Promise<void> {\n\t\tObject.assign(this.config, config);\n\n\t\tconst locale = config.locale || this.detectBrowserLocale();\n\t\tlog(`Initializing with locale: ${locale}`);\n\n\t\tawait this.setLocale(locale);\n\t}\n\n\t/**\n\t * Translate a key with optional interpolation\n\t *\n\t * @param key Translation key (e.g., 'common.save')\n\t * @param params Optional parameters for interpolation\n\t * @returns Translated string\n\t */\n\tt(key: string, params?: Record<string, any>): string {\n\t\tconst translation = this.getTranslation(key);\n\t\treturn this.interpolate(translation as string, params);\n\t}\n\n\t/**\n\t * Translate with pluralization\n\t *\n\t * @param key Translation key\n\t * @param count Count for pluralization\n\t * @param params Optional parameters for interpolation\n\t * @returns Translated string with plural form\n\t */\n\ttn(key: string, count: number, params?: Record<string, any>): string {\n\t\tconst translation = this.getTranslation(key);\n\n\t\tif (typeof translation === \"object\") {\n\t\t\tconst pluralForm = this.selectPluralForm(count, this.locale);\n\t\t\tconst text = translation[pluralForm] || translation.other;\n\t\t\treturn this.interpolate(text, { ...params, count });\n\t\t}\n\n\t\treturn this.interpolate(translation as string, { ...params, count });\n\t}\n\n\t/**\n\t * Get current locale\n\t */\n\tgetLocale(): string {\n\t\treturn this.locale;\n\t}\n\n\t/**\n\t * Change locale (triggers async loading if needed)\n\t *\n\t * @param locale Locale code (e.g., 'en', 'es', 'zh', 'ar')\n\t */\n\tasync setLocale(locale: string): Promise<void> {\n\t\tlog(`Setting locale to: ${locale}`);\n\n\t\t// Check if already loading\n\t\tif (this.loadingPromises.has(locale)) {\n\t\t\tlog(`Locale ${locale} is already loading, waiting...`);\n\t\t\tawait this.loadingPromises.get(locale);\n\t\t\treturn;\n\t\t}\n\n\t\t// Check if already loaded\n\t\tif (this.translations.has(locale)) {\n\t\t\tlog(`Locale ${locale} already loaded`);\n\t\t\tthis.applyLocale(locale);\n\t\t\treturn;\n\t\t}\n\n\t\t// Load translations\n\t\tconst loadingPromise = this.loadTranslationsForLocale(locale);\n\t\tthis.loadingPromises.set(locale, loadingPromise);\n\n\t\ttry {\n\t\t\tawait loadingPromise;\n\t\t\tthis.applyLocale(locale);\n\t\t} finally {\n\t\t\tthis.loadingPromises.delete(locale);\n\t\t}\n\t}\n\n\t/**\n\t * Get current text direction\n\t */\n\tgetDirection(): \"ltr\" | \"rtl\" {\n\t\treturn this.direction;\n\t}\n\n\t/**\n\t * Get available locales\n\t */\n\tgetAvailableLocales(): string[] {\n\t\treturn Array.from(this.translations.keys());\n\t}\n\n\t/**\n\t * Check if locale is loaded\n\t */\n\tisLocaleLoaded(locale: string): boolean {\n\t\treturn this.translations.has(locale);\n\t}\n\n\t/**\n\t * Subscribe to locale/translation changes\n\t * Returns unsubscribe function\n\t */\n\tsubscribe(listener: () => void): () => void {\n\t\tthis.listeners.add(listener);\n\t\treturn () => {\n\t\t\tthis.listeners.delete(listener);\n\t\t};\n\t}\n\n\t/**\n\t * Check if a translation key exists\n\t */\n\thasKey(key: string): boolean {\n\t\tconst bundle = this.translations.get(this.locale);\n\t\treturn !!bundle?.translations[key];\n\t}\n\n\t/**\n\t * Notify all listeners of state change\n\t */\n\tprivate notifyListeners(): void {\n\t\tthis.listeners.forEach((listener) => listener());\n\t}\n\n\t/**\n\t * Apply locale and notify listeners\n\t */\n\tprivate applyLocale(locale: string): void {\n\t\tconst bundle = this.translations.get(locale);\n\t\tif (!bundle) {\n\t\t\tlog(`No bundle found for locale: ${locale}`, \"warn\");\n\t\t\treturn;\n\t\t}\n\n\t\tconst previousLocale = this.locale;\n\t\tthis.locale = locale;\n\t\tthis.direction = bundle.direction;\n\n\t\tlog(`Applied locale: ${locale} (direction: ${this.direction})`);\n\n\t\tthis.applyDOMDirection();\n\t\tthis.notifyListeners();\n\t}\n\n\t/**\n\t * Apply direction to DOM\n\t */\n\tprivate applyDOMDirection(): void {\n\t\tif (typeof document === \"undefined\") return;\n\n\t\tdocument.documentElement.setAttribute(\"dir\", this.direction);\n\t\tdocument.documentElement.setAttribute(\"lang\", this.locale);\n\n\t\tlog(\n\t\t\t`Applied DOM attributes: dir=\"${this.direction}\" lang=\"${this.locale}\"`,\n\t\t);\n\t}\n\n\t/**\n\t * Load translations for a locale\n\t */\n\tprivate async loadTranslationsForLocale(locale: string): Promise<void> {\n\t\tif (!this.config.loadTranslations) {\n\t\t\tthrow new Error(`No translation loader configured for locale: ${locale}`);\n\t\t}\n\n\t\tlog(`Loading translations for: ${locale}`);\n\n\t\ttry {\n\t\t\tconst bundle = await this.config.loadTranslations(locale);\n\t\t\tthis.translations.set(locale, bundle);\n\t\t\tlog(\n\t\t\t\t`Loaded translations for: ${locale} (${Object.keys(bundle.translations).length} keys)`,\n\t\t\t);\n\t\t} catch (error) {\n\t\t\tlog(`Failed to load translations for: ${locale}`, \"error\");\n\t\t\tthrow error;\n\t\t}\n\t}\n\n\t/**\n\t * Get translation for a key\n\t */\n\tprivate getTranslation(key: string): string | PluralTranslation {\n\t\t// Try current locale\n\t\tconst currentBundle = this.translations.get(this.locale);\n\t\tif (currentBundle?.translations[key]) {\n\t\t\treturn currentBundle.translations[key];\n\t\t}\n\n\t\t// Try fallback locale\n\t\tconst fallbackBundle = this.translations.get(this.fallbackLocale);\n\t\tif (fallbackBundle?.translations[key]) {\n\t\t\tif (this.config.debug) {\n\t\t\t\tlog(`Using fallback translation for key: ${key}`);\n\t\t\t}\n\t\t\treturn fallbackBundle.translations[key];\n\t\t}\n\n\t\t// Missing key handling\n\t\tif (this.config.onMissingKey) {\n\t\t\tthis.config.onMissingKey(key, this.locale);\n\t\t}\n\n\t\tif (this.config.debug) {\n\t\t\tlog(`Missing translation key: ${key} (locale: ${this.locale})`, \"warn\");\n\t\t}\n\n\t\treturn key;\n\t}\n\n\t/**\n\t * Interpolate variables in translation string\n\t * Replaces {variable} with params.variable\n\t */\n\tprivate interpolate(text: string, params?: Record<string, any>): string {\n\t\tif (!params) return text;\n\n\t\treturn text.replace(/\\{(\\w+)\\}/g, (match, key) => {\n\t\t\treturn params[key]?.toString() || match;\n\t\t});\n\t}\n\n\t/**\n\t * Select plural form based on count and locale\n\t * Simplified implementation - real implementation would use Intl.PluralRules\n\t */\n\tprivate selectPluralForm(\n\t\tcount: number,\n\t\tlocale: string,\n\t): keyof PluralTranslation {\n\t\t// Use Intl.PluralRules if available\n\t\tif (typeof Intl !== \"undefined\" && Intl.PluralRules) {\n\t\t\ttry {\n\t\t\t\tconst rules = new Intl.PluralRules(locale);\n\t\t\t\tconst category = rules.select(count);\n\t\t\t\treturn category as keyof PluralTranslation;\n\t\t\t} catch (error) {\n\t\t\t\tlog(`Failed to use Intl.PluralRules for locale: ${locale}`, \"warn\");\n\t\t\t}\n\t\t}\n\n\t\t// Fallback to simple rules\n\t\tif (count === 0) return \"zero\";\n\t\tif (count === 1) return \"one\";\n\t\treturn \"other\";\n\t}\n\n\t/**\n\t * Detect browser locale\n\t */\n\tprivate detectBrowserLocale(): string {\n\t\tif (typeof navigator === \"undefined\") return \"en\";\n\n\t\tconst browserLang =\n\t\t\tnavigator.language ||\n\t\t\t(navigator.languages && navigator.languages[0]) ||\n\t\t\t\"en\";\n\n\t\t// Extract language code (e.g., 'en-US' -> 'en')\n\t\treturn browserLang.split(\"-\")[0];\n\t}\n}\n"]}
|
|
1
|
+
{"version":3,"file":"I18nService.js","sourceRoot":"","sources":["../../src/services/I18nService.ts"],"names":[],"mappings":"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","sourcesContent":["/**\n * I18nService\n *\n * Internationalization service with hybrid loading strategy.\n * Manages translations, locale switching, and RTL/LTR direction.\n *\n * Features:\n * - Subscriber/listener pattern for reactive updates\n * - Hybrid loading: Bundle English, lazy-load other locales\n * - Interpolation: {variable} syntax\n * - Pluralization: ICU-style plural rules\n * - RTL detection: Automatic based on locale\n * - Fallback to English for missing keys\n *\n * Part of PIE Assessment Toolkit.\n */\n\nimport type {\n\tI18nConfig,\n\tI18nServiceApi,\n\tPluralTranslation,\n\tTranslationBundle,\n} from \"@pie-players/pie-players-shared/i18n\";\nimport { createLogger } from \"../utils/logger.js\";\n\nconst log = createLogger(\"I18nService\");\n\n// Re-export types for convenience\nexport type {\n\tI18nConfig,\n\tI18nServiceApi,\n\tPluralTranslation,\n\tTranslationBundle,\n};\n\n/**\n * I18nService\n *\n * Manages internationalization with reactive state updates.\n */\nexport class I18nService implements I18nServiceApi {\n\tprivate locale: string = \"en\";\n\tprivate fallbackLocale: string = \"en\";\n\tprivate direction: \"ltr\" | \"rtl\" = \"ltr\";\n\tprivate translations = new Map<string, TranslationBundle>();\n\tprivate listeners = new Set<() => void>();\n\tprivate loadingPromises = new Map<string, Promise<void>>();\n\tprivate config: I18nConfig;\n\n\tconstructor(config: I18nConfig = {}) {\n\t\tthis.config = config;\n\t\tthis.fallbackLocale = config.fallbackLocale || \"en\";\n\n\t\tlog(\"I18nService initialized\", { fallbackLocale: this.fallbackLocale });\n\n\t\t// Load bundled translations (English by default)\n\t\tif (config.bundledTranslations) {\n\t\t\tfor (const [locale, bundle] of Object.entries(\n\t\t\t\tconfig.bundledTranslations,\n\t\t\t)) {\n\t\t\t\tthis.translations.set(locale, bundle);\n\t\t\t\tlog(`Loaded bundled translations for: ${locale}`);\n\t\t\t}\n\t\t}\n\t}\n\n\t/**\n\t * Initialize i18n with locale and loading strategy\n\t */\n\tasync initialize(config: I18nConfig): Promise<void> {\n\t\tObject.assign(this.config, config);\n\n\t\tconst locale = config.locale || this.detectBrowserLocale();\n\t\tlog(`Initializing with locale: ${locale}`);\n\n\t\tawait this.setLocale(locale);\n\t}\n\n\t/**\n\t * Translate a key with optional interpolation\n\t *\n\t * @param key Translation key (e.g., 'common.save')\n\t * @param params Optional parameters for interpolation\n\t * @returns Translated string\n\t */\n\tt(key: string, params?: Record<string, any>): string {\n\t\tconst translation = this.getTranslation(key);\n\t\treturn this.interpolate(translation as string, params);\n\t}\n\n\t/**\n\t * Translate with pluralization\n\t *\n\t * @param key Translation key\n\t * @param count Count for pluralization\n\t * @param params Optional parameters for interpolation\n\t * @returns Translated string with plural form\n\t */\n\ttn(key: string, count: number, params?: Record<string, any>): string {\n\t\tconst translation = this.getTranslation(key);\n\n\t\tif (typeof translation === \"object\") {\n\t\t\tconst pluralForm = this.selectPluralForm(count, this.locale);\n\t\t\tconst text = translation[pluralForm] || translation.other;\n\t\t\treturn this.interpolate(text, { ...params, count });\n\t\t}\n\n\t\treturn this.interpolate(translation as string, { ...params, count });\n\t}\n\n\t/**\n\t * Get current locale\n\t */\n\tgetLocale(): string {\n\t\treturn this.locale;\n\t}\n\n\t/**\n\t * Change locale (triggers async loading if needed)\n\t *\n\t * @param locale Locale code (e.g., 'en', 'es', 'zh', 'ar')\n\t */\n\tasync setLocale(locale: string): Promise<void> {\n\t\tlog(`Setting locale to: ${locale}`);\n\n\t\t// Check if already loading\n\t\tif (this.loadingPromises.has(locale)) {\n\t\t\tlog(`Locale ${locale} is already loading, waiting...`);\n\t\t\tawait this.loadingPromises.get(locale);\n\t\t\treturn;\n\t\t}\n\n\t\t// Check if already loaded\n\t\tif (this.translations.has(locale)) {\n\t\t\tlog(`Locale ${locale} already loaded`);\n\t\t\tthis.applyLocale(locale);\n\t\t\treturn;\n\t\t}\n\n\t\t// Load translations\n\t\tconst loadingPromise = this.loadTranslationsForLocale(locale);\n\t\tthis.loadingPromises.set(locale, loadingPromise);\n\n\t\ttry {\n\t\t\tawait loadingPromise;\n\t\t\tthis.applyLocale(locale);\n\t\t} finally {\n\t\t\tthis.loadingPromises.delete(locale);\n\t\t}\n\t}\n\n\t/**\n\t * Get current text direction\n\t */\n\tgetDirection(): \"ltr\" | \"rtl\" {\n\t\treturn this.direction;\n\t}\n\n\t/**\n\t * Get available locales\n\t */\n\tgetAvailableLocales(): string[] {\n\t\treturn Array.from(this.translations.keys());\n\t}\n\n\t/**\n\t * Check if locale is loaded\n\t */\n\tisLocaleLoaded(locale: string): boolean {\n\t\treturn this.translations.has(locale);\n\t}\n\n\t/**\n\t * Subscribe to locale/translation changes\n\t * Returns unsubscribe function\n\t */\n\tsubscribe(listener: () => void): () => void {\n\t\tthis.listeners.add(listener);\n\t\treturn () => {\n\t\t\tthis.listeners.delete(listener);\n\t\t};\n\t}\n\n\t/**\n\t * Check if a translation key exists\n\t */\n\thasKey(key: string): boolean {\n\t\tconst bundle = this.translations.get(this.locale);\n\t\treturn !!bundle?.translations[key];\n\t}\n\n\t/**\n\t * Notify all listeners of state change\n\t */\n\tprivate notifyListeners(): void {\n\t\tthis.listeners.forEach((listener) => listener());\n\t}\n\n\t/**\n\t * Apply locale and notify listeners\n\t */\n\tprivate applyLocale(locale: string): void {\n\t\tconst bundle = this.translations.get(locale);\n\t\tif (!bundle) {\n\t\t\tlog(`No bundle found for locale: ${locale}`, \"warn\");\n\t\t\treturn;\n\t\t}\n\n\t\tconst previousLocale = this.locale;\n\t\tthis.locale = locale;\n\t\tthis.direction = bundle.direction;\n\n\t\tlog(`Applied locale: ${locale} (direction: ${this.direction})`);\n\n\t\tthis.applyDOMDirection();\n\t\tthis.notifyListeners();\n\t}\n\n\t/**\n\t * Apply direction to DOM\n\t */\n\tprivate applyDOMDirection(): void {\n\t\tif (typeof document === \"undefined\") return;\n\n\t\tdocument.documentElement.setAttribute(\"dir\", this.direction);\n\t\tdocument.documentElement.setAttribute(\"lang\", this.locale);\n\n\t\tlog(\n\t\t\t`Applied DOM attributes: dir=\"${this.direction}\" lang=\"${this.locale}\"`,\n\t\t);\n\t}\n\n\t/**\n\t * Load translations for a locale\n\t */\n\tprivate async loadTranslationsForLocale(locale: string): Promise<void> {\n\t\tif (!this.config.loadTranslations) {\n\t\t\tthrow new Error(`No translation loader configured for locale: ${locale}`);\n\t\t}\n\n\t\tlog(`Loading translations for: ${locale}`);\n\n\t\ttry {\n\t\t\tconst bundle = await this.config.loadTranslations(locale);\n\t\t\tthis.translations.set(locale, bundle);\n\t\t\tlog(\n\t\t\t\t`Loaded translations for: ${locale} (${Object.keys(bundle.translations).length} keys)`,\n\t\t\t);\n\t\t} catch (error) {\n\t\t\tlog(`Failed to load translations for: ${locale}`, \"error\");\n\t\t\tthrow error;\n\t\t}\n\t}\n\n\t/**\n\t * Get translation for a key\n\t */\n\tprivate getTranslation(key: string): string | PluralTranslation {\n\t\t// Try current locale\n\t\tconst currentBundle = this.translations.get(this.locale);\n\t\tif (currentBundle?.translations[key]) {\n\t\t\treturn currentBundle.translations[key];\n\t\t}\n\n\t\t// Try fallback locale\n\t\tconst fallbackBundle = this.translations.get(this.fallbackLocale);\n\t\tif (fallbackBundle?.translations[key]) {\n\t\t\tif (this.config.debug) {\n\t\t\t\tlog(`Using fallback translation for key: ${key}`);\n\t\t\t}\n\t\t\treturn fallbackBundle.translations[key];\n\t\t}\n\n\t\t// Missing key handling\n\t\tif (this.config.onMissingKey) {\n\t\t\tthis.config.onMissingKey(key, this.locale);\n\t\t}\n\n\t\tif (this.config.debug) {\n\t\t\tlog(`Missing translation key: ${key} (locale: ${this.locale})`, \"warn\");\n\t\t}\n\n\t\treturn key;\n\t}\n\n\t/**\n\t * Interpolate variables in translation string\n\t * Replaces {variable} with params.variable\n\t */\n\tprivate interpolate(text: string, params?: Record<string, any>): string {\n\t\tif (!params) return text;\n\n\t\treturn text.replace(/\\{(\\w+)\\}/g, (match, key) => {\n\t\t\treturn params[key]?.toString() || match;\n\t\t});\n\t}\n\n\t/**\n\t * Select plural form based on count and locale\n\t * Simplified implementation - real implementation would use Intl.PluralRules\n\t */\n\tprivate selectPluralForm(\n\t\tcount: number,\n\t\tlocale: string,\n\t): keyof PluralTranslation {\n\t\t// Use Intl.PluralRules if available\n\t\tif (typeof Intl !== \"undefined\" && Intl.PluralRules) {\n\t\t\ttry {\n\t\t\t\tconst rules = new Intl.PluralRules(locale);\n\t\t\t\tconst category = rules.select(count);\n\t\t\t\treturn category as keyof PluralTranslation;\n\t\t\t} catch (error) {\n\t\t\t\tlog(`Failed to use Intl.PluralRules for locale: ${locale}`, \"warn\");\n\t\t\t}\n\t\t}\n\n\t\t// Fallback to simple rules\n\t\tif (count === 0) return \"zero\";\n\t\tif (count === 1) return \"one\";\n\t\treturn \"other\";\n\t}\n\n\t/**\n\t * Detect browser locale\n\t */\n\tprivate detectBrowserLocale(): string {\n\t\tif (typeof navigator === \"undefined\") return \"en\";\n\n\t\tconst browserLang =\n\t\t\tnavigator.language ||\n\t\t\t(navigator.languages && navigator.languages[0]) ||\n\t\t\t\"en\";\n\n\t\t// Extract language code (e.g., 'en-US' -> 'en')\n\t\treturn browserLang.split(\"-\")[0];\n\t}\n}\n"]}
|