@vizejs/ui 0.345.0 → 0.347.7

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 (44) hide show
  1. package/dist/{button-D7sM9Xmj.d.mts → button-BMIqJ_M5.d.mts} +1 -1
  2. package/dist/button.d.mts +1 -1
  3. package/dist/button.mjs +1 -1
  4. package/dist/{checkbox-DkwZFC80.d.mts → checkbox-sbhaWekB.d.mts} +1 -1
  5. package/dist/checkbox.d.mts +1 -1
  6. package/dist/collection-CoOROaho.mjs +453 -0
  7. package/dist/collection-aHZ6Pf0e.d.mts +185 -0
  8. package/dist/collection.d.mts +2 -0
  9. package/dist/collection.mjs +2 -0
  10. package/dist/controllable-state.d.mts +1 -1
  11. package/dist/id-BSgJwErt.d.mts +127 -0
  12. package/dist/id-CPBdeoL3.mjs +137 -0
  13. package/dist/id.d.mts +2 -0
  14. package/dist/id.mjs +2 -0
  15. package/dist/index.d.mts +12 -6
  16. package/dist/index.mjs +9 -4
  17. package/dist/interaction-modality-CO-eQzNy.mjs +304 -0
  18. package/dist/interaction-modality-tee79ZBZ.d.mts +89 -0
  19. package/dist/interaction-modality.d.mts +2 -0
  20. package/dist/interaction-modality.mjs +2 -0
  21. package/dist/long-press-CRjjjJK2.d.mts +115 -0
  22. package/dist/long-press.d.mts +2 -0
  23. package/dist/long-press.mjs +246 -0
  24. package/dist/media-pdf.d.mts +1 -1
  25. package/dist/media-pdf.mjs +1 -1
  26. package/dist/media.d.mts +1 -1
  27. package/dist/media.mjs +1 -1
  28. package/dist/press-Bp57IOe2.mjs +615 -0
  29. package/dist/press-types-B8Ssxqg4.d.mts +112 -0
  30. package/dist/press.d.mts +14 -0
  31. package/dist/press.mjs +2 -0
  32. package/dist/primitive.d.mts +1 -1
  33. package/dist/primitive.mjs +1 -1
  34. package/dist/visually-hidden.d.mts +1 -1
  35. package/dist/visually-hidden.mjs +1 -1
  36. package/package.json +34 -7
  37. /package/dist/{button-8BOlFJNu.mjs → button-CaLxP2l2.mjs} +0 -0
  38. /package/dist/{controllable-state-DXsYJ3yl.d.mts → controllable-state-B9v6FClp.d.mts} +0 -0
  39. /package/dist/{pdf-source-COxN3A1l.d.mts → pdf-source-BbZKF_dS.d.mts} +0 -0
  40. /package/dist/{pdf-source-C52YE8tp.mjs → pdf-source-C9zNQd9l.mjs} +0 -0
  41. /package/dist/{primitive-DJB7pOf3.mjs → primitive-BE28SwD7.mjs} +0 -0
  42. /package/dist/{primitive-BtvwikH1.d.mts → primitive-Bog8qvd8.d.mts} +0 -0
  43. /package/dist/{visually-hidden-QENRapzW.mjs → visually-hidden-CTSV3ctZ.mjs} +0 -0
  44. /package/dist/{visually-hidden-BegtnMng.d.mts → visually-hidden-CekDwEwR.d.mts} +0 -0
