@jsenv/navi 0.29.18 → 0.29.19
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 +95 -27
- package/dist/jsenv_navi.js.map +7 -6
- package/package.json +1 -1
package/dist/jsenv_navi.js
CHANGED
|
@@ -7990,12 +7990,40 @@ const requestPseudoStateCheck = (element, detail) => {
|
|
|
7990
7990
|
);
|
|
7991
7991
|
}
|
|
7992
7992
|
};
|
|
7993
|
-
|
|
7994
|
-
|
|
7995
|
-
|
|
7996
|
-
|
|
7997
|
-
|
|
7998
|
-
|
|
7993
|
+
/**
|
|
7994
|
+
* Called back whenever `element`'s pseudo state changes.
|
|
7995
|
+
*
|
|
7996
|
+
* Kept beside the element rather than announced to the DOM: an element that
|
|
7997
|
+
* changes state has at most one or two interested parties, each known by name
|
|
7998
|
+
* (the box drawing it, the accent color reading its computed style), and a
|
|
7999
|
+
* CustomEvent costs its allocation and its capture/bubble walk whether anyone
|
|
8000
|
+
* listens or not — paid on every element, on every state change. A lookup that
|
|
8001
|
+
* finds nothing costs nothing.
|
|
8002
|
+
*
|
|
8003
|
+
* @param {Element} element
|
|
8004
|
+
* @param {(pseudoState: object, oldPseudoState: object) => void} callback
|
|
8005
|
+
* @returns {() => void} teardown
|
|
8006
|
+
*/
|
|
8007
|
+
const subscribeToPseudoState = (element, callback) => {
|
|
8008
|
+
let subscriberSet = pseudoStateSubscriberSetWeakMap.get(element);
|
|
8009
|
+
if (!subscriberSet) {
|
|
8010
|
+
subscriberSet = new Set();
|
|
8011
|
+
pseudoStateSubscriberSetWeakMap.set(element, subscriberSet);
|
|
8012
|
+
}
|
|
8013
|
+
subscriberSet.add(callback);
|
|
8014
|
+
return () => {
|
|
8015
|
+
subscriberSet.delete(callback);
|
|
8016
|
+
};
|
|
8017
|
+
};
|
|
8018
|
+
const pseudoStateSubscriberSetWeakMap = new WeakMap();
|
|
8019
|
+
const notifyPseudoStateSubscribers = (element, value, oldValue) => {
|
|
8020
|
+
const subscriberSet = pseudoStateSubscriberSetWeakMap.get(element);
|
|
8021
|
+
if (!subscriberSet) {
|
|
8022
|
+
return;
|
|
8023
|
+
}
|
|
8024
|
+
for (const subscriber of subscriberSet) {
|
|
8025
|
+
subscriber(value, oldValue);
|
|
8026
|
+
}
|
|
7999
8027
|
};
|
|
8000
8028
|
|
|
8001
8029
|
const PSEUDO_CLASSES = {};
|
|
@@ -8809,7 +8837,7 @@ const initPseudoStyles = (
|
|
|
8809
8837
|
const onStateChange = (value, oldValue) => {
|
|
8810
8838
|
effect?.(value, oldValue);
|
|
8811
8839
|
if (elementListeningPseudoState) {
|
|
8812
|
-
|
|
8840
|
+
notifyPseudoStateSubscribers(
|
|
8813
8841
|
elementListeningPseudoState,
|
|
8814
8842
|
value,
|
|
8815
8843
|
oldValue,
|
|
@@ -8892,11 +8920,12 @@ const initPseudoStyles = (
|
|
|
8892
8920
|
onStateChange(state, oldState);
|
|
8893
8921
|
};
|
|
8894
8922
|
|
|
8895
|
-
|
|
8896
|
-
|
|
8897
|
-
|
|
8898
|
-
|
|
8899
|
-
|
|
8923
|
+
addTeardown(
|
|
8924
|
+
subscribeToPseudoState(element, (pseudoState, oldPseudoState) => {
|
|
8925
|
+
state = pseudoState;
|
|
8926
|
+
onStateChange(state, oldPseudoState);
|
|
8927
|
+
}),
|
|
8928
|
+
);
|
|
8900
8929
|
element.addEventListener("navi_pseudo_state_request_check", () => {
|
|
8901
8930
|
checkPseudoClasses();
|
|
8902
8931
|
});
|
|
@@ -9014,18 +9043,7 @@ const updateStyle = (element, style, preventInitialTransition) => {
|
|
|
9014
9043
|
styleKeySetToApply = new Set(styleKeySet);
|
|
9015
9044
|
styleKeySetToApply.delete("transition");
|
|
9016
9045
|
}
|
|
9017
|
-
|
|
9018
|
-
if (elementTransitionWeakMap.has(element)) {
|
|
9019
|
-
const transitionToRestore = elementTransitionWeakMap.get(element);
|
|
9020
|
-
if (transitionToRestore === undefined) {
|
|
9021
|
-
element.style.transition = "";
|
|
9022
|
-
} else {
|
|
9023
|
-
element.style.transition = transitionToRestore;
|
|
9024
|
-
}
|
|
9025
|
-
elementTransitionWeakMap.delete(element);
|
|
9026
|
-
}
|
|
9027
|
-
elementRenderedWeakSet.add(element);
|
|
9028
|
-
});
|
|
9046
|
+
afterFirstFrame(element);
|
|
9029
9047
|
}
|
|
9030
9048
|
|
|
9031
9049
|
// Apply all styles normally (excluding transition during anti-flicker)
|
|
@@ -9056,6 +9074,39 @@ const updateStyle = (element, style, preventInitialTransition) => {
|
|
|
9056
9074
|
styleKeySetWeakMap.set(element, styleKeySet);
|
|
9057
9075
|
};
|
|
9058
9076
|
|
|
9077
|
+
// One frame for every element waiting for its first one, not one frame each.
|
|
9078
|
+
// What this owes each element — put back the transition suppressed above, and
|
|
9079
|
+
// remember it has now been painted once — is a few microseconds, while asking
|
|
9080
|
+
// the browser for a frame costs more than that, and a page mounting thousands of
|
|
9081
|
+
// boxes asks thousands of times in the same tick. A Set, so an element styled
|
|
9082
|
+
// twice before the frame arrives is still one entry.
|
|
9083
|
+
const elementSetWaitingFirstFrame = new Set();
|
|
9084
|
+
let firstFrameScheduled = false;
|
|
9085
|
+
const afterFirstFrame = (element) => {
|
|
9086
|
+
elementSetWaitingFirstFrame.add(element);
|
|
9087
|
+
if (firstFrameScheduled) {
|
|
9088
|
+
return;
|
|
9089
|
+
}
|
|
9090
|
+
firstFrameScheduled = true;
|
|
9091
|
+
requestAnimationFrame(() => {
|
|
9092
|
+
firstFrameScheduled = false;
|
|
9093
|
+
const elements = [...elementSetWaitingFirstFrame];
|
|
9094
|
+
elementSetWaitingFirstFrame.clear();
|
|
9095
|
+
for (const element of elements) {
|
|
9096
|
+
if (elementTransitionWeakMap.has(element)) {
|
|
9097
|
+
const transitionToRestore = elementTransitionWeakMap.get(element);
|
|
9098
|
+
if (transitionToRestore === undefined) {
|
|
9099
|
+
element.style.transition = "";
|
|
9100
|
+
} else {
|
|
9101
|
+
element.style.transition = transitionToRestore;
|
|
9102
|
+
}
|
|
9103
|
+
elementTransitionWeakMap.delete(element);
|
|
9104
|
+
}
|
|
9105
|
+
elementRenderedWeakSet.add(element);
|
|
9106
|
+
}
|
|
9107
|
+
});
|
|
9108
|
+
};
|
|
9109
|
+
|
|
9059
9110
|
/**
|
|
9060
9111
|
* Keeps a DOM element in sync with `syncElement(el)` whenever syncElement changes.
|
|
9061
9112
|
* - If element is already mounted: runs syncElement immediately during render.
|
|
@@ -11465,9 +11516,12 @@ const useAccentColorAttributes = (
|
|
|
11465
11516
|
}
|
|
11466
11517
|
};
|
|
11467
11518
|
updateAttributes();
|
|
11468
|
-
|
|
11519
|
+
const unsubscribeFromPseudoState = subscribeToPseudoState(
|
|
11520
|
+
el,
|
|
11521
|
+
updateAttributes,
|
|
11522
|
+
);
|
|
11469
11523
|
return () => {
|
|
11470
|
-
|
|
11524
|
+
unsubscribeFromPseudoState();
|
|
11471
11525
|
el.removeAttribute(LIGHT_ACCENT_ATTRIBUTE);
|
|
11472
11526
|
el.removeAttribute(VERY_LIGHT_ACCENT_ATTRIBUTE);
|
|
11473
11527
|
el.removeAttribute(DARK_CONTRAST_ATTRIBUTE);
|
|
@@ -22470,6 +22524,20 @@ const useControlProps = (props, {
|
|
|
22470
22524
|
uiStateController
|
|
22471
22525
|
}];
|
|
22472
22526
|
};
|
|
22527
|
+
/**
|
|
22528
|
+
* Whether the caller has told this control what it holds. Three ways, and only
|
|
22529
|
+
* three — the controlled `value`, the uncontrolled `defaultValue`, a bound
|
|
22530
|
+
* `signal` — the same three createControlInfo below reads, in that precedence
|
|
22531
|
+
* order, to seed the state.
|
|
22532
|
+
*
|
|
22533
|
+
* None of them and the control starts with nothing: whatever it ends up holding
|
|
22534
|
+
* has to come from somewhere else — a parent form distributing its own value,
|
|
22535
|
+
* or, for a picker, the control sitting in its popup (see
|
|
22536
|
+
* useUIFacadeStateController). Anyone who needs to know whether a control can
|
|
22537
|
+
* answer for itself before anything mounts asks this rather than re-listing the
|
|
22538
|
+
* props, which is how `signal` came to be forgotten.
|
|
22539
|
+
*/
|
|
22540
|
+
const isControlValueGivenByProps = props => Object.hasOwn(props, "value") || Object.hasOwn(props, "defaultValue") || Object.hasOwn(props, "signal");
|
|
22473
22541
|
const createControlInfo = (props, {
|
|
22474
22542
|
controlType
|
|
22475
22543
|
}) => {
|
|
@@ -46296,7 +46364,7 @@ const PickerCustom = props => {
|
|
|
46296
46364
|
// opens anything. Told a value — even an empty one — the picker owns it
|
|
46297
46365
|
// and pushes it down instead, leaving the popup free to build its
|
|
46298
46366
|
// content only when it is first opened (see popup_content_mount.js).
|
|
46299
|
-
mountWhenClosed: !
|
|
46367
|
+
mountWhenClosed: !isControlValueGivenByProps(props),
|
|
46300
46368
|
// Not on pickerProps (the trigger): commands.js's own
|
|
46301
46369
|
// resolveClosestExpandable() does `el.closest("[aria-expanded]")` to
|
|
46302
46370
|
// find where to dispatch navi_request_open/navi_request_close — and
|