@jsenv/navi 0.23.9 → 0.24.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_navi.js +251 -117
- package/dist/jsenv_navi.js.map +12 -11
- package/package.json +9 -9
package/dist/jsenv_navi.js
CHANGED
|
@@ -1,5 +1,5 @@
|
|
|
1
1
|
import { installImportMetaCssBuild } from "./jsenv_navi_side_effects.js";
|
|
2
|
-
import { isValidElement, h, createContext, toChildArray, render, createRef, cloneElement } from "preact";
|
|
2
|
+
import { isValidElement, h, createContext, options, toChildArray, render, createRef, cloneElement } from "preact";
|
|
3
3
|
import { useErrorBoundary, useLayoutEffect, useEffect, useMemo, useRef, useState, useCallback, useContext, useImperativeHandle, useId } from "preact/hooks";
|
|
4
4
|
import { jsxs, jsx, Fragment } from "preact/jsx-runtime";
|
|
5
5
|
import { signal, effect, computed, batch, useSignal } from "@preact/signals";
|
|
@@ -7515,6 +7515,111 @@ const updateStyle = (element, style, preventInitialTransition) => {
|
|
|
7515
7515
|
styleKeySetWeakMap.set(element, styleKeySet);
|
|
7516
7516
|
};
|
|
7517
7517
|
|
|
7518
|
+
// Implementation notes:
|
|
7519
|
+
//
|
|
7520
|
+
// options.__r fires before each component render — we capture the current
|
|
7521
|
+
// component instance (vnode.__c) so useEarlyDOMEffect can register itself.
|
|
7522
|
+
//
|
|
7523
|
+
// options.__c (commitRoot) fires after refs are assigned and before any
|
|
7524
|
+
// useLayoutEffect runs. We flush all pending effects there.
|
|
7525
|
+
// The DOM node is read from component.__v.__e (vnode → root DOM node),
|
|
7526
|
+
// which Preact sets during diffing, before options.__c fires.
|
|
7527
|
+
//
|
|
7528
|
+
// stateMap (WeakMap) stores { cleanup, deps } per component instance.
|
|
7529
|
+
// It's auto-GC'd when a component is destroyed; options.unmount also
|
|
7530
|
+
// deletes entries eagerly to release cleanup functions sooner.
|
|
7531
|
+
//
|
|
7532
|
+
// pendingMap (Map) holds effects registered during the current render pass.
|
|
7533
|
+
// It is always fully cleared in options.__c — bounded to one commit, no leak.
|
|
7534
|
+
|
|
7535
|
+
/**
|
|
7536
|
+
* Like useLayoutEffect, but runs before any layout effect in the commit —
|
|
7537
|
+
* including those of descendant components.
|
|
7538
|
+
*
|
|
7539
|
+
* Use this when a parent needs to mutate the DOM (e.g. apply styles) so that
|
|
7540
|
+
* children can read those mutations in their own useLayoutEffect.
|
|
7541
|
+
*
|
|
7542
|
+
* The DOM node of the component is passed as the first argument to fn.
|
|
7543
|
+
* The effect is skipped if no DOM node is found (e.g. on a fragment root).
|
|
7544
|
+
*
|
|
7545
|
+
* Supports deps and cleanup return, same as useLayoutEffect.
|
|
7546
|
+
*/
|
|
7547
|
+
const useEarlyDOMEffect = (fn, deps) => {
|
|
7548
|
+
const component = _currentComponent;
|
|
7549
|
+
if (component) {
|
|
7550
|
+
pendingMap.set(component, { fn, deps });
|
|
7551
|
+
}
|
|
7552
|
+
};
|
|
7553
|
+
|
|
7554
|
+
// Populated during render, consumed + cleared in options.__c each commit.
|
|
7555
|
+
const pendingMap = new Map(); // component → { fn, deps, ref }
|
|
7556
|
+
|
|
7557
|
+
// Persists across commits. WeakMap → no leak when component is destroyed.
|
|
7558
|
+
const stateMap = new WeakMap(); // component → { cleanup, deps }
|
|
7559
|
+
|
|
7560
|
+
let _currentComponent = null;
|
|
7561
|
+
const _prevBeforeRender = options.__r;
|
|
7562
|
+
options.__r = (vnode) => {
|
|
7563
|
+
_currentComponent = vnode.__c;
|
|
7564
|
+
if (_prevBeforeRender) {
|
|
7565
|
+
_prevBeforeRender(vnode);
|
|
7566
|
+
}
|
|
7567
|
+
};
|
|
7568
|
+
|
|
7569
|
+
const _prevCommit = options.__c;
|
|
7570
|
+
options.__c = (root, commitQueue) => {
|
|
7571
|
+
for (const [component, { fn, deps }] of pendingMap) {
|
|
7572
|
+
// component.__v is the component's vnode; __e is its root DOM node.
|
|
7573
|
+
// Both are set during diff, before options.__c fires.
|
|
7574
|
+
const element = component.__v && component.__v.__e;
|
|
7575
|
+
if (!element) {
|
|
7576
|
+
continue;
|
|
7577
|
+
}
|
|
7578
|
+
const prev = stateMap.get(component);
|
|
7579
|
+
const prevDeps = prev ? prev.deps : undefined;
|
|
7580
|
+
let depsChanged;
|
|
7581
|
+
if (!prevDeps || !deps || prevDeps.length !== deps.length) {
|
|
7582
|
+
depsChanged = true;
|
|
7583
|
+
} else {
|
|
7584
|
+
for (let i = 0; i < deps.length; i++) {
|
|
7585
|
+
if (!Object.is(deps[i], prevDeps[i])) {
|
|
7586
|
+
depsChanged = true;
|
|
7587
|
+
break;
|
|
7588
|
+
}
|
|
7589
|
+
}
|
|
7590
|
+
}
|
|
7591
|
+
if (depsChanged) {
|
|
7592
|
+
if (prev && prev.cleanup) {
|
|
7593
|
+
prev.cleanup();
|
|
7594
|
+
}
|
|
7595
|
+
const result = fn(element);
|
|
7596
|
+
const cleanup = typeof result === "function" ? result : undefined;
|
|
7597
|
+
stateMap.set(component, { cleanup, deps });
|
|
7598
|
+
}
|
|
7599
|
+
}
|
|
7600
|
+
pendingMap.clear();
|
|
7601
|
+
if (_prevCommit) {
|
|
7602
|
+
_prevCommit(root, commitQueue);
|
|
7603
|
+
}
|
|
7604
|
+
};
|
|
7605
|
+
|
|
7606
|
+
const _prevUnmount = options.unmount;
|
|
7607
|
+
options.unmount = (vnode) => {
|
|
7608
|
+
const component = vnode.__c;
|
|
7609
|
+
if (component) {
|
|
7610
|
+
const state = stateMap.get(component);
|
|
7611
|
+
if (state && state.cleanup) {
|
|
7612
|
+
state.cleanup();
|
|
7613
|
+
}
|
|
7614
|
+
// stateMap is a WeakMap so the entry is GC'd automatically,
|
|
7615
|
+
// but deleting explicitly releases the cleanup fn sooner.
|
|
7616
|
+
stateMap.delete(component);
|
|
7617
|
+
}
|
|
7618
|
+
if (_prevUnmount) {
|
|
7619
|
+
_prevUnmount(vnode);
|
|
7620
|
+
}
|
|
7621
|
+
};
|
|
7622
|
+
|
|
7518
7623
|
installImportMetaCssBuild(import.meta);/**
|
|
7519
7624
|
* Box - A Swiss Army Knife for Layout
|
|
7520
7625
|
*
|
|
@@ -7539,6 +7644,33 @@ installImportMetaCssBuild(import.meta);/**
|
|
|
7539
7644
|
* ## Spacing & Sizing
|
|
7540
7645
|
*
|
|
7541
7646
|
* Props for margin, padding, gap, width, height, expand, shrink, and more.
|
|
7647
|
+
*
|
|
7648
|
+
* ## Pseudo-class Styles
|
|
7649
|
+
*
|
|
7650
|
+
* The `style` prop supports pseudo-class keys alongside regular CSS properties.
|
|
7651
|
+
* This lets you express hover, focus, and custom interaction states in one object,
|
|
7652
|
+
* without writing CSS or adding class names:
|
|
7653
|
+
*
|
|
7654
|
+
* ```jsx
|
|
7655
|
+
* <Box
|
|
7656
|
+
* style={{
|
|
7657
|
+
* backgroundColor: "blue",
|
|
7658
|
+
* ":-navi:pressed": {
|
|
7659
|
+
* backgroundColor: "darkblue",
|
|
7660
|
+
* },
|
|
7661
|
+
* ":hover": {
|
|
7662
|
+
* backgroundColor: "lightblue",
|
|
7663
|
+
* },
|
|
7664
|
+
* }}
|
|
7665
|
+
* />
|
|
7666
|
+
* ```
|
|
7667
|
+
*
|
|
7668
|
+
* Styles are applied directly to the DOM (not via Preact's style prop) for two reasons:
|
|
7669
|
+
* 1. **Pseudo-class support**: reacting to `:hover`, `:focus`, or custom states like
|
|
7670
|
+
* `:-navi:pressed` without re-rendering the component on every pseudo state change.
|
|
7671
|
+
* 2. **Correct initial render**: pseudo-class state must be read from the DOM node at
|
|
7672
|
+
* mount time. Preact's style prop runs before the DOM exists, so the right initial
|
|
7673
|
+
* style can only be determined once the node is available.
|
|
7542
7674
|
*/
|
|
7543
7675
|
import.meta.css = [/* css */`
|
|
7544
7676
|
[navi-box-flow="inline"] {
|
|
@@ -7930,42 +8062,36 @@ const Box = props => {
|
|
|
7930
8062
|
visitProp(styleValue, styleName, styleContext, boxStyles, "style");
|
|
7931
8063
|
}
|
|
7932
8064
|
}
|
|
7933
|
-
|
|
7934
|
-
const boxEl = ref.current;
|
|
7935
|
-
applyStyle(boxEl, boxStyles, state, boxPseudoNamedStyles, preventInitialTransition);
|
|
7936
|
-
}, styleDeps);
|
|
7937
|
-
const finalStyleDeps = [pseudoStateSelector, innerPseudoState, updateStyle];
|
|
8065
|
+
styleDeps.push(pseudoStateSelector, innerPseudoState);
|
|
7938
8066
|
let innerPseudoClasses;
|
|
7939
8067
|
if (pseudoClassesFromStyleSet.size) {
|
|
7940
8068
|
innerPseudoClasses = [...pseudoClasses];
|
|
7941
8069
|
if (pseudoClasses !== PSEUDO_CLASSES_DEFAULT) {
|
|
7942
|
-
|
|
8070
|
+
styleDeps.push(...pseudoClasses);
|
|
7943
8071
|
}
|
|
7944
8072
|
for (const key of pseudoClassesFromStyleSet) {
|
|
7945
8073
|
innerPseudoClasses.push(key);
|
|
7946
|
-
|
|
8074
|
+
styleDeps.push(key);
|
|
7947
8075
|
}
|
|
7948
8076
|
} else {
|
|
7949
8077
|
innerPseudoClasses = pseudoClasses;
|
|
7950
8078
|
if (pseudoClasses !== PSEUDO_CLASSES_DEFAULT) {
|
|
7951
|
-
|
|
8079
|
+
styleDeps.push(...pseudoClasses);
|
|
7952
8080
|
}
|
|
7953
8081
|
}
|
|
7954
|
-
|
|
7955
|
-
const boxEl = ref.current;
|
|
7956
|
-
if (!boxEl) {
|
|
7957
|
-
return null;
|
|
7958
|
-
}
|
|
8082
|
+
useEarlyDOMEffect(boxEl => {
|
|
7959
8083
|
const pseudoStateEl = pseudoStateSelector ? boxEl.querySelector(pseudoStateSelector) : boxEl;
|
|
7960
8084
|
const visualEl = visualSelector ? boxEl.querySelector(visualSelector) : null;
|
|
7961
8085
|
return initPseudoStyles(pseudoStateEl, {
|
|
7962
8086
|
pseudoClasses: innerPseudoClasses,
|
|
7963
8087
|
pseudoState: innerPseudoState,
|
|
7964
|
-
effect:
|
|
8088
|
+
effect: state => {
|
|
8089
|
+
applyStyle(boxEl, boxStyles, state, boxPseudoNamedStyles, preventInitialTransition);
|
|
8090
|
+
},
|
|
7965
8091
|
elementToImpact: boxEl,
|
|
7966
8092
|
elementListeningPseudoState: visualEl === pseudoStateEl ? null : visualEl
|
|
7967
8093
|
});
|
|
7968
|
-
},
|
|
8094
|
+
}, styleDeps);
|
|
7969
8095
|
}
|
|
7970
8096
|
|
|
7971
8097
|
// When hasChildFunction is used it means
|
|
@@ -13884,7 +14010,7 @@ const RouteActive = ({
|
|
|
13884
14010
|
const routeAction = (
|
|
13885
14011
|
route,
|
|
13886
14012
|
action,
|
|
13887
|
-
paramsEffect = () =>
|
|
14013
|
+
paramsEffect = () => true,
|
|
13888
14014
|
options = {},
|
|
13889
14015
|
) => {
|
|
13890
14016
|
const actionBoundToRoute = actionRunEffect(
|
|
@@ -20955,6 +21081,109 @@ const Icon = ({
|
|
|
20955
21081
|
});
|
|
20956
21082
|
};
|
|
20957
21083
|
|
|
21084
|
+
/**
|
|
21085
|
+
* Toggles a `data-dark-background` attribute on the referenced element based on its
|
|
21086
|
+
* computed background color. Pair it with a CSS variable to get automatic
|
|
21087
|
+
* light/dark text without hard-coding colors:
|
|
21088
|
+
*
|
|
21089
|
+
* ```css
|
|
21090
|
+
* .my-element {
|
|
21091
|
+
* --color-contrasting: black;
|
|
21092
|
+
* &[data-dark-background] {
|
|
21093
|
+
* --color-contrasting: white;
|
|
21094
|
+
* }
|
|
21095
|
+
* color: var(--color-contrasting);
|
|
21096
|
+
* }
|
|
21097
|
+
* ```
|
|
21098
|
+
*
|
|
21099
|
+
* - `data-dark-background` is **set** when the background is dark enough that white text
|
|
21100
|
+
* provides better (or equal) contrast.
|
|
21101
|
+
* - `data-dark-background` is **absent** when black text is the better choice.
|
|
21102
|
+
*
|
|
21103
|
+
* @param {import("preact").RefObject} ref - Ref to the element that receives
|
|
21104
|
+
* the `data-dark-background` attribute and is also passed to `contrastColor` for
|
|
21105
|
+
* resolving CSS variables.
|
|
21106
|
+
* @param {object} [options]
|
|
21107
|
+
* @param {string} [options.backgroundElementSelector] - CSS selector relative
|
|
21108
|
+
* to `ref.current` pointing to a child element whose `background-color`
|
|
21109
|
+
* should be tested instead of the element itself. Useful when the element
|
|
21110
|
+
* has a transparent background but contains a coloured child (e.g. a fill
|
|
21111
|
+
* bar inside a track).
|
|
21112
|
+
*/
|
|
21113
|
+
|
|
21114
|
+
const useDarkBackgroundAttribute = (
|
|
21115
|
+
ref,
|
|
21116
|
+
deps = [],
|
|
21117
|
+
{
|
|
21118
|
+
backgroundElementSelector,
|
|
21119
|
+
attributeName = "data-dark-background",
|
|
21120
|
+
hardcoded = {},
|
|
21121
|
+
} = {},
|
|
21122
|
+
) => {
|
|
21123
|
+
const innerDeps = [
|
|
21124
|
+
...deps,
|
|
21125
|
+
// ref can change is the component pass a different ref on different render based on some logic
|
|
21126
|
+
// (can be used to control which element backgroundColor is being checked by switching the ref to another element)
|
|
21127
|
+
ref,
|
|
21128
|
+
// backgroundElementSelector can change if the component pass a different selector on different render based on some logic
|
|
21129
|
+
// (can be used to control which element backgroundColor is being checked by switching the selector to point to another element)
|
|
21130
|
+
backgroundElementSelector,
|
|
21131
|
+
];
|
|
21132
|
+
|
|
21133
|
+
const hardcodedMap = new Map();
|
|
21134
|
+
for (const key of Object.keys(hardcoded)) {
|
|
21135
|
+
const value = hardcoded[key];
|
|
21136
|
+
innerDeps.push(key, value);
|
|
21137
|
+
const colorString = normalizeColorString(key);
|
|
21138
|
+
hardcodedMap.set(colorString, value);
|
|
21139
|
+
}
|
|
21140
|
+
|
|
21141
|
+
useLayoutEffect(() => {
|
|
21142
|
+
const el = ref.current;
|
|
21143
|
+
if (!el) {
|
|
21144
|
+
return undefined;
|
|
21145
|
+
}
|
|
21146
|
+
let elementToCheck = el;
|
|
21147
|
+
if (backgroundElementSelector) {
|
|
21148
|
+
elementToCheck = el.querySelector(backgroundElementSelector);
|
|
21149
|
+
if (!elementToCheck) {
|
|
21150
|
+
return undefined;
|
|
21151
|
+
}
|
|
21152
|
+
}
|
|
21153
|
+
const updateAttribute = () => {
|
|
21154
|
+
const computedStyle = getComputedStyle(elementToCheck);
|
|
21155
|
+
const backgroundColor = computedStyle.backgroundColor;
|
|
21156
|
+
if (!backgroundColor) {
|
|
21157
|
+
el.removeAttribute(attributeName);
|
|
21158
|
+
return;
|
|
21159
|
+
}
|
|
21160
|
+
const backgroundColorString = normalizeColorString(backgroundColor, el);
|
|
21161
|
+
const hardcodedContrast = hardcodedMap.get(backgroundColorString);
|
|
21162
|
+
const contrastingColor =
|
|
21163
|
+
hardcodedContrast || contrastColor(backgroundColor, el);
|
|
21164
|
+
if (contrastingColor === "white") {
|
|
21165
|
+
el.setAttribute(attributeName, "");
|
|
21166
|
+
} else {
|
|
21167
|
+
el.removeAttribute(attributeName);
|
|
21168
|
+
}
|
|
21169
|
+
};
|
|
21170
|
+
updateAttribute();
|
|
21171
|
+
el.addEventListener(NAVI_PSEUDO_STATE_CUSTOM_EVENT, updateAttribute);
|
|
21172
|
+
return () => {
|
|
21173
|
+
el.removeEventListener(NAVI_PSEUDO_STATE_CUSTOM_EVENT, updateAttribute);
|
|
21174
|
+
el.removeAttribute(attributeName);
|
|
21175
|
+
};
|
|
21176
|
+
}, innerDeps);
|
|
21177
|
+
};
|
|
21178
|
+
|
|
21179
|
+
const normalizeColorString = (color, el) => {
|
|
21180
|
+
const colorRgba = resolveCSSColor(color, el);
|
|
21181
|
+
if (!colorRgba) {
|
|
21182
|
+
return "";
|
|
21183
|
+
}
|
|
21184
|
+
return String(colorRgba);
|
|
21185
|
+
};
|
|
21186
|
+
|
|
20958
21187
|
const useFormEvents = (
|
|
20959
21188
|
elementRef,
|
|
20960
21189
|
{
|
|
@@ -21559,8 +21788,6 @@ const css$r = /* css */`
|
|
|
21559
21788
|
--x-button-background-color: var(--button-background-color);
|
|
21560
21789
|
--x-button-color: var(--button-color);
|
|
21561
21790
|
--x-button-cursor: var(--button-cursor);
|
|
21562
|
-
|
|
21563
|
-
position: relative;
|
|
21564
21791
|
box-sizing: border-box;
|
|
21565
21792
|
aspect-ratio: inherit;
|
|
21566
21793
|
padding: 0;
|
|
@@ -21573,6 +21800,10 @@ const css$r = /* css */`
|
|
|
21573
21800
|
touch-action: manipulation;
|
|
21574
21801
|
user-select: none;
|
|
21575
21802
|
|
|
21803
|
+
&[data-dark-background] {
|
|
21804
|
+
--button-color: white;
|
|
21805
|
+
}
|
|
21806
|
+
|
|
21576
21807
|
&[data-icon] {
|
|
21577
21808
|
--button-padding: 0;
|
|
21578
21809
|
}
|
|
@@ -21855,6 +22086,7 @@ const ButtonBasic = props => {
|
|
|
21855
22086
|
innerTarget = target === undefined ? isSameSite ? undefined : "_blank" : target;
|
|
21856
22087
|
innerRel = rel === undefined ? isSameSite ? undefined : "noopener noreferrer" : rel;
|
|
21857
22088
|
}
|
|
22089
|
+
useDarkBackgroundAttribute(ref, [innerLoading, innerDisabled, innerReadOnly]);
|
|
21858
22090
|
const renderButtonContent = buttonProps => {
|
|
21859
22091
|
return jsxs(Text, {
|
|
21860
22092
|
...buttonProps,
|
|
@@ -22217,104 +22449,6 @@ const Title = props => {
|
|
|
22217
22449
|
});
|
|
22218
22450
|
};
|
|
22219
22451
|
|
|
22220
|
-
/**
|
|
22221
|
-
* Toggles a `data-dark-background` attribute on the referenced element based on its
|
|
22222
|
-
* computed background color. Pair it with a CSS variable to get automatic
|
|
22223
|
-
* light/dark text without hard-coding colors:
|
|
22224
|
-
*
|
|
22225
|
-
* ```css
|
|
22226
|
-
* .my-element {
|
|
22227
|
-
* --color-contrasting: black;
|
|
22228
|
-
* &[data-dark-background] {
|
|
22229
|
-
* --color-contrasting: white;
|
|
22230
|
-
* }
|
|
22231
|
-
* color: var(--color-contrasting);
|
|
22232
|
-
* }
|
|
22233
|
-
* ```
|
|
22234
|
-
*
|
|
22235
|
-
* - `data-dark-background` is **set** when the background is dark enough that white text
|
|
22236
|
-
* provides better (or equal) contrast.
|
|
22237
|
-
* - `data-dark-background` is **absent** when black text is the better choice.
|
|
22238
|
-
*
|
|
22239
|
-
* @param {import("preact").RefObject} ref - Ref to the element that receives
|
|
22240
|
-
* the `data-dark-background` attribute and is also passed to `contrastColor` for
|
|
22241
|
-
* resolving CSS variables.
|
|
22242
|
-
* @param {object} [options]
|
|
22243
|
-
* @param {string} [options.backgroundElementSelector] - CSS selector relative
|
|
22244
|
-
* to `ref.current` pointing to a child element whose `background-color`
|
|
22245
|
-
* should be tested instead of the element itself. Useful when the element
|
|
22246
|
-
* has a transparent background but contains a coloured child (e.g. a fill
|
|
22247
|
-
* bar inside a track).
|
|
22248
|
-
*/
|
|
22249
|
-
|
|
22250
|
-
const useDarkBackgroundAttribute = (
|
|
22251
|
-
ref,
|
|
22252
|
-
deps = [],
|
|
22253
|
-
{
|
|
22254
|
-
backgroundElementSelector,
|
|
22255
|
-
attributeName = "data-dark-background",
|
|
22256
|
-
hardcoded = {},
|
|
22257
|
-
} = {},
|
|
22258
|
-
) => {
|
|
22259
|
-
const innerDeps = [
|
|
22260
|
-
...deps,
|
|
22261
|
-
// ref can change is the component pass a different ref on different render based on some logic
|
|
22262
|
-
// (can be used to control which element backgroundColor is being checked by switching the ref to another element)
|
|
22263
|
-
ref,
|
|
22264
|
-
// backgroundElementSelector can change if the component pass a different selector on different render based on some logic
|
|
22265
|
-
// (can be used to control which element backgroundColor is being checked by switching the selector to point to another element)
|
|
22266
|
-
backgroundElementSelector,
|
|
22267
|
-
];
|
|
22268
|
-
|
|
22269
|
-
const hardcodedMap = new Map();
|
|
22270
|
-
for (const key of Object.keys(hardcoded)) {
|
|
22271
|
-
const value = hardcoded[key];
|
|
22272
|
-
innerDeps.push(key, value);
|
|
22273
|
-
const colorString = normalizeColorString(key);
|
|
22274
|
-
hardcodedMap.set(colorString, value);
|
|
22275
|
-
}
|
|
22276
|
-
|
|
22277
|
-
useLayoutEffect(() => {
|
|
22278
|
-
const el = ref.current;
|
|
22279
|
-
if (!el) {
|
|
22280
|
-
return null;
|
|
22281
|
-
}
|
|
22282
|
-
let elementToCheck = el;
|
|
22283
|
-
if (backgroundElementSelector) {
|
|
22284
|
-
elementToCheck = el.querySelector(backgroundElementSelector);
|
|
22285
|
-
if (!elementToCheck) {
|
|
22286
|
-
return null;
|
|
22287
|
-
}
|
|
22288
|
-
}
|
|
22289
|
-
const computedStyle = getComputedStyle(elementToCheck);
|
|
22290
|
-
const backgroundColor = computedStyle.backgroundColor;
|
|
22291
|
-
if (!backgroundColor) {
|
|
22292
|
-
el.removeAttribute(attributeName);
|
|
22293
|
-
return null;
|
|
22294
|
-
}
|
|
22295
|
-
const backgroundColorString = normalizeColorString(backgroundColor, el);
|
|
22296
|
-
const hardcodedContrast = hardcodedMap.get(backgroundColorString);
|
|
22297
|
-
const contrastingColor =
|
|
22298
|
-
hardcodedContrast || contrastColor(backgroundColor, el);
|
|
22299
|
-
if (contrastingColor === "white") {
|
|
22300
|
-
el.setAttribute(attributeName, "");
|
|
22301
|
-
return () => {
|
|
22302
|
-
el.removeAttribute(attributeName);
|
|
22303
|
-
};
|
|
22304
|
-
}
|
|
22305
|
-
el.removeAttribute(attributeName);
|
|
22306
|
-
return null;
|
|
22307
|
-
}, innerDeps);
|
|
22308
|
-
};
|
|
22309
|
-
|
|
22310
|
-
const normalizeColorString = (color, el) => {
|
|
22311
|
-
const colorRgba = resolveCSSColor(color, el);
|
|
22312
|
-
if (!colorRgba) {
|
|
22313
|
-
return "";
|
|
22314
|
-
}
|
|
22315
|
-
return String(colorRgba);
|
|
22316
|
-
};
|
|
22317
|
-
|
|
22318
22452
|
/**
|
|
22319
22453
|
* Hook that reactively checks if a URL is visited.
|
|
22320
22454
|
* Re-renders when the visited URL set changes.
|