@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
package/dist/jsenv_dom.js
CHANGED
|
@@ -61,6 +61,16 @@ import { useState, useLayoutEffect } from "preact/hooks";
|
|
|
61
61
|
* getElementSignature(null) // Returns: "null"
|
|
62
62
|
*/
|
|
63
63
|
const getElementSignature = (element) => {
|
|
64
|
+
if (Array.isArray(element)) {
|
|
65
|
+
if (element.length === 0) {
|
|
66
|
+
return "empty";
|
|
67
|
+
}
|
|
68
|
+
if (element.length === 1) {
|
|
69
|
+
return getElementSignature(element[0]);
|
|
70
|
+
}
|
|
71
|
+
const parent = element[0].parentNode;
|
|
72
|
+
return `${getElementSignature(parent)} children`;
|
|
73
|
+
}
|
|
64
74
|
if (!element) {
|
|
65
75
|
return String(element);
|
|
66
76
|
}
|
|
@@ -306,11 +316,13 @@ const getAssociatedElements = (element) => {
|
|
|
306
316
|
return null;
|
|
307
317
|
};
|
|
308
318
|
|
|
309
|
-
const getComputedStyle$1 = (element) =>
|
|
310
|
-
elementToOwnerWindow(element).getComputedStyle(element);
|
|
319
|
+
const getComputedStyle$1 = (element) => {
|
|
320
|
+
return elementToOwnerWindow(element).getComputedStyle(element);
|
|
321
|
+
};
|
|
311
322
|
|
|
312
|
-
const getStyle = (element, name) =>
|
|
313
|
-
getComputedStyle$1(element).getPropertyValue(name);
|
|
323
|
+
const getStyle = (element, name) => {
|
|
324
|
+
return getComputedStyle$1(element).getPropertyValue(name);
|
|
325
|
+
};
|
|
314
326
|
const setStyle = (element, name, value) => {
|
|
315
327
|
|
|
316
328
|
const prevValue = element.style[name];
|
|
@@ -487,7 +499,11 @@ const normalizeStyle = (value, propertyName, context = "js") => {
|
|
|
487
499
|
// If value is a CSS transform string, parse it first to extract the specific property
|
|
488
500
|
if (typeof value === "string") {
|
|
489
501
|
if (value === "none") {
|
|
490
|
-
|
|
502
|
+
if (transformProperty.startsWith("scale")) {
|
|
503
|
+
return 1;
|
|
504
|
+
}
|
|
505
|
+
// translate, rotate, skew
|
|
506
|
+
return 0;
|
|
491
507
|
}
|
|
492
508
|
const parsedTransform = parseCSSTransform(value);
|
|
493
509
|
return parsedTransform?.[transformProperty];
|
|
@@ -501,38 +517,55 @@ const normalizeStyle = (value, propertyName, context = "js") => {
|
|
|
501
517
|
}
|
|
502
518
|
|
|
503
519
|
if (pxProperties.includes(propertyName)) {
|
|
504
|
-
return normalizeNumber(value,
|
|
520
|
+
return normalizeNumber(value, {
|
|
521
|
+
propertyName,
|
|
522
|
+
unit: "px",
|
|
523
|
+
preferedType: context === "js" ? "number" : "string",
|
|
524
|
+
});
|
|
505
525
|
}
|
|
506
526
|
if (degProperties.includes(propertyName)) {
|
|
507
|
-
return normalizeNumber(value,
|
|
527
|
+
return normalizeNumber(value, {
|
|
528
|
+
propertyName,
|
|
529
|
+
unit: "deg",
|
|
530
|
+
preferedType: "string",
|
|
531
|
+
});
|
|
508
532
|
}
|
|
509
533
|
if (unitlessProperties.includes(propertyName)) {
|
|
510
|
-
return normalizeNumber(value,
|
|
534
|
+
return normalizeNumber(value, {
|
|
535
|
+
propertyName,
|
|
536
|
+
unit: "",
|
|
537
|
+
preferedType: context === "js" ? "number" : "string",
|
|
538
|
+
});
|
|
511
539
|
}
|
|
512
540
|
|
|
513
541
|
return value;
|
|
514
542
|
};
|
|
515
|
-
const normalizeNumber = (value,
|
|
516
|
-
if (context === "css") {
|
|
517
|
-
if (typeof value === "number") {
|
|
518
|
-
if (isNaN(value)) {
|
|
519
|
-
console.warn(`NaN found for "${propertyName}"`);
|
|
520
|
-
}
|
|
521
|
-
return `${value}${unit}`;
|
|
522
|
-
}
|
|
523
|
-
return value;
|
|
524
|
-
}
|
|
543
|
+
const normalizeNumber = (value, { unit, propertyName, preferedType }) => {
|
|
525
544
|
if (typeof value === "string") {
|
|
526
|
-
//
|
|
527
|
-
if (
|
|
545
|
+
// Keep strings as-is (including %, em, rem, auto, none, etc.)
|
|
546
|
+
if (preferedType === "string") {
|
|
547
|
+
return value;
|
|
548
|
+
}
|
|
549
|
+
// convert to number if possible (font-size: "12px" -> fontSize:12, opacity: "0.5" -> opacity: 0.5)
|
|
550
|
+
if (!unit || value.endsWith(unit)) {
|
|
528
551
|
const numericValue = parseFloat(value);
|
|
529
552
|
if (!isNaN(numericValue)) {
|
|
530
553
|
return numericValue;
|
|
531
554
|
}
|
|
532
555
|
}
|
|
533
|
-
// Keep all other strings as-is (including %, em, rem, auto, none, etc.)
|
|
534
556
|
return value;
|
|
535
557
|
}
|
|
558
|
+
if (typeof value === "number") {
|
|
559
|
+
if (isNaN(value)) {
|
|
560
|
+
console.warn(`NaN found for "${propertyName}"`);
|
|
561
|
+
}
|
|
562
|
+
if (preferedType === "number") {
|
|
563
|
+
return value;
|
|
564
|
+
}
|
|
565
|
+
// convert to string with unit
|
|
566
|
+
return `${value}${unit}`;
|
|
567
|
+
}
|
|
568
|
+
|
|
536
569
|
return value;
|
|
537
570
|
};
|
|
538
571
|
|
|
@@ -958,6 +991,21 @@ const onElementControllerRemoved = (element, controller) => {
|
|
|
958
991
|
}
|
|
959
992
|
};
|
|
960
993
|
|
|
994
|
+
/**
|
|
995
|
+
* Creates a style controller that can safely manage CSS styles on DOM elements.
|
|
996
|
+
*
|
|
997
|
+
* Uses Web Animations API to override styles without touching inline styles,
|
|
998
|
+
* allowing multiple controllers to work together and providing intelligent transform composition.
|
|
999
|
+
*
|
|
1000
|
+
* @param {string} [name="anonymous"] - Debug name for the controller
|
|
1001
|
+
* @returns {Object} Controller with methods: set, get, delete, getUnderlyingValue, commit, clear, clearAll
|
|
1002
|
+
*
|
|
1003
|
+
* @example
|
|
1004
|
+
* const controller = createStyleController("myFeature");
|
|
1005
|
+
* controller.set(element, { opacity: 0.5, transform: { translateX: 100 } });
|
|
1006
|
+
* controller.getUnderlyingValue(element, "opacity"); // Read value without controller influence
|
|
1007
|
+
* controller.clearAll(); // Cleanup
|
|
1008
|
+
*/
|
|
961
1009
|
const createStyleController = (name = "anonymous") => {
|
|
962
1010
|
// Store element data for this controller: element -> { styles, animation }
|
|
963
1011
|
const elementWeakMap = new WeakMap();
|
|
@@ -1014,11 +1062,27 @@ const createStyleController = (name = "anonymous") => {
|
|
|
1014
1062
|
return;
|
|
1015
1063
|
}
|
|
1016
1064
|
const { styles, animation } = elementData;
|
|
1017
|
-
|
|
1018
|
-
|
|
1019
|
-
|
|
1065
|
+
if (propertyName.startsWith("transform.")) {
|
|
1066
|
+
const transformProp = propertyName.slice("transform.".length);
|
|
1067
|
+
const transformObject = styles.transform;
|
|
1068
|
+
if (!transformObject) {
|
|
1069
|
+
return;
|
|
1070
|
+
}
|
|
1071
|
+
const hasTransformProp = Object.hasOwn(transformObject, transformProp);
|
|
1072
|
+
if (!hasTransformProp) {
|
|
1073
|
+
return;
|
|
1074
|
+
}
|
|
1075
|
+
delete transformObject[transformProp];
|
|
1076
|
+
if (Object.keys(transformObject).length === 0) {
|
|
1077
|
+
delete styles.transform;
|
|
1078
|
+
}
|
|
1079
|
+
} else {
|
|
1080
|
+
const hasStyle = Object.hasOwn(styles, propertyName);
|
|
1081
|
+
if (!hasStyle) {
|
|
1082
|
+
return;
|
|
1083
|
+
}
|
|
1084
|
+
delete styles[propertyName];
|
|
1020
1085
|
}
|
|
1021
|
-
delete styles[propertyName];
|
|
1022
1086
|
const isEmpty = Object.keys(styles).length === 0;
|
|
1023
1087
|
// Clean up empty controller
|
|
1024
1088
|
if (isEmpty) {
|
|
@@ -1220,6 +1284,44 @@ const updateAnimationStyles = (animation, styles) => {
|
|
|
1220
1284
|
animation.pause();
|
|
1221
1285
|
};
|
|
1222
1286
|
|
|
1287
|
+
const dormantStyleController = createStyleController("dormant");
|
|
1288
|
+
const getOpacity = (
|
|
1289
|
+
element,
|
|
1290
|
+
styleControllerToIgnore = dormantStyleController,
|
|
1291
|
+
) => {
|
|
1292
|
+
return styleControllerToIgnore.getUnderlyingValue(element, "opacity");
|
|
1293
|
+
};
|
|
1294
|
+
const getTranslateX = (
|
|
1295
|
+
element,
|
|
1296
|
+
styleControllerToIgnore = dormantStyleController,
|
|
1297
|
+
) => {
|
|
1298
|
+
return styleControllerToIgnore.getUnderlyingValue(
|
|
1299
|
+
element,
|
|
1300
|
+
"transform.translateX",
|
|
1301
|
+
);
|
|
1302
|
+
};
|
|
1303
|
+
const getTranslateY = (
|
|
1304
|
+
element,
|
|
1305
|
+
styleControllerToIgnore = dormantStyleController,
|
|
1306
|
+
) => {
|
|
1307
|
+
return styleControllerToIgnore.getUnderlyingValue(
|
|
1308
|
+
element,
|
|
1309
|
+
"transform.translateY",
|
|
1310
|
+
);
|
|
1311
|
+
};
|
|
1312
|
+
const getWidth$1 = (
|
|
1313
|
+
element,
|
|
1314
|
+
styleControllerToIgnore = dormantStyleController,
|
|
1315
|
+
) => {
|
|
1316
|
+
return styleControllerToIgnore.getUnderlyingValue(element, "rect.width");
|
|
1317
|
+
};
|
|
1318
|
+
const getHeight$1 = (
|
|
1319
|
+
element,
|
|
1320
|
+
styleControllerToIgnore = dormantStyleController,
|
|
1321
|
+
) => {
|
|
1322
|
+
return styleControllerToIgnore.getUnderlyingValue(element, "rect.height");
|
|
1323
|
+
};
|
|
1324
|
+
|
|
1223
1325
|
// Register the style isolator custom element once
|
|
1224
1326
|
let persistentStyleIsolator = null;
|
|
1225
1327
|
const getNaviStyleIsolator = () => {
|
|
@@ -7990,32 +8092,6 @@ const pickPositionRelativeTo = (
|
|
|
7990
8092
|
};
|
|
7991
8093
|
};
|
|
7992
8094
|
|
|
7993
|
-
const parseTransform = (transform) => {
|
|
7994
|
-
if (!transform || transform === "none") return new Map();
|
|
7995
|
-
const transformMap = new Map();
|
|
7996
|
-
|
|
7997
|
-
if (transform.startsWith("matrix(")) {
|
|
7998
|
-
// matrix(a, b, c, d, e, f) where e is translateX and f is translateY
|
|
7999
|
-
const values = transform
|
|
8000
|
-
.match(/matrix\((.*?)\)/)?.[1]
|
|
8001
|
-
.split(",")
|
|
8002
|
-
.map(Number);
|
|
8003
|
-
if (values) {
|
|
8004
|
-
const translateX = values[4]; // e value from matrix
|
|
8005
|
-
transformMap.set("translateX", { value: translateX, unit: "px" });
|
|
8006
|
-
return transformMap;
|
|
8007
|
-
}
|
|
8008
|
-
}
|
|
8009
|
-
|
|
8010
|
-
// For direct transform functions (when set via style.transform)
|
|
8011
|
-
const matches = transform.matchAll(/(\w+)\(([-\d.]+)(%|px|deg)?\)/g);
|
|
8012
|
-
for (const match of matches) {
|
|
8013
|
-
const [, func, value, unit = ""] = match;
|
|
8014
|
-
transformMap.set(func, { value: parseFloat(value), unit });
|
|
8015
|
-
}
|
|
8016
|
-
return transformMap;
|
|
8017
|
-
};
|
|
8018
|
-
|
|
8019
8095
|
const EASING = {
|
|
8020
8096
|
LINEAR: (x) => x,
|
|
8021
8097
|
EASE: (x) => {
|
|
@@ -8493,25 +8569,7 @@ const createCallbackController = () => {
|
|
|
8493
8569
|
return [callbacks, execute];
|
|
8494
8570
|
};
|
|
8495
8571
|
|
|
8496
|
-
|
|
8497
|
-
import.meta.css = /* css */ `
|
|
8498
|
-
/* Transition data attributes override inline styles using CSS custom properties */
|
|
8499
|
-
*[data-transition-opacity] {
|
|
8500
|
-
opacity: var(--ui-transition-opacity) !important;
|
|
8501
|
-
}
|
|
8502
|
-
|
|
8503
|
-
*[data-transition-translate-x] {
|
|
8504
|
-
transform: translateX(var(--ui-transition-translate-x)) !important;
|
|
8505
|
-
}
|
|
8506
|
-
|
|
8507
|
-
*[data-transition-width] {
|
|
8508
|
-
width: var(--ui-transition-width) !important;
|
|
8509
|
-
}
|
|
8510
|
-
|
|
8511
|
-
*[data-transition-height] {
|
|
8512
|
-
height: var(--ui-transition-height) !important;
|
|
8513
|
-
}
|
|
8514
|
-
`;
|
|
8572
|
+
const transitionStyleController = createStyleController("transition");
|
|
8515
8573
|
|
|
8516
8574
|
const createHeightTransition = (element, to, options) => {
|
|
8517
8575
|
const heightTransition = createTimelineTransition({
|
|
@@ -8523,22 +8581,16 @@ const createHeightTransition = (element, to, options) => {
|
|
|
8523
8581
|
minDiff: 10,
|
|
8524
8582
|
lifecycle: {
|
|
8525
8583
|
setup: () => {
|
|
8526
|
-
const restoreWillChange = addWillChange(element, "height");
|
|
8527
8584
|
return {
|
|
8528
|
-
from: getHeight(element),
|
|
8585
|
+
from: getHeight$1(element),
|
|
8529
8586
|
update: ({ value }) => {
|
|
8530
|
-
|
|
8531
|
-
element.setAttribute("data-transition-height", valueWithUnit);
|
|
8532
|
-
element.style.setProperty("--ui-transition-height", valueWithUnit);
|
|
8587
|
+
transitionStyleController.set(element, { height: value });
|
|
8533
8588
|
},
|
|
8534
8589
|
teardown: () => {
|
|
8535
|
-
|
|
8536
|
-
element.style.removeProperty("--ui-transition-height");
|
|
8537
|
-
restoreWillChange();
|
|
8590
|
+
transitionStyleController.delete(element, "height");
|
|
8538
8591
|
},
|
|
8539
8592
|
restore: () => {
|
|
8540
|
-
|
|
8541
|
-
element.style.removeProperty("--ui-transition-height");
|
|
8593
|
+
transitionStyleController.delete(element, "height");
|
|
8542
8594
|
},
|
|
8543
8595
|
};
|
|
8544
8596
|
},
|
|
@@ -8556,22 +8608,16 @@ const createWidthTransition = (element, to, options) => {
|
|
|
8556
8608
|
isVisual: true,
|
|
8557
8609
|
lifecycle: {
|
|
8558
8610
|
setup: () => {
|
|
8559
|
-
const restoreWillChange = addWillChange(element, "width");
|
|
8560
8611
|
return {
|
|
8561
|
-
from: getWidth(element),
|
|
8612
|
+
from: getWidth$1(element),
|
|
8562
8613
|
update: ({ value }) => {
|
|
8563
|
-
|
|
8564
|
-
element.setAttribute("data-transition-width", valueWithUnit);
|
|
8565
|
-
element.style.setProperty("--ui-transition-width", valueWithUnit);
|
|
8614
|
+
transitionStyleController.set(element, { width: value });
|
|
8566
8615
|
},
|
|
8567
8616
|
teardown: () => {
|
|
8568
|
-
|
|
8569
|
-
element.style.removeProperty("--ui-transition-width");
|
|
8570
|
-
restoreWillChange();
|
|
8617
|
+
transitionStyleController.delete(element, "width");
|
|
8571
8618
|
},
|
|
8572
8619
|
restore: () => {
|
|
8573
|
-
|
|
8574
|
-
element.style.removeProperty("--ui-transition-width");
|
|
8620
|
+
transitionStyleController.delete(element, "width");
|
|
8575
8621
|
},
|
|
8576
8622
|
};
|
|
8577
8623
|
},
|
|
@@ -8589,21 +8635,16 @@ const createOpacityTransition = (element, to, options = {}) => {
|
|
|
8589
8635
|
isVisual: true,
|
|
8590
8636
|
lifecycle: {
|
|
8591
8637
|
setup: () => {
|
|
8592
|
-
const restoreWillChange = addWillChange(element, "opacity");
|
|
8593
8638
|
return {
|
|
8594
8639
|
from: getOpacity(element),
|
|
8595
8640
|
update: ({ value }) => {
|
|
8596
|
-
|
|
8597
|
-
element.style.setProperty("--ui-transition-opacity", value);
|
|
8641
|
+
transitionStyleController.set(element, { opacity: value });
|
|
8598
8642
|
},
|
|
8599
8643
|
teardown: () => {
|
|
8600
|
-
|
|
8601
|
-
element.style.removeProperty("--ui-transition-opacity");
|
|
8602
|
-
restoreWillChange();
|
|
8644
|
+
transitionStyleController.delete(element, "opacity");
|
|
8603
8645
|
},
|
|
8604
8646
|
restore: () => {
|
|
8605
|
-
|
|
8606
|
-
element.style.removeProperty("--ui-transition-opacity");
|
|
8647
|
+
transitionStyleController.delete(element, "opacity");
|
|
8607
8648
|
},
|
|
8608
8649
|
};
|
|
8609
8650
|
},
|
|
@@ -8611,19 +8652,8 @@ const createOpacityTransition = (element, to, options = {}) => {
|
|
|
8611
8652
|
});
|
|
8612
8653
|
return opacityTransition;
|
|
8613
8654
|
};
|
|
8614
|
-
const getOpacity = (element) => {
|
|
8615
|
-
return parseFloat(getComputedStyle(element).opacity) || 0;
|
|
8616
|
-
};
|
|
8617
8655
|
|
|
8618
8656
|
const createTranslateXTransition = (element, to, options) => {
|
|
8619
|
-
let unit = "px";
|
|
8620
|
-
if (typeof to === "string") {
|
|
8621
|
-
if (to.endsWith("%")) {
|
|
8622
|
-
unit = "%";
|
|
8623
|
-
}
|
|
8624
|
-
to = parseFloat(to);
|
|
8625
|
-
}
|
|
8626
|
-
|
|
8627
8657
|
const translateXTransition = createTimelineTransition({
|
|
8628
8658
|
...options,
|
|
8629
8659
|
constructor: createTranslateXTransition,
|
|
@@ -8633,25 +8663,20 @@ const createTranslateXTransition = (element, to, options) => {
|
|
|
8633
8663
|
isVisual: true,
|
|
8634
8664
|
lifecycle: {
|
|
8635
8665
|
setup: () => {
|
|
8636
|
-
const restoreWillChange = addWillChange(element, "transform");
|
|
8637
8666
|
return {
|
|
8638
8667
|
from: getTranslateX(element),
|
|
8639
8668
|
update: ({ value }) => {
|
|
8640
|
-
|
|
8641
|
-
|
|
8642
|
-
|
|
8643
|
-
|
|
8644
|
-
|
|
8645
|
-
);
|
|
8669
|
+
transitionStyleController.set(element, {
|
|
8670
|
+
transform: {
|
|
8671
|
+
translateX: value,
|
|
8672
|
+
},
|
|
8673
|
+
});
|
|
8646
8674
|
},
|
|
8647
8675
|
teardown: () => {
|
|
8648
|
-
|
|
8649
|
-
element.removeAttribute("data-transition-translate-x");
|
|
8650
|
-
element.style.removeProperty("--ui-transition-translate-x");
|
|
8676
|
+
transitionStyleController.delete(element, "transform.translateX");
|
|
8651
8677
|
},
|
|
8652
8678
|
restore: () => {
|
|
8653
|
-
|
|
8654
|
-
element.style.removeProperty("--ui-transition-translate-x");
|
|
8679
|
+
transitionStyleController.delete(element, "transform.translateX");
|
|
8655
8680
|
},
|
|
8656
8681
|
};
|
|
8657
8682
|
},
|
|
@@ -8659,48 +8684,12 @@ const createTranslateXTransition = (element, to, options) => {
|
|
|
8659
8684
|
});
|
|
8660
8685
|
return translateXTransition;
|
|
8661
8686
|
};
|
|
8662
|
-
const getTranslateX = (element) => {
|
|
8663
|
-
const transform = getComputedStyle(element).transform;
|
|
8664
|
-
const transformMap = parseTransform(transform);
|
|
8665
|
-
return transformMap.get("translateX")?.value || 0;
|
|
8666
|
-
};
|
|
8667
|
-
|
|
8668
|
-
// Helper functions for getting natural (non-transition) values
|
|
8669
|
-
const getOpacityWithoutTransition = (element) => {
|
|
8670
|
-
const transitionOpacity = element.getAttribute("data-transition-opacity");
|
|
8671
|
-
|
|
8672
|
-
// Temporarily remove transition attribute
|
|
8673
|
-
element.removeAttribute("data-transition-opacity");
|
|
8674
|
-
|
|
8675
|
-
const naturalValue = parseFloat(getComputedStyle(element).opacity) || 0;
|
|
8676
|
-
|
|
8677
|
-
// Restore transition attribute if it existed
|
|
8678
|
-
if (transitionOpacity !== null) {
|
|
8679
|
-
element.setAttribute("data-transition-opacity", transitionOpacity);
|
|
8680
|
-
}
|
|
8681
|
-
|
|
8682
|
-
return naturalValue;
|
|
8683
|
-
};
|
|
8684
|
-
|
|
8685
|
-
const getTranslateXWithoutTransition = (element) => {
|
|
8686
|
-
const transitionTranslateX = element.getAttribute(
|
|
8687
|
-
"data-transition-translate-x",
|
|
8688
|
-
);
|
|
8689
|
-
|
|
8690
|
-
// Temporarily remove transition attribute
|
|
8691
|
-
element.removeAttribute("data-transition-translate-x");
|
|
8692
8687
|
|
|
8693
|
-
|
|
8694
|
-
|
|
8695
|
-
|
|
8696
|
-
|
|
8697
|
-
|
|
8698
|
-
if (transitionTranslateX !== null) {
|
|
8699
|
-
element.setAttribute("data-transition-translate-x", transitionTranslateX);
|
|
8700
|
-
}
|
|
8701
|
-
|
|
8702
|
-
return naturalValue;
|
|
8703
|
-
};
|
|
8688
|
+
// Helper functions for getting natural values
|
|
8689
|
+
const getOpacityWithoutTransition = (element) =>
|
|
8690
|
+
getOpacity(element, transitionStyleController);
|
|
8691
|
+
const getTranslateXWithoutTransition = (element) =>
|
|
8692
|
+
getTranslateX(element, transitionStyleController);
|
|
8704
8693
|
|
|
8705
8694
|
// transition that manages multiple transitions
|
|
8706
8695
|
const createGroupTransition = (transitionArray) => {
|
|
@@ -10290,10 +10279,16 @@ import.meta.css = /* css */ `
|
|
|
10290
10279
|
.ui_transition_container,
|
|
10291
10280
|
.ui_transition_outer_wrapper,
|
|
10292
10281
|
.ui_transition_measure_wrapper,
|
|
10293
|
-
.ui_transition_slot
|
|
10282
|
+
.ui_transition_slot,
|
|
10283
|
+
.ui_transition_phase_overlay,
|
|
10284
|
+
.ui_transition_content_overlay {
|
|
10294
10285
|
display: inline-flex;
|
|
10295
|
-
width:
|
|
10296
|
-
height:
|
|
10286
|
+
width: 100%;
|
|
10287
|
+
height: 100%;
|
|
10288
|
+
}
|
|
10289
|
+
|
|
10290
|
+
.ui_transition_measure_wrapper[data-transition-translate-x] {
|
|
10291
|
+
overflow: hidden;
|
|
10297
10292
|
}
|
|
10298
10293
|
|
|
10299
10294
|
.ui_transition_container,
|
|
@@ -10316,11 +10311,15 @@ const DEBUG = {
|
|
|
10316
10311
|
};
|
|
10317
10312
|
|
|
10318
10313
|
// Utility function to format content key states consistently for debug logs
|
|
10319
|
-
const formatContentKeyState = (
|
|
10314
|
+
const formatContentKeyState = (
|
|
10315
|
+
contentKey,
|
|
10316
|
+
hasChildren,
|
|
10317
|
+
hasTextNode = false,
|
|
10318
|
+
) => {
|
|
10320
10319
|
if (hasTextNode) {
|
|
10321
10320
|
return "[text]";
|
|
10322
10321
|
}
|
|
10323
|
-
if (!
|
|
10322
|
+
if (!hasChildren) {
|
|
10324
10323
|
return "[empty]";
|
|
10325
10324
|
}
|
|
10326
10325
|
if (contentKey === null || contentKey === undefined) {
|
|
@@ -10341,6 +10340,7 @@ const initUITransition = (container) => {
|
|
|
10341
10340
|
...DEBUG,
|
|
10342
10341
|
transition: container.hasAttribute("data-debug-transition"),
|
|
10343
10342
|
};
|
|
10343
|
+
const debugClones = container.hasAttribute("data-debug-clones");
|
|
10344
10344
|
|
|
10345
10345
|
const debug = (type, ...args) => {
|
|
10346
10346
|
if (localDebug[type]) {
|
|
@@ -10365,17 +10365,6 @@ const initUITransition = (container) => {
|
|
|
10365
10365
|
".ui_transition_content_overlay",
|
|
10366
10366
|
);
|
|
10367
10367
|
|
|
10368
|
-
if (!phaseOverlay) {
|
|
10369
|
-
phaseOverlay = document.createElement("div");
|
|
10370
|
-
phaseOverlay.className = "ui_transition_phase_overlay";
|
|
10371
|
-
measureWrapper.appendChild(phaseOverlay);
|
|
10372
|
-
}
|
|
10373
|
-
if (!contentOverlay) {
|
|
10374
|
-
contentOverlay = document.createElement("div");
|
|
10375
|
-
contentOverlay.className = "ui_transition_content_overlay";
|
|
10376
|
-
container.appendChild(contentOverlay);
|
|
10377
|
-
}
|
|
10378
|
-
|
|
10379
10368
|
if (
|
|
10380
10369
|
!outerWrapper ||
|
|
10381
10370
|
!measureWrapper ||
|
|
@@ -10418,7 +10407,7 @@ const initUITransition = (container) => {
|
|
|
10418
10407
|
|
|
10419
10408
|
// Child state
|
|
10420
10409
|
let lastContentKey = null;
|
|
10421
|
-
let
|
|
10410
|
+
let previousChildNodes = [];
|
|
10422
10411
|
let isContentPhase = false; // Current state: true when showing content phase (loading/error)
|
|
10423
10412
|
let wasContentPhase = false; // Previous state for comparison
|
|
10424
10413
|
|
|
@@ -10647,40 +10636,48 @@ const initUITransition = (container) => {
|
|
|
10647
10636
|
const setupTransition = ({
|
|
10648
10637
|
isPhaseTransition = false,
|
|
10649
10638
|
overlay,
|
|
10650
|
-
|
|
10651
|
-
|
|
10652
|
-
|
|
10653
|
-
firstChild,
|
|
10639
|
+
needsOldChildNodesClone,
|
|
10640
|
+
previousChildNodes,
|
|
10641
|
+
childNodes,
|
|
10654
10642
|
attributeToRemove = [],
|
|
10655
10643
|
}) => {
|
|
10656
|
-
let oldChild = null;
|
|
10657
10644
|
let cleanup = () => {};
|
|
10658
|
-
|
|
10645
|
+
let elementToImpact;
|
|
10659
10646
|
|
|
10660
|
-
if (
|
|
10661
|
-
|
|
10647
|
+
if (overlay.childNodes.length > 0) {
|
|
10648
|
+
elementToImpact = overlay;
|
|
10649
|
+
cleanup = () => {
|
|
10650
|
+
if (!debugClones) {
|
|
10651
|
+
overlay.innerHTML = "";
|
|
10652
|
+
}
|
|
10653
|
+
};
|
|
10662
10654
|
debug(
|
|
10663
10655
|
"transition",
|
|
10664
10656
|
`Continuing from current ${isPhaseTransition ? "phase" : "content"} transition element`,
|
|
10665
10657
|
);
|
|
10666
|
-
|
|
10667
|
-
} else if (needsOldChildClone) {
|
|
10658
|
+
} else if (needsOldChildNodesClone) {
|
|
10668
10659
|
overlay.innerHTML = "";
|
|
10669
|
-
|
|
10670
|
-
|
|
10671
|
-
|
|
10672
|
-
|
|
10673
|
-
|
|
10674
|
-
|
|
10675
|
-
|
|
10676
|
-
|
|
10677
|
-
|
|
10660
|
+
for (const previousChildNode of previousChildNodes) {
|
|
10661
|
+
const previousChildClone = previousChildNode.cloneNode(true);
|
|
10662
|
+
if (previousChildClone.nodeType !== Node.TEXT_NODE) {
|
|
10663
|
+
for (const attrToRemove of attributeToRemove) {
|
|
10664
|
+
previousChildClone.removeAttribute(attrToRemove);
|
|
10665
|
+
}
|
|
10666
|
+
previousChildClone.setAttribute("data-ui-transition-clone", "");
|
|
10667
|
+
}
|
|
10668
|
+
overlay.appendChild(previousChildClone);
|
|
10669
|
+
}
|
|
10670
|
+
elementToImpact = overlay;
|
|
10671
|
+
cleanup = () => {
|
|
10672
|
+
if (!debugClones) {
|
|
10673
|
+
overlay.innerHTML = "";
|
|
10674
|
+
}
|
|
10675
|
+
};
|
|
10678
10676
|
debug(
|
|
10679
10677
|
"transition",
|
|
10680
10678
|
`Cloned previous child for ${isPhaseTransition ? "phase" : "content"} transition:`,
|
|
10681
|
-
getElementSignature(
|
|
10679
|
+
getElementSignature(previousChildNodes),
|
|
10682
10680
|
);
|
|
10683
|
-
cleanup = () => oldChild.remove();
|
|
10684
10681
|
} else {
|
|
10685
10682
|
overlay.innerHTML = "";
|
|
10686
10683
|
debug(
|
|
@@ -10696,16 +10693,15 @@ const initUITransition = (container) => {
|
|
|
10696
10693
|
let newElement;
|
|
10697
10694
|
if (isPhaseTransition) {
|
|
10698
10695
|
// Phase transitions work on individual elements
|
|
10699
|
-
oldElement =
|
|
10700
|
-
newElement =
|
|
10696
|
+
oldElement = elementToImpact;
|
|
10697
|
+
newElement = slot;
|
|
10701
10698
|
} else {
|
|
10702
10699
|
// Content transitions work at container level and can outlive content phase changes
|
|
10703
|
-
oldElement =
|
|
10704
|
-
newElement =
|
|
10700
|
+
oldElement = previousChildNodes.length ? elementToImpact : null;
|
|
10701
|
+
newElement = childNodes.length ? measureWrapper : null;
|
|
10705
10702
|
}
|
|
10706
10703
|
|
|
10707
10704
|
return {
|
|
10708
|
-
oldChild,
|
|
10709
10705
|
cleanup,
|
|
10710
10706
|
oldElement,
|
|
10711
10707
|
newElement,
|
|
@@ -10725,102 +10721,75 @@ const initUITransition = (container) => {
|
|
|
10725
10721
|
|
|
10726
10722
|
try {
|
|
10727
10723
|
isUpdating = true;
|
|
10728
|
-
const
|
|
10729
|
-
const childUIName = firstChild?.getAttribute("data-ui-name");
|
|
10724
|
+
const childNodes = Array.from(slot.childNodes);
|
|
10730
10725
|
if (localDebug.transition) {
|
|
10731
10726
|
const updateLabel =
|
|
10732
|
-
|
|
10733
|
-
|
|
10727
|
+
childNodes.length === 0
|
|
10728
|
+
? "cleared/empty"
|
|
10729
|
+
: childNodes.length === 1
|
|
10730
|
+
? getElementSignature(childNodes[0])
|
|
10731
|
+
: getElementSignature(slot);
|
|
10734
10732
|
console.group(`UI Update: ${updateLabel} (reason: ${reason})`);
|
|
10735
10733
|
}
|
|
10736
10734
|
|
|
10737
|
-
//
|
|
10738
|
-
|
|
10739
|
-
|
|
10740
|
-
|
|
10741
|
-
|
|
10742
|
-
console.warn(
|
|
10743
|
-
"UI Transition: Text nodes in transition slots are not supported. Please wrap text content in an element.",
|
|
10744
|
-
{ slot, textContent: slot.textContent.trim() },
|
|
10745
|
-
);
|
|
10746
|
-
}
|
|
10747
|
-
|
|
10748
|
-
// Check for multiple elements in the slot (not supported yet)
|
|
10749
|
-
const hasMultipleElements = slot.children.length > 1;
|
|
10750
|
-
if (hasMultipleElements) {
|
|
10751
|
-
console.warn(
|
|
10752
|
-
"UI Transition: Multiple elements in transition slots are not supported yet. Please use a single container element.",
|
|
10753
|
-
{ slot, elementCount: slot.children.length },
|
|
10754
|
-
);
|
|
10755
|
-
}
|
|
10735
|
+
// Determine transition scenarios early for early registration check
|
|
10736
|
+
// Prepare phase info early so logging can be unified (even for early return)
|
|
10737
|
+
wasContentPhase = isContentPhase;
|
|
10738
|
+
const hadChild = previousChildNodes.length > 0;
|
|
10739
|
+
const hasChild = childNodes.length > 0;
|
|
10756
10740
|
|
|
10757
10741
|
// Prefer data-content-key on child, fallback to slot
|
|
10758
10742
|
let currentContentKey = null;
|
|
10759
10743
|
let slotContentKey = slot.getAttribute("data-content-key");
|
|
10760
|
-
let childContentKey
|
|
10744
|
+
let childContentKey;
|
|
10745
|
+
|
|
10746
|
+
if (childNodes.length === 0) {
|
|
10747
|
+
childContentKey = null;
|
|
10748
|
+
isContentPhase = true; // empty (no child) is treated as content phase
|
|
10749
|
+
} else {
|
|
10750
|
+
for (const childNode of childNodes) {
|
|
10751
|
+
if (childNode.nodeType === Node.TEXT_NODE) {
|
|
10752
|
+
} else if (childNode.hasAttribute("data-content-key")) {
|
|
10753
|
+
childContentKey = childNode.getAttribute("data-content-key");
|
|
10754
|
+
} else if (childNode.hasAttribute("data-content-phase")) {
|
|
10755
|
+
isContentPhase = true;
|
|
10756
|
+
}
|
|
10757
|
+
}
|
|
10758
|
+
}
|
|
10761
10759
|
if (childContentKey && slotContentKey) {
|
|
10762
10760
|
console.warn(
|
|
10763
|
-
|
|
10764
|
-
{ childContentKey, slotContentKey },
|
|
10761
|
+
`Slot and slot child both have a [data-content-key]. Slot is ${slotContentKey} and child is ${childContentKey}, using the child.`,
|
|
10765
10762
|
);
|
|
10766
10763
|
}
|
|
10767
10764
|
currentContentKey = childContentKey || slotContentKey || null;
|
|
10768
|
-
|
|
10769
|
-
// Determine transition scenarios early for early registration check
|
|
10770
|
-
const hadChild = previousChild !== null;
|
|
10771
|
-
const hasChild = firstChild !== null;
|
|
10772
|
-
|
|
10773
|
-
// Check for text nodes in previous state (reconstruct from previousChild)
|
|
10774
|
-
const hadTextNode =
|
|
10775
|
-
previousChild && previousChild.nodeType === Node.TEXT_NODE;
|
|
10776
|
-
|
|
10777
10765
|
// Compute formatted content key states ONCE per mutation (requirement: max 2 calls)
|
|
10778
10766
|
const previousContentKeyState = formatContentKeyState(
|
|
10779
10767
|
lastContentKey,
|
|
10780
10768
|
hadChild,
|
|
10781
|
-
hadTextNode,
|
|
10782
10769
|
);
|
|
10783
10770
|
const currentContentKeyState = formatContentKeyState(
|
|
10784
10771
|
currentContentKey,
|
|
10785
10772
|
hasChild,
|
|
10786
|
-
hasTextNode,
|
|
10787
10773
|
);
|
|
10788
|
-
|
|
10789
10774
|
// Track previous key before any potential early registration update
|
|
10790
10775
|
const prevKeyBeforeRegistration = lastContentKey;
|
|
10791
|
-
|
|
10792
|
-
// Prepare phase info early so logging can be unified (even for early return)
|
|
10793
|
-
wasContentPhase = isContentPhase;
|
|
10794
|
-
isContentPhase = firstChild
|
|
10795
|
-
? firstChild.hasAttribute("data-content-phase")
|
|
10796
|
-
: true; // empty (no child) is treated as content phase
|
|
10797
|
-
|
|
10798
10776
|
const previousIsContentPhase = !hadChild || wasContentPhase;
|
|
10799
10777
|
const currentIsContentPhase = !hasChild || isContentPhase;
|
|
10800
10778
|
|
|
10801
|
-
// Early conceptual registration path: empty slot
|
|
10802
|
-
const shouldGiveUpEarlyAndJustRegister =
|
|
10803
|
-
(!hadChild && !hasChild && !hasTextNode) ||
|
|
10804
|
-
hasTextNode ||
|
|
10805
|
-
hasMultipleElements;
|
|
10779
|
+
// Early conceptual registration path: empty slot
|
|
10780
|
+
const shouldGiveUpEarlyAndJustRegister = !hadChild && !hasChild;
|
|
10806
10781
|
let earlyAction = null;
|
|
10807
10782
|
if (shouldGiveUpEarlyAndJustRegister) {
|
|
10808
|
-
|
|
10809
|
-
|
|
10810
|
-
|
|
10811
|
-
earlyAction = "
|
|
10783
|
+
const prevKey = prevKeyBeforeRegistration;
|
|
10784
|
+
const keyChanged = prevKey !== currentContentKey;
|
|
10785
|
+
if (!keyChanged) {
|
|
10786
|
+
earlyAction = "unchanged";
|
|
10787
|
+
} else if (prevKey === null && currentContentKey !== null) {
|
|
10788
|
+
earlyAction = "registered";
|
|
10789
|
+
} else if (prevKey !== null && currentContentKey === null) {
|
|
10790
|
+
earlyAction = "cleared";
|
|
10812
10791
|
} else {
|
|
10813
|
-
|
|
10814
|
-
const keyChanged = prevKey !== currentContentKey;
|
|
10815
|
-
if (!keyChanged) {
|
|
10816
|
-
earlyAction = "unchanged";
|
|
10817
|
-
} else if (prevKey === null && currentContentKey !== null) {
|
|
10818
|
-
earlyAction = "registered";
|
|
10819
|
-
} else if (prevKey !== null && currentContentKey === null) {
|
|
10820
|
-
earlyAction = "cleared";
|
|
10821
|
-
} else {
|
|
10822
|
-
earlyAction = "changed";
|
|
10823
|
-
}
|
|
10792
|
+
earlyAction = "changed";
|
|
10824
10793
|
}
|
|
10825
10794
|
// Will update lastContentKey after unified logging
|
|
10826
10795
|
}
|
|
@@ -10871,7 +10840,7 @@ const initUITransition = (container) => {
|
|
|
10871
10840
|
|
|
10872
10841
|
// Handle resize observation
|
|
10873
10842
|
stopResizeObserver();
|
|
10874
|
-
if (
|
|
10843
|
+
if (hasChild && !isContentPhase) {
|
|
10875
10844
|
startResizeObserver();
|
|
10876
10845
|
debug("size", "Observing child resize");
|
|
10877
10846
|
}
|
|
@@ -10897,11 +10866,7 @@ const initUITransition = (container) => {
|
|
|
10897
10866
|
|
|
10898
10867
|
// Content key change when either slot or child has data-content-key and it changed
|
|
10899
10868
|
let shouldDoContentTransition = false;
|
|
10900
|
-
if (
|
|
10901
|
-
(slot.getAttribute("data-content-key") ||
|
|
10902
|
-
firstChild?.getAttribute("data-content-key")) &&
|
|
10903
|
-
lastContentKey !== null
|
|
10904
|
-
) {
|
|
10869
|
+
if (currentContentKey && lastContentKey !== null) {
|
|
10905
10870
|
shouldDoContentTransition = currentContentKey !== lastContentKey;
|
|
10906
10871
|
}
|
|
10907
10872
|
|
|
@@ -10985,7 +10950,7 @@ const initUITransition = (container) => {
|
|
|
10985
10950
|
}
|
|
10986
10951
|
|
|
10987
10952
|
// Register state and mark initial population done
|
|
10988
|
-
|
|
10953
|
+
previousChildNodes = childNodes;
|
|
10989
10954
|
lastContentKey = currentContentKey;
|
|
10990
10955
|
hasPopulatedOnce = true;
|
|
10991
10956
|
if (localDebug.transition) {
|
|
@@ -11058,11 +11023,7 @@ const initUITransition = (container) => {
|
|
|
11058
11023
|
shouldDoContentTransitionIncludingPopulation &&
|
|
11059
11024
|
!preserveOnlyContentTransition
|
|
11060
11025
|
) {
|
|
11061
|
-
const existingOldContents = contentOverlay.querySelectorAll(
|
|
11062
|
-
"[data-ui-transition-old]",
|
|
11063
|
-
);
|
|
11064
11026
|
const animationProgress = activeContentTransition?.progress || 0;
|
|
11065
|
-
|
|
11066
11027
|
if (animationProgress > 0) {
|
|
11067
11028
|
debug(
|
|
11068
11029
|
"transition",
|
|
@@ -11076,7 +11037,6 @@ const initUITransition = (container) => {
|
|
|
11076
11037
|
const canContinueSmoothly =
|
|
11077
11038
|
activeContentTransitionType === newTransitionType &&
|
|
11078
11039
|
activeContentTransition;
|
|
11079
|
-
|
|
11080
11040
|
if (canContinueSmoothly) {
|
|
11081
11041
|
debug(
|
|
11082
11042
|
"transition",
|
|
@@ -11097,11 +11057,8 @@ const initUITransition = (container) => {
|
|
|
11097
11057
|
activeContentTransition.cancel();
|
|
11098
11058
|
}
|
|
11099
11059
|
|
|
11100
|
-
const
|
|
11101
|
-
(contentChange || becomesEmpty) &&
|
|
11102
|
-
previousChild &&
|
|
11103
|
-
!existingOldContents[0];
|
|
11104
|
-
|
|
11060
|
+
const needsOldChildNodesClone =
|
|
11061
|
+
(contentChange || becomesEmpty) && hadChild;
|
|
11105
11062
|
const duration = parseInt(
|
|
11106
11063
|
container.getAttribute("data-content-transition-duration") ||
|
|
11107
11064
|
CONTENT_TRANSITION_DURATION,
|
|
@@ -11114,10 +11071,9 @@ const initUITransition = (container) => {
|
|
|
11114
11071
|
setupTransition({
|
|
11115
11072
|
isPhaseTransition: false,
|
|
11116
11073
|
overlay: contentOverlay,
|
|
11117
|
-
|
|
11118
|
-
|
|
11119
|
-
|
|
11120
|
-
firstChild,
|
|
11074
|
+
needsOldChildNodesClone,
|
|
11075
|
+
previousChildNodes,
|
|
11076
|
+
childNodes,
|
|
11121
11077
|
attributeToRemove: ["data-content-key"],
|
|
11122
11078
|
});
|
|
11123
11079
|
|
|
@@ -11136,9 +11092,8 @@ const initUITransition = (container) => {
|
|
|
11136
11092
|
}
|
|
11137
11093
|
}
|
|
11138
11094
|
|
|
11139
|
-
activeContentTransition =
|
|
11095
|
+
activeContentTransition = applyTransition(
|
|
11140
11096
|
transitionController,
|
|
11141
|
-
firstChild,
|
|
11142
11097
|
setupContentTransition,
|
|
11143
11098
|
{
|
|
11144
11099
|
duration,
|
|
@@ -11180,12 +11135,7 @@ const initUITransition = (container) => {
|
|
|
11180
11135
|
if (shouldDoPhaseTransition) {
|
|
11181
11136
|
const phaseTransitionType =
|
|
11182
11137
|
container.getAttribute("data-phase-transition") || PHASE_TRANSITION;
|
|
11183
|
-
|
|
11184
|
-
const existingOldPhaseContents = phaseOverlay.querySelectorAll(
|
|
11185
|
-
"[data-ui-transition-old]",
|
|
11186
|
-
);
|
|
11187
11138
|
const phaseAnimationProgress = activePhaseTransition?.progress || 0;
|
|
11188
|
-
|
|
11189
11139
|
if (phaseAnimationProgress > 0) {
|
|
11190
11140
|
debug(
|
|
11191
11141
|
"transition",
|
|
@@ -11215,10 +11165,7 @@ const initUITransition = (container) => {
|
|
|
11215
11165
|
}
|
|
11216
11166
|
|
|
11217
11167
|
const needsOldPhaseClone =
|
|
11218
|
-
(becomesEmpty || becomesPopulated || phaseChange) &&
|
|
11219
|
-
previousChild &&
|
|
11220
|
-
!existingOldPhaseContents[0];
|
|
11221
|
-
|
|
11168
|
+
(becomesEmpty || becomesPopulated || phaseChange) && hadChild;
|
|
11222
11169
|
const phaseDuration = parseInt(
|
|
11223
11170
|
container.getAttribute("data-phase-transition-duration") ||
|
|
11224
11171
|
PHASE_TRANSITION_DURATION,
|
|
@@ -11228,10 +11175,9 @@ const initUITransition = (container) => {
|
|
|
11228
11175
|
setupTransition({
|
|
11229
11176
|
isPhaseTransition: true,
|
|
11230
11177
|
overlay: phaseOverlay,
|
|
11231
|
-
|
|
11232
|
-
|
|
11233
|
-
|
|
11234
|
-
firstChild,
|
|
11178
|
+
needsOldChildNodesClone: needsOldPhaseClone,
|
|
11179
|
+
previousChildNodes,
|
|
11180
|
+
childNodes,
|
|
11235
11181
|
attributeToRemove: ["data-content-key", "data-content-phase"],
|
|
11236
11182
|
});
|
|
11237
11183
|
|
|
@@ -11251,9 +11197,8 @@ const initUITransition = (container) => {
|
|
|
11251
11197
|
`Starting phase transition: ${fromPhase} → ${toPhase}`,
|
|
11252
11198
|
);
|
|
11253
11199
|
|
|
11254
|
-
activePhaseTransition =
|
|
11200
|
+
activePhaseTransition = applyTransition(
|
|
11255
11201
|
transitionController,
|
|
11256
|
-
firstChild,
|
|
11257
11202
|
setupPhaseTransition,
|
|
11258
11203
|
{
|
|
11259
11204
|
duration: phaseDuration,
|
|
@@ -11279,7 +11224,7 @@ const initUITransition = (container) => {
|
|
|
11279
11224
|
}
|
|
11280
11225
|
|
|
11281
11226
|
// Store current child for next transition
|
|
11282
|
-
|
|
11227
|
+
previousChildNodes = childNodes;
|
|
11283
11228
|
lastContentKey = currentContentKey;
|
|
11284
11229
|
if (becomesPopulated) {
|
|
11285
11230
|
hasPopulatedOnce = true;
|
|
@@ -11363,7 +11308,6 @@ const initUITransition = (container) => {
|
|
|
11363
11308
|
characterData: false,
|
|
11364
11309
|
});
|
|
11365
11310
|
|
|
11366
|
-
// Return API
|
|
11367
11311
|
return {
|
|
11368
11312
|
slot,
|
|
11369
11313
|
|
|
@@ -11408,9 +11352,8 @@ const initUITransition = (container) => {
|
|
|
11408
11352
|
};
|
|
11409
11353
|
};
|
|
11410
11354
|
|
|
11411
|
-
const
|
|
11355
|
+
const applyTransition = (
|
|
11412
11356
|
transitionController,
|
|
11413
|
-
newChild,
|
|
11414
11357
|
setupTransition,
|
|
11415
11358
|
{
|
|
11416
11359
|
type,
|
|
@@ -11432,7 +11375,7 @@ const animateTransition = (
|
|
|
11432
11375
|
return null;
|
|
11433
11376
|
}
|
|
11434
11377
|
|
|
11435
|
-
const { cleanup, oldElement, newElement } = setupTransition();
|
|
11378
|
+
const { cleanup, oldElement, newElement, onTeardown } = setupTransition();
|
|
11436
11379
|
// Use precomputed content key states (expected to be provided by caller)
|
|
11437
11380
|
const fromContentKey = fromContentKeyState;
|
|
11438
11381
|
const toContentKey = toContentKeyState;
|
|
@@ -11462,6 +11405,7 @@ const animateTransition = (
|
|
|
11462
11405
|
if (transitions.length === 0) {
|
|
11463
11406
|
debug("transition", "No transitions to animate, cleaning up immediately");
|
|
11464
11407
|
cleanup();
|
|
11408
|
+
onTeardown?.();
|
|
11465
11409
|
onComplete?.();
|
|
11466
11410
|
return null;
|
|
11467
11411
|
}
|
|
@@ -11470,6 +11414,7 @@ const animateTransition = (
|
|
|
11470
11414
|
onFinish: () => {
|
|
11471
11415
|
groupTransition.cancel();
|
|
11472
11416
|
cleanup();
|
|
11417
|
+
onTeardown?.();
|
|
11473
11418
|
onComplete?.();
|
|
11474
11419
|
},
|
|
11475
11420
|
});
|
|
@@ -11706,4 +11651,4 @@ const crossFade = {
|
|
|
11706
11651
|
},
|
|
11707
11652
|
};
|
|
11708
11653
|
|
|
11709
|
-
export { EASING, activeElementSignal, addActiveElementEffect, addAttributeEffect, addWillChange, allowWheelThrough, appendStyles, canInterceptKeys, captureScrollState, createDragGestureController, createDragToMoveGestureController, createHeightTransition, createIterableWeakSet, createOpacityTransition, createPubSub, createStyleController, createTimelineTransition, createTransition, createTranslateXTransition, createValueEffect, createWidthTransition, cubicBezier, dragAfterThreshold, elementIsFocusable, elementIsVisibleForFocus, elementIsVisuallyVisible, findAfter, findAncestor, findBefore, findDescendant, findFocusable, getAvailableHeight, getAvailableWidth, getBorderSizes, getContrastRatio, getDefaultStyles, getDragCoordinates, getDropTargetInfo, getElementSignature, getFirstVisuallyVisibleAncestor, getFocusVisibilityInfo, getHeight, getInnerHeight, getInnerWidth, getMarginSizes, getMaxHeight, getMaxWidth, getMinHeight, getMinWidth, getPaddingSizes, getPositionedParent, getPreferedColorScheme, getScrollContainer, getScrollContainerSet, getScrollRelativeRect, getSelfAndAncestorScrolls, getStyle, getVisuallyVisibleInfo, getWidth, initFlexDetailsSet, initFocusGroup, initPositionSticky, initUITransition, isScrollable, mergeStyles, normalizeStyles, parseCSSColor, pickLightOrDark, pickPositionRelativeTo, prefersDarkColors, prefersLightColors, preventFocusNav, preventFocusNavViaKeyboard, resolveCSSColor, resolveCSSSize, setAttribute, setAttributes, setStyles, startDragToResizeGesture, stickyAsRelativeCoords, stringifyCSSColor, trapFocusInside, trapScrollInside, useActiveElement, useAvailableHeight, useAvailableWidth, useMaxHeight, useMaxWidth, useResizeStatus, visibleRectEffect };
|
|
11654
|
+
export { EASING, activeElementSignal, addActiveElementEffect, addAttributeEffect, addWillChange, allowWheelThrough, appendStyles, canInterceptKeys, captureScrollState, createDragGestureController, createDragToMoveGestureController, createHeightTransition, createIterableWeakSet, createOpacityTransition, createPubSub, createStyleController, createTimelineTransition, createTransition, createTranslateXTransition, createValueEffect, createWidthTransition, cubicBezier, dragAfterThreshold, elementIsFocusable, elementIsVisibleForFocus, elementIsVisuallyVisible, findAfter, findAncestor, findBefore, findDescendant, findFocusable, getAvailableHeight, getAvailableWidth, getBorderSizes, getContrastRatio, getDefaultStyles, getDragCoordinates, getDropTargetInfo, getElementSignature, getFirstVisuallyVisibleAncestor, getFocusVisibilityInfo, getHeight, getInnerHeight, getInnerWidth, getMarginSizes, getMaxHeight, getMaxWidth, getMinHeight, getMinWidth, getOpacity, getPaddingSizes, getPositionedParent, getPreferedColorScheme, getScrollContainer, getScrollContainerSet, getScrollRelativeRect, getSelfAndAncestorScrolls, getStyle, getTranslateX, getTranslateY, getVisuallyVisibleInfo, getWidth, initFlexDetailsSet, initFocusGroup, initPositionSticky, initUITransition, isScrollable, mergeStyles, normalizeStyles, parseCSSColor, pickLightOrDark, pickPositionRelativeTo, prefersDarkColors, prefersLightColors, preventFocusNav, preventFocusNavViaKeyboard, resolveCSSColor, resolveCSSSize, setAttribute, setAttributes, setStyles, startDragToResizeGesture, stickyAsRelativeCoords, stringifyCSSColor, trapFocusInside, trapScrollInside, useActiveElement, useAvailableHeight, useAvailableWidth, useMaxHeight, useMaxWidth, useResizeStatus, visibleRectEffect };
|