@jsenv/navi 0.29.167 → 0.29.168
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 +192 -105
- package/dist/jsenv_navi.js.map +17 -17
- package/docs/interactions.md +10 -0
- package/docs/popup_open.md +7 -0
- package/package.json +2 -2
package/dist/jsenv_navi.js
CHANGED
|
@@ -4,7 +4,7 @@
|
|
|
4
4
|
*/
|
|
5
5
|
import { installImportMetaCssBuild, windowHeightSignal, windowWidthSignal, visualViewportHeightSignal, visualViewportWidthSignal, getAppHeight, getAppWidth, coarsePointerSignal, smallTouchScreenSignal } from "./jsenv_navi_side_effects.js";
|
|
6
6
|
export { disableVirtualKeyboardOverlay } from "./jsenv_navi_side_effects.js";
|
|
7
|
-
import { elementIsFocusable, createIterableWeakSet, dispatchInternalCustomEvent, dispatchCustomEvent, getVisuallyVisibleInfo, getFirstVisuallyVisibleAncestor, getElementSignature, createPubSub, findEvent, createValueEffect, findFocusDelegateTarget, findFocusable, allowWheelThrough, dispatchPublicCustomEvent, resolveCSSColor, ELEMENT_SIZE_CHANGE, findSelfOrAncestorFixedPosition, visibleRectEffect, pickPositionRelativeTo, getBorderSizes, getPaddingSizes, applyNewPosition, measureLongestVisualLineWidth, chainEvent, waitForPressHeld, suppressClickAfterGesture, startDragToTravel, markDragSource, startDragTo, createEventGroupLogger, getKeyboardEventDefaultAction, activeElementSignal, normalizeStyle, mergeOneStyle, getPositionedParent, normalizeStyles, createGroupTransitionController, getBorderRadius, preventIntermediateScrollbar, createOpacityTransition, watchWheelTravel, scrollRoomTowards, getScrollContainer, closestOpenableAncestor, isAncestorOpen, isDisplayedDespiteClosedAncestor, observeAncestorOpenState, getAncestorOpenType, findBefore, findAfter, resolveCSSSize, hasCSSSizeUnit, releaseWheelGesture, getScrollIntoViewScopedOffsets, wheelGestureIsTakenFrom, claimWheelGesture, scrollIntoViewScoped, initFocusGroup, isTouchDrivenEvent, stringifyStyle as stringifyStyle$1, resolveOklchLightness, contrastColor, parsePositionArea, snapToPixel, trapFocusInside, trapScrollInside, onAncestorReopen, isPressDisputedByDrag, canScroll, measureWidestChildRow, performTabNavigation, dragAfterIntent, stickyAsRelativeCoords, createDragToMoveGestureController, getDropTargetInfo, setStyles, useActiveElement } from "@jsenv/dom";
|
|
7
|
+
import { elementIsFocusable, createIterableWeakSet, dispatchInternalCustomEvent, dispatchCustomEvent, getVisuallyVisibleInfo, getFirstVisuallyVisibleAncestor, getElementSignature, createPubSub, findEvent, createValueEffect, findFocusDelegateTarget, findFocusable, scrollIntoViewThroughScrollables, allowWheelThrough, dispatchPublicCustomEvent, resolveCSSColor, ELEMENT_SIZE_CHANGE, findSelfOrAncestorFixedPosition, visibleRectEffect, pickPositionRelativeTo, getBorderSizes, getPaddingSizes, applyNewPosition, measureLongestVisualLineWidth, chainEvent, waitForPressHeld, suppressClickAfterGesture, startDragToTravel, markDragSource, startDragTo, createEventGroupLogger, getKeyboardEventDefaultAction, activeElementSignal, normalizeStyle, mergeOneStyle, getPositionedParent, normalizeStyles, createGroupTransitionController, getBorderRadius, preventIntermediateScrollbar, createOpacityTransition, watchWheelTravel, scrollRoomTowards, getScrollContainer, closestOpenableAncestor, isAncestorOpen, isDisplayedDespiteClosedAncestor, observeAncestorOpenState, getAncestorOpenType, findBefore, findAfter, resolveCSSSize, hasCSSSizeUnit, releaseWheelGesture, getScrollIntoViewScopedOffsets, wheelGestureIsTakenFrom, claimWheelGesture, scrollIntoViewScoped, initFocusGroup, isTouchDrivenEvent, stringifyStyle as stringifyStyle$1, resolveOklchLightness, contrastColor, parsePositionArea, snapToPixel, trapFocusInside, trapScrollInside, onAncestorReopen, isPressDisputedByDrag, canScroll, measureWidestChildRow, performTabNavigation, dragAfterIntent, stickyAsRelativeCoords, createDragToMoveGestureController, getDropTargetInfo, setStyles, useActiveElement } from "@jsenv/dom";
|
|
8
8
|
export { chainEvent, clickIsSuppressed, contrastColor, findEvent, startDragTo } from "@jsenv/dom";
|
|
9
9
|
import { signal, computed, effect, untracked, batch, useComputed, useSignal } from "@preact/signals";
|
|
10
10
|
import { isValidElement, h, Fragment, createContext, render, toChildArray, options, cloneElement } from "preact";
|
|
@@ -7284,7 +7284,9 @@ const openCallout = (message, {
|
|
|
7284
7284
|
// that whole window: by the time anything measures anchorElement, it's
|
|
7285
7285
|
// already at its final position, so there's no transient frame left to
|
|
7286
7286
|
// latch onto.
|
|
7287
|
-
|
|
7287
|
+
// Through the boxes that scroll and none of the ones that only clip: an
|
|
7288
|
+
// `overflow: hidden` card takes a scroll no user can give back.
|
|
7289
|
+
scrollIntoViewThroughScrollables(anchorElement, {
|
|
7288
7290
|
behavior: "instant",
|
|
7289
7291
|
block: "nearest"
|
|
7290
7292
|
});
|
|
@@ -8276,13 +8278,20 @@ const formatCompactNumber = (value, lang) => {
|
|
|
8276
8278
|
* Formats a date as a human-readable day string.
|
|
8277
8279
|
*
|
|
8278
8280
|
* @param {Date} date
|
|
8279
|
-
* @param {{ lang?: string, format?: "long"|"short"|"narrow"|"numeric" }} [options]
|
|
8281
|
+
* @param {{ lang?: string, format?: "long"|"short"|"narrow"|"numeric"|{ weekday?: "long"|"short"|"narrow", month?: "long"|"short"|"narrow"|"numeric" } }} [options]
|
|
8282
|
+
* A string spells the weekday and the month the same way. An object spells
|
|
8283
|
+
* them apart, each key defaulting to `"long"`: a narrow card usually wants
|
|
8284
|
+
* the weekday whole (it is the reading anchor) and the month abbreviated (it
|
|
8285
|
+
* is where the characters are — "septembre" is 9 of them, "sept." reads the
|
|
8286
|
+
* same). `"numeric"` stays a string-only spelling: it drops the weekday and
|
|
8287
|
+
* writes the whole date in digits.
|
|
8280
8288
|
*
|
|
8281
8289
|
* @example
|
|
8282
8290
|
* formatDay(new Date(), { lang: "fr" }) // "lundi 11 mai" (long, default)
|
|
8283
8291
|
* formatDay(new Date(), { lang: "fr", format: "short" }) // "lun. 11 mai"
|
|
8284
8292
|
* formatDay(new Date(), { lang: "fr", format: "narrow" }) // "lu. 11 mai"
|
|
8285
8293
|
* formatDay(new Date(), { lang: "fr", format: "numeric" }) // "11/05/2026"
|
|
8294
|
+
* formatDay(new Date(), { lang: "fr", format: { weekday: "long", month: "short" } }) // "mercredi 2 sept."
|
|
8286
8295
|
*/
|
|
8287
8296
|
const formatDay = (
|
|
8288
8297
|
date,
|
|
@@ -8295,10 +8304,12 @@ const formatDay = (
|
|
|
8295
8304
|
year: "numeric",
|
|
8296
8305
|
}).format(date);
|
|
8297
8306
|
}
|
|
8307
|
+
const { weekday = "long", month = "long" } =
|
|
8308
|
+
typeof format === "string" ? { weekday: format, month: format } : format;
|
|
8298
8309
|
return new Intl.DateTimeFormat(lang, {
|
|
8299
|
-
weekday
|
|
8310
|
+
weekday, // "long", "short", or "narrow"
|
|
8300
8311
|
day: "numeric",
|
|
8301
|
-
month
|
|
8312
|
+
month,
|
|
8302
8313
|
}).format(date);
|
|
8303
8314
|
};
|
|
8304
8315
|
|
|
@@ -9909,7 +9920,7 @@ const formatDateIso = (iso, inputType) => {
|
|
|
9909
9920
|
const locale = languagesSignal.value;
|
|
9910
9921
|
if (inputType === "month") {
|
|
9911
9922
|
const date = new Date(`${iso}-01T00:00:00`);
|
|
9912
|
-
return formatMonth(date, locale);
|
|
9923
|
+
return formatMonth(date, { lang: locale });
|
|
9913
9924
|
}
|
|
9914
9925
|
// date, week, datetime-local: extract YYYY-MM-DD part and parse as local date
|
|
9915
9926
|
const isoMatch = /^(\d{4}-\d{2}-\d{2})/.exec(iso);
|
|
@@ -9921,7 +9932,7 @@ const formatDateIso = (iso, inputType) => {
|
|
|
9921
9932
|
if (isNaN(date.getTime())) {
|
|
9922
9933
|
return iso;
|
|
9923
9934
|
}
|
|
9924
|
-
return formatDay(date, locale);
|
|
9935
|
+
return formatDay(date, { lang: locale });
|
|
9925
9936
|
};
|
|
9926
9937
|
|
|
9927
9938
|
const READONLY_CONSTRAINT = {
|
|
@@ -11045,6 +11056,12 @@ installImportMetaCssBuild(import.meta);/**
|
|
|
11045
11056
|
* wants the right click to do what the hold does says so, with `contextmenu`
|
|
11046
11057
|
* beside it.
|
|
11047
11058
|
*
|
|
11059
|
+
* It DOES take the selection, and so does a swipe: nothing under either is text
|
|
11060
|
+
* to select, because the browser answers that same press by selecting the word
|
|
11061
|
+
* under the thumb and leaves it selected once its menu is gone. What never
|
|
11062
|
+
* answered the press keeps its text — a field, a popover, a dialog (see the
|
|
11063
|
+
* stylesheet below).
|
|
11064
|
+
*
|
|
11048
11065
|
* A hold CAN open a popup while the finger is still down — a menu appearing under
|
|
11049
11066
|
* a waiting finger, which is the native gesture. navi's Popover is `popover="manual"`
|
|
11050
11067
|
* and owns its own dismissal, so the `pointerup` that ends the press is not read as
|
|
@@ -11129,6 +11146,14 @@ import.meta.css = [/* css */`@property --swipe-progress {
|
|
|
11129
11146
|
-webkit-touch-callout: none;
|
|
11130
11147
|
}
|
|
11131
11148
|
|
|
11149
|
+
[data-longpress], [data-swipe] {
|
|
11150
|
+
user-select: none;
|
|
11151
|
+
}
|
|
11152
|
+
|
|
11153
|
+
:is([data-longpress], [data-swipe]) :is([data-drag-ignore], [popover], dialog), :is([data-longpress], [data-swipe]) :is(input:not([data-press-only]), textarea), :is([data-longpress], [data-swipe]) :is([contenteditable=""], [contenteditable="true"]) {
|
|
11154
|
+
user-select: text;
|
|
11155
|
+
}
|
|
11156
|
+
|
|
11132
11157
|
[data-swiping="left"], [data-swiping="right"] {
|
|
11133
11158
|
translate: var(--swipe-pulled) 0;
|
|
11134
11159
|
}
|
|
@@ -18925,9 +18950,15 @@ const getHowToHandleStyleProp = (name) => {
|
|
|
18925
18950
|
}
|
|
18926
18951
|
return getStyle;
|
|
18927
18952
|
};
|
|
18928
|
-
|
|
18953
|
+
// The css value `name` would take, written in the scale that style is read in:
|
|
18954
|
+
// "s" on a spacing style is a length, "s" on a typo style is a font size, and a
|
|
18955
|
+
// bare number gets the unit the style expects.
|
|
18956
|
+
const stringifyStyleValue = (value, name, styleContext) => {
|
|
18929
18957
|
const stringifier = getStringifier(name);
|
|
18930
|
-
|
|
18958
|
+
return stringifier(value, name, styleContext);
|
|
18959
|
+
};
|
|
18960
|
+
const prepareStyleValue = (existingValue, value, name, styleContext) => {
|
|
18961
|
+
const cssValue = stringifyStyleValue(value, name, styleContext);
|
|
18931
18962
|
const mergedValue = mergeOneStyle(existingValue, cssValue, name, "css");
|
|
18932
18963
|
return mergedValue;
|
|
18933
18964
|
};
|
|
@@ -20963,6 +20994,15 @@ import.meta.css = [/* css */`[data-scrollable] > .navi_loading_outline_wrapper,
|
|
|
20963
20994
|
const PSEUDO_CLASSES_DEFAULT = [];
|
|
20964
20995
|
const PSEUDO_ELEMENTS_DEFAULT = [];
|
|
20965
20996
|
const STYLE_CSS_VARS_DEFAULT = {};
|
|
20997
|
+
// An entry of styleCSSVars is the css variable the prop writes into, alone when
|
|
20998
|
+
// the prop is named after a css style — Box then already knows how to read its
|
|
20999
|
+
// value — or paired with the style whose values it borrows when it is not.
|
|
21000
|
+
const readCSSVarEntry = entry => {
|
|
21001
|
+
if (Array.isArray(entry)) {
|
|
21002
|
+
return entry;
|
|
21003
|
+
}
|
|
21004
|
+
return [entry, null];
|
|
21005
|
+
};
|
|
20966
21006
|
// When only pseudoStateSelector is set (no visualSelector), the box owns its
|
|
20967
21007
|
// visual identity. Only event handlers and these explicit props are forwarded
|
|
20968
21008
|
// to the inner semantic/interactive child element.
|
|
@@ -20973,7 +21013,7 @@ const PSEUDO_STATE_CHILD_PROP_SET = new Set(["tabIndex", "tabindex"]);
|
|
|
20973
21013
|
* as?: string,
|
|
20974
21014
|
* className?: string,
|
|
20975
21015
|
* style?: import("ignore:preact").JSX.CSSProperties & { [pseudo: string]: import("ignore:preact").JSX.CSSProperties },
|
|
20976
|
-
* styleCSSVars?: { [
|
|
21016
|
+
* styleCSSVars?: { [propName: string]: string | [string, string] },
|
|
20977
21017
|
* inline?: boolean,
|
|
20978
21018
|
* block?: boolean,
|
|
20979
21019
|
* flex?: "x" | "y" | boolean,
|
|
@@ -21334,7 +21374,7 @@ const computeBox = (props, parentBoxFlow) => {
|
|
|
21334
21374
|
const canForwardToChild = hasChildUsingForwardedProps;
|
|
21335
21375
|
const addStyle = (value, name, styleContext, stylesTarget) => {
|
|
21336
21376
|
const mergedValue = prepareStyleValue(stylesTarget[name], value, name, styleContext);
|
|
21337
|
-
const cssVar = styleContext.styleCSSVars[name];
|
|
21377
|
+
const [cssVar] = readCSSVarEntry(styleContext.styleCSSVars[name]);
|
|
21338
21378
|
if (cssVar) {
|
|
21339
21379
|
addCSSVar(mergedValue, cssVar, stylesTarget);
|
|
21340
21380
|
if (name === "borderRadius" && value === "inherit") {
|
|
@@ -21455,10 +21495,18 @@ const computeBox = (props, parentBoxFlow) => {
|
|
|
21455
21495
|
}
|
|
21456
21496
|
return;
|
|
21457
21497
|
}
|
|
21458
|
-
const
|
|
21459
|
-
if (
|
|
21498
|
+
const cssVarEntry = styleCSSVars[name];
|
|
21499
|
+
if (cssVarEntry) {
|
|
21460
21500
|
if (value !== undefined) {
|
|
21461
|
-
|
|
21501
|
+
const [cssVarName, valueStyleName] = readCSSVarEntry(cssVarEntry);
|
|
21502
|
+
const cssValue = valueStyleName ? stringifyStyleValue(value, valueStyleName, styleContext) : value;
|
|
21503
|
+
if (isSizeSpacingKey(cssValue)) {
|
|
21504
|
+
// A size keyword reaching a custom property stays that word: every
|
|
21505
|
+
// declaration reading the variable is then invalid, drops back to
|
|
21506
|
+
// its initial value, and says nothing about it.
|
|
21507
|
+
console.warn(`"${name}" cannot take the size keyword "${cssValue}": it goes into ${cssVarName} as-is, which makes every declaration reading that variable invalid. Pass "${stringifySpacingStyle(cssValue)}" instead.`);
|
|
21508
|
+
}
|
|
21509
|
+
addCSSVar(cssValue, cssVarName, boxStylesTarget);
|
|
21462
21510
|
}
|
|
21463
21511
|
return;
|
|
21464
21512
|
}
|
|
@@ -31253,7 +31301,32 @@ const anyMatchingRouteSignal = (routes) => {
|
|
|
31253
31301
|
* when that is not the element asking: a menu opened by a press belongs at the
|
|
31254
31302
|
* point the press happened, and the row that was pressed is not that point.
|
|
31255
31303
|
*/
|
|
31256
|
-
const triggerNaviCommand = (
|
|
31304
|
+
const triggerNaviCommand = (element, command, event, options) => {
|
|
31305
|
+
const run = resolveNaviCommand(element, command, event, options);
|
|
31306
|
+
return run ? run() : false;
|
|
31307
|
+
};
|
|
31308
|
+
|
|
31309
|
+
/**
|
|
31310
|
+
* The same command, in its two moments: WHAT it aims at, decided here and now,
|
|
31311
|
+
* and what it then does, in the function returned. One caller needs them apart
|
|
31312
|
+
* — a button whose command waits for its own action (see the command trigger in
|
|
31313
|
+
* ui_state_controller.js) — and it needs it because resolution reads the DOM
|
|
31314
|
+
* AROUND the source: the closest expandable, the parent control, the slide it
|
|
31315
|
+
* stands in. An action that succeeds has usually re-rendered the tree it was
|
|
31316
|
+
* asked from, which is what an action is for, so by then the source is
|
|
31317
|
+
* detached: `closest` walks a subtree the popup is no longer in, and a command
|
|
31318
|
+
* that had a perfectly good target at the press finds none and is dropped with
|
|
31319
|
+
* a warning — the popup stays open over a request that went through.
|
|
31320
|
+
*
|
|
31321
|
+
* Freezing the target at the press is also what one means by it: the popup
|
|
31322
|
+
* pressed in is the popup to close, even when the press is what emptied it.
|
|
31323
|
+
* What the command DOES stays live — every handler reads the state it needs
|
|
31324
|
+
* inside its implementation, never while resolving.
|
|
31325
|
+
*
|
|
31326
|
+
* Returns undefined when there is nothing to run (unknown command, no target).
|
|
31327
|
+
* See triggerNaviCommand's jsdoc for the parameters.
|
|
31328
|
+
*/
|
|
31329
|
+
const resolveNaviCommand = (
|
|
31257
31330
|
element,
|
|
31258
31331
|
command,
|
|
31259
31332
|
event,
|
|
@@ -31268,7 +31341,7 @@ const triggerNaviCommand = (
|
|
|
31268
31341
|
NAVI_COMMANDS[command] || NAVI_COMMANDS[commandName(command)];
|
|
31269
31342
|
if (!naviCommand) {
|
|
31270
31343
|
console.warn(`Unknown command "${command}"`);
|
|
31271
|
-
return
|
|
31344
|
+
return undefined;
|
|
31272
31345
|
}
|
|
31273
31346
|
// Check for explicit HTML target overrides early so a misconfigured commandfor
|
|
31274
31347
|
// attribute (id not found) aborts immediately rather than silently falling back
|
|
@@ -31276,7 +31349,7 @@ const triggerNaviCommand = (
|
|
|
31276
31349
|
const explicitTarget = resolveExplicitTarget(element);
|
|
31277
31350
|
if (explicitTarget === null) {
|
|
31278
31351
|
// attribute was present but target not found — already warned inside resolveExplicitTarget
|
|
31279
|
-
return
|
|
31352
|
+
return undefined;
|
|
31280
31353
|
}
|
|
31281
31354
|
const execute = naviCommand.commandHandler(element, event, {
|
|
31282
31355
|
// Whatever followed the colon: "--navi-go-to-slide:edit" → "edit".
|
|
@@ -31289,37 +31362,40 @@ const triggerNaviCommand = (
|
|
|
31289
31362
|
});
|
|
31290
31363
|
if (!execute) {
|
|
31291
31364
|
if (optional) {
|
|
31292
|
-
return
|
|
31365
|
+
return undefined;
|
|
31293
31366
|
}
|
|
31294
31367
|
console.warn(
|
|
31295
31368
|
`"${command}" triggered on element but no suitable target found`,
|
|
31296
31369
|
element,
|
|
31297
31370
|
);
|
|
31298
|
-
return
|
|
31371
|
+
return undefined;
|
|
31299
31372
|
}
|
|
31300
31373
|
const { target, implementation } = execute;
|
|
31301
|
-
|
|
31302
|
-
|
|
31303
|
-
|
|
31304
|
-
|
|
31305
|
-
|
|
31306
|
-
|
|
31307
|
-
|
|
31308
|
-
|
|
31309
|
-
|
|
31310
|
-
|
|
31311
|
-
|
|
31312
|
-
|
|
31313
|
-
|
|
31314
|
-
|
|
31315
|
-
|
|
31316
|
-
|
|
31374
|
+
return () => {
|
|
31375
|
+
// The event is how the target takes part in what it was asked to do (a
|
|
31376
|
+
// popup closing on --navi-close also has its own things to do); the command
|
|
31377
|
+
// itself is the implementation, and it must not depend on someone
|
|
31378
|
+
// listening. Nobody does when the target has left the document — a trigger
|
|
31379
|
+
// whose own action took it away, which is the shape of "delete this, then
|
|
31380
|
+
// leave the page it was on" (see runWhenActionSucceeded in
|
|
31381
|
+
// rules/control_action.js): the command was decided above, while the
|
|
31382
|
+
// trigger was there, and runs once the action has succeeded, by which time
|
|
31383
|
+
// the row it stood in is gone. So the command runs here rather than being
|
|
31384
|
+
// lost in silence.
|
|
31385
|
+
const detail = {
|
|
31386
|
+
command,
|
|
31387
|
+
event,
|
|
31388
|
+
source: element,
|
|
31389
|
+
implementation,
|
|
31390
|
+
value,
|
|
31391
|
+
answered: false,
|
|
31392
|
+
};
|
|
31393
|
+
const dispatched = dispatchCustomEvent(target, "navi_command", detail);
|
|
31394
|
+
if (!detail.answered) {
|
|
31395
|
+
implementation();
|
|
31396
|
+
}
|
|
31397
|
+
return dispatched;
|
|
31317
31398
|
};
|
|
31318
|
-
const dispatched = dispatchCustomEvent(target, "navi_command", detail);
|
|
31319
|
-
if (!detail.answered) {
|
|
31320
|
-
implementation();
|
|
31321
|
-
}
|
|
31322
|
-
return dispatched;
|
|
31323
31399
|
};
|
|
31324
31400
|
|
|
31325
31401
|
// Returns the target explicitly declared via HTML attributes (commandfor / navi-command-target),
|
|
@@ -33731,18 +33807,26 @@ const useUIStateController = (
|
|
|
33731
33807
|
debugUIState(
|
|
33732
33808
|
`triggering command "${command}" for "${controlType}"`,
|
|
33733
33809
|
);
|
|
33734
|
-
const runCommand = () => {
|
|
33735
|
-
triggerNaviCommand(element, command, e);
|
|
33736
|
-
};
|
|
33737
33810
|
// What the press means may not be due yet: a button with an
|
|
33738
33811
|
// action of its own runs the work first and lets its command
|
|
33739
33812
|
// follow only once that work succeeded (see control_hooks).
|
|
33740
33813
|
// The command is handed over rather than run; nobody claiming
|
|
33741
33814
|
// it means now.
|
|
33815
|
+
//
|
|
33816
|
+
// Only the RUN waits. What the command aims at is decided here,
|
|
33817
|
+
// while the button is still in the document, because that is
|
|
33818
|
+
// what resolving reads — the popup around it, the control above
|
|
33819
|
+
// it — and the action it waits for is likely to re-render that
|
|
33820
|
+
// away before it succeeds. Resolved late, the command would
|
|
33821
|
+
// find nothing to aim at and be dropped (see
|
|
33822
|
+
// resolveNaviCommand).
|
|
33742
33823
|
if (controller.commandDeferral) {
|
|
33743
|
-
|
|
33824
|
+
const runCommand = resolveNaviCommand(element, command, e);
|
|
33825
|
+
if (runCommand) {
|
|
33826
|
+
controller.commandDeferral(runCommand);
|
|
33827
|
+
}
|
|
33744
33828
|
} else {
|
|
33745
|
-
|
|
33829
|
+
triggerNaviCommand(element, command, e);
|
|
33746
33830
|
}
|
|
33747
33831
|
}
|
|
33748
33832
|
}
|
|
@@ -36355,6 +36439,14 @@ const useControlProps = (props, {
|
|
|
36355
36439
|
return false;
|
|
36356
36440
|
}
|
|
36357
36441
|
const control = ref.current;
|
|
36442
|
+
if (!control) {
|
|
36443
|
+
// The ui action the reaction ran a line earlier is free to take this
|
|
36444
|
+
// control away: a list row answering its popup's question closes it, and
|
|
36445
|
+
// mount="while-opened" unmounts the row. Nothing left to read a value
|
|
36446
|
+
// from, and what the press was for has already happened (the button and
|
|
36447
|
+
// link reactions bail on the same ground).
|
|
36448
|
+
return false;
|
|
36449
|
+
}
|
|
36358
36450
|
const currentValue = readControlValue(control);
|
|
36359
36451
|
// For checkables: skip value dedup. The browser only fires `input` when state
|
|
36360
36452
|
// actually changes, so there is no spurious double-dispatch to guard against.
|
|
@@ -41904,7 +41996,7 @@ const NavStyleCSSVars = {
|
|
|
41904
41996
|
paddingLeft: "--nav-padding-left",
|
|
41905
41997
|
background: "--nav-background",
|
|
41906
41998
|
currentIndicatorColor: "--nav-current-indicator-color",
|
|
41907
|
-
currentIndicatorSize: "--nav-current-indicator-size"
|
|
41999
|
+
currentIndicatorSize: ["--nav-current-indicator-size", "height"]
|
|
41908
42000
|
};
|
|
41909
42001
|
const positionOfCurrentIndicator = (currentIndicator, vertical) => {
|
|
41910
42002
|
if (currentIndicator === true) {
|
|
@@ -42999,7 +43091,7 @@ const css$V = /* css */`@layer navi {
|
|
|
42999
43091
|
const BinderStyleCSSVars = {
|
|
43000
43092
|
borderWidth: "--binder-border-width",
|
|
43001
43093
|
borderRadius: "--binder-border-radius",
|
|
43002
|
-
tabBorderRadius: "--binder-tab-border-radius",
|
|
43094
|
+
tabBorderRadius: ["--binder-tab-border-radius", "borderRadius"],
|
|
43003
43095
|
borderColor: "--binder-border-color",
|
|
43004
43096
|
background: "--binder-background",
|
|
43005
43097
|
tabBackground: "--binder-tab-background",
|
|
@@ -43008,7 +43100,7 @@ const BinderStyleCSSVars = {
|
|
|
43008
43100
|
tabColor: "--binder-tab-color",
|
|
43009
43101
|
paddingX: "--binder-padding-x",
|
|
43010
43102
|
paddingY: "--binder-padding-y",
|
|
43011
|
-
pagePadding: "--binder-page-padding"
|
|
43103
|
+
pagePadding: ["--binder-page-padding", "padding"]
|
|
43012
43104
|
};
|
|
43013
43105
|
const TABS_ALIGN_TO_JUSTIFY_CONTENT = {
|
|
43014
43106
|
start: "flex-start",
|
|
@@ -43159,12 +43251,12 @@ const Binder = ({
|
|
|
43159
43251
|
"data-tabs-position": tabsPosition,
|
|
43160
43252
|
"data-tabs-align": tabsAlign,
|
|
43161
43253
|
"data-scrollable-page": scrollablePage ? "" : undefined,
|
|
43162
|
-
borderWidth:
|
|
43163
|
-
borderRadius:
|
|
43164
|
-
tabBorderRadius:
|
|
43165
|
-
paddingX:
|
|
43166
|
-
paddingY:
|
|
43167
|
-
pagePadding:
|
|
43254
|
+
borderWidth: borderWidth,
|
|
43255
|
+
borderRadius: borderRadius,
|
|
43256
|
+
tabBorderRadius: tabBorderRadius,
|
|
43257
|
+
paddingX: paddingX,
|
|
43258
|
+
paddingY: paddingY,
|
|
43259
|
+
pagePadding: pagePadding,
|
|
43168
43260
|
...props,
|
|
43169
43261
|
styleCSSVars: BinderStyleCSSVars,
|
|
43170
43262
|
children: [jsx(BinderOutline, {
|
|
@@ -43397,15 +43489,6 @@ const measureDrawing = ({
|
|
|
43397
43489
|
};
|
|
43398
43490
|
};
|
|
43399
43491
|
|
|
43400
|
-
// A bare number in a CSS var stays a bare number and the declaration is
|
|
43401
|
-
// dropped; every length prop here is in pixels when it is not spelled out.
|
|
43402
|
-
const withPixelUnit = value => {
|
|
43403
|
-
if (typeof value === "number") {
|
|
43404
|
-
return `${value}px`;
|
|
43405
|
-
}
|
|
43406
|
-
return value;
|
|
43407
|
-
};
|
|
43408
|
-
|
|
43409
43492
|
/**
|
|
43410
43493
|
* How much room the fixed bars take on each edge, published for the safe area
|
|
43411
43494
|
* to add up (see layout/safe_area.js — it declares the four variables written
|
|
@@ -48121,14 +48204,13 @@ const FieldAsLabel = props => {
|
|
|
48121
48204
|
});
|
|
48122
48205
|
};
|
|
48123
48206
|
const FieldCSSVars = {
|
|
48124
|
-
spacingWithControl: "--spacing-with-control"
|
|
48207
|
+
spacingWithControl: ["--spacing-with-control", "padding"]
|
|
48125
48208
|
};
|
|
48126
48209
|
const FieldAsContainer = props => {
|
|
48127
48210
|
import.meta.css = [css$L, "@jsenv/navi/src/control/field.jsx"];
|
|
48128
48211
|
const {
|
|
48129
48212
|
children
|
|
48130
48213
|
} = props;
|
|
48131
|
-
props.spacingWithControl = resolveSpacingSize(props.spacingWithControl);
|
|
48132
48214
|
const isVertical = props.flex === "y";
|
|
48133
48215
|
const [messageProps, remainingProps] = extractMessageAndRemainingProps({
|
|
48134
48216
|
...props,
|
|
@@ -50242,10 +50324,6 @@ const useInputTextualProps = props => {
|
|
|
50242
50324
|
};
|
|
50243
50325
|
const InputTextualUI = props => {
|
|
50244
50326
|
installInputCss();
|
|
50245
|
-
// Spacing props travel to CSS as a raw custom property value, so the size
|
|
50246
|
-
// keywords have to become lengths here — "s" reaching CSS untouched makes the
|
|
50247
|
-
// declaration invalid, silently, and the gap just goes away.
|
|
50248
|
-
props.slotSpacing = resolveSpacingSize(props.slotSpacing);
|
|
50249
50327
|
const {
|
|
50250
50328
|
ui,
|
|
50251
50329
|
variant,
|
|
@@ -50450,7 +50528,7 @@ const RealInput = ({
|
|
|
50450
50528
|
// Shared with textarea.jsx: a textarea is styled as a .navi_input box, so the
|
|
50451
50529
|
// two read the same style props and pseudo states.
|
|
50452
50530
|
const InputStyleCSSVars = {
|
|
50453
|
-
"slotSpacing": "--slot-spacing",
|
|
50531
|
+
"slotSpacing": ["--slot-spacing", "margin"],
|
|
50454
50532
|
"outlineWidth": "--outline-width",
|
|
50455
50533
|
"borderWidth": "--border-width",
|
|
50456
50534
|
"borderRadius": "--border-radius",
|
|
@@ -51088,6 +51166,10 @@ const css$I = /* css */`.navi_textarea {
|
|
|
51088
51166
|
}
|
|
51089
51167
|
}
|
|
51090
51168
|
|
|
51169
|
+
&[data-width-from-container] {
|
|
51170
|
+
contain: inline-size;
|
|
51171
|
+
}
|
|
51172
|
+
|
|
51091
51173
|
&[data-resizable] {
|
|
51092
51174
|
& .navi_control_input {
|
|
51093
51175
|
height: calc(var(--textarea-min-rows, 1.5) * 1lh);
|
|
@@ -51138,9 +51220,13 @@ const TextareaStyleCSSVars = {
|
|
|
51138
51220
|
* @param {number} [maxLength] The character limit, validated at submit. Pair
|
|
51139
51221
|
* with `maxLengthGuard` to block typing past it, and render a
|
|
51140
51222
|
* TextareaCharCount to show it.
|
|
51141
|
-
* @param {string} [width="35ch"] The control's width.
|
|
51142
|
-
* field-sizing the width would otherwise follow the longest
|
|
51143
|
-
* that widens while one types is a box one chases.
|
|
51223
|
+
* @param {string} [width="35ch"] The control's width. A length by default, on
|
|
51224
|
+
* purpose: with field-sizing the width would otherwise follow the longest
|
|
51225
|
+
* line, and a box that widens while one types is a box one chases. A
|
|
51226
|
+
* percentage means "fill what contains me" and holds the same promise — the
|
|
51227
|
+
* control then takes the width it is given without having a say in it, even
|
|
51228
|
+
* inside a container that sizes itself from its content (a Popover, a
|
|
51229
|
+
* Picker's popup), where the text wraps instead of widening the popup.
|
|
51144
51230
|
*/
|
|
51145
51231
|
const Textarea = ({
|
|
51146
51232
|
// Destructured, never deleted off the props object: Preact reuses the same
|
|
@@ -51167,8 +51253,21 @@ const Textarea = ({
|
|
|
51167
51253
|
// element they would become its text content.
|
|
51168
51254
|
delete hostProps.children;
|
|
51169
51255
|
const loading = basePseudoState[":-navi-loading"];
|
|
51256
|
+
|
|
51257
|
+
// A percentage is not a definite length: while a container is being sized
|
|
51258
|
+
// from its content it cannot be resolved, so the box falls back to its own
|
|
51259
|
+
// max-content — which `field-sizing: content` makes the longest line typed,
|
|
51260
|
+
// and the field widens the very box it asked to fill. The CSS above takes
|
|
51261
|
+
// that vote away, which is why the percentage lands on the contained box
|
|
51262
|
+
// rather than on the field: the field fills it from the inside (flex-grow
|
|
51263
|
+
// in input_css.js).
|
|
51264
|
+
const widthFromContainer = String(width).includes("%");
|
|
51170
51265
|
delete rootProps.width;
|
|
51171
|
-
|
|
51266
|
+
if (widthFromContainer) {
|
|
51267
|
+
rootProps.width = width;
|
|
51268
|
+
} else {
|
|
51269
|
+
hostProps.width = width;
|
|
51270
|
+
}
|
|
51172
51271
|
return jsxs(Box, {
|
|
51173
51272
|
as: "span",
|
|
51174
51273
|
inline: true,
|
|
@@ -51177,6 +51276,7 @@ const Textarea = ({
|
|
|
51177
51276
|
...rootProps,
|
|
51178
51277
|
basePseudoState: basePseudoState,
|
|
51179
51278
|
"data-resizable": resizable ? "" : undefined,
|
|
51279
|
+
"data-width-from-container": widthFromContainer ? "" : undefined,
|
|
51180
51280
|
styleCSSVars: TextareaStyleCSSVars,
|
|
51181
51281
|
pseudoStateSelector: ".navi_control_input",
|
|
51182
51282
|
pseudoClasses: InputPseudoClasses,
|
|
@@ -68801,16 +68901,6 @@ const PickerButton = props => {
|
|
|
68801
68901
|
if (typeof props.maxLines === "string") {
|
|
68802
68902
|
props.maxLines = parseInt(props.maxLines);
|
|
68803
68903
|
}
|
|
68804
|
-
// Spacing props travel to CSS as a raw custom property value, so the size
|
|
68805
|
-
// keywords have to become lengths here — "s" reaching CSS untouched makes
|
|
68806
|
-
// the declaration invalid, silently, and the gap just goes away.
|
|
68807
|
-
props.slotSpacing = resolveSpacingSize(props.slotSpacing);
|
|
68808
|
-
for (const pressPaddingPropName of PRESS_PADDING_PROP_NAMES) {
|
|
68809
|
-
const pressPadding = props[pressPaddingPropName];
|
|
68810
|
-
if (pressPadding !== undefined) {
|
|
68811
|
-
props[pressPaddingPropName] = stringifySpacingStyle(pressPadding);
|
|
68812
|
-
}
|
|
68813
|
-
}
|
|
68814
68904
|
const {
|
|
68815
68905
|
ref,
|
|
68816
68906
|
variant,
|
|
@@ -69408,32 +69498,29 @@ const NON_MOBILE_KEYBOARD_TYPES = new Set(["date", "month", "week", "time", "dat
|
|
|
69408
69498
|
const PICKER_BUTTON_PSEUDO_CLASSES = [":hover", ":focus", ":focus-visible", ":focus-within", ":read-only", ":disabled", ":-navi-loading", ":-navi-expanded", ":-navi-has-value"];
|
|
69409
69499
|
const PickerInputPseudoClasses = [":focus", ":focus-visible", ":read-only", ":disabled", ":-navi-loading", ":-navi-has-value", ":-navi-expanded"];
|
|
69410
69500
|
|
|
69411
|
-
//
|
|
69412
|
-
//
|
|
69413
|
-
//
|
|
69414
|
-
// invalid and drops the press area back to the box. Hence the pass in
|
|
69415
|
-
// PickerButton, which turns them into lengths.
|
|
69416
|
-
const PRESS_PADDING_PROP_NAMES = ["pressPadding", "pressPaddingX", "pressPaddingY", "pressPaddingTop", "pressPaddingRight", "pressPaddingBottom", "pressPaddingLeft"];
|
|
69501
|
+
// A pair is [the css variable, the style whose values the prop is written in]:
|
|
69502
|
+
// popupBorderRadius takes what borderRadius takes, dialogMinWidth what minWidth
|
|
69503
|
+
// takes — see box.jsx's readCSSVarEntry.
|
|
69417
69504
|
const PickerStyleCSSVars = {
|
|
69418
69505
|
"outlineWidth": "--picker-outline-width",
|
|
69419
69506
|
"borderWidth": "--picker-border-width",
|
|
69420
69507
|
"borderRadius": "--picker-border-radius",
|
|
69421
|
-
"popoverMaxHeight": "--picker-popover-max-height",
|
|
69422
|
-
"dialogMinWidth": "--picker-dialog-min-width",
|
|
69423
|
-
"dialogMinHeight": "--picker-dialog-min-height",
|
|
69424
|
-
"dialogMaxWidth": "--picker-dialog-max-width",
|
|
69425
|
-
"dialogMaxHeight": "--picker-dialog-max-height",
|
|
69508
|
+
"popoverMaxHeight": ["--picker-popover-max-height", "maxHeight"],
|
|
69509
|
+
"dialogMinWidth": ["--picker-dialog-min-width", "minWidth"],
|
|
69510
|
+
"dialogMinHeight": ["--picker-dialog-min-height", "minHeight"],
|
|
69511
|
+
"dialogMaxWidth": ["--picker-dialog-max-width", "maxWidth"],
|
|
69512
|
+
"dialogMaxHeight": ["--picker-dialog-max-height", "maxHeight"],
|
|
69426
69513
|
"popupBackgroundColor": "--picker-popup-background-color",
|
|
69427
|
-
"popupBorderRadius": "--picker-popup-border-radius",
|
|
69428
|
-
"dialogBorderWidth": "--picker-dialog-border-width",
|
|
69429
|
-
"slotSpacing": "--picker-slot-spacing",
|
|
69430
|
-
"pressPadding": "--picker-press-padding",
|
|
69431
|
-
"pressPaddingX": "--picker-press-padding-x",
|
|
69432
|
-
"pressPaddingY": "--picker-press-padding-y",
|
|
69433
|
-
"pressPaddingTop": "--picker-press-padding-top",
|
|
69434
|
-
"pressPaddingRight": "--picker-press-padding-right",
|
|
69435
|
-
"pressPaddingBottom": "--picker-press-padding-bottom",
|
|
69436
|
-
"pressPaddingLeft": "--picker-press-padding-left",
|
|
69514
|
+
"popupBorderRadius": ["--picker-popup-border-radius", "borderRadius"],
|
|
69515
|
+
"dialogBorderWidth": ["--picker-dialog-border-width", "borderWidth"],
|
|
69516
|
+
"slotSpacing": ["--picker-slot-spacing", "margin"],
|
|
69517
|
+
"pressPadding": ["--picker-press-padding", "padding"],
|
|
69518
|
+
"pressPaddingX": ["--picker-press-padding-x", "padding"],
|
|
69519
|
+
"pressPaddingY": ["--picker-press-padding-y", "padding"],
|
|
69520
|
+
"pressPaddingTop": ["--picker-press-padding-top", "padding"],
|
|
69521
|
+
"pressPaddingRight": ["--picker-press-padding-right", "padding"],
|
|
69522
|
+
"pressPaddingBottom": ["--picker-press-padding-bottom", "padding"],
|
|
69523
|
+
"pressPaddingLeft": ["--picker-press-padding-left", "padding"],
|
|
69437
69524
|
// alignX/alignY resolve to these two on a flex-x box; naming the CSS style
|
|
69438
69525
|
// (not the prop) is what styleCSSVars matches, so justifyContent/alignItems
|
|
69439
69526
|
// passed directly land in the same variables.
|