@jsenv/navi 0.29.396 → 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) {
@@ -10955,15 +10958,17 @@ const resolveInteractions = (interactions) => {
10955
10958
  }
10956
10959
  }
10957
10960
  const kept = {};
10961
+ let keptSome = false;
10958
10962
  for (const type of Object.keys(resolved)) {
10959
10963
  if (resolved[type]) {
10960
10964
  kept[type] = resolved[type];
10965
+ keptSome = true;
10961
10966
  }
10962
10967
  }
10963
- resolved = kept;
10964
- if (Object.keys(resolved).length === 0) {
10968
+ if (!keptSome) {
10965
10969
  return null;
10966
10970
  }
10971
+ resolved = kept;
10967
10972
  {
10968
10973
  for (const type of Object.keys(resolved)) {
10969
10974
  const detector = detectors.find((candidate) => candidate.claims(type));
@@ -22169,8 +22174,7 @@ const getStyleToApply = (styles, pseudoState, pseudoNamedStyles) => {
22169
22174
  }
22170
22175
  let style = styles;
22171
22176
  for (const pseudoKey of Object.keys(pseudoNamedStyles)) {
22172
- const requiredStates = getPseudoKeyRequiredStates(pseudoKey);
22173
- if (!requiredStates.every((state) => pseudoState[state])) {
22177
+ if (!hasEveryState(pseudoState, getPseudoKeyRequiredStates(pseudoKey))) {
22174
22178
  continue;
22175
22179
  }
22176
22180
  if (style === styles) {
@@ -22225,6 +22229,14 @@ const getPseudoKeyRequiredStates = (pseudoKey) => {
22225
22229
  pseudoKeyRequiredStatesMap.set(pseudoKey, requiredStates);
22226
22230
  return requiredStates;
22227
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
+ };
22228
22240
 
22229
22241
  // element → the style object last written to it, so the next one is written
22230
22242
  // as a difference: the values that changed, the keys it no longer has.
@@ -22302,7 +22314,7 @@ const updateStyle = (element, style, preventInitialTransition) => {
22302
22314
  // the browser for a frame costs more than that, and a page mounting thousands of
22303
22315
  // boxes asks thousands of times in the same tick. A Set, so an element styled
22304
22316
  // twice before the frame arrives is still one entry.
22305
- const elementSetWaitingFirstFrame = new Set();
22317
+ let elementSetWaitingFirstFrame = new Set();
22306
22318
  let firstFrameScheduled = false;
22307
22319
  const afterFirstFrame = (element) => {
22308
22320
  elementSetWaitingFirstFrame.add(element);
@@ -22312,8 +22324,8 @@ const afterFirstFrame = (element) => {
22312
22324
  firstFrameScheduled = true;
22313
22325
  requestAnimationFrame(() => {
22314
22326
  firstFrameScheduled = false;
22315
- const elements = [...elementSetWaitingFirstFrame];
22316
- elementSetWaitingFirstFrame.clear();
22327
+ const elements = elementSetWaitingFirstFrame;
22328
+ elementSetWaitingFirstFrame = new Set();
22317
22329
  for (const element of elements) {
22318
22330
  if (elementTransitionWeakMap.has(element)) {
22319
22331
  const transitionToRestore = elementTransitionWeakMap.get(element);
@@ -22649,6 +22661,7 @@ const readCSSVarEntry = entry => {
22649
22661
  }
22650
22662
  return [entry, null];
22651
22663
  };
22664
+ const readCSSVarName = entry => Array.isArray(entry) ? entry[0] : entry;
22652
22665
  // When only pseudoStateSelector is set (no visualSelector), the box owns its
22653
22666
  // visual identity. Only event handlers and these explicit props are forwarded
22654
22667
  // to the inner semantic/interactive child element.
@@ -22758,18 +22771,23 @@ const Box = props => {
22758
22771
  // exception — a closure is new on every render — so they are compared by
22759
22772
  // name only and put back fresh, see withCurrentHandlers.
22760
22773
  const renderMemoRef = useRef(null);
22774
+ if (!renderMemoRef.current) {
22775
+ renderMemoRef.current = {
22776
+ props: null,
22777
+ parentBoxFlow: null,
22778
+ computed: null
22779
+ };
22780
+ }
22761
22781
  const renderMemo = renderMemoRef.current;
22762
22782
  let computed;
22763
- if (renderMemo && renderMemo.parentBoxFlow === parentBoxFlow && arePropsEquivalent(renderMemo.props, computeProps)) {
22783
+ if (renderMemo.computed && renderMemo.parentBoxFlow === parentBoxFlow && arePropsEquivalent(renderMemo.props, computeProps)) {
22764
22784
  computed = withCurrentHandlers(renderMemo.computed, computeProps);
22765
22785
  } else {
22766
22786
  computed = computeBox(computeProps, parentBoxFlow);
22767
22787
  }
22768
- renderMemoRef.current = {
22769
- props: computeProps,
22770
- parentBoxFlow,
22771
- computed
22772
- };
22788
+ renderMemo.props = computeProps;
22789
+ renderMemo.parentBoxFlow = parentBoxFlow;
22790
+ renderMemo.computed = computed;
22773
22791
  const {
22774
22792
  TagName,
22775
22793
  boxFlow,
@@ -22801,6 +22819,16 @@ const Box = props => {
22801
22819
  children: innerChildren
22802
22820
  });
22803
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
+ }
22804
22832
  return jsx(TagName, {
22805
22833
  ref: finalRef,
22806
22834
  className: innerClassName,
@@ -22810,10 +22838,7 @@ const Box = props => {
22810
22838
  "navi-aspect-ratio": aspectRatio ? aspectRatio : undefined,
22811
22839
  "data-visual-selector": visualSelector,
22812
22840
  ...selfForwardedProps,
22813
- children: jsx(BoxFlowContext.Provider, {
22814
- value: boxFlow,
22815
- children: innerChildren
22816
- })
22841
+ children: innerChildren
22817
22842
  });
22818
22843
  };
22819
22844
 
@@ -23039,21 +23064,15 @@ const computeBox = (props, parentBoxFlow) => {
23039
23064
  let innerPseudoState;
23040
23065
  if (basePseudoState && pseudoState) {
23041
23066
  innerPseudoState = {};
23042
- const baseStateKeys = Object.keys(basePseudoState);
23043
- const pseudoStateKeySet = new Set(Object.keys(pseudoState));
23044
- for (const key of baseStateKeys) {
23045
- if (pseudoStateKeySet.has(key)) {
23046
- pseudoStateKeySet.delete(key);
23047
- const value = pseudoState[key];
23048
- styleDeps.push(key, value);
23049
- innerPseudoState[key] = value;
23050
- } else {
23051
- const value = basePseudoState[key];
23052
- styleDeps.push(key, value);
23053
- innerPseudoState[key] = value;
23054
- }
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;
23055
23071
  }
23056
- for (const key of pseudoStateKeySet) {
23072
+ for (const key of Object.keys(pseudoState)) {
23073
+ if (Object.hasOwn(basePseudoState, key)) {
23074
+ continue;
23075
+ }
23057
23076
  const value = pseudoState[key];
23058
23077
  styleDeps.push(key, value);
23059
23078
  innerPseudoState[key] = value;
@@ -23087,7 +23106,7 @@ const computeBox = (props, parentBoxFlow) => {
23087
23106
  const canForwardToChild = hasChildUsingForwardedProps;
23088
23107
  const addStyle = (value, name, styleContext, stylesTarget) => {
23089
23108
  const mergedValue = prepareStyleValue(stylesTarget[name], value, name, styleContext);
23090
- const [cssVar] = readCSSVarEntry(styleContext.styleCSSVars[name]);
23109
+ const cssVar = readCSSVarName(styleContext.styleCSSVars[name]);
23091
23110
  if (cssVar) {
23092
23111
  addCSSVar(mergedValue, cssVar, stylesTarget);
23093
23112
  if (name === "borderRadius" && value === "inherit") {
@@ -23143,12 +23162,13 @@ const computeBox = (props, parentBoxFlow) => {
23143
23162
  if (boxPseudoNamedStyles === PSEUDO_NAMED_STYLES_DEFAULT) {
23144
23163
  boxPseudoNamedStyles = {};
23145
23164
  }
23165
+ const pseudoCSSVars = styleCSSVars[name];
23146
23166
  const pseudoStyleContext = {
23147
23167
  ...styleContext,
23148
- styleCSSVars: {
23168
+ styleCSSVars: pseudoCSSVars ? {
23149
23169
  ...styleCSSVars,
23150
- ...styleCSSVars[name]
23151
- },
23170
+ ...pseudoCSSVars
23171
+ } : styleCSSVars,
23152
23172
  pseudoName: name
23153
23173
  };
23154
23174
  const pseudoStyleKeys = Object.keys(value);
@@ -23395,17 +23415,51 @@ const declaresSomething = value => {
23395
23415
  return true;
23396
23416
  };
23397
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
+ };
23398
23436
 
23399
23437
  // Same props as far as computeBox is concerned. Handlers count by name only,
23400
- // see withCurrentHandlers; no style or state key starts with "on".
23401
- const arePropsEquivalent = (previousProps, props) => compareTwoJsValues(previousProps, props, {
23402
- keyComparator: comparePropAt
23403
- });
23404
- const comparePropAt = (a, b, key, recurse) => {
23405
- if (typeof key === "string" && key.startsWith("on")) {
23406
- 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
+ }
23407
23461
  }
23408
- return recurse(a, b);
23462
+ return true;
23409
23463
  };
23410
23464
  // The previous computation with this render's handlers: a handler goes where
23411
23465
  // its name went the previous time, self or child, the split being decided by