@x-plat/design-system 0.14.12 → 0.14.14

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.
package/dist/index.cjs CHANGED
@@ -8411,26 +8411,27 @@ var findScrollParent = (el) => {
8411
8411
  }
8412
8412
  return null;
8413
8413
  };
8414
+ var TRIGGER_GAP = 8;
8414
8415
  var computePlacement = (triggerRect, popW, popH, clip) => {
8415
- const roomBelow = clip.bottom - triggerRect.bottom;
8416
- const roomAbove = triggerRect.top - clip.top;
8416
+ const roomBelow = clip.bottom - triggerRect.bottom - TRIGGER_GAP;
8417
+ const roomAbove = triggerRect.top - clip.top - TRIGGER_GAP;
8417
8418
  let direction;
8418
8419
  let top;
8419
8420
  let maxHeight = null;
8420
8421
  if (popH <= roomBelow) {
8421
8422
  direction = "bottom";
8422
- top = triggerRect.bottom;
8423
+ top = triggerRect.bottom + TRIGGER_GAP;
8423
8424
  } else if (popH <= roomAbove) {
8424
8425
  direction = "top";
8425
- top = triggerRect.top - popH;
8426
+ top = triggerRect.top - TRIGGER_GAP - popH;
8426
8427
  } else {
8427
8428
  const room = Math.max(roomBelow, roomAbove, 0);
8428
8429
  if (roomBelow >= roomAbove) {
8429
8430
  direction = "bottom";
8430
- top = triggerRect.bottom;
8431
+ top = triggerRect.bottom + TRIGGER_GAP;
8431
8432
  } else {
8432
8433
  direction = "top";
8433
- top = triggerRect.top - room;
8434
+ top = triggerRect.top - TRIGGER_GAP - room;
8434
8435
  }
8435
8436
  maxHeight = room;
8436
8437
  }
@@ -8454,15 +8455,18 @@ var computePlacement = (triggerRect, popW, popH, clip) => {
8454
8455
  };
8455
8456
  };
