@jsenv/dom 0.8.7 → 0.9.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 (2) hide show
  1. package/dist/jsenv_dom.js +104 -73
  2. package/package.json +9 -4
package/dist/jsenv_dom.js CHANGED
@@ -104,29 +104,31 @@ const getElementSignature = (element) => {
104
104
  if (element.nodeType === Node.TEXT_NODE) {
105
105
  return `#text(${getElementSignature(element.nodeValue)})`;
106
106
  }
107
+ if (element instanceof HTMLElement) {
108
+ const tagName = element.tagName.toLowerCase();
109
+ const dataUIName = element.getAttribute("data-ui-name");
110
+ if (dataUIName) {
111
+ return `${tagName}[data-ui-name="${dataUIName}"]`;
112
+ }
113
+ if (element === document.body) {
114
+ return "<body>";
115
+ }
116
+ if (element === document.documentElement) {
117
+ return "<html>";
118
+ }
119
+ const elementId = element.id;
120
+ if (elementId) {
121
+ return `${tagName}#${elementId}`;
122
+ }
123
+ const className = element.className;
124
+ if (className) {
125
+ return `${tagName}.${className.split(" ").join(".")}`;
126
+ }
107
127
 
108
- const tagName = element.tagName.toLowerCase();
109
- const dataUIName = element.getAttribute("data-ui-name");
110
- if (dataUIName) {
111
- return `${tagName}[data-ui-name="${dataUIName}"]`;
128
+ const parentSignature = getElementSignature(element.parentElement);
129
+ return `${parentSignature} > ${tagName}`;
112
130
  }
113
- if (element === document.body) {
114
- return "<body>";
115
- }
116
- if (element === document.documentElement) {
117
- return "<html>";
118
- }
119
- const elementId = element.id;
120
- if (elementId) {
121
- return `${tagName}#${elementId}`;
122
- }
123
- const className = element.className;
124
- if (className) {
125
- return `${tagName}.${className.split(" ").join(".")}`;
126
- }
127
-
128
- const parentSignature = getElementSignature(element.parentElement);
129
- return `${parentSignature} > ${tagName}`;
131
+ return String(element);
130
132
  };
131
133
 
132
134
  const createIterableWeakSet = () => {
@@ -7078,12 +7080,12 @@ const createConstraintFeedbackLine = () => {
7078
7080
  import.meta.css = /* css */ `
7079
7081
  .navi_constraint_feedback_line {
7080
7082
  position: fixed;
7081
- pointer-events: none;
7082
7083
  z-index: 9998;
7084
+ border-top: 2px dotted rgba(59, 130, 246, 0.7);
7083
7085
  visibility: hidden;
7084
- transition: opacity 0.15s ease;
7085
7086
  transform-origin: left center;
7086
- border-top: 2px dotted rgba(59, 130, 246, 0.7);
7087
+ transition: opacity 0.15s ease;
7088
+ pointer-events: none;
7087
7089
  }
7088
7090
 
7089
7091
  .navi_constraint_feedback_line[data-visible] {
@@ -7524,11 +7526,11 @@ import.meta.css = /* css */ `
7524
7526
  position: fixed;
7525
7527
  top: 0;
7526
7528
  left: 0;
7529
+ z-index: 999998;
7527
7530
  width: 100vw;
7528
7531
  height: 100vh;
7529
- overflow: hidden;
7530
7532
  pointer-events: none;
7531
- z-index: 999998;
7533
+ overflow: hidden;
7532
7534
  --marker-size: ${MARKER_SIZE}px;
7533
7535
  }
7534
7536
 
@@ -7593,33 +7595,33 @@ import.meta.css = /* css */ `
7593
7595
 
7594
7596
  .navi_debug_marker_label {
7595
7597
  position: absolute;
7596
- font-size: 12px;
7598
+ padding: 2px 6px;
7599
+ color: rgb(from var(--marker-color) r g b / 1);
7597
7600
  font-weight: bold;
7601
+ font-size: 12px;
7602
+ white-space: nowrap;
7598
7603
  background: rgba(255, 255, 255, 0.9);
7599
- padding: 2px 6px;
7600
- border-radius: 3px;
7601
7604
  border: 1px solid;
7602
- white-space: nowrap;
7603
- pointer-events: none;
7604
- color: rgb(from var(--marker-color) r g b / 1);
7605
7605
  border-color: rgb(from var(--marker-color) r g b / 1);
7606
+ border-radius: 3px;
7607
+ pointer-events: none;
7606
7608
  }
7607
7609
 
7608
7610
  /* Label positioning based on side data attributes */
7609
7611
 
7610
7612
  /* Left side markers - vertical with 90° rotation */
7611
7613
  .navi_debug_marker[data-left] .navi_debug_marker_label {
7612
- left: 10px;
7613
7614
  top: 20px;
7615
+ left: 10px;
7614
7616
  transform: rotate(90deg);
7615
7617
  transform-origin: left center;
7616
7618
  }
7617
7619
 
7618
7620
  /* Right side markers - vertical with -90° rotation */
7619
7621
  .navi_debug_marker[data-right] .navi_debug_marker_label {
7622
+ top: 20px;
7620
7623
  right: 10px;
7621
7624
  left: auto;
7622
- top: 20px;
7623
7625
  transform: rotate(-90deg);
7624
7626
  transform-origin: right center;
7625
7627
  }
@@ -7632,16 +7634,16 @@ import.meta.css = /* css */ `
7632
7634
 
7633
7635
  /* Bottom side markers - horizontal, label on the line */
7634
7636
  .navi_debug_marker[data-bottom] .navi_debug_marker_label {
7635
- bottom: 0px;
7636
7637
  top: auto;
7638
+ bottom: 0px;
7637
7639
  left: 20px;
7638
7640
  }
7639
7641
 
7640
7642
  .navi_obstacle_marker {
7641
7643
  position: absolute;
7644
+ z-index: 9999;
7642
7645
  background-color: orange;
7643
7646
  opacity: 0.6;
7644
- z-index: 9999;
7645
7647
  pointer-events: none;
7646
7648
  }
7647
7649
 
@@ -7649,20 +7651,20 @@ import.meta.css = /* css */ `
7649
7651
  position: absolute;
7650
7652
  top: 50%;
7651
7653
  left: 50%;
7652
- transform: translate(-50%, -50%);
7653
- font-size: 12px;
7654
- font-weight: bold;
7655
7654
  color: white;
7655
+ font-weight: bold;
7656
+ font-size: 12px;
7656
7657
  text-shadow: 1px 1px 1px rgba(0, 0, 0, 0.8);
7658
+ transform: translate(-50%, -50%);
7657
7659
  pointer-events: none;
7658
7660
  }
7659
7661
 
7660
7662
  .navi_element_marker {
7661
7663
  position: absolute;
7664
+ z-index: 9997;
7662
7665
  background-color: var(--element-color-alpha, rgba(255, 0, 150, 0.3));
7663
7666
  border: 2px solid var(--element-color, rgb(255, 0, 150));
7664
7667
  opacity: 0.9;
7665
- z-index: 9997;
7666
7668
  pointer-events: none;
7667
7669
  }
7668
7670
 
@@ -7670,23 +7672,23 @@ import.meta.css = /* css */ `
7670
7672
  position: absolute;
7671
7673
  top: -25px;
7672
7674
  right: 0;
7673
- font-size: 11px;
7674
- font-weight: bold;
7675
+ padding: 2px 6px;
7675
7676
  color: var(--element-color, rgb(255, 0, 150));
7677
+ font-weight: bold;
7678
+ font-size: 11px;
7679
+ white-space: nowrap;
7676
7680
  background: rgba(255, 255, 255, 0.9);
7677
- padding: 2px 6px;
7678
- border-radius: 3px;
7679
7681
  border: 1px solid var(--element-color, rgb(255, 0, 150));
7680
- white-space: nowrap;
7682
+ border-radius: 3px;
7681
7683
  pointer-events: none;
7682
7684
  }
7683
7685
 
7684
7686
  .navi_reference_element_marker {
7685
7687
  position: absolute;
7688
+ z-index: 9998;
7686
7689
  background-color: rgba(0, 150, 255, 0.3);
7687
7690
  border: 2px dashed rgba(0, 150, 255, 0.7);
7688
7691
  opacity: 0.8;
7689
- z-index: 9998;
7690
7692
  pointer-events: none;
7691
7693
  }
7692
7694
 
@@ -7694,14 +7696,14 @@ import.meta.css = /* css */ `
7694
7696
  position: absolute;
7695
7697
  top: -25px;
7696
7698
  left: 0;
7697
- font-size: 11px;
7698
- font-weight: bold;
7699
+ padding: 2px 6px;
7699
7700
  color: rgba(0, 150, 255, 1);
7701
+ font-weight: bold;
7702
+ font-size: 11px;
7703
+ white-space: nowrap;
7700
7704
  background: rgba(255, 255, 255, 0.9);
7701
- padding: 2px 6px;
7702
- border-radius: 3px;
7703
7705
  border: 1px solid rgba(0, 150, 255, 0.7);
7704
- white-space: nowrap;
7706
+ border-radius: 3px;
7705
7707
  pointer-events: none;
7706
7708
  }
7707
7709
  `;
@@ -8359,7 +8361,7 @@ const createDragToMoveGestureController = ({
8359
8361
  { element, referenceElement, elementToMove, convertScrollablePosition },
8360
8362
  ) => {
8361
8363
  const direction = dragGesture.gestureInfo.direction;
8362
- dragGesture.gestureInfo.name;
8364
+ // const dragGestureName = dragGesture.gestureInfo.name;
8363
8365
  const scrollContainer = dragGesture.gestureInfo.scrollContainer;
8364
8366
  const elementImpacted = elementToMove || element;
8365
8367
  const translateXAtGrab = dragStyleController.getUnderlyingValue(
@@ -8416,7 +8418,9 @@ const createDragToMoveGestureController = ({
8416
8418
  autoScrollArea,
8417
8419
  {
8418
8420
  scrollContainer,
8419
- direction},
8421
+ direction,
8422
+ // dragGestureName,
8423
+ },
8420
8424
  );
8421
8425
  }
8422
8426
  if (autoScrollAreaPadding > 0) {
@@ -8869,10 +8873,10 @@ const getWidth = (element) => {
8869
8873
  installImportMetaCss(import.meta);
8870
8874
  import.meta.css = /* css */ `
8871
8875
  [data-position-sticky-placeholder] {
8872
- opacity: 0 !important;
8873
8876
  position: static !important;
8874
8877
  width: auto !important;
8875
8878
  height: auto !important;
8879
+ opacity: 0 !important;
8876
8880
  }
8877
8881
  `;
8878
8882
 
@@ -9989,7 +9993,6 @@ const createTransition = ({
9989
9993
  `Debug breakpoint hit at ${(breakpoint * 100).toFixed(1)}% progress`,
9990
9994
  );
9991
9995
  const notifyDebuggerEnd = notifyDebuggerStart();
9992
- debugger;
9993
9996
  notifyDebuggerEnd();
9994
9997
  }
9995
9998
  if (effect === "pause") {
@@ -11613,7 +11616,7 @@ const initFlexDetailsSet = (
11613
11616
  }
11614
11617
  };
11615
11618
 
11616
- const applyAllocatedSpaces = (resizeDetails) => {
11619
+ const applyAllocatedSpaces = ({ reason, animated }) => {
11617
11620
  const changeSet = new Set();
11618
11621
  let maxChange = 0;
11619
11622
 
@@ -11621,9 +11624,8 @@ const initFlexDetailsSet = (
11621
11624
  const allocatedSpace = allocatedSpaceMap.get(child);
11622
11625
  const allocatedSize = spaceToSize(allocatedSpace, child);
11623
11626
  const space = spaceMap.get(child);
11624
- const size = spaceToSize(space, child);
11627
+ const size = spaceToSize(space === undefined ? 0 : space, child);
11625
11628
  const sizeChange = Math.abs(size - allocatedSize);
11626
-
11627
11629
  if (size === allocatedSize) {
11628
11630
  continue;
11629
11631
  }
@@ -11656,16 +11658,18 @@ const initFlexDetailsSet = (
11656
11658
  }
11657
11659
 
11658
11660
  // Don't animate if changes are too small (avoids imperceptible animations that hide scrollbars)
11659
- const shouldAnimate =
11660
- resizeDetails.animated && maxChange >= ANIMATION_THRESHOLD_PX;
11661
+ const shouldAnimate = animated && maxChange >= ANIMATION_THRESHOLD_PX;
11661
11662
 
11662
- if (debug && resizeDetails.animated && !shouldAnimate) {
11663
+ if (debug && animated && !shouldAnimate) {
11663
11664
  console.debug(
11664
11665
  `🚫 Skipping animation: max change ${maxChange.toFixed(2)}px < ${ANIMATION_THRESHOLD_PX}px threshold`,
11665
11666
  );
11666
11667
  }
11667
11668
 
11668
11669
  if (!shouldAnimate) {
11670
+ if (debug) {
11671
+ console.debug(`Applying size changes without animation`);
11672
+ }
11669
11673
  const sizeChangeEntries = [];
11670
11674
  for (const { element, target, sideEffect } of changeSet) {
11671
11675
  element.style.height = `${target}px`;
@@ -11675,19 +11679,26 @@ const initFlexDetailsSet = (
11675
11679
  }
11676
11680
  sizeChangeEntries.push({ element, value: target });
11677
11681
  }
11678
- onSizeChange?.(sizeChangeEntries, resizeDetails);
11682
+ onSizeChange?.(sizeChangeEntries, { reason, animated });
11679
11683
  return;
11680
11684
  }
11681
11685
 
11686
+ if (debug) {
11687
+ console.debug(`Start animating size changes`);
11688
+ }
11682
11689
  // Create height animations for each element in changeSet
11683
11690
  const transitions = Array.from(changeSet).map(({ element, target }) => {
11684
11691
  const transition = createHeightTransition(element, target, {
11685
11692
  duration: HEIGHT_TRANSITION_DURATION,
11693
+ // because we also set inline height when we don't want animation and it should win
11694
+ // we could also commit styles for animation or cancel any animation so that when we explicitely set height
11695
+ // sync the transition gets overriden
11696
+ styleSynchronizer: "inline_style",
11686
11697
  });
11687
11698
  return transition;
11688
11699
  });
11689
11700
 
11690
- const transition = transitionController.animate(transitions, {
11701
+ const transition = transitionController.update(transitions, {
11691
11702
  onChange: (changeEntries, isLast) => {
11692
11703
  // Apply side effects for each animated element
11693
11704
  for (const { transition, value } of changeEntries) {
@@ -11711,7 +11722,7 @@ const initFlexDetailsSet = (
11711
11722
  );
11712
11723
  onSizeChange(
11713
11724
  sizeChangeEntries,
11714
- isLast ? { ...resizeDetails, animated: false } : resizeDetails,
11725
+ isLast ? { reason, animated: false } : { reason, animated },
11715
11726
  );
11716
11727
  }
11717
11728
  },
@@ -11956,23 +11967,23 @@ const initFlexDetailsSet = (
11956
11967
  }
11957
11968
  };
11958
11969
 
11959
- const updateSpaceDistribution = (resizeDetails) => {
11970
+ const updateSpaceDistribution = ({ reason, animated }) => {
11960
11971
  if (debug) {
11961
- console.group(`updateSpaceDistribution: ${resizeDetails.reason}`);
11972
+ console.group(`updateSpaceDistribution: ${reason}`);
11962
11973
  }
11963
11974
  prepareSpaceDistribution();
11964
- distributeAvailableSpace(resizeDetails.reason);
11975
+ distributeAvailableSpace(reason);
11965
11976
  distributeRemainingSpace({
11966
11977
  childToGrow: openedDetailsArray[openedDetailsArray.length - 1],
11967
11978
  childToShrinkFrom: lastChild,
11968
11979
  });
11969
11980
  if (
11970
- resizeDetails.reason === "initial_space_distribution" ||
11971
- resizeDetails.reason === "content_change"
11981
+ reason === "initial_space_distribution" ||
11982
+ reason === "content_change"
11972
11983
  ) {
11973
11984
  spaceMap.clear(); // force to set size at start
11974
11985
  }
11975
- applyAllocatedSpaces(resizeDetails);
11986
+ applyAllocatedSpaces({ reason, animated });
11976
11987
  saveCurrentSizeAsRequestedSizes();
11977
11988
  if (debug) {
11978
11989
  console.groupEnd();
@@ -12013,6 +12024,19 @@ const initFlexDetailsSet = (
12013
12024
  }
12014
12025
  }
12015
12026
  if (someNew || someOld) {
12027
+ for (const child of container.children) {
12028
+ if (!child.dispatchEvent) {
12029
+ // ignore text nodes
12030
+ continue;
12031
+ }
12032
+ child.dispatchEvent(
12033
+ new CustomEvent("resizablechange", {
12034
+ detail: {
12035
+ resizable: resizableDetailsIdSet.has(child.id),
12036
+ },
12037
+ }),
12038
+ );
12039
+ }
12016
12040
  onResizableDetailsChange?.(resizableDetailsIdSet);
12017
12041
  }
12018
12042
  };
@@ -12229,11 +12253,18 @@ const initFlexDetailsSet = (
12229
12253
  if (currentAllocatedSpaceMap) {
12230
12254
  allocatedSpaceMap = currentAllocatedSpaceMap;
12231
12255
  saveCurrentSizeAsRequestedSizes({ replaceExistingAttributes: true });
12232
- if (onRequestedSizeChange) {
12233
- for (const [child, allocatedSpace] of allocatedSpaceMap) {
12234
- const size = spaceToSize(allocatedSpace, child);
12256
+ for (const [child, allocatedSpace] of allocatedSpaceMap) {
12257
+ const size = spaceToSize(allocatedSpace, child);
12258
+ if (onRequestedSizeChange) {
12235
12259
  onRequestedSizeChange(child, size);
12236
12260
  }
12261
+ child.dispatchEvent(
12262
+ new CustomEvent("resizeend", {
12263
+ detail: {
12264
+ size,
12265
+ },
12266
+ }),
12267
+ );
12237
12268
  }
12238
12269
  onMouseResizeEnd?.();
12239
12270
  }
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@jsenv/dom",
3
- "version": "0.8.7",
3
+ "version": "0.9.0",
4
4
  "description": "DOM utilities for writing frontend code",
5
5
  "repository": {
6
6
  "type": "git",
@@ -18,8 +18,13 @@
18
18
  "type": "module",
19
19
  "exports": {
20
20
  ".": {
21
- "dev:jsenv": "./index.js",
22
- "default": "./dist/jsenv_dom.js"
21
+ "node": {
22
+ "default": "./index_node.js"
23
+ },
24
+ "browser": {
25
+ "dev:jsenv": "./index.js",
26
+ "default": "./dist/jsenv_dom.js"
27
+ }
23
28
  },
24
29
  "./details_content_full_height": "./src/size/details_content_full_height.js",
25
30
  "./details_toggle_animation": "./src/details_toggle_animation.js",
@@ -37,7 +42,7 @@
37
42
  "@jsenv/core": "../../../",
38
43
  "@jsenv/navi": "../navi",
39
44
  "@jsenv/snapshot": "../../tooling/snapshot",
40
- "@preact/signals": "2.5.0",
45
+ "@preact/signals": "2.8.1",
41
46
  "preact": "11.0.0-beta.0"
42
47
  },
43
48
  "publishConfig": {