@jsenv/navi 0.29.97 → 0.29.98
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 +424 -258
- package/dist/jsenv_navi.js.map +26 -26
- 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 {
|
|
@@ -18873,7 +18883,7 @@ const setupNetworkMonitoring = () => {
|
|
|
18873
18883
|
};
|
|
18874
18884
|
setupNetworkMonitoring();
|
|
18875
18885
|
|
|
18876
|
-
installImportMetaCssBuild(import.meta);const css$
|
|
18886
|
+
installImportMetaCssBuild(import.meta);const css$12 = /* css */`
|
|
18877
18887
|
.navi_loading_indicator_fluid_container {
|
|
18878
18888
|
position: relative;
|
|
18879
18889
|
display: flex;
|
|
@@ -18905,7 +18915,7 @@ const LoadingIndicatorFluid = ({
|
|
|
18905
18915
|
visuallyHidden,
|
|
18906
18916
|
...rest
|
|
18907
18917
|
}) => {
|
|
18908
|
-
import.meta.css = [css$
|
|
18918
|
+
import.meta.css = [css$12, "@jsenv/navi/src/graphic/loading/loading_indicator_fluid.jsx"];
|
|
18909
18919
|
const ref = useRef(null);
|
|
18910
18920
|
// The container dimensions can be deduced from the ref itself as the indicator is absolute inset 0
|
|
18911
18921
|
const [containerWidth, setContainerWidth] = useState(0);
|
|
@@ -19110,7 +19120,7 @@ const LoadingRectangleSvg = ({
|
|
|
19110
19120
|
});
|
|
19111
19121
|
};
|
|
19112
19122
|
|
|
19113
|
-
installImportMetaCssBuild(import.meta);const css$
|
|
19123
|
+
installImportMetaCssBuild(import.meta);const css$11 = /* css */`
|
|
19114
19124
|
.navi_loading_outline_wrapper {
|
|
19115
19125
|
position: absolute;
|
|
19116
19126
|
/* Controls place the outline slightly outside their box, right on top of
|
|
@@ -19147,7 +19157,7 @@ installImportMetaCssBuild(import.meta);const css$10 = /* css */`
|
|
|
19147
19157
|
}
|
|
19148
19158
|
`;
|
|
19149
19159
|
const LoadingOutline = props => {
|
|
19150
|
-
import.meta.css = [css$
|
|
19160
|
+
import.meta.css = [css$11, "@jsenv/navi/src/graphic/loading/loading_outline.jsx"];
|
|
19151
19161
|
if (props.containerRef) {
|
|
19152
19162
|
const container = props.containerRef.current;
|
|
19153
19163
|
if (!container) {
|
|
@@ -19437,7 +19447,7 @@ const selectByTextStrings = (element, range, startText, endText) => {
|
|
|
19437
19447
|
};
|
|
19438
19448
|
|
|
19439
19449
|
installImportMetaCssBuild(import.meta);// https://jsfiddle.net/v5xzJ/4/
|
|
19440
|
-
const css
|
|
19450
|
+
const css$10 = /* css */`
|
|
19441
19451
|
@layer navi {
|
|
19442
19452
|
.navi_text {
|
|
19443
19453
|
&[data-skeleton] {
|
|
@@ -19958,7 +19968,7 @@ const TextShrinkWrap = props => {
|
|
|
19958
19968
|
});
|
|
19959
19969
|
};
|
|
19960
19970
|
const TextUI = props => {
|
|
19961
|
-
import.meta.css = [css
|
|
19971
|
+
import.meta.css = [css$10, "@jsenv/navi/src/text/text.jsx"];
|
|
19962
19972
|
let {
|
|
19963
19973
|
ref,
|
|
19964
19974
|
spacing,
|
|
@@ -27333,18 +27343,31 @@ const useInteractiveProps = (props, {
|
|
|
27333
27343
|
controlRootProps.onnavi_action_end?.(e);
|
|
27334
27344
|
uiStateController.onActionEnd(e);
|
|
27335
27345
|
|
|
27336
|
-
//
|
|
27337
|
-
//
|
|
27338
|
-
//
|
|
27346
|
+
// Auto-trigger the parent group's action after the leaf action
|
|
27347
|
+
// completes, for the groups that ARE one control made of parts: a
|
|
27348
|
+
// radio or checkbox group, a wheel group (an hour wheel settling is
|
|
27349
|
+
// the time settling). The parent has already aggregated the new
|
|
27350
|
+
// state by now, so uiStateSignal is correct. One level only: the
|
|
27351
|
+
// parent's own action end does not climb further unless that parent
|
|
27352
|
+
// is itself such a group.
|
|
27339
27353
|
const parentController = uiStateController.parentUIStateController;
|
|
27340
|
-
if (parentController && (parentController.controlType === "radio_group" || parentController.controlType === "checkbox_group")) {
|
|
27354
|
+
if (parentController && (parentController.controlType === "radio_group" || parentController.controlType === "checkbox_group" || parentController.controlType === "wheel_group")) {
|
|
27341
27355
|
const parentEl = parentController.ref.current;
|
|
27342
27356
|
if (parentEl) {
|
|
27343
|
-
const originalEvent = e.detail.eventChain[0];
|
|
27344
27357
|
dispatchRequestAction(parentEl, {
|
|
27345
|
-
event:
|
|
27358
|
+
event: e.detail.eventChain[0],
|
|
27346
27359
|
name: "auto_group_action",
|
|
27347
|
-
requester: e.detail.requester
|
|
27360
|
+
requester: e.detail.requester,
|
|
27361
|
+
// The interactivity gate is not re-asked: the user already
|
|
27362
|
+
// interacted — with the child, whose gate said yes — and this
|
|
27363
|
+
// follow-up is automatic. Asking again would also answer
|
|
27364
|
+
// wrong: this event is dispatched inside the batch() that
|
|
27365
|
+
// settles the child's action, where a bound action still
|
|
27366
|
+
// READS as running (its state is mirrored through a signal
|
|
27367
|
+
// effect the batch defers, see watchActionCompletion) — the
|
|
27368
|
+
// busy constraint would refuse the group for an action that
|
|
27369
|
+
// is already over. The validity gate still applies.
|
|
27370
|
+
bypassInteractivity: true
|
|
27348
27371
|
});
|
|
27349
27372
|
}
|
|
27350
27373
|
}
|
|
@@ -27406,7 +27429,7 @@ const getAssociatedLabels = element => {
|
|
|
27406
27429
|
return Array.from(element.labels);
|
|
27407
27430
|
};
|
|
27408
27431
|
|
|
27409
|
-
installImportMetaCssBuild(import.meta);const css
|
|
27432
|
+
installImportMetaCssBuild(import.meta);const css$$ = /* css */`
|
|
27410
27433
|
@layer navi {
|
|
27411
27434
|
.navi_button {
|
|
27412
27435
|
--button-border-radius: var(--navi-control-border-radius);
|
|
@@ -27837,7 +27860,7 @@ installImportMetaCssBuild(import.meta);const css$_ = /* css */`
|
|
|
27837
27860
|
}
|
|
27838
27861
|
`;
|
|
27839
27862
|
const ButtonUI = props => {
|
|
27840
|
-
import.meta.css = [css
|
|
27863
|
+
import.meta.css = [css$$, "@jsenv/navi/src/control/input/button_ui.jsx"];
|
|
27841
27864
|
const {
|
|
27842
27865
|
ref,
|
|
27843
27866
|
// href/link
|
|
@@ -29548,7 +29571,7 @@ installImportMetaCssBuild(import.meta);/**
|
|
|
29548
29571
|
* reaches the real container.
|
|
29549
29572
|
*/
|
|
29550
29573
|
let openLocalDialogCount = 0;
|
|
29551
|
-
const css$
|
|
29574
|
+
const css$_ = /* css */`
|
|
29552
29575
|
@layer navi {
|
|
29553
29576
|
.navi_dialog {
|
|
29554
29577
|
/* Min gap between the dialog and the edges of its container. Written
|
|
@@ -30132,7 +30155,7 @@ const css$Z = /* css */`
|
|
|
30132
30155
|
* @param {import("ignore:preact").ComponentChildren} props.children
|
|
30133
30156
|
*/
|
|
30134
30157
|
const Dialog = props => {
|
|
30135
|
-
import.meta.css = [css$
|
|
30158
|
+
import.meta.css = [css$_, "@jsenv/navi/src/layout/dialog.jsx"];
|
|
30136
30159
|
if (props.openController) {
|
|
30137
30160
|
return jsx(ControlledDialog, {
|
|
30138
30161
|
...props
|
|
@@ -31124,7 +31147,7 @@ installImportMetaCssBuild(import.meta);/**
|
|
|
31124
31147
|
* and applied.
|
|
31125
31148
|
*/
|
|
31126
31149
|
let openLocalPopoverCount = 0;
|
|
31127
|
-
const css$
|
|
31150
|
+
const css$Z = /* css */`
|
|
31128
31151
|
@layer navi {
|
|
31129
31152
|
.navi_popover {
|
|
31130
31153
|
/* soft: user-configurable preferred max-height. Kept as a *default*
|
|
@@ -31580,7 +31603,7 @@ const css$Y = /* css */`
|
|
|
31580
31603
|
* @param {import("ignore:preact").ComponentChildren} props.children
|
|
31581
31604
|
*/
|
|
31582
31605
|
const Popover = props => {
|
|
31583
|
-
import.meta.css = [css$
|
|
31606
|
+
import.meta.css = [css$Z, "@jsenv/navi/src/layout/popover.jsx"];
|
|
31584
31607
|
if (props.openController) {
|
|
31585
31608
|
return jsx(ControlledPopover, {
|
|
31586
31609
|
...props
|
|
@@ -32608,7 +32631,7 @@ installImportMetaCssBuild(import.meta);/**
|
|
|
32608
32631
|
* event, and a caller replacing the body entirely then has one protocol to
|
|
32609
32632
|
* follow — `--navi-confirm` for yes, anything that closes for no.
|
|
32610
32633
|
*/
|
|
32611
|
-
const css$
|
|
32634
|
+
const css$Y = /* css */`
|
|
32612
32635
|
/* The width lives on the body rather than on the popup, so that custom
|
|
32613
32636
|
content (which replaces this body entirely) sizes itself instead of
|
|
32614
32637
|
inheriting a ceiling meant for a sentence-long question. */
|
|
@@ -32745,7 +32768,7 @@ const ConfirmPopup = ({
|
|
|
32745
32768
|
onAnswer,
|
|
32746
32769
|
onClosed
|
|
32747
32770
|
}) => {
|
|
32748
|
-
import.meta.css = [css$
|
|
32771
|
+
import.meta.css = [css$Y, "@jsenv/navi/src/action/confirm_popup.jsx"];
|
|
32749
32772
|
const {
|
|
32750
32773
|
mode,
|
|
32751
32774
|
confirmLabel,
|
|
@@ -32829,7 +32852,7 @@ const defaultBody = (message, {
|
|
|
32829
32852
|
});
|
|
32830
32853
|
};
|
|
32831
32854
|
|
|
32832
|
-
installImportMetaCssBuild(import.meta);const css$
|
|
32855
|
+
installImportMetaCssBuild(import.meta);const css$X = /* css */`
|
|
32833
32856
|
.action_error {
|
|
32834
32857
|
margin-top: 0;
|
|
32835
32858
|
margin-bottom: 20px;
|
|
@@ -32854,7 +32877,7 @@ const ActionRenderer = ({
|
|
|
32854
32877
|
children,
|
|
32855
32878
|
disabled
|
|
32856
32879
|
}) => {
|
|
32857
|
-
import.meta.css = [css$
|
|
32880
|
+
import.meta.css = [css$X, "@jsenv/navi/src/action/action_renderer.jsx"];
|
|
32858
32881
|
if (action === undefined) {
|
|
32859
32882
|
throw new Error("ActionRenderer requires an action to render, but none was provided.");
|
|
32860
32883
|
}
|
|
@@ -38598,7 +38621,7 @@ const ROUTE_TRAVEL_ATTRIBUTE = "data-navi-route-travel";
|
|
|
38598
38621
|
// the root pictures must NOT move (they carry the whole viewport, blank bands
|
|
38599
38622
|
// included).
|
|
38600
38623
|
|
|
38601
|
-
const css$
|
|
38624
|
+
const css$W = /* css */`
|
|
38602
38625
|
/* The marked region is a picture of its own for the length of a transition of
|
|
38603
38626
|
OURS, and only then — the name is what makes the pages a picture the
|
|
38604
38627
|
movement below can carry.
|
|
@@ -39027,7 +39050,7 @@ const RouteTransitionArea = ({
|
|
|
39027
39050
|
children,
|
|
39028
39051
|
...rest
|
|
39029
39052
|
}) => {
|
|
39030
|
-
import.meta.css = [css$
|
|
39053
|
+
import.meta.css = [css$W, "@jsenv/navi/src/nav/route_transition.jsx"];
|
|
39031
39054
|
const props = {
|
|
39032
39055
|
...rest,
|
|
39033
39056
|
[TRANSITION_AREA_ATTRIBUTE]: ""
|
|
@@ -39084,7 +39107,7 @@ const RouteTransitionArea = ({
|
|
|
39084
39107
|
* @returns {() => void} remove this relation.
|
|
39085
39108
|
*/
|
|
39086
39109
|
const defineRouteTransition = (from, to, transition) => {
|
|
39087
|
-
import.meta.css = [css$
|
|
39110
|
+
import.meta.css = [css$W, "@jsenv/navi/src/nav/route_transition.jsx"];
|
|
39088
39111
|
const {
|
|
39089
39112
|
type,
|
|
39090
39113
|
duration
|
|
@@ -39120,7 +39143,7 @@ const defineRouteTransition = (from, to, transition) => {
|
|
|
39120
39143
|
* @returns {() => void} remove this default.
|
|
39121
39144
|
*/
|
|
39122
39145
|
const defineRouteDefaultTransition = transition => {
|
|
39123
|
-
import.meta.css = [css$
|
|
39146
|
+
import.meta.css = [css$W, "@jsenv/navi/src/nav/route_transition.jsx"];
|
|
39124
39147
|
const value = normalizeTransition(transition);
|
|
39125
39148
|
defaultTransition = value;
|
|
39126
39149
|
return () => {
|
|
@@ -39721,7 +39744,7 @@ const DRAGGED_ATTRIBUTE = "data-navi-route-travel-dragged";
|
|
|
39721
39744
|
const TURNED_ATTRIBUTE = "data-navi-route-travel-turned";
|
|
39722
39745
|
// The name the box wears while it travels, and only then (see nameForTravel).
|
|
39723
39746
|
const TRAVEL_NAME = "navi-route-travel";
|
|
39724
|
-
const css$
|
|
39747
|
+
const css$V = /* css */`
|
|
39725
39748
|
/* The name that makes the page inside this box a picture of its own during a
|
|
39726
39749
|
transition — rather than part of the one big picture the document takes, so
|
|
39727
39750
|
the two pages can move past each other while everything else stays where it
|
|
@@ -40111,7 +40134,7 @@ const RouteTravel = ({
|
|
|
40111
40134
|
children,
|
|
40112
40135
|
...rest
|
|
40113
40136
|
}) => {
|
|
40114
|
-
import.meta.css = [css$
|
|
40137
|
+
import.meta.css = [css$V, "@jsenv/navi/src/nav/route_travel.jsx"];
|
|
40115
40138
|
const elementRef = useRef();
|
|
40116
40139
|
const gestureRef = useRef(null);
|
|
40117
40140
|
// The travel in hand: the transition keeping the picture of the page being
|
|
@@ -42673,7 +42696,7 @@ const PhoneSvg = () => {
|
|
|
42673
42696
|
};
|
|
42674
42697
|
|
|
42675
42698
|
installImportMetaCssBuild(import.meta);// # TextAnchor — how it works
|
|
42676
|
-
const css$
|
|
42699
|
+
const css$U = /* css */`
|
|
42677
42700
|
.navi_text_anchor {
|
|
42678
42701
|
vertical-align: baseline;
|
|
42679
42702
|
user-select: none;
|
|
@@ -42708,7 +42731,7 @@ const TextAnchor = ({
|
|
|
42708
42731
|
textSize,
|
|
42709
42732
|
lineLayout
|
|
42710
42733
|
}) => {
|
|
42711
|
-
import.meta.css = [css$
|
|
42734
|
+
import.meta.css = [css$U, "@jsenv/navi/src/text/text_anchor.jsx"];
|
|
42712
42735
|
const anchorRef = useRef();
|
|
42713
42736
|
|
|
42714
42737
|
// Plain useLayoutEffect would also fire while an ancestor dialog/popover
|
|
@@ -42823,7 +42846,7 @@ const computeTopOffset = ({
|
|
|
42823
42846
|
};
|
|
42824
42847
|
const charTopCanvas = document.createElement("canvas");
|
|
42825
42848
|
|
|
42826
|
-
installImportMetaCssBuild(import.meta);const css$
|
|
42849
|
+
installImportMetaCssBuild(import.meta);const css$T = /* css */`
|
|
42827
42850
|
@layer navi {
|
|
42828
42851
|
/* Ensure data attributes from box.jsx can win to update display */
|
|
42829
42852
|
.navi_icon {
|
|
@@ -42981,7 +43004,7 @@ const Icon = ({
|
|
|
42981
43004
|
fillLine,
|
|
42982
43005
|
...props
|
|
42983
43006
|
}) => {
|
|
42984
|
-
import.meta.css = [css$
|
|
43007
|
+
import.meta.css = [css$T, "@jsenv/navi/src/text/icon.jsx"];
|
|
42985
43008
|
const innerChildren = href ? jsx("svg", {
|
|
42986
43009
|
width: "100%",
|
|
42987
43010
|
height: "100%",
|
|
@@ -43143,7 +43166,7 @@ const useDimColorWhen = (elementRef, shouldDim) => {
|
|
|
43143
43166
|
});
|
|
43144
43167
|
};
|
|
43145
43168
|
|
|
43146
|
-
installImportMetaCssBuild(import.meta);const css$
|
|
43169
|
+
installImportMetaCssBuild(import.meta);const css$S = /* css */`
|
|
43147
43170
|
@layer navi {
|
|
43148
43171
|
.navi_link {
|
|
43149
43172
|
--link-border-radius: unset;
|
|
@@ -43605,7 +43628,7 @@ Object.assign(PSEUDO_CLASSES, {
|
|
|
43605
43628
|
* @param {boolean} [props.readOnly]
|
|
43606
43629
|
*/
|
|
43607
43630
|
const Link = props => {
|
|
43608
|
-
import.meta.css = [css$
|
|
43631
|
+
import.meta.css = [css$S, "@jsenv/navi/src/nav/link/link.jsx"];
|
|
43609
43632
|
if (props.route) {
|
|
43610
43633
|
return jsx(LinkWithRoute, {
|
|
43611
43634
|
...props
|
|
@@ -43928,7 +43951,7 @@ installImportMetaCssBuild(import.meta);/**
|
|
|
43928
43951
|
* https://dribbble.com/search/tabs
|
|
43929
43952
|
*/
|
|
43930
43953
|
let navCount = 0;
|
|
43931
|
-
const css$
|
|
43954
|
+
const css$R = /* css */`
|
|
43932
43955
|
@layer navi {
|
|
43933
43956
|
.navi_nav {
|
|
43934
43957
|
--nav-border: none;
|
|
@@ -44211,7 +44234,7 @@ const Nav = ({
|
|
|
44211
44234
|
slideContainer,
|
|
44212
44235
|
...props
|
|
44213
44236
|
}) => {
|
|
44214
|
-
import.meta.css = [css$
|
|
44237
|
+
import.meta.css = [css$R, "@jsenv/navi/src/nav/link/nav.jsx"];
|
|
44215
44238
|
const defaultRef = useRef();
|
|
44216
44239
|
props.ref = props.ref || defaultRef;
|
|
44217
44240
|
const navRef = props.ref;
|
|
@@ -44738,7 +44761,7 @@ installImportMetaCssBuild(import.meta);/**
|
|
|
44738
44761
|
* Border width participates in layout (it is added to the tab and page
|
|
44739
44762
|
* padding): a thick border grows the binder rather than eating into the text.
|
|
44740
44763
|
*/
|
|
44741
|
-
const css$
|
|
44764
|
+
const css$Q = /* css */`
|
|
44742
44765
|
@layer navi {
|
|
44743
44766
|
.navi_binder {
|
|
44744
44767
|
--binder-border-width: var(--navi-control-border-width);
|
|
@@ -45051,7 +45074,7 @@ const Binder = ({
|
|
|
45051
45074
|
pagePadding,
|
|
45052
45075
|
...props
|
|
45053
45076
|
}) => {
|
|
45054
|
-
import.meta.css = [css$
|
|
45077
|
+
import.meta.css = [css$Q, "@jsenv/navi/src/nav/binder/binder.jsx"];
|
|
45055
45078
|
const items = toChildArray(children).map((child, index) => {
|
|
45056
45079
|
const {
|
|
45057
45080
|
value: itemValue,
|
|
@@ -45538,7 +45561,7 @@ installImportMetaCssBuild(import.meta);/**
|
|
|
45538
45561
|
* added to the size asked for exactly like the notch inset is, so the
|
|
45539
45562
|
* content still gets the size the prop names.
|
|
45540
45563
|
*/
|
|
45541
|
-
const css$
|
|
45564
|
+
const css$P = /* css */`
|
|
45542
45565
|
@layer navi {
|
|
45543
45566
|
:root {
|
|
45544
45567
|
--navi-fixed-bar-width: 56px;
|
|
@@ -45686,7 +45709,7 @@ const FixedBar = ({
|
|
|
45686
45709
|
border = true,
|
|
45687
45710
|
...props
|
|
45688
45711
|
}) => {
|
|
45689
|
-
import.meta.css = [css$
|
|
45712
|
+
import.meta.css = [css$P, "@jsenv/navi/src/layout/fixed_bar/fixed_bar.jsx"];
|
|
45690
45713
|
const defaultRef = useRef();
|
|
45691
45714
|
props.ref = props.ref || defaultRef;
|
|
45692
45715
|
// Said with the width the border rule reads rather than with an attribute of
|
|
@@ -45780,7 +45803,7 @@ const FixedBar = ({
|
|
|
45780
45803
|
// Subpixel layout rounds rectangles up on boxes that fit exactly.
|
|
45781
45804
|
const OVERFLOW_TOLERANCE = 1;
|
|
45782
45805
|
|
|
45783
|
-
const css$
|
|
45806
|
+
const css$O = /* css */ `
|
|
45784
45807
|
[data-navi-overflow-x] {
|
|
45785
45808
|
outline: 2px dashed #e74c3c;
|
|
45786
45809
|
outline-offset: -2px;
|
|
@@ -45804,7 +45827,7 @@ const detectHorizontalOverflow = ({
|
|
|
45804
45827
|
let styleEl = null;
|
|
45805
45828
|
if (highlight) {
|
|
45806
45829
|
styleEl = document.createElement("style");
|
|
45807
|
-
styleEl.textContent = css$
|
|
45830
|
+
styleEl.textContent = css$O;
|
|
45808
45831
|
document.head.appendChild(styleEl);
|
|
45809
45832
|
}
|
|
45810
45833
|
|
|
@@ -45959,7 +45982,7 @@ const useFocusGroup = (
|
|
|
45959
45982
|
};
|
|
45960
45983
|
|
|
45961
45984
|
installImportMetaCssBuild(import.meta);const rightArrowPath = "M680-480L360-160l-80-80 240-240-240-240 80-80 320 320z";
|
|
45962
|
-
const css$
|
|
45985
|
+
const css$N = /* css */`
|
|
45963
45986
|
.navi_summary_marker {
|
|
45964
45987
|
width: 1em;
|
|
45965
45988
|
height: 1em;
|
|
@@ -46049,7 +46072,7 @@ const SummaryMarker = ({
|
|
|
46049
46072
|
loading,
|
|
46050
46073
|
openDirection = "down"
|
|
46051
46074
|
}) => {
|
|
46052
|
-
import.meta.css = [css$
|
|
46075
|
+
import.meta.css = [css$N, "@jsenv/navi/src/control/details/summary_marker.jsx"];
|
|
46053
46076
|
const showLoading = useDebounceTrue(loading, 300);
|
|
46054
46077
|
return jsx("span", {
|
|
46055
46078
|
className: "navi_summary_marker",
|
|
@@ -46094,7 +46117,7 @@ const SummaryMarker = ({
|
|
|
46094
46117
|
});
|
|
46095
46118
|
};
|
|
46096
46119
|
|
|
46097
|
-
installImportMetaCssBuild(import.meta);const css$
|
|
46120
|
+
installImportMetaCssBuild(import.meta);const css$M = /* css */`
|
|
46098
46121
|
.navi_details {
|
|
46099
46122
|
position: relative;
|
|
46100
46123
|
z-index: 1;
|
|
@@ -46140,7 +46163,7 @@ const Details = props => {
|
|
|
46140
46163
|
return details;
|
|
46141
46164
|
};
|
|
46142
46165
|
const DetailsField = props => {
|
|
46143
|
-
import.meta.css = [css$
|
|
46166
|
+
import.meta.css = [css$M, "@jsenv/navi/src/control/details/details.jsx"];
|
|
46144
46167
|
const {
|
|
46145
46168
|
ref,
|
|
46146
46169
|
persists,
|
|
@@ -46360,7 +46383,7 @@ installImportMetaCssBuild(import.meta);/**
|
|
|
46360
46383
|
* UI when it comes first). Once settled open the clipping is released, so a
|
|
46361
46384
|
* popover or focus ring inside is not cut at the edges.
|
|
46362
46385
|
*/
|
|
46363
|
-
const css$
|
|
46386
|
+
const css$L = /* css */`
|
|
46364
46387
|
.navi_expandable {
|
|
46365
46388
|
position: relative;
|
|
46366
46389
|
display: flex;
|
|
@@ -46586,7 +46609,7 @@ const useExpandableContext = partName => {
|
|
|
46586
46609
|
* and rebuilds it from scratch on every expansion.
|
|
46587
46610
|
*/
|
|
46588
46611
|
const Expandable = props => {
|
|
46589
|
-
import.meta.css = [css$
|
|
46612
|
+
import.meta.css = [css$L, "@jsenv/navi/src/control/expandable/expandable.jsx"];
|
|
46590
46613
|
const {
|
|
46591
46614
|
ref,
|
|
46592
46615
|
ui,
|
|
@@ -47251,7 +47274,7 @@ const ControlGroup = props => {
|
|
|
47251
47274
|
};
|
|
47252
47275
|
const CONTROL_GROUP_PSEUDO_CLASSES = [":hover", ":focus", ":focus-visible", ":read-only", ":disabled", ":-navi-loading"];
|
|
47253
47276
|
|
|
47254
|
-
installImportMetaCssBuild(import.meta);const css$
|
|
47277
|
+
installImportMetaCssBuild(import.meta);const css$K = /* css */`
|
|
47255
47278
|
@layer navi {
|
|
47256
47279
|
.navi_checkbox {
|
|
47257
47280
|
--switch-margin: 0; /* Useful to reserve space for outline */
|
|
@@ -47329,7 +47352,7 @@ installImportMetaCssBuild(import.meta);const css$J = /* css */`
|
|
|
47329
47352
|
}
|
|
47330
47353
|
`;
|
|
47331
47354
|
const SwitchUI = () => {
|
|
47332
|
-
import.meta.css = [css$
|
|
47355
|
+
import.meta.css = [css$K, "@jsenv/navi/src/control/input/switch_ui.jsx"];
|
|
47333
47356
|
return jsx(Box, {
|
|
47334
47357
|
className: "navi_switch",
|
|
47335
47358
|
as: "svg",
|
|
@@ -47371,7 +47394,7 @@ const useCheckableProps = (props, options) => {
|
|
|
47371
47394
|
return result;
|
|
47372
47395
|
};
|
|
47373
47396
|
|
|
47374
|
-
installImportMetaCssBuild(import.meta);const css$
|
|
47397
|
+
installImportMetaCssBuild(import.meta);const css$J = /* css */`
|
|
47375
47398
|
@layer navi {
|
|
47376
47399
|
.navi_checkbox {
|
|
47377
47400
|
--border-radius: var(--navi-checkbox-border-radius);
|
|
@@ -47698,7 +47721,7 @@ const InputCheckboxHeadless = props => {
|
|
|
47698
47721
|
});
|
|
47699
47722
|
};
|
|
47700
47723
|
const InputCheckboxFieldInterface = props => {
|
|
47701
|
-
import.meta.css = [css$
|
|
47724
|
+
import.meta.css = [css$J, "@jsenv/navi/src/control/input/input_checkbox.jsx"];
|
|
47702
47725
|
const [checkboxRootProps, checkboxHostProps] = useCheckableProps(props);
|
|
47703
47726
|
const {
|
|
47704
47727
|
icon,
|
|
@@ -47820,7 +47843,7 @@ const CheckboxButtonStyleCSSVars = {
|
|
|
47820
47843
|
const CheckboxPseudoClasses = [":hover", ":active", ":focus", ":focus-visible", ":read-only", ":disabled", ":checked", ":-navi-loading"];
|
|
47821
47844
|
const CheckboxPseudoElements = ["::-navi-loader", "::-navi-checkmark"];
|
|
47822
47845
|
|
|
47823
|
-
installImportMetaCssBuild(import.meta);const css$
|
|
47846
|
+
installImportMetaCssBuild(import.meta);const css$I = /* css */`
|
|
47824
47847
|
@layer navi {
|
|
47825
47848
|
.navi_label {
|
|
47826
47849
|
--label-required-indicator-color: var(--navi-color-danger, #b42318);
|
|
@@ -47900,7 +47923,7 @@ installImportMetaCssBuild(import.meta);const css$H = /* css */`
|
|
|
47900
47923
|
* </Field>
|
|
47901
47924
|
*/
|
|
47902
47925
|
const Field = props => {
|
|
47903
|
-
import.meta.css = [css$
|
|
47926
|
+
import.meta.css = [css$I, "@jsenv/navi/src/control/field.jsx"];
|
|
47904
47927
|
const refDefault = useRef();
|
|
47905
47928
|
props.ref = props.ref || refDefault;
|
|
47906
47929
|
const {
|
|
@@ -47935,7 +47958,7 @@ const FieldCSSVars = {
|
|
|
47935
47958
|
spacingWithControl: "--spacing-with-control"
|
|
47936
47959
|
};
|
|
47937
47960
|
const FieldAsContainer = props => {
|
|
47938
|
-
import.meta.css = [css$
|
|
47961
|
+
import.meta.css = [css$I, "@jsenv/navi/src/control/field.jsx"];
|
|
47939
47962
|
const {
|
|
47940
47963
|
children
|
|
47941
47964
|
} = props;
|
|
@@ -47967,7 +47990,7 @@ const FieldAsContainer = props => {
|
|
|
47967
47990
|
};
|
|
47968
47991
|
const FIELD_PSEUDO_CLASSES = [":hover", ":active", ":focus", ":focus-visible", ":read-only", ":disabled", ":-navi-loading"];
|
|
47969
47992
|
const Label = props => {
|
|
47970
|
-
import.meta.css = [css$
|
|
47993
|
+
import.meta.css = [css$I, "@jsenv/navi/src/control/field.jsx"];
|
|
47971
47994
|
const {
|
|
47972
47995
|
children,
|
|
47973
47996
|
// Marks the label when its control is required. Takes what to show, or
|
|
@@ -48129,7 +48152,7 @@ const InputSlot = ({
|
|
|
48129
48152
|
});
|
|
48130
48153
|
};
|
|
48131
48154
|
|
|
48132
|
-
installImportMetaCssBuild(import.meta);const css$
|
|
48155
|
+
installImportMetaCssBuild(import.meta);const css$H = /* css */`
|
|
48133
48156
|
@layer navi {
|
|
48134
48157
|
.navi_radio {
|
|
48135
48158
|
--margin: 3px 3px 3px 5px;
|
|
@@ -48492,7 +48515,7 @@ const InputRadioHeadless = props => {
|
|
|
48492
48515
|
};
|
|
48493
48516
|
const VARIANT_SET = new Set(["icon", "button", "radio"]);
|
|
48494
48517
|
const InputRadioFieldInterface = props => {
|
|
48495
|
-
import.meta.css = [css$
|
|
48518
|
+
import.meta.css = [css$H, "@jsenv/navi/src/control/input/input_radio.jsx"];
|
|
48496
48519
|
const [radioRootProps, radioHostProps] = useCheckableProps(props);
|
|
48497
48520
|
const {
|
|
48498
48521
|
icon,
|
|
@@ -48638,7 +48661,7 @@ const RadioButtonStyleCSSVars = {
|
|
|
48638
48661
|
const RadioPseudoClasses = [":hover", ":active", ":focus", ":focus-visible", ":read-only", ":disabled", ":checked", ":-navi-loading"];
|
|
48639
48662
|
const RadioPseudoElements = ["::-navi-loader", "::-navi-radiomark"];
|
|
48640
48663
|
|
|
48641
|
-
installImportMetaCssBuild(import.meta);const css$
|
|
48664
|
+
installImportMetaCssBuild(import.meta);const css$G = /* css */`
|
|
48642
48665
|
@layer navi {
|
|
48643
48666
|
.navi_input_range {
|
|
48644
48667
|
--border-radius: 6px;
|
|
@@ -48893,7 +48916,7 @@ const InputRange = props => {
|
|
|
48893
48916
|
});
|
|
48894
48917
|
};
|
|
48895
48918
|
const InputRangeFieldInterface = props => {
|
|
48896
|
-
import.meta.css = [css$
|
|
48919
|
+
import.meta.css = [css$G, "@jsenv/navi/src/control/input/input_range.jsx"];
|
|
48897
48920
|
const {
|
|
48898
48921
|
ref
|
|
48899
48922
|
} = props;
|
|
@@ -51001,7 +51024,7 @@ installImportMetaCssBuild(import.meta);/**
|
|
|
51001
51024
|
* This means an editable thing MUST have a parent with position relative that wraps the content and the eventual editable input
|
|
51002
51025
|
*
|
|
51003
51026
|
*/
|
|
51004
|
-
const css$
|
|
51027
|
+
const css$F = /* css */`
|
|
51005
51028
|
.navi_editable_wrapper {
|
|
51006
51029
|
--inset-top: 0px;
|
|
51007
51030
|
--inset-right: 0px;
|
|
@@ -51050,7 +51073,7 @@ const useEditionController = () => {
|
|
|
51050
51073
|
};
|
|
51051
51074
|
};
|
|
51052
51075
|
const Editable = props => {
|
|
51053
|
-
import.meta.css = [css$
|
|
51076
|
+
import.meta.css = [css$F, "@jsenv/navi/src/control/edition/editable.jsx"];
|
|
51054
51077
|
let {
|
|
51055
51078
|
children,
|
|
51056
51079
|
action,
|
|
@@ -51599,7 +51622,7 @@ installImportMetaCssBuild(import.meta);/**
|
|
|
51599
51622
|
* meet are drawn once instead of twice, and only the outer corners stay
|
|
51600
51623
|
* rounded. See docs/control_group.md.
|
|
51601
51624
|
*/
|
|
51602
|
-
const css$
|
|
51625
|
+
const css$E = /* css */`
|
|
51603
51626
|
.navi_group {
|
|
51604
51627
|
--group-border-width: var(--navi-control-border-width);
|
|
51605
51628
|
|
|
@@ -51715,7 +51738,7 @@ const Group = ({
|
|
|
51715
51738
|
vertical = row,
|
|
51716
51739
|
...props
|
|
51717
51740
|
}) => {
|
|
51718
|
-
import.meta.css = [css$
|
|
51741
|
+
import.meta.css = [css$E, "@jsenv/navi/src/control/group.jsx"];
|
|
51719
51742
|
return jsx(Box, {
|
|
51720
51743
|
baseClassName: "navi_group",
|
|
51721
51744
|
"data-vertical": vertical ? "" : undefined
|
|
@@ -51881,7 +51904,7 @@ installImportMetaCssBuild(import.meta);/**
|
|
|
51881
51904
|
* So: nothing scrollable between the cap and the slides (a shared [data-body]
|
|
51882
51905
|
* around them IS a scroller, see box.jsx), and `overflow="auto"` on each Slide.
|
|
51883
51906
|
*/
|
|
51884
|
-
const css$
|
|
51907
|
+
const css$D = /* css */`
|
|
51885
51908
|
/* Where the picture stands relative to the slide that is current, in boxes
|
|
51886
51909
|
(see paintTravelProgress). Declared, so that it is a NUMBER the browser can
|
|
51887
51910
|
interpolate: the trait an indicator draws has to travel with the slides,
|
|
@@ -52375,7 +52398,7 @@ const SlideContainer = ({
|
|
|
52375
52398
|
children,
|
|
52376
52399
|
...rest
|
|
52377
52400
|
}) => {
|
|
52378
|
-
import.meta.css = [css$
|
|
52401
|
+
import.meta.css = [css$D, "@jsenv/navi/src/layout/slide_container.jsx"];
|
|
52379
52402
|
const debugFocus = useDebugFocus();
|
|
52380
52403
|
const trackRef = useRef();
|
|
52381
52404
|
// The box itself: it is what takes the keyboard when what is on screen holds
|
|
@@ -55220,7 +55243,7 @@ installImportMetaCssBuild(import.meta);/**
|
|
|
55220
55243
|
* and only under its own `sizeFromAnchor`) pass through untouched via
|
|
55221
55244
|
* `...rest` to whichever of Popover/Dialog actually renders.
|
|
55222
55245
|
*/
|
|
55223
|
-
const css$
|
|
55246
|
+
const css$C = /* css */`
|
|
55224
55247
|
@layer navi {
|
|
55225
55248
|
.navi_popup {
|
|
55226
55249
|
--popup-border-radius: var(--navi-popup-border-radius);
|
|
@@ -55337,7 +55360,7 @@ const css$B = /* css */`
|
|
|
55337
55360
|
* @param {import("ignore:preact").ComponentChildren} props.children
|
|
55338
55361
|
*/
|
|
55339
55362
|
const Popup = props => {
|
|
55340
|
-
import.meta.css = [css$
|
|
55363
|
+
import.meta.css = [css$C, "@jsenv/navi/src/layout/popup.jsx"];
|
|
55341
55364
|
const {
|
|
55342
55365
|
mode: modeProp,
|
|
55343
55366
|
maxWidth,
|
|
@@ -55398,7 +55421,7 @@ const Popup = props => {
|
|
|
55398
55421
|
});
|
|
55399
55422
|
};
|
|
55400
55423
|
|
|
55401
|
-
installImportMetaCssBuild(import.meta);const css$
|
|
55424
|
+
installImportMetaCssBuild(import.meta);const css$B = /* css */`
|
|
55402
55425
|
.navi_picker {
|
|
55403
55426
|
/* Sizing ceilings (maxmax), background, box-shadow, outline, padding,
|
|
55404
55427
|
overflow... are already handled correctly by Popup/Popover/Dialog
|
|
@@ -55526,7 +55549,7 @@ installImportMetaCssBuild(import.meta);const css$A = /* css */`
|
|
|
55526
55549
|
}
|
|
55527
55550
|
`;
|
|
55528
55551
|
const PickerCustomResolver = props => {
|
|
55529
|
-
import.meta.css = [css$
|
|
55552
|
+
import.meta.css = [css$B, "@jsenv/navi/src/control/picker/picker_custom.jsx"];
|
|
55530
55553
|
if (props.children === undefined) {
|
|
55531
55554
|
return jsx(PickerNative, {
|
|
55532
55555
|
...props
|
|
@@ -56320,7 +56343,7 @@ const LoadingIndicator = ({
|
|
|
56320
56343
|
});
|
|
56321
56344
|
};
|
|
56322
56345
|
|
|
56323
|
-
installImportMetaCssBuild(import.meta);const css$
|
|
56346
|
+
installImportMetaCssBuild(import.meta);const css$A = /* css */`
|
|
56324
56347
|
@layer navi {
|
|
56325
56348
|
.navi_separator {
|
|
56326
56349
|
--size: 1px;
|
|
@@ -56398,7 +56421,7 @@ const Separator = ({
|
|
|
56398
56421
|
style,
|
|
56399
56422
|
...props
|
|
56400
56423
|
}) => {
|
|
56401
|
-
import.meta.css = [css$
|
|
56424
|
+
import.meta.css = [css$A, "@jsenv/navi/src/layout/separator.jsx"];
|
|
56402
56425
|
return jsx(Box, {
|
|
56403
56426
|
as: vertical ? "span" : "hr",
|
|
56404
56427
|
...props,
|
|
@@ -56891,7 +56914,7 @@ const ListItemFooter = props => {
|
|
|
56891
56914
|
});
|
|
56892
56915
|
};
|
|
56893
56916
|
|
|
56894
|
-
installImportMetaCssBuild(import.meta);const css$
|
|
56917
|
+
installImportMetaCssBuild(import.meta);const css$z = /* css */`
|
|
56895
56918
|
@layer navi {
|
|
56896
56919
|
.navi_list_container[navi-selectable] {
|
|
56897
56920
|
/* Focus outline */
|
|
@@ -57103,7 +57126,7 @@ const ListSelectableResolver = props => {
|
|
|
57103
57126
|
};
|
|
57104
57127
|
const ListSelectable = props => {
|
|
57105
57128
|
const Next = useNextResolver();
|
|
57106
|
-
import.meta.css = [css$
|
|
57129
|
+
import.meta.css = [css$z, "@jsenv/navi/src/control/list/list_selectable.jsx"];
|
|
57107
57130
|
// we allow ourselves to auto-generate a name
|
|
57108
57131
|
const defaultName = useId();
|
|
57109
57132
|
props.name = props.name || `listbox_${defaultName}`;
|
|
@@ -57723,7 +57746,7 @@ const ListVirtualContext = createContext(null);
|
|
|
57723
57746
|
// that returning a component of one's own — instead of a bare <List.Item> —
|
|
57724
57747
|
// works the same way.
|
|
57725
57748
|
const ListRowContext = createContext(null);
|
|
57726
|
-
const css$
|
|
57749
|
+
const css$y = /* css */`
|
|
57727
57750
|
@layer navi {
|
|
57728
57751
|
.navi_list_container {
|
|
57729
57752
|
--list-outline-width: 1px;
|
|
@@ -58422,7 +58445,7 @@ const css$x = /* css */`
|
|
|
58422
58445
|
}
|
|
58423
58446
|
`;
|
|
58424
58447
|
const ListUI = props => {
|
|
58425
|
-
import.meta.css = [css$
|
|
58448
|
+
import.meta.css = [css$y, "@jsenv/navi/src/control/list/list.jsx"];
|
|
58426
58449
|
const {
|
|
58427
58450
|
ref,
|
|
58428
58451
|
renderBudget: renderBudgetProp = RENDER_BUDGET_DEFAULT,
|
|
@@ -62091,7 +62114,7 @@ const PickerPresetResolver = props => {
|
|
|
62091
62114
|
});
|
|
62092
62115
|
};
|
|
62093
62116
|
|
|
62094
|
-
installImportMetaCssBuild(import.meta);const css$
|
|
62117
|
+
installImportMetaCssBuild(import.meta);const css$x = /* css */`
|
|
62095
62118
|
@layer navi {
|
|
62096
62119
|
}
|
|
62097
62120
|
.navi_badge {
|
|
@@ -62203,7 +62226,7 @@ const Badge = ({
|
|
|
62203
62226
|
className,
|
|
62204
62227
|
...props
|
|
62205
62228
|
}) => {
|
|
62206
|
-
import.meta.css = [css$
|
|
62229
|
+
import.meta.css = [css$x, "@jsenv/navi/src/text/badge.jsx"];
|
|
62207
62230
|
const defaultRef = useRef();
|
|
62208
62231
|
props.ref = props.ref || defaultRef;
|
|
62209
62232
|
const {
|
|
@@ -62255,7 +62278,7 @@ const BadgeButton = props => {
|
|
|
62255
62278
|
};
|
|
62256
62279
|
Badge.Button = BadgeButton;
|
|
62257
62280
|
|
|
62258
|
-
installImportMetaCssBuild(import.meta);const css$
|
|
62281
|
+
installImportMetaCssBuild(import.meta);const css$w = /* css */`
|
|
62259
62282
|
@layer navi {
|
|
62260
62283
|
}
|
|
62261
62284
|
.navi_badge_list {
|
|
@@ -62280,7 +62303,7 @@ const BadgeList = ({
|
|
|
62280
62303
|
max,
|
|
62281
62304
|
...props
|
|
62282
62305
|
}) => {
|
|
62283
|
-
import.meta.css = [css$
|
|
62306
|
+
import.meta.css = [css$w, "@jsenv/navi/src/text/badge_list.jsx"];
|
|
62284
62307
|
const measureRef = useRef();
|
|
62285
62308
|
const visibleRef = useRef();
|
|
62286
62309
|
useLayoutEffect(() => {
|
|
@@ -62355,7 +62378,7 @@ const BadgeList = ({
|
|
|
62355
62378
|
});
|
|
62356
62379
|
};
|
|
62357
62380
|
|
|
62358
|
-
installImportMetaCssBuild(import.meta);const css$
|
|
62381
|
+
installImportMetaCssBuild(import.meta);const css$v = /* css */`
|
|
62359
62382
|
.navi_color {
|
|
62360
62383
|
display: block;
|
|
62361
62384
|
aspect-ratio: 1/1;
|
|
@@ -62386,7 +62409,7 @@ const Color = ({
|
|
|
62386
62409
|
children,
|
|
62387
62410
|
...rest
|
|
62388
62411
|
}) => {
|
|
62389
|
-
import.meta.css = [css$
|
|
62412
|
+
import.meta.css = [css$v, "@jsenv/navi/src/text/color.jsx"];
|
|
62390
62413
|
const color = children || undefined;
|
|
62391
62414
|
return jsx(Box, {
|
|
62392
62415
|
as: "span",
|
|
@@ -62843,7 +62866,7 @@ const PickerFileUI = () => {
|
|
|
62843
62866
|
return String(value);
|
|
62844
62867
|
};
|
|
62845
62868
|
|
|
62846
|
-
installImportMetaCssBuild(import.meta);const css$
|
|
62869
|
+
installImportMetaCssBuild(import.meta);const css$u = /* css */`
|
|
62847
62870
|
@layer navi {
|
|
62848
62871
|
.navi_picker {
|
|
62849
62872
|
--picker-border-radius: var(--navi-control-border-radius);
|
|
@@ -63232,7 +63255,7 @@ installImportMetaCssBuild(import.meta);const css$t = /* css */`
|
|
|
63232
63255
|
}
|
|
63233
63256
|
`;
|
|
63234
63257
|
const PickerButton = props => {
|
|
63235
|
-
import.meta.css = [css$
|
|
63258
|
+
import.meta.css = [css$u, "@jsenv/navi/src/control/picker/picker.jsx"];
|
|
63236
63259
|
if (typeof props.maxLines === "string") {
|
|
63237
63260
|
props.maxLines = parseInt(props.maxLines);
|
|
63238
63261
|
}
|
|
@@ -63681,7 +63704,7 @@ installImportMetaCssBuild(import.meta);/**
|
|
|
63681
63704
|
* refuse it on purpose, which is what keeps the focus where the travel happens
|
|
63682
63705
|
* instead of moving it into a slide that is about to leave.
|
|
63683
63706
|
*/
|
|
63684
|
-
const css$
|
|
63707
|
+
const css$t = /* css */`
|
|
63685
63708
|
@layer navi {
|
|
63686
63709
|
.navi_picker_spin {
|
|
63687
63710
|
/* A picker one steps through is still a picker: what themes every picker
|
|
@@ -64150,7 +64173,7 @@ const Spin = ({
|
|
|
64150
64173
|
nextLabel,
|
|
64151
64174
|
...rest
|
|
64152
64175
|
}) => {
|
|
64153
|
-
import.meta.css = [css$
|
|
64176
|
+
import.meta.css = [css$t, "@jsenv/navi/src/control/picker/picker_spin.jsx"];
|
|
64154
64177
|
const id = useId();
|
|
64155
64178
|
// What the group around it says, when there is one: how big the whole thing
|
|
64156
64179
|
// is written is said once, on the group, and every spin in it follows.
|
|
@@ -64686,7 +64709,7 @@ const renderValueDefault = value => String(value ?? "");
|
|
|
64686
64709
|
* are passed on to the spins sitting in them.
|
|
64687
64710
|
*/
|
|
64688
64711
|
const SpinGroup = props => {
|
|
64689
|
-
import.meta.css = [css$
|
|
64712
|
+
import.meta.css = [css$t, "@jsenv/navi/src/control/picker/picker_spin.jsx"];
|
|
64690
64713
|
const {
|
|
64691
64714
|
size
|
|
64692
64715
|
} = props;
|
|
@@ -65199,7 +65222,7 @@ const TimeRangeSpin = ({
|
|
|
65199
65222
|
};
|
|
65200
65223
|
|
|
65201
65224
|
installImportMetaCssBuild(import.meta);// TOFIX: select in data then reset, it reset to red/blue instead of red/blue/green
|
|
65202
|
-
const css$
|
|
65225
|
+
const css$s = /* css */`
|
|
65203
65226
|
.navi_checkbox_group {
|
|
65204
65227
|
border-style: solid;
|
|
65205
65228
|
|
|
@@ -65240,7 +65263,7 @@ const CheckboxGroup = props => {
|
|
|
65240
65263
|
return checkboxGroup;
|
|
65241
65264
|
};
|
|
65242
65265
|
const CheckboxGroupInterface = props => {
|
|
65243
|
-
import.meta.css = [css$
|
|
65266
|
+
import.meta.css = [css$s, "@jsenv/navi/src/control/input/checkbox_group.jsx"];
|
|
65244
65267
|
const {
|
|
65245
65268
|
ref
|
|
65246
65269
|
} = props;
|
|
@@ -65289,7 +65312,7 @@ installImportMetaCssBuild(import.meta);/**
|
|
|
65289
65312
|
* shared sheet is registered here too — a page may render a Textarea without
|
|
65290
65313
|
* any Input.
|
|
65291
65314
|
*/
|
|
65292
|
-
const css$
|
|
65315
|
+
const css$r = /* css */`
|
|
65293
65316
|
.navi_input.navi_textarea {
|
|
65294
65317
|
.navi_control_input {
|
|
65295
65318
|
min-height: calc(var(--textarea-min-rows, 1.5) * 1lh);
|
|
@@ -65376,7 +65399,7 @@ const Textarea = ({
|
|
|
65376
65399
|
width = "35ch",
|
|
65377
65400
|
...props
|
|
65378
65401
|
}) => {
|
|
65379
|
-
import.meta.css = [inputCss + css$
|
|
65402
|
+
import.meta.css = [inputCss + css$r, "@jsenv/navi/src/control/input/textarea.jsx"];
|
|
65380
65403
|
const defaultRef = useRef(null);
|
|
65381
65404
|
props.ref = props.ref || defaultRef;
|
|
65382
65405
|
usePlaceholderHeight(props.ref, props.placeholder);
|
|
@@ -65450,7 +65473,7 @@ const TextareaCharCount = ({
|
|
|
65450
65473
|
maxLength,
|
|
65451
65474
|
...rest
|
|
65452
65475
|
}) => {
|
|
65453
|
-
import.meta.css = [css$
|
|
65476
|
+
import.meta.css = [css$r, "@jsenv/navi/src/control/input/textarea.jsx"];
|
|
65454
65477
|
const resolvedValue = signal ? signal.value : value;
|
|
65455
65478
|
const length = typeof resolvedValue === "string" ? resolvedValue.length : 0;
|
|
65456
65479
|
return jsx(Box, {
|
|
@@ -65635,7 +65658,7 @@ const formatIntlUnit = (unit, {
|
|
|
65635
65658
|
}
|
|
65636
65659
|
};
|
|
65637
65660
|
|
|
65638
|
-
installImportMetaCssBuild(import.meta);const css$
|
|
65661
|
+
installImportMetaCssBuild(import.meta);const css$q = /* css */`
|
|
65639
65662
|
.navi_input_duration {
|
|
65640
65663
|
--duration-separator-spacing: 4px;
|
|
65641
65664
|
--loader-color: var(--navi-loader-color);
|
|
@@ -65702,7 +65725,7 @@ installImportMetaCssBuild(import.meta);const css$p = /* css */`
|
|
|
65702
65725
|
* "auto" aligns each field toward its neighbouring separator (first→right, last→left, middle/solo→center).
|
|
65703
65726
|
*/
|
|
65704
65727
|
const InputDuration = props => {
|
|
65705
|
-
import.meta.css = [css$
|
|
65728
|
+
import.meta.css = [css$q, "@jsenv/navi/src/control/input/input_duration.jsx"];
|
|
65706
65729
|
const defaultRef = useRef();
|
|
65707
65730
|
props.ref = props.ref || defaultRef;
|
|
65708
65731
|
props.max = props.max || "23h59";
|
|
@@ -66204,7 +66227,7 @@ const InputDurationPart = ({
|
|
|
66204
66227
|
});
|
|
66205
66228
|
};
|
|
66206
66229
|
|
|
66207
|
-
installImportMetaCssBuild(import.meta);const css$
|
|
66230
|
+
installImportMetaCssBuild(import.meta);const css$p = /* css */`
|
|
66208
66231
|
.navi_radio_group {
|
|
66209
66232
|
border-style: solid;
|
|
66210
66233
|
|
|
@@ -66224,7 +66247,7 @@ const RadioGroup = props => {
|
|
|
66224
66247
|
return radioGroup;
|
|
66225
66248
|
};
|
|
66226
66249
|
const RadioGroupInterface = props => {
|
|
66227
|
-
import.meta.css = [css$
|
|
66250
|
+
import.meta.css = [css$p, "@jsenv/navi/src/control/input/radio_group.jsx"];
|
|
66228
66251
|
const {
|
|
66229
66252
|
ref
|
|
66230
66253
|
} = props;
|
|
@@ -66282,7 +66305,7 @@ installImportMetaCssBuild(import.meta);/**
|
|
|
66282
66305
|
* control is drawn — the list it opens stays the platform's own, which is the
|
|
66283
66306
|
* whole point of using a select.
|
|
66284
66307
|
*/
|
|
66285
|
-
const css$
|
|
66308
|
+
const css$o = /* css */`
|
|
66286
66309
|
.navi_input.navi_select {
|
|
66287
66310
|
.navi_control_input {
|
|
66288
66311
|
/* Room for the chevron, which sits over the padding rather than beside
|
|
@@ -66337,7 +66360,7 @@ const Select = ({
|
|
|
66337
66360
|
multiple,
|
|
66338
66361
|
...props
|
|
66339
66362
|
}) => {
|
|
66340
|
-
import.meta.css = [inputCss + css$
|
|
66363
|
+
import.meta.css = [inputCss + css$o, "@jsenv/navi/src/control/input/select.jsx"];
|
|
66341
66364
|
const defaultRef = useRef(null);
|
|
66342
66365
|
props.ref = props.ref || defaultRef;
|
|
66343
66366
|
seedDefaultValueFromSignal(props);
|
|
@@ -66405,7 +66428,7 @@ installImportMetaCssBuild(import.meta);/**
|
|
|
66405
66428
|
* running: one loading outline around both, which is why each half is told
|
|
66406
66429
|
* `loadingOutline={false}`.
|
|
66407
66430
|
*/
|
|
66408
|
-
const css$
|
|
66431
|
+
const css$n = /* css */`
|
|
66409
66432
|
/* Around the pair rather than in it: the outline is drawn against this
|
|
66410
66433
|
element and follows its corners, and a Group counts its own children to
|
|
66411
66434
|
know which corners to square — an outline among them would be one of the
|
|
@@ -66517,7 +66540,7 @@ const css$m = /* css */`
|
|
|
66517
66540
|
* Anything else lands on the split button's own box.
|
|
66518
66541
|
*/
|
|
66519
66542
|
const SplitButton = props => {
|
|
66520
|
-
import.meta.css = [css$
|
|
66543
|
+
import.meta.css = [css$n, "@jsenv/navi/src/control/input/split_button.jsx"];
|
|
66521
66544
|
const {
|
|
66522
66545
|
options = [],
|
|
66523
66546
|
value,
|
|
@@ -67168,7 +67191,7 @@ installImportMetaCssBuild(import.meta);/*
|
|
|
67168
67191
|
* accessors (top/height vs left/width) chosen from `horizontal`, and the CSS has
|
|
67169
67192
|
* a [data-horizontal] variant.
|
|
67170
67193
|
*/
|
|
67171
|
-
const css$
|
|
67194
|
+
const css$m = /* css */`
|
|
67172
67195
|
.navi_wheel_container {
|
|
67173
67196
|
/* Row size and emphasis band are read together: the band is what a value
|
|
67174
67197
|
must cross to lose its emphasis, and the row is how far it has to travel
|
|
@@ -68290,7 +68313,7 @@ const useWheelKeyboard = ({
|
|
|
68290
68313
|
}, [isHorizontal, interactive, isLoop]);
|
|
68291
68314
|
};
|
|
68292
68315
|
function WheelUI(props) {
|
|
68293
|
-
import.meta.css = [css$
|
|
68316
|
+
import.meta.css = [css$m, "@jsenv/navi/src/control/wheel/wheel.jsx"];
|
|
68294
68317
|
const {
|
|
68295
68318
|
ref,
|
|
68296
68319
|
visibleCount = 3,
|
|
@@ -68691,6 +68714,16 @@ function WheelUI(props) {
|
|
|
68691
68714
|
// uiAction; here we fire the action explicitly, once, on the settled value.
|
|
68692
68715
|
const input = inputRef.current;
|
|
68693
68716
|
if (input) {
|
|
68717
|
+
// Said out loud too, OUTSIDE the action pipeline: the action above goes
|
|
68718
|
+
// through the gates (validity included), and what listens to a settle
|
|
68719
|
+
// may be exactly the thing that RESTORES validity — a range's other
|
|
68720
|
+
// bound giving way (see TimeRangeWheel) cannot wait on a gate that
|
|
68721
|
+
// refuses invalid values. Bubbles, so a group holding this wheel hears
|
|
68722
|
+
// it without knowing where the wheel sits.
|
|
68723
|
+
dispatchPublicCustomEvent(input, "navi_wheel_settle", {
|
|
68724
|
+
value: trackedItemsRef.current[index].value,
|
|
68725
|
+
event: settleEvent
|
|
68726
|
+
});
|
|
68694
68727
|
dispatchRequestAction(input, {
|
|
68695
68728
|
event: settleEvent
|
|
68696
68729
|
});
|
|
@@ -69199,7 +69232,7 @@ Wheel.Item = WheelItem;
|
|
|
69199
69232
|
* @param {boolean} [props.zoom] - Enlarge the centered value of every wheel (see Wheel's zoom prop) with one prop for the whole group.
|
|
69200
69233
|
*/
|
|
69201
69234
|
const WheelGroup = props => {
|
|
69202
|
-
import.meta.css = [css$
|
|
69235
|
+
import.meta.css = [css$m, "@jsenv/navi/src/control/wheel/wheel.jsx"];
|
|
69203
69236
|
// WheelGroup IS a control group: it aggregates its named wheels ("hours",
|
|
69204
69237
|
// "minutes"…) into one object value, so it can sit directly inside a Form or a
|
|
69205
69238
|
// Picker with no extra <ControlGroup> wrapper. The wheel-specific presentation
|
|
@@ -69230,7 +69263,11 @@ const WheelGroup = props => {
|
|
|
69230
69263
|
const [controlgroupRootProps, controlgroupProps, childrenWrapperProps] = useControlgroupProps(props, {
|
|
69231
69264
|
allowCapture: true,
|
|
69232
69265
|
wantRequesterButtonState: true,
|
|
69233
|
-
|
|
69266
|
+
// Its own type, not the generic "control_group": the group IS one
|
|
69267
|
+
// control made of parts, and a wheel settling runs the group's own
|
|
69268
|
+
// action — the way a radio checking runs its group's (the auto group
|
|
69269
|
+
// action in control_hooks keys on this type).
|
|
69270
|
+
controlType: "wheel_group",
|
|
69234
69271
|
stateType: "object",
|
|
69235
69272
|
cascadeValidationToChildren: true,
|
|
69236
69273
|
aggregateChildStates: props.aggregateChildStates,
|
|
@@ -69365,7 +69402,7 @@ const WheelColon = props => {
|
|
|
69365
69402
|
};
|
|
69366
69403
|
Wheel.Colon = WheelColon;
|
|
69367
69404
|
|
|
69368
|
-
|
|
69405
|
+
installImportMetaCssBuild(import.meta);/**
|
|
69369
69406
|
* A time of day, and a span between two of them, set by turning rather than by
|
|
69370
69407
|
* typing. A wheel only ever shows values that exist: there is no half-written
|
|
69371
69408
|
* hour to bound and correct under the fingers, which is what a time typed digit
|
|
@@ -69375,11 +69412,33 @@ Wheel.Colon = WheelColon;
|
|
|
69375
69412
|
* like `TimeSpin` — the two are interchangeable in a form. `TimeRangeWheel` is
|
|
69376
69413
|
* two of those and carries `{ start, end }`, with the rule such a pair always
|
|
69377
69414
|
* 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
|
|
69415
|
+
* checked — a bound settling pushes the other out of its way, so what the
|
|
69416
|
+
* wheels show at rest is always a span. The send-time constraint stays
|
|
69417
|
+
* underneath for what pushing cannot fix (a start so late the span no longer
|
|
69418
|
+
* fits in the day).
|
|
69381
69419
|
*/
|
|
69420
|
+
const css$l = /* css */`
|
|
69421
|
+
/* The words around a span's wheels ("De", "à"): one line box, the height
|
|
69422
|
+
of a wheel row (--wheel-item-height re-exposed, same value as
|
|
69423
|
+
.navi_wheel_container), centered against the wheels by the group. The
|
|
69424
|
+
box's strut — this element's own font — is what places the baseline,
|
|
69425
|
+
exactly where a wheel row places its numbers'; and because the content
|
|
69426
|
+
stays in inline flow, anything written INSIDE at another size still
|
|
69427
|
+
sits on that same baseline. Two things this depends on: the label is a
|
|
69428
|
+
<Text size={size}> so its em — and therefore this line-height — is the
|
|
69429
|
+
SAME em as the wheel rows' (a label left at the control font under
|
|
69430
|
+
bigger wheels computes a shorter row and its baseline drifts); and no
|
|
69431
|
+
flex centering of the content (centering re-centers a smaller glyph,
|
|
69432
|
+
baselines are not centers). */
|
|
69433
|
+
.navi_time_range_label {
|
|
69434
|
+
--wheel-item-height: round(1.8em, 1px);
|
|
69382
69435
|
|
|
69436
|
+
color: var(--wheel-color, light-dark(#111, #eee));
|
|
69437
|
+
line-height: var(--wheel-item-height);
|
|
69438
|
+
white-space: nowrap;
|
|
69439
|
+
user-select: none;
|
|
69440
|
+
}
|
|
69441
|
+
`;
|
|
69383
69442
|
const HOUR_COUNT = 24;
|
|
69384
69443
|
const MINUTES_PER_HOUR = 60;
|
|
69385
69444
|
const LAST_MINUTE_OF_DAY = 23 * 60 + 59;
|
|
@@ -69538,6 +69597,7 @@ const TimeRangeWheel = ({
|
|
|
69538
69597
|
endTimeProps,
|
|
69539
69598
|
...rest
|
|
69540
69599
|
}) => {
|
|
69600
|
+
import.meta.css = [css$l, "@jsenv/navi/src/control/wheel/wheel_time.jsx"];
|
|
69541
69601
|
const startId = useId();
|
|
69542
69602
|
const startRef = useRef(null);
|
|
69543
69603
|
const endRef = useRef(null);
|
|
@@ -69549,10 +69609,15 @@ const TimeRangeWheel = ({
|
|
|
69549
69609
|
distributeChildUIState
|
|
69550
69610
|
} = useAnswered(placeholder, rest, aggregateSpan, distributeSpan);
|
|
69551
69611
|
|
|
69552
|
-
// What the pair does
|
|
69553
|
-
//
|
|
69554
|
-
//
|
|
69555
|
-
//
|
|
69612
|
+
// What the pair does once a bound SETTLES: the one that was moved stays
|
|
69613
|
+
// where it was put and the OTHER one gives way — a refusal at that point
|
|
69614
|
+
// would leave the person to undo what they just did. Settles, not while it
|
|
69615
|
+
// turns: a wheel under the finger holds a value nobody has chosen yet, and
|
|
69616
|
+
// the other bound jumping around mid-gesture answers a question that was
|
|
69617
|
+
// not asked. Wired on the wheel's settle EVENT (navi_wheel_settle), never
|
|
69618
|
+
// on `action`: an action goes through the gates, validity included, and
|
|
69619
|
+
// the moment this must run is precisely the moment the pair is INVALID —
|
|
69620
|
+
// an action-gated push would be refused by the very thing it fixes.
|
|
69556
69621
|
const keepBoundsApart = (movedSide, movedTime, e) => {
|
|
69557
69622
|
const movedMinutes = minutesFromTime(movedTime);
|
|
69558
69623
|
if (movedMinutes === null) {
|
|
@@ -69596,6 +69661,7 @@ const TimeRangeWheel = ({
|
|
|
69596
69661
|
value: answeredRef,
|
|
69597
69662
|
children: [startLabel === null ? null : jsx(Text, {
|
|
69598
69663
|
size: size,
|
|
69664
|
+
className: "navi_time_range_label",
|
|
69599
69665
|
children: startLabel
|
|
69600
69666
|
}), jsx(TimeWheel, {
|
|
69601
69667
|
id: startId,
|
|
@@ -69605,12 +69671,20 @@ const TimeRangeWheel = ({
|
|
|
69605
69671
|
hours: hours,
|
|
69606
69672
|
loop: loop,
|
|
69607
69673
|
size: size,
|
|
69608
|
-
placeholder: placeholder ? placeholder.start : undefined
|
|
69609
|
-
|
|
69674
|
+
placeholder: placeholder ? placeholder.start : undefined
|
|
69675
|
+
// e.detail.value is the settled WHEEL's own value (an hour, a
|
|
69676
|
+
// minute) — half a time. What the pair compares is this bound's
|
|
69677
|
+
// whole time, read off the element the listener sits on.
|
|
69678
|
+
,
|
|
69679
|
+
|
|
69680
|
+
onnavi_wheel_settle: e => {
|
|
69681
|
+
keepBoundsApart("start", getUIStateFromElement(e.currentTarget), e);
|
|
69682
|
+
},
|
|
69610
69683
|
...timeProps,
|
|
69611
69684
|
...startTimeProps
|
|
69612
69685
|
}), endLabel === null ? null : jsx(Text, {
|
|
69613
69686
|
size: size,
|
|
69687
|
+
className: "navi_time_range_label",
|
|
69614
69688
|
children: endLabel
|
|
69615
69689
|
}), jsx(TimeWheel, {
|
|
69616
69690
|
ref: endRef,
|
|
@@ -69620,11 +69694,14 @@ const TimeRangeWheel = ({
|
|
|
69620
69694
|
loop: loop,
|
|
69621
69695
|
size: size,
|
|
69622
69696
|
placeholder: placeholder ? placeholder.end : undefined,
|
|
69623
|
-
|
|
69697
|
+
onnavi_wheel_settle: e => {
|
|
69698
|
+
keepBoundsApart("end", getUIStateFromElement(e.currentTarget), e);
|
|
69699
|
+
}
|
|
69624
69700
|
// Which time it comes after, and how much room there must be between
|
|
69625
69701
|
// the two: said on the LATER of the two, so the answer is given where
|
|
69626
69702
|
// the time one would have to move is (see time_range_constraint.js).
|
|
69627
69703
|
,
|
|
69704
|
+
|
|
69628
69705
|
"data-time-after": startId,
|
|
69629
69706
|
"data-time-min-duration": minDuration,
|
|
69630
69707
|
...timeProps,
|
|
@@ -75257,18 +75334,34 @@ installImportMetaCssBuild(import.meta);/**
|
|
|
75257
75334
|
* Two distinct facts, drawn separately — they usually agree, and everything
|
|
75258
75335
|
* this component says comes from the moments they do not:
|
|
75259
75336
|
*
|
|
75260
|
-
* - the PATH (
|
|
75261
|
-
*
|
|
75262
|
-
*
|
|
75263
|
-
*
|
|
75337
|
+
* - DONE and the PATH (the blue fill). The mental model, to keep in mind
|
|
75338
|
+
* when touching any of this: the circles are THINGS TO DO, and the path is
|
|
75339
|
+
* the progression along the linear walk from the first to the last — a
|
|
75340
|
+
* thing done is what lets the path advance. Answering a step fills its
|
|
75341
|
+
* dot AND the line onward, up to the NEXT dot: the invitation to go
|
|
75342
|
+
* there. If that next step is already done the path crosses it from
|
|
75343
|
+
* behind and carries on, and so forth — the fill covers the answered
|
|
75344
|
+
* prefix plus one segment of appetite. It stops at the edge of the first
|
|
75345
|
+
* dot not answered, which stays empty: the fill's one meaning is
|
|
75346
|
+
* "answered", and the first dot is NOT filled on arrival — it becomes so
|
|
75347
|
+
* by being answered. Past the fill the line is dashed, the road not
|
|
75348
|
+
* walked yet; steps answered out of order are filled dots standing alone,
|
|
75349
|
+
* dashed segments around them: the holes, readable at a glance.
|
|
75264
75350
|
* - 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).
|
|
75351
|
+
* around its dot and its label emphasized. It travels freely, so it can
|
|
75352
|
+
* be AHEAD of the path or BEHIND it.
|
|
75268
75353
|
*
|
|
75269
75354
|
* Both move smoothly on change (a CSS transition each), so pressing a step
|
|
75270
75355
|
* or answering one is seen travelling rather than jumping.
|
|
75271
75356
|
*
|
|
75357
|
+
* The steps are the CHILDREN — <StepList.Item value="club">Club</StepList.Item>.
|
|
75358
|
+
* An Item renders nothing: it REGISTERS with the list as it renders (order
|
|
75359
|
+
* of rendering is the order of the steps), and the list draws everything —
|
|
75360
|
+
* which is what lets an Item come from anywhere: a .map(), a fragment, a
|
|
75361
|
+
* component of your own wrapping it. One caveat comes with reading the
|
|
75362
|
+
* children as they render: hand the list fresh Item vnodes on each render
|
|
75363
|
+
* (the usual JSX), not a memoized array a bailout would keep from rendering.
|
|
75364
|
+
*
|
|
75272
75365
|
* The dots are drawn in SVG, twice: a muted layer, and a filled layer
|
|
75273
75366
|
* clipped at the path's edge — the clip is what makes the path's progress a
|
|
75274
75367
|
* single sweep that fills the line and the dots it crosses in one movement.
|
|
@@ -75277,28 +75370,21 @@ installImportMetaCssBuild(import.meta);/**
|
|
|
75277
75370
|
* surface. Colors are CSS custom properties (see the css below), overridden
|
|
75278
75371
|
* from outside for a dark band or a different accent.
|
|
75279
75372
|
*
|
|
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
75373
|
* `slideContainer` connects the list to a <SlideContainer> by id, both ways:
|
|
75286
75374
|
* pressing a step travels there (--navi-go-to-slide), and the position is
|
|
75287
75375
|
* READ off the container rather than said by a prop — including mid-travel:
|
|
75288
75376
|
* the container paints --slide-travel-progress on this element (it is a
|
|
75289
75377
|
* 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.
|
|
75378
|
+
* drag under the finger, in CSS alone. The path is not concerned: it moves
|
|
75379
|
+
* on answers, never on movement.
|
|
75294
75380
|
*/
|
|
75295
75381
|
const css$2 = /* css */`
|
|
75296
75382
|
.navi_step_list {
|
|
75297
|
-
/* The knobs: accent
|
|
75298
|
-
|
|
75299
|
-
|
|
75300
|
-
|
|
75301
|
-
|
|
75383
|
+
/* The knobs: one accent for everything filled — the dots and the line
|
|
75384
|
+
share it, because the fill has ONE meaning (answered) and a meaning
|
|
75385
|
+
does not change color. Muted is what is not answered, on-accent
|
|
75386
|
+
writes on filled dots. Said from OUTSIDE (any ancestor — a dark band,
|
|
75387
|
+
a themed app) on the plain names; resolved here through an
|
|
75302
75388
|
indirection (--x-…, the way Button does), because a default written
|
|
75303
75389
|
on the plain name on this very element would beat anything an
|
|
75304
75390
|
ancestor says. */
|
|
@@ -75313,10 +75399,9 @@ const css$2 = /* css */`
|
|
|
75313
75399
|
--step-list-current-color,
|
|
75314
75400
|
light-dark(#1c2433, white)
|
|
75315
75401
|
);
|
|
75316
|
-
|
|
75317
|
-
|
|
75318
|
-
|
|
75319
|
-
);
|
|
75402
|
+
/* How long a movement takes — the path sweeping, the halo sliding. One
|
|
75403
|
+
number for all of them: they tell one story. */
|
|
75404
|
+
--x-step-list-duration: var(--step-list-duration, 300ms);
|
|
75320
75405
|
|
|
75321
75406
|
position: relative;
|
|
75322
75407
|
display: block;
|
|
@@ -75354,14 +75439,26 @@ const css$2 = /* css */`
|
|
|
75354
75439
|
.navi_step_list_rail g[data-current] text {
|
|
75355
75440
|
fill: var(--x-step-list-current-color);
|
|
75356
75441
|
}
|
|
75357
|
-
/*
|
|
75358
|
-
|
|
75359
|
-
|
|
75442
|
+
/* A step answered has its dot filled, wherever the path stands: answered
|
|
75443
|
+
out of order it stands alone, a filled dot between dashed segments.
|
|
75444
|
+
After the current rule on purpose: answered wins the drawing, the halo
|
|
75445
|
+
says current. */
|
|
75446
|
+
.navi_step_list_rail g[data-done] circle {
|
|
75447
|
+
fill: var(--x-step-list-accent);
|
|
75448
|
+
stroke: var(--x-step-list-accent);
|
|
75449
|
+
}
|
|
75450
|
+
.navi_step_list_rail g[data-done] text {
|
|
75451
|
+
fill: var(--x-step-list-on-accent);
|
|
75452
|
+
}
|
|
75453
|
+
/* The path: same drawing, filled, revealed up to the fill's edge — the
|
|
75454
|
+
answered prefix plus its segment of appetite (see the top comment). The
|
|
75455
|
+
clip is set inline (a width in px); transitioning it is what makes an
|
|
75456
|
+
answered step SWEEP its dot and the line onward rather than pop. */
|
|
75360
75457
|
.navi_step_list_rail_filled {
|
|
75361
|
-
transition: clip-path
|
|
75458
|
+
transition: clip-path var(--x-step-list-duration) ease;
|
|
75362
75459
|
}
|
|
75363
75460
|
.navi_step_list_rail_filled line {
|
|
75364
|
-
stroke: var(--x-step-list-
|
|
75461
|
+
stroke: var(--x-step-list-accent);
|
|
75365
75462
|
stroke-dasharray: none;
|
|
75366
75463
|
}
|
|
75367
75464
|
.navi_step_list_rail_filled circle {
|
|
@@ -75375,7 +75472,7 @@ const css$2 = /* css */`
|
|
|
75375
75472
|
to dot (transform, transitioned) — the g moves, the circle inside is
|
|
75376
75473
|
drawn at x=0. */
|
|
75377
75474
|
.navi_step_list_marker {
|
|
75378
|
-
transition: transform
|
|
75475
|
+
transition: transform var(--x-step-list-duration) ease;
|
|
75379
75476
|
}
|
|
75380
75477
|
.navi_step_list_marker circle {
|
|
75381
75478
|
fill: none;
|
|
@@ -75387,8 +75484,7 @@ const css$2 = /* css */`
|
|
|
75387
75484
|
container paints --slide-travel-progress here (this element follows it,
|
|
75388
75485
|
see data-slide-container-follows) — an asked-for travel animates it, a
|
|
75389
75486
|
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.
|
|
75487
|
+
the halo and the path move per frame in CSS alone.
|
|
75392
75488
|
Position, in dots-x px: where the picture is right now. */
|
|
75393
75489
|
.navi_step_list[data-slide-container-follows] {
|
|
75394
75490
|
--step-list-position: calc(
|
|
@@ -75400,36 +75496,11 @@ const css$2 = /* css */`
|
|
|
75400
75496
|
transform: translateX(calc(var(--step-list-position) * 1px));
|
|
75401
75497
|
transition: none;
|
|
75402
75498
|
}
|
|
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
75499
|
|
|
75429
75500
|
/* One press target per step, covering the dot AND the label under it. The
|
|
75430
75501
|
feedback is NOT the whole surface: a rectangle would say the whole band
|
|
75431
75502
|
is a button, when the affordance is the dot — so hover and focus land on
|
|
75432
|
-
a circle drawn over the dot
|
|
75503
|
+
a circle drawn over the dot, plus the label brightening.
|
|
75433
75504
|
--step-dot-x anchors both on the dot, wherever the dot sits in the slot:
|
|
75434
75505
|
the first and last slots are asymmetric (cut at the container's edge,
|
|
75435
75506
|
see the geometry in the component). */
|
|
@@ -75454,13 +75525,15 @@ const css$2 = /* css */`
|
|
|
75454
75525
|
--button-color-readonly: var(--x-step-list-muted);
|
|
75455
75526
|
/* The button's own focus ring, silenced: it would outline the whole
|
|
75456
75527
|
press surface, and the ring this list draws is the one around the dot
|
|
75457
|
-
(see
|
|
75458
|
-
|
|
75528
|
+
(see below) — two rings read as a mistake. Width rather than style,
|
|
75529
|
+
because the dot sets its own style in full. */
|
|
75459
75530
|
--button-outline-width: 0px;
|
|
75460
75531
|
}
|
|
75461
75532
|
/* Centered on the dot: same vertical middle as the rail (top 0, height 34,
|
|
75462
|
-
cy 17).
|
|
75463
|
-
|
|
75533
|
+
cy 17). A real element rather than a ::before, because it is also what a
|
|
75534
|
+
callout anchors to (data-callout-anchor needs a selector) — a message
|
|
75535
|
+
about a step points at its CIRCLE, not at the press surface. */
|
|
75536
|
+
.navi_step_list_dot {
|
|
75464
75537
|
position: absolute;
|
|
75465
75538
|
top: 17px;
|
|
75466
75539
|
left: var(--step-dot-x);
|
|
@@ -75468,18 +75541,18 @@ const css$2 = /* css */`
|
|
|
75468
75541
|
height: 30px;
|
|
75469
75542
|
border-radius: 50%;
|
|
75470
75543
|
translate: -50% -50%;
|
|
75471
|
-
|
|
75544
|
+
pointer-events: none;
|
|
75472
75545
|
}
|
|
75473
|
-
.navi_step_list_step:hover
|
|
75474
|
-
.navi_step_list_step[data-hover]
|
|
75546
|
+
.navi_step_list_step:hover .navi_step_list_dot,
|
|
75547
|
+
.navi_step_list_step[data-hover] .navi_step_list_dot {
|
|
75475
75548
|
background: color-mix(in srgb, var(--x-step-list-accent) 15%, transparent);
|
|
75476
75549
|
}
|
|
75477
75550
|
.navi_step_list .navi_step_list_step:hover,
|
|
75478
75551
|
.navi_step_list .navi_step_list_step[data-hover] {
|
|
75479
75552
|
--button-color: var(--x-step-list-current-color);
|
|
75480
75553
|
}
|
|
75481
|
-
.navi_step_list_step:focus-visible
|
|
75482
|
-
.navi_step_list_step[data-focus-visible]
|
|
75554
|
+
.navi_step_list_step:focus-visible .navi_step_list_dot,
|
|
75555
|
+
.navi_step_list_step[data-focus-visible] .navi_step_list_dot {
|
|
75483
75556
|
outline-width: var(--navi-focus-outline-width);
|
|
75484
75557
|
outline-style: solid;
|
|
75485
75558
|
outline-color: var(--navi-focus-outline-color);
|
|
@@ -75507,28 +75580,24 @@ const EDGE_INSET = 30;
|
|
|
75507
75580
|
// halo of a current dot not to sit on the line.
|
|
75508
75581
|
const LINE_GAP = 5;
|
|
75509
75582
|
|
|
75583
|
+
// What the Items say to the list holding them (see Step): where to write
|
|
75584
|
+
// themselves down. Null outside any list — a Step alone renders nothing and
|
|
75585
|
+
// registers nowhere.
|
|
75586
|
+
const StepListContext = createContext(null);
|
|
75587
|
+
|
|
75510
75588
|
/**
|
|
75511
75589
|
* @type {import("ignore:preact").FunctionComponent<{
|
|
75512
75590
|
* current?: string,
|
|
75513
|
-
* reached?: string,
|
|
75514
|
-
* reachable?: string,
|
|
75515
75591
|
* slideContainer?: string,
|
|
75516
75592
|
* travelByClick?: boolean,
|
|
75517
75593
|
* travelByKeyboard?: boolean,
|
|
75594
|
+
* duration?: string,
|
|
75518
75595
|
* [key: string]: any,
|
|
75519
75596
|
* }>}
|
|
75520
75597
|
* @param {string} [current] - the step being looked at: its dot gets the
|
|
75521
75598
|
* halo, its label the emphasis. Omit for "nowhere" — a confirmation
|
|
75522
75599
|
* screen after the walk, say. With `slideContainer` the position is read
|
|
75523
75600
|
* 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
75601
|
* @param {string} [slideContainer] - id of a <SlideContainer> these steps
|
|
75533
75602
|
* are the slides of. Pressing a step travels there
|
|
75534
75603
|
* (--navi-go-to-slide), the halo follows the container — drags included —
|
|
@@ -75545,14 +75614,16 @@ const LINE_GAP = 5;
|
|
|
75545
75614
|
* CONTAINER — this element is a follower, so a press here already walks
|
|
75546
75615
|
* the slides, and the container's own `travelByKeyboard` is the one that
|
|
75547
75616
|
* says so. One owner per mode, or one arrow would do both.
|
|
75617
|
+
* @param {string} [duration] - how long a movement takes (the path
|
|
75618
|
+
* sweeping, the halo sliding), any CSS duration. 300ms unless said —
|
|
75619
|
+
* here, or from outside via --step-list-duration.
|
|
75548
75620
|
*/
|
|
75549
75621
|
const StepList = ({
|
|
75550
75622
|
current,
|
|
75551
|
-
reached,
|
|
75552
|
-
reachable,
|
|
75553
75623
|
slideContainer,
|
|
75554
75624
|
travelByClick = true,
|
|
75555
75625
|
travelByKeyboard = true,
|
|
75626
|
+
duration,
|
|
75556
75627
|
children,
|
|
75557
75628
|
...rest
|
|
75558
75629
|
}) => {
|
|
@@ -75584,11 +75655,33 @@ const StepList = ({
|
|
|
75584
75655
|
direction: "x"
|
|
75585
75656
|
});
|
|
75586
75657
|
|
|
75587
|
-
// The
|
|
75588
|
-
//
|
|
75589
|
-
|
|
75590
|
-
|
|
75591
|
-
|
|
75658
|
+
// The roll call: every render of this list opens a fresh page, the Items
|
|
75659
|
+
// rendering below write themselves on it (in rendering order, which is the
|
|
75660
|
+
// order of the steps), and the layout effect reads the page back. What was
|
|
75661
|
+
// read is STATE — the first render knows no steps, the effect's render
|
|
75662
|
+
// draws them — and a change in what the Items say (a done toggled) flows
|
|
75663
|
+
// the same way: fresh page, fresh read, redraw.
|
|
75664
|
+
const registryRef = useRef(null);
|
|
75665
|
+
if (!registryRef.current) {
|
|
75666
|
+
registryRef.current = {
|
|
75667
|
+
renderedSteps: []
|
|
75668
|
+
};
|
|
75669
|
+
}
|
|
75670
|
+
const registry = registryRef.current;
|
|
75671
|
+
registry.renderedSteps = [];
|
|
75672
|
+
const [steps, setSteps] = useState([]);
|
|
75673
|
+
useLayoutEffect(() => {
|
|
75674
|
+
const collected = registry.renderedSteps;
|
|
75675
|
+
// An empty page while steps are known: the children were most likely
|
|
75676
|
+
// bailed out of rendering (memoized vnodes), not removed — keeping the
|
|
75677
|
+
// known steps beats erasing the drawing (see the caveat in the top
|
|
75678
|
+
// comment).
|
|
75679
|
+
if (collected.length === 0 && steps.length > 0) {
|
|
75680
|
+
return;
|
|
75681
|
+
}
|
|
75682
|
+
setSteps(previous => sameSteps(previous, collected) ? previous : [...collected]);
|
|
75683
|
+
});
|
|
75684
|
+
const stepCount = steps.length;
|
|
75592
75685
|
const dotXs = [];
|
|
75593
75686
|
if (width > 0 && stepCount > 0) {
|
|
75594
75687
|
const span = width - EDGE_INSET * 2;
|
|
@@ -75598,7 +75691,7 @@ const StepList = ({
|
|
|
75598
75691
|
index++;
|
|
75599
75692
|
}
|
|
75600
75693
|
}
|
|
75601
|
-
const indexOf = value =>
|
|
75694
|
+
const indexOf = value => steps.findIndex(step => step.value === value);
|
|
75602
75695
|
|
|
75603
75696
|
// Where the slides are, read off the container: which slide is current,
|
|
75604
75697
|
// and — while a travel or a drag is playing — which one the picture leans
|
|
@@ -75656,19 +75749,31 @@ const StepList = ({
|
|
|
75656
75749
|
}, [slideContainer, width, stepCount]);
|
|
75657
75750
|
const resolvedCurrent = slideContainer ? containerCurrent : current;
|
|
75658
75751
|
const currentIndex = resolvedCurrent === undefined ? -1 : indexOf(resolvedCurrent);
|
|
75659
|
-
|
|
75660
|
-
|
|
75661
|
-
|
|
75662
|
-
|
|
75663
|
-
|
|
75664
|
-
|
|
75665
|
-
|
|
75666
|
-
|
|
75752
|
+
// The path, deduced from what the Items say: the steps answered without a
|
|
75753
|
+
// gap from the start. -1 when the first step is not answered yet — there
|
|
75754
|
+
// is no path then, only dots.
|
|
75755
|
+
let pathEndIndex = steps.findIndex(step => !step.done);
|
|
75756
|
+
if (pathEndIndex === -1) {
|
|
75757
|
+
pathEndIndex = stepCount;
|
|
75758
|
+
}
|
|
75759
|
+
pathEndIndex -= 1;
|
|
75760
|
+
// How far the fill goes: nowhere while nothing is answered; past the last
|
|
75761
|
+
// dot (radius plus stroke) when everything is; otherwise THROUGH the
|
|
75762
|
+
// answered prefix and onward to the edge of the next dot — the segment of
|
|
75763
|
+
// appetite (see the top comment), with the dot it points at left empty.
|
|
75764
|
+
let fillX;
|
|
75765
|
+
if (pathEndIndex === -1) {
|
|
75766
|
+
fillX = 0;
|
|
75767
|
+
} else if (pathEndIndex >= stepCount - 1) {
|
|
75768
|
+
fillX = dotXs[stepCount - 1] + DOT_R + 3;
|
|
75769
|
+
} else {
|
|
75770
|
+
fillX = dotXs[pathEndIndex + 1] - DOT_R - LINE_GAP;
|
|
75771
|
+
}
|
|
75667
75772
|
const cy = RAIL_H / 2;
|
|
75668
75773
|
const slotWidth = dotXs.length > 1 ? dotXs[1] - dotXs[0] : width;
|
|
75669
75774
|
const renderRail = filled => jsx("svg", {
|
|
75670
75775
|
className: filled ? "navi_step_list_rail navi_step_list_rail_filled" : "navi_step_list_rail",
|
|
75671
|
-
style: filled
|
|
75776
|
+
style: filled ? {
|
|
75672
75777
|
clipPath: `inset(0 ${width - fillX}px 0 0)`
|
|
75673
75778
|
} : undefined,
|
|
75674
75779
|
width: width,
|
|
@@ -75676,9 +75781,10 @@ const StepList = ({
|
|
|
75676
75781
|
viewBox: `0 0 ${width} ${RAIL_H}`,
|
|
75677
75782
|
"aria-hidden": "true",
|
|
75678
75783
|
children: dotXs.map((x, index) => jsxs("g", {
|
|
75679
|
-
// Base layer only:
|
|
75680
|
-
//
|
|
75784
|
+
// Base layer only: dots the path covers are drawn filled by the
|
|
75785
|
+
// layer above anyway (see the css).
|
|
75681
75786
|
"data-current": !filled && index === currentIndex ? "" : undefined,
|
|
75787
|
+
"data-done": !filled && steps[index].done ? "" : undefined,
|
|
75682
75788
|
children: [index > 0 ? jsx("line", {
|
|
75683
75789
|
x1: dotXs[index - 1] + DOT_R + LINE_GAP,
|
|
75684
75790
|
y1: cy,
|
|
@@ -75695,9 +75801,9 @@ const StepList = ({
|
|
|
75695
75801
|
"text-anchor": "middle",
|
|
75696
75802
|
children: index + 1
|
|
75697
75803
|
})]
|
|
75698
|
-
},
|
|
75804
|
+
}, steps[index].value))
|
|
75699
75805
|
});
|
|
75700
|
-
return
|
|
75806
|
+
return jsxs(Box, {
|
|
75701
75807
|
...rest,
|
|
75702
75808
|
ref: rootRef,
|
|
75703
75809
|
baseClassName: "navi_step_list",
|
|
@@ -75710,13 +75816,14 @@ const StepList = ({
|
|
|
75710
75816
|
"data-slide-container-follows": slideContainer,
|
|
75711
75817
|
style: {
|
|
75712
75818
|
...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]
|
|
75819
|
+
...(duration ? {
|
|
75820
|
+
"--step-list-duration": duration
|
|
75717
75821
|
} : undefined)
|
|
75718
75822
|
},
|
|
75719
|
-
children:
|
|
75823
|
+
children: [jsx(StepListContext.Provider, {
|
|
75824
|
+
value: registry,
|
|
75825
|
+
children: children
|
|
75826
|
+
}), width > 0 && stepCount > 0 ? jsxs(Fragment$1, {
|
|
75720
75827
|
children: [renderRail(false), renderRail(true), currentIndex !== -1 && dotXs[currentIndex] !== undefined ? jsx("svg", {
|
|
75721
75828
|
className: "navi_step_list_rail",
|
|
75722
75829
|
width: width,
|
|
@@ -75738,15 +75845,7 @@ const StepList = ({
|
|
|
75738
75845
|
r: RING_R
|
|
75739
75846
|
})
|
|
75740
75847
|
})
|
|
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;
|
|
75848
|
+
}) : null, steps.map((step, index) => {
|
|
75750
75849
|
// The slots tile the row, cut at the container's edges: the
|
|
75751
75850
|
// first and the last cover only the inner half of the room an
|
|
75752
75851
|
// interior slot gets, so pressing just outside the box presses
|
|
@@ -75762,8 +75861,8 @@ const StepList = ({
|
|
|
75762
75861
|
"width": `${slotRight - slotLeft}px`,
|
|
75763
75862
|
"--step-dot-x": `${dotXs[index] - slotLeft}px`
|
|
75764
75863
|
},
|
|
75765
|
-
children:
|
|
75766
|
-
...
|
|
75864
|
+
children: jsxs(Button, {
|
|
75865
|
+
...step.buttonProps,
|
|
75767
75866
|
// bare, not discrete: what is drawn IS the dot and its
|
|
75768
75867
|
// label — the hover wash a discrete button paints over its
|
|
75769
75868
|
// whole surface is exactly what must not appear here (the
|
|
@@ -75776,38 +75875,105 @@ const StepList = ({
|
|
|
75776
75875
|
// Towards the slides when connected, by name: the command
|
|
75777
75876
|
// reaches the container wherever this list sits on the
|
|
75778
75877
|
// page. What else a press should do is the Item's own
|
|
75779
|
-
// onClick, which arrived through
|
|
75878
|
+
// onClick, which arrived through buttonProps.
|
|
75780
75879
|
,
|
|
75781
75880
|
|
|
75782
|
-
command: slideContainer && travelByClick ? `--navi-go-to-slide:${value}` : undefined,
|
|
75783
|
-
commandFor: slideContainer
|
|
75784
|
-
|
|
75881
|
+
command: slideContainer && travelByClick ? `--navi-go-to-slide:${step.value}` : undefined,
|
|
75882
|
+
commandFor: slideContainer
|
|
75883
|
+
// A message about a step (a callout) points at its circle,
|
|
75884
|
+
// above it: the label lives below.
|
|
75885
|
+
,
|
|
75886
|
+
|
|
75887
|
+
"data-callout-anchor": ".navi_step_list_dot",
|
|
75888
|
+
"data-callout-position": "top",
|
|
75889
|
+
children: [jsx("span", {
|
|
75890
|
+
className: "navi_step_list_dot",
|
|
75891
|
+
"aria-hidden": "true"
|
|
75892
|
+
}), jsx("span", {
|
|
75785
75893
|
className: "navi_step_list_label",
|
|
75786
|
-
children:
|
|
75787
|
-
})
|
|
75894
|
+
children: step.label
|
|
75895
|
+
})]
|
|
75788
75896
|
})
|
|
75789
|
-
}, value);
|
|
75897
|
+
}, step.value);
|
|
75790
75898
|
})]
|
|
75791
|
-
}) : null
|
|
75899
|
+
}) : null]
|
|
75792
75900
|
});
|
|
75793
75901
|
};
|
|
75794
75902
|
|
|
75903
|
+
// The same steps saying the same things: nothing to redraw. The labels are
|
|
75904
|
+
// vnodes, fresh objects on every render — comparing them would always say
|
|
75905
|
+
// "changed", so they are left out: what they show changes through the state
|
|
75906
|
+
// it came from, which re-renders this list anyway.
|
|
75907
|
+
const sameSteps = (previousSteps, nextSteps) => {
|
|
75908
|
+
if (previousSteps.length !== nextSteps.length) {
|
|
75909
|
+
return false;
|
|
75910
|
+
}
|
|
75911
|
+
let index = 0;
|
|
75912
|
+
while (index < previousSteps.length) {
|
|
75913
|
+
const previous = previousSteps[index];
|
|
75914
|
+
const next = nextSteps[index];
|
|
75915
|
+
if (previous.value !== next.value || previous.done !== next.done) {
|
|
75916
|
+
return false;
|
|
75917
|
+
}
|
|
75918
|
+
if (!sameShallow(previous.buttonProps, next.buttonProps)) {
|
|
75919
|
+
return false;
|
|
75920
|
+
}
|
|
75921
|
+
index++;
|
|
75922
|
+
}
|
|
75923
|
+
return true;
|
|
75924
|
+
};
|
|
75925
|
+
const sameShallow = (previousObject, nextObject) => {
|
|
75926
|
+
const previousKeys = Object.keys(previousObject);
|
|
75927
|
+
const nextKeys = Object.keys(nextObject);
|
|
75928
|
+
if (previousKeys.length !== nextKeys.length) {
|
|
75929
|
+
return false;
|
|
75930
|
+
}
|
|
75931
|
+
for (const key of previousKeys) {
|
|
75932
|
+
if (previousObject[key] !== nextObject[key]) {
|
|
75933
|
+
return false;
|
|
75934
|
+
}
|
|
75935
|
+
}
|
|
75936
|
+
return true;
|
|
75937
|
+
};
|
|
75938
|
+
|
|
75795
75939
|
/**
|
|
75796
|
-
* One step of the walk: `value` names it (what `current
|
|
75797
|
-
*
|
|
75798
|
-
*
|
|
75940
|
+
* One step of the walk: `value` names it (what `current` says and what a
|
|
75941
|
+
* press reports), `done` says it is answered (its dot fills, and the path is
|
|
75942
|
+
* deduced from the answered steps), the children are its label.
|
|
75943
|
+
*
|
|
75944
|
+
* It renders NOTHING: it registers with the list around it as it renders,
|
|
75945
|
+
* and the list draws everything — the dot, the label, the button. Whatever
|
|
75946
|
+
* else it carries (onClick, pseudoState, aria-*) lands on that button.
|
|
75799
75947
|
*
|
|
75800
75948
|
* It is both StepList.Item and an export of its own, the way Slide is to
|
|
75801
75949
|
* SlideContainer.
|
|
75802
75950
|
*
|
|
75803
75951
|
* @type {import("ignore:preact").FunctionComponent<{
|
|
75804
75952
|
* value: string,
|
|
75953
|
+
* done?: boolean,
|
|
75805
75954
|
* [key: string]: any,
|
|
75806
75955
|
* }>}
|
|
75956
|
+
* @param {boolean} [done] - this step is answered: its dot is filled — the
|
|
75957
|
+
* fill's one meaning. Steps answered out of order are filled dots
|
|
75958
|
+
* standing alone, dashed segments around them.
|
|
75807
75959
|
*/
|
|
75808
75960
|
const Step = ({
|
|
75809
|
-
|
|
75810
|
-
|
|
75961
|
+
value,
|
|
75962
|
+
done,
|
|
75963
|
+
children,
|
|
75964
|
+
...buttonProps
|
|
75965
|
+
}) => {
|
|
75966
|
+
const registry = useContext(StepListContext);
|
|
75967
|
+
if (registry) {
|
|
75968
|
+
registry.renderedSteps.push({
|
|
75969
|
+
value: value ?? String(registry.renderedSteps.length),
|
|
75970
|
+
done: Boolean(done),
|
|
75971
|
+
label: children,
|
|
75972
|
+
buttonProps
|
|
75973
|
+
});
|
|
75974
|
+
}
|
|
75975
|
+
return null;
|
|
75976
|
+
};
|
|
75811
75977
|
StepList.Item = Step;
|
|
75812
75978
|
|
|
75813
75979
|
installImportMetaCssBuild(import.meta);const css$1 = /* css */`
|