@jsenv/navi 0.29.395 → 0.29.397

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.
@@ -6227,6 +6227,9 @@ const findControlProxyTarget = (el) => {
6227
6227
  return document.getElementById(proxyFor);
6228
6228
  };
6229
6229
 
6230
+ // Shared: asked on every pseudo state change of every box, and almost always
6231
+ // empty.
6232
+ const NO_PROXIES = Object.freeze([]);
6230
6233
  /**
6231
6234
  * Given a real control element, returns every proxy that visually represents
6232
6235
  * it — a control can have more than one (an "enable"/"disable" button pair for
@@ -6241,11 +6244,11 @@ const findControlProxyTarget = (el) => {
6241
6244
  */
6242
6245
  const findControlProxies = (el) => {
6243
6246
  if (!el.id) {
6244
- return [];
6247
+ return NO_PROXIES;
6245
6248
  }
6246
6249
  const proxyControllerSet = findProxyControllers(el.id);
6247
6250
  if (!proxyControllerSet) {
6248
- return [];
6251
+ return NO_PROXIES;
6249
6252
  }
6250
6253
  const proxyElements = [];
6251
6254
  for (const proxyController of proxyControllerSet) {
@@ -6592,10 +6595,6 @@ const css$13 = /* css */ `
6592
6595
  border: none;
6593
6596
  outline: none; /* programmatic focus may land here briefly before being redirected to close button */
6594
6597
  opacity: 0;
6595
- /* opacity only: the placement lives in the translate property, which
6596
- applyNewPosition (visible_rect.js) owns and animates itself through the
6597
- Web Animations API, same mechanism Popover/Dialog use. */
6598
- transition: opacity 0.2s ease-in-out;
6599
6598
  cursor: initial; /* Do not inherit element cursor, inside the element but should use regular cursor */
6600
6599
  pointer-events: auto; /* Must be interactive to be closabled (overrid list item pointer-events none for instance) */
6601
6600
  overflow: visible;
@@ -6604,6 +6603,15 @@ const css$13 = /* css */ `
6604
6603
  position: absolute;
6605
6604
  }
6606
6605
 
6606
+ /* Armed after the first placement: the first show answers a tap or a
6607
+ click and appears at once, the fade is for the anchor scrolling out of
6608
+ view and back. Opacity only: the placement lives in the translate
6609
+ property, which applyNewPosition (visible_rect.js) owns and animates
6610
+ itself through the Web Animations API, same mechanism Popover/Dialog use. */
6611
+ &[data-placed] {
6612
+ transition: opacity 0.12s ease-out;
6613
+ }
6614
+
6607
6615
  &[data-status="success"] {
6608
6616
  --x-callout-status-color: var(--callout-success-color);
6609
6617
  }
@@ -8031,6 +8039,13 @@ const positionCallout = (
8031
8039
  calloutFrameElement.innerHTML = generateSvgWithoutArrow(width, height);
8032
8040
  calloutElement.style.opacity = 1;
8033
8041
  }
8042
+ if (!calloutElement.hasAttribute("data-placed")) {
8043
+ // Style flush between the first opacity write and arming the
8044
+ // transition, so that first write lands unanimated in the same frame.
8045
+ // eslint-disable-next-line no-unused-expressions
8046
+ getComputedStyle(calloutElement).opacity;
8047
+ calloutElement.setAttribute("data-placed", "");
8048
+ }
8034
8049
  applyNewPosition(calloutElement, position);
8035
8050
  },
8036
8051
  );
@@ -10602,15 +10617,17 @@ const resolveInteractions = (interactions) => {
10602
10617
  }
10603
10618
  }
10604
10619
  const kept = {};
10620
+ let keptSome = false;
10605
10621
  for (const type of Object.keys(resolved)) {
10606
10622
  if (resolved[type]) {
10607
10623
  kept[type] = resolved[type];
10624
+ keptSome = true;
10608
10625
  }
10609
10626
  }
