@pie-players/pie-assessment-toolkit 0.3.47 → 0.3.49

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (86) hide show
  1. package/dist/attempt/AssessmentSession.js +2 -1
  2. package/dist/attempt/AssessmentSession.js.map +1 -1
  3. package/dist/attempt/adapters/activity-to-test-attempt-session.js +12 -8
  4. package/dist/attempt/adapters/activity-to-test-attempt-session.js.map +1 -1
  5. package/dist/components/ItemToolBar.custom-element.js +56 -17
  6. package/dist/components/PieAssessmentToolkit.custom-element.js +84 -29
  7. package/dist/components/SectionToolBar.custom-element.js +55 -17
  8. package/dist/index.d.ts +1 -1
  9. package/dist/index.js.map +1 -1
  10. package/dist/policy/core/pnp-policy-inputs.js +1 -2
  11. package/dist/policy/core/pnp-policy-inputs.js.map +1 -1
  12. package/dist/policy/core/provenance.js.map +1 -1
  13. package/dist/runtime/SectionRuntimeEngine.js +1 -1
  14. package/dist/runtime/SectionRuntimeEngine.js.map +1 -1
  15. package/dist/runtime/core/cohort.js.map +1 -1
  16. package/dist/runtime/core/engine-input.js.map +1 -1
  17. package/dist/runtime/core/engine-readiness.js.map +1 -1
  18. package/dist/runtime/core/engine-resolver.js.map +1 -1
  19. package/dist/runtime/core/engine-transition.js +1 -3
  20. package/dist/runtime/core/engine-transition.js.map +1 -1
  21. package/dist/runtime/registration-events.js.map +1 -1
  22. package/dist/runtime/session-event-emitter-policy.js.map +1 -1
  23. package/dist/services/HighlightCoordinator.js +2 -1
  24. package/dist/services/HighlightCoordinator.js.map +1 -1
  25. package/dist/services/I18nService.d.ts +1 -1
  26. package/dist/services/I18nService.js.map +1 -1
  27. package/dist/services/SSMLExtractor.js.map +1 -1
  28. package/dist/services/TTSService.js +5 -2
  29. package/dist/services/TTSService.js.map +1 -1
  30. package/dist/services/ThemeProvider.js.map +1 -1
  31. package/dist/services/ToolRegistry.d.ts +1 -1
  32. package/dist/services/ToolRegistry.js.map +1 -1
  33. package/dist/services/ToolkitCoordinator.js +21 -11
  34. package/dist/services/ToolkitCoordinator.js.map +1 -1
  35. package/dist/services/createDefaultToolRegistry.js +4 -2
  36. package/dist/services/createDefaultToolRegistry.js.map +1 -1
  37. package/dist/services/framework-error-bus.js.map +1 -1
  38. package/dist/services/framework-error.js.map +1 -1
  39. package/dist/services/interfaces.js.map +1 -1
  40. package/dist/services/section-controller-types.js.map +1 -1
  41. package/dist/services/tool-config-defaults.js +7 -1
  42. package/dist/services/tool-config-defaults.js.map +1 -1
  43. package/dist/services/tool-config-validation.js +3 -1
  44. package/dist/services/tool-config-validation.js.map +1 -1
  45. package/dist/services/tool-instance-id.js.map +1 -1
  46. package/dist/services/tool-providers/DesmosToolProvider.js.map +1 -1
  47. package/dist/services/tool-providers/TTSToolProvider.js.map +1 -1
  48. package/dist/services/toolbar-items.js.map +1 -1
  49. package/dist/services/tools-config-normalizer.js +1 -2
  50. package/dist/services/tools-config-normalizer.js.map +1 -1
  51. package/dist/services/tts/browser-provider.js +60 -18
  52. package/dist/services/tts/browser-provider.js.map +1 -1
  53. package/dist/services/tts/catalog-span-alignment.js +8 -3
  54. package/dist/services/tts/catalog-span-alignment.js.map +1 -1
  55. package/dist/services/tts/generated-speech/assemble-plan.js.map +1 -1
  56. package/dist/services/tts/generated-speech/index.d.ts +1 -1
  57. package/dist/services/tts/generated-speech/index.js +1 -1
  58. package/dist/services/tts/generated-speech/index.js.map +1 -1
  59. package/dist/services/tts/generated-speech/math-speech-cache.js +3 -1
  60. package/dist/services/tts/generated-speech/math-speech-cache.js.map +1 -1
  61. package/dist/services/tts/highlight-pipeline/boundary-normalizer.js.map +1 -1
  62. package/dist/services/tts/highlight-pipeline/create-highlight-plan.js.map +1 -1
  63. package/dist/services/tts/math-alignment/mathml-tokenizer.js.map +1 -1
  64. package/dist/services/tts/math-alignment/sequence-aligner.js.map +1 -1
  65. package/dist/services/tts/math-alignment/speech-tokenizer.js.map +1 -1
  66. package/dist/services/tts/math-aware-text-processing.js +6 -3
  67. package/dist/services/tts/math-aware-text-processing.js.map +1 -1
  68. package/dist/services/tts/math-speech.js +3 -1
  69. package/dist/services/tts/math-speech.js.map +1 -1
  70. package/dist/services/tts/visual-line-ranges.js.map +1 -1
  71. package/dist/services/tts-runtime-config.js +6 -2
  72. package/dist/services/tts-runtime-config.js.map +1 -1
  73. package/dist/tools/calculators/desmos-provider.js.map +1 -1
  74. package/dist/tools/default-tool-module-loaders.js.map +1 -1
  75. package/dist/tools/registrations/accessibility-tools.js.map +1 -1
  76. package/dist/tools/registrations/calculator.js +1 -1
  77. package/dist/tools/registrations/calculator.js.map +1 -1
  78. package/dist/tools/registrations/interaction-tools.js.map +1 -1
  79. package/dist/tools/registrations/measurement-tools.js.map +1 -1
  80. package/dist/tools/registrations/subject-specific-tools.js +1 -1
  81. package/dist/tools/registrations/subject-specific-tools.js.map +1 -1
  82. package/dist/tools/registrations/tts.js +4 -2
  83. package/dist/tools/registrations/tts.js.map +1 -1
  84. package/dist/tools/types.js.map +1 -1
  85. package/dist/tools/variant-resolver.js.map +1 -1
  86. package/package.json +7 -7
