@qti-components/base 1.5.1 → 2.0.0

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 (58) hide show
  1. package/dist/abstract/interaction.d.ts +54 -64
  2. package/dist/abstract/interaction.js +103 -276
  3. package/dist/abstract/interaction.js.map +1 -1
  4. package/dist/abstract/qti-expression.d.ts +1 -1
  5. package/dist/abstract/qti-expression.js +23 -2
  6. package/dist/abstract/qti-expression.js.map +1 -1
  7. package/dist/abstract/qti-feedback.js +1 -1
  8. package/dist/abstract/qti-feedback.js.map +1 -1
  9. package/dist/context/computed-item.context.d.ts +1 -16
  10. package/dist/context/computed-item.context.js.map +1 -1
  11. package/dist/context/computed.context.d.ts +1 -26
  12. package/dist/context/computed.context.js.map +1 -1
  13. package/dist/context/config.context.d.ts +61 -12
  14. package/dist/context/config.context.js.map +1 -1
  15. package/dist/context/interaction.context.d.ts +36 -0
  16. package/dist/context/interaction.context.js +3 -0
  17. package/dist/context/interaction.context.js.map +1 -0
  18. package/dist/context/item.context.d.ts +4 -12
  19. package/dist/context/item.context.js +2 -16
  20. package/dist/context/item.context.js.map +1 -1
  21. package/dist/context/test.context.d.ts +1 -1
  22. package/dist/context/test.context.js.map +1 -1
  23. package/dist/context/types/computed-item.types.d.ts +16 -0
  24. package/dist/context/types/computed-item.types.js +2 -0
  25. package/dist/context/types/computed-item.types.js.map +1 -0
  26. package/dist/context/types/computed.types.d.ts +26 -0
  27. package/dist/context/types/computed.types.js +2 -0
  28. package/dist/context/types/computed.types.js.map +1 -0
  29. package/dist/context/types/item.types.d.ts +12 -0
  30. package/dist/context/types/item.types.js +17 -0
  31. package/dist/context/types/item.types.js.map +1 -0
  32. package/dist/elements.d.ts +24 -0
  33. package/dist/elements.js +22 -0
  34. package/dist/elements.js.map +1 -0
  35. package/dist/index.d.ts +9 -1
  36. package/dist/index.js +9 -1
  37. package/dist/index.js.map +1 -1
  38. package/dist/lib/interaction.interface.d.ts +39 -15
  39. package/dist/lib/interaction.interface.js.map +1 -1
  40. package/dist/lib/response.d.ts +104 -0
  41. package/dist/lib/response.js +168 -0
  42. package/dist/lib/response.js.map +1 -0
  43. package/dist/register.d.ts +1 -0
  44. package/dist/register.js +7 -0
  45. package/dist/register.js.map +1 -0
  46. package/dist/styles/box-sizing.styles.d.ts +19 -0
  47. package/dist/styles/box-sizing.styles.js +31 -0
  48. package/dist/styles/box-sizing.styles.js.map +1 -0
  49. package/dist/styles/drop-region.styles.d.ts +36 -0
  50. package/dist/styles/drop-region.styles.js +78 -0
  51. package/dist/styles/drop-region.styles.js.map +1 -0
  52. package/dist/styles/validation-message.styles.d.ts +18 -0
  53. package/dist/styles/validation-message.styles.js +24 -0
  54. package/dist/styles/validation-message.styles.js.map +1 -0
  55. package/package.json +16 -1
  56. package/dist/context/qti-assessment-item.context.d.ts +0 -4
  57. package/dist/context/qti-assessment-item.context.js +0 -3
  58. package/dist/context/qti-assessment-item.context.js.map +0 -1
