@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.
- package/README.md +26 -28
- package/dist/anta_helpers.d.ts +4 -0
- package/dist/anta_helpers.js +14 -0
- package/dist/box-types.d.ts +1 -1
- package/dist/bundle.css +1 -1
- package/dist/bundle.js +25 -25
- package/dist/capture-types.d.ts +156 -0
- package/dist/capture-types.js +0 -0
- package/dist/components/Box.d.ts +15 -0
- package/dist/components/Box.js +3 -11
- package/dist/components/Capture.d.ts +39 -0
- package/dist/components/Capture.js +36 -0
- package/dist/components/capture-props.d.ts +30 -0
- package/dist/components/capture-props.js +44 -0
- package/dist/elements/a-box.d.ts +1 -1
- package/dist/elements/a-box.js +11 -3
- package/dist/elements/a-capture.css +1 -0
- package/dist/elements/a-capture.d.ts +10 -0
- package/dist/elements/a-capture.js +24 -0
- package/dist/elements/a-checkbox.js +4 -4
- package/dist/elements/a-slider.js +6 -6
- package/dist/elements/capture-input.d.ts +5 -0
- package/dist/elements/capture-input.js +609 -0
- package/dist/elements/index.d.ts +1 -0
- package/dist/elements/index.js +3 -0
- package/dist/general_types.d.ts +34 -0
- package/dist/index.d.ts +3 -0
- package/dist/index.js +2 -0
- package/dist/jsx-runtime.d.ts +2 -1
- package/docs/accessibility.md +24 -0
- package/docs/changelog.md +22 -0
- package/docs/colors.md +141 -0
- package/docs/comparison.md +463 -28
- package/docs/components/avatar.md +13 -17
- package/docs/components/banner.md +13 -27
- package/docs/components/box.md +226 -154
- package/docs/components/breadcrumbs.md +7 -6
- package/docs/components/button.md +48 -37
- package/docs/components/capture.md +345 -0
- package/docs/components/card.md +17 -38
- package/docs/components/checkbox.md +16 -39
- package/docs/components/dialog.md +14 -36
- package/docs/components/expander.md +15 -40
- package/docs/components/icon.md +111 -9
- package/docs/components/input-autocomplete.md +9 -11
- package/docs/components/input-date.md +33 -23
- package/docs/components/input-time.md +15 -23
- package/docs/components/input.md +27 -76
- package/docs/components/loader.md +7 -5
- package/docs/components/menu.md +73 -77
- package/docs/components/progress.md +10 -14
- package/docs/components/radio.md +17 -36
- package/docs/components/select-faceted.md +7 -25
- package/docs/components/select.md +24 -97
- package/docs/components/slider.md +16 -21
- package/docs/components/steps.md +38 -8
- package/docs/components/switch.md +11 -14
- package/docs/components/tabs.md +52 -40
- package/docs/components/tag.md +11 -22
- package/docs/components/text.md +10 -23
- package/docs/components/title.md +7 -8
- package/docs/components/toaster.md +6 -3
- package/docs/components/tooltip.md +13 -23
- package/docs/index.md +3 -1
- package/docs/install-config.md +24 -0
- package/docs/normalization.md +45 -0
- package/docs/packages/stickers.md +56 -0
- package/docs/theming.md +270 -0
- 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
|
+
};
|
package/dist/elements/index.d.ts
CHANGED
|
@@ -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';
|
package/dist/elements/index.js
CHANGED
|
@@ -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,
|
package/dist/general_types.d.ts
CHANGED
|
@@ -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`. */
|