@jsenv/dom 0.1.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 (101) hide show
  1. package/dist/jsenv_dom.js +9653 -0
  2. package/index.js +101 -0
  3. package/package.json +47 -0
  4. package/src/attr/add_attribute_effect.js +93 -0
  5. package/src/attr/attributes.js +32 -0
  6. package/src/demos/3_columns_resize_demo.html +84 -0
  7. package/src/demos/3_rows_resize_demo.html +89 -0
  8. package/src/demos/aside_and_main_demo.html +93 -0
  9. package/src/demos/coordinates_demo.html +450 -0
  10. package/src/demos/document_autoscroll_demo.html +517 -0
  11. package/src/demos/drag_gesture_constraints_demo.html +701 -0
  12. package/src/demos/drag_gesture_demo.html +1047 -0
  13. package/src/demos/drag_gesture_element_to_impact_demo.html +445 -0
  14. package/src/demos/drag_reference_element_demo.html +480 -0
  15. package/src/demos/flex_details_set_demo.html +302 -0
  16. package/src/demos/flex_details_set_demo_2.html +315 -0
  17. package/src/demos/visible_rect_demo.html +525 -0
  18. package/src/interaction/drag/constraint_feedback_line.js +92 -0
  19. package/src/interaction/drag/drag_constraint.js +659 -0
  20. package/src/interaction/drag/drag_debug_markers.js +635 -0
  21. package/src/interaction/drag/drag_element_positioner.js +382 -0
  22. package/src/interaction/drag/drag_gesture.js +566 -0
  23. package/src/interaction/drag/drag_resize_demo.html +571 -0
  24. package/src/interaction/drag/drag_to_move.js +301 -0
  25. package/src/interaction/drag/drag_to_resize_gesture.js +68 -0
  26. package/src/interaction/drag/drop_target_detection.js +148 -0
  27. package/src/interaction/drag/sticky_frontiers.js +160 -0
  28. package/src/interaction/element_log.js +8 -0
  29. package/src/interaction/event_marker.js +14 -0
  30. package/src/interaction/focus/active_element.js +33 -0
  31. package/src/interaction/focus/arrow_navigation.js +599 -0
  32. package/src/interaction/focus/element_is_focusable.js +57 -0
  33. package/src/interaction/focus/element_is_visible.js +36 -0
  34. package/src/interaction/focus/find_focusable.js +21 -0
  35. package/src/interaction/focus/focus_group.js +91 -0
  36. package/src/interaction/focus/focus_group_registry.js +12 -0
  37. package/src/interaction/focus/focus_nav.js +12 -0
  38. package/src/interaction/focus/focus_nav_event_marker.js +14 -0
  39. package/src/interaction/focus/focus_trap.js +105 -0
  40. package/src/interaction/focus/tab_navigation.js +128 -0
  41. package/src/interaction/focus/tests/focus_group_skip_tab_test.html +206 -0
  42. package/src/interaction/focus/tests/tree_focus_test.html +304 -0
  43. package/src/interaction/focus/tests/tree_focus_test.jsx +261 -0
  44. package/src/interaction/focus/tests/tree_focus_test_preact.html +13 -0
  45. package/src/interaction/isolate_interactions.js +161 -0
  46. package/src/interaction/keyboard.js +26 -0
  47. package/src/interaction/scroll/capture_scroll.js +47 -0
  48. package/src/interaction/scroll/is_scrollable.js +159 -0
  49. package/src/interaction/scroll/scroll_container.js +110 -0
  50. package/src/interaction/scroll/scroll_trap.js +44 -0
  51. package/src/interaction/scroll/scrollbar_size.js +20 -0
  52. package/src/interaction/scroll/wheel_through.js +138 -0
  53. package/src/iterable_weak_set.js +66 -0
  54. package/src/position/dom_coords.js +340 -0
  55. package/src/position/offset_parent.js +15 -0
  56. package/src/position/position_fixed.js +15 -0
  57. package/src/position/position_sticky.js +213 -0
  58. package/src/position/sticky_rect.js +79 -0
  59. package/src/position/visible_rect.js +482 -0
  60. package/src/pub_sub.js +28 -0
  61. package/src/size/can_take_size.js +11 -0
  62. package/src/size/details_content_full_height.js +63 -0
  63. package/src/size/flex_details_set.js +974 -0
  64. package/src/size/get_available_height.js +22 -0
  65. package/src/size/get_available_width.js +22 -0
  66. package/src/size/get_border_sizes.js +14 -0
  67. package/src/size/get_height.js +4 -0
  68. package/src/size/get_inner_height.js +15 -0
  69. package/src/size/get_inner_width.js +15 -0
  70. package/src/size/get_margin_sizes.js +10 -0
  71. package/src/size/get_max_height.js +57 -0
  72. package/src/size/get_max_width.js +47 -0
  73. package/src/size/get_min_height.js +14 -0
  74. package/src/size/get_min_width.js +14 -0
  75. package/src/size/get_padding_sizes.js +10 -0
  76. package/src/size/get_width.js +4 -0
  77. package/src/size/hooks/use_available_height.js +27 -0
  78. package/src/size/hooks/use_available_width.js +27 -0
  79. package/src/size/hooks/use_max_height.js +10 -0
  80. package/src/size/hooks/use_max_width.js +10 -0
  81. package/src/size/hooks/use_resize_status.js +62 -0
  82. package/src/size/resize.js +695 -0
  83. package/src/size/resolve_css_size.js +32 -0
  84. package/src/style/dom_styles.js +97 -0
  85. package/src/style/style_composition.js +78 -0
  86. package/src/style/style_controller.js +345 -0
  87. package/src/style/style_parsing.js +317 -0
  88. package/src/transition/demos/animation_resumption_test.xhtml +500 -0
  89. package/src/transition/demos/height_toggle_test.xhtml +515 -0
  90. package/src/transition/dom_transition.js +254 -0
  91. package/src/transition/easing.js +48 -0
  92. package/src/transition/group_transition.js +261 -0
  93. package/src/transition/transform_style_parser.js +32 -0
  94. package/src/transition/transition_playback.js +366 -0
  95. package/src/transition/transition_timeline.js +79 -0
  96. package/src/traversal.js +247 -0
  97. package/src/ui_transition/demos/content_states_transition_demo.html +628 -0
  98. package/src/ui_transition/demos/smooth_height_transition_demo.html +149 -0
  99. package/src/ui_transition/demos/transition_testing.html +354 -0
  100. package/src/ui_transition/ui_transition.js +1492 -0
  101. package/src/utils.js +69 -0