@@ -1 +1 @@
1
- {"version":3,"file":"accessibility-tools.js","sourceRoot":"","sources":["../../../src/tools/registrations/accessibility-tools.ts"],"names":[],"mappings":"AAAA;;;;;;;;;;;GAWG;AASH,OAAO,EAAE,eAAe,EAAE,MAAM,gCAAgC,CAAC;AACjE,OAAO,EACN,iBAAiB,GAEjB,MAAM,oBAAoB,CAAC;AAC5B,OAAO,EACN,mBAAmB,EACnB,6BAA6B,EAC7B,8BAA8B,GAC9B,MAAM,mCAAmC,CAAC;AAE3C;;;;;GAKG;AACH,MAAM,CAAC,MAAM,0BAA0B,GAAqB;IAC3D,MAAM,EAAE,YAAY;IACpB,IAAI,EAAE,aAAa;IACnB,WAAW,EAAE,uBAAuB;IACpC,IAAI,EAAE,QAAQ;IAEd,iDAAiD;IACjD,eAAe,EAAE,CAAC,SAAS,EAAE,SAAS,EAAE,QAAQ,EAAE,MAAM,CAAC;IAEzD,kBAAkB;IAClB,6EAA6E;IAC7E,aAAa,EAAE;QACd,aAAa,EAAE,yCAAyC;QACxD,cAAc,EAAE,0CAA0C;QAC1D,cAAc,EAAE,0CAA0C;QAC1D,YAAY,EAAE,iBAAiB;QAC/B,eAAe,EAAE,iBAAiB;KAClC;IAED;;OAEG;IACH,kBAAkB,CAAC,OAAoB;QACtC,OAAO,eAAe,CAAC,OAAO,CAAC,CAAC;IACjC,CAAC;IAED,aAAa,CACZ,OAAoB,EACpB,cAA8B;QAE9B,MAAM,UAAU,GAAG,6BAA6B,CAAC,IAAI,CAAC,MAAM,EAAE,cAAc,CAAC,CAAC;QAC9E,MAAM,MAAM,GAAgC;YAC3C,MAAM,EAAE,IAAI,CAAC,MAAM;YACnB,KAAK,EAAE,IAAI,CAAC,IAAI;YAChB,IAAI,EAAE,OAAO,IAAI,CAAC,IAAI,KAAK,UAAU,CAAC,CAAC,CAAC,IAAI,CAAC,IAAI,CAAC,OAAO,CAAC,CAAC,CAAC,CAAC,IAAI,CAAC,IAAI;YACtE,QAAQ,EAAE,KAAK;YACf,SAAS,EAAE,6BAA6B;YACxC,OAAO,EAAE,aAAa;YACtB,OAAO,EAAE,GAAG,EAAE,CAAC,cAAc,CAAC,UAAU,CAAC,IAAI,CAAC,MAAM,CAAC;YACrD,MAAM,EAAE,UAAU,CAAC,QAAQ,EAAE;SAC7B,CAAC;QACF,MAAM,kBAAkB,GACtB,cAAc,CAAC,kBAAyD,IAAI,EAAE,CAAC;QACjF,MAAM,OAAO,GAAG,iBAAiB,CAChC,IAAI,CAAC,MAAM,EACX,OAAO,EACP,cAAc,EACd,kBAAkB,CAKlB,CAAC;QACF,OAAO,CAAC,YAAY,CAAC,SAAS,EAAE,UAAU,CAAC,UAAU,CAAC,CAAC;QACvD,mBAAmB,CAAC,OAAO,EAAE,WAAW,CAAC,CAAC;QAC1C,OAAO;YACN,MAAM,EAAE,IAAI,CAAC,MAAM;YACnB,MAAM;YACN,QAAQ,EAAE,CAAC,EAAE,OAAO,EAAE,OAAO,EAAE,KAAK,EAAE,eAAe,EAAE,CAAC;YACxD,IAAI,EAAE,GAAG,EAAE;gBACV,8BAA8B,CAAC;oBAC9B,MAAM;oBACN,OAAO;oBACP,QAAQ,EAAE,UAAU,CAAC,QAAQ;iBAC7B,CAAC,CAAC;gBACH,IAAI,cAAc,CAAC,kBAAkB,EAAE,CAAC;oBACvC,OAAO,CAAC,kBAAkB,GAAG,cAAc,CAAC,kBAAkB,CAAC;gBAChE,CAAC;YACF,CAAC;YACD,eAAe,EAAE,UAAU,CAAC,eAAe;SAC3C,CAAC;IACH,CAAC;CACD,CAAC;AAEF;;;;;GAKG;AACH,MAAM,CAAC,MAAM,qBAAqB,GAAqB;IACtD,MAAM,EAAE,OAAO;IACf,IAAI,EAAE,OAAO;IACb,WAAW,EAAE,gCAAgC;IAC7C,IAAI,EAAE,QAAQ;IAEd,kCAAkC;IAClC,eAAe,EAAE,CAAC,YAAY,EAAE,SAAS,CAAC;IAE1C,kBAAkB;IAClB,sFAAsF;IACtF,aAAa,EAAE;QACd,qBAAqB,EAAE,gDAAgD;QACvE,eAAe,EAAE,0CAA0C;QAC3D,cAAc,EAAE,yCAAyC;QACzD,OAAO,EAAE,eAAe;QACxB,cAAc,EAAE,iBAAiB;QACjC,cAAc,EAAE,iBAAiB;KACjC;IAED;;OAEG;IACH,kBAAkB,CAAC,OAAoB;QACtC,OAAO,IAAI,CAAC,CAAC,yCAAyC;IACvD,CAAC;IAED,aAAa,CACZ,OAAoB,EACpB,cAA8B;QAE9B,MAAM,UAAU,GAAG,6BAA6B,CAAC,IAAI,CAAC,MAAM,EAAE,cAAc,CAAC,CAAC;QAC9E,MAAM,MAAM,GAAgC;YAC3C,MAAM,EAAE,IAAI,CAAC,MAAM;YACnB,KAAK,EAAE,IAAI,CAAC,IAAI;YAChB,IAAI,EAAE,OAAO,IAAI,CAAC,IAAI,KAAK,UAAU,CAAC,CAAC,CAAC,IAAI,CAAC,IAAI,CAAC,OAAO,CAAC,CAAC,CAAC,CAAC,IAAI,CAAC,IAAI;YACtE,QAAQ,EAAE,KAAK;YACf,SAAS,EAAE,oCAAoC;YAC/C,OAAO,EAAE,OAAO;YAChB,OAAO,EAAE,GAAG,EAAE,CAAC,cAAc,CAAC,UAAU,CAAC,IAAI,CAAC,MAAM,CAAC;YACrD,MAAM,EAAE,UAAU,CAAC,QAAQ,EAAE;SAC7B,CAAC;QACF,MAAM,kBAAkB,GACtB,cAAc,CAAC,kBAAyD,IAAI,EAAE,CAAC;QACjF,MAAM,OAAO,GAAG,iBAAiB,CAChC,IAAI,CAAC,MAAM,EACX,OAAO,EACP,cAAc,EACd,kBAAkB,CAKlB,CAAC;QACF,OAAO,CAAC,YAAY,CAAC,SAAS,EAAE,UAAU,CAAC,UAAU,CAAC,CAAC;QACvD,OAAO;YACN,MAAM,EAAE,IAAI,CAAC,MAAM;YACnB,MAAM;YACN,QAAQ,EAAE;gBACT;oBACC,OAAO,EAAE,OAAO;oBAChB,KAAK,EAAE,eAAe;oBACtB,KAAK,EAAE;wBACN,KAAK,EAAE,IAAI,CAAC,IAAI;wBAChB,SAAS,EAAE,IAAI;wBACf,SAAS,EAAE,KAAK;wBAChB,SAAS,EAAE,IAAI;wBACf,YAAY,EAAE,GAAG;wBACjB,aAAa,EAAE,GAAG;wBAClB,QAAQ,EAAE,GAAG;wBACb,SAAS,EAAE,GAAG;qBACd;iBACD;aACD;YACD,IAAI,EAAE,GAAG,EAAE;gBACV,8BAA8B,CAAC;oBAC9B,MAAM;oBACN,OAAO;oBACP,QAAQ,EAAE,UAAU,CAAC,QAAQ;iBAC7B,CAAC,CAAC;gBACH,IAAI,cAAc,CAAC,kBAAkB,EAAE,CAAC;oBACvC,OAAO,CAAC,kBAAkB,GAAG,cAAc,CAAC,kBAAkB,CAAC;gBAChE,CAAC;YACF,CAAC;YACD,eAAe,EAAE,UAAU,CAAC,eAAe;SAC3C,CAAC;IACH,CAAC;CACD,CAAC;AAEF;;;;;GAKG;AACH,MAAM,CAAC,MAAM,6BAA6B,GAAqB;IAC9D,MAAM,EAAE,mBAAmB;IAC3B,IAAI,EAAE,aAAa;IACnB,WAAW,EAAE,6BAA6B;IAC1C,IAAI,EAAE,aAAa;IACnB,UAAU,EAAE,mBAAmB;IAC/B,cAAc,EAAE,SAAS;IAEzB,gDAAgD;IAChD,eAAe,EAAE,CAAC,SAAS,EAAE,QAAQ,EAAE,MAAM,EAAE,SAAS,CAAC;IAEzD,kBAAkB;IAClB,+DAA+D;IAC/D,aAAa,EAAE;QACd,cAAc,EAAE,uEAAuE;QACvF,aAAa,EAAE,2CAA2C;QAC1D,aAAa,EAAE,iBAAiB;QAChC,eAAe,EAAE,iBAAiB;QAClC,YAAY,EAAE,iBAAiB;KAC/B;IAED;;OAEG;IACH,kBAAkB,CAAC,OAAoB;QACtC,OAAO,eAAe,CAAC,OAAO,CAAC,CAAC;IACjC,CAAC;IAED,aAAa,CACZ,OAAoB,EACpB,cAA8B;QAE9B,MAAM,UAAU,GAAG,6BAA6B,CAAC,IAAI,CAAC,MAAM,EAAE,cAAc,CAAC,CAAC;QAC9E,MAAM,MAAM,GAAgC;YAC3C,MAAM,EAAE,IAAI,CAAC,MAAM;YACnB,KAAK,EAAE,IAAI,CAAC,IAAI;YAChB,IAAI,EAAE,OAAO,IAAI,CAAC,IAAI,KAAK,UAAU,CAAC,CAAC,CAAC,IAAI,CAAC,IAAI,CAAC,OAAO,CAAC,CAAC,CAAC,CAAC,IAAI,CAAC,IAAI;YACtE,QAAQ,EAAE,KAAK;YACf,SAAS,EAAE,qCAAqC;YAChD,OAAO,EAAE,WAAW;YACpB,OAAO,EAAE,GAAG,EAAE,CAAC,cAAc,CAAC,UAAU,CAAC,IAAI,CAAC,MAAM,CAAC;YACrD,MAAM,EAAE,UAAU,CAAC,QAAQ,EAAE;SAC7B,CAAC;QACF,MAAM,kBAAkB,GACtB,cAAc,CAAC,kBAAyD,IAAI,EAAE,CAAC;QACjF,MAAM,OAAO,GAAG,iBAAiB,CAChC,IAAI,CAAC,MAAM,EACX,OAAO,EACP,cAAc,EACd,kBAAkB,CAKlB,CAAC;QACF,OAAO,CAAC,YAAY,CAAC,SAAS,EAAE,UAAU,CAAC,UAAU,CAAC,CAAC;QACvD,OAAO;YACN,MAAM,EAAE,IAAI,CAAC,MAAM;YACnB,MAAM;YACN,QAAQ,EAAE,CAAC,EAAE,OAAO,EAAE,OAAO,EAAE,KAAK,EAAE,eAAe,EAAE,CAAC;YACxD,IAAI,EAAE,GAAG,EAAE;gBACV,8BAA8B,CAAC;oBAC9B,MAAM;oBACN,OAAO;oBACP,QAAQ,EAAE,UAAU,CAAC,QAAQ;iBAC7B,CAAC,CAAC;gBACH,IAAI,cAAc,CAAC,kBAAkB,EAAE,CAAC;oBACvC,OAAO,CAAC,kBAAkB,GAAG,cAAc,CAAC,kBAAkB,CAAC;gBAChE,CAAC;YACF,CAAC;YACD,eAAe,EAAE,UAAU,CAAC,eAAe;SAC3C,CAAC;IACH,CAAC;CACD,CAAC","sourcesContent":["/**\n * Accessibility Tools Registrations\n *\n * Registers tools for visual accessibility and reading support:\n * - Line Reader (reading guide)\n * - Color Scheme (theme/contrast)\n * - Annotation Toolbar (text highlighting)\n *\n * Maps to QTI 3.0 standard access features from:\n * - visual category: highContrastDisplay, colorContrast\n * - reading category: readingMask, readingGuide, highlighting\n */\n\nimport type {\n\tToolRegistration,\n\tToolToolbarButtonDefinition,\n\tToolToolbarRenderResult,\n\tToolbarContext,\n} from \"../../services/ToolRegistry.js\";\nimport type { ToolContext } from \"../../services/tool-context.js\";\nimport { hasReadableText } from \"../../services/tool-context.js\";\nimport {\n\tcreateToolElement,\n\ttype ToolComponentOverrides,\n} from \"../tool-tag-map.js\";\nimport {\n\tapplyOverlaySurface,\n\tcreateScopedVisibilityBinding,\n\tsyncButtonAndOverlayVisibility,\n} from \"./toolbar-registration-helpers.js\";\n\n/**\n * Line Reader tool registration\n *\n * Provides a reading guide overlay to help track reading position.\n * Useful for text-heavy passages and questions.\n */\nexport const lineReaderToolRegistration: ToolRegistration = {\n\ttoolId: \"lineReader\",\n\tname: \"Line Reader\",\n\tdescription: \"Reading guide overlay\",\n\ticon: \"bars-3\",\n\n\t// Line reader appears where there's text to read\n\tsupportedLevels: [\"section\", \"passage\", \"rubric\", \"item\"],\n\n\t// PNP support IDs\n\t// Maps to QTI 3.0 standard features: readingMask, readingGuide, readingRuler\n\tpnpSupportIds: [\n\t\t\"readingMask\", // QTI 3.0 standard (reading.readingMask)\n\t\t\"readingGuide\", // QTI 3.0 standard (reading.readingGuide)\n\t\t\"readingRuler\", // QTI 3.0 standard (reading.readingRuler)\n\t\t\"lineReader\", // Common variant\n\t\t\"trackingGuide\", // Common variant\n\t],\n\n\t/**\n\t * Pass 2: Line reader is relevant when readable text is present\n\t */\n\tisVisibleInContext(context: ToolContext): boolean {\n\t\treturn hasReadableText(context);\n\t},\n\n\trenderToolbar(\n\t\tcontext: ToolContext,\n\t\ttoolbarContext: ToolbarContext,\n\t): ToolToolbarRenderResult {\n\t\tconst visibility = createScopedVisibilityBinding(this.toolId, toolbarContext);\n\t\tconst button: ToolToolbarButtonDefinition = {\n\t\t\ttoolId: this.toolId,\n\t\t\tlabel: this.name,\n\t\t\ticon: typeof this.icon === \"function\" ? this.icon(context) : this.icon,\n\t\t\tdisabled: false,\n\t\t\tariaLabel: \"Line reader - Reading guide\",\n\t\t\ttooltip: \"Line Reader\",\n\t\t\tonClick: () => toolbarContext.toggleTool(this.toolId),\n\t\t\tactive: visibility.isActive(),\n\t\t};\n\t\tconst componentOverrides =\n\t\t\t(toolbarContext.componentOverrides as ToolComponentOverrides | undefined) ?? {};\n\t\tconst overlay = createToolElement(\n\t\t\tthis.toolId,\n\t\t\tcontext,\n\t\t\ttoolbarContext,\n\t\t\tcomponentOverrides,\n\t\t) as HTMLElement & {\n\t\t\tvisible?: boolean;\n\t\t\ttoolId?: string;\n\t\t\ttoolkitCoordinator: unknown;\n\t\t};\n\t\toverlay.setAttribute(\"tool-id\", visibility.fullToolId);\n\t\tapplyOverlaySurface(overlay, \"frameless\");\n\t\treturn {\n\t\t\ttoolId: this.toolId,\n\t\t\tbutton,\n\t\t\telements: [{ element: overlay, mount: \"after-buttons\" }],\n\t\t\tsync: () => {\n\t\t\t\tsyncButtonAndOverlayVisibility({\n\t\t\t\t\tbutton,\n\t\t\t\t\toverlay,\n\t\t\t\t\tisActive: visibility.isActive,\n\t\t\t\t});\n\t\t\t\tif (toolbarContext.toolkitCoordinator) {\n\t\t\t\t\toverlay.toolkitCoordinator = toolbarContext.toolkitCoordinator;\n\t\t\t\t}\n\t\t\t},\n\t\t\tsubscribeActive: visibility.subscribeActive,\n\t\t};\n\t},\n};\n\n/**\n * Theme tool registration\n *\n * Provides accessible theme and contrast controls.\n * Global tool that affects entire assessment.\n */\nexport const themeToolRegistration: ToolRegistration = {\n\ttoolId: \"theme\",\n\tname: \"Theme\",\n\tdescription: \"Accessible themes and contrast\",\n\ticon: \"swatch\",\n\n\t// Color scheme is assessment-wide\n\tsupportedLevels: [\"assessment\", \"section\"],\n\n\t// PNP support IDs\n\t// Maps to QTI 3.0 standard features: highContrastDisplay, colorContrast, invertColors\n\tpnpSupportIds: [\n\t\t\"highContrastDisplay\", // QTI 3.0 standard (visual.highContrastDisplay)\n\t\t\"colorContrast\", // QTI 3.0 standard (visual.colorContrast)\n\t\t\"invertColors\", // QTI 3.0 standard (visual.invertColors)\n\t\t\"theme\", // Canonical id\n\t\t\"highContrast\", // Common variant\n\t\t\"customColors\", // Common variant\n\t],\n\n\t/**\n\t * Pass 2: Color scheme is always relevant when allowed\n\t */\n\tisVisibleInContext(context: ToolContext): boolean {\n\t\treturn true; // Always show if allowed by orchestrator\n\t},\n\n\trenderToolbar(\n\t\tcontext: ToolContext,\n\t\ttoolbarContext: ToolbarContext,\n\t): ToolToolbarRenderResult {\n\t\tconst visibility = createScopedVisibilityBinding(this.toolId, toolbarContext);\n\t\tconst button: ToolToolbarButtonDefinition = {\n\t\t\ttoolId: this.toolId,\n\t\t\tlabel: this.name,\n\t\t\ticon: typeof this.icon === \"function\" ? this.icon(context) : this.icon,\n\t\t\tdisabled: false,\n\t\t\tariaLabel: \"Theme - Change colors and contrast\",\n\t\t\ttooltip: \"Theme\",\n\t\t\tonClick: () => toolbarContext.toggleTool(this.toolId),\n\t\t\tactive: visibility.isActive(),\n\t\t};\n\t\tconst componentOverrides =\n\t\t\t(toolbarContext.componentOverrides as ToolComponentOverrides | undefined) ?? {};\n\t\tconst overlay = createToolElement(\n\t\t\tthis.toolId,\n\t\t\tcontext,\n\t\t\ttoolbarContext,\n\t\t\tcomponentOverrides,\n\t\t) as HTMLElement & {\n\t\t\tvisible?: boolean;\n\t\t\ttoolId?: string;\n\t\t\ttoolkitCoordinator: unknown;\n\t\t};\n\t\toverlay.setAttribute(\"tool-id\", visibility.fullToolId);\n\t\treturn {\n\t\t\ttoolId: this.toolId,\n\t\t\tbutton,\n\t\t\telements: [\n\t\t\t\t{\n\t\t\t\t\telement: overlay,\n\t\t\t\t\tmount: \"after-buttons\",\n\t\t\t\t\tshell: {\n\t\t\t\t\t\ttitle: this.name,\n\t\t\t\t\t\tdraggable: true,\n\t\t\t\t\t\tresizable: false,\n\t\t\t\t\t\tcloseable: true,\n\t\t\t\t\t\tinitialWidth: 520,\n\t\t\t\t\t\tinitialHeight: 380,\n\t\t\t\t\t\tminWidth: 420,\n\t\t\t\t\t\tminHeight: 300,\n\t\t\t\t\t},\n\t\t\t\t},\n\t\t\t],\n\t\t\tsync: () => {\n\t\t\t\tsyncButtonAndOverlayVisibility({\n\t\t\t\t\tbutton,\n\t\t\t\t\toverlay,\n\t\t\t\t\tisActive: visibility.isActive,\n\t\t\t\t});\n\t\t\t\tif (toolbarContext.toolkitCoordinator) {\n\t\t\t\t\toverlay.toolkitCoordinator = toolbarContext.toolkitCoordinator;\n\t\t\t\t}\n\t\t\t},\n\t\t\tsubscribeActive: visibility.subscribeActive,\n\t\t};\n\t},\n};\n\n/**\n * Annotation Toolbar registration\n *\n * Text highlighting with CSS Custom Highlight API.\n * Zero DOM mutation, optimal performance.\n */\nexport const annotationToolbarRegistration: ToolRegistration = {\n\ttoolId: \"annotationToolbar\",\n\tname: \"Highlighter\",\n\tdescription: \"Highlight and annotate text\",\n\ticon: \"highlighter\",\n\tactivation: \"selection-gateway\",\n\tsingletonScope: \"section\",\n\n\t// Annotation appears where there's text content\n\tsupportedLevels: [\"passage\", \"rubric\", \"item\", \"element\"],\n\n\t// PNP support IDs\n\t// Maps to QTI 3.0 standard features: highlighting, annotations\n\tpnpSupportIds: [\n\t\t\"highlighting\", // QTI 3.0 standard (cognitive.highlighting / reading.wordHighlighting)\n\t\t\"annotations\", // QTI 3.0 standard (cognitive.annotations)\n\t\t\"highlighter\", // Common variant\n\t\t\"textHighlight\", // Common variant\n\t\t\"annotation\", // Common variant\n\t],\n\n\t/**\n\t * Pass 2: Annotation is relevant when readable text is present\n\t */\n\tisVisibleInContext(context: ToolContext): boolean {\n\t\treturn hasReadableText(context);\n\t},\n\n\trenderToolbar(\n\t\tcontext: ToolContext,\n\t\ttoolbarContext: ToolbarContext,\n\t): ToolToolbarRenderResult {\n\t\tconst visibility = createScopedVisibilityBinding(this.toolId, toolbarContext);\n\t\tconst button: ToolToolbarButtonDefinition = {\n\t\t\ttoolId: this.toolId,\n\t\t\tlabel: this.name,\n\t\t\ticon: typeof this.icon === \"function\" ? this.icon(context) : this.icon,\n\t\t\tdisabled: false,\n\t\t\tariaLabel: \"Annotation toolbar - Highlight text\",\n\t\t\ttooltip: \"Highlight\",\n\t\t\tonClick: () => toolbarContext.toggleTool(this.toolId),\n\t\t\tactive: visibility.isActive(),\n\t\t};\n\t\tconst componentOverrides =\n\t\t\t(toolbarContext.componentOverrides as ToolComponentOverrides | undefined) ?? {};\n\t\tconst overlay = createToolElement(\n\t\t\tthis.toolId,\n\t\t\tcontext,\n\t\t\ttoolbarContext,\n\t\t\tcomponentOverrides,\n\t\t) as HTMLElement & {\n\t\t\tvisible?: boolean;\n\t\t\ttoolId?: string;\n\t\t\ttoolkitCoordinator: unknown;\n\t\t};\n\t\toverlay.setAttribute(\"tool-id\", visibility.fullToolId);\n\t\treturn {\n\t\t\ttoolId: this.toolId,\n\t\t\tbutton,\n\t\t\telements: [{ element: overlay, mount: \"after-buttons\" }],\n\t\t\tsync: () => {\n\t\t\t\tsyncButtonAndOverlayVisibility({\n\t\t\t\t\tbutton,\n\t\t\t\t\toverlay,\n\t\t\t\t\tisActive: visibility.isActive,\n\t\t\t\t});\n\t\t\t\tif (toolbarContext.toolkitCoordinator) {\n\t\t\t\t\toverlay.toolkitCoordinator = toolbarContext.toolkitCoordinator;\n\t\t\t\t}\n\t\t\t},\n\t\t\tsubscribeActive: visibility.subscribeActive,\n\t\t};\n\t},\n};\n"]}
1
+ {"version":3,"file":"accessibility-tools.js","sourceRoot":"","sources":["../../../src/tools/registrations/accessibility-tools.ts"],"names":[],"mappings":"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","sourcesContent":["/**\n * Accessibility Tools Registrations\n *\n * Registers tools for visual accessibility and reading support:\n * - Line Reader (reading guide)\n * - Color Scheme (theme/contrast)\n * - Annotation Toolbar (text highlighting)\n *\n * Maps to QTI 3.0 standard access features from:\n * - visual category: highContrastDisplay, colorContrast\n * - reading category: readingMask, readingGuide, highlighting\n */\n\nimport type {\n\tToolRegistration,\n\tToolToolbarButtonDefinition,\n\tToolToolbarRenderResult,\n\tToolbarContext,\n} from \"../../services/ToolRegistry.js\";\nimport type { ToolContext } from \"../../services/tool-context.js\";\nimport { hasReadableText } from \"../../services/tool-context.js\";\nimport {\n\tcreateToolElement,\n\ttype ToolComponentOverrides,\n} from \"../tool-tag-map.js\";\nimport {\n\tapplyOverlaySurface,\n\tcreateScopedVisibilityBinding,\n\tsyncButtonAndOverlayVisibility,\n} from \"./toolbar-registration-helpers.js\";\n\n/**\n * Line Reader tool registration\n *\n * Provides a reading guide overlay to help track reading position.\n * Useful for text-heavy passages and questions.\n */\nexport const lineReaderToolRegistration: ToolRegistration = {\n\ttoolId: \"lineReader\",\n\tname: \"Line Reader\",\n\tdescription: \"Reading guide overlay\",\n\ticon: \"bars-3\",\n\n\t// Line reader appears where there's text to read\n\tsupportedLevels: [\"section\", \"passage\", \"rubric\", \"item\"],\n\n\t// PNP support IDs\n\t// Maps to QTI 3.0 standard features: readingMask, readingGuide, readingRuler\n\tpnpSupportIds: [\n\t\t\"readingMask\", // QTI 3.0 standard (reading.readingMask)\n\t\t\"readingGuide\", // QTI 3.0 standard (reading.readingGuide)\n\t\t\"readingRuler\", // QTI 3.0 standard (reading.readingRuler)\n\t\t\"lineReader\", // Common variant\n\t\t\"trackingGuide\", // Common variant\n\t],\n\n\t/**\n\t * Pass 2: Line reader is relevant when readable text is present\n\t */\n\tisVisibleInContext(context: ToolContext): boolean {\n\t\treturn hasReadableText(context);\n\t},\n\n\trenderToolbar(\n\t\tcontext: ToolContext,\n\t\ttoolbarContext: ToolbarContext,\n\t): ToolToolbarRenderResult {\n\t\tconst visibility = createScopedVisibilityBinding(\n\t\t\tthis.toolId,\n\t\t\ttoolbarContext,\n\t\t);\n\t\tconst button: ToolToolbarButtonDefinition = {\n\t\t\ttoolId: this.toolId,\n\t\t\tlabel: this.name,\n\t\t\ticon: typeof this.icon === \"function\" ? this.icon(context) : this.icon,\n\t\t\tdisabled: false,\n\t\t\tariaLabel: \"Line reader - Reading guide\",\n\t\t\ttooltip: \"Line Reader\",\n\t\t\tonClick: () => toolbarContext.toggleTool(this.toolId),\n\t\t\tactive: visibility.isActive(),\n\t\t};\n\t\tconst componentOverrides =\n\t\t\t(toolbarContext.componentOverrides as\n\t\t\t\t| ToolComponentOverrides\n\t\t\t\t| undefined) ?? {};\n\t\tconst overlay = createToolElement(\n\t\t\tthis.toolId,\n\t\t\tcontext,\n\t\t\ttoolbarContext,\n\t\t\tcomponentOverrides,\n\t\t) as HTMLElement & {\n\t\t\tvisible?: boolean;\n\t\t\ttoolId?: string;\n\t\t\ttoolkitCoordinator: unknown;\n\t\t};\n\t\toverlay.setAttribute(\"tool-id\", visibility.fullToolId);\n\t\tapplyOverlaySurface(overlay, \"frameless\");\n\t\treturn {\n\t\t\ttoolId: this.toolId,\n\t\t\tbutton,\n\t\t\telements: [{ element: overlay, mount: \"after-buttons\" }],\n\t\t\tsync: () => {\n\t\t\t\tsyncButtonAndOverlayVisibility({\n\t\t\t\t\tbutton,\n\t\t\t\t\toverlay,\n\t\t\t\t\tisActive: visibility.isActive,\n\t\t\t\t});\n\t\t\t\tif (toolbarContext.toolkitCoordinator) {\n\t\t\t\t\toverlay.toolkitCoordinator = toolbarContext.toolkitCoordinator;\n\t\t\t\t}\n\t\t\t},\n\t\t\tsubscribeActive: visibility.subscribeActive,\n\t\t};\n\t},\n};\n\n/**\n * Theme tool registration\n *\n * Provides accessible theme and contrast controls.\n * Global tool that affects entire assessment.\n */\nexport const themeToolRegistration: ToolRegistration = {\n\ttoolId: \"theme\",\n\tname: \"Theme\",\n\tdescription: \"Accessible themes and contrast\",\n\ticon: \"swatch\",\n\n\t// Color scheme is assessment-wide\n\tsupportedLevels: [\"assessment\", \"section\"],\n\n\t// PNP support IDs\n\t// Maps to QTI 3.0 standard features: highContrastDisplay, colorContrast, invertColors\n\tpnpSupportIds: [\n\t\t\"highContrastDisplay\", // QTI 3.0 standard (visual.highContrastDisplay)\n\t\t\"colorContrast\", // QTI 3.0 standard (visual.colorContrast)\n\t\t\"invertColors\", // QTI 3.0 standard (visual.invertColors)\n\t\t\"theme\", // Canonical id\n\t\t\"highContrast\", // Common variant\n\t\t\"customColors\", // Common variant\n\t],\n\n\t/**\n\t * Pass 2: Color scheme is always relevant when allowed\n\t */\n\tisVisibleInContext(context: ToolContext): boolean {\n\t\treturn true; // Always show if allowed by orchestrator\n\t},\n\n\trenderToolbar(\n\t\tcontext: ToolContext,\n\t\ttoolbarContext: ToolbarContext,\n\t): ToolToolbarRenderResult {\n\t\tconst visibility = createScopedVisibilityBinding(\n\t\t\tthis.toolId,\n\t\t\ttoolbarContext,\n\t\t);\n\t\tconst button: ToolToolbarButtonDefinition = {\n\t\t\ttoolId: this.toolId,\n\t\t\tlabel: this.name,\n\t\t\ticon: typeof this.icon === \"function\" ? this.icon(context) : this.icon,\n\t\t\tdisabled: false,\n\t\t\tariaLabel: \"Theme - Change colors and contrast\",\n\t\t\ttooltip: \"Theme\",\n\t\t\tonClick: () => toolbarContext.toggleTool(this.toolId),\n\t\t\tactive: visibility.isActive(),\n\t\t};\n\t\tconst componentOverrides =\n\t\t\t(toolbarContext.componentOverrides as\n\t\t\t\t| ToolComponentOverrides\n\t\t\t\t| undefined) ?? {};\n\t\tconst overlay = createToolElement(\n\t\t\tthis.toolId,\n\t\t\tcontext,\n\t\t\ttoolbarContext,\n\t\t\tcomponentOverrides,\n\t\t) as HTMLElement & {\n\t\t\tvisible?: boolean;\n\t\t\ttoolId?: string;\n\t\t\ttoolkitCoordinator: unknown;\n\t\t};\n\t\toverlay.setAttribute(\"tool-id\", visibility.fullToolId);\n\t\treturn {\n\t\t\ttoolId: this.toolId,\n\t\t\tbutton,\n\t\t\telements: [\n\t\t\t\t{\n\t\t\t\t\telement: overlay,\n\t\t\t\t\tmount: \"after-buttons\",\n\t\t\t\t\tshell: {\n\t\t\t\t\t\ttitle: this.name,\n\t\t\t\t\t\tdraggable: true,\n\t\t\t\t\t\tresizable: false,\n\t\t\t\t\t\tcloseable: true,\n\t\t\t\t\t\tinitialWidth: 520,\n\t\t\t\t\t\tinitialHeight: 380,\n\t\t\t\t\t\tminWidth: 420,\n\t\t\t\t\t\tminHeight: 300,\n\t\t\t\t\t},\n\t\t\t\t},\n\t\t\t],\n\t\t\tsync: () => {\n\t\t\t\tsyncButtonAndOverlayVisibility({\n\t\t\t\t\tbutton,\n\t\t\t\t\toverlay,\n\t\t\t\t\tisActive: visibility.isActive,\n\t\t\t\t});\n\t\t\t\tif (toolbarContext.toolkitCoordinator) {\n\t\t\t\t\toverlay.toolkitCoordinator = toolbarContext.toolkitCoordinator;\n\t\t\t\t}\n\t\t\t},\n\t\t\tsubscribeActive: visibility.subscribeActive,\n\t\t};\n\t},\n};\n\n/**\n * Annotation Toolbar registration\n *\n * Text highlighting with CSS Custom Highlight API.\n * Zero DOM mutation, optimal performance.\n */\nexport const annotationToolbarRegistration: ToolRegistration = {\n\ttoolId: \"annotationToolbar\",\n\tname: \"Highlighter\",\n\tdescription: \"Highlight and annotate text\",\n\ticon: \"highlighter\",\n\tactivation: \"selection-gateway\",\n\tsingletonScope: \"section\",\n\n\t// Annotation appears where there's text content\n\tsupportedLevels: [\"passage\", \"rubric\", \"item\", \"element\"],\n\n\t// PNP support IDs\n\t// Maps to QTI 3.0 standard features: highlighting, annotations\n\tpnpSupportIds: [\n\t\t\"highlighting\", // QTI 3.0 standard (cognitive.highlighting / reading.wordHighlighting)\n\t\t\"annotations\", // QTI 3.0 standard (cognitive.annotations)\n\t\t\"highlighter\", // Common variant\n\t\t\"textHighlight\", // Common variant\n\t\t\"annotation\", // Common variant\n\t],\n\n\t/**\n\t * Pass 2: Annotation is relevant when readable text is present\n\t */\n\tisVisibleInContext(context: ToolContext): boolean {\n\t\treturn hasReadableText(context);\n\t},\n\n\trenderToolbar(\n\t\tcontext: ToolContext,\n\t\ttoolbarContext: ToolbarContext,\n\t): ToolToolbarRenderResult {\n\t\tconst visibility = createScopedVisibilityBinding(\n\t\t\tthis.toolId,\n\t\t\ttoolbarContext,\n\t\t);\n\t\tconst button: ToolToolbarButtonDefinition = {\n\t\t\ttoolId: this.toolId,\n\t\t\tlabel: this.name,\n\t\t\ticon: typeof this.icon === \"function\" ? this.icon(context) : this.icon,\n\t\t\tdisabled: false,\n\t\t\tariaLabel: \"Annotation toolbar - Highlight text\",\n\t\t\ttooltip: \"Highlight\",\n\t\t\tonClick: () => toolbarContext.toggleTool(this.toolId),\n\t\t\tactive: visibility.isActive(),\n\t\t};\n\t\tconst componentOverrides =\n\t\t\t(toolbarContext.componentOverrides as\n\t\t\t\t| ToolComponentOverrides\n\t\t\t\t| undefined) ?? {};\n\t\tconst overlay = createToolElement(\n\t\t\tthis.toolId,\n\t\t\tcontext,\n\t\t\ttoolbarContext,\n\t\t\tcomponentOverrides,\n\t\t) as HTMLElement & {\n\t\t\tvisible?: boolean;\n\t\t\ttoolId?: string;\n\t\t\ttoolkitCoordinator: unknown;\n\t\t};\n\t\toverlay.setAttribute(\"tool-id\", visibility.fullToolId);\n\t\treturn {\n\t\t\ttoolId: this.toolId,\n\t\t\tbutton,\n\t\t\telements: [{ element: overlay, mount: \"after-buttons\" }],\n\t\t\tsync: () => {\n\t\t\t\tsyncButtonAndOverlayVisibility({\n\t\t\t\t\tbutton,\n\t\t\t\t\toverlay,\n\t\t\t\t\tisActive: visibility.isActive,\n\t\t\t\t});\n\t\t\t\tif (toolbarContext.toolkitCoordinator) {\n\t\t\t\t\toverlay.toolkitCoordinator = toolbarContext.toolkitCoordinator;\n\t\t\t\t}\n\t\t\t},\n\t\t\tsubscribeActive: visibility.subscribeActive,\n\t\t};\n\t},\n};\n"]}
@@ -189,7 +189,7 @@ export const calculatorToolRegistration = {
189
189
  initialHeight: 420,
190
190
  minWidth: 380,
191
191
  minHeight: 420,
192
- initialAlign: 'bottom-right',
192
+ initialAlign: "bottom-right",
193
193
  initialMargin: 16,
194
194
  },
195
195
  },
