@qti-components/order-interaction 1.1.4 → 2.0.0
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/dist/elements.d.ts +6 -0
- package/dist/elements.js +4 -0
- package/dist/elements.js.map +1 -0
- package/dist/qti-order-interaction.d.ts +34 -6
- package/dist/qti-order-interaction.js +55 -94
- package/dist/qti-order-interaction.js.map +1 -1
- package/dist/qti-order-interaction.styles.d.ts +18 -1
- package/dist/qti-order-interaction.styles.js +234 -83
- package/dist/qti-order-interaction.styles.js.map +1 -1
- package/dist/register.js +6 -2
- package/dist/register.js.map +1 -1
- package/package.json +10 -4
package/dist/elements.js
ADDED
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"elements.js","sourceRoot":"","sources":["../src/elements.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,mBAAmB,EAAE,MAAM,yBAAyB,CAAC;AAE9D,MAAM,CAAC,MAAM,QAAQ,GAAG,CAAC,EAAE,GAAG,EAAE,uBAAuB,EAAE,IAAI,EAAE,mBAAmB,EAAE,CAAU,CAAC;AAE/F,OAAO,EAAE,mBAAmB,EAAE,CAAC","sourcesContent":["import { QtiOrderInteraction } from './qti-order-interaction';\n\nexport const elements = [{ tag: 'qti-order-interaction', ctor: QtiOrderInteraction }] as const;\n\nexport { QtiOrderInteraction };\n"]}
|
|
@@ -1,17 +1,45 @@
|
|
|
1
1
|
import { Interaction } from '@qti-components/base';
|
|
2
2
|
declare const QtiOrderInteraction_base: (abstract new (...args: any[]) => import("@qti-components/interactions-core/mixins/drag-drop-observables").DragDropSlottedSortable) & (abstract new (...args: any[]) => import("@qti-components/interactions-core/mixins/drag-drop-observables").DragDropSlotted) & typeof Interaction;
|
|
3
|
+
/**
|
|
4
|
+
* Order interaction: candidates arrange choices into a target sequence.
|
|
5
|
+
*
|
|
6
|
+
* @customElement qti-order-interaction
|
|
7
|
+
*
|
|
8
|
+
* @attr {string} response-identifier - Required. Identifier of the bound response variable.
|
|
9
|
+
* @attr {'horizontal'|'vertical'} [orientation=vertical] - Layout direction of the drop
|
|
10
|
+
* sequence. Unlike on `qti-choice-interaction`, QTI does not deprecate this for order.
|
|
11
|
+
* @attr {boolean} [shuffle=false] - Requests choice shuffling. Applied by the transform
|
|
12
|
+
* pipeline (`qti-transformers`), not by this element.
|
|
13
|
+
* @attr {number} [min-associations=1] - Non-QTI vocabulary inherited from the drag-drop
|
|
14
|
+
* mixin; currently the only way to set the lower bound. QTI spells this `min-choices`.
|
|
15
|
+
* @attr {number} [max-associations=0] - Non-QTI vocabulary inherited from the drag-drop
|
|
16
|
+
* mixin; currently the only way to set the upper bound. QTI spells this `max-choices`.
|
|
17
|
+
* @attr {number} min-choices - Not implemented. The QTI-correct spelling of the lower bound.
|
|
18
|
+
* See plans/interaction-attribute-spec-conformance.md.
|
|
19
|
+
* @attr {number} max-choices - Not implemented. The QTI-correct spelling of the upper bound.
|
|
20
|
+
* See plans/interaction-attribute-spec-conformance.md.
|
|
21
|
+
* @attr {boolean} [auto-size-dropzones=true] - Extension, not QTI. Sizes every drop target to
|
|
22
|
+
* the widest chip so placement does not reflow the layout. On by default: an order slot is a
|
|
23
|
+
* socket cut to one chip, and both axes are measured (see DROP-SIZING.md).
|
|
24
|
+
* @attr {boolean} [disable-animations=false] - Extension, not QTI. Disables the FLIP move
|
|
25
|
+
* animation.
|
|
26
|
+
*
|
|
27
|
+
* @slot prompt - The prompt shown above the interaction.
|
|
28
|
+
* @slot drags - The draggable choice sources.
|
|
29
|
+
*
|
|
30
|
+
* @csspart container - The outer container wrapping drags and drops.
|
|
31
|
+
* @csspart drags - Wrapper around the drag sources slot.
|
|
32
|
+
* @csspart drops - The drop-target region.
|
|
33
|
+
* @csspart drop - Each individual drop target.
|
|
34
|
+
* @csspart drag - A choice that has been placed into a drop target.
|
|
35
|
+
*/
|
|
3
36
|
export declare class QtiOrderInteraction extends QtiOrderInteraction_base {
|
|
4
|
-
|
|
5
|
-
static styles: import("lit").CSSResult;
|
|
37
|
+
static styles: import("lit").CSSResult[];
|
|
6
38
|
protected childrenMap: Element[];
|
|
7
39
|
protected nrChoices: number;
|
|
8
|
-
correctResponses: string[];
|
|
9
|
-
showCorrectResponses: boolean;
|
|
10
40
|
/** orientation of choices */
|
|
11
41
|
orientation: 'horizontal' | 'vertical';
|
|
12
42
|
render(): import("lit").TemplateResult<1>;
|
|
13
|
-
toggleCorrectResponse(show: boolean): void;
|
|
14
|
-
toggleCandidateCorrection(show: boolean): void;
|
|
15
43
|
getValue(val: string[]): string[];
|
|
16
44
|
protected getResponse(): string[];
|
|
17
45
|
shouldTreatBlockedMaxAsInvalid(): boolean;
|
|
@@ -5,36 +5,51 @@ var __decorate = (this && this.__decorate) || function (decorators, target, key,
|
|
|
5
5
|
return c > 3 && r && Object.defineProperty(target, key, r), r;
|
|
6
6
|
};
|
|
7
7
|
import { html } from 'lit';
|
|
8
|
+
import { repeat } from 'lit/directives/repeat.js';
|
|
8
9
|
import { property, state } from 'lit/decorators.js';
|
|
9
10
|
import { Interaction } from '@qti-components/base';
|
|
10
11
|
import { DragDropSlottedMixin, DragDropSlottedSortableMixin } from '@qti-components/interactions-core/mixins/drag-drop-observables';
|
|
11
12
|
import styles from './qti-order-interaction.styles';
|
|
12
|
-
const SlottedBase = DragDropSlottedMixin(Interaction, `qti-simple-choice`, 'drop
|
|
13
|
+
const SlottedBase = DragDropSlottedMixin(Interaction, `qti-simple-choice`, `[part~='drop']`, `slot[part~='drags']`);
|
|
14
|
+
/**
|
|
15
|
+
* Order interaction: candidates arrange choices into a target sequence.
|
|
16
|
+
*
|
|
17
|
+
* @customElement qti-order-interaction
|
|
18
|
+
*
|
|
19
|
+
* @attr {string} response-identifier - Required. Identifier of the bound response variable.
|
|
20
|
+
* @attr {'horizontal'|'vertical'} [orientation=vertical] - Layout direction of the drop
|
|
21
|
+
* sequence. Unlike on `qti-choice-interaction`, QTI does not deprecate this for order.
|
|
22
|
+
* @attr {boolean} [shuffle=false] - Requests choice shuffling. Applied by the transform
|
|
23
|
+
* pipeline (`qti-transformers`), not by this element.
|
|
24
|
+
* @attr {number} [min-associations=1] - Non-QTI vocabulary inherited from the drag-drop
|
|
25
|
+
* mixin; currently the only way to set the lower bound. QTI spells this `min-choices`.
|
|
26
|
+
* @attr {number} [max-associations=0] - Non-QTI vocabulary inherited from the drag-drop
|
|
27
|
+
* mixin; currently the only way to set the upper bound. QTI spells this `max-choices`.
|
|
28
|
+
* @attr {number} min-choices - Not implemented. The QTI-correct spelling of the lower bound.
|
|
29
|
+
* See plans/interaction-attribute-spec-conformance.md.
|
|
30
|
+
* @attr {number} max-choices - Not implemented. The QTI-correct spelling of the upper bound.
|
|
31
|
+
* See plans/interaction-attribute-spec-conformance.md.
|
|
32
|
+
* @attr {boolean} [auto-size-dropzones=true] - Extension, not QTI. Sizes every drop target to
|
|
33
|
+
* the widest chip so placement does not reflow the layout. On by default: an order slot is a
|
|
34
|
+
* socket cut to one chip, and both axes are measured (see DROP-SIZING.md).
|
|
35
|
+
* @attr {boolean} [disable-animations=false] - Extension, not QTI. Disables the FLIP move
|
|
36
|
+
* animation.
|
|
37
|
+
*
|
|
38
|
+
* @slot prompt - The prompt shown above the interaction.
|
|
39
|
+
* @slot drags - The draggable choice sources.
|
|
40
|
+
*
|
|
41
|
+
* @csspart container - The outer container wrapping drags and drops.
|
|
42
|
+
* @csspart drags - Wrapper around the drag sources slot.
|
|
43
|
+
* @csspart drops - The drop-target region.
|
|
44
|
+
* @csspart drop - Each individual drop target.
|
|
45
|
+
* @csspart drag - A choice that has been placed into a drop target.
|
|
46
|
+
*/
|
|
13
47
|
export class QtiOrderInteraction extends DragDropSlottedSortableMixin(SlottedBase, '[qti-draggable="true"]') {
|
|
14
48
|
constructor() {
|
|
15
49
|
super(...arguments);
|
|
16
50
|
this.nrChoices = 0;
|
|
17
|
-
this.correctResponses = [];
|
|
18
|
-
this.showCorrectResponses = false;
|
|
19
51
|
}
|
|
20
52
|
static { this.styles = styles; }
|
|
21
|
-
#getCorrectOrderEntries() {
|
|
22
|
-
const responseVariable = this.responseVariable;
|
|
23
|
-
if (!responseVariable?.correctResponse) {
|
|
24
|
-
return [];
|
|
25
|
-
}
|
|
26
|
-
const response = Array.isArray(responseVariable.correctResponse)
|
|
27
|
-
? responseVariable.correctResponse
|
|
28
|
-
: [responseVariable.correctResponse];
|
|
29
|
-
return response
|
|
30
|
-
.map((entry, index) => {
|
|
31
|
-
const [identifier, dropId] = entry.split(' ');
|
|
32
|
-
const parsedDropIndex = dropId?.startsWith('droplist') ? parseInt(dropId.replace('droplist', ''), 10) : index;
|
|
33
|
-
const dropIndex = Number.isNaN(parsedDropIndex) ? index : parsedDropIndex;
|
|
34
|
-
return { identifier, dropIndex };
|
|
35
|
-
})
|
|
36
|
-
.filter(entry => Boolean(entry.identifier));
|
|
37
|
-
}
|
|
38
53
|
render() {
|
|
39
54
|
const choices = Array.from(this.querySelectorAll('qti-simple-choice'));
|
|
40
55
|
if (this.nrChoices < choices.length) {
|
|
@@ -44,69 +59,20 @@ export class QtiOrderInteraction extends DragDropSlottedSortableMixin(SlottedBas
|
|
|
44
59
|
<div part="container">
|
|
45
60
|
<slot part="drags"> </slot>
|
|
46
61
|
<div part="drops">
|
|
47
|
-
${[...Array(this.nrChoices)].map((_, i) =>
|
|
62
|
+
${[...Array(this.nrChoices)].map((_, i) => {
|
|
63
|
+
const identifier = `droplist${i}`;
|
|
64
|
+
// The chips are rendered here, from the interaction's placement map, rather than being
|
|
65
|
+
// appended into this div by handleDrop. `data-declarative-drops` is what tells the
|
|
66
|
+
// mixin to keep them in the map and leave this element's children alone.
|
|
67
|
+
const drags = this._dragDrop?.nodesByTarget?.[identifier] ?? [];
|
|
68
|
+
return html `<div role="region" part="drop" data-declarative-drops identifier=${identifier}>
|
|
69
|
+
${repeat(drags, node => node.getAttribute('identifier'), node => node)}
|
|
70
|
+
</div>`;
|
|
71
|
+
})}
|
|
48
72
|
</div>
|
|
73
|
+
<div id="validation-message" part="message" role="alert" style="display:none;"></div>
|
|
49
74
|
</div>`;
|
|
50
75
|
}
|
|
51
|
-
toggleCorrectResponse(show) {
|
|
52
|
-
// Always start by removing old correct answers
|
|
53
|
-
this.shadowRoot.querySelectorAll('.correct-option').forEach(option => option.remove());
|
|
54
|
-
if (show) {
|
|
55
|
-
const entries = this.#getCorrectOrderEntries();
|
|
56
|
-
const labelsByIdentifier = new Map();
|
|
57
|
-
Array.from(this.querySelectorAll('qti-simple-choice')).forEach(choice => {
|
|
58
|
-
const id = choice.getAttribute('identifier');
|
|
59
|
-
const label = choice.textContent?.trim();
|
|
60
|
-
if (id && label) {
|
|
61
|
-
labelsByIdentifier.set(id, label);
|
|
62
|
-
}
|
|
63
|
-
});
|
|
64
|
-
entries.forEach(({ identifier, dropIndex }) => {
|
|
65
|
-
const label = labelsByIdentifier.get(identifier);
|
|
66
|
-
if (!label)
|
|
67
|
-
return;
|
|
68
|
-
const relativeDrop = this.shadowRoot.querySelector(`drop-list[identifier="droplist${dropIndex}"]`);
|
|
69
|
-
if (!relativeDrop)
|
|
70
|
-
return;
|
|
71
|
-
const span = document.createElement('span');
|
|
72
|
-
span.classList.add('correct-option');
|
|
73
|
-
span.textContent = label;
|
|
74
|
-
span.style.border = '1px solid var(--qti-correct)';
|
|
75
|
-
span.style.borderRadius = '4px';
|
|
76
|
-
span.style.padding = '2px 4px';
|
|
77
|
-
span.style.display = 'inline-block';
|
|
78
|
-
span.style.marginTop = '4px';
|
|
79
|
-
relativeDrop.insertAdjacentElement('afterend', span);
|
|
80
|
-
});
|
|
81
|
-
}
|
|
82
|
-
}
|
|
83
|
-
toggleCandidateCorrection(show) {
|
|
84
|
-
super.toggleCandidateCorrection(show);
|
|
85
|
-
const placedChoices = Array.from(this.shadowRoot.querySelectorAll('drop-list [qti-draggable="true"]'));
|
|
86
|
-
placedChoices.forEach(choice => {
|
|
87
|
-
choice.internals.states.delete('candidate-correct');
|
|
88
|
-
choice.internals.states.delete('candidate-incorrect');
|
|
89
|
-
});
|
|
90
|
-
if (!show)
|
|
91
|
-
return;
|
|
92
|
-
const entries = this.#getCorrectOrderEntries();
|
|
93
|
-
const correctByDrop = new Map();
|
|
94
|
-
entries.forEach(entry => correctByDrop.set(entry.dropIndex, entry.identifier));
|
|
95
|
-
const dropLists = Array.from(this.shadowRoot.querySelectorAll('drop-list'));
|
|
96
|
-
dropLists.forEach((dropList, index) => {
|
|
97
|
-
const placedChoice = dropList.querySelector('[qti-draggable="true"]');
|
|
98
|
-
if (!placedChoice)
|
|
99
|
-
return;
|
|
100
|
-
const expectedIdentifier = correctByDrop.get(index);
|
|
101
|
-
const actualIdentifier = placedChoice.getAttribute('identifier');
|
|
102
|
-
if (expectedIdentifier && actualIdentifier === expectedIdentifier) {
|
|
103
|
-
placedChoice.internals.states.add('candidate-correct');
|
|
104
|
-
}
|
|
105
|
-
else {
|
|
106
|
-
placedChoice.internals.states.add('candidate-incorrect');
|
|
107
|
-
}
|
|
108
|
-
});
|
|
109
|
-
}
|
|
110
76
|
// some interactions have a different way of getting the response
|
|
111
77
|
// this is called from the drag and drop mixin class
|
|
112
78
|
// you have to implement your own getResponse method in the superclass
|
|
@@ -120,13 +86,12 @@ export class QtiOrderInteraction extends DragDropSlottedSortableMixin(SlottedBas
|
|
|
120
86
|
// cause they are different for some interactions.
|
|
121
87
|
// MH: is this function called? Shouldn't we use getValue?
|
|
122
88
|
getResponse() {
|
|
123
|
-
const droppables = Array.from(this.shadowRoot.querySelectorAll('drop
|
|
124
|
-
|
|
125
|
-
|
|
126
|
-
|
|
127
|
-
|
|
128
|
-
|
|
129
|
-
return response;
|
|
89
|
+
const droppables = Array.from(this.shadowRoot.querySelectorAll(`[part~='drop']`));
|
|
90
|
+
// Read placement, not the DOM. The DOM is rendered *from* placement now, so querying it back
|
|
91
|
+
// out would be asking the same question twice and hoping for the same answer.
|
|
92
|
+
return droppables.map(droppable => this.chipsIn(droppable)
|
|
93
|
+
.map(chip => chip.getAttribute('identifier'))
|
|
94
|
+
.join(' '));
|
|
130
95
|
}
|
|
131
96
|
shouldTreatBlockedMaxAsInvalid() {
|
|
132
97
|
return false;
|
|
@@ -134,18 +99,14 @@ export class QtiOrderInteraction extends DragDropSlottedSortableMixin(SlottedBas
|
|
|
134
99
|
async firstUpdated() {
|
|
135
100
|
super.firstUpdated();
|
|
136
101
|
this.childrenMap = Array.from(this.querySelectorAll('qti-simple-choice'));
|
|
137
|
-
|
|
102
|
+
// `part="drag"` used to be stamped on the light-DOM originals here, purely so the clone would
|
|
103
|
+
// inherit it — a slotted chip's own `part` is unreachable. The mixin stamps the clone directly
|
|
104
|
+
// now, at the moment it makes it.
|
|
138
105
|
}
|
|
139
106
|
}
|
|
140
107
|
__decorate([
|
|
141
108
|
state()
|
|
142
109
|
], QtiOrderInteraction.prototype, "nrChoices", void 0);
|
|
143
|
-
__decorate([
|
|
144
|
-
state()
|
|
145
|
-
], QtiOrderInteraction.prototype, "correctResponses", void 0);
|
|
146
|
-
__decorate([
|
|
147
|
-
state()
|
|
148
|
-
], QtiOrderInteraction.prototype, "showCorrectResponses", void 0);
|
|
149
110
|
__decorate([
|
|
150
111
|
property({ type: String })
|
|
151
112
|
], QtiOrderInteraction.prototype, "orientation", void 0);
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"qti-order-interaction.js","sourceRoot":"","sources":["../src/qti-order-interaction.ts"],"names":[],"mappings":"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","sourcesContent":["import { html } 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\nimport styles from './qti-order-interaction.styles';\n\nimport type { PropertyValueMap } from 'lit';\nimport type { QtiSimpleChoice } from '@qti-components/interactions-core/elements/qti-simple-choice';\n\nconst SlottedBase = DragDropSlottedMixin(Interaction, `qti-simple-choice`, 'drop-list', `slot[part='drags']`);\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 @state() correctResponses: string[] = [];\n @state() showCorrectResponses: boolean = false;\n\n /** orientation of choices */\n @property({ type: String })\n public orientation: 'horizontal' | 'vertical';\n\n #getCorrectOrderEntries(): Array<{ identifier: string; dropIndex: number }> {\n const responseVariable = this.responseVariable;\n if (!responseVariable?.correctResponse) {\n return [];\n }\n\n const response = Array.isArray(responseVariable.correctResponse)\n ? responseVariable.correctResponse\n : [responseVariable.correctResponse];\n\n return response\n .map((entry, index) => {\n const [identifier, dropId] = entry.split(' ');\n const parsedDropIndex = dropId?.startsWith('droplist') ? parseInt(dropId.replace('droplist', ''), 10) : index;\n const dropIndex = Number.isNaN(parsedDropIndex) ? index : parsedDropIndex;\n return { identifier, dropIndex };\n })\n .filter(entry => Boolean(entry.identifier));\n }\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(\n (_, i) => html`<drop-list role=\"region\" part=\"drop-list\" identifier=\"droplist${i}\"></drop-list>`\n )}\n </div>\n </div>`;\n }\n\n public override toggleCorrectResponse(show: boolean): void {\n // Always start by removing old correct answers\n this.shadowRoot.querySelectorAll('.correct-option').forEach(option => option.remove());\n\n if (show) {\n const entries = this.#getCorrectOrderEntries();\n const labelsByIdentifier = new Map<string, string>();\n Array.from(this.querySelectorAll('qti-simple-choice')).forEach(choice => {\n const id = choice.getAttribute('identifier');\n const label = choice.textContent?.trim();\n if (id && label) {\n labelsByIdentifier.set(id, label);\n }\n });\n\n entries.forEach(({ identifier, dropIndex }) => {\n const label = labelsByIdentifier.get(identifier);\n if (!label) return;\n\n const relativeDrop = this.shadowRoot.querySelector(`drop-list[identifier=\"droplist${dropIndex}\"]`);\n if (!relativeDrop) return;\n\n const span = document.createElement('span');\n span.classList.add('correct-option');\n span.textContent = label;\n span.style.border = '1px solid var(--qti-correct)';\n span.style.borderRadius = '4px';\n span.style.padding = '2px 4px';\n span.style.display = 'inline-block';\n span.style.marginTop = '4px';\n\n relativeDrop.insertAdjacentElement('afterend', span);\n });\n }\n }\n\n public override toggleCandidateCorrection(show: boolean): void {\n super.toggleCandidateCorrection(show);\n\n const placedChoices = Array.from(\n this.shadowRoot.querySelectorAll<QtiSimpleChoice>('drop-list [qti-draggable=\"true\"]')\n );\n placedChoices.forEach(choice => {\n choice.internals.states.delete('candidate-correct');\n choice.internals.states.delete('candidate-incorrect');\n });\n\n if (!show) return;\n\n const entries = this.#getCorrectOrderEntries();\n const correctByDrop = new Map<number, string>();\n entries.forEach(entry => correctByDrop.set(entry.dropIndex, entry.identifier));\n\n const dropLists = Array.from(this.shadowRoot.querySelectorAll<HTMLElement>('drop-list'));\n dropLists.forEach((dropList, index) => {\n const placedChoice = dropList.querySelector<QtiSimpleChoice>('[qti-draggable=\"true\"]');\n if (!placedChoice) return;\n\n const expectedIdentifier = correctByDrop.get(index);\n const actualIdentifier = placedChoice.getAttribute('identifier');\n if (expectedIdentifier && actualIdentifier === expectedIdentifier) {\n placedChoice.internals.states.add('candidate-correct');\n } else {\n placedChoice.internals.states.add('candidate-incorrect');\n }\n });\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<QtiSimpleChoice>(this.shadowRoot.querySelectorAll('drop-list'));\n\n const response = droppables.map(droppable => {\n const dragsInDroppable = droppable.querySelectorAll('[qti-draggable=\"true\"]');\n const identifiers = Array.from(dragsInDroppable).map(d => d.getAttribute('identifier'));\n return [...identifiers].join(' ');\n });\n return response;\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 this.childrenMap.forEach(el => el.setAttribute('part', 'qti-simple-choice'));\n }\n}\n\ndeclare global {\n interface HTMLElementTagNameMap {\n 'qti-order-interaction': QtiOrderInteraction;\n }\n}\n"]}
|
|
1
|
+
{"version":3,"file":"qti-order-interaction.js","sourceRoot":"","sources":["../src/qti-order-interaction.ts"],"names":[],"mappings":"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","sourcesContent":["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"]}
|
|
@@ -1,2 +1,19 @@
|
|
|
1
|
-
|
|
1
|
+
/**
|
|
2
|
+
* Layout and sizing only. Paint and state live in the theme.
|
|
3
|
+
*
|
|
4
|
+
* What left, and where it went — `styles/qti-theme/interactions/qti-order-interaction.css` and
|
|
5
|
+
* `styles/overrides/kennisnet/qti/order-interaction.scss`:
|
|
6
|
+
*
|
|
7
|
+
* [part~='drop'][active] / [enabled] -> ::part(active) / ::part(enabled)
|
|
8
|
+
* [part~='drop']:has([part='drag']) -> ::part(filled)
|
|
9
|
+
*
|
|
10
|
+
* They had to be rewritten, not relocated: an attribute selector and `:has()` cannot follow
|
|
11
|
+
* `::part()`, so the drop's flags became part tokens (verified in Chromium, see setDropFlag).
|
|
12
|
+
*
|
|
13
|
+
* Two rules were deleted rather than moved, because neither did anything:
|
|
14
|
+
* - `background-color: var(--qti-background-color-active-droplist)` — that property is never
|
|
15
|
+
* defined anywhere in the repo, so the declaration was invalid at computed-value time.
|
|
16
|
+
* - `[part~='drop'][data-cross-slot-target]` — nothing has ever set that attribute.
|
|
17
|
+
*/
|
|
18
|
+
declare const _default: import("lit").CSSResult[];
|
|
2
19
|
export default _default;
|
|
@@ -1,85 +1,236 @@
|
|
|
1
1
|
import { css } from 'lit';
|
|
2
|
-
|
|
3
|
-
|
|
4
|
-
|
|
5
|
-
|
|
6
|
-
|
|
7
|
-
|
|
8
|
-
|
|
9
|
-
|
|
10
|
-
|
|
11
|
-
|
|
12
|
-
|
|
13
|
-
|
|
14
|
-
|
|
15
|
-
|
|
16
|
-
|
|
17
|
-
|
|
18
|
-
|
|
19
|
-
|
|
20
|
-
|
|
21
|
-
|
|
22
|
-
|
|
23
|
-
|
|
24
|
-
|
|
25
|
-
|
|
26
|
-
|
|
27
|
-
|
|
28
|
-
|
|
29
|
-
|
|
30
|
-
|
|
31
|
-
|
|
32
|
-
|
|
33
|
-
|
|
34
|
-
|
|
35
|
-
|
|
36
|
-
|
|
37
|
-
|
|
38
|
-
|
|
39
|
-
|
|
40
|
-
|
|
41
|
-
|
|
42
|
-
|
|
43
|
-
|
|
44
|
-
|
|
45
|
-
|
|
46
|
-
|
|
47
|
-
|
|
48
|
-
|
|
49
|
-
|
|
50
|
-
|
|
51
|
-
|
|
52
|
-
|
|
53
|
-
|
|
54
|
-
|
|
55
|
-
|
|
56
|
-
|
|
57
|
-
|
|
58
|
-
|
|
59
|
-
|
|
60
|
-
|
|
61
|
-
|
|
62
|
-
|
|
63
|
-
|
|
64
|
-
|
|
65
|
-
|
|
66
|
-
|
|
67
|
-
|
|
68
|
-
|
|
69
|
-
|
|
70
|
-
|
|
71
|
-
|
|
72
|
-
|
|
73
|
-
|
|
74
|
-
|
|
75
|
-
|
|
76
|
-
|
|
77
|
-
|
|
78
|
-
|
|
79
|
-
|
|
80
|
-
|
|
81
|
-
|
|
82
|
-
|
|
83
|
-
|
|
84
|
-
|
|
2
|
+
import { boxSizing, dropRegion, validationMessage } from '@qti-components/base';
|
|
3
|
+
/**
|
|
4
|
+
* Layout and sizing only. Paint and state live in the theme.
|
|
5
|
+
*
|
|
6
|
+
* What left, and where it went — `styles/qti-theme/interactions/qti-order-interaction.css` and
|
|
7
|
+
* `styles/overrides/kennisnet/qti/order-interaction.scss`:
|
|
8
|
+
*
|
|
9
|
+
* [part~='drop'][active] / [enabled] -> ::part(active) / ::part(enabled)
|
|
10
|
+
* [part~='drop']:has([part='drag']) -> ::part(filled)
|
|
11
|
+
*
|
|
12
|
+
* They had to be rewritten, not relocated: an attribute selector and `:has()` cannot follow
|
|
13
|
+
* `::part()`, so the drop's flags became part tokens (verified in Chromium, see setDropFlag).
|
|
14
|
+
*
|
|
15
|
+
* Two rules were deleted rather than moved, because neither did anything:
|
|
16
|
+
* - `background-color: var(--qti-background-color-active-droplist)` — that property is never
|
|
17
|
+
* defined anywhere in the repo, so the declaration was invalid at computed-value time.
|
|
18
|
+
* - `[part~='drop'][data-cross-slot-target]` — nothing has ever set that attribute.
|
|
19
|
+
*/
|
|
20
|
+
export default [
|
|
21
|
+
boxSizing,
|
|
22
|
+
validationMessage,
|
|
23
|
+
dropRegion,
|
|
24
|
+
css `
|
|
25
|
+
/* The box this element already had. See the note in qti-match-interaction.styles.ts. */
|
|
26
|
+
:host {
|
|
27
|
+
display: block;
|
|
28
|
+
}
|
|
29
|
+
|
|
30
|
+
[part='drags'] {
|
|
31
|
+
display: flex;
|
|
32
|
+
align-items: flex-start;
|
|
33
|
+
flex: 1;
|
|
34
|
+
flex-wrap: wrap;
|
|
35
|
+
}
|
|
36
|
+
|
|
37
|
+
[part='drops'] {
|
|
38
|
+
flex: 1;
|
|
39
|
+
display: grid;
|
|
40
|
+
grid-auto-flow: row;
|
|
41
|
+
/*
|
|
42
|
+
* A column floor and a drop's own min-width are two jobs, and this asks for both by name
|
|
43
|
+
* rather than letting one token mean both. --qti-drop-track-min-width is the policy: a column
|
|
44
|
+
* stays usable however narrow the chips are. --qti-dropzone-min-width is the measurement: a
|
|
45
|
+
* column is never narrower than the chip it holds. max() of the two is what the grid wants,
|
|
46
|
+
* and the 0px fallback is what makes this correct for an interaction that never measures.
|
|
47
|
+
*
|
|
48
|
+
* One name did both until --qti-drop-min-width was deleted for exactly that (it meant the
|
|
49
|
+
* track floor here and a drop's own min-width in the match target). Folding the track back
|
|
50
|
+
* onto --qti-dropzone-min-width brought the conflation back: a theme setting it to give
|
|
51
|
+
* unmeasured drops a floor also set every column, and a code path that stopped publishing a
|
|
52
|
+
* measured width stopped meaning "no floor".
|
|
53
|
+
*/
|
|
54
|
+
grid-template-columns: repeat(
|
|
55
|
+
auto-fit,
|
|
56
|
+
minmax(max(var(--qti-drop-track-min-width, 120px), var(--qti-dropzone-min-width, 0px)), 1fr)
|
|
57
|
+
);
|
|
58
|
+
gap: 0.5rem;
|
|
59
|
+
}
|
|
60
|
+
|
|
61
|
+
:host([orientation='horizontal']) [part='drags'],
|
|
62
|
+
:host(.qti-orientation-horizontal) [part='drags'] {
|
|
63
|
+
flex-direction: row;
|
|
64
|
+
}
|
|
65
|
+
/*
|
|
66
|
+
* Horizontal adds nothing to [part='drops']: the base rule above is already the horizontal
|
|
67
|
+
* layout — auto-fit columns that wrap. Only 'vertical' overrides it, to a single column.
|
|
68
|
+
*
|
|
69
|
+
* There used to be a 'grid-auto-flow: column' here, which forced every drop onto one
|
|
70
|
+
* non-wrapping line. The theme cancelled it by restating the base rule at
|
|
71
|
+
* qti-order-interaction.css, but only for '[orientation='horizontal']' — so the attribute
|
|
72
|
+
* wrapped and the '.qti-orientation-horizontal' class did not. The theme's rule is gone and so
|
|
73
|
+
* is this one; both spellings now wrap, which is what the attribute already did.
|
|
74
|
+
*/
|
|
75
|
+
:host([orientation='vertical']) [part='drags'],
|
|
76
|
+
:host(.qti-orientation-vertical) [part='drags'] {
|
|
77
|
+
flex-direction: column;
|
|
78
|
+
}
|
|
79
|
+
:host([orientation='vertical']) [part='drops'],
|
|
80
|
+
:host(.qti-orientation-vertical) [part='drops'] {
|
|
81
|
+
grid-template-columns: 1fr;
|
|
82
|
+
}
|
|
83
|
+
|
|
84
|
+
/* Drop target. The interaction measures its chips and publishes the result as a custom
|
|
85
|
+
property on its host; the property itself lives here, not in a style attribute. */
|
|
86
|
+
[part~='drop'] {
|
|
87
|
+
display: flex;
|
|
88
|
+
flex: 1;
|
|
89
|
+
min-height: var(--qti-dropzone-min-height, 0);
|
|
90
|
+
|
|
91
|
+
/*
|
|
92
|
+
* Both axes, not just the height.
|
|
93
|
+
*
|
|
94
|
+
* The width was measured and published all along and then thrown away: the drop is a grid item
|
|
95
|
+
* and stretched to its track, which is 1fr, so a slot in the vertical layout came out 669px
|
|
96
|
+
* wide for a 149px chip. justify-self: start stops the stretch and the measured minimum then
|
|
97
|
+
* decides, so a slot is exactly as wide as the widest chip — the same rule the height has
|
|
98
|
+
* always followed.
|
|
99
|
+
*
|
|
100
|
+
* The grid is untouched: the tracks still lay the slots out and still wrap in the horizontal
|
|
101
|
+
* layout. Only the slot inside the track stops filling it.
|
|
102
|
+
*/
|
|
103
|
+
min-width: var(--qti-dropzone-min-width, 0);
|
|
104
|
+
justify-self: start;
|
|
105
|
+
|
|
106
|
+
/* A chip's drop shadow hangs outside its column. */
|
|
107
|
+
overflow: visible;
|
|
108
|
+
}
|
|
109
|
+
|
|
110
|
+
[part='drops'] {
|
|
111
|
+
overflow: visible;
|
|
112
|
+
}
|
|
113
|
+
|
|
114
|
+
/* Once a drop holds a chip it stops stretching to the row and sits at the top of it. */
|
|
115
|
+
:host(:has(qti-simple-choice)) [part~='drop'] {
|
|
116
|
+
align-self: flex-start;
|
|
117
|
+
}
|
|
118
|
+
|
|
119
|
+
/*
|
|
120
|
+
* The chip a drop renders.
|
|
121
|
+
*
|
|
122
|
+
* 'overflow: visible', not 'hidden'. The theme declared both, in two '::part(drag)' blocks at
|
|
123
|
+
* equal specificity in the same layer, so the later one won and the chip has always been
|
|
124
|
+
* unclipped. The 'text-overflow: ellipsis' still sitting beside the first one has therefore
|
|
125
|
+
* never done anything; it is left in the theme rather than deleted here, since removing it is a
|
|
126
|
+
* decision about how a long label should behave, not a relocation.
|
|
127
|
+
*/
|
|
128
|
+
[part~='drag'] {
|
|
129
|
+
display: flex;
|
|
130
|
+
align-items: center;
|
|
131
|
+
overflow: visible;
|
|
132
|
+
}
|
|
133
|
+
|
|
134
|
+
[part='container'] {
|
|
135
|
+
display: grid;
|
|
136
|
+
grid-template-areas:
|
|
137
|
+
'drags drops'
|
|
138
|
+
'message message';
|
|
139
|
+
grid-template-columns: minmax(0, 1fr) minmax(0, 1fr);
|
|
140
|
+
align-items: start;
|
|
141
|
+
gap: 0.5rem;
|
|
142
|
+
}
|
|
143
|
+
|
|
144
|
+
slot[part~='drags'] {
|
|
145
|
+
grid-area: drags;
|
|
146
|
+
}
|
|
147
|
+
|
|
148
|
+
[part='drops'] {
|
|
149
|
+
grid-area: drops;
|
|
150
|
+
}
|
|
151
|
+
|
|
152
|
+
[part='message'] {
|
|
153
|
+
grid-area: message;
|
|
154
|
+
width: 100%;
|
|
155
|
+
justify-self: start;
|
|
156
|
+
}
|
|
157
|
+
|
|
158
|
+
/*
|
|
159
|
+
* The PLATFORM DEFAULT for container positioning, when the orientation is horizontal.
|
|
160
|
+
*
|
|
161
|
+
* Read that carefully, because the two things are separate axes in QTI 3 and this rule does not
|
|
162
|
+
* merge them. Vocabulary §1.2.9.3 defines qti-choices-* as where the choices container sits
|
|
163
|
+
* relative to the order-target container; orientation is how items flow WITHIN a container.
|
|
164
|
+
* They compose: §1.2.9.2 Figure 73 is orientation="vertical" class="qti-choices-left" and
|
|
165
|
+
* renders two COLUMNS SIDE BY SIDE — vertical does not stack the containers, and horizontal does
|
|
166
|
+
* not imply that it should.
|
|
167
|
+
*
|
|
168
|
+
* What makes this rule legitimate is that §1.2.9.3 declines to specify the positioning at all
|
|
169
|
+
* when no class is given: "In the absence of choices | order target container positioning,
|
|
170
|
+
* delivery systems should render platform defaults." That default is ours, and for a horizontal
|
|
171
|
+
* flow the useful one is stacked, because a row needs the width. An author who wants something
|
|
172
|
+
* else says so with qti-choices-*, which is exactly what the spec provides it for — and those
|
|
173
|
+
* rules below still win (see the source-order note).
|
|
174
|
+
*
|
|
175
|
+
* Side by side used to work here anyway, but only because a slot could be narrower
|
|
176
|
+
* than the chip standing in it: the theme gave a placed chip width: 100%, so a 218px chip was
|
|
177
|
+
* squeezed into a 184px track and three of them fitted in half the width. That squeeze is gone
|
|
178
|
+
* (DROP-SIZING.md §5), and without it "van links naar rechts" collapsed to a single column,
|
|
179
|
+
* because 384px cannot hold two 218px chips.
|
|
180
|
+
*
|
|
181
|
+
* Measured on ITEM013: side by side gives the slots 384px and one 384px track; stacked gives them
|
|
182
|
+
* 800px and three 256px tracks, each wider than the chip. Vertical is untouched — one column is
|
|
183
|
+
* what it wants, and the split suits it.
|
|
184
|
+
*
|
|
185
|
+
* Deliberately BEFORE the qti-choices-* rules below, not after. Those tie on specificity, so
|
|
186
|
+
* source order decides: an author who writes qti-choices-left still gets it, and this is only the
|
|
187
|
+
* default for an orientation that has no such class.
|
|
188
|
+
*/
|
|
189
|
+
:host([orientation='horizontal']) [part='container'],
|
|
190
|
+
:host(.qti-orientation-horizontal) [part='container'] {
|
|
191
|
+
grid-template-areas:
|
|
192
|
+
'drags'
|
|
193
|
+
'drops'
|
|
194
|
+
'message';
|
|
195
|
+
grid-template-columns: minmax(0, 1fr);
|
|
196
|
+
}
|
|
197
|
+
|
|
198
|
+
:host(.qti-choices-top) [part='container'] {
|
|
199
|
+
grid-template-areas:
|
|
200
|
+
'drags'
|
|
201
|
+
'drops'
|
|
202
|
+
'message';
|
|
203
|
+
grid-template-columns: minmax(0, 1fr);
|
|
204
|
+
}
|
|
205
|
+
|
|
206
|
+
:host(.qti-choices-bottom) [part='container'] {
|
|
207
|
+
grid-template-areas:
|
|
208
|
+
'drops'
|
|
209
|
+
'drags'
|
|
210
|
+
'message';
|
|
211
|
+
grid-template-columns: minmax(0, 1fr);
|
|
212
|
+
}
|
|
213
|
+
|
|
214
|
+
:host(.qti-choices-left) [part='container'] {
|
|
215
|
+
grid-template-areas:
|
|
216
|
+
'drags drops'
|
|
217
|
+
'message message';
|
|
218
|
+
grid-template-columns: minmax(0, 1fr) minmax(0, 1fr);
|
|
219
|
+
}
|
|
220
|
+
|
|
221
|
+
:host(.qti-choices-right) [part='container'] {
|
|
222
|
+
grid-template-areas:
|
|
223
|
+
'drops drags'
|
|
224
|
+
'message message';
|
|
225
|
+
grid-template-columns: minmax(0, 1fr) minmax(0, 1fr);
|
|
226
|
+
}
|
|
227
|
+
|
|
228
|
+
/* An answer key shows the answer, not the bank you would have dragged it from. The attribute is
|
|
229
|
+
set on the clone by the correct-response mixin; the theme used to do this with a
|
|
230
|
+
'.full-correct-response' descendant selector, from the document. */
|
|
231
|
+
:host([answer-key]) [part~='drags'] {
|
|
232
|
+
display: none;
|
|
233
|
+
}
|
|
234
|
+
`
|
|
235
|
+
];
|
|
85
236
|
//# sourceMappingURL=qti-order-interaction.styles.js.map
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"qti-order-interaction.styles.js","sourceRoot":"","sources":["../src/qti-order-interaction.styles.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,GAAG,EAAE,MAAM,KAAK,CAAC;AAC1B,yEAAyE;AACzE,UAAU;AACV,2BAA2B;AAC3B,wBAAwB;AACxB,IAAI;AACJ,wBAAwB;AACxB,eAAe,GAAG,CAAA;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;CA4EjB,CAAC","sourcesContent":["import { css } from 'lit';\n// import componentStyles from '../../utilities/styles/component.styles';\n// :host {\n// display: inline-block;\n// position: relative;\n// }\n/* ${componentStyles} */\nexport default css`\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: column;\n grid-auto-columns: 1fr;\n }\n\n :host([orientation='horizontal']) [part='drags'] {\n flex-direction: row;\n }\n :host([orientation='horizontal']) [part='drops'] {\n grid-auto-flow: column;\n }\n :host([orientation='vertical']) [part='drags'] {\n flex-direction: column;\n }\n :host([orientation='vertical']) [part='drops'] {\n grid-auto-flow: row;\n }\n\n [part='drop-list'] {\n display: block;\n flex: 1;\n }\n\n [part='drop-list'][active] {\n border-color: var(--qti-border-active) !important;\n background-color: var(--qti-bg-active) !important;\n }\n\n [part='drop-list'][enabled] {\n background-color: var(--qti-bg-active) !important;\n }\n\n [part='drop-list'][data-cross-slot-target] {\n border-color: var(--qti-border-active, #0066cc) !important;\n background-color: var(--qti-bg-active, rgba(0, 102, 204, 0.1)) !important;\n outline: 2px dashed var(--qti-border-active, #0066cc);\n outline-offset: -2px;\n }\n\n /* Candidate correction colors for choices placed inside drop-lists. */\n drop-list [qti-draggable='true']:state(candidate-correct),\n [part='qti-simple-choice']:state(candidate-correct) {\n background-color: var(--qti-correct) !important;\n }\n\n drop-list [qti-draggable='true']:state(candidate-incorrect),\n [part='qti-simple-choice']:state(candidate-incorrect) {\n background-color: var(--qti-incorrect) !important;\n }\n\n [part='container'] {\n display: flex;\n gap: 0.5rem;\n }\n :host(.qti-choices-top) [part='container'] {\n flex-direction: column;\n }\n :host(.qti-choices-bottom) [part='container'] {\n flex-direction: column-reverse;\n }\n :host(.qti-choices-left) [part='container'] {\n flex-direction: row;\n }\n :host(.qti-choices-right) [part='container'] {\n flex-direction: row-reverse;\n }\n`;\n"]}
|
|
1
|
+
{"version":3,"file":"qti-order-interaction.styles.js","sourceRoot":"","sources":["../src/qti-order-interaction.styles.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,GAAG,EAAE,MAAM,KAAK,CAAC;AAE1B,OAAO,EAAE,SAAS,EAAE,UAAU,EAAE,iBAAiB,EAAE,MAAM,sBAAsB,CAAC;AAEhF;;;;;;;;;;;;;;;;GAgBG;AACH,eAAe;IACb,SAAS;IACT,iBAAiB;IACjB,UAAU;IACV,GAAG,CAAA;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;GAkNF;CACF,CAAC","sourcesContent":["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"]}
|
package/dist/register.js
CHANGED
|
@@ -1,3 +1,7 @@
|
|
|
1
|
-
import {
|
|
2
|
-
|
|
1
|
+
import { elements } from './elements';
|
|
2
|
+
for (const { tag, ctor } of elements) {
|
|
3
|
+
if (!customElements.get(tag)) {
|
|
4
|
+
customElements.define(tag, ctor);
|
|
5
|
+
}
|
|
6
|
+
}
|
|
3
7
|
//# sourceMappingURL=register.js.map
|
package/dist/register.js.map
CHANGED
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"register.js","sourceRoot":"","sources":["../src/register.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,
|
|
1
|
+
{"version":3,"file":"register.js","sourceRoot":"","sources":["../src/register.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,QAAQ,EAAE,MAAM,YAAY,CAAC;AAEtC,KAAK,MAAM,EAAE,GAAG,EAAE,IAAI,EAAE,IAAI,QAAQ,EAAE,CAAC;IACrC,IAAI,CAAC,cAAc,CAAC,GAAG,CAAC,GAAG,CAAC,EAAE,CAAC;QAC7B,cAAc,CAAC,MAAM,CAAC,GAAG,EAAE,IAAI,CAAC,CAAC;IACnC,CAAC;AACH,CAAC","sourcesContent":["import { elements } from './elements';\n\nfor (const { tag, ctor } of elements) {\n if (!customElements.get(tag)) {\n customElements.define(tag, ctor);\n }\n}\n"]}
|
package/package.json
CHANGED
|
@@ -1,11 +1,11 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@qti-components/order-interaction",
|
|
3
3
|
"description": "QTI order-interaction interaction",
|
|
4
|
-
"version": "
|
|
4
|
+
"version": "2.0.0",
|
|
5
5
|
"author": "",
|
|
6
6
|
"dependencies": {
|
|
7
|
-
"@qti-components/base": "^
|
|
8
|
-
"@qti-components/interactions-core": "^
|
|
7
|
+
"@qti-components/base": "^2.0.0",
|
|
8
|
+
"@qti-components/interactions-core": "^2.0.0",
|
|
9
9
|
"@qti-components/utilities": "^1.3.3"
|
|
10
10
|
},
|
|
11
11
|
"devDependencies": {
|
|
@@ -45,6 +45,10 @@
|
|
|
45
45
|
"./styles": {
|
|
46
46
|
"types": "./dist/qti-order-interaction.styles.d.ts",
|
|
47
47
|
"import": "./dist/qti-order-interaction.styles.js"
|
|
48
|
+
},
|
|
49
|
+
"./elements": {
|
|
50
|
+
"types": "./dist/elements.d.ts",
|
|
51
|
+
"import": "./dist/elements.js"
|
|
48
52
|
}
|
|
49
53
|
},
|
|
50
54
|
"repository": {
|
|
@@ -55,6 +59,8 @@
|
|
|
55
59
|
"scripts": {
|
|
56
60
|
"attw": "attw --profile esm-only --pack",
|
|
57
61
|
"build": "tsc --paths null",
|
|
58
|
-
"clean": "rm -rf dist"
|
|
62
|
+
"clean": "rm -rf dist",
|
|
63
|
+
"yalc": "yalc publish",
|
|
64
|
+
"yalc:push": "yalc push"
|
|
59
65
|
}
|
|
60
66
|
}
|