@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,317 @@
1
+ // Properties that need px units
2
+ const pxProperties = [
3
+ "width",
4
+ "height",
5
+ "top",
6
+ "left",
7
+ "right",
8
+ "bottom",
9
+ "margin",
10
+ "marginTop",
11
+ "marginRight",
12
+ "marginBottom",
13
+ "marginLeft",
14
+ "padding",
15
+ "paddingTop",
16
+ "paddingRight",
17
+ "paddingBottom",
18
+ "paddingLeft",
19
+ "border",
20
+ "borderWidth",
21
+ "borderTopWidth",
22
+ "borderRightWidth",
23
+ "borderBottomWidth",
24
+ "borderLeftWidth",
25
+ "fontSize",
26
+ "lineHeight",
27
+ "letterSpacing",
28
+ "wordSpacing",
29
+ "translateX",
30
+ "translateY",
31
+ "translateZ",
32
+ "borderRadius",
33
+ "borderTopLeftRadius",
34
+ "borderTopRightRadius",
35
+ "borderBottomLeftRadius",
36
+ "borderBottomRightRadius",
37
+ ];
38
+
39
+ // Properties that need deg units
40
+ const degProperties = [
41
+ "rotate",
42
+ "rotateX",
43
+ "rotateY",
44
+ "rotateZ",
45
+ "skew",
46
+ "skewX",
47
+ "skewY",
48
+ ];
49
+
50
+ // Properties that should remain unitless
51
+ const unitlessProperties = [
52
+ "opacity",
53
+ "zIndex",
54
+ "flexGrow",
55
+ "flexShrink",
56
+ "order",
57
+ "columnCount",
58
+ "scale",
59
+ "scaleX",
60
+ "scaleY",
61
+ "scaleZ",
62
+ ];
63
+
64
+ // Normalize a single style value
65
+ export const normalizeStyle = (value, propertyName, context = "js") => {
66
+ if (propertyName === "transform") {
67
+ if (context === "js") {
68
+ if (typeof value === "string") {
69
+ // For js context, prefer objects
70
+ return parseCSSTransform(value);
71
+ }
72
+ // If code does transform: { translateX: "10px" }
73
+ // we want to store { translateX: 10 }
74
+ const transformNormalized = {};
75
+ for (const key of Object.keys(value)) {
76
+ const partValue = normalizeStyle(value[key], key, "js");
77
+ transformNormalized[key] = partValue;
78
+ }
79
+ return transformNormalized;
80
+ }
81
+ if (typeof value === "object" && value !== null) {
82
+ // For CSS context, ensure transform is a string
83
+ return stringifyCSSTransform(value);
84
+ }
85
+ return value;
86
+ }
87
+
88
+ // Handle transform.* properties (e.g., "transform.translateX")
89
+ if (propertyName.startsWith("transform.")) {
90
+ if (context === "css") {
91
+ console.warn(
92
+ `normalizeStyle: magic properties like "${propertyName}" are not applicable in "css" context. Returning original value.`,
93
+ );
94
+ return value;
95
+ }
96
+ const transformProperty = propertyName.slice(10); // Remove "transform." prefix
97
+ // If value is a CSS transform string, parse it first to extract the specific property
98
+ if (typeof value === "string") {
99
+ if (value === "none") {
100
+ return undefined;
101
+ }
102
+ const parsedTransform = parseCSSTransform(value);
103
+ return parsedTransform?.[transformProperty];
104
+ }
105
+ // If value is a transform object, extract the property directly
106
+ if (typeof value === "object" && value !== null) {
107
+ return value[transformProperty];
108
+ }
109
+ // never supposed to happen, the value given is neither string nor object
110
+ return undefined;
111
+ }
112
+
113
+ if (pxProperties.includes(propertyName)) {
114
+ return normalizeNumber(value, context, "px", propertyName);
115
+ }
116
+ if (degProperties.includes(propertyName)) {
117
+ return normalizeNumber(value, context, "deg", propertyName);
118
+ }
119
+ if (unitlessProperties.includes(propertyName)) {
120
+ return normalizeNumber(value, context, "", propertyName);
121
+ }
122
+
123
+ return value;
124
+ };
125
+ const normalizeNumber = (value, context, unit, propertyName) => {
126
+ if (context === "css") {
127
+ if (typeof value === "number") {
128
+ if (isNaN(value)) {
129
+ console.warn(`NaN found for "${propertyName}"`);
130
+ }
131
+ return `${value}${unit}`;
132
+ }
133
+ return value;
134
+ }
135
+ if (typeof value === "string") {
136
+ if (value === "auto") {
137
+ return "auto";
138
+ }
139
+ const numericValue = parseFloat(value);
140
+ if (isNaN(numericValue)) {
141
+ console.warn(
142
+ `"${propertyName}": ${value} cannot be converted to number, returning value as-is.`,
143
+ );
144
+ return value;
145
+ }
146
+ return numericValue;
147
+ }
148
+ return value;
149
+ };
150
+
151
+ // Normalize styles for DOM application
152
+ export const normalizeStyles = (styles, context = "js") => {
153
+ const normalized = {};
154
+ for (const [key, value] of Object.entries(styles)) {
155
+ normalized[key] = normalizeStyle(value, key, context);
156
+ }
157
+ return normalized;
158
+ };
159
+
160
+ // Convert transform object to CSS string
161
+ export const stringifyCSSTransform = (transformObj) => {
162
+ const transforms = [];
163
+ for (const key of Object.keys(transformObj)) {
164
+ const transformPartValue = transformObj[key];
165
+ const normalizedTransformPartValue = normalizeStyle(
166
+ transformPartValue,
167
+ key,
168
+ "css",
169
+ );
170
+ transforms.push(`${key}(${normalizedTransformPartValue})`);
171
+ }
172
+ return transforms.join(" ");
173
+ };
174
+
175
+ // Parse transform CSS string into object
176
+ export const parseCSSTransform = (transformString) => {
177
+ if (!transformString || transformString === "none") {
178
+ return undefined;
179
+ }
180
+
181
+ const transformObj = {};
182
+
183
+ // Parse transform functions
184
+ const transformPattern = /(\w+)\(([^)]+)\)/g;
185
+ let match;
186
+
187
+ while ((match = transformPattern.exec(transformString)) !== null) {
188
+ const [, functionName, value] = match;
189
+
190
+ // Handle matrix functions specially
191
+ if (functionName === "matrix" || functionName === "matrix3d") {
192
+ const matrixComponents = parseMatrixTransform(match[0]);
193
+ if (matrixComponents) {
194
+ // Only add non-default values to preserve original information
195
+ Object.assign(transformObj, matrixComponents);
196
+ }
197
+ // If matrix can't be parsed to simple components, skip it (keep complex transforms as-is)
198
+ continue;
199
+ }
200
+
201
+ // Handle regular transform functions
202
+ const normalizedValue = normalizeStyle(value.trim(), functionName, "js");
203
+ if (normalizedValue !== undefined) {
204
+ transformObj[functionName] = normalizedValue;
205
+ }
206
+ }
207
+
208
+ // Return undefined if no properties were extracted (preserves original information)
209
+ return Object.keys(transformObj).length > 0 ? transformObj : undefined;
210
+ };
211
+
212
+ // Parse a matrix transform and extract simple transform components when possible
213
+ const parseMatrixTransform = (matrixString) => {
214
+ // Match matrix() or matrix3d() functions
215
+ const matrixMatch = matrixString.match(/matrix(?:3d)?\(([^)]+)\)/);
216
+ if (!matrixMatch) {
217
+ return null;
218
+ }
219
+
220
+ const values = matrixMatch[1].split(",").map((v) => parseFloat(v.trim()));
221
+
222
+ if (matrixString.includes("matrix3d")) {
223
+ // matrix3d(a, b, c, d, e, f, g, h, i, j, k, l, m, n, o, p)
224
+ if (values.length !== 16) {
225
+ return null;
226
+ }
227
+ const [a, b, c, d, e, f, g, h, i, j, k, l, m, n, o, p] = values;
228
+ // Check if it's a simple 2D transform (most common case)
229
+ if (
230
+ c === 0 &&
231
+ d === 0 &&
232
+ g === 0 &&
233
+ h === 0 &&
234
+ i === 0 &&
235
+ j === 0 &&
236
+ k === 1 &&
237
+ l === 0 &&
238
+ o === 0 &&
239
+ p === 1
240
+ ) {
241
+ // This is essentially a 2D transform
242
+ return parseSimple2DMatrix(a, b, e, f, m, n);
243
+ }
244
+ return null; // Complex 3D transform
245
+ }
246
+ // matrix(a, b, c, d, e, f)
247
+ if (values.length !== 6) {
248
+ return null;
249
+ }
250
+ const [a, b, c, d, e, f] = values;
251
+ return parseSimple2DMatrix(a, b, c, d, e, f);
252
+ };
253
+
254
+ // Parse a simple 2D matrix into transform components
255
+ const parseSimple2DMatrix = (a, b, c, d, e, f) => {
256
+ const result = {};
257
+
258
+ // Extract translation - only add if not default (0)
259
+ if (e !== 0) {
260
+ result.translateX = e;
261
+ }
262
+ if (f !== 0) {
263
+ result.translateY = f;
264
+ }
265
+
266
+ // Check for identity matrix (no transform)
267
+ if (a === 1 && b === 0 && c === 0 && d === 1) {
268
+ return result; // Only translation
269
+ }
270
+
271
+ // Decompose the 2D transformation matrix
272
+ // Based on: https://frederic-wang.fr/decomposition-of-2d-transform-matrices.html
273
+
274
+ const det = a * d - b * c;
275
+ // Degenerate matrix (maps to a line or point)
276
+ if (det === 0) {
277
+ return null;
278
+ }
279
+
280
+ // Extract scale and rotation
281
+ if (c === 0) {
282
+ // Simple case: no skew
283
+ if (a !== 1) {
284
+ result.scaleX = a;
285
+ }
286
+ if (d !== 1) {
287
+ result.scaleY = d;
288
+ }
289
+ if (b !== 0) {
290
+ const angle = Math.atan(b / a) * (180 / Math.PI);
291
+ if (angle !== 0) {
292
+ result.rotate = angle;
293
+ }
294
+ }
295
+ return result;
296
+ }
297
+
298
+ // General case: decompose using QR decomposition approach
299
+ const scaleX = Math.sqrt(a * a + b * b);
300
+ const scaleY = det / scaleX;
301
+ const rotation = Math.atan2(b, a) * (180 / Math.PI);
302
+ const skewX =
303
+ Math.atan((a * c + b * d) / (scaleX * scaleX)) * (180 / Math.PI);
304
+ if (scaleX !== 1) {
305
+ result.scaleX = scaleX;
306
+ }
307
+ if (scaleY !== 1) {
308
+ result.scaleY = scaleY;
309
+ }
310
+ if (rotation !== 0) {
311
+ result.rotate = rotation;
312
+ }
313
+ if (skewX !== 0) {
314
+ result.skewX = skewX;
315
+ }
316
+ return result;
317
+ };