@@ -1 +1 @@
1
- {"version":3,"file":"calculator.js","sourceRoot":"","sources":["../../../src/tools/registrations/calculator.ts"],"names":[],"mappings":"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","sourcesContent":["/**\n * Calculator Tool Registration\n *\n * Registers the calculator tool with support for multiple calculator types\n * (basic, scientific, graphing) via Desmos provider.\n *\n * Maps to QTI 3.0 standard access features:\n * - calculator (cognitive support)\n * - graphingCalculator (assessment tool)\n */\n\nimport type {\n\tToolRegistration,\n\tToolToolbarButtonDefinition,\n\tToolToolbarRenderResult,\n\tToolbarContext,\n} from \"../../services/ToolRegistry.js\";\nimport type { ToolCoordinatorApi } from \"../../services/interfaces.js\";\nimport type { ToolProviderConfig } from \"../../services/tools-config-normalizer.js\";\nimport type { ToolContext } from \"../../services/tool-context.js\";\nimport { hasMathContent } from \"../../services/tool-context.js\";\nimport { createScopedToolId } from \"../../services/tool-instance-id.js\";\nimport { DesmosToolProvider } from \"../../services/tool-providers/index.js\";\nimport { createToolElement } from \"../tool-tag-map.js\";\n\ntype CalculatorType = \"basic\" | \"scientific\";\n\n// The toolbar parent re-derives `renderedTools` whenever item state changes\n// (e.g. the learner answers a question and `effectiveItem`/`renderContext`\n// recompute). Calculator initialization is expensive (Desmos boot, container\n// mount), so we cache the overlay element by coordinator + scoped tool id.\n// Reusing the same element keeps `mountContent` a no-op and avoids tearing\n// down and re-initializing the calculator on every re-render.\nconst overlayElementCache = new WeakMap<\n\tToolCoordinatorApi,\n\tMap<string, HTMLElement>\n>();\n\nfunction getCachedOverlay(\n\tcoordinator: ToolCoordinatorApi | null,\n\tfullToolId: string,\n): HTMLElement | null {\n\tif (!coordinator) return null;\n\tconst scoped = overlayElementCache.get(coordinator);\n\tconst element = scoped?.get(fullToolId);\n\tif (!element) return null;\n\t// Svelte custom elements destroy their component when disconnected.\n\t// A detached cached element is a dead instance — drop it and recreate.\n\tif (!element.isConnected) {\n\t\tscoped?.delete(fullToolId);\n\t\treturn null;\n\t}\n\treturn element;\n}\n\nfunction setCachedOverlay(\n\tcoordinator: ToolCoordinatorApi | null,\n\tfullToolId: string,\n\telement: HTMLElement,\n): void {\n\tif (!coordinator) return;\n\tlet scoped = overlayElementCache.get(coordinator);\n\tif (!scoped) {\n\t\tscoped = new Map();\n\t\toverlayElementCache.set(coordinator, scoped);\n\t}\n\tscoped.set(fullToolId, element);\n}\n\nfunction normalizeCalculatorType(value: unknown): CalculatorType | null {\n\treturn value === \"basic\" || value === \"scientific\" ? value : null;\n}\n\nfunction getCalculatorRenderParams(toolbarContext: ToolbarContext): {\n\tcalculatorType: CalculatorType | null;\n\tavailableTypes: CalculatorType[] | null;\n\tdisplayName: string;\n} {\n\tconst params = toolbarContext.getToolRenderParams?.(\"calculator\") ?? {};\n\tconst calculatorType = normalizeCalculatorType(params.calculatorType);\n\tconst availableTypesRaw = params.availableTypes;\n\tconst availableTypes = Array.isArray(availableTypesRaw)\n\t\t? availableTypesRaw\n\t\t\t\t.map((value) => normalizeCalculatorType(value))\n\t\t\t\t.filter((value): value is CalculatorType => value !== null)\n\t\t: calculatorType\n\t\t\t? [calculatorType]\n\t\t\t: null;\n\n\treturn {\n\t\tcalculatorType,\n\t\tavailableTypes,\n\t\tdisplayName:\n\t\t\tcalculatorType === \"scientific\"\n\t\t\t\t? \"Scientific Calculator\"\n\t\t\t\t: calculatorType === \"basic\"\n\t\t\t\t\t? \"Basic Calculator\"\n\t\t\t\t\t: \"Calculator\",\n\t};\n}\n\nfunction applyCalculatorParamsToElement(\n\telement: HTMLElement,\n\tcalculatorType: CalculatorType | null,\n\tavailableTypes: CalculatorType[] | null,\n): void {\n\tconst calculatorElement = element as HTMLElement & {\n\t\tcalculatorType?: CalculatorType;\n\t\tavailableTypes?: CalculatorType[];\n\t};\n\n\tif (calculatorType) {\n\t\tcalculatorElement.calculatorType = calculatorType;\n\t\telement.setAttribute(\"calculator-type\", calculatorType);\n\t} else {\n\t\tdelete calculatorElement.calculatorType;\n\t\telement.removeAttribute(\"calculator-type\");\n\t}\n\n\tif (availableTypes && availableTypes.length > 0) {\n\t\tcalculatorElement.availableTypes = availableTypes;\n\t} else {\n\t\tdelete calculatorElement.availableTypes;\n\t}\n}\n\n/**\n * Calculator tool registration\n *\n * Supports:\n * - Basic, scientific, and graphing calculators via Desmos\n * - Context-aware visibility (shows only when math content is detected)\n * - Item level only\n */\nexport const calculatorToolRegistration: ToolRegistration = {\n\ttoolId: \"calculator\",\n\tname: \"Calculator\",\n\tdescription: \"Multi-type calculator (basic, scientific, graphing)\",\n\ticon: \"calculator\",\n\tprovider: {\n\t\tgetProviderId: (config: ToolProviderConfig | undefined) =>\n\t\t\ttypeof config?.provider?.id === \"string\" && config.provider.id.length > 0\n\t\t\t\t? config.provider.id\n\t\t\t\t: \"calculator-desmos\",\n\t\tcreateProvider: () => new DesmosToolProvider(),\n\t\tgetInitConfig: (config: ToolProviderConfig | undefined) =>\n\t\t\tconfig?.provider?.init ?? {},\n\t\tgetAuthFetcher: (config: ToolProviderConfig | undefined) => {\n\t\t\tconst runtimeAuthFetcher = config?.provider?.runtime?.authFetcher;\n\t\t\tif (typeof runtimeAuthFetcher === \"function\") return runtimeAuthFetcher;\n\t\t\treturn async () => {\n\t\t\t\tconst response = await fetch(\"/api/tools/desmos/auth\", {\n\t\t\t\t\tmethod: \"GET\",\n\t\t\t\t\tcredentials: \"same-origin\",\n\t\t\t\t});\n\t\t\t\tif (!response.ok) {\n\t\t\t\t\tthrow new Error(\n\t\t\t\t\t\t`Failed to fetch Desmos auth config (${response.status})`,\n\t\t\t\t\t);\n\t\t\t\t}\n\t\t\t\treturn (await response.json()) as Record<string, unknown>;\n\t\t\t};\n\t\t},\n\t\tlazy: true,\n\t},\n\n\t// Calculator is item-level in this player architecture.\n\tsupportedLevels: [\"item\"],\n\n\t// PNP support IDs that enable this tool\n\t// Maps to QTI 3.0 standard features: calculator, graphingCalculator\n\tpnpSupportIds: [\n\t\t\"calculator\", // QTI 3.0 standard (cognitive.calculator)\n\t\t\"graphingCalculator\", // QTI 3.0 standard (assessment.graphingCalculator)\n\t\t\"basicCalculator\", // Common variant\n\t\t\"scientificCalculator\", // Common variant\n\t],\n\n\t/**\n\t * Pass 2: Determine if calculator is relevant in this context\n\t *\n\t * Calculator is relevant when context contains mathematical content\n\t * (MathML, LaTeX, arithmetic markers).\n\t */\n\tisVisibleInContext(context: ToolContext): boolean {\n\t\t// Show only when math is present in item content.\n\t\treturn hasMathContent(context);\n\t},\n\n\trenderToolbar(\n\t\tcontext: ToolContext,\n\t\ttoolbarContext: ToolbarContext,\n\t): ToolToolbarRenderResult {\n\t\tconst { calculatorType, availableTypes, displayName } =\n\t\t\tgetCalculatorRenderParams(toolbarContext);\n\t\tconst fullToolId = createScopedToolId(\n\t\t\tthis.toolId,\n\t\t\ttoolbarContext.scope.level,\n\t\t\ttoolbarContext.scope.scopeId,\n\t\t);\n\t\tconst componentOverrides = toolbarContext.componentOverrides;\n\t\tconst cachedOverlay = getCachedOverlay(\n\t\t\ttoolbarContext.toolCoordinator,\n\t\t\tfullToolId,\n\t\t);\n\t\tconst overlay = (cachedOverlay ??\n\t\t\tcreateToolElement(\n\t\t\t\tthis.toolId,\n\t\t\t\tcontext,\n\t\t\t\ttoolbarContext,\n\t\t\t\tcomponentOverrides,\n\t\t\t)) as HTMLElement & {\n\t\t\tvisible?: boolean;\n\t\t\ttoolId?: string;\n\t\t\ttoolkitCoordinator?: unknown;\n\t\t};\n\t\tif (!cachedOverlay) {\n\t\t\tsetCachedOverlay(toolbarContext.toolCoordinator, fullToolId, overlay);\n\t\t}\n\t\toverlay.setAttribute(\"tool-id\", fullToolId);\n\t\toverlay.toolkitCoordinator = toolbarContext.toolkitCoordinator;\n\t\tapplyCalculatorParamsToElement(overlay, calculatorType, availableTypes);\n\t\tconst openLabel =\n\t\t\tcalculatorType === null\n\t\t\t\t? \"Open scientific calculator\"\n\t\t\t\t: `Open ${displayName.toLowerCase()}`;\n\t\tconst closeLabel =\n\t\t\tcalculatorType === null\n\t\t\t\t? \"Close scientific calculator\"\n\t\t\t\t: `Close ${displayName.toLowerCase()}`;\n\t\tconst button: ToolToolbarButtonDefinition = {\n\t\t\ttoolId: this.toolId,\n\t\t\tlabel: displayName,\n\t\t\ticon: typeof this.icon === \"function\" ? this.icon(context) : this.icon,\n\t\t\tdisabled: false,\n\t\t\tariaLabel: openLabel,\n\t\t\ttooltip: displayName,\n\t\t\tonClick: () => toolbarContext.toggleTool(this.toolId),\n\t\t\tactive: toolbarContext.isToolVisible(fullToolId),\n\t\t};\n\t\tlet lastVisibleState: boolean | undefined = button.active;\n\t\tif (overlay.visible !== button.active) {\n\t\t\toverlay.visible = button.active;\n\t\t}\n\n\t\treturn {\n\t\t\ttoolId: this.toolId,\n\t\t\telements: [\n\t\t\t\t{\n\t\t\t\t\telement: overlay,\n\t\t\t\t\tmount: \"after-buttons\",\n\t\t\t\t\tshell: {\n\t\t\t\t\t\ttitle: this.name,\n\t\t\t\t\t\tdraggable: true,\n\t\t\t\t\t\tresizable: true,\n\t\t\t\t\t\tcloseable: true,\n\t\t\t\t\t\tinitialWidth: 380,\n\t\t\t\t\t\tinitialHeight: 420,\n\t\t\t\t\t\tminWidth: 380,\n\t\t\t\t\t\tminHeight: 420,\n\t\t\t\t\t\tinitialAlign: 'bottom-right',\n\t\t\t\t\t\tinitialMargin: 16,\n\t\t\t\t\t},\n\t\t\t\t},\n\t\t\t],\n\t\t\tbutton,\n\t\t\tsync: () => {\n\t\t\t\tconst active = toolbarContext.isToolVisible(fullToolId);\n\t\t\t\tbutton.active = active;\n\t\t\t\tbutton.label = displayName;\n\t\t\t\tbutton.ariaLabel = active ? closeLabel : openLabel;\n\t\t\t\tbutton.tooltip = active\n\t\t\t\t\t? `Close ${displayName.toLowerCase()}`\n\t\t\t\t\t: displayName;\n\t\t\t\tif (lastVisibleState !== active) {\n\t\t\t\t\toverlay.visible = active;\n\t\t\t\t\tlastVisibleState = active;\n\t\t\t\t}\n\t\t\t\tif (overlay.toolkitCoordinator !== toolbarContext.toolkitCoordinator) {\n\t\t\t\t\toverlay.toolkitCoordinator = toolbarContext.toolkitCoordinator;\n\t\t\t\t}\n\t\t\t\tapplyCalculatorParamsToElement(overlay, calculatorType, availableTypes);\n\t\t\t},\n\t\t\tsubscribeActive: (callback: (active: boolean) => void) => {\n\t\t\t\tif (!toolbarContext.subscribeVisibility) return () => {};\n\t\t\t\treturn toolbarContext.subscribeVisibility(() => {\n\t\t\t\t\tcallback(toolbarContext.isToolVisible(fullToolId));\n\t\t\t\t});\n\t\t\t},\n\t\t};\n\t},\n};\n"]}
1
+ {"version":3,"file":"calculator.js","sourceRoot":"","sources":["../../../src/tools/registrations/calculator.ts"],"names":[],"mappings":"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","sourcesContent":["/**\n * Calculator Tool Registration\n *\n * Registers the calculator tool with support for multiple calculator types\n * (basic, scientific, graphing) via Desmos provider.\n *\n * Maps to QTI 3.0 standard access features:\n * - calculator (cognitive support)\n * - graphingCalculator (assessment tool)\n */\n\nimport type {\n\tToolRegistration,\n\tToolToolbarButtonDefinition,\n\tToolToolbarRenderResult,\n\tToolbarContext,\n} from \"../../services/ToolRegistry.js\";\nimport type { ToolCoordinatorApi } from \"../../services/interfaces.js\";\nimport type { ToolProviderConfig } from \"../../services/tools-config-normalizer.js\";\nimport type { ToolContext } from \"../../services/tool-context.js\";\nimport { hasMathContent } from \"../../services/tool-context.js\";\nimport { createScopedToolId } from \"../../services/tool-instance-id.js\";\nimport { DesmosToolProvider } from \"../../services/tool-providers/index.js\";\nimport { createToolElement } from \"../tool-tag-map.js\";\n\ntype CalculatorType = \"basic\" | \"scientific\";\n\n// The toolbar parent re-derives `renderedTools` whenever item state changes\n// (e.g. the learner answers a question and `effectiveItem`/`renderContext`\n// recompute). Calculator initialization is expensive (Desmos boot, container\n// mount), so we cache the overlay element by coordinator + scoped tool id.\n// Reusing the same element keeps `mountContent` a no-op and avoids tearing\n// down and re-initializing the calculator on every re-render.\nconst overlayElementCache = new WeakMap<\n\tToolCoordinatorApi,\n\tMap<string, HTMLElement>\n>();\n\nfunction getCachedOverlay(\n\tcoordinator: ToolCoordinatorApi | null,\n\tfullToolId: string,\n): HTMLElement | null {\n\tif (!coordinator) return null;\n\tconst scoped = overlayElementCache.get(coordinator);\n\tconst element = scoped?.get(fullToolId);\n\tif (!element) return null;\n\t// Svelte custom elements destroy their component when disconnected.\n\t// A detached cached element is a dead instance — drop it and recreate.\n\tif (!element.isConnected) {\n\t\tscoped?.delete(fullToolId);\n\t\treturn null;\n\t}\n\treturn element;\n}\n\nfunction setCachedOverlay(\n\tcoordinator: ToolCoordinatorApi | null,\n\tfullToolId: string,\n\telement: HTMLElement,\n): void {\n\tif (!coordinator) return;\n\tlet scoped = overlayElementCache.get(coordinator);\n\tif (!scoped) {\n\t\tscoped = new Map();\n\t\toverlayElementCache.set(coordinator, scoped);\n\t}\n\tscoped.set(fullToolId, element);\n}\n\nfunction normalizeCalculatorType(value: unknown): CalculatorType | null {\n\treturn value === \"basic\" || value === \"scientific\" ? value : null;\n}\n\nfunction getCalculatorRenderParams(toolbarContext: ToolbarContext): {\n\tcalculatorType: CalculatorType | null;\n\tavailableTypes: CalculatorType[] | null;\n\tdisplayName: string;\n} {\n\tconst params = toolbarContext.getToolRenderParams?.(\"calculator\") ?? {};\n\tconst calculatorType = normalizeCalculatorType(params.calculatorType);\n\tconst availableTypesRaw = params.availableTypes;\n\tconst availableTypes = Array.isArray(availableTypesRaw)\n\t\t? availableTypesRaw\n\t\t\t\t.map((value) => normalizeCalculatorType(value))\n\t\t\t\t.filter((value): value is CalculatorType => value !== null)\n\t\t: calculatorType\n\t\t\t? [calculatorType]\n\t\t\t: null;\n\n\treturn {\n\t\tcalculatorType,\n\t\tavailableTypes,\n\t\tdisplayName:\n\t\t\tcalculatorType === \"scientific\"\n\t\t\t\t? \"Scientific Calculator\"\n\t\t\t\t: calculatorType === \"basic\"\n\t\t\t\t\t? \"Basic Calculator\"\n\t\t\t\t\t: \"Calculator\",\n\t};\n}\n\nfunction applyCalculatorParamsToElement(\n\telement: HTMLElement,\n\tcalculatorType: CalculatorType | null,\n\tavailableTypes: CalculatorType[] | null,\n): void {\n\tconst calculatorElement = element as HTMLElement & {\n\t\tcalculatorType?: CalculatorType;\n\t\tavailableTypes?: CalculatorType[];\n\t};\n\n\tif (calculatorType) {\n\t\tcalculatorElement.calculatorType = calculatorType;\n\t\telement.setAttribute(\"calculator-type\", calculatorType);\n\t} else {\n\t\tdelete calculatorElement.calculatorType;\n\t\telement.removeAttribute(\"calculator-type\");\n\t}\n\n\tif (availableTypes && availableTypes.length > 0) {\n\t\tcalculatorElement.availableTypes = availableTypes;\n\t} else {\n\t\tdelete calculatorElement.availableTypes;\n\t}\n}\n\n/**\n * Calculator tool registration\n *\n * Supports:\n * - Basic, scientific, and graphing calculators via Desmos\n * - Context-aware visibility (shows only when math content is detected)\n * - Item level only\n */\nexport const calculatorToolRegistration: ToolRegistration = {\n\ttoolId: \"calculator\",\n\tname: \"Calculator\",\n\tdescription: \"Multi-type calculator (basic, scientific, graphing)\",\n\ticon: \"calculator\",\n\tprovider: {\n\t\tgetProviderId: (config: ToolProviderConfig | undefined) =>\n\t\t\ttypeof config?.provider?.id === \"string\" && config.provider.id.length > 0\n\t\t\t\t? config.provider.id\n\t\t\t\t: \"calculator-desmos\",\n\t\tcreateProvider: () => new DesmosToolProvider(),\n\t\tgetInitConfig: (config: ToolProviderConfig | undefined) =>\n\t\t\tconfig?.provider?.init ?? {},\n\t\tgetAuthFetcher: (config: ToolProviderConfig | undefined) => {\n\t\t\tconst runtimeAuthFetcher = config?.provider?.runtime?.authFetcher;\n\t\t\tif (typeof runtimeAuthFetcher === \"function\") return runtimeAuthFetcher;\n\t\t\treturn async () => {\n\t\t\t\tconst response = await fetch(\"/api/tools/desmos/auth\", {\n\t\t\t\t\tmethod: \"GET\",\n\t\t\t\t\tcredentials: \"same-origin\",\n\t\t\t\t});\n\t\t\t\tif (!response.ok) {\n\t\t\t\t\tthrow new Error(\n\t\t\t\t\t\t`Failed to fetch Desmos auth config (${response.status})`,\n\t\t\t\t\t);\n\t\t\t\t}\n\t\t\t\treturn (await response.json()) as Record<string, unknown>;\n\t\t\t};\n\t\t},\n\t\tlazy: true,\n\t},\n\n\t// Calculator is item-level in this player architecture.\n\tsupportedLevels: [\"item\"],\n\n\t// PNP support IDs that enable this tool\n\t// Maps to QTI 3.0 standard features: calculator, graphingCalculator\n\tpnpSupportIds: [\n\t\t\"calculator\", // QTI 3.0 standard (cognitive.calculator)\n\t\t\"graphingCalculator\", // QTI 3.0 standard (assessment.graphingCalculator)\n\t\t\"basicCalculator\", // Common variant\n\t\t\"scientificCalculator\", // Common variant\n\t],\n\n\t/**\n\t * Pass 2: Determine if calculator is relevant in this context\n\t *\n\t * Calculator is relevant when context contains mathematical content\n\t * (MathML, LaTeX, arithmetic markers).\n\t */\n\tisVisibleInContext(context: ToolContext): boolean {\n\t\t// Show only when math is present in item content.\n\t\treturn hasMathContent(context);\n\t},\n\n\trenderToolbar(\n\t\tcontext: ToolContext,\n\t\ttoolbarContext: ToolbarContext,\n\t): ToolToolbarRenderResult {\n\t\tconst { calculatorType, availableTypes, displayName } =\n\t\t\tgetCalculatorRenderParams(toolbarContext);\n\t\tconst fullToolId = createScopedToolId(\n\t\t\tthis.toolId,\n\t\t\ttoolbarContext.scope.level,\n\t\t\ttoolbarContext.scope.scopeId,\n\t\t);\n\t\tconst componentOverrides = toolbarContext.componentOverrides;\n\t\tconst cachedOverlay = getCachedOverlay(\n\t\t\ttoolbarContext.toolCoordinator,\n\t\t\tfullToolId,\n\t\t);\n\t\tconst overlay = (cachedOverlay ??\n\t\t\tcreateToolElement(\n\t\t\t\tthis.toolId,\n\t\t\t\tcontext,\n\t\t\t\ttoolbarContext,\n\t\t\t\tcomponentOverrides,\n\t\t\t)) as HTMLElement & {\n\t\t\tvisible?: boolean;\n\t\t\ttoolId?: string;\n\t\t\ttoolkitCoordinator?: unknown;\n\t\t};\n\t\tif (!cachedOverlay) {\n\t\t\tsetCachedOverlay(toolbarContext.toolCoordinator, fullToolId, overlay);\n\t\t}\n\t\toverlay.setAttribute(\"tool-id\", fullToolId);\n\t\toverlay.toolkitCoordinator = toolbarContext.toolkitCoordinator;\n\t\tapplyCalculatorParamsToElement(overlay, calculatorType, availableTypes);\n\t\tconst openLabel =\n\t\t\tcalculatorType === null\n\t\t\t\t? \"Open scientific calculator\"\n\t\t\t\t: `Open ${displayName.toLowerCase()}`;\n\t\tconst closeLabel =\n\t\t\tcalculatorType === null\n\t\t\t\t? \"Close scientific calculator\"\n\t\t\t\t: `Close ${displayName.toLowerCase()}`;\n\t\tconst button: ToolToolbarButtonDefinition = {\n\t\t\ttoolId: this.toolId,\n\t\t\tlabel: displayName,\n\t\t\ticon: typeof this.icon === \"function\" ? this.icon(context) : this.icon,\n\t\t\tdisabled: false,\n\t\t\tariaLabel: openLabel,\n\t\t\ttooltip: displayName,\n\t\t\tonClick: () => toolbarContext.toggleTool(this.toolId),\n\t\t\tactive: toolbarContext.isToolVisible(fullToolId),\n\t\t};\n\t\tlet lastVisibleState: boolean | undefined = button.active;\n\t\tif (overlay.visible !== button.active) {\n\t\t\toverlay.visible = button.active;\n\t\t}\n\n\t\treturn {\n\t\t\ttoolId: this.toolId,\n\t\t\telements: [\n\t\t\t\t{\n\t\t\t\t\telement: overlay,\n\t\t\t\t\tmount: \"after-buttons\",\n\t\t\t\t\tshell: {\n\t\t\t\t\t\ttitle: this.name,\n\t\t\t\t\t\tdraggable: true,\n\t\t\t\t\t\tresizable: true,\n\t\t\t\t\t\tcloseable: true,\n\t\t\t\t\t\tinitialWidth: 380,\n\t\t\t\t\t\tinitialHeight: 420,\n\t\t\t\t\t\tminWidth: 380,\n\t\t\t\t\t\tminHeight: 420,\n\t\t\t\t\t\tinitialAlign: \"bottom-right\",\n\t\t\t\t\t\tinitialMargin: 16,\n\t\t\t\t\t},\n\t\t\t\t},\n\t\t\t],\n\t\t\tbutton,\n\t\t\tsync: () => {\n\t\t\t\tconst active = toolbarContext.isToolVisible(fullToolId);\n\t\t\t\tbutton.active = active;\n\t\t\t\tbutton.label = displayName;\n\t\t\t\tbutton.ariaLabel = active ? closeLabel : openLabel;\n\t\t\t\tbutton.tooltip = active\n\t\t\t\t\t? `Close ${displayName.toLowerCase()}`\n\t\t\t\t\t: displayName;\n\t\t\t\tif (lastVisibleState !== active) {\n\t\t\t\t\toverlay.visible = active;\n\t\t\t\t\tlastVisibleState = active;\n\t\t\t\t}\n\t\t\t\tif (overlay.toolkitCoordinator !== toolbarContext.toolkitCoordinator) {\n\t\t\t\t\toverlay.toolkitCoordinator = toolbarContext.toolkitCoordinator;\n\t\t\t\t}\n\t\t\t\tapplyCalculatorParamsToElement(overlay, calculatorType, availableTypes);\n\t\t\t},\n\t\t\tsubscribeActive: (callback: (active: boolean) => void) => {\n\t\t\t\tif (!toolbarContext.subscribeVisibility) return () => {};\n\t\t\t\treturn toolbarContext.subscribeVisibility(() => {\n\t\t\t\t\tcallback(toolbarContext.isToolVisible(fullToolId));\n\t\t\t\t});\n\t\t\t},\n\t\t};\n\t},\n};\n"]}
@@ -1 +1 @@
1
- {"version":3,"file":"interaction-tools.js","sourceRoot":"","sources":["../../../src/tools/registrations/interaction-tools.ts"],"names":[],"mappings":"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","sourcesContent":["/**\n * Interaction Tools Registrations\n *\n * Registers tools for interacting with question content:\n * - Answer Eliminator (strike through answer choices)\n * - Highlighter (highlight text passages)\n *\n * Maps to QTI 3.0 standard access features:\n * - answerMasking (assessment tool)\n * - strikethrough (visual transformation)\n * - highlighting (cognitive/reading support)\n */\n\nimport type {\n\tToolRegistration,\n\tToolToolbarButtonDefinition,\n\tToolToolbarRenderResult,\n\tToolbarContext,\n} from \"../../services/ToolRegistry.js\";\nimport type { ToolContext } from \"../../services/tool-context.js\";\nimport {\n\thasChoiceInteraction,\n\thasReadableText,\n} from \"../../services/tool-context.js\";\nimport {\n\tcreateToolElement,\n\ttype ToolComponentOverrides,\n} from \"../tool-tag-map.js\";\nimport {\n\tcreateScopedVisibilityBinding,\n\tsyncButtonAndOverlayVisibility,\n} from \"./toolbar-registration-helpers.js\";\n\n/**\n * Answer Eliminator tool registration\n *\n * Allows students to strike through incorrect answer choices.\n * Only appears on multiple-choice style questions.\n */\nexport const answerEliminatorToolRegistration: ToolRegistration = {\n\ttoolId: \"answerEliminator\",\n\tname: \"Answer Eliminator\",\n\tdescription: \"Strike through answer choices\",\n\ticon: \"strikethrough\",\n\n\t// Answer eliminator appears at item level only\n\tsupportedLevels: [\"item\"],\n\n\t// PNP support IDs\n\t// Maps to QTI 3.0 standard feature: answerMasking\n\tpnpSupportIds: [\n\t\t\"answerMasking\", // QTI 3.0 standard (assessment.answerMasking)\n\t\t\"answerEliminator\", // QTI 3.0 standard (assessment.answerEliminator)\n\t\t\"strikethrough\", // Common variant\n\t\t\"choiceMasking\", // Common variant\n\t],\n\n\t/**\n\t * Pass 2: Answer eliminator is relevant only for choice-based questions\n\t */\n\tisVisibleInContext(context: ToolContext): boolean {\n\t\treturn hasChoiceInteraction(context);\n\t},\n\n\trenderToolbar(\n\t\tcontext: ToolContext,\n\t\ttoolbarContext: ToolbarContext,\n\t): ToolToolbarRenderResult {\n\t\tconst visibility = createScopedVisibilityBinding(this.toolId, toolbarContext);\n\t\tconst componentOverrides =\n\t\t\t(toolbarContext.componentOverrides as ToolComponentOverrides | undefined) ?? {};\n\t\tconst overlay = createToolElement(\n\t\t\tthis.toolId,\n\t\t\tcontext,\n\t\t\ttoolbarContext,\n\t\t\tcomponentOverrides,\n\t\t) as HTMLElement & {\n\t\t\tvisible?: boolean;\n\t\t\ttoolId?: string;\n\t\t\tcoordinator?: unknown;\n\t\t\telementToolStateStore?: unknown;\n\t\t\tglobalElementId?: string;\n\t\t\tscopeElement?: HTMLElement | null;\n\t\t};\n\t\toverlay.setAttribute(\"tool-id\", visibility.fullToolId);\n\t\toverlay.setAttribute(\"strategy\", \"strikethrough\");\n\t\toverlay.setAttribute(\"button-alignment\", \"inline\");\n\n\t\tconst button: ToolToolbarButtonDefinition = {\n\t\t\ttoolId: this.toolId,\n\t\t\tlabel: this.name,\n\t\t\ticon: '<svg xmlns=\"http://www.w3.org/2000/svg\" viewBox=\"0 0 24 24\" width=\"20\" height=\"20\" fill=\"currentColor\" aria-hidden=\"true\"><path d=\"M19,3H16.3H7.7H5A2,2 0 0,0 3,5V7.7V16.4V19A2,2 0 0,0 5,21H7.7H16.4H19A2,2 0 0,0 21,19V16.3V7.7V5A2,2 0 0,0 19,3M15.6,17L12,13.4L8.4,17L7,15.6L10.6,12L7,8.4L8.4,7L12,10.6L15.6,7L17,8.4L13.4,12L17,15.6L15.6,17Z\"/></svg>',\n\t\t\tdisabled: false,\n\t\t\tariaLabel: \"Answer eliminator - Strike through choices\",\n\t\t\ttooltip: \"Strike Through\",\n\t\t\tonClick: () => toolbarContext.toggleTool(this.toolId),\n\t\t\tactive: visibility.isActive(),\n\t\t};\n\n\t\treturn {\n\t\t\ttoolId: this.toolId,\n\t\t\tbutton,\n\t\t\telements: [{ element: overlay, mount: \"after-buttons\" }],\n\t\t\tsync: () => {\n\t\t\t\tsyncButtonAndOverlayVisibility({\n\t\t\t\t\tbutton,\n\t\t\t\t\toverlay,\n\t\t\t\t\tisActive: visibility.isActive,\n\t\t\t\t});\n\t\t\t\tif (toolbarContext.toolCoordinator) {\n\t\t\t\t\toverlay.coordinator = toolbarContext.toolCoordinator;\n\t\t\t\t}\n\t\t\t\toverlay.scopeElement = toolbarContext.getScopeElement?.() || null;\n\t\t\t\tif (toolbarContext.elementToolStateStore) {\n\t\t\t\t\toverlay.elementToolStateStore = toolbarContext.elementToolStateStore;\n\t\t\t\t}\n\t\t\t\tconst globalElementId = toolbarContext.getGlobalElementId?.();\n\t\t\t\tif (globalElementId) {\n\t\t\t\t\toverlay.globalElementId = globalElementId;\n\t\t\t\t}\n\t\t\t},\n\t\t\tsubscribeActive: visibility.subscribeActive,\n\t\t};\n\t},\n};\n\n/**\n * Highlighter tool registration\n *\n * Allows students to highlight text in passages and questions.\n * Appears on items with readable text content.\n */\nexport const highlighterToolRegistration: ToolRegistration = {\n\ttoolId: \"highlighter\",\n\tname: \"Highlighter\",\n\tdescription: \"Highlight text\",\n\ticon: \"highlighter\",\n\tactivation: \"toolbar-toggle\",\n\n\t// Highlighter appears at passage, rubric, item, and element levels\n\tsupportedLevels: [\"passage\", \"rubric\", \"item\", \"element\"],\n\n\t// PNP support IDs\n\tpnpSupportIds: [\"highlighter\", \"textHighlight\", \"annotation\"],\n\n\t/**\n\t * Pass 2: Highlighter is relevant when readable text is available\n\t */\n\tisVisibleInContext(context: ToolContext): boolean {\n\t\treturn hasReadableText(context);\n\t},\n\n\trenderToolbar(\n\t\tcontext: ToolContext,\n\t\ttoolbarContext: ToolbarContext,\n\t): ToolToolbarRenderResult {\n\t\tconst visibility = createScopedVisibilityBinding(this.toolId, toolbarContext);\n\t\tconst button: ToolToolbarButtonDefinition = {\n\t\t\ttoolId: this.toolId,\n\t\t\tlabel: this.name,\n\t\t\ticon: typeof this.icon === \"function\" ? this.icon(context) : this.icon,\n\t\t\tdisabled: false,\n\t\t\tariaLabel: \"Highlighter - Highlight text\",\n\t\t\ttooltip: \"Highlight\",\n\t\t\tonClick: () => toolbarContext.toggleTool(this.toolId),\n\t\t\tactive: visibility.isActive(),\n\t\t};\n\t\tconst componentOverrides =\n\t\t\t(toolbarContext.componentOverrides as ToolComponentOverrides | undefined) ?? {};\n\t\tconst overlay = createToolElement(\n\t\t\tthis.toolId,\n\t\t\tcontext,\n\t\t\ttoolbarContext,\n\t\t\tcomponentOverrides,\n\t\t) as HTMLElement & {\n\t\t\tenabled?: boolean;\n\t\t\tvisible?: boolean;\n\t\t\ttoolId?: string;\n\t\t\thighlightCoordinator?: unknown;\n\t\t\tttsService?: unknown;\n\t\t};\n\t\toverlay.setAttribute(\"tool-id\", visibility.fullToolId);\n\t\treturn {\n\t\t\ttoolId: this.toolId,\n\t\t\tbutton,\n\t\t\telements: [{ element: overlay, mount: \"after-buttons\" }],\n\t\t\tsync: () => {\n\t\t\t\tsyncButtonAndOverlayVisibility({\n\t\t\t\t\tbutton,\n\t\t\t\t\toverlay,\n\t\t\t\t\tisActive: visibility.isActive,\n\t\t\t\t\tonActiveChange: (active) => {\n\t\t\t\t\t\toverlay.enabled = active;\n\t\t\t\t\t},\n\t\t\t\t});\n\t\t\t\tif (toolbarContext.ttsService) {\n\t\t\t\t\toverlay.ttsService = toolbarContext.ttsService;\n\t\t\t\t}\n\t\t\t},\n\t\t\tsubscribeActive: visibility.subscribeActive,\n\t\t};\n\t},\n};\n"]}
1
+ {"version":3,"file":"interaction-tools.js","sourceRoot":"","sources":["../../../src/tools/registrations/interaction-tools.ts"],"names":[],"mappings":"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","sourcesContent":["/**\n * Interaction Tools Registrations\n *\n * Registers tools for interacting with question content:\n * - Answer Eliminator (strike through answer choices)\n * - Highlighter (highlight text passages)\n *\n * Maps to QTI 3.0 standard access features:\n * - answerMasking (assessment tool)\n * - strikethrough (visual transformation)\n * - highlighting (cognitive/reading support)\n */\n\nimport type {\n\tToolRegistration,\n\tToolToolbarButtonDefinition,\n\tToolToolbarRenderResult,\n\tToolbarContext,\n} from \"../../services/ToolRegistry.js\";\nimport type { ToolContext } from \"../../services/tool-context.js\";\nimport {\n\thasChoiceInteraction,\n\thasReadableText,\n} from \"../../services/tool-context.js\";\nimport {\n\tcreateToolElement,\n\ttype ToolComponentOverrides,\n} from \"../tool-tag-map.js\";\nimport {\n\tcreateScopedVisibilityBinding,\n\tsyncButtonAndOverlayVisibility,\n} from \"./toolbar-registration-helpers.js\";\n\n/**\n * Answer Eliminator tool registration\n *\n * Allows students to strike through incorrect answer choices.\n * Only appears on multiple-choice style questions.\n */\nexport const answerEliminatorToolRegistration: ToolRegistration = {\n\ttoolId: \"answerEliminator\",\n\tname: \"Answer Eliminator\",\n\tdescription: \"Strike through answer choices\",\n\ticon: \"strikethrough\",\n\n\t// Answer eliminator appears at item level only\n\tsupportedLevels: [\"item\"],\n\n\t// PNP support IDs\n\t// Maps to QTI 3.0 standard feature: answerMasking\n\tpnpSupportIds: [\n\t\t\"answerMasking\", // QTI 3.0 standard (assessment.answerMasking)\n\t\t\"answerEliminator\", // QTI 3.0 standard (assessment.answerEliminator)\n\t\t\"strikethrough\", // Common variant\n\t\t\"choiceMasking\", // Common variant\n\t],\n\n\t/**\n\t * Pass 2: Answer eliminator is relevant only for choice-based questions\n\t */\n\tisVisibleInContext(context: ToolContext): boolean {\n\t\treturn hasChoiceInteraction(context);\n\t},\n\n\trenderToolbar(\n\t\tcontext: ToolContext,\n\t\ttoolbarContext: ToolbarContext,\n\t): ToolToolbarRenderResult {\n\t\tconst visibility = createScopedVisibilityBinding(\n\t\t\tthis.toolId,\n\t\t\ttoolbarContext,\n\t\t);\n\t\tconst componentOverrides =\n\t\t\t(toolbarContext.componentOverrides as\n\t\t\t\t| ToolComponentOverrides\n\t\t\t\t| undefined) ?? {};\n\t\tconst overlay = createToolElement(\n\t\t\tthis.toolId,\n\t\t\tcontext,\n\t\t\ttoolbarContext,\n\t\t\tcomponentOverrides,\n\t\t) as HTMLElement & {\n\t\t\tvisible?: boolean;\n\t\t\ttoolId?: string;\n\t\t\tcoordinator?: unknown;\n\t\t\telementToolStateStore?: unknown;\n\t\t\tglobalElementId?: string;\n\t\t\tscopeElement?: HTMLElement | null;\n\t\t};\n\t\toverlay.setAttribute(\"tool-id\", visibility.fullToolId);\n\t\toverlay.setAttribute(\"strategy\", \"strikethrough\");\n\t\toverlay.setAttribute(\"button-alignment\", \"inline\");\n\n\t\tconst button: ToolToolbarButtonDefinition = {\n\t\t\ttoolId: this.toolId,\n\t\t\tlabel: this.name,\n\t\t\ticon: '<svg xmlns=\"http://www.w3.org/2000/svg\" viewBox=\"0 0 24 24\" width=\"20\" height=\"20\" fill=\"currentColor\" aria-hidden=\"true\"><path d=\"M19,3H16.3H7.7H5A2,2 0 0,0 3,5V7.7V16.4V19A2,2 0 0,0 5,21H7.7H16.4H19A2,2 0 0,0 21,19V16.3V7.7V5A2,2 0 0,0 19,3M15.6,17L12,13.4L8.4,17L7,15.6L10.6,12L7,8.4L8.4,7L12,10.6L15.6,7L17,8.4L13.4,12L17,15.6L15.6,17Z\"/></svg>',\n\t\t\tdisabled: false,\n\t\t\tariaLabel: \"Answer eliminator - Strike through choices\",\n\t\t\ttooltip: \"Strike Through\",\n\t\t\tonClick: () => toolbarContext.toggleTool(this.toolId),\n\t\t\tactive: visibility.isActive(),\n\t\t};\n\n\t\treturn {\n\t\t\ttoolId: this.toolId,\n\t\t\tbutton,\n\t\t\telements: [{ element: overlay, mount: \"after-buttons\" }],\n\t\t\tsync: () => {\n\t\t\t\tsyncButtonAndOverlayVisibility({\n\t\t\t\t\tbutton,\n\t\t\t\t\toverlay,\n\t\t\t\t\tisActive: visibility.isActive,\n\t\t\t\t});\n\t\t\t\tif (toolbarContext.toolCoordinator) {\n\t\t\t\t\toverlay.coordinator = toolbarContext.toolCoordinator;\n\t\t\t\t}\n\t\t\t\toverlay.scopeElement = toolbarContext.getScopeElement?.() || null;\n\t\t\t\tif (toolbarContext.elementToolStateStore) {\n\t\t\t\t\toverlay.elementToolStateStore = toolbarContext.elementToolStateStore;\n\t\t\t\t}\n\t\t\t\tconst globalElementId = toolbarContext.getGlobalElementId?.();\n\t\t\t\tif (globalElementId) {\n\t\t\t\t\toverlay.globalElementId = globalElementId;\n\t\t\t\t}\n\t\t\t},\n\t\t\tsubscribeActive: visibility.subscribeActive,\n\t\t};\n\t},\n};\n\n/**\n * Highlighter tool registration\n *\n * Allows students to highlight text in passages and questions.\n * Appears on items with readable text content.\n */\nexport const highlighterToolRegistration: ToolRegistration = {\n\ttoolId: \"highlighter\",\n\tname: \"Highlighter\",\n\tdescription: \"Highlight text\",\n\ticon: \"highlighter\",\n\tactivation: \"toolbar-toggle\",\n\n\t// Highlighter appears at passage, rubric, item, and element levels\n\tsupportedLevels: [\"passage\", \"rubric\", \"item\", \"element\"],\n\n\t// PNP support IDs\n\tpnpSupportIds: [\"highlighter\", \"textHighlight\", \"annotation\"],\n\n\t/**\n\t * Pass 2: Highlighter is relevant when readable text is available\n\t */\n\tisVisibleInContext(context: ToolContext): boolean {\n\t\treturn hasReadableText(context);\n\t},\n\n\trenderToolbar(\n\t\tcontext: ToolContext,\n\t\ttoolbarContext: ToolbarContext,\n\t): ToolToolbarRenderResult {\n\t\tconst visibility = createScopedVisibilityBinding(\n\t\t\tthis.toolId,\n\t\t\ttoolbarContext,\n\t\t);\n\t\tconst button: ToolToolbarButtonDefinition = {\n\t\t\ttoolId: this.toolId,\n\t\t\tlabel: this.name,\n\t\t\ticon: typeof this.icon === \"function\" ? this.icon(context) : this.icon,\n\t\t\tdisabled: false,\n\t\t\tariaLabel: \"Highlighter - Highlight text\",\n\t\t\ttooltip: \"Highlight\",\n\t\t\tonClick: () => toolbarContext.toggleTool(this.toolId),\n\t\t\tactive: visibility.isActive(),\n\t\t};\n\t\tconst componentOverrides =\n\t\t\t(toolbarContext.componentOverrides as\n\t\t\t\t| ToolComponentOverrides\n\t\t\t\t| undefined) ?? {};\n\t\tconst overlay = createToolElement(\n\t\t\tthis.toolId,\n\t\t\tcontext,\n\t\t\ttoolbarContext,\n\t\t\tcomponentOverrides,\n\t\t) as HTMLElement & {\n\t\t\tenabled?: boolean;\n\t\t\tvisible?: boolean;\n\t\t\ttoolId?: string;\n\t\t\thighlightCoordinator?: unknown;\n\t\t\tttsService?: unknown;\n\t\t};\n\t\toverlay.setAttribute(\"tool-id\", visibility.fullToolId);\n\t\treturn {\n\t\t\ttoolId: this.toolId,\n\t\t\tbutton,\n\t\t\telements: [{ element: overlay, mount: \"after-buttons\" }],\n\t\t\tsync: () => {\n\t\t\t\tsyncButtonAndOverlayVisibility({\n\t\t\t\t\tbutton,\n\t\t\t\t\toverlay,\n\t\t\t\t\tisActive: visibility.isActive,\n\t\t\t\t\tonActiveChange: (active) => {\n\t\t\t\t\t\toverlay.enabled = active;\n\t\t\t\t\t},\n\t\t\t\t});\n\t\t\t\tif (toolbarContext.ttsService) {\n\t\t\t\t\toverlay.ttsService = toolbarContext.ttsService;\n\t\t\t\t}\n\t\t\t},\n\t\t\tsubscribeActive: visibility.subscribeActive,\n\t\t};\n\t},\n};\n"]}
@@ -1 +1 @@
1
- {"version":3,"file":"measurement-tools.js","sourceRoot":"","sources":["../../../src/tools/registrations/measurement-tools.ts"],"names":[],"mappings":"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","sourcesContent":["/**\n * Measurement Tools Registrations\n *\n * Registers ruler and protractor tools for on-screen measurements.\n *\n * Maps to QTI 3.0 standard access features:\n * - ruler (assessment tool)\n * - protractor (assessment tool)\n */\n\nimport type {\n\tToolRegistration,\n\tToolToolbarButtonDefinition,\n\tToolToolbarRenderResult,\n\tToolbarContext,\n} from \"../../services/ToolRegistry.js\";\nimport type { ToolContext } from \"../../services/tool-context.js\";\nimport { hasMathContent } from \"../../services/tool-context.js\";\nimport {\n\tcreateToolElement,\n\ttype ToolComponentOverrides,\n} from \"../tool-tag-map.js\";\nimport {\n\tapplyOverlaySurface,\n\tcreateScopedVisibilityBinding,\n\tsyncButtonAndOverlayVisibility,\n} from \"./toolbar-registration-helpers.js\";\n\n/**\n * Ruler tool registration\n *\n * Provides an on-screen ruler for measuring lengths.\n * Typically appears on geometry or measurement problems.\n */\nexport const rulerToolRegistration: ToolRegistration = {\n\ttoolId: \"ruler\",\n\tname: \"Ruler\",\n\tdescription: \"On-screen ruler for measurements\",\n\ticon: \"ruler\",\n\n\t// Ruler typically appears at section/item/element level\n\tsupportedLevels: [\"section\", \"item\", \"element\"],\n\n\t// PNP support IDs\n\t// Maps to QTI 3.0 standard feature: ruler\n\tpnpSupportIds: [\n\t\t\"ruler\", // QTI 3.0 standard (assessment.ruler)\n\t\t\"measurement\", // Common variant\n\t],\n\n\t/**\n\t * Pass 2: Ruler is relevant when math content is present\n\t */\n\tisVisibleInContext(context: ToolContext): boolean {\n\t\treturn hasMathContent(context);\n\t},\n\n\trenderToolbar(\n\t\tcontext: ToolContext,\n\t\ttoolbarContext: ToolbarContext,\n\t): ToolToolbarRenderResult {\n\t\tconst visibility = createScopedVisibilityBinding(this.toolId, toolbarContext);\n\t\tconst button: ToolToolbarButtonDefinition = {\n\t\t\ttoolId: this.toolId,\n\t\t\tlabel: this.name,\n\t\t\ticon: typeof this.icon === \"function\" ? this.icon(context) : this.icon,\n\t\t\tdisabled: false,\n\t\t\tariaLabel: \"Open ruler tool\",\n\t\t\ttooltip: \"Ruler\",\n\t\t\tonClick: () => toolbarContext.toggleTool(this.toolId),\n\t\t\tactive: visibility.isActive(),\n\t\t};\n\t\tconst componentOverrides =\n\t\t\t(toolbarContext.componentOverrides as ToolComponentOverrides | undefined) ?? {};\n\t\tconst overlay = createToolElement(\n\t\t\tthis.toolId,\n\t\t\tcontext,\n\t\t\ttoolbarContext,\n\t\t\tcomponentOverrides,\n\t\t) as HTMLElement & {\n\t\t\tvisible?: boolean;\n\t\t\ttoolId?: string;\n\t\t\ttoolkitCoordinator: unknown;\n\t\t};\n\t\toverlay.setAttribute(\"tool-id\", visibility.fullToolId);\n\t\tapplyOverlaySurface(overlay, \"frameless\");\n\t\treturn {\n\t\t\ttoolId: this.toolId,\n\t\t\tbutton,\n\t\t\telements: [{ element: overlay, mount: \"after-buttons\" }],\n\t\t\tsync: () => {\n\t\t\t\tsyncButtonAndOverlayVisibility({\n\t\t\t\t\tbutton,\n\t\t\t\t\toverlay,\n\t\t\t\t\tisActive: visibility.isActive,\n\t\t\t\t});\n\t\t\t\tif (toolbarContext.toolkitCoordinator) {\n\t\t\t\t\toverlay.toolkitCoordinator = toolbarContext.toolkitCoordinator;\n\t\t\t\t}\n\t\t\t},\n\t\t\tsubscribeActive: visibility.subscribeActive,\n\t\t};\n\t},\n};\n\n/**\n * Protractor tool registration\n *\n * Provides an on-screen protractor for measuring angles.\n * Typically appears on geometry problems.\n */\nexport const protractorToolRegistration: ToolRegistration = {\n\ttoolId: \"protractor\",\n\tname: \"Protractor\",\n\tdescription: \"On-screen protractor for angle measurements\",\n\ticon: \"protractor\",\n\n\t// Protractor typically appears at section/item/element level\n\tsupportedLevels: [\"section\", \"item\", \"element\"],\n\n\t// PNP support IDs\n\t// Maps to QTI 3.0 standard feature: protractor\n\tpnpSupportIds: [\n\t\t\"protractor\", // QTI 3.0 standard (assessment.protractor)\n\t\t\"angleMeasurement\", // Common variant\n\t],\n\n\t/**\n\t * Pass 2: Protractor is relevant when math content is present\n\t */\n\tisVisibleInContext(context: ToolContext): boolean {\n\t\treturn hasMathContent(context);\n\t},\n\n\trenderToolbar(\n\t\tcontext: ToolContext,\n\t\ttoolbarContext: ToolbarContext,\n\t): ToolToolbarRenderResult {\n\t\tconst visibility = createScopedVisibilityBinding(this.toolId, toolbarContext);\n\t\tconst button: ToolToolbarButtonDefinition = {\n\t\t\ttoolId: this.toolId,\n\t\t\tlabel: this.name,\n\t\t\ticon: typeof this.icon === \"function\" ? this.icon(context) : this.icon,\n\t\t\tdisabled: false,\n\t\t\tariaLabel: \"Open protractor tool\",\n\t\t\ttooltip: \"Protractor\",\n\t\t\tonClick: () => toolbarContext.toggleTool(this.toolId),\n\t\t\tactive: visibility.isActive(),\n\t\t};\n\t\tconst componentOverrides =\n\t\t\t(toolbarContext.componentOverrides as ToolComponentOverrides | undefined) ?? {};\n\t\tconst overlay = createToolElement(\n\t\t\tthis.toolId,\n\t\t\tcontext,\n\t\t\ttoolbarContext,\n\t\t\tcomponentOverrides,\n\t\t) as HTMLElement & {\n\t\t\tvisible?: boolean;\n\t\t\ttoolId?: string;\n\t\t\ttoolkitCoordinator: unknown;\n\t\t};\n\t\toverlay.setAttribute(\"tool-id\", visibility.fullToolId);\n\t\tapplyOverlaySurface(overlay, \"frameless\");\n\t\treturn {\n\t\t\ttoolId: this.toolId,\n\t\t\tbutton,\n\t\t\telements: [{ element: overlay, mount: \"after-buttons\" }],\n\t\t\tsync: () => {\n\t\t\t\tsyncButtonAndOverlayVisibility({\n\t\t\t\t\tbutton,\n\t\t\t\t\toverlay,\n\t\t\t\t\tisActive: visibility.isActive,\n\t\t\t\t});\n\t\t\t\tif (toolbarContext.toolkitCoordinator) {\n\t\t\t\t\toverlay.toolkitCoordinator = toolbarContext.toolkitCoordinator;\n\t\t\t\t}\n\t\t\t},\n\t\t\tsubscribeActive: visibility.subscribeActive,\n\t\t};\n\t},\n};\n"]}
1
+ {"version":3,"file":"measurement-tools.js","sourceRoot":"","sources":["../../../src/tools/registrations/measurement-tools.ts"],"names":[],"mappings":"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","sourcesContent":["/**\n * Measurement Tools Registrations\n *\n * Registers ruler and protractor tools for on-screen measurements.\n *\n * Maps to QTI 3.0 standard access features:\n * - ruler (assessment tool)\n * - protractor (assessment tool)\n */\n\nimport type {\n\tToolRegistration,\n\tToolToolbarButtonDefinition,\n\tToolToolbarRenderResult,\n\tToolbarContext,\n} from \"../../services/ToolRegistry.js\";\nimport type { ToolContext } from \"../../services/tool-context.js\";\nimport { hasMathContent } from \"../../services/tool-context.js\";\nimport {\n\tcreateToolElement,\n\ttype ToolComponentOverrides,\n} from \"../tool-tag-map.js\";\nimport {\n\tapplyOverlaySurface,\n\tcreateScopedVisibilityBinding,\n\tsyncButtonAndOverlayVisibility,\n} from \"./toolbar-registration-helpers.js\";\n\n/**\n * Ruler tool registration\n *\n * Provides an on-screen ruler for measuring lengths.\n * Typically appears on geometry or measurement problems.\n */\nexport const rulerToolRegistration: ToolRegistration = {\n\ttoolId: \"ruler\",\n\tname: \"Ruler\",\n\tdescription: \"On-screen ruler for measurements\",\n\ticon: \"ruler\",\n\n\t// Ruler typically appears at section/item/element level\n\tsupportedLevels: [\"section\", \"item\", \"element\"],\n\n\t// PNP support IDs\n\t// Maps to QTI 3.0 standard feature: ruler\n\tpnpSupportIds: [\n\t\t\"ruler\", // QTI 3.0 standard (assessment.ruler)\n\t\t\"measurement\", // Common variant\n\t],\n\n\t/**\n\t * Pass 2: Ruler is relevant when math content is present\n\t */\n\tisVisibleInContext(context: ToolContext): boolean {\n\t\treturn hasMathContent(context);\n\t},\n\n\trenderToolbar(\n\t\tcontext: ToolContext,\n\t\ttoolbarContext: ToolbarContext,\n\t): ToolToolbarRenderResult {\n\t\tconst visibility = createScopedVisibilityBinding(\n\t\t\tthis.toolId,\n\t\t\ttoolbarContext,\n\t\t);\n\t\tconst button: ToolToolbarButtonDefinition = {\n\t\t\ttoolId: this.toolId,\n\t\t\tlabel: this.name,\n\t\t\ticon: typeof this.icon === \"function\" ? this.icon(context) : this.icon,\n\t\t\tdisabled: false,\n\t\t\tariaLabel: \"Open ruler tool\",\n\t\t\ttooltip: \"Ruler\",\n\t\t\tonClick: () => toolbarContext.toggleTool(this.toolId),\n\t\t\tactive: visibility.isActive(),\n\t\t};\n\t\tconst componentOverrides =\n\t\t\t(toolbarContext.componentOverrides as\n\t\t\t\t| ToolComponentOverrides\n\t\t\t\t| undefined) ?? {};\n\t\tconst overlay = createToolElement(\n\t\t\tthis.toolId,\n\t\t\tcontext,\n\t\t\ttoolbarContext,\n\t\t\tcomponentOverrides,\n\t\t) as HTMLElement & {\n\t\t\tvisible?: boolean;\n\t\t\ttoolId?: string;\n\t\t\ttoolkitCoordinator: unknown;\n\t\t};\n\t\toverlay.setAttribute(\"tool-id\", visibility.fullToolId);\n\t\tapplyOverlaySurface(overlay, \"frameless\");\n\t\treturn {\n\t\t\ttoolId: this.toolId,\n\t\t\tbutton,\n\t\t\telements: [{ element: overlay, mount: \"after-buttons\" }],\n\t\t\tsync: () => {\n\t\t\t\tsyncButtonAndOverlayVisibility({\n\t\t\t\t\tbutton,\n\t\t\t\t\toverlay,\n\t\t\t\t\tisActive: visibility.isActive,\n\t\t\t\t});\n\t\t\t\tif (toolbarContext.toolkitCoordinator) {\n\t\t\t\t\toverlay.toolkitCoordinator = toolbarContext.toolkitCoordinator;\n\t\t\t\t}\n\t\t\t},\n\t\t\tsubscribeActive: visibility.subscribeActive,\n\t\t};\n\t},\n};\n\n/**\n * Protractor tool registration\n *\n * Provides an on-screen protractor for measuring angles.\n * Typically appears on geometry problems.\n */\nexport const protractorToolRegistration: ToolRegistration = {\n\ttoolId: \"protractor\",\n\tname: \"Protractor\",\n\tdescription: \"On-screen protractor for angle measurements\",\n\ticon: \"protractor\",\n\n\t// Protractor typically appears at section/item/element level\n\tsupportedLevels: [\"section\", \"item\", \"element\"],\n\n\t// PNP support IDs\n\t// Maps to QTI 3.0 standard feature: protractor\n\tpnpSupportIds: [\n\t\t\"protractor\", // QTI 3.0 standard (assessment.protractor)\n\t\t\"angleMeasurement\", // Common variant\n\t],\n\n\t/**\n\t * Pass 2: Protractor is relevant when math content is present\n\t */\n\tisVisibleInContext(context: ToolContext): boolean {\n\t\treturn hasMathContent(context);\n\t},\n\n\trenderToolbar(\n\t\tcontext: ToolContext,\n\t\ttoolbarContext: ToolbarContext,\n\t): ToolToolbarRenderResult {\n\t\tconst visibility = createScopedVisibilityBinding(\n\t\t\tthis.toolId,\n\t\t\ttoolbarContext,\n\t\t);\n\t\tconst button: ToolToolbarButtonDefinition = {\n\t\t\ttoolId: this.toolId,\n\t\t\tlabel: this.name,\n\t\t\ticon: typeof this.icon === \"function\" ? this.icon(context) : this.icon,\n\t\t\tdisabled: false,\n\t\t\tariaLabel: \"Open protractor tool\",\n\t\t\ttooltip: \"Protractor\",\n\t\t\tonClick: () => toolbarContext.toggleTool(this.toolId),\n\t\t\tactive: visibility.isActive(),\n\t\t};\n\t\tconst componentOverrides =\n\t\t\t(toolbarContext.componentOverrides as\n\t\t\t\t| ToolComponentOverrides\n\t\t\t\t| undefined) ?? {};\n\t\tconst overlay = createToolElement(\n\t\t\tthis.toolId,\n\t\t\tcontext,\n\t\t\ttoolbarContext,\n\t\t\tcomponentOverrides,\n\t\t) as HTMLElement & {\n\t\t\tvisible?: boolean;\n\t\t\ttoolId?: string;\n\t\t\ttoolkitCoordinator: unknown;\n\t\t};\n\t\toverlay.setAttribute(\"tool-id\", visibility.fullToolId);\n\t\tapplyOverlaySurface(overlay, \"frameless\");\n\t\treturn {\n\t\t\ttoolId: this.toolId,\n\t\t\tbutton,\n\t\t\telements: [{ element: overlay, mount: \"after-buttons\" }],\n\t\t\tsync: () => {\n\t\t\t\tsyncButtonAndOverlayVisibility({\n\t\t\t\t\tbutton,\n\t\t\t\t\toverlay,\n\t\t\t\t\tisActive: visibility.isActive,\n\t\t\t\t});\n\t\t\t\tif (toolbarContext.toolkitCoordinator) {\n\t\t\t\t\toverlay.toolkitCoordinator = toolbarContext.toolkitCoordinator;\n\t\t\t\t}\n\t\t\t},\n\t\t\tsubscribeActive: visibility.subscribeActive,\n\t\t};\n\t},\n};\n"]}
@@ -10,7 +10,7 @@
10
10
  * - graph (assessment tool)
