@jsenv/navi 0.29.127 → 0.29.129
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 +144 -82
- package/dist/jsenv_navi.js.map +8 -6
- package/docs/actions.md +3 -2
- package/docs/offline.md +7 -5
- package/package.json +1 -1
package/dist/jsenv_navi.js
CHANGED
|
@@ -3000,8 +3000,9 @@ naviI18n.addAll({
|
|
|
3000
3000
|
* read by the action layer rather than by every callback.
|
|
3001
3001
|
*
|
|
3002
3002
|
* Under a policy (a truthy reason):
|
|
3003
|
-
* - a resource GET answers with the row its store holds for
|
|
3004
|
-
*
|
|
3003
|
+
* - a resource GET answers with the row its store holds for it — named by its
|
|
3004
|
+
* params, or the one it last completed with — and asks nothing
|
|
3005
|
+
* (resource_graph.js, applyNetworkPolicy); a completed read
|
|
3005
3006
|
* asked to rerun stays completed (actions.js, handleActionRequest);
|
|
3006
3007
|
* anything else settles with an OfflineError carrying the reason;
|
|
3007
3008
|
* - a control bound to a write — or inside a form bound to one — is read-only
|
|
@@ -4037,6 +4038,7 @@ const createAction = (callback, rootOptions = {}) => {
|
|
|
4037
4038
|
event,
|
|
4038
4039
|
signal: internalAbortSignal,
|
|
4039
4040
|
isPrerun,
|
|
4041
|
+
action,
|
|
4040
4042
|
});
|
|
4041
4043
|
const returnValue = sideEffect(...args);
|
|
4042
4044
|
if (typeof returnValue === "function") {
|
|
@@ -14792,7 +14794,7 @@ const debug$3 = (...args) => {
|
|
|
14792
14794
|
*
|
|
14793
14795
|
* @param {string} name - resource name, used in action names and error messages
|
|
14794
14796
|
* @param {Object} restCallbacks - `{ idKey, uniqueKeys, rerunOn, dependencies, GET, GET_MANY, GET_RANGE, POST, POST_MANY, PUT, PUT_MANY, PATCH, PATCH_MANY, DELETE, DELETE_MANY }`
|
|
14795
|
-
* @param {string} [restCallbacks.idKey] - primary key property, defaults to `"id"`
|
|
14797
|
+
* @param {string} [restCallbacks.idKey] - primary key property, defaults to `"id"`
|
|
14796
14798
|
* @param {string[]} [restCallbacks.uniqueKeys] - alternate keys the store can find an item by (e.g. `"username"`); a callback may return a different `id` to rename the item's primary key
|
|
14797
14799
|
* @see docs/resource.md — relationships, callback return contracts, decision table
|
|
14798
14800
|
*
|
|
@@ -14808,7 +14810,7 @@ const resource = (
|
|
|
14808
14810
|
name,
|
|
14809
14811
|
{
|
|
14810
14812
|
// configuration options
|
|
14811
|
-
idKey,
|
|
14813
|
+
idKey = "id",
|
|
14812
14814
|
uniqueKeys = [],
|
|
14813
14815
|
rerunOn,
|
|
14814
14816
|
dependencies,
|
|
@@ -14827,9 +14829,6 @@ const resource = (
|
|
|
14827
14829
|
} = {},
|
|
14828
14830
|
) => {
|
|
14829
14831
|
const declarationSite = getDeclarationSite();
|
|
14830
|
-
if (idKey === undefined) {
|
|
14831
|
-
idKey = uniqueKeys.length === 0 ? "id" : uniqueKeys[0];
|
|
14832
|
-
}
|
|
14833
14832
|
const setupCallbackSet = new Set();
|
|
14834
14833
|
const addItemSetup = (callback) => {
|
|
14835
14834
|
setupCallbackSet.add(callback);
|
|
@@ -14877,10 +14876,12 @@ const resource = (
|
|
|
14877
14876
|
store,
|
|
14878
14877
|
declarationSite,
|
|
14879
14878
|
});
|
|
14880
|
-
// The row a GET
|
|
14881
|
-
// value under idKey may be the id or any unique key (a route opening a
|
|
14882
|
-
// by id or by slug names both `id`), and a unique key may be given under
|
|
14883
|
-
// own name
|
|
14879
|
+
// The row a GET designates, when the store already holds it — by its params:
|
|
14880
|
+
// the value under idKey may be the id or any unique key (a route opening a
|
|
14881
|
+
// user by id or by slug names both `id`), and a unique key may be given under
|
|
14882
|
+
// its own name; or, when the params name no row (a GET without params, or
|
|
14883
|
+
// whose params carry no key), the row the action last completed with.
|
|
14884
|
+
// Answers a GET under a network policy (see applyNetworkPolicy).
|
|
14884
14885
|
const selectByAnyKey = (value) => {
|
|
14885
14886
|
const item = store.select(value);
|
|
14886
14887
|
if (item) {
|
|
@@ -14894,31 +14895,42 @@ const resource = (
|
|
|
14894
14895
|
}
|
|
14895
14896
|
return null;
|
|
14896
14897
|
};
|
|
14897
|
-
const
|
|
14898
|
-
|
|
14899
|
-
|
|
14900
|
-
|
|
14901
|
-
|
|
14902
|
-
|
|
14903
|
-
|
|
14898
|
+
const findItemByParams = (params) => {
|
|
14899
|
+
if (primitiveCanBeId(params)) {
|
|
14900
|
+
return selectByAnyKey(params);
|
|
14901
|
+
}
|
|
14902
|
+
if (!isProps(params)) {
|
|
14903
|
+
return null;
|
|
14904
|
+
}
|
|
14905
|
+
const idParam = params[idKey];
|
|
14906
|
+
if (idParam !== undefined) {
|
|
14907
|
+
const item = selectByAnyKey(idParam);
|
|
14908
|
+
if (item) {
|
|
14909
|
+
return item;
|
|
14904
14910
|
}
|
|
14905
|
-
|
|
14906
|
-
|
|
14907
|
-
|
|
14911
|
+
}
|
|
14912
|
+
for (const uniqueKey of uniqueKeys) {
|
|
14913
|
+
const uniqueKeyParam = params[uniqueKey];
|
|
14914
|
+
if (uniqueKeyParam !== undefined) {
|
|
14915
|
+
const item = store.select(uniqueKey, uniqueKeyParam);
|
|
14908
14916
|
if (item) {
|
|
14909
14917
|
return item;
|
|
14910
14918
|
}
|
|
14911
14919
|
}
|
|
14912
|
-
|
|
14913
|
-
|
|
14914
|
-
|
|
14915
|
-
|
|
14916
|
-
|
|
14917
|
-
|
|
14918
|
-
|
|
14919
|
-
|
|
14920
|
+
}
|
|
14921
|
+
return null;
|
|
14922
|
+
};
|
|
14923
|
+
const findItemInStore = (params, action) => {
|
|
14924
|
+
return untracked(() => {
|
|
14925
|
+
const itemByParams = findItemByParams(params);
|
|
14926
|
+
if (itemByParams) {
|
|
14927
|
+
return itemByParams;
|
|
14920
14928
|
}
|
|
14921
|
-
|
|
14929
|
+
const lastItemId = getLastGetItemId(action);
|
|
14930
|
+
if (lastItemId === undefined) {
|
|
14931
|
+
return null;
|
|
14932
|
+
}
|
|
14933
|
+
return store.select(lastItemId) || null;
|
|
14922
14934
|
});
|
|
14923
14935
|
};
|
|
14924
14936
|
return createResource(name, {
|
|
@@ -15970,6 +15982,9 @@ const createRestActionFactoryForRoot = (
|
|
|
15970
15982
|
// lifecycle rules can detect whether sub-resources were embedded.
|
|
15971
15983
|
if (verb === "GET") {
|
|
15972
15984
|
recordGetResultProperties(action, Object.keys(result));
|
|
15985
|
+
const itemId = applyResultToValue(result);
|
|
15986
|
+
lastGetItemIdWeakMap.set(action, itemId);
|
|
15987
|
+
return itemId;
|
|
15973
15988
|
}
|
|
15974
15989
|
return applyResultToValue(result);
|
|
15975
15990
|
},
|
|
@@ -16017,12 +16032,12 @@ const createRestActionFactoryForRoot = (
|
|
|
16017
16032
|
};
|
|
16018
16033
|
|
|
16019
16034
|
// Under a network policy no callback is called (see network_policy.js). A GET
|
|
16020
|
-
// of a root resource answers with the row the store holds for
|
|
16021
|
-
// handing the item back is an upsert without effect, so the
|
|
16022
|
-
// with what it had and nothing is asked. A relationship GET
|
|
16023
|
-
// own to answer with, and a write has nothing to answer:
|
|
16024
|
-
// OfflineError carrying the policy's reason. A completed
|
|
16025
|
-
// never gets here (actions.js holds it).
|
|
16035
|
+
// of a root resource answers with the row the store holds for it (see
|
|
16036
|
+
// findItemInStore) — handing the item back is an upsert without effect, so the
|
|
16037
|
+
// action completes with what it had and nothing is asked. A relationship GET
|
|
16038
|
+
// has no row of its own to answer with, and a write has nothing to answer:
|
|
16039
|
+
// both settle with an OfflineError carrying the policy's reason. A completed
|
|
16040
|
+
// GET asked to rerun never gets here (actions.js holds it).
|
|
16026
16041
|
const applyNetworkPolicy = (
|
|
16027
16042
|
restCallback,
|
|
16028
16043
|
{ verb, isMany, findItemInStore },
|
|
@@ -16033,7 +16048,7 @@ const applyNetworkPolicy = (
|
|
|
16033
16048
|
return restCallback(params, context);
|
|
16034
16049
|
}
|
|
16035
16050
|
if (verb === "GET" && !isMany && findItemInStore) {
|
|
16036
|
-
const item = findItemInStore(params);
|
|
16051
|
+
const item = findItemInStore(params, context.action);
|
|
16037
16052
|
if (item) {
|
|
16038
16053
|
return item;
|
|
16039
16054
|
}
|
|
@@ -16042,6 +16057,14 @@ const applyNetworkPolicy = (
|
|
|
16042
16057
|
};
|
|
16043
16058
|
};
|
|
16044
16059
|
|
|
16060
|
+
// WeakMap<action, itemId> — the row each GET action last completed with. A
|
|
16061
|
+
// reset clears the action's value; this survives it, so a GET run again after
|
|
16062
|
+
// a reset can still be answered from the store under a network policy.
|
|
16063
|
+
const lastGetItemIdWeakMap = new WeakMap();
|
|
16064
|
+
const getLastGetItemId = (action) => {
|
|
16065
|
+
return lastGetItemIdWeakMap.get(action);
|
|
16066
|
+
};
|
|
16067
|
+
|
|
16045
16068
|
// Captures the "file:line:column" of the user code that invoked the public
|
|
16046
16069
|
// function (resource(), .one(), .many(), withParams, …), so invalid-result
|
|
16047
16070
|
// errors can point at where the callbacks were declared, not at this file.
|
|
@@ -17610,6 +17633,7 @@ const LAYOUT_PROPS = {
|
|
|
17610
17633
|
flexWrap: applyToCssPropWhenTruthy("flexWrap", "wrap", "nowrap"),
|
|
17611
17634
|
grid: () => {},
|
|
17612
17635
|
gridTemplateColumns: PASS_THROUGH,
|
|
17636
|
+
gridTemplateRows: PASS_THROUGH,
|
|
17613
17637
|
display: PASS_THROUGH, // in case people write "display: none" (even if hidden prop is recommended)
|
|
17614
17638
|
row: () => {},
|
|
17615
17639
|
column: () => {},
|
|
@@ -73451,6 +73475,7 @@ const TimeWheel = ({
|
|
|
73451
73475
|
* size?: string,
|
|
73452
73476
|
* startLabel?: import("ignore:preact").ComponentChildren,
|
|
73453
73477
|
* endLabel?: import("ignore:preact").ComponentChildren,
|
|
73478
|
+
* labelPosition?: "before" | "above",
|
|
73454
73479
|
* timeProps?: object,
|
|
73455
73480
|
* [key: string]: any,
|
|
73456
73481
|
* }>}
|
|
@@ -73459,6 +73484,13 @@ const TimeWheel = ({
|
|
|
73459
73484
|
* @param {import("ignore:preact").ComponentChildren} [startLabel] What is written
|
|
73460
73485
|
* before the first time ("De"), and `endLabel` between the two ("à"). Say
|
|
73461
73486
|
* `null` for neither.
|
|
73487
|
+
* @param {"before"|"above"} [labelPosition="before"] Where each label stands.
|
|
73488
|
+
* Before its wheels, the span reads as one sentence ("De 9h00 à 18h00").
|
|
73489
|
+
* Above them, each bound is a column — "Début" over its wheels, "Fin" over
|
|
73490
|
+
* the other — two answers side by side, whose wheels land at the same place
|
|
73491
|
+
* whatever the width of the words. Labels that are nouns rather than
|
|
73492
|
+
* prepositions belong there; the group is still a row, and takes `flexWrap`
|
|
73493
|
+
* for screens too narrow to hold both columns.
|
|
73462
73494
|
* @param {number} [minuteStep=1] How many minutes apart the values on both
|
|
73463
73495
|
* minute wheels are.
|
|
73464
73496
|
* @param {{min?: number, max?: number}|number[]} [hours] Which hours both
|
|
@@ -73487,6 +73519,7 @@ const TimeRangeWheel = ({
|
|
|
73487
73519
|
size,
|
|
73488
73520
|
startLabel = naviI18n("time_range.from"),
|
|
73489
73521
|
endLabel = naviI18n("time_range.to"),
|
|
73522
|
+
labelPosition = "before",
|
|
73490
73523
|
timeProps,
|
|
73491
73524
|
startTimeProps,
|
|
73492
73525
|
endTimeProps,
|
|
@@ -73554,53 +73587,61 @@ const TimeRangeWheel = ({
|
|
|
73554
73587
|
...rest,
|
|
73555
73588
|
children: jsxs(AnsweredContext.Provider, {
|
|
73556
73589
|
value: answeredRef,
|
|
73557
|
-
children: [
|
|
73558
|
-
|
|
73559
|
-
|
|
73560
|
-
|
|
73561
|
-
|
|
73562
|
-
|
|
73563
|
-
|
|
73564
|
-
|
|
73565
|
-
|
|
73566
|
-
|
|
73567
|
-
|
|
73568
|
-
|
|
73569
|
-
|
|
73570
|
-
|
|
73571
|
-
|
|
73572
|
-
|
|
73573
|
-
|
|
73590
|
+
children: [jsx(TimeBound, {
|
|
73591
|
+
labelPosition: labelPosition,
|
|
73592
|
+
label: startLabel === null ? null : jsx(Text, {
|
|
73593
|
+
size: size,
|
|
73594
|
+
className: "navi_time_range_label",
|
|
73595
|
+
children: startLabel
|
|
73596
|
+
}),
|
|
73597
|
+
children: jsx(TimeWheel, {
|
|
73598
|
+
id: startId,
|
|
73599
|
+
ref: startRef,
|
|
73600
|
+
name: "start",
|
|
73601
|
+
minuteStep: minuteStep,
|
|
73602
|
+
hours: hours,
|
|
73603
|
+
loop: loop,
|
|
73604
|
+
size: size,
|
|
73605
|
+
placeholder: placeholder ? placeholder.start : undefined
|
|
73606
|
+
// e.detail.value is the settled WHEEL's own value (an hour, a
|
|
73607
|
+
// minute) — half a time. What the pair compares is this bound's
|
|
73608
|
+
// whole time, read off the element the listener sits on.
|
|
73609
|
+
,
|
|
73574
73610
|
|
|
73575
|
-
|
|
73576
|
-
|
|
73577
|
-
|
|
73578
|
-
|
|
73579
|
-
|
|
73580
|
-
|
|
73581
|
-
|
|
73582
|
-
|
|
73583
|
-
|
|
73584
|
-
|
|
73585
|
-
|
|
73586
|
-
|
|
73587
|
-
|
|
73588
|
-
|
|
73589
|
-
|
|
73590
|
-
|
|
73591
|
-
|
|
73592
|
-
|
|
73593
|
-
|
|
73594
|
-
|
|
73595
|
-
|
|
73596
|
-
|
|
73597
|
-
|
|
73598
|
-
|
|
73611
|
+
onnavi_wheel_settle: e => {
|
|
73612
|
+
keepBoundsApart("start", getUIStateFromElement(e.currentTarget), e);
|
|
73613
|
+
},
|
|
73614
|
+
...timeProps,
|
|
73615
|
+
...startTimeProps
|
|
73616
|
+
})
|
|
73617
|
+
}), jsx(TimeBound, {
|
|
73618
|
+
labelPosition: labelPosition,
|
|
73619
|
+
label: endLabel === null ? null : jsx(Text, {
|
|
73620
|
+
size: size,
|
|
73621
|
+
className: "navi_time_range_label",
|
|
73622
|
+
children: endLabel
|
|
73623
|
+
}),
|
|
73624
|
+
children: jsx(TimeWheel, {
|
|
73625
|
+
ref: endRef,
|
|
73626
|
+
name: "end",
|
|
73627
|
+
minuteStep: minuteStep,
|
|
73628
|
+
hours: hours,
|
|
73629
|
+
loop: loop,
|
|
73630
|
+
size: size,
|
|
73631
|
+
placeholder: placeholder ? placeholder.end : undefined,
|
|
73632
|
+
onnavi_wheel_settle: e => {
|
|
73633
|
+
keepBoundsApart("end", getUIStateFromElement(e.currentTarget), e);
|
|
73634
|
+
}
|
|
73635
|
+
// Which time it comes after, and how much room there must be between
|
|
73636
|
+
// the two: said on the LATER of the two, so the answer is given where
|
|
73637
|
+
// the time one would have to move is (see time_range_constraint.js).
|
|
73638
|
+
,
|
|
73599
73639
|
|
|
73600
|
-
|
|
73601
|
-
|
|
73602
|
-
|
|
73603
|
-
|
|
73640
|
+
"data-time-after": startId,
|
|
73641
|
+
"data-time-min-duration": minDuration,
|
|
73642
|
+
...timeProps,
|
|
73643
|
+
...endTimeProps
|
|
73644
|
+
})
|
|
73604
73645
|
})]
|
|
73605
73646
|
})
|
|
73606
73647
|
});
|
|
@@ -73719,6 +73760,27 @@ const resolveHourList = hours => {
|
|
|
73719
73760
|
};
|
|
73720
73761
|
const padTwo = value => String(value).padStart(2, "0");
|
|
73721
73762
|
|
|
73763
|
+
// A label and its wheels. Side by side, they are two items of the group's own
|
|
73764
|
+
// row. One above the other, they are one item: the two bounds then stand at
|
|
73765
|
+
// the same height and their wheels line up whatever the width of the words.
|
|
73766
|
+
const TimeBound = ({
|
|
73767
|
+
labelPosition,
|
|
73768
|
+
label,
|
|
73769
|
+
children
|
|
73770
|
+
}) => {
|
|
73771
|
+
if (labelPosition === "above") {
|
|
73772
|
+
return jsxs(Box, {
|
|
73773
|
+
flex: "y",
|
|
73774
|
+
alignX: "center",
|
|
73775
|
+
spacing: "xs",
|
|
73776
|
+
children: [label, children]
|
|
73777
|
+
});
|
|
73778
|
+
}
|
|
73779
|
+
return jsxs(Fragment$1, {
|
|
73780
|
+
children: [label, children]
|
|
73781
|
+
});
|
|
73782
|
+
};
|
|
73783
|
+
|
|
73722
73784
|
// The two times as one span, { start, end } — the shape a pair carries.
|
|
73723
73785
|
const aggregateSpan = childUIStateControllers => {
|
|
73724
73786
|
const span = {};
|