@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.
@@ -6472,6 +6472,9 @@ const findControlProxyTarget = (el) => {
6472
6472
  return document.getElementById(proxyFor);
6473
6473
  };
6474
6474
 
6475
+ // Shared: asked on every pseudo state change of every box, and almost always
6476
+ // empty.
6477
+ const NO_PROXIES = Object.freeze([]);
6475
6478
  /**
6476
6479
  * Given a real control element, returns every proxy that visually represents
6477
6480
  * it — a control can have more than one (an "enable"/"disable" button pair for
@@ -6486,11 +6489,11 @@ const findControlProxyTarget = (el) => {
6486
6489
  */
6487
6490
  const findControlProxies = (el) => {
6488
6491
  if (!el.id) {
6489
- return [];
6492
+ return NO_PROXIES;
6490
6493
  }
6491
6494
  const proxyControllerSet = findProxyControllers(el.id);
6492
6495
  if (!proxyControllerSet) {
6493
- return [];
6496
+ return NO_PROXIES;
6494
6497
  }
6495
6498
  const proxyElements = [];
6496
6499
  for (const proxyController of proxyControllerSet) {
@@ -6837,10 +6840,6 @@ const css$13 = /* css */ `
6837
6840
  border: none;
6838
6841
  outline: none; /* programmatic focus may land here briefly before being redirected to close button */
6839
6842
  opacity: 0;
6840
- /* opacity only: the placement lives in the translate property, which
6841
- applyNewPosition (visible_rect.js) owns and animates itself through the
6842
- Web Animations API, same mechanism Popover/Dialog use. */
6843
- transition: opacity 0.2s ease-in-out;
6844
6843
  cursor: initial; /* Do not inherit element cursor, inside the element but should use regular cursor */
6845
6844
  pointer-events: auto; /* Must be interactive to be closabled (overrid list item pointer-events none for instance) */
6846
6845
  overflow: visible;
@@ -6849,6 +6848,15 @@ const css$13 = /* css */ `
6849
6848
  position: absolute;
6850
6849
  }
6851
6850
 
6851
+ /* Armed after the first placement: the first show answers a tap or a
6852
+ click and appears at once, the fade is for the anchor scrolling out of
6853
+ view and back. Opacity only: the placement lives in the translate
6854
+ property, which applyNewPosition (visible_rect.js) owns and animates
6855
+ itself through the Web Animations API, same mechanism Popover/Dialog use. */
6856
+ &[data-placed] {
6857
+ transition: opacity 0.12s ease-out;
6858
+ }
6859
+
6852
6860
  &[data-status="success"] {
6853
6861
  --x-callout-status-color: var(--callout-success-color);
6854
6862
  }
@@ -8290,6 +8298,13 @@ const positionCallout = (
8290
8298
  calloutFrameElement.innerHTML = generateSvgWithoutArrow(width, height);
8291
8299
  calloutElement.style.opacity = 1;
8292
8300
  }
8301
+ if (!calloutElement.hasAttribute("data-placed")) {
8302
+ // Style flush between the first opacity write and arming the
8303
+ // transition, so that first write lands unanimated in the same frame.
8304
+ // eslint-disable-next-line no-unused-expressions
8305
+ getComputedStyle(calloutElement).opacity;
8306
+ calloutElement.setAttribute("data-placed", "");
8307
+ }
8293
8308
  applyNewPosition(calloutElement, position);
8294
8309
  },
8295
8310
  );
@@ -10943,15 +10958,17 @@ const resolveInteractions = (interactions) => {
10943
10958
  }
10944
10959
  }
10945
10960
  const kept = {};
10961
+ let keptSome = false;
10946
10962
  for (const type of Object.keys(resolved)) {
10947
10963
  if (resolved[type]) {
10948
10964
  kept[type] = resolved[type];
10965
+ keptSome = true;
10949
10966
  }
10950
10967
  }