11
11
  * - periodicTable (assessment tool)
12
12
  */
13
- import { hasMathContent, hasScienceContent } from "../../services/tool-context.js";
13
+ import { hasMathContent, hasScienceContent, } from "../../services/tool-context.js";
14
14
  import { createToolElement, } from "../tool-tag-map.js";
15
15
  import { createScopedVisibilityBinding, syncButtonAndOverlayVisibility, } from "./toolbar-registration-helpers.js";
16
16
  /**
@@ -1 +1 @@
1
- {"version":3,"file":"subject-specific-tools.js","sourceRoot":"","sources":["../../../src/tools/registrations/subject-specific-tools.ts"],"names":[],"mappings":"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","sourcesContent":["/**\n * Subject-Specific Tools Registrations\n *\n * Registers tools for specific subject areas:\n * - Graph (graphing calculator/coordinate plane)\n * - Periodic Table (chemistry reference)\n *\n * Maps to QTI 3.0 standard access features:\n * - graphingCalculator (assessment tool)\n * - graph (assessment tool)\n * - periodicTable (assessment tool)\n */\n\nimport type {\n\tToolRegistration,\n\tToolToolbarButtonDefinition,\n\tToolToolbarRenderResult,\n\tToolbarContext,\n} from \"../../services/ToolRegistry.js\";\nimport type { ToolContext } from \"../../services/tool-context.js\";\nimport { hasMathContent, hasScienceContent } from \"../../services/tool-context.js\";\nimport {\n\tcreateToolElement,\n\ttype ToolComponentOverrides,\n} from \"../tool-tag-map.js\";\nimport {\n\tcreateScopedVisibilityBinding,\n\tsyncButtonAndOverlayVisibility,\n} from \"./toolbar-registration-helpers.js\";\n\n/**\n * Graph tool registration\n *\n * Provides graphing calculator and coordinate plane functionality.\n * Context-smart: appears automatically for math content or when explicitly enabled.\n */\nexport const graphToolRegistration: ToolRegistration = {\n\ttoolId: \"graph\",\n\tname: \"Graph\",\n\tdescription: \"Graphing calculator and coordinate plane\",\n\ticon: \"chart-bar\",\n\n\t// Graph is a section-level floating tool.\n\tsupportedLevels: [\"section\"],\n\n\t// PNP support IDs\n\t// Maps to QTI 3.0 standard features: graph, graphingCalculator\n\tpnpSupportIds: [\n\t\t\"graph\", // QTI 3.0 standard (assessment.graph)\n\t\t\"graphingCalculator\", // QTI 3.0 standard (assessment.graphingCalculator)\n\t\t\"coordinatePlane\", // Common variant\n\t\t\"graphingTool\", // Common variant\n\t],\n\n\t/**\n\t * Pass 2: Graph is relevant when math content is present\n\t */\n\tisVisibleInContext(context: ToolContext): boolean {\n\t\treturn hasMathContent(context);\n\t},\n\n\trenderToolbar(\n\t\tcontext: ToolContext,\n\t\ttoolbarContext: ToolbarContext,\n\t): ToolToolbarRenderResult {\n\t\tconst visibility = createScopedVisibilityBinding(this.toolId, toolbarContext);\n\t\tconst button: ToolToolbarButtonDefinition = {\n\t\t\ttoolId: this.toolId,\n\t\t\tlabel: this.name,\n\t\t\ticon: typeof this.icon === \"function\" ? this.icon(context) : this.icon,\n\t\t\tdisabled: false,\n\t\t\tariaLabel: \"Graph - Graphing calculator\",\n\t\t\ttooltip: \"Graph\",\n\t\t\tonClick: () => toolbarContext.toggleTool(this.toolId),\n\t\t\tactive: visibility.isActive(),\n\t\t};\n\t\tconst componentOverrides =\n\t\t\t(toolbarContext.componentOverrides as ToolComponentOverrides | undefined) ?? {};\n\t\tconst overlay = createToolElement(\n\t\t\tthis.toolId,\n\t\t\tcontext,\n\t\t\ttoolbarContext,\n\t\t\tcomponentOverrides,\n\t\t) as HTMLElement & {\n\t\t\tvisible?: boolean;\n\t\t\ttoolId?: string;\n\t\t};\n\t\toverlay.setAttribute(\"tool-id\", visibility.fullToolId);\n\t\treturn {\n\t\t\ttoolId: this.toolId,\n\t\t\tbutton,\n\t\t\telements: [\n\t\t\t\t{\n\t\t\t\t\telement: overlay,\n\t\t\t\t\tmount: \"after-buttons\",\n\t\t\t\t\tshell: {\n\t\t\t\t\t\ttitle: this.name,\n\t\t\t\t\t\tdraggable: true,\n\t\t\t\t\t\tresizable: true,\n\t\t\t\t\t\tcloseable: true,\n\t\t\t\t\t\tinitialWidth: 920,\n\t\t\t\t\t\tinitialHeight: 680,\n\t\t\t\t\t\tminWidth: 640,\n\t\t\t\t\t\tminHeight: 500,\n\t\t\t\t\t},\n\t\t\t\t},\n\t\t\t],\n\t\t\tsync: () => {\n\t\t\t\tsyncButtonAndOverlayVisibility({\n\t\t\t\t\tbutton,\n\t\t\t\t\toverlay,\n\t\t\t\t\tisActive: visibility.isActive,\n\t\t\t\t});\n\t\t\t},\n\t\t\tsubscribeActive: visibility.subscribeActive,\n\t\t};\n\t},\n};\n\n/**\n * Periodic Table tool registration\n *\n * Provides chemistry periodic table reference.\n * Context-smart: appears automatically for science content or when explicitly enabled.\n */\nexport const periodicTableToolRegistration: ToolRegistration = {\n\ttoolId: \"periodicTable\",\n\tname: \"Periodic Table\",\n\tdescription: \"Chemistry periodic table reference\",\n\ticon: \"beaker\",\n\n\t// Periodic table is a section-level floating tool.\n\tsupportedLevels: [\"section\"],\n\n\t// PNP support IDs\n\t// Maps to QTI 3.0 standard feature: periodicTable\n\tpnpSupportIds: [\n\t\t\"periodicTable\", // QTI 3.0 standard (assessment.periodicTable)\n\t\t\"chemistryReference\", // Common variant\n\t\t\"elementReference\", // Common variant\n\t],\n\n\t/**\n\t * Pass 2: Periodic table is relevant when science content is present\n\t */\n\tisVisibleInContext(context: ToolContext): boolean {\n\t\treturn hasScienceContent(context);\n\t},\n\n\trenderToolbar(\n\t\tcontext: ToolContext,\n\t\ttoolbarContext: ToolbarContext,\n\t): ToolToolbarRenderResult {\n\t\tconst visibility = createScopedVisibilityBinding(this.toolId, toolbarContext);\n\t\tconst button: ToolToolbarButtonDefinition = {\n\t\t\ttoolId: this.toolId,\n\t\t\tlabel: this.name,\n\t\t\ticon: typeof this.icon === \"function\" ? this.icon(context) : this.icon,\n\t\t\tdisabled: false,\n\t\t\tariaLabel: \"Periodic table - Chemistry reference\",\n\t\t\ttooltip: \"Periodic Table\",\n\t\t\tonClick: () => toolbarContext.toggleTool(this.toolId),\n\t\t\tactive: visibility.isActive(),\n\t\t};\n\t\tconst componentOverrides =\n\t\t\t(toolbarContext.componentOverrides as ToolComponentOverrides | undefined) ?? {};\n\t\tconst overlay = createToolElement(\n\t\t\tthis.toolId,\n\t\t\tcontext,\n\t\t\ttoolbarContext,\n\t\t\tcomponentOverrides,\n\t\t) as HTMLElement & {\n\t\t\tvisible?: boolean;\n\t\t\ttoolId?: string;\n\t\t};\n\t\toverlay.setAttribute(\"tool-id\", visibility.fullToolId);\n\t\treturn {\n\t\t\ttoolId: this.toolId,\n\t\t\tbutton,\n\t\t\telements: [\n\t\t\t\t{\n\t\t\t\t\telement: overlay,\n\t\t\t\t\tmount: \"after-buttons\",\n\t\t\t\t\tshell: {\n\t\t\t\t\t\ttitle: this.name,\n\t\t\t\t\t\tdraggable: true,\n\t\t\t\t\t\tresizable: true,\n\t\t\t\t\t\tcloseable: true,\n\t\t\t\t\t\tinitialWidth: 1160,\n\t\t\t\t\t\tinitialHeight: 760,\n\t\t\t\t\t\tminWidth: 920,\n\t\t\t\t\t\tminHeight: 620,\n\t\t\t\t\t},\n\t\t\t\t},\n\t\t\t],\n\t\t\tsync: () => {\n\t\t\t\tsyncButtonAndOverlayVisibility({\n\t\t\t\t\tbutton,\n\t\t\t\t\toverlay,\n\t\t\t\t\tisActive: visibility.isActive,\n\t\t\t\t});\n\t\t\t},\n\t\t\tsubscribeActive: visibility.subscribeActive,\n\t\t};\n\t},\n};\n"]}
1
+ {"version":3,"file":"subject-specific-tools.js","sourceRoot":"","sources":["../../../src/tools/registrations/subject-specific-tools.ts"],"names":[],"mappings":"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","sourcesContent":["/**\n * Subject-Specific Tools Registrations\n *\n * Registers tools for specific subject areas:\n * - Graph (graphing calculator/coordinate plane)\n * - Periodic Table (chemistry reference)\n *\n * Maps to QTI 3.0 standard access features:\n * - graphingCalculator (assessment tool)\n * - graph (assessment tool)\n * - periodicTable (assessment tool)\n */\n\nimport type {\n\tToolRegistration,\n\tToolToolbarButtonDefinition,\n\tToolToolbarRenderResult,\n\tToolbarContext,\n} from \"../../services/ToolRegistry.js\";\nimport type { ToolContext } from \"../../services/tool-context.js\";\nimport {\n\thasMathContent,\n\thasScienceContent,\n} from \"../../services/tool-context.js\";\nimport {\n\tcreateToolElement,\n\ttype ToolComponentOverrides,\n} from \"../tool-tag-map.js\";\nimport {\n\tcreateScopedVisibilityBinding,\n\tsyncButtonAndOverlayVisibility,\n} from \"./toolbar-registration-helpers.js\";\n\n/**\n * Graph tool registration\n *\n * Provides graphing calculator and coordinate plane functionality.\n * Context-smart: appears automatically for math content or when explicitly enabled.\n */\nexport const graphToolRegistration: ToolRegistration = {\n\ttoolId: \"graph\",\n\tname: \"Graph\",\n\tdescription: \"Graphing calculator and coordinate plane\",\n\ticon: \"chart-bar\",\n\n\t// Graph is a section-level floating tool.\n\tsupportedLevels: [\"section\"],\n\n\t// PNP support IDs\n\t// Maps to QTI 3.0 standard features: graph, graphingCalculator\n\tpnpSupportIds: [\n\t\t\"graph\", // QTI 3.0 standard (assessment.graph)\n\t\t\"graphingCalculator\", // QTI 3.0 standard (assessment.graphingCalculator)\n\t\t\"coordinatePlane\", // Common variant\n\t\t\"graphingTool\", // Common variant\n\t],\n\n\t/**\n\t * Pass 2: Graph is relevant when math content is present\n\t */\n\tisVisibleInContext(context: ToolContext): boolean {\n\t\treturn hasMathContent(context);\n\t},\n\n\trenderToolbar(\n\t\tcontext: ToolContext,\n\t\ttoolbarContext: ToolbarContext,\n\t): ToolToolbarRenderResult {\n\t\tconst visibility = createScopedVisibilityBinding(\n\t\t\tthis.toolId,\n\t\t\ttoolbarContext,\n\t\t);\n\t\tconst button: ToolToolbarButtonDefinition = {\n\t\t\ttoolId: this.toolId,\n\t\t\tlabel: this.name,\n\t\t\ticon: typeof this.icon === \"function\" ? this.icon(context) : this.icon,\n\t\t\tdisabled: false,\n\t\t\tariaLabel: \"Graph - Graphing calculator\",\n\t\t\ttooltip: \"Graph\",\n\t\t\tonClick: () => toolbarContext.toggleTool(this.toolId),\n\t\t\tactive: visibility.isActive(),\n\t\t};\n\t\tconst componentOverrides =\n\t\t\t(toolbarContext.componentOverrides as\n\t\t\t\t| ToolComponentOverrides\n\t\t\t\t| undefined) ?? {};\n\t\tconst overlay = createToolElement(\n\t\t\tthis.toolId,\n\t\t\tcontext,\n\t\t\ttoolbarContext,\n\t\t\tcomponentOverrides,\n\t\t) as HTMLElement & {\n\t\t\tvisible?: boolean;\n\t\t\ttoolId?: string;\n\t\t};\n\t\toverlay.setAttribute(\"tool-id\", visibility.fullToolId);\n\t\treturn {\n\t\t\ttoolId: this.toolId,\n\t\t\tbutton,\n\t\t\telements: [\n\t\t\t\t{\n\t\t\t\t\telement: overlay,\n\t\t\t\t\tmount: \"after-buttons\",\n\t\t\t\t\tshell: {\n\t\t\t\t\t\ttitle: this.name,\n\t\t\t\t\t\tdraggable: true,\n\t\t\t\t\t\tresizable: true,\n\t\t\t\t\t\tcloseable: true,\n\t\t\t\t\t\tinitialWidth: 920,\n\t\t\t\t\t\tinitialHeight: 680,\n\t\t\t\t\t\tminWidth: 640,\n\t\t\t\t\t\tminHeight: 500,\n\t\t\t\t\t},\n\t\t\t\t},\n\t\t\t],\n\t\t\tsync: () => {\n\t\t\t\tsyncButtonAndOverlayVisibility({\n\t\t\t\t\tbutton,\n\t\t\t\t\toverlay,\n\t\t\t\t\tisActive: visibility.isActive,\n\t\t\t\t});\n\t\t\t},\n\t\t\tsubscribeActive: visibility.subscribeActive,\n\t\t};\n\t},\n};\n\n/**\n * Periodic Table tool registration\n *\n * Provides chemistry periodic table reference.\n * Context-smart: appears automatically for science content or when explicitly enabled.\n */\nexport const periodicTableToolRegistration: ToolRegistration = {\n\ttoolId: \"periodicTable\",\n\tname: \"Periodic Table\",\n\tdescription: \"Chemistry periodic table reference\",\n\ticon: \"beaker\",\n\n\t// Periodic table is a section-level floating tool.\n\tsupportedLevels: [\"section\"],\n\n\t// PNP support IDs\n\t// Maps to QTI 3.0 standard feature: periodicTable\n\tpnpSupportIds: [\n\t\t\"periodicTable\", // QTI 3.0 standard (assessment.periodicTable)\n\t\t\"chemistryReference\", // Common variant\n\t\t\"elementReference\", // Common variant\n\t],\n\n\t/**\n\t * Pass 2: Periodic table is relevant when science content is present\n\t */\n\tisVisibleInContext(context: ToolContext): boolean {\n\t\treturn hasScienceContent(context);\n\t},\n\n\trenderToolbar(\n\t\tcontext: ToolContext,\n\t\ttoolbarContext: ToolbarContext,\n\t): ToolToolbarRenderResult {\n\t\tconst visibility = createScopedVisibilityBinding(\n\t\t\tthis.toolId,\n\t\t\ttoolbarContext,\n\t\t);\n\t\tconst button: ToolToolbarButtonDefinition = {\n\t\t\ttoolId: this.toolId,\n\t\t\tlabel: this.name,\n\t\t\ticon: typeof this.icon === \"function\" ? this.icon(context) : this.icon,\n\t\t\tdisabled: false,\n\t\t\tariaLabel: \"Periodic table - Chemistry reference\",\n\t\t\ttooltip: \"Periodic Table\",\n\t\t\tonClick: () => toolbarContext.toggleTool(this.toolId),\n\t\t\tactive: visibility.isActive(),\n\t\t};\n\t\tconst componentOverrides =\n\t\t\t(toolbarContext.componentOverrides as\n\t\t\t\t| ToolComponentOverrides\n\t\t\t\t| undefined) ?? {};\n\t\tconst overlay = createToolElement(\n\t\t\tthis.toolId,\n\t\t\tcontext,\n\t\t\ttoolbarContext,\n\t\t\tcomponentOverrides,\n\t\t) as HTMLElement & {\n\t\t\tvisible?: boolean;\n\t\t\ttoolId?: string;\n\t\t};\n\t\toverlay.setAttribute(\"tool-id\", visibility.fullToolId);\n\t\treturn {\n\t\t\ttoolId: this.toolId,\n\t\t\tbutton,\n\t\t\telements: [\n\t\t\t\t{\n\t\t\t\t\telement: overlay,\n\t\t\t\t\tmount: \"after-buttons\",\n\t\t\t\t\tshell: {\n\t\t\t\t\t\ttitle: this.name,\n\t\t\t\t\t\tdraggable: true,\n\t\t\t\t\t\tresizable: true,\n\t\t\t\t\t\tcloseable: true,\n\t\t\t\t\t\tinitialWidth: 1160,\n\t\t\t\t\t\tinitialHeight: 760,\n\t\t\t\t\t\tminWidth: 920,\n\t\t\t\t\t\tminHeight: 620,\n\t\t\t\t\t},\n\t\t\t\t},\n\t\t\t],\n\t\t\tsync: () => {\n\t\t\t\tsyncButtonAndOverlayVisibility({\n\t\t\t\t\tbutton,\n\t\t\t\t\toverlay,\n\t\t\t\t\tisActive: visibility.isActive,\n\t\t\t\t});\n\t\t\t},\n\t\t\tsubscribeActive: visibility.subscribeActive,\n\t\t};\n\t},\n};\n"]}
@@ -97,7 +97,8 @@ export const ttsToolRegistration = {
97
97
  return hasReadableText(context);
98
98
  },
