@jsenv/navi 0.28.10 → 0.28.11
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
CHANGED
|
@@ -5356,7 +5356,7 @@ const stateSignal = (defaultValue, options = {}) => {
|
|
|
5356
5356
|
const existingEntry = globalSignalRegistry.get(signalIdString);
|
|
5357
5357
|
{
|
|
5358
5358
|
throw new Error(
|
|
5359
|
-
`Signal ID conflict: A signal with ID "${signalIdString}" already exists (existing default: ${existingEntry.options.getDefaultValue()})
|
|
5359
|
+
`Signal ID conflict: A signal with ID "${signalIdString}" already exists (existing default: ${existingEntry.options.getDefaultValue()}). If this is the same stateSignal() call site running twice, the module was evaluated twice — check the network tab for the same file requested both bare and with "?hot=".`,
|
|
5360
5360
|
);
|
|
5361
5361
|
}
|
|
5362
5362
|
}
|
|
@@ -33946,10 +33946,13 @@ installImportMetaCssBuild(import.meta);const css$E = /* css */`
|
|
|
33946
33946
|
black
|
|
33947
33947
|
);
|
|
33948
33948
|
/* Readonly */
|
|
33949
|
+
/* Fading toward the surface, not toward white: "washed out" means
|
|
33950
|
+
closer to the paper behind the button, whatever color that paper is
|
|
33951
|
+
(white here IS the surface only in the light theme). */
|
|
33949
33952
|
--button-border-color-readonly: color-mix(
|
|
33950
33953
|
in srgb,
|
|
33951
33954
|
var(--button-border-color) 30%,
|
|
33952
|
-
|
|
33955
|
+
var(--navi-surface-color)
|
|
33953
33956
|
);
|
|
33954
33957
|
--button-background-color-readonly: var(--button-background-color);
|
|
33955
33958
|
--button-color-readonly: color-mix(
|
|
@@ -43668,6 +43671,10 @@ const lengthValue = value => typeof value === "number" ? `${value}px` : value;
|
|
|
43668
43671
|
*
|
|
43669
43672
|
* getTrackedItemByIndex(index): synchronous O(1) lookup of a visible item by
|
|
43670
43673
|
* its visible rank. Returns undefined when index is out of range.
|
|
43674
|
+
*
|
|
43675
|
+
* peekItems(): the items as they stand right now, without waiting for the
|
|
43676
|
+
* deferred notification — what a sibling rendering after the items must read
|
|
43677
|
+
* to paint them in the same commit.
|
|
43671
43678
|
*/
|
|
43672
43679
|
|
|
43673
43680
|
const useItemTracker = ({ onChange } = {}) => {
|
|
@@ -43770,7 +43777,8 @@ const createItemTracker = (onChange) => {
|
|
|
43770
43777
|
visibleItemsSignal.value = visibleItems;
|
|
43771
43778
|
someChange = true;
|
|
43772
43779
|
}
|
|
43773
|
-
const noMatchCountModified =
|
|
43780
|
+
const noMatchCountModified =
|
|
43781
|
+
noMatchCountSignal.peek() !== newNoMatchCount;
|
|
43774
43782
|
if (noMatchCountModified) {
|
|
43775
43783
|
noMatchCountSignal.value = newNoMatchCount;
|
|
43776
43784
|
someChange = true;
|
|
@@ -43964,9 +43972,32 @@ const createItemTracker = (onChange) => {
|
|
|
43964
43972
|
return registrations.get(key);
|
|
43965
43973
|
};
|
|
43966
43974
|
|
|
43975
|
+
// The items as they stand right now, notification pending or not — same
|
|
43976
|
+
// content as itemsSignal, minus the wait.
|
|
43977
|
+
//
|
|
43978
|
+
// Items register during their own render, while the signal is only updated
|
|
43979
|
+
// on a deferred microtask (see notify): a sibling rendering after them would
|
|
43980
|
+
// otherwise paint from an empty list and correct itself a frame later. That
|
|
43981
|
+
// frame is visible whenever the painted size feeds a layout decision — a
|
|
43982
|
+
// dialog sizing itself on its content measures the empty version and shifts
|
|
43983
|
+
// once the real one lands. Reading this instead makes the first paint the
|
|
43984
|
+
// right one. Callers must still subscribe to itemsSignal to re-render on
|
|
43985
|
+
// LATER changes; this is the value to display, not the notification.
|
|
43986
|
+
const peekItems = () => {
|
|
43987
|
+
if (!notifyScheduled) {
|
|
43988
|
+
return itemsSignal.peek();
|
|
43989
|
+
}
|
|
43990
|
+
const items = [];
|
|
43991
|
+
for (const key of allOrderedKeys) {
|
|
43992
|
+
items.push(allRegistrations.get(key));
|
|
43993
|
+
}
|
|
43994
|
+
return items;
|
|
43995
|
+
};
|
|
43996
|
+
|
|
43967
43997
|
return {
|
|
43968
43998
|
useTrackItem,
|
|
43969
43999
|
getTrackedItemByIndex,
|
|
44000
|
+
peekItems,
|
|
43970
44001
|
itemsSignal,
|
|
43971
44002
|
visibleItemsSignal,
|
|
43972
44003
|
countSignal,
|
|
@@ -50733,12 +50764,16 @@ const css$k = /* css */`
|
|
|
50733
50764
|
as rows scroll under the pointer. */
|
|
50734
50765
|
user-select: none;
|
|
50735
50766
|
-webkit-tap-highlight-color: transparent;
|
|
50736
|
-
/*
|
|
50737
|
-
|
|
50738
|
-
|
|
50739
|
-
|
|
50740
|
-
|
|
50741
|
-
|
|
50767
|
+
/* NO content-visibility here, ever. content-visibility: auto was tried
|
|
50768
|
+
(to skip painting clipped rows) and it breaks the first opening of any
|
|
50769
|
+
popup holding a wheel: rows born inside a closed dialog are "skipped"
|
|
50770
|
+
with no last-remembered size, so they measure as empty (padding-only) on
|
|
50771
|
+
the open's own layout — the dialog positions itself against that width
|
|
50772
|
+
and visibly slides once the real width lands. The un-skip only happens
|
|
50773
|
+
at the next update-the-rendering step: no forced reflow can read the
|
|
50774
|
+
true size any earlier, making the bug unfixable from the dialog side.
|
|
50775
|
+
There is also nothing left to win: the window renders only
|
|
50776
|
+
visibleCount + 2 recycled rows, all in or against the viewport. */
|
|
50742
50777
|
}
|
|
50743
50778
|
|
|
50744
50779
|
/* Orientation-specific sizing/layout. The mask worn by the base layer: the
|
|
@@ -51706,23 +51741,16 @@ function WheelUI(props) {
|
|
|
51706
51741
|
const trackedItems = tracker.itemsSignal.value;
|
|
51707
51742
|
const trackedItemsRef = useRef(trackedItems);
|
|
51708
51743
|
trackedItemsRef.current = trackedItems;
|
|
51709
|
-
const itemCount = trackedItems.length;
|
|
51710
51744
|
|
|
51711
51745
|
// Virtualization: render only visibleCount + 2 rows (one buffer each side to
|
|
51712
51746
|
// cover the partial rows a scroll reveals + a re-render's one-frame lag) and
|
|
51713
|
-
// recycle them
|
|
51714
|
-
//
|
|
51715
|
-
//
|
|
51716
|
-
//
|
|
51717
|
-
//
|
|
51718
|
-
//
|
|
51719
|
-
//
|
|
51720
|
-
// the transform stays consistent with it.
|
|
51721
|
-
// visibleCount + 2, but never more rows than there are values.
|
|
51722
|
-
let windowSize = visibleCount + 2;
|
|
51723
|
-
if (windowSize > itemCount) {
|
|
51724
|
-
windowSize = itemCount;
|
|
51725
|
-
}
|
|
51747
|
+
// recycle them. `centerRowSignal` holds the row currently at the center
|
|
51748
|
+
// (round(pos / itemSize)); it changes only when the wheel crosses a row (not
|
|
51749
|
+
// every frame), so the window re-renders on demand, not per frame. WheelWindow
|
|
51750
|
+
// owns both its size and its top slot (base), derived from that row and from the
|
|
51751
|
+
// items it reads off the tracker itself — see its own comment. The per-frame
|
|
51752
|
+
// transform is imperative (--wheel-offset); renderedBaseRef mirrors the base the
|
|
51753
|
+
// DOM shows so the transform stays consistent with it.
|
|
51726
51754
|
const centerRowSignal = useSignal(0);
|
|
51727
51755
|
const renderedBaseRef = useRef(0);
|
|
51728
51756
|
// Row size in px, measured once from a rendered slot (rows are uniform).
|
|
@@ -52426,8 +52454,8 @@ function WheelUI(props) {
|
|
|
52426
52454
|
className: "navi_wheel_list",
|
|
52427
52455
|
children: jsx(WheelWindow, {
|
|
52428
52456
|
centerRowSignal: centerRowSignal,
|
|
52429
|
-
|
|
52430
|
-
|
|
52457
|
+
visibleCount: visibleCount,
|
|
52458
|
+
tracker: tracker,
|
|
52431
52459
|
isLoop: isLoop,
|
|
52432
52460
|
onBaseCommit: commitRenderedBase
|
|
52433
52461
|
})
|
|
@@ -52440,8 +52468,8 @@ function WheelUI(props) {
|
|
|
52440
52468
|
className: "navi_wheel_list",
|
|
52441
52469
|
children: jsx(WheelWindow, {
|
|
52442
52470
|
centerRowSignal: centerRowSignal,
|
|
52443
|
-
|
|
52444
|
-
|
|
52471
|
+
visibleCount: visibleCount,
|
|
52472
|
+
tracker: tracker,
|
|
52445
52473
|
isLoop: isLoop
|
|
52446
52474
|
})
|
|
52447
52475
|
})
|
|
@@ -52458,21 +52486,38 @@ const WHEEL_PSEUDO_CLASSES = [":focus-within", ":focus-visible", ":read-only", "
|
|
|
52458
52486
|
|
|
52459
52487
|
// The recycled window: a fixed set of `windowSize` <li> slots (one per visible
|
|
52460
52488
|
// row + 2 buffer), keyed by slot position so each DOM node is reused and only its
|
|
52461
|
-
// content re-renders. `base` (the top slot's value index)
|
|
52462
|
-
//
|
|
52463
|
-
//
|
|
52464
|
-
//
|
|
52465
|
-
//
|
|
52466
|
-
//
|
|
52467
|
-
//
|
|
52489
|
+
// content re-renders. `base` (the top slot's value index) and windowSize are both
|
|
52490
|
+
// derived here rather than upstream, from the items read straight off the tracker:
|
|
52491
|
+
// this component renders right after the Wheel.Item children, which register
|
|
52492
|
+
// during their own render, so it can draw the real rows in the very first commit.
|
|
52493
|
+
// Taking them from the parent instead would mean drawing an empty wheel first (the
|
|
52494
|
+
// parent renders before its children, and the tracker's signal only lands on a
|
|
52495
|
+
// microtask) — a wheel with no width, which is enough to misplace whatever sizes
|
|
52496
|
+
// itself on it, e.g. a dialog centered on its content.
|
|
52497
|
+
// Each slot shows items[base + slot] (wrapped when looping). It reads
|
|
52498
|
+
// centerRowSignal, so it re-renders ONLY when the wheel crosses a row, not every
|
|
52499
|
+
// frame — the per-frame motion is the imperative transform in applyOffset. On each
|
|
52500
|
+
// new base it calls onBaseCommit so the transform re-syncs to the freshly rendered
|
|
52501
|
+
// rows same-frame.
|
|
52468
52502
|
const WheelWindow = ({
|
|
52469
52503
|
centerRowSignal,
|
|
52470
|
-
|
|
52471
|
-
|
|
52504
|
+
visibleCount,
|
|
52505
|
+
tracker,
|
|
52472
52506
|
isLoop,
|
|
52473
52507
|
onBaseCommit
|
|
52474
52508
|
}) => {
|
|
52509
|
+
// Subscribing is what re-renders this window when items are added or removed
|
|
52510
|
+
// later; what to draw right now is read synchronously below.
|
|
52511
|
+
// eslint-disable-next-line no-unused-expressions
|
|
52512
|
+
tracker.itemsSignal.value;
|
|
52513
|
+
const trackedItems = tracker.peekItems();
|
|
52475
52514
|
const count = trackedItems.length;
|
|
52515
|
+
// visibleCount + 2 (one buffer row each side), but never more rows than there
|
|
52516
|
+
// are values.
|
|
52517
|
+
let windowSize = visibleCount + 2;
|
|
52518
|
+
if (windowSize > count) {
|
|
52519
|
+
windowSize = count;
|
|
52520
|
+
}
|
|
52476
52521
|
let base = centerRowSignal.value - Math.floor(windowSize / 2);
|
|
52477
52522
|
// Non-loop: keep the window inside the value range so every slot maps to a real
|
|
52478
52523
|
// value; the transform then leaves the blank runway above the first / below the
|
|
@@ -57972,9 +58017,9 @@ const css$2 = /* css */`
|
|
|
57972
58017
|
.navi_card_layout {
|
|
57973
58018
|
--layout-margin: 30px;
|
|
57974
58019
|
--layout-padding: 20px;
|
|
57975
|
-
--layout-background:
|
|
58020
|
+
--layout-background: var(--navi-surface-color);
|
|
57976
58021
|
--layout-border-width: 2px;
|
|
57977
|
-
--layout-border-color:
|
|
58022
|
+
--layout-border-color: var(--navi-popup-border-color);
|
|
57978
58023
|
--layout-border-radius: 10px;
|
|
57979
58024
|
--layout-min-width: 300px;
|
|
57980
58025
|
--layout-min-height: auto;
|
|
@@ -58093,7 +58138,9 @@ installImportMetaCssBuild(import.meta);const css$1 = /* css */`
|
|
|
58093
58138
|
@layer navi {
|
|
58094
58139
|
.navi_viewport_layout {
|
|
58095
58140
|
--layout-padding: 40px;
|
|
58096
|
-
|
|
58141
|
+
/* The page's own paper: the shared surface token, so a dark theme gets a
|
|
58142
|
+
dark page without every screen overriding it. */
|
|
58143
|
+
--layout-background: var(--navi-surface-color);
|
|
58097
58144
|
}
|
|
58098
58145
|
}
|
|
58099
58146
|
|
|
@@ -58300,14 +58347,17 @@ const css = /* css */`
|
|
|
58300
58347
|
z-index: 1;
|
|
58301
58348
|
background-color: var(--navi-popup-background-color);
|
|
58302
58349
|
}
|
|
58350
|
+
/* The separator token, not the popup border: these lines split two
|
|
58351
|
+
regions of the panel's own surface (the head/foot from what scrolls
|
|
58352
|
+
under them), they are not the panel's edge. */
|
|
58303
58353
|
.navi_side_panel_head {
|
|
58304
58354
|
top: 0;
|
|
58305
|
-
border-bottom: 1px solid var(--navi-
|
|
58355
|
+
border-bottom: 1px solid var(--navi-separator-color-default);
|
|
58306
58356
|
}
|
|
58307
58357
|
.navi_side_panel_foot {
|
|
58308
58358
|
bottom: 0;
|
|
58309
58359
|
padding: 12px 16px;
|
|
58310
|
-
border-top: 1px solid var(--navi-
|
|
58360
|
+
border-top: 1px solid var(--navi-separator-color-default);
|
|
58311
58361
|
}
|
|
58312
58362
|
}
|
|
58313
58363
|
`;
|