10610
- resolved = kept;
10611
- if (Object.keys(resolved).length === 0) {
10627
+ if (!keptSome) {
10612
10628
  return null;
10613
10629
  }
10630
+ resolved = kept;
10614
10631
  return resolved;
10615
10632
  };
10616
10633
 
@@ -21549,8 +21566,7 @@ const getStyleToApply = (styles, pseudoState, pseudoNamedStyles) => {
21549
21566
  }
21550
21567
  let style = styles;
21551
21568
  for (const pseudoKey of Object.keys(pseudoNamedStyles)) {
21552
- const requiredStates = getPseudoKeyRequiredStates(pseudoKey);
21553
- if (!requiredStates.every((state) => pseudoState[state])) {
21569
+ if (!hasEveryState(pseudoState, getPseudoKeyRequiredStates(pseudoKey))) {
21554
21570
  continue;
21555
21571
  }
21556
21572
  if (style === styles) {
@@ -21605,6 +21621,14 @@ const getPseudoKeyRequiredStates = (pseudoKey) => {
21605
21621
  pseudoKeyRequiredStatesMap.set(pseudoKey, requiredStates);
21606
21622
  return requiredStates;
21607
21623
  };
21624
+ const hasEveryState = (pseudoState, states) => {
21625
+ for (const state of states) {
21626
+ if (!pseudoState[state]) {
21627
+ return false;
21628
+ }
21629
+ }
21630
+ return true;
21631
+ };
21608
21632
 
21609
21633
  // element → the style object last written to it, so the next one is written
21610
21634
  // as a difference: the values that changed, the keys it no longer has.
@@ -21682,7 +21706,7 @@ const updateStyle = (element, style, preventInitialTransition) => {
21682
21706
  // the browser for a frame costs more than that, and a page mounting thousands of
21683
21707
  // boxes asks thousands of times in the same tick. A Set, so an element styled
21684
21708
  // twice before the frame arrives is still one entry.
21685
- const elementSetWaitingFirstFrame = new Set();
21709
+ let elementSetWaitingFirstFrame = new Set();
21686
21710
  let firstFrameScheduled = false;
21687
21711
  const afterFirstFrame = (element) => {
21688
21712
  elementSetWaitingFirstFrame.add(element);
@@ -21692,8 +21716,8 @@ const afterFirstFrame = (element) => {
21692
21716
  firstFrameScheduled = true;
21693
21717
  requestAnimationFrame(() => {
21694
21718
  firstFrameScheduled = false;
21695
- const elements = [...elementSetWaitingFirstFrame];
21696
- elementSetWaitingFirstFrame.clear();
21719
+ const elements = elementSetWaitingFirstFrame;
21720
+ elementSetWaitingFirstFrame = new Set();
21697
21721
  for (const element of elements) {
21698
21722
  if (elementTransitionWeakMap.has(element)) {
21699
21723
  const transitionToRestore = elementTransitionWeakMap.get(element);
@@ -22005,6 +22029,7 @@ const readCSSVarEntry = entry => {
22005
22029
  }
22006
22030
  return [entry, null];
22007
22031
  };
22032
+ const readCSSVarName = entry => Array.isArray(entry) ? entry[0] : entry;
22008
22033
  // When only pseudoStateSelector is set (no visualSelector), the box owns its
22009
22034
  // visual identity. Only event handlers and these explicit props are forwarded
22010
22035
  // to the inner semantic/interactive child element.
@@ -22114,18 +22139,23 @@ const Box = props => {
22114
22139
  // exception — a closure is new on every render — so they are compared by
22115
22140
  // name only and put back fresh, see withCurrentHandlers.
22116
22141
  const renderMemoRef = useRef(null);
22142
+ if (!renderMemoRef.current) {
22143
+ renderMemoRef.current = {
22144
+ props: null,
22145
+ parentBoxFlow: null,
22146
+ computed: null
22147
+ };
22148
+ }
22117
22149
  const renderMemo = renderMemoRef.current;
22118
22150
  let computed;
22119
- if (renderMemo && renderMemo.parentBoxFlow === parentBoxFlow && arePropsEquivalent(renderMemo.props, computeProps)) {
22151
+ if (renderMemo.computed && renderMemo.parentBoxFlow === parentBoxFlow && arePropsEquivalent(renderMemo.props, computeProps)) {
22120
22152
  computed = withCurrentHandlers(renderMemo.computed, computeProps);
22121
22153
  } else {
22122
22154
  computed = computeBox(computeProps, parentBoxFlow);
22123
22155
  }
22124
- renderMemoRef.current = {
22125
- props: computeProps,
22126
- parentBoxFlow,
22127
- computed
22128
- };
22156
+ renderMemo.props = computeProps;
22157
+ renderMemo.parentBoxFlow = parentBoxFlow;
22158
+ renderMemo.computed = computed;
22129
22159
  const {
22130
22160
  TagName,
22131
22161
  boxFlow,
@@ -22157,6 +22187,16 @@ const Box = props => {
22157
22187
  children: innerChildren
22158
22188
  });
22159
22189
  }
22190
+
22191
+ // Only a Box reads the flow, and a box holding nothing but text has no Box
22192
+ // below it: the provider, a component of its own, is left out there. Moving
22193
+ // between the two shapes recreates text nodes, never a component.
22194
+ if (mayHoldComponent(innerChildren)) {
22195
+ innerChildren = jsx(BoxFlowContext.Provider, {
22196
+ value: boxFlow,
22197
+ children: innerChildren
22198
+ });
22199
+ }
22160
22200
  return jsx(TagName, {
22161
22201
  ref: finalRef,
22162
22202
  className: innerClassName,
@@ -22166,10 +22206,7 @@ const Box = props => {
22166
22206
  "navi-aspect-ratio": aspectRatio ? aspectRatio : undefined,
22167
22207
  "data-visual-selector": visualSelector,
22168
22208
  ...selfForwardedProps,
22169
- children: jsx(BoxFlowContext.Provider, {
22170
- value: boxFlow,
22171
- children: innerChildren
22172
- })
22209
+ children: innerChildren
22173
22210
  });
22174
22211
  };
22175
22212
 
@@ -22387,21 +22424,15 @@ const computeBox = (props, parentBoxFlow) => {
22387
22424
  let innerPseudoState;
22388
22425
  if (basePseudoState && pseudoState) {
22389
22426
  innerPseudoState = {};
22390
- const baseStateKeys = Object.keys(basePseudoState);
22391
- const pseudoStateKeySet = new Set(Object.keys(pseudoState));
22392
- for (const key of baseStateKeys) {
22393
- if (pseudoStateKeySet.has(key)) {
22394
- pseudoStateKeySet.delete(key);
22395
- const value = pseudoState[key];
22396
- styleDeps.push(key, value);
22397
- innerPseudoState[key] = value;
22398
- } else {
22399
- const value = basePseudoState[key];
22400
- styleDeps.push(key, value);
22401
- innerPseudoState[key] = value;
22402
- }
22427
+ for (const key of Object.keys(basePseudoState)) {
22428
+ const value = Object.hasOwn(pseudoState, key) ? pseudoState[key] : basePseudoState[key];
22429
+ styleDeps.push(key, value);
22430
+ innerPseudoState[key] = value;
22403
22431
  }
22404
- for (const key of pseudoStateKeySet) {
22432
+ for (const key of Object.keys(pseudoState)) {
22433
+ if (Object.hasOwn(basePseudoState, key)) {
22434
+ continue;
22435
+ }
22405
22436
  const value = pseudoState[key];
22406
22437
  styleDeps.push(key, value);
22407
22438
  innerPseudoState[key] = value;
@@ -22435,7 +22466,7 @@ const computeBox = (props, parentBoxFlow) => {
22435
22466
  const canForwardToChild = hasChildUsingForwardedProps;
22436
22467
  const addStyle = (value, name, styleContext, stylesTarget) => {
22437
22468
  const mergedValue = prepareStyleValue(stylesTarget[name], value, name, styleContext);
22438
- const [cssVar] = readCSSVarEntry(styleContext.styleCSSVars[name]);
22469
+ const cssVar = readCSSVarName(styleContext.styleCSSVars[name]);
22439
22470
  if (cssVar) {
22440
22471
  addCSSVar(mergedValue, cssVar, stylesTarget);
22441
22472
  if (name === "borderRadius" && value === "inherit") {
@@ -22491,12 +22522,13 @@ const computeBox = (props, parentBoxFlow) => {
22491
22522
  if (boxPseudoNamedStyles === PSEUDO_NAMED_STYLES_DEFAULT) {
22492
22523
  boxPseudoNamedStyles = {};
22493
22524
  }
22525
+ const pseudoCSSVars = styleCSSVars[name];
22494
22526
  const pseudoStyleContext = {
22495
22527
  ...styleContext,
22496
- styleCSSVars: {
22528
+ styleCSSVars: pseudoCSSVars ? {
22497
22529
  ...styleCSSVars,
22498
- ...styleCSSVars[name]
22499
- },
22530
+ ...pseudoCSSVars
22531
+ } : styleCSSVars,
22500
22532
  pseudoName: name
22501
22533
  };
22502
22534
  const pseudoStyleKeys = Object.keys(value);
@@ -22743,17 +22775,51 @@ const declaresSomething = value => {
22743
22775
  return true;
22744
22776
  };
22745
22777
  const isScrollingOverflow = value => value === "auto" || value === "scroll";
22778
+ const mayHoldComponent = children => {
22779
+ if (children === null || children === undefined) {
22780
+ return false;
22781
+ }
22782
+ const type = typeof children;
22783
+ if (type === "string" || type === "number" || type === "boolean") {
22784
+ return false;
22785
+ }
22786
+ if (Array.isArray(children)) {
22787
+ for (const child of children) {
22788
+ if (mayHoldComponent(child)) {
22789
+ return true;
22790
+ }
22791
+ }
22792
+ return false;
22793
+ }
22794
+ return true;
22795
+ };
22746
22796
 
22747
22797
  // Same props as far as computeBox is concerned. Handlers count by name only,
22748
- // see withCurrentHandlers; no style or state key starts with "on".
22749
- const arePropsEquivalent = (previousProps, props) => compareTwoJsValues(previousProps, props, {
22750
- keyComparator: comparePropAt
22751
- });
22752
- const comparePropAt = (a, b, key, recurse) => {
22753
- if (typeof key === "string" && key.startsWith("on")) {
22754
- return true;
22798
+ // see withCurrentHandlers. Identity first: most values are the very ones of
22799
+ // the previous render, only what a caller rebuilds inline (a style, a pseudo
22800
+ // state) needs the deep walk.
22801
+ const arePropsEquivalent = (previousProps, props) => {
22802
+ const keys = Object.keys(props);
22803
+ if (keys.length !== Object.keys(previousProps).length) {
22804
+ return false;
22805
+ }
22806
+ for (const key of keys) {
22807
+ if (!Object.hasOwn(previousProps, key)) {
22808
+ return false;
22809
+ }
22810
+ if (key.startsWith("on")) {
22811
+ continue;
22812
+ }
22813
+ const value = props[key];
22814
+ const previousValue = previousProps[key];
22815
+ if (value === previousValue) {
22816
+ continue;
22817
+ }
22818
+ if (!compareTwoJsValues(previousValue, value)) {
22819
+ return false;
22820
+ }
22755
22821
  }
22756
- return recurse(a, b);
22822
+ return true;
22757
22823
  };
22758
22824
  // The previous computation with this render's handlers: a handler goes where
22759
22825
  // its name went the previous time, self or child, the split being decided by