@jsenv/navi 0.29.146 → 0.29.148
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 +191 -124
- package/dist/jsenv_navi.js.map +26 -17
- package/docs/AI_INSTRUCTIONS.md +12 -7
- package/docs/actions.md +4 -0
- package/docs/autofocus.md +68 -2
- package/docs/control_value.md +32 -0
- package/docs/popup_open.md +26 -0
- package/docs/state_binding.md +34 -0
- package/docs/testid.md +5 -0
- package/package.json +1 -1
package/dist/jsenv_navi.js
CHANGED
|
@@ -17086,7 +17086,7 @@ const useActionAsyncData = (action, {
|
|
|
17086
17086
|
}) => {
|
|
17087
17087
|
const loadingRef = useContext(LoadingContext);
|
|
17088
17088
|
if (!loadingRef) {
|
|
17089
|
-
throw new Error(
|
|
17089
|
+
throw new Error(`Missing <Loading>: useAsyncData delegates the wait, so it needs a <Loading> boundary above it — or "loading: true" to draw that wait here.`);
|
|
17090
17090
|
}
|
|
17091
17091
|
useOnLoad(action, onLoad);
|
|
17092
17092
|
|
|
@@ -31192,7 +31192,9 @@ const createDisplayedEvent = (ancestor, becauseAncestorOpened) => {
|
|
|
31192
31192
|
* 5. The element focused before the container opened
|
|
31193
31193
|
*
|
|
31194
31194
|
* [navi-autofocus="restore"] appears in step 1 only: it never claims focus on
|
|
31195
|
-
* a fresh open, it only gets it back.
|
|
31195
|
+
* a fresh open, it only gets it back. Unless a caller says the arrival is not a
|
|
31196
|
+
* fresh open but the answer to a press aimed at that very control — see
|
|
31197
|
+
* findFocusTarget's `restoreMayClaim`.
|
|
31196
31198
|
*
|
|
31197
31199
|
* A ladder that comes back empty — a container holding nothing focusable yet —
|
|
31198
31200
|
* places no focus, and says so on the container ([navi-autofocus-unplaced]),
|
|
@@ -31340,9 +31342,19 @@ const markAutofocusRestoreOnClose = (
|
|
|
31340
31342
|
* it, so landing there scrolls whatever comes before it out of sight.
|
|
31341
31343
|
* transferFocus turns this on by itself wherever the keyboard is a virtual
|
|
31342
31344
|
* one — see the reasoning there.
|
|
31345
|
+
* @param {boolean} [options.restoreMayClaim]
|
|
31346
|
+
* Lets `navi-autofocus="restore"` claim the focus like a plain `autoFocus`.
|
|
31347
|
+
* Its "never on a fresh open" is about a surface APPEARING — a sheet whose
|
|
31348
|
+
* field must not raise a phone's keyboard by opening. A press aimed at the
|
|
31349
|
+
* very control being handed the focus is not that: it IS the ask, and
|
|
31350
|
+
* refusing it leaves the focus on the button that was pressed. Only
|
|
31351
|
+
* "restore" is freed; "last-resort" still waits its turn.
|
|
31343
31352
|
* @returns {{target: HTMLElement, reason: string}|undefined}
|
|
31344
31353
|
*/
|
|
31345
|
-
const findFocusTarget = (
|
|
31354
|
+
const findFocusTarget = (
|
|
31355
|
+
containerEl,
|
|
31356
|
+
{ skipFirstFocusable, restoreMayClaim } = {},
|
|
31357
|
+
) => {
|
|
31346
31358
|
// Not while there is anything else: what takes the focus only for want of
|
|
31347
31359
|
// anything better ("last-resort") and what only takes it back ("restore").
|
|
31348
31360
|
// Neither is dropped, both are simply tried later — step 3 below for the
|
|
@@ -31359,8 +31371,15 @@ const findFocusTarget = (containerEl, { skipFirstFocusable } = {}) => {
|
|
|
31359
31371
|
const isHiddenFromAssistiveTech = (element) =>
|
|
31360
31372
|
Boolean(element.closest?.(`[aria-hidden="true"]`));
|
|
31361
31373
|
|
|
31362
|
-
const skip = (element) =>
|
|
31363
|
-
|
|
31374
|
+
const skip = (element) => {
|
|
31375
|
+
if (isHiddenFromAssistiveTech(element)) {
|
|
31376
|
+
return true;
|
|
31377
|
+
}
|
|
31378
|
+
if (restoreMayClaim) {
|
|
31379
|
+
return element.getAttribute("navi-autofocus") === "last-resort";
|
|
31380
|
+
}
|
|
31381
|
+
return isRestorableAutofocus(element);
|
|
31382
|
+
};
|
|
31364
31383
|
|
|
31365
31384
|
// Every mark, not just the first: a mark is only worth stopping at if it
|
|
31366
31385
|
// leads somewhere focusable. One inside a screen waiting its turn (an inert
|
|
@@ -31606,8 +31625,44 @@ const retryWhenPlaceable = (
|
|
|
31606
31625
|
};
|
|
31607
31626
|
};
|
|
31608
31627
|
|
|
31628
|
+
/**
|
|
31629
|
+
* Focuses `element` the way navi focuses anything: without the browser's
|
|
31630
|
+
* scroll-into-view, and showing a ring only when the user is on the keyboard.
|
|
31631
|
+
*
|
|
31632
|
+
* Both are decisions, not details. The scroll reads geometry a layout effect
|
|
31633
|
+
* may still be deciding. And whether a ring shows belongs to the modality of
|
|
31634
|
+
* what asked for this — a press with a finger or a mouse must not leave an
|
|
31635
|
+
* outline nobody asked for, a movement asked for with a key must — never to
|
|
31636
|
+
* the fact that the call came from code, which is all the browser can see. An
|
|
31637
|
+
* editable target outranks the modality: someone about to type has to see
|
|
31638
|
+
* where.
|
|
31639
|
+
*
|
|
31640
|
+
* So a bare `element.focus()` is the thing to avoid, in navi and in an app
|
|
31641
|
+
* using it: it answers "who" and leaves "is this visible" to the browser.
|
|
31642
|
+
*
|
|
31643
|
+
* @param {HTMLElement} element
|
|
31644
|
+
* @param {object} [options]
|
|
31645
|
+
* @param {boolean} [options.focusVisible] Decides the ring instead of the
|
|
31646
|
+
* modality — for a caller that knows better than the last interaction does
|
|
31647
|
+
* (a transfer speaking for the gesture that opened a container, say).
|
|
31648
|
+
* @param {boolean} [options.preventScroll=true] Pass false to let the browser
|
|
31649
|
+
* scroll the element into view.
|
|
31650
|
+
*/
|
|
31651
|
+
const moveFocusTo = (
|
|
31652
|
+
element,
|
|
31653
|
+
{ focusVisible, preventScroll = true } = {},
|
|
31654
|
+
) => {
|
|
31655
|
+
element.focus({
|
|
31656
|
+
preventScroll,
|
|
31657
|
+
focusVisible:
|
|
31658
|
+
focusVisible === undefined
|
|
31659
|
+
? isKeyboardModality() || isEditableTarget(element)
|
|
31660
|
+
: focusVisible,
|
|
31661
|
+
});
|
|
31662
|
+
};
|
|
31663
|
+
|
|
31609
31664
|
const focusTransferTarget = (target, focusVisible) => {
|
|
31610
|
-
target
|
|
31665
|
+
moveFocusTo(target, { focusVisible });
|
|
31611
31666
|
if (target.hasAttribute("navi-autofocus-select")) {
|
|
31612
31667
|
target.select();
|
|
31613
31668
|
// Keep the beginning of the text visible instead of scrolling to the end
|
|
@@ -44562,40 +44617,43 @@ installImportMetaCssBuild(import.meta);/**
|
|
|
44562
44617
|
* a switch that moves when you flip it: the finger that opened the search has
|
|
44563
44618
|
* to travel to close it again. Out here, the same pixel does both.
|
|
44564
44619
|
*
|
|
44565
|
-
* Nothing is unmounted. Two elements that never
|
|
44566
|
-
* interpolate between, so both
|
|
44567
|
-
*
|
|
44568
|
-
*
|
|
44569
|
-
*
|
|
44570
|
-
*
|
|
44571
|
-
*
|
|
44572
|
-
*
|
|
44573
|
-
*
|
|
44574
|
-
*
|
|
44575
|
-
*
|
|
44576
|
-
*
|
|
44577
|
-
*
|
|
44578
|
-
*
|
|
44579
|
-
*
|
|
44580
|
-
*
|
|
44581
|
-
*
|
|
44582
|
-
*
|
|
44583
|
-
*
|
|
44584
|
-
* defaulting to the height of a navi control at its default padding; a row of
|
|
44585
|
-
* roomier controls says so once, there.
|
|
44620
|
+
* Nothing is unmounted, and nothing is resized. Two elements that never
|
|
44621
|
+
* coexist have nothing to interpolate between, so both controls stay mounted
|
|
44622
|
+
* and laid out at all times, side by side on a track twice the width of the
|
|
44623
|
+
* middle; the track slides, and one control pushes the other out under the cap
|
|
44624
|
+
* it belongs to. A share of the middle traded between two shrinking boxes
|
|
44625
|
+
* gives a wipe instead — each control squeezed live, text rewrapping under the
|
|
44626
|
+
* movement, and nothing that reads as one thing arriving over another.
|
|
44627
|
+
*
|
|
44628
|
+
* The control without the floor is off the middle rather than gone: `inert`,
|
|
44629
|
+
* so no finger and no Tab reaches it, and holding what was typed in it for the
|
|
44630
|
+
* round trip back.
|
|
44631
|
+
*
|
|
44632
|
+
* The row has ONE height, and everything in it is that tall: the caps are
|
|
44633
|
+
* squares of it, the controls are given it. Nothing is measured — a height
|
|
44634
|
+
* read off the controls could only come back through a resize observer, and a
|
|
44635
|
+
* cap made square with `aspect-ratio` never reads it anyway (on a flex item
|
|
44636
|
+
* stretched to its line, the main size is resolved from content first). It is
|
|
44637
|
+
* a length, `--navi-control-swap-size`, and it is the only thing to say to
|
|
44638
|
+
* make the row thinner or thicker.
|
|
44586
44639
|
*/
|
|
44587
44640
|
const css$O = /* css */`.navi_control_swap {
|
|
44588
|
-
|
|
44589
|
-
|
|
44641
|
+
font-size: var(--navi-control-font-size);
|
|
44642
|
+
--x-control-swap-size: var(--navi-control-swap-size, calc(var(--navi-control-line-height) + 2 * var(--navi-s) + 2 *
|
|
44590
44643
|
var(--navi-control-border-width)));
|
|
44644
|
+
--x-control-swap-gap: var(--navi-control-swap-gap, var(--navi-xs));
|
|
44591
44645
|
height: var(--x-control-swap-size);
|
|
44592
44646
|
align-items: stretch;
|
|
44647
|
+
gap: var(--x-control-swap-gap);
|
|
44593
44648
|
|
|
44594
44649
|
& > .navi_control_swap_cap {
|
|
44595
|
-
|
|
44650
|
+
--button-background-color: var(--navi-surface-color);
|
|
44651
|
+
aspect-ratio: 1;
|
|
44652
|
+
flex: none;
|
|
44596
44653
|
justify-content: center;
|
|
44597
|
-
align-self: stretch;
|
|
44598
44654
|
align-items: center;
|
|
44655
|
+
min-width: 0;
|
|
44656
|
+
height: 100%;
|
|
44599
44657
|
position: relative;
|
|
44600
44658
|
|
|
44601
44659
|
& .navi_control_swap_badge {
|
|
@@ -44612,51 +44670,43 @@ const css$O = /* css */`.navi_control_swap {
|
|
|
44612
44670
|
}
|
|
44613
44671
|
|
|
44614
44672
|
& > .navi_control_swap_stage {
|
|
44615
|
-
|
|
44673
|
+
overflow-clip-margin: var(--navi-focus-outline-width);
|
|
44616
44674
|
flex: 1 1 0;
|
|
44617
44675
|
min-width: 0;
|
|
44618
44676
|
display: flex;
|
|
44677
|
+
overflow: clip;
|
|
44619
44678
|
container-type: inline-size;
|
|
44679
|
+
}
|
|
44680
|
+
|
|
44681
|
+
& > .navi_control_swap_stage > .navi_control_swap_track {
|
|
44682
|
+
gap: var(--x-control-swap-gap);
|
|
44683
|
+
flex-direction: row;
|
|
44684
|
+
flex: none;
|
|
44685
|
+
height: 100%;
|
|
44686
|
+
display: flex;
|
|
44620
44687
|
|
|
44621
44688
|
& > .navi_control_swap_slot {
|
|
44622
|
-
flex:
|
|
44623
|
-
min-width: 0;
|
|
44689
|
+
flex: 0 0 100cqw;
|
|
44624
44690
|
display: flex;
|
|
44625
|
-
overflow: hidden;
|
|
44626
44691
|
|
|
44627
|
-
& >
|
|
44628
|
-
|
|
44629
|
-
|
|
44630
|
-
justify-content: center;
|
|
44631
|
-
width: 100cqw;
|
|
44632
|
-
display: flex;
|
|
44633
|
-
|
|
44634
|
-
& > * {
|
|
44635
|
-
width: 100%;
|
|
44636
|
-
}
|
|
44637
|
-
}
|
|
44638
|
-
|
|
44639
|
-
&[data-collapsed] {
|
|
44640
|
-
flex-grow: 0;
|
|
44641
|
-
}
|
|
44642
|
-
|
|
44643
|
-
&[data-pinned="end"] {
|
|
44644
|
-
justify-content: flex-end;
|
|
44692
|
+
& > * {
|
|
44693
|
+
width: 100%;
|
|
44694
|
+
height: 100%;
|
|
44645
44695
|
}
|
|
44646
44696
|
}
|
|
44647
44697
|
}
|
|
44648
44698
|
|
|
44649
|
-
&[data-
|
|
44650
|
-
|
|
44699
|
+
&[data-active-index="1"] > .navi_control_swap_stage > .navi_control_swap_track {
|
|
44700
|
+
transform: translateX(calc(-100cqw - var(--x-control-swap-gap)));
|
|
44651
44701
|
}
|
|
44652
44702
|
|
|
44653
|
-
&[data-animation] > .navi_control_swap_stage > .
|
|
44654
|
-
transition:
|
|
44703
|
+
&[data-animation] > .navi_control_swap_stage > .navi_control_swap_track {
|
|
44704
|
+
transition: transform var(--navi-control-swap-animation-duration, .22s)
|
|
44655
44705
|
ease;
|
|
44656
44706
|
}
|
|
44657
44707
|
|
|
44658
44708
|
@media (prefers-reduced-motion: reduce) {
|
|
44659
|
-
&[data-animation] > .navi_control_swap_stage > .
|
|
44709
|
+
&[data-animation] > .navi_control_swap_stage > .navi_control_swap_track {
|
|
44660
44710
|
transition: none;
|
|
44661
44711
|
}
|
|
44662
44712
|
}
|
|
@@ -44681,13 +44731,14 @@ const css$O = /* css */`.navi_control_swap {
|
|
|
44681
44731
|
* side's name back into it whenever a press swaps it. Excludes `value`.
|
|
44682
44732
|
* @param onChange - Called with the name of the side taking the floor, and the
|
|
44683
44733
|
* press that gave it.
|
|
44684
|
-
* @param animation - On by default: the
|
|
44685
|
-
*
|
|
44686
|
-
*
|
|
44687
|
-
*
|
|
44688
|
-
* The row is one length tall — `--navi-control-swap-size`,
|
|
44689
|
-
*
|
|
44690
|
-
*
|
|
44734
|
+
* @param animation - On by default: the track slides from one control to the
|
|
44735
|
+
* other over `--navi-control-swap-animation-duration` (0.22s). `false` puts
|
|
44736
|
+
* it there in one frame; `prefers-reduced-motion` does too.
|
|
44737
|
+
*
|
|
44738
|
+
* The row is one length tall — `--navi-control-swap-size`, a line of text
|
|
44739
|
+
* between two `s` paddings — and everything in it is that tall: the caps are
|
|
44740
|
+
* squares of it, the control holding the floor fills it. `--navi-control-swap-gap`
|
|
44741
|
+
* is the space between the boxes.
|
|
44691
44742
|
*/
|
|
44692
44743
|
const ControlSwap = props => {
|
|
44693
44744
|
import.meta.css = [css$O, "@jsenv/navi/src/control/control_swap/control_swap.jsx"];
|
|
@@ -44718,16 +44769,12 @@ const ControlSwap = props => {
|
|
|
44718
44769
|
const slotIdPrefix = useId();
|
|
44719
44770
|
const activeNameRef = useRef(activeName);
|
|
44720
44771
|
activeNameRef.current = activeSide.name;
|
|
44721
|
-
|
|
44722
|
-
// The movement is over and the slots are where they belong (see the CSS).
|
|
44723
|
-
const [settled, setSettled] = useState(true);
|
|
44724
44772
|
const swapTo = (name, event) => {
|
|
44725
44773
|
if (name === activeNameRef.current) {
|
|
44726
44774
|
return;
|
|
44727
44775
|
}
|
|
44728
44776
|
activeNameRef.current = name;
|
|
44729
44777
|
setActiveName(name);
|
|
44730
|
-
setSettled(!animation);
|
|
44731
44778
|
if (signal) {
|
|
44732
44779
|
signal.value = name;
|
|
44733
44780
|
}
|
|
@@ -44758,16 +44805,9 @@ const ControlSwap = props => {
|
|
|
44758
44805
|
useLayoutEffect(() => {
|
|
44759
44806
|
if (isFirstActiveRunRef.current) {
|
|
44760
44807
|
isFirstActiveRunRef.current = false;
|
|
44761
|
-
return
|
|
44762
|
-
}
|
|
44763
|
-
const activeSlot = slotRefs[activeIndex].current;
|
|
44764
|
-
focusWithTheFloor(activeSlot, activeSide, capRefs[activeIndex].current);
|
|
44765
|
-
if (!animation) {
|
|
44766
|
-
return undefined;
|
|
44808
|
+
return;
|
|
44767
44809
|
}
|
|
44768
|
-
|
|
44769
|
-
setSettled(true);
|
|
44770
|
-
});
|
|
44810
|
+
focusWithTheFloor(slotRefs[activeIndex].current, activeSide, capRefs[activeIndex].current);
|
|
44771
44811
|
}, [activeSide.name]);
|
|
44772
44812
|
|
|
44773
44813
|
// Both caps do the same thing, and it is the reason they sit outside the
|
|
@@ -44781,7 +44821,7 @@ const ControlSwap = props => {
|
|
|
44781
44821
|
baseClassName: "navi_control_swap",
|
|
44782
44822
|
role: "group",
|
|
44783
44823
|
"data-animation": animation ? "" : undefined,
|
|
44784
|
-
"data-
|
|
44824
|
+
"data-active-index": activeIndex,
|
|
44785
44825
|
...rest,
|
|
44786
44826
|
children: [jsx(ControlSwapCap, {
|
|
44787
44827
|
ref: capRefs[0],
|
|
@@ -44791,18 +44831,16 @@ const ControlSwap = props => {
|
|
|
44791
44831
|
onPress: swapOnPress
|
|
44792
44832
|
}), jsx("div", {
|
|
44793
44833
|
className: "navi_control_swap_stage",
|
|
44794
|
-
children:
|
|
44795
|
-
|
|
44796
|
-
|
|
44797
|
-
|
|
44798
|
-
|
|
44799
|
-
|
|
44800
|
-
|
|
44801
|
-
|
|
44802
|
-
|
|
44803
|
-
|
|
44804
|
-
})
|
|
44805
|
-
}, side.name))
|
|
44834
|
+
children: jsx("div", {
|
|
44835
|
+
className: "navi_control_swap_track",
|
|
44836
|
+
children: sides.map((side, index) => jsx("div", {
|
|
44837
|
+
ref: slotRefs[index],
|
|
44838
|
+
id: `${slotIdPrefix}_${index}`,
|
|
44839
|
+
className: "navi_control_swap_slot",
|
|
44840
|
+
inert: index === activeIndex ? undefined : true,
|
|
44841
|
+
children: side.control
|
|
44842
|
+
}, side.name))
|
|
44843
|
+
})
|
|
44806
44844
|
}), jsx(ControlSwapCap, {
|
|
44807
44845
|
ref: capRefs[1],
|
|
44808
44846
|
side: sides[1],
|
|
@@ -44815,7 +44853,8 @@ const ControlSwap = props => {
|
|
|
44815
44853
|
|
|
44816
44854
|
/**
|
|
44817
44855
|
* One of the two controls, and the cap that speaks for it. Declarative: the row
|
|
44818
|
-
* reads these and draws the caps at its ends, the controls between them.
|
|
44856
|
+
* reads these and draws the caps at its ends, the controls between them. The
|
|
44857
|
+
* props below say what the side IS; every other prop describes its cap.
|
|
44819
44858
|
*
|
|
44820
44859
|
* @type {import("ignore:preact").FunctionComponent<{
|
|
44821
44860
|
* name?: string,
|
|
@@ -44824,6 +44863,7 @@ const ControlSwap = props => {
|
|
|
44824
44863
|
* badge?: boolean | import("ignore:preact").ComponentChildren,
|
|
44825
44864
|
* autoFocus?: boolean,
|
|
44826
44865
|
* children?: import("ignore:preact").ComponentChildren,
|
|
44866
|
+
* [key: string]: any,
|
|
44827
44867
|
* }>}
|
|
44828
44868
|
* @param name - How `value`/`signal`/`onChange` name this side. Its position
|
|
44829
44869
|
* ("0" or "1") by default.
|
|
@@ -44835,10 +44875,17 @@ const ControlSwap = props => {
|
|
|
44835
44875
|
* doing something (a filter set, a search typed). `true` draws a dot;
|
|
44836
44876
|
* anything else is drawn as given (a `<BadgeCount>`, say).
|
|
44837
44877
|
* @param autoFocus - On by default: the focus goes into this control when it
|
|
44838
|
-
* takes the floor
|
|
44839
|
-
* `false` leaves it on the cap
|
|
44840
|
-
*
|
|
44841
|
-
* on mount, whatever the
|
|
44878
|
+
* takes the floor, where navi's ladder puts it — an `autoFocus` inside the
|
|
44879
|
+
* control first, its first focusable otherwise. `false` leaves it on the cap
|
|
44880
|
+
* that was pressed, for a control one reads before writing in (and, on a
|
|
44881
|
+
* phone, for a keyboard that must not rise). Never on mount, whatever the
|
|
44882
|
+
* setting.
|
|
44883
|
+
*
|
|
44884
|
+
* Anything else — `data-testid`, `variant`, `backgroundColor`, `color`, an
|
|
44885
|
+
* `aria-describedby` — goes to the cap, which is a `<Button>`. It is the one
|
|
44886
|
+
* element of the row an application does not render, so nothing else can name
|
|
44887
|
+
* it or dress it; the control it stands for is a vnode of the caller's own and
|
|
44888
|
+
* takes its props directly.
|
|
44842
44889
|
*/
|
|
44843
44890
|
const ControlSwapSide = () => null;
|
|
44844
44891
|
const ControlSwapCap = ({
|
|
@@ -44851,19 +44898,25 @@ const ControlSwapCap = ({
|
|
|
44851
44898
|
const {
|
|
44852
44899
|
icon,
|
|
44853
44900
|
label,
|
|
44854
|
-
badge
|
|
44855
|
-
|
|
44901
|
+
badge,
|
|
44902
|
+
...capProps
|
|
44903
|
+
} = side.capProps;
|
|
44856
44904
|
return jsxs(Button, {
|
|
44857
|
-
ref: ref,
|
|
44858
|
-
className: "navi_control_swap_cap",
|
|
44859
|
-
variant: "discrete",
|
|
44860
44905
|
icon: true,
|
|
44906
|
+
pressEffect: "none",
|
|
44861
44907
|
"aria-label": label,
|
|
44908
|
+
...capProps,
|
|
44909
|
+
ref: ref
|
|
44910
|
+
// After the caller's props, all of them: the class is what the row's own
|
|
44911
|
+
// CSS reaches for, and the rest is the wiring that makes the cap a cap.
|
|
44912
|
+
,
|
|
44913
|
+
|
|
44914
|
+
className: capProps.className ? `navi_control_swap_cap ${capProps.className}` : "navi_control_swap_cap",
|
|
44862
44915
|
"aria-expanded": active,
|
|
44863
44916
|
"aria-controls": slotId,
|
|
44864
44917
|
onClick: onPress,
|
|
44865
44918
|
children: [jsx(Icon, {
|
|
44866
|
-
width: "
|
|
44919
|
+
width: "50%",
|
|
44867
44920
|
square: true,
|
|
44868
44921
|
children: icon
|
|
44869
44922
|
}), badge ? jsx("span", {
|
|
@@ -44880,13 +44933,20 @@ const readSides = children => {
|
|
|
44880
44933
|
if (!child || child.type !== ControlSwapSide) {
|
|
44881
44934
|
continue;
|
|
44882
44935
|
}
|
|
44936
|
+
// What is left over once the side's own vocabulary is taken out describes
|
|
44937
|
+
// the cap: the control is a vnode the caller wrote and dresses itself, so
|
|
44938
|
+
// the cap is the only thing in the row left to describe.
|
|
44883
44939
|
const {
|
|
44884
44940
|
name,
|
|
44885
|
-
|
|
44941
|
+
autoFocus,
|
|
44942
|
+
children: control,
|
|
44943
|
+
...capProps
|
|
44886
44944
|
} = child.props;
|
|
44887
44945
|
sides.push({
|
|
44888
44946
|
name: name === undefined ? String(sides.length) : name,
|
|
44889
|
-
|
|
44947
|
+
autoFocus,
|
|
44948
|
+
control,
|
|
44949
|
+
capProps
|
|
44890
44950
|
});
|
|
44891
44951
|
}
|
|
44892
44952
|
return sides;
|
|
@@ -44894,33 +44954,40 @@ const readSides = children => {
|
|
|
44894
44954
|
|
|
44895
44955
|
// The floor moved: the press that gave it landed on a cap, and what one wants
|
|
44896
44956
|
// next is the control that just arrived — typing into the search field one just
|
|
44897
|
-
// opened, not pressing its icon again.
|
|
44898
|
-
//
|
|
44899
|
-
//
|
|
44900
|
-
//
|
|
44901
|
-
|
|
44902
|
-
|
|
44903
|
-
|
|
44904
|
-
|
|
44905
|
-
|
|
44957
|
+
// opened, not pressing its icon again.
|
|
44958
|
+
//
|
|
44959
|
+
// WHERE inside is navi's own ladder (findFocusTarget): an `autoFocus` in the
|
|
44960
|
+
// control's own content first, the first focusable otherwise, a last resort
|
|
44961
|
+
// after that. Two of the ladder's reflexes are turned off here, and it is the
|
|
44962
|
+
// same reason both times — they are about a surface APPEARING, and this is a
|
|
44963
|
+
// press aimed at the control being handed the focus:
|
|
44964
|
+
// - the first focusable is kept even where the pointer is coarse (an arriving
|
|
44965
|
+
// popup drops it so a virtual keyboard does not rise over what it just
|
|
44966
|
+
// showed, see docs/autofocus.md); pressing a cap to reach a field is asking
|
|
44967
|
+
// for that keyboard;
|
|
44968
|
+
// - `autoFocus="restore"` may claim it, though it means "never on a fresh
|
|
44969
|
+
// open". A field marked that way so its sheet opens quietly would otherwise
|
|
44970
|
+
// leave the focus on the magnifier that was pressed to reach it.
|
|
44971
|
+
// A side one reads before writing in says `autoFocus={false}`.
|
|
44972
|
+
const focusWithTheFloor = (arrivingSlot, arrivingSide, arrivingCap) => {
|
|
44973
|
+
if (arrivingSide.autoFocus !== false) {
|
|
44974
|
+
const found = findFocusTarget(arrivingSlot, {
|
|
44975
|
+
restoreMayClaim: true
|
|
44976
|
+
});
|
|
44977
|
+
if (found) {
|
|
44978
|
+
moveFocusTo(found.target);
|
|
44906
44979
|
return;
|
|
44907
44980
|
}
|
|
44908
44981
|
}
|
|
44982
|
+
// Whatever the leaving slot held is inert and off the window now, so the
|
|
44983
|
+
// browser dropped its focus to the document body: it has to land somewhere,
|
|
44984
|
+
// and the cap of the side taking over is where the gesture was.
|
|
44909
44985
|
const {
|
|
44910
44986
|
activeElement
|
|
44911
44987
|
} = document;
|
|
44912
44988
|
if (!activeElement || activeElement === document.body) {
|
|
44913
|
-
|
|
44914
|
-
}
|
|
44915
|
-
};
|
|
44916
|
-
const findElementToFocus = slot => {
|
|
44917
|
-
const autofocusElement = slot.querySelector("[autofocus]");
|
|
44918
|
-
if (autofocusElement) {
|
|
44919
|
-
return autofocusElement;
|
|
44989
|
+
moveFocusTo(arrivingCap);
|
|
44920
44990
|
}
|
|
44921
|
-
return findAfter(slot, elementIsFocusable, {
|
|
44922
|
-
root: slot
|
|
44923
|
-
});
|
|
44924
44991
|
};
|
|
44925
44992
|
|
|
44926
44993
|
const DEFAULT_VALIDITY_STATE = { valid: true, reported: null };
|
|
@@ -79532,5 +79599,5 @@ const UserSvg = () => jsx("svg", {
|
|
|
79532
79599
|
})
|
|
79533
79600
|
});
|
|
79534
79601
|
|
|
79535
|
-
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, NumberSpin, OfflineError, Paragraph, Picker, Popover, Popup, 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, anyMatchingRouteSignal, applySearch, arraySignalMembership, canNavBackSignal, canNavForwardSignal, coarsePointerSignal, compareTwoJsValues, constraintFromValidityRule, createAction, createAvailableConstraint, createI18n, createRequestCanceller, createSearch, createSelectionKeyboardShortcuts, createSlot, defineInteractionDetector, defineRouteDefaultTransition, defineRouteTransition, detectHorizontalOverflow, enableDebugActions, enableDebugOnDocumentLoading, ensureDocumentStartViewTransition, errorIsDisplayed, filterTableSelection, formatDatetime, formatDay, formatDayRelative, formatMonth, formatNumber, formatTime, formatTimeRelative, getNowHours, getNowHoursRoundedToStep, interpolateText, isCellSelected, isColumnSelected, isOfflineError, isRowSelected, isScrolling, isToday, languagesSignal, localStorageSignal, markErrorAsDisplayedBy, moveArrayItemByIndex, navBack, navForward, navIntegratedVia, navTo, naviI18n, openCallout, rawUrlPart, registerGlobalConstraint, reload, rerunActions, resource, route, routeAction, scrollActivitySignal, setBaseUrl, setNetworkPolicy, setPreferredLanguage, setSupportedLanguages, setUrlTargetOptions, setupRoutes, smallTouchScreenSignal, stateSignal, stopLoad, stringifyTableSelectionValue, swapArrayItemByIndex, syncOwnedResourceToSignals, syncResourceToSignals, triggerNaviCommand, updateActions, useActionStatus, useArraySignalMembership, useAsyncData, useCalloutElement, useCalloutRequestClose, useCanNavBack, useCanNavForward, useCancelPrevious, useCellGridFromRows, useConstraintValidityState, useDependenciesDiff, useDisplayedLayoutEffect, useDocumentResource, useDocumentState, useDocumentUrl, useEditionController, useFocusGroup, useInputGroup, useKeyboardShortcuts, useNavState, useNetworkPolicyReason, useOrderedColumns, usePopupMode, useRouteStatus, useSearchText, useSelectableElement, useSelectionController, useSignalSync, useSlideContainer, useSlideValue, useStateArray, useTitleLevel, useUrlSearchParam, useUrlTargetId, valueInLocalStorage, windowWidthSignal };
|
|
79602
|
+
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, NumberSpin, OfflineError, Paragraph, Picker, Popover, Popup, 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, anyMatchingRouteSignal, applySearch, arraySignalMembership, canNavBackSignal, canNavForwardSignal, coarsePointerSignal, compareTwoJsValues, constraintFromValidityRule, createAction, createAvailableConstraint, createI18n, createRequestCanceller, createSearch, createSelectionKeyboardShortcuts, createSlot, defineInteractionDetector, defineRouteDefaultTransition, defineRouteTransition, detectHorizontalOverflow, enableDebugActions, enableDebugOnDocumentLoading, ensureDocumentStartViewTransition, errorIsDisplayed, filterTableSelection, formatDatetime, formatDay, formatDayRelative, formatMonth, formatNumber, formatTime, formatTimeRelative, getNowHours, getNowHoursRoundedToStep, interpolateText, isCellSelected, isColumnSelected, isOfflineError, isRowSelected, isScrolling, isToday, languagesSignal, localStorageSignal, markErrorAsDisplayedBy, moveArrayItemByIndex, moveFocusTo, navBack, navForward, navIntegratedVia, navTo, naviI18n, openCallout, rawUrlPart, registerGlobalConstraint, reload, rerunActions, resource, route, routeAction, scrollActivitySignal, setBaseUrl, setNetworkPolicy, setPreferredLanguage, setSupportedLanguages, setUrlTargetOptions, setupRoutes, smallTouchScreenSignal, stateSignal, stopLoad, stringifyTableSelectionValue, swapArrayItemByIndex, syncOwnedResourceToSignals, syncResourceToSignals, triggerNaviCommand, updateActions, useActionStatus, useArraySignalMembership, useAsyncData, useCalloutElement, useCalloutRequestClose, useCanNavBack, useCanNavForward, useCancelPrevious, useCellGridFromRows, useConstraintValidityState, useDependenciesDiff, useDisplayedLayoutEffect, useDocumentResource, useDocumentState, useDocumentUrl, useEditionController, useFocusGroup, useInputGroup, useKeyboardShortcuts, useNavState, useNetworkPolicyReason, useOrderedColumns, usePopupMode, useRouteStatus, useSearchText, useSelectableElement, useSelectionController, useSignalSync, useSlideContainer, useSlideValue, useStateArray, useTitleLevel, useUrlSearchParam, useUrlTargetId, valueInLocalStorage, windowWidthSignal };
|
|
79536
79603
|
//# sourceMappingURL=jsenv_navi.js.map
|