@qti-editor/interaction-select-point 0.1.0

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (28) hide show
  1. package/dist/components/qti-select-point-interaction/img-select-point.schema.d.ts +3 -0
  2. package/dist/components/qti-select-point-interaction/img-select-point.schema.d.ts.map +1 -0
  3. package/dist/components/qti-select-point-interaction/img-select-point.schema.js +47 -0
  4. package/dist/components/qti-select-point-interaction/qti-select-point-interaction.commands.d.ts +6 -0
  5. package/dist/components/qti-select-point-interaction/qti-select-point-interaction.commands.d.ts.map +1 -0
  6. package/dist/components/qti-select-point-interaction/qti-select-point-interaction.commands.js +26 -0
  7. package/dist/components/qti-select-point-interaction/qti-select-point-interaction.compose.d.ts +3 -0
  8. package/dist/components/qti-select-point-interaction/qti-select-point-interaction.compose.d.ts.map +1 -0
  9. package/dist/components/qti-select-point-interaction/qti-select-point-interaction.compose.js +154 -0
  10. package/dist/components/qti-select-point-interaction/qti-select-point-interaction.d.ts +38 -0
  11. package/dist/components/qti-select-point-interaction/qti-select-point-interaction.d.ts.map +1 -0
  12. package/dist/components/qti-select-point-interaction/qti-select-point-interaction.js +650 -0
  13. package/dist/components/qti-select-point-interaction/qti-select-point-interaction.schema.d.ts +3 -0
  14. package/dist/components/qti-select-point-interaction/qti-select-point-interaction.schema.d.ts.map +1 -0
  15. package/dist/components/qti-select-point-interaction/qti-select-point-interaction.schema.js +98 -0
  16. package/dist/composer/handler.d.ts +3 -0
  17. package/dist/composer/handler.d.ts.map +1 -0
  18. package/dist/composer/handler.js +6 -0
  19. package/dist/composer/metadata.d.ts +22 -0
  20. package/dist/composer/metadata.d.ts.map +1 -0
  21. package/dist/composer/metadata.js +29 -0
  22. package/dist/descriptor.d.ts +30 -0
  23. package/dist/descriptor.d.ts.map +1 -0
  24. package/dist/descriptor.js +18 -0
  25. package/dist/index.d.ts +9 -0
  26. package/dist/index.d.ts.map +1 -0
  27. package/dist/index.js +8 -0
  28. package/package.json +42 -0