@@ -0,0 +1,615 @@
1
+ import { getCurrentScope, onScopeDispose, shallowReadonly, shallowRef, toValue } from "vue";
2
+ //#region src/press-event.ts
3
+ const invalidOptionDiagnostic = "VIZE_UI_PRESS_OPTION";
4
+ const pointerTypes = new Set([
5
+ "keyboard",
6
+ "mouse",
7
+ "pen",
8
+ "pointer",
9
+ "touch",
10
+ "virtual"
11
+ ]);
12
+ const keyboardBehaviors = new Set([
13
+ "button",
14
+ "link",
15
+ "none"
16
+ ]);
17
+ /** Resolve and validate a reactive boolean option for JavaScript consumers. */
18
+ function readBooleanOption(value, name) {
19
+ const resolved = toValue(value);
20
+ if (resolved === void 0) return false;
21
+ if (typeof resolved !== "boolean") throw new TypeError(`${invalidOptionDiagnostic}: ${name} must resolve to a boolean`);
22
+ return resolved;
23
+ }
24
+ /** Resolve the closed keyboard behavior union without accepting mistyped JS. */
25
+ function readKeyboardBehavior(value) {
26
+ const resolved = toValue(value) ?? "button";
27
+ if (!keyboardBehaviors.has(resolved)) throw new TypeError(`${invalidOptionDiagnostic}: keyboardBehavior must resolve to button, link, or none`);
28
+ return resolved;
29
+ }
30
+ /** Resolve a cross-realm event currentTarget without instanceof assumptions. */
31
+ function eventElement(event) {
32
+ const value = event.currentTarget;
33
+ return value && value.nodeType === 1 ? value : null;
34
+ }
35
+ /** Map Pointer Events' extensible device string to the stable public union. */
36
+ function pointerTypeOf(event) {
37
+ if (event.pointerId === -1 && event.pointerType === "") return "virtual";
38
+ if (event.pointerType === "mouse" || event.pointerType === "pen") return event.pointerType;
39
+ if (event.pointerType === "touch") return "touch";
40
+ return "pointer";
41
+ }
42
+ /** Only a primary contact and its primary button can activate a control. */
43
+ function isPrimaryPointer(event) {
44
+ return event.isPrimary !== false && event.button === 0;
45
+ }
46
+ function eventPoint(event, touchIdentifier = null) {
47
+ if (!event) return null;
48
+ if ("clientX" in event && "clientY" in event) return {
49
+ x: Number(event.clientX),
50
+ y: Number(event.clientY)
51
+ };
52
+ if ("changedTouches" in event) {
53
+ const touches = Array.from(event.changedTouches);
54
+ const touch = (touchIdentifier === null ? touches[0] : touches.find(({ identifier }) => identifier === touchIdentifier)) ?? null;
55
+ if (touch) return {
56
+ x: touch.clientX,
57
+ y: touch.clientY
58
+ };
59
+ }
60
+ return null;
61
+ }
62
+ function modifier(event, key) {
63
+ return event && key in event ? Boolean(event[key]) : false;
64
+ }
65
+ /** Build a frozen snapshot so later browser mutation cannot change callbacks' data. */
66
+ function createPressEvent(type, target, pointerType, originalEvent, isCanceled = false, touchIdentifier = null) {
67
+ if (!pointerTypes.has(pointerType)) throw new TypeError(`${invalidOptionDiagnostic}: invalid press pointer type`);
68
+ const point = eventPoint(originalEvent, touchIdentifier);
69
+ return Object.freeze({
70
+ type,
71
+ pointerType,
72
+ target,
73
+ originalEvent,
74
+ x: point?.x ?? null,
75
+ y: point?.y ?? null,
76
+ altKey: modifier(originalEvent, "altKey"),
77
+ ctrlKey: modifier(originalEvent, "ctrlKey"),
78
+ metaKey: modifier(originalEvent, "metaKey"),
79
+ shiftKey: modifier(originalEvent, "shiftKey"),
80
+ isCanceled
81
+ });
82
+ }
83
+ /** Native elements retain their own activation timing and default actions. */
84
+ function keyboardActivation(target, key, behavior) {
85
+ if (behavior === "none") return null;
86
+ const tag = target.localName;
87
+ if (tag === "a" || tag === "area") {
88
+ if (target.hasAttribute("href")) return key === "Enter" ? "native" : null;
89
+ }
90
+ if (tag === "button") return key === "Enter" || key === " " ? "native" : null;
91
+ if (tag === "summary") return key === "Enter" || key === " " ? "native" : null;
92
+ if (tag === "input") {
93
+ const type = (target.getAttribute("type") ?? "text").toLowerCase();
94
+ if (type === "checkbox" || type === "radio") return key === " " ? "native" : null;
95
+ return new Set([
96
+ "button",
97
+ "file",
98
+ "image",
99
+ "reset",
100
+ "submit"
101
+ ]).has(type) && (key === "Enter" || key === " ") ? "native" : null;
102
+ }
103
+ if (behavior === "link") return key === "Enter" ? "custom" : null;
104
+ return key === "Enter" || key === " " ? "custom" : null;
105
+ }
106
+ /** Determine pointer containment without assuming events originate in one realm. */
107
+ function isEventInside(event, target, touchIdentifier = null) {
108
+ const point = eventPoint(event, touchIdentifier);
109
+ if (point) {
110
+ const hit = target.ownerDocument.elementFromPoint?.(point.x, point.y);
111
+ if (hit) return hit === target || target.contains(hit);
112
+ }
113
+ return event.composedPath().includes(target);
114
+ }
115
+ /** Apply a transient selection guard and return an exact, idempotent restore. */
116
+ function disableTextSelection(target) {
117
+ if (!("style" in target)) return () => void 0;
118
+ const style = target.style;
119
+ if (!style || typeof style.setProperty !== "function") return () => void 0;
120
+ const properties = ["user-select", "-webkit-user-select"];
121
+ const previous = properties.map((property) => ({
122
+ property,
123
+ value: style.getPropertyValue(property),
124
+ priority: style.getPropertyPriority(property)
125
+ }));
126
+ for (const property of properties) style.setProperty(property, "none");
127
+ let restored = false;
128
+ return () => {
129
+ if (restored) return;
130
+ restored = true;
131
+ for (const { property, value, priority } of previous) if (value) style.setProperty(property, value, priority);
132
+ else style.removeProperty(property);
133
+ };
134
+ }
135
+ /** Validate callback slots eagerly so setup failures never install listeners. */
136
+ function validatePressOptions(options) {
137
+ for (const name of [
138
+ "onPress",
139
+ "onPressChange",
140
+ "onPressEnd",
141
+ "onPressStart",
142
+ "onPressUp"
143
+ ]) {
144
+ const callback = options[name];
145
+ if (callback !== void 0 && typeof callback !== "function") throw new TypeError(`${invalidOptionDiagnostic}: ${name} must be a function`);
146
+ }
147
+ }
148
+ //#endregion
149
+ //#region src/press-handlers.ts
150
+ /** Adapt Pointer Events plus legacy mouse/touch and keyboard events to one lifecycle. */
151
+ function createPressHandlers(lifecycle) {
152
+ let lastTouchTime = Number.NEGATIVE_INFINITY;
153
+ function onPointerDown(event) {
154
+ if (lifecycle.disposed || lifecycle.active || !isPrimaryPointer(event)) return;
155
+ const target = eventElement(event);
156
+ if (!target || readBooleanOption(lifecycle.options.isDisabled, "isDisabled")) return;
157
+ lifecycle.start(event, target, "pointer", pointerTypeOf(event), event.pointerId, null, false);
158
+ }
159
+ function onPointerMove(event) {
160
+ const current = lifecycle.active;
161
+ if (!matches(current, "pointer", event.pointerId)) return;
162
+ lifecycle.updatePointerBoundary(current, event);
163
+ }
164
+ function onPointerUp(event) {
165
+ const current = lifecycle.active;
166
+ if (!matches(current, "pointer", event.pointerId)) return;
167
+ lifecycle.finishPointer(current, event);
168
+ }
169
+ function onPointerCancel(event) {
170
+ const current = lifecycle.active;
171
+ if (matches(current, "pointer", event.pointerId)) lifecycle.cancelActive(event);
172
+ }
173
+ function onMouseDown(event) {
174
+ if (lifecycle.disposed || event.button !== 0) return;
175
+ const target = eventElement(event);
176
+ if (!target || readBooleanOption(lifecycle.options.isDisabled, "isDisabled")) return;
177
+ const elapsed = event.timeStamp - lastTouchTime;
178
+ if (elapsed >= 0 && elapsed < 800) return;
179
+ if (readBooleanOption(lifecycle.options.preventFocusOnPress, "preventFocusOnPress")) event.preventDefault();
180
+ if (event.view && "PointerEvent" in event.view || lifecycle.active) return;
181
+ lifecycle.start(event, target, "mouse", "mouse", null, null, false);
182
+ }
183
+ function onMouseMove(event) {
184
+ const current = lifecycle.active;
185
+ if (current?.source === "mouse") lifecycle.updatePointerBoundary(current, event);
186
+ }
187
+ function onMouseUp(event) {
188
+ const current = lifecycle.active;
189
+ if (current?.source === "mouse" && event.button === 0) lifecycle.finishPointer(current, event);
190
+ }
191
+ function onTouchStart(event) {
192
+ if (lifecycle.disposed || event.view && "PointerEvent" in event.view || lifecycle.active || event.changedTouches.length !== 1) return;
193
+ const target = eventElement(event);
194
+ if (!target || readBooleanOption(lifecycle.options.isDisabled, "isDisabled")) return;
195
+ const touch = event.changedTouches.item(0);
196
+ lastTouchTime = event.timeStamp;
197
+ lifecycle.start(event, target, "touch", "touch", touch.identifier, null, false);
198
+ }
199
+ function onTouchMove(event) {
200
+ const current = lifecycle.active;
201
+ if (current?.source === "touch" && touchMatches(event, current)) lifecycle.updatePointerBoundary(current, event);
202
+ }
203
+ function onTouchEnd(event) {
204
+ const current = lifecycle.active;
205
+ if (current?.source === "touch" && touchMatches(event, current)) lifecycle.finishPointer(current, event);
206
+ }
207
+ function onTouchCancel(event) {
208
+ const current = lifecycle.active;
209
+ if (current?.source === "touch" && touchMatches(event, current)) lifecycle.cancelActive(event);
210
+ }
211
+ function onKeyDown(event) {
212
+ if (lifecycle.disposed || lifecycle.active || event.isComposing || event.repeat || event.target !== event.currentTarget) return;
213
+ const target = eventElement(event);
214
+ if (!target || readBooleanOption(lifecycle.options.isDisabled, "isDisabled")) return;
215
+ const activation = keyboardActivation(target, event.key, readKeyboardBehavior(lifecycle.options.keyboardBehavior));
216
+ if (!activation) return;
217
+ if (event.key === " " && activation === "custom") event.preventDefault();
218
+ lifecycle.start(event, target, "keyboard", "keyboard", null, event.key, activation === "native");
219
+ }
220
+ function onKeyUp(event) {
221
+ const current = lifecycle.active;
222
+ if (current?.source === "keyboard" && event.key === current.key) lifecycle.finishKeyboard(current, event);
223
+ }
224
+ function onClick(event) {
225
+ if (lifecycle.disposed) return;
226
+ const target = eventElement(event);
227
+ if (target) lifecycle.activateClick(target, event);
228
+ }
229
+ function onDragStart(event) {
230
+ if (lifecycle.active?.target === eventElement(event)) lifecycle.cancelActive(event);
231
+ }
232
+ function onWindowBlur(event) {
233
+ lifecycle.cancelActive(event);
234
+ }
235
+ function onVisibilityChange(event) {
236
+ if (lifecycle.active?.document.visibilityState === "hidden") lifecycle.cancelActive(event);
237
+ }
238
+ function onFocusIn(event) {
239
+ const current = lifecycle.active;
240
+ if (current?.source === "keyboard" && event.target !== current.target) lifecycle.cancelActive(event, false);
241
+ }
242
+ const pressProps = Object.freeze({
243
+ onClick,
244
+ onDragstart: onDragStart,
245
+ onKeydown: onKeyDown,
246
+ onKeyup: onKeyUp,
247
+ onMousedown: onMouseDown,
248
+ onMousemove: onMouseMove,
249
+ onMouseup: onMouseUp,
250
+ onPointercancel: onPointerCancel,
251
+ onPointerdown: onPointerDown,
252
+ onPointermove: onPointerMove,
253
+ onPointerup: onPointerUp,
254
+ onTouchcancel: onTouchCancel,
255
+ onTouchend: onTouchEnd,
256
+ onTouchmove: onTouchMove,
257
+ onTouchstart: onTouchStart
258
+ });
259
+ return Object.freeze({
260
+ ...pressProps,
261
+ installListeners(document, source) {
262
+ const removals = [];
263
+ const listen = (owner, type, listener, capture = true) => {
264
+ owner.addEventListener(type, listener, capture);
265
+ removals.push(() => owner.removeEventListener(type, listener, capture));
266
+ };
267
+ try {
268
+ if (source === "pointer") {
269
+ listen(document, "pointermove", onPointerMove);
270
+ listen(document, "pointerup", onPointerUp);
271
+ listen(document, "pointercancel", onPointerCancel);
272
+ } else if (source === "mouse") {
273
+ listen(document, "mousemove", onMouseMove);
274
+ listen(document, "mouseup", onMouseUp);
275
+ } else if (source === "touch") {
276
+ listen(document, "touchmove", onTouchMove);
277
+ listen(document, "touchend", onTouchEnd);
278
+ listen(document, "touchcancel", onTouchCancel);
279
+ } else {
280
+ listen(document, "keyup", onKeyUp);
281
+ listen(document, "focusin", onFocusIn);
282
+ }
283
+ if (document.defaultView) listen(document.defaultView, "blur", onWindowBlur, false);
284
+ listen(document, "visibilitychange", onVisibilityChange);
285
+ } catch (error) {
286
+ for (const remove of removals.reverse()) remove();
287
+ throw error;
288
+ }
289
+ let released = false;
290
+ return () => {
291
+ if (released) return;
292
+ released = true;
293
+ for (const remove of removals) remove();
294
+ };
295
+ }
296
+ });
297
+ }
298
+ function matches(active, source, id) {
299
+ return active?.source === source && active.id === id;
300
+ }
301
+ function touchMatches(event, active) {
302
+ return Array.from(event.changedTouches).some((touch) => touch.identifier === active.id);
303
+ }
304
+ //#endregion
305
+ //#region src/press-activation-memory.ts
306
+ /** Own short-lived tokens that associate release, cancellation, and click. */
307
+ var PressActivationMemory = class {
308
+ #pending = null;
309
+ #suppressedTarget = null;
310
+ #suppressedTimer = null;
311
+ remember(target, pointerType) {
312
+ this.#clearPending();
313
+ const timer = setTimeout(() => {
314
+ if (this.#pending?.timer === timer) this.#pending = null;
315
+ }, 1e3);
316
+ this.#pending = {
317
+ target,
318
+ pointerType,
319
+ timer
320
+ };
321
+ }
322
+ take(target) {
323
+ if (this.#pending?.target !== target) return null;
324
+ const pointerType = this.#pending.pointerType;
325
+ this.#clearPending();
326
+ return pointerType;
327
+ }
328
+ suppress(target) {
329
+ this.#suppressedTarget = target;
330
+ if (this.#suppressedTimer) clearTimeout(this.#suppressedTimer);
331
+ this.#suppressedTimer = setTimeout(() => {
332
+ this.#suppressedTarget = null;
333
+ this.#suppressedTimer = null;
334
+ }, 1e3);
335
+ }
336
+ consumeSuppressed(target) {
337
+ if (this.#suppressedTarget !== target) return false;
338
+ this.#suppressedTarget = null;
339
+ if (this.#suppressedTimer) clearTimeout(this.#suppressedTimer);
340
+ this.#suppressedTimer = null;
341
+ return true;
342
+ }
343
+ begin(target) {
344
+ this.#clearPending();
345
+ this.consumeSuppressed(target);
346
+ }
347
+ dispose() {
348
+ this.#clearPending();
349
+ if (this.#suppressedTimer) clearTimeout(this.#suppressedTimer);
350
+ this.#suppressedTimer = null;
351
+ this.#suppressedTarget = null;
352
+ }
353
+ #clearPending() {
354
+ if (!this.#pending) return;
355
+ clearTimeout(this.#pending.timer);
356
+ this.#pending = null;
357
+ }
358
+ };
359
+ //#endregion
360
+ //#region src/press-notify.ts
361
+ /** Execute every notification before surfacing one or more consumer errors. */
362
+ function notifyAll(notifications) {
363
+ const errors = [];
364
+ for (const notify of notifications) try {
365
+ notify();
366
+ } catch (error) {
367
+ errors.push(error);
368
+ }
369
+ if (errors.length === 1) throw errors[0];
370
+ if (errors.length > 1) throw new AggregateError(errors, "Press callbacks failed");
371
+ }
372
+ /** Capture one consumer failure while allowing the lifecycle to settle. */
373
+ function captureError(errors, callback) {
374
+ try {
375
+ callback();
376
+ } catch (error) {
377
+ errors.push(error);
378
+ }
379
+ }
380
+ /** Surface captured failures after every required transition has run. */
381
+ function surfaceErrors(errors) {
382
+ if (errors.length === 0) return;
383
+ notifyAll(errors.map((error) => () => {
384
+ throw error;
385
+ }));
386
+ }
387
+ //#endregion
388
+ //#region src/press-lifecycle.ts
389
+ const disposedDiagnostic = "VIZE_UI_PRESS_DISPOSED";
390
+ /** Internal press state machine shared by all native-event adapters. */
391
+ var PressLifecycle = class {
392
+ options;
393
+ installListeners;
394
+ #pressed = shallowRef(false);
395
+ #activation = new PressActivationMemory();
396
+ #active = null;
397
+ #disposed = false;
398
+ #synthetic = null;
399
+ #transitionVersion = 0;
400
+ constructor(options, installListeners) {
401
+ validatePressOptions(options);
402
+ this.options = options;
403
+ this.installListeners = installListeners;
404
+ }
405
+ get active() {
406
+ return this.#active;
407
+ }
408
+ get disposed() {
409
+ return this.#disposed;
410
+ }
411
+ start(event, target, source, pointerType, id, key, nativeKeyboard) {
412
+ this.#activation.begin(target);
413
+ let releaseListeners = () => void 0;
414
+ let restoreSelection = () => void 0;
415
+ try {
416
+ releaseListeners = this.installListeners(target.ownerDocument, source);
417
+ if (source !== "keyboard" && !readBooleanOption(this.options.allowTextSelectionOnPress, "allowTextSelectionOnPress")) restoreSelection = disableTextSelection(target);
418
+ } catch (error) {
419
+ releaseListeners();
420
+ restoreSelection();
421
+ throw error;
422
+ }
423
+ const current = {
424
+ document: target.ownerDocument,
425
+ id,
426
+ key,
427
+ nativeKeyboard,
428
+ pointerType,
429
+ releaseListeners,
430
+ restoreSelection,
431
+ source,
432
+ target,
433
+ delivered: false,
434
+ inside: true,
435
+ lastEvent: event
436
+ };
437
+ this.#active = current;
438
+ this.#transition(true, createPressEvent("pressstart", target, pointerType, event, false, source === "touch" ? id : null));
439
+ }
440
+ updatePointerBoundary(current, event) {
441
+ current.lastEvent = event;
442
+ if (readBooleanOption(this.options.isDisabled, "isDisabled")) {
443
+ this.cancelActive(event);
444
+ return;
445
+ }
446
+ const inside = isEventInside(event, current.target, current.source === "touch" ? current.id : null);
447
+ if (inside === current.inside) return;
448
+ current.inside = inside;
449
+ if (!inside && readBooleanOption(this.options.shouldCancelOnPointerExit, "shouldCancelOnPointerExit")) {
450
+ this.cancelActive(event);
451
+ return;
452
+ }
453
+ this.#transition(inside, createPressEvent(inside ? "pressstart" : "pressend", current.target, current.pointerType, event, !inside, current.source === "touch" ? current.id : null));
454
+ }
455
+ finishPointer(current, event) {
456
+ current.lastEvent = event;
457
+ const inside = current.target.isConnected && current.inside && isEventInside(event, current.target, current.source === "touch" ? current.id : null);
458
+ if (readBooleanOption(this.options.isDisabled, "isDisabled") || !inside) {
459
+ this.cancelActive(event);
460
+ return;
461
+ }
462
+ const errors = [];
463
+ captureError(errors, () => this.#emitUp(current, event));
464
+ if (this.#active === current) {
465
+ this.#activation.remember(current.target, current.pointerType);
466
+ captureError(errors, () => this.#endActive(current, event, false));
467
+ }
468
+ surfaceErrors(errors);
469
+ }
470
+ finishKeyboard(current, event) {
471
+ current.lastEvent = event;
472
+ const disabled = !current.target.isConnected || readBooleanOption(this.options.isDisabled, "isDisabled");
473
+ const errors = [];
474
+ let completed = false;
475
+ if (!disabled) captureError(errors, () => this.#emitUp(current, event));
476
+ if (this.#active === current) {
477
+ completed = !disabled;
478
+ captureError(errors, () => this.#endActive(current, event, disabled));
479
+ }
480
+ if (completed && !this.#disposed && !current.delivered) if (current.nativeKeyboard) this.#activation.remember(current.target, "keyboard");
481
+ else captureError(errors, () => this.#emitPress(current.target, "keyboard", event));
482
+ surfaceErrors(errors);
483
+ }
484
+ activateClick(target, event) {
485
+ if (readBooleanOption(this.options.isDisabled, "isDisabled")) {
486
+ event.preventDefault();
487
+ this.cancelActive(event);
488
+ this.#activation.dispose();
489
+ return;
490
+ }
491
+ if (this.#activation.consumeSuppressed(target)) {
492
+ event.preventDefault();
493
+ return;
494
+ }
495
+ const current = this.#active;
496
+ if (current?.target === target && current.source === "keyboard") {
497
+ const shouldDeliver = !current.delivered;
498
+ current.delivered = true;
499
+ if (shouldDeliver) this.#emitPress(target, "keyboard", event);
500
+ return;
501
+ }
502
+ if (current?.target === target) this.finishPointer(current, event);
503
+ const pendingPointerType = this.#activation.take(target);
504
+ if (pendingPointerType) {
505
+ this.#emitPress(target, pendingPointerType, event);
506
+ return;
507
+ }
508
+ this.#syntheticClickCycle(target, event, event.detail === 0 ? "virtual" : "mouse");
509
+ }
510
+ cancelActive(originalEvent, suppress = true) {
511
+ const current = this.#active;
512
+ if (current) {
513
+ if (suppress && current.source !== "keyboard") this.#activation.suppress(current.target);
514
+ this.#endActive(current, originalEvent ?? current.lastEvent, true);
515
+ return true;
516
+ }
517
+ const synthetic = this.#synthetic;
518
+ if (!synthetic || synthetic.canceled) return false;
519
+ synthetic.canceled = true;
520
+ this.#transition(false, createPressEvent("pressend", synthetic.target, synthetic.pointerType, originalEvent ?? synthetic.event, true));
521
+ return true;
522
+ }
523
+ toController(pressProps) {
524
+ return Object.freeze({
525
+ isPressed: shallowReadonly(this.#pressed),
526
+ pressProps,
527
+ cancel: () => {
528
+ if (this.#disposed) throw new Error(`${disposedDiagnostic}: the controller has been disposed`);
529
+ return this.cancelActive(null);
530
+ },
531
+ dispose: () => this.dispose()
532
+ });
533
+ }
534
+ dispose() {
535
+ if (this.#disposed) return;
536
+ const current = this.#active;
537
+ if (current) {
538
+ current.releaseListeners();
539
+ current.restoreSelection();
540
+ this.#active = null;
541
+ this.#pressed.value = false;
542
+ this.#transitionVersion++;
543
+ }
544
+ if (this.#synthetic) this.#synthetic.canceled = true;
545
+ this.#synthetic = null;
546
+ if (this.#pressed.value) {
547
+ this.#pressed.value = false;
548
+ this.#transitionVersion++;
549
+ }
550
+ this.#activation.dispose();
551
+ this.#disposed = true;
552
+ }
553
+ #transition(next, event) {
554
+ if (this.#pressed.value === next) return;
555
+ this.#pressed.value = next;
556
+ const version = ++this.#transitionVersion;
557
+ const phase = next ? this.options.onPressStart : this.options.onPressEnd;
558
+ notifyAll([() => phase?.(event), () => {
559
+ if (this.#transitionVersion === version) this.options.onPressChange?.(next);
560
+ }]);
561
+ }
562
+ #endActive(current, originalEvent, canceled) {
563
+ current.releaseListeners();
564
+ current.restoreSelection();
565
+ if (this.#active === current) this.#active = null;
566
+ this.#transition(false, createPressEvent("pressend", current.target, current.pointerType, originalEvent, canceled, current.source === "touch" ? current.id : null));
567
+ }
568
+ #emitUp(current, event) {
569
+ this.options.onPressUp?.(createPressEvent("pressup", current.target, current.pointerType, event, false, current.source === "touch" ? current.id : null));
570
+ }
571
+ #emitPress(target, pointerType, event) {
572
+ this.options.onPress?.(createPressEvent("press", target, pointerType, event));
573
+ }
574
+ #syntheticClickCycle(target, event, pointerType) {
575
+ const errors = [];
576
+ const cycle = {
577
+ event,
578
+ pointerType,
579
+ target,
580
+ canceled: false
581
+ };
582
+ this.#synthetic = cycle;
583
+ captureError(errors, () => this.#transition(true, createPressEvent("pressstart", target, pointerType, event)));
584
+ if (!cycle.canceled && !this.#disposed) captureError(errors, () => this.options.onPressUp?.(createPressEvent("pressup", target, pointerType, event)));
585
+ if (!cycle.canceled && !this.#disposed) captureError(errors, () => this.#transition(false, createPressEvent("pressend", target, pointerType, event)));
586
+ if (!cycle.canceled && !this.#disposed) captureError(errors, () => this.#emitPress(target, pointerType, event));
587
+ if (this.#synthetic === cycle) this.#synthetic = null;
588
+ surfaceErrors(errors);
589
+ }
590
+ };
591
+ //#endregion
592
+ //#region src/press.ts
593
+ const setupDiagnostic = "VIZE_UI_PRESS_SETUP";
594
+ /**
595
+ * Create an SSR-safe press normalizer for one host element.
596
+ *
597
+ * Spread the returned `pressProps` onto the host and call `dispose` when using
598
+ * this factory outside a Vue effect scope. No DOM global is read at setup.
599
+ */
600
+ function createPress(options = {}) {
601
+ let handlers;
602
+ const lifecycle = new PressLifecycle(options, (document, source) => handlers.installListeners(document, source));
603
+ handlers = createPressHandlers(lifecycle);
604
+ const { installListeners: _, ...pressProps } = handlers;
605
+ return lifecycle.toController(Object.freeze(pressProps));
606
+ }
607
+ /** Create a press normalizer disposed with the current Vue effect scope. */
608
+ function usePress(options = {}) {
609
+ if (!getCurrentScope()) throw new Error(`${setupDiagnostic}: use inside component setup or an active effect scope`);
610
+ const controller = createPress(options);
611
+ onScopeDispose(controller.dispose);
612
+ return controller;
613
+ }
614
+ //#endregion
615
+ export { disableTextSelection as i, usePress as n, createPressEvent as r, createPress as t };