@@ -0,0 +1,149 @@
1
+ <!doctype html>
2
+ <html>
3
+ <head>
4
+ <title>Smooth height transition demo</title>
5
+ <style>
6
+ body {
7
+ margin: 0;
8
+ font-family: system-ui;
9
+ }
10
+
11
+ .controls {
12
+ padding: 20px;
13
+ border-bottom: 1px solid #ccc;
14
+ background: #f5f5f5;
15
+ }
16
+
17
+ .demo-container {
18
+ padding: 20px;
19
+ }
20
+
21
+ /* The element we'll apply the smooth transition to */
22
+ #dynamic-content {
23
+ background: white;
24
+ border: 2px solid #666;
25
+ padding: 16px;
26
+ margin: 20px 0;
27
+ width: 300px;
28
+ /* we'll handle height transitions in JS */
29
+ }
30
+
31
+ /* Some preset content styles for testing */
32
+ .content-block {
33
+ background: #f0f0f0;
34
+ margin: 8px 0;
35
+ padding: 12px;
36
+ }
37
+
38
+ button {
39
+ margin: 0 8px 8px 0;
40
+ padding: 8px 16px;
41
+ }
42
+
43
+ textarea {
44
+ display: block;
45
+ width: 300px;
46
+ height: 100px;
47
+ margin: 8px 0;
48
+ }
49
+ </style>
50
+ </head>
51
+ <body>
52
+ <div class="controls">
53
+ <h3>Test Controls</h3>
54
+ <div>
55
+ <button id="small-content">Small Content</button>
56
+ <button id="medium-content">Medium Content</button>
57
+ <button id="large-content">Large Content</button>
58
+ </div>
59
+ <div>
60
+ <button id="add-block">Add Block</button>
61
+ <button id="remove-block">Remove Block</button>
62
+ </div>
63
+ <div>
64
+ <p>Custom content:</p>
65
+ <textarea id="custom-content">
66
+ Hello, this is some initial content.</textarea
67
+ >
68
+ </div>
69
+ </div>
70
+
71
+ <div class="demo-container">
72
+ <div id="dynamic-content" class="ui-transition-container">
73
+ <div class="ui-transition-outer-wrapper">
74
+ <div class="ui-transition-measure-wrapper">
75
+ <div class="ui-transition-slot">
76
+ <div class="content-block">Initial content block</div>
77
+ </div>
78
+ </div>
79
+ </div>
80
+ <div class="ui-transition-overlay"></div>
81
+ </div>
82
+ </div>
83
+
84
+ <script type="module">
85
+ import { initUITransition } from "../ui_transition.js";
86
+
87
+ const dynamicContent = document.getElementById("dynamic-content");
88
+ const { slot } = initUITransition(dynamicContent);
89
+
90
+ // Setup event listeners
91
+ document
92
+ .getElementById("small-content")
93
+ .addEventListener("click", () => setPresetContent("small"));
94
+ document
95
+ .getElementById("medium-content")
96
+ .addEventListener("click", () => setPresetContent("medium"));
97
+ document
98
+ .getElementById("large-content")
99
+ .addEventListener("click", () => setPresetContent("large"));
100
+ document.getElementById("add-block").addEventListener("click", addBlock);
101
+ document
102
+ .getElementById("remove-block")
103
+ .addEventListener("click", removeBlock);
104
+ document
105
+ .getElementById("custom-content")
106
+ .addEventListener("input", (e) => updateCustomContent(e.target.value));
107
+
108
+ // Test helpers
109
+ const presetContents = {
110
+ small: `<div class="content-block">Small content</div>`,
111
+ medium: `
112
+ <div class="content-block">Medium content</div>
113
+ <div class="content-block">With multiple blocks</div>
114
+ <div class="content-block">To test transitions</div>
115
+ `,
116
+ large: `
117
+ <div class="content-block">Large content</div>
118
+ <div class="content-block">With many blocks</div>
119
+ <div class="content-block">To properly test</div>
120
+ <div class="content-block">How the transitions work</div>
121
+ <div class="content-block">With varying amounts of content</div>
122
+ <div class="content-block">And different heights</div>
123
+ `,
124
+ };
125
+
126
+ function setPresetContent(size) {
127
+ slot.innerHTML = presetContents[size];
128
+ }
129
+
130
+ function addBlock() {
131
+ const block = document.createElement("div");
132
+ block.className = "content-block";
133
+ block.textContent = `New content block ${slot.children.length + 1}`;
134
+ slot.appendChild(block);
135
+ }
136
+
137
+ function removeBlock() {
138
+ const blocks = slot.getElementsByClassName("content-block");
139
+ if (blocks.length > 0) {
140
+ blocks[blocks.length - 1].remove();
141
+ }
142
+ }
143
+
144
+ function updateCustomContent(text) {
145
+ slot.innerHTML = `<div class="content-block">${text}</div>`;
146
+ }
147
+ </script>
148
+ </body>
149
+ </html>
@@ -0,0 +1,354 @@
1
+ <!doctype html>
2
+ <html>
3
+ <head>
4
+ <meta charset="utf-8" />
5
+ <title>UI Transition Testing</title>
6
+ <style>
7
+ body {
8
+ margin: 0;
9
+ font-family: system-ui;
10
+ padding: 20px;
11
+ }
12
+
13
+ .controls {
14
+ margin-bottom: 20px;
15
+ padding: 16px;
16
+ background: #f5f5f5;
17
+ border: 1px solid #ccc;
18
+ border-radius: 4px;
19
+ }
20
+
21
+ .button-group {
22
+ margin-bottom: 12px;
23
+ }
24
+
25
+ button {
26
+ margin: 0 8px 8px 0;
27
+ padding: 8px 16px;
28
+ }
29
+
30
+ .description {
31
+ color: #666;
32
+ font-size: 0.9em;
33
+ margin: 8px 0;
34
+ }
35
+
36
+ /* Test content styles */
37
+ #transition-box {
38
+ border: 2px solid #666;
39
+ /* padding: 16px; */
40
+ width: 300px;
41
+ margin-top: 20px;
42
+ }
43
+
44
+ .test-content {
45
+ padding: 20px;
46
+ background: #f0f0f0;
47
+ margin: 8px 0;
48
+ text-align: center;
49
+ }
50
+
51
+ .test-content.loading {
52
+ background: #e3f2fd;
53
+ }
54
+
55
+ .test-content.content {
56
+ background: #e8f5e9;
57
+ }
58
+
59
+ /* Debug info */
60
+ #debug-info {
61
+ margin-top: 20px;
62
+ font-family: monospace;
63
+ white-space: pre-wrap;
64
+ }
65
+ </style>
66
+ </head>
67
+ <body>
68
+ <div class="controls">
69
+ <div class="button-group">
70
+ <button id="start-transition">Start Transition</button>
71
+ <button id="slow-loading">Slow Loading (3s)</button>
72
+ <button id="pause-transition" disabled>Pause Transition</button>
73
+ <button id="resume-transition" disabled>Resume Transition</button>
74
+ </div>
75
+ <div class="button-group">
76
+ <button id="insert-content" disabled>Insert Content</button>
77
+ <button id="change-to-fade" disabled>Change to Cross-fade</button>
78
+ <button id="change-to-slide" disabled>Change to Slide-left</button>
79
+ <button id="reset">Reset</button>
80
+ </div>
81
+ <div>
82
+ <label>
83
+ Content Transition Duration (ms):
84
+ <input
85
+ type="number"
86
+ id="transition-duration"
87
+ value="3000"
88
+ min="100"
89
+ step="100"
90
+ style="width: 80px"
91
+ />
92
+ </label>
93
+ <label style="margin-left: 20px">
94
+ Phase Transition Duration (ms):
95
+ <input
96
+ type="number"
97
+ id="phase-duration"
98
+ value="300"
99
+ min="100"
100
+ step="100"
101
+ style="width: 80px"
102
+ />
103
+ </label>
104
+ </div>
105
+ <div>
106
+ <label>
107
+ Content Transition Type:
108
+ <select id="content-transition-type">
109
+ <option value="slide-left">Slide Left</option>
110
+ <option value="cross-fade">Cross Fade</option>
111
+ </select>
112
+ </label>
113
+ <label style="margin-left: 20px">
114
+ Phase Transition Type:
115
+ <select id="phase-transition-type">
116
+ <option value="cross-fade">Cross Fade</option>
117
+ <option value="slide-left">Slide Left</option>
118
+ </select>
119
+ </label>
120
+ </div>
121
+ <div class="description">
122
+ <strong>Content Transitions:</strong> Between different content keys (a
123
+ → b → c)<br />
124
+ <strong>Phase Transitions:</strong> Between loading/content states for
125
+ same content key (loading → content)<br />
126
+ Test smooth transition interruptions: Start a transition, then click
127
+ "Insert Content" mid-animation to see smooth easing continuation.
128
+ </div>
129
+ </div>
130
+
131
+ <div
132
+ id="transition-box"
133
+ class="ui_transition_container"
134
+ data-size-transition
135
+ data-content-transition="slide-left"
136
+ data-content-transition-duration="3000"
137
+ data-phase-transition="cross-fade"
138
+ data-phase-transition-duration="300"
139
+ >
140
+ <div class="ui_transition_outer_wrapper">
141
+ <div class="ui_transition_measure_wrapper">
142
+ <div class="ui_transition_slot">
143
+ <div
144
+ class="test-content content"
145
+ data-content-key="a"
146
+ data-ui-name="a-content"
147
+ >
148
+ Initial Content
149
+ </div>
150
+ </div>
151
+ <div class="ui_transition_phase_overlay"></div>
152
+ </div>
153
+ </div>
154
+ <div class="ui_transition_content_overlay"></div>
155
+ </div>
156
+
157
+ <div id="debug-info"></div>
158
+
159
+ <script type="module">
160
+ import { initUITransition } from "../ui_transition.js";
161
+
162
+ const box = document.getElementById("transition-box");
163
+ const debugInfo = document.getElementById("debug-info");
164
+ const durationInput = document.getElementById("transition-duration");
165
+ const phaseDurationInput = document.getElementById("phase-duration");
166
+ const contentTypeSelect = document.getElementById(
167
+ "content-transition-type",
168
+ );
169
+ const phaseTypeSelect = document.getElementById("phase-transition-type");
170
+
171
+ const startButton = document.getElementById("start-transition");
172
+ const slowLoadingButton = document.getElementById("slow-loading");
173
+ const pauseButton = document.getElementById("pause-transition");
174
+ const resumeButton = document.getElementById("resume-transition");
175
+ const insertButton = document.getElementById("insert-content");
176
+ const changeToFadeButton = document.getElementById("change-to-fade");
177
+ const changeToSlideButton = document.getElementById("change-to-slide");
178
+ const resetButton = document.getElementById("reset");
179
+
180
+ let uiTransition = initUITransition(box);
181
+
182
+ // Update duration when input changes
183
+ durationInput.addEventListener("change", () => {
184
+ box.dataset.contentTransitionDuration = durationInput.value;
185
+ });
186
+
187
+ phaseDurationInput.addEventListener("change", () => {
188
+ box.dataset.phaseTransitionDuration = phaseDurationInput.value;
189
+ });
190
+
191
+ // Update transition types when selects change
192
+ contentTypeSelect.addEventListener("change", () => {
193
+ box.dataset.contentTransition = contentTypeSelect.value;
194
+ });
195
+
196
+ phaseTypeSelect.addEventListener("change", () => {
197
+ box.dataset.phaseTransition = phaseTypeSelect.value;
198
+ });
199
+
200
+ function updateDebugInfo() {
201
+ if (!uiTransition) return;
202
+
203
+ const state = uiTransition.getState();
204
+ debugInfo.textContent = JSON.stringify(
205
+ {
206
+ isPaused: state.isPaused,
207
+ contentTransitionInProgress: state.contentTransitionInProgress,
208
+ phaseTransitionInProgress: state.phaseTransitionInProgress,
209
+ contentDuration: box.dataset.contentTransitionDuration,
210
+ phaseDuration: box.dataset.phaseTransitionDuration,
211
+ contentType: box.dataset.contentTransition,
212
+ phaseType: box.dataset.phaseTransition,
213
+ },
214
+ null,
215
+ 2,
216
+ );
217
+ }
218
+
219
+ // Update debug info periodically
220
+ setInterval(updateDebugInfo, 100);
221
+
222
+ function setContent(content) {
223
+ uiTransition.slot.innerHTML = content;
224
+ }
225
+
226
+ startButton.addEventListener("click", () => {
227
+ // Set loading state with same content key for phase transition
228
+ setContent(`
229
+ <div class="test-content loading" data-content-key="b" data-ui-name="b-loading" data-content-phase>
230
+ Loading...
231
+ </div>
232
+ `);
233
+
234
+ // Enable relevant buttons
235
+ pauseButton.disabled = false;
236
+ insertButton.disabled = false;
237
+ changeToFadeButton.disabled = false;
238
+ changeToSlideButton.disabled = false;
239
+ startButton.disabled = true;
240
+
241
+ updateDebugInfo();
242
+ });
243
+
244
+ slowLoadingButton.addEventListener("click", () => {
245
+ // Set slow loading state with same content key for phase transition
246
+ setContent(`
247
+ <div class="test-content loading" data-content-key="slow" data-ui-name="slow-loading" data-content-phase>
248
+ Slow Loading (3 seconds)...
249
+ </div>
250
+ `);
251
+
252
+ // Simulate slow loading, then show content with SAME content key
253
+ setTimeout(() => {
254
+ setContent(`
255
+ <div class="test-content content" data-content-key="slow" data-ui-name="slow-content">
256
+ Slow Content Loaded!
257
+ </div>
258
+ `);
259
+ }, 3000);
260
+
261
+ // Enable relevant buttons
262
+ pauseButton.disabled = false;
263
+ slowLoadingButton.disabled = true;
264
+
265
+ updateDebugInfo();
266
+ });
267
+
268
+ pauseButton.addEventListener("click", () => {
269
+ // Will be implemented when we add pause to the animation controller
270
+ uiTransition.pause();
271
+ pauseButton.disabled = true;
272
+ resumeButton.disabled = false;
273
+ updateDebugInfo();
274
+ });
275
+
276
+ resumeButton.addEventListener("click", () => {
277
+ // Will be implemented when we add resume to the animation controller
278
+ uiTransition.resume();
279
+ resumeButton.disabled = true;
280
+ pauseButton.disabled = false;
281
+ updateDebugInfo();
282
+ });
283
+
284
+ insertButton.addEventListener("click", () => {
285
+ // Replace loading with content (same content key for phase transition)
286
+ setContent(`
287
+ <div class="test-content content" style="background-color: orange" data-content-key="b" data-ui-name="b-content">
288
+ New Content
289
+ </div>
290
+ `);
291
+
292
+ // Disable buttons
293
+ insertButton.disabled = true;
294
+ updateDebugInfo();
295
+ });
296
+
297
+ changeToFadeButton.addEventListener("click", () => {
298
+ // Change transition type to cross-fade mid-animation
299
+ box.dataset.contentTransition = "cross-fade";
300
+
301
+ // Trigger content change to see smooth transition type change
302
+ setContent(`
303
+ <div class="test-content content" style="background-color: lightblue" data-content-key="c" data-ui-name="c-fade">
304
+ Cross-fade Content
305
+ </div>
306
+ `);
307
+
308
+ changeToFadeButton.disabled = true;
309
+ updateDebugInfo();
310
+ });
311
+
312
+ changeToSlideButton.addEventListener("click", () => {
313
+ // Change transition type back to slide-left mid-animation
314
+ box.dataset.contentTransition = "slide-left";
315
+
316
+ // Trigger content change to see smooth transition type change
317
+ setContent(`
318
+ <div class="test-content content" style="background-color: lightgreen" data-content-key="d" data-ui-name="d-slide">
319
+ Slide-left Content
320
+ </div>
321
+ `);
322
+
323
+ changeToSlideButton.disabled = true;
324
+ updateDebugInfo();
325
+ });
326
+
327
+ resetButton.addEventListener("click", () => {
328
+ // Reset to initial state
329
+ if (uiTransition) {
330
+ uiTransition.cleanup();
331
+ }
332
+
333
+ setContent(`
334
+ <div class="test-content content" data-content-key="a" data-ui-name="a-content">
335
+ Initial Content
336
+ </div>
337
+ `);
338
+
339
+ uiTransition = initUITransition(box);
340
+
341
+ // Reset buttons
342
+ startButton.disabled = false;
343
+ slowLoadingButton.disabled = false;
344
+ pauseButton.disabled = true;
345
+ resumeButton.disabled = true;
346
+ insertButton.disabled = true;
347
+ changeToFadeButton.disabled = true;
348
+ changeToSlideButton.disabled = true;
349
+
350
+ updateDebugInfo();
351
+ });
352
+ </script>
353
+ </body>
354
+ </html>