@jsenv/dom 0.6.1 → 0.7.0
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/dist/jsenv_dom.js +259 -314
- package/package.json +2 -4
- package/index.js +0 -124
- package/src/attr/add_attribute_effect.js +0 -93
- package/src/attr/attributes.js +0 -32
- package/src/color/color_constrast.js +0 -69
- package/src/color/color_parsing.js +0 -319
- package/src/color/color_scheme.js +0 -28
- package/src/color/pick_light_or_dark.js +0 -34
- package/src/color/resolve_css_color.js +0 -60
- package/src/demos/3_columns_resize_demo.html +0 -84
- package/src/demos/3_rows_resize_demo.html +0 -89
- package/src/demos/aside_and_main_demo.html +0 -93
- package/src/demos/coordinates_demo.html +0 -450
- package/src/demos/document_autoscroll_demo.html +0 -517
- package/src/demos/drag_gesture_constraints_demo.html +0 -701
- package/src/demos/drag_gesture_demo.html +0 -1047
- package/src/demos/drag_gesture_element_to_impact_demo.html +0 -445
- package/src/demos/drag_reference_element_demo.html +0 -480
- package/src/demos/flex_details_set_demo.html +0 -302
- package/src/demos/flex_details_set_demo_2.html +0 -315
- package/src/demos/visible_rect_demo.html +0 -525
- package/src/element_signature.js +0 -100
- package/src/interaction/drag/constraint_feedback_line.js +0 -92
- package/src/interaction/drag/drag_constraint.js +0 -659
- package/src/interaction/drag/drag_debug_markers.js +0 -635
- package/src/interaction/drag/drag_element_positioner.js +0 -382
- package/src/interaction/drag/drag_gesture.js +0 -566
- package/src/interaction/drag/drag_resize_demo.html +0 -571
- package/src/interaction/drag/drag_to_move.js +0 -301
- package/src/interaction/drag/drag_to_resize_gesture.js +0 -68
- package/src/interaction/drag/drop_target_detection.js +0 -148
- package/src/interaction/drag/sticky_frontiers.js +0 -160
- package/src/interaction/event_marker.js +0 -14
- package/src/interaction/focus/active_element.js +0 -33
- package/src/interaction/focus/arrow_navigation.js +0 -599
- package/src/interaction/focus/element_is_focusable.js +0 -57
- package/src/interaction/focus/element_visibility.js +0 -111
- package/src/interaction/focus/find_focusable.js +0 -21
- package/src/interaction/focus/focus_group.js +0 -91
- package/src/interaction/focus/focus_group_registry.js +0 -12
- package/src/interaction/focus/focus_nav.js +0 -12
- package/src/interaction/focus/focus_nav_event_marker.js +0 -14
- package/src/interaction/focus/focus_trap.js +0 -105
- package/src/interaction/focus/tab_navigation.js +0 -128
- package/src/interaction/focus/tests/focus_group_skip_tab_test.html +0 -206
- package/src/interaction/focus/tests/tree_focus_test.html +0 -304
- package/src/interaction/focus/tests/tree_focus_test.jsx +0 -261
- package/src/interaction/focus/tests/tree_focus_test_preact.html +0 -13
- package/src/interaction/isolate_interactions.js +0 -161
- package/src/interaction/keyboard.js +0 -26
- package/src/interaction/scroll/capture_scroll.js +0 -47
- package/src/interaction/scroll/is_scrollable.js +0 -159
- package/src/interaction/scroll/scroll_container.js +0 -110
- package/src/interaction/scroll/scroll_trap.js +0 -44
- package/src/interaction/scroll/scrollbar_size.js +0 -20
- package/src/interaction/scroll/wheel_through.js +0 -138
- package/src/iterable_weak_set.js +0 -66
- package/src/position/dom_coords.js +0 -340
- package/src/position/offset_parent.js +0 -15
- package/src/position/position_fixed.js +0 -15
- package/src/position/position_sticky.js +0 -213
- package/src/position/sticky_rect.js +0 -79
- package/src/position/visible_rect.js +0 -486
- package/src/pub_sub.js +0 -31
- package/src/size/can_take_size.js +0 -11
- package/src/size/details_content_full_height.js +0 -63
- package/src/size/flex_details_set.js +0 -974
- package/src/size/get_available_height.js +0 -22
- package/src/size/get_available_width.js +0 -22
- package/src/size/get_border_sizes.js +0 -14
- package/src/size/get_height.js +0 -4
- package/src/size/get_inner_height.js +0 -15
- package/src/size/get_inner_width.js +0 -15
- package/src/size/get_margin_sizes.js +0 -10
- package/src/size/get_max_height.js +0 -57
- package/src/size/get_max_width.js +0 -47
- package/src/size/get_min_height.js +0 -14
- package/src/size/get_min_width.js +0 -14
- package/src/size/get_padding_sizes.js +0 -10
- package/src/size/get_width.js +0 -4
- package/src/size/hooks/use_available_height.js +0 -27
- package/src/size/hooks/use_available_width.js +0 -27
- package/src/size/hooks/use_max_height.js +0 -10
- package/src/size/hooks/use_max_width.js +0 -10
- package/src/size/hooks/use_resize_status.js +0 -62
- package/src/size/resize.js +0 -695
- package/src/size/resolve_css_size.js +0 -32
- package/src/style/dom_styles.js +0 -97
- package/src/style/style_composition.js +0 -121
- package/src/style/style_controller.js +0 -345
- package/src/style/style_default.js +0 -153
- package/src/style/style_default_demo.html +0 -128
- package/src/style/style_parsing.js +0 -375
- package/src/transition/demos/animation_resumption_test.xhtml +0 -500
- package/src/transition/demos/height_toggle_test.xhtml +0 -515
- package/src/transition/dom_transition.js +0 -254
- package/src/transition/easing.js +0 -48
- package/src/transition/group_transition.js +0 -261
- package/src/transition/transform_style_parser.js +0 -32
- package/src/transition/transition_playback.js +0 -366
- package/src/transition/transition_timeline.js +0 -79
- package/src/traversal.js +0 -247
- package/src/ui_transition/demos/content_states_transition_demo.html +0 -628
- package/src/ui_transition/demos/smooth_height_transition_demo.html +0 -149
- package/src/ui_transition/demos/transition_testing.html +0 -354
- package/src/ui_transition/ui_transition.js +0 -1470
- package/src/utils.js +0 -69
- package/src/value_effect.js +0 -35
|
@@ -1,566 +0,0 @@
|
|
|
1
|
-
/**
|
|
2
|
-
* Drag Gesture System
|
|
3
|
-
*
|
|
4
|
-
* TODO: rename moveX/moveY en juste x/y
|
|
5
|
-
* puisque move c'est perturbant sachant que c'est drag + scroll
|
|
6
|
-
* et que drag c'est juste la partie mouvement de la souris
|
|
7
|
-
*
|
|
8
|
-
* donc juste x/y ca seras surement mieux
|
|
9
|
-
*
|
|
10
|
-
*/
|
|
11
|
-
|
|
12
|
-
import { createPubSub } from "../../pub_sub.js";
|
|
13
|
-
import { findFocusable } from "../focus/find_focusable.js";
|
|
14
|
-
import { isolateInteractions } from "../isolate_interactions.js";
|
|
15
|
-
|
|
16
|
-
export const createDragGestureController = (options = {}) => {
|
|
17
|
-
const {
|
|
18
|
-
name,
|
|
19
|
-
onGrab,
|
|
20
|
-
onDragStart,
|
|
21
|
-
onDrag,
|
|
22
|
-
onRelease,
|
|
23
|
-
threshold = 5,
|
|
24
|
-
direction: defaultDirection = { x: true, y: true },
|
|
25
|
-
documentInteractions = "auto",
|
|
26
|
-
backdrop = true,
|
|
27
|
-
backdropZIndex = 999999,
|
|
28
|
-
} = options;
|
|
29
|
-
|
|
30
|
-
const dragGestureController = {
|
|
31
|
-
grab: null,
|
|
32
|
-
gravViaPointer: null,
|
|
33
|
-
};
|
|
34
|
-
|
|
35
|
-
const grab = ({
|
|
36
|
-
element,
|
|
37
|
-
direction = defaultDirection,
|
|
38
|
-
event = new CustomEvent("programmatic"),
|
|
39
|
-
grabX = 0,
|
|
40
|
-
grabY = 0,
|
|
41
|
-
cursor = "grabbing",
|
|
42
|
-
scrollContainer = document.documentElement,
|
|
43
|
-
layoutScrollableLeft: scrollableLeftAtGrab = 0,
|
|
44
|
-
layoutScrollableTop: scrollableTopAtGrab = 0,
|
|
45
|
-
} = {}) => {
|
|
46
|
-
if (!element) {
|
|
47
|
-
throw new Error("element is required");
|
|
48
|
-
}
|
|
49
|
-
if (!direction.x && !direction.y) {
|
|
50
|
-
return null;
|
|
51
|
-
}
|
|
52
|
-
|
|
53
|
-
const [publishBeforeDrag, addBeforeDragCallback] = createPubSub();
|
|
54
|
-
const [publishDrag, addDragCallback] = createPubSub();
|
|
55
|
-
const [publishRelease, addReleaseCallback] = createPubSub();
|
|
56
|
-
if (onDrag) {
|
|
57
|
-
addDragCallback(onDrag);
|
|
58
|
-
}
|
|
59
|
-
if (onRelease) {
|
|
60
|
-
addReleaseCallback(onRelease);
|
|
61
|
-
}
|
|
62
|
-
|
|
63
|
-
const scrollLeftAtGrab = scrollContainer.scrollLeft;
|
|
64
|
-
const scrollTopAtGrab = scrollContainer.scrollTop;
|
|
65
|
-
const leftAtGrab = scrollLeftAtGrab + scrollableLeftAtGrab;
|
|
66
|
-
const topAtGrab = scrollTopAtGrab + scrollableTopAtGrab;
|
|
67
|
-
const createLayout = (x, y) => {
|
|
68
|
-
const { scrollLeft, scrollTop } = scrollContainer;
|
|
69
|
-
const left = scrollableLeftAtGrab + x;
|
|
70
|
-
const top = scrollableTopAtGrab + y;
|
|
71
|
-
const scrollableLeft = left - scrollLeft;
|
|
72
|
-
const scrollableTop = top - scrollTop;
|
|
73
|
-
const layoutProps = {
|
|
74
|
-
// Raw input coordinates (dragX - grabX + scrollContainer.scrollLeft)
|
|
75
|
-
x,
|
|
76
|
-
y,
|
|
77
|
-
// container scrolls when layout is created
|
|
78
|
-
scrollLeft,
|
|
79
|
-
scrollTop,
|
|
80
|
-
// Position relative to container excluding scrolls
|
|
81
|
-
scrollableLeft,
|
|
82
|
-
scrollableTop,
|
|
83
|
-
// Position relative to container including scrolls
|
|
84
|
-
left,
|
|
85
|
-
top,
|
|
86
|
-
// Delta since grab (number representing how much we dragged)
|
|
87
|
-
xDelta: left - leftAtGrab,
|
|
88
|
-
yDelta: top - topAtGrab,
|
|
89
|
-
};
|
|
90
|
-
return layoutProps;
|
|
91
|
-
};
|
|
92
|
-
|
|
93
|
-
const grabLayout = createLayout(
|
|
94
|
-
grabX + scrollContainer.scrollLeft,
|
|
95
|
-
grabY + scrollContainer.scrollTop,
|
|
96
|
-
);
|
|
97
|
-
const gestureInfo = {
|
|
98
|
-
name,
|
|
99
|
-
direction,
|
|
100
|
-
started: !threshold,
|
|
101
|
-
status: "grabbed",
|
|
102
|
-
|
|
103
|
-
element,
|
|
104
|
-
scrollContainer,
|
|
105
|
-
grabX, // x grab coordinate (excluding scroll)
|
|
106
|
-
grabY, // y grab coordinate (excluding scroll)
|
|
107
|
-
grabLayout,
|
|
108
|
-
leftAtGrab,
|
|
109
|
-
topAtGrab,
|
|
110
|
-
|
|
111
|
-
dragX: grabX, // coordinate of the last drag (excluding scroll of the scrollContainer)
|
|
112
|
-
dragY: grabY, // coordinate of the last drag (excluding scroll of the scrollContainer)
|
|
113
|
-
layout: grabLayout,
|
|
114
|
-
|
|
115
|
-
isGoingUp: undefined,
|
|
116
|
-
isGoingDown: undefined,
|
|
117
|
-
isGoingLeft: undefined,
|
|
118
|
-
isGoingRight: undefined,
|
|
119
|
-
|
|
120
|
-
// metadata about interaction sources
|
|
121
|
-
grabEvent: event,
|
|
122
|
-
dragEvent: null,
|
|
123
|
-
releaseEvent: null,
|
|
124
|
-
};
|
|
125
|
-
definePropertyAsReadOnly(gestureInfo, "name");
|
|
126
|
-
definePropertyAsReadOnly(gestureInfo, "direction");
|
|
127
|
-
definePropertyAsReadOnly(gestureInfo, "scrollContainer");
|
|
128
|
-
definePropertyAsReadOnly(gestureInfo, "grabX");
|
|
129
|
-
definePropertyAsReadOnly(gestureInfo, "grabY");
|
|
130
|
-
definePropertyAsReadOnly(gestureInfo, "grabLayout");
|
|
131
|
-
definePropertyAsReadOnly(gestureInfo, "leftAtGrab");
|
|
132
|
-
definePropertyAsReadOnly(gestureInfo, "topAtGrab");
|
|
133
|
-
definePropertyAsReadOnly(gestureInfo, "grabEvent");
|
|
134
|
-
|
|
135
|
-
document_interactions: {
|
|
136
|
-
if (documentInteractions === "manual") {
|
|
137
|
-
break document_interactions;
|
|
138
|
-
}
|
|
139
|
-
/*
|
|
140
|
-
GOAL: Take control of document-level interactions during drag gestures
|
|
141
|
-
|
|
142
|
-
WHY: During drag operations, we need to prevent conflicting user interactions that would:
|
|
143
|
-
1. Interfere with the drag gesture (competing pointer events, focus changes)
|
|
144
|
-
2. Break the visual feedback (inconsistent cursors, hover states)
|
|
145
|
-
3. Cause unwanted scrolling (keyboard shortcuts, wheel events in restricted directions)
|
|
146
|
-
4. Create accessibility issues (focus jumping, screen reader confusion)
|
|
147
|
-
|
|
148
|
-
STRATEGY: Create a controlled interaction environment by:
|
|
149
|
-
1. VISUAL CONTROL: Use a backdrop to unify cursor appearance and block pointer events
|
|
150
|
-
2. INTERACTION ISOLATION: Make non-dragged elements inert to prevent interference
|
|
151
|
-
3. FOCUS MANAGEMENT: Control focus location and prevent focus changes during drag
|
|
152
|
-
4. SELECTIVE SCROLLING: Allow scrolling only in directions supported by the drag gesture
|
|
153
|
-
|
|
154
|
-
IMPLEMENTATION:
|
|
155
|
-
*/
|
|
156
|
-
|
|
157
|
-
// 1. INTERACTION ISOLATION: Make everything except the dragged element inert
|
|
158
|
-
// This prevents keyboard events, pointer interactions, and screen reader navigation
|
|
159
|
-
// on non-relevant elements during the drag operation
|
|
160
|
-
const cleanupInert = isolateInteractions([
|
|
161
|
-
element,
|
|
162
|
-
...Array.from(document.querySelectorAll("[data-droppable]")),
|
|
163
|
-
]);
|
|
164
|
-
addReleaseCallback(() => {
|
|
165
|
-
cleanupInert();
|
|
166
|
-
});
|
|
167
|
-
|
|
168
|
-
// 2. VISUAL CONTROL: Backdrop for consistent cursor and pointer event blocking
|
|
169
|
-
if (backdrop) {
|
|
170
|
-
const backdropElement = document.createElement("div");
|
|
171
|
-
backdropElement.className = "navi_drag_gesture_backdrop";
|
|
172
|
-
backdropElement.ariaHidden = "true";
|
|
173
|
-
backdropElement.setAttribute("data-backdrop", "");
|
|
174
|
-
backdropElement.style.zIndex = backdropZIndex;
|
|
175
|
-
backdropElement.style.cursor = cursor;
|
|
176
|
-
|
|
177
|
-
// Handle wheel events on backdrop for directionally-constrained drag gestures
|
|
178
|
-
// (e.g., table column resize should only allow horizontal scrolling)
|
|
179
|
-
if (!direction.x || !direction.y) {
|
|
180
|
-
backdropElement.onwheel = (e) => {
|
|
181
|
-
e.preventDefault();
|
|
182
|
-
const scrollX = direction.x ? e.deltaX : 0;
|
|
183
|
-
const scrollY = direction.y ? e.deltaY : 0;
|
|
184
|
-
scrollContainer.scrollBy({
|
|
185
|
-
left: scrollX,
|
|
186
|
-
top: scrollY,
|
|
187
|
-
behavior: "auto",
|
|
188
|
-
});
|
|
189
|
-
};
|
|
190
|
-
}
|
|
191
|
-
document.body.appendChild(backdropElement);
|
|
192
|
-
addReleaseCallback(() => {
|
|
193
|
-
backdropElement.remove();
|
|
194
|
-
});
|
|
195
|
-
}
|
|
196
|
-
|
|
197
|
-
// 3. FOCUS MANAGEMENT: Control and stabilize focus during drag
|
|
198
|
-
const { activeElement } = document;
|
|
199
|
-
const focusableElement = findFocusable(element);
|
|
200
|
-
// Focus the dragged element (or document.body as fallback) to establish clear focus context
|
|
201
|
-
// This also ensure any keydown event listened by the currently focused element
|
|
202
|
-
// won't be available during drag
|
|
203
|
-
const elementToFocus = focusableElement || document.body;
|
|
204
|
-
elementToFocus.focus({
|
|
205
|
-
preventScroll: true,
|
|
206
|
-
});
|
|
207
|
-
addReleaseCallback(() => {
|
|
208
|
-
// Restore original focus on release
|
|
209
|
-
activeElement.focus({
|
|
210
|
-
preventScroll: true,
|
|
211
|
-
});
|
|
212
|
-
});
|
|
213
|
-
// Prevent Tab navigation entirely (focus should stay stable)
|
|
214
|
-
const onkeydown = (e) => {
|
|
215
|
-
if (e.key === "Tab") {
|
|
216
|
-
e.preventDefault();
|
|
217
|
-
return;
|
|
218
|
-
}
|
|
219
|
-
};
|
|
220
|
-
document.addEventListener("keydown", onkeydown);
|
|
221
|
-
addReleaseCallback(() => {
|
|
222
|
-
document.removeEventListener("keydown", onkeydown);
|
|
223
|
-
});
|
|
224
|
-
|
|
225
|
-
// 4. SELECTIVE SCROLLING: Allow keyboard scrolling only in supported directions
|
|
226
|
-
scroll_via_keyboard: {
|
|
227
|
-
const onDocumentKeydown = (keyboardEvent) => {
|
|
228
|
-
// Vertical scrolling keys - prevent if vertical movement not supported
|
|
229
|
-
if (
|
|
230
|
-
keyboardEvent.key === "ArrowUp" ||
|
|
231
|
-
keyboardEvent.key === "ArrowDown" ||
|
|
232
|
-
keyboardEvent.key === " " ||
|
|
233
|
-
keyboardEvent.key === "PageUp" ||
|
|
234
|
-
keyboardEvent.key === "PageDown" ||
|
|
235
|
-
keyboardEvent.key === "Home" ||
|
|
236
|
-
keyboardEvent.key === "End"
|
|
237
|
-
) {
|
|
238
|
-
if (!direction.y) {
|
|
239
|
-
keyboardEvent.preventDefault();
|
|
240
|
-
}
|
|
241
|
-
return;
|
|
242
|
-
}
|
|
243
|
-
// Horizontal scrolling keys - prevent if horizontal movement not supported
|
|
244
|
-
if (
|
|
245
|
-
keyboardEvent.key === "ArrowLeft" ||
|
|
246
|
-
keyboardEvent.key === "ArrowRight"
|
|
247
|
-
) {
|
|
248
|
-
if (!direction.x) {
|
|
249
|
-
keyboardEvent.preventDefault();
|
|
250
|
-
}
|
|
251
|
-
return;
|
|
252
|
-
}
|
|
253
|
-
};
|
|
254
|
-
document.addEventListener("keydown", onDocumentKeydown);
|
|
255
|
-
addReleaseCallback(() => {
|
|
256
|
-
document.removeEventListener("keydown", onDocumentKeydown);
|
|
257
|
-
});
|
|
258
|
-
}
|
|
259
|
-
}
|
|
260
|
-
|
|
261
|
-
// Set up scroll event handling to adjust drag position when scrolling occurs
|
|
262
|
-
drag_on_scroll: {
|
|
263
|
-
let isHandlingScroll = false;
|
|
264
|
-
const handleScroll = (scrollEvent) => {
|
|
265
|
-
if (isHandlingScroll) {
|
|
266
|
-
return;
|
|
267
|
-
}
|
|
268
|
-
isHandlingScroll = true;
|
|
269
|
-
drag(gestureInfo.dragX, gestureInfo.dragY, { event: scrollEvent });
|
|
270
|
-
isHandlingScroll = false;
|
|
271
|
-
};
|
|
272
|
-
const scrollEventReceiver =
|
|
273
|
-
scrollContainer === document.documentElement
|
|
274
|
-
? document
|
|
275
|
-
: scrollContainer;
|
|
276
|
-
scrollEventReceiver.addEventListener("scroll", handleScroll, {
|
|
277
|
-
passive: true,
|
|
278
|
-
});
|
|
279
|
-
addReleaseCallback(() => {
|
|
280
|
-
scrollEventReceiver.removeEventListener("scroll", handleScroll, {
|
|
281
|
-
passive: true,
|
|
282
|
-
});
|
|
283
|
-
});
|
|
284
|
-
}
|
|
285
|
-
|
|
286
|
-
const determineDragData = ({
|
|
287
|
-
dragX,
|
|
288
|
-
dragY,
|
|
289
|
-
dragEvent,
|
|
290
|
-
isRelease = false,
|
|
291
|
-
}) => {
|
|
292
|
-
// === ÉTAT INITIAL (au moment du grab) ===
|
|
293
|
-
const { grabX, grabY, grabLayout } = gestureInfo;
|
|
294
|
-
// === CE QUI EST DEMANDÉ (où on veut aller) ===
|
|
295
|
-
// Calcul de la direction basé sur le mouvement précédent
|
|
296
|
-
// (ne tient pas compte du mouvement final une fois les contraintes appliquées)
|
|
297
|
-
// (ici on veut connaitre l'intention)
|
|
298
|
-
// on va utiliser cela pour savoir vers où on scroll si nécéssaire par ex
|
|
299
|
-
const currentDragX = gestureInfo.dragX;
|
|
300
|
-
const currentDragY = gestureInfo.dragY;
|
|
301
|
-
const isGoingLeft = dragX < currentDragX;
|
|
302
|
-
const isGoingRight = dragX > currentDragX;
|
|
303
|
-
const isGoingUp = dragY < currentDragY;
|
|
304
|
-
const isGoingDown = dragY > currentDragY;
|
|
305
|
-
|
|
306
|
-
const layoutXRequested = direction.x
|
|
307
|
-
? scrollContainer.scrollLeft + (dragX - grabX)
|
|
308
|
-
: grabLayout.scrollLeft;
|
|
309
|
-
const layoutYRequested = direction.y
|
|
310
|
-
? scrollContainer.scrollTop + (dragY - grabY)
|
|
311
|
-
: grabLayout.scrollTop;
|
|
312
|
-
const layoutRequested = createLayout(layoutXRequested, layoutYRequested);
|
|
313
|
-
const currentLayout = gestureInfo.layout;
|
|
314
|
-
let layout;
|
|
315
|
-
if (
|
|
316
|
-
layoutRequested.x === currentLayout.x &&
|
|
317
|
-
layoutRequested.y === currentLayout.y
|
|
318
|
-
) {
|
|
319
|
-
layout = currentLayout;
|
|
320
|
-
} else {
|
|
321
|
-
// === APPLICATION DES CONTRAINTES ===
|
|
322
|
-
let layoutConstrained = layoutRequested;
|
|
323
|
-
const limitLayout = (left, top) => {
|
|
324
|
-
layoutConstrained = createLayout(
|
|
325
|
-
left === undefined
|
|
326
|
-
? layoutConstrained.x
|
|
327
|
-
: left - scrollableLeftAtGrab,
|
|
328
|
-
top === undefined ? layoutConstrained.y : top - scrollableTopAtGrab,
|
|
329
|
-
);
|
|
330
|
-
};
|
|
331
|
-
|
|
332
|
-
publishBeforeDrag(layoutRequested, currentLayout, limitLayout, {
|
|
333
|
-
dragEvent,
|
|
334
|
-
isRelease,
|
|
335
|
-
});
|
|
336
|
-
// === ÉTAT FINAL ===
|
|
337
|
-
layout = layoutConstrained;
|
|
338
|
-
}
|
|
339
|
-
|
|
340
|
-
const dragData = {
|
|
341
|
-
dragX,
|
|
342
|
-
dragY,
|
|
343
|
-
layout,
|
|
344
|
-
|
|
345
|
-
isGoingLeft,
|
|
346
|
-
isGoingRight,
|
|
347
|
-
isGoingUp,
|
|
348
|
-
isGoingDown,
|
|
349
|
-
|
|
350
|
-
status: isRelease ? "released" : "dragging",
|
|
351
|
-
dragEvent: isRelease ? gestureInfo.dragEvent : dragEvent,
|
|
352
|
-
releaseEvent: isRelease ? dragEvent : null,
|
|
353
|
-
};
|
|
354
|
-
|
|
355
|
-
if (isRelease) {
|
|
356
|
-
return dragData;
|
|
357
|
-
}
|
|
358
|
-
if (!gestureInfo.started && threshold) {
|
|
359
|
-
const deltaX = Math.abs(dragX - grabX);
|
|
360
|
-
const deltaY = Math.abs(dragY - grabY);
|
|
361
|
-
if (direction.x && direction.y) {
|
|
362
|
-
// Both directions: check both axes
|
|
363
|
-
if (deltaX < threshold && deltaY < threshold) {
|
|
364
|
-
return dragData;
|
|
365
|
-
}
|
|
366
|
-
} else if (direction.x) {
|
|
367
|
-
if (deltaX < threshold) {
|
|
368
|
-
return dragData;
|
|
369
|
-
}
|
|
370
|
-
} else if (direction.y) {
|
|
371
|
-
if (deltaY < threshold) {
|
|
372
|
-
return dragData;
|
|
373
|
-
}
|
|
374
|
-
}
|
|
375
|
-
dragData.started = true;
|
|
376
|
-
}
|
|
377
|
-
return dragData;
|
|
378
|
-
};
|
|
379
|
-
|
|
380
|
-
const drag = (
|
|
381
|
-
dragX = gestureInfo.dragX, // Scroll container relative X coordinate
|
|
382
|
-
dragY = gestureInfo.dragY, // Scroll container relative Y coordinate
|
|
383
|
-
{ event = new CustomEvent("programmatic"), isRelease = false } = {},
|
|
384
|
-
) => {
|
|
385
|
-
if (import.meta.dev && (isNaN(dragX) || isNaN(dragY))) {
|
|
386
|
-
throw new Error(`Invalid drag coordinates x=${dragX} y=${dragY}`);
|
|
387
|
-
}
|
|
388
|
-
|
|
389
|
-
const dragData = determineDragData({
|
|
390
|
-
dragX,
|
|
391
|
-
dragY,
|
|
392
|
-
dragEvent: event,
|
|
393
|
-
isRelease,
|
|
394
|
-
});
|
|
395
|
-
const startedPrevious = gestureInfo.started;
|
|
396
|
-
const layoutPrevious = gestureInfo.layout;
|
|
397
|
-
// previousGestureInfo = { ...gestureInfo };
|
|
398
|
-
Object.assign(gestureInfo, dragData);
|
|
399
|
-
if (!startedPrevious && gestureInfo.started) {
|
|
400
|
-
onDragStart?.(gestureInfo);
|
|
401
|
-
}
|
|
402
|
-
const someLayoutChange = gestureInfo.layout !== layoutPrevious;
|
|
403
|
-
publishDrag(
|
|
404
|
-
gestureInfo,
|
|
405
|
-
// we still publish drag event even when unchanged
|
|
406
|
-
// because UI might need to adjust when document scrolls
|
|
407
|
-
// even if nothing truly changes visually the element
|
|
408
|
-
// can decide to stick to the scroll for example
|
|
409
|
-
someLayoutChange,
|
|
410
|
-
);
|
|
411
|
-
};
|
|
412
|
-
|
|
413
|
-
const release = ({
|
|
414
|
-
event = new CustomEvent("programmatic"),
|
|
415
|
-
releaseX = gestureInfo.dragX,
|
|
416
|
-
releaseY = gestureInfo.dragY,
|
|
417
|
-
} = {}) => {
|
|
418
|
-
drag(releaseX, releaseY, { event, isRelease: true });
|
|
419
|
-
publishRelease(gestureInfo);
|
|
420
|
-
};
|
|
421
|
-
|
|
422
|
-
onGrab?.(gestureInfo);
|
|
423
|
-
const dragGesture = {
|
|
424
|
-
gestureInfo,
|
|
425
|
-
addBeforeDragCallback,
|
|
426
|
-
addDragCallback,
|
|
427
|
-
addReleaseCallback,
|
|
428
|
-
drag,
|
|
429
|
-
release,
|
|
430
|
-
};
|
|
431
|
-
return dragGesture;
|
|
432
|
-
};
|
|
433
|
-
dragGestureController.grab = grab;
|
|
434
|
-
|
|
435
|
-
const initDragByPointer = (grabEvent, dragOptions, initializer) => {
|
|
436
|
-
if (grabEvent.button !== undefined && grabEvent.button !== 0) {
|
|
437
|
-
return null;
|
|
438
|
-
}
|
|
439
|
-
const target = grabEvent.target;
|
|
440
|
-
if (!target.closest) {
|
|
441
|
-
// target is a text node
|
|
442
|
-
return null;
|
|
443
|
-
}
|
|
444
|
-
const mouseEventCoords = (mouseEvent) => {
|
|
445
|
-
const { clientX, clientY } = mouseEvent;
|
|
446
|
-
return [clientX, clientY];
|
|
447
|
-
};
|
|
448
|
-
const [grabX, grabY] = mouseEventCoords(grabEvent);
|
|
449
|
-
const dragGesture = dragGestureController.grab({
|
|
450
|
-
grabX,
|
|
451
|
-
grabY,
|
|
452
|
-
event: grabEvent,
|
|
453
|
-
...dragOptions,
|
|
454
|
-
});
|
|
455
|
-
const dragViaPointer = (dragEvent) => {
|
|
456
|
-
const [mouseDragX, mouseDragY] = mouseEventCoords(dragEvent);
|
|
457
|
-
dragGesture.drag(mouseDragX, mouseDragY, {
|
|
458
|
-
event: dragEvent,
|
|
459
|
-
});
|
|
460
|
-
};
|
|
461
|
-
const releaseViaPointer = (mouseupEvent) => {
|
|
462
|
-
const [mouseReleaseX, mouseReleaseY] = mouseEventCoords(mouseupEvent);
|
|
463
|
-
dragGesture.release({
|
|
464
|
-
event: mouseupEvent,
|
|
465
|
-
releaseX: mouseReleaseX,
|
|
466
|
-
releaseY: mouseReleaseY,
|
|
467
|
-
});
|
|
468
|
-
};
|
|
469
|
-
dragGesture.dragViaPointer = dragViaPointer;
|
|
470
|
-
dragGesture.releaseViaPointer = releaseViaPointer;
|
|
471
|
-
const cleanup = initializer({
|
|
472
|
-
onMove: dragViaPointer,
|
|
473
|
-
onRelease: releaseViaPointer,
|
|
474
|
-
});
|
|
475
|
-
dragGesture.addReleaseCallback(() => {
|
|
476
|
-
cleanup();
|
|
477
|
-
});
|
|
478
|
-
return dragGesture;
|
|
479
|
-
};
|
|
480
|
-
|
|
481
|
-
const grabViaPointer = (grabEvent, options) => {
|
|
482
|
-
if (grabEvent.type === "pointerdown") {
|
|
483
|
-
return initDragByPointer(grabEvent, options, ({ onMove, onRelease }) => {
|
|
484
|
-
const target = grabEvent.target;
|
|
485
|
-
target.setPointerCapture(grabEvent.pointerId);
|
|
486
|
-
target.addEventListener("lostpointercapture", onRelease);
|
|
487
|
-
target.addEventListener("pointercancel", onRelease);
|
|
488
|
-
target.addEventListener("pointermove", onMove);
|
|
489
|
-
target.addEventListener("pointerup", onRelease);
|
|
490
|
-
return () => {
|
|
491
|
-
target.releasePointerCapture(grabEvent.pointerId);
|
|
492
|
-
target.removeEventListener("lostpointercapture", onRelease);
|
|
493
|
-
target.removeEventListener("pointercancel", onRelease);
|
|
494
|
-
target.removeEventListener("pointermove", onMove);
|
|
495
|
-
target.removeEventListener("pointerup", onRelease);
|
|
496
|
-
};
|
|
497
|
-
});
|
|
498
|
-
}
|
|
499
|
-
if (grabEvent.type === "mousedown") {
|
|
500
|
-
console.warn(
|
|
501
|
-
`Received "mousedown" event, "pointerdown" events are recommended to perform drag gestures.`,
|
|
502
|
-
);
|
|
503
|
-
return initDragByPointer(grabEvent, options, ({ onMove, onRelease }) => {
|
|
504
|
-
const onPointerUp = (pointerEvent) => {
|
|
505
|
-
// <button disabled> for example does not emit mouseup if we release mouse over it
|
|
506
|
-
// -> we add "pointerup" to catch mouseup occuring on disabled element
|
|
507
|
-
if (pointerEvent.pointerType === "mouse") {
|
|
508
|
-
onRelease(pointerEvent);
|
|
509
|
-
}
|
|
510
|
-
};
|
|
511
|
-
document.addEventListener("mousemove", onMove);
|
|
512
|
-
document.addEventListener("mouseup", onRelease);
|
|
513
|
-
document.addEventListener("pointerup", onPointerUp);
|
|
514
|
-
return () => {
|
|
515
|
-
document.removeEventListener("mousemove", onMove);
|
|
516
|
-
document.removeEventListener("mouseup", onRelease);
|
|
517
|
-
document.removeEventListener("pointerup", onPointerUp);
|
|
518
|
-
};
|
|
519
|
-
});
|
|
520
|
-
}
|
|
521
|
-
throw new Error(
|
|
522
|
-
`Unsupported "${grabEvent.type}" evenet passed to grabViaPointer. "pointerdown" was expected.`,
|
|
523
|
-
);
|
|
524
|
-
};
|
|
525
|
-
dragGestureController.grabViaPointer = grabViaPointer;
|
|
526
|
-
|
|
527
|
-
return dragGestureController;
|
|
528
|
-
};
|
|
529
|
-
|
|
530
|
-
export const dragAfterThreshold = (
|
|
531
|
-
grabEvent,
|
|
532
|
-
dragGestureInitializer,
|
|
533
|
-
threshold,
|
|
534
|
-
) => {
|
|
535
|
-
const significantDragGestureController = createDragGestureController({
|
|
536
|
-
threshold,
|
|
537
|
-
// allow interaction for this intermediate gesture:
|
|
538
|
-
// user should still be able to scroll or interact with the document
|
|
539
|
-
// only once the gesture is significant we take control
|
|
540
|
-
documentInteractions: "manual",
|
|
541
|
-
onDragStart: (gestureInfo) => {
|
|
542
|
-
significantDragGesture.release(); // kill that gesture
|
|
543
|
-
const dragGesture = dragGestureInitializer();
|
|
544
|
-
dragGesture.dragViaPointer(gestureInfo.dragEvent);
|
|
545
|
-
},
|
|
546
|
-
});
|
|
547
|
-
const significantDragGesture =
|
|
548
|
-
significantDragGestureController.grabViaPointer(grabEvent, {
|
|
549
|
-
element: grabEvent.target,
|
|
550
|
-
});
|
|
551
|
-
};
|
|
552
|
-
|
|
553
|
-
const definePropertyAsReadOnly = (object, propertyName) => {
|
|
554
|
-
Object.defineProperty(object, propertyName, {
|
|
555
|
-
writable: false,
|
|
556
|
-
value: object[propertyName],
|
|
557
|
-
});
|
|
558
|
-
};
|
|
559
|
-
|
|
560
|
-
import.meta.css = /* css */ `
|
|
561
|
-
.navi_drag_gesture_backdrop {
|
|
562
|
-
position: fixed;
|
|
563
|
-
inset: 0;
|
|
564
|
-
user-select: none;
|
|
565
|
-
}
|
|
566
|
-
`;
|