@citolab/qti-components 8.0.1 → 8.0.2
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/cdn/index.global.js +1 -1
- package/cdn/index.js +103 -103
- package/dist/base.d.ts +3 -3
- package/dist/base.js +1 -1
- package/dist/chunk-4DB4SC5K.js +100 -0
- package/dist/chunk-4DB4SC5K.js.map +1 -0
- package/dist/{chunk-WVVMNF74.js → chunk-7AVWRQIS.js} +188 -160
- package/dist/{chunk-WVVMNF74.js.map → chunk-7AVWRQIS.js.map} +1 -1
- package/dist/{chunk-CAO4JRLY.js → chunk-BQFWCZFH.js} +2 -2
- package/dist/{chunk-LVBIQDPM.js → chunk-CK7AV2UJ.js} +147 -101
- package/dist/chunk-CK7AV2UJ.js.map +1 -0
- package/dist/{chunk-7HC5SMCU.js → chunk-G6GFQDVN.js} +1 -96
- package/dist/chunk-G6GFQDVN.js.map +1 -0
- package/dist/{chunk-RXGDQDOV.js → chunk-HBSWJC3B.js} +478 -392
- package/dist/chunk-HBSWJC3B.js.map +1 -0
- package/dist/chunk-HQESINXH.js +834 -0
- package/dist/chunk-HQESINXH.js.map +1 -0
- package/dist/{chunk-XU7HNT4F.js → chunk-J5SQLKNP.js} +145 -119
- package/dist/{chunk-XU7HNT4F.js.map → chunk-J5SQLKNP.js.map} +1 -1
- package/dist/{chunk-V5G7X53Y.js → chunk-NJQHUUTN.js} +2 -2
- package/dist/{chunk-QECOPVPO.js → chunk-RSVRS5AK.js} +59 -58
- package/dist/chunk-RSVRS5AK.js.map +1 -0
- package/dist/{chunk-F4BNJWYN.js → chunk-TWPXES3S.js} +642 -673
- package/dist/chunk-TWPXES3S.js.map +1 -0
- package/dist/{chunk-NA2N2WSG.js → chunk-VAE6HBKR.js} +176 -152
- package/dist/{chunk-NA2N2WSG.js.map → chunk-VAE6HBKR.js.map} +1 -1
- package/dist/{chunk-3AJOQCDU.js → chunk-ZII6M3SN.js} +2 -2
- package/dist/{computed.types.d-rKLSPvVG.d.ts → computed.types.d-DpKIYO6e.d.ts} +2 -0
- package/dist/corrections.d.ts +12 -29
- package/dist/corrections.js +8 -9
- package/dist/elements.d.ts +86 -86
- package/dist/elements.js +4 -5
- package/dist/index.d.ts +6 -37
- package/dist/index.js +13 -14
- package/dist/{interaction.d-D4MstYRz.d.ts → interaction.d-CJiMv8H7.d.ts} +13 -2
- package/dist/interactions.d.ts +11 -1299
- package/dist/interactions.js +4 -5
- package/dist/item.d.ts +3 -3
- package/dist/item.js +5 -5
- package/dist/processing.js +2 -2
- package/dist/qti-components-jsx.d.ts +759 -739
- package/dist/qti-test.d-_YAlhDbt.d.ts +702 -0
- package/dist/qti-text-entry-interaction.d-BGdfV9qG.d.ts +1567 -0
- package/dist/test.d.ts +11 -678
- package/dist/test.js +6 -7
- package/package.json +8 -7
- package/dist/chunk-64XSIBGO.js +0 -241
- package/dist/chunk-64XSIBGO.js.map +0 -1
- package/dist/chunk-7HC5SMCU.js.map +0 -1
- package/dist/chunk-F4BNJWYN.js.map +0 -1
- package/dist/chunk-H3J7LFRO.js +0 -2243
- package/dist/chunk-H3J7LFRO.js.map +0 -1
- package/dist/chunk-LVBIQDPM.js.map +0 -1
- package/dist/chunk-QECOPVPO.js.map +0 -1
- package/dist/chunk-RXGDQDOV.js.map +0 -1
- package/dist/chunk-X3E5HXG2.js +0 -20
- package/dist/chunk-X3E5HXG2.js.map +0 -1
- /package/dist/{chunk-CAO4JRLY.js.map → chunk-BQFWCZFH.js.map} +0 -0
- /package/dist/{chunk-V5G7X53Y.js.map → chunk-NJQHUUTN.js.map} +0 -0
- /package/dist/{chunk-3AJOQCDU.js.map → chunk-ZII6M3SN.js.map} +0 -0
|
@@ -1 +0,0 @@
|
|
|
1
|
-
{"version":3,"sources":["../../interactions/core/src/mixins/active-element/active-element.mixin.ts","../../interactions/core/src/elements/qti-gap-text/qti-gap-text.styles.ts","../../interactions/core/src/elements/qti-gap-text/qti-gap-text.ts","../../interactions/core/src/elements/qti-hotspot-choice/qti-hotspot-choice.styles.ts","../../interactions/core/src/elements/qti-hotspot-choice/qti-hotspot-choice.ts","../../interactions/core/src/elements/qti-hottext/qti-hottext.styles.ts","../../interactions/core/src/elements/qti-hottext/qti-hottext.ts","../../../node_modules/.pnpm/lit-html@3.3.2/node_modules/lit-html/src/directives/repeat.ts","../../interactions/core/src/context/drag-drop.context.ts","../../interactions/core/src/elements/qti-simple-associable-choice/qti-simple-associable-choice.styles.ts","../../interactions/core/src/elements/qti-simple-associable-choice/qti-simple-associable-choice.ts","../../interactions/core/src/elements/qti-simple-choice/qti-simple-choice.styles.ts","../../interactions/core/src/elements/qti-simple-choice/qti-simple-choice.ts","../../interactions/core/src/mixins/dropzone-auto-size/dropzone-auto-size.mixin.ts","../../../node_modules/.pnpm/observable-polyfill@0.0.29/node_modules/observable-polyfill/observable.js","../../interactions/core/src/mixins/drag-drop-observables/utils/collision.utils.ts","../../interactions/core/src/mixins/drag-drop-observables/utils/drag-drop.utils.ts","../../interactions/core/src/mixins/drag-drop-observables/utils/drag-clone-host.ts","../../interactions/core/src/mixins/drag-drop-observables/drag-drop-core.mixin.ts","../../interactions/core/src/mixins/drag-drop-observables/utils/flip.utils.ts","../../interactions/core/src/mixins/drag-drop-observables/drag-drop-slotted.mixin.ts","../../interactions/core/src/mixins/drag-drop-observables/strategies/sorting.strategy.ts","../../interactions/core/src/mixins/drag-drop-observables/utils/sortable.utils.ts","../../interactions/core/src/mixins/drag-drop-observables/drag-drop-slotted-sortable.mixin.ts","../../interactions/associate-interaction/src/qti-associate-interaction.styles.ts","../../interactions/associate-interaction/src/qti-associate-interaction.ts","../../interactions/core/src/mixins/choices/choices.mixin.ts","../../interactions/core/src/mixins/vocabulary/vocabulary-mixin.ts","../../interactions/choice-interaction/src/qti-choice-interaction.styles.ts","../../interactions/choice-interaction/src/qti-choice-interaction.ts","../../interactions/extended-text-interaction/src/qti-extended-text-interaction.styles.ts","../../interactions/extended-text-interaction/src/qti-extended-text-interaction.ts","../../interactions/gap-match-interaction/src/qti-gap-match-interaction.styles.ts","../../interactions/gap-match-interaction/src/qti-gap-match-interaction.ts","../../interactions/core/src/internal/hotspots/hotspot.ts","../../interactions/graphic-associate-interaction/src/qti-graphic-associate-interaction.styles.ts","../../interactions/graphic-associate-interaction/src/qti-graphic-associate-interaction.ts","../../interactions/graphic-gap-match-interaction/src/qti-graphic-gap-match-interaction.styles.ts","../../interactions/graphic-gap-match-interaction/src/qti-graphic-gap-match-interaction.ts","../../interactions/graphic-order-interaction/src/qti-graphic-order-interaction.styles.ts","../../interactions/graphic-order-interaction/src/qti-graphic-order-interaction.ts","../../interactions/hotspot-interaction/src/qti-hotspot-interaction.styles.ts","../../interactions/hotspot-interaction/src/qti-hotspot-interaction.ts","../../interactions/hottext-interaction/src/qti-hottext-interaction.styles.ts","../../interactions/hottext-interaction/src/qti-hottext-interaction.ts","../../interactions/core/src/mixins/menu-auto-size/menu-auto-size.mixin.ts","../../interactions/inline-choice-interaction/src/qti-inline-choice-interaction.styles.ts","../../interactions/inline-choice-interaction/src/qti-inline-choice-interaction.ts","../../interactions/match-interaction/src/qti-match-interaction.styles.ts","../../interactions/match-interaction/src/qti-match-interaction-tabular.styles.ts","../../interactions/match-interaction/src/qti-match-interaction.ts","../../interactions/order-interaction/src/qti-order-interaction.styles.ts","../../interactions/order-interaction/src/qti-order-interaction.ts","../../interactions/portable-custom-interaction/src/qti-portable-custom-interaction.styles.ts","../../interactions/portable-custom-interaction/src/qti-portable-custom-interaction.ts","../../../node_modules/.pnpm/lit-html@3.3.2/node_modules/lit-html/src/directives/style-map.ts","../../interactions/select-point-interaction/src/qti-select-point-interaction.styles.ts","../../interactions/select-point-interaction/src/qti-select-point-interaction.ts","../../interactions/slider-interaction/src/qti-slider-interaction.styles.ts","../../interactions/slider-interaction/src/qti-slider-interaction.ts","../../../node_modules/.pnpm/lit-html@3.3.2/node_modules/lit-html/src/directives/ref.ts","../../interactions/text-entry-interaction/src/qti-text-entry-interaction.styles.ts","../../interactions/text-entry-interaction/src/qti-text-entry-interaction.ts","../../interactions/associate-interaction/src/elements.ts","../../interactions/choice-interaction/src/elements.ts","../../interactions/extended-text-interaction/src/elements.ts","../../interactions/gap-match-interaction/src/elements.ts","../../interactions/graphic-associate-interaction/src/elements.ts","../../interactions/graphic-gap-match-interaction/src/elements.ts","../../interactions/graphic-order-interaction/src/elements.ts","../../interactions/hotspot-interaction/src/elements.ts","../../interactions/hottext-interaction/src/elements.ts","../../interactions/inline-choice-interaction/src/elements.ts","../../interactions/match-interaction/src/elements.ts","../../interactions/order-interaction/src/elements.ts","../../interactions/portable-custom-interaction/src/qti-portable-custom-test-interaction.ts","../../interactions/portable-custom-interaction/src/elements.ts","../../interactions/select-point-interaction/src/elements.ts","../../interactions/slider-interaction/src/elements.ts","../../interactions/text-entry-interaction/src/elements.ts"],"sourcesContent":["import { html } from 'lit';\nimport { property, state } from 'lit/decorators.js';\nimport { consume } from '@lit/context';\n\nimport { watch } from '@qti-components/utilities';\nimport { interactionContext } from '@qti-components/base';\n\nimport type { ComplexAttributeConverter, LitElement, PropertyValues } from 'lit';\nimport type { InteractionContext } from '@qti-components/base';\n\ntype Constructor<T = {}> = abstract new (...args: any[]) => T;\n\nexport interface ChoiceInterface {\n identifier: string;\n disabled: boolean;\n readonly: boolean;\n}\n\n/**\n * Converter to handle boolean attributes for ARIA properties,\n * ensuring they are set as 'true' or 'false' strings.\n */\nconst ariaBooleanConverter: ComplexAttributeConverter<boolean, boolean> = {\n toAttribute: (value: boolean) => (value ? 'true' : 'false'),\n fromAttribute: (value: string | null) => value === 'true'\n};\n\n/**\n * A mixin that adds choice functionality to a LitElement-based class.\n * It dispatches events with a custom `type` and handles selection logic.\n *\n * @param Base - The base class to extend.\n * @param type - The type of the choice, used in event names.\n * @returns A new class extending the base class with choice functionality.\n */\nexport interface ActiveElementMixinInterface {\n identifier: string;\n tabIndex: number;\n disabled: boolean;\n readonly: boolean;\n internals: ElementInternals;\n}\n\nexport function ActiveElementMixin<T extends Constructor<LitElement>>(Base: T, type: string) {\n abstract class QtiChoice extends Base {\n @property({ type: String })\n public identifier = '';\n\n /*\n * `tabindex` is a native focusability attribute, not an ARIA state — it has to reach the\n * DOM or the element cannot be focused. Reflect it, unlike disabled/readonly below.\n */\n @property({ type: Number, reflect: true, attribute: 'tabindex' })\n public override tabIndex = 0;\n\n /*\n * Author markup may set `aria-disabled` / `aria-readonly` to seed these, but they are\n * deliberately never reflected back out. The semantics live on ElementInternals: the\n * ARIA property feeds the accessibility tree, the custom state feeds CSS. Style with\n * `:state(disabled)` / `:state(readonly)`, never an attribute selector.\n */\n @property({\n type: Boolean,\n attribute: 'aria-disabled',\n converter: ariaBooleanConverter\n })\n public disabled = false;\n\n @property({\n type: Boolean,\n attribute: 'aria-readonly',\n converter: ariaBooleanConverter\n })\n public readonly = false;\n\n public internals: ElementInternals;\n\n /*\n * The role this element should take — radio, checkbox, or drag chip — is a property of the\n * interaction it sits in, not of the element. It subscribes rather than being told, so it\n * behaves correctly wherever it is placed, and works standalone with no provider above it.\n */\n @consume({ context: interactionContext, subscribe: true })\n @state()\n protected _interactionContext?: Readonly<InteractionContext>;\n\n #appliedChoiceRole: string | null = null;\n\n /**\n * Apply what the interaction published. No provider (standalone) means no role.\n *\n * `radio` / `checkbox` are both ARIA roles and custom states.\n *\n * Drag/drop states are owned by the drag-drop mixins, because they already track which\n * elements are draggable or droppable and can update those states directly.\n */\n #syncChoiceRole() {\n const ctx = this._interactionContext;\n\n const role = ctx?.choiceRole ?? null;\n if (role !== this.#appliedChoiceRole) {\n if (this.#appliedChoiceRole) this.internals.states.delete(this.#appliedChoiceRole);\n this.#appliedChoiceRole = role;\n this.internals.role = role;\n if (role) this.internals.states.add(role);\n }\n }\n\n @watch('disabled', { waitUntilFirstUpdate: true })\n handleDisabledChange(_oldValue: boolean, disabled: boolean) {\n // Mirror the semantic onto ElementInternals: the ARIA property feeds the accessibility\n // tree, the custom state feeds CSS (`:state(disabled)`). Only assert them when actually\n // disabled and clear them otherwise, so an enabled element carries no disabled semantics.\n if (disabled) {\n this.internals.ariaDisabled = 'true';\n this.internals.states.add('disabled');\n this.blur();\n } else {\n this.internals.ariaDisabled = null;\n this.internals.states.delete('disabled');\n }\n this.tabIndex = disabled ? -1 : 0;\n }\n\n @watch('readonly', { waitUntilFirstUpdate: true })\n handleReadonlyChange(_oldValue: boolean, readonly: boolean) {\n if (readonly) {\n this.internals.ariaReadOnly = 'true';\n this.internals.states.add('readonly');\n } else {\n this.internals.ariaReadOnly = null;\n this.internals.states.delete('readonly');\n }\n }\n\n constructor(...args: any[]) {\n super(...args);\n this.internals = this.attachInternals();\n }\n\n override willUpdate(changed: PropertyValues<this>) {\n super.willUpdate(changed);\n this.#syncChoiceRole();\n }\n\n override connectedCallback() {\n super.connectedCallback();\n\n // Initialize ARIA/state on internals (watchers only fire on change). Only assert\n // disabled/readonly when true — an enabled, editable element carries no such semantics.\n this.internals.ariaChecked = 'false';\n if (this.disabled) {\n this.internals.ariaDisabled = 'true';\n this.internals.states.add('disabled');\n this.tabIndex = -1;\n }\n if (this.readonly) {\n this.internals.ariaReadOnly = 'true';\n this.internals.states.add('readonly');\n }\n\n this.addEventListener('keyup', this._onKeyUp);\n this.addEventListener('click', this._onClick);\n\n this.dispatchEvent(\n new CustomEvent(`register-${type}`, {\n bubbles: true,\n composed: true\n })\n );\n }\n\n override disconnectedCallback() {\n super.disconnectedCallback();\n this.removeEventListener('keyup', this._onKeyUp);\n this.removeEventListener('click', this._onClick);\n this.dispatchEvent(\n new CustomEvent(`unregister-${type}`, {\n bubbles: true,\n composed: true\n })\n );\n }\n\n private _onKeyUp(event: KeyboardEvent) {\n if (event.altKey) return;\n\n if (event.code === 'Space' || event.code === 'Enter') {\n event.preventDefault();\n this._activate();\n }\n }\n\n private _onClick() {\n if (this.disabled || this.readonly) return;\n this.focus();\n this._activate();\n }\n\n private _activate() {\n if (this.disabled || this.readonly) return;\n\n this.dispatchEvent(\n new CustomEvent<{ identifier: string }>(`activate-${type}`, {\n bubbles: true,\n composed: true,\n detail: { identifier: this.identifier }\n })\n );\n }\n\n override render() {\n return html`<slot></slot>`;\n }\n }\n return QtiChoice as Constructor<ActiveElementMixinInterface> & T;\n}\n","import { css } from 'lit';\n\nimport { boxSizing } from '@qti-components/base';\n\nexport default [\n boxSizing,\n css`\n /*\n * A chip's own box. Both drag-drop interactions that use this element laid it out from the\n * theme — gap-match with 'display: flex !important; align-items: center !important',\n * graphic-gap-match with the same plus centred justification — and both were overriding the\n * 'inline-flex' this file used to declare. Flex is what actually rendered, so flex is what it\n * says now.\n *\n * Justification is a variable because only graphic-gap-match centres, where a chip is a tile\n * filling its hotspot. A gap-match chip hugs its text, and centring moved that text.\n */\n /*\n * Centred wherever it lives — this is the one-line follow-up the note here used to promise.\n *\n * It read :host(:not([part~='drag'])), which reproduced an older accident: the centring rule\n * used to be a document selector ('qti-gap-match-interaction qti-gap-text'), and a placed chip\n * lives inside qti-gap's shadow root where no document selector reaches. So a chip in the bank was\n * centred and the same chip in a gap was not, and the stylesheet gave no hint why.\n *\n * That contradicts the layout-invariance contract — a chip is the same chip wherever it stands —\n * and it showed: the correction badge centred in the bank and rode to the top once placed. The\n * badge now sets align-self and no longer depends on this, but the label and the drag grip\n * still did. Making it unconditional costs a one-pixel text shift on placed chips, which is the\n * rendering change the old note was deferring, and a VRT re-baseline.\n */\n :host {\n display: flex;\n align-items: center;\n justify-content: var(--qti-drag-justify-content, normal);\n user-select: none;\n }\n `\n];\n","import { html, LitElement } from 'lit';\nimport { property } from 'lit/decorators.js';\n\nimport { ActiveElementMixin } from '../../mixins/active-element/active-element.mixin';\nimport styles from './qti-gap-text.styles';\n\nimport type { CSSResultGroup } from 'lit';\n\n/**\n * A draggable text token that fills a `qti-gap` inside `qti-gap-match-interaction`.\n *\n * @customElement qti-gap-text\n *\n * @attr {string} identifier - Required. Value recorded in the response pair when this token is\n * placed into a gap.\n * @attr {number} [match-max=1] - How many gaps this token may fill; `0` means unlimited.\n * Read from the DOM by the drag-drop mixin.\n * @attr {number} [match-min=0] - Minimum gaps this token must fill.\n * @attr {boolean} [fixed=false] - Pins this token in place when the interaction is shuffled.\n * @attr {string} template-identifier - Not implemented. Identifier of a template variable\n * controlling this token's visibility.\n * @attr {'show'|'hide'} [show-hide=show] - Not implemented. How `template-identifier` controls\n * visibility.\n */\nexport class QtiGapText extends ActiveElementMixin(LitElement, 'qti-gap-text') {\n static override styles: CSSResultGroup = styles;\n\n @property({ type: Number, reflect: true }) tabindex: number | undefined = 0;\n\n override connectedCallback(): void {\n super.connectedCallback();\n this.setAttribute('slot', 'drags');\n }\n\n override render() {\n return html`<div part=\"control\"></div>\n <slot part=\"label\"></slot>`;\n }\n}\n\ndeclare global {\n interface HTMLElementTagNameMap {\n 'qti-gap-text': QtiGapText;\n }\n}\n","import { css } from 'lit';\n\nimport { boxSizing } from '@qti-components/base';\n\nexport default [\n boxSizing,\n css`\n :host {\n display: flex;\n user-select: none;\n position: absolute;\n }\n\n /*\n * Graphic-order paints an order pin anchored to this hotspot, and the pin sits outside the\n * hotspot's own box. Both of these were in the theme, keyed on the same ARIA attributes the\n * interaction already writes to the host.\n */\n :host([aria-ordervalue]) {\n overflow: visible;\n }\n\n :host([aria-ordercorrectvalue]) {\n display: grid;\n place-content: center;\n }\n `\n];\n","import { LitElement } from 'lit';\nimport { property } from 'lit/decorators.js';\n\nimport { ActiveElementMixin } from '../../mixins/active-element/active-element.mixin';\nimport styles from './qti-hotspot-choice.styles';\n\nimport type { CSSResultGroup } from 'lit';\n\n// type shape = { shape: 'rect' | 'circle' | 'poly'; coords: number[] };\nexport class QtiHotspotChoice extends ActiveElementMixin(LitElement, 'qti-hotspot-choice') {\n static override styles: CSSResultGroup = styles;\n @property({ attribute: 'aria-ordervalue', type: Number, reflect: true }) order: number;\n}\n\ndeclare global {\n interface HTMLElementTagNameMap {\n 'qti-hotspot-choice': QtiHotspotChoice;\n }\n}\n","import { css } from 'lit';\n\nimport { boxSizing } from '@qti-components/base';\n\nexport default [\n boxSizing,\n css`\n /* 'position: relative' is the containing block for the answer-key tick the theme draws as an\n absolutely positioned ::before. See CONTRACT.md §7. */\n :host {\n display: inline-flex;\n align-items: center;\n position: relative;\n padding: var(--qti-padding-inline, 1px 4px);\n }\n\n /*\n * A hottext never shows the native radio/checkbox box — every theme variant draws selection on\n * the word itself. The control stays in the tree for the accessibility mapping, out of the flow.\n *\n * This was three identical '::part(control) { display: none }' rules in the theme, one per\n * variant, under a fourth that had already hidden it unconditionally.\n */\n [part='control'] {\n display: none;\n }\n `\n];\n","import { html, LitElement } from 'lit';\n\nimport { ActiveElementMixin } from '../../mixins/active-element/active-element.mixin';\nimport styles from './qti-hottext.styles';\n\nimport type { CSSResultGroup } from 'lit';\n\n/**\n * A selectable span of text inside `qti-hottext-interaction`.\n *\n * @customElement qti-hottext\n *\n * @attr {string} identifier - Required. Value recorded in the response when this span is\n * selected.\n * @attr {string} template-identifier - Not implemented. Identifier of a template variable\n * controlling this span's visibility.\n * @attr {'show'|'hide'} [show-hide=show] - Not implemented. How `template-identifier` controls\n * visibility.\n */\nexport class QtiHottext extends ActiveElementMixin(LitElement, 'qti-hottext') {\n static override styles: CSSResultGroup = styles;\n\n override render() {\n return html`<div part=\"control\"><div part=\"control-mark\"></div></div>\n <slot part=\"label\"></slot>`;\n }\n}\n\ndeclare global {\n interface HTMLElementTagNameMap {\n 'qti-hottext': QtiHottext;\n }\n}\n","/**\n * @license\n * Copyright 2017 Google LLC\n * SPDX-License-Identifier: BSD-3-Clause\n */\n\nimport {ChildPart, noChange} from '../lit-html.js';\nimport {directive, Directive, PartInfo, PartType} from '../directive.js';\nimport {\n insertPart,\n getCommittedValue,\n removePart,\n setCommittedValue,\n setChildPartValue,\n} from '../directive-helpers.js';\n\nexport type KeyFn<T> = (item: T, index: number) => unknown;\nexport type ItemTemplate<T> = (item: T, index: number) => unknown;\n\n// Helper for generating a map of array item to its index over a subset\n// of an array (used to lazily generate `newKeyToIndexMap` and\n// `oldKeyToIndexMap`)\nconst generateMap = (list: unknown[], start: number, end: number) => {\n const map = new Map<unknown, number>();\n for (let i = start; i <= end; i++) {\n map.set(list[i], i);\n }\n return map;\n};\n\nclass RepeatDirective extends Directive {\n private _itemKeys?: unknown[];\n\n constructor(partInfo: PartInfo) {\n super(partInfo);\n if (partInfo.type !== PartType.CHILD) {\n throw new Error('repeat() can only be used in text expressions');\n }\n }\n\n private _getValuesAndKeys<T>(\n items: Iterable<T>,\n keyFnOrTemplate: KeyFn<T> | ItemTemplate<T>,\n template?: ItemTemplate<T>\n ) {\n let keyFn: KeyFn<T> | undefined;\n if (template === undefined) {\n template = keyFnOrTemplate;\n } else if (keyFnOrTemplate !== undefined) {\n keyFn = keyFnOrTemplate as KeyFn<T>;\n }\n const keys = [];\n const values = [];\n let index = 0;\n for (const item of items) {\n keys[index] = keyFn ? keyFn(item, index) : index;\n values[index] = template!(item, index);\n index++;\n }\n return {\n values,\n keys,\n };\n }\n\n render<T>(items: Iterable<T>, template: ItemTemplate<T>): Array<unknown>;\n render<T>(\n items: Iterable<T>,\n keyFn: KeyFn<T> | ItemTemplate<T>,\n template: ItemTemplate<T>\n ): Array<unknown>;\n render<T>(\n items: Iterable<T>,\n keyFnOrTemplate: KeyFn<T> | ItemTemplate<T>,\n template?: ItemTemplate<T>\n ) {\n return this._getValuesAndKeys(items, keyFnOrTemplate, template).values;\n }\n\n override update<T>(\n containerPart: ChildPart,\n [items, keyFnOrTemplate, template]: [\n Iterable<T>,\n KeyFn<T> | ItemTemplate<T>,\n ItemTemplate<T>,\n ]\n ) {\n // Old part & key lists are retrieved from the last update (which may\n // be primed by hydration)\n const oldParts = getCommittedValue(\n containerPart\n ) as Array<ChildPart | null>;\n const {values: newValues, keys: newKeys} = this._getValuesAndKeys(\n items,\n keyFnOrTemplate,\n template\n );\n\n // We check that oldParts, the committed value, is an Array as an\n // indicator that the previous value came from a repeat() call. If\n // oldParts is not an Array then this is the first render and we return\n // an array for lit-html's array handling to render, and remember the\n // keys.\n if (!Array.isArray(oldParts)) {\n this._itemKeys = newKeys;\n return newValues;\n }\n\n // In SSR hydration it's possible for oldParts to be an array but for us\n // to not have item keys because the update() hasn't run yet. We set the\n // keys to an empty array. This will cause all oldKey/newKey comparisons\n // to fail and execution to fall to the last nested brach below which\n // reuses the oldPart.\n const oldKeys = (this._itemKeys ??= []);\n\n // New part list will be built up as we go (either reused from\n // old parts or created for new keys in this update). This is\n // saved in the above cache at the end of the update.\n const newParts: ChildPart[] = [];\n\n // Maps from key to index for current and previous update; these\n // are generated lazily only when needed as a performance\n // optimization, since they are only required for multiple\n // non-contiguous changes in the list, which are less common.\n let newKeyToIndexMap!: Map<unknown, number>;\n let oldKeyToIndexMap!: Map<unknown, number>;\n\n // Head and tail pointers to old parts and new values\n let oldHead = 0;\n let oldTail = oldParts.length - 1;\n let newHead = 0;\n let newTail = newValues.length - 1;\n\n // Overview of O(n) reconciliation algorithm (general approach\n // based on ideas found in ivi, vue, snabbdom, etc.):\n //\n // * We start with the list of old parts and new values (and\n // arrays of their respective keys), head/tail pointers into\n // each, and we build up the new list of parts by updating\n // (and when needed, moving) old parts or creating new ones.\n // The initial scenario might look like this (for brevity of\n // the diagrams, the numbers in the array reflect keys\n // associated with the old parts or new values, although keys\n // and parts/values are actually stored in parallel arrays\n // indexed using the same head/tail pointers):\n //\n // oldHead v v oldTail\n // oldKeys: [0, 1, 2, 3, 4, 5, 6]\n // newParts: [ , , , , , , ]\n // newKeys: [0, 2, 1, 4, 3, 7, 6] <- reflects the user's new\n // item order\n // newHead ^ ^ newTail\n //\n // * Iterate old & new lists from both sides, updating,\n // swapping, or removing parts at the head/tail locations\n // until neither head nor tail can move.\n //\n // * Example below: keys at head pointers match, so update old\n // part 0 in-place (no need to move it) and record part 0 in\n // the `newParts` list. The last thing we do is advance the\n // `oldHead` and `newHead` pointers (will be reflected in the\n // next diagram).\n //\n // oldHead v v oldTail\n // oldKeys: [0, 1, 2, 3, 4, 5, 6]\n // newParts: [0, , , , , , ] <- heads matched: update 0\n // newKeys: [0, 2, 1, 4, 3, 7, 6] and advance both oldHead\n // & newHead\n // newHead ^ ^ newTail\n //\n // * Example below: head pointers don't match, but tail\n // pointers do, so update part 6 in place (no need to move\n // it), and record part 6 in the `newParts` list. Last,\n // advance the `oldTail` and `oldHead` pointers.\n //\n // oldHead v v oldTail\n // oldKeys: [0, 1, 2, 3, 4, 5, 6]\n // newParts: [0, , , , , , 6] <- tails matched: update 6\n // newKeys: [0, 2, 1, 4, 3, 7, 6] and advance both oldTail\n // & newTail\n // newHead ^ ^ newTail\n //\n // * If neither head nor tail match; next check if one of the\n // old head/tail items was removed. We first need to generate\n // the reverse map of new keys to index (`newKeyToIndexMap`),\n // which is done once lazily as a performance optimization,\n // since we only hit this case if multiple non-contiguous\n // changes were made. Note that for contiguous removal\n // anywhere in the list, the head and tails would advance\n // from either end and pass each other before we get to this\n // case and removals would be handled in the final while loop\n // without needing to generate the map.\n //\n // * Example below: The key at `oldTail` was removed (no longer\n // in the `newKeyToIndexMap`), so remove that part from the\n // DOM and advance just the `oldTail` pointer.\n //\n // oldHead v v oldTail\n // oldKeys: [0, 1, 2, 3, 4, 5, 6]\n // newParts: [0, , , , , , 6] <- 5 not in new map: remove\n // newKeys: [0, 2, 1, 4, 3, 7, 6] 5 and advance oldTail\n // newHead ^ ^ newTail\n //\n // * Once head and tail cannot move, any mismatches are due to\n // either new or moved items; if a new key is in the previous\n // \"old key to old index\" map, move the old part to the new\n // location, otherwise create and insert a new part. Note\n // that when moving an old part we null its position in the\n // oldParts array if it lies between the head and tail so we\n // know to skip it when the pointers get there.\n //\n // * Example below: neither head nor tail match, and neither\n // were removed; so find the `newHead` key in the\n // `oldKeyToIndexMap`, and move that old part's DOM into the\n // next head position (before `oldParts[oldHead]`). Last,\n // null the part in the `oldPart` array since it was\n // somewhere in the remaining oldParts still to be scanned\n // (between the head and tail pointers) so that we know to\n // skip that old part on future iterations.\n //\n // oldHead v v oldTail\n // oldKeys: [0, 1, -, 3, 4, 5, 6]\n // newParts: [0, 2, , , , , 6] <- stuck: update & move 2\n // newKeys: [0, 2, 1, 4, 3, 7, 6] into place and advance\n // newHead\n // newHead ^ ^ newTail\n //\n // * Note that for moves/insertions like the one above, a part\n // inserted at the head pointer is inserted before the\n // current `oldParts[oldHead]`, and a part inserted at the\n // tail pointer is inserted before `newParts[newTail+1]`. The\n // seeming asymmetry lies in the fact that new parts are\n // moved into place outside in, so to the right of the head\n // pointer are old parts, and to the right of the tail\n // pointer are new parts.\n //\n // * We always restart back from the top of the algorithm,\n // allowing matching and simple updates in place to\n // continue...\n //\n // * Example below: the head pointers once again match, so\n // simply update part 1 and record it in the `newParts`\n // array. Last, advance both head pointers.\n //\n // oldHead v v oldTail\n // oldKeys: [0, 1, -, 3, 4, 5, 6]\n // newParts: [0, 2, 1, , , , 6] <- heads matched: update 1\n // newKeys: [0, 2, 1, 4, 3, 7, 6] and advance both oldHead\n // & newHead\n // newHead ^ ^ newTail\n //\n // * As mentioned above, items that were moved as a result of\n // being stuck (the final else clause in the code below) are\n // marked with null, so we always advance old pointers over\n // these so we're comparing the next actual old value on\n // either end.\n //\n // * Example below: `oldHead` is null (already placed in\n // newParts), so advance `oldHead`.\n //\n // oldHead v v oldTail\n // oldKeys: [0, 1, -, 3, 4, 5, 6] <- old head already used:\n // newParts: [0, 2, 1, , , , 6] advance oldHead\n // newKeys: [0, 2, 1, 4, 3, 7, 6]\n // newHead ^ ^ newTail\n //\n // * Note it's not critical to mark old parts as null when they\n // are moved from head to tail or tail to head, since they\n // will be outside the pointer range and never visited again.\n //\n // * Example below: Here the old tail key matches the new head\n // key, so the part at the `oldTail` position and move its\n // DOM to the new head position (before `oldParts[oldHead]`).\n // Last, advance `oldTail` and `newHead` pointers.\n //\n // oldHead v v oldTail\n // oldKeys: [0, 1, -, 3, 4, 5, 6]\n // newParts: [0, 2, 1, 4, , , 6] <- old tail matches new\n // newKeys: [0, 2, 1, 4, 3, 7, 6] head: update & move 4,\n // advance oldTail & newHead\n // newHead ^ ^ newTail\n //\n // * Example below: Old and new head keys match, so update the\n // old head part in place, and advance the `oldHead` and\n // `newHead` pointers.\n //\n // oldHead v oldTail\n // oldKeys: [0, 1, -, 3, 4, 5, 6]\n // newParts: [0, 2, 1, 4, 3, ,6] <- heads match: update 3\n // newKeys: [0, 2, 1, 4, 3, 7, 6] and advance oldHead &\n // newHead\n // newHead ^ ^ newTail\n //\n // * Once the new or old pointers move past each other then all\n // we have left is additions (if old list exhausted) or\n // removals (if new list exhausted). Those are handled in the\n // final while loops at the end.\n //\n // * Example below: `oldHead` exceeded `oldTail`, so we're done\n // with the main loop. Create the remaining part and insert\n // it at the new head position, and the update is complete.\n //\n // (oldHead > oldTail)\n // oldKeys: [0, 1, -, 3, 4, 5, 6]\n // newParts: [0, 2, 1, 4, 3, 7 ,6] <- create and insert 7\n // newKeys: [0, 2, 1, 4, 3, 7, 6]\n // newHead ^ newTail\n //\n // * Note that the order of the if/else clauses is not\n // important to the algorithm, as long as the null checks\n // come first (to ensure we're always working on valid old\n // parts) and that the final else clause comes last (since\n // that's where the expensive moves occur). The order of\n // remaining clauses is just a simple guess at which cases\n // will be most common.\n //\n // * Note, we could calculate the longest\n // increasing subsequence (LIS) of old items in new position,\n // and only move those not in the LIS set. However that costs\n // O(nlogn) time and adds a bit more code, and only helps\n // make rare types of mutations require fewer moves. The\n // above handles removes, adds, reversal, swaps, and single\n // moves of contiguous items in linear time, in the minimum\n // number of moves. As the number of multiple moves where LIS\n // might help approaches a random shuffle, the LIS\n // optimization becomes less helpful, so it seems not worth\n // the code at this point. Could reconsider if a compelling\n // case arises.\n\n while (oldHead <= oldTail && newHead <= newTail) {\n if (oldParts[oldHead] === null) {\n // `null` means old part at head has already been used\n // below; skip\n oldHead++;\n } else if (oldParts[oldTail] === null) {\n // `null` means old part at tail has already been used\n // below; skip\n oldTail--;\n } else if (oldKeys[oldHead] === newKeys[newHead]) {\n // Old head matches new head; update in place\n newParts[newHead] = setChildPartValue(\n oldParts[oldHead]!,\n newValues[newHead]\n );\n oldHead++;\n newHead++;\n } else if (oldKeys[oldTail] === newKeys[newTail]) {\n // Old tail matches new tail; update in place\n newParts[newTail] = setChildPartValue(\n oldParts[oldTail]!,\n newValues[newTail]\n );\n oldTail--;\n newTail--;\n } else if (oldKeys[oldHead] === newKeys[newTail]) {\n // Old head matches new tail; update and move to new tail\n newParts[newTail] = setChildPartValue(\n oldParts[oldHead]!,\n newValues[newTail]\n );\n insertPart(containerPart, newParts[newTail + 1], oldParts[oldHead]!);\n oldHead++;\n newTail--;\n } else if (oldKeys[oldTail] === newKeys[newHead]) {\n // Old tail matches new head; update and move to new head\n newParts[newHead] = setChildPartValue(\n oldParts[oldTail]!,\n newValues[newHead]\n );\n insertPart(containerPart, oldParts[oldHead]!, oldParts[oldTail]!);\n oldTail--;\n newHead++;\n } else {\n if (newKeyToIndexMap === undefined) {\n // Lazily generate key-to-index maps, used for removals &\n // moves below\n newKeyToIndexMap = generateMap(newKeys, newHead, newTail);\n oldKeyToIndexMap = generateMap(oldKeys, oldHead, oldTail);\n }\n if (!newKeyToIndexMap.has(oldKeys[oldHead])) {\n // Old head is no longer in new list; remove\n removePart(oldParts[oldHead]!);\n oldHead++;\n } else if (!newKeyToIndexMap.has(oldKeys[oldTail])) {\n // Old tail is no longer in new list; remove\n removePart(oldParts[oldTail]!);\n oldTail--;\n } else {\n // Any mismatches at this point are due to additions or\n // moves; see if we have an old part we can reuse and move\n // into place\n const oldIndex = oldKeyToIndexMap.get(newKeys[newHead]);\n const oldPart = oldIndex !== undefined ? oldParts[oldIndex] : null;\n if (oldPart === null) {\n // No old part for this value; create a new one and\n // insert it\n const newPart = insertPart(containerPart, oldParts[oldHead]!);\n setChildPartValue(newPart, newValues[newHead]);\n newParts[newHead] = newPart;\n } else {\n // Reuse old part\n newParts[newHead] = setChildPartValue(oldPart, newValues[newHead]);\n insertPart(containerPart, oldParts[oldHead]!, oldPart);\n // This marks the old part as having been used, so that\n // it will be skipped in the first two checks above\n oldParts[oldIndex as number] = null;\n }\n newHead++;\n }\n }\n }\n // Add parts for any remaining new values\n while (newHead <= newTail) {\n // For all remaining additions, we insert before last new\n // tail, since old pointers are no longer valid\n const newPart = insertPart(containerPart, newParts[newTail + 1]);\n setChildPartValue(newPart, newValues[newHead]);\n newParts[newHead++] = newPart;\n }\n // Remove any remaining unused old parts\n while (oldHead <= oldTail) {\n const oldPart = oldParts[oldHead++];\n if (oldPart !== null) {\n removePart(oldPart);\n }\n }\n\n // Save order of new parts for next round\n this._itemKeys = newKeys;\n // Directly set part value, bypassing it's dirty-checking\n setCommittedValue(containerPart, newParts);\n return noChange;\n }\n}\n\nexport interface RepeatDirectiveFn {\n <T>(\n items: Iterable<T>,\n keyFnOrTemplate: KeyFn<T> | ItemTemplate<T>,\n template?: ItemTemplate<T>\n ): unknown;\n <T>(items: Iterable<T>, template: ItemTemplate<T>): unknown;\n <T>(\n items: Iterable<T>,\n keyFn: KeyFn<T> | ItemTemplate<T>,\n template: ItemTemplate<T>\n ): unknown;\n}\n\n/**\n * A directive that repeats a series of values (usually `TemplateResults`)\n * generated from an iterable, and updates those items efficiently when the\n * iterable changes based on user-provided `keys` associated with each item.\n *\n * Note that if a `keyFn` is provided, strict key-to-DOM mapping is maintained,\n * meaning previous DOM for a given key is moved into the new position if\n * needed, and DOM will never be reused with values for different keys (new DOM\n * will always be created for new keys). This is generally the most efficient\n * way to use `repeat` since it performs minimum unnecessary work for insertions\n * and removals.\n *\n * The `keyFn` takes two parameters, the item and its index, and returns a unique key value.\n *\n * ```js\n * html`\n * <ol>\n * ${repeat(this.items, (item) => item.id, (item, index) => {\n * return html`<li>${index}: ${item.name}</li>`;\n * })}\n * </ol>\n * `\n * ```\n *\n * **Important**: If providing a `keyFn`, keys *must* be unique for all items in a\n * given call to `repeat`. The behavior when two or more items have the same key\n * is undefined.\n *\n * If no `keyFn` is provided, this directive will perform similar to mapping\n * items to values, and DOM will be reused against potentially different items.\n */\nexport const repeat = directive(RepeatDirective) as RepeatDirectiveFn;\n\n/**\n * The type of the class that powers this directive. Necessary for naming the\n * directive's return type.\n */\nexport type {RepeatDirective};\n","import { createContext } from '@lit/context';\n\n/**\n * What each drop target currently holds, published by the drag-drop interaction.\n *\n * Today this is *derived* from the DOM in one place (`DragDropSlottedMixin`), replacing nine\n * separate `querySelectorAll` readbacks scattered across capacity checks, association counts and\n * response serialisation. It is the seam for the next step: once drop targets render their own\n * chips from this context, the map becomes authoritative and the DOM becomes derived from it.\n *\n * Provided by the `qti-*-interaction`, never by `qti-assessment-item` - interactions must work\n * standalone. Consumers read `this.ctx?.dragsByTarget?.[id] ?? []`.\n *\n * Reassign, never mutate: an in-place change does not notify consumers.\n */\nexport interface DragDropState {\n /**\n * Target identifier -> the drag identifiers it holds, in DOM order.\n * Matched with the interaction's `draggablesSelector`, which is what the response is built from.\n */\n readonly dragsByTarget: Readonly<Record<string, readonly string[]>>;\n\n /**\n * Target identifier -> how many chips it holds for capacity purposes.\n *\n * Deliberately *not* `dragsByTarget[id].length`. Capacity counts\n * `max(draggablesSelector matches, [qti-draggable] matches)`, because a dropped clone may not\n * match the interaction's structural selector (match-interaction's nested choices do; a bare\n * clone elsewhere may only carry the attribute). Response serialisation uses the selector\n * only. Collapsing the two would silently change `matchMax` behaviour.\n */\n readonly countByTarget: Readonly<Record<string, number>>;\n\n /**\n * Target identifier -> the chip nodes it holds, for targets that render their own chips.\n *\n * This is the authoritative half. A target that opts in (`acceptsDeclarativeDrops`) renders\n * `repeat(nodesByTarget[id])` into its own shadow root, and the interaction never appends into\n * it. The nodes are cloned **once, when the drop happens**, and the same node reference is\n * passed on every render -- Lit renders a `Node` by reference, so a stable node is moved, never\n * recreated. Cloning inside `render()` would mint a new element per update: focus loss,\n * restarted transitions, a half-built shadow root.\n *\n * Today it is still *derived* from the DOM alongside `dragsByTarget`. It becomes authoritative\n * when the first target opts in to rendering its own chips.\n */\n readonly nodesByTarget: Readonly<Record<string, readonly HTMLElement[]>>;\n}\n\nexport const dragDropContext = createContext<Readonly<DragDropState>>(Symbol('dragDropContext'));\n","import { css } from 'lit';\n\nimport { boxSizing, dropRegion } from '@qti-components/base';\n\nexport default [\n boxSizing,\n dropRegion,\n css`\n /*\n * 'align-items' / 'justify-content' are variables because one caller cannot be reached any other\n * way. In tabular match this element is a light-DOM *grandchild* of the slotted\n * <qti-simple-match-set>, so no selector in the interaction's shadow root reaches it —\n * '::slotted()' takes no descendants — and the element itself cannot tell it is in a tabular\n * match. The theme sets the two properties on the match-set and they inherit down; the box model\n * stays here. Defaults are the flex initial values, so every other caller is unaffected.\n */\n :host {\n display: flex;\n align-items: var(--qti-choice-align-items, normal);\n justify-content: var(--qti-choice-justify-content, normal);\n user-select: none;\n }\n\n /*\n * This element plays two parts. In associate-interaction and in match's first match-set it is a\n * draggable chip; in match's last match-set it is a drop target. In tabular match it is neither —\n * drag-drop is off and it is a row or column header in a grid.\n *\n * So the drop-target rules key on :state(droppable), which the interaction sets on exactly the\n * elements it tracks as droppables. Keying on the *absence* of a chip marker instead\n * (:not(:state(drag))) swept up every tabular header cell and gave each one a 4rem minimum.\n *\n * A state rather than an attribute, and this used to be written both ways. An attribute cannot\n * be used by every host: the editor renders these choices inside a ProseMirror document, whose\n * mutation observer reverts any attribute outside the schema — and the revert re-triggers the\n * observer that wrote it, which hard-freezes the tab. ElementInternals states are invisible to\n * that observer, so the state is the form that works everywhere and the [qti-droppable]\n * attribute that used to accompany it is gone. Positive opt-in, so tabular headers are untouched.\n */\n :host(:state(droppable)) {\n /*\n * The CARD token, not the slot one. This element is a droppable only in match, and match\n * publishes no measurement — so reading --qti-dropzone-min-height here meant reading a name\n * whose whole purpose is to carry a measurement that never arrives, and relying on the 4rem\n * fallback to be the real value. That held only while the slot name stayed undeclared: the\n * moment it was declared at 3rem the fallback became unreachable and every card silently lost\n * 16px, with no rule mentioning cards anywhere in the diff.\n *\n * The width stays on the slot name. It is still 0 when unmeasured — a card is as wide as its\n * grid track gives it, and the track has its own floor (--qti-drop-track-min-width).\n */\n min-height: var(--qti-drop-card-min-height, 4rem);\n min-width: var(--qti-dropzone-min-width, 0);\n\n /*\n * A target is a card: label pinned to the top, drop region filling the rest. Was\n * 'display: flex; flex-direction: column; justify-content: space-between' in the theme's\n * match-interaction rules, on a light-DOM grandchild it reached by descendant selector.\n * A 'grid-row: unset' went with it — the initial value, on an element whose grid placement\n * nothing sets.\n */\n flex-direction: column;\n justify-content: space-between;\n }\n\n :host(:state(droppable)) [part~='drop'] {\n /*\n * Match's dropzones are NOT auto-sized from the chips: a match target is a category, and\n * should look able to hold several answers rather than hugging the widest one. So this reads\n * the card's OWN token rather than the measured one — qti-match-interaction publishes no\n * measurement, and a name that exists to carry one is the wrong place to keep a constant.\n * A theme retunes every card by setting --qti-drop-card-min-height.\n *\n * Deliberately NOT conditional on this target's own match-max. Whether a drop is a category or\n * a slot is a property of the interaction, not of one target: a match-max=\"1\" target is still a\n * category that happens to take one answer, and it sits in a grid beside targets that take\n * several. Sizing each to its own contents would make that grid ragged. qti-match-interaction\n * turns measurement off for the whole interaction for the same reason.\n */\n min-height: var(--qti-drop-card-min-height, 4rem);\n\n /*\n * A card has room in it, so its contents sit inside a margin rather than against the edge, and\n * two answers in the same card do not touch. The one drop in the library that wants either.\n *\n * Declared, not routed through a token. A slot-shaped drop wants neither (dropRegion), and a\n * theme retunes these by reaching the same element with ::part(drop) from the document — so a\n * custom property in between would add a name without adding reach.\n */\n padding: 0.25rem;\n gap: 0.25rem;\n\n /*\n * The one place a drop centres its chips rather than packing them to the start, overriding\n * dropRegion. A match target is a category card with room to spare, so chips sitting in the\n * middle of it reads as deliberate where a lone chip pinned to the top-left reads as broken.\n * Centring positions without resizing — 'align-items: center' suppresses the stretch just as\n * 'flex-start' does — so the chip-is-the-same-chip invariant holds either way.\n */\n justify-content: center;\n align-items: center;\n flex-grow: 1;\n }\n\n /* The label sits against the drop region below it. */\n :host(:state(droppable)) [part~='label'] {\n align-content: flex-end;\n }\n\n /*\n * A chip has no drop region. It renders one anyway — same element, both parts — and an empty\n * region with a minimum height made every placed chip 20px taller than the same chip in the\n * bank. The <slot> this replaced collapsed to nothing by accident; a div has to be told.\n *\n * Two conditions, because a chip identifies itself two ways:\n * :state(drag) a chip in the light-DOM bank, from the interaction's draggablesSelector\n * [part~='drag'] a chip a drop target renders, where that selector cannot reach it — match's\n * selector names a light-DOM ancestry the placed clone no longer has\n */\n :host(:state(drag)) [part~='drop'],\n :host([part~='drag']) [part~='drop'] {\n display: none;\n }\n\n /*\n * The label's box type is a variable for the same reason as the two above: only the interaction\n * knows which arrangement it is running. Non-tabular match wants an inline label so a chip hugs\n * its text; everywhere else the label is a block that fills the choice. The theme spent an\n * 'display: inline !important' on ::part(label) to say so, from the document.\n */\n slot {\n width: 100%;\n display: var(--qti-choice-label-display, block);\n }\n\n slot[name='qti-simple-associable-choice'] {\n width: auto;\n }\n\n /* Author markup inside a chip runs inline — a <p> would otherwise break the chip onto its own\n line. The theme keeps the matching 'margin: 0', which is spacing. */\n ::slotted(p) {\n display: inline;\n }\n `\n];\n","import { html, LitElement } from 'lit';\nimport { property, state } from 'lit/decorators.js';\nimport { repeat } from 'lit/directives/repeat.js';\nimport { consume } from '@lit/context';\n\nimport { dragDropContext } from '../../context/drag-drop.context';\nimport { ActiveElementMixin } from '../../mixins/active-element/active-element.mixin';\nimport styles from './qti-simple-associable-choice.styles';\n\nimport type { DragDropState } from '../../context/drag-drop.context';\nimport type { CSSResultGroup } from 'lit';\n\n/**\n * A choice in one of the two match sets of `qti-match-interaction`, or in\n * `qti-associate-interaction`.\n *\n * @customElement qti-simple-associable-choice\n *\n * @attr {string} identifier - Required. Value recorded in the response pair when this choice\n * participates in an association.\n * @attr {number} [match-max=1] - How many associations this choice may take part in; `0` means\n * unlimited. On a target this is its capacity — the bucket size in a sorting item.\n * @attr {number} [match-min=0] - Minimum associations this choice must take part in.\n * @attr {boolean} [fixed=false] - Pins this choice in place when the enclosing interaction is\n * shuffled.\n * @attr {string} template-identifier - Not implemented. Identifier of a template variable\n * controlling this choice's visibility.\n * @attr {'show'|'hide'} [show-hide=show] - Not implemented. How `template-identifier` controls\n * visibility.\n */\n// tslint:disable: indent\nexport class QtiSimpleAssociableChoice extends ActiveElementMixin(LitElement, 'qti-simple-associable-choice') {\n static override styles: CSSResultGroup = styles;\n\n /** the minimal number of selections a candidate must make */\n @property({\n type: Number,\n attribute: 'match-min'\n })\n public matchMin: number = 0;\n\n /** the maximum number of selections a candidate must make, the other options will be disabled when max options is checked */\n @property({\n type: Number,\n attribute: 'match-max'\n })\n public matchMax: number = 1;\n\n @property({\n type: String,\n attribute: 'fixed',\n converter: {\n fromAttribute: (value: string | null) => value === 'true',\n toAttribute: (value: boolean) => String(value)\n }\n })\n public fixed: boolean = false;\n\n // pk: This needs some explanation\n // in the associate interaction there is a special slot for these qti-simple-associable-choices\n override connectedCallback(): void {\n super.connectedCallback();\n this.setAttribute('slot', 'qti-simple-associable-choice');\n // `part=\"qti-simple-associable-choice\"` used to be stamped here — a part named after the tag,\n // and one that clobbered the `part=\"drag\"` the mixin puts on a clone the moment the clone\n // connected. The theme reaches a placed chip as `::part(drag)` now.\n }\n\n /** Opt-in marker read by `DragDropSlottedMixin`; see qti-gap. */\n public readonly acceptsDeclarativeDrops = true;\n\n @consume({ context: dragDropContext, subscribe: true })\n @state()\n private _dragDrop?: Readonly<DragDropState>;\n\n /** The chips this choice holds when it acts as a drop target (match-interaction's second set). */\n public get drags(): readonly HTMLElement[] {\n return this._dragDrop?.nodesByTarget?.[this.identifier] ?? [];\n }\n\n // pk: This needs some explanation\n // in qti-match-interaction, qti-simple-associable-choice is used to denote the\n // draggable, but also the droppable. WEIRD.. but lets deal with it.\n // So we have a slot for whenever another qti-simple-associable-choice is dropped in here.\n // And we have slot for content like in this associate interaction\n override render() {\n // The same element is a drag source in one match set and a drop target in the other. As a\n // source it holds nothing and this region stays empty.\n return html`\n <div part=\"control\"></div>\n <slot part=\"label\"></slot>\n <div part=\"drop\">\n ${repeat(\n this.drags,\n node => node.getAttribute('identifier'),\n node => node\n )}\n </div>\n `;\n }\n}\n\ndeclare global {\n interface HTMLElementTagNameMap {\n 'qti-simple-associable-choice': QtiSimpleAssociableChoice;\n }\n}\n","import { css } from 'lit';\n\nimport { boxSizing } from '@qti-components/base';\n\nexport default [\n boxSizing,\n css`\n /*\n * 'position: relative' unconditionally, because this element can carry a correction badge and a\n * badge needs a containing block. The theme draws the badge as an absolutely positioned ::after\n * and used to declare the containing block too — from the document, and only for the\n * .qti-input-control-hidden variant, so the anchor and the thing anchored to it were set in two\n * different stylesheets. See CONTRACT.md §7.\n */\n :host {\n display: flex;\n align-items: center;\n position: relative;\n user-select: none;\n }\n /*\n * The label's box type is a variable because only the interaction knows the arrangement.\n * choice-interaction wants an inline label so a choice hugs its text; order-interaction uses\n * this same element as a chip and wants the flex default. The theme said so with an\n * '::part(label) { display: inline !important }'.\n */\n slot {\n width: 100%;\n display: var(--qti-choice-label-display, flex);\n align-items: center;\n }\n /*\n * The variant that hides the native control ('.qti-input-control-hidden') is a presentation\n * class only the interaction sees, on a box only this file can lay out. The theme sets the\n * variable; the property stays here.\n */\n [part='control'] {\n display: var(--qti-control-display, flex);\n flex-shrink: 0;\n align-items: center;\n justify-content: center;\n }\n `\n];\n","import { css, html, LitElement, nothing } from 'lit';\nimport { property } from 'lit/decorators.js';\n\nimport { ActiveElementMixin } from '../../mixins/active-element/active-element.mixin';\nimport styles from './qti-simple-choice.styles';\n\nimport type { CSSResultGroup } from 'lit';\n\n/**\n * A choice, used by `qti-choice-interaction` and `qti-order-interaction`.\n *\n * The `control` part is one box whose *role* is carried by state, not by its name: a radio\n * circle under `:state(radio)`, a checkbox square under `:state(checkbox)`, and a drag grip\n * when the choice is draggable. Style it as `qti-simple-choice::part(control)`.\n *\n * @customElement qti-simple-choice\n *\n * @attr {string} identifier - Required. Value recorded in the response when this choice is\n * selected, or its position when used for ordering.\n * @attr {boolean} [fixed=false] - Pins this choice in place when the enclosing interaction is\n * shuffled.\n * @attr {string} template-identifier - Identifier of a template variable controlling this\n * choice's visibility.\n * @attr {'show'|'hide'} [show-hide=show] - How `template-identifier` controls visibility.\n *\n * @csspart control - The box before the label (radio / checkbox / drag grip).\n * @csspart control-mark - The mark inside the box (inner dot / checkmark).\n * @csspart label - The default slot holding the choice content.\n * @csspart marker - The order-number badge, when `marker` is set.\n */\nexport class QtiSimpleChoice extends ActiveElementMixin(LitElement, 'qti-simple-choice') {\n static override styles: CSSResultGroup = styles;\n\n static override shadowRootOptions: ShadowRootInit = {\n ...LitElement.shadowRootOptions,\n delegatesFocus: true\n };\n\n @property({ type: String, attribute: 'template-identifier' })\n public templateIdentifier: string | null = null;\n\n @property({ type: String, attribute: 'show-hide' })\n public showHide: string | null = 'show';\n\n @property({\n type: Boolean,\n converter: {\n fromAttribute: (value: string | null) => value === 'true',\n toAttribute: (value: boolean) => String(value)\n }\n })\n public fixed: boolean = false;\n\n // property label\n @property({ type: String, attribute: false })\n public marker: string;\n\n get checked() {\n return this['internals'].states.has('checked');\n }\n\n override render() {\n return html`<div part=\"control\" tabindex=\"0\"><div part=\"control-mark\"></div></div>\n ${this.marker ? html`<div id=\"label\" part=\"marker\">${this.marker}</div>` : nothing}\n <slot part=\"label\"></slot>`;\n }\n}\n\ndeclare global {\n interface HTMLElementTagNameMap {\n 'qti-simple-choice': QtiSimpleChoice;\n }\n}\n","import { property } from 'lit/decorators.js';\n\nimport type { LitElement } from 'lit';\n\ntype Constructor<T = {}> = abstract new (...args: any[]) => T;\n\n/**\n * Measure the chips and publish the result as `--qti-dropzone-min-height` / `--qti-dropzone-min-width`.\n *\n * Lives here rather than in `drag-drop.utils` because this mixin is its only caller, and because\n * keeping it here is what makes the mixin an abstraction rather than a wiring layer: EVERYTHING that\n * knows how a dropzone gets its size is in this file, and the rest of the library knows only the two\n * custom properties. Drop the mixin from an interaction and its drops fall back to the theme's\n * declared defaults — see the note on both names in qti-variables.css — so nothing breaks and an\n * author can set the two properties by hand to size the drops themselves.\n *\n * JavaScript owns the *measurement*; CSS owns the *properties*. Each droppable's stylesheet reads\n * `min-height: var(--qti-dropzone-min-height)`, so nothing is written to a droppable's `style` and a\n * theme overrides by setting the variable closer.\n *\n * That also removes a precedence trap: when both `min-width` and `width` were written inline,\n * `min-width` silently won, discarding an authored `data-choices-container-width`.\n *\n * Exported for its spec only — the folder's `index.ts` names just the mixin, so this does not reach\n * the package's public surface.\n */\nexport function applyDropzoneAutoSizing(\n host: HTMLElement,\n draggables: HTMLElement[],\n droppables: HTMLElement[],\n dragContainers: HTMLElement[],\n options: {\n hostWindow?: Window | null;\n /**\n * Called with the measurement before anything is written; return false to skip the write. The\n * mixin uses it to suppress a no-op write, which is what keeps its `ResizeObserver` from feeding\n * itself.\n */\n hasChanged?: (measured: { height: number; width: number }) => boolean;\n /**\n * Publish the measured width. False when something else owns that axis — an authored\n * `data-choices-container-width` — in which case the height is still measured and published and\n * the width is simply never written.\n *\n * Not writing is deliberate, and replaces a \"write then undo\" arrangement that had the caller\n * zero the property afterwards. That only held while this ran exactly once and wrote to exactly\n * one element; re-measurement and a second write target each broke it independently.\n */\n publishWidth?: boolean;\n } = {}\n): void {\n const publishWidth = options.publishWidth ?? true;\n const hostWindow = options.hostWindow ?? (typeof window !== 'undefined' ? window : null);\n if (!draggables.length || !droppables.length || !hostWindow) return;\n\n let maxDraggableHeight = 0;\n let maxDraggableWidth = 0;\n\n /*\n * Measure each chip at its INTRINSIC width, with any minimum this pass previously gave it\n * neutralised — otherwise the measurement reads its own output and the result is a one-way ratchet.\n *\n * `@mixin drag` gives a chip `min-width: var(--qti-dropzone-min-width)`, which is what makes a chip\n * and its slot the same size. It also means that once the widest chip has set the reservation,\n * every chip is at least that wide — so shortening the longest one can never bring the number back\n * down. Measured: a chip edited from 191px of text back to 106px left the reservation at 191px\n * forever, and with it every chip and every drop.\n *\n * Growing was never the problem; not being able to shrink was. Nothing paints between the\n * neutralise and the restore, so this is invisible.\n *\n * The neutralise goes on the SLOT — never as an inline `min-width` on each chip, and never on the\n * host — and that is load-bearing under ProseMirror. A chip is a light-DOM node the editor's\n * document owns, and ProseMirror's DOMObserver runs with `attributes: true` over its subtree: a\n * `style` attribute it did not author marks the node dirty, it re-renders from the doc, and the\n * re-render re-triggers whatever measured. That loop freezes the tab. Pointing\n * `dropzonePropertyTarget()` at a shadow node is not enough on its own, because that only moves\n * where the RESULT lands, not where the measurement pokes.\n *\n * A slot is always inside the shadow root and is the chips' parent in the flat tree, so setting the\n * property to 0 there reaches exactly the chips being measured, by the same inheritance that\n * delivers the reservation itself — `@mixin drag` is the only rule that gives a chip a min-width,\n * it reads exactly this property, and nothing sets it closer. `MenuAutoSizeMixin` writes to a\n * shadow node for the same reason; this is that rule applied to the measurement, not just the\n * result.\n *\n * `dragContainers` is the slot list the caller already collected (and already writes a min-height\n * to). With none supplied there is nothing between here and the chips, so fall back to the target.\n */\n const neutraliseOn: HTMLElement[] = dragContainers.length ? dragContainers : [host];\n const restore = neutraliseOn.map(el => ({\n el,\n reservation: el.style.getPropertyValue('--qti-drag-min-width'),\n hadStyleAttribute: el.hasAttribute('style')\n }));\n // --qti-drag-min-width, because that is the name `@mixin drag` reads. Zeroing the dropzone name\n // here would leave the chips at whatever the theme's default gives them and measure that instead.\n neutraliseOn.forEach(el => el.style.setProperty('--qti-drag-min-width', '0px'));\n\n draggables.forEach(draggable => {\n const rect = draggable.getBoundingClientRect();\n maxDraggableHeight = Math.max(maxDraggableHeight, rect.height);\n maxDraggableWidth = Math.max(maxDraggableWidth, rect.width);\n });\n\n /*\n * Put it back before the early return below, so a pass that changes nothing leaves no trace.\n *\n * \"No trace\" includes the attribute itself: removing the last property off `style` leaves an empty\n * `style=\"\"` behind, and an empty attribute is still an attribute — still a mutation record for\n * ProseMirror, and still a broken invariant for the spec that asserts a skipped pass writes\n * nothing at all.\n */\n restore.forEach(({ el, reservation, hadStyleAttribute }) => {\n if (reservation) el.style.setProperty('--qti-drag-min-width', reservation);\n else el.style.removeProperty('--qti-drag-min-width');\n if (!hadStyleAttribute && el.getAttribute('style') === '') el.removeAttribute('style');\n });\n\n if (options.hasChanged?.({ height: maxDraggableHeight, width: maxDraggableWidth }) === false) return;\n\n /*\n * Measured values go on `host` as custom properties; each droppable's own stylesheet reads them.\n *\n * `host` is not necessarily the interaction: custom properties inherit down the flat tree, so any\n * ancestor of the drops will do, and a host whose own attributes are policed (the editor, under\n * ProseMirror) passes a node inside its shadow root instead.\n *\n * Both axes, for every dropzone. `--qti-dropzone-min-width` used to reach only gaps and the match\n * grid, so order's and associate's drops were tall enough for the largest chip but not wide enough\n * for it, and a drop grew sideways the moment one landed.\n */\n host.style.setProperty('--qti-dropzone-min-height', `${maxDraggableHeight}px`);\n if (publishWidth) {\n // Both width names get the same measured value. They exist as two names only so their\n // UNMEASURED defaults can differ — a chip keeps its natural width, a drops-grid track must not\n // collapse — and writing both here is what keeps a chip the same size as its slot.\n host.style.setProperty('--qti-dropzone-min-width', `${maxDraggableWidth}px`);\n host.style.setProperty('--qti-drag-min-width', `${maxDraggableWidth}px`);\n }\n\n dragContainers.forEach(dragContainer => {\n dragContainer.style.minHeight = `var(--qti-drag-container-min-height, ${maxDraggableHeight}px)`;\n\n /*\n * The reservation lands here as well, and that is what lets a host keep every write inside its\n * shadow root.\n *\n * A chip reads `--qti-dropzone-min-width` (`@mixin drag`) and its parent in the flat tree is this\n * slot, so publishing here reaches the chips without needing an ancestor that also contains the\n * drops. gap-match and associate have no such ancestor — their drags slot and their drops are\n * siblings under the shadow root — so before this they had to publish on the interaction host to\n * reach both, which is a light-DOM node the editor's ProseMirror document owns. Now they point\n * `dropzonePropertyTarget()` at the DROPS and the chips are still covered from here.\n *\n * In the runtime nothing changes: the value is the same one the host publishes, so a chip that\n * used to inherit it from the host now inherits the identical value from a closer element.\n */\n dragContainer.style.setProperty('--qti-dropzone-min-height', `${maxDraggableHeight}px`);\n if (publishWidth) {\n dragContainer.style.setProperty('--qti-dropzone-min-width', `${maxDraggableWidth}px`);\n dragContainer.style.setProperty('--qti-drag-min-width', `${maxDraggableWidth}px`);\n }\n });\n}\n\n/** The elements a measurement pass looks at. */\nexport interface DropzoneAutoSizeTargets {\n /** Measured. The largest of these decides the reservation. */\n draggables: HTMLElement[];\n /** Not measured — only their presence gates the pass (nothing to reserve for, nothing to do). */\n droppables: HTMLElement[];\n /** The chip banks, which get a matching `min-height` so an emptied bank does not collapse. */\n dragContainers: HTMLElement[];\n}\n\nexport type DropzoneAutoSize = LitElement & {\n autoSizeDropzones: boolean;\n /**\n * False when something else owns the width axis — see the class below.\n *\n * Declared as an accessor, not a `readonly` property. The class implements it as a getter and\n * `DragDropSlottedMixin` overrides it with another getter; a property here makes that override a\n * TS2611 (\"defined as a property in the base, overridden as an accessor\").\n */\n get autoSizeDropzoneWidth(): boolean;\n updateMinDimensionsForDropZones(): void;\n /** Overridable hooks — see the class below. Public because a subclass has to be able to say\n * `override`, which the house style already does for `afterCache` and `isDragDropEnabled`. */\n collectAutoSizeTargets(): DropzoneAutoSizeTargets;\n dropzonePropertyTarget(): HTMLElement;\n};\n\n/**\n * Publishes `--qti-dropzone-min-height` / `--qti-dropzone-min-width` from the measured chips, and\n * keeps them up to date as the chips change size.\n *\n * ── Why this is a mixin of its own ───────────────────────────────────────────────────────────\n *\n * It used to be two members of `DragDropSlottedMixin`, reachable only by inheriting the whole\n * drag-drop stack. The editor needs exactly this and none of the rest: it renders the same\n * elements, imports the same stylesheets — so its drops already read\n * `min-height: var(--qti-dropzone-min-height, 0)` — but it does its own drag handling inside a\n * ProseMirror document. Splitting the measurement out means both sides run the same code instead of\n * the editor growing a parallel copy that drifts.\n *\n * ── When it runs ─────────────────────────────────────────────────────────────────────────────\n *\n * On mount, and then whenever a chip changes size. The second half is new: the only trigger used to\n * be `connectedCallback → setupDragDrop → afterCache`, so a chip that changed size after first paint\n * never re-measured and its drop stayed the wrong size. That bites an author typing into a chip in\n * the editor, and it bites a delivered item too — a late-loading image or a web-font swap does the\n * same thing.\n *\n * A `ResizeObserver` over the chips is the trigger, because it catches all three causes (text\n * reflow, image load, font swap) in one mechanism. A `MutationObserver` would need\n * `characterData: true` and would still miss the image. The dead legacy mixin at\n * `mixins/drag-drop/drag-drop-interaction-mixin.ts` used both and still caught neither reliably.\n *\n * ── Where the properties land ────────────────────────────────────────────────────────────────\n *\n * On `dropzonePropertyTarget()`, which defaults to the host. Custom properties inherit down the flat\n * tree, so any element that is an ancestor of the drops works — and the editor needs that, because\n * writing `style` on a ProseMirror-managed host is reverted by its mutation observer, and the revert\n * re-triggers the observer that wrote it. There it returns a node inside the shadow root instead,\n * which a mutation observer on the document cannot see.\n */\nexport const DropzoneAutoSizeMixin = <T extends Constructor<LitElement>>(\n superClass: T,\n draggablesSelector: string,\n droppablesSelector: string,\n dragContainersSelector = 'slot[part=\"drags\"]'\n) => {\n abstract class DropzoneAutoSizeElement extends superClass {\n @property({ type: Boolean, attribute: 'auto-size-dropzones' })\n /**\n * Size the dropzones from the chips they will hold.\n *\n * On by default: a drop that is already as big as the largest chip does not resize when one\n * lands in it — the invariant `drag-drop.invariance.spec.ts` calls \"an empty drop is already the\n * size of the chip it will hold\". With it off, a dropzone falls back to whatever floor its own\n * stylesheet declares.\n */\n public autoSizeDropzones = true;\n\n /**\n * Size the dropzones' WIDTH from the chips. Separate from `autoSizeDropzones` because the two\n * axes can have different owners: `data-choices-container-width` is an explicit authoring\n * instruction about width alone, and the height should still be measured under it.\n *\n * A subclass that overrides this to false gets no `--qti-dropzone-min-width` written at all —\n * rather than one written and then zeroed by whoever runs next. That distinction is the point.\n * The old arrangement held only while this pass ran exactly once, and wrote to exactly one\n * element; re-measurement broke the first assumption and publishing on the drag containers\n * broke the second, each time by silently discarding the authored width.\n */\n public get autoSizeDropzoneWidth(): boolean {\n return true;\n }\n\n #resizeObserver: ResizeObserver | null = null;\n #observed = new Set<Element>();\n #contentObserver: MutationObserver | null = null;\n #pendingFrame = 0;\n /**\n * The last values written, so a measurement that changed nothing writes nothing.\n *\n * Without this the observer feeds itself: setting a min-height changes layout, layout change\n * fires the observer, and the browser reports `ResizeObserver loop limit exceeded`. The editor\n * has a note about a chatty observer causing exactly this in tabular match.\n */\n #lastWritten: { height: number; width: number } | null = null;\n\n /**\n * The elements to measure. Overridden by a host that already tracks them — the drag-drop stack\n * caches these on every `cacheInteractiveElements()`, and re-querying would be a second, slightly\n * different answer to the same question.\n */\n public collectAutoSizeTargets(): DropzoneAutoSizeTargets {\n const collect = (selector: string, scope: ParentNode | null | undefined): HTMLElement[] =>\n Array.from(scope?.querySelectorAll<HTMLElement>(selector) ?? []);\n\n return {\n draggables: [...collect(draggablesSelector, this), ...collect(draggablesSelector, this.shadowRoot)],\n droppables: [...collect(droppablesSelector, this), ...collect(droppablesSelector, this.shadowRoot)],\n dragContainers: [...collect(dragContainersSelector, this), ...collect(dragContainersSelector, this.shadowRoot)]\n };\n }\n\n /**\n * Where the measured custom properties are written. The host, unless a subclass says otherwise —\n * see the note on ProseMirror in this file's header.\n */\n public dropzonePropertyTarget(): HTMLElement {\n return this;\n }\n\n public updateMinDimensionsForDropZones(): void {\n if (!this.autoSizeDropzones) return;\n\n const { draggables, droppables, dragContainers } = this.collectAutoSizeTargets();\n if (draggables.length === 0) return;\n\n applyDropzoneAutoSizing(this.dropzonePropertyTarget(), draggables, droppables, dragContainers, {\n publishWidth: this.autoSizeDropzoneWidth,\n hasChanged: measured => {\n const last = this.#lastWritten;\n if (last && last.height === measured.height && last.width === measured.width) return false;\n this.#lastWritten = measured;\n return true;\n }\n });\n\n this.#observeDraggables(draggables);\n this.#observeContent();\n }\n\n /**\n * Re-measure when the CHIPS THEMSELVES change — one added, removed, or its text edited.\n *\n * The ResizeObserver below cannot see any of that. It only knows the chips it was handed on the\n * last pass, so a chip that did not exist then is not observed, and nothing brings it to\n * attention. In a delivered item that barely matters — the set is fixed by the markup. In an\n * editor it is the normal case: an author adds a drag by pressing Enter, and types into it.\n *\n * `characterData` and `subtree` as well as `childList`, so editing the text of an existing chip\n * counts and not only adding one.\n *\n * This cannot feed itself: it observes the light DOM under this element, and the measurements\n * are written to `dropzonePropertyTarget()` — the host's own style in the runtime, a shadow node\n * in the editor. A MutationObserver does not cross into a shadow root, and a host's `style`\n * attribute is not in its own observed subtree.\n *\n * Coalesced to one measurement per frame: both observers can fire for the same edit, and a\n * measurement forces layout.\n *\n * Caveat worth knowing: this measures whatever `collectAutoSizeTargets()` returns. The drag-drop\n * stack overrides that with its cached lists, which a bare DOM insertion does not refresh — so\n * there a brand-new chip is measured on the next pass that re-caches, not on this one. A host\n * using the default, query-based implementation (the editor) always sees the current DOM.\n */\n #observeContent(): void {\n if (typeof MutationObserver === 'undefined' || this.#contentObserver) return;\n\n this.#contentObserver = new MutationObserver(() => this.#scheduleMeasure());\n this.#contentObserver.observe(this, { childList: true, subtree: true, characterData: true });\n }\n\n #scheduleMeasure(): void {\n if (this.#pendingFrame) return;\n this.#pendingFrame = requestAnimationFrame(() => {\n this.#pendingFrame = 0;\n this.updateMinDimensionsForDropZones();\n });\n }\n\n /**\n * Watch the chips, not the drops. A drop's size is downstream of a chip's, so observing drops\n * would be observing this mixin's own output — the loop the `#lastWritten` guard also defends.\n */\n #observeDraggables(draggables: HTMLElement[]): void {\n if (typeof ResizeObserver === 'undefined') return;\n\n this.#resizeObserver ??= new ResizeObserver(() => this.#scheduleMeasure());\n\n const next = new Set<Element>(draggables);\n for (const el of this.#observed) {\n if (!next.has(el)) this.#resizeObserver.unobserve(el);\n }\n for (const el of next) {\n if (!this.#observed.has(el)) this.#resizeObserver.observe(el);\n }\n this.#observed = next;\n }\n\n public override disconnectedCallback(): void {\n this.#resizeObserver?.disconnect();\n this.#resizeObserver = null;\n this.#observed.clear();\n this.#contentObserver?.disconnect();\n this.#contentObserver = null;\n if (this.#pendingFrame) cancelAnimationFrame(this.#pendingFrame);\n this.#pendingFrame = 0;\n // Not the written values: a re-connected element re-measures anyway, and clearing them would\n // only make the first pass after a move write properties that are already correct.\n super.disconnectedCallback();\n }\n }\n\n return DropzoneAutoSizeElement as Constructor<DropzoneAutoSize> & T;\n};\n","// getting a reference of some used global objects as globalThis is getting undefined when a iframe is removed\nconst { AbortController, AbortSignal, WeakMap, WeakRef, Window, reportError = console.log } = globalThis;\n\n// https://html.spec.whatwg.org/multipage/document-sequences.html#fully-active\n// A Document d is said to be fully active when d is the active document of\n// a navigable navigable, and either navigable is a top-level traversable or\n// navigable's container document is fully active.\nconst isDocumentFullyActive = (d) => d && d.defaultView !== null && d.defaultView.document === d && (d.defaultView.top === d.defaultView || isDocumentFullyActive(d.defaultView.parent.document));\n\n// check if we run in a browser\nconst isBrowserContext = () => !!Window && globalThis instanceof Window;\n\nconst unset = Symbol(\"unset\");\n\nconst [Observable, Subscriber] = (() => {\n function enumerate(obj, key, enumerable = true) {\n Object.defineProperty(obj, key, {\n ...Object.getOwnPropertyDescriptor(obj, key),\n enumerable,\n });\n }\n\n const pTry = \"try\" in Promise ? Promise.try.bind(Promise) : (fn, ...args) => new Promise((r) => r(fn(...args)));\n\n const pWithResolvers = 'withResolvers' in Promise ? Promise.withResolvers.bind(Promise) : () => {\n let resolve, reject;\n const promise = new Promise((res, rej) => ((resolve = res), (reject = rej)));\n return { promise, resolve, reject };\n };\n\n function getIteratorFromMethod(obj, method) {\n // 1. Let iterator be ? Call(method, obj).\n const iterator = method.call(obj);\n // 2. If iterator is not an Object, throw a TypeError exception.\n if (iterator === null || typeof iterator !== \"object\") throw new TypeError(\"Iterator is not an object\");\n // 3. Return ? GetIteratorDirect(iterator)\n return iterator;\n }\n\n const privateState = new WeakMap();\n\n const AsyncFromSyncIteratorPrototype = {\n next(...args) {\n // 1. Let O be the this value.\n const O = this;\n // 2. Assert: O is an Object that has a [[SyncIteratorRecord]] internal slot.\n const state = privateState.get(O);\n if (!state?.syncIteratorRecord)\n throw new TypeError(\n \"AsyncFromSyncIteratorPrototype.next called on invalid object\"\n );\n // 4. Let syncIteratorRecord be O.[[SyncIteratorRecord]].\n const { syncIteratorRecord } = state;\n return pTry(() => syncIteratorRecord.next(...args));\n },\n return(...args) {\n // 1. Let O be the this value.\n const O = this;\n // 2. Assert: O is an Object that has a [[SyncIteratorRecord]] internal slot.\n const state = privateState.get(O);\n if (!state?.syncIteratorRecord)\n throw new TypeError(\n \"AsyncFromSyncIteratorPrototype.return called on invalid object\"\n );\n // 4. Let syncIteratorRecord be O.[[SyncIteratorRecord]].\n const { syncIteratorRecord } = state;\n return pTry(() => {\n if (!syncIteratorRecord.return) return { value: undefined, done: true };\n return syncIteratorRecord.return(...args);\n });\n },\n throw(...args) {\n // 1. Let O be the this value.\n const O = this;\n // 2. Assert: O is an Object that has a [[SyncIteratorRecord]] internal slot.\n const state = privateState.get(O);\n if (!state?.syncIteratorRecord)\n throw new TypeError(\n \"AsyncFromSyncIteratorPrototype.throw called on invalid object\"\n );\n // 4. Let syncIteratorRecord be O.[[SyncIteratorRecord]].\n const { syncIteratorRecord } = state;\n return pTry(() => {\n if (!syncIteratorRecord.throw) {\n // a. NOTE: If syncIterator does not have a throw method, close it to give it a chance to clean up before we reject the capability.\n syncIteratorRecord.return();\n throw new TypeError(\"no throw method\");\n }\n return syncIteratorRecord.throw(...args);\n });\n },\n };\n\n function createAsyncFromSyncIterator(syncIteratorRecord) {\n // 1. Let asyncIterator be OrdinaryObjectCreate(%AsyncFromSyncIteratorPrototype%, « [[SyncIteratorRecord]] »).\n const asyncIterator = Object.create(AsyncFromSyncIteratorPrototype);\n // 2. Set asyncIterator.[[SyncIteratorRecord]] to syncIteratorRecord.\n privateState.set(asyncIterator, { syncIteratorRecord });\n return asyncIterator;\n }\n\n function getIterator(obj, isAsync) {\n let method = undefined;\n // 1. if kind is ASYNC, then\n if (isAsync) {\n // 1.a. Let method be ? GetMethod(obj, %Symbol.asyncIterator%).\n method = obj[Symbol.asyncIterator];\n // 1.b. If method is undefined, then\n if (method == undefined) {\n // 1.b.i. Let method be ? GetMethod(obj, %Symbol.iterator%).\n method = obj[Symbol.iterator];\n // 1.b.ii. If method is undefined, throw a TypeError exception.\n if (method == undefined) throw new TypeError(\"Object is not async iterable\");\n // 1.b.iii. Let syncIteratorRecord be ? GetIteratorFromMethod(obj, syncMethod).\n const syncIteratorRecord = getIteratorFromMethod(obj, method);\n // 1.b.iv. Return ! CreateAsyncFromSyncIterator(syncIteratorRecord).\n return createAsyncFromSyncIterator(syncIteratorRecord);\n }\n // 2. Else,\n } else {\n // 2.a. Let method be ? GetMethod(obj, %Symbol.iterator%).\n method = obj[Symbol.iterator];\n }\n // 3. If method is undefined, throw a TypeError exception.\n if (method == undefined) throw new TypeError(\"Object is not iterable\");\n // 4. Return ? GetIteratorFromMethod(obj, method).\n return getIteratorFromMethod(obj, method);\n }\n\n const abortSignalAny = \"any\" in AbortSignal ? AbortSignal.any.bind(AbortSignal) : (signals) => {\n // create a signal that will abort when any of the signals aborts.\n const ac = new AbortController();\n // when any of the signals is already aborted, abort ac immediately and return its signal.\n for (const signal of signals) {\n if (signal.aborted) {\n ac.abort(signal.reason);\n return ac.signal;\n }\n }\n // otherwise, add an abort listener to each signal that will abort ac.\n for (const signal of signals) {\n signal.addEventListener(\"abort\", () => {\n ac.abort(signal.reason);\n }, { signal: ac.signal });\n }\n // return the signal.\n return ac.signal;\n };\n\n // wrapper for AbortSignal.any that removes null and undefined, for convenience.\n const anySignal = (signalArray) => abortSignalAny(signalArray.filter(Boolean));\n\n class InternalObserver {\n constructor({ next, error, complete } = {}) {\n privateState.set(this, { next, error, complete });\n }\n\n next(value) {\n const { next } = privateState.get(this) || {};\n if (next) next(value);\n }\n\n error(value) {\n const { error } = privateState.get(this) || {};\n if (error) error(value);\n else reportError(value);\n }\n\n complete() {\n const { complete } = privateState.get(this) || {};\n if (complete) complete();\n }\n }\n\n // https://wicg.github.io/observable/#close-a-subscription\n function closeASubscription(subscriber, reason) {\n const state = privateState.get(subscriber);\n \n // 1. If subscriber’s active is false, then return.\n if (!state?.active) return;\n\n // 2. Set subscriber’s active boolean to false.\n state.active = false;\n\n // 3. Signal abort subscriber’s subscription controller with reason, if it is given.\n state.subscriptionController.abort(reason);\n\n // 4. For each teardown of subscriber’s teardown callbacks sorted in reverse insertion order:\n for (const teardown of state.teardowns.reverse()) {\n // 4.1. If subscriber’s relevant global object is a Window object, and its associated Document is not fully active, then abort these steps.\n if (isBrowserContext() && !isDocumentFullyActive(document)) return;\n // 4.2. Invoke teardown.\n try {\n teardown();\n } catch (e) {\n reportError(e);\n }\n }\n }\n\n // https://wicg.github.io/observable/#observable-subscribe-to-an-observable\n function subscribeTo(observable, observer, options = {}) {\n // 1. If this’s relevant global object is a Window object, and its associated Document is not fully active, then return.\n if (isBrowserContext() && !isDocumentFullyActive(document)) return;\n\n // 2. Let internal observer be a new internal observer.\n let internalObserver;\n\n // 3. Process observer as follows:\n // 3.1. If observer is an ObservableSubscriptionCallback\n if (typeof observer == \"function\") {\n // 3.2. Set internal observer’s next steps to these steps that take an\n // any value:\n internalObserver = new InternalObserver({ next: observer });\n // 4. If observer is a SubscriptionObserver\n } else if (observer && !(observer instanceof InternalObserver)) {\n // 4.1. If observer’s next exists, then set internal observer’s next\n // steps to these steps that take an any value:\n // 4.2. If observer’s error exists, then set internal observer’s error\n // steps to these steps that take an any error:\n // 4.3. If observer’s complete exists, then set internal observer’s\n // complete steps to these steps:\n internalObserver = new InternalObserver(observer);\n } else {\n internalObserver = observer || new InternalObserver();\n }\n\n const observableState = privateState.get(observable);\n\n // 5. If this’s weak subscriber is not null and this’s weak subscriber’s active is true:\n const existingSubscriber = observableState.weakSubscriber?.deref();\n if (existingSubscriber?.active) {\n // 5.1. Let subscriber be this’s weak subscriber.\n const subscriber = existingSubscriber;\n const subscriberState = privateState.get(subscriber);\n // 5.2. Append internal observer to subscriber’s internal observers.\n subscriberState.observers.add(internalObserver);\n // 5.3. If options’s signal exists, then:\n if (options.signal) {\n // 5.3.1 If options’s signal is aborted, then remove internal observer from subscriber’s internal observers.\n if (options.signal.aborted) subscriberState.observers.delete(internalObserver);\n // 5.3.2 Otherwise, add the following abort algorithm to options’s signal:\n else options.signal.addEventListener(\"abort\", () => {\n const subscriberState = privateState.get(subscriber);\n // 5.3.2.1 If subscriber’s active is false, then abort these steps.\n if (!subscriberState?.active) return;\n // 5.3.2.2 Remove internal observer from subscriber’s internal observers.\n subscriberState.observers.delete(internalObserver);\n // 5.3.2.3 If subscriber’s internal observers is empty, then close subscriber with options’s signal’s abort reason.\n if (subscriberState.observers.size == 0) {\n closeASubscription(subscriber, options.signal.reason);\n }\n });\n }\n // 5.4. return\n return;\n }\n\n // 6. Let subscriber be a new Subscriber.\n // 7. Append internal observer to subscriber’s internal observers.\n const subscriber = new Subscriber(internalObserver);\n\n // 8. Set this’s weak subscriber to subscriber.\n observableState.weakSubscriber = new WeakRef(subscriber);\n\n // 9. If options’s signal exists, then:\n if (\"signal\" in options) {\n // 9.1. If options’s signal is aborted, then close subscriber given options’s signal abort reason.\n if (options.signal.aborted)\n closeASubscription(subscriber, options.signal.reason);\n // 9.2. Otherwise, add the following abort algorithm to options’s signal:\n else\n options.signal.addEventListener(\"abort\", () => {\n const subscriberState = privateState.get(subscriber);\n // 9.2.1. If subscriber’s active is false, then abort these steps.\n if (!subscriberState?.active) return;\n // 9.2.2. Remove internal observer from subscriber’s internal observers.\n subscriberState.observers.delete(internalObserver);\n // 9.2.3. If subscriber’s internal observers is empty, then close subscriber with options’s signal’s abort reason.\n if (subscriberState.observers.size == 0) {\n closeASubscription(subscriber, options.signal.reason);\n }\n });\n }\n\n // 7. If observable's subscribe callback is a SubscribeCallback, invoke it with subscriber.\n if (observableState.subscribeCallback) {\n // If an exception E was thrown, call subscriber’s error() method with E.\n try {\n observableState.subscribeCallback(subscriber);\n } catch (e) {\n subscriber.error(e);\n }\n }\n // 8. Otherwise, run the steps given by observable's subscribe callback, given subscriber.\n // (Not needed because internal subscribers use the same callback function)\n }\n\n // https://wicg.github.io/observable/#subscriber-api\n class Subscriber {\n get [Symbol.toStringTag]() {\n return \"Subscriber\";\n }\n\n constructor(internalObserver = null) {\n if (!(internalObserver instanceof InternalObserver)) {\n throw new TypeError(\"Illegal constructor\");\n }\n privateState.set(this, {\n active: true,\n observers: new Set([internalObserver]),\n teardowns: [],\n subscriptionController: new AbortController(),\n });\n }\n\n // https://wicg.github.io/observable/#dom-subscriber-next\n next(value) {\n if (!(this instanceof Subscriber))\n throw new TypeError(\"illegal invocation\");\n if (!arguments.length) throw new TypeError(\"too few arguments\");\n\n const state = privateState.get(this);\n\n // 1. If this's active is false, then return.\n if (!state?.active) return;\n\n // 2. If this’s relevant global object is a Window object, and its associated Document is not fully active, then return.\n if (isBrowserContext() && !isDocumentFullyActive(document)) return;\n\n // 3. Let internal observers copy be a copy of this’s internal observers.\n const internalObservers = new Set(state.observers);\n\n // 4. For each observer of this’s internal observers copy:\n for (const observer of internalObservers) {\n // 3.1. Run observer’s next steps given value.\n observer.next(value);\n }\n }\n\n // https://wicg.github.io/observable/#dom-subscriber-error\n error(error) {\n if (!(this instanceof Subscriber))\n throw new TypeError(\"illegal invocation\");\n\n if (!arguments.length) throw new TypeError(\"too few arguments\");\n\n const state = privateState.get(this);\n\n // 1. If this’s active is false, report an exception with error and this’s relevant global object, then return.\n if (!state?.active) {\n reportError(error);\n return;\n }\n\n // 2. If this’s relevant global object is a Window object, and its associated Document is not fully active, then return.\n if (isBrowserContext() && !isDocumentFullyActive(document)) return;\n\n // 3. Close this.\n closeASubscription(this, error);\n\n // 4. Let internal observers copy be a copy of this’s internal observers.\n const internalObservers = new Set(state.observers);\n\n // 5. For each observer of this’s internal observers copy:\n for (const observer of internalObservers) {\n // 5.1. Run observer’s error steps given error.\n observer.error(error);\n }\n }\n\n // https://wicg.github.io/observable/#dom-subscriber-complete\n complete() {\n if (!(this instanceof Subscriber))\n throw new TypeError(\"illegal invocation\");\n\n const state = privateState.get(this);\n\n // 1. If this's active is false, then return.\n if (!state?.active) return;\n\n // 2. If this’s relevant global object is a Window object, and its associated Document is not fully active, then return.\n if (isBrowserContext() && !isDocumentFullyActive(document)) return;\n\n // 3. Close this.\n closeASubscription(this);\n\n // 4. Let internal observers copy be a copy of this’s internal observers.\n const internalObservers = new Set(state.observers);\n\n // 5. For each observer of this’s internal observers copy:\n for (const observer of internalObservers) {\n // 5.1. Run observer’s complete steps.\n observer.complete();\n }\n }\n\n // https://wicg.github.io/observable/#dom-subscriber-addteardown\n addTeardown(teardown) {\n if (!(this instanceof Subscriber))\n throw new TypeError(\"illegal invocation\");\n\n if (typeof teardown != \"function\") {\n throw new TypeError(`Parameter 1 is not of type 'Function'`);\n }\n\n // 1. If this’s relevant global object is a Window object, and its associated Document is not fully active, then return.\n if (isBrowserContext() && !isDocumentFullyActive(document)) return;\n\n // 2. If this's active is true, then append teardown to this's teardown callbacks list.\n const state = privateState.get(this);\n if (state?.active)\n state.teardowns.push(teardown);\n // 3. Otherwise, invoke teardown.\n else teardown();\n }\n\n get active() {\n if (!(this instanceof Subscriber))\n throw new TypeError(\"illegal invocation\");\n\n return !!privateState.get(this)?.active;\n }\n\n get signal() {\n if (!(this instanceof Subscriber))\n throw new TypeError(\"illegal invocation\");\n\n if (!privateState.has(this)) {\n const controller = new AbortController();\n controller.abort();\n return controller.signal;\n }\n return privateState.get(this).subscriptionController.signal;\n }\n }\n\n enumerate(Subscriber.prototype, \"next\");\n enumerate(Subscriber.prototype, \"error\");\n enumerate(Subscriber.prototype, \"complete\");\n enumerate(Subscriber.prototype, \"addTeardown\");\n enumerate(Subscriber.prototype, \"active\");\n enumerate(Subscriber.prototype, \"signal\");\n\n // https://wicg.github.io/observable/#observable-api\n class Observable {\n get [Symbol.toStringTag]() {\n return \"Observable\";\n }\n\n // https://wicg.github.io/observable/#dom-observable-observable\n constructor(subscribeCallback) {\n if (!subscribeCallback) {\n throw new TypeError(\"1 argument required but 0 present\");\n }\n privateState.set(this, {\n weakSubscriber: null,\n subscribeCallback,\n });\n }\n\n // https://wicg.github.io/observable/#observable-from\n static from(value) {\n // 1. If Type(value) is not Object, throw a TypeError.\n if (value === null || typeof value !== \"object\") throw new TypeError(\"Observable.from only accepts objects\");\n\n // 2. From Observable: If value’s specific type is an Observable, then return value.\n if (value instanceof Observable) return value;\n\n // 3. Let asyncIteratorMethodRecord be GetMethod(value, %Symbol.asyncIterator%).\n const asyncIteratorMethodRecord = Symbol.asyncIterator in value && value[Symbol.asyncIterator];\n // 4. If asyncIteratorMethod’s is undefined or null, then jump to the step labeled From iterable.\n if (typeof asyncIteratorMethodRecord === \"function\") {\n let done = false;\n // 5. Let nextAlgorithm be the following steps, given a Subscriber subscriber and an Iterator Record iteratorRecord:\n function nextAlgorithm(subscriber, iteratorRecord) {\n // 5.1. If subscriber’s subscription controller’s signal is aborted, then return.\n if (subscriber.signal.aborted) return;\n // 5.2. Let nextPromise be a Promise-or-undefined, initially undefined.\n let nextPromise = undefined;\n try {\n // 5.3. Let nextCompletion be IteratorNext(iteratorRecord).\n let nextCompletion = iteratorRecord.next();\n // 5.5. Otherwise, if nextRecord is normal completion, then set nextPromise to a promise resolved with nextRecord’s [[Value]].\n nextPromise = Promise.resolve(nextCompletion);\n } catch (error) {\n // 5.4. If nextCompletion is a throw completion, then:\n // 5.4.1. Assert: iteratorRecord’s [[Done]] is true.\n // 5.4.2. Set nextPromise to a promise rejected with nextRecord’s [[Value]].\n nextPromise = Promise.reject(error);\n }\n // 5.6. React to nextPromise:\n nextPromise.then(\n // If nextPromise was fulfilled with value iteratorResult, then:\n (iteratorResult) => {\n // 5.6.1 If Type(iteratorResult) is not Object, then run subscriber’s error() method with a TypeError and abort these steps.\n if (iteratorResult === null || typeof iteratorResult !== \"object\") {\n subscriber.error(new TypeError(\"Not an IteratorResult.\"));\n return;\n }\n try {\n // 5.6.2 Let done be IteratorComplete(iteratorResult).\n ({ done } = iteratorResult);\n } catch (error) {\n // 5.6.3 If done is a throw completion, then run subscriber’s error() method with done’s [[Value]] and abort these steps.\n subscriber.error(error);\n return;\n }\n // 5.6.4. If done’s [[Value]] is true, then run subscriber’s complete() and abort these steps.\n if (done) {\n subscriber.complete();\n return;\n }\n let value;\n try {\n // 5.6.5. Let value be IteratorValue(iteratorResult).\n value = iteratorResult.value;\n } catch (error) {\n // 5.6.6. If value is a throw completion, then run subscriber’s error() method with value’s [[Value]] and abort these steps.\n subscriber.error(error);\n return;\n }\n // 5.6.7. Run subscriber’s next() given value’s [[Value]].\n subscriber.next(value);\n // 5.6.8. Run nextAlgorithm given subscriber and iteratorRecord.\n nextAlgorithm(subscriber, iteratorRecord);\n },\n // If nextPromise was rejected with reason r, then run subscriber’s error() method given r.\n (r) => {\n subscriber.error(r);\n }\n );\n }\n // 6. Return a new Observable whose subscribe callback is an algorithm that takes a Subscriber subscriber and does the following:\n return new Observable((subscriber) => {\n // 6.1. If subscriber’s subscription controller’s signal is aborted, then return.\n if (subscriber.signal.aborted) return;\n let iteratorRecordCompletion;\n try {\n // 6.2. Let iteratorRecordCompletion be GetIterator(value, async).\n iteratorRecordCompletion = getIterator(value, true);\n } catch (error) {\n // 6.3. If iteratorRecordCompletion is a throw completion, then run subscriber’s error() method with iteratorRecordCompletion’s [[Value]] and abort these steps.\n subscriber.error(error);\n return;\n }\n // 6.4. Let iteratorRecord be ! iteratorRecordCompletion.\n // 6.5. Assert: iteratorRecord is an Iterator Record.\n const iteratorRecord = iteratorRecordCompletion;\n // 6.6. If subscriber’s subscription controller’s signal is aborted, then return.\n if (subscriber.signal.aborted) return;\n // 6.7. Add the following abort algorithm to subscriber’s subscription controller’s signal:\n subscriber.signal.addEventListener(\"abort\", () => {\n // 6.7.1. Run AsyncIteratorClose(iteratorRecord, NormalCompletion(subscriber’s subscription controller’s abort reason)).\n if (typeof iteratorRecord.return !== \"function\" || done) return;\n const returnPromise = pTry(() => iteratorRecord.return(subscriber.signal.reason));\n returnPromise.then((result) => {\n if (result === null || typeof result !== \"object\") {\n throw new TypeError(\"Iterator .return() must return an Object\");\n }\n });\n });\n // 6.8. Run nextAlgorithm given subscriber and iteratorRecord.\n nextAlgorithm(subscriber, iteratorRecord);\n });\n }\n\n // 7. From iterable: Let iteratorMethod be ? GetMethod(value, %Symbol.iterator%).\n let iteratorMethod = Symbol.iterator in value && value[Symbol.iterator];\n // 8. If iteratorMethod is undefined, then jump to the step labeled From Promise.\n if (typeof iteratorMethod === \"function\") {\n // Otherwise, return a new Observable whose subscribe callback is an algorithm that takes a Subscriber subscriber and does the following:\n return new Observable((subscriber) => {\n // 8.1. If subscriber’s subscription controller’s signal is aborted, then return.\n if (subscriber.signal.aborted) return;\n let iteratorRecordCompletion;\n try {\n // 8.2. Let iteratorRecordCompletion be GetIterator(value, sync).\n iteratorRecordCompletion = getIterator(value, false);\n } catch (error) {\n // 8.3. If iteratorRecordCompletion is a throw completion, then run subscriber’s error() method, given iteratorRecordCompletion’s [[Value]], and abort these steps.\n subscriber.error(error);\n return;\n }\n let done = false;\n // 8.4. Let iteratorRecord be ! iteratorRecordCompletion.\n let iteratorRecord = iteratorRecordCompletion;\n // 8.5 If subscriber’s subscription controller’s signal is aborted, then return.\n if (subscriber.signal.aborted) return;\n // 8.6. Add the following abort algorithm to subscriber’s subscription controller’s signal:\n subscriber.signal.addEventListener(\"abort\", () => {\n // 8.6.1. Run IteratorClose(iteratorRecord, NormalCompletion(UNUSED)).\n if (typeof iteratorRecord.return !== \"function\" || done) return;\n const returnResult = iteratorRecord.return();\n if (returnResult === null || typeof returnResult !== \"object\") {\n throw new TypeError(\"Iterator .return() must return an Object\");\n }\n });\n // 8.7. While true:\n while (true) {\n try {\n // 8.7.1. Let next be IteratorStepValue(iteratorRecord).\n let next = iteratorRecord.next();\n ({ done } = next);\n // 8.7.3. Set next to ! to next.\n // 8.7.4. If next is done, then:\n if (done) {\n // 8.7.4.1. Assert: iteratorRecord’s [[Done]] is true.\n // 8.7.4.2. Run subscriber’s complete().\n subscriber.complete();\n // 8.7.4.3. return\n return;\n }\n // 8.7.5 Run subscriber’s next() given next.\n subscriber.next(next.value);\n // 8.7.6. If subscriber’s subscription controller’s signal is aborted, then break.\n if (subscriber.signal.aborted) break;\n } catch (error) {\n // 8.7.2. If next is a throw completion, then run subscriber’s error() method, given next’s [[Value]], and break.\n subscriber.error(error);\n break;\n }\n }\n });\n }\n\n // 9. From Promise: If IsPromise(value) is true, then:\n if (value instanceof Promise || typeof value.then === \"function\") {\n // 9.1. Return a new Observable whose subscribe callback is an algorithm that takes a Subscriber subscriber and does the following:\n return new Observable((subscriber) => {\n // 9.1.1. React to value:\n value.then(\n // 9.1.1.1. If value was fulfilled with value v, then:\n (v) => {\n // 9.1.1.1.1 Run subscriber’s next() method, given v.\n subscriber.next(v);\n // 9.1.1.1.2 Run subscriber’s complete() method.\n subscriber.complete();\n },\n // 9.1.1.2 If value was rejected with reason r, then run subscriber’s error() method, given r.\n (r) => {\n subscriber.error(r);\n }\n );\n });\n }\n\n // 10. Throw a TypeError.\n throw new TypeError(\"Could not convert value to Observable\");\n }\n\n // https://wicg.github.io/observable/#dom-observable-subscribe\n subscribe(observer = null, options = {}) {\n if (!(this instanceof Observable))\n throw new TypeError(\"illegal invocation\");\n // 1. Subscribe to this given observer and options.\n subscribeTo(this, observer, options);\n }\n\n // https://wicg.github.io/observable/#dom-observable-takeuntil\n takeUntil(value) {\n if (!(this instanceof Observable))\n throw new TypeError(\"illegal invocation\");\n\n // 1. Let sourceObservable be this.\n let sourceObservable = this;\n\n // 2. Let notifier be the result of converting value to an Observable.\n let notifier = Observable.from(value);\n\n // 3. Let observable be a new Observable whose subscribe callback is an algorithm that takes a Subscriber subscriber and does the following:\n return new Observable((subscriber) => {\n // 3.1. Let notifierObserver be a new internal observer, initialized as follows:\n const notifierObserver = new InternalObserver({\n // 3.1.1. For the next callback, run subscriber’s complete() method.\n next() {\n subscriber.complete();\n },\n // 3.1.2. For the error callback, run subscriber’s complete() method.\n error() {\n subscriber.complete();\n },\n });\n\n // 3.2. Let options be a new SubscribeOptions whose signal is subscriber’s subscription controller's signal.\n let options = { signal: subscriber.signal };\n\n // 3.3. Subscribe to notifier given notifierObserver and options.\n subscribeTo(notifier, notifierObserver, options);\n\n // 3.4. If subscriber’s active is false, then return.\n if (!subscriber.active) return;\n\n // 3.5. Let sourceObserver be a new internal observer, initialized as follows:\n let sourceObserver = new InternalObserver({\n // 3.5.1. For the next callback, run subscriber’s next() method, given the passed in value.\n next(value) {\n subscriber.next(value);\n },\n // 3.5.2. For the error callback, run subscriber’s error() method, given the passed in error.\n error(value) {\n subscriber.error(value);\n },\n // 3.5.3. For the complete callback, run subscriber’s complete() method.\n complete() {\n subscriber.complete();\n },\n });\n\n // 3.6. Subscribe to sourceObservable given sourceObserver and options.\n subscribeTo(sourceObservable, sourceObserver, options);\n });\n }\n\n // https://wicg.github.io/observable/#dom-observable-map\n map(mapper) {\n if (!(this instanceof Observable))\n throw new TypeError(\"illegal invocation\");\n if (typeof mapper !== \"function\")\n throw new TypeError(`Parameter 1 is not of type 'Function'`);\n // 1. Let sourceObservable be this.\n let sourceObservable = this;\n // 2. Let observable be a new Observable whose subscribe callback is an algorithm that takes a Subscriber subscriber and does the following:\n // 3. Return observable.\n return new Observable((subscriber) => {\n // 2.1. Let idx be an unsigned long long, initially 0.\n let idx = 0;\n // 2.2. Let sourceObserver be a new internal observer, initialized as follows:\n let sourceObserver = new InternalObserver({\n next(value) {\n let mappedValue;\n // 1. Invoke mapper with the passed in value, and idx, and let mappedValue be the returned value.\n try {\n mappedValue = mapper(value, idx);\n } catch (e) {\n // 2. If an exception E was thrown, then run subscriber’s error() method, given E, and abort these steps.\n subscriber.error(e);\n return;\n }\n // 3. Increment idx.\n idx += 1;\n // 4. Run subscriber’s next() method, given mappedValue.\n subscriber.next(mappedValue);\n },\n error(value) {\n // Run subscriber’s error() method, given the passed in error.\n subscriber.error(value);\n },\n complete() {\n // Run subscriber’s complete() method.\n subscriber.complete();\n },\n });\n // 3. Let options be a new SubscribeOptions whose signal is subscriber’s subscription controller's signal.\n let options = { signal: subscriber.signal };\n // 4. Subscribe to sourceObservable given sourceObserver and options.\n subscribeTo(sourceObservable, sourceObserver, options);\n });\n }\n\n // https://wicg.github.io/observable/#dom-observable-inspect\n inspect(inspectorUnion = {}) {\n // 1: Let subscribe callback be a `VoidFunction`-or-null, initially null.\n let subscribeCallback = null;\n // 2: Let next callback be a `ObservableSubscriptionCallback`-or-null, initially null.\n let nextCallback = null;\n // 3: Let error callback be a `ObservableSubscriptionCallback`-or-null, initially null.\n let errorCallback = null;\n // 4: Let complete callback be a `VoidFunction`-or-null, initially null.\n let completeCallback = null;\n // 5: Let abort callback be a `ObservableInspectorAbortHandler`-or-null, initially null.\n let abortCallback = null;\n\n // 6: Process inspectorUnion as follows:\n if (typeof inspectorUnion === \"function\") {\n // If inspectorUnion is an `ObservableSubscriptionCallback`\n // 6.1: Set next callback to inspectorUnion.\n nextCallback = inspectorUnion;\n } else if (inspectorUnion && typeof inspectorUnion === \"object\") {\n // If inspectorUnion is an `ObservableInspector`\n // 6.1: If `subscribe` exists in inspectorUnion, then set subscribe callback to it.\n if (\"subscribe\" in inspectorUnion) subscribeCallback = inspectorUnion.subscribe;\n // 6.2: If `next` exists in inspectorUnion, then set next callback to it.\n if (\"next\" in inspectorUnion) nextCallback = inspectorUnion.next;\n // 6.3: If `error` exists in inspectorUnion, then set error callback to it.\n if (\"error\" in inspectorUnion) errorCallback = inspectorUnion.error;\n // 6.4: If `complete` exists in inspectorUnion, then set complete callback to it.\n if (\"complete\" in inspectorUnion) completeCallback = inspectorUnion.complete;\n // 6.5: If `abort` exists in inspectorUnion, then set abort callback to it.\n if (\"abort\" in inspectorUnion) abortCallback = inspectorUnion.abort;\n }\n\n // 7: Let sourceObservable be this.\n const sourceObservable = this;\n // 8: Let observable be a new `Observable` whose subscribe callback is an algorithm that takes a `Subscriber` subscriber and does the following:\n return new Observable((subscriber) => {\n // 8.1: If subscribe callback is not null, then invoke it.\n if (subscribeCallback !== null) {\n try {\n subscribeCallback();\n } catch (e) {\n // If an exception E was thrown, then run subscriber’s `error()` method, given E, and abort these steps.\n subscriber.error(e);\n return;\n }\n }\n\n // 8.2: If abort callback is not null, then add the following abort algorithm to subscriber’s subscription controller’s signal:\n const abortCallbackWrapped = () => {\n // 8.2.1: Invoke abort callback with subscriber’s subscription controller’s signal’s abort reason.\n try {\n if (abortCallback !== null) {\n abortCallback(subscriber.signal.reason);\n }\n } catch (e) {\n // If an exception E was thrown, then report the exception E.\n reportError(e);\n }\n };\n subscriber.signal.addEventListener(\"abort\", abortCallbackWrapped, { once: true });\n\n // 8.3: Let sourceObserver be a new internal observer, initialized as follows:\n const sourceObserver = new InternalObserver({\n next(value) {\n // next steps\n // 8.3.next.1: If next callback is not null, then invoke next callback with the passed in value.\n if (nextCallback !== null) {\n try {\n nextCallback(value);\n } catch (e) {\n // If an exception E was thrown, then:\n // 8.3.next.1.1: Remove abort callback from subscriber’s subscription controller’s signal.\n subscriber.signal.removeEventListener(\"abort\", abortCallbackWrapped);\n // 8.3.next.1.2: Run subscriber’s `error()` method, given E, and abort these steps.\n subscriber.error(e);\n return;\n }\n }\n // 8.3.next.2: Run subscriber’s `next()` method with the passed in value.\n subscriber.next(value);\n },\n error(error) {\n // error steps\n // 8.3.error.1: Remove abort callback from subscriber’s subscription controller’s signal.\n subscriber.signal.removeEventListener(\"abort\", abortCallbackWrapped);\n // 8.3.error.2: If error callback is not null, then invoke error callback given the passed in error.\n if (errorCallback !== null) {\n try {\n errorCallback(error);\n } catch (e) {\n // If an exception E was thrown, then run subscriber’s `error()` method, given E, and abort these steps.\n subscriber.error(e);\n return;\n }\n }\n // 8.3.error.3: Run subscriber’s `error()` method, given the passed in error.\n subscriber.error(error);\n },\n complete() {\n // complete steps\n // 8.3.complete.1: Remove abort callback from subscriber’s subscription controller’s signal.\n subscriber.signal.removeEventListener(\"abort\", abortCallbackWrapped);\n // 8.3.complete.2: If complete callback is not null, then invoke complete callback.\n if (completeCallback !== null) {\n try {\n completeCallback();\n } catch (e) {\n // If an exception E was thrown, then run subscriber’s `error()` method, given E, and abort these steps.\n subscriber.error(e);\n return;\n }\n }\n // 8.3.complete.3: Run subscriber’s `complete()` method.\n subscriber.complete();\n },\n });\n\n // 8.4: Let options be a new `SubscribeOptions` whose `signal` is subscriber’s subscription controller’s signal.\n const options = { signal: subscriber.signal };\n // 8.5: Subscribe to sourceObservable given sourceObserver and options.\n subscribeTo(sourceObservable, sourceObserver, options);\n });\n }\n\n // https://wicg.github.io/observable/#dom-observable-filter\n filter(predicate) {\n if (!(this instanceof Observable))\n throw new TypeError(\"illegal invocation\");\n if (typeof predicate !== \"function\")\n throw new TypeError(`Parameter 1 is not of type 'Function'`);\n // 1. Let sourceObservable be this.\n let sourceObservable = this;\n // 2. Let observable be a new Observable whose subscribe callback is an algorithm that takes a Subscriber subscriber and does the following:\n // 3. Return observable.\n return new Observable((subscriber) => {\n // 2.1. Let idx be an unsigned long long, initially 0.\n let idx = 0;\n // 2.2. Let sourceObserver be a new internal observer, initialized as follows:\n let sourceObserver = new InternalObserver({\n next(value) {\n let matches = false;\n // 1. Invoke mapper with the passed in value, and idx, and let mappedValue be the returned value.\n try {\n matches = predicate(value, idx);\n } catch (e) {\n // 2. If an exception E was thrown, then run subscriber’s error() method, given E, and abort these steps.\n subscriber.error(e);\n return;\n }\n // 3. Set idx to idx + 1.\n idx += 1;\n // 4. If matches is true, then run subscriber’s next() method, given value.\n if (matches) {\n subscriber.next(value);\n }\n },\n error(value) {\n // Run subscriber’s error() method, given the passed in error.\n subscriber.error(value);\n },\n complete() {\n // Run subscriber’s complete() method.\n subscriber.complete();\n },\n });\n // 3. Let options be a new SubscribeOptions whose signal is subscriber’s subscription controller's signal.\n let options = { signal: subscriber.signal };\n // 4. Subscribe to sourceObservable given sourceObserver and options.\n subscribeTo(sourceObservable, sourceObserver, options);\n });\n }\n\n // https://wicg.github.io/observable/#dom-observable-take\n take(amount) {\n if (!(this instanceof Observable))\n throw new TypeError(\"illegal invocation\");\n // 1. Let sourceObservable be this.\n let sourceObservable = this;\n // 2. Let observable be a new Observable whose subscribe callback is an algorithm that takes a Subscriber subscriber and does the following:\n // 3. Return observable.\n return new Observable((subscriber) => {\n // 2.1. Let remaining be amount.\n let remaining = amount;\n // 2.2. If remaining is 0, then run subscriber’s complete() method and abort these steps.\n if (remaining == 0) return subscriber.complete();\n // 2.3. Let sourceObserver be a new internal observer, initialized as follows:\n let sourceObserver = new InternalObserver({\n next(value) {\n // 1. Run subscriber’s next() method with the passed in value.\n subscriber.next(value);\n // 2. Decrement remaining.\n remaining -= 1;\n // 3. If remaining is 0, then run subscriber’s complete() method.\n if (remaining == 0) subscriber.complete();\n },\n error(value) {\n // Run subscriber’s error() method, given the passed in error.\n subscriber.error(value);\n },\n complete() {\n // Run subscriber’s complete() method.\n subscriber.complete();\n },\n });\n // 3. Let options be a new SubscribeOptions whose signal is subscriber’s subscription controller's signal.\n let options = { signal: subscriber.signal };\n // 4. Subscribe to sourceObservable given sourceObserver and options.\n subscribeTo(sourceObservable, sourceObserver, options);\n });\n }\n\n // https://wicg.github.io/observable/#dom-observable-drop\n drop(amount) {\n if (!(this instanceof Observable))\n throw new TypeError(\"illegal invocation\");\n // 1. Let sourceObservable be this.\n let sourceObservable = this;\n // 2. Let observable be a new Observable whose subscribe callback is an algorithm that takes a Subscriber subscriber and does the following:\n // 3. Return observable.\n return new Observable((subscriber) => {\n // 2.1. Let remaining be amount.\n let remaining = amount;\n // 2.3. Let sourceObserver be a new internal observer, initialized as follows:\n let sourceObserver = new InternalObserver({\n next(value) {\n // 1. If remaining is > 0, then decrement remaining and abort these steps.\n if (remaining > 0) return (remaining -= 1);\n // 2. Assert: remaining is 0.\n if (remaining != 0) return;\n // 3. Run subscriber’s next() method with the passed in value.\n subscriber.next(value);\n },\n error(value) {\n // Run subscriber’s error() method, given the passed in error.\n subscriber.error(value);\n },\n complete() {\n // Run subscriber’s complete() method.\n subscriber.complete();\n },\n });\n // 3. Let options be a new SubscribeOptions whose signal is subscriber’s subscription controller's signal.\n let options = { signal: subscriber.signal };\n // 4. Subscribe to sourceObservable given sourceObserver and options.\n subscribeTo(sourceObservable, sourceObserver, options);\n });\n }\n\n // https://wicg.github.io/observable/#dom-observable-flatmap\n flatMap(mapper) {\n if (!(this instanceof Observable))\n throw new TypeError(\"illegal invocation\");\n if (typeof mapper !== \"function\")\n throw new TypeError(`Parameter 1 is not of type 'Function'`);\n // 1. Let sourceObservable be this.\n let sourceObservable = this;\n // 2. Let observable be a new Observable whose subscribe callback is an algorithm that takes a Subscriber subscriber and does the following:\n // 3. Return observable.\n return new Observable((subscriber) => {\n // 2.1. Let idx be an unsigned long long, initially 0.\n let idx = 0;\n // 2.2. Let outerSubscriptionHasCompleted to a boolean, initially false.\n let outerSubscriptionHasCompleted = false;\n // 2.3. Let queue be a new list of any values, initially empty.\n let queue = [];\n\n // https://wicg.github.io/observable/#flatmap-process-next-value-steps\n // The flatmap process next value steps, given an any value, a\n // Subscriber subscriber, a Mapper mapper, and references to all\n // of the following: a list of any values queue, a boolean\n // activeInnerSubscription, a boolean outerSubscriptionHasCompleted,\n // and an unsigned long long idx:\n function flatmapProcessNextValueSteps(value) {\n // 1. Let mappedResult be the result of invoking mapper with value, idx and \"rethrow\".\n let mappedResult;\n try {\n mappedResult = mapper(value, idx);\n } catch (e) {\n return subscriber.error(e);\n }\n // 2. Set idx to idx + 1.\n idx += 1;\n // 3. Let innerObservable be the result of calling from() with mappedResult.\n let innerObservable;\n try {\n innerObservable = Observable.from(mappedResult);\n } catch (e) {\n return subscriber.error(e);\n }\n // 4. Let innerObserver be a new internal observer, initialized as follows:\n let innerObserver = new InternalObserver({\n next(value) {\n // Run subscriber’s next() method, given the passed in value.\n subscriber.next(value);\n },\n error(value) {\n // Run subscriber’s error() method, given the passed in error.\n subscriber.error(value);\n },\n complete() {\n // 1. If queue is not empty, then:\n if (queue.length) {\n // 1.1. Let nextValue be the first item in queue; remove remove this item from queue.\n let nextValue = queue.shift();\n // 1.2. Run flatmap process next value steps given nextValue, subscriber, mapper, and references to queue and activeInnerSubscription.\n flatmapProcessNextValueSteps(nextValue);\n // 2. Otherwise:\n } else {\n // 2.1. Set activeInnerSubscription to false.\n activeInnerSubscription = false;\n // 2.2. If outerSubscriptionHasCompleted is true, run subscriber’s complete() method.\n if (outerSubscriptionHasCompleted) subscriber.complete();\n }\n },\n });\n // 5. Let innerOptions be a new SubscribeOptions whose signal is subscriber’s subscription controller's signal.\n let innerOptions = { signal: subscriber.signal };\n // 6. Subscribe to innerObservable given innerObserver and innerOptions.\n subscribeTo(innerObservable, innerObserver, innerOptions);\n }\n\n // 2.4. Let activeInnerSubscription be a boolean, initially false.\n let activeInnerSubscription = false;\n // 2.5. Let sourceObserver be a new internal observer, initialized as follows:\n let sourceObserver = new InternalObserver({\n next(value) {\n // 1. If activeInnerSubscription is true, then:\n if (activeInnerSubscription) {\n // 1.1. Append value to queue.\n queue.push(value);\n // 2. Otherwise:\n } else {\n // 2.1. Set activeInnerSubscription to true.\n activeInnerSubscription = true;\n // 2.2. Run the flatmap process next value steps with value,\n // subscriber, mapper, and references to all of the following:\n // queue, activeInnerSubscription, outerSubscriptionHasCompleted,\n // and idx.\n flatmapProcessNextValueSteps(value);\n }\n },\n error(value) {\n // Run subscriber’s error() method, given the passed in error.\n subscriber.error(value);\n },\n complete() {\n // 1. Set outerSubscriptionHasCompleted to true.\n outerSubscriptionHasCompleted = true;\n // 2. If activeInnerSubscription is false and queue is empty, run subscriber’s complete() method.\n if (!activeInnerSubscription && !queue.length) {\n subscriber.complete();\n }\n },\n });\n // 2.6. Let options be a new SubscribeOptions whose signal is subscriber’s subscription controller’s signal.\n const options = { signal: subscriber.signal };\n // 2.7. Subscribe to sourceObservable given sourceObserver and options.\n subscribeTo(sourceObservable, sourceObserver, options);\n });\n }\n\n // https://wicg.github.io/observable/#dom-observable-switchmap\n switchMap(mapper) {\n if (!(this instanceof Observable))\n throw new TypeError(\"illegal invocation\");\n if (typeof mapper !== \"function\")\n throw new TypeError(`Parameter 1 is not of type 'Function'`);\n // 1. Let sourceObservable be this.\n let sourceObservable = this;\n // 2. Let observable be a new Observable whose subscribe callback is an algorithm that takes a Subscriber subscriber and does the following:\n // 3. Return observable.\n return new Observable((subscriber) => {\n // 2.1. Let idx be an unsigned long long, initially 0.\n let idx = 0;\n // 2.2. Let outerSubscriptionHasCompleted to a boolean, initially false.\n let outerSubscriptionHasCompleted = false;\n // 2.3. Let activeInnerAbortController be an AbortController-or-null, initially null.\n let activeInnerAbortController = null;\n\n function switchmapProcessNextValueSteps(value) {\n // https://wicg.github.io/observable/#flatmap-process-next-value-steps\n // The flatmap process next value steps, given an any value, a\n // Subscriber subscriber, a Mapper mapper, and references to all\n // of the following: a list of any values queue, a boolean\n // activeInnerSubscription, a boolean outerSubscriptionHasCompleted,\n // and an unsigned long long idx:\n //\n // 1. Let mappedResult be the result of invoking mapper with value\n // and idx.\n let mappedResult;\n try {\n mappedResult = mapper(value, idx);\n } catch (e) {\n return subscriber.error(e);\n }\n // 2. Set idx to idx + 1.\n idx += 1;\n // 3. Let innerObservable be the result of calling from() with mappedResult.\n let innerObservable;\n try {\n innerObservable = Observable.from(mappedResult);\n } catch (e) {\n return subscriber.error(e);\n }\n // 4. Let innerObserver be a new internal observer, initialized as follows:\n let innerObserver = new InternalObserver({\n next(value) {\n // Run subscriber’s next() method, given the passed in value.\n subscriber.next(value);\n },\n error(value) {\n // Run subscriber’s error() method, given the passed in error.\n subscriber.error(value);\n },\n complete(value) {\n // 1. If outerSubscriptionHasCompleted is true, run subscriber’s complete() method.\n if (outerSubscriptionHasCompleted) subscriber.complete();\n // 2. Otherwise, set activeInnerAbortController to null.\n else activeInnerAbortController = null;\n },\n });\n // 5. Let innerOptions be a new SubscribeOptions whose signal is the\n // result of creating a dependent abort signal from the list\n // «activeInnerAbortController’s signal, subscriber’s subscription\n // controller's signal», using AbortSignal, and the current realm.\n const innerOptions = { signal: anySignal([activeInnerAbortController.signal, subscriber.signal]) };\n // 6. Subscribe to innerObservable given innerObserver and innerOptions.\n subscribeTo(innerObservable, innerObserver, innerOptions);\n }\n\n // 2.4. Let activeInnerSubscription be a boolean, initially false.\n // 2.5. Let sourceObserver be a new internal observer, initialized as follows:\n let sourceObserver = new InternalObserver({\n next(value) {\n // 1. If activeInnerAbortController is not null, then signal abort activeInnerAbortController.\n if (activeInnerAbortController) {\n activeInnerAbortController.abort();\n }\n // 2. Set activeInnerAbortController to a new AbortController.\n activeInnerAbortController = new AbortController();\n // 3. Run the switchmap process next value steps with value,\n // subscriber, mapper, and references to all of the\n // following: activeInnerAbortController,\n // outerSubscriptionHasCompleted, and idx.\n switchmapProcessNextValueSteps(value);\n },\n error(value) {\n // Run subscriber’s error() method, given the passed in error.\n subscriber.error(value);\n },\n complete() {\n // 1. Set outerSubscriptionHasCompleted to true.\n outerSubscriptionHasCompleted = true;\n // 2. If activeInnerAbortController is null, run subscriber’s complete() method.\n if (!activeInnerAbortController) subscriber.complete();\n },\n });\n // 3. Let options be a new SubscribeOptions whose signal is subscriber’s subscription controller's signal.\n let options = { signal: subscriber.signal };\n // 4. Subscribe to sourceObservable given sourceObserver and options.\n subscribeTo(sourceObservable, sourceObserver, options);\n });\n }\n\n // https://wicg.github.io/observable/#dom-observable-catch\n catch(callback) {\n if (!(this instanceof Observable))\n throw new TypeError(\"illegal invocation\");\n if (typeof callback !== \"function\")\n throw new TypeError(`Parameter 1 is not of type 'Function'`);\n // 1. Let sourceObservable be this.\n const sourceObservable = this;\n // 2. Let observable be a new Observable whose subscribe callback is an algorithm that takes a Subscriber subscriber and does the following:\n const observable = new Observable((subscriber) => {\n // 2.1 Let sourceObserver be a new internal observer, initialized as follows:\n const sourceObserver = new InternalObserver({\n next(value) {\n // 2.1.next Run subscriber’s next() method, given the passed in value.\n subscriber.next(value);\n },\n error(value) {\n // 2.1.error.1 Invoke callback with «the passed in error» and \"rethrow\". Let result be the returned value.\n // If an exception E was thrown, then run subscriber’s error() with E, and abort these steps.\n let result;\n try {\n result = callback(value);\n } catch (error) {\n subscriber.error(error);\n return;\n }\n // 2.1.error.2 Let innerObservable be the result of calling from() with result.\n // If an exception E was thrown, then run subscriber’s error() method, given E, and abort these steps.\n let innerObservable;\n try {\n innerObservable = Observable.from(result);\n } catch (error) {\n subscriber.error(error);\n return;\n }\n // 2.1.error.3 Let innerObserver be a new internal observer, initialized as follows:\n const innerObserver = new InternalObserver({\n next(value) {\n // Run subscriber’s next() method, given the passed in value.\n subscriber.next(value);\n },\n error(error) {\n // Run subscriber’s error() method, given the passed in error.\n subscriber.error(error);\n },\n complete() {\n // Run subscriber’s complete() method.\n subscriber.complete();\n },\n });\n // 2.1.error.4 Let innerOptions be a new SubscribeOptions whose signal is subscriber’s subscription controller’s signal.\n const innerOptions = { signal: subscriber.signal };\n // 2.1.error.5 Subscribe to innerObservable given innerObserver and innerOptions.\n subscribeTo(innerObservable, innerObserver, innerOptions);\n },\n complete() {\n // 2.1.complete Run subscriber’s complete() method.\n subscriber.complete();\n },\n });\n // 2.2. Let options be a new SubscribeOptions whose signal is subscriber’s subscription controller’s signal.\n const options = { signal: subscriber.signal };\n // 2.3. Subscribe to sourceObservable given sourceObserver and options.\n subscribeTo(sourceObservable, sourceObserver, options);\n });\n // 3. Return observable.\n return observable;\n }\n\n // https://wicg.github.io/observable/#dom-observable-finally\n finally(callback) {\n if (!(this instanceof Observable))\n throw new TypeError(\"illegal invocation\");\n if (typeof callback !== \"function\")\n throw new TypeError(`Parameter 1 is not of type 'Function'`);\n // 1. Let sourceObservable be this.\n let sourceObservable = this;\n // 2. Let observable be a new Observable whose subscribe callback is an algorithm that takes a Subscriber subscriber and does the following:\n // 3. Return observable.\n return new Observable((subscriber) => {\n // 2.1. Run subscriber’s addTeardown() method with callback.\n subscriber.addTeardown(callback);\n // 2.2. Let sourceObserver be a new internal observer, initialized as follows:\n const sourceObserver = new InternalObserver({\n next(value) {\n // Run subscriber’s next() method, given the passed in value.\n subscriber.next(value);\n },\n error(value) {\n // Run subscriber’s error() method, given the passed in error.\n subscriber.error(value);\n },\n complete() {\n // Run subscriber’s complete() method.\n subscriber.complete();\n },\n });\n // 3. Let options be a new SubscribeOptions whose signal is subscriber’s subscription controller’s signal.\n let options = { signal: subscriber.signal };\n // 4. Subscribe to sourceObservable given sourceObserver and options.\n subscribeTo(sourceObservable, sourceObserver, options);\n });\n }\n\n // https://wicg.github.io/observable/#dom-observable-toarray\n toArray(options = {}) {\n if (!(this instanceof Observable))\n throw new TypeError(\"illegal invocation\");\n // 1. Let p a new promise.\n let { promise: p, resolve, reject } = pWithResolvers();\n // 2. If options’s signal is not null:\n if (options.signal) {\n // 2.1. If options’s signal is aborted, then:\n if (options.signal.aborted) {\n // 2.1.1. Reject p with options’s signal's abort reason.\n // 2.1.2. Return p.\n return Promise.reject(options.signal.reason);\n }\n // 2.2. Add the following abort algorithm to options’s signal:\n options.signal.addEventListener(\"abort\", () => {\n // 2.2.1. Reject p with options’s signal's abort reason.\n reject(options.signal.reason);\n });\n }\n // 3. Let values be a new list.\n let values = [];\n // 4. Let observer be a new internal observer, initialized as follows:\n let observer = new InternalObserver({\n next(value) {\n // Append the passed in value to values.\n values.push(value);\n },\n error(error) {\n // Reject p with the passed in error.\n reject(error);\n },\n complete() {\n // Resolve p with values.\n resolve(values);\n },\n });\n // 5. Subscribe to this given observer and options.\n subscribeTo(this, observer, options);\n // 6. Return p.\n return p;\n }\n\n // https://wicg.github.io/observable/#dom-observable-foreach\n forEach(callback, options = {}) {\n if (!(this instanceof Observable))\n throw new TypeError(\"illegal invocation\");\n if (typeof callback !== \"function\")\n throw new TypeError(`Parameter 1 is not of type 'Function'`);\n // 1. Let p a new promise.\n let { promise: p, resolve, reject } = pWithResolvers();\n // 2. Let visitor callback controller be a new AbortController.\n let visitorCallbackController = new AbortController();\n // 3. Let internal options be a new SubscribeOptions whose signal is the\n // result of creating a dependent abort signal from the list «visitor\n // callback controller’s signal, options’s signal if non-null», using\n // AbortSignal, and the current realm.\n const internalOptions = { signal: anySignal([visitorCallbackController.signal, options.signal]) };\n // 4. If internal options’s signal is aborted, then:\n if (internalOptions.signal.aborted) {\n // 4.1. Reject p with internal options’s signal's abort reason.\n reject(internalOptions.signal.reason);\n // 4.2. Return p.\n return p;\n }\n // 5. Add the following abort algorithm to internal options’s signal:\n internalOptions.signal.addEventListener(\"abort\", () => {\n // Reject p with internal options’s signal's abort reason.\n reject(internalOptions.signal.reason);\n });\n\n // 6. Let idx be an unsigned long long, initially 0.\n let idx = 0;\n // 7. Let observer be a new internal observer, initialized as follows:\n let observer = new InternalObserver({\n next(value) {\n // 1. Invoke callback with the passed in value, and idx.\n try {\n callback(value, idx);\n } catch (e) {\n // If an exception E was thrown, then reject p with E, and signal abort visitor callback controller with E.\n reject(e);\n visitorCallbackController.abort(e);\n }\n // 2. Increment idx.\n idx += 1;\n },\n error(error) {\n // Reject p with the passed in error.\n reject(error);\n },\n complete() {\n // Resolve p with undefined.\n resolve();\n },\n });\n // 8. Subscribe to this given observer and internal options.\n subscribeTo(this, observer, internalOptions);\n // 9. Return p.\n return p;\n }\n\n // https://wicg.github.io/observable/#dom-observable-every\n every(predicate, options = {}) {\n if (!(this instanceof Observable))\n throw new TypeError(\"illegal invocation\");\n if (typeof predicate !== \"function\")\n throw new TypeError(`Parameter 1 is not of type 'Function'`);\n // 1. Let p a new promise.\n let { promise: p, resolve, reject } = pWithResolvers();\n // 2. Let controller be a new AbortController.\n let controller = new AbortController();\n // 3. Let internal options be a new SubscribeOptions whose signal is the\n // result of creating a dependent abort signal from the list «controller’s\n // signal, options’s signal if non-null», using AbortSignal, and the\n // current realm.\n const internalOptions = { signal: anySignal([controller.signal, options.signal]) };\n // 4. If internal options’s signal is aborted, then:\n if (internalOptions.signal.aborted) {\n // 4.1. Reject p with internal options’s signal's abort reason.\n reject(internalOptions.signal.reason);\n // 4.2. Return p.\n return p;\n }\n // 5. Add the following abort algorithm to internal options’s signal:\n internalOptions.signal.addEventListener(\"abort\", () => {\n // Reject p with internal options’s signal's abort reason.\n reject(internalOptions.signal.reason);\n });\n\n // 6. Let idx be an unsigned long long, initially 0.\n let idx = 0;\n // 7. Let observer be a new internal observer, initialized as follows:\n let observer = new InternalObserver({\n next(value) {\n let passed = false;\n // 1. Invoke predicate with the passed in value, and idx.\n try {\n passed = predicate(value, idx);\n } catch (e) {\n // If an exception E was thrown, then reject p with E, and signal abort visitor callback controller with E.\n reject(e);\n controller.abort(e);\n }\n // 2. Set idx to idx + 1.\n idx += 1;\n // 3. If passed is false, then resolve p with false, and signal abort controller.\n if (!passed) {\n resolve(false);\n controller.abort();\n }\n },\n error(error) {\n // Reject p with the passed in error.\n reject(error);\n },\n complete() {\n // Resolve p with true.\n resolve(true);\n },\n });\n // 8. Subscribe to this given observer and internal options.\n subscribeTo(this, observer, internalOptions);\n // 9. Return p.\n return p;\n }\n\n // https://wicg.github.io/observable/#dom-observable-first\n first(options = {}) {\n if (!(this instanceof Observable))\n throw new TypeError(\"illegal invocation\");\n // 1. Let p a new promise.\n let { promise: p, resolve, reject } = pWithResolvers();\n // 2. Let controller be a new AbortController.\n let controller = new AbortController();\n // 3. Let internal options be a new SubscribeOptions whose signal is the\n // result of creating a dependent abort signal from the list «controller’s\n // signal, options’s signal if non-null», using AbortSignal, and the\n // current realm.\n const internalOptions = { signal: anySignal([controller.signal, options.signal]) };\n // 4. If internal options’s signal is aborted, then:\n if (internalOptions.signal.aborted) {\n // 4.1. Reject p with internal options’s signal's abort reason.\n reject(internalOptions.signal.reason);\n // 4.2. Return p.\n return p;\n }\n // 5. Add the following abort algorithm to internal options’s signal:\n internalOptions.signal.addEventListener(\"abort\", () => {\n // Reject p with internal options’s signal's abort reason.\n reject(internalOptions.signal.reason);\n });\n // 6. Let observer be a new internal observer, initialized as follows:\n let observer = new InternalObserver({\n next(value) {\n // 1. Resolve p with the passed in value.\n resolve(value);\n // 2. Signal abort controller.\n controller.abort();\n },\n error(error) {\n // Reject p with the passed in error.\n reject(error);\n },\n complete() {\n // Reject p with a new RangeError.\n // Note: This is only reached when the source Observable completes before it emits a single value.\n reject(new RangeError('No values in Observable'));\n },\n });\n // 7. Subscribe to this given internal observer and internal options.\n subscribeTo(this, observer, internalOptions);\n // 8. Return p.\n return p;\n }\n\n // https://wicg.github.io/observable/#dom-observable-last\n last(options = {}) {\n if (!(this instanceof Observable))\n throw new TypeError(\"illegal invocation\");\n // 1. Let p a new promise.\n let { promise: p, resolve, reject } = pWithResolvers();\n // 2. If options’s signal is not null:\n if (options.signal) {\n // 2.1. If options’s signal is aborted, then:\n if (options.signal.aborted) {\n // 2.1.1 Reject p with options’s signal's abort reason.\n reject(options.signal.reason);\n // 2.1.2 Return p.\n return p;\n }\n // 2.2. Add the following abort algorithm to options’s signal:\n options.signal.addEventListener(\"abort\", () => {\n // Reject p with internal options’s signal's abort reason.\n reject(options.signal.reason);\n });\n }\n // 3. Let lastValue be an any-or-null, initially null.\n let lastValue = null;\n // 4. Let hasLastValue be a boolean, initially false.\n let hasLastValue = false;\n // 5. Let observer be a new internal observer, initialized as follows:\n let observer = new InternalObserver({\n next(value) {\n // 1. Set hasLastValue to true.\n hasLastValue = true;\n // 2. Set lastValue to the passed in value.\n lastValue = value;\n },\n error(error) {\n // Reject p with the passed in error.\n reject(error);\n },\n complete() {\n // 1. If hasLastValue is true, resolve p with lastValue.\n if (hasLastValue) resolve(lastValue);\n // 2. Otherwise, reject p with a new RangeError.\n else reject(new RangeError('No values in Observable'));\n },\n });\n // 5. Subscribe to this given observer and options.\n subscribeTo(this, observer, options);\n // 6. Return p.\n return p;\n }\n\n // https://wicg.github.io/observable/#dom-observable-find\n find(predicate, options = {}) {\n if (!(this instanceof Observable))\n throw new TypeError(\"illegal invocation\");\n if (typeof predicate !== \"function\")\n throw new TypeError(`Parameter 1 is not of type 'Function'`);\n // 1. Let p a new promise.\n let { promise: p, resolve, reject } = pWithResolvers();\n // 2. Let controller be a new AbortController.\n let controller = new AbortController();\n // 3. Let internal options be a new SubscribeOptions whose signal is the\n // result of creating a dependent abort signal from the list «controller’s\n // signal, options’s signal if non-null», using AbortSignal, and the\n // current realm.\n const internalOptions = { signal: anySignal([controller.signal, options.signal]) };\n // 4. If internal options’s signal is aborted, then:\n if (internalOptions.signal.aborted) {\n // 4.1. Reject p with internal options’s signal's abort reason.\n reject(internalOptions.signal.reason);\n // 4.2. Return p.\n return p;\n }\n // 5. Add the following abort algorithm to internal options’s signal:\n internalOptions.signal.addEventListener(\"abort\", () => {\n // Reject p with internal options’s signal's abort reason.\n reject(internalOptions.signal.reason);\n });\n\n // 6. Let idx be an unsigned long long, initially 0.\n let idx = 0;\n // 7. Let observer be a new internal observer, initialized as follows:\n let observer = new InternalObserver({\n next(value) {\n let passed = false;\n // 1. Invoke predicate with the passed in value, and idx.\n try {\n passed = predicate(value, idx);\n } catch (e) {\n // If an exception E was thrown, then reject p with E, and signal abort visitor callback controller with E.\n reject(e);\n controller.abort(e);\n }\n // 2. Set idx to idx + 1.\n idx += 1;\n // 3. If passed is true, then resolve p with value, and signal abort controller.\n if (passed) {\n resolve(value);\n controller.abort();\n }\n },\n error(error) {\n // Reject p with the passed in error.\n reject(error);\n },\n complete() {\n // Resolve p with undefined.\n resolve();\n },\n });\n // 8. Subscribe to this given observer and internal options.\n subscribeTo(this, observer, internalOptions);\n // 9. Return p.\n return p;\n }\n\n // https://wicg.github.io/observable/#dom-observable-some\n some(predicate, options = {}) {\n if (!(this instanceof Observable))\n throw new TypeError(\"illegal invocation\");\n if (typeof predicate !== \"function\")\n throw new TypeError(`Parameter 1 is not of type 'Function'`);\n // 1. Let p a new promise.\n let { promise: p, resolve, reject } = pWithResolvers();\n // 2. Let controller be a new AbortController.\n let controller = new AbortController();\n // 3. Let internal options be a new SubscribeOptions whose signal is the\n // result of creating a dependent abort signal from the list «controller’s\n // signal, options’s signal if non-null», using AbortSignal, and the\n // current realm.\n const internalOptions = { signal: anySignal([controller.signal, options.signal]) };\n // 4. If internal options’s signal is aborted, then:\n if (internalOptions.signal.aborted) {\n // 4.1. Reject p with internal options’s signal's abort reason.\n reject(internalOptions.signal.reason);\n // 4.2. Return p.\n return p;\n }\n // 5. Add the following abort algorithm to internal options’s signal:\n internalOptions.signal.addEventListener(\"abort\", () => {\n // Reject p with internal options’s signal's abort reason.\n reject(internalOptions.signal.reason);\n });\n\n // 6. Let idx be an unsigned long long, initially 0.\n let idx = 0;\n // 7. Let observer be a new internal observer, initialized as follows:\n let observer = new InternalObserver({\n next(value) {\n let passed = false;\n // 1. Invoke predicate with the passed in value, and idx.\n try {\n passed = predicate(value, idx);\n } catch (e) {\n // If an exception E was thrown, then reject p with E, and signal abort controller with E.\n reject(e);\n controller.abort(e);\n }\n // 2. Set idx to idx + 1.\n idx += 1;\n // 3. If passed is true, then resolve p with true, and signal abort controller.\n if (passed) {\n resolve(true);\n controller.abort();\n }\n },\n error(error) {\n // Reject p with the passed in error.\n reject(error);\n },\n complete() {\n // Resolve p with false.\n resolve(false);\n },\n });\n // 8. Subscribe to this given observer and internal options.\n subscribeTo(this, observer, internalOptions);\n // 9. Return p.\n return p;\n }\n\n // https://wicg.github.io/observable/#dom-observable-reduce\n reduce(reducer, initialValue, options = {}) {\n if (!(this instanceof Observable))\n throw new TypeError(\"illegal invocation\");\n if (typeof reducer !== \"function\")\n throw new TypeError(`Parameter 1 is not of type 'Function'`);\n // 1. Let p a new promise.\n let { promise: p, resolve, reject } = pWithResolvers();\n // 2. Let controller be a new AbortController.\n const controller = new AbortController();\n // 3. Let internal options be a new SubscribeOptions whose signal is the\n // result of creating a dependent abort signal from the list «controller’s\n // signal, options’s signal if non-null», using AbortSignal, and the\n // current realm.\n const internalOptions = { signal: anySignal([controller.signal, options.signal]) };\n // 4. If internal options’s signal is aborted, then:\n if (internalOptions.signal.aborted) {\n // 4.1 Reject p with internal options’s signal’s abort reason.\n reject(internalOptions.signal.reason);\n // 4.2 Return p.\n return p;\n }\n // 5. Add the following abort algorithm to internal options’s signal:\n internalOptions.signal.addEventListener(\"abort\", () => {\n // 5.1 Reject p with internal options’s signal’s abort reason.\n reject(internalOptions.signal.reason);\n }, { once: true });\n // 6. Let idx be an unsigned long long, initially 0.\n let idx = 0;\n // 7. Let accumulator be initialValue if it is given, and uninitialized otherwise.\n let accumulator = arguments.length > 1 ? initialValue : unset;\n // 8. Let observer be a new internal observer, initialized as follows:\n const observer = new InternalObserver({\n // next steps\n next(value) {\n // 8.1 If accumulator is uninitialized (meaning no initialValue was passed in), then set accumulator to the passed in value, set idx to idx + 1, and abort these steps.\n if (accumulator === unset) {\n accumulator = value;\n idx++;\n return;\n }\n try {\n // 8.2 Invoke reducer with «accumulator as accumulator, the passed in value as currentValue, idx as index» and \"rethrow\". Let result be the returned value.\n const result = reducer(accumulator, value, idx);\n // 8.3 Set idx to idx + 1.\n idx++;\n // 8.4 Set accumulator to result.\n accumulator = result;\n } catch (e) {\n // 8.2-error If an exception E was thrown, then reject p with E, and signal abort controller with E.\n reject(e);\n controller.abort(e);\n return;\n }\n },\n // error steps\n error(error) {\n // Reject p with the passed in error.\n reject(error);\n },\n // complete steps\n complete() {\n // 1. If accumulator is not \"unset\", then resolve p with accumulator.\n // Otherwise, reject p with a TypeError.\n if (accumulator !== unset) {\n resolve(accumulator);\n } else {\n reject(new TypeError('no initial value provided and no values emitted'));\n }\n },\n });\n // 9. Subscribe to this given observer and internal options.\n subscribeTo(this, observer, internalOptions);\n // 10. Return p.\n return p;\n }\n }\n\n enumerate(Observable.prototype, \"subscribe\");\n\n return [Observable, Subscriber];\n})();\n\nfunction isSupported() {\n return typeof globalThis.Observable === \"function\";\n}\n\nfunction isPolyfilled() {\n return globalThis.Observable === Observable;\n}\n\nfunction apply() {\n Object.defineProperties(globalThis, {\n Observable: {\n value: Observable,\n configurable: true,\n writable: true,\n },\n Subscriber: {\n value: Subscriber,\n configurable: true,\n writable: true,\n },\n });\n\n EventTarget.prototype.when = function (type, options = {}) {\n // Step 1: If this’s relevant global object is a Window object, and its associated Document is not fully active, then return.\n if (isBrowserContext() && !isDocumentFullyActive(document)) return;\n\n // Step 2: Let event target be this.\n const eventTarget = this;\n\n // Step 3: Let observable be a new Observable, initialized with a subscribe callback.\n return new Observable((subscriber) => {\n // Step 3.1: If event target is null, abort these steps.\n if (!eventTarget) return;\n\n // Step 3.2: If subscriber’s subscription controller’s signal is aborted, then return.\n if (subscriber.signal.aborted) return;\n\n // Step 3.3: Add an event listener with the following configuration:\n // - type: type (passed as argument)\n // - callback: A new Web IDL EventListener instance that invokes subscriber.next(event)\n // - capture: options.capture (default false)\n // - passive: options.passive (default undefined)\n // - once: false (explicitly set per spec)\n // - signal: subscriber.signal (for aborting the subscription)\n const listener = (event) => {\n // Observable event listener invoke algorithm: Run subscriber’s next() method with event.\n subscriber.next(event);\n };\n\n eventTarget.addEventListener(type, listener, {\n capture: options.capture || false,\n passive: options.passive,\n once: false, // Explicitly false as required by spec\n signal: subscriber.signal,\n });\n });\n };\n}\n\nexport { Observable, Subscriber, isPolyfilled, isSupported, apply };\n","/**\n * Collision detection algorithms for drag and drop interactions\n * Based on dnd-kit collision detection strategies\n */\n\nexport type CollisionDetectionAlgorithm =\n | 'pointerWithin'\n | 'rectangleIntersection'\n | 'closestCenter'\n | 'closestCorners'\n | 'closestCornersWithInventoryPriority';\n\nexport interface CollisionDetectionOptions {\n algorithm: CollisionDetectionAlgorithm;\n}\n\nexport interface CollisionDetectionStrategy {\n (\n dropzones: HTMLElement[],\n clientX: number,\n clientY: number,\n dragElement?: HTMLElement | null,\n dragContainers?: HTMLElement[]\n ): HTMLElement | null;\n}\n\n/**\n * Pointer Within Algorithm\n * Only registers collision when the pointer is contained within the bounding rectangle\n * of the droppable container. Best for high-precision interfaces.\n */\nexport function pointerWithinCollision(dropzones: HTMLElement[], clientX: number, clientY: number): HTMLElement | null {\n const activeZones = dropzones.filter(zone => !zone.hasAttribute('disabled'));\n\n for (const zone of activeZones) {\n const rect = zone.getBoundingClientRect();\n if (clientX >= rect.left && clientX <= rect.right && clientY >= rect.top && clientY <= rect.bottom) {\n return zone;\n }\n }\n\n return null;\n}\n\n/**\n * Rectangle Intersection Algorithm\n * Ensures there is no gap between any of the 4 sides of the rectangles.\n * A draggable is considered over a droppable only when their bounding boxes physically intersect.\n */\nexport function rectangleIntersectionCollision(\n dropzones: HTMLElement[],\n _clientX: number,\n _clientY: number,\n dragElement?: HTMLElement | null\n): HTMLElement | null {\n if (!dragElement) return null;\n\n const activeZones = dropzones.filter(zone => !zone.hasAttribute('disabled'));\n const dragRect = dragElement.getBoundingClientRect();\n\n for (const zone of activeZones) {\n const dropRect = zone.getBoundingClientRect();\n\n // Check if rectangles intersect\n const intersects = !(\n dragRect.right < dropRect.left ||\n dragRect.left > dropRect.right ||\n dragRect.bottom < dropRect.top ||\n dragRect.top > dropRect.bottom\n );\n\n if (intersects) {\n return zone;\n }\n }\n\n return null;\n}\n\n/**\n * Closest Center Algorithm\n * Identifies the droppable container whose center is closest to the center\n * of the bounding rectangle of the active draggable item.\n * Recommended for sortable lists.\n */\nexport function closestCenterCollision(\n dropzones: HTMLElement[],\n clientX: number,\n clientY: number,\n dragElement?: HTMLElement | null\n): HTMLElement | null {\n const activeZones = dropzones.filter(zone => !zone.hasAttribute('disabled'));\n if (activeZones.length === 0) return null;\n\n // Calculate drag center (use pointer or element center)\n let dragCenterX: number;\n let dragCenterY: number;\n\n if (dragElement) {\n const dragRect = dragElement.getBoundingClientRect();\n dragCenterX = dragRect.left + dragRect.width / 2;\n dragCenterY = dragRect.top + dragRect.height / 2;\n } else {\n dragCenterX = clientX;\n dragCenterY = clientY;\n }\n\n let closestZone: HTMLElement | null = null;\n let minDistance = Infinity;\n\n for (const zone of activeZones) {\n const rect = zone.getBoundingClientRect();\n const centerX = rect.left + rect.width / 2;\n const centerY = rect.top + rect.height / 2;\n\n const distance = Math.sqrt(Math.pow(dragCenterX - centerX, 2) + Math.pow(dragCenterY - centerY, 2));\n\n if (distance < minDistance) {\n minDistance = distance;\n closestZone = zone;\n }\n }\n\n return closestZone;\n}\n\n/**\n * Closest Corners Algorithm\n * Measures the distance between all four corners of the active draggable item\n * and the four corners of each droppable container.\n * Preferred for Kanban boards and interfaces with stacked droppable containers.\n *\n * Uses average corner distance rather than minimum to reduce flickering.\n */\nexport function closestCornersCollision(\n dropzones: HTMLElement[],\n clientX: number,\n clientY: number,\n dragElement?: HTMLElement | null\n): HTMLElement | null {\n const activeZones = dropzones.filter(zone => !zone.hasAttribute('disabled'));\n if (activeZones.length === 0) return null;\n\n // Get drag corners (use pointer or element corners)\n let dragCorners: { x: number; y: number }[];\n\n if (dragElement) {\n const dragRect = dragElement.getBoundingClientRect();\n dragCorners = [\n { x: dragRect.left, y: dragRect.top },\n { x: dragRect.right, y: dragRect.top },\n { x: dragRect.left, y: dragRect.bottom },\n { x: dragRect.right, y: dragRect.bottom }\n ];\n } else {\n // If no drag element, use pointer as all corners\n dragCorners = [\n { x: clientX, y: clientY },\n { x: clientX, y: clientY },\n { x: clientX, y: clientY },\n { x: clientX, y: clientY }\n ];\n }\n\n let closestZone: HTMLElement | null = null;\n let minAverageDistance = Infinity;\n\n for (const zone of activeZones) {\n const rect = zone.getBoundingClientRect();\n const dropCorners = [\n { x: rect.left, y: rect.top },\n { x: rect.right, y: rect.top },\n { x: rect.left, y: rect.bottom },\n { x: rect.right, y: rect.bottom }\n ];\n\n // Calculate average distance between all corner pairs\n let totalDistance = 0;\n let pairCount = 0;\n\n for (const dragCorner of dragCorners) {\n for (const dropCorner of dropCorners) {\n const distance = Math.sqrt(Math.pow(dragCorner.x - dropCorner.x, 2) + Math.pow(dragCorner.y - dropCorner.y, 2));\n totalDistance += distance;\n pairCount++;\n }\n }\n\n const averageDistance = totalDistance / pairCount;\n\n // Use average distance to reduce sensitivity and flickering\n if (averageDistance < minAverageDistance) {\n minAverageDistance = averageDistance;\n closestZone = zone;\n }\n }\n\n return closestZone;\n}\n\n/**\n * Closest Corners with Inventory Priority Algorithm\n * Similar to closestCorners but gives priority to drag containers (inventory slots).\n * When a draggable is within reasonable range of a drag container, it will prefer\n * the drag container over other dropzones. This makes it easier to return items\n * to the inventory without having to drag them far away from other drop zones.\n *\n * Uses a threshold-based approach:\n * - If drag container distance is within a threshold multiplier, prefer it\n * - Otherwise, use standard closest corners logic\n */\nexport function closestCornersWithInventoryPriorityCollision(\n dropzones: HTMLElement[],\n clientX: number,\n clientY: number,\n dragElement?: HTMLElement | null,\n dragContainers?: HTMLElement[]\n): HTMLElement | null {\n // Separate drag containers from regular droppables BEFORE filtering by disabled\n // Drag containers (inventory) should always be available for dropping\n // Use the provided dragContainers array if available, otherwise fall back to detecting by attributes\n const identifiedDragContainers =\n dragContainers && dragContainers.length > 0\n ? dropzones.filter(zone => dragContainers.includes(zone))\n : dropzones.filter(\n zone => zone.tagName === 'SLOT' && zone.hasAttribute('part') && zone.getAttribute('part')?.includes('drags')\n );\n const allRegularDroppables = dropzones.filter(zone => !identifiedDragContainers.includes(zone));\n\n // Keep disabled droppables in collision resolution.\n // They remain non-droppable via allowDrop(), but this lets drag-end detect\n // \"attempted drop on disabled target\" and trigger proper invalid/max messaging.\n const regularDroppables = allRegularDroppables;\n\n if (identifiedDragContainers.length === 0 && regularDroppables.length === 0) return null;\n\n // Get drag corners (use pointer or element corners)\n let dragCorners: { x: number; y: number }[];\n\n if (dragElement) {\n const dragRect = dragElement.getBoundingClientRect();\n dragCorners = [\n { x: dragRect.left, y: dragRect.top },\n { x: dragRect.right, y: dragRect.top },\n { x: dragRect.left, y: dragRect.bottom },\n { x: dragRect.right, y: dragRect.bottom }\n ];\n } else {\n // If no drag element, use pointer as all corners\n dragCorners = [\n { x: clientX, y: clientY },\n { x: clientX, y: clientY },\n { x: clientX, y: clientY },\n { x: clientX, y: clientY }\n ];\n }\n\n const calculateAverageDistance = (zone: HTMLElement): number => {\n const rect = zone.getBoundingClientRect();\n const dropCorners = [\n { x: rect.left, y: rect.top },\n { x: rect.right, y: rect.top },\n { x: rect.left, y: rect.bottom },\n { x: rect.right, y: rect.bottom }\n ];\n\n let totalDistance = 0;\n let pairCount = 0;\n\n for (const dragCorner of dragCorners) {\n for (const dropCorner of dropCorners) {\n const distance = Math.sqrt(Math.pow(dragCorner.x - dropCorner.x, 2) + Math.pow(dragCorner.y - dropCorner.y, 2));\n totalDistance += distance;\n pairCount++;\n }\n }\n\n return totalDistance / pairCount;\n };\n\n // Find closest drag container\n let closestDragContainer: HTMLElement | null = null;\n let minDragContainerDistance = Infinity;\n\n for (const container of identifiedDragContainers) {\n const distance = calculateAverageDistance(container);\n if (distance < minDragContainerDistance) {\n minDragContainerDistance = distance;\n closestDragContainer = container;\n }\n }\n\n // Find closest regular droppable\n let closestDroppable: HTMLElement | null = null;\n let minDroppableDistance = Infinity;\n\n for (const droppable of regularDroppables) {\n const distance = calculateAverageDistance(droppable);\n if (distance < minDroppableDistance) {\n minDroppableDistance = distance;\n closestDroppable = droppable;\n }\n }\n\n // FIRST: Check if pointer/drag is actually INSIDE any drag container\n // If the user is hovering directly over inventory, give it absolute priority\n if (closestDragContainer && dragElement) {\n const dragRect = dragElement.getBoundingClientRect();\n const containerRect = closestDragContainer.getBoundingClientRect();\n\n // Check if drag element's center is inside the container\n const dragCenterX = dragRect.left + dragRect.width / 2;\n const dragCenterY = dragRect.top + dragRect.height / 2;\n\n const isInsideContainer =\n dragCenterX >= containerRect.left &&\n dragCenterX <= containerRect.right &&\n dragCenterY >= containerRect.top &&\n dragCenterY <= containerRect.bottom;\n\n if (isInsideContainer) {\n return closestDragContainer;\n }\n }\n\n // SECOND: Use distance-based priority with threshold.\n // For drags that originate from a dropzone, avoid over-prioritizing inventory:\n // users typically expect the item to remain in/return to a dropzone unless they\n // explicitly drag into the inventory container.\n const dragOrigin = dragElement?.getAttribute('data-drag-origin');\n const inventoryPriorityThreshold = dragOrigin === 'droppable' ? 0.85 : 1.5;\n\n if (closestDragContainer && closestDroppable) {\n // If drag container is close enough, prefer it\n if (minDragContainerDistance <= minDroppableDistance * inventoryPriorityThreshold) {\n return closestDragContainer;\n }\n return closestDroppable;\n }\n\n // Return whichever is available\n const result = closestDragContainer || closestDroppable;\n return result;\n}\n\n/**\n * Get the collision detection strategy based on the algorithm name\n */\nexport function getCollisionDetectionStrategy(algorithm: CollisionDetectionAlgorithm): CollisionDetectionStrategy {\n switch (algorithm) {\n case 'pointerWithin':\n return pointerWithinCollision;\n case 'rectangleIntersection':\n return rectangleIntersectionCollision;\n case 'closestCenter':\n return closestCenterCollision;\n case 'closestCorners':\n return closestCornersCollision;\n case 'closestCornersWithInventoryPriority':\n return closestCornersWithInventoryPriorityCollision;\n default:\n return pointerWithinCollision;\n }\n}\n\n/**\n * Main collision detection function that delegates to the appropriate strategy\n */\nexport function detectCollision(\n dropzones: HTMLElement[],\n clientX: number,\n clientY: number,\n dragElement?: HTMLElement | null,\n algorithm: CollisionDetectionAlgorithm = 'pointerWithin',\n dragContainers?: HTMLElement[]\n): HTMLElement | null {\n const strategy = getCollisionDetectionStrategy(algorithm);\n return strategy(dropzones, clientX, clientY, dragElement, dragContainers);\n}\n","export function findDraggableTarget(event: Event, draggablesSelector: string): HTMLElement | null {\n const composedPath = event.composedPath ? event.composedPath() : [event.target];\n\n for (const element of composedPath) {\n if (element instanceof HTMLElement && element.tagName !== 'SLOT') {\n if (element.matches(draggablesSelector) || element.hasAttribute('qti-draggable')) {\n return element;\n }\n\n const closest = element.closest(draggablesSelector) || element.closest('[qti-draggable=\"true\"]');\n if (closest) {\n return closest as HTMLElement;\n }\n }\n }\n\n return null;\n}\n\n/**\n * Draggable chips express `disabled` through ElementInternals — the ARIA property feeds the\n * accessibility tree and the custom state feeds CSS. The `aria-disabled` attribute is not\n * reflected, so it cannot be read back off the element.\n *\n * A bare `disabled` attribute is still honoured as an authoring escape hatch.\n */\nexport function isDraggableDisabled(target: HTMLElement | null | undefined): boolean {\n if (!target) return false;\n if (target.hasAttribute('disabled')) return true;\n\n const internals = (target as { internals?: ElementInternals }).internals;\n return internals?.states?.has('disabled') ?? false;\n}\n\n/**\n * Presentation states on a source chip in the drag bank. Both leave a hole where the chip was,\n * and both are styled by CSS rather than by writing `element.style.opacity` from here.\n *\n * - `dragging` — this chip's clone is currently following the cursor.\n * - `placeholder` — this chip's copy sits in a dropzone (`matchMax` reached).\n *\n * They are distinct: a theme may want a dashed outline while dragging and a solid inset box\n * once placed.\n */\nexport type DragChipState = 'dragging' | 'placeholder' | 'return-anchor';\n\nconst internalsOf = (el: HTMLElement | null | undefined): ElementInternals | undefined =>\n (el as { internals?: ElementInternals } | null | undefined)?.internals;\n\nexport function setDragChipState(el: HTMLElement | null | undefined, state: DragChipState, on: boolean): void {\n const states = internalsOf(el)?.states;\n if (!states) return;\n if (on) states.add(state);\n else states.delete(state);\n}\n\nexport function hasDragChipState(el: HTMLElement | null | undefined, state: DragChipState): boolean {\n return internalsOf(el)?.states?.has(state) ?? false;\n}\n\n/** Clear both hole-leaving states — the chip is back in the bank and interactive again. */\nexport function clearDragChipStates(el: HTMLElement | null | undefined): void {\n setDragChipState(el, 'dragging', false);\n setDragChipState(el, 'placeholder', false);\n setDragChipState(el, 'return-anchor', false);\n}\n\n/** A chip that currently leaves a hole: not draggable, and skipped by keyboard navigation. */\nexport function isDragChipHidden(el: HTMLElement | null | undefined): boolean {\n return hasDragChipState(el, 'dragging') || hasDragChipState(el, 'placeholder');\n}\n\n/**\n * Mark a drop target as holding at least one chip.\n *\n * Two spellings, because the five drop targets are not the same kind of thing and cannot be made\n * so. `qti-gap`, `qti-associable-hotspot` and `qti-simple-associable-choice` are custom elements\n * with an `ElementInternals`, so they take a real custom state. Order's and associate's targets are\n * plain `<div part=\"drop\">` in the interaction's shadow root, and **a div cannot carry\n * `:state()`** — there is no `attachInternals` for it. They take an extra part token instead.\n *\n * Both are reachable, and a theme addresses them the same way it addresses a chip's three homes:\n *\n * :state(filled) the light-DOM custom-element targets\n * ::part(filled) the shadow-resident divs — and `::part(drop)` still matches them\n *\n * Verified in Chromium: an extra part token does not stop `::part(drop)` matching, and an unfilled\n * target matches neither.\n *\n * Replaces `data-has-drop`, which was set in exactly one of the branches that could set it and\n * removed in two that could not.\n */\n/**\n * Flags a drop target carries, readable from a theme.\n *\n * `filled` — holds at least one chip\n * `active` — a drag is in progress and this target could receive it\n * `enabled` — same, kept distinct because the themes distinguish them\n * `hover` — the chip is currently over this target\n */\nexport type DropFlag = 'filled' | 'active' | 'enabled' | 'hover';\n\n/**\n * Set a flag on a drop target, in the only spelling that element can carry.\n *\n * Verified in Chromium, and it is the whole reason there are two spellings:\n *\n * ::part(x):state(y) MATCHES — but only when x is a custom element\n * ::part(x)[attr] never matches\n * ::part(x):has(…) never matches\n * ::part(y) (token) MATCHES — on anything\n *\n * A plain `<div>` cannot carry a custom state: `attachInternals()` throws NotSupportedError. So\n * order's and associate's `<div part=\"drop\">` take an extra part token, and a theme reaches them as\n * `::part(active)`. The custom-element targets take a real state.\n *\n * The plain attribute is written too, because shadow-internal styles and existing vendor rules\n * still select on it. Nothing reads it from the document — nothing can.\n */\nexport function setDropFlag(el: HTMLElement | null | undefined, flag: DropFlag, on: boolean): void {\n if (!el) return;\n\n if (on) el.setAttribute(flag, '');\n else el.removeAttribute(flag);\n\n const states = internalsOf(el)?.states;\n if (states) {\n if (on) states.add(flag);\n else states.delete(flag);\n return;\n }\n\n const tokens = new Set((el.getAttribute('part') ?? '').split(/\\s+/).filter(Boolean));\n // Only a drop target takes the token. `allDropzones` also holds the drag container — a\n // `<slot part=\"drags\">` — and stamping it would rewrite a part list that other selectors read.\n if (!tokens.has('drop')) return;\n if (on) tokens.add(flag);\n else tokens.delete(flag);\n el.setAttribute('part', [...tokens].join(' '));\n}\n\nexport function setDropFilled(el: HTMLElement | null | undefined, filled: boolean): void {\n setDropFlag(el, 'filled', filled);\n}\n\n/** Does this drop target currently hold a chip? Reads whichever spelling the target uses. */\nexport function isDropFilled(el: HTMLElement | null | undefined): boolean {\n if (!el) return false;\n const states = internalsOf(el)?.states;\n if (states) return states.has('filled');\n return (el.getAttribute('part') ?? '').split(/\\s+/).includes('filled');\n}\n\n// Re-export collision detection types and functions for convenience\nexport type { CollisionDetectionAlgorithm } from './collision.utils';\nexport {\n detectCollision,\n getCollisionDetectionStrategy,\n pointerWithinCollision,\n rectangleIntersectionCollision,\n closestCenterCollision,\n closestCornersCollision\n} from './collision.utils';\n\nexport function findInventoryItems(dragContainers: HTMLElement[], identifier: string): HTMLElement[] {\n const items: HTMLElement[] = [];\n\n dragContainers.forEach(container => {\n let matches: Element[] = [];\n\n if (container.tagName.toLowerCase() === 'slot') {\n const slotElement = container as HTMLSlotElement;\n const assignedElements = slotElement.assignedElements({ flatten: true });\n\n matches = assignedElements.filter(el => el.getAttribute('identifier') === identifier);\n } else {\n matches = Array.from(container.querySelectorAll(`[identifier=\"${identifier}\"]`));\n }\n\n items.push(...(matches as HTMLElement[]));\n });\n\n return items;\n}\n\nexport function getMatchMaxValue(draggables: HTMLElement[], identifier: string): number {\n const element = draggables.find(el => el.getAttribute('identifier') === identifier);\n if (!element) return 1;\n\n const matchMax = element.getAttribute('match-max');\n return matchMax ? parseInt(matchMax, 10) || 0 : 1;\n}\n\n/**\n * @deprecated No longer used in production. DragDropSlottedMixin now derives placement once,\n * in `syncDragDropState()`, and publishes it on `dragDropContext`. Kept only because its spec\n * documents the exact counting semantics that method reproduces:\n * response uses the structural selector, capacity uses max(selector, [qti-draggable]).\n * Delete once drop targets render from the context.\n */\nexport function isDroppableAtCapacity(droppable: HTMLElement, draggablesSelector: string): boolean {\n const parsedMatchMax = parseInt(droppable.getAttribute('match-max') || '1', 10);\n const matchMax = Number.isNaN(parsedMatchMax) ? 1 : parsedMatchMax;\n if (matchMax === 0) return false;\n\n const selectorMatches = droppable.querySelectorAll(draggablesSelector);\n const attributeMatches = droppable.querySelectorAll('[qti-draggable=\"true\"]');\n const current = Math.max(selectorMatches.length, attributeMatches.length);\n\n return current >= matchMax;\n}\n\n/**\n * @deprecated No longer used in production. DragDropSlottedMixin now derives placement once,\n * in `syncDragDropState()`, and publishes it on `dragDropContext`. Kept only because its spec\n * documents the exact counting semantics that method reproduces:\n * response uses the structural selector, capacity uses max(selector, [qti-draggable]).\n * Delete once drop targets render from the context.\n */\nexport function countTotalAssociations(droppables: HTMLElement[], draggablesSelector: string): number {\n return droppables.reduce((total, droppable) => {\n const selectorMatches = droppable.querySelectorAll(draggablesSelector).length;\n const attributeMatches = droppable.querySelectorAll('[qti-draggable=\"true\"]').length;\n return total + Math.max(selectorMatches, attributeMatches);\n }, 0);\n}\n\n/**\n * @deprecated No longer used in production. DragDropSlottedMixin now derives placement once,\n * in `syncDragDropState()`, and publishes it on `dragDropContext`. Kept only because its spec\n * documents the exact counting semantics that method reproduces:\n * response uses the structural selector, capacity uses max(selector, [qti-draggable]).\n * Delete once drop targets render from the context.\n */\nexport function collectResponseData(droppables: HTMLElement[], draggablesSelector: string): string[] {\n return droppables\n .map(droppable => {\n const draggablesInDroppable = Array.from(droppable.querySelectorAll<HTMLElement>(draggablesSelector));\n const identifiers = draggablesInDroppable\n .map(element => element.getAttribute('identifier'))\n .filter((identifier): identifier is string => Boolean(identifier));\n const droppableIdentifier = droppable.getAttribute('identifier');\n return identifiers.map(id => `${id} ${droppableIdentifier}`);\n })\n .flat();\n}\n","/**\n * Where a drag clone has to live to be painted, and in which coordinate space it is positioned.\n *\n * The mixin's preferred host is the *interaction's* root node: item-container adopts the theme's\n * item.css into its shadow root, so a clone parked on `document.body` sits in a tree those rules\n * cannot reach - `[data-drag-clone]` goes inert and the chip's grip, a `::before` and so the one\n * thing a computed-style copy cannot carry, disappears the moment the chip is picked up.\n *\n * That preference cannot be unconditional, because of the **Fullscreen API** (exam lockdown /\n * kiosk): the browser paints only the fullscreen element's subtree, in the top layer, which no\n * `z-index` can reach past. A clone outside that subtree is not painted at all, so the dragged\n * element simply disappears while it is held. When the preferred host is *inside* the fullscreen\n * element - the usual case, a player that fullscreens its own wrapper around item-container - it is\n * kept, and the theme still reaches the clone. Only when it is not does the fullscreen element take\n * over as host, trading scoped styling for being visible at all; `createDragClone` inlines the\n * source's computed styles either way.\n *\n * What no host may be is the tree the clone was dragged *out of*: that tree belongs to the\n * interaction, which queries and observes it, and a clone living there is picked up as one of its\n * own elements. The order-interaction press/release conformance test fails exactly that way. The\n * interaction's root sits one level above a placed chip's gap or hotspot shadow root, and the\n * interaction's own queries exclude `[data-drag-clone]`, so it is safe as a host.\n */\n\ntype FullscreenDocument = Document & { webkitFullscreenElement?: Element | null };\ntype FullscreenRoot = ShadowRoot & { fullscreenElement?: Element | null };\n\n/** A node a clone can be appended to. A shadow root is used when its host cannot slot the clone. */\nexport type DragCloneHost = HTMLElement | ShadowRoot;\n\n/**\n * The coordinate space a `position: fixed` clone is laid out in.\n *\n * `fixed` is relative to the viewport only while no ancestor establishes a containing block\n * (`transform`, `filter`, `backdrop-filter`, `perspective`, `contain`, `will-change`, `zoom`).\n * Above item-container that is the integrator's choice, not ours - and a player scaling an item to\n * fit the screen is exactly where such a wrapper appears - so the frame is measured, not assumed.\n */\nexport interface FixedFrame {\n origin: { x: number; y: number };\n scale: { x: number; y: number };\n}\n\n/** Viewport coordinates, no scaling: the frame of a clone hosted by `document.body`. */\nexport const IDENTITY_FIXED_FRAME: FixedFrame = { origin: { x: 0, y: 0 }, scale: { x: 1, y: 1 } };\n\nconst PROBE_SIZE = 100;\n\n/**\n * `document.fullscreenElement` is retargeted against the document: when the element that went\n * fullscreen lives inside a shadow tree, the document reports that tree's host instead. Walk down\n * the shadow trees to find the element that is really fullscreen, otherwise the clone is appended\n * to a host that never renders it.\n */\nconst deepestFullscreenElement = (ownerDocument: FullscreenDocument): HTMLElement | null => {\n let current = (ownerDocument.fullscreenElement ?? ownerDocument.webkitFullscreenElement ?? null) as Element | null;\n\n while (current instanceof HTMLElement) {\n const nested = (current.shadowRoot as FullscreenRoot | null)?.fullscreenElement ?? null;\n if (!nested || nested === current) break;\n current = nested;\n }\n\n return current instanceof HTMLElement ? current : null;\n};\n\n/**\n * Light-DOM children of a shadow host are only painted when the shadow tree has a slot to put them\n * in. Without a default slot the clone would be invisible again, so it goes into the shadow tree.\n */\nconst hostFor = (element: HTMLElement): DragCloneHost => {\n const shadowRoot = element.shadowRoot;\n if (!shadowRoot) return element;\n return shadowRoot.querySelector('slot:not([name])') ? element : shadowRoot;\n};\n\n/**\n * Whether `node` is painted as part of `ancestor`'s subtree. Crosses shadow boundaries upward -\n * `parentNode` is null on a shadow root, where the walk continues through its host.\n */\nconst isInSubtreeOf = (ancestor: Node, node: Node | null): boolean => {\n let current: Node | null = node;\n\n while (current) {\n if (current === ancestor) return true;\n current = current.parentNode ?? (current as ShadowRoot).host ?? null;\n }\n\n return false;\n};\n\n/**\n * Resolves the host for a clone of `dragSource`: `preferredHost` while the browser still paints it,\n * the fullscreen element when it does not, and `document.body` when there is no preferred host.\n */\nexport const resolveDragCloneHost = (dragSource: Node, preferredHost?: DragCloneHost | null): DragCloneHost => {\n const ownerDocument = (dragSource.ownerDocument ?? document) as FullscreenDocument;\n const host = preferredHost ?? ownerDocument.body;\n\n const fullscreenElement = deepestFullscreenElement(ownerDocument);\n if (fullscreenElement && !isInSubtreeOf(fullscreenElement, host)) return hostFor(fullscreenElement);\n\n return host;\n};\n\n/**\n * Measures the frame a `position: fixed` child of `host` is laid out in, using a throwaway probe so\n * the clone's own `transform` / `rotate` cannot skew the reading. Costs one layout per drag start.\n */\nexport const measureFixedFrame = (host: DragCloneHost): FixedFrame => {\n const ownerDocument = host.ownerDocument ?? document;\n const probe = ownerDocument.createElement('div');\n probe.style.cssText =\n `position:fixed;left:0;top:0;width:${PROBE_SIZE}px;height:${PROBE_SIZE}px;` +\n 'margin:0;padding:0;border:0;visibility:hidden;pointer-events:none;';\n\n host.appendChild(probe);\n const rect = probe.getBoundingClientRect();\n probe.remove();\n\n return {\n origin: { x: rect.left, y: rect.top },\n scale: { x: rect.width / PROBE_SIZE || 1, y: rect.height / PROBE_SIZE || 1 }\n };\n};\n\n/** Converts a viewport coordinate into the host's fixed-positioning space. */\nexport const toFrameCoordinates = (frame: FixedFrame, x: number, y: number): { x: number; y: number } => ({\n x: (x - frame.origin.x) / frame.scale.x,\n y: (y - frame.origin.y) / frame.scale.y\n});\n","import { isSupported, apply } from 'observable-polyfill/fn';\n\nimport { interactionContext } from '@qti-components/base';\n\nimport {\n clearDragChipStates,\n detectCollision,\n findDraggableTarget,\n findInventoryItems,\n isDragChipHidden,\n isDraggableDisabled,\n setDragChipState,\n setDropFlag\n} from './utils/drag-drop.utils';\nimport {\n IDENTITY_FIXED_FRAME,\n measureFixedFrame,\n resolveDragCloneHost,\n toFrameCoordinates\n} from './utils/drag-clone-host';\n\nimport type { Interaction } from '@qti-components/base';\nimport type { CollisionDetectionAlgorithm } from './utils/drag-drop.utils';\nimport type { DragCloneHost, FixedFrame } from './utils/drag-clone-host';\n\nif (!isSupported()) apply();\n\n// Global setup for iOS Safari touch events\nconst patchedWindows = new WeakSet<Window>();\n\nfunction patchWindow(window?: Window | null) {\n if (!window || patchedWindows.has(window)) {\n return;\n }\n // This noop touchmove listener with passive: false allows preventDefault() calls\n // to work properly in dynamically added touchmove handlers (iOS Safari fix)\n window.addEventListener('touchmove', () => {}, { capture: false, passive: false });\n patchedWindows.add(window);\n}\n\ntype Constructor<T = {}> = abstract new (...args: any[]) => T;\n\nexport type DragDropCore = Interaction & {\n isDragDropEnabled(): boolean;\n trackedDraggables: HTMLElement[];\n trackedDroppables: HTMLElement[];\n trackedDragContainers: HTMLElement[];\n allDropzones: HTMLElement[];\n dragState: DragState;\n collisionDetectionAlgorithm: CollisionDetectionAlgorithm;\n get response(): string | string[] | null;\n set response(value: string | string[] | null);\n saveResponse(value?: string | string[]): void;\n validate(): boolean;\n reportValidity(): boolean;\n cacheInteractiveElements(): void;\n resetDragState(): void;\n afterCache(): void;\n removeChipFromDroppable(droppable: HTMLElement | null, chip: HTMLElement): void;\n allowDrop(draggable: HTMLElement, droppable: HTMLElement): boolean;\n handleDrop(draggable: HTMLElement, droppable: HTMLElement): void;\n handleInvalidDrop(dragSource: HTMLElement | null): void;\n initiateDrag(\n dragElement: HTMLElement,\n startX: number,\n startY: number,\n inputType: 'mouse' | 'touch',\n eventSource?: 'pointer' | 'mouse' | 'touch',\n pointerId?: number,\n startedFromTrustedEvent?: boolean\n ): void;\n createDragClone(element: HTMLElement, rect: DOMRect): HTMLElement;\n updateClonePosition(clientX: number, clientY: number): void;\n activateAllDroppables(): void;\n setupMoveObservables(inputType: 'mouse' | 'touch', eventSource?: 'pointer' | 'mouse' | 'touch'): void;\n};\n\ninterface DragState {\n dragging: boolean;\n dragSource: HTMLElement | null;\n dragClone: HTMLElement | null;\n startOffset: { x: number; y: number };\n currentTarget: HTMLElement | null;\n sourceDroppable: HTMLElement | null;\n inputType: 'mouse' | 'touch' | null;\n pointerId?: number;\n startedFromTrustedEvent?: boolean;\n initialCoordinates?: { x: number; y: number };\n activationTimeout?: number;\n touchCleanup?: () => void;\n lastTargetChangeTime?: number;\n returnAnchorItems?: HTMLElement[];\n /** Last pointer position, so the clone can be repositioned after it is re-hosted mid-drag. */\n lastCoordinates?: { x: number; y: number };\n}\n\ntype DragEventSource = 'pointer' | 'mouse' | 'touch';\n\ntype StatefulElement = HTMLElement & { internals: ElementInternals };\n\nconst hasStates = (el: HTMLElement): el is StatefulElement =>\n !!(el as { internals?: ElementInternals }).internals?.states;\n\nexport const DragDropCoreMixin = <T extends Constructor<Interaction>>(\n superClass: T,\n draggablesSelector: string,\n droppablesSelector: string,\n dragContainersSelector = 'slot[part=\"drags\"]',\n defaultCollisionAlgorithm: CollisionDetectionAlgorithm = 'pointerWithin'\n) => {\n abstract class DragDropCoreElement extends superClass {\n protected trackedDraggables: HTMLElement[] = [];\n protected trackedDroppables: HTMLElement[] = [];\n protected trackedDragContainers: HTMLElement[] = [];\n protected allDropzones: HTMLElement[] = [];\n\n /**\n * The collision detection algorithm to use for drag and drop\n * Can be overridden by subclasses or configured per interaction type\n */\n public collisionDetectionAlgorithm: CollisionDetectionAlgorithm = defaultCollisionAlgorithm;\n\n protected dragState: DragState = {\n dragging: false,\n dragSource: null,\n dragClone: null,\n startOffset: { x: 0, y: 0 },\n currentTarget: null,\n sourceDroppable: null,\n inputType: null,\n returnAnchorItems: []\n };\n\n /** Coordinate space of the current clone's host; identity while nothing above it scales. */\n private cloneFrame: FixedFrame = IDENTITY_FIXED_FRAME;\n\n private subscriptions: Array<{ unsubscribe: () => void }> = [];\n private dragSubscriptions: Array<{ unsubscribe: () => void }> = [];\n private lastPointerDownAt = 0;\n private lastTouchStartAt = 0;\n #statefulRoleElements = new Set<StatefulElement>();\n\n abstract saveResponse(value?: string | string[]): void;\n\n /**\n * Whether drag-and-drop is live for this interaction. `qti-match-interaction` turns it off\n * in tabular mode, where the choices are a radio/checkbox grid rather than chips.\n */\n public isDragDropEnabled(): boolean {\n return true;\n }\n\n /**\n * Publish how a chip recognises itself. Draggability is positional in match-interaction —\n * the same tag is a source in one match-set and a drop target in the other — so each element\n * tests itself against this selector rather than being told.\n */\n protected publishDraggablesSelector(): void {\n const selector = this.isDragDropEnabled() ? draggablesSelector : null;\n if (this._interactionContext.draggablesSelector !== selector) {\n this._interactionContext = { ...this._interactionContext, draggablesSelector: selector };\n }\n }\n\n override connectedCallback(): void {\n super.connectedCallback();\n // Capture phase: @lit/context's provider stops the event in the bubble phase.\n this.addEventListener('context-request', this.#onContextRequest, { capture: true });\n patchWindow(this.ownerDocument?.defaultView);\n this.publishDraggablesSelector();\n this.setupDragDrop();\n }\n\n override disconnectedCallback(): void {\n super.disconnectedCallback();\n this.removeEventListener('context-request', this.#onContextRequest, { capture: true });\n this.#contextConsumers.clear();\n this.cleanup();\n }\n\n protected async setupDragDrop(): Promise<void> {\n await this.updateComplete;\n\n this.cacheInteractiveElements();\n this.afterCache();\n this.setupDragObservables();\n }\n\n public afterCache(): void {\n // Extension hook\n }\n\n /**\n * Detach a chip from the target holding it.\n *\n * Default: the chip is a DOM child of the target, so removing the node is enough. A target that\n * renders its own chips from `dragDropContext` overrides this — see `DragDropSlottedMixin`.\n */\n public removeChipFromDroppable(_droppable: HTMLElement | null, chip: HTMLElement): void {\n chip.remove();\n }\n\n /**\n * Every element that has asked this interaction for `interactionContext`.\n *\n * A chip announces itself: `ContextConsumer` dispatches `context-request` with\n * `bubbles: true, composed: true`, so the event crosses shadow boundaries that\n * `querySelectorAll` cannot. That is what makes a chip rendered *inside a drop target's shadow\n * root* discoverable at all — `this.querySelectorAll(draggablesSelector)` stops at the\n * boundary, and so does `droppable.contains(chip)`.\n *\n * Two details of @lit/context decide the shape of this:\n *\n * - the provider calls `stopPropagation()` once it satisfies a request, so this listener has\n * to run in the **capture** phase to see the event at all;\n * - `event.target` is retargeted to the shadow host and is useless here. The event carries\n * `contextTarget`, the real requester, which is what the provider itself reads.\n *\n * There is no counterpart \"consumer disconnected\" event — @lit/context unsubscribes through a\n * closure — so entries are pruned lazily by `isConnected`.\n */\n #contextConsumers = new Set<HTMLElement>();\n\n #onContextRequest = (event: Event): void => {\n const request = event as Event & { context?: unknown; contextTarget?: Element };\n if (request.context !== interactionContext) return;\n const consumer = request.contextTarget;\n if (consumer instanceof HTMLElement) this.#contextConsumers.add(consumer);\n };\n\n /** Registered consumers matching `selector`, minus the ones that have since left the DOM. */\n protected registeredMatching(selector: string): HTMLElement[] {\n for (const el of this.#contextConsumers) {\n if (!el.isConnected) this.#contextConsumers.delete(el);\n }\n return [...this.#contextConsumers].filter(el => el.matches(selector));\n }\n\n public cacheInteractiveElements(): void {\n const collect = (selector: string, scope: ParentNode | ShadowRoot | null | undefined) =>\n Array.from(scope?.querySelectorAll<HTMLElement>(selector) ?? []);\n\n const lightDraggables = collect(draggablesSelector, this);\n const shadowDraggables = collect(draggablesSelector, this.shadowRoot);\n\n const lightClones = collect('[qti-draggable=\"true\"]:not([data-drag-clone])', this);\n const shadowClones = collect('[qti-draggable=\"true\"]:not([data-drag-clone])', this.shadowRoot);\n\n // The registry finds chips a query cannot reach — one shadow root deeper, inside a drop\n // target that renders its own contents. It is a union, not a replacement: an element that\n // never consumed the context (qti-gap-img has no ActiveElementMixin) is still found by query.\n const registeredDraggables = this.registeredMatching(draggablesSelector);\n\n this.trackedDraggables = Array.from(\n new Set([...lightDraggables, ...shadowDraggables, ...lightClones, ...shadowClones, ...registeredDraggables])\n );\n\n const lightDroppables = collect(droppablesSelector, this);\n const shadowDroppables = collect(droppablesSelector, this.shadowRoot);\n this.trackedDroppables = Array.from(new Set([...lightDroppables, ...shadowDroppables]));\n\n const lightDragContainers = collect(dragContainersSelector, this);\n const shadowDragContainers = collect(dragContainersSelector, this.shadowRoot);\n\n this.trackedDragContainers = Array.from(new Set([...lightDragContainers, ...shadowDragContainers]));\n\n this.allDropzones = [...this.trackedDroppables, ...this.trackedDragContainers];\n\n const dragDropEnabled = this.isDragDropEnabled();\n\n const draggableSet = new Set(this.trackedDraggables);\n const droppableSet = new Set(this.trackedDroppables);\n /*\n * The `drag` role state is NOT filtered by isDragChipHidden.\n *\n * `drag` is the noun here, the same one `part=\"drags\"` uses for the bank: it says what an\n * element *is*, not what is happening to it. One that has been lifted or spent is still a\n * drag, and has to keep saying so — the theme draws its box from `:state(drag)` and only\n * repaints it from `:state(placeholder)` / `:state(dragging)`. Filter the role and those stop\n * composing: the base rule stops matching the moment it is placed, the box collapses, and the\n * bank reflows around a hole 20px narrower than the thing that left it.\n *\n * Measured in drag-drop.invariance.spec.ts, \"a spent drag keeps its footprint\". Restore the\n * filter and those five assertions fail.\n *\n * Pickability is the separate question, and still filtered: isDragChipHidden is consulted\n * directly at the drag-start and keyboard-navigation sites below, and a spent drag still loses\n * `qti-draggable` and its tabindex.\n */\n const dragRoleSet = dragDropEnabled ? draggableSet : new Set<HTMLElement>();\n const effectiveDroppableSet = dragDropEnabled ? droppableSet : new Set<HTMLElement>();\n const currentStateful = new Set<StatefulElement>([...draggableSet, ...droppableSet].filter(hasStates));\n\n // Clear stale drag/drop role states from elements that are no longer tracked.\n for (const el of this.#statefulRoleElements) {\n if (currentStateful.has(el)) continue;\n el.internals.states.delete('drag');\n el.internals.states.delete('droppable');\n }\n\n /*\n * Drag-drop ownership of the drag/droppable role states.\n *\n * `droppable` is the drop-side twin of `qti-draggable`, and it is the ONLY marker. Three of\n * the five drop targets are light-DOM elements authored in the item body (`qti-gap`,\n * `qti-associable-hotspot`, `qti-simple-associable-choice`), so no part can name them — a part\n * only exists inside the shadow tree that declares it — and a stylesheet needs some way to say\n * \"this element is a drop target, whichever interaction it belongs to\".\n *\n * It used to be said twice: this state, spelled `drop`, plus a `qti-droppable=\"true\"`\n * attribute stamped on `trackedDroppables` just below. Two spellings meant every drop-side\n * rule was written twice, and they did not even agree — the attribute reached elements this\n * loop skips (see the two notes below). The attribute is gone; a host that cannot write\n * attributes uses the state, which is what the editor already did. ElementInternals states are\n * invisible to a mutation observer, which is why that host can use it: ProseMirror reverts any\n * attribute outside its schema, and the revert re-triggers the observer that wrote it.\n *\n * Two consequences of the state being the survivor, both deliberate:\n *\n * - `currentStateful` is filtered by `hasStates`, so order's and associate's shadow\n * `<div part=\"drop\">` get nothing — `attachInternals()` throws on a plain div. Those two\n * are reachable as `::part(drop)` from their own interaction, which is the hook they\n * actually use; the attribute on them was never read by anything.\n * - `isDrop` is `!isDrag && …`, so an element that is somehow both is a drag only. The\n * attribute was unconditional. No shipped interaction has an element in both sets.\n *\n * Gated on `isDragDropEnabled()` through `effectiveDroppableSet`: match-interaction's tabular\n * mode is a radio grid, and its `qti-simple-associable-choice` elements are row and column\n * headers, not drop targets. They must not reserve a dropzone's worth of space.\n */\n for (const el of currentStateful) {\n const isDrag = dragRoleSet.has(el);\n const isDrop = !isDrag && effectiveDroppableSet.has(el);\n if (isDrag) el.internals.states.add('drag');\n else el.internals.states.delete('drag');\n\n if (isDrop) el.internals.states.add('droppable');\n else el.internals.states.delete('droppable');\n }\n\n this.#statefulRoleElements = currentStateful;\n\n this.trackedDraggables.forEach(draggable => {\n const draggableHidden = isDragChipHidden(draggable);\n const canStartDrag = dragDropEnabled && !draggableHidden;\n\n if (canStartDrag) {\n draggable.style.cursor = 'grab';\n draggable.style.userSelect = 'none';\n draggable.style.touchAction = 'none'; // Prevent ALL default touch behaviors\n draggable.style.webkitUserSelect = 'none'; // Safari compatibility\n (draggable.style as any).webkitTouchCallout = 'none'; // Prevent iOS callout\n draggable.setAttribute('qti-draggable', 'true');\n draggable.setAttribute('tabindex', '0');\n } else {\n draggable.style.cursor = '';\n draggable.style.userSelect = '';\n draggable.style.touchAction = '';\n draggable.style.webkitUserSelect = '';\n (draggable.style as any).webkitTouchCallout = '';\n draggable.removeAttribute('qti-draggable');\n if (draggable.getAttribute('tabindex') === '0') {\n draggable.removeAttribute('tabindex');\n }\n }\n });\n }\n\n protected setupDragObservables(): void {\n const shadowRoot = this.shadowRoot;\n if (!shadowRoot) {\n console.error('❌ [Observable DnD] No shadow root found!');\n return;\n }\n\n const pointerDragSub = (shadowRoot as any)\n .when('pointerdown')\n .filter((e: PointerEvent) => {\n // Ignore synthetic pointerdown events generated by test helpers.\n // Storybook drag helpers dispatch synthetic mouse events, and browsers may\n // synthesize pointer compatibility events from them. Handling both pointer\n // and mouse streams can create duplicate drag starts and stale ghost clones.\n if (!e.isTrusted) {\n return false;\n }\n const target = findDraggableTarget(e, draggablesSelector);\n const hostDisabled = (this as any).disabled || (this as any).readonly;\n // Refuse drag starts from chips that currently leave a hole in the bank.\n const targetDisabled = isDraggableDisabled(target) || isDragChipHidden(target);\n const touchHandledRecently = Date.now() - this.lastTouchStartAt < 50;\n return (\n target &&\n e.isPrimary !== false &&\n e.button === 0 &&\n !hostDisabled &&\n !targetDisabled &&\n !touchHandledRecently\n );\n })\n .subscribe((downEvent: PointerEvent) => {\n this.lastPointerDownAt = Date.now();\n const dragTarget = findDraggableTarget(downEvent, draggablesSelector);\n if (!dragTarget) {\n console.warn('⚠️ [Observable DnD] No draggable target found');\n return;\n }\n\n if (downEvent.pointerType === 'touch') {\n downEvent.preventDefault();\n downEvent.stopPropagation();\n }\n\n // Keep a small activation delay for real user input, but avoid delay/cancellation\n // machinery for synthetic events (storybook/play) to reduce flaky cross-input races.\n const delay = downEvent.isTrusted ? (downEvent.pointerType === 'touch' ? 100 : 10) : 0;\n if (this.dragState.activationTimeout) {\n clearTimeout(this.dragState.activationTimeout);\n }\n\n if (delay === 0) {\n if (!this.dragState.dragging) {\n this.initiateDrag(\n dragTarget,\n downEvent.clientX,\n downEvent.clientY,\n downEvent.pointerType as 'mouse' | 'touch',\n 'pointer',\n downEvent.pointerId,\n downEvent.isTrusted\n );\n }\n return;\n }\n\n const cancelPendingActivation = () => {\n if (this.dragState.activationTimeout) {\n clearTimeout(this.dragState.activationTimeout);\n this.dragState.activationTimeout = undefined;\n }\n document.removeEventListener('pointerup', cancelPendingActivation, true);\n document.removeEventListener('pointercancel', cancelPendingActivation, true);\n };\n\n document.addEventListener('pointerup', cancelPendingActivation, { once: true, capture: true });\n document.addEventListener('pointercancel', cancelPendingActivation, { once: true, capture: true });\n\n this.dragState.activationTimeout = window.setTimeout(() => {\n this.dragState.activationTimeout = undefined;\n document.removeEventListener('pointerup', cancelPendingActivation, true);\n document.removeEventListener('pointercancel', cancelPendingActivation, true);\n if (!this.dragState.dragging) {\n this.initiateDrag(\n dragTarget,\n downEvent.clientX,\n downEvent.clientY,\n downEvent.pointerType as 'mouse' | 'touch',\n 'pointer',\n downEvent.pointerId,\n downEvent.isTrusted\n );\n }\n }, delay);\n });\n\n const mouseDragSub = (shadowRoot as any)\n .when('mousedown')\n .filter((e: MouseEvent) => {\n const target = findDraggableTarget(e, draggablesSelector);\n const hostDisabled = (this as any).disabled || (this as any).readonly;\n // Refuse drag starts from chips that currently leave a hole in the bank.\n const targetDisabled = isDraggableDisabled(target) || isDragChipHidden(target);\n const isLeftButton = e.button === 0;\n const pointerHandledRecently = Date.now() - this.lastPointerDownAt < 50;\n return target && isLeftButton && !hostDisabled && !targetDisabled && !pointerHandledRecently;\n })\n .subscribe((downEvent: MouseEvent) => {\n const dragTarget = findDraggableTarget(downEvent, draggablesSelector);\n if (!dragTarget || this.dragState.dragging) {\n return;\n }\n\n downEvent.preventDefault();\n\n this.initiateDrag(\n dragTarget,\n downEvent.clientX,\n downEvent.clientY,\n 'mouse',\n 'mouse',\n undefined,\n downEvent.isTrusted\n );\n });\n\n const touchDragSub = (shadowRoot as any)\n .when('touchstart')\n .filter((e: TouchEvent) => {\n const target = findDraggableTarget(e, draggablesSelector);\n const hostDisabled = (this as any).disabled || (this as any).readonly;\n // Refuse drag starts from chips that currently leave a hole in the bank.\n const targetDisabled = isDraggableDisabled(target) || isDragChipHidden(target);\n const hasTouchPoint = Boolean(e.touches?.[0] || e.changedTouches?.[0]);\n const pointerHandledRecently = Date.now() - this.lastPointerDownAt < 50;\n return target && hasTouchPoint && !hostDisabled && !targetDisabled && !pointerHandledRecently;\n })\n .subscribe((startEvent: TouchEvent) => {\n const dragTarget = findDraggableTarget(startEvent, draggablesSelector);\n const touch = startEvent.touches?.[0] || startEvent.changedTouches?.[0];\n if (!dragTarget || !touch || this.dragState.dragging) {\n return;\n }\n\n this.lastTouchStartAt = Date.now();\n startEvent.preventDefault();\n startEvent.stopPropagation();\n this.initiateDrag(\n dragTarget,\n touch.clientX,\n touch.clientY,\n 'touch',\n 'touch',\n undefined,\n startEvent.isTrusted\n );\n });\n\n let keyboardState = {\n dragging: false,\n dragElement: null as HTMLElement | null,\n dragIndex: 0,\n dropIndex: 0,\n dropElement: null as HTMLElement | null\n };\n\n const keyboardStream = (shadowRoot as any).when('keydown').subscribe((e: KeyboardEvent) => {\n // Skip chips that currently leave a hole in the bank — dragging, or already placed.\n const draggables = this.trackedDraggables.filter(d => !isDragChipHidden(d));\n const dropTargets = [...this.trackedDroppables, ...this.trackedDragContainers];\n\n // Start drag\n if (!keyboardState.dragging) {\n const target = findDraggableTarget(e, draggablesSelector);\n const hostDisabled = (this as any).disabled || (this as any).readonly;\n // Refuse drag starts from chips that currently leave a hole in the bank.\n const targetDisabled = isDraggableDisabled(target) || isDragChipHidden(target);\n\n if (target && ['Space', 'Enter'].includes(e.code) && !hostDisabled && !targetDisabled) {\n e.preventDefault();\n target.setAttribute('data-keyboard-dragging', 'true');\n keyboardState = {\n dragging: true,\n dragElement: target,\n dragIndex: draggables.indexOf(target),\n dropIndex: 0,\n dropElement: dropTargets[0]\n };\n }\n } else {\n // Navigation and drop/cancel\n switch (e.code) {\n case 'ArrowRight':\n case 'ArrowDown': {\n e.preventDefault();\n const nextDropIndex = (keyboardState.dropIndex + 1) % dropTargets.length;\n keyboardState = { ...keyboardState, dropIndex: nextDropIndex, dropElement: dropTargets[nextDropIndex] };\n break;\n }\n case 'ArrowLeft':\n case 'ArrowUp': {\n e.preventDefault();\n const prevDropIndex = (keyboardState.dropIndex - 1 + dropTargets.length) % dropTargets.length;\n keyboardState = { ...keyboardState, dropIndex: prevDropIndex, dropElement: dropTargets[prevDropIndex] };\n break;\n }\n case 'Space':\n case 'Enter':\n case 'Tab': {\n e.preventDefault();\n if (keyboardState.dragElement && keyboardState.dropElement) {\n const canDrop =\n this.allowDrop(keyboardState.dragElement, keyboardState.dropElement) ||\n this.trackedDragContainers.includes(keyboardState.dropElement);\n\n if (canDrop) {\n this.handleDrop(keyboardState.dragElement, keyboardState.dropElement);\n } else {\n this.handleInvalidDrop(keyboardState.dragElement);\n }\n }\n this.trackedDraggables.forEach(d => d.removeAttribute('data-keyboard-dragging'));\n this.saveResponse();\n keyboardState = {\n dragging: false,\n dragElement: null,\n dragIndex: 0,\n dropIndex: 0,\n dropElement: null\n };\n break;\n }\n case 'Escape': {\n e.preventDefault();\n this.trackedDraggables.forEach(d => d.removeAttribute('data-keyboard-dragging'));\n keyboardState = {\n dragging: false,\n dragElement: null,\n dragIndex: 0,\n dropIndex: 0,\n dropElement: null\n };\n break;\n }\n }\n }\n\n this.allDropzones.forEach(zone => zone.removeAttribute('hover'));\n if (keyboardState.dragging && keyboardState.dropElement) {\n keyboardState.dropElement.setAttribute('hover', '');\n if (\n keyboardState.dropElement.hasAttribute('tabindex') &&\n keyboardState.dropElement.getAttribute('tabindex') !== '-1'\n ) {\n keyboardState.dropElement.focus();\n }\n }\n });\n\n this.subscriptions.push(pointerDragSub, mouseDragSub, touchDragSub, keyboardStream);\n }\n\n protected initiateDrag(\n dragElement: HTMLElement,\n startX: number,\n startY: number,\n inputType: 'mouse' | 'touch',\n eventSource: DragEventSource = 'pointer',\n pointerId?: number,\n startedFromTrustedEvent?: boolean\n ): void {\n if (this.dragState.dragging) {\n console.warn('⚠️ [Observable DnD] Already dragging, ignoring initiateDrag');\n return;\n }\n if (dragElement.hasAttribute('data-drag-clone')) {\n console.warn('⚠️ [Observable DnD] Attempted to drag visual clone, ignoring');\n return;\n }\n\n // `Node.contains` does not cross a shadow boundary, and a chip rendered by a drop target\n // lives in that target's shadow root. Ask both trees.\n const holds = (d: HTMLElement) => d.contains(dragElement) || !!d.shadowRoot?.contains(dragElement);\n const isCloneInDroppable = this.trackedDroppables.some(holds);\n const sourceDroppable = this.trackedDroppables.find(holds) || null;\n\n // A chip grabbed while it is still flying home has a transform on it, and\n // `getBoundingClientRect` reports the transformed box, not the layout box. The drag would\n // then start from wherever the animation happened to be, `createDragClone` would copy the\n // half-applied transform into the clone, and the drop would resolve against a rect that is\n // still moving. Land it first: `cancel()` drops the fill and the chip snaps to where it\n // really lives.\n dragElement.getAnimations().forEach(animation => animation.cancel());\n\n const rect = dragElement.getBoundingClientRect();\n\n this.dragState = {\n dragging: true,\n dragSource: dragElement,\n dragClone: this.createDragClone(dragElement, rect),\n startOffset: {\n x: startX - rect.left,\n y: startY - rect.top\n },\n currentTarget: null,\n sourceDroppable: sourceDroppable,\n inputType: inputType,\n pointerId,\n startedFromTrustedEvent,\n initialCoordinates: { x: startX, y: startY },\n returnAnchorItems: []\n };\n\n if (isCloneInDroppable) {\n this.dragState.dragClone?.setAttribute('data-drag-origin', 'droppable');\n // A chip a target renders from data cannot be `remove()`d — the node would come straight\n // back on the next render. The target has to be told to stop holding it.\n this.removeChipFromDroppable(sourceDroppable, dragElement);\n this.cacheInteractiveElements();\n\n // Mark the source droppable so it won't be disabled during drag\n if (sourceDroppable) {\n sourceDroppable.setAttribute('data-drag-source', 'true');\n }\n\n // Mark the exact source placeholder(s) this chip would return to on invalid drop.\n const identifier = dragElement.getAttribute('identifier');\n if (identifier) {\n const anchors = findInventoryItems(this.trackedDragContainers, identifier);\n anchors.forEach(item => setDragChipState(item, 'return-anchor', true));\n this.dragState.returnAnchorItems = anchors;\n }\n } else {\n this.dragState.dragClone?.setAttribute('data-drag-origin', 'inventory');\n // The clone is already made, so it does not inherit this state. CSS hides the source.\n setDragChipState(dragElement, 'dragging', true);\n }\n\n this.updateClonePosition(startX, startY);\n this.activateAllDroppables();\n this.watchDragCloneHost();\n this.setupMoveObservables(inputType, eventSource);\n }\n\n protected setupMoveObservables(inputType: 'mouse' | 'touch', eventSource: DragEventSource = 'pointer'): void {\n if (inputType === 'touch') {\n if (eventSource === 'pointer') {\n try {\n const captureTarget = this.dragState.dragSource;\n const activePointerId = this.dragState.pointerId;\n if (captureTarget && activePointerId !== undefined && captureTarget.setPointerCapture) {\n captureTarget.setPointerCapture(activePointerId);\n }\n } catch (e) {\n // Ignore if pointer capture is unavailable for this event source.\n }\n }\n\n const preventAllTouch = (e: TouchEvent) => {\n if (e.cancelable) {\n e.preventDefault();\n // Keep propagation for synthetic touch fallback so document-level\n // observable listeners still receive touchmove/touchend.\n if (eventSource === 'pointer') {\n e.stopPropagation();\n }\n }\n };\n\n document.addEventListener('touchmove', preventAllTouch, { passive: false, capture: true });\n document.addEventListener('touchstart', preventAllTouch, { passive: false, capture: true });\n document.addEventListener('touchend', preventAllTouch, { passive: false, capture: true });\n document.addEventListener('gesturestart', preventAllTouch, { passive: false });\n document.addEventListener('gesturechange', preventAllTouch, { passive: false });\n document.addEventListener('gestureend', preventAllTouch, { passive: false });\n\n const cleanup = () => {\n document.removeEventListener('touchmove', preventAllTouch, { capture: true });\n document.removeEventListener('touchstart', preventAllTouch, { capture: true });\n document.removeEventListener('touchend', preventAllTouch, { capture: true });\n document.removeEventListener('gesturestart', preventAllTouch);\n document.removeEventListener('gesturechange', preventAllTouch);\n document.removeEventListener('gestureend', preventAllTouch);\n if (eventSource === 'pointer') {\n try {\n const captureTarget = this.dragState.dragSource;\n const activePointerId = this.dragState.pointerId;\n if (captureTarget && activePointerId !== undefined && captureTarget.releasePointerCapture) {\n captureTarget.releasePointerCapture(activePointerId);\n }\n } catch (e) {\n // Ignore errors if capture was already released\n }\n }\n };\n\n this.dragState.touchCleanup = cleanup;\n }\n\n const moveEventName =\n eventSource === 'mouse' ? 'mousemove' : eventSource === 'touch' ? 'touchmove' : 'pointermove';\n const upEventName = eventSource === 'mouse' ? 'mouseup' : eventSource === 'touch' ? 'touchend' : 'pointerup';\n const trustMatchesCurrentDrag = (evt: Event) => {\n const expected = this.dragState.startedFromTrustedEvent;\n return expected === undefined || evt.isTrusted === expected;\n };\n\n const moveSub = (document as any)\n .when(moveEventName)\n .takeUntil((document as any).when(upEventName))\n .subscribe({\n next: (e: MouseEvent | PointerEvent | TouchEvent) => {\n if (!trustMatchesCurrentDrag(e)) {\n return;\n }\n e.preventDefault();\n e.stopPropagation();\n\n if (eventSource === 'touch') {\n const touch = (e as TouchEvent).touches?.[0] || (e as TouchEvent).changedTouches?.[0];\n if (!touch) return;\n this.handleDragMove(touch.clientX, touch.clientY);\n return;\n }\n\n // For mouse-driven drags, only react while primary button is held.\n // This prevents passive user cursor movement from interfering with\n // an active synthetic/storybook drag sequence.\n if (eventSource === 'mouse') {\n const mouseEvent = e as MouseEvent;\n if (typeof mouseEvent.buttons === 'number' && (mouseEvent.buttons & 1) !== 1) {\n return;\n }\n }\n\n this.handleDragMove((e as MouseEvent | PointerEvent).clientX, (e as MouseEvent | PointerEvent).clientY);\n }\n });\n\n const endSub = (document as any).when(upEventName).subscribe({\n next: (e: MouseEvent | PointerEvent | TouchEvent) => {\n if (!trustMatchesCurrentDrag(e)) {\n return;\n }\n e.preventDefault();\n e.stopPropagation();\n\n this.handleDragEnd();\n }\n });\n\n const cancelSub =\n eventSource === 'touch'\n ? (document as any).when('touchcancel').subscribe({\n next: (e: Event) => {\n if (!trustMatchesCurrentDrag(e)) {\n return;\n }\n this.handleDragEnd();\n }\n })\n : eventSource === 'mouse'\n ? null\n : (document as any).when('pointercancel').subscribe({\n next: (e: Event) => {\n if (!trustMatchesCurrentDrag(e)) {\n return;\n }\n this.handleDragEnd();\n }\n });\n\n const escapeSub = (document as any)\n .when('keydown')\n .filter((e: KeyboardEvent) => e.key === 'Escape')\n .subscribe({\n next: (e: KeyboardEvent) => {\n if (!trustMatchesCurrentDrag(e)) {\n return;\n }\n this.handleDragEnd();\n }\n });\n\n const nextSubscriptions = [moveSub, endSub, escapeSub];\n if (cancelSub) {\n nextSubscriptions.push(cancelSub);\n }\n this.dragSubscriptions.push(...nextSubscriptions);\n }\n\n protected handleDragMove(clientX: number, clientY: number): void {\n if (!this.dragState.dragging || !this.dragState.dragClone) return;\n\n this.updateClonePosition(clientX, clientY);\n\n const dropTarget = detectCollision(\n this.allDropzones,\n clientX,\n clientY,\n this.dragState.dragClone,\n this.collisionDetectionAlgorithm,\n this.trackedDragContainers\n );\n\n // Hysteresis, so the `hover` outline does not flicker between adjacent zones. It governs\n // only what is highlighted; `handleDragEnd` resolves the drop from where the chip actually\n // comes to rest, never from this latched value.\n const now = Date.now();\n const timeSinceLastChange = now - (this.dragState.lastTargetChangeTime || 0);\n const MIN_TARGET_SWITCH_INTERVAL = 50; // milliseconds\n\n if (dropTarget !== this.dragState.currentTarget) {\n // Allow immediate switch to null (leaving a zone) or if enough time has passed\n if (dropTarget === null || timeSinceLastChange >= MIN_TARGET_SWITCH_INTERVAL) {\n this.allDropzones.forEach(zone => setDropFlag(zone, 'hover', false));\n if (dropTarget) {\n setDropFlag(dropTarget, 'hover', true);\n }\n this.dragState.currentTarget = dropTarget;\n this.dragState.lastTargetChangeTime = now;\n }\n }\n }\n\n protected handleDragEnd(): void {\n if (!this.dragState.dragging) return;\n\n const { dragSource, dragClone, currentTarget, sourceDroppable } = this.dragState;\n\n // Resolve the drop from where the chip came to rest.\n //\n // `currentTarget` is the hover highlight, and handleDragMove latches it for\n // MIN_TARGET_SWITCH_INTERVAL to keep that highlight from flickering. Dropping into it made\n // the latch decide the outcome: a flick whose every move falls inside one 50ms window keeps\n // the first zone its path happened to cross, however far away the chip was released.\n //\n // The fallback it replaces was worse in a quieter way — it probed from\n // `initialCoordinates`, which is where the drag *started*, so a drag that never produced a\n // move event resolved against the chip's original position in the bank.\n let dropTarget = currentTarget;\n if (dragClone) {\n const rect = dragClone.getBoundingClientRect();\n const resolved = detectCollision(\n this.allDropzones,\n rect.left + rect.width / 2,\n rect.top + rect.height / 2,\n dragClone,\n this.collisionDetectionAlgorithm,\n this.trackedDragContainers\n );\n // Null means the chip rests over nothing. Keep the hovered zone then, so releasing a hair\n // outside a zone still drops into it.\n dropTarget = resolved ?? currentTarget;\n }\n\n // `allowDrop` already decides `disabled` — including the cases that override it: returning to\n // the droppable a chip came from, and swapping into a full one. Re-testing the attribute here\n // vetoed a drop that had just been allowed.\n const canDrop = !!dragSource && !!dropTarget && this.allowDrop(dragSource, dropTarget);\n\n if (canDrop && dragSource && dropTarget) {\n this.handleDrop(dragSource, dropTarget);\n // The clone has landed, so the source is no longer mid-drag. `handleDrop` has already\n // decided whether it becomes a `placeholder`; only the transient state is cleared here.\n // (`handleInvalidDrop` clears both.) This used to be implicit: the inventory refresh\n // reset `style.opacity = '1.0'`, undoing the mid-drag hiding as a side effect.\n setDragChipState(dragSource, 'dragging', false);\n } else {\n this.handleInvalidDrop(dragSource);\n }\n\n if (dragClone) {\n dragClone.remove();\n }\n\n (this.dragState.returnAnchorItems || []).forEach(item => {\n setDragChipState(item, 'return-anchor', false);\n });\n\n if (this.dragState.touchCleanup) {\n this.dragState.touchCleanup();\n }\n\n this.resetDragState();\n this.deactivateAllDroppables();\n this.saveResponse();\n\n // Clear the drag-source marker AFTER saveResponse to ensure it's not disabled during drop processing\n if (sourceDroppable) {\n sourceDroppable.removeAttribute('data-drag-source');\n }\n\n // Re-sync dropzone capacity/disabled states after removing the drag-source marker.\n this.cacheInteractiveElements();\n const syncDropzones = (this as unknown as { checkAllMaxAssociations?: () => void }).checkAllMaxAssociations;\n if (typeof syncDropzones === 'function') {\n syncDropzones.call(this);\n }\n }\n\n public allowDrop(_draggable: HTMLElement, droppable: HTMLElement): boolean {\n // Allow drops into both regular droppables and drag containers (inventory)\n return this.trackedDroppables.includes(droppable) || this.trackedDragContainers.includes(droppable);\n }\n\n public abstract handleDrop(draggable: HTMLElement, droppable: HTMLElement): void;\n\n public handleInvalidDrop(dragSource: HTMLElement | null): void {\n clearDragChipStates(dragSource);\n }\n\n protected createDragClone(element: HTMLElement, rect: DOMRect): HTMLElement {\n const clone = element.cloneNode(true) as HTMLElement;\n\n const computedStyles = window.getComputedStyle(element);\n for (let i = 0; i < computedStyles.length; i++) {\n const property = computedStyles[i];\n clone.style.setProperty(property, computedStyles.getPropertyValue(property));\n }\n\n // Where the clone can live: the interaction's root while the browser paints it, the\n // fullscreen element when it does not. See utils/drag-clone-host.ts for why each is needed —\n // the root carries the theme, the fullscreen element carries the paint — and why the tree the\n // chip was dragged out of is never a candidate.\n //\n // `this.getRootNode()`, deliberately, not `element.getRootNode()`. A bank chip's root is the\n // item's shadow root either way, but a PLACED chip being re-dragged lives in its gap's or its\n // hotspot's own shadow root, and cloning it there would append the clone inside the very\n // element it is being dragged out of. The interaction's root is the same node for both.\n const host = resolveDragCloneHost(element.isConnected ? element : this, this.dragCloneRoot());\n this.cloneFrame = measureFixedFrame(host);\n\n clone.style.position = 'fixed';\n // `rect` is in viewport pixels; the host may lay its fixed children out in a scaled space.\n clone.style.width = `${rect.width / this.cloneFrame.scale.x}px`;\n clone.style.height = `${rect.height / this.cloneFrame.scale.y}px`;\n clone.style.zIndex = '9999';\n clone.style.pointerEvents = 'none'; // Critical: never capture events\n clone.style.touchAction = 'none'; // Prevent touch interactions\n clone.style.userSelect = 'none'; // Prevent selection\n clone.style.opacity = '0.8';\n\n clone.removeAttribute('qti-draggable');\n clone.removeAttribute('tabindex');\n clone.setAttribute('data-drag-clone', 'true');\n // Which interaction this chip came from, for theme rules that need to tell one in flight from\n // another (graphic-gap-match chips take no card styling). An attribute rather than an ancestor\n // selector because the clone is a sibling of the interaction, not a descendant.\n clone.setAttribute('data-drag-interaction', this.tagName.toLowerCase());\n\n host.appendChild(clone);\n return clone;\n }\n\n /**\n * The interaction's own tree, and the clone's preferred home.\n *\n * A stylesheet can only see its own tree. item-container adopts item.css into its shadow root\n * (item-container.ts), so a clone parked on document.body sat in a tree the theme could not\n * reach: every `[data-drag-clone]` rule was inert, and the chip's grip — a ::before, and so the\n * one thing a computed-style copy cannot carry — went missing the moment you picked a chip up.\n * Measured: with the theme in a shadow root, a body clone reports `content: none` for its grip\n * while the chip it was cloned from reports the glyph. It only ever looked right in Storybook,\n * whose preview.ts also injects item.css at document level.\n *\n * Null when that tree is the document, which leaves the choice of `document.body` to the\n * resolver: a document-level clone gains nothing from being hosted anywhere in particular.\n */\n private dragCloneRoot(): DragCloneHost | null {\n const root = this.getRootNode();\n return root instanceof ShadowRoot ? root : null;\n }\n\n protected updateClonePosition(clientX: number, clientY: number): void {\n this.dragState.lastCoordinates = { x: clientX, y: clientY };\n\n if (!this.dragState.dragClone) return;\n\n // `startOffset` is in viewport pixels, so the target position is resolved there and only then\n // converted into the host's space.\n const { startOffset } = this.dragState;\n const { x, y } = toFrameCoordinates(this.cloneFrame, clientX - startOffset.x, clientY - startOffset.y);\n\n this.dragState.dragClone.style.left = `${x}px`;\n this.dragState.dragClone.style.top = `${y}px`;\n }\n\n /**\n * Keeps the clone in a host the browser still paints when the page enters or leaves fullscreen\n * mid-drag — otherwise it is stranded in a container that is no longer rendered. Re-parenting\n * reconnects the clone's custom elements, which is why it only happens on an actual change.\n */\n private watchDragCloneHost(): void {\n const ownerDocument = this.ownerDocument ?? document;\n\n const rehost = () => {\n const { dragClone, dragSource, lastCoordinates } = this.dragState;\n if (!dragClone) return;\n\n const anchor = dragSource?.isConnected ? dragSource : this;\n const host = resolveDragCloneHost(anchor, this.dragCloneRoot());\n if (host === dragClone.parentNode) return;\n\n host.appendChild(dragClone);\n this.cloneFrame = measureFixedFrame(host);\n if (lastCoordinates) {\n this.updateClonePosition(lastCoordinates.x, lastCoordinates.y);\n }\n };\n\n ownerDocument.addEventListener('fullscreenchange', rehost);\n ownerDocument.addEventListener('webkitfullscreenchange', rehost);\n\n this.dragSubscriptions.push({\n unsubscribe: () => {\n ownerDocument.removeEventListener('fullscreenchange', rehost);\n ownerDocument.removeEventListener('webkitfullscreenchange', rehost);\n }\n });\n }\n\n protected activateAllDroppables(): void {\n this.setInternalsState('dragzone-enabled', true);\n this.setInternalsState('dragzone-active', true);\n\n this.allDropzones.forEach(zone => {\n setDropFlag(zone, 'enabled', true);\n setDropFlag(zone, 'active', true);\n });\n }\n\n protected deactivateAllDroppables(): void {\n this.setInternalsState('dragzone-enabled', false);\n this.setInternalsState('dragzone-active', false);\n\n this.allDropzones.forEach(zone => {\n setDropFlag(zone, 'enabled', false);\n setDropFlag(zone, 'active', false);\n setDropFlag(zone, 'hover', false);\n });\n }\n\n public resetDragState(): void {\n if (this.dragState.activationTimeout) {\n clearTimeout(this.dragState.activationTimeout);\n }\n\n (this.dragState.returnAnchorItems || []).forEach(item => {\n setDragChipState(item, 'return-anchor', false);\n });\n\n if (this.dragState.touchCleanup) {\n try {\n this.dragState.touchCleanup();\n } catch (error) {\n console.warn('⚠️ [Observable DnD] Error during touch cleanup:', error);\n }\n }\n\n this.dragSubscriptions.forEach(sub => {\n try {\n if (sub && typeof sub.unsubscribe === 'function') {\n sub.unsubscribe();\n }\n } catch (error) {\n console.warn('⚠️ [Observable DnD] Error unsubscribing:', error);\n }\n });\n this.dragSubscriptions = [];\n this.cloneFrame = IDENTITY_FIXED_FRAME;\n\n this.dragState = {\n dragging: false,\n dragSource: null,\n dragClone: null,\n startOffset: { x: 0, y: 0 },\n currentTarget: null,\n sourceDroppable: null,\n inputType: null,\n pointerId: undefined,\n startedFromTrustedEvent: undefined,\n touchCleanup: undefined,\n returnAnchorItems: []\n };\n }\n\n protected setInternalsState(state: string, enabled: boolean): void {\n const internals = (this as any)._internals;\n if (!internals?.states) return;\n\n if (enabled) {\n internals.states.add(state);\n } else {\n internals.states.delete(state);\n }\n }\n\n protected cleanup(): void {\n this.subscriptions.forEach(sub => {\n try {\n sub.unsubscribe();\n } catch (e) {\n // Ignore cleanup errors\n }\n });\n this.subscriptions = [];\n\n if (this.dragState.dragClone) {\n this.dragState.dragClone.remove();\n }\n\n for (const el of this.#statefulRoleElements) {\n if (!hasStates(el)) continue;\n el.internals.states.delete('drag');\n el.internals.states.delete('droppable');\n }\n this.#statefulRoleElements.clear();\n\n this.resetDragState();\n }\n }\n\n return DragDropCoreElement as unknown as Constructor<DragDropCore> & T;\n};\n","/**\n * FLIP (First, Last, Invert, Play) animation utilities\n *\n * Based on Paul Lewis's FLIP technique for performant layout animations.\n * @see https://css-tricks.com/animating-layouts-with-the-flip-technique/\n *\n * FLIP enables smooth animations by:\n * 1. First - capturing initial position/size\n * 2. Last - capturing final position/size after DOM changes\n * 3. Invert - applying inverse transform to make element appear at start position\n * 4. Play - animating from inverted state back to final position\n */\n\nexport interface FlipState {\n left: number;\n top: number;\n width: number;\n height: number;\n}\n\nexport interface FlipAnimationOptions {\n duration?: number;\n easing?: string;\n fill?: FillMode;\n}\n\nexport const DEFAULT_FLIP_OPTIONS: Required<FlipAnimationOptions> = {\n duration: 250,\n easing: 'ease',\n fill: 'both'\n};\n\n/**\n * Capture the current position and dimensions of an element\n */\nexport function captureFlipState(element: Element): FlipState {\n const rect = element.getBoundingClientRect();\n return {\n left: rect.left,\n top: rect.top,\n width: rect.width,\n height: rect.height\n };\n}\n\n/**\n * A chip's last on-screen position, as a FLIP \"first\" state.\n *\n * The drag clone is `position: fixed` and is destroyed the moment the pointer is released, so the\n * only record of where the chip was is the rect taken just before it goes. Handing that rect to\n * `animateFlip` as the \"first\" state is what lets a chip fly home rather than blink home.\n */\nexport function flipStateFromRect(rect: DOMRect): FlipState {\n return { left: rect.left, top: rect.top, width: rect.width, height: rect.height };\n}\n\n/**\n * Capture FLIP states for multiple elements\n */\nexport function captureMultipleFlipStates(elements: Element[]): Map<Element, FlipState> {\n const states = new Map<Element, FlipState>();\n elements.forEach(element => {\n states.set(element, captureFlipState(element));\n });\n return states;\n}\n\n/**\n * Calculate the transform needed to invert an element back to its first state\n */\nexport function calculateInversion(\n first: FlipState,\n last: FlipState\n): {\n deltaX: number;\n deltaY: number;\n deltaW: number;\n deltaH: number;\n} {\n return {\n deltaX: first.left - last.left,\n deltaY: first.top - last.top,\n deltaW: first.width / last.width,\n deltaH: first.height / last.height\n };\n}\n\n/**\n * The interaction's motion budget: the computed `--qti-motion` custom property — a unitless\n * multiplier, default 1 — forced to 0 when the OS requests reduced motion. `0` means \"no motion\":\n * FLIP is skipped entirely. A positive value scales the configured FLIP duration, so a theme (or a\n * PNP profile) can slow motion down (`0.5`) or switch it off (`0`) from CSS, the single source of\n * truth the drag-drop engine reads. `--qti-motion` inherits from the interaction down to the items\n * it animates, so reading it off any animated element is representative.\n *\n * Every FLIP path funnels through `animateFlip`, so gating here covers slotted, slotted-sortable,\n * sortable reorder and return animations in one place.\n */\nexport function resolveMotionScale(element: Element | null | undefined): number {\n if (\n typeof window !== 'undefined' &&\n typeof window.matchMedia === 'function' &&\n window.matchMedia('(prefers-reduced-motion: reduce)').matches\n ) {\n return 0;\n }\n if (!element) return 1;\n const raw = getComputedStyle(element).getPropertyValue('--qti-motion').trim();\n if (raw === '') return 1; // token absent (e.g. theme CSS not loaded) → motion on\n const n = Number.parseFloat(raw);\n return Number.isFinite(n) && n > 0 ? n : 0;\n}\n\n/** Whether FLIP should run for this element, honouring `--qti-motion` and `prefers-reduced-motion`. */\nexport function motionEnabled(element: Element | null | undefined): boolean {\n return resolveMotionScale(element) > 0;\n}\n\n/**\n * Animate a single element using FLIP technique\n */\nexport function animateFlip(\n element: HTMLElement,\n first: FlipState,\n options: FlipAnimationOptions = {}\n): Animation | null {\n const motionScale = resolveMotionScale(element);\n if (motionScale <= 0) return null; // --qti-motion: 0 or reduced-motion → snap, no animation\n\n const last = captureFlipState(element);\n const { deltaX, deltaY, deltaW, deltaH } = calculateInversion(first, last);\n\n if (deltaX === 0 && deltaY === 0 && deltaW === 1 && deltaH === 1) {\n return null;\n }\n\n const { duration, easing, fill } = { ...DEFAULT_FLIP_OPTIONS, ...options };\n\n const animation = element.animate(\n [\n {\n transformOrigin: 'top left',\n transform: `translate(${deltaX}px, ${deltaY}px) scale(${deltaW}, ${deltaH})`\n },\n {\n transformOrigin: 'top left',\n transform: 'none'\n }\n ],\n {\n duration: duration * motionScale, // scaled by --qti-motion (1 = configured speed)\n easing,\n fill\n }\n );\n\n return animation;\n}\n\n/**\n * Animate multiple elements using their captured states\n * Returns a map of elements to their animations\n */\nexport function animateMultipleFlips(\n previousStates: Map<Element, FlipState>,\n options: FlipAnimationOptions = {}\n): Map<Element, Animation> {\n const animations = new Map<Element, Animation>();\n\n previousStates.forEach((firstState, element) => {\n if (!(element instanceof HTMLElement)) return;\n\n const animation = animateFlip(element, firstState, options);\n if (animation) {\n animations.set(element, animation);\n }\n });\n\n return animations;\n}\n\n/**\n * Helper to perform a complete FLIP animation cycle\n *\n * @param elements - Elements to animate\n * @param mutationFn - Function that triggers DOM changes\n * @param options - Animation options\n *\n * @example\n * ```ts\n * performFlip(\n * [...this.children],\n * () => {\n * // Reorder children\n * this.appendChild(firstChild);\n * },\n * { duration: 400 }\n * );\n * ```\n */\nexport async function performFlip(\n elements: Element[],\n mutationFn: () => void | Promise<void>,\n options: FlipAnimationOptions = {}\n): Promise<void> {\n // First - capture initial states\n const firstStates = captureMultipleFlipStates(elements);\n\n // Last - execute the mutation\n await mutationFn();\n\n // Invert & Play - animate elements\n const animations = animateMultipleFlips(firstStates, options);\n\n // Wait for all animations to complete\n await Promise.all(Array.from(animations.values()).map(animation => animation.finished));\n}\n","import { property } from 'lit/decorators.js';\nimport { provide } from '@lit/context';\n\nimport { responseAttributeConverter } from '@qti-components/base';\n\nimport { dragDropContext } from '../../context/drag-drop.context';\nimport {\n clearDragChipStates,\n findInventoryItems,\n getMatchMaxValue,\n hasDragChipState,\n setDropFilled,\n setDragChipState\n} from './utils/drag-drop.utils';\nimport { DragDropCoreMixin } from './drag-drop-core.mixin';\nimport { DropzoneAutoSizeMixin } from '../dropzone-auto-size/dropzone-auto-size.mixin';\nimport {\n animateFlip,\n captureMultipleFlipStates,\n animateMultipleFlips,\n flipStateFromRect,\n motionEnabled,\n type FlipAnimationOptions\n} from './utils/flip.utils';\n\nimport type { ComplexAttributeConverter } from 'lit';\nimport type { CollisionDetectionAlgorithm } from './utils/drag-drop.utils';\nimport type { Interaction, RegisteredInteraction } from '@qti-components/base';\nimport type { DragDropState } from '../../context/drag-drop.context';\nimport type { DragDropCore } from './drag-drop-core.mixin';\nimport type { DropzoneAutoSize } from '../dropzone-auto-size/dropzone-auto-size.mixin';\n\ntype Constructor<T = {}> = abstract new (...args: any[]) => T;\n\nexport type DragDropSlotted = DragDropCore &\n DropzoneAutoSize & {\n minAssociations: number;\n maxAssociations: number;\n disableAnimations: boolean;\n enableFlipAnimations: boolean;\n validate(): boolean;\n reportValidity(): boolean;\n reset(): void;\n saveResponse(value?: string | string[]): void;\n shouldTreatBlockedMaxAsInvalid(): boolean;\n shouldReturnToInventoryOnInventoryDrop(): boolean;\n\n /** Placement, published on `dragDropContext`. An interaction that renders its own drop targets\n * reads `nodesByTarget` straight out of it. */\n _dragDrop: Readonly<DragDropState>;\n /** The chips a target holds — from the placement map, or the DOM, depending on the target. */\n chipsIn(droppable: HTMLElement): HTMLElement[];\n isDeclarativeTarget(el: HTMLElement | null | undefined): boolean;\n\n /** Republish placement on `dragDropContext` and re-render the targets that read it. */\n syncDragDropState(): void;\n\n /**\n * How many associations exist, for `min-associations` / `max-associations`.\n *\n * The default counts placed chips, which is one-to-one with associations only when a chip *is*\n * an association — a gap holding one chip, a match target holding one chip. Associate pairs two\n * chips per association and overrides this. Declared here so it can be.\n */\n totalAssociationsFromState(): number;\n };\n\nexport const DragDropSlottedMixin = <T extends Constructor<Interaction>>(\n superClass: T,\n draggablesSelector: string,\n droppablesSelector: string,\n dragContainersSelector = 'slot[part=\"drags\"]',\n collisionAlgorithm: CollisionDetectionAlgorithm = 'closestCornersWithInventoryPriority'\n) => {\n /*\n * Measurement is layered UNDER the drag-drop stack, not inside it, so the editor can take it\n * without the rest — it renders the same elements and imports the same stylesheets, but does its\n * own drag handling inside a ProseMirror document. Same selectors, so both layers agree on what a\n * chip is; `collectAutoSizeTargets` below then hands it the already-cached lists rather than\n * letting it re-query.\n */\n const AutoSized = DropzoneAutoSizeMixin(superClass, draggablesSelector, droppablesSelector, dragContainersSelector);\n\n // Use 'closestCorners' by default for associate interactions (better for multiple drop zones)\n const Core = DragDropCoreMixin(\n AutoSized,\n draggablesSelector,\n droppablesSelector,\n dragContainersSelector,\n collisionAlgorithm\n );\n\n abstract class DragDropSlottedElement extends Core implements RegisteredInteraction {\n /*\n * A `configuration` object used to sit here — { copyStylesDragClone, dragCanBePlacedBack,\n * dragOnClick } — and configured nothing. Nothing in the repo ever assigned it; `dragOnClick`\n * had no reader at all, `copyStylesDragClone` only one in the dead legacy mixin (the live\n * `createDragClone` copies computed styles unconditionally), and `dragCanBePlacedBack` gated the\n * branch below on a value that was always true. It was also unreachable by design —\n * `attribute: false` AND `protected` — so no author or host could have set it either.\n *\n * If any of the three is ever wanted for real, it should come back as an attribute (like\n * `auto-size-dropzones`) or through `configContext`, not as a private object nobody can reach.\n */\n @property({ type: Number, reflect: true, attribute: 'min-associations' }) minAssociations = 1;\n\n private _maxAssociations = 0;\n private _maxAssociationsDefaultApplied = false;\n\n @property({ type: Number, reflect: true, attribute: 'max-associations' })\n get maxAssociations(): number {\n // QTI compatibility: gap-match interactions default max-associations to 1\n // when the attribute is omitted.\n if (!this._maxAssociationsDefaultApplied) {\n this._maxAssociationsDefaultApplied = true;\n const tagName = this.tagName?.toLowerCase() || '';\n const isGapMatchInteraction =\n tagName === 'qti-graphic-gap-match-interaction' || tagName === 'qti-gap-match-interaction';\n if (isGapMatchInteraction && !this.hasAttribute('max-associations') && this._maxAssociations === 0) {\n this._maxAssociations = 1;\n }\n }\n return this._maxAssociations;\n }\n\n set maxAssociations(value: number) {\n const oldValue = this._maxAssociations;\n this._maxAssociations = value;\n this.requestUpdate('maxAssociations', oldValue);\n }\n\n protected _response: string[] = [];\n\n /**\n * What each drop target holds. Published to the drop targets, which will render themselves\n * from it once the DOM stops being the source of truth.\n *\n * Reassign, never mutate — an in-place change does not notify consumers.\n */\n @provide({ context: dragDropContext })\n public _dragDrop: Readonly<DragDropState> = { dragsByTarget: {}, countByTarget: {}, nodesByTarget: {} };\n\n /**\n * The one place that reads placement out of the DOM.\n *\n * Replaces nine scattered `querySelectorAll` readbacks (`collectResponseData`,\n * `countTotalAssociations`, `isDroppableAtCapacity`). The DOM is still authoritative here;\n * centralising it is what makes inverting that possible without touching nine call sites.\n */\n /**\n * What each declarative drop target holds. The DOM is derived from this, not the other way.\n *\n * A target opts in with `acceptsDeclarativeDrops`, consumes `dragDropContext`, and renders\n * `repeat(nodesByTarget[id])` into its own shadow root. The interaction never appends into it.\n * Everything else still takes an `appendChild` and is read back by query — the two live side by\n * side, and `chipsIn` hides which is which.\n *\n * Keyed by element, not identifier: the map is short-lived and element identity is exact.\n */\n #placement = new WeakMap<HTMLElement, HTMLElement[]>();\n\n /**\n * Is this a full *single-capacity* declarative target receiving a chip dragged out of a\n * different target? Only single-capacity targets swap — the occupant leaves so the incoming chip\n * can take its place. A multi-capacity target at match-max has no room to give: it must stay\n * blocked, or a cross-target move would append past its capacity (the per-target match-max is\n * meaningless otherwise). `allowDrop` uses this to re-permit a target it disabled for capacity.\n */\n protected isSwapTarget(droppable: HTMLElement): boolean {\n const source = this.dragState.sourceDroppable;\n const parsedMatchMax = parseInt(droppable.getAttribute('match-max') || '1', 10);\n const isSingleCapacity = (Number.isNaN(parsedMatchMax) ? 1 : parsedMatchMax) === 1;\n return (\n isSingleCapacity &&\n this.isDeclarativeTarget(droppable) &&\n !!source &&\n source !== droppable &&\n this.trackedDroppables.includes(source)\n );\n }\n\n /**\n * Does this target render its own chips?\n *\n * A custom element says so with a property (`qti-gap`, `qti-associable-hotspot`). Order's and\n * associate's targets are plain `<div part=\"drop\">` in the interaction's own shadow root, and a\n * div cannot carry a property that survives a Lit re-render — it says so with an attribute, and\n * the *interaction* renders the chips into it. Same placement map either way.\n */\n public isDeclarativeTarget(el: HTMLElement | null | undefined): boolean {\n if (!el) return false;\n if ((el as unknown as { acceptsDeclarativeDrops?: boolean }).acceptsDeclarativeDrops === true) return true;\n return el.hasAttribute('data-declarative-drops');\n }\n\n /** The chips a target holds, whichever way it holds them. */\n public chipsIn(droppable: HTMLElement): HTMLElement[] {\n if (this.isDeclarativeTarget(droppable)) return [...(this.#placement.get(droppable) ?? [])];\n return Array.from(droppable.querySelectorAll<HTMLElement>(draggablesSelector));\n }\n\n /** The target currently holding this chip, across shadow boundaries. */\n protected droppableHolding(chip: HTMLElement): HTMLElement | null {\n return (\n this.trackedDroppables.find(\n d => this.chipsIn(d).includes(chip) || d.contains(chip) || !!d.shadowRoot?.contains(chip)\n ) ?? null\n );\n }\n\n private placeChip(droppable: HTMLElement, chip: HTMLElement): void {\n this.#placement.set(droppable, [...(this.#placement.get(droppable) ?? []), chip]);\n }\n\n public override removeChipFromDroppable(droppable: HTMLElement | null, chip: HTMLElement): void {\n const target = droppable ?? this.droppableHolding(chip);\n if (target && this.isDeclarativeTarget(target)) {\n const remaining = (this.#placement.get(target) ?? []).filter(node => node !== chip);\n this.#placement.set(target, remaining);\n if (remaining.length === 0) setDropFilled(target, false);\n this.syncDragDropState();\n return;\n }\n chip.remove();\n }\n\n private clearChips(droppable: HTMLElement): void {\n if (this.isDeclarativeTarget(droppable)) {\n this.#placement.set(droppable, []);\n // Emptying the map is not enough: nothing re-renders until placement is published.\n this.syncDragDropState();\n } else {\n this.chipsIn(droppable).forEach(chip => chip.remove());\n }\n setDropFilled(droppable, false);\n }\n\n public syncDragDropState(): void {\n const dragsByTarget: Record<string, string[]> = {};\n const countByTarget: Record<string, number> = {};\n const nodesByTarget: Record<string, HTMLElement[]> = {};\n\n for (const droppable of this.trackedDroppables) {\n const targetId = droppable.getAttribute('identifier');\n if (!targetId) continue;\n\n const bySelector = this.chipsIn(droppable);\n const byAttribute = this.isDeclarativeTarget(droppable)\n ? bySelector\n : Array.from(droppable.querySelectorAll<HTMLElement>('[qti-draggable=\"true\"]'));\n\n // Response uses the structural selector only; capacity uses whichever finds more.\n // These differ, and collapsing them would silently change matchMax behaviour.\n dragsByTarget[targetId] = bySelector\n .map(chip => chip.getAttribute('identifier'))\n .filter((id): id is string => Boolean(id));\n countByTarget[targetId] = Math.max(bySelector.length, byAttribute.length);\n nodesByTarget[targetId] = bySelector;\n }\n\n this._dragDrop = { dragsByTarget, countByTarget, nodesByTarget };\n // Consumers of the context re-render on reassignment. An interaction that renders its own\n // drop targets is not a consumer of its own context, so it has to be told.\n this.requestUpdate();\n }\n\n /** The response, derived from placement: `\"<dragId> <targetId>\"` per placed chip. */\n protected responseFromState(): string[] {\n this.syncDragDropState();\n const { dragsByTarget } = this._dragDrop;\n return this.trackedDroppables.flatMap(droppable => {\n const targetId = droppable.getAttribute('identifier');\n if (!targetId) return [];\n return (dragsByTarget[targetId] ?? []).map(dragId => `${dragId} ${targetId}`);\n });\n }\n\n public totalAssociationsFromState(): number {\n this.syncDragDropState();\n return Object.values(this._dragDrop.countByTarget).reduce((total, count) => total + count, 0);\n }\n\n /**\n * Is this drop target full?\n *\n * `match-max` on a drop is QTI's own capacity attribute, and the semantics here match the spec:\n * the value is per-target (\"match-max on the characters … is 1 because each character can be in\n * only one play but it is 4 on the plays … because each play could contain all the characters\",\n * QTI 3 implementation guide §3.2.9), and **0 means unlimited** (§3.2.5's gap table spells it\n * out: \"Non-negative integer, 0 means unlimited\").\n *\n * The `|| '1'` is NOT a spec default — the spec marks `match-max` **required** on\n * `qti-simple-associable-choice` and states no default. It is a lenient fallback for markup that\n * omits a required attribute, chosen as 1 because a drop that takes one chip is the least\n * surprising reading of \"unspecified\". Same for the NaN guard.\n */\n protected droppableAtCapacityFromState(droppable: HTMLElement): boolean {\n const parsed = parseInt(droppable.getAttribute('match-max') || '1', 10);\n const matchMax = Number.isNaN(parsed) ? 1 : parsed;\n if (matchMax === 0) return false;\n\n const targetId = droppable.getAttribute('identifier');\n const current = targetId ? (this._dragDrop.countByTarget[targetId] ?? 0) : 0;\n return current >= matchMax;\n }\n\n // Track when a drop was blocked due to max capacity\n private _dropBlockedDueToMax = false;\n\n // FLIP animation configuration\n public flipAnimationConfig: FlipAnimationOptions = {\n duration: 200, // Slightly faster for slotted interactions\n easing: 'ease' // Simple, browser-optimized easing\n };\n\n private _enableFlipAnimations = true;\n\n @property({ type: Boolean, attribute: 'disable-animations' })\n set disableAnimations(value: boolean) {\n this._enableFlipAnimations = !value;\n }\n get disableAnimations(): boolean {\n return !this._enableFlipAnimations;\n }\n\n /* The `disable-animations` attribute AND the theme's motion budget: FLIP runs only when both\n allow it, so `--qti-motion: 0` / reduced-motion disables it without any consumer code. */\n get enableFlipAnimations(): boolean {\n return this._enableFlipAnimations && motionEnabled(this as unknown as Element);\n }\n\n /**\n * Measure what the drag-drop machinery already tracks, rather than re-querying.\n *\n * `cacheInteractiveElements()` resolves the same three selectors and then adds what a plain\n * query cannot see — drag clones, and chips registered through `context-request` from a shadow\n * root one level deeper. Re-querying would give the auto-sizer a smaller set than the one the\n * drops are actually built from, so the widest chip could be missed.\n */\n public override collectAutoSizeTargets() {\n return {\n draggables: this.trackedDraggables,\n droppables: this.trackedDroppables,\n dragContainers: this.trackedDragContainers\n };\n }\n\n /**\n * Set via the `response=\"…\"` attribute before the drag/drop machinery has\n * cached its dropzones (`setupDragDrop` awaits the first render). The\n * `afterCache` extension hook in this mixin applies it once dropzones exist.\n */\n private _pendingResponse: string[] | undefined = undefined;\n\n @property({\n attribute: 'response',\n reflect: false,\n noAccessor: true,\n converter: responseAttributeConverter({ emptyAs: [] }) as ComplexAttributeConverter<unknown, unknown>\n })\n get response(): string {\n const getResponse = (this as unknown as { getResponse?: () => unknown }).getResponse;\n const candidate = typeof getResponse === 'function' ? getResponse.call(this) : undefined;\n const computedResponse = Array.isArray(candidate)\n ? candidate\n : (() => {\n this.cacheInteractiveElements();\n return this.responseFromState();\n })();\n return computedResponse.join(',');\n }\n\n set response(value: string | string[]) {\n if (Array.isArray(value)) {\n // Dropzones haven't been cached yet — defer to `afterCache`.\n if (!this.trackedDroppables || this.trackedDroppables.length === 0) {\n this._pendingResponse = value;\n this._internals.setFormValue(JSON.stringify(value));\n return;\n }\n const getValue = (this as unknown as { getValue?: (v: string[]) => unknown }).getValue;\n const normalized = typeof getValue === 'function' ? getValue.call(this, value) : value;\n const responseEntries = Array.isArray(normalized)\n ? normalized\n : typeof normalized === 'string' && normalized.length > 0\n ? [normalized]\n : [];\n\n this.reset(false);\n responseEntries.forEach(entry => this.placeResponse(entry));\n\n const getResponse = (this as unknown as { getResponse?: () => unknown }).getResponse;\n const candidate = typeof getResponse === 'function' ? getResponse.call(this) : undefined;\n this._response = Array.isArray(candidate)\n ? candidate\n : (() => {\n this.cacheInteractiveElements();\n return this.responseFromState();\n })();\n } else {\n // Compatibility note:\n // legacy drag/drop behavior treats string response assignment as form-state only.\n // It does not replay placements into dropzones; only array-based input does.\n this._response = typeof value === 'string' && value.length > 0 ? [value] : [];\n }\n\n this._internals.setFormValue(JSON.stringify(this._response));\n }\n\n public override afterCache(): void {\n // Order no longer matters between these two. Auto-sizing used to write a `min-width` from the\n // widest chip that the configured width then had to run after and clear — `min-width` beats\n // `width` — which made a re-measurement enough to silently discard\n // `data-choices-container-width` again. `autoSizeDropzoneWidth` now suppresses that write at\n // the source, so there is nothing to undo and nothing to sequence.\n this.updateMinDimensionsForDropZones();\n this.applyConfiguredChoicesContainerWidth();\n if (this._pendingResponse !== undefined) {\n const pending = this._pendingResponse;\n this._pendingResponse = undefined;\n this.response = pending;\n }\n }\n\n /**\n * `data-choices-container-width` is an explicit authoring instruction, so the measured width\n * must not compete with it: auto-sizing derives that width from the widest chip and `min-width`\n * takes precedence over `width`, so a theme with roomy chips would silently widen the gap past\n * the authored value.\n *\n * Suppressing the measurement is how that is expressed — see `autoSizeDropzoneWidth`. The\n * height is still measured; only the axis the author has spoken for is given up.\n */\n public override get autoSizeDropzoneWidth(): boolean {\n return !this.dataset.choicesContainerWidth;\n }\n private applyConfiguredChoicesContainerWidth(): void {\n const configuredWidth = this.dataset.choicesContainerWidth;\n if (!configuredWidth) return;\n\n // Nothing to undo here: `autoSizeDropzoneWidth` is false whenever this attribute is set (see\n // the getter below), so the measurement never published a width in the first place. This used\n // to zero `--qti-dropzone-min-width` on the host instead, which only worked while it ran\n // strictly after the pass AND while the pass wrote to exactly one element — two facts that\n // stopped being true when the mixin gained re-measurement and a second write target.\n\n // `width` stays an inline style, deliberately. `qti-associable-hotspot` already carries an\n // inline width derived from its `coords`, and an authored container width must override\n // that — a custom property read from the element's own `:host` rule never could.\n this.trackedDroppables.forEach(droppable => {\n droppable.style.width = `${configuredWidth}px`;\n droppable.style.boxSizing = 'border-box';\n });\n }\n\n public shouldTreatBlockedMaxAsInvalid(): boolean {\n return true;\n }\n\n public shouldReturnToInventoryOnInventoryDrop(): boolean {\n return false;\n }\n\n private getFirstMessageAttribute(attributeNames: string[]): string | null {\n for (const name of attributeNames) {\n const direct = this.getAttribute(name);\n if (direct && direct.trim().length > 0) return direct;\n }\n\n const normalized = attributeNames.map(name => name.toLowerCase());\n for (const attr of Array.from(this.attributes)) {\n if (normalized.includes(attr.name.toLowerCase()) && attr.value.trim().length > 0) {\n return attr.value;\n }\n }\n\n return null;\n }\n\n public override allowDrop(_draggable: HTMLElement, droppable: HTMLElement): boolean {\n // Always allow dropping into drag containers (inventory).\n if (this.trackedDragContainers.includes(droppable)) {\n return true;\n }\n\n // Allow drop if:\n // 1. The droppable is tracked\n // 2. AND either: it's not disabled OR it has the data-drag-source marker (returning to source)\n const isTracked = this.trackedDroppables.includes(droppable);\n const isDisabled = droppable.hasAttribute('disabled');\n const isReturningToSource = droppable.hasAttribute('data-drag-source');\n\n // A full single-capacity target is still droppable when the chip comes from another target:\n // that is what a swap is. The sortable mixin used to arrange this implicitly, by moving the\n // occupant's DOM node out during the hover preview so the target stopped being at capacity.\n // A target that renders from data has no node to move, so the rule is stated outright.\n if (isDisabled && this.isSwapTarget(droppable)) {\n return true;\n }\n\n return isTracked && (!isDisabled || isReturningToSource);\n }\n\n public override handleDrop(draggable: HTMLElement, droppable: HTMLElement): void {\n // Capture the drag clone's position before it gets removed\n // The dragClone is the visual element being dragged\n const dragClonePosition = this.dragState.dragClone?.getBoundingClientRect();\n\n this.dropDraggableInDroppable(draggable, droppable, dragClonePosition);\n const identifier = draggable.getAttribute('identifier');\n\n if (identifier) {\n this.updateInventoryBasedOnMatchMax(identifier);\n }\n\n // Always refresh configured validity UI after user-driven drop changes.\n // This ensures inline messages clear immediately when state becomes valid again.\n this.validate();\n this.reportValidity();\n }\n\n public override handleInvalidDrop(dragSource: HTMLElement | null): void {\n const sourceDroppable = this.dragState.sourceDroppable;\n const currentTarget = this.dragState.currentTarget;\n const droppedOutsideKnownZones = !currentTarget;\n const inventoryReturnTarget = this.trackedDragContainers[0] || null;\n\n if (!dragSource) {\n return;\n }\n\n // Legacy compatibility:\n // If drag started from a dropzone and ended on host/background (no collision target),\n // interpret this as \"return to inventory\".\n if (sourceDroppable && droppedOutsideKnownZones && inventoryReturnTarget) {\n this.dropDraggableInDroppable(dragSource, inventoryReturnTarget);\n }\n // If drag started from a dropzone and the drop is invalid, restore only this\n // dragged instance back to its source droppable.\n else if (sourceDroppable && this.trackedDroppables.includes(sourceDroppable)) {\n // Released over nothing, having come from a dropzone: the chip goes back where it was, and\n // it travels there. The clone is still alive at this point — `handleDragEnd` removes it\n // only after `handleInvalidDrop` returns — so its rect is the chip's last real position.\n this.dropDraggableInDroppable(dragSource, sourceDroppable, this.dragState.dragClone?.getBoundingClientRect());\n } else if (hasDragChipState(dragSource, 'dragging')) {\n // Drag started from inventory: simply restore inventory visual state.\n this.restoreInventoryItem(dragSource, this.dragState.dragClone?.getBoundingClientRect());\n const identifier = dragSource.getAttribute('identifier');\n if (identifier) {\n // If this identifier is already fully placed (match-max reached),\n // keep the inventory item as a placeholder after invalid release.\n this.updateInventoryBasedOnMatchMax(identifier);\n }\n this.cacheInteractiveElements();\n this.checkAllMaxAssociations();\n }\n\n // Only flag \"blocked due to max\" when the user attempted to drop on\n // a disabled non-source target while global max is reached.\n // This avoids showing max-capacity errors for unrelated invalid drops\n // (e.g. dropping outside any known dropzone).\n const totalAssociations = this.totalAssociationsFromState();\n const maxReached = this.maxAssociations > 0 && totalAssociations >= this.maxAssociations;\n const attemptedDisabledTarget =\n !!currentTarget && currentTarget.hasAttribute('disabled') && !currentTarget.hasAttribute('data-drag-source');\n\n this._dropBlockedDueToMax = attemptedDisabledTarget && maxReached;\n this.validate();\n this.reportValidity();\n }\n\n /**\n * Fly a chip home from wherever it was last seen on screen.\n *\n * `from` is never read off `dragState` in here, and that is deliberate. Two different chips take\n * this path: the one the user dragged, whose origin is the drag clone, and the occupant a swap\n * evicted, whose origin is the dropzone it was sitting in. Reading the clone's rect for both\n * would launch the evicted chip out of the cursor, from a place it had never been.\n */\n private animateReturn(element: HTMLElement | undefined, from: DOMRect | undefined): void {\n if (!element || !from || !this.enableFlipAnimations) return;\n // A frame late, on purpose. A declarative target's chips are rendered by Lit on a microtask,\n // so measuring the chip's resting box straight after `placeChip` reads the box it had before\n // the render. FLIP would then invert against the wrong \"last\" and the chip would arrive\n // somewhere other than where it is.\n requestAnimationFrame(() => {\n animateFlip(element, flipStateFromRect(from), this.flipAnimationConfig);\n });\n }\n\n private restoreInventoryItem(dragSource: HTMLElement, from?: DOMRect): void {\n clearDragChipStates(dragSource);\n dragSource.style.display = '';\n dragSource.style.position = '';\n this.animateReturn(dragSource, from);\n }\n\n private placeResponse(response: string): void {\n const [dropIdentifier, ...dragIdentifiers] = response.split(' ').reverse();\n const droppable = this.trackedDroppables.find(d => d.getAttribute('identifier') === dropIdentifier);\n if (!droppable) return;\n\n dragIdentifiers.forEach(dragId => {\n if (!dragId) return;\n\n const fromInventory = findInventoryItems(this.trackedDragContainers, dragId).at(0);\n const draggable = fromInventory || this.trackedDraggables.find(d => d.getAttribute('identifier') === dragId);\n if (!draggable) return;\n\n this.dropDraggableInDroppable(draggable, droppable);\n });\n }\n\n private dropDraggableInDroppable(\n draggable: HTMLElement,\n droppable: HTMLElement,\n dragClonePosition?: DOMRect\n ): void {\n const isDragContainer = this.trackedDragContainers.includes(droppable);\n\n if (isDragContainer) {\n // Optional legacy compatibility:\n // for some interactions, dropping an inventory item back onto inventory\n // clears placed clones for that identifier.\n if (!this.dragState.sourceDroppable) {\n if (this.shouldReturnToInventoryOnInventoryDrop()) {\n this.returnToInventory(draggable, dragClonePosition);\n this._dropBlockedDueToMax = false;\n this.validate();\n return;\n }\n\n // Keep the inventory source item in place for interactions that don't\n // use \"drop to inventory clears placed clones\" semantics (e.g. gap-match).\n this.restoreInventoryItem(draggable, dragClonePosition);\n this.cacheInteractiveElements();\n this.checkAllMaxAssociations();\n this._dropBlockedDueToMax = false;\n this.validate();\n return;\n }\n\n const identifier = draggable.getAttribute('identifier');\n this.removeChipFromDroppable(this.droppableHolding(draggable), draggable);\n\n if (identifier) {\n this.restoreOriginalInInventory(identifier, dragClonePosition);\n }\n\n this.cacheInteractiveElements();\n this.checkAllMaxAssociations();\n\n // Clear the blocked flag and re-validate since we've removed an association\n this._dropBlockedDueToMax = false;\n this.validate();\n\n return;\n }\n\n const parsedMatchMax = parseInt(droppable.getAttribute('match-max') || '1', 10);\n const matchMax = Number.isNaN(parsedMatchMax) ? 1 : parsedMatchMax;\n const allowsMultiple = matchMax === 0 || matchMax > 1;\n\n // FLIP: First - capture positions of existing children in droppable\n const existingChildren = Array.from(droppable.querySelectorAll<HTMLElement>('[qti-draggable=\"true\"]'));\n const flipStates =\n this.enableFlipAnimations && existingChildren.length > 0 ? captureMultipleFlipStates(existingChildren) : null;\n\n if (!allowsMultiple) {\n const existing =\n this.chipsIn(droppable)[0] ??\n (this.isDeclarativeTarget(droppable) ? null : droppable.querySelector('[qti-draggable=\"true\"]'));\n if (existing) {\n const existingId = existing.getAttribute('identifier');\n // Where the evicted occupant is standing right now. Taken before it is removed, because\n // afterwards it has no box to measure — and it is *this* rect it should travel from, not\n // the dragged chip's clone.\n const evictedFrom = (existing as HTMLElement).getBoundingClientRect();\n this.removeChipFromDroppable(droppable, existing as HTMLElement);\n\n // A single-capacity target that already holds a chip and receives one *from another\n // target* swaps them: the occupant takes the dragged chip's vacated place. Dragged from\n // the inventory instead, the occupant simply goes back to the bank.\n //\n // Non-declarative targets get this from the sortable mixin's hover preview, which moves\n // the occupant's DOM node. A target that renders from data has no node to move.\n const source = this.dragState.sourceDroppable;\n const swapInto =\n this.isDeclarativeTarget(droppable) && source && source !== droppable && this.isDeclarativeTarget(source)\n ? source\n : null;\n\n if (swapInto) {\n this.placeChip(swapInto, existing as HTMLElement);\n setDropFilled(swapInto, true);\n this.animateReturn(existing as HTMLElement, evictedFrom);\n } else if (existingId) {\n this.restoreOriginalInInventory(existingId, evictedFrom);\n }\n }\n }\n\n const cleanClone = draggable.cloneNode(true) as HTMLElement;\n cleanClone.removeAttribute('style'); // Remove inline styles from the clone\n cleanClone.removeAttribute('data-keyboard-dragging'); // Remove keyboard dragging indicator\n cleanClone.setAttribute('qti-draggable', 'true');\n cleanClone.setAttribute('tabindex', '0');\n\n // FLIP: Last - add the new element (this may cause siblings to shift)\n if (this.isDeclarativeTarget(droppable)) {\n // A chip inside the target's shadow root is unreachable by tag, attribute or `:state()`\n // from the document — `::part()` is the only way in, and a bare `::part(drag)` matches in\n // any shadow root. Without this the chip renders unstyled, which the invariance spec\n // catches as \"a chip is not the same size wherever it lives\".\n cleanClone.setAttribute('part', 'drag');\n // Parts do not chain: `::part(drag)::part(control)` is inert. The chip forwards its own\n // inner part up one level, renamed, so a theme can still reach the drag handle as\n // `::part(drag-control)`. Drawing the grip on the chip host instead would have worked too,\n // but it moves the glyph for every *other* interaction's chips as well.\n // `correction*` forwarded under its own name: the theme reaches the badge with a bare\n // `::part(correction-correct)` whether the chip is in the bank or inside this target.\n cleanClone.setAttribute(\n 'exportparts',\n 'control: drag-control, label: drag-label, correction, correction-correct, correction-incorrect'\n );\n // Cloned once, here — never inside `render()`, which would mint a new node per update and\n // lose focus, transitions and the chip's own shadow root.\n this.placeChip(droppable, cleanClone);\n } else if (droppable.tagName === 'SLOT') {\n cleanClone.setAttribute('slot', droppable.getAttribute('name') || '');\n } else if (droppable.tagName === 'QTI-SIMPLE-ASSOCIABLE-CHOICE') {\n cleanClone.setAttribute('slot', 'qti-simple-associable-choice');\n droppable.appendChild(cleanClone);\n } else {\n droppable.appendChild(cleanClone);\n }\n\n // Every drop target says it is occupied, not just the one branch that used to.\n setDropFilled(droppable, true);\n // Publish placement so a declarative target re-renders before anything measures it.\n this.syncDragDropState();\n\n if (flipStates && this.enableFlipAnimations) {\n animateMultipleFlips(flipStates, this.flipAnimationConfig);\n }\n\n // FLIP: Animate the newly dropped element from drag position to final position\n if (dragClonePosition && this.enableFlipAnimations) {\n requestAnimationFrame(() => {\n const finalPosition = cleanClone.getBoundingClientRect();\n\n const deltaX = dragClonePosition.left - finalPosition.left;\n const deltaY = dragClonePosition.top - finalPosition.top;\n\n // Only animate if there's actual movement\n if (deltaX !== 0 || deltaY !== 0) {\n cleanClone.animate(\n [\n {\n transform: `translate(${deltaX}px, ${deltaY}px)`,\n opacity: 0.8\n },\n {\n transform: 'translate(0, 0)',\n opacity: 1\n }\n ],\n {\n duration: this.flipAnimationConfig.duration || 200,\n easing: this.flipAnimationConfig.easing || 'ease',\n fill: 'both'\n }\n );\n }\n });\n }\n\n const identifier = draggable.getAttribute('identifier');\n if (identifier) {\n this.updateInventoryBasedOnMatchMax(identifier);\n }\n\n this.cacheInteractiveElements();\n this.checkAllMaxAssociations();\n }\n\n private returnToInventory(element: HTMLElement, from?: DOMRect): void {\n const identifier = element.getAttribute('identifier');\n if (identifier) {\n // Remove all clones of this item from drop zones\n this.trackedDroppables.forEach(droppable => {\n const clones = this.chipsIn(droppable).filter(chip => chip.getAttribute('identifier') === identifier);\n clones.forEach(clone => this.removeChipFromDroppable(droppable, clone));\n if (clones.length > 0 && this.chipsIn(droppable).length === 0) {\n setDropFilled(droppable, false);\n }\n });\n\n this.restoreOriginalInInventory(identifier, from);\n }\n this.cacheInteractiveElements();\n this.checkAllMaxAssociations();\n }\n\n /**\n * @param from where the chip was last painted on screen. Given one, the restored inventory item\n * travels back from there instead of blinking into the bank. The bank's *other* chips still\n * FLIP from their own captured positions, since removing a placeholder can rewrap the row.\n */\n private restoreOriginalInInventory(identifier: string, from?: DOMRect): void {\n const inventoryItems = findInventoryItems(this.trackedDragContainers, identifier);\n\n // FLIP: First - capture positions of the items that merely *shift* when the hole closes.\n //\n // The returning items themselves are excluded. They are still hidden at this point, so their\n // rect is 0×0 at the viewport origin, and FLIP read that as their \"first\" state: the chip\n // animated in from the top-left corner of the screen at scale(0). It travels from `from`\n // instead, which is where the user last saw it.\n const returning = new Set<HTMLElement>(inventoryItems);\n const shiftingItems: HTMLElement[] = [];\n this.trackedDragContainers.forEach(container => {\n container\n .querySelectorAll<HTMLElement>('[qti-draggable=\"true\"]')\n .forEach(item => !returning.has(item) && shiftingItems.push(item));\n });\n\n const flipStates =\n this.enableFlipAnimations && shiftingItems.length > 0 ? captureMultipleFlipStates(shiftingItems) : null;\n\n // FLIP: Last - restore the inventory items (may cause reflow)\n inventoryItems.forEach(item => {\n clearDragChipStates(item);\n item.style.display = '';\n item.style.visibility = 'visible';\n });\n\n // FLIP: Invert & Play - animate items that may have shifted\n if (flipStates && this.enableFlipAnimations) {\n animateMultipleFlips(flipStates, this.flipAnimationConfig);\n }\n\n // ...and fly the chip itself home, from the dropzone or the cursor it left.\n inventoryItems.forEach(item => this.animateReturn(item, from));\n }\n\n private updateInventoryBasedOnMatchMax(identifier: string): void {\n const inventoryItems = findInventoryItems(this.trackedDragContainers, identifier);\n const matchMax = getMatchMaxValue(this.trackedDraggables, identifier);\n\n // Count only items placed in dropzones, not in inventory/drag containers\n const placedInDropzones = this.trackedDroppables.reduce((count, droppable) => {\n if (this.isDeclarativeTarget(droppable)) {\n return count + this.chipsIn(droppable).filter(c => c.getAttribute('identifier') === identifier).length;\n }\n return count + droppable.querySelectorAll(`[identifier=\"${identifier}\"]`).length;\n }, 0);\n\n // This source chip's copies are all placed — it becomes the hole they left behind.\n inventoryItems.forEach(item => {\n setDragChipState(item, 'placeholder', matchMax !== 0 && placedInDropzones >= matchMax);\n });\n }\n\n private checkAllMaxAssociations(): void {\n const totalAssociations = this.totalAssociationsFromState();\n const disableAtMax = this.resolveDisableAfterMaxReached({ defaultWhenUnset: true });\n\n const maxReached = this.maxAssociations > 0 && totalAssociations >= this.maxAssociations;\n\n this.trackedDroppables.forEach(droppable => {\n // Don't disable the source droppable during an active drag\n const isDragSource = droppable.hasAttribute('data-drag-source');\n const isAtCapacity = this.droppableAtCapacityFromState(droppable);\n\n if ((isAtCapacity || (disableAtMax && maxReached)) && !isDragSource) {\n droppable.setAttribute('disabled', '');\n } else {\n droppable.removeAttribute('disabled');\n }\n });\n }\n\n public override saveResponse(): void;\n public override saveResponse(value: string | string[]): void;\n public override saveResponse(value?: string | string[]): void {\n const getResponse = (this as unknown as { getResponse?: () => unknown }).getResponse;\n const candidate = value ?? (typeof getResponse === 'function' ? getResponse.call(this) : undefined);\n const responseData = Array.isArray(candidate)\n ? candidate\n : typeof candidate === 'string'\n ? [candidate]\n : (() => {\n this.cacheInteractiveElements();\n return this.responseFromState();\n })();\n\n // Persist response state without mutating the DOM tree.\n // Using the response setter here can trigger reset/replay flows that clear\n // partially completed interactions (e.g. associate left side dropped first).\n this._response = responseData;\n this._internals.setFormValue(JSON.stringify(this._response));\n\n this.dispatchEvent(\n new CustomEvent('qti-interaction-response', {\n bubbles: true,\n composed: true,\n detail: {\n responseIdentifier: (this as unknown as { responseIdentifier?: string }).responseIdentifier,\n response: responseData\n }\n })\n );\n\n this.requestUpdate();\n }\n\n override reset(): void;\n override reset(save: boolean): void;\n override reset(save = true): void {\n this.trackedDroppables.forEach(droppable => {\n this.clearChips(droppable);\n });\n\n this.trackedDraggables.forEach(draggable => {\n const identifier = draggable.getAttribute('identifier');\n if (identifier) {\n this.restoreOriginalInInventory(identifier);\n }\n });\n\n this.resetDragState();\n this.cacheInteractiveElements();\n\n this._response = [];\n this._internals.setFormValue(JSON.stringify(this._response));\n\n if (save) {\n this.saveResponse();\n }\n }\n\n public override validate(): boolean {\n const totalAssociations = this.totalAssociationsFromState();\n\n const atMaxCapacity = this.maxAssociations > 0 && totalAssociations >= this.maxAssociations;\n const exceedsMax = this.maxAssociations > 0 && totalAssociations > this.maxAssociations;\n const belowMin = this.minAssociations > 0 && totalAssociations < this.minAssociations;\n\n let validityMessage = '';\n let isValid = true;\n\n // Priority order: exceedsMax > (atMaxCapacity && blockedDrop) > belowMin\n if (exceedsMax) {\n // QTI conformance: default platform message format\n validityMessage =\n this.getFirstMessageAttribute(['data-max-associations-message', 'data-max-selections-message']) ||\n this.dataset.maxAssociationsMessage ||\n this.dataset.maxSelectionsMessage ||\n `You've selected too many associations. Maximum allowed is ${this.maxAssociations}.`;\n isValid = false;\n } else if (atMaxCapacity && this._dropBlockedDueToMax && this.shouldTreatBlockedMaxAsInvalid()) {\n validityMessage =\n this.getFirstMessageAttribute(['data-max-associations-message', 'data-max-selections-message']) ||\n this.dataset.maxAssociationsMessage ||\n this.dataset.maxSelectionsMessage ||\n `You've selected too many associations. Maximum allowed is ${this.maxAssociations}.`;\n isValid = false;\n } else if (belowMin) {\n validityMessage =\n this.getFirstMessageAttribute(['data-min-associations-message', 'data-min-selections-message']) ||\n this.dataset.minAssociationsMessage ||\n this.dataset.minSelectionsMessage ||\n `Please select at least ${this.minAssociations} ${this.minAssociations === 1 ? 'association' : 'associations'}.`;\n isValid = false;\n // Clear the blocked flag since we're now in a different error state\n this._dropBlockedDueToMax = false;\n } else {\n // Clear the blocked flag when validation passes\n this._dropBlockedDueToMax = false;\n }\n\n const validityAnchor = this.trackedDroppables[0] ?? this.trackedDraggables[0] ?? this;\n this.setInteractionValidity(isValid, validityMessage, validityAnchor, { suppressInline: true });\n\n return isValid;\n }\n\n public override reportValidity(): boolean {\n return super.reportValidity();\n }\n }\n\n return DragDropSlottedElement as unknown as Constructor<DragDropSlotted> & T;\n};\n","/**\n * Sorting strategies for different layouts.\n */\n\nexport interface InsertPosition {\n index: number;\n placeAfter: boolean;\n}\n\nexport interface SortingStrategy {\n /**\n * Calculate where to insert an item based on pointer position\n * @param elements - Array of sortable elements\n * @param activeElement - The element being dragged\n * @param targetElement - The element being hovered over\n * @param clientX - Pointer X coordinate\n * @param clientY - Pointer Y coordinate\n * @returns Insert position information\n */\n getInsertPosition(\n elements: HTMLElement[],\n activeElement: HTMLElement,\n targetElement: HTMLElement,\n clientX: number,\n clientY: number\n ): InsertPosition | null;\n}\n\nexport class VerticalListSortingStrategy implements SortingStrategy {\n getInsertPosition(\n elements: HTMLElement[],\n _activeElement: HTMLElement,\n targetElement: HTMLElement,\n _clientX: number,\n clientY: number\n ): InsertPosition | null {\n const targetIndex = elements.indexOf(targetElement);\n if (targetIndex === -1) return null;\n\n const rect = targetElement.getBoundingClientRect();\n const relative = (clientY - rect.top) / rect.height;\n const clampedRelative = Math.min(1, Math.max(0, relative));\n\n // Use 50% threshold - simpler and more intuitive\n // If pointer is in top half, place before; if in bottom half, place after\n const placeAfter = clampedRelative > 0.5;\n\n return {\n index: targetIndex,\n placeAfter\n };\n }\n}\n\nexport class HorizontalListSortingStrategy implements SortingStrategy {\n getInsertPosition(\n elements: HTMLElement[],\n _activeElement: HTMLElement,\n targetElement: HTMLElement,\n clientX: number,\n _clientY: number\n ): InsertPosition | null {\n const targetIndex = elements.indexOf(targetElement);\n if (targetIndex === -1) return null;\n\n const rect = targetElement.getBoundingClientRect();\n const relative = (clientX - rect.left) / rect.width;\n const clampedRelative = Math.min(1, Math.max(0, relative));\n\n // Check if this is the last item in the list\n const isLastItem = targetIndex === elements.length - 1;\n\n // For the last item, use a 33% threshold to make it easier to place items after it\n // For other items, use 50% threshold for balanced behavior\n const threshold = isLastItem ? 0.33 : 0.5;\n const placeAfter = clampedRelative > threshold;\n\n return {\n index: targetIndex,\n placeAfter\n };\n }\n}\n\n/**\n * Default sorting strategy (vertical)\n * Use VerticalListSortingStrategy or HorizontalListSortingStrategy explicitly\n * for better control over orientation.\n */\nexport const defaultSortingStrategy = new VerticalListSortingStrategy();\n","/**\n * Shared utilities for sortable drag-and-drop behavior.\n * Used by both DragDropSortableMixin (standalone) and SlotSortableEnhancerMixin (composition).\n */\n\nimport {\n captureMultipleFlipStates,\n animateMultipleFlips,\n resolveMotionScale,\n type FlipAnimationOptions\n} from './flip.utils';\n\nimport type { SortingStrategy, InsertPosition } from '../strategies/sorting.strategy';\n\n/**\n * Configuration for drop placeholder styling\n */\nexport interface PlaceholderConfig {\n borderStyle?: string;\n borderColor?: string;\n background?: string;\n transitionDuration?: number;\n}\n\nconst defaultPlaceholderConfig: PlaceholderConfig = {\n borderStyle: '2px dashed',\n borderColor: 'var(--qti-drop-highlight-border-color, #c1c1c1)',\n background: 'transparent',\n transitionDuration: 150\n};\n\n/**\n * State tracking for sortable drag operations\n */\nexport interface SortableDragContext {\n /** The placeholder element shown during drag */\n placeholder: HTMLElement | null;\n /** Last element that was hovered over */\n lastHoverTarget: HTMLElement | null;\n /** Last calculated placement to avoid redundant DOM operations */\n lastPlacement: { target: HTMLElement; after: boolean } | null;\n /** Container where sorting is occurring */\n sortContainer: HTMLElement | null;\n}\n\n/**\n * Creates a new sortable drag context\n */\nexport function createSortableDragContext(): SortableDragContext {\n return {\n placeholder: null,\n lastHoverTarget: null,\n lastPlacement: null,\n sortContainer: null\n };\n}\n\n/**\n * Resets the sortable drag context, cleaning up any DOM elements\n */\nexport function resetSortableDragContext(context: SortableDragContext): void {\n context.placeholder?.remove();\n context.placeholder = null;\n context.lastHoverTarget = null;\n context.lastPlacement = null;\n context.sortContainer = null;\n}\n\n/**\n * Creates a placeholder element that matches the dimensions of the dragged element\n */\nexport function createDropPlaceholder(source: HTMLElement, rect: DOMRect, config: PlaceholderConfig = {}): HTMLElement {\n const mergedConfig = { ...defaultPlaceholderConfig, ...config };\n const placeholder = document.createElement('div');\n\n placeholder.setAttribute('data-drop-placeholder', 'true');\n placeholder.style.width = `${rect.width}px`;\n placeholder.style.height = `${rect.height}px`;\n placeholder.style.margin = window.getComputedStyle(source).margin;\n placeholder.style.boxSizing = 'border-box';\n placeholder.style.border = `${mergedConfig.borderStyle} ${mergedConfig.borderColor}`;\n placeholder.style.borderRadius = getComputedStyle(source).borderRadius;\n placeholder.style.background = mergedConfig.background!;\n // Same --qti-motion budget as FLIP: 0 (or reduced-motion) snaps the placeholder instead of sliding.\n placeholder.style.transition = `transform ${mergedConfig.transitionDuration! * resolveMotionScale(source)}ms ease`;\n placeholder.style.pointerEvents = 'none';\n\n return placeholder;\n}\n\n/**\n * Options for placeholder positioning\n */\nexport interface PlacePlaceholderOptions {\n /** The sortable drag context */\n context: SortableDragContext;\n /** Selector to find sortable items */\n itemSelector: string;\n /** Sorting strategy to use */\n strategy: SortingStrategy;\n /** The element being dragged (to exclude from sibling calculations) */\n dragSource: HTMLElement | null;\n /** Target element under the pointer */\n dropTarget: HTMLElement | null;\n /** Pointer X coordinate */\n clientX: number;\n /** Pointer Y coordinate */\n clientY: number;\n /** Whether to animate sibling movements */\n enableAnimations: boolean;\n /** Animation configuration */\n animationConfig?: FlipAnimationOptions;\n}\n\n/**\n * Places the placeholder at the appropriate position within the sort container.\n * Uses FLIP animations for smooth sibling transitions.\n *\n * @returns The calculated insert position, or null if placement was skipped\n */\nexport function placePlaceholderAtPosition(options: PlacePlaceholderOptions): InsertPosition | null {\n const {\n context,\n itemSelector,\n strategy,\n dragSource,\n dropTarget,\n clientX,\n clientY,\n enableAnimations,\n animationConfig = { duration: 150, easing: 'ease' }\n } = options;\n\n if (!context.placeholder || !context.sortContainer) return null;\n\n const target = dropTarget || context.lastHoverTarget;\n if (!target || target === dragSource) return null;\n\n // Ensure placeholder is in the container\n if (context.placeholder.parentElement !== context.sortContainer) {\n context.sortContainer.appendChild(context.placeholder);\n }\n\n // Get visible siblings (exclude placeholder and hidden elements)\n const siblings = Array.from(context.sortContainer.querySelectorAll<HTMLElement>(itemSelector)).filter(\n el => el !== context.placeholder && el.style.display !== 'none'\n );\n\n if (!dragSource || siblings.indexOf(target) === -1) return null;\n\n // Use strategy to determine insertion position\n const insertPosition = strategy.getInsertPosition(siblings, dragSource, target, clientX, clientY);\n if (!insertPosition) return null;\n\n const { placeAfter } = insertPosition;\n\n // Check if this placement is the same as the last one\n if (context.lastPlacement && context.lastPlacement.target === target && context.lastPlacement.after === placeAfter) {\n return insertPosition;\n }\n\n // FLIP: First - capture positions of all visible siblings before moving placeholder\n const visibleSiblings = Array.from(context.sortContainer.children).filter(\n child => child !== context.placeholder && (child as HTMLElement).style.display !== 'none'\n ) as HTMLElement[];\n\n const flipStates = enableAnimations ? captureMultipleFlipStates(visibleSiblings) : null;\n\n // Calculate the reference node for insertion\n const referenceNode = placeAfter ? target.nextElementSibling : target;\n\n // FLIP: Last - perform the DOM mutation\n context.sortContainer.insertBefore(context.placeholder, referenceNode);\n context.lastPlacement = { target, after: placeAfter };\n\n // FLIP: Invert & Play - animate siblings to their new positions\n if (flipStates && enableAnimations) {\n animateMultipleFlips(flipStates, animationConfig);\n }\n\n return insertPosition;\n}\n\n/**\n * Options for finalizing a sortable drop\n */\nexport interface FinalizeSortableDropOptions {\n /** The sortable drag context */\n context: SortableDragContext;\n /** The element being dropped */\n draggable: HTMLElement;\n /** Callback after the element is placed */\n onPlaced?: (draggable: HTMLElement, container: HTMLElement) => void;\n}\n\n/**\n * Finalizes a sortable drop by replacing the placeholder with the actual element\n */\nexport function finalizeSortableDrop(options: FinalizeSortableDropOptions): boolean {\n const { context, draggable, onPlaced } = options;\n\n if (context.placeholder?.parentElement) {\n context.placeholder.parentElement.replaceChild(draggable, context.placeholder);\n\n // Restore draggable styles\n draggable.style.opacity = '1.0';\n draggable.style.display = '';\n draggable.style.pointerEvents = 'auto';\n\n if (onPlaced && context.sortContainer) {\n onPlaced(draggable, context.sortContainer);\n }\n\n // Cleanup\n context.placeholder = null;\n context.lastPlacement = null;\n\n return true;\n }\n\n return false;\n}\n\n/**\n * Cancels a sortable drag, cleaning up the placeholder\n */\nexport function cancelSortableDrag(context: SortableDragContext, dragSource: HTMLElement | null): void {\n if (dragSource) {\n dragSource.style.opacity = '1.0';\n dragSource.style.display = '';\n dragSource.style.pointerEvents = 'auto';\n }\n\n resetSortableDragContext(context);\n}\n\n/**\n * Reorders DOM elements according to a list of identifiers.\n * Uses FLIP animation for smooth transitions.\n */\nexport function reorderDOMByIdentifiers(\n container: HTMLElement,\n draggables: HTMLElement[],\n identifiers: string[],\n enableAnimations: boolean,\n animationConfig: FlipAnimationOptions = { duration: 250, easing: 'ease' }\n): void {\n if (!container) return;\n\n const byId = new Map(\n draggables.map(el => [el.getAttribute('identifier') ?? '', el] as const).filter(([id]) => Boolean(id))\n );\n\n // FLIP: First - capture initial positions before DOM changes\n const flipStates = enableAnimations ? captureMultipleFlipStates(draggables) : null;\n\n // FLIP: Last - perform the DOM mutation\n identifiers.forEach(id => {\n const el = byId.get(id);\n if (el) {\n container.appendChild(el);\n }\n });\n\n // Append any elements not in the identifiers list at the end\n draggables\n .filter(el => {\n const id = el.getAttribute('identifier') ?? '';\n return id && !identifiers.includes(id);\n })\n .forEach(el => container.appendChild(el));\n\n // FLIP: Invert & Play - animate elements to their new positions\n if (flipStates && enableAnimations) {\n animateMultipleFlips(flipStates, animationConfig);\n }\n}\n\n/**\n * Collects identifiers from elements in DOM order\n */\nexport function collectIdentifiersInOrder(elements: HTMLElement[]): string[] {\n return elements.map(el => el.getAttribute('identifier')).filter((id): id is string => Boolean(id));\n}\n\n/**\n * Checks if an element is inside a slot/droppable container\n */\nexport function isElementInContainer(element: HTMLElement, containers: HTMLElement[]): HTMLElement | null {\n for (const container of containers) {\n if (container.contains(element) && container !== element) {\n return container;\n }\n }\n return null;\n}\n","import {\n createSortableDragContext,\n resetSortableDragContext,\n createDropPlaceholder,\n isElementInContainer,\n type SortableDragContext,\n type PlaceholderConfig\n} from './utils/sortable.utils';\nimport { captureMultipleFlipStates, animateMultipleFlips, type FlipAnimationOptions } from './utils/flip.utils';\nimport { detectCollision } from './utils/collision.utils';\n\nimport type { DragDropSlotted } from './drag-drop-slotted.mixin';\n\ntype Constructor<T = {}> = abstract new (...args: any[]) => T;\n\nexport type DragDropSlottedSortable = DragDropSlotted & {\n allowReorder: boolean;\n readonly isDraggingFromSlot: boolean;\n sortablePlaceholderConfig: PlaceholderConfig;\n};\n\ninterface ShiftState {\n hoveredSlot: HTMLElement | null;\n originalPositions: Map<HTMLElement, HTMLElement>;\n}\n\nexport const DragDropSlottedSortableMixin = <T extends Constructor<DragDropSlotted>>(\n superClass: T,\n sortableItemSelector = '[qti-draggable=\"true\"]'\n) => {\n abstract class DragDropSlottedSortableElement extends superClass {\n #sourceSlot: HTMLElement | null = null;\n // The drop target a drag originated from (null for bank/inventory-origin drags). Set at\n // initiateDrag while the chip is still in place; read by allowDrop to block reorders.\n #dragOriginDroppable: HTMLElement | null = null;\n #sortableContext: SortableDragContext = createSortableDragContext();\n #shiftState: ShiftState = {\n hoveredSlot: null,\n originalPositions: new Map()\n };\n #temporarilyEnabledSlots = new Set<HTMLElement>();\n\n // Reordering placed chips is on by default. Resolved from the `allowReorder` config-context\n // value (see resolveAllowReorder), with an explicit property assignment taking precedence — so\n // `interaction.allowReorder = false` still works, and a config provider can set it globally.\n #allowReorderExplicit?: boolean;\n set allowReorder(value: boolean) {\n this.#allowReorderExplicit = value;\n }\n get allowReorder(): boolean {\n return this.#allowReorderExplicit ?? this.resolveAllowReorder({ defaultWhenUnset: true });\n }\n public sortablePlaceholderConfig: PlaceholderConfig = {};\n public sortableAnimationConfig: FlipAnimationOptions = {\n duration: 150,\n easing: 'ease'\n };\n\n get isDraggingFromSlot(): boolean {\n return this.#sourceSlot !== null;\n }\n\n protected findContainingDroppable(element: HTMLElement): HTMLElement | null {\n return isElementInContainer(element, this.trackedDroppables);\n }\n\n #getItemInSlot(slot: HTMLElement): HTMLElement | null {\n return slot.querySelector(sortableItemSelector) as HTMLElement | null;\n }\n\n #slotAllowsMultiple(slot: HTMLElement): boolean {\n const matchMax = this.#getSlotMatchMax(slot);\n return matchMax === 0 || matchMax > 1;\n }\n\n #getSlotMatchMax(slot: HTMLElement): number {\n const parsedMatchMax = parseInt(slot.getAttribute('match-max') || '1', 10);\n return Number.isNaN(parsedMatchMax) ? 1 : parsedMatchMax;\n }\n\n #getSlotItemCount(slot: HTMLElement): number {\n return slot.querySelectorAll(sortableItemSelector).length;\n }\n\n #isSlotAtCapacity(slot: HTMLElement): boolean {\n const matchMax = this.#getSlotMatchMax(slot);\n if (matchMax === 0) return false;\n return this.#getSlotItemCount(slot) >= matchMax;\n }\n\n #resetShiftState(): void {\n this.#shiftState = {\n hoveredSlot: null,\n originalPositions: new Map()\n };\n }\n\n #performVisualSwap(targetSlot: HTMLElement): void {\n if (!this.#sourceSlot || targetSlot === this.#sourceSlot) {\n this.#revertVisualSwaps();\n return;\n }\n\n if (this.#shiftState.hoveredSlot === targetSlot) {\n return;\n }\n\n this.#revertVisualSwaps();\n\n const targetItem = this.#getItemInSlot(targetSlot);\n if (!targetItem) {\n if (this.#sortableContext.placeholder) {\n targetSlot.appendChild(this.#sortableContext.placeholder);\n }\n this.#shiftState.hoveredSlot = targetSlot;\n return;\n }\n\n // For multi-capacity slots we preview append semantics, not swap semantics.\n if (this.#slotAllowsMultiple(targetSlot)) {\n if (this.#isSlotAtCapacity(targetSlot)) {\n if (this.#sortableContext.placeholder && this.#sourceSlot) {\n this.#sourceSlot.appendChild(this.#sortableContext.placeholder);\n }\n this.#shiftState.hoveredSlot = null;\n return;\n }\n if (this.#sortableContext.placeholder) {\n targetSlot.appendChild(this.#sortableContext.placeholder);\n }\n this.#shiftState.hoveredSlot = targetSlot;\n return;\n }\n\n // A declarative target renders its chips from `dragDropContext`. Moving its nodes here as a\n // hover preview would be undone by the next render, and the swap it was standing in for is\n // done properly at drop time over the placement map. So: no preview, just the hover state.\n //\n // Use the shared declarative-target predicate from DragDropSlottedMixin so both declarative\n // forms are covered (property-based custom elements and attribute-based targets like\n // `data-declarative-drops` in order-interaction).\n if (this.isDeclarativeTarget(targetSlot)) {\n if (this.#sortableContext.placeholder?.parentElement) this.#sortableContext.placeholder.remove();\n this.#shiftState.hoveredSlot = targetSlot;\n return;\n }\n\n const itemsToAnimate = [targetItem];\n const flipStates = captureMultipleFlipStates(itemsToAnimate);\n\n this.#shiftState.originalPositions.set(targetItem, targetSlot);\n\n if (this.#sortableContext.placeholder && this.#sortableContext.placeholder.parentElement) {\n this.#sortableContext.placeholder.remove();\n }\n\n this.#sourceSlot.appendChild(targetItem);\n\n if (this.#sortableContext.placeholder) {\n targetSlot.appendChild(this.#sortableContext.placeholder);\n }\n\n this.#shiftState.hoveredSlot = targetSlot;\n\n animateMultipleFlips(flipStates, this.sortableAnimationConfig);\n }\n\n #revertVisualSwaps(): void {\n if (this.#shiftState.originalPositions.size === 0 && this.#shiftState.hoveredSlot === null) {\n return;\n }\n\n const itemsToAnimate = Array.from(this.#shiftState.originalPositions.keys());\n const flipStates = itemsToAnimate.length > 0 ? captureMultipleFlipStates(itemsToAnimate) : null;\n\n for (const [item, originalSlot] of this.#shiftState.originalPositions) {\n originalSlot.appendChild(item);\n }\n\n if (this.#sortableContext.placeholder && this.#sourceSlot) {\n this.#sourceSlot.appendChild(this.#sortableContext.placeholder);\n }\n\n if (flipStates) {\n animateMultipleFlips(flipStates, this.sortableAnimationConfig);\n }\n\n this.#shiftState.originalPositions.clear();\n this.#shiftState.hoveredSlot = null;\n }\n\n public override initiateDrag(\n dragElement: HTMLElement,\n startX: number,\n startY: number,\n inputType: 'mouse' | 'touch',\n ...rest: [eventSource?: 'pointer' | 'mouse' | 'touch']\n ): void {\n this.#sourceSlot = null;\n this.#sortableContext = createSortableDragContext();\n this.#resetShiftState();\n\n const containingDroppable = this.findContainingDroppable(dragElement);\n // Record the origin drop target now, while the chip is still in place — allowDrop needs it to\n // block a reorder, and by drop time the chip has been lifted out. Captured for every drag,\n // independent of allowReorder (which only gates the sortable preview below).\n this.#dragOriginDroppable = containingDroppable;\n\n if (containingDroppable && this.allowReorder) {\n this.#sourceSlot = containingDroppable;\n this.#sortableContext.sortContainer = containingDroppable;\n\n const rect = dragElement.getBoundingClientRect();\n this.#sortableContext.placeholder = createDropPlaceholder(dragElement, rect, this.sortablePlaceholderConfig);\n // Copy the slot attribute from the dragged element so the placeholder\n // renders in the same named slot (e.g. slot=\"drags\" in qti-gap), preserving\n // the droppable's dimensions when the drag element is removed.\n // Use visibility:hidden instead of display:none so it occupies space but\n // remains invisible, preventing inline layout shift of surrounding text.\n const slotAttr = dragElement.getAttribute('slot');\n if (slotAttr) {\n this.#sortableContext.placeholder.setAttribute('slot', slotAttr);\n }\n this.#sortableContext.placeholder.style.visibility = 'hidden';\n\n containingDroppable.appendChild(this.#sortableContext.placeholder);\n\n // Temporarily enable peer slots so slot-origin drags can still land on max-gated targets.\n this.trackedDroppables.forEach(slot => {\n if (slot !== containingDroppable && slot.hasAttribute('disabled')) {\n if (this.#slotAllowsMultiple(slot) && this.#isSlotAtCapacity(slot)) {\n return;\n }\n slot.removeAttribute('disabled');\n this.#temporarilyEnabledSlots.add(slot);\n }\n });\n }\n\n const [eventSource] = rest;\n (super.initiateDrag as any)(dragElement, startX, startY, inputType, eventSource);\n }\n\n protected cleanupSortableState(revertSwaps = true): void {\n if (revertSwaps) {\n for (const [item, originalSlot] of this.#shiftState.originalPositions) {\n originalSlot.appendChild(item);\n }\n }\n\n if (this.#sortableContext.placeholder) {\n this.#sortableContext.placeholder.remove();\n }\n\n resetSortableDragContext(this.#sortableContext);\n this.#temporarilyEnabledSlots.clear();\n this.#sourceSlot = null;\n this.#resetShiftState();\n }\n\n public onSortableDragMove(clientX: number, clientY: number): void {\n if (!this.isDraggingFromSlot) return;\n\n const dropTarget = detectCollision(\n this.trackedDroppables,\n clientX,\n clientY,\n this.dragState.dragClone,\n this.collisionDetectionAlgorithm\n );\n\n if (dropTarget) {\n this.#performVisualSwap(dropTarget);\n } else {\n this.#revertVisualSwaps();\n }\n }\n\n protected handleDragMove(clientX: number, clientY: number): void {\n const baseProto = Object.getPrototypeOf(DragDropSlottedSortableElement.prototype) as {\n handleDragMove?: (x: number, y: number) => void;\n };\n baseProto.handleDragMove?.call(this, clientX, clientY);\n this.onSortableDragMove(clientX, clientY);\n }\n\n public override allowDrop(draggable: HTMLElement, droppable: HTMLElement): boolean {\n // Reordering disabled: a chip already placed in a *drop target* may not move to a different\n // target. The origin is captured at initiateDrag (#dragOriginDroppable) because by now the chip\n // has been lifted out of its slot. Bank/inventory-origin drags (origin is a drag container, or\n // null) are initial placements, not reorders, so they pass through untouched.\n if (\n !this.allowReorder &&\n this.#dragOriginDroppable &&\n !this.trackedDragContainers.includes(this.#dragOriginDroppable) &&\n droppable !== this.#dragOriginDroppable &&\n this.trackedDroppables.includes(droppable)\n ) {\n return false;\n }\n if (this.isDraggingFromSlot && this.trackedDroppables.includes(droppable)) {\n if (!this.#slotAllowsMultiple(droppable)) {\n return true;\n }\n return !this.#isSlotAtCapacity(droppable);\n }\n if (this.isDraggingFromSlot && this.trackedDragContainers.includes(droppable)) {\n return true;\n }\n return super.allowDrop(draggable, droppable);\n }\n\n public override handleDrop(draggable: HTMLElement, droppable: HTMLElement): void {\n super.handleDrop(draggable, droppable);\n this.cleanupSortableState(false);\n }\n\n public override handleInvalidDrop(dragSource: HTMLElement | null): void {\n this.cleanupSortableState();\n super.handleInvalidDrop(dragSource);\n }\n }\n\n return DragDropSlottedSortableElement as Constructor<DragDropSlottedSortable> & T;\n};\n\nexport type { PlaceholderConfig };\n","import { css } from 'lit';\n\nimport { boxSizing, dropRegion, validationMessage } from '@qti-components/base';\n\n/**\n * Layout and sizing only. Paint and state live in the theme.\n *\n * `[part~='drop'][active]` and `[part~='drop'][enabled]` moved to\n * `styles/qti-theme/interactions/qti-associate-interaction.css` as `::part(active)` /\n * `::part(enabled)`, since an attribute selector cannot follow `::part()` and a <div> cannot carry\n * a custom state. Both carried `!important`, which only existed to beat the shadow's own rules from\n * the shadow. Neither needs it from the theme.\n */\n\nexport default [\n boxSizing,\n validationMessage,\n dropRegion,\n css`\n :host {\n display: block; /* necessary to calculate scaling position */\n }\n /* The bank WRAPS. Without flex-wrap the row is nowrap, and a flex item's default flex-shrink: 1\n then compresses the chips instead of moving them down: a bank of six squeezed the last chip\n until only its grip was left, at no width the author could see coming. A chip is a fixed\n thing, so the only place the overflow can go is the next line. */\n slot[part~='drags'] {\n display: flex;\n flex-wrap: wrap;\n align-items: flex-start;\n flex: 1;\n border: 2px solid transparent;\n margin: 1rem 0;\n border-radius: 0.3rem;\n gap: 0.5rem;\n }\n\n /* Drop target. --qti-dropzone-min-height is published by the interaction from the measured\n chip height; 3rem is the fallback when there is nothing to measure. Was an inline style. */\n [part~='drop'] {\n display: grid;\n min-height: var(--qti-dropzone-min-height, 3rem);\n min-width: var(--qti-dropzone-min-width, 3rem);\n border: 1px solid var(--qti-border-color, #d1d5db);\n border-radius: 0.25rem;\n overflow: hidden;\n }\n\n [part='drops'] {\n display: flex;\n flex-direction: column;\n gap: 0.5rem;\n }\n\n :host::part(drop-row) {\n display: flex;\n justify-content: space-between;\n background: linear-gradient(\n 180deg,\n rgb(0 0 0 / 0%) calc(50% - 1px),\n var(--qti-border-color) calc(50%),\n rgb(0 0 0 / 0%) calc(50% + 1px)\n );\n }\n\n /* An answer key shows the answer, not the bank you would have dragged it from. The attribute is\n set on the clone by the correct-response mixin; the theme used to do this with a\n '.full-correct-response' descendant selector, from the document. */\n :host([answer-key]) ::slotted(qti-simple-associable-choice) {\n display: none;\n }\n `\n];\n","import { html } from 'lit';\nimport { repeat } from 'lit/directives/repeat.js';\nimport { state } from 'lit/decorators.js';\n\nimport { Interaction } from '@qti-components/base';\nimport {\n DragDropSlottedMixin,\n DragDropSlottedSortableMixin\n} from '@qti-components/interactions-core/mixins/drag-drop-observables';\n\n// import { DragDropInteractionMixin } from '@qti-components/interactions-core/mixins/drag-drop';\nimport styles from './qti-associate-interaction.styles';\n\nimport type { QtiSimpleAssociableChoice } from '@qti-components/interactions-core/elements/qti-simple-associable-choice';\nimport type { CSSResultGroup } from 'lit';\nconst SlottedBase = DragDropSlottedMixin(\n Interaction,\n 'qti-simple-associable-choice',\n `[part~='drop']`,\n `slot[name='qti-simple-associable-choice']`,\n 'pointerWithin'\n);\n\n/**\n * Drag-and-drop associate interaction: candidates pair associable choices.\n *\n * @slot prompt - The prompt shown above the choices.\n * @slot qti-simple-associable-choice - The associable choice sources.\n *\n * @csspart drags - Wrapper around the associable choice slot.\n * @csspart drops - The container holding all drop targets.\n * @csspart drop-row - Container for one left/right drop pair.\n * @csspart drop - Each individual drop target.\n * @csspart message - Live validation message region (role=\"alert\").\n */\nexport class QtiAssociateInteraction extends DragDropSlottedSortableMixin(SlottedBase, '[qti-draggable=\"true\"]') {\n static override styles: CSSResultGroup = styles;\n @state() protected _childrenMap: Element[] = [];\n\n protected _registerChoiceHandler: (event: CustomEvent) => void;\n\n constructor() {\n super();\n this._registerChoiceHandler = this._registerChoice.bind(this);\n this.addEventListener('register-qti-simple-associable-choice', this._registerChoiceHandler);\n }\n\n protected _registerChoice(event: CustomEvent) {\n // Use composedPath()[0] to get the actual origin — event.target is retargeted to `this`\n // when a composed event crosses the shadow DOM boundary, making it useless for filtering.\n const origin = event.composedPath()[0] as HTMLElement;\n // Ignore clones placed in shadow DOM drop zones — only register light DOM choices\n if (this.shadowRoot?.contains(origin)) return;\n const choice = origin as QtiSimpleAssociableChoice;\n if (!this._childrenMap.includes(choice)) {\n this._childrenMap = [...this._childrenMap, choice];\n }\n }\n\n /**\n * A drop target, holding whatever the interaction's placement map says it holds.\n * `data-declarative-drops` tells the mixin to keep the chips in that map rather than appending\n * them into this div.\n */\n #renderDrop(identifier: string, name: string) {\n const drags = this._dragDrop?.nodesByTarget?.[identifier] ?? [];\n return html`<div name=${name} part=\"drop\" data-declarative-drops identifier=${identifier}>\n ${repeat(\n drags,\n node => node.getAttribute('identifier'),\n node => node\n )}\n </div>`;\n }\n\n /**\n * How many association rows to render.\n *\n * `max-associations` is how many associations the candidate may *make*, so it is exactly the\n * number of rows. This used to be `ceil(choices / 2)` — the number of pairs the choices could\n * possibly form — which made the limit unenforceable: with six choices the interaction always\n * drew three rows, so `max-associations=\"3\"` could never be exceeded and its validation always\n * passed. Worse, the number read as a cap on *drags placed* rather than on associations formed.\n *\n * `0` is QTI's \"no limit\". With no limit there is still a natural ceiling: every choice paired\n * with one other.\n */\n get #rowCount(): number {\n return this.maxAssociations > 0 ? this.maxAssociations : Math.ceil(this._childrenMap.length / 2);\n }\n\n protected getResponse(): string[] {\n const response: string[] = [];\n // Same count as `render()`. Read fewer rows than were drawn and the pairs in the last rows\n // vanish from the response without a trace.\n for (let i = 0; i < this.#rowCount; i++) {\n const leftDrop = this.shadowRoot?.querySelector(`[part~='drop'][identifier=\"droplist${i}_left\"]`);\n const rightDrop = this.shadowRoot?.querySelector(`[part~='drop'][identifier=\"droplist${i}_right\"]`);\n // Read placement, not the DOM: the DOM is rendered from placement now.\n const leftId = leftDrop && this.chipsIn(leftDrop as HTMLElement)[0]?.getAttribute('identifier');\n const rightId = rightDrop && this.chipsIn(rightDrop as HTMLElement)[0]?.getAttribute('identifier');\n if (leftId && rightId) {\n response.push(`${leftId} ${rightId}`);\n }\n }\n return response;\n }\n\n /**\n * How many associations the candidate has made.\n *\n * The mixin counts placed chips, which is right for gap-match — one chip in one gap is one\n * association — and wrong here. An association is a *pair*, so three associations are six chips,\n * and `max-associations=\"3\"` compared 6 against 3 and declared the item invalid the moment it was\n * correctly filled in.\n *\n * A half-filled row is not an association yet, and `getResponse()` already knows that: it emits a\n * pair only when both sides hold a chip. Counting its entries counts associations by definition,\n * and keeps the number validation sees equal to the number the response reports.\n */\n public override totalAssociationsFromState(): number {\n // The mixin's version syncs first, and callers depend on that: `getResponse` reads the\n // placement map, which is stale until the sync runs.\n this.syncDragDropState();\n return this.getResponse().length;\n }\n\n getValue(val: string[]) {\n return (\n val?.flatMap((pair, i) => {\n const parts = pair.split(' ');\n if (parts.length !== 2) return [];\n return [`${parts[0]} droplist${i}_left`, `${parts[1]} droplist${i}_right`];\n }) ?? []\n );\n }\n\n override render() {\n return html` <slot name=\"prompt\"></slot>\n <slot part=\"drags\" name=\"qti-simple-associable-choice\"></slot>\n <div part=\"drops\">\n ${this._childrenMap.length > 0 &&\n Array.from(\n { length: this.#rowCount },\n (_, index) =>\n html`<div part=\"drop-row\">\n ${this.#renderDrop(`droplist${index}_left`, `left${index}`)}\n ${this.#renderDrop(`droplist${index}_right`, `right${index}`)}\n </div>`\n )}\n\n <div role=\"alert\" part=\"message\" id=\"validation-message\"></div>\n </div>`;\n }\n\n protected override updated(changedProperties: Map<string, unknown>): void {\n super.updated(changedProperties);\n if (changedProperties.has('_childrenMap')) {\n this.cacheInteractiveElements();\n }\n }\n\n override disconnectedCallback() {\n super.disconnectedCallback();\n this.removeEventListener('register-qti-simple-associable-choice', this._registerChoiceHandler);\n }\n}\n\ndeclare global {\n interface HTMLElementTagNameMap {\n 'qti-associate-interaction': QtiAssociateInteraction;\n }\n}\n","import { property, query, state } from 'lit/decorators.js';\n\nimport { watch } from '@qti-components/utilities';\nimport { responseAttributeConverter } from '@qti-components/base';\n\nimport type { ComplexAttributeConverter } from 'lit';\nimport type { Interaction, ValidatableInteraction } from '@qti-components/base';\nimport type { ChoiceInterface } from '../active-element/active-element.mixin';\n\ntype Constructor<T = {}> = abstract new (...args: any[]) => T;\n\nexport type Choice = HTMLElement & ChoiceInterface & { internals: ElementInternals };\n\nexport interface ChoicesInterface extends ValidatableInteraction {\n minChoices: number;\n maxChoices: number;\n value: string | null;\n response: string | string[] | null;\n}\n\nexport const ChoicesMixin = <T extends Constructor<Interaction>>(superClass: T, selector: string) => {\n abstract class ChoicesMixinElement extends superClass implements ChoicesInterface {\n protected _choiceElements: Choice[] = [];\n\n #mutationObserver: MutationObserver | null = null;\n\n @query('#validation-message')\n protected _validationMessageElement!: HTMLElement;\n\n @property({ type: Number, attribute: 'min-choices' })\n public minChoices = 0;\n\n @property({ type: Number, attribute: 'max-choices' })\n public maxChoices = 1;\n\n /* removed waitUntilFirstUpdate to fix issues with stories and tests */\n @watch('maxChoices')\n protected _handleMaxChoicesChange(_oldValue: number, _newValue: number) {\n this._determineInputType();\n }\n\n @watch('disabled', { waitUntilFirstUpdate: true })\n protected _handleDisabledChange = (_: boolean, disabled: boolean) => {\n this._choiceElements.forEach(ch => (ch.disabled = disabled));\n };\n\n @watch('readonly', { waitUntilFirstUpdate: true })\n protected _handleReadonlyChange = (_: boolean, readonly: boolean) => {\n this._choiceElements.forEach(choice => (choice.readonly = readonly));\n };\n\n @property({\n attribute: 'response',\n reflect: false,\n converter: responseAttributeConverter({ emptyAs: '' }) as ComplexAttributeConverter<unknown, unknown>\n })\n response: string | string[] | null = '';\n\n @watch('response', { waitUntilFirstUpdate: true })\n protected _handleValueChange = () => {\n this._internals.setFormValue(this.value);\n this._updateChoiceSelection();\n };\n\n override get value(): string | null {\n if (Array.isArray(this.response) && this.response.length === 0) {\n return null;\n } else if (this.response === '') {\n return null;\n }\n return Array.isArray(this.response) ? this.response.join(',') : this.response;\n }\n\n override set value(val: string | null) {\n if (this.maxChoices > 1 && (typeof val === 'string' || val === null)) {\n this.response = !val ? [] : val.toString().split(',');\n } else {\n this.response = val || '';\n }\n }\n\n protected override firstUpdated() {\n super.firstUpdated();\n // The `response` watcher has waitUntilFirstUpdate:true, so an initial\n // value set via the `response` attribute never fires it — sync the\n // radios/checkboxes explicitly here.\n this._updateChoiceSelection();\n }\n\n override connectedCallback() {\n super.connectedCallback();\n this.addEventListener(`activate-${selector}`, this._choiceElementSelectedHandler);\n\n // Use MutationObserver to track choice elements (handles both direct children and nested descendants)\n this.#mutationObserver = new MutationObserver(() => this._syncChoicesFromDOM());\n this.#mutationObserver.observe(this, { childList: true, subtree: true });\n\n // Initial sync after DOM is ready\n this._syncChoicesFromDOM();\n }\n\n override disconnectedCallback() {\n super.disconnectedCallback();\n this.removeEventListener(`activate-${selector}`, this._choiceElementSelectedHandler);\n\n // Disconnect the observer\n if (this.#mutationObserver) {\n this.#mutationObserver.disconnect();\n this.#mutationObserver = null;\n }\n }\n\n /**\n * Synchronizes the internal choice elements list with the current DOM state.\n * Also filters the response to only include valid identifiers.\n */\n protected _syncChoicesFromDOM() {\n const previousChoices = new Set(this._choiceElements);\n this._choiceElements = Array.from(this.querySelectorAll(selector)) as Choice[];\n\n // Initialize new choice elements\n this._choiceElements.forEach(choiceElement => {\n if (!previousChoices.has(choiceElement)) {\n // New choice element - initialize it\n if (this.disabled) {\n choiceElement.disabled = true;\n }\n choiceElement.readonly = this.readonly;\n\n if (choiceElement.internals && !choiceElement.internals.ariaChecked) {\n choiceElement.internals.ariaChecked = 'false';\n }\n }\n });\n\n // Choices pull their own role from `interactionContext`; nothing to push here.\n this._determineInputType();\n\n // Filter response to only include valid identifiers (handles removal)\n const validIdentifiers = new Set(this._choiceElements.map(c => c.identifier));\n if (Array.isArray(this.response)) {\n const filteredResponse = this.response.filter(id => validIdentifiers.has(id));\n if (filteredResponse.length !== this.response.length) {\n this.response = filteredResponse;\n }\n } else if (this.response && !validIdentifiers.has(this.response)) {\n this.response = '';\n }\n\n // Update selection state to match response\n this._updateChoiceSelection();\n }\n\n public validate(): boolean {\n const selectedChoices = this._choiceElements.filter(choice => this._getChoiceChecked(choice));\n const selectedCount = selectedChoices.length;\n let isValid = true;\n let validityMessage = '';\n if (this.maxChoices !== 0 && selectedCount > this.maxChoices) {\n isValid = false;\n validityMessage =\n this.dataset.maxSelectionsMessage ||\n `Please select no more than ${this.maxChoices} ${this.maxChoices === 1 ? 'option' : 'options'}.`;\n } else if (selectedCount < this.minChoices) {\n isValid = false;\n validityMessage =\n this.dataset.minSelectionsMessage ||\n `Please select at least ${this.minChoices} ${this.minChoices === 1 ? 'option' : 'options'}.`;\n }\n\n // Always set validity state, regardless of whether there are selections.\n const anchor = this._choiceElements.find(c => this.contains(c)) || this;\n this.setInteractionValidity(isValid, validityMessage, anchor, { suppressInline: true });\n\n return isValid;\n }\n\n override reportValidity() {\n return super.reportValidity();\n }\n\n /**\n * Publish the role the choices should take. Each choice subscribes to\n * `interactionContext` and applies its own ARIA role and `:state(radio|checkbox)`.\n *\n * The interaction no longer reaches into its children to do this. That also removes the\n * upgrade-order hazard the old code worked around: a choice that had not yet upgraded had\n * no `internals`, so the push silently did nothing. A subscriber applies the role whenever\n * it is ready.\n */\n protected _determineInputType() {\n this._internals.role = this.maxChoices === 1 ? 'radiogroup' : null;\n const choiceRole = this.maxChoices === 1 ? 'radio' : 'checkbox';\n if (this._interactionContext.choiceRole !== choiceRole) {\n this._interactionContext = { ...this._interactionContext, choiceRole };\n }\n }\n\n protected _choiceElementSelectedHandler(event: CustomEvent<{ identifier: string }>) {\n this._toggleChoiceChecked(event.target as Choice);\n const shouldDisableAtMax = this.resolveDisableAfterMaxReached({ defaultWhenUnset: false });\n if (this.maxChoices === 1) {\n this._choiceElements.forEach(choice => {\n if (choice.identifier !== event.detail.identifier) {\n this._setChoiceChecked(choice, false);\n }\n });\n } else if (this.maxChoices !== 0 && shouldDisableAtMax) {\n const selectedChoices = this._choiceElements.filter(choice => this._getChoiceChecked(choice));\n if (selectedChoices.length >= this.maxChoices) {\n this._choiceElements.forEach(choice => {\n if (!this._getChoiceChecked(choice)) {\n choice.disabled = true;\n }\n });\n } else {\n this._choiceElements.forEach(choice => (choice.disabled = false));\n }\n }\n\n this._handleChoiceSelection();\n }\n\n protected _setChoiceChecked(choice: Choice, checked: boolean) {\n if (choice.internals?.states) {\n if (checked) {\n choice.internals.states.add('checked');\n choice.internals.ariaChecked = 'true';\n } else {\n choice.internals.states.delete('checked');\n choice.internals.ariaChecked = 'false';\n }\n }\n }\n\n protected _getChoiceChecked(choice: Choice): boolean {\n return choice.internals.states.has('checked');\n }\n\n protected _toggleChoiceChecked(choice: Choice) {\n const checked = this._getChoiceChecked(choice);\n this._setChoiceChecked(choice, !checked);\n }\n\n protected _handleChoiceSelection() {\n const selectedChoices = this._choiceElements.filter(choice => this._getChoiceChecked(choice));\n const selectedIdentifiers = selectedChoices.map(choice => choice.identifier);\n\n this.response = this.maxChoices === 1 ? selectedIdentifiers[0] || '' : selectedIdentifiers;\n\n this.validate();\n\n // Always update the configured validity UI mode after user-driven selection changes.\n // This ensures inline messages are cleared immediately when state becomes valid again.\n this.reportValidity();\n\n this.saveResponse(this.response);\n }\n\n /**\n * Updates the selection state of each choice element based on the current response.\n */\n protected _updateChoiceSelection() {\n const responseArray = Array.isArray(this.response) ? this.response : [this.response];\n this._choiceElements.forEach(choice => {\n const isSelected = responseArray.includes(choice.identifier);\n this._setChoiceChecked(choice, isSelected);\n });\n }\n }\n return ChoicesMixinElement as Constructor<ChoicesInterface> & T;\n};\n","import { property } from 'lit/decorators.js';\n\nimport type { QtiSimpleChoice } from '../../elements/qti-simple-choice';\nimport type { LitElement, PropertyValues } from 'lit';\n\ntype Constructor<T = {}> = abstract new (...args: any[]) => T;\n\ntype LabelType = 'qti-labels-none' | 'qti-labels-decimal' | 'qti-labels-lower-alpha' | 'qti-labels-upper-alpha';\ntype LabelSuffixType = 'qti-labels-suffix-none' | 'qti-labels-suffix-period' | 'qti-labels-suffix-parenthesis';\n\ndeclare class VocabularyInterface {}\n\nexport const VocabularyMixin = <T extends Constructor<LitElement>>(superClass: T, _selector: string) => {\n abstract class VocabularyElement extends superClass {\n #classes: string[] = [];\n #allLabels: LabelType[] = [\n 'qti-labels-none',\n 'qti-labels-decimal',\n 'qti-labels-lower-alpha',\n 'qti-labels-upper-alpha'\n ];\n #allLabelSuffixes: LabelSuffixType[] = [\n 'qti-labels-suffix-none',\n 'qti-labels-suffix-period',\n 'qti-labels-suffix-parenthesis'\n ];\n #mutationObserver: MutationObserver | null = null;\n\n @property({\n type: String,\n attribute: 'class'\n })\n set class(value: string) {\n this.#classes = this.#tokenizeClasses(value);\n this.#syncLabels();\n }\n\n get class(): string {\n return this.#classes.join(' ');\n }\n\n override attributeChangedCallback(name: string, oldValue: string | null, newValue: string | null): void {\n super.attributeChangedCallback(name, oldValue, newValue);\n\n if (name === 'class' && oldValue !== newValue) {\n this.class = newValue ?? '';\n }\n }\n\n protected override updated(_changedProperties: PropertyValues): void {\n super.updated(_changedProperties);\n this.#syncLabels();\n }\n\n override connectedCallback(): void {\n super.connectedCallback();\n this.class = this.getAttribute('class') ?? '';\n this.#mutationObserver = new MutationObserver(mutations => {\n if (\n mutations.some(\n mutation =>\n mutation.type === 'childList' || (mutation.type === 'attributes' && mutation.attributeName === 'style')\n )\n ) {\n this.#syncLabels();\n }\n });\n this.#mutationObserver.observe(this, {\n childList: true,\n subtree: true,\n attributes: true,\n attributeFilter: ['style']\n });\n }\n\n override disconnectedCallback(): void {\n super.disconnectedCallback();\n this.#mutationObserver?.disconnect();\n this.#mutationObserver = null;\n }\n\n #tokenizeClasses(value: string | null | undefined): string[] {\n if (!value) return [];\n\n return value\n .split(/\\s+/)\n .map(token => token.trim())\n .filter(Boolean)\n .filter((token, index, tokens) => tokens.indexOf(token) === index);\n }\n\n #syncLabels() {\n const choiceElements = Array.from(this.querySelectorAll('qti-simple-choice')).map(c => c as QtiSimpleChoice);\n const choices = this.#getOrderedChoices(choiceElements);\n const labelType = this.#getActiveLabelType();\n const labelSuffixType = this.#getActiveLabelSuffixType();\n\n choices.forEach((choice, index) => {\n choice.marker = this.#getLabel(index + 1, labelType, labelSuffixType);\n });\n }\n\n #getOrderedChoices(choiceElements: QtiSimpleChoice[]): QtiSimpleChoice[] {\n return choiceElements\n .map((choice, index) => {\n const order = Number(choice.style.order);\n return { el: choice, order: Number.isFinite(order) ? order : index + 1, index };\n })\n .sort((a, b) => a.order - b.order || a.index - b.index)\n .map(choice => choice.el);\n }\n\n #getActiveLabelType(): LabelType | null {\n return (\n (this.#classes.filter(c => this.#allLabels.includes(c as LabelType)).pop() as LabelType | undefined) ?? null\n );\n }\n\n #getActiveLabelSuffixType(): LabelSuffixType | null {\n return (\n (this.#classes.filter(c => this.#allLabelSuffixes.includes(c as LabelSuffixType)).pop() as\n | LabelSuffixType\n | undefined) ?? null\n );\n }\n\n #getLabel(index: number, labelType: LabelType | null, labelSuffixType: LabelSuffixType | null): string {\n let effectiveLabelType = labelType;\n\n if (!effectiveLabelType && labelSuffixType && labelSuffixType !== 'qti-labels-suffix-none') {\n effectiveLabelType = 'qti-labels-upper-alpha';\n }\n\n if (!effectiveLabelType || effectiveLabelType === 'qti-labels-none') {\n return '';\n }\n\n let label = '';\n switch (effectiveLabelType) {\n case 'qti-labels-decimal':\n label = `${index}`;\n break;\n case 'qti-labels-lower-alpha':\n label = this.#toAlphabetic(index, 'lower');\n break;\n case 'qti-labels-upper-alpha':\n label = this.#toAlphabetic(index, 'upper');\n break;\n }\n\n if (labelSuffixType === 'qti-labels-suffix-period') {\n return `${label}.`;\n }\n\n if (labelSuffixType === 'qti-labels-suffix-parenthesis') {\n return `${label})`;\n }\n\n return label;\n }\n\n #toAlphabetic(index: number, casing: 'lower' | 'upper'): string {\n let value = index;\n let label = '';\n const charCodeBase = casing === 'lower' ? 97 : 65;\n\n while (value > 0) {\n value -= 1;\n label = String.fromCharCode(charCodeBase + (value % 26)) + label;\n value = Math.floor(value / 26);\n }\n\n return label;\n }\n }\n return VocabularyElement as Constructor<VocabularyInterface> & T;\n};\n","import { css } from 'lit';\n\nimport { boxSizing, validationMessage } from '@qti-components/base';\n\nexport default [\n boxSizing,\n validationMessage,\n css`\n :host {\n display: block;\n }\n\n [part='slot'] {\n display: grid;\n gap: 10px;\n }\n\n /* Define the number of columns dynamically */\n :host([class*='qti-choices-stacking-']) [part='slot'] {\n grid-template-columns: repeat(var(--stacking-count, 1), 1fr);\n }\n\n /* Apply dynamic stacking count based on class */\n :host(.qti-choices-stacking-1) {\n --stacking-count: 1;\n }\n :host(.qti-choices-stacking-2) {\n --stacking-count: 2;\n }\n :host(.qti-choices-stacking-3) {\n --stacking-count: 3;\n }\n :host(.qti-choices-stacking-4) {\n --stacking-count: 4;\n }\n :host(.qti-choices-stacking-5) {\n --stacking-count: 5;\n }\n\n /* Default slot item layout */\n ::slotted(qti-simple-choice) {\n display: flex;\n align-items: center;\n white-space: normal;\n }\n\n /* Orientation styles */\n :host(.qti-orientation-horizontal) [part='slot'] {\n grid-auto-flow: dense column;\n grid-auto-columns: 1fr;\n }\n\n :host(.qti-orientation-vertical) [part='slot'] {\n grid-auto-flow: row;\n }\n\n /* Vertical and horizontal stacking logic */\n :host(.qti-orientation-vertical[class*='qti-choices-stacking-']) [part='slot'] {\n grid-auto-flow: dense column;\n grid-auto-columns: 1fr;\n grid-template-columns: repeat(var(--stacking-count), 1fr);\n grid-template-rows: repeat(calc(var(--item-count) / var(--stacking-count)), 1fr);\n }\n\n :host(.qti-orientation-horizontal[class*='qti-choices-stacking-']) [part='slot'] {\n grid-auto-flow: row;\n grid-template-columns: repeat(var(--stacking-count), 1fr);\n grid-template-rows: unset;\n }\n\n /* Ensure even distribution in vertical mode */\n :host(.qti-orientation-vertical) ::slotted(qti-simple-choice:nth-child(even)) {\n grid-row: auto;\n }\n `\n];\n","import { html } from 'lit';\nimport { property } from 'lit/decorators.js';\n\nimport { Interaction } from '@qti-components/base';\nimport { ChoicesMixin } from '@qti-components/interactions-core/mixins/choices/choices.mixin';\nimport { VocabularyMixin } from '@qti-components/interactions-core/mixins/vocabulary/vocabulary-mixin';\n\nimport styles from './qti-choice-interaction.styles';\n\nimport type { ChoicesInterface } from '@qti-components/interactions-core/mixins/choices/choices.mixin';\nimport type { CSSResultGroup } from 'lit';\n\nexport type Orientation = 'horizontal' | 'vertical' | undefined;\n\n/**\n * A single-response or multiple-response choice interaction.\n *\n * @customElement qti-choice-interaction\n *\n * @attr {string} response-identifier - Required. Identifier of the bound response variable.\n * @attr {number} [max-choices=1] - Maximum selectable choices. `1` is a single-response\n * item; `0` means unlimited and makes it a multiple-response item.\n * @attr {number} [min-choices=0] - Minimum selectable choices for a valid response.\n * @attr {'horizontal'|'vertical'} [orientation=vertical] - Deprecated by QTI in favour of\n * the `qti-orientation-*` class vocabulary.\n * @attr {boolean} [shuffle=false] - Requests choice shuffling. Applied by the transform\n * pipeline (`qti-transformers`), not by this element.\n * @attr {'qti-orientation-horizontal'|'qti-orientation-vertical'|'qti-choices-stacking-1'|'qti-choices-stacking-2'|'qti-choices-stacking-3'|'qti-choices-stacking-4'|'qti-choices-stacking-5'|'qti-labels-none'|'qti-labels-decimal'|'qti-labels-lower-alpha'|'qti-labels-upper-alpha'|'qti-labels-suffix-none'|'qti-labels-suffix-period'|'qti-labels-suffix-parenthesis'|'qti-input-control-hidden'} class - QTI shared presentation vocabulary. Space-separated; takes precedence over `orientation`.\n *\n * @slot prompt - The prompt shown above the choices.\n * @slot - Default slot for `qti-simple-choice` elements.\n *\n * @csspart prompt - Wrapper around the prompt slot.\n * @csspart slot - Wrapper around the default slot containing the choices.\n * @csspart message - Live validation message region (role=\"alert\").\n */\nexport class QtiChoiceInteraction\n extends VocabularyMixin(ChoicesMixin(Interaction, 'qti-simple-choice'), 'qti-simple-choice')\n implements ChoicesInterface\n{\n static override styles: CSSResultGroup = styles;\n\n /** @deprecated, use 'qti-orientation-horizontal' or 'qti-orientation-vertical' instead */\n @property({ type: String })\n public orientation: Orientation = 'vertical';\n\n #handleSlotChange() {\n // count the number of choices, set a css variable for the number of choices\n const choices = this.querySelectorAll('qti-simple-choice');\n this.style.setProperty('--item-count', choices.length.toString());\n }\n\n override render() {\n return html`\n <slot part=\"prompt\" name=\"prompt\"></slot>\n <slot part=\"slot\" @slotchange=${this.#handleSlotChange}></slot>\n <div part=\"message\" role=\"alert\" id=\"validation-message\"></div>\n `;\n }\n}\n\ndeclare global {\n interface HTMLElementTagNameMap {\n 'qti-choice-interaction': QtiChoiceInteraction;\n }\n}\n","import { css } from 'lit';\n\nimport { boxSizing } from '@qti-components/base';\n\nexport default [\n boxSizing,\n css`\n /* PK: display host as block, else design will be collapsed */\n /* 'position: relative' anchors the correction glyph the theme draws over the textarea. */\n :host {\n display: block;\n position: relative;\n }\n textarea {\n box-sizing: border-box;\n width: 100%;\n height: 100%;\n border: 0;\n }\n `\n];\n","import { html } from 'lit';\nimport { ifDefined } from 'lit/directives/if-defined.js';\nimport { property, state } from 'lit/decorators.js';\n\nimport { watch } from '@qti-components/utilities';\nimport { Interaction } from '@qti-components/base';\n\nimport styles from './qti-extended-text-interaction.styles';\n\nimport type { CSSResultGroup } from 'lit';\n/** Rows rendered when neither the class vocabulary nor either length hint resolves. */\nconst DEFAULT_ROWS = 5;\n\n/** Rough characters-per-row rate used to turn `expected-length` into a row count. */\nconst CHARS_PER_ROW = 50;\n\n/** QTI shared presentation vocabulary prefix carrying an explicit row count. */\nconst HEIGHT_LINES_PREFIX = 'qti-height-lines-';\n\n/**\n * Warn once per page rather than once per element: an item bank rendering many essays would\n * otherwise bury the console in the same message.\n */\nlet warnedAboutXhtml = false;\n\n/**\n * A multi-line text-entry interaction.\n *\n * @customElement qti-extended-text-interaction\n *\n * @attr {string} response-identifier - Required. Identifier of the bound response variable.\n * @attr {number} expected-length - Hint at the expected answer length in characters; sets the\n * textarea's `maxlength`. Also the last-resort row count, used only when neither a\n * `qti-height-lines-*` class nor `expected-lines` is present.\n * @attr {string} pattern-mask - Regular expression the value must match to be valid.\n * @attr {string} placeholder-text - Placeholder shown while the textarea is empty.\n * @attr {string} data-patternmask-message - Custom validation message shown when\n * `pattern-mask` fails. Part of the QTI shared interaction vocabulary.\n * @attr {'qti-height-lines-3'|'qti-height-lines-6'|'qti-height-lines-15'} class - QTI shared\n * presentation vocabulary controlling the rendered height. Outranks both `expected-lines`\n * and `expected-length`.\n * @attr {number} expected-lines - Expected number of lines of response, and the rendered row\n * count unless a `qti-height-lines-*` class is present.\n * @attr {number} [base=10] - Not implemented. Numeric base used when recording the value.\n * @attr {string} string-identifier - Not implemented. Identifier of a second, string-typed\n * response variable that also receives the raw entry.\n * @attr {number} max-strings - Not implemented. Maximum number of separate string responses. QTI\n * defines these for a multi-string response — several bound variables, one field each. This\n * element renders a single textarea bound to one variable, so there is nothing for the bounds\n * to count: reading them as a word or paragraph limit would invent a rule QTI does not state.\n * Implement alongside multi-string rendering, not before it.\n * @attr {number} min-strings - Not implemented. See `max-strings`.\n * @attr {'plain'|'preformatted'|'xhtml'} [format=plain] - How the response is presented.\n * `preformatted` renders the field monospaced; `xhtml` is accepted but downgraded to plain,\n * because the field is a textarea with no rich-text editor behind it.\n *\n * @slot prompt - The prompt shown above the textarea.\n *\n * @csspart textarea - The textarea input element.\n */\nexport class QtiExtendedTextInteraction extends Interaction {\n static override styles: CSSResultGroup = styles;\n\n @state()\n protected _rows = DEFAULT_ROWS;\n\n /** expected length is mapped to the property maxlength on the textarea */\n @property({ type: Number, attribute: 'expected-length' }) expectedLength: number;\n\n /** QTI's own hint at the response height. Outranked by `qti-height-lines-*`; see `#resolveRows`. */\n @property({ type: Number, attribute: 'expected-lines' }) expectedLines: number;\n\n /**\n * How the response text is presented. Reflected so themes can key off\n * `:host([format='preformatted'])`.\n *\n * `xhtml` is accepted and recorded but renders as `plain`: the field is a `<textarea>`, and\n * there is no rich-text editor behind it. Downgrading loudly beats either refusing valid QTI\n * or pretending to support formatting the candidate cannot actually produce.\n */\n /*\n * The vocabulary is written inline rather than as an exported `TextFormat` alias. Both text\n * interactions need it in their public API, and the umbrella `@qti-components/interactions`\n * re-exports both packages — two identically-named exported aliases collide at that barrel\n * (TS2308). Inline, there is no name to collide, and the manifest still reads the union.\n */\n @property({ type: String, reflect: true }) format: 'plain' | 'preformatted' | 'xhtml' = 'plain';\n\n @watch('format')\n protected _handleFormatChange = () => {\n if (this.format !== 'xhtml' || warnedAboutXhtml) return;\n\n warnedAboutXhtml = true;\n console.warn(\n '<qti-extended-text-interaction format=\"xhtml\"> renders as plain text. ' +\n 'The interaction has no rich-text editor; the recorded response will contain no markup.'\n );\n };\n\n @property({ type: String, attribute: 'pattern-mask' }) patternMask: string;\n\n /** text appearing in the extended-text-interaction if it is empty */\n @property({ type: String, attribute: 'placeholder-text' }) placeholderText: string;\n\n @property({ type: String, attribute: 'data-patternmask-message' }) dataPatternmaskMessage: string;\n\n @property({ type: String, attribute: 'class' }) classNames: string;\n\n /*\n * All three inputs feed one resolver rather than each assigning `_rows` in its own handler.\n * With separate handlers the last attribute to change would win, so the same markup could\n * render a different height depending on attribute order — and `expected-length` only ever\n * applied when a `class` was also present, because the fallback lived inside the class watcher.\n */\n @watch(['classNames', 'expectedLines', 'expectedLength'])\n protected _handleRowsInputChange() {\n this._rows = this.#resolveRows();\n }\n\n /**\n * Row count, highest precedence first:\n *\n * 1. `qti-height-lines-N` — the QTI shared presentation vocabulary. An explicit rendering\n * instruction, so it outranks the content-level hints below.\n * 2. `expected-lines` — QTI's hint at how long the response should be.\n * 3. `expected-length` — a character count, converted at a rough characters-per-row rate.\n * 4. {@link DEFAULT_ROWS}.\n */\n #resolveRows(): number {\n const fromHeightLines = this.#rowsFromHeightLinesClass();\n if (fromHeightLines !== null) return fromHeightLines;\n\n if (this.expectedLines > 0) return this.expectedLines;\n if (this.expectedLength > 0) return Math.ceil(this.expectedLength / CHARS_PER_ROW);\n\n return DEFAULT_ROWS;\n }\n\n /** The `N` of the first usable `qti-height-lines-N` class, or null when none is present. */\n #rowsFromHeightLinesClass(): number | null {\n for (const className of (this.classNames ?? '').split(' ')) {\n if (!className.startsWith(HEIGHT_LINES_PREFIX)) continue;\n\n const rows = parseInt(className.slice(HEIGHT_LINES_PREFIX.length), 10);\n // A bare `qti-height-lines-` parses to NaN; ignore it rather than render NaN rows.\n if (!Number.isNaN(rows) && rows > 0) return rows;\n }\n\n return null;\n }\n\n /*\n * Declared with `attribute: 'response'`, not `@state`, so `response=\"…\"` in markup reaches the\n * field. As a `@state` it was unobserved: every sibling interaction accepts the attribute — it\n * is half of the codec's contract in packages/qti-base/src/lib/response.ts, which parses\n * `response` and `correct-response` alike — but this one silently ignored it, so authored or\n * restored prose rendered as an empty textarea.\n *\n * Plain `type: String`, deliberately NOT `responseAttributeConverter`. That codec splits on\n * commas to build multi-value responses, which is right for identifiers, pairs and points and\n * wrong for prose: an essay containing a comma would arrive as an array. text-entry, the other\n * single-string interaction, declares it plainly for the same reason.\n */\n @property({ type: String, attribute: 'response', reflect: false })\n response: string | null = null;\n\n @watch('response', { waitUntilFirstUpdate: true })\n protected _handleResponseChange = () => {\n this._internals.setFormValue(this.value);\n this.validate();\n };\n\n override get value(): string | null {\n return this.response || null;\n }\n override set value(val: string | null) {\n this.response = val || null;\n }\n\n public override validate() {\n const textarea = this.shadowRoot.querySelector('textarea');\n if (!textarea) return false;\n let validityMessage = '';\n let isValid = false;\n\n if (this.patternMask && this.dataPatternmaskMessage) {\n // Clear any custom error initially\n textarea.setCustomValidity('');\n const patternSource =\n this.patternMask.startsWith('^') && this.patternMask.endsWith('$') ? this.patternMask : `^${this.patternMask}$`;\n\n const pattern = new RegExp(patternSource);\n isValid = textarea.checkValidity() && pattern.test(textarea.value);\n\n if (!isValid) {\n // Set custom error if invalid\n validityMessage = this.dataPatternmaskMessage;\n textarea.setCustomValidity(this.dataPatternmaskMessage);\n }\n } else {\n isValid = textarea.checkValidity();\n }\n\n if (isValid && !this.response) {\n isValid = false;\n }\n\n if (!isValid && !validityMessage) {\n validityMessage = textarea.validationMessage || 'Invalid value.';\n }\n\n this.setInteractionValidity(isValid, validityMessage, textarea, { suppressInline: true });\n return isValid;\n }\n\n override reportValidity() {\n this.validate();\n return super.reportValidity();\n }\n\n /*\n * The template in named pieces, so a subclass can recompose it.\n *\n * Each piece renders one thing and returns it; `render()` below just orders them. A subclass\n * overrides `render()` and calls the pieces where it wants them — which is the point: an extension\n * point that only lets you APPEND has already decided the layout on the subclass's behalf, and the\n * subclass is usually the one that knows better. The correction variant in\n * @qti-components/corrections puts its badge between the field and the validation message;\n * something else may want it above the prompt, or may want to drop a piece entirely.\n *\n * Override a piece to change what one part looks like; override `render()` to change the order.\n */\n\n /** The prompt, above the field. */\n protected renderPrompt(): unknown {\n return html`<slot name=\"prompt\"></slot>`;\n }\n\n /** The field itself. */\n protected renderTextarea(): unknown {\n return html`<textarea\n part=\"textarea\"\n name=\"${this.responseIdentifier}\"\n spellcheck=\"false\"\n autocomplete=\"off\"\n maxlength=\"${5000}\"\n @keydown=\"${(event: KeyboardEvent) => event.stopImmediatePropagation()}\"\n @keyup=\"${this.textChanged}\"\n @change=\"${this.textChanged}\"\n @blur=\"${(_: FocusEvent) => {\n this.reportValidity();\n }}\"\n placeholder=\"${ifDefined(this.placeholderText ? this.placeholderText : undefined)}\"\n rows=\"${this._rows}\"\n ?disabled=\"${this.disabled}\"\n ?readonly=\"${this.readonly}\"\n .value=${this.response}\n ></textarea>`;\n }\n\n /** Hidden until `Interaction.reportValidity` shows it. */\n protected renderValidationMessage(): unknown {\n return html`<div id=\"validation-message\" part=\"message\" role=\"alert\" style=\"display:none;\"></div>`;\n }\n\n override render() {\n /* The prompt and the field are written with NO whitespace between them, deliberately: a text\n node there puts a line box between the two. The original template said `</slot\\n><textarea`\n to avoid exactly that, and interpolating them adjacently keeps it. */\n return html`${this.renderPrompt()}${this.renderTextarea()} ${this.renderValidationMessage()}`;\n }\n\n protected textChanged(event: Event) {\n if (this.disabled || this.readonly) return;\n const input = event.target as HTMLInputElement;\n if (this.response !== input.value) {\n this.value = input.value;\n this.saveResponse(input.value);\n }\n }\n}\n\ndeclare global {\n interface HTMLElementTagNameMap {\n 'qti-extended-text-interaction': QtiExtendedTextInteraction;\n }\n}\n","import { css } from 'lit';\n\nimport { boxSizing, validationMessage } from '@qti-components/base';\n// import componentStyles from '../../utilities/styles/component.styles';\n// :host {\n// display: inline-block;\n// position: relative;\n// }\n/* ${componentStyles} */\nexport default [\n boxSizing,\n validationMessage,\n css`\n :host {\n display: flex;\n align-items: flex-start;\n flex-direction: column;\n flex-wrap: wrap;\n gap: 0.5rem;\n }\n\n :host(.qti-choices-top) {\n flex-direction: column;\n }\n :host(.qti-choices-bottom) {\n flex-direction: column-reverse;\n }\n :host(.qti-choices-left) {\n flex-direction: row;\n }\n :host(.qti-choices-right) {\n flex-direction: row-reverse;\n }\n /* [part='drops'] , */\n [name='prompt'] {\n width: 100%;\n }\n /* Wraps, for the reason spelled out on associate's identical bank: nowrap does not overflow, it\n shrinks, and a squeezed chip is worse than a second line. */\n [name='drags'] {\n display: flex;\n flex-wrap: wrap;\n align-items: flex-start;\n flex: 1;\n border: 2px solid transparent;\n padding: 0.3rem;\n border-radius: 0.3rem;\n gap: 0.5rem;\n }\n\n /* An answer key shows the answer, not the bank you would have dragged it from. The attribute is\n set on the clone by the correct-response mixin; the theme used to do this with a\n '.full-correct-response' descendant selector, from the document. */\n :host([answer-key]) [part~='drags'] {\n display: none;\n }\n `\n];\n","import { html } from 'lit';\n\nimport { Interaction } from '@qti-components/base';\nimport {\n DragDropSlottedMixin,\n DragDropSlottedSortableMixin\n} from '@qti-components/interactions-core/mixins/drag-drop-observables';\n\n// import { DragDropInteractionMixin } from '@qti-components/interactions-core/mixins/drag-drop/drag-drop-interaction-mixin.js';\nimport styles from './qti-gap-match-interaction.styles.js';\n\nimport type { CSSResultGroup } from 'lit';\n/**\n * Drag-and-drop gap-match interaction: candidates drag choices into gap targets.\n *\n * @customElement qti-gap-match-interaction\n *\n * @attr {string} response-identifier - Required. Identifier of the bound response variable.\n * @attr {number} [max-associations=1] - Maximum gaps that may be filled across the whole\n * interaction; `0` means unlimited.\n * @attr {number} [min-associations=1] - Minimum filled gaps for a valid response.\n * @attr {boolean} [shuffle=false] - Requests shuffling of the `qti-gap-text` sources. Applied\n * by the transform pipeline (`qti-transformers`), not by this element.\n * @attr {'qti-choices-top'|'qti-choices-bottom'|'qti-choices-left'|'qti-choices-right'} class -\n * QTI shared presentation vocabulary positioning the gap-choices container.\n * @attr {boolean} [auto-size-dropzones=true] - Extension, not QTI. Sizes every gap to the\n * widest chip so placement does not reflow the prose. On by default: a gap is a slot, and a slot\n * that is already the size of the chip it will hold does not resize when one lands in it.\n * @attr {boolean} [disable-animations=false] - Extension, not QTI. Disables the FLIP move\n * animation.\n *\n * @slot prompt - The prompt shown above the interaction.\n * @slot drags - The draggable choice sources.\n * @slot - Default slot for the drop targets (gaps).\n *\n * @csspart drags - Wrapper around the drag sources slot.\n * @csspart drops - Wrapper around the drop targets slot.\n * @csspart message - Live validation message region (role=\"alert\").\n */\nexport class QtiGapMatchInteraction extends DragDropSlottedSortableMixin(\n DragDropSlottedMixin(Interaction, 'qti-gap-text', 'qti-gap', `slot[part~='drags']`),\n '[qti-draggable=\"true\"]'\n) {\n static override styles: CSSResultGroup = styles;\n\n override render() {\n return html`<slot name=\"prompt\"> </slot>\n <slot part=\"drags\" name=\"drags\"></slot>\n <slot part=\"drops\"></slot>\n <div role=\"alert\" part=\"message\" id=\"validation-message\"></div>`;\n }\n}\n\ndeclare global {\n interface HTMLElementTagNameMap {\n 'qti-gap-match-interaction': QtiGapMatchInteraction;\n }\n}\n","export function positionShapes(shape: string, coordsNumber: number[], img: HTMLImageElement, hotspot: HTMLElement) {\n // Determine the reference width and height based on the attributes or natural dimensions\n const imgWidth = img.getAttribute('width') ? parseFloat(img.getAttribute('width')!) : img.naturalWidth;\n const imgHeight = img.getAttribute('height') ? parseFloat(img.getAttribute('height')!) : img.naturalHeight;\n\n switch (shape) {\n case 'circle':\n {\n if (coordsNumber.length !== 3) {\n console.error('Invalid circle coordinates:', coordsNumber);\n return;\n }\n const [centerX, centerY, radius] = coordsNumber;\n\n // Calculate percentages for center and radius\n const centerXPer = (centerX / imgWidth) * 100;\n const centerYPer = (centerY / imgHeight) * 100;\n const radiusXPer = (radius / imgWidth) * 100; // Relative to width\n const radiusYPer = (radius / imgHeight) * 100; // Relative to height\n\n // Position the hotspot so its center aligns with the circle center\n hotspot.style.left = centerXPer - radiusXPer + '%';\n hotspot.style.top = centerYPer - radiusYPer + '%';\n hotspot.style.width = 2 * radiusXPer + '%';\n hotspot.style.height = 2 * radiusYPer + '%';\n hotspot.style.borderRadius = `50%`; // Create a circular shape\n }\n break;\n\n case 'rect':\n {\n if (coordsNumber.length !== 4) {\n console.error('Invalid rectangle coordinates:', coordsNumber);\n return;\n }\n const [leftX, topY, rightX, bottomY] = coordsNumber;\n const leftXPer = (leftX / imgWidth) * 100;\n const topYPer = (topY / imgHeight) * 100;\n const rightXPer = (rightX / imgWidth) * 100;\n const bottomYPer = (bottomY / imgHeight) * 100;\n hotspot.style.left = leftXPer + '%';\n hotspot.style.top = topYPer + '%';\n hotspot.style.width = rightXPer - leftXPer + '%';\n hotspot.style.height = bottomYPer - topYPer + '%';\n }\n break;\n case 'ellipse':\n {\n if (coordsNumber.length !== 4) {\n console.error('Invalid ellipse coordinates:', coordsNumber);\n return;\n }\n const [centerX, centerY, radiusX, radiusY] = coordsNumber;\n\n // Calculate center position as percentages\n const centerXPer = (centerX / imgWidth) * 100;\n const centerYPer = (centerY / imgHeight) * 100;\n\n // Calculate radii as percentages (relative to their respective dimensions)\n const radiusXPer = (radiusX / imgWidth) * 100;\n const radiusYPer = (radiusY / imgHeight) * 100;\n\n // Position the hotspot so its center aligns with the ellipse center\n hotspot.style.left = centerXPer - radiusXPer + '%';\n hotspot.style.top = centerYPer - radiusYPer + '%';\n hotspot.style.width = 2 * radiusXPer + '%';\n hotspot.style.height = 2 * radiusYPer + '%';\n hotspot.style.borderRadius = `50%`; // Create an elliptical shape\n }\n break;\n case 'poly':\n {\n if (coordsNumber.length < 6 || coordsNumber.length % 2 !== 0) {\n console.error('Invalid polygon coordinates:', coordsNumber);\n return;\n }\n // Convert coordsNumber to an array of {x, y}\n const polycoords = [];\n for (let i = 0; i < coordsNumber.length; i += 2) {\n polycoords.push({ x: coordsNumber[i], y: coordsNumber[i + 1] });\n }\n\n // Calculate the bounding box\n const leftX = Math.min(...polycoords.map(point => point.x));\n const rightX = Math.max(...polycoords.map(point => point.x));\n const topY = Math.min(...polycoords.map(point => point.y));\n const bottomY = Math.max(...polycoords.map(point => point.y));\n\n // Set the hotspot position and size in percentages\n const leftXPer = (leftX / imgWidth) * 100;\n const topYPer = (topY / imgHeight) * 100;\n const rightXPer = (rightX / imgWidth) * 100;\n const bottomYPer = (bottomY / imgHeight) * 100;\n\n hotspot.style.left = leftXPer + '%';\n hotspot.style.top = topYPer + '%';\n hotspot.style.width = rightXPer - leftXPer + '%';\n hotspot.style.height = bottomYPer - topYPer + '%';\n\n // Calculate the clip path based on the bounding box\n const polygonData = polycoords.map(point => ({\n x: ((point.x - leftX) / (rightX - leftX)) * 100,\n y: ((point.y - topY) / (bottomY - topY)) * 100\n }));\n\n const polyD = polygonData.map(p => `${p.x}% ${p.y}%`).join(',');\n hotspot.style.clipPath = `polygon(${polyD})`;\n\n /*\n * Publish the polygon outline as SVG-stroke masks, so a theme can draw a ring round a poly\n * hotspot the way it draws a border round a circle. A `clip-path` box has no border-box\n * edge for a CSS `border` to paint on, so this is the only way to outline a polygon.\n *\n * Geometry only — the mask carries the shape, the theme's `background-color` carries the\n * colour, so selection/light-dark/correction theming all stay in CSS (see\n * qti-hotspot-interaction.css). Two widths, so a theme can swap thin↔bold between resting\n * and selected without JS.\n *\n * `viewBox 0 0 100 100` + `preserveAspectRatio=none` stretches to the element; the points\n * are the same percentages as the clip-path. `vector-effect=non-scaling-stroke` keeps the\n * stroke a uniform screen width through any (even non-uniform) resize — verified.\n *\n * The theme keeps clip-path ON for hit-testing and layers the mask over it, so the stroke's\n * outer half is clipped and a clean inner-edge ring remains — matching the inner edge a\n * border-box border draws on the box shapes. Hence the widths here are doubled: the visible\n * (inner) half is ~2px / ~4px.\n */\n const svgPoints = polygonData.map(p => `${p.x},${p.y}`).join(' ');\n const outline = (strokeWidth: number): string =>\n `url(\"data:image/svg+xml,${encodeURIComponent(\n `<svg xmlns='http://www.w3.org/2000/svg' viewBox='0 0 100 100' preserveAspectRatio='none'>` +\n `<polygon points='${svgPoints}' fill='none' stroke='black' stroke-width='${strokeWidth}' ` +\n `vector-effect='non-scaling-stroke' stroke-linejoin='round'/></svg>`\n )}\")`;\n hotspot.style.setProperty('--qti-shape-outline', outline(4));\n hotspot.style.setProperty('--qti-shape-outline-bold', outline(8));\n }\n break;\n\n default:\n console.error(`Unsupported shape: ${shape}`);\n break;\n }\n}\n","import { css } from 'lit';\n\nimport { boxSizing, validationMessage } from '@qti-components/base';\n\nexport default [\n boxSizing,\n validationMessage,\n css`\n /* Containing block for the absolutely positioned hotspots over the image. Was on this host in\n the theme, together with a 'display: block' this component now owns. */\n :host {\n display: block;\n position: relative;\n }\n\n slot:not([name='prompt']) {\n display: block;\n width: fit-content; /* hotspots not stretching further if image is at max size */\n }\n ::slotted(img) {\n /* image not selectable anymore */\n pointer-events: none;\n user-select: none;\n }\n ::slotted(qti-associable-hotspot) {\n transform: translate(-50%, -50%);\n }\n line-container {\n display: block;\n position: relative;\n width: fit-content;\n }\n svg {\n position: absolute;\n top: 0px;\n left: 0px;\n }\n `\n];\n","import { html, nothing, svg } from 'lit';\nimport { property, queryAssignedElements, state } from 'lit/decorators.js';\nimport { ifDefined } from 'lit/directives/if-defined.js';\nimport { repeat } from 'lit/directives/repeat.js';\n\nimport { Interaction, responseAttributeConverter } from '@qti-components/base';\nimport { positionShapes } from '@qti-components/interactions-core/internal/hotspots/hotspot';\n\nimport styles from './qti-graphic-associate-interaction.styles';\n\nimport type { QtiAssociableHotspot } from '@qti-components/interactions-core/elements/qti-associable-hotspot';\nimport type { QtiHotspotChoice } from '@qti-components/interactions-core/elements/qti-hotspot-choice';\nimport type { CSSResultGroup } from 'lit';\n/**\n * Graphic associate interaction: candidates connect points/hotspots on an image with lines.\n *\n * @slot prompt - The prompt shown above the image.\n * @slot - Default slot for hotspot choices layered over the image.\n *\n * @csspart line - Each line drawn by the candidate.\n * @csspart correct-line - Each line displayed as part of the correct response.\n * @csspart point - Each in-progress endpoint indicator.\n * @csspart message - Live validation message region (role=\"alert\").\n */\nexport class QtiGraphicAssociateInteraction extends Interaction {\n static override styles: CSSResultGroup = styles;\n\n #hotspots: any[] | NodeListOf<QtiAssociableHotspot>;\n #startPoint: HTMLElement | null = null;\n #endPoint: HTMLElement | null = null;\n\n @state() private startCoord: { x: number; y: number };\n @state() private mouseCoord: { x: number; y: number };\n @queryAssignedElements({ selector: 'img' }) grImage: any[];\n\n @state()\n private _response: string[] | null = [];\n\n constructor() {\n super();\n this.addEventListener('qti-register-hotspot', this.#positionHotspotOnRegister);\n }\n\n override reset(): void {\n this._response = [];\n }\n\n validate(): boolean {\n return this.#getResponseArray().length > 0;\n }\n\n @property({\n attribute: 'response',\n reflect: false,\n noAccessor: true,\n converter: responseAttributeConverter({ emptyAs: [] })\n })\n set response(val: string | string[] | null) {\n this._response = this.#normalizeResponse(val);\n }\n\n get response(): string[] | null {\n return this._response;\n }\n\n #normalizeResponse(value: string | string[] | null | undefined): string[] {\n if (value === null || value === undefined || value === '') return [];\n return Array.isArray(value) ? value : [value];\n }\n\n #getResponseArray(): string[] {\n return this.#normalizeResponse(this._response);\n }\n\n /** Extension hook for optional SVG lines rendered above the candidate response. */\n protected renderSupplementalLines(): unknown {\n return nothing;\n }\n\n override render() {\n return html`<slot name=\"prompt\"></slot>\n <line-container>\n <svg\n width=${ifDefined(this.grImage[0]?.width)}\n height=${ifDefined(this.grImage[0]?.height)}\n viewbox=\"0 0 ${this.grImage[0]?.width} ${this.grImage[0]?.height}\"\n >\n ${repeat(\n this.#getResponseArray(),\n line => line,\n (line, index) => svg`\n <line\n part=\"line\"\n x1=${parseInt(this.querySelector<SVGLineElement>(`[identifier=${line.split(' ')[0]}]`).style.left)}\n y1=${parseInt(this.querySelector<SVGLineElement>(`[identifier=${line.split(' ')[0]}]`).style.top)}\n x2=${parseInt(this.querySelector<SVGLineElement>(`[identifier=${line.split(' ')[1]}]`).style.left)}\n y2=${parseInt(this.querySelector<SVGLineElement>(`[identifier=${line.split(' ')[1]}]`).style.top)}\n stroke=\"red\"\n stroke-width=\"3\"\n @click=${(e: Event) => {\n e.stopPropagation();\n this._response = this._response.filter((_, i) => i !== index);\n this.saveResponse(this.response);\n }}\n />\n `\n )}\n ${this.renderSupplementalLines()}\n ${this.#startPoint &&\n svg`<line\n part=\"point\"\n x1=${this.startCoord.x}\n y1=${this.startCoord.y}\n x2=${this.mouseCoord.x}\n y2=${this.mouseCoord.y}\n stroke=\"var(--qti-border-active)\"\n stroke-width=\"3\"\n />`}\n </svg>\n <slot></slot>\n </line-container>\n <div role=\"alert\" part=\"message\" id=\"validation-message\"></div>`;\n }\n\n #positionHotspotOnRegister(e: CustomEvent<QtiHotspotChoice>): void {\n const img = this.querySelector('img') as HTMLImageElement;\n const hotspot = e.target as QtiHotspotChoice;\n const coords = hotspot.getAttribute('coords');\n const shape = hotspot.getAttribute('shape');\n const coordsNumber = coords.split(',').map(s => parseInt(s));\n positionShapes(shape, coordsNumber, img, hotspot);\n }\n\n override firstUpdated(): void {\n super.firstUpdated();\n this.#hotspots = this.querySelectorAll('qti-associable-hotspot');\n\n this.addEventListener('mousemove', event => {\n const img = this.grImage[0];\n if (!img) return;\n\n const rect = img.getBoundingClientRect();\n // const scaleX = img.naturalWidth / img.clientWidth;\n // const scaleY = img.naturalHeight / img.clientHeight;\n\n // console.log(`scaleX: ${scaleX}, scaleY: ${scaleY}`);\n\n this.mouseCoord = {\n x: event.clientX - rect.left, // * scaleX,\n y: event.clientY - rect.top // * scaleY\n };\n });\n\n this.#hotspots.forEach(hotspot => {\n // const img = thisgrImage[0];\n // const scaleX = img.naturalWidth / img.clientWidth;\n // const scaleY = img.naturalHeight / img.clientHeight;\n\n hotspot.style.left = hotspot.getAttribute('coords').split(',')[0] + 'px';\n hotspot.style.top = hotspot.getAttribute('coords').split(',')[1] + 'px';\n\n hotspot.addEventListener('click', event => {\n if (!this.#startPoint) {\n this.#startPoint = event.target as HTMLElement;\n\n this.startCoord = {\n x: parseInt(this.#startPoint.getAttribute('coords').split(',')[0]),\n y: parseInt(this.#startPoint.getAttribute('coords').split(',')[1])\n };\n } else if (!this.#endPoint) {\n this.#endPoint = event.target as HTMLElement;\n\n this._response = this.#getResponseArray();\n this._response = [\n ...this._response,\n `${this.#startPoint.getAttribute('identifier')} ${this.#endPoint.getAttribute('identifier')}`\n ];\n this.saveResponse(this.response);\n this.#startPoint = null;\n this.#endPoint = null;\n }\n });\n });\n }\n\n override disconnectedCallback(): void {\n super.disconnectedCallback();\n this.removeEventListener('qti-register-hotspot', this.#positionHotspotOnRegister);\n }\n}\n\ndeclare global {\n interface HTMLElementTagNameMap {\n 'qti-graphic-associate-interaction': QtiGraphicAssociateInteraction;\n }\n}\n","import { css } from 'lit';\n\nimport { boxSizing, validationMessage } from '@qti-components/base';\n\nexport default [\n boxSizing,\n validationMessage,\n css`\n :host {\n display: flex;\n align-items: flex-start;\n flex-direction: column;\n flex-wrap: wrap;\n gap: 0.5rem;\n /* Containing block for the absolutely positioned hotspots over the image. Was set on this\n host from the theme. */\n position: relative;\n }\n\n :host(.qti-choices-top) {\n flex-direction: column-reverse;\n }\n :host(.qti-choices-bottom) {\n flex-direction: column;\n }\n :host(.qti-choices-left) {\n flex-direction: row-reverse;\n & [name='drags'] {\n width: 25%;\n }\n & [part='image'] {\n width: 75%;\n }\n }\n :host(.qti-choices-right) {\n flex-direction: row;\n & [name='drags'] {\n width: 25%;\n }\n & [part='image'] {\n width: 75%;\n }\n }\n [part='image'] {\n display: block;\n position: relative;\n }\n /* [part='drops'] , */\n\n [name='drags'] {\n display: flex;\n align-items: flex-start;\n flex-wrap: wrap;\n flex: 1;\n border: 2px solid transparent;\n padding: 0.3rem;\n border-radius: 0.3rem;\n gap: 0.5rem;\n }\n ::slotted(img) {\n display: inline-block;\n user-select: none;\n pointer-events: none;\n }\n `\n];\n","import { html } from 'lit';\n\nimport { Interaction } from '@qti-components/base';\nimport {\n DragDropSlottedMixin,\n DragDropSlottedSortableMixin\n} from '@qti-components/interactions-core/mixins/drag-drop-observables';\n\n// import { DragDropInteractionMixin } from '@qti-components/interactions-core/mixins/drag-drop';\nimport styles from './qti-graphic-gap-match-interaction.styles';\n\nimport type { QtiHotspotChoice } from '@qti-components/interactions-core/elements/qti-hotspot-choice';\nimport type { CSSResultGroup } from 'lit';\nconst SlottedBase = DragDropSlottedMixin(\n Interaction,\n 'qti-gap-img, qti-gap-text',\n 'qti-associable-hotspot',\n `slot[part~='drags']`\n);\n\n/**\n * Graphic gap-match interaction: candidates drag choices onto image hotspots.\n *\n * @slot prompt - The prompt shown above the image.\n * @slot drags - The draggable choice sources.\n * @slot - Default slot for the base image and hotspots.\n *\n * @csspart image - Wrapper around the image slot.\n * @csspart drags - Wrapper around the drag sources slot.\n * @csspart message - Live validation message region (role=\"alert\").\n */\nexport class QtiGraphicGapMatchInteraction extends DragDropSlottedSortableMixin(SlottedBase, '[qti-draggable=\"true\"]') {\n static override styles: CSSResultGroup = styles;\n\n override render() {\n return html` <slot name=\"prompt\"></slot>\n <slot part=\"image\"></slot>\n <slot part=\"drags\" name=\"drags\" class=\"hover-border\"></slot>\n <div role=\"alert\" part=\"message\" id=\"validation-message\"></div>`;\n }\n\n public override shouldReturnToInventoryOnInventoryDrop(): boolean {\n return true;\n }\n\n #positionHotspotOnRegister(e: CustomEvent<null>): void {\n const hotspot = e.target as QtiHotspotChoice;\n const coords = hotspot.getAttribute('coords');\n const shape = hotspot.getAttribute('shape');\n const coordsNumber = coords.split(',').map(s => parseInt(s));\n\n // positionHotspots(shape, coordsNumber, img, hotspot);\n switch (shape) {\n case 'circle':\n {\n const [centerX, centerY, radius] = coordsNumber;\n hotspot.style.left = centerX - radius + 'px';\n hotspot.style.top = centerY - radius + 'px';\n hotspot.style.width = hotspot.style.height = 2 * radius + 'px';\n }\n break;\n\n case 'rect':\n {\n const [leftX, topY, rightX, bottomY] = coordsNumber;\n hotspot.style.left = leftX + 'px';\n hotspot.style.top = topY + 'px';\n hotspot.style.width = rightX - leftX + 'px';\n hotspot.style.height = bottomY - topY + 'px';\n }\n break;\n\n default:\n break;\n }\n }\n\n override connectedCallback(): void {\n super.connectedCallback();\n this.addEventListener('qti-register-hotspot', this.#positionHotspotOnRegister);\n }\n override disconnectedCallback() {\n super.disconnectedCallback();\n this.removeEventListener('qti-register-hotspot', this.#positionHotspotOnRegister);\n }\n}\n\ndeclare global {\n interface HTMLElementTagNameMap {\n 'qti-graphic-gap-match-interaction': QtiGraphicGapMatchInteraction;\n }\n}\n","import { css } from 'lit';\n\nimport { boxSizing, validationMessage } from '@qti-components/base';\n\nexport default [\n boxSizing,\n validationMessage,\n css`\n /* The order pins are anchored outside their hotspot's box. */\n :host {\n /* The box this element already had. See the note in qti-match-interaction.styles.ts. */\n display: block;\n overflow: visible;\n }\n\n slot:not([name='prompt']) {\n position: relative; /* qti-hotspot-choice relative to the slot */\n display: block;\n width: fit-content; /* hotspots not stretching further if image is at max size */\n }\n\n /*\n * The order pin. A light-DOM <span> this interaction appends (see #LOCATOR_CLASS), so it lands\n * in the default slot above and ::slotted() reaches it — its containing block is that slot.\n *\n * Placement only. The pin's face — the teardrop SVG, its fill, the number's colour and size —\n * is paint and stays in the theme, which is also where the --qti-graphic-order-pin-* tokens\n * live. 'position-anchor' is repeated as a declaration because the JS writes the per-hotspot\n * anchor name inline; this is the property's home, the inline style is its value.\n */\n ::slotted(.cito-graphic-order-marker) {\n position: absolute;\n left: anchor(center);\n top: anchor(center);\n transform: translate(-50%, var(--qti-graphic-order-pin-anchor));\n display: flex;\n justify-content: center;\n align-items: flex-start;\n z-index: 3;\n }\n ::slotted(img) {\n /* image not selectable anymore */\n pointer-events: none;\n user-select: none;\n }\n `\n];\n","import { html } from 'lit';\n\nimport { Interaction } from '@qti-components/base';\nimport { ChoicesMixin } from '@qti-components/interactions-core/mixins/choices/choices.mixin';\nimport { positionShapes } from '@qti-components/interactions-core/internal/hotspots/hotspot';\n\nimport styles from './qti-graphic-order-interaction.styles';\n\nimport type { QtiHotspotChoice } from '@qti-components/interactions-core/elements/qti-hotspot-choice';\nimport type { Choice } from '@qti-components/interactions-core/mixins/choices/choices.mixin';\nimport type { CSSResultGroup } from 'lit';\n\ntype HotspotChoice = Choice & { order: number };\n/**\n * Graphic order interaction: candidates order hotspots on an image.\n *\n * @slot prompt - The prompt shown above the image.\n * @slot - Default slot for the image and hotspot choices.\n *\n * @csspart message - Live validation message region (role=\"alert\").\n */\nexport class QtiGraphicOrderInteraction extends ChoicesMixin(Interaction, 'qti-hotspot-choice') {\n static override styles: CSSResultGroup = styles;\n\n static readonly #LOCATOR_CLASS = 'cito-graphic-order-marker';\n\n protected choiceOrdering: boolean;\n\n protected _choiceElements: Choice[] = [];\n\n override render() {\n return html`\n <slot name=\"prompt\"></slot>\n <slot></slot>\n <div role=\"alert\" part=\"message\" id=\"validation-message\"></div>\n `;\n }\n\n #setHotspotOrder(e: CustomEvent<{ identifier: string }>): void {\n const { identifier } = e.detail;\n\n const hotspot = this._choiceElements.find(el => el.getAttribute('identifier') === identifier) as HotspotChoice;\n\n if (!hotspot) return;\n\n const maxSelection = this._choiceElements.length;\n\n if (!this.choiceOrdering) {\n this.choiceOrdering = true;\n\n if (hotspot.order == null) {\n // Hotspot is not selected, so assign the next available order\n const currentSelection = (this._choiceElements as HotspotChoice[]).filter(i => i.order != null).length;\n\n if (currentSelection >= maxSelection) {\n this.choiceOrdering = false;\n return; // Maximum selection reached\n }\n\n hotspot.order = currentSelection + 1;\n } else {\n // Hotspot is already selected, so remove its order and renumber the rest\n const removedOrder = hotspot.order;\n\n hotspot.order = null;\n\n (this._choiceElements as HotspotChoice[]).forEach(hotspot => {\n if (hotspot.order != null && hotspot.order > removedOrder) {\n hotspot.order--;\n }\n });\n }\n\n this.refreshLocatorPins();\n this.choiceOrdering = false;\n }\n }\n\n #anchorNameForChoice(choice: HotspotChoice): string {\n const raw = choice.identifier || choice.getAttribute('identifier') || 'hotspot';\n const normalized = raw.toLowerCase().replace(/[^a-z0-9_-]/g, '-');\n return `--qti-graphic-order-${normalized}`;\n }\n\n /** Extension hook for packages that add semantic color states to locator pins. */\n protected resolvePinColor(_choice: HotspotChoice): string {\n return 'var(--qti-selected-bg)';\n }\n\n protected refreshLocatorPins() {\n // Remove previous markers and anchor names managed by this component.\n this.querySelectorAll(`.${QtiGraphicOrderInteraction.#LOCATOR_CLASS}`).forEach(marker => marker.remove());\n\n (this._choiceElements as HotspotChoice[]).forEach(choice => {\n choice.style.removeProperty('anchor-name');\n });\n\n const orderedChoices = (this._choiceElements as HotspotChoice[])\n .filter(choice => choice.order != null)\n .sort((a, b) => a.order - b.order);\n\n orderedChoices.forEach(choice => {\n const anchorName = this.#anchorNameForChoice(choice);\n choice.style.setProperty('anchor-name', anchorName);\n\n const marker = document.createElement('span');\n marker.className = QtiGraphicOrderInteraction.#LOCATOR_CLASS;\n marker.style.setProperty('position-anchor', anchorName);\n marker.style.setProperty('--qti-graphic-order-pin-color', this.resolvePinColor(choice));\n if (choice.getAttribute('shape') === 'poly') {\n marker.classList.add('cito-graphic-order-marker--poly');\n }\n marker.setAttribute('aria-hidden', 'true');\n marker.textContent = String(choice.order);\n this.append(marker);\n });\n }\n\n #positionHotspotOnRegister(e: CustomEvent<QtiHotspotChoice>): void {\n const img = this.querySelector('img') as HTMLImageElement;\n const hotspot = e.target as QtiHotspotChoice;\n const coords = hotspot.getAttribute('coords');\n const shape = hotspot.getAttribute('shape');\n const coordsNumber = coords.split(',').map(s => parseInt(s));\n\n positionShapes(shape, coordsNumber, img, hotspot);\n }\n\n override connectedCallback(): void {\n super.connectedCallback();\n this.addEventListener('activate-qti-hotspot-choice', this.#setHotspotOrder);\n this.addEventListener('register-qti-hotspot-choice', this.#positionHotspotOnRegister);\n this.refreshLocatorPins();\n }\n override disconnectedCallback() {\n this.querySelectorAll(`.${QtiGraphicOrderInteraction.#LOCATOR_CLASS}`).forEach(marker => marker.remove());\n super.disconnectedCallback();\n this.removeEventListener('activate-qti-hotspot-choice', this.#setHotspotOrder);\n this.removeEventListener('register-qti-hotspot-choice', this.#positionHotspotOnRegister);\n }\n}\n\ndeclare global {\n interface HTMLElementTagNameMap {\n 'qti-graphic-order-interaction': QtiGraphicOrderInteraction;\n }\n}\n","import { css } from 'lit';\n\nimport { boxSizing, validationMessage } from '@qti-components/base';\n\nexport default [\n boxSizing,\n validationMessage,\n css`\n :host {\n display: block;\n }\n /*\n * This slot is the coordinate space the hotspots sit on. Every qti-hotspot-choice is\n * position:absolute and placed with left/top percentages (positionShapes, hotspot.ts), so the\n * slot must be both (a) a positioning context and (b) exactly the box of the image — or those\n * percentages resolve against the wrong rectangle and every hotspot is offset from the picture.\n *\n * position: relative the containing block the percent offsets resolve against. Without it\n * they would position against the nearest positioned ancestor.\n * display: inline-block shrink-wraps the slot to its content instead of a full-width block,\n * width: fit-content and caps that at the width of the image, so the slot never extends\n * past the picture and drags a 100%-wide hotspot out with it.\n *\n * A line-height:0 used to sit here to kill the inline descender gap under an image. The image is\n * display:block below, which has no such gap, so it was redundant and is gone.\n */\n slot:not([name='prompt']) {\n position: relative;\n display: inline-block;\n width: fit-content;\n }\n ::slotted(img) {\n display: block; /* out of the inline flow; also why the slot needs no line-height reset */\n pointer-events: none; /* image not selectable; clicks belong to the hotspots over it */\n user-select: none;\n /*\n * Fluid, and unconditionally, unlike the global reset rule img:not([width]) that leaves an\n * authored-size image fixed. A hotspot image is the coordinate space its hotspots sit on (they\n * are percentages of this box), so it MUST fit the viewport: a fixed-width image on a narrow\n * screen would overflow and carry its hotspots off the visible area.\n *\n * max-width: 100% caps the image at the container. NOT width:100%, which would force the\n * image to fill and upscale a small picture past its natural size into\n * blur; max-width shrinks on narrow and never upscales. (With the\n * fit-content slot above the two render the same today, but max-width says\n * the actual intent.)\n * height: auto lets the height follow the aspect ratio the width and height attributes\n * declare. Without it a height attribute pins the height while the width\n * shrinks, and the image squashes horizontally into an ellipse.\n *\n * The hotspots are percentages of this image, so they scale with it and stay registered; the\n * poly ring masks stretch with their element and keep a uniform stroke.\n */\n max-width: 100%;\n height: auto;\n }\n `\n];\n","import { html } from 'lit';\n\nimport { Interaction } from '@qti-components/base';\nimport { ChoicesMixin } from '@qti-components/interactions-core/mixins/choices/choices.mixin';\nimport { positionShapes } from '@qti-components/interactions-core/internal/hotspots/hotspot';\n\nimport styles from './qti-hotspot-interaction.styles';\n\nimport type { QtiHotspotChoice } from '@qti-components/interactions-core/elements/qti-hotspot-choice';\nimport type { CSSResultGroup } from 'lit';\n/**\n * Hotspot interaction: candidates select one or more hotspots on an image.\n *\n * @slot prompt - The prompt shown above the image.\n * @slot - Default slot for the image and hotspot choices.\n */\nexport class QtiHotspotInteraction extends ChoicesMixin(Interaction, 'qti-hotspot-choice') {\n static override styles: CSSResultGroup = styles;\n\n override render() {\n return html`\n <slot name=\"prompt\"></slot>\n <slot></slot>\n <div part=\"message\" role=\"alert\" id=\"validation-message\"></div>\n `;\n }\n\n #imageLoadPromise: Promise<HTMLImageElement> | null = null;\n\n #getImageLoadPromise(img: HTMLImageElement): Promise<HTMLImageElement> {\n if (!this.#imageLoadPromise) {\n if (img.naturalWidth > 0 && img.naturalHeight > 0) {\n this.#imageLoadPromise = Promise.resolve(img);\n } else {\n this.#imageLoadPromise = new Promise(resolve => {\n const handler = () => {\n img.removeEventListener('load', handler);\n resolve(img);\n };\n img.addEventListener('load', handler);\n });\n }\n }\n return this.#imageLoadPromise;\n }\n\n async #positionHotspotOnRegister(e: CustomEvent<QtiHotspotChoice>): Promise<void> {\n const img = this.querySelector('img') as HTMLImageElement;\n const hotspot = e.target as QtiHotspotChoice;\n const coords = hotspot.getAttribute('coords');\n const shape = hotspot.getAttribute('shape');\n const coordsNumber = coords.split(',').map(s => parseInt(s));\n const loadedImg = await this.#getImageLoadPromise(img);\n positionShapes(shape, coordsNumber, loadedImg, hotspot);\n }\n\n override connectedCallback(): void {\n super.connectedCallback();\n this.addEventListener('register-qti-hotspot-choice', this.#positionHotspotOnRegister);\n }\n override disconnectedCallback() {\n super.disconnectedCallback();\n this.removeEventListener('unregister-qti-hotspot-choice', this.#positionHotspotOnRegister);\n }\n}\n\ndeclare global {\n interface HTMLElementTagNameMap {\n 'qti-hotspot-interaction': QtiHotspotInteraction;\n }\n}\n","import { css } from 'lit';\n\nimport { boxSizing, validationMessage } from '@qti-components/base';\n\nexport default [\n boxSizing,\n validationMessage,\n css`\n /* The box this element already had. See the note in qti-match-interaction.styles.ts. */\n :host {\n display: block;\n }\n `\n];\n","import { html } from 'lit';\nimport { property } from 'lit/decorators.js';\n\nimport { Interaction } from '@qti-components/base';\nimport { ChoicesMixin } from '@qti-components/interactions-core/mixins/choices/choices.mixin';\n\nimport styles from './qti-hottext-interaction.styles';\n\nimport type { CSSResultGroup, PropertyValues } from 'lit';\n/**\n * Hottext interaction: candidates select highlighted words within a text block.\n *\n * @customElement qti-hottext-interaction\n *\n * @attr {string} response-identifier - Required. Identifier of the bound response variable.\n * @attr {number} [max-choices=1] - Maximum selectable hottexts; `0` means unlimited.\n * @attr {number} [min-choices=0] - Minimum selectable hottexts for a valid response.\n * @attr {'qti-unselected-hidden'} class - QTI shared presentation vocabulary.\n * `qti-unselected-hidden` leaves the selectable words visually indistinguishable from the\n * surrounding prose until they are selected.\n *\n * @slot - Default slot for the mixed content and `qti-hottext` choices.\n *\n * @csspart message - Live validation message region (role=\"alert\").\n */\nexport class QtiHottextInteraction extends ChoicesMixin(Interaction, 'qti-hottext') {\n static override styles: CSSResultGroup = styles;\n\n override render = () =>\n html`<slot></slot>\n <div part=\"message\" role=\"alert\" id=\"validation-message\"></div>`;\n}\n","import type { LitElement } from 'lit';\n\ntype Constructor<T = {}> = abstract new (...args: any[]) => T;\n\nexport type MenuAutoSize = LitElement & {\n updateMenuWidth(): void;\n shouldAutoSizeMenu(): boolean;\n menuAutoSizeExtraWidth(): number;\n menuAutoSizePropertyTarget(): HTMLElement | null;\n menuAutoSizeRows(): HTMLElement[];\n withMenuMeasurable<T>(measure: () => T): T;\n};\n\n/**\n * Sizes a closed combobox to the widest thing in its menu.\n *\n * A dropdown that is only as wide as the option currently showing jumps every time the candidate\n * picks a longer one, and in running prose that reflows the sentence around it. Measuring the menu\n * once and giving the trigger that width as a floor makes the control a constant box.\n *\n * ── Why this is a mixin ──────────────────────────────────────────────────────────────────────\n *\n * Same reason as `DropzoneAutoSizeMixin`, which this deliberately mirrors: the editor renders the\n * same control and wants the same behaviour, but does its own everything-else. It used to be two\n * private methods on `qti-inline-choice-interaction`, so the editor's copy was commented out and\n * rotting (`#estimateOptimalWidth`, disabled because it wrote to the host — see below).\n *\n * ── Where the width is written ───────────────────────────────────────────────────────────────\n *\n * On `menuAutoSizePropertyTarget()`, which defaults to the trigger INSIDE THE SHADOW ROOT — not on\n * the host, which is what the runtime used to do (`this.style.setProperty(...)`).\n *\n * That is the whole reason the editor could not reuse it. `style` is an attribute, ProseMirror's\n * mutation observer reverts any attribute its schema does not know, and the revert re-triggers the\n * observer that wrote it — a loop that hard-freezes the tab. A node inside a shadow root is\n * invisible to that observer, because MutationObserver does not cross shadow boundaries.\n *\n * Writing on the trigger rather than the host also happens to be the more honest target: the trigger\n * is the element whose `min-width` reads the property. Nothing inherits it that should not.\n *\n * ── Precedence ───────────────────────────────────────────────────────────────────────────────\n *\n * An inline style on the trigger outranks the `:host(.qti-input-width-*)` rules that also set this\n * property, so cascade order alone would let a measurement beat an author's explicit width class.\n * It does not, because the gate is in JS: `shouldAutoSizeMenu()` returns false when such a class is\n * present, and nothing is written at all. Keep that check there — do not try to express it in CSS.\n *\n * ── When it re-measures ──────────────────────────────────────────────────────────────────────\n *\n * On demand (the options changed), and whenever the menu changes size WHILE OPEN, via a\n * `ResizeObserver`. Open is the condition that matters: a popover is `display: none` when closed, so\n * the observer also fires with a 0x0 box on every open and close, and acting on those would both\n * write nonsense and feed itself. Reading only while open means the measurement pass below — which\n * opens the menu invisibly — cannot loop: the one observation it provokes reports the size that was\n * just written, and the changed-value guard drops it.\n */\nexport const MenuAutoSizeMixin = <T extends Constructor<LitElement>>(\n superClass: T,\n menuSelector = \"[part='menu']\",\n triggerSelector = \"[part='trigger']\",\n customProperty = '--qti-inline-choice-width'\n) => {\n abstract class MenuAutoSizeElement extends superClass {\n #resizeObserver: ResizeObserver | null = null;\n #observedMenu: Element | null = null;\n #contentObserver: MutationObserver | null = null;\n #pendingFrame = 0;\n /** Last width written, so an unchanged measurement writes nothing. See the observer note above. */\n #lastWritten: number | null = null;\n\n /**\n * Opt in. Off by default, so mixing this in changes nothing until the host says so.\n *\n * The host is also where the \"an explicit width class wins\" check belongs — see Precedence.\n */\n public shouldAutoSizeMenu(): boolean {\n return false;\n }\n\n /**\n * Anything the trigger shows beside the option text, which the menu does not have and therefore\n * does not contribute to the measurement — the dropdown chevron, in the shipped control.\n */\n public menuAutoSizeExtraWidth(): number {\n return 0;\n }\n\n /** Where the measured width is written. Inside the shadow root — see the header. */\n public menuAutoSizePropertyTarget(): HTMLElement | null {\n return this.renderRoot?.querySelector<HTMLElement>(triggerSelector) ?? null;\n }\n\n /**\n * The menu's rows, which is what actually gets measured — one at a time.\n *\n * Flat tree, so a `<slot>` is replaced by the elements assigned to it: in the shipped control the\n * prompt is rendered in the shadow root and the author's options are slotted light DOM, and both\n * are rows of the same list.\n */\n public menuAutoSizeRows(): HTMLElement[] {\n const menu = this.renderRoot?.querySelector<HTMLElement>(menuSelector);\n if (!menu) return [];\n\n return Array.from(menu.children).flatMap(child =>\n child instanceof HTMLSlotElement\n ? child.assignedElements().filter((el): el is HTMLElement => el instanceof HTMLElement)\n : child instanceof HTMLElement\n ? [child]\n : []\n );\n }\n\n /**\n * Make the rows measurable, run `measure`, and put everything back.\n *\n * A hook, because hosts hide their menu differently and a measurement needs layout. The default\n * covers the shipped control, whose menu is always in the DOM as a popover: open it invisibly if\n * it is closed. A host that renders the menu ONLY while open — the editor does exactly that, so\n * there is no element to open — overrides this to reveal whatever it hides instead.\n *\n * Synchronous, deliberately: the browser does not paint between the reveal and the restore, so\n * nothing flickers however the host implements it.\n */\n public withMenuMeasurable<T>(measure: () => T): T {\n const menu = this.renderRoot?.querySelector<HTMLElement>(menuSelector);\n if (!menu) return measure();\n\n const wasOpen = menu.matches(':popover-open');\n const prevVisibility = menu.style.visibility;\n const prevDisplay = menu.style.display;\n\n if (!wasOpen) {\n menu.style.visibility = 'hidden';\n menu.style.display = 'block';\n menu.showPopover?.();\n }\n try {\n return measure();\n } finally {\n if (!wasOpen) {\n menu.hidePopover?.();\n menu.style.visibility = prevVisibility;\n menu.style.display = prevDisplay;\n }\n }\n }\n\n public updateMenuWidth(): void {\n if (!this.isConnected || !this.shouldAutoSizeMenu()) return;\n\n const target = this.menuAutoSizePropertyTarget();\n if (!target) return;\n\n const menu = this.renderRoot?.querySelector<HTMLElement>(menuSelector);\n if (menu) this.#observeMenu(menu);\n this.#observeContent();\n\n const width = this.#measure() + this.menuAutoSizeExtraWidth();\n if (width <= 0 || width === this.#lastWritten) return;\n\n this.#lastWritten = width;\n target.style.setProperty(customProperty, `${width}px`);\n }\n\n /**\n * The width of the WIDEST ROW, plus whatever box the menu wraps around it. Opens the menu\n * invisibly if it is closed, because a closed popover has no layout to measure.\n *\n * Per row, deliberately, and NOT `width: max-content` on the menu as a whole. That was tried and\n * is wrong here: the option rows are inline-level (`display: inline-flex`, see\n * qti-inline-choice.styles.ts), so a max-content menu lays them all out ON ONE LINE and its\n * intrinsic width becomes the SUM of every option. Measured on a two-option control: rows of\n * 53.33 and 283.91 gave a menu of 343.42 instead of 283.91, so the trigger came out ~60px too\n * wide with a hole between the value and the chevron — and it would grow with every option\n * added. A row is only ever as wide as itself, so the max over rows is the number wanted.\n *\n * Measuring rows rather than the menu box also removes the feedback loop for free. The menu is\n * anchor-positioned with `min-width: anchor-size(width)`, i.e. never narrower than the trigger,\n * so reading the MENU and writing the result back to the trigger is a cycle that grows by\n * `menuAutoSizeExtraWidth()` on every pass — visibly, on every open, forever. A row does not\n * read the trigger, so nothing here can feed itself.\n */\n #measure(): number {\n return this.withMenuMeasurable(() => {\n let widest = 0;\n for (const row of this.menuAutoSizeRows()) {\n // max-content asks the one question with a single answer: how wide is this row if nothing\n // wraps. Without it a row reports whatever width the menu currently happens to give it —\n // the rows are `width: 100%` — which is another way of measuring our own output.\n const prevWidth = row.style.width;\n row.style.width = 'max-content';\n widest = Math.max(widest, row.getBoundingClientRect().width);\n row.style.width = prevWidth;\n }\n if (widest <= 0) return 0;\n\n // The rows sit inside the menu's own padding and border, and the trigger has to be wide\n // enough for the whole box, not just the text in it.\n const menu = this.renderRoot?.querySelector<HTMLElement>(menuSelector);\n if (!menu) return widest;\n\n const menuStyle = getComputedStyle(menu);\n return (\n widest +\n parseFloat(menuStyle.paddingLeft) +\n parseFloat(menuStyle.paddingRight) +\n parseFloat(menuStyle.borderLeftWidth) +\n parseFloat(menuStyle.borderRightWidth)\n );\n });\n }\n\n /**\n * Re-measure when the OPTIONS themselves change — a row added, removed, or its text edited.\n *\n * The ResizeObserver below cannot see any of that, because it only reads while the menu is open\n * and a closed popover is `display: none`: no box, no resize, no signal. That is fine in the\n * runtime, whose own slot observer rebuilds the options and calls updateMenuWidth() as part of\n * it — and useless in an editor, where an author adds a row by pressing Enter with the menu shut.\n * Relying on the host to remember is what left the editor's previous attempt at this dead.\n *\n * `characterData` as well as `childList`, so typing inside an existing option counts too, and\n * `subtree` because an option's text is a descendant, not a child.\n *\n * Coalesced to one measurement per frame. Both observers can fire for the same edit, and a\n * measurement forces layout — the write is already idempotent via #lastWritten, this keeps the\n * reads down too.\n */\n #observeContent(): void {\n if (typeof MutationObserver === 'undefined' || this.#contentObserver) return;\n\n this.#contentObserver = new MutationObserver(() => this.#scheduleMeasure());\n this.#contentObserver.observe(this, { childList: true, subtree: true, characterData: true });\n }\n\n #scheduleMeasure(): void {\n if (this.#pendingFrame) return;\n this.#pendingFrame = requestAnimationFrame(() => {\n this.#pendingFrame = 0;\n this.updateMenuWidth();\n });\n }\n\n #observeMenu(menu: HTMLElement): void {\n if (typeof ResizeObserver === 'undefined' || this.#observedMenu === menu) return;\n\n this.#resizeObserver ??= new ResizeObserver(() => {\n // Only while open: a closed popover reports 0x0, and reacting to that would write a zero\n // width and then re-fire on the way back up.\n if (!(this.#observedMenu as HTMLElement | null)?.matches(':popover-open')) return;\n\n // Deliberately the same path as everything else, rather than a cheaper inline read: only\n // #measure knows to measure rows instead of the menu box, and a shortcut here would\n // reintroduce the cycle and the sum-of-all-options bug that method exists to avoid.\n this.#scheduleMeasure();\n });\n\n if (this.#observedMenu) this.#resizeObserver.unobserve(this.#observedMenu);\n this.#resizeObserver.observe(menu);\n this.#observedMenu = menu;\n }\n\n public override disconnectedCallback(): void {\n this.#resizeObserver?.disconnect();\n this.#resizeObserver = null;\n this.#observedMenu = null;\n this.#contentObserver?.disconnect();\n this.#contentObserver = null;\n if (this.#pendingFrame) cancelAnimationFrame(this.#pendingFrame);\n this.#pendingFrame = 0;\n super.disconnectedCallback();\n }\n }\n\n return MenuAutoSizeElement as Constructor<MenuAutoSize> & T;\n};\n","import { css } from 'lit';\n\nimport type { CSSResultGroup } from 'lit';\n\nconst own = css`\n /* ── Host ──────────────────────────────────────────────────────────────────\n Inline-block so the element flows with surrounding text.\n --qti-inline-choice-width is the single width control surface:\n 0 (default) → trigger sizes to its content\n set by qti-input-width-* classes → trigger has a character-count minimum\n set by autosizing JS (inlineChoiceAutosize) → trigger matches widest option\n */\n :host {\n /*\n * The menu anchors to the HOST, not to the trigger inside it.\n *\n * The host is the box that paints the field border (@mixin field in the theme); the trigger is\n * transparent and border-less and therefore sits one border-width in on every side. Anchoring to\n * the trigger lined the menu up with that inner box, so the open control was 1px narrower than\n * the closed one on each side — measured: host 96.38→465.80, menu 97.38→464.80. Anchoring to the\n * host lines the menu up with the edge you can actually see.\n */\n anchor-name: --qti-inline-choice-anchor;\n\n display: inline-flex;\n align-items: center;\n vertical-align: baseline;\n position: relative;\n --qti-inline-choice-width: 0;\n /*\n * Four component-local tokens used to sit here and all four are gone.\n *\n * Three were pure aliases — --qti-inline-choice-overlay-z-index, -popover-z-index and\n * -motion-duration-fast each held nothing but var() of the global token of the same meaning,\n * were read exactly once, and were reachable from nowhere else. A second name for one value is\n * not an override surface; a theme retunes --qti-overlay-z-index and every reader follows.\n *\n * The fourth, --qti-inline-choice-trigger-gap, was calc(var(--qti-gap) / 2) — the arithmetic\n * the spacing vocabulary explicitly rules out: \"a call site that needs half of a gap is\n * describing a fourth value that does not exist in the vocabulary, and the answer is to pick the\n * nearest of the three, not to do arithmetic\" (qti-variables.css). The nearest is --qti-gap,\n * which is what the trigger spends now.\n */\n }\n\n /* ── QTI mandatory input-width shared vocabulary (15 values) ─────────────── */\n :host(.qti-input-width-1) {\n --qti-inline-choice-width: 1ch;\n }\n :host(.qti-input-width-2) {\n --qti-inline-choice-width: 2ch;\n }\n :host(.qti-input-width-3) {\n --qti-inline-choice-width: 3ch;\n }\n :host(.qti-input-width-4) {\n --qti-inline-choice-width: 4ch;\n }\n :host(.qti-input-width-6) {\n --qti-inline-choice-width: 6ch;\n }\n :host(.qti-input-width-10) {\n --qti-inline-choice-width: 10ch;\n }\n :host(.qti-input-width-15) {\n --qti-inline-choice-width: 15ch;\n }\n :host(.qti-input-width-20) {\n --qti-inline-choice-width: 20ch;\n }\n :host(.qti-input-width-25) {\n --qti-inline-choice-width: 25ch;\n }\n :host(.qti-input-width-30) {\n --qti-inline-choice-width: 30ch;\n }\n :host(.qti-input-width-35) {\n --qti-inline-choice-width: 35ch;\n }\n :host(.qti-input-width-40) {\n --qti-inline-choice-width: 40ch;\n }\n :host(.qti-input-width-45) {\n --qti-inline-choice-width: 45ch;\n }\n :host(.qti-input-width-50) {\n --qti-inline-choice-width: 50ch;\n }\n :host(.qti-input-width-72) {\n --qti-inline-choice-width: 72ch;\n }\n\n /* ── Trigger button — layout only, all paint lives in the theme ───────────── */\n button[part='trigger'] {\n display: inline-grid;\n grid-template-columns: minmax(0, 1fr) auto;\n align-items: center;\n column-gap: var(--qti-glyph-gap);\n box-sizing: border-box;\n min-width: var(--qti-inline-choice-width);\n vertical-align: baseline;\n }\n\n [part='value'] {\n min-width: 0;\n overflow: hidden;\n text-overflow: ellipsis;\n white-space: nowrap;\n text-align: left;\n }\n\n /* ── Chevron icon ─────────────────────────────────────────────────────────────\n Rendered as a CSS mask so the theme controls its colour via color:.\n The span in the template is empty; this CSS provides the visual.\n */\n [part~='dropdown-icon'] {\n flex: 0 0 auto;\n display: inline-block;\n width: 1em;\n height: 1em;\n background-color: currentColor;\n mask: var(--qti-chevron-mask) no-repeat center / contain;\n -webkit-mask: var(--qti-chevron-mask) no-repeat center / contain;\n transition: transform var(--qti-motion-duration-fast) ease;\n transform-origin: center;\n }\n\n [part~='dropdown-icon-open'] {\n transform: rotate(180deg);\n }\n\n /* ── Popover menu — anchor positioning only, all paint in the theme ──────── */\n [part='menu'] {\n position-anchor: --qti-inline-choice-anchor;\n inset: auto;\n margin: 0;\n z-index: var(--qti-popover-z-index);\n top: anchor(bottom);\n left: anchor(left);\n min-width: anchor-size(width);\n max-width: min(90vw, 36rem);\n max-height: min(40vh, 20rem);\n overflow: auto;\n box-sizing: border-box;\n position-try-fallbacks: flip-block, flip-inline;\n }\n\n /* ── Option rows — layout only, all paint in the theme ─────────────────── */\n button[part~='option'] {\n display: flex;\n align-items: center;\n width: 100%;\n box-sizing: border-box;\n text-align: left;\n font: inherit;\n color: inherit;\n white-space: nowrap;\n overflow: hidden;\n text-overflow: ellipsis;\n }\n\n [part='option-content'] {\n flex: 1 1 auto;\n min-width: 0;\n overflow: hidden;\n text-overflow: ellipsis;\n white-space: nowrap;\n }\n\n img {\n display: inline-block;\n vertical-align: middle;\n }\n\n /* ── Validation message ────────────────────────────────────────────────────\n Absolutely positioned below the trigger so it does not push surrounding\n inline text and cannot be obscured by the open popover menu.\n */\n [part='message'] {\n position: absolute;\n inset-block-start: 100%;\n inset-inline-start: 0;\n z-index: var(--qti-overlay-z-index);\n white-space: nowrap;\n }\n`;\n\nconst styles: CSSResultGroup = own;\n\nexport default styles;\n","import { html } from 'lit';\nimport { property, state } from 'lit/decorators.js';\nimport { consume } from '@lit/context';\n\nimport { watch } from '@qti-components/utilities';\nimport { Interaction } from '@qti-components/base';\nimport { configContext } from '@qti-components/base';\nimport { MenuAutoSizeMixin } from '@qti-components/interactions-core/mixins/menu-auto-size';\n\nimport styles from './qti-inline-choice-interaction.styles.js';\n\nimport type { PropertyValues } from 'lit';\nimport type { ConfigContext } from '@qti-components/base';\nimport type { ActiveElementMixinInterface } from '@qti-components/interactions-core/mixins/active-element/active-element.mixin';\n\ninterface OptionType {\n content: string | Node[];\n value: string;\n selected: boolean;\n}\n\ntype InlineChoiceOptionElement = HTMLElement & ActiveElementMixinInterface;\n\nlet inlineChoiceMenuCounter = 0;\n\n/**\n * Inline choice interaction: dropdown selector rendered inline with surrounding text.\n *\n * @customElement qti-inline-choice-interaction\n *\n * @attr {string} response-identifier - Required. Identifier of the bound response variable.\n * @attr {string} data-prompt - Placeholder shown before a choice is picked. Falls back to\n * the item configuration's `inlineChoicePrompt`, then to `select`.\n * @attr {boolean} [shuffle=false] - Requests option shuffling. Applied by the transform\n * pipeline (`qti-transformers`), not by this element.\n * @attr {boolean} [required=false] - Whether a choice must be selected for the response to be\n * valid. Written as `required=\"true\"` / `required=\"false\"`; a bare `required` is accepted too.\n * @attr {number} [min-choices=0] - Equivalent spelling of `required`: `1` demands an answer.\n * Absent from the QTI attribute table for this element but used by the conformance suite.\n *\n * @slot - Default slot for `qti-inline-choice` options.\n *\n * @csspart trigger - The dropdown trigger button.\n * @csspart value - The currently displayed value inside the trigger.\n * @csspart dropdown-icon - The chevron icon inside the trigger; also carries `dropdown-icon-open` when open.\n * @csspart menu - The popover element containing the option list.\n * @csspart option - Each option button; also carries `option-prompt` and `option-selected` variants.\n * @csspart option-content - The content wrapper inside each option.\n */\nexport class QtiInlineChoiceInteraction extends MenuAutoSizeMixin(Interaction) {\n constructor() {\n super();\n this.internals.role = 'listbox';\n }\n\n override get isInline(): boolean {\n return true;\n }\n\n static override get styles() {\n return [styles];\n }\n\n @state()\n protected options: OptionType[] = [];\n\n @state()\n protected _dropdownOpen = false;\n\n private _slotObserver: MutationObserver | null = null;\n private readonly _menuId = `qti-inline-choice-menu-${inlineChoiceMenuCounter++}`;\n\n @consume({ context: configContext, subscribe: true })\n @property({ attribute: false })\n declare configContext: ConfigContext;\n\n /**\n * Placeholder shown in the closed combobox before a choice is picked.\n *\n * Declared rather than read straight off `dataset` so it reaches the custom elements\n * manifest, the generated types and the Storybook controls — and so that changing it\n * re-renders, which reading `dataset` at render time never did.\n *\n * Falls back to the item configuration's `inlineChoicePrompt`, then to `select`.\n */\n @property({ type: String, attribute: 'data-prompt' }) dataPrompt: string;\n\n @watch('dataPrompt', { waitUntilFirstUpdate: true })\n protected _handleDataPromptChange = () => {\n this.#updateOptions();\n };\n\n /**\n * Whether a choice must be selected for the response to be valid. QTI defaults this to\n * false, so an untouched dropdown is a valid empty response unless an author opts in.\n *\n * QTI writes `required=\"true\"` / `required=\"false\"` rather than using HTML's bare-attribute\n * boolean, so `required=\"false\"` must read as false — which Lit's default Boolean converter\n * would get backwards, since it only tests for the attribute's presence.\n */\n @property({\n type: Boolean,\n reflect: true,\n converter: {\n // A bare `required` is accepted too, so HTML-style authoring still behaves sensibly.\n fromAttribute: (value: string | null) => value === 'true' || value === '',\n toAttribute: (value: boolean) => (value ? 'true' : null)\n }\n })\n required = false;\n\n /**\n * Minimum selections for a valid response — in practice 0 or 1, since the dropdown holds one.\n *\n * Not in the QTI 3 Implementation Guide's attribute table for this element, which offers only\n * `required`. It is in the conformance suite: `Advanced/Q12-inline-choice/inline-choice-sv-3`\n * expresses \"must answer\" as `min-choices=\"1\"`, and pairs it with `data-min-selections-message`.\n * Authors reach for it because every sibling interaction takes it, so it is honoured here as an\n * equivalent spelling of `required`.\n */\n @property({ type: Number, attribute: 'min-choices' }) minChoices = 0;\n\n @watch(['required', 'minChoices'], { waitUntilFirstUpdate: true })\n protected _handleRequiredChange = () => {\n this.validate();\n this.reportValidity();\n };\n\n /*\n * The template in named pieces, so a subclass can recompose it. Override a piece to change what\n * one part looks like; override `render()` to change the order. See the longer note on the same\n * pattern in qti-extended-text-interaction.\n */\n\n /** The closed combobox — the box showing the chosen option. */\n protected renderTrigger(): unknown {\n const selected = this.#selectedOption();\n\n return html`\n <button\n part=\"trigger\"\n type=\"button\"\n @click=${this.#onTriggerClick}\n @keydown=${this.#onCustomTriggerKeyDown}\n aria-haspopup=\"listbox\"\n aria-expanded=\"${this._dropdownOpen ? 'true' : 'false'}\"\n aria-controls=\"${this._menuId}\"\n popovertarget=\"${this._menuId}\"\n popovertargetaction=\"toggle\"\n ?disabled=\"${this.disabled}\"\n data-readonly=\"${this.readonly ? 'true' : 'false'}\"\n >\n <span part=\"value\">${selected?.content}</span>\n <span\n part=\"${this._dropdownOpen ? 'dropdown-icon dropdown-icon-open' : 'dropdown-icon'}\"\n aria-hidden=\"true\"\n ></span>\n </button>\n `;\n }\n\n /** The popover listbox. */\n protected renderMenu(): unknown {\n return html`\n <div\n id=\"${this._menuId}\"\n part=\"menu\"\n role=\"listbox\"\n popover=\"auto\"\n @toggle=${this.#onMenuToggle}\n @keydown=${this.#onCustomMenuKeyDown}\n >\n <button\n part=\"${this.options[0]?.selected ? 'option option-prompt option-selected' : 'option option-prompt'}\"\n type=\"button\"\n role=\"option\"\n aria-selected=\"${this.options[0]?.selected ? 'true' : 'false'}\"\n @click=${() => this.#selectValue('')}\n >\n <span part=\"option-content\">${this.options[0]?.content}</span>\n </button>\n <slot @slotchange=${this.#onChoicesSlotChange}></slot>\n </div>\n `;\n }\n\n /** Hidden until `Interaction.reportValidity` shows it. */\n protected renderValidationMessage(): unknown {\n return html`<div id=\"validation-message\" part=\"message\" role=\"alert\" style=\"display:none;\"></div>`;\n }\n\n override render() {\n return html` ${this.renderTrigger()} ${this.renderMenu()} ${this.renderValidationMessage()} `;\n }\n\n override async connectedCallback() {\n super.connectedCallback();\n this.#updateOptions();\n this.#startSlotObserver();\n\n // First measurement, once the trigger and menu exist to be measured. After this the mixin's\n // ResizeObserver keeps the width current on its own.\n await this.updateComplete;\n\n if (!this.isConnected) return;\n\n this.updateMenuWidth();\n }\n\n override disconnectedCallback() {\n super.disconnectedCallback();\n\n this.#teardownSlottedChoices();\n this._slotObserver?.disconnect();\n this._slotObserver = null;\n }\n\n override willUpdate(changed: PropertyValues<this>) {\n if (changed.has('configContext')) {\n this.#updateOptions();\n }\n }\n\n override updated(changed: PropertyValues<this>) {\n const dropdownOpenKey = '_dropdownOpen' as keyof QtiInlineChoiceInteraction;\n if (changed.has(dropdownOpenKey) && this._dropdownOpen) {\n this.#syncSlottedChoices();\n const first = this.#allMenuOptions()[0];\n first?.focus();\n }\n\n if (changed.has('disabled') || changed.has('readonly')) {\n this.#syncSlottedChoices();\n }\n }\n\n #selectedOption(): OptionType | undefined {\n return this.options.find(option => option.selected) ?? this.options[0];\n }\n\n #updateOptions() {\n const choices = Array.from(this.querySelectorAll('qti-inline-choice'));\n const prompt = this.dataPrompt || this.configContext?.inlineChoicePrompt || 'select';\n\n // Pending value from `response=\"…\"` attribute set before slotted options existed\n // takes precedence over any current selection.\n const pendingValue = this._pendingResponse;\n const currentlySelectedValue =\n pendingValue !== undefined ? (pendingValue ?? '') : (this.options.find(o => o.selected)?.value ?? '');\n\n const nextOptions: OptionType[] = [\n {\n content: prompt,\n value: '',\n selected: currentlySelectedValue === ''\n },\n ...choices.map(choice => {\n const value = choice.getAttribute('identifier') ?? '';\n return {\n content: Array.from(choice.childNodes).map(node => node.cloneNode(true)),\n value,\n selected: value !== '' && value === currentlySelectedValue\n };\n })\n ];\n\n const hasSelected = nextOptions.some(o => o.selected);\n this.options = hasSelected ? nextOptions : nextOptions.map((o, i) => ({ ...o, selected: i === 0 }));\n this._pendingResponse = undefined;\n this.#syncSlottedChoices();\n\n this.updateMenuWidth();\n }\n\n /**\n * Autosizing is opt-in through `configContext.inlineChoiceAutosize`, and an explicit\n * `qti-input-width-*` class always wins.\n *\n * That second check has to live here rather than in CSS: the measurement is written as an inline\n * style on the trigger, and the width classes set the same property on `:host`, so the cascade\n * would hand it to the measurement every time. Not writing at all is what makes the class win.\n */\n public override shouldAutoSizeMenu(): boolean {\n if (!this.configContext?.inlineChoiceAutosize) return false;\n return !Array.from(this.classList).some(c => c.startsWith('qti-input-width-'));\n }\n\n /**\n * The chevron sits in the trigger and not in the menu, so the menu never measures it.\n *\n * `offsetWidth`, NOT `getBoundingClientRect().width`: the icon rotates when the menu opens, and a\n * client rect reports the TRANSFORMED box — so a chevron caught mid-rotation measures wider than\n * it is, and the trigger grew and shrank by a few pixels on every open. offsetWidth is the layout\n * box and ignores the transform. (Same trap the drag-drop clone code documents for a chip picked\n * up mid-animation.)\n */\n public override menuAutoSizeExtraWidth(): number {\n const icon = this.renderRoot.querySelector<HTMLElement>('span[part~=\"dropdown-icon\"]');\n return icon?.offsetWidth ?? 0;\n }\n\n public validate(): boolean {\n const selectedOption = this.options.find(option => option.selected);\n const hasSelection = selectedOption ? selectedOption.value !== '' : false;\n\n // An empty response only invalidates when the author asked for one, spelled either way.\n // Before `required` existed this returned `hasSelection` outright, which made every\n // untouched dropdown invalid — the behaviour of a permanently-required field, and out of\n // step with `ChoicesMixin`, where an empty response is valid while `min-choices` is 0.\n const answerDemanded = this.required || this.minChoices >= 1;\n const isValid = hasSelection || !answerDemanded;\n\n const validityMessage = this.dataset.minChoicesMessage || 'Please select an option.';\n this.setInteractionValidity(isValid, isValid ? '' : validityMessage, this, { suppressInline: true });\n return isValid;\n }\n\n public override reportValidity(): boolean {\n return super.reportValidity();\n }\n\n public override reset() {\n this.#setDropdownOpen(false);\n this.options = this.options.map((option, i) => ({ ...option, selected: i === 0 }));\n this.#syncSlottedChoices();\n }\n\n /**\n * Captures an attribute-set response before slotted options have been\n * gathered. `#updateOptions` consumes it once the options exist.\n * `undefined` = no pending value.\n */\n private _pendingResponse: string | null | undefined = undefined;\n\n @property({ attribute: 'response', reflect: false, noAccessor: true })\n public set response(value: string | null) {\n const nextValue = value ?? '';\n if (this.options.length === 0) {\n this._pendingResponse = value;\n return;\n }\n this.options = this.options.map(option => ({ ...option, selected: option.value === nextValue }));\n this.#syncSlottedChoices();\n }\n get response(): string | null {\n const value = this.options.find(option => option.selected)?.value ?? '';\n return value === '' ? null : value;\n }\n\n #selectValue(value: string) {\n this.options = this.options.map(option => ({ ...option, selected: option.value === value }));\n this.#syncSlottedChoices();\n this.validate();\n this.reportValidity();\n this.saveResponse(value);\n this.#setDropdownOpen(false);\n }\n\n #setDropdownOpen(open: boolean) {\n const menu = this.#menuElement();\n if (!menu) return;\n\n if (open) {\n if (!menu.matches(':popover-open')) {\n menu.showPopover();\n }\n return;\n }\n\n if (menu.matches(':popover-open')) {\n menu.hidePopover();\n }\n }\n\n #onTriggerClick = (event: MouseEvent) => {\n if (this.disabled || this.readonly) {\n event.preventDefault();\n }\n };\n\n #onCustomTriggerKeyDown = (event: KeyboardEvent) => {\n if (this.disabled || this.readonly) return;\n if (event.key === 'ArrowDown' || event.key === 'Enter' || event.key === ' ') {\n event.preventDefault();\n this.#setDropdownOpen(true);\n }\n };\n\n #onMenuToggle = (event: Event) => {\n const toggleEvent = event as Event & { newState?: 'open' | 'closed' };\n const open = toggleEvent.newState === 'open';\n if (this._dropdownOpen !== open) {\n this._dropdownOpen = open;\n }\n // Published as a custom state so the theme can paint the open control — it squares the corners\n // where the trigger meets the menu. `_dropdownOpen` is a Lit @state and reaches no selector; a\n // custom state is the same opt-in the theme already uses for :state(disabled) / :state(readonly)\n // on this element. Not an attribute: a host whose mutation observer polices attributes (the\n // ProseMirror editor) cannot take one.\n if (open) this._internals.states.add('open');\n else this._internals.states.delete('open');\n };\n\n #onCustomMenuKeyDown = (event: KeyboardEvent) => {\n if (!this._dropdownOpen) return;\n if (event.key === 'Escape') {\n event.preventDefault();\n this.#setDropdownOpen(false);\n this.#focusTrigger();\n return;\n }\n\n const optionElements = this.#allMenuOptions();\n const shadowActive = (this.renderRoot as ShadowRoot).activeElement as HTMLElement | null;\n const deepActive = this.#getDeepActiveElement();\n const active =\n shadowActive ||\n (deepActive instanceof HTMLElement && this.#isElementInsideInteraction(deepActive) ? deepActive : null);\n const activeIndex = optionElements.findIndex(el => el === active);\n\n if (event.key === 'ArrowDown') {\n event.preventDefault();\n optionElements[Math.min(optionElements.length - 1, Math.max(0, activeIndex + 1))]?.focus();\n }\n\n if (event.key === 'ArrowUp') {\n event.preventDefault();\n optionElements[Math.max(0, activeIndex - 1)]?.focus();\n }\n\n if (event.key === 'Enter' || event.key === ' ') {\n if (!active) return;\n event.preventDefault();\n if (active instanceof HTMLButtonElement) {\n active.click();\n } else {\n const value = active.getAttribute('identifier') ?? '';\n this.#selectValue(value);\n }\n }\n };\n\n #focusTrigger() {\n this.renderRoot.querySelector<HTMLButtonElement>('button[part=\"trigger\"]')?.focus();\n }\n\n #getDeepActiveElement(): Element | null {\n let current: Element | null = document.activeElement;\n\n while (current && current instanceof HTMLElement && current.shadowRoot?.activeElement) {\n current = current.shadowRoot.activeElement;\n }\n\n return current;\n }\n\n #isElementInsideInteraction(element: HTMLElement): boolean {\n return element === this || this.contains(element) || this.renderRoot.contains(element);\n }\n\n #menuElement(): HTMLElement | null {\n return this.renderRoot.querySelector<HTMLElement>(`#${this._menuId}`);\n }\n\n #startSlotObserver() {\n this._slotObserver = new MutationObserver(() => this.#updateOptions());\n this._slotObserver.observe(this, { childList: true, subtree: true });\n }\n\n #onChoicesSlotChange = () => {\n this.#updateOptions();\n };\n\n #onSlottedChoiceClick = (event: Event) => {\n if (this.disabled || this.readonly) return;\n const target = event.currentTarget as HTMLElement;\n const value = target.getAttribute('identifier') ?? '';\n this.#selectValue(value);\n };\n\n #teardownSlottedChoices() {\n const choices = Array.from(this.querySelectorAll<InlineChoiceOptionElement>('qti-inline-choice'));\n for (const choice of choices) {\n choice.removeEventListener('click', this.#onSlottedChoiceClick);\n choice.removeAttribute('tabindex');\n choice.internals.role = null;\n choice.internals.ariaSelected = null;\n choice.internals.ariaChecked = 'false';\n choice.internals.states.delete('checked');\n }\n }\n\n async #syncSlottedChoices() {\n await this.updateComplete;\n const selectedValue = this.options.find(option => option.selected)?.value ?? '';\n const choices = Array.from(this.querySelectorAll<InlineChoiceOptionElement>('qti-inline-choice'));\n for (const choice of choices) {\n const value = choice.getAttribute('identifier') ?? '';\n const isSelected = value === selectedValue;\n choice.removeEventListener('click', this.#onSlottedChoiceClick);\n choice.addEventListener('click', this.#onSlottedChoiceClick);\n choice.disabled = this.disabled;\n choice.readonly = this.readonly;\n choice.internals.role = 'option';\n choice.internals.ariaSelected = isSelected ? 'true' : 'false';\n choice.internals.ariaChecked = isSelected ? 'true' : 'false';\n choice.internals.ariaDisabled = this.disabled ? 'true' : 'false';\n choice.internals.ariaReadOnly = this.readonly ? 'true' : 'false';\n if (isSelected) {\n choice.internals.states.add('checked');\n } else {\n choice.internals.states.delete('checked');\n }\n choice.tabIndex = -1;\n }\n }\n\n #allMenuOptions(): HTMLElement[] {\n const promptOption = this.renderRoot.querySelector<HTMLElement>('button[part~=\"option\"]');\n const slottedChoices = Array.from(this.querySelectorAll<HTMLElement>('qti-inline-choice'));\n return [...(promptOption ? [promptOption] : []), ...slottedChoices];\n }\n}\n\ndeclare global {\n interface HTMLElementTagNameMap {\n 'qti-inline-choice-interaction': QtiInlineChoiceInteraction;\n }\n}\n","import { css } from 'lit';\n\nimport { boxSizing, validationMessage } from '@qti-components/base';\n// import componentStyles from '../../utilities/styles/component.styles';\n\n/* ${componentStyles} */\nexport default [\n boxSizing,\n validationMessage,\n css`\n /*\n * A custom element is inline unless it says otherwise, and this one never did. Its shadow content\n * is block-level, so block-in-inline generated the anonymous block boxes and it looked correct —\n * but an inline box whose children are all block has no background area of its own, so the host\n * could not be painted, outlined or given a radius by anything downstream. Declaring the box the\n * element already had is layout-neutral: measured on ITEM009, the element rect and the following\n * sibling's position are identical to the pixel with and without this.\n */\n :host {\n display: block;\n\n /*\n * Match's columns are wider than the shared default, because each one is a category card\n * rather than a slot holding one chip. This was the 150px fallback inside the grid rule\n * below; a fallback could hold it only while nothing declared the token, so it is a real\n * declaration now. On :host, so it survives with or without the theme — and so a theme can\n * still retune it from the document, which outranks :host for the element it matches.\n */\n --qti-drop-track-min-width: 150px;\n }\n\n slot:not([hidden]) {\n /* slot where the */\n display: flex;\n flex-direction: column;\n gap: 0.5rem;\n }\n :host(.qti-choices-top) slot {\n flex-direction: column;\n }\n :host(.qti-choices-bottom) slot {\n flex-direction: column-reverse;\n }\n :host(.qti-choices-left) slot {\n flex-direction: row;\n }\n :host(.qti-choices-right) slot {\n flex-direction: row-reverse;\n }\n slot[name='prompt'] {\n display: block;\n }\n ::slotted(qti-simple-match-set) {\n /* Make sure the drag and drop container slots have the same width */\n flex: 1;\n }\n\n /*\n * The two match sets, in drag-drop mode. Both are slotted, so ::slotted() reaches them; the\n * theme used to lay them out by descendant selector from the document.\n *\n * First set is the chip bank — a wrapping row. Last set is the target grid, whose track floor is\n * a token so a theme can decide how wide a category card gets. That floor used to be a bare\n * '150px' in the theme, the one responsive breakpoint hiding in a stylesheet that is meant to\n * hold none.\n *\n * The gaps stay in the theme: gap is spacing.\n */\n :host(:not(.qti-match-tabular)) ::slotted(qti-simple-match-set:first-of-type) {\n display: flex;\n flex-wrap: wrap;\n\n /*\n * Two different properties, and the bank needs both.\n *\n * align-items packs a chip to the top of ITS OWN line. align-content packs the LINES to the\n * top of the container, and was missing — so it took the initial normal, which for a\n * multi-line flex container behaves as stretch.\n *\n * That only shows once the bank wraps AND is taller than its content, which is exactly the\n * side-by-side arrangement: the bank and the target grid are flex siblings, so the bank is\n * stretched to the grid's height. Measured on ITEM008 at 740px, where the bank wraps to two\n * lines: container 272px tall for 37px chips, the two lines stretched to 136px each, and the\n * second row of chips floating 144px below the first instead of 53px.\n */\n align-items: flex-start;\n align-content: flex-start;\n }\n\n :host(:not(.qti-match-tabular)) ::slotted(qti-simple-match-set:last-of-type) {\n display: grid;\n /*\n * The track floor by name — see the same rule in qti-order-interaction.styles.ts. Match sets\n * it wider than the shared default below, because a category card has to look able to hold\n * several answers. The measured term is still in the max() and still resolves to 0px here:\n * this interaction sets autoSizeDropzones = false, so nothing ever publishes it. Written out\n * anyway so the two grids read identically and neither has to be understood as the special one.\n */\n grid-template-columns: repeat(\n auto-fit,\n minmax(max(var(--qti-drop-track-min-width, 150px), var(--qti-dropzone-min-width, 0px)), 1fr)\n );\n }\n\n /* An answer key shows the answer, not the bank you would have dragged it from. The attribute is\n set on the clone by the correct-response mixin; the theme used to do this with a\n '.full-correct-response' descendant selector, from the document. */\n :host([answer-key]:not(.qti-match-tabular)) ::slotted(qti-simple-match-set:first-of-type) {\n display: none;\n }\n\n /* Same for a disabled interaction: nothing left to drag, so no bank. */\n :host(:disabled:not(.qti-match-tabular)) ::slotted(qti-simple-match-set:first-of-type) {\n display: none;\n }\n `\n];\n","import { css } from 'lit';\n\nimport { boxSizing } from '@qti-components/base';\n\n/**\n * Shadow-DOM styles for the tabular layout of qti-match-interaction\n * (class=\"qti-match-tabular\"). The two qti-simple-match-set children are\n * slotted into named slots and participate in a CSS grid as light-DOM\n * row/column headers via display: contents. Drag-drop mode is untouched.\n */\nexport default [\n boxSizing,\n css`\n :host(.qti-match-tabular) slot:not([hidden]) {\n display: contents;\n }\n :host(.qti-match-tabular) [part='grid'] {\n display: grid;\n /* Clips the cell rules — which are the grid's own background showing through a 1px gap — to the\n theme's border-radius. */\n overflow: hidden;\n width: fit-content;\n max-width: 100%;\n grid-template-columns: minmax(min-content, max-content) repeat(var(--qti-match-cols, 1), auto);\n grid-template-rows: auto repeat(var(--qti-match-rows, 1), auto);\n }\n /* Subgrid wrappers carry the slotted choices and the input cells into the\n outer grid's tracks. This structure is shared with the editor's tabular\n template so both can inherit the same theme CSS. No per-choice inline\n style writes are needed — auto-flow + subgrid handle placement. */\n :host(.qti-match-tabular) [part='cols-wrap'] {\n grid-column: 2 / -1;\n grid-row: 1;\n display: grid;\n grid-template-columns: subgrid;\n }\n :host(.qti-match-tabular) [part='rows-wrap'] {\n grid-column: 1;\n grid-row: 2 / -1;\n display: grid;\n grid-template-rows: subgrid;\n }\n :host(.qti-match-tabular) [part='checkbox-grid'] {\n grid-column: 2 / -1;\n grid-row: 2 / -1;\n display: grid;\n grid-template-columns: subgrid;\n grid-template-rows: subgrid;\n }\n :host(.qti-match-tabular) ::slotted(qti-simple-match-set) {\n display: contents;\n }\n\n /*\n * The radio/checkbox box centres its own mark. qti-simple-choice.styles.ts does the same for\n * the non-tabular control; here the cells are plain spans in this shadow root, so the rule\n * belongs to this file.\n *\n * The theme's 'form' mixin used to carry 'display: grid; place-content: center', which centred\n * both — from a document stylesheet, overriding qti-simple-choice's own flex centring. The mixin\n * keeps the box's size and paint; the box itself is laid out here.\n */\n :host(.qti-match-tabular) [part~='control'] {\n display: flex;\n align-items: center;\n justify-content: center;\n flex-shrink: 0;\n }\n `\n];\n","import { html, nothing } from 'lit';\nimport { property, state } from 'lit/decorators.js';\n\nimport { Interaction } from '@qti-components/base';\nimport {\n DragDropSlottedMixin,\n DragDropSlottedSortableMixin\n} from '@qti-components/interactions-core/mixins/drag-drop-observables';\n\n// import { DragDropInteractionMixin } from '@qti-components/interactions-core/mixins/drag-drop';\nimport styles from './qti-match-interaction.styles';\nimport tabularStyles from './qti-match-interaction-tabular.styles';\n\nimport type { ResponseVariable } from '@qti-components/base';\nimport type { CSSResultGroup, PropertyValues } from 'lit';\nimport type { ResponseInteraction } from '@qti-components/base';\nimport type { QtiSimpleAssociableChoice } from '@qti-components/interactions-core/elements/qti-simple-associable-choice';\n/**\n * Match interaction: candidates pair items from two sets, either as drag-and-drop or as a tabular grid.\n *\n * @customElement qti-match-interaction\n *\n * @attr {string} response-identifier - Required. Identifier of the bound response variable.\n * @attr {number} [max-associations=0] - Maximum pairings across the whole interaction; `0`\n * means unlimited. QTI's own default is `1`; this element defaults to unlimited because a\n * literal `1` breaks any multi-pair match item. See plans/interaction-attribute-spec-conformance.md.\n * @attr {number} [min-associations=1] - Minimum pairings for a valid response.\n * @attr {boolean} [shuffle=false] - Requests shuffling of both match sets. Applied by the\n * transform pipeline (`qti-transformers`), not by this element.\n * @attr {'qti-match-tabular'|'qti-choices-top'|'qti-choices-bottom'|'qti-choices-left'|'qti-choices-right'} class -\n * QTI shared presentation vocabulary. `qti-match-tabular` renders a checkbox/radio grid\n * instead of drag-and-drop; the `qti-choices-*` values position the source set.\n * @attr {boolean} [auto-size-dropzones=false] - Extension, not QTI. Sizes every drop target to\n * the widest chip so placement does not reflow the layout. The mixin default is `true`; this\n * interaction is the one that overrides it to `false`, because a match target is a category card\n * rather than a socket (see the field below and DROP-SIZING.md §1).\n * @attr {boolean} [disable-animations=false] - Extension, not QTI. Disables the FLIP move\n * animation.\n *\n * @slot prompt - The prompt shown above the interaction.\n * @slot match-cols - Column headers (tabular mode).\n * @slot match-rows - Row headers (tabular mode).\n * @slot - Default slot for the two match sets (drag-and-drop mode).\n *\n * @csspart grid - The tabular grid container.\n * @csspart corner - The top-left corner cell of the grid.\n * @csspart cols-wrap - Wrapper row for the column headers.\n * @csspart c-header - The column header slot wrapper.\n * @csspart rows-wrap - Wrapper column for the row headers.\n * @csspart r-header - The row header slot wrapper.\n * @csspart checkbox-grid - The interactive cell grid area.\n * @csspart input-cell - Each cell's label element.\n * @csspart control - The visible checkbox/radio box (tabular mode). Also carries the variant\n * tokens `radio` | `checkbox`, `checked`, and `correct` | `incorrect` — e.g.\n * `::part(control radio checked correct)`. These mirror the custom-state vocabulary; the cells\n * are plain spans in the shadow root, so they cannot carry real `:state()`.\n * @csspart control-mark - The inner mark element; carries the same variant tokens as `control`.\n * @csspart message - Live validation message region (role=\"alert\").\n */\nexport class QtiMatchInteraction extends DragDropSlottedSortableMixin(\n DragDropSlottedMixin(\n Interaction,\n 'qti-simple-match-set:first-of-type qti-simple-associable-choice, qti-simple-match-set:last-of-type > qti-simple-associable-choice > qti-simple-associable-choice',\n 'qti-simple-match-set:last-of-type > qti-simple-associable-choice',\n 'qti-simple-match-set:first-of-type'\n ),\n '[qti-draggable=\"true\"]'\n) {\n static override styles: CSSResultGroup = [styles, tabularStyles];\n\n /**\n * Match targets are categories, not slots. They should look able to hold several answers, so they\n * take a flat floor (the `--qti-dropzone-min-height` fallback) rather than the size of the widest chip.\n *\n * This is a property of the INTERACTION, not of an individual target. A `match-max=\"1\"` target is\n * still a category that happens to take one answer, and it sits in a grid beside targets that take\n * several — sizing each one to its own contents would make that grid ragged. So the whole\n * interaction opts out, and the per-target `match-max` decides nothing about size here.\n *\n * The interactions where a drop IS a slot — gap-match, order, associate — keep measurement on, and\n * their drops are exactly the widest chip plus the inset.\n */\n public override autoSizeDropzones = false;\n\n protected sourceChoices: QtiSimpleAssociableChoice[];\n protected targetChoices: QtiSimpleAssociableChoice[];\n protected lastCheckedRadio: HTMLInputElement | null = null;\n\n @property({ type: String }) class: string = '';\n\n @state() protected _response: string | string[] = [];\n // dragDropApi: TouchDragAndDrop;\n get response(): string[] {\n if (!this.classList.contains('qti-match-tabular')) return super.response as string[];\n else return this._response as string[];\n }\n set response(val: string[]) {\n if (!this.classList.contains('qti-match-tabular')) super.response = val;\n else this._response = val;\n }\n\n // Tabular mode is a pure radio/checkbox grid — drag-drop has no role there, so the choices\n // must not advertise themselves as draggable either. Suppresses `:state(drag)` on them.\n public override isDragDropEnabled(): boolean {\n return !this.classList.contains('qti-match-tabular');\n }\n\n // Tabular mode is a pure radio/checkbox grid — drag-drop has no role there.\n // Short-circuit drag initiation so no clone is created and no shadow/lightdom\n // state can diverge from this._response.\n public override initiateDrag(...args: any[]): void {\n if (this.classList.contains('qti-match-tabular')) return;\n (super.initiateDrag as (...a: any[]) => void)(...args);\n }\n\n // Skip the drag-drop auto-sizing pass in tabular mode — it would write\n // inline min-width/min-height onto each choice that forces the grid columns\n // to the draggable's natural width.\n public override afterCache(): void {\n if (this.classList.contains('qti-match-tabular')) return;\n super.afterCache();\n }\n\n @property({ type: String, attribute: 'response-identifier' }) override responseIdentifier: string = '';\n\n override async connectedCallback(): Promise<void> {\n super.connectedCallback();\n this.sourceChoices = Array.from<QtiSimpleAssociableChoice>(\n this.querySelectorAll('qti-simple-match-set:first-of-type qti-simple-associable-choice')\n );\n this.targetChoices = Array.from<QtiSimpleAssociableChoice>(\n this.querySelectorAll('qti-simple-match-set:last-of-type qti-simple-associable-choice')\n );\n\n this.syncTabularSlotting();\n }\n\n protected override willUpdate(changed: PropertyValues): void {\n super.willUpdate?.(changed);\n if (changed.has('class')) this.syncTabularSlotting();\n }\n\n private syncTabularSlotting(): void {\n const isTabular = this.classList.contains('qti-match-tabular');\n const sets = this.querySelectorAll(':scope > qti-simple-match-set');\n const sourceSet = sets[0] as HTMLElement | undefined;\n const targetSet = sets[1] as HTMLElement | undefined;\n\n const stripSizing = (c: QtiSimpleAssociableChoice) => {\n c.style.removeProperty('min-width');\n c.style.removeProperty('min-height');\n c.style.removeProperty('--qti-dropzone-min-height');\n };\n if (isTabular) {\n sourceSet?.setAttribute('slot', 'match-rows');\n targetSet?.setAttribute('slot', 'match-cols');\n // Choices flow into the subgrid wrappers via DOM order — no per-choice\n // grid-row/grid-column writes required. --qti-match-rows/-cols are set\n // inline on [part='grid'] from render() so the editor (which can't write\n // to host style under ProseMirror) shares the same mechanism.\n this.sourceChoices?.forEach(c => {\n stripSizing(c);\n c.setAttribute('role', 'rowheader');\n });\n this.targetChoices?.forEach(c => {\n stripSizing(c);\n c.setAttribute('role', 'columnheader');\n });\n } else {\n sourceSet?.removeAttribute('slot');\n targetSet?.removeAttribute('slot');\n this.sourceChoices?.forEach(c => c.removeAttribute('role'));\n this.targetChoices?.forEach(c => c.removeAttribute('role'));\n }\n }\n\n protected handleRadioClick = (e: { target: HTMLInputElement }) => {\n const radio = e.target as HTMLInputElement;\n if (this.lastCheckedRadio === radio) {\n radio.checked = false;\n this.lastCheckedRadio = null;\n this.handleRadioChange(e);\n } else {\n this.lastCheckedRadio = radio;\n }\n };\n\n protected handleRadioChange = (e: { target: any }) => {\n const checkbox = e.target as HTMLInputElement;\n const value = checkbox.value;\n const name = checkbox.name;\n const type = checkbox.type;\n\n if (checkbox.checked) {\n if (!this.response) {\n this.response = [value];\n } else if (this.response.indexOf(value) === -1) {\n if (type === 'radio') {\n this.response = (this.response || []).filter(v => v.indexOf(name) === -1);\n }\n this.response = [...this.response, value];\n }\n this.lastCheckedRadio = checkbox;\n } else {\n this.response = (this.response || []).filter(v => v !== value);\n this.lastCheckedRadio = null;\n }\n\n this.requestUpdate();\n this.dispatchEvent(\n new CustomEvent<ResponseInteraction>('qti-interaction-response', {\n bubbles: true,\n composed: true,\n detail: {\n responseIdentifier: this.responseIdentifier,\n response: Array.isArray(this.response) ? [...this.response] : this.response\n }\n })\n );\n };\n\n validate(): boolean {\n if (this.class.split(' ').includes('qti-match-tabular')) {\n return this.response?.length === this.sourceChoices.length;\n } else {\n return super.validate();\n }\n }\n\n /** Extension hook for packages that add visual state tokens to tabular cells. */\n protected getCellStateVariant(_value: string, _checked: boolean): string {\n return '';\n }\n\n override render() {\n const isTabular = this.class.split(' ').includes('qti-match-tabular');\n return html`\n <slot name=\"prompt\"></slot>\n <slot ?hidden=${isTabular}></slot>\n\n ${isTabular\n ? html`\n <div\n part=\"grid\"\n role=\"grid\"\n style=\"--qti-match-rows: ${this.sourceChoices.length}; --qti-match-cols: ${this.targetChoices.length};\"\n >\n <div part=\"corner\"></div>\n <div part=\"cols-wrap\" role=\"row\"><slot name=\"match-cols\" part=\"c-header\"></slot></div>\n <div part=\"rows-wrap\"><slot name=\"match-rows\" part=\"r-header\"></slot></div>\n <div part=\"checkbox-grid\">\n ${this.sourceChoices.map(\n (row, r) => html`\n <div role=\"row\" style=\"display: contents;\">\n ${this.targetChoices.map((col, c) => {\n const rowId = row.getAttribute('identifier');\n const colId = col.getAttribute('identifier');\n const value = `${rowId} ${colId}`;\n const selectedInRowCount =\n (this.response || []).filter(v => v.split(' ')[0] === rowId).length || 0;\n const checked = this.response?.includes(value) || false;\n const type = row.matchMax === 1 ? 'radio' : 'checkbox';\n /*\n * The cells are plain spans in this interaction's shadow root, so they\n * have no ElementInternals and cannot carry `:state()` — and\n * `::part(x):state(y)` requires the state to live on the part's own\n * element. Multi-token parts are the correct mechanism here. The tokens\n * deliberately reuse the state vocabulary (`radio`, `checkbox`,\n * `checked`, `correct`, `incorrect`) so a themer reads the same words\n * everywhere.\n *\n */\n const stateVariant = this.getCellStateVariant(value, checked);\n const checkedMarker = checked ? 'checked' : '';\n const controlPart = `control ${type} ${checkedMarker} ${stateVariant}`.trim();\n const controlMarkPart = `control-mark ${type} ${checkedMarker} ${stateVariant}`.trim();\n const disable =\n row.matchMax === 1\n ? false\n : row.matchMax !== 0 && selectedInRowCount >= row.matchMax && !checked;\n return html`\n <label\n part=\"input-cell\"\n role=\"gridcell\"\n style=\"grid-row: ${r + 1}; grid-column: ${c +\n 1}; display: flex; align-items: center; justify-content: center; cursor: pointer;\"\n >\n <input\n type=${type}\n hidden\n name=${rowId}\n value=${value}\n .checked=${checked}\n .disabled=${disable}\n @change=${(e: { target: any }) => this.handleRadioChange(e)}\n @click=${(e: { target: HTMLInputElement }) =>\n row.matchMax === 1 ? this.handleRadioClick(e) : null}\n />\n <span part=${controlPart} role=${type} aria-checked=${checked ? 'true' : 'false'}>\n <span part=${controlMarkPart}></span>\n </span>\n </label>\n `;\n })}\n </div>\n `\n )}\n </div>\n </div>\n `\n : nothing}\n\n <div role=\"alert\" part=\"message\" id=\"validation-message\"></div>\n `;\n }\n}\n\ndeclare global {\n interface HTMLElementTagNameMap {\n 'qti-match-interaction': QtiMatchInteraction;\n }\n}\n","import { css } from 'lit';\n\nimport { boxSizing, dropRegion, validationMessage } from '@qti-components/base';\n\n/**\n * Layout and sizing only. Paint and state live in the theme.\n *\n * What left, and where it went — `styles/qti-theme/interactions/qti-order-interaction.css` and\n * `styles/overrides/kennisnet/qti/order-interaction.scss`:\n *\n * [part~='drop'][active] / [enabled] -> ::part(active) / ::part(enabled)\n * [part~='drop']:has([part='drag']) -> ::part(filled)\n *\n * They had to be rewritten, not relocated: an attribute selector and `:has()` cannot follow\n * `::part()`, so the drop's flags became part tokens (verified in Chromium, see setDropFlag).\n *\n * Two rules were deleted rather than moved, because neither did anything:\n * - `background-color: var(--qti-background-color-active-droplist)` — that property is never\n * defined anywhere in the repo, so the declaration was invalid at computed-value time.\n * - `[part~='drop'][data-cross-slot-target]` — nothing has ever set that attribute.\n */\nexport default [\n boxSizing,\n validationMessage,\n dropRegion,\n css`\n /* The box this element already had. See the note in qti-match-interaction.styles.ts. */\n :host {\n display: block;\n }\n\n [part='drags'] {\n display: flex;\n align-items: flex-start;\n flex: 1;\n flex-wrap: wrap;\n }\n\n [part='drops'] {\n flex: 1;\n display: grid;\n grid-auto-flow: row;\n /*\n * A column floor and a drop's own min-width are two jobs, and this asks for both by name\n * rather than letting one token mean both. --qti-drop-track-min-width is the policy: a column\n * stays usable however narrow the chips are. --qti-dropzone-min-width is the measurement: a\n * column is never narrower than the chip it holds. max() of the two is what the grid wants,\n * and the 0px fallback is what makes this correct for an interaction that never measures.\n *\n * One name did both until --qti-drop-min-width was deleted for exactly that (it meant the\n * track floor here and a drop's own min-width in the match target). Folding the track back\n * onto --qti-dropzone-min-width brought the conflation back: a theme setting it to give\n * unmeasured drops a floor also set every column, and a code path that stopped publishing a\n * measured width stopped meaning \"no floor\".\n */\n grid-template-columns: repeat(\n auto-fit,\n minmax(max(var(--qti-drop-track-min-width, 120px), var(--qti-dropzone-min-width, 0px)), 1fr)\n );\n gap: 0.5rem;\n }\n\n :host([orientation='horizontal']) [part='drags'],\n :host(.qti-orientation-horizontal) [part='drags'] {\n flex-direction: row;\n }\n /*\n * Horizontal adds nothing to [part='drops']: the base rule above is already the horizontal\n * layout — auto-fit columns that wrap. Only 'vertical' overrides it, to a single column.\n *\n * There used to be a 'grid-auto-flow: column' here, which forced every drop onto one\n * non-wrapping line. The theme cancelled it by restating the base rule at\n * qti-order-interaction.css, but only for '[orientation='horizontal']' — so the attribute\n * wrapped and the '.qti-orientation-horizontal' class did not. The theme's rule is gone and so\n * is this one; both spellings now wrap, which is what the attribute already did.\n */\n :host([orientation='vertical']) [part='drags'],\n :host(.qti-orientation-vertical) [part='drags'] {\n flex-direction: column;\n }\n :host([orientation='vertical']) [part='drops'],\n :host(.qti-orientation-vertical) [part='drops'] {\n grid-template-columns: 1fr;\n }\n\n /* Drop target. The interaction measures its chips and publishes the result as a custom\n property on its host; the property itself lives here, not in a style attribute. */\n [part~='drop'] {\n display: flex;\n flex: 1;\n min-height: var(--qti-dropzone-min-height, 0);\n\n /*\n * Both axes, not just the height.\n *\n * The width was measured and published all along and then thrown away: the drop is a grid item\n * and stretched to its track, which is 1fr, so a slot in the vertical layout came out 669px\n * wide for a 149px chip. justify-self: start stops the stretch and the measured minimum then\n * decides, so a slot is exactly as wide as the widest chip — the same rule the height has\n * always followed.\n *\n * The grid is untouched: the tracks still lay the slots out and still wrap in the horizontal\n * layout. Only the slot inside the track stops filling it.\n */\n min-width: var(--qti-dropzone-min-width, 0);\n justify-self: start;\n\n /* A chip's drop shadow hangs outside its column. */\n overflow: visible;\n }\n\n [part='drops'] {\n overflow: visible;\n }\n\n /* Once a drop holds a chip it stops stretching to the row and sits at the top of it. */\n :host(:has(qti-simple-choice)) [part~='drop'] {\n align-self: flex-start;\n }\n\n /*\n * The chip a drop renders.\n *\n * 'overflow: visible', not 'hidden'. The theme declared both, in two '::part(drag)' blocks at\n * equal specificity in the same layer, so the later one won and the chip has always been\n * unclipped. The 'text-overflow: ellipsis' still sitting beside the first one has therefore\n * never done anything; it is left in the theme rather than deleted here, since removing it is a\n * decision about how a long label should behave, not a relocation.\n */\n [part~='drag'] {\n display: flex;\n align-items: center;\n overflow: visible;\n }\n\n [part='container'] {\n display: grid;\n grid-template-areas:\n 'drags drops'\n 'message message';\n grid-template-columns: minmax(0, 1fr) minmax(0, 1fr);\n align-items: start;\n gap: 0.5rem;\n }\n\n slot[part~='drags'] {\n grid-area: drags;\n }\n\n [part='drops'] {\n grid-area: drops;\n }\n\n [part='message'] {\n grid-area: message;\n width: 100%;\n justify-self: start;\n }\n\n /*\n * The PLATFORM DEFAULT for container positioning, when the orientation is horizontal.\n *\n * Read that carefully, because the two things are separate axes in QTI 3 and this rule does not\n * merge them. Vocabulary §1.2.9.3 defines qti-choices-* as where the choices container sits\n * relative to the order-target container; orientation is how items flow WITHIN a container.\n * They compose: §1.2.9.2 Figure 73 is orientation=\"vertical\" class=\"qti-choices-left\" and\n * renders two COLUMNS SIDE BY SIDE — vertical does not stack the containers, and horizontal does\n * not imply that it should.\n *\n * What makes this rule legitimate is that §1.2.9.3 declines to specify the positioning at all\n * when no class is given: \"In the absence of choices | order target container positioning,\n * delivery systems should render platform defaults.\" That default is ours, and for a horizontal\n * flow the useful one is stacked, because a row needs the width. An author who wants something\n * else says so with qti-choices-*, which is exactly what the spec provides it for — and those\n * rules below still win (see the source-order note).\n *\n * Side by side used to work here anyway, but only because a slot could be narrower\n * than the chip standing in it: the theme gave a placed chip width: 100%, so a 218px chip was\n * squeezed into a 184px track and three of them fitted in half the width. That squeeze is gone\n * (DROP-SIZING.md §5), and without it \"van links naar rechts\" collapsed to a single column,\n * because 384px cannot hold two 218px chips.\n *\n * Measured on ITEM013: side by side gives the slots 384px and one 384px track; stacked gives them\n * 800px and three 256px tracks, each wider than the chip. Vertical is untouched — one column is\n * what it wants, and the split suits it.\n *\n * Deliberately BEFORE the qti-choices-* rules below, not after. Those tie on specificity, so\n * source order decides: an author who writes qti-choices-left still gets it, and this is only the\n * default for an orientation that has no such class.\n */\n :host([orientation='horizontal']) [part='container'],\n :host(.qti-orientation-horizontal) [part='container'] {\n grid-template-areas:\n 'drags'\n 'drops'\n 'message';\n grid-template-columns: minmax(0, 1fr);\n }\n\n :host(.qti-choices-top) [part='container'] {\n grid-template-areas:\n 'drags'\n 'drops'\n 'message';\n grid-template-columns: minmax(0, 1fr);\n }\n\n :host(.qti-choices-bottom) [part='container'] {\n grid-template-areas:\n 'drops'\n 'drags'\n 'message';\n grid-template-columns: minmax(0, 1fr);\n }\n\n :host(.qti-choices-left) [part='container'] {\n grid-template-areas:\n 'drags drops'\n 'message message';\n grid-template-columns: minmax(0, 1fr) minmax(0, 1fr);\n }\n\n :host(.qti-choices-right) [part='container'] {\n grid-template-areas:\n 'drops drags'\n 'message message';\n grid-template-columns: minmax(0, 1fr) minmax(0, 1fr);\n }\n\n /* An answer key shows the answer, not the bank you would have dragged it from. The attribute is\n set on the clone by the correct-response mixin; the theme used to do this with a\n '.full-correct-response' descendant selector, from the document. */\n :host([answer-key]) [part~='drags'] {\n display: none;\n }\n `\n];\n","import { html } from 'lit';\nimport { repeat } from 'lit/directives/repeat.js';\nimport { property, state } from 'lit/decorators.js';\n\nimport { Interaction } from '@qti-components/base';\nimport {\n DragDropSlottedMixin,\n DragDropSlottedSortableMixin\n} from '@qti-components/interactions-core/mixins/drag-drop-observables';\n\nimport styles from './qti-order-interaction.styles';\n\nimport type { PropertyValueMap } from 'lit';\n\nconst SlottedBase = DragDropSlottedMixin(Interaction, `qti-simple-choice`, `[part~='drop']`, `slot[part~='drags']`);\n\n/**\n * Order interaction: candidates arrange choices into a target sequence.\n *\n * @customElement qti-order-interaction\n *\n * @attr {string} response-identifier - Required. Identifier of the bound response variable.\n * @attr {'horizontal'|'vertical'} [orientation=vertical] - Layout direction of the drop\n * sequence. Unlike on `qti-choice-interaction`, QTI does not deprecate this for order.\n * @attr {boolean} [shuffle=false] - Requests choice shuffling. Applied by the transform\n * pipeline (`qti-transformers`), not by this element.\n * @attr {number} [min-associations=1] - Non-QTI vocabulary inherited from the drag-drop\n * mixin; currently the only way to set the lower bound. QTI spells this `min-choices`.\n * @attr {number} [max-associations=0] - Non-QTI vocabulary inherited from the drag-drop\n * mixin; currently the only way to set the upper bound. QTI spells this `max-choices`.\n * @attr {number} min-choices - Not implemented. The QTI-correct spelling of the lower bound.\n * See plans/interaction-attribute-spec-conformance.md.\n * @attr {number} max-choices - Not implemented. The QTI-correct spelling of the upper bound.\n * See plans/interaction-attribute-spec-conformance.md.\n * @attr {boolean} [auto-size-dropzones=true] - Extension, not QTI. Sizes every drop target to\n * the widest chip so placement does not reflow the layout. On by default: an order slot is a\n * socket cut to one chip, and both axes are measured (see DROP-SIZING.md).\n * @attr {boolean} [disable-animations=false] - Extension, not QTI. Disables the FLIP move\n * animation.\n *\n * @slot prompt - The prompt shown above the interaction.\n * @slot drags - The draggable choice sources.\n *\n * @csspart container - The outer container wrapping drags and drops.\n * @csspart drags - Wrapper around the drag sources slot.\n * @csspart drops - The drop-target region.\n * @csspart drop - Each individual drop target.\n * @csspart drag - A choice that has been placed into a drop target.\n */\nexport class QtiOrderInteraction extends DragDropSlottedSortableMixin(SlottedBase, '[qti-draggable=\"true\"]') {\n static override styles = styles;\n protected childrenMap: Element[];\n\n @state() protected nrChoices: number = 0;\n\n /** orientation of choices */\n @property({ type: String })\n public orientation: 'horizontal' | 'vertical';\n\n override render() {\n const choices = Array.from(this.querySelectorAll('qti-simple-choice'));\n if (this.nrChoices < choices.length) {\n this.nrChoices = choices.length;\n }\n\n return html` <slot name=\"prompt\"> </slot>\n <div part=\"container\">\n <slot part=\"drags\"> </slot>\n <div part=\"drops\">\n ${[...Array(this.nrChoices)].map((_, i) => {\n const identifier = `droplist${i}`;\n // The chips are rendered here, from the interaction's placement map, rather than being\n // appended into this div by handleDrop. `data-declarative-drops` is what tells the\n // mixin to keep them in the map and leave this element's children alone.\n const drags = this._dragDrop?.nodesByTarget?.[identifier] ?? [];\n return html`<div role=\"region\" part=\"drop\" data-declarative-drops identifier=${identifier}>\n ${repeat(\n drags,\n node => node.getAttribute('identifier'),\n node => node\n )}\n </div>`;\n })}\n </div>\n <div id=\"validation-message\" part=\"message\" role=\"alert\" style=\"display:none;\"></div>\n </div>`;\n }\n\n // some interactions have a different way of getting the response\n // this is called from the drag and drop mixin class\n // you have to implement your own getResponse method in the superclass\n // cause they are different for some interactions.\n getValue(val: string[]) {\n return val?.map((v, i) => `${v} droplist${i}`) || [];\n }\n\n // some interactions have a different way of getting the response\n // this is called from the drag and drop mixin class\n // you have to implement your own getResponse method in the superclass\n // cause they are different for some interactions.\n // MH: is this function called? Shouldn't we use getValue?\n protected getResponse(): string[] {\n const droppables = Array.from<HTMLElement>(this.shadowRoot.querySelectorAll(`[part~='drop']`));\n\n // Read placement, not the DOM. The DOM is rendered *from* placement now, so querying it back\n // out would be asking the same question twice and hoping for the same answer.\n return droppables.map(droppable =>\n this.chipsIn(droppable)\n .map(chip => chip.getAttribute('identifier'))\n .join(' ')\n );\n }\n\n public override shouldTreatBlockedMaxAsInvalid(): boolean {\n return false;\n }\n\n override async firstUpdated() {\n super.firstUpdated();\n this.childrenMap = Array.from(this.querySelectorAll('qti-simple-choice'));\n // `part=\"drag\"` used to be stamped on the light-DOM originals here, purely so the clone would\n // inherit it — a slotted chip's own `part` is unreachable. The mixin stamps the clone directly\n // now, at the moment it makes it.\n }\n}\n\ndeclare global {\n interface HTMLElementTagNameMap {\n 'qti-order-interaction': QtiOrderInteraction;\n }\n}\n","import { css } from 'lit';\n\nimport { boxSizing } from '@qti-components/base';\n// import componentStyles from '../../utilities/styles/component.styles';\n\n/* ${componentStyles} */\nexport default [\n boxSizing,\n css`\n :host {\n display: block;\n width: 100%;\n min-height: 50px;\n }\n\n ::slotted(qti-interaction-markup) {\n display: none;\n }\n `\n];\n","import { css, html } from 'lit';\nimport { property, state } from 'lit/decorators.js';\nimport { consume } from '@lit/context';\n\nimport {\n Interaction,\n itemContext,\n qtiContext,\n removeDoubleSlashes,\n responseAttributeConverter\n} from '@qti-components/base';\n\nimport styles from './qti-portable-custom-interaction.styles';\n\nimport type { CSSResultGroup } from 'lit';\nimport type { BaseType, Cardinality, ItemContext, QtiContext } from '@qti-components/base';\nimport type {\n PciInteractionStatus,\n PciResponseDeclaration,\n QtiRecordItem,\n QtiVariableJSON,\n ResponseVariableType\n} from './interface';\n\n/** Statuses in which the item is showing the correct response, so a PCI may legitimately see it. */\nconst STATUSES_SHOWING_CORRECT_RESPONSE: PciInteractionStatus[] = ['solution', 'review'];\n\n/**\n * Whether a response variable actually declares a correct response.\n *\n * Non-single cardinality yields `[]` for an empty `<qti-correct-response>`, which is \"no correct\n * response\" and must not be reported as one.\n */\nfunction hasCorrectResponseValue(value: string | string[] | null | undefined): boolean {\n if (value === null || value === undefined) return false;\n return Array.isArray(value) ? value.length > 0 : value !== '';\n}\n\nexport class QtiPortableCustomInteraction extends Interaction {\n #value: string | string[];\n\n protected _iframeLoaded = false;\n protected _interactionReady = false;\n protected _pendingMessages: Array<{ method: string; params: any }> = [];\n protected iframe: HTMLIFrameElement;\n protected _iframeMessageOrigin: string | null = null;\n\n // This implementation always renders inside an iframe.\n static override styles: CSSResultGroup = [\n styles,\n css`\n :host {\n display: block;\n width: 100%;\n min-height: 50px;\n }\n `\n ];\n\n @property({ type: String, attribute: 'module' })\n module: string;\n\n @property({ type: String, attribute: 'custom-interaction-type-identifier' })\n customInteractionTypeIdentifier: string;\n\n @property({ type: String, attribute: 'data-require-paths' })\n requirePathsJson: string = '';\n\n @property({ type: String, attribute: 'data-require-shim' })\n requireShimJson: string = '';\n\n @property({ type: String, attribute: 'data-require-js-url' })\n requireJsUrl: string = 'https://cdnjs.cloudflare.com/ajax/libs/require.js/2.3.6/require.min.js';\n\n @property({ type: String, attribute: 'data-base-url' })\n baseUrl: string = '';\n\n @property({ type: Boolean, attribute: 'data-use-default-paths' })\n useDefaultPaths = false;\n\n /**\n * Item lifecycle status handed to the PCI in its `getInstance` configuration.\n * A delivery engine sets `solution` to let a PCI render the correct response.\n */\n @property({ type: String, attribute: 'data-status' })\n status: PciInteractionStatus = 'interacting';\n\n #responseDeclaration: PciResponseDeclaration | null = null;\n\n /**\n * Response declaration passed into the PCI configuration, so a PCI can render\n * the correct response itself instead of having it pushed in as a response.\n *\n * Derived from the item context, unless a host sets it explicitly - the\n * correct response viewer does, since it has no response declaration of its own.\n *\n * See https://github.com/1EdTech/qti-project-management/issues/210\n */\n set responseDeclaration(declaration: PciResponseDeclaration | null) {\n this.#responseDeclaration = declaration;\n }\n\n get responseDeclaration(): PciResponseDeclaration | null {\n if (this.#responseDeclaration) {\n return this.#responseDeclaration;\n }\n\n const variable = this.responseVariable;\n if (!variable) {\n return null;\n }\n\n const declaration: PciResponseDeclaration = {\n baseType: variable.baseType,\n cardinality: variable.cardinality\n };\n\n const correctResponse = variable.correctResponse;\n if (hasCorrectResponseValue(correctResponse)) {\n declaration.correctResponse = { value: correctResponse };\n }\n\n return declaration;\n }\n\n /**\n * The declaration as it goes into the PCI configuration.\n *\n * `correctResponse` is withheld unless the item is actually showing a solution. A PCI is\n * third-party code running in an iframe, and there is no reason for it to hold the answer key\n * while the candidate is still working - the use case this field exists for only applies once\n * the status says the correct response is being shown.\n *\n * The filter sits here rather than in the `responseDeclaration` getter so it also covers a\n * declaration a host set explicitly, not just the one derived from the item context.\n */\n #responseDeclarationForStatus(): PciResponseDeclaration | null {\n const declaration = this.responseDeclaration;\n if (!declaration?.correctResponse) {\n return declaration;\n }\n if (STATUSES_SHOWING_CORRECT_RESPONSE.includes(this.status)) {\n return declaration;\n }\n\n const { correctResponse: _withheld, ...rest } = declaration;\n return rest;\n }\n\n @state()\n private _errorMessage: string = null;\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 @property({ attribute: 'response', reflect: false, converter: responseAttributeConverter({ emptyAs: null }) })\n response: string | string[] | null = null;\n\n #parsedRequirePaths: Record<string, string | string[]> = null;\n #parsedRequireShim: Record<string, any> = null;\n #pciValidity: boolean | null = null;\n #pciCustomValidityMessage = '';\n\n /**\n * Parse the require paths JSON string into an object\n */\n #getRequirePaths(): Record<string, string | string[]> {\n if (this.#parsedRequirePaths === null && this.requirePathsJson) {\n try {\n const parsedJson = JSON.parse(this.requirePathsJson);\n if (Array.isArray(parsedJson) || !parsedJson || typeof parsedJson !== 'object') {\n throw new Error('Require paths must be a JSON object.');\n }\n this.#parsedRequirePaths = parsedJson;\n } catch (e) {\n console.error('Error parsing require paths JSON:', e);\n this._errorMessage = `Error parsing require paths JSON: ${e.message}`;\n this.#parsedRequirePaths = {};\n }\n }\n return this.#parsedRequirePaths || {};\n }\n\n /**\n * Parse the require shim JSON string into an object\n */\n #getRequireShim(): Record<string, any> {\n if (this.#parsedRequireShim === null && this.requireShimJson) {\n try {\n this.#parsedRequireShim = JSON.parse(this.requireShimJson);\n } catch (e) {\n console.error('Error parsing require shim JSON:', e);\n this._errorMessage = `Error parsing require shim JSON: ${e.message}`;\n this.#parsedRequireShim = {};\n }\n }\n return this.#parsedRequireShim || {};\n }\n\n /**\n * Get the final require paths by combining defaults with user-provided paths\n */\n #getFinalRequirePaths(): Record<string, string | string[]> {\n // Return only user-provided paths to keep PCI completely self-contained\n return this.#getRequirePaths();\n }\n\n /**\n * Get the final require shim\n */\n #getFinalRequireShim(): Record<string, any> {\n return this.#getRequireShim();\n }\n\n /**\n * Converts QtiVariableJSON to a string or string array\n */\n #convertQtiVariableJSON(input: QtiVariableJSON): string | string[] {\n for (const topLevelKey in input) {\n // eslint-disable-next-line no-prototype-builtins\n if (input.hasOwnProperty(topLevelKey)) {\n const nestedObject = input[topLevelKey as 'list' | 'base'];\n if (nestedObject) {\n for (const nestedKey in nestedObject) {\n // eslint-disable-next-line no-prototype-builtins\n if (nestedObject.hasOwnProperty(nestedKey)) {\n const value = nestedObject[nestedKey as keyof typeof nestedObject];\n if (Array.isArray(value)) {\n return value.map(String); // Convert each element in the array to string\n } else if (value !== undefined && value !== null) {\n return String(value); // Convert the single value to string\n }\n }\n }\n }\n }\n }\n return null;\n }\n\n /**\n * Get direct child elements by tag name\n */\n private getDirectChildrenByTag(tagName: string): Element[] {\n const needle = tagName.toLowerCase();\n return Array.from(this.children).filter(child => child.tagName.toLowerCase() === needle);\n }\n\n /**\n * Coerce a scalar value to the expected base-type when possible\n */\n private coerceBaseValue(value: unknown, baseType: BaseType): unknown {\n if (value === null || value === undefined) return value;\n\n switch (baseType) {\n case 'integer': {\n if (typeof value === 'number') return value;\n const parsed = parseInt(String(value), 10);\n return Number.isNaN(parsed) ? value : parsed;\n }\n case 'float':\n case 'duration': {\n if (typeof value === 'number') return value;\n const parsed = parseFloat(String(value));\n return Number.isNaN(parsed) ? value : parsed;\n }\n case 'boolean': {\n if (typeof value === 'boolean') return value;\n if (typeof value === 'string') {\n const lowered = value.toLowerCase();\n if (lowered === 'true') return true;\n if (lowered === 'false') return false;\n }\n return value;\n }\n case 'string':\n case 'identifier':\n default:\n return String(value);\n }\n }\n\n /**\n * Normalize an input into a list form\n */\n private normalizeListValue(value: unknown): unknown[] {\n if (value === null || value === undefined) return [];\n return Array.isArray(value) ? value : [value];\n }\n\n /**\n * Convert a variable value to QtiVariableJSON\n */\n private variableToQtiVariableJSON(value: unknown, cardinality: Cardinality, baseType: BaseType): QtiVariableJSON {\n if (cardinality === 'record' || baseType === 'record') {\n return this.recordToQtiVariableJSON(value);\n }\n\n if (cardinality !== 'single') {\n const listValues = this.normalizeListValue(value).map(v => this.coerceBaseValue(v, baseType));\n return { list: { [baseType]: listValues } };\n }\n\n return { base: { [baseType]: this.coerceBaseValue(value, baseType) } };\n }\n\n /**\n * Convert a record object into QtiVariableJSON\n */\n private recordToQtiVariableJSON(value: unknown): QtiVariableJSON {\n if (!value || typeof value !== 'object') {\n return { record: [] };\n }\n\n const recordEntries: QtiRecordItem[] = [];\n for (const [name, entryValue] of Object.entries(value as Record<string, unknown>)) {\n recordEntries.push(this.recordEntryFromValue(name, entryValue));\n }\n\n return { record: recordEntries };\n }\n\n /**\n * Build a record entry from an arbitrary value\n */\n private recordEntryFromValue(name: string, entryValue: unknown): QtiRecordItem {\n if (Array.isArray(entryValue)) {\n const filtered = entryValue.filter(v => v !== null && v !== undefined);\n\n if (filtered.length && filtered.every(v => typeof v === 'boolean')) {\n return { name, list: { boolean: filtered as boolean[] } };\n }\n\n if (filtered.length && filtered.every(v => typeof v === 'number')) {\n const numbers = filtered as number[];\n const isIntegers = numbers.every(n => Number.isInteger(n));\n return { name, list: { [isIntegers ? 'integer' : 'float']: numbers } };\n }\n\n return { name, list: { string: entryValue.map(v => (v === null || v === undefined ? '' : String(v))) } };\n }\n\n if (typeof entryValue === 'boolean') {\n return { name, base: { boolean: entryValue } };\n }\n\n if (typeof entryValue === 'number') {\n if (Number.isInteger(entryValue)) return { name, base: { integer: entryValue } };\n return { name, base: { float: entryValue } };\n }\n\n if (entryValue === null || entryValue === undefined) {\n return { name, base: { string: '' } };\n }\n\n if (typeof entryValue === 'object') {\n try {\n return { name, base: { string: JSON.stringify(entryValue) } };\n } catch {\n return { name, base: { string: String(entryValue) } };\n }\n }\n\n return { name, base: { string: String(entryValue) } };\n }\n\n /**\n * Extract default QTI_CONTEXT values from qti-context-declaration elements\n */\n private getQtiContextDefaultsFromItem(): Record<string, unknown> {\n const itemElement = this.closest('qti-assessment-item');\n if (!itemElement) return {};\n\n const defaults: Record<string, unknown> = {};\n const contextDeclarations = itemElement.querySelectorAll('qti-context-declaration[identifier=\"QTI_CONTEXT\"]');\n\n contextDeclarations.forEach(declaration => {\n const defaultValueElement = declaration.querySelector('qti-default-value');\n if (!defaultValueElement) return;\n\n const valueElements = defaultValueElement.querySelectorAll('qti-value[field-identifier]');\n valueElements.forEach(valueElement => {\n const fieldIdentifier = valueElement.getAttribute('field-identifier');\n if (!fieldIdentifier) return;\n\n const baseType = (valueElement.getAttribute('base-type') || 'string') as BaseType;\n const textContent = valueElement.textContent?.trim() || '';\n defaults[fieldIdentifier] = this.coerceBaseValue(textContent, baseType);\n });\n });\n\n return defaults;\n }\n\n /**\n * Build a QTI_CONTEXT record for PCI consumption\n */\n private getQtiContextRecord(): QtiVariableJSON | null {\n const defaults = this.getQtiContextDefaultsFromItem();\n const runtime = this.qtiContext?.QTI_CONTEXT || {};\n const merged: Record<string, unknown> = { ...defaults, ...runtime };\n if (!Object.keys(merged).length) return null;\n\n const normalized = {\n candidateIdentifier: merged.candidateIdentifier ?? '',\n testIdentifier: merged.testIdentifier ?? '',\n environmentIdentifier: merged.environmentIdentifier ?? '',\n ...merged\n };\n\n return this.recordToQtiVariableJSON(normalized);\n }\n\n /**\n * Collect template variables referenced by qti-template-variable children\n */\n private getTemplateVariables(): Record<string, QtiVariableJSON> {\n const templateVariables: Record<string, QtiVariableJSON> = {};\n const templateVariableElements = this.getDirectChildrenByTag('qti-template-variable');\n if (!templateVariableElements.length) return templateVariables;\n\n templateVariableElements.forEach(el => {\n const identifier = el.getAttribute('template-identifier') || el.getAttribute('identifier') || '';\n if (!identifier) return;\n\n const variable = this.context?.variables?.find(v => v.identifier === identifier);\n if (!variable) return;\n\n const cardinality = (variable.cardinality || 'single') as Cardinality;\n const baseType = (variable.baseType || 'string') as BaseType;\n templateVariables[identifier] = this.variableToQtiVariableJSON(variable.value, cardinality, baseType);\n });\n\n return templateVariables;\n }\n\n /**\n * Collect context variables referenced by qti-context-variable children\n */\n private getContextVariables(): Record<string, QtiVariableJSON> {\n const contextVariables: Record<string, QtiVariableJSON> = {};\n const contextVariableElements = this.getDirectChildrenByTag('qti-context-variable');\n if (!contextVariableElements.length) return contextVariables;\n\n contextVariableElements.forEach(el => {\n const identifier = el.getAttribute('identifier') || '';\n if (!identifier) return;\n\n if (identifier === 'QTI_CONTEXT') {\n const record = this.getQtiContextRecord();\n if (record) contextVariables[identifier] = record;\n return;\n }\n\n const variable = this.context?.variables?.find(v => v.identifier === identifier);\n if (!variable) return;\n\n const cardinality = (variable.cardinality || 'single') as Cardinality;\n const baseType = (variable.baseType || 'string') as BaseType;\n contextVariables[identifier] = this.variableToQtiVariableJSON(variable.value, cardinality, baseType);\n });\n\n return contextVariables;\n }\n\n /**\n * Adds hyphenated versions of camelCase keys to properties object\n */\n #addHyphenatedKeys(properties: Record<string, any>): Record<string, any> {\n const updatedProperties = { ...properties };\n\n for (const key in properties) {\n if (Object.prototype.hasOwnProperty.call(properties, key)) {\n const hyphenatedKey = key.replace(/[A-Z]/g, char => `-${char.toLowerCase()}`);\n updatedProperties[hyphenatedKey] = properties[key];\n }\n }\n\n return updatedProperties;\n }\n\n #toNestedProperties(properties: Record<string, any>): Record<string, any> {\n const nestedProperties = { ...properties };\n\n const setNestedValue = (root: Record<string, any>, path: string[], value: any): void => {\n let cursor = root;\n\n for (let i = 0; i < path.length; i += 1) {\n const segment = path[i];\n const isLast = i === path.length - 1;\n\n if (isLast) {\n cursor[segment] = value;\n return;\n }\n\n if (!cursor[segment] || typeof cursor[segment] !== 'object' || Array.isArray(cursor[segment])) {\n cursor[segment] = {};\n }\n\n cursor = cursor[segment];\n }\n };\n\n for (const [key, value] of Object.entries(properties)) {\n if (!key.includes('__')) continue;\n const path = key.split('__').filter(Boolean);\n if (path.length < 2) continue;\n setNestedValue(nestedProperties, path, value);\n }\n\n return nestedProperties;\n }\n\n /**\n * Converts response variables to QtiVariableJSON\n */\n protected responseVariablesToQtiVariableJSON(\n input: string | string[],\n cardinality: Cardinality,\n baseType: BaseType\n ): QtiVariableJSON {\n if (cardinality !== 'single') {\n const list = { list: {} };\n list.list[baseType] = input;\n return list;\n } else {\n const base = { base: {} };\n base.base[baseType] = input;\n return base;\n }\n }\n\n #hasNonEmptyResponse(): boolean {\n if (this.response === null || this.response === undefined) return false;\n if (Array.isArray(this.response)) {\n if (this.response.length === 0) return false;\n return this.response.some(v => v !== '' && v !== null && v !== undefined);\n }\n return this.response !== '';\n }\n\n #setInteractionValidity(isValid: boolean, customMessage?: string): void {\n const fallbackMessage = this.dataset.invalidresponsemessage || 'Invalid response.';\n const message = isValid ? '' : customMessage && customMessage.trim().length > 0 ? customMessage : fallbackMessage;\n this._internals.setValidity(isValid ? {} : { customError: true }, message);\n }\n\n validate(): boolean {\n const isValid = typeof this.#pciValidity === 'boolean' ? this.#pciValidity : this.#hasNonEmptyResponse();\n this.#setInteractionValidity(isValid, this.#pciCustomValidityMessage);\n return isValid;\n }\n\n override set value(v: string | null) {\n if (v === null) {\n this.#value = [];\n } else {\n this.#value = Array.isArray(v) ? v : v.split(',');\n }\n // PCI handles response setting via boundTo property during initialization\n // No need to call setResponse directly\n }\n\n override get value(): string | null {\n if (this.#value === null || this.#value === undefined) return null;\n return Array.isArray(this.#value) ? this.#value.join(',') : String(this.#value);\n }\n\n set boundTo(newValue: Record<string, ResponseVariableType>) {\n if (!newValue || !newValue[this.responseIdentifier]) {\n return;\n }\n\n const value = this.#convertQtiVariableJSON(newValue[this.responseIdentifier]);\n this.#value = value;\n\n // No direct call to setResponse - PCI will handle this during initialization\n // through the boundTo property in the config\n\n this.saveResponse(value);\n }\n\n get boundTo(): Record<string, QtiVariableJSON> {\n const responseVariable: Record<string, QtiVariableJSON> = {};\n const variable = this.context?.variables?.find(v => v.identifier === this.responseIdentifier);\n if (variable) {\n const cardinality =\n this.context?.variables?.find(v => v.identifier === this.responseIdentifier)?.cardinality || 'single';\n const baseType =\n this.context?.variables?.find(v => v.identifier === this.responseIdentifier)?.baseType || 'string';\n const value = this.context?.variables?.find(v => v.identifier === this.responseIdentifier)?.value || null;\n const responseVal = this.responseVariablesToQtiVariableJSON(value as string | string[], cardinality, baseType);\n responseVariable[this.responseIdentifier] = responseVal;\n }\n\n return responseVariable;\n }\n\n /**\n * Unescape HTML entities in a string\n */\n #unescapeHtml(str: string): string {\n if (!str) return str;\n\n return str\n .replace(/&/g, '&')\n .replace(/</g, '<')\n .replace(/>/g, '>')\n .replace(/"/g, '\"')\n .replace(/'/g, \"'\")\n .replace(///g, '/')\n .replace(/`/g, '`')\n .replace(/=/g, '=');\n }\n\n /**\n * Unescape HTML entities in all values of an object\n */\n #unescapeDataAttributes(obj: Record<string, any>): Record<string, any> {\n const unescaped: Record<string, any> = {};\n\n for (const [key, value] of Object.entries(obj)) {\n if (typeof value === 'string') {\n unescaped[key] = this.#unescapeHtml(value);\n } else {\n unescaped[key] = value;\n }\n }\n\n return unescaped;\n }\n\n override disconnectedCallback(): void {\n super.disconnectedCallback();\n window.removeEventListener('message', this.handleIframeMessage);\n }\n\n /**\n * IFRAME MODE: Send message to iframe\n */\n protected sendMessageToIframe(method: string, params: any) {\n const targetWindow = this.iframe?.contentWindow;\n if (!this._iframeLoaded || !targetWindow) {\n this._pendingMessages.push({ method, params });\n return;\n }\n targetWindow.postMessage(\n {\n source: 'qti-portable-custom-interaction',\n responseIdentifier: this.responseIdentifier,\n method,\n params\n },\n '*'\n );\n }\n\n /**\n * IFRAME MODE: Process pending messages\n */\n #processPendingMessages() {\n if (this._pendingMessages.length) {\n this._pendingMessages.forEach(message => {\n this.sendMessageToIframe(message.method, message.params);\n });\n this._pendingMessages = [];\n }\n }\n\n /**\n * IFRAME MODE: Handle iframe messages\n */\n protected handleIframeMessage = (event: MessageEvent) => {\n const { data } = event;\n // Ensure the message is from our iframe\n if (!data || data.source !== 'qti-pci-iframe') {\n return;\n }\n if (!this.iframe?.contentWindow || event.source !== this.iframe.contentWindow) {\n return;\n }\n if (data.responseIdentifier && data.responseIdentifier !== this.responseIdentifier) {\n return;\n }\n if (this._iframeMessageOrigin === null) {\n this._iframeMessageOrigin = event.origin;\n } else if (event.origin !== this._iframeMessageOrigin) {\n return;\n }\n switch (data.method) {\n case 'iframeReady':\n this._interactionReady = true;\n this.#initializeInteraction();\n this.#processPendingMessages();\n this.dispatchEvent(\n new CustomEvent('qti-portable-custom-interaction-loaded', {\n bubbles: true\n })\n );\n break;\n\n case 'resize':\n if (typeof data.height === 'number' && this.iframe) {\n this.iframe.style.height = `${data.height}px`;\n this.iframe.style.width = `${data.width}px`;\n }\n break;\n case 'console':\n this.dispatchEvent(\n new CustomEvent('qti-pci-console', {\n detail: {\n level: data.level,\n args: data.args\n },\n bubbles: true\n })\n );\n break;\n\n case 'interactionChanged': {\n const raw = data?.params?.value;\n const converted = raw && typeof raw === 'object' ? this.#convertQtiVariableJSON(raw as QtiVariableJSON) : null;\n const pciValid = typeof data?.params?.valid === 'boolean' ? (data.params.valid as boolean) : null;\n const pciCustomValidity =\n typeof data?.params?.customValidity === 'string' ? (data.params.customValidity as string) : null;\n if (pciValid !== null) {\n this.#pciValidity = pciValid;\n if (pciValid && pciCustomValidity === null) {\n this.#pciCustomValidityMessage = '';\n }\n }\n if (pciCustomValidity !== null) {\n this.#pciCustomValidityMessage = pciCustomValidity;\n }\n // PCI state \"should\" be an opaque string, but a lot of existing PCIs (including the\n // IMS conformance examples) return a structured object from getState().\n //\n // We store a string in itemContext.state, so we serialize non-string states with a\n // prefix to safely round-trip them without accidentally parsing user-provided strings.\n const stateRaw = data?.params?.state as unknown;\n let state: string | null | undefined;\n if (stateRaw === undefined) {\n state = undefined;\n } else if (stateRaw === null) {\n state = null;\n } else if (typeof stateRaw === 'string') {\n state = stateRaw;\n } else {\n try {\n state = `__qti_json__::${JSON.stringify(stateRaw)}`;\n } catch {\n state = null;\n }\n }\n\n // Treat null/undefined or unconvertible responses as \"cleared\".\n // The iframe side is responsible for not emitting an initial clear on load.\n if (converted === null) {\n const emptyResponse = this.responseVariable?.cardinality === 'single' ? '' : [];\n this.response = emptyResponse;\n this.validate();\n this.saveResponse(emptyResponse, state);\n break;\n }\n\n this.response = converted;\n this.validate();\n this.saveResponse(converted, state);\n break;\n }\n case 'error':\n this._errorMessage = data.params.message;\n console.error('Error from PCI iframe:', data.params.message);\n break;\n }\n };\n\n /**\n * IFRAME MODE: Create iframe element\n */\n protected createIframe() {\n this._interactionReady = false;\n this.iframe = document.createElement('iframe');\n this.iframe.id = `pci-iframe-${this.responseIdentifier}`;\n this.iframe.setAttribute('title', 'QTI PCI Iframe');\n this.iframe.setAttribute('aria-label', 'QTI PCI Iframe');\n this.iframe.setAttribute('aria-hidden', 'false');\n this.iframe.setAttribute('role', 'application');\n this.iframe.style.width = '100%';\n this.iframe.style.border = 'none';\n this.iframe.style.display = 'block';\n\n // Handle iframe load event\n this.iframe.onload = () => {\n this._iframeLoaded = true;\n this.#addMarkupToIframe();\n // Send initialization data to iframe\n this.#sendIframeInitData();\n };\n\n // Create a unique name for the iframe\n const iframeName = `qti-pci-${this.responseIdentifier}-${Date.now()}`;\n this.iframe.name = iframeName;\n\n // Generate iframe HTML content with all required scripts\n const iframeContent = this.generateIframeContent();\n\n // Use `srcdoc` rather than a `blob:` (or `data:`) URL. Both of those give the iframe document\n // a URL that is out of scope for any http(s) Service Worker registration, so a player that\n // serves package resources through a Service Worker (CacheStorage, virtual paths) would see\n // every request made from inside the PCI - module scripts, images, media, stylesheets, fetches -\n // bypass it and hit the network instead. An `srcdoc` frame inherits this document's URL and\n // stays controlled by the same Service Worker. It is same-origin either way, and messages are\n // posted with a `'*'` target origin, so nothing about postMessage changes.\n this.iframe.srcdoc = iframeContent;\n\n // Append iframe to component\n this.appendChild(this.iframe);\n }\n\n /**\n * IFRAME MODE: Send initialization data to iframe\n */\n #sendIframeInitData() {\n // Once iframe is loaded, send initialization data\n const properties = this.#addHyphenatedKeys(\n this.#toNestedProperties(this.#unescapeDataAttributes({ ...this.dataset }))\n );\n const storedStateRaw = this.context?.state?.[this.responseIdentifier];\n const storedState = typeof storedStateRaw === 'string' && storedStateRaw.length > 0 ? storedStateRaw : null;\n const initData = {\n module: this.module,\n customInteractionTypeIdentifier: this.customInteractionTypeIdentifier,\n baseUrl: !this.baseUrl\n ? window.location.origin\n : this.baseUrl.startsWith('http') || this.baseUrl.startsWith('blob') || this.baseUrl.startsWith('base64')\n ? this.baseUrl\n : removeDoubleSlashes(`${window.location.origin}${this.baseUrl}`),\n responseIdentifier: this.responseIdentifier,\n properties,\n contextVariables: this.getContextVariables(),\n templateVariables: this.getTemplateVariables(),\n dataAttributes: { ...this.dataset },\n interactionModules: this.#getInteractionModules(),\n boundTo: storedState ? null : this.boundTo,\n responseDeclaration: this.#responseDeclarationForStatus(),\n status: this.status,\n state: storedState\n };\n\n this.sendMessageToIframe('initialize', initData);\n }\n\n /**\n * IFRAME MODE: Get interaction modules from DOM\n */\n #getInteractionModules() {\n const modules = [];\n const interactionModules = this.querySelector('qti-interaction-modules');\n\n if (interactionModules) {\n const moduleElements = interactionModules.querySelectorAll('qti-interaction-module');\n for (const module of moduleElements) {\n modules.push({\n id: module.getAttribute('id'),\n primaryPath: module.getAttribute('primary-path'),\n fallbackPath: module.getAttribute('fallback-path')\n });\n }\n }\n\n return modules;\n }\n\n /**\n * IFRAME MODE: Add markup, stylesheets, and properties to iframe\n */\n #addMarkupToIframe() {\n // Get interaction markup if any\n const markup = this.querySelector('qti-interaction-markup');\n if (markup) {\n this.sendMessageToIframe('setMarkup', markup.innerHTML);\n }\n\n const stylesheets = Array.from(this.querySelectorAll('qti-stylesheet'));\n if (stylesheets.length) {\n const stylesheetsHtml = stylesheets.map(sheet => sheet.outerHTML).join('\\n');\n this.sendMessageToIframe('setStylesheets', stylesheetsHtml);\n }\n\n // Get properties if any\n const properties = this.querySelector('properties');\n if (properties) {\n this.sendMessageToIframe('setProperties', properties.innerHTML);\n }\n }\n\n /**\n * IFRAME MODE: Initialize the interaction\n */\n #initializeInteraction() {\n // No explicit action needed, as the PCI will initialize\n // with the boundTo property already provided\n }\n\n override connectedCallback(): void {\n super.connectedCallback();\n this.#pciValidity = null;\n this.#pciCustomValidityMessage = '';\n // Reflect any pre-existing response (e.g. restored session) for validation/completionStatus.\n // Don't clobber a value already set via the `response=\"...\"` attribute.\n const currentResponse = this.response;\n const hasResponse = Array.isArray(currentResponse) ? currentResponse.length > 0 : !!currentResponse;\n if (!hasResponse) {\n this.response = (this.responseVariable?.value as string | string[] | null) ?? null;\n }\n window.addEventListener('message', this.handleIframeMessage);\n this.createIframe();\n }\n\n /**\n * IFRAME MODE: Generate iframe HTML content\n */\n protected generateIframeContent(): string {\n const parentStyles = window.getComputedStyle(document.body);\n\n // Get the configured require paths and shim\n const requirePaths = JSON.stringify(this.#getFinalRequirePaths());\n const requireShim = JSON.stringify(this.#getFinalRequireShim());\n const iframeBaseUrl = this.dataset.baseUrl\n ? this.dataset.baseUrl.startsWith('/')\n ? `${window.location.origin}${this.dataset.baseUrl}`\n : this.dataset.baseUrl\n : '';\n // `data-base-url` names the directory the item was loaded from, so it is also the base every\n // relative URL inside the interaction should resolve against - the markup's `src`/`href`, the\n // stylesheets, and whatever the PCI module resolves itself. Anchoring `<base>` at the site\n // origin instead would send `../assets/x.png` to `/assets/x.png`. Normalise to a trailing\n // slash: without one the last segment counts as a filename and gets dropped.\n const iframeBaseHref = iframeBaseUrl\n ? iframeBaseUrl.endsWith('/')\n ? iframeBaseUrl\n : `${iframeBaseUrl}/`\n : `${window.location.origin}/`;\n const forwardConsole = this.dataset.forwardConsole === 'true';\n const isLocalhost = window.location.hostname === 'localhost' || window.location.hostname === '127.0.0.1';\n const defaultComponentsCdnUrl = isLocalhost\n ? `${window.location.origin}/cdn/index.js`\n : 'https://unpkg.com/@citolab/qti-components/cdn';\n const defaultComponentsCssUrl = isLocalhost\n ? `${window.location.origin}/dist/item.css`\n : 'https://unpkg.com/@citolab/qti-components@latest/dist/item.css';\n const componentsCdnUrl = this.dataset.componentsCdnUrl || defaultComponentsCdnUrl;\n const componentsCssUrl = this.dataset.componentsCssUrl || defaultComponentsCssUrl;\n\n // Extract just the font-related properties you want to copy\n const fontStyles = `\n font-family: ${parentStyles.getPropertyValue('font-family')};\n font-size: ${parentStyles.getPropertyValue('font-size')};\n line-height: ${parentStyles.getPropertyValue('line-height')};\n font-weight: ${parentStyles.getPropertyValue('font-weight')};\n color: ${parentStyles.getPropertyValue('color')};\n `;\n\n return /* html */ `<!DOCTYPE html>\n <html lang=\"en\">\n <head>\n <meta charset=\"utf-8\" />\n <title>QTI PCI Container</title>\n <base href=\"${iframeBaseHref}\" />\n <script type=\"module\">\n import '${componentsCdnUrl}';\n </script>\n <style>\n body, html {\n margin: 0;\n padding: 0;\n width: 100%;\n height: auto;\n overflow: hidden;\n /* Add the extracted font styles here */\n ${fontStyles}\n };\n .qti-customInteraction {\n width: 100%;\n height: 100%;\n }\n #pci-container {\n width: 100%;\n }\n qti-interaction-markup {\n display: block;\n width: 100%;\n min-height: 50px;\n }\n </style>\n <link href=\"${componentsCssUrl}\" rel=\"stylesheet\" />\n <script src=\"${this.requireJsUrl}\"></script>\n <script>\n const forwardConsole = ${forwardConsole ? 'true' : 'false'};\n if (forwardConsole) {\n const originalLog = console.log.bind(console);\n const originalError = console.error.bind(console);\n const stringifyArgs = args =>\n args.map(arg => {\n if (typeof arg === 'string') return arg;\n try {\n return JSON.stringify(arg);\n } catch (e) {\n return String(arg);\n }\n });\n console.log = (...args) => {\n originalLog(...args);\n window.parent.postMessage(\n {\n source: 'qti-pci-iframe',\n responseIdentifier: (window.PCIManager && window.PCIManager.responseIdentifier) || null,\n method: 'console',\n level: 'log',\n args: stringifyArgs(args)\n },\n '*'\n );\n };\n console.error = (...args) => {\n originalError(...args);\n window.parent.postMessage(\n {\n source: 'qti-pci-iframe',\n responseIdentifier: (window.PCIManager && window.PCIManager.responseIdentifier) || null,\n method: 'console',\n level: 'error',\n args: stringifyArgs(args)\n },\n '*'\n );\n };\n }\n // Define standard paths and shims\n window.requirePaths = ${requirePaths};\n\n window.requireShim = ${requireShim};\n\n // Single initial RequireJS configuration with error handling\n window.requirejs.config({\n catchError: true,\n waitSeconds: 30,\n paths: window.requirePaths,\n baseUrl: '${iframeBaseUrl}',\n shim: window.requireShim,\n onNodeCreated: function (node, config, moduleName, url) {\n // Add error handler to script node\n node.addEventListener('error', function (evt) {\n console.error('Script load error for module:', moduleName, 'URL:', url, 'Event:', evt);\n });\n },\n onError: function (err) {\n console.error('RequireJS error:', {\n type: err.requireType,\n modules: err.requireModules,\n error: err\n });\n\n if (err.requireType === 'scripterror') {\n console.error('Script error usually indicates a network or CORS issue with:', err.requireModules);\n }\n\n // Notify parent window about the error\n window.parent.postMessage(\n {\n source: 'qti-pci-iframe',\n responseIdentifier: (window.PCIManager && window.PCIManager.responseIdentifier) || null,\n method: 'error',\n params: {\n message: 'RequireJS ' + err.requireType + ' error for modules: ' + err.requireModules,\n details: {\n type: err.requireType,\n modules: err.requireModules,\n error: err.toString()\n }\n }\n },\n '*'\n );\n }\n });\n\n // PCI Manager for iframe implementation\n window.PCIManager = {\n pciInstance: null,\n pciConfig: null,\n container: null,\n markupEl: null,\n propertiesEl: null,\n customInteractionTypeIdentifier: null,\n responseIdentifier: null,\n pendingBoundTo: null,\n pendingMarkup: null,\n pendingProperties: null,\n pendingState: null,\n pendingStylesheets: null,\n stylesheetKeys: {},\n interactionChangedViaEvent: false,\n eventBridgeAttached: false,\n lastResponseStr: null,\n hadResponse: false,\n\n initialize: function (config) {\n this.customInteractionTypeIdentifier = config.customInteractionTypeIdentifier;\n this.responseIdentifier = config.responseIdentifier;\n this.container = document.getElementById('pci-container');\n this.container.classList.add('qti-customInteraction');\n\n function qtiVariableHasValue(qtiVar) {\n if (!qtiVar) return false;\n if (qtiVar.base) {\n for (const k in qtiVar.base) {\n if (!Object.prototype.hasOwnProperty.call(qtiVar.base, k)) continue;\n const v = qtiVar.base[k];\n if (v !== null && v !== undefined && v !== '') return true;\n }\n }\n if (qtiVar.list) {\n for (const k in qtiVar.list) {\n if (!Object.prototype.hasOwnProperty.call(qtiVar.list, k)) continue;\n const v = qtiVar.list[k];\n if (Array.isArray(v) && v.some(x => x !== null && x !== undefined && x !== '')) return true;\n }\n }\n if (Array.isArray(qtiVar.record) && qtiVar.record.length > 0) return true;\n return false;\n }\n\n const initialBoundTo = config.boundTo && config.boundTo[this.responseIdentifier];\n this.hadResponse = qtiVariableHasValue(initialBoundTo);\n this.lastResponseStr = this.hadResponse ? JSON.stringify(initialBoundTo) : null;\n // Ensure expected DOM structure exists (markup + properties)\n this.markupEl = this.container.querySelector('qti-interaction-markup');\n if (!this.markupEl) {\n this.markupEl = document.createElement('qti-interaction-markup');\n this.container.appendChild(this.markupEl);\n }\n this.markupEl.classList.add('qti-customInteraction');\n this.propertiesEl = this.container.querySelector('properties');\n if (!this.propertiesEl) {\n this.propertiesEl = document.createElement('properties');\n this.propertiesEl.style.display = 'none';\n this.container.appendChild(this.propertiesEl);\n } else {\n this.propertiesEl.style.display = 'none';\n }\n\n // Apply any markup/properties that arrived before initialization\n if (this.pendingMarkup !== null) {\n this.setMarkup(this.pendingMarkup);\n this.pendingMarkup = null;\n }\n if (this.pendingProperties !== null) {\n this.setProperties(this.pendingProperties);\n this.pendingProperties = null;\n }\n if (this.pendingStylesheets !== null) {\n this.setStylesheets(this.pendingStylesheets);\n this.pendingStylesheets = null;\n }\n\n // Bridge qti-interaction-changed events (preferred over polling)\n if (!this.eventBridgeAttached) {\n this.eventBridgeAttached = true;\n const self = this;\n this.container.addEventListener(\n 'qti-interaction-changed',\n function (evt) {\n try {\n self.interactionChangedViaEvent = true;\n const value = evt && evt.detail ? evt.detail.value : undefined;\n if (value !== undefined) {\n const validFromEvent =\n evt && evt.detail && typeof evt.detail.valid === 'boolean' ? evt.detail.valid : undefined;\n let valid = validFromEvent;\n if (valid === undefined && self.pciInstance && typeof self.pciInstance.checkValidity === 'function') {\n try {\n valid = self.pciInstance.checkValidity();\n } catch (e) {\n // Keep undefined on PCI validity read errors.\n }\n }\n const customValidityFromEvent =\n evt && evt.detail && typeof evt.detail.customValidity === 'string'\n ? evt.detail.customValidity\n : undefined;\n let customValidity = customValidityFromEvent;\n if (\n customValidity === undefined &&\n self.pciInstance &&\n typeof self.pciInstance.getCustomValidity === 'function'\n ) {\n try {\n customValidity = self.pciInstance.getCustomValidity();\n } catch (e) {\n // Keep undefined on PCI custom validity read errors.\n }\n }\n const state =\n self.pciInstance && typeof self.pciInstance.getState === 'function'\n ? self.pciInstance.getState()\n : null;\n self.notifyInteractionChanged(value, state, valid, customValidity);\n }\n } catch (e) {\n // ignore bridge errors, polling fallback may still work\n }\n },\n true\n );\n }\n\n function getResolvablePath(path, basePath) {\n if (Array.isArray(path)) {\n return path.map(p => getResolvablePathString(p, basePath));\n } else {\n return getResolvablePathString(path, basePath);\n }\n }\n\n function removeDoubleSlashes(str) {\n return str\n .replace(/([^:\\\\/])\\\\/\\\\/+/g, '$1/')\n .replace(/\\\\/\\\\//g, '/')\n .replace('http:/', 'http://')\n .replace('https:/', 'https://');\n }\n\n function ensureDirectoryBasePath(basePath) {\n if (!basePath) return basePath;\n if (basePath.endsWith('/')) return basePath;\n return basePath + '/';\n }\n\n\n\n function combineRequireResolvePaths(path1, path2, baseUrl) {\n path1 = getResolvablePath(path1, baseUrl);\n const path1Array = Array.isArray(path1) ? path1 : [path1];\n if (!path2) {\n return path1Array;\n }\n path2 = getResolvablePath(path2, baseUrl);\n const path2Array = Array.isArray(path2) ? path2 : [path2];\n return path1Array.concat(path2Array).filter((value, index, self) => self.indexOf(value) === index);\n }\n\n // Update paths with modules from the config\n if (config.interactionModules && config.interactionModules.length > 0) {\n config.interactionModules.forEach(module => {\n if (module.id && module.primaryPath) {\n const currentPath = window.requirePaths[module.id] || [];\n const currentPaths = Array.isArray(currentPath) ? currentPath : [currentPath];\n const newPath = combineRequireResolvePaths(\n module.primaryPath,\n module.fallbackPath,\n config.baseUrl\n );\n window.requirePaths[module.id] = newPath.concat(currentPaths)\n .filter((value, index, self) => self.indexOf(value) === index);\n }\n });\n }\n\n // The ONLY other requirejs.config call - with the context for this specific PCI\n window.requirejs.config({\n context: this.customInteractionTypeIdentifier,\n paths: window.requirePaths,\n shim: window.requireShim\n });\n\n // Define qtiCustomInteractionContext for the PCI\n define('qtiCustomInteractionContext', () => {\n return {\n register: pciInstance => {\n this.pciInstance = pciInstance;\n // Configure PCI instance\n const pciConfig = {\n properties: config.properties || {},\n contextVariables: config.contextVariables || {},\n templateVariables: config.templateVariables || {},\n onready: pciInstance => {\n this.pciInstance = pciInstance;\n // Apply any pending updates that arrived before onready\n if (this.pendingBoundTo) {\n this.applyBoundTo(this.pendingBoundTo);\n this.pendingBoundTo = null;\n }\n if (this.pendingState && typeof this.pciInstance.setState === 'function') {\n this.pciInstance.setState(this.pendingState);\n this.pendingState = null;\n }\n this.notifyReady();\n },\n ondone: (pciInstance, response, state, status) => {\n const valid =\n this.pciInstance && typeof this.pciInstance.checkValidity === 'function'\n ? this.pciInstance.checkValidity()\n : undefined;\n const customValidity =\n this.pciInstance && typeof this.pciInstance.getCustomValidity === 'function'\n ? this.pciInstance.getCustomValidity()\n : undefined;\n this.notifyInteractionChanged(\n response,\n typeof state === 'string' ? state : null,\n valid,\n customValidity\n );\n },\n responseIdentifier: config.responseIdentifier,\n boundTo: config.boundTo,\n responseDeclaration: config.responseDeclaration || undefined,\n status: config.status || 'interacting'\n };\n\n if (pciInstance.getInstance) {\n const dom = this.markupEl || this.container;\n // Round-trip support for object states (stored as a prefixed JSON string by the host).\n // For strict string-based PCIs we pass the original string through unchanged.\n let restoredState = config.state;\n if (typeof restoredState === 'string' && restoredState.indexOf('__qti_json__::') === 0) {\n try {\n restoredState = JSON.parse(restoredState.substring('__qti_json__::'.length));\n } catch (e) {\n // If parsing fails, fall back to the raw string.\n restoredState = config.state;\n }\n }\n // Keep the configuration around next to the instance, it carries the\n // status and response declaration this PCI was constructed with.\n this.pciConfig = pciConfig;\n pciInstance.getInstance(dom, pciConfig, restoredState || undefined);\n } else {\n this.notifyError('Loaded PCI module has no getInstance().');\n }\n },\n notifyReady: () => {\n PCIManager.notifyReady();\n }\n };\n });\n\n function getResolvablePathString(path, basePath) {\n path = path.replace(/\\\\.js$/, '');\n if (/^[a-z][a-z0-9+.-]*:/i.test(path) || !basePath) {\n return path;\n }\n\n if (path.startsWith('/') && !path.startsWith('//')) {\n path = path.slice(1);\n }\n\n try {\n const resolved = new URL(path, ensureDirectoryBasePath(basePath)).toString();\n return resolved.replace(/\\\\.js$/, '');\n } catch (error) {\n return removeDoubleSlashes(ensureDirectoryBasePath(basePath) + path);\n }\n }\n\n // Load the PCI module\n this.loadModule(config.module);\n },\n\n loadModule: function (modulePath) {\n try {\n // Get the context-specific require\n const contextRequire = window.requirejs.config({\n context: this.customInteractionTypeIdentifier\n });\n contextRequire(['require'], require => {\n // Now load the actual module\n require([modulePath], () => {}, err => {\n console.error('Error loading module:', modulePath, err);\n this.notifyError('Module load error: ' + err.toString());\n });\n });\n } catch (error) {\n console.error('Exception in loadModule:', modulePath);\n console.error(error);\n this.notifyError('Error in require call: ' + error.toString());\n }\n },\n\n notifyReady: function () {\n window.parent.postMessage(\n {\n source: 'qti-pci-iframe',\n responseIdentifier: this.responseIdentifier,\n method: 'iframeReady'\n },\n '*'\n );\n },\n\n notifyInteractionChanged: function (response, state, valid, customValidity) {\n window.parent.postMessage(\n {\n source: 'qti-pci-iframe',\n responseIdentifier: this.responseIdentifier,\n method: 'interactionChanged',\n params: {\n value: response,\n state: state,\n valid: typeof valid === 'boolean' ? valid : undefined,\n customValidity: typeof customValidity === 'string' ? customValidity : undefined\n }\n },\n '*'\n );\n },\n\n notifyError: function (message) {\n console.error('PCI Error:', message);\n window.parent.postMessage(\n {\n source: 'qti-pci-iframe',\n responseIdentifier: this.responseIdentifier,\n method: 'error',\n params: { message: message }\n },\n '*'\n );\n },\n\n setMarkup: function (markupHtml) {\n if (!this.container) {\n this.container = document.getElementById('pci-container');\n }\n if (!this.container) {\n this.pendingMarkup = markupHtml;\n return;\n }\n this.markupEl = this.container.querySelector('qti-interaction-markup');\n if (!this.markupEl) {\n this.markupEl = document.createElement('qti-interaction-markup');\n this.container.appendChild(this.markupEl);\n }\n this.markupEl.classList.add('qti-customInteraction');\n this.markupEl.innerHTML = markupHtml || '';\n },\n\n setProperties: function (propertiesHtml) {\n if (!this.container) {\n this.container = document.getElementById('pci-container');\n }\n if (!this.container) {\n this.pendingProperties = propertiesHtml;\n return;\n }\n this.propertiesEl = this.container.querySelector('properties');\n if (!this.propertiesEl) {\n this.propertiesEl = document.createElement('properties');\n this.container.appendChild(this.propertiesEl);\n }\n this.propertiesEl.style.display = 'none';\n this.propertiesEl.innerHTML = propertiesHtml || '';\n },\n\n minifyCss: function (cssContent) {\n return cssContent\n .replace(/\\\\/\\\\*[\\\\s\\\\S]*?\\\\*\\\\//g, '')\n .replace(/\\\\s+/g, ' ')\n .replace(/\\\\s*([{}:;])\\\\s*/g, '$1')\n .trim();\n },\n\n setStylesheets: function (stylesheetsHtml) {\n if (!stylesheetsHtml) return;\n if (!this.container) {\n this.container = document.getElementById('pci-container');\n }\n const target = this.container || document.body;\n if (!target) return;\n target.insertAdjacentHTML('afterbegin', stylesheetsHtml);\n },\n\n\n applyBoundTo: function (boundTo) {\n if (!this.pciInstance || typeof this.pciInstance.setResponse !== 'function') return;\n const value = boundTo && (boundTo[this.responseIdentifier] || boundTo[Object.keys(boundTo)[0]]);\n if (value) this.pciInstance.setResponse(value);\n }\n };\n\n // Set up message listener for communication with parent\n let expectedParentOrigin = null;\n window.addEventListener('message', function (event) {\n const { data } = event;\n\n // Ensure the message is from our parent\n if (event.source !== window.parent || !data || data.source !== 'qti-portable-custom-interaction') {\n return;\n }\n if (expectedParentOrigin === null) {\n expectedParentOrigin = event.origin;\n } else if (event.origin !== expectedParentOrigin) {\n return;\n }\n\n function deepQuerySelector(root, selector) {\n if (!root) return null;\n try {\n const direct = root.querySelector ? root.querySelector(selector) : null;\n if (direct) return direct;\n } catch (e) {\n // ignore invalid selector for this root\n }\n if (!root.querySelectorAll) return null;\n const nodes = root.querySelectorAll('*');\n for (const node of nodes) {\n if (node && node.shadowRoot) {\n const found = deepQuerySelector(node.shadowRoot, selector);\n if (found) return found;\n }\n }\n return null;\n }\n\n function deepFindElementByExactText(root, text) {\n if (!root || !text) return null;\n if (root.querySelectorAll) {\n const nodes = root.querySelectorAll('*');\n for (const node of nodes) {\n if ((node.textContent || '').trim() === text) return node;\n if (node.shadowRoot) {\n const found = deepFindElementByExactText(node.shadowRoot, text);\n if (found) return found;\n }\n }\n }\n return null;\n }\n\n switch (data.method) {\n case 'initialize':\n PCIManager.initialize(data.params);\n break;\n\n case 'setMarkup':\n PCIManager.setMarkup(data.params);\n break;\n\n case 'setBoundTo':\n if (PCIManager.pciInstance) {\n PCIManager.applyBoundTo(data.params);\n } else {\n PCIManager.pendingBoundTo = data.params;\n }\n break;\n\n case 'setProperties':\n PCIManager.setProperties(data.params);\n break;\n\n case 'setStylesheets':\n PCIManager.setStylesheets(data.params);\n break;\n\n case 'setState':\n if (PCIManager.pciInstance && typeof PCIManager.pciInstance.setState === 'function') {\n PCIManager.pciInstance.setState((data.params && data.params.state) || data.params);\n } else {\n PCIManager.pendingState = (data.params && data.params.state) || data.params;\n }\n break;\n\n case 'getContent': {\n const messageId = data.params && data.params.messageId;\n const collectShadowHtml = root => {\n const parts = [];\n if (!root || !root.querySelectorAll) return parts;\n const nodes = root.querySelectorAll('*');\n for (const node of nodes) {\n if (node && node.shadowRoot) {\n parts.push(node.shadowRoot.innerHTML || '');\n parts.push(...collectShadowHtml(node.shadowRoot));\n }\n }\n return parts;\n };\n const shadowHtml = collectShadowHtml(document).join('\\\\n');\n window.parent.postMessage(\n {\n source: 'qti-pci-iframe',\n responseIdentifier: PCIManager.responseIdentifier,\n method: 'getContentResponse',\n messageId: messageId,\n content: (document.documentElement ? document.documentElement.outerHTML : '') + '\\\\n' + shadowHtml\n },\n '*'\n );\n break;\n }\n\n case 'simulateClick': {\n const messageId = data.params && data.params.messageId;\n const x = data.params && data.params.x;\n const y = data.params && data.params.y;\n const el = typeof x === 'number' && typeof y === 'number' ? document.elementFromPoint(x, y) : null;\n const target = (el && el.closest && el.closest('.hitbox')) || document.querySelector('.hitbox') || el;\n if (target) {\n const evt = new MouseEvent('click', {\n bubbles: true,\n clientX: x,\n clientY: y,\n screenX: x,\n screenY: y,\n view: window\n });\n target.dispatchEvent(evt);\n }\n window.parent.postMessage(\n {\n source: 'qti-pci-iframe',\n responseIdentifier: PCIManager.responseIdentifier,\n method: 'clickResponse',\n messageId: messageId\n },\n '*'\n );\n break;\n }\n\n case 'getBoundingRect': {\n const messageId = data.params && data.params.messageId;\n const selector = data.params && data.params.selector;\n const el = selector ? deepQuerySelector(document, selector) : null;\n const rect = el && typeof el.getBoundingClientRect === 'function' ? el.getBoundingClientRect() : null;\n window.parent.postMessage(\n {\n source: 'qti-pci-iframe',\n responseIdentifier: PCIManager.responseIdentifier,\n method: 'getBoundingRectResponse',\n messageId: messageId,\n rect: rect\n ? {\n left: rect.left,\n top: rect.top,\n width: rect.width,\n height: rect.height\n }\n : null\n },\n '*'\n );\n break;\n }\n\n case 'clickOnSelector': {\n const messageId = data.params && data.params.messageId;\n const selector = data.params && data.params.selector;\n const el = selector ? deepQuerySelector(document, selector) : null;\n const success = !!el;\n if (el && typeof el.click === 'function') el.click();\n window.parent.postMessage(\n {\n source: 'qti-pci-iframe',\n responseIdentifier: PCIManager.responseIdentifier,\n method: 'clickSelectorResponse',\n messageId: messageId,\n success: success\n },\n '*'\n );\n break;\n }\n\n case 'clickOnElementByText': {\n const messageId = data.params && data.params.messageId;\n const text = data.params && data.params.text;\n const target = text ? deepFindElementByExactText(document, text) : null;\n const success = !!target;\n if (target && typeof target.click === 'function') target.click();\n window.parent.postMessage(\n {\n source: 'qti-pci-iframe',\n responseIdentifier: PCIManager.responseIdentifier,\n method: 'clickTextResponse',\n messageId: messageId,\n success: success\n },\n '*'\n );\n break;\n }\n\n case 'setValueElement': {\n const messageId = data.params && data.params.messageId;\n const selector = data.params && data.params.selector;\n const value = data.params && data.params.value;\n const el = selector ? deepQuerySelector(document, selector) : null;\n let success = false;\n if (el && 'value' in el) {\n try {\n el.value = value;\n el.dispatchEvent(new Event('input', { bubbles: true }));\n el.dispatchEvent(new Event('change', { bubbles: true }));\n success = true;\n } catch (e) {\n success = false;\n }\n }\n window.parent.postMessage(\n {\n source: 'qti-pci-iframe',\n responseIdentifier: PCIManager.responseIdentifier,\n method: 'setValueResponse',\n messageId: messageId,\n success: success\n },\n '*'\n );\n break;\n }\n\n case 'console':\n window.parent.postMessage(\n {\n source: 'qti-pci-iframe',\n responseIdentifier: PCIManager.responseIdentifier,\n method: 'console',\n level: data.level,\n args: data.args\n },\n '*'\n );\n break;\n }\n });\n\n let resizeTimeout;\n let previousHeight = 0;\n const notifyResize = () => {\n const container = document.getElementById('pci-container');\n const newHeight = container.scrollHeight + 100;\n if (newHeight !== previousHeight) {\n previousHeight = newHeight;\n clearTimeout(resizeTimeout);\n resizeTimeout = setTimeout(() => {\n window.parent.postMessage(\n {\n source: 'qti-pci-iframe',\n responseIdentifier: PCIManager.responseIdentifier,\n method: 'resize',\n height: newHeight,\n width: container.scrollWidth\n },\n '*'\n );\n }, 100); // Adjust debounce time as needed\n }\n };\n\n function setupResizeObserver() {\n const container = document.getElementById('pci-container');\n if (!container || !(container instanceof Element)) {\n console.warn('ResizeObserver: document.container is not an Element');\n return;\n }\n\n const resizeObserver = new ResizeObserver(() => {\n notifyResize();\n });\n\n resizeObserver.observe(container);\n }\n\n // Run setup once DOM is ready\n if (document.readyState === 'loading') {\n document.addEventListener('DOMContentLoaded', () => {\n notifyResize(); // initial resize\n setupResizeObserver();\n });\n } else {\n notifyResize();\n setupResizeObserver();\n }\n\n window.addEventListener('load', () => {\n notifyResize();\n });\n let lastResponseStr = '';\n setInterval(() => {\n if (PCIManager.interactionChangedViaEvent) return;\n if (PCIManager.pciInstance && PCIManager.pciInstance.getResponse) {\n const response = PCIManager.pciInstance.getResponse();\n const valid =\n PCIManager.pciInstance && typeof PCIManager.pciInstance.checkValidity === 'function'\n ? PCIManager.pciInstance.checkValidity()\n : undefined;\n const customValidity =\n PCIManager.pciInstance && typeof PCIManager.pciInstance.getCustomValidity === 'function'\n ? PCIManager.pciInstance.getCustomValidity()\n : undefined;\n if (response === undefined) {\n // Don't emit an initial empty on load; only emit a clear if we previously had a value\n if (!PCIManager.hadResponse) return;\n PCIManager.hadResponse = false;\n PCIManager.lastResponseStr = null;\n const state =\n PCIManager.pciInstance && typeof PCIManager.pciInstance.getState === 'function'\n ? PCIManager.pciInstance.getState()\n : null;\n window.parent.postMessage(\n {\n source: 'qti-pci-iframe',\n responseIdentifier: PCIManager.responseIdentifier,\n method: 'interactionChanged',\n params: { value: null, state: state, valid: valid, customValidity: customValidity }\n },\n '*'\n );\n return;\n }\n\n const responseStr = JSON.stringify(response);\n\n if (responseStr !== PCIManager.lastResponseStr) {\n PCIManager.lastResponseStr = responseStr;\n PCIManager.hadResponse = true;\n const state =\n PCIManager.pciInstance && typeof PCIManager.pciInstance.getState === 'function'\n ? PCIManager.pciInstance.getState()\n : null;\n window.parent.postMessage(\n {\n source: 'qti-pci-iframe',\n responseIdentifier: PCIManager.responseIdentifier,\n method: 'interactionChanged',\n params: { value: response, state: state, valid: valid, customValidity: customValidity }\n },\n '*'\n );\n }\n }\n }, 500); // Check every 500ms\n </script>\n </head>\n <body>\n <div id=\"pci-container\"></div>\n </body>\n </html>`;\n }\n\n /**\n * Method to disable the PCI for review mode\n * This can be used when showing the correct response\n */\n public disable() {\n // First, store the current state of the PCI\n this.#previousState = {\n pointerEvents: this.style.pointerEvents,\n position: this.style.position\n };\n\n this.sendMessageToIframe('setState', { state: 'disabled' });\n\n // Add an overlay to prevent interaction if not already there\n const existingOverlay = this.querySelector('.pci-interaction-overlay');\n if (!existingOverlay) {\n const overlay = document.createElement('div');\n overlay.className = 'pci-interaction-overlay';\n overlay.style.position = 'absolute';\n overlay.style.top = '0';\n overlay.style.left = '0';\n overlay.style.width = '100%';\n overlay.style.height = '100%';\n overlay.style.backgroundColor = 'rgba(200, 200, 200, 0.3)';\n overlay.style.zIndex = '100';\n overlay.style.pointerEvents = 'all';\n overlay.style.cursor = 'not-allowed';\n\n // Make sure the container is relatively positioned\n if (getComputedStyle(this).position === 'static') {\n this.style.position = 'relative';\n }\n\n this.appendChild(overlay);\n }\n }\n\n /**\n * Method to enable the PCI for interactive mode\n */\n public enable() {\n // Remove any overlays\n const overlay = this.querySelector('.pci-interaction-overlay');\n if (overlay) {\n overlay.remove();\n }\n\n // Restore previous state if available\n if (this.#previousState) {\n if (this.#previousState.pointerEvents) {\n this.style.pointerEvents = this.#previousState.pointerEvents;\n }\n if (this.#previousState.position) {\n this.style.position = this.#previousState.position;\n }\n this.#previousState = null;\n }\n\n this.sendMessageToIframe('setState', { state: 'interacting' });\n }\n\n // Add this property to store the previous state\n #previousState: {\n pointerEvents?: string;\n position?: string;\n } = null;\n\n override render() {\n return html`\n <slot></slot>\n ${this._errorMessage\n ? html`<div style=\"color:red\">\n <h1>Error</h1>\n ${this._errorMessage}\n </div>`\n : ''}\n `;\n }\n}\n\ndeclare global {\n interface HTMLElementTagNameMap {\n 'qti-portable-custom-interaction': QtiPortableCustomInteraction;\n }\n}\n","/**\n * @license\n * Copyright 2018 Google LLC\n * SPDX-License-Identifier: BSD-3-Clause\n */\n\nimport {AttributePart, noChange} from '../lit-html.js';\nimport {\n directive,\n Directive,\n DirectiveParameters,\n PartInfo,\n PartType,\n} from '../directive.js';\n\n/**\n * A key-value set of CSS properties and values.\n *\n * The key should be either a valid CSS property name string, like\n * `'background-color'`, or a valid JavaScript camel case property name\n * for CSSStyleDeclaration like `backgroundColor`.\n */\nexport interface StyleInfo {\n [name: string]: string | number | undefined | null;\n}\n\nconst important = 'important';\n// The leading space is important\nconst importantFlag = ' !' + important;\n// How many characters to remove from a value, as a negative number\nconst flagTrim = 0 - importantFlag.length;\n\nclass StyleMapDirective extends Directive {\n private _previousStyleProperties?: Set<string>;\n\n constructor(partInfo: PartInfo) {\n super(partInfo);\n if (\n partInfo.type !== PartType.ATTRIBUTE ||\n partInfo.name !== 'style' ||\n (partInfo.strings?.length as number) > 2\n ) {\n throw new Error(\n 'The `styleMap` directive must be used in the `style` attribute ' +\n 'and must be the only part in the attribute.'\n );\n }\n }\n\n render(styleInfo: Readonly<StyleInfo>) {\n return Object.keys(styleInfo).reduce((style, prop) => {\n const value = styleInfo[prop];\n if (value == null) {\n return style;\n }\n // Convert property names from camel-case to dash-case, i.e.:\n // `backgroundColor` -> `background-color`\n // Vendor-prefixed names need an extra `-` appended to front:\n // `webkitAppearance` -> `-webkit-appearance`\n // Exception is any property name containing a dash, including\n // custom properties; we assume these are already dash-cased i.e.:\n // `--my-button-color` --> `--my-button-color`\n prop = prop.includes('-')\n ? prop\n : prop\n .replace(/(?:^(webkit|moz|ms|o)|)(?=[A-Z])/g, '-$&')\n .toLowerCase();\n return style + `${prop}:${value};`;\n }, '');\n }\n\n override update(part: AttributePart, [styleInfo]: DirectiveParameters<this>) {\n const {style} = part.element as HTMLElement;\n\n if (this._previousStyleProperties === undefined) {\n this._previousStyleProperties = new Set(Object.keys(styleInfo));\n return this.render(styleInfo);\n }\n\n // Remove old properties that no longer exist in styleInfo\n for (const name of this._previousStyleProperties) {\n // If the name isn't in styleInfo or it's null/undefined\n if (styleInfo[name] == null) {\n this._previousStyleProperties!.delete(name);\n if (name.includes('-')) {\n style.removeProperty(name);\n } else {\n // eslint-disable-next-line @typescript-eslint/no-explicit-any\n (style as any)[name] = null;\n }\n }\n }\n\n // Add or update properties\n for (const name in styleInfo) {\n const value = styleInfo[name];\n if (value != null) {\n this._previousStyleProperties.add(name);\n const isImportant =\n typeof value === 'string' && value.endsWith(importantFlag);\n if (name.includes('-') || isImportant) {\n style.setProperty(\n name,\n isImportant\n ? (value as string).slice(0, flagTrim)\n : (value as string),\n isImportant ? important : ''\n );\n } else {\n // eslint-disable-next-line @typescript-eslint/no-explicit-any\n (style as any)[name] = value;\n }\n }\n }\n return noChange;\n }\n}\n\n/**\n * A directive that applies CSS properties to an element.\n *\n * `styleMap` can only be used in the `style` attribute and must be the only\n * expression in the attribute. It takes the property names in the\n * {@link StyleInfo styleInfo} object and adds the properties to the inline\n * style of the element.\n *\n * Property names with dashes (`-`) are assumed to be valid CSS\n * property names and set on the element's style object using `setProperty()`.\n * Names without dashes are assumed to be camelCased JavaScript property names\n * and set on the element's style object using property assignment, allowing the\n * style object to translate JavaScript-style names to CSS property names.\n *\n * For example `styleMap({backgroundColor: 'red', 'border-top': '5px', '--size':\n * '0'})` sets the `background-color`, `border-top` and `--size` properties.\n *\n * @param styleInfo\n * @see {@link https://lit.dev/docs/templates/directives/#stylemap styleMap code samples on Lit.dev}\n */\nexport const styleMap = directive(StyleMapDirective);\n\n/**\n * The type of the class that powers this directive. Necessary for naming the\n * directive's return type.\n */\nexport type {StyleMapDirective};\n","import { css } from 'lit';\n\nimport { boxSizing } from '@qti-components/base';\n\nexport default [\n boxSizing,\n css`\n :host {\n display: block;\n --qti-select-point-marker-size: 1.5rem;\n --qti-select-point-marker-anchor: -100%;\n --qti-select-point-icon: url(\"data:image/svg+xml,%3Csvg xmlns='http://www.w3.org/2000/svg' viewBox='0 0 384 512'%3E%3Cpath d='M172.268 501.67C26.97 291.031 0 269.413 0 192 0 85.961 85.961 0 192 0s192 85.961 192 192c0 77.413-26.97 99.031-172.268 309.67-9.535 13.774-29.93 13.773-39.464 0zM192 272c44.183 0 80-35.817 80-80s-35.817-80-80-80-80 35.817-80 80 35.817 80 80 80z'/%3E%3C/svg%3E\");\n }\n point-container {\n display: block;\n position: relative;\n width: fit-content;\n }\n\n ::slotted(img) {\n max-width: 100%;\n height: auto;\n display: block;\n }\n\n [part~='point'] {\n transform: translate(-50%, var(--qti-select-point-marker-anchor));\n width: var(--qti-select-point-marker-size);\n height: var(--qti-select-point-marker-size);\n min-width: var(--qti-select-point-marker-size);\n min-height: var(--qti-select-point-marker-size);\n padding: 0;\n margin: 0;\n border: none;\n background: transparent;\n color: inherit;\n cursor: pointer;\n background-color: var(--qti-select-point-marker-color, currentColor);\n -webkit-mask: var(--qti-select-point-icon) no-repeat center / contain;\n mask: var(--qti-select-point-icon) no-repeat center / contain;\n }\n `\n];\n","import { html, nothing } from 'lit';\nimport { property, state } from 'lit/decorators.js';\nimport { repeat } from 'lit/directives/repeat.js';\nimport { styleMap } from 'lit/directives/style-map.js';\n\nimport { watch } from '@qti-components/utilities';\nimport { Interaction } from '@qti-components/base';\nimport { parseResponseAttribute, serializeResponseAttribute } from '@qti-components/base';\nimport { positionShapes } from '@qti-components/interactions-core/internal/hotspots/hotspot';\n\nimport styles from './qti-select-point-interaction.styles';\n\nimport type { CSSResultGroup } from 'lit';\nimport type { QtiAreaMapEntry, QtiAreaMapping } from '@qti-components/base';\n/**\n * Select-point interaction: candidates place points onto a background image.\n *\n * @customElement qti-select-point-interaction\n *\n * @attr {string} response-identifier - Required. Identifier of the bound response variable,\n * which must have base-type `point`.\n * @attr {number} [max-choices=0] - Maximum points the candidate may place; `0` means unlimited.\n * @attr {number} [min-choices=0] - Minimum points for a valid response.\n * @attr {string} area-mappings - Extension, not QTI. JSON array of\n * `{shape, coords, mappedValue?, defaultValue?}` entries used when no\n * `qti-response-declaration` supplies an `qti-area-mapping`.\n *\n * @slot prompt - The prompt shown above the image.\n * @slot - Default slot for the base image.\n *\n * @csspart point - Each selected point marker.\n * @cssprop --qti-select-point-icon - Marker mask image (SVG data URL). Should be a solid silhouette for color inheritance.\n * @cssprop --qti-select-point-marker-size - Marker size.\n * @cssprop --qti-select-point-marker-anchor - Vertical translate anchor (`-100%` for bottom tip, `-50%` for center).\n * @cssprop --qti-select-point-marker-color - Marker color; defaults to currentColor so it can be inherited.\n */\nexport class QtiSelectPointInteraction extends Interaction {\n static override styles: CSSResultGroup = styles;\n\n @property({\n type: Number,\n attribute: 'max-choices'\n })\n public maxChoices: number = Infinity;\n\n @property({\n type: Number,\n attribute: 'min-choices'\n })\n public minChoices: number = 0;\n\n @property({\n attribute: 'response',\n reflect: false,\n converter: {\n // Each entry is `\"x y\"`; the codec splits on commas. Point cardinality\n // needs an array locally, so wrap a single-string codec output.\n fromAttribute: (value: string | null) => {\n const parsed = parseResponseAttribute(value);\n if (parsed === null) return null;\n return Array.isArray(parsed) ? parsed : [parsed];\n },\n toAttribute: (value: string[] | null) => serializeResponseAttribute(value)\n }\n })\n response: string[] | null = null;\n\n /**\n * Standalone area mapping as a JSON string. Mirrors the editor's\n * `#syncAreaEntriesFromAttribute` codec — each entry has `{shape, coords, mappedValue?, defaultValue?}`\n * and `shape` must be `'circle'` or `'rect'`. Used when no\n * `qti-response-declaration` provides `areaMapping`.\n *\n * @example\n * ```html\n * <qti-select-point-interaction area-mappings='[{\"shape\":\"circle\",\"coords\":\"191,393,10\",\"mappedValue\":1}]'>\n * ```\n */\n @property({ attribute: 'area-mappings' })\n areaMappings: string | null = null;\n\n @state()\n private _areaEntries: QtiAreaMapEntry[] = [];\n\n @watch('areaMappings' as never)\n protected _handleAreaMappingsChange = () => {\n this.#syncAreaEntriesFromAttribute();\n };\n\n #syncAreaEntriesFromAttribute() {\n try {\n const raw = JSON.parse(this.areaMappings || '[]');\n if (!Array.isArray(raw)) {\n this._areaEntries = [];\n return;\n }\n this._areaEntries = raw\n .filter(\n entry => entry && (entry.shape === 'circle' || entry.shape === 'rect') && typeof entry.coords === 'string'\n )\n .map(entry => ({\n shape: entry.shape,\n coords: String(entry.coords),\n mappedValue: Number(entry.mappedValue ?? 1),\n defaultValue: Number(entry.defaultValue ?? 0)\n }));\n } catch {\n this._areaEntries = [];\n }\n }\n\n protected get _effectiveAreaEntries(): QtiAreaMapEntry[] {\n const fromResponseVariable = (this.responseVariable?.areaMapping as QtiAreaMapping | undefined)?.areaMapEntries;\n if (fromResponseVariable?.length) return fromResponseVariable;\n return this._areaEntries;\n }\n\n // Reference to the image element\n #imgElement: HTMLImageElement | null = null;\n\n #scaleX = 1;\n #scaleY = 1;\n #imageWidthOriginal = 0;\n #imageHeightOriginal = 0;\n\n // Extracted click handler method\n #onImageClick = (event: MouseEvent) => {\n if (this.disabled) {\n return;\n }\n if (!this.#imgElement) {\n console.warn('No <img> element found in <qti-select-point-interaction>');\n return;\n }\n this.#calculateScale();\n // Get the image's bounding rectangle and calculate scaling factors\n const rect = this.#imgElement.getBoundingClientRect();\n\n // Calculate the x and y coordinates relative to the original image size\n const x = (event.clientX - rect.left) * this.#scaleX;\n const y = (event.clientY - rect.top) * this.#scaleY;\n\n // Save the new point as a string\n const newPoint = `${x.toFixed()} ${y.toFixed()}`;\n\n if (this.maxChoices === 1) {\n // If maxChoices is 1, replace the existing marker with the new one\n this.response = [newPoint];\n } else {\n // If maxChoices > 1, add a new marker if within the limit\n if (this.maxChoices === 0 || (this.response || []).length < this.maxChoices) {\n this.response = [...(this.response || []), newPoint];\n } else {\n // Optional: Notify the user to remove a marker before adding a new one\n // console.warn('Maximum number of points reached. Remove a marker to add a new one.');\n }\n }\n // Save the response with the calculated points\n this.saveResponse(this.response);\n };\n\n override connectedCallback() {\n super.connectedCallback();\n window.addEventListener('resize', this.#onResize);\n }\n\n #onResize = () => {\n this.#calculateScale();\n };\n\n get responsePoints() {\n const raw = this.response;\n const list = Array.isArray(raw) ? raw : raw ? [raw] : [];\n return list\n .filter(point => point)\n .map(point => {\n const [x, y] = point.split(' ').map(Number);\n return { x, y };\n });\n }\n\n /** Extension hook for additional part tokens on a rendered response point. */\n protected pointPart(_point: string, _index: number): string {\n return 'point';\n }\n\n /** Extension hook for optional layers rendered above the response points. */\n protected renderSupplementalLayer(): unknown {\n return nothing;\n }\n\n /** Positions overlay elements that carry `data-coord` and `data-shape`. */\n protected positionOverlayElements(elements: Iterable<HTMLElement>): void {\n const img = this.#imgElement;\n if (!img) return;\n this.#calculateScale();\n for (const element of elements) {\n const coords = element.dataset.coord;\n const shape = element.dataset.shape;\n if (!coords || !shape) continue;\n positionShapes(\n shape,\n coords.split(',').map(c => +c),\n img,\n element\n );\n }\n }\n\n override render() {\n const rawResponse = this.response;\n const responseList = Array.isArray(rawResponse) ? rawResponse : rawResponse ? [rawResponse] : [];\n return html` <slot name=\"prompt\"></slot>\n <point-container>\n ${repeat(\n responseList.filter(point => point),\n point => point,\n (point, index) => {\n const [x, y] = point.split(' ').map(Number);\n // point are based on the original image size, so we need calculate the percentage based on the original image\n const leftPercentage = (x / (this.#imageWidthOriginal || 1)) * 100;\n const topPercentage = (y / (this.#imageHeightOriginal || 1)) * 100;\n\n return html`\n <button\n part=${this.pointPart(point, index)}\n style=${styleMap({\n pointerEvents: this.maxChoices === 1 ? 'none' : 'auto',\n position: 'absolute',\n left: `${leftPercentage}%`,\n top: `${topPercentage}%`\n })}\n aria-label=\"Remove point at ${point}\"\n ?disabled=${this.disabled}\n @click=${(e: Event) => {\n e.stopPropagation();\n this.response = (this.response || []).filter((_, i) => i !== index);\n this.saveResponse(this.response);\n }}\n ></button>\n `;\n }\n )}\n ${this.renderSupplementalLayer()}\n <slot></slot>\n </point-container>`;\n }\n\n validate(): boolean {\n const selectedCount = this.response?.length ?? 0;\n const exceedsMax = this.maxChoices !== 0 && Number.isFinite(this.maxChoices) && selectedCount > this.maxChoices;\n const belowMin = selectedCount < this.minChoices;\n\n let isValid = true;\n let validityMessage = '';\n\n if (exceedsMax) {\n isValid = false;\n validityMessage =\n this.dataset.maxSelectionsMessage ||\n `Please select no more than ${this.maxChoices} ${this.maxChoices === 1 ? 'point' : 'points'}.`;\n } else if (belowMin) {\n isValid = false;\n validityMessage =\n this.dataset.minSelectionsMessage ||\n `Please select at least ${this.minChoices} ${this.minChoices === 1 ? 'point' : 'points'}.`;\n }\n\n this.setInteractionValidity(isValid, validityMessage, this.#imgElement ?? this, { suppressInline: true });\n return isValid;\n }\n\n public override reportValidity(): boolean {\n return super.reportValidity();\n }\n\n #calculateScale() {\n // Get the image dimensions\n this.#imageWidthOriginal = this.#imgElement.getAttribute('width')\n ? parseFloat(this.#imgElement.getAttribute('width')!)\n : this.#imgElement.naturalWidth;\n this.#imageHeightOriginal = this.#imgElement.getAttribute('height')\n ? parseFloat(this.#imgElement.getAttribute('height')!)\n : this.#imgElement.naturalHeight;\n // Get the image's bounding rectangle and calculate scaling factors\n const rect = this.#imgElement.getBoundingClientRect();\n this.#scaleX = rect.width === 0 ? 1 : this.#imageWidthOriginal / rect.width; // Horizontal scaling factor\n this.#scaleY = rect.height === 0 ? 1 : this.#imageHeightOriginal / rect.height; // Vertical scaling factor\n }\n\n override firstUpdated(): void {\n super.firstUpdated();\n this.#imgElement = this.querySelector('img');\n\n if (this.#imgElement) {\n this.#calculateScale();\n // Attach the click event listener to the image element\n this.#imgElement.addEventListener('click', this.#onImageClick);\n } else {\n console.warn('No <img> element found in <qti-select-point-interaction>');\n }\n }\n\n override disconnectedCallback(): void {\n super.disconnectedCallback();\n\n window.removeEventListener('resize', this.#onResize);\n if (this.#imgElement) {\n // Remove the click event listener from the image element\n this.#imgElement.removeEventListener('click', this.#onImageClick);\n }\n }\n}\n\ndeclare global {\n interface HTMLElementTagNameMap {\n 'qti-select-point-interaction': QtiSelectPointInteraction;\n }\n}\n","import { css } from 'lit';\n\nimport { boxSizing } from '@qti-components/base';\n\nexport default [\n boxSizing,\n css`\n :host {\n display: block;\n --show-bounds: true;\n --show-ticks: true;\n --show-value: true;\n }\n\n [part='slider'] {\n margin-left: 2rem; /* mx-8 */\n margin-right: 2rem;\n padding-bottom: 1rem; /* pb-4 */\n padding-top: 1.25rem; /* pt-5 */\n }\n\n [part='bounds'] {\n display: flex;\n width: 100%;\n justify-content: space-between;\n margin-bottom: 0.5rem; /* mb-2 */\n }\n\n [part='ticks'] {\n margin-left: 0.125rem; /* mx-0.5 */\n margin-right: 0.125rem;\n margin-bottom: 0.25rem; /* mb-1 */\n height: 0.5rem; /* h-2 */\n background: linear-gradient(to right, var(--qti-border-color) var(--qti-border-thickness), transparent 1px)\n repeat-x 0 center / calc(calc(100% - var(--qti-border-thickness)) / ((var(--max) - var(--min)) / var(--step)))\n 100%;\n }\n\n [part='rail'] {\n display: flex;\n align-items: center;\n box-sizing: border-box;\n height: 0.375rem; /* h-1.5 */\n width: 100%;\n cursor: pointer;\n border-radius: 9999px; /* rounded-full */\n border: 1px solid #d1d5db; /* border-gray-300 */\n background-color: #e5e7eb; /* bg-gray-200 */\n }\n\n [part='knob'] {\n background-color: var(--qti-bg-active);\n border: 2px solid var(--qti-border-active);\n position: relative;\n height: 1rem; /* h-4 */\n width: 1rem; /* w-4 */\n transform-origin: center;\n transform: translateX(-50%);\n cursor: pointer;\n border-radius: 9999px; /* rounded-full */\n left: var(--value-percentage);\n }\n [part='value'] {\n position: absolute;\n bottom: 2rem; /* bottom-8 */\n left: 0.5rem; /* left-2 */\n transform: translateX(-50%);\n cursor: pointer;\n border-radius: 0.25rem; /* rounded */\n background-color: #f3f4f6; /* bg-gray-100 */\n padding: 0.25rem 0.5rem; /* px-2 py-1 */\n text-align: center;\n color: #6b7280; /* text-gray-500 */\n }\n `\n];\n","import { html, nothing } from 'lit';\nimport { property, query } from 'lit/decorators.js';\n\nimport { Interaction } from '@qti-components/base';\n\nimport styles from './qti-slider-interaction.styles';\n\nimport type { CSSResultGroup } from 'lit';\n/**\n * Slider interaction: candidates pick a numeric value along a rail.\n *\n * @slot prompt - The prompt shown above the slider.\n *\n * @csspart slider - The slider root element.\n * @csspart bounds - The min/max bounds label wrapper.\n * @csspart ticks - The tick marks along the rail.\n * @csspart rail - The rail element the knob slides along.\n * @csspart knob - The draggable knob.\n * @csspart value - The current value display (used twice in the layout).\n * @csspart knob-correct - Ghost knob shown at the correct response position.\n */\nexport class QtiSliderInteraction extends Interaction {\n static override styles: CSSResultGroup = styles;\n\n #value = 0;\n\n @query('#rail') private _rail!: HTMLElement;\n\n @property({ type: Number, attribute: 'lower-bound' }) min = 0;\n @property({ type: Number, attribute: 'upper-bound' }) max = 100;\n @property({ type: Number, attribute: 'step' }) step = 1;\n\n validate(): boolean {\n return true;\n }\n\n override connectedCallback() {\n super.connectedCallback();\n // Only seed with `min` if no explicit response was set via attribute/property.\n if (!this.hasAttribute('response')) {\n this.#updateValue(this.min);\n }\n this.setAttribute('tabindex', '0');\n this.setAttribute('role', 'slider');\n }\n\n @property({ attribute: 'response', reflect: false, noAccessor: true })\n get response(): string {\n return this.#value.toString();\n }\n\n set response(val: string | null) {\n if (val === null || val === '') return;\n const newValue = parseFloat(val);\n if (!isNaN(newValue)) {\n this.#updateValue(newValue);\n }\n }\n\n /** Extension hook for optional content rendered on the slider rail. */\n protected renderRailSupplement(): unknown {\n return nothing;\n }\n\n #updateValue(newValue: number) {\n const oldValue = this.#value;\n this.#value = Math.min(this.max, Math.max(this.min, newValue));\n if (this.#value === oldValue) {\n return; // Do not update if the value is the same as before\n }\n const valuePercentage = ((this.#value - this.min) / (this.max - this.min)) * 100;\n this.style.setProperty('--value-percentage', `${valuePercentage}%`);\n this._internals.setFormValue(this.value); // Update form value\n this.saveResponse(this.response);\n this.requestUpdate();\n }\n\n override render() {\n return html`\n <slot name=\"prompt\"></slot>\n <div id=\"slider\" part=\"slider\">\n <div id=\"bounds\" part=\"bounds\">\n <div>${this.min}</div>\n <div>${this.max}</div>\n </div>\n\n <div id=\"ticks\" part=\"ticks\"></div>\n\n <div id=\"rail\" part=\"rail\" @mousedown=${this.#onMouseDown} @touchstart=${this.#onTouchStart}>\n <div id=\"knob\" part=\"knob\">\n <div id=\"value\" part=\"value\">${this.response}</div>\n </div>\n\n ${this.renderRailSupplement()}\n </div>\n </div>\n `;\n }\n\n #onMouseDown(event: MouseEvent) {\n this.#startDrag(event.pageX);\n const handleMouseMove = (e: MouseEvent) => this.#onDrag(e.pageX);\n const handleMouseUp = () => {\n document.removeEventListener('mousemove', handleMouseMove);\n document.removeEventListener('mouseup', handleMouseUp);\n this.#onDragEnd();\n };\n\n document.addEventListener('mousemove', handleMouseMove);\n document.addEventListener('mouseup', handleMouseUp);\n }\n\n #onTouchStart(event: TouchEvent) {\n this.#startDrag(event.touches[0].pageX);\n const handleTouchMove = (e: TouchEvent) => this.#onDrag(e.touches[0].pageX);\n const handleTouchEnd = () => {\n document.removeEventListener('touchmove', handleTouchMove);\n document.removeEventListener('touchend', handleTouchEnd);\n this.#onDragEnd();\n };\n\n document.addEventListener('touchmove', handleTouchMove, { passive: false });\n document.addEventListener('touchend', handleTouchEnd);\n }\n\n #startDrag(pageX: number) {\n this.#onDrag(pageX);\n }\n\n #onDrag(pageX: number) {\n const railRect = this._rail.getBoundingClientRect();\n const diffX = pageX - railRect.left;\n const percentage = Math.min(1, Math.max(0, diffX / railRect.width));\n const steppedValue = this.min + Math.round((percentage * (this.max - this.min)) / this.step) * this.step;\n this.#updateValue(steppedValue);\n }\n\n #onDragEnd() {\n this.dispatchEvent(new Event('change', { bubbles: true }));\n }\n}\n\ndeclare global {\n interface HTMLElementTagNameMap {\n 'qti-slider-interaction': QtiSliderInteraction;\n }\n}\n","/**\n * @license\n * Copyright 2020 Google LLC\n * SPDX-License-Identifier: BSD-3-Clause\n */\nimport {nothing, ElementPart} from '../lit-html.js';\nimport {directive, AsyncDirective} from '../async-directive.js';\n\n/**\n * Creates a new Ref object, which is container for a reference to an element.\n */\nexport const createRef = <T = Element>() => new Ref<T>();\n\n/**\n * An object that holds a ref value.\n */\nclass Ref<T = Element> {\n /**\n * The current Element value of the ref, or else `undefined` if the ref is no\n * longer rendered.\n */\n readonly value?: T;\n}\n\nexport type {Ref};\n\ninterface RefInternal {\n value: Element | undefined;\n}\n\n// When callbacks are used for refs, this map tracks the last value the callback\n// was called with, for ensuring a directive doesn't clear the ref if the ref\n// has already been rendered to a new spot. It is double-keyed on both the\n// context (`options.host`) and the callback, since we auto-bind class methods\n// to `options.host`.\nconst lastElementForContextAndCallback = new WeakMap<\n object,\n WeakMap<Function, Element | undefined>\n>();\n\nexport type RefOrCallback<T = Element> = Ref<T> | ((el: T | undefined) => void);\n\nclass RefDirective extends AsyncDirective {\n private _element?: Element;\n private _ref?: RefOrCallback;\n private _context?: object;\n\n render(_ref?: RefOrCallback) {\n return nothing;\n }\n\n override update(part: ElementPart, [ref]: Parameters<this['render']>) {\n const refChanged = ref !== this._ref;\n if (refChanged && this._ref !== undefined) {\n // The ref passed to the directive has changed;\n // unset the previous ref's value\n this._updateRefValue(undefined);\n }\n if (refChanged || this._lastElementForRef !== this._element) {\n // We either got a new ref or this is the first render;\n // store the ref/element & update the ref value\n this._ref = ref;\n this._context = part.options?.host;\n this._updateRefValue((this._element = part.element));\n }\n return nothing;\n }\n\n private _updateRefValue(element: Element | undefined) {\n if (!this.isConnected) {\n element = undefined;\n }\n if (typeof this._ref === 'function') {\n // If the current ref was called with a previous value, call with\n // `undefined`; We do this to ensure callbacks are called in a consistent\n // way regardless of whether a ref might be moving up in the tree (in\n // which case it would otherwise be called with the new value before the\n // previous one unsets it) and down in the tree (where it would be unset\n // before being set). Note that element lookup is keyed by\n // both the context and the callback, since we allow passing unbound\n // functions that are called on options.host, and we want to treat\n // these as unique \"instances\" of a function.\n const context = this._context ?? globalThis;\n let lastElementForCallback =\n lastElementForContextAndCallback.get(context);\n if (lastElementForCallback === undefined) {\n lastElementForCallback = new WeakMap();\n lastElementForContextAndCallback.set(context, lastElementForCallback);\n }\n if (lastElementForCallback.get(this._ref) !== undefined) {\n this._ref.call(this._context, undefined);\n }\n lastElementForCallback.set(this._ref, element);\n // Call the ref with the new element value\n if (element !== undefined) {\n this._ref.call(this._context, element);\n }\n } else {\n (this._ref as RefInternal)!.value = element;\n }\n }\n\n private get _lastElementForRef() {\n return typeof this._ref === 'function'\n ? lastElementForContextAndCallback\n .get(this._context ?? globalThis)\n ?.get(this._ref)\n : this._ref?.value;\n }\n\n override disconnected() {\n // Only clear the box if our element is still the one in it (i.e. another\n // directive instance hasn't rendered its element to it before us); that\n // only happens in the event of the directive being cleared (not via manual\n // disconnection)\n if (this._lastElementForRef === this._element) {\n this._updateRefValue(undefined);\n }\n }\n\n override reconnected() {\n // If we were manually disconnected, we can safely put our element back in\n // the box, since no rendering could have occurred to change its state\n this._updateRefValue(this._element);\n }\n}\n\n/**\n * Sets the value of a Ref object or calls a ref callback with the element it's\n * bound to.\n *\n * A Ref object acts as a container for a reference to an element. A ref\n * callback is a function that takes an element as its only argument.\n *\n * The ref directive sets the value of the Ref object or calls the ref callback\n * during rendering, if the referenced element changed.\n *\n * Note: If a ref callback is rendered to a different element position or is\n * removed in a subsequent render, it will first be called with `undefined`,\n * followed by another call with the new element it was rendered to (if any).\n *\n * ```js\n * // Using Ref object\n * const inputRef = createRef();\n * render(html`<input ${ref(inputRef)}>`, container);\n * inputRef.value.focus();\n *\n * // Using callback\n * const callback = (inputElement) => inputElement.focus();\n * render(html`<input ${ref(callback)}>`, container);\n * ```\n */\nexport const ref = directive(RefDirective);\n\n/**\n * The type of the class that powers this directive. Necessary for naming the\n * directive's return type.\n */\nexport type {RefDirective};\n","import { css } from 'lit';\n\nimport { boxSizing } from '@qti-components/base';\n\nexport default [\n boxSizing,\n css`\n :host {\n display: inline-flex;\n align-items: center;\n vertical-align: middle;\n }\n\n /*\n * The QTI presentation class .qti-input-width-N promises room for N characters, so the CSS\n * says exactly that: N times the width of a zero glyph, which is the definition of the ch\n * unit — the same metric the HTML size attribute uses, and the one the conformance suite\n * measures against (see inputCharCapacity in the Q20 stories).\n *\n * This used to be a ladder of sixteen hand-tuned rem values, and they were only approximately\n * N: about 1.1rem per character up to -6, then about 0.8rem per character from -10 up. So the\n * small classes were roughly double what they claimed and the large ones about 1.5x. Worse, a\n * rem is fixed while a character is not, so every theme that changed the input's font silently\n * changed how many characters fit. In ch the promise holds in any font at any size.\n *\n * Two details:\n *\n * content-box is what makes the unit mean anything. Under the border-box reset above, the\n * theme's padding and border would be taken *out* of the N characters, and .qti-input-width-1\n * would leave no room for the one character it names. The input is inside this shadow tree, so\n * it can opt out; a document-level reset never reaches it.\n *\n * The 2px is the caret's column. Without it the final character scrolls out from under the\n * cursor as it is typed. It also keeps clientWidth — which the CSSOM rounds to a whole pixel —\n * from landing a hair under N characters and failing the conformance assertion.\n *\n * Both the width and the content-box are gated on the class being present. An input with no\n * qti-input-width-N keeps the width its theme gives it and stays border-box like everything\n * else; only an input that has been *promised* N characters opts out to guarantee them.\n */\n :host([class*='qti-input-width-']) [part='input'] {\n box-sizing: content-box;\n width: calc(var(--qti-input-width) * 1ch + 2px);\n min-width: calc(var(--qti-input-width) * 1ch + 2px);\n }\n\n [part='input'] {\n padding: var(--qti-padding-box);\n }\n\n :host(.qti-input-width-1) {\n --qti-input-width: 1;\n }\n :host(.qti-input-width-2) {\n --qti-input-width: 2;\n }\n :host(.qti-input-width-3) {\n --qti-input-width: 3;\n }\n :host(.qti-input-width-4) {\n --qti-input-width: 4;\n }\n :host(.qti-input-width-6) {\n --qti-input-width: 6;\n }\n :host(.qti-input-width-10) {\n --qti-input-width: 10;\n }\n :host(.qti-input-width-15) {\n --qti-input-width: 15;\n }\n :host(.qti-input-width-20) {\n --qti-input-width: 20;\n }\n :host(.qti-input-width-25) {\n --qti-input-width: 25;\n }\n :host(.qti-input-width-30) {\n --qti-input-width: 30;\n }\n :host(.qti-input-width-35) {\n --qti-input-width: 35;\n }\n :host(.qti-input-width-40) {\n --qti-input-width: 40;\n }\n :host(.qti-input-width-45) {\n --qti-input-width: 45;\n }\n :host(.qti-input-width-50) {\n --qti-input-width: 50;\n }\n :host(.qti-input-width-72) {\n --qti-input-width: 72;\n }\n `\n];\n","import { html, nothing } from 'lit';\nimport { property, query } from 'lit/decorators.js';\nimport { ifDefined } from 'lit/directives/if-defined.js';\nimport { createRef } from 'lit/directives/ref.js';\n\nimport { watch } from '@qti-components/utilities';\nimport { Interaction } from '@qti-components/base';\n\nimport styles from './qti-text-entry-interaction.styles';\n\nimport type { CSSResultGroup } from 'lit';\n\n/**\n * Text-entry interaction: single-line inline text input.\n *\n * @customElement qti-text-entry-interaction\n *\n * @attr {string} response-identifier - Required. Identifier of the bound response variable.\n * @attr {number} expected-length - Hint at the expected answer length; drives the rendered\n * field width and the input's `maxlength`.\n * @attr {string} pattern-mask - Regular expression the value must match to be valid.\n * @attr {string} placeholder-text - Placeholder shown while the field is empty.\n * @attr {string} data-patternmask-message - Custom validation message shown when\n * `pattern-mask` fails. Part of the QTI shared interaction vocabulary.\n * @attr {number} [base=10] - Not implemented. Numeric base used when recording the value.\n * @attr {string} string-identifier - Not implemented. Identifier of a second, string-typed\n * response variable that also receives the raw entry.\n * @attr {string} format - Not implemented. QTI types this as a bare normalized string here rather\n * than as the `plain | preformatted | xhtml` vocabulary it defines for extended-text, and a\n * single-line input has no formatting to render: it can show neither preserved line breaks nor\n * markup. The field is always plain text, so this is not planned either.\n *\n * @csspart answer - The answer-key line, revealed above the field when the correct response is shown.\n * @csspart input - The text input element.\n * @csspart message - The validation message, hidden until `reportValidity` shows it.\n */\nexport class QtiTextEntryInteraction extends Interaction {\n static override styles: CSSResultGroup = styles;\n inputRef = createRef<HTMLInputElement>();\n\n @property({ type: Number, attribute: 'expected-length' }) expectedLength: number;\n\n @property({ type: String, attribute: 'pattern-mask' }) patternMask: string;\n\n @property({ type: String, attribute: 'placeholder-text' }) placeholderText: string;\n\n @property({ type: String, attribute: 'data-patternmask-message' }) dataPatternmaskMessage: string;\n\n @property({ type: String, attribute: 'response', reflect: false })\n response: string | null = null;\n\n @query('input') private _input!: HTMLInputElement;\n\n @watch('response', { waitUntilFirstUpdate: true })\n protected _handleValueChange = () => {\n this._internals.setFormValue(this.value);\n this.validate();\n };\n\n override get value(): string | null {\n return this.response || null;\n }\n override set value(val: string | null) {\n this.response = val || null;\n }\n\n override get isInline(): boolean {\n return true;\n }\n\n public override validate(): boolean {\n if (!this._input) return false;\n let validityMessage = '';\n let isValid = false;\n\n if (this.patternMask && this.dataPatternmaskMessage) {\n // Clear any custom error if the this._input is valid\n this._input.setCustomValidity(''); // Clear the custom message\n isValid = this._input.checkValidity();\n if (!isValid) {\n // Set custom error if invalid\n validityMessage = this.dataPatternmaskMessage;\n this._input.setCustomValidity(this.dataPatternmaskMessage); // Set custom message only if invalid\n }\n } else {\n isValid = this._input.checkValidity();\n }\n\n if (isValid && this.response === '') {\n isValid = false;\n }\n\n if (!isValid && !validityMessage) {\n validityMessage = this._input.validationMessage || 'Invalid value.';\n }\n\n this.setInteractionValidity(isValid, validityMessage, this._input, { suppressInline: true });\n return isValid;\n }\n\n /*\n * The template in named pieces, so a subclass can recompose it. Override a piece to change what\n * one part looks like; override `render()` to change the order. See the longer note on the same\n * pattern in qti-extended-text-interaction.\n */\n\n /** The answer-key line, revealed above the field when the correct response is shown. */\n protected renderAnswer(): unknown {\n return html`<div part=\"answer\" aria-hidden=\"true\"></div>`;\n }\n\n /** The field itself. */\n protected renderInput(): unknown {\n return html`<input\n part=\"input\"\n name=\"${this.responseIdentifier}\"\n spellcheck=\"false\"\n autocomplete=\"off\"\n @blur=\"${(_: FocusEvent) => {\n this.reportValidity();\n }}\"\n @keydown=\"${(event: KeyboardEvent) => event.stopImmediatePropagation()}\"\n @keyup=\"${this.textChanged}\"\n @change=\"${this.textChanged}\"\n type=\"${this.patternMask == '[0-9]*' ? 'number' : 'text'}\"\n placeholder=\"${ifDefined(this.placeholderText ? this.placeholderText : undefined)}\"\n .value=\"${this.response}\"\n pattern=\"${ifDefined(this.patternMask ? this.patternMask : undefined)}\"\n maxlength=${1000}\n ?disabled=\"${this.disabled}\"\n ?readonly=\"${this.readonly}\"\n />`;\n }\n\n /** Hidden until `Interaction.reportValidity` shows it. */\n protected renderValidationMessage(): unknown {\n return html`<div id=\"validation-message\" part=\"message\" role=\"alert\" style=\"display:none;\"></div>`;\n }\n\n override render() {\n return html` ${this.renderAnswer()} ${this.renderInput()} ${this.renderValidationMessage()} `;\n }\n\n protected textChanged(event: Event): void {\n if (this.disabled || this.readonly) return;\n const input = event.target as HTMLInputElement;\n if (this.response !== input.value) {\n this.value = input.value;\n this.saveResponse(input.value);\n }\n }\n\n override reportValidity(): boolean {\n this.validate();\n return super.reportValidity();\n }\n\n override reset(): void {\n this.response = '';\n }\n}\n\ndeclare global {\n interface HTMLElementTagNameMap {\n 'qti-text-entry-interaction': QtiTextEntryInteraction;\n }\n}\n","import { QtiAssociateInteraction } from './qti-associate-interaction';\n\nexport const elements = [{ tag: 'qti-associate-interaction', ctor: QtiAssociateInteraction }] as const;\n\nexport { QtiAssociateInteraction };\n","import { QtiChoiceInteraction } from './qti-choice-interaction';\n\nexport const elements = [{ tag: 'qti-choice-interaction', ctor: QtiChoiceInteraction }] as const;\n\nexport { QtiChoiceInteraction };\n","import { QtiExtendedTextInteraction } from './qti-extended-text-interaction';\n\nexport const elements = [{ tag: 'qti-extended-text-interaction', ctor: QtiExtendedTextInteraction }] as const;\n\nexport { QtiExtendedTextInteraction };\n","import { QtiGapMatchInteraction } from './qti-gap-match-interaction';\n\nexport const elements = [{ tag: 'qti-gap-match-interaction', ctor: QtiGapMatchInteraction }] as const;\n\nexport { QtiGapMatchInteraction };\n","import { QtiGraphicAssociateInteraction } from './qti-graphic-associate-interaction';\n\nexport const elements = [{ tag: 'qti-graphic-associate-interaction', ctor: QtiGraphicAssociateInteraction }] as const;\n\nexport { QtiGraphicAssociateInteraction };\n","import { QtiGraphicGapMatchInteraction } from './qti-graphic-gap-match-interaction';\n\nexport const elements = [{ tag: 'qti-graphic-gap-match-interaction', ctor: QtiGraphicGapMatchInteraction }] as const;\n\nexport { QtiGraphicGapMatchInteraction };\n","import { QtiGraphicOrderInteraction } from './qti-graphic-order-interaction';\n\nexport const elements = [{ tag: 'qti-graphic-order-interaction', ctor: QtiGraphicOrderInteraction }] as const;\n\nexport { QtiGraphicOrderInteraction };\n","import { QtiHotspotInteraction } from './qti-hotspot-interaction';\n\nexport const elements = [{ tag: 'qti-hotspot-interaction', ctor: QtiHotspotInteraction }] as const;\n\nexport { QtiHotspotInteraction };\n","import { QtiHottextInteraction } from './qti-hottext-interaction';\n\nexport const elements = [{ tag: 'qti-hottext-interaction', ctor: QtiHottextInteraction }] as const;\n\nexport { QtiHottextInteraction };\n","import { QtiInlineChoiceInteraction } from './qti-inline-choice-interaction';\n\nexport const elements = [{ tag: 'qti-inline-choice-interaction', ctor: QtiInlineChoiceInteraction }] as const;\n\nexport { QtiInlineChoiceInteraction };\n","import { QtiMatchInteraction } from './qti-match-interaction';\n\nexport const elements = [{ tag: 'qti-match-interaction', ctor: QtiMatchInteraction }] as const;\n\nexport { QtiMatchInteraction };\n","import { QtiOrderInteraction } from './qti-order-interaction';\n\nexport const elements = [{ tag: 'qti-order-interaction', ctor: QtiOrderInteraction }] as const;\n\nexport { QtiOrderInteraction };\n","import { QtiPortableCustomInteraction } from './qti-portable-custom-interaction';\n\nimport type { ItemContext } from '@qti-components/base';\n\n/**\n * Test-specific extension of QtiPortableCustomInteraction that adds methods\n * for interacting with the iframe content in tests.\n */\nexport class QtiPortableCustomInteractionTest extends QtiPortableCustomInteraction {\n #recreatingIframe = false;\n\n /** Wait until the PCI has completed its iframe handshake, even if it became ready before the test started. */\n public async waitForReady(timeout = 5000): Promise<void> {\n if (this._interactionReady) return;\n\n await new Promise<void>((resolve, reject) => {\n const loadHandler = () => {\n window.clearTimeout(timeoutId);\n resolve();\n };\n const timeoutId = window.setTimeout(() => {\n this.removeEventListener('qti-portable-custom-interaction-loaded', loadHandler);\n reject(new Error(`Portable custom interaction did not become ready within ${timeout}ms`));\n }, timeout);\n\n this.addEventListener('qti-portable-custom-interaction-loaded', loadHandler, { once: true });\n });\n }\n\n /**\n * Gets the HTML content of the iframe for testing purposes\n * @returns Promise that resolves with the HTML content string\n */\n async getIFrameContent(): Promise<string> {\n return new Promise(resolve => {\n const messageId = `get-content-${Date.now()}`;\n\n const messageHandler = (event: MessageEvent) => {\n const { data } = event;\n if (\n data?.source === 'qti-pci-iframe' &&\n (!data?.responseIdentifier || data?.responseIdentifier === this.responseIdentifier) &&\n data?.method === 'getContentResponse' &&\n data?.messageId === messageId\n ) {\n window.removeEventListener('message', messageHandler);\n resolve(data.content);\n }\n };\n\n window.addEventListener('message', messageHandler);\n\n this.sendMessageToIframe('getContent', { messageId });\n\n // Set timeout to avoid hanging promises\n setTimeout(() => {\n window.removeEventListener('message', messageHandler);\n resolve('');\n }, 5000);\n });\n }\n\n // Expose the protected context\n public setTestContext(newContext: ItemContext): void {\n this.context = newContext;\n\n // If needed, force an update to push the context changes to the iframe\n this.updateComplete.then(() => {\n // const responseVal = this.responseVariablesToQtiVariableJSON(\n // (newContext?.variables?.find(v => v.identifier === this.responseIdentifier)?.value as string | string[]) ||\n // null,\n // newContext?.variables?.find(v => v.identifier === this.responseIdentifier)?.cardinality || 'single',\n // newContext?.variables?.find(v => v.identifier === this.responseIdentifier)?.baseType || 'string'\n // );\n this.value = newContext?.variables?.find(v => v.identifier === this.responseIdentifier).value as string;\n // this.recreateIframe();\n });\n }\n\n /**\n * Recreates the iframe completely\n * @returns Promise that resolves when the iframe is loaded\n */\n public async recreateIframe(): Promise<void> {\n this.#recreatingIframe = true;\n\n try {\n // Remove existing iframe if it exists\n if (this.iframe) {\n this._iframeLoaded = false;\n this.iframe.remove();\n }\n\n this._pendingMessages = [];\n\n // Create a new iframe\n this.createIframe();\n\n await this.waitForReady();\n } finally {\n this.#recreatingIframe = false;\n }\n }\n\n /**\n * Override the original disconnectedCallback to handle iframe recreation\n */\n override disconnectedCallback(): void {\n // Only call super if we're not in the process of recreating the iframe\n // This prevents removing event listeners that we still need\n if (!this.#recreatingIframe) {\n super.disconnectedCallback();\n }\n }\n\n /**\n * Simulates a mouse click at specific coordinates within the iframe\n * @param x The x coordinate\n * @param y The y coordinate\n * @returns Promise that resolves when the click is performed\n */\n async iFrameMouseClick(x: number, y: number): Promise<void> {\n return new Promise(resolve => {\n const messageId = `click-${Date.now()}`;\n\n const messageHandler = (event: MessageEvent) => {\n const { data } = event;\n if (\n data?.source === 'qti-pci-iframe' &&\n (!data?.responseIdentifier || data?.responseIdentifier === this.responseIdentifier) &&\n data?.method === 'clickResponse' &&\n data?.messageId === messageId\n ) {\n window.removeEventListener('message', messageHandler);\n resolve();\n }\n };\n\n window.addEventListener('message', messageHandler);\n\n this.sendMessageToIframe('simulateClick', { x, y, messageId });\n\n // Set timeout to avoid hanging promises\n setTimeout(() => {\n window.removeEventListener('message', messageHandler);\n resolve();\n }, 5000);\n });\n }\n\n /**\n * Clicks on an element identified by a CSS selector\n * @param selector The CSS selector string\n * @returns Promise that resolves with boolean indicating if the element was found and clicked\n */\n async iFrameClickOnElement(selector: string): Promise<boolean> {\n return new Promise(resolve => {\n const messageId = `click-selector-${Date.now()}`;\n\n const messageHandler = (event: MessageEvent) => {\n const { data } = event;\n if (\n data?.source === 'qti-pci-iframe' &&\n (!data?.responseIdentifier || data?.responseIdentifier === this.responseIdentifier) &&\n data?.method === 'clickSelectorResponse' &&\n data?.messageId === messageId\n ) {\n window.removeEventListener('message', messageHandler);\n resolve(data.success);\n }\n };\n\n window.addEventListener('message', messageHandler);\n\n this.sendMessageToIframe('clickOnSelector', { selector, messageId });\n\n // Set timeout to avoid hanging promises\n setTimeout(() => {\n window.removeEventListener('message', messageHandler);\n resolve(false);\n }, 5000);\n });\n }\n\n /**\n * Clicks on an element containing the specified text\n * @param text The text to search for within elements\n * @returns Promise that resolves with boolean indicating if the element was found and clicked\n */\n async iFrameClickOnElementByText(text: string): Promise<boolean> {\n return new Promise(resolve => {\n const messageId = `click-text-${Date.now()}`;\n\n const messageHandler = (event: MessageEvent) => {\n const { data } = event;\n if (\n data?.source === 'qti-pci-iframe' &&\n (!data?.responseIdentifier || data?.responseIdentifier === this.responseIdentifier) &&\n data?.method === 'clickTextResponse' &&\n data?.messageId === messageId\n ) {\n window.removeEventListener('message', messageHandler);\n resolve(data.success);\n }\n };\n\n window.addEventListener('message', messageHandler);\n\n this.sendMessageToIframe('clickOnElementByText', { text, messageId });\n\n // Set timeout to avoid hanging promises\n setTimeout(() => {\n window.removeEventListener('message', messageHandler);\n resolve(false);\n }, 5000);\n });\n }\n\n /**\n * Sets the value of an input element identified by a CSS selector\n * @param selector The CSS selector string\n * @param value The value to set\n * @returns Promise that resolves with boolean indicating if the element was found and value was set\n */\n async iFrameSetValueElement(selector: string, value: string): Promise<boolean> {\n return new Promise(resolve => {\n const messageId = `set-value-${Date.now()}`;\n\n const messageHandler = (event: MessageEvent) => {\n const { data } = event;\n if (\n data?.source === 'qti-pci-iframe' &&\n (!data?.responseIdentifier || data?.responseIdentifier === this.responseIdentifier) &&\n data?.method === 'setValueResponse' &&\n data?.messageId === messageId\n ) {\n window.removeEventListener('message', messageHandler);\n resolve(data.success);\n }\n };\n\n window.addEventListener('message', messageHandler);\n\n this.sendMessageToIframe('setValueElement', { selector, value, messageId });\n\n // Set timeout to avoid hanging promises\n setTimeout(() => {\n window.removeEventListener('message', messageHandler);\n resolve(false);\n }, 5000);\n });\n }\n\n /**\n * Gets the bounding client rect for an element inside the iframe\n * @param selector The CSS selector string\n * @returns Promise that resolves with the rect or null\n */\n async iFrameGetBoundingClientRect(\n selector: string\n ): Promise<{ left: number; top: number; width: number; height: number } | null> {\n return new Promise(resolve => {\n const messageId = `get-bounding-rect-${Date.now()}`;\n\n const messageHandler = (event: MessageEvent) => {\n const { data } = event;\n if (\n data?.source === 'qti-pci-iframe' &&\n (!data?.responseIdentifier || data?.responseIdentifier === this.responseIdentifier) &&\n data?.method === 'getBoundingRectResponse' &&\n data?.messageId === messageId\n ) {\n window.removeEventListener('message', messageHandler);\n resolve(data.rect ?? null);\n }\n };\n\n window.addEventListener('message', messageHandler);\n\n this.sendMessageToIframe('getBoundingRect', { selector, messageId });\n\n setTimeout(() => {\n window.removeEventListener('message', messageHandler);\n resolve(null);\n }, 5000);\n });\n }\n\n /**\n * Sets the value of an input element containing the specified text\n * @param text The text to search for within elements\n * @param value The value to set\n * @returns Promise that resolves with boolean indicating if the element was found and value was set\n */\n async iFrameSetValueElementByText(text: string, value: string): Promise<boolean> {\n return new Promise(resolve => {\n const messageId = `set-value-text-${Date.now()}`;\n\n const messageHandler = (event: MessageEvent) => {\n const { data } = event;\n if (\n data?.source === 'qti-pci-iframe' &&\n (!data?.responseIdentifier || data?.responseIdentifier === this.responseIdentifier) &&\n data?.method === 'setValueByTextResponse' &&\n data?.messageId === messageId\n ) {\n window.removeEventListener('message', messageHandler);\n resolve(data.success);\n }\n };\n\n window.addEventListener('message', messageHandler);\n\n this.sendMessageToIframe('setValueElementByText', { text, value, messageId });\n\n // Set timeout to avoid hanging promises\n setTimeout(() => {\n window.removeEventListener('message', messageHandler);\n resolve(false);\n }, 5000);\n });\n }\n\n /**\n * Performs a mousedown event on an element identified by a CSS selector\n * @param selector The CSS selector string\n * @returns Promise that resolves with boolean indicating if the element was found and mousedown was performed\n */\n async iFrameMousedownOnElement(selector: string): Promise<boolean> {\n return new Promise(resolve => {\n const messageId = `mousedown-selector-${Date.now()}`;\n\n const messageHandler = (event: MessageEvent) => {\n const { data } = event;\n if (\n data?.source === 'qti-pci-iframe' &&\n (!data?.responseIdentifier || data?.responseIdentifier === this.responseIdentifier) &&\n data?.method === 'mousedownSelectorResponse' &&\n data?.messageId === messageId\n ) {\n window.removeEventListener('message', messageHandler);\n resolve(data.success);\n }\n };\n\n window.addEventListener('message', messageHandler);\n\n this.sendMessageToIframe('mousedownOnSelector', { selector, messageId });\n\n // Set timeout to avoid hanging promises\n setTimeout(() => {\n window.removeEventListener('message', messageHandler);\n resolve(false);\n }, 5000);\n });\n }\n\n /**\n * Override the original generateIframeContent method to include\n * the test message handlers in the iframe HTML\n */\n override generateIframeContent(): string {\n // Get the original iframe HTML from the parent class\n const originalContent = super.generateIframeContent();\n\n // Insert our test message handlers before the closing </script> tag\n const testHandlers = `\n // Test helper functions for QtiPortableCustomInteractionTest\n // Base iframe implementation already provides PCIManager.getContent\n \n // Base iframe implementation already provides PCIManager.simulateClick\n \n // Base iframe implementation already provides PCIManager.clickOnSelector\n \n // Base iframe implementation already provides PCIManager.clickOnElementByText\n \n // Base iframe implementation already provides PCIManager.setValueElement\n \n function deepQuerySelector(root, selector) {\n if (!root) return null;\n try {\n const direct = root.querySelector ? root.querySelector(selector) : null;\n if (direct) return direct;\n } catch (e) {\n // ignore invalid selector for this root\n }\n if (!root.querySelectorAll) return null;\n const nodes = root.querySelectorAll('*');\n for (const node of nodes) {\n if (node && node.shadowRoot) {\n const found = deepQuerySelector(node.shadowRoot, selector);\n if (found) return found;\n }\n }\n return null;\n }\n\n function deepFindElementByExactText(root, text) {\n if (!root || !text) return null;\n if (root.querySelectorAll) {\n const nodes = root.querySelectorAll('*');\n for (const node of nodes) {\n if ((node.textContent || '').trim() === text) return node;\n if (node.shadowRoot) {\n const found = deepFindElementByExactText(node.shadowRoot, text);\n if (found) return found;\n }\n }\n }\n return null;\n }\n\n function escapeSelectorId(id) {\n try {\n if (window.CSS && typeof window.CSS.escape === 'function') return window.CSS.escape(id);\n } catch (e) {\n // ignore\n }\n return String(id).replace(/([ #;?%&,.+*~\\\\':\"!^$[\\\\]()=>|\\\\/])/g, '\\\\\\\\$1');\n }\n\n PCIManager.setValueElementByText = function(params) {\n const messageId = params && params.messageId;\n try {\n const text = params && params.text;\n const value = params && params.value;\n\n const textEl = text ? deepFindElementByExactText(document, text) : null;\n let target = null;\n\n if (textEl) {\n const tag = (textEl.tagName || '').toUpperCase();\n if (tag === 'INPUT' || tag === 'TEXTAREA' || tag === 'SELECT') {\n target = textEl;\n } else if (tag === 'LABEL' && textEl.htmlFor) {\n const id = escapeSelectorId(textEl.htmlFor);\n target = deepQuerySelector(document, '#' + id);\n }\n\n if (!target) {\n let parent = textEl.parentElement;\n while (parent) {\n const candidate = parent.querySelector ? parent.querySelector('input, textarea, select') : null;\n if (candidate) {\n target = candidate;\n break;\n }\n parent = parent.parentElement;\n }\n }\n }\n\n const success = !!target && setValueOnElement(target, value);\n window.parent.postMessage(\n {\n source: 'qti-pci-iframe',\n responseIdentifier: PCIManager.responseIdentifier,\n method: 'setValueByTextResponse',\n messageId: messageId,\n success: success\n },\n '*'\n );\n } catch (error) {\n console.error('Error setting value by text:', error);\n window.parent.postMessage(\n {\n source: 'qti-pci-iframe',\n responseIdentifier: PCIManager.responseIdentifier,\n method: 'setValueByTextResponse',\n messageId: messageId,\n success: false,\n error: error.toString()\n },\n '*'\n );\n }\n };\n \n PCIManager.mousedownOnSelector = function(params) {\n try {\n const element = params && params.selector ? deepQuerySelector(document, params.selector) : null;\n \n let success = false;\n \n if (element) {\n const rect = element.getBoundingClientRect();\n const mousedownEvent = new MouseEvent('mousedown', {\n bubbles: true,\n cancelable: true,\n view: window,\n clientX: rect.left + rect.width / 2,\n clientY: rect.top + rect.height / 2\n });\n element.dispatchEvent(mousedownEvent);\n success = true;\n }\n \n window.parent.postMessage({\n source: 'qti-pci-iframe',\n responseIdentifier: PCIManager.responseIdentifier,\n method: 'mousedownSelectorResponse',\n messageId: params.messageId,\n success\n }, '*');\n } catch (error) {\n console.error('Error performing mousedown on selector:', error);\n window.parent.postMessage({\n source: 'qti-pci-iframe',\n responseIdentifier: PCIManager.responseIdentifier,\n method: 'mousedownSelectorResponse',\n messageId: params.messageId,\n success: false,\n error: error.toString()\n }, '*');\n }\n };\n \n // Helper function for setting values on elements\n function setValueOnElement(element, value) {\n if (element.tagName === 'INPUT' || element.tagName === 'TEXTAREA') {\n element.value = value;\n element.dispatchEvent(new Event('input', { bubbles: true }));\n element.dispatchEvent(new Event('change', { bubbles: true }));\n return true;\n } else if (element.tagName === 'SELECT') {\n element.value = value;\n element.dispatchEvent(new Event('change', { bubbles: true }));\n return true;\n } else if (element.isContentEditable) {\n element.textContent = value;\n element.dispatchEvent(new Event('input', { bubbles: true }));\n return true;\n }\n return false;\n }\n \n // Add test-related message handlers (do not override global handlers)\n let expectedParentOriginTest = null;\n window.addEventListener(\n 'message',\n function(event) {\n const { data } = event;\n\n if (event.source !== window.parent || !data || data.source !== 'qti-portable-custom-interaction') return;\n if (expectedParentOriginTest === null) expectedParentOriginTest = event.origin;\n else if (event.origin !== expectedParentOriginTest) return;\n if (data.responseIdentifier && data.responseIdentifier !== PCIManager.responseIdentifier) return;\n\n switch (data.method) {\n case 'setValueElementByText':\n PCIManager.setValueElementByText(data.params);\n return;\n case 'mousedownOnSelector':\n PCIManager.mousedownOnSelector(data.params);\n return;\n }\n },\n true\n );`;\n\n // Find the position to insert our test handlers\n const insertPosition = originalContent.lastIndexOf('</script>');\n\n // Insert our handlers\n const modifiedContent =\n originalContent.substring(0, insertPosition) + testHandlers + originalContent.substring(insertPosition);\n\n return modifiedContent;\n }\n}\n\ndeclare global {\n interface HTMLElementTagNameMap {\n 'qti-portable-custom-interaction-test': QtiPortableCustomInteractionTest;\n }\n}\n","import { QtiPortableCustomInteraction } from './qti-portable-custom-interaction';\nimport { QtiPortableCustomInteractionTest } from './qti-portable-custom-test-interaction';\n\nexport const elements = [\n { tag: 'qti-portable-custom-interaction', ctor: QtiPortableCustomInteraction },\n { tag: 'qti-portable-custom-interaction-test', ctor: QtiPortableCustomInteractionTest }\n] as const;\n\nexport { QtiPortableCustomInteraction, QtiPortableCustomInteractionTest };\n","import { QtiSelectPointInteraction } from './qti-select-point-interaction';\n\nexport const elements = [{ tag: 'qti-select-point-interaction', ctor: QtiSelectPointInteraction }] as const;\n\nexport { QtiSelectPointInteraction };\n","import { QtiSliderInteraction } from './qti-slider-interaction';\n\nexport const elements = [{ tag: 'qti-slider-interaction', ctor: QtiSliderInteraction }] as const;\n\nexport { QtiSliderInteraction };\n","import { QtiTextEntryInteraction } from './qti-text-entry-interaction';\n\nexport const elements = [{ tag: 'qti-text-entry-interaction', ctor: QtiTextEntryInteraction }] as const;\n\nexport { QtiTextEntryInteraction };\n"],"mappings":"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","names":["n","i","__decorate","n","i","__decorate","n","i","generateMap","list","start","end","map","Map","i","set","repeat","directive","Directive","partInfo","super","type","PartType","CHILD","Error","items","keyFnOrTemplate","template","keyFn","keys","values","index","item","this","_getValuesAndKeys","containerPart","oldParts","getCommittedValue","newValues","newKeys","Array","isArray","_itemKeys","oldKeys","newParts","newKeyToIndexMap","oldKeyToIndexMap","oldHead","oldTail","length","newHead","newTail","setChildPartValue","insertPart","has","oldIndex","get","oldPart","newPart","removePart","setCommittedValue","noChange","i","c","__decorate","n","i","__decorate","n","__decorate","n","WeakMap","r","e","subscriber","subscriberState","Subscriber","Observable","value","v","p","window","e","i","elements","n","identifier","c","__decorate","n","elements","c","i","__decorate","c","__decorate","e","n","c","b","__decorate","n","__decorate","n","o","__decorate","n","i","p","o","c","e","i","__decorate","n","SlottedBase","e","e","i","hotspot","b","e","o","i","c","__decorate","n","e","v","c","r","__decorate","n","SlottedBase","i","c","v","__decorate","n","e","v","n","i","__decorate","important","importantFlag","styleMap","directive","Directive","partInfo","super","type","PartType","ATTRIBUTE","name","strings","length","Error","styleInfo","Object","keys","reduce","style","prop","value","includes","replace","toLowerCase","part","element","this","_previousStyleProperties","Set","render","delete","removeProperty","add","isImportant","endsWith","setProperty","slice","noChange","elements","c","o","e","i","__decorate","n","e","__decorate","n","createRef","Ref","lastElementForContextAndCallback","WeakMap","ref","directive","AsyncDirective","_ref","nothing","part","refChanged","this","_updateRefValue","undefined","_lastElementForRef","_element","_context","options","host","element","isConnected","context","globalThis","lastElementForCallback","get","set","call","value","disconnected","reconnected","e","o","__decorate","n","elements","elements","elements","elements","elements","elements","elements","elements","elements","elements","elements","v","elements","elements","elements","elements"]}
|