@geometra/core 1.49.0 → 1.53.0
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/README.md +14 -4
- package/dist/a11y.d.ts.map +1 -1
- package/dist/a11y.js +3 -2
- package/dist/a11y.js.map +1 -1
- package/dist/animation-choreography.d.ts +88 -0
- package/dist/animation-choreography.d.ts.map +1 -0
- package/dist/animation-choreography.js +283 -0
- package/dist/animation-choreography.js.map +1 -0
- package/dist/animation.d.ts.map +1 -1
- package/dist/animation.js +3 -2
- package/dist/animation.js.map +1 -1
- package/dist/app.js +2 -2
- package/dist/app.js.map +1 -1
- package/dist/focus.d.ts +2 -0
- package/dist/focus.d.ts.map +1 -1
- package/dist/focus.js +5 -2
- package/dist/focus.js.map +1 -1
- package/dist/gestures.d.ts +110 -0
- package/dist/gestures.d.ts.map +1 -0
- package/dist/gestures.js +248 -0
- package/dist/gestures.js.map +1 -0
- package/dist/hit-test.d.ts +6 -5
- package/dist/hit-test.d.ts.map +1 -1
- package/dist/hit-test.js +39 -44
- package/dist/hit-test.js.map +1 -1
- package/dist/index.d.ts +15 -5
- package/dist/index.d.ts.map +1 -1
- package/dist/index.js +12 -4
- package/dist/index.js.map +1 -1
- package/dist/layout-bounds.d.ts +13 -5
- package/dist/layout-bounds.d.ts.map +1 -1
- package/dist/layout-bounds.js +17 -7
- package/dist/layout-bounds.js.map +1 -1
- package/dist/performance-now.d.ts +14 -3
- package/dist/performance-now.d.ts.map +1 -1
- package/dist/performance-now.js +18 -4
- package/dist/performance-now.js.map +1 -1
- package/dist/selection.d.ts +2 -0
- package/dist/selection.d.ts.map +1 -1
- package/dist/selection.js +5 -2
- package/dist/selection.js.map +1 -1
- package/dist/text-input.d.ts +10 -1
- package/dist/text-input.d.ts.map +1 -1
- package/dist/text-input.js +12 -1
- package/dist/text-input.js.map +1 -1
- package/dist/types.d.ts +46 -6
- package/dist/types.d.ts.map +1 -1
- package/dist/virtual-scroll.d.ts +26 -5
- package/dist/virtual-scroll.d.ts.map +1 -1
- package/dist/virtual-scroll.js +40 -9
- package/dist/virtual-scroll.js.map +1 -1
- package/package.json +2 -2
package/dist/focus.js
CHANGED
|
@@ -19,6 +19,8 @@ export function clearFocus() {
|
|
|
19
19
|
* Non-box leaves (`text`, `image`, `scene3d`) are ignored — only `box` nodes participate in this walk.
|
|
20
20
|
* Boxes with a missing or non-array `children` field are treated as leaf boxes (no throw) so bad
|
|
21
21
|
* deserialization cannot take down focus walks.
|
|
22
|
+
* At each index, both the element child and `layout.children[i]` must be present — a hole in the
|
|
23
|
+
* element `children` array with a layout slot still present is skipped (same rule as hit-testing).
|
|
22
24
|
* Skips boxes whose layout bounds are non-finite or have negative width/height, and does not walk
|
|
23
25
|
* their subtrees — same rule as hit-testing so corrupt geometry cannot enter focus order.
|
|
24
26
|
*
|
|
@@ -42,9 +44,10 @@ function collectFocusable(element, layout, results) {
|
|
|
42
44
|
const kids = element.children;
|
|
43
45
|
const n = Array.isArray(kids) ? kids.length : 0;
|
|
44
46
|
for (let i = 0; i < n; i++) {
|
|
47
|
+
const child = kids[i];
|
|
45
48
|
const childLayout = layout.children[i];
|
|
46
|
-
if (childLayout) {
|
|
47
|
-
collectFocusable(
|
|
49
|
+
if (child && childLayout) {
|
|
50
|
+
collectFocusable(child, childLayout, results);
|
|
48
51
|
}
|
|
49
52
|
}
|
|
50
53
|
}
|
package/dist/focus.js.map
CHANGED
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"focus.js","sourceRoot":"","sources":["../src/focus.ts"],"names":[],"mappings":"AAEA,OAAO,EAAE,yBAAyB,EAAE,MAAM,uBAAuB,CAAA;AACjE,OAAO,EAAE,qBAAqB,EAAE,MAAM,oBAAoB,CAAA;AAC1D,OAAO,EAAE,MAAM,EAAE,MAAM,cAAc,CAAA;AASrC,qDAAqD;AACrD,MAAM,CAAC,MAAM,cAAc,GAA+B,MAAM,CAAqB,IAAI,CAAC,CAAA;AAE1F,+BAA+B;AAC/B,MAAM,UAAU,QAAQ,CAAC,OAAmB,EAAE,MAAsB;IAClE,cAAc,CAAC,GAAG,CAAC,EAAE,OAAO,EAAE,MAAM,EAAE,CAAC,CAAA;AACzC,CAAC;AAED,+BAA+B;AAC/B,MAAM,UAAU,UAAU;IACxB,cAAc,CAAC,GAAG,CAAC,IAAI,CAAC,CAAA;AAC1B,CAAC;AAED
|
|
1
|
+
{"version":3,"file":"focus.js","sourceRoot":"","sources":["../src/focus.ts"],"names":[],"mappings":"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"}
|
|
@@ -0,0 +1,110 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Renderer-agnostic pointer gesture recognizers: pan/drag, swipe, and pinch.
|
|
3
|
+
*
|
|
4
|
+
* Each recognizer is a pure state machine. Host code (canvas hit-test,
|
|
5
|
+
* terminal pointer, native bridge, tests) feeds it pointer events via
|
|
6
|
+
* `pointerDown`/`pointerMove`/`pointerUp`/`pointerCancel`; the recognizer
|
|
7
|
+
* invokes callbacks when thresholds are crossed. No DOM, no raf.
|
|
8
|
+
*
|
|
9
|
+
* Pointer IDs are integers (matching Pointer Events API conventions), but any
|
|
10
|
+
* stable per-pointer identity works — synthesized ids from terminal tap
|
|
11
|
+
* protocols are fine as long as down/move/up match.
|
|
12
|
+
*/
|
|
13
|
+
export interface PointerSample {
|
|
14
|
+
id: number;
|
|
15
|
+
x: number;
|
|
16
|
+
y: number;
|
|
17
|
+
/** High-resolution timestamp in ms. Finite values only; callers are responsible. */
|
|
18
|
+
timestampMs: number;
|
|
19
|
+
}
|
|
20
|
+
export interface PanEvent {
|
|
21
|
+
pointerId: number;
|
|
22
|
+
x: number;
|
|
23
|
+
y: number;
|
|
24
|
+
startX: number;
|
|
25
|
+
startY: number;
|
|
26
|
+
deltaX: number;
|
|
27
|
+
deltaY: number;
|
|
28
|
+
/** Time since the gesture started moving past `minDistance`. */
|
|
29
|
+
elapsedMs: number;
|
|
30
|
+
}
|
|
31
|
+
export interface PanRecognizerOptions {
|
|
32
|
+
/** Distance in px the pointer must travel before `onStart` fires. Default 4. */
|
|
33
|
+
minDistance?: number;
|
|
34
|
+
/** Fires when the pointer crosses `minDistance`. */
|
|
35
|
+
onStart?: (event: PanEvent) => void;
|
|
36
|
+
/** Fires on each pointer move after `onStart`. */
|
|
37
|
+
onMove?: (event: PanEvent) => void;
|
|
38
|
+
/** Fires on `pointerUp`. Carries the final sample. */
|
|
39
|
+
onEnd?: (event: PanEvent) => void;
|
|
40
|
+
/** Fires on `pointerCancel`. No event is built if the gesture never started. */
|
|
41
|
+
onCancel?: (event: PanEvent) => void;
|
|
42
|
+
}
|
|
43
|
+
export interface PanRecognizer {
|
|
44
|
+
pointerDown(sample: PointerSample): void;
|
|
45
|
+
pointerMove(sample: PointerSample): void;
|
|
46
|
+
pointerUp(sample: PointerSample): void;
|
|
47
|
+
pointerCancel(pointerId: number): void;
|
|
48
|
+
/** True while the pan gesture has crossed `minDistance` and not yet ended. */
|
|
49
|
+
isActive(): boolean;
|
|
50
|
+
/** Drop any in-flight gesture without firing callbacks. */
|
|
51
|
+
reset(): void;
|
|
52
|
+
}
|
|
53
|
+
export declare function createPanRecognizer(options?: PanRecognizerOptions): PanRecognizer;
|
|
54
|
+
export type SwipeDirection = 'left' | 'right' | 'up' | 'down';
|
|
55
|
+
export interface SwipeEvent {
|
|
56
|
+
pointerId: number;
|
|
57
|
+
direction: SwipeDirection;
|
|
58
|
+
deltaX: number;
|
|
59
|
+
deltaY: number;
|
|
60
|
+
/** px/ms magnitude of the final velocity. */
|
|
61
|
+
velocity: number;
|
|
62
|
+
elapsedMs: number;
|
|
63
|
+
}
|
|
64
|
+
export interface SwipeRecognizerOptions {
|
|
65
|
+
/** Minimum total travel (px) before a swipe can register. Default 24. */
|
|
66
|
+
minDistance?: number;
|
|
67
|
+
/** Minimum velocity (px/ms) of the release. Default 0.3. */
|
|
68
|
+
minVelocity?: number;
|
|
69
|
+
/** Swipe must complete within this many ms. Default 600. */
|
|
70
|
+
maxDurationMs?: number;
|
|
71
|
+
onSwipe?: (event: SwipeEvent) => void;
|
|
72
|
+
}
|
|
73
|
+
export interface SwipeRecognizer {
|
|
74
|
+
pointerDown(sample: PointerSample): void;
|
|
75
|
+
pointerMove(sample: PointerSample): void;
|
|
76
|
+
pointerUp(sample: PointerSample): void;
|
|
77
|
+
pointerCancel(pointerId: number): void;
|
|
78
|
+
reset(): void;
|
|
79
|
+
}
|
|
80
|
+
export declare function createSwipeRecognizer(options?: SwipeRecognizerOptions): SwipeRecognizer;
|
|
81
|
+
export interface PinchEvent {
|
|
82
|
+
pointerIds: [number, number];
|
|
83
|
+
/** Current distance between the two tracked pointers. */
|
|
84
|
+
distance: number;
|
|
85
|
+
/** Distance between pointers when the gesture became active. */
|
|
86
|
+
startDistance: number;
|
|
87
|
+
/** `distance / startDistance`. Values > 1 = zoom in, < 1 = zoom out. */
|
|
88
|
+
scale: number;
|
|
89
|
+
/** Midpoint of the two pointers, useful as a zoom focal point. */
|
|
90
|
+
centerX: number;
|
|
91
|
+
centerY: number;
|
|
92
|
+
elapsedMs: number;
|
|
93
|
+
}
|
|
94
|
+
export interface PinchRecognizerOptions {
|
|
95
|
+
/** Minimum absolute distance change (px) before `onStart` fires. Default 4. */
|
|
96
|
+
minDeltaDistance?: number;
|
|
97
|
+
onStart?: (event: PinchEvent) => void;
|
|
98
|
+
onMove?: (event: PinchEvent) => void;
|
|
99
|
+
onEnd?: (event: PinchEvent) => void;
|
|
100
|
+
}
|
|
101
|
+
export interface PinchRecognizer {
|
|
102
|
+
pointerDown(sample: PointerSample): void;
|
|
103
|
+
pointerMove(sample: PointerSample): void;
|
|
104
|
+
pointerUp(sample: PointerSample): void;
|
|
105
|
+
pointerCancel(pointerId: number): void;
|
|
106
|
+
isActive(): boolean;
|
|
107
|
+
reset(): void;
|
|
108
|
+
}
|
|
109
|
+
export declare function createPinchRecognizer(options?: PinchRecognizerOptions): PinchRecognizer;
|
|
110
|
+
//# sourceMappingURL=gestures.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"gestures.d.ts","sourceRoot":"","sources":["../src/gestures.ts"],"names":[],"mappings":"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"}
|
package/dist/gestures.js
ADDED
|
@@ -0,0 +1,248 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Renderer-agnostic pointer gesture recognizers: pan/drag, swipe, and pinch.
|
|
3
|
+
*
|
|
4
|
+
* Each recognizer is a pure state machine. Host code (canvas hit-test,
|
|
5
|
+
* terminal pointer, native bridge, tests) feeds it pointer events via
|
|
6
|
+
* `pointerDown`/`pointerMove`/`pointerUp`/`pointerCancel`; the recognizer
|
|
7
|
+
* invokes callbacks when thresholds are crossed. No DOM, no raf.
|
|
8
|
+
*
|
|
9
|
+
* Pointer IDs are integers (matching Pointer Events API conventions), but any
|
|
10
|
+
* stable per-pointer identity works — synthesized ids from terminal tap
|
|
11
|
+
* protocols are fine as long as down/move/up match.
|
|
12
|
+
*/
|
|
13
|
+
function resolveMinDistance(distance, fallback) {
|
|
14
|
+
if (typeof distance !== 'number' || !Number.isFinite(distance) || distance < 0)
|
|
15
|
+
return fallback;
|
|
16
|
+
return distance;
|
|
17
|
+
}
|
|
18
|
+
export function createPanRecognizer(options = {}) {
|
|
19
|
+
const minDistance = resolveMinDistance(options.minDistance, 4);
|
|
20
|
+
const tracked = new Map();
|
|
21
|
+
function buildEvent(t, now) {
|
|
22
|
+
return {
|
|
23
|
+
pointerId: t.start.id,
|
|
24
|
+
x: now.x,
|
|
25
|
+
y: now.y,
|
|
26
|
+
startX: t.start.x,
|
|
27
|
+
startY: t.start.y,
|
|
28
|
+
deltaX: now.x - t.start.x,
|
|
29
|
+
deltaY: now.y - t.start.y,
|
|
30
|
+
elapsedMs: now.timestampMs - t.startTimeMs,
|
|
31
|
+
};
|
|
32
|
+
}
|
|
33
|
+
return {
|
|
34
|
+
pointerDown(sample) {
|
|
35
|
+
tracked.set(sample.id, {
|
|
36
|
+
start: sample,
|
|
37
|
+
last: sample,
|
|
38
|
+
startTimeMs: sample.timestampMs,
|
|
39
|
+
startedGesture: false,
|
|
40
|
+
});
|
|
41
|
+
},
|
|
42
|
+
pointerMove(sample) {
|
|
43
|
+
const t = tracked.get(sample.id);
|
|
44
|
+
if (!t)
|
|
45
|
+
return;
|
|
46
|
+
t.last = sample;
|
|
47
|
+
if (!t.startedGesture) {
|
|
48
|
+
const dx = sample.x - t.start.x;
|
|
49
|
+
const dy = sample.y - t.start.y;
|
|
50
|
+
const dist2 = dx * dx + dy * dy;
|
|
51
|
+
if (dist2 >= minDistance * minDistance) {
|
|
52
|
+
t.startedGesture = true;
|
|
53
|
+
t.startTimeMs = sample.timestampMs;
|
|
54
|
+
options.onStart?.(buildEvent(t, sample));
|
|
55
|
+
}
|
|
56
|
+
return;
|
|
57
|
+
}
|
|
58
|
+
options.onMove?.(buildEvent(t, sample));
|
|
59
|
+
},
|
|
60
|
+
pointerUp(sample) {
|
|
61
|
+
const t = tracked.get(sample.id);
|
|
62
|
+
if (!t)
|
|
63
|
+
return;
|
|
64
|
+
tracked.delete(sample.id);
|
|
65
|
+
if (!t.startedGesture)
|
|
66
|
+
return;
|
|
67
|
+
t.last = sample;
|
|
68
|
+
options.onEnd?.(buildEvent(t, sample));
|
|
69
|
+
},
|
|
70
|
+
pointerCancel(pointerId) {
|
|
71
|
+
const t = tracked.get(pointerId);
|
|
72
|
+
if (!t)
|
|
73
|
+
return;
|
|
74
|
+
tracked.delete(pointerId);
|
|
75
|
+
if (!t.startedGesture)
|
|
76
|
+
return;
|
|
77
|
+
options.onCancel?.(buildEvent(t, t.last));
|
|
78
|
+
},
|
|
79
|
+
isActive() {
|
|
80
|
+
for (const t of tracked.values())
|
|
81
|
+
if (t.startedGesture)
|
|
82
|
+
return true;
|
|
83
|
+
return false;
|
|
84
|
+
},
|
|
85
|
+
reset() {
|
|
86
|
+
tracked.clear();
|
|
87
|
+
},
|
|
88
|
+
};
|
|
89
|
+
}
|
|
90
|
+
function classifyDirection(dx, dy) {
|
|
91
|
+
return Math.abs(dx) >= Math.abs(dy) ? (dx >= 0 ? 'right' : 'left') : dy >= 0 ? 'down' : 'up';
|
|
92
|
+
}
|
|
93
|
+
const VELOCITY_WINDOW_MS = 100;
|
|
94
|
+
export function createSwipeRecognizer(options = {}) {
|
|
95
|
+
const minDistance = resolveMinDistance(options.minDistance, 24);
|
|
96
|
+
const minVelocity = typeof options.minVelocity === 'number' && Number.isFinite(options.minVelocity) && options.minVelocity > 0
|
|
97
|
+
? options.minVelocity
|
|
98
|
+
: 0.3;
|
|
99
|
+
const maxDurationMs = typeof options.maxDurationMs === 'number' && Number.isFinite(options.maxDurationMs) && options.maxDurationMs > 0
|
|
100
|
+
? options.maxDurationMs
|
|
101
|
+
: 600;
|
|
102
|
+
const tracked = new Map();
|
|
103
|
+
return {
|
|
104
|
+
pointerDown(sample) {
|
|
105
|
+
tracked.set(sample.id, { start: sample, samples: [sample] });
|
|
106
|
+
},
|
|
107
|
+
pointerMove(sample) {
|
|
108
|
+
const t = tracked.get(sample.id);
|
|
109
|
+
if (!t)
|
|
110
|
+
return;
|
|
111
|
+
t.samples.push(sample);
|
|
112
|
+
// Keep only the trailing window so velocity doesn't drift on long pans.
|
|
113
|
+
const cutoff = sample.timestampMs - VELOCITY_WINDOW_MS;
|
|
114
|
+
while (t.samples.length > 2 && t.samples[0].timestampMs < cutoff)
|
|
115
|
+
t.samples.shift();
|
|
116
|
+
},
|
|
117
|
+
pointerUp(sample) {
|
|
118
|
+
const t = tracked.get(sample.id);
|
|
119
|
+
if (!t)
|
|
120
|
+
return;
|
|
121
|
+
tracked.delete(sample.id);
|
|
122
|
+
const dx = sample.x - t.start.x;
|
|
123
|
+
const dy = sample.y - t.start.y;
|
|
124
|
+
const dist = Math.hypot(dx, dy);
|
|
125
|
+
const elapsedMs = sample.timestampMs - t.start.timestampMs;
|
|
126
|
+
if (dist < minDistance || elapsedMs <= 0 || elapsedMs > maxDurationMs)
|
|
127
|
+
return;
|
|
128
|
+
const windowStart = t.samples[0];
|
|
129
|
+
const ws = sample.timestampMs - windowStart.timestampMs;
|
|
130
|
+
const wdx = sample.x - windowStart.x;
|
|
131
|
+
const wdy = sample.y - windowStart.y;
|
|
132
|
+
const velocity = ws > 0 ? Math.hypot(wdx, wdy) / ws : 0;
|
|
133
|
+
if (velocity < minVelocity)
|
|
134
|
+
return;
|
|
135
|
+
options.onSwipe?.({
|
|
136
|
+
pointerId: t.start.id,
|
|
137
|
+
direction: classifyDirection(dx, dy),
|
|
138
|
+
deltaX: dx,
|
|
139
|
+
deltaY: dy,
|
|
140
|
+
velocity,
|
|
141
|
+
elapsedMs,
|
|
142
|
+
});
|
|
143
|
+
},
|
|
144
|
+
pointerCancel(pointerId) {
|
|
145
|
+
tracked.delete(pointerId);
|
|
146
|
+
},
|
|
147
|
+
reset() {
|
|
148
|
+
tracked.clear();
|
|
149
|
+
},
|
|
150
|
+
};
|
|
151
|
+
}
|
|
152
|
+
export function createPinchRecognizer(options = {}) {
|
|
153
|
+
const minDelta = resolveMinDistance(options.minDeltaDistance, 4);
|
|
154
|
+
const state = {
|
|
155
|
+
pointers: new Map(),
|
|
156
|
+
lastPair: null,
|
|
157
|
+
startDistance: 0,
|
|
158
|
+
startTimeMs: 0,
|
|
159
|
+
started: false,
|
|
160
|
+
};
|
|
161
|
+
function twoPointers() {
|
|
162
|
+
if (state.pointers.size !== 2)
|
|
163
|
+
return null;
|
|
164
|
+
const iter = state.pointers.values();
|
|
165
|
+
const first = iter.next().value;
|
|
166
|
+
const second = iter.next().value;
|
|
167
|
+
return [first, second];
|
|
168
|
+
}
|
|
169
|
+
function distance(a, b) {
|
|
170
|
+
return Math.hypot(a.x - b.x, a.y - b.y);
|
|
171
|
+
}
|
|
172
|
+
function buildEvent(pair, now) {
|
|
173
|
+
const d = distance(pair[0], pair[1]);
|
|
174
|
+
return {
|
|
175
|
+
pointerIds: [pair[0].id, pair[1].id],
|
|
176
|
+
distance: d,
|
|
177
|
+
startDistance: state.startDistance || d,
|
|
178
|
+
scale: state.startDistance > 0 ? d / state.startDistance : 1,
|
|
179
|
+
centerX: (pair[0].x + pair[1].x) / 2,
|
|
180
|
+
centerY: (pair[0].y + pair[1].y) / 2,
|
|
181
|
+
elapsedMs: now - state.startTimeMs,
|
|
182
|
+
};
|
|
183
|
+
}
|
|
184
|
+
function endGesture(lastTimestamp) {
|
|
185
|
+
if (!state.started)
|
|
186
|
+
return;
|
|
187
|
+
const pair = state.lastPair ?? twoPointers();
|
|
188
|
+
if (pair)
|
|
189
|
+
options.onEnd?.(buildEvent(pair, lastTimestamp));
|
|
190
|
+
state.started = false;
|
|
191
|
+
state.startDistance = 0;
|
|
192
|
+
state.lastPair = null;
|
|
193
|
+
}
|
|
194
|
+
return {
|
|
195
|
+
pointerDown(sample) {
|
|
196
|
+
if (state.pointers.size >= 2 && !state.pointers.has(sample.id))
|
|
197
|
+
return;
|
|
198
|
+
state.pointers.set(sample.id, sample);
|
|
199
|
+
if (state.pointers.size === 2 && !state.started) {
|
|
200
|
+
const pair = twoPointers();
|
|
201
|
+
state.startDistance = distance(pair[0], pair[1]);
|
|
202
|
+
state.startTimeMs = sample.timestampMs;
|
|
203
|
+
state.lastPair = pair;
|
|
204
|
+
}
|
|
205
|
+
},
|
|
206
|
+
pointerMove(sample) {
|
|
207
|
+
if (!state.pointers.has(sample.id))
|
|
208
|
+
return;
|
|
209
|
+
state.pointers.set(sample.id, sample);
|
|
210
|
+
const pair = twoPointers();
|
|
211
|
+
if (!pair)
|
|
212
|
+
return;
|
|
213
|
+
state.lastPair = pair;
|
|
214
|
+
const d = distance(pair[0], pair[1]);
|
|
215
|
+
if (!state.started) {
|
|
216
|
+
if (Math.abs(d - state.startDistance) < minDelta)
|
|
217
|
+
return;
|
|
218
|
+
state.started = true;
|
|
219
|
+
options.onStart?.(buildEvent(pair, sample.timestampMs));
|
|
220
|
+
return;
|
|
221
|
+
}
|
|
222
|
+
options.onMove?.(buildEvent(pair, sample.timestampMs));
|
|
223
|
+
},
|
|
224
|
+
pointerUp(sample) {
|
|
225
|
+
const existed = state.pointers.has(sample.id);
|
|
226
|
+
state.pointers.delete(sample.id);
|
|
227
|
+
if (existed && state.pointers.size < 2)
|
|
228
|
+
endGesture(sample.timestampMs);
|
|
229
|
+
},
|
|
230
|
+
pointerCancel(pointerId) {
|
|
231
|
+
const existed = state.pointers.has(pointerId);
|
|
232
|
+
state.pointers.delete(pointerId);
|
|
233
|
+
if (existed && state.pointers.size < 2)
|
|
234
|
+
endGesture(state.startTimeMs);
|
|
235
|
+
},
|
|
236
|
+
isActive() {
|
|
237
|
+
return state.started;
|
|
238
|
+
},
|
|
239
|
+
reset() {
|
|
240
|
+
state.pointers.clear();
|
|
241
|
+
state.started = false;
|
|
242
|
+
state.startDistance = 0;
|
|
243
|
+
state.startTimeMs = 0;
|
|
244
|
+
state.lastPair = null;
|
|
245
|
+
},
|
|
246
|
+
};
|
|
247
|
+
}
|
|
248
|
+
//# sourceMappingURL=gestures.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"gestures.js","sourceRoot":"","sources":["../src/gestures.ts"],"names":[],"mappings":"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"}
|
package/dist/hit-test.d.ts
CHANGED
|
@@ -46,8 +46,9 @@ export interface HitDispatchResult {
|
|
|
46
46
|
* For `onClick` only, the return value may include `focusTarget` for focus routing
|
|
47
47
|
* (including click-to-focus when there is no `onClick` handler).
|
|
48
48
|
* Non-box roots (`text`, `image`, `scene3d`) always return `{ handled: false }` — attach pointer handlers to a parent {@link import('./types.js').BoxElement}.
|
|
49
|
-
* Pointer `x` / `y` must be finite numbers
|
|
50
|
-
*
|
|
49
|
+
* Pointer `x` / `y` must be **primitive** finite numbers — same rule as
|
|
50
|
+
* {@link import('./layout-bounds.js').isFinitePlainNumber} / {@link import('./layout-bounds.js').pointInInclusiveLayoutRect}
|
|
51
|
+
* (boxed numbers and non-numbers return `{ handled: false }` without invoking handlers).
|
|
51
52
|
* Layout bounds must be finite and non-negative on `width` and `height`; otherwise the node is
|
|
52
53
|
* skipped for hit-testing (corrupt geometry from Yoga or a bad snapshot).
|
|
53
54
|
*
|
|
@@ -75,7 +76,7 @@ export declare function dispatchHit(element: UIElement, layout: ComputedLayout,
|
|
|
75
76
|
* (`onClick`, `onPointerDown` / `Up` / `Move`, `onWheel`). Keyboard and composition
|
|
76
77
|
* handlers alone do not count — use this for hover / pointer-capture style checks.
|
|
77
78
|
*
|
|
78
|
-
* Non-finite or non-number `x` / `y` return `false` (same
|
|
79
|
+
* Non-finite or non-number `x` / `y` return `false` (same {@link import('./layout-bounds.js').isFinitePlainNumber} guard as {@link dispatchHit}).
|
|
79
80
|
*
|
|
80
81
|
* Optional `offsetX` / `offsetY` match {@link hitPathAtPoint} / {@link dispatchHit} for rooted coordinate transforms.
|
|
81
82
|
* Non-finite or non-number offsets are treated as `0`.
|
|
@@ -94,7 +95,7 @@ export declare function hasInteractiveHitAtPoint(element: UIElement, layout: Com
|
|
|
94
95
|
* non-finite or non-number `zIndex` values match `dispatchHit` / paint order (treated as `0`).
|
|
95
96
|
* Boxes with `pointerEvents: 'none'` are skipped for path segments; if the deepest matching geometry is only such a box
|
|
96
97
|
* (no deeper box under the point), returns `null` (same as missing the interactive stack).
|
|
97
|
-
* Non-finite or non-number `x` / `y` return `null` (same
|
|
98
|
+
* Non-finite or non-number `x` / `y` return `null` (same {@link import('./layout-bounds.js').isFinitePlainNumber} guard as {@link dispatchHit}).
|
|
98
99
|
* Returns `null` when the point misses the tree, when the root is not a `box` (text/image/scene3d roots have no index path),
|
|
99
100
|
* or in the `pointerEvents: 'none'` deepest-only case above. Returns `[]` when the point hits a box root or leaf box with
|
|
100
101
|
* no deeper box under the point.
|
|
@@ -119,7 +120,7 @@ export declare function hitPathAtPoint(element: UIElement, layout: ComputedLayou
|
|
|
119
120
|
* fall through to geometry behind, matching {@link hitPathAtPoint}.
|
|
120
121
|
*
|
|
121
122
|
* Root `offsetX` / `offsetY` follow {@link dispatchHit}: non-finite or non-number values are treated as `0`.
|
|
122
|
-
* Non-finite or non-number `x` / `y` return `null
|
|
123
|
+
* Non-finite or non-number `x` / `y` return `null` ({@link import('./layout-bounds.js').isFinitePlainNumber}).
|
|
123
124
|
*
|
|
124
125
|
* An empty-string `cursor` on a nested box does not stop the walk (child results are checked with truthiness),
|
|
125
126
|
* so the nearest ancestor with a non-empty `cursor` wins. A root hit on a lone box with `cursor: ''` still
|
package/dist/hit-test.d.ts.map
CHANGED
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"hit-test.d.ts","sourceRoot":"","sources":["../src/hit-test.ts"],"names":[],"mappings":"AAAA,OAAO,KAAK,EAAE,cAAc,EAAE,MAAM,SAAS,CAAA;AAC7C,OAAO,KAAK,EAAE,SAAS,EAAE,UAAU,EAAE,aAAa,EAAY,MAAM,YAAY,CAAA;
|
|
1
|
+
{"version":3,"file":"hit-test.d.ts","sourceRoot":"","sources":["../src/hit-test.ts"],"names":[],"mappings":"AAAA,OAAO,KAAK,EAAE,cAAc,EAAE,MAAM,SAAS,CAAA;AAC7C,OAAO,KAAK,EAAE,SAAS,EAAE,UAAU,EAAE,aAAa,EAAY,MAAM,YAAY,CAAA;AAsHhF;;;GAGG;AACH,MAAM,WAAW,iBAAiB;IAChC;;;;;;;OAOG;IACH,OAAO,EAAE,OAAO,CAAA;IAChB;;;;;;OAMG;IACH,WAAW,CAAC,EAAE;QAAE,OAAO,EAAE,UAAU,CAAC;QAAC,MAAM,EAAE,cAAc,CAAA;KAAE,CAAA;CAC9D;AA2HD;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;GA2CG;AACH,wBAAgB,WAAW,CACzB,OAAO,EAAE,SAAS,EAClB,MAAM,EAAE,cAAc,EACtB,SAAS,EAAE,MAAM,aAAa,EAC9B,CAAC,EAAE,MAAM,EACT,CAAC,EAAE,MAAM,EACT,KAAK,CAAC,EAAE,MAAM,CAAC,MAAM,EAAE,OAAO,CAAC,EAC/B,OAAO,SAAI,EACX,OAAO,SAAI,GACV,iBAAiB,CAWnB;AAED;;;;;;;;;;;;;;;;;GAiBG;AACH,wBAAgB,wBAAwB,CACtC,OAAO,EAAE,SAAS,EAClB,MAAM,EAAE,cAAc,EACtB,CAAC,EAAE,MAAM,EACT,CAAC,EAAE,MAAM,EACT,OAAO,SAAI,EACX,OAAO,SAAI,GACV,OAAO,CAgBT;AA2BD;;;;;;;;;;;;;;;;;;GAkBG;AACH,wBAAgB,cAAc,CAC5B,OAAO,EAAE,SAAS,EAClB,MAAM,EAAE,cAAc,EACtB,CAAC,EAAE,MAAM,EACT,CAAC,EAAE,MAAM,EACT,OAAO,SAAI,EACX,OAAO,SAAI,GACV,MAAM,EAAE,GAAG,IAAI,CAuBjB;AAED;;;;;;;;;;;;;;;;;;;;;;;;GAwBG;AACH,wBAAgB,gBAAgB,CAC9B,OAAO,EAAE,SAAS,EAClB,MAAM,EAAE,cAAc,EACtB,CAAC,EAAE,MAAM,EACT,CAAC,EAAE,MAAM,EACT,OAAO,SAAI,EACX,OAAO,SAAI,GACV,MAAM,GAAG,IAAI,CAiCf"}
|
package/dist/hit-test.js
CHANGED
|
@@ -1,5 +1,5 @@
|
|
|
1
1
|
import { hasFocusCandidateHandlers } from './focus-candidates.js';
|
|
2
|
-
import { finiteNumberOrZero, layoutBoundsAreFinite, pointInInclusiveLayoutRect, scrollSafeChildOffsets, } from './layout-bounds.js';
|
|
2
|
+
import { finiteNumberOrZero, isFinitePlainNumber, layoutBoundsAreFinite, pointInInclusiveLayoutRect, scrollSafeChildOffsets, } from './layout-bounds.js';
|
|
3
3
|
const zIndexOrderCache = new WeakMap();
|
|
4
4
|
function zIndexOf(el) {
|
|
5
5
|
if (el == null)
|
|
@@ -31,44 +31,43 @@ function getChildrenByZAsc(boxEl) {
|
|
|
31
31
|
zIndexOrderCache.set(boxEl, { zValues, asc });
|
|
32
32
|
return asc;
|
|
33
33
|
}
|
|
34
|
-
// Three+ children
|
|
35
|
-
|
|
36
|
-
|
|
37
|
-
|
|
38
|
-
|
|
39
|
-
|
|
40
|
-
|
|
41
|
-
|
|
42
|
-
|
|
43
|
-
|
|
44
|
-
|
|
45
|
-
|
|
46
|
-
|
|
47
|
-
|
|
48
|
-
|
|
49
|
-
|
|
50
|
-
|
|
51
|
-
|
|
52
|
-
|
|
34
|
+
// Three+ children: one zIndexOf pass fills zValues, then either identity order (all equal z) or sort.
|
|
35
|
+
// Cache checks compare against that same zValues array — no second zIndexOf sweep before sort.
|
|
36
|
+
const zValues = new Array(n);
|
|
37
|
+
zValues[0] = zIndexOf(kids[0]);
|
|
38
|
+
let allEqual = true;
|
|
39
|
+
for (let i = 1; i < n; i++) {
|
|
40
|
+
const zi = zIndexOf(kids[i]);
|
|
41
|
+
zValues[i] = zi;
|
|
42
|
+
if (zi !== zValues[0])
|
|
43
|
+
allEqual = false;
|
|
44
|
+
}
|
|
45
|
+
if (allEqual) {
|
|
46
|
+
const z0 = zValues[0];
|
|
47
|
+
const cached = zIndexOrderCache.get(boxEl);
|
|
48
|
+
if (cached && cached.zValues.length === n) {
|
|
49
|
+
let match = true;
|
|
50
|
+
for (let j = 0; j < n; j++) {
|
|
51
|
+
if (cached.zValues[j] !== z0) {
|
|
52
|
+
match = false;
|
|
53
|
+
break;
|
|
53
54
|
}
|
|
54
|
-
if (match)
|
|
55
|
-
return cached.asc;
|
|
56
|
-
}
|
|
57
|
-
const zValues = new Array(n);
|
|
58
|
-
const asc = new Array(n);
|
|
59
|
-
for (let i = 0; i < n; i++) {
|
|
60
|
-
zValues[i] = z0;
|
|
61
|
-
asc[i] = i;
|
|
62
55
|
}
|
|
63
|
-
|
|
64
|
-
|
|
56
|
+
if (match)
|
|
57
|
+
return cached.asc;
|
|
65
58
|
}
|
|
59
|
+
const asc = new Array(n);
|
|
60
|
+
for (let i = 0; i < n; i++) {
|
|
61
|
+
asc[i] = i;
|
|
62
|
+
}
|
|
63
|
+
zIndexOrderCache.set(boxEl, { zValues, asc });
|
|
64
|
+
return asc;
|
|
66
65
|
}
|
|
67
66
|
const cached = zIndexOrderCache.get(boxEl);
|
|
68
67
|
if (cached && cached.zValues.length === n) {
|
|
69
68
|
let unchanged = true;
|
|
70
69
|
for (let i = 0; i < n; i++) {
|
|
71
|
-
if (cached.zValues[i] !==
|
|
70
|
+
if (cached.zValues[i] !== zValues[i]) {
|
|
72
71
|
unchanged = false;
|
|
73
72
|
break;
|
|
74
73
|
}
|
|
@@ -76,11 +75,6 @@ function getChildrenByZAsc(boxEl) {
|
|
|
76
75
|
if (unchanged)
|
|
77
76
|
return cached.asc;
|
|
78
77
|
}
|
|
79
|
-
// Single pass: stale or missing cache must not re-call zIndexOf after validation (was map + prior loop).
|
|
80
|
-
const zValues = new Array(n);
|
|
81
|
-
for (let i = 0; i < n; i++) {
|
|
82
|
-
zValues[i] = zIndexOf(kids[i]);
|
|
83
|
-
}
|
|
84
78
|
const asc = new Array(n);
|
|
85
79
|
for (let i = 0; i < n; i++) {
|
|
86
80
|
asc[i] = i;
|
|
@@ -101,7 +95,7 @@ function getChildrenByZAsc(boxEl) {
|
|
|
101
95
|
}
|
|
102
96
|
/** Walk the element tree + computed layout in parallel to find hit targets at (x, y). */
|
|
103
97
|
function collectHits(element, layout, x, y, offsetX, offsetY, results) {
|
|
104
|
-
if (!
|
|
98
|
+
if (!isFinitePlainNumber(x) || !isFinitePlainNumber(y))
|
|
105
99
|
return;
|
|
106
100
|
if (!layoutBoundsAreFinite(layout))
|
|
107
101
|
return;
|
|
@@ -128,7 +122,7 @@ function collectHits(element, layout, x, y, offsetX, offsetY, results) {
|
|
|
128
122
|
}
|
|
129
123
|
}
|
|
130
124
|
function dispatchHitRecursive(element, layout, eventType, x, y, offsetX, offsetY, extra) {
|
|
131
|
-
if (!
|
|
125
|
+
if (!isFinitePlainNumber(x) || !isFinitePlainNumber(y))
|
|
132
126
|
return { handled: false };
|
|
133
127
|
if (!layoutBoundsAreFinite(layout))
|
|
134
128
|
return { handled: false };
|
|
@@ -206,8 +200,9 @@ function dispatchHitRecursive(element, layout, eventType, x, y, offsetX, offsetY
|
|
|
206
200
|
* For `onClick` only, the return value may include `focusTarget` for focus routing
|
|
207
201
|
* (including click-to-focus when there is no `onClick` handler).
|
|
208
202
|
* Non-box roots (`text`, `image`, `scene3d`) always return `{ handled: false }` — attach pointer handlers to a parent {@link import('./types.js').BoxElement}.
|
|
209
|
-
* Pointer `x` / `y` must be finite numbers
|
|
210
|
-
*
|
|
203
|
+
* Pointer `x` / `y` must be **primitive** finite numbers — same rule as
|
|
204
|
+
* {@link import('./layout-bounds.js').isFinitePlainNumber} / {@link import('./layout-bounds.js').pointInInclusiveLayoutRect}
|
|
205
|
+
* (boxed numbers and non-numbers return `{ handled: false }` without invoking handlers).
|
|
211
206
|
* Layout bounds must be finite and non-negative on `width` and `height`; otherwise the node is
|
|
212
207
|
* skipped for hit-testing (corrupt geometry from Yoga or a bad snapshot).
|
|
213
208
|
*
|
|
@@ -237,7 +232,7 @@ export function dispatchHit(element, layout, eventType, x, y, extra, offsetX = 0
|
|
|
237
232
|
* (`onClick`, `onPointerDown` / `Up` / `Move`, `onWheel`). Keyboard and composition
|
|
238
233
|
* handlers alone do not count — use this for hover / pointer-capture style checks.
|
|
239
234
|
*
|
|
240
|
-
* Non-finite or non-number `x` / `y` return `false` (same
|
|
235
|
+
* Non-finite or non-number `x` / `y` return `false` (same {@link import('./layout-bounds.js').isFinitePlainNumber} guard as {@link dispatchHit}).
|
|
241
236
|
*
|
|
242
237
|
* Optional `offsetX` / `offsetY` match {@link hitPathAtPoint} / {@link dispatchHit} for rooted coordinate transforms.
|
|
243
238
|
* Non-finite or non-number offsets are treated as `0`.
|
|
@@ -272,7 +267,7 @@ export function hasInteractiveHitAtPoint(element, layout, x, y, offsetX = 0, off
|
|
|
272
267
|
* Returns the node’s absolute origin `(absX, absY)` when the point hits the layout rect.
|
|
273
268
|
*/
|
|
274
269
|
function rootedLayoutPointContainment(layout, x, y, offsetX, offsetY) {
|
|
275
|
-
if (!
|
|
270
|
+
if (!isFinitePlainNumber(x) || !isFinitePlainNumber(y))
|
|
276
271
|
return null;
|
|
277
272
|
if (!layoutBoundsAreFinite(layout))
|
|
278
273
|
return null;
|
|
@@ -289,7 +284,7 @@ function rootedLayoutPointContainment(layout, x, y, offsetX, offsetY) {
|
|
|
289
284
|
* non-finite or non-number `zIndex` values match `dispatchHit` / paint order (treated as `0`).
|
|
290
285
|
* Boxes with `pointerEvents: 'none'` are skipped for path segments; if the deepest matching geometry is only such a box
|
|
291
286
|
* (no deeper box under the point), returns `null` (same as missing the interactive stack).
|
|
292
|
-
* Non-finite or non-number `x` / `y` return `null` (same
|
|
287
|
+
* Non-finite or non-number `x` / `y` return `null` (same {@link import('./layout-bounds.js').isFinitePlainNumber} guard as {@link dispatchHit}).
|
|
293
288
|
* Returns `null` when the point misses the tree, when the root is not a `box` (text/image/scene3d roots have no index path),
|
|
294
289
|
* or in the `pointerEvents: 'none'` deepest-only case above. Returns `[]` when the point hits a box root or leaf box with
|
|
295
290
|
* no deeper box under the point.
|
|
@@ -339,7 +334,7 @@ export function hitPathAtPoint(element, layout, x, y, offsetX = 0, offsetY = 0)
|
|
|
339
334
|
* fall through to geometry behind, matching {@link hitPathAtPoint}.
|
|
340
335
|
*
|
|
341
336
|
* Root `offsetX` / `offsetY` follow {@link dispatchHit}: non-finite or non-number values are treated as `0`.
|
|
342
|
-
* Non-finite or non-number `x` / `y` return `null
|
|
337
|
+
* Non-finite or non-number `x` / `y` return `null` ({@link import('./layout-bounds.js').isFinitePlainNumber}).
|
|
343
338
|
*
|
|
344
339
|
* An empty-string `cursor` on a nested box does not stop the walk (child results are checked with truthiness),
|
|
345
340
|
* so the nearest ancestor with a non-empty `cursor` wins. A root hit on a lone box with `cursor: ''` still
|