@@ -0,0 +1,3 @@
1
+ import type { NodeSpec } from 'prosemirror-model';
2
+ export declare const imgSelectPointNodeSpec: NodeSpec;
3
+ //# sourceMappingURL=img-select-point.schema.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"img-select-point.schema.d.ts","sourceRoot":"","sources":["../../../src/components/qti-select-point-interaction/img-select-point.schema.ts"],"names":[],"mappings":"AAAA,OAAO,KAAK,EAAiB,QAAQ,EAAE,MAAM,mBAAmB,CAAC;AAYjE,eAAO,MAAM,sBAAsB,EAAE,QAgCpC,CAAC"}
@@ -0,0 +1,47 @@
1
+ function parseNumberAttribute(value) {
2
+ if (value == null || value === '')
3
+ return null;
4
+ const parsed = Number(value);
5
+ return Number.isFinite(parsed) ? parsed : null;
6
+ }
7
+ function isElementLike(node) {
8
+ return typeof node === 'object' && node !== null && 'getAttribute' in node && typeof node.getAttribute === 'function';
9
+ }
10
+ export const imgSelectPointNodeSpec = {
11
+ group: 'block qtiMedia',
12
+ atom: true,
13
+ selectable: true,
14
+ attrs: {
15
+ imageSrc: { default: null },
16
+ imageAlt: { default: null },
17
+ imageWidth: { default: null },
18
+ imageHeight: { default: null }
19
+ },
20
+ parseDOM: [
21
+ {
22
+ tag: 'img',
23
+ getAttrs: (node) => {
24
+ if (!isElementLike(node))
25
+ return {};
26
+ return {
27
+ imageSrc: node.getAttribute('src'),
28
+ imageAlt: node.getAttribute('alt'),
29
+ imageWidth: parseNumberAttribute(node.getAttribute('width')),
30
+ imageHeight: parseNumberAttribute(node.getAttribute('height'))
31
+ };
32
+ }
33
+ }
34
+ ],
35
+ toDOM(node) {
36
+ const attrs = {};
37
+ if (node.attrs.imageSrc)
38
+ attrs.src = String(node.attrs.imageSrc);
39
+ if (node.attrs.imageAlt)
40
+ attrs.alt = String(node.attrs.imageAlt);
41
+ if (node.attrs.imageWidth != null)
42
+ attrs.width = String(node.attrs.imageWidth);
43
+ if (node.attrs.imageHeight != null)
44
+ attrs.height = String(node.attrs.imageHeight);
45
+ return ['img', attrs];
46
+ }
47
+ };
@@ -0,0 +1,6 @@
1
+ import type { Command } from 'prosemirror-state';
2
+ /**
3
+ * Command to insert a select point interaction at the current selection.
4
+ */
5
+ export declare const insertSelectPointInteraction: Command;
6
+ //# sourceMappingURL=qti-select-point-interaction.commands.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"qti-select-point-interaction.commands.d.ts","sourceRoot":"","sources":["../../../src/components/qti-select-point-interaction/qti-select-point-interaction.commands.ts"],"names":[],"mappings":"AAEA,OAAO,KAAK,EAAE,OAAO,EAAE,MAAM,mBAAmB,CAAC;AAEjD;;GAEG;AACH,eAAO,MAAM,4BAA4B,EAAE,OA0B1C,CAAC"}
@@ -0,0 +1,26 @@
1
+ import { createInsertBlockInteractionCommand } from '@qti-editor/interaction-shared/commands/insert.js';
2
+ /**
3
+ * Command to insert a select point interaction at the current selection.
4
+ */
5
+ export const insertSelectPointInteraction = (state, dispatch) => {
6
+ return createInsertBlockInteractionCommand({
7
+ createNode: currentState => {
8
+ const { schema } = currentState;
9
+ const interactionType = schema.nodes.qtiSelectPointInteraction;
10
+ const promptType = schema.nodes.qtiPrompt;
11
+ const promptParagraphType = schema.nodes.qtiPromptParagraph;
12
+ const imgSelectPointType = schema.nodes.imgSelectPoint;
13
+ if (!interactionType || !promptType || !promptParagraphType || !imgSelectPointType)
14
+ return null;
15
+ const prompt = promptType.create(null, promptParagraphType.create(null, schema.text('Mark the correct point on the image.')));
16
+ const imgSelectPoint = imgSelectPointType.create();
17
+ return interactionType.create({
18
+ responseIdentifier: `RESPONSE_${crypto.randomUUID()}`,
19
+ maxChoices: 0,
20
+ minChoices: 0,
21
+ areaMappings: '[]',
22
+ }, [prompt, imgSelectPoint]);
23
+ },
24
+ selectionOffset: 2,
25
+ })(state, dispatch);
26
+ };
@@ -0,0 +1,3 @@
1
+ import type { InteractionComposeResult } from '@qti-editor/interaction-shared/composer/types.js';
2
+ export declare function composeSelectPointInteractionElement(sourceElement: Element, xmlDoc: Document): InteractionComposeResult;
3
+ //# sourceMappingURL=qti-select-point-interaction.compose.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"qti-select-point-interaction.compose.d.ts","sourceRoot":"","sources":["../../../src/components/qti-select-point-interaction/qti-select-point-interaction.compose.ts"],"names":[],"mappings":"AAEA,OAAO,KAAK,EAAmB,wBAAwB,EAAmD,MAAM,kDAAkD,CAAC;AA8FnK,wBAAgB,oCAAoC,CAAC,aAAa,EAAE,OAAO,EAAE,MAAM,EAAE,QAAQ,GAAG,wBAAwB,CAkFvH"}
@@ -0,0 +1,154 @@
1
+ import { selectPointInteractionComposerMetadata, SELECT_POINT_INTERACTION_TAG } from '../../composer/metadata.js';
2
+ function toFiniteNumber(value, fallback) {
3
+ if (value == null || value.trim().length === 0)
4
+ return fallback;
5
+ const parsed = Number(value);
6
+ return Number.isFinite(parsed) ? parsed : fallback;
7
+ }
8
+ function toNonEmptyString(value) {
9
+ if (!value)
10
+ return null;
11
+ const trimmed = value.trim();
12
+ return trimmed.length > 0 ? trimmed : null;
13
+ }
14
+ function parseAreaMappings(raw) {
15
+ const warnings = [];
16
+ if (!raw || raw.trim().length === 0) {
17
+ return { warnings };
18
+ }
19
+ let parsed;
20
+ try {
21
+ parsed = JSON.parse(raw);
22
+ }
23
+ catch {
24
+ warnings.push({
25
+ code: 'INVALID_AREA_MAPPINGS_JSON',
26
+ message: 'qti-select-point-interaction has invalid area-mappings JSON; skipping qti-area-mapping.',
27
+ tagName: SELECT_POINT_INTERACTION_TAG,
28
+ });
29
+ return { warnings };
30
+ }
31
+ if (!Array.isArray(parsed)) {
32
+ warnings.push({
33
+ code: 'INVALID_AREA_MAPPINGS_JSON',
34
+ message: 'qti-select-point-interaction area-mappings is not an array; skipping qti-area-mapping.',
35
+ tagName: SELECT_POINT_INTERACTION_TAG,
36
+ });
37
+ return { warnings };
38
+ }
39
+ const entries = [];
40
+ let defaultValue = 0;
41
+ parsed.forEach((entry, index) => {
42
+ const asRecord = typeof entry === 'object' && entry != null ? entry : null;
43
+ const shape = asRecord?.shape;
44
+ const coords = asRecord?.coords;
45
+ if ((shape !== 'circle' && shape !== 'rect') || typeof coords !== 'string' || coords.trim().length === 0) {
46
+ warnings.push({
47
+ code: 'INVALID_AREA_MAPPING_ENTRY',
48
+ message: `Invalid area-mappings entry at index ${index}; expected shape (circle|rect) and coords string.`,
49
+ tagName: SELECT_POINT_INTERACTION_TAG,
50
+ });
51
+ return;
52
+ }
53
+ const mappedValueRaw = asRecord?.mappedValue;
54
+ const mappedValue = Number.isFinite(Number(mappedValueRaw)) ? Number(mappedValueRaw) : 0;
55
+ const defaultValueRaw = asRecord?.defaultValue;
56
+ if (Number.isFinite(Number(defaultValueRaw))) {
57
+ defaultValue = Number(defaultValueRaw);
58
+ }
59
+ entries.push({
60
+ shape,
61
+ coords: coords.trim(),
62
+ mappedValue,
63
+ });
64
+ });
65
+ if (entries.length === 0) {
66
+ return { warnings };
67
+ }
68
+ return {
69
+ areaMapping: {
70
+ defaultValue,
71
+ entries,
72
+ },
73
+ warnings,
74
+ };
75
+ }
76
+ function removeChildrenByTagName(element, tagName) {
77
+ Array.from(element.children)
78
+ .filter(child => child.tagName.toLowerCase() === tagName)
79
+ .forEach(child => child.remove());
80
+ }
81
+ export function composeSelectPointInteractionElement(sourceElement, xmlDoc) {
82
+ const metadata = selectPointInteractionComposerMetadata;
83
+ const warnings = [];
84
+ const responseIdentifier = toNonEmptyString(sourceElement.getAttribute('response-identifier'));
85
+ const maxChoices = toFiniteNumber(sourceElement.getAttribute('max-choices'), 1);
86
+ const minChoices = toFiniteNumber(sourceElement.getAttribute('min-choices'), 0);
87
+ const promptFromChild = sourceElement.querySelector('qti-prompt')?.textContent;
88
+ const prompt = toNonEmptyString(promptFromChild ?? null);
89
+ const imageElement = sourceElement.querySelector('img');
90
+ const imageSrc = toNonEmptyString(imageElement?.getAttribute('src') ?? null);
91
+ const imageAlt = toNonEmptyString(imageElement?.getAttribute('alt') ?? null);
92
+ const imageWidth = toNonEmptyString(imageElement?.getAttribute('width') ?? null);
93
+ const imageHeight = toNonEmptyString(imageElement?.getAttribute('height') ?? null);
94
+ const normalizedElement = xmlDoc.importNode(sourceElement, true);
95
+ const editorOnlyAttributes = [...metadata.editorOnlyAttributes];
96
+ editorOnlyAttributes.forEach(attr => normalizedElement.removeAttribute(attr));
97
+ normalizedElement.setAttribute('max-choices', String(maxChoices > 0 ? maxChoices : 1));
98
+ if (minChoices > 0) {
99
+ normalizedElement.setAttribute('min-choices', String(minChoices));
100
+ }
101
+ else {
102
+ normalizedElement.removeAttribute('min-choices');
103
+ }
104
+ removeChildrenByTagName(normalizedElement, 'img');
105
+ removeChildrenByTagName(normalizedElement, 'qti-prompt');
106
+ if (prompt) {
107
+ const qtiPrompt = xmlDoc.createElementNS(normalizedElement.namespaceURI || null, 'qti-prompt');
108
+ const paragraph = xmlDoc.createElementNS(normalizedElement.namespaceURI || null, 'p');
109
+ paragraph.textContent = prompt;
110
+ qtiPrompt.appendChild(paragraph);
111
+ normalizedElement.appendChild(qtiPrompt);
112
+ }
113
+ if (imageSrc) {
114
+ const image = xmlDoc.createElementNS(normalizedElement.namespaceURI || null, 'img');
115
+ image.setAttribute('src', imageSrc);
116
+ if (imageAlt)
117
+ image.setAttribute('alt', imageAlt);
118
+ if (imageWidth)
119
+ image.setAttribute('width', imageWidth);
120
+ if (imageHeight)
121
+ image.setAttribute('height', imageHeight);
122
+ normalizedElement.appendChild(image);
123
+ }
124
+ const areaMappingsRaw = sourceElement.getAttribute('area-mappings');
125
+ const areaMappingResult = parseAreaMappings(areaMappingsRaw);
126
+ warnings.push(...areaMappingResult.warnings);
127
+ let responseDeclaration;
128
+ if (!responseIdentifier) {
129
+ warnings.push({
130
+ code: 'MISSING_RESPONSE_IDENTIFIER',
131
+ message: 'qti-select-point-interaction is missing response-identifier; declaration will be skipped.',
132
+ tagName: metadata.tagName,
133
+ });
134
+ }
135
+ else {
136
+ const correctResponse = toNonEmptyString(sourceElement.getAttribute('correct-response'));
137
+ responseDeclaration = {
138
+ identifier: responseIdentifier,
139
+ cardinality: maxChoices > 1 ? 'multiple' : 'single',
140
+ baseType: 'point',
141
+ correctResponse: correctResponse ?? undefined,
142
+ areaMapping: areaMappingResult.areaMapping,
143
+ sourceTag: metadata.tagName,
144
+ };
145
+ }
146
+ return {
147
+ normalizedElement,
148
+ responseDeclaration,
149
+ responseProcessingTemplate: metadata.responseProcessingTemplate,
150
+ responseProcessingKind: metadata.responseProcessing.internalKind,
151
+ editorOnlyAttributes,
152
+ warnings,
153
+ };
154
+ }
@@ -0,0 +1,38 @@
1
+ import { Interaction } from '@qti-editor/interaction-shared/components/interaction.js';
2
+ import type { CSSResultGroup, TemplateResult } from 'lit';
3
+ type DrawMode = 'select' | 'circle' | 'rect';
4
+ type AreaShape = 'circle' | 'rect';
5
+ type AreaMappingEntry = {
6
+ id: string;
7
+ shape: AreaShape;
8
+ coords: string;
9
+ mappedValue: number;
10
+ defaultValue: number;
11
+ };
12
+ type DraftShape = {
13
+ shape: AreaShape;
14
+ startX: number;
15
+ startY: number;
16
+ currentX: number;
17
+ currentY: number;
18
+ };
19
+ export declare class QtiSelectPointInteractionEdit extends Interaction {
20
+ #private;
21
+ static styles: CSSResultGroup;
22
+ areaMappings: string;
23
+ protected drawMode: DrawMode;
24
+ protected imageReady: boolean;
25
+ protected imageSrc: string | null;
26
+ protected imageAlt: string | null;
27
+ protected imageWidth: number | null;
28
+ protected imageHeight: number | null;
29
+ protected areaEntries: AreaMappingEntry[];
30
+ protected draft: DraftShape | null;
31
+ protected sourceError: string | null;
32
+ connectedCallback(): void;
33
+ firstUpdated(): void;
34
+ updated(changedProperties: Map<string | number | symbol, unknown>): void;
35
+ render(): TemplateResult<1>;
36
+ }
37
+ export {};
38
+ //# sourceMappingURL=qti-select-point-interaction.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"qti-select-point-interaction.d.ts","sourceRoot":"","sources":["../../../src/components/qti-select-point-interaction/qti-select-point-interaction.ts"],"names":[],"mappings":"AAGA,OAAO,EAAE,WAAW,EAAE,MAAM,0DAA0D,CAAC;AAEvF,OAAO,KAAK,EAAE,cAAc,EAAE,cAAc,EAAE,MAAM,KAAK,CAAC;AAE1D,KAAK,QAAQ,GAAG,QAAQ,GAAG,QAAQ,GAAG,MAAM,CAAC;AAC7C,KAAK,SAAS,GAAG,QAAQ,GAAG,MAAM,CAAC;AAEnC,KAAK,gBAAgB,GAAG;IACtB,EAAE,EAAE,MAAM,CAAC;IACX,KAAK,EAAE,SAAS,CAAC;IACjB,MAAM,EAAE,MAAM,CAAC;IACf,WAAW,EAAE,MAAM,CAAC;IACpB,YAAY,EAAE,MAAM,CAAC;CACtB,CAAC;AAEF,KAAK,UAAU,GAAG;IAChB,KAAK,EAAE,SAAS,CAAC;IACjB,MAAM,EAAE,MAAM,CAAC;IACf,MAAM,EAAE,MAAM,CAAC;IACf,QAAQ,EAAE,MAAM,CAAC;IACjB,QAAQ,EAAE,MAAM,CAAC;CAClB,CAAC;AAsBF,qBAAa,6BAA8B,SAAQ,WAAW;;IAC5D,OAAgB,MAAM,EAAE,cAAc,CAsFpC;IAGF,YAAY,SAAQ;IAGpB,SAAS,CAAC,QAAQ,EAAE,QAAQ,CAAY;IAGxC,SAAS,CAAC,UAAU,UAAS;IAG7B,SAAS,CAAC,QAAQ,EAAE,MAAM,GAAG,IAAI,CAAQ;IAGzC,SAAS,CAAC,QAAQ,EAAE,MAAM,GAAG,IAAI,CAAQ;IAGzC,SAAS,CAAC,UAAU,EAAE,MAAM,GAAG,IAAI,CAAQ;IAG3C,SAAS,CAAC,WAAW,EAAE,MAAM,GAAG,IAAI,CAAQ;IAG5C,SAAS,CAAC,WAAW,EAAE,gBAAgB,EAAE,CAAM;IAG/C,SAAS,CAAC,KAAK,EAAE,UAAU,GAAG,IAAI,CAAQ;IAG1C,SAAS,CAAC,WAAW,EAAE,MAAM,GAAG,IAAI,CAAQ;IAQnC,iBAAiB,IAAI,IAAI;IAKzB,YAAY,IAAI,IAAI;IAKpB,OAAO,CAAC,iBAAiB,EAAE,GAAG,CAAC,MAAM,GAAG,MAAM,GAAG,MAAM,EAAE,OAAO,CAAC,GAAG,IAAI;IA6fxE,MAAM;CA8DhB"}
@@ -0,0 +1,650 @@
1
+ var __decorate = (this && this.__decorate) || function (decorators, target, key, desc) {
2
+ var c = arguments.length, r = c < 3 ? target : desc === null ? desc = Object.getOwnPropertyDescriptor(target, key) : desc, d;
3
+ if (typeof Reflect === "object" && typeof Reflect.decorate === "function") r = Reflect.decorate(decorators, target, key, desc);
4
+ else for (var i = decorators.length - 1; i >= 0; i--) if (d = decorators[i]) r = (c < 3 ? d(r) : c > 3 ? d(target, key, r) : d(target, key)) || r;
5
+ return c > 3 && r && Object.defineProperty(target, key, r), r;
6
+ };
7
+ var __classPrivateFieldGet = (this && this.__classPrivateFieldGet) || function (receiver, state, kind, f) {
8
+ if (kind === "a" && !f) throw new TypeError("Private accessor was defined without a getter");
9
+ if (typeof state === "function" ? receiver !== state || !f : !state.has(receiver)) throw new TypeError("Cannot read private member from an object whose class did not declare it");
10
+ return kind === "m" ? f : kind === "a" ? f.call(receiver) : f ? f.value : state.get(receiver);
11
+ };
12
+ var __classPrivateFieldSet = (this && this.__classPrivateFieldSet) || function (receiver, state, value, kind, f) {
13
+ if (kind === "m") throw new TypeError("Private method is not writable");
14
+ if (kind === "a" && !f) throw new TypeError("Private accessor was defined without a setter");
15
+ if (typeof state === "function" ? receiver !== state || !f : !state.has(receiver)) throw new TypeError("Cannot write private member to an object whose class did not declare it");
16
+ return (kind === "a" ? f.call(receiver, value) : f ? f.value = value : state.set(receiver, value)), value;
17
+ };
18
+ var _QtiSelectPointInteractionEdit_instances, _QtiSelectPointInteractionEdit_imageElement, _QtiSelectPointInteractionEdit_dragging, _QtiSelectPointInteractionEdit_activePointerId, _QtiSelectPointInteractionEdit_shapeDrag, _QtiSelectPointInteractionEdit_fileInputRef, _QtiSelectPointInteractionEdit_syncImageFromDom, _QtiSelectPointInteractionEdit_ensureChildSlots, _QtiSelectPointInteractionEdit_parseDimension, _QtiSelectPointInteractionEdit_syncAreaEntriesFromAttribute, _QtiSelectPointInteractionEdit_persistAreaEntries, _QtiSelectPointInteractionEdit_onFileChange, _QtiSelectPointInteractionEdit_openFilePicker, _QtiSelectPointInteractionEdit_isValidHttpUrl, _QtiSelectPointInteractionEdit_pasteImageFromClipboard, _QtiSelectPointInteractionEdit_applyImageSource, _QtiSelectPointInteractionEdit_removeImage, _QtiSelectPointInteractionEdit_toDataUrl, _QtiSelectPointInteractionEdit_loadImageDimensions, _QtiSelectPointInteractionEdit_onImageLoad, _QtiSelectPointInteractionEdit_toOriginalCoords, _QtiSelectPointInteractionEdit_onPointerDown, _QtiSelectPointInteractionEdit_onPointerMove, _QtiSelectPointInteractionEdit_onPointerUp, _QtiSelectPointInteractionEdit_onPointerCancel, _QtiSelectPointInteractionEdit_parseCoords, _QtiSelectPointInteractionEdit_findHitShapeIndex, _QtiSelectPointInteractionEdit_moveShape, _QtiSelectPointInteractionEdit_draftToEntry, _QtiSelectPointInteractionEdit_renderAreaShape, _QtiSelectPointInteractionEdit_renderDraft, _QtiSelectPointInteractionEdit_setDrawMode, _QtiSelectPointInteractionEdit_clearMappings, _QtiSelectPointInteractionEdit_emitWrapperAttrsChange, _QtiSelectPointInteractionEdit_emitImageAttrsChange;
19
+ import { css, html, nothing, svg } from 'lit';
20
+ import { createRef, ref } from 'lit/directives/ref.js';
21
+ import { property, state } from 'lit/decorators.js';
22
+ import { Interaction } from '@qti-editor/interaction-shared/components/interaction.js';
23
+ export class QtiSelectPointInteractionEdit extends Interaction {
24
+ constructor() {
25
+ super(...arguments);
26
+ _QtiSelectPointInteractionEdit_instances.add(this);
27
+ this.areaMappings = '[]';
28
+ this.drawMode = 'select';
29
+ this.imageReady = false;
30
+ this.imageSrc = null;
31
+ this.imageAlt = null;
32
+ this.imageWidth = null;
33
+ this.imageHeight = null;
34
+ this.areaEntries = [];
35
+ this.draft = null;
36
+ this.sourceError = null;
37
+ _QtiSelectPointInteractionEdit_imageElement.set(this, null);
38
+ _QtiSelectPointInteractionEdit_dragging.set(this, false);
39
+ _QtiSelectPointInteractionEdit_activePointerId.set(this, null);
40
+ _QtiSelectPointInteractionEdit_shapeDrag.set(this, null);
41
+ _QtiSelectPointInteractionEdit_fileInputRef.set(this, createRef());
42
+ _QtiSelectPointInteractionEdit_onImageLoad.set(this, (event) => {
43
+ const img = event.currentTarget;
44
+ __classPrivateFieldSet(this, _QtiSelectPointInteractionEdit_imageElement, img, "f");
45
+ if (!this.imageWidth || !this.imageHeight) {
46
+ this.imageWidth = img.naturalWidth;
47
+ this.imageHeight = img.naturalHeight;
48
+ __classPrivateFieldGet(this, _QtiSelectPointInteractionEdit_instances, "m", _QtiSelectPointInteractionEdit_emitImageAttrsChange).call(this);
49
+ }
50
+ this.imageReady = true;
51
+ });
52
+ }
53
+ connectedCallback() {
54
+ super.connectedCallback();
55
+ __classPrivateFieldGet(this, _QtiSelectPointInteractionEdit_instances, "m", _QtiSelectPointInteractionEdit_syncAreaEntriesFromAttribute).call(this);
56
+ }
57
+ firstUpdated() {
58
+ __classPrivateFieldGet(this, _QtiSelectPointInteractionEdit_instances, "m", _QtiSelectPointInteractionEdit_ensureChildSlots).call(this);
59
+ __classPrivateFieldGet(this, _QtiSelectPointInteractionEdit_instances, "m", _QtiSelectPointInteractionEdit_syncImageFromDom).call(this);
60
+ }
61
+ updated(changedProperties) {
62
+ if (changedProperties.has('areaMappings')) {
63
+ __classPrivateFieldGet(this, _QtiSelectPointInteractionEdit_instances, "m", _QtiSelectPointInteractionEdit_syncAreaEntriesFromAttribute).call(this);
64
+ }
65
+ }
66
+ render() {
67
+ const viewWidth = this.imageWidth || 100;
68
+ const viewHeight = this.imageHeight || 100;
69
+ return html `
70
+ <slot name="prompt"></slot>
71
+
72
+ <div class="toolbar">
73
+ ${this.imageSrc
74
+ ? html `
75
+ <button
76
+ type="button"
77
+ aria-pressed=${this.drawMode === 'select'}
78
+ @click=${() => __classPrivateFieldGet(this, _QtiSelectPointInteractionEdit_instances, "m", _QtiSelectPointInteractionEdit_setDrawMode).call(this, 'select')}
79
+ >
80
+ Select
81
+ </button>
82
+ <button
83
+ type="button"
84
+ aria-pressed=${this.drawMode === 'circle'}
85
+ @click=${() => __classPrivateFieldGet(this, _QtiSelectPointInteractionEdit_instances, "m", _QtiSelectPointInteractionEdit_setDrawMode).call(this, 'circle')}
86
+ >
87
+ Circle
88
+ </button>
89
+ <button
90
+ type="button"
91
+ aria-pressed=${this.drawMode === 'rect'}
92
+ @click=${() => __classPrivateFieldGet(this, _QtiSelectPointInteractionEdit_instances, "m", _QtiSelectPointInteractionEdit_setDrawMode).call(this, 'rect')}
93
+ >
94
+ Rect
95
+ </button>
96
+ <button type="button" class="danger" @click=${__classPrivateFieldGet(this, _QtiSelectPointInteractionEdit_instances, "m", _QtiSelectPointInteractionEdit_clearMappings)}>Clear mappings</button>
97
+ <button type="button" class="danger" @click=${__classPrivateFieldGet(this, _QtiSelectPointInteractionEdit_instances, "m", _QtiSelectPointInteractionEdit_removeImage)}>Remove image</button>
98
+ `
99
+ : html `
100
+ <button type="button" @click=${__classPrivateFieldGet(this, _QtiSelectPointInteractionEdit_instances, "m", _QtiSelectPointInteractionEdit_pasteImageFromClipboard)}>Paste URL</button>
101
+ <button type="button" @click=${__classPrivateFieldGet(this, _QtiSelectPointInteractionEdit_instances, "m", _QtiSelectPointInteractionEdit_openFilePicker)}>Upload image</button>
102
+ <input ${ref(__classPrivateFieldGet(this, _QtiSelectPointInteractionEdit_fileInputRef, "f"))} type="file" accept="image/*" @change=${__classPrivateFieldGet(this, _QtiSelectPointInteractionEdit_instances, "m", _QtiSelectPointInteractionEdit_onFileChange)} />
103
+ `}
104
+ </div>
105
+
106
+ ${this.sourceError ? html `<p class="meta" style="color:#b91c1c; margin-top:0;">${this.sourceError}</p>` : nothing}
107
+
108
+ <div
109
+ class="surface"
110
+ @pointerdown=${__classPrivateFieldGet(this, _QtiSelectPointInteractionEdit_instances, "m", _QtiSelectPointInteractionEdit_onPointerDown)}
111
+ @pointermove=${__classPrivateFieldGet(this, _QtiSelectPointInteractionEdit_instances, "m", _QtiSelectPointInteractionEdit_onPointerMove)}
112
+ @pointerup=${__classPrivateFieldGet(this, _QtiSelectPointInteractionEdit_instances, "m", _QtiSelectPointInteractionEdit_onPointerUp)}
113
+ @pointercancel=${__classPrivateFieldGet(this, _QtiSelectPointInteractionEdit_instances, "m", _QtiSelectPointInteractionEdit_onPointerCancel)}
114
+ >
115
+ <slot @slotchange=${__classPrivateFieldGet(this, _QtiSelectPointInteractionEdit_instances, "m", _QtiSelectPointInteractionEdit_syncImageFromDom)}></slot>
116
+ ${this.imageSrc
117
+ ? html `<svg viewBox="0 0 ${viewWidth} ${viewHeight}" preserveAspectRatio="none">
118
+ ${this.areaEntries.map(entry => __classPrivateFieldGet(this, _QtiSelectPointInteractionEdit_instances, "m", _QtiSelectPointInteractionEdit_renderAreaShape).call(this, entry))} ${__classPrivateFieldGet(this, _QtiSelectPointInteractionEdit_instances, "m", _QtiSelectPointInteractionEdit_renderDraft).call(this)}
119
+ </svg>
120
+ `
121
+ : nothing}
122
+ </div>
123
+
124
+ <div class="meta">Mappings: ${this.areaEntries.length} | mode: ${this.drawMode}</div>
125
+ `;
126
+ }
127
+ }
128
+ _QtiSelectPointInteractionEdit_imageElement = new WeakMap(), _QtiSelectPointInteractionEdit_dragging = new WeakMap(), _QtiSelectPointInteractionEdit_activePointerId = new WeakMap(), _QtiSelectPointInteractionEdit_shapeDrag = new WeakMap(), _QtiSelectPointInteractionEdit_fileInputRef = new WeakMap(), _QtiSelectPointInteractionEdit_onImageLoad = new WeakMap(), _QtiSelectPointInteractionEdit_instances = new WeakSet(), _QtiSelectPointInteractionEdit_syncImageFromDom = function _QtiSelectPointInteractionEdit_syncImageFromDom() {
129
+ if (__classPrivateFieldGet(this, _QtiSelectPointInteractionEdit_imageElement, "f")) {
130
+ __classPrivateFieldGet(this, _QtiSelectPointInteractionEdit_imageElement, "f").removeEventListener('load', __classPrivateFieldGet(this, _QtiSelectPointInteractionEdit_onImageLoad, "f"));
131
+ }
132
+ const image = this.querySelector(':scope > img');
133
+ __classPrivateFieldSet(this, _QtiSelectPointInteractionEdit_imageElement, image, "f");
134
+ if (!image) {
135
+ this.imageSrc = null;
136
+ this.imageAlt = null;
137
+ this.imageWidth = null;
138
+ this.imageHeight = null;
139
+ this.imageReady = false;
140
+ return;
141
+ }
142
+ image.addEventListener('load', __classPrivateFieldGet(this, _QtiSelectPointInteractionEdit_onImageLoad, "f"));
143
+ this.imageSrc = image.getAttribute('src') || null;
144
+ this.imageAlt = image.getAttribute('alt') || null;
145
+ this.imageWidth = __classPrivateFieldGet(this, _QtiSelectPointInteractionEdit_instances, "m", _QtiSelectPointInteractionEdit_parseDimension).call(this, image.getAttribute('width'));
146
+ this.imageHeight = __classPrivateFieldGet(this, _QtiSelectPointInteractionEdit_instances, "m", _QtiSelectPointInteractionEdit_parseDimension).call(this, image.getAttribute('height'));
147
+ this.imageReady = image.complete && !!this.imageSrc;
148
+ }, _QtiSelectPointInteractionEdit_ensureChildSlots = function _QtiSelectPointInteractionEdit_ensureChildSlots() {
149
+ const prompt = this.querySelector(':scope > qti-prompt');
150
+ if (prompt && prompt.getAttribute('slot') !== 'prompt') {
151
+ prompt.setAttribute('slot', 'prompt');
152
+ }
153
+ }, _QtiSelectPointInteractionEdit_parseDimension = function _QtiSelectPointInteractionEdit_parseDimension(value) {
154
+ if (!value)
155
+ return null;
156
+ const parsed = Number(value);
157
+ return Number.isFinite(parsed) ? parsed : null;
158
+ }, _QtiSelectPointInteractionEdit_syncAreaEntriesFromAttribute = function _QtiSelectPointInteractionEdit_syncAreaEntriesFromAttribute() {
159
+ try {
160
+ const raw = JSON.parse(this.areaMappings || '[]');
161
+ if (!Array.isArray(raw)) {
162
+ this.areaEntries = [];
163
+ return;
164
+ }
165
+ this.areaEntries = raw
166
+ .filter(entry => entry && (entry.shape === 'circle' || entry.shape === 'rect') && typeof entry.coords === 'string')
167
+ .map((entry, index) => ({
168
+ id: String(entry.id || `A${index + 1}`),
169
+ shape: entry.shape,
170
+ coords: String(entry.coords),
171
+ mappedValue: Number(entry.mappedValue ?? 1),
172
+ defaultValue: Number(entry.defaultValue ?? 0),
173
+ }));
174
+ }
175
+ catch {
176
+ this.areaEntries = [];
177
+ }
178
+ }, _QtiSelectPointInteractionEdit_persistAreaEntries = function _QtiSelectPointInteractionEdit_persistAreaEntries(entries) {
179
+ this.areaEntries = entries;
180
+ this.areaMappings = JSON.stringify(entries);
181
+ __classPrivateFieldGet(this, _QtiSelectPointInteractionEdit_instances, "m", _QtiSelectPointInteractionEdit_emitWrapperAttrsChange).call(this);
182
+ }, _QtiSelectPointInteractionEdit_onFileChange = async function _QtiSelectPointInteractionEdit_onFileChange(event) {
183
+ const input = event.currentTarget;
184
+ const file = input.files?.[0];
185
+ if (!file)
186
+ return;
187
+ const dataUrl = await __classPrivateFieldGet(this, _QtiSelectPointInteractionEdit_instances, "m", _QtiSelectPointInteractionEdit_toDataUrl).call(this, file);
188
+ await __classPrivateFieldGet(this, _QtiSelectPointInteractionEdit_instances, "m", _QtiSelectPointInteractionEdit_applyImageSource).call(this, dataUrl, file.name);
189
+ input.value = '';
190
+ }, _QtiSelectPointInteractionEdit_openFilePicker = function _QtiSelectPointInteractionEdit_openFilePicker(event) {
191
+ event.preventDefault();
192
+ event.stopPropagation();
193
+ __classPrivateFieldGet(this, _QtiSelectPointInteractionEdit_fileInputRef, "f").value?.click();
194
+ }, _QtiSelectPointInteractionEdit_isValidHttpUrl = function _QtiSelectPointInteractionEdit_isValidHttpUrl(value) {
195
+ try {
196
+ const url = new URL(value);
197
+ return url.protocol === 'http:' || url.protocol === 'https:';
198
+ }
199
+ catch {
200
+ return false;
201
+ }
202
+ }, _QtiSelectPointInteractionEdit_pasteImageFromClipboard = async function _QtiSelectPointInteractionEdit_pasteImageFromClipboard(event) {
203
+ event.preventDefault();
204
+ if (!navigator.clipboard?.readText) {
205
+ this.sourceError = 'Clipboard API is unavailable in this context.';
206
+ return;
207
+ }
208
+ const value = (await navigator.clipboard.readText()).trim();
209
+ if (!value) {
210
+ this.sourceError = 'Clipboard does not contain text.';
211
+ return;
212
+ }
213
+ if (!__classPrivateFieldGet(this, _QtiSelectPointInteractionEdit_instances, "m", _QtiSelectPointInteractionEdit_isValidHttpUrl).call(this, value)) {
214
+ this.sourceError = 'Clipboard text is not a valid URL.';
215
+ return;
216
+ }
217
+ await __classPrivateFieldGet(this, _QtiSelectPointInteractionEdit_instances, "m", _QtiSelectPointInteractionEdit_applyImageSource).call(this, value, null);
218
+ }, _QtiSelectPointInteractionEdit_applyImageSource = async function _QtiSelectPointInteractionEdit_applyImageSource(source, fallbackAlt) {
219
+ try {
220
+ const dimensions = await __classPrivateFieldGet(this, _QtiSelectPointInteractionEdit_instances, "m", _QtiSelectPointInteractionEdit_loadImageDimensions).call(this, source);
221
+ this.imageSrc = source;
222
+ this.imageAlt = this.imageAlt || fallbackAlt || 'image';
223
+ if (!this.imageWidth || !this.imageHeight) {
224
+ this.imageWidth = dimensions.width;
225
+ this.imageHeight = dimensions.height;
226
+ }
227
+ this.imageReady = false;
228
+ this.sourceError = null;
229
+ __classPrivateFieldGet(this, _QtiSelectPointInteractionEdit_instances, "m", _QtiSelectPointInteractionEdit_emitImageAttrsChange).call(this);
230
+ }
231
+ catch {
232
+ this.sourceError = 'Could not load image from that source.';
233
+ }
234
+ }, _QtiSelectPointInteractionEdit_removeImage = function _QtiSelectPointInteractionEdit_removeImage() {
235
+ this.imageSrc = null;
236
+ this.imageAlt = null;
237
+ this.imageWidth = null;
238
+ this.imageHeight = null;
239
+ this.imageReady = false;
240
+ this.draft = null;
241
+ __classPrivateFieldGet(this, _QtiSelectPointInteractionEdit_instances, "m", _QtiSelectPointInteractionEdit_persistAreaEntries).call(this, []);
242
+ __classPrivateFieldGet(this, _QtiSelectPointInteractionEdit_instances, "m", _QtiSelectPointInteractionEdit_emitImageAttrsChange).call(this);
243
+ }, _QtiSelectPointInteractionEdit_toDataUrl = function _QtiSelectPointInteractionEdit_toDataUrl(file) {
244
+ return new Promise((resolve, reject) => {
245
+ const reader = new FileReader();
246
+ reader.onload = () => resolve(String(reader.result || ''));
247
+ reader.onerror = () => reject(reader.error);
248
+ reader.readAsDataURL(file);
249
+ });
250
+ }, _QtiSelectPointInteractionEdit_loadImageDimensions = function _QtiSelectPointInteractionEdit_loadImageDimensions(src) {
251
+ return new Promise((resolve, reject) => {
252
+ const img = new Image();
253
+ img.onload = () => resolve({ width: img.naturalWidth, height: img.naturalHeight });
254
+ img.onerror = reject;
255
+ img.src = src;
256
+ });
257
+ }, _QtiSelectPointInteractionEdit_toOriginalCoords = function _QtiSelectPointInteractionEdit_toOriginalCoords(clientX, clientY) {
258
+ const img = __classPrivateFieldGet(this, _QtiSelectPointInteractionEdit_imageElement, "f");
259
+ if (!img)
260
+ return null;
261
+ const rect = img.getBoundingClientRect();
262
+ if (rect.width === 0 || rect.height === 0)
263
+ return null;
264
+ const originalWidth = this.imageWidth || img.naturalWidth || rect.width;
265
+ const originalHeight = this.imageHeight || img.naturalHeight || rect.height;
266
+ const x = ((clientX - rect.left) / rect.width) * originalWidth;
267
+ const y = ((clientY - rect.top) / rect.height) * originalHeight;
268
+ return {
269
+ x: Math.max(0, Math.min(originalWidth, x)),
270
+ y: Math.max(0, Math.min(originalHeight, y)),
271
+ };
272
+ }, _QtiSelectPointInteractionEdit_onPointerDown = function _QtiSelectPointInteractionEdit_onPointerDown(event) {
273
+ if (!this.imageReady || !this.imageSrc)
274
+ return;
275
+ const point = __classPrivateFieldGet(this, _QtiSelectPointInteractionEdit_instances, "m", _QtiSelectPointInteractionEdit_toOriginalCoords).call(this, event.clientX, event.clientY);
276
+ if (!point)
277
+ return;
278
+ if (this.drawMode === 'select') {
279
+ const shapeIndex = __classPrivateFieldGet(this, _QtiSelectPointInteractionEdit_instances, "m", _QtiSelectPointInteractionEdit_findHitShapeIndex).call(this, point.x, point.y);
280
+ if (shapeIndex < 0)
281
+ return;
282
+ const entry = this.areaEntries[shapeIndex];
283
+ const originCoords = __classPrivateFieldGet(this, _QtiSelectPointInteractionEdit_instances, "m", _QtiSelectPointInteractionEdit_parseCoords).call(this, entry.coords);
284
+ if (!originCoords)
285
+ return;
286
+ event.preventDefault();
287
+ event.stopPropagation();
288
+ const surface = event.currentTarget;
289
+ surface?.setPointerCapture(event.pointerId);
290
+ __classPrivateFieldSet(this, _QtiSelectPointInteractionEdit_dragging, true, "f");
291
+ __classPrivateFieldSet(this, _QtiSelectPointInteractionEdit_activePointerId, event.pointerId, "f");
292
+ __classPrivateFieldSet(this, _QtiSelectPointInteractionEdit_shapeDrag, {
293
+ index: shapeIndex,
294
+ startX: point.x,
295
+ startY: point.y,
296
+ originCoords,
297
+ shape: entry.shape,
298
+ }, "f");
299
+ return;
300
+ }
301
+ event.preventDefault();
302
+ event.stopPropagation();
303
+ const surface = event.currentTarget;
304
+ surface?.setPointerCapture(event.pointerId);
305
+ __classPrivateFieldSet(this, _QtiSelectPointInteractionEdit_dragging, true, "f");
306
+ __classPrivateFieldSet(this, _QtiSelectPointInteractionEdit_activePointerId, event.pointerId, "f");
307
+ this.draft = {
308
+ shape: this.drawMode,
309
+ startX: point.x,
310
+ startY: point.y,
311
+ currentX: point.x,
312
+ currentY: point.y,
313
+ };
314
+ }, _QtiSelectPointInteractionEdit_onPointerMove = function _QtiSelectPointInteractionEdit_onPointerMove(event) {
315
+ if (!__classPrivateFieldGet(this, _QtiSelectPointInteractionEdit_dragging, "f") || __classPrivateFieldGet(this, _QtiSelectPointInteractionEdit_activePointerId, "f") !== event.pointerId)
316
+ return;
317
+ event.preventDefault();
318
+ event.stopPropagation();
319
+ const point = __classPrivateFieldGet(this, _QtiSelectPointInteractionEdit_instances, "m", _QtiSelectPointInteractionEdit_toOriginalCoords).call(this, event.clientX, event.clientY);
320
+ if (!point)
321
+ return;
322
+ if (__classPrivateFieldGet(this, _QtiSelectPointInteractionEdit_shapeDrag, "f")) {
323
+ const moved = __classPrivateFieldGet(this, _QtiSelectPointInteractionEdit_instances, "m", _QtiSelectPointInteractionEdit_moveShape).call(this, __classPrivateFieldGet(this, _QtiSelectPointInteractionEdit_shapeDrag, "f"), point.x, point.y);
324
+ if (!moved)
325
+ return;
326
+ const nextEntries = [...this.areaEntries];
327
+ nextEntries[__classPrivateFieldGet(this, _QtiSelectPointInteractionEdit_shapeDrag, "f").index] = moved;
328
+ this.areaEntries = nextEntries;
329
+ return;
330
+ }
331
+ if (!this.draft)
332
+ return;
333
+ this.draft = {
334
+ ...this.draft,
335
+ currentX: point.x,
336
+ currentY: point.y,
337
+ };
338
+ }, _QtiSelectPointInteractionEdit_onPointerUp = function _QtiSelectPointInteractionEdit_onPointerUp(event) {
339
+ if (!__classPrivateFieldGet(this, _QtiSelectPointInteractionEdit_dragging, "f") || __classPrivateFieldGet(this, _QtiSelectPointInteractionEdit_activePointerId, "f") !== event.pointerId)
340
+ return;
341
+ event.preventDefault();
342
+ event.stopPropagation();
343
+ const point = __classPrivateFieldGet(this, _QtiSelectPointInteractionEdit_instances, "m", _QtiSelectPointInteractionEdit_toOriginalCoords).call(this, event.clientX, event.clientY);
344
+ const surface = event.currentTarget;
345
+ if (surface?.hasPointerCapture(event.pointerId)) {
346
+ surface.releasePointerCapture(event.pointerId);
347
+ }
348
+ __classPrivateFieldSet(this, _QtiSelectPointInteractionEdit_dragging, false, "f");
349
+ __classPrivateFieldSet(this, _QtiSelectPointInteractionEdit_activePointerId, null, "f");
350
+ if (__classPrivateFieldGet(this, _QtiSelectPointInteractionEdit_shapeDrag, "f")) {
351
+ __classPrivateFieldSet(this, _QtiSelectPointInteractionEdit_shapeDrag, null, "f");
352
+ __classPrivateFieldGet(this, _QtiSelectPointInteractionEdit_instances, "m", _QtiSelectPointInteractionEdit_persistAreaEntries).call(this, [...this.areaEntries]);
353
+ return;
354
+ }
355
+ if (!this.draft)
356
+ return;
357
+ if (!point) {
358
+ this.draft = null;
359
+ return;
360
+ }
361
+ const completedDraft = {
362
+ ...this.draft,
363
+ currentX: point.x,
364
+ currentY: point.y,
365
+ };
366
+ const entry = __classPrivateFieldGet(this, _QtiSelectPointInteractionEdit_instances, "m", _QtiSelectPointInteractionEdit_draftToEntry).call(this, completedDraft);
367
+ this.draft = null;
368
+ if (!entry)
369
+ return;
370
+ __classPrivateFieldGet(this, _QtiSelectPointInteractionEdit_instances, "m", _QtiSelectPointInteractionEdit_persistAreaEntries).call(this, [...this.areaEntries, entry]);
371
+ }, _QtiSelectPointInteractionEdit_onPointerCancel = function _QtiSelectPointInteractionEdit_onPointerCancel(event) {
372
+ if (__classPrivateFieldGet(this, _QtiSelectPointInteractionEdit_activePointerId, "f") !== event.pointerId)
373
+ return;
374
+ const surface = event.currentTarget;
375
+ if (surface?.hasPointerCapture(event.pointerId)) {
376
+ surface.releasePointerCapture(event.pointerId);
377
+ }
378
+ __classPrivateFieldSet(this, _QtiSelectPointInteractionEdit_dragging, false, "f");
379
+ __classPrivateFieldSet(this, _QtiSelectPointInteractionEdit_activePointerId, null, "f");
380
+ __classPrivateFieldSet(this, _QtiSelectPointInteractionEdit_shapeDrag, null, "f");
381
+ this.draft = null;
382
+ }, _QtiSelectPointInteractionEdit_parseCoords = function _QtiSelectPointInteractionEdit_parseCoords(coords) {
383
+ const values = coords.split(',').map(v => Number(v));
384
+ if (values.some(v => Number.isNaN(v)))
385
+ return null;
386
+ return values;
387
+ }, _QtiSelectPointInteractionEdit_findHitShapeIndex = function _QtiSelectPointInteractionEdit_findHitShapeIndex(x, y) {
388
+ for (let i = this.areaEntries.length - 1; i >= 0; i -= 1) {
389
+ const entry = this.areaEntries[i];
390
+ const values = __classPrivateFieldGet(this, _QtiSelectPointInteractionEdit_instances, "m", _QtiSelectPointInteractionEdit_parseCoords).call(this, entry.coords);
391
+ if (!values)
392
+ continue;
393
+ if (entry.shape === 'circle' && values.length >= 3) {
394
+ const [cx, cy, r] = values;
395
+ const dx = x - cx;
396
+ const dy = y - cy;
397
+ if (dx * dx + dy * dy <= r * r)
398
+ return i;
399
+ }
400
+ if (entry.shape === 'rect' && values.length >= 4) {
401
+ const [x1, y1, x2, y2] = values;
402
+ const minX = Math.min(x1, x2);
403
+ const maxX = Math.max(x1, x2);
404
+ const minY = Math.min(y1, y2);
405
+ const maxY = Math.max(y1, y2);
406
+ if (x >= minX && x <= maxX && y >= minY && y <= maxY)
407
+ return i;
408
+ }
409
+ }
410
+ return -1;
411
+ }, _QtiSelectPointInteractionEdit_moveShape = function _QtiSelectPointInteractionEdit_moveShape(state, x, y) {
412
+ const deltaX = x - state.startX;
413
+ const deltaY = y - state.startY;
414
+ const source = this.areaEntries[state.index];
415
+ if (!source)
416
+ return null;
417
+ if (state.shape === 'circle' && state.originCoords.length >= 3) {
418
+ const [cx, cy, r] = state.originCoords;
419
+ return {
420
+ ...source,
421
+ coords: `${Math.round(cx + deltaX)},${Math.round(cy + deltaY)},${Math.round(r)}`,
422
+ };
423
+ }
424
+ if (state.shape === 'rect' && state.originCoords.length >= 4) {
425
+ const [x1, y1, x2, y2] = state.originCoords;
426
+ return {
427
+ ...source,
428
+ coords: `${Math.round(x1 + deltaX)},${Math.round(y1 + deltaY)},${Math.round(x2 + deltaX)},${Math.round(y2 + deltaY)}`,
429
+ };
430
+ }
431
+ return null;
432
+ }, _QtiSelectPointInteractionEdit_draftToEntry = function _QtiSelectPointInteractionEdit_draftToEntry(draft) {
433
+ const epsilon = 1;
434
+ if (draft.shape === 'circle') {
435
+ const dx = draft.currentX - draft.startX;
436
+ const dy = draft.currentY - draft.startY;
437
+ const radius = Math.round(Math.sqrt(dx * dx + dy * dy));
438
+ if (radius < epsilon)
439
+ return null;
440
+ return {
441
+ id: `A${Date.now()}`,
442
+ shape: 'circle',
443
+ coords: `${Math.round(draft.startX)},${Math.round(draft.startY)},${radius}`,
444
+ mappedValue: 1,
445
+ defaultValue: 0,
446
+ };
447
+ }
448
+ const x1 = Math.round(Math.min(draft.startX, draft.currentX));
449
+ const y1 = Math.round(Math.min(draft.startY, draft.currentY));
450
+ const x2 = Math.round(Math.max(draft.startX, draft.currentX));
451
+ const y2 = Math.round(Math.max(draft.startY, draft.currentY));
452
+ if (Math.abs(x2 - x1) < epsilon || Math.abs(y2 - y1) < epsilon)
453
+ return null;
454
+ return {
455
+ id: `A${Date.now()}`,
456
+ shape: 'rect',
457
+ coords: `${x1},${y1},${x2},${y2}`,
458
+ mappedValue: 1,
459
+ defaultValue: 0,
460
+ };
461
+ }, _QtiSelectPointInteractionEdit_renderAreaShape = function _QtiSelectPointInteractionEdit_renderAreaShape(entry) {
462
+ const values = entry.coords.split(',').map(Number);
463
+ if (entry.shape === 'circle' && values.length >= 3) {
464
+ const [cx, cy, r] = values;
465
+ return svg `<circle
466
+ cx="${cx}"
467
+ cy="${cy}"
468
+ r="${r}"
469
+ fill="rgba(37,99,235,0.2)"
470
+ stroke="#1d4ed8"
471
+ stroke-width="2"
472
+ />`;
473
+ }
474
+ if (entry.shape === 'rect' && values.length >= 4) {
475
+ const [x1, y1, x2, y2] = values;
476
+ return svg `<rect
477
+ x="${Math.min(x1, x2)}"
478
+ y="${Math.min(y1, y2)}"
479
+ width="${Math.abs(x2 - x1)}"
480
+ height="${Math.abs(y2 - y1)}"
481
+ fill="rgba(37,99,235,0.2)"
482
+ stroke="#1d4ed8"
483
+ stroke-width="2"
484
+ />`;
485
+ }
486
+ return nothing;
487
+ }, _QtiSelectPointInteractionEdit_renderDraft = function _QtiSelectPointInteractionEdit_renderDraft() {
488
+ if (!this.draft)
489
+ return nothing;
490
+ const draftEntry = __classPrivateFieldGet(this, _QtiSelectPointInteractionEdit_instances, "m", _QtiSelectPointInteractionEdit_draftToEntry).call(this, this.draft);
491
+ if (!draftEntry)
492
+ return nothing;
493
+ return __classPrivateFieldGet(this, _QtiSelectPointInteractionEdit_instances, "m", _QtiSelectPointInteractionEdit_renderAreaShape).call(this, draftEntry);
494
+ }, _QtiSelectPointInteractionEdit_setDrawMode = function _QtiSelectPointInteractionEdit_setDrawMode(mode) {
495
+ this.drawMode = mode;
496
+ }, _QtiSelectPointInteractionEdit_clearMappings = function _QtiSelectPointInteractionEdit_clearMappings() {
497
+ __classPrivateFieldGet(this, _QtiSelectPointInteractionEdit_instances, "m", _QtiSelectPointInteractionEdit_persistAreaEntries).call(this, []);
498
+ }, _QtiSelectPointInteractionEdit_emitWrapperAttrsChange = function _QtiSelectPointInteractionEdit_emitWrapperAttrsChange() {
499
+ const detail = {
500
+ nodeType: 'qtiSelectPointInteraction',
501
+ tagName: 'qti-select-point-interaction',
502
+ attrs: {
503
+ areaMappings: this.areaMappings ?? '[]',
504
+ },
505
+ };
506
+ this.dispatchEvent(new CustomEvent('qti-prosemirror-node-attrs-change', {
507
+ bubbles: true,
508
+ composed: true,
509
+ detail,
510
+ }));
511
+ }, _QtiSelectPointInteractionEdit_emitImageAttrsChange = function _QtiSelectPointInteractionEdit_emitImageAttrsChange() {
512
+ const image = this.querySelector(':scope > img');
513
+ if (!image)
514
+ return;
515
+ const detail = {
516
+ nodeType: 'imgSelectPoint',
517
+ tagName: 'img',
518
+ attrs: {
519
+ imageSrc: this.imageSrc ?? null,
520
+ imageAlt: this.imageAlt ?? null,
521
+ imageWidth: this.imageWidth ?? null,
522
+ imageHeight: this.imageHeight ?? null,
523
+ },
524
+ };
525
+ image.dispatchEvent(new CustomEvent('qti-prosemirror-node-attrs-change', {
526
+ bubbles: true,
527
+ composed: true,
528
+ detail,
529
+ }));
530
+ };
531
+ QtiSelectPointInteractionEdit.styles = [
532
+ css `
533
+ :host {
534
+ display: block;
535
+ border: 1px solid #d1d5db;
536
+ border-radius: 6px;
537
+ padding: 12px;
538
+ background: #ffffff;
539
+ white-space: normal;
540
+ }
541
+
542
+ ::slotted(qti-prompt) {
543
+ display: block;
544
+ margin-bottom: 10px;
545
+ }
546
+
547
+ ::slotted(img) {
548
+ display: block;
549
+ max-width: 100%;
550
+ height: auto;
551
+ }
552
+
553
+ ::slotted(img:not([src])) {
554
+ min-width: 240px;
555
+ min-height: 160px;
556
+ border: 1px dashed #d1d5db;
557
+ background: #f9fafb;
558
+ }
559
+
560
+ .toolbar {
561
+ display: flex;
562
+ align-items: center;
563
+ gap: 8px;
564
+ margin-bottom: 10px;
565
+ flex-wrap: wrap;
566
+ }
567
+
568
+ .toolbar button,
569
+ .toolbar input {
570
+ font: inherit;
571
+ font-size: 12px;
572
+ }
573
+
574
+ .toolbar button {
575
+ border: 1px solid #9ca3af;
576
+ background: #f9fafb;
577
+ border-radius: 4px;
578
+ padding: 4px 8px;
579
+ cursor: pointer;
580
+ }
581
+
582
+ .toolbar button[aria-pressed='true'] {
583
+ background: #2563eb;
584
+ border-color: #2563eb;
585
+ color: #ffffff;
586
+ }
587
+
588
+ .toolbar .danger {
589
+ border-color: #b91c1c;
590
+ color: #b91c1c;
591
+ }
592
+
593
+ .surface {
594
+ position: relative;
595
+ display: inline-block;
596
+ max-width: 100%;
597
+ line-height: 0;
598
+ }
599
+
600
+ svg {
601
+ position: absolute;
602
+ inset: 0;
603
+ width: 100%;
604
+ height: 100%;
605
+ }
606
+
607
+ .meta {
608
+ margin-top: 8px;
609
+ font-size: 12px;
610
+ color: #4b5563;
611
+ }
612
+
613
+ input[type='file'] {
614
+ display: none;
615
+ }
616
+ `,
617
+ ];
618
+ __decorate([
619
+ property({ type: String, attribute: 'area-mappings' })
620
+ ], QtiSelectPointInteractionEdit.prototype, "areaMappings", void 0);
621
+ __decorate([
622
+ state()
623
+ ], QtiSelectPointInteractionEdit.prototype, "drawMode", void 0);
624
+ __decorate([
625
+ state()
626
+ ], QtiSelectPointInteractionEdit.prototype, "imageReady", void 0);
627
+ __decorate([
628
+ state()
629
+ ], QtiSelectPointInteractionEdit.prototype, "imageSrc", void 0);
630
+ __decorate([
631
+ state()
632
+ ], QtiSelectPointInteractionEdit.prototype, "imageAlt", void 0);
633
+ __decorate([
634
+ state()
635
+ ], QtiSelectPointInteractionEdit.prototype, "imageWidth", void 0);
636
+ __decorate([
637
+ state()
638
+ ], QtiSelectPointInteractionEdit.prototype, "imageHeight", void 0);
639
+ __decorate([
640
+ state()
641
+ ], QtiSelectPointInteractionEdit.prototype, "areaEntries", void 0);
642
+ __decorate([
643
+ state()
644
+ ], QtiSelectPointInteractionEdit.prototype, "draft", void 0);
645
+ __decorate([
646
+ state()
647
+ ], QtiSelectPointInteractionEdit.prototype, "sourceError", void 0);
648
+ if (!customElements.get('qti-select-point-interaction')) {
649
+ customElements.define('qti-select-point-interaction', QtiSelectPointInteractionEdit);
650
+ }
@@ -0,0 +1,3 @@
1
+ import type { NodeSpec } from 'prosemirror-model';
2
+ export declare const qtiSelectPointInteractionNodeSpec: NodeSpec;
3
+ //# sourceMappingURL=qti-select-point-interaction.schema.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"qti-select-point-interaction.schema.d.ts","sourceRoot":"","sources":["../../../src/components/qti-select-point-interaction/qti-select-point-interaction.schema.ts"],"names":[],"mappings":"AAEA,OAAO,KAAK,EAA0C,QAAQ,EAAU,MAAM,mBAAmB,CAAC;AAqElG,eAAO,MAAM,iCAAiC,EAAE,QA2C/C,CAAC"}
@@ -0,0 +1,98 @@
1
+ import { Fragment } from 'prosemirror-model';
2
+ function parseNumberAttribute(value) {
3
+ if (value == null || value === '')
4
+ return null;
5
+ const parsed = Number(value);
6
+ return Number.isFinite(parsed) ? parsed : null;
7
+ }
8
+ function isElementLike(node) {
9
+ return (typeof node === 'object' &&
10
+ node !== null &&
11
+ 'getAttribute' in node &&
12
+ typeof node.getAttribute === 'function' &&
13
+ 'querySelector' in node &&
14
+ typeof node.querySelector === 'function');
15
+ }
16
+ function parseWrapperAttrs(node) {
17
+ return {
18
+ responseIdentifier: node.getAttribute('response-identifier'),
19
+ maxChoices: parseNumberAttribute(node.getAttribute('max-choices')) ?? 0,
20
+ minChoices: parseNumberAttribute(node.getAttribute('min-choices')) ?? 0,
21
+ class: node.getAttribute('class') || null,
22
+ areaMappings: node.getAttribute('area-mappings') || '[]',
23
+ correctResponse: node.getAttribute('correct-response') || null,
24
+ };
25
+ }
26
+ function buildPromptNode(schema, node) {
27
+ const qtiPromptType = schema.nodes.qtiPrompt;
28
+ const promptParagraphType = schema.nodes.qtiPromptParagraph;
29
+ if (!qtiPromptType || !promptParagraphType)
30
+ return null;
31
+ const promptElement = node.querySelector('qti-prompt');
32
+ const promptText = promptElement?.textContent?.trim() || 'Mark the correct point on the image.';
33
+ const paragraph = promptParagraphType.create(null, promptText ? schema.text(promptText) : null);
34
+ return qtiPromptType.create(null, paragraph);
35
+ }
36
+ function buildImgSelectPointNode(schema, node) {
37
+ const imgSelectPointType = schema.nodes.imgSelectPoint;
38
+ if (!imgSelectPointType)
39
+ return null;
40
+ const image = node.querySelector('img');
41
+ const imageSrc = image?.getAttribute('src') || null;
42
+ const imageAlt = image?.getAttribute('alt') || null;
43
+ const imageWidth = parseNumberAttribute(image?.getAttribute('width') || null);
44
+ const imageHeight = parseNumberAttribute(image?.getAttribute('height') || null);
45
+ return imgSelectPointType.create({
46
+ imageSrc,
47
+ imageAlt,
48
+ imageWidth,
49
+ imageHeight,
50
+ });
51
+ }
52
+ export const qtiSelectPointInteractionNodeSpec = {
53
+ group: 'block',
54
+ content: 'qtiPrompt imgSelectPoint',
55
+ selectable: true,
56
+ isolating: true,
57
+ attrs: {
58
+ responseIdentifier: { default: null },
59
+ maxChoices: { default: 0 },
60
+ minChoices: { default: 0 },
61
+ class: { default: null },
62
+ areaMappings: { default: '[]' },
63
+ correctResponse: { default: null },
64
+ },
65
+ parseDOM: [
66
+ {
67
+ tag: 'qti-select-point-interaction',
68
+ getAttrs: (node) => {
69
+ if (!isElementLike(node))
70
+ return {};
71
+ return parseWrapperAttrs(node);
72
+ },
73
+ getContent: (node, schema) => {
74
+ if (!isElementLike(node))
75
+ return Fragment.empty;
76
+ const promptNode = buildPromptNode(schema, node);
77
+ const imageNode = buildImgSelectPointNode(schema, node);
78
+ const children = [promptNode, imageNode].filter(Boolean);
79
+ return Fragment.fromArray(children);
80
+ },
81
+ },
82
+ ],
83
+ toDOM(node) {
84
+ const attrs = {
85
+ 'max-choices': String(node.attrs.maxChoices ?? 0),
86
+ 'min-choices': String(node.attrs.minChoices ?? 0),
87
+ };
88
+ if (node.attrs.responseIdentifier)
89
+ attrs['response-identifier'] = String(node.attrs.responseIdentifier);
90
+ if (node.attrs.class)
91
+ attrs.class = String(node.attrs.class);
92
+ if (node.attrs.areaMappings)
93
+ attrs['area-mappings'] = String(node.attrs.areaMappings);
94
+ if (node.attrs.correctResponse)
95
+ attrs['correct-response'] = String(node.attrs.correctResponse);
96
+ return ['qti-select-point-interaction', attrs, 0];
97
+ },
98
+ };
@@ -0,0 +1,3 @@
1
+ import type { InteractionComposerHandler } from '@qti-editor/interaction-shared/composer/types.js';
2
+ export declare const selectPointComposerHandler: InteractionComposerHandler;
3
+ //# sourceMappingURL=handler.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"handler.d.ts","sourceRoot":"","sources":["../../src/composer/handler.ts"],"names":[],"mappings":"AAGA,OAAO,KAAK,EAAE,0BAA0B,EAAE,MAAM,kDAAkD,CAAC;AAEnG,eAAO,MAAM,0BAA0B,EAAE,0BAGxC,CAAC"}
@@ -0,0 +1,6 @@
1
+ import { composeSelectPointInteractionElement } from '../components/qti-select-point-interaction/qti-select-point-interaction.compose.js';
2
+ import { SELECT_POINT_INTERACTION_TAG } from './metadata.js';
3
+ export const selectPointComposerHandler = {
4
+ tagName: SELECT_POINT_INTERACTION_TAG,
5
+ compose: composeSelectPointInteractionElement,
6
+ };
@@ -0,0 +1,22 @@
1
+ export declare const MAP_RESPONSE_POINT_TEMPLATE = "https://purl.imsglobal.org/spec/qti/v3p0/rptemplates/map_response_point.xml";
2
+ export declare const SELECT_POINT_INTERACTION_TAG: "qti-select-point-interaction";
3
+ export declare const SELECT_POINT_INTERACTION_NODE_TYPE: "qtiSelectPointInteraction";
4
+ export declare const selectPointInteractionComposerMetadata: {
5
+ tagName: "qti-select-point-interaction";
6
+ nodeTypeName: "qtiSelectPointInteraction";
7
+ responseProcessingTemplate: string;
8
+ responseProcessing: {
9
+ templateUri: string;
10
+ internalKind: "map_response_point";
11
+ internalSourceXml: string;
12
+ };
13
+ editorOnlyAttributes: string[];
14
+ userEditableAttributes: string[];
15
+ };
16
+ export declare const selectPointNodeAttributePanelMetadataByNodeTypeName: {
17
+ [x: string]: {
18
+ nodeTypeName: "qtiSelectPointInteraction";
19
+ editableAttributes: string[];
20
+ };
21
+ };
22
+ //# sourceMappingURL=metadata.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"metadata.d.ts","sourceRoot":"","sources":["../../src/composer/metadata.ts"],"names":[],"mappings":"AAEA,eAAO,MAAM,2BAA2B,gFACuC,CAAC;AAWhF,eAAO,MAAM,4BAA4B,EAAG,8BAAuC,CAAC;AACpF,eAAO,MAAM,kCAAkC,EAAG,2BAAoC,CAAC;AAEvF,eAAO,MAAM,sCAAsC;;;;;;;;;;;CAWZ,CAAC;AAExC,eAAO,MAAM,mDAAmD;;;;;CAKV,CAAC"}
@@ -0,0 +1,29 @@
1
+ export const MAP_RESPONSE_POINT_TEMPLATE = 'https://purl.imsglobal.org/spec/qti/v3p0/rptemplates/map_response_point.xml';
2
+ const MAP_RESPONSE_POINT_INTERNAL_TEMPLATE = `
3
+ <qti-set-outcome-value identifier="SCORE">
4
+ <qti-sum>
5
+ <qti-variable identifier="SCORE"/>
6
+ <qti-map-response-point identifier="$responseIdentifier"/>
7
+ </qti-sum>
8
+ </qti-set-outcome-value>
9
+ `;
10
+ export const SELECT_POINT_INTERACTION_TAG = 'qti-select-point-interaction';
11
+ export const SELECT_POINT_INTERACTION_NODE_TYPE = 'qtiSelectPointInteraction';
12
+ export const selectPointInteractionComposerMetadata = {
13
+ tagName: SELECT_POINT_INTERACTION_TAG,
14
+ nodeTypeName: SELECT_POINT_INTERACTION_NODE_TYPE,
15
+ responseProcessingTemplate: MAP_RESPONSE_POINT_TEMPLATE,
16
+ responseProcessing: {
17
+ templateUri: MAP_RESPONSE_POINT_TEMPLATE,
18
+ internalKind: 'map_response_point',
19
+ internalSourceXml: MAP_RESPONSE_POINT_INTERNAL_TEMPLATE,
20
+ },
21
+ editorOnlyAttributes: ['class', 'area-mappings', 'correct-response'],
22
+ userEditableAttributes: ['maxChoices', 'minChoices'],
23
+ };
24
+ export const selectPointNodeAttributePanelMetadataByNodeTypeName = {
25
+ [SELECT_POINT_INTERACTION_NODE_TYPE.toLowerCase()]: {
26
+ nodeTypeName: SELECT_POINT_INTERACTION_NODE_TYPE,
27
+ editableAttributes: selectPointInteractionComposerMetadata.userEditableAttributes,
28
+ },
29
+ };
@@ -0,0 +1,30 @@
1
+ export declare const selectPointInteractionDescriptor: {
2
+ tagName: string;
3
+ nodeTypeName: string;
4
+ nodeSpecs: {
5
+ name: string;
6
+ spec: import("prosemirror-model").NodeSpec;
7
+ }[];
8
+ insertCommand: import("prosemirror-state").Command;
9
+ keyboardShortcut: string;
10
+ composerMetadata: {
11
+ tagName: "qti-select-point-interaction";
12
+ nodeTypeName: "qtiSelectPointInteraction";
13
+ responseProcessingTemplate: string;
14
+ responseProcessing: {
15
+ templateUri: string;
16
+ internalKind: "map_response_point";
17
+ internalSourceXml: string;
18
+ };
19
+ editorOnlyAttributes: string[];
20
+ userEditableAttributes: string[];
21
+ };
22
+ composerHandler: import("@qti-editor/interfaces").InteractionComposerHandler;
23
+ attributePanelMetadata: {
24
+ [x: string]: {
25
+ nodeTypeName: "qtiSelectPointInteraction";
26
+ editableAttributes: string[];
27
+ };
28
+ };
29
+ };
30
+ //# sourceMappingURL=descriptor.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"descriptor.d.ts","sourceRoot":"","sources":["../src/descriptor.ts"],"names":[],"mappings":"AASA,eAAO,MAAM,gCAAgC;;;;;;;;;;;;;;;;;;;;;;;;;;;;CAYZ,CAAC"}
@@ -0,0 +1,18 @@
1
+ import { insertSelectPointInteraction } from './components/qti-select-point-interaction/qti-select-point-interaction.commands.js';
2
+ import { qtiSelectPointInteractionNodeSpec } from './components/qti-select-point-interaction/qti-select-point-interaction.schema.js';
3
+ import { imgSelectPointNodeSpec } from './components/qti-select-point-interaction/img-select-point.schema.js';
4
+ import { selectPointInteractionComposerMetadata, selectPointNodeAttributePanelMetadataByNodeTypeName } from './composer/metadata.js';
5
+ import { selectPointComposerHandler } from './composer/handler.js';
6
+ export const selectPointInteractionDescriptor = {
7
+ tagName: 'qti-select-point-interaction',
8
+ nodeTypeName: 'qtiSelectPointInteraction',
9
+ nodeSpecs: [
10
+ { name: 'qtiSelectPointInteraction', spec: qtiSelectPointInteractionNodeSpec },
11
+ { name: 'imgSelectPoint', spec: imgSelectPointNodeSpec },
12
+ ],
13
+ insertCommand: insertSelectPointInteraction,
14
+ keyboardShortcut: 'Mod-Shift-p',
15
+ composerMetadata: selectPointInteractionComposerMetadata,
16
+ composerHandler: selectPointComposerHandler,
17
+ attributePanelMetadata: selectPointNodeAttributePanelMetadataByNodeTypeName,
18
+ };
@@ -0,0 +1,9 @@
1
+ export * from './components/qti-select-point-interaction/qti-select-point-interaction.js';
2
+ export * from './components/qti-select-point-interaction/qti-select-point-interaction.schema.js';
3
+ export * from './components/qti-select-point-interaction/qti-select-point-interaction.commands.js';
4
+ export * from './components/qti-select-point-interaction/qti-select-point-interaction.compose.js';
5
+ export * from './components/qti-select-point-interaction/img-select-point.schema.js';
6
+ export * from './composer/metadata.js';
7
+ export * from './composer/handler.js';
8
+ export * from './descriptor.js';
9
+ //# sourceMappingURL=index.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"index.d.ts","sourceRoot":"","sources":["../src/index.ts"],"names":[],"mappings":"AAAA,cAAc,2EAA2E,CAAC;AAC1F,cAAc,kFAAkF,CAAC;AACjG,cAAc,oFAAoF,CAAC;AACnG,cAAc,mFAAmF,CAAC;AAClG,cAAc,sEAAsE,CAAC;AAErF,cAAc,wBAAwB,CAAC;AACvC,cAAc,uBAAuB,CAAC;AACtC,cAAc,iBAAiB,CAAC"}
package/dist/index.js ADDED
@@ -0,0 +1,8 @@
1
+ export * from './components/qti-select-point-interaction/qti-select-point-interaction.js';
2
+ export * from './components/qti-select-point-interaction/qti-select-point-interaction.schema.js';
3
+ export * from './components/qti-select-point-interaction/qti-select-point-interaction.commands.js';
4
+ export * from './components/qti-select-point-interaction/qti-select-point-interaction.compose.js';
5
+ export * from './components/qti-select-point-interaction/img-select-point.schema.js';
6
+ export * from './composer/metadata.js';
7
+ export * from './composer/handler.js';
8
+ export * from './descriptor.js';
package/package.json ADDED
@@ -0,0 +1,42 @@
1
+ {
2
+ "name": "@qti-editor/interaction-select-point",
3
+ "description": "QTI select-point interaction schemas, components, commands, and composer",
4
+ "version": "0.1.0",
5
+ "type": "module",
6
+ "main": "./dist/index.js",
7
+ "types": "./dist/index.d.ts",
8
+ "exports": {
9
+ ".": {
10
+ "types": "./dist/index.d.ts",
11
+ "default": "./dist/index.js"
12
+ },
13
+ "./*": {
14
+ "types": "./dist/*",
15
+ "default": "./dist/*"
16
+ }
17
+ },
18
+ "dependencies": {
19
+ "@qti-components/select-point-interaction": "^1.0.1",
20
+ "@qti-editor/interfaces": "0.1.0",
21
+ "@qti-editor/interaction-shared": "0.1.0"
22
+ },
23
+ "peerDependencies": {
24
+ "lit": "^3.3.1"
25
+ },
26
+ "devDependencies": {
27
+ "lit": "^3.3.1",
28
+ "prosemirror-model": "^1.25.4",
29
+ "prosemirror-state": "^1.4.4"
30
+ },
31
+ "files": [
32
+ "dist"
33
+ ],
34
+ "publishConfig": {
35
+ "access": "public"
36
+ },
37
+ "scripts": {
38
+ "typecheck": "tsc --noEmit",
39
+ "build": "tsc",
40
+ "clean": "rm -rf dist"
41
+ }
42
+ }