10951
- resolved = kept;
10952
- if (Object.keys(resolved).length === 0) {
10968
+ if (!keptSome) {
10953
10969
  return null;
10954
10970
  }
10971
+ resolved = kept;
10955
10972
  {
10956
10973
  for (const type of Object.keys(resolved)) {
10957
10974
  const detector = detectors.find((candidate) => candidate.claims(type));
@@ -22157,8 +22174,7 @@ const getStyleToApply = (styles, pseudoState, pseudoNamedStyles) => {
22157
22174
  }
22158
22175
  let style = styles;
22159
22176
  for (const pseudoKey of Object.keys(pseudoNamedStyles)) {
22160
- const requiredStates = getPseudoKeyRequiredStates(pseudoKey);
22161
- if (!requiredStates.every((state) => pseudoState[state])) {
22177
+ if (!hasEveryState(pseudoState, getPseudoKeyRequiredStates(pseudoKey))) {
22162
22178
  continue;
22163
22179
  }
22164
22180
  if (style === styles) {
@@ -22213,6 +22229,14 @@ const getPseudoKeyRequiredStates = (pseudoKey) => {
22213
22229
  pseudoKeyRequiredStatesMap.set(pseudoKey, requiredStates);
22214
22230
  return requiredStates;
22215
22231
  };
22232
+ const hasEveryState = (pseudoState, states) => {
22233
+ for (const state of states) {
22234
+ if (!pseudoState[state]) {
22235
+ return false;
22236
+ }
22237
+ }
22238
+ return true;
22239
+ };
22216
22240
 
22217
22241
  // element → the style object last written to it, so the next one is written
22218
22242
  // as a difference: the values that changed, the keys it no longer has.
@@ -22290,7 +22314,7 @@ const updateStyle = (element, style, preventInitialTransition) => {
22290
22314
  // the browser for a frame costs more than that, and a page mounting thousands of
22291
22315
  // boxes asks thousands of times in the same tick. A Set, so an element styled
22292
22316
  // twice before the frame arrives is still one entry.
22293
- const elementSetWaitingFirstFrame = new Set();
22317
+ let elementSetWaitingFirstFrame = new Set();
22294
22318
  let firstFrameScheduled = false;
22295
22319
  const afterFirstFrame = (element) => {
22296
22320
  elementSetWaitingFirstFrame.add(element);
@@ -22300,8 +22324,8 @@ const afterFirstFrame = (element) => {
22300
22324
  firstFrameScheduled = true;
22301
22325
  requestAnimationFrame(() => {
22302
22326
  firstFrameScheduled = false;
22303
- const elements = [...elementSetWaitingFirstFrame];
22304
- elementSetWaitingFirstFrame.clear();
22327
+ const elements = elementSetWaitingFirstFrame;
22328
+ elementSetWaitingFirstFrame = new Set();
22305
22329
  for (const element of elements) {
22306
22330
  if (elementTransitionWeakMap.has(element)) {
22307
22331
  const transitionToRestore = elementTransitionWeakMap.get(element);
@@ -22637,6 +22661,7 @@ const readCSSVarEntry = entry => {
22637
22661
  }
22638
22662
  return [entry, null];
22639
22663
  };
22664
+ const readCSSVarName = entry => Array.isArray(entry) ? entry[0] : entry;
22640
22665
  // When only pseudoStateSelector is set (no visualSelector), the box owns its
22641
22666
  // visual identity. Only event handlers and these explicit props are forwarded
22642
22667
  // to the inner semantic/interactive child element.
@@ -22746,18 +22771,23 @@ const Box = props => {
22746
22771
  // exception — a closure is new on every render — so they are compared by
22747
22772
  // name only and put back fresh, see withCurrentHandlers.
22748
22773
  const renderMemoRef = useRef(null);
22774
+ if (!renderMemoRef.current) {
22775
+ renderMemoRef.current = {
22776
+ props: null,
22777
+ parentBoxFlow: null,
22778
+ computed: null
22779
+ };
22780
+ }
22749
22781
  const renderMemo = renderMemoRef.current;
22750
22782
  let computed;
22751
- if (renderMemo && renderMemo.parentBoxFlow === parentBoxFlow && arePropsEquivalent(renderMemo.props, computeProps)) {
22783
+ if (renderMemo.computed && renderMemo.parentBoxFlow === parentBoxFlow && arePropsEquivalent(renderMemo.props, computeProps)) {
22752
22784
  computed = withCurrentHandlers(renderMemo.computed, computeProps);
22753
22785
  } else {
22754
22786
  computed = computeBox(computeProps, parentBoxFlow);
22755
22787
  }
22756
- renderMemoRef.current = {
22757
- props: computeProps,
22758
- parentBoxFlow,
22759
- computed
22760
- };
22788
+ renderMemo.props = computeProps;
22789
+ renderMemo.parentBoxFlow = parentBoxFlow;
22790
+ renderMemo.computed = computed;
22761
22791
  const {
22762
22792
  TagName,
22763
22793
  boxFlow,
@@ -22789,6 +22819,16 @@ const Box = props => {
22789
22819
  children: innerChildren
22790
22820
  });
22791
22821
  }
22822
+
22823
+ // Only a Box reads the flow, and a box holding nothing but text has no Box
22824
+ // below it: the provider, a component of its own, is left out there. Moving
22825
+ // between the two shapes recreates text nodes, never a component.
22826
+ if (mayHoldComponent(innerChildren)) {
22827
+ innerChildren = jsx(BoxFlowContext.Provider, {
22828
+ value: boxFlow,
22829
+ children: innerChildren
22830
+ });
22831
+ }
22792
22832
  return jsx(TagName, {
22793
22833
  ref: finalRef,
22794
22834
  className: innerClassName,
@@ -22798,10 +22838,7 @@ const Box = props => {
22798
22838
  "navi-aspect-ratio": aspectRatio ? aspectRatio : undefined,
22799
22839
  "data-visual-selector": visualSelector,
22800
22840
  ...selfForwardedProps,
22801
- children: jsx(BoxFlowContext.Provider, {
22802
- value: boxFlow,
22803
- children: innerChildren
22804
- })
22841
+ children: innerChildren
22805
22842
  });
22806
22843
  };
22807
22844
 
@@ -23027,21 +23064,15 @@ const computeBox = (props, parentBoxFlow) => {
23027
23064
  let innerPseudoState;
23028
23065
  if (basePseudoState && pseudoState) {
23029
23066
  innerPseudoState = {};
23030
- const baseStateKeys = Object.keys(basePseudoState);
23031
- const pseudoStateKeySet = new Set(Object.keys(pseudoState));
23032
- for (const key of baseStateKeys) {
23033
- if (pseudoStateKeySet.has(key)) {
23034
- pseudoStateKeySet.delete(key);
23035
- const value = pseudoState[key];
23036
- styleDeps.push(key, value);
23037
- innerPseudoState[key] = value;
23038
- } else {
23039
- const value = basePseudoState[key];
23040
- styleDeps.push(key, value);
23041
- innerPseudoState[key] = value;
23042
- }
23067
+ for (const key of Object.keys(basePseudoState)) {
23068
+ const value = Object.hasOwn(pseudoState, key) ? pseudoState[key] : basePseudoState[key];
23069
+ styleDeps.push(key, value);
23070
+ innerPseudoState[key] = value;
23043
23071
  }
23044
- for (const key of pseudoStateKeySet) {
23072
+ for (const key of Object.keys(pseudoState)) {
23073
+ if (Object.hasOwn(basePseudoState, key)) {
23074
+ continue;
23075
+ }
23045
23076
  const value = pseudoState[key];
23046
23077
  styleDeps.push(key, value);
23047
23078
  innerPseudoState[key] = value;
@@ -23075,7 +23106,7 @@ const computeBox = (props, parentBoxFlow) => {
23075
23106
  const canForwardToChild = hasChildUsingForwardedProps;
23076
23107
  const addStyle = (value, name, styleContext, stylesTarget) => {
23077
23108
  const mergedValue = prepareStyleValue(stylesTarget[name], value, name, styleContext);
23078
- const [cssVar] = readCSSVarEntry(styleContext.styleCSSVars[name]);
23109
+ const cssVar = readCSSVarName(styleContext.styleCSSVars[name]);
23079
23110
  if (cssVar) {
23080
23111
  addCSSVar(mergedValue, cssVar, stylesTarget);
23081
23112
  if (name === "borderRadius" && value === "inherit") {
@@ -23131,12 +23162,13 @@ const computeBox = (props, parentBoxFlow) => {
23131
23162
  if (boxPseudoNamedStyles === PSEUDO_NAMED_STYLES_DEFAULT) {
23132
23163
  boxPseudoNamedStyles = {};
23133
23164
  }
23165
+ const pseudoCSSVars = styleCSSVars[name];
23134
23166
  const pseudoStyleContext = {
23135
23167
  ...styleContext,
23136
- styleCSSVars: {
23168
+ styleCSSVars: pseudoCSSVars ? {
23137
23169
  ...styleCSSVars,
23138
- ...styleCSSVars[name]
23139
- },
23170
+ ...pseudoCSSVars
23171
+ } : styleCSSVars,
23140
23172
  pseudoName: name
23141
23173
  };
23142
23174
  const pseudoStyleKeys = Object.keys(value);
@@ -23383,17 +23415,51 @@ const declaresSomething = value => {
23383
23415
  return true;
23384
23416
  };
23385
23417
  const isScrollingOverflow = value => value === "auto" || value === "scroll";
23418
+ const mayHoldComponent = children => {
23419
+ if (children === null || children === undefined) {
23420
+ return false;
23421
+ }
23422
+ const type = typeof children;
23423
+ if (type === "string" || type === "number" || type === "boolean") {
23424
+ return false;
23425
+ }
23426
+ if (Array.isArray(children)) {
23427
+ for (const child of children) {
23428
+ if (mayHoldComponent(child)) {
23429
+ return true;
23430
+ }
23431
+ }
23432
+ return false;
23433
+ }
23434
+ return true;
23435
+ };
23386
23436
 
23387
23437
  // Same props as far as computeBox is concerned. Handlers count by name only,
23388
- // see withCurrentHandlers; no style or state key starts with "on".
23389
- const arePropsEquivalent = (previousProps, props) => compareTwoJsValues(previousProps, props, {
23390
- keyComparator: comparePropAt
23391
- });
23392
- const comparePropAt = (a, b, key, recurse) => {
23393
- if (typeof key === "string" && key.startsWith("on")) {
23394
- return true;
23438
+ // see withCurrentHandlers. Identity first: most values are the very ones of
23439
+ // the previous render, only what a caller rebuilds inline (a style, a pseudo
23440
+ // state) needs the deep walk.
23441
+ const arePropsEquivalent = (previousProps, props) => {
23442
+ const keys = Object.keys(props);
23443
+ if (keys.length !== Object.keys(previousProps).length) {
23444
+ return false;
23445
+ }
23446
+ for (const key of keys) {
23447
+ if (!Object.hasOwn(previousProps, key)) {
23448
+ return false;
23449
+ }
23450
+ if (key.startsWith("on")) {
23451
+ continue;
23452
+ }
23453
+ const value = props[key];
23454
+ const previousValue = previousProps[key];
23455
+ if (value === previousValue) {
23456
+ continue;
23457
+ }
23458
+ if (!compareTwoJsValues(previousValue, value)) {
23459
+ return false;
23460
+ }
23395
23461
  }
23396
- return recurse(a, b);
23462
+ return true;
23397
23463
  };
23398
23464
  // The previous computation with this render's handlers: a handler goes where
23399
23465
  // its name went the previous time, self or child, the split being decided by