@jsenv/navi 0.29.141 → 0.29.142
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 +49 -26
- package/dist/jsenv_navi.js.map +4 -5
- package/docs/popup_open.md +18 -5
- package/package.json +1 -1
package/dist/jsenv_navi.js
CHANGED
|
@@ -5,7 +5,7 @@
|
|
|
5
5
|
import { installImportMetaCssBuild, windowHeightSignal, windowWidthSignal, visualViewportHeightSignal, visualViewportWidthSignal, getAppHeight, getAppWidth, coarsePointerSignal, smallTouchScreenSignal } from "./jsenv_navi_side_effects.js";
|
|
6
6
|
export { disableVirtualKeyboardOverlay } from "./jsenv_navi_side_effects.js";
|
|
7
7
|
import { elementIsFocusable, createIterableWeakSet, dispatchInternalCustomEvent, dispatchCustomEvent, getVisuallyVisibleInfo, getFirstVisuallyVisibleAncestor, getElementSignature, createPubSub, findEvent, createValueEffect, findFocusDelegateTarget, findFocusable, allowWheelThrough, dispatchPublicCustomEvent, resolveCSSColor, ELEMENT_SIZE_CHANGE, findSelfOrAncestorFixedPosition, visibleRectEffect, pickPositionRelativeTo, getBorderSizes, getPaddingSizes, applyNewPosition, measureLongestVisualLineWidth, chainEvent, waitForPressHeld, suppressClickAfterGesture, startDragToTravel, markDragSource, startDragTo, createEventGroupLogger, getKeyboardEventDefaultAction, activeElementSignal, normalizeStyle, mergeOneStyle, getPositionedParent, normalizeStyles, createGroupTransitionController, getBorderRadius, preventIntermediateScrollbar, createOpacityTransition, watchWheelTravel, scrollRoomTowards, getScrollContainer, closestOpenableAncestor, isAncestorOpen, isDisplayedDespiteClosedAncestor, observeAncestorOpenState, getAncestorOpenType, findBefore, findAfter, resolveCSSSize, hasCSSSizeUnit, initFocusGroup, scrollIntoViewScoped, stringifyStyle as stringifyStyle$1, resolveOklchLightness, contrastColor, isTouchDrivenEvent, parsePositionArea, snapToPixel, trapFocusInside, trapScrollInside, onAncestorReopen, canScroll, measureWidestChildRow, performTabNavigation, wheelGestureIsTakenFrom, releaseWheelGesture, claimWheelGesture, dragAfterIntent, stickyAsRelativeCoords, createDragToMoveGestureController, getDropTargetInfo, setStyles, useActiveElement } from "@jsenv/dom";
|
|
8
|
-
export { clickIsSuppressed, contrastColor, findEvent, startDragTo } from "@jsenv/dom";
|
|
8
|
+
export { chainEvent, clickIsSuppressed, contrastColor, findEvent, startDragTo } from "@jsenv/dom";
|
|
9
9
|
import { signal, computed, effect, untracked, batch, useComputed, useSignal } from "@preact/signals";
|
|
10
10
|
import { isValidElement, h, Fragment, createContext, render, toChildArray, options, cloneElement } from "preact";
|
|
11
11
|
import { useErrorBoundary, useLayoutEffect, useContext, useCallback, useRef, useState, useEffect, useMemo, useId } from "preact/hooks";
|
|
@@ -30465,7 +30465,16 @@ const anyMatchingRouteSignal = (routes) => {
|
|
|
30465
30465
|
* @param {Element} element The element asking — the command's source, and the
|
|
30466
30466
|
* anchor a popup opens on unless `anchor` says otherwise.
|
|
30467
30467
|
* @param {string} command
|
|
30468
|
-
* @param {Event} event What
|
|
30468
|
+
* @param {Event} event What caused this. Mandatory: it is what makes a command
|
|
30469
|
+
* traceable back to its origin — the debug panel groups everything a gesture
|
|
30470
|
+
* set off under it, and the gates below read it to know whether the default
|
|
30471
|
+
* was already prevented and which mouse button was pressed. When nothing was
|
|
30472
|
+
* handed over — a timer firing, an action settling, a signal changing — build
|
|
30473
|
+
* a `CustomEvent` that names what happened and chain it to whatever preceded
|
|
30474
|
+
* it, rather than leaving the origin unsaid:
|
|
30475
|
+
* const expiredEvent = new CustomEvent("session_expired");
|
|
30476
|
+
* chainEvent(expiredEvent, causeEvent); // when something did precede it
|
|
30477
|
+
* triggerNaviCommand(dialogEl, "--navi-open", expiredEvent);
|
|
30469
30478
|
* @param {object} [options]
|
|
30470
30479
|
* @param {boolean} [options.optional] No suitable target is not a warning.
|
|
30471
30480
|
* @param {any} [options.value] What the command is about, carried to whoever
|
|
@@ -30482,6 +30491,11 @@ const triggerNaviCommand = (
|
|
|
30482
30491
|
event,
|
|
30483
30492
|
{ optional, value, anchor } = {},
|
|
30484
30493
|
) => {
|
|
30494
|
+
if (!event) {
|
|
30495
|
+
throw new Error(
|
|
30496
|
+
`"${command}" triggered without an event: it is mandatory, a command must say what caused it. Pass the gesture, or a CustomEvent naming the cause when no gesture did — see triggerNaviCommand's jsdoc.`,
|
|
30497
|
+
);
|
|
30498
|
+
}
|
|
30485
30499
|
const naviCommand =
|
|
30486
30500
|
NAVI_COMMANDS[command] || NAVI_COMMANDS[commandName(command)];
|
|
30487
30501
|
if (!naviCommand) {
|
|
@@ -33597,6 +33611,12 @@ const GROUP_DEFAULTS = {
|
|
|
33597
33611
|
*
|
|
33598
33612
|
* **Filtering**: `childControlFilter` can exclude certain child types from aggregation
|
|
33599
33613
|
* (e.g. ignoring buttons inside a selectable list).
|
|
33614
|
+
*
|
|
33615
|
+
* **Aggregating**: `aggregateChildStates(children, fallbackState, stateNow)` — what the
|
|
33616
|
+
* children add up to. `fallbackState` is the empty of the declared `stateType`;
|
|
33617
|
+
* `stateNow` is what the group is worth as it is asked, which an aggregate reads to
|
|
33618
|
+
* answer for children that are not there (a selectable list whose selected row is not
|
|
33619
|
+
* drawn).
|
|
33600
33620
|
*/
|
|
33601
33621
|
const useUIGroupStateController = (
|
|
33602
33622
|
props,
|
|
@@ -33753,16 +33773,22 @@ const useUIGroupStateController = (
|
|
|
33753
33773
|
// taking that for an answer is how a value handed to it evaporates on
|
|
33754
33774
|
// the way in, and how that emptiness then travels back up to whoever
|
|
33755
33775
|
// handed it (a picker showing its row as unanswered).
|
|
33756
|
-
|
|
33776
|
+
//
|
|
33777
|
+
// `stateNow` is what the group is worth as it is asked: what it keeps
|
|
33778
|
+
// when there is nobody to ask, and what an aggregate reads to answer for
|
|
33779
|
+
// what its children do not say — a selection whose row is not drawn (see
|
|
33780
|
+
// ListSelectable) lives there and nowhere else.
|
|
33781
|
+
const aggregateGroupUIState = (stateNow) => {
|
|
33757
33782
|
const someChildCanAnswer = childUIStateControllerArray.some(
|
|
33758
33783
|
shouldPropagateStateToChild,
|
|
33759
33784
|
);
|
|
33760
33785
|
if (!someChildCanAnswer) {
|
|
33761
|
-
return
|
|
33786
|
+
return stateNow;
|
|
33762
33787
|
}
|
|
33763
33788
|
const aggChildState = resolvedAggregateChildStates(
|
|
33764
33789
|
childUIStateControllerArray,
|
|
33765
33790
|
fallbackState,
|
|
33791
|
+
stateNow,
|
|
33766
33792
|
);
|
|
33767
33793
|
if (aggChildState !== undefined) {
|
|
33768
33794
|
return aggChildState;
|
|
@@ -34286,8 +34312,6 @@ const useUIGroupStateController = (
|
|
|
34286
34312
|
// ── update: runs every render after the first ─────────────────────────
|
|
34287
34313
|
(s) => {
|
|
34288
34314
|
const { controller } = s;
|
|
34289
|
-
const prevValue = controller.value;
|
|
34290
|
-
const prevHasValueProp = controller.hasValueProp;
|
|
34291
34315
|
const prevDefaultValue = controller.defaultValue;
|
|
34292
34316
|
controller.props = props;
|
|
34293
34317
|
controller.ref = ref;
|
|
@@ -34305,10 +34329,14 @@ const useUIGroupStateController = (
|
|
|
34305
34329
|
controller.placeChildrenUIState(groupUIState, propagateDownEvent);
|
|
34306
34330
|
controller.syncInternalState(groupUIState);
|
|
34307
34331
|
};
|
|
34308
|
-
|
|
34309
|
-
|
|
34310
|
-
|
|
34311
|
-
|
|
34332
|
+
// A controlled group goes on showing the value it is given. A child
|
|
34333
|
+
// answering for itself moves what the group is worth — that is what
|
|
34334
|
+
// `uiAction` reports — but the value stays the owner's, so the test is
|
|
34335
|
+
// against what the children are showing, not against the value handed
|
|
34336
|
+
// down last time. A popup reopened on another subject hands down the very
|
|
34337
|
+
// same empty value it did before, and the selection left inside it from
|
|
34338
|
+
// the previous opening is what has to go.
|
|
34339
|
+
if (hasValueProp && !compareTwoJsValues(value, controller.uiState)) {
|
|
34312
34340
|
placeChildrenFrom(value);
|
|
34313
34341
|
}
|
|
34314
34342
|
if (
|
|
@@ -61346,23 +61374,22 @@ const ListSelectable = props => {
|
|
|
61346
61374
|
focusGroupDirection,
|
|
61347
61375
|
focusGroupWrap
|
|
61348
61376
|
} = props;
|
|
61349
|
-
//
|
|
61350
|
-
// draws the rows it needs and no more
|
|
61351
|
-
// of the window
|
|
61352
|
-
//
|
|
61353
|
-
//
|
|
61354
|
-
|
|
61355
|
-
|
|
61356
|
-
|
|
61357
|
-
|
|
61377
|
+
// `kept` is what the list holds as it is asked, which is not the same as what
|
|
61378
|
+
// its rows say: a list draws the rows it needs and no more, so the selected
|
|
61379
|
+
// one may be scrolled out of the window or filtered out of the view, and a
|
|
61380
|
+
// row that is not there cannot say it is not selected. Reading it off the
|
|
61381
|
+
// group rather than remembering it here is what makes a value put ON the list
|
|
61382
|
+
// (a `value` prop, a signal, a reopened popup) replace the whole selection —
|
|
61383
|
+
// a private memory of its own would go on holding the rows it could not see
|
|
61384
|
+
// being unselected.
|
|
61385
|
+
//
|
|
61358
61386
|
// `fallbackState` is the empty of the shape the list declared below
|
|
61359
61387
|
// (`stateType`): `[]` for a multiple list, nothing for a single one. Taking
|
|
61360
61388
|
// it is what lets an emptied list say "empty" — `undefined` is the word for
|
|
61361
61389
|
// "unset", and a bound stateSignal reads that as "nothing decided here, go
|
|
61362
61390
|
// back to the default" (see docs/control_value.md), which is how a list
|
|
61363
61391
|
// emptied down to its last row puts that row back on reload.
|
|
61364
|
-
const aggregateChildStates = (children, fallbackState) => {
|
|
61365
|
-
const kept = selectionRef.current;
|
|
61392
|
+
const aggregateChildStates = (children, fallbackState, kept) => {
|
|
61366
61393
|
if (multiple) {
|
|
61367
61394
|
const drawnValues = new Set(children.map(child => child.props.value));
|
|
61368
61395
|
const stillSelected = Array.isArray(kept) ? kept.filter(value => !drawnValues.has(value)) : [];
|
|
@@ -61371,13 +61398,10 @@ const ListSelectable = props => {
|
|
|
61371
61398
|
stillSelected.push(child.uiState);
|
|
61372
61399
|
}
|
|
61373
61400
|
}
|
|
61374
|
-
|
|
61375
|
-
selectionRef.current = values;
|
|
61376
|
-
return values;
|
|
61401
|
+
return stillSelected.length === 0 ? fallbackState : stillSelected;
|
|
61377
61402
|
}
|
|
61378
61403
|
for (const child of children) {
|
|
61379
61404
|
if (child.uiState !== undefined) {
|
|
61380
|
-
selectionRef.current = child.uiState;
|
|
61381
61405
|
return child.uiState;
|
|
61382
61406
|
}
|
|
61383
61407
|
}
|
|
@@ -61385,7 +61409,6 @@ const ListSelectable = props => {
|
|
|
61385
61409
|
// deselected; if it is not, the list keeps what it holds.
|
|
61386
61410
|
const keptIsDrawn = children.some(child => child.props.value === kept);
|
|
61387
61411
|
if (keptIsDrawn) {
|
|
61388
|
-
selectionRef.current = undefined;
|
|
61389
61412
|
return undefined;
|
|
61390
61413
|
}
|
|
61391
61414
|
return kept;
|