@@ -1 +1 @@
1
- {"version":3,"file":"interaction.js","sourceRoot":"","sources":["../../src/abstract/interaction.ts"],"names":[],"mappings":"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","sourcesContent":["import { property, state } from 'lit/decorators.js';\nimport { LitElement } from 'lit';\nimport { consume } from '@lit/context';\n\nimport { watch } from '@qti-components/utilities';\n\nimport { configContext } from '../context/config.context';\nimport { itemContext } from '../context/qti-assessment-item.context';\n\nimport type { ConfigContext } from '../context/config.context';\nimport type { ResponseVariable } from '../lib/variables';\nimport type { IInteraction } from '../lib/interaction.interface';\nimport type { ItemContext } from '../context/item.context';\n\nexport enum Correctness {\n Correct = 'correct',\n PartiallyCorrect = 'partially-correct',\n Incorrect = 'incorrect'\n}\n\nexport abstract class Interaction extends LitElement implements IInteraction {\n @consume({ context: itemContext, subscribe: true })\n private _context: ItemContext;\n\n @consume({ context: configContext, subscribe: true })\n protected configContext: ConfigContext;\n\n static formAssociated = true;\n protected _internals: ElementInternals;\n\n get internals(): ElementInternals {\n return this._internals;\n }\n\n @property({ type: String, attribute: 'response-identifier' }) responseIdentifier: string;\n\n @property({ reflect: true, type: Boolean }) disabled = false;\n\n @property({ reflect: true, type: Boolean }) readonly = false;\n\n @property({ type: String }) name;\n\n // ═══════════════════════════════════════════════════════════════════════════════\n // CORRECT RESPONSE - Standalone mode attributes\n // ═══════════════════════════════════════════════════════════════════════════════\n\n /**\n * The correct response for this interaction. Can be set as a comma-separated\n * string via attribute or as string/string[] via property.\n *\n * @example\n * ```html\n * <qti-choice-interaction correct-response=\"A,B\">\n * ```\n */\n @property({ type: String, attribute: 'correct-response', reflect: true })\n set correctResponseAttr(val: string | null) {\n if (val === null) {\n this._correctResponse = null;\n } else if (val.includes(',')) {\n this._correctResponse = val.split(',').map(v => v.trim());\n } else {\n this._correctResponse = val;\n }\n }\n\n get correctResponseAttr(): string | null {\n if (this._correctResponse === null || this._correctResponse === undefined) {\n return null;\n }\n return Array.isArray(this._correctResponse) ? this._correctResponse.join(',') : this._correctResponse;\n }\n\n /**\n * Shows which choices are correct with inline indicators.\n * Adds `correct-response` / `incorrect-response` states to choices.\n */\n @property({ type: Boolean, attribute: 'show-correct-response', reflect: true })\n showCorrectResponse = false;\n\n @watch('showCorrectResponse', { waitUntilFirstUpdate: true })\n protected _handleShowCorrectResponseChange = (_: boolean, show: boolean) => {\n this.toggleInternalCorrectResponse(show);\n };\n\n /**\n * Shows a cloned interaction with the correct answers filled in.\n * Creates a disabled copy positioned after this interaction.\n */\n @property({ type: Boolean, attribute: 'show-full-correct-response', reflect: true })\n showFullCorrectResponse = false;\n\n @watch('showFullCorrectResponse', { waitUntilFirstUpdate: true })\n protected _handleShowFullCorrectResponseChange = (_: boolean, show: boolean) => {\n this.toggleFullCorrectResponse(show);\n };\n\n /**\n * Shows feedback on candidate's selections compared to correct response.\n * Adds `candidate-correct` / `candidate-incorrect` states to choices.\n */\n @property({ type: Boolean, attribute: 'show-candidate-correction', reflect: true })\n showCandidateCorrection = false;\n\n @watch('showCandidateCorrection', { waitUntilFirstUpdate: true })\n protected _handleShowCandidateCorrectionChange = (_: boolean, show: boolean) => {\n this.toggleCandidateCorrection(show);\n };\n\n // ═══════════════════════════════════════════════════════════════════════════════\n\n @state()\n protected _isFullCorrectResponse: boolean;\n\n get isFullCorrectResponse(): Readonly<boolean> {\n return this._isFullCorrectResponse;\n }\n\n set isFullCorrectResponse(val: Readonly<boolean>) {\n this._isFullCorrectResponse = val as boolean;\n if (val) {\n this.disabled = true;\n this.setAttribute('inert', '');\n this.setAttribute('response-identifier', this.responseIdentifier + '_cr');\n }\n }\n\n /* PK: Correct response */\n @state()\n protected _correctResponse: string | string[] | null = null;\n\n /**\n * Get/set correct response programmatically.\n * This property syncs with the `correct-response` attribute.\n */\n get correctResponse(): Readonly<string | string[] | null> {\n // In standalone mode, use the local _correctResponse\n // In item context mode, prefer responseVariable.correctResponse\n const responseVariable = this.responseVariable;\n if (responseVariable?.correctResponse) {\n return responseVariable.correctResponse;\n }\n return this._correctResponse;\n }\n\n set correctResponse(val: Readonly<string | string[] | null>) {\n const oldVal = this._correctResponse;\n this._correctResponse = val as string | string[] | null;\n // Sync to attribute\n if (val === null || val === undefined) {\n this.removeAttribute('correct-response');\n } else {\n this.setAttribute('correct-response', Array.isArray(val) ? val.join(',') : (val as string));\n }\n this.requestUpdate('_correctResponse', oldVal);\n }\n\n /**\n * Returns the correctness of the current response compared to correct response.\n * Works in both standalone mode (using `correct-response` attribute) and\n * item context mode (using responseVariable).\n */\n get correctness(): Readonly<Correctness | null> {\n const correctResponse = this.correctResponse;\n if (!correctResponse) return null;\n\n const currentResponse = this.response;\n // No response yet (null, undefined, empty string, or empty array)\n if (\n currentResponse === null ||\n currentResponse === undefined ||\n currentResponse === '' ||\n (Array.isArray(currentResponse) && currentResponse.length === 0)\n ) {\n return null;\n }\n\n // Normalize both to arrays for comparison\n const correctArr = Array.isArray(correctResponse) ? correctResponse : [correctResponse];\n const responseArr = Array.isArray(currentResponse) ? currentResponse : [currentResponse];\n\n // Filter out empty strings\n const filteredResponseArr = responseArr.filter(r => r !== '');\n if (filteredResponseArr.length === 0) return null;\n\n // Check for partial correctness - some correct selections but not all, or extra incorrect selections\n const correctCount = filteredResponseArr.filter(r => correctArr.includes(r)).length;\n const incorrectCount = filteredResponseArr.filter(r => !correctArr.includes(r)).length;\n\n // All responses are correct and we have all correct answers\n if (\n correctCount === correctArr.length &&\n incorrectCount === 0 &&\n filteredResponseArr.length === correctArr.length\n ) {\n return Correctness.Correct;\n }\n\n // Some correct responses but not complete or has incorrect responses\n if (correctCount > 0 && (correctCount < correctArr.length || incorrectCount > 0)) {\n return Correctness.PartiallyCorrect;\n }\n\n return Correctness.Incorrect;\n }\n\n get isInline(): boolean {\n return false;\n }\n\n get responseVariable(): ResponseVariable | undefined {\n // In standalone mode (no item context), return undefined\n if (!this._context?.variables) {\n return undefined;\n }\n\n // Get all response variables\n const responseVariables = this._context.variables.filter(v => v.type === 'response') as ResponseVariable[];\n\n // Get the response identifier for this interaction\n const responseIdentifier = this.getAttribute('response-identifier');\n\n // Return the matching response variable for this interaction\n return responseVariables.find(v => v.identifier === responseIdentifier);\n }\n\n public toggleCorrectResponse(show: boolean): void {\n const correctResponseMode = this?.configContext?.correctResponseMode || 'internal';\n\n if (correctResponseMode === 'full') {\n this.toggleFullCorrectResponse(show);\n } else {\n this.toggleInternalCorrectResponse(show);\n }\n }\n\n protected async toggleFullCorrectResponse(show: boolean): Promise<void> {\n const nextSibling = this.nextSibling;\n const nextSiblingIsFullCorrectResponse =\n nextSibling instanceof HTMLDivElement && nextSibling?.classList.contains('full-correct-response');\n\n // Get correct response from either responseVariable (item context) or local property (standalone)\n const correctResponse = this.correctResponse;\n\n if (!correctResponse) {\n return;\n }\n\n const showFullCorrectResponse =\n show &&\n (this?.configContext?.fullCorrectResponseOnlyWhenIncorrect === false || this.correctness !== Correctness.Correct);\n\n if (!showFullCorrectResponse) {\n if (!nextSiblingIsFullCorrectResponse) {\n return;\n }\n // Remove cloned interaction\n this.parentElement?.removeChild(nextSibling);\n return;\n }\n\n if (nextSiblingIsFullCorrectResponse) {\n return; // Already exists\n }\n\n // Add a clone of interaction with the correct response\n const clone = this.cloneNode(true) as Interaction;\n\n // Remove attributes that could cause issues on the clone\n clone.removeAttribute('show-full-correct-response');\n clone.removeAttribute('show-correct-response');\n clone.removeAttribute('show-candidate-correction');\n\n const containerDiv = document.createElement('div');\n containerDiv.classList.add('full-correct-response');\n if (this.isInline) {\n containerDiv.classList.add('full-correct-response-inline');\n } else {\n containerDiv.classList.add('full-correct-response-block');\n }\n containerDiv.role = 'full-correct-response';\n containerDiv.appendChild(clone);\n\n clone.isFullCorrectResponse = true;\n\n this.parentElement?.insertBefore(containerDiv, this.nextSibling);\n await clone.updateComplete;\n\n clone.response = Array.isArray(correctResponse) ? ([...correctResponse] as string[]) : (correctResponse as string);\n }\n\n protected toggleInternalCorrectResponse(show: boolean): void {\n // This method is meant to be overridden by mixins like ChoicesMixin\n // In the base class, we just update internal state for CSS states\n this._internals.states.delete('show-correct-response');\n if (show && this.correctResponse) {\n this._internals.states.add('show-correct-response');\n }\n }\n\n public toggleCandidateCorrection(show: boolean): void {\n this._internals.states.delete('candidate-correct');\n this._internals.states.delete('candidate-partially-correct');\n this._internals.states.delete('candidate-incorrect');\n\n if (!show) {\n return;\n }\n\n // correctness getter now works in both standalone and item context modes\n if (this.correctness === Correctness.Correct) {\n this._internals.states.add('candidate-correct');\n }\n if (this.correctness === Correctness.PartiallyCorrect) {\n this._internals.states.add('candidate-partially-correct');\n }\n if (this.correctness === Correctness.Incorrect) {\n this._internals.states.add('candidate-incorrect');\n }\n }\n\n constructor() {\n super();\n this._internals = this.attachInternals();\n }\n\n abstract validate(): boolean;\n\n get value(): string | null {\n return JSON.stringify(this.response);\n }\n\n set value(val: string | null) {\n this.response = val ? JSON.parse(val) : null;\n }\n\n abstract get response(): string | string[] | null;\n abstract set response(val: string | string[] | null);\n\n public reportValidity(): boolean {\n return this._internals.reportValidity();\n }\n\n public reset(): void {\n this.response = null;\n }\n\n /**\n * Called by the browser when the associated form is reset.\n * Part of the Form-Associated Custom Elements API.\n */\n public formResetCallback(): void {\n this.reset();\n }\n\n // attributeChangedCallback(name: string, _old: string | null, value: string | null): void {\n // super.attributeChangedCallback(name, _old, value);\n // // changing attributes in lit is not a thing, they are defined in the QTI XML and will never change\n // // except in storybook where we can change the value of the attribute\n // // this can make the internal state out of sync with the attribute\n // // so we reset the value to null to force the internal state to be reset\n // const attributeNamesToExclude = ['style', 'class'];\n // if (!attributeNamesToExclude.includes(name)) {\n // this.reset();\n // }\n // }\n\n public override connectedCallback(): void {\n super.connectedCallback();\n\n if (this.isFullCorrectResponse) {\n return;\n }\n\n this.dispatchEvent(\n new CustomEvent('qti-register-interaction', {\n bubbles: true,\n composed: true,\n cancelable: false,\n detail: {\n interactionElement: this,\n responseIdentifier: this.responseIdentifier\n }\n })\n );\n }\n\n protected override firstUpdated(): void {\n // Skip for full correct response clones to avoid infinite loops\n if (this.isFullCorrectResponse) {\n return;\n }\n\n // Apply initial correct response display states after first render\n if (this.showCorrectResponse) {\n this.toggleInternalCorrectResponse(true);\n }\n if (this.showFullCorrectResponse) {\n this.toggleFullCorrectResponse(true);\n }\n if (this.showCandidateCorrection) {\n this.toggleCandidateCorrection(true);\n }\n }\n\n public saveResponse(value: string | string[], state?: string | null): void {\n this.dispatchEvent(\n new CustomEvent('qti-interaction-response', {\n bubbles: true,\n composed: true,\n cancelable: false,\n detail: {\n responseIdentifier: this.responseIdentifier,\n response: Array.isArray(value) ? [...value] : value,\n ...(state !== undefined ? { state } : {})\n }\n })\n );\n }\n}\n"]}
1
+ {"version":3,"file":"interaction.js","sourceRoot":"","sources":["../../src/abstract/interaction.ts"],"names":[],"mappings":"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","sourcesContent":["import { consume, provide } from '@lit/context';\nimport { LitElement } from 'lit';\nimport { property } from 'lit/decorators.js';\n\nimport { configContext } from '../context/config.context';\nimport { interactionContext } from '../context/interaction.context';\nimport { itemContext } from '../context/item.context';\n\nimport type { PropertyValues } from 'lit';\nimport type { InteractionContext } from '../context/interaction.context';\nimport type { ConfigContext, ValidationDisplayMode } from '../context/config.context';\nimport type { ItemContext } from '../context/types/item.types';\nimport type { ValidatableInteraction } from '../lib/interaction.interface';\nimport type { ResponseVariable } from '../lib/variables';\n\n/**\n * Shared QTI interaction base. Formative correction behavior is supplied by the\n * `@qti-components/corrections` package.\n */\nexport abstract class Interaction extends LitElement implements ValidatableInteraction {\n @consume({ context: itemContext, subscribe: true })\n private _context: ItemContext;\n\n /**\n * Delivery configuration, from the nearest provider — `qti-test` or `qti-item`.\n *\n * **Public so it can be assigned directly, which is the development-time route.** An interaction\n * has to work standalone, and in a story or a spec there is usually no provider above it — so\n * setting the field is all that is needed:\n *\n * orderInteraction.configContext = { allowReorder: false, validationDisplayMode: 'none' };\n *\n * With no provider, nothing ever overwrites it. That is the whole contract, and its limit: where a\n * provider DOES exist it re-emits on its next update and wins, because `@consume` writes this same\n * field. There is no merging — set the value on the provider in that case.\n *\n * In a lit-html template, bind it as a property rather than assigning after the fact:\n *\n * html`<qti-order-interaction .configContext=${{ allowReorder: false }}>…`\n *\n * The binding is committed on the detached template clone, before the fragment is inserted, so it\n * is in place by `connectedCallback` — which matters for anything that reads config on connect.\n *\n * It was `protected`, which fooled nobody: every caller reached it anyway through an\n * `as any` / `as { configContext?: … }` cast. Public says what was already true and removes the\n * casts, rather than pretending at an encapsulation the type system was the only thing enforcing.\n */\n @consume({ context: configContext, subscribe: true })\n public configContext: ConfigContext;\n\n #didLogDisableAfterIfMaxChoicesReachedDeprecation = false;\n\n /*\n * Published to the choice elements inside this interaction — their role, and how to tell\n * whether they are draggable. Provided here on the base rather than in a mixin so that\n * ChoicesMixin and the drag-drop mixins can each contribute without two providers of the same\n * context competing on one element.\n *\n * Reassign, never mutate: an in-place change does not notify consumers.\n */\n @provide({ context: interactionContext })\n protected _interactionContext: Readonly<InteractionContext> = { choiceRole: null, draggablesSelector: null };\n\n static formAssociated = true;\n protected _internals: ElementInternals;\n\n get internals(): ElementInternals {\n return this._internals;\n }\n\n @property({ type: String, attribute: 'response-identifier' }) responseIdentifier: string;\n\n @property({ reflect: true, type: Boolean }) disabled = false;\n\n @property({ reflect: true, type: Boolean }) readonly = false;\n\n @property({ type: String }) name;\n\n /** Extension point used by wrappers that should not register as candidate inputs. */\n protected get registersWithItem(): boolean {\n return true;\n }\n\n get isInline(): boolean {\n return false;\n }\n\n get responseVariable(): ResponseVariable | undefined {\n if (!this._context?.variables) {\n return undefined;\n }\n const responseVariables = this._context.variables.filter(v => v.type === 'response') as ResponseVariable[];\n const responseIdentifier = this.getAttribute('response-identifier');\n return responseVariables.find(v => v.identifier === responseIdentifier);\n }\n\n abstract validate(): boolean;\n\n get value(): string | null {\n return JSON.stringify(this.response);\n }\n\n set value(val: string | null) {\n this.response = val ? JSON.parse(val) : null;\n }\n\n abstract get response(): string | string[] | null;\n abstract set response(val: string | string[] | null);\n\n public reportValidity(): boolean {\n const isValid = this._internals.validity.valid;\n const mode = this.validationDisplayMode;\n\n if (mode === 'native' || mode === 'both') {\n this._internals.reportValidity();\n }\n\n if (mode === 'inline' || mode === 'both') {\n this.updateInlineValidationMessage();\n } else {\n this.clearInlineValidationMessage();\n }\n\n if (mode === 'none') {\n this.clearInlineValidationMessage();\n }\n\n return isValid;\n }\n\n protected get validationDisplayMode(): ValidationDisplayMode {\n return this.configContext?.validationDisplayMode ?? 'inline';\n }\n\n protected resolveAllowReorder(options?: { defaultWhenUnset?: boolean }): boolean {\n const defaultWhenUnset = options?.defaultWhenUnset ?? true;\n const config = this.configContext;\n if (!config) {\n return defaultWhenUnset;\n }\n if (config.allowReorder !== undefined) {\n return config.allowReorder;\n }\n return defaultWhenUnset;\n }\n\n protected resolveDisableAfterMaxReached(options?: { defaultWhenUnset?: boolean }): boolean {\n const defaultWhenUnset = options?.defaultWhenUnset ?? false;\n const config = this.configContext;\n\n if (!config) {\n return defaultWhenUnset;\n }\n\n if (config.disableAfterMaxReached !== undefined) {\n return config.disableAfterMaxReached;\n }\n\n if (config.disableAfterIfMaxChoicesReached !== undefined) {\n if (!this.#didLogDisableAfterIfMaxChoicesReachedDeprecation) {\n this.#didLogDisableAfterIfMaxChoicesReachedDeprecation = true;\n console.log(\n '[QTI Config] `disableAfterIfMaxChoicesReached` is deprecated. Use `disableAfterMaxReached` instead.'\n );\n }\n return config.disableAfterIfMaxChoicesReached;\n }\n\n return defaultWhenUnset;\n }\n\n protected setInteractionValidity(\n isValid: boolean,\n validityMessage = '',\n anchor?: HTMLElement | null,\n options?: { suppressInline?: boolean }\n ): void {\n const validityAnchor = anchor ?? this;\n this._internals.setValidity(isValid ? {} : { customError: true }, validityMessage, validityAnchor);\n\n if (\n options?.suppressInline !== true &&\n (this.validationDisplayMode === 'inline' || this.validationDisplayMode === 'both')\n ) {\n this.updateInlineValidationMessage();\n }\n }\n\n protected updateInlineValidationMessage(): void {\n const validationMessageElement = this.getValidationMessageElement();\n if (!validationMessageElement) {\n return;\n }\n\n if (!this._internals.validity.valid) {\n validationMessageElement.textContent = this._internals.validationMessage;\n validationMessageElement.style.setProperty('display', 'block', 'important');\n return;\n }\n\n validationMessageElement.textContent = '';\n validationMessageElement.style.display = 'none';\n }\n\n protected clearInlineValidationMessage(): void {\n const validationMessageElement = this.getValidationMessageElement();\n if (!validationMessageElement) {\n return;\n }\n\n validationMessageElement.textContent = '';\n validationMessageElement.style.display = 'none';\n }\n\n protected getValidationMessageElement(): HTMLElement | null {\n return this.shadowRoot?.querySelector('#validation-message') as HTMLElement | null;\n }\n\n public reset(): void {\n this.response = null;\n }\n\n public formResetCallback(): void {\n this.reset();\n }\n\n public override connectedCallback(): void {\n super.connectedCallback();\n\n if (!this.registersWithItem) {\n return;\n }\n\n this.dispatchEvent(\n new CustomEvent('qti-register-interaction', {\n bubbles: true,\n composed: true,\n cancelable: false,\n detail: {\n interactionElement: this,\n responseIdentifier: this.responseIdentifier\n }\n })\n );\n }\n\n public saveResponse(value: string | string[], state?: string | null): void {\n this.dispatchEvent(\n new CustomEvent('qti-interaction-response', {\n bubbles: true,\n composed: true,\n cancelable: false,\n detail: {\n responseIdentifier: this.responseIdentifier,\n response: Array.isArray(value) ? [...value] : value,\n ...(state !== undefined ? { state } : {})\n }\n })\n );\n }\n\n constructor() {\n super();\n this._internals = this.attachInternals();\n }\n\n /** Optional lifecycle bridge for interaction subclasses that do not need changed-property data. */\n protected override firstUpdated(_changedProperties?: PropertyValues<this>): void {}\n}\n"]}
@@ -1,7 +1,7 @@
1
1
  import { LitElement } from 'lit';
