@jsenv/navi 0.27.59 → 0.27.61

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.
@@ -14696,23 +14696,37 @@ const setupBrowserIntegrationViaHistory = ({
14696
14696
  };
14697
14697
 
14698
14698
  let abortController = null;
14699
- const handleRoutingTask = (
14700
- url,
14701
- {
14699
+ const handleRoutingTask = (url, options) => {
14700
+ const isSameUrl = url === window.location.href;
14701
+ const {
14702
14702
  reason,
14703
14703
  navigationType, // "load", "reload", "replace", "push", "traverse"
14704
14704
  state,
14705
- },
14706
- ) => {
14707
- const isSameUrl = url === window.location.href;
14705
+ } = options;
14708
14706
 
14709
14707
  if (navigationType === "push" || navigationType === "replace") {
14710
- // Pre-merge visited URLs so push/replaceState is called only once.
14711
14708
  markUrlAsVisited(url);
14712
- const effectiveState = {
14713
- ...(state || {}),
14709
+ // undefined inherit current state (link click, neutral navigation)
14710
+ // null → explicit reset (no nav-state keys carried over)
14711
+ // {...} → explicit state from enter()/leave(), already built from currentState
14712
+ // When state is given it's responsability of the caller to ensure it inherits document state (or not, you want it 99% of the time)
14713
+ let effectiveState;
14714
+ const sharedState = {
14714
14715
  jsenv_visited_urls: Array.from(visitedUrlSet),
14715
14716
  };
14717
+ if (state === undefined) {
14718
+ effectiveState = {
14719
+ ...(getDocumentState() || {}),
14720
+ ...sharedState,
14721
+ };
14722
+ } else if (state === null) {
14723
+ effectiveState = sharedState;
14724
+ } else if (state) {
14725
+ effectiveState = {
14726
+ ...state,
14727
+ ...sharedState,
14728
+ };
14729
+ }
14716
14730
  if (navigationType === "push") {
14717
14731
  window.history.pushState(effectiveState, null, url);
14718
14732
  } else {
@@ -14798,7 +14812,6 @@ const setupBrowserIntegrationViaHistory = ({
14798
14812
  handleRoutingTask(href, {
14799
14813
  reason: `"click" on a[href="${href}"]`,
14800
14814
  navigationType: "push",
14801
- state: null,
14802
14815
  });
14803
14816
  },
14804
14817
  { capture: true },
@@ -14823,7 +14836,7 @@ const setupBrowserIntegrationViaHistory = ({
14823
14836
  });
14824
14837
  });
14825
14838
 
14826
- const navTo = async (url, { replace, state = null } = {}) => {
14839
+ const navTo = async (url, { replace, state } = {}) => {
14827
14840
  handleRoutingTask(url, {
14828
14841
  reason: `navTo called with "${url}"`,
14829
14842
  navigationType: replace ? "replace" : "push",
@@ -14994,41 +15007,33 @@ const NO_OP = () => {};
14994
15007
  const NO_ID_GIVEN = [undefined, NO_OP, NO_OP];
14995
15008
  const useNavStateBasic = (
14996
15009
  id,
14997
- initialValue,
14998
- { debug, type = "replace", onLeave } = {},
15010
+ { debug, type = "replace", onLeave, defaultValue } = {},
14999
15011
  ) => {
15000
15012
  // Hooks must be called unconditionally — before the !id early return.
15001
15013
  const state = documentStateSignal.value;
15002
- const valueInState = id
15003
- ? state !== null
15004
- ? state[id]
15005
- : undefined
15006
- : undefined;
15014
+ // Key presence is the flag — the value may be anything, including undefined.
15015
+ const keyInState = Boolean(id && state && Object.hasOwn(state, id));
15007
15016
  const onLeaveRef = useRef(onLeave);
15008
15017
  onLeaveRef.current = onLeave;
15009
- const prevValueInStateRef = useRef(valueInState);
15018
+ const prevKeyInStateRef = useRef(keyInState);
15010
15019
  // enteredRef tracks whether enter() was called without a matching leave() yet.
15011
15020
  // It lets the effect distinguish an external disappearance (back button → fire onLeave)
15012
15021
  // from a programmatic one (leave() already set it to false before the state updates).
15013
15022
  const enteredRef = useRef(false);
15014
15023
  useEffect(() => {
15015
- const prevValue = prevValueInStateRef.current;
15016
- prevValueInStateRef.current = valueInState;
15017
- if (
15018
- prevValue !== undefined &&
15019
- valueInState === undefined &&
15020
- enteredRef.current
15021
- ) {
15024
+ const prevKeyInState = prevKeyInStateRef.current;
15025
+ prevKeyInStateRef.current = keyInState;
15026
+ if (prevKeyInState && !keyInState && enteredRef.current) {
15022
15027
  enteredRef.current = false;
15023
15028
  onLeaveRef.current?.();
15024
15029
  }
15025
- }, [valueInState]);
15030
+ }, [keyInState]);
15026
15031
 
15027
15032
  if (!id) {
15028
15033
  return NO_ID_GIVEN;
15029
15034
  }
15030
15035
 
15031
- const currentValue = valueInState !== undefined ? valueInState : initialValue;
15036
+ const currentValue = keyInState ? state[id] : defaultValue;
15032
15037
 
15033
15038
  if (debug) {
15034
15039
  console.debug(`useNavState(${id}) current value is ${currentValue}`);
@@ -15040,30 +15045,36 @@ const useNavStateBasic = (
15040
15045
  // extra data with the entry when needed.
15041
15046
  const enter = (value = "on") => {
15042
15047
  enteredRef.current = true;
15043
- const currentState = browserIntegration.getDocumentState() || {};
15044
- if (currentState[id] === value) {
15048
+ const currentStateCopy = browserIntegration.getDocumentState() || {};
15049
+ if (Object.hasOwn(currentStateCopy, id) && currentStateCopy[id] === value) {
15045
15050
  return;
15046
15051
  }
15047
- const newState = { ...currentState, [id]: value };
15052
+ currentStateCopy[id] = value;
15048
15053
  navTo(window.location.href, {
15049
15054
  replace: type !== "push",
15050
- state: newState,
15055
+ state: currentStateCopy,
15051
15056
  });
15052
15057
  };
15053
15058
 
15054
15059
  // leave(): navigate AWAY FROM this state (navBack in push mode, replace in replace mode).
15055
- const leave = () => {
15060
+ // isBack: when true (cancel close in push mode), call history.back() to restore the
15061
+ // pre-open state — discards any in-progress edits.
15062
+ // When false (confirmed close), replace the pushed entry instead: preserves the
15063
+ // current URL state (e.g. a new picker value) while removing the popup key.
15064
+ const leave = ({ isBack } = {}) => {
15056
15065
  enteredRef.current = false;
15057
- const currentState = browserIntegration.getDocumentState() || {};
15058
- if (!Object.hasOwn(currentState, id)) {
15066
+ const currentStateCopy = browserIntegration.getDocumentState() || {};
15067
+ if (!Object.hasOwn(currentStateCopy, id)) {
15059
15068
  return;
15060
15069
  }
15061
- if (type === "push") {
15070
+ if (type === "push" && isBack) {
15062
15071
  browserIntegration.navBack();
15063
15072
  } else {
15064
- const newState = { ...currentState };
15065
- delete newState[id];
15066
- navTo(window.location.href, { replace: true, state: newState });
15073
+ delete currentStateCopy[id];
15074
+ navTo(window.location.href, {
15075
+ replace: true,
15076
+ state: currentStateCopy,
15077
+ });
15067
15078
  }
15068
15079
  };
15069
15080
 
@@ -15077,9 +15088,6 @@ const useNavStateBasic = (
15077
15088
  * @param {string} id
15078
15089
  * Unique key used to store the value in document state. Must be stable across renders.
15079
15090
  *
15080
- * @param {*} initialValue
15081
- * Value returned when `id` is absent from document state (e.g. before enter() is called).
15082
- *
15083
15091
  * @param {object} [options]
15084
15092
  * @param {"push"|"replace"} [options.type="replace"]
15085
15093
  * Controls how enter() adds the state to browser history.
@@ -15088,9 +15096,11 @@ const useNavStateBasic = (
15088
15096
  * @param {() => void} [options.onLeave]
15089
15097
  * Called when the state key disappears **externally** — e.g. the user presses the browser
15090
15098
  * back button. Not called when leave() is invoked programmatically.
15099
+ * @param {*} [options.defaultValue]
15100
+ * Value returned when `id` is absent from document state. Defaults to `undefined`.
15091
15101
  *
15092
15102
  * @returns {[value, enter, leave]}
15093
- * - `value`: current value from document state, or `initialValue` when the key is absent.
15103
+ * - `value`: current value from document state, or `defaultValue` when the key is absent.
15094
15104
  * - `enter(value = "on")`: navigate TO this state (stores `value` under `id`).
15095
15105
  * Calling without an argument stores `"on"` — the presence of the key is enough to match;
15096
15106
  * the value allows associating extra data when needed.
@@ -22705,6 +22715,23 @@ const useUIStateController = (
22705
22715
  if (e.type === "facade_propagate_up") {
22706
22716
  notifyParentAboutChildUIAction(e, { stateChanged: true });
22707
22717
  }
22718
+ // Exception: state_prop_change can only fire on a control with its own
22719
+ // controlled state/value prop (see hasStateProp above) — groups never
22720
+ // cascade state down into such children (they're explicitly skipped,
22721
+ // see shouldPropagateStateToChild/hasStateProp checks), so this change
22722
+ // can never be an echo of the parent's own cascade. The loop risk this
22723
+ // suppression exists for only applies when the parent itself just pushed
22724
+ // this value down, which requires the parent to be controlled (have its
22725
+ // own state/value prop). When the parent is "stateless" (uncontrolled),
22726
+ // notifying it is always safe and necessary — otherwise its aggregated
22727
+ // state silently drifts out of sync with this child.
22728
+ if (
22729
+ e.type === "state_prop_change" &&
22730
+ parentUIStateController &&
22731
+ !parentUIStateController.hasStateProp
22732
+ ) {
22733
+ notifyParentAboutChildUIAction(e, { stateChanged: true });
22734
+ }
22708
22735
  return true;
22709
22736
  }
22710
22737
  notifyParentAboutChildUIAction(e, { stateChanged: true });
@@ -35552,7 +35579,8 @@ installImportMetaCssBuild(import.meta);const css$r = /* css */`
35552
35579
  const Dialog = props => {
35553
35580
  import.meta.css = [css$r, "@jsenv/navi/src/popup/dialog.jsx"];
35554
35581
  const {
35555
- open: openProp = false,
35582
+ // requestOpen,
35583
+ requestClose,
35556
35584
  anchorRef,
35557
35585
  children,
35558
35586
  scrollTrap,
@@ -35630,7 +35658,7 @@ const Dialog = props => {
35630
35658
  focusedBeforeOpen
35631
35659
  });
35632
35660
  };
35633
- const close = (e, detail = {}) => {
35661
+ const close = e => {
35634
35662
  debugPopup(`"${e.type}" on ${getElementSignature(e.target)} -> closeDialog`);
35635
35663
  const dialogEl = ref.current;
35636
35664
  markAutofocusRestoreOnClose(dialogEl);
@@ -35638,70 +35666,9 @@ const Dialog = props => {
35638
35666
  cleanup();
35639
35667
  openedRef.current = false;
35640
35668
  dispatchCustomEvent(dialogEl, "navi_close", {
35641
- event: e,
35642
- ...detail
35669
+ event: e
35643
35670
  });
35644
35671
  };
35645
- const onRequestOpen = e => {
35646
- const dialogEl = ref.current;
35647
- if (!dialogEl) {
35648
- return;
35649
- }
35650
- if (openedRef.current) {
35651
- return;
35652
- }
35653
- open(e);
35654
- };
35655
- const onRequestClose = (e, detail = {}) => {
35656
- const dialogEl = ref.current;
35657
- if (!dialogEl) {
35658
- return;
35659
- }
35660
- if (!openedRef.current) {
35661
- return;
35662
- }
35663
- if (closeRequestHandler) {
35664
- let denied = false;
35665
- const closePermission = {
35666
- deny: () => {
35667
- denied = true;
35668
- },
35669
- allow: () => {
35670
- denied = false;
35671
- }
35672
- };
35673
- closeRequestHandler(e, closePermission, detail);
35674
- if (denied) {
35675
- if (e.type === "cancel") {
35676
- e.preventDefault();
35677
- }
35678
- closePermission.allow = () => {
35679
- close(e, detail);
35680
- };
35681
- return;
35682
- }
35683
- }
35684
- close(e, detail);
35685
- };
35686
- useLayoutEffect(() => {
35687
- if (openProp === undefined) {
35688
- return;
35689
- }
35690
- // Skip when the popover is already in the desired state.
35691
- // This avoids a feedback loop: our own close/open dispatches navi_close/navi_open,
35692
- // the parent updates the prop, and the effect would fire again for a change we
35693
- // already handled. Comparing against openedRef is the authoritative check because
35694
- // it reflects the actual DOM state, not the React render cycle.
35695
- if (openProp === openedRef.current) {
35696
- return;
35697
- }
35698
- const e = new CustomEvent("open_prop_change");
35699
- if (openProp) {
35700
- onRequestOpen(e);
35701
- } else {
35702
- onRequestClose(e);
35703
- }
35704
- }, [openProp]);
35705
35672
  return jsx(Box, {
35706
35673
  ...rest,
35707
35674
  ...autoFocusProps,
@@ -35718,20 +35685,57 @@ const Dialog = props => {
35718
35685
  const rect = ref.current.getBoundingClientRect();
35719
35686
  const isBackdrop = e.clientX < rect.left || e.clientX > rect.right || e.clientY < rect.top || e.clientY > rect.bottom;
35720
35687
  if (isBackdrop) {
35721
- onRequestClose(e, {
35722
- isClickOutside: true
35688
+ requestClose(e, {
35689
+ isCancel: true
35723
35690
  });
35724
35691
  }
35725
35692
  }
35726
35693
  },
35727
35694
  onCancel: e => {
35728
- onRequestClose(e);
35695
+ requestClose(e, {
35696
+ isCancel: true
35697
+ });
35729
35698
  },
35730
35699
  onnavi_request_open: e => {
35731
- onRequestOpen(e);
35700
+ const dialogEl = ref.current;
35701
+ if (!dialogEl) {
35702
+ return;
35703
+ }
35704
+ if (openedRef.current) {
35705
+ return;
35706
+ }
35707
+ open(e);
35732
35708
  },
35733
35709
  onnavi_request_close: e => {
35734
- onRequestClose(e);
35710
+ const dialogEl = ref.current;
35711
+ if (!dialogEl) {
35712
+ return;
35713
+ }
35714
+ if (!openedRef.current) {
35715
+ return;
35716
+ }
35717
+ if (closeRequestHandler) {
35718
+ let denied = false;
35719
+ const closePermission = {
35720
+ deny: () => {
35721
+ denied = true;
35722
+ },
35723
+ allow: () => {
35724
+ denied = false;
35725
+ }
35726
+ };
35727
+ closeRequestHandler(e, closePermission);
35728
+ if (denied) {
35729
+ if (e.type === "cancel") {
35730
+ e.preventDefault();
35731
+ }
35732
+ closePermission.allow = () => {
35733
+ close(e);
35734
+ };
35735
+ return;
35736
+ }
35737
+ }
35738
+ close(e);
35735
35739
  },
35736
35740
  children: children
35737
35741
  });
@@ -35763,7 +35767,7 @@ installImportMetaCssBuild(import.meta);const css$q = /* css */`
35763
35767
  const Popover = props => {
35764
35768
  import.meta.css = [css$q, "@jsenv/navi/src/popup/popover.jsx"];
35765
35769
  const {
35766
- open: openProp = false,
35770
+ requestClose,
35767
35771
  anchorRef,
35768
35772
  scrollTrap,
35769
35773
  pointerTrap,
@@ -35875,7 +35879,7 @@ const Popover = props => {
35875
35879
  focusedBeforeOpen
35876
35880
  });
35877
35881
  };
35878
- const close = (e, detail = {}) => {
35882
+ const close = e => {
35879
35883
  debugPopup(e, `closePopover()`);
35880
35884
  const popoverEl = ref.current;
35881
35885
  markAutofocusRestoreOnClose(popoverEl);
@@ -35883,69 +35887,9 @@ const Popover = props => {
35883
35887
  cleanup();
35884
35888
  openedRef.current = false;
35885
35889
  dispatchCustomEvent(popoverEl, "navi_close", {
35886
- event: e,
35887
- ...detail
35890
+ event: e
35888
35891
  });
35889
35892
  };
35890
- const onRequestOpen = e => {
35891
- const popoverEl = ref.current;
35892
- if (!popoverEl) {
35893
- return;
35894
- }
35895
- if (openedRef.current) {
35896
- return;
35897
- }
35898
- open(e);
35899
- };
35900
- const onRequestClose = (e, detail = {}) => {
35901
- const popoverEl = ref.current;
35902
- if (!popoverEl) {
35903
- return;
35904
- }
35905
- if (!openedRef.current) {
35906
- return;
35907
- }
35908
- if (closeRequestHandler) {
35909
- let denied = false;
35910
- const closePermission = {
35911
- deny: () => {
35912
- denied = true;
35913
- },
35914
- allow: () => {
35915
- denied = false;
35916
- }
35917
- };
35918
- closeRequestHandler(e, closePermission, detail);
35919
- if (denied) {
35920
- closePermission.allow = () => {
35921
- close(e, detail);
35922
- };
35923
- return;
35924
- }
35925
- }
35926
- close(e, detail);
35927
- };
35928
- useLayoutEffect(() => {
35929
- if (openProp === undefined) {
35930
- return;
35931
- }
35932
- // Skip when the popover is already in the desired state.
35933
- // This avoids a feedback loop: our own close/open dispatches navi_close/navi_open,
35934
- // the parent updates the prop, and the effect would fire again for a change we
35935
- // already handled. Comparing against openedRef is the authoritative check because
35936
- // it reflects the actual DOM state, not the React render cycle.
35937
- if (openProp === openedRef.current) {
35938
- return;
35939
- }
35940
- const e = new CustomEvent("open_prop_change", {
35941
- detail: {}
35942
- });
35943
- if (openProp) {
35944
- onRequestOpen(e);
35945
- } else {
35946
- onRequestClose(e);
35947
- }
35948
- }, [openProp]);
35949
35893
  return jsxs(Box, {
35950
35894
  id: id,
35951
35895
  popover: "manual",
@@ -35955,10 +35899,42 @@ const Popover = props => {
35955
35899
  baseClassName: "navi_popover",
35956
35900
  pseudoClasses: POPOVER_PSEUDO_CLASSES,
35957
35901
  onnavi_request_open: e => {
35958
- onRequestOpen(e);
35902
+ const popoverEl = ref.current;
35903
+ if (!popoverEl) {
35904
+ return;
35905
+ }
35906
+ if (openedRef.current) {
35907
+ return;
35908
+ }
35909
+ open(e);
35959
35910
  },
35960
35911
  onnavi_request_close: e => {
35961
- onRequestClose(e);
35912
+ const popoverEl = ref.current;
35913
+ if (!popoverEl) {
35914
+ return;
35915
+ }
35916
+ if (!openedRef.current) {
35917
+ return;
35918
+ }
35919
+ if (closeRequestHandler) {
35920
+ let denied = false;
35921
+ const closePermission = {
35922
+ deny: () => {
35923
+ denied = true;
35924
+ },
35925
+ allow: () => {
35926
+ denied = false;
35927
+ }
35928
+ };
35929
+ closeRequestHandler(e, closePermission);
35930
+ if (denied) {
35931
+ closePermission.allow = () => {
35932
+ close(e);
35933
+ };
35934
+ return;
35935
+ }
35936
+ }
35937
+ close(e);
35962
35938
  },
35963
35939
  children: [jsx("div", {
35964
35940
  className: "navi_popover_backdrop",
@@ -35971,8 +35947,8 @@ const Popover = props => {
35971
35947
  e.preventDefault();
35972
35948
  return;
35973
35949
  }
35974
- onRequestClose(e, {
35975
- isClickOutside: true
35950
+ requestClose(e, {
35951
+ isCancel: true
35976
35952
  });
35977
35953
  }
35978
35954
  }), children]
@@ -36261,8 +36237,7 @@ const PickerCustom = props => {
36261
36237
  const popupRef = useRef(null);
36262
36238
  popupProps.ref = popupRef;
36263
36239
  // aria-controls + id
36264
- const autoId = useId();
36265
- const popupId = `picker_popup_${autoId}`;
36240
+ const popupId = `${props.id}_picker_popup`;
36266
36241
  {
36267
36242
  Object.assign(pickerProps, {
36268
36243
  "aria-controls": popupId
@@ -36279,7 +36254,7 @@ const PickerCustom = props => {
36279
36254
  // In "popover" mode, it replaces the current history state (no history entry added).
36280
36255
  const pickerNavType = mode === "dialog" ? "push" : "replace";
36281
36256
  const expandedRef = useRef(false);
36282
- const [expanded, enterExpanded, leaveExpanded] = useNavState(popupId, false, {
36257
+ const [expanded, enterExpanded, leaveExpanded] = useNavState(popupId, {
36283
36258
  type: pickerNavType,
36284
36259
  // onLeave fires only when the state key disappears externally (back button/gesture most of the time).
36285
36260
  onLeave: () => {
@@ -36290,7 +36265,8 @@ const PickerCustom = props => {
36290
36265
  });
36291
36266
  }
36292
36267
  });
36293
- expandedRef.current = Boolean(expanded);
36268
+ // expandedRef tracks actual open/close state, updated only by onOpen/onClose.
36269
+ // NOT synced to expanded on every render so the useLayoutEffect guard below works.
36294
36270
  const valueAtOpenRef = useRef(null);
36295
36271
  const activeElementAtOpenRef = useRef(null);
36296
36272
  const onOpen = e => {
@@ -36338,7 +36314,9 @@ const PickerCustom = props => {
36338
36314
  }
36339
36315
  }
36340
36316
  expandedRef.current = false;
36341
- leaveExpanded();
36317
+ leaveExpanded({
36318
+ isBack: e.detail.isCancel
36319
+ });
36342
36320
  // Reset so the next opening re-evaluates screen size
36343
36321
  defaultModeRef.current = null;
36344
36322
  restoreFocus(e);
@@ -36346,7 +36324,7 @@ const PickerCustom = props => {
36346
36324
  const disableClickFor = useIgnoreClickForMousedown(ref, e => {
36347
36325
  debugPopup(e, `click ignored`);
36348
36326
  });
36349
- const requestOpen = e => {
36327
+ const requestOpen = (e, detail) => {
36350
36328
  // scroll <button> of the picker into view when opening it
36351
36329
  const pickerEl = ref.current;
36352
36330
  pickerEl.scrollIntoView({
@@ -36354,18 +36332,47 @@ const PickerCustom = props => {
36354
36332
  });
36355
36333
  const popupEl = popupRef.current;
36356
36334
  return dispatchCustomEvent(popupEl, "navi_request_open", {
36357
- event: e
36335
+ event: e,
36336
+ ...detail
36358
36337
  });
36359
36338
  };
36360
- const requestClose = (e = new CustomEvent("programmatic"), {
36361
- isCancel = false
36362
- } = {}) => {
36339
+ const requestClose = (e = new CustomEvent("programmatic", {
36340
+ detail: {}
36341
+ }), detail) => {
36363
36342
  const popupEl = popupRef.current;
36364
36343
  return dispatchCustomEvent(popupEl, "navi_request_close", {
36365
36344
  event: e,
36366
- isCancel
36345
+ ...detail
36367
36346
  });
36368
36347
  };
36348
+ const open = Boolean(expanded);
36349
+ useLayoutEffect(() => {
36350
+ if (open === undefined) {
36351
+ return;
36352
+ }
36353
+ // Skip when the popup is already in the desired state.
36354
+ // expandedRef tracks actual open/close (updated by onOpen/onClose, not by renders)
36355
+ // so it is the authoritative check against feedback loops.
36356
+ if (open === expandedRef.current) {
36357
+ return;
36358
+ }
36359
+ // open_prop_change means the parent is driving the open state directly
36360
+ // (e.g. back-button navigation flipped openProp to false before onLeave fires).
36361
+ // Always treat it as cancel — the user's in-progress edit should be discarded.
36362
+ if (open) {
36363
+ requestOpen(new CustomEvent("open_by_prop", {
36364
+ detail: {}
36365
+ }), {
36366
+ isCancel: true
36367
+ });
36368
+ } else {
36369
+ requestClose(new CustomEvent("close_by_prop", {
36370
+ detail: {}
36371
+ }), {
36372
+ isCancel: true
36373
+ });
36374
+ }
36375
+ }, [open]);
36369
36376
  const requestInteraction = options => {
36370
36377
  dispatchRequestInteraction(ref.current, options);
36371
36378
  };
@@ -36407,12 +36414,9 @@ const PickerCustom = props => {
36407
36414
  });
36408
36415
  Object.assign(popupProps, {
36409
36416
  anchorRef: props.ref,
36410
- open: Boolean(expanded),
36411
- closeRequestHandler: (requestCloseEvent, closePermission, {
36412
- isClickOutside
36413
- } = {}) => {
36414
- const cancelEvent = findEvent(requestCloseEvent, eInChain => eInChain.type === "navi_request_close" && eInChain.detail.isCancel);
36415
- const isCancel = isClickOutside || Boolean(cancelEvent);
36417
+ requestClose,
36418
+ closeRequestHandler: (requestCloseEvent, closePermission) => {
36419
+ const isCancel = requestCloseEvent.detail.isCancel;
36416
36420
  if (isCancel) {
36417
36421
  const pickerEl = ref.current;
36418
36422
  const inputEl = getPickerInput(pickerEl);