@x-plat/design-system 0.10.0 → 0.12.0
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/AutoResizeTextArea/index.cjs +14 -5
- package/dist/components/AutoResizeTextArea/index.css +15 -0
- package/dist/components/AutoResizeTextArea/index.d.cts +4 -0
- package/dist/components/AutoResizeTextArea/index.d.ts +4 -0
- package/dist/components/AutoResizeTextArea/index.js +14 -5
- package/dist/components/Badge/index.d.cts +1 -1
- package/dist/components/Badge/index.d.ts +1 -1
- package/dist/components/ChatInput/index.cjs +20 -7
- package/dist/components/ChatInput/index.css +15 -0
- package/dist/components/ChatInput/index.d.cts +4 -0
- package/dist/components/ChatInput/index.d.ts +4 -0
- package/dist/components/ChatInput/index.js +20 -7
- package/dist/components/CheckBox/index.cjs +8 -3
- package/dist/components/CheckBox/index.css +15 -0
- package/dist/components/CheckBox/index.d.cts +1 -1
- package/dist/components/CheckBox/index.d.ts +1 -1
- package/dist/components/CheckBox/index.js +8 -3
- package/dist/components/DatePicker/index.cjs +179 -64
- package/dist/components/DatePicker/index.css +19 -0
- package/dist/components/DatePicker/index.js +179 -64
- package/dist/components/Drawer/index.cjs +83 -4
- package/dist/components/Drawer/index.js +83 -4
- package/dist/components/Dropdown/index.cjs +57 -16
- package/dist/components/Dropdown/index.css +3 -0
- package/dist/components/Dropdown/index.js +57 -16
- package/dist/components/Editor/index.cjs +779 -50
- package/dist/components/Editor/index.css +100 -0
- package/dist/components/Editor/index.d.cts +1 -1
- package/dist/components/Editor/index.d.ts +1 -1
- package/dist/components/Editor/index.js +779 -50
- package/dist/components/FieldMessage/index.cjs +8 -3
- package/dist/components/FieldMessage/index.css +15 -0
- package/dist/components/FieldMessage/index.d.cts +11 -4
- package/dist/components/FieldMessage/index.d.ts +11 -4
- package/dist/components/FieldMessage/index.js +8 -3
- package/dist/components/FileUpload/index.cjs +8 -3
- package/dist/components/FileUpload/index.css +15 -0
- package/dist/components/FileUpload/index.js +8 -3
- package/dist/components/ImageSelector/index.cjs +8 -3
- package/dist/components/ImageSelector/index.css +15 -0
- package/dist/components/ImageSelector/index.js +8 -3
- package/dist/components/Input/index.cjs +15 -5
- package/dist/components/Input/index.css +15 -0
- package/dist/components/Input/index.d.cts +4 -0
- package/dist/components/Input/index.d.ts +4 -0
- package/dist/components/Input/index.js +15 -5
- package/dist/components/Modal/index.cjs +84 -5
- package/dist/components/Modal/index.js +84 -5
- package/dist/components/NotificationBadge/index.d.cts +1 -1
- package/dist/components/NotificationBadge/index.d.ts +1 -1
- package/dist/components/Pagination/index.d.cts +1 -1
- package/dist/components/Pagination/index.d.ts +1 -1
- package/dist/components/PopOver/index.cjs +55 -13
- package/dist/components/PopOver/index.css +3 -0
- package/dist/components/PopOver/index.js +55 -13
- package/dist/components/Progress/index.d.cts +1 -1
- package/dist/components/Progress/index.d.ts +1 -1
- package/dist/components/Radio/index.cjs +8 -3
- package/dist/components/Radio/index.css +15 -0
- package/dist/components/Radio/index.d.cts +1 -1
- package/dist/components/Radio/index.d.ts +1 -1
- package/dist/components/Radio/index.js +8 -3
- package/dist/components/Select/index.cjs +120 -39
- package/dist/components/Select/index.css +57 -0
- package/dist/components/Select/index.d.cts +11 -0
- package/dist/components/Select/index.d.ts +11 -0
- package/dist/components/Select/index.js +120 -39
- package/dist/components/Spinner/index.d.cts +1 -1
- package/dist/components/Spinner/index.d.ts +1 -1
- package/dist/components/Stat/index.cjs +84 -0
- package/dist/components/Stat/index.css +96 -0
- package/dist/components/Stat/index.d.cts +37 -0
- package/dist/components/Stat/index.d.ts +37 -0
- package/dist/components/Stat/index.js +57 -0
- package/dist/components/Steps/index.d.cts +1 -1
- package/dist/components/Steps/index.d.ts +1 -1
- package/dist/components/Switch/index.cjs +14 -5
- package/dist/components/Switch/index.css +15 -0
- package/dist/components/Switch/index.d.cts +6 -1
- package/dist/components/Switch/index.d.ts +6 -1
- package/dist/components/Switch/index.js +14 -5
- package/dist/components/Tab/index.cjs +49 -25
- package/dist/components/Tab/index.css +4 -0
- package/dist/components/Tab/index.js +49 -25
- package/dist/components/TextArea/index.cjs +14 -4
- package/dist/components/TextArea/index.css +15 -0
- package/dist/components/TextArea/index.d.cts +4 -0
- package/dist/components/TextArea/index.d.ts +4 -0
- package/dist/components/TextArea/index.js +14 -4
- package/dist/components/TimePicker/index.cjs +461 -0
- package/dist/components/TimePicker/index.css +175 -0
- package/dist/components/TimePicker/index.d.cts +42 -0
- package/dist/components/TimePicker/index.d.ts +42 -0
- package/dist/components/TimePicker/index.js +424 -0
- package/dist/components/index.cjs +1500 -398
- package/dist/components/index.css +385 -0
- package/dist/components/index.d.cts +3 -1
- package/dist/components/index.d.ts +3 -1
- package/dist/components/index.js +1498 -398
- package/dist/index.cjs +1524 -422
- package/dist/index.css +385 -0
- package/dist/index.d.cts +3 -1
- package/dist/index.d.ts +3 -1
- package/dist/index.js +1522 -422
- package/dist/status-njWqQWFV.d.cts +20 -0
- package/dist/status-njWqQWFV.d.ts +20 -0
- package/guidelines/AGENT_PROMPT.md +3 -3
- package/guidelines/Guidelines.md +3 -0
- package/guidelines/components/editor.md +141 -0
- package/guidelines/components/form.md +19 -0
- package/guidelines/components/stat.md +31 -0
- package/guidelines/components/time-picker.md +49 -0
- package/package.json +1 -1
- package/dist/status-g_KP3qT6.d.cts +0 -8
- package/dist/status-g_KP3qT6.d.ts +0 -8
|
@@ -1,5 +1,5 @@
|
|
|
1
1
|
// src/components/DatePicker/InputDatePicker/index.tsx
|
|
2
|
-
import
|
|
2
|
+
import React7 from "react";
|
|
3
3
|
|
|
4
4
|
// ../../node_modules/clsx/dist/clsx.mjs
|
|
5
5
|
function r(e) {
|
|
@@ -167,11 +167,16 @@ var FieldMessage = (props) => {
|
|
|
167
167
|
FieldMessage.displayName = "FieldMessage";
|
|
168
168
|
var FieldMessage_default = FieldMessage;
|
|
169
169
|
var Field = (props) => {
|
|
170
|
-
const { validations, children } = props;
|
|
171
|
-
|
|
170
|
+
const { label, required = false, htmlFor, validations, children } = props;
|
|
171
|
+
const hasMessages = !!validations && validations.length > 0;
|
|
172
|
+
if (!label && !hasMessages) return /* @__PURE__ */ jsx5(Fragment, { children });
|
|
172
173
|
return /* @__PURE__ */ jsxs3("div", { className: "lib-xplat-field", children: [
|
|
174
|
+
label && /* @__PURE__ */ jsxs3("label", { className: "lib-xplat-field-label", htmlFor, children: [
|
|
175
|
+
label,
|
|
176
|
+
required && /* @__PURE__ */ jsx5("span", { className: "required", "aria-hidden": "true", children: "*" })
|
|
177
|
+
] }),
|
|
173
178
|
children,
|
|
174
|
-
/* @__PURE__ */ jsx5(FieldMessage, { validations })
|
|
179
|
+
hasMessages && /* @__PURE__ */ jsx5(FieldMessage, { validations })
|
|
175
180
|
] });
|
|
176
181
|
};
|
|
177
182
|
Field.displayName = "Field";
|
|
@@ -270,8 +275,12 @@ var Input = React.forwardRef((props, ref) => {
|
|
|
270
275
|
suffix,
|
|
271
276
|
disabled,
|
|
272
277
|
validations,
|
|
278
|
+
label,
|
|
279
|
+
required,
|
|
273
280
|
...inputProps
|
|
274
281
|
} = props;
|
|
282
|
+
const autoId = React.useId();
|
|
283
|
+
const fieldId = inputProps.id ?? autoId;
|
|
275
284
|
const localValue = formatValue(type, value);
|
|
276
285
|
const handleChange = (e) => {
|
|
277
286
|
let val = e.target.value;
|
|
@@ -287,7 +296,7 @@ var Input = React.forwardRef((props, ref) => {
|
|
|
287
296
|
onChange(event);
|
|
288
297
|
}
|
|
289
298
|
};
|
|
290
|
-
return /* @__PURE__ */ jsxs4("div", { className: clsx_default("lib-xplat-input-wrap", className), children: [
|
|
299
|
+
return /* @__PURE__ */ jsx6(Field, { label, required, htmlFor: fieldId, children: /* @__PURE__ */ jsxs4("div", { className: clsx_default("lib-xplat-input-wrap", className), children: [
|
|
291
300
|
/* @__PURE__ */ jsxs4(
|
|
292
301
|
"div",
|
|
293
302
|
{
|
|
@@ -298,6 +307,7 @@ var Input = React.forwardRef((props, ref) => {
|
|
|
298
307
|
{
|
|
299
308
|
...inputProps,
|
|
300
309
|
ref,
|
|
310
|
+
id: fieldId,
|
|
301
311
|
disabled,
|
|
302
312
|
type: type === "number" ? "text" : type,
|
|
303
313
|
value: localValue,
|
|
@@ -310,7 +320,7 @@ var Input = React.forwardRef((props, ref) => {
|
|
|
310
320
|
}
|
|
311
321
|
),
|
|
312
322
|
/* @__PURE__ */ jsx6(FieldMessage_default, { validations })
|
|
313
|
-
] });
|
|
323
|
+
] }) });
|
|
314
324
|
});
|
|
315
325
|
Input.displayName = "Input";
|
|
316
326
|
var Input_default = Input;
|
|
@@ -407,16 +417,96 @@ var PasswordInput = React2.forwardRef(
|
|
|
407
417
|
PasswordInput.displayName = "PasswordInput";
|
|
408
418
|
|
|
409
419
|
// src/components/Modal/Modal.tsx
|
|
410
|
-
import
|
|
420
|
+
import React4 from "react";
|
|
411
421
|
import { createPortal } from "react-dom";
|
|
422
|
+
|
|
423
|
+
// src/tokens/hooks/useOverlayKeyboard.ts
|
|
424
|
+
import React3 from "react";
|
|
425
|
+
var FOCUSABLE = [
|
|
426
|
+
"a[href]",
|
|
427
|
+
"button:not([disabled])",
|
|
428
|
+
"input:not([disabled]):not([type='hidden'])",
|
|
429
|
+
"select:not([disabled])",
|
|
430
|
+
"textarea:not([disabled])",
|
|
431
|
+
"[tabindex]:not([tabindex='-1'])"
|
|
432
|
+
].join(",");
|
|
433
|
+
var focusableIn = (el) => Array.from(el.querySelectorAll(FOCUSABLE)).filter(
|
|
434
|
+
// 화면에 없는 것은 제외 (display:none 등)
|
|
435
|
+
(n) => n.offsetWidth > 0 || n.offsetHeight > 0 || n === document.activeElement
|
|
436
|
+
);
|
|
437
|
+
var useEscapeKey = (enabled, onEscape) => {
|
|
438
|
+
React3.useEffect(() => {
|
|
439
|
+
if (!enabled) return;
|
|
440
|
+
const onKey = (e) => {
|
|
441
|
+
if (e.key !== "Escape") return;
|
|
442
|
+
if (e.defaultPrevented) return;
|
|
443
|
+
e.preventDefault();
|
|
444
|
+
onEscape();
|
|
445
|
+
};
|
|
446
|
+
document.addEventListener("keydown", onKey);
|
|
447
|
+
return () => document.removeEventListener("keydown", onKey);
|
|
448
|
+
}, [enabled, onEscape]);
|
|
449
|
+
};
|
|
450
|
+
var useFocusTrap = (containerRef, enabled, options = {}) => {
|
|
451
|
+
const { trap = false, initialFocus } = options;
|
|
452
|
+
const restoreRef = React3.useRef(null);
|
|
453
|
+
React3.useEffect(() => {
|
|
454
|
+
if (!enabled) return;
|
|
455
|
+
restoreRef.current = document.activeElement;
|
|
456
|
+
const raf = requestAnimationFrame(() => {
|
|
457
|
+
const el = containerRef.current;
|
|
458
|
+
if (!el) return;
|
|
459
|
+
const target = initialFocus?.current ?? focusableIn(el)[0] ?? el;
|
|
460
|
+
if (!target.hasAttribute("tabindex") && !focusableIn(el).includes(target)) {
|
|
461
|
+
target.setAttribute("tabindex", "-1");
|
|
462
|
+
}
|
|
463
|
+
target.focus({ preventScroll: true });
|
|
464
|
+
});
|
|
465
|
+
return () => {
|
|
466
|
+
cancelAnimationFrame(raf);
|
|
467
|
+
const prev = restoreRef.current;
|
|
468
|
+
if (prev && document.contains(prev)) prev.focus({ preventScroll: true });
|
|
469
|
+
};
|
|
470
|
+
}, [enabled, containerRef, initialFocus]);
|
|
471
|
+
React3.useEffect(() => {
|
|
472
|
+
if (!enabled || !trap) return;
|
|
473
|
+
const onKey = (e) => {
|
|
474
|
+
if (e.key !== "Tab") return;
|
|
475
|
+
const el = containerRef.current;
|
|
476
|
+
if (!el) return;
|
|
477
|
+
const items = focusableIn(el);
|
|
478
|
+
if (items.length === 0) {
|
|
479
|
+
e.preventDefault();
|
|
480
|
+
return;
|
|
481
|
+
}
|
|
482
|
+
const first = items[0];
|
|
483
|
+
const last = items[items.length - 1];
|
|
484
|
+
const active = document.activeElement;
|
|
485
|
+
if (e.shiftKey && (active === first || !el.contains(active))) {
|
|
486
|
+
e.preventDefault();
|
|
487
|
+
last.focus();
|
|
488
|
+
} else if (!e.shiftKey && (active === last || !el.contains(active))) {
|
|
489
|
+
e.preventDefault();
|
|
490
|
+
first.focus();
|
|
491
|
+
}
|
|
492
|
+
};
|
|
493
|
+
document.addEventListener("keydown", onKey);
|
|
494
|
+
return () => document.removeEventListener("keydown", onKey);
|
|
495
|
+
}, [enabled, trap, containerRef]);
|
|
496
|
+
};
|
|
497
|
+
|
|
498
|
+
// src/components/Modal/Modal.tsx
|
|
412
499
|
import { jsx as jsx10 } from "react/jsx-runtime";
|
|
413
500
|
var ANIMATION_DURATION_MS = 200;
|
|
414
501
|
var Modal = (props) => {
|
|
415
502
|
const { isOpen, onClose, children } = props;
|
|
416
|
-
const [mounted, setMounted] =
|
|
417
|
-
const [visible, setVisible] =
|
|
418
|
-
const [settled, setSettled] =
|
|
419
|
-
|
|
503
|
+
const [mounted, setMounted] = React4.useState(false);
|
|
504
|
+
const [visible, setVisible] = React4.useState(false);
|
|
505
|
+
const [settled, setSettled] = React4.useState(false);
|
|
506
|
+
const boxRef = React4.useRef(null);
|
|
507
|
+
useEscapeKey(isOpen, onClose);
|
|
508
|
+
useFocusTrap(boxRef, isOpen && mounted, { trap: true });
|
|
509
|
+
React4.useEffect(() => {
|
|
420
510
|
if (isOpen) {
|
|
421
511
|
setMounted(true);
|
|
422
512
|
const show = setTimeout(() => setVisible(true), 1);
|
|
@@ -443,6 +533,7 @@ var Modal = (props) => {
|
|
|
443
533
|
children: /* @__PURE__ */ jsx10(
|
|
444
534
|
"div",
|
|
445
535
|
{
|
|
536
|
+
ref: boxRef,
|
|
446
537
|
className: clsx_default("lib-xplat-modal", "modal-box", stateClass, settled && "settled"),
|
|
447
538
|
role: "dialog",
|
|
448
539
|
"aria-modal": "true",
|
|
@@ -1370,15 +1461,15 @@ import { jsx as jsx298, jsxs as jsxs189 } from "react/jsx-runtime";
|
|
|
1370
1461
|
import { jsx as jsx299, jsxs as jsxs190 } from "react/jsx-runtime";
|
|
1371
1462
|
|
|
1372
1463
|
// src/components/DatePicker/SingleDatePicker/index.tsx
|
|
1373
|
-
import
|
|
1464
|
+
import React6 from "react";
|
|
1374
1465
|
|
|
1375
1466
|
// src/components/Calendar/useCalendar.ts
|
|
1376
|
-
import
|
|
1467
|
+
import React5 from "react";
|
|
1377
1468
|
var useCalendar = (initialYear, initialMonth) => {
|
|
1378
1469
|
const today = /* @__PURE__ */ new Date();
|
|
1379
|
-
const [year, setYear] =
|
|
1380
|
-
const [month, setMonth] =
|
|
1381
|
-
const days =
|
|
1470
|
+
const [year, setYear] = React5.useState(initialYear ?? today.getFullYear());
|
|
1471
|
+
const [month, setMonth] = React5.useState(initialMonth ?? today.getMonth());
|
|
1472
|
+
const days = React5.useMemo(() => {
|
|
1382
1473
|
const firstDay = new Date(year, month, 1);
|
|
1383
1474
|
const lastDay = new Date(year, month + 1, 0);
|
|
1384
1475
|
const startDayOfWeek = firstDay.getDay();
|
|
@@ -1421,7 +1512,7 @@ var useCalendar = (initialYear, initialMonth) => {
|
|
|
1421
1512
|
}
|
|
1422
1513
|
return result;
|
|
1423
1514
|
}, [year, month]);
|
|
1424
|
-
const goToPrevMonth =
|
|
1515
|
+
const goToPrevMonth = React5.useCallback(() => {
|
|
1425
1516
|
setMonth((prev) => {
|
|
1426
1517
|
if (prev === 0) {
|
|
1427
1518
|
setYear((y) => y - 1);
|
|
@@ -1430,7 +1521,7 @@ var useCalendar = (initialYear, initialMonth) => {
|
|
|
1430
1521
|
return prev - 1;
|
|
1431
1522
|
});
|
|
1432
1523
|
}, []);
|
|
1433
|
-
const goToNextMonth =
|
|
1524
|
+
const goToNextMonth = React5.useCallback(() => {
|
|
1434
1525
|
setMonth((prev) => {
|
|
1435
1526
|
if (prev === 11) {
|
|
1436
1527
|
setYear((y) => y + 1);
|
|
@@ -1439,7 +1530,7 @@ var useCalendar = (initialYear, initialMonth) => {
|
|
|
1439
1530
|
return prev + 1;
|
|
1440
1531
|
});
|
|
1441
1532
|
}, []);
|
|
1442
|
-
const goToToday =
|
|
1533
|
+
const goToToday = React5.useCallback(() => {
|
|
1443
1534
|
setYear(today.getFullYear());
|
|
1444
1535
|
setMonth(today.getMonth());
|
|
1445
1536
|
}, []);
|
|
@@ -1474,7 +1565,7 @@ var MONTH_LABELS = {
|
|
|
1474
1565
|
|
|
1475
1566
|
// src/components/DatePicker/SingleDatePicker/index.tsx
|
|
1476
1567
|
import { Fragment as Fragment2, jsx as jsx300, jsxs as jsxs191 } from "react/jsx-runtime";
|
|
1477
|
-
var DayCell =
|
|
1568
|
+
var DayCell = React6.memo(
|
|
1478
1569
|
({
|
|
1479
1570
|
day,
|
|
1480
1571
|
disabled,
|
|
@@ -1526,26 +1617,26 @@ var SingleDatePicker = (props) => {
|
|
|
1526
1617
|
initialYear,
|
|
1527
1618
|
initialMonth
|
|
1528
1619
|
);
|
|
1529
|
-
const [pickerMode, setPickerMode] =
|
|
1530
|
-
const [yearRangeStart, setYearRangeStart] =
|
|
1620
|
+
const [pickerMode, setPickerMode] = React6.useState("days");
|
|
1621
|
+
const [yearRangeStart, setYearRangeStart] = React6.useState(
|
|
1531
1622
|
Math.floor((initialYear ?? (/* @__PURE__ */ new Date()).getFullYear()) / 12) * 12
|
|
1532
1623
|
);
|
|
1533
|
-
const minTime =
|
|
1624
|
+
const minTime = React6.useMemo(
|
|
1534
1625
|
() => minDate ? new Date(minDate.getFullYear(), minDate.getMonth(), minDate.getDate()).getTime() : -Infinity,
|
|
1535
1626
|
[minDate]
|
|
1536
1627
|
);
|
|
1537
|
-
const maxTime =
|
|
1628
|
+
const maxTime = React6.useMemo(
|
|
1538
1629
|
() => maxDate ? new Date(maxDate.getFullYear(), maxDate.getMonth(), maxDate.getDate()).getTime() : Infinity,
|
|
1539
1630
|
[maxDate]
|
|
1540
1631
|
);
|
|
1541
|
-
const highlightSet =
|
|
1632
|
+
const highlightSet = React6.useMemo(() => {
|
|
1542
1633
|
const set = /* @__PURE__ */ new Set();
|
|
1543
1634
|
for (const h of highlightDates) {
|
|
1544
1635
|
set.add(`${h.getFullYear()}-${h.getMonth()}-${h.getDate()}`);
|
|
1545
1636
|
}
|
|
1546
1637
|
return set;
|
|
1547
1638
|
}, [highlightDates]);
|
|
1548
|
-
const handleSelect =
|
|
1639
|
+
const handleSelect = React6.useCallback(
|
|
1549
1640
|
(date) => {
|
|
1550
1641
|
onChange?.(date);
|
|
1551
1642
|
},
|
|
@@ -1674,8 +1765,8 @@ var formatDate = (date) => {
|
|
|
1674
1765
|
};
|
|
1675
1766
|
var InputDatePicker = (props) => {
|
|
1676
1767
|
const { value, onChange, minDate, maxDate, disabled, locale = "ko", placeholder } = props;
|
|
1677
|
-
const [isOpen, setIsOpen] =
|
|
1678
|
-
const [tempDate, setTempDate] =
|
|
1768
|
+
const [isOpen, setIsOpen] = React7.useState(false);
|
|
1769
|
+
const [tempDate, setTempDate] = React7.useState(value ?? /* @__PURE__ */ new Date());
|
|
1679
1770
|
const handleOpen = () => {
|
|
1680
1771
|
if (disabled) return;
|
|
1681
1772
|
setTempDate(value ?? /* @__PURE__ */ new Date());
|
|
@@ -1724,23 +1815,27 @@ InputDatePicker.displayName = "InputDatePicker";
|
|
|
1724
1815
|
var InputDatePicker_default = InputDatePicker;
|
|
1725
1816
|
|
|
1726
1817
|
// src/components/DatePicker/PopupPicker/index.tsx
|
|
1727
|
-
import
|
|
1818
|
+
import React11 from "react";
|
|
1728
1819
|
|
|
1729
1820
|
// src/components/DatePicker/RangePicker/index.tsx
|
|
1730
|
-
import
|
|
1821
|
+
import React10 from "react";
|
|
1731
1822
|
|
|
1732
1823
|
// src/components/Tab/Tab.tsx
|
|
1733
|
-
import
|
|
1824
|
+
import React9 from "react";
|
|
1734
1825
|
|
|
1735
1826
|
// src/components/Tab/TabItem.tsx
|
|
1736
|
-
import
|
|
1827
|
+
import React8 from "react";
|
|
1737
1828
|
import { jsx as jsx302 } from "react/jsx-runtime";
|
|
1738
|
-
var TabItem =
|
|
1829
|
+
var TabItem = React8.forwardRef((props, ref) => {
|
|
1739
1830
|
const { isActive, title, onClick } = props;
|
|
1740
1831
|
return /* @__PURE__ */ jsx302(
|
|
1741
|
-
"
|
|
1832
|
+
"button",
|
|
1742
1833
|
{
|
|
1743
1834
|
ref,
|
|
1835
|
+
type: "button",
|
|
1836
|
+
role: "tab",
|
|
1837
|
+
"aria-selected": isActive,
|
|
1838
|
+
tabIndex: isActive ? 0 : -1,
|
|
1744
1839
|
className: clsx_default("tab-item", isActive ? "active" : null),
|
|
1745
1840
|
onClick,
|
|
1746
1841
|
children: title
|
|
@@ -1755,44 +1850,64 @@ import { jsx as jsx303, jsxs as jsxs193 } from "react/jsx-runtime";
|
|
|
1755
1850
|
var Tab = (props) => {
|
|
1756
1851
|
const { activeIndex, onChange, tabs, variant, type, size = "md" } = props;
|
|
1757
1852
|
const shape = variant ?? type ?? "default";
|
|
1758
|
-
const [underlineStyle, setUnderlineStyle] =
|
|
1853
|
+
const [underlineStyle, setUnderlineStyle] = React9.useState({
|
|
1759
1854
|
left: 0,
|
|
1760
1855
|
width: 0
|
|
1761
1856
|
});
|
|
1762
|
-
const itemRefs =
|
|
1857
|
+
const itemRefs = React9.useRef([]);
|
|
1858
|
+
const handleKeyDown = (e) => {
|
|
1859
|
+
const last = tabs.length - 1;
|
|
1860
|
+
let next = null;
|
|
1861
|
+
if (e.key === "ArrowRight") next = activeIndex >= last ? 0 : activeIndex + 1;
|
|
1862
|
+
else if (e.key === "ArrowLeft") next = activeIndex <= 0 ? last : activeIndex - 1;
|
|
1863
|
+
else if (e.key === "Home") next = 0;
|
|
1864
|
+
else if (e.key === "End") next = last;
|
|
1865
|
+
if (next === null) return;
|
|
1866
|
+
e.preventDefault();
|
|
1867
|
+
onChange(tabs[next], next);
|
|
1868
|
+
itemRefs.current[next]?.focus();
|
|
1869
|
+
};
|
|
1763
1870
|
const handleChangeActiveTab = (tabItem, tabIdx) => {
|
|
1764
1871
|
onChange(tabItem, tabIdx);
|
|
1765
1872
|
};
|
|
1766
|
-
|
|
1873
|
+
React9.useEffect(() => {
|
|
1767
1874
|
const el = itemRefs.current[activeIndex];
|
|
1768
1875
|
if (el) {
|
|
1769
1876
|
setUnderlineStyle({ left: el.offsetLeft, width: el.offsetWidth });
|
|
1770
1877
|
}
|
|
1771
1878
|
}, [activeIndex, tabs.length]);
|
|
1772
|
-
return /* @__PURE__ */ jsxs193(
|
|
1773
|
-
|
|
1774
|
-
|
|
1775
|
-
{
|
|
1776
|
-
|
|
1777
|
-
|
|
1778
|
-
|
|
1779
|
-
|
|
1780
|
-
|
|
1781
|
-
|
|
1782
|
-
|
|
1783
|
-
|
|
1784
|
-
|
|
1785
|
-
|
|
1786
|
-
|
|
1787
|
-
|
|
1788
|
-
|
|
1789
|
-
|
|
1790
|
-
|
|
1791
|
-
|
|
1792
|
-
|
|
1793
|
-
|
|
1794
|
-
|
|
1795
|
-
|
|
1879
|
+
return /* @__PURE__ */ jsxs193(
|
|
1880
|
+
"div",
|
|
1881
|
+
{
|
|
1882
|
+
className: clsx_default("lib-xplat-tab", `type-${shape}`, size),
|
|
1883
|
+
role: "tablist",
|
|
1884
|
+
onKeyDown: handleKeyDown,
|
|
1885
|
+
children: [
|
|
1886
|
+
tabs.map((tab, idx) => /* @__PURE__ */ jsx303(
|
|
1887
|
+
TabItem_default,
|
|
1888
|
+
{
|
|
1889
|
+
onClick: () => handleChangeActiveTab(tab, idx),
|
|
1890
|
+
isActive: activeIndex === idx,
|
|
1891
|
+
ref: (el) => {
|
|
1892
|
+
itemRefs.current[idx] = el;
|
|
1893
|
+
},
|
|
1894
|
+
title: tab.title
|
|
1895
|
+
},
|
|
1896
|
+
`${tab.value}_${idx}`
|
|
1897
|
+
)),
|
|
1898
|
+
shape === "toggle" && /* @__PURE__ */ jsx303(
|
|
1899
|
+
"div",
|
|
1900
|
+
{
|
|
1901
|
+
className: "tab-toggle-underline",
|
|
1902
|
+
style: {
|
|
1903
|
+
left: underlineStyle.left,
|
|
1904
|
+
width: underlineStyle.width
|
|
1905
|
+
}
|
|
1906
|
+
}
|
|
1907
|
+
)
|
|
1908
|
+
]
|
|
1909
|
+
}
|
|
1910
|
+
);
|
|
1796
1911
|
};
|
|
1797
1912
|
Tab.displayName = "Tab";
|
|
1798
1913
|
var Tab_default = Tab;
|
|
@@ -1808,7 +1923,7 @@ var RangePicker = (props) => {
|
|
|
1808
1923
|
maxDate,
|
|
1809
1924
|
locale = "ko"
|
|
1810
1925
|
} = props;
|
|
1811
|
-
const [activeTab, setActiveTab] =
|
|
1926
|
+
const [activeTab, setActiveTab] = React10.useState("start");
|
|
1812
1927
|
const handleStartChange = (date) => {
|
|
1813
1928
|
if (!date) return;
|
|
1814
1929
|
const newStart = date > endDate ? endDate : date;
|
|
@@ -1893,7 +2008,7 @@ var RangePicker_default = RangePicker;
|
|
|
1893
2008
|
import { jsx as jsx305, jsxs as jsxs195 } from "react/jsx-runtime";
|
|
1894
2009
|
var PopupPicker = (props) => {
|
|
1895
2010
|
const { component, type, locale } = props;
|
|
1896
|
-
const [isOpen, setIsOpen] =
|
|
2011
|
+
const [isOpen, setIsOpen] = React11.useState(false);
|
|
1897
2012
|
const handleClick = () => setIsOpen(true);
|
|
1898
2013
|
const handleClose = () => setIsOpen(false);
|
|
1899
2014
|
const handleSingleChange = (date) => {
|
|
@@ -1902,7 +2017,7 @@ var PopupPicker = (props) => {
|
|
|
1902
2017
|
handleClose();
|
|
1903
2018
|
};
|
|
1904
2019
|
return /* @__PURE__ */ jsxs195("div", { className: "lib-xplat-popup-datepicker", children: [
|
|
1905
|
-
|
|
2020
|
+
React11.cloneElement(component, { onClick: handleClick }),
|
|
1906
2021
|
/* @__PURE__ */ jsx305(Modal_default, { isOpen, onClose: handleClose, children: /* @__PURE__ */ jsxs195("div", { className: clsx_default("lib-xplat-popup-datepicker-card", type === "range" && "range-mode"), children: [
|
|
1907
2022
|
/* @__PURE__ */ jsxs195("div", { className: "popup-datepicker-content", children: [
|
|
1908
2023
|
type === "single" && /* @__PURE__ */ jsx305(
|
|
@@ -35,9 +35,84 @@ __export(Drawer_exports, {
|
|
|
35
35
|
module.exports = __toCommonJS(Drawer_exports);
|
|
36
36
|
|
|
37
37
|
// src/components/Drawer/Drawer.tsx
|
|
38
|
-
var
|
|
38
|
+
var import_react2 = __toESM(require("react"), 1);
|
|
39
39
|
var import_react_dom = require("react-dom");
|
|
40
40
|
|
|
41
|
+
// src/tokens/hooks/useOverlayKeyboard.ts
|
|
42
|
+
var import_react = __toESM(require("react"), 1);
|
|
43
|
+
var FOCUSABLE = [
|
|
44
|
+
"a[href]",
|
|
45
|
+
"button:not([disabled])",
|
|
46
|
+
"input:not([disabled]):not([type='hidden'])",
|
|
47
|
+
"select:not([disabled])",
|
|
48
|
+
"textarea:not([disabled])",
|
|
49
|
+
"[tabindex]:not([tabindex='-1'])"
|
|
50
|
+
].join(",");
|
|
51
|
+
var focusableIn = (el) => Array.from(el.querySelectorAll(FOCUSABLE)).filter(
|
|
52
|
+
// 화면에 없는 것은 제외 (display:none 등)
|
|
53
|
+
(n) => n.offsetWidth > 0 || n.offsetHeight > 0 || n === document.activeElement
|
|
54
|
+
);
|
|
55
|
+
var useEscapeKey = (enabled, onEscape) => {
|
|
56
|
+
import_react.default.useEffect(() => {
|
|
57
|
+
if (!enabled) return;
|
|
58
|
+
const onKey = (e) => {
|
|
59
|
+
if (e.key !== "Escape") return;
|
|
60
|
+
if (e.defaultPrevented) return;
|
|
61
|
+
e.preventDefault();
|
|
62
|
+
onEscape();
|
|
63
|
+
};
|
|
64
|
+
document.addEventListener("keydown", onKey);
|
|
65
|
+
return () => document.removeEventListener("keydown", onKey);
|
|
66
|
+
}, [enabled, onEscape]);
|
|
67
|
+
};
|
|
68
|
+
var useFocusTrap = (containerRef, enabled, options = {}) => {
|
|
69
|
+
const { trap = false, initialFocus } = options;
|
|
70
|
+
const restoreRef = import_react.default.useRef(null);
|
|
71
|
+
import_react.default.useEffect(() => {
|
|
72
|
+
if (!enabled) return;
|
|
73
|
+
restoreRef.current = document.activeElement;
|
|
74
|
+
const raf = requestAnimationFrame(() => {
|
|
75
|
+
const el = containerRef.current;
|
|
76
|
+
if (!el) return;
|
|
77
|
+
const target = initialFocus?.current ?? focusableIn(el)[0] ?? el;
|
|
78
|
+
if (!target.hasAttribute("tabindex") && !focusableIn(el).includes(target)) {
|
|
79
|
+
target.setAttribute("tabindex", "-1");
|
|
80
|
+
}
|
|
81
|
+
target.focus({ preventScroll: true });
|
|
82
|
+
});
|
|
83
|
+
return () => {
|
|
84
|
+
cancelAnimationFrame(raf);
|
|
85
|
+
const prev = restoreRef.current;
|
|
86
|
+
if (prev && document.contains(prev)) prev.focus({ preventScroll: true });
|
|
87
|
+
};
|
|
88
|
+
}, [enabled, containerRef, initialFocus]);
|
|
89
|
+
import_react.default.useEffect(() => {
|
|
90
|
+
if (!enabled || !trap) return;
|
|
91
|
+
const onKey = (e) => {
|
|
92
|
+
if (e.key !== "Tab") return;
|
|
93
|
+
const el = containerRef.current;
|
|
94
|
+
if (!el) return;
|
|
95
|
+
const items = focusableIn(el);
|
|
96
|
+
if (items.length === 0) {
|
|
97
|
+
e.preventDefault();
|
|
98
|
+
return;
|
|
99
|
+
}
|
|
100
|
+
const first = items[0];
|
|
101
|
+
const last = items[items.length - 1];
|
|
102
|
+
const active = document.activeElement;
|
|
103
|
+
if (e.shiftKey && (active === first || !el.contains(active))) {
|
|
104
|
+
e.preventDefault();
|
|
105
|
+
last.focus();
|
|
106
|
+
} else if (!e.shiftKey && (active === last || !el.contains(active))) {
|
|
107
|
+
e.preventDefault();
|
|
108
|
+
first.focus();
|
|
109
|
+
}
|
|
110
|
+
};
|
|
111
|
+
document.addEventListener("keydown", onKey);
|
|
112
|
+
return () => document.removeEventListener("keydown", onKey);
|
|
113
|
+
}, [enabled, trap, containerRef]);
|
|
114
|
+
};
|
|
115
|
+
|
|
41
116
|
// ../../node_modules/clsx/dist/clsx.mjs
|
|
42
117
|
function r(e) {
|
|
43
118
|
var t, f, n = "";
|
|
@@ -59,9 +134,12 @@ var import_jsx_runtime = require("react/jsx-runtime");
|
|
|
59
134
|
var ANIMATION_DURATION_MS = 250;
|
|
60
135
|
var Drawer = (props) => {
|
|
61
136
|
const { isOpen, onClose, placement = "right", size = "md", title, children } = props;
|
|
62
|
-
const [mounted, setMounted] =
|
|
63
|
-
const [visible, setVisible] =
|
|
64
|
-
|
|
137
|
+
const [mounted, setMounted] = import_react2.default.useState(false);
|
|
138
|
+
const [visible, setVisible] = import_react2.default.useState(false);
|
|
139
|
+
const panelRef = import_react2.default.useRef(null);
|
|
140
|
+
useEscapeKey(isOpen, onClose);
|
|
141
|
+
useFocusTrap(panelRef, isOpen && mounted, { trap: true });
|
|
142
|
+
import_react2.default.useEffect(() => {
|
|
65
143
|
if (isOpen) {
|
|
66
144
|
setMounted(true);
|
|
67
145
|
const t2 = setTimeout(() => setVisible(true), 1);
|
|
@@ -83,6 +161,7 @@ var Drawer = (props) => {
|
|
|
83
161
|
children: /* @__PURE__ */ (0, import_jsx_runtime.jsxs)(
|
|
84
162
|
"div",
|
|
85
163
|
{
|
|
164
|
+
ref: panelRef,
|
|
86
165
|
className: clsx_default("lib-xplat-drawer", placement, size, stateClass),
|
|
87
166
|
role: "dialog",
|
|
88
167
|
"aria-modal": "true",
|
|
@@ -1,7 +1,82 @@
|
|
|
1
1
|
// src/components/Drawer/Drawer.tsx
|
|
2
|
-
import
|
|
2
|
+
import React2 from "react";
|
|
3
3
|
import { createPortal } from "react-dom";
|
|
4
4
|
|
|
5
|
+
// src/tokens/hooks/useOverlayKeyboard.ts
|
|
6
|
+
import React from "react";
|
|
7
|
+
var FOCUSABLE = [
|
|
8
|
+
"a[href]",
|
|
9
|
+
"button:not([disabled])",
|
|
10
|
+
"input:not([disabled]):not([type='hidden'])",
|
|
11
|
+
"select:not([disabled])",
|
|
12
|
+
"textarea:not([disabled])",
|
|
13
|
+
"[tabindex]:not([tabindex='-1'])"
|
|
14
|
+
].join(",");
|
|
15
|
+
var focusableIn = (el) => Array.from(el.querySelectorAll(FOCUSABLE)).filter(
|
|
16
|
+
// 화면에 없는 것은 제외 (display:none 등)
|
|
17
|
+
(n) => n.offsetWidth > 0 || n.offsetHeight > 0 || n === document.activeElement
|
|
18
|
+
);
|
|
19
|
+
var useEscapeKey = (enabled, onEscape) => {
|
|
20
|
+
React.useEffect(() => {
|
|
21
|
+
if (!enabled) return;
|
|
22
|
+
const onKey = (e) => {
|
|
23
|
+
if (e.key !== "Escape") return;
|
|
24
|
+
if (e.defaultPrevented) return;
|
|
25
|
+
e.preventDefault();
|
|
26
|
+
onEscape();
|
|
27
|
+
};
|
|
28
|
+
document.addEventListener("keydown", onKey);
|
|
29
|
+
return () => document.removeEventListener("keydown", onKey);
|
|
30
|
+
}, [enabled, onEscape]);
|
|
31
|
+
};
|
|
32
|
+
var useFocusTrap = (containerRef, enabled, options = {}) => {
|
|
33
|
+
const { trap = false, initialFocus } = options;
|
|
34
|
+
const restoreRef = React.useRef(null);
|
|
35
|
+
React.useEffect(() => {
|
|
36
|
+
if (!enabled) return;
|
|
37
|
+
restoreRef.current = document.activeElement;
|
|
38
|
+
const raf = requestAnimationFrame(() => {
|
|
39
|
+
const el = containerRef.current;
|
|
40
|
+
if (!el) return;
|
|
41
|
+
const target = initialFocus?.current ?? focusableIn(el)[0] ?? el;
|
|
42
|
+
if (!target.hasAttribute("tabindex") && !focusableIn(el).includes(target)) {
|
|
43
|
+
target.setAttribute("tabindex", "-1");
|
|
44
|
+
}
|
|
45
|
+
target.focus({ preventScroll: true });
|
|
46
|
+
});
|
|
47
|
+
return () => {
|
|
48
|
+
cancelAnimationFrame(raf);
|
|
49
|
+
const prev = restoreRef.current;
|
|
50
|
+
if (prev && document.contains(prev)) prev.focus({ preventScroll: true });
|
|
51
|
+
};
|
|
52
|
+
}, [enabled, containerRef, initialFocus]);
|
|
53
|
+
React.useEffect(() => {
|
|
54
|
+
if (!enabled || !trap) return;
|
|
55
|
+
const onKey = (e) => {
|
|
56
|
+
if (e.key !== "Tab") return;
|
|
57
|
+
const el = containerRef.current;
|
|
58
|
+
if (!el) return;
|
|
59
|
+
const items = focusableIn(el);
|
|
60
|
+
if (items.length === 0) {
|
|
61
|
+
e.preventDefault();
|
|
62
|
+
return;
|
|
63
|
+
}
|
|
64
|
+
const first = items[0];
|
|
65
|
+
const last = items[items.length - 1];
|
|
66
|
+
const active = document.activeElement;
|
|
67
|
+
if (e.shiftKey && (active === first || !el.contains(active))) {
|
|
68
|
+
e.preventDefault();
|
|
69
|
+
last.focus();
|
|
70
|
+
} else if (!e.shiftKey && (active === last || !el.contains(active))) {
|
|
71
|
+
e.preventDefault();
|
|
72
|
+
first.focus();
|
|
73
|
+
}
|
|
74
|
+
};
|
|
75
|
+
document.addEventListener("keydown", onKey);
|
|
76
|
+
return () => document.removeEventListener("keydown", onKey);
|
|
77
|
+
}, [enabled, trap, containerRef]);
|
|
78
|
+
};
|
|
79
|
+
|
|
5
80
|
// ../../node_modules/clsx/dist/clsx.mjs
|
|
6
81
|
function r(e) {
|
|
7
82
|
var t, f, n = "";
|
|
@@ -23,9 +98,12 @@ import { jsx, jsxs } from "react/jsx-runtime";
|
|
|
23
98
|
var ANIMATION_DURATION_MS = 250;
|
|
24
99
|
var Drawer = (props) => {
|
|
25
100
|
const { isOpen, onClose, placement = "right", size = "md", title, children } = props;
|
|
26
|
-
const [mounted, setMounted] =
|
|
27
|
-
const [visible, setVisible] =
|
|
28
|
-
|
|
101
|
+
const [mounted, setMounted] = React2.useState(false);
|
|
102
|
+
const [visible, setVisible] = React2.useState(false);
|
|
103
|
+
const panelRef = React2.useRef(null);
|
|
104
|
+
useEscapeKey(isOpen, onClose);
|
|
105
|
+
useFocusTrap(panelRef, isOpen && mounted, { trap: true });
|
|
106
|
+
React2.useEffect(() => {
|
|
29
107
|
if (isOpen) {
|
|
30
108
|
setMounted(true);
|
|
31
109
|
const t2 = setTimeout(() => setVisible(true), 1);
|
|
@@ -47,6 +125,7 @@ var Drawer = (props) => {
|
|
|
47
125
|
children: /* @__PURE__ */ jsxs(
|
|
48
126
|
"div",
|
|
49
127
|
{
|
|
128
|
+
ref: panelRef,
|
|
50
129
|
className: clsx_default("lib-xplat-drawer", placement, size, stateClass),
|
|
51
130
|
role: "dialog",
|
|
52
131
|
"aria-modal": "true",
|