@jsenv/navi 0.29.505 → 0.29.507
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/dist/dev/jsenv_navi.js +187 -36
- package/dist/dev/jsenv_navi.js.map +4 -4
- package/dist/jsenv_navi.js +188 -37
- package/dist/jsenv_navi.js.map +4 -4
- package/docs/drag_to_travel.md +4 -0
- package/docs/state_binding.md +28 -0
- package/package.json +4 -4
package/dist/jsenv_navi.js
CHANGED
|
@@ -50092,7 +50092,7 @@ const useControlProps = (props, {
|
|
|
50092
50092
|
}
|
|
50093
50093
|
const domProps = toDomProps(newUIState);
|
|
50094
50094
|
Object.assign(el, domProps);
|
|
50095
|
-
debugUIState(e, `syncDomState: updated to ${getElementSignature(el)}
|
|
50095
|
+
debugUIState(e, `syncDomState: updated to ${getElementSignature(el)}`);
|
|
50096
50096
|
};
|
|
50097
50097
|
const controlInfo = createControlInfo(props, {
|
|
50098
50098
|
controlType
|
|
@@ -68014,6 +68014,40 @@ const causeOfEvent = event => {
|
|
|
68014
68014
|
// into says (see writeAreaAsked).
|
|
68015
68015
|
const CAUSES_WRITTEN_BY_REPLACEMENT = ["drag", "refusal", "state"];
|
|
68016
68016
|
const readArea = slideElement => slideElement.getAttribute("data-slide-area") || slideElement.id || "";
|
|
68017
|
+
const slidesOf = containerElement => Array.from(containerElement.querySelectorAll(":scope > [data-slide-track] > [data-slide]"));
|
|
68018
|
+
|
|
68019
|
+
// Who is drawing something about a box from outside it: a tab bar saying where
|
|
68020
|
+
// one is, a row of dots. They name the box they follow by its id, the way
|
|
68021
|
+
// everything else that talks to it across the document does (commandfor).
|
|
68022
|
+
const readFollowerElements = containerElement => {
|
|
68023
|
+
const {
|
|
68024
|
+
id
|
|
68025
|
+
} = containerElement;
|
|
68026
|
+
if (!id) {
|
|
68027
|
+
return [];
|
|
68028
|
+
}
|
|
68029
|
+
return Array.from(document.querySelectorAll(`[data-slide-container-follows="${CSS.escape(id)}"]`));
|
|
68030
|
+
};
|
|
68031
|
+
|
|
68032
|
+
// The containers inside a slide bound to the same state as the slide's own
|
|
68033
|
+
// container (see `signal`) — the ones directly under it, a container sharing
|
|
68034
|
+
// with one of those is that one's business.
|
|
68035
|
+
const sharingContainersIn = slideElement => {
|
|
68036
|
+
const holderElement = slideElement.closest("[data-slide-container]");
|
|
68037
|
+
return Array.from(slideElement.querySelectorAll("[data-slide-shares-state]")).filter(innerElement => innerElement.parentElement.closest("[data-slide-container]") === holderElement);
|
|
68038
|
+
};
|
|
68039
|
+
|
|
68040
|
+
// Whether the state holding `area` is on screen when this slide is: it is the
|
|
68041
|
+
// slide's own area, or a slide of a container sharing the state inside it.
|
|
68042
|
+
const slideShows = (slideElement, area) => readArea(slideElement) === area || sharingContainersIn(slideElement).some(innerElement => slidesOf(innerElement).some(innerSlide => slideShows(innerSlide, area)));
|
|
68043
|
+
|
|
68044
|
+
// What the state holds while this slide is on screen: the area a container
|
|
68045
|
+
// sharing the state inside it stands on, its own area when there is none.
|
|
68046
|
+
const areaHeldOn = slideElement => {
|
|
68047
|
+
const [innerElement] = sharingContainersIn(slideElement);
|
|
68048
|
+
const innerCurrent = innerElement && slidesOf(innerElement).find(innerSlide => innerSlide.hasAttribute("data-current"));
|
|
68049
|
+
return innerCurrent ? areaHeldOn(innerCurrent) : readArea(slideElement);
|
|
68050
|
+
};
|
|
68017
68051
|
|
|
68018
68052
|
/**
|
|
68019
68053
|
* The slide shown can be driven from outside (a `signal`, or `current` +
|
|
@@ -68048,6 +68082,10 @@ const readArea = slideElement => slideElement.getAttribute("data-slide-area") ||
|
|
|
68048
68082
|
* "create"]`. Spelled like grid-template-areas ("." is a hole, a name
|
|
68049
68083
|
* repeated spans), except that a row needs no trailing hole: what is not
|
|
68050
68084
|
* written is simply not there.
|
|
68085
|
+
* A map is read as a map: a step landing on a hole is not offered. So rows
|
|
68086
|
+
* of different lengths, each walked on its own and changed as a whole (a
|
|
68087
|
+
* column of levels, a row of titles in each), are not a map but a container
|
|
68088
|
+
* in each slide of a column, all bound to one signal — see `signal`.
|
|
68051
68089
|
* @param {string} [props.current] - area (or id) of the slide being shown; omit
|
|
68052
68090
|
* to keep it here and drive it by command. An area named from outside is a
|
|
68053
68091
|
* REQUEST rather than a placement — see `signal` for what that means.
|
|
@@ -68088,6 +68126,47 @@ const readArea = slideElement => slideElement.getAttribute("data-slide-area") ||
|
|
|
68088
68126
|
* by links built to that route. Written by replacement unless the state says
|
|
68089
68127
|
* `history: "push"`, and even then a slide reached by DRAGGING replaces — see
|
|
68090
68128
|
* docs/navigation.md.
|
|
68129
|
+
* ONE STATE FOR CONTAINERS INSIDE ONE ANOTHER: a container in a slide,
|
|
68130
|
+
* bound to the SAME signal as the container holding it, shares that state.
|
|
68131
|
+
* For screens where one place is said at two levels — a column of
|
|
68132
|
+
* tournament levels with a row of titles in each, the address saying which
|
|
68133
|
+
* title (`?cup=P100:2`): the level is not a second state, it is read from
|
|
68134
|
+
* the title.
|
|
68135
|
+
* ```jsx
|
|
68136
|
+
* const cupSignal = stateSignal(undefined, { id: "cup" });
|
|
68137
|
+
*
|
|
68138
|
+
* <SlideContainer layout="column" signal={cupSignal}>
|
|
68139
|
+
* {levels.map((level) => (
|
|
68140
|
+
* <Slide area={level.name}>
|
|
68141
|
+
* <LevelHeader level={level} />
|
|
68142
|
+
* <SlideContainer signal={cupSignal} defaultCurrent={level.entryKey}>
|
|
68143
|
+
* {level.titles.map((title) => (
|
|
68144
|
+
* <Slide area={title.key}>…</Slide>
|
|
68145
|
+
* ))}
|
|
68146
|
+
* </SlideContainer>
|
|
68147
|
+
* </Slide>
|
|
68148
|
+
* ))}
|
|
68149
|
+
* </SlideContainer>
|
|
68150
|
+
* ```
|
|
68151
|
+
* - The state holds an area of an INNER container. The outer one shows the
|
|
68152
|
+
* slide holding it, the inner ones that do not have it stay where they
|
|
68153
|
+
* are.
|
|
68154
|
+
* - A travel of the outer one writes the area the inner one stands on in the
|
|
68155
|
+
* slide it arrives at: a row left keeps its place for when one comes back,
|
|
68156
|
+
* and a row not seen yet opens on its `defaultCurrent`.
|
|
68157
|
+
* - A value written from outside (an address, a traversal) is walked to by
|
|
68158
|
+
* both, each on its own axis.
|
|
68159
|
+
* - The arrows of the inner one on screen are heard on the outer box and on
|
|
68160
|
+
* what follows it (`data-slide-container-follows`), so a surface follows
|
|
68161
|
+
* the OUTER one and all four arrows walk it.
|
|
68162
|
+
* - `onCurrentChange` still tells each one its own area: the level to the
|
|
68163
|
+
* outer one, the title to the inner one.
|
|
68164
|
+
* What an outer slide holds is read in the DOM: one whose content is not
|
|
68165
|
+
* built (`mount="near"`) holds nothing the state can name.
|
|
68166
|
+
* Neither `current` + `onCurrentChange` on each, ignoring `cause: "state"`
|
|
68167
|
+
* and remembering by hand where each row was left — that is a second copy of
|
|
68168
|
+
* the state (see docs/state_binding.md) — nor one map with rows of different
|
|
68169
|
+
* lengths (see `layout`).
|
|
68091
68170
|
* @param {string} [props.defaultCurrent] - which slide to open on, for a
|
|
68092
68171
|
* container that owns its position. Mount-only, like every other `default*`:
|
|
68093
68172
|
* it says where one starts, not where one is — say `current` for that.
|
|
@@ -68097,7 +68176,8 @@ const readArea = slideElement => slideElement.getAttribute("data-slide-area") ||
|
|
|
68097
68176
|
* opens is that state's own default (`stateSignal`'s first argument) rather
|
|
68098
68177
|
* than this: one place says where the area starts, and it is the place a
|
|
68099
68178
|
* reset goes back to. This still answers for a signal holding nothing at
|
|
68100
|
-
* all.
|
|
68179
|
+
* all. And for a container sharing the state of the one holding it (see
|
|
68180
|
+
* `signal`), it is where it opens while the state names a place elsewhere.
|
|
68101
68181
|
* @param {(area: string, detail: {cause: "drag"|"keyboard"|"command"|"code"|"state", event: Event}) => void|false|Promise<void|false>} [props.onCurrentChange]
|
|
68102
68182
|
* - the slide being shown has changed. `cause` says what asked for it, which
|
|
68103
68183
|
* is what tells a place browsed past from a place aimed at — a slide dragged
|
|
@@ -68217,6 +68297,10 @@ const SlideContainer = ({
|
|
|
68217
68297
|
// The box itself: it is what takes the keyboard when what is on screen holds
|
|
68218
68298
|
// nothing that can (see handOverFocus).
|
|
68219
68299
|
const containerRef = useRef();
|
|
68300
|
+
// Bound to the state of the container holding this one: its slides are
|
|
68301
|
+
// places inside one of that container's slides (see `signal`).
|
|
68302
|
+
const holder = useContext(SlideContainerContext);
|
|
68303
|
+
const sharesState = Boolean(currentSignal) && holder?.signal === currentSignal;
|
|
68220
68304
|
// The AREA of the slide being shown, not its rank: a rank would be wrong the
|
|
68221
68305
|
// moment a slide appears before it, and there is nothing to renumber here.
|
|
68222
68306
|
// This is where the container's own answer lives, and it is the only one the
|
|
@@ -68227,7 +68311,10 @@ const SlideContainer = ({
|
|
|
68227
68311
|
// walking past every lock in exactly the case the locks are there for.
|
|
68228
68312
|
// So the picture starts where the state itself would open (a stateSignal's
|
|
68229
68313
|
// own default), or on `defaultCurrent`, and the walk goes from there.
|
|
68230
|
-
|
|
68314
|
+
// A container sharing its holder's state starts on `defaultCurrent`: the
|
|
68315
|
+
// state's default is a place in ONE of the containers sharing it, and the
|
|
68316
|
+
// one holding it is walked there like any other.
|
|
68317
|
+
const [currentAreaState, setCurrentAreaState] = useState(() => sharesState ? defaultCurrent : currentSignal?.options?.getDefaultValue?.() ?? defaultCurrent);
|
|
68231
68318
|
// The slide this container is travelling to while its controller has not been
|
|
68232
68319
|
// told yet (commit="rest"): for the length of that travel the container is
|
|
68233
68320
|
// ahead of whoever holds `current`, and this is where it keeps its own answer
|
|
@@ -68310,6 +68397,21 @@ const SlideContainer = ({
|
|
|
68310
68397
|
const followerElementsRef = useRef([]);
|
|
68311
68398
|
const currentFromCaller = currentSignal ? currentSignal.value : currentProp;
|
|
68312
68399
|
const current = rollingArea ?? provisionalArea ?? currentAreaState;
|
|
68400
|
+
// The area of this box a value held outside is shown on: the slide of that
|
|
68401
|
+
// name, or the one holding a container that shares the state and has it.
|
|
68402
|
+
// Read off the last commit, so a render before the first sees it as it is.
|
|
68403
|
+
const ownAreaOf = value => {
|
|
68404
|
+
const track = trackRef.current;
|
|
68405
|
+
if (value === undefined || !track) {
|
|
68406
|
+
return value;
|
|
68407
|
+
}
|
|
68408
|
+
const slideElements = Array.from(track.children);
|
|
68409
|
+
if (slideElements.some(slideElement => readArea(slideElement) === value)) {
|
|
68410
|
+
return value;
|
|
68411
|
+
}
|
|
68412
|
+
const holding = slideElements.find(slideElement => slideShows(slideElement, value));
|
|
68413
|
+
return holding ? readArea(holding) : value;
|
|
68414
|
+
};
|
|
68313
68415
|
// The last area this container knows the caller holds, whether it wrote it
|
|
68314
68416
|
// there or read it from there. What makes a two-way binding stop turning: an
|
|
68315
68417
|
// area held outside is an INSTRUCTION only when it changed by itself (a load,
|
|
@@ -68328,7 +68430,7 @@ const SlideContainer = ({
|
|
|
68328
68430
|
// it is painted, the first request included — and the container's own answer
|
|
68329
68431
|
// otherwise. What a slide waiting for a travel reads to have its content in
|
|
68330
68432
|
// the very render that shows it (see Slide's `mount`).
|
|
68331
|
-
const areaShownNext = requestIsNews() ? currentFromCaller : current;
|
|
68433
|
+
const areaShownNext = requestIsNews() ? ownAreaOf(currentFromCaller) : current;
|
|
68332
68434
|
// Where the container stands, said where the caller holds it.
|
|
68333
68435
|
//
|
|
68334
68436
|
// Whether a slide is a place one came from is the STATE's own business (see
|
|
@@ -68345,17 +68447,31 @@ const SlideContainer = ({
|
|
|
68345
68447
|
const writeAreaAsked = (area, {
|
|
68346
68448
|
cause
|
|
68347
68449
|
} = {}) => {
|
|
68348
|
-
areaAskedSeenRef.current = area;
|
|
68349
68450
|
if (!currentSignal) {
|
|
68451
|
+
areaAskedSeenRef.current = area;
|
|
68350
68452
|
return;
|
|
68351
68453
|
}
|
|
68454
|
+
const value = valueOfArea(area);
|
|
68455
|
+
areaAskedSeenRef.current = value;
|
|
68352
68456
|
if (CAUSES_WRITTEN_BY_REPLACEMENT.includes(cause) && currentSignal.set) {
|
|
68353
|
-
currentSignal.set(
|
|
68457
|
+
currentSignal.set(value, {
|
|
68354
68458
|
history: "replace"
|
|
68355
68459
|
});
|
|
68356
68460
|
return;
|
|
68357
68461
|
}
|
|
68358
|
-
currentSignal.value =
|
|
68462
|
+
currentSignal.value = value;
|
|
68463
|
+
};
|
|
68464
|
+
// What the state holds for one of this box's areas: the place a container
|
|
68465
|
+
// sharing it stands on inside that slide (see areaHeldOn). A state already
|
|
68466
|
+
// naming a place in that slide is kept as it is — a container in there may
|
|
68467
|
+
// have written it in this very commit, before its DOM says so.
|
|
68468
|
+
const valueOfArea = area => {
|
|
68469
|
+
const held = currentSignal.peek();
|
|
68470
|
+
if (held !== area && ownAreaOf(held) === area) {
|
|
68471
|
+
return held;
|
|
68472
|
+
}
|
|
68473
|
+
const slideElement = readMap().slideElements.find(slideElement => readArea(slideElement) === area);
|
|
68474
|
+
return slideElement ? areaHeldOn(slideElement) : area;
|
|
68359
68475
|
};
|
|
68360
68476
|
const vertical = layout === "column";
|
|
68361
68477
|
// What the map has, and what each way of asking is allowed to use of it.
|
|
@@ -68407,7 +68523,7 @@ const SlideContainer = ({
|
|
|
68407
68523
|
if (provisionalArea === null) {
|
|
68408
68524
|
return;
|
|
68409
68525
|
}
|
|
68410
|
-
const heldOutside = currentFromCaller ?? currentAreaState;
|
|
68526
|
+
const heldOutside = ownAreaOf(currentFromCaller) ?? currentAreaState;
|
|
68411
68527
|
if (heldOutside === provisionalArea) {
|
|
68412
68528
|
setProvisionalArea(null);
|
|
68413
68529
|
}
|
|
@@ -68498,20 +68614,6 @@ const SlideContainer = ({
|
|
|
68498
68614
|
};
|
|
68499
68615
|
};
|
|
68500
68616
|
|
|
68501
|
-
// Who is drawing something about this box from outside it: a tab bar saying
|
|
68502
|
-
// where one is, a row of dots. They name the box they follow by its id, the
|
|
68503
|
-
// way everything else that talks to it across the document does (commandfor).
|
|
68504
|
-
const readFollowerElements = () => {
|
|
68505
|
-
const containerEl = containerRef.current;
|
|
68506
|
-
const {
|
|
68507
|
-
id
|
|
68508
|
-
} = containerEl;
|
|
68509
|
-
if (!id) {
|
|
68510
|
-
return [];
|
|
68511
|
-
}
|
|
68512
|
-
return Array.from(document.querySelectorAll(`[data-slide-container-follows="${CSS.escape(id)}"]`));
|
|
68513
|
-
};
|
|
68514
|
-
|
|
68515
68617
|
// Which slide is on screen, said in the DOM: it is what anything outside the
|
|
68516
68618
|
// box reads to know where one is (a tab bar marking its current tab), and
|
|
68517
68619
|
// there is nothing else for it to read — a slide the container holds by
|
|
@@ -68650,7 +68752,7 @@ const SlideContainer = ({
|
|
|
68650
68752
|
// Read on every render rather than subscribed to: a follower says who it
|
|
68651
68753
|
// follows in the DOM, and the render that mounted one is the render this
|
|
68652
68754
|
// runs after.
|
|
68653
|
-
followerElementsRef.current = readFollowerElements();
|
|
68755
|
+
followerElementsRef.current = readFollowerElements(containerRef.current);
|
|
68654
68756
|
const {
|
|
68655
68757
|
slideElements,
|
|
68656
68758
|
placeOf
|
|
@@ -68923,7 +69025,7 @@ const SlideContainer = ({
|
|
|
68923
69025
|
// this one, in the same commit, and the slides around a picture about to be
|
|
68924
69026
|
// walked away from would be built for nothing. The neighbours only at
|
|
68925
69027
|
// rest, see renderNear.
|
|
68926
|
-
const settlingArea = requestIsNews() && reachableTowards(currentArea, currentFromCaller) || currentArea;
|
|
69028
|
+
const settlingArea = requestIsNews() && reachableTowards(currentArea, ownAreaOf(currentFromCaller)) || currentArea;
|
|
68927
69029
|
renderNear(settlingArea, {
|
|
68928
69030
|
alongside: !stageRef.current
|
|
68929
69031
|
});
|
|
@@ -69173,8 +69275,11 @@ const SlideContainer = ({
|
|
|
69173
69275
|
// content arrives a request later. Not a refusal: nothing is remembered and
|
|
69174
69276
|
// nothing is written, and the render that brings the slide asks again. A
|
|
69175
69277
|
// name that will never be a slide is the state's to refuse (`oneOf`), not
|
|
69176
|
-
// the container's: from here, "later" and "never" look the same.
|
|
69177
|
-
|
|
69278
|
+
// the container's: from here, "later" and "never" look the same. Nor is a
|
|
69279
|
+
// place shown by another container sharing the state — a row of a column
|
|
69280
|
+
// of rows stays where it was while the state names a place in another one.
|
|
69281
|
+
const areaAsked = ownAreaOf(currentFromCaller);
|
|
69282
|
+
if (!readMap().slideElements.some(slideElement => readArea(slideElement) === areaAsked)) {
|
|
69178
69283
|
return;
|
|
69179
69284
|
}
|
|
69180
69285
|
areaAskedSeenRef.current = currentFromCaller;
|
|
@@ -69182,10 +69287,10 @@ const SlideContainer = ({
|
|
|
69182
69287
|
// names a slide, and the container standing on its first one is a fact only
|
|
69183
69288
|
// the map knows (see the layout effect that paints it).
|
|
69184
69289
|
const areaOnScreen = containerRef.current.getAttribute(SLIDE_CURRENT_ATTRIBUTE);
|
|
69185
|
-
if (
|
|
69290
|
+
if (areaAsked === areaOnScreen) {
|
|
69186
69291
|
return;
|
|
69187
69292
|
}
|
|
69188
|
-
const reached = reachableTowards(areaOnScreen,
|
|
69293
|
+
const reached = reachableTowards(areaOnScreen, areaAsked);
|
|
69189
69294
|
if (reached && reached !== areaOnScreen) {
|
|
69190
69295
|
// Told rather than asked: the walk above has already put every lock on
|
|
69191
69296
|
// the way the question goToArea would have put the first one, and this
|
|
@@ -69614,7 +69719,7 @@ const SlideContainer = ({
|
|
|
69614
69719
|
// Read again at the start of every travel, not only at every render: a
|
|
69615
69720
|
// follower appearing does not make this box render, and the travel it must
|
|
69616
69721
|
// draw is the one about to start.
|
|
69617
|
-
followerElementsRef.current = readFollowerElements();
|
|
69722
|
+
followerElementsRef.current = readFollowerElements(containerRef.current);
|
|
69618
69723
|
cancelTravelProgressAnimation();
|
|
69619
69724
|
paintTravelProgress(0);
|
|
69620
69725
|
const painters = travelPainters();
|
|
@@ -69927,7 +70032,7 @@ const SlideContainer = ({
|
|
|
69927
70032
|
trackAnimationRef.current?.cancel();
|
|
69928
70033
|
trackAnimationRef.current = null;
|
|
69929
70034
|
cancelTravelProgressAnimation();
|
|
69930
|
-
followerElementsRef.current = readFollowerElements();
|
|
70035
|
+
followerElementsRef.current = readFollowerElements(containerRef.current);
|
|
69931
70036
|
drag.axis = axis;
|
|
69932
70037
|
drag.areaBack = areaBack;
|
|
69933
70038
|
drag.areaOn = areaOn;
|
|
@@ -70315,6 +70420,35 @@ const SlideContainer = ({
|
|
|
70315
70420
|
}
|
|
70316
70421
|
};
|
|
70317
70422
|
});
|
|
70423
|
+
// A container sharing the state of the one holding it is part of that one's
|
|
70424
|
+
// surface: the arrows it walks are heard on the holder's box and on what
|
|
70425
|
+
// follows it, while its slide is the one on screen — a row of a column of
|
|
70426
|
+
// rows walks sideways with the keyboard on the column, or on a chevron of
|
|
70427
|
+
// the column. A press something already travelled on is left alone (it is
|
|
70428
|
+
// marked, see applyKeyboardShortcuts), and so is one pressed inside this box,
|
|
70429
|
+
// which heard it first.
|
|
70430
|
+
useLayoutEffect(() => {
|
|
70431
|
+
const holderElement = sharesState && holder.containerRef.current;
|
|
70432
|
+
if (!holderElement) {
|
|
70433
|
+
return undefined;
|
|
70434
|
+
}
|
|
70435
|
+
const surfaceElements = [holderElement, ...readFollowerElements(holderElement)];
|
|
70436
|
+
const onSurfaceKeyDown = keyDownEvent => {
|
|
70437
|
+
const containerEl = containerRef.current;
|
|
70438
|
+
if (keyDownEvent.defaultPrevented || !containerEl || containerEl.contains(keyDownEvent.target) || !containerEl.closest("[data-slide]")?.hasAttribute("data-current")) {
|
|
70439
|
+
return;
|
|
70440
|
+
}
|
|
70441
|
+
onKeyDownShortcuts(keyDownEvent);
|
|
70442
|
+
};
|
|
70443
|
+
for (const surfaceElement of surfaceElements) {
|
|
70444
|
+
surfaceElement.addEventListener("keydown", onSurfaceKeyDown);
|
|
70445
|
+
}
|
|
70446
|
+
return () => {
|
|
70447
|
+
for (const surfaceElement of surfaceElements) {
|
|
70448
|
+
surfaceElement.removeEventListener("keydown", onSurfaceKeyDown);
|
|
70449
|
+
}
|
|
70450
|
+
};
|
|
70451
|
+
});
|
|
70318
70452
|
return (
|
|
70319
70453
|
// Box rather than a plain div: it is how every navi component takes the
|
|
70320
70454
|
// onnavi_* handlers below — they are navi's own event names, and Box is
|
|
@@ -70324,6 +70458,10 @@ const SlideContainer = ({
|
|
|
70324
70458
|
ref: containerRef,
|
|
70325
70459
|
baseClassName: "navi_slide_container",
|
|
70326
70460
|
"data-slide-container": ""
|
|
70461
|
+
// What the holder reads to show the slide holding the place the state
|
|
70462
|
+
// names, and to write the place this box stands on (see `signal`).
|
|
70463
|
+
,
|
|
70464
|
+
"data-slide-shares-state": sharesState ? "" : undefined
|
|
70327
70465
|
// Which axes a touch may travel on, said in the DOM: what the browser
|
|
70328
70466
|
// does with a finger is decided by CSS (touch-action) before any of this
|
|
70329
70467
|
// has seen the gesture — and it is also what a box HOLDING this one reads
|
|
@@ -70465,6 +70603,9 @@ const SlideContainer = ({
|
|
|
70465
70603
|
areaShownNext,
|
|
70466
70604
|
nearAreas,
|
|
70467
70605
|
claimOpening: areaShownNext === undefined ? claimOpening : null,
|
|
70606
|
+
// What a container nested in a slide compares its own with, to
|
|
70607
|
+
// know it shares this state (see `signal`).
|
|
70608
|
+
signal: currentSignal,
|
|
70468
70609
|
// The box itself, for what is written INSIDE it to read the same
|
|
70469
70610
|
// facts what is written outside reads by id (useSlideContainer):
|
|
70470
70611
|
// a way out is a way out on either side of the box.
|
|
@@ -82942,7 +83083,8 @@ const SelectableInput = SelectableInputProxy;
|
|
|
82942
83083
|
* The `highlight` argument of `useSearchHighlight` (a row's `matchInfo.matchRanges`) can be:
|
|
82943
83084
|
* - an array of [start, end] pairs — applied to all text nodes under the root element
|
|
82944
83085
|
* - an object { [domSelector]: [[start, end], …] } — applied to each sub-element
|
|
82945
|
-
* matched by the selector (the format produced by createSearch)
|
|
83086
|
+
* matched by the selector (the format produced by createSearch); a selector
|
|
83087
|
+
* matching nothing under the root element marks nothing
|
|
82946
83088
|
*/
|
|
82947
83089
|
|
|
82948
83090
|
// Module-level shared Highlight instance — created lazily once.
|
|
@@ -82988,10 +83130,12 @@ const applySearchHighlight = (el, highlight) => {
|
|
|
82988
83130
|
? highlight.length === 0
|
|
82989
83131
|
? []
|
|
82990
83132
|
: [{ root: el, ranges: highlight }]
|
|
82991
|
-
: Object.entries(highlight).
|
|
82992
|
-
|
|
82993
|
-
|
|
82994
|
-
|
|
83133
|
+
: Object.entries(highlight).flatMap(([selector, ranges]) => {
|
|
83134
|
+
// The ranges are offsets into the selected element's text: an item
|
|
83135
|
+
// that doesn't render it has nothing to mark.
|
|
83136
|
+
const root = el.querySelector(selector);
|
|
83137
|
+
return root ? [{ root, ranges }] : [];
|
|
83138
|
+
});
|
|
82995
83139
|
|
|
82996
83140
|
if (entries.length === 0) {
|
|
82997
83141
|
return undefined;
|
|
@@ -96738,7 +96882,12 @@ const mergeRanges = (ranges) => {
|
|
|
96738
96882
|
*
|
|
96739
96883
|
* Each field config:
|
|
96740
96884
|
* - getter(item): string — extracts the text to search
|
|
96741
|
-
* - domSelector
|
|
96885
|
+
* - domSelector?: string — CSS selector used by ListItem to find the target element.
|
|
96886
|
+
* Without it, the field is searched and scored but highlights
|
|
96887
|
+
* nothing: text the item doesn't write (an alias, a civil name
|
|
96888
|
+
* under a nickname, tags). One field per selector: the ranges
|
|
96889
|
+
* of two fields sharing one are offsets into two different
|
|
96890
|
+
* strings, so the last field wins.
|
|
96742
96891
|
* - priority?: number — multiplier applied to the field's score (default 1)
|
|
96743
96892
|
* - matchFn?: function — custom match function (searchText, fieldValue) => { match, matchScore, matchRanges }
|
|
96744
96893
|
* defaults to applySearch
|
|
@@ -96758,7 +96907,9 @@ const createSearch = (fields) => {
|
|
|
96758
96907
|
const result = matchFn(searchText, fieldValue);
|
|
96759
96908
|
if (result.match && result.matchRanges.length > 0) {
|
|
96760
96909
|
totalScore += result.matchScore * priority;
|
|
96761
|
-
|
|
96910
|
+
if (domSelector) {
|
|
96911
|
+
matchRanges[domSelector] = result.matchRanges;
|
|
96912
|
+
}
|
|
96762
96913
|
}
|
|
96763
96914
|
}
|
|
96764
96915
|
if (totalScore === 0) {
|