8456
8457
  var useAutoPosition = (triggerRef, popRef, enabled = true) => {
8457
- const [direction, setDirection] = import_react19.default.useState("bottom");
8458
8458
  const directionRef = import_react19.default.useRef("bottom");
8459
8459
  const sizeRef = import_react19.default.useRef(null);
8460
8460
  const scrollParentRef = import_react19.default.useRef(null);
8461
+ const placedRef = import_react19.default.useRef(false);
8461
8462
  const calculatePosition = import_react19.default.useCallback((remeasure = false) => {
8462
8463
  const pop = popRef.current;
8463
8464
  if (!triggerRef.current || !pop) return;
8464
8465
  if (remeasure || !sizeRef.current) {
8465
- sizeRef.current = { w: pop.offsetWidth, h: pop.offsetHeight };
8466
+ sizeRef.current = {
8467
+ w: pop.offsetWidth,
8468
+ h: Math.max(pop.offsetHeight, pop.scrollHeight)
8469
+ };
8466
8470
  }
8467
8471
  const { w: popW, h: popH } = sizeRef.current;
8468
8472
  const triggerRect = triggerRef.current.getBoundingClientRect();
@@ -8477,6 +8481,8 @@ var useAutoPosition = (triggerRef, popRef, enabled = true) => {
8477
8481
  left: Math.max(parentRect?.left ?? 0, 0),
8478
8482
  right: Math.min(parentRect?.right ?? window.innerWidth, window.innerWidth)
8479
8483
  };
8484
+ const first = !placedRef.current;
8485
+ if (first) pop.style.transition = "none";
8480
8486
  const { direction: next, top, left, over, maxHeight } = computePlacement(
8481
8487
  triggerRect,
8482
8488
  popW,
@@ -8487,15 +8493,20 @@ var useAutoPosition = (triggerRef, popRef, enabled = true) => {
8487
8493
  pop.style.left = `${left + window.scrollX}px`;
8488
8494
  pop.style.maxHeight = maxHeight === null ? "" : `${maxHeight}px`;
8489
8495
  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";
8490
- if (next !== directionRef.current) {
8491
- directionRef.current = next;
8492
- setDirection(next);
8496
+ directionRef.current = next;
8497
+ pop.classList.toggle("top", next === "top");
8498
+ pop.classList.toggle("bottom", next === "bottom");
8499
+ if (first) {
8500
+ void pop.offsetHeight;
8501
+ pop.style.transition = "";
8502
+ placedRef.current = true;
8493
8503
  }
8494
8504
  }, [triggerRef, popRef]);
8495
8505
  import_react19.default.useLayoutEffect(() => {
8496
8506
  if (!enabled) {
8497
8507
  sizeRef.current = null;
8498
8508
  scrollParentRef.current = null;
8509
+ placedRef.current = false;
8499
8510
  return;
8500
8511
  }
8501
8512
  if (triggerRef.current) {
@@ -8524,7 +8535,6 @@ var useAutoPosition = (triggerRef, popRef, enabled = true) => {
8524
8535
  window.removeEventListener("scroll", onScroll, true);
8525
8536
  };
8526
8537
  }, [calculatePosition, enabled]);
8527
- return { direction };
8528
8538
  };
8529
8539
  var useAutoPosition_default = useAutoPosition;
8530
8540
 
@@ -8562,7 +8572,7 @@ var Dropdown = (props) => {
8562
8572
  const [visible, setVisible] = import_react21.default.useState(false);
8563
8573
  const triggerRef = import_react21.default.useRef(null);
8564
8574
  const menuRef = import_react21.default.useRef(null);
8565
- const { direction } = useAutoPosition_default(triggerRef, menuRef, mounted);
8575
+ useAutoPosition_default(triggerRef, menuRef, mounted);
8566
8576
  useClickOutside_default([triggerRef, menuRef], () => setIsOpen(false), isOpen);
8567
8577
  useCloseOnContainerScroll(isOpen, menuRef, () => setIsOpen(false));
8568
8578
  useEscapeKey(isOpen, () => {
@@ -8598,7 +8608,7 @@ var Dropdown = (props) => {
8598
8608
  "div",
8599
8609
  {
8600
8610
  ref: menuRef,
8601
- className: clsx_default("lib-xplat-dropdown-menu", direction, { visible }),
8611
+ className: clsx_default("lib-xplat-dropdown-menu", { visible }),
8602
8612
  role: "menu",
8603
8613
  children: items.map((item) => /* @__PURE__ */ (0, import_jsx_runtime322.jsx)(
8604
8614
  "button",
@@ -10500,7 +10510,7 @@ var PopOver = (props) => {
10500
10510
  onClose();
10501
10511
  triggerRef.current?.focus({ preventScroll: true });
10502
10512
  });
10503
- const position = useAutoPosition_default(triggerRef, popRef, localOpen);
10513
+ useAutoPosition_default(triggerRef, popRef, localOpen);
10504
10514
  import_react27.default.useEffect(() => {
10505
10515
  if (isOpen) {
10506
10516
  setLocalOpen(isOpen);
@@ -10529,7 +10539,6 @@ var PopOver = (props) => {
10529
10539
  {
10530
10540
  className: clsx_default(
10531
10541
  "lib-xplat-pop-over-content",
10532
- position.direction,
10533
10542
  eventTrigger && "visible"
10534
10543
  ),
10535
10544
  ref: popRef,
@@ -10781,7 +10790,7 @@ var SelectRoot = (props) => {
10781
10790
  close();
10782
10791
  triggerRef.current?.focus({ preventScroll: true });
10783
10792
  });
10784
- const position = useAutoPosition_default(triggerRef, contentRef, mounted);
10793
+ useAutoPosition_default(triggerRef, contentRef, mounted);
10785
10794
  const setSelected = import_react31.default.useCallback(
10786
10795
  (label2, itemValue) => {
10787
10796
  if (!isControlled) {
@@ -10874,7 +10883,7 @@ var SelectRoot = (props) => {
10874
10883
  mounted && /* @__PURE__ */ (0, import_jsx_runtime337.jsx)(Portal_default, { children: /* @__PURE__ */ (0, import_jsx_runtime337.jsxs)(
10875
10884
  "div",
10876
10885
  {
10877
- className: clsx_default("lib-xplat-select-content", size, position.direction, stateClass),
10886
+ className: clsx_default("lib-xplat-select-content", size, stateClass),
10878
10887
  ref: contentRef,
10879
10888
  style: { width: triggerRef.current?.offsetWidth },
10880
10889
  role: "listbox",
package/dist/index.css CHANGED
@@ -3282,11 +3282,11 @@
3282
3282
  box-shadow: var(--semantic-shadow-md);
3283
3283
  padding: var(--spacing-space-1) 0;
3284
3284
  opacity: 0;
3285
- transform: translateY(-4px);
3285
+ transform: translateY(4px);
3286
3286
  transition: opacity 0.15s ease, transform 0.15s ease;
3287
3287
  }
3288
3288
  .lib-xplat-dropdown-menu.bottom {
3289
- transform: translateY(4px);
3289
+ transform: translateY(-4px);
3290
3290
  }
3291
3291
  .lib-xplat-dropdown-menu.visible {
3292
3292
  opacity: 1;
@@ -4513,7 +4513,7 @@
4513
4513
  transition: transform 0.2s ease, opacity 0.2s ease;
4514
4514
  }
4515
4515
  .lib-xplat-select-content.bottom {
4516
- transform: translateY(8px);
4516
+ transform: translateY(-4px);
4517
4517
  }
4518
4518
  .lib-xplat-select-content.bottom.visible {
4519
4519
  opacity: 1;
@@ -4521,12 +4521,12 @@
4521
4521
  }
4522
4522
  .lib-xplat-select-content.bottom.exit {
4523
4523
  opacity: 0;
4524
- transform: translateY(8px);
4524
+ transform: translateY(-4px);
4525
4525
  }
4526
4526
  .lib-xplat-select-content {
4527
4527
  }
4528
4528
  .lib-xplat-select-content.top {
4529
- transform: translateY(-8px);
4529
+ transform: translateY(4px);
4530
4530
  }
4531
4531
  .lib-xplat-select-content.top.visible {
4532
4532
  opacity: 1;
@@ -4534,7 +4534,7 @@
4534
4534
  }
4535
4535
  .lib-xplat-select-content.top.exit {
4536
4536
  opacity: 0;
4537
- transform: translateY(-8px);
4537
+ transform: translateY(4px);
4538
4538
  }
4539
4539
  .lib-xplat-select-content.sm .select-item {
4540
4540
  padding: var(--spacing-space-2) var(--spacing-space-2);
package/dist/index.js CHANGED
@@ -8000,26 +8000,27 @@ var findScrollParent = (el) => {
8000
8000
  }
8001
8001
  return null;
8002
8002
  };
8003
+ var TRIGGER_GAP = 8;
8003
8004
  var computePlacement = (triggerRect, popW, popH, clip) => {
8004
- const roomBelow = clip.bottom - triggerRect.bottom;
8005
- const roomAbove = triggerRect.top - clip.top;
8005
+ const roomBelow = clip.bottom - triggerRect.bottom - TRIGGER_GAP;
8006
+ const roomAbove = triggerRect.top - clip.top - TRIGGER_GAP;
8006
8007
  let direction;
8007
8008
  let top;
8008
8009
  let maxHeight = null;
8009
8010
  if (popH <= roomBelow) {
8010
8011
  direction = "bottom";
8011
- top = triggerRect.bottom;
8012
+ top = triggerRect.bottom + TRIGGER_GAP;
8012
8013
  } else if (popH <= roomAbove) {
8013
8014
  direction = "top";
8014
- top = triggerRect.top - popH;
8015
+ top = triggerRect.top - TRIGGER_GAP - popH;
8015
8016
  } else {
8016
8017
  const room = Math.max(roomBelow, roomAbove, 0);
8017
8018
  if (roomBelow >= roomAbove) {
8018
8019
  direction = "bottom";
8019
- top = triggerRect.bottom;
8020
+ top = triggerRect.bottom + TRIGGER_GAP;
8020
8021
  } else {
8021
8022
  direction = "top";
8022
- top = triggerRect.top - room;
8023
+ top = triggerRect.top - TRIGGER_GAP - room;
8023
8024
  }
8024
8025
  maxHeight = room;
8025
8026
  }
@@ -8043,15 +8044,18 @@ var computePlacement = (triggerRect, popW, popH, clip) => {
8043
8044
  };
8044
8045
  };
8045
8046
  var useAutoPosition = (triggerRef, popRef, enabled = true) => {
8046
- const [direction, setDirection] = React19.useState("bottom");
8047
8047
  const directionRef = React19.useRef("bottom");
8048
8048
  const sizeRef = React19.useRef(null);
8049
8049
  const scrollParentRef = React19.useRef(null);
8050
+ const placedRef = React19.useRef(false);
8050
8051
  const calculatePosition = React19.useCallback((remeasure = false) => {
8051
8052
  const pop = popRef.current;
8052
8053
  if (!triggerRef.current || !pop) return;
8053
8054
  if (remeasure || !sizeRef.current) {
8054
- sizeRef.current = { w: pop.offsetWidth, h: pop.offsetHeight };
8055
+ sizeRef.current = {
8056
+ w: pop.offsetWidth,
8057
+ h: Math.max(pop.offsetHeight, pop.scrollHeight)
8058
+ };
8055
8059
  }
8056
8060
  const { w: popW, h: popH } = sizeRef.current;
8057
8061
  const triggerRect = triggerRef.current.getBoundingClientRect();
@@ -8066,6 +8070,8 @@ var useAutoPosition = (triggerRef, popRef, enabled = true) => {
8066
8070
  left: Math.max(parentRect?.left ?? 0, 0),
8067
8071
  right: Math.min(parentRect?.right ?? window.innerWidth, window.innerWidth)
8068
8072
  };
8073
+ const first = !placedRef.current;
8074
+ if (first) pop.style.transition = "none";
8069
8075
  const { direction: next, top, left, over, maxHeight } = computePlacement(
8070
8076
  triggerRect,
8071
8077
  popW,
@@ -8076,15 +8082,20 @@ var useAutoPosition = (triggerRef, popRef, enabled = true) => {
8076
8082
  pop.style.left = `${left + window.scrollX}px`;
8077
8083
  pop.style.maxHeight = maxHeight === null ? "" : `${maxHeight}px`;
8078
8084
  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";
8079
- if (next !== directionRef.current) {
8080
- directionRef.current = next;
8081
- setDirection(next);
8085
+ directionRef.current = next;
8086
+ pop.classList.toggle("top", next === "top");
8087
+ pop.classList.toggle("bottom", next === "bottom");
8088
+ if (first) {
8089
+ void pop.offsetHeight;
8090
+ pop.style.transition = "";
8091
+ placedRef.current = true;
8082
8092
  }
8083
8093
  }, [triggerRef, popRef]);
8084
8094
  React19.useLayoutEffect(() => {
8085
8095
  if (!enabled) {
8086
8096
  sizeRef.current = null;
8087
8097
  scrollParentRef.current = null;
8098
+ placedRef.current = false;
8088
8099
  return;
8089
8100
  }
8090
8101
  if (triggerRef.current) {
@@ -8113,7 +8124,6 @@ var useAutoPosition = (triggerRef, popRef, enabled = true) => {
8113
8124
  window.removeEventListener("scroll", onScroll, true);
8114
8125
  };
8115
8126
  }, [calculatePosition, enabled]);
8116
- return { direction };
8117
8127
  };
8118
8128
  var useAutoPosition_default = useAutoPosition;
8119
8129
 
@@ -8151,7 +8161,7 @@ var Dropdown = (props) => {
8151
8161
  const [visible, setVisible] = React21.useState(false);
8152
8162
  const triggerRef = React21.useRef(null);
8153
8163
  const menuRef = React21.useRef(null);
8154
- const { direction } = useAutoPosition_default(triggerRef, menuRef, mounted);
8164
+ useAutoPosition_default(triggerRef, menuRef, mounted);
8155
8165
  useClickOutside_default([triggerRef, menuRef], () => setIsOpen(false), isOpen);
8156
8166
  useCloseOnContainerScroll(isOpen, menuRef, () => setIsOpen(false));
8157
8167
  useEscapeKey(isOpen, () => {
@@ -8187,7 +8197,7 @@ var Dropdown = (props) => {
8187
8197
  "div",
8188
8198
  {
8189
8199
  ref: menuRef,
8190
- className: clsx_default("lib-xplat-dropdown-menu", direction, { visible }),
8200
+ className: clsx_default("lib-xplat-dropdown-menu", { visible }),
8191
8201
  role: "menu",
8192
8202
  children: items.map((item) => /* @__PURE__ */ jsx322(
8193
8203
  "button",
@@ -10089,7 +10099,7 @@ var PopOver = (props) => {
10089
10099
  onClose();
10090
10100
  triggerRef.current?.focus({ preventScroll: true });
10091
10101
  });
10092
- const position = useAutoPosition_default(triggerRef, popRef, localOpen);
10102
+ useAutoPosition_default(triggerRef, popRef, localOpen);
10093
10103
  React27.useEffect(() => {
10094
10104
  if (isOpen) {
10095
10105
  setLocalOpen(isOpen);
@@ -10118,7 +10128,6 @@ var PopOver = (props) => {
10118
10128
  {
10119
10129
  className: clsx_default(
10120
10130
  "lib-xplat-pop-over-content",
10121
- position.direction,
10122
10131
  eventTrigger && "visible"
10123
10132
  ),
10124
10133
  ref: popRef,
@@ -10370,7 +10379,7 @@ var SelectRoot = (props) => {
10370
10379
  close();
10371
10380
  triggerRef.current?.focus({ preventScroll: true });
10372
10381
  });
10373
- const position = useAutoPosition_default(triggerRef, contentRef, mounted);
10382
+ useAutoPosition_default(triggerRef, contentRef, mounted);
10374
10383
  const setSelected = React31.useCallback(
10375
10384
  (label2, itemValue) => {
10376
10385
  if (!isControlled) {
@@ -10463,7 +10472,7 @@ var SelectRoot = (props) => {
10463
10472
  mounted && /* @__PURE__ */ jsx337(Portal_default, { children: /* @__PURE__ */ jsxs216(
10464
10473
  "div",
10465
10474
  {
10466
- className: clsx_default("lib-xplat-select-content", size, position.direction, stateClass),
10475
+ className: clsx_default("lib-xplat-select-content", size, stateClass),
10467
10476
  ref: contentRef,
10468
10477
  style: { width: triggerRef.current?.offsetWidth },
10469
10478
  role: "listbox",
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@x-plat/design-system",
3
- "version": "0.14.12",
3
+ "version": "0.14.14",
4
4
  "description": "XPLAT UI Design System",
5
5
  "author": "XPLAT WOONG",
6
6
  "main": "dist/index.cjs",