@jsenv/navi 0.29.97 → 0.29.100
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 +859 -798
- package/dist/jsenv_navi.js.map +29 -29
- package/package.json +1 -1
package/dist/jsenv_navi.js
CHANGED
|
@@ -38,7 +38,7 @@ installImportMetaCssBuild(import.meta);/**
|
|
|
38
38
|
* any of these, and a number is the last resort, not the first tool.
|
|
39
39
|
*/
|
|
40
40
|
|
|
41
|
-
const css$
|
|
41
|
+
const css$15 = /* css */`
|
|
42
42
|
@layer navi {
|
|
43
43
|
:root {
|
|
44
44
|
/* A control that overlaps its neighbours (the members of a Group share
|
|
@@ -92,7 +92,7 @@ const css$14 = /* css */`
|
|
|
92
92
|
}
|
|
93
93
|
}
|
|
94
94
|
`;
|
|
95
|
-
import.meta.css = [css$
|
|
95
|
+
import.meta.css = [css$15, "@jsenv/navi/src/navi_z_indexes.js"];
|
|
96
96
|
|
|
97
97
|
const addIntoArray = (array, ...valuesToAdd) => {
|
|
98
98
|
if (valuesToAdd.length === 1) {
|
|
@@ -361,7 +361,7 @@ installImportMetaCssBuild(import.meta);/**
|
|
|
361
361
|
* the very first render and the browser does everything on its own.
|
|
362
362
|
*/
|
|
363
363
|
const URL_TARGET_ATTRIBUTE = "data-url-target";
|
|
364
|
-
const css$
|
|
364
|
+
const css$14 = /* css */`
|
|
365
365
|
@layer navi {
|
|
366
366
|
[${URL_TARGET_ATTRIBUTE}] {
|
|
367
367
|
animation: navi_url_target var(--navi-url-target-duration, 2000ms)
|
|
@@ -379,7 +379,7 @@ const css$13 = /* css */`
|
|
|
379
379
|
}
|
|
380
380
|
}
|
|
381
381
|
`;
|
|
382
|
-
import.meta.css = [css$
|
|
382
|
+
import.meta.css = [css$14, "@jsenv/navi/src/nav/url_target/url_target.js"];
|
|
383
383
|
let urlTargetOptions = {
|
|
384
384
|
block: "start",
|
|
385
385
|
behavior: "instant",
|
|
@@ -6403,7 +6403,7 @@ installImportMetaCssBuild(import.meta);/**
|
|
|
6403
6403
|
* - Arrow automatically shows when pointing at a valid anchor element
|
|
6404
6404
|
* - Centers in viewport when no anchor element provided or anchor is too big
|
|
6405
6405
|
*/
|
|
6406
|
-
const css$
|
|
6406
|
+
const css$13 = /* css */`
|
|
6407
6407
|
@layer navi {
|
|
6408
6408
|
.navi_callout {
|
|
6409
6409
|
/* A callout is parented to what it explains, so it inherits from it — and
|
|
@@ -6646,7 +6646,7 @@ const openCallout = (message, {
|
|
|
6646
6646
|
skipFocus = false,
|
|
6647
6647
|
debug = () => {}
|
|
6648
6648
|
} = {}) => {
|
|
6649
|
-
import.meta.css = [css$
|
|
6649
|
+
import.meta.css = [css$13, "@jsenv/navi/src/control/rules/callout/callout.js"];
|
|
6650
6650
|
if (debug === true) {
|
|
6651
6651
|
debug = (e, ...args) => console.debug(`"${e.type}" -> `, ...args);
|
|
6652
6652
|
}
|
|
@@ -8012,12 +8012,20 @@ const isControlBusy = (field) => {
|
|
|
8012
8012
|
// An optimistic control stays interactive while its bound action runs:
|
|
8013
8013
|
// a new interaction is queued behind the run (see the action queue in
|
|
8014
8014
|
// control_hooks.jsx) rather than refused.
|
|
8015
|
-
if (
|
|
8016
|
-
|
|
8017
|
-
|
|
8018
|
-
|
|
8019
|
-
|
|
8020
|
-
|
|
8015
|
+
if (!field.optimistic && boundAction) {
|
|
8016
|
+
// The INSTANCE the proxy resolves to right now, not the proxy's own
|
|
8017
|
+
// signal: that one is a MIRROR, synced by an effect the settling batch
|
|
8018
|
+
// defers — read mid-batch (a state echo carrying the user's event back
|
|
8019
|
+
// down, an automatic follow-up), it still says RUNNING for an action
|
|
8020
|
+
// that is already over, and the gate would refuse — callout included —
|
|
8021
|
+
// for nothing. The resolved instance is the live truth: at that echo it
|
|
8022
|
+
// is the instance that just settled, already COMPLETED. And it IS the
|
|
8023
|
+
// running one whenever one runs — a non-optimistic control's state
|
|
8024
|
+
// cannot move mid-run, this very gate blocks it.
|
|
8025
|
+
const liveAction = boundAction.getCurrentAction?.() ?? boundAction;
|
|
8026
|
+
if (liveAction.runningStateSignal.value === RUNNING) {
|
|
8027
|
+
return true;
|
|
8028
|
+
}
|
|
8021
8029
|
}
|
|
8022
8030
|
if (field.loadingFromParent) {
|
|
8023
8031
|
const parent = field.parentUIStateController;
|
|
@@ -8940,10 +8948,12 @@ const REQUIRED_CONSTRAINT = {
|
|
|
8940
8948
|
};
|
|
8941
8949
|
}
|
|
8942
8950
|
|
|
8943
|
-
// checkbox_group controller: check aggregate uiState array
|
|
8951
|
+
// checkbox_group controller: check aggregate uiState array. An empty
|
|
8952
|
+
// selection aggregates to undefined, not to an empty array (see
|
|
8953
|
+
// GROUP_DEFAULTS.checkbox_group) — both mean "nothing checked" here.
|
|
8944
8954
|
if (controlType === "checkbox_group") {
|
|
8945
8955
|
const uiState = field.uiState;
|
|
8946
|
-
if (uiState.length > 0) {
|
|
8956
|
+
if (uiState !== undefined && uiState.length > 0) {
|
|
8947
8957
|
return null;
|
|
8948
8958
|
}
|
|
8949
8959
|
return {
|
|
@@ -11928,6 +11938,39 @@ const reportErrorIfNobodyDisplaysIt = (error, { action } = {}) => {
|
|
|
11928
11938
|
|
|
11929
11939
|
const SYMBOL_OBJECT_SIGNAL = Symbol.for("navi_object_signal");
|
|
11930
11940
|
|
|
11941
|
+
/*
|
|
11942
|
+
* Actions: async callbacks wrapped in reactive state.
|
|
11943
|
+
*
|
|
11944
|
+
* An action owns a set of signals (params, runningState, error, value, data)
|
|
11945
|
+
* and moves through IDLE → RUNNING → COMPLETED / FAILED / ABORTED (see
|
|
11946
|
+
* action_run_states.js). `createAction(callback)` returns the root action;
|
|
11947
|
+
* `.bindParams(params)` derives child actions (one per params value, cached),
|
|
11948
|
+
* and binding a signal (or an object containing signals) returns an action
|
|
11949
|
+
* *proxy* that retargets itself to the right child action as the signal
|
|
11950
|
+
* changes (see createActionProxyFromSignal).
|
|
11951
|
+
*
|
|
11952
|
+
* How things run: prerun/run/rerun/reset never execute the action directly —
|
|
11953
|
+
* they go through `dispatchActions`, which the navigation integration can
|
|
11954
|
+
* replace via `setActionDispatcher` so that every action update participates
|
|
11955
|
+
* in the browser navigation lifecycle (abort signals, navigation events).
|
|
11956
|
+
* The default dispatcher calls `updateActions`, the single entry point that
|
|
11957
|
+
* resolves priorities between the four operation sets (reset > rerun > run >
|
|
11958
|
+
* prerun) and performs them.
|
|
11959
|
+
*
|
|
11960
|
+
* Memory design (the surprising part): nothing here keeps actions alive.
|
|
11961
|
+
* Child actions are held through ephemerons (createJsValueWeakMap) so a child
|
|
11962
|
+
* and its params are garbage-collected together, running actions live in
|
|
11963
|
+
* iterable *weak* sets, and property/signal mirroring uses weakEffect. Two
|
|
11964
|
+
* consequences to be aware of:
|
|
11965
|
+
* - an action can exist in several places only if everyone shares the same
|
|
11966
|
+
* instance (the caches above are what makes lookups return it);
|
|
11967
|
+
* - prerun actions may have no other reference yet, so
|
|
11968
|
+
* prerunProtectionRegistry pins them for a few minutes.
|
|
11969
|
+
*
|
|
11970
|
+
* An action run never throws: failures land in errorSignal and are reported
|
|
11971
|
+
* once, by one rule, in action_error_report.js (see the comment in onRunError).
|
|
11972
|
+
*/
|
|
11973
|
+
|
|
11931
11974
|
let DEBUG$1 = false;
|
|
11932
11975
|
const enableDebugActions = () => {
|
|
11933
11976
|
DEBUG$1 = true;
|
|
@@ -11966,7 +12009,7 @@ const getActionDispatcher = () => dispatchActions;
|
|
|
11966
12009
|
const rerunActions = async (actionSet, options) => {
|
|
11967
12010
|
return dispatchActions({
|
|
11968
12011
|
rerunSet: actionSet,
|
|
11969
|
-
reason: "rerunActions was
|
|
12012
|
+
reason: "rerunActions was called",
|
|
11970
12013
|
...options,
|
|
11971
12014
|
});
|
|
11972
12015
|
};
|
|
@@ -11985,7 +12028,7 @@ const rerunActions = async (actionSet, options) => {
|
|
|
11985
12028
|
*/
|
|
11986
12029
|
const prerunProtectionRegistry = (() => {
|
|
11987
12030
|
const protectedActionMap = new Map(); // action -> { timeoutId, timestamp }
|
|
11988
|
-
const PROTECTION_DURATION = 5 * 60 * 1000; // 5 minutes
|
|
12031
|
+
const PROTECTION_DURATION = 5 * 60 * 1000; // 5 minutes
|
|
11989
12032
|
|
|
11990
12033
|
const unprotect = (action) => {
|
|
11991
12034
|
const protection = protectedActionMap.get(action);
|
|
@@ -11999,7 +12042,7 @@ const prerunProtectionRegistry = (() => {
|
|
|
11999
12042
|
|
|
12000
12043
|
return {
|
|
12001
12044
|
protect(action) {
|
|
12002
|
-
//
|
|
12045
|
+
// already protected: extend the protection
|
|
12003
12046
|
if (protectedActionMap.has(action)) {
|
|
12004
12047
|
const existing = protectedActionMap.get(action);
|
|
12005
12048
|
clearTimeout(existing.timeoutId);
|
|
@@ -12019,29 +12062,11 @@ const prerunProtectionRegistry = (() => {
|
|
|
12019
12062
|
},
|
|
12020
12063
|
|
|
12021
12064
|
unprotect,
|
|
12022
|
-
|
|
12023
|
-
isProtected(action) {
|
|
12024
|
-
return protectedActionMap.has(action);
|
|
12025
|
-
},
|
|
12026
|
-
|
|
12027
|
-
// Pour debugging
|
|
12028
|
-
getProtectedActions() {
|
|
12029
|
-
return Array.from(protectedActionMap.keys());
|
|
12030
|
-
},
|
|
12031
|
-
|
|
12032
|
-
// Nettoyage manuel si nécessaire
|
|
12033
|
-
clear() {
|
|
12034
|
-
for (const [, protection] of protectedActionMap) {
|
|
12035
|
-
clearTimeout(protection.timeoutId);
|
|
12036
|
-
}
|
|
12037
|
-
protectedActionMap.clear();
|
|
12038
|
-
},
|
|
12039
12065
|
};
|
|
12040
12066
|
})();
|
|
12041
12067
|
|
|
12042
12068
|
const formatActionSet = (actionSet, prefix = "") => {
|
|
12043
|
-
let message =
|
|
12044
|
-
message += `${prefix}`;
|
|
12069
|
+
let message = prefix;
|
|
12045
12070
|
for (const action of actionSet) {
|
|
12046
12071
|
message += "\n";
|
|
12047
12072
|
message += prefixFirstAndIndentRemainingLines(String(action), {
|
|
@@ -12376,7 +12401,6 @@ ${lines.join("\n")}`);
|
|
|
12376
12401
|
};
|
|
12377
12402
|
|
|
12378
12403
|
const NO_PARAMS = { __no_params__: true };
|
|
12379
|
-
const initialParamsDefault = NO_PARAMS;
|
|
12380
12404
|
const mergeActionParams = (currentParams, newParams) => {
|
|
12381
12405
|
if (currentParams === NO_PARAMS) {
|
|
12382
12406
|
return newParams;
|
|
@@ -12424,7 +12448,7 @@ const createAction = (callback, rootOptions = {}) => {
|
|
|
12424
12448
|
} = options;
|
|
12425
12449
|
if (!Object.hasOwn(options, "params")) {
|
|
12426
12450
|
// even undefined should be respected it's only when not provided at all we use default
|
|
12427
|
-
params =
|
|
12451
|
+
params = NO_PARAMS;
|
|
12428
12452
|
}
|
|
12429
12453
|
if (value === undefined && data !== undefined) {
|
|
12430
12454
|
value = data;
|
|
@@ -12437,11 +12461,7 @@ const createAction = (callback, rootOptions = {}) => {
|
|
|
12437
12461
|
const errorSignal = signal(error);
|
|
12438
12462
|
const valueSignal = signal(valueInitial);
|
|
12439
12463
|
const dataSignal = valueToData
|
|
12440
|
-
? computed(() =>
|
|
12441
|
-
const value = valueSignal.value;
|
|
12442
|
-
const data = valueToData(value);
|
|
12443
|
-
return data;
|
|
12444
|
-
})
|
|
12464
|
+
? computed(() => valueToData(valueSignal.value))
|
|
12445
12465
|
: valueSignal;
|
|
12446
12466
|
|
|
12447
12467
|
const prerun = (options) => {
|
|
@@ -12474,7 +12494,7 @@ const createAction = (callback, rootOptions = {}) => {
|
|
|
12474
12494
|
return dispatchSingleAction(action, "reset", options);
|
|
12475
12495
|
};
|
|
12476
12496
|
const abort = (reason) => {
|
|
12477
|
-
if (
|
|
12497
|
+
if (runningStateSignal.peek() !== RUNNING) {
|
|
12478
12498
|
return false;
|
|
12479
12499
|
}
|
|
12480
12500
|
const actionAbort = actionAbortMap.get(action);
|
|
@@ -12500,7 +12520,7 @@ const createAction = (callback, rootOptions = {}) => {
|
|
|
12500
12520
|
*/
|
|
12501
12521
|
const childActionWeakMap = createJsValueWeakMap();
|
|
12502
12522
|
const _bindParams = (newParamsOrSignal, options = {}) => {
|
|
12503
|
-
//
|
|
12523
|
+
// Case 1: a signal → proxy that retargets as the signal changes
|
|
12504
12524
|
if (isSignal(newParamsOrSignal)) {
|
|
12505
12525
|
const combinedParamsSignal = computed(() => {
|
|
12506
12526
|
const newParams = newParamsOrSignal.value;
|
|
@@ -12514,7 +12534,7 @@ const createAction = (callback, rootOptions = {}) => {
|
|
|
12514
12534
|
);
|
|
12515
12535
|
}
|
|
12516
12536
|
|
|
12517
|
-
//
|
|
12537
|
+
// Case 2: a plain object → child action, or proxy when it contains signals
|
|
12518
12538
|
if (isPlainObject$1(newParamsOrSignal)) {
|
|
12519
12539
|
const staticParams = {};
|
|
12520
12540
|
const signalMap = new Map();
|
|
@@ -12535,7 +12555,7 @@ const createAction = (callback, rootOptions = {}) => {
|
|
|
12535
12555
|
}
|
|
12536
12556
|
|
|
12537
12557
|
if (signalMap.size === 0) {
|
|
12538
|
-
//
|
|
12558
|
+
// no signals: plain static merge
|
|
12539
12559
|
if (
|
|
12540
12560
|
params === null ||
|
|
12541
12561
|
typeof params !== "object" ||
|
|
@@ -12553,24 +12573,27 @@ const createAction = (callback, rootOptions = {}) => {
|
|
|
12553
12573
|
});
|
|
12554
12574
|
}
|
|
12555
12575
|
|
|
12556
|
-
|
|
12557
|
-
|
|
12558
|
-
const params = {};
|
|
12576
|
+
const combinedParamsSignal = computed(() => {
|
|
12577
|
+
const combinedParams = {};
|
|
12559
12578
|
for (const key of keyArray) {
|
|
12560
12579
|
const signalForThisKey = signalMap.get(key);
|
|
12561
12580
|
if (signalForThisKey) {
|
|
12562
12581
|
// eslint-disable-next-line signals/no-conditional-value-read
|
|
12563
|
-
|
|
12582
|
+
combinedParams[key] = signalForThisKey.value;
|
|
12564
12583
|
} else {
|
|
12565
|
-
|
|
12584
|
+
combinedParams[key] = staticParams[key];
|
|
12566
12585
|
}
|
|
12567
12586
|
}
|
|
12568
|
-
return
|
|
12587
|
+
return combinedParams;
|
|
12569
12588
|
});
|
|
12570
|
-
return createActionProxyFromSignal(
|
|
12589
|
+
return createActionProxyFromSignal(
|
|
12590
|
+
action,
|
|
12591
|
+
combinedParamsSignal,
|
|
12592
|
+
options,
|
|
12593
|
+
);
|
|
12571
12594
|
}
|
|
12572
12595
|
|
|
12573
|
-
//
|
|
12596
|
+
// Case 3: a primitive or non-plain object (DOM event, …) → child action
|
|
12574
12597
|
return createChildAction({
|
|
12575
12598
|
params: newParamsOrSignal,
|
|
12576
12599
|
...options,
|
|
@@ -12603,7 +12626,6 @@ const createAction = (callback, rootOptions = {}) => {
|
|
|
12603
12626
|
return childAction;
|
|
12604
12627
|
};
|
|
12605
12628
|
|
|
12606
|
-
// ✅ Implement matchAllSelfOrDescendant
|
|
12607
12629
|
const matchAllSelfOrDescendant = (predicate, { includeProxies } = {}) => {
|
|
12608
12630
|
const matches = [];
|
|
12609
12631
|
|
|
@@ -12638,32 +12660,31 @@ const createAction = (callback, rootOptions = {}) => {
|
|
|
12638
12660
|
generateActionCallSource(name, params),
|
|
12639
12661
|
);
|
|
12640
12662
|
|
|
12641
|
-
|
|
12642
|
-
|
|
12643
|
-
|
|
12644
|
-
|
|
12645
|
-
|
|
12646
|
-
|
|
12647
|
-
|
|
12648
|
-
|
|
12649
|
-
|
|
12650
|
-
|
|
12651
|
-
|
|
12652
|
-
|
|
12653
|
-
|
|
12654
|
-
|
|
12655
|
-
|
|
12656
|
-
|
|
12657
|
-
|
|
12658
|
-
|
|
12659
|
-
|
|
12660
|
-
|
|
12661
|
-
|
|
12662
|
-
|
|
12663
|
-
|
|
12664
|
-
|
|
12665
|
-
|
|
12666
|
-
}
|
|
12663
|
+
// The action is a callable: `ACTION(params)` is `ACTION.bindParams(params).rerun()`
|
|
12664
|
+
action = function actionFunction(...args) {
|
|
12665
|
+
if (args.length === 0) {
|
|
12666
|
+
return action.rerun();
|
|
12667
|
+
}
|
|
12668
|
+
const boundAction = bindParams(...args);
|
|
12669
|
+
return boundAction.rerun();
|
|
12670
|
+
};
|
|
12671
|
+
Object.defineProperty(action, "name", {
|
|
12672
|
+
configurable: true,
|
|
12673
|
+
get() {
|
|
12674
|
+
return actionNameSignal.value;
|
|
12675
|
+
},
|
|
12676
|
+
});
|
|
12677
|
+
Object.defineProperty(action, "callSource", {
|
|
12678
|
+
configurable: true,
|
|
12679
|
+
get() {
|
|
12680
|
+
return actionCallSourceSignal.value;
|
|
12681
|
+
},
|
|
12682
|
+
set(v) {
|
|
12683
|
+
actionCallSourceSignal.value = v;
|
|
12684
|
+
},
|
|
12685
|
+
});
|
|
12686
|
+
// makes createAction(anAction) return the action itself
|
|
12687
|
+
actionWeakMap.set(action, action);
|
|
12667
12688
|
|
|
12668
12689
|
// Assign all the action properties and methods to the function
|
|
12669
12690
|
Object.assign(action, {
|
|
@@ -12685,7 +12706,7 @@ const createAction = (callback, rootOptions = {}) => {
|
|
|
12685
12706
|
reset,
|
|
12686
12707
|
abort,
|
|
12687
12708
|
bindParams,
|
|
12688
|
-
matchAllSelfOrDescendant,
|
|
12709
|
+
matchAllSelfOrDescendant,
|
|
12689
12710
|
replaceParams: (newParams) => {
|
|
12690
12711
|
const currentParams = paramsSignal.value;
|
|
12691
12712
|
const nextParams = mergeActionParams(currentParams, newParams);
|
|
@@ -12713,7 +12734,7 @@ const createAction = (callback, rootOptions = {}) => {
|
|
|
12713
12734
|
toString: () => action.callSource,
|
|
12714
12735
|
meta,
|
|
12715
12736
|
debug: (...args) => {
|
|
12716
|
-
if (!meta.debug
|
|
12737
|
+
if (!meta.debug && !DEBUG$1) {
|
|
12717
12738
|
return;
|
|
12718
12739
|
}
|
|
12719
12740
|
console.debug(...args);
|
|
@@ -12728,7 +12749,8 @@ const createAction = (callback, rootOptions = {}) => {
|
|
|
12728
12749
|
});
|
|
12729
12750
|
Object.preventExtensions(action);
|
|
12730
12751
|
|
|
12731
|
-
//
|
|
12752
|
+
// Mirror signals into plain properties (action.error, action.data, …)
|
|
12753
|
+
// so non-reactive code can read them without subscribing.
|
|
12732
12754
|
{
|
|
12733
12755
|
weakEffect([action], (actionRef) => {
|
|
12734
12756
|
isPrerun = isPrerunSignal.value;
|
|
@@ -12754,7 +12776,6 @@ const createAction = (callback, rootOptions = {}) => {
|
|
|
12754
12776
|
});
|
|
12755
12777
|
}
|
|
12756
12778
|
|
|
12757
|
-
// Propriétés privées
|
|
12758
12779
|
{
|
|
12759
12780
|
const ui = {
|
|
12760
12781
|
renderLoaded: null,
|
|
@@ -13033,8 +13054,8 @@ const createAction = (callback, rootOptions = {}) => {
|
|
|
13033
13054
|
* @param {boolean} options.rerunOnChange - Ensures the action is rerun every time a signal value is modified.
|
|
13034
13055
|
* This enables live updates - for example, performing an HTTP GET request every time
|
|
13035
13056
|
* a list of filters changes, providing real-time results without user interaction.
|
|
13036
|
-
* @param {boolean} options.inheritData - When
|
|
13037
|
-
* By default (
|
|
13057
|
+
* @param {boolean} options.inheritData - When false, each new target action starts fresh with no inherited state.
|
|
13058
|
+
* By default (true), the proxy carries over the previous target's value and error into the new action.
|
|
13038
13059
|
* This keeps the facade in sync with the latest known data: `action.dataSignal.value` only changes when a
|
|
13039
13060
|
* new action completes, not when it starts loading. Code that needs to distinguish loading state can still
|
|
13040
13061
|
* check `action.runningState`, while code that just reads `action.data` always sees the most recent
|
|
@@ -13128,6 +13149,7 @@ const createActionProxyFromSignal = (
|
|
|
13128
13149
|
currentAction = actionTarget;
|
|
13129
13150
|
currentActionPrivateProperties = getActionPrivateProperties(actionTarget);
|
|
13130
13151
|
}
|
|
13152
|
+
|
|
13131
13153
|
actionTargetPreviousWeakRef = actionTarget
|
|
13132
13154
|
? new WeakRef(actionTarget)
|
|
13133
13155
|
: null;
|
|
@@ -13153,25 +13175,22 @@ const createActionProxyFromSignal = (
|
|
|
13153
13175
|
|
|
13154
13176
|
const nameSignal = signal(action.name);
|
|
13155
13177
|
const callSourceSignal = signal(`[Proxy] ${action.callSource}`);
|
|
13156
|
-
|
|
13157
|
-
|
|
13158
|
-
|
|
13159
|
-
|
|
13160
|
-
|
|
13161
|
-
|
|
13162
|
-
|
|
13163
|
-
|
|
13164
|
-
|
|
13165
|
-
|
|
13166
|
-
|
|
13167
|
-
|
|
13168
|
-
|
|
13169
|
-
|
|
13170
|
-
|
|
13171
|
-
|
|
13172
|
-
});
|
|
13173
|
-
actionWeakMap.set(actionProxy, actionProxy);
|
|
13174
|
-
}
|
|
13178
|
+
const actionProxy = function actionProxyFunction() {
|
|
13179
|
+
return actionProxy.rerun();
|
|
13180
|
+
};
|
|
13181
|
+
Object.defineProperty(actionProxy, "name", {
|
|
13182
|
+
configurable: true,
|
|
13183
|
+
get() {
|
|
13184
|
+
return nameSignal.value;
|
|
13185
|
+
},
|
|
13186
|
+
});
|
|
13187
|
+
Object.defineProperty(actionProxy, "callSource", {
|
|
13188
|
+
configurable: true,
|
|
13189
|
+
get() {
|
|
13190
|
+
return callSourceSignal.value;
|
|
13191
|
+
},
|
|
13192
|
+
});
|
|
13193
|
+
actionWeakMap.set(actionProxy, actionProxy);
|
|
13175
13194
|
|
|
13176
13195
|
// Create our own signal for params that we control completely
|
|
13177
13196
|
const proxyParamsSignal = signal(paramsSignal.value);
|
|
@@ -13374,11 +13393,6 @@ const isPlainObject$1 = (obj) => {
|
|
|
13374
13393
|
);
|
|
13375
13394
|
};
|
|
13376
13395
|
|
|
13377
|
-
const COMPLETED_ACTION = createAction(() => undefined, {
|
|
13378
|
-
name: "ACTION.COMPLETED",
|
|
13379
|
-
});
|
|
13380
|
-
getActionPrivateProperties(COMPLETED_ACTION).performRun({});
|
|
13381
|
-
|
|
13382
13396
|
// used by form elements such as <input>, <select>, <textarea> to have their own action bound to a single parameter
|
|
13383
13397
|
// when inside a <form> the form params are updated when the form element single param is updated
|
|
13384
13398
|
const useActionBoundToOneParam = (action, paramsSignal) => {
|
|
@@ -13400,19 +13414,27 @@ const useAction = (action, paramsSignal) => {
|
|
|
13400
13414
|
};
|
|
13401
13415
|
|
|
13402
13416
|
const useBoundAction = (action, actionParamsSignal) => {
|
|
13403
|
-
|
|
13417
|
+
// The cache gives an inline function a stable action identity across renders.
|
|
13418
|
+
// That identity is only wanted while `action` stays the same kind
|
|
13419
|
+
// (function to function); when the kind changes — none ↔ function ↔ action
|
|
13420
|
+
// object — each branch clears the other kind's refs so the control picks up
|
|
13421
|
+
// its new role instead of the action it was born with.
|
|
13422
|
+
const noopActionRef = useRef();
|
|
13423
|
+
const actionFromFunctionRef = useRef();
|
|
13404
13424
|
const actionCallbackRef = useRef();
|
|
13405
13425
|
|
|
13406
13426
|
if (!action) {
|
|
13407
|
-
|
|
13408
|
-
|
|
13409
|
-
|
|
13427
|
+
actionFromFunctionRef.current = undefined;
|
|
13428
|
+
actionCallbackRef.current = undefined;
|
|
13429
|
+
const existingNoopAction = noopActionRef.current;
|
|
13430
|
+
if (existingNoopAction) {
|
|
13431
|
+
return existingNoopAction;
|
|
13410
13432
|
}
|
|
13411
13433
|
const noopAction = createAction(() => {}, { params: undefined });
|
|
13412
13434
|
const noopActionBound = actionParamsSignal
|
|
13413
13435
|
? noopAction.bindParams(actionParamsSignal)
|
|
13414
13436
|
: noopAction;
|
|
13415
|
-
|
|
13437
|
+
noopActionRef.current = noopActionBound;
|
|
13416
13438
|
return noopActionBound;
|
|
13417
13439
|
}
|
|
13418
13440
|
const isFunction = typeof action === "function";
|
|
@@ -13423,7 +13445,7 @@ const useBoundAction = (action, actionParamsSignal) => {
|
|
|
13423
13445
|
}
|
|
13424
13446
|
if (isFunctionButNotAnActionFunction(action)) {
|
|
13425
13447
|
actionCallbackRef.current = action;
|
|
13426
|
-
const existingAction =
|
|
13448
|
+
const existingAction = actionFromFunctionRef.current;
|
|
13427
13449
|
if (existingAction) {
|
|
13428
13450
|
return existingAction;
|
|
13429
13451
|
}
|
|
@@ -13439,14 +13461,16 @@ const useBoundAction = (action, actionParamsSignal) => {
|
|
|
13439
13461
|
},
|
|
13440
13462
|
);
|
|
13441
13463
|
if (!actionParamsSignal) {
|
|
13442
|
-
|
|
13464
|
+
actionFromFunctionRef.current = actionFromFunction;
|
|
13443
13465
|
return actionFromFunction;
|
|
13444
13466
|
}
|
|
13445
13467
|
const actionBoundToParams =
|
|
13446
13468
|
actionFromFunction.bindParams(actionParamsSignal);
|
|
13447
|
-
|
|
13469
|
+
actionFromFunctionRef.current = actionBoundToParams;
|
|
13448
13470
|
return actionBoundToParams;
|
|
13449
13471
|
}
|
|
13472
|
+
actionFromFunctionRef.current = undefined;
|
|
13473
|
+
actionCallbackRef.current = undefined;
|
|
13450
13474
|
if (actionParamsSignal) {
|
|
13451
13475
|
return action.bindParams(actionParamsSignal);
|
|
13452
13476
|
}
|
|
@@ -18873,7 +18897,7 @@ const setupNetworkMonitoring = () => {
|
|
|
18873
18897
|
};
|
|
18874
18898
|
setupNetworkMonitoring();
|
|
18875
18899
|
|
|
18876
|
-
installImportMetaCssBuild(import.meta);const css$
|
|
18900
|
+
installImportMetaCssBuild(import.meta);const css$12 = /* css */`
|
|
18877
18901
|
.navi_loading_indicator_fluid_container {
|
|
18878
18902
|
position: relative;
|
|
18879
18903
|
display: flex;
|
|
@@ -18905,7 +18929,7 @@ const LoadingIndicatorFluid = ({
|
|
|
18905
18929
|
visuallyHidden,
|
|
18906
18930
|
...rest
|
|
18907
18931
|
}) => {
|
|
18908
|
-
import.meta.css = [css$
|
|
18932
|
+
import.meta.css = [css$12, "@jsenv/navi/src/graphic/loading/loading_indicator_fluid.jsx"];
|
|
18909
18933
|
const ref = useRef(null);
|
|
18910
18934
|
// The container dimensions can be deduced from the ref itself as the indicator is absolute inset 0
|
|
18911
18935
|
const [containerWidth, setContainerWidth] = useState(0);
|
|
@@ -19110,7 +19134,7 @@ const LoadingRectangleSvg = ({
|
|
|
19110
19134
|
});
|
|
19111
19135
|
};
|
|
19112
19136
|
|
|
19113
|
-
installImportMetaCssBuild(import.meta);const css$
|
|
19137
|
+
installImportMetaCssBuild(import.meta);const css$11 = /* css */`
|
|
19114
19138
|
.navi_loading_outline_wrapper {
|
|
19115
19139
|
position: absolute;
|
|
19116
19140
|
/* Controls place the outline slightly outside their box, right on top of
|
|
@@ -19147,7 +19171,7 @@ installImportMetaCssBuild(import.meta);const css$10 = /* css */`
|
|
|
19147
19171
|
}
|
|
19148
19172
|
`;
|
|
19149
19173
|
const LoadingOutline = props => {
|
|
19150
|
-
import.meta.css = [css$
|
|
19174
|
+
import.meta.css = [css$11, "@jsenv/navi/src/graphic/loading/loading_outline.jsx"];
|
|
19151
19175
|
if (props.containerRef) {
|
|
19152
19176
|
const container = props.containerRef.current;
|
|
19153
19177
|
if (!container) {
|
|
@@ -19437,7 +19461,7 @@ const selectByTextStrings = (element, range, startText, endText) => {
|
|
|
19437
19461
|
};
|
|
19438
19462
|
|
|
19439
19463
|
installImportMetaCssBuild(import.meta);// https://jsfiddle.net/v5xzJ/4/
|
|
19440
|
-
const css
|
|
19464
|
+
const css$10 = /* css */`
|
|
19441
19465
|
@layer navi {
|
|
19442
19466
|
.navi_text {
|
|
19443
19467
|
&[data-skeleton] {
|
|
@@ -19958,7 +19982,7 @@ const TextShrinkWrap = props => {
|
|
|
19958
19982
|
});
|
|
19959
19983
|
};
|
|
19960
19984
|
const TextUI = props => {
|
|
19961
|
-
import.meta.css = [css
|
|
19985
|
+
import.meta.css = [css$10, "@jsenv/navi/src/text/text.jsx"];
|
|
19962
19986
|
let {
|
|
19963
19987
|
ref,
|
|
19964
19988
|
spacing,
|
|
@@ -27333,18 +27357,31 @@ const useInteractiveProps = (props, {
|
|
|
27333
27357
|
controlRootProps.onnavi_action_end?.(e);
|
|
27334
27358
|
uiStateController.onActionEnd(e);
|
|
27335
27359
|
|
|
27336
|
-
//
|
|
27337
|
-
//
|
|
27338
|
-
//
|
|
27360
|
+
// Auto-trigger the parent group's action after the leaf action
|
|
27361
|
+
// completes, for the groups that ARE one control made of parts: a
|
|
27362
|
+
// radio or checkbox group, a wheel group (an hour wheel settling is
|
|
27363
|
+
// the time settling). The parent has already aggregated the new
|
|
27364
|
+
// state by now, so uiStateSignal is correct. One level only: the
|
|
27365
|
+
// parent's own action end does not climb further unless that parent
|
|
27366
|
+
// is itself such a group.
|
|
27339
27367
|
const parentController = uiStateController.parentUIStateController;
|
|
27340
|
-
if (parentController && (parentController.controlType === "radio_group" || parentController.controlType === "checkbox_group")) {
|
|
27368
|
+
if (parentController && (parentController.controlType === "radio_group" || parentController.controlType === "checkbox_group" || parentController.controlType === "wheel_group")) {
|
|
27341
27369
|
const parentEl = parentController.ref.current;
|
|
27342
27370
|
if (parentEl) {
|
|
27343
|
-
const originalEvent = e.detail.eventChain[0];
|
|
27344
27371
|
dispatchRequestAction(parentEl, {
|
|
27345
|
-
event:
|
|
27372
|
+
event: e.detail.eventChain[0],
|
|
27346
27373
|
name: "auto_group_action",
|
|
27347
|
-
requester: e.detail.requester
|
|
27374
|
+
requester: e.detail.requester,
|
|
27375
|
+
// The interactivity gate is not re-asked: the user already
|
|
27376
|
+
// interacted — with the child, whose gate said yes — and this
|
|
27377
|
+
// follow-up is automatic. Asking again would also answer
|
|
27378
|
+
// wrong: this event is dispatched inside the batch() that
|
|
27379
|
+
// settles the child's action, where a bound action still
|
|
27380
|
+
// READS as running (its state is mirrored through a signal
|
|
27381
|
+
// effect the batch defers, see watchActionCompletion) — the
|
|
27382
|
+
// busy constraint would refuse the group for an action that
|
|
27383
|
+
// is already over. The validity gate still applies.
|
|
27384
|
+
bypassInteractivity: true
|
|
27348
27385
|
});
|
|
27349
27386
|
}
|
|
27350
27387
|
}
|
|
@@ -27406,7 +27443,7 @@ const getAssociatedLabels = element => {
|
|
|
27406
27443
|
return Array.from(element.labels);
|
|
27407
27444
|
};
|
|
27408
27445
|
|
|
27409
|
-
installImportMetaCssBuild(import.meta);const css
|
|
27446
|
+
installImportMetaCssBuild(import.meta);const css$$ = /* css */`
|
|
27410
27447
|
@layer navi {
|
|
27411
27448
|
.navi_button {
|
|
27412
27449
|
--button-border-radius: var(--navi-control-border-radius);
|
|
@@ -27837,7 +27874,7 @@ installImportMetaCssBuild(import.meta);const css$_ = /* css */`
|
|
|
27837
27874
|
}
|
|
27838
27875
|
`;
|
|
27839
27876
|
const ButtonUI = props => {
|
|
27840
|
-
import.meta.css = [css
|
|
27877
|
+
import.meta.css = [css$$, "@jsenv/navi/src/control/input/button_ui.jsx"];
|
|
27841
27878
|
const {
|
|
27842
27879
|
ref,
|
|
27843
27880
|
// href/link
|
|
@@ -29548,7 +29585,7 @@ installImportMetaCssBuild(import.meta);/**
|
|
|
29548
29585
|
* reaches the real container.
|
|
29549
29586
|
*/
|
|
29550
29587
|
let openLocalDialogCount = 0;
|
|
29551
|
-
const css$
|
|
29588
|
+
const css$_ = /* css */`
|
|
29552
29589
|
@layer navi {
|
|
29553
29590
|
.navi_dialog {
|
|
29554
29591
|
/* Min gap between the dialog and the edges of its container. Written
|
|
@@ -30132,7 +30169,7 @@ const css$Z = /* css */`
|
|
|
30132
30169
|
* @param {import("ignore:preact").ComponentChildren} props.children
|
|
30133
30170
|
*/
|
|
30134
30171
|
const Dialog = props => {
|
|
30135
|
-
import.meta.css = [css$
|
|
30172
|
+
import.meta.css = [css$_, "@jsenv/navi/src/layout/dialog.jsx"];
|
|
30136
30173
|
if (props.openController) {
|
|
30137
30174
|
return jsx(ControlledDialog, {
|
|
30138
30175
|
...props
|
|
@@ -31124,7 +31161,7 @@ installImportMetaCssBuild(import.meta);/**
|
|
|
31124
31161
|
* and applied.
|
|
31125
31162
|
*/
|
|
31126
31163
|
let openLocalPopoverCount = 0;
|
|
31127
|
-
const css$
|
|
31164
|
+
const css$Z = /* css */`
|
|
31128
31165
|
@layer navi {
|
|
31129
31166
|
.navi_popover {
|
|
31130
31167
|
/* soft: user-configurable preferred max-height. Kept as a *default*
|
|
@@ -31580,7 +31617,7 @@ const css$Y = /* css */`
|
|
|
31580
31617
|
* @param {import("ignore:preact").ComponentChildren} props.children
|
|
31581
31618
|
*/
|
|
31582
31619
|
const Popover = props => {
|
|
31583
|
-
import.meta.css = [css$
|
|
31620
|
+
import.meta.css = [css$Z, "@jsenv/navi/src/layout/popover.jsx"];
|
|
31584
31621
|
if (props.openController) {
|
|
31585
31622
|
return jsx(ControlledPopover, {
|
|
31586
31623
|
...props
|
|
@@ -32608,7 +32645,7 @@ installImportMetaCssBuild(import.meta);/**
|
|
|
32608
32645
|
* event, and a caller replacing the body entirely then has one protocol to
|
|
32609
32646
|
* follow — `--navi-confirm` for yes, anything that closes for no.
|
|
32610
32647
|
*/
|
|
32611
|
-
const css$
|
|
32648
|
+
const css$Y = /* css */`
|
|
32612
32649
|
/* The width lives on the body rather than on the popup, so that custom
|
|
32613
32650
|
content (which replaces this body entirely) sizes itself instead of
|
|
32614
32651
|
inheriting a ceiling meant for a sentence-long question. */
|
|
@@ -32745,7 +32782,7 @@ const ConfirmPopup = ({
|
|
|
32745
32782
|
onAnswer,
|
|
32746
32783
|
onClosed
|
|
32747
32784
|
}) => {
|
|
32748
|
-
import.meta.css = [css$
|
|
32785
|
+
import.meta.css = [css$Y, "@jsenv/navi/src/action/confirm_popup.jsx"];
|
|
32749
32786
|
const {
|
|
32750
32787
|
mode,
|
|
32751
32788
|
confirmLabel,
|
|
@@ -32829,7 +32866,7 @@ const defaultBody = (message, {
|
|
|
32829
32866
|
});
|
|
32830
32867
|
};
|
|
32831
32868
|
|
|
32832
|
-
installImportMetaCssBuild(import.meta);const css$
|
|
32869
|
+
installImportMetaCssBuild(import.meta);const css$X = /* css */`
|
|
32833
32870
|
.action_error {
|
|
32834
32871
|
margin-top: 0;
|
|
32835
32872
|
margin-bottom: 20px;
|
|
@@ -32854,7 +32891,7 @@ const ActionRenderer = ({
|
|
|
32854
32891
|
children,
|
|
32855
32892
|
disabled
|
|
32856
32893
|
}) => {
|
|
32857
|
-
import.meta.css = [css$
|
|
32894
|
+
import.meta.css = [css$X, "@jsenv/navi/src/action/action_renderer.jsx"];
|
|
32858
32895
|
if (action === undefined) {
|
|
32859
32896
|
throw new Error("ActionRenderer requires an action to render, but none was provided.");
|
|
32860
32897
|
}
|
|
@@ -34579,7 +34616,7 @@ const describeRangeAsked = (rangeParams) => {
|
|
|
34579
34616
|
};
|
|
34580
34617
|
|
|
34581
34618
|
const resourceLifecycleManager = createResourceLifecycleManager();
|
|
34582
|
-
const debug$2 = (args) => {
|
|
34619
|
+
const debug$2 = (...args) => {
|
|
34583
34620
|
{
|
|
34584
34621
|
return;
|
|
34585
34622
|
}
|
|
@@ -34644,6 +34681,7 @@ const resource = (
|
|
|
34644
34681
|
DELETE_MANY,
|
|
34645
34682
|
} = {},
|
|
34646
34683
|
) => {
|
|
34684
|
+
const declarationSite = getDeclarationSite();
|
|
34647
34685
|
if (idKey === undefined) {
|
|
34648
34686
|
idKey = uniqueKeys.length === 0 ? "id" : uniqueKeys[0];
|
|
34649
34687
|
}
|
|
@@ -34692,6 +34730,7 @@ const resource = (
|
|
|
34692
34730
|
const createRestActionForRoot = createRestActionFactoryForRoot(name, {
|
|
34693
34731
|
idKey,
|
|
34694
34732
|
store,
|
|
34733
|
+
declarationSite,
|
|
34695
34734
|
});
|
|
34696
34735
|
return createResource(name, {
|
|
34697
34736
|
idKey,
|
|
@@ -34730,11 +34769,8 @@ const createResource = (
|
|
|
34730
34769
|
paramScope,
|
|
34731
34770
|
rerunOn,
|
|
34732
34771
|
dependencies,
|
|
34733
|
-
}
|
|
34772
|
+
},
|
|
34734
34773
|
) => {
|
|
34735
|
-
if (idKey === undefined) {
|
|
34736
|
-
idKey = uniqueKeys.length === 0 ? "id" : uniqueKeys[0];
|
|
34737
|
-
}
|
|
34738
34774
|
const params = paramScope.params;
|
|
34739
34775
|
const stateFacade = {
|
|
34740
34776
|
// public
|
|
@@ -34755,7 +34791,6 @@ const createResource = (
|
|
|
34755
34791
|
store,
|
|
34756
34792
|
addItemSetup,
|
|
34757
34793
|
};
|
|
34758
|
-
const lifecycleCtx = { onComplete: null };
|
|
34759
34794
|
|
|
34760
34795
|
resourceLifecycleManager.registerResource(stateFacade, {
|
|
34761
34796
|
rerunOn,
|
|
@@ -34763,7 +34798,7 @@ const createResource = (
|
|
|
34763
34798
|
dependencies,
|
|
34764
34799
|
uniqueKeys,
|
|
34765
34800
|
});
|
|
34766
|
-
|
|
34801
|
+
const onActionComplete = (actionCompleted) => {
|
|
34767
34802
|
resourceLifecycleManager.onActionComplete(actionCompleted, {
|
|
34768
34803
|
resourceScope: stateFacade,
|
|
34769
34804
|
});
|
|
@@ -34800,6 +34835,7 @@ const createResource = (
|
|
|
34800
34835
|
paramsToInject,
|
|
34801
34836
|
{ dependencies: withParamsDeps, rerunOn: withParamsRerunOn } = {},
|
|
34802
34837
|
) => {
|
|
34838
|
+
const declarationSite = getDeclarationSite();
|
|
34803
34839
|
if (!paramsToInject || Object.keys(paramsToInject).length === 0) {
|
|
34804
34840
|
throw new Error(`resource(${name}).withParams() requires parameters`);
|
|
34805
34841
|
}
|
|
@@ -34810,6 +34846,7 @@ const createResource = (
|
|
|
34810
34846
|
const createRestActionWithParams = createRestActionFactoryForRoot(name, {
|
|
34811
34847
|
idKey,
|
|
34812
34848
|
store,
|
|
34849
|
+
declarationSite,
|
|
34813
34850
|
});
|
|
34814
34851
|
return createResource(name, {
|
|
34815
34852
|
idKey,
|
|
@@ -34862,40 +34899,37 @@ const createResource = (
|
|
|
34862
34899
|
DELETE,
|
|
34863
34900
|
} = {},
|
|
34864
34901
|
) => {
|
|
34902
|
+
const declarationSite = getDeclarationSite();
|
|
34865
34903
|
const childName = `${name}.${propertyName}`;
|
|
34904
|
+
const childIdKey = childResource.idKey;
|
|
34905
|
+
const childStore = childResource.store;
|
|
34866
34906
|
addItemSetup((item) => {
|
|
34867
|
-
const childIdKeyForSetup = childResource.idKey;
|
|
34868
34907
|
const childItemIdSignal = signal();
|
|
34869
34908
|
const updateChildItemId = (value) => {
|
|
34870
34909
|
const currentChildItemId = childItemIdSignal.peek();
|
|
34910
|
+
let childItemProps;
|
|
34871
34911
|
if (isProps(value)) {
|
|
34872
|
-
|
|
34873
|
-
|
|
34874
|
-
|
|
34875
|
-
|
|
34876
|
-
|
|
34877
|
-
childItemIdSignal.value = childItemId;
|
|
34878
|
-
return true;
|
|
34879
|
-
}
|
|
34880
|
-
if (primitiveCanBeId(value)) {
|
|
34881
|
-
const childItemProps = { [childIdKeyForSetup]: value };
|
|
34882
|
-
const childItem = childResource.store.upsert(childItemProps);
|
|
34883
|
-
const childItemId = childItem[childIdKeyForSetup];
|
|
34884
|
-
if (currentChildItemId === childItemId) {
|
|
34912
|
+
childItemProps = value;
|
|
34913
|
+
} else if (primitiveCanBeId(value)) {
|
|
34914
|
+
childItemProps = { [childIdKey]: value };
|
|
34915
|
+
} else {
|
|
34916
|
+
if (currentChildItemId === undefined) {
|
|
34885
34917
|
return false;
|
|
34886
34918
|
}
|
|
34887
|
-
childItemIdSignal.value =
|
|
34919
|
+
childItemIdSignal.value = undefined;
|
|
34888
34920
|
return true;
|
|
34889
34921
|
}
|
|
34890
|
-
|
|
34922
|
+
const childItem = childStore.upsert(childItemProps);
|
|
34923
|
+
const childItemId = childItem[childIdKey];
|
|
34924
|
+
if (currentChildItemId === childItemId) {
|
|
34891
34925
|
return false;
|
|
34892
34926
|
}
|
|
34893
|
-
childItemIdSignal.value =
|
|
34927
|
+
childItemIdSignal.value = childItemId;
|
|
34894
34928
|
return true;
|
|
34895
34929
|
};
|
|
34896
34930
|
updateChildItemId(item[propertyName]);
|
|
34897
34931
|
const childItemSignal = computed(() =>
|
|
34898
|
-
|
|
34932
|
+
childStore.select(childItemIdSignal.value),
|
|
34899
34933
|
);
|
|
34900
34934
|
const childItemFacadeSignal = computed(() => {
|
|
34901
34935
|
const childItem = childItemSignal.value;
|
|
@@ -34926,9 +34960,7 @@ const createResource = (
|
|
|
34926
34960
|
);
|
|
34927
34961
|
});
|
|
34928
34962
|
|
|
34929
|
-
const
|
|
34930
|
-
const childStore = childResource.store;
|
|
34931
|
-
const createRestActionForOne = (verb, callback, { lifecycleCtx }) => {
|
|
34963
|
+
const createRestActionForOne = (verb, callback, { onActionComplete }) => {
|
|
34932
34964
|
const applyResultToValue =
|
|
34933
34965
|
verb === "DELETE"
|
|
34934
34966
|
? (itemId) => {
|
|
@@ -34940,33 +34972,18 @@ const createResource = (
|
|
|
34940
34972
|
});
|
|
34941
34973
|
return childItemId;
|
|
34942
34974
|
}
|
|
34943
|
-
: //
|
|
34944
|
-
//
|
|
34945
|
-
// [idKey]: 123,
|
|
34946
|
-
// [propertyName]: {
|
|
34947
|
-
// [childIdKey]: 456, ...childProps
|
|
34948
|
-
// }
|
|
34949
|
-
// }
|
|
34950
|
-
// the following could happen too if there is no relationship
|
|
34951
|
-
// {
|
|
34952
|
-
// [idKey]: 123,
|
|
34953
|
-
// [propertyName]: null
|
|
34954
|
-
// }
|
|
34975
|
+
: // GET/PUT contract (see .one() JSDoc): the parent object with the
|
|
34976
|
+
// relationship nested inside, or null for no relationship.
|
|
34955
34977
|
(result) => {
|
|
34956
34978
|
const item = store.upsert(result);
|
|
34957
34979
|
const childItem = item[propertyName];
|
|
34958
|
-
|
|
34959
|
-
return childItemId;
|
|
34980
|
+
return childItem ? childItem[childIdKey] : undefined;
|
|
34960
34981
|
};
|
|
34961
|
-
|
|
34962
|
-
|
|
34963
|
-
|
|
34964
|
-
|
|
34965
|
-
|
|
34966
|
-
: callerInfo.raw || "unknown location";
|
|
34967
|
-
const originalActionName = `${name}.${verb}`;
|
|
34968
|
-
|
|
34969
|
-
const actionAffectingOneItem = createAction(callback, {
|
|
34982
|
+
const throwInvalidResult = createInvalidResultThrower(
|
|
34983
|
+
`${name}.${verb}`,
|
|
34984
|
+
declarationSite,
|
|
34985
|
+
);
|
|
34986
|
+
return createAction(callback, {
|
|
34970
34987
|
meta: {
|
|
34971
34988
|
verb,
|
|
34972
34989
|
isMany: false,
|
|
@@ -34974,35 +34991,30 @@ const createResource = (
|
|
|
34974
34991
|
},
|
|
34975
34992
|
name: `${name}.${verb}`,
|
|
34976
34993
|
resultToValue: (result, action) => {
|
|
34977
|
-
const actionLabel = action.name;
|
|
34978
|
-
|
|
34979
34994
|
if (verb === "DELETE") {
|
|
34980
34995
|
if (!isProps(result) && !primitiveCanBeId(result)) {
|
|
34981
|
-
|
|
34982
|
-
|
|
34983
|
-
|
|
34996
|
+
throwInvalidResult(
|
|
34997
|
+
action.name,
|
|
34998
|
+
`an object (that will be used to drop "${name}" resource)`,
|
|
34999
|
+
result,
|
|
34984
35000
|
);
|
|
34985
35001
|
}
|
|
34986
|
-
|
|
34987
|
-
|
|
34988
|
-
|
|
34989
|
-
|
|
34990
|
-
|
|
34991
|
-
${originalActionName} source location: ${locationInfo}`,
|
|
35002
|
+
} else if (!isProps(result)) {
|
|
35003
|
+
throwInvalidResult(
|
|
35004
|
+
action.name,
|
|
35005
|
+
`an object (that will be used to upsert "${name}" resource)`,
|
|
35006
|
+
result,
|
|
34992
35007
|
);
|
|
34993
35008
|
}
|
|
34994
35009
|
return applyResultToValue(result);
|
|
34995
35010
|
},
|
|
34996
35011
|
valueToData: (childItemId) => childStore.select(childItemId),
|
|
34997
|
-
completeSideEffect:
|
|
34998
|
-
lifecycleCtx.onComplete(actionCompleted);
|
|
34999
|
-
},
|
|
35012
|
+
completeSideEffect: onActionComplete,
|
|
35000
35013
|
});
|
|
35001
|
-
return actionAffectingOneItem;
|
|
35002
35014
|
};
|
|
35003
35015
|
|
|
35004
35016
|
return createResource(childName, {
|
|
35005
|
-
idKey:
|
|
35017
|
+
idKey: childIdKey,
|
|
35006
35018
|
restCallbacks: {
|
|
35007
35019
|
GET,
|
|
35008
35020
|
PUT,
|
|
@@ -35059,49 +35071,21 @@ ${originalActionName} source location: ${locationInfo}`,
|
|
|
35059
35071
|
DELETE_MANY,
|
|
35060
35072
|
} = {},
|
|
35061
35073
|
) => {
|
|
35074
|
+
const declarationSite = getDeclarationSite();
|
|
35062
35075
|
const childStore = childResource.store;
|
|
35063
35076
|
const childIdKey = childResource.idKey;
|
|
35064
35077
|
const childName = `${name}.${propertyName}`;
|
|
35065
35078
|
addItemSetup((item) => {
|
|
35066
35079
|
const childItemIdArraySignal = signal([]);
|
|
35067
|
-
const updateChildItemIdArray = (
|
|
35068
|
-
|
|
35069
|
-
|
|
35070
|
-
|
|
35071
|
-
|
|
35072
|
-
return;
|
|
35073
|
-
}
|
|
35074
|
-
let i = 0;
|
|
35075
|
-
const idArray = [];
|
|
35076
|
-
let modified = false;
|
|
35077
|
-
while (i < valueArray.length) {
|
|
35078
|
-
const value = valueArray[i];
|
|
35079
|
-
const currentIdAtIndex = currentIdArray[idArray.length];
|
|
35080
|
-
i++;
|
|
35081
|
-
if (isProps(value)) {
|
|
35082
|
-
const childItem = childResource.store.upsert(value);
|
|
35083
|
-
const childItemId = childItem[childIdKey];
|
|
35084
|
-
if (currentIdAtIndex !== childItemId) modified = true;
|
|
35085
|
-
idArray.push(childItemId);
|
|
35086
|
-
continue;
|
|
35087
|
-
}
|
|
35088
|
-
if (primitiveCanBeId(value)) {
|
|
35089
|
-
const childItemProps = { [childIdKey]: value };
|
|
35090
|
-
const childItem = childResource.store.upsert(childItemProps);
|
|
35091
|
-
const childItemId = childItem[childIdKey];
|
|
35092
|
-
if (currentIdAtIndex !== childItemId) modified = true;
|
|
35093
|
-
idArray.push(childItemId);
|
|
35094
|
-
continue;
|
|
35095
|
-
}
|
|
35096
|
-
}
|
|
35097
|
-
if (modified || currentIdArray.length !== idArray.length) {
|
|
35098
|
-
childItemIdArraySignal.value = idArray;
|
|
35099
|
-
}
|
|
35100
|
-
};
|
|
35080
|
+
const updateChildItemIdArray = createChildIdArrayUpdater(
|
|
35081
|
+
childStore,
|
|
35082
|
+
childIdKey,
|
|
35083
|
+
childItemIdArraySignal,
|
|
35084
|
+
);
|
|
35101
35085
|
updateChildItemIdArray(item[propertyName]);
|
|
35102
35086
|
const childItemArraySignal = computed(() => {
|
|
35103
35087
|
const idArray = childItemIdArraySignal.value;
|
|
35104
|
-
const arr =
|
|
35088
|
+
const arr = childStore.selectAll(idArray);
|
|
35105
35089
|
Object.defineProperty(arr, SYMBOL_OBJECT_SIGNAL, {
|
|
35106
35090
|
value: childItemArraySignal,
|
|
35107
35091
|
writable: false,
|
|
@@ -35114,23 +35098,27 @@ ${originalActionName} source location: ${locationInfo}`,
|
|
|
35114
35098
|
get: () => childItemArraySignal.value,
|
|
35115
35099
|
set: updateChildItemIdArray,
|
|
35116
35100
|
});
|
|
35117
|
-
syncIdArrayOnRename(
|
|
35118
|
-
childResource.store,
|
|
35119
|
-
childIdKey,
|
|
35120
|
-
childItemIdArraySignal,
|
|
35121
|
-
);
|
|
35101
|
+
syncIdArrayOnRename(childStore, childIdKey, childItemIdArraySignal);
|
|
35122
35102
|
});
|
|
35123
35103
|
const createRestActionForMany = (
|
|
35124
35104
|
verb,
|
|
35125
35105
|
callback,
|
|
35126
|
-
{ isMany,
|
|
35106
|
+
{ isMany, onActionComplete },
|
|
35127
35107
|
) => {
|
|
35128
35108
|
if (!isMany) {
|
|
35129
|
-
return createRestActionAffectingOneItem(verb, callback,
|
|
35109
|
+
return createRestActionAffectingOneItem(verb, callback, {
|
|
35110
|
+
onActionComplete,
|
|
35111
|
+
});
|
|
35130
35112
|
}
|
|
35131
|
-
return createRestActionAffectingManyItems(verb, callback,
|
|
35113
|
+
return createRestActionAffectingManyItems(verb, callback, {
|
|
35114
|
+
onActionComplete,
|
|
35115
|
+
});
|
|
35132
35116
|
};
|
|
35133
|
-
const createRestActionAffectingOneItem = (
|
|
35117
|
+
const createRestActionAffectingOneItem = (
|
|
35118
|
+
verb,
|
|
35119
|
+
callback,
|
|
35120
|
+
{ onActionComplete },
|
|
35121
|
+
) => {
|
|
35134
35122
|
const applyResultToValue =
|
|
35135
35123
|
verb === "DELETE"
|
|
35136
35124
|
? ([itemId, childItemId]) => {
|
|
@@ -35139,8 +35127,7 @@ ${originalActionName} source location: ${locationInfo}`,
|
|
|
35139
35127
|
const childItemArrayWithoutThisOne = [];
|
|
35140
35128
|
let found = false;
|
|
35141
35129
|
for (const childItemCandidate of childItemArray) {
|
|
35142
|
-
|
|
35143
|
-
if (childItemCandidateId === childItemId) {
|
|
35130
|
+
if (childItemCandidate[childIdKey] === childItemId) {
|
|
35144
35131
|
found = true;
|
|
35145
35132
|
} else {
|
|
35146
35133
|
childItemArrayWithoutThisOne.push(childItemCandidate);
|
|
@@ -35155,162 +35142,127 @@ ${originalActionName} source location: ${locationInfo}`,
|
|
|
35155
35142
|
return childItemId;
|
|
35156
35143
|
}
|
|
35157
35144
|
: (childData) => {
|
|
35145
|
+
// an array is [property, value, props], used to rename the child id
|
|
35158
35146
|
const childItem = Array.isArray(childData)
|
|
35159
35147
|
? childStore.upsert(...childData)
|
|
35160
35148
|
: childStore.upsert(childData);
|
|
35161
|
-
|
|
35162
|
-
return childItemId;
|
|
35149
|
+
return childItem[childIdKey];
|
|
35163
35150
|
};
|
|
35164
|
-
|
|
35165
|
-
|
|
35166
|
-
|
|
35167
|
-
|
|
35168
|
-
|
|
35169
|
-
: callerInfo.raw || "unknown location";
|
|
35170
|
-
const originalActionName = `${name}.${verb}`;
|
|
35171
|
-
|
|
35172
|
-
const actionAffectingOneItem = createAction(callback, {
|
|
35151
|
+
const throwInvalidResult = createInvalidResultThrower(
|
|
35152
|
+
`${name}.${verb}`,
|
|
35153
|
+
declarationSite,
|
|
35154
|
+
);
|
|
35155
|
+
return createAction(callback, {
|
|
35173
35156
|
meta: { verb, isMany: false, paramScope },
|
|
35174
35157
|
name: `${name}.${verb}`,
|
|
35175
35158
|
resultToValue: (result, action) => {
|
|
35176
|
-
const actionLabel = action.name;
|
|
35177
|
-
|
|
35178
35159
|
if (verb === "DELETE") {
|
|
35179
35160
|
if (!Array.isArray(result) || result.length !== 2) {
|
|
35180
|
-
|
|
35181
|
-
|
|
35182
|
-
|
|
35161
|
+
throwInvalidResult(
|
|
35162
|
+
action.name,
|
|
35163
|
+
`an array [itemId, childItemId] (that will be used to remove relationship)`,
|
|
35164
|
+
result,
|
|
35183
35165
|
);
|
|
35184
35166
|
}
|
|
35185
|
-
|
|
35186
|
-
|
|
35187
|
-
|
|
35188
|
-
|
|
35189
|
-
|
|
35190
|
-
${originalActionName} source location: ${locationInfo}`,
|
|
35167
|
+
} else if (!isProps(result)) {
|
|
35168
|
+
throwInvalidResult(
|
|
35169
|
+
action.name,
|
|
35170
|
+
`an object (that will be used to upsert child item)`,
|
|
35171
|
+
result,
|
|
35191
35172
|
);
|
|
35192
35173
|
}
|
|
35193
35174
|
return applyResultToValue(result);
|
|
35194
35175
|
},
|
|
35195
35176
|
valueToData: (childItemId) => childStore.select(childItemId),
|
|
35196
|
-
completeSideEffect:
|
|
35197
|
-
lifecycleCtx.onComplete(actionCompleted);
|
|
35198
|
-
},
|
|
35177
|
+
completeSideEffect: onActionComplete,
|
|
35199
35178
|
});
|
|
35200
|
-
return actionAffectingOneItem;
|
|
35201
35179
|
};
|
|
35202
35180
|
const createRestActionAffectingManyItems = (
|
|
35203
35181
|
verb,
|
|
35204
35182
|
callback,
|
|
35205
|
-
|
|
35183
|
+
{ onActionComplete },
|
|
35206
35184
|
) => {
|
|
35207
35185
|
const applyResultToValue =
|
|
35208
35186
|
verb === "GET"
|
|
35209
35187
|
? (result) => {
|
|
35210
|
-
//
|
|
35211
|
-
//
|
|
35212
|
-
// [idKey]: 123,
|
|
35213
|
-
// [propertyName]: [
|
|
35214
|
-
// { [childIdKey]: 456, ...childProps },
|
|
35215
|
-
// { [childIdKey]: 789, ...childProps },
|
|
35216
|
-
// ...
|
|
35217
|
-
// ]
|
|
35218
|
-
// }
|
|
35219
|
-
// the array can be empty
|
|
35188
|
+
// GET_MANY contract (see .many() JSDoc): the parent object with
|
|
35189
|
+
// the child array nested inside; the array replaces the relationship.
|
|
35220
35190
|
const item = store.upsert(result);
|
|
35221
35191
|
const childItemArray = item[propertyName];
|
|
35222
|
-
|
|
35223
|
-
(childItem) => childItem[childIdKey],
|
|
35224
|
-
);
|
|
35225
|
-
return childItemIdArray;
|
|
35192
|
+
return childItemArray.map((childItem) => childItem[childIdKey]);
|
|
35226
35193
|
}
|
|
35227
35194
|
: verb === "DELETE"
|
|
35228
35195
|
? ([itemIdOrMutableId, childItemIdOrMutableIdArray]) => {
|
|
35229
35196
|
const item = store.select(itemIdOrMutableId);
|
|
35230
35197
|
const childItemArray = item[propertyName];
|
|
35231
|
-
const
|
|
35232
|
-
|
|
35233
|
-
let someFound = false;
|
|
35234
|
-
const deletedChildItemArray = childStore.select(
|
|
35235
|
-
childItemIdOrMutableIdArray,
|
|
35198
|
+
const deletedChildItemSet = new Set(
|
|
35199
|
+
childStore.selectAll(childItemIdOrMutableIdArray),
|
|
35236
35200
|
);
|
|
35201
|
+
const deletedChildItemIdArray = [];
|
|
35202
|
+
const childItemArrayWithoutThose = [];
|
|
35237
35203
|
for (const childItemCandidate of childItemArray) {
|
|
35238
|
-
if (
|
|
35239
|
-
someFound = true;
|
|
35204
|
+
if (deletedChildItemSet.has(childItemCandidate)) {
|
|
35240
35205
|
deletedChildItemIdArray.push(
|
|
35241
35206
|
childItemCandidate[childIdKey],
|
|
35242
35207
|
);
|
|
35243
35208
|
} else {
|
|
35244
|
-
|
|
35209
|
+
childItemArrayWithoutThose.push(childItemCandidate);
|
|
35245
35210
|
}
|
|
35246
35211
|
}
|
|
35247
|
-
if (
|
|
35212
|
+
if (deletedChildItemIdArray.length > 0) {
|
|
35248
35213
|
store.upsert({
|
|
35249
35214
|
[idKey]: item[idKey],
|
|
35250
|
-
[propertyName]:
|
|
35215
|
+
[propertyName]: childItemArrayWithoutThose,
|
|
35251
35216
|
});
|
|
35252
35217
|
}
|
|
35253
35218
|
return deletedChildItemIdArray;
|
|
35254
35219
|
}
|
|
35255
35220
|
: (childDataArray) => {
|
|
35256
35221
|
const childItemArray = childStore.upsert(childDataArray);
|
|
35257
|
-
|
|
35258
|
-
(childItem) => childItem[childIdKey],
|
|
35259
|
-
);
|
|
35260
|
-
return childItemIdArray;
|
|
35222
|
+
return childItemArray.map((childItem) => childItem[childIdKey]);
|
|
35261
35223
|
};
|
|
35262
|
-
|
|
35263
|
-
|
|
35264
|
-
|
|
35265
|
-
|
|
35266
|
-
|
|
35267
|
-
: callerInfo.raw || "unknown location";
|
|
35268
|
-
const originalActionName = `${name}.${verb}[many]`;
|
|
35269
|
-
|
|
35270
|
-
const actionAffectingManyItem = createAction(callback, {
|
|
35224
|
+
const throwInvalidResult = createInvalidResultThrower(
|
|
35225
|
+
`${name}.${verb}[many]`,
|
|
35226
|
+
declarationSite,
|
|
35227
|
+
);
|
|
35228
|
+
return createAction(callback, {
|
|
35271
35229
|
meta: { verb, isMany: true, paramScope },
|
|
35272
35230
|
name: `${name}.${verb}[many]`,
|
|
35273
35231
|
dataDefault: [],
|
|
35274
35232
|
resultToValue: (result, action) => {
|
|
35275
|
-
const actionLabel = action.name;
|
|
35276
|
-
|
|
35277
35233
|
if (verb === "GET") {
|
|
35278
35234
|
if (!isProps(result)) {
|
|
35279
|
-
|
|
35280
|
-
|
|
35281
|
-
${
|
|
35235
|
+
throwInvalidResult(
|
|
35236
|
+
action.name,
|
|
35237
|
+
`an object (that will be used to upsert "${name}" resource with many relationships)`,
|
|
35238
|
+
result,
|
|
35282
35239
|
);
|
|
35283
35240
|
}
|
|
35284
|
-
|
|
35285
|
-
}
|
|
35286
|
-
if (verb === "DELETE") {
|
|
35241
|
+
} else if (verb === "DELETE") {
|
|
35287
35242
|
if (
|
|
35288
35243
|
!Array.isArray(result) ||
|
|
35289
35244
|
result.length !== 2 ||
|
|
35290
35245
|
!Array.isArray(result[1])
|
|
35291
35246
|
) {
|
|
35292
|
-
|
|
35293
|
-
|
|
35294
|
-
|
|
35247
|
+
throwInvalidResult(
|
|
35248
|
+
action.name,
|
|
35249
|
+
`an array [itemId, childItemIdArray] (that will be used to remove relationships)`,
|
|
35250
|
+
result,
|
|
35295
35251
|
);
|
|
35296
35252
|
}
|
|
35297
|
-
|
|
35298
|
-
|
|
35299
|
-
|
|
35300
|
-
|
|
35301
|
-
|
|
35302
|
-
${originalActionName} source location: ${locationInfo}`,
|
|
35253
|
+
} else if (!Array.isArray(result)) {
|
|
35254
|
+
throwInvalidResult(
|
|
35255
|
+
action.name,
|
|
35256
|
+
`an array of objects (that will be used to upsert child items)`,
|
|
35257
|
+
result,
|
|
35303
35258
|
);
|
|
35304
35259
|
}
|
|
35305
35260
|
return applyResultToValue(result);
|
|
35306
35261
|
},
|
|
35307
35262
|
valueToData: (childItemIdArray) =>
|
|
35308
35263
|
childStore.selectAll(childItemIdArray),
|
|
35309
|
-
completeSideEffect:
|
|
35310
|
-
lifecycleCtx.onComplete(actionCompleted);
|
|
35311
|
-
},
|
|
35264
|
+
completeSideEffect: onActionComplete,
|
|
35312
35265
|
});
|
|
35313
|
-
return actionAffectingManyItem;
|
|
35314
35266
|
};
|
|
35315
35267
|
|
|
35316
35268
|
return createResource(childName, {
|
|
@@ -35375,26 +35327,20 @@ ${originalActionName} source location: ${locationInfo}`,
|
|
|
35375
35327
|
) => {
|
|
35376
35328
|
const childName = `${name}.${propertyName}`;
|
|
35377
35329
|
|
|
35378
|
-
//
|
|
35379
|
-
//
|
|
35380
|
-
const
|
|
35381
|
-
const childAddItemSetup = (callback) =>
|
|
35382
|
-
|
|
35383
|
-
const scopedItemMap = new Map(); // ownerId → stable child item object
|
|
35384
|
-
const scopedSignalMap = new Map(); // ownerId → signal<childItem | null>
|
|
35330
|
+
// Callbacks added by chained .one()/.many() on the child resource,
|
|
35331
|
+
// applied to each per-owner child object when it is first created.
|
|
35332
|
+
const childSetupCallbackSet = new Set();
|
|
35333
|
+
const childAddItemSetup = (callback) => childSetupCallbackSet.add(callback);
|
|
35334
|
+
const applyPropsMap = new Map(); // ownerId → applyProps(props | null)
|
|
35385
35335
|
addItemSetup((ownerItem) => {
|
|
35386
35336
|
const ownerId = ownerItem[idKey];
|
|
35387
|
-
//
|
|
35388
|
-
//
|
|
35389
|
-
// so they survive across multiple prop updates.
|
|
35337
|
+
// A stable child object, mutated in place: reactive getters/setters from
|
|
35338
|
+
// chained .one() etc. are defined on it once and survive prop updates.
|
|
35390
35339
|
const childItem = {};
|
|
35391
|
-
for (const childSetup of
|
|
35340
|
+
for (const childSetup of childSetupCallbackSet) {
|
|
35392
35341
|
childSetup(childItem);
|
|
35393
35342
|
}
|
|
35394
|
-
scopedItemMap.set(ownerId, childItem);
|
|
35395
35343
|
const childSignal = signal(null);
|
|
35396
|
-
scopedSignalMap.set(ownerId, childSignal);
|
|
35397
|
-
|
|
35398
35344
|
const applyProps = (props) => {
|
|
35399
35345
|
if (!props) {
|
|
35400
35346
|
childSignal.value = null;
|
|
@@ -35408,6 +35354,7 @@ ${originalActionName} source location: ${locationInfo}`,
|
|
|
35408
35354
|
childSignal.value = childItem; // first activation: null → childItem
|
|
35409
35355
|
}
|
|
35410
35356
|
};
|
|
35357
|
+
applyPropsMap.set(ownerId, applyProps);
|
|
35411
35358
|
|
|
35412
35359
|
applyProps(ownerItem[propertyName]);
|
|
35413
35360
|
|
|
@@ -35416,9 +35363,13 @@ ${originalActionName} source location: ${locationInfo}`,
|
|
|
35416
35363
|
set: applyProps,
|
|
35417
35364
|
});
|
|
35418
35365
|
});
|
|
35419
|
-
const createRestActionForScopedOne = (
|
|
35366
|
+
const createRestActionForScopedOne = (
|
|
35367
|
+
verb,
|
|
35368
|
+
callback,
|
|
35369
|
+
{ onActionComplete },
|
|
35370
|
+
) => {
|
|
35420
35371
|
const childActionName = `${childName}.${verb}`;
|
|
35421
|
-
|
|
35372
|
+
return createAction(callback, {
|
|
35422
35373
|
name: childActionName,
|
|
35423
35374
|
meta: { verb, isMany: false, paramScope },
|
|
35424
35375
|
resultToValue: (result) => {
|
|
@@ -35435,33 +35386,20 @@ ${originalActionName} source location: ${locationInfo}`,
|
|
|
35435
35386
|
uniqueKeys,
|
|
35436
35387
|
childActionName,
|
|
35437
35388
|
);
|
|
35438
|
-
const
|
|
35439
|
-
if (!
|
|
35389
|
+
const applyProps = applyPropsMap.get(ownerId);
|
|
35390
|
+
if (!applyProps) {
|
|
35440
35391
|
throw new Error(
|
|
35441
35392
|
`${childActionName}: no item found for scope id "${ownerId}"`,
|
|
35442
35393
|
);
|
|
35443
35394
|
}
|
|
35444
|
-
|
|
35445
|
-
if (props) {
|
|
35446
|
-
for (const [key, value] of Object.entries(props)) {
|
|
35447
|
-
childItem[key] = value;
|
|
35448
|
-
}
|
|
35449
|
-
if (childSignal.peek() !== childItem) {
|
|
35450
|
-
childSignal.value = childItem;
|
|
35451
|
-
}
|
|
35452
|
-
} else {
|
|
35453
|
-
childSignal.value = null;
|
|
35454
|
-
}
|
|
35395
|
+
applyProps(props);
|
|
35455
35396
|
return [ownerId, props];
|
|
35456
35397
|
},
|
|
35457
|
-
completeSideEffect:
|
|
35458
|
-
lifecycleCtx.onComplete(actionCompleted);
|
|
35459
|
-
},
|
|
35398
|
+
completeSideEffect: onActionComplete,
|
|
35460
35399
|
});
|
|
35461
|
-
return restAction;
|
|
35462
35400
|
};
|
|
35463
35401
|
|
|
35464
|
-
|
|
35402
|
+
return createResource(childName, {
|
|
35465
35403
|
idKey: childIdKey,
|
|
35466
35404
|
restCallbacks: {
|
|
35467
35405
|
GET,
|
|
@@ -35477,7 +35415,6 @@ ${originalActionName} source location: ${locationInfo}`,
|
|
|
35477
35415
|
rerunOn: scopedOneRerunOn ?? rerunOn,
|
|
35478
35416
|
dependencies: scopedOneDependencies ?? dependencies,
|
|
35479
35417
|
});
|
|
35480
|
-
return childResource;
|
|
35481
35418
|
};
|
|
35482
35419
|
|
|
35483
35420
|
/**
|
|
@@ -35531,108 +35468,76 @@ ${originalActionName} source location: ${locationInfo}`,
|
|
|
35531
35468
|
) => {
|
|
35532
35469
|
const childName = `${name}.${propertyName}`;
|
|
35533
35470
|
|
|
35534
|
-
//
|
|
35535
|
-
//
|
|
35471
|
+
// Callbacks added by chained .one()/.many() on the child resource,
|
|
35472
|
+
// applied to each child item created in a per-owner store.
|
|
35536
35473
|
const childSetupCallbackSet = new Set();
|
|
35537
35474
|
const childAddItemSetup = (callback) => childSetupCallbackSet.add(callback);
|
|
35538
|
-
|
|
35539
|
-
|
|
35475
|
+
// ownerKey (id or any uniqueKey value) → { childStore, idArraySignal }
|
|
35476
|
+
// One owner can be registered under several keys, all pointing to the same scope.
|
|
35477
|
+
const scopeMap = new Map();
|
|
35478
|
+
const createScope = (ownerKey) => {
|
|
35479
|
+
const childStore = arraySignalStore([], childIdKey, {
|
|
35480
|
+
name: `${childName}#${ownerKey} store`,
|
|
35481
|
+
createItem: (props) => {
|
|
35482
|
+
const childItem = {};
|
|
35483
|
+
Object.assign(childItem, props);
|
|
35484
|
+
for (const childSetup of childSetupCallbackSet) {
|
|
35485
|
+
childSetup(childItem);
|
|
35486
|
+
}
|
|
35487
|
+
return childItem;
|
|
35488
|
+
},
|
|
35489
|
+
});
|
|
35490
|
+
const scope = { childStore, idArraySignal: signal([]) };
|
|
35491
|
+
scopeMap.set(ownerKey, scope);
|
|
35492
|
+
return scope;
|
|
35493
|
+
};
|
|
35540
35494
|
addItemSetup((item) => {
|
|
35541
35495
|
const ownerId = item[idKey];
|
|
35542
35496
|
|
|
35543
|
-
// Reuse an existing
|
|
35544
|
-
// (e.g. rows were fetched by tablename before the full table was loaded).
|
|
35545
|
-
let
|
|
35546
|
-
|
|
35547
|
-
if (!childStore) {
|
|
35497
|
+
// Reuse an existing scope if one was already created under a uniqueKey
|
|
35498
|
+
// value (e.g. rows were fetched by tablename before the full table was loaded).
|
|
35499
|
+
let scope = scopeMap.get(ownerId);
|
|
35500
|
+
if (!scope) {
|
|
35548
35501
|
for (const uniqueKey of uniqueKeys) {
|
|
35549
35502
|
const uniqueKeyValue = item[uniqueKey];
|
|
35550
|
-
if (uniqueKeyValue !== undefined) {
|
|
35551
|
-
|
|
35552
|
-
|
|
35553
|
-
childStore = existing;
|
|
35554
|
-
childItemIdArraySignal =
|
|
35555
|
-
scopedIdArraySignalMap.get(uniqueKeyValue);
|
|
35556
|
-
break;
|
|
35557
|
-
}
|
|
35503
|
+
if (uniqueKeyValue !== undefined && scopeMap.has(uniqueKeyValue)) {
|
|
35504
|
+
scope = scopeMap.get(uniqueKeyValue);
|
|
35505
|
+
break;
|
|
35558
35506
|
}
|
|
35559
35507
|
}
|
|
35560
35508
|
}
|
|
35561
|
-
if (!
|
|
35562
|
-
|
|
35563
|
-
name: `${childName}#${ownerId} store`,
|
|
35564
|
-
createItem: (props) => {
|
|
35565
|
-
const childItem = {};
|
|
35566
|
-
Object.assign(childItem, props);
|
|
35567
|
-
for (const childSetup of childSetupCallbackSet) {
|
|
35568
|
-
childSetup(childItem);
|
|
35569
|
-
}
|
|
35570
|
-
return childItem;
|
|
35571
|
-
},
|
|
35572
|
-
});
|
|
35573
|
-
childItemIdArraySignal = signal([]);
|
|
35509
|
+
if (!scope) {
|
|
35510
|
+
scope = createScope(ownerId);
|
|
35574
35511
|
}
|
|
35575
|
-
|
|
35576
|
-
//
|
|
35577
|
-
|
|
35512
|
+
// Register the scope under the id and every uniqueKey value so that
|
|
35513
|
+
// resolveOwnerId can address it whichever key a callback returns.
|
|
35514
|
+
scopeMap.set(ownerId, scope);
|
|
35578
35515
|
for (const uniqueKey of uniqueKeys) {
|
|
35579
35516
|
const uniqueKeyValue = item[uniqueKey];
|
|
35580
35517
|
if (uniqueKeyValue !== undefined) {
|
|
35581
|
-
|
|
35518
|
+
scopeMap.set(uniqueKeyValue, scope);
|
|
35582
35519
|
}
|
|
35583
35520
|
}
|
|
35584
35521
|
|
|
35585
|
-
|
|
35586
|
-
|
|
35587
|
-
|
|
35588
|
-
|
|
35589
|
-
|
|
35590
|
-
|
|
35522
|
+
const { childStore, idArraySignal } = scope;
|
|
35523
|
+
const updateChildItemIdArray = createChildIdArrayUpdater(
|
|
35524
|
+
childStore,
|
|
35525
|
+
childIdKey,
|
|
35526
|
+
idArraySignal,
|
|
35527
|
+
);
|
|
35528
|
+
// The parent may not carry the property at all (e.g. created by a POST
|
|
35529
|
+
// that does not embed it): leave the collection of a reused scope
|
|
35530
|
+
// untouched — children may have been fetched by uniqueKey before the
|
|
35531
|
+
// parent was loaded. Only an explicit value replaces the collection.
|
|
35532
|
+
if (item[propertyName] !== undefined) {
|
|
35533
|
+
updateChildItemIdArray(item[propertyName]);
|
|
35591
35534
|
}
|
|
35592
35535
|
|
|
35593
|
-
const updateChildItemIdArray = (valueArray) => {
|
|
35594
|
-
const currentIdArray = childItemIdArraySignal.peek();
|
|
35595
|
-
if (!Array.isArray(valueArray)) {
|
|
35596
|
-
if (currentIdArray.length === 0) return;
|
|
35597
|
-
childItemIdArraySignal.value = [];
|
|
35598
|
-
return;
|
|
35599
|
-
}
|
|
35600
|
-
let i = 0;
|
|
35601
|
-
const idArray = [];
|
|
35602
|
-
let modified = false;
|
|
35603
|
-
while (i < valueArray.length) {
|
|
35604
|
-
const value = valueArray[i];
|
|
35605
|
-
const currentIdAtIndex = currentIdArray[idArray.length];
|
|
35606
|
-
i++;
|
|
35607
|
-
if (isProps(value)) {
|
|
35608
|
-
const childItem = childStore.upsert(value);
|
|
35609
|
-
const childItemId = childItem[childIdKey];
|
|
35610
|
-
if (currentIdAtIndex !== childItemId) modified = true;
|
|
35611
|
-
idArray.push(childItemId);
|
|
35612
|
-
continue;
|
|
35613
|
-
}
|
|
35614
|
-
if (primitiveCanBeId(value)) {
|
|
35615
|
-
const childItemProps = { [childIdKey]: value };
|
|
35616
|
-
const childItem = childStore.upsert(childItemProps);
|
|
35617
|
-
const childItemId = childItem[childIdKey];
|
|
35618
|
-
if (currentIdAtIndex !== childItemId) modified = true;
|
|
35619
|
-
idArray.push(childItemId);
|
|
35620
|
-
continue;
|
|
35621
|
-
}
|
|
35622
|
-
}
|
|
35623
|
-
if (modified || currentIdArray.length !== idArray.length) {
|
|
35624
|
-
childItemIdArraySignal.value = idArray;
|
|
35625
|
-
}
|
|
35626
|
-
};
|
|
35627
|
-
|
|
35628
|
-
updateChildItemIdArray(item[propertyName]);
|
|
35629
|
-
|
|
35630
35536
|
// When an id is renamed (PUT/PATCH changes the idKey), patch the id array.
|
|
35631
|
-
syncIdArrayOnRename(childStore, childIdKey,
|
|
35537
|
+
syncIdArrayOnRename(childStore, childIdKey, idArraySignal);
|
|
35632
35538
|
|
|
35633
35539
|
const childItemArraySignal = computed(() => {
|
|
35634
|
-
const
|
|
35635
|
-
const childItemArray = childStore.selectAll(childItemIdArray);
|
|
35540
|
+
const childItemArray = childStore.selectAll(idArraySignal.value);
|
|
35636
35541
|
Object.defineProperty(childItemArray, SYMBOL_OBJECT_SIGNAL, {
|
|
35637
35542
|
value: childItemArraySignal,
|
|
35638
35543
|
writable: false,
|
|
@@ -35650,13 +35555,10 @@ ${originalActionName} source location: ${locationInfo}`,
|
|
|
35650
35555
|
const createRestActionForScopedMany = (
|
|
35651
35556
|
verb,
|
|
35652
35557
|
callback,
|
|
35653
|
-
{ isMany,
|
|
35558
|
+
{ isMany, onActionComplete },
|
|
35654
35559
|
) => {
|
|
35655
|
-
if (!callback) {
|
|
35656
|
-
return undefined;
|
|
35657
|
-
}
|
|
35658
35560
|
const childActionName = `${childName}.${verb}`;
|
|
35659
|
-
|
|
35561
|
+
return createAction(callback, {
|
|
35660
35562
|
name: childActionName,
|
|
35661
35563
|
meta: { verb, isMany, paramScope },
|
|
35662
35564
|
resultToValue: (result) => {
|
|
@@ -35673,48 +35575,33 @@ ${originalActionName} source location: ${locationInfo}`,
|
|
|
35673
35575
|
uniqueKeys,
|
|
35674
35576
|
childActionName,
|
|
35675
35577
|
);
|
|
35676
|
-
|
|
35677
|
-
|
|
35678
|
-
|
|
35679
|
-
|
|
35680
|
-
childStore = arraySignalStore([], childIdKey, {
|
|
35681
|
-
name: `${childName}#${ownerId} store`,
|
|
35682
|
-
createItem: (props) => {
|
|
35683
|
-
const childItem = {};
|
|
35684
|
-
Object.assign(childItem, props);
|
|
35685
|
-
for (const childSetup of childSetupCallbackSet) {
|
|
35686
|
-
childSetup(childItem);
|
|
35687
|
-
}
|
|
35688
|
-
return childItem;
|
|
35689
|
-
},
|
|
35690
|
-
});
|
|
35691
|
-
scopedStoreMap.set(ownerId, childStore);
|
|
35692
|
-
const newIdArraySignal = signal([]);
|
|
35693
|
-
scopedIdArraySignalMap.set(ownerId, newIdArraySignal);
|
|
35694
|
-
}
|
|
35695
|
-
const childItemIdArraySignal = scopedIdArraySignalMap.get(ownerId);
|
|
35578
|
+
// Owner not in store yet: create the scope so actions can run before
|
|
35579
|
+
// the parent item has been loaded (e.g. rows fetched before their table).
|
|
35580
|
+
const scope = scopeMap.get(ownerId) || createScope(ownerId);
|
|
35581
|
+
const { childStore, idArraySignal } = scope;
|
|
35696
35582
|
|
|
35697
35583
|
if (verb === "DELETE") {
|
|
35698
35584
|
if (isMany) {
|
|
35699
35585
|
const idArray = childStore.drop(rest[0]);
|
|
35700
35586
|
const toRemoveSet = new Set(idArray);
|
|
35701
|
-
|
|
35587
|
+
idArraySignal.value = idArraySignal
|
|
35702
35588
|
.peek()
|
|
35703
35589
|
.filter((id) => !toRemoveSet.has(id));
|
|
35704
35590
|
return [ownerId, idArray];
|
|
35705
35591
|
}
|
|
35706
35592
|
const childId = childStore.drop(rest[0]);
|
|
35707
|
-
|
|
35593
|
+
idArraySignal.value = idArraySignal
|
|
35708
35594
|
.peek()
|
|
35709
35595
|
.filter((id) => id !== childId);
|
|
35710
35596
|
return [ownerId, childId];
|
|
35711
35597
|
}
|
|
35712
35598
|
|
|
35713
35599
|
if (isMany) {
|
|
35714
|
-
// GET_MANY, POST_MANY, PUT_MANY etc: rest[0] is the array of items
|
|
35600
|
+
// GET_MANY, POST_MANY, PUT_MANY etc: rest[0] is the array of items,
|
|
35601
|
+
// and it replaces the whole collection.
|
|
35715
35602
|
const itemArray = childStore.upsert(rest[0]);
|
|
35716
|
-
const idArray = itemArray.map((
|
|
35717
|
-
|
|
35603
|
+
const idArray = itemArray.map((childItem) => childItem[childIdKey]);
|
|
35604
|
+
idArraySignal.value = idArray;
|
|
35718
35605
|
return [ownerId, idArray];
|
|
35719
35606
|
}
|
|
35720
35607
|
|
|
@@ -35726,25 +35613,23 @@ ${originalActionName} source location: ${locationInfo}`,
|
|
|
35726
35613
|
return [ownerId, childItem[childIdKey]];
|
|
35727
35614
|
},
|
|
35728
35615
|
valueToData: (value) => {
|
|
35729
|
-
if (!value)
|
|
35616
|
+
if (!value) {
|
|
35617
|
+
return isMany ? [] : undefined;
|
|
35618
|
+
}
|
|
35730
35619
|
const [ownerId, idOrIdArray] = value;
|
|
35731
|
-
const
|
|
35732
|
-
if (!
|
|
35733
|
-
|
|
35734
|
-
|
|
35735
|
-
|
|
35736
|
-
|
|
35737
|
-
|
|
35620
|
+
const scope = scopeMap.get(ownerId);
|
|
35621
|
+
if (!scope) {
|
|
35622
|
+
return isMany ? [] : undefined;
|
|
35623
|
+
}
|
|
35624
|
+
if (isMany) {
|
|
35625
|
+
return scope.childStore.selectAll(idOrIdArray);
|
|
35626
|
+
}
|
|
35627
|
+
return scope.childStore.select(idOrIdArray);
|
|
35738
35628
|
},
|
|
35629
|
+
completeSideEffect: onActionComplete,
|
|
35739
35630
|
});
|
|
35740
|
-
return childAction;
|
|
35741
35631
|
};
|
|
35742
35632
|
|
|
35743
|
-
// When a child (scopedMany) item is mutated via POST, the parent GET must
|
|
35744
|
-
// re-fetch because the parent embeds the child array and we cannot know the
|
|
35745
|
-
// new ordering without asking the backend again.
|
|
35746
|
-
// (scopedOne does NOT need this: the mutation result contains the updated
|
|
35747
|
-
// item directly, so no parent re-fetch is necessary.)
|
|
35748
35633
|
const childResource = createResource(childName, {
|
|
35749
35634
|
idKey: childIdKey,
|
|
35750
35635
|
restCallbacks: {
|
|
@@ -35766,19 +35651,23 @@ ${originalActionName} source location: ${locationInfo}`,
|
|
|
35766
35651
|
rerunOn: scopedManyRerunOn ?? rerunOn,
|
|
35767
35652
|
dependencies: scopedManyDependencies ?? dependencies,
|
|
35768
35653
|
});
|
|
35769
|
-
//
|
|
35654
|
+
// When a scoped child collection is mutated (POST etc.), the parent GET must
|
|
35655
|
+
// re-fetch: the parent embeds the child array and only the backend knows the
|
|
35656
|
+
// new ordering. (scopedOne does not need this: the mutation result contains
|
|
35657
|
+
// the updated object directly.)
|
|
35770
35658
|
resourceLifecycleManager.addDependency(
|
|
35771
35659
|
childResource,
|
|
35772
35660
|
stateFacade,
|
|
35773
35661
|
propertyName,
|
|
35774
35662
|
);
|
|
35775
|
-
childResource.getChildStore = (ownerKey) =>
|
|
35663
|
+
childResource.getChildStore = (ownerKey) =>
|
|
35664
|
+
scopeMap.get(ownerKey)?.childStore;
|
|
35776
35665
|
return childResource;
|
|
35777
35666
|
};
|
|
35778
35667
|
|
|
35779
|
-
// expose
|
|
35668
|
+
// expose one action (or range reader) per provided rest callback
|
|
35780
35669
|
for (const [restCallbackKey, restCallback] of Object.entries(restCallbacks)) {
|
|
35781
|
-
if (restCallback
|
|
35670
|
+
if (!restCallback) {
|
|
35782
35671
|
continue;
|
|
35783
35672
|
}
|
|
35784
35673
|
if (restCallbackKey === "GET_RANGE") {
|
|
@@ -35800,25 +35689,16 @@ ${originalActionName} source location: ${locationInfo}`,
|
|
|
35800
35689
|
const verb = isMany
|
|
35801
35690
|
? restCallbackKey.replace("_MANY", "")
|
|
35802
35691
|
: restCallbackKey;
|
|
35803
|
-
|
|
35692
|
+
let restAction = createRestAction(verb, restCallback, {
|
|
35804
35693
|
isMany,
|
|
35805
|
-
|
|
35694
|
+
onActionComplete,
|
|
35806
35695
|
paramScope,
|
|
35807
35696
|
});
|
|
35808
|
-
if (!restAction) {
|
|
35809
|
-
console.error("no action returned (here to see when it happens)");
|
|
35810
|
-
continue;
|
|
35811
|
-
}
|
|
35812
|
-
let actionToRegister;
|
|
35813
35697
|
if (params) {
|
|
35814
|
-
|
|
35815
|
-
stateFacade[restCallbackKey] = restActionBound;
|
|
35816
|
-
actionToRegister = restActionBound;
|
|
35817
|
-
} else {
|
|
35818
|
-
stateFacade[restCallbackKey] = restAction;
|
|
35819
|
-
actionToRegister = restAction;
|
|
35698
|
+
restAction = restAction.bindParams(params);
|
|
35820
35699
|
}
|
|
35821
|
-
|
|
35700
|
+
stateFacade[restCallbackKey] = restAction;
|
|
35701
|
+
resourceLifecycleManager.registerAction(stateFacade, restAction);
|
|
35822
35702
|
}
|
|
35823
35703
|
|
|
35824
35704
|
return stateFacade;
|
|
@@ -35829,76 +35709,64 @@ const createRestActionFactoryForRoot = (
|
|
|
35829
35709
|
{
|
|
35830
35710
|
idKey,
|
|
35831
35711
|
store, // see array_signal_store.js
|
|
35712
|
+
declarationSite,
|
|
35832
35713
|
},
|
|
35833
35714
|
) => {
|
|
35834
35715
|
const createActionForRoot = (
|
|
35835
35716
|
verb,
|
|
35836
35717
|
restCallback,
|
|
35837
|
-
{ isMany,
|
|
35718
|
+
{ isMany, onActionComplete, paramScope },
|
|
35838
35719
|
) => {
|
|
35839
35720
|
if (!isMany) {
|
|
35840
35721
|
return createActionAffectingOneItem(verb, restCallback, {
|
|
35841
|
-
|
|
35722
|
+
onActionComplete,
|
|
35842
35723
|
paramScope,
|
|
35843
35724
|
});
|
|
35844
35725
|
}
|
|
35845
35726
|
return createActionAffectingManyItems(verb, restCallback, {
|
|
35846
|
-
|
|
35727
|
+
onActionComplete,
|
|
35847
35728
|
paramScope,
|
|
35848
35729
|
});
|
|
35849
35730
|
};
|
|
35850
35731
|
const createActionAffectingOneItem = (
|
|
35851
35732
|
verb,
|
|
35852
35733
|
callback,
|
|
35853
|
-
{
|
|
35734
|
+
{ onActionComplete, paramScope },
|
|
35854
35735
|
) => {
|
|
35855
35736
|
const applyResultToValue =
|
|
35856
35737
|
verb === "DELETE"
|
|
35857
|
-
? (itemIdOrItemProps) =>
|
|
35858
|
-
const itemId = store.drop(itemIdOrItemProps);
|
|
35859
|
-
return itemId;
|
|
35860
|
-
}
|
|
35738
|
+
? (itemIdOrItemProps) => store.drop(itemIdOrItemProps)
|
|
35861
35739
|
: (result) => {
|
|
35862
|
-
|
|
35863
|
-
|
|
35864
|
-
|
|
35865
|
-
|
|
35866
|
-
|
|
35867
|
-
|
|
35868
|
-
item = store.upsert(...result);
|
|
35869
|
-
} else {
|
|
35870
|
-
item = store.upsert(result);
|
|
35871
|
-
}
|
|
35872
|
-
const itemId = item[idKey];
|
|
35873
|
-
return itemId;
|
|
35740
|
+
// An array result is [property, value, props] — used to rename the
|
|
35741
|
+
// idKey of an item: store.upsert("name", "currentName", { name: "newName" })
|
|
35742
|
+
const item = Array.isArray(result)
|
|
35743
|
+
? store.upsert(...result)
|
|
35744
|
+
: store.upsert(result);
|
|
35745
|
+
return item[idKey];
|
|
35874
35746
|
};
|
|
35875
|
-
|
|
35876
|
-
|
|
35877
|
-
|
|
35878
|
-
|
|
35879
|
-
|
|
35880
|
-
? `${callerInfo.file}:${callerInfo.line}:${callerInfo.column}`
|
|
35881
|
-
: callerInfo.raw || "unknown location";
|
|
35882
|
-
const originalActionName = `${name}.${verb}`;
|
|
35883
|
-
const actionAffectingOneItem = createAction(callback, {
|
|
35747
|
+
const throwInvalidResult = createInvalidResultThrower(
|
|
35748
|
+
`${name}.${verb}`,
|
|
35749
|
+
declarationSite,
|
|
35750
|
+
);
|
|
35751
|
+
return createAction(callback, {
|
|
35884
35752
|
name: `${name}.${verb}`,
|
|
35885
35753
|
meta: { verb, isMany: false, paramScope },
|
|
35886
35754
|
resultToValue: (result, action) => {
|
|
35887
|
-
const actionLabel = action.name;
|
|
35888
|
-
|
|
35889
35755
|
if (verb === "DELETE") {
|
|
35890
35756
|
if (!isProps(result) && !primitiveCanBeId(result)) {
|
|
35891
|
-
|
|
35892
|
-
|
|
35893
|
-
|
|
35757
|
+
throwInvalidResult(
|
|
35758
|
+
action.name,
|
|
35759
|
+
`an object (that will be used to drop "${name}" resource)`,
|
|
35760
|
+
result,
|
|
35894
35761
|
);
|
|
35895
35762
|
}
|
|
35896
35763
|
return applyResultToValue(result);
|
|
35897
35764
|
}
|
|
35898
35765
|
if (!isProps(result)) {
|
|
35899
|
-
|
|
35900
|
-
|
|
35901
|
-
|
|
35766
|
+
throwInvalidResult(
|
|
35767
|
+
action.name,
|
|
35768
|
+
`an object (that will be used to upsert "${name}" resource)`,
|
|
35769
|
+
result,
|
|
35902
35770
|
);
|
|
35903
35771
|
}
|
|
35904
35772
|
// Track which top-level properties the GET response contained so that
|
|
@@ -35909,40 +35777,30 @@ ${originalActionName} source location: ${locationInfo}`,
|
|
|
35909
35777
|
return applyResultToValue(result);
|
|
35910
35778
|
},
|
|
35911
35779
|
valueToData: (itemId) => store.select(itemId),
|
|
35912
|
-
completeSideEffect:
|
|
35913
|
-
lifecycleCtx.onComplete(actionCompleted);
|
|
35914
|
-
},
|
|
35780
|
+
completeSideEffect: onActionComplete,
|
|
35915
35781
|
});
|
|
35916
|
-
return actionAffectingOneItem;
|
|
35917
35782
|
};
|
|
35918
35783
|
const createActionAffectingManyItems = (
|
|
35919
35784
|
verb,
|
|
35920
35785
|
callback,
|
|
35921
|
-
{
|
|
35786
|
+
{ onActionComplete, paramScope },
|
|
35922
35787
|
) => {
|
|
35923
35788
|
const applyResultToValue =
|
|
35924
35789
|
verb === "DELETE"
|
|
35925
|
-
? (idOrMutableIdArray) =>
|
|
35926
|
-
const idArray = store.drop(idOrMutableIdArray);
|
|
35927
|
-
return idArray;
|
|
35928
|
-
}
|
|
35790
|
+
? (idOrMutableIdArray) => store.drop(idOrMutableIdArray)
|
|
35929
35791
|
: (dataArray) => {
|
|
35930
35792
|
const itemArray = store.upsert(dataArray);
|
|
35931
|
-
|
|
35932
|
-
return idArray;
|
|
35793
|
+
return itemArray.map((item) => item[idKey]);
|
|
35933
35794
|
};
|
|
35934
35795
|
|
|
35935
|
-
|
|
35796
|
+
return createAction(callback, {
|
|
35936
35797
|
meta: { verb, isMany: true, paramScope },
|
|
35937
35798
|
name: `${name}.${verb}_MANY`,
|
|
35938
35799
|
dataDefault: [],
|
|
35939
35800
|
resultToValue: applyResultToValue,
|
|
35940
|
-
valueToData: (idArray) =>
|
|
35941
|
-
const items = store.selectAll(idArray);
|
|
35942
|
-
return items;
|
|
35943
|
-
},
|
|
35801
|
+
valueToData: (idArray) => store.selectAll(idArray),
|
|
35944
35802
|
completeSideEffect: (actionCompleted) => {
|
|
35945
|
-
|
|
35803
|
+
onActionComplete(actionCompleted);
|
|
35946
35804
|
if (
|
|
35947
35805
|
verb === "DELETE" ||
|
|
35948
35806
|
actionCompleted.valueSignal.peek().length === 0
|
|
@@ -35956,12 +35814,70 @@ ${originalActionName} source location: ${locationInfo}`,
|
|
|
35956
35814
|
return syncIdArrayOnRename(store, idKey, actionCompleted.valueSignal);
|
|
35957
35815
|
},
|
|
35958
35816
|
});
|
|
35959
|
-
return actionAffectingManyItems;
|
|
35960
35817
|
};
|
|
35961
35818
|
|
|
35962
35819
|
return createActionForRoot;
|
|
35963
35820
|
};
|
|
35964
35821
|
|
|
35822
|
+
// Captures the "file:line:column" of the user code that invoked the public
|
|
35823
|
+
// function (resource(), .one(), .many(), withParams, …), so invalid-result
|
|
35824
|
+
// errors can point at where the callbacks were declared, not at this file.
|
|
35825
|
+
// Must be called directly from the public function: the stack offset accounts
|
|
35826
|
+
// for exactly two frames (getCallerInfo → getDeclarationSite → public fn → user code).
|
|
35827
|
+
const getDeclarationSite = () => {
|
|
35828
|
+
const callerInfo = getCallerInfo(null, 1);
|
|
35829
|
+
if (callerInfo.file && callerInfo.line && callerInfo.column) {
|
|
35830
|
+
return `${callerInfo.file}:${callerInfo.line}:${callerInfo.column}`;
|
|
35831
|
+
}
|
|
35832
|
+
return callerInfo.raw || "unknown location";
|
|
35833
|
+
};
|
|
35834
|
+
|
|
35835
|
+
const createInvalidResultThrower = (originalActionName, declarationSite) => {
|
|
35836
|
+
return (actionLabel, expected, result) => {
|
|
35837
|
+
throw new TypeError(
|
|
35838
|
+
`${actionLabel} must return ${expected}, received ${result}.
|
|
35839
|
+
${originalActionName} source location: ${declarationSite}`,
|
|
35840
|
+
);
|
|
35841
|
+
};
|
|
35842
|
+
};
|
|
35843
|
+
|
|
35844
|
+
// Shared by .many() and .scopedMany(): converts a raw relationship value (an
|
|
35845
|
+
// array of child props/ids, or anything else meaning "empty") into an array of
|
|
35846
|
+
// child ids, upserting each entry into the child store. The id array signal is
|
|
35847
|
+
// only touched when the resulting ids actually differ.
|
|
35848
|
+
const createChildIdArrayUpdater = (childStore, childIdKey, idArraySignal) => {
|
|
35849
|
+
return (valueArray) => {
|
|
35850
|
+
const currentIdArray = idArraySignal.peek();
|
|
35851
|
+
if (!Array.isArray(valueArray)) {
|
|
35852
|
+
if (currentIdArray.length > 0) {
|
|
35853
|
+
idArraySignal.value = [];
|
|
35854
|
+
}
|
|
35855
|
+
return;
|
|
35856
|
+
}
|
|
35857
|
+
const idArray = [];
|
|
35858
|
+
let modified = false;
|
|
35859
|
+
for (const value of valueArray) {
|
|
35860
|
+
let childItemProps;
|
|
35861
|
+
if (isProps(value)) {
|
|
35862
|
+
childItemProps = value;
|
|
35863
|
+
} else if (primitiveCanBeId(value)) {
|
|
35864
|
+
childItemProps = { [childIdKey]: value };
|
|
35865
|
+
} else {
|
|
35866
|
+
continue;
|
|
35867
|
+
}
|
|
35868
|
+
const childItem = childStore.upsert(childItemProps);
|
|
35869
|
+
const childItemId = childItem[childIdKey];
|
|
35870
|
+
if (currentIdArray[idArray.length] !== childItemId) {
|
|
35871
|
+
modified = true;
|
|
35872
|
+
}
|
|
35873
|
+
idArray.push(childItemId);
|
|
35874
|
+
}
|
|
35875
|
+
if (modified || currentIdArray.length !== idArray.length) {
|
|
35876
|
+
idArraySignal.value = idArray;
|
|
35877
|
+
}
|
|
35878
|
+
};
|
|
35879
|
+
};
|
|
35880
|
+
|
|
35965
35881
|
const syncIdArrayOnRename = (store, idKey, idArraySignal) => {
|
|
35966
35882
|
return store.observeProperties((mutations) => {
|
|
35967
35883
|
const idArray = idArraySignal.peek();
|
|
@@ -36021,7 +35937,7 @@ const resolveOwnerId = (rawOwnerId, store, idKey, uniqueKeys, actionName) => {
|
|
|
36021
35937
|
return item[idKey];
|
|
36022
35938
|
}
|
|
36023
35939
|
throw new TypeError(
|
|
36024
|
-
`${actionName}: the first element of the returned array is { ${propName}: "${propValue}" } but "${propName}" is neither the idKey ("${idKey}") nor a declared uniqueKey (${uniqueKeys.length ? uniqueKeys.join(", ") : "none"}).
|
|
35940
|
+
`${actionName}: the first element of the returned array is { ${propName}: "${propValue}" } but "${propName}" is neither the idKey ("${idKey}") nor a declared uniqueKey (${uniqueKeys.length ? uniqueKeys.join(", ") : "none"}).
|
|
36025
35941
|
Return a primitive id or a single-property object whose key is the idKey or a uniqueKey.`,
|
|
36026
35942
|
);
|
|
36027
35943
|
}
|
|
@@ -36030,7 +35946,7 @@ Return a primitive id or a single-property object whose key is the idKey or a un
|
|
|
36030
35946
|
if (idKey in rawOwnerId) {
|
|
36031
35947
|
const resolvedId = rawOwnerId[idKey];
|
|
36032
35948
|
console.warn(
|
|
36033
|
-
`${actionName}: the first element of the returned array is an object with multiple properties.
|
|
35949
|
+
`${actionName}: the first element of the returned array is an object with multiple properties.
|
|
36034
35950
|
Only "${idKey}" is needed. Consider returning a primitive id or { ${idKey}: value } instead.`,
|
|
36035
35951
|
);
|
|
36036
35952
|
return resolvedId;
|
|
@@ -36042,8 +35958,10 @@ Received an object with keys: ${keys.join(", ")}.`,
|
|
|
36042
35958
|
);
|
|
36043
35959
|
};
|
|
36044
35960
|
|
|
36045
|
-
/**
|
|
36046
|
-
*
|
|
35961
|
+
/**
|
|
35962
|
+
* Keeps external signals in sync with properties of the resource's store items:
|
|
35963
|
+
* when a tracked property changes on an item, the corresponding signal is
|
|
35964
|
+
* updated automatically.
|
|
36047
35965
|
*
|
|
36048
35966
|
* Since signals are typically connected to route parameters via the route template
|
|
36049
35967
|
* syntax, this keeps the URL in sync when a store item's mutable key is renamed.
|
|
@@ -38598,7 +38516,7 @@ const ROUTE_TRAVEL_ATTRIBUTE = "data-navi-route-travel";
|
|
|
38598
38516
|
// the root pictures must NOT move (they carry the whole viewport, blank bands
|
|
38599
38517
|
// included).
|
|
38600
38518
|
|
|
38601
|
-
const css$
|
|
38519
|
+
const css$W = /* css */`
|
|
38602
38520
|
/* The marked region is a picture of its own for the length of a transition of
|
|
38603
38521
|
OURS, and only then — the name is what makes the pages a picture the
|
|
38604
38522
|
movement below can carry.
|
|
@@ -39027,7 +38945,7 @@ const RouteTransitionArea = ({
|
|
|
39027
38945
|
children,
|
|
39028
38946
|
...rest
|
|
39029
38947
|
}) => {
|
|
39030
|
-
import.meta.css = [css$
|
|
38948
|
+
import.meta.css = [css$W, "@jsenv/navi/src/nav/route_transition.jsx"];
|
|
39031
38949
|
const props = {
|
|
39032
38950
|
...rest,
|
|
39033
38951
|
[TRANSITION_AREA_ATTRIBUTE]: ""
|
|
@@ -39084,7 +39002,7 @@ const RouteTransitionArea = ({
|
|
|
39084
39002
|
* @returns {() => void} remove this relation.
|
|
39085
39003
|
*/
|
|
39086
39004
|
const defineRouteTransition = (from, to, transition) => {
|
|
39087
|
-
import.meta.css = [css$
|
|
39005
|
+
import.meta.css = [css$W, "@jsenv/navi/src/nav/route_transition.jsx"];
|
|
39088
39006
|
const {
|
|
39089
39007
|
type,
|
|
39090
39008
|
duration
|
|
@@ -39120,7 +39038,7 @@ const defineRouteTransition = (from, to, transition) => {
|
|
|
39120
39038
|
* @returns {() => void} remove this default.
|
|
39121
39039
|
*/
|
|
39122
39040
|
const defineRouteDefaultTransition = transition => {
|
|
39123
|
-
import.meta.css = [css$
|
|
39041
|
+
import.meta.css = [css$W, "@jsenv/navi/src/nav/route_transition.jsx"];
|
|
39124
39042
|
const value = normalizeTransition(transition);
|
|
39125
39043
|
defaultTransition = value;
|
|
39126
39044
|
return () => {
|
|
@@ -39721,7 +39639,7 @@ const DRAGGED_ATTRIBUTE = "data-navi-route-travel-dragged";
|
|
|
39721
39639
|
const TURNED_ATTRIBUTE = "data-navi-route-travel-turned";
|
|
39722
39640
|
// The name the box wears while it travels, and only then (see nameForTravel).
|
|
39723
39641
|
const TRAVEL_NAME = "navi-route-travel";
|
|
39724
|
-
const css$
|
|
39642
|
+
const css$V = /* css */`
|
|
39725
39643
|
/* The name that makes the page inside this box a picture of its own during a
|
|
39726
39644
|
transition — rather than part of the one big picture the document takes, so
|
|
39727
39645
|
the two pages can move past each other while everything else stays where it
|
|
@@ -40111,7 +40029,7 @@ const RouteTravel = ({
|
|
|
40111
40029
|
children,
|
|
40112
40030
|
...rest
|
|
40113
40031
|
}) => {
|
|
40114
|
-
import.meta.css = [css$
|
|
40032
|
+
import.meta.css = [css$V, "@jsenv/navi/src/nav/route_travel.jsx"];
|
|
40115
40033
|
const elementRef = useRef();
|
|
40116
40034
|
const gestureRef = useRef(null);
|
|
40117
40035
|
// The travel in hand: the transition keeping the picture of the page being
|
|
@@ -42673,7 +42591,7 @@ const PhoneSvg = () => {
|
|
|
42673
42591
|
};
|
|
42674
42592
|
|
|
42675
42593
|
installImportMetaCssBuild(import.meta);// # TextAnchor — how it works
|
|
42676
|
-
const css$
|
|
42594
|
+
const css$U = /* css */`
|
|
42677
42595
|
.navi_text_anchor {
|
|
42678
42596
|
vertical-align: baseline;
|
|
42679
42597
|
user-select: none;
|
|
@@ -42708,7 +42626,7 @@ const TextAnchor = ({
|
|
|
42708
42626
|
textSize,
|
|
42709
42627
|
lineLayout
|
|
42710
42628
|
}) => {
|
|
42711
|
-
import.meta.css = [css$
|
|
42629
|
+
import.meta.css = [css$U, "@jsenv/navi/src/text/text_anchor.jsx"];
|
|
42712
42630
|
const anchorRef = useRef();
|
|
42713
42631
|
|
|
42714
42632
|
// Plain useLayoutEffect would also fire while an ancestor dialog/popover
|
|
@@ -42823,7 +42741,7 @@ const computeTopOffset = ({
|
|
|
42823
42741
|
};
|
|
42824
42742
|
const charTopCanvas = document.createElement("canvas");
|
|
42825
42743
|
|
|
42826
|
-
installImportMetaCssBuild(import.meta);const css$
|
|
42744
|
+
installImportMetaCssBuild(import.meta);const css$T = /* css */`
|
|
42827
42745
|
@layer navi {
|
|
42828
42746
|
/* Ensure data attributes from box.jsx can win to update display */
|
|
42829
42747
|
.navi_icon {
|
|
@@ -42981,7 +42899,7 @@ const Icon = ({
|
|
|
42981
42899
|
fillLine,
|
|
42982
42900
|
...props
|
|
42983
42901
|
}) => {
|
|
42984
|
-
import.meta.css = [css$
|
|
42902
|
+
import.meta.css = [css$T, "@jsenv/navi/src/text/icon.jsx"];
|
|
42985
42903
|
const innerChildren = href ? jsx("svg", {
|
|
42986
42904
|
width: "100%",
|
|
42987
42905
|
height: "100%",
|
|
@@ -43143,7 +43061,7 @@ const useDimColorWhen = (elementRef, shouldDim) => {
|
|
|
43143
43061
|
});
|
|
43144
43062
|
};
|
|
43145
43063
|
|
|
43146
|
-
installImportMetaCssBuild(import.meta);const css$
|
|
43064
|
+
installImportMetaCssBuild(import.meta);const css$S = /* css */`
|
|
43147
43065
|
@layer navi {
|
|
43148
43066
|
.navi_link {
|
|
43149
43067
|
--link-border-radius: unset;
|
|
@@ -43605,7 +43523,7 @@ Object.assign(PSEUDO_CLASSES, {
|
|
|
43605
43523
|
* @param {boolean} [props.readOnly]
|
|
43606
43524
|
*/
|
|
43607
43525
|
const Link = props => {
|
|
43608
|
-
import.meta.css = [css$
|
|
43526
|
+
import.meta.css = [css$S, "@jsenv/navi/src/nav/link/link.jsx"];
|
|
43609
43527
|
if (props.route) {
|
|
43610
43528
|
return jsx(LinkWithRoute, {
|
|
43611
43529
|
...props
|
|
@@ -43928,7 +43846,7 @@ installImportMetaCssBuild(import.meta);/**
|
|
|
43928
43846
|
* https://dribbble.com/search/tabs
|
|
43929
43847
|
*/
|
|
43930
43848
|
let navCount = 0;
|
|
43931
|
-
const css$
|
|
43849
|
+
const css$R = /* css */`
|
|
43932
43850
|
@layer navi {
|
|
43933
43851
|
.navi_nav {
|
|
43934
43852
|
--nav-border: none;
|
|
@@ -44211,7 +44129,7 @@ const Nav = ({
|
|
|
44211
44129
|
slideContainer,
|
|
44212
44130
|
...props
|
|
44213
44131
|
}) => {
|
|
44214
|
-
import.meta.css = [css$
|
|
44132
|
+
import.meta.css = [css$R, "@jsenv/navi/src/nav/link/nav.jsx"];
|
|
44215
44133
|
const defaultRef = useRef();
|
|
44216
44134
|
props.ref = props.ref || defaultRef;
|
|
44217
44135
|
const navRef = props.ref;
|
|
@@ -44738,7 +44656,7 @@ installImportMetaCssBuild(import.meta);/**
|
|
|
44738
44656
|
* Border width participates in layout (it is added to the tab and page
|
|
44739
44657
|
* padding): a thick border grows the binder rather than eating into the text.
|
|
44740
44658
|
*/
|
|
44741
|
-
const css$
|
|
44659
|
+
const css$Q = /* css */`
|
|
44742
44660
|
@layer navi {
|
|
44743
44661
|
.navi_binder {
|
|
44744
44662
|
--binder-border-width: var(--navi-control-border-width);
|
|
@@ -45051,7 +44969,7 @@ const Binder = ({
|
|
|
45051
44969
|
pagePadding,
|
|
45052
44970
|
...props
|
|
45053
44971
|
}) => {
|
|
45054
|
-
import.meta.css = [css$
|
|
44972
|
+
import.meta.css = [css$Q, "@jsenv/navi/src/nav/binder/binder.jsx"];
|
|
45055
44973
|
const items = toChildArray(children).map((child, index) => {
|
|
45056
44974
|
const {
|
|
45057
44975
|
value: itemValue,
|
|
@@ -45538,7 +45456,7 @@ installImportMetaCssBuild(import.meta);/**
|
|
|
45538
45456
|
* added to the size asked for exactly like the notch inset is, so the
|
|
45539
45457
|
* content still gets the size the prop names.
|
|
45540
45458
|
*/
|
|
45541
|
-
const css$
|
|
45459
|
+
const css$P = /* css */`
|
|
45542
45460
|
@layer navi {
|
|
45543
45461
|
:root {
|
|
45544
45462
|
--navi-fixed-bar-width: 56px;
|
|
@@ -45686,7 +45604,7 @@ const FixedBar = ({
|
|
|
45686
45604
|
border = true,
|
|
45687
45605
|
...props
|
|
45688
45606
|
}) => {
|
|
45689
|
-
import.meta.css = [css$
|
|
45607
|
+
import.meta.css = [css$P, "@jsenv/navi/src/layout/fixed_bar/fixed_bar.jsx"];
|
|
45690
45608
|
const defaultRef = useRef();
|
|
45691
45609
|
props.ref = props.ref || defaultRef;
|
|
45692
45610
|
// Said with the width the border rule reads rather than with an attribute of
|
|
@@ -45780,7 +45698,7 @@ const FixedBar = ({
|
|
|
45780
45698
|
// Subpixel layout rounds rectangles up on boxes that fit exactly.
|
|
45781
45699
|
const OVERFLOW_TOLERANCE = 1;
|
|
45782
45700
|
|
|
45783
|
-
const css$
|
|
45701
|
+
const css$O = /* css */ `
|
|
45784
45702
|
[data-navi-overflow-x] {
|
|
45785
45703
|
outline: 2px dashed #e74c3c;
|
|
45786
45704
|
outline-offset: -2px;
|
|
@@ -45804,7 +45722,7 @@ const detectHorizontalOverflow = ({
|
|
|
45804
45722
|
let styleEl = null;
|
|
45805
45723
|
if (highlight) {
|
|
45806
45724
|
styleEl = document.createElement("style");
|
|
45807
|
-
styleEl.textContent = css$
|
|
45725
|
+
styleEl.textContent = css$O;
|
|
45808
45726
|
document.head.appendChild(styleEl);
|
|
45809
45727
|
}
|
|
45810
45728
|
|
|
@@ -45959,7 +45877,7 @@ const useFocusGroup = (
|
|
|
45959
45877
|
};
|
|
45960
45878
|
|
|
45961
45879
|
installImportMetaCssBuild(import.meta);const rightArrowPath = "M680-480L360-160l-80-80 240-240-240-240 80-80 320 320z";
|
|
45962
|
-
const css$
|
|
45880
|
+
const css$N = /* css */`
|
|
45963
45881
|
.navi_summary_marker {
|
|
45964
45882
|
width: 1em;
|
|
45965
45883
|
height: 1em;
|
|
@@ -46049,7 +45967,7 @@ const SummaryMarker = ({
|
|
|
46049
45967
|
loading,
|
|
46050
45968
|
openDirection = "down"
|
|
46051
45969
|
}) => {
|
|
46052
|
-
import.meta.css = [css$
|
|
45970
|
+
import.meta.css = [css$N, "@jsenv/navi/src/control/details/summary_marker.jsx"];
|
|
46053
45971
|
const showLoading = useDebounceTrue(loading, 300);
|
|
46054
45972
|
return jsx("span", {
|
|
46055
45973
|
className: "navi_summary_marker",
|
|
@@ -46094,7 +46012,7 @@ const SummaryMarker = ({
|
|
|
46094
46012
|
});
|
|
46095
46013
|
};
|
|
46096
46014
|
|
|
46097
|
-
installImportMetaCssBuild(import.meta);const css$
|
|
46015
|
+
installImportMetaCssBuild(import.meta);const css$M = /* css */`
|
|
46098
46016
|
.navi_details {
|
|
46099
46017
|
position: relative;
|
|
46100
46018
|
z-index: 1;
|
|
@@ -46140,7 +46058,7 @@ const Details = props => {
|
|
|
46140
46058
|
return details;
|
|
46141
46059
|
};
|
|
46142
46060
|
const DetailsField = props => {
|
|
46143
|
-
import.meta.css = [css$
|
|
46061
|
+
import.meta.css = [css$M, "@jsenv/navi/src/control/details/details.jsx"];
|
|
46144
46062
|
const {
|
|
46145
46063
|
ref,
|
|
46146
46064
|
persists,
|
|
@@ -46360,7 +46278,7 @@ installImportMetaCssBuild(import.meta);/**
|
|
|
46360
46278
|
* UI when it comes first). Once settled open the clipping is released, so a
|
|
46361
46279
|
* popover or focus ring inside is not cut at the edges.
|
|
46362
46280
|
*/
|
|
46363
|
-
const css$
|
|
46281
|
+
const css$L = /* css */`
|
|
46364
46282
|
.navi_expandable {
|
|
46365
46283
|
position: relative;
|
|
46366
46284
|
display: flex;
|
|
@@ -46586,7 +46504,7 @@ const useExpandableContext = partName => {
|
|
|
46586
46504
|
* and rebuilds it from scratch on every expansion.
|
|
46587
46505
|
*/
|
|
46588
46506
|
const Expandable = props => {
|
|
46589
|
-
import.meta.css = [css$
|
|
46507
|
+
import.meta.css = [css$L, "@jsenv/navi/src/control/expandable/expandable.jsx"];
|
|
46590
46508
|
const {
|
|
46591
46509
|
ref,
|
|
46592
46510
|
ui,
|
|
@@ -47251,7 +47169,7 @@ const ControlGroup = props => {
|
|
|
47251
47169
|
};
|
|
47252
47170
|
const CONTROL_GROUP_PSEUDO_CLASSES = [":hover", ":focus", ":focus-visible", ":read-only", ":disabled", ":-navi-loading"];
|
|
47253
47171
|
|
|
47254
|
-
installImportMetaCssBuild(import.meta);const css$
|
|
47172
|
+
installImportMetaCssBuild(import.meta);const css$K = /* css */`
|
|
47255
47173
|
@layer navi {
|
|
47256
47174
|
.navi_checkbox {
|
|
47257
47175
|
--switch-margin: 0; /* Useful to reserve space for outline */
|
|
@@ -47329,7 +47247,7 @@ installImportMetaCssBuild(import.meta);const css$J = /* css */`
|
|
|
47329
47247
|
}
|
|
47330
47248
|
`;
|
|
47331
47249
|
const SwitchUI = () => {
|
|
47332
|
-
import.meta.css = [css$
|
|
47250
|
+
import.meta.css = [css$K, "@jsenv/navi/src/control/input/switch_ui.jsx"];
|
|
47333
47251
|
return jsx(Box, {
|
|
47334
47252
|
className: "navi_switch",
|
|
47335
47253
|
as: "svg",
|
|
@@ -47371,7 +47289,7 @@ const useCheckableProps = (props, options) => {
|
|
|
47371
47289
|
return result;
|
|
47372
47290
|
};
|
|
47373
47291
|
|
|
47374
|
-
installImportMetaCssBuild(import.meta);const css$
|
|
47292
|
+
installImportMetaCssBuild(import.meta);const css$J = /* css */`
|
|
47375
47293
|
@layer navi {
|
|
47376
47294
|
.navi_checkbox {
|
|
47377
47295
|
--border-radius: var(--navi-checkbox-border-radius);
|
|
@@ -47698,7 +47616,7 @@ const InputCheckboxHeadless = props => {
|
|
|
47698
47616
|
});
|
|
47699
47617
|
};
|
|
47700
47618
|
const InputCheckboxFieldInterface = props => {
|
|
47701
|
-
import.meta.css = [css$
|
|
47619
|
+
import.meta.css = [css$J, "@jsenv/navi/src/control/input/input_checkbox.jsx"];
|
|
47702
47620
|
const [checkboxRootProps, checkboxHostProps] = useCheckableProps(props);
|
|
47703
47621
|
const {
|
|
47704
47622
|
icon,
|
|
@@ -47820,7 +47738,7 @@ const CheckboxButtonStyleCSSVars = {
|
|
|
47820
47738
|
const CheckboxPseudoClasses = [":hover", ":active", ":focus", ":focus-visible", ":read-only", ":disabled", ":checked", ":-navi-loading"];
|
|
47821
47739
|
const CheckboxPseudoElements = ["::-navi-loader", "::-navi-checkmark"];
|
|
47822
47740
|
|
|
47823
|
-
installImportMetaCssBuild(import.meta);const css$
|
|
47741
|
+
installImportMetaCssBuild(import.meta);const css$I = /* css */`
|
|
47824
47742
|
@layer navi {
|
|
47825
47743
|
.navi_label {
|
|
47826
47744
|
--label-required-indicator-color: var(--navi-color-danger, #b42318);
|
|
@@ -47900,7 +47818,7 @@ installImportMetaCssBuild(import.meta);const css$H = /* css */`
|
|
|
47900
47818
|
* </Field>
|
|
47901
47819
|
*/
|
|
47902
47820
|
const Field = props => {
|
|
47903
|
-
import.meta.css = [css$
|
|
47821
|
+
import.meta.css = [css$I, "@jsenv/navi/src/control/field.jsx"];
|
|
47904
47822
|
const refDefault = useRef();
|
|
47905
47823
|
props.ref = props.ref || refDefault;
|
|
47906
47824
|
const {
|
|
@@ -47935,7 +47853,7 @@ const FieldCSSVars = {
|
|
|
47935
47853
|
spacingWithControl: "--spacing-with-control"
|
|
47936
47854
|
};
|
|
47937
47855
|
const FieldAsContainer = props => {
|
|
47938
|
-
import.meta.css = [css$
|
|
47856
|
+
import.meta.css = [css$I, "@jsenv/navi/src/control/field.jsx"];
|
|
47939
47857
|
const {
|
|
47940
47858
|
children
|
|
47941
47859
|
} = props;
|
|
@@ -47967,7 +47885,7 @@ const FieldAsContainer = props => {
|
|
|
47967
47885
|
};
|
|
47968
47886
|
const FIELD_PSEUDO_CLASSES = [":hover", ":active", ":focus", ":focus-visible", ":read-only", ":disabled", ":-navi-loading"];
|
|
47969
47887
|
const Label = props => {
|
|
47970
|
-
import.meta.css = [css$
|
|
47888
|
+
import.meta.css = [css$I, "@jsenv/navi/src/control/field.jsx"];
|
|
47971
47889
|
const {
|
|
47972
47890
|
children,
|
|
47973
47891
|
// Marks the label when its control is required. Takes what to show, or
|
|
@@ -48129,7 +48047,7 @@ const InputSlot = ({
|
|
|
48129
48047
|
});
|
|
48130
48048
|
};
|
|
48131
48049
|
|
|
48132
|
-
installImportMetaCssBuild(import.meta);const css$
|
|
48050
|
+
installImportMetaCssBuild(import.meta);const css$H = /* css */`
|
|
48133
48051
|
@layer navi {
|
|
48134
48052
|
.navi_radio {
|
|
48135
48053
|
--margin: 3px 3px 3px 5px;
|
|
@@ -48492,7 +48410,7 @@ const InputRadioHeadless = props => {
|
|
|
48492
48410
|
};
|
|
48493
48411
|
const VARIANT_SET = new Set(["icon", "button", "radio"]);
|
|
48494
48412
|
const InputRadioFieldInterface = props => {
|
|
48495
|
-
import.meta.css = [css$
|
|
48413
|
+
import.meta.css = [css$H, "@jsenv/navi/src/control/input/input_radio.jsx"];
|
|
48496
48414
|
const [radioRootProps, radioHostProps] = useCheckableProps(props);
|
|
48497
48415
|
const {
|
|
48498
48416
|
icon,
|
|
@@ -48638,7 +48556,7 @@ const RadioButtonStyleCSSVars = {
|
|
|
48638
48556
|
const RadioPseudoClasses = [":hover", ":active", ":focus", ":focus-visible", ":read-only", ":disabled", ":checked", ":-navi-loading"];
|
|
48639
48557
|
const RadioPseudoElements = ["::-navi-loader", "::-navi-radiomark"];
|
|
48640
48558
|
|
|
48641
|
-
installImportMetaCssBuild(import.meta);const css$
|
|
48559
|
+
installImportMetaCssBuild(import.meta);const css$G = /* css */`
|
|
48642
48560
|
@layer navi {
|
|
48643
48561
|
.navi_input_range {
|
|
48644
48562
|
--border-radius: 6px;
|
|
@@ -48893,7 +48811,7 @@ const InputRange = props => {
|
|
|
48893
48811
|
});
|
|
48894
48812
|
};
|
|
48895
48813
|
const InputRangeFieldInterface = props => {
|
|
48896
|
-
import.meta.css = [css$
|
|
48814
|
+
import.meta.css = [css$G, "@jsenv/navi/src/control/input/input_range.jsx"];
|
|
48897
48815
|
const {
|
|
48898
48816
|
ref
|
|
48899
48817
|
} = props;
|
|
@@ -51001,7 +50919,7 @@ installImportMetaCssBuild(import.meta);/**
|
|
|
51001
50919
|
* This means an editable thing MUST have a parent with position relative that wraps the content and the eventual editable input
|
|
51002
50920
|
*
|
|
51003
50921
|
*/
|
|
51004
|
-
const css$
|
|
50922
|
+
const css$F = /* css */`
|
|
51005
50923
|
.navi_editable_wrapper {
|
|
51006
50924
|
--inset-top: 0px;
|
|
51007
50925
|
--inset-right: 0px;
|
|
@@ -51050,7 +50968,7 @@ const useEditionController = () => {
|
|
|
51050
50968
|
};
|
|
51051
50969
|
};
|
|
51052
50970
|
const Editable = props => {
|
|
51053
|
-
import.meta.css = [css$
|
|
50971
|
+
import.meta.css = [css$F, "@jsenv/navi/src/control/edition/editable.jsx"];
|
|
51054
50972
|
let {
|
|
51055
50973
|
children,
|
|
51056
50974
|
action,
|
|
@@ -51599,7 +51517,7 @@ installImportMetaCssBuild(import.meta);/**
|
|
|
51599
51517
|
* meet are drawn once instead of twice, and only the outer corners stay
|
|
51600
51518
|
* rounded. See docs/control_group.md.
|
|
51601
51519
|
*/
|
|
51602
|
-
const css$
|
|
51520
|
+
const css$E = /* css */`
|
|
51603
51521
|
.navi_group {
|
|
51604
51522
|
--group-border-width: var(--navi-control-border-width);
|
|
51605
51523
|
|
|
@@ -51715,7 +51633,7 @@ const Group = ({
|
|
|
51715
51633
|
vertical = row,
|
|
51716
51634
|
...props
|
|
51717
51635
|
}) => {
|
|
51718
|
-
import.meta.css = [css$
|
|
51636
|
+
import.meta.css = [css$E, "@jsenv/navi/src/control/group.jsx"];
|
|
51719
51637
|
return jsx(Box, {
|
|
51720
51638
|
baseClassName: "navi_group",
|
|
51721
51639
|
"data-vertical": vertical ? "" : undefined
|
|
@@ -51881,7 +51799,7 @@ installImportMetaCssBuild(import.meta);/**
|
|
|
51881
51799
|
* So: nothing scrollable between the cap and the slides (a shared [data-body]
|
|
51882
51800
|
* around them IS a scroller, see box.jsx), and `overflow="auto"` on each Slide.
|
|
51883
51801
|
*/
|
|
51884
|
-
const css$
|
|
51802
|
+
const css$D = /* css */`
|
|
51885
51803
|
/* Where the picture stands relative to the slide that is current, in boxes
|
|
51886
51804
|
(see paintTravelProgress). Declared, so that it is a NUMBER the browser can
|
|
51887
51805
|
interpolate: the trait an indicator draws has to travel with the slides,
|
|
@@ -52375,7 +52293,7 @@ const SlideContainer = ({
|
|
|
52375
52293
|
children,
|
|
52376
52294
|
...rest
|
|
52377
52295
|
}) => {
|
|
52378
|
-
import.meta.css = [css$
|
|
52296
|
+
import.meta.css = [css$D, "@jsenv/navi/src/layout/slide_container.jsx"];
|
|
52379
52297
|
const debugFocus = useDebugFocus();
|
|
52380
52298
|
const trackRef = useRef();
|
|
52381
52299
|
// The box itself: it is what takes the keyboard when what is on screen holds
|
|
@@ -55220,7 +55138,7 @@ installImportMetaCssBuild(import.meta);/**
|
|
|
55220
55138
|
* and only under its own `sizeFromAnchor`) pass through untouched via
|
|
55221
55139
|
* `...rest` to whichever of Popover/Dialog actually renders.
|
|
55222
55140
|
*/
|
|
55223
|
-
const css$
|
|
55141
|
+
const css$C = /* css */`
|
|
55224
55142
|
@layer navi {
|
|
55225
55143
|
.navi_popup {
|
|
55226
55144
|
--popup-border-radius: var(--navi-popup-border-radius);
|
|
@@ -55337,7 +55255,7 @@ const css$B = /* css */`
|
|
|
55337
55255
|
* @param {import("ignore:preact").ComponentChildren} props.children
|
|
55338
55256
|
*/
|
|
55339
55257
|
const Popup = props => {
|
|
55340
|
-
import.meta.css = [css$
|
|
55258
|
+
import.meta.css = [css$C, "@jsenv/navi/src/layout/popup.jsx"];
|
|
55341
55259
|
const {
|
|
55342
55260
|
mode: modeProp,
|
|
55343
55261
|
maxWidth,
|
|
@@ -55398,7 +55316,7 @@ const Popup = props => {
|
|
|
55398
55316
|
});
|
|
55399
55317
|
};
|
|
55400
55318
|
|
|
55401
|
-
installImportMetaCssBuild(import.meta);const css$
|
|
55319
|
+
installImportMetaCssBuild(import.meta);const css$B = /* css */`
|
|
55402
55320
|
.navi_picker {
|
|
55403
55321
|
/* Sizing ceilings (maxmax), background, box-shadow, outline, padding,
|
|
55404
55322
|
overflow... are already handled correctly by Popup/Popover/Dialog
|
|
@@ -55526,7 +55444,7 @@ installImportMetaCssBuild(import.meta);const css$A = /* css */`
|
|
|
55526
55444
|
}
|
|
55527
55445
|
`;
|
|
55528
55446
|
const PickerCustomResolver = props => {
|
|
55529
|
-
import.meta.css = [css$
|
|
55447
|
+
import.meta.css = [css$B, "@jsenv/navi/src/control/picker/picker_custom.jsx"];
|
|
55530
55448
|
if (props.children === undefined) {
|
|
55531
55449
|
return jsx(PickerNative, {
|
|
55532
55450
|
...props
|
|
@@ -56320,7 +56238,7 @@ const LoadingIndicator = ({
|
|
|
56320
56238
|
});
|
|
56321
56239
|
};
|
|
56322
56240
|
|
|
56323
|
-
installImportMetaCssBuild(import.meta);const css$
|
|
56241
|
+
installImportMetaCssBuild(import.meta);const css$A = /* css */`
|
|
56324
56242
|
@layer navi {
|
|
56325
56243
|
.navi_separator {
|
|
56326
56244
|
--size: 1px;
|
|
@@ -56398,7 +56316,7 @@ const Separator = ({
|
|
|
56398
56316
|
style,
|
|
56399
56317
|
...props
|
|
56400
56318
|
}) => {
|
|
56401
|
-
import.meta.css = [css$
|
|
56319
|
+
import.meta.css = [css$A, "@jsenv/navi/src/layout/separator.jsx"];
|
|
56402
56320
|
return jsx(Box, {
|
|
56403
56321
|
as: vertical ? "span" : "hr",
|
|
56404
56322
|
...props,
|
|
@@ -56891,7 +56809,7 @@ const ListItemFooter = props => {
|
|
|
56891
56809
|
});
|
|
56892
56810
|
};
|
|
56893
56811
|
|
|
56894
|
-
installImportMetaCssBuild(import.meta);const css$
|
|
56812
|
+
installImportMetaCssBuild(import.meta);const css$z = /* css */`
|
|
56895
56813
|
@layer navi {
|
|
56896
56814
|
.navi_list_container[navi-selectable] {
|
|
56897
56815
|
/* Focus outline */
|
|
@@ -57103,7 +57021,7 @@ const ListSelectableResolver = props => {
|
|
|
57103
57021
|
};
|
|
57104
57022
|
const ListSelectable = props => {
|
|
57105
57023
|
const Next = useNextResolver();
|
|
57106
|
-
import.meta.css = [css$
|
|
57024
|
+
import.meta.css = [css$z, "@jsenv/navi/src/control/list/list_selectable.jsx"];
|
|
57107
57025
|
// we allow ourselves to auto-generate a name
|
|
57108
57026
|
const defaultName = useId();
|
|
57109
57027
|
props.name = props.name || `listbox_${defaultName}`;
|
|
@@ -57723,7 +57641,7 @@ const ListVirtualContext = createContext(null);
|
|
|
57723
57641
|
// that returning a component of one's own — instead of a bare <List.Item> —
|
|
57724
57642
|
// works the same way.
|
|
57725
57643
|
const ListRowContext = createContext(null);
|
|
57726
|
-
const css$
|
|
57644
|
+
const css$y = /* css */`
|
|
57727
57645
|
@layer navi {
|
|
57728
57646
|
.navi_list_container {
|
|
57729
57647
|
--list-outline-width: 1px;
|
|
@@ -58422,7 +58340,7 @@ const css$x = /* css */`
|
|
|
58422
58340
|
}
|
|
58423
58341
|
`;
|
|
58424
58342
|
const ListUI = props => {
|
|
58425
|
-
import.meta.css = [css$
|
|
58343
|
+
import.meta.css = [css$y, "@jsenv/navi/src/control/list/list.jsx"];
|
|
58426
58344
|
const {
|
|
58427
58345
|
ref,
|
|
58428
58346
|
renderBudget: renderBudgetProp = RENDER_BUDGET_DEFAULT,
|
|
@@ -62091,7 +62009,7 @@ const PickerPresetResolver = props => {
|
|
|
62091
62009
|
});
|
|
62092
62010
|
};
|
|
62093
62011
|
|
|
62094
|
-
installImportMetaCssBuild(import.meta);const css$
|
|
62012
|
+
installImportMetaCssBuild(import.meta);const css$x = /* css */`
|
|
62095
62013
|
@layer navi {
|
|
62096
62014
|
}
|
|
62097
62015
|
.navi_badge {
|
|
@@ -62203,7 +62121,7 @@ const Badge = ({
|
|
|
62203
62121
|
className,
|
|
62204
62122
|
...props
|
|
62205
62123
|
}) => {
|
|
62206
|
-
import.meta.css = [css$
|
|
62124
|
+
import.meta.css = [css$x, "@jsenv/navi/src/text/badge.jsx"];
|
|
62207
62125
|
const defaultRef = useRef();
|
|
62208
62126
|
props.ref = props.ref || defaultRef;
|
|
62209
62127
|
const {
|
|
@@ -62255,7 +62173,7 @@ const BadgeButton = props => {
|
|
|
62255
62173
|
};
|
|
62256
62174
|
Badge.Button = BadgeButton;
|
|
62257
62175
|
|
|
62258
|
-
installImportMetaCssBuild(import.meta);const css$
|
|
62176
|
+
installImportMetaCssBuild(import.meta);const css$w = /* css */`
|
|
62259
62177
|
@layer navi {
|
|
62260
62178
|
}
|
|
62261
62179
|
.navi_badge_list {
|
|
@@ -62280,7 +62198,7 @@ const BadgeList = ({
|
|
|
62280
62198
|
max,
|
|
62281
62199
|
...props
|
|
62282
62200
|
}) => {
|
|
62283
|
-
import.meta.css = [css$
|
|
62201
|
+
import.meta.css = [css$w, "@jsenv/navi/src/text/badge_list.jsx"];
|
|
62284
62202
|
const measureRef = useRef();
|
|
62285
62203
|
const visibleRef = useRef();
|
|
62286
62204
|
useLayoutEffect(() => {
|
|
@@ -62355,7 +62273,7 @@ const BadgeList = ({
|
|
|
62355
62273
|
});
|
|
62356
62274
|
};
|
|
62357
62275
|
|
|
62358
|
-
installImportMetaCssBuild(import.meta);const css$
|
|
62276
|
+
installImportMetaCssBuild(import.meta);const css$v = /* css */`
|
|
62359
62277
|
.navi_color {
|
|
62360
62278
|
display: block;
|
|
62361
62279
|
aspect-ratio: 1/1;
|
|
@@ -62386,7 +62304,7 @@ const Color = ({
|
|
|
62386
62304
|
children,
|
|
62387
62305
|
...rest
|
|
62388
62306
|
}) => {
|
|
62389
|
-
import.meta.css = [css$
|
|
62307
|
+
import.meta.css = [css$v, "@jsenv/navi/src/text/color.jsx"];
|
|
62390
62308
|
const color = children || undefined;
|
|
62391
62309
|
return jsx(Box, {
|
|
62392
62310
|
as: "span",
|
|
@@ -62843,7 +62761,7 @@ const PickerFileUI = () => {
|
|
|
62843
62761
|
return String(value);
|
|
62844
62762
|
};
|
|
62845
62763
|
|
|
62846
|
-
installImportMetaCssBuild(import.meta);const css$
|
|
62764
|
+
installImportMetaCssBuild(import.meta);const css$u = /* css */`
|
|
62847
62765
|
@layer navi {
|
|
62848
62766
|
.navi_picker {
|
|
62849
62767
|
--picker-border-radius: var(--navi-control-border-radius);
|
|
@@ -63232,7 +63150,7 @@ installImportMetaCssBuild(import.meta);const css$t = /* css */`
|
|
|
63232
63150
|
}
|
|
63233
63151
|
`;
|
|
63234
63152
|
const PickerButton = props => {
|
|
63235
|
-
import.meta.css = [css$
|
|
63153
|
+
import.meta.css = [css$u, "@jsenv/navi/src/control/picker/picker.jsx"];
|
|
63236
63154
|
if (typeof props.maxLines === "string") {
|
|
63237
63155
|
props.maxLines = parseInt(props.maxLines);
|
|
63238
63156
|
}
|
|
@@ -63681,7 +63599,7 @@ installImportMetaCssBuild(import.meta);/**
|
|
|
63681
63599
|
* refuse it on purpose, which is what keeps the focus where the travel happens
|
|
63682
63600
|
* instead of moving it into a slide that is about to leave.
|
|
63683
63601
|
*/
|
|
63684
|
-
const css$
|
|
63602
|
+
const css$t = /* css */`
|
|
63685
63603
|
@layer navi {
|
|
63686
63604
|
.navi_picker_spin {
|
|
63687
63605
|
/* A picker one steps through is still a picker: what themes every picker
|
|
@@ -64150,7 +64068,7 @@ const Spin = ({
|
|
|
64150
64068
|
nextLabel,
|
|
64151
64069
|
...rest
|
|
64152
64070
|
}) => {
|
|
64153
|
-
import.meta.css = [css$
|
|
64071
|
+
import.meta.css = [css$t, "@jsenv/navi/src/control/picker/picker_spin.jsx"];
|
|
64154
64072
|
const id = useId();
|
|
64155
64073
|
// What the group around it says, when there is one: how big the whole thing
|
|
64156
64074
|
// is written is said once, on the group, and every spin in it follows.
|
|
@@ -64686,7 +64604,7 @@ const renderValueDefault = value => String(value ?? "");
|
|
|
64686
64604
|
* are passed on to the spins sitting in them.
|
|
64687
64605
|
*/
|
|
64688
64606
|
const SpinGroup = props => {
|
|
64689
|
-
import.meta.css = [css$
|
|
64607
|
+
import.meta.css = [css$t, "@jsenv/navi/src/control/picker/picker_spin.jsx"];
|
|
64690
64608
|
const {
|
|
64691
64609
|
size
|
|
64692
64610
|
} = props;
|
|
@@ -65199,7 +65117,7 @@ const TimeRangeSpin = ({
|
|
|
65199
65117
|
};
|
|
65200
65118
|
|
|
65201
65119
|
installImportMetaCssBuild(import.meta);// TOFIX: select in data then reset, it reset to red/blue instead of red/blue/green
|
|
65202
|
-
const css$
|
|
65120
|
+
const css$s = /* css */`
|
|
65203
65121
|
.navi_checkbox_group {
|
|
65204
65122
|
border-style: solid;
|
|
65205
65123
|
|
|
@@ -65240,7 +65158,7 @@ const CheckboxGroup = props => {
|
|
|
65240
65158
|
return checkboxGroup;
|
|
65241
65159
|
};
|
|
65242
65160
|
const CheckboxGroupInterface = props => {
|
|
65243
|
-
import.meta.css = [css$
|
|
65161
|
+
import.meta.css = [css$s, "@jsenv/navi/src/control/input/checkbox_group.jsx"];
|
|
65244
65162
|
const {
|
|
65245
65163
|
ref
|
|
65246
65164
|
} = props;
|
|
@@ -65289,7 +65207,7 @@ installImportMetaCssBuild(import.meta);/**
|
|
|
65289
65207
|
* shared sheet is registered here too — a page may render a Textarea without
|
|
65290
65208
|
* any Input.
|
|
65291
65209
|
*/
|
|
65292
|
-
const css$
|
|
65210
|
+
const css$r = /* css */`
|
|
65293
65211
|
.navi_input.navi_textarea {
|
|
65294
65212
|
.navi_control_input {
|
|
65295
65213
|
min-height: calc(var(--textarea-min-rows, 1.5) * 1lh);
|
|
@@ -65376,7 +65294,7 @@ const Textarea = ({
|
|
|
65376
65294
|
width = "35ch",
|
|
65377
65295
|
...props
|
|
65378
65296
|
}) => {
|
|
65379
|
-
import.meta.css = [inputCss + css$
|
|
65297
|
+
import.meta.css = [inputCss + css$r, "@jsenv/navi/src/control/input/textarea.jsx"];
|
|
65380
65298
|
const defaultRef = useRef(null);
|
|
65381
65299
|
props.ref = props.ref || defaultRef;
|
|
65382
65300
|
usePlaceholderHeight(props.ref, props.placeholder);
|
|
@@ -65450,7 +65368,7 @@ const TextareaCharCount = ({
|
|
|
65450
65368
|
maxLength,
|
|
65451
65369
|
...rest
|
|
65452
65370
|
}) => {
|
|
65453
|
-
import.meta.css = [css$
|
|
65371
|
+
import.meta.css = [css$r, "@jsenv/navi/src/control/input/textarea.jsx"];
|
|
65454
65372
|
const resolvedValue = signal ? signal.value : value;
|
|
65455
65373
|
const length = typeof resolvedValue === "string" ? resolvedValue.length : 0;
|
|
65456
65374
|
return jsx(Box, {
|
|
@@ -65635,7 +65553,7 @@ const formatIntlUnit = (unit, {
|
|
|
65635
65553
|
}
|
|
65636
65554
|
};
|
|
65637
65555
|
|
|
65638
|
-
installImportMetaCssBuild(import.meta);const css$
|
|
65556
|
+
installImportMetaCssBuild(import.meta);const css$q = /* css */`
|
|
65639
65557
|
.navi_input_duration {
|
|
65640
65558
|
--duration-separator-spacing: 4px;
|
|
65641
65559
|
--loader-color: var(--navi-loader-color);
|
|
@@ -65702,7 +65620,7 @@ installImportMetaCssBuild(import.meta);const css$p = /* css */`
|
|
|
65702
65620
|
* "auto" aligns each field toward its neighbouring separator (first→right, last→left, middle/solo→center).
|
|
65703
65621
|
*/
|
|
65704
65622
|
const InputDuration = props => {
|
|
65705
|
-
import.meta.css = [css$
|
|
65623
|
+
import.meta.css = [css$q, "@jsenv/navi/src/control/input/input_duration.jsx"];
|
|
65706
65624
|
const defaultRef = useRef();
|
|
65707
65625
|
props.ref = props.ref || defaultRef;
|
|
65708
65626
|
props.max = props.max || "23h59";
|
|
@@ -66204,7 +66122,7 @@ const InputDurationPart = ({
|
|
|
66204
66122
|
});
|
|
66205
66123
|
};
|
|
66206
66124
|
|
|
66207
|
-
installImportMetaCssBuild(import.meta);const css$
|
|
66125
|
+
installImportMetaCssBuild(import.meta);const css$p = /* css */`
|
|
66208
66126
|
.navi_radio_group {
|
|
66209
66127
|
border-style: solid;
|
|
66210
66128
|
|
|
@@ -66224,7 +66142,7 @@ const RadioGroup = props => {
|
|
|
66224
66142
|
return radioGroup;
|
|
66225
66143
|
};
|
|
66226
66144
|
const RadioGroupInterface = props => {
|
|
66227
|
-
import.meta.css = [css$
|
|
66145
|
+
import.meta.css = [css$p, "@jsenv/navi/src/control/input/radio_group.jsx"];
|
|
66228
66146
|
const {
|
|
66229
66147
|
ref
|
|
66230
66148
|
} = props;
|
|
@@ -66282,7 +66200,7 @@ installImportMetaCssBuild(import.meta);/**
|
|
|
66282
66200
|
* control is drawn — the list it opens stays the platform's own, which is the
|
|
66283
66201
|
* whole point of using a select.
|
|
66284
66202
|
*/
|
|
66285
|
-
const css$
|
|
66203
|
+
const css$o = /* css */`
|
|
66286
66204
|
.navi_input.navi_select {
|
|
66287
66205
|
.navi_control_input {
|
|
66288
66206
|
/* Room for the chevron, which sits over the padding rather than beside
|
|
@@ -66337,7 +66255,7 @@ const Select = ({
|
|
|
66337
66255
|
multiple,
|
|
66338
66256
|
...props
|
|
66339
66257
|
}) => {
|
|
66340
|
-
import.meta.css = [inputCss + css$
|
|
66258
|
+
import.meta.css = [inputCss + css$o, "@jsenv/navi/src/control/input/select.jsx"];
|
|
66341
66259
|
const defaultRef = useRef(null);
|
|
66342
66260
|
props.ref = props.ref || defaultRef;
|
|
66343
66261
|
seedDefaultValueFromSignal(props);
|
|
@@ -66405,7 +66323,7 @@ installImportMetaCssBuild(import.meta);/**
|
|
|
66405
66323
|
* running: one loading outline around both, which is why each half is told
|
|
66406
66324
|
* `loadingOutline={false}`.
|
|
66407
66325
|
*/
|
|
66408
|
-
const css$
|
|
66326
|
+
const css$n = /* css */`
|
|
66409
66327
|
/* Around the pair rather than in it: the outline is drawn against this
|
|
66410
66328
|
element and follows its corners, and a Group counts its own children to
|
|
66411
66329
|
know which corners to square — an outline among them would be one of the
|
|
@@ -66517,7 +66435,7 @@ const css$m = /* css */`
|
|
|
66517
66435
|
* Anything else lands on the split button's own box.
|
|
66518
66436
|
*/
|
|
66519
66437
|
const SplitButton = props => {
|
|
66520
|
-
import.meta.css = [css$
|
|
66438
|
+
import.meta.css = [css$n, "@jsenv/navi/src/control/input/split_button.jsx"];
|
|
66521
66439
|
const {
|
|
66522
66440
|
options = [],
|
|
66523
66441
|
value,
|
|
@@ -67168,7 +67086,7 @@ installImportMetaCssBuild(import.meta);/*
|
|
|
67168
67086
|
* accessors (top/height vs left/width) chosen from `horizontal`, and the CSS has
|
|
67169
67087
|
* a [data-horizontal] variant.
|
|
67170
67088
|
*/
|
|
67171
|
-
const css$
|
|
67089
|
+
const css$m = /* css */`
|
|
67172
67090
|
.navi_wheel_container {
|
|
67173
67091
|
/* Row size and emphasis band are read together: the band is what a value
|
|
67174
67092
|
must cross to lose its emphasis, and the row is how far it has to travel
|
|
@@ -68290,7 +68208,7 @@ const useWheelKeyboard = ({
|
|
|
68290
68208
|
}, [isHorizontal, interactive, isLoop]);
|
|
68291
68209
|
};
|
|
68292
68210
|
function WheelUI(props) {
|
|
68293
|
-
import.meta.css = [css$
|
|
68211
|
+
import.meta.css = [css$m, "@jsenv/navi/src/control/wheel/wheel.jsx"];
|
|
68294
68212
|
const {
|
|
68295
68213
|
ref,
|
|
68296
68214
|
visibleCount = 3,
|
|
@@ -68691,6 +68609,16 @@ function WheelUI(props) {
|
|
|
68691
68609
|
// uiAction; here we fire the action explicitly, once, on the settled value.
|
|
68692
68610
|
const input = inputRef.current;
|
|
68693
68611
|
if (input) {
|
|
68612
|
+
// Said out loud too, OUTSIDE the action pipeline: the action above goes
|
|
68613
|
+
// through the gates (validity included), and what listens to a settle
|
|
68614
|
+
// may be exactly the thing that RESTORES validity — a range's other
|
|
68615
|
+
// bound giving way (see TimeRangeWheel) cannot wait on a gate that
|
|
68616
|
+
// refuses invalid values. Bubbles, so a group holding this wheel hears
|
|
68617
|
+
// it without knowing where the wheel sits.
|
|
68618
|
+
dispatchPublicCustomEvent(input, "navi_wheel_settle", {
|
|
68619
|
+
value: trackedItemsRef.current[index].value,
|
|
68620
|
+
event: settleEvent
|
|
68621
|
+
});
|
|
68694
68622
|
dispatchRequestAction(input, {
|
|
68695
68623
|
event: settleEvent
|
|
68696
68624
|
});
|
|
@@ -69199,7 +69127,7 @@ Wheel.Item = WheelItem;
|
|
|
69199
69127
|
* @param {boolean} [props.zoom] - Enlarge the centered value of every wheel (see Wheel's zoom prop) with one prop for the whole group.
|
|
69200
69128
|
*/
|
|
69201
69129
|
const WheelGroup = props => {
|
|
69202
|
-
import.meta.css = [css$
|
|
69130
|
+
import.meta.css = [css$m, "@jsenv/navi/src/control/wheel/wheel.jsx"];
|
|
69203
69131
|
// WheelGroup IS a control group: it aggregates its named wheels ("hours",
|
|
69204
69132
|
// "minutes"…) into one object value, so it can sit directly inside a Form or a
|
|
69205
69133
|
// Picker with no extra <ControlGroup> wrapper. The wheel-specific presentation
|
|
@@ -69230,7 +69158,11 @@ const WheelGroup = props => {
|
|
|
69230
69158
|
const [controlgroupRootProps, controlgroupProps, childrenWrapperProps] = useControlgroupProps(props, {
|
|
69231
69159
|
allowCapture: true,
|
|
69232
69160
|
wantRequesterButtonState: true,
|
|
69233
|
-
|
|
69161
|
+
// Its own type, not the generic "control_group": the group IS one
|
|
69162
|
+
// control made of parts, and a wheel settling runs the group's own
|
|
69163
|
+
// action — the way a radio checking runs its group's (the auto group
|
|
69164
|
+
// action in control_hooks keys on this type).
|
|
69165
|
+
controlType: "wheel_group",
|
|
69234
69166
|
stateType: "object",
|
|
69235
69167
|
cascadeValidationToChildren: true,
|
|
69236
69168
|
aggregateChildStates: props.aggregateChildStates,
|
|
@@ -69365,7 +69297,7 @@ const WheelColon = props => {
|
|
|
69365
69297
|
};
|
|
69366
69298
|
Wheel.Colon = WheelColon;
|
|
69367
69299
|
|
|
69368
|
-
|
|
69300
|
+
installImportMetaCssBuild(import.meta);/**
|
|
69369
69301
|
* A time of day, and a span between two of them, set by turning rather than by
|
|
69370
69302
|
* typing. A wheel only ever shows values that exist: there is no half-written
|
|
69371
69303
|
* hour to bound and correct under the fingers, which is what a time typed digit
|
|
@@ -69375,11 +69307,33 @@ Wheel.Colon = WheelColon;
|
|
|
69375
69307
|
* like `TimeSpin` — the two are interchangeable in a form. `TimeRangeWheel` is
|
|
69376
69308
|
* two of those and carries `{ start, end }`, with the rule such a pair always
|
|
69377
69309
|
* has: the end comes after the start. Here that rule is lived rather than
|
|
69378
|
-
* checked —
|
|
69379
|
-
* is always a span. The send-time constraint stays
|
|
69380
|
-
* cannot fix (a start so late the span no longer
|
|
69310
|
+
* checked — a bound settling pushes the other out of its way, so what the
|
|
69311
|
+
* wheels show at rest is always a span. The send-time constraint stays
|
|
69312
|
+
* underneath for what pushing cannot fix (a start so late the span no longer
|
|
69313
|
+
* fits in the day).
|
|
69381
69314
|
*/
|
|
69315
|
+
const css$l = /* css */`
|
|
69316
|
+
/* The words around a span's wheels ("De", "à"): one line box, the height
|
|
69317
|
+
of a wheel row (--wheel-item-height re-exposed, same value as
|
|
69318
|
+
.navi_wheel_container), centered against the wheels by the group. The
|
|
69319
|
+
box's strut — this element's own font — is what places the baseline,
|
|
69320
|
+
exactly where a wheel row places its numbers'; and because the content
|
|
69321
|
+
stays in inline flow, anything written INSIDE at another size still
|
|
69322
|
+
sits on that same baseline. Two things this depends on: the label is a
|
|
69323
|
+
<Text size={size}> so its em — and therefore this line-height — is the
|
|
69324
|
+
SAME em as the wheel rows' (a label left at the control font under
|
|
69325
|
+
bigger wheels computes a shorter row and its baseline drifts); and no
|
|
69326
|
+
flex centering of the content (centering re-centers a smaller glyph,
|
|
69327
|
+
baselines are not centers). */
|
|
69328
|
+
.navi_time_range_label {
|
|
69329
|
+
--wheel-item-height: round(1.8em, 1px);
|
|
69382
69330
|
|
|
69331
|
+
color: var(--wheel-color, light-dark(#111, #eee));
|
|
69332
|
+
line-height: var(--wheel-item-height);
|
|
69333
|
+
white-space: nowrap;
|
|
69334
|
+
user-select: none;
|
|
69335
|
+
}
|
|
69336
|
+
`;
|
|
69383
69337
|
const HOUR_COUNT = 24;
|
|
69384
69338
|
const MINUTES_PER_HOUR = 60;
|
|
69385
69339
|
const LAST_MINUTE_OF_DAY = 23 * 60 + 59;
|
|
@@ -69538,6 +69492,7 @@ const TimeRangeWheel = ({
|
|
|
69538
69492
|
endTimeProps,
|
|
69539
69493
|
...rest
|
|
69540
69494
|
}) => {
|
|
69495
|
+
import.meta.css = [css$l, "@jsenv/navi/src/control/wheel/wheel_time.jsx"];
|
|
69541
69496
|
const startId = useId();
|
|
69542
69497
|
const startRef = useRef(null);
|
|
69543
69498
|
const endRef = useRef(null);
|
|
@@ -69549,10 +69504,15 @@ const TimeRangeWheel = ({
|
|
|
69549
69504
|
distributeChildUIState
|
|
69550
69505
|
} = useAnswered(placeholder, rest, aggregateSpan, distributeSpan);
|
|
69551
69506
|
|
|
69552
|
-
// What the pair does
|
|
69553
|
-
//
|
|
69554
|
-
//
|
|
69555
|
-
//
|
|
69507
|
+
// What the pair does once a bound SETTLES: the one that was moved stays
|
|
69508
|
+
// where it was put and the OTHER one gives way — a refusal at that point
|
|
69509
|
+
// would leave the person to undo what they just did. Settles, not while it
|
|
69510
|
+
// turns: a wheel under the finger holds a value nobody has chosen yet, and
|
|
69511
|
+
// the other bound jumping around mid-gesture answers a question that was
|
|
69512
|
+
// not asked. Wired on the wheel's settle EVENT (navi_wheel_settle), never
|
|
69513
|
+
// on `action`: an action goes through the gates, validity included, and
|
|
69514
|
+
// the moment this must run is precisely the moment the pair is INVALID —
|
|
69515
|
+
// an action-gated push would be refused by the very thing it fixes.
|
|
69556
69516
|
const keepBoundsApart = (movedSide, movedTime, e) => {
|
|
69557
69517
|
const movedMinutes = minutesFromTime(movedTime);
|
|
69558
69518
|
if (movedMinutes === null) {
|
|
@@ -69596,6 +69556,7 @@ const TimeRangeWheel = ({
|
|
|
69596
69556
|
value: answeredRef,
|
|
69597
69557
|
children: [startLabel === null ? null : jsx(Text, {
|
|
69598
69558
|
size: size,
|
|
69559
|
+
className: "navi_time_range_label",
|
|
69599
69560
|
children: startLabel
|
|
69600
69561
|
}), jsx(TimeWheel, {
|
|
69601
69562
|
id: startId,
|
|
@@ -69605,12 +69566,20 @@ const TimeRangeWheel = ({
|
|
|
69605
69566
|
hours: hours,
|
|
69606
69567
|
loop: loop,
|
|
69607
69568
|
size: size,
|
|
69608
|
-
placeholder: placeholder ? placeholder.start : undefined
|
|
69609
|
-
|
|
69569
|
+
placeholder: placeholder ? placeholder.start : undefined
|
|
69570
|
+
// e.detail.value is the settled WHEEL's own value (an hour, a
|
|
69571
|
+
// minute) — half a time. What the pair compares is this bound's
|
|
69572
|
+
// whole time, read off the element the listener sits on.
|
|
69573
|
+
,
|
|
69574
|
+
|
|
69575
|
+
onnavi_wheel_settle: e => {
|
|
69576
|
+
keepBoundsApart("start", getUIStateFromElement(e.currentTarget), e);
|
|
69577
|
+
},
|
|
69610
69578
|
...timeProps,
|
|
69611
69579
|
...startTimeProps
|
|
69612
69580
|
}), endLabel === null ? null : jsx(Text, {
|
|
69613
69581
|
size: size,
|
|
69582
|
+
className: "navi_time_range_label",
|
|
69614
69583
|
children: endLabel
|
|
69615
69584
|
}), jsx(TimeWheel, {
|
|
69616
69585
|
ref: endRef,
|
|
@@ -69620,11 +69589,14 @@ const TimeRangeWheel = ({
|
|
|
69620
69589
|
loop: loop,
|
|
69621
69590
|
size: size,
|
|
69622
69591
|
placeholder: placeholder ? placeholder.end : undefined,
|
|
69623
|
-
|
|
69592
|
+
onnavi_wheel_settle: e => {
|
|
69593
|
+
keepBoundsApart("end", getUIStateFromElement(e.currentTarget), e);
|
|
69594
|
+
}
|
|
69624
69595
|
// Which time it comes after, and how much room there must be between
|
|
69625
69596
|
// the two: said on the LATER of the two, so the answer is given where
|
|
69626
69597
|
// the time one would have to move is (see time_range_constraint.js).
|
|
69627
69598
|
,
|
|
69599
|
+
|
|
69628
69600
|
"data-time-after": startId,
|
|
69629
69601
|
"data-time-min-duration": minDuration,
|
|
69630
69602
|
...timeProps,
|
|
@@ -75257,18 +75229,34 @@ installImportMetaCssBuild(import.meta);/**
|
|
|
75257
75229
|
* Two distinct facts, drawn separately — they usually agree, and everything
|
|
75258
75230
|
* this component says comes from the moments they do not:
|
|
75259
75231
|
*
|
|
75260
|
-
* - the PATH (
|
|
75261
|
-
*
|
|
75262
|
-
*
|
|
75263
|
-
*
|
|
75232
|
+
* - DONE and the PATH (the blue fill). The mental model, to keep in mind
|
|
75233
|
+
* when touching any of this: the circles are THINGS TO DO, and the path is
|
|
75234
|
+
* the progression along the linear walk from the first to the last — a
|
|
75235
|
+
* thing done is what lets the path advance. Answering a step fills its
|
|
75236
|
+
* dot AND the line onward, up to the NEXT dot: the invitation to go
|
|
75237
|
+
* there. If that next step is already done the path crosses it from
|
|
75238
|
+
* behind and carries on, and so forth — the fill covers the answered
|
|
75239
|
+
* prefix plus one segment of appetite. It stops at the edge of the first
|
|
75240
|
+
* dot not answered, which stays empty: the fill's one meaning is
|
|
75241
|
+
* "answered", and the first dot is NOT filled on arrival — it becomes so
|
|
75242
|
+
* by being answered. Past the fill the line is dashed, the road not
|
|
75243
|
+
* walked yet; steps answered out of order are filled dots standing alone,
|
|
75244
|
+
* dashed segments around them: the holes, readable at a glance.
|
|
75264
75245
|
* - the POSITION (`current`): the step being looked at, marked by a halo
|
|
75265
|
-
* around its dot and its label emphasized. It travels freely, so it can
|
|
75266
|
-
* AHEAD of the path
|
|
75267
|
-
* or BEHIND it (back on step 1 to change something already answered).
|
|
75246
|
+
* around its dot and its label emphasized. It travels freely, so it can
|
|
75247
|
+
* be AHEAD of the path or BEHIND it.
|
|
75268
75248
|
*
|
|
75269
75249
|
* Both move smoothly on change (a CSS transition each), so pressing a step
|
|
75270
75250
|
* or answering one is seen travelling rather than jumping.
|
|
75271
75251
|
*
|
|
75252
|
+
* The steps are the CHILDREN — <StepList.Item value="club">Club</StepList.Item>.
|
|
75253
|
+
* An Item renders nothing: it REGISTERS with the list as it renders (order
|
|
75254
|
+
* of rendering is the order of the steps), and the list draws everything —
|
|
75255
|
+
* which is what lets an Item come from anywhere: a .map(), a fragment, a
|
|
75256
|
+
* component of your own wrapping it. One caveat comes with reading the
|
|
75257
|
+
* children as they render: hand the list fresh Item vnodes on each render
|
|
75258
|
+
* (the usual JSX), not a memoized array a bailout would keep from rendering.
|
|
75259
|
+
*
|
|
75272
75260
|
* The dots are drawn in SVG, twice: a muted layer, and a filled layer
|
|
75273
75261
|
* clipped at the path's edge — the clip is what makes the path's progress a
|
|
75274
75262
|
* single sweep that fills the line and the dots it crosses in one movement.
|
|
@@ -75277,28 +75265,21 @@ installImportMetaCssBuild(import.meta);/**
|
|
|
75277
75265
|
* surface. Colors are CSS custom properties (see the css below), overridden
|
|
75278
75266
|
* from outside for a dark band or a different accent.
|
|
75279
75267
|
*
|
|
75280
|
-
* The steps are the CHILDREN — <StepList.Item value="club">Club</StepList.Item>
|
|
75281
|
-
* — read off the vnodes (toChildArray, so a .map() or a fragment is fine; a
|
|
75282
|
-
* component of your own wrapping an Item is not seen). The Item renders its
|
|
75283
|
-
* label; everything positional is this component's business.
|
|
75284
|
-
*
|
|
75285
75268
|
* `slideContainer` connects the list to a <SlideContainer> by id, both ways:
|
|
75286
75269
|
* pressing a step travels there (--navi-go-to-slide), and the position is
|
|
75287
75270
|
* READ off the container rather than said by a prop — including mid-travel:
|
|
75288
75271
|
* the container paints --slide-travel-progress on this element (it is a
|
|
75289
75272
|
* follower, same mechanism as <Nav slideContainer>), so the halo rides the
|
|
75290
|
-
* drag under the finger, in CSS alone. The path
|
|
75291
|
-
*
|
|
75292
|
-
* ahead of the answers): dragging towards a step whose way is earned fills
|
|
75293
|
-
* the line under the finger, dragging past the answers does not.
|
|
75273
|
+
* drag under the finger, in CSS alone. The path is not concerned: it moves
|
|
75274
|
+
* on answers, never on movement.
|
|
75294
75275
|
*/
|
|
75295
75276
|
const css$2 = /* css */`
|
|
75296
75277
|
.navi_step_list {
|
|
75297
|
-
/* The knobs: accent
|
|
75298
|
-
|
|
75299
|
-
|
|
75300
|
-
|
|
75301
|
-
|
|
75278
|
+
/* The knobs: one accent for everything filled — the dots and the line
|
|
75279
|
+
share it, because the fill has ONE meaning (answered) and a meaning
|
|
75280
|
+
does not change color. Muted is what is not answered, on-accent
|
|
75281
|
+
writes on filled dots. Said from OUTSIDE (any ancestor — a dark band,
|
|
75282
|
+
a themed app) on the plain names; resolved here through an
|
|
75302
75283
|
indirection (--x-…, the way Button does), because a default written
|
|
75303
75284
|
on the plain name on this very element would beat anything an
|
|
75304
75285
|
ancestor says. */
|
|
@@ -75313,10 +75294,9 @@ const css$2 = /* css */`
|
|
|
75313
75294
|
--step-list-current-color,
|
|
75314
75295
|
light-dark(#1c2433, white)
|
|
75315
75296
|
);
|
|
75316
|
-
|
|
75317
|
-
|
|
75318
|
-
|
|
75319
|
-
);
|
|
75297
|
+
/* How long a movement takes — the path sweeping, the halo sliding. One
|
|
75298
|
+
number for all of them: they tell one story. */
|
|
75299
|
+
--x-step-list-duration: var(--step-list-duration, 300ms);
|
|
75320
75300
|
|
|
75321
75301
|
position: relative;
|
|
75322
75302
|
display: block;
|
|
@@ -75354,14 +75334,26 @@ const css$2 = /* css */`
|
|
|
75354
75334
|
.navi_step_list_rail g[data-current] text {
|
|
75355
75335
|
fill: var(--x-step-list-current-color);
|
|
75356
75336
|
}
|
|
75357
|
-
/*
|
|
75358
|
-
|
|
75359
|
-
|
|
75337
|
+
/* A step answered has its dot filled, wherever the path stands: answered
|
|
75338
|
+
out of order it stands alone, a filled dot between dashed segments.
|
|
75339
|
+
After the current rule on purpose: answered wins the drawing, the halo
|
|
75340
|
+
says current. */
|
|
75341
|
+
.navi_step_list_rail g[data-done] circle {
|
|
75342
|
+
fill: var(--x-step-list-accent);
|
|
75343
|
+
stroke: var(--x-step-list-accent);
|
|
75344
|
+
}
|
|
75345
|
+
.navi_step_list_rail g[data-done] text {
|
|
75346
|
+
fill: var(--x-step-list-on-accent);
|
|
75347
|
+
}
|
|
75348
|
+
/* The path: same drawing, filled, revealed up to the fill's edge — the
|
|
75349
|
+
answered prefix plus its segment of appetite (see the top comment). The
|
|
75350
|
+
clip is set inline (a width in px); transitioning it is what makes an
|
|
75351
|
+
answered step SWEEP its dot and the line onward rather than pop. */
|
|
75360
75352
|
.navi_step_list_rail_filled {
|
|
75361
|
-
transition: clip-path
|
|
75353
|
+
transition: clip-path var(--x-step-list-duration) ease;
|
|
75362
75354
|
}
|
|
75363
75355
|
.navi_step_list_rail_filled line {
|
|
75364
|
-
stroke: var(--x-step-list-
|
|
75356
|
+
stroke: var(--x-step-list-accent);
|
|
75365
75357
|
stroke-dasharray: none;
|
|
75366
75358
|
}
|
|
75367
75359
|
.navi_step_list_rail_filled circle {
|
|
@@ -75375,7 +75367,7 @@ const css$2 = /* css */`
|
|
|
75375
75367
|
to dot (transform, transitioned) — the g moves, the circle inside is
|
|
75376
75368
|
drawn at x=0. */
|
|
75377
75369
|
.navi_step_list_marker {
|
|
75378
|
-
transition: transform
|
|
75370
|
+
transition: transform var(--x-step-list-duration) ease;
|
|
75379
75371
|
}
|
|
75380
75372
|
.navi_step_list_marker circle {
|
|
75381
75373
|
fill: none;
|
|
@@ -75387,8 +75379,7 @@ const css$2 = /* css */`
|
|
|
75387
75379
|
container paints --slide-travel-progress here (this element follows it,
|
|
75388
75380
|
see data-slide-container-follows) — an asked-for travel animates it, a
|
|
75389
75381
|
finger drags it — and everything below is a calc() of that number, so
|
|
75390
|
-
the halo and the path move per frame in CSS alone.
|
|
75391
|
-
off: they would chase a finger that is already the pace.
|
|
75382
|
+
the halo and the path move per frame in CSS alone.
|
|
75392
75383
|
Position, in dots-x px: where the picture is right now. */
|
|
75393
75384
|
.navi_step_list[data-slide-container-follows] {
|
|
75394
75385
|
--step-list-position: calc(
|
|
@@ -75400,36 +75391,11 @@ const css$2 = /* css */`
|
|
|
75400
75391
|
transform: translateX(calc(var(--step-list-position) * 1px));
|
|
75401
75392
|
transition: none;
|
|
75402
75393
|
}
|
|
75403
|
-
/* The path follows the position, clamped: never back below what was
|
|
75404
|
-
earned (--step-list-reached-x), never ahead of what the answers allow
|
|
75405
|
-
(--step-list-reachable-x). The +14 covers the dot it stands on (radius
|
|
75406
|
-
plus stroke). */
|
|
75407
|
-
.navi_step_list[data-slide-container-follows] .navi_step_list_rail_filled {
|
|
75408
|
-
clip-path: inset(
|
|
75409
|
-
0
|
|
75410
|
-
calc(
|
|
75411
|
-
(
|
|
75412
|
-
var(--step-list-w, 0) -
|
|
75413
|
-
(
|
|
75414
|
-
clamp(
|
|
75415
|
-
var(--step-list-reached-x, -9999),
|
|
75416
|
-
var(--step-list-position),
|
|
75417
|
-
var(--step-list-reachable-x, -9999)
|
|
75418
|
-
) +
|
|
75419
|
-
14
|
|
75420
|
-
)
|
|
75421
|
-
) *
|
|
75422
|
-
1px
|
|
75423
|
-
)
|
|
75424
|
-
0 0
|
|
75425
|
-
);
|
|
75426
|
-
transition: none;
|
|
75427
|
-
}
|
|
75428
75394
|
|
|
75429
75395
|
/* One press target per step, covering the dot AND the label under it. The
|
|
75430
75396
|
feedback is NOT the whole surface: a rectangle would say the whole band
|
|
75431
75397
|
is a button, when the affordance is the dot — so hover and focus land on
|
|
75432
|
-
a circle drawn over the dot
|
|
75398
|
+
a circle drawn over the dot, plus the label brightening.
|
|
75433
75399
|
--step-dot-x anchors both on the dot, wherever the dot sits in the slot:
|
|
75434
75400
|
the first and last slots are asymmetric (cut at the container's edge,
|
|
75435
75401
|
see the geometry in the component). */
|
|
@@ -75454,13 +75420,15 @@ const css$2 = /* css */`
|
|
|
75454
75420
|
--button-color-readonly: var(--x-step-list-muted);
|
|
75455
75421
|
/* The button's own focus ring, silenced: it would outline the whole
|
|
75456
75422
|
press surface, and the ring this list draws is the one around the dot
|
|
75457
|
-
(see
|
|
75458
|
-
|
|
75423
|
+
(see below) — two rings read as a mistake. Width rather than style,
|
|
75424
|
+
because the dot sets its own style in full. */
|
|
75459
75425
|
--button-outline-width: 0px;
|
|
75460
75426
|
}
|
|
75461
75427
|
/* Centered on the dot: same vertical middle as the rail (top 0, height 34,
|
|
75462
|
-
cy 17).
|
|
75463
|
-
|
|
75428
|
+
cy 17). A real element rather than a ::before, because it is also what a
|
|
75429
|
+
callout anchors to (data-callout-anchor needs a selector) — a message
|
|
75430
|
+
about a step points at its CIRCLE, not at the press surface. */
|
|
75431
|
+
.navi_step_list_dot {
|
|
75464
75432
|
position: absolute;
|
|
75465
75433
|
top: 17px;
|
|
75466
75434
|
left: var(--step-dot-x);
|
|
@@ -75468,18 +75436,18 @@ const css$2 = /* css */`
|
|
|
75468
75436
|
height: 30px;
|
|
75469
75437
|
border-radius: 50%;
|
|
75470
75438
|
translate: -50% -50%;
|
|
75471
|
-
|
|
75439
|
+
pointer-events: none;
|
|
75472
75440
|
}
|
|
75473
|
-
.navi_step_list_step:hover
|
|
75474
|
-
.navi_step_list_step[data-hover]
|
|
75441
|
+
.navi_step_list_step:hover .navi_step_list_dot,
|
|
75442
|
+
.navi_step_list_step[data-hover] .navi_step_list_dot {
|
|
75475
75443
|
background: color-mix(in srgb, var(--x-step-list-accent) 15%, transparent);
|
|
75476
75444
|
}
|
|
75477
75445
|
.navi_step_list .navi_step_list_step:hover,
|
|
75478
75446
|
.navi_step_list .navi_step_list_step[data-hover] {
|
|
75479
75447
|
--button-color: var(--x-step-list-current-color);
|
|
75480
75448
|
}
|
|
75481
|
-
.navi_step_list_step:focus-visible
|
|
75482
|
-
.navi_step_list_step[data-focus-visible]
|
|
75449
|
+
.navi_step_list_step:focus-visible .navi_step_list_dot,
|
|
75450
|
+
.navi_step_list_step[data-focus-visible] .navi_step_list_dot {
|
|
75483
75451
|
outline-width: var(--navi-focus-outline-width);
|
|
75484
75452
|
outline-style: solid;
|
|
75485
75453
|
outline-color: var(--navi-focus-outline-color);
|
|
@@ -75507,28 +75475,24 @@ const EDGE_INSET = 30;
|
|
|
75507
75475
|
// halo of a current dot not to sit on the line.
|
|
75508
75476
|
const LINE_GAP = 5;
|
|
75509
75477
|
|
|
75478
|
+
// What the Items say to the list holding them (see Step): where to write
|
|
75479
|
+
// themselves down. Null outside any list — a Step alone renders nothing and
|
|
75480
|
+
// registers nowhere.
|
|
75481
|
+
const StepListContext = createContext(null);
|
|
75482
|
+
|
|
75510
75483
|
/**
|
|
75511
75484
|
* @type {import("ignore:preact").FunctionComponent<{
|
|
75512
75485
|
* current?: string,
|
|
75513
|
-
* reached?: string,
|
|
75514
|
-
* reachable?: string,
|
|
75515
75486
|
* slideContainer?: string,
|
|
75516
75487
|
* travelByClick?: boolean,
|
|
75517
75488
|
* travelByKeyboard?: boolean,
|
|
75489
|
+
* duration?: string,
|
|
75518
75490
|
* [key: string]: any,
|
|
75519
75491
|
* }>}
|
|
75520
75492
|
* @param {string} [current] - the step being looked at: its dot gets the
|
|
75521
75493
|
* halo, its label the emphasis. Omit for "nowhere" — a confirmation
|
|
75522
75494
|
* screen after the walk, say. With `slideContainer` the position is read
|
|
75523
75495
|
* off the container instead, and this prop is ignored.
|
|
75524
|
-
* @param {string} [reached] - the step the path has come to: the line is
|
|
75525
|
-
* solid and the dots filled up to it, dashed past it. Omit for a path
|
|
75526
|
-
* that has not started.
|
|
75527
|
-
* @param {string} [reachable] - how far the path MAY go (with
|
|
75528
|
-
* `slideContainer` only): between `reached` and this step the path
|
|
75529
|
-
* follows the position — a drag towards a step whose way is earned fills
|
|
75530
|
-
* the line under the finger. Defaults to `reached`: the path then never
|
|
75531
|
-
* moves with the position at all.
|
|
75532
75496
|
* @param {string} [slideContainer] - id of a <SlideContainer> these steps
|
|
75533
75497
|
* are the slides of. Pressing a step travels there
|
|
75534
75498
|
* (--navi-go-to-slide), the halo follows the container — drags included —
|
|
@@ -75545,14 +75509,16 @@ const LINE_GAP = 5;
|
|
|
75545
75509
|
* CONTAINER — this element is a follower, so a press here already walks
|
|
75546
75510
|
* the slides, and the container's own `travelByKeyboard` is the one that
|
|
75547
75511
|
* says so. One owner per mode, or one arrow would do both.
|
|
75512
|
+
* @param {string} [duration] - how long a movement takes (the path
|
|
75513
|
+
* sweeping, the halo sliding), any CSS duration. 300ms unless said —
|
|
75514
|
+
* here, or from outside via --step-list-duration.
|
|
75548
75515
|
*/
|
|
75549
75516
|
const StepList = ({
|
|
75550
75517
|
current,
|
|
75551
|
-
reached,
|
|
75552
|
-
reachable,
|
|
75553
75518
|
slideContainer,
|
|
75554
75519
|
travelByClick = true,
|
|
75555
75520
|
travelByKeyboard = true,
|
|
75521
|
+
duration,
|
|
75556
75522
|
children,
|
|
75557
75523
|
...rest
|
|
75558
75524
|
}) => {
|
|
@@ -75584,11 +75550,33 @@ const StepList = ({
|
|
|
75584
75550
|
direction: "x"
|
|
75585
75551
|
});
|
|
75586
75552
|
|
|
75587
|
-
// The
|
|
75588
|
-
//
|
|
75589
|
-
|
|
75590
|
-
|
|
75591
|
-
|
|
75553
|
+
// The roll call: every render of this list opens a fresh page, the Items
|
|
75554
|
+
// rendering below write themselves on it (in rendering order, which is the
|
|
75555
|
+
// order of the steps), and the layout effect reads the page back. What was
|
|
75556
|
+
// read is STATE — the first render knows no steps, the effect's render
|
|
75557
|
+
// draws them — and a change in what the Items say (a done toggled) flows
|
|
75558
|
+
// the same way: fresh page, fresh read, redraw.
|
|
75559
|
+
const registryRef = useRef(null);
|
|
75560
|
+
if (!registryRef.current) {
|
|
75561
|
+
registryRef.current = {
|
|
75562
|
+
renderedSteps: []
|
|
75563
|
+
};
|
|
75564
|
+
}
|
|
75565
|
+
const registry = registryRef.current;
|
|
75566
|
+
registry.renderedSteps = [];
|
|
75567
|
+
const [steps, setSteps] = useState([]);
|
|
75568
|
+
useLayoutEffect(() => {
|
|
75569
|
+
const collected = registry.renderedSteps;
|
|
75570
|
+
// An empty page while steps are known: the children were most likely
|
|
75571
|
+
// bailed out of rendering (memoized vnodes), not removed — keeping the
|
|
75572
|
+
// known steps beats erasing the drawing (see the caveat in the top
|
|
75573
|
+
// comment).
|
|
75574
|
+
if (collected.length === 0 && steps.length > 0) {
|
|
75575
|
+
return;
|
|
75576
|
+
}
|
|
75577
|
+
setSteps(previous => sameSteps(previous, collected) ? previous : [...collected]);
|
|
75578
|
+
});
|
|
75579
|
+
const stepCount = steps.length;
|
|
75592
75580
|
const dotXs = [];
|
|
75593
75581
|
if (width > 0 && stepCount > 0) {
|
|
75594
75582
|
const span = width - EDGE_INSET * 2;
|
|
@@ -75598,7 +75586,7 @@ const StepList = ({
|
|
|
75598
75586
|
index++;
|
|
75599
75587
|
}
|
|
75600
75588
|
}
|
|
75601
|
-
const indexOf = value =>
|
|
75589
|
+
const indexOf = value => steps.findIndex(step => step.value === value);
|
|
75602
75590
|
|
|
75603
75591
|
// Where the slides are, read off the container: which slide is current,
|
|
75604
75592
|
// and — while a travel or a drag is playing — which one the picture leans
|
|
@@ -75656,19 +75644,31 @@ const StepList = ({
|
|
|
75656
75644
|
}, [slideContainer, width, stepCount]);
|
|
75657
75645
|
const resolvedCurrent = slideContainer ? containerCurrent : current;
|
|
75658
75646
|
const currentIndex = resolvedCurrent === undefined ? -1 : indexOf(resolvedCurrent);
|
|
75659
|
-
|
|
75660
|
-
|
|
75661
|
-
|
|
75662
|
-
|
|
75663
|
-
|
|
75664
|
-
|
|
75665
|
-
|
|
75666
|
-
|
|
75647
|
+
// The path, deduced from what the Items say: the steps answered without a
|
|
75648
|
+
// gap from the start. -1 when the first step is not answered yet — there
|
|
75649
|
+
// is no path then, only dots.
|
|
75650
|
+
let pathEndIndex = steps.findIndex(step => !step.done);
|
|
75651
|
+
if (pathEndIndex === -1) {
|
|
75652
|
+
pathEndIndex = stepCount;
|
|
75653
|
+
}
|
|
75654
|
+
pathEndIndex -= 1;
|
|
75655
|
+
// How far the fill goes: nowhere while nothing is answered; past the last
|
|
75656
|
+
// dot (radius plus stroke) when everything is; otherwise THROUGH the
|
|
75657
|
+
// answered prefix and onward to the edge of the next dot — the segment of
|
|
75658
|
+
// appetite (see the top comment), with the dot it points at left empty.
|
|
75659
|
+
let fillX;
|
|
75660
|
+
if (pathEndIndex === -1) {
|
|
75661
|
+
fillX = 0;
|
|
75662
|
+
} else if (pathEndIndex >= stepCount - 1) {
|
|
75663
|
+
fillX = dotXs[stepCount - 1] + DOT_R + 3;
|
|
75664
|
+
} else {
|
|
75665
|
+
fillX = dotXs[pathEndIndex + 1] - DOT_R - LINE_GAP;
|
|
75666
|
+
}
|
|
75667
75667
|
const cy = RAIL_H / 2;
|
|
75668
75668
|
const slotWidth = dotXs.length > 1 ? dotXs[1] - dotXs[0] : width;
|
|
75669
75669
|
const renderRail = filled => jsx("svg", {
|
|
75670
75670
|
className: filled ? "navi_step_list_rail navi_step_list_rail_filled" : "navi_step_list_rail",
|
|
75671
|
-
style: filled
|
|
75671
|
+
style: filled ? {
|
|
75672
75672
|
clipPath: `inset(0 ${width - fillX}px 0 0)`
|
|
75673
75673
|
} : undefined,
|
|
75674
75674
|
width: width,
|
|
@@ -75676,9 +75676,10 @@ const StepList = ({
|
|
|
75676
75676
|
viewBox: `0 0 ${width} ${RAIL_H}`,
|
|
75677
75677
|
"aria-hidden": "true",
|
|
75678
75678
|
children: dotXs.map((x, index) => jsxs("g", {
|
|
75679
|
-
// Base layer only:
|
|
75680
|
-
//
|
|
75679
|
+
// Base layer only: dots the path covers are drawn filled by the
|
|
75680
|
+
// layer above anyway (see the css).
|
|
75681
75681
|
"data-current": !filled && index === currentIndex ? "" : undefined,
|
|
75682
|
+
"data-done": !filled && steps[index].done ? "" : undefined,
|
|
75682
75683
|
children: [index > 0 ? jsx("line", {
|
|
75683
75684
|
x1: dotXs[index - 1] + DOT_R + LINE_GAP,
|
|
75684
75685
|
y1: cy,
|
|
@@ -75695,9 +75696,9 @@ const StepList = ({
|
|
|
75695
75696
|
"text-anchor": "middle",
|
|
75696
75697
|
children: index + 1
|
|
75697
75698
|
})]
|
|
75698
|
-
},
|
|
75699
|
+
}, steps[index].value))
|
|
75699
75700
|
});
|
|
75700
|
-
return
|
|
75701
|
+
return jsxs(Box, {
|
|
75701
75702
|
...rest,
|
|
75702
75703
|
ref: rootRef,
|
|
75703
75704
|
baseClassName: "navi_step_list",
|
|
@@ -75710,13 +75711,14 @@ const StepList = ({
|
|
|
75710
75711
|
"data-slide-container-follows": slideContainer,
|
|
75711
75712
|
style: {
|
|
75712
75713
|
...rest.style,
|
|
75713
|
-
...(
|
|
75714
|
-
"--step-list-
|
|
75715
|
-
"--step-list-reached-x": reachedIndex === -1 ? -9999 : dotXs[reachedIndex],
|
|
75716
|
-
"--step-list-reachable-x": reachableIndex === -1 ? -9999 : dotXs[reachableIndex]
|
|
75714
|
+
...(duration ? {
|
|
75715
|
+
"--step-list-duration": duration
|
|
75717
75716
|
} : undefined)
|
|
75718
75717
|
},
|
|
75719
|
-
children:
|
|
75718
|
+
children: [jsx(StepListContext.Provider, {
|
|
75719
|
+
value: registry,
|
|
75720
|
+
children: children
|
|
75721
|
+
}), width > 0 && stepCount > 0 ? jsxs(Fragment$1, {
|
|
75720
75722
|
children: [renderRail(false), renderRail(true), currentIndex !== -1 && dotXs[currentIndex] !== undefined ? jsx("svg", {
|
|
75721
75723
|
className: "navi_step_list_rail",
|
|
75722
75724
|
width: width,
|
|
@@ -75738,15 +75740,7 @@ const StepList = ({
|
|
|
75738
75740
|
r: RING_R
|
|
75739
75741
|
})
|
|
75740
75742
|
})
|
|
75741
|
-
}) : null,
|
|
75742
|
-
const value = valueOf(stepVNode, index);
|
|
75743
|
-
// Whatever else the Item was given reaches its button — a
|
|
75744
|
-
// pseudoState held for a demo, an aria attribute.
|
|
75745
|
-
const itemRest = {
|
|
75746
|
-
...stepVNode.props
|
|
75747
|
-
};
|
|
75748
|
-
delete itemRest.value;
|
|
75749
|
-
delete itemRest.children;
|
|
75743
|
+
}) : null, steps.map((step, index) => {
|
|
75750
75744
|
// The slots tile the row, cut at the container's edges: the
|
|
75751
75745
|
// first and the last cover only the inner half of the room an
|
|
75752
75746
|
// interior slot gets, so pressing just outside the box presses
|
|
@@ -75762,8 +75756,8 @@ const StepList = ({
|
|
|
75762
75756
|
"width": `${slotRight - slotLeft}px`,
|
|
75763
75757
|
"--step-dot-x": `${dotXs[index] - slotLeft}px`
|
|
75764
75758
|
},
|
|
75765
|
-
children:
|
|
75766
|
-
...
|
|
75759
|
+
children: jsxs(Button, {
|
|
75760
|
+
...step.buttonProps,
|
|
75767
75761
|
// bare, not discrete: what is drawn IS the dot and its
|
|
75768
75762
|
// label — the hover wash a discrete button paints over its
|
|
75769
75763
|
// whole surface is exactly what must not appear here (the
|
|
@@ -75776,38 +75770,105 @@ const StepList = ({
|
|
|
75776
75770
|
// Towards the slides when connected, by name: the command
|
|
75777
75771
|
// reaches the container wherever this list sits on the
|
|
75778
75772
|
// page. What else a press should do is the Item's own
|
|
75779
|
-
// onClick, which arrived through
|
|
75773
|
+
// onClick, which arrived through buttonProps.
|
|
75774
|
+
,
|
|
75775
|
+
|
|
75776
|
+
command: slideContainer && travelByClick ? `--navi-go-to-slide:${step.value}` : undefined,
|
|
75777
|
+
commandFor: slideContainer
|
|
75778
|
+
// A message about a step (a callout) points at its circle,
|
|
75779
|
+
// above it: the label lives below.
|
|
75780
75780
|
,
|
|
75781
75781
|
|
|
75782
|
-
|
|
75783
|
-
|
|
75784
|
-
children: jsx("span", {
|
|
75782
|
+
"data-callout-anchor": ".navi_step_list_dot",
|
|
75783
|
+
"data-callout-position": "top",
|
|
75784
|
+
children: [jsx("span", {
|
|
75785
|
+
className: "navi_step_list_dot",
|
|
75786
|
+
"aria-hidden": "true"
|
|
75787
|
+
}), jsx("span", {
|
|
75785
75788
|
className: "navi_step_list_label",
|
|
75786
|
-
children:
|
|
75787
|
-
})
|
|
75789
|
+
children: step.label
|
|
75790
|
+
})]
|
|
75788
75791
|
})
|
|
75789
|
-
}, value);
|
|
75792
|
+
}, step.value);
|
|
75790
75793
|
})]
|
|
75791
|
-
}) : null
|
|
75794
|
+
}) : null]
|
|
75792
75795
|
});
|
|
75793
75796
|
};
|
|
75794
75797
|
|
|
75798
|
+
// The same steps saying the same things: nothing to redraw. The labels are
|
|
75799
|
+
// vnodes, fresh objects on every render — comparing them would always say
|
|
75800
|
+
// "changed", so they are left out: what they show changes through the state
|
|
75801
|
+
// it came from, which re-renders this list anyway.
|
|
75802
|
+
const sameSteps = (previousSteps, nextSteps) => {
|
|
75803
|
+
if (previousSteps.length !== nextSteps.length) {
|
|
75804
|
+
return false;
|
|
75805
|
+
}
|
|
75806
|
+
let index = 0;
|
|
75807
|
+
while (index < previousSteps.length) {
|
|
75808
|
+
const previous = previousSteps[index];
|
|
75809
|
+
const next = nextSteps[index];
|
|
75810
|
+
if (previous.value !== next.value || previous.done !== next.done) {
|
|
75811
|
+
return false;
|
|
75812
|
+
}
|
|
75813
|
+
if (!sameShallow(previous.buttonProps, next.buttonProps)) {
|
|
75814
|
+
return false;
|
|
75815
|
+
}
|
|
75816
|
+
index++;
|
|
75817
|
+
}
|
|
75818
|
+
return true;
|
|
75819
|
+
};
|
|
75820
|
+
const sameShallow = (previousObject, nextObject) => {
|
|
75821
|
+
const previousKeys = Object.keys(previousObject);
|
|
75822
|
+
const nextKeys = Object.keys(nextObject);
|
|
75823
|
+
if (previousKeys.length !== nextKeys.length) {
|
|
75824
|
+
return false;
|
|
75825
|
+
}
|
|
75826
|
+
for (const key of previousKeys) {
|
|
75827
|
+
if (previousObject[key] !== nextObject[key]) {
|
|
75828
|
+
return false;
|
|
75829
|
+
}
|
|
75830
|
+
}
|
|
75831
|
+
return true;
|
|
75832
|
+
};
|
|
75833
|
+
|
|
75795
75834
|
/**
|
|
75796
|
-
* One step of the walk: `value` names it (what `current
|
|
75797
|
-
*
|
|
75798
|
-
*
|
|
75835
|
+
* One step of the walk: `value` names it (what `current` says and what a
|
|
75836
|
+
* press reports), `done` says it is answered (its dot fills, and the path is
|
|
75837
|
+
* deduced from the answered steps), the children are its label.
|
|
75838
|
+
*
|
|
75839
|
+
* It renders NOTHING: it registers with the list around it as it renders,
|
|
75840
|
+
* and the list draws everything — the dot, the label, the button. Whatever
|
|
75841
|
+
* else it carries (onClick, pseudoState, aria-*) lands on that button.
|
|
75799
75842
|
*
|
|
75800
75843
|
* It is both StepList.Item and an export of its own, the way Slide is to
|
|
75801
75844
|
* SlideContainer.
|
|
75802
75845
|
*
|
|
75803
75846
|
* @type {import("ignore:preact").FunctionComponent<{
|
|
75804
75847
|
* value: string,
|
|
75848
|
+
* done?: boolean,
|
|
75805
75849
|
* [key: string]: any,
|
|
75806
75850
|
* }>}
|
|
75851
|
+
* @param {boolean} [done] - this step is answered: its dot is filled — the
|
|
75852
|
+
* fill's one meaning. Steps answered out of order are filled dots
|
|
75853
|
+
* standing alone, dashed segments around them.
|
|
75807
75854
|
*/
|
|
75808
75855
|
const Step = ({
|
|
75809
|
-
|
|
75810
|
-
|
|
75856
|
+
value,
|
|
75857
|
+
done,
|
|
75858
|
+
children,
|
|
75859
|
+
...buttonProps
|
|
75860
|
+
}) => {
|
|
75861
|
+
const registry = useContext(StepListContext);
|
|
75862
|
+
if (registry) {
|
|
75863
|
+
registry.renderedSteps.push({
|
|
75864
|
+
value: value ?? String(registry.renderedSteps.length),
|
|
75865
|
+
done: Boolean(done),
|
|
75866
|
+
label: children,
|
|
75867
|
+
buttonProps
|
|
75868
|
+
});
|
|
75869
|
+
}
|
|
75870
|
+
return null;
|
|
75871
|
+
};
|
|
75811
75872
|
StepList.Item = Step;
|
|
75812
75873
|
|
|
75813
75874
|
installImportMetaCssBuild(import.meta);const css$1 = /* css */`
|