@jsenv/dom 0.6.0 → 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 +262 -330
- 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 -1491
- 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
8687
|
|
|
8675
|
-
|
|
8676
|
-
|
|
8677
|
-
|
|
8678
|
-
|
|
8679
|
-
|
|
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
|
-
|
|
8693
|
-
const transform = getComputedStyle(element).transform;
|
|
8694
|
-
const transformMap = parseTransform(transform);
|
|
8695
|
-
const naturalValue = transformMap.get("translateX")?.value || 0;
|
|
8696
|
-
|
|
8697
|
-
// Restore transition attribute if it existed
|
|
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) => {
|
|
@@ -10287,34 +10276,27 @@ const useResizeStatus = (elementRef, { as = "number" } = {}) => {
|
|
|
10287
10276
|
|
|
10288
10277
|
installImportMetaCss(import.meta);
|
|
10289
10278
|
import.meta.css = /* css */ `
|
|
10290
|
-
.ui_transition_container
|
|
10291
|
-
|
|
10292
|
-
|
|
10293
|
-
|
|
10294
|
-
|
|
10295
|
-
|
|
10296
|
-
.ui_transition_outer_wrapper {
|
|
10279
|
+
.ui_transition_container,
|
|
10280
|
+
.ui_transition_outer_wrapper,
|
|
10281
|
+
.ui_transition_measure_wrapper,
|
|
10282
|
+
.ui_transition_slot,
|
|
10283
|
+
.ui_transition_phase_overlay,
|
|
10284
|
+
.ui_transition_content_overlay {
|
|
10297
10285
|
display: inline-flex;
|
|
10298
|
-
|
|
10286
|
+
width: 100%;
|
|
10287
|
+
height: 100%;
|
|
10299
10288
|
}
|
|
10300
10289
|
|
|
10301
|
-
.ui_transition_measure_wrapper {
|
|
10302
|
-
|
|
10303
|
-
flex: 1;
|
|
10290
|
+
.ui_transition_measure_wrapper[data-transition-translate-x] {
|
|
10291
|
+
overflow: hidden;
|
|
10304
10292
|
}
|
|
10305
10293
|
|
|
10294
|
+
.ui_transition_container,
|
|
10306
10295
|
.ui_transition_slot {
|
|
10307
10296
|
position: relative;
|
|
10308
|
-
display: inline-flex;
|
|
10309
|
-
flex: 1;
|
|
10310
|
-
}
|
|
10311
|
-
|
|
10312
|
-
.ui_transition_phase_overlay {
|
|
10313
|
-
position: absolute;
|
|
10314
|
-
inset: 0;
|
|
10315
|
-
pointer-events: none;
|
|
10316
10297
|
}
|
|
10317
10298
|
|
|
10299
|
+
.ui_transition_phase_overlay,
|
|
10318
10300
|
.ui_transition_content_overlay {
|
|
10319
10301
|
position: absolute;
|
|
10320
10302
|
inset: 0;
|
|
@@ -10329,11 +10311,15 @@ const DEBUG = {
|
|
|
10329
10311
|
};
|
|
10330
10312
|
|
|
10331
10313
|
// Utility function to format content key states consistently for debug logs
|
|
10332
|
-
const formatContentKeyState = (
|
|
10314
|
+
const formatContentKeyState = (
|
|
10315
|
+
contentKey,
|
|
10316
|
+
hasChildren,
|
|
10317
|
+
hasTextNode = false,
|
|
10318
|
+
) => {
|
|
10333
10319
|
if (hasTextNode) {
|
|
10334
10320
|
return "[text]";
|
|
10335
10321
|
}
|
|
10336
|
-
if (!
|
|
10322
|
+
if (!hasChildren) {
|
|
10337
10323
|
return "[empty]";
|
|
10338
10324
|
}
|
|
10339
10325
|
if (contentKey === null || contentKey === undefined) {
|
|
@@ -10354,6 +10340,7 @@ const initUITransition = (container) => {
|
|
|
10354
10340
|
...DEBUG,
|
|
10355
10341
|
transition: container.hasAttribute("data-debug-transition"),
|
|
10356
10342
|
};
|
|
10343
|
+
const debugClones = container.hasAttribute("data-debug-clones");
|
|
10357
10344
|
|
|
10358
10345
|
const debug = (type, ...args) => {
|
|
10359
10346
|
if (localDebug[type]) {
|
|
@@ -10378,17 +10365,6 @@ const initUITransition = (container) => {
|
|
|
10378
10365
|
".ui_transition_content_overlay",
|
|
10379
10366
|
);
|
|
10380
10367
|
|
|
10381
|
-
if (!phaseOverlay) {
|
|
10382
|
-
phaseOverlay = document.createElement("div");
|
|
10383
|
-
phaseOverlay.className = "ui_transition_phase_overlay";
|
|
10384
|
-
measureWrapper.appendChild(phaseOverlay);
|
|
10385
|
-
}
|
|
10386
|
-
if (!contentOverlay) {
|
|
10387
|
-
contentOverlay = document.createElement("div");
|
|
10388
|
-
contentOverlay.className = "ui_transition_content_overlay";
|
|
10389
|
-
container.appendChild(contentOverlay);
|
|
10390
|
-
}
|
|
10391
|
-
|
|
10392
10368
|
if (
|
|
10393
10369
|
!outerWrapper ||
|
|
10394
10370
|
!measureWrapper ||
|
|
@@ -10431,7 +10407,7 @@ const initUITransition = (container) => {
|
|
|
10431
10407
|
|
|
10432
10408
|
// Child state
|
|
10433
10409
|
let lastContentKey = null;
|
|
10434
|
-
let
|
|
10410
|
+
let previousChildNodes = [];
|
|
10435
10411
|
let isContentPhase = false; // Current state: true when showing content phase (loading/error)
|
|
10436
10412
|
let wasContentPhase = false; // Previous state for comparison
|
|
10437
10413
|
|
|
@@ -10660,40 +10636,48 @@ const initUITransition = (container) => {
|
|
|
10660
10636
|
const setupTransition = ({
|
|
10661
10637
|
isPhaseTransition = false,
|
|
10662
10638
|
overlay,
|
|
10663
|
-
|
|
10664
|
-
|
|
10665
|
-
|
|
10666
|
-
firstChild,
|
|
10639
|
+
needsOldChildNodesClone,
|
|
10640
|
+
previousChildNodes,
|
|
10641
|
+
childNodes,
|
|
10667
10642
|
attributeToRemove = [],
|
|
10668
10643
|
}) => {
|
|
10669
|
-
let oldChild = null;
|
|
10670
10644
|
let cleanup = () => {};
|
|
10671
|
-
|
|
10645
|
+
let elementToImpact;
|
|
10672
10646
|
|
|
10673
|
-
if (
|
|
10674
|
-
|
|
10647
|
+
if (overlay.childNodes.length > 0) {
|
|
10648
|
+
elementToImpact = overlay;
|
|
10649
|
+
cleanup = () => {
|
|
10650
|
+
if (!debugClones) {
|
|
10651
|
+
overlay.innerHTML = "";
|
|
10652
|
+
}
|
|
10653
|
+
};
|
|
10675
10654
|
debug(
|
|
10676
10655
|
"transition",
|
|
10677
10656
|
`Continuing from current ${isPhaseTransition ? "phase" : "content"} transition element`,
|
|
10678
10657
|
);
|
|
10679
|
-
|
|
10680
|
-
} else if (needsOldChildClone) {
|
|
10658
|
+
} else if (needsOldChildNodesClone) {
|
|
10681
10659
|
overlay.innerHTML = "";
|
|
10682
|
-
|
|
10683
|
-
|
|
10684
|
-
|
|
10685
|
-
|
|
10686
|
-
|
|
10687
|
-
|
|
10688
|
-
|
|
10689
|
-
|
|
10690
|
-
|
|
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
|
+
};
|
|
10691
10676
|
debug(
|
|
10692
10677
|
"transition",
|
|
10693
10678
|
`Cloned previous child for ${isPhaseTransition ? "phase" : "content"} transition:`,
|
|
10694
|
-
getElementSignature(
|
|
10679
|
+
getElementSignature(previousChildNodes),
|
|
10695
10680
|
);
|
|
10696
|
-
cleanup = () => oldChild.remove();
|
|
10697
10681
|
} else {
|
|
10698
10682
|
overlay.innerHTML = "";
|
|
10699
10683
|
debug(
|
|
@@ -10709,16 +10693,15 @@ const initUITransition = (container) => {
|
|
|
10709
10693
|
let newElement;
|
|
10710
10694
|
if (isPhaseTransition) {
|
|
10711
10695
|
// Phase transitions work on individual elements
|
|
10712
|
-
oldElement =
|
|
10713
|
-
newElement =
|
|
10696
|
+
oldElement = elementToImpact;
|
|
10697
|
+
newElement = slot;
|
|
10714
10698
|
} else {
|
|
10715
10699
|
// Content transitions work at container level and can outlive content phase changes
|
|
10716
|
-
oldElement =
|
|
10717
|
-
newElement =
|
|
10700
|
+
oldElement = previousChildNodes.length ? elementToImpact : null;
|
|
10701
|
+
newElement = childNodes.length ? measureWrapper : null;
|
|
10718
10702
|
}
|
|
10719
10703
|
|
|
10720
10704
|
return {
|
|
10721
|
-
oldChild,
|
|
10722
10705
|
cleanup,
|
|
10723
10706
|
oldElement,
|
|
10724
10707
|
newElement,
|
|
@@ -10738,102 +10721,75 @@ const initUITransition = (container) => {
|
|
|
10738
10721
|
|
|
10739
10722
|
try {
|
|
10740
10723
|
isUpdating = true;
|
|
10741
|
-
const
|
|
10742
|
-
const childUIName = firstChild?.getAttribute("data-ui-name");
|
|
10724
|
+
const childNodes = Array.from(slot.childNodes);
|
|
10743
10725
|
if (localDebug.transition) {
|
|
10744
10726
|
const updateLabel =
|
|
10745
|
-
|
|
10746
|
-
|
|
10727
|
+
childNodes.length === 0
|
|
10728
|
+
? "cleared/empty"
|
|
10729
|
+
: childNodes.length === 1
|
|
10730
|
+
? getElementSignature(childNodes[0])
|
|
10731
|
+
: getElementSignature(slot);
|
|
10747
10732
|
console.group(`UI Update: ${updateLabel} (reason: ${reason})`);
|
|
10748
10733
|
}
|
|
10749
10734
|
|
|
10750
|
-
//
|
|
10751
|
-
|
|
10752
|
-
|
|
10753
|
-
|
|
10754
|
-
|
|
10755
|
-
console.warn(
|
|
10756
|
-
"UI Transition: Text nodes in transition slots are not supported. Please wrap text content in an element.",
|
|
10757
|
-
{ slot, textContent: slot.textContent.trim() },
|
|
10758
|
-
);
|
|
10759
|
-
}
|
|
10760
|
-
|
|
10761
|
-
// Check for multiple elements in the slot (not supported yet)
|
|
10762
|
-
const hasMultipleElements = slot.children.length > 1;
|
|
10763
|
-
if (hasMultipleElements) {
|
|
10764
|
-
console.warn(
|
|
10765
|
-
"UI Transition: Multiple elements in transition slots are not supported yet. Please use a single container element.",
|
|
10766
|
-
{ slot, elementCount: slot.children.length },
|
|
10767
|
-
);
|
|
10768
|
-
}
|
|
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;
|
|
10769
10740
|
|
|
10770
10741
|
// Prefer data-content-key on child, fallback to slot
|
|
10771
10742
|
let currentContentKey = null;
|
|
10772
10743
|
let slotContentKey = slot.getAttribute("data-content-key");
|
|
10773
|
-
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
|
+
}
|
|
10774
10759
|
if (childContentKey && slotContentKey) {
|
|
10775
10760
|
console.warn(
|
|
10776
|
-
|
|
10777
|
-
{ childContentKey, slotContentKey },
|
|
10761
|
+
`Slot and slot child both have a [data-content-key]. Slot is ${slotContentKey} and child is ${childContentKey}, using the child.`,
|
|
10778
10762
|
);
|
|
10779
10763
|
}
|
|
10780
10764
|
currentContentKey = childContentKey || slotContentKey || null;
|
|
10781
|
-
|
|
10782
|
-
// Determine transition scenarios early for early registration check
|
|
10783
|
-
const hadChild = previousChild !== null;
|
|
10784
|
-
const hasChild = firstChild !== null;
|
|
10785
|
-
|
|
10786
|
-
// Check for text nodes in previous state (reconstruct from previousChild)
|
|
10787
|
-
const hadTextNode =
|
|
10788
|
-
previousChild && previousChild.nodeType === Node.TEXT_NODE;
|
|
10789
|
-
|
|
10790
10765
|
// Compute formatted content key states ONCE per mutation (requirement: max 2 calls)
|
|
10791
10766
|
const previousContentKeyState = formatContentKeyState(
|
|
10792
10767
|
lastContentKey,
|
|
10793
10768
|
hadChild,
|
|
10794
|
-
hadTextNode,
|
|
10795
10769
|
);
|
|
10796
10770
|
const currentContentKeyState = formatContentKeyState(
|
|
10797
10771
|
currentContentKey,
|
|
10798
10772
|
hasChild,
|
|
10799
|
-
hasTextNode,
|
|
10800
10773
|
);
|
|
10801
|
-
|
|
10802
10774
|
// Track previous key before any potential early registration update
|
|
10803
10775
|
const prevKeyBeforeRegistration = lastContentKey;
|
|
10804
|
-
|
|
10805
|
-
// Prepare phase info early so logging can be unified (even for early return)
|
|
10806
|
-
wasContentPhase = isContentPhase;
|
|
10807
|
-
isContentPhase = firstChild
|
|
10808
|
-
? firstChild.hasAttribute("data-content-phase")
|
|
10809
|
-
: true; // empty (no child) is treated as content phase
|
|
10810
|
-
|
|
10811
10776
|
const previousIsContentPhase = !hadChild || wasContentPhase;
|
|
10812
10777
|
const currentIsContentPhase = !hasChild || isContentPhase;
|
|
10813
10778
|
|
|
10814
|
-
// Early conceptual registration path: empty slot
|
|
10815
|
-
const shouldGiveUpEarlyAndJustRegister =
|
|
10816
|
-
(!hadChild && !hasChild && !hasTextNode) ||
|
|
10817
|
-
hasTextNode ||
|
|
10818
|
-
hasMultipleElements;
|
|
10779
|
+
// Early conceptual registration path: empty slot
|
|
10780
|
+
const shouldGiveUpEarlyAndJustRegister = !hadChild && !hasChild;
|
|
10819
10781
|
let earlyAction = null;
|
|
10820
10782
|
if (shouldGiveUpEarlyAndJustRegister) {
|
|
10821
|
-
|
|
10822
|
-
|
|
10823
|
-
|
|
10824
|
-
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";
|
|
10825
10791
|
} else {
|
|
10826
|
-
|
|
10827
|
-
const keyChanged = prevKey !== currentContentKey;
|
|
10828
|
-
if (!keyChanged) {
|
|
10829
|
-
earlyAction = "unchanged";
|
|
10830
|
-
} else if (prevKey === null && currentContentKey !== null) {
|
|
10831
|
-
earlyAction = "registered";
|
|
10832
|
-
} else if (prevKey !== null && currentContentKey === null) {
|
|
10833
|
-
earlyAction = "cleared";
|
|
10834
|
-
} else {
|
|
10835
|
-
earlyAction = "changed";
|
|
10836
|
-
}
|
|
10792
|
+
earlyAction = "changed";
|
|
10837
10793
|
}
|
|
10838
10794
|
// Will update lastContentKey after unified logging
|
|
10839
10795
|
}
|
|
@@ -10884,7 +10840,7 @@ const initUITransition = (container) => {
|
|
|
10884
10840
|
|
|
10885
10841
|
// Handle resize observation
|
|
10886
10842
|
stopResizeObserver();
|
|
10887
|
-
if (
|
|
10843
|
+
if (hasChild && !isContentPhase) {
|
|
10888
10844
|
startResizeObserver();
|
|
10889
10845
|
debug("size", "Observing child resize");
|
|
10890
10846
|
}
|
|
@@ -10910,11 +10866,7 @@ const initUITransition = (container) => {
|
|
|
10910
10866
|
|
|
10911
10867
|
// Content key change when either slot or child has data-content-key and it changed
|
|
10912
10868
|
let shouldDoContentTransition = false;
|
|
10913
|
-
if (
|
|
10914
|
-
(slot.getAttribute("data-content-key") ||
|
|
10915
|
-
firstChild?.getAttribute("data-content-key")) &&
|
|
10916
|
-
lastContentKey !== null
|
|
10917
|
-
) {
|
|
10869
|
+
if (currentContentKey && lastContentKey !== null) {
|
|
10918
10870
|
shouldDoContentTransition = currentContentKey !== lastContentKey;
|
|
10919
10871
|
}
|
|
10920
10872
|
|
|
@@ -10998,7 +10950,7 @@ const initUITransition = (container) => {
|
|
|
10998
10950
|
}
|
|
10999
10951
|
|
|
11000
10952
|
// Register state and mark initial population done
|
|
11001
|
-
|
|
10953
|
+
previousChildNodes = childNodes;
|
|
11002
10954
|
lastContentKey = currentContentKey;
|
|
11003
10955
|
hasPopulatedOnce = true;
|
|
11004
10956
|
if (localDebug.transition) {
|
|
@@ -11071,11 +11023,7 @@ const initUITransition = (container) => {
|
|
|
11071
11023
|
shouldDoContentTransitionIncludingPopulation &&
|
|
11072
11024
|
!preserveOnlyContentTransition
|
|
11073
11025
|
) {
|
|
11074
|
-
const existingOldContents = contentOverlay.querySelectorAll(
|
|
11075
|
-
"[data-ui-transition-old]",
|
|
11076
|
-
);
|
|
11077
11026
|
const animationProgress = activeContentTransition?.progress || 0;
|
|
11078
|
-
|
|
11079
11027
|
if (animationProgress > 0) {
|
|
11080
11028
|
debug(
|
|
11081
11029
|
"transition",
|
|
@@ -11089,7 +11037,6 @@ const initUITransition = (container) => {
|
|
|
11089
11037
|
const canContinueSmoothly =
|
|
11090
11038
|
activeContentTransitionType === newTransitionType &&
|
|
11091
11039
|
activeContentTransition;
|
|
11092
|
-
|
|
11093
11040
|
if (canContinueSmoothly) {
|
|
11094
11041
|
debug(
|
|
11095
11042
|
"transition",
|
|
@@ -11110,11 +11057,8 @@ const initUITransition = (container) => {
|
|
|
11110
11057
|
activeContentTransition.cancel();
|
|
11111
11058
|
}
|
|
11112
11059
|
|
|
11113
|
-
const
|
|
11114
|
-
(contentChange || becomesEmpty) &&
|
|
11115
|
-
previousChild &&
|
|
11116
|
-
!existingOldContents[0];
|
|
11117
|
-
|
|
11060
|
+
const needsOldChildNodesClone =
|
|
11061
|
+
(contentChange || becomesEmpty) && hadChild;
|
|
11118
11062
|
const duration = parseInt(
|
|
11119
11063
|
container.getAttribute("data-content-transition-duration") ||
|
|
11120
11064
|
CONTENT_TRANSITION_DURATION,
|
|
@@ -11127,10 +11071,9 @@ const initUITransition = (container) => {
|
|
|
11127
11071
|
setupTransition({
|
|
11128
11072
|
isPhaseTransition: false,
|
|
11129
11073
|
overlay: contentOverlay,
|
|
11130
|
-
|
|
11131
|
-
|
|
11132
|
-
|
|
11133
|
-
firstChild,
|
|
11074
|
+
needsOldChildNodesClone,
|
|
11075
|
+
previousChildNodes,
|
|
11076
|
+
childNodes,
|
|
11134
11077
|
attributeToRemove: ["data-content-key"],
|
|
11135
11078
|
});
|
|
11136
11079
|
|
|
@@ -11149,9 +11092,8 @@ const initUITransition = (container) => {
|
|
|
11149
11092
|
}
|
|
11150
11093
|
}
|
|
11151
11094
|
|
|
11152
|
-
activeContentTransition =
|
|
11095
|
+
activeContentTransition = applyTransition(
|
|
11153
11096
|
transitionController,
|
|
11154
|
-
firstChild,
|
|
11155
11097
|
setupContentTransition,
|
|
11156
11098
|
{
|
|
11157
11099
|
duration,
|
|
@@ -11193,12 +11135,7 @@ const initUITransition = (container) => {
|
|
|
11193
11135
|
if (shouldDoPhaseTransition) {
|
|
11194
11136
|
const phaseTransitionType =
|
|
11195
11137
|
container.getAttribute("data-phase-transition") || PHASE_TRANSITION;
|
|
11196
|
-
|
|
11197
|
-
const existingOldPhaseContents = phaseOverlay.querySelectorAll(
|
|
11198
|
-
"[data-ui-transition-old]",
|
|
11199
|
-
);
|
|
11200
11138
|
const phaseAnimationProgress = activePhaseTransition?.progress || 0;
|
|
11201
|
-
|
|
11202
11139
|
if (phaseAnimationProgress > 0) {
|
|
11203
11140
|
debug(
|
|
11204
11141
|
"transition",
|
|
@@ -11228,10 +11165,7 @@ const initUITransition = (container) => {
|
|
|
11228
11165
|
}
|
|
11229
11166
|
|
|
11230
11167
|
const needsOldPhaseClone =
|
|
11231
|
-
(becomesEmpty || becomesPopulated || phaseChange) &&
|
|
11232
|
-
previousChild &&
|
|
11233
|
-
!existingOldPhaseContents[0];
|
|
11234
|
-
|
|
11168
|
+
(becomesEmpty || becomesPopulated || phaseChange) && hadChild;
|
|
11235
11169
|
const phaseDuration = parseInt(
|
|
11236
11170
|
container.getAttribute("data-phase-transition-duration") ||
|
|
11237
11171
|
PHASE_TRANSITION_DURATION,
|
|
@@ -11241,10 +11175,9 @@ const initUITransition = (container) => {
|
|
|
11241
11175
|
setupTransition({
|
|
11242
11176
|
isPhaseTransition: true,
|
|
11243
11177
|
overlay: phaseOverlay,
|
|
11244
|
-
|
|
11245
|
-
|
|
11246
|
-
|
|
11247
|
-
firstChild,
|
|
11178
|
+
needsOldChildNodesClone: needsOldPhaseClone,
|
|
11179
|
+
previousChildNodes,
|
|
11180
|
+
childNodes,
|
|
11248
11181
|
attributeToRemove: ["data-content-key", "data-content-phase"],
|
|
11249
11182
|
});
|
|
11250
11183
|
|
|
@@ -11264,9 +11197,8 @@ const initUITransition = (container) => {
|
|
|
11264
11197
|
`Starting phase transition: ${fromPhase} → ${toPhase}`,
|
|
11265
11198
|
);
|
|
11266
11199
|
|
|
11267
|
-
activePhaseTransition =
|
|
11200
|
+
activePhaseTransition = applyTransition(
|
|
11268
11201
|
transitionController,
|
|
11269
|
-
firstChild,
|
|
11270
11202
|
setupPhaseTransition,
|
|
11271
11203
|
{
|
|
11272
11204
|
duration: phaseDuration,
|
|
@@ -11292,7 +11224,7 @@ const initUITransition = (container) => {
|
|
|
11292
11224
|
}
|
|
11293
11225
|
|
|
11294
11226
|
// Store current child for next transition
|
|
11295
|
-
|
|
11227
|
+
previousChildNodes = childNodes;
|
|
11296
11228
|
lastContentKey = currentContentKey;
|
|
11297
11229
|
if (becomesPopulated) {
|
|
11298
11230
|
hasPopulatedOnce = true;
|
|
@@ -11376,7 +11308,6 @@ const initUITransition = (container) => {
|
|
|
11376
11308
|
characterData: false,
|
|
11377
11309
|
});
|
|
11378
11310
|
|
|
11379
|
-
// Return API
|
|
11380
11311
|
return {
|
|
11381
11312
|
slot,
|
|
11382
11313
|
|
|
@@ -11421,9 +11352,8 @@ const initUITransition = (container) => {
|
|
|
11421
11352
|
};
|
|
11422
11353
|
};
|
|
11423
11354
|
|
|
11424
|
-
const
|
|
11355
|
+
const applyTransition = (
|
|
11425
11356
|
transitionController,
|
|
11426
|
-
newChild,
|
|
11427
11357
|
setupTransition,
|
|
11428
11358
|
{
|
|
11429
11359
|
type,
|
|
@@ -11445,7 +11375,7 @@ const animateTransition = (
|
|
|
11445
11375
|
return null;
|
|
11446
11376
|
}
|
|
11447
11377
|
|
|
11448
|
-
const { cleanup, oldElement, newElement } = setupTransition();
|
|
11378
|
+
const { cleanup, oldElement, newElement, onTeardown } = setupTransition();
|
|
11449
11379
|
// Use precomputed content key states (expected to be provided by caller)
|
|
11450
11380
|
const fromContentKey = fromContentKeyState;
|
|
11451
11381
|
const toContentKey = toContentKeyState;
|
|
@@ -11475,6 +11405,7 @@ const animateTransition = (
|
|
|
11475
11405
|
if (transitions.length === 0) {
|
|
11476
11406
|
debug("transition", "No transitions to animate, cleaning up immediately");
|
|
11477
11407
|
cleanup();
|
|
11408
|
+
onTeardown?.();
|
|
11478
11409
|
onComplete?.();
|
|
11479
11410
|
return null;
|
|
11480
11411
|
}
|
|
@@ -11483,6 +11414,7 @@ const animateTransition = (
|
|
|
11483
11414
|
onFinish: () => {
|
|
11484
11415
|
groupTransition.cancel();
|
|
11485
11416
|
cleanup();
|
|
11417
|
+
onTeardown?.();
|
|
11486
11418
|
onComplete?.();
|
|
11487
11419
|
},
|
|
11488
11420
|
});
|
|
@@ -11719,4 +11651,4 @@ const crossFade = {
|
|
|
11719
11651
|
},
|
|
11720
11652
|
};
|
|
11721
11653
|
|
|
11722
|
-
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 };
|