@x-plat/design-system 0.14.14 → 0.14.16

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.
@@ -3053,7 +3053,7 @@ Chip.displayName = "Chip";
3053
3053
  var Chip_default = Chip;
3054
3054
 
3055
3055
  // src/components/DatePicker/InputDatePicker/index.tsx
3056
- var import_react13 = __toESM(require("react"), 1);
3056
+ var import_react14 = __toESM(require("react"), 1);
3057
3057
 
3058
3058
  // src/components/Input/Input.tsx
3059
3059
  var import_react8 = __toESM(require("react"), 1);
@@ -3226,11 +3226,149 @@ PasswordInput.displayName = "PasswordInput";
3226
3226
  var PasswordInput_default = PasswordInput;
3227
3227
 
3228
3228
  // src/components/Modal/Modal.tsx
3229
- var import_react11 = __toESM(require("react"), 1);
3229
+ var import_react12 = __toESM(require("react"), 1);
3230
3230
  var import_react_dom = require("react-dom");
3231
3231
 
3232
3232
  // src/tokens/hooks/useOverlayKeyboard.ts
3233
+ var import_react11 = __toESM(require("react"), 1);
3234
+
3235
+ // src/tokens/hooks/useAutoPosition.ts
3233
3236
  var import_react10 = __toESM(require("react"), 1);
