@jsenv/navi 0.29.80 → 0.29.82
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/README.md +1 -1
- package/dist/jsenv_navi.js +157 -54
- package/dist/jsenv_navi.js.map +9 -10
- package/docs/AI_INSTRUCTIONS.md +6 -0
- package/docs/autofocus.md +61 -20
- package/docs/typography.md +176 -0
- package/package.json +1 -1
package/README.md
CHANGED
|
@@ -27,7 +27,7 @@ between related actions. Parent/child relations are first-class — `.one`,
|
|
|
27
27
|
|
|
28
28
|
**`Box`** is the main layout primitive. It wraps CSS Flexbox with a friendlier API: `flex` for horizontal layout, `flex="y"` for vertical (no more guessing what `flex-direction: column` does visually). Supports `grid`, `inline`, alignment via `alignX`/`alignY`, and spacing props.
|
|
29
29
|
|
|
30
|
-
**`Text`** and related components (`Title`, `Paragraph`, `Code`, `Caption`) handle typography consistently across the app.
|
|
30
|
+
**`Text`** and related components (`Title`, `Paragraph`, `Code`, `Caption`) handle typography consistently across the app — including the parts of a line that are not text: icons, counts, truncation (`maxLines`), skeletons, and where a line may break. See [docs/typography.md](./docs/typography.md).
|
|
31
31
|
|
|
32
32
|
## Texts & i18n
|
|
33
33
|
|
package/dist/jsenv_navi.js
CHANGED
|
@@ -2,8 +2,8 @@
|
|
|
2
2
|
* AI reading this file: read ../docs/AI_INSTRUCTIONS.md for context on
|
|
3
3
|
* using @jsenv/navi as intended.
|
|
4
4
|
*/
|
|
5
|
-
import { installImportMetaCssBuild, windowHeightSignal, windowWidthSignal, visualViewportHeightSignal, visualViewportWidthSignal, getAppHeight, getAppWidth, smallTouchScreenSignal } from "./jsenv_navi_side_effects.js";
|
|
6
|
-
export {
|
|
5
|
+
import { installImportMetaCssBuild, windowHeightSignal, windowWidthSignal, visualViewportHeightSignal, visualViewportWidthSignal, getAppHeight, getAppWidth, coarsePointerSignal, smallTouchScreenSignal } from "./jsenv_navi_side_effects.js";
|
|
6
|
+
export { disableVirtualKeyboardOverlay } from "./jsenv_navi_side_effects.js";
|
|
7
7
|
import { elementIsFocusable, createPubSub, dispatchInternalCustomEvent, dispatchCustomEvent, getVisuallyVisibleInfo, getFirstVisuallyVisibleAncestor, getElementSignature, findEvent, createValueEffect, findFocusDelegateTarget, findFocusable, allowWheelThrough, dispatchPublicCustomEvent, resolveCSSColor, ELEMENT_SIZE_CHANGE, findSelfOrAncestorFixedPosition, visibleRectEffect, pickPositionRelativeTo, getBorderSizes, getPaddingSizes, applyNewPosition, measureLongestVisualLineWidth, chainEvent, waitForPressHeld, suppressClickAfterGesture, startDragToTravel, markDragSource, startDragTo, createIterableWeakSet, createEventGroupLogger, getKeyboardEventDefaultAction, activeElementSignal, normalizeStyle, mergeOneStyle, getPositionedParent, mergeTwoStyles, normalizeStyles, resolveCSSSize, hasCSSSizeUnit, resolveOklchLightness, contrastColor, closestOpenableAncestor, isAncestorOpen, observeAncestorOpenState, getAncestorOpenType, clickIsSuppressed, isTouchDrivenEvent, scrollIntoViewScoped, scrollRoomTowards, parsePositionArea, snapToPixel, trapFocusInside, trapScrollInside, onAncestorReopen, createGroupTransitionController, getBorderRadius, preventIntermediateScrollbar, createOpacityTransition, watchWheelTravel, findBefore, findAfter, initFocusGroup, getScrollContainer, canScroll, measureWidestChildRow, performTabNavigation, wheelGestureIsTakenFrom, releaseWheelGesture, claimWheelGesture, dragAfterIntent, stickyAsRelativeCoords, createDragToMoveGestureController, getDropTargetInfo, setStyles, useActiveElement, stringifyStyle as stringifyStyle$1 } from "@jsenv/dom";
|
|
8
8
|
export { clickIsSuppressed, contrastColor, findEvent, startDragTo } from "@jsenv/dom";
|
|
9
9
|
import { signal, computed, effect, batch, untracked, useSignal } from "@preact/signals";
|
|
@@ -17134,6 +17134,12 @@ const TYPO_PROPS = {
|
|
|
17134
17134
|
uppercase: applyToCssPropWhenTruthy("textTransform", "uppercase", "none"),
|
|
17135
17135
|
lowercase: applyToCssPropWhenTruthy("textTransform", "lowercase", "none"),
|
|
17136
17136
|
letterSpacing: PASS_THROUGH,
|
|
17137
|
+
// How many lines before truncation, for anything that is not a `Text`.
|
|
17138
|
+
// On a `Text`, `maxLines` is the prop to use and it does more than this
|
|
17139
|
+
// mapping (block display, min-width, white-space per tag) — see
|
|
17140
|
+
// docs/typography.md. `lineClamp` and `overflowEllipsis` below are the raw
|
|
17141
|
+
// one-to-one CSS mappings, kept for an element that opts out of `Text` and
|
|
17142
|
+
// still wants that exact CSS; `lineClamp: 1` is NOT single-line truncation.
|
|
17137
17143
|
maxLines: (value) => {
|
|
17138
17144
|
if (!value) {
|
|
17139
17145
|
return null;
|
|
@@ -21128,6 +21134,12 @@ const shouldInjectSpacingBetween = (left, right) => {
|
|
|
21128
21134
|
};
|
|
21129
21135
|
|
|
21130
21136
|
/**
|
|
21137
|
+
* The typography primitive: every string an app displays goes through it, or
|
|
21138
|
+
* through something built on it (`Title`, `Paragraph`, `Caption`, `Link`, a
|
|
21139
|
+
* control's label). It accepts every `Box` prop on top of the ones below.
|
|
21140
|
+
* See `docs/typography.md` for the decisions behind it — truncating, rows made
|
|
21141
|
+
* of an icon, a text and an icon, and where a line may break.
|
|
21142
|
+
*
|
|
21131
21143
|
* @type {import("ignore:preact").FunctionComponent<{
|
|
21132
21144
|
* children?: import("ignore:preact").ComponentChildren,
|
|
21133
21145
|
* as?: string,
|
|
@@ -21139,6 +21151,7 @@ const shouldInjectSpacingBetween = (left, right) => {
|
|
|
21139
21151
|
* spacing?: string | number | import("ignore:preact").ComponentChildren,
|
|
21140
21152
|
* loading?: boolean,
|
|
21141
21153
|
* skeleton?: boolean,
|
|
21154
|
+
* attachLastChild?: boolean,
|
|
21142
21155
|
* preventSpaceUnderlines?: boolean,
|
|
21143
21156
|
* holdSpaceForStyle?: import("ignore:preact").JSX.CSSProperties,
|
|
21144
21157
|
* boldStable?: boolean,
|
|
@@ -21150,9 +21163,14 @@ const shouldInjectSpacingBetween = (left, right) => {
|
|
|
21150
21163
|
* }>}
|
|
21151
21164
|
*
|
|
21152
21165
|
* @param {number} [maxLines]
|
|
21153
|
-
*
|
|
21154
|
-
* single
|
|
21155
|
-
*
|
|
21166
|
+
* How many lines the text may take before it is truncated with an ellipsis.
|
|
21167
|
+
* `maxLines={1}` truncates on a single line; `maxLines={n}` (n > 1) clamps to
|
|
21168
|
+
* n lines. This is the only prop to use for that — `Box`'s `lineClamp` /
|
|
21169
|
+
* `overflowEllipsis` are raw CSS mappings meant for elements that are not a
|
|
21170
|
+
* `Text`, and `lineClamp={1}` is never the single-line truncation you want.
|
|
21171
|
+
* Truncation only happens if the element may become narrower than its
|
|
21172
|
+
* content: `maxLines` sets `min-width: 0` here, but each `Box` between this
|
|
21173
|
+
* one and the element that carries the width must set it too.
|
|
21156
21174
|
*
|
|
21157
21175
|
* @param {string|number} [spacing]
|
|
21158
21176
|
* Separator injected between child nodes. Accepts a size token (`"s"`, `"m"`, …),
|
|
@@ -21168,7 +21186,10 @@ const shouldInjectSpacingBetween = (left, right) => {
|
|
|
21168
21186
|
* @param {boolean} [attachLastChild]
|
|
21169
21187
|
* Keeps the last child on the same line as the word before it — a trailing
|
|
21170
21188
|
* icon, a unit, an arrow. Without it the browser may break the line right
|
|
21171
|
-
* before that child and leave it alone underneath
|
|
21189
|
+
* before that child and leave it alone underneath, and no character can
|
|
21190
|
+
* prevent that break. For wrapping text; a child that must survive
|
|
21191
|
+
* truncation belongs outside the `Text` instead (see `docs/typography.md`).
|
|
21192
|
+
* `Link` sets it on its own whenever it renders an end icon.
|
|
21172
21193
|
*
|
|
21173
21194
|
* @param {boolean} [preventSpaceUnderlines]
|
|
21174
21195
|
* Replaces real space characters between children with padding-based spaces.
|
|
@@ -21832,14 +21853,16 @@ const markAutofocusRestoreOnClose = (
|
|
|
21832
21853
|
*
|
|
21833
21854
|
* @param {HTMLElement} containerEl
|
|
21834
21855
|
* @param {object} [options]
|
|
21835
|
-
* @param {boolean} [options.
|
|
21836
|
-
*
|
|
21837
|
-
*
|
|
21838
|
-
*
|
|
21839
|
-
*
|
|
21856
|
+
* @param {boolean} [options.skipFirstFocusable]
|
|
21857
|
+
* Drops step 2 — the focus then goes where something ASKED for it, or to the
|
|
21858
|
+
* last resort, which for a container is itself. For a surface that is read
|
|
21859
|
+
* before it is reached: the first focusable is wherever the content happens
|
|
21860
|
+
* to put it, so landing there scrolls whatever comes before it out of sight
|
|
21861
|
+
* (see open_controller.js, which turns this on wherever the keyboard is a
|
|
21862
|
+
* virtual one).
|
|
21840
21863
|
* @returns {{target: HTMLElement, reason: string}|undefined}
|
|
21841
21864
|
*/
|
|
21842
|
-
const findFocusTarget = (containerEl, {
|
|
21865
|
+
const findFocusTarget = (containerEl, { skipFirstFocusable } = {}) => {
|
|
21843
21866
|
// Not while there is anything else: what takes the focus only for want of
|
|
21844
21867
|
// anything better ("last-resort") and what only takes it back ("restore").
|
|
21845
21868
|
// Neither is dropped, both are simply tried later — step 3 below for the
|
|
@@ -21863,7 +21886,17 @@ const findFocusTarget = (containerEl, { avoidEditable } = {}) => {
|
|
|
21863
21886
|
// leads somewhere focusable. One inside a screen waiting its turn (an inert
|
|
21864
21887
|
// slide) says where the focus goes WHEN it arrives there, not now — so it is
|
|
21865
21888
|
// passed over here rather than treated as an answer that then fails silently.
|
|
21866
|
-
|
|
21889
|
+
//
|
|
21890
|
+
// The container's own mark comes last among the asked, and querySelectorAll
|
|
21891
|
+
// does not return it: a surface saying "the keyboard stops on me" is answered
|
|
21892
|
+
// by anything inside it that named itself, the more precise answer winning.
|
|
21893
|
+
const askedList = Array.from(
|
|
21894
|
+
containerEl.querySelectorAll(`[navi-autofocus]`),
|
|
21895
|
+
);
|
|
21896
|
+
if (containerEl.matches?.(`[navi-autofocus]`)) {
|
|
21897
|
+
askedList.push(containerEl);
|
|
21898
|
+
}
|
|
21899
|
+
for (const asked of askedList) {
|
|
21867
21900
|
if (skip(asked)) {
|
|
21868
21901
|
continue;
|
|
21869
21902
|
}
|
|
@@ -21876,13 +21909,11 @@ const findFocusTarget = (containerEl, { avoidEditable } = {}) => {
|
|
|
21876
21909
|
return { target: askedFocusable, reason: "navi-autofocus" };
|
|
21877
21910
|
}
|
|
21878
21911
|
}
|
|
21879
|
-
|
|
21880
|
-
exclude:
|
|
21881
|
-
|
|
21882
|
-
:
|
|
21883
|
-
|
|
21884
|
-
if (focusable) {
|
|
21885
|
-
return { target: focusable, reason: "first focusable element" };
|
|
21912
|
+
if (!skipFirstFocusable) {
|
|
21913
|
+
const focusable = findFocusable(containerEl, { exclude: skip });
|
|
21914
|
+
if (focusable) {
|
|
21915
|
+
return { target: focusable, reason: "first focusable element" };
|
|
21916
|
+
}
|
|
21886
21917
|
}
|
|
21887
21918
|
const lastResorts = Array.from(
|
|
21888
21919
|
containerEl.querySelectorAll(`[navi-autofocus="last-resort"]`),
|
|
@@ -21950,7 +21981,7 @@ const prepareFocusTransfer = (prepareEvent, debugFocus) => {
|
|
|
21950
21981
|
transferFocus: (
|
|
21951
21982
|
transferEvent,
|
|
21952
21983
|
containerEl,
|
|
21953
|
-
{ getDelay,
|
|
21984
|
+
{ getDelay, skipFirstFocusable } = {},
|
|
21954
21985
|
) => {
|
|
21955
21986
|
let target;
|
|
21956
21987
|
let reason;
|
|
@@ -21967,7 +21998,7 @@ const prepareFocusTransfer = (prepareEvent, debugFocus) => {
|
|
|
21967
21998
|
}
|
|
21968
21999
|
}
|
|
21969
22000
|
if (!target) {
|
|
21970
|
-
const found = findFocusTarget(containerEl, {
|
|
22001
|
+
const found = findFocusTarget(containerEl, { skipFirstFocusable });
|
|
21971
22002
|
if (found) {
|
|
21972
22003
|
reason = found.reason;
|
|
21973
22004
|
target = found.target;
|
|
@@ -21984,14 +22015,20 @@ const prepareFocusTransfer = (prepareEvent, debugFocus) => {
|
|
|
21984
22015
|
// appears inside it next (see claimUnplacedAutofocus). Both ways of
|
|
21985
22016
|
// saying no count: finding nothing at all, and the fallback above, which
|
|
21986
22017
|
// leaves the focus where it already was — outside.
|
|
21987
|
-
|
|
21988
|
-
|
|
21989
|
-
|
|
21990
|
-
) {
|
|
22018
|
+
const placedInside =
|
|
22019
|
+
target && (containerEl === target || containerEl.contains(target));
|
|
22020
|
+
let cancelRetry;
|
|
22021
|
+
if (!placedInside) {
|
|
21991
22022
|
containerEl.setAttribute(AUTOFOCUS_UNPLACED_ATTRIBUTE, "");
|
|
22023
|
+
cancelRetry = retryWhenPlaceable(containerEl, {
|
|
22024
|
+
skipFirstFocusable,
|
|
22025
|
+
focusVisible,
|
|
22026
|
+
debugFocus,
|
|
22027
|
+
transferEvent,
|
|
22028
|
+
});
|
|
21992
22029
|
}
|
|
21993
22030
|
if (!target) {
|
|
21994
|
-
return
|
|
22031
|
+
return cancelRetry;
|
|
21995
22032
|
}
|
|
21996
22033
|
// The modality speaks for the transfer, but an editable target outranks
|
|
21997
22034
|
// it: it draws its ring on any focus (see isMatchingFocusVisible), so
|
|
@@ -22002,19 +22039,12 @@ const prepareFocusTransfer = (prepareEvent, debugFocus) => {
|
|
|
22002
22039
|
transferEvent,
|
|
22003
22040
|
`Moving focus to ${getElementSignature(target)}.focus({ preventScroll: true, focusVisible: ${targetFocusVisible} }) (reason: ${reason})`,
|
|
22004
22041
|
);
|
|
22005
|
-
target
|
|
22006
|
-
preventScroll: true,
|
|
22007
|
-
focusVisible: targetFocusVisible,
|
|
22008
|
-
});
|
|
22009
|
-
if (target.hasAttribute("navi-autofocus-select")) {
|
|
22010
|
-
target.select();
|
|
22011
|
-
target.scrollLeft = 0;
|
|
22012
|
-
}
|
|
22042
|
+
focusTransferTarget(target, targetFocusVisible);
|
|
22013
22043
|
};
|
|
22014
22044
|
const delay = getDelay?.(target) || 0;
|
|
22015
22045
|
if (!delay) {
|
|
22016
22046
|
giveFocus();
|
|
22017
|
-
return
|
|
22047
|
+
return cancelRetry;
|
|
22018
22048
|
}
|
|
22019
22049
|
debugFocus(
|
|
22020
22050
|
transferEvent,
|
|
@@ -22023,6 +22053,7 @@ const prepareFocusTransfer = (prepareEvent, debugFocus) => {
|
|
|
22023
22053
|
const timeout = setTimeout(giveFocus, delay);
|
|
22024
22054
|
return () => {
|
|
22025
22055
|
clearTimeout(timeout);
|
|
22056
|
+
cancelRetry?.();
|
|
22026
22057
|
};
|
|
22027
22058
|
},
|
|
22028
22059
|
|
|
@@ -22042,6 +22073,57 @@ const prepareFocusTransfer = (prepareEvent, debugFocus) => {
|
|
|
22042
22073
|
};
|
|
22043
22074
|
};
|
|
22044
22075
|
|
|
22076
|
+
/**
|
|
22077
|
+
* The second and last try at placing a focus the ladder had nowhere to put.
|
|
22078
|
+
*
|
|
22079
|
+
* A container can open on a moment where nothing in it — its own contents, and
|
|
22080
|
+
* itself — can take the focus: content still being built, a screen not yet
|
|
22081
|
+
* interactive. That moment is over almost immediately, and nothing else would
|
|
22082
|
+
* ever come back to it: the opening is the one event there is, and it has
|
|
22083
|
+
* passed. So the transfer keeps its promise one microtask later, still before
|
|
22084
|
+
* the browser paints, and still before anything the user does.
|
|
22085
|
+
*
|
|
22086
|
+
* Whoever settled the debt in between wins — content arriving with an autofocus
|
|
22087
|
+
* of its own claims it through use_auto_focus.js, and finding the mark gone is
|
|
22088
|
+
* how this knows to stand down.
|
|
22089
|
+
*/
|
|
22090
|
+
const retryWhenPlaceable = (
|
|
22091
|
+
containerEl,
|
|
22092
|
+
{ skipFirstFocusable, focusVisible, debugFocus, transferEvent },
|
|
22093
|
+
) => {
|
|
22094
|
+
let cancelled = false;
|
|
22095
|
+
queueMicrotask(() => {
|
|
22096
|
+
if (cancelled || !containerEl.isConnected) {
|
|
22097
|
+
return;
|
|
22098
|
+
}
|
|
22099
|
+
if (!claimUnplacedAutofocus(containerEl)) {
|
|
22100
|
+
return;
|
|
22101
|
+
}
|
|
22102
|
+
const found = findFocusTarget(containerEl, { skipFirstFocusable });
|
|
22103
|
+
if (!found) {
|
|
22104
|
+
return;
|
|
22105
|
+
}
|
|
22106
|
+
const { target, reason } = found;
|
|
22107
|
+
debugFocus(
|
|
22108
|
+
transferEvent,
|
|
22109
|
+
`Moving focus to ${getElementSignature(target)} on second try (reason: ${reason})`,
|
|
22110
|
+
);
|
|
22111
|
+
focusTransferTarget(target, focusVisible || isEditableTarget(target));
|
|
22112
|
+
});
|
|
22113
|
+
return () => {
|
|
22114
|
+
cancelled = true;
|
|
22115
|
+
};
|
|
22116
|
+
};
|
|
22117
|
+
|
|
22118
|
+
const focusTransferTarget = (target, focusVisible) => {
|
|
22119
|
+
target.focus({ preventScroll: true, focusVisible });
|
|
22120
|
+
if (target.hasAttribute("navi-autofocus-select")) {
|
|
22121
|
+
target.select();
|
|
22122
|
+
// Keep the beginning of the text visible instead of scrolling to the end
|
|
22123
|
+
target.scrollLeft = 0;
|
|
22124
|
+
}
|
|
22125
|
+
};
|
|
22126
|
+
|
|
22045
22127
|
// Get the active element before we transfer focus in the popover/dialog
|
|
22046
22128
|
// We don't just use document.activeElement because when dialog is opened by mousedown
|
|
22047
22129
|
// we prevent default so browser don't steal focus back from the dialog
|
|
@@ -22097,7 +22179,14 @@ const getFocusedBeforeTransfer = (e) => {
|
|
|
22097
22179
|
* @param {boolean|"last-resort"|"restore"} autoFocus
|
|
22098
22180
|
* When false the hook is a no-op. The other values say WHEN this element is
|
|
22099
22181
|
* the right place for the keyboard (the whole ladder lives in
|
|
22100
|
-
* findFocusTarget, see focus_transfer.js
|
|
22182
|
+
* findFocusTarget, see focus_transfer.js, and the decisions behind it in
|
|
22183
|
+
* docs/autofocus.md):
|
|
22184
|
+
* - `true` — "I am what the user came for". On a FIELD it asks for the
|
|
22185
|
+
* keyboard outright, on a touch device included, where a popup otherwise
|
|
22186
|
+
* keeps it down: the comment box of a popup opened to write a comment. On a
|
|
22187
|
+
* CONTAINER it says the opposite, since a surface takes no keyboard by
|
|
22188
|
+
* being focused — the popup that is read before it is filled, arriving at
|
|
22189
|
+
* the top of its own reading order.
|
|
22101
22190
|
* - `"last-resort"` — "not me, unless you have nothing else". Said by a
|
|
22102
22191
|
* focusable that is a poor place to arrive (a picker's search box, a
|
|
22103
22192
|
* panel's close button, a slide's chevron) and by a container about its own
|
|
@@ -29059,7 +29148,7 @@ const createOpenController = (
|
|
|
29059
29148
|
requestOpenEvent,
|
|
29060
29149
|
debugInteraction,
|
|
29061
29150
|
);
|
|
29062
|
-
controller.transferFocusOnOpen = (el
|
|
29151
|
+
controller.transferFocusOnOpen = (el) => {
|
|
29063
29152
|
// requestOpenEvent, not the raw `e` — getFocusedBeforeTransfer needs
|
|
29064
29153
|
// e.detail.eventChain (built by chainEvent above) to recover the
|
|
29065
29154
|
// element a mousedown/click landed on. `e` itself is usually the raw
|
|
@@ -29086,7 +29175,19 @@ const createOpenController = (
|
|
|
29086
29175
|
findEvent(requestOpenEvent, isTouchDrivenEvent),
|
|
29087
29176
|
);
|
|
29088
29177
|
const cancelPendingFocus = focusTransfer.transferFocus(e, el, {
|
|
29089
|
-
|
|
29178
|
+
// A popup is READ before it is reached wherever the keyboard is a
|
|
29179
|
+
// virtual one. Landing on the first focusable there costs the top of
|
|
29180
|
+
// the popup twice over: the browser scrolls that element into view,
|
|
29181
|
+
// and a field raises a keyboard that takes a third of what is left —
|
|
29182
|
+
// so the title and the sentence saying what this is about are gone
|
|
29183
|
+
// before the popup has been looked at. Only something that ASKED for
|
|
29184
|
+
// the focus is worth that, and asking is what `autoFocus` is.
|
|
29185
|
+
//
|
|
29186
|
+
// The device, not the opening (unlike the delay below): whether
|
|
29187
|
+
// focusing raises a keyboard over the popup is true of the screen,
|
|
29188
|
+
// and a popup opened by the page loading — no pointer in it at all —
|
|
29189
|
+
// is precisely the one that must not be answered "no keyboard here".
|
|
29190
|
+
skipFirstFocusable: coarsePointerSignal.value,
|
|
29090
29191
|
getDelay: (target) =>
|
|
29091
29192
|
openedByTouch && isEditableTarget(target)
|
|
29092
29193
|
? FOCUS_DELAY_ON_KEYBOARD_MS
|
|
@@ -30746,10 +30847,10 @@ const css$X = /* css */`
|
|
|
30746
30847
|
* focusable of its own.
|
|
30747
30848
|
* - `"restore"` — the dialog stays out of the opening focus chain unless it
|
|
30748
30849
|
* held focus when it closed.
|
|
30749
|
-
*
|
|
30750
|
-
*
|
|
30751
|
-
*
|
|
30752
|
-
*
|
|
30850
|
+
* Wherever the keyboard is a virtual one (a touch device), the surface is
|
|
30851
|
+
* already what one arrives on: a popup is read before it is reached there, so
|
|
30852
|
+
* the focus only leaves it for something that asked by name (`autoFocus` on
|
|
30853
|
+
* that element, which outranks whatever the dialog says).
|
|
30753
30854
|
* @param {boolean} [props.open] - Controlled open state.
|
|
30754
30855
|
* @param {boolean|"interaction"} [props.defaultOpen] - Uncontrolled, mount-only
|
|
30755
30856
|
* initial open state. `true` plays no entrance animation: the dialog was
|
|
@@ -31446,16 +31547,7 @@ const useDialogProps = props => {
|
|
|
31446
31547
|
// entrance to be over. Decided by transferFocusOnOpen, the only place that
|
|
31447
31548
|
// knows WHICH element is about to be focused (open_controller.js and its
|
|
31448
31549
|
// FOCUS_DELAY_ON_KEYBOARD_MS).
|
|
31449
|
-
|
|
31450
|
-
// Docked, the keyboard costs more than a wait: it takes a third of a phone
|
|
31451
|
-
// screen from a dialog that starts at the bottom edge, pushing whatever
|
|
31452
|
-
// comes before the field — the title, the sentence saying why it is asked
|
|
31453
|
-
// for — above the top edge before the dialog has even been looked at. So a
|
|
31454
|
-
// docked dialog is READ first: the transfer only reaches a field that asked
|
|
31455
|
-
// for the keyboard by name (see findFocusTarget's `avoidEditable`).
|
|
31456
|
-
const restoreFocus = openController.transferFocusOnOpen(dialogEl, {
|
|
31457
|
-
avoidEditable: isDocked
|
|
31458
|
-
});
|
|
31550
|
+
const restoreFocus = openController.transferFocusOnOpen(dialogEl);
|
|
31459
31551
|
|
|
31460
31552
|
// isModal outside-click detection (see this file's top comment for why
|
|
31461
31553
|
// this is a plain document-level listener rather than anything
|
|
@@ -32194,6 +32286,10 @@ const css$W = /* css */`
|
|
|
32194
32286
|
* - `false` — no open-time focus transfer at all: nothing inside the popover
|
|
32195
32287
|
* receives focus, whoever had the keyboard keeps it — the combobox case,
|
|
32196
32288
|
* where suggestions open under an input being typed in.
|
|
32289
|
+
* Wherever the keyboard is a virtual one (a touch device), the surface is
|
|
32290
|
+
* already what one arrives on: a popup is read before it is reached there, so
|
|
32291
|
+
* the focus only leaves it for something that asked by name (`autoFocus` on
|
|
32292
|
+
* that element, which outranks whatever the popover says).
|
|
32197
32293
|
* @param {boolean} [props.open] - Controlled open state.
|
|
32198
32294
|
* @param {boolean|"interaction"} [props.defaultOpen] - Uncontrolled, mount-only
|
|
32199
32295
|
* initial open state. `true` plays no entrance animation: the popover was
|
|
@@ -49775,6 +49871,13 @@ const inputCss = /* css */`
|
|
|
49775
49871
|
|
|
49776
49872
|
.navi_button {
|
|
49777
49873
|
font-size: inherit;
|
|
49874
|
+
/* A <button> does not inherit the font on its own — same as the
|
|
49875
|
+
<input> above — and what stands in a slot is measured on the line
|
|
49876
|
+
box (Icon fillLine is 1lh): left on the browser's own font, the
|
|
49877
|
+
clear cross would resolve 1lh against a font the field is not
|
|
49878
|
+
written in, and the field would change height the moment the icon
|
|
49879
|
+
is replaced by the button. */
|
|
49880
|
+
font-family: inherit;
|
|
49778
49881
|
|
|
49779
49882
|
/* A button in a slot (e.g. the clear cross) is drawn small but must
|
|
49780
49883
|
not be small to hit: the spacing around it — the slot margins on the
|
|
@@ -75069,5 +75172,5 @@ const UserSvg = () => jsx("svg", {
|
|
|
75069
75172
|
})
|
|
75070
75173
|
});
|
|
75071
75174
|
|
|
75072
|
-
export { ActionRenderer, ActiveKeyboardShortcuts, Address, Badge, BadgeCount, BadgeList, Binder, Box, Button, ButtonCopyToClipboard, Caption, CardLayout, CheckSvg, CheckboxGroup, CloseSvg, Code, Col, Colgroup, Color, ConstructionSvg, ControlGroup, DaySpin, Details, Dialog, Editable, ErrorBoundary, ErrorBoundaryContext, ExclamationSvg, EyeClosedSvg, EyeSvg, Field, FixedBar, Form, Group, Head, HeartSvg, HomeSvg, Icon, Image, Input, InputDuration, Interpolate, Label, Link, LinkAnchorSvg, LinkBlankTargetSvg, LinkCurrentSvg, List, ListItem, ListItemGroup, ListItems, Loading, LoadingDotsSvg, LoadingIndicator, LoadingIndicatorFluid, LoadingOutline, MessageBox, Meter, Nav, NaviDebug, NumberSpin, 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, SummaryMarker, Svg, Table, TableCell, Tbody, Text, TextBox, Textarea, TextareaCharCount, Thead, Time, TimeRangeSpin, TimeSpin, Title, Tr, UITransition, Unit, UserSvg, ViewportLayout, Wheel, WheelGroup, WheelItem, actionRunEffect, anyMatchingRouteSignal, applySearch, arraySignalMembership, compareTwoJsValues, createAction, createAvailableConstraint, createI18n, createRequestCanceller, createSearch, createSelectionKeyboardShortcuts, createSlot, defineInteractionDetector, defineNaviConfirmPopupOptions, defineRouteDefaultTransition, defineRouteTransition, detectHorizontalOverflow, enableDebugActions, enableDebugOnDocumentLoading, ensureDocumentStartViewTransition, errorIsDisplayed, filterTableSelection, formatDatetime, formatDay, formatDayRelative, formatMonth, formatNumber, formatTime, formatTimeRelative, getNowHours, getNowHoursRoundedToStep, interpolateText, isCellSelected, isColumnSelected, isRowSelected, isScrolling, isToday, languagesSignal, localStorageSignal, markErrorAsDisplayedBy, moveArrayItemByIndex, navBack, navForward, navIntegratedVia, navTo, naviI18n, openCallout, rawUrlPart, registerGlobalConstraint, reload, rerunActions, resource, route, routeAction, scrollActivitySignal, setBaseUrl, setPreferredLanguage, setSupportedLanguages, setUrlTargetOptions, setupRoutes, smallTouchScreenSignal, stateSignal, stopLoad, stringifyTableSelectionValue, swapArrayItemByIndex, syncOwnedResourceToSignals, syncResourceToSignals, triggerNaviCommand, updateActions, useActionStatus, useArraySignalMembership, useAsyncData, useCalloutRequestClose, useCancelPrevious, useCellGridFromRows, useConstraintValidityState, useDependenciesDiff, useDisplayedLayoutEffect, useDocumentResource, useDocumentState, useDocumentUrl, useEditionController, useFocusGroup, useInputGroup, useKeyboardShortcuts, useNavState, useOrderedColumns, usePopupMode, useRouteStatus, useRunOnMount, useSearchText, useSelectableElement, useSelectionController, useSignalSync, useSlideValue, useStateArray, useTitleLevel, useUrlSearchParam, useUrlTargetId, valueInLocalStorage, windowWidthSignal };
|
|
75175
|
+
export { ActionRenderer, ActiveKeyboardShortcuts, Address, Badge, BadgeCount, BadgeList, Binder, Box, Button, ButtonCopyToClipboard, Caption, CardLayout, CheckSvg, CheckboxGroup, CloseSvg, Code, Col, Colgroup, Color, ConstructionSvg, ControlGroup, DaySpin, Details, Dialog, Editable, ErrorBoundary, ErrorBoundaryContext, ExclamationSvg, EyeClosedSvg, EyeSvg, Field, FixedBar, Form, Group, Head, HeartSvg, HomeSvg, Icon, Image, Input, InputDuration, Interpolate, Label, Link, LinkAnchorSvg, LinkBlankTargetSvg, LinkCurrentSvg, List, ListItem, ListItemGroup, ListItems, Loading, LoadingDotsSvg, LoadingIndicator, LoadingIndicatorFluid, LoadingOutline, MessageBox, Meter, Nav, NaviDebug, NumberSpin, 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, SummaryMarker, Svg, Table, TableCell, Tbody, Text, TextBox, Textarea, TextareaCharCount, Thead, Time, TimeRangeSpin, TimeSpin, Title, Tr, UITransition, Unit, UserSvg, ViewportLayout, Wheel, WheelGroup, WheelItem, actionRunEffect, anyMatchingRouteSignal, applySearch, arraySignalMembership, coarsePointerSignal, compareTwoJsValues, createAction, createAvailableConstraint, createI18n, createRequestCanceller, createSearch, createSelectionKeyboardShortcuts, createSlot, defineInteractionDetector, defineNaviConfirmPopupOptions, defineRouteDefaultTransition, defineRouteTransition, detectHorizontalOverflow, enableDebugActions, enableDebugOnDocumentLoading, ensureDocumentStartViewTransition, errorIsDisplayed, filterTableSelection, formatDatetime, formatDay, formatDayRelative, formatMonth, formatNumber, formatTime, formatTimeRelative, getNowHours, getNowHoursRoundedToStep, interpolateText, isCellSelected, isColumnSelected, isRowSelected, isScrolling, isToday, languagesSignal, localStorageSignal, markErrorAsDisplayedBy, moveArrayItemByIndex, navBack, navForward, navIntegratedVia, navTo, naviI18n, openCallout, rawUrlPart, registerGlobalConstraint, reload, rerunActions, resource, route, routeAction, scrollActivitySignal, setBaseUrl, setPreferredLanguage, setSupportedLanguages, setUrlTargetOptions, setupRoutes, smallTouchScreenSignal, stateSignal, stopLoad, stringifyTableSelectionValue, swapArrayItemByIndex, syncOwnedResourceToSignals, syncResourceToSignals, triggerNaviCommand, updateActions, useActionStatus, useArraySignalMembership, useAsyncData, useCalloutRequestClose, useCancelPrevious, useCellGridFromRows, useConstraintValidityState, useDependenciesDiff, useDisplayedLayoutEffect, useDocumentResource, useDocumentState, useDocumentUrl, useEditionController, useFocusGroup, useInputGroup, useKeyboardShortcuts, useNavState, useOrderedColumns, usePopupMode, useRouteStatus, useRunOnMount, useSearchText, useSelectableElement, useSelectionController, useSignalSync, useSlideValue, useStateArray, useTitleLevel, useUrlSearchParam, useUrlTargetId, valueInLocalStorage, windowWidthSignal };
|
|
75073
75176
|
//# sourceMappingURL=jsenv_navi.js.map
|