@jsenv/dom 0.7.4 → 0.8.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 +93 -26
- package/package.json +3 -3
package/dist/jsenv_dom.js
CHANGED
|
@@ -398,7 +398,7 @@ const setStyles = createSetMany$1(setStyle);
|
|
|
398
398
|
const forceStyles = createSetMany$1(forceStyle);
|
|
399
399
|
|
|
400
400
|
// Properties that need px units
|
|
401
|
-
const
|
|
401
|
+
const pxPropertySet = new Set([
|
|
402
402
|
"width",
|
|
403
403
|
"height",
|
|
404
404
|
"top",
|
|
@@ -415,14 +415,13 @@ const pxProperties = [
|
|
|
415
415
|
"paddingRight",
|
|
416
416
|
"paddingBottom",
|
|
417
417
|
"paddingLeft",
|
|
418
|
-
"border",
|
|
419
418
|
"borderWidth",
|
|
420
419
|
"borderTopWidth",
|
|
421
420
|
"borderRightWidth",
|
|
422
421
|
"borderBottomWidth",
|
|
423
422
|
"borderLeftWidth",
|
|
424
423
|
"fontSize",
|
|
425
|
-
|
|
424
|
+
// lineHeight intentionally excluded - it should remain unitless when no unit is specified
|
|
426
425
|
"letterSpacing",
|
|
427
426
|
"wordSpacing",
|
|
428
427
|
"translateX",
|
|
@@ -436,10 +435,10 @@ const pxProperties = [
|
|
|
436
435
|
"gap",
|
|
437
436
|
"rowGap",
|
|
438
437
|
"columnGap",
|
|
439
|
-
];
|
|
438
|
+
]);
|
|
440
439
|
|
|
441
440
|
// Properties that need deg units
|
|
442
|
-
const
|
|
441
|
+
const degPropertySet = new Set([
|
|
443
442
|
"rotate",
|
|
444
443
|
"rotateX",
|
|
445
444
|
"rotateY",
|
|
@@ -447,10 +446,10 @@ const degProperties = [
|
|
|
447
446
|
"skew",
|
|
448
447
|
"skewX",
|
|
449
448
|
"skewY",
|
|
450
|
-
];
|
|
449
|
+
]);
|
|
451
450
|
|
|
452
451
|
// Properties that should remain unitless
|
|
453
|
-
const
|
|
452
|
+
const unitlessPropertySet = new Set([
|
|
454
453
|
"opacity",
|
|
455
454
|
"zIndex",
|
|
456
455
|
"flexGrow",
|
|
@@ -461,7 +460,7 @@ const unitlessProperties = [
|
|
|
461
460
|
"scaleX",
|
|
462
461
|
"scaleY",
|
|
463
462
|
"scaleZ",
|
|
464
|
-
];
|
|
463
|
+
]);
|
|
465
464
|
|
|
466
465
|
// Well-known CSS units and keywords that indicate a value already has proper formatting
|
|
467
466
|
const cssSizeUnitSet = new Set([
|
|
@@ -505,15 +504,16 @@ const cssKeywordSet = new Set([
|
|
|
505
504
|
"revert",
|
|
506
505
|
]);
|
|
507
506
|
|
|
508
|
-
|
|
509
|
-
const hasUnit = (value) => {
|
|
507
|
+
const getUnit = (value) => {
|
|
510
508
|
for (const cssUnit of cssUnitSet) {
|
|
511
509
|
if (value.endsWith(cssUnit)) {
|
|
512
|
-
return
|
|
510
|
+
return cssUnit;
|
|
513
511
|
}
|
|
514
512
|
}
|
|
515
|
-
return
|
|
513
|
+
return "";
|
|
516
514
|
};
|
|
515
|
+
// Check if value already has a unit
|
|
516
|
+
const isUnitless = (value) => getUnit(value) === "";
|
|
517
517
|
const isKeyword = (value) => {
|
|
518
518
|
return cssKeywordSet.has(value);
|
|
519
519
|
};
|
|
@@ -589,21 +589,45 @@ const normalizeStyle = (value, propertyName, context = "js") => {
|
|
|
589
589
|
return value;
|
|
590
590
|
}
|
|
591
591
|
|
|
592
|
-
if (
|
|
592
|
+
if (propertyName === "lineHeight") {
|
|
593
|
+
if (context === "js") {
|
|
594
|
+
if (typeof value === "string") {
|
|
595
|
+
const unit = getUnit(value);
|
|
596
|
+
if (unit === "px") {
|
|
597
|
+
const float = parseFloat(value);
|
|
598
|
+
return float;
|
|
599
|
+
}
|
|
600
|
+
if (unit === "") {
|
|
601
|
+
return `${value}em`;
|
|
602
|
+
}
|
|
603
|
+
return value;
|
|
604
|
+
}
|
|
605
|
+
}
|
|
606
|
+
if (context === "css") {
|
|
607
|
+
if (typeof value === "number") {
|
|
608
|
+
// When line height is converted to a number it means
|
|
609
|
+
// it was in pixels, we must restore the unit
|
|
610
|
+
return `${value}px`;
|
|
611
|
+
}
|
|
612
|
+
}
|
|
613
|
+
return value;
|
|
614
|
+
}
|
|
615
|
+
|
|
616
|
+
if (pxPropertySet.has(propertyName)) {
|
|
593
617
|
return normalizeNumber(value, {
|
|
594
618
|
propertyName,
|
|
595
619
|
unit: "px",
|
|
596
620
|
preferedType: context === "js" ? "number" : "string",
|
|
597
621
|
});
|
|
598
622
|
}
|
|
599
|
-
if (
|
|
623
|
+
if (degPropertySet.has(propertyName)) {
|
|
600
624
|
return normalizeNumber(value, {
|
|
601
625
|
propertyName,
|
|
602
626
|
unit: "deg",
|
|
603
627
|
preferedType: "string",
|
|
604
628
|
});
|
|
605
629
|
}
|
|
606
|
-
if (
|
|
630
|
+
if (unitlessPropertySet.has(propertyName)) {
|
|
607
631
|
return normalizeNumber(value, {
|
|
608
632
|
propertyName,
|
|
609
633
|
unit: "",
|
|
@@ -617,7 +641,7 @@ const normalizeNumber = (value, { unit, propertyName, preferedType }) => {
|
|
|
617
641
|
if (typeof value === "string") {
|
|
618
642
|
// Keep strings as-is (including %, em, rem, auto, none, etc.)
|
|
619
643
|
if (preferedType === "string") {
|
|
620
|
-
if (unit &&
|
|
644
|
+
if (unit && isUnitless(value) && !isKeyword(value)) {
|
|
621
645
|
return `${value}${unit}`;
|
|
622
646
|
}
|
|
623
647
|
return value;
|
|
@@ -664,6 +688,9 @@ const normalizeStyles = (styles, context = "js", mutate = false) => {
|
|
|
664
688
|
const normalized = {};
|
|
665
689
|
for (const key of Object.keys(styles)) {
|
|
666
690
|
const value = styles[key];
|
|
691
|
+
if (value === undefined) {
|
|
692
|
+
continue;
|
|
693
|
+
}
|
|
667
694
|
normalized[key] = normalizeStyle(value, key, context);
|
|
668
695
|
}
|
|
669
696
|
return normalized;
|
|
@@ -878,7 +905,7 @@ const parseSimple2DMatrix = (a, b, c, d, e, f) => {
|
|
|
878
905
|
};
|
|
879
906
|
|
|
880
907
|
// Merge two style objects, handling special cases like transform
|
|
881
|
-
const
|
|
908
|
+
const mergeTwoStyles = (stylesA, stylesB, context = "js") => {
|
|
882
909
|
if (!stylesA) {
|
|
883
910
|
return normalizeStyles(stylesB, context);
|
|
884
911
|
}
|
|
@@ -1118,7 +1145,7 @@ const createStyleController = (name = "anonymous") => {
|
|
|
1118
1145
|
}
|
|
1119
1146
|
|
|
1120
1147
|
const { styles, animation } = elementData;
|
|
1121
|
-
const mergedStyles =
|
|
1148
|
+
const mergedStyles = mergeTwoStyles(styles, stylesToSet);
|
|
1122
1149
|
elementData.styles = mergedStyles;
|
|
1123
1150
|
updateAnimationStyles(animation, mergedStyles);
|
|
1124
1151
|
};
|
|
@@ -1348,8 +1375,12 @@ const createStyleController = (name = "anonymous") => {
|
|
|
1348
1375
|
return controller;
|
|
1349
1376
|
};
|
|
1350
1377
|
|
|
1378
|
+
const getStyleForKeyframe = (styles) => {
|
|
1379
|
+
const cssStyles = normalizeStyles(styles, "css");
|
|
1380
|
+
return cssStyles;
|
|
1381
|
+
};
|
|
1351
1382
|
const createAnimationForStyles = (element, styles, id) => {
|
|
1352
|
-
const cssStylesToSet =
|
|
1383
|
+
const cssStylesToSet = getStyleForKeyframe(styles);
|
|
1353
1384
|
const animation = element.animate([cssStylesToSet], {
|
|
1354
1385
|
duration: 0,
|
|
1355
1386
|
fill: "forwards",
|
|
@@ -1361,7 +1392,7 @@ const createAnimationForStyles = (element, styles, id) => {
|
|
|
1361
1392
|
};
|
|
1362
1393
|
|
|
1363
1394
|
const updateAnimationStyles = (animation, styles) => {
|
|
1364
|
-
const cssStyles =
|
|
1395
|
+
const cssStyles = getStyleForKeyframe(styles);
|
|
1365
1396
|
animation.effect.setKeyframes([cssStyles]);
|
|
1366
1397
|
animation.play();
|
|
1367
1398
|
animation.pause();
|
|
@@ -2149,6 +2180,11 @@ const resolveCSSColor = (color, element, context = "js") => {
|
|
|
2149
2180
|
}
|
|
2150
2181
|
}
|
|
2151
2182
|
|
|
2183
|
+
if (color.startsWith("--")) {
|
|
2184
|
+
console.warn(`found "${color}". Use "var(${color})" instead.`);
|
|
2185
|
+
return null;
|
|
2186
|
+
}
|
|
2187
|
+
|
|
2152
2188
|
// Parse the resolved color and return in the requested format
|
|
2153
2189
|
const rgba = parseCSSColor(resolvedColor);
|
|
2154
2190
|
|
|
@@ -2161,18 +2197,24 @@ const resolveCSSColor = (color, element, context = "js") => {
|
|
|
2161
2197
|
|
|
2162
2198
|
/**
|
|
2163
2199
|
* Chooses between light and dark colors based on which provides better contrast against a background
|
|
2164
|
-
* @param {
|
|
2165
|
-
* @param {string}
|
|
2166
|
-
* @param {string}
|
|
2167
|
-
* @param {
|
|
2200
|
+
* @param {string} backgroundColor - CSS color value (hex, rgb, hsl, CSS variable, etc.) to test against
|
|
2201
|
+
* @param {string} [lightColor="white"] - Light color option (typically for dark backgrounds)
|
|
2202
|
+
* @param {string} [darkColor="black"] - Dark color option (typically for light backgrounds)
|
|
2203
|
+
* @param {Element} [element] - DOM element to resolve CSS variables against
|
|
2168
2204
|
* @returns {string} The color that provides better contrast (lightColor or darkColor)
|
|
2205
|
+
* @example
|
|
2206
|
+
* // Choose text color for a dark blue background
|
|
2207
|
+
* pickLightOrDark("#1a202c") // returns "white"
|
|
2208
|
+
*
|
|
2209
|
+
* // Choose text color for a light background with CSS variable
|
|
2210
|
+
* pickLightOrDark("var(--bg-color)", "white", "black", element) // returns "black" or "white"
|
|
2169
2211
|
*/
|
|
2170
2212
|
|
|
2171
2213
|
const pickLightOrDark = (
|
|
2172
|
-
element,
|
|
2173
2214
|
backgroundColor,
|
|
2174
2215
|
lightColor = "white",
|
|
2175
2216
|
darkColor = "black",
|
|
2217
|
+
element,
|
|
2176
2218
|
) => {
|
|
2177
2219
|
const resolvedBgColor = resolveCSSColor(backgroundColor, element);
|
|
2178
2220
|
const resolvedLightColor = resolveCSSColor(lightColor, element);
|
|
@@ -2192,6 +2234,31 @@ const pickLightOrDark = (
|
|
|
2192
2234
|
return contrastWithLight > contrastWithDark ? lightColor : darkColor;
|
|
2193
2235
|
};
|
|
2194
2236
|
|
|
2237
|
+
/**
|
|
2238
|
+
* Resolves the luminance value of a CSS color
|
|
2239
|
+
* @param {string} color - CSS color value (hex, rgb, hsl, CSS variable, etc.)
|
|
2240
|
+
* @param {Element} [element] - DOM element to resolve CSS variables against
|
|
2241
|
+
* @returns {number|undefined} Relative luminance (0-1) according to WCAG formula, or undefined if color cannot be resolved
|
|
2242
|
+
* @example
|
|
2243
|
+
* // Get luminance of a hex color
|
|
2244
|
+
* resolveColorLuminance("#ff0000") // returns ~0.213 (red)
|
|
2245
|
+
*
|
|
2246
|
+
* // Get luminance of a CSS variable
|
|
2247
|
+
* resolveColorLuminance("var(--primary-color)", element) // returns luminance value or undefined
|
|
2248
|
+
*
|
|
2249
|
+
* // Use for light/dark classification
|
|
2250
|
+
* const luminance = resolveColorLuminance("#2ecc71");
|
|
2251
|
+
* const isLight = luminance > 0.3; // true for light colors, false for dark
|
|
2252
|
+
*/
|
|
2253
|
+
const resolveColorLuminance = (color, element) => {
|
|
2254
|
+
const resolvedColor = resolveCSSColor(color, element);
|
|
2255
|
+
if (!resolvedColor) {
|
|
2256
|
+
return undefined;
|
|
2257
|
+
}
|
|
2258
|
+
const [r, g, b] = resolvedColor;
|
|
2259
|
+
return getLuminance(r, g, b);
|
|
2260
|
+
};
|
|
2261
|
+
|
|
2195
2262
|
const findAncestor = (node, predicate) => {
|
|
2196
2263
|
let ancestor = node.parentNode;
|
|
2197
2264
|
while (ancestor) {
|
|
@@ -11803,4 +11870,4 @@ const notifyTransitionOverflow = (element, transitionId) => {
|
|
|
11803
11870
|
};
|
|
11804
11871
|
};
|
|
11805
11872
|
|
|
11806
|
-
export { EASING, activeElementSignal, addActiveElementEffect, addAttributeEffect, addWillChange, allowWheelThrough, appendStyles, 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, getElementSignature, getFirstVisuallyVisibleAncestor, getFocusVisibilityInfo, getHeight, getInnerHeight, getInnerWidth, getMarginSizes, getMaxHeight, getMaxWidth, getMinHeight, getMinWidth, getOpacity, getPaddingSizes, getPositionedParent, getPreferedColorScheme, getScrollContainer, getScrollContainerSet, getScrollRelativeRect, getSelfAndAncestorScrolls, getStyle, getTranslateX, getTranslateY, getVisuallyVisibleInfo, getWidth, initFlexDetailsSet, initFocusGroup, initPositionSticky, initUITransition, isScrollable,
|
|
11873
|
+
export { EASING, activeElementSignal, addActiveElementEffect, addAttributeEffect, addWillChange, allowWheelThrough, appendStyles, 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, getElementSignature, getFirstVisuallyVisibleAncestor, getFocusVisibilityInfo, getHeight, getInnerHeight, getInnerWidth, getLuminance, getMarginSizes, getMaxHeight, getMaxWidth, getMinHeight, getMinWidth, getOpacity, getPaddingSizes, getPositionedParent, getPreferedColorScheme, getScrollContainer, getScrollContainerSet, getScrollRelativeRect, getSelfAndAncestorScrolls, getStyle, getTranslateX, getTranslateY, getVisuallyVisibleInfo, getWidth, initFlexDetailsSet, initFocusGroup, initPositionSticky, initUITransition, isScrollable, mergeTwoStyles, normalizeStyle, normalizeStyles, parseCSSColor, pickLightOrDark, pickPositionRelativeTo, prefersDarkColors, prefersLightColors, preventFocusNav, preventFocusNavViaKeyboard, resolveCSSColor, resolveCSSSize, resolveColorLuminance, setAttribute, setAttributes, setStyles, startDragToResizeGesture, stickyAsRelativeCoords, stringifyCSSColor, trapFocusInside, trapScrollInside, useActiveElement, useAvailableHeight, useAvailableWidth, useMaxHeight, useMaxWidth, useResizeStatus, visibleRectEffect };
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@jsenv/dom",
|
|
3
|
-
"version": "0.
|
|
3
|
+
"version": "0.8.0",
|
|
4
4
|
"description": "DOM utilities for writing frontend code",
|
|
5
5
|
"repository": {
|
|
6
6
|
"type": "git",
|
|
@@ -36,8 +36,8 @@
|
|
|
36
36
|
"devDependencies": {
|
|
37
37
|
"@jsenv/core": "../../../",
|
|
38
38
|
"@jsenv/navi": "../navi",
|
|
39
|
-
"@preact/signals": "
|
|
40
|
-
"preact": "
|
|
39
|
+
"@preact/signals": "2.4.0",
|
|
40
|
+
"preact": "11.0.0-beta.0"
|
|
41
41
|
},
|
|
42
42
|
"publishConfig": {
|
|
43
43
|
"access": "public"
|