@jsenv/navi 0.23.8 → 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 +285 -127
- package/dist/jsenv_navi.js.map +16 -17
- 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";
|
|
@@ -7026,11 +7026,29 @@ const PSEUDO_CLASSES = {
|
|
|
7026
7026
|
el.removeEventListener("lostpointercapture", onRelease);
|
|
7027
7027
|
el.removeEventListener("pointercancel", onRelease);
|
|
7028
7028
|
el.removeEventListener("pointerup", onRelease);
|
|
7029
|
+
el.removeEventListener("contextmenu", onContextMenu);
|
|
7029
7030
|
callback();
|
|
7030
7031
|
};
|
|
7032
|
+
const onContextMenu = (e) => {
|
|
7033
|
+
// On touch devices, a long-press triggers the context menu.
|
|
7034
|
+
// If the context menu is not prevented, it means it will open and the
|
|
7035
|
+
// pointer events (pointerup, lostpointercapture) won't fire normally,
|
|
7036
|
+
// leaving the element stuck in pressed state. We clear it manually.
|
|
7037
|
+
// e.button === -1 means the event was synthesized from a long-press (not a real mouse click).
|
|
7038
|
+
if (e.button === -1 && !e.defaultPrevented) {
|
|
7039
|
+
pressedElements.delete(el);
|
|
7040
|
+
el.releasePointerCapture(e.pointerId);
|
|
7041
|
+
el.removeEventListener("lostpointercapture", onRelease);
|
|
7042
|
+
el.removeEventListener("pointercancel", onRelease);
|
|
7043
|
+
el.removeEventListener("pointerup", onRelease);
|
|
7044
|
+
el.removeEventListener("contextmenu", onContextMenu);
|
|
7045
|
+
callback();
|
|
7046
|
+
}
|
|
7047
|
+
};
|
|
7031
7048
|
el.addEventListener("lostpointercapture", onRelease);
|
|
7032
7049
|
el.addEventListener("pointercancel", onRelease);
|
|
7033
7050
|
el.addEventListener("pointerup", onRelease);
|
|
7051
|
+
el.addEventListener("contextmenu", onContextMenu);
|
|
7034
7052
|
callback();
|
|
7035
7053
|
};
|
|
7036
7054
|
el.addEventListener("pointerdown", onPointerDown);
|
|
@@ -7497,6 +7515,111 @@ const updateStyle = (element, style, preventInitialTransition) => {
|
|
|
7497
7515
|
styleKeySetWeakMap.set(element, styleKeySet);
|
|
7498
7516
|
};
|
|
7499
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
|
+
|
|
7500
7623
|
installImportMetaCssBuild(import.meta);/**
|
|
7501
7624
|
* Box - A Swiss Army Knife for Layout
|
|
7502
7625
|
*
|
|
@@ -7521,6 +7644,33 @@ installImportMetaCssBuild(import.meta);/**
|
|
|
7521
7644
|
* ## Spacing & Sizing
|
|
7522
7645
|
*
|
|
7523
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.
|
|
7524
7674
|
*/
|
|
7525
7675
|
import.meta.css = [/* css */`
|
|
7526
7676
|
[navi-box-flow="inline"] {
|
|
@@ -7912,42 +8062,36 @@ const Box = props => {
|
|
|
7912
8062
|
visitProp(styleValue, styleName, styleContext, boxStyles, "style");
|
|
7913
8063
|
}
|
|
7914
8064
|
}
|
|
7915
|
-
|
|
7916
|
-
const boxEl = ref.current;
|
|
7917
|
-
applyStyle(boxEl, boxStyles, state, boxPseudoNamedStyles, preventInitialTransition);
|
|
7918
|
-
}, styleDeps);
|
|
7919
|
-
const finalStyleDeps = [pseudoStateSelector, innerPseudoState, updateStyle];
|
|
8065
|
+
styleDeps.push(pseudoStateSelector, innerPseudoState);
|
|
7920
8066
|
let innerPseudoClasses;
|
|
7921
8067
|
if (pseudoClassesFromStyleSet.size) {
|
|
7922
8068
|
innerPseudoClasses = [...pseudoClasses];
|
|
7923
8069
|
if (pseudoClasses !== PSEUDO_CLASSES_DEFAULT) {
|
|
7924
|
-
|
|
8070
|
+
styleDeps.push(...pseudoClasses);
|
|
7925
8071
|
}
|
|
7926
8072
|
for (const key of pseudoClassesFromStyleSet) {
|
|
7927
8073
|
innerPseudoClasses.push(key);
|
|
7928
|
-
|
|
8074
|
+
styleDeps.push(key);
|
|
7929
8075
|
}
|
|
7930
8076
|
} else {
|
|
7931
8077
|
innerPseudoClasses = pseudoClasses;
|
|
7932
8078
|
if (pseudoClasses !== PSEUDO_CLASSES_DEFAULT) {
|
|
7933
|
-
|
|
8079
|
+
styleDeps.push(...pseudoClasses);
|
|
7934
8080
|
}
|
|
7935
8081
|
}
|
|
7936
|
-
|
|
7937
|
-
const boxEl = ref.current;
|
|
7938
|
-
if (!boxEl) {
|
|
7939
|
-
return null;
|
|
7940
|
-
}
|
|
8082
|
+
useEarlyDOMEffect(boxEl => {
|
|
7941
8083
|
const pseudoStateEl = pseudoStateSelector ? boxEl.querySelector(pseudoStateSelector) : boxEl;
|
|
7942
8084
|
const visualEl = visualSelector ? boxEl.querySelector(visualSelector) : null;
|
|
7943
8085
|
return initPseudoStyles(pseudoStateEl, {
|
|
7944
8086
|
pseudoClasses: innerPseudoClasses,
|
|
7945
8087
|
pseudoState: innerPseudoState,
|
|
7946
|
-
effect:
|
|
8088
|
+
effect: state => {
|
|
8089
|
+
applyStyle(boxEl, boxStyles, state, boxPseudoNamedStyles, preventInitialTransition);
|
|
8090
|
+
},
|
|
7947
8091
|
elementToImpact: boxEl,
|
|
7948
8092
|
elementListeningPseudoState: visualEl === pseudoStateEl ? null : visualEl
|
|
7949
8093
|
});
|
|
7950
|
-
},
|
|
8094
|
+
}, styleDeps);
|
|
7951
8095
|
}
|
|
7952
8096
|
|
|
7953
8097
|
// When hasChildFunction is used it means
|
|
@@ -13866,7 +14010,7 @@ const RouteActive = ({
|
|
|
13866
14010
|
const routeAction = (
|
|
13867
14011
|
route,
|
|
13868
14012
|
action,
|
|
13869
|
-
paramsEffect = () =>
|
|
14013
|
+
paramsEffect = () => true,
|
|
13870
14014
|
options = {},
|
|
13871
14015
|
) => {
|
|
13872
14016
|
const actionBoundToRoute = actionRunEffect(
|
|
@@ -20937,6 +21081,109 @@ const Icon = ({
|
|
|
20937
21081
|
});
|
|
20938
21082
|
};
|
|
20939
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
|
+
|
|
20940
21187
|
const useFormEvents = (
|
|
20941
21188
|
elementRef,
|
|
20942
21189
|
{
|
|
@@ -21521,10 +21768,10 @@ const css$r = /* css */`
|
|
|
21521
21768
|
}
|
|
21522
21769
|
|
|
21523
21770
|
a.navi_button {
|
|
21524
|
-
color: inherit;
|
|
21525
|
-
text-decoration: none;
|
|
21526
21771
|
display: inline-block;
|
|
21772
|
+
color: inherit;
|
|
21527
21773
|
text-align: center;
|
|
21774
|
+
text-decoration: none;
|
|
21528
21775
|
}
|
|
21529
21776
|
|
|
21530
21777
|
.navi_button {
|
|
@@ -21541,8 +21788,6 @@ const css$r = /* css */`
|
|
|
21541
21788
|
--x-button-background-color: var(--button-background-color);
|
|
21542
21789
|
--x-button-color: var(--button-color);
|
|
21543
21790
|
--x-button-cursor: var(--button-cursor);
|
|
21544
|
-
|
|
21545
|
-
position: relative;
|
|
21546
21791
|
box-sizing: border-box;
|
|
21547
21792
|
aspect-ratio: inherit;
|
|
21548
21793
|
padding: 0;
|
|
@@ -21555,6 +21800,10 @@ const css$r = /* css */`
|
|
|
21555
21800
|
touch-action: manipulation;
|
|
21556
21801
|
user-select: none;
|
|
21557
21802
|
|
|
21803
|
+
&[data-dark-background] {
|
|
21804
|
+
--button-color: white;
|
|
21805
|
+
}
|
|
21806
|
+
|
|
21558
21807
|
&[data-icon] {
|
|
21559
21808
|
--button-padding: 0;
|
|
21560
21809
|
}
|
|
@@ -21837,6 +22086,7 @@ const ButtonBasic = props => {
|
|
|
21837
22086
|
innerTarget = target === undefined ? isSameSite ? undefined : "_blank" : target;
|
|
21838
22087
|
innerRel = rel === undefined ? isSameSite ? undefined : "noopener noreferrer" : rel;
|
|
21839
22088
|
}
|
|
22089
|
+
useDarkBackgroundAttribute(ref, [innerLoading, innerDisabled, innerReadOnly]);
|
|
21840
22090
|
const renderButtonContent = buttonProps => {
|
|
21841
22091
|
return jsxs(Text, {
|
|
21842
22092
|
...buttonProps,
|
|
@@ -21855,14 +22105,20 @@ const ButtonBasic = props => {
|
|
|
21855
22105
|
rel: innerRel,
|
|
21856
22106
|
ref: ref,
|
|
21857
22107
|
onContextMenu: e => {
|
|
21858
|
-
if (
|
|
21859
|
-
//
|
|
21860
|
-
|
|
21861
|
-
|
|
21862
|
-
|
|
21863
|
-
//
|
|
21864
|
-
|
|
22108
|
+
if (as === "a") {
|
|
22109
|
+
// For link we keep context menu to allow "open in new tab" and other browser features
|
|
22110
|
+
return;
|
|
22111
|
+
}
|
|
22112
|
+
if (e.pointerType !== "touch") {
|
|
22113
|
+
// right click is allowed
|
|
22114
|
+
return;
|
|
21865
22115
|
}
|
|
22116
|
+
// Suppress the native context menu triggered by long-press on touch devices.
|
|
22117
|
+
// Buttons have no meaningful context menu (no text to copy/paste/search),
|
|
22118
|
+
// and the long-press visual state would get stuck if we let the menu open.
|
|
22119
|
+
// Note: e.button === -1 is equivalent — it means no physical button triggered
|
|
22120
|
+
// the event, i.e. it was synthesized from a long-press gesture (right-click gives e.button === 2).
|
|
22121
|
+
e.preventDefault();
|
|
21866
22122
|
},
|
|
21867
22123
|
"data-icon": icon ? "" : undefined,
|
|
21868
22124
|
"data-reveal-on-interaction": revealOnInteraction ? "" : undefined,
|
|
@@ -22193,104 +22449,6 @@ const Title = props => {
|
|
|
22193
22449
|
});
|
|
22194
22450
|
};
|
|
22195
22451
|
|
|
22196
|
-
/**
|
|
22197
|
-
* Toggles a `data-dark-background` attribute on the referenced element based on its
|
|
22198
|
-
* computed background color. Pair it with a CSS variable to get automatic
|
|
22199
|
-
* light/dark text without hard-coding colors:
|
|
22200
|
-
*
|
|
22201
|
-
* ```css
|
|
22202
|
-
* .my-element {
|
|
22203
|
-
* --color-contrasting: black;
|
|
22204
|
-
* &[data-dark-background] {
|
|
22205
|
-
* --color-contrasting: white;
|
|
22206
|
-
* }
|
|
22207
|
-
* color: var(--color-contrasting);
|
|
22208
|
-
* }
|
|
22209
|
-
* ```
|
|
22210
|
-
*
|
|
22211
|
-
* - `data-dark-background` is **set** when the background is dark enough that white text
|
|
22212
|
-
* provides better (or equal) contrast.
|
|
22213
|
-
* - `data-dark-background` is **absent** when black text is the better choice.
|
|
22214
|
-
*
|
|
22215
|
-
* @param {import("preact").RefObject} ref - Ref to the element that receives
|
|
22216
|
-
* the `data-dark-background` attribute and is also passed to `contrastColor` for
|
|
22217
|
-
* resolving CSS variables.
|
|
22218
|
-
* @param {object} [options]
|
|
22219
|
-
* @param {string} [options.backgroundElementSelector] - CSS selector relative
|
|
22220
|
-
* to `ref.current` pointing to a child element whose `background-color`
|
|
22221
|
-
* should be tested instead of the element itself. Useful when the element
|
|
22222
|
-
* has a transparent background but contains a coloured child (e.g. a fill
|
|
22223
|
-
* bar inside a track).
|
|
22224
|
-
*/
|
|
22225
|
-
|
|
22226
|
-
const useDarkBackgroundAttribute = (
|
|
22227
|
-
ref,
|
|
22228
|
-
deps = [],
|
|
22229
|
-
{
|
|
22230
|
-
backgroundElementSelector,
|
|
22231
|
-
attributeName = "data-dark-background",
|
|
22232
|
-
hardcoded = {},
|
|
22233
|
-
} = {},
|
|
22234
|
-
) => {
|
|
22235
|
-
const innerDeps = [
|
|
22236
|
-
...deps,
|
|
22237
|
-
// ref can change is the component pass a different ref on different render based on some logic
|
|
22238
|
-
// (can be used to control which element backgroundColor is being checked by switching the ref to another element)
|
|
22239
|
-
ref,
|
|
22240
|
-
// backgroundElementSelector can change if the component pass a different selector on different render based on some logic
|
|
22241
|
-
// (can be used to control which element backgroundColor is being checked by switching the selector to point to another element)
|
|
22242
|
-
backgroundElementSelector,
|
|
22243
|
-
];
|
|
22244
|
-
|
|
22245
|
-
const hardcodedMap = new Map();
|
|
22246
|
-
for (const key of Object.keys(hardcoded)) {
|
|
22247
|
-
const value = hardcoded[key];
|
|
22248
|
-
innerDeps.push(key, value);
|
|
22249
|
-
const colorString = normalizeColorString(key);
|
|
22250
|
-
hardcodedMap.set(colorString, value);
|
|
22251
|
-
}
|
|
22252
|
-
|
|
22253
|
-
useLayoutEffect(() => {
|
|
22254
|
-
const el = ref.current;
|
|
22255
|
-
if (!el) {
|
|
22256
|
-
return null;
|
|
22257
|
-
}
|
|
22258
|
-
let elementToCheck = el;
|
|
22259
|
-
if (backgroundElementSelector) {
|
|
22260
|
-
elementToCheck = el.querySelector(backgroundElementSelector);
|
|
22261
|
-
if (!elementToCheck) {
|
|
22262
|
-
return null;
|
|
22263
|
-
}
|
|
22264
|
-
}
|
|
22265
|
-
const computedStyle = getComputedStyle(elementToCheck);
|
|
22266
|
-
const backgroundColor = computedStyle.backgroundColor;
|
|
22267
|
-
if (!backgroundColor) {
|
|
22268
|
-
el.removeAttribute(attributeName);
|
|
22269
|
-
return null;
|
|
22270
|
-
}
|
|
22271
|
-
const backgroundColorString = normalizeColorString(backgroundColor, el);
|
|
22272
|
-
const hardcodedContrast = hardcodedMap.get(backgroundColorString);
|
|
22273
|
-
const contrastingColor =
|
|
22274
|
-
hardcodedContrast || contrastColor(backgroundColor, el);
|
|
22275
|
-
if (contrastingColor === "white") {
|
|
22276
|
-
el.setAttribute(attributeName, "");
|
|
22277
|
-
return () => {
|
|
22278
|
-
el.removeAttribute(attributeName);
|
|
22279
|
-
};
|
|
22280
|
-
}
|
|
22281
|
-
el.removeAttribute(attributeName);
|
|
22282
|
-
return null;
|
|
22283
|
-
}, innerDeps);
|
|
22284
|
-
};
|
|
22285
|
-
|
|
22286
|
-
const normalizeColorString = (color, el) => {
|
|
22287
|
-
const colorRgba = resolveCSSColor(color, el);
|
|
22288
|
-
if (!colorRgba) {
|
|
22289
|
-
return "";
|
|
22290
|
-
}
|
|
22291
|
-
return String(colorRgba);
|
|
22292
|
-
};
|
|
22293
|
-
|
|
22294
22452
|
/**
|
|
22295
22453
|
* Hook that reactively checks if a URL is visited.
|
|
22296
22454
|
* Re-renders when the visited URL set changes.
|
|
@@ -32661,5 +32819,5 @@ const UserSvg = () => jsx("svg", {
|
|
|
32661
32819
|
})
|
|
32662
32820
|
});
|
|
32663
32821
|
|
|
32664
|
-
export { ActionRenderer, ActiveKeyboardShortcuts, Address, Badge, BadgeCount, Box, Button, ButtonCopyToClipboard, Caption, CheckSvg, Checkbox, CheckboxList, CloseSvg, Code, Col, Colgroup, ConstructionSvg, Details, DialogLayout, Editable, ErrorBoundary, ErrorBoundaryContext, ExclamationSvg, EyeClosedSvg, EyeSvg, Form, Group, Head, HeartSvg, HomeSvg, Icon, Image, Input, Label, Link, LinkAnchorSvg, LinkBlankTargetSvg, LinkCurrentSvg, Loading, MessageBox, Meter, Nav, Paragraph, Quantity, QuantityIntl, Radio, RadioList, Route, RowNumberCol, RowNumberTableCell,
|
|
32822
|
+
export { ActionRenderer, ActiveKeyboardShortcuts, Address, Badge, BadgeCount, Box, Button, ButtonCopyToClipboard, Caption, CheckSvg, Checkbox, CheckboxList, CloseSvg, Code, Col, Colgroup, ConstructionSvg, Details, DialogLayout, Editable, ErrorBoundary, ErrorBoundaryContext, ExclamationSvg, EyeClosedSvg, EyeSvg, Form, Group, Head, HeartSvg, HomeSvg, Icon, Image, Input, Label, Link, LinkAnchorSvg, LinkBlankTargetSvg, LinkCurrentSvg, Loading, MessageBox, Meter, Nav, Paragraph, Quantity, QuantityIntl, Radio, RadioList, Route, RowNumberCol, RowNumberTableCell, SVGMaskOverlay, SearchSvg, Select, SelectionContext, Separator, SettingsSvg, SidePanel, StarSvg, SummaryMarker, Svg, Table, TableCell, Tbody, Text, Thead, Title, Tr, UITransition, UserSvg, ViewportLayout, actionIntegratedVia, actionRunEffect, addCustomMessage, arraySignalMembership, compareTwoJsValues, createAction, createAvailableConstraint, createIntl, createRequestCanceller, createSelectionKeyboardShortcuts, enableDebugActions, enableDebugOnDocumentLoading, filterTableSelection, forwardActionRequested, installCustomConstraintValidation, isCellSelected, isColumnSelected, isRowSelected, localStorageSignal, navBack, navForward, navTo, openCallout, rawUrlPart, reload, removeCustomMessage, requestAction, rerunActions, resource, route, routeAction, setBaseUrl, setupRoutes, stateSignal, stopLoad, stringifyTableSelectionValue, syncOwnedResourceToSignals, syncResourceToSignals, updateActions, useActionStatus, useArraySignalMembership, useAsyncData, useCalloutClose, useCancelPrevious, useCellGridFromRows, useConstraintValidityState, useDarkBackgroundAttribute, useDependenciesDiff, useDocumentResource, useDocumentState, useDocumentUrl, useEditionController, useFocusGroup, useKeyboardShortcuts, useNavState$1 as useNavState, useOrderedColumns, useRouteStatus, useRunOnMount, useSelectableElement, useSelectionController, useSidePanelClose, useSignalSync, useStateArray, useTitleLevel, useUrlSearchParam, valueInLocalStorage };
|
|
32665
32823
|
//# sourceMappingURL=jsenv_navi.js.map
|