@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.
Files changed (109) hide show
  1. package/dist/jsenv_dom.js +259 -314
  2. package/package.json +2 -4
  3. package/index.js +0 -124
  4. package/src/attr/add_attribute_effect.js +0 -93
  5. package/src/attr/attributes.js +0 -32
  6. package/src/color/color_constrast.js +0 -69
  7. package/src/color/color_parsing.js +0 -319
  8. package/src/color/color_scheme.js +0 -28
  9. package/src/color/pick_light_or_dark.js +0 -34
  10. package/src/color/resolve_css_color.js +0 -60
  11. package/src/demos/3_columns_resize_demo.html +0 -84
  12. package/src/demos/3_rows_resize_demo.html +0 -89
  13. package/src/demos/aside_and_main_demo.html +0 -93
  14. package/src/demos/coordinates_demo.html +0 -450
  15. package/src/demos/document_autoscroll_demo.html +0 -517
  16. package/src/demos/drag_gesture_constraints_demo.html +0 -701
  17. package/src/demos/drag_gesture_demo.html +0 -1047
  18. package/src/demos/drag_gesture_element_to_impact_demo.html +0 -445
  19. package/src/demos/drag_reference_element_demo.html +0 -480
  20. package/src/demos/flex_details_set_demo.html +0 -302
  21. package/src/demos/flex_details_set_demo_2.html +0 -315
  22. package/src/demos/visible_rect_demo.html +0 -525
  23. package/src/element_signature.js +0 -100
  24. package/src/interaction/drag/constraint_feedback_line.js +0 -92
  25. package/src/interaction/drag/drag_constraint.js +0 -659
  26. package/src/interaction/drag/drag_debug_markers.js +0 -635
  27. package/src/interaction/drag/drag_element_positioner.js +0 -382
  28. package/src/interaction/drag/drag_gesture.js +0 -566
  29. package/src/interaction/drag/drag_resize_demo.html +0 -571
  30. package/src/interaction/drag/drag_to_move.js +0 -301
  31. package/src/interaction/drag/drag_to_resize_gesture.js +0 -68
  32. package/src/interaction/drag/drop_target_detection.js +0 -148
  33. package/src/interaction/drag/sticky_frontiers.js +0 -160
  34. package/src/interaction/event_marker.js +0 -14
  35. package/src/interaction/focus/active_element.js +0 -33
  36. package/src/interaction/focus/arrow_navigation.js +0 -599
  37. package/src/interaction/focus/element_is_focusable.js +0 -57
  38. package/src/interaction/focus/element_visibility.js +0 -111
  39. package/src/interaction/focus/find_focusable.js +0 -21
  40. package/src/interaction/focus/focus_group.js +0 -91
  41. package/src/interaction/focus/focus_group_registry.js +0 -12
  42. package/src/interaction/focus/focus_nav.js +0 -12
  43. package/src/interaction/focus/focus_nav_event_marker.js +0 -14
  44. package/src/interaction/focus/focus_trap.js +0 -105
  45. package/src/interaction/focus/tab_navigation.js +0 -128
  46. package/src/interaction/focus/tests/focus_group_skip_tab_test.html +0 -206
  47. package/src/interaction/focus/tests/tree_focus_test.html +0 -304
  48. package/src/interaction/focus/tests/tree_focus_test.jsx +0 -261
  49. package/src/interaction/focus/tests/tree_focus_test_preact.html +0 -13
  50. package/src/interaction/isolate_interactions.js +0 -161
  51. package/src/interaction/keyboard.js +0 -26
  52. package/src/interaction/scroll/capture_scroll.js +0 -47
  53. package/src/interaction/scroll/is_scrollable.js +0 -159
  54. package/src/interaction/scroll/scroll_container.js +0 -110
  55. package/src/interaction/scroll/scroll_trap.js +0 -44
  56. package/src/interaction/scroll/scrollbar_size.js +0 -20
  57. package/src/interaction/scroll/wheel_through.js +0 -138
  58. package/src/iterable_weak_set.js +0 -66
  59. package/src/position/dom_coords.js +0 -340
  60. package/src/position/offset_parent.js +0 -15
  61. package/src/position/position_fixed.js +0 -15
  62. package/src/position/position_sticky.js +0 -213
  63. package/src/position/sticky_rect.js +0 -79
  64. package/src/position/visible_rect.js +0 -486
  65. package/src/pub_sub.js +0 -31
  66. package/src/size/can_take_size.js +0 -11
  67. package/src/size/details_content_full_height.js +0 -63
  68. package/src/size/flex_details_set.js +0 -974
  69. package/src/size/get_available_height.js +0 -22
  70. package/src/size/get_available_width.js +0 -22
  71. package/src/size/get_border_sizes.js +0 -14
  72. package/src/size/get_height.js +0 -4
  73. package/src/size/get_inner_height.js +0 -15
  74. package/src/size/get_inner_width.js +0 -15
  75. package/src/size/get_margin_sizes.js +0 -10
  76. package/src/size/get_max_height.js +0 -57
  77. package/src/size/get_max_width.js +0 -47
  78. package/src/size/get_min_height.js +0 -14
  79. package/src/size/get_min_width.js +0 -14
  80. package/src/size/get_padding_sizes.js +0 -10
  81. package/src/size/get_width.js +0 -4
  82. package/src/size/hooks/use_available_height.js +0 -27
  83. package/src/size/hooks/use_available_width.js +0 -27
  84. package/src/size/hooks/use_max_height.js +0 -10
  85. package/src/size/hooks/use_max_width.js +0 -10
  86. package/src/size/hooks/use_resize_status.js +0 -62
  87. package/src/size/resize.js +0 -695
  88. package/src/size/resolve_css_size.js +0 -32
  89. package/src/style/dom_styles.js +0 -97
  90. package/src/style/style_composition.js +0 -121
  91. package/src/style/style_controller.js +0 -345
  92. package/src/style/style_default.js +0 -153
  93. package/src/style/style_default_demo.html +0 -128
  94. package/src/style/style_parsing.js +0 -375
  95. package/src/transition/demos/animation_resumption_test.xhtml +0 -500
  96. package/src/transition/demos/height_toggle_test.xhtml +0 -515
  97. package/src/transition/dom_transition.js +0 -254
  98. package/src/transition/easing.js +0 -48
  99. package/src/transition/group_transition.js +0 -261
  100. package/src/transition/transform_style_parser.js +0 -32
  101. package/src/transition/transition_playback.js +0 -366
  102. package/src/transition/transition_timeline.js +0 -79
  103. package/src/traversal.js +0 -247
  104. package/src/ui_transition/demos/content_states_transition_demo.html +0 -628
  105. package/src/ui_transition/demos/smooth_height_transition_demo.html +0 -149
  106. package/src/ui_transition/demos/transition_testing.html +0 -354
  107. package/src/ui_transition/ui_transition.js +0 -1470
  108. package/src/utils.js +0 -69
  109. 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