3237
+ var findScrollParent = (el) => {
3238
+ for (let p = el.parentElement; p; p = p.parentElement) {
3239
+ const { overflowY, overflowX } = getComputedStyle(p);
3240
+ if (/(auto|scroll)/.test(overflowY) || /(auto|scroll)/.test(overflowX)) return p;
3241
+ }
3242
+ return null;
3243
+ };
3244
+ var TRIGGER_GAP = 8;
3245
+ var computePlacement = (triggerRect, popW, popH, clip) => {
3246
+ const roomBelow = clip.bottom - triggerRect.bottom - TRIGGER_GAP;
3247
+ const roomAbove = triggerRect.top - clip.top - TRIGGER_GAP;
3248
+ let direction;
3249
+ let top;
3250
+ let maxHeight = null;
3251
+ if (popH <= roomBelow) {
3252
+ direction = "bottom";
3253
+ top = triggerRect.bottom + TRIGGER_GAP;
3254
+ } else if (popH <= roomAbove) {
3255
+ direction = "top";
3256
+ top = triggerRect.top - TRIGGER_GAP - popH;
3257
+ } else {
3258
+ const room = Math.max(roomBelow, roomAbove, 0);
3259
+ if (roomBelow >= roomAbove) {
3260
+ direction = "bottom";
3261
+ top = triggerRect.bottom + TRIGGER_GAP;
3262
+ } else {
3263
+ direction = "top";
3264
+ top = triggerRect.top - TRIGGER_GAP - room;
3265
+ }
3266
+ maxHeight = room;
3267
+ }
3268
+ let left = triggerRect.left;
3269
+ if (left + popW > clip.right - 8) {
3270
+ left = triggerRect.right - popW;
3271
+ }
3272
+ if (left < clip.left + 8) left = clip.left + 8;
3273
+ const drawnH = maxHeight === null ? popH : Math.min(popH, maxHeight);
3274
+ return {
3275
+ direction,
3276
+ top,
3277
+ left,
3278
+ maxHeight,
3279
+ over: {
3280
+ top: Math.max(0, clip.top - top),
3281
+ right: Math.max(0, left + popW - clip.right),
3282
+ bottom: Math.max(0, top + drawnH - clip.bottom),
3283
+ left: Math.max(0, clip.left - left)
3284
+ }
3285
+ };
3286
+ };
3287
+ var useAutoPosition = (triggerRef, popRef, enabled = true) => {
3288
+ const directionRef = import_react10.default.useRef("bottom");
3289
+ const sizeRef = import_react10.default.useRef(null);
3290
+ const scrollParentRef = import_react10.default.useRef(null);
3291
+ const placedRef = import_react10.default.useRef(false);
3292
+ const calculatePosition = import_react10.default.useCallback((remeasure = false) => {
3293
+ const pop = popRef.current;
3294
+ if (!triggerRef.current || !pop) return;
3295
+ if (remeasure || !sizeRef.current) {
3296
+ sizeRef.current = {
3297
+ w: pop.offsetWidth,
3298
+ h: Math.max(pop.offsetHeight, pop.scrollHeight)
3299
+ };
3300
+ }
3301
+ const { w: popW, h: popH } = sizeRef.current;
3302
+ const triggerRect = triggerRef.current.getBoundingClientRect();
3303
+ if (popH === 0 || popW === 0) {
3304
+ sizeRef.current = null;
3305
+ return;
3306
+ }
3307
+ const parentRect = scrollParentRef.current?.getBoundingClientRect();
3308
+ const clip = {
3309
+ top: Math.max(parentRect?.top ?? 0, 0),
3310
+ bottom: Math.min(parentRect?.bottom ?? window.innerHeight, window.innerHeight),
3311
+ left: Math.max(parentRect?.left ?? 0, 0),
3312
+ right: Math.min(parentRect?.right ?? window.innerWidth, window.innerWidth)
3313
+ };
3314
+ const first = !placedRef.current;
3315
+ if (first) pop.style.transition = "none";
3316
+ const { direction: next, top, left, over, maxHeight } = computePlacement(
3317
+ triggerRect,
3318
+ popW,
3319
+ popH,
3320
+ clip
3321
+ );
3322
+ pop.style.top = `${top + window.scrollY}px`;
3323
+ pop.style.left = `${left + window.scrollX}px`;
3324
+ pop.style.maxHeight = maxHeight === null ? "" : `${maxHeight}px`;
3325
+ pop.style.clipPath = over.top || over.right || over.bottom || over.left ? `inset(${over.top}px ${over.right}px ${over.bottom}px ${over.left}px)` : "none";
3326
+ directionRef.current = next;
3327
+ pop.classList.toggle("top", next === "top");
3328
+ pop.classList.toggle("bottom", next === "bottom");
3329
+ if (first) {
3330
+ void pop.offsetHeight;
3331
+ pop.style.transition = "";
3332
+ placedRef.current = true;
3333
+ }
3334
+ }, [triggerRef, popRef]);
3335
+ import_react10.default.useLayoutEffect(() => {
3336
+ if (!enabled) {
3337
+ sizeRef.current = null;
3338
+ scrollParentRef.current = null;
3339
+ placedRef.current = false;
3340
+ return;
3341
+ }
3342
+ if (triggerRef.current) {
3343
+ scrollParentRef.current = findScrollParent(triggerRef.current);
3344
+ }
3345
+ calculatePosition(true);
3346
+ const raf = requestAnimationFrame(() => calculatePosition(true));
3347
+ return () => cancelAnimationFrame(raf);
3348
+ }, [calculatePosition, enabled, triggerRef]);
3349
+ import_react10.default.useEffect(() => {
3350
+ if (!enabled || !popRef.current) return;
3351
+ const observer = new ResizeObserver(() => {
3352
+ calculatePosition(true);
3353
+ });
3354
+ observer.observe(popRef.current);
3355
+ return () => observer.disconnect();
3356
+ }, [calculatePosition, enabled, popRef]);
3357
+ import_react10.default.useEffect(() => {
3358
+ if (!enabled) return;
3359
+ const onScroll = () => calculatePosition();
3360
+ const onResize = () => calculatePosition(true);
3361
+ window.addEventListener("resize", onResize, { passive: true });
3362
+ window.addEventListener("scroll", onScroll, { passive: true, capture: true });
3363
+ return () => {
3364
+ window.removeEventListener("resize", onResize);
3365
+ window.removeEventListener("scroll", onScroll, true);
3366
+ };
3367
+ }, [calculatePosition, enabled]);
3368
+ };
3369
+ var useAutoPosition_default = useAutoPosition;
3370
+
3371
+ // src/tokens/hooks/useOverlayKeyboard.ts
3234
3372
  var FOCUSABLE = [
3235
3373
  "a[href]",
3236
3374
  "button:not([disabled])",
@@ -3244,7 +3382,7 @@ var focusableIn = (el) => Array.from(el.querySelectorAll(FOCUSABLE)).filter(
3244
3382
  (n) => n.offsetWidth > 0 || n.offsetHeight > 0 || n === document.activeElement
3245
3383
  );
3246
3384
  var useEscapeKey = (enabled, onEscape) => {
3247
- import_react10.default.useEffect(() => {
3385
+ import_react11.default.useEffect(() => {
3248
3386
  if (!enabled) return;
3249
3387
  const onKey = (e) => {
3250
3388
  if (e.key !== "Escape") return;
@@ -3258,8 +3396,8 @@ var useEscapeKey = (enabled, onEscape) => {
3258
3396
  };
3259
3397
  var useFocusTrap = (containerRef, enabled, options = {}) => {
3260
3398
  const { trap = false, initialFocus } = options;
3261
- const restoreRef = import_react10.default.useRef(null);
3262
- import_react10.default.useEffect(() => {
3399
+ const restoreRef = import_react11.default.useRef(null);
3400
+ import_react11.default.useEffect(() => {
3263
3401
  if (!enabled) return;
3264
3402
  restoreRef.current = document.activeElement;
3265
3403
  const raf = requestAnimationFrame(() => {
@@ -3277,7 +3415,7 @@ var useFocusTrap = (containerRef, enabled, options = {}) => {
3277
3415
  if (prev && document.contains(prev)) prev.focus({ preventScroll: true });
3278
3416
  };
3279
3417
  }, [enabled, containerRef, initialFocus]);
3280
- import_react10.default.useEffect(() => {
3418
+ import_react11.default.useEffect(() => {
3281
3419
  if (!enabled || !trap) return;
3282
3420
  const onKey = (e) => {
3283
3421
  if (e.key !== "Tab") return;
@@ -3303,22 +3441,25 @@ var useFocusTrap = (containerRef, enabled, options = {}) => {
3303
3441
  return () => document.removeEventListener("keydown", onKey);
3304
3442
  }, [enabled, trap, containerRef]);
3305
3443
  };
3306
- var useCloseOnContainerScroll = (enabled, popRef, onClose) => {
3307
- const onCloseRef = import_react10.default.useRef(onClose);
3444
+ var useCloseWhenFocusHidden = (enabled, triggerRef, popRef, onClose) => {
3445
+ const onCloseRef = import_react11.default.useRef(onClose);
3308
3446
  onCloseRef.current = onClose;
3309
- import_react10.default.useEffect(() => {
3310
- if (!enabled) return;
3311
- const onScroll = (e) => {
3312
- const target = e.target;
3313
- if (target === document || target === document.documentElement || target === document.body) {
3314
- return;
3315
- }
3316
- if (target instanceof Node && popRef.current?.contains(target)) return;
3317
- onCloseRef.current();
3318
- };
3319
- window.addEventListener("scroll", onScroll, { passive: true, capture: true });
3320
- return () => window.removeEventListener("scroll", onScroll, true);
3321
- }, [enabled, popRef]);
3447
+ import_react11.default.useEffect(() => {
3448
+ const trigger = triggerRef.current;
3449
+ if (!enabled || !trigger) return;
3450
+ const observer = new IntersectionObserver(
3451
+ ([entry]) => {
3452
+ if (entry.isIntersecting) return;
3453
+ if (!popRef.current?.contains(document.activeElement)) return;
3454
+ onCloseRef.current();
3455
+ trigger.focus({ preventScroll: true });
3456
+ },
3457
+ // 그릇이 없으면 root: null → 뷰포트 기준
3458
+ { root: findScrollParent(trigger), threshold: 0 }
3459
+ );
3460
+ observer.observe(trigger);
3461
+ return () => observer.disconnect();
3462
+ }, [enabled, triggerRef, popRef]);
3322
3463
  };
3323
3464
 
3324
3465
  // src/components/Modal/Modal.tsx
@@ -3326,13 +3467,13 @@ var import_jsx_runtime313 = require("react/jsx-runtime");
3326
3467
  var ANIMATION_DURATION_MS = 200;
3327
3468
  var Modal = (props) => {
3328
3469
  const { isOpen, onClose, children } = props;
3329
- const [mounted, setMounted] = import_react11.default.useState(false);
3330
- const [visible, setVisible] = import_react11.default.useState(false);
3331
- const [settled, setSettled] = import_react11.default.useState(false);
3332
- const boxRef = import_react11.default.useRef(null);
3470
+ const [mounted, setMounted] = import_react12.default.useState(false);
3471
+ const [visible, setVisible] = import_react12.default.useState(false);
3472
+ const [settled, setSettled] = import_react12.default.useState(false);
3473
+ const boxRef = import_react12.default.useRef(null);
3333
3474
  useEscapeKey(isOpen, onClose);
3334
3475
  useFocusTrap(boxRef, isOpen && mounted, { trap: true });
3335
- import_react11.default.useEffect(() => {
3476
+ import_react12.default.useEffect(() => {
3336
3477
  if (isOpen) {
3337
3478
  setMounted(true);
3338
3479
  const show = setTimeout(() => setVisible(true), 1);
@@ -3376,9 +3517,9 @@ Modal.displayName = "Modal";
3376
3517
  var Modal_default = Modal;
3377
3518
 
3378
3519
  // src/components/DatePicker/SingleDatePicker/index.tsx
3379
- var import_react12 = __toESM(require("react"), 1);
3520
+ var import_react13 = __toESM(require("react"), 1);
3380
3521
  var import_jsx_runtime314 = require("react/jsx-runtime");
3381
- var DayCell2 = import_react12.default.memo(
3522
+ var DayCell2 = import_react13.default.memo(
3382
3523
  ({
3383
3524
  day,
3384
3525
  disabled,
@@ -3427,33 +3568,33 @@ var SingleDatePicker = (props) => {
3427
3568
  required,
3428
3569
  validations
3429
3570
  } = props;
3430
- const labelId = import_react12.default.useId();
3571
+ const labelId = import_react13.default.useId();
3431
3572
  const initialYear = value?.getFullYear();
3432
3573
  const initialMonth = value?.getMonth();
3433
3574
  const { year, month, days, goToPrevMonth, goToNextMonth, setYear, setMonth } = useCalendar(
3434
3575
  initialYear,
3435
3576
  initialMonth
3436
3577
  );
3437
- const [pickerMode, setPickerMode] = import_react12.default.useState("days");
3438
- const [yearRangeStart, setYearRangeStart] = import_react12.default.useState(
3578
+ const [pickerMode, setPickerMode] = import_react13.default.useState("days");
3579
+ const [yearRangeStart, setYearRangeStart] = import_react13.default.useState(
3439
3580
  Math.floor((initialYear ?? (/* @__PURE__ */ new Date()).getFullYear()) / 12) * 12
3440
3581
  );
3441
- const minTime = import_react12.default.useMemo(
3582
+ const minTime = import_react13.default.useMemo(
3442
3583
  () => minDate ? new Date(minDate.getFullYear(), minDate.getMonth(), minDate.getDate()).getTime() : -Infinity,
3443
3584
  [minDate]
3444
3585
  );
3445
- const maxTime = import_react12.default.useMemo(
3586
+ const maxTime = import_react13.default.useMemo(
3446
3587
  () => maxDate ? new Date(maxDate.getFullYear(), maxDate.getMonth(), maxDate.getDate()).getTime() : Infinity,
3447
3588
  [maxDate]
3448
3589
  );
3449
- const highlightSet = import_react12.default.useMemo(() => {
3590
+ const highlightSet = import_react13.default.useMemo(() => {
3450
3591
  const set = /* @__PURE__ */ new Set();
3451
3592
  for (const h of highlightDates) {
3452
3593
  set.add(`${h.getFullYear()}-${h.getMonth()}-${h.getDate()}`);
3453
3594
  }
3454
3595
  return set;
3455
3596
  }, [highlightDates]);
3456
- const handleSelect = import_react12.default.useCallback(
3597
+ const handleSelect = import_react13.default.useCallback(
3457
3598
  (date) => {
3458
3599
  onChange?.(date);
3459
3600
  },
@@ -3596,8 +3737,8 @@ var InputDatePicker = (props) => {
3596
3737
  required,
3597
3738
  validations
3598
3739
  } = props;
3599
- const [isOpen, setIsOpen] = import_react13.default.useState(false);
3600
- const [tempDate, setTempDate] = import_react13.default.useState(value ?? /* @__PURE__ */ new Date());
3740
+ const [isOpen, setIsOpen] = import_react14.default.useState(false);
3741
+ const [tempDate, setTempDate] = import_react14.default.useState(value ?? /* @__PURE__ */ new Date());
3601
3742
  const handleOpen = () => {
3602
3743
  if (disabled) return;
3603
3744
  setTempDate(value ?? /* @__PURE__ */ new Date());
@@ -3649,18 +3790,18 @@ InputDatePicker.displayName = "InputDatePicker";
3649
3790
  var InputDatePicker_default = InputDatePicker;
3650
3791
 
3651
3792
  // src/components/DatePicker/PopupPicker/index.tsx
3652
- var import_react17 = __toESM(require("react"), 1);
3793
+ var import_react18 = __toESM(require("react"), 1);
3653
3794
 
3654
3795
  // src/components/DatePicker/RangePicker/index.tsx
3655
- var import_react16 = __toESM(require("react"), 1);
3796
+ var import_react17 = __toESM(require("react"), 1);
3656
3797
 
3657
3798
  // src/components/Tab/Tab.tsx
3658
- var import_react15 = __toESM(require("react"), 1);
3799
+ var import_react16 = __toESM(require("react"), 1);
3659
3800
 
3660
3801
  // src/components/Tab/TabItem.tsx
3661
- var import_react14 = __toESM(require("react"), 1);
3802
+ var import_react15 = __toESM(require("react"), 1);
3662
3803
  var import_jsx_runtime316 = require("react/jsx-runtime");
3663
- var TabItem = import_react14.default.forwardRef((props, ref) => {
3804
+ var TabItem = import_react15.default.forwardRef((props, ref) => {
3664
3805
  const { isActive: isActive2, title, onClick } = props;
3665
3806
  return /* @__PURE__ */ (0, import_jsx_runtime316.jsx)(
3666
3807
  "button",
@@ -3684,11 +3825,11 @@ var import_jsx_runtime317 = require("react/jsx-runtime");
3684
3825
  var Tab = (props) => {
3685
3826
  const { activeIndex, onChange, tabs, variant, type, size = "md" } = props;
3686
3827
  const shape = variant ?? type ?? "default";
3687
- const [underlineStyle, setUnderlineStyle] = import_react15.default.useState({
3828
+ const [underlineStyle, setUnderlineStyle] = import_react16.default.useState({
3688
3829
  left: 0,
3689
3830
  width: 0
3690
3831
  });
3691
- const itemRefs = import_react15.default.useRef([]);
3832
+ const itemRefs = import_react16.default.useRef([]);
3692
3833
  const handleKeyDown = (e) => {
3693
3834
  const last = tabs.length - 1;
3694
3835
  let next = null;
@@ -3704,7 +3845,7 @@ var Tab = (props) => {
3704
3845
  const handleChangeActiveTab = (tabItem, tabIdx) => {
3705
3846
  onChange(tabItem, tabIdx);
3706
3847
  };
3707
- import_react15.default.useEffect(() => {
3848
+ import_react16.default.useEffect(() => {
3708
3849
  const el = itemRefs.current[activeIndex];
3709
3850
  if (el) {
3710
3851
  setUnderlineStyle({ left: el.offsetLeft, width: el.offsetWidth });
@@ -3760,8 +3901,8 @@ var RangePicker = (props) => {
3760
3901
  required,
3761
3902
  validations
3762
3903
  } = props;
3763
- const labelId = import_react16.default.useId();
3764
- const [activeTab, setActiveTab] = import_react16.default.useState("start");
3904
+ const labelId = import_react17.default.useId();
3905
+ const [activeTab, setActiveTab] = import_react17.default.useState("start");
3765
3906
  const handleStartChange = (date) => {
3766
3907
  if (!date) return;
3767
3908
  const newStart = date > endDate ? endDate : date;
@@ -3855,7 +3996,7 @@ var RangePicker_default = RangePicker;
3855
3996
  var import_jsx_runtime319 = require("react/jsx-runtime");
3856
3997
  var PopupPicker = (props) => {
3857
3998
  const { component, type, locale } = props;
3858
- const [isOpen, setIsOpen] = import_react17.default.useState(false);
3999
+ const [isOpen, setIsOpen] = import_react18.default.useState(false);
3859
4000
  const handleClick = () => setIsOpen(true);
3860
4001
  const handleClose = () => setIsOpen(false);
3861
4002
  const handleSingleChange = (date) => {
@@ -3864,7 +4005,7 @@ var PopupPicker = (props) => {
3864
4005
  handleClose();
3865
4006
  };
3866
4007
  return /* @__PURE__ */ (0, import_jsx_runtime319.jsxs)("div", { className: "lib-xplat-popup-datepicker", children: [
3867
- import_react17.default.cloneElement(component, { onClick: handleClick }),
4008
+ import_react18.default.cloneElement(component, { onClick: handleClick }),
3868
4009
  /* @__PURE__ */ (0, import_jsx_runtime319.jsx)(Modal_default, { isOpen, onClose: handleClose, children: /* @__PURE__ */ (0, import_jsx_runtime319.jsxs)("div", { className: clsx_default("lib-xplat-popup-datepicker-card", type === "range" && "range-mode"), children: [
3869
4010
  /* @__PURE__ */ (0, import_jsx_runtime319.jsxs)("div", { className: "popup-datepicker-content", children: [
3870
4011
  type === "single" && /* @__PURE__ */ (0, import_jsx_runtime319.jsx)(
@@ -3923,18 +4064,18 @@ Divider.displayName = "Divider";
3923
4064
  var Divider_default = Divider;
3924
4065
 
3925
4066
  // src/components/Drawer/Drawer.tsx
3926
- var import_react18 = __toESM(require("react"), 1);
4067
+ var import_react19 = __toESM(require("react"), 1);
3927
4068
  var import_react_dom2 = require("react-dom");
3928
4069
  var import_jsx_runtime321 = require("react/jsx-runtime");
3929
4070
  var ANIMATION_DURATION_MS2 = 250;
3930
4071
  var Drawer = (props) => {
3931
4072
  const { isOpen, onClose, placement = "right", size = "md", title, children } = props;
3932
- const [mounted, setMounted] = import_react18.default.useState(false);
3933
- const [visible, setVisible] = import_react18.default.useState(false);
3934
- const panelRef = import_react18.default.useRef(null);
4073
+ const [mounted, setMounted] = import_react19.default.useState(false);
4074
+ const [visible, setVisible] = import_react19.default.useState(false);
4075
+ const panelRef = import_react19.default.useRef(null);
3935
4076
  useEscapeKey(isOpen, onClose);
3936
4077
  useFocusTrap(panelRef, isOpen && mounted, { trap: true });
3937
- import_react18.default.useEffect(() => {
4078
+ import_react19.default.useEffect(() => {
3938
4079
  if (isOpen) {
3939
4080
  setMounted(true);
3940
4081
  const t2 = setTimeout(() => setVisible(true), 1);
@@ -3990,142 +4131,6 @@ var Portal = ({ children }) => {
3990
4131
  Portal.displayName = "Portal";
3991
4132
  var Portal_default = Portal;
3992
4133
 
3993
- // src/tokens/hooks/useAutoPosition.ts
3994
- var import_react19 = __toESM(require("react"), 1);
3995
- var findScrollParent = (el) => {
3996
- for (let p = el.parentElement; p; p = p.parentElement) {
3997
- const { overflowY, overflowX } = getComputedStyle(p);
3998
- if (/(auto|scroll)/.test(overflowY) || /(auto|scroll)/.test(overflowX)) return p;
3999
- }
4000
- return null;
4001
- };
4002
- var TRIGGER_GAP = 8;
4003
- var computePlacement = (triggerRect, popW, popH, clip) => {
4004
- const roomBelow = clip.bottom - triggerRect.bottom - TRIGGER_GAP;
4005
- const roomAbove = triggerRect.top - clip.top - TRIGGER_GAP;
4006
- let direction;
4007
- let top;
4008
- let maxHeight = null;
4009
- if (popH <= roomBelow) {
4010
- direction = "bottom";
4011
- top = triggerRect.bottom + TRIGGER_GAP;
4012
- } else if (popH <= roomAbove) {
4013
- direction = "top";
4014
- top = triggerRect.top - TRIGGER_GAP - popH;
4015
- } else {
4016
- const room = Math.max(roomBelow, roomAbove, 0);
4017
- if (roomBelow >= roomAbove) {
4018
- direction = "bottom";
4019
- top = triggerRect.bottom + TRIGGER_GAP;
4020
- } else {
4021
- direction = "top";
4022
- top = triggerRect.top - TRIGGER_GAP - room;
4023
- }
4024
- maxHeight = room;
4025
- }
4026
- let left = triggerRect.left;
4027
- if (left + popW > clip.right - 8) {
4028
- left = triggerRect.right - popW;
4029
- }
4030
- if (left < clip.left + 8) left = clip.left + 8;
4031
- const drawnH = maxHeight === null ? popH : Math.min(popH, maxHeight);
4032
- return {
4033
- direction,
4034
- top,
4035
- left,
4036
- maxHeight,
4037
- over: {
4038
- top: Math.max(0, clip.top - top),
4039
- right: Math.max(0, left + popW - clip.right),
4040
- bottom: Math.max(0, top + drawnH - clip.bottom),
4041
- left: Math.max(0, clip.left - left)
4042
- }
4043
- };
4044
- };
4045
- var useAutoPosition = (triggerRef, popRef, enabled = true) => {
4046
- const directionRef = import_react19.default.useRef("bottom");
4047
- const sizeRef = import_react19.default.useRef(null);
4048
- const scrollParentRef = import_react19.default.useRef(null);
4049
- const placedRef = import_react19.default.useRef(false);
4050
- const calculatePosition = import_react19.default.useCallback((remeasure = false) => {
4051
- const pop = popRef.current;
4052
- if (!triggerRef.current || !pop) return;
4053
- if (remeasure || !sizeRef.current) {
4054
- sizeRef.current = {
4055
- w: pop.offsetWidth,
4056
- h: Math.max(pop.offsetHeight, pop.scrollHeight)
4057
- };
4058
- }
4059
- const { w: popW, h: popH } = sizeRef.current;
4060
- const triggerRect = triggerRef.current.getBoundingClientRect();
4061
- if (popH === 0 || popW === 0) {
4062
- sizeRef.current = null;
4063
- return;
4064
- }
4065
- const parentRect = scrollParentRef.current?.getBoundingClientRect();
4066
- const clip = {
4067
- top: Math.max(parentRect?.top ?? 0, 0),
4068
- bottom: Math.min(parentRect?.bottom ?? window.innerHeight, window.innerHeight),
4069
- left: Math.max(parentRect?.left ?? 0, 0),
4070
- right: Math.min(parentRect?.right ?? window.innerWidth, window.innerWidth)
4071
- };
4072
- const first = !placedRef.current;
4073
- if (first) pop.style.transition = "none";
4074
- const { direction: next, top, left, over, maxHeight } = computePlacement(
4075
- triggerRect,
4076
- popW,
4077
- popH,
4078
- clip
4079
- );
4080
- pop.style.top = `${top + window.scrollY}px`;
4081
- pop.style.left = `${left + window.scrollX}px`;
4082
- pop.style.maxHeight = maxHeight === null ? "" : `${maxHeight}px`;
4083
- pop.style.clipPath = over.top || over.right || over.bottom || over.left ? `inset(${over.top}px ${over.right}px ${over.bottom}px ${over.left}px)` : "none";
4084
- directionRef.current = next;
4085
- pop.classList.toggle("top", next === "top");
4086
- pop.classList.toggle("bottom", next === "bottom");
4087
- if (first) {
4088
- void pop.offsetHeight;
4089
- pop.style.transition = "";
4090
- placedRef.current = true;
4091
- }
4092
- }, [triggerRef, popRef]);
4093
- import_react19.default.useLayoutEffect(() => {
4094
- if (!enabled) {
4095
- sizeRef.current = null;
4096
- scrollParentRef.current = null;
4097
- placedRef.current = false;
4098
- return;
4099
- }
4100
- if (triggerRef.current) {
4101
- scrollParentRef.current = findScrollParent(triggerRef.current);
4102
- }
4103
- calculatePosition(true);
4104
- const raf = requestAnimationFrame(() => calculatePosition(true));
4105
- return () => cancelAnimationFrame(raf);
4106
- }, [calculatePosition, enabled, triggerRef]);
4107
- import_react19.default.useEffect(() => {
4108
- if (!enabled || !popRef.current) return;
4109
- const observer = new ResizeObserver(() => {
4110
- calculatePosition(true);
4111
- });
4112
- observer.observe(popRef.current);
4113
- return () => observer.disconnect();
4114
- }, [calculatePosition, enabled, popRef]);
4115
- import_react19.default.useEffect(() => {
4116
- if (!enabled) return;
4117
- const onScroll = () => calculatePosition();
4118
- const onResize = () => calculatePosition(true);
4119
- window.addEventListener("resize", onResize, { passive: true });
4120
- window.addEventListener("scroll", onScroll, { passive: true, capture: true });
4121
- return () => {
4122
- window.removeEventListener("resize", onResize);
4123
- window.removeEventListener("scroll", onScroll, true);
4124
- };
4125
- }, [calculatePosition, enabled]);
4126
- };
4127
- var useAutoPosition_default = useAutoPosition;
4128
-
4129
4134
  // src/tokens/hooks/useClickOutside.ts
4130
4135
  var import_react20 = __toESM(require("react"), 1);
4131
4136
  var useClickOutside = (refs, handler, enabled = true) => {
@@ -4162,7 +4167,7 @@ var Dropdown = (props) => {
4162
4167
  const menuRef = import_react21.default.useRef(null);
4163
4168
  useAutoPosition_default(triggerRef, menuRef, mounted);
4164
4169
  useClickOutside_default([triggerRef, menuRef], () => setIsOpen(false), isOpen);
4165
- useCloseOnContainerScroll(isOpen, menuRef, () => setIsOpen(false));
4170
+ useCloseWhenFocusHidden(isOpen, triggerRef, menuRef, () => setIsOpen(false));
4166
4171
  useEscapeKey(isOpen, () => {
4167
4172
  setIsOpen(false);
4168
4173
  triggerRef.current?.focus({ preventScroll: true });
@@ -6093,7 +6098,7 @@ var PopOver = (props) => {
6093
6098
  const [localOpen, setLocalOpen] = import_react27.default.useState(false);
6094
6099
  const [eventTrigger, setEventTrigger] = import_react27.default.useState(false);
6095
6100
  useClickOutside_default([popRef, triggerRef], onClose, isOpen);
6096
- useCloseOnContainerScroll(isOpen, popRef, onClose);
6101
+ useCloseWhenFocusHidden(isOpen, triggerRef, popRef, onClose);
6097
6102
  useEscapeKey(isOpen, () => {
6098
6103
  onClose();
6099
6104
  triggerRef.current?.focus({ preventScroll: true });
@@ -6373,7 +6378,7 @@ var SelectRoot = (props) => {
6373
6378
  }, []);
6374
6379
  const toggle = import_react31.default.useCallback(() => setOpen((prev) => !prev), []);
6375
6380
  useClickOutside_default([contentRef, triggerRef], close, isOpen);
6376
- useCloseOnContainerScroll(isOpen, contentRef, close);
6381
+ useCloseWhenFocusHidden(isOpen, triggerRef, contentRef, close);
6377
6382
  useEscapeKey(isOpen, () => {
6378
6383
  close();
6379
6384
  triggerRef.current?.focus({ preventScroll: true });
@@ -7314,7 +7319,7 @@ var TimePicker = (props) => {
7314
7319
  }, [step, min, max]);
7315
7320
  const close = import_react40.default.useCallback(() => setOpen(false), []);
7316
7321
  useClickOutside_default([triggerRef, contentRef], close, isOpen);
7317
- useCloseOnContainerScroll(isOpen, contentRef, close);
7322
+ useCloseWhenFocusHidden(isOpen, triggerRef, contentRef, close);
7318
7323
  useEscapeKey(isOpen, () => {
7319
7324
  close();
7320
7325
  triggerRef.current?.focus({ preventScroll: true });