@antadesign/anta 0.3.26 → 0.3.27

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 (69) hide show
  1. package/README.md +26 -28
  2. package/dist/anta_helpers.d.ts +4 -0
  3. package/dist/anta_helpers.js +14 -0
  4. package/dist/box-types.d.ts +1 -1
  5. package/dist/bundle.css +1 -1
  6. package/dist/bundle.js +25 -25
  7. package/dist/capture-types.d.ts +156 -0
  8. package/dist/capture-types.js +0 -0
  9. package/dist/components/Box.d.ts +15 -0
  10. package/dist/components/Box.js +3 -11
  11. package/dist/components/Capture.d.ts +39 -0
  12. package/dist/components/Capture.js +36 -0
  13. package/dist/components/capture-props.d.ts +30 -0
  14. package/dist/components/capture-props.js +44 -0
  15. package/dist/elements/a-box.d.ts +1 -1
  16. package/dist/elements/a-box.js +11 -3
  17. package/dist/elements/a-capture.css +1 -0
  18. package/dist/elements/a-capture.d.ts +10 -0
  19. package/dist/elements/a-capture.js +24 -0
  20. package/dist/elements/a-checkbox.js +4 -4
  21. package/dist/elements/a-slider.js +6 -6
  22. package/dist/elements/capture-input.d.ts +5 -0
  23. package/dist/elements/capture-input.js +609 -0
  24. package/dist/elements/index.d.ts +1 -0
  25. package/dist/elements/index.js +3 -0
  26. package/dist/general_types.d.ts +34 -0
  27. package/dist/index.d.ts +3 -0
  28. package/dist/index.js +2 -0
  29. package/dist/jsx-runtime.d.ts +2 -1
  30. package/docs/accessibility.md +24 -0
  31. package/docs/changelog.md +22 -0
  32. package/docs/colors.md +141 -0
  33. package/docs/comparison.md +463 -28
  34. package/docs/components/avatar.md +13 -17
  35. package/docs/components/banner.md +13 -27
  36. package/docs/components/box.md +226 -154
  37. package/docs/components/breadcrumbs.md +7 -6
  38. package/docs/components/button.md +48 -37
  39. package/docs/components/capture.md +345 -0
  40. package/docs/components/card.md +17 -38
  41. package/docs/components/checkbox.md +16 -39
  42. package/docs/components/dialog.md +14 -36
  43. package/docs/components/expander.md +15 -40
  44. package/docs/components/icon.md +111 -9
  45. package/docs/components/input-autocomplete.md +9 -11
  46. package/docs/components/input-date.md +33 -23
  47. package/docs/components/input-time.md +15 -23
  48. package/docs/components/input.md +27 -76
  49. package/docs/components/loader.md +7 -5
  50. package/docs/components/menu.md +73 -77
  51. package/docs/components/progress.md +10 -14
  52. package/docs/components/radio.md +17 -36
  53. package/docs/components/select-faceted.md +7 -25
  54. package/docs/components/select.md +24 -97
  55. package/docs/components/slider.md +16 -21
  56. package/docs/components/steps.md +38 -8
  57. package/docs/components/switch.md +11 -14
  58. package/docs/components/tabs.md +52 -40
  59. package/docs/components/tag.md +11 -22
  60. package/docs/components/text.md +10 -23
  61. package/docs/components/title.md +7 -8
  62. package/docs/components/toaster.md +6 -3
  63. package/docs/components/tooltip.md +13 -23
  64. package/docs/index.md +3 -1
  65. package/docs/install-config.md +24 -0
  66. package/docs/normalization.md +45 -0
  67. package/docs/packages/stickers.md +56 -0
  68. package/docs/theming.md +270 -0
  69. package/package.json +3 -1
