@jsenv/dom 0.9.0 → 0.9.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.
Files changed (2) hide show
  1. package/dist/jsenv_dom.js +62 -33
  2. package/package.json +1 -1
package/dist/jsenv_dom.js CHANGED
@@ -442,7 +442,6 @@ const parseCSSColor = (color, element) => {
442
442
 
443
443
  // Pass through CSS color functions we don't handle
444
444
  if (
445
- color.startsWith("color(") ||
446
445
  color.startsWith("lch(") ||
447
446
  color.startsWith("oklch(") ||
448
447
  color.startsWith("lab(") ||
@@ -453,6 +452,21 @@ const parseCSSColor = (color, element) => {
453
452
  return color;
454
453
  }
455
454
 
455
+ // color(srgb r g b) and color(srgb r g b / a)
456
+ if (color.startsWith("color(")) {
457
+ const srgbMatch = color.match(
458
+ /^color\(\s*srgb\s+([\d.]+)\s+([\d.]+)\s+([\d.]+)(?:\s*\/\s*([\d.]+))?\s*\)$/,
459
+ );
460
+ if (srgbMatch) {
461
+ const r = Math.round(parseFloat(srgbMatch[1]) * 255);
462
+ const g = Math.round(parseFloat(srgbMatch[2]) * 255);
463
+ const b = Math.round(parseFloat(srgbMatch[3]) * 255);
464
+ const a = srgbMatch[4] !== undefined ? parseFloat(srgbMatch[4]) : 1;
465
+ return [r, g, b, a];
466
+ }
467
+ return color;
468
+ }
469
+
456
470
  // Pass through relative color syntax (CSS Color Module Level 5)
457
471
  if (color.includes(" from ")) {
458
472
  return color;
@@ -600,8 +614,9 @@ const convertColorToRgba = (color) => {
600
614
  }
601
615
 
602
616
  // Named colors (basic set)
603
- if (namedColors[color]) {
604
- return [...namedColors[color], 1];
617
+ const namedColorRgb = namedColors[color];
618
+ if (namedColorRgb) {
619
+ return [...namedColorRgb, 1];
605
620
  }
606
621
  return null;
607
622
  };
@@ -3324,46 +3339,60 @@ const createSetMany = (setter) => {
3324
3339
 
3325
3340
  const setAttributes = createSetMany(setAttribute);
3326
3341
 
3342
+ const isSameColor = (color1, color2) => {
3343
+ if (color1 === color2) {
3344
+ return true;
3345
+ }
3346
+ const color1String = String(parseCSSColor(color1));
3347
+ const color2String = String(parseCSSColor(color2));
3348
+ return color1String === color2String;
3349
+ };
3350
+
3327
3351
  /**
3328
- * Chooses between light and dark colors based on which provides better contrast against a background
3329
- * @param {string} backgroundColor - CSS color value (hex, rgb, hsl, CSS variable, etc.) to test against
3330
- * @param {string} [lightColor="white"] - Light color option (typically for dark backgrounds)
3331
- * @param {string} [darkColor="black"] - Dark color option (typically for light backgrounds)
3332
- * @param {Element} [element] - DOM element to resolve CSS variables against
3333
- * @returns {string} The color that provides better contrast (lightColor or darkColor)
3334
- * @example
3335
- * // Choose text color for a dark blue background
3336
- * pickLightOrDark("#1a202c") // returns "white"
3352
+ * Returns `"white"` or `"black"`, whichever provides better contrast against
3353
+ * the given background color mirroring the CSS `contrast-color()` function.
3354
+ *
3355
+ * `"white"` is preferred when both colors yield the same contrast ratio.
3337
3356
  *
3338
- * // Choose text color for a light background with CSS variable
3339
- * pickLightOrDark("var(--bg-color)", "white", "black", element) // returns "black" or "white"
3357
+ * @param {string} backgroundColor - CSS color value (hex, rgb, hsl, CSS variable, …)
3358
+ * @param {Element} [element] - DOM element used to resolve CSS variables / computed styles
3359
+ * @returns {"white"|"black"}
3360
+ * @example
3361
+ * contrastColor("#1a202c") // "white" (dark background)
3362
+ * contrastColor("#f5f5f5") // "black" (light background)
3363
+ * contrastColor("var(--bg)", el) // "white" or "black"
3340
3364
  */
3341
3365
 
3342
3366
 
3343
- const pickLightOrDark = (
3344
- backgroundColor,
3345
- lightColor = "white",
3346
- darkColor = "black",
3347
- element,
3348
- ) => {
3367
+ const contrastColor = (backgroundColor, element) => {
3349
3368
  const resolvedBgColor = parseCSSColor(backgroundColor, element);
3350
- const resolvedLightColor = parseCSSColor(lightColor, element);
3351
- const resolvedDarkColor = parseCSSColor(darkColor, element);
3352
-
3353
- if (!resolvedBgColor || !resolvedLightColor || !resolvedDarkColor) {
3354
- // Fallback to light color if parsing fails
3355
- return lightColor;
3369
+ if (!resolvedBgColor) {
3370
+ return "white";
3356
3371
  }
3357
3372
 
3358
- const contrastWithLight = getContrastRatio(
3359
- resolvedBgColor,
3360
- resolvedLightColor,
3361
- );
3362
- const contrastWithDark = getContrastRatio(resolvedBgColor, resolvedDarkColor);
3373
+ // Composite against white when the background has transparency so the
3374
+ // luminance reflects what the user actually sees.
3375
+ const [r, g, b] =
3376
+ resolvedBgColor[3] === 1
3377
+ ? resolvedBgColor
3378
+ : compositeColor(resolvedBgColor, WHITE_RGBA);
3363
3379
 
3364
- return contrastWithLight > contrastWithDark ? lightColor : darkColor;
3380
+ const bgLuminance = getLuminance(r, g, b);
3381
+
3382
+ // One luminance comparison replaces two full contrast-ratio computations.
3383
+ // White wins (or ties) when bgLuminance <= the crossover point where both
3384
+ // colors yield identical ratios:
3385
+ // contrastWithWhite = contrastWithBlack
3386
+ // 1.05 / (L + 0.05) = (L + 0.05) / 0.05
3387
+ // L = √(1.05 × 0.05) − 0.05 ≈ 0.179
3388
+ return bgLuminance <= EQUAL_CONTRAST_LUMINANCE ? "white" : "black";
3365
3389
  };
3366
3390
 
3391
+ // Luminance threshold at which white and black yield the same contrast ratio
3392
+ // against a background. Below → white wins or ties; above → black wins.
3393
+ const EQUAL_CONTRAST_LUMINANCE = Math.sqrt(1.05 * 0.05) - 0.05;
3394
+ const WHITE_RGBA = [255, 255, 255, 1];
3395
+
3367
3396
  /**
3368
3397
  * Resolves the luminance value of a CSS color
3369
3398
  * @param {string} color - CSS color value (hex, rgb, hsl, CSS variable, etc.)
@@ -12702,4 +12731,4 @@ const useResizeStatus = (elementRef, { as = "number" } = {}) => {
12702
12731
  };
12703
12732
  };
12704
12733
 
12705
- export { EASING, activeElementSignal, addActiveElementEffect, addAttributeEffect, allowWheelThrough, appendStyles, canInterceptKeys, captureScrollState, createBackgroundColorTransition, createBackgroundTransition, createBorderRadiusTransition, createBorderTransition, createDragGestureController, createDragToMoveGestureController, createGroupTransitionController, createHeightTransition, createIterableWeakSet, createOpacityTransition, createPubSub, createStyleController, createTimelineTransition, createTransition, createTranslateXTransition, createValueEffect, createWidthTransition, cubicBezier, dragAfterThreshold, elementIsFocusable, elementIsVisibleForFocus, elementIsVisuallyVisible, findAfter, findAncestor, findBefore, findDescendant, findFocusable, getAvailableHeight, getAvailableWidth, getBackground, getBackgroundColor, getBorder, getBorderRadius, getBorderSizes, getContrastRatio, getDefaultStyles, getDragCoordinates, getDropTargetInfo, getElementSignature, getFirstVisuallyVisibleAncestor, getFocusVisibilityInfo, getHeight, getHeightWithoutTransition, getInnerHeight, getInnerWidth, getLuminance, getMarginSizes, getMaxHeight, getMaxWidth, getMinHeight, getMinWidth, getOpacity, getOpacityWithoutTransition, getPaddingSizes, getPositionedParent, getPreferedColorScheme, getScrollBox, getScrollContainer, getScrollContainerSet, getScrollRelativeRect, getSelfAndAncestorScrolls, getStyle, getTranslateX, getTranslateXWithoutTransition, getTranslateY, getVisuallyVisibleInfo, getWidth, getWidthWithoutTransition, hasCSSSizeUnit, initFlexDetailsSet, initFocusGroup, initPositionSticky, isScrollable, measureScrollbar, mergeOneStyle, mergeTwoStyles, normalizeStyles, parseStyle, pickLightOrDark, pickPositionRelativeTo, prefersDarkColors, prefersLightColors, preventFocusNav, preventFocusNavViaKeyboard, preventIntermediateScrollbar, resolveCSSColor, resolveCSSSize, resolveColorLuminance, setAttribute, setAttributes, setStyles, startDragToResizeGesture, stickyAsRelativeCoords, stringifyStyle, trapFocusInside, trapScrollInside, useActiveElement, useAvailableHeight, useAvailableWidth, useMaxHeight, useMaxWidth, useResizeStatus, visibleRectEffect };
12734
+ export { EASING, activeElementSignal, addActiveElementEffect, addAttributeEffect, allowWheelThrough, appendStyles, canInterceptKeys, captureScrollState, contrastColor, createBackgroundColorTransition, createBackgroundTransition, createBorderRadiusTransition, createBorderTransition, createDragGestureController, createDragToMoveGestureController, createGroupTransitionController, createHeightTransition, createIterableWeakSet, createOpacityTransition, createPubSub, createStyleController, createTimelineTransition, createTransition, createTranslateXTransition, createValueEffect, createWidthTransition, cubicBezier, dragAfterThreshold, elementIsFocusable, elementIsVisibleForFocus, elementIsVisuallyVisible, findAfter, findAncestor, findBefore, findDescendant, findFocusable, getAvailableHeight, getAvailableWidth, getBackground, getBackgroundColor, getBorder, getBorderRadius, getBorderSizes, getContrastRatio, getDefaultStyles, getDragCoordinates, getDropTargetInfo, getElementSignature, getFirstVisuallyVisibleAncestor, getFocusVisibilityInfo, getHeight, getHeightWithoutTransition, getInnerHeight, getInnerWidth, getLuminance, getMarginSizes, getMaxHeight, getMaxWidth, getMinHeight, getMinWidth, getOpacity, getOpacityWithoutTransition, getPaddingSizes, getPositionedParent, getPreferedColorScheme, getScrollBox, getScrollContainer, getScrollContainerSet, getScrollRelativeRect, getSelfAndAncestorScrolls, getStyle, getTranslateX, getTranslateXWithoutTransition, getTranslateY, getVisuallyVisibleInfo, getWidth, getWidthWithoutTransition, hasCSSSizeUnit, initFlexDetailsSet, initFocusGroup, initPositionSticky, isSameColor, isScrollable, measureScrollbar, mergeOneStyle, mergeTwoStyles, normalizeStyles, parseStyle, pickPositionRelativeTo, prefersDarkColors, prefersLightColors, preventFocusNav, preventFocusNavViaKeyboard, preventIntermediateScrollbar, resolveCSSColor, resolveCSSSize, resolveColorLuminance, setAttribute, setAttributes, setStyles, startDragToResizeGesture, stickyAsRelativeCoords, stringifyStyle, 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.9.0",
3
+ "version": "0.9.1",
4
4
  "description": "DOM utilities for writing frontend code",
5
5
  "repository": {
6
6
  "type": "git",