@jsenv/navi 0.29.388 → 0.29.389
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/dist/dev/jsenv_navi.js +163 -89
- package/dist/dev/jsenv_navi.js.map +18 -18
- package/dist/dev/jsenv_navi_side_effects.js +87 -78
- package/dist/dev/jsenv_navi_side_effects.js.map +4 -4
- package/dist/jsenv_navi.js +162 -88
- package/dist/jsenv_navi.js.map +18 -18
- package/dist/jsenv_navi_side_effects.js +87 -78
- package/dist/jsenv_navi_side_effects.js.map +4 -4
- package/docs/dialog_shape.md +3 -2
- package/docs/drag_interactions.md +5 -5
- package/docs/drag_to_travel.md +3 -1
- package/docs/error_handling.md +5 -3
- package/docs/i18n.md +16 -7
- package/docs/list_refresh.md +5 -4
- package/docs/network_policy.md +12 -4
- package/docs/pan_zoom.md +14 -7
- package/docs/resource.md +8 -4
- package/docs/safe_area.md +28 -24
- package/package.json +2 -2
package/dist/dev/jsenv_navi.js
CHANGED
|
@@ -554,7 +554,10 @@ effect(() => {
|
|
|
554
554
|
* The active language is read from `languagesSignal` (see lang_signal.js —
|
|
555
555
|
* combines the browser's own `navigator.languages`, an optional
|
|
556
556
|
* `setPreferredLanguage()` user override, and an optional
|
|
557
|
-
* `setSupportedLanguages()` app-wide allow-list), live on every lookup.
|
|
557
|
+
* `setSupportedLanguages()` app-wide allow-list), live on every lookup. Each
|
|
558
|
+
* key is looked up in those languages in order, then in English, which
|
|
559
|
+
* translates every key: a language shipped for part of the keys only (German
|
|
560
|
+
* has the `time.*` words) never shows a raw key.
|
|
558
561
|
*
|
|
559
562
|
* Built-in key namespaces, all overridable — the registrations below are the
|
|
560
563
|
* exhaustive list, read them to find the exact key to override:
|
|
@@ -1474,19 +1477,25 @@ const isNetworkPolicyError = (error) => {
|
|
|
1474
1477
|
* is already saying it in words the person understands.
|
|
1475
1478
|
*
|
|
1476
1479
|
* navi's own report leaves it alone (action_error_report.js). What is left is
|
|
1477
|
-
* the
|
|
1478
|
-
*
|
|
1479
|
-
*
|
|
1480
|
-
*
|
|
1481
|
-
* asked. Cancelling the event is what says it is handled: the browser drops
|
|
1480
|
+
* the error reaching `window` on its own — a run called by hand whose failure
|
|
1481
|
+
* nobody catches, a render throw no boundary took — where it lands as an
|
|
1482
|
+
* uncaught error in the console, about a request the app itself declared would
|
|
1483
|
+
* not leave. Cancelling the event is what says it is handled: the browser drops
|
|
1482
1484
|
* the console line, and the jsenv supervisor skips prevented events too.
|
|
1483
1485
|
*
|
|
1484
1486
|
* Both shapes a failure travels in are covered, since which one it is depends
|
|
1485
1487
|
* on whether the resource callback happened to be async — the throw reaching
|
|
1486
1488
|
* `window`, and the rejection nobody caught.
|
|
1487
1489
|
*
|
|
1488
|
-
*
|
|
1489
|
-
*
|
|
1490
|
+
* A boundary displaying it raises no event at all. In dev, `preact/debug` hands
|
|
1491
|
+
* every error a boundary caught to `console.error`, after the boundary took it
|
|
1492
|
+
* and before it rendered anything; it reads no option and no flag, so that line
|
|
1493
|
+
* stays. Muting it from here is not done: wrapping `console.error` rewrites a
|
|
1494
|
+
* global, and wrapping `options._catchError` reaches into preact's private
|
|
1495
|
+
* hooks, both to hide one class of error.
|
|
1496
|
+
*
|
|
1497
|
+
* Scoped to the policy's own error and to nothing else — every other error
|
|
1498
|
+
* thrown at window, and every other rejection let go, stays exactly as loud as
|
|
1490
1499
|
* it is.
|
|
1491
1500
|
*/
|
|
1492
1501
|
let networkPolicyErrorSilenced = false;
|
|
@@ -1652,8 +1661,8 @@ const markErrorAsStoppingRender = (error) => {
|
|
|
1652
1661
|
* An error the network policy produced is never reported: the app declared the
|
|
1653
1662
|
* state that produced it, the request never left, and there is nothing for a
|
|
1654
1663
|
* developer to fix. It is data a screen shows, and it stays data whether or not
|
|
1655
|
-
* one does (see network_policy.js, which also
|
|
1656
|
-
*
|
|
1664
|
+
* one does (see network_policy.js, which also cancels it when it reaches
|
|
1665
|
+
* window).
|
|
1657
1666
|
*/
|
|
1658
1667
|
const errorIsAccountedFor = (error) => {
|
|
1659
1668
|
return (
|
|
@@ -12640,8 +12649,9 @@ defineInteractionDetector({
|
|
|
12640
12649
|
name: "surface",
|
|
12641
12650
|
claims: (type) =>
|
|
12642
12651
|
type === PAN || type === ZOOM || type === GRAB || type === RELEASE,
|
|
12643
|
-
// A press on the surface may be a tap, a hold or the
|
|
12644
|
-
// nothing may read it as the first until the pointer has said
|
|
12652
|
+
// A press on the surface may be a tap, a hold or the first finger of a pan or
|
|
12653
|
+
// a pinch, and nothing may read it as the first until the pointer has said
|
|
12654
|
+
// which.
|
|
12645
12655
|
disputesPress: true,
|
|
12646
12656
|
setup: (element, trigger, { types, readConfig }) => {
|
|
12647
12657
|
const canPan = types.includes(PAN);
|
|
@@ -15763,21 +15773,33 @@ const getActionResultProperties = (action) => {
|
|
|
15763
15773
|
return actionResultPropertiesMap.get(action);
|
|
15764
15774
|
};
|
|
15765
15775
|
|
|
15766
|
-
// PUT/PATCH results update the UI through the store, and DELETE resets the GET
|
|
15767
|
-
// instead of rerunning it, so a GET rerun would only ever cost a request.
|
|
15768
|
-
// A POST is the one case the client cannot decide alone: whether a new item
|
|
15769
|
-
// belongs to a list depends on filters/pagination the backend owns.
|
|
15770
15776
|
// Rationale in full, plus when to override: docs/list_refresh.md
|
|
15771
15777
|
const defaultRerunOn = {
|
|
15778
|
+
// PUT/PATCH results update the UI through the store, and DELETE resets the
|
|
15779
|
+
// GET rather than rerunning it, so a GET rerun would only ever cost a request.
|
|
15772
15780
|
GET: false,
|
|
15781
|
+
// A POST is the one case the client cannot decide alone: whether a new item
|
|
15782
|
+
// belongs to a list depends on filters/pagination the backend owns.
|
|
15773
15783
|
GET_MANY: ["POST"],
|
|
15784
|
+
// DELETE is in there, unlike for GET_MANY: an action holds ids and the store
|
|
15785
|
+
// drops the deleted one out of every list holding it, while a list reading
|
|
15786
|
+
// by slices holds places — the row that left takes the ones after it one
|
|
15787
|
+
// rank up, and only the collection knows who fills the last one.
|
|
15788
|
+
GET_RANGE: ["POST", "DELETE"],
|
|
15789
|
+
};
|
|
15790
|
+
// A key a `rerunOn` leaves out keeps the value it would have had without it:
|
|
15791
|
+
// the default for a resource, the value of the resource it is declared on for
|
|
15792
|
+
// a withParams() scope or a relation.
|
|
15793
|
+
const resolveRerunOn = (rerunOn, inheritedRerunOn = defaultRerunOn) => {
|
|
15794
|
+
if (!rerunOn) {
|
|
15795
|
+
return inheritedRerunOn;
|
|
15796
|
+
}
|
|
15797
|
+
return {
|
|
15798
|
+
GET: rerunOn.GET ?? inheritedRerunOn.GET,
|
|
15799
|
+
GET_MANY: rerunOn.GET_MANY ?? inheritedRerunOn.GET_MANY,
|
|
15800
|
+
GET_RANGE: rerunOn.GET_RANGE ?? inheritedRerunOn.GET_RANGE,
|
|
15801
|
+
};
|
|
15774
15802
|
};
|
|
15775
|
-
// What makes a range reader stale (rerunOn.GET_RANGE overrides it). DELETE is
|
|
15776
|
-
// in there, unlike for GET_MANY: an action holds ids and the store drops the
|
|
15777
|
-
// deleted one out of every list holding it, while a list reading by slices
|
|
15778
|
-
// holds places — the row that left takes the ones after it one rank up, and
|
|
15779
|
-
// only the collection knows who fills the last one.
|
|
15780
|
-
const defaultInvalidateRangeOn = ["POST", "DELETE"];
|
|
15781
15803
|
|
|
15782
15804
|
// This handles ALL resource lifecycle logic (rerun/reset) across all resources
|
|
15783
15805
|
const createResourceLifecycleManager = () => {
|
|
@@ -15787,7 +15809,7 @@ const createResourceLifecycleManager = () => {
|
|
|
15787
15809
|
|
|
15788
15810
|
const registerResource = (resourceScope, config) => {
|
|
15789
15811
|
const {
|
|
15790
|
-
rerunOn
|
|
15812
|
+
rerunOn,
|
|
15791
15813
|
paramScope = null,
|
|
15792
15814
|
dependencies = [],
|
|
15793
15815
|
uniqueKeys = [],
|
|
@@ -16070,8 +16092,7 @@ const createResourceLifecycleManager = () => {
|
|
|
16070
16092
|
if (!isSameResource && !isDependent) {
|
|
16071
16093
|
continue;
|
|
16072
16094
|
}
|
|
16073
|
-
|
|
16074
|
-
if (!shouldRerunAfter(invalidateOn, triggerVerb)) {
|
|
16095
|
+
if (!shouldRerunAfter(config.rerunOn.GET_RANGE, triggerVerb)) {
|
|
16075
16096
|
continue;
|
|
16076
16097
|
}
|
|
16077
16098
|
for (const rangeReader of config.rangeReaderSet) {
|
|
@@ -16572,7 +16593,7 @@ const resource = (
|
|
|
16572
16593
|
addItemSetup,
|
|
16573
16594
|
createRestAction: createRestActionForRoot,
|
|
16574
16595
|
paramScope: getParamScope(undefined),
|
|
16575
|
-
rerunOn,
|
|
16596
|
+
rerunOn: resolveRerunOn(rerunOn),
|
|
16576
16597
|
dependencies,
|
|
16577
16598
|
});
|
|
16578
16599
|
};
|
|
@@ -16636,7 +16657,7 @@ const createResource = (
|
|
|
16636
16657
|
* identical parameters, preventing cross-contamination between different parameter sets.
|
|
16637
16658
|
*
|
|
16638
16659
|
* @param {Object} params - Parameters to bind to all actions of this resource (required)
|
|
16639
|
-
* @param {{ rerunOn?: Object, dependencies?: Object[] }} [options] - reruns of that scope; left out
|
|
16660
|
+
* @param {{ rerunOn?: Object, dependencies?: Object[] }} [options] - reruns of that scope; a `rerunOn` key left out keeps the resource's value, and `dependencies` left out are the resource's
|
|
16640
16661
|
* @returns {Object} A new resource instance with parameter-bound actions and isolated lifecycle
|
|
16641
16662
|
* @see docs/resource.md — what a scope isolates, and `dependencies`
|
|
16642
16663
|
*
|
|
@@ -16682,7 +16703,7 @@ const createResource = (
|
|
|
16682
16703
|
addItemSetup,
|
|
16683
16704
|
createRestAction: createRestActionWithParams,
|
|
16684
16705
|
paramScope: resolvedParamScope,
|
|
16685
|
-
rerunOn: withParamsRerunOn
|
|
16706
|
+
rerunOn: resolveRerunOn(withParamsRerunOn, rerunOn),
|
|
16686
16707
|
dependencies: withParamsDeps ?? dependencies,
|
|
16687
16708
|
});
|
|
16688
16709
|
};
|
|
@@ -16700,14 +16721,15 @@ const createResource = (
|
|
|
16700
16721
|
* Callback return contracts:
|
|
16701
16722
|
* - GET / PUT → the parent object with the relationship nested inside:
|
|
16702
16723
|
* `async ({ id }) => ({ id, session: { id: 10, token: "abc" } })`; `null` for no relationship
|
|
16703
|
-
* - DELETE → the parent id
|
|
16724
|
+
* - DELETE → the parent id, or `{ id }`; the property is set to `null`
|
|
16704
16725
|
*
|
|
16705
16726
|
* The backend may also embed the child inline in a parent GET/POST response — the
|
|
16706
16727
|
* setter on the property upserts the nested object into the child store.
|
|
16707
16728
|
*
|
|
16708
|
-
* Returns the relationship resource
|
|
16709
|
-
*
|
|
16710
|
-
*
|
|
16729
|
+
* Returns the relationship resource, itself chainable. Its items are the child
|
|
16730
|
+
* resource's own, shared by every parent: `USER_SESSION.one("device", DEVICE)`
|
|
16731
|
+
* adds a reactive `.device` property to every session, as
|
|
16732
|
+
* `SESSION.one("device", DEVICE)` would.
|
|
16711
16733
|
*
|
|
16712
16734
|
* @param {string} propertyName - property holding the child on each parent item
|
|
16713
16735
|
* @param {Object} childResource - the independent resource created by `resource()`
|
|
@@ -16790,11 +16812,11 @@ const createResource = (
|
|
|
16790
16812
|
const createRestActionForOne = (verb, callback, { onActionComplete }) => {
|
|
16791
16813
|
const applyResultToValue =
|
|
16792
16814
|
verb === "DELETE"
|
|
16793
|
-
? (
|
|
16794
|
-
const item = store.select(
|
|
16815
|
+
? (itemIdOrItemProps) => {
|
|
16816
|
+
const item = store.select(itemIdOrItemProps);
|
|
16795
16817
|
const childItemId = item[propertyName][childIdKey];
|
|
16796
16818
|
store.upsert({
|
|
16797
|
-
[idKey]:
|
|
16819
|
+
[idKey]: item[idKey],
|
|
16798
16820
|
[propertyName]: null,
|
|
16799
16821
|
});
|
|
16800
16822
|
return childItemId;
|
|
@@ -16822,7 +16844,7 @@ const createResource = (
|
|
|
16822
16844
|
if (!isProps(result) && !primitiveCanBeId(result)) {
|
|
16823
16845
|
throwInvalidResult(
|
|
16824
16846
|
action.name,
|
|
16825
|
-
`
|
|
16847
|
+
`the "${name}" id, or { ${idKey} } (the item whose "${propertyName}" becomes null)`,
|
|
16826
16848
|
result,
|
|
16827
16849
|
);
|
|
16828
16850
|
}
|
|
@@ -16847,11 +16869,11 @@ const createResource = (
|
|
|
16847
16869
|
PUT,
|
|
16848
16870
|
DELETE,
|
|
16849
16871
|
},
|
|
16850
|
-
store,
|
|
16851
|
-
addItemSetup,
|
|
16872
|
+
store: childStore,
|
|
16873
|
+
addItemSetup: childResource.addItemSetup,
|
|
16852
16874
|
createRestAction: createRestActionForOne,
|
|
16853
16875
|
paramScope,
|
|
16854
|
-
rerunOn: oneRerunOn
|
|
16876
|
+
rerunOn: resolveRerunOn(oneRerunOn, rerunOn),
|
|
16855
16877
|
dependencies: oneDependencies ?? dependencies,
|
|
16856
16878
|
});
|
|
16857
16879
|
};
|
|
@@ -16874,6 +16896,9 @@ const createResource = (
|
|
|
16874
16896
|
* - DELETE → `[parentId, childId]`
|
|
16875
16897
|
* - DELETE_MANY → `[parentId, [childId, childId, …]]`
|
|
16876
16898
|
*
|
|
16899
|
+
* Returns the relationship resource, itself chainable; its items are the child
|
|
16900
|
+
* resource's own, as for `.one()`.
|
|
16901
|
+
*
|
|
16877
16902
|
* @param {string} propertyName - property holding the child array on each parent item
|
|
16878
16903
|
* @param {Object} childResource - the independent resource created by `resource()`
|
|
16879
16904
|
* @param {Object} [restCallbacks] - `{ rerunOn, dependencies, GET, GET_MANY, POST, POST_MANY, PUT, PUT_MANY, PATCH, PATCH_MANY, DELETE, DELETE_MANY }`
|
|
@@ -17109,11 +17134,11 @@ const createResource = (
|
|
|
17109
17134
|
DELETE,
|
|
17110
17135
|
DELETE_MANY,
|
|
17111
17136
|
},
|
|
17112
|
-
store,
|
|
17113
|
-
addItemSetup,
|
|
17137
|
+
store: childStore,
|
|
17138
|
+
addItemSetup: childResource.addItemSetup,
|
|
17114
17139
|
createRestAction: createRestActionForMany,
|
|
17115
17140
|
paramScope,
|
|
17116
|
-
rerunOn: manyRerunOn
|
|
17141
|
+
rerunOn: resolveRerunOn(manyRerunOn, rerunOn),
|
|
17117
17142
|
dependencies: manyDependencies ?? dependencies,
|
|
17118
17143
|
});
|
|
17119
17144
|
};
|
|
@@ -17242,7 +17267,7 @@ const createResource = (
|
|
|
17242
17267
|
addItemSetup: childAddItemSetup,
|
|
17243
17268
|
createRestAction: createRestActionForScopedOne,
|
|
17244
17269
|
paramScope,
|
|
17245
|
-
rerunOn: scopedOneRerunOn
|
|
17270
|
+
rerunOn: resolveRerunOn(scopedOneRerunOn, rerunOn),
|
|
17246
17271
|
dependencies: scopedOneDependencies ?? dependencies,
|
|
17247
17272
|
});
|
|
17248
17273
|
};
|
|
@@ -17477,7 +17502,7 @@ const createResource = (
|
|
|
17477
17502
|
addItemSetup: childAddItemSetup,
|
|
17478
17503
|
createRestAction: createRestActionForScopedMany,
|
|
17479
17504
|
paramScope,
|
|
17480
|
-
rerunOn: scopedManyRerunOn
|
|
17505
|
+
rerunOn: resolveRerunOn(scopedManyRerunOn, rerunOn),
|
|
17481
17506
|
dependencies: scopedManyDependencies ?? dependencies,
|
|
17482
17507
|
});
|
|
17483
17508
|
// When a scoped child collection is mutated (POST etc.), the parent GET must
|
|
@@ -20196,9 +20221,9 @@ const isSizeSpacingKey = (key) => {
|
|
|
20196
20221
|
// "vvw"/"vvh" are navi's own: the *visual* viewport, which — unlike vw/dvw —
|
|
20197
20222
|
// shrinks when the mobile virtual keyboard opens (see layout/responsive.js), so
|
|
20198
20223
|
// they are what a popup meant to stay clear of the keyboard should use.
|
|
20199
|
-
// "appw"/"apph" are the same thing narrowed to the app's own screen:
|
|
20200
|
-
//
|
|
20201
|
-
//
|
|
20224
|
+
// "appw"/"apph" are the same thing narrowed to the app's own screen: the
|
|
20225
|
+
// visual viewport minus the app's bands (--navi-app-inset-*), so identical to
|
|
20226
|
+
// vvw/vvh until the app declares bands. A gap meant to read as "a small margin" must use these —
|
|
20202
20227
|
// 3vvw on a 1500px window is a 45px gap around a 600px app.
|
|
20203
20228
|
// Functions rather than the signals themselves: appw/apph are not a signal to
|
|
20204
20229
|
// read but a value to compute (a signal, then a CSS var read back). Reading the
|
|
@@ -30202,8 +30227,8 @@ const TRANSITION_FURNITURE_CSS = /* css */ `.navi_fixed_bar[data-navi-transition
|
|
|
30202
30227
|
}
|
|
30203
30228
|
`;
|
|
30204
30229
|
|
|
30205
|
-
// Called
|
|
30206
|
-
//
|
|
30230
|
+
// Called as a movement starts over a marked area, never at module scope: a
|
|
30231
|
+
// page that never travels between routes must not carry this sheet, and a
|
|
30207
30232
|
// build that sees no caller drops the css with the function.
|
|
30208
30233
|
const installTransitionFurnitureCss = () => {
|
|
30209
30234
|
import.meta.css = [TRANSITION_FURNITURE_CSS, "@jsenv/navi/src/nav/transition_furniture.js"];
|
|
@@ -30666,9 +30691,10 @@ const TRANSITION_WINDOW_CSS = /* css */ `@property --navi-transition-cover-top {
|
|
|
30666
30691
|
}
|
|
30667
30692
|
`;
|
|
30668
30693
|
|
|
30669
|
-
// Called
|
|
30670
|
-
// a page that never travels between routes must not
|
|
30671
|
-
// build that sees no caller drops the css with the
|
|
30694
|
+
// Called by whatever needs the window — a render, or a movement starting —
|
|
30695
|
+
// never at module scope: a page that never travels between routes must not
|
|
30696
|
+
// carry this sheet, and a build that sees no caller drops the css with the
|
|
30697
|
+
// function.
|
|
30672
30698
|
const installTransitionWindowCss = () => {
|
|
30673
30699
|
import.meta.css = [TRANSITION_WINDOW_CSS, "@jsenv/navi/src/nav/transition_window.js"];
|
|
30674
30700
|
};
|
|
@@ -31481,9 +31507,6 @@ const RouteTransitionArea = ({
|
|
|
31481
31507
|
children,
|
|
31482
31508
|
...rest
|
|
31483
31509
|
}) => {
|
|
31484
|
-
import.meta.css = [css$12, "@jsenv/navi/src/nav/route_transition.jsx"];
|
|
31485
|
-
installTransitionWindowCss();
|
|
31486
|
-
installTransitionFurnitureCss();
|
|
31487
31510
|
const props = {
|
|
31488
31511
|
...rest,
|
|
31489
31512
|
[TRANSITION_AREA_ATTRIBUTE]: ""
|
|
@@ -31552,8 +31575,6 @@ const RouteTransitionArea = ({
|
|
|
31552
31575
|
* @returns {() => void} remove this relation.
|
|
31553
31576
|
*/
|
|
31554
31577
|
const defineRouteTransition = (from, to, transition) => {
|
|
31555
|
-
import.meta.css = [css$12, "@jsenv/navi/src/nav/route_transition.jsx"];
|
|
31556
|
-
installTransitionWindowCss();
|
|
31557
31578
|
if (!to) {
|
|
31558
31579
|
throw new TypeError(`defineRouteTransition needs a destination: "to" is ${to}. The page reached from anywhere is written defineRouteTransition(null, THAT_PAGE, ...) — there is no relation the other way round, a page LEFT for anywhere being the back half of that one.`);
|
|
31559
31580
|
}
|
|
@@ -31593,8 +31614,6 @@ const defineRouteTransition = (from, to, transition) => {
|
|
|
31593
31614
|
* @returns {() => void} remove this default.
|
|
31594
31615
|
*/
|
|
31595
31616
|
const defineRouteDefaultTransition = transition => {
|
|
31596
|
-
import.meta.css = [css$12, "@jsenv/navi/src/nav/route_transition.jsx"];
|
|
31597
|
-
installTransitionWindowCss();
|
|
31598
31617
|
const value = normalizeTransition(transition);
|
|
31599
31618
|
defaultTransition = value;
|
|
31600
31619
|
return () => {
|
|
@@ -32176,6 +32195,10 @@ const beginTransition = ({
|
|
|
32176
32195
|
// Said before the picture is taken: whoever names something for a movement
|
|
32177
32196
|
// between two pages decides on it now (see transition_destination.js).
|
|
32178
32197
|
holdTransitionDestination(transition, url);
|
|
32198
|
+
// Adopted by what starts a movement rather than by what declares one: a link
|
|
32199
|
+
// or a navTo() asks for a movement in an app that declared none, and an app
|
|
32200
|
+
// that never moves never carries the sheet.
|
|
32201
|
+
import.meta.css = [css$12, "@jsenv/navi/src/nav/route_transition.jsx"];
|
|
32179
32202
|
documentElement.setAttribute(TRANSITION_ATTRIBUTE, direction);
|
|
32180
32203
|
if (type) {
|
|
32181
32204
|
documentElement.setAttribute(TRANSITION_TYPE_ATTRIBUTE, type);
|
|
@@ -32197,6 +32220,10 @@ const beginTransition = ({
|
|
|
32197
32220
|
// left (see transition_window.js).
|
|
32198
32221
|
let areaStateBefore = null;
|
|
32199
32222
|
if (areaElement) {
|
|
32223
|
+
// The area is the application's element as often as <RouteTransitionArea>,
|
|
32224
|
+
// so what a movement on it plays with is adopted here, where it is found.
|
|
32225
|
+
installTransitionWindowCss();
|
|
32226
|
+
installTransitionFurnitureCss();
|
|
32200
32227
|
documentElement.setAttribute(TRANSITION_TARGET_ATTRIBUTE, "area");
|
|
32201
32228
|
// Said before the picture is taken, like every name (see
|
|
32202
32229
|
// transition_furniture.js): what the bars are wearing when the transition
|
|
@@ -45400,16 +45427,6 @@ const css$Z = /* css */`@layer navi {
|
|
|
45400
45427
|
border-radius: .2em;
|
|
45401
45428
|
}
|
|
45402
45429
|
|
|
45403
|
-
&[data-capitalize] {
|
|
45404
|
-
text-transform: capitalize;
|
|
45405
|
-
|
|
45406
|
-
& .navi_text_sizer {
|
|
45407
|
-
& .navi_text {
|
|
45408
|
-
display: inline-block;
|
|
45409
|
-
}
|
|
45410
|
-
}
|
|
45411
|
-
}
|
|
45412
|
-
|
|
45413
45430
|
&[data-shrinkwrap] {
|
|
45414
45431
|
display: inline-block;
|
|
45415
45432
|
}
|
|
@@ -45432,12 +45449,6 @@ time.navi_text {
|
|
|
45432
45449
|
}
|
|
45433
45450
|
|
|
45434
45451
|
.navi_text {
|
|
45435
|
-
&[data-capitalize] {
|
|
45436
|
-
&:first-letter, & .navi_text_sizer_placeholder:first-letter, & .navi_text_sizer_overlay:first-letter {
|
|
45437
|
-
text-transform: uppercase;
|
|
45438
|
-
}
|
|
45439
|
-
}
|
|
45440
|
-
|
|
45441
45452
|
& .navi_text_sizer, & .navi_text_sizer_placeholder, & .navi_text_sizer_overlay {
|
|
45442
45453
|
display: inherit;
|
|
45443
45454
|
width: inherit;
|
|
@@ -45885,7 +45896,9 @@ const shouldInjectSpacingBetween = (left, right) => {
|
|
|
45885
45896
|
* text block from being wider than its content when inside a flex/grid container.
|
|
45886
45897
|
*
|
|
45887
45898
|
* @param {boolean} [capitalize]
|
|
45888
|
-
* Uppercases the first letter of the text
|
|
45899
|
+
* Uppercases the first letter of the text, and only that one: "lundi 11 mai"
|
|
45900
|
+
* reads "Lundi 11 mai". Applied to the string the text starts with; a text
|
|
45901
|
+
* starting with an element keeps its first letter as written.
|
|
45889
45902
|
*
|
|
45890
45903
|
* @param {string|[number,number]|[string,string]} [selectRange]
|
|
45891
45904
|
* Selects a portion of the text on mount. Pass a substring to search for, a
|
|
@@ -46005,11 +46018,13 @@ const TextUI = props => {
|
|
|
46005
46018
|
shrinkWrap,
|
|
46006
46019
|
...rest
|
|
46007
46020
|
} = props;
|
|
46021
|
+
if (capitalize) {
|
|
46022
|
+
children = capitalizeFirstLetter(children);
|
|
46023
|
+
}
|
|
46008
46024
|
const defaultSpace = preventSpaceUnderlines ? FAKE_SPACE : REGULAR_SPACE;
|
|
46009
46025
|
const resolvedSpacing = spacing ?? defaultSpace;
|
|
46010
46026
|
const boxProps = {
|
|
46011
46027
|
"as": "span",
|
|
46012
|
-
"data-capitalize": capitalize ? "" : undefined,
|
|
46013
46028
|
"data-shrinkwrap": shrinkWrap ? "" : undefined,
|
|
46014
46029
|
...rest,
|
|
46015
46030
|
ref,
|
|
@@ -46310,6 +46325,28 @@ const Icon = ({
|
|
|
46310
46325
|
});
|
|
46311
46326
|
};
|
|
46312
46327
|
|
|
46328
|
+
// On the string rather than with ::first-letter, which needs a block container:
|
|
46329
|
+
// an inline text made one is an atomic box, and the ellipsis of the line
|
|
46330
|
+
// holding it (a Picker's value) can then no longer cut it. The string is also
|
|
46331
|
+
// what every copy of the children (sizer, bold background) renders, so they
|
|
46332
|
+
// all read the same. Leading spaces and punctuation are skipped, and a text
|
|
46333
|
+
// starting with a digit is left as it is, as ::first-letter would.
|
|
46334
|
+
const capitalizeFirstLetter = children => {
|
|
46335
|
+
if (typeof children === "string") {
|
|
46336
|
+
return children.replace(FIRST_LOWERCASE_LETTER_REGEXP, (match, lead, letter) => `${lead}${letter.toLocaleUpperCase()}`);
|
|
46337
|
+
}
|
|
46338
|
+
if (Array.isArray(children) && children.length > 0) {
|
|
46339
|
+
const first = children[0];
|
|
46340
|
+
const firstCapitalized = capitalizeFirstLetter(first);
|
|
46341
|
+
if (firstCapitalized === first) {
|
|
46342
|
+
return children;
|
|
46343
|
+
}
|
|
46344
|
+
return [firstCapitalized, ...children.slice(1)];
|
|
46345
|
+
}
|
|
46346
|
+
return children;
|
|
46347
|
+
};
|
|
46348
|
+
const FIRST_LOWERCASE_LETTER_REGEXP = /^([\s\p{P}]*)(\p{Ll})/u;
|
|
46349
|
+
|
|
46313
46350
|
/**
|
|
46314
46351
|
* Where a link leads, asked for when the pointer or the focus arrives on it:
|
|
46315
46352
|
* the moment the user signals a destination, before the press. Only what the
|
|
@@ -61246,7 +61283,6 @@ const createSwipeToClose = (side, { grip } = {}) => {
|
|
|
61246
61283
|
panelEl.style.transform = "";
|
|
61247
61284
|
panelEl.style.clipPath = "";
|
|
61248
61285
|
panelEl.style.transitionProperty = "";
|
|
61249
|
-
panelEl.style.userSelect = "";
|
|
61250
61286
|
};
|
|
61251
61287
|
// The resting value is written first and the animation only covers the way
|
|
61252
61288
|
// to it: both end on the same number, so nothing is seen changing when the
|
|
@@ -61290,10 +61326,6 @@ const createSwipeToClose = (side, { grip } = {}) => {
|
|
|
61290
61326
|
return false;
|
|
61291
61327
|
}
|
|
61292
61328
|
panelEl.style.transitionProperty = "none";
|
|
61293
|
-
panelEl.style.userSelect = "none";
|
|
61294
|
-
// What the first pixels of the gesture may have started selecting is
|
|
61295
|
-
// not a selection, it is the beginning of this travel.
|
|
61296
|
-
window.getSelection().removeAllRanges();
|
|
61297
61329
|
// The way out is the only way there is anything: pulling the other way
|
|
61298
61330
|
// leans against a wall and comes back.
|
|
61299
61331
|
return {
|
|
@@ -61999,7 +62031,7 @@ const css$E = /* css */`
|
|
|
61999
62031
|
--navi-app-width rather than 3vvw): the gap must read as a small
|
|
62000
62032
|
margin around the dialog, and 3% of a 1500px window is a 45px gap
|
|
62001
62033
|
around a 600px app. Identical to 3vvw until the app declares
|
|
62002
|
-
--navi-app-max-width. */
|
|
62034
|
+
bands (--navi-app-max-width, or --navi-app-inset-* written by it). */
|
|
62003
62035
|
--x-dialog-container-spacing: calc(0.03 * var(--navi-app-width));
|
|
62004
62036
|
|
|
62005
62037
|
/* --navi-app-width, not --navi-vvw: a top-layer dialog is calibrated on
|
|
@@ -62736,8 +62768,8 @@ const css$E = /* css */`
|
|
|
62736
62768
|
* `positionArea`: it both caps the dialog's own size (via
|
|
62737
62769
|
* `--x-dialog-container-spacing`, written from this prop) and offsets a docked
|
|
62738
62770
|
* one from the edge it docks to. Accepts a number of pixels, a viewport
|
|
62739
|
-
* length — "appw"/"apph" being the app's own screen (the visual viewport
|
|
62740
|
-
*
|
|
62771
|
+
* length — "appw"/"apph" being the app's own screen (the visual viewport
|
|
62772
|
+
* minus the app's bands, see docs/safe_area.md) and
|
|
62741
62773
|
* "vvw"/"vvh" the visual viewport itself, which shrinks when the mobile
|
|
62742
62774
|
* keyboard opens — or a container length ("3cqw", the `layer="local"`
|
|
62743
62775
|
* default). Pass 0 for a dialog meant to sit flush (a side panel).
|
|
@@ -65881,6 +65913,8 @@ const css$C = /* css */`@layer navi {
|
|
|
65881
65913
|
* `maxWidth` below.
|
|
65882
65914
|
* @param {boolean} [props.sizeFromAnchor] - **Dialog-only**, same guard.
|
|
65883
65915
|
* @param {"box"|"scene"} [props.lift] - **Dialog-only**, same guard.
|
|
65916
|
+
* @param {Element|{current: Element}|string} [props.liftAnchor] -
|
|
65917
|
+
* **Dialog-only**, same guard.
|
|
65884
65918
|
* @param {string} [props.positionArea] - Forwarded as-is — `Dialog` and
|
|
65885
65919
|
* `Popover` have different own defaults (`"center"` vs. `"bottom"`),
|
|
65886
65920
|
* deliberately not homogenized here (each reads best for its own typical
|
|
@@ -65914,8 +65948,13 @@ const css$C = /* css */`@layer navi {
|
|
|
65914
65948
|
* identically): the wash the backdrop paints over what is behind.
|
|
65915
65949
|
* @param {string} [props.backdropFilter] - Forwarded as-is: what that wash
|
|
65916
65950
|
* does to the picture underneath, `"blur(4px)"` and the like.
|
|
65917
|
-
* @param {boolean|"auto"|"fading"|"scaling"|"sliding"
|
|
65918
|
-
* - Forwarded
|
|
65951
|
+
* @param {boolean|"auto"|"fading"|"scaling"|"sliding"|`slide-from-${string}`|"expanding"|`expand-${string}`|"lifting"|{open: boolean|"auto"|"fading"|"scaling"|"sliding"|`slide-from-${string}`, close: "lifting"}} [props.animation]
|
|
65952
|
+
* - Forwarded to whichever renders — see either component's own doc.
|
|
65953
|
+
* `"expanding"`/`"expand-*"` are `Popover`'s own; `"lifting"` and
|
|
65954
|
+
* `{ open, close: "lifting" }` are `Dialog`'s. A popover has no lift, so in
|
|
65955
|
+
* popover mode `"lifting"` plays no movement (what a dialog does with no
|
|
65956
|
+
* anchor to lift out of) and the object form opens with its `open`, which
|
|
65957
|
+
* the close plays backwards like every other kind.
|
|
65919
65958
|
* @param {string} [props.animationDuration] - Forwarded as-is.
|
|
65920
65959
|
* @param {string} [props.maxWidth] - Forwarded as-is to both; also read
|
|
65921
65960
|
* here directly to help decide the automatic `mode` (a fixed length under
|
|
@@ -65981,6 +66020,8 @@ const Popup = props => {
|
|
|
65981
66020
|
// mode the automatic screen-size resolution happens to pick.
|
|
65982
66021
|
pressOutside = "close",
|
|
65983
66022
|
backdrop,
|
|
66023
|
+
// A popover is handed only the values it understands (toPopoverAnimation).
|
|
66024
|
+
animation,
|
|
65984
66025
|
// Popover-only (see this component's own doc) — destructured out so
|
|
65985
66026
|
// they're never part of ...rest, and therefore never forwarded to
|
|
65986
66027
|
// Dialog below, where they'd otherwise leak onto the real <dialog>
|
|
@@ -65995,6 +66036,7 @@ const Popup = props => {
|
|
|
65995
66036
|
dockedOnSmallTouchScreen,
|
|
65996
66037
|
sizeFromAnchor,
|
|
65997
66038
|
lift,
|
|
66039
|
+
liftAnchor,
|
|
65998
66040
|
...rest
|
|
65999
66041
|
} = props;
|
|
66000
66042
|
const [mode] = useResolvedPopupMode(modeProp, maxWidth, {
|
|
@@ -66014,6 +66056,8 @@ const Popup = props => {
|
|
|
66014
66056
|
dockedOnSmallTouchScreen: dockedOnSmallTouchScreen,
|
|
66015
66057
|
sizeFromAnchor: sizeFromAnchor,
|
|
66016
66058
|
lift: lift,
|
|
66059
|
+
liftAnchor: liftAnchor,
|
|
66060
|
+
animation: animation,
|
|
66017
66061
|
maxWidth: maxWidth,
|
|
66018
66062
|
pressOutside: pressOutside,
|
|
66019
66063
|
backdrop: backdrop,
|
|
@@ -66027,6 +66071,7 @@ const Popup = props => {
|
|
|
66027
66071
|
}
|
|
66028
66072
|
return jsx(Popover, {
|
|
66029
66073
|
...rest,
|
|
66074
|
+
animation: toPopoverAnimation(animation),
|
|
66030
66075
|
maxWidth: maxWidth,
|
|
66031
66076
|
pressOutside: pressOutside,
|
|
66032
66077
|
backdrop: backdrop,
|
|
@@ -66044,6 +66089,18 @@ const Popup = props => {
|
|
|
66044
66089
|
};
|
|
66045
66090
|
Popup.Close = PopupClose;
|
|
66046
66091
|
|
|
66092
|
+
// What Dialog's own animation values mean to a popover, which has no lift
|
|
66093
|
+
// (see the `animation` doc above).
|
|
66094
|
+
const toPopoverAnimation = animation => {
|
|
66095
|
+
if (animation === "lifting") {
|
|
66096
|
+
return undefined;
|
|
66097
|
+
}
|
|
66098
|
+
if (animation !== null && typeof animation === "object") {
|
|
66099
|
+
return animation.open;
|
|
66100
|
+
}
|
|
66101
|
+
return animation;
|
|
66102
|
+
};
|
|
66103
|
+
|
|
66047
66104
|
installImportMetaCssBuild(import.meta);
|
|
66048
66105
|
const css$B = /* css */`.navi_picker_callout_dock > [data-picker-content] {
|
|
66049
66106
|
display: none;
|
|
@@ -67368,9 +67425,14 @@ const PickerNaviMinute = props => {
|
|
|
67368
67425
|
step,
|
|
67369
67426
|
value
|
|
67370
67427
|
} = props;
|
|
67428
|
+
|
|
67429
|
+
// resolveInputProps has already run (PickerFirstResolver), so the type
|
|
67430
|
+
// handed on is one the picker renders as is — the text field a navi numeric
|
|
67431
|
+
// type resolves to, told what its value is.
|
|
67371
67432
|
return jsx(Next, {
|
|
67372
67433
|
...props,
|
|
67373
|
-
type: "
|
|
67434
|
+
type: "text",
|
|
67435
|
+
"navi-input-type": "minute",
|
|
67374
67436
|
children: jsxs(Box, {
|
|
67375
67437
|
flex: "y",
|
|
67376
67438
|
spacing: "s",
|
|
@@ -76525,7 +76587,7 @@ const PickerFirstResolver = props => {
|
|
|
76525
76587
|
* `focusOnOpen` below.
|
|
76526
76588
|
*
|
|
76527
76589
|
* @type {import("ignore:preact").FunctionComponent<{
|
|
76528
|
-
* type?: "date" | "month" | "week" | "time" | "datetime" | "duration" | "color" | "file" | "text" | "object" | "array" | "confirm" | "navi_time" | "navi_number" | "navi_percentage",
|
|
76590
|
+
* type?: "date" | "month" | "week" | "time" | "datetime" | "duration" | "color" | "file" | "text" | "object" | "array" | "confirm" | "navi_time" | "navi_minute" | "navi_number" | "navi_percentage",
|
|
76529
76591
|
* value?: any,
|
|
76530
76592
|
* defaultValue?: any,
|
|
76531
76593
|
* name?: string,
|
|
@@ -88548,6 +88610,8 @@ const css$3 = /* css */`@layer navi {
|
|
|
88548
88610
|
}
|
|
88549
88611
|
|
|
88550
88612
|
.navi_card_layout {
|
|
88613
|
+
box-sizing: border-box;
|
|
88614
|
+
min-height: 100%;
|
|
88551
88615
|
padding-top: var(--layout-margin-top, var(--layout-margin-y, var(--layout-margin)));
|
|
88552
88616
|
padding-right: var(--layout-margin-right, var(--layout-margin-x, var(--layout-margin)));
|
|
88553
88617
|
padding-bottom: var(--layout-margin-bottom, var(--layout-margin-y, var(--layout-margin)));
|
|
@@ -88589,6 +88653,11 @@ const CardLayoutStyleCSSVars = {
|
|
|
88589
88653
|
minHeight: "--layout-min-height"
|
|
88590
88654
|
};
|
|
88591
88655
|
/**
|
|
88656
|
+
* The card is centered in the area both ways and is as wide as its content,
|
|
88657
|
+
* `minWidth` at least. Down the area, the layout takes at least the height of
|
|
88658
|
+
* what holds it, so how tall that area is is up to the page around it, as for
|
|
88659
|
+
* `ViewportLayout`.
|
|
88660
|
+
*
|
|
88592
88661
|
* @type {import("ignore:preact").FunctionComponent<{
|
|
88593
88662
|
* alignX?: string,
|
|
88594
88663
|
* alignY?: string,
|
|
@@ -88618,6 +88687,11 @@ const CardLayout = ({
|
|
|
88618
88687
|
}) => {
|
|
88619
88688
|
import.meta.css = [css$3, "@jsenv/navi/src/layout/card_layout.jsx"];
|
|
88620
88689
|
return jsx(Box, {
|
|
88690
|
+
flex: true
|
|
88691
|
+
// The card's place in the area; alignX/alignY below are its content's.
|
|
88692
|
+
,
|
|
88693
|
+
alignX: "center",
|
|
88694
|
+
alignY: "center",
|
|
88621
88695
|
baseClassName: "navi_card_layout",
|
|
88622
88696
|
styleCSSVars: CardLayoutStyleCSSVars,
|
|
88623
88697
|
visualSelector: ".navi_card",
|