@@ -0,0 +1,609 @@
1
+ import { finiteNumber } from "../anta_helpers";
2
+ const CAPTURE_INPUT_ATTRIBUTES = [
3
+ "wheel-capture",
4
+ "wheel-activation",
5
+ "wheel-modifier",
6
+ "wheel-delay",
7
+ "wheel-tolerance",
8
+ "wheel-reset-on-move",
9
+ "pointer-capture",
10
+ "pointer-buttons",
11
+ "pointer-threshold",
12
+ "pointer-modifier",
13
+ "pointer-include-interactive",
14
+ "pan",
15
+ "pan-pointer-types",
16
+ "pan-threshold",
17
+ "pan-directions",
18
+ "pan-inertia",
19
+ "pan-time-constant",
20
+ "pan-min-velocity"
21
+ ];
22
+ const inputs = /* @__PURE__ */ new WeakMap();
23
+ const documents = /* @__PURE__ */ new WeakMap();
24
+ const DIRECTIONS = { up: 1, down: 2, left: 4, right: 8 };
25
+ const POINTER_TYPES = { mouse: 1, pen: 2, touch: 4 };
26
+ const WHEEL_CONTROLS = 'textarea, select, input[type="number"], input[type="range"], a-menu';
27
+ const INTERACTIVE = [
28
+ 'input, textarea, select, button, summary, a[href], [contenteditable]:not([contenteditable="false"])',
29
+ ...[
30
+ "button",
31
+ "checkbox",
32
+ "combobox",
33
+ "link",
34
+ "menuitem",
35
+ "menuitemcheckbox",
36
+ "menuitemradio",
37
+ "option",
38
+ "radio",
39
+ "scrollbar",
40
+ "searchbox",
41
+ "slider",
42
+ "spinbutton",
43
+ "switch",
44
+ "tab",
45
+ "textbox",
46
+ "treeitem"
47
+ ].map((role) => `[role~="${role}"]`),
48
+ "a-input, a-button, a-slider, a-checkbox, a-switch, a-radio, a-menu, a-menu-item, a-tab"
49
+ ].join(", ");
50
+ function mask(value, values, fallback) {
51
+ if (value === null || value === "") return fallback;
52
+ if (value === "all") return Object.values(values).reduce((result, bit) => result | bit, 0);
53
+ return value.trim().split(/\s+/).reduce((result, key) => result | (values[key] ?? 0), 0);
54
+ }
55
+ function numberAttr(surface, name, fallback, min = 0) {
56
+ return Math.max(min, finiteNumber(surface.getAttribute(name)?.trim() ?? null, fallback));
57
+ }
58
+ function modifierAttr(surface, name, fallback) {
59
+ const value = surface.getAttribute(name);
60
+ return value === "any" || value === "none" || value === "alt" || value === "ctrl" || value === "meta" || value === "shift" ? value : fallback;
61
+ }
62
+ function readWheel(surface) {
63
+ if (!surface.hasAttribute("wheel-capture")) return;
64
+ const directions = mask(surface.getAttribute("wheel-capture"), DIRECTIONS, 15);
65
+ const activation = surface.getAttribute("wheel-activation");
66
+ return {
67
+ directions,
68
+ activation: activation === "hover" || activation === "focus" || activation === "settled-or-focus" ? activation : "settled",
69
+ modifier: modifierAttr(surface, "wheel-modifier", "none"),
70
+ delay: numberAttr(surface, "wheel-delay", 150),
71
+ tolerance: numberAttr(surface, "wheel-tolerance", 5),
72
+ resetOnMove: surface.hasAttribute("wheel-reset-on-move")
73
+ };
74
+ }
75
+ function readPointer(surface) {
76
+ if (!surface.hasAttribute("pointer-capture")) return;
77
+ const types = mask(surface.getAttribute("pointer-capture"), POINTER_TYPES, 7);
78
+ if (!types) return;
79
+ const buttonAttribute = surface.getAttribute("pointer-buttons");
80
+ const buttons = buttonAttribute === null ? 1 : buttonAttribute.split(/\s+/).reduce((bits, button) => {
81
+ const n = Number(button);
82
+ return Number.isInteger(n) && n >= 0 && n <= 5 ? bits | 1 << n : bits;
83
+ }, 0);
84
+ if (!buttons) return;
85
+ return {
86
+ types,
87
+ buttons,
88
+ threshold: numberAttr(surface, "pointer-threshold", 0),
89
+ modifier: modifierAttr(surface, "pointer-modifier", "any"),
90
+ interactive: surface.hasAttribute("pointer-include-interactive")
91
+ };
92
+ }
93
+ function readPan(surface) {
94
+ if (!surface.hasAttribute("pan")) return;
95
+ const axis = surface.getAttribute("pan");
96
+ if (axis !== "" && axis !== "both" && axis !== "x" && axis !== "y") return;
97
+ const types = mask(surface.getAttribute("pan-pointer-types"), POINTER_TYPES, 4);
98
+ if (!types) return;
99
+ return {
100
+ types,
101
+ axis: axis || "both",
102
+ threshold: numberAttr(surface, "pan-threshold", 3),
103
+ directions: mask(surface.getAttribute("pan-directions"), DIRECTIONS, 15),
104
+ inertia: surface.hasAttribute("pan-inertia"),
105
+ tau: numberAttr(surface, "pan-time-constant", 325, 1),
106
+ minVelocity: numberAttr(surface, "pan-min-velocity", 0.02, 1e-3)
107
+ };
108
+ }
109
+ function inputStore(surface) {
110
+ const doc = surface.ownerDocument;
111
+ let store = documents.get(doc);
112
+ if (store) return store;
113
+ const view = doc.defaultView;
114
+ store = { doc, view, states: /* @__PURE__ */ new Set(), dwell: /* @__PURE__ */ new Map(), sessions: /* @__PURE__ */ new Map(), momenta: /* @__PURE__ */ new Set(), tracking: false, listening: false };
115
+ documents.set(doc, store);
116
+ view.addEventListener("blur", onWindowBlur);
117
+ doc.addEventListener("visibilitychange", onVisibilityChange);
118
+ return store;
119
+ }
120
+ function syncCaptureInput(surface, attribute) {
121
+ if (!surface.isConnected || !surface.ownerDocument.defaultView) return;
122
+ let state = inputs.get(surface);
123
+ if (!state && !surface.hasAttribute("wheel-capture") && !surface.hasAttribute("pointer-capture") && !surface.hasAttribute("pan")) return;
124
+ const wheel = readWheel(surface);
125
+ const pointer = readPointer(surface);
126
+ const pan = readPan(surface);
127
+ if (!wheel && !pointer && !pan) {
128
+ disconnectCaptureInput(surface, "disabled");
129
+ return;
130
+ }
131
+ if (!state) {
132
+ state = { surface, store: inputStore(surface) };
133
+ inputs.set(surface, state);
134
+ state.store.states.add(state);
135
+ }
136
+ const hadWheel = !!state.wheel;
137
+ const hadPointer = !!(state.pointer || state.pan);
138
+ state.wheel = wheel;
139
+ state.pointer = pointer;
140
+ state.pan = pan;
141
+ if (hadWheel !== !!wheel) {
142
+ if (wheel) surface.addEventListener("wheel", onWheel, { passive: false });
143
+ else surface.removeEventListener("wheel", onWheel);
144
+ }
145
+ if (hadPointer !== !!(pointer || pan)) {
146
+ if (pointer || pan) {
147
+ surface.addEventListener("pointerdown", onPointerDown);
148
+ surface.addEventListener("lostpointercapture", onLostCapture);
149
+ surface.addEventListener("click", onClick, true);
150
+ surface.addEventListener("dragstart", onDragStart);
151
+ } else removePointerListeners(surface);
152
+ }
153
+ if (!wheel || attribute?.startsWith("wheel-") && attribute !== "wheel-capture") state.store.dwell.delete(surface);
154
+ if (state.session && attribute && (attribute.startsWith("pointer-") || attribute === "pan" || attribute === "pan-pointer-types" || attribute === "pan-threshold")) {
155
+ finishSession(state.session, null, "disabled");
156
+ }
157
+ if (state.momentum && (!pan?.inertia || !pan.directions)) stopMomentum(state.momentum, "disabled");
158
+ syncDwellTracking(state.store);
159
+ }
160
+ function disconnectCaptureInput(surface, reason = "disconnected") {
161
+ const state = inputs.get(surface);
162
+ if (!state) return;
163
+ inputs.delete(surface);
164
+ state.wheel = void 0;
165
+ state.pointer = void 0;
166
+ state.pan = void 0;
167
+ surface.removeEventListener("wheel", onWheel);
168
+ removePointerListeners(surface);
169
+ if (state.session) finishSession(state.session, null, reason);
170
+ if (state.momentum) stopMomentum(state.momentum, reason);
171
+ const store = state.store;
172
+ store.dwell.delete(surface);
173
+ store.states.delete(state);
174
+ syncDwellTracking(store);
175
+ if (store.states.size) return;
176
+ store.view.removeEventListener("blur", onWindowBlur);
177
+ store.doc.removeEventListener("visibilitychange", onVisibilityChange);
178
+ if (documents.get(store.doc) === store) documents.delete(store.doc);
179
+ }
180
+ function removePointerListeners(surface) {
181
+ surface.removeEventListener("pointerdown", onPointerDown);
182
+ surface.removeEventListener("lostpointercapture", onLostCapture);
183
+ surface.removeEventListener("click", onClick, true);
184
+ surface.removeEventListener("dragstart", onDragStart);
185
+ }
186
+ function needsDwell(options) {
187
+ return options?.activation === "settled" || options?.activation === "settled-or-focus";
188
+ }
189
+ function syncDwellTracking(store) {
190
+ const tracking = Array.from(store.states).some((state) => needsDwell(state.wheel));
191
+ if (tracking === store.tracking) return;
192
+ store.tracking = tracking;
193
+ if (tracking) {
194
+ store.doc.addEventListener("pointermove", onDwellMove, { passive: true, capture: true });
195
+ store.doc.addEventListener("pointerout", onDwellOut, { passive: true, capture: true });
196
+ store.doc.addEventListener("wheel", onDwellWheel, { passive: true, capture: true });
197
+ } else {
198
+ store.doc.removeEventListener("pointermove", onDwellMove, true);
199
+ store.doc.removeEventListener("pointerout", onDwellOut, true);
200
+ store.doc.removeEventListener("wheel", onDwellWheel, true);
201
+ store.dwell.clear();
202
+ }
203
+ }
204
+ function onDwellMove(event) {
205
+ const store = documents.get(this);
206
+ if (!store || event.pointerType === "touch") return;
207
+ const path = event.composedPath();
208
+ for (const surface of store.dwell.keys()) {
209
+ if (!path.includes(surface) || event.buttons && !geometry(surface, event.clientX, event.clientY).inside) {
210
+ store.dwell.delete(surface);
211
+ }
212
+ }
213
+ for (const target of path) {
214
+ const state = inputs.get(target);
215
+ const options = state?.wheel;
216
+ if (!state || !options || !needsDwell(options)) continue;
217
+ let dwell = store.dwell.get(state.surface);
218
+ if (!dwell) {
219
+ if (event.buttons) continue;
220
+ store.dwell.set(state.surface, { x: event.clientX, y: event.clientY, time: event.timeStamp });
221
+ continue;
222
+ }
223
+ if (event.clientX === dwell.x && event.clientY === dwell.y) continue;
224
+ if (event.timeStamp - dwell.time >= options.delay && !options.resetOnMove) continue;
225
+ if (Math.abs(event.clientX - dwell.x) > options.tolerance || Math.abs(event.clientY - dwell.y) > options.tolerance) {
226
+ dwell = { x: event.clientX, y: event.clientY, time: event.timeStamp };
227
+ store.dwell.set(state.surface, dwell);
228
+ }
229
+ }
230
+ }
231
+ function onDwellOut(event) {
232
+ if (event.pointerType === "touch") return;
233
+ if (event.relatedTarget === null) documents.get(this)?.dwell.clear();
234
+ }
235
+ function onDwellWheel(event) {
236
+ const store = documents.get(this);
237
+ if (!store) return;
238
+ const path = event.composedPath();
239
+ for (const surface of store.dwell.keys()) if (!path.includes(surface)) store.dwell.delete(surface);
240
+ }
241
+ function matchesModifier(event, modifier) {
242
+ if (modifier === "any") return true;
243
+ if (modifier === "none") return !event.altKey && !event.ctrlKey && !event.metaKey && !event.shiftKey;
244
+ return event[`${modifier}Key`];
245
+ }
246
+ function ignoredTarget(surface, event, controls) {
247
+ const view = surface.ownerDocument.defaultView;
248
+ for (const target of event.composedPath()) {
249
+ if (target === surface) break;
250
+ if (target instanceof view.Element && (target.hasAttribute("data-capture-ignore") || controls && target.matches(controls))) return true;
251
+ }
252
+ return surface.hasAttribute("data-capture-ignore");
253
+ }
254
+ function allows(directions, delta, horizontal) {
255
+ return delta !== 0 && !!(directions & (horizontal ? delta < 0 ? 4 : 8 : delta < 0 ? 1 : 2));
256
+ }
257
+ function geometry(surface, x, y) {
258
+ const rect = surface.getBoundingClientRect();
259
+ return {
260
+ localX: x - rect.left,
261
+ localY: y - rect.top,
262
+ boxWidth: rect.width,
263
+ boxHeight: rect.height,
264
+ inside: x >= rect.left && x <= rect.right && y >= rect.top && y <= rect.bottom,
265
+ focusWithin: surface.matches(":focus-within")
266
+ };
267
+ }
268
+ function serializeMouse(event) {
269
+ return {
270
+ type: event.type,
271
+ timeStamp: event.timeStamp,
272
+ isTrusted: event.isTrusted,
273
+ cancelable: event.cancelable,
274
+ defaultPrevented: event.defaultPrevented,
275
+ altKey: event.altKey,
276
+ ctrlKey: event.ctrlKey,
277
+ metaKey: event.metaKey,
278
+ shiftKey: event.shiftKey,
279
+ button: event.button,
280
+ buttons: event.buttons,
281
+ clientX: event.clientX,
282
+ clientY: event.clientY,
283
+ pageX: event.pageX,
284
+ pageY: event.pageY,
285
+ screenX: event.screenX,
286
+ screenY: event.screenY,
287
+ offsetX: event.offsetX,
288
+ offsetY: event.offsetY
289
+ };
290
+ }
291
+ function serializePointer(event) {
292
+ return {
293
+ ...serializeMouse(event),
294
+ pointerId: event.pointerId,
295
+ pointerType: event.pointerType,
296
+ isPrimary: event.isPrimary,
297
+ width: event.width,
298
+ height: event.height,
299
+ pressure: event.pressure,
300
+ tangentialPressure: event.tangentialPressure,
301
+ tiltX: event.tiltX,
302
+ tiltY: event.tiltY,
303
+ twist: event.twist
304
+ };
305
+ }
306
+ function emit(state, type, detail) {
307
+ state.surface.dispatchEvent(new state.store.view.CustomEvent(type, { detail }));
308
+ }
309
+ function onWheel(event) {
310
+ const state = inputs.get(this);
311
+ const options = state?.wheel;
312
+ if (!state || !options || !options.directions || event.defaultPrevented || !event.cancelable || !matchesModifier(event, options.modifier)) return;
313
+ const deltaMode = event.deltaMode;
314
+ const deltaX = event.deltaX, deltaY = event.deltaY;
315
+ const horizontal = Math.abs(deltaX) > Math.abs(deltaY);
316
+ if (!allows(options.directions, horizontal ? deltaX : deltaY, horizontal)) return;
317
+ let activationReason;
318
+ if ((options.activation === "focus" || options.activation === "settled-or-focus") && this.matches(":focus-within")) activationReason = "focus";
319
+ else if (options.activation === "hover") activationReason = "immediate";
320
+ else {
321
+ const dwell = state.store.dwell.get(this);
322
+ if (!needsDwell(options) || !dwell || event.timeStamp - dwell.time < options.delay) return;
323
+ activationReason = "settled";
324
+ }
325
+ if (ignoredTarget(this, event, WHEEL_CONTROLS)) return;
326
+ const bounds = geometry(this, event.clientX, event.clientY);
327
+ if (!bounds.inside) return;
328
+ event.preventDefault();
329
+ if (!event.defaultPrevented) return;
330
+ event.stopPropagation();
331
+ const wheelEvent = { ...serializeMouse(event), deltaMode, deltaX, deltaY, deltaZ: event.deltaZ };
332
+ if (state.momentum) stopMomentum(state.momentum, "interrupted");
333
+ emit(state, "wheelinput", { wheelEvent, ...bounds, activationReason });
334
+ }
335
+ function point(event) {
336
+ return { x: event.clientX, y: event.clientY, time: event.timeStamp };
337
+ }
338
+ function onPointerDown(event) {
339
+ const state = inputs.get(this);
340
+ if (!state) return;
341
+ state.suppressClickUntil = void 0;
342
+ if (state.momentum) stopMomentum(state.momentum, "interrupted");
343
+ if (event.defaultPrevented || !event.isPrimary || state.session || state.store.sessions.has(event.pointerId)) return;
344
+ const type = POINTER_TYPES[event.pointerType] ?? 0;
345
+ const options = state.pointer;
346
+ const pointer = !!options && !!(options.types & type) && !!(options.buttons & 1 << event.button) && matchesModifier(event, options.modifier) && !ignoredTarget(this, event, options.interactive ? "" : INTERACTIVE);
347
+ const pan = !!state.pan && !!(state.pan.types & type) && event.button === 0 && state.pan.directions !== 0 && !ignoredTarget(this, event, INTERACTIVE);
348
+ if (!pointer && !pan) return;
349
+ const snapshot = serializePointer(event);
350
+ const origin = point(snapshot);
351
+ const session = {
352
+ state,
353
+ id: event.pointerId,
354
+ start: { pointerEvent: snapshot, ...geometry(this, event.clientX, event.clientY) },
355
+ current: snapshot,
356
+ pointer,
357
+ pan,
358
+ pointerStarted: false,
359
+ panStarted: false,
360
+ captured: false,
361
+ pointerReason: options?.threshold ? "drag-threshold" : "pointer-down",
362
+ panReason: state.pan?.threshold ? "drag-threshold" : "pointer-down",
363
+ pointerLast: origin,
364
+ panLast: origin,
365
+ samples: pan ? [origin] : [],
366
+ lastMoveTime: event.timeStamp
367
+ };
368
+ state.session = session;
369
+ state.store.sessions.set(session.id, session);
370
+ syncSessionListeners(state.store);
371
+ updateSession(session, event, true);
372
+ }
373
+ function syncSessionListeners(store) {
374
+ const listening = store.sessions.size > 0;
375
+ if (listening === store.listening) return;
376
+ store.listening = listening;
377
+ if (listening) {
378
+ store.doc.addEventListener("pointermove", onSessionMove, { capture: true, passive: false });
379
+ store.doc.addEventListener("pointerup", onSessionUp, { capture: true, passive: false });
380
+ store.doc.addEventListener("pointercancel", onSessionCancel, true);
381
+ } else {
382
+ store.doc.removeEventListener("pointermove", onSessionMove, true);
383
+ store.doc.removeEventListener("pointerup", onSessionUp, true);
384
+ store.doc.removeEventListener("pointercancel", onSessionCancel, true);
385
+ }
386
+ }
387
+ function onSessionMove(event) {
388
+ const session = documents.get(this)?.sessions.get(event.pointerId);
389
+ if (session) updateSession(session, event);
390
+ }
391
+ function onSessionUp(event) {
392
+ const session = documents.get(this)?.sessions.get(event.pointerId);
393
+ if (session) finishSession(session, event);
394
+ }
395
+ function onSessionCancel(event) {
396
+ const session = documents.get(this)?.sessions.get(event.pointerId);
397
+ if (session) finishSession(session, event, "pointer-cancel");
398
+ }
399
+ function onLostCapture(event) {
400
+ const session = inputs.get(this)?.session;
401
+ if (session?.id === event.pointerId && session.captured) finishSession(session, event, "lost-capture");
402
+ }
403
+ function consumePointer(event) {
404
+ if (event.cancelable) event.preventDefault();
405
+ }
406
+ function recordSample(session, event) {
407
+ if (!session.pan) return;
408
+ const last = session.samples.at(-1);
409
+ if (!last || last.x !== event.clientX || last.y !== event.clientY) session.lastMoveTime = event.timeStamp;
410
+ session.samples.push(point(event));
411
+ while (session.samples.length > 8 || session.samples.length > 2 && event.timeStamp - session.samples[0].time > 100) session.samples.shift();
412
+ }
413
+ function velocity(session, time) {
414
+ if (time - session.lastMoveTime > 80) return { x: 0, y: 0 };
415
+ const last = session.samples.at(-1);
416
+ const first = session.samples.find((sample) => last && last.time - sample.time <= 100);
417
+ const dt = last && first ? last.time - first.time : 0;
418
+ return dt > 0 && first && last ? { x: (first.x - last.x) / dt, y: (first.y - last.y) / dt } : { x: 0, y: 0 };
419
+ }
420
+ function panDelta(options, x, y) {
421
+ return {
422
+ x: options.axis !== "y" && allows(options.directions, x, true) ? x : 0,
423
+ y: options.axis !== "x" && allows(options.directions, y, false) ? y : 0
424
+ };
425
+ }
426
+ function updateSession(session, event, down = false) {
427
+ const state = session.state;
428
+ const x = event.clientX - session.start.pointerEvent.clientX;
429
+ const y = event.clientY - session.start.pointerEvent.clientY;
430
+ const distance = Math.hypot(x, y);
431
+ const pointerStarts = session.pointer && !session.pointerStarted && !!state.pointer && distance >= state.pointer.threshold;
432
+ const panDistance = state.pan?.axis === "x" ? Math.abs(x) : state.pan?.axis === "y" ? Math.abs(y) : distance;
433
+ const panStarts = session.pan && !session.panStarted && !!state.pan && panDistance >= state.pan.threshold;
434
+ if (pointerStarts || panStarts || session.captured) {
435
+ if (!session.captured) {
436
+ try {
437
+ state.surface.setPointerCapture(session.id);
438
+ } catch {
439
+ finishSession(session, event, "lost-capture");
440
+ return;
441
+ }
442
+ session.captured = true;
443
+ }
444
+ consumePointer(event);
445
+ }
446
+ session.current = serializePointer(event);
447
+ if (down) session.start.pointerEvent = session.current;
448
+ if (!down) recordSample(session, event);
449
+ if (pointerStarts) {
450
+ session.pointerStarted = true;
451
+ emitPointer(session, "start", session.start.pointerEvent);
452
+ if (state.session !== session) return;
453
+ }
454
+ if (panStarts) {
455
+ session.panStarted = true;
456
+ emitPan(session, "start", session.start.pointerEvent);
457
+ if (state.session !== session) return;
458
+ }
459
+ if (down) return;
460
+ if (session.pointerStarted) {
461
+ emitPointer(session, "move", session.current);
462
+ if (state.session !== session) return;
463
+ }
464
+ if (session.panStarted && state.pan) {
465
+ const delta = panDelta(state.pan, session.panLast.x - event.clientX, session.panLast.y - event.clientY);
466
+ const v = velocity(session, event.timeStamp);
467
+ const speed = panDelta(state.pan, v.x, v.y);
468
+ session.panLast = point(event);
469
+ emitPan(session, "move", session.current, { deltaX: delta.x, deltaY: delta.y, velocityX: speed.x, velocityY: speed.y });
470
+ }
471
+ }
472
+ function emitPointer(session, phase, event, cancelReason) {
473
+ const current = event ?? session.current;
474
+ const start = session.start.pointerEvent;
475
+ const first = phase === "start";
476
+ const deltaX = first ? 0 : current.clientX - session.pointerLast.x;
477
+ const deltaY = first ? 0 : current.clientY - session.pointerLast.y;
478
+ session.pointerLast = point(current);
479
+ emit(session.state, "pointerinput", {
480
+ phase,
481
+ pointerEvent: event ? { ...event } : null,
482
+ start: snapshotStart(session),
483
+ ...geometry(session.state.surface, current.clientX, current.clientY),
484
+ deltaX,
485
+ deltaY,
486
+ movementX: current.clientX - start.clientX,
487
+ movementY: current.clientY - start.clientY,
488
+ activationReason: session.pointerReason,
489
+ ...cancelReason ? { cancelReason } : {}
490
+ });
491
+ }
492
+ function emitPan(session, phase, event, motion) {
493
+ const current = event ?? session.current;
494
+ emit(session.state, "paninput", {
495
+ phase,
496
+ pointerEvent: event ? { ...event } : null,
497
+ start: snapshotStart(session),
498
+ ...geometry(session.state.surface, current.clientX, current.clientY),
499
+ deltaX: 0,
500
+ deltaY: 0,
501
+ velocityX: 0,
502
+ velocityY: 0,
503
+ activationReason: session.panReason,
504
+ ...motion
505
+ });
506
+ }
507
+ function snapshotStart(session) {
508
+ return { ...session.start, pointerEvent: { ...session.start.pointerEvent } };
509
+ }
510
+ function finishSession(session, event, reason) {
511
+ const state = session.state;
512
+ if (state.session !== session) return;
513
+ state.session = void 0;
514
+ state.store.sessions.delete(session.id);
515
+ syncSessionListeners(state.store);
516
+ if (event) {
517
+ if (session.captured && !reason) consumePointer(event);
518
+ recordSample(session, event);
519
+ session.current = serializePointer(event);
520
+ }
521
+ if (state.surface.hasPointerCapture(session.id)) state.surface.releasePointerCapture(session.id);
522
+ if (session.captured) state.suppressClickUntil = state.store.view.performance.now() + 400;
523
+ if (session.pointerStarted) emitPointer(session, reason ? "cancel" : "end", event ? session.current : null, reason);
524
+ if (!session.panStarted) return;
525
+ if (reason || inputs.get(state.surface) !== state || !state.pan) {
526
+ emitPan(session, "cancel", event ? session.current : null, { cancelReason: reason ?? "disabled" });
527
+ return;
528
+ }
529
+ const finalDelta = panDelta(state.pan, session.panLast.x - session.current.clientX, session.panLast.y - session.current.clientY);
530
+ const v = velocity(session, session.current.timeStamp);
531
+ const speed = panDelta(state.pan, v.x, v.y);
532
+ emitPan(session, "release", session.current, { deltaX: finalDelta.x, deltaY: finalDelta.y, velocityX: speed.x, velocityY: speed.y });
533
+ const options = state.pan;
534
+ if (inputs.get(state.surface) !== state || !options || state.session) {
535
+ emitPan(session, "cancel", null, { cancelReason: "disabled" });
536
+ return;
537
+ }
538
+ if (options.inertia && (Math.abs(speed.x) >= options.minVelocity || Math.abs(speed.y) >= options.minVelocity)) {
539
+ const momentum = { state, session, vx: speed.x, vy: speed.y, time: state.store.view.performance.now() };
540
+ state.momentum = momentum;
541
+ state.store.momenta.add(momentum);
542
+ scheduleMomentum(state.store);
543
+ } else emitPan(session, "end", session.current);
544
+ }
545
+ function scheduleMomentum(store) {
546
+ if (store.frame !== void 0 || !store.momenta.size) return;
547
+ store.animate ??= (time) => advanceMomentum(store, time);
548
+ store.frame = store.view.requestAnimationFrame(store.animate);
549
+ }
550
+ function advanceMomentum(store, time) {
551
+ store.frame = void 0;
552
+ for (const motion of Array.from(store.momenta)) {
553
+ const options = motion.state.pan;
554
+ if (!options?.inertia || !motion.state.surface.isConnected) {
555
+ stopMomentum(motion, "disabled");
556
+ continue;
557
+ }
558
+ const dt = Math.min(50, Math.max(0, time - motion.time));
559
+ motion.time = time;
560
+ const decay = Math.exp(-dt / options.tau);
561
+ const delta = panDelta(options, motion.vx * options.tau * (1 - decay), motion.vy * options.tau * (1 - decay));
562
+ const speed = panDelta(options, motion.vx * decay, motion.vy * decay);
563
+ motion.vx = speed.x;
564
+ motion.vy = speed.y;
565
+ if (delta.x || delta.y) emitPan(motion.session, "inertia", null, { deltaX: delta.x, deltaY: delta.y, velocityX: speed.x, velocityY: speed.y });
566
+ if (!store.momenta.has(motion)) continue;
567
+ if (Math.abs(speed.x) < options.minVelocity && Math.abs(speed.y) < options.minVelocity) stopMomentum(motion);
568
+ }
569
+ scheduleMomentum(store);
570
+ }
571
+ function stopMomentum(motion, reason) {
572
+ const state = motion.state;
573
+ if (state.momentum !== motion) return;
574
+ state.momentum = void 0;
575
+ state.store.momenta.delete(motion);
576
+ if (!state.store.momenta.size && state.store.frame !== void 0) {
577
+ state.store.view.cancelAnimationFrame(state.store.frame);
578
+ state.store.frame = void 0;
579
+ }
580
+ emitPan(motion.session, reason ? "cancel" : "end", null, reason ? { cancelReason: reason } : void 0);
581
+ }
582
+ function onClick(event) {
583
+ const state = inputs.get(this);
584
+ if (!state?.suppressClickUntil || event.detail === 0 || state.store.view.performance.now() > state.suppressClickUntil) return;
585
+ state.suppressClickUntil = void 0;
586
+ event.preventDefault();
587
+ event.stopPropagation();
588
+ }
589
+ function onDragStart(event) {
590
+ if (inputs.get(this)?.session) event.preventDefault();
591
+ }
592
+ function cancelStore(store) {
593
+ store.dwell.clear();
594
+ for (const session of Array.from(store.sessions.values())) finishSession(session, null, "blur");
595
+ for (const motion of Array.from(store.momenta)) stopMomentum(motion, "blur");
596
+ }
597
+ function onWindowBlur() {
598
+ const store = documents.get(this.document);
599
+ if (store) cancelStore(store);
600
+ }
601
+ function onVisibilityChange() {
602
+ const store = documents.get(this);
603
+ if (store && this.hidden) cancelStore(store);
604
+ }
605
+ export {
606
+ CAPTURE_INPUT_ATTRIBUTES,
607
+ disconnectCaptureInput,
608
+ syncCaptureInput
609
+ };
@@ -18,6 +18,7 @@ export { AProgressElement, register_a_progress } from './a-progress';
18
18
  export { ALoaderElement, register_a_loader } from './a-loader';
