@jsenv/dom 0.5.0 → 0.5.1
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
CHANGED
|
@@ -316,6 +316,9 @@ const pxProperties = [
|
|
|
316
316
|
"borderTopRightRadius",
|
|
317
317
|
"borderBottomLeftRadius",
|
|
318
318
|
"borderBottomRightRadius",
|
|
319
|
+
"gap",
|
|
320
|
+
"rowGap",
|
|
321
|
+
"columnGap",
|
|
319
322
|
];
|
|
320
323
|
|
|
321
324
|
// Properties that need deg units
|
|
@@ -435,13 +438,67 @@ const normalizeNumber = (value, context, unit, propertyName) => {
|
|
|
435
438
|
|
|
436
439
|
// Normalize styles for DOM application
|
|
437
440
|
const normalizeStyles = (styles, context = "js") => {
|
|
441
|
+
if (typeof styles === "string") {
|
|
442
|
+
styles = parseStyleString(styles);
|
|
443
|
+
return styles;
|
|
444
|
+
}
|
|
438
445
|
const normalized = {};
|
|
439
|
-
for (const
|
|
446
|
+
for (const key of Object.keys(styles)) {
|
|
447
|
+
const value = styles[key];
|
|
440
448
|
normalized[key] = normalizeStyle(value, key, context);
|
|
441
449
|
}
|
|
442
450
|
return normalized;
|
|
443
451
|
};
|
|
444
452
|
|
|
453
|
+
/**
|
|
454
|
+
* Parses a CSS style string into a style object.
|
|
455
|
+
* Handles CSS properties with proper camelCase conversion.
|
|
456
|
+
*
|
|
457
|
+
* @param {string} styleString - CSS style string like "color: red; font-size: 14px;"
|
|
458
|
+
* @returns {object} Style object with camelCase properties
|
|
459
|
+
*/
|
|
460
|
+
const parseStyleString = (styleString, context = "js") => {
|
|
461
|
+
const style = {};
|
|
462
|
+
|
|
463
|
+
if (!styleString || typeof styleString !== "string") {
|
|
464
|
+
return style;
|
|
465
|
+
}
|
|
466
|
+
|
|
467
|
+
// Split by semicolon and process each declaration
|
|
468
|
+
const declarations = styleString.split(";");
|
|
469
|
+
|
|
470
|
+
for (let declaration of declarations) {
|
|
471
|
+
declaration = declaration.trim();
|
|
472
|
+
if (!declaration) continue;
|
|
473
|
+
|
|
474
|
+
const colonIndex = declaration.indexOf(":");
|
|
475
|
+
if (colonIndex === -1) continue;
|
|
476
|
+
|
|
477
|
+
const property = declaration.slice(0, colonIndex).trim();
|
|
478
|
+
const value = declaration.slice(colonIndex + 1).trim();
|
|
479
|
+
|
|
480
|
+
if (property && value) {
|
|
481
|
+
// CSS custom properties (starting with --) should NOT be converted to camelCase
|
|
482
|
+
if (property.startsWith("--")) {
|
|
483
|
+
style[property] = normalizeStyle(value, property, context);
|
|
484
|
+
} else {
|
|
485
|
+
// Convert kebab-case to camelCase (e.g., "font-size" -> "fontSize")
|
|
486
|
+
const camelCaseProperty = property.replace(
|
|
487
|
+
/-([a-z])/g,
|
|
488
|
+
(match, letter) => letter.toUpperCase(),
|
|
489
|
+
);
|
|
490
|
+
style[camelCaseProperty] = normalizeStyle(
|
|
491
|
+
value,
|
|
492
|
+
camelCaseProperty,
|
|
493
|
+
context,
|
|
494
|
+
);
|
|
495
|
+
}
|
|
496
|
+
}
|
|
497
|
+
}
|
|
498
|
+
|
|
499
|
+
return style;
|
|
500
|
+
};
|
|
501
|
+
|
|
445
502
|
// Convert transform object to CSS string
|
|
446
503
|
const stringifyCSSTransform = (transformObj) => {
|
|
447
504
|
const transforms = [];
|
|
@@ -602,15 +659,28 @@ const parseSimple2DMatrix = (a, b, c, d, e, f) => {
|
|
|
602
659
|
};
|
|
603
660
|
|
|
604
661
|
// Merge two style objects, handling special cases like transform
|
|
605
|
-
const mergeStyles = (stylesA, stylesB) => {
|
|
606
|
-
|
|
607
|
-
|
|
608
|
-
|
|
609
|
-
|
|
662
|
+
const mergeStyles = (stylesA, stylesB, context = "js") => {
|
|
663
|
+
if (!stylesA) {
|
|
664
|
+
return normalizeStyles(stylesB, context);
|
|
665
|
+
}
|
|
666
|
+
if (!stylesB) {
|
|
667
|
+
return normalizeStyles(stylesA, context);
|
|
668
|
+
}
|
|
669
|
+
const result = {};
|
|
670
|
+
const aKeys = Object.keys(stylesA);
|
|
671
|
+
const bKeyToVisitSet = new Set(Object.keys(stylesB));
|
|
672
|
+
for (const aKey of aKeys) {
|
|
673
|
+
const bHasKey = bKeyToVisitSet.has(aKey);
|
|
674
|
+
if (bHasKey) {
|
|
675
|
+
bKeyToVisitSet.delete(aKey);
|
|
676
|
+
result[aKey] = mergeOneStyle(stylesA[aKey], stylesB[aKey], aKey, context);
|
|
610
677
|
} else {
|
|
611
|
-
result[
|
|
678
|
+
result[aKey] = normalizeStyle(stylesA[aKey], aKey, context);
|
|
612
679
|
}
|
|
613
680
|
}
|
|
681
|
+
for (const bKey of bKeyToVisitSet) {
|
|
682
|
+
result[bKey] = normalizeStyle(stylesB[bKey], bKey, context);
|
|
683
|
+
}
|
|
614
684
|
return result;
|
|
615
685
|
};
|
|
616
686
|
|
|
@@ -772,9 +842,9 @@ const createStyleController = (name = "anonymous") => {
|
|
|
772
842
|
throw new Error("styles must be an object");
|
|
773
843
|
}
|
|
774
844
|
|
|
775
|
-
const normalizedStylesToSet = normalizeStyles(stylesToSet, "js");
|
|
776
845
|
const elementData = elementWeakMap.get(element);
|
|
777
846
|
if (!elementData) {
|
|
847
|
+
const normalizedStylesToSet = normalizeStyles(stylesToSet, "js");
|
|
778
848
|
const animation = createAnimationForStyles(
|
|
779
849
|
element,
|
|
780
850
|
normalizedStylesToSet,
|
|
@@ -789,7 +859,7 @@ const createStyleController = (name = "anonymous") => {
|
|
|
789
859
|
}
|
|
790
860
|
|
|
791
861
|
const { styles, animation } = elementData;
|
|
792
|
-
const mergedStyles = mergeStyles(styles,
|
|
862
|
+
const mergedStyles = mergeStyles(styles, stylesToSet);
|
|
793
863
|
elementData.styles = mergedStyles;
|
|
794
864
|
updateAnimationStyles(animation, mergedStyles);
|
|
795
865
|
};
|
|
@@ -10478,10 +10548,9 @@ const useResizeStatus = (elementRef, { as = "number" } = {}) => {
|
|
|
10478
10548
|
installImportMetaCss(import.meta);
|
|
10479
10549
|
import.meta.css = /* css */ `
|
|
10480
10550
|
.ui_transition_container {
|
|
10551
|
+
position: relative;
|
|
10481
10552
|
display: inline-flex;
|
|
10482
10553
|
flex: 1;
|
|
10483
|
-
position: relative;
|
|
10484
|
-
overflow: hidden;
|
|
10485
10554
|
}
|
|
10486
10555
|
|
|
10487
10556
|
.ui_transition_outer_wrapper {
|
|
@@ -10490,7 +10559,6 @@ import.meta.css = /* css */ `
|
|
|
10490
10559
|
}
|
|
10491
10560
|
|
|
10492
10561
|
.ui_transition_measure_wrapper {
|
|
10493
|
-
overflow: hidden;
|
|
10494
10562
|
display: inline-flex;
|
|
10495
10563
|
flex: 1;
|
|
10496
10564
|
}
|
|
@@ -11911,4 +11979,4 @@ const crossFade = {
|
|
|
11911
11979
|
},
|
|
11912
11980
|
};
|
|
11913
11981
|
|
|
11914
|
-
export { EASING, activeElementSignal, addActiveElementEffect, addAttributeEffect, addWillChange, allowWheelThrough, canInterceptKeys, captureScrollState, createDragGestureController, createDragToMoveGestureController, createHeightTransition, createIterableWeakSet, createOpacityTransition, createPubSub, createStyleController, createTimelineTransition, createTransition, createTranslateXTransition, createValueEffect, createWidthTransition, cubicBezier, dragAfterThreshold, elementIsFocusable, elementIsVisibleForFocus, elementIsVisuallyVisible, findAfter, findAncestor, findBefore, findDescendant, findFocusable, getAvailableHeight, getAvailableWidth, getBorderSizes, getContrastRatio, getDefaultStyles, getDragCoordinates, getDropTargetInfo, getFirstVisuallyVisibleAncestor, getFocusVisibilityInfo, getHeight, getInnerHeight, getInnerWidth, getMarginSizes, getMaxHeight, getMaxWidth, getMinHeight, getMinWidth, getPaddingSizes, getPositionedParent, getPreferedColorScheme, getScrollContainer, getScrollContainerSet, getScrollRelativeRect, getSelfAndAncestorScrolls, getStyle, getVisuallyVisibleInfo, getWidth, initFlexDetailsSet, initFocusGroup, initPositionSticky, initUITransition, isScrollable, parseCSSColor, pickLightOrDark, pickPositionRelativeTo, prefersDarkColors, prefersLightColors, preventFocusNav, preventFocusNavViaKeyboard, resolveCSSColor, resolveCSSSize, setAttribute, setAttributes, setStyles, startDragToResizeGesture, stickyAsRelativeCoords, stringifyCSSColor, trapFocusInside, trapScrollInside, useActiveElement, useAvailableHeight, useAvailableWidth, useMaxHeight, useMaxWidth, useResizeStatus, visibleRectEffect };
|
|
11982
|
+
export { EASING, activeElementSignal, addActiveElementEffect, addAttributeEffect, addWillChange, allowWheelThrough, canInterceptKeys, captureScrollState, createDragGestureController, createDragToMoveGestureController, createHeightTransition, createIterableWeakSet, createOpacityTransition, createPubSub, createStyleController, createTimelineTransition, createTransition, createTranslateXTransition, createValueEffect, createWidthTransition, cubicBezier, dragAfterThreshold, elementIsFocusable, elementIsVisibleForFocus, elementIsVisuallyVisible, findAfter, findAncestor, findBefore, findDescendant, findFocusable, getAvailableHeight, getAvailableWidth, getBorderSizes, getContrastRatio, getDefaultStyles, getDragCoordinates, getDropTargetInfo, getFirstVisuallyVisibleAncestor, getFocusVisibilityInfo, getHeight, getInnerHeight, getInnerWidth, getMarginSizes, getMaxHeight, getMaxWidth, getMinHeight, getMinWidth, getPaddingSizes, getPositionedParent, getPreferedColorScheme, getScrollContainer, getScrollContainerSet, getScrollRelativeRect, getSelfAndAncestorScrolls, getStyle, getVisuallyVisibleInfo, getWidth, initFlexDetailsSet, initFocusGroup, initPositionSticky, initUITransition, isScrollable, mergeStyles, normalizeStyles, parseCSSColor, pickLightOrDark, pickPositionRelativeTo, prefersDarkColors, prefersLightColors, preventFocusNav, preventFocusNavViaKeyboard, resolveCSSColor, resolveCSSSize, setAttribute, setAttributes, setStyles, startDragToResizeGesture, stickyAsRelativeCoords, stringifyCSSColor, trapFocusInside, trapScrollInside, useActiveElement, useAvailableHeight, useAvailableWidth, useMaxHeight, useMaxWidth, useResizeStatus, visibleRectEffect };
|
package/index.js
CHANGED
|
@@ -5,8 +5,10 @@ export { createValueEffect } from "./src/value_effect.js";
|
|
|
5
5
|
|
|
6
6
|
// style
|
|
7
7
|
export { addWillChange, getStyle, setStyles } from "./src/style/dom_styles.js";
|
|
8
|
+
export { mergeStyles } from "./src/style/style_composition.js";
|
|
8
9
|
export { createStyleController } from "./src/style/style_controller.js";
|
|
9
10
|
export { getDefaultStyles } from "./src/style/style_default.js";
|
|
11
|
+
export { normalizeStyles } from "./src/style/style_parsing.js";
|
|
10
12
|
|
|
11
13
|
// attributes
|
|
12
14
|
export { addAttributeEffect } from "./src/attr/add_attribute_effect.js";
|
package/package.json
CHANGED
|
@@ -1,15 +1,33 @@
|
|
|
1
|
-
import {
|
|
1
|
+
import {
|
|
2
|
+
normalizeStyle,
|
|
3
|
+
normalizeStyles,
|
|
4
|
+
parseCSSTransform,
|
|
5
|
+
stringifyCSSTransform,
|
|
6
|
+
} from "./style_parsing.js";
|
|
2
7
|
|
|
3
8
|
// Merge two style objects, handling special cases like transform
|
|
4
|
-
export const mergeStyles = (stylesA, stylesB) => {
|
|
5
|
-
|
|
6
|
-
|
|
7
|
-
|
|
8
|
-
|
|
9
|
+
export const mergeStyles = (stylesA, stylesB, context = "js") => {
|
|
10
|
+
if (!stylesA) {
|
|
11
|
+
return normalizeStyles(stylesB, context);
|
|
12
|
+
}
|
|
13
|
+
if (!stylesB) {
|
|
14
|
+
return normalizeStyles(stylesA, context);
|
|
15
|
+
}
|
|
16
|
+
const result = {};
|
|
17
|
+
const aKeys = Object.keys(stylesA);
|
|
18
|
+
const bKeyToVisitSet = new Set(Object.keys(stylesB));
|
|
19
|
+
for (const aKey of aKeys) {
|
|
20
|
+
const bHasKey = bKeyToVisitSet.has(aKey);
|
|
21
|
+
if (bHasKey) {
|
|
22
|
+
bKeyToVisitSet.delete(aKey);
|
|
23
|
+
result[aKey] = mergeOneStyle(stylesA[aKey], stylesB[aKey], aKey, context);
|
|
9
24
|
} else {
|
|
10
|
-
result[
|
|
25
|
+
result[aKey] = normalizeStyle(stylesA[aKey], aKey, context);
|
|
11
26
|
}
|
|
12
27
|
}
|
|
28
|
+
for (const bKey of bKeyToVisitSet) {
|
|
29
|
+
result[bKey] = normalizeStyle(stylesB[bKey], bKey, context);
|
|
30
|
+
}
|
|
13
31
|
return result;
|
|
14
32
|
};
|
|
15
33
|
|
|
@@ -94,9 +94,9 @@ export const createStyleController = (name = "anonymous") => {
|
|
|
94
94
|
throw new Error("styles must be an object");
|
|
95
95
|
}
|
|
96
96
|
|
|
97
|
-
const normalizedStylesToSet = normalizeStyles(stylesToSet, "js");
|
|
98
97
|
const elementData = elementWeakMap.get(element);
|
|
99
98
|
if (!elementData) {
|
|
99
|
+
const normalizedStylesToSet = normalizeStyles(stylesToSet, "js");
|
|
100
100
|
const animation = createAnimationForStyles(
|
|
101
101
|
element,
|
|
102
102
|
normalizedStylesToSet,
|
|
@@ -111,7 +111,7 @@ export const createStyleController = (name = "anonymous") => {
|
|
|
111
111
|
}
|
|
112
112
|
|
|
113
113
|
const { styles, animation } = elementData;
|
|
114
|
-
const mergedStyles = mergeStyles(styles,
|
|
114
|
+
const mergedStyles = mergeStyles(styles, stylesToSet);
|
|
115
115
|
elementData.styles = mergedStyles;
|
|
116
116
|
updateAnimationStyles(animation, mergedStyles);
|
|
117
117
|
};
|
|
@@ -34,6 +34,9 @@ const pxProperties = [
|
|
|
34
34
|
"borderTopRightRadius",
|
|
35
35
|
"borderBottomLeftRadius",
|
|
36
36
|
"borderBottomRightRadius",
|
|
37
|
+
"gap",
|
|
38
|
+
"rowGap",
|
|
39
|
+
"columnGap",
|
|
37
40
|
];
|
|
38
41
|
|
|
39
42
|
// Properties that need deg units
|
|
@@ -153,13 +156,67 @@ const normalizeNumber = (value, context, unit, propertyName) => {
|
|
|
153
156
|
|
|
154
157
|
// Normalize styles for DOM application
|
|
155
158
|
export const normalizeStyles = (styles, context = "js") => {
|
|
159
|
+
if (typeof styles === "string") {
|
|
160
|
+
styles = parseStyleString(styles);
|
|
161
|
+
return styles;
|
|
162
|
+
}
|
|
156
163
|
const normalized = {};
|
|
157
|
-
for (const
|
|
164
|
+
for (const key of Object.keys(styles)) {
|
|
165
|
+
const value = styles[key];
|
|
158
166
|
normalized[key] = normalizeStyle(value, key, context);
|
|
159
167
|
}
|
|
160
168
|
return normalized;
|
|
161
169
|
};
|
|
162
170
|
|
|
171
|
+
/**
|
|
172
|
+
* Parses a CSS style string into a style object.
|
|
173
|
+
* Handles CSS properties with proper camelCase conversion.
|
|
174
|
+
*
|
|
175
|
+
* @param {string} styleString - CSS style string like "color: red; font-size: 14px;"
|
|
176
|
+
* @returns {object} Style object with camelCase properties
|
|
177
|
+
*/
|
|
178
|
+
export const parseStyleString = (styleString, context = "js") => {
|
|
179
|
+
const style = {};
|
|
180
|
+
|
|
181
|
+
if (!styleString || typeof styleString !== "string") {
|
|
182
|
+
return style;
|
|
183
|
+
}
|
|
184
|
+
|
|
185
|
+
// Split by semicolon and process each declaration
|
|
186
|
+
const declarations = styleString.split(";");
|
|
187
|
+
|
|
188
|
+
for (let declaration of declarations) {
|
|
189
|
+
declaration = declaration.trim();
|
|
190
|
+
if (!declaration) continue;
|
|
191
|
+
|
|
192
|
+
const colonIndex = declaration.indexOf(":");
|
|
193
|
+
if (colonIndex === -1) continue;
|
|
194
|
+
|
|
195
|
+
const property = declaration.slice(0, colonIndex).trim();
|
|
196
|
+
const value = declaration.slice(colonIndex + 1).trim();
|
|
197
|
+
|
|
198
|
+
if (property && value) {
|
|
199
|
+
// CSS custom properties (starting with --) should NOT be converted to camelCase
|
|
200
|
+
if (property.startsWith("--")) {
|
|
201
|
+
style[property] = normalizeStyle(value, property, context);
|
|
202
|
+
} else {
|
|
203
|
+
// Convert kebab-case to camelCase (e.g., "font-size" -> "fontSize")
|
|
204
|
+
const camelCaseProperty = property.replace(
|
|
205
|
+
/-([a-z])/g,
|
|
206
|
+
(match, letter) => letter.toUpperCase(),
|
|
207
|
+
);
|
|
208
|
+
style[camelCaseProperty] = normalizeStyle(
|
|
209
|
+
value,
|
|
210
|
+
camelCaseProperty,
|
|
211
|
+
context,
|
|
212
|
+
);
|
|
213
|
+
}
|
|
214
|
+
}
|
|
215
|
+
}
|
|
216
|
+
|
|
217
|
+
return style;
|
|
218
|
+
};
|
|
219
|
+
|
|
163
220
|
// Convert transform object to CSS string
|
|
164
221
|
export const stringifyCSSTransform = (transformObj) => {
|
|
165
222
|
const transforms = [];
|
|
@@ -58,10 +58,9 @@ import { createGroupTransitionController } from "../transition/group_transition.
|
|
|
58
58
|
|
|
59
59
|
import.meta.css = /* css */ `
|
|
60
60
|
.ui_transition_container {
|
|
61
|
+
position: relative;
|
|
61
62
|
display: inline-flex;
|
|
62
63
|
flex: 1;
|
|
63
|
-
position: relative;
|
|
64
|
-
overflow: hidden;
|
|
65
64
|
}
|
|
66
65
|
|
|
67
66
|
.ui_transition_outer_wrapper {
|
|
@@ -70,7 +69,6 @@ import.meta.css = /* css */ `
|
|
|
70
69
|
}
|
|
71
70
|
|
|
72
71
|
.ui_transition_measure_wrapper {
|
|
73
|
-
overflow: hidden;
|
|
74
72
|
display: inline-flex;
|
|
75
73
|
flex: 1;
|
|
76
74
|
}
|