@jsenv/navi 0.29.104 → 0.29.106
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 +490 -282
- package/dist/jsenv_navi.js.map +63 -56
- package/docs/AI_INSTRUCTIONS.md +3 -3
- package/docs/actions.md +33 -0
- package/docs/badge_list.md +3 -2
- package/docs/interactions.md +16 -7
- package/docs/popup_open.md +102 -0
- package/package.json +2 -2
package/dist/jsenv_navi.js
CHANGED
|
@@ -4,7 +4,7 @@
|
|
|
4
4
|
*/
|
|
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
|
-
import { elementIsFocusable, createPubSub, dispatchInternalCustomEvent, dispatchCustomEvent, getVisuallyVisibleInfo, getFirstVisuallyVisibleAncestor, getElementSignature, findEvent, createValueEffect, findFocusDelegateTarget, findFocusable, allowWheelThrough, dispatchPublicCustomEvent, resolveCSSColor, ELEMENT_SIZE_CHANGE, findSelfOrAncestorFixedPosition, visibleRectEffect, pickPositionRelativeTo, getBorderSizes, getPaddingSizes, applyNewPosition, measureLongestVisualLineWidth, chainEvent, waitForPressHeld, suppressClickAfterGesture, startDragToTravel, markDragSource, startDragTo, createIterableWeakSet, createEventGroupLogger, getKeyboardEventDefaultAction, activeElementSignal, normalizeStyle, mergeOneStyle, getPositionedParent,
|
|
7
|
+
import { elementIsFocusable, createPubSub, dispatchInternalCustomEvent, dispatchCustomEvent, getVisuallyVisibleInfo, getFirstVisuallyVisibleAncestor, getElementSignature, findEvent, createValueEffect, findFocusDelegateTarget, findFocusable, allowWheelThrough, dispatchPublicCustomEvent, resolveCSSColor, ELEMENT_SIZE_CHANGE, findSelfOrAncestorFixedPosition, visibleRectEffect, pickPositionRelativeTo, getBorderSizes, getPaddingSizes, applyNewPosition, measureLongestVisualLineWidth, chainEvent, waitForPressHeld, suppressClickAfterGesture, startDragToTravel, markDragSource, startDragTo, createIterableWeakSet, createEventGroupLogger, getKeyboardEventDefaultAction, activeElementSignal, normalizeStyle, mergeOneStyle, getPositionedParent, normalizeStyles, resolveCSSSize, closestOpenableAncestor, isAncestorOpen, observeAncestorOpenState, getAncestorOpenType, hasCSSSizeUnit, resolveOklchLightness, contrastColor, clickIsSuppressed, isTouchDrivenEvent, scrollIntoViewScoped, scrollRoomTowards, parsePositionArea, snapToPixel, trapFocusInside, trapScrollInside, onAncestorReopen, createGroupTransitionController, getBorderRadius, preventIntermediateScrollbar, createOpacityTransition, watchWheelTravel, findBefore, findAfter, initFocusGroup, stringifyStyle as stringifyStyle$1, getScrollContainer, canScroll, measureWidestChildRow, performTabNavigation, wheelGestureIsTakenFrom, releaseWheelGesture, claimWheelGesture, dragAfterIntent, stickyAsRelativeCoords, createDragToMoveGestureController, getDropTargetInfo, setStyles, useActiveElement } from "@jsenv/dom";
|
|
8
8
|
export { clickIsSuppressed, contrastColor, findEvent, startDragTo } from "@jsenv/dom";
|
|
9
9
|
import { signal, computed, effect, batch, untracked, useSignal } from "@preact/signals";
|
|
10
10
|
import { createContext, isValidElement, h, Fragment, render, toChildArray, options, cloneElement } from "preact";
|
|
@@ -2430,9 +2430,13 @@ const useOwnTargetHidden = (props) => {
|
|
|
2430
2430
|
*
|
|
2431
2431
|
* Beyond recursive object/array comparison it covers the edge cases `===` gets
|
|
2432
2432
|
* "wrong" for equality purposes: NaN equals NaN, Date compared by time value,
|
|
2433
|
-
* cycles don't loop (a
|
|
2434
|
-
*
|
|
2435
|
-
*
|
|
2433
|
+
* cycles don't loop (a set of the pairs being compared guards circular refs),
|
|
2434
|
+
* and same-type is required
|
|
2435
|
+
* before descending. Functions, and objects with nothing enumerable to compare
|
|
2436
|
+
* (a Set, a Map, an element, a URL), are equal by reference only — nothing in
|
|
2437
|
+
* them says whether two are "the same". Cheap paths run first: reference
|
|
2438
|
+
* equality, then the identity short-circuit below, then array length before
|
|
2439
|
+
* element-by-element.
|
|
2436
2440
|
*
|
|
2437
2441
|
* SYMBOL_IDENTITY. Two *different* object instances can be declared "conceptually
|
|
2438
2442
|
* the same" by sharing a SYMBOL_IDENTITY value; the comparison then treats them as
|
|
@@ -2494,6 +2498,11 @@ const compareTwoJsValues = (
|
|
|
2494
2498
|
if (aType !== bType) {
|
|
2495
2499
|
return false;
|
|
2496
2500
|
}
|
|
2501
|
+
if (aType === "function") {
|
|
2502
|
+
// Not the same function (reference equality came first), and nothing in
|
|
2503
|
+
// a function says whether two of them do the same thing.
|
|
2504
|
+
return false;
|
|
2505
|
+
}
|
|
2497
2506
|
const aIsPrimitive =
|
|
2498
2507
|
a === null || (aType !== "object" && aType !== "function");
|
|
2499
2508
|
const bIsPrimitive =
|
|
@@ -2504,14 +2513,22 @@ const compareTwoJsValues = (
|
|
|
2504
2513
|
if (aIsPrimitive && bIsPrimitive) {
|
|
2505
2514
|
return a === b;
|
|
2506
2515
|
}
|
|
2507
|
-
|
|
2508
|
-
|
|
2509
|
-
|
|
2510
|
-
if (seenSet.has(b)) {
|
|
2516
|
+
// Back on something still being compared: a cycle. No loop, and no answer
|
|
2517
|
+
// either — equal by a route that never ends is not equal.
|
|
2518
|
+
if (seenSet.has(a) || seenSet.has(b)) {
|
|
2511
2519
|
return false;
|
|
2512
2520
|
}
|
|
2521
|
+
// Held only while a and b are being compared, not for the rest of the
|
|
2522
|
+
// walk: the same object is rightly met again elsewhere — in an unordered
|
|
2523
|
+
// array every element of a is tried against every element of b.
|
|
2513
2524
|
seenSet.add(a);
|
|
2514
2525
|
seenSet.add(b);
|
|
2526
|
+
const result = compareComposite(a, b);
|
|
2527
|
+
seenSet.delete(a);
|
|
2528
|
+
seenSet.delete(b);
|
|
2529
|
+
return result;
|
|
2530
|
+
};
|
|
2531
|
+
const compareComposite = (a, b) => {
|
|
2515
2532
|
const aIsArray = Array.isArray(a);
|
|
2516
2533
|
const bIsArray = Array.isArray(b);
|
|
2517
2534
|
if (aIsArray !== bIsArray) {
|
|
@@ -2569,25 +2586,25 @@ const compareTwoJsValues = (
|
|
|
2569
2586
|
return true;
|
|
2570
2587
|
}
|
|
2571
2588
|
// Date objects must be compared by time value, not by enumerable keys (which are empty)
|
|
2572
|
-
|
|
2573
|
-
|
|
2574
|
-
|
|
2575
|
-
|
|
2576
|
-
|
|
2577
|
-
|
|
2578
|
-
|
|
2579
|
-
const aTime = a.getTime();
|
|
2580
|
-
const bTime = b.getTime();
|
|
2581
|
-
if (aTime !== bTime) {
|
|
2582
|
-
return false;
|
|
2583
|
-
}
|
|
2584
|
-
}
|
|
2589
|
+
const aIsDate = a instanceof Date;
|
|
2590
|
+
const bIsDate = b instanceof Date;
|
|
2591
|
+
if (aIsDate !== bIsDate) {
|
|
2592
|
+
return false;
|
|
2593
|
+
}
|
|
2594
|
+
if (aIsDate) {
|
|
2595
|
+
return a.getTime() === b.getTime();
|
|
2585
2596
|
}
|
|
2586
2597
|
const aKeys = Object.keys(a);
|
|
2587
2598
|
const bKeys = Object.keys(b);
|
|
2588
2599
|
if (aKeys.length !== bKeys.length) {
|
|
2589
2600
|
return false;
|
|
2590
2601
|
}
|
|
2602
|
+
if (aKeys.length === 0 && (!isPlainObject$2(a) || !isPlainObject$2(b))) {
|
|
2603
|
+
// A Set, a Map, an element, a URL: nothing enumerable to tell two of them
|
|
2604
|
+
// apart, so they are the same one or they are not — and they are not,
|
|
2605
|
+
// reference equality came first.
|
|
2606
|
+
return false;
|
|
2607
|
+
}
|
|
2591
2608
|
if (lightKeySet) {
|
|
2592
2609
|
// compare light keys first, then remaining keys
|
|
2593
2610
|
// (optimization for cases where some keys are more likely to differ and/or faster to compare)
|
|
@@ -2625,6 +2642,11 @@ const compareTwoJsValues = (
|
|
|
2625
2642
|
return compare(rootA, rootB);
|
|
2626
2643
|
};
|
|
2627
2644
|
|
|
2645
|
+
const isPlainObject$2 = (value) => {
|
|
2646
|
+
const prototype = Object.getPrototypeOf(value);
|
|
2647
|
+
return prototype === Object.prototype || prototype === null;
|
|
2648
|
+
};
|
|
2649
|
+
|
|
2628
2650
|
// Global signal registry for route template detection
|
|
2629
2651
|
const globalSignalRegistry = new Map();
|
|
2630
2652
|
let signalIdCounter = 0;
|
|
@@ -16708,16 +16730,10 @@ const getHowToHandleStyleProp = (name) => {
|
|
|
16708
16730
|
}
|
|
16709
16731
|
return getStyle;
|
|
16710
16732
|
};
|
|
16711
|
-
const prepareStyleValue = (
|
|
16712
|
-
existingValue,
|
|
16713
|
-
value,
|
|
16714
|
-
name,
|
|
16715
|
-
styleContext,
|
|
16716
|
-
context,
|
|
16717
|
-
) => {
|
|
16733
|
+
const prepareStyleValue = (existingValue, value, name, styleContext) => {
|
|
16718
16734
|
const stringifier = getStringifier(name);
|
|
16719
|
-
const cssValue = stringifier(value, name, styleContext
|
|
16720
|
-
const mergedValue = mergeOneStyle(existingValue, cssValue, name,
|
|
16735
|
+
const cssValue = stringifier(value, name, styleContext);
|
|
16736
|
+
const mergedValue = mergeOneStyle(existingValue, cssValue, name, "css");
|
|
16721
16737
|
return mergedValue;
|
|
16722
16738
|
};
|
|
16723
16739
|
|
|
@@ -17806,30 +17822,61 @@ const isKeyboardModality = () => keyboardNavigationUsed;
|
|
|
17806
17822
|
return false;
|
|
17807
17823
|
};
|
|
17808
17824
|
|
|
17809
|
-
//
|
|
17810
|
-
//
|
|
17811
|
-
//
|
|
17812
|
-
//
|
|
17813
|
-
|
|
17814
|
-
|
|
17815
|
-
|
|
17816
|
-
|
|
17817
|
-
|
|
17818
|
-
|
|
17819
|
-
|
|
17820
|
-
|
|
17821
|
-
|
|
17822
|
-
|
|
17823
|
-
|
|
17824
|
-
|
|
17825
|
-
|
|
17826
|
-
|
|
17827
|
-
|
|
17828
|
-
|
|
17829
|
-
|
|
17830
|
-
|
|
17825
|
+
// One registration per element for everything focus-related, shared by
|
|
17826
|
+
// :focus, :focus-visible and :focus-within: they all react to the same
|
|
17827
|
+
// focusin/focusout, and they all re-check through the same callback (see
|
|
17828
|
+
// initPseudoStyles), which the Set turns into one call.
|
|
17829
|
+
const focusTrackingWeakMap = new WeakMap();
|
|
17830
|
+
const trackFocus = (el, callback) => {
|
|
17831
|
+
let tracking = focusTrackingWeakMap.get(el);
|
|
17832
|
+
if (!tracking) {
|
|
17833
|
+
const callbackSet = new Set();
|
|
17834
|
+
const onFocusChange = (e) => {
|
|
17835
|
+
for (const trackedCallback of callbackSet) {
|
|
17836
|
+
trackedCallback();
|
|
17837
|
+
}
|
|
17838
|
+
notifyAriaControlled(el, e);
|
|
17839
|
+
};
|
|
17840
|
+
el.addEventListener("focusin", onFocusChange);
|
|
17841
|
+
el.addEventListener("focusout", onFocusChange);
|
|
17842
|
+
tracking = {
|
|
17843
|
+
callbackSet,
|
|
17844
|
+
teardown: () => {
|
|
17845
|
+
el.removeEventListener("focusin", onFocusChange);
|
|
17846
|
+
el.removeEventListener("focusout", onFocusChange);
|
|
17847
|
+
focusTrackingWeakMap.delete(el);
|
|
17848
|
+
},
|
|
17849
|
+
};
|
|
17850
|
+
focusTrackingWeakMap.set(el, tracking);
|
|
17851
|
+
observeAriaControls();
|
|
17852
|
+
}
|
|
17853
|
+
tracking.callbackSet.add(callback);
|
|
17854
|
+
return () => {
|
|
17855
|
+
tracking.callbackSet.delete(callback);
|
|
17856
|
+
if (tracking.callbackSet.size === 0) {
|
|
17857
|
+
tracking.teardown();
|
|
17831
17858
|
}
|
|
17859
|
+
};
|
|
17860
|
+
};
|
|
17861
|
+
// When aria-controls changes on a focused element, what it used to control
|
|
17862
|
+
// and what it controls now both re-check their inherited focus. One observer
|
|
17863
|
+
// on the document rather than one per tracked element: the attribute changes
|
|
17864
|
+
// rarely, on few elements, while thousands are tracked — and it can be set
|
|
17865
|
+
// after the element was, so "has it at setup" would miss it.
|
|
17866
|
+
let ariaControlsObserver = null;
|
|
17867
|
+
const observeAriaControls = () => {
|
|
17868
|
+
if (ariaControlsObserver) {
|
|
17869
|
+
return;
|
|
17870
|
+
}
|
|
17871
|
+
ariaControlsObserver = new MutationObserver((mutations) => {
|
|
17832
17872
|
for (const mutation of mutations) {
|
|
17873
|
+
const el = mutation.target;
|
|
17874
|
+
if (!focusTrackingWeakMap.has(el)) {
|
|
17875
|
+
continue;
|
|
17876
|
+
}
|
|
17877
|
+
if (!el.matches(":focus-within")) {
|
|
17878
|
+
continue;
|
|
17879
|
+
}
|
|
17833
17880
|
const oldIds = (mutation.oldValue || "").split(" ").filter(Boolean);
|
|
17834
17881
|
for (const id of oldIds) {
|
|
17835
17882
|
const controlled = document.getElementById(id);
|
|
@@ -17837,30 +17884,20 @@ const isKeyboardModality = () => keyboardNavigationUsed;
|
|
|
17837
17884
|
requestPseudoStateCheck(controlled, {});
|
|
17838
17885
|
}
|
|
17839
17886
|
}
|
|
17887
|
+
notifyAriaControlled(el, {});
|
|
17840
17888
|
}
|
|
17841
|
-
notifyAriaControlled(el, {});
|
|
17842
17889
|
});
|
|
17843
|
-
|
|
17890
|
+
ariaControlsObserver.observe(document.documentElement, {
|
|
17891
|
+
subtree: true,
|
|
17844
17892
|
attributes: true,
|
|
17845
17893
|
attributeFilter: ["aria-controls"],
|
|
17846
17894
|
attributeOldValue: true,
|
|
17847
17895
|
});
|
|
17848
|
-
// }
|
|
17849
|
-
return () => {
|
|
17850
|
-
el.removeEventListener("focusin", onFocusChange);
|
|
17851
|
-
el.removeEventListener("focusout", onFocusChange);
|
|
17852
|
-
observer?.disconnect();
|
|
17853
|
-
};
|
|
17854
17896
|
};
|
|
17855
17897
|
|
|
17856
17898
|
definePseudoClass(":focus", {
|
|
17857
17899
|
attribute: "data-focus",
|
|
17858
|
-
setup:
|
|
17859
|
-
const cleanup = setupFocus(el, callback);
|
|
17860
|
-
return () => {
|
|
17861
|
-
cleanup();
|
|
17862
|
-
};
|
|
17863
|
-
},
|
|
17900
|
+
setup: trackFocus,
|
|
17864
17901
|
test: (el) => {
|
|
17865
17902
|
if (el.matches(":focus")) {
|
|
17866
17903
|
return true;
|
|
@@ -17876,9 +17913,7 @@ const isKeyboardModality = () => keyboardNavigationUsed;
|
|
|
17876
17913
|
// No per-element keydown/keyup listener: the shared recheckFocusChainOnKey
|
|
17877
17914
|
// handler re-checks the focused element (the only one a keystroke can turn
|
|
17878
17915
|
// focus-visible) so a keypress stays O(1), not O(number-of-boxes).
|
|
17879
|
-
setup:
|
|
17880
|
-
return setupFocus(el, callback);
|
|
17881
|
-
},
|
|
17916
|
+
setup: trackFocus,
|
|
17882
17917
|
test: (el) => {
|
|
17883
17918
|
if (isMatchingFocusVisible(el)) {
|
|
17884
17919
|
return true;
|
|
@@ -17891,18 +17926,7 @@ const isKeyboardModality = () => keyboardNavigationUsed;
|
|
|
17891
17926
|
});
|
|
17892
17927
|
definePseudoClass(":focus-within", {
|
|
17893
17928
|
attribute: "data-focus-within",
|
|
17894
|
-
setup:
|
|
17895
|
-
const onFocusChange = (e) => {
|
|
17896
|
-
callback();
|
|
17897
|
-
notifyAriaControlled(el, e);
|
|
17898
|
-
};
|
|
17899
|
-
el.addEventListener("focusin", onFocusChange);
|
|
17900
|
-
el.addEventListener("focusout", onFocusChange);
|
|
17901
|
-
return () => {
|
|
17902
|
-
el.removeEventListener("focusin", onFocusChange);
|
|
17903
|
-
el.removeEventListener("focusout", onFocusChange);
|
|
17904
|
-
};
|
|
17905
|
-
},
|
|
17929
|
+
setup: trackFocus,
|
|
17906
17930
|
test: (el) => {
|
|
17907
17931
|
if (el.matches(":focus-within")) {
|
|
17908
17932
|
return true;
|
|
@@ -18197,8 +18221,18 @@ const initPseudoStyles = (
|
|
|
18197
18221
|
onStateChange(state, oldPseudoState);
|
|
18198
18222
|
}),
|
|
18199
18223
|
);
|
|
18200
|
-
|
|
18224
|
+
// One function for every way a re-check can be asked, so that setups
|
|
18225
|
+
// registering it side by side (the focus tracking, for one) hold the same
|
|
18226
|
+
// callback and call it once.
|
|
18227
|
+
const requestCheck = () => {
|
|
18201
18228
|
checkPseudoClasses();
|
|
18229
|
+
};
|
|
18230
|
+
element.addEventListener("navi_pseudo_state_request_check", requestCheck);
|
|
18231
|
+
addTeardown(() => {
|
|
18232
|
+
element.removeEventListener(
|
|
18233
|
+
"navi_pseudo_state_request_check",
|
|
18234
|
+
requestCheck,
|
|
18235
|
+
);
|
|
18202
18236
|
});
|
|
18203
18237
|
|
|
18204
18238
|
for (const pseudoClass of pseudoClasses) {
|
|
@@ -18209,9 +18243,7 @@ const initPseudoStyles = (
|
|
|
18209
18243
|
}
|
|
18210
18244
|
const { setup } = pseudoClassDefinition;
|
|
18211
18245
|
if (setup) {
|
|
18212
|
-
const cleanup = setup(element,
|
|
18213
|
-
checkPseudoClasses();
|
|
18214
|
-
});
|
|
18246
|
+
const cleanup = setup(element, requestCheck);
|
|
18215
18247
|
addTeardown(cleanup);
|
|
18216
18248
|
}
|
|
18217
18249
|
}
|
|
@@ -18231,6 +18263,11 @@ const applyStyle = (
|
|
|
18231
18263
|
return;
|
|
18232
18264
|
}
|
|
18233
18265
|
const styleToApply = getStyleToApply(style, pseudoState, pseudoNamedStyles);
|
|
18266
|
+
// The same object comes back for every state change of a box whose inline
|
|
18267
|
+
// style has no pseudo entry: nothing to write.
|
|
18268
|
+
if (appliedStyleWeakMap.get(element) === styleToApply) {
|
|
18269
|
+
return;
|
|
18270
|
+
}
|
|
18234
18271
|
updateStyle(element, styleToApply, preventInitialTransition);
|
|
18235
18272
|
};
|
|
18236
18273
|
|
|
@@ -18245,52 +18282,74 @@ const getStyleToApply = (styles, pseudoState, pseudoNamedStyles) => {
|
|
|
18245
18282
|
) {
|
|
18246
18283
|
return styles;
|
|
18247
18284
|
}
|
|
18248
|
-
|
|
18249
|
-
const
|
|
18250
|
-
|
|
18251
|
-
|
|
18252
|
-
|
|
18253
|
-
return true;
|
|
18254
|
-
}
|
|
18255
|
-
// Handle pseudo-elements with states like "::-navi-loader:checked:disabled"
|
|
18256
|
-
const pseudoStatesString = pseudoKey.slice(nextColonIndex);
|
|
18257
|
-
return isMatching(pseudoStatesString);
|
|
18285
|
+
let style = styles;
|
|
18286
|
+
for (const pseudoKey of Object.keys(pseudoNamedStyles)) {
|
|
18287
|
+
const requiredStates = getPseudoKeyRequiredStates(pseudoKey);
|
|
18288
|
+
if (!requiredStates.every((state) => pseudoState[state])) {
|
|
18289
|
+
continue;
|
|
18258
18290
|
}
|
|
18259
|
-
|
|
18260
|
-
|
|
18261
|
-
return pseudoState[pseudoKey];
|
|
18291
|
+
if (style === styles) {
|
|
18292
|
+
style = { ...styles };
|
|
18262
18293
|
}
|
|
18263
|
-
//
|
|
18264
|
-
|
|
18265
|
-
|
|
18266
|
-
|
|
18267
|
-
|
|
18268
|
-
|
|
18269
|
-
|
|
18270
|
-
|
|
18271
|
-
|
|
18272
|
-
|
|
18273
|
-
|
|
18274
|
-
|
|
18294
|
+
// Both sides are already normalized for CSS by the box; only the
|
|
18295
|
+
// properties that compose (a press scale on top of a translate) go through
|
|
18296
|
+
// a merge, the rest is a plain override.
|
|
18297
|
+
const styleToAdd = pseudoNamedStyles[pseudoKey];
|
|
18298
|
+
for (const key of Object.keys(styleToAdd)) {
|
|
18299
|
+
const value = styleToAdd[key];
|
|
18300
|
+
if (value === undefined) {
|
|
18301
|
+
continue;
|
|
18302
|
+
}
|
|
18303
|
+
if (key === "transform" || key === "willChange") {
|
|
18304
|
+
style[key] = mergeOneStyle(style[key], value, key, "css");
|
|
18305
|
+
} else {
|
|
18306
|
+
style[key] = value;
|
|
18307
|
+
}
|
|
18275
18308
|
}
|
|
18276
18309
|
}
|
|
18277
|
-
|
|
18278
|
-
|
|
18310
|
+
return style;
|
|
18311
|
+
};
|
|
18312
|
+
|
|
18313
|
+
// The state names a pseudo key asks for, parsed once: the same few keys come
|
|
18314
|
+
// back on every state change of every box that has them. "::x" alone always
|
|
18315
|
+
// matches; "::x:a:b" and ":a:b" ask for ":a" and ":b" — the state keys as
|
|
18316
|
+
// checkPseudoClasses writes them, colon included.
|
|
18317
|
+
const pseudoKeyRequiredStatesMap = new Map();
|
|
18318
|
+
const getPseudoKeyRequiredStates = (pseudoKey) => {
|
|
18319
|
+
const cached = pseudoKeyRequiredStatesMap.get(pseudoKey);
|
|
18320
|
+
if (cached) {
|
|
18321
|
+
return cached;
|
|
18279
18322
|
}
|
|
18280
|
-
let
|
|
18281
|
-
|
|
18282
|
-
|
|
18323
|
+
let requiredStates;
|
|
18324
|
+
if (pseudoKey.startsWith("::")) {
|
|
18325
|
+
const nextColonIndex = pseudoKey.indexOf(":", 2);
|
|
18326
|
+
requiredStates =
|
|
18327
|
+
nextColonIndex === -1
|
|
18328
|
+
? []
|
|
18329
|
+
: getPseudoKeyRequiredStates(pseudoKey.slice(nextColonIndex));
|
|
18330
|
+
} else {
|
|
18331
|
+
const nextColonIndex = pseudoKey.indexOf(":", 1);
|
|
18332
|
+
requiredStates =
|
|
18333
|
+
nextColonIndex === -1
|
|
18334
|
+
? [pseudoKey]
|
|
18335
|
+
: pseudoKey
|
|
18336
|
+
.slice(1)
|
|
18337
|
+
.split(":")
|
|
18338
|
+
.map((state) => `:${state}`);
|
|
18283
18339
|
}
|
|
18284
|
-
|
|
18340
|
+
pseudoKeyRequiredStatesMap.set(pseudoKey, requiredStates);
|
|
18341
|
+
return requiredStates;
|
|
18285
18342
|
};
|
|
18286
18343
|
|
|
18287
|
-
|
|
18344
|
+
// element → the style object last written to it, so the next one is written
|
|
18345
|
+
// as a difference: the values that changed, the keys it no longer has.
|
|
18346
|
+
const appliedStyleWeakMap = new WeakMap();
|
|
18288
18347
|
const elementTransitionWeakMap = new WeakMap();
|
|
18289
18348
|
const elementRenderedWeakSet = new WeakSet();
|
|
18290
|
-
const
|
|
18349
|
+
const NO_STYLE = {};
|
|
18291
18350
|
const updateStyle = (element, style, preventInitialTransition) => {
|
|
18292
|
-
const
|
|
18293
|
-
const
|
|
18351
|
+
const styleToApply = style || NO_STYLE;
|
|
18352
|
+
const styleApplied = appliedStyleWeakMap.get(element) || NO_STYLE;
|
|
18294
18353
|
// TRANSITION ANTI-FLICKER STRATEGY:
|
|
18295
18354
|
// Problem: When setting both transition and styled properties simultaneously
|
|
18296
18355
|
// (e.g., el.style.transition = "border-radius 0.3s ease"; el.style.borderRadius = "20px"),
|
|
@@ -18300,32 +18359,32 @@ const updateStyle = (element, style, preventInitialTransition) => {
|
|
|
18300
18359
|
// transition to "none", then restore the intended transition after the frame completes.
|
|
18301
18360
|
// We handle multiple updateStyle calls in the same frame gracefully - only one
|
|
18302
18361
|
// requestAnimationFrame is scheduled per element, and the final transition value wins.
|
|
18303
|
-
let
|
|
18362
|
+
let skipTransition = false;
|
|
18304
18363
|
if (!elementRenderedWeakSet.has(element)) {
|
|
18305
|
-
const hasTransition =
|
|
18364
|
+
const hasTransition = Object.hasOwn(styleToApply, "transition");
|
|
18306
18365
|
if (hasTransition || preventInitialTransition) {
|
|
18307
|
-
if (elementTransitionWeakMap.has(element)) {
|
|
18308
|
-
elementTransitionWeakMap.set(element, style?.transition);
|
|
18309
|
-
} else {
|
|
18366
|
+
if (!elementTransitionWeakMap.has(element)) {
|
|
18310
18367
|
element.style.transition = "none";
|
|
18311
|
-
elementTransitionWeakMap.set(element, style?.transition);
|
|
18312
18368
|
}
|
|
18313
|
-
|
|
18314
|
-
|
|
18315
|
-
|
|
18369
|
+
elementTransitionWeakMap.set(element, styleToApply.transition);
|
|
18370
|
+
// Stays "none" until the first frame puts the intended value back
|
|
18371
|
+
skipTransition = true;
|
|
18316
18372
|
}
|
|
18317
18373
|
afterFirstFrame(element);
|
|
18318
18374
|
}
|
|
18319
18375
|
|
|
18320
|
-
|
|
18321
|
-
|
|
18322
|
-
for (const key of styleKeySetToApply) {
|
|
18323
|
-
const value = style[key];
|
|
18376
|
+
for (const key of Object.keys(styleToApply)) {
|
|
18377
|
+
const value = styleToApply[key];
|
|
18324
18378
|
if (value === undefined || value === null) {
|
|
18325
|
-
//
|
|
18379
|
+
// a removal: handled below with the keys this style no longer has
|
|
18380
|
+
continue;
|
|
18381
|
+
}
|
|
18382
|
+
if (skipTransition && key === "transition") {
|
|
18383
|
+
continue;
|
|
18384
|
+
}
|
|
18385
|
+
if (styleApplied[key] === value) {
|
|
18326
18386
|
continue;
|
|
18327
18387
|
}
|
|
18328
|
-
keysToDelete.delete(key);
|
|
18329
18388
|
if (key.startsWith("--")) {
|
|
18330
18389
|
element.style.setProperty(key, value);
|
|
18331
18390
|
} else {
|
|
@@ -18333,8 +18392,15 @@ const updateStyle = (element, style, preventInitialTransition) => {
|
|
|
18333
18392
|
}
|
|
18334
18393
|
}
|
|
18335
18394
|
|
|
18336
|
-
|
|
18337
|
-
|
|
18395
|
+
for (const key of Object.keys(styleApplied)) {
|
|
18396
|
+
const previousValue = styleApplied[key];
|
|
18397
|
+
if (previousValue === undefined || previousValue === null) {
|
|
18398
|
+
continue;
|
|
18399
|
+
}
|
|
18400
|
+
const value = styleToApply[key];
|
|
18401
|
+
if (value !== undefined && value !== null) {
|
|
18402
|
+
continue;
|
|
18403
|
+
}
|
|
18338
18404
|
if (key.startsWith("--")) {
|
|
18339
18405
|
element.style.removeProperty(key);
|
|
18340
18406
|
} else {
|
|
@@ -18342,7 +18408,7 @@ const updateStyle = (element, style, preventInitialTransition) => {
|
|
|
18342
18408
|
}
|
|
18343
18409
|
}
|
|
18344
18410
|
|
|
18345
|
-
|
|
18411
|
+
appliedStyleWeakMap.set(element, styleToApply);
|
|
18346
18412
|
};
|
|
18347
18413
|
|
|
18348
18414
|
// One frame for every element waiting for its first one, not one frame each.
|
|
@@ -18394,8 +18460,10 @@ const useComposeElementRef = (syncElement, externalRef) => {
|
|
|
18394
18460
|
const cleanupRef = useRef(null);
|
|
18395
18461
|
const elRef = useRef(null);
|
|
18396
18462
|
const prevSyncElementRef = useRef(undefined);
|
|
18397
|
-
const
|
|
18463
|
+
const stableRef = useRef(null);
|
|
18398
18464
|
const externalRefRef = useRef(externalRef);
|
|
18465
|
+
const syncElementRef = useRef(syncElement);
|
|
18466
|
+
syncElementRef.current = syncElement;
|
|
18399
18467
|
// Detect external ref identity change between renders. The refCallback is
|
|
18400
18468
|
// stable across renders, so when the parent passes a new ref object (or
|
|
18401
18469
|
// switches from null to a ref), Preact does NOT re-fire the callback while
|
|
@@ -18419,24 +18487,24 @@ const useComposeElementRef = (syncElement, externalRef) => {
|
|
|
18419
18487
|
}
|
|
18420
18488
|
externalRefRef.current = externalRef;
|
|
18421
18489
|
|
|
18422
|
-
|
|
18423
|
-
|
|
18424
|
-
|
|
18425
|
-
|
|
18426
|
-
|
|
18427
|
-
|
|
18428
|
-
const
|
|
18429
|
-
|
|
18430
|
-
|
|
18431
|
-
|
|
18432
|
-
|
|
18433
|
-
|
|
18434
|
-
|
|
18435
|
-
|
|
18436
|
-
|
|
18437
|
-
|
|
18438
|
-
|
|
18439
|
-
|
|
18490
|
+
if (!stableRef.current) {
|
|
18491
|
+
// Created once, like the ref callback that calls it, and reading the sync
|
|
18492
|
+
// function through a ref for that reason: the element can be replaced long
|
|
18493
|
+
// after the first render — a tag that changes, a box hidden then shown —
|
|
18494
|
+
// and what the new element gets must be the current render's sync, not
|
|
18495
|
+
// the one the first render closed over.
|
|
18496
|
+
const runSync = (el) => {
|
|
18497
|
+
if (cleanupRef.current) {
|
|
18498
|
+
cleanupRef.current();
|
|
18499
|
+
cleanupRef.current = null;
|
|
18500
|
+
}
|
|
18501
|
+
const syncElementNow = syncElementRef.current;
|
|
18502
|
+
prevSyncElementRef.current = syncElementNow;
|
|
18503
|
+
const cleanup = syncElementNow(el);
|
|
18504
|
+
if (typeof cleanup === "function") {
|
|
18505
|
+
cleanupRef.current = cleanup;
|
|
18506
|
+
}
|
|
18507
|
+
};
|
|
18440
18508
|
const refCallback = (el) => {
|
|
18441
18509
|
elRef.current = el;
|
|
18442
18510
|
// Keep .current in sync immediately so useEffect callbacks that read
|
|
@@ -18460,10 +18528,15 @@ const useComposeElementRef = (syncElement, externalRef) => {
|
|
|
18460
18528
|
prevSyncElementRef.current = undefined;
|
|
18461
18529
|
}
|
|
18462
18530
|
};
|
|
18463
|
-
|
|
18531
|
+
stableRef.current = { refCallback, runSync };
|
|
18532
|
+
}
|
|
18533
|
+
const { refCallback, runSync } = stableRef.current;
|
|
18534
|
+
|
|
18535
|
+
// If element already mounted, re-sync when syncElement reference changed.
|
|
18536
|
+
if (elRef.current && syncElement !== prevSyncElementRef.current) {
|
|
18537
|
+
runSync(elRef.current);
|
|
18464
18538
|
}
|
|
18465
18539
|
|
|
18466
|
-
const refCallback = refCallbackRef.current;
|
|
18467
18540
|
refCallback.current = elRef.current;
|
|
18468
18541
|
return refCallback;
|
|
18469
18542
|
};
|
|
@@ -18657,12 +18730,6 @@ import.meta.css = [/* css */`
|
|
|
18657
18730
|
told it may, and without that the body grows instead of scrolling */
|
|
18658
18731
|
min-height: 0;
|
|
18659
18732
|
flex: 0 1 auto;
|
|
18660
|
-
/* Overflow makes it focusable via tab: apply the outline styles */
|
|
18661
|
-
outline-width: var(--navi-focus-outline-width);
|
|
18662
|
-
/* Outline must appear ON the body, not outside */
|
|
18663
|
-
/* Because for instance when body is within dialog or slide with overflow: hidden it would not be visible */
|
|
18664
|
-
outline-offset: calc(-1 * var(--navi-focus-outline-width));
|
|
18665
|
-
overflow: auto;
|
|
18666
18733
|
|
|
18667
18734
|
/* The same reading as the header's corners above, on all four: a body
|
|
18668
18735
|
follows the corners of the box it is drawn in — which is also what
|
|
@@ -18671,6 +18738,12 @@ import.meta.css = [/* css */`
|
|
|
18671
18738
|
border-top-right-radius: inherit;
|
|
18672
18739
|
border-bottom-right-radius: inherit;
|
|
18673
18740
|
border-bottom-left-radius: inherit;
|
|
18741
|
+
/* Overflow makes it focusable via tab: apply the outline styles */
|
|
18742
|
+
outline-width: var(--navi-focus-outline-width);
|
|
18743
|
+
/* Outline must appear ON the body, not outside */
|
|
18744
|
+
/* Because for instance when body is within dialog or slide with overflow: hidden it would not be visible */
|
|
18745
|
+
outline-offset: calc(-1 * var(--navi-focus-outline-width));
|
|
18746
|
+
overflow: auto;
|
|
18674
18747
|
|
|
18675
18748
|
&:focus-visible {
|
|
18676
18749
|
outline-style: solid;
|
|
@@ -18817,6 +18890,7 @@ const PSEUDO_STATE_CHILD_PROP_SET = new Set(["tabIndex", "tabindex"]);
|
|
|
18817
18890
|
* childPropSet?: Set<string>,
|
|
18818
18891
|
* preventInitialTransition?: boolean,
|
|
18819
18892
|
* separator?: import("ignore:preact").ComponentChildren | ((index: number) => import("ignore:preact").ComponentChildren),
|
|
18893
|
+
* ownTarget?: boolean | "refuse" | "always",
|
|
18820
18894
|
* children?: import("ignore:preact").ComponentChildren,
|
|
18821
18895
|
* [key: string]: any,
|
|
18822
18896
|
* }>}
|
|
@@ -18824,10 +18898,94 @@ const PSEUDO_STATE_CHILD_PROP_SET = new Set(["tabIndex", "tabindex"]);
|
|
|
18824
18898
|
const Box = props => {
|
|
18825
18899
|
const {
|
|
18826
18900
|
ref,
|
|
18901
|
+
children,
|
|
18902
|
+
separator,
|
|
18903
|
+
interactions,
|
|
18904
|
+
...computeProps
|
|
18905
|
+
} = props;
|
|
18906
|
+
const parentBoxFlow = useContext(BoxFlowContext);
|
|
18907
|
+
// Which interactions this box answers, and with what. Read here rather than
|
|
18908
|
+
// on the control, so a swipe or a hold can be declared on anything — a row, a
|
|
18909
|
+
// card, a block of text — and reach the control it belongs to (which is what
|
|
18910
|
+
// carries the action, and what knows it is disabled) by looking for it.
|
|
18911
|
+
// Read through a ref by the effect below: what an interaction DOES is this
|
|
18912
|
+
// render, while WHEN it happens is wired once, at mount (see
|
|
18913
|
+
// useInteractionsEffect).
|
|
18914
|
+
const interactionsRef = useRef(null);
|
|
18915
|
+
interactionsRef.current = resolveInteractions(interactions);
|
|
18916
|
+
|
|
18917
|
+
// What the props say about this box is worked out once per distinct set of
|
|
18918
|
+
// them: a parent re-rendering hands every box below it a new props object,
|
|
18919
|
+
// and most of the time nothing in it has changed. Handlers are the
|
|
18920
|
+
// exception — a closure is new on every render — so they are compared by
|
|
18921
|
+
// name only and put back fresh, see withCurrentHandlers.
|
|
18922
|
+
const renderMemoRef = useRef(null);
|
|
18923
|
+
const renderMemo = renderMemoRef.current;
|
|
18924
|
+
let computed;
|
|
18925
|
+
if (renderMemo && renderMemo.parentBoxFlow === parentBoxFlow && arePropsEquivalent(renderMemo.props, computeProps)) {
|
|
18926
|
+
computed = withCurrentHandlers(renderMemo.computed, computeProps);
|
|
18927
|
+
} else {
|
|
18928
|
+
computed = computeBox(computeProps, parentBoxFlow);
|
|
18929
|
+
}
|
|
18930
|
+
renderMemoRef.current = {
|
|
18931
|
+
props: computeProps,
|
|
18932
|
+
parentBoxFlow,
|
|
18933
|
+
computed
|
|
18934
|
+
};
|
|
18935
|
+
const {
|
|
18936
|
+
TagName,
|
|
18937
|
+
boxFlow,
|
|
18938
|
+
boxFlowIsDefault,
|
|
18939
|
+
row,
|
|
18940
|
+
column,
|
|
18941
|
+
aspectRatio,
|
|
18942
|
+
visualSelector,
|
|
18943
|
+
innerClassName,
|
|
18944
|
+
selfForwardedProps,
|
|
18945
|
+
childForwardedProps,
|
|
18946
|
+
styleDeps
|
|
18947
|
+
} = computed;
|
|
18948
|
+
const syncBox = useCallback(computed.syncBox, styleDeps);
|
|
18949
|
+
const finalRef = useComposeElementRef(syncBox, ref);
|
|
18950
|
+
useInteractionsEffect(finalRef, interactionsRef);
|
|
18951
|
+
let innerChildren = children;
|
|
18952
|
+
if (separator) {
|
|
18953
|
+
// Flatten nested arrays (e.g., from .map()) to treat each element as individual child
|
|
18954
|
+
innerChildren = applySeparatorOnChildren(innerChildren, separator);
|
|
18955
|
+
}
|
|
18956
|
+
|
|
18957
|
+
// When hasChildUsingForwardedProps is used it means
|
|
18958
|
+
// Some/all the children needs to access remainingProps
|
|
18959
|
+
// to render and will provide a function to do so.
|
|
18960
|
+
if (props.hasChildUsingForwardedProps) {
|
|
18961
|
+
innerChildren = jsx(BoxForwardedPropsContext.Provider, {
|
|
18962
|
+
value: childForwardedProps,
|
|
18963
|
+
children: innerChildren
|
|
18964
|
+
});
|
|
18965
|
+
}
|
|
18966
|
+
return jsx(TagName, {
|
|
18967
|
+
ref: finalRef,
|
|
18968
|
+
className: innerClassName,
|
|
18969
|
+
"navi-box-flow": boxFlowIsDefault ? undefined : boxFlow,
|
|
18970
|
+
"navi-box-flow-row": row ? "" : undefined,
|
|
18971
|
+
"navi-box-flow-column": column ? "" : undefined,
|
|
18972
|
+
"navi-aspect-ratio": aspectRatio ? aspectRatio : undefined,
|
|
18973
|
+
"data-visual-selector": visualSelector,
|
|
18974
|
+
...selfForwardedProps,
|
|
18975
|
+
children: jsx(BoxFlowContext.Provider, {
|
|
18976
|
+
value: boxFlow,
|
|
18977
|
+
children: innerChildren
|
|
18978
|
+
})
|
|
18979
|
+
});
|
|
18980
|
+
};
|
|
18981
|
+
|
|
18982
|
+
// Everything the props decide, for the JSX and for the DOM sync. Pure, which
|
|
18983
|
+
// is what lets Box keep the previous result when the props are equivalent.
|
|
18984
|
+
const computeBox = (props, parentBoxFlow) => {
|
|
18985
|
+
const {
|
|
18827
18986
|
as: asProp = "div",
|
|
18828
18987
|
baseClassName,
|
|
18829
18988
|
className,
|
|
18830
|
-
baseStyle,
|
|
18831
18989
|
// style management
|
|
18832
18990
|
style,
|
|
18833
18991
|
styleCSSVars = STYLE_CSS_VARS_DEFAULT,
|
|
@@ -18853,8 +19011,6 @@ const Box = props => {
|
|
|
18853
19011
|
// (when transition is set via props, this is done automatically)
|
|
18854
19012
|
// so this prop is useful only when transition is enabled from "outside" (via CSS)
|
|
18855
19013
|
preventInitialTransition,
|
|
18856
|
-
children,
|
|
18857
|
-
separator,
|
|
18858
19014
|
// Layout roles inside a scrolling container (a Dialog, a Popover): the
|
|
18859
19015
|
// header stays at the top and the footer at the bottom while the rest
|
|
18860
19016
|
// scrolls, or — when a body is present — the body is what scrolls and the
|
|
@@ -18864,22 +19020,24 @@ const Box = props => {
|
|
|
18864
19020
|
header,
|
|
18865
19021
|
footer,
|
|
18866
19022
|
body,
|
|
18867
|
-
//
|
|
18868
|
-
//
|
|
18869
|
-
//
|
|
18870
|
-
//
|
|
18871
|
-
|
|
19023
|
+
// A press landing here is aimed AT this box, not at whatever it sits in — a
|
|
19024
|
+
// cross an application draws in a card's corner, a badge on a row that
|
|
19025
|
+
// travels. Writing the attribute is the whole of it here: it is read off
|
|
19026
|
+
// the DOM by the controls above and by the gesture readers, and what an
|
|
19027
|
+
// affordance makes of the read-only around it is a question only a control
|
|
19028
|
+
// can answer (see own_target.js).
|
|
19029
|
+
ownTarget,
|
|
18872
19030
|
...rest
|
|
18873
19031
|
} = props;
|
|
19032
|
+
if (ownTarget) {
|
|
19033
|
+
rest[OWN_TARGET_ATTRIBUTE] = typeof ownTarget === "string" ? ownTarget : "";
|
|
19034
|
+
}
|
|
18874
19035
|
let as = asProp;
|
|
18875
19036
|
|
|
18876
19037
|
// A box that scrolls is what gives header/footer/body their meaning, and
|
|
18877
19038
|
// saying overflow="auto" is already saying it — no second prop for the same
|
|
18878
19039
|
// fact. Dialog and Popover get it the same way, by asking for that overflow.
|
|
18879
|
-
const scrolls =
|
|
18880
|
-
const value = rest[name];
|
|
18881
|
-
return value === "auto" || value === "scroll";
|
|
18882
|
-
});
|
|
19040
|
+
const scrolls = isScrollingOverflow(rest.overflow) || isScrollingOverflow(rest.overflowX) || isScrollingOverflow(rest.overflowY);
|
|
18883
19041
|
// <header>/<footer> rather than a div: the role is exactly what those tags
|
|
18884
19042
|
// mean, and a screen reader gets it for free. The body stays a div — <main>
|
|
18885
19043
|
// means "the main content of the document", which a popup's body is not.
|
|
@@ -18915,8 +19073,6 @@ const Box = props => {
|
|
|
18915
19073
|
}
|
|
18916
19074
|
}
|
|
18917
19075
|
const defaultDisplay = getDefaultDisplay(TagName);
|
|
18918
|
-
// Read the parent flow early so we can use it when display="inherit" is requested.
|
|
18919
|
-
const parentBoxFlow = useContext(BoxFlowContext);
|
|
18920
19076
|
let {
|
|
18921
19077
|
inline,
|
|
18922
19078
|
block,
|
|
@@ -18992,12 +19148,6 @@ const Box = props => {
|
|
|
18992
19148
|
}
|
|
18993
19149
|
const boxFlowIsDefault = boxFlow === defaultDisplay;
|
|
18994
19150
|
|
|
18995
|
-
// Read through a ref by the effect below: what an interaction DOES is this
|
|
18996
|
-
// render, while WHEN it happens is wired once, at mount (see
|
|
18997
|
-
// useInteractionsEffect).
|
|
18998
|
-
const interactionsRef = useRef(null);
|
|
18999
|
-
interactionsRef.current = resolveInteractions(interactions);
|
|
19000
|
-
const remainingPropKeySet = new Set(Object.keys(rest));
|
|
19001
19151
|
// The box is only a frame and one of its descendants IS the component (a Button
|
|
19002
19152
|
// and its content): everything, event handlers included, belongs to that
|
|
19003
19153
|
// descendant.
|
|
@@ -19005,15 +19155,20 @@ const Box = props => {
|
|
|
19005
19155
|
const innerClassName = withPropsClassName(baseClassName, className);
|
|
19006
19156
|
const selfForwardedProps = {};
|
|
19007
19157
|
const childForwardedProps = {};
|
|
19008
|
-
let
|
|
19158
|
+
let styleDeps;
|
|
19159
|
+
let syncBox;
|
|
19009
19160
|
{
|
|
19010
|
-
|
|
19161
|
+
styleDeps = [
|
|
19011
19162
|
// Layout and alignment props
|
|
19012
19163
|
parentBoxFlow, boxFlow,
|
|
19013
19164
|
// Style context dependencies
|
|
19014
19165
|
styleCSSVars, pseudoClasses, pseudoElements,
|
|
19015
19166
|
// Selectors
|
|
19016
19167
|
visualSelector, pseudoStateSelector, preventInitialTransition];
|
|
19168
|
+
// The pseudo state goes into the deps as key/value entries and never as the
|
|
19169
|
+
// object itself: a control builds that object on every render, and its
|
|
19170
|
+
// identity in the deps would re-run the sync — listeners, observers, style
|
|
19171
|
+
// writes — on each of them, for a state that has not changed.
|
|
19017
19172
|
let innerPseudoState;
|
|
19018
19173
|
if (basePseudoState && pseudoState) {
|
|
19019
19174
|
innerPseudoState = {};
|
|
@@ -19023,30 +19178,28 @@ const Box = props => {
|
|
|
19023
19178
|
if (pseudoStateKeySet.has(key)) {
|
|
19024
19179
|
pseudoStateKeySet.delete(key);
|
|
19025
19180
|
const value = pseudoState[key];
|
|
19026
|
-
styleDeps.push(value);
|
|
19181
|
+
styleDeps.push(key, value);
|
|
19027
19182
|
innerPseudoState[key] = value;
|
|
19028
19183
|
} else {
|
|
19029
19184
|
const value = basePseudoState[key];
|
|
19030
|
-
styleDeps.push(value);
|
|
19185
|
+
styleDeps.push(key, value);
|
|
19031
19186
|
innerPseudoState[key] = value;
|
|
19032
19187
|
}
|
|
19033
19188
|
}
|
|
19034
19189
|
for (const key of pseudoStateKeySet) {
|
|
19035
19190
|
const value = pseudoState[key];
|
|
19036
|
-
styleDeps.push(value);
|
|
19191
|
+
styleDeps.push(key, value);
|
|
19037
19192
|
innerPseudoState[key] = value;
|
|
19038
19193
|
}
|
|
19039
19194
|
} else if (basePseudoState) {
|
|
19040
19195
|
innerPseudoState = basePseudoState;
|
|
19041
19196
|
for (const key of Object.keys(basePseudoState)) {
|
|
19042
|
-
|
|
19043
|
-
styleDeps.push(value);
|
|
19197
|
+
styleDeps.push(key, basePseudoState[key]);
|
|
19044
19198
|
}
|
|
19045
19199
|
} else if (pseudoState) {
|
|
19046
19200
|
innerPseudoState = pseudoState;
|
|
19047
19201
|
for (const key of Object.keys(pseudoState)) {
|
|
19048
|
-
|
|
19049
|
-
styleDeps.push(value);
|
|
19202
|
+
styleDeps.push(key, pseudoState[key]);
|
|
19050
19203
|
}
|
|
19051
19204
|
} else {
|
|
19052
19205
|
innerPseudoState = PSEUDO_STATE_DEFAULT;
|
|
@@ -19064,8 +19217,8 @@ const Box = props => {
|
|
|
19064
19217
|
};
|
|
19065
19218
|
let boxPseudoNamedStyles = PSEUDO_NAMED_STYLES_DEFAULT;
|
|
19066
19219
|
const canForwardToChild = hasChildUsingForwardedProps;
|
|
19067
|
-
const addStyle = (value, name, styleContext, stylesTarget
|
|
19068
|
-
const mergedValue = prepareStyleValue(stylesTarget[name], value, name, styleContext
|
|
19220
|
+
const addStyle = (value, name, styleContext, stylesTarget) => {
|
|
19221
|
+
const mergedValue = prepareStyleValue(stylesTarget[name], value, name, styleContext);
|
|
19069
19222
|
const cssVar = styleContext.styleCSSVars[name];
|
|
19070
19223
|
if (cssVar) {
|
|
19071
19224
|
addCSSVar(mergedValue, cssVar, stylesTarget);
|
|
@@ -19087,20 +19240,20 @@ const Box = props => {
|
|
|
19087
19240
|
styleDeps.push(name, value); // impact box style -> add to deps
|
|
19088
19241
|
stylesTarget[name] = value;
|
|
19089
19242
|
};
|
|
19090
|
-
const addStyleMaybeForwarding = (value, name, styleContext, stylesTarget,
|
|
19243
|
+
const addStyleMaybeForwarding = (value, name, styleContext, stylesTarget, visualChildPropStrategy) => {
|
|
19091
19244
|
if (!visualChildPropStrategy) {
|
|
19092
|
-
addStyle(value, name, styleContext, stylesTarget
|
|
19245
|
+
addStyle(value, name, styleContext, stylesTarget);
|
|
19093
19246
|
return false;
|
|
19094
19247
|
}
|
|
19095
19248
|
const cssVar = styleCSSVars[name];
|
|
19096
19249
|
if (cssVar) {
|
|
19097
19250
|
// css var wins over visual child handling
|
|
19098
|
-
addStyle(value, name, styleContext, stylesTarget
|
|
19251
|
+
addStyle(value, name, styleContext, stylesTarget);
|
|
19099
19252
|
return false;
|
|
19100
19253
|
}
|
|
19101
19254
|
if (visualChildPropStrategy === "copy") {
|
|
19102
19255
|
// we stylyze ourself + forward prop to the child
|
|
19103
|
-
addStyle(value, name, styleContext, stylesTarget
|
|
19256
|
+
addStyle(value, name, styleContext, stylesTarget);
|
|
19104
19257
|
}
|
|
19105
19258
|
if (!canForwardToChild) {
|
|
19106
19259
|
return false;
|
|
@@ -19113,13 +19266,15 @@ const Box = props => {
|
|
|
19113
19266
|
// style={{ ":hover": { backgroundColor: "red" } }}
|
|
19114
19267
|
// then we'll track ":hover" state changes even for basic elements like <div>
|
|
19115
19268
|
const pseudoClassesFromStyleSet = new Set();
|
|
19116
|
-
boxPseudoNamedStyles = {};
|
|
19117
19269
|
const visitProp = (value, name, styleContext, boxStylesTarget, styleOrigin) => {
|
|
19118
19270
|
const isPseudoElement = name.startsWith("::");
|
|
19119
19271
|
const isPseudoClass = name.startsWith(":");
|
|
19120
19272
|
if (isPseudoElement || isPseudoClass) {
|
|
19121
19273
|
styleDeps.push(name);
|
|
19122
19274
|
pseudoClassesFromStyleSet.add(name);
|
|
19275
|
+
if (boxPseudoNamedStyles === PSEUDO_NAMED_STYLES_DEFAULT) {
|
|
19276
|
+
boxPseudoNamedStyles = {};
|
|
19277
|
+
}
|
|
19123
19278
|
const pseudoStyleContext = {
|
|
19124
19279
|
...styleContext,
|
|
19125
19280
|
styleCSSVars: {
|
|
@@ -19140,18 +19295,16 @@ const Box = props => {
|
|
|
19140
19295
|
const pseudoClassStyles = {};
|
|
19141
19296
|
for (const key of pseudoStyleKeys) {
|
|
19142
19297
|
visitProp(value[key], key, pseudoStyleContext, pseudoClassStyles, "pseudo_style");
|
|
19143
|
-
boxPseudoNamedStyles[name] = pseudoClassStyles;
|
|
19144
19298
|
}
|
|
19299
|
+
boxPseudoNamedStyles[name] = pseudoClassStyles;
|
|
19145
19300
|
return;
|
|
19146
19301
|
}
|
|
19147
|
-
|
|
19148
|
-
|
|
19149
|
-
if (isCss) {
|
|
19150
|
-
addStyle(value, name, styleContext, boxStylesTarget, context);
|
|
19302
|
+
if (styleOrigin === "style") {
|
|
19303
|
+
addStyle(value, name, styleContext, boxStylesTarget);
|
|
19151
19304
|
return;
|
|
19152
19305
|
}
|
|
19153
19306
|
if (name.startsWith("--")) {
|
|
19154
|
-
addStyle(value, name, styleContext, boxStylesTarget
|
|
19307
|
+
addStyle(value, name, styleContext, boxStylesTarget);
|
|
19155
19308
|
return;
|
|
19156
19309
|
}
|
|
19157
19310
|
const isPseudoStyle = styleOrigin === "pseudo_style";
|
|
@@ -19163,7 +19316,7 @@ const Box = props => {
|
|
|
19163
19316
|
if (
|
|
19164
19317
|
// prop name === css style name
|
|
19165
19318
|
!getStyle) {
|
|
19166
|
-
const needForwarding = addStyleMaybeForwarding(value, name, styleContext, boxStylesTarget,
|
|
19319
|
+
const needForwarding = addStyleMaybeForwarding(value, name, styleContext, boxStylesTarget, visualChildPropStrategy);
|
|
19167
19320
|
if (needForwarding) {
|
|
19168
19321
|
if (isPseudoStyle) ; else {
|
|
19169
19322
|
childForwardedProps[name] = value;
|
|
@@ -19178,7 +19331,7 @@ const Box = props => {
|
|
|
19178
19331
|
let needForwarding = false;
|
|
19179
19332
|
for (const styleName of Object.keys(cssValues)) {
|
|
19180
19333
|
const cssValue = cssValues[styleName];
|
|
19181
|
-
needForwarding = addStyleMaybeForwarding(cssValue, styleName, styleContext, boxStylesTarget,
|
|
19334
|
+
needForwarding = addStyleMaybeForwarding(cssValue, styleName, styleContext, boxStylesTarget, visualChildPropStrategy);
|
|
19182
19335
|
}
|
|
19183
19336
|
if (needForwarding) {
|
|
19184
19337
|
if (isPseudoStyle) ; else {
|
|
@@ -19214,13 +19367,7 @@ const Box = props => {
|
|
|
19214
19367
|
}
|
|
19215
19368
|
return;
|
|
19216
19369
|
};
|
|
19217
|
-
|
|
19218
|
-
for (const key of baseStyle) {
|
|
19219
|
-
const value = baseStyle[key];
|
|
19220
|
-
visitProp(value, key, styleContext, boxStyles, "baseStyle");
|
|
19221
|
-
}
|
|
19222
|
-
}
|
|
19223
|
-
for (const propName of remainingPropKeySet) {
|
|
19370
|
+
for (const propName of Object.keys(rest)) {
|
|
19224
19371
|
const propValue = rest[propName];
|
|
19225
19372
|
if (baseChildPropSet?.has(propName) || childPropSet?.has(propName)) {
|
|
19226
19373
|
if (canForwardToChild) {
|
|
@@ -19230,9 +19377,6 @@ const Box = props => {
|
|
|
19230
19377
|
}
|
|
19231
19378
|
continue;
|
|
19232
19379
|
}
|
|
19233
|
-
if (canForwardToChild && toCopySet.has(propName)) {
|
|
19234
|
-
childForwardedProps[propName] = propValue;
|
|
19235
|
-
}
|
|
19236
19380
|
const isDataAttribute = propName.startsWith("data-");
|
|
19237
19381
|
if (isDataAttribute) {
|
|
19238
19382
|
selfForwardedProps[propName] = propValue;
|
|
@@ -19274,7 +19418,6 @@ const Box = props => {
|
|
|
19274
19418
|
visitProp(styleValue, styleName, styleContext, boxStyles, "style");
|
|
19275
19419
|
}
|
|
19276
19420
|
}
|
|
19277
|
-
styleDeps.push(pseudoStateSelector, innerPseudoState);
|
|
19278
19421
|
let innerPseudoClasses;
|
|
19279
19422
|
if (pseudoClassesFromStyleSet.size) {
|
|
19280
19423
|
innerPseudoClasses = [...pseudoClasses];
|
|
@@ -19291,7 +19434,7 @@ const Box = props => {
|
|
|
19291
19434
|
styleDeps.push(...pseudoClasses);
|
|
19292
19435
|
}
|
|
19293
19436
|
}
|
|
19294
|
-
|
|
19437
|
+
syncBox = boxEl => {
|
|
19295
19438
|
const pseudoStateEl = pseudoStateSelector ? boxEl.querySelector(pseudoStateSelector) : boxEl;
|
|
19296
19439
|
if (!pseudoStateEl) {
|
|
19297
19440
|
console.error(`pseudoStateSelector "${pseudoStateSelector}" did not match any element inside the box`, boxEl);
|
|
@@ -19306,42 +19449,24 @@ const Box = props => {
|
|
|
19306
19449
|
elementToImpact: boxEl,
|
|
19307
19450
|
elementListeningPseudoState: visualEl === pseudoStateEl ? null : visualEl
|
|
19308
19451
|
});
|
|
19309
|
-
}
|
|
19310
|
-
finalRef = useComposeElementRef(syncBox, ref);
|
|
19311
|
-
}
|
|
19312
|
-
useInteractionsEffect(finalRef, interactionsRef);
|
|
19313
|
-
let innerChildren = children;
|
|
19314
|
-
if (separator) {
|
|
19315
|
-
// Flatten nested arrays (e.g., from .map()) to treat each element as individual child
|
|
19316
|
-
innerChildren = applySeparatorOnChildren(innerChildren, separator);
|
|
19317
|
-
}
|
|
19318
|
-
|
|
19319
|
-
// When hasChildUsingForwardedProps is used it means
|
|
19320
|
-
// Some/all the children needs to access remainingProps
|
|
19321
|
-
// to render and will provide a function to do so.
|
|
19322
|
-
if (hasChildUsingForwardedProps) {
|
|
19323
|
-
innerChildren = jsx(BoxForwardedPropsContext.Provider, {
|
|
19324
|
-
value: childForwardedProps,
|
|
19325
|
-
children: innerChildren
|
|
19326
|
-
});
|
|
19452
|
+
};
|
|
19327
19453
|
}
|
|
19328
19454
|
const aspectRatio = rest.square || rest.circle ? "1/1" : rest.aspectRatio;
|
|
19329
|
-
return
|
|
19330
|
-
|
|
19331
|
-
|
|
19332
|
-
|
|
19333
|
-
|
|
19334
|
-
|
|
19335
|
-
|
|
19336
|
-
|
|
19337
|
-
|
|
19338
|
-
|
|
19339
|
-
|
|
19340
|
-
|
|
19341
|
-
|
|
19342
|
-
}
|
|
19455
|
+
return {
|
|
19456
|
+
TagName,
|
|
19457
|
+
boxFlow,
|
|
19458
|
+
boxFlowIsDefault,
|
|
19459
|
+
row,
|
|
19460
|
+
column,
|
|
19461
|
+
aspectRatio,
|
|
19462
|
+
visualSelector,
|
|
19463
|
+
innerClassName,
|
|
19464
|
+
selfForwardedProps,
|
|
19465
|
+
childForwardedProps,
|
|
19466
|
+
styleDeps,
|
|
19467
|
+
syncBox
|
|
19468
|
+
};
|
|
19343
19469
|
};
|
|
19344
|
-
const toCopySet = new Set([]);
|
|
19345
19470
|
const applySeparatorOnChildren = (children, separator) => {
|
|
19346
19471
|
const flattenedChildren = toChildArray(children);
|
|
19347
19472
|
if (flattenedChildren.length <= 1) {
|
|
@@ -19387,6 +19512,62 @@ const isNonZeroSpacing = value => {
|
|
|
19387
19512
|
}
|
|
19388
19513
|
return true;
|
|
19389
19514
|
};
|
|
19515
|
+
const isScrollingOverflow = value => value === "auto" || value === "scroll";
|
|
19516
|
+
|
|
19517
|
+
// Same props as far as computeBox is concerned. Handlers count by name only,
|
|
19518
|
+
// see withCurrentHandlers; no style or state key starts with "on".
|
|
19519
|
+
const arePropsEquivalent = (previousProps, props) => compareTwoJsValues(previousProps, props, {
|
|
19520
|
+
keyComparator: comparePropAt
|
|
19521
|
+
});
|
|
19522
|
+
const comparePropAt = (a, b, key, recurse) => {
|
|
19523
|
+
if (typeof key === "string" && key.startsWith("on")) {
|
|
19524
|
+
return true;
|
|
19525
|
+
}
|
|
19526
|
+
return recurse(a, b);
|
|
19527
|
+
};
|
|
19528
|
+
// The previous computation with this render's handlers: a handler goes where
|
|
19529
|
+
// its name went the previous time, self or child, the split being decided by
|
|
19530
|
+
// props that are the same. The forwarded objects keep their identity when no
|
|
19531
|
+
// handler changed, so what reads them through context sees nothing new.
|
|
19532
|
+
const withCurrentHandlers = (computed, props) => {
|
|
19533
|
+
let {
|
|
19534
|
+
selfForwardedProps,
|
|
19535
|
+
childForwardedProps
|
|
19536
|
+
} = computed;
|
|
19537
|
+
for (const key of Object.keys(props)) {
|
|
19538
|
+
if (!key.startsWith("on")) {
|
|
19539
|
+
continue;
|
|
19540
|
+
}
|
|
19541
|
+
const value = props[key];
|
|
19542
|
+
if (Object.hasOwn(childForwardedProps, key)) {
|
|
19543
|
+
if (childForwardedProps[key] !== value) {
|
|
19544
|
+
if (childForwardedProps === computed.childForwardedProps) {
|
|
19545
|
+
childForwardedProps = {
|
|
19546
|
+
...childForwardedProps
|
|
19547
|
+
};
|
|
19548
|
+
}
|
|
19549
|
+
childForwardedProps[key] = value;
|
|
19550
|
+
}
|
|
19551
|
+
} else if (Object.hasOwn(selfForwardedProps, key)) {
|
|
19552
|
+
if (selfForwardedProps[key] !== value) {
|
|
19553
|
+
if (selfForwardedProps === computed.selfForwardedProps) {
|
|
19554
|
+
selfForwardedProps = {
|
|
19555
|
+
...selfForwardedProps
|
|
19556
|
+
};
|
|
19557
|
+
}
|
|
19558
|
+
selfForwardedProps[key] = value;
|
|
19559
|
+
}
|
|
19560
|
+
}
|
|
19561
|
+
}
|
|
19562
|
+
if (selfForwardedProps === computed.selfForwardedProps && childForwardedProps === computed.childForwardedProps) {
|
|
19563
|
+
return computed;
|
|
19564
|
+
}
|
|
19565
|
+
return {
|
|
19566
|
+
...computed,
|
|
19567
|
+
selfForwardedProps,
|
|
19568
|
+
childForwardedProps
|
|
19569
|
+
};
|
|
19570
|
+
};
|
|
19390
19571
|
|
|
19391
19572
|
const useDebounceTrue = (value, delay = 300) => {
|
|
19392
19573
|
const [debouncedTrue, setDebouncedTrue] = useState(false);
|
|
@@ -20844,14 +21025,6 @@ const shouldInjectSpacingBetween = (left, right) => {
|
|
|
20844
21025
|
* internally for overlays such as the skeleton container.
|
|
20845
21026
|
*/
|
|
20846
21027
|
const Text = props => {
|
|
20847
|
-
const defaultRef = useRef();
|
|
20848
|
-
const ref = props.ref || defaultRef;
|
|
20849
|
-
return jsx(TextDispatcher, {
|
|
20850
|
-
...props,
|
|
20851
|
-
ref: ref
|
|
20852
|
-
});
|
|
20853
|
-
};
|
|
20854
|
-
const TextDispatcher = props => {
|
|
20855
21028
|
if (props.loading || props.skeleton) {
|
|
20856
21029
|
return jsx(TextSkeleton, {
|
|
20857
21030
|
...props
|
|
@@ -20877,9 +21050,8 @@ const TextDispatcher = props => {
|
|
|
20877
21050
|
});
|
|
20878
21051
|
};
|
|
20879
21052
|
const TextShrinkWrap = props => {
|
|
20880
|
-
const
|
|
20881
|
-
|
|
20882
|
-
} = props;
|
|
21053
|
+
const defaultRef = useRef();
|
|
21054
|
+
const ref = props.ref || defaultRef;
|
|
20883
21055
|
const applyWidth = () => {
|
|
20884
21056
|
const text = ref.current;
|
|
20885
21057
|
// Reset any previously forced width so we measure the natural size
|
|
@@ -20920,8 +21092,9 @@ const TextShrinkWrap = props => {
|
|
|
20920
21092
|
window.removeEventListener("resize", applyWidth);
|
|
20921
21093
|
};
|
|
20922
21094
|
}, []);
|
|
20923
|
-
return jsx(
|
|
21095
|
+
return jsx(Text, {
|
|
20924
21096
|
...props,
|
|
21097
|
+
ref: ref,
|
|
20925
21098
|
"data-shrinkwrap": "",
|
|
20926
21099
|
shrinkWrap: undefined
|
|
20927
21100
|
});
|
|
@@ -21037,7 +21210,7 @@ const TextSkeleton = ({
|
|
|
21037
21210
|
"aria-hidden": "true",
|
|
21038
21211
|
children: "W"
|
|
21039
21212
|
});
|
|
21040
|
-
return jsx(
|
|
21213
|
+
return jsx(Text, {
|
|
21041
21214
|
"data-skeleton": "",
|
|
21042
21215
|
"data-loading": loading ? "" : undefined,
|
|
21043
21216
|
...props,
|
|
@@ -21053,7 +21226,7 @@ const TextOverflow = ({
|
|
|
21053
21226
|
children,
|
|
21054
21227
|
...rest
|
|
21055
21228
|
}) => {
|
|
21056
|
-
return jsx(
|
|
21229
|
+
return jsx(Text, {
|
|
21057
21230
|
block: true,
|
|
21058
21231
|
as: "div",
|
|
21059
21232
|
pre: noWrap === undefined ? true : undefined
|
|
@@ -21075,10 +21248,12 @@ const TextWithSelectRange = ({
|
|
|
21075
21248
|
selectRange,
|
|
21076
21249
|
...props
|
|
21077
21250
|
}) => {
|
|
21078
|
-
|
|
21079
|
-
|
|
21251
|
+
const defaultRef = useRef();
|
|
21252
|
+
const innerRef = ref || defaultRef;
|
|
21253
|
+
useInitialTextSelection(innerRef, selectRange);
|
|
21254
|
+
return jsx(Text, {
|
|
21080
21255
|
...props,
|
|
21081
|
-
ref:
|
|
21256
|
+
ref: innerRef,
|
|
21082
21257
|
selectRange: undefined
|
|
21083
21258
|
});
|
|
21084
21259
|
};
|
|
@@ -63256,7 +63431,8 @@ const useBadgeRegistry = (children, enabled) => {
|
|
|
63256
63431
|
* not the same in each. Nothing is set up for a case that cannot happen: a
|
|
63257
63432
|
* plain list is one element holding its children as-is — no registry, no
|
|
63258
63433
|
* effect —, a capped one collects its badges but measures nothing, and only
|
|
63259
|
-
* shrinkWrap
|
|
63434
|
+
* shrinkWrap on its own builds the measurement ghost: under maxLines the list
|
|
63435
|
+
* is measured in place, once the rows are known.
|
|
63260
63436
|
*
|
|
63261
63437
|
* @param {import("ignore:preact").ComponentChildren} [fallback]
|
|
63262
63438
|
* Rendered in place of the badges when there is none. Without it an empty
|
|
@@ -63271,8 +63447,9 @@ const useBadgeRegistry = (children, enabled) => {
|
|
|
63271
63447
|
* Narrows the list down to its widest row so the last row isn't ragged.
|
|
63272
63448
|
* Defaults to true inside a <Picker> — the trigger draws a border around the
|
|
63273
63449
|
* list, so the ragged edge shows — and false elsewhere, where the work would
|
|
63274
|
-
* often go unseen: opt in where an edge is visible.
|
|
63275
|
-
*
|
|
63450
|
+
* often go unseen: opt in where an edge is visible. Composes with maxLines:
|
|
63451
|
+
* the rows are read at the full width first, and the list is narrowed once
|
|
63452
|
+
* the surplus is gone.
|
|
63276
63453
|
* @param {number} [max]
|
|
63277
63454
|
* Caps how many badges are rendered; the surplus becomes a "+N" badge, which
|
|
63278
63455
|
* takes one of the max slots.
|
|
@@ -63296,11 +63473,10 @@ const BadgeList = props => {
|
|
|
63296
63473
|
shrinkWrap = maxLinesFromAbove !== undefined
|
|
63297
63474
|
} = props;
|
|
63298
63475
|
if (maxLinesResolved !== undefined) {
|
|
63299
|
-
// shrinkWrap is dropped on purpose: it narrows the list down to its widest
|
|
63300
|
-
// row, which would re-wrap the badges under the cap just measured.
|
|
63301
63476
|
return jsx(BadgeListMaxLines, {
|
|
63302
63477
|
...props,
|
|
63303
|
-
maxLines: maxLinesResolved
|
|
63478
|
+
maxLines: maxLinesResolved,
|
|
63479
|
+
shrinkWrap: shrinkWrap
|
|
63304
63480
|
});
|
|
63305
63481
|
}
|
|
63306
63482
|
if (shrinkWrap) {
|
|
@@ -63441,6 +63617,7 @@ const BadgeListMaxLines = ({
|
|
|
63441
63617
|
children,
|
|
63442
63618
|
max,
|
|
63443
63619
|
maxLines,
|
|
63620
|
+
shrinkWrap,
|
|
63444
63621
|
...boxProps
|
|
63445
63622
|
}) => {
|
|
63446
63623
|
const registry = useBadgeRegistry(children, true);
|
|
@@ -63462,8 +63639,29 @@ const BadgeListMaxLines = ({
|
|
|
63462
63639
|
// out of the cap and nothing has to be watched.
|
|
63463
63640
|
const watchesResize = fit !== null && fit.count > 1;
|
|
63464
63641
|
|
|
63642
|
+
// The list's own width. While the rows are being read the list takes all the
|
|
63643
|
+
// room it is given — a width kept from an earlier shrink wrap would fold the
|
|
63644
|
+
// badges under it. Once the surplus is gone, shrinkWrap narrows the list to
|
|
63645
|
+
// its widest row, measured where the badges stand: nothing is painted before
|
|
63646
|
+
// the effect below has run, so no clone is needed.
|
|
63647
|
+
useLayoutEffect(() => {
|
|
63648
|
+
const visibleEl = visibleRef.current;
|
|
63649
|
+
if (!visibleEl) {
|
|
63650
|
+
return;
|
|
63651
|
+
}
|
|
63652
|
+
visibleEl.style.width = "";
|
|
63653
|
+
if (fit === null || !shrinkWrap) {
|
|
63654
|
+
return;
|
|
63655
|
+
}
|
|
63656
|
+
const widestRowWidth = measureWidestChildRow(visibleEl);
|
|
63657
|
+
if (widestRowWidth !== null) {
|
|
63658
|
+
visibleEl.style.width = `${Math.ceil(widestRowWidth)}px`;
|
|
63659
|
+
}
|
|
63660
|
+
}, [fit, shrinkWrap]);
|
|
63661
|
+
|
|
63465
63662
|
// Runs after every render, which is when the badges have registered and the
|
|
63466
|
-
// DOM holds whatever this render asked for
|
|
63663
|
+
// DOM holds whatever this render asked for, at the width the effect above
|
|
63664
|
+
// gave it.
|
|
63467
63665
|
useLayoutEffect(() => {
|
|
63468
63666
|
const visibleEl = visibleRef.current;
|
|
63469
63667
|
if (!visibleEl) {
|
|
@@ -63498,7 +63696,8 @@ const BadgeListMaxLines = ({
|
|
|
63498
63696
|
// And not every width change either. Nothing guarantees an ancestor whose
|
|
63499
63697
|
// width does not follow its content (a column with align-items: start
|
|
63500
63698
|
// sizes every row to what is inside it), so rendering every badge widens
|
|
63501
|
-
// what is being watched and dropping the surplus
|
|
63699
|
+
// what is being watched and dropping the surplus — then shrink wrapping
|
|
63700
|
+
// what is left — narrows it right back.
|
|
63502
63701
|
// Those two widths are this list talking to itself; measuring again on
|
|
63503
63702
|
// them never ends. Any other width is the room around it changing.
|
|
63504
63703
|
const width = outerParent.getBoundingClientRect().width;
|
|
@@ -64813,7 +65012,7 @@ const PickerButton = props => {
|
|
|
64813
65012
|
});
|
|
64814
65013
|
e.preventDefault();
|
|
64815
65014
|
}
|
|
64816
|
-
}), variant === "
|
|
65015
|
+
}), variant === "headless" || ui === "default" ? null : jsx(Text, {
|
|
64817
65016
|
className: "navi_picker_value",
|
|
64818
65017
|
"navi-placeholder": uiStateHoldsNothing(value) ? "" : undefined,
|
|
64819
65018
|
maxLines: maxLines,
|
|
@@ -64826,11 +65025,20 @@ const PickerButton = props => {
|
|
|
64826
65025
|
},
|
|
64827
65026
|
children: jsx(MaxLinesContext.Provider, {
|
|
64828
65027
|
value: maxLines,
|
|
64829
|
-
children: ui === undefined ?
|
|
65028
|
+
children: ui === undefined ? variant === "icon" ?
|
|
65029
|
+
// An icon picker draws no value, so there is no slot
|
|
65030
|
+
// beside it either — the icon that would have sat in
|
|
65031
|
+
// that slot IS the trigger, and a caller's own `ui`
|
|
65032
|
+
// replaces it like any other.
|
|
65033
|
+
jsx(Icon, {
|
|
65034
|
+
size: rightSlotIconSize,
|
|
65035
|
+
lineOverflow: "allow",
|
|
65036
|
+
children: rightSlotIcon === undefined ? jsx(ChevronDownSvg$1, {}) : rightSlotIcon
|
|
65037
|
+
}) : jsx(PickerDefaultUI, {}) : ui
|
|
64830
65038
|
})
|
|
64831
65039
|
})
|
|
64832
65040
|
})
|
|
64833
|
-
}), variant === "headless" || ui === "default" ? null : jsx("span", {
|
|
65041
|
+
}), variant === "icon" || variant === "headless" || ui === "default" ? null : jsx("span", {
|
|
64834
65042
|
className: "navi_picker_right_slot",
|
|
64835
65043
|
children: jsx(PickerOwnContent, {
|
|
64836
65044
|
children: clearable && interactive && value !== undefined && value !== "" ? jsx(Button, {
|