99
99
  renderToolbar(_context, toolbarContext) {
100
- const resolveRuntimeSettings = () => resolveTTSRuntimeSettings(toolbarContext.toolkitCoordinator?.getToolConfig(this.toolId) || undefined);
100
+ const resolveRuntimeSettings = () => resolveTTSRuntimeSettings(toolbarContext.toolkitCoordinator?.getToolConfig(this.toolId) ||
101
+ undefined);
101
102
  const resolveElementSpeedOptions = () => {
102
103
  const runtimeSettings = resolveRuntimeSettings();
103
104
  return normalizeTTSSpeedOptions(runtimeSettings.speedOptions);
@@ -112,7 +113,8 @@ export const ttsToolRegistration = {
112
113
  const ensureElement = () => {
113
114
  let element = inlineTTSControls.get(fullToolId);
114
115
  if (element &&
115
- typeof element.isConnected === "boolean" &&
116
+ typeof element.isConnected ===
117
+ "boolean" &&
116
118
  !element.isConnected) {
117
119
  inlineTTSControls.delete(fullToolId);
118
120
  element = undefined;
@@ -1 +1 @@
1
- {"version":3,"file":"tts.js","sourceRoot":"","sources":["../../../src/tools/registrations/tts.ts"],"names":[],"mappings":"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","sourcesContent":["/**\n * Text-to-Speech (TTS) Tool Registration\n *\n * Registers the TTS tool for reading content aloud.\n *\n * Maps to QTI 3.0 standard access features:\n * - textToSpeech (auditory support)\n * - readAloud (auditory support)\n */\n\nimport type {\n\tToolRegistration,\n\tToolToolbarRenderResult,\n\tToolbarContext,\n} from \"../../services/ToolRegistry.js\";\nimport type { ToolContext } from \"../../services/tool-context.js\";\nimport { hasReadableText } from \"../../services/tool-context.js\";\nimport { createScopedToolId } from \"../../services/tool-instance-id.js\";\nimport {\n\tbuildRuntimeTTSConfig,\n\tnormalizeTTSLayoutMode,\n\tnormalizeTTSSpeedOptions,\n\tresolveTTSHostToolbarLayout,\n\tresolveTTSLayoutMode,\n\tresolveTTSBackend,\n\tresolveTTSRuntimeSettings,\n\tresolveRuntimeProvider,\n\tresolveTransportMode,\n} from \"../../services/tts-runtime-config.js\";\nimport { TTSToolProvider } from \"../../services/tool-providers/index.js\";\n\nconst inlineTTSControls = new Map<string, HTMLElement>();\nexport const TOOL_ELEMENT_UNMOUNT_CALLBACK_PROP = \"__pieToolElementUnmount\";\nexport const TOOL_ACTIVE_CHANGE_EVENT = \"pie-tool-active-change\";\n\n/**\n * Text-to-Speech tool registration\n *\n * Supports:\n * - Reading content aloud using browser TTS or external providers\n * - Context-aware visibility (shows when readable text is available)\n * - All levels except assessment and element\n */\nexport const ttsToolRegistration: ToolRegistration = {\n\ttoolId: \"textToSpeech\",\n\tname: \"Text to Speech\",\n\tdescription: \"Read content aloud\",\n\ticon: \"volume-up\",\n\tprovider: {\n\t\tgetProviderId: () => \"tts\",\n\t\tcreateProvider: (config) => {\n\t\t\tconst settings = resolveTTSRuntimeSettings(config);\n\t\t\treturn new TTSToolProvider(resolveTTSBackend(settings));\n\t\t},\n\t\tgetInitConfig: (config) => {\n\t\t\tconst settings = resolveTTSRuntimeSettings(config);\n\t\t\tconst backend = resolveTTSBackend(settings);\n\t\t\tconst serverProvider = resolveRuntimeProvider(settings, backend);\n\t\t\tconst transportMode = resolveTransportMode(settings, serverProvider);\n\t\t\treturn {\n\t\t\t\tbackend,\n\t\t\t\tserverProvider,\n\t\t\t\ttransportMode,\n\t\t\t\t...buildRuntimeTTSConfig(settings),\n\t\t\t};\n\t\t},\n\t\tgetAuthFetcher: (config) => {\n\t\t\tconst runtimeAuthFetcher = config?.provider?.runtime?.authFetcher;\n\t\t\treturn typeof runtimeAuthFetcher === \"function\"\n\t\t\t\t? runtimeAuthFetcher\n\t\t\t\t: undefined;\n\t\t},\n\t\tsanitizeConfig: (config) => {\n\t\t\tconst settings =\n\t\t\t\tconfig.settings && typeof config.settings === \"object\"\n\t\t\t\t\t? { ...(config.settings as Record<string, unknown>) }\n\t\t\t\t\t: undefined;\n\t\t\tif (settings && \"layoutMode\" in settings) {\n\t\t\t\tsettings.layoutMode = normalizeTTSLayoutMode(settings.layoutMode);\n\t\t\t}\n\t\t\tif (settings && \"speedOptions\" in settings) {\n\t\t\t\tsettings.speedOptions = normalizeTTSSpeedOptions(settings.speedOptions);\n\t\t\t}\n\t\t\tconst normalizedConfig: Record<string, unknown> = {\n\t\t\t\t...(config as Record<string, unknown>),\n\t\t\t};\n\t\t\tif (\"layoutMode\" in normalizedConfig) {\n\t\t\t\tnormalizedConfig.layoutMode = normalizeTTSLayoutMode(\n\t\t\t\t\tnormalizedConfig.layoutMode,\n\t\t\t\t);\n\t\t\t}\n\t\t\tif (\"speedOptions\" in normalizedConfig) {\n\t\t\t\tnormalizedConfig.speedOptions = normalizeTTSSpeedOptions(\n\t\t\t\t\tnormalizedConfig.speedOptions,\n\t\t\t\t);\n\t\t\t}\n\t\t\tif (settings) {\n\t\t\t\tnormalizedConfig.settings = settings;\n\t\t\t}\n\t\t\treturn normalizedConfig as typeof config;\n\t\t},\n\t\tlazy: true,\n\t},\n\n\t// TTS is inline-only and scoped to item/passage contexts.\n\tsupportedLevels: [\"item\", \"passage\"],\n\n\t// PNP support IDs that enable this tool\n\t// Maps to QTI 3.0 standard features: textToSpeech, readAloud\n\tpnpSupportIds: [\n\t\t\"textToSpeech\", // QTI 3.0 standard (auditory.textToSpeech)\n\t\t\"readAloud\", // QTI 3.0 standard (auditory.readAloud)\n\t\t\"tts\", // Common abbreviation\n\t\t\"speechOutput\", // Common variant\n\t],\n\n\t/**\n\t * Pass 2: Determine if TTS is relevant in this context\n\t *\n\t * TTS is relevant when:\n\t * - Context contains readable text (at least 10 characters)\n\t */\n\tisVisibleInContext(context: ToolContext): boolean {\n\t\treturn hasReadableText(context);\n\t},\n\n\trenderToolbar(\n\t\t_context: ToolContext,\n\t\ttoolbarContext: ToolbarContext,\n\t): ToolToolbarRenderResult {\n\t\tconst resolveRuntimeSettings = () =>\n\t\t\tresolveTTSRuntimeSettings(\n\t\t\t\ttoolbarContext.toolkitCoordinator?.getToolConfig(this.toolId) || undefined,\n\t\t\t);\n\t\tconst resolveElementSpeedOptions = (): number[] => {\n\t\t\tconst runtimeSettings = resolveRuntimeSettings();\n\t\t\treturn normalizeTTSSpeedOptions(runtimeSettings.speedOptions);\n\t\t};\n\t\tconst resolveLayoutMode = () => resolveTTSLayoutMode(resolveRuntimeSettings());\n\t\tconst resolveHostLayout = () => resolveTTSHostToolbarLayout(resolveRuntimeSettings());\n\t\tconst fullToolId = createScopedToolId(\n\t\t\tthis.toolId,\n\t\t\ttoolbarContext.scope.level,\n\t\t\ttoolbarContext.scope.scopeId,\n\t\t);\n\t\tconst resolveControlSize = (): \"sm\" | \"md\" | \"lg\" => {\n\t\t\tconst raw = toolbarContext.ui?.size;\n\t\t\treturn raw === \"sm\" || raw === \"lg\" ? raw : \"md\";\n\t\t};\n\t\tconst ensureElement = (): HTMLElement => {\n\t\t\tlet element = inlineTTSControls.get(fullToolId);\n\t\t\tif (\n\t\t\t\telement &&\n\t\t\t\ttypeof (element as { isConnected?: boolean }).isConnected === \"boolean\" &&\n\t\t\t\t!(element as { isConnected?: boolean }).isConnected\n\t\t\t) {\n\t\t\t\tinlineTTSControls.delete(fullToolId);\n\t\t\t\telement = undefined;\n\t\t\t}\n\t\t\tif (!element) {\n\t\t\t\telement = document.createElement(\"pie-tool-tts-inline\");\n\t\t\t\t(\n\t\t\t\t\telement as HTMLElement & {\n\t\t\t\t\t\t[key: string]: unknown;\n\t\t\t\t\t}\n\t\t\t\t)[TOOL_ELEMENT_UNMOUNT_CALLBACK_PROP] = () => {\n\t\t\t\t\tif (inlineTTSControls.get(fullToolId) === element) {\n\t\t\t\t\t\tinlineTTSControls.delete(fullToolId);\n\t\t\t\t\t}\n\t\t\t\t};\n\t\t\t\tinlineTTSControls.set(fullToolId, element);\n\t\t\t}\n\t\t\telement.setAttribute(\"tool-id\", fullToolId);\n\t\t\telement.setAttribute(\"catalog-id\", toolbarContext.catalogId || toolbarContext.itemId);\n\t\t\telement.setAttribute(\"language\", toolbarContext.language || \"en-US\");\n\t\t\telement.setAttribute(\"size\", resolveControlSize());\n\t\t\telement.setAttribute(\"layout-mode\", resolveLayoutMode());\n\t\t\t(element as HTMLElement & { speedOptions?: number[] }).speedOptions =\n\t\t\t\tresolveElementSpeedOptions();\n\t\t\treturn element;\n\t\t};\n\t\tconst hostLayout = resolveHostLayout();\n\n\t\treturn {\n\t\t\ttoolId: this.toolId,\n\t\t\tbutton: null,\n\t\t\telements: [\n\t\t\t\t{\n\t\t\t\t\telement: ensureElement(),\n\t\t\t\t\tmount: hostLayout.mount,\n\t\t\t\t\tlayoutHints: {\n\t\t\t\t\t\tcontrolsRow: {\n\t\t\t\t\t\t\treserveSpace: hostLayout.controlsRow.reserveSpace,\n\t\t\t\t\t\t\tshowWhenToolActive: hostLayout.controlsRow.expandWhenToolActive,\n\t\t\t\t\t\t},\n\t\t\t\t\t},\n\t\t\t\t},\n\t\t\t],\n\t\t\tsubscribeActive: (callback) => {\n\t\t\t\tconst element = ensureElement();\n\t\t\t\tconst handler = (event: Event) => {\n\t\t\t\t\tconst detail = (event as CustomEvent<{ active?: boolean }>).detail;\n\t\t\t\t\tcallback(detail?.active === true);\n\t\t\t\t};\n\t\t\t\telement.addEventListener(TOOL_ACTIVE_CHANGE_EVENT, handler);\n\t\t\t\treturn () => {\n\t\t\t\t\telement.removeEventListener(TOOL_ACTIVE_CHANGE_EVENT, handler);\n\t\t\t\t};\n\t\t\t},\n\t\t\tsync: () => {\n\t\t\t\tconst element = ensureElement();\n\t\t\t\telement.setAttribute(\"tool-id\", fullToolId);\n\t\t\t\telement.setAttribute(\"catalog-id\", toolbarContext.catalogId || toolbarContext.itemId);\n\t\t\t\telement.setAttribute(\"language\", toolbarContext.language || \"en-US\");\n\t\t\t\telement.setAttribute(\"size\", resolveControlSize());\n\t\t\t\telement.setAttribute(\"layout-mode\", resolveLayoutMode());\n\t\t\t\t(element as HTMLElement & { speedOptions?: number[] }).speedOptions =\n\t\t\t\t\tresolveElementSpeedOptions();\n\t\t\t},\n\t\t};\n\t},\n};\n"]}
1
+ {"version":3,"file":"tts.js","sourceRoot":"","sources":["../../../src/tools/registrations/tts.ts"],"names":[],"mappings":"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","sourcesContent":["/**\n * Text-to-Speech (TTS) Tool Registration\n *\n * Registers the TTS tool for reading content aloud.\n *\n * Maps to QTI 3.0 standard access features:\n * - textToSpeech (auditory support)\n * - readAloud (auditory support)\n */\n\nimport type {\n\tToolRegistration,\n\tToolToolbarRenderResult,\n\tToolbarContext,\n} from \"../../services/ToolRegistry.js\";\nimport type { ToolContext } from \"../../services/tool-context.js\";\nimport { hasReadableText } from \"../../services/tool-context.js\";\nimport { createScopedToolId } from \"../../services/tool-instance-id.js\";\nimport {\n\tbuildRuntimeTTSConfig,\n\tnormalizeTTSLayoutMode,\n\tnormalizeTTSSpeedOptions,\n\tresolveTTSHostToolbarLayout,\n\tresolveTTSLayoutMode,\n\tresolveTTSBackend,\n\tresolveTTSRuntimeSettings,\n\tresolveRuntimeProvider,\n\tresolveTransportMode,\n} from \"../../services/tts-runtime-config.js\";\nimport { TTSToolProvider } from \"../../services/tool-providers/index.js\";\n\nconst inlineTTSControls = new Map<string, HTMLElement>();\nexport const TOOL_ELEMENT_UNMOUNT_CALLBACK_PROP = \"__pieToolElementUnmount\";\nexport const TOOL_ACTIVE_CHANGE_EVENT = \"pie-tool-active-change\";\n\n/**\n * Text-to-Speech tool registration\n *\n * Supports:\n * - Reading content aloud using browser TTS or external providers\n * - Context-aware visibility (shows when readable text is available)\n * - All levels except assessment and element\n */\nexport const ttsToolRegistration: ToolRegistration = {\n\ttoolId: \"textToSpeech\",\n\tname: \"Text to Speech\",\n\tdescription: \"Read content aloud\",\n\ticon: \"volume-up\",\n\tprovider: {\n\t\tgetProviderId: () => \"tts\",\n\t\tcreateProvider: (config) => {\n\t\t\tconst settings = resolveTTSRuntimeSettings(config);\n\t\t\treturn new TTSToolProvider(resolveTTSBackend(settings));\n\t\t},\n\t\tgetInitConfig: (config) => {\n\t\t\tconst settings = resolveTTSRuntimeSettings(config);\n\t\t\tconst backend = resolveTTSBackend(settings);\n\t\t\tconst serverProvider = resolveRuntimeProvider(settings, backend);\n\t\t\tconst transportMode = resolveTransportMode(settings, serverProvider);\n\t\t\treturn {\n\t\t\t\tbackend,\n\t\t\t\tserverProvider,\n\t\t\t\ttransportMode,\n\t\t\t\t...buildRuntimeTTSConfig(settings),\n\t\t\t};\n\t\t},\n\t\tgetAuthFetcher: (config) => {\n\t\t\tconst runtimeAuthFetcher = config?.provider?.runtime?.authFetcher;\n\t\t\treturn typeof runtimeAuthFetcher === \"function\"\n\t\t\t\t? runtimeAuthFetcher\n\t\t\t\t: undefined;\n\t\t},\n\t\tsanitizeConfig: (config) => {\n\t\t\tconst settings =\n\t\t\t\tconfig.settings && typeof config.settings === \"object\"\n\t\t\t\t\t? { ...(config.settings as Record<string, unknown>) }\n\t\t\t\t\t: undefined;\n\t\t\tif (settings && \"layoutMode\" in settings) {\n\t\t\t\tsettings.layoutMode = normalizeTTSLayoutMode(settings.layoutMode);\n\t\t\t}\n\t\t\tif (settings && \"speedOptions\" in settings) {\n\t\t\t\tsettings.speedOptions = normalizeTTSSpeedOptions(settings.speedOptions);\n\t\t\t}\n\t\t\tconst normalizedConfig: Record<string, unknown> = {\n\t\t\t\t...(config as Record<string, unknown>),\n\t\t\t};\n\t\t\tif (\"layoutMode\" in normalizedConfig) {\n\t\t\t\tnormalizedConfig.layoutMode = normalizeTTSLayoutMode(\n\t\t\t\t\tnormalizedConfig.layoutMode,\n\t\t\t\t);\n\t\t\t}\n\t\t\tif (\"speedOptions\" in normalizedConfig) {\n\t\t\t\tnormalizedConfig.speedOptions = normalizeTTSSpeedOptions(\n\t\t\t\t\tnormalizedConfig.speedOptions,\n\t\t\t\t);\n\t\t\t}\n\t\t\tif (settings) {\n\t\t\t\tnormalizedConfig.settings = settings;\n\t\t\t}\n\t\t\treturn normalizedConfig as typeof config;\n\t\t},\n\t\tlazy: true,\n\t},\n\n\t// TTS is inline-only and scoped to item/passage contexts.\n\tsupportedLevels: [\"item\", \"passage\"],\n\n\t// PNP support IDs that enable this tool\n\t// Maps to QTI 3.0 standard features: textToSpeech, readAloud\n\tpnpSupportIds: [\n\t\t\"textToSpeech\", // QTI 3.0 standard (auditory.textToSpeech)\n\t\t\"readAloud\", // QTI 3.0 standard (auditory.readAloud)\n\t\t\"tts\", // Common abbreviation\n\t\t\"speechOutput\", // Common variant\n\t],\n\n\t/**\n\t * Pass 2: Determine if TTS is relevant in this context\n\t *\n\t * TTS is relevant when:\n\t * - Context contains readable text (at least 10 characters)\n\t */\n\tisVisibleInContext(context: ToolContext): boolean {\n\t\treturn hasReadableText(context);\n\t},\n\n\trenderToolbar(\n\t\t_context: ToolContext,\n\t\ttoolbarContext: ToolbarContext,\n\t): ToolToolbarRenderResult {\n\t\tconst resolveRuntimeSettings = () =>\n\t\t\tresolveTTSRuntimeSettings(\n\t\t\t\ttoolbarContext.toolkitCoordinator?.getToolConfig(this.toolId) ||\n\t\t\t\t\tundefined,\n\t\t\t);\n\t\tconst resolveElementSpeedOptions = (): number[] => {\n\t\t\tconst runtimeSettings = resolveRuntimeSettings();\n\t\t\treturn normalizeTTSSpeedOptions(runtimeSettings.speedOptions);\n\t\t};\n\t\tconst resolveLayoutMode = () =>\n\t\t\tresolveTTSLayoutMode(resolveRuntimeSettings());\n\t\tconst resolveHostLayout = () =>\n\t\t\tresolveTTSHostToolbarLayout(resolveRuntimeSettings());\n\t\tconst fullToolId = createScopedToolId(\n\t\t\tthis.toolId,\n\t\t\ttoolbarContext.scope.level,\n\t\t\ttoolbarContext.scope.scopeId,\n\t\t);\n\t\tconst resolveControlSize = (): \"sm\" | \"md\" | \"lg\" => {\n\t\t\tconst raw = toolbarContext.ui?.size;\n\t\t\treturn raw === \"sm\" || raw === \"lg\" ? raw : \"md\";\n\t\t};\n\t\tconst ensureElement = (): HTMLElement => {\n\t\t\tlet element = inlineTTSControls.get(fullToolId);\n\t\t\tif (\n\t\t\t\telement &&\n\t\t\t\ttypeof (element as { isConnected?: boolean }).isConnected ===\n\t\t\t\t\t\"boolean\" &&\n\t\t\t\t!(element as { isConnected?: boolean }).isConnected\n\t\t\t) {\n\t\t\t\tinlineTTSControls.delete(fullToolId);\n\t\t\t\telement = undefined;\n\t\t\t}\n\t\t\tif (!element) {\n\t\t\t\telement = document.createElement(\"pie-tool-tts-inline\");\n\t\t\t\t(\n\t\t\t\t\telement as HTMLElement & {\n\t\t\t\t\t\t[key: string]: unknown;\n\t\t\t\t\t}\n\t\t\t\t)[TOOL_ELEMENT_UNMOUNT_CALLBACK_PROP] = () => {\n\t\t\t\t\tif (inlineTTSControls.get(fullToolId) === element) {\n\t\t\t\t\t\tinlineTTSControls.delete(fullToolId);\n\t\t\t\t\t}\n\t\t\t\t};\n\t\t\t\tinlineTTSControls.set(fullToolId, element);\n\t\t\t}\n\t\t\telement.setAttribute(\"tool-id\", fullToolId);\n\t\t\telement.setAttribute(\n\t\t\t\t\"catalog-id\",\n\t\t\t\ttoolbarContext.catalogId || toolbarContext.itemId,\n\t\t\t);\n\t\t\telement.setAttribute(\"language\", toolbarContext.language || \"en-US\");\n\t\t\telement.setAttribute(\"size\", resolveControlSize());\n\t\t\telement.setAttribute(\"layout-mode\", resolveLayoutMode());\n\t\t\t(element as HTMLElement & { speedOptions?: number[] }).speedOptions =\n\t\t\t\tresolveElementSpeedOptions();\n\t\t\treturn element;\n\t\t};\n\t\tconst hostLayout = resolveHostLayout();\n\n\t\treturn {\n\t\t\ttoolId: this.toolId,\n\t\t\tbutton: null,\n\t\t\telements: [\n\t\t\t\t{\n\t\t\t\t\telement: ensureElement(),\n\t\t\t\t\tmount: hostLayout.mount,\n\t\t\t\t\tlayoutHints: {\n\t\t\t\t\t\tcontrolsRow: {\n\t\t\t\t\t\t\treserveSpace: hostLayout.controlsRow.reserveSpace,\n\t\t\t\t\t\t\tshowWhenToolActive: hostLayout.controlsRow.expandWhenToolActive,\n\t\t\t\t\t\t},\n\t\t\t\t\t},\n\t\t\t\t},\n\t\t\t],\n\t\t\tsubscribeActive: (callback) => {\n\t\t\t\tconst element = ensureElement();\n\t\t\t\tconst handler = (event: Event) => {\n\t\t\t\t\tconst detail = (event as CustomEvent<{ active?: boolean }>).detail;\n\t\t\t\t\tcallback(detail?.active === true);\n\t\t\t\t};\n\t\t\t\telement.addEventListener(TOOL_ACTIVE_CHANGE_EVENT, handler);\n\t\t\t\treturn () => {\n\t\t\t\t\telement.removeEventListener(TOOL_ACTIVE_CHANGE_EVENT, handler);\n\t\t\t\t};\n\t\t\t},\n\t\t\tsync: () => {\n\t\t\t\tconst element = ensureElement();\n\t\t\t\telement.setAttribute(\"tool-id\", fullToolId);\n\t\t\t\telement.setAttribute(\n\t\t\t\t\t\"catalog-id\",\n\t\t\t\t\ttoolbarContext.catalogId || toolbarContext.itemId,\n\t\t\t\t);\n\t\t\t\telement.setAttribute(\"language\", toolbarContext.language || \"en-US\");\n\t\t\t\telement.setAttribute(\"size\", resolveControlSize());\n\t\t\t\telement.setAttribute(\"layout-mode\", resolveLayoutMode());\n\t\t\t\t(element as HTMLElement & { speedOptions?: number[] }).speedOptions =\n\t\t\t\t\tresolveElementSpeedOptions();\n\t\t\t},\n\t\t};\n\t},\n};\n"]}
@@ -1 +1 @@
1
- {"version":3,"file":"types.js","sourceRoot":"","sources":["../../src/tools/types.ts"],"names":[],"mappings":"AAAA;;GAEG;AAyPH;;GAEG;AACH,MAAM,CAAN,IAAY,YAIX;AAJD,WAAY,YAAY;IACvB,yCAAyB,CAAA;IACzB,2DAA2C,CAAA;IAC3C,uDAAuC,CAAA;AACxC,CAAC,EAJW,YAAY,KAAZ,YAAY,QAIvB","sourcesContent":["/**\n * Tool system type definitions\n */\n\n// Re-export calculator types from @pie-players/pie-calculator\nexport type {\n\tCalculationHistoryEntry,\n\tCalculator,\n\tCalculatorProvider,\n\tCalculatorProviderCapabilities,\n\tCalculatorProviderConfig,\n\tCalculatorState,\n\tCalculatorType,\n\tDesmosCalculatorConfig,\n} from \"@pie-players/pie-calculator\";\n\nexport type ToolId = string;\n\nexport interface ToolState {\n\tid: ToolId;\n\tname: string;\n\tisVisible: boolean;\n\tisActive: boolean;\n\tzIndex: number;\n\telement?: HTMLElement;\n}\n\nexport interface ToolPosition {\n\tx: number;\n\ty: number;\n}\n\nexport interface ToolSize {\n\twidth: number;\n\theight: number;\n}\n\nexport interface ToolConfig {\n\tid: ToolId;\n\tname: string;\n\ticon?: string;\n\tenabled: boolean;\n\talwaysAvailable?: boolean; // If true, available regardless of assessment config\n}\n\nexport interface AssessmentToolConfig {\n\tenabledTools: ToolId[];\n\ttoolSettings?: Record<ToolId, any>;\n}\n\n// ===== ARCHITECTURAL ENHANCEMENTS =====\n\n/**\n * Tool allowance: \"0\" = blocked, \"1\" = allowed\n * Based on existing platform patterns\n */\nexport type ToolAllowance = \"0\" | \"1\";\n\n/**\n * Roster/Test-level tool configuration\n * Defines default tool availability for an assessment\n */\nexport interface RosterToolConfiguration {\n\trosterId: string;\n\ttestId?: string;\n\ttoolAllowances: Record<string, ToolAllowance>;\n\tdefaultToolConfigs?: Record<string, ToolConfig>;\n}\n\n/**\n * Configuration source for tool resolution\n */\nexport type ConfigurationSource =\n\t| \"roster-block\"\n\t| \"item-restriction\"\n\t| \"item-requirement\"\n\t| \"student-accommodation\"\n\t| \"roster-default\"\n\t| \"system-default\";\n\n/**\n * Resolved tool configuration with source tracking\n */\nexport interface ResolvedToolConfig extends ToolConfig {\n\tresolvedFrom: ConfigurationSource;\n\trequired: boolean;\n\treason: string;\n}\n\n/**\n * Tool resolution result\n */\nexport interface ToolResolutionResult {\n\tallowed: boolean;\n\treason: string;\n\tsource: ConfigurationSource;\n\tconfig?: ToolConfig;\n}\n\n/**\n * Item-level tool configuration\n */\nexport interface ItemToolConfig {\n\titemId: string;\n\trequiredTools?: string[];\n\trestrictedTools?: string[];\n\ttoolParameters?: Record<string, ItemToolParameters>;\n\tvariantConfig?: ItemVariantConfig;\n}\n\n/**\n * Item tool parameters\n */\nexport interface ItemToolParameters {\n\tconfig?: Partial<ToolConfig>;\n\thint?: string;\n\tpreOpen?: boolean;\n\tvariants?: Record<string, ItemToolParametersVariant>;\n}\n\n/**\n * Item tool parameters variant\n */\nexport interface ItemToolParametersVariant {\n\tconfig?: Partial<ToolConfig>;\n\thint?: string;\n\tpreOpen?: boolean;\n}\n\n/**\n * Item variant configuration for A/B testing and scaffolding\n */\nexport interface ItemVariantConfig {\n\tvariantId?: string;\n\ttoolOverrides?: Record<string, ItemToolOverride>;\n\tadaptations?: ContentAdaptation[];\n\texperimental?: Record<string, any>;\n}\n\n/**\n * Tool override for item variants\n */\nexport interface ItemToolOverride {\n\tconfig?: Partial<ToolConfig>;\n\tuiVariant?: string;\n\tparameters?: Record<string, any>;\n\treplacementTool?: string;\n}\n\n/**\n * Content adaptation types\n */\nexport interface ContentAdaptation {\n\ttype: \"scaffolding\" | \"difficulty\" | \"language\" | \"modality\" | \"custom\";\n\tlevel: string | number;\n\taffectedTools?: string[];\n\tconfig?: Record<string, any>;\n}\n\n/**\n * Variant context for resolution\n */\nexport interface VariantContext {\n\tstudentId: string;\n\tsessionId: string;\n\tlanguage?: string;\n\tscaffoldingLevel?: number;\n\tdifficultyLevel?: string;\n\tcustom?: Record<string, any>;\n}\n\n/**\n * Resolved item configuration with variants applied\n */\nexport interface ResolvedItemConfig {\n\titemId: string;\n\trequiredTools: string[];\n\trestrictedTools: string[];\n\ttoolParameters: Record<string, ResolvedItemToolParameters>;\n\tappliedVariant?: string;\n\tappliedAdaptations?: ContentAdaptation[];\n}\n\n/**\n * Resolved item tool parameters\n */\nexport interface ResolvedItemToolParameters extends ItemToolParameters {\n\tfinalConfig: ToolConfig;\n}\n\n/**\n * Library configuration for external dependencies\n */\nexport interface LibraryConfig {\n\tid: string;\n\turl: string;\n\tfallbackUrls?: string[];\n\tglobalVar?: string;\n\tdependencies?: string[];\n\tintegrity?: string;\n\tcrossorigin?: \"anonymous\" | \"use-credentials\";\n\ttimeout?: number;\n\tasync?: boolean;\n\tdefer?: boolean;\n\tretry?: RetryConfig;\n}\n\n/**\n * Retry configuration for library loading\n */\nexport interface RetryConfig {\n\tmaxAttempts: number;\n\tdelay: number;\n\tbackoffMultiplier?: number;\n}\n\n/**\n * Library loader statistics\n */\nexport interface LoaderStats {\n\tloaded: string[];\n\tfailed: string[];\n\tpending: string[];\n\tcacheHits: number;\n\tcacheMisses: number;\n\ttotalLoadTime: number;\n}\n\n/**\n * Base interface that all tool components should implement\n */\nexport interface Tool {\n\t/** Unique identifier for this tool */\n\tid: ToolId;\n\n\t/** Display name */\n\tname: string;\n\n\t/** Show the tool */\n\tshow(): void;\n\n\t/** Hide the tool */\n\thide(): void;\n\n\t/** Toggle visibility */\n\ttoggle(): void;\n\n\t/** Cleanup when tool is destroyed */\n\tdestroy?(): void;\n}\n\n/**\n * Tool categories for organizational purposes\n */\nexport enum ToolCategory {\n\tSTANDALONE = \"standalone\",\n\tCONTENT_INTERACTIVE = \"content-interactive\",\n\tSERVICE_DEPENDENT = \"service-dependent\",\n}\n\n/**\n * Tool metadata\n */\nexport interface ToolMetadata {\n\tid: ToolId;\n\tname: string;\n\tdescription: string;\n\tcategory: ToolCategory;\n\ticon?: string;\n\tdependencies?: string[];\n}\n\n// ===== SERVICE INTERFACES (Architectural Enhancements) =====\n\n/**\n * Accommodation Resolver Service\n * Resolves final tool configuration by merging roster, student, and item configs\n * Precedence: Roster block > Item restriction > Item requirement > Student accommodation > Roster default\n */\nexport interface AccommodationResolver {\n\t/**\n\t * Resolve final tools for an item given all configuration sources\n\t */\n\tresolveToolsForItem(\n\t\tstudent: AccommodationProfile,\n\t\troster: RosterToolConfiguration,\n\t\titem: ItemToolConfig,\n\t): ResolvedToolConfig[];\n\n\t/**\n\t * Check if a specific tool is allowed\n\t */\n\tisToolAllowed(\n\t\ttoolType: string,\n\t\tstudent: AccommodationProfile,\n\t\troster: RosterToolConfiguration,\n\t\titem: ItemToolConfig,\n\t): ToolResolutionResult;\n\n\t/**\n\t * Get resolution trace for debugging\n\t */\n\tgetResolutionTrace(\n\t\ttoolType: string,\n\t\tstudent: AccommodationProfile,\n\t\troster: RosterToolConfiguration,\n\t\titem: ItemToolConfig,\n\t): ResolutionTrace;\n}\n\n/**\n * Accommodation profile (student-level tool permissions)\n */\nexport interface AccommodationProfile {\n\tstudentId: string;\n\ttestId?: string;\n\trosterId?: string;\n\taccommodations: Record<string, boolean>;\n}\n\n/**\n * Resolution trace for debugging\n */\nexport interface ResolutionTrace {\n\ttoolType: string;\n\tsteps: ResolutionStep[];\n\tfinalDecision: ToolResolutionResult;\n}\n\n/**\n * Resolution step in trace\n */\nexport interface ResolutionStep {\n\tsource: ConfigurationSource;\n\tdecision: \"allow\" | \"block\" | \"require\" | \"skip\";\n\treason: string;\n\tconfig?: Partial<ToolConfig>;\n}\n\n/**\n * Variant Resolver Service\n * Resolves item configuration considering variants\n */\nexport interface VariantResolver {\n\t/**\n\t * Resolve variant configuration for an item\n\t */\n\tresolveVariant(\n\t\titemConfig: ItemToolConfig,\n\t\tcontext: VariantContext,\n\t): ResolvedItemConfig;\n}\n\n/**\n * Library Loader Service\n * Dynamically loads external libraries with retry and fallback support\n */\nexport interface LibraryLoader {\n\t/**\n\t * Load a JavaScript library\n\t */\n\tloadScript(library: LibraryConfig): Promise<void>;\n\n\t/**\n\t * Load a stylesheet\n\t */\n\tloadStylesheet(url: string, targetRoot?: Document | ShadowRoot): Promise<void>;\n\n\t/**\n\t * Check if a library is already loaded\n\t */\n\tisLoaded(libraryId: string): boolean;\n\n\t/**\n\t * Preload multiple libraries in parallel\n\t */\n\tpreload(libraries: LibraryConfig[]): Promise<void>;\n\n\t/**\n\t * Unload a library (remove script tag)\n\t */\n\tunload(libraryId: string): void;\n\n\t/**\n\t * Get loader statistics\n\t */\n\tgetStats(): LoaderStats;\n}\n\n// Calculator types now exported from @pie-players/pie-calculator (see top of file)\n\n/**\n * PIE Response Component Interface\n * For tool-to-response integration (e.g., calculator inserting into text field)\n */\nexport interface PIEResponseComponent {\n\treadonly responseId: string;\n\treadonly responseType: PIEResponseType;\n\n\tgetCapabilities(): ResponseCapabilities;\n\tcanAccept(content: string, format: ContentFormat): boolean;\n\tinsertContent(\n\t\tcontent: string,\n\t\toptions: InsertionOptions,\n\t): Promise<InsertionResult>;\n\tgetContent(format?: ContentFormat): string;\n\tgetCursorPosition(): number | null;\n\tsetCursorPosition(position: number): void;\n\tfocus(): void;\n\tisFocused(): boolean;\n\tvalidate(content: string, format: ContentFormat): ValidationResult;\n}\n\n/**\n * PIE response types\n */\nexport type PIEResponseType =\n\t| \"text-entry\"\n\t| \"extended-text-entry\"\n\t| \"math-inline\"\n\t| \"math-block\"\n\t| \"numeric\"\n\t| \"multiple-choice\"\n\t| \"custom\";\n\n/**\n * Response capabilities\n */\nexport interface ResponseCapabilities {\n\tacceptsPlainText?: boolean;\n\tacceptsLatex?: boolean;\n\tacceptsNumeric?: boolean;\n\tacceptsHtml?: boolean;\n\tacceptsFormattedText?: boolean;\n\tsupportedFormats: ContentFormat[];\n\tsupportsReplacement?: boolean;\n\tsupportsInsertion?: boolean;\n\tsupportsAppend?: boolean;\n\tmaxLength?: number;\n\tallowedCharacters?: string;\n}\n\n/**\n * Content formats\n */\nexport type ContentFormat =\n\t| \"plain-text\"\n\t| \"latex\"\n\t| \"mathml\"\n\t| \"numeric\"\n\t| \"html\"\n\t| \"markdown\"\n\t| \"formatted-text\";\n\n/**\n * Insertion options for response content\n */\nexport interface InsertionOptions {\n\tmode: \"replace\" | \"insert\" | \"append\";\n\tformat: ContentFormat;\n\tposition?: number;\n\tselect?: boolean;\n\tfocus?: boolean;\n\tsource?: {\n\t\ttoolId: string;\n\t\ttoolType: string;\n\t\ttimestamp: number;\n\t};\n}\n\n/**\n * Insertion result\n */\nexport interface InsertionResult {\n\tsuccess: boolean;\n\terror?: string;\n\tinsertedLength?: number;\n\tfinalCursorPosition?: number;\n}\n\n/**\n * Validation result\n */\nexport interface ValidationResult {\n\tvalid: boolean;\n\terrors?: ValidationError[];\n\twarnings?: string[];\n}\n\n/**\n * Validation error\n */\nexport interface ValidationError {\n\tcode: string;\n\tmessage: string;\n\tposition?: number;\n}\n\n/**\n * Response Discovery Service\n * Finds and manages PIE response components for tool integration\n */\nexport interface ResponseDiscoveryService {\n\tgetActiveResponse(): PIEResponseComponent | null;\n\tgetResponse(responseId: string): PIEResponseComponent | null;\n\tgetAllResponses(): PIEResponseComponent[];\n\tgetResponsesAccepting(format: ContentFormat): PIEResponseComponent[];\n\tregisterResponse(response: PIEResponseComponent): void;\n\tunregisterResponse(responseId: string): void;\n\tsignalActive(responseId: string): void;\n\tsignalInactive(responseId: string): void;\n\tonActiveResponseChanged(\n\t\tlistener: (response: PIEResponseComponent | null) => void,\n\t): void;\n}\n"]}
1
+ {"version":3,"file":"types.js","sourceRoot":"","sources":["../../src/tools/types.ts"],"names":[],"mappings":"AAAA;;GAEG;AAyPH;;GAEG;AACH,MAAM,CAAN,IAAY,YAIX;AAJD,WAAY,YAAY;IACvB,yCAAyB,CAAA;IACzB,2DAA2C,CAAA;IAC3C,uDAAuC,CAAA;AACxC,CAAC,EAJW,YAAY,KAAZ,YAAY,QAIvB","sourcesContent":["/**\n * Tool system type definitions\n */\n\n// Re-export calculator types from @pie-players/pie-calculator\nexport type {\n\tCalculationHistoryEntry,\n\tCalculator,\n\tCalculatorProvider,\n\tCalculatorProviderCapabilities,\n\tCalculatorProviderConfig,\n\tCalculatorState,\n\tCalculatorType,\n\tDesmosCalculatorConfig,\n} from \"@pie-players/pie-calculator\";\n\nexport type ToolId = string;\n\nexport interface ToolState {\n\tid: ToolId;\n\tname: string;\n\tisVisible: boolean;\n\tisActive: boolean;\n\tzIndex: number;\n\telement?: HTMLElement;\n}\n\nexport interface ToolPosition {\n\tx: number;\n\ty: number;\n}\n\nexport interface ToolSize {\n\twidth: number;\n\theight: number;\n}\n\nexport interface ToolConfig {\n\tid: ToolId;\n\tname: string;\n\ticon?: string;\n\tenabled: boolean;\n\talwaysAvailable?: boolean; // If true, available regardless of assessment config\n}\n\nexport interface AssessmentToolConfig {\n\tenabledTools: ToolId[];\n\ttoolSettings?: Record<ToolId, any>;\n}\n\n// ===== ARCHITECTURAL ENHANCEMENTS =====\n\n/**\n * Tool allowance: \"0\" = blocked, \"1\" = allowed\n * Based on existing platform patterns\n */\nexport type ToolAllowance = \"0\" | \"1\";\n\n/**\n * Roster/Test-level tool configuration\n * Defines default tool availability for an assessment\n */\nexport interface RosterToolConfiguration {\n\trosterId: string;\n\ttestId?: string;\n\ttoolAllowances: Record<string, ToolAllowance>;\n\tdefaultToolConfigs?: Record<string, ToolConfig>;\n}\n\n/**\n * Configuration source for tool resolution\n */\nexport type ConfigurationSource =\n\t| \"roster-block\"\n\t| \"item-restriction\"\n\t| \"item-requirement\"\n\t| \"student-accommodation\"\n\t| \"roster-default\"\n\t| \"system-default\";\n\n/**\n * Resolved tool configuration with source tracking\n */\nexport interface ResolvedToolConfig extends ToolConfig {\n\tresolvedFrom: ConfigurationSource;\n\trequired: boolean;\n\treason: string;\n}\n\n/**\n * Tool resolution result\n */\nexport interface ToolResolutionResult {\n\tallowed: boolean;\n\treason: string;\n\tsource: ConfigurationSource;\n\tconfig?: ToolConfig;\n}\n\n/**\n * Item-level tool configuration\n */\nexport interface ItemToolConfig {\n\titemId: string;\n\trequiredTools?: string[];\n\trestrictedTools?: string[];\n\ttoolParameters?: Record<string, ItemToolParameters>;\n\tvariantConfig?: ItemVariantConfig;\n}\n\n/**\n * Item tool parameters\n */\nexport interface ItemToolParameters {\n\tconfig?: Partial<ToolConfig>;\n\thint?: string;\n\tpreOpen?: boolean;\n\tvariants?: Record<string, ItemToolParametersVariant>;\n}\n\n/**\n * Item tool parameters variant\n */\nexport interface ItemToolParametersVariant {\n\tconfig?: Partial<ToolConfig>;\n\thint?: string;\n\tpreOpen?: boolean;\n}\n\n/**\n * Item variant configuration for A/B testing and scaffolding\n */\nexport interface ItemVariantConfig {\n\tvariantId?: string;\n\ttoolOverrides?: Record<string, ItemToolOverride>;\n\tadaptations?: ContentAdaptation[];\n\texperimental?: Record<string, any>;\n}\n\n/**\n * Tool override for item variants\n */\nexport interface ItemToolOverride {\n\tconfig?: Partial<ToolConfig>;\n\tuiVariant?: string;\n\tparameters?: Record<string, any>;\n\treplacementTool?: string;\n}\n\n/**\n * Content adaptation types\n */\nexport interface ContentAdaptation {\n\ttype: \"scaffolding\" | \"difficulty\" | \"language\" | \"modality\" | \"custom\";\n\tlevel: string | number;\n\taffectedTools?: string[];\n\tconfig?: Record<string, any>;\n}\n\n/**\n * Variant context for resolution\n */\nexport interface VariantContext {\n\tstudentId: string;\n\tsessionId: string;\n\tlanguage?: string;\n\tscaffoldingLevel?: number;\n\tdifficultyLevel?: string;\n\tcustom?: Record<string, any>;\n}\n\n/**\n * Resolved item configuration with variants applied\n */\nexport interface ResolvedItemConfig {\n\titemId: string;\n\trequiredTools: string[];\n\trestrictedTools: string[];\n\ttoolParameters: Record<string, ResolvedItemToolParameters>;\n\tappliedVariant?: string;\n\tappliedAdaptations?: ContentAdaptation[];\n}\n\n/**\n * Resolved item tool parameters\n */\nexport interface ResolvedItemToolParameters extends ItemToolParameters {\n\tfinalConfig: ToolConfig;\n}\n\n/**\n * Library configuration for external dependencies\n */\nexport interface LibraryConfig {\n\tid: string;\n\turl: string;\n\tfallbackUrls?: string[];\n\tglobalVar?: string;\n\tdependencies?: string[];\n\tintegrity?: string;\n\tcrossorigin?: \"anonymous\" | \"use-credentials\";\n\ttimeout?: number;\n\tasync?: boolean;\n\tdefer?: boolean;\n\tretry?: RetryConfig;\n}\n\n/**\n * Retry configuration for library loading\n */\nexport interface RetryConfig {\n\tmaxAttempts: number;\n\tdelay: number;\n\tbackoffMultiplier?: number;\n}\n\n/**\n * Library loader statistics\n */\nexport interface LoaderStats {\n\tloaded: string[];\n\tfailed: string[];\n\tpending: string[];\n\tcacheHits: number;\n\tcacheMisses: number;\n\ttotalLoadTime: number;\n}\n\n/**\n * Base interface that all tool components should implement\n */\nexport interface Tool {\n\t/** Unique identifier for this tool */\n\tid: ToolId;\n\n\t/** Display name */\n\tname: string;\n\n\t/** Show the tool */\n\tshow(): void;\n\n\t/** Hide the tool */\n\thide(): void;\n\n\t/** Toggle visibility */\n\ttoggle(): void;\n\n\t/** Cleanup when tool is destroyed */\n\tdestroy?(): void;\n}\n\n/**\n * Tool categories for organizational purposes\n */\nexport enum ToolCategory {\n\tSTANDALONE = \"standalone\",\n\tCONTENT_INTERACTIVE = \"content-interactive\",\n\tSERVICE_DEPENDENT = \"service-dependent\",\n}\n\n/**\n * Tool metadata\n */\nexport interface ToolMetadata {\n\tid: ToolId;\n\tname: string;\n\tdescription: string;\n\tcategory: ToolCategory;\n\ticon?: string;\n\tdependencies?: string[];\n}\n\n// ===== SERVICE INTERFACES (Architectural Enhancements) =====\n\n/**\n * Accommodation Resolver Service\n * Resolves final tool configuration by merging roster, student, and item configs\n * Precedence: Roster block > Item restriction > Item requirement > Student accommodation > Roster default\n */\nexport interface AccommodationResolver {\n\t/**\n\t * Resolve final tools for an item given all configuration sources\n\t */\n\tresolveToolsForItem(\n\t\tstudent: AccommodationProfile,\n\t\troster: RosterToolConfiguration,\n\t\titem: ItemToolConfig,\n\t): ResolvedToolConfig[];\n\n\t/**\n\t * Check if a specific tool is allowed\n\t */\n\tisToolAllowed(\n\t\ttoolType: string,\n\t\tstudent: AccommodationProfile,\n\t\troster: RosterToolConfiguration,\n\t\titem: ItemToolConfig,\n\t): ToolResolutionResult;\n\n\t/**\n\t * Get resolution trace for debugging\n\t */\n\tgetResolutionTrace(\n\t\ttoolType: string,\n\t\tstudent: AccommodationProfile,\n\t\troster: RosterToolConfiguration,\n\t\titem: ItemToolConfig,\n\t): ResolutionTrace;\n}\n\n/**\n * Accommodation profile (student-level tool permissions)\n */\nexport interface AccommodationProfile {\n\tstudentId: string;\n\ttestId?: string;\n\trosterId?: string;\n\taccommodations: Record<string, boolean>;\n}\n\n/**\n * Resolution trace for debugging\n */\nexport interface ResolutionTrace {\n\ttoolType: string;\n\tsteps: ResolutionStep[];\n\tfinalDecision: ToolResolutionResult;\n}\n\n/**\n * Resolution step in trace\n */\nexport interface ResolutionStep {\n\tsource: ConfigurationSource;\n\tdecision: \"allow\" | \"block\" | \"require\" | \"skip\";\n\treason: string;\n\tconfig?: Partial<ToolConfig>;\n}\n\n/**\n * Variant Resolver Service\n * Resolves item configuration considering variants\n */\nexport interface VariantResolver {\n\t/**\n\t * Resolve variant configuration for an item\n\t */\n\tresolveVariant(\n\t\titemConfig: ItemToolConfig,\n\t\tcontext: VariantContext,\n\t): ResolvedItemConfig;\n}\n\n/**\n * Library Loader Service\n * Dynamically loads external libraries with retry and fallback support\n */\nexport interface LibraryLoader {\n\t/**\n\t * Load a JavaScript library\n\t */\n\tloadScript(library: LibraryConfig): Promise<void>;\n\n\t/**\n\t * Load a stylesheet\n\t */\n\tloadStylesheet(\n\t\turl: string,\n\t\ttargetRoot?: Document | ShadowRoot,\n\t): Promise<void>;\n\n\t/**\n\t * Check if a library is already loaded\n\t */\n\tisLoaded(libraryId: string): boolean;\n\n\t/**\n\t * Preload multiple libraries in parallel\n\t */\n\tpreload(libraries: LibraryConfig[]): Promise<void>;\n\n\t/**\n\t * Unload a library (remove script tag)\n\t */\n\tunload(libraryId: string): void;\n\n\t/**\n\t * Get loader statistics\n\t */\n\tgetStats(): LoaderStats;\n}\n\n// Calculator types now exported from @pie-players/pie-calculator (see top of file)\n\n/**\n * PIE Response Component Interface\n * For tool-to-response integration (e.g., calculator inserting into text field)\n */\nexport interface PIEResponseComponent {\n\treadonly responseId: string;\n\treadonly responseType: PIEResponseType;\n\n\tgetCapabilities(): ResponseCapabilities;\n\tcanAccept(content: string, format: ContentFormat): boolean;\n\tinsertContent(\n\t\tcontent: string,\n\t\toptions: InsertionOptions,\n\t): Promise<InsertionResult>;\n\tgetContent(format?: ContentFormat): string;\n\tgetCursorPosition(): number | null;\n\tsetCursorPosition(position: number): void;\n\tfocus(): void;\n\tisFocused(): boolean;\n\tvalidate(content: string, format: ContentFormat): ValidationResult;\n}\n\n/**\n * PIE response types\n */\nexport type PIEResponseType =\n\t| \"text-entry\"\n\t| \"extended-text-entry\"\n\t| \"math-inline\"\n\t| \"math-block\"\n\t| \"numeric\"\n\t| \"multiple-choice\"\n\t| \"custom\";\n\n/**\n * Response capabilities\n */\nexport interface ResponseCapabilities {\n\tacceptsPlainText?: boolean;\n\tacceptsLatex?: boolean;\n\tacceptsNumeric?: boolean;\n\tacceptsHtml?: boolean;\n\tacceptsFormattedText?: boolean;\n\tsupportedFormats: ContentFormat[];\n\tsupportsReplacement?: boolean;\n\tsupportsInsertion?: boolean;\n\tsupportsAppend?: boolean;\n\tmaxLength?: number;\n\tallowedCharacters?: string;\n}\n\n/**\n * Content formats\n */\nexport type ContentFormat =\n\t| \"plain-text\"\n\t| \"latex\"\n\t| \"mathml\"\n\t| \"numeric\"\n\t| \"html\"\n\t| \"markdown\"\n\t| \"formatted-text\";\n\n/**\n * Insertion options for response content\n */\nexport interface InsertionOptions {\n\tmode: \"replace\" | \"insert\" | \"append\";\n\tformat: ContentFormat;\n\tposition?: number;\n\tselect?: boolean;\n\tfocus?: boolean;\n\tsource?: {\n\t\ttoolId: string;\n\t\ttoolType: string;\n\t\ttimestamp: number;\n\t};\n}\n\n/**\n * Insertion result\n */\nexport interface InsertionResult {\n\tsuccess: boolean;\n\terror?: string;\n\tinsertedLength?: number;\n\tfinalCursorPosition?: number;\n}\n\n/**\n * Validation result\n */\nexport interface ValidationResult {\n\tvalid: boolean;\n\terrors?: ValidationError[];\n\twarnings?: string[];\n}\n\n/**\n * Validation error\n */\nexport interface ValidationError {\n\tcode: string;\n\tmessage: string;\n\tposition?: number;\n}\n\n/**\n * Response Discovery Service\n * Finds and manages PIE response components for tool integration\n */\nexport interface ResponseDiscoveryService {\n\tgetActiveResponse(): PIEResponseComponent | null;\n\tgetResponse(responseId: string): PIEResponseComponent | null;\n\tgetAllResponses(): PIEResponseComponent[];\n\tgetResponsesAccepting(format: ContentFormat): PIEResponseComponent[];\n\tregisterResponse(response: PIEResponseComponent): void;\n\tunregisterResponse(responseId: string): void;\n\tsignalActive(responseId: string): void;\n\tsignalInactive(responseId: string): void;\n\tonActiveResponseChanged(\n\t\tlistener: (response: PIEResponseComponent | null) => void,\n\t): void;\n}\n"]}
@@ -1 +1 @@
1
- {"version":3,"file":"variant-resolver.js","sourceRoot":"","sources":["../../src/tools/variant-resolver.ts"],"names":[],"mappings":"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","sourcesContent":["/**\n * Variant Resolver Service\n * Resolves item configuration considering variants for A/B testing, scaffolding, and adaptations\n *\n * Based on architectural enhancements for item-level variant configuration\n */\n\nimport type {\n\tItemToolConfig,\n\tItemToolParameters,\n\tResolvedItemConfig,\n\tResolvedItemToolParameters,\n\tToolConfig,\n\tVariantContext,\n\tVariantResolver,\n} from \"./types.js\";\n\nexport class VariantResolverImpl implements VariantResolver {\n\t/**\n\t * Resolve variant configuration for an item\n\t */\n\tresolveVariant(\n\t\titemConfig: ItemToolConfig,\n\t\tcontext: VariantContext,\n\t): ResolvedItemConfig {\n\t\t// If no variant config, return item as-is\n\t\tif (!itemConfig.variantConfig) {\n\t\t\treturn this._buildResolvedConfig(itemConfig, null, []);\n\t\t}\n\n\t\tconst { variantConfig } = itemConfig;\n\t\tconst { variantId, toolOverrides, adaptations } = variantConfig;\n\n\t\t// Apply tool overrides if variant specified\n\t\tconst resolvedToolParameters: Record<string, ResolvedItemToolParameters> =\n\t\t\t{};\n\n\t\tif (itemConfig.toolParameters) {\n\t\t\tfor (const [toolType, params] of Object.entries(\n\t\t\t\titemConfig.toolParameters,\n\t\t\t)) {\n\t\t\t\tresolvedToolParameters[toolType] = this._resolveToolParameters(\n\t\t\t\t\ttoolType,\n\t\t\t\t\tparams,\n\t\t\t\t\ttoolOverrides,\n\t\t\t\t\tcontext,\n\t\t\t\t);\n\t\t\t}\n\t\t}\n\n\t\t// Apply tool overrides that aren't in original tool parameters\n\t\tif (toolOverrides) {\n\t\t\tfor (const [toolType, override] of Object.entries(toolOverrides)) {\n\t\t\t\tif (!resolvedToolParameters[toolType]) {\n\t\t\t\t\tresolvedToolParameters[toolType] =\n\t\t\t\t\t\tthis._createToolParametersFromOverride(toolType, override);\n\t\t\t\t}\n\t\t\t}\n\t\t}\n\n\t\t// Build final resolved config\n\t\treturn {\n\t\t\titemId: itemConfig.itemId,\n\t\t\trequiredTools: this._resolveRequiredTools(itemConfig, toolOverrides),\n\t\t\trestrictedTools: itemConfig.restrictedTools || [],\n\t\t\ttoolParameters: resolvedToolParameters,\n\t\t\tappliedVariant: variantId,\n\t\t\tappliedAdaptations: this._filterAdaptations(adaptations, context),\n\t\t};\n\t}\n\n\t/**\n\t * Resolve tool parameters considering variant and context\n\t */\n\tprivate _resolveToolParameters(\n\t\ttoolType: string,\n\t\tparams: ItemToolParameters,\n\t\ttoolOverrides: Record<string, any> | undefined,\n\t\tcontext: VariantContext,\n\t): ResolvedItemToolParameters {\n\t\t// Start with base parameters\n\t\tlet finalConfig: Partial<ToolConfig> = params.config || {};\n\t\tlet finalHint = params.hint;\n\t\tlet finalPreOpen = params.preOpen;\n\n\t\t// Apply variant-specific parameters if they exist\n\t\tif (params.variants) {\n\t\t\tconst variantParams = this._selectVariantParameters(\n\t\t\t\tparams.variants,\n\t\t\t\tcontext,\n\t\t\t);\n\t\t\tif (variantParams) {\n\t\t\t\tfinalConfig = { ...finalConfig, ...variantParams.config };\n\t\t\t\tif (variantParams.hint !== undefined) finalHint = variantParams.hint;\n\t\t\t\tif (variantParams.preOpen !== undefined)\n\t\t\t\t\tfinalPreOpen = variantParams.preOpen;\n\t\t\t}\n\t\t}\n\n\t\t// Apply tool override from variant config\n\t\tif (toolOverrides && toolOverrides[toolType]) {\n\t\t\tconst override = toolOverrides[toolType];\n\t\t\tif (override.config) {\n\t\t\t\tfinalConfig = { ...finalConfig, ...override.config };\n\t\t\t}\n\t\t\tif (override.parameters) {\n\t\t\t\t// Merge additional parameters\n\t\t\t\tfinalConfig = { ...finalConfig, ...override.parameters };\n\t\t\t}\n\t\t}\n\n\t\treturn {\n\t\t\tconfig: params.config,\n\t\t\thint: finalHint,\n\t\t\tpreOpen: finalPreOpen,\n\t\t\tvariants: params.variants,\n\t\t\tfinalConfig: finalConfig as ToolConfig,\n\t\t};\n\t}\n\n\t/**\n\t * Select variant parameters based on context\n\t */\n\tprivate _selectVariantParameters(\n\t\tvariants: Record<string, any>,\n\t\tcontext: VariantContext,\n\t): any | null {\n\t\t// Strategy: Select based on context properties\n\n\t\t// 1. Check for scaffolding level match\n\t\tif (context.scaffoldingLevel !== undefined) {\n\t\t\tconst scaffoldKey = `scaffolding-${context.scaffoldingLevel}`;\n\t\t\tif (variants[scaffoldKey]) return variants[scaffoldKey];\n\t\t}\n\n\t\t// 2. Check for difficulty level match\n\t\tif (context.difficultyLevel) {\n\t\t\tconst difficultyKey = `difficulty-${context.difficultyLevel}`;\n\t\t\tif (variants[difficultyKey]) return variants[difficultyKey];\n\t\t}\n\n\t\t// 3. Check for language match\n\t\tif (context.language) {\n\t\t\tconst langKey = `lang-${context.language}`;\n\t\t\tif (variants[langKey]) return variants[langKey];\n\t\t}\n\n\t\t// 4. Check custom context keys\n\t\tif (context.custom) {\n\t\t\tfor (const [key, value] of Object.entries(context.custom)) {\n\t\t\t\tconst customKey = `${key}-${value}`;\n\t\t\t\tif (variants[customKey]) return variants[customKey];\n\t\t\t}\n\t\t}\n\n\t\t// 5. Check for default variant\n\t\tif (variants.default) return variants.default;\n\n\t\treturn null;\n\t}\n\n\t/**\n\t * Create tool parameters from override\n\t */\n\tprivate _createToolParametersFromOverride(\n\t\ttoolType: string,\n\t\toverride: any,\n\t): ResolvedItemToolParameters {\n\t\treturn {\n\t\t\tconfig: override.config,\n\t\t\thint: override.hint,\n\t\t\tpreOpen: override.preOpen,\n\t\t\tfinalConfig: {\n\t\t\t\tid: toolType,\n\t\t\t\tname: this._humanizeName(toolType),\n\t\t\t\tenabled: true,\n\t\t\t\t...override.config,\n\t\t\t},\n\t\t};\n\t}\n\n\t/**\n\t * Resolve required tools considering overrides\n\t */\n\tprivate _resolveRequiredTools(\n\t\titemConfig: ItemToolConfig,\n\t\ttoolOverrides: Record<string, any> | undefined,\n\t): string[] {\n\t\tconst required = new Set<string>(itemConfig.requiredTools || []);\n\n\t\t// Add tools that have replacements via overrides\n\t\tif (toolOverrides) {\n\t\t\tfor (const [toolType, override] of Object.entries(toolOverrides)) {\n\t\t\t\tif (override.replacementTool) {\n\t\t\t\t\trequired.delete(toolType);\n\t\t\t\t\trequired.add(override.replacementTool);\n\t\t\t\t}\n\t\t\t}\n\t\t}\n\n\t\treturn Array.from(required);\n\t}\n\n\t/**\n\t * Filter adaptations based on context\n\t */\n\tprivate _filterAdaptations(\n\t\tadaptations: any[] | undefined,\n\t\tcontext: VariantContext,\n\t): any[] {\n\t\tif (!adaptations) return [];\n\n\t\treturn adaptations.filter((adaptation) => {\n\t\t\t// Check if adaptation matches context\n\t\t\tif (\n\t\t\t\tadaptation.type === \"scaffolding\" &&\n\t\t\t\tcontext.scaffoldingLevel !== undefined\n\t\t\t) {\n\t\t\t\treturn adaptation.level === context.scaffoldingLevel;\n\t\t\t}\n\n\t\t\tif (adaptation.type === \"difficulty\" && context.difficultyLevel) {\n\t\t\t\treturn adaptation.level === context.difficultyLevel;\n\t\t\t}\n\n\t\t\tif (adaptation.type === \"language\" && context.language) {\n\t\t\t\treturn adaptation.level === context.language;\n\t\t\t}\n\n\t\t\t// Include custom adaptations by default\n\t\t\treturn true;\n\t\t});\n\t}\n\n\t/**\n\t * Build resolved config without variants\n\t */\n\tprivate _buildResolvedConfig(\n\t\titemConfig: ItemToolConfig,\n\t\tvariantId: string | null,\n\t\tadaptations: any[],\n\t): ResolvedItemConfig {\n\t\tconst resolvedToolParameters: Record<string, ResolvedItemToolParameters> =\n\t\t\t{};\n\n\t\tif (itemConfig.toolParameters) {\n\t\t\tfor (const [toolType, params] of Object.entries(\n\t\t\t\titemConfig.toolParameters,\n\t\t\t)) {\n\t\t\t\tresolvedToolParameters[toolType] = {\n\t\t\t\t\t...params,\n\t\t\t\t\tfinalConfig: {\n\t\t\t\t\t\tid: toolType,\n\t\t\t\t\t\tname: this._humanizeName(toolType),\n\t\t\t\t\t\tenabled: true,\n\t\t\t\t\t\t...params.config,\n\t\t\t\t\t},\n\t\t\t\t};\n\t\t\t}\n\t\t}\n\n\t\treturn {\n\t\t\titemId: itemConfig.itemId,\n\t\t\trequiredTools: itemConfig.requiredTools || [],\n\t\t\trestrictedTools: itemConfig.restrictedTools || [],\n\t\t\ttoolParameters: resolvedToolParameters,\n\t\t\tappliedVariant: variantId || undefined,\n\t\t\tappliedAdaptations: adaptations,\n\t\t};\n\t}\n\n\t/**\n\t * Convert tool type to human-readable name\n\t */\n\tprivate _humanizeName(toolType: string): string {\n\t\treturn toolType\n\t\t\t.replace(/[-_]/g, \" \")\n\t\t\t.replace(/\\b\\w/g, (char) => char.toUpperCase());\n\t}\n}\n\n"]}
1
+ {"version":3,"file":"variant-resolver.js","sourceRoot":"","sources":["../../src/tools/variant-resolver.ts"],"names":[],"mappings":"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","sourcesContent":["/**\n * Variant Resolver Service\n * Resolves item configuration considering variants for A/B testing, scaffolding, and adaptations\n *\n * Based on architectural enhancements for item-level variant configuration\n */\n\nimport type {\n\tItemToolConfig,\n\tItemToolParameters,\n\tResolvedItemConfig,\n\tResolvedItemToolParameters,\n\tToolConfig,\n\tVariantContext,\n\tVariantResolver,\n} from \"./types.js\";\n\nexport class VariantResolverImpl implements VariantResolver {\n\t/**\n\t * Resolve variant configuration for an item\n\t */\n\tresolveVariant(\n\t\titemConfig: ItemToolConfig,\n\t\tcontext: VariantContext,\n\t): ResolvedItemConfig {\n\t\t// If no variant config, return item as-is\n\t\tif (!itemConfig.variantConfig) {\n\t\t\treturn this._buildResolvedConfig(itemConfig, null, []);\n\t\t}\n\n\t\tconst { variantConfig } = itemConfig;\n\t\tconst { variantId, toolOverrides, adaptations } = variantConfig;\n\n\t\t// Apply tool overrides if variant specified\n\t\tconst resolvedToolParameters: Record<string, ResolvedItemToolParameters> =\n\t\t\t{};\n\n\t\tif (itemConfig.toolParameters) {\n\t\t\tfor (const [toolType, params] of Object.entries(\n\t\t\t\titemConfig.toolParameters,\n\t\t\t)) {\n\t\t\t\tresolvedToolParameters[toolType] = this._resolveToolParameters(\n\t\t\t\t\ttoolType,\n\t\t\t\t\tparams,\n\t\t\t\t\ttoolOverrides,\n\t\t\t\t\tcontext,\n\t\t\t\t);\n\t\t\t}\n\t\t}\n\n\t\t// Apply tool overrides that aren't in original tool parameters\n\t\tif (toolOverrides) {\n\t\t\tfor (const [toolType, override] of Object.entries(toolOverrides)) {\n\t\t\t\tif (!resolvedToolParameters[toolType]) {\n\t\t\t\t\tresolvedToolParameters[toolType] =\n\t\t\t\t\t\tthis._createToolParametersFromOverride(toolType, override);\n\t\t\t\t}\n\t\t\t}\n\t\t}\n\n\t\t// Build final resolved config\n\t\treturn {\n\t\t\titemId: itemConfig.itemId,\n\t\t\trequiredTools: this._resolveRequiredTools(itemConfig, toolOverrides),\n\t\t\trestrictedTools: itemConfig.restrictedTools || [],\n\t\t\ttoolParameters: resolvedToolParameters,\n\t\t\tappliedVariant: variantId,\n\t\t\tappliedAdaptations: this._filterAdaptations(adaptations, context),\n\t\t};\n\t}\n\n\t/**\n\t * Resolve tool parameters considering variant and context\n\t */\n\tprivate _resolveToolParameters(\n\t\ttoolType: string,\n\t\tparams: ItemToolParameters,\n\t\ttoolOverrides: Record<string, any> | undefined,\n\t\tcontext: VariantContext,\n\t): ResolvedItemToolParameters {\n\t\t// Start with base parameters\n\t\tlet finalConfig: Partial<ToolConfig> = params.config || {};\n\t\tlet finalHint = params.hint;\n\t\tlet finalPreOpen = params.preOpen;\n\n\t\t// Apply variant-specific parameters if they exist\n\t\tif (params.variants) {\n\t\t\tconst variantParams = this._selectVariantParameters(\n\t\t\t\tparams.variants,\n\t\t\t\tcontext,\n\t\t\t);\n\t\t\tif (variantParams) {\n\t\t\t\tfinalConfig = { ...finalConfig, ...variantParams.config };\n\t\t\t\tif (variantParams.hint !== undefined) finalHint = variantParams.hint;\n\t\t\t\tif (variantParams.preOpen !== undefined)\n\t\t\t\t\tfinalPreOpen = variantParams.preOpen;\n\t\t\t}\n\t\t}\n\n\t\t// Apply tool override from variant config\n\t\tif (toolOverrides && toolOverrides[toolType]) {\n\t\t\tconst override = toolOverrides[toolType];\n\t\t\tif (override.config) {\n\t\t\t\tfinalConfig = { ...finalConfig, ...override.config };\n\t\t\t}\n\t\t\tif (override.parameters) {\n\t\t\t\t// Merge additional parameters\n\t\t\t\tfinalConfig = { ...finalConfig, ...override.parameters };\n\t\t\t}\n\t\t}\n\n\t\treturn {\n\t\t\tconfig: params.config,\n\t\t\thint: finalHint,\n\t\t\tpreOpen: finalPreOpen,\n\t\t\tvariants: params.variants,\n\t\t\tfinalConfig: finalConfig as ToolConfig,\n\t\t};\n\t}\n\n\t/**\n\t * Select variant parameters based on context\n\t */\n\tprivate _selectVariantParameters(\n\t\tvariants: Record<string, any>,\n\t\tcontext: VariantContext,\n\t): any | null {\n\t\t// Strategy: Select based on context properties\n\n\t\t// 1. Check for scaffolding level match\n\t\tif (context.scaffoldingLevel !== undefined) {\n\t\t\tconst scaffoldKey = `scaffolding-${context.scaffoldingLevel}`;\n\t\t\tif (variants[scaffoldKey]) return variants[scaffoldKey];\n\t\t}\n\n\t\t// 2. Check for difficulty level match\n\t\tif (context.difficultyLevel) {\n\t\t\tconst difficultyKey = `difficulty-${context.difficultyLevel}`;\n\t\t\tif (variants[difficultyKey]) return variants[difficultyKey];\n\t\t}\n\n\t\t// 3. Check for language match\n\t\tif (context.language) {\n\t\t\tconst langKey = `lang-${context.language}`;\n\t\t\tif (variants[langKey]) return variants[langKey];\n\t\t}\n\n\t\t// 4. Check custom context keys\n\t\tif (context.custom) {\n\t\t\tfor (const [key, value] of Object.entries(context.custom)) {\n\t\t\t\tconst customKey = `${key}-${value}`;\n\t\t\t\tif (variants[customKey]) return variants[customKey];\n\t\t\t}\n\t\t}\n\n\t\t// 5. Check for default variant\n\t\tif (variants.default) return variants.default;\n\n\t\treturn null;\n\t}\n\n\t/**\n\t * Create tool parameters from override\n\t */\n\tprivate _createToolParametersFromOverride(\n\t\ttoolType: string,\n\t\toverride: any,\n\t): ResolvedItemToolParameters {\n\t\treturn {\n\t\t\tconfig: override.config,\n\t\t\thint: override.hint,\n\t\t\tpreOpen: override.preOpen,\n\t\t\tfinalConfig: {\n\t\t\t\tid: toolType,\n\t\t\t\tname: this._humanizeName(toolType),\n\t\t\t\tenabled: true,\n\t\t\t\t...override.config,\n\t\t\t},\n\t\t};\n\t}\n\n\t/**\n\t * Resolve required tools considering overrides\n\t */\n\tprivate _resolveRequiredTools(\n\t\titemConfig: ItemToolConfig,\n\t\ttoolOverrides: Record<string, any> | undefined,\n\t): string[] {\n\t\tconst required = new Set<string>(itemConfig.requiredTools || []);\n\n\t\t// Add tools that have replacements via overrides\n\t\tif (toolOverrides) {\n\t\t\tfor (const [toolType, override] of Object.entries(toolOverrides)) {\n\t\t\t\tif (override.replacementTool) {\n\t\t\t\t\trequired.delete(toolType);\n\t\t\t\t\trequired.add(override.replacementTool);\n\t\t\t\t}\n\t\t\t}\n\t\t}\n\n\t\treturn Array.from(required);\n\t}\n\n\t/**\n\t * Filter adaptations based on context\n\t */\n\tprivate _filterAdaptations(\n\t\tadaptations: any[] | undefined,\n\t\tcontext: VariantContext,\n\t): any[] {\n\t\tif (!adaptations) return [];\n\n\t\treturn adaptations.filter((adaptation) => {\n\t\t\t// Check if adaptation matches context\n\t\t\tif (\n\t\t\t\tadaptation.type === \"scaffolding\" &&\n\t\t\t\tcontext.scaffoldingLevel !== undefined\n\t\t\t) {\n\t\t\t\treturn adaptation.level === context.scaffoldingLevel;\n\t\t\t}\n\n\t\t\tif (adaptation.type === \"difficulty\" && context.difficultyLevel) {\n\t\t\t\treturn adaptation.level === context.difficultyLevel;\n\t\t\t}\n\n\t\t\tif (adaptation.type === \"language\" && context.language) {\n\t\t\t\treturn adaptation.level === context.language;\n\t\t\t}\n\n\t\t\t// Include custom adaptations by default\n\t\t\treturn true;\n\t\t});\n\t}\n\n\t/**\n\t * Build resolved config without variants\n\t */\n\tprivate _buildResolvedConfig(\n\t\titemConfig: ItemToolConfig,\n\t\tvariantId: string | null,\n\t\tadaptations: any[],\n\t): ResolvedItemConfig {\n\t\tconst resolvedToolParameters: Record<string, ResolvedItemToolParameters> =\n\t\t\t{};\n\n\t\tif (itemConfig.toolParameters) {\n\t\t\tfor (const [toolType, params] of Object.entries(\n\t\t\t\titemConfig.toolParameters,\n\t\t\t)) {\n\t\t\t\tresolvedToolParameters[toolType] = {\n\t\t\t\t\t...params,\n\t\t\t\t\tfinalConfig: {\n\t\t\t\t\t\tid: toolType,\n\t\t\t\t\t\tname: this._humanizeName(toolType),\n\t\t\t\t\t\tenabled: true,\n\t\t\t\t\t\t...params.config,\n\t\t\t\t\t},\n\t\t\t\t};\n\t\t\t}\n\t\t}\n\n\t\treturn {\n\t\t\titemId: itemConfig.itemId,\n\t\t\trequiredTools: itemConfig.requiredTools || [],\n\t\t\trestrictedTools: itemConfig.restrictedTools || [],\n\t\t\ttoolParameters: resolvedToolParameters,\n\t\t\tappliedVariant: variantId || undefined,\n\t\t\tappliedAdaptations: adaptations,\n\t\t};\n\t}\n\n\t/**\n\t * Convert tool type to human-readable name\n\t */\n\tprivate _humanizeName(toolType: string): string {\n\t\treturn toolType\n\t\t\t.replace(/[-_]/g, \" \")\n\t\t\t.replace(/\\b\\w/g, (char) => char.toUpperCase());\n\t}\n}\n"]}
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@pie-players/pie-assessment-toolkit",
3
- "version": "0.3.47",
3
+ "version": "0.3.49",
4
4
  "type": "module",
5
5
  "description": "PIE assessment toolkit: composable services + reference implementation for assessment players and tool coordination",
6
6
  "license": "MIT",
@@ -75,15 +75,15 @@
75
75
  "test": "bun test"
76
76
  },
77
77
  "dependencies": {
78
- "@pie-players/pie-calculator": "0.3.47",
79
- "@pie-players/pie-context": "0.3.47",
80
- "@pie-players/pie-players-shared": "0.3.47",
81
- "@pie-players/pie-tts": "0.3.47",
78
+ "@pie-players/pie-calculator": "0.3.49",
79
+ "@pie-players/pie-context": "0.3.49",
80
+ "@pie-players/pie-players-shared": "0.3.49",
81
+ "@pie-players/pie-tts": "0.3.49",
82
82
  "speech-rule-engine": "^5.0.0-rc.1"
83
83
  },
84
84
  "peerDependencies": {
85
- "@pie-players/pie-calculator-desmos": "0.3.47",
86
- "@pie-players/tts-client-server": "0.3.47"
85
+ "@pie-players/pie-calculator-desmos": "0.3.49",
86
+ "@pie-players/tts-client-server": "0.3.49"
87
87
  },
88
88
  "peerDependenciesMeta": {
89
89
  "@pie-players/pie-calculator-desmos": {