@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.
- package/dist/jsenv_dom.js +9653 -0
- package/index.js +101 -0
- package/package.json +47 -0
- package/src/attr/add_attribute_effect.js +93 -0
- package/src/attr/attributes.js +32 -0
- package/src/demos/3_columns_resize_demo.html +84 -0
- package/src/demos/3_rows_resize_demo.html +89 -0
- package/src/demos/aside_and_main_demo.html +93 -0
- package/src/demos/coordinates_demo.html +450 -0
- package/src/demos/document_autoscroll_demo.html +517 -0
- package/src/demos/drag_gesture_constraints_demo.html +701 -0
- package/src/demos/drag_gesture_demo.html +1047 -0
- package/src/demos/drag_gesture_element_to_impact_demo.html +445 -0
- package/src/demos/drag_reference_element_demo.html +480 -0
- package/src/demos/flex_details_set_demo.html +302 -0
- package/src/demos/flex_details_set_demo_2.html +315 -0
- package/src/demos/visible_rect_demo.html +525 -0
- package/src/interaction/drag/constraint_feedback_line.js +92 -0
- package/src/interaction/drag/drag_constraint.js +659 -0
- package/src/interaction/drag/drag_debug_markers.js +635 -0
- package/src/interaction/drag/drag_element_positioner.js +382 -0
- package/src/interaction/drag/drag_gesture.js +566 -0
- package/src/interaction/drag/drag_resize_demo.html +571 -0
- package/src/interaction/drag/drag_to_move.js +301 -0
- package/src/interaction/drag/drag_to_resize_gesture.js +68 -0
- package/src/interaction/drag/drop_target_detection.js +148 -0
- package/src/interaction/drag/sticky_frontiers.js +160 -0
- package/src/interaction/element_log.js +8 -0
- package/src/interaction/event_marker.js +14 -0
- package/src/interaction/focus/active_element.js +33 -0
- package/src/interaction/focus/arrow_navigation.js +599 -0
- package/src/interaction/focus/element_is_focusable.js +57 -0
- package/src/interaction/focus/element_is_visible.js +36 -0
- package/src/interaction/focus/find_focusable.js +21 -0
- package/src/interaction/focus/focus_group.js +91 -0
- package/src/interaction/focus/focus_group_registry.js +12 -0
- package/src/interaction/focus/focus_nav.js +12 -0
- package/src/interaction/focus/focus_nav_event_marker.js +14 -0
- package/src/interaction/focus/focus_trap.js +105 -0
- package/src/interaction/focus/tab_navigation.js +128 -0
- package/src/interaction/focus/tests/focus_group_skip_tab_test.html +206 -0
- package/src/interaction/focus/tests/tree_focus_test.html +304 -0
- package/src/interaction/focus/tests/tree_focus_test.jsx +261 -0
- package/src/interaction/focus/tests/tree_focus_test_preact.html +13 -0
- package/src/interaction/isolate_interactions.js +161 -0
- package/src/interaction/keyboard.js +26 -0
- package/src/interaction/scroll/capture_scroll.js +47 -0
- package/src/interaction/scroll/is_scrollable.js +159 -0
- package/src/interaction/scroll/scroll_container.js +110 -0
- package/src/interaction/scroll/scroll_trap.js +44 -0
- package/src/interaction/scroll/scrollbar_size.js +20 -0
- package/src/interaction/scroll/wheel_through.js +138 -0
- package/src/iterable_weak_set.js +66 -0
- package/src/position/dom_coords.js +340 -0
- package/src/position/offset_parent.js +15 -0
- package/src/position/position_fixed.js +15 -0
- package/src/position/position_sticky.js +213 -0
- package/src/position/sticky_rect.js +79 -0
- package/src/position/visible_rect.js +482 -0
- package/src/pub_sub.js +28 -0
- package/src/size/can_take_size.js +11 -0
- package/src/size/details_content_full_height.js +63 -0
- package/src/size/flex_details_set.js +974 -0
- package/src/size/get_available_height.js +22 -0
- package/src/size/get_available_width.js +22 -0
- package/src/size/get_border_sizes.js +14 -0
- package/src/size/get_height.js +4 -0
- package/src/size/get_inner_height.js +15 -0
- package/src/size/get_inner_width.js +15 -0
- package/src/size/get_margin_sizes.js +10 -0
- package/src/size/get_max_height.js +57 -0
- package/src/size/get_max_width.js +47 -0
- package/src/size/get_min_height.js +14 -0
- package/src/size/get_min_width.js +14 -0
- package/src/size/get_padding_sizes.js +10 -0
- package/src/size/get_width.js +4 -0
- package/src/size/hooks/use_available_height.js +27 -0
- package/src/size/hooks/use_available_width.js +27 -0
- package/src/size/hooks/use_max_height.js +10 -0
- package/src/size/hooks/use_max_width.js +10 -0
- package/src/size/hooks/use_resize_status.js +62 -0
- package/src/size/resize.js +695 -0
- package/src/size/resolve_css_size.js +32 -0
- package/src/style/dom_styles.js +97 -0
- package/src/style/style_composition.js +78 -0
- package/src/style/style_controller.js +345 -0
- package/src/style/style_parsing.js +317 -0
- package/src/transition/demos/animation_resumption_test.xhtml +500 -0
- package/src/transition/demos/height_toggle_test.xhtml +515 -0
- package/src/transition/dom_transition.js +254 -0
- package/src/transition/easing.js +48 -0
- package/src/transition/group_transition.js +261 -0
- package/src/transition/transform_style_parser.js +32 -0
- package/src/transition/transition_playback.js +366 -0
- package/src/transition/transition_timeline.js +79 -0
- package/src/traversal.js +247 -0
- package/src/ui_transition/demos/content_states_transition_demo.html +628 -0
- package/src/ui_transition/demos/smooth_height_transition_demo.html +149 -0
- package/src/ui_transition/demos/transition_testing.html +354 -0
- package/src/ui_transition/ui_transition.js +1492 -0
- 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
|
+
};
|