@x-plat/design-system 0.14.13 → 0.14.15
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/components/DatePicker/index.cjs +46 -41
- package/dist/components/DatePicker/index.js +46 -41
- package/dist/components/Drawer/index.cjs +14 -9
- package/dist/components/Drawer/index.js +14 -9
- package/dist/components/Dropdown/index.cjs +21 -20
- package/dist/components/Dropdown/index.css +2 -2
- package/dist/components/Dropdown/index.js +21 -20
- package/dist/components/Modal/index.cjs +15 -10
- package/dist/components/Modal/index.js +15 -10
- package/dist/components/PopOver/index.cjs +21 -20
- package/dist/components/PopOver/index.js +21 -20
- package/dist/components/Select/index.cjs +21 -20
- package/dist/components/Select/index.css +4 -4
- package/dist/components/Select/index.js +21 -20
- package/dist/components/TimePicker/index.cjs +21 -20
- package/dist/components/TimePicker/index.js +21 -20
- package/dist/components/index.cjs +196 -193
- package/dist/components/index.css +6 -6
- package/dist/components/index.js +196 -193
- package/dist/index.cjs +196 -193
- package/dist/index.css +6 -6
- package/dist/index.js +196 -193
- package/guidelines/MIGRATION.md +28 -30
- package/package.json +1 -1
package/dist/index.js
CHANGED
|
@@ -7054,7 +7054,7 @@ Chip.displayName = "Chip";
|
|
|
7054
7054
|
var Chip_default = Chip;
|
|
7055
7055
|
|
|
7056
7056
|
// src/components/DatePicker/InputDatePicker/index.tsx
|
|
7057
|
-
import
|
|
7057
|
+
import React14 from "react";
|
|
7058
7058
|
|
|
7059
7059
|
// src/components/Input/Input.tsx
|
|
7060
7060
|
import React8 from "react";
|
|
@@ -7227,11 +7227,149 @@ PasswordInput.displayName = "PasswordInput";
|
|
|
7227
7227
|
var PasswordInput_default = PasswordInput;
|
|
7228
7228
|
|
|
7229
7229
|
// src/components/Modal/Modal.tsx
|
|
7230
|
-
import
|
|
7230
|
+
import React12 from "react";
|
|
7231
7231
|
import { createPortal } from "react-dom";
|
|
7232
7232
|
|
|
7233
7233
|
// src/tokens/hooks/useOverlayKeyboard.ts
|
|
7234
|
+
import React11 from "react";
|
|
7235
|
+
|
|
7236
|
+
// src/tokens/hooks/useAutoPosition.ts
|
|
7234
7237
|
import React10 from "react";
|
|
7238
|
+
var findScrollParent = (el) => {
|
|
7239
|
+
for (let p = el.parentElement; p; p = p.parentElement) {
|
|
7240
|
+
const { overflowY, overflowX } = getComputedStyle(p);
|
|
7241
|
+
if (/(auto|scroll)/.test(overflowY) || /(auto|scroll)/.test(overflowX)) return p;
|
|
7242
|
+
}
|
|
7243
|
+
return null;
|
|
7244
|
+
};
|
|
7245
|
+
var TRIGGER_GAP = 8;
|
|
7246
|
+
var computePlacement = (triggerRect, popW, popH, clip) => {
|
|
7247
|
+
const roomBelow = clip.bottom - triggerRect.bottom - TRIGGER_GAP;
|
|
7248
|
+
const roomAbove = triggerRect.top - clip.top - TRIGGER_GAP;
|
|
7249
|
+
let direction;
|
|
7250
|
+
let top;
|
|
7251
|
+
let maxHeight = null;
|
|
7252
|
+
if (popH <= roomBelow) {
|
|
7253
|
+
direction = "bottom";
|
|
7254
|
+
top = triggerRect.bottom + TRIGGER_GAP;
|
|
7255
|
+
} else if (popH <= roomAbove) {
|
|
7256
|
+
direction = "top";
|
|
7257
|
+
top = triggerRect.top - TRIGGER_GAP - popH;
|
|
7258
|
+
} else {
|
|
7259
|
+
const room = Math.max(roomBelow, roomAbove, 0);
|
|
7260
|
+
if (roomBelow >= roomAbove) {
|
|
7261
|
+
direction = "bottom";
|
|
7262
|
+
top = triggerRect.bottom + TRIGGER_GAP;
|
|
7263
|
+
} else {
|
|
7264
|
+
direction = "top";
|
|
7265
|
+
top = triggerRect.top - TRIGGER_GAP - room;
|
|
7266
|
+
}
|
|
7267
|
+
maxHeight = room;
|
|
7268
|
+
}
|
|
7269
|
+
let left = triggerRect.left;
|
|
7270
|
+
if (left + popW > clip.right - 8) {
|
|
7271
|
+
left = triggerRect.right - popW;
|
|
7272
|
+
}
|
|
7273
|
+
if (left < clip.left + 8) left = clip.left + 8;
|
|
7274
|
+
const drawnH = maxHeight === null ? popH : Math.min(popH, maxHeight);
|
|
7275
|
+
return {
|
|
7276
|
+
direction,
|
|
7277
|
+
top,
|
|
7278
|
+
left,
|
|
7279
|
+
maxHeight,
|
|
7280
|
+
over: {
|
|
7281
|
+
top: Math.max(0, clip.top - top),
|
|
7282
|
+
right: Math.max(0, left + popW - clip.right),
|
|
7283
|
+
bottom: Math.max(0, top + drawnH - clip.bottom),
|
|
7284
|
+
left: Math.max(0, clip.left - left)
|
|
7285
|
+
}
|
|
7286
|
+
};
|
|
7287
|
+
};
|
|
7288
|
+
var useAutoPosition = (triggerRef, popRef, enabled = true) => {
|
|
7289
|
+
const directionRef = React10.useRef("bottom");
|
|
7290
|
+
const sizeRef = React10.useRef(null);
|
|
7291
|
+
const scrollParentRef = React10.useRef(null);
|
|
7292
|
+
const placedRef = React10.useRef(false);
|
|
7293
|
+
const calculatePosition = React10.useCallback((remeasure = false) => {
|
|
7294
|
+
const pop = popRef.current;
|
|
7295
|
+
if (!triggerRef.current || !pop) return;
|
|
7296
|
+
if (remeasure || !sizeRef.current) {
|
|
7297
|
+
sizeRef.current = {
|
|
7298
|
+
w: pop.offsetWidth,
|
|
7299
|
+
h: Math.max(pop.offsetHeight, pop.scrollHeight)
|
|
7300
|
+
};
|
|
7301
|
+
}
|
|
7302
|
+
const { w: popW, h: popH } = sizeRef.current;
|
|
7303
|
+
const triggerRect = triggerRef.current.getBoundingClientRect();
|
|
7304
|
+
if (popH === 0 || popW === 0) {
|
|
7305
|
+
sizeRef.current = null;
|
|
7306
|
+
return;
|
|
7307
|
+
}
|
|
7308
|
+
const parentRect = scrollParentRef.current?.getBoundingClientRect();
|
|
7309
|
+
const clip = {
|
|
7310
|
+
top: Math.max(parentRect?.top ?? 0, 0),
|
|
7311
|
+
bottom: Math.min(parentRect?.bottom ?? window.innerHeight, window.innerHeight),
|
|
7312
|
+
left: Math.max(parentRect?.left ?? 0, 0),
|
|
7313
|
+
right: Math.min(parentRect?.right ?? window.innerWidth, window.innerWidth)
|
|
7314
|
+
};
|
|
7315
|
+
const first = !placedRef.current;
|
|
7316
|
+
if (first) pop.style.transition = "none";
|
|
7317
|
+
const { direction: next, top, left, over, maxHeight } = computePlacement(
|
|
7318
|
+
triggerRect,
|
|
7319
|
+
popW,
|
|
7320
|
+
popH,
|
|
7321
|
+
clip
|
|
7322
|
+
);
|
|
7323
|
+
pop.style.top = `${top + window.scrollY}px`;
|
|
7324
|
+
pop.style.left = `${left + window.scrollX}px`;
|
|
7325
|
+
pop.style.maxHeight = maxHeight === null ? "" : `${maxHeight}px`;
|
|
7326
|
+
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";
|
|
7327
|
+
directionRef.current = next;
|
|
7328
|
+
pop.classList.toggle("top", next === "top");
|
|
7329
|
+
pop.classList.toggle("bottom", next === "bottom");
|
|
7330
|
+
if (first) {
|
|
7331
|
+
void pop.offsetHeight;
|
|
7332
|
+
pop.style.transition = "";
|
|
7333
|
+
placedRef.current = true;
|
|
7334
|
+
}
|
|
7335
|
+
}, [triggerRef, popRef]);
|
|
7336
|
+
React10.useLayoutEffect(() => {
|
|
7337
|
+
if (!enabled) {
|
|
7338
|
+
sizeRef.current = null;
|
|
7339
|
+
scrollParentRef.current = null;
|
|
7340
|
+
placedRef.current = false;
|
|
7341
|
+
return;
|
|
7342
|
+
}
|
|
7343
|
+
if (triggerRef.current) {
|
|
7344
|
+
scrollParentRef.current = findScrollParent(triggerRef.current);
|
|
7345
|
+
}
|
|
7346
|
+
calculatePosition(true);
|
|
7347
|
+
const raf = requestAnimationFrame(() => calculatePosition(true));
|
|
7348
|
+
return () => cancelAnimationFrame(raf);
|
|
7349
|
+
}, [calculatePosition, enabled, triggerRef]);
|
|
7350
|
+
React10.useEffect(() => {
|
|
7351
|
+
if (!enabled || !popRef.current) return;
|
|
7352
|
+
const observer = new ResizeObserver(() => {
|
|
7353
|
+
calculatePosition(true);
|
|
7354
|
+
});
|
|
7355
|
+
observer.observe(popRef.current);
|
|
7356
|
+
return () => observer.disconnect();
|
|
7357
|
+
}, [calculatePosition, enabled, popRef]);
|
|
7358
|
+
React10.useEffect(() => {
|
|
7359
|
+
if (!enabled) return;
|
|
7360
|
+
const onScroll = () => calculatePosition();
|
|
7361
|
+
const onResize = () => calculatePosition(true);
|
|
7362
|
+
window.addEventListener("resize", onResize, { passive: true });
|
|
7363
|
+
window.addEventListener("scroll", onScroll, { passive: true, capture: true });
|
|
7364
|
+
return () => {
|
|
7365
|
+
window.removeEventListener("resize", onResize);
|
|
7366
|
+
window.removeEventListener("scroll", onScroll, true);
|
|
7367
|
+
};
|
|
7368
|
+
}, [calculatePosition, enabled]);
|
|
7369
|
+
};
|
|
7370
|
+
var useAutoPosition_default = useAutoPosition;
|
|
7371
|
+
|
|
7372
|
+
// src/tokens/hooks/useOverlayKeyboard.ts
|
|
7235
7373
|
var FOCUSABLE = [
|
|
7236
7374
|
"a[href]",
|
|
7237
7375
|
"button:not([disabled])",
|
|
@@ -7245,7 +7383,7 @@ var focusableIn = (el) => Array.from(el.querySelectorAll(FOCUSABLE)).filter(
|
|
|
7245
7383
|
(n) => n.offsetWidth > 0 || n.offsetHeight > 0 || n === document.activeElement
|
|
7246
7384
|
);
|
|
7247
7385
|
var useEscapeKey = (enabled, onEscape) => {
|
|
7248
|
-
|
|
7386
|
+
React11.useEffect(() => {
|
|
7249
7387
|
if (!enabled) return;
|
|
7250
7388
|
const onKey = (e) => {
|
|
7251
7389
|
if (e.key !== "Escape") return;
|
|
@@ -7259,8 +7397,8 @@ var useEscapeKey = (enabled, onEscape) => {
|
|
|
7259
7397
|
};
|
|
7260
7398
|
var useFocusTrap = (containerRef, enabled, options = {}) => {
|
|
7261
7399
|
const { trap = false, initialFocus } = options;
|
|
7262
|
-
const restoreRef =
|
|
7263
|
-
|
|
7400
|
+
const restoreRef = React11.useRef(null);
|
|
7401
|
+
React11.useEffect(() => {
|
|
7264
7402
|
if (!enabled) return;
|
|
7265
7403
|
restoreRef.current = document.activeElement;
|
|
7266
7404
|
const raf = requestAnimationFrame(() => {
|
|
@@ -7278,7 +7416,7 @@ var useFocusTrap = (containerRef, enabled, options = {}) => {
|
|
|
7278
7416
|
if (prev && document.contains(prev)) prev.focus({ preventScroll: true });
|
|
7279
7417
|
};
|
|
7280
7418
|
}, [enabled, containerRef, initialFocus]);
|
|
7281
|
-
|
|
7419
|
+
React11.useEffect(() => {
|
|
7282
7420
|
if (!enabled || !trap) return;
|
|
7283
7421
|
const onKey = (e) => {
|
|
7284
7422
|
if (e.key !== "Tab") return;
|
|
@@ -7304,22 +7442,22 @@ var useFocusTrap = (containerRef, enabled, options = {}) => {
|
|
|
7304
7442
|
return () => document.removeEventListener("keydown", onKey);
|
|
7305
7443
|
}, [enabled, trap, containerRef]);
|
|
7306
7444
|
};
|
|
7307
|
-
var
|
|
7308
|
-
const onCloseRef =
|
|
7445
|
+
var useCloseWhenTriggerHidden = (enabled, triggerRef, onClose) => {
|
|
7446
|
+
const onCloseRef = React11.useRef(onClose);
|
|
7309
7447
|
onCloseRef.current = onClose;
|
|
7310
|
-
|
|
7311
|
-
|
|
7312
|
-
|
|
7313
|
-
|
|
7314
|
-
|
|
7315
|
-
|
|
7316
|
-
}
|
|
7317
|
-
|
|
7318
|
-
|
|
7319
|
-
|
|
7320
|
-
|
|
7321
|
-
return () =>
|
|
7322
|
-
}, [enabled,
|
|
7448
|
+
React11.useEffect(() => {
|
|
7449
|
+
const trigger = triggerRef.current;
|
|
7450
|
+
if (!enabled || !trigger) return;
|
|
7451
|
+
const observer = new IntersectionObserver(
|
|
7452
|
+
([entry]) => {
|
|
7453
|
+
if (!entry.isIntersecting) onCloseRef.current();
|
|
7454
|
+
},
|
|
7455
|
+
// 그릇이 없으면 root: null → 뷰포트 기준
|
|
7456
|
+
{ root: findScrollParent(trigger), threshold: 0 }
|
|
7457
|
+
);
|
|
7458
|
+
observer.observe(trigger);
|
|
7459
|
+
return () => observer.disconnect();
|
|
7460
|
+
}, [enabled, triggerRef]);
|
|
7323
7461
|
};
|
|
7324
7462
|
|
|
7325
7463
|
// src/components/Modal/Modal.tsx
|
|
@@ -7327,13 +7465,13 @@ import { jsx as jsx313 } from "react/jsx-runtime";
|
|
|
7327
7465
|
var ANIMATION_DURATION_MS = 200;
|
|
7328
7466
|
var Modal = (props) => {
|
|
7329
7467
|
const { isOpen, onClose, children } = props;
|
|
7330
|
-
const [mounted, setMounted] =
|
|
7331
|
-
const [visible, setVisible] =
|
|
7332
|
-
const [settled, setSettled] =
|
|
7333
|
-
const boxRef =
|
|
7468
|
+
const [mounted, setMounted] = React12.useState(false);
|
|
7469
|
+
const [visible, setVisible] = React12.useState(false);
|
|
7470
|
+
const [settled, setSettled] = React12.useState(false);
|
|
7471
|
+
const boxRef = React12.useRef(null);
|
|
7334
7472
|
useEscapeKey(isOpen, onClose);
|
|
7335
7473
|
useFocusTrap(boxRef, isOpen && mounted, { trap: true });
|
|
7336
|
-
|
|
7474
|
+
React12.useEffect(() => {
|
|
7337
7475
|
if (isOpen) {
|
|
7338
7476
|
setMounted(true);
|
|
7339
7477
|
const show = setTimeout(() => setVisible(true), 1);
|
|
@@ -7377,9 +7515,9 @@ Modal.displayName = "Modal";
|
|
|
7377
7515
|
var Modal_default = Modal;
|
|
7378
7516
|
|
|
7379
7517
|
// src/components/DatePicker/SingleDatePicker/index.tsx
|
|
7380
|
-
import
|
|
7518
|
+
import React13 from "react";
|
|
7381
7519
|
import { Fragment as Fragment4, jsx as jsx314, jsxs as jsxs200 } from "react/jsx-runtime";
|
|
7382
|
-
var DayCell2 =
|
|
7520
|
+
var DayCell2 = React13.memo(
|
|
7383
7521
|
({
|
|
7384
7522
|
day,
|
|
7385
7523
|
disabled,
|
|
@@ -7428,33 +7566,33 @@ var SingleDatePicker = (props) => {
|
|
|
7428
7566
|
required,
|
|
7429
7567
|
validations
|
|
7430
7568
|
} = props;
|
|
7431
|
-
const labelId =
|
|
7569
|
+
const labelId = React13.useId();
|
|
7432
7570
|
const initialYear = value?.getFullYear();
|
|
7433
7571
|
const initialMonth = value?.getMonth();
|
|
7434
7572
|
const { year, month, days, goToPrevMonth, goToNextMonth, setYear, setMonth } = useCalendar(
|
|
7435
7573
|
initialYear,
|
|
7436
7574
|
initialMonth
|
|
7437
7575
|
);
|
|
7438
|
-
const [pickerMode, setPickerMode] =
|
|
7439
|
-
const [yearRangeStart, setYearRangeStart] =
|
|
7576
|
+
const [pickerMode, setPickerMode] = React13.useState("days");
|
|
7577
|
+
const [yearRangeStart, setYearRangeStart] = React13.useState(
|
|
7440
7578
|
Math.floor((initialYear ?? (/* @__PURE__ */ new Date()).getFullYear()) / 12) * 12
|
|
7441
7579
|
);
|
|
7442
|
-
const minTime =
|
|
7580
|
+
const minTime = React13.useMemo(
|
|
7443
7581
|
() => minDate ? new Date(minDate.getFullYear(), minDate.getMonth(), minDate.getDate()).getTime() : -Infinity,
|
|
7444
7582
|
[minDate]
|
|
7445
7583
|
);
|
|
7446
|
-
const maxTime =
|
|
7584
|
+
const maxTime = React13.useMemo(
|
|
7447
7585
|
() => maxDate ? new Date(maxDate.getFullYear(), maxDate.getMonth(), maxDate.getDate()).getTime() : Infinity,
|
|
7448
7586
|
[maxDate]
|
|
7449
7587
|
);
|
|
7450
|
-
const highlightSet =
|
|
7588
|
+
const highlightSet = React13.useMemo(() => {
|
|
7451
7589
|
const set = /* @__PURE__ */ new Set();
|
|
7452
7590
|
for (const h of highlightDates) {
|
|
7453
7591
|
set.add(`${h.getFullYear()}-${h.getMonth()}-${h.getDate()}`);
|
|
7454
7592
|
}
|
|
7455
7593
|
return set;
|
|
7456
7594
|
}, [highlightDates]);
|
|
7457
|
-
const handleSelect =
|
|
7595
|
+
const handleSelect = React13.useCallback(
|
|
7458
7596
|
(date) => {
|
|
7459
7597
|
onChange?.(date);
|
|
7460
7598
|
},
|
|
@@ -7597,8 +7735,8 @@ var InputDatePicker = (props) => {
|
|
|
7597
7735
|
required,
|
|
7598
7736
|
validations
|
|
7599
7737
|
} = props;
|
|
7600
|
-
const [isOpen, setIsOpen] =
|
|
7601
|
-
const [tempDate, setTempDate] =
|
|
7738
|
+
const [isOpen, setIsOpen] = React14.useState(false);
|
|
7739
|
+
const [tempDate, setTempDate] = React14.useState(value ?? /* @__PURE__ */ new Date());
|
|
7602
7740
|
const handleOpen = () => {
|
|
7603
7741
|
if (disabled) return;
|
|
7604
7742
|
setTempDate(value ?? /* @__PURE__ */ new Date());
|
|
@@ -7650,18 +7788,18 @@ InputDatePicker.displayName = "InputDatePicker";
|
|
|
7650
7788
|
var InputDatePicker_default = InputDatePicker;
|
|
7651
7789
|
|
|
7652
7790
|
// src/components/DatePicker/PopupPicker/index.tsx
|
|
7653
|
-
import
|
|
7791
|
+
import React18 from "react";
|
|
7654
7792
|
|
|
7655
7793
|
// src/components/DatePicker/RangePicker/index.tsx
|
|
7656
|
-
import
|
|
7794
|
+
import React17 from "react";
|
|
7657
7795
|
|
|
7658
7796
|
// src/components/Tab/Tab.tsx
|
|
7659
|
-
import
|
|
7797
|
+
import React16 from "react";
|
|
7660
7798
|
|
|
7661
7799
|
// src/components/Tab/TabItem.tsx
|
|
7662
|
-
import
|
|
7800
|
+
import React15 from "react";
|
|
7663
7801
|
import { jsx as jsx316 } from "react/jsx-runtime";
|
|
7664
|
-
var TabItem =
|
|
7802
|
+
var TabItem = React15.forwardRef((props, ref) => {
|
|
7665
7803
|
const { isActive: isActive2, title, onClick } = props;
|
|
7666
7804
|
return /* @__PURE__ */ jsx316(
|
|
7667
7805
|
"button",
|
|
@@ -7685,11 +7823,11 @@ import { jsx as jsx317, jsxs as jsxs202 } from "react/jsx-runtime";
|
|
|
7685
7823
|
var Tab = (props) => {
|
|
7686
7824
|
const { activeIndex, onChange, tabs, variant, type, size = "md" } = props;
|
|
7687
7825
|
const shape = variant ?? type ?? "default";
|
|
7688
|
-
const [underlineStyle, setUnderlineStyle] =
|
|
7826
|
+
const [underlineStyle, setUnderlineStyle] = React16.useState({
|
|
7689
7827
|
left: 0,
|
|
7690
7828
|
width: 0
|
|
7691
7829
|
});
|
|
7692
|
-
const itemRefs =
|
|
7830
|
+
const itemRefs = React16.useRef([]);
|
|
7693
7831
|
const handleKeyDown = (e) => {
|
|
7694
7832
|
const last = tabs.length - 1;
|
|
7695
7833
|
let next = null;
|
|
@@ -7705,7 +7843,7 @@ var Tab = (props) => {
|
|
|
7705
7843
|
const handleChangeActiveTab = (tabItem, tabIdx) => {
|
|
7706
7844
|
onChange(tabItem, tabIdx);
|
|
7707
7845
|
};
|
|
7708
|
-
|
|
7846
|
+
React16.useEffect(() => {
|
|
7709
7847
|
const el = itemRefs.current[activeIndex];
|
|
7710
7848
|
if (el) {
|
|
7711
7849
|
setUnderlineStyle({ left: el.offsetLeft, width: el.offsetWidth });
|
|
@@ -7761,8 +7899,8 @@ var RangePicker = (props) => {
|
|
|
7761
7899
|
required,
|
|
7762
7900
|
validations
|
|
7763
7901
|
} = props;
|
|
7764
|
-
const labelId =
|
|
7765
|
-
const [activeTab, setActiveTab] =
|
|
7902
|
+
const labelId = React17.useId();
|
|
7903
|
+
const [activeTab, setActiveTab] = React17.useState("start");
|
|
7766
7904
|
const handleStartChange = (date) => {
|
|
7767
7905
|
if (!date) return;
|
|
7768
7906
|
const newStart = date > endDate ? endDate : date;
|
|
@@ -7856,7 +7994,7 @@ var RangePicker_default = RangePicker;
|
|
|
7856
7994
|
import { jsx as jsx319, jsxs as jsxs204 } from "react/jsx-runtime";
|
|
7857
7995
|
var PopupPicker = (props) => {
|
|
7858
7996
|
const { component, type, locale } = props;
|
|
7859
|
-
const [isOpen, setIsOpen] =
|
|
7997
|
+
const [isOpen, setIsOpen] = React18.useState(false);
|
|
7860
7998
|
const handleClick = () => setIsOpen(true);
|
|
7861
7999
|
const handleClose = () => setIsOpen(false);
|
|
7862
8000
|
const handleSingleChange = (date) => {
|
|
@@ -7865,7 +8003,7 @@ var PopupPicker = (props) => {
|
|
|
7865
8003
|
handleClose();
|
|
7866
8004
|
};
|
|
7867
8005
|
return /* @__PURE__ */ jsxs204("div", { className: "lib-xplat-popup-datepicker", children: [
|
|
7868
|
-
|
|
8006
|
+
React18.cloneElement(component, { onClick: handleClick }),
|
|
7869
8007
|
/* @__PURE__ */ jsx319(Modal_default, { isOpen, onClose: handleClose, children: /* @__PURE__ */ jsxs204("div", { className: clsx_default("lib-xplat-popup-datepicker-card", type === "range" && "range-mode"), children: [
|
|
7870
8008
|
/* @__PURE__ */ jsxs204("div", { className: "popup-datepicker-content", children: [
|
|
7871
8009
|
type === "single" && /* @__PURE__ */ jsx319(
|
|
@@ -7924,18 +8062,18 @@ Divider.displayName = "Divider";
|
|
|
7924
8062
|
var Divider_default = Divider;
|
|
7925
8063
|
|
|
7926
8064
|
// src/components/Drawer/Drawer.tsx
|
|
7927
|
-
import
|
|
8065
|
+
import React19 from "react";
|
|
7928
8066
|
import { createPortal as createPortal2 } from "react-dom";
|
|
7929
8067
|
import { jsx as jsx321, jsxs as jsxs205 } from "react/jsx-runtime";
|
|
7930
8068
|
var ANIMATION_DURATION_MS2 = 250;
|
|
7931
8069
|
var Drawer = (props) => {
|
|
7932
8070
|
const { isOpen, onClose, placement = "right", size = "md", title, children } = props;
|
|
7933
|
-
const [mounted, setMounted] =
|
|
7934
|
-
const [visible, setVisible] =
|
|
7935
|
-
const panelRef =
|
|
8071
|
+
const [mounted, setMounted] = React19.useState(false);
|
|
8072
|
+
const [visible, setVisible] = React19.useState(false);
|
|
8073
|
+
const panelRef = React19.useRef(null);
|
|
7936
8074
|
useEscapeKey(isOpen, onClose);
|
|
7937
8075
|
useFocusTrap(panelRef, isOpen && mounted, { trap: true });
|
|
7938
|
-
|
|
8076
|
+
React19.useEffect(() => {
|
|
7939
8077
|
if (isOpen) {
|
|
7940
8078
|
setMounted(true);
|
|
7941
8079
|
const t2 = setTimeout(() => setVisible(true), 1);
|
|
@@ -7991,141 +8129,6 @@ var Portal = ({ children }) => {
|
|
|
7991
8129
|
Portal.displayName = "Portal";
|
|
7992
8130
|
var Portal_default = Portal;
|
|
7993
8131
|
|
|
7994
|
-
// src/tokens/hooks/useAutoPosition.ts
|
|
7995
|
-
import React19 from "react";
|
|
7996
|
-
var findScrollParent = (el) => {
|
|
7997
|
-
for (let p = el.parentElement; p; p = p.parentElement) {
|
|
7998
|
-
const { overflowY, overflowX } = getComputedStyle(p);
|
|
7999
|
-
if (/(auto|scroll)/.test(overflowY) || /(auto|scroll)/.test(overflowX)) return p;
|
|
8000
|
-
}
|
|
8001
|
-
return null;
|
|
8002
|
-
};
|
|
8003
|
-
var computePlacement = (triggerRect, popW, popH, clip) => {
|
|
8004
|
-
const roomBelow = clip.bottom - triggerRect.bottom;
|
|
8005
|
-
const roomAbove = triggerRect.top - clip.top;
|
|
8006
|
-
let direction;
|
|
8007
|
-
let top;
|
|
8008
|
-
let maxHeight = null;
|
|
8009
|
-
if (popH <= roomBelow) {
|
|
8010
|
-
direction = "bottom";
|
|
8011
|
-
top = triggerRect.bottom;
|
|
8012
|
-
} else if (popH <= roomAbove) {
|
|
8013
|
-
direction = "top";
|
|
8014
|
-
top = triggerRect.top - popH;
|
|
8015
|
-
} else {
|
|
8016
|
-
const room = Math.max(roomBelow, roomAbove, 0);
|
|
8017
|
-
if (roomBelow >= roomAbove) {
|
|
8018
|
-
direction = "bottom";
|
|
8019
|
-
top = triggerRect.bottom;
|
|
8020
|
-
} else {
|
|
8021
|
-
direction = "top";
|
|
8022
|
-
top = triggerRect.top - room;
|
|
8023
|
-
}
|
|
8024
|
-
maxHeight = room;
|
|
8025
|
-
}
|
|
8026
|
-
let left = triggerRect.left;
|
|
8027
|
-
if (left + popW > clip.right - 8) {
|
|
8028
|
-
left = triggerRect.right - popW;
|
|
8029
|
-
}
|
|
8030
|
-
if (left < clip.left + 8) left = clip.left + 8;
|
|
8031
|
-
const drawnH = maxHeight === null ? popH : Math.min(popH, maxHeight);
|
|
8032
|
-
return {
|
|
8033
|
-
direction,
|
|
8034
|
-
top,
|
|
8035
|
-
left,
|
|
8036
|
-
maxHeight,
|
|
8037
|
-
over: {
|
|
8038
|
-
top: Math.max(0, clip.top - top),
|
|
8039
|
-
right: Math.max(0, left + popW - clip.right),
|
|
8040
|
-
bottom: Math.max(0, top + drawnH - clip.bottom),
|
|
8041
|
-
left: Math.max(0, clip.left - left)
|
|
8042
|
-
}
|
|
8043
|
-
};
|
|
8044
|
-
};
|
|
8045
|
-
var useAutoPosition = (triggerRef, popRef, enabled = true) => {
|
|
8046
|
-
const directionRef = React19.useRef("bottom");
|
|
8047
|
-
const sizeRef = React19.useRef(null);
|
|
8048
|
-
const scrollParentRef = React19.useRef(null);
|
|
8049
|
-
const placedRef = React19.useRef(false);
|
|
8050
|
-
const calculatePosition = React19.useCallback((remeasure = false) => {
|
|
8051
|
-
const pop = popRef.current;
|
|
8052
|
-
if (!triggerRef.current || !pop) return;
|
|
8053
|
-
if (remeasure || !sizeRef.current) {
|
|
8054
|
-
sizeRef.current = {
|
|
8055
|
-
w: pop.offsetWidth,
|
|
8056
|
-
h: Math.max(pop.offsetHeight, pop.scrollHeight)
|
|
8057
|
-
};
|
|
8058
|
-
}
|
|
8059
|
-
const { w: popW, h: popH } = sizeRef.current;
|
|
8060
|
-
const triggerRect = triggerRef.current.getBoundingClientRect();
|
|
8061
|
-
if (popH === 0 || popW === 0) {
|
|
8062
|
-
sizeRef.current = null;
|
|
8063
|
-
return;
|
|
8064
|
-
}
|
|
8065
|
-
const parentRect = scrollParentRef.current?.getBoundingClientRect();
|
|
8066
|
-
const clip = {
|
|
8067
|
-
top: Math.max(parentRect?.top ?? 0, 0),
|
|
8068
|
-
bottom: Math.min(parentRect?.bottom ?? window.innerHeight, window.innerHeight),
|
|
8069
|
-
left: Math.max(parentRect?.left ?? 0, 0),
|
|
8070
|
-
right: Math.min(parentRect?.right ?? window.innerWidth, window.innerWidth)
|
|
8071
|
-
};
|
|
8072
|
-
const first = !placedRef.current;
|
|
8073
|
-
if (first) pop.style.transition = "none";
|
|
8074
|
-
const { direction: next, top, left, over, maxHeight } = computePlacement(
|
|
8075
|
-
triggerRect,
|
|
8076
|
-
popW,
|
|
8077
|
-
popH,
|
|
8078
|
-
clip
|
|
8079
|
-
);
|
|
8080
|
-
pop.style.top = `${top + window.scrollY}px`;
|
|
8081
|
-
pop.style.left = `${left + window.scrollX}px`;
|
|
8082
|
-
pop.style.maxHeight = maxHeight === null ? "" : `${maxHeight}px`;
|
|
8083
|
-
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";
|
|
8084
|
-
directionRef.current = next;
|
|
8085
|
-
pop.classList.toggle("top", next === "top");
|
|
8086
|
-
pop.classList.toggle("bottom", next === "bottom");
|
|
8087
|
-
if (first) {
|
|
8088
|
-
void pop.offsetHeight;
|
|
8089
|
-
pop.style.transition = "";
|
|
8090
|
-
placedRef.current = true;
|
|
8091
|
-
}
|
|
8092
|
-
}, [triggerRef, popRef]);
|
|
8093
|
-
React19.useLayoutEffect(() => {
|
|
8094
|
-
if (!enabled) {
|
|
8095
|
-
sizeRef.current = null;
|
|
8096
|
-
scrollParentRef.current = null;
|
|
8097
|
-
placedRef.current = false;
|
|
8098
|
-
return;
|
|
8099
|
-
}
|
|
8100
|
-
if (triggerRef.current) {
|
|
8101
|
-
scrollParentRef.current = findScrollParent(triggerRef.current);
|
|
8102
|
-
}
|
|
8103
|
-
calculatePosition(true);
|
|
8104
|
-
const raf = requestAnimationFrame(() => calculatePosition(true));
|
|
8105
|
-
return () => cancelAnimationFrame(raf);
|
|
8106
|
-
}, [calculatePosition, enabled, triggerRef]);
|
|
8107
|
-
React19.useEffect(() => {
|
|
8108
|
-
if (!enabled || !popRef.current) return;
|
|
8109
|
-
const observer = new ResizeObserver(() => {
|
|
8110
|
-
calculatePosition(true);
|
|
8111
|
-
});
|
|
8112
|
-
observer.observe(popRef.current);
|
|
8113
|
-
return () => observer.disconnect();
|
|
8114
|
-
}, [calculatePosition, enabled, popRef]);
|
|
8115
|
-
React19.useEffect(() => {
|
|
8116
|
-
if (!enabled) return;
|
|
8117
|
-
const onScroll = () => calculatePosition();
|
|
8118
|
-
const onResize = () => calculatePosition(true);
|
|
8119
|
-
window.addEventListener("resize", onResize, { passive: true });
|
|
8120
|
-
window.addEventListener("scroll", onScroll, { passive: true, capture: true });
|
|
8121
|
-
return () => {
|
|
8122
|
-
window.removeEventListener("resize", onResize);
|
|
8123
|
-
window.removeEventListener("scroll", onScroll, true);
|
|
8124
|
-
};
|
|
8125
|
-
}, [calculatePosition, enabled]);
|
|
8126
|
-
};
|
|
8127
|
-
var useAutoPosition_default = useAutoPosition;
|
|
8128
|
-
|
|
8129
8132
|
// src/tokens/hooks/useClickOutside.ts
|
|
8130
8133
|
import React20 from "react";
|
|
8131
8134
|
var useClickOutside = (refs, handler, enabled = true) => {
|
|
@@ -8162,7 +8165,7 @@ var Dropdown = (props) => {
|
|
|
8162
8165
|
const menuRef = React21.useRef(null);
|
|
8163
8166
|
useAutoPosition_default(triggerRef, menuRef, mounted);
|
|
8164
8167
|
useClickOutside_default([triggerRef, menuRef], () => setIsOpen(false), isOpen);
|
|
8165
|
-
|
|
8168
|
+
useCloseWhenTriggerHidden(isOpen, triggerRef, () => setIsOpen(false));
|
|
8166
8169
|
useEscapeKey(isOpen, () => {
|
|
8167
8170
|
setIsOpen(false);
|
|
8168
8171
|
triggerRef.current?.focus({ preventScroll: true });
|
|
@@ -10093,7 +10096,7 @@ var PopOver = (props) => {
|
|
|
10093
10096
|
const [localOpen, setLocalOpen] = React27.useState(false);
|
|
10094
10097
|
const [eventTrigger, setEventTrigger] = React27.useState(false);
|
|
10095
10098
|
useClickOutside_default([popRef, triggerRef], onClose, isOpen);
|
|
10096
|
-
|
|
10099
|
+
useCloseWhenTriggerHidden(isOpen, triggerRef, onClose);
|
|
10097
10100
|
useEscapeKey(isOpen, () => {
|
|
10098
10101
|
onClose();
|
|
10099
10102
|
triggerRef.current?.focus({ preventScroll: true });
|
|
@@ -10373,7 +10376,7 @@ var SelectRoot = (props) => {
|
|
|
10373
10376
|
}, []);
|
|
10374
10377
|
const toggle = React31.useCallback(() => setOpen((prev) => !prev), []);
|
|
10375
10378
|
useClickOutside_default([contentRef, triggerRef], close, isOpen);
|
|
10376
|
-
|
|
10379
|
+
useCloseWhenTriggerHidden(isOpen, triggerRef, close);
|
|
10377
10380
|
useEscapeKey(isOpen, () => {
|
|
10378
10381
|
close();
|
|
10379
10382
|
triggerRef.current?.focus({ preventScroll: true });
|
|
@@ -11314,7 +11317,7 @@ var TimePicker = (props) => {
|
|
|
11314
11317
|
}, [step, min, max]);
|
|
11315
11318
|
const close = React40.useCallback(() => setOpen(false), []);
|
|
11316
11319
|
useClickOutside_default([triggerRef, contentRef], close, isOpen);
|
|
11317
|
-
|
|
11320
|
+
useCloseWhenTriggerHidden(isOpen, triggerRef, close);
|
|
11318
11321
|
useEscapeKey(isOpen, () => {
|
|
11319
11322
|
close();
|
|
11320
11323
|
triggerRef.current?.focus({ preventScroll: true });
|
package/guidelines/MIGRATION.md
CHANGED
|
@@ -284,44 +284,32 @@ Dropdown · PopOver · TimePicker 가 전부 애니메이션 없이 툭 튀어
|
|
|
284
284
|
**올리기만 하면 된다. 쓰는 쪽에서 고칠 것은 없다.** `.repositioning` 클래스를
|
|
285
285
|
직접 잡는 CSS 를 쓰고 있었다면 그 규칙만 지우면 된다.
|
|
286
286
|
|
|
287
|
-
## 0.14.
|
|
287
|
+
## 0.14.7 ~ 0.14.14 — 안쪽 상자가 스크롤되면 닫혔다 (0.14.15 에서 되돌림)
|
|
288
288
|
|
|
289
|
-
|
|
290
|
-
채
|
|
289
|
+
**이 구간을 쓰고 있었다면** `Select` · `Dropdown` · `PopOver` · `TimePicker`
|
|
290
|
+
를 열어 둔 채 페이지가 아닌 안쪽 상자를 스크롤하면 닫혔다. **0.14.15 부터는
|
|
291
|
+
닫지 않는다** — 따라간다.
|
|
291
292
|
|
|
292
|
-
|
|
293
|
+
0.14.7 에 그 땜질을 넣은 것은 팝업이 스크롤을 **제때 못 따라가고**(JS 로
|
|
294
|
+
옮기느라 한 프레임 늦었다) 그릇 밖으로 나가도 안 잘려 헤더를 덮었기
|
|
295
|
+
때문이다. 어차피 어긋나 보이니 닫는 쪽이 나았다.
|
|
293
296
|
|
|
294
|
-
|
|
295
|
-
옮겨 준다. 지연도 겹침도 없으므로 닫을 이유가 없다.
|
|
296
|
-
- **팝업 자기 목록 스크롤** — 셀렉트 목록은 `max-height` 안에서 스스로
|
|
297
|
-
스크롤한다. 그걸로 닫히면 고를 수가 없다.
|
|
297
|
+
그 전제가 둘 다 무너졌다:
|
|
298
298
|
|
|
299
|
-
|
|
299
|
+
0.14.3 ~ 0.14.6 자리를 DOM 에 직접 쓰고 문서 좌표로 바꿔 지연이 사라졌다
|
|
300
|
+
0.14.9 ~ 0.14.14 그릇 기준으로 자리를 잡고 그릇 밖은 clip-path 로 잘라낸다
|
|
300
301
|
|
|
301
|
-
|
|
302
|
-
|
|
303
|
-
먼저 그리고 `scroll` 이벤트는 그 뒤에 메인 스레드로 온다.** 그래서 JS 로
|
|
304
|
-
옮기는 한 항상 한 프레임 이상 늦는다. 0.12.0 부터 0.14.6 까지 네 번에 걸쳐
|
|
305
|
-
줄여 봤지만(rAF 묶기 → DOM 직접 쓰기 → 문서 좌표 → rAF 제거) 원리가 그대로라
|
|
306
|
-
남았다.
|
|
302
|
+
이제 따라가도 어긋나 보이지 않는다. 그리고 닫는 쪽이 손해다 — 긴 목록에서
|
|
303
|
+
아래를 보려고 바퀴를 조금 굴렸을 뿐인데 고르던 것이 사라진다.
|
|
307
304
|
|
|
308
|
-
|
|
309
|
-
않으므로, 트리거가 헤더 밑으로 지나가도 팝업만 헤더 위에 남는다. **위치가
|
|
310
|
-
틀린 것이지 순서가 틀린 게 아니라서 `z-index` 로는 못 고친다** — 헤더를
|
|
311
|
-
올리면 이번엔 목록 윗부분이 잘린다.
|
|
305
|
+
### 다만 트리거가 그릇 밖으로 완전히 나가면 닫는다
|
|
312
306
|
|
|
313
|
-
닫으면
|
|
307
|
+
안 닫으면 **패널이 통째로 잘려 안 보이는데 열린 상태**가 된다. 눈에는 닫힌
|
|
308
|
+
것 같은데 키보드 포커스와 `Escape` 는 거기 살아 있다. 판정은
|
|
309
|
+
`IntersectionObserver` 에 맡긴다 — 스크롤마다 재는 것보다 싸고, 그릇이
|
|
310
|
+
스크롤하든 페이지가 스크롤하든 같은 방식으로 걸린다.
|
|
314
311
|
|
|
315
|
-
|
|
316
|
-
> `.lib-xplat-layout` 이 `overflow: hidden` 이고 `.lib-xplat-layout-content`
|
|
317
|
-
> 만 `overflow: auto` 라 페이지가 아예 스크롤되지 않는다.
|
|
318
|
-
|
|
319
|
-
### 쓰는 쪽에서 할 일
|
|
320
|
-
|
|
321
|
-
**없다.** 다만 「열어 둔 채 스크롤하며 고르는」 흐름이 있었다면 그것만 막힌다.
|
|
322
|
-
목록이 길어 스크롤이 필요하다면 `Select` 의 `searchable` 로 걸러내는 쪽이 낫다.
|
|
323
|
-
|
|
324
|
-
---
|
|
312
|
+
**쓰는 쪽에서 할 일은 없다.**
|
|
325
313
|
|
|
326
314
|
## Next.js App Router 에서 반드시 걸리는 것
|
|
327
315
|
|
|
@@ -395,11 +383,21 @@ export { Button, Input, Select, SideBar /* 쓰는 것만 */ } from "@x-plat/desi
|
|
|
395
383
|
| 안쪽 상자 스크롤 시 닫힘 (0.14.7) | **사람이 화면에서 확인함** |
|
|
396
384
|
| 팝업 목록 안에서 휠 → 안 닫힘 (0.14.7) | **사람이 화면에서 확인함** |
|
|
397
385
|
| 긴 항목 줄바꿈 (0.14.8) | **사람이 화면에서 확인함** — 두세 줄로 떨어진다 |
|
|
386
|
+
| 자리·간격·여는 동안 (0.14.14) | **프레임 단위로 측정함** — 멈춘 상태 간격 8px, 여는 동안 4→8 로 벌어짐, 포커스 링 여유가 한 프레임도 음수가 아님 |
|
|
398
387
|
| 페이지(문서) 스크롤 시 안 닫힘 (0.14.7) | **확인 안 됨.** 규칙상 맞지만 그 조건의 화면에 고르개가 없어 볼 자리가 없었다 |
|
|
399
388
|
| `Layout` 타입 (0.14.2) | 소비자 흉내 프로젝트로 타입 검사 통과 |
|
|
400
389
|
| `ToggleChip` 커서·초점 테두리 | 마크업·CSS 만 확인. 눌러 본 사람 없음 |
|
|
401
390
|
| Editor | 아래 |
|
|
402
391
|
|
|
392
|
+
> **재는 범위가 화면과 같은지 먼저 볼 것.** `getBoundingClientRect` 는
|
|
393
|
+
> `outline` 도 `box-shadow` 도 안 친다. 상자만 재면 "겹침 0" 이 나오는데
|
|
394
|
+
> 눈에는 포커스 링이 덮여 보인다 — 0.14.14 가 그 건이다. 상자·링·그림자를
|
|
395
|
+
> 같이 재야 한다.
|
|
396
|
+
>
|
|
397
|
+
> 그리고 포커스 링을 볼 때는 **키보드로 열 것**(`Tab` → `Enter`). 트리거가
|
|
398
|
+
> `div[tabindex]` 라 마우스 클릭에는 `:focus-visible` 이 안 걸린다. 마우스로만
|
|
399
|
+
> 열면 링이 아예 안 떠서 그 항목이 **늘 통과한다.**
|
|
400
|
+
>
|
|
403
401
|
> 확인할 때는 **배포가 앉은 뒤에** 볼 것. 한 번은 "안 닫힌다" 로 나왔다가
|
|
404
402
|
> 다시 보니 닫혔다 — 반쯤 배포된 화면이었다. 그리고 버전 번호가 아니라
|
|
405
403
|
> 받은 파일 안을 열어 확인하는 편이 낫다(0.14.1 은 번호만 올라가고 내용이
|