@jsenv/navi 0.27.5 → 0.27.6
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 +83 -24
- package/dist/jsenv_navi.js.map +17 -16
- package/package.json +2 -2
package/dist/jsenv_navi.js
CHANGED
|
@@ -3,7 +3,7 @@ import { isValidElement, createContext, h, toChildArray, render, Fragment, clone
|
|
|
3
3
|
import { useErrorBoundary, useLayoutEffect, useEffect, useContext, useMemo, useRef, useState, useCallback, useId } from "preact/hooks";
|
|
4
4
|
import { jsxs, jsx, Fragment as Fragment$1 } from "preact/jsx-runtime";
|
|
5
5
|
import { signal, effect, computed, batch, useSignal } from "@preact/signals";
|
|
6
|
-
import { createIterableWeakSet, createEventGroupLogger, mergeOneStyle, normalizeStyle, createPubSub, findEvent, dispatchInternalCustomEvent, getElementSignature, mergeTwoStyles, normalizeStyles, createGroupTransitionController, getBorderRadius, preventIntermediateScrollbar, createOpacityTransition, findBefore, findAfter, createValueEffect, getVisuallyVisibleInfo, getFirstVisuallyVisibleAncestor, allowWheelThrough, dispatchPublicCustomEvent, resolveCSSColor, createStyleController, visibleRectEffect, pickPositionRelativeTo, getBorderSizes, getPaddingSizes, measureLongestVisualLineWidth, findFocusDelegateTarget, getKeyboardEventDefaultAction, resolveCSSSize, activeElementSignal, hasCSSSizeUnit, resolveOklchLightness, contrastColor, dispatchCustomEvent, initFocusGroup, elementIsFocusable, findFocusable, trapScrollInside, trapFocusInside,
|
|
6
|
+
import { createIterableWeakSet, createEventGroupLogger, mergeOneStyle, normalizeStyle, createPubSub, findEvent, dispatchInternalCustomEvent, getElementSignature, mergeTwoStyles, normalizeStyles, createGroupTransitionController, getBorderRadius, preventIntermediateScrollbar, createOpacityTransition, findBefore, findAfter, createValueEffect, getVisuallyVisibleInfo, getFirstVisuallyVisibleAncestor, allowWheelThrough, dispatchPublicCustomEvent, resolveCSSColor, createStyleController, visibleRectEffect, pickPositionRelativeTo, getBorderSizes, getPaddingSizes, measureLongestVisualLineWidth, findFocusDelegateTarget, getKeyboardEventDefaultAction, resolveCSSSize, activeElementSignal, hasCSSSizeUnit, resolveOklchLightness, contrastColor, dispatchCustomEvent, initFocusGroup, elementIsFocusable, findFocusable, snapToPixel, trapScrollInside, trapFocusInside, scrollIntoViewScoped, dragAfterThreshold, getScrollContainer, stickyAsRelativeCoords, createDragToMoveGestureController, getDropTargetInfo, setStyles, useActiveElement, measureWidestChildRow } from "@jsenv/dom";
|
|
7
7
|
export { contrastColor, startDragToReorder } from "@jsenv/dom";
|
|
8
8
|
import { prefixFirstAndIndentRemainingLines } from "@jsenv/humanize";
|
|
9
9
|
import { createValidity } from "@jsenv/validity";
|
|
@@ -24713,6 +24713,7 @@ const CONTROL_ATTRIBUTE_SET = new Set([
|
|
|
24713
24713
|
"navi-input-type",
|
|
24714
24714
|
"navi-control-proxy-for",
|
|
24715
24715
|
"aria-controls",
|
|
24716
|
+
"tabIndex",
|
|
24716
24717
|
|
|
24717
24718
|
"data-callout-arrow-x",
|
|
24718
24719
|
"data-callout-point-to-border-box",
|
|
@@ -28653,8 +28654,9 @@ installImportMetaCssBuild(import.meta);const css$z = /* css */`
|
|
|
28653
28654
|
--margin: 3px 3px 0 5px;
|
|
28654
28655
|
--outline-offset: 1px;
|
|
28655
28656
|
--outline-width: 2px;
|
|
28656
|
-
|
|
28657
|
-
--
|
|
28657
|
+
/* Rounding ensures outline is visually a nice circle */
|
|
28658
|
+
--width: round(0.815em, 1px);
|
|
28659
|
+
--height: round(0.815em, 1px);
|
|
28658
28660
|
|
|
28659
28661
|
--color-mix-light: black;
|
|
28660
28662
|
--color-mix-dark: white;
|
|
@@ -31623,9 +31625,18 @@ const Dialog = props => {
|
|
|
31623
31625
|
const debugFocus = useDebugFocus();
|
|
31624
31626
|
const openedRef = useRef(false);
|
|
31625
31627
|
const [addCleanup, cleanup] = useCleanup();
|
|
31626
|
-
const open = e
|
|
31628
|
+
const open = (e, {
|
|
31629
|
+
anchor
|
|
31630
|
+
}) => {
|
|
31631
|
+
const effectiveAnchor = anchor || document.documentElement;
|
|
31627
31632
|
debugPopup(`"${e.type}" on ${getElementSignature(e.target)} -> openDialog`);
|
|
31628
31633
|
const dialogEl = ref.current;
|
|
31634
|
+
const {
|
|
31635
|
+
width,
|
|
31636
|
+
height
|
|
31637
|
+
} = effectiveAnchor.getBoundingClientRect();
|
|
31638
|
+
dialogEl.style.setProperty("--anchor-width", `${snapToPixel(width)}px`);
|
|
31639
|
+
dialogEl.style.setProperty("--anchor-height", `${snapToPixel(height)}px`);
|
|
31629
31640
|
dialogEl.showModal();
|
|
31630
31641
|
focusFirstAutofocusOrFocusable(dialogEl, debugFocus, e);
|
|
31631
31642
|
if (scrollTrap) {
|
|
@@ -31647,7 +31658,9 @@ const Dialog = props => {
|
|
|
31647
31658
|
event: e
|
|
31648
31659
|
});
|
|
31649
31660
|
};
|
|
31650
|
-
const onRequestOpen = e
|
|
31661
|
+
const onRequestOpen = (e, {
|
|
31662
|
+
anchor
|
|
31663
|
+
}) => {
|
|
31651
31664
|
const dialogEl = ref.current;
|
|
31652
31665
|
if (!dialogEl) {
|
|
31653
31666
|
return;
|
|
@@ -31655,7 +31668,9 @@ const Dialog = props => {
|
|
|
31655
31668
|
if (openedRef.current) {
|
|
31656
31669
|
return;
|
|
31657
31670
|
}
|
|
31658
|
-
open(e
|
|
31671
|
+
open(e, {
|
|
31672
|
+
anchor
|
|
31673
|
+
});
|
|
31659
31674
|
};
|
|
31660
31675
|
const onRequestClose = e => {
|
|
31661
31676
|
const dialogEl = ref.current;
|
|
@@ -31687,7 +31702,12 @@ const Dialog = props => {
|
|
|
31687
31702
|
onRequestClose(e);
|
|
31688
31703
|
},
|
|
31689
31704
|
onnavi_request_open: e => {
|
|
31690
|
-
|
|
31705
|
+
const {
|
|
31706
|
+
anchor
|
|
31707
|
+
} = e.detail;
|
|
31708
|
+
onRequestOpen(e, {
|
|
31709
|
+
anchor
|
|
31710
|
+
});
|
|
31691
31711
|
},
|
|
31692
31712
|
onnavi_request_close: e => {
|
|
31693
31713
|
onRequestClose(e);
|
|
@@ -31960,7 +31980,10 @@ installImportMetaCssBuild(import.meta);const css$p = /* css */`
|
|
|
31960
31980
|
/* The list scrolls inside the popover */
|
|
31961
31981
|
.navi_list_container {
|
|
31962
31982
|
width: 100%;
|
|
31963
|
-
border-radius:
|
|
31983
|
+
border-radius: max(
|
|
31984
|
+
0px,
|
|
31985
|
+
var(--picker-border-radius) - var(--picker-border-width)
|
|
31986
|
+
);
|
|
31964
31987
|
overflow: auto;
|
|
31965
31988
|
overscroll-behavior: none;
|
|
31966
31989
|
}
|
|
@@ -32006,6 +32029,7 @@ installImportMetaCssBuild(import.meta);const css$p = /* css */`
|
|
|
32006
32029
|
/* dialog */
|
|
32007
32030
|
&[aria-haspopup="dialog"] {
|
|
32008
32031
|
.navi_picker_dialog {
|
|
32032
|
+
min-width: var(--anchor-width, 0px);
|
|
32009
32033
|
max-height: 95dvh;
|
|
32010
32034
|
padding: 0;
|
|
32011
32035
|
background: var(--picker-background-color);
|
|
@@ -32030,9 +32054,12 @@ installImportMetaCssBuild(import.meta);const css$p = /* css */`
|
|
|
32030
32054
|
|
|
32031
32055
|
.navi_list_container {
|
|
32032
32056
|
width: 100%;
|
|
32033
|
-
border:
|
|
32034
|
-
|
|
32035
|
-
|
|
32057
|
+
border-radius: max(
|
|
32058
|
+
0px,
|
|
32059
|
+
var(--picker-border-radius) - var(--picker-border-width)
|
|
32060
|
+
);
|
|
32061
|
+
overflow: auto;
|
|
32062
|
+
overscroll-behavior: none;
|
|
32036
32063
|
}
|
|
32037
32064
|
|
|
32038
32065
|
/* .navi_list_container {
|
|
@@ -33816,11 +33843,10 @@ const css$m = /* css */`
|
|
|
33816
33843
|
.navi_list_fallback,
|
|
33817
33844
|
.navi_list_no_match_fallback {
|
|
33818
33845
|
order: -1;
|
|
33846
|
+
color: light-dark(#888, #aaa);
|
|
33819
33847
|
&[navi-default] {
|
|
33820
33848
|
display: inline;
|
|
33821
33849
|
padding: var(--list-item-padding);
|
|
33822
|
-
color: light-dark(#888, #aaa);
|
|
33823
|
-
font-size: 0.9em;
|
|
33824
33850
|
text-align: center;
|
|
33825
33851
|
user-select: none;
|
|
33826
33852
|
}
|
|
@@ -34139,7 +34165,9 @@ const useListScrollSync = ({
|
|
|
34139
34165
|
}
|
|
34140
34166
|
const scrollItemIntoView = itemEl => {
|
|
34141
34167
|
const trigger = `"${event.type}" on ${getElementSignature(event.target)} (${reason})`;
|
|
34142
|
-
|
|
34168
|
+
// When we display the list we prefer to have selected item at the center
|
|
34169
|
+
// otherwise, usually when focused by arrow nav, we want to keep it into view close to the nearest edge
|
|
34170
|
+
const block = event.type === "navi_displayed" ? "center" : "nearest";
|
|
34143
34171
|
const scrollToItemCall = `${getElementSignature(itemEl)}.scrollIntoView({ block: "${block}", container: "nearest" })`;
|
|
34144
34172
|
const listScrollContainerEl = ref.current.querySelector(`.navi_list_scroll_container`);
|
|
34145
34173
|
debugScroll(`${trigger} -> ${scrollToItemCall}`);
|
|
@@ -34223,12 +34251,16 @@ const useListScrollSync = ({
|
|
|
34223
34251
|
const firstSelected = items.find(i => i.selected);
|
|
34224
34252
|
if (firstSelected) {
|
|
34225
34253
|
scrollToItem(firstSelected, {
|
|
34226
|
-
event:
|
|
34254
|
+
event: new CustomEvent("navi_displayed", {
|
|
34255
|
+
detail: {
|
|
34256
|
+
originalEvent: openEvent
|
|
34257
|
+
}
|
|
34258
|
+
}),
|
|
34227
34259
|
reason: "scroll to selected"
|
|
34228
34260
|
});
|
|
34229
34261
|
} else {
|
|
34230
34262
|
scrollToItem(items[0], {
|
|
34231
|
-
event: new CustomEvent("
|
|
34263
|
+
event: new CustomEvent("navi_displayed", {
|
|
34232
34264
|
detail: {
|
|
34233
34265
|
originalEvent: openEvent
|
|
34234
34266
|
}
|
|
@@ -34661,12 +34693,25 @@ const ListItemRealOrVoid = props => {
|
|
|
34661
34693
|
const listItemVnode = jsx(ListItemReal, {
|
|
34662
34694
|
...props
|
|
34663
34695
|
});
|
|
34664
|
-
//
|
|
34665
|
-
//
|
|
34666
|
-
|
|
34667
|
-
|
|
34696
|
+
// For separator decision, we need to know "am I the first visible item?".
|
|
34697
|
+
// We deliberately do NOT use tracker's visibleIndex here because, during a
|
|
34698
|
+
// reorder render pass (e.g. items resorted by search score), other items
|
|
34699
|
+
// still have stale keyToExplicitOrder values — the binary search reads
|
|
34700
|
+
// those stale values and computes wrong indices. The result is that no
|
|
34701
|
+
// item gets visibleIndex === 0 and a spurious <hr> appears at the top.
|
|
34702
|
+
//
|
|
34703
|
+
// Instead we use the parent-provided index, which is race-free:
|
|
34704
|
+
// - global list: props.index === 0 means "first by explicit order"
|
|
34705
|
+
// (parent passes sequential indices starting at 0; filtered items
|
|
34706
|
+
// are already pushed to the end by useSearchText)
|
|
34707
|
+
// - inside a group: each group has its own item tracker and group
|
|
34708
|
+
// items don't reorder, so groupVisibleIndex is reliable
|
|
34709
|
+
const isFirstInList = groupVisibleIndex === null ? props.index === 0 : groupVisibleIndex === 0;
|
|
34710
|
+
if (!separator || isFirstInList) {
|
|
34668
34711
|
return listItemVnode;
|
|
34669
34712
|
}
|
|
34713
|
+
// separatorIndex is only used as the function-form argument (gap index)
|
|
34714
|
+
const separatorIndex = groupVisibleIndex === null ? visibleIndex : groupVisibleIndex;
|
|
34670
34715
|
const separatorVnode = typeof separator === "function" ? separator(separatorIndex - 1) : separator;
|
|
34671
34716
|
return jsxs(Fragment$1, {
|
|
34672
34717
|
children: [separatorVnode, listItemVnode]
|
|
@@ -34716,6 +34761,8 @@ const ListItemReal = props => {
|
|
|
34716
34761
|
"navi-list-item-real": "",
|
|
34717
34762
|
...rest,
|
|
34718
34763
|
index: undefined,
|
|
34764
|
+
selected: undefined,
|
|
34765
|
+
matchScore: undefined,
|
|
34719
34766
|
hidden: hidden,
|
|
34720
34767
|
ref: ref,
|
|
34721
34768
|
children: children
|
|
@@ -35561,22 +35608,34 @@ installImportMetaCssBuild(import.meta);const css$k = /* css */`
|
|
|
35561
35608
|
--x-picker-border-color: var(--picker-border-color);
|
|
35562
35609
|
--x-picker-padding-top: var(
|
|
35563
35610
|
--picker-padding-top,
|
|
35564
|
-
var(
|
|
35611
|
+
var(
|
|
35612
|
+
--picker-padding-y,
|
|
35613
|
+
var(--picker-padding, var(--picker-padding-y-default))
|
|
35614
|
+
)
|
|
35565
35615
|
);
|
|
35566
35616
|
--x-picker-padding-right-base: var(
|
|
35567
35617
|
--picker-padding-right,
|
|
35568
|
-
var(
|
|
35618
|
+
var(
|
|
35619
|
+
--picker-padding-x,
|
|
35620
|
+
var(--picker-padding, var(--picker-padding-x-default))
|
|
35621
|
+
)
|
|
35569
35622
|
);
|
|
35570
35623
|
--x-picker-padding-right: calc(
|
|
35571
35624
|
var(--x-picker-padding-right-base) + var(--picker-right-slot-size) - 2px
|
|
35572
35625
|
);
|
|
35573
35626
|
--x-picker-padding-left: var(
|
|
35574
35627
|
--picker-padding-left,
|
|
35575
|
-
var(
|
|
35628
|
+
var(
|
|
35629
|
+
--picker-padding-x,
|
|
35630
|
+
var(--picker-padding, var(--picker-padding-x-default))
|
|
35631
|
+
)
|
|
35576
35632
|
);
|
|
35577
35633
|
--x-picker-padding-bottom: var(
|
|
35578
35634
|
--picker-padding-bottom,
|
|
35579
|
-
var(
|
|
35635
|
+
var(
|
|
35636
|
+
--picker-padding-y,
|
|
35637
|
+
var(--picker-padding, var(--picker-padding-y-default))
|
|
35638
|
+
)
|
|
35580
35639
|
);
|
|
35581
35640
|
--x-picker-color: var(--picker-color);
|
|
35582
35641
|
|