@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,254 +0,0 @@
|
|
|
1
|
-
/**
|
|
2
|
-
* TODO: use style_controller.js
|
|
3
|
-
*
|
|
4
|
-
* - Able to force transition styles
|
|
5
|
-
* - Able to read natural styles (getUnderlyingValue)
|
|
6
|
-
* - Able to getWith/Height/opacity without transition
|
|
7
|
-
*
|
|
8
|
-
*/
|
|
9
|
-
|
|
10
|
-
import { getHeight } from "../size/get_height.js";
|
|
11
|
-
import { getWidth } from "../size/get_width.js";
|
|
12
|
-
import { addWillChange } from "../style/dom_styles.js";
|
|
13
|
-
import { parseTransform } from "./transform_style_parser.js";
|
|
14
|
-
import { createTimelineTransition } from "./transition_playback.js";
|
|
15
|
-
|
|
16
|
-
import.meta.css = /* css */ `
|
|
17
|
-
/* Transition data attributes override inline styles using CSS custom properties */
|
|
18
|
-
*[data-transition-opacity] {
|
|
19
|
-
opacity: var(--ui-transition-opacity) !important;
|
|
20
|
-
}
|
|
21
|
-
|
|
22
|
-
*[data-transition-translate-x] {
|
|
23
|
-
transform: translateX(var(--ui-transition-translate-x)) !important;
|
|
24
|
-
}
|
|
25
|
-
|
|
26
|
-
*[data-transition-width] {
|
|
27
|
-
width: var(--ui-transition-width) !important;
|
|
28
|
-
}
|
|
29
|
-
|
|
30
|
-
*[data-transition-height] {
|
|
31
|
-
height: var(--ui-transition-height) !important;
|
|
32
|
-
}
|
|
33
|
-
`;
|
|
34
|
-
|
|
35
|
-
export const createHeightTransition = (element, to, options) => {
|
|
36
|
-
const heightTransition = createTimelineTransition({
|
|
37
|
-
...options,
|
|
38
|
-
constructor: createHeightTransition,
|
|
39
|
-
key: element,
|
|
40
|
-
to,
|
|
41
|
-
isVisual: true,
|
|
42
|
-
minDiff: 10,
|
|
43
|
-
lifecycle: {
|
|
44
|
-
setup: () => {
|
|
45
|
-
const restoreWillChange = addWillChange(element, "height");
|
|
46
|
-
return {
|
|
47
|
-
from: getHeight(element),
|
|
48
|
-
update: ({ value }) => {
|
|
49
|
-
const valueWithUnit = `${value}px`;
|
|
50
|
-
element.setAttribute("data-transition-height", valueWithUnit);
|
|
51
|
-
element.style.setProperty("--ui-transition-height", valueWithUnit);
|
|
52
|
-
},
|
|
53
|
-
teardown: () => {
|
|
54
|
-
element.removeAttribute("data-transition-height");
|
|
55
|
-
element.style.removeProperty("--ui-transition-height");
|
|
56
|
-
restoreWillChange();
|
|
57
|
-
},
|
|
58
|
-
restore: () => {
|
|
59
|
-
element.removeAttribute("data-transition-height");
|
|
60
|
-
element.style.removeProperty("--ui-transition-height");
|
|
61
|
-
},
|
|
62
|
-
};
|
|
63
|
-
},
|
|
64
|
-
},
|
|
65
|
-
});
|
|
66
|
-
return heightTransition;
|
|
67
|
-
};
|
|
68
|
-
export const createWidthTransition = (element, to, options) => {
|
|
69
|
-
const widthTransition = createTimelineTransition({
|
|
70
|
-
...options,
|
|
71
|
-
constructor: createWidthTransition,
|
|
72
|
-
key: element,
|
|
73
|
-
to,
|
|
74
|
-
minDiff: 10,
|
|
75
|
-
isVisual: true,
|
|
76
|
-
lifecycle: {
|
|
77
|
-
setup: () => {
|
|
78
|
-
const restoreWillChange = addWillChange(element, "width");
|
|
79
|
-
return {
|
|
80
|
-
from: getWidth(element),
|
|
81
|
-
update: ({ value }) => {
|
|
82
|
-
const valueWithUnit = `${value}px`;
|
|
83
|
-
element.setAttribute("data-transition-width", valueWithUnit);
|
|
84
|
-
element.style.setProperty("--ui-transition-width", valueWithUnit);
|
|
85
|
-
},
|
|
86
|
-
teardown: () => {
|
|
87
|
-
element.removeAttribute("data-transition-width");
|
|
88
|
-
element.style.removeProperty("--ui-transition-width");
|
|
89
|
-
restoreWillChange();
|
|
90
|
-
},
|
|
91
|
-
restore: () => {
|
|
92
|
-
element.removeAttribute("data-transition-width");
|
|
93
|
-
element.style.removeProperty("--ui-transition-width");
|
|
94
|
-
},
|
|
95
|
-
};
|
|
96
|
-
},
|
|
97
|
-
},
|
|
98
|
-
});
|
|
99
|
-
return widthTransition;
|
|
100
|
-
};
|
|
101
|
-
export const createOpacityTransition = (element, to, options = {}) => {
|
|
102
|
-
const opacityTransition = createTimelineTransition({
|
|
103
|
-
...options,
|
|
104
|
-
constructor: createOpacityTransition,
|
|
105
|
-
key: element,
|
|
106
|
-
to,
|
|
107
|
-
minDiff: 0.1,
|
|
108
|
-
isVisual: true,
|
|
109
|
-
lifecycle: {
|
|
110
|
-
setup: () => {
|
|
111
|
-
const restoreWillChange = addWillChange(element, "opacity");
|
|
112
|
-
return {
|
|
113
|
-
from: getOpacity(element),
|
|
114
|
-
update: ({ value }) => {
|
|
115
|
-
element.setAttribute("data-transition-opacity", value);
|
|
116
|
-
element.style.setProperty("--ui-transition-opacity", value);
|
|
117
|
-
},
|
|
118
|
-
teardown: () => {
|
|
119
|
-
element.removeAttribute("data-transition-opacity");
|
|
120
|
-
element.style.removeProperty("--ui-transition-opacity");
|
|
121
|
-
restoreWillChange();
|
|
122
|
-
},
|
|
123
|
-
restore: () => {
|
|
124
|
-
element.removeAttribute("data-transition-opacity");
|
|
125
|
-
element.style.removeProperty("--ui-transition-opacity");
|
|
126
|
-
},
|
|
127
|
-
};
|
|
128
|
-
},
|
|
129
|
-
},
|
|
130
|
-
});
|
|
131
|
-
return opacityTransition;
|
|
132
|
-
};
|
|
133
|
-
export const getOpacity = (element) => {
|
|
134
|
-
return parseFloat(getComputedStyle(element).opacity) || 0;
|
|
135
|
-
};
|
|
136
|
-
|
|
137
|
-
export const createTranslateXTransition = (element, to, options) => {
|
|
138
|
-
let unit = "px";
|
|
139
|
-
if (typeof to === "string") {
|
|
140
|
-
if (to.endsWith("%")) {
|
|
141
|
-
unit = "%";
|
|
142
|
-
}
|
|
143
|
-
to = parseFloat(to);
|
|
144
|
-
}
|
|
145
|
-
|
|
146
|
-
const translateXTransition = createTimelineTransition({
|
|
147
|
-
...options,
|
|
148
|
-
constructor: createTranslateXTransition,
|
|
149
|
-
key: element,
|
|
150
|
-
to,
|
|
151
|
-
minDiff: 10,
|
|
152
|
-
isVisual: true,
|
|
153
|
-
lifecycle: {
|
|
154
|
-
setup: () => {
|
|
155
|
-
const restoreWillChange = addWillChange(element, "transform");
|
|
156
|
-
return {
|
|
157
|
-
from: getTranslateX(element),
|
|
158
|
-
update: ({ value }) => {
|
|
159
|
-
const valueWithUnit = `${value}${unit}`;
|
|
160
|
-
element.setAttribute("data-transition-translate-x", valueWithUnit);
|
|
161
|
-
element.style.setProperty(
|
|
162
|
-
"--ui-transition-translate-x",
|
|
163
|
-
valueWithUnit,
|
|
164
|
-
);
|
|
165
|
-
},
|
|
166
|
-
teardown: () => {
|
|
167
|
-
restoreWillChange();
|
|
168
|
-
element.removeAttribute("data-transition-translate-x");
|
|
169
|
-
element.style.removeProperty("--ui-transition-translate-x");
|
|
170
|
-
},
|
|
171
|
-
restore: () => {
|
|
172
|
-
element.removeAttribute("data-transition-translate-x");
|
|
173
|
-
element.style.removeProperty("--ui-transition-translate-x");
|
|
174
|
-
},
|
|
175
|
-
};
|
|
176
|
-
},
|
|
177
|
-
},
|
|
178
|
-
});
|
|
179
|
-
return translateXTransition;
|
|
180
|
-
};
|
|
181
|
-
export const getTranslateX = (element) => {
|
|
182
|
-
const transform = getComputedStyle(element).transform;
|
|
183
|
-
const transformMap = parseTransform(transform);
|
|
184
|
-
return transformMap.get("translateX")?.value || 0;
|
|
185
|
-
};
|
|
186
|
-
|
|
187
|
-
// Helper functions for getting natural (non-transition) values
|
|
188
|
-
export const getOpacityWithoutTransition = (element) => {
|
|
189
|
-
const transitionOpacity = element.getAttribute("data-transition-opacity");
|
|
190
|
-
|
|
191
|
-
// Temporarily remove transition attribute
|
|
192
|
-
element.removeAttribute("data-transition-opacity");
|
|
193
|
-
|
|
194
|
-
const naturalValue = parseFloat(getComputedStyle(element).opacity) || 0;
|
|
195
|
-
|
|
196
|
-
// Restore transition attribute if it existed
|
|
197
|
-
if (transitionOpacity !== null) {
|
|
198
|
-
element.setAttribute("data-transition-opacity", transitionOpacity);
|
|
199
|
-
}
|
|
200
|
-
|
|
201
|
-
return naturalValue;
|
|
202
|
-
};
|
|
203
|
-
|
|
204
|
-
export const getTranslateXWithoutTransition = (element) => {
|
|
205
|
-
const transitionTranslateX = element.getAttribute(
|
|
206
|
-
"data-transition-translate-x",
|
|
207
|
-
);
|
|
208
|
-
|
|
209
|
-
// Temporarily remove transition attribute
|
|
210
|
-
element.removeAttribute("data-transition-translate-x");
|
|
211
|
-
|
|
212
|
-
const transform = getComputedStyle(element).transform;
|
|
213
|
-
const transformMap = parseTransform(transform);
|
|
214
|
-
const naturalValue = transformMap.get("translateX")?.value || 0;
|
|
215
|
-
|
|
216
|
-
// Restore transition attribute if it existed
|
|
217
|
-
if (transitionTranslateX !== null) {
|
|
218
|
-
element.setAttribute("data-transition-translate-x", transitionTranslateX);
|
|
219
|
-
}
|
|
220
|
-
|
|
221
|
-
return naturalValue;
|
|
222
|
-
};
|
|
223
|
-
|
|
224
|
-
export const getWidthWithoutTransition = (element) => {
|
|
225
|
-
const transitionWidth = element.getAttribute("data-transition-width");
|
|
226
|
-
|
|
227
|
-
// Temporarily remove transition attribute
|
|
228
|
-
element.removeAttribute("data-transition-width");
|
|
229
|
-
|
|
230
|
-
const naturalValue = getWidth(element);
|
|
231
|
-
|
|
232
|
-
// Restore transition attribute if it existed
|
|
233
|
-
if (transitionWidth !== null) {
|
|
234
|
-
element.setAttribute("data-transition-width", transitionWidth);
|
|
235
|
-
}
|
|
236
|
-
|
|
237
|
-
return naturalValue;
|
|
238
|
-
};
|
|
239
|
-
|
|
240
|
-
export const getHeightWithoutTransition = (element) => {
|
|
241
|
-
const transitionHeight = element.getAttribute("data-transition-height");
|
|
242
|
-
|
|
243
|
-
// Temporarily remove transition attribute
|
|
244
|
-
element.removeAttribute("data-transition-height");
|
|
245
|
-
|
|
246
|
-
const naturalValue = getHeight(element);
|
|
247
|
-
|
|
248
|
-
// Restore transition attribute if it existed
|
|
249
|
-
if (transitionHeight !== null) {
|
|
250
|
-
element.setAttribute("data-transition-height", transitionHeight);
|
|
251
|
-
}
|
|
252
|
-
|
|
253
|
-
return naturalValue;
|
|
254
|
-
};
|
package/src/transition/easing.js
DELETED
|
@@ -1,48 +0,0 @@
|
|
|
1
|
-
export const EASING = {
|
|
2
|
-
LINEAR: (x) => x,
|
|
3
|
-
EASE: (x) => {
|
|
4
|
-
return cubicBezier(x, 0.25, 0.1, 0.25, 1.0);
|
|
5
|
-
},
|
|
6
|
-
EASE_IN: (x) => {
|
|
7
|
-
return cubicBezier(x, 0.42, 0, 1.0, 1.0);
|
|
8
|
-
},
|
|
9
|
-
EASE_OUT: (x) => {
|
|
10
|
-
return cubicBezier(x, 0, 0, 0.58, 1.0);
|
|
11
|
-
},
|
|
12
|
-
EASE_IN_OUT: (x) => {
|
|
13
|
-
return cubicBezier(x, 0.42, 0, 0.58, 1.0);
|
|
14
|
-
},
|
|
15
|
-
EASE_IN_OUT_CUBIC: (x) => {
|
|
16
|
-
return x < 0.5 ? 4 * x * x * x : 1 - Math.pow(-2 * x + 2, 3) / 2;
|
|
17
|
-
},
|
|
18
|
-
EASE_IN_EXPO: (x) => {
|
|
19
|
-
return x === 0 ? 0 : Math.pow(2, 10 * x - 10);
|
|
20
|
-
},
|
|
21
|
-
EASE_OUT_EXPO: (x) => {
|
|
22
|
-
return x === 1 ? 1 : 1 - Math.pow(2, -10 * x);
|
|
23
|
-
},
|
|
24
|
-
EASE_OUT_ELASTIC: (x) => {
|
|
25
|
-
const c4 = (2 * Math.PI) / 3;
|
|
26
|
-
if (x === 0) {
|
|
27
|
-
return 0;
|
|
28
|
-
}
|
|
29
|
-
if (x === 1) {
|
|
30
|
-
return 1;
|
|
31
|
-
}
|
|
32
|
-
return Math.pow(2, -10 * x) * Math.sin((x * 10 - 0.75) * c4) + 1;
|
|
33
|
-
},
|
|
34
|
-
EASE_OUT_CUBIC: (x) => {
|
|
35
|
-
return 1 - Math.pow(1 - x, 3);
|
|
36
|
-
},
|
|
37
|
-
};
|
|
38
|
-
|
|
39
|
-
export const easingDefault = (x) => cubicBezier(x, 0.1, 0.4, 0.6, 1.0);
|
|
40
|
-
|
|
41
|
-
export const cubicBezier = (t, initial, p1, p2, final) => {
|
|
42
|
-
return (
|
|
43
|
-
(1 - t) * (1 - t) * (1 - t) * initial +
|
|
44
|
-
3 * (1 - t) * (1 - t) * t * p1 +
|
|
45
|
-
3 * (1 - t) * t * t * p2 +
|
|
46
|
-
t * t * t * final
|
|
47
|
-
);
|
|
48
|
-
};
|
|
@@ -1,261 +0,0 @@
|
|
|
1
|
-
import { createTransition } from "./transition_playback.js";
|
|
2
|
-
|
|
3
|
-
// transition that manages multiple transitions
|
|
4
|
-
export const createGroupTransition = (transitionArray) => {
|
|
5
|
-
let finishedCount = 0;
|
|
6
|
-
let duration = 0;
|
|
7
|
-
let childCount = transitionArray.length;
|
|
8
|
-
for (const childTransition of transitionArray) {
|
|
9
|
-
if (childTransition.duration > duration) {
|
|
10
|
-
duration = childTransition.duration;
|
|
11
|
-
}
|
|
12
|
-
}
|
|
13
|
-
|
|
14
|
-
const groupTransition = createTransition({
|
|
15
|
-
constructor: createGroupTransition,
|
|
16
|
-
from: 0,
|
|
17
|
-
to: 1,
|
|
18
|
-
duration,
|
|
19
|
-
lifecycle: {
|
|
20
|
-
setup: (transition) => {
|
|
21
|
-
finishedCount = 0;
|
|
22
|
-
|
|
23
|
-
const cleanupCallbackSet = new Set();
|
|
24
|
-
for (const childTransition of transitionArray) {
|
|
25
|
-
const removeFinishListener = childTransition.channels.finish.add(
|
|
26
|
-
// eslint-disable-next-line no-loop-func
|
|
27
|
-
() => {
|
|
28
|
-
finishedCount++;
|
|
29
|
-
const allFinished = finishedCount === childCount;
|
|
30
|
-
if (allFinished) {
|
|
31
|
-
transition.finish();
|
|
32
|
-
}
|
|
33
|
-
},
|
|
34
|
-
);
|
|
35
|
-
cleanupCallbackSet.add(removeFinishListener);
|
|
36
|
-
childTransition.play();
|
|
37
|
-
|
|
38
|
-
const removeUpdateListener = childTransition.channels.update.add(
|
|
39
|
-
() => {
|
|
40
|
-
// Calculate average progress (handle undefined progress)
|
|
41
|
-
let totalProgress = 0;
|
|
42
|
-
let progressCount = 0;
|
|
43
|
-
for (const t of transitionArray) {
|
|
44
|
-
if (typeof t.progress === "number") {
|
|
45
|
-
totalProgress += t.progress;
|
|
46
|
-
progressCount++;
|
|
47
|
-
}
|
|
48
|
-
}
|
|
49
|
-
const averageProgress =
|
|
50
|
-
progressCount > 0 ? totalProgress / progressCount : 0;
|
|
51
|
-
// Expose progress on the group transition for external access
|
|
52
|
-
transition.progress = averageProgress;
|
|
53
|
-
// Update this transition's value with average progress
|
|
54
|
-
const isLast = averageProgress >= 1;
|
|
55
|
-
transition.update(averageProgress, isLast);
|
|
56
|
-
},
|
|
57
|
-
);
|
|
58
|
-
cleanupCallbackSet.add(removeUpdateListener);
|
|
59
|
-
}
|
|
60
|
-
|
|
61
|
-
return {
|
|
62
|
-
update: () => {},
|
|
63
|
-
teardown: () => {
|
|
64
|
-
for (const cleanupCallback of cleanupCallbackSet) {
|
|
65
|
-
cleanupCallback();
|
|
66
|
-
}
|
|
67
|
-
cleanupCallbackSet.clear();
|
|
68
|
-
},
|
|
69
|
-
restore: () => {},
|
|
70
|
-
};
|
|
71
|
-
},
|
|
72
|
-
pause: () => {
|
|
73
|
-
for (const childTransition of transitionArray) {
|
|
74
|
-
if (childTransition.playState === "running") {
|
|
75
|
-
childTransition.pause();
|
|
76
|
-
}
|
|
77
|
-
}
|
|
78
|
-
return () => {
|
|
79
|
-
for (const childTransition of transitionArray) {
|
|
80
|
-
if (childTransition.playState === "paused") {
|
|
81
|
-
childTransition.play();
|
|
82
|
-
}
|
|
83
|
-
}
|
|
84
|
-
};
|
|
85
|
-
},
|
|
86
|
-
|
|
87
|
-
cancel: () => {
|
|
88
|
-
for (const childTransition of transitionArray) {
|
|
89
|
-
if (childTransition.playState !== "idle") {
|
|
90
|
-
childTransition.cancel();
|
|
91
|
-
}
|
|
92
|
-
}
|
|
93
|
-
},
|
|
94
|
-
|
|
95
|
-
finish: () => {
|
|
96
|
-
for (const childTransition of transitionArray) {
|
|
97
|
-
if (childTransition.playState !== "finished") {
|
|
98
|
-
childTransition.finish();
|
|
99
|
-
}
|
|
100
|
-
}
|
|
101
|
-
},
|
|
102
|
-
|
|
103
|
-
reverse: () => {
|
|
104
|
-
for (const childTransition of transitionArray) {
|
|
105
|
-
if (
|
|
106
|
-
childTransition.playState === "running" ||
|
|
107
|
-
childTransition.playState === "paused"
|
|
108
|
-
) {
|
|
109
|
-
childTransition.reverse();
|
|
110
|
-
}
|
|
111
|
-
}
|
|
112
|
-
},
|
|
113
|
-
},
|
|
114
|
-
});
|
|
115
|
-
return groupTransition;
|
|
116
|
-
};
|
|
117
|
-
|
|
118
|
-
/**
|
|
119
|
-
* Creates an interface that manages ongoing transitions
|
|
120
|
-
* and handles target updates automatically
|
|
121
|
-
*/
|
|
122
|
-
export const createGroupTransitionController = () => {
|
|
123
|
-
// Track all active transitions for cancellation and matching
|
|
124
|
-
const activeTransitions = new Set();
|
|
125
|
-
|
|
126
|
-
return {
|
|
127
|
-
/**
|
|
128
|
-
* Animate multiple transitions simultaneously
|
|
129
|
-
* Automatically handles updateTarget for transitions that match constructor + targetKey
|
|
130
|
-
* @param {Array} transitions - Array of transition objects with constructor and targetKey properties
|
|
131
|
-
* @param {Object} options - Transition options
|
|
132
|
-
* @param {Function} options.onChange - Called with (changeEntries, isLast) during transition
|
|
133
|
-
* @param {Function} options.onFinish - Called when all transitions complete
|
|
134
|
-
* @returns {Object} Playback controller with play(), pause(), cancel(), etc.
|
|
135
|
-
*/
|
|
136
|
-
animate: (transitions, options = {}) => {
|
|
137
|
-
const { onChange, onFinish } = options;
|
|
138
|
-
|
|
139
|
-
if (transitions.length === 0) {
|
|
140
|
-
// No transitions to animate, call onFinish immediately
|
|
141
|
-
if (onFinish) {
|
|
142
|
-
onFinish([]);
|
|
143
|
-
}
|
|
144
|
-
return {
|
|
145
|
-
play: () => {},
|
|
146
|
-
pause: () => {},
|
|
147
|
-
cancel: () => {},
|
|
148
|
-
finish: () => {},
|
|
149
|
-
playState: "idle",
|
|
150
|
-
channels: { update: { add: () => {} }, finish: { add: () => {} } },
|
|
151
|
-
};
|
|
152
|
-
}
|
|
153
|
-
|
|
154
|
-
const newTransitions = [];
|
|
155
|
-
const updatedTransitions = [];
|
|
156
|
-
|
|
157
|
-
// Separate transitions into new vs updates to existing ones
|
|
158
|
-
for (const transition of transitions) {
|
|
159
|
-
// Look for existing transition with same constructor and targetKey
|
|
160
|
-
let existingTransition = null;
|
|
161
|
-
for (const transitionCandidate of activeTransitions) {
|
|
162
|
-
if (
|
|
163
|
-
transitionCandidate.constructor === transition.constructor &&
|
|
164
|
-
transitionCandidate.key === transition.key
|
|
165
|
-
) {
|
|
166
|
-
existingTransition = transitionCandidate;
|
|
167
|
-
break;
|
|
168
|
-
}
|
|
169
|
-
}
|
|
170
|
-
|
|
171
|
-
if (existingTransition && existingTransition.playState === "running") {
|
|
172
|
-
// Update the existing transition's target if it supports updateTarget
|
|
173
|
-
if (existingTransition.updateTarget) {
|
|
174
|
-
existingTransition.updateTarget(transition.to);
|
|
175
|
-
}
|
|
176
|
-
updatedTransitions.push(existingTransition);
|
|
177
|
-
} else {
|
|
178
|
-
// Track this new transition
|
|
179
|
-
activeTransitions.add(transition);
|
|
180
|
-
// Clean up tracking when transition finishes
|
|
181
|
-
transition.channels.finish.add(() => {
|
|
182
|
-
activeTransitions.delete(transition);
|
|
183
|
-
});
|
|
184
|
-
|
|
185
|
-
newTransitions.push(transition);
|
|
186
|
-
}
|
|
187
|
-
}
|
|
188
|
-
|
|
189
|
-
// If we only have updated transitions (no new ones), return a minimal controller
|
|
190
|
-
if (newTransitions.length === 0) {
|
|
191
|
-
return {
|
|
192
|
-
play: () => {}, // Already playing
|
|
193
|
-
pause: () =>
|
|
194
|
-
updatedTransitions.forEach((transition) => transition.pause()),
|
|
195
|
-
cancel: () =>
|
|
196
|
-
updatedTransitions.forEach((transition) => transition.cancel()),
|
|
197
|
-
finish: () =>
|
|
198
|
-
updatedTransitions.forEach((transition) => transition.finish()),
|
|
199
|
-
reverse: () =>
|
|
200
|
-
updatedTransitions.forEach((transition) => transition.reverse()),
|
|
201
|
-
playState: "running", // All are already running
|
|
202
|
-
channels: {
|
|
203
|
-
update: { add: () => {} }, // Update tracking already set up
|
|
204
|
-
finish: { add: () => {} },
|
|
205
|
-
},
|
|
206
|
-
};
|
|
207
|
-
}
|
|
208
|
-
|
|
209
|
-
// Create group transition to coordinate new transitions only
|
|
210
|
-
const groupTransition = createGroupTransition(newTransitions);
|
|
211
|
-
|
|
212
|
-
// Add unified update tracking for ALL transitions (new + updated)
|
|
213
|
-
if (onChange) {
|
|
214
|
-
groupTransition.channels.update.add((transition) => {
|
|
215
|
-
// Build change entries for current state of ALL transitions
|
|
216
|
-
const changeEntries = [...newTransitions, ...updatedTransitions].map(
|
|
217
|
-
(transition) => ({
|
|
218
|
-
transition,
|
|
219
|
-
value: transition.value,
|
|
220
|
-
}),
|
|
221
|
-
);
|
|
222
|
-
|
|
223
|
-
const isLast = transition.value >= 1; // isLast = value >= 1 (since group tracks 0-1)
|
|
224
|
-
onChange(changeEntries, isLast);
|
|
225
|
-
});
|
|
226
|
-
}
|
|
227
|
-
|
|
228
|
-
// Add finish tracking
|
|
229
|
-
if (onFinish) {
|
|
230
|
-
groupTransition.channels.finish.add(() => {
|
|
231
|
-
const changeEntries = [...newTransitions, ...updatedTransitions].map(
|
|
232
|
-
(transition) => ({
|
|
233
|
-
transition,
|
|
234
|
-
value: transition.value,
|
|
235
|
-
}),
|
|
236
|
-
);
|
|
237
|
-
onFinish(changeEntries);
|
|
238
|
-
});
|
|
239
|
-
}
|
|
240
|
-
|
|
241
|
-
return groupTransition;
|
|
242
|
-
},
|
|
243
|
-
|
|
244
|
-
/**
|
|
245
|
-
* Cancel all ongoing transitions managed by this controller
|
|
246
|
-
*/
|
|
247
|
-
cancel: () => {
|
|
248
|
-
// Cancel all active transitions
|
|
249
|
-
for (const transition of activeTransitions) {
|
|
250
|
-
if (
|
|
251
|
-
transition.playState === "running" ||
|
|
252
|
-
transition.playState === "paused"
|
|
253
|
-
) {
|
|
254
|
-
transition.cancel();
|
|
255
|
-
}
|
|
256
|
-
}
|
|
257
|
-
// Clear the sets - the finish callbacks will handle individual cleanup
|
|
258
|
-
activeTransitions.clear();
|
|
259
|
-
},
|
|
260
|
-
};
|
|
261
|
-
};
|
|
@@ -1,32 +0,0 @@
|
|
|
1
|
-
export const parseTransform = (transform) => {
|
|
2
|
-
if (!transform || transform === "none") return new Map();
|
|
3
|
-
const transformMap = new Map();
|
|
4
|
-
|
|
5
|
-
if (transform.startsWith("matrix(")) {
|
|
6
|
-
// matrix(a, b, c, d, e, f) where e is translateX and f is translateY
|
|
7
|
-
const values = transform
|
|
8
|
-
.match(/matrix\((.*?)\)/)?.[1]
|
|
9
|
-
.split(",")
|
|
10
|
-
.map(Number);
|
|
11
|
-
if (values) {
|
|
12
|
-
const translateX = values[4]; // e value from matrix
|
|
13
|
-
transformMap.set("translateX", { value: translateX, unit: "px" });
|
|
14
|
-
return transformMap;
|
|
15
|
-
}
|
|
16
|
-
}
|
|
17
|
-
|
|
18
|
-
// For direct transform functions (when set via style.transform)
|
|
19
|
-
const matches = transform.matchAll(/(\w+)\(([-\d.]+)(%|px|deg)?\)/g);
|
|
20
|
-
for (const match of matches) {
|
|
21
|
-
const [, func, value, unit = ""] = match;
|
|
22
|
-
transformMap.set(func, { value: parseFloat(value), unit });
|
|
23
|
-
}
|
|
24
|
-
return transformMap;
|
|
25
|
-
};
|
|
26
|
-
|
|
27
|
-
export const stringifyTransform = (transformMap) => {
|
|
28
|
-
if (transformMap.size === 0) return "none";
|
|
29
|
-
return Array.from(transformMap.entries())
|
|
30
|
-
.map(([func, { value, unit }]) => `${func}(${value}${unit})`)
|
|
31
|
-
.join(" ");
|
|
32
|
-
};
|