@jsenv/navi 0.29.120 → 0.29.122
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 +434 -36
- package/dist/jsenv_navi.js.map +39 -20
- package/package.json +1 -1
package/dist/jsenv_navi.js
CHANGED
|
@@ -4256,6 +4256,53 @@ const findControlProxy = (el) => {
|
|
|
4256
4256
|
return firstProxy;
|
|
4257
4257
|
};
|
|
4258
4258
|
|
|
4259
|
+
/**
|
|
4260
|
+
* Typography reset shared by the surfaces a control opens: callout, popover,
|
|
4261
|
+
* dialog.
|
|
4262
|
+
*
|
|
4263
|
+
* A surface is painted on top of the page but lives in the DOM subtree of the
|
|
4264
|
+
* element it opens from, so every inherited text property of that element
|
|
4265
|
+
* reaches it. The ink an element chose for its own background — centered,
|
|
4266
|
+
* shadowed, uppercase, letter-spaced, kept on one line — arrives on paper that
|
|
4267
|
+
* has none of that background, and the caller discovers it as a symptom
|
|
4268
|
+
* (a blurred tooltip, a centered message) with nothing on screen pointing back
|
|
4269
|
+
* to the rule three elements up. A surface writes its own text, on its own
|
|
4270
|
+
* paper, in the document's terms.
|
|
4271
|
+
*
|
|
4272
|
+
* Every one of them is set to its initial value rather than `revert`: only
|
|
4273
|
+
* `color` and `background-color` are declared by the UA on a `[popover]`/
|
|
4274
|
+
* `<dialog>`, so `revert` on any of these would roll back to the inherited
|
|
4275
|
+
* value — the very thing to stop. `text-align: initial` is `start`, which
|
|
4276
|
+
* still reads the surface's own `direction`, so an RTL document keeps its
|
|
4277
|
+
* side.
|
|
4278
|
+
*
|
|
4279
|
+
* `font-family` is deliberately absent: a surface keeps the face of what
|
|
4280
|
+
* opened it, so a section written in a display font gets its tooltips in that
|
|
4281
|
+
* font. `color`, `font-size` and `font-weight` are absent too — each surface
|
|
4282
|
+
* answers those its own way (a popup writes in --navi-popup-color and follows
|
|
4283
|
+
* the size of what opened it; a callout reverts to the document's ink and
|
|
4284
|
+
* size).
|
|
4285
|
+
*
|
|
4286
|
+
* In `@layer navi` so an app that wants one of these back says so on the
|
|
4287
|
+
* surface and wins, without having to out-specify anything.
|
|
4288
|
+
*/
|
|
4289
|
+
const surfaceTextCss = /* css */ `
|
|
4290
|
+
@layer navi {
|
|
4291
|
+
.navi_callout,
|
|
4292
|
+
.navi_popover,
|
|
4293
|
+
.navi_dialog {
|
|
4294
|
+
font-style: initial;
|
|
4295
|
+
text-align: initial;
|
|
4296
|
+
text-indent: initial;
|
|
4297
|
+
text-transform: initial;
|
|
4298
|
+
text-shadow: none;
|
|
4299
|
+
white-space: initial;
|
|
4300
|
+
word-spacing: initial;
|
|
4301
|
+
letter-spacing: initial;
|
|
4302
|
+
}
|
|
4303
|
+
}
|
|
4304
|
+
`;
|
|
4305
|
+
|
|
4259
4306
|
const CalloutContext = createContext();
|
|
4260
4307
|
const useCalloutRequestClose = () => {
|
|
4261
4308
|
return useContext(CalloutContext)?.requestClose;
|
|
@@ -4601,7 +4648,6 @@ const css$11 = /* css */`
|
|
|
4601
4648
|
box-sizing: border-box;
|
|
4602
4649
|
box-decoration-break: clone;
|
|
4603
4650
|
align-self: center;
|
|
4604
|
-
white-space: normal; /* Override in case ancetor sets nowrap */
|
|
4605
4651
|
word-break: break-word;
|
|
4606
4652
|
overflow-wrap: anywhere;
|
|
4607
4653
|
|
|
@@ -4670,6 +4716,8 @@ const css$11 = /* css */`
|
|
|
4670
4716
|
}
|
|
4671
4717
|
}
|
|
4672
4718
|
}
|
|
4719
|
+
|
|
4720
|
+
${surfaceTextCss}
|
|
4673
4721
|
`;
|
|
4674
4722
|
|
|
4675
4723
|
/**
|
|
@@ -39602,6 +39650,193 @@ const LinkCurrentIndicator = () => {
|
|
|
39602
39650
|
};
|
|
39603
39651
|
markAsOutsideTextFlow(LinkCurrentIndicator);
|
|
39604
39652
|
|
|
39653
|
+
/**
|
|
39654
|
+
* What the container tells what is inside it: which way it travels so a button
|
|
39655
|
+
* can point the right way without being told twice, what a travel handed to a
|
|
39656
|
+
* slide, and the box itself — which is how a way out written inside reads the
|
|
39657
|
+
* same facts a way out written outside reads by id (see useSlideContainer).
|
|
39658
|
+
*
|
|
39659
|
+
* Its own module, tiny on purpose: the hook that reads a container and the
|
|
39660
|
+
* container that fills this in would otherwise have to import each other.
|
|
39661
|
+
*/
|
|
39662
|
+
const SlideContainerContext = createContext(null);
|
|
39663
|
+
|
|
39664
|
+
/**
|
|
39665
|
+
* What a SlideContainer is doing, read from outside it.
|
|
39666
|
+
*
|
|
39667
|
+
* Only slides go in the box, so everything drawn AROUND the travel is written
|
|
39668
|
+
* around it — a chevron pinned to the edge of a full-screen viewer, a "3 / 8"
|
|
39669
|
+
* counter, a bar. Those need to know things the box alone knows: where one is,
|
|
39670
|
+
* and whether there is anywhere to go that way. A container driven by nobody
|
|
39671
|
+
* (no `current`, no `signal`) knows them and no one else does, so this is also
|
|
39672
|
+
* what keeps such a container usable without lifting its state out of it.
|
|
39673
|
+
*
|
|
39674
|
+
* Two channels, and they answer two different questions. The attributes the box
|
|
39675
|
+
* paints on itself are the STATE: they are there for whoever arrives later, and
|
|
39676
|
+
* CSS draws with them without any of this ([data-slide-ways~="right"]). The
|
|
39677
|
+
* event it dispatches is the NEWS: it says WHEN something changed, which no
|
|
39678
|
+
* attribute can say. So this reads the first and listens to the second.
|
|
39679
|
+
*
|
|
39680
|
+
* Not watching the DOM for it, which is the tempting third way and the wrong
|
|
39681
|
+
* one: a write is not a change. Under a finger the box writes where the picture
|
|
39682
|
+
* leans on every frame, with the same value in it more often than not, and a
|
|
39683
|
+
* watcher is woken for every one of them — while the box itself knows perfectly
|
|
39684
|
+
* well whether anything is different, and says so once.
|
|
39685
|
+
*
|
|
39686
|
+
* Nothing is told to the box in return, and nothing has to be wired: it
|
|
39687
|
+
* announces to itself and to its followers, so the thing doing the reading sits
|
|
39688
|
+
* anywhere on the page — in a fixed bar, in the frame around the box, in a
|
|
39689
|
+
* dialog holding it — and a container which never re-renders (a travel it drove
|
|
39690
|
+
* itself) is still followed.
|
|
39691
|
+
*
|
|
39692
|
+
* Reading only. Asking for a travel is what it always was: a command aimed at
|
|
39693
|
+
* the box (`commandFor={id}` + `--navi-right`, or triggerNaviCommand) — one way
|
|
39694
|
+
* of asking, wherever the asking is written.
|
|
39695
|
+
*/
|
|
39696
|
+
|
|
39697
|
+
|
|
39698
|
+
// The vocabulary the box publishes, in one place: written by slide_container,
|
|
39699
|
+
// read here and by anything styling in CSS alone
|
|
39700
|
+
// ([data-slide-ways~="right"]).
|
|
39701
|
+
const SLIDE_CURRENT_ATTRIBUTE = "data-slide-current";
|
|
39702
|
+
const SLIDE_TOWARD_ATTRIBUTE = "data-slide-travel-toward";
|
|
39703
|
+
// Every way out that would DO something right now, in the words the commands
|
|
39704
|
+
// use: a direction ("left", "right", "up", "down") when there is a slide that
|
|
39705
|
+
// way, plus "first" and "last" when one is not already standing at that end of
|
|
39706
|
+
// the walk — and, in all cases, the slide on screen letting go.
|
|
39707
|
+
const SLIDE_WAYS_ATTRIBUTE = "data-slide-ways";
|
|
39708
|
+
// …and the ways out that are there and refused: the slide on screen holds on to
|
|
39709
|
+
// the user that way (preventNav, or a `required` step still unanswered). Two
|
|
39710
|
+
// facts, not one: a way out leading nowhere is not there at all, while a way
|
|
39711
|
+
// out being held IS there and says no — which is why it stays visible and
|
|
39712
|
+
// explainable rather than hidden. A way out is dead in both cases.
|
|
39713
|
+
const SLIDE_HELD_ATTRIBUTE = "data-slide-held";
|
|
39714
|
+
// …and the one word said out loud, on the box and on every follower of it, when
|
|
39715
|
+
// any of the above has actually changed. It carries the whole state as its
|
|
39716
|
+
// detail, so `onnavi_slide_state` on the box is a way of hearing it too.
|
|
39717
|
+
const SLIDE_STATE_EVENT = "navi_slide_state";
|
|
39718
|
+
|
|
39719
|
+
const NO_WAYS = [];
|
|
39720
|
+
// No box to read: not "a box with nothing in it". The difference is the whole
|
|
39721
|
+
// point — see `can` below, which must not answer "there is nowhere to go" to
|
|
39722
|
+
// the question "where can one go" when it has not been told anything yet.
|
|
39723
|
+
const NOTHING = {
|
|
39724
|
+
known: false,
|
|
39725
|
+
current: undefined,
|
|
39726
|
+
toward: undefined,
|
|
39727
|
+
areas: NO_WAYS,
|
|
39728
|
+
ways: NO_WAYS,
|
|
39729
|
+
held: NO_WAYS,
|
|
39730
|
+
};
|
|
39731
|
+
|
|
39732
|
+
const wordsOf = (element, attribute) => {
|
|
39733
|
+
const value = element.getAttribute(attribute);
|
|
39734
|
+
return value ? value.split(" ") : NO_WAYS;
|
|
39735
|
+
};
|
|
39736
|
+
|
|
39737
|
+
const readSlideContainerState = (element) => ({
|
|
39738
|
+
known: true,
|
|
39739
|
+
current: element.getAttribute(SLIDE_CURRENT_ATTRIBUTE) ?? undefined,
|
|
39740
|
+
toward: element.getAttribute(SLIDE_TOWARD_ATTRIBUTE) ?? undefined,
|
|
39741
|
+
// In DOM order — which is the order of the WALK for a line, and not
|
|
39742
|
+
// necessarily for a map: there the order is the one the areas are written in
|
|
39743
|
+
// (see parseAreas). Ask `can("first")` / `can("last")` about the ends rather
|
|
39744
|
+
// than the two ends of this list.
|
|
39745
|
+
areas: Array.from(
|
|
39746
|
+
element.querySelectorAll(":scope > [data-slide-track] > [data-slide]"),
|
|
39747
|
+
(slideElement) =>
|
|
39748
|
+
slideElement.getAttribute("data-slide-area") || slideElement.id || "",
|
|
39749
|
+
),
|
|
39750
|
+
ways: wordsOf(element, SLIDE_WAYS_ATTRIBUTE),
|
|
39751
|
+
held: wordsOf(element, SLIDE_HELD_ATTRIBUTE),
|
|
39752
|
+
});
|
|
39753
|
+
|
|
39754
|
+
const sameSlideContainerState = (a, b) =>
|
|
39755
|
+
a.known === b.known &&
|
|
39756
|
+
a.current === b.current &&
|
|
39757
|
+
a.toward === b.toward &&
|
|
39758
|
+
a.areas.join(" ") === b.areas.join(" ") &&
|
|
39759
|
+
a.ways.join(" ") === b.ways.join(" ") &&
|
|
39760
|
+
a.held.join(" ") === b.held.join(" ");
|
|
39761
|
+
|
|
39762
|
+
/**
|
|
39763
|
+
* @param {string|Element|{current: Element}} [target] - the container: its id
|
|
39764
|
+
* (the way everything else addresses one), the element, or a ref to it. Not a
|
|
39765
|
+
* follower — a follower is painted for CSS to draw with, the box is what holds
|
|
39766
|
+
* the walk. Left out, it is the box this is written INSIDE, if any: a way out
|
|
39767
|
+
* reads the same facts on either side of the box, which is the whole point of
|
|
39768
|
+
* there being one answer to "what would this do".
|
|
39769
|
+
* @returns {{
|
|
39770
|
+
* known: boolean,
|
|
39771
|
+
* current: string|undefined,
|
|
39772
|
+
* toward: string|undefined,
|
|
39773
|
+
* areas: string[],
|
|
39774
|
+
* can: (wayOut: "left"|"right"|"up"|"down"|"first"|"last") => boolean,
|
|
39775
|
+
* held: (wayOut: "left"|"right"|"up"|"down"|"first"|"last") => boolean,
|
|
39776
|
+
* }} where the box stands. `current` is the slide on screen — the one being
|
|
39777
|
+
* travelled TO while a travel plays, because that is what one is looking at;
|
|
39778
|
+
* `toward` is the other slide in the frame while the picture is between two,
|
|
39779
|
+
* and nothing at rest. `can` is "asking for it would do something", `held` is
|
|
39780
|
+
* "it is there and this slide says no" — a way out is dead in both cases, and
|
|
39781
|
+
* only the second is worth a word to the reader.
|
|
39782
|
+
* `known` is false until the box has been read: no box was named and none is
|
|
39783
|
+
* above, the id names nothing, or — for one commit — this mounted before the
|
|
39784
|
+
* box had painted. Until then `can` answers YES, because it is the answer that
|
|
39785
|
+
* degrades well: a way out offered for one frame and then taken away is a
|
|
39786
|
+
* button that did nothing once, while the reverse hides every way out of every
|
|
39787
|
+
* box that this cannot see and says nothing about it.
|
|
39788
|
+
*/
|
|
39789
|
+
const useSlideContainer = (target) => {
|
|
39790
|
+
const [state, setState] = useState(NOTHING);
|
|
39791
|
+
// The box this is written inside, when nothing names one. Read
|
|
39792
|
+
// unconditionally, like every hook, and used only as a fallback.
|
|
39793
|
+
const containerInContext = useContext(SlideContainerContext);
|
|
39794
|
+
const fallbackRef = containerInContext?.containerRef;
|
|
39795
|
+
|
|
39796
|
+
useLayoutEffect(() => {
|
|
39797
|
+
const resolved = target ?? fallbackRef;
|
|
39798
|
+
const element =
|
|
39799
|
+
typeof resolved === "string"
|
|
39800
|
+
? document.getElementById(resolved)
|
|
39801
|
+
: resolved && "current" in resolved
|
|
39802
|
+
? resolved.current
|
|
39803
|
+
: resolved;
|
|
39804
|
+
if (!element) {
|
|
39805
|
+
if (typeof resolved === "string") {
|
|
39806
|
+
console.warn(
|
|
39807
|
+
`useSlideContainer("${resolved}") but no element with that id found`,
|
|
39808
|
+
);
|
|
39809
|
+
}
|
|
39810
|
+
setState(NOTHING);
|
|
39811
|
+
return undefined;
|
|
39812
|
+
}
|
|
39813
|
+
// Read off the DOM rather than taken from the event's detail, even though
|
|
39814
|
+
// the two say the same thing: the first read has no event to take it from
|
|
39815
|
+
// (the box was already standing somewhere when this mounted), and one way
|
|
39816
|
+
// of reading is one thing that can be wrong.
|
|
39817
|
+
const read = () => {
|
|
39818
|
+
const nextState = readSlideContainerState(element);
|
|
39819
|
+
setState((previous) =>
|
|
39820
|
+
sameSlideContainerState(previous, nextState) ? previous : nextState,
|
|
39821
|
+
);
|
|
39822
|
+
};
|
|
39823
|
+
read();
|
|
39824
|
+
element.addEventListener(SLIDE_STATE_EVENT, read);
|
|
39825
|
+
return () => {
|
|
39826
|
+
element.removeEventListener(SLIDE_STATE_EVENT, read);
|
|
39827
|
+
};
|
|
39828
|
+
}, [target, fallbackRef]);
|
|
39829
|
+
|
|
39830
|
+
return {
|
|
39831
|
+
known: state.known,
|
|
39832
|
+
current: state.current,
|
|
39833
|
+
toward: state.toward,
|
|
39834
|
+
areas: state.areas,
|
|
39835
|
+
can: (wayOut) => !state.known || state.ways.includes(wayOut),
|
|
39836
|
+
held: (wayOut) => state.held.includes(wayOut),
|
|
39837
|
+
};
|
|
39838
|
+
};
|
|
39839
|
+
|
|
39605
39840
|
installImportMetaCssBuild(import.meta);/**
|
|
39606
39841
|
* TabList component with support for horizontal and vertical layouts
|
|
39607
39842
|
* https://dribbble.com/search/tabs
|
|
@@ -40000,19 +40235,17 @@ const Nav = ({
|
|
|
40000
40235
|
}
|
|
40001
40236
|
slideContainerElementRef.current = containerElement;
|
|
40002
40237
|
const readContainer = () => {
|
|
40003
|
-
setCurrentSlideArea(containerElement.getAttribute(
|
|
40238
|
+
setCurrentSlideArea(containerElement.getAttribute(SLIDE_CURRENT_ATTRIBUTE) ?? undefined);
|
|
40004
40239
|
paintIndicatorGeometryRef.current();
|
|
40005
40240
|
};
|
|
40006
40241
|
readContainer();
|
|
40007
|
-
//
|
|
40008
|
-
//
|
|
40009
|
-
//
|
|
40010
|
-
// rather than
|
|
40011
|
-
|
|
40012
|
-
|
|
40013
|
-
|
|
40014
|
-
attributeFilter: ["data-slide-current", "data-slide-travel-toward"]
|
|
40015
|
-
});
|
|
40242
|
+
// Where one is and what the picture leans on are written on the container,
|
|
40243
|
+
// and the container says out loud when either has changed: this row is not
|
|
40244
|
+
// in the box (it sits above it, in a fixed bar, anywhere), so it reads the
|
|
40245
|
+
// first and listens to the second. Listening rather than watching the DOM
|
|
40246
|
+
// because a write is not a change — the attribute the trait follows is
|
|
40247
|
+
// written on every frame of a gesture with the same value in it.
|
|
40248
|
+
containerElement.addEventListener(SLIDE_STATE_EVENT, readContainer);
|
|
40016
40249
|
// A row whose tabs changed width — a badge count, a font that just
|
|
40017
40250
|
// arrived, a window resized — is measured again: what was written is
|
|
40018
40251
|
// pixels, and pixels go stale.
|
|
@@ -40021,7 +40254,7 @@ const Nav = ({
|
|
|
40021
40254
|
});
|
|
40022
40255
|
sizeObserver.observe(navRef.current);
|
|
40023
40256
|
return () => {
|
|
40024
|
-
|
|
40257
|
+
containerElement.removeEventListener(SLIDE_STATE_EVENT, readContainer);
|
|
40025
40258
|
sizeObserver.disconnect();
|
|
40026
40259
|
slideContainerElementRef.current = null;
|
|
40027
40260
|
};
|
|
@@ -49706,9 +49939,6 @@ const isWayOut = element => Boolean(element && element.closest && element.closes
|
|
|
49706
49939
|
// empty map, and a re-render changes nothing for them.
|
|
49707
49940
|
const EMPTY_VALUE_BY_AREA = {};
|
|
49708
49941
|
|
|
49709
|
-
// What the container tells what is inside it: which way it travels, so a button
|
|
49710
|
-
// can point the right way without being told twice.
|
|
49711
|
-
const SlideContainerContext = createContext(null);
|
|
49712
49942
|
// What a slide tells what is inside IT: whether leaving it is allowed right
|
|
49713
49943
|
// now, so its own prev/next buttons say so instead of failing when pressed.
|
|
49714
49944
|
const SlideContext = createContext(null);
|
|
@@ -49916,6 +50146,13 @@ const readArea = slideElement => slideElement.getAttribute("data-slide-area") ||
|
|
|
49916
50146
|
* screens are steps rather than places — so the keys keep the meaning the
|
|
49917
50147
|
* content gives them, and travelling stays something one asks for (a button,
|
|
49918
50148
|
* a command).
|
|
50149
|
+
* WHERE they are heard is a separate question, and it is not answered here: a
|
|
50150
|
+
* key only ever reaches what has the focus, so this box hears the ones pressed
|
|
50151
|
+
* inside it — and every follower of it hears the rest. A chevron pinned to the
|
|
50152
|
+
* edge of a full-screen surface is outside the box by necessity (only slides
|
|
50153
|
+
* go in it), so the surface says `data-slide-container-follows={id}` and the
|
|
50154
|
+
* arrows keep walking wherever the keyboard is in it. See the paragraph above
|
|
50155
|
+
* about what is drawn AROUND the travel.
|
|
49919
50156
|
* @param {boolean|"x"|"y"|"xy"} [props.travelByDrag=true] - whether a pointer
|
|
49920
50157
|
* dragging the slides travels. On by default: slides side by side are
|
|
49921
50158
|
* something one expects to push around with a thumb. Off where the gesture
|
|
@@ -50236,7 +50473,7 @@ const SlideContainer = ({
|
|
|
50236
50473
|
// there is nothing else for it to read — a slide the container holds by
|
|
50237
50474
|
// itself is known to no one else.
|
|
50238
50475
|
const paintCurrentArea = area => {
|
|
50239
|
-
containerRef.current?.setAttribute(
|
|
50476
|
+
containerRef.current?.setAttribute(SLIDE_CURRENT_ATTRIBUTE, area);
|
|
50240
50477
|
};
|
|
50241
50478
|
const markAnswered = area => {
|
|
50242
50479
|
const order = readMap().slideElements.map(readArea);
|
|
@@ -50559,6 +50796,14 @@ const SlideContainer = ({
|
|
|
50559
50796
|
if (!stageRef.current) {
|
|
50560
50797
|
drawnAreaRef.current = currentArea;
|
|
50561
50798
|
}
|
|
50799
|
+
// Said last, and after data-current has been written: what a travel would do
|
|
50800
|
+
// is read off the map from the slide that is now current, and off the locks
|
|
50801
|
+
// that slide is wearing in this very commit.
|
|
50802
|
+
paintWays(currentElement);
|
|
50803
|
+
// …and once everything this commit had to write is written, the box says so
|
|
50804
|
+
// — a single announcement for a render that may have changed several of the
|
|
50805
|
+
// facts at once.
|
|
50806
|
+
announceState();
|
|
50562
50807
|
// The finger has the last word: everything above drew the map at rest, and
|
|
50563
50808
|
// where the track actually is right now is where the gesture put it.
|
|
50564
50809
|
paintDrag();
|
|
@@ -51086,11 +51331,109 @@ const SlideContainer = ({
|
|
|
51086
51331
|
const paintTravelToward = area => {
|
|
51087
51332
|
for (const element of travelPainters()) {
|
|
51088
51333
|
if (area) {
|
|
51089
|
-
element.setAttribute(
|
|
51334
|
+
element.setAttribute(SLIDE_TOWARD_ATTRIBUTE, area);
|
|
51090
51335
|
} else {
|
|
51091
|
-
element.removeAttribute(
|
|
51336
|
+
element.removeAttribute(SLIDE_TOWARD_ATTRIBUTE);
|
|
51092
51337
|
}
|
|
51093
51338
|
}
|
|
51339
|
+
// The one fact that changes without a render behind it: under a finger this
|
|
51340
|
+
// is written per frame, so the announcement is left to say whether any of
|
|
51341
|
+
// those writes was a change.
|
|
51342
|
+
announceState();
|
|
51343
|
+
};
|
|
51344
|
+
|
|
51345
|
+
// What a travel would do right now, said in two lists because they are two
|
|
51346
|
+
// different facts: `ways` is where one WOULD go — there is a slide that way
|
|
51347
|
+
// and the one on screen lets go of it — and `held` is where there is a slide
|
|
51348
|
+
// that way and this one holds on to the user (preventNav, a `required` step
|
|
51349
|
+
// still unanswered). A way out leading nowhere is not there; a way out being
|
|
51350
|
+
// held is there and says no, which is why it stays visible and explainable.
|
|
51351
|
+
//
|
|
51352
|
+
// Painted rather than rendered, and on the followers too: only slides go in
|
|
51353
|
+
// this box, so the chevrons, the counters and the bars that go with it are
|
|
51354
|
+
// written AROUND it — in CSS off these attributes
|
|
51355
|
+
// ([data-slide-ways~="right"]), or through useSlideContainer, which watches
|
|
51356
|
+
// them. Nothing is told, everything is read: it is what lets them sit
|
|
51357
|
+
// anywhere, and what lets a container nobody drives still be followed.
|
|
51358
|
+
const paintWays = currentElement => {
|
|
51359
|
+
const ways = [];
|
|
51360
|
+
const held = [];
|
|
51361
|
+
// Whether the slide being left says no, this way. The one gate again, read
|
|
51362
|
+
// exactly as goToArea reads it at the moment of the travel — so what is
|
|
51363
|
+
// published here and what would happen cannot disagree.
|
|
51364
|
+
const holdsTowards = forward => currentElement?.hasAttribute(forward ? "data-prevent-nav-next" : "data-prevent-nav-previous");
|
|
51365
|
+
const say = (name, offered, forward) => {
|
|
51366
|
+
if (!offered) {
|
|
51367
|
+
return;
|
|
51368
|
+
}
|
|
51369
|
+
(holdsTowards(forward) ? held : ways).push(name);
|
|
51370
|
+
};
|
|
51371
|
+
for (const direction of Object.keys(DIRECTIONS)) {
|
|
51372
|
+
const {
|
|
51373
|
+
dx,
|
|
51374
|
+
dy
|
|
51375
|
+
} = DIRECTIONS[direction];
|
|
51376
|
+
if (!mapAxes?.includes(dx ? "x" : "y")) {
|
|
51377
|
+
// Not an axis this map has: a row has no up and no down, and saying so
|
|
51378
|
+
// would be saying it about every row on the page.
|
|
51379
|
+
continue;
|
|
51380
|
+
}
|
|
51381
|
+
say(direction, Boolean(areaTowards(dx, dy)), dx > 0 || dy > 0);
|
|
51382
|
+
}
|
|
51383
|
+
// The two ends are ways out like the others — "all the way that way", said
|
|
51384
|
+
// by the map's own order rather than by a direction (see goToEnd, and
|
|
51385
|
+
// SlideContainer.First / .Last). Offered while one is not already standing
|
|
51386
|
+
// there, and held by the same lock the direction they lie in would be.
|
|
51387
|
+
const {
|
|
51388
|
+
order
|
|
51389
|
+
} = readMap();
|
|
51390
|
+
const currentArea = currentElement ? readArea(currentElement) : undefined;
|
|
51391
|
+
say("first", order.length > 0 && order[0] !== currentArea, false);
|
|
51392
|
+
say("last", order.length > 0 && order[order.length - 1] !== currentArea, true);
|
|
51393
|
+
for (const element of travelPainters()) {
|
|
51394
|
+
if (ways.length) {
|
|
51395
|
+
element.setAttribute(SLIDE_WAYS_ATTRIBUTE, ways.join(" "));
|
|
51396
|
+
} else {
|
|
51397
|
+
element.removeAttribute(SLIDE_WAYS_ATTRIBUTE);
|
|
51398
|
+
}
|
|
51399
|
+
if (held.length) {
|
|
51400
|
+
element.setAttribute(SLIDE_HELD_ATTRIBUTE, held.join(" "));
|
|
51401
|
+
} else {
|
|
51402
|
+
element.removeAttribute(SLIDE_HELD_ATTRIBUTE);
|
|
51403
|
+
}
|
|
51404
|
+
}
|
|
51405
|
+
};
|
|
51406
|
+
|
|
51407
|
+
// The news, as opposed to the state. Everything painted above IS the state:
|
|
51408
|
+
// it is what anything arriving later reads, and what CSS draws with. What an
|
|
51409
|
+
// attribute cannot say is WHEN it changed — and watching it is the wrong way
|
|
51410
|
+
// to ask, because a write is not a change: `data-slide-travel-toward` is
|
|
51411
|
+
// written on every frame of a gesture with the same value in it, and every
|
|
51412
|
+
// watcher would be woken sixty times a second for nothing. So the box says it
|
|
51413
|
+
// itself, once, and only when something is actually different.
|
|
51414
|
+
//
|
|
51415
|
+
// Said to its followers as well as to itself, exactly as the painting is: a
|
|
51416
|
+
// frame drawn around the box hears what the box is doing without knowing its
|
|
51417
|
+
// id, and a row of tabs beside it listens on the box by id. Not bubbling, like
|
|
51418
|
+
// every other navi event — what is announced is about THIS box, and a box
|
|
51419
|
+
// inside another must not be heard as the one around it.
|
|
51420
|
+
const announcedRef = useRef(null);
|
|
51421
|
+
const announceState = () => {
|
|
51422
|
+
const containerEl = containerRef.current;
|
|
51423
|
+
if (!containerEl) {
|
|
51424
|
+
return;
|
|
51425
|
+
}
|
|
51426
|
+
const state = readSlideContainerState(containerEl);
|
|
51427
|
+
const announced = announcedRef.current;
|
|
51428
|
+
if (announced && sameSlideContainerState(announced, state)) {
|
|
51429
|
+
return;
|
|
51430
|
+
}
|
|
51431
|
+
announcedRef.current = state;
|
|
51432
|
+
for (const element of travelPainters()) {
|
|
51433
|
+
dispatchCustomEvent(element, SLIDE_STATE_EVENT, {
|
|
51434
|
+
...state
|
|
51435
|
+
});
|
|
51436
|
+
}
|
|
51094
51437
|
};
|
|
51095
51438
|
|
|
51096
51439
|
// Where the picture stands relative to the slide that is CURRENT, in boxes:
|
|
@@ -51789,7 +52132,11 @@ const SlideContainer = ({
|
|
|
51789
52132
|
answeredAreas,
|
|
51790
52133
|
done,
|
|
51791
52134
|
valueByArea,
|
|
51792
|
-
settleFocus
|
|
52135
|
+
settleFocus,
|
|
52136
|
+
// The box itself, for what is written INSIDE it to read the same
|
|
52137
|
+
// facts what is written outside reads by id (useSlideContainer):
|
|
52138
|
+
// a way out is a way out on either side of the box.
|
|
52139
|
+
containerRef
|
|
51793
52140
|
},
|
|
51794
52141
|
children: children
|
|
51795
52142
|
})
|
|
@@ -52002,7 +52349,19 @@ const SlideMove = ({
|
|
|
52002
52349
|
label
|
|
52003
52350
|
} = DIRECTIONS[direction];
|
|
52004
52351
|
const forward = dx > 0 || dy > 0;
|
|
52005
|
-
|
|
52352
|
+
// What this way out would DO, read from wherever it is written: off the box it
|
|
52353
|
+
// names when it is drawn around the box (only slides go in it, so a chevron
|
|
52354
|
+
// pinned to the edge of a full-screen surface has to be), off the box above it
|
|
52355
|
+
// otherwise. One answer on either side of the box.
|
|
52356
|
+
const slides = useSlideContainer(rest.commandFor);
|
|
52357
|
+
// Two reasons to be dead, and they are not the same thing to a reader: this
|
|
52358
|
+
// slide holding on to them (worth explaining — see readOnly on SlideNavButton)
|
|
52359
|
+
// and there being nothing that way at all (the end of the walk, which explains
|
|
52360
|
+
// itself). The lock also comes down as context when this is written inside a
|
|
52361
|
+
// slide, which is the same fact one commit earlier: the box publishes it after
|
|
52362
|
+
// the render, and there is no frame where the way out is live for nothing.
|
|
52363
|
+
const held = (forward ? locks?.preventNavNext : locks?.preventNavPrevious) || slides.held(direction);
|
|
52364
|
+
const locked = held || !slides.can(direction);
|
|
52006
52365
|
return jsx(SlideNavButton, {
|
|
52007
52366
|
command: command,
|
|
52008
52367
|
locked: locked,
|
|
@@ -52014,16 +52373,24 @@ const SlideMove = ({
|
|
|
52014
52373
|
|
|
52015
52374
|
// "All the way that way": the first slide of the walk, or the last one. Not a
|
|
52016
52375
|
// direction — a map reads its own order — so it is its own component rather
|
|
52017
|
-
// than a fifth arrow.
|
|
52376
|
+
// than a fifth arrow. Which is exactly why it cannot work out on its own whether
|
|
52377
|
+
// it would do anything: only the box knows its order, so only the box can say
|
|
52378
|
+
// that one is already standing at that end. It says it in the same breath as the
|
|
52379
|
+
// rest (see paintWays).
|
|
52018
52380
|
const SlideEnd = ({
|
|
52019
52381
|
last,
|
|
52020
52382
|
...rest
|
|
52021
|
-
}) =>
|
|
52022
|
-
|
|
52023
|
-
|
|
52024
|
-
|
|
52025
|
-
|
|
52026
|
-
|
|
52383
|
+
}) => {
|
|
52384
|
+
const slides = useSlideContainer(rest.commandFor);
|
|
52385
|
+
const wayOut = last ? "last" : "first";
|
|
52386
|
+
return jsx(SlideNavButton, {
|
|
52387
|
+
command: last ? "--navi-last" : "--navi-first",
|
|
52388
|
+
locked: slides.held(wayOut) || !slides.can(wayOut),
|
|
52389
|
+
ChevronSvg: last ? ChevronLastSvg : ChevronFirstSvg,
|
|
52390
|
+
"aria-label": last ? "Last slide" : "First slide",
|
|
52391
|
+
...rest
|
|
52392
|
+
});
|
|
52393
|
+
};
|
|
52027
52394
|
const SlideFirst = props => jsx(SlideEnd, {
|
|
52028
52395
|
...props,
|
|
52029
52396
|
last: false
|
|
@@ -54555,6 +54922,7 @@ const css$E = /* css */`
|
|
|
54555
54922
|
}
|
|
54556
54923
|
}
|
|
54557
54924
|
|
|
54925
|
+
${surfaceTextCss}
|
|
54558
54926
|
${popupCss}
|
|
54559
54927
|
`;
|
|
54560
54928
|
|
|
@@ -56052,6 +56420,7 @@ const css$D = /* css */`
|
|
|
56052
56420
|
}
|
|
56053
56421
|
}
|
|
56054
56422
|
|
|
56423
|
+
${surfaceTextCss}
|
|
56055
56424
|
${popupCss}
|
|
56056
56425
|
`;
|
|
56057
56426
|
|
|
@@ -66172,6 +66541,20 @@ installImportMetaCssBuild(import.meta);const css$t = /* css */`
|
|
|
66172
66541
|
pointer-events: none;
|
|
66173
66542
|
user-select: none;
|
|
66174
66543
|
|
|
66544
|
+
/* The value the picker draws itself is the control's own text, at the
|
|
66545
|
+
control's font size: it keeps the control line, snapped to the pixel
|
|
66546
|
+
like the field around it. A caller's "ui" is the caller's own drawing
|
|
66547
|
+
of the control, and it is written on the page's line, as the number,
|
|
66548
|
+
so each text it holds keeps a line relative to its own size. The
|
|
66549
|
+
control line is a length (--navi-control-line-height), and inherited
|
|
66550
|
+
it would arrive as the control's pixels: a 14px label under an 18px
|
|
66551
|
+
picker's 23px line carries ~5px of leading above and below that no
|
|
66552
|
+
glyph occupies and nothing on screen explains. Same reason a popup
|
|
66553
|
+
takes the number — see .navi_popup in popup.jsx. */
|
|
66554
|
+
&[data-picker-facade] {
|
|
66555
|
+
line-height: var(--navi-line-height);
|
|
66556
|
+
}
|
|
66557
|
+
|
|
66175
66558
|
&[navi-placeholder] {
|
|
66176
66559
|
color: var(--picker-placeholder-color);
|
|
66177
66560
|
font-style: var(--picker-placeholder-font-style);
|
|
@@ -66311,6 +66694,16 @@ installImportMetaCssBuild(import.meta);const css$t = /* css */`
|
|
|
66311
66694
|
--x-corner-bottom-left-radius: initial;
|
|
66312
66695
|
|
|
66313
66696
|
display: contents;
|
|
66697
|
+
/* What opens from a control is a page of its own, not part of that
|
|
66698
|
+
control's type scale: it is written at the control font by name,
|
|
66699
|
+
rather than by inheriting the size the picker itself is drawn at. A
|
|
66700
|
+
caller who sizes a picker to the façade it holds (so the padding, the
|
|
66701
|
+
corners and the chevron the picker draws in em land on the text the
|
|
66702
|
+
caller actually wrote) would otherwise take the popup down with it:
|
|
66703
|
+
its title, and everything in it that does not state a size of its
|
|
66704
|
+
own. Same reason the popup is written on the page's line rather than
|
|
66705
|
+
the control's — see .navi_popup in popup.jsx. */
|
|
66706
|
+
font-size: var(--navi-control-font-size);
|
|
66314
66707
|
text-align: initial; /* Don't inherit picker text align */
|
|
66315
66708
|
}
|
|
66316
66709
|
|
|
@@ -66714,6 +67107,12 @@ const PickerButton = props => {
|
|
|
66714
67107
|
}
|
|
66715
67108
|
}), variant === "headless" || ui === "default" ? null : jsx(Text, {
|
|
66716
67109
|
className: "navi_picker_value"
|
|
67110
|
+
// Tells the caller's own drawing of the control from the value
|
|
67111
|
+
// the picker draws itself, so each is written on its own line
|
|
67112
|
+
// (see .navi_picker_value in the CSS above).
|
|
67113
|
+
,
|
|
67114
|
+
|
|
67115
|
+
"data-picker-facade": ui === undefined ? undefined : ""
|
|
66717
67116
|
// A button's label is not a placeholder, however empty the
|
|
66718
67117
|
// picker behind it is.
|
|
66719
67118
|
,
|
|
@@ -78903,8 +79302,8 @@ const StepList = ({
|
|
|
78903
79302
|
}
|
|
78904
79303
|
const rootElement = rootRef.current;
|
|
78905
79304
|
const read = () => {
|
|
78906
|
-
const currentArea = containerElement.getAttribute(
|
|
78907
|
-
const towardArea = containerElement.getAttribute(
|
|
79305
|
+
const currentArea = containerElement.getAttribute(SLIDE_CURRENT_ATTRIBUTE);
|
|
79306
|
+
const towardArea = containerElement.getAttribute(SLIDE_TOWARD_ATTRIBUTE);
|
|
78908
79307
|
setContainerCurrent(currentArea ?? undefined);
|
|
78909
79308
|
const currentIdx = currentArea === null ? -1 : indexOf(currentArea);
|
|
78910
79309
|
if (currentIdx === -1) {
|
|
@@ -78928,13 +79327,12 @@ const StepList = ({
|
|
|
78928
79327
|
rootElement.style.setProperty("--step-list-pos-dx", dx);
|
|
78929
79328
|
};
|
|
78930
79329
|
read();
|
|
78931
|
-
|
|
78932
|
-
|
|
78933
|
-
|
|
78934
|
-
|
|
78935
|
-
});
|
|
79330
|
+
// Read off the container, and re-read when it says something has changed:
|
|
79331
|
+
// a write is not a change, and the attribute the halo follows is written on
|
|
79332
|
+
// every frame of a gesture with the same value in it.
|
|
79333
|
+
containerElement.addEventListener(SLIDE_STATE_EVENT, read);
|
|
78936
79334
|
return () => {
|
|
78937
|
-
|
|
79335
|
+
containerElement.removeEventListener(SLIDE_STATE_EVENT, read);
|
|
78938
79336
|
};
|
|
78939
79337
|
// width: the dots move when the room does, and the written positions are
|
|
78940
79338
|
// pixels of those dots.
|
|
@@ -79765,5 +80163,5 @@ const UserSvg = () => jsx("svg", {
|
|
|
79765
80163
|
})
|
|
79766
80164
|
});
|
|
79767
80165
|
|
|
79768
|
-
export { ActionRenderer, ActiveKeyboardShortcuts, Address, Badge, BadgeCount, BadgeList, Binder, Box, Button, ButtonCopyToClipboard, CalloutStatusIcon, Caption, CardLayout, CheckSvg, CheckboxGroup, CloseSvg, Code, Col, Colgroup, Color, ConstructionSvg, ControlGroup, DaySpin, Details, Dialog, Editable, ErrorBoundary, ErrorBoundaryContext, ExclamationSvg, Expandable, EyeClosedSvg, EyeSvg, Field, FixedBar, Form, Group, Head, HeartSvg, HomeSvg, Icon, Image, InfoSvg, Input, InputDuration, Interpolate, Label, Link, LinkAnchorSvg, LinkBlankTargetSvg, LinkCurrentSvg, List, ListItem, ListItemGroup, ListItems, Loading, LoadingDotsSvg, LoadingIndicator, LoadingIndicatorFluid, LoadingOutline, MessageBox, Meter, Nav, NaviDebug, NumberSpin, Paragraph, Picker, Popover, Popup, Quantity, RadioGroup, Route, RouteTransitionArea, RouteTravel, RowNumberCol, RowNumberTableCell, SVGMaskOverlay, SearchSvg, Select, SelectableInput, SelectionContext, Separator, SettingsSvg, SidePanel, Slide, SlideContainer, Spin, SpinGroup, SplitButton, StarSvg, Step, StepList, SummaryMarker, Svg, Table, TableCell, Tbody, Text, TextBox, Textarea, TextareaCharCount, Thead, Time, TimeRangeSpin, TimeRangeWheel, TimeSpin, TimeWheel, Title, Tr, UITransition, Unit, UserSvg, ViewportLayout, Wheel, WheelGroup, WheelItem, actionRunEffect, anyMatchingRouteSignal, applySearch, arraySignalMembership, canNavBackSignal, canNavForwardSignal, coarsePointerSignal, compareTwoJsValues, constraintFromValidityRule, createAction, createAvailableConstraint, createI18n, createRequestCanceller, createSearch, createSelectionKeyboardShortcuts, createSlot, defineInteractionDetector, defineRouteDefaultTransition, defineRouteTransition, detectHorizontalOverflow, enableDebugActions, enableDebugOnDocumentLoading, ensureDocumentStartViewTransition, errorIsDisplayed, filterTableSelection, formatDatetime, formatDay, formatDayRelative, formatMonth, formatNumber, formatTime, formatTimeRelative, getNowHours, getNowHoursRoundedToStep, interpolateText, isCellSelected, isColumnSelected, isRowSelected, isScrolling, isToday, languagesSignal, localStorageSignal, markErrorAsDisplayedBy, moveArrayItemByIndex, navBack, navForward, navIntegratedVia, navTo, naviI18n, openCallout, rawUrlPart, registerGlobalConstraint, reload, rerunActions, resource, route, routeAction, scrollActivitySignal, setBaseUrl, setPreferredLanguage, setSupportedLanguages, setUrlTargetOptions, setupRoutes, smallTouchScreenSignal, stateSignal, stopLoad, stringifyTableSelectionValue, swapArrayItemByIndex, syncOwnedResourceToSignals, syncResourceToSignals, triggerNaviCommand, updateActions, useActionStatus, useArraySignalMembership, useAsyncData, useCalloutElement, useCalloutRequestClose, useCanNavBack, useCanNavForward, useCancelPrevious, useCellGridFromRows, useConstraintValidityState, useDependenciesDiff, useDisplayedLayoutEffect, useDocumentResource, useDocumentState, useDocumentUrl, useEditionController, useFocusGroup, useInputGroup, useKeyboardShortcuts, useNavState, useOrderedColumns, usePopupMode, useRouteStatus, useRunOnMount, useSearchText, useSelectableElement, useSelectionController, useSignalSync, useSlideValue, useStateArray, useTitleLevel, useUrlSearchParam, useUrlTargetId, valueInLocalStorage, windowWidthSignal };
|
|
80166
|
+
export { ActionRenderer, ActiveKeyboardShortcuts, Address, Badge, BadgeCount, BadgeList, Binder, Box, Button, ButtonCopyToClipboard, CalloutStatusIcon, Caption, CardLayout, CheckSvg, CheckboxGroup, CloseSvg, Code, Col, Colgroup, Color, ConstructionSvg, ControlGroup, DaySpin, Details, Dialog, Editable, ErrorBoundary, ErrorBoundaryContext, ExclamationSvg, Expandable, EyeClosedSvg, EyeSvg, Field, FixedBar, Form, Group, Head, HeartSvg, HomeSvg, Icon, Image, InfoSvg, Input, InputDuration, Interpolate, Label, Link, LinkAnchorSvg, LinkBlankTargetSvg, LinkCurrentSvg, List, ListItem, ListItemGroup, ListItems, Loading, LoadingDotsSvg, LoadingIndicator, LoadingIndicatorFluid, LoadingOutline, MessageBox, Meter, Nav, NaviDebug, NumberSpin, Paragraph, Picker, Popover, Popup, Quantity, RadioGroup, Route, RouteTransitionArea, RouteTravel, RowNumberCol, RowNumberTableCell, SVGMaskOverlay, SearchSvg, Select, SelectableInput, SelectionContext, Separator, SettingsSvg, SidePanel, Slide, SlideContainer, Spin, SpinGroup, SplitButton, StarSvg, Step, StepList, SummaryMarker, Svg, Table, TableCell, Tbody, Text, TextBox, Textarea, TextareaCharCount, Thead, Time, TimeRangeSpin, TimeRangeWheel, TimeSpin, TimeWheel, Title, Tr, UITransition, Unit, UserSvg, ViewportLayout, Wheel, WheelGroup, WheelItem, actionRunEffect, anyMatchingRouteSignal, applySearch, arraySignalMembership, canNavBackSignal, canNavForwardSignal, coarsePointerSignal, compareTwoJsValues, constraintFromValidityRule, createAction, createAvailableConstraint, createI18n, createRequestCanceller, createSearch, createSelectionKeyboardShortcuts, createSlot, defineInteractionDetector, defineRouteDefaultTransition, defineRouteTransition, detectHorizontalOverflow, enableDebugActions, enableDebugOnDocumentLoading, ensureDocumentStartViewTransition, errorIsDisplayed, filterTableSelection, formatDatetime, formatDay, formatDayRelative, formatMonth, formatNumber, formatTime, formatTimeRelative, getNowHours, getNowHoursRoundedToStep, interpolateText, isCellSelected, isColumnSelected, isRowSelected, isScrolling, isToday, languagesSignal, localStorageSignal, markErrorAsDisplayedBy, moveArrayItemByIndex, navBack, navForward, navIntegratedVia, navTo, naviI18n, openCallout, rawUrlPart, registerGlobalConstraint, reload, rerunActions, resource, route, routeAction, scrollActivitySignal, setBaseUrl, setPreferredLanguage, setSupportedLanguages, setUrlTargetOptions, setupRoutes, smallTouchScreenSignal, stateSignal, stopLoad, stringifyTableSelectionValue, swapArrayItemByIndex, syncOwnedResourceToSignals, syncResourceToSignals, triggerNaviCommand, updateActions, useActionStatus, useArraySignalMembership, useAsyncData, useCalloutElement, useCalloutRequestClose, useCanNavBack, useCanNavForward, useCancelPrevious, useCellGridFromRows, useConstraintValidityState, useDependenciesDiff, useDisplayedLayoutEffect, useDocumentResource, useDocumentState, useDocumentUrl, useEditionController, useFocusGroup, useInputGroup, useKeyboardShortcuts, useNavState, useOrderedColumns, usePopupMode, useRouteStatus, useRunOnMount, useSearchText, useSelectableElement, useSelectionController, useSignalSync, useSlideContainer, useSlideValue, useStateArray, useTitleLevel, useUrlSearchParam, useUrlTargetId, valueInLocalStorage, windowWidthSignal };
|
|
79769
80167
|
//# sourceMappingURL=jsenv_navi.js.map
|