@mirasen/chessboard 1.1.5 → 1.2.1
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/CHANGELOG.md +45 -0
- package/README.md +61 -13
- package/dist/animation/render/fade.d.ts +2 -3
- package/dist/animation/render/fade.js +6 -6
- package/dist/animation/render/move.d.ts +2 -3
- package/dist/animation/render/move.js +6 -6
- package/dist/animation/render/plan.d.ts +3 -4
- package/dist/animation/render/plan.js +5 -5
- package/dist/animation/render/static.d.ts +2 -3
- package/dist/animation/render/static.js +4 -4
- package/dist/animation/render/types.d.ts +10 -4
- package/dist/extensions/build/index.d.ts +1 -2
- package/dist/extensions/build/index.js +1 -1
- package/dist/extensions/factory/main.js +11 -7
- package/dist/extensions/factory/runtime.js +24 -1
- package/dist/extensions/first-party/active-target/factory.js +18 -11
- package/dist/extensions/first-party/annotations/api.d.ts +16 -0
- package/dist/extensions/first-party/annotations/api.js +79 -0
- package/dist/extensions/first-party/annotations/committed.d.ts +3 -0
- package/dist/extensions/first-party/annotations/committed.js +11 -0
- package/dist/extensions/first-party/annotations/constants.d.ts +3 -0
- package/dist/extensions/first-party/annotations/constants.js +54 -0
- package/dist/extensions/first-party/annotations/denormalize.d.ts +4 -0
- package/dist/extensions/first-party/annotations/denormalize.js +22 -0
- package/dist/extensions/first-party/annotations/factory.d.ts +3 -0
- package/dist/extensions/first-party/annotations/factory.js +143 -0
- package/dist/extensions/first-party/annotations/interaction.d.ts +8 -0
- package/dist/extensions/first-party/annotations/interaction.js +129 -0
- package/dist/extensions/first-party/annotations/invalidation.d.ts +3 -0
- package/dist/extensions/first-party/annotations/invalidation.js +7 -0
- package/dist/extensions/first-party/annotations/normalize.d.ts +12 -0
- package/dist/extensions/first-party/annotations/normalize.js +54 -0
- package/dist/extensions/first-party/annotations/render/committed.d.ts +3 -0
- package/dist/extensions/first-party/annotations/render/committed.js +123 -0
- package/dist/extensions/first-party/annotations/render/helpers/arrows.d.ts +33 -0
- package/dist/extensions/first-party/annotations/render/helpers/arrows.js +93 -0
- package/dist/extensions/first-party/annotations/render/helpers/circles.d.ts +18 -0
- package/dist/extensions/first-party/annotations/render/helpers/circles.js +30 -0
- package/dist/extensions/first-party/annotations/render/preview.d.ts +3 -0
- package/dist/extensions/first-party/annotations/render/preview.js +96 -0
- package/dist/extensions/first-party/annotations/types/internal.d.ts +77 -0
- package/dist/extensions/first-party/annotations/types/internal.js +1 -0
- package/dist/extensions/first-party/annotations/types/main.d.ts +40 -0
- package/dist/extensions/first-party/annotations/types/main.js +6 -0
- package/dist/extensions/first-party/annotations/types/public.d.ts +48 -0
- package/dist/extensions/first-party/annotations/types/public.js +1 -0
- package/dist/extensions/first-party/annotations/update.d.ts +3 -0
- package/dist/extensions/first-party/annotations/update.js +45 -0
- package/dist/extensions/first-party/auto-promote/factory.js +6 -6
- package/dist/extensions/first-party/board-events/factory.js +6 -6
- package/dist/extensions/first-party/common/helpers.d.ts +2 -1
- package/dist/extensions/first-party/common/helpers.js +6 -5
- package/dist/extensions/first-party/common/types.d.ts +2 -0
- package/dist/extensions/first-party/last-move/factory.js +9 -9
- package/dist/extensions/first-party/legal-moves/factory.js +8 -8
- package/dist/extensions/first-party/main-renderer/animation/factory.d.ts +2 -2
- package/dist/extensions/first-party/main-renderer/animation/factory.js +4 -4
- package/dist/extensions/first-party/main-renderer/animation/render.d.ts +1 -1
- package/dist/extensions/first-party/main-renderer/animation/render.js +2 -2
- package/dist/extensions/first-party/main-renderer/animation/types.d.ts +3 -3
- package/dist/extensions/first-party/main-renderer/board/factory.js +2 -2
- package/dist/extensions/first-party/main-renderer/board/render.d.ts +1 -1
- package/dist/extensions/first-party/main-renderer/board/render.js +4 -4
- package/dist/extensions/first-party/main-renderer/board/types.d.ts +1 -1
- package/dist/extensions/first-party/main-renderer/coordinates/factory.js +2 -2
- package/dist/extensions/first-party/main-renderer/coordinates/render.d.ts +1 -1
- package/dist/extensions/first-party/main-renderer/coordinates/render.js +5 -5
- package/dist/extensions/first-party/main-renderer/coordinates/types.d.ts +1 -1
- package/dist/extensions/first-party/main-renderer/drag/factory.d.ts +2 -2
- package/dist/extensions/first-party/main-renderer/drag/factory.js +11 -8
- package/dist/extensions/first-party/main-renderer/drag/render.d.ts +1 -1
- package/dist/extensions/first-party/main-renderer/drag/render.js +7 -6
- package/dist/extensions/first-party/main-renderer/drag/types.d.ts +6 -5
- package/dist/extensions/first-party/main-renderer/drag/update.js +2 -2
- package/dist/extensions/first-party/main-renderer/factory.js +9 -5
- package/dist/extensions/first-party/main-renderer/piece-symbols.d.ts +19 -0
- package/dist/extensions/first-party/main-renderer/piece-symbols.js +45 -0
- package/dist/extensions/first-party/main-renderer/pieces/factory.d.ts +2 -2
- package/dist/extensions/first-party/main-renderer/pieces/factory.js +4 -4
- package/dist/extensions/first-party/main-renderer/pieces/render.d.ts +1 -1
- package/dist/extensions/first-party/main-renderer/pieces/render.js +8 -8
- package/dist/extensions/first-party/main-renderer/pieces/types.d.ts +4 -4
- package/dist/extensions/first-party/main-renderer/types/extension.d.ts +1 -1
- package/dist/extensions/first-party/main-renderer/types/extension.js +8 -1
- package/dist/extensions/first-party/main-renderer/types/instance.d.ts +2 -0
- package/dist/extensions/first-party/promotion/factory.js +10 -10
- package/dist/extensions/first-party/selected-square/factory.js +8 -8
- package/dist/extensions/first-party/watermark/factory.js +8 -8
- package/dist/extensions/types/basic/events.d.ts +32 -3
- package/dist/extensions/types/basic/events.js +2 -1
- package/dist/extensions/types/basic/mount.d.ts +5 -2
- package/dist/extensions/types/basic/mount.js +0 -2
- package/dist/extensions/types/basic/transient-visuals.d.ts +1 -1
- package/dist/extensions/types/context/animation.d.ts +3 -3
- package/dist/extensions/types/context/events.d.ts +2 -1
- package/dist/extensions/types/context/update.d.ts +6 -7
- package/dist/extensions/types/extension.d.ts +3 -0
- package/dist/extensions/types/main.d.ts +1 -0
- package/dist/extensions/types/surface/commands.d.ts +1 -1
- package/dist/extensions/types/surface/main.d.ts +6 -4
- package/dist/extensions/types/wrapper.d.ts +3 -1
- package/dist/extensions/types/wrapper.js +6 -2
- package/dist/extensions/update.js +6 -10
- package/dist/index.d.ts +1 -1
- package/dist/render/mount.js +3 -3
- package/dist/render/rendering/state.js +2 -2
- package/dist/render/svg/factory.js +40 -25
- package/dist/render/svg/helpers.d.ts +8 -4
- package/dist/render/svg/helpers.js +27 -12
- package/dist/render/svg/ids.d.ts +6 -0
- package/dist/render/svg/ids.js +11 -0
- package/dist/render/types.d.ts +4 -3
- package/dist/render/types.js +2 -1
- package/dist/runtime/factory/input.d.ts +3 -1
- package/dist/runtime/factory/input.js +11 -2
- package/dist/runtime/factory/main.js +10 -4
- package/dist/runtime/input/adapter/event.js +2 -2
- package/dist/runtime/input/adapter/pointer.d.ts +2 -2
- package/dist/runtime/input/controller/factory.d.ts +1 -1
- package/dist/runtime/input/controller/factory.js +35 -15
- package/dist/runtime/input/controller/helpers.d.ts +1 -1
- package/dist/runtime/input/controller/interaction.d.ts +3 -0
- package/dist/runtime/input/controller/interaction.js +14 -0
- package/dist/runtime/input/controller/pointer.d.ts +6 -6
- package/dist/runtime/input/controller/pointer.js +53 -27
- package/dist/runtime/input/controller/transient-visuals.d.ts +2 -3
- package/dist/runtime/input/controller/types.d.ts +6 -5
- package/dist/runtime/types/main.d.ts +1 -1
- package/dist/wrapper/factory.js +2 -7
- package/dist/wrapper/types.d.ts +3 -11
- package/package.json +1 -2
|
@@ -1,43 +1,58 @@
|
|
|
1
|
-
import { createSvgElement } from './helpers.js';
|
|
1
|
+
import { createSvgDefsElement, createSvgElement, createSvgRootElement } from './helpers.js';
|
|
2
2
|
export function createSvgRoots(options) {
|
|
3
|
-
const {
|
|
4
|
-
const svgRoot =
|
|
3
|
+
const { element } = options;
|
|
4
|
+
const svgRoot = createSvgRootElement(element, { 'data-chessboard-id': 'svg-root' });
|
|
5
5
|
svgRoot.style.setProperty('user-select', 'none');
|
|
6
6
|
svgRoot.style.setProperty('-webkit-user-select', 'none');
|
|
7
7
|
svgRoot.style.setProperty('touch-action', 'pinch-zoom');
|
|
8
8
|
svgRoot.style.setProperty('-webkit-touch-callout', 'none');
|
|
9
9
|
svgRoot.style.setProperty('-webkit-tap-highlight-color', 'transparent');
|
|
10
|
+
// Create children in the correct order
|
|
11
|
+
const board = createSvgElement(svgRoot, 'g', { 'data-chessboard-id': 'board-root' });
|
|
12
|
+
const coordinates = createSvgElement(svgRoot, 'g', {
|
|
13
|
+
'data-chessboard-id': 'coordinates-root'
|
|
14
|
+
});
|
|
15
|
+
const underPieces = createSvgElement(svgRoot, 'g', {
|
|
16
|
+
'data-chessboard-id': 'under-pieces-root'
|
|
17
|
+
});
|
|
18
|
+
const pieces = createSvgElement(svgRoot, 'g', { 'data-chessboard-id': 'pieces-root' });
|
|
19
|
+
const overPieces = createSvgElement(svgRoot, 'g', {
|
|
20
|
+
'data-chessboard-id': 'over-pieces-root'
|
|
21
|
+
});
|
|
22
|
+
const animation = createSvgElement(svgRoot, 'g', {
|
|
23
|
+
'data-chessboard-id': 'animation-root'
|
|
24
|
+
});
|
|
25
|
+
const underDrag = createSvgElement(svgRoot, 'g', {
|
|
26
|
+
'data-chessboard-id': 'under-drag-root'
|
|
27
|
+
});
|
|
28
|
+
const drag = createSvgElement(svgRoot, 'g', { 'data-chessboard-id': 'drag-root' });
|
|
29
|
+
const overDrag = createSvgElement(svgRoot, 'g', {
|
|
30
|
+
'data-chessboard-id': 'over-drag-root'
|
|
31
|
+
});
|
|
10
32
|
const result = {
|
|
11
33
|
svgRoot,
|
|
12
|
-
|
|
13
|
-
|
|
14
|
-
|
|
15
|
-
|
|
16
|
-
|
|
17
|
-
|
|
18
|
-
|
|
19
|
-
|
|
20
|
-
|
|
21
|
-
overDrag: createSvgElement(doc, 'g', { 'data-chessboard-id': 'over-drag-root' })
|
|
34
|
+
board,
|
|
35
|
+
coordinates,
|
|
36
|
+
underPieces,
|
|
37
|
+
pieces,
|
|
38
|
+
overPieces,
|
|
39
|
+
animation,
|
|
40
|
+
underDrag,
|
|
41
|
+
drag,
|
|
42
|
+
overDrag
|
|
22
43
|
};
|
|
23
|
-
// Attach layers in the correct order
|
|
24
|
-
svgRoot.appendChild(result.defs);
|
|
25
|
-
svgRoot.appendChild(result.board);
|
|
26
|
-
svgRoot.appendChild(result.coordinates);
|
|
27
|
-
svgRoot.appendChild(result.underPieces);
|
|
28
|
-
svgRoot.appendChild(result.pieces);
|
|
29
|
-
svgRoot.appendChild(result.overPieces);
|
|
30
|
-
svgRoot.appendChild(result.animation);
|
|
31
|
-
svgRoot.appendChild(result.underDrag);
|
|
32
|
-
svgRoot.appendChild(result.drag);
|
|
33
|
-
svgRoot.appendChild(result.overDrag);
|
|
34
44
|
return result;
|
|
35
45
|
}
|
|
36
46
|
export function allocateExtensionSlotRoots(svgRoots, extensionId, slots) {
|
|
37
47
|
const result = {};
|
|
38
48
|
for (const slot of slots) {
|
|
39
49
|
const id = `extension-slot-root-${slot}-${extensionId}`;
|
|
40
|
-
|
|
50
|
+
if (slot === 'defs') {
|
|
51
|
+
result[slot] = createSvgDefsElement(svgRoots.svgRoot, { 'data-chessboard-id': id });
|
|
52
|
+
}
|
|
53
|
+
else {
|
|
54
|
+
result[slot] = createSvgElement(svgRoots[slot], 'g', { 'data-chessboard-id': id });
|
|
55
|
+
}
|
|
41
56
|
}
|
|
42
57
|
return result;
|
|
43
58
|
}
|
|
@@ -9,10 +9,14 @@ export declare const SVG_NS = "http://www.w3.org/2000/svg";
|
|
|
9
9
|
export declare function isLightSquare(sq: Square): boolean;
|
|
10
10
|
export type SvgElementNames = keyof SVGElementTagNameMap;
|
|
11
11
|
export type SvgElementAttributes = Record<string, string>;
|
|
12
|
-
export type SvgElementOtherAttributes = SvgElementAttributes;
|
|
13
12
|
export type SvgElementWithIdAttributes = SvgElementAttributes & {
|
|
14
13
|
'data-chessboard-id': string;
|
|
15
14
|
};
|
|
16
|
-
export
|
|
17
|
-
|
|
18
|
-
|
|
15
|
+
export type SvgElementOtherAttributes = SvgElementAttributes & {
|
|
16
|
+
'data-chessboard-id'?: never;
|
|
17
|
+
};
|
|
18
|
+
export declare function createSvgRootElement(parent: HTMLElement, attrs: SvgElementWithIdAttributes): SVGSVGElement;
|
|
19
|
+
export declare function createSvgDefsElement(parent: SVGSVGElement, attrs: SvgElementWithIdAttributes): SVGDefsElement;
|
|
20
|
+
export declare function createSvgElement<K extends Exclude<SvgElementNames, 'svg' | 'defs'>>(parent: SVGElement, name: K, attrs: SvgElementWithIdAttributes): SVGElementTagNameMap[K];
|
|
21
|
+
export declare function updateSvgElementAttributes(element: SVGElement, attrs: SvgElementOtherAttributes): void;
|
|
22
|
+
export declare function clearSvgElementChildren(element: SVGElement): void;
|
|
@@ -11,23 +11,38 @@ export function isLightSquare(sq) {
|
|
|
11
11
|
const r = rankOf(sq);
|
|
12
12
|
return ((f + r) & 1) === 1;
|
|
13
13
|
}
|
|
14
|
-
|
|
15
|
-
const doc = parentOrDoc instanceof Document ? parentOrDoc : parentOrDoc.ownerDocument;
|
|
16
|
-
const el = doc.createElementNS(SVG_NS, name);
|
|
14
|
+
function _updateElementAttributes(element, attrs) {
|
|
17
15
|
for (const [key, value] of Object.entries(attrs)) {
|
|
18
|
-
|
|
19
|
-
}
|
|
20
|
-
if (parentOrDoc instanceof Element) {
|
|
21
|
-
parentOrDoc.appendChild(el);
|
|
16
|
+
element.setAttribute(key, value);
|
|
22
17
|
}
|
|
18
|
+
}
|
|
19
|
+
export function createSvgRootElement(parent, attrs) {
|
|
20
|
+
const doc = parent.ownerDocument;
|
|
21
|
+
const el = doc.createElementNS(SVG_NS, 'svg');
|
|
22
|
+
_updateElementAttributes(el, attrs);
|
|
23
|
+
parent.appendChild(el);
|
|
23
24
|
return el;
|
|
24
25
|
}
|
|
25
|
-
export function
|
|
26
|
-
|
|
27
|
-
|
|
28
|
-
|
|
26
|
+
export function createSvgDefsElement(parent, attrs) {
|
|
27
|
+
const doc = parent.ownerDocument;
|
|
28
|
+
const el = doc.createElementNS(SVG_NS, 'defs');
|
|
29
|
+
_updateElementAttributes(el, attrs);
|
|
30
|
+
// Keep extension-owned defs roots before visual roots.
|
|
31
|
+
const firstNonDefsChild = Array.from(parent.children).find((child) => child.tagName.toLowerCase() !== 'defs');
|
|
32
|
+
parent.insertBefore(el, firstNonDefsChild ?? null);
|
|
33
|
+
return el;
|
|
34
|
+
}
|
|
35
|
+
export function createSvgElement(parent, name, attrs) {
|
|
36
|
+
const doc = parent.ownerDocument;
|
|
37
|
+
const el = doc.createElementNS(SVG_NS, name);
|
|
38
|
+
_updateElementAttributes(el, attrs);
|
|
39
|
+
parent.appendChild(el);
|
|
40
|
+
return el;
|
|
41
|
+
}
|
|
42
|
+
export function updateSvgElementAttributes(element, attrs) {
|
|
43
|
+
_updateElementAttributes(element, attrs);
|
|
29
44
|
}
|
|
30
|
-
export function
|
|
45
|
+
export function clearSvgElementChildren(element) {
|
|
31
46
|
while (element.firstChild) {
|
|
32
47
|
element.removeChild(element.firstChild);
|
|
33
48
|
}
|
|
@@ -0,0 +1,11 @@
|
|
|
1
|
+
let nextId = 0;
|
|
2
|
+
export function createSvgIdResolver() {
|
|
3
|
+
const prefix = `cb${nextId++}`;
|
|
4
|
+
function makeId(scope, localId) {
|
|
5
|
+
return `${prefix}-${scope}-${localId}`;
|
|
6
|
+
}
|
|
7
|
+
function makeHref(scope, localId) {
|
|
8
|
+
return `#${makeId(scope, localId)}`;
|
|
9
|
+
}
|
|
10
|
+
return { prefix, makeId, makeHref };
|
|
11
|
+
}
|
package/dist/render/types.d.ts
CHANGED
|
@@ -3,9 +3,10 @@ import { RenderFrameSnapshot } from '../extensions/types/basic/render.js';
|
|
|
3
3
|
import { TransientInput } from '../extensions/types/basic/transient-visuals.js';
|
|
4
4
|
import { ExtensionSystemExtensionRecord, ExtensionSystemSharedDataForRenderSystem } from '../extensions/types/main.js';
|
|
5
5
|
import { Scheduler } from './scheduler/types.js';
|
|
6
|
-
export
|
|
6
|
+
export type RootExtensionSlotName = Exclude<(typeof ALL_EXTENSION_SLOTS)[number], 'defs'>;
|
|
7
|
+
export declare const ROOT_EXTENSION_SLOTS: readonly RootExtensionSlotName[];
|
|
8
|
+
export interface SvgRoots extends ExtensionSlotSvgRoots<typeof ROOT_EXTENSION_SLOTS> {
|
|
7
9
|
readonly svgRoot: SVGSVGElement;
|
|
8
|
-
readonly defs: SVGDefsElement;
|
|
9
10
|
}
|
|
10
11
|
export interface RenderExtensionRecordRender {
|
|
11
12
|
readonly slots: ExtensionAllocatedSlotsInternal;
|
|
@@ -24,7 +25,7 @@ export interface RenderSystemInternal {
|
|
|
24
25
|
readonly transientVisualsSubscribers: ReadonlySet<string>;
|
|
25
26
|
}
|
|
26
27
|
export interface RenderSystemInitOptions {
|
|
27
|
-
|
|
28
|
+
element: HTMLElement;
|
|
28
29
|
sharedDataFromExtensionSystem: ExtensionSystemSharedDataForRenderSystem;
|
|
29
30
|
}
|
|
30
31
|
export interface RenderSystemInitOptionsInternal extends RenderSystemInitOptions {
|
package/dist/render/types.js
CHANGED
|
@@ -1 +1,2 @@
|
|
|
1
|
-
|
|
1
|
+
import { ALL_EXTENSION_SLOTS } from '../extensions/types/basic/mount.js';
|
|
2
|
+
export const ROOT_EXTENSION_SLOTS = ALL_EXTENSION_SLOTS.filter((slot) => slot !== 'defs');
|
|
@@ -1,3 +1,5 @@
|
|
|
1
|
+
import { DragSessionSnapshot } from '../../state/interaction/types/internal.js';
|
|
1
2
|
import { RuntimeInteractionSurface } from '../input/controller/types.js';
|
|
2
|
-
import { GetInternalState } from '../types/main.js';
|
|
3
|
+
import { GetInternalState, RuntimeInternal } from '../types/main.js';
|
|
4
|
+
export declare function notifyExtensionCancelDragIfOwned(internalState: RuntimeInternal, dragSession: DragSessionSnapshot | null): void;
|
|
3
5
|
export declare function createRuntimeInteractionSurface(state: GetInternalState): RuntimeInteractionSurface;
|
|
@@ -3,6 +3,11 @@ import { isEmptyPieceCode } from '../../state/board/check.js';
|
|
|
3
3
|
import { isDragSessionCoreOwned } from '../../state/interaction/helpers.js';
|
|
4
4
|
import { runtimeRunMutationPipeline } from '../mutation/run.js';
|
|
5
5
|
import { uiMoveCompleteTo } from './helpers.js';
|
|
6
|
+
export function notifyExtensionCancelDragIfOwned(internalState, dragSession) {
|
|
7
|
+
if (dragSession && !isDragSessionCoreOwned(dragSession)) {
|
|
8
|
+
internalState.extensionSystem.cancelDrag(dragSession);
|
|
9
|
+
}
|
|
10
|
+
}
|
|
6
11
|
export function createRuntimeInteractionSurface(state) {
|
|
7
12
|
return {
|
|
8
13
|
getInteractionStateSnapshot() {
|
|
@@ -80,13 +85,17 @@ export function createRuntimeInteractionSurface(state) {
|
|
|
80
85
|
cancelActiveInteraction() {
|
|
81
86
|
const internalState = state();
|
|
82
87
|
const mutationSession = internalState.mutation.getSession();
|
|
83
|
-
internalState.state.interaction
|
|
88
|
+
const interaction = internalState.state.interaction;
|
|
89
|
+
notifyExtensionCancelDragIfOwned(internalState, interaction.dragSession);
|
|
90
|
+
interaction.clearActive(mutationSession);
|
|
84
91
|
runtimeRunMutationPipeline(internalState);
|
|
85
92
|
},
|
|
86
93
|
cancelInteraction() {
|
|
87
94
|
const internalState = state();
|
|
88
95
|
const mutationSession = internalState.mutation.getSession();
|
|
89
|
-
internalState.state.interaction
|
|
96
|
+
const interaction = internalState.state.interaction;
|
|
97
|
+
notifyExtensionCancelDragIfOwned(internalState, interaction.dragSession);
|
|
98
|
+
interaction.clear(mutationSession);
|
|
90
99
|
runtimeRunMutationPipeline(internalState);
|
|
91
100
|
},
|
|
92
101
|
updateDragSessionCurrentTarget(target) {
|
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
import assert from '@ktarmyshov/assert';
|
|
2
2
|
import { createExtensionSystem } from '../../extensions/factory/main.js';
|
|
3
|
-
import {
|
|
3
|
+
import { isFrameRenderable } from '../../extensions/types/basic/update.js';
|
|
4
4
|
import { createLayout } from '../../layout/factory.js';
|
|
5
5
|
import { createRenderSystem } from '../../render/factory.js';
|
|
6
6
|
import { isNonEmptyPieceCode } from '../../state/board/check.js';
|
|
@@ -11,11 +11,11 @@ import { runtimeDestroy, runtimeMount, runtimeUnmount } from '../lifecycle.js';
|
|
|
11
11
|
import { createRuntimeMutationPipeline } from '../mutation/factory.js';
|
|
12
12
|
import { runtimeRunMutationPipeline } from '../mutation/run.js';
|
|
13
13
|
import { createExtensionRuntimeSurfaceEvents } from './events.js';
|
|
14
|
-
import { createRuntimeInteractionSurface } from './input.js';
|
|
14
|
+
import { createRuntimeInteractionSurface, notifyExtensionCancelDragIfOwned } from './input.js';
|
|
15
15
|
function createRuntimeInternal(options) {
|
|
16
16
|
const extensionSystem = createExtensionSystem(options);
|
|
17
17
|
const render = createRenderSystem({
|
|
18
|
-
|
|
18
|
+
element: options.element,
|
|
19
19
|
sharedDataFromExtensionSystem: extensionSystem.getSharedDataForRenderSystem()
|
|
20
20
|
});
|
|
21
21
|
return {
|
|
@@ -69,9 +69,13 @@ function createExtensionRuntimeSurfaceCommandsInternalSurface(getInternalState)
|
|
|
69
69
|
state: state.state.getSnapshot(),
|
|
70
70
|
layout: state.layout.getSnapshot()
|
|
71
71
|
};
|
|
72
|
-
|
|
72
|
+
if (!isFrameRenderable(renderRequest)) {
|
|
73
|
+
return false;
|
|
74
|
+
}
|
|
73
75
|
state.renderSystem.requestRender(renderRequest);
|
|
76
|
+
return true;
|
|
74
77
|
}
|
|
78
|
+
return false;
|
|
75
79
|
},
|
|
76
80
|
setOrientation(orientation) {
|
|
77
81
|
const state = getInternalState();
|
|
@@ -114,6 +118,7 @@ function createExtensionRuntimeSurfaceCommandsInternalSurface(getInternalState)
|
|
|
114
118
|
clearActiveInteraction() {
|
|
115
119
|
const state = getInternalState();
|
|
116
120
|
const mutationSession = state.mutation.getSession();
|
|
121
|
+
notifyExtensionCancelDragIfOwned(state, state.state.interaction.dragSession);
|
|
117
122
|
const changed = state.state.interaction.clearActive(mutationSession);
|
|
118
123
|
runtimeRunMutationPipeline(state);
|
|
119
124
|
return changed;
|
|
@@ -121,6 +126,7 @@ function createExtensionRuntimeSurfaceCommandsInternalSurface(getInternalState)
|
|
|
121
126
|
clearInteraction() {
|
|
122
127
|
const state = getInternalState();
|
|
123
128
|
const mutationSession = state.mutation.getSession();
|
|
129
|
+
notifyExtensionCancelDragIfOwned(state, state.state.interaction.dragSession);
|
|
124
130
|
const changed = state.state.interaction.clear(mutationSession);
|
|
125
131
|
runtimeRunMutationPipeline(state);
|
|
126
132
|
return changed;
|
|
@@ -1,11 +1,11 @@
|
|
|
1
1
|
import { ALL_SCENE_POINTER_EVENT_TYPES } from '../../../extensions/types/basic/events.js';
|
|
2
2
|
import { pointerEventDestroy, pointerEventHandler } from './pointer.js';
|
|
3
3
|
export function eventHandler(state, e) {
|
|
4
|
-
let context
|
|
4
|
+
let context;
|
|
5
5
|
if (ALL_SCENE_POINTER_EVENT_TYPES.has(e.type)) {
|
|
6
6
|
context = pointerEventHandler(state, e);
|
|
7
7
|
}
|
|
8
|
-
|
|
8
|
+
else {
|
|
9
9
|
context = {
|
|
10
10
|
rawEvent: e,
|
|
11
11
|
sceneEvent: null
|
|
@@ -1,6 +1,6 @@
|
|
|
1
|
-
import {
|
|
1
|
+
import { InteractionControllerOnEventContext } from '../controller/types.js';
|
|
2
2
|
import { InputAdapterInternal } from './types.js';
|
|
3
|
-
export declare function pointerEventHandler(state: InputAdapterInternal, e: PointerEvent):
|
|
3
|
+
export declare function pointerEventHandler(state: InputAdapterInternal, e: PointerEvent): InteractionControllerOnEventContext;
|
|
4
4
|
/** Release capture for the currently tracked pointer and clear tracking state. */
|
|
5
5
|
export declare function releaseCapture(state: InputAdapterInternal): void;
|
|
6
6
|
export declare function adapterOnPointerDown(state: InputAdapterInternal, e: PointerEvent): void;
|
|
@@ -1,2 +1,2 @@
|
|
|
1
|
-
import { InteractionController, InteractionControllerInitOptions } from './types.js';
|
|
1
|
+
import type { InteractionController, InteractionControllerInitOptions } from './types.js';
|
|
2
2
|
export declare function createInteractionController(options: InteractionControllerInitOptions): InteractionController;
|
|
@@ -1,4 +1,4 @@
|
|
|
1
|
-
import {
|
|
1
|
+
import { determineRuntimeInteractionAction } from './interaction.js';
|
|
2
2
|
import { transmitTransientInput } from './transient-visuals.js';
|
|
3
3
|
function createInteractionControllerInternal(options) {
|
|
4
4
|
return {
|
|
@@ -9,24 +9,44 @@ export function createInteractionController(options) {
|
|
|
9
9
|
const internalState = createInteractionControllerInternal(options);
|
|
10
10
|
return {
|
|
11
11
|
onEvent(context) {
|
|
12
|
-
internalState
|
|
12
|
+
const action = determineRuntimeInteractionAction(internalState, context);
|
|
13
|
+
const extensionContext = {
|
|
14
|
+
...context,
|
|
15
|
+
runtimeInteractionActionPreview: action
|
|
16
|
+
};
|
|
17
|
+
internalState.surface.onEvent(extensionContext);
|
|
13
18
|
if (context.rawEvent.defaultPrevented) {
|
|
14
19
|
transmitTransientInput(internalState, context);
|
|
15
20
|
return; // The event has been handled by the surface (extensions)
|
|
16
21
|
}
|
|
17
|
-
|
|
18
|
-
|
|
19
|
-
|
|
20
|
-
|
|
21
|
-
|
|
22
|
-
|
|
23
|
-
|
|
24
|
-
|
|
25
|
-
|
|
26
|
-
|
|
27
|
-
|
|
28
|
-
|
|
29
|
-
|
|
22
|
+
if (action) {
|
|
23
|
+
switch (action.type) {
|
|
24
|
+
case 'startLiftedDrag':
|
|
25
|
+
internalState.surface.startLiftedDrag(action.source, action.target);
|
|
26
|
+
break;
|
|
27
|
+
case 'startReleaseTargetingDrag':
|
|
28
|
+
internalState.surface.startReleaseTargetingDrag(action.source, action.target);
|
|
29
|
+
break;
|
|
30
|
+
case 'completeCoreDragTo':
|
|
31
|
+
internalState.surface.completeCoreDragTo(action.target);
|
|
32
|
+
break;
|
|
33
|
+
case 'completeExtensionDrag':
|
|
34
|
+
internalState.surface.completeExtensionDrag(action.target);
|
|
35
|
+
break;
|
|
36
|
+
case 'updateDragSessionCurrentTarget':
|
|
37
|
+
internalState.surface.updateDragSessionCurrentTarget(action.target);
|
|
38
|
+
break;
|
|
39
|
+
case 'cancelActiveInteraction':
|
|
40
|
+
internalState.surface.cancelActiveInteraction();
|
|
41
|
+
break;
|
|
42
|
+
case 'cancelInteraction':
|
|
43
|
+
internalState.surface.cancelInteraction();
|
|
44
|
+
break;
|
|
45
|
+
default:
|
|
46
|
+
throw new Error(
|
|
47
|
+
// eslint-disable-next-line @typescript-eslint/no-explicit-any
|
|
48
|
+
`Unhandled RuntimeInteractionAction type: ${String(action.type)}`);
|
|
49
|
+
}
|
|
30
50
|
}
|
|
31
51
|
transmitTransientInput(internalState, context);
|
|
32
52
|
}
|
|
@@ -1,3 +1,3 @@
|
|
|
1
1
|
import type { Square } from '../../../state/board/types/internal.js';
|
|
2
|
-
import { InteractionStateSnapshot } from '../../../state/interaction/types/main.js';
|
|
2
|
+
import type { InteractionStateSnapshot } from '../../../state/interaction/types/main.js';
|
|
3
3
|
export declare function canMoveTo(snapshot: InteractionStateSnapshot, target: Square): boolean;
|
|
@@ -0,0 +1,3 @@
|
|
|
1
|
+
import type { RuntimeInteractionAction } from '../../../extensions/types/basic/events.js';
|
|
2
|
+
import type { InteractionControllerInternal, InteractionControllerOnEventContext } from './types.js';
|
|
3
|
+
export declare function determineRuntimeInteractionAction(state: InteractionControllerInternal, context: InteractionControllerOnEventContext): RuntimeInteractionAction | null;
|
|
@@ -0,0 +1,14 @@
|
|
|
1
|
+
import { determineActionPointerCancel, determineActionPointerDown, determineActionPointerMove, determineActionPointerUp } from './pointer.js';
|
|
2
|
+
export function determineRuntimeInteractionAction(state, context) {
|
|
3
|
+
switch (context.rawEvent.type) {
|
|
4
|
+
case 'pointerdown':
|
|
5
|
+
return determineActionPointerDown(state, context);
|
|
6
|
+
case 'pointermove':
|
|
7
|
+
return determineActionPointerMove(state, context);
|
|
8
|
+
case 'pointerup':
|
|
9
|
+
return determineActionPointerUp(state, context);
|
|
10
|
+
case 'pointercancel':
|
|
11
|
+
return determineActionPointerCancel(state, context);
|
|
12
|
+
}
|
|
13
|
+
return null;
|
|
14
|
+
}
|
|
@@ -1,6 +1,6 @@
|
|
|
1
|
-
import {
|
|
2
|
-
import { InteractionControllerInternal } from './types.js';
|
|
3
|
-
export declare function
|
|
4
|
-
export declare function
|
|
5
|
-
export declare function
|
|
6
|
-
export declare function
|
|
1
|
+
import type { RuntimeInteractionAction } from '../../../extensions/types/basic/events.js';
|
|
2
|
+
import type { InteractionControllerInternal, InteractionControllerOnEventContext } from './types.js';
|
|
3
|
+
export declare function determineActionPointerDown(state: InteractionControllerInternal, context: InteractionControllerOnEventContext): RuntimeInteractionAction | null;
|
|
4
|
+
export declare function determineActionPointerMove(state: InteractionControllerInternal, context: InteractionControllerOnEventContext): RuntimeInteractionAction | null;
|
|
5
|
+
export declare function determineActionPointerUp(state: InteractionControllerInternal, context: InteractionControllerOnEventContext): RuntimeInteractionAction | null;
|
|
6
|
+
export declare function determineActionPointerCancel(state: InteractionControllerInternal, context: InteractionControllerOnEventContext): RuntimeInteractionAction | null;
|
|
@@ -3,19 +3,19 @@ import { isEmptyPieceCode, isNonEmptyPieceCode } from '../../../state/board/chec
|
|
|
3
3
|
import { fromPieceCode } from '../../../state/board/piece.js';
|
|
4
4
|
import { isDragSessionCoreOwned } from '../../../state/interaction/helpers.js';
|
|
5
5
|
import { canMoveTo } from './helpers.js';
|
|
6
|
-
export function
|
|
7
|
-
assert(context.rawEvent.type === 'pointerdown', '
|
|
6
|
+
export function determineActionPointerDown(state, context) {
|
|
7
|
+
assert(context.rawEvent.type === 'pointerdown', 'determineActionPointerDown should only be called for pointerdown events');
|
|
8
8
|
const rawEvent = context.rawEvent;
|
|
9
9
|
if (rawEvent.button !== 0) {
|
|
10
10
|
// Only handle left-click for now
|
|
11
|
-
return;
|
|
11
|
+
return null;
|
|
12
12
|
}
|
|
13
13
|
const sceneEvent = context.sceneEvent;
|
|
14
14
|
assert(sceneEvent, 'Scene event should be present for pointer events');
|
|
15
15
|
const interaction = state.surface.getInteractionStateSnapshot();
|
|
16
16
|
if (interaction.dragSession) {
|
|
17
17
|
// Ignore pointer down events if there's already an active drag session
|
|
18
|
-
return;
|
|
18
|
+
return null;
|
|
19
19
|
}
|
|
20
20
|
if (sceneEvent.targetSquare !== null) {
|
|
21
21
|
/**
|
|
@@ -28,16 +28,22 @@ export function handlePointerDown(state, context) {
|
|
|
28
28
|
assert(isNonEmptyPieceCode(selectedPieceCode), 'Selected piece code must be non-zero');
|
|
29
29
|
const targetPieceCode = state.surface.getPieceCodeAt(sceneEvent.targetSquare);
|
|
30
30
|
if (isEmptyPieceCode(targetPieceCode)) {
|
|
31
|
-
|
|
32
|
-
|
|
31
|
+
return {
|
|
32
|
+
type: 'startReleaseTargetingDrag',
|
|
33
|
+
source: interaction.selected.square,
|
|
34
|
+
target: sceneEvent.targetSquare
|
|
35
|
+
};
|
|
33
36
|
}
|
|
34
37
|
const isLegalMoveTarget = interaction.movability.mode === 1 /* MovabilityModeCode.Free */ ||
|
|
35
38
|
(interaction.movability.mode === 2 /* MovabilityModeCode.Strict */ &&
|
|
36
39
|
interaction.activeDestinations.has(sceneEvent.targetSquare));
|
|
37
40
|
if (fromPieceCode(targetPieceCode).color !== fromPieceCode(selectedPieceCode).color &&
|
|
38
41
|
isLegalMoveTarget) {
|
|
39
|
-
|
|
40
|
-
|
|
42
|
+
return {
|
|
43
|
+
type: 'startReleaseTargetingDrag',
|
|
44
|
+
source: interaction.selected.square,
|
|
45
|
+
target: sceneEvent.targetSquare
|
|
46
|
+
};
|
|
41
47
|
}
|
|
42
48
|
}
|
|
43
49
|
/**
|
|
@@ -46,60 +52,80 @@ export function handlePointerDown(state, context) {
|
|
|
46
52
|
*/
|
|
47
53
|
const pieceCode = state.surface.getPieceCodeAt(sceneEvent.targetSquare);
|
|
48
54
|
if (!isEmptyPieceCode(pieceCode)) {
|
|
49
|
-
|
|
55
|
+
return {
|
|
56
|
+
type: 'startLiftedDrag',
|
|
57
|
+
source: sceneEvent.targetSquare,
|
|
58
|
+
target: sceneEvent.targetSquare
|
|
59
|
+
};
|
|
50
60
|
}
|
|
51
61
|
}
|
|
62
|
+
return null;
|
|
52
63
|
}
|
|
53
|
-
export function
|
|
54
|
-
assert(context.rawEvent.type === 'pointermove', '
|
|
64
|
+
export function determineActionPointerMove(state, context) {
|
|
65
|
+
assert(context.rawEvent.type === 'pointermove', 'determineActionPointerMove should only be called for pointermove events');
|
|
55
66
|
const interaction = state.surface.getInteractionStateSnapshot();
|
|
56
67
|
if (interaction.dragSession) {
|
|
57
|
-
|
|
68
|
+
return {
|
|
69
|
+
type: 'updateDragSessionCurrentTarget',
|
|
70
|
+
target: context.sceneEvent?.targetSquare ?? null
|
|
71
|
+
};
|
|
58
72
|
}
|
|
73
|
+
return null;
|
|
59
74
|
}
|
|
60
|
-
export function
|
|
61
|
-
assert(context.rawEvent.type === 'pointerup', '
|
|
75
|
+
export function determineActionPointerUp(state, context) {
|
|
76
|
+
assert(context.rawEvent.type === 'pointerup', 'determineActionPointerUp should only be called for pointerup events');
|
|
62
77
|
const interaction = state.surface.getInteractionStateSnapshot();
|
|
63
78
|
const dragSession = interaction.dragSession;
|
|
64
79
|
if (!dragSession) {
|
|
65
80
|
// No active drag session, so nothing to do on pointer up
|
|
66
|
-
return;
|
|
81
|
+
return null;
|
|
67
82
|
}
|
|
68
83
|
const sceneEvent = context.sceneEvent;
|
|
69
84
|
assert(sceneEvent, 'Scene event should be present for pointer events');
|
|
70
85
|
if (!isDragSessionCoreOwned(dragSession)) {
|
|
71
86
|
// For extension-owned drag sessions, we simply end the session without attempting to make a move,
|
|
72
87
|
// since the runtime doesn't have enough information about the semantics of the drag session.
|
|
73
|
-
|
|
74
|
-
|
|
88
|
+
return {
|
|
89
|
+
type: 'completeExtensionDrag',
|
|
90
|
+
target: sceneEvent.targetSquare
|
|
91
|
+
};
|
|
75
92
|
}
|
|
76
93
|
// Check if the square is the same as the source square of the drag session.
|
|
77
94
|
// If it is, then we can end the drag session without making a move.
|
|
78
95
|
if (sceneEvent.targetSquare === dragSession.sourceSquare) {
|
|
79
|
-
|
|
80
|
-
|
|
96
|
+
return {
|
|
97
|
+
type: 'cancelActiveInteraction'
|
|
98
|
+
};
|
|
81
99
|
}
|
|
82
100
|
// Check if the target square is a valid destination for the selected piece.
|
|
83
101
|
if (sceneEvent.targetSquare !== null && canMoveTo(interaction, sceneEvent.targetSquare)) {
|
|
84
|
-
|
|
85
|
-
|
|
102
|
+
return {
|
|
103
|
+
type: 'completeCoreDragTo',
|
|
104
|
+
target: sceneEvent.targetSquare
|
|
105
|
+
};
|
|
86
106
|
}
|
|
87
107
|
// Invalid target: piece returns to source for lifted drag (selection preserved),
|
|
88
108
|
// or selection is cleared for release targeting.
|
|
89
109
|
if (dragSession.type === 'lifted-piece-drag') {
|
|
90
|
-
|
|
110
|
+
return {
|
|
111
|
+
type: 'cancelActiveInteraction'
|
|
112
|
+
};
|
|
91
113
|
}
|
|
92
114
|
else {
|
|
93
|
-
|
|
115
|
+
return {
|
|
116
|
+
type: 'cancelInteraction'
|
|
117
|
+
};
|
|
94
118
|
}
|
|
95
119
|
}
|
|
96
|
-
export function
|
|
97
|
-
assert(context.rawEvent.type === 'pointercancel', '
|
|
120
|
+
export function determineActionPointerCancel(state, context) {
|
|
121
|
+
assert(context.rawEvent.type === 'pointercancel', 'determineActionPointerCancel should only be called for pointercancel events');
|
|
98
122
|
const interaction = state.surface.getInteractionStateSnapshot();
|
|
99
123
|
if (!interaction.dragSession) {
|
|
100
124
|
// No active drag session, so nothing to do on pointer cancel
|
|
101
|
-
return;
|
|
125
|
+
return null;
|
|
102
126
|
}
|
|
103
127
|
// Cancel the active interaction on pointer cancel
|
|
104
|
-
|
|
128
|
+
return {
|
|
129
|
+
type: 'cancelActiveInteraction'
|
|
130
|
+
};
|
|
105
131
|
}
|
|
@@ -1,3 +1,2 @@
|
|
|
1
|
-
import {
|
|
2
|
-
|
|
3
|
-
export declare function transmitTransientInput(state: InteractionControllerInternal, context: ExtensionOnEventContext): void;
|
|
1
|
+
import type { InteractionControllerInternal, InteractionControllerOnEventContext } from './types.js';
|
|
2
|
+
export declare function transmitTransientInput(state: InteractionControllerInternal, context: InteractionControllerOnEventContext): void;
|
|
@@ -1,7 +1,7 @@
|
|
|
1
|
-
import { TransientInput } from '../../../extensions/types/basic/transient-visuals.js';
|
|
2
|
-
import { ExtensionOnEventContext } from '../../../extensions/types/context/events.js';
|
|
3
|
-
import { PieceCode, Square } from '../../../state/board/types/internal.js';
|
|
4
|
-
import { InteractionStateSnapshot } from '../../../state/interaction/types/main.js';
|
|
1
|
+
import type { TransientInput } from '../../../extensions/types/basic/transient-visuals.js';
|
|
2
|
+
import type { ExtensionOnEventContext } from '../../../extensions/types/context/events.js';
|
|
3
|
+
import type { PieceCode, Square } from '../../../state/board/types/internal.js';
|
|
4
|
+
import type { InteractionStateSnapshot } from '../../../state/interaction/types/main.js';
|
|
5
5
|
export interface RuntimeInteractionSurface {
|
|
6
6
|
getInteractionStateSnapshot(): InteractionStateSnapshot;
|
|
7
7
|
getPieceCodeAt(square: Square): PieceCode;
|
|
@@ -21,6 +21,7 @@ export interface InteractionControllerInternal {
|
|
|
21
21
|
export interface InteractionControllerInitOptions {
|
|
22
22
|
surface: RuntimeInteractionSurface;
|
|
23
23
|
}
|
|
24
|
+
export type InteractionControllerOnEventContext = Omit<ExtensionOnEventContext, 'runtimeInteractionActionPreview'>;
|
|
24
25
|
export interface InteractionController {
|
|
25
|
-
onEvent(context:
|
|
26
|
+
onEvent(context: InteractionControllerOnEventContext): void;
|
|
26
27
|
}
|
|
@@ -14,7 +14,7 @@ export interface RuntimeInternal extends RuntimeMutationPipelineContext {
|
|
|
14
14
|
}
|
|
15
15
|
export type GetInternalState = () => RuntimeInternal;
|
|
16
16
|
export interface RuntimeInitOptions {
|
|
17
|
-
|
|
17
|
+
element: HTMLElement;
|
|
18
18
|
state?: RuntimeStateInitOptions;
|
|
19
19
|
extensions?: readonly AnyExtensionDefinition[];
|
|
20
20
|
}
|