- return undefined;
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, context, "px", propertyName);
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, context, "deg", propertyName);
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, context, "", propertyName);
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, context, unit, propertyName) => {
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
- // For js context, only convert px values to numbers
527
- if (unit === "px" && value.endsWith("px")) {
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
- const hasStyle = Object.hasOwn(styles, propertyName);
1018
- if (!hasStyle) {
1019
- return;
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
- installImportMetaCss(import.meta);
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
- const valueWithUnit = `${value}px`;
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
- element.removeAttribute("data-transition-height");
8536
- element.style.removeProperty("--ui-transition-height");
8537
- restoreWillChange();
8590
+ transitionStyleController.delete(element, "height");
8538
8591
  },
8539
8592
  restore: () => {
8540
- element.removeAttribute("data-transition-height");
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
- const valueWithUnit = `${value}px`;
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
- element.removeAttribute("data-transition-width");
8569
- element.style.removeProperty("--ui-transition-width");
8570
- restoreWillChange();
8617
+ transitionStyleController.delete(element, "width");
8571
8618
  },
8572
8619
  restore: () => {
8573
- element.removeAttribute("data-transition-width");
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
- element.setAttribute("data-transition-opacity", value);
8597
- element.style.setProperty("--ui-transition-opacity", value);
8641
+ transitionStyleController.set(element, { opacity: value });
8598
8642
  },
8599
8643
  teardown: () => {
8600
- element.removeAttribute("data-transition-opacity");
8601
- element.style.removeProperty("--ui-transition-opacity");
8602
- restoreWillChange();
8644
+ transitionStyleController.delete(element, "opacity");
8603
8645
  },
8604
8646
  restore: () => {
8605
- element.removeAttribute("data-transition-opacity");
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
- const valueWithUnit = `${value}${unit}`;
8641
- element.setAttribute("data-transition-translate-x", valueWithUnit);
8642
- element.style.setProperty(
8643
- "--ui-transition-translate-x",
8644
- valueWithUnit,
8645
- );
8669
+ transitionStyleController.set(element, {
8670
+ transform: {
8671
+ translateX: value,
8672
+ },
8673
+ });
8646
8674
  },
8647
8675
  teardown: () => {
8648
- restoreWillChange();
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
- element.removeAttribute("data-transition-translate-x");
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
- 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) => {
@@ -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: fit-content;
10296
- height: fit-content;
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 = (contentKey, hasChild, hasTextNode = false) => {
10314
+ const formatContentKeyState = (
10315
+ contentKey,
10316
+ hasChildren,
10317
+ hasTextNode = false,
10318
+ ) => {
10320
10319
  if (hasTextNode) {
10321
10320
  return "[text]";
10322
10321
  }
10323
- if (!hasChild) {
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 previousChild = null;
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
- existingOldContents,
10651
- needsOldChildClone,
10652
- previousChild,
10653
- firstChild,
10639
+ needsOldChildNodesClone,
10640
+ previousChildNodes,
10641
+ childNodes,
10654
10642
  attributeToRemove = [],
10655
10643
  }) => {
10656
- let oldChild = null;
10657
10644
  let cleanup = () => {};
10658
- const currentTransitionElement = existingOldContents[0];
10645
+ let elementToImpact;
10659
10646
 
10660
- if (currentTransitionElement) {
10661
- oldChild = currentTransitionElement;
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
- cleanup = () => oldChild.remove();
10667
- } else if (needsOldChildClone) {
10658
+ } else if (needsOldChildNodesClone) {
10668
10659
  overlay.innerHTML = "";
10669
-
10670
- // Clone the individual element for the transition
10671
- oldChild = previousChild.cloneNode(true);
10672
-
10673
- // Remove specified attributes
10674
- attributeToRemove.forEach((attr) => oldChild.removeAttribute(attr));
10675
-
10676
- oldChild.setAttribute("data-ui-transition-old", "");
10677
- overlay.appendChild(oldChild);
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(previousChild),
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 = oldChild;
10700
- newElement = firstChild;
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 = oldChild ? overlay : null;
10704
- newElement = firstChild ? measureWrapper : null;
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 firstChild = slot.children[0] || null;
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
- childUIName ||
10733
- (firstChild ? getElementSignature(firstChild) : "cleared/empty");
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
- // Check for text nodes in the slot (not supported)
10738
- const hasTextNode = Array.from(slot.childNodes).some(
10739
- (node) => node.nodeType === Node.TEXT_NODE && node.textContent.trim(),
10740
- );
10741
- if (hasTextNode) {
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 = firstChild?.getAttribute("data-content-key");
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
- "Both data-content-key found on child and ui_transition_slot. Using child value.",
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, text nodes, or multiple elements (no visual transition)
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
- if (hasTextNode) {
10809
- earlyAction = "text_nodes_unsupported";
10810
- } else if (hasMultipleElements) {
10811
- earlyAction = "multiple_elements_unsupported";
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
- const prevKey = prevKeyBeforeRegistration;
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 (firstChild && !isContentPhase) {
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
- previousChild = firstChild;
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 needsOldChildClone =
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
- existingOldContents,
11118
- needsOldChildClone,
11119
- previousChild,
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 = animateTransition(
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
- existingOldContents: existingOldPhaseContents,
11232
- needsOldChildClone: needsOldPhaseClone,
11233
- previousChild,
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 = animateTransition(
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
- previousChild = firstChild;
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 animateTransition = (
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 };