19
19
  export { ATextElement, register_a_text } from './a-text';
20
20
  export { ABoxElement, register_a_box } from './a-box';
21
+ export { ACaptureElement, register_a_capture } from './a-capture';
21
22
  export { AIconElement, register_a_icon } from './a-icon';
22
23
  export { AButtonElement, register_a_button } from './a-button';
23
24
  export { ACopyElement, register_a_copy } from './a-copy';
@@ -3,6 +3,7 @@ import { AProgressElement, register_a_progress } from "./a-progress";
3
3
  import { ALoaderElement, register_a_loader } from "./a-loader";
4
4
  import { ATextElement, register_a_text } from "./a-text";
5
5
  import { ABoxElement, register_a_box } from "./a-box";
6
+ import { ACaptureElement, register_a_capture } from "./a-capture";
6
7
  import { AIconElement, register_a_icon } from "./a-icon";
7
8
  import { AButtonElement, register_a_button } from "./a-button";
8
9
  import { ACopyElement, register_a_copy } from "./a-copy";
@@ -36,6 +37,7 @@ export {
36
37
  ABoxElement,
37
38
  AButtonElement,
38
39
  ACalendarElement,
40
+ ACaptureElement,
39
41
  ACardElement,
40
42
  ACheckboxElement,
41
43
  ACopyElement,
@@ -66,6 +68,7 @@ export {
66
68
  register_a_box,
67
69
  register_a_button,
68
70
  register_a_calendar,
71
+ register_a_capture,
69
72
  register_a_card,
70
73
  register_a_checkbox,
71
74
  register_a_copy,
@@ -1,5 +1,6 @@
1
1
  import type { IconShape } from './elements/a-icon.shapes';
2
2
  import type { BoxContextChange, BoxDisplay, BoxMeasurementChange } from './box-types';
3
+ import type { CaptureInputModifier, CapturePanInput, CapturePointerInput, CaptureWheelActivation, CaptureWheelInput } from './capture-types';
3
4
  /** Common props for JSX component wrappers. */
4
5
  export interface BaseProps {
5
6
  /** CSS class on the component's root element (merged with the component's own
@@ -268,6 +269,39 @@ export interface ATextAttributes extends BaseAttributes {
268
269
  /** ARIA disclosure state, mirrors the JSX wrapper's `expanded` flag. */
269
270
  'aria-expanded'?: boolean | 'true' | 'false';
270
271
  }
272
+ /** Attributes for the opt-in light-DOM capture surface. */
273
+ export interface ACaptureAttributes extends BaseAttributes {
274
+ /** Space-separated accepted wheel directions. Bare means all; `none` preserves settling while declining input. */
275
+ 'wheel-capture'?: string;
276
+ 'wheel-activation'?: CaptureWheelActivation;
277
+ 'wheel-modifier'?: CaptureInputModifier;
278
+ 'wheel-delay'?: number | string;
279
+ 'wheel-tolerance'?: number | string;
280
+ 'wheel-reset-on-move'?: boolean | '';
281
+ /** Space-separated pointer types. Bare means mouse, pen, and touch. */
282
+ 'pointer-capture'?: string;
283
+ 'pointer-buttons'?: string;
284
+ 'pointer-threshold'?: number | string;
285
+ 'pointer-modifier'?: CaptureInputModifier;
286
+ 'pointer-include-interactive'?: boolean | '';
287
+ /** Enable custom panning on the selected axes. */
288
+ pan?: '' | 'x' | 'y' | 'both';
289
+ 'pan-pointer-types'?: string;
290
+ 'pan-threshold'?: number | string;
291
+ 'pan-directions'?: string;
292
+ 'pan-inertia'?: boolean | '';
293
+ 'pan-time-constant'?: number | string;
294
+ 'pan-min-velocity'?: number | string;
295
+ onwheelinput?: (event: CustomEvent<CaptureWheelInput> | {
296
+ nativeEvent: CustomEvent<CaptureWheelInput>;
297
+ }) => void;
298
+ onpointerinput?: (event: CustomEvent<CapturePointerInput> | {
299
+ nativeEvent: CustomEvent<CapturePointerInput>;
300
+ }) => void;
301
+ onpaninput?: (event: CustomEvent<CapturePanInput> | {
302
+ nativeEvent: CustomEvent<CapturePanInput>;
303
+ }) => void;
304
+ }
271
305
  /** Attributes for the light-DOM `<a-box>` observing container. For the JSX
272
306
  * wrapper with cross-renderer event unwrapping, use `Box` from
273
307
  * `@antadesign/anta`. */