@jsenv/navi 0.29.487 → 0.29.489
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/dev/jsenv_navi.js +661 -185
- package/dist/dev/jsenv_navi.js.map +37 -33
- package/dist/jsenv_navi.js +661 -185
- package/dist/jsenv_navi.js.map +37 -33
- package/docs/navigation.md +5 -0
- package/docs/popup_open.md +7 -3
- package/docs/resource.md +1 -1
- package/package.json +2 -2
package/dist/dev/jsenv_navi.js
CHANGED
|
@@ -993,6 +993,10 @@ const buttonI18n = /*#__PURE__*/ defineNaviMessages({
|
|
|
993
993
|
en: "Copied!",
|
|
994
994
|
fr: "Copié !",
|
|
995
995
|
},
|
|
996
|
+
"button.copy_refused": {
|
|
997
|
+
en: "Could not copy.",
|
|
998
|
+
fr: "Impossible de copier.",
|
|
999
|
+
},
|
|
996
1000
|
});
|
|
997
1001
|
|
|
998
1002
|
// Spin messages — the ends of what one steps through when the control holding
|
|
@@ -2755,18 +2759,18 @@ const debounceSignal = (
|
|
|
2755
2759
|
signalToDebounce,
|
|
2756
2760
|
{ delay = 300, deepCompare = true } = {},
|
|
2757
2761
|
) => {
|
|
2762
|
+
const isSameValue = (a, b) =>
|
|
2763
|
+
deepCompare ? compareTwoJsValues(a, b) : a === b;
|
|
2758
2764
|
let timeoutId;
|
|
2759
2765
|
let latestValue = signalToDebounce.peek();
|
|
2760
|
-
|
|
2761
|
-
|
|
2762
|
-
|
|
2766
|
+
// Following the source subscribes to it, and through it to whatever it reads:
|
|
2767
|
+
// an app-level signal it reads would keep it — and its timer — alive for
|
|
2768
|
+
// good. So it is followed only while something reads the debounced value.
|
|
2769
|
+
let stopFollowing = null;
|
|
2770
|
+
const follow = () => {
|
|
2763
2771
|
const value = signalToDebounce.value;
|
|
2764
2772
|
const debouncedValue = debouncedSignal.peek();
|
|
2765
|
-
if (
|
|
2766
|
-
deepCompare
|
|
2767
|
-
? compareTwoJsValues(value, debouncedValue)
|
|
2768
|
-
: value === debouncedValue
|
|
2769
|
-
) {
|
|
2773
|
+
if (isSameValue(value, debouncedValue)) {
|
|
2770
2774
|
// The signal came back to where the debounced one already is: whatever it
|
|
2771
2775
|
// passed through on the way is not on its way any more. Leaving the timer
|
|
2772
2776
|
// armed would publish that in-between value once the delay elapses, and
|
|
@@ -2781,11 +2785,37 @@ const debounceSignal = (
|
|
|
2781
2785
|
timeoutId = setTimeout(() => {
|
|
2782
2786
|
debouncedSignal.value = latestValue;
|
|
2783
2787
|
}, delay);
|
|
2788
|
+
};
|
|
2789
|
+
const catchUp = () => {
|
|
2790
|
+
const value = signalToDebounce.peek();
|
|
2791
|
+
if (!isSameValue(value, debouncedSignal.peek())) {
|
|
2792
|
+
debouncedSignal.value = value;
|
|
2793
|
+
}
|
|
2794
|
+
latestValue = debouncedSignal.peek();
|
|
2795
|
+
};
|
|
2796
|
+
const debouncedSignal = signal(latestValue, {
|
|
2797
|
+
watched: () => {
|
|
2798
|
+
// Nobody was waiting on what the source said while nothing read it:
|
|
2799
|
+
// that is taken at once, not after a delay.
|
|
2800
|
+
catchUp();
|
|
2801
|
+
stopFollowing = effect(follow);
|
|
2802
|
+
},
|
|
2803
|
+
unwatched: () => {
|
|
2804
|
+
stopFollowing();
|
|
2805
|
+
stopFollowing = null;
|
|
2806
|
+
clearTimeout(timeoutId);
|
|
2807
|
+
timeoutId = undefined;
|
|
2808
|
+
},
|
|
2784
2809
|
});
|
|
2785
2810
|
|
|
2786
2811
|
debouncedSignal.flush = () => {
|
|
2787
2812
|
clearTimeout(timeoutId);
|
|
2788
|
-
|
|
2813
|
+
timeoutId = undefined;
|
|
2814
|
+
if (stopFollowing) {
|
|
2815
|
+
debouncedSignal.value = latestValue;
|
|
2816
|
+
return;
|
|
2817
|
+
}
|
|
2818
|
+
catchUp();
|
|
2789
2819
|
};
|
|
2790
2820
|
// Whoever reads the debounced value gets the previous one during the delay,
|
|
2791
2821
|
// with nothing saying a newer one is on its way. This says it.
|
|
@@ -4936,10 +4966,46 @@ const createActionProxyFromSignal = (
|
|
|
4936
4966
|
});
|
|
4937
4967
|
actionWeakMap.set(actionProxy, actionProxy);
|
|
4938
4968
|
|
|
4969
|
+
// Following the params subscribes to them, and through them to whatever
|
|
4970
|
+
// they read: a component's computed params reading an app-level signal stay
|
|
4971
|
+
// reachable from that signal for as long as anything listens to them. So a
|
|
4972
|
+
// binding follows its params only while something reads what it says (a
|
|
4973
|
+
// mounted component, a run's subscriber), and catches up when read again;
|
|
4974
|
+
// unread, every method retargets first (see proxyMethod). A binding asked to
|
|
4975
|
+
// act on their changes (runOnce, rerunOnChange, onChange: a route action,
|
|
4976
|
+
// actionRunEffect) follows them for as long as it exists.
|
|
4977
|
+
const followsParamsAlways = runOnce || rerunOnChange || Boolean(onChange);
|
|
4978
|
+
let readerCount = 0;
|
|
4979
|
+
let stopFollowingParams = null;
|
|
4980
|
+
const readerWatchOptions = followsParamsAlways
|
|
4981
|
+
? undefined
|
|
4982
|
+
: {
|
|
4983
|
+
watched: () => {
|
|
4984
|
+
readerCount++;
|
|
4985
|
+
if (readerCount === 1) {
|
|
4986
|
+
const stopMirroringParams = effect(() => {
|
|
4987
|
+
proxyParamsSignal.value = paramsSignal.value;
|
|
4988
|
+
});
|
|
4989
|
+
const stopRetargeting = effect(retargetOnParamsChange);
|
|
4990
|
+
stopFollowingParams = () => {
|
|
4991
|
+
stopMirroringParams();
|
|
4992
|
+
stopRetargeting();
|
|
4993
|
+
};
|
|
4994
|
+
}
|
|
4995
|
+
},
|
|
4996
|
+
unwatched: () => {
|
|
4997
|
+
readerCount--;
|
|
4998
|
+
if (readerCount === 0) {
|
|
4999
|
+
stopFollowingParams();
|
|
5000
|
+
stopFollowingParams = null;
|
|
5001
|
+
}
|
|
5002
|
+
},
|
|
5003
|
+
};
|
|
5004
|
+
|
|
4939
5005
|
// Create our own signal for params that we control completely
|
|
4940
5006
|
const proxyParamsSignal = signal(paramsSignal.value);
|
|
4941
5007
|
const proxySignal = (signalPropertyName, propertyName) => {
|
|
4942
|
-
const signalProxy = signal();
|
|
5008
|
+
const signalProxy = signal(undefined, readerWatchOptions);
|
|
4943
5009
|
let dispose;
|
|
4944
5010
|
onActionTargetChange(() => {
|
|
4945
5011
|
if (dispose) {
|
|
@@ -5066,20 +5132,34 @@ const createActionProxyFromSignal = (
|
|
|
5066
5132
|
}
|
|
5067
5133
|
// Watch for changes in the original paramsSignal and update ours
|
|
5068
5134
|
// (original signal wins over any replaceParams calls)
|
|
5069
|
-
|
|
5070
|
-
[paramsSignal, proxyParamsSignal],
|
|
5071
|
-
(paramsSignalRef, proxyParamsSignalRef) => {
|
|
5072
|
-
const newParams = paramsSignalRef.value;
|
|
5073
|
-
proxyParamsSignalRef.value = newParams;
|
|
5074
|
-
},
|
|
5075
|
-
);
|
|
5076
|
-
weakEffect([action], () => {
|
|
5135
|
+
const retargetOnParamsChange = () => {
|
|
5077
5136
|
// eslint-disable-next-line no-unused-expressions
|
|
5078
5137
|
proxyParamsSignal.value;
|
|
5079
5138
|
_updateTarget({
|
|
5080
5139
|
changeCause: "params_signal_change",
|
|
5081
5140
|
});
|
|
5082
|
-
}
|
|
5141
|
+
};
|
|
5142
|
+
if (followsParamsAlways) {
|
|
5143
|
+
weakEffect(
|
|
5144
|
+
[paramsSignal, proxyParamsSignal],
|
|
5145
|
+
(paramsSignalRef, proxyParamsSignalRef) => {
|
|
5146
|
+
const newParams = paramsSignalRef.value;
|
|
5147
|
+
proxyParamsSignalRef.value = newParams;
|
|
5148
|
+
},
|
|
5149
|
+
);
|
|
5150
|
+
weakEffect([action], retargetOnParamsChange);
|
|
5151
|
+
} else {
|
|
5152
|
+
// The first target is resolved now, as following would resolve it: the
|
|
5153
|
+
// subscribers wired above read what it says from the start (see
|
|
5154
|
+
// onActionTargetChange above). Untracked, as inside the effect that
|
|
5155
|
+
// resolves it otherwise: a binding is made during a render, which must
|
|
5156
|
+
// not subscribe to what retargeting reads.
|
|
5157
|
+
untracked(() => {
|
|
5158
|
+
_updateTarget({
|
|
5159
|
+
changeCause: "params_signal_change",
|
|
5160
|
+
});
|
|
5161
|
+
});
|
|
5162
|
+
}
|
|
5083
5163
|
actionProxy.replaceParams = (newParams) => {
|
|
5084
5164
|
if (currentAction === action) {
|
|
5085
5165
|
const currentParams = proxyParamsSignal.value;
|
|
@@ -6068,6 +6148,10 @@ const isPickerBoundaryFor = (candidate, el) => {
|
|
|
6068
6148
|
*/
|
|
6069
6149
|
const getParentControl = (el) => {
|
|
6070
6150
|
const ownControlRoot = el.closest("[navi-control]");
|
|
6151
|
+
if (!ownControlRoot) {
|
|
6152
|
+
// In no control at all (a list's root, a plain element): none around it.
|
|
6153
|
+
return null;
|
|
6154
|
+
}
|
|
6071
6155
|
const parentControlRoot = ownControlRoot.parentNode.closest("[navi-control]");
|
|
6072
6156
|
return parentControlRoot;
|
|
6073
6157
|
};
|
|
@@ -6543,10 +6627,14 @@ const resolveInputProps = (props, { controlType = "input" } = {}) => {
|
|
|
6543
6627
|
// signal wants a date field — but a boolean one maps to a checkbox, and
|
|
6544
6628
|
// a picker made into a checkbox is not a picker with a different look:
|
|
6545
6629
|
// it is another control, with no popup to open. A picker asked to hold
|
|
6546
|
-
// a yes/no keeps its two rows and stays itself.
|
|
6630
|
+
// a yes/no keeps its two rows and stays itself. Nor does a picker with
|
|
6631
|
+
// a popup of its own become the field for that type: it is what its
|
|
6632
|
+
// popup is — a frise one slides in is no number one types.
|
|
6547
6633
|
const wouldChangeWhatTheControlIs =
|
|
6548
6634
|
controlType === "picker" &&
|
|
6549
|
-
(
|
|
6635
|
+
(props.children !== undefined ||
|
|
6636
|
+
typeFromSignal === "checkbox" ||
|
|
6637
|
+
typeFromSignal === "radio");
|
|
6550
6638
|
if (typeFromSignal !== undefined && !wouldChangeWhatTheControlIs) {
|
|
6551
6639
|
props.type = typeFromSignal;
|
|
6552
6640
|
}
|
|
@@ -7818,7 +7906,8 @@ const STATE_SIGNAL_OPTIONS = new Set([
|
|
|
7818
7906
|
* deploys holds one copy, not ten. Only the storage key changes, the id the url reads stays `id`.
|
|
7819
7907
|
* @param {string} [options.type] - Type the value is coerced to, and read back as from localStorage and the url:
|
|
7820
7908
|
* any @jsenv/validity type (`"string"`, `"number"`, `"boolean"`, `"array"`, `"object"`, `"integer"`, `"date"`,
|
|
7821
|
-
* `"time"`…). Without it the value is not coerced.
|
|
7909
|
+
* `"time"`…). Without it the value is not coerced. On a type that is not text (`"string"`, `"email"`,
|
|
7910
|
+
* `"url"`), `""` — what a cleared control writes — is absence.
|
|
7822
7911
|
* @param {"string" | "number" | "boolean"} [options.itemType] - For array type: type of the array items.
|
|
7823
7912
|
* Used when reading the value back from a url search param, where everything is a string:
|
|
7824
7913
|
* `?level=3,4` becomes `[3, 4]` instead of `["3", "4"]`. Without it items stay strings.
|
|
@@ -7913,6 +8002,8 @@ const STATE_SIGNAL_OPTIONS = new Set([
|
|
|
7913
8002
|
* const childTab = stateSignal(parentTab);
|
|
7914
8003
|
* // childTab follows parentTab changes unless explicitly set
|
|
7915
8004
|
*/
|
|
8005
|
+
// The types "" is a value of: an empty text is still a text.
|
|
8006
|
+
const TEXT_TYPE_SET = new Set(["string", "email", "url"]);
|
|
7916
8007
|
const stateSignal = (defaultValue, options = {}) => {
|
|
7917
8008
|
const {
|
|
7918
8009
|
id,
|
|
@@ -8104,8 +8195,13 @@ const stateSignal = (defaultValue, options = {}) => {
|
|
|
8104
8195
|
};
|
|
8105
8196
|
|
|
8106
8197
|
// Create signal with initial value: use stored value, or undefined to indicate no explicit value
|
|
8198
|
+
// Whether "" says nothing at all: on a type that is not text, it is what a
|
|
8199
|
+
// cleared control writes (an empty field, a picker's cross) — no number, no
|
|
8200
|
+
// date — and kept, it would be an invalid value the address carries.
|
|
8201
|
+
const emptyStringIsAbsence =
|
|
8202
|
+
type !== undefined && !TEXT_TYPE_SET.has(type);
|
|
8107
8203
|
const processValue = (value) => {
|
|
8108
|
-
if (value === undefined) {
|
|
8204
|
+
if (value === undefined || (value === "" && emptyStringIsAbsence)) {
|
|
8109
8205
|
// Absence is never validated, and the verdict on the previous value
|
|
8110
8206
|
// (validSignal, validity.valid) must not outlive it.
|
|
8111
8207
|
clearValidity();
|
|
@@ -15651,6 +15747,14 @@ PSEUDO_CLASSES[":active"] = {
|
|
|
15651
15747
|
// focus_classes block below. At module scope so isMatchingFocusVisible (used
|
|
15652
15748
|
// here and in control_hooks.jsx) can read it.
|
|
15653
15749
|
let keyboardNavigationUsed = false;
|
|
15750
|
+
// The element a caller focused saying the ring must show (`focusVisible: true`
|
|
15751
|
+
// to moveFocusTo or autoFocus): it knows better than the modality — a screen
|
|
15752
|
+
// showing where Enter goes before any key was pressed. Until a pointer goes
|
|
15753
|
+
// down, which says the hand is elsewhere.
|
|
15754
|
+
let focusVisibleAskedElement = null;
|
|
15755
|
+
const askFocusVisible = (element) => {
|
|
15756
|
+
focusVisibleAskedElement = element;
|
|
15757
|
+
};
|
|
15654
15758
|
|
|
15655
15759
|
// HOW FOCUS-VISIBLE IS DECIDED (the details behind isMatchingFocusVisible)
|
|
15656
15760
|
//
|
|
@@ -15680,7 +15784,10 @@ let keyboardNavigationUsed = false;
|
|
|
15680
15784
|
//
|
|
15681
15785
|
// `keyboardNavigationUsed` has no such blind spot — it is set by navigation
|
|
15682
15786
|
// keydowns and cleared by pointerdown, whatever anyone prevents afterwards
|
|
15683
|
-
// — so it is the authority for everything rule 1 does not cover.
|
|
15787
|
+
// — so it is the authority for everything rule 1 does not cover. Save for
|
|
15788
|
+
// the element a caller explicitly focused with a ring (askFocusVisible):
|
|
15789
|
+
// that is somebody knowing better than the last interaction, not a state
|
|
15790
|
+
// left behind.
|
|
15684
15791
|
//
|
|
15685
15792
|
// Ring INHERITANCE (a controlled element ringing because its aria-controls
|
|
15686
15793
|
// controller is focused) stays gated on the keyboard modality even for an
|
|
@@ -15703,7 +15810,7 @@ const isMatchingFocusVisible = (el) => {
|
|
|
15703
15810
|
return false;
|
|
15704
15811
|
}
|
|
15705
15812
|
if (!keyboardNavigationUsed) {
|
|
15706
|
-
return
|
|
15813
|
+
return el === focusVisibleAskedElement;
|
|
15707
15814
|
}
|
|
15708
15815
|
return true;
|
|
15709
15816
|
};
|
|
@@ -15824,6 +15931,7 @@ const isKeyboardModality = () => keyboardNavigationUsed;
|
|
|
15824
15931
|
"pointerdown",
|
|
15825
15932
|
() => {
|
|
15826
15933
|
keyboardNavigationUsed = false;
|
|
15934
|
+
focusVisibleAskedElement = null;
|
|
15827
15935
|
},
|
|
15828
15936
|
{ capture: true },
|
|
15829
15937
|
);
|
|
@@ -17000,7 +17108,8 @@ const retryWhenPlaceable = (
|
|
|
17000
17108
|
* @param {object} [options]
|
|
17001
17109
|
* @param {boolean} [options.focusVisible] Decides the ring instead of the
|
|
17002
17110
|
* modality — for a caller that knows better than the last interaction does
|
|
17003
|
-
* (a transfer speaking for the gesture that opened a container, say).
|
|
17111
|
+
* (a transfer speaking for the gesture that opened a container, say). `true`
|
|
17112
|
+
* draws the ring even before any key was pressed, until a pointer goes down.
|
|
17004
17113
|
* @param {boolean} [options.preventScroll=true] Pass false to let the browser
|
|
17005
17114
|
* scroll the element into view.
|
|
17006
17115
|
*/
|
|
@@ -17008,6 +17117,9 @@ const moveFocusTo = (
|
|
|
17008
17117
|
element,
|
|
17009
17118
|
{ focusVisible, preventScroll = true } = {},
|
|
17010
17119
|
) => {
|
|
17120
|
+
if (focusVisible === true) {
|
|
17121
|
+
askFocusVisible(element);
|
|
17122
|
+
}
|
|
17011
17123
|
element.focus({
|
|
17012
17124
|
preventScroll,
|
|
17013
17125
|
focusVisible:
|
|
@@ -17185,6 +17297,14 @@ document.addEventListener(
|
|
|
17185
17297
|
const openedDuringThisPress = (openController) =>
|
|
17186
17298
|
openController.pressCountAtOpen === pressCount;
|
|
17187
17299
|
|
|
17300
|
+
/**
|
|
17301
|
+
* Which press the events landing now belong to: the pointerdown, mousedown and
|
|
17302
|
+
* click of one press read the same count, a tap's compatibility events
|
|
17303
|
+
* included (see above). A click the keyboard makes brings no pointerdown, so it
|
|
17304
|
+
* reads the count of the last press: tell it apart by `event.detail === 0`.
|
|
17305
|
+
*/
|
|
17306
|
+
const readPressCount = () => pressCount;
|
|
17307
|
+
|
|
17188
17308
|
// How long a popup waits before handing the focus to a field, when giving it
|
|
17189
17309
|
// is what raises the on-screen keyboard.
|
|
17190
17310
|
//
|
|
@@ -17577,6 +17697,14 @@ const createOpenController = (
|
|
|
17577
17697
|
// whole point: learning it afterwards means the content mounted on the
|
|
17578
17698
|
// previous subject first.
|
|
17579
17699
|
onOpen: null,
|
|
17700
|
+
// What the popup is open ON, as its content reads it (usePopupValue in
|
|
17701
|
+
// popup_value.js): written at the opening, right after `onOpen`, and left
|
|
17702
|
+
// alone by the close, so the content keeps drawing it while it leaves.
|
|
17703
|
+
popupValueSignal: signal(undefined),
|
|
17704
|
+
// How the opening reads that value, set by whoever holds the open state
|
|
17705
|
+
// (see useOpenPropsEffectOnOpenController); left unset, the value the
|
|
17706
|
+
// opening carries (a --navi-open source's).
|
|
17707
|
+
readPopupValue: null,
|
|
17580
17708
|
// What an Escape means for this popup, whoever heard the key — its own
|
|
17581
17709
|
// shortcut, its trigger's, the group it stands in, a bubble's: a cancel
|
|
17582
17710
|
// (what it holds reverts), unless its owner says otherwise (a Picker's
|
|
@@ -17711,6 +17839,9 @@ const createOpenController = (
|
|
|
17711
17839
|
// openEffect, which shows it: what the popup opens ON has to be
|
|
17712
17840
|
// known before either (see `onOpen` above).
|
|
17713
17841
|
controller.onOpen?.(requestOpenEvent);
|
|
17842
|
+
controller.popupValueSignal.value = controller.readPopupValue
|
|
17843
|
+
? controller.readPopupValue(requestOpenEvent)
|
|
17844
|
+
: requestOpenEvent.detail.value;
|
|
17714
17845
|
// After prepareFocusTransfer, which has to record what held the
|
|
17715
17846
|
// focus before anything inside the popup can claim it, and before
|
|
17716
17847
|
// openEffect, which measures the popup to place it.
|
|
@@ -18090,6 +18221,39 @@ const useOpenPropsEffectOnOpenController = (
|
|
|
18090
18221
|
if (signal && open) {
|
|
18091
18222
|
openSignalValueRef.current = signal.value;
|
|
18092
18223
|
}
|
|
18224
|
+
// What the popup is open ON (see usePopupValue): the id the signal names
|
|
18225
|
+
// when it holds more than "open", else the popup's own `value`, else what the
|
|
18226
|
+
// opening carries. Read once `onOpen` has run, which may write the signal.
|
|
18227
|
+
openController.readPopupValue = (requestOpenEvent) => {
|
|
18228
|
+
if (signal) {
|
|
18229
|
+
const signalValue = signal.peek();
|
|
18230
|
+
if (signalValue !== true && readOpened(signalValue, value)) {
|
|
18231
|
+
return signalValue;
|
|
18232
|
+
}
|
|
18233
|
+
}
|
|
18234
|
+
if (value !== undefined) {
|
|
18235
|
+
return value;
|
|
18236
|
+
}
|
|
18237
|
+
return requestOpenEvent.detail.value;
|
|
18238
|
+
};
|
|
18239
|
+
// The signal walked to another id while open (a sheet's "next"): the
|
|
18240
|
+
// content follows it. Written closed, it is left alone — that is the close
|
|
18241
|
+
// starting, and the content still has its exit to draw.
|
|
18242
|
+
useLayoutEffect(() => {
|
|
18243
|
+
if (!signal) {
|
|
18244
|
+
return undefined;
|
|
18245
|
+
}
|
|
18246
|
+
return effect(() => {
|
|
18247
|
+
const signalValue = signal.value;
|
|
18248
|
+
if (
|
|
18249
|
+
openController.opened &&
|
|
18250
|
+
signalValue !== true &&
|
|
18251
|
+
readOpened(signalValue, value)
|
|
18252
|
+
) {
|
|
18253
|
+
openController.popupValueSignal.value = signalValue;
|
|
18254
|
+
}
|
|
18255
|
+
});
|
|
18256
|
+
}, [signal, value]);
|
|
18093
18257
|
// Assigned on every render, like openEffect, so it always closes over the
|
|
18094
18258
|
// latest prop: a popup that opens or closes on its own (Escape, backdrop, a
|
|
18095
18259
|
// --navi-close command) writes what happened where the caller keeps it, so
|
|
@@ -26049,6 +26213,14 @@ const arraySignalStore = (
|
|
|
26049
26213
|
if (props === null || typeof props !== "object") {
|
|
26050
26214
|
return props;
|
|
26051
26215
|
}
|
|
26216
|
+
if (props[idKey] === undefined) {
|
|
26217
|
+
// Kept under `undefined`, every such item would be one and the same: a
|
|
26218
|
+
// list drawing its last row as many times as it has rows, a creation
|
|
26219
|
+
// rewriting all of them — and nothing saying why.
|
|
26220
|
+
throw new Error(
|
|
26221
|
+
`${name || "store"}: an item arrived without "${idKey}" (it has ${Object.keys(props).join(", ")}) — declare its key with idKey, or give a single item an id of its own ({ id: "me", … })`,
|
|
26222
|
+
);
|
|
26223
|
+
}
|
|
26052
26224
|
const item = createItem(props);
|
|
26053
26225
|
return item;
|
|
26054
26226
|
};
|
|
@@ -27234,13 +27406,12 @@ const createResourceLifecycleManager = () => {
|
|
|
27234
27406
|
if (!isSameResource && !isDependent) {
|
|
27235
27407
|
continue;
|
|
27236
27408
|
}
|
|
27409
|
+
// A write of a resource this one depends on reaches its lists as it
|
|
27410
|
+
// reruns its GET and GET_MANY: being heard is the whole condition (see
|
|
27411
|
+
// findEffectOnActions). rerunOn is about this resource's own writes.
|
|
27237
27412
|
if (
|
|
27238
|
-
|
|
27239
|
-
|
|
27240
|
-
config,
|
|
27241
|
-
triggeringAction,
|
|
27242
|
-
isSameResource,
|
|
27243
|
-
)
|
|
27413
|
+
isSameResource &&
|
|
27414
|
+
!shouldReadRerunAfter("GET_RANGE", config, triggeringAction, true)
|
|
27244
27415
|
) {
|
|
27245
27416
|
continue;
|
|
27246
27417
|
}
|
|
@@ -30437,6 +30608,17 @@ const useActionAsyncData = (action, {
|
|
|
30437
30608
|
useOnLoad(action, onLoad);
|
|
30438
30609
|
usePoll(action, poll);
|
|
30439
30610
|
|
|
30611
|
+
// The instance the binding points at, remembered from one render to the
|
|
30612
|
+
// next: a binding that comes back to params whose instance failed — a search
|
|
30613
|
+
// typed again after a network blip — asks again, as typing them the first
|
|
30614
|
+
// time did. Staying on the instance that just failed asks nothing (see
|
|
30615
|
+
// runIsOwed), and neither does a mount, which never switched to anything.
|
|
30616
|
+
// Read as it stands: getCurrentAction() would flush a debounced binding,
|
|
30617
|
+
// publishing every keystroke the moment it renders.
|
|
30618
|
+
const instance = action.isProxy ? getActionPrivateProperties(action).currentAction : action;
|
|
30619
|
+
const instanceRef = useRef(instance);
|
|
30620
|
+
const backOnFailure = instanceRef.current !== instance && action.runningStateSignal.peek() === FAILED;
|
|
30621
|
+
instanceRef.current = instance;
|
|
30440
30622
|
// `run: true` — this component owns the request, so it is what starts it, and
|
|
30441
30623
|
// it starts it from the render rather than from an effect: a component that
|
|
30442
30624
|
// suspends has no effects, so a run written in one would be waiting for
|
|
@@ -30444,7 +30626,7 @@ const useActionAsyncData = (action, {
|
|
|
30444
30626
|
// no-op — which is what makes starting it while rendering sound. From there
|
|
30445
30627
|
// the wait is the ordinary one: suspended into <Loading>, or drawn by the
|
|
30446
30628
|
// component under `loading: true`, exactly as for data someone else ran.
|
|
30447
|
-
if (run && action.paramsSignal.peek() !== undefined && runIsOwed(action)) {
|
|
30629
|
+
if (run && action.paramsSignal.peek() !== undefined && (runIsOwed(action) || backOnFailure)) {
|
|
30448
30630
|
// Nothing waits on this run: the failure is held by the action, and this
|
|
30449
30631
|
// hook is what reads it back.
|
|
30450
30632
|
runUnwatched(() => action.run({
|
|
@@ -32082,6 +32264,38 @@ const resolveContainerLength = (size, element) => {
|
|
|
32082
32264
|
return (parseFloat(amount) / 100) * containerSize;
|
|
32083
32265
|
};
|
|
32084
32266
|
|
|
32267
|
+
// "s", "-m" — the spacing scale, whose tokens are ems of the font where they
|
|
32268
|
+
// apply: a length only CSS knows, handed back as the var() it maps to, which
|
|
32269
|
+
// nothing can place with. Read off the given element (the root when none is),
|
|
32270
|
+
// for a caller asking for a number.
|
|
32271
|
+
const SCALE_WORD_REGEX = /^(-?)(xxs|xs|xl|xxl|[lms])$/;
|
|
32272
|
+
const TOKEN_LENGTH_REGEX = /^(-?[\d.]+)(px|r?em)$/;
|
|
32273
|
+
const resolveScaleLength = (size, element = document.documentElement) => {
|
|
32274
|
+
if (typeof size !== "string") {
|
|
32275
|
+
return null;
|
|
32276
|
+
}
|
|
32277
|
+
const match = SCALE_WORD_REGEX.exec(size);
|
|
32278
|
+
if (!match) {
|
|
32279
|
+
return null;
|
|
32280
|
+
}
|
|
32281
|
+
const [, sign, word] = match;
|
|
32282
|
+
const computedStyle = getComputedStyle(element);
|
|
32283
|
+
const token = computedStyle.getPropertyValue(`--navi-${word}`).trim();
|
|
32284
|
+
const tokenMatch = TOKEN_LENGTH_REGEX.exec(token);
|
|
32285
|
+
if (!tokenMatch) {
|
|
32286
|
+
return null;
|
|
32287
|
+
}
|
|
32288
|
+
const [, amount, unit] = tokenMatch;
|
|
32289
|
+
let unitInPx = 1;
|
|
32290
|
+
if (unit === "em") {
|
|
32291
|
+
unitInPx = parseFloat(computedStyle.fontSize);
|
|
32292
|
+
} else if (unit === "rem") {
|
|
32293
|
+
unitInPx = parseFloat(getComputedStyle(document.documentElement).fontSize);
|
|
32294
|
+
}
|
|
32295
|
+
const length = parseFloat(amount) * unitInPx;
|
|
32296
|
+
return sign ? -length : length;
|
|
32297
|
+
};
|
|
32298
|
+
|
|
32085
32299
|
const resolveSpacingSize = (size, element, property = "padding") => {
|
|
32086
32300
|
const viewportLength = resolveViewportLength(size);
|
|
32087
32301
|
if (viewportLength !== null) {
|
|
@@ -32091,6 +32305,10 @@ const resolveSpacingSize = (size, element, property = "padding") => {
|
|
|
32091
32305
|
if (containerLength !== null) {
|
|
32092
32306
|
return containerLength;
|
|
32093
32307
|
}
|
|
32308
|
+
const scaleLength = resolveScaleLength(size, element);
|
|
32309
|
+
if (scaleLength !== null) {
|
|
32310
|
+
return scaleLength;
|
|
32311
|
+
}
|
|
32094
32312
|
return normalizeStyle(SIZE_MAP[size] || size, property, "js", element);
|
|
32095
32313
|
};
|
|
32096
32314
|
// Whether a spacing is nothing at all, answered without resolving it. A
|
|
@@ -34725,20 +34943,32 @@ const useUrlSearchParam = (paramName, defaultValue) => {
|
|
|
34725
34943
|
* the one it would have picked, painted over.
|
|
34726
34944
|
*/
|
|
34727
34945
|
|
|
34728
|
-
const headEntries = [];
|
|
34946
|
+
const headEntries$1 = [];
|
|
34729
34947
|
const popupLayers = [];
|
|
34730
34948
|
const ownMetas = [];
|
|
34731
34949
|
|
|
34732
34950
|
/**
|
|
34733
|
-
*
|
|
34734
|
-
*
|
|
34951
|
+
* A Head's place in the stack, taken as it arrives and kept while what it asks
|
|
34952
|
+
* for changes (see head.jsx).
|
|
34953
|
+
*
|
|
34954
|
+
* @returns {{
|
|
34955
|
+
* set: (themeColors: Array<{ content: string, media: string|null }>) => void,
|
|
34956
|
+
* remove: () => void,
|
|
34957
|
+
* }}
|
|
34735
34958
|
*/
|
|
34736
|
-
const pushHeadThemeColors = (
|
|
34737
|
-
|
|
34738
|
-
|
|
34739
|
-
return
|
|
34740
|
-
|
|
34741
|
-
|
|
34959
|
+
const pushHeadThemeColors = () => {
|
|
34960
|
+
const themeColors = [];
|
|
34961
|
+
headEntries$1.push(themeColors);
|
|
34962
|
+
return {
|
|
34963
|
+
set: (themeColorsNext) => {
|
|
34964
|
+
themeColors.length = 0;
|
|
34965
|
+
themeColors.push(...themeColorsNext);
|
|
34966
|
+
queueRender();
|
|
34967
|
+
},
|
|
34968
|
+
remove: () => {
|
|
34969
|
+
headEntries$1.splice(headEntries$1.indexOf(themeColors), 1);
|
|
34970
|
+
queueRender();
|
|
34971
|
+
},
|
|
34742
34972
|
};
|
|
34743
34973
|
};
|
|
34744
34974
|
|
|
@@ -34836,8 +35066,8 @@ const readBackdropColor = (element) => {
|
|
|
34836
35066
|
};
|
|
34837
35067
|
|
|
34838
35068
|
let renderQueued = false;
|
|
34839
|
-
// Once per commit: a
|
|
34840
|
-
//
|
|
35069
|
+
// Once per commit: a page leaving as another arrives, or several Heads
|
|
35070
|
+
// changing together, hand the browser one colour, never the one in between.
|
|
34841
35071
|
const queueRender = () => {
|
|
34842
35072
|
if (renderQueued) {
|
|
34843
35073
|
return;
|
|
@@ -34856,8 +35086,8 @@ const render = () => {
|
|
|
34856
35086
|
media: meta.getAttribute("media"),
|
|
34857
35087
|
}));
|
|
34858
35088
|
let colors = [];
|
|
34859
|
-
for (let i = headEntries.length - 1; i >= 0; i--) {
|
|
34860
|
-
colors.push(...headEntries[i]);
|
|
35089
|
+
for (let i = headEntries$1.length - 1; i >= 0; i--) {
|
|
35090
|
+
colors.push(...headEntries$1[i]);
|
|
34861
35091
|
}
|
|
34862
35092
|
colors.push(...htmlColors);
|
|
34863
35093
|
for (const layer of popupLayers) {
|
|
@@ -34983,67 +35213,119 @@ const drawColor = (color) => {
|
|
|
34983
35213
|
// title it found would put its own page's title over the new one. A
|
|
34984
35214
|
// theme-color meta follows the same rule, kept by theme_color.js, where the
|
|
34985
35215
|
// popups of the top layer paint over it.
|
|
34986
|
-
|
|
35216
|
+
// Arriving is mounting: a Head that renders again — a layout's head whose
|
|
35217
|
+
// count moved, children built anew at every render — is updated where it
|
|
35218
|
+
// stands, under the Heads that arrived after it. Taken off and pushed back, a
|
|
35219
|
+
// layout's head would take the title from every page below it.
|
|
35220
|
+
const headEntries = [];
|
|
34987
35221
|
let titleWithoutHead = null;
|
|
34988
35222
|
const Head = ({
|
|
34989
35223
|
children
|
|
34990
35224
|
}) => {
|
|
35225
|
+
const entryRef = useRef(null);
|
|
34991
35226
|
useLayoutEffect(() => {
|
|
34992
|
-
|
|
34993
|
-
|
|
35227
|
+
const entry = {
|
|
35228
|
+
title: null,
|
|
35229
|
+
themeColors: pushHeadThemeColors()
|
|
35230
|
+
};
|
|
35231
|
+
headEntries.push(entry);
|
|
35232
|
+
entryRef.current = entry;
|
|
35233
|
+
return () => {
|
|
35234
|
+
entry.themeColors.remove();
|
|
35235
|
+
headEntries.splice(headEntries.indexOf(entry), 1);
|
|
35236
|
+
writeDocumentTitle();
|
|
35237
|
+
};
|
|
35238
|
+
}, []);
|
|
35239
|
+
const {
|
|
35240
|
+
title,
|
|
35241
|
+
themeColors,
|
|
35242
|
+
elements
|
|
35243
|
+
} = readHeadChildren(children);
|
|
35244
|
+
// What the children say, rather than the children: the elements are built
|
|
35245
|
+
// anew at every render, and saying the same thing again changes nothing.
|
|
35246
|
+
const contentKey = JSON.stringify([title, themeColors, elements]);
|
|
35247
|
+
useLayoutEffect(() => {
|
|
35248
|
+
const entry = entryRef.current;
|
|
35249
|
+
if (title !== null && !headEntries.some(other => other.title !== null)) {
|
|
35250
|
+
titleWithoutHead = document.title;
|
|
34994
35251
|
}
|
|
34995
|
-
|
|
35252
|
+
entry.title = title;
|
|
35253
|
+
writeDocumentTitle();
|
|
35254
|
+
entry.themeColors.set(themeColors);
|
|
34996
35255
|
const appendedElements = [];
|
|
34997
|
-
const
|
|
34998
|
-
|
|
34999
|
-
|
|
35000
|
-
|
|
35001
|
-
|
|
35002
|
-
}
|
|
35003
|
-
if (child.type === "title") {
|
|
35004
|
-
const titleChildren = child.props.children;
|
|
35005
|
-
titleEntry = {
|
|
35006
|
-
title: Array.isArray(titleChildren) ? titleChildren.join("") : titleChildren ?? ""
|
|
35007
|
-
};
|
|
35008
|
-
continue;
|
|
35009
|
-
}
|
|
35010
|
-
if (child.type === "meta" && child.props.name === "theme-color") {
|
|
35011
|
-
themeColors.push({
|
|
35012
|
-
content: child.props.content,
|
|
35013
|
-
media: child.props.media ?? null
|
|
35014
|
-
});
|
|
35015
|
-
continue;
|
|
35016
|
-
}
|
|
35017
|
-
const el = document.createElement(child.type);
|
|
35018
|
-
const props = child.props || {};
|
|
35256
|
+
for (const {
|
|
35257
|
+
type,
|
|
35258
|
+
props
|
|
35259
|
+
} of elements) {
|
|
35260
|
+
const el = document.createElement(type);
|
|
35019
35261
|
for (const [key, value] of Object.entries(props)) {
|
|
35020
35262
|
el.setAttribute(key, value);
|
|
35021
35263
|
}
|
|
35022
35264
|
document.head.appendChild(el);
|
|
35023
35265
|
appendedElements.push(el);
|
|
35024
35266
|
}
|
|
35025
|
-
if (titleEntry) {
|
|
35026
|
-
if (titleEntries.length === 0) {
|
|
35027
|
-
titleWithoutHead = document.title;
|
|
35028
|
-
}
|
|
35029
|
-
titleEntries.push(titleEntry);
|
|
35030
|
-
document.title = titleEntry.title;
|
|
35031
|
-
}
|
|
35032
|
-
const removeThemeColors = themeColors.length > 0 ? pushHeadThemeColors(themeColors) : null;
|
|
35033
35267
|
return () => {
|
|
35034
|
-
removeThemeColors?.();
|
|
35035
|
-
if (titleEntry) {
|
|
35036
|
-
titleEntries.splice(titleEntries.indexOf(titleEntry), 1);
|
|
35037
|
-
const lastEntry = titleEntries[titleEntries.length - 1];
|
|
35038
|
-
document.title = lastEntry ? lastEntry.title : titleWithoutHead;
|
|
35039
|
-
}
|
|
35040
35268
|
for (const el of appendedElements) {
|
|
35041
35269
|
el.remove();
|
|
35042
35270
|
}
|
|
35043
35271
|
};
|
|
35044
|
-
}, [
|
|
35272
|
+
}, [contentKey]);
|
|
35045
35273
|
return null;
|
|
35046
35274
|
};
|
|
35275
|
+
const writeDocumentTitle = () => {
|
|
35276
|
+
for (let i = headEntries.length - 1; i >= 0; i--) {
|
|
35277
|
+
const {
|
|
35278
|
+
title
|
|
35279
|
+
} = headEntries[i];
|
|
35280
|
+
if (title !== null) {
|
|
35281
|
+
document.title = title;
|
|
35282
|
+
return;
|
|
35283
|
+
}
|
|
35284
|
+
}
|
|
35285
|
+
if (titleWithoutHead !== null) {
|
|
35286
|
+
document.title = titleWithoutHead;
|
|
35287
|
+
titleWithoutHead = null;
|
|
35288
|
+
}
|
|
35289
|
+
};
|
|
35290
|
+
const readHeadChildren = children => {
|
|
35291
|
+
let title = null;
|
|
35292
|
+
const themeColors = [];
|
|
35293
|
+
const elements = [];
|
|
35294
|
+
if (!children) {
|
|
35295
|
+
return {
|
|
35296
|
+
title,
|
|
35297
|
+
themeColors,
|
|
35298
|
+
elements
|
|
35299
|
+
};
|
|
35300
|
+
}
|
|
35301
|
+
const childArray = Array.isArray(children) ? children : [children];
|
|
35302
|
+
for (const child of childArray) {
|
|
35303
|
+
if (!child) {
|
|
35304
|
+
continue;
|
|
35305
|
+
}
|
|
35306
|
+
if (child.type === "title") {
|
|
35307
|
+
const titleChildren = child.props.children;
|
|
35308
|
+
title = Array.isArray(titleChildren) ? titleChildren.join("") : titleChildren ?? "";
|
|
35309
|
+
continue;
|
|
35310
|
+
}
|
|
35311
|
+
if (child.type === "meta" && child.props.name === "theme-color") {
|
|
35312
|
+
themeColors.push({
|
|
35313
|
+
content: child.props.content,
|
|
35314
|
+
media: child.props.media ?? null
|
|
35315
|
+
});
|
|
35316
|
+
continue;
|
|
35317
|
+
}
|
|
35318
|
+
elements.push({
|
|
35319
|
+
type: child.type,
|
|
35320
|
+
props: child.props || {}
|
|
35321
|
+
});
|
|
35322
|
+
}
|
|
35323
|
+
return {
|
|
35324
|
+
title,
|
|
35325
|
+
themeColors,
|
|
35326
|
+
elements
|
|
35327
|
+
};
|
|
35328
|
+
};
|
|
35047
35329
|
|
|
35048
35330
|
/**
|
|
35049
35331
|
* A page is `{ route, params }`, never the route alone: a section of a page is
|
|
@@ -41789,7 +42071,7 @@ const resolveCommandValue = (source, event) => {
|
|
|
41789
42071
|
return event.detail.value;
|
|
41790
42072
|
}
|
|
41791
42073
|
if (source.hasAttribute("command-value")) {
|
|
41792
|
-
return source
|
|
42074
|
+
return readCommandValue(source);
|
|
41793
42075
|
}
|
|
41794
42076
|
if (source.type === "radio" || source.type === "checkbox") {
|
|
41795
42077
|
// Use readControlValue so that radio/checkbox sources return their `value`
|
|
@@ -41805,6 +42087,20 @@ const resolveCommandValue = (source, event) => {
|
|
|
41805
42087
|
// selected, and the screen it opens would prefill a new entry with it.
|
|
41806
42088
|
return getUIStateFromElement(source, { own: true });
|
|
41807
42089
|
};
|
|
42090
|
+
// The value as it was given: a <Button command-value={12}> holds the number, an
|
|
42091
|
+
// object, whatever the prop said, where its attribute can only say a string. A
|
|
42092
|
+
// plain element carrying the attribute says that string.
|
|
42093
|
+
const readCommandValue = (source) => {
|
|
42094
|
+
let responded = false;
|
|
42095
|
+
let value;
|
|
42096
|
+
dispatchCustomEvent(source, "navi_get_command_value", {
|
|
42097
|
+
respondWith: (jsValue) => {
|
|
42098
|
+
responded = true;
|
|
42099
|
+
value = jsValue;
|
|
42100
|
+
},
|
|
42101
|
+
});
|
|
42102
|
+
return responded ? value : source.getAttribute("command-value");
|
|
42103
|
+
};
|
|
41808
42104
|
|
|
41809
42105
|
const onNaviCommand = (e, { debugCommand = () => {} } = {}) => {
|
|
41810
42106
|
const { command, event, source, implementation } = e.detail;
|
|
@@ -42572,7 +42868,11 @@ const executeNaviDefine = (source, event, target) => {
|
|
|
42572
42868
|
// reads it (see List). "--navi-scroll:smooth" asks for the glide.
|
|
42573
42869
|
const scrollCommand = (source, event, { argument, value }) => {
|
|
42574
42870
|
const target =
|
|
42575
|
-
resolveExplicitTarget(source) ||
|
|
42871
|
+
resolveExplicitTarget(source) ||
|
|
42872
|
+
// The list sending it about itself, as List's JSDoc writes a scroll asked
|
|
42873
|
+
// by code: triggerNaviCommand(listEl, "--navi-scroll", event, { value }).
|
|
42874
|
+
(source.matches(".navi_list_container") ? source : null) ||
|
|
42875
|
+
resolveFirstParentControl(source);
|
|
42576
42876
|
if (!target) {
|
|
42577
42877
|
return undefined;
|
|
42578
42878
|
}
|
|
@@ -44106,6 +44406,9 @@ const useAutoFocus = (
|
|
|
44106
44406
|
`[autofocus] "${ancestorType}" opened ${getElementSignature(ancestor)} -> ${focusDebugCall}`,
|
|
44107
44407
|
);
|
|
44108
44408
|
}
|
|
44409
|
+
if (focusVisible === true) {
|
|
44410
|
+
askFocusVisible(focusableElement);
|
|
44411
|
+
}
|
|
44109
44412
|
focusableElement.focus({ preventScroll, focusVisible });
|
|
44110
44413
|
if (autoSelect) {
|
|
44111
44414
|
focusableElement.select();
|
|
@@ -49147,12 +49450,17 @@ const useControlProps = (props, {
|
|
|
49147
49450
|
}
|
|
49148
49451
|
};
|
|
49149
49452
|
}
|
|
49453
|
+
|
|
49454
|
+
// A field with an action of its own has Enter answered already: the
|
|
49455
|
+
// input effect (input_effect.js) commits it — through the change Enter
|
|
49456
|
+
// fires, or on the keydown itself under actionDebounce — and an action
|
|
49457
|
+
// run on every keystroke has nothing left to commit. --navi-send would
|
|
49458
|
+
// run that same action a second time. Nothing answers it under
|
|
49459
|
+
// actionEvent="custom", where the field's caller does.
|
|
49460
|
+
const enterAnsweredByInputEffect = Boolean(actionDebounce) || props.action !== undefined && actionEvent !== "custom";
|
|
49150
49461
|
const keyDownDefaultOnInput = e => {
|
|
49151
49462
|
if (e.key === "Enter") {
|
|
49152
|
-
if (
|
|
49153
|
-
// The input has its own debounced action; Enter fires it directly
|
|
49154
|
-
// (input_effect.js cancels the debounce and triggers the action via the change event).
|
|
49155
|
-
// Don't propagate to --navi-send, which would cause a double action call.
|
|
49463
|
+
if (enterAnsweredByInputEffect) {
|
|
49156
49464
|
return null;
|
|
49157
49465
|
}
|
|
49158
49466
|
return enterToSend(e);
|
|
@@ -53837,12 +54145,15 @@ const TextOverflow = ({
|
|
|
53837
54145
|
}) => {
|
|
53838
54146
|
return jsx(Text, {
|
|
53839
54147
|
block: true,
|
|
53840
|
-
as: "div"
|
|
53841
|
-
|
|
54148
|
+
as: "div"
|
|
54149
|
+
// One line does not wrap, at a typed newline either: white-space: pre
|
|
54150
|
+
// would keep every newline, and the text would be one line only while it
|
|
54151
|
+
// has none. A white-space the caller says wins.
|
|
54152
|
+
,
|
|
54153
|
+
noWrap: noWrap ?? (rest.as === "p" || saysWhiteSpace(rest) ? undefined : true)
|
|
53842
54154
|
// For paragraph we prefer to keep lines and only hide unbreakable long sections
|
|
53843
54155
|
,
|
|
53844
54156
|
preLine: rest.as === "p" ? true : undefined,
|
|
53845
|
-
noWrap: noWrap,
|
|
53846
54157
|
...rest,
|
|
53847
54158
|
maxLines: undefined,
|
|
53848
54159
|
"data-text-overflow": "",
|
|
@@ -59432,7 +59743,7 @@ const css$S = /* css */`@layer navi {
|
|
|
59432
59743
|
transparent);
|
|
59433
59744
|
}
|
|
59434
59745
|
|
|
59435
|
-
.navi_button
|
|
59746
|
+
.navi_button {
|
|
59436
59747
|
background: none;
|
|
59437
59748
|
border: none;
|
|
59438
59749
|
padding: 0;
|
|
@@ -59464,10 +59775,8 @@ a.navi_button {
|
|
|
59464
59775
|
outline: none;
|
|
59465
59776
|
position: relative;
|
|
59466
59777
|
|
|
59467
|
-
|
|
59468
|
-
|
|
59469
|
-
border: none;
|
|
59470
|
-
padding: 0;
|
|
59778
|
+
& .navi_button_content > [data-navi-space] {
|
|
59779
|
+
display: contents;
|
|
59471
59780
|
}
|
|
59472
59781
|
|
|
59473
59782
|
& .navi_button_content {
|
|
@@ -59742,6 +60051,12 @@ const ButtonUI = props => {
|
|
|
59742
60051
|
,
|
|
59743
60052
|
onnavi_get_value: e => {
|
|
59744
60053
|
e.detail.respondWith(props.value);
|
|
60054
|
+
}
|
|
60055
|
+
// Same for what a command is about, when it is not the button's value
|
|
60056
|
+
// (see resolveCommandValue).
|
|
60057
|
+
,
|
|
60058
|
+
onnavi_get_command_value: e => {
|
|
60059
|
+
e.detail.respondWith(props["command-value"]);
|
|
59745
60060
|
},
|
|
59746
60061
|
onContextMenu: e => {
|
|
59747
60062
|
if (as === "a") {
|
|
@@ -59782,7 +60097,12 @@ const ButtonUI = props => {
|
|
|
59782
60097
|
...controlChildrenWrapperProps,
|
|
59783
60098
|
children: jsx(ButtonContent, {
|
|
59784
60099
|
spacing: spacing,
|
|
59785
|
-
contentDisplay: contentDisplay
|
|
60100
|
+
contentDisplay: contentDisplay
|
|
60101
|
+
// The frame lays the children out in the button's flow: told so, a
|
|
60102
|
+
// `spacing` is its gap rather than a space one line tall. Not without
|
|
60103
|
+
// a frame: the button's box lays them out then.
|
|
60104
|
+
,
|
|
60105
|
+
flex: contentDisplay === "contents" ? undefined : props.flex ?? (icon ? "x" : undefined),
|
|
59786
60106
|
children: children
|
|
59787
60107
|
})
|
|
59788
60108
|
})]
|
|
@@ -59795,12 +60115,14 @@ const ButtonUI = props => {
|
|
|
59795
60115
|
const ButtonContent = ({
|
|
59796
60116
|
spacing,
|
|
59797
60117
|
contentDisplay = "inherit",
|
|
60118
|
+
flex,
|
|
59798
60119
|
children
|
|
59799
60120
|
}) => {
|
|
59800
60121
|
const boxForwardedProps = useContext(BoxForwardedPropsContext);
|
|
59801
60122
|
return jsxs(Text, {
|
|
59802
60123
|
...boxForwardedProps,
|
|
59803
60124
|
display: contentDisplay,
|
|
60125
|
+
flex: flex,
|
|
59804
60126
|
spacing: spacing,
|
|
59805
60127
|
className: "navi_button_content",
|
|
59806
60128
|
children: [children, jsx(ButtonShadow, {})]
|
|
@@ -70091,7 +70413,10 @@ const engageGroup = (groupEl, group, {
|
|
|
70091
70413
|
const focusWasInGroup = Boolean(focusedBefore) && focusedBefore !== groupEl && groupEl.contains(focusedBefore);
|
|
70092
70414
|
// What the focus goes back to, when nothing holds it any more at the close.
|
|
70093
70415
|
const focusOrigin = !focusWasInGroup && focusedBefore && focusedBefore !== document.body && focusedBefore !== groupEl ? focusedBefore : null;
|
|
70094
|
-
|
|
70416
|
+
// The ring navi drew, not the browser's flag: the flag outlives a press
|
|
70417
|
+
// whose mousedown was prevented, and given back as `focusVisible: true` it
|
|
70418
|
+
// would draw a ring nobody saw before (see isMatchingFocusVisible).
|
|
70419
|
+
const ringBefore = Boolean(focusedBefore?.matches && isMatchingFocusVisible(focusedBefore));
|
|
70095
70420
|
const {
|
|
70096
70421
|
scrollTop,
|
|
70097
70422
|
scrollLeft
|
|
@@ -70267,7 +70592,7 @@ const engageGroup = (groupEl, group, {
|
|
|
70267
70592
|
// or the user, put it since. Unless nothing moved it, that element is
|
|
70268
70593
|
// made no focus target for the call: inert — or, holding the focus
|
|
70269
70594
|
// inside it, without its tabindex, inert taking the focus with it.
|
|
70270
|
-
const ringBeforeClose = Boolean(focusedBeforeClose?.matches
|
|
70595
|
+
const ringBeforeClose = Boolean(focusedBeforeClose?.matches && isMatchingFocusVisible(focusedBeforeClose));
|
|
70271
70596
|
const focusMovedInGroup = focusWasInGroup && focusedBeforeClose && focusedBeforeClose !== document.body && focusedBeforeClose !== groupEl && focusedBeforeClose !== focusedBefore && focusedBeforeClose.isConnected && focusedBefore.isConnected;
|
|
70272
70597
|
const holdsFocusInside = focusMovedInGroup && focusedBefore.contains(focusedBeforeClose);
|
|
70273
70598
|
const madeInert = focusMovedInGroup && !holdsFocusInside && !focusedBefore.inert;
|
|
@@ -72250,6 +72575,29 @@ const usePopupName = ({
|
|
|
72250
72575
|
};
|
|
72251
72576
|
const NO_TITLE = [];
|
|
72252
72577
|
|
|
72578
|
+
// The open controller's popupValueSignal (see open_controller.js), handed to
|
|
72579
|
+
// the content by whatever renders it: Dialog, Popover, a picker's callout.
|
|
72580
|
+
const PopupValueContext = createContext(null);
|
|
72581
|
+
|
|
72582
|
+
/**
|
|
72583
|
+
* What the popup this is rendered inside is open ON: the value its `signal`
|
|
72584
|
+
* held while it read open (the id a single sheet bound to `?open=<id>` shows),
|
|
72585
|
+
* else its `value`, else the value of whatever opened it
|
|
72586
|
+
* (`<Button value={id} command="--navi-open">`).
|
|
72587
|
+
*
|
|
72588
|
+
* Held from the opening to the end of the exit, whoever asks the close: the
|
|
72589
|
+
* signal and the address read closed as soon as the close starts, while an
|
|
72590
|
+
* animated exit — and a lift flying back to the card it came from — still
|
|
72591
|
+
* draws what the content renders. A refused close keeps it; a reopening on
|
|
72592
|
+
* another value switches it at the reopening.
|
|
72593
|
+
*
|
|
72594
|
+
* @returns {any} `undefined` outside a popup.
|
|
72595
|
+
*/
|
|
72596
|
+
const usePopupValue = () => {
|
|
72597
|
+
const popupValueSignal = useContext(PopupValueContext);
|
|
72598
|
+
return popupValueSignal ? popupValueSignal.value : undefined;
|
|
72599
|
+
};
|
|
72600
|
+
|
|
72253
72601
|
installImportMetaCssBuild(import.meta);
|
|
72254
72602
|
// Same need popover.jsx has for its own local renderer (see its
|
|
72255
72603
|
// openLocalPopoverCount): a layer="local" dialog is a plain positioned element
|
|
@@ -73194,7 +73542,7 @@ const css$C = /* css */`
|
|
|
73194
73542
|
* whatever triggered the open (`e.detail.source`). A string is resolved via
|
|
73195
73543
|
* `document.getElementById` when the dialog opens — see popover.jsx's own
|
|
73196
73544
|
* `anchor` doc for why (mainly `defaultOpen`).
|
|
73197
|
-
* @param {Element|{current: Element}|string} [props.liftAnchor] - Under
|
|
73545
|
+
* @param {Element|{current: Element}|string|((popupValue: any) => Element|{current: Element}|string)} [props.liftAnchor] - Under
|
|
73198
73546
|
* `animation="lifting"` or `animation={{ open, close: "lifting" }}`, where the closing
|
|
73199
73547
|
* brings the box back to, when that is not where it came from: a popup one
|
|
73200
73548
|
* walks through (a row of cards shown one at a time) has something else in
|
|
@@ -73202,8 +73550,10 @@ const css$C = /* css */`
|
|
|
73202
73550
|
* card the press opened on. Same grammar as `anchor` (element, ref or id),
|
|
73203
73551
|
* resolved once the close is made — after `onClose` — so whatever names the
|
|
73204
73552
|
* card currently in front, or the box the close itself renders, is read
|
|
73205
|
-
* then and not at the opening.
|
|
73206
|
-
*
|
|
73553
|
+
* then and not at the opening. A function is called then with what the
|
|
73554
|
+
* dialog was open on (see `usePopupValue`): a close the holder asks for
|
|
73555
|
+
* (Back taking the id out of the address) has emptied its signal by then.
|
|
73556
|
+
* Left out, the box comes back to the anchor it came out of.
|
|
73207
73557
|
* @param {boolean} [props.sizeFromAnchor=false] - Whether the dialog takes the
|
|
73208
73558
|
* anchor's width/height as a min-width/min-height floor
|
|
73209
73559
|
* (`--anchor-width`/`--anchor-height`). Off by default: unlike a popover,
|
|
@@ -73736,9 +74086,12 @@ const useDialogProps = props => {
|
|
|
73736
74086
|
openerAriaLabel,
|
|
73737
74087
|
openerAriaLabelledBy
|
|
73738
74088
|
});
|
|
73739
|
-
const children = contentMounted ? jsx(
|
|
73740
|
-
value:
|
|
73741
|
-
children:
|
|
74089
|
+
const children = contentMounted ? jsx(PopupValueContext.Provider, {
|
|
74090
|
+
value: openController.popupValueSignal,
|
|
74091
|
+
children: jsx(PopupTitleContext.Provider, {
|
|
74092
|
+
value: registerTitle,
|
|
74093
|
+
children: childrenProp
|
|
74094
|
+
})
|
|
73742
74095
|
}) : null;
|
|
73743
74096
|
// Where it is placed, and whether there is a wall — the two questions that
|
|
73744
74097
|
// pick the show call (see this file's top comment).
|
|
@@ -73939,12 +74292,18 @@ const useDialogProps = props => {
|
|
|
73939
74292
|
// Silent when it names nothing: the close may be what renders it, and
|
|
73940
74293
|
// popup_lift.js asks again until it is there (and warns past that).
|
|
73941
74294
|
const resolveLiftAnchorElement = () => {
|
|
73942
|
-
|
|
73943
|
-
|
|
74295
|
+
// Asked with what the dialog was open on, which the signal holding it no
|
|
74296
|
+
// longer says once the close has started (see usePopupValue).
|
|
74297
|
+
const named = typeof liftAnchor === "function" ? liftAnchor(openController.popupValueSignal.peek()) : liftAnchor;
|
|
74298
|
+
if (!named) {
|
|
74299
|
+
return null;
|
|
74300
|
+
}
|
|
74301
|
+
if (typeof named === "string") {
|
|
74302
|
+
return document.getElementById(named);
|
|
73944
74303
|
}
|
|
73945
74304
|
// A ref is unwrapped even when it holds nothing, the same way `anchor` is:
|
|
73946
74305
|
// the ref object itself has no box to come back to.
|
|
73947
|
-
return "current" in
|
|
74306
|
+
return "current" in named ? named.current : named;
|
|
73948
74307
|
};
|
|
73949
74308
|
|
|
73950
74309
|
// The dialog and the anchor are the same box at two sizes, so the opening
|
|
@@ -74186,10 +74545,10 @@ const useDialogProps = props => {
|
|
|
74186
74545
|
// resolveSpacingSize walks up from there to find that container.
|
|
74187
74546
|
let marginWithContainerInPixels = resolveSpacingSize(marginWithContainer, dialogEl.parentElement);
|
|
74188
74547
|
if (typeof marginWithContainerInPixels !== "number") {
|
|
74189
|
-
// A value only CSS could evaluate (a
|
|
74190
|
-
//
|
|
74191
|
-
//
|
|
74192
|
-
console.warn(`Dialog: marginWithContainer="${marginWithContainer}" cannot be resolved to pixels. Use a number, a viewport length ("3appw", "3vvw", "2vvh") or a container length ("3cqw", "2cqh").`);
|
|
74548
|
+
// A value only CSS could evaluate (a percentage, a calc()…) — the
|
|
74549
|
+
// placement below needs a real number, and letting it through would
|
|
74550
|
+
// put the dialog at NaN.
|
|
74551
|
+
console.warn(`Dialog: marginWithContainer="${marginWithContainer}" cannot be resolved to pixels. Use a number, a spacing word ("s", "m"…), a viewport length ("3appw", "3vvw", "2vvh") or a container length ("3cqw", "2cqh").`);
|
|
74193
74552
|
marginWithContainerInPixels = 0;
|
|
74194
74553
|
}
|
|
74195
74554
|
// The size caps read the same gap in CSS as the placement below applies
|
|
@@ -75226,9 +75585,11 @@ const css$B = /* css */`
|
|
|
75226
75585
|
* big to bother anchoring to (`isAnchorTooBig`, always checked — see
|
|
75227
75586
|
* `pickPositionRelativeTo`'s own doc in visible_rect.js).
|
|
75228
75587
|
* @param {string|number} [props.marginWithContainer=0] - Extra spacing kept
|
|
75229
|
-
* between the popover and the edges of its container
|
|
75588
|
+
* between the popover and the edges of its container: a number of px, a
|
|
75589
|
+
* spacing word (`"s"`, read at the page's font size), a viewport length
|
|
75590
|
+
* (`"3appw"`) or a container length (`"3cqw"`).
|
|
75230
75591
|
* @param {string|number} [props.marginWithAnchor=0] - Extra spacing kept
|
|
75231
|
-
* between the popover and the edges of its anchor.
|
|
75592
|
+
* between the popover and the edges of its anchor, written the same way.
|
|
75232
75593
|
* @param {boolean} [props.backdrop=true] - Whether anything is laid between
|
|
75233
75594
|
* the popover and the page at all — asked before what an outside press does
|
|
75234
75595
|
* and before how the backdrop is painted. `false` leaves the page
|
|
@@ -75692,9 +76053,12 @@ const usePopoverProps = props => {
|
|
|
75692
76053
|
openerAriaLabel,
|
|
75693
76054
|
openerAriaLabelledBy
|
|
75694
76055
|
});
|
|
75695
|
-
const children = contentMounted ? jsx(
|
|
75696
|
-
value:
|
|
75697
|
-
children:
|
|
76056
|
+
const children = contentMounted ? jsx(PopupValueContext.Provider, {
|
|
76057
|
+
value: openController.popupValueSignal,
|
|
76058
|
+
children: jsx(PopupTitleContext.Provider, {
|
|
76059
|
+
value: registerTitle,
|
|
76060
|
+
children: childrenProp
|
|
76061
|
+
})
|
|
75698
76062
|
}) : null;
|
|
75699
76063
|
const isTopLayer = layer === "top";
|
|
75700
76064
|
const ref = props.ref;
|
|
@@ -76009,8 +76373,8 @@ const usePopoverProps = props => {
|
|
|
76009
76373
|
positionArea,
|
|
76010
76374
|
positionAreaFixed,
|
|
76011
76375
|
positionAreaWhenAnchorIsInvalid,
|
|
76012
|
-
marginWithAnchor:
|
|
76013
|
-
marginWithContainer:
|
|
76376
|
+
marginWithAnchor: resolveMarginInPixels(marginWithAnchor, "marginWithAnchor"),
|
|
76377
|
+
marginWithContainer: resolveMarginInPixels(marginWithContainer, "marginWithContainer"),
|
|
76014
76378
|
// Only meaningful for the custom renderer: popoverEl is always
|
|
76015
76379
|
// position: absolute relative to its own positioned ancestor,
|
|
76016
76380
|
// real anchor or not — this tells pickPositionRelativeTo to
|
|
@@ -76067,7 +76431,7 @@ const usePopoverProps = props => {
|
|
|
76067
76431
|
const pickOptions = {
|
|
76068
76432
|
positionArea,
|
|
76069
76433
|
container: positionedAncestor,
|
|
76070
|
-
marginWithContainer:
|
|
76434
|
+
marginWithContainer: resolveMarginInPixels(marginWithContainer, "marginWithContainer"),
|
|
76071
76435
|
event: positionEvent
|
|
76072
76436
|
};
|
|
76073
76437
|
position = pickPositionRelativeTo(popoverEl, null, pickOptions);
|
|
@@ -76643,6 +77007,17 @@ const resolvePositionAreaAndAnimationKind = ({
|
|
|
76643
77007
|
Popover.Close = PopupClose;
|
|
76644
77008
|
Popover.Title = PopupTitle;
|
|
76645
77009
|
|
|
77010
|
+
// The placement needs pixels: a value only CSS could evaluate (a percentage, a
|
|
77011
|
+
// calc()…) would put the popover at NaN, which is the top of the page.
|
|
77012
|
+
const resolveMarginInPixels = (margin, name) => {
|
|
77013
|
+
const pixels = resolveSpacingSize(margin);
|
|
77014
|
+
if (typeof pixels === "number") {
|
|
77015
|
+
return pixels;
|
|
77016
|
+
}
|
|
77017
|
+
console.warn(`Popover: ${name}="${margin}" cannot be resolved to pixels. Use a number, a spacing word ("xs", "s", "m"…), a viewport length ("3appw", "3vvw") or a container length ("3cqw", "2cqh").`);
|
|
77018
|
+
return 0;
|
|
77019
|
+
};
|
|
77020
|
+
|
|
76646
77021
|
installImportMetaCssBuild(import.meta);
|
|
76647
77022
|
const css$A = /* css */`@layer navi {
|
|
76648
77023
|
.navi_popup {
|
|
@@ -76702,7 +77077,7 @@ const css$A = /* css */`@layer navi {
|
|
|
76702
77077
|
* `maxWidth` below.
|
|
76703
77078
|
* @param {boolean} [props.sizeFromAnchor] - **Dialog-only**, same guard.
|
|
76704
77079
|
* @param {"box"|"scene"} [props.lift] - **Dialog-only**, same guard.
|
|
76705
|
-
* @param {Element|{current: Element}|string} [props.liftAnchor] -
|
|
77080
|
+
* @param {Element|{current: Element}|string|((popupValue: any) => Element|{current: Element}|string)} [props.liftAnchor] -
|
|
76706
77081
|
* **Dialog-only**, same guard.
|
|
76707
77082
|
* @param {string} [props.positionArea] - Forwarded as-is — `Dialog` and
|
|
76708
77083
|
* `Popover` have different own defaults (`"center"` vs. `"bottom"`),
|
|
@@ -76991,9 +77366,12 @@ const getPickerHostLabelId = (id, props) => {
|
|
|
76991
77366
|
* right now: in the popup, what is being picked, before anything is sent; on
|
|
76992
77367
|
* the façade, the answer the popup just closed on, before the server has said
|
|
76993
77368
|
* anything, and put back if the action fails. `loading` is the run in flight;
|
|
76994
|
-
* `interactive` is false while the picker is disabled, read-only or busy
|
|
77369
|
+
* `interactive` is false while the picker is disabled, read-only or busy;
|
|
77370
|
+
* `readOnly` says the picker is read-only or held by the network policy — a
|
|
77371
|
+
* hold the controls a caller draws on the façade are not held by, so a face
|
|
77372
|
+
* that wants to look held reads it here.
|
|
76995
77373
|
*
|
|
76996
|
-
* @returns {{ value: any, loading: boolean, interactive: boolean } | null}
|
|
77374
|
+
* @returns {{ value: any, loading: boolean, interactive: boolean, readOnly: boolean } | null}
|
|
76997
77375
|
* null outside a picker.
|
|
76998
77376
|
*/
|
|
76999
77377
|
const usePickerState = () => {
|
|
@@ -77004,12 +77382,14 @@ const usePickerState = () => {
|
|
|
77004
77382
|
const {
|
|
77005
77383
|
value,
|
|
77006
77384
|
loading,
|
|
77007
|
-
interactive
|
|
77385
|
+
interactive,
|
|
77386
|
+
readOnly
|
|
77008
77387
|
} = context;
|
|
77009
77388
|
return {
|
|
77010
77389
|
value,
|
|
77011
77390
|
loading,
|
|
77012
|
-
interactive
|
|
77391
|
+
interactive,
|
|
77392
|
+
readOnly
|
|
77013
77393
|
};
|
|
77014
77394
|
};
|
|
77015
77395
|
|
|
@@ -77347,6 +77727,9 @@ const PickerCustom = props => {
|
|
|
77347
77727
|
onConfirm,
|
|
77348
77728
|
onClose
|
|
77349
77729
|
};
|
|
77730
|
+
// The press the trigger's mousedown answered (see its reactions below): the
|
|
77731
|
+
// click it ends with is that press, not a second question.
|
|
77732
|
+
const pressAnsweredAtMouseDownRef = useRef(null);
|
|
77350
77733
|
// aria-controls + id
|
|
77351
77734
|
const popupId = `${props.id}_picker_popup`;
|
|
77352
77735
|
{
|
|
@@ -77620,11 +78003,6 @@ const PickerCustom = props => {
|
|
|
77620
78003
|
// button) hangs its popup off the whole control instead.
|
|
77621
78004
|
anchor: props.anchor || props.ref,
|
|
77622
78005
|
openController,
|
|
77623
|
-
// Before the content is built and shown, so it is laid out and placed
|
|
77624
|
-
// at the size it is read at (see .navi_picker_content in picker.jsx).
|
|
77625
|
-
onOpen: () => {
|
|
77626
|
-
writeContainerFont(ref.current, popupRef.current);
|
|
77627
|
-
},
|
|
77628
78006
|
// A picker whose value was never given to it reads it off the control in
|
|
77629
78007
|
// its popup (see useUIFacadeStateController), so that control is built as
|
|
77630
78008
|
// soon as something reads the value: at mount when the picker sees the
|
|
@@ -77856,6 +78234,7 @@ const PickerCustom = props => {
|
|
|
77856
78234
|
// Closing stays on the press even then: a gesture starting on an
|
|
77857
78235
|
// open picker wants the popup out of the way, and there is no
|
|
77858
78236
|
// choice being taken from anyone.
|
|
78237
|
+
pressAnsweredAtMouseDownRef.current = readPressCount();
|
|
77859
78238
|
return {
|
|
77860
78239
|
name: "mousedown to close picker",
|
|
77861
78240
|
intent: "read",
|
|
@@ -77874,6 +78253,7 @@ const PickerCustom = props => {
|
|
|
77874
78253
|
if (!opensOnPress || interactionsDispute || isPressDisputedByDrag(e.target) || isPressDisputedByHold(ref.current)) {
|
|
77875
78254
|
return null;
|
|
77876
78255
|
}
|
|
78256
|
+
pressAnsweredAtMouseDownRef.current = readPressCount();
|
|
77877
78257
|
return {
|
|
77878
78258
|
name: "mousedown to open picker",
|
|
77879
78259
|
intent: "read",
|
|
@@ -77888,6 +78268,15 @@ const PickerCustom = props => {
|
|
|
77888
78268
|
if (isWithinPickerContent(e.target)) {
|
|
77889
78269
|
return null;
|
|
77890
78270
|
}
|
|
78271
|
+
// One press, one answer: the press its mousedown answered is only
|
|
78272
|
+
// ending. Asked again, a refusal still on screen would read this
|
|
78273
|
+
// click as "got it" and take its explanation down before a frame
|
|
78274
|
+
// is drawn — under a finger the mousedown and the click arrive
|
|
78275
|
+
// together, after touchend (see reportInteractivity).
|
|
78276
|
+
if (e.detail !== 0 && pressAnsweredAtMouseDownRef.current === readPressCount()) {
|
|
78277
|
+
e.preventDefault();
|
|
78278
|
+
return null;
|
|
78279
|
+
}
|
|
77891
78280
|
// Still open at the click of a later press: that press brought no
|
|
77892
78281
|
// mousedown to close on (a drag source cancelled its pointerdown),
|
|
77893
78282
|
// so it closes here, as it opens here in that case. A mousedown
|
|
@@ -77993,17 +78382,35 @@ const getTriggerLabelIds = pickerEl => {
|
|
|
77993
78382
|
return ids.length === 0 ? undefined : ids.join(" ");
|
|
77994
78383
|
};
|
|
77995
78384
|
// What the picker holds without the person having changed it: its `value` (or
|
|
77996
|
-
// signal) moving, a default moving under it
|
|
77997
|
-
//
|
|
77998
|
-
//
|
|
78385
|
+
// signal) moving, a default moving under it, and what its popup's controls are
|
|
78386
|
+
// placed on as they mount. Read along the chain, never off the event alone: a
|
|
78387
|
+
// control in the popup carries its change up to the picker as an event of its
|
|
78388
|
+
// own (see the facade in ui_state_controller.js), chained to what caused it —
|
|
78389
|
+
// an app writing that control's bound signal included.
|
|
78390
|
+
const OUTSIDE_WRITE_TYPE_SET = new Set(["state_prop_change", "initial_state_push", "facade_child_mount_sync", "outside_value_follow"]);
|
|
77999
78391
|
const isWrittenByTheOutside = e => {
|
|
78000
78392
|
if (!e) {
|
|
78001
78393
|
return false;
|
|
78002
78394
|
}
|
|
78003
|
-
|
|
78395
|
+
return Boolean(findEvent(e, event => OUTSIDE_WRITE_TYPE_SET.has(event.type)));
|
|
78396
|
+
};
|
|
78397
|
+
// The popup echoes the trigger's corners (see the CSS above), right for a
|
|
78398
|
+
// length and wrong for a shape: a round trigger's 50% read on a sheet of
|
|
78399
|
+
// another size is an ellipse, and a pill's 999px a stadium. A shape leaves the
|
|
78400
|
+
// popup on the corners every popup has.
|
|
78401
|
+
const PILL_RADIUS_MIN_PX = 100;
|
|
78402
|
+
const isBorderRadiusAShape = borderRadius => {
|
|
78403
|
+
if (typeof borderRadius === "number") {
|
|
78404
|
+
return borderRadius >= PILL_RADIUS_MIN_PX;
|
|
78405
|
+
}
|
|
78406
|
+
if (typeof borderRadius !== "string") {
|
|
78407
|
+
return false;
|
|
78408
|
+
}
|
|
78409
|
+
const radius = borderRadius.trim();
|
|
78410
|
+
if (radius.endsWith("%")) {
|
|
78004
78411
|
return true;
|
|
78005
78412
|
}
|
|
78006
|
-
return
|
|
78413
|
+
return radius.endsWith("px") && parseFloat(radius) >= PILL_RADIUS_MIN_PX;
|
|
78007
78414
|
};
|
|
78008
78415
|
const getPickerInputUIState = pickerEl => {
|
|
78009
78416
|
const pickerInput = getPickerInput(pickerEl);
|
|
@@ -78178,7 +78585,7 @@ const PickerContentInsidePopup = props => {
|
|
|
78178
78585
|
,
|
|
78179
78586
|
"data-picker-popup": "",
|
|
78180
78587
|
backgroundColor: popupBackgroundColor,
|
|
78181
|
-
borderRadius: popupBorderRadius,
|
|
78588
|
+
borderRadius: popupBorderRadius === undefined && isBorderRadiusAShape(props.borderRadius) ? "var(--navi-popup-border-radius)" : popupBorderRadius,
|
|
78182
78589
|
boxShadow: popupBoxShadow,
|
|
78183
78590
|
borderWidth: isPopover ? undefined : dialogBorderWidth,
|
|
78184
78591
|
minWidth: isPopover ? popupWidthFitContent ? undefined : "var(--anchor-width, 0px)" : dialogMinWidth,
|
|
@@ -78278,7 +78685,10 @@ const PickerCalloutPopup = ({
|
|
|
78278
78685
|
mount,
|
|
78279
78686
|
anchor
|
|
78280
78687
|
});
|
|
78281
|
-
const children = contentMounted ?
|
|
78688
|
+
const children = contentMounted ? jsx(PopupValueContext.Provider, {
|
|
78689
|
+
value: openController.popupValueSignal,
|
|
78690
|
+
children: childrenProp
|
|
78691
|
+
}) : null;
|
|
78282
78692
|
// Inside a <PopupGroup> the wall is the group's (see popup_group.jsx): it
|
|
78283
78693
|
// decides what a press outside the callout does, and the callout spends and
|
|
78284
78694
|
// closes on none of its own.
|
|
@@ -78437,6 +78847,13 @@ const findFileChooser = pickerEl => {
|
|
|
78437
78847
|
return pickerEl.querySelector(".navi_picker_file_chooser");
|
|
78438
78848
|
};
|
|
78439
78849
|
const showNativePicker = (pickerInput, event) => {
|
|
78850
|
+
if (pickerInput.type === "file") {
|
|
78851
|
+
// WebKit presents nothing for a file input's showPicker() and throws
|
|
78852
|
+
// nothing, so the catch below never learns of it; a click, within the
|
|
78853
|
+
// press, opens the chooser in every engine.
|
|
78854
|
+
pickerInput.click();
|
|
78855
|
+
return;
|
|
78856
|
+
}
|
|
78440
78857
|
if (findEvent(event, isTouchDrivenEvent)) {
|
|
78441
78858
|
moveFocusTo(pickerInput, {
|
|
78442
78859
|
focusVisible: false
|
|
@@ -78449,30 +78866,6 @@ const showNativePicker = (pickerInput, event) => {
|
|
|
78449
78866
|
}
|
|
78450
78867
|
};
|
|
78451
78868
|
|
|
78452
|
-
// The popup of a picker is opened where the picker stands, so it writes at the
|
|
78453
|
-
// size and weight of what is around it — the ones a Dialog rendered there
|
|
78454
|
-
// inherits — and never at the ones the trigger is drawn at. CSS cannot reach
|
|
78455
|
-
// past the picker's own: its root holds the popup and sets both. Written on the
|
|
78456
|
-
// holder only when they differ, so an opening that changes nothing invalidates
|
|
78457
|
-
// no style.
|
|
78458
|
-
const writeContainerFont = (pickerEl, popupEl) => {
|
|
78459
|
-
const container = pickerEl?.parentElement;
|
|
78460
|
-
const holder = popupEl?.closest("[data-picker-content]");
|
|
78461
|
-
if (!container || !holder) {
|
|
78462
|
-
return;
|
|
78463
|
-
}
|
|
78464
|
-
const {
|
|
78465
|
-
fontSize,
|
|
78466
|
-
fontWeight
|
|
78467
|
-
} = getComputedStyle(container);
|
|
78468
|
-
if (holder.style.fontSize !== fontSize) {
|
|
78469
|
-
holder.style.fontSize = fontSize;
|
|
78470
|
-
}
|
|
78471
|
-
if (holder.style.fontWeight !== fontWeight) {
|
|
78472
|
-
holder.style.fontWeight = fontWeight;
|
|
78473
|
-
}
|
|
78474
|
-
};
|
|
78475
|
-
|
|
78476
78869
|
installImportMetaCssBuild(import.meta);
|
|
78477
78870
|
const css$y = /* css */`.navi_picker_confirm_body {
|
|
78478
78871
|
min-width: 180px;
|
|
@@ -79092,7 +79485,8 @@ const css$x = /* css */`@layer navi {
|
|
|
79092
79485
|
* vertical one matches the line of text it sits on.
|
|
79093
79486
|
* @param {string} [props.color] - The line's own colour — `--color`.
|
|
79094
79487
|
* @param {string|number} [props.margin="0.5em"] - Room kept on both sides of
|
|
79095
|
-
* the line — `--margin`.
|
|
79488
|
+
* the line — `--margin`. A spacing word (`"xs"`, `"s"`, `"m"`…), a length or
|
|
79489
|
+
* a number of px, like any margin prop.
|
|
79096
79490
|
* @param {string|number} [props.marginStart] - Room on one side only —
|
|
79097
79491
|
* `--margin-start`, above a horizontal rule and left of a vertical one.
|
|
79098
79492
|
* @param {string|number} [props.marginEnd] - …and the other, `--margin-end`.
|
|
@@ -79123,9 +79517,9 @@ const Separator = ({
|
|
|
79123
79517
|
...cssVars({
|
|
79124
79518
|
"--size": lengthValue(size),
|
|
79125
79519
|
"--color": color,
|
|
79126
|
-
"--margin":
|
|
79127
|
-
"--margin-start":
|
|
79128
|
-
"--margin-end":
|
|
79520
|
+
"--margin": spacingValue(margin),
|
|
79521
|
+
"--margin-start": spacingValue(marginStart),
|
|
79522
|
+
"--margin-end": spacingValue(marginEnd)
|
|
79129
79523
|
}),
|
|
79130
79524
|
...style
|
|
79131
79525
|
}
|
|
@@ -79146,6 +79540,10 @@ const cssVars = vars => {
|
|
|
79146
79540
|
return declared;
|
|
79147
79541
|
};
|
|
79148
79542
|
const lengthValue = value => typeof value === "number" ? `${value}px` : value;
|
|
79543
|
+
// A margin reads the spacing scale like every other margin prop ("s" →
|
|
79544
|
+
// var(--navi-s)): written raw, a word is a valid custom property and an invalid
|
|
79545
|
+
// margin, which computes to 0 without falling back to anything.
|
|
79546
|
+
const spacingValue = value => value === undefined ? undefined : stringifySpacingStyle(value, "margin");
|
|
79149
79547
|
|
|
79150
79548
|
const ListItemHeaderOrFooterResolver = props => {
|
|
79151
79549
|
const Next = useNextResolver();
|
|
@@ -79646,7 +80044,9 @@ const createListItems = () => {
|
|
|
79646
80044
|
dropItemLocator: (ownerId) => {
|
|
79647
80045
|
locatorByOwner.delete(ownerId);
|
|
79648
80046
|
},
|
|
79649
|
-
// Where the item named by that id sits, asked of whoever holds it
|
|
80047
|
+
// Where the item named by that id sits, asked of whoever holds it: a run
|
|
80048
|
+
// knows its items, drawn or not; an item declared one by one is its own
|
|
80049
|
+
// holder, and says its place when it draws.
|
|
79650
80050
|
locateItem: (id) => {
|
|
79651
80051
|
for (const locator of locatorByOwner.values()) {
|
|
79652
80052
|
const index = locator.indexOf(id);
|
|
@@ -79654,6 +80054,16 @@ const createListItems = () => {
|
|
|
79654
80054
|
return index;
|
|
79655
80055
|
}
|
|
79656
80056
|
}
|
|
80057
|
+
for (const [entryId, entry] of entryById) {
|
|
80058
|
+
if (
|
|
80059
|
+
entry.ownerId === entryId &&
|
|
80060
|
+
entry.item &&
|
|
80061
|
+
entry.place !== undefined &&
|
|
80062
|
+
entry.data.itemId === id
|
|
80063
|
+
) {
|
|
80064
|
+
return entry.place;
|
|
80065
|
+
}
|
|
80066
|
+
}
|
|
79657
80067
|
return null;
|
|
79658
80068
|
},
|
|
79659
80069
|
// The room the item at that index takes: the room it took when it was
|
|
@@ -81044,6 +81454,11 @@ const css$v = /* css */`@property --list-group-label-height {
|
|
|
81044
81454
|
overflow: clip;
|
|
81045
81455
|
}
|
|
81046
81456
|
|
|
81457
|
+
.navi_list_container[data-horizontal]:not([data-scroller], [data-overflow-visible]) > .navi_list_scroll_container > .navi_list:not([navi-box-flow="grid"]) {
|
|
81458
|
+
width: min-content;
|
|
81459
|
+
min-width: 100%;
|
|
81460
|
+
}
|
|
81461
|
+
|
|
81047
81462
|
.navi_list_container[data-horizontal] {
|
|
81048
81463
|
--list-max-height: none;
|
|
81049
81464
|
|
|
@@ -81191,6 +81606,7 @@ const css$v = /* css */`@property --list-group-label-height {
|
|
|
81191
81606
|
|
|
81192
81607
|
& .navi_list_item_group_list {
|
|
81193
81608
|
--list-group-label-height: inherit;
|
|
81609
|
+
gap: var(--x-list-gap, 0px);
|
|
81194
81610
|
flex-direction: column;
|
|
81195
81611
|
width: 100%;
|
|
81196
81612
|
margin: 0;
|
|
@@ -88806,6 +89222,16 @@ const PickerChip = ({
|
|
|
88806
89222
|
children,
|
|
88807
89223
|
...rest
|
|
88808
89224
|
}) => {
|
|
89225
|
+
// Its picker's own state, not the zone's: on the façade the network policy's
|
|
89226
|
+
// hold is not handed down (see faceReadOnly in picker.jsx), and the cross is
|
|
89227
|
+
// what changes the picker.
|
|
89228
|
+
const pickerContext = usePickerContext();
|
|
89229
|
+
if (commandFor === undefined && pickerContext?.readOnly) {
|
|
89230
|
+
return jsx(Badge, {
|
|
89231
|
+
...rest,
|
|
89232
|
+
children: children
|
|
89233
|
+
});
|
|
89234
|
+
}
|
|
88809
89235
|
return jsxs(Badge, {
|
|
88810
89236
|
...rest,
|
|
88811
89237
|
children: [children, jsx(Badge.Button, {
|
|
@@ -89127,7 +89553,17 @@ const PickerFileUI = /*#__PURE__*/asPickerOwnUI(() => {
|
|
|
89127
89553
|
});
|
|
89128
89554
|
|
|
89129
89555
|
installImportMetaCssBuild(import.meta);
|
|
89130
|
-
const css$r = /* css */`@
|
|
89556
|
+
const css$r = /* css */`@property --navi-picker-container-font-size {
|
|
89557
|
+
syntax: "<length>";
|
|
89558
|
+
inherits: true;
|
|
89559
|
+
initial-value: 16px;
|
|
89560
|
+
}
|
|
89561
|
+
|
|
89562
|
+
@layer navi {
|
|
89563
|
+
:where(:has( > .navi_picker)) {
|
|
89564
|
+
--navi-picker-container-font-size: 1em;
|
|
89565
|
+
}
|
|
89566
|
+
|
|
89131
89567
|
.navi_picker {
|
|
89132
89568
|
--picker-border-radius: var(--navi-control-border-radius);
|
|
89133
89569
|
--picker-border-width: var(--navi-control-border-width);
|
|
@@ -89138,6 +89574,7 @@ const css$r = /* css */`@layer navi {
|
|
|
89138
89574
|
--picker-padding-x-default: var(--navi-picker-padding-x-default);
|
|
89139
89575
|
--picker-padding-y-default: var(--navi-picker-padding-y-default);
|
|
89140
89576
|
--picker-font-size: var(--navi-control-font-size);
|
|
89577
|
+
--picker-font-weight: initial;
|
|
89141
89578
|
--picker-font-family: var(--navi-control-font-family, inherit);
|
|
89142
89579
|
--picker-loader-color: var(--navi-loader-color);
|
|
89143
89580
|
--picker-cta-background-color: var(--navi-accent-color);
|
|
@@ -89364,6 +89801,7 @@ const css$r = /* css */`@layer navi {
|
|
|
89364
89801
|
padding-bottom: var(--x-picker-padding-bottom);
|
|
89365
89802
|
align-items: var(--x-picker-align-y);
|
|
89366
89803
|
justify-content: var(--x-picker-align-x);
|
|
89804
|
+
font-weight: var(--picker-font-weight, inherit);
|
|
89367
89805
|
background-color: var(--x-picker-background-color);
|
|
89368
89806
|
border-width: var(--picker-border-width);
|
|
89369
89807
|
border-style: solid;
|
|
@@ -89398,7 +89836,7 @@ const css$r = /* css */`@layer navi {
|
|
|
89398
89836
|
flex-grow: 1;
|
|
89399
89837
|
display: inline-block;
|
|
89400
89838
|
|
|
89401
|
-
&[data-picker-facade] {
|
|
89839
|
+
&[data-picker-facade="drawing"] {
|
|
89402
89840
|
line-height: var(--navi-line-height);
|
|
89403
89841
|
}
|
|
89404
89842
|
|
|
@@ -89542,9 +89980,8 @@ const css$r = /* css */`@layer navi {
|
|
|
89542
89980
|
--x-corner-top-right-radius: initial;
|
|
89543
89981
|
--x-corner-bottom-right-radius: initial;
|
|
89544
89982
|
--x-corner-bottom-left-radius: initial;
|
|
89545
|
-
font-
|
|
89983
|
+
font-size: var(--navi-picker-container-font-size);
|
|
89546
89984
|
text-align: initial;
|
|
89547
|
-
font-size: 1rem;
|
|
89548
89985
|
display: contents;
|
|
89549
89986
|
}
|
|
89550
89987
|
|
|
@@ -89566,6 +90003,10 @@ const css$r = /* css */`@layer navi {
|
|
|
89566
90003
|
--x-picker-cursor: pointer;
|
|
89567
90004
|
}
|
|
89568
90005
|
|
|
90006
|
+
&[data-readonly]:has( > .navi_picker_box > .navi_picker_input[data-readonly-reason="network-policy"]) > .navi_picker_box > .navi_picker_value[data-picker-facade="drawing"] {
|
|
90007
|
+
color: var(--picker-color);
|
|
90008
|
+
}
|
|
90009
|
+
|
|
89569
90010
|
&[data-focus-within]:has( > .navi_picker_box > .navi_picker_input[data-focus-visible]), &[data-focus-visible] {
|
|
89570
90011
|
--x-picker-border-color: transparent;
|
|
89571
90012
|
|
|
@@ -89791,6 +90232,12 @@ const PickerButton = props => {
|
|
|
89791
90232
|
// with it: what the popup changes is what the picker would send.
|
|
89792
90233
|
const readOnlyFromAbove = useContext(ReadOnlyContext);
|
|
89793
90234
|
const [readOnlyResolved, readOnlyMessageResolved] = readOnlyHandedDown(uiStateController, readOnly || readOnlyFromAbove);
|
|
90235
|
+
// What a caller draws on the face (its `ui`, its right slot) is read-only
|
|
90236
|
+
// with the picker, and not held with it: the network policy holds what the
|
|
90237
|
+
// picker would send, which its popup changes. A card used as the trigger
|
|
90238
|
+
// keeps its links and buttons, each held for what it sends itself.
|
|
90239
|
+
const faceReadOnly = readOnly || readOnlyFromAbove;
|
|
90240
|
+
const faceReadOnlyMessage = faceReadOnly ? props.readOnlyMessage ?? uiStateController.readOnlyMessageFromAbove : undefined;
|
|
89794
90241
|
// Read off the controller rather than worked out again: what makes a
|
|
89795
90242
|
// read-only picker open is settled once, where the gate reads it (see
|
|
89796
90243
|
// createControlInfo's readOnlyOpens). Needed here for the cursor.
|
|
@@ -89812,6 +90259,9 @@ const PickerButton = props => {
|
|
|
89812
90259
|
maxLines,
|
|
89813
90260
|
id: inputProps.id,
|
|
89814
90261
|
interactive,
|
|
90262
|
+
// Read-only, or held by the network policy — never busy: an action in
|
|
90263
|
+
// flight is not a value nobody may change (see the ReadOnlyProvider below).
|
|
90264
|
+
readOnly: Boolean(readOnlyResolved),
|
|
89815
90265
|
loading,
|
|
89816
90266
|
clearConfirm,
|
|
89817
90267
|
requestValue
|
|
@@ -90022,7 +90472,7 @@ const PickerButton = props => {
|
|
|
90022
90472
|
// the picker draws itself, so each is written on its own line
|
|
90023
90473
|
// (see .navi_picker_value in the CSS above).
|
|
90024
90474
|
,
|
|
90025
|
-
"data-picker-facade": ui === undefined ? undefined : ""
|
|
90475
|
+
"data-picker-facade": ui === undefined ? undefined : typeof ui === "string" || typeof ui === "number" ? "text" : "drawing"
|
|
90026
90476
|
// A placeholder is the picker saying "nothing here yet" about
|
|
90027
90477
|
// the value navi draws — the default rendering, or the one a
|
|
90028
90478
|
// typed picker installs for itself. A button's label is not
|
|
@@ -90034,6 +90484,8 @@ const PickerButton = props => {
|
|
|
90034
90484
|
"navi-placeholder": (ui === undefined || pickerUIIsNaviOwn(ui)) && !drawnAsButton && variant !== "text" && uiStateHoldsNothing(value) ? "" : undefined,
|
|
90035
90485
|
maxLines: maxLines,
|
|
90036
90486
|
children: jsx(PickerOwnContent, {
|
|
90487
|
+
readOnly: faceReadOnly,
|
|
90488
|
+
readOnlyMessage: faceReadOnlyMessage,
|
|
90037
90489
|
children: jsx(MaxLinesContext.Provider, {
|
|
90038
90490
|
value: maxLines,
|
|
90039
90491
|
children: ui === undefined ? isIcon ?
|
|
@@ -90061,6 +90513,8 @@ const PickerButton = props => {
|
|
|
90061
90513
|
}), hasRightSlot ? jsx("span", {
|
|
90062
90514
|
className: "navi_picker_right_slot",
|
|
90063
90515
|
children: jsx(PickerOwnContent, {
|
|
90516
|
+
readOnly: faceReadOnly,
|
|
90517
|
+
readOnlyMessage: faceReadOnlyMessage,
|
|
90064
90518
|
children: clearable && pickerHasSomethingToClear(pickerContext) ? jsx(PickerClear, {
|
|
90065
90519
|
size: rightSlotIconSize
|
|
90066
90520
|
}) : rightSlot === undefined ?
|
|
@@ -90221,12 +90675,18 @@ const warnOnClearOutsidePicker = () => {
|
|
|
90221
90675
|
// is empty, a chip the moment its value is taken out — takes the picker's own
|
|
90222
90676
|
// entry with it, leaving the picker looking for a controller that is gone.
|
|
90223
90677
|
const PickerOwnContent = ({
|
|
90678
|
+
readOnly,
|
|
90679
|
+
readOnlyMessage,
|
|
90224
90680
|
children
|
|
90225
90681
|
}) => jsx(ControlIdContext.Provider, {
|
|
90226
90682
|
value: undefined,
|
|
90227
90683
|
children: jsx(ControlNameContext.Provider, {
|
|
90228
90684
|
value: undefined,
|
|
90229
|
-
children:
|
|
90685
|
+
children: jsx(ReadOnlyProvider, {
|
|
90686
|
+
readOnly: readOnly,
|
|
90687
|
+
readOnlyMessage: readOnlyMessage,
|
|
90688
|
+
children: children
|
|
90689
|
+
})
|
|
90230
90690
|
})
|
|
90231
90691
|
});
|
|
90232
90692
|
|
|
@@ -90362,6 +90822,9 @@ const PickerInputPseudoClasses = [":focus", ":focus-visible", ":read-only", ":di
|
|
|
90362
90822
|
// picker_custom.jsx: a variable on the root inherits into everything the popup
|
|
90363
90823
|
// holds, and the pickers in there would read it as their own.
|
|
90364
90824
|
const PickerStyleCSSVars = {
|
|
90825
|
+
// Onto the trigger's frame rather than the root, which holds the popup too
|
|
90826
|
+
// (see --picker-font-weight).
|
|
90827
|
+
"fontWeight": "--picker-font-weight",
|
|
90365
90828
|
"outlineWidth": "--picker-outline-width",
|
|
90366
90829
|
"borderWidth": "--picker-border-width",
|
|
90367
90830
|
"borderRadius": "--picker-border-radius",
|
|
@@ -90595,7 +91058,7 @@ const PickerUI = /*#__PURE__*/Object.assign(PickerDefaultUI, {
|
|
|
90595
91058
|
* openOn?: "press" | "longpress" | "contextmenu" | string | string[],
|
|
90596
91059
|
* animation?: boolean | "auto" | "fading" | "scaling" | "sliding" | "lifting" | `slide-from-${string}` | { open: boolean | "auto" | "fading" | "scaling" | "sliding" | `slide-from-${string}`, close: "lifting" },
|
|
90597
91060
|
* lift?: "box" | "scene",
|
|
90598
|
-
* liftAnchor?: Element | { current: Element } | string,
|
|
91061
|
+
* liftAnchor?: Element | { current: Element } | string | ((popupValue: any) => Element | { current: Element } | string),
|
|
90599
91062
|
* animationDuration?: string,
|
|
90600
91063
|
* calloutStatus?: "info" | "warning" | "error" | "success" | "none",
|
|
90601
91064
|
* calloutIcon?: boolean,
|
|
@@ -90670,7 +91133,9 @@ const PickerUI = /*#__PURE__*/Object.assign(PickerDefaultUI, {
|
|
|
90670
91133
|
* follows the theme) — the trigger's own `backgroundColor` is not it, so a
|
|
90671
91134
|
* variant that paints the trigger transparent leaves the popup a real sheet.
|
|
90672
91135
|
* @param {number|string} [popupBorderRadius] The popup's corners. Left out they
|
|
90673
|
-
* echo the trigger's `borderRadius
|
|
91136
|
+
* echo the trigger's `borderRadius` when it is a length of corners; a shape
|
|
91137
|
+
* (a percentage, a pill's 999px) leaves the popup on the corners every popup
|
|
91138
|
+
* has.
|
|
90674
91139
|
* @param {string} [popupBoxShadow] The popup's shadow, popover or dialog. Left
|
|
90675
91140
|
* out it is the one every navi popup casts. `"none"` for a popup that is
|
|
90676
91141
|
* not a sheet — a card lifted out of a page draws its own edges, and the
|
|
@@ -91042,11 +91507,12 @@ const PickerUI = /*#__PURE__*/Object.assign(PickerDefaultUI, {
|
|
|
91042
91507
|
* that opens precisely to get bigger. It brings an opaque, blurred backdrop
|
|
91043
91508
|
* with it (`--navi-backdrop-lift-*`); `backdropVariant="discrete"` asks for
|
|
91044
91509
|
* the light wash back.
|
|
91045
|
-
* @param {Element|{current: Element}|string} [liftAnchor] Dialog mode,
|
|
91510
|
+
* @param {Element|{current: Element}|string|((popupValue: any) => Element|{current: Element}|string)} [liftAnchor] Dialog mode,
|
|
91046
91511
|
* Dialog's own: where a lifting close lands when that is not the trigger
|
|
91047
91512
|
* (`animation="lifting"`, or `animation={{ open, close: "lifting" }}` for a
|
|
91048
91513
|
* popup that opens the plain way and only lands on close),
|
|
91049
|
-
* read once the close is made (after `onClose`).
|
|
91514
|
+
* read once the close is made (after `onClose`). A function is called with
|
|
91515
|
+
* what the popup was open on (see `usePopupValue`).
|
|
91050
91516
|
* @param {"box"|"scene"} [lift="box"] Dialog's own, under `animation="lifting"`:
|
|
91051
91517
|
* `"box"` for a card that extends (its top stays, the box uncovers the rest),
|
|
91052
91518
|
* `"scene"` for a thumbnail that is a band cut from the middle of the bigger
|
|
@@ -101086,9 +101552,11 @@ const KeyboardShortcutAriaElement = ({
|
|
|
101086
101552
|
* <Button action={copy}>{copied ? i18n("Copied") : i18n("Copy link")}</Button>
|
|
101087
101553
|
* ```
|
|
101088
101554
|
*
|
|
101089
|
-
* `copy` rejects when the browser refuses the write
|
|
101090
|
-
*
|
|
101091
|
-
*
|
|
101555
|
+
* `copy` rejects when the browser refuses the write (permission blocked, page
|
|
101556
|
+
* not in front, no clipboard outside a secure context), with navi's
|
|
101557
|
+
* `"button.copy_refused"` sentence — the browser's own error as its `cause` —
|
|
101558
|
+
* so an `action` running it says why on the control in the page's language. A
|
|
101559
|
+
* press while `copied` holds starts the moment again.
|
|
101092
101560
|
*
|
|
101093
101561
|
* @param {string | (() => string | Promise<string>)} text What is copied. A
|
|
101094
101562
|
* function is called at the press: for a text only built then (a report, a
|
|
@@ -101128,6 +101596,14 @@ const useCopyToClipboard = (text, { duration = 1500 } = {}) => {
|
|
|
101128
101596
|
|
|
101129
101597
|
const writeToClipboard = async (text) => {
|
|
101130
101598
|
const value = typeof text === "function" ? text() : text;
|
|
101599
|
+
try {
|
|
101600
|
+
await writeValueToClipboard(value);
|
|
101601
|
+
} catch (error) {
|
|
101602
|
+
// The browser's words are in its own language, and name its API.
|
|
101603
|
+
throw new Error(buttonI18n("button.copy_refused"), { cause: error });
|
|
101604
|
+
}
|
|
101605
|
+
};
|
|
101606
|
+
const writeValueToClipboard = async (value) => {
|
|
101131
101607
|
if (typeof value === "string") {
|
|
101132
101608
|
await window.navigator.clipboard.writeText(value);
|
|
101133
101609
|
return;
|
|
@@ -104132,5 +104608,5 @@ const UserSvg = () => jsx("svg", {
|
|
|
104132
104608
|
})
|
|
104133
104609
|
});
|
|
104134
104610
|
|
|
104135
|
-
export { ActionRenderer, ActiveKeyboardShortcuts, Address, Badge, BadgeCount, BadgeList, Binder, Box, Button, ButtonCopyToClipboard, CalloutStatusIcon, Caption, CardLayout, CheckSvg, CheckboxGroup, CloseSvg, Code, Col, Colgroup, Color, ConstructionSvg, ControlGroup, ControlSwap, DaySpin, Details, Dialog, Editable, ErrorBoundary, ErrorBoundaryContext, ExclamationSvg, Expandable, EyeClosedSvg, EyeSvg, Field, FixedBar, Form, Group, Head, HeartSvg, HomeSvg, Icon, Image, InfoSvg, Input, InputDuration, Interpolate, Label, Link, LinkAnchorSvg, LinkBlankTargetSvg, LinkCurrentSvg, List, ListItem, ListItemGroup, ListItems, Loading, LoadingDotsSvg, LoadingIndicator, LoadingIndicatorFluid, LoadingOutline, MessageBox, Meter, Nav, NaviDebug, NetworkPolicyError, NumberSpin, Paragraph, Picker, Popover, Popup, PopupGroup, Quantity, RadioGroup, Route, RouteTransitionArea, RouteTravel, RowNumberCol, RowNumberTableCell, SVGMaskOverlay, SearchSvg, Select, SelectableInput, SelectionContext, Separator, SettingsSvg, SidePanel, Slide, SlideContainer, Spin, SpinGroup, SplitButton, StarSvg, Step, StepList, SummaryMarker, Svg, Table, TableCell, Tbody, Text, TextBox, Textarea, TextareaCharCount, Thead, Time, TimeRange, TimeRangeSpin, TimeRangeWheel, TimeSpin, TimeWheel, Title, Tr, UITransition, Unit, UserSvg, ViewportLayout, Wheel, WheelGroup, WheelItem, actionRunEffect, activeRouteActionsSignal, activeRouteReadsSignal, anyMatchingRouteSignal, applySearch, arraySignalMembership, canNavBackSignal, canNavForwardSignal, coarsePointerSignal, compareTwoJsValues, constraintFromValidityRule, createAction, createAvailableConstraint, createRequestCanceller, createSearch, createSelectionKeyboardShortcuts, createSlot, defineInteractionDetector, defineRouteDefaultTransition, defineRouteTransition, detectHorizontalOverflow, dispatchRequestSetUIState, enableDebugActions, enableDebugOnDocumentLoading, enableVirtualKeyboardOverlay, ensureDocumentStartViewTransition, errorIsDisplayed, filterTableSelection, getNowHours, getNowHoursRoundedToStep, isCellSelected, isColumnSelected, isNetworkPolicyError, isPressOnControl, isRowSelected, isScrolling, isToday, keepPageOnScreen, languagesSignal, localStorageSignal, markAsOutsideTextFlow, markErrorAsDisplayedBy, moveArrayItemByIndex, moveFocusTo, navBack, navForward, navIntegratedVia, navTo, naviI18n, openCallout, preloadUrl, rawUrlPart, registerGlobalConstraint, reload, rerunActions, resource, route, routeAction, routeFallback, scrollActivitySignal, setBaseUrl, setNetworkPolicy, setPreferredLanguage, setSupportedLanguages, setUrlTargetOptions, setupRoutes, smallTouchScreenSignal, stateSignal, stopLoad, stringifyTableSelectionValue, swapArrayItemByIndex, syncOwnedResourceToSignals, syncResourceToSignals, todaySignal, triggerNaviCommand, updateActions, useActionStatus, useArraySignalMembership, useAsyncData, useCalloutElement, useCalloutRequestClose, useCanNavBack, useCanNavForward, useCancelPrevious, useCellGridFromRows, useConstraintValidityState, useCopyToClipboard, useDependenciesDiff, useDisplayedLayoutEffect, useDocumentResource, useDocumentState, useDocumentUrl, useEditionController, useFocusGroup, useHoldScrollRestoration, useInputGroup, useKeyboardShortcuts, useListItemState, useNavState, useNetworkPolicyReason, useOrderedColumns, usePickerState, usePopupMode, useRouteStatus, useSearchText, useSelectableElement, useSelectionController, useSignalSync, useSlideContainer, useSlideValue, useStateArray, useTitleLevel, useTransitionCover, useUrlSearchParam, useUrlTargetId, valueInLocalStorage, windowWidthSignal };
|
|
104611
|
+
export { ActionRenderer, ActiveKeyboardShortcuts, Address, Badge, BadgeCount, BadgeList, Binder, Box, Button, ButtonCopyToClipboard, CalloutStatusIcon, Caption, CardLayout, CheckSvg, CheckboxGroup, CloseSvg, Code, Col, Colgroup, Color, ConstructionSvg, ControlGroup, ControlSwap, DaySpin, Details, Dialog, Editable, ErrorBoundary, ErrorBoundaryContext, ExclamationSvg, Expandable, EyeClosedSvg, EyeSvg, Field, FixedBar, Form, Group, Head, HeartSvg, HomeSvg, Icon, Image, InfoSvg, Input, InputDuration, Interpolate, Label, Link, LinkAnchorSvg, LinkBlankTargetSvg, LinkCurrentSvg, List, ListItem, ListItemGroup, ListItems, Loading, LoadingDotsSvg, LoadingIndicator, LoadingIndicatorFluid, LoadingOutline, MessageBox, Meter, Nav, NaviDebug, NetworkPolicyError, NumberSpin, Paragraph, Picker, Popover, Popup, PopupGroup, Quantity, RadioGroup, Route, RouteTransitionArea, RouteTravel, RowNumberCol, RowNumberTableCell, SVGMaskOverlay, SearchSvg, Select, SelectableInput, SelectionContext, Separator, SettingsSvg, SidePanel, Slide, SlideContainer, Spin, SpinGroup, SplitButton, StarSvg, Step, StepList, SummaryMarker, Svg, Table, TableCell, Tbody, Text, TextBox, Textarea, TextareaCharCount, Thead, Time, TimeRange, TimeRangeSpin, TimeRangeWheel, TimeSpin, TimeWheel, Title, Tr, UITransition, Unit, UserSvg, ViewportLayout, Wheel, WheelGroup, WheelItem, actionRunEffect, activeRouteActionsSignal, activeRouteReadsSignal, anyMatchingRouteSignal, applySearch, arraySignalMembership, canNavBackSignal, canNavForwardSignal, coarsePointerSignal, compareTwoJsValues, constraintFromValidityRule, createAction, createAvailableConstraint, createRequestCanceller, createSearch, createSelectionKeyboardShortcuts, createSlot, defineInteractionDetector, defineRouteDefaultTransition, defineRouteTransition, detectHorizontalOverflow, dispatchRequestSetUIState, enableDebugActions, enableDebugOnDocumentLoading, enableVirtualKeyboardOverlay, ensureDocumentStartViewTransition, errorIsDisplayed, filterTableSelection, getNowHours, getNowHoursRoundedToStep, isCellSelected, isColumnSelected, isNetworkPolicyError, isPressOnControl, isRowSelected, isScrolling, isToday, keepPageOnScreen, languagesSignal, localStorageSignal, markAsOutsideTextFlow, markErrorAsDisplayedBy, moveArrayItemByIndex, moveFocusTo, navBack, navForward, navIntegratedVia, navTo, naviI18n, openCallout, preloadUrl, rawUrlPart, registerGlobalConstraint, reload, rerunActions, resource, route, routeAction, routeFallback, scrollActivitySignal, setBaseUrl, setNetworkPolicy, setPreferredLanguage, setSupportedLanguages, setUrlTargetOptions, setupRoutes, smallTouchScreenSignal, stateSignal, stopLoad, stringifyTableSelectionValue, swapArrayItemByIndex, syncOwnedResourceToSignals, syncResourceToSignals, todaySignal, triggerNaviCommand, updateActions, useActionStatus, useArraySignalMembership, useAsyncData, useCalloutElement, useCalloutRequestClose, useCanNavBack, useCanNavForward, useCancelPrevious, useCellGridFromRows, useConstraintValidityState, useCopyToClipboard, useDependenciesDiff, useDisplayedLayoutEffect, useDocumentResource, useDocumentState, useDocumentUrl, useEditionController, useFocusGroup, useHoldScrollRestoration, useInputGroup, useKeyboardShortcuts, useListItemState, useNavState, useNetworkPolicyReason, useOrderedColumns, usePickerState, usePopupMode, usePopupValue, useRouteStatus, useSearchText, useSelectableElement, useSelectionController, useSignalSync, useSlideContainer, useSlideValue, useStateArray, useTitleLevel, useTransitionCover, useUrlSearchParam, useUrlTargetId, valueInLocalStorage, windowWidthSignal };
|
|
104136
104612
|
//# sourceMappingURL=jsenv_navi.js.map
|