@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.
Files changed (109) hide show
  1. package/dist/jsenv_dom.js +262 -330
  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 -1491
  108. package/src/utils.js +0 -69
  109. package/src/value_effect.js +0 -35
@@ -1,486 +0,0 @@
1
- import { getScrollContainer } from "../interaction/scroll/scroll_container.js";
2
- import { createPubSub } from "../pub_sub.js";
3
-
4
- const DEBUG = false;
5
-
6
- // Creates a visible rect effect that tracks how much of an element is visible within its scrollable parent
7
- // and within the document viewport. This is useful for implementing overlays, lazy loading, or any UI
8
- // that needs to react to element visibility changes.
9
- //
10
- // The function returns two visibility ratios:
11
- // - scrollVisibilityRatio: Visibility ratio relative to the scrollable parent (0-1)
12
- // - visibilityRatio: Visibility ratio relative to the document viewport (0-1)
13
- //
14
- // When scrollable parent is the document, both ratios will be the same.
15
- // When scrollable parent is a custom container, scrollVisibilityRatio might be 1.0 (fully visible
16
- // within the container) while visibilityRatio could be 0.0 (container is scrolled out of viewport).
17
- // A bit like https://tetherjs.dev/ but different
18
- export const visibleRectEffect = (element, update) => {
19
- const [teardown, addTeardown] = createPubSub();
20
- const scrollContainer = getScrollContainer(element);
21
- const scrollContainerIsDocument =
22
- scrollContainer === document.documentElement;
23
- let lastMeasuredWidth;
24
- let lastMeasuredHeight;
25
- const check = (reason) => {
26
- if (DEBUG) {
27
- console.group(`visibleRect.check("${reason}")`);
28
- }
29
-
30
- // 1. Calculate element position relative to scrollable parent
31
- const { scrollLeft, scrollTop } = scrollContainer;
32
- const visibleAreaLeft = scrollLeft;
33
- const visibleAreaTop = scrollTop;
34
-
35
- // Get element position relative to its scrollable parent
36
- let elementAbsoluteLeft;
37
- let elementAbsoluteTop;
38
- if (scrollContainerIsDocument) {
39
- // For document scrolling, use offsetLeft/offsetTop relative to document
40
- const rect = element.getBoundingClientRect();
41
- elementAbsoluteLeft = rect.left + scrollLeft;
42
- elementAbsoluteTop = rect.top + scrollTop;
43
- } else {
44
- // For custom container, get position relative to the container
45
- const elementRect = element.getBoundingClientRect();
46
- const scrollContainerRect = scrollContainer.getBoundingClientRect();
47
- elementAbsoluteLeft =
48
- elementRect.left - scrollContainerRect.left + scrollLeft;
49
- elementAbsoluteTop =
50
- elementRect.top - scrollContainerRect.top + scrollTop;
51
- }
52
-
53
- const leftVisible =
54
- visibleAreaLeft < elementAbsoluteLeft
55
- ? elementAbsoluteLeft - visibleAreaLeft
56
- : 0;
57
- const topVisible =
58
- visibleAreaTop < elementAbsoluteTop
59
- ? elementAbsoluteTop - visibleAreaTop
60
- : 0;
61
- // Convert to overlay coordinates (adjust for custom scrollable container)
62
- let overlayLeft = leftVisible;
63
- let overlayTop = topVisible;
64
- if (!scrollContainerIsDocument) {
65
- const { left: scrollableLeft, top: scrollableTop } =
66
- scrollContainer.getBoundingClientRect();
67
- overlayLeft += scrollableLeft;
68
- overlayTop += scrollableTop;
69
- }
70
-
71
- // 2. Calculate element visible width/height
72
- const { width, height } = element.getBoundingClientRect();
73
- lastMeasuredWidth = width;
74
- lastMeasuredHeight = height;
75
- const visibleAreaWidth = scrollContainer.clientWidth;
76
- const visibleAreaHeight = scrollContainer.clientHeight;
77
- const visibleAreaRight = visibleAreaLeft + visibleAreaWidth;
78
- const visibleAreaBottom = visibleAreaTop + visibleAreaHeight;
79
- // 2.1 Calculate visible width
80
- let widthVisible;
81
- {
82
- const maxVisibleWidth = visibleAreaWidth - leftVisible;
83
- const elementAbsoluteRight = elementAbsoluteLeft + width;
84
- const elementLeftIsVisible = elementAbsoluteLeft >= visibleAreaLeft;
85
- const elementRightIsVisible = elementAbsoluteRight <= visibleAreaRight;
86
- if (elementLeftIsVisible && elementRightIsVisible) {
87
- // Element fully visible horizontally
88
- widthVisible = width;
89
- } else if (elementLeftIsVisible && !elementRightIsVisible) {
90
- // Element left is visible, right is cut off
91
- widthVisible = visibleAreaRight - elementAbsoluteLeft;
92
- } else if (!elementLeftIsVisible && elementRightIsVisible) {
93
- // Element left is cut off, right is visible
94
- widthVisible = elementAbsoluteRight - visibleAreaLeft;
95
- } else {
96
- // Element spans beyond both sides, show only visible area portion
97
- widthVisible = maxVisibleWidth;
98
- }
99
- }
100
- // 2.2 Calculate visible height
101
- let heightVisible;
102
- {
103
- const maxVisibleHeight = visibleAreaHeight - topVisible;
104
- const elementAbsoluteBottom = elementAbsoluteTop + height;
105
- const elementTopIsVisible = elementAbsoluteTop >= visibleAreaTop;
106
- const elementBottomIsVisible = elementAbsoluteBottom <= visibleAreaBottom;
107
- if (elementTopIsVisible && elementBottomIsVisible) {
108
- // Element fully visible vertically
109
- heightVisible = height;
110
- } else if (elementTopIsVisible && !elementBottomIsVisible) {
111
- // Element top is visible, bottom is cut off
112
- heightVisible = visibleAreaBottom - elementAbsoluteTop;
113
- } else if (!elementTopIsVisible && elementBottomIsVisible) {
114
- // Element top is cut off, bottom is visible
115
- heightVisible = elementAbsoluteBottom - visibleAreaTop;
116
- } else {
117
- // Element spans beyond both sides, show only visible area portion
118
- heightVisible = maxVisibleHeight;
119
- }
120
- }
121
-
122
- // Calculate visibility ratios
123
- const scrollVisibilityRatio =
124
- (widthVisible * heightVisible) / (width * height);
125
- // Calculate visibility ratio relative to document viewport
126
- let documentVisibilityRatio;
127
- if (scrollContainerIsDocument) {
128
- documentVisibilityRatio = scrollVisibilityRatio;
129
- } else {
130
- // For custom containers, calculate visibility relative to document viewport
131
- const elementRect = element.getBoundingClientRect();
132
- const viewportWidth = window.innerWidth;
133
- const viewportHeight = window.innerHeight;
134
- // Calculate how much of the element is visible in the document viewport
135
- const elementLeft = Math.max(0, elementRect.left);
136
- const elementTop = Math.max(0, elementRect.top);
137
- const elementRight = Math.min(viewportWidth, elementRect.right);
138
- const elementBottom = Math.min(viewportHeight, elementRect.bottom);
139
- const documentVisibleWidth = Math.max(0, elementRight - elementLeft);
140
- const documentVisibleHeight = Math.max(0, elementBottom - elementTop);
141
- documentVisibilityRatio =
142
- (documentVisibleWidth * documentVisibleHeight) / (width * height);
143
- }
144
-
145
- const visibleRect = {
146
- left: overlayLeft,
147
- top: overlayTop,
148
- right: overlayLeft + widthVisible,
149
- bottom: overlayTop + heightVisible,
150
- width: widthVisible,
151
- height: heightVisible,
152
- visibilityRatio: documentVisibilityRatio,
153
- scrollVisibilityRatio,
154
- };
155
-
156
- if (DEBUG) {
157
- console.log(`update(${JSON.stringify(visibleRect, null, " ")})`);
158
- console.groupEnd();
159
- }
160
- update(visibleRect, {
161
- width,
162
- height,
163
- });
164
- };
165
-
166
- check("initialization");
167
-
168
- const [publishBeforeAutoCheck, onBeforeAutoCheck] = createPubSub();
169
- auto_check: {
170
- const autoCheck = (reason) => {
171
- const beforeCheckResults = publishBeforeAutoCheck(reason);
172
- check(reason);
173
- for (const beforeCheckResult of beforeCheckResults) {
174
- if (typeof beforeCheckResult === "function") {
175
- beforeCheckResult();
176
- }
177
- }
178
- };
179
- // let rafId = null;
180
- // const scheduleCheck = (reason) => {
181
- // cancelAnimationFrame(rafId);
182
- // rafId = requestAnimationFrame(() => {
183
- // autoCheck(reason);
184
- // });
185
- // };
186
- // addTeardown(() => {
187
- // cancelAnimationFrame(rafId);
188
- // });
189
-
190
- on_scroll: {
191
- // If scrollable parent is not document, also listen to document scroll
192
- // to update UI position when the scrollable parent moves in viewport
193
- const onDocumentScroll = () => {
194
- autoCheck("document_scroll");
195
- };
196
- document.addEventListener("scroll", onDocumentScroll, {
197
- passive: true,
198
- });
199
- addTeardown(() => {
200
- document.removeEventListener("scroll", onDocumentScroll, {
201
- passive: true,
202
- });
203
- });
204
- if (!scrollContainerIsDocument) {
205
- const onScroll = () => {
206
- autoCheck("scrollable_parent_scroll");
207
- };
208
- scrollContainer.addEventListener("scroll", onScroll, {
209
- passive: true,
210
- });
211
- addTeardown(() => {
212
- scrollContainer.removeEventListener("scroll", onScroll, {
213
- passive: true,
214
- });
215
- });
216
- }
217
- }
218
- on_window_resize: {
219
- const onWindowResize = () => {
220
- autoCheck("window_size_change");
221
- };
222
- window.addEventListener("resize", onWindowResize);
223
- addTeardown(() => {
224
- window.removeEventListener("resize", onWindowResize);
225
- });
226
- }
227
- on_element_resize: {
228
- let handlingResize = true;
229
- const resizeObserver = new ResizeObserver(() => {
230
- if (handlingResize) {
231
- return;
232
- }
233
- // we use directly the result of getBoundingClientRect() instead of the resizeEntry.contentRect or resizeEntry.borderBoxSize
234
- // so that:
235
- // - We can compare the dimensions measure in the last check and the current one
236
- // - We don't have to check element boz-sizing to know what to compare
237
- // - resizeEntry.borderBoxSize browser support is not that great
238
- const { width, height } = element.getBoundingClientRect();
239
- const widthDiff = Math.abs(width - lastMeasuredWidth);
240
- const heightDiff = Math.abs(height - lastMeasuredHeight);
241
- if (widthDiff === 0 && heightDiff === 0) {
242
- return;
243
- }
244
- handlingResize = true;
245
- autoCheck(`element_size_change (${width}x${height})`);
246
- handlingResize = false;
247
- });
248
- resizeObserver.observe(element);
249
- // Temporarily disconnect ResizeObserver to prevent feedback loops eventually caused by update function
250
- onBeforeAutoCheck(() => {
251
- resizeObserver.unobserve(element);
252
- return () => {
253
- // This triggers a new call to the resive observer that will be ignored thanks to
254
- // the widthDiff/heightDiff early return
255
- resizeObserver.observe(element);
256
- };
257
- });
258
- addTeardown(() => {
259
- resizeObserver.disconnect();
260
- });
261
- }
262
- on_intersection_change: {
263
- const documentIntersectionObserver = new IntersectionObserver(
264
- () => {
265
- autoCheck("element_intersection_with_document_change");
266
- },
267
- {
268
- root: null,
269
- rootMargin: "0px",
270
- threshold: [0, 0.1, 0.9, 1],
271
- },
272
- );
273
- documentIntersectionObserver.observe(element);
274
- addTeardown(() => {
275
- documentIntersectionObserver.disconnect();
276
- });
277
- if (!scrollContainerIsDocument) {
278
- const scrollIntersectionObserver = new IntersectionObserver(
279
- () => {
280
- autoCheck("element_intersection_with_scroll_change");
281
- },
282
- {
283
- root: scrollContainer,
284
- rootMargin: "0px",
285
- threshold: [0, 0, 1, 0.9, 1],
286
- },
287
- );
288
- scrollIntersectionObserver.observe(element);
289
- addTeardown(() => {
290
- scrollIntersectionObserver.disconnect();
291
- });
292
- }
293
- }
294
- on_window_touchmove: {
295
- const onWindowTouchMove = () => {
296
- autoCheck("window_touchmove");
297
- };
298
- window.addEventListener("touchmove", onWindowTouchMove, {
299
- passive: true,
300
- });
301
- addTeardown(() => {
302
- window.removeEventListener("touchmove", onWindowTouchMove, {
303
- passive: true,
304
- });
305
- });
306
- }
307
- }
308
-
309
- return {
310
- check,
311
- onBeforeAutoCheck,
312
- disconnect: () => {
313
- teardown();
314
- },
315
- };
316
- };
317
-
318
- export const pickPositionRelativeTo = (
319
- element,
320
- target,
321
- {
322
- alignToViewportEdgeWhenTargetNearEdge = 0,
323
- minLeft = 0,
324
- forcePosition,
325
- } = {},
326
- ) => {
327
- if (
328
- import.meta.dev &&
329
- getScrollContainer(element) !== document.documentElement
330
- ) {
331
- // The idea behind this warning is that pickPositionRelativeTo is meant to position a tooltip/dropdown etc
332
- // And for this use case the element to position should be document-relative
333
- // (position: absolute with first scrollable parent being the document)
334
- // Because this is how you achieve the best results:
335
- // 1. The element naturally follow document scroll
336
- // Which gives the best experience when user scrolls the page or the container
337
- // 2. The element can take more visible size in case target is within a scrollable container
338
- // or uses overflow: hidden somewhere in its ancestor chain
339
- console.warn(
340
- "pickPositionRelativeTo should be used only for document-relative element",
341
- );
342
- }
343
-
344
- const viewportWidth = document.documentElement.clientWidth;
345
- const viewportHeight = document.documentElement.clientHeight;
346
- // Get viewport-relative positions
347
- const elementRect = element.getBoundingClientRect();
348
- const targetRect = target.getBoundingClientRect();
349
- const {
350
- left: elementLeft,
351
- right: elementRight,
352
- top: elementTop,
353
- bottom: elementBottom,
354
- } = elementRect;
355
- const {
356
- left: targetLeft,
357
- right: targetRight,
358
- top: targetTop,
359
- bottom: targetBottom,
360
- } = targetRect;
361
- const elementWidth = elementRight - elementLeft;
362
- const elementHeight = elementBottom - elementTop;
363
- const targetWidth = targetRight - targetLeft;
364
-
365
- // Calculate horizontal position (viewport-relative)
366
- let elementPositionLeft;
367
- {
368
- // Check if target element is wider than viewport
369
- const targetIsWiderThanViewport = targetWidth > viewportWidth;
370
- if (targetIsWiderThanViewport) {
371
- const targetLeftIsVisible = targetLeft >= 0;
372
- const targetRightIsVisible = targetRight <= viewportWidth;
373
-
374
- if (!targetLeftIsVisible && targetRightIsVisible) {
375
- // Target extends beyond left edge but right side is visible
376
- const viewportCenter = viewportWidth / 2;
377
- const distanceFromRightEdge = viewportWidth - targetRight;
378
- elementPositionLeft =
379
- viewportCenter - distanceFromRightEdge / 2 - elementWidth / 2;
380
- } else if (targetLeftIsVisible && !targetRightIsVisible) {
381
- // Target extends beyond right edge but left side is visible
382
- const viewportCenter = viewportWidth / 2;
383
- const distanceFromLeftEdge = -targetLeft;
384
- elementPositionLeft =
385
- viewportCenter - distanceFromLeftEdge / 2 - elementWidth / 2;
386
- } else {
387
- // Target extends beyond both edges or is fully visible (center in viewport)
388
- elementPositionLeft = viewportWidth / 2 - elementWidth / 2;
389
- }
390
- } else {
391
- // Target fits within viewport width - center element relative to target
392
- elementPositionLeft = targetLeft + targetWidth / 2 - elementWidth / 2;
393
- // Special handling when element is wider than target
394
- if (alignToViewportEdgeWhenTargetNearEdge) {
395
- const elementIsWiderThanTarget = elementWidth > targetWidth;
396
- const targetIsNearLeftEdge =
397
- targetLeft < alignToViewportEdgeWhenTargetNearEdge;
398
- if (elementIsWiderThanTarget && targetIsNearLeftEdge) {
399
- elementPositionLeft = minLeft; // Left edge of viewport
400
- }
401
- }
402
- }
403
- // Constrain horizontal position to viewport boundaries
404
- if (elementPositionLeft < 0) {
405
- elementPositionLeft = 0;
406
- } else if (elementPositionLeft + elementWidth > viewportWidth) {
407
- elementPositionLeft = viewportWidth - elementWidth;
408
- }
409
- }
410
-
411
- // Calculate vertical position (viewport-relative)
412
- let position;
413
- const spaceAboveTarget = targetTop;
414
- const spaceBelowTarget = viewportHeight - targetBottom;
415
- determine_position: {
416
- if (forcePosition) {
417
- position = forcePosition;
418
- break determine_position;
419
- }
420
- const preferredPosition = element.getAttribute("data-position");
421
- const minContentVisibilityRatio = 0.6; // 60% minimum visibility to keep position
422
- if (preferredPosition) {
423
- // Element has a preferred position - try to keep it unless we really struggle
424
- const visibleRatio =
425
- preferredPosition === "above"
426
- ? spaceAboveTarget / elementHeight
427
- : spaceBelowTarget / elementHeight;
428
- const canShowMinimumContent = visibleRatio >= minContentVisibilityRatio;
429
- if (canShowMinimumContent) {
430
- position = preferredPosition;
431
- break determine_position;
432
- }
433
- }
434
- // No preferred position - use original logic (prefer below, fallback to above if more space)
435
- const elementFitsBelow = spaceBelowTarget >= elementHeight;
436
- if (elementFitsBelow) {
437
- position = "below";
438
- break determine_position;
439
- }
440
- const hasMoreSpaceBelow = spaceBelowTarget >= spaceAboveTarget;
441
- position = hasMoreSpaceBelow ? "below" : "above";
442
- }
443
-
444
- let elementPositionTop;
445
- {
446
- if (position === "below") {
447
- // Calculate top position when placing below target (ensure whole pixels)
448
- const idealTopWhenBelow = targetBottom;
449
- elementPositionTop =
450
- idealTopWhenBelow % 1 === 0
451
- ? idealTopWhenBelow
452
- : Math.floor(idealTopWhenBelow) + 1;
453
- } else {
454
- // Calculate top position when placing above target
455
- const idealTopWhenAbove = targetTop - elementHeight;
456
- const minimumTopInViewport = 0;
457
- elementPositionTop =
458
- idealTopWhenAbove < minimumTopInViewport
459
- ? minimumTopInViewport
460
- : idealTopWhenAbove;
461
- }
462
- }
463
-
464
- // Get document scroll for final coordinate conversion
465
- const { scrollLeft, scrollTop } = document.documentElement;
466
- const elementDocumentLeft = elementPositionLeft + scrollLeft;
467
- const elementDocumentTop = elementPositionTop + scrollTop;
468
- const targetDocumentLeft = targetLeft + scrollLeft;
469
- const targetDocumentTop = targetTop + scrollTop;
470
- const targetDocumentRight = targetRight + scrollLeft;
471
- const targetDocumentBottom = targetBottom + scrollTop;
472
-
473
- return {
474
- position,
475
- left: elementDocumentLeft,
476
- top: elementDocumentTop,
477
- width: elementWidth,
478
- height: elementHeight,
479
- targetLeft: targetDocumentLeft,
480
- targetTop: targetDocumentTop,
481
- targetRight: targetDocumentRight,
482
- targetBottom: targetDocumentBottom,
483
- spaceAboveTarget,
484
- spaceBelowTarget,
485
- };
486
- };
package/src/pub_sub.js DELETED
@@ -1,31 +0,0 @@
1
- export const createPubSub = (clearOnPublish = false) => {
2
- const callbackSet = new Set();
3
-
4
- const publish = (...args) => {
5
- const results = [];
6
- for (const callback of callbackSet) {
7
- const result = callback(...args);
8
- results.push(result);
9
- }
10
- if (clearOnPublish) {
11
- callbackSet.clear();
12
- }
13
- return results;
14
- };
15
-
16
- const subscribe = (callback) => {
17
- if (typeof callback !== "function") {
18
- throw new TypeError("callback must be a function");
19
- }
20
- callbackSet.add(callback);
21
- return () => {
22
- callbackSet.delete(callback);
23
- };
24
- };
25
-
26
- const clear = () => {
27
- callbackSet.clear();
28
- };
29
-
30
- return [publish, subscribe, clear];
31
- };
@@ -1,11 +0,0 @@
1
- export const canTakeSize = (element) => {
2
- const computedStyle = window.getComputedStyle(element);
3
-
4
- if (computedStyle.display === "none") {
5
- return false;
6
- }
7
- if (computedStyle.position === "absolute") {
8
- return false;
9
- }
10
- return true;
11
- };
@@ -1,63 +0,0 @@
1
- import { addAttributeEffect } from "../attr/add_attribute_effect.js";
2
- import { getHeight } from "./get_height.js";
3
-
4
- export const ensureDetailsContentFullHeight = (details) => {
5
- const updateHeight = () => {
6
- if (!details.open) {
7
- return;
8
- }
9
- let summary = details.querySelector("summary");
10
- const summaryNextSiblingSet = new Set();
11
- {
12
- let child = summary;
13
- let nextElementSibling;
14
- while ((nextElementSibling = child.nextElementSibling)) {
15
- nextElementSibling.style.height = "auto";
16
- summaryNextSiblingSet.add(nextElementSibling);
17
- child = nextElementSibling;
18
- }
19
- }
20
-
21
- const detailsHeight = getHeight(details);
22
- let summaryHeight = getHeight(summary);
23
- let heightBefore = summaryHeight;
24
- for (const nextElementSibling of summaryNextSiblingSet) {
25
- const contentHeight = detailsHeight - heightBefore;
26
- nextElementSibling.style.height = `${contentHeight}px`;
27
- }
28
- };
29
-
30
- updateHeight();
31
-
32
- const cleanupCallbackSet = new Set();
33
- update_on_size_change: {
34
- const resizeObserver = new ResizeObserver(() => {
35
- requestAnimationFrame(() => {
36
- updateHeight();
37
- });
38
- });
39
- resizeObserver.observe(details);
40
- cleanupCallbackSet.add(() => {
41
- resizeObserver.disconnect();
42
- });
43
- }
44
- update_on_toggle: {
45
- const ontoggle = () => {
46
- updateHeight();
47
- };
48
- details.addEventListener("toggle", ontoggle);
49
- cleanupCallbackSet.add(() => {
50
- details.removeEventListener("toggle", ontoggle);
51
- });
52
- }
53
- return () => {
54
- for (const cleanupCallback of cleanupCallbackSet) {
55
- cleanupCallback();
56
- }
57
- cleanupCallbackSet.clear();
58
- };
59
- };
60
-
61
- addAttributeEffect("data-details-content-full-height", (details) => {
62
- return ensureDetailsContentFullHeight(details);
63
- });