2
+ import type { ItemContext } from '../context/types/item.types';
2
3
  import type { QtiContext, QtiContextType } from '../context/qti.context';
3
4
  import type { ResponseVariable, VariableDeclaration } from '../lib/variables';
4
- import type { ItemContext } from '../context/item.context';
5
5
  export interface QtiExpressionBase<T> {
6
6
  calculate(): Readonly<T>;
7
7
  }
@@ -7,7 +7,7 @@ var __decorate = (this && this.__decorate) || function (decorators, target, key,
7
7
  import { consume } from '@lit/context';
8
8
  import { css, html, LitElement } from 'lit';
9
9
  import { state } from 'lit/decorators.js';
10
- import { itemContext } from '../context/qti-assessment-item.context';
10
+ import { itemContext } from '../context/item.context';
11
11
  import { qtiContext } from '../context/qti.context';
12
12
  export class QtiExpression extends LitElement {
13
13
  constructor() {
@@ -118,7 +118,28 @@ export class QtiExpression extends LitElement {
118
118
  .flatMap(v => (Array.isArray(v) ? v : [v]))
119
119
  .filter(v => v !== null);
120
120
  }
121
- // hide the slot with css
121
+ /*
122
+ * Written here rather than imported from a .css file, and that is a packaging constraint rather
123
+ * than a style preference.
124
+ *
125
+ * The rule used to live in qti-expression.css, imported with Vite's inline-stylesheet query so
126
+ * DevTools could show source-file provenance. That query is a VITE specifier, and tsc copies it
127
+ * verbatim into dist — so the published package shipped an import only a Vite-based consumer
128
+ * could resolve. Every other consumer broke on it: plain Node, tsx, any non-Vite bundler. It was
129
+ * the single such specifier reachable from this package, and it took down QTI-Editor's schema
130
+ * check, which loads the components under tsx to build the real ProseMirror schema
131
+ * (ERR_UNKNOWN_FILE_EXTENSION on a file that has nothing to do with schemas).
132
+ *
133
+ * A `build:assets` step used to copy the .css into dist beside it. That went too — it existed
134
+ * only to give the unresolvable import something to point at.
135
+ *
136
+ * Two lines of CSS are not worth a dist that only one bundler can consume. If this ever grows
137
+ * into a real stylesheet, give it a `.styles.ts` exporting a `css` template — the house pattern
138
+ * everywhere else in this repo — rather than reintroducing a bundler-specific import.
139
+ *
140
+ * The element renders a debug <pre> of its computed result plus a <slot>; hiding the slot is all
141
+ * the styling it has ever had.
142
+ */
122
143
  static { this.styles = css `
123
144
  slot {
124
145
  display: none;
@@ -1 +1 @@
1
- {"version":3,"file":"qti-expression.js","sourceRoot":"","sources":["../../src/abstract/qti-expression.ts"],"names":[],"mappings":"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","sourcesContent":["import { consume } from '@lit/context';\nimport { css, html, LitElement } from 'lit';\nimport { state } from 'lit/decorators.js';\n\nimport { itemContext } from '../context/qti-assessment-item.context';\nimport { qtiContext } from '../context/qti.context';\n\nimport type { QtiContext, QtiContextType } from '../context/qti.context';\nimport type { ResponseVariable, VariableDeclaration } from '../lib/variables';\nimport type { ItemContext } from '../context/item.context';\n\nexport interface QtiExpressionBase<T> {\n // get assessmentItem(): QtiAssessmentItem;\n\n // getVariables(): VariableDeclaration<number | string | (number | string)[] | null>[];\n calculate(): Readonly<T>;\n}\n\nexport abstract class QtiExpression<T> extends LitElement implements QtiExpressionBase<T> {\n @state()\n protected result: any;\n\n // hide the slot with css\n static override styles = css`\n slot {\n display: none;\n }\n `;\n\n override render() {\n return html`<pre>${JSON.stringify(this.result, null, 2)}</pre>\n <slot></slot>`;\n }\n\n public calculate(): Readonly<T> {\n this.result = this.getResult();\n return this.result;\n }\n\n protected getResult(): Readonly<T> {\n throw new Error('Not implemented');\n }\n\n @consume({ context: itemContext, subscribe: true })\n @state()\n protected context?: ItemContext;\n\n @consume({ context: qtiContext, subscribe: true })\n @state()\n protected qtiContext?: QtiContext;\n\n getVariables = (): (ResponseVariable | VariableDeclaration<QtiContextType>)[] =>\n // FIXME: if this itself is multiple, this will never enter the qti-multiple switch\n // See this example here: https://github.com/1EdTech/qti-examples/blob/master/qtiv3-examples/packaging/items/Example05-feedbackBlock-adaptive.xml\n\n Array.from(this.children)\n .map((e: Element) => {\n console.debug('getVariables', e.tagName.toLowerCase());\n switch (e.tagName.toLowerCase()) {\n case 'qti-base-value': {\n return {\n baseType: e.getAttribute('base-type'),\n value: e.textContent.trim(),\n cardinality: 'single'\n } as ResponseVariable;\n }\n case 'qti-variable': {\n const identifier = e.getAttribute('identifier') || '';\n\n // Special handling for QTI_CONTEXT\n if (identifier === 'QTI_CONTEXT') {\n if (!this.qtiContext?.QTI_CONTEXT) {\n console.warn('QTI_CONTEXT not available');\n return {\n identifier: 'QTI_CONTEXT',\n baseType: 'record',\n value: this.qtiContext.QTI_CONTEXT,\n cardinality: 'record',\n type: 'context'\n } as VariableDeclaration<QtiContextType>;\n }\n return {\n identifier: 'QTI_CONTEXT',\n baseType: 'record',\n value: this.qtiContext.QTI_CONTEXT,\n cardinality: 'record',\n type: 'context'\n } as VariableDeclaration<QtiContextType>;\n }\n\n const variable = this.context.variables.find(v => v.identifier === identifier) || null;\n return variable;\n }\n case 'qti-multiple': {\n const multiple = e as QtiExpression<ResponseVariable[]>;\n\n const values = multiple.getResult();\n console.debug('values', values);\n if (values?.length > 0) {\n return {\n identifier: '',\n baseType: values[0].baseType,\n value: values.map(v => v.value),\n cardinality: 'multiple',\n type: 'response'\n } as ResponseVariable;\n }\n return null;\n }\n case 'qti-ordered': {\n const multiple = e as QtiExpression<ResponseVariable[]>;\n const values = multiple.getResult();\n if (values?.length > 0) {\n return {\n identifier: '',\n baseType: values[0].baseType,\n value: values.map(v => v.value),\n cardinality: 'ordered',\n type: 'response'\n } as ResponseVariable;\n }\n return null;\n }\n case 'qti-repeat': {\n const repeat = e as QtiExpression<ResponseVariable[]>;\n const values = repeat.getResult();\n if (values?.length > 0) {\n return values;\n }\n return null;\n }\n case 'qti-correct': {\n const identifier = e.getAttribute('identifier') || '';\n const responseVariable: ResponseVariable =\n this.context?.variables?.find(v => v.identifier === identifier) || null;\n return {\n baseType: responseVariable.baseType,\n value: responseVariable.correctResponse,\n cardinality: responseVariable.cardinality\n } as ResponseVariable;\n }\n default: {\n // added for use of qti-equal-rounded\n try {\n const expression = e as QtiExpression<number>;\n const value = expression.getResult();\n return {\n baseType: 'integer',\n value: value?.toString() || null,\n cardinality: 'single'\n } as ResponseVariable;\n } catch (error) {\n console.warn('default not sufficient');\n }\n return null;\n }\n }\n })\n .flatMap(v => (Array.isArray(v) ? v : [v]))\n .filter(v => v !== null);\n}\n"]}
1
+ {"version":3,"file":"qti-expression.js","sourceRoot":"","sources":["../../src/abstract/qti-expression.ts"],"names":[],"mappings":"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","sourcesContent":["import { consume } from '@lit/context';\nimport { css, html, LitElement } from 'lit';\nimport { state } from 'lit/decorators.js';\n\nimport { itemContext } from '../context/item.context';\nimport { qtiContext } from '../context/qti.context';\n\nimport type { ItemContext } from '../context/types/item.types';\nimport type { QtiContext, QtiContextType } from '../context/qti.context';\nimport type { ResponseVariable, VariableDeclaration } from '../lib/variables';\n\nexport interface QtiExpressionBase<T> {\n // get assessmentItem(): QtiAssessmentItem;\n\n // getVariables(): VariableDeclaration<number | string | (number | string)[] | null>[];\n calculate(): Readonly<T>;\n}\n\nexport abstract class QtiExpression<T> extends LitElement implements QtiExpressionBase<T> {\n @state()\n protected result: any;\n\n /*\n * Written here rather than imported from a .css file, and that is a packaging constraint rather\n * than a style preference.\n *\n * The rule used to live in qti-expression.css, imported with Vite's inline-stylesheet query so\n * DevTools could show source-file provenance. That query is a VITE specifier, and tsc copies it\n * verbatim into dist — so the published package shipped an import only a Vite-based consumer\n * could resolve. Every other consumer broke on it: plain Node, tsx, any non-Vite bundler. It was\n * the single such specifier reachable from this package, and it took down QTI-Editor's schema\n * check, which loads the components under tsx to build the real ProseMirror schema\n * (ERR_UNKNOWN_FILE_EXTENSION on a file that has nothing to do with schemas).\n *\n * A `build:assets` step used to copy the .css into dist beside it. That went too — it existed\n * only to give the unresolvable import something to point at.\n *\n * Two lines of CSS are not worth a dist that only one bundler can consume. If this ever grows\n * into a real stylesheet, give it a `.styles.ts` exporting a `css` template — the house pattern\n * everywhere else in this repo — rather than reintroducing a bundler-specific import.\n *\n * The element renders a debug <pre> of its computed result plus a <slot>; hiding the slot is all\n * the styling it has ever had.\n */\n static override styles = css`\n slot {\n display: none;\n }\n `;\n\n override render() {\n return html`<pre>${JSON.stringify(this.result, null, 2)}</pre>\n <slot></slot>`;\n }\n\n public calculate(): Readonly<T> {\n this.result = this.getResult();\n return this.result;\n }\n\n protected getResult(): Readonly<T> {\n throw new Error('Not implemented');\n }\n\n @consume({ context: itemContext, subscribe: true })\n @state()\n protected context?: ItemContext;\n\n @consume({ context: qtiContext, subscribe: true })\n @state()\n protected qtiContext?: QtiContext;\n\n getVariables = (): (ResponseVariable | VariableDeclaration<QtiContextType>)[] =>\n // FIXME: if this itself is multiple, this will never enter the qti-multiple switch\n // See this example here: https://github.com/1EdTech/qti-examples/blob/master/qtiv3-examples/packaging/items/Example05-feedbackBlock-adaptive.xml\n\n Array.from(this.children)\n .map((e: Element) => {\n console.debug('getVariables', e.tagName.toLowerCase());\n switch (e.tagName.toLowerCase()) {\n case 'qti-base-value': {\n return {\n baseType: e.getAttribute('base-type'),\n value: e.textContent.trim(),\n cardinality: 'single'\n } as ResponseVariable;\n }\n case 'qti-variable': {\n const identifier = e.getAttribute('identifier') || '';\n\n // Special handling for QTI_CONTEXT\n if (identifier === 'QTI_CONTEXT') {\n if (!this.qtiContext?.QTI_CONTEXT) {\n console.warn('QTI_CONTEXT not available');\n return {\n identifier: 'QTI_CONTEXT',\n baseType: 'record',\n value: this.qtiContext.QTI_CONTEXT,\n cardinality: 'record',\n type: 'context'\n } as VariableDeclaration<QtiContextType>;\n }\n return {\n identifier: 'QTI_CONTEXT',\n baseType: 'record',\n value: this.qtiContext.QTI_CONTEXT,\n cardinality: 'record',\n type: 'context'\n } as VariableDeclaration<QtiContextType>;\n }\n\n const variable = this.context.variables.find(v => v.identifier === identifier) || null;\n return variable;\n }\n case 'qti-multiple': {\n const multiple = e as QtiExpression<ResponseVariable[]>;\n\n const values = multiple.getResult();\n console.debug('values', values);\n if (values?.length > 0) {\n return {\n identifier: '',\n baseType: values[0].baseType,\n value: values.map(v => v.value),\n cardinality: 'multiple',\n type: 'response'\n } as ResponseVariable;\n }\n return null;\n }\n case 'qti-ordered': {\n const multiple = e as QtiExpression<ResponseVariable[]>;\n const values = multiple.getResult();\n if (values?.length > 0) {\n return {\n identifier: '',\n baseType: values[0].baseType,\n value: values.map(v => v.value),\n cardinality: 'ordered',\n type: 'response'\n } as ResponseVariable;\n }\n return null;\n }\n case 'qti-repeat': {\n const repeat = e as QtiExpression<ResponseVariable[]>;\n const values = repeat.getResult();\n if (values?.length > 0) {\n return values;\n }\n return null;\n }\n case 'qti-correct': {\n const identifier = e.getAttribute('identifier') || '';\n const responseVariable: ResponseVariable =\n this.context?.variables?.find(v => v.identifier === identifier) || null;\n return {\n baseType: responseVariable.baseType,\n value: responseVariable.correctResponse,\n cardinality: responseVariable.cardinality\n } as ResponseVariable;\n }\n default: {\n // added for use of qti-equal-rounded\n try {\n const expression = e as QtiExpression<number>;\n const value = expression.getResult();\n return {\n baseType: 'integer',\n value: value?.toString() || null,\n cardinality: 'single'\n } as ResponseVariable;\n } catch (error) {\n console.warn('default not sufficient');\n }\n return null;\n }\n }\n })\n .flatMap(v => (Array.isArray(v) ? v : [v]))\n .filter(v => v !== null);\n}\n"]}
@@ -7,7 +7,7 @@ var __decorate = (this && this.__decorate) || function (decorators, target, key,
7
7
  import { consume } from '@lit/context';
8
8
  import { LitElement } from 'lit';
9
9
  import { property, state } from 'lit/decorators.js';
10
- import { itemContext } from '../context/qti-assessment-item.context';
10
+ import { itemContext } from '../context/item.context';
11
11
  import { IsNullOrUndefined } from '../utils/utils';
12
12
  export class QtiFeedback extends LitElement {
13
13
  constructor() {
@@ -1 +1 @@
1
- {"version":3,"file":"qti-feedback.js","sourceRoot":"","sources":["../../src/abstract/qti-feedback.ts"],"names":[],"mappings":";;;;;;AAAA,OAAO,EAAE,OAAO,EAAE,MAAM,cAAc,CAAC;AACvC,OAAO,EAAE,UAAU,EAAE,MAAM,KAAK,CAAC;AACjC,OAAO,EAAE,QAAQ,EAAE,KAAK,EAAE,MAAM,mBAAmB,CAAC;AAEpD,OAAO,EAAE,WAAW,EAAE,MAAM,wCAAwC,CAAC;AACrE,OAAO,EAAE,iBAAiB,EAAE,MAAM,gBAAgB,CAAC;AAInD,MAAM,OAAgB,WAAY,SAAQ,UAAU;IAApD;;QAEY,aAAQ,GAAoB,MAAM,CAAC;IA8C/C,CAAC;IA/BiB,iBAAiB;QAC/B,KAAK,CAAC,iBAAiB,EAAE,CAAC;QAC1B,IAAI,CAAC,aAAa,CAChB,IAAI,WAAW,CAAc,uBAAuB,EAAE;YACpD,OAAO,EAAE,IAAI;YACb,QAAQ,EAAE,IAAI;YACd,MAAM,EAAE,IAAI;SACb,CAAC,CACH,CAAC;IACJ,CAAC;IAEM,iBAAiB,CAAC,iBAAyB;QAChD,MAAM,eAAe,GAAG,IAAI,CAAC,QAAQ,CAAC,SAAS,CAAC,IAAI,CAAC,CAAC,CAAC,EAAE,CAAC,CAAC,CAAC,UAAU,KAAK,iBAAiB,CAAC,IAAI,IAAI,CAAC;QACtG,IAAI,IAAI,CAAC,iBAAiB,KAAK,iBAAiB,IAAI,CAAC,eAAe;YAAE,OAAO;QAC7E,IAAI,OAAO,GAAG,KAAK,CAAC;QACpB,IAAI,KAAK,CAAC,OAAO,CAAC,eAAe,CAAC,KAAK,CAAC,EAAE,CAAC;YACzC,OAAO,GAAG,eAAe,CAAC,KAAK,CAAC,QAAQ,CAAC,IAAI,CAAC,UAAU,CAAC,CAAC;QAC5D,CAAC;aAAM,CAAC;YACN,OAAO;gBACL,CAAC,CAAC,iBAAiB,CAAC,IAAI,CAAC,UAAU,CAAC;oBAClC,CAAC,iBAAiB,CAAC,eAAe,EAAE,KAAK,CAAC;oBAC1C,IAAI,CAAC,UAAU,KAAK,eAAe,CAAC,KAAK,CAAC;oBAC5C,KAAK,CAAC;QACV,CAAC;QAED,IAAI,CAAC,aAAa,CAAC,OAAO,CAAC,CAAC;IAC9B,CAAC;IAED,aAAa,CAAC,KAAc;QAC1B,IAAI,CAAC,UAAU,GAAG,CAAC,KAAK,IAAI,IAAI,CAAC,QAAQ,KAAK,MAAM,CAAC,IAAI,CAAC,CAAC,KAAK,IAAI,IAAI,CAAC,QAAQ,KAAK,MAAM,CAAC,CAAC,CAAC,CAAC,IAAI,CAAC,CAAC,CAAC,KAAK,CAAC;IAC/G,CAAC;CACF;AA9CW;IADT,QAAQ,CAAC,EAAE,IAAI,EAAE,MAAM,EAAE,SAAS,EAAE,WAAW,EAAE,CAAC;6CACN;AAGtC;IADN,QAAQ,CAAC,EAAE,IAAI,EAAE,MAAM,EAAE,SAAS,EAAE,oBAAoB,EAAE,CAAC;sDAC3B;AAGvB;IADT,QAAQ,CAAC,EAAE,IAAI,EAAE,MAAM,EAAE,CAAC;+CACE;AAGtB;IADN,QAAQ,CAAC,EAAE,IAAI,EAAE,MAAM,EAAE,SAAS,EAAE,KAAK,EAAE,CAAC;+CACnB;AAIlB;IAFP,OAAO,CAAC,EAAE,OAAO,EAAE,WAAW,EAAE,SAAS,EAAE,IAAI,EAAE,CAAC;IAClD,KAAK,EAAE;6CACuB","sourcesContent":["import { consume } from '@lit/context';\nimport { LitElement } from 'lit';\nimport { property, state } from 'lit/decorators.js';\n\nimport { itemContext } from '../context/qti-assessment-item.context';\nimport { IsNullOrUndefined } from '../utils/utils';\n\nimport type { ItemContext } from '../context/item.context';\n\nexport abstract class QtiFeedback extends LitElement {\n @property({ type: String, attribute: 'show-hide' })\n protected showHide: 'show' | 'hide' = 'show';\n\n @property({ type: String, attribute: 'outcome-identifier' })\n public outcomeIdentifier: string;\n\n @property({ type: String })\n protected identifier: string;\n\n @property({ type: String, attribute: false })\n public showStatus: string;\n\n @consume({ context: itemContext, subscribe: true })\n @state()\n private _context?: ItemContext;\n\n public override connectedCallback() {\n super.connectedCallback();\n this.dispatchEvent(\n new CustomEvent<QtiFeedback>('qti-register-feedback', {\n bubbles: true,\n composed: true,\n detail: this\n })\n );\n }\n\n public checkShowFeedback(outcomeIdentifier: string) {\n const outcomeVariable = this._context.variables.find(v => v.identifier === outcomeIdentifier) || null;\n if (this.outcomeIdentifier !== outcomeIdentifier || !outcomeVariable) return;\n let isFound = false;\n if (Array.isArray(outcomeVariable.value)) {\n isFound = outcomeVariable.value.includes(this.identifier);\n } else {\n isFound =\n (!IsNullOrUndefined(this.identifier) &&\n !IsNullOrUndefined(outcomeVariable?.value) &&\n this.identifier === outcomeVariable.value) ||\n false;\n }\n\n this.#showFeedback(isFound);\n }\n\n #showFeedback(value: boolean) {\n this.showStatus = (value && this.showHide === 'show') || (!value && this.showHide === 'hide') ? 'on' : 'off';\n }\n}\n"]}
1
+ {"version":3,"file":"qti-feedback.js","sourceRoot":"","sources":["../../src/abstract/qti-feedback.ts"],"names":[],"mappings":";;;;;;AAAA,OAAO,EAAE,OAAO,EAAE,MAAM,cAAc,CAAC;AACvC,OAAO,EAAE,UAAU,EAAE,MAAM,KAAK,CAAC;AACjC,OAAO,EAAE,QAAQ,EAAE,KAAK,EAAE,MAAM,mBAAmB,CAAC;AAEpD,OAAO,EAAE,WAAW,EAAE,MAAM,yBAAyB,CAAC;AACtD,OAAO,EAAE,iBAAiB,EAAE,MAAM,gBAAgB,CAAC;AAInD,MAAM,OAAgB,WAAY,SAAQ,UAAU;IAApD;;QAEY,aAAQ,GAAoB,MAAM,CAAC;IA8C/C,CAAC;IA/BiB,iBAAiB;QAC/B,KAAK,CAAC,iBAAiB,EAAE,CAAC;QAC1B,IAAI,CAAC,aAAa,CAChB,IAAI,WAAW,CAAc,uBAAuB,EAAE;YACpD,OAAO,EAAE,IAAI;YACb,QAAQ,EAAE,IAAI;YACd,MAAM,EAAE,IAAI;SACb,CAAC,CACH,CAAC;IACJ,CAAC;IAEM,iBAAiB,CAAC,iBAAyB;QAChD,MAAM,eAAe,GAAG,IAAI,CAAC,QAAQ,CAAC,SAAS,CAAC,IAAI,CAAC,CAAC,CAAC,EAAE,CAAC,CAAC,CAAC,UAAU,KAAK,iBAAiB,CAAC,IAAI,IAAI,CAAC;QACtG,IAAI,IAAI,CAAC,iBAAiB,KAAK,iBAAiB,IAAI,CAAC,eAAe;YAAE,OAAO;QAC7E,IAAI,OAAO,GAAG,KAAK,CAAC;QACpB,IAAI,KAAK,CAAC,OAAO,CAAC,eAAe,CAAC,KAAK,CAAC,EAAE,CAAC;YACzC,OAAO,GAAG,eAAe,CAAC,KAAK,CAAC,QAAQ,CAAC,IAAI,CAAC,UAAU,CAAC,CAAC;QAC5D,CAAC;aAAM,CAAC;YACN,OAAO;gBACL,CAAC,CAAC,iBAAiB,CAAC,IAAI,CAAC,UAAU,CAAC;oBAClC,CAAC,iBAAiB,CAAC,eAAe,EAAE,KAAK,CAAC;oBAC1C,IAAI,CAAC,UAAU,KAAK,eAAe,CAAC,KAAK,CAAC;oBAC5C,KAAK,CAAC;QACV,CAAC;QAED,IAAI,CAAC,aAAa,CAAC,OAAO,CAAC,CAAC;IAC9B,CAAC;IAED,aAAa,CAAC,KAAc;QAC1B,IAAI,CAAC,UAAU,GAAG,CAAC,KAAK,IAAI,IAAI,CAAC,QAAQ,KAAK,MAAM,CAAC,IAAI,CAAC,CAAC,KAAK,IAAI,IAAI,CAAC,QAAQ,KAAK,MAAM,CAAC,CAAC,CAAC,CAAC,IAAI,CAAC,CAAC,CAAC,KAAK,CAAC;IAC/G,CAAC;CACF;AA9CW;IADT,QAAQ,CAAC,EAAE,IAAI,EAAE,MAAM,EAAE,SAAS,EAAE,WAAW,EAAE,CAAC;6CACN;AAGtC;IADN,QAAQ,CAAC,EAAE,IAAI,EAAE,MAAM,EAAE,SAAS,EAAE,oBAAoB,EAAE,CAAC;sDAC3B;AAGvB;IADT,QAAQ,CAAC,EAAE,IAAI,EAAE,MAAM,EAAE,CAAC;+CACE;AAGtB;IADN,QAAQ,CAAC,EAAE,IAAI,EAAE,MAAM,EAAE,SAAS,EAAE,KAAK,EAAE,CAAC;+CACnB;AAIlB;IAFP,OAAO,CAAC,EAAE,OAAO,EAAE,WAAW,EAAE,SAAS,EAAE,IAAI,EAAE,CAAC;IAClD,KAAK,EAAE;6CACuB","sourcesContent":["import { consume } from '@lit/context';\nimport { LitElement } from 'lit';\nimport { property, state } from 'lit/decorators.js';\n\nimport { itemContext } from '../context/item.context';\nimport { IsNullOrUndefined } from '../utils/utils';\n\nimport type { ItemContext } from '../context/types/item.types';\n\nexport abstract class QtiFeedback extends LitElement {\n @property({ type: String, attribute: 'show-hide' })\n protected showHide: 'show' | 'hide' = 'show';\n\n @property({ type: String, attribute: 'outcome-identifier' })\n public outcomeIdentifier: string;\n\n @property({ type: String })\n protected identifier: string;\n\n @property({ type: String, attribute: false })\n public showStatus: string;\n\n @consume({ context: itemContext, subscribe: true })\n @state()\n private _context?: ItemContext;\n\n public override connectedCallback() {\n super.connectedCallback();\n this.dispatchEvent(\n new CustomEvent<QtiFeedback>('qti-register-feedback', {\n bubbles: true,\n composed: true,\n detail: this\n })\n );\n }\n\n public checkShowFeedback(outcomeIdentifier: string) {\n const outcomeVariable = this._context.variables.find(v => v.identifier === outcomeIdentifier) || null;\n if (this.outcomeIdentifier !== outcomeIdentifier || !outcomeVariable) return;\n let isFound = false;\n if (Array.isArray(outcomeVariable.value)) {\n isFound = outcomeVariable.value.includes(this.identifier);\n } else {\n isFound =\n (!IsNullOrUndefined(this.identifier) &&\n !IsNullOrUndefined(outcomeVariable?.value) &&\n this.identifier === outcomeVariable.value) ||\n false;\n }\n\n this.#showFeedback(isFound);\n }\n\n #showFeedback(value: boolean) {\n this.showStatus = (value && this.showHide === 'show') || (!value && this.showHide === 'hide') ? 'on' : 'off';\n }\n}\n"]}
@@ -1,19 +1,4 @@
1
- import type { VariableDeclaration } from '../lib/variables';
2
- export type ComputedItemContext = {
3
- identifier: string;
4
- href?: string;
5
- correct?: boolean;
6
- incorrect?: boolean;
7
- completed?: boolean;
8
- adaptive?: boolean;
9
- timeDependent?: boolean;
10
- title?: string;
11
- label?: string;
12
- score?: number;
13
- maxScore?: number;
14
- completionStatus?: string;
15
- variables: ReadonlyArray<VariableDeclaration<string | string[] | null>>;
16
- };
1
+ import type { ComputedItemContext } from './types/computed-item.types';
17
2
  export declare const computedItemContext: {
18
3
  __context__: Readonly<ComputedItemContext>;
19
4
  };
@@ -1 +1 @@
1
- {"version":3,"file":"computed-item.context.js","sourceRoot":"","sources":["../../src/context/computed-item.context.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,aAAa,EAAE,MAAM,cAAc,CAAC;AAoB7C,MAAM,CAAC,MAAM,mBAAmB,GAAG,aAAa,CAAgC,MAAM,CAAC,qBAAqB,CAAC,CAAC,CAAC","sourcesContent":["import { createContext } from '@lit/context';\n\nimport type { VariableDeclaration } from '../lib/variables';\n\nexport type ComputedItemContext = {\n identifier: string;\n href?: string;\n correct?: boolean;\n incorrect?: boolean;\n completed?: boolean;\n adaptive?: boolean;\n timeDependent?: boolean;\n title?: string;\n label?: string;\n score?: number;\n maxScore?: number;\n completionStatus?: string;\n variables: ReadonlyArray<VariableDeclaration<string | string[] | null>>;\n};\n\nexport const computedItemContext = createContext<Readonly<ComputedItemContext>>(Symbol('computedItemContext'));\n"]}
1
+ {"version":3,"file":"computed-item.context.js","sourceRoot":"","sources":["../../src/context/computed-item.context.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,aAAa,EAAE,MAAM,cAAc,CAAC;AAI7C,MAAM,CAAC,MAAM,mBAAmB,GAAG,aAAa,CAAgC,MAAM,CAAC,qBAAqB,CAAC,CAAC,CAAC","sourcesContent":["import { createContext } from '@lit/context';\n\nimport type { ComputedItemContext } from './types/computed-item.types';\n\nexport const computedItemContext = createContext<Readonly<ComputedItemContext>>(Symbol('computedItemContext'));\n"]}
@@ -1,29 +1,4 @@
1
- import type { View } from './session.context';
2
- import type { ComputedItemContext } from './computed-item.context';
3
- export type ComputedItem = ComputedItemContext & {
4
- categories?: string[];
5
- type?: 'info' | 'regular';
6
- index?: number;
7
- active?: boolean;
8
- };
9
- export type ComputedContext = {
10
- view: View;
11
- identifier: string;
12
- title: string;
13
- testParts: {
14
- active?: boolean;
15
- identifier: string;
16
- navigationMode: 'linear' | 'nonlinear';
17
- submissionMode: 'individual' | 'simultaneous';
18
- sections: {
19
- active?: boolean;
20
- identifier: string;
21
- title: string;
22
- completed?: boolean;
23
- items: ComputedItem[];
24
- }[];
25
- }[];
26
- };
1
+ import type { ComputedContext } from './types/computed.types';
27
2
  export declare const computedContext: {
28
3
  __context__: Readonly<ComputedContext>;
29
4
  };
@@ -1 +1 @@
1
- {"version":3,"file":"computed.context.js","sourceRoot":"","sources":["../../src/context/computed.context.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,aAAa,EAAE,MAAM,cAAc,CAAC;AA+B7C,MAAM,CAAC,MAAM,eAAe,GAAG,aAAa,CAA4B,MAAM,CAAC,iBAAiB,CAAC,CAAC,CAAC","sourcesContent":["import { createContext } from '@lit/context';\n\nimport type { View } from './session.context';\nimport type { ComputedItemContext } from './computed-item.context';\n\nexport type ComputedItem = ComputedItemContext & {\n categories?: string[]; // not necessary for outside world\n type?: 'info' | 'regular';\n index?: number;\n active?: boolean;\n};\n\nexport type ComputedContext = {\n view: View;\n identifier: string;\n title: string;\n testParts: {\n active?: boolean;\n identifier: string;\n navigationMode: 'linear' | 'nonlinear';\n submissionMode: 'individual' | 'simultaneous';\n sections: {\n active?: boolean;\n identifier: string;\n title: string;\n completed?: boolean;\n items: ComputedItem[];\n }[];\n }[];\n};\n\nexport const computedContext = createContext<Readonly<ComputedContext>>(Symbol('computedContext'));\n"]}
1
+ {"version":3,"file":"computed.context.js","sourceRoot":"","sources":["../../src/context/computed.context.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,aAAa,EAAE,MAAM,cAAc,CAAC;AAI7C,MAAM,CAAC,MAAM,eAAe,GAAG,aAAa,CAA4B,MAAM,CAAC,iBAAiB,CAAC,CAAC,CAAC","sourcesContent":["import { createContext } from '@lit/context';\n\nimport type { ComputedContext } from './types/computed.types';\n\nexport const computedContext = createContext<Readonly<ComputedContext>>(Symbol('computedContext'));\n"]}
@@ -1,6 +1,40 @@
1
- export type CorrectResponseMode = 'internal' | 'full';
1
+ export type ValidationDisplayMode = 'inline' | 'native' | 'both' | 'none';
2
2
  /**
3
- * Configuration context for QTI components. Provides runtime options for assessment item and interaction behavior.
3
+ * Configuration context for QTI components. Provides runtime options for assessment item and
4
+ * interaction behavior.
5
+ *
6
+ * ── Three ways to set it, in the order you should reach for them ─────────────────────────────
7
+ *
8
+ * 1. **On a provider**, for real delivery. `qti-test` and `qti-item` both provide it, so setting
9
+ * `item.configContext = {…}` configures every interaction inside.
10
+ *
11
+ * 2. **On one interaction, directly** — the development-time route, and the reason
12
+ * `Interaction.configContext` is public:
13
+ *
14
+ * orderInteraction.configContext = { allowReorder: false };
15
+ *
16
+ * or, in a lit-html template, as a property binding — which lands before `connectedCallback`:
17
+ *
18
+ * html`<qti-order-interaction .configContext=${{ allowReorder: false }}>…`
19
+ *
20
+ * An interaction has to work standalone, so in a story or a spec there is usually no provider
21
+ * above it, and then nothing ever overwrites what you set. Where a provider DOES exist it wins on
22
+ * its next emit, because `@consume` writes that same field.
23
+ *
24
+ * A `qti-config-test-provider` element used to exist for scoping config to a subtree. It is gone:
25
+ * it was test-only yet registered itself into every consumer's element registry via an unguarded
26
+ * `@customElement`, which threw whenever two copies of this package ended up in one module graph.
27
+ * Bind the property on each interaction instead, or provide from `qti-item`.
28
+ *
29
+ * There is no merging at any level: @lit/context resolves to the nearest provider and that object
30
+ * replaces the ancestor's wholesale. A deeper provider therefore has to restate anything from above
31
+ * that it still wants.
32
+ *
33
+ * Note what is NOT here. Options an item author chooses per question are attributes on the
34
+ * interaction (`auto-size-dropzones`, `max-associations`, `disable-animations`); options only a
35
+ * developer chooses are mixin factory arguments or method overrides. This context is for what a
36
+ * delivery environment decides across items. `interactionContext` and `dragDropContext` are neither
37
+ * — they publish derived state (what a choice IS, what a drop HOLDS), never configuration.
4
38
  */
5
39
  export interface ConfigContext {
6
40
  /**
@@ -14,26 +48,41 @@ export interface ConfigContext {
14
48
  */
15
49
  reportValidityAfterScoring?: boolean;
16
50
  /**
17
- * If true, disables further selection in choice interactions after the maximum number of choices is reached.
18
- * Used in multiple-choice and similar interactions to enforce maxChoices.
51
+ * Controls how validation feedback is displayed by interactions:
52
+ * - 'inline': render message in #validation-message (default behavior)
53
+ * - 'native': use browser-native reportValidity popup behavior
54
+ * - 'both': show both inline and native feedback
55
+ * - 'none': keep validity state only, without visual feedback
19
56
  */
20
- disableAfterIfMaxChoicesReached?: boolean;
57
+ validationDisplayMode?: ValidationDisplayMode;
58
+ /**
59
+ * If true, disables further user actions when an interaction reaches its configured maximum.
60
+ * Applies to both choice-based and drag/drop interactions.
61
+ */
62
+ disableAfterMaxReached?: boolean;
21
63
  /**
22
- * Controls the mode for showing correct responses:
23
- * - 'internal': Only show correct responses for the current interaction.
24
- * - 'full': Show all correct responses for the item.
64
+ * If false, chips already placed in a drop target cannot be reordered or moved between targets in
65
+ * drag/drop sortable interactions (order, match, gap-match). Defaults to true. A per-interaction
66
+ * `allowReorder` property overrides this.
25
67
  */
26
- correctResponseMode?: CorrectResponseMode;
68
+ allowReorder?: boolean;
69
+ /**
70
+ * If true, disables further selection in choice interactions after the maximum number of choices is reached.
71
+ * @deprecated Legacy alias for choice interactions. Prefer disableAfterMaxReached.
72
+ */
73
+ disableAfterIfMaxChoicesReached?: boolean;
27
74
  /**
28
75
  * Optional prompt text to display in inline choice interactions when no option is selected.
29
76
  * Example: "Select an answer..."
30
77
  */
31
78
  inlineChoicePrompt?: string;
32
79
  /**
33
- * If true, only show the full correct response when the candidate's response is incorrect.
34
- * Used to control feedback visibility in review/correction modes.
80
+ * If true, the inline choice interaction automatically measures the widest option and sizes the
81
+ * trigger button to match. Defaults to false.
82
+ * When a `qti-input-width-*` class is present on the interaction, that class width always takes
83
+ * precedence and autosizing is skipped regardless of this setting.
35
84
  */
36
- fullCorrectResponseOnlyWhenIncorrect?: boolean;
85
+ inlineChoiceAutosize?: boolean;
37
86
  }
38
87
  export declare const configContext: {
39
88
  __context__: Readonly<ConfigContext>;
@@ -1 +1 @@
1
- {"version":3,"file":"config.context.js","sourceRoot":"","sources":["../../src/context/config.context.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,aAAa,EAAE,MAAM,cAAc,CAAC;AA8C7C,MAAM,CAAC,MAAM,aAAa,GAAG,aAAa,CAA0B,MAAM,CAAC,eAAe,CAAC,CAAC,CAAC","sourcesContent":["import { createContext } from '@lit/context';\n\nexport type CorrectResponseMode = 'internal' | 'full';\n\n/**\n * Configuration context for QTI components. Provides runtime options for assessment item and interaction behavior.\n */\nexport interface ConfigContext {\n /**\n * Optional category label for info items, used for reporting or display purposes.\n * Example: \"General Information\", \"Instructions\".\n */\n infoItemCategory?: string;\n\n /**\n * If true, calls reportValidity() on interactions after scoring to show validation feedback.\n * Used to trigger UI validation after a scoring event.\n */\n reportValidityAfterScoring?: boolean;\n\n /**\n * If true, disables further selection in choice interactions after the maximum number of choices is reached.\n * Used in multiple-choice and similar interactions to enforce maxChoices.\n */\n disableAfterIfMaxChoicesReached?: boolean;\n\n /**\n * Controls the mode for showing correct responses:\n * - 'internal': Only show correct responses for the current interaction.\n * - 'full': Show all correct responses for the item.\n */\n correctResponseMode?: CorrectResponseMode;\n\n /**\n * Optional prompt text to display in inline choice interactions when no option is selected.\n * Example: \"Select an answer...\"\n */\n inlineChoicePrompt?: string;\n\n /**\n * If true, only show the full correct response when the candidate's response is incorrect.\n * Used to control feedback visibility in review/correction modes.\n */\n fullCorrectResponseOnlyWhenIncorrect?: boolean;\n}\n\nexport const configContext = createContext<Readonly<ConfigContext>>(Symbol('configContext'));\n"]}
1
+ {"version":3,"file":"config.context.js","sourceRoot":"","sources":["../../src/context/config.context.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,aAAa,EAAE,MAAM,cAAc,CAAC;AAiG7C,MAAM,CAAC,MAAM,aAAa,GAAG,aAAa,CAA0B,MAAM,CAAC,eAAe,CAAC,CAAC,CAAC","sourcesContent":["import { createContext } from '@lit/context';\n\nexport type ValidationDisplayMode = 'inline' | 'native' | 'both' | 'none';\n\n/**\n * Configuration context for QTI components. Provides runtime options for assessment item and\n * interaction behavior.\n *\n * ── Three ways to set it, in the order you should reach for them ─────────────────────────────\n *\n * 1. **On a provider**, for real delivery. `qti-test` and `qti-item` both provide it, so setting\n * `item.configContext = {…}` configures every interaction inside.\n *\n * 2. **On one interaction, directly** — the development-time route, and the reason\n * `Interaction.configContext` is public:\n *\n * orderInteraction.configContext = { allowReorder: false };\n *\n * or, in a lit-html template, as a property binding — which lands before `connectedCallback`:\n *\n * html`<qti-order-interaction .configContext=${{ allowReorder: false }}>…`\n *\n * An interaction has to work standalone, so in a story or a spec there is usually no provider\n * above it, and then nothing ever overwrites what you set. Where a provider DOES exist it wins on\n * its next emit, because `@consume` writes that same field.\n *\n * A `qti-config-test-provider` element used to exist for scoping config to a subtree. It is gone:\n * it was test-only yet registered itself into every consumer's element registry via an unguarded\n * `@customElement`, which threw whenever two copies of this package ended up in one module graph.\n * Bind the property on each interaction instead, or provide from `qti-item`.\n *\n * There is no merging at any level: @lit/context resolves to the nearest provider and that object\n * replaces the ancestor's wholesale. A deeper provider therefore has to restate anything from above\n * that it still wants.\n *\n * Note what is NOT here. Options an item author chooses per question are attributes on the\n * interaction (`auto-size-dropzones`, `max-associations`, `disable-animations`); options only a\n * developer chooses are mixin factory arguments or method overrides. This context is for what a\n * delivery environment decides across items. `interactionContext` and `dragDropContext` are neither\n * — they publish derived state (what a choice IS, what a drop HOLDS), never configuration.\n */\nexport interface ConfigContext {\n /**\n * Optional category label for info items, used for reporting or display purposes.\n * Example: \"General Information\", \"Instructions\".\n */\n infoItemCategory?: string;\n\n /**\n * If true, calls reportValidity() on interactions after scoring to show validation feedback.\n * Used to trigger UI validation after a scoring event.\n */\n reportValidityAfterScoring?: boolean;\n\n /**\n * Controls how validation feedback is displayed by interactions:\n * - 'inline': render message in #validation-message (default behavior)\n * - 'native': use browser-native reportValidity popup behavior\n * - 'both': show both inline and native feedback\n * - 'none': keep validity state only, without visual feedback\n */\n validationDisplayMode?: ValidationDisplayMode;\n\n /**\n * If true, disables further user actions when an interaction reaches its configured maximum.\n * Applies to both choice-based and drag/drop interactions.\n */\n disableAfterMaxReached?: boolean;\n\n /**\n * If false, chips already placed in a drop target cannot be reordered or moved between targets in\n * drag/drop sortable interactions (order, match, gap-match). Defaults to true. A per-interaction\n * `allowReorder` property overrides this.\n */\n allowReorder?: boolean;\n\n /**\n * If true, disables further selection in choice interactions after the maximum number of choices is reached.\n * @deprecated Legacy alias for choice interactions. Prefer disableAfterMaxReached.\n */\n disableAfterIfMaxChoicesReached?: boolean;\n\n /**\n * Optional prompt text to display in inline choice interactions when no option is selected.\n * Example: \"Select an answer...\"\n */\n inlineChoicePrompt?: string;\n\n /**\n * If true, the inline choice interaction automatically measures the widest option and sizes the\n * trigger button to match. Defaults to false.\n * When a `qti-input-width-*` class is present on the interaction, that class width always takes\n * precedence and autosizing is skipped regardless of this setting.\n */\n inlineChoiceAutosize?: boolean;\n}\n\nexport const configContext = createContext<Readonly<ConfigContext>>(Symbol('configContext'));\n"]}
@@ -0,0 +1,36 @@
1
+ /**
2
+ * What a choice element should render and behave as. The same element — `qti-simple-choice`,
3
+ * `qti-hottext` — is a radio in one interaction and a checkbox in another. It cannot know this
4
+ * by itself.
5
+ *
6
+ * Note "drag" is deliberately *not* a choiceRole. In `qti-match-interaction` the same element
7
+ * type is a drag in one match-set and a drop target in the other, so draggability is positional,
8
+ * not a property of the interaction. It is derived from `draggablesSelector` instead. It is also
9
+ * not a valid ARIA role, so it may only ever be a custom state.
10
+ */
11
+ export type ChoiceRole = 'radio' | 'checkbox';
12
+ /**
13
+ * State an interaction publishes to the choice elements inside it.
14
+ *
15
+ * Provided by the `qti-*-interaction`, never by `qti-assessment-item`: interactions must work
16
+ * standalone — in a plain form, in a story, in a vendor's app — with no QTI ancestor. Consumers
17
+ * must therefore tolerate its absence and fall back to a sensible default:
18
+ *
19
+ * const role = this.interactionContext?.choiceRole ?? null;
20
+ */
21
+ export interface InteractionContext {
22
+ /** `null` when the interaction assigns no particular role to its choices. */
23
+ choiceRole: ChoiceRole | null;
24
+ /**
25
+ * The selector this interaction uses to recognise its draggable chips. An element tests
26
+ * itself with `this.matches(draggablesSelector)` and takes `:state(chip)` if it matches.
27
+ *
28
+ * Published rather than pushed because draggability can be positional: match-interaction's
29
+ * selector distinguishes the source match-set from the target one, so two elements of the
30
+ * same tag get different answers.
31
+ */
32
+ draggablesSelector: string | null;
33
+ }
34
+ export declare const interactionContext: {
35
+ __context__: Readonly<InteractionContext>;
36
+ };
@@ -0,0 +1,3 @@
1
+ import { createContext } from '@lit/context';
2
+ export const interactionContext = createContext(Symbol('interactionContext'));
3
+ //# sourceMappingURL=interaction.context.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"interaction.context.js","sourceRoot":"","sources":["../../src/context/interaction.context.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,aAAa,EAAE,MAAM,cAAc,CAAC;AAsC7C,MAAM,CAAC,MAAM,kBAAkB,GAAG,aAAa,CAA+B,MAAM,CAAC,oBAAoB,CAAC,CAAC,CAAC","sourcesContent":["import { createContext } from '@lit/context';\n\n/**\n * What a choice element should render and behave as. The same element — `qti-simple-choice`,\n * `qti-hottext` — is a radio in one interaction and a checkbox in another. It cannot know this\n * by itself.\n *\n * Note \"drag\" is deliberately *not* a choiceRole. In `qti-match-interaction` the same element\n * type is a drag in one match-set and a drop target in the other, so draggability is positional,\n * not a property of the interaction. It is derived from `draggablesSelector` instead. It is also\n * not a valid ARIA role, so it may only ever be a custom state.\n */\nexport type ChoiceRole = 'radio' | 'checkbox';\n\n/**\n * State an interaction publishes to the choice elements inside it.\n *\n * Provided by the `qti-*-interaction`, never by `qti-assessment-item`: interactions must work\n * standalone — in a plain form, in a story, in a vendor's app — with no QTI ancestor. Consumers\n * must therefore tolerate its absence and fall back to a sensible default:\n *\n * const role = this.interactionContext?.choiceRole ?? null;\n */\nexport interface InteractionContext {\n /** `null` when the interaction assigns no particular role to its choices. */\n choiceRole: ChoiceRole | null;\n\n /**\n * The selector this interaction uses to recognise its draggable chips. An element tests\n * itself with `this.matches(draggablesSelector)` and takes `:state(chip)` if it matches.\n *\n * Published rather than pushed because draggability can be positional: match-interaction's\n * selector distinguishes the source match-set from the target one, so two elements of the\n * same tag get different answers.\n */\n draggablesSelector: string | null;\n}\n\nexport const interactionContext = createContext<Readonly<InteractionContext>>(Symbol('interactionContext'));\n"]}
@@ -1,12 +1,4 @@
1
- import type { VariableDeclaration } from '../lib/variables';
2
- export interface ItemContext {
3
- identifier?: string;
4
- href?: string;
5
- variables?: ReadonlyArray<VariableDeclaration<string | string[] | null>>;
6
- /**
7
- * Optional per-interaction opaque state, keyed by responseIdentifier.
8
- * Used for interactions that support state save/restore (e.g. PCI).
9
- */
10
- state?: Record<string, string | null>;
11
- }
12
- export declare const itemContextVariables: VariableDeclaration<string | string[]>[];
1
+ import type { ItemContext } from './types/item.types';
2
+ export declare const itemContext: {
3
+ __context__: ItemContext;
4
+ };
@@ -1,17 +1,3 @@
1
- export const itemContextVariables = [
2
- {
3
- identifier: 'completionStatus',
4
- cardinality: 'single',
5
- baseType: 'string',
6
- value: 'unknown',
7
- type: 'outcome'
8
- },
9
- {
10
- identifier: 'numAttempts',
11
- cardinality: 'single',
12
- baseType: 'integer',
13
- value: '0',
14
- type: 'response'
15
- }
16
- ];
1
+ import { createContext } from '@lit/context';
2
+ export const itemContext = createContext(Symbol('item'));
17
3
  //# sourceMappingURL=item.context.js.map
@@ -1 +1 @@
1
- {"version":3,"file":"item.context.js","sourceRoot":"","sources":["../../src/context/item.context.ts"],"names":[],"mappings":"AAaA,MAAM,CAAC,MAAM,oBAAoB,GAAG;IAClC;QACE,UAAU,EAAE,kBAAkB;QAC9B,WAAW,EAAE,QAAQ;QACrB,QAAQ,EAAE,QAAQ;QAClB,KAAK,EAAE,SAAS;QAChB,IAAI,EAAE,SAAS;KAChB;IACD;QACE,UAAU,EAAE,aAAa;QACzB,WAAW,EAAE,QAAQ;QACrB,QAAQ,EAAE,SAAS;QACnB,KAAK,EAAE,GAAG;QACV,IAAI,EAAE,UAAU;KACjB;CAC0C,CAAC","sourcesContent":["import type { VariableDeclaration } from '../lib/variables';\n\nexport interface ItemContext {\n identifier?: string;\n href?: string;\n variables?: ReadonlyArray<VariableDeclaration<string | string[] | null>>;\n /**\n * Optional per-interaction opaque state, keyed by responseIdentifier.\n * Used for interactions that support state save/restore (e.g. PCI).\n */\n state?: Record<string, string | null>;\n}\n\nexport const itemContextVariables = [\n {\n identifier: 'completionStatus',\n cardinality: 'single',\n baseType: 'string',\n value: 'unknown',\n type: 'outcome'\n },\n {\n identifier: 'numAttempts',\n cardinality: 'single',\n baseType: 'integer',\n value: '0',\n type: 'response'\n }\n] as VariableDeclaration<string | string[]>[];\n"]}
1
+ {"version":3,"file":"item.context.js","sourceRoot":"","sources":["../../src/context/item.context.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,aAAa,EAAE,MAAM,cAAc,CAAC;AAI7C,MAAM,CAAC,MAAM,WAAW,GAAG,aAAa,CAAc,MAAM,CAAC,MAAM,CAAC,CAAC,CAAC","sourcesContent":["import { createContext } from '@lit/context';\n\nimport type { ItemContext } from './types/item.types';\n\nexport const itemContext = createContext<ItemContext>(Symbol('item'));\n"]}
@@ -1,4 +1,4 @@
1
- import type { ItemContext } from './item.context';
1
+ import type { ItemContext } from './types/item.types';
2
2
  import type { VariableDeclaration } from '../lib/variables';
3
3
  export interface TestContext {
4
4
  items: (ItemContext & {
@@ -1 +1 @@
1
- {"version":3,"file":"test.context.js","sourceRoot":"","sources":["../../src/context/test.context.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,aAAa,EAAE,MAAM,cAAc,CAAC;AAU7C,MAAM,CAAC,MAAM,oBAAoB,GAA0B,EAAE,KAAK,EAAE,EAAE,EAAE,oBAAoB,EAAE,EAAE,EAAE,CAAC;AAEnG,MAAM,CAAC,MAAM,WAAW,GAAG,aAAa,CAAwB,MAAM,CAAC,aAAa,CAAC,CAAC,CAAC","sourcesContent":["import { createContext } from '@lit/context';\n\nimport type { ItemContext } from './item.context';\nimport type { VariableDeclaration } from '../lib/variables';\n\nexport interface TestContext {\n items: (ItemContext & { category?: string })[];\n testOutcomeVariables?: VariableDeclaration<string | string[] | null>[];\n}\n\nexport const INITIAL_TEST_CONTEXT: Readonly<TestContext> = { items: [], testOutcomeVariables: [] };\n\nexport const testContext = createContext<Readonly<TestContext>>(Symbol('testContext'));\n"]}
1
+ {"version":3,"file":"test.context.js","sourceRoot":"","sources":["../../src/context/test.context.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,aAAa,EAAE,MAAM,cAAc,CAAC;AAU7C,MAAM,CAAC,MAAM,oBAAoB,GAA0B,EAAE,KAAK,EAAE,EAAE,EAAE,oBAAoB,EAAE,EAAE,EAAE,CAAC;AAEnG,MAAM,CAAC,MAAM,WAAW,GAAG,aAAa,CAAwB,MAAM,CAAC,aAAa,CAAC,CAAC,CAAC","sourcesContent":["import { createContext } from '@lit/context';\n\nimport type { ItemContext } from './types/item.types';\nimport type { VariableDeclaration } from '../lib/variables';\n\nexport interface TestContext {\n items: (ItemContext & { category?: string })[];\n testOutcomeVariables?: VariableDeclaration<string | string[] | null>[];\n}\n\nexport const INITIAL_TEST_CONTEXT: Readonly<TestContext> = { items: [], testOutcomeVariables: [] };\n\nexport const testContext = createContext<Readonly<TestContext>>(Symbol('testContext'));\n"]}
@@ -0,0 +1,16 @@
1
+ import type { VariableDeclaration } from '../../lib/variables';
2
+ export type ComputedItemContext = {
3
+ identifier: string;
4
+ href?: string;
5
+ correct?: boolean;
6
+ incorrect?: boolean;
7
+ completed?: boolean;
8
+ adaptive?: boolean;
9
+ timeDependent?: boolean;
10
+ title?: string;
11
+ label?: string;
12
+ score?: number;
13
+ maxScore?: number;
14
+ completionStatus?: string;
15
+ variables: ReadonlyArray<VariableDeclaration<string | string[] | null>>;
16
+ };
@@ -0,0 +1,2 @@
1
+ export {};
2
+ //# sourceMappingURL=computed-item.types.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"computed-item.types.js","sourceRoot":"","sources":["../../../src/context/types/computed-item.types.ts"],"names":[],"mappings":"","sourcesContent":["import type { VariableDeclaration } from '../../lib/variables';\n\nexport type ComputedItemContext = {\n identifier: string;\n href?: string;\n correct?: boolean;\n incorrect?: boolean;\n completed?: boolean;\n adaptive?: boolean;\n timeDependent?: boolean;\n title?: string;\n label?: string;\n score?: number;\n maxScore?: number;\n completionStatus?: string;\n variables: ReadonlyArray<VariableDeclaration<string | string[] | null>>;\n};\n"]}
@@ -0,0 +1,26 @@
1
+ import type { View } from '../session.context';
2
+ import type { ComputedItemContext } from './computed-item.types';
3
+ export type ComputedItem = ComputedItemContext & {
4
+ categories?: string[];
5
+ type?: 'info' | 'regular';
6
+ index?: number;
7
+ active?: boolean;
8
+ };
9
+ export type ComputedContext = {
10
+ view: View;
11
+ identifier: string;
12
+ title: string;
13
+ testParts: {
14
+ active?: boolean;
15
+ identifier: string;
16
+ navigationMode: 'linear' | 'nonlinear';
17
+ submissionMode: 'individual' | 'simultaneous';
18
+ sections: {
19
+ active?: boolean;
20
+ identifier: string;
21
+ title: string;
22
+ completed?: boolean;
23
+ items: ComputedItem[];
24
+ }[];
25
+ }[];
26
+ };
@@ -0,0 +1,2 @@
1
+ export {};
2
+ //# sourceMappingURL=computed.types.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"computed.types.js","sourceRoot":"","sources":["../../../src/context/types/computed.types.ts"],"names":[],"mappings":"","sourcesContent":["import type { View } from '../session.context';\nimport type { ComputedItemContext } from './computed-item.types';\n\nexport type ComputedItem = ComputedItemContext & {\n categories?: string[]; // not necessary for outside world\n type?: 'info' | 'regular';\n index?: number;\n active?: boolean;\n};\n\nexport type ComputedContext = {\n view: View;\n identifier: string;\n title: string;\n testParts: {\n active?: boolean;\n identifier: string;\n navigationMode: 'linear' | 'nonlinear';\n submissionMode: 'individual' | 'simultaneous';\n sections: {\n active?: boolean;\n identifier: string;\n title: string;\n completed?: boolean;\n items: ComputedItem[];\n }[];\n }[];\n};\n"]}