@jsenv/dom 0.5.0 → 0.5.2
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,30 @@ 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
|
+
// in case stylesB is a string we first parse it
|
|
672
|
+
stylesB = normalizeStyles(stylesB, context);
|
|
673
|
+
const bKeyToVisitSet = new Set(Object.keys(stylesB));
|
|
674
|
+
for (const aKey of aKeys) {
|
|
675
|
+
const bHasKey = bKeyToVisitSet.has(aKey);
|
|
676
|
+
if (bHasKey) {
|
|
677
|
+
bKeyToVisitSet.delete(aKey);
|
|
678
|
+
result[aKey] = mergeOneStyle(stylesA[aKey], stylesB[aKey], aKey, context);
|
|
610
679
|
} else {
|
|
611
|
-
result[
|
|
680
|
+
result[aKey] = normalizeStyle(stylesA[aKey], aKey, context);
|
|
612
681
|
}
|
|
613
682
|
}
|
|
683
|
+
for (const bKey of bKeyToVisitSet) {
|
|
684
|
+
result[bKey] = stylesB[bKey];
|
|
685
|
+
}
|
|
614
686
|
return result;
|
|
615
687
|
};
|
|
616
688
|
|
|
@@ -772,9 +844,9 @@ const createStyleController = (name = "anonymous") => {
|
|
|
772
844
|
throw new Error("styles must be an object");
|
|
773
845
|
}
|
|
774
846
|
|
|
775
|
-
const normalizedStylesToSet = normalizeStyles(stylesToSet, "js");
|
|
776
847
|
const elementData = elementWeakMap.get(element);
|
|
777
848
|
if (!elementData) {
|
|
849
|
+
const normalizedStylesToSet = normalizeStyles(stylesToSet, "js");
|
|
778
850
|
const animation = createAnimationForStyles(
|
|
779
851
|
element,
|
|
780
852
|
normalizedStylesToSet,
|
|
@@ -789,7 +861,7 @@ const createStyleController = (name = "anonymous") => {
|
|
|
789
861
|
}
|
|
790
862
|
|
|
791
863
|
const { styles, animation } = elementData;
|
|
792
|
-
const mergedStyles = mergeStyles(styles,
|
|
864
|
+
const mergedStyles = mergeStyles(styles, stylesToSet);
|
|
793
865
|
elementData.styles = mergedStyles;
|
|
794
866
|
updateAnimationStyles(animation, mergedStyles);
|
|
795
867
|
};
|
|
@@ -10478,10 +10550,9 @@ const useResizeStatus = (elementRef, { as = "number" } = {}) => {
|
|
|
10478
10550
|
installImportMetaCss(import.meta);
|
|
10479
10551
|
import.meta.css = /* css */ `
|
|
10480
10552
|
.ui_transition_container {
|
|
10553
|
+
position: relative;
|
|
10481
10554
|
display: inline-flex;
|
|
10482
10555
|
flex: 1;
|
|
10483
|
-
position: relative;
|
|
10484
|
-
overflow: hidden;
|
|
10485
10556
|
}
|
|
10486
10557
|
|
|
10487
10558
|
.ui_transition_outer_wrapper {
|
|
@@ -10490,7 +10561,6 @@ import.meta.css = /* css */ `
|
|
|
10490
10561
|
}
|
|
10491
10562
|
|
|
10492
10563
|
.ui_transition_measure_wrapper {
|
|
10493
|
-
overflow: hidden;
|
|
10494
10564
|
display: inline-flex;
|
|
10495
10565
|
flex: 1;
|
|
10496
10566
|
}
|
|
@@ -11911,4 +11981,4 @@ const crossFade = {
|
|
|
11911
11981
|
},
|
|
11912
11982
|
};
|
|
11913
11983
|
|
|
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 };
|
|
11984
|
+
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,35 @@
|
|
|
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
|
+
// in case stylesB is a string we first parse it
|
|
19
|
+
stylesB = normalizeStyles(stylesB, context);
|
|
20
|
+
const bKeyToVisitSet = new Set(Object.keys(stylesB));
|
|
21
|
+
for (const aKey of aKeys) {
|
|
22
|
+
const bHasKey = bKeyToVisitSet.has(aKey);
|
|
23
|
+
if (bHasKey) {
|
|
24
|
+
bKeyToVisitSet.delete(aKey);
|
|
25
|
+
result[aKey] = mergeOneStyle(stylesA[aKey], stylesB[aKey], aKey, context);
|
|
9
26
|
} else {
|
|
10
|
-
result[
|
|
27
|
+
result[aKey] = normalizeStyle(stylesA[aKey], aKey, context);
|
|
11
28
|
}
|
|
12
29
|
}
|
|
30
|
+
for (const bKey of bKeyToVisitSet) {
|
|
31
|
+
result[bKey] = stylesB[bKey];
|
|
32
|
+
}
|
|
13
33
|
return result;
|
|
14
34
|
};
|
|
15
35
|
|
|
@@ -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
|
}
|