@bigtablet/design-system 3.3.0 → 3.4.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/README.md +2 -0
- package/dist/index.css +250 -4
- package/dist/index.d.ts +125 -16
- package/dist/index.js +656 -308
- package/dist/styles/icon/_index.scss +5 -0
- package/dist/styles/token.scss +1 -0
- package/package.json +7 -7
package/dist/index.js
CHANGED
|
@@ -1,9 +1,9 @@
|
|
|
1
1
|
"use client";
|
|
2
2
|
import './index.css';
|
|
3
|
-
import * as
|
|
3
|
+
import * as React19 from 'react';
|
|
4
4
|
import { createContext, useRef, useState, useId, useEffect, useContext, useCallback, useMemo, Fragment, useLayoutEffect } from 'react';
|
|
5
5
|
import { useSpring, animated } from '@react-spring/web';
|
|
6
|
-
import { ChevronDown,
|
|
6
|
+
import { ChevronDown, ChevronRight, Globe, ChevronLeft, XCircle, AlertTriangle, CheckCircle2, Info, Search, Check, X, Image, ArrowUp, ArrowDown, ArrowUpDown, Bell, TriangleAlert } from 'lucide-react';
|
|
7
7
|
import { jsx, jsxs, Fragment as Fragment$1 } from 'react/jsx-runtime';
|
|
8
8
|
import { createPortal } from 'react-dom';
|
|
9
9
|
|
|
@@ -38,8 +38,8 @@ var FOCUSABLE_SELECTORS = [
|
|
|
38
38
|
'[tabindex]:not([tabindex="-1"])'
|
|
39
39
|
].join(", ");
|
|
40
40
|
function useFocusTrap(containerRef, isActive) {
|
|
41
|
-
const previousActiveElement =
|
|
42
|
-
|
|
41
|
+
const previousActiveElement = React19.useRef(null);
|
|
42
|
+
React19.useEffect(() => {
|
|
43
43
|
if (!isActive) return;
|
|
44
44
|
const container = containerRef.current;
|
|
45
45
|
if (!container) return;
|
|
@@ -116,14 +116,14 @@ function getServerSnapshot() {
|
|
|
116
116
|
return false;
|
|
117
117
|
}
|
|
118
118
|
function useReducedMotion() {
|
|
119
|
-
return
|
|
119
|
+
return React19.useSyncExternalStore(subscribe, getSnapshot, getServerSnapshot);
|
|
120
120
|
}
|
|
121
121
|
var useSafeLayoutEffect = typeof window !== "undefined" ? useLayoutEffect : useEffect;
|
|
122
122
|
function useSpringHover({
|
|
123
123
|
scale = 1.02,
|
|
124
124
|
lift = -2
|
|
125
125
|
} = {}) {
|
|
126
|
-
const [hovered, setHovered] =
|
|
126
|
+
const [hovered, setHovered] = React19.useState(false);
|
|
127
127
|
const reduced = useReducedMotion();
|
|
128
128
|
const style = useSpring({
|
|
129
129
|
transform: hovered ? `translateY(${lift}px) scale(${scale})` : "translateY(0px) scale(1)",
|
|
@@ -167,6 +167,15 @@ function useSpringPresence({
|
|
|
167
167
|
}
|
|
168
168
|
});
|
|
169
169
|
}
|
|
170
|
+
|
|
171
|
+
// src/styles/icon/index.ts
|
|
172
|
+
var iconSize = {
|
|
173
|
+
xs: 14,
|
|
174
|
+
sm: 16,
|
|
175
|
+
md: 18,
|
|
176
|
+
lg: 20,
|
|
177
|
+
xl: 32
|
|
178
|
+
};
|
|
170
179
|
var Accordion = ({
|
|
171
180
|
items,
|
|
172
181
|
multiple = false,
|
|
@@ -178,7 +187,7 @@ var Accordion = ({
|
|
|
178
187
|
...props
|
|
179
188
|
}) => {
|
|
180
189
|
const isControlled = controlledKeys !== void 0;
|
|
181
|
-
const [internalKeys, setInternalKeys] =
|
|
190
|
+
const [internalKeys, setInternalKeys] = React19.useState(defaultOpenKeys);
|
|
182
191
|
const open = isControlled ? controlledKeys ?? [] : internalKeys;
|
|
183
192
|
const toggle = (key) => {
|
|
184
193
|
const isOpen = open.includes(key);
|
|
@@ -206,7 +215,7 @@ var Accordion = ({
|
|
|
206
215
|
/* @__PURE__ */ jsx(
|
|
207
216
|
ChevronDown,
|
|
208
217
|
{
|
|
209
|
-
size:
|
|
218
|
+
size: iconSize.lg,
|
|
210
219
|
className: cn("accordion_chevron", isOpen && "accordion_chevron_open"),
|
|
211
220
|
"aria-hidden": "true"
|
|
212
221
|
}
|
|
@@ -245,7 +254,7 @@ var Avatar = ({
|
|
|
245
254
|
style,
|
|
246
255
|
...props
|
|
247
256
|
}) => {
|
|
248
|
-
const [imgFailed, setImgFailed] =
|
|
257
|
+
const [imgFailed, setImgFailed] = React19.useState(false);
|
|
249
258
|
const showImage = src && !imgFailed;
|
|
250
259
|
const initials = getInitials(name);
|
|
251
260
|
return /* @__PURE__ */ jsx(
|
|
@@ -394,7 +403,7 @@ var Breadcrumb = ({
|
|
|
394
403
|
className,
|
|
395
404
|
...props
|
|
396
405
|
}) => {
|
|
397
|
-
const sep = separator ?? /* @__PURE__ */ jsx(ChevronRight, { size:
|
|
406
|
+
const sep = separator ?? /* @__PURE__ */ jsx(ChevronRight, { size: iconSize.xs, "aria-hidden": "true" });
|
|
398
407
|
return /* @__PURE__ */ jsx("nav", { "aria-label": "Breadcrumb", className: cn("breadcrumb", className), ...props, children: /* @__PURE__ */ jsx("ol", { className: "breadcrumb_list", children: items.map((item, idx) => {
|
|
399
408
|
const isLast = idx === items.length - 1;
|
|
400
409
|
return (
|
|
@@ -463,12 +472,12 @@ var ErrorState = ({
|
|
|
463
472
|
);
|
|
464
473
|
};
|
|
465
474
|
var Menu = ({ items, trigger, align = "start" }) => {
|
|
466
|
-
const [open, setOpen] =
|
|
467
|
-
const wrapperRef =
|
|
468
|
-
const itemRefs =
|
|
469
|
-
const menuId =
|
|
475
|
+
const [open, setOpen] = React19.useState(false);
|
|
476
|
+
const wrapperRef = React19.useRef(null);
|
|
477
|
+
const itemRefs = React19.useRef([]);
|
|
478
|
+
const menuId = React19.useId();
|
|
470
479
|
const style = useSpringPresence({ visible: open, from: "translateY(-4px)" });
|
|
471
|
-
|
|
480
|
+
React19.useEffect(() => {
|
|
472
481
|
if (!open) return;
|
|
473
482
|
const handleClick = (e) => {
|
|
474
483
|
if (!wrapperRef.current?.contains(e.target)) setOpen(false);
|
|
@@ -483,7 +492,7 @@ var Menu = ({ items, trigger, align = "start" }) => {
|
|
|
483
492
|
document.removeEventListener("keydown", handleEsc);
|
|
484
493
|
};
|
|
485
494
|
}, [open]);
|
|
486
|
-
|
|
495
|
+
React19.useEffect(() => {
|
|
487
496
|
const active = document.activeElement;
|
|
488
497
|
if (!open || active && itemRefs.current.includes(active)) return;
|
|
489
498
|
const first = items.findIndex((it) => !it.disabled);
|
|
@@ -529,7 +538,7 @@ var Menu = ({ items, trigger, align = "start" }) => {
|
|
|
529
538
|
break;
|
|
530
539
|
}
|
|
531
540
|
};
|
|
532
|
-
const triggerWithProps =
|
|
541
|
+
const triggerWithProps = React19.cloneElement(
|
|
533
542
|
trigger,
|
|
534
543
|
{
|
|
535
544
|
onClick: () => setOpen((o) => !o),
|
|
@@ -746,9 +755,16 @@ var LocaleSwitcher = ({ locale }) => {
|
|
|
746
755
|
"aria-controls": menuId,
|
|
747
756
|
onClick: () => setOpen((p) => !p),
|
|
748
757
|
children: [
|
|
749
|
-
/* @__PURE__ */ jsx(Globe, { size:
|
|
758
|
+
/* @__PURE__ */ jsx(Globe, { size: iconSize.sm, "aria-hidden": "true" }),
|
|
750
759
|
!locale.hideLabel && /* @__PURE__ */ jsx("span", { className: "nav_bar_locale_label", children: currentOption?.label ?? locale.current.toUpperCase() }),
|
|
751
|
-
/* @__PURE__ */ jsx(
|
|
760
|
+
/* @__PURE__ */ jsx(
|
|
761
|
+
ChevronDown,
|
|
762
|
+
{
|
|
763
|
+
size: iconSize.xs,
|
|
764
|
+
"aria-hidden": "true",
|
|
765
|
+
className: "nav_bar_locale_chevron"
|
|
766
|
+
}
|
|
767
|
+
)
|
|
752
768
|
]
|
|
753
769
|
}
|
|
754
770
|
),
|
|
@@ -812,9 +828,9 @@ var Sidebar = ({
|
|
|
812
828
|
...props
|
|
813
829
|
}) => {
|
|
814
830
|
const isControlled = collapsedProp !== void 0;
|
|
815
|
-
const [internalCollapsed, setInternalCollapsed] =
|
|
831
|
+
const [internalCollapsed, setInternalCollapsed] = React19.useState(defaultCollapsed);
|
|
816
832
|
const collapsed = isControlled ? collapsedProp : internalCollapsed;
|
|
817
|
-
const toggle =
|
|
833
|
+
const toggle = React19.useCallback(() => {
|
|
818
834
|
const next = !collapsed;
|
|
819
835
|
if (!isControlled) setInternalCollapsed(next);
|
|
820
836
|
onCollapsedChange?.(next);
|
|
@@ -846,7 +862,7 @@ var Sidebar = ({
|
|
|
846
862
|
onClick: toggle,
|
|
847
863
|
"aria-label": toggleLabel,
|
|
848
864
|
"aria-expanded": !collapsed,
|
|
849
|
-
children: collapsed ? /* @__PURE__ */ jsx(ChevronRight, { size:
|
|
865
|
+
children: collapsed ? /* @__PURE__ */ jsx(ChevronRight, { size: iconSize.xs }) : /* @__PURE__ */ jsx(ChevronLeft, { size: iconSize.xs })
|
|
850
866
|
}
|
|
851
867
|
)
|
|
852
868
|
]
|
|
@@ -887,9 +903,9 @@ var SidebarSection = ({ label, className, children, ...props }) => {
|
|
|
887
903
|
children
|
|
888
904
|
] });
|
|
889
905
|
};
|
|
890
|
-
var TabsContext =
|
|
906
|
+
var TabsContext = React19.createContext(null);
|
|
891
907
|
function useTabsContext() {
|
|
892
|
-
const ctx =
|
|
908
|
+
const ctx = React19.useContext(TabsContext);
|
|
893
909
|
if (!ctx) {
|
|
894
910
|
throw new Error(
|
|
895
911
|
'[Bigtablet DS] <Tab>, <TabList>, <TabPanel>\uC740 \uBC18\uB4DC\uC2DC <Tabs> \uC548\uC5D0 \uC788\uC5B4\uC57C \uD569\uB2C8\uB2E4.\n\n\uC62C\uBC14\uB978 \uC0AC\uC6A9 \uC608:\n <Tabs defaultValue="a">\n <TabList>\n <Tab value="a">A</Tab>\n </TabList>\n <TabPanel value="a">...</TabPanel>\n </Tabs>'
|
|
@@ -908,17 +924,17 @@ var Tabs = ({
|
|
|
908
924
|
...props
|
|
909
925
|
}) => {
|
|
910
926
|
const isControlled = controlledValue !== void 0;
|
|
911
|
-
const [internalValue, setInternalValue] =
|
|
927
|
+
const [internalValue, setInternalValue] = React19.useState(defaultValue);
|
|
912
928
|
const value = isControlled ? controlledValue : internalValue;
|
|
913
|
-
const setValue =
|
|
929
|
+
const setValue = React19.useCallback(
|
|
914
930
|
(v) => {
|
|
915
931
|
if (!isControlled) setInternalValue(v);
|
|
916
932
|
onValueChange?.(v);
|
|
917
933
|
},
|
|
918
934
|
[isControlled, onValueChange]
|
|
919
935
|
);
|
|
920
|
-
const idPrefix =
|
|
921
|
-
const ctx =
|
|
936
|
+
const idPrefix = React19.useId();
|
|
937
|
+
const ctx = React19.useMemo(
|
|
922
938
|
() => ({ value, setValue, variant, size, idPrefix }),
|
|
923
939
|
[value, setValue, variant, size, idPrefix]
|
|
924
940
|
);
|
|
@@ -926,9 +942,9 @@ var Tabs = ({
|
|
|
926
942
|
};
|
|
927
943
|
var TabList = ({ ariaLabel, className, children, ...props }) => {
|
|
928
944
|
const { variant } = useTabsContext();
|
|
929
|
-
const listRef =
|
|
930
|
-
const [indicator, setIndicator] =
|
|
931
|
-
const [hasMounted, setHasMounted] =
|
|
945
|
+
const listRef = React19.useRef(null);
|
|
946
|
+
const [indicator, setIndicator] = React19.useState(null);
|
|
947
|
+
const [hasMounted, setHasMounted] = React19.useState(false);
|
|
932
948
|
useSafeLayoutEffect(() => {
|
|
933
949
|
const list = listRef.current;
|
|
934
950
|
if (!list) return;
|
|
@@ -1077,15 +1093,15 @@ var Popover = ({
|
|
|
1077
1093
|
className
|
|
1078
1094
|
}) => {
|
|
1079
1095
|
const isControlled = openProp !== void 0;
|
|
1080
|
-
const [internalOpen, setInternalOpen] =
|
|
1096
|
+
const [internalOpen, setInternalOpen] = React19.useState(defaultOpen);
|
|
1081
1097
|
const open = isControlled ? openProp : internalOpen;
|
|
1082
|
-
const [shouldRender, setShouldRender] =
|
|
1098
|
+
const [shouldRender, setShouldRender] = React19.useState(open ?? false);
|
|
1083
1099
|
if (open && !shouldRender) setShouldRender(true);
|
|
1084
|
-
const wrapperRef =
|
|
1085
|
-
const popoverRef =
|
|
1086
|
-
const previousFocusRef =
|
|
1087
|
-
const popoverId =
|
|
1088
|
-
const setOpen =
|
|
1100
|
+
const wrapperRef = React19.useRef(null);
|
|
1101
|
+
const popoverRef = React19.useRef(null);
|
|
1102
|
+
const previousFocusRef = React19.useRef(null);
|
|
1103
|
+
const popoverId = React19.useId();
|
|
1104
|
+
const setOpen = React19.useCallback(
|
|
1089
1105
|
(next) => {
|
|
1090
1106
|
if (!isControlled) setInternalOpen(next);
|
|
1091
1107
|
onOpenChange?.(next);
|
|
@@ -1105,7 +1121,7 @@ var Popover = ({
|
|
|
1105
1121
|
}
|
|
1106
1122
|
})();
|
|
1107
1123
|
const style = useSpringPresence({ visible: open, from: fromTransform, onExitComplete: () => setShouldRender(false) });
|
|
1108
|
-
|
|
1124
|
+
React19.useEffect(() => {
|
|
1109
1125
|
if (!open) return;
|
|
1110
1126
|
previousFocusRef.current = document.activeElement;
|
|
1111
1127
|
const node = popoverRef.current;
|
|
@@ -1113,7 +1129,7 @@ var Popover = ({
|
|
|
1113
1129
|
const focusable = node.querySelector(FOCUSABLE_SELECTORS2);
|
|
1114
1130
|
(focusable ?? node).focus();
|
|
1115
1131
|
}, [open]);
|
|
1116
|
-
|
|
1132
|
+
React19.useEffect(() => {
|
|
1117
1133
|
if (!open) return;
|
|
1118
1134
|
const handleClick = (e) => {
|
|
1119
1135
|
if (!wrapperRef.current?.contains(e.target)) setOpen(false);
|
|
@@ -1131,7 +1147,7 @@ var Popover = ({
|
|
|
1131
1147
|
document.removeEventListener("keydown", handleKeyDown);
|
|
1132
1148
|
};
|
|
1133
1149
|
}, [open, setOpen]);
|
|
1134
|
-
const triggerWithProps =
|
|
1150
|
+
const triggerWithProps = React19.cloneElement(
|
|
1135
1151
|
trigger,
|
|
1136
1152
|
{
|
|
1137
1153
|
onClick: (e) => {
|
|
@@ -1170,18 +1186,18 @@ var Tooltip = ({
|
|
|
1170
1186
|
disabled = false,
|
|
1171
1187
|
children
|
|
1172
1188
|
}) => {
|
|
1173
|
-
const [open, setOpen] =
|
|
1174
|
-
const timerRef =
|
|
1175
|
-
const tooltipId =
|
|
1176
|
-
const show =
|
|
1189
|
+
const [open, setOpen] = React19.useState(false);
|
|
1190
|
+
const timerRef = React19.useRef(null);
|
|
1191
|
+
const tooltipId = React19.useId();
|
|
1192
|
+
const show = React19.useCallback(() => {
|
|
1177
1193
|
if (timerRef.current) clearTimeout(timerRef.current);
|
|
1178
1194
|
timerRef.current = setTimeout(() => setOpen(true), delay);
|
|
1179
1195
|
}, [delay]);
|
|
1180
|
-
const hide =
|
|
1196
|
+
const hide = React19.useCallback(() => {
|
|
1181
1197
|
if (timerRef.current) clearTimeout(timerRef.current);
|
|
1182
1198
|
setOpen(false);
|
|
1183
1199
|
}, []);
|
|
1184
|
-
|
|
1200
|
+
React19.useEffect(() => {
|
|
1185
1201
|
return () => {
|
|
1186
1202
|
if (timerRef.current) clearTimeout(timerRef.current);
|
|
1187
1203
|
};
|
|
@@ -1201,7 +1217,7 @@ var Tooltip = ({
|
|
|
1201
1217
|
const style = useSpringPresence({ visible: open, from: fromTransform });
|
|
1202
1218
|
const child = children;
|
|
1203
1219
|
const childProps = child.props;
|
|
1204
|
-
const trigger =
|
|
1220
|
+
const trigger = React19.cloneElement(child, {
|
|
1205
1221
|
onMouseEnter: (e) => {
|
|
1206
1222
|
childProps.onMouseEnter?.(e);
|
|
1207
1223
|
show();
|
|
@@ -1745,10 +1761,10 @@ var Button = ({
|
|
|
1745
1761
|
] });
|
|
1746
1762
|
};
|
|
1747
1763
|
var ICONS = {
|
|
1748
|
-
info: /* @__PURE__ */ jsx(Info, { size:
|
|
1749
|
-
success: /* @__PURE__ */ jsx(CheckCircle2, { size:
|
|
1750
|
-
warning: /* @__PURE__ */ jsx(AlertTriangle, { size:
|
|
1751
|
-
error: /* @__PURE__ */ jsx(XCircle, { size:
|
|
1764
|
+
info: /* @__PURE__ */ jsx(Info, { size: iconSize.lg, "aria-hidden": "true" }),
|
|
1765
|
+
success: /* @__PURE__ */ jsx(CheckCircle2, { size: iconSize.lg, "aria-hidden": "true" }),
|
|
1766
|
+
warning: /* @__PURE__ */ jsx(AlertTriangle, { size: iconSize.lg, "aria-hidden": "true" }),
|
|
1767
|
+
error: /* @__PURE__ */ jsx(XCircle, { size: iconSize.lg, "aria-hidden": "true" })
|
|
1752
1768
|
};
|
|
1753
1769
|
var AlertContext = createContext(null);
|
|
1754
1770
|
var useAlert = () => {
|
|
@@ -1804,12 +1820,12 @@ var AlertModal = ({
|
|
|
1804
1820
|
onCancel,
|
|
1805
1821
|
onClose
|
|
1806
1822
|
}) => {
|
|
1807
|
-
const panelRef =
|
|
1808
|
-
const titleId =
|
|
1809
|
-
const messageId =
|
|
1823
|
+
const panelRef = React19.useRef(null);
|
|
1824
|
+
const titleId = React19.useId();
|
|
1825
|
+
const messageId = React19.useId();
|
|
1810
1826
|
const [shouldRender, setShouldRender] = useState(isOpen);
|
|
1811
1827
|
useFocusTrap(panelRef, isOpen);
|
|
1812
|
-
|
|
1828
|
+
React19.useEffect(() => {
|
|
1813
1829
|
if (isOpen) setShouldRender(true);
|
|
1814
1830
|
}, [isOpen]);
|
|
1815
1831
|
const overlayStyle = useSpring({
|
|
@@ -1917,12 +1933,12 @@ var Checkbox = ({
|
|
|
1917
1933
|
ref,
|
|
1918
1934
|
...props
|
|
1919
1935
|
}) => {
|
|
1920
|
-
const inputRef =
|
|
1921
|
-
|
|
1936
|
+
const inputRef = React19.useRef(null);
|
|
1937
|
+
React19.useImperativeHandle(
|
|
1922
1938
|
ref,
|
|
1923
1939
|
() => inputRef.current
|
|
1924
1940
|
);
|
|
1925
|
-
|
|
1941
|
+
React19.useEffect(() => {
|
|
1926
1942
|
if (!inputRef.current) return;
|
|
1927
1943
|
inputRef.current.indeterminate = Boolean(indeterminate);
|
|
1928
1944
|
}, [indeterminate]);
|
|
@@ -2094,40 +2110,91 @@ var Chip = ({
|
|
|
2094
2110
|
)
|
|
2095
2111
|
] });
|
|
2096
2112
|
};
|
|
2097
|
-
var
|
|
2098
|
-
|
|
2099
|
-
|
|
2100
|
-
|
|
2101
|
-
|
|
2102
|
-
|
|
2103
|
-
|
|
2104
|
-
|
|
2105
|
-
|
|
2106
|
-
|
|
2107
|
-
|
|
2108
|
-
|
|
2109
|
-
|
|
2113
|
+
var normalizeForSearch = (s) => s.toLowerCase().replace(/\s+/g, "");
|
|
2114
|
+
var Dropdown = (props) => {
|
|
2115
|
+
const {
|
|
2116
|
+
id,
|
|
2117
|
+
label,
|
|
2118
|
+
placeholder = "Select\u2026",
|
|
2119
|
+
options,
|
|
2120
|
+
disabled,
|
|
2121
|
+
size = "md",
|
|
2122
|
+
className,
|
|
2123
|
+
searchable = false,
|
|
2124
|
+
searchPlaceholder = "\uAC80\uC0C9\u2026",
|
|
2125
|
+
emptyText = "\uACB0\uACFC \uC5C6\uC74C",
|
|
2126
|
+
selectedSummary = (count) => `${count}\uAC1C \uC120\uD0DD`
|
|
2127
|
+
} = props;
|
|
2128
|
+
const multiple = props.multiple === true;
|
|
2110
2129
|
const internalId = useId();
|
|
2111
2130
|
const dropdownId = id ?? internalId;
|
|
2112
|
-
const isControlled = value !== void 0;
|
|
2113
|
-
const [
|
|
2114
|
-
|
|
2131
|
+
const isControlled = props.value !== void 0;
|
|
2132
|
+
const [internalSingle, setInternalSingle] = useState(
|
|
2133
|
+
() => props.multiple === true ? null : props.defaultValue ?? null
|
|
2134
|
+
);
|
|
2135
|
+
const [internalMulti, setInternalMulti] = useState(
|
|
2136
|
+
() => props.multiple === true ? props.defaultValue ?? [] : []
|
|
2137
|
+
);
|
|
2115
2138
|
const [isOpen, setIsOpen] = useState(false);
|
|
2116
2139
|
const [activeIndex, setActiveIndex] = useState(-1);
|
|
2117
2140
|
const [dropUp, setDropUp] = useState(false);
|
|
2141
|
+
const [searchText, setSearchText] = useState("");
|
|
2142
|
+
const [committedQuery, setCommittedQuery] = useState("");
|
|
2143
|
+
const isComposingRef = useRef(false);
|
|
2118
2144
|
const wrapperRef = useRef(null);
|
|
2119
2145
|
const controlRef = useRef(null);
|
|
2120
|
-
const
|
|
2121
|
-
|
|
2122
|
-
|
|
2123
|
-
|
|
2124
|
-
|
|
2146
|
+
const searchRef = useRef(null);
|
|
2147
|
+
const selectedValues = useMemo(() => {
|
|
2148
|
+
if (multiple) {
|
|
2149
|
+
const v2 = isControlled ? props.value : internalMulti;
|
|
2150
|
+
return v2 ?? [];
|
|
2151
|
+
}
|
|
2152
|
+
const v = isControlled ? props.value : internalSingle;
|
|
2153
|
+
return v != null ? [v] : [];
|
|
2154
|
+
}, [multiple, isControlled, props.value, internalMulti, internalSingle]);
|
|
2155
|
+
const visibleOptions = useMemo(() => {
|
|
2156
|
+
if (!searchable) return options;
|
|
2157
|
+
const q = normalizeForSearch(committedQuery);
|
|
2158
|
+
if (q === "") return options;
|
|
2159
|
+
return options.filter((o) => normalizeForSearch(o.label).includes(q));
|
|
2160
|
+
}, [options, searchable, committedQuery]);
|
|
2161
|
+
const selectSingle = useCallback(
|
|
2125
2162
|
(next) => {
|
|
2126
2163
|
const option = options.find((o) => o.value === next) ?? null;
|
|
2127
|
-
if (!isControlled)
|
|
2128
|
-
(
|
|
2164
|
+
if (!isControlled) setInternalSingle(next);
|
|
2165
|
+
if (props.multiple !== true) {
|
|
2166
|
+
(props.onValueChange ?? props.onChange)?.(next, option);
|
|
2167
|
+
}
|
|
2129
2168
|
},
|
|
2130
|
-
[isControlled, onValueChange, onChange
|
|
2169
|
+
[isControlled, options, props.multiple, props.onValueChange, props.onChange]
|
|
2170
|
+
);
|
|
2171
|
+
const toggleMultiple = useCallback(
|
|
2172
|
+
(opt) => {
|
|
2173
|
+
const exists = selectedValues.includes(opt.value);
|
|
2174
|
+
const nextValues = exists ? selectedValues.filter((v) => v !== opt.value) : [...selectedValues, opt.value];
|
|
2175
|
+
const nextOptions = nextValues.map((v) => options.find((o) => o.value === v)).filter((o) => Boolean(o));
|
|
2176
|
+
if (!isControlled) setInternalMulti(nextValues);
|
|
2177
|
+
if (props.multiple === true) {
|
|
2178
|
+
(props.onValueChange ?? props.onChange)?.(nextValues, nextOptions);
|
|
2179
|
+
}
|
|
2180
|
+
},
|
|
2181
|
+
[selectedValues, options, isControlled, props.multiple, props.onValueChange, props.onChange]
|
|
2182
|
+
);
|
|
2183
|
+
const closePanel = useCallback(() => {
|
|
2184
|
+
setIsOpen(false);
|
|
2185
|
+
if (searchable) controlRef.current?.focus();
|
|
2186
|
+
}, [searchable]);
|
|
2187
|
+
const selectOption = useCallback(
|
|
2188
|
+
(opt) => {
|
|
2189
|
+
if (opt.disabled) return;
|
|
2190
|
+
if (multiple) {
|
|
2191
|
+
toggleMultiple(opt);
|
|
2192
|
+
} else {
|
|
2193
|
+
selectSingle(opt.value);
|
|
2194
|
+
closePanel();
|
|
2195
|
+
}
|
|
2196
|
+
},
|
|
2197
|
+
[multiple, toggleMultiple, selectSingle, closePanel]
|
|
2131
2198
|
);
|
|
2132
2199
|
useEffect(() => {
|
|
2133
2200
|
const handleOutsideClick = (e) => {
|
|
@@ -2138,31 +2205,33 @@ var Dropdown = ({
|
|
|
2138
2205
|
document.addEventListener("mousedown", handleOutsideClick);
|
|
2139
2206
|
return () => document.removeEventListener("mousedown", handleOutsideClick);
|
|
2140
2207
|
}, []);
|
|
2141
|
-
const moveActive = (
|
|
2142
|
-
|
|
2143
|
-
|
|
2144
|
-
|
|
2145
|
-
|
|
2146
|
-
|
|
2147
|
-
let i = activeIndex;
|
|
2148
|
-
const len = options.length;
|
|
2149
|
-
for (let step = 0; step < len; step++) {
|
|
2150
|
-
i = (i + dir + len) % len;
|
|
2151
|
-
if (!options[i].disabled) {
|
|
2152
|
-
setActiveIndex(i);
|
|
2153
|
-
break;
|
|
2208
|
+
const moveActive = useCallback(
|
|
2209
|
+
(dir) => {
|
|
2210
|
+
if (visibleOptions.length === 0) return;
|
|
2211
|
+
if (!isOpen) {
|
|
2212
|
+
setIsOpen(true);
|
|
2213
|
+
return;
|
|
2154
2214
|
}
|
|
2155
|
-
|
|
2156
|
-
|
|
2157
|
-
|
|
2158
|
-
|
|
2159
|
-
|
|
2160
|
-
|
|
2161
|
-
|
|
2162
|
-
|
|
2163
|
-
|
|
2164
|
-
|
|
2165
|
-
|
|
2215
|
+
let i = activeIndex;
|
|
2216
|
+
if (i === -1) {
|
|
2217
|
+
i = dir === 1 ? -1 : 0;
|
|
2218
|
+
}
|
|
2219
|
+
const len = visibleOptions.length;
|
|
2220
|
+
for (let step = 0; step < len; step++) {
|
|
2221
|
+
i = (i + dir + len) % len;
|
|
2222
|
+
if (!visibleOptions[i].disabled) {
|
|
2223
|
+
setActiveIndex(i);
|
|
2224
|
+
break;
|
|
2225
|
+
}
|
|
2226
|
+
}
|
|
2227
|
+
},
|
|
2228
|
+
[visibleOptions, isOpen, activeIndex]
|
|
2229
|
+
);
|
|
2230
|
+
const commitActive = useCallback(() => {
|
|
2231
|
+
if (activeIndex < 0 || activeIndex >= visibleOptions.length) return;
|
|
2232
|
+
selectOption(visibleOptions[activeIndex]);
|
|
2233
|
+
}, [activeIndex, visibleOptions, selectOption]);
|
|
2234
|
+
const onControlKeyDown = (e) => {
|
|
2166
2235
|
if (disabled) return;
|
|
2167
2236
|
switch (e.key) {
|
|
2168
2237
|
case " ":
|
|
@@ -2182,13 +2251,13 @@ var Dropdown = ({
|
|
|
2182
2251
|
case "Home":
|
|
2183
2252
|
e.preventDefault();
|
|
2184
2253
|
setIsOpen(true);
|
|
2185
|
-
setActiveIndex(
|
|
2254
|
+
setActiveIndex(visibleOptions.findIndex((o) => !o.disabled));
|
|
2186
2255
|
break;
|
|
2187
2256
|
case "End":
|
|
2188
2257
|
e.preventDefault();
|
|
2189
2258
|
setIsOpen(true);
|
|
2190
|
-
for (let i =
|
|
2191
|
-
if (!
|
|
2259
|
+
for (let i = visibleOptions.length - 1; i >= 0; i--) {
|
|
2260
|
+
if (!visibleOptions[i].disabled) {
|
|
2192
2261
|
setActiveIndex(i);
|
|
2193
2262
|
break;
|
|
2194
2263
|
}
|
|
@@ -2200,16 +2269,46 @@ var Dropdown = ({
|
|
|
2200
2269
|
break;
|
|
2201
2270
|
}
|
|
2202
2271
|
};
|
|
2272
|
+
const onSearchKeyDown = (e) => {
|
|
2273
|
+
if (e.nativeEvent.isComposing) return;
|
|
2274
|
+
switch (e.key) {
|
|
2275
|
+
case "ArrowDown":
|
|
2276
|
+
e.preventDefault();
|
|
2277
|
+
moveActive(1);
|
|
2278
|
+
break;
|
|
2279
|
+
case "ArrowUp":
|
|
2280
|
+
e.preventDefault();
|
|
2281
|
+
moveActive(-1);
|
|
2282
|
+
break;
|
|
2283
|
+
case "Enter":
|
|
2284
|
+
e.preventDefault();
|
|
2285
|
+
commitActive();
|
|
2286
|
+
break;
|
|
2287
|
+
case "Escape":
|
|
2288
|
+
e.preventDefault();
|
|
2289
|
+
closePanel();
|
|
2290
|
+
break;
|
|
2291
|
+
}
|
|
2292
|
+
};
|
|
2203
2293
|
useEffect(() => {
|
|
2204
2294
|
if (!isOpen) return;
|
|
2205
|
-
const
|
|
2206
|
-
|
|
2207
|
-
matchedIndex >= 0 ? matchedIndex : Math.max(
|
|
2208
|
-
0,
|
|
2209
|
-
options.findIndex((o) => !o.disabled)
|
|
2210
|
-
)
|
|
2295
|
+
const selectedIdx = visibleOptions.findIndex(
|
|
2296
|
+
(o) => selectedValues.includes(o.value) && !o.disabled
|
|
2211
2297
|
);
|
|
2212
|
-
|
|
2298
|
+
setActiveIndex(selectedIdx >= 0 ? selectedIdx : visibleOptions.findIndex((o) => !o.disabled));
|
|
2299
|
+
}, [isOpen, visibleOptions]);
|
|
2300
|
+
useEffect(() => {
|
|
2301
|
+
if (!isOpen) {
|
|
2302
|
+
setSearchText("");
|
|
2303
|
+
setCommittedQuery("");
|
|
2304
|
+
isComposingRef.current = false;
|
|
2305
|
+
}
|
|
2306
|
+
}, [isOpen]);
|
|
2307
|
+
useEffect(() => {
|
|
2308
|
+
if (isOpen && searchable) {
|
|
2309
|
+
searchRef.current?.focus();
|
|
2310
|
+
}
|
|
2311
|
+
}, [isOpen, searchable]);
|
|
2213
2312
|
useEffect(() => {
|
|
2214
2313
|
if (!isOpen || !controlRef.current) return;
|
|
2215
2314
|
const rect = controlRef.current.getBoundingClientRect();
|
|
@@ -2218,6 +2317,13 @@ var Dropdown = ({
|
|
|
2218
2317
|
const MIN_BELOW = 120;
|
|
2219
2318
|
setDropUp(spaceBelow < MIN_BELOW && spaceAbove > spaceBelow);
|
|
2220
2319
|
}, [isOpen]);
|
|
2320
|
+
const currentOption = useMemo(
|
|
2321
|
+
() => multiple ? null : options.find((o) => o.value === selectedValues[0]) ?? null,
|
|
2322
|
+
[multiple, options, selectedValues]
|
|
2323
|
+
);
|
|
2324
|
+
const hasSelection = selectedValues.length > 0;
|
|
2325
|
+
const showValue = multiple ? hasSelection : currentOption != null;
|
|
2326
|
+
const controlText = multiple ? hasSelection ? selectedSummary(selectedValues.length) : placeholder : currentOption ? currentOption.label : placeholder;
|
|
2221
2327
|
const rootClassName = cn("dropdown", `dropdown_size_${size}`, className);
|
|
2222
2328
|
const fieldsetClassName = cn("dropdown_fieldset", { is_open: isOpen, is_disabled: disabled });
|
|
2223
2329
|
const listClassName = cn("dropdown_list", { dropdown_list_up: dropUp });
|
|
@@ -2225,86 +2331,107 @@ var Dropdown = ({
|
|
|
2225
2331
|
visible: isOpen,
|
|
2226
2332
|
from: dropUp ? "translateY(4px)" : "translateY(-4px)"
|
|
2227
2333
|
});
|
|
2228
|
-
return /* @__PURE__ */ jsxs(
|
|
2229
|
-
"
|
|
2230
|
-
{
|
|
2231
|
-
|
|
2232
|
-
|
|
2233
|
-
|
|
2234
|
-
|
|
2235
|
-
|
|
2236
|
-
|
|
2334
|
+
return /* @__PURE__ */ jsxs("div", { ref: wrapperRef, className: rootClassName, children: [
|
|
2335
|
+
label && /* @__PURE__ */ jsx("label", { htmlFor: dropdownId, className: "dropdown_label", children: label }),
|
|
2336
|
+
/* @__PURE__ */ jsx("div", { className: fieldsetClassName, children: /* @__PURE__ */ jsxs(
|
|
2337
|
+
"button",
|
|
2338
|
+
{
|
|
2339
|
+
ref: controlRef,
|
|
2340
|
+
id: dropdownId,
|
|
2341
|
+
type: "button",
|
|
2342
|
+
className: cn("dropdown_control", { is_disabled: disabled }),
|
|
2343
|
+
"aria-haspopup": "listbox",
|
|
2344
|
+
"aria-expanded": isOpen,
|
|
2345
|
+
"aria-controls": `${dropdownId}_listbox`,
|
|
2346
|
+
onClick: () => !disabled && setIsOpen((o) => !o),
|
|
2347
|
+
onKeyDown: onControlKeyDown,
|
|
2348
|
+
disabled,
|
|
2349
|
+
children: [
|
|
2350
|
+
/* @__PURE__ */ jsx("span", { className: showValue ? "dropdown_value" : "dropdown_placeholder", children: controlText }),
|
|
2351
|
+
/* @__PURE__ */ jsx("span", { className: cn("dropdown_icon", { dropdown_icon_open: isOpen }), "aria-hidden": "true", children: /* @__PURE__ */ jsx(ChevronDown, { size: iconSize.lg }) })
|
|
2352
|
+
]
|
|
2353
|
+
}
|
|
2354
|
+
) }),
|
|
2355
|
+
isOpen && /* @__PURE__ */ jsxs(animated.div, { className: listClassName, style: listStyle, children: [
|
|
2356
|
+
searchable && /* @__PURE__ */ jsxs("div", { className: "dropdown_search", children: [
|
|
2357
|
+
/* @__PURE__ */ jsx("span", { className: "dropdown_search_icon", "aria-hidden": "true", children: /* @__PURE__ */ jsx(Search, { size: iconSize.sm }) }),
|
|
2358
|
+
/* @__PURE__ */ jsx(
|
|
2359
|
+
"input",
|
|
2237
2360
|
{
|
|
2238
|
-
ref:
|
|
2239
|
-
|
|
2240
|
-
|
|
2241
|
-
|
|
2242
|
-
"aria-
|
|
2361
|
+
ref: searchRef,
|
|
2362
|
+
type: "text",
|
|
2363
|
+
className: "dropdown_search_input",
|
|
2364
|
+
placeholder: searchPlaceholder,
|
|
2365
|
+
"aria-label": searchPlaceholder,
|
|
2366
|
+
autoComplete: "off",
|
|
2367
|
+
role: "combobox",
|
|
2368
|
+
"aria-autocomplete": "list",
|
|
2243
2369
|
"aria-expanded": isOpen,
|
|
2244
2370
|
"aria-controls": `${dropdownId}_listbox`,
|
|
2245
|
-
|
|
2246
|
-
|
|
2247
|
-
|
|
2248
|
-
|
|
2249
|
-
|
|
2250
|
-
|
|
2251
|
-
|
|
2252
|
-
|
|
2253
|
-
|
|
2254
|
-
|
|
2255
|
-
|
|
2256
|
-
|
|
2257
|
-
|
|
2258
|
-
|
|
2259
|
-
|
|
2260
|
-
|
|
2261
|
-
|
|
2262
|
-
animated.div,
|
|
2263
|
-
{
|
|
2264
|
-
id: `${dropdownId}_listbox`,
|
|
2265
|
-
role: "listbox",
|
|
2266
|
-
className: listClassName,
|
|
2267
|
-
style: listStyle,
|
|
2268
|
-
children: options.map((opt, i) => {
|
|
2269
|
-
const selected = currentValue === opt.value;
|
|
2270
|
-
const active = i === activeIndex;
|
|
2271
|
-
return /* @__PURE__ */ jsxs(Fragment, { children: [
|
|
2272
|
-
/* @__PURE__ */ jsxs(
|
|
2273
|
-
"div",
|
|
2274
|
-
{
|
|
2275
|
-
role: "option",
|
|
2276
|
-
tabIndex: -1,
|
|
2277
|
-
"aria-selected": selected,
|
|
2278
|
-
"aria-disabled": opt.disabled ? true : void 0,
|
|
2279
|
-
className: cn("dropdown_option", {
|
|
2280
|
-
is_selected: selected,
|
|
2281
|
-
is_active: active,
|
|
2282
|
-
is_disabled: opt.disabled
|
|
2283
|
-
}),
|
|
2284
|
-
onMouseEnter: () => !opt.disabled && setActiveIndex(i),
|
|
2285
|
-
onClick: () => {
|
|
2286
|
-
if (opt.disabled) return;
|
|
2287
|
-
setValue(opt.value);
|
|
2288
|
-
setIsOpen(false);
|
|
2289
|
-
},
|
|
2290
|
-
children: [
|
|
2291
|
-
opt.leadingIcon && /* @__PURE__ */ jsx("span", { className: "dropdown_option_icon", children: opt.leadingIcon }),
|
|
2292
|
-
/* @__PURE__ */ jsxs("span", { className: "dropdown_option_content", children: [
|
|
2293
|
-
/* @__PURE__ */ jsx("span", { className: "dropdown_option_label", children: opt.label }),
|
|
2294
|
-
opt.supportingText && /* @__PURE__ */ jsx("span", { className: "dropdown_option_supporting", children: opt.supportingText })
|
|
2295
|
-
] }),
|
|
2296
|
-
(selected || opt.trailingIcon) && /* @__PURE__ */ jsx("span", { className: "dropdown_option_trailing", children: opt.trailingIcon ?? /* @__PURE__ */ jsx(Check, { size: 16, "aria-hidden": "true" }) })
|
|
2297
|
-
]
|
|
2298
|
-
}
|
|
2299
|
-
),
|
|
2300
|
-
opt.showDivider && /* @__PURE__ */ jsx("hr", { className: "dropdown_option_divider" })
|
|
2301
|
-
] }, opt.value);
|
|
2302
|
-
})
|
|
2371
|
+
"aria-activedescendant": activeIndex >= 0 && visibleOptions[activeIndex] ? `${dropdownId}_option_${activeIndex}` : void 0,
|
|
2372
|
+
value: searchText,
|
|
2373
|
+
onChange: (e) => {
|
|
2374
|
+
const v = e.target.value;
|
|
2375
|
+
setSearchText(v);
|
|
2376
|
+
if (!isComposingRef.current) setCommittedQuery(v);
|
|
2377
|
+
},
|
|
2378
|
+
onCompositionStart: () => {
|
|
2379
|
+
isComposingRef.current = true;
|
|
2380
|
+
},
|
|
2381
|
+
onCompositionEnd: (e) => {
|
|
2382
|
+
isComposingRef.current = false;
|
|
2383
|
+
const v = e.currentTarget.value;
|
|
2384
|
+
setSearchText(v);
|
|
2385
|
+
setCommittedQuery(v);
|
|
2386
|
+
},
|
|
2387
|
+
onKeyDown: onSearchKeyDown
|
|
2303
2388
|
}
|
|
2304
2389
|
)
|
|
2305
|
-
]
|
|
2306
|
-
|
|
2307
|
-
|
|
2390
|
+
] }),
|
|
2391
|
+
/* @__PURE__ */ jsx(
|
|
2392
|
+
"div",
|
|
2393
|
+
{
|
|
2394
|
+
id: `${dropdownId}_listbox`,
|
|
2395
|
+
role: "listbox",
|
|
2396
|
+
className: "dropdown_options",
|
|
2397
|
+
"aria-multiselectable": multiple || void 0,
|
|
2398
|
+
children: visibleOptions.length === 0 ? searchable && /* @__PURE__ */ jsx("div", { className: "dropdown_empty", children: emptyText }) : visibleOptions.map((opt, i) => {
|
|
2399
|
+
const selected = selectedValues.includes(opt.value);
|
|
2400
|
+
const active = i === activeIndex;
|
|
2401
|
+
return /* @__PURE__ */ jsxs(Fragment, { children: [
|
|
2402
|
+
/* @__PURE__ */ jsxs(
|
|
2403
|
+
"div",
|
|
2404
|
+
{
|
|
2405
|
+
id: `${dropdownId}_option_${i}`,
|
|
2406
|
+
role: "option",
|
|
2407
|
+
tabIndex: -1,
|
|
2408
|
+
"aria-selected": selected,
|
|
2409
|
+
"aria-disabled": opt.disabled ? true : void 0,
|
|
2410
|
+
className: cn("dropdown_option", {
|
|
2411
|
+
is_selected: selected,
|
|
2412
|
+
is_active: active,
|
|
2413
|
+
is_disabled: opt.disabled
|
|
2414
|
+
}),
|
|
2415
|
+
onMouseEnter: () => !opt.disabled && setActiveIndex(i),
|
|
2416
|
+
onClick: () => selectOption(opt),
|
|
2417
|
+
children: [
|
|
2418
|
+
multiple && /* @__PURE__ */ jsx("span", { className: "dropdown_option_check", "aria-hidden": "true", children: selected && /* @__PURE__ */ jsx(Check, { size: iconSize.sm }) }),
|
|
2419
|
+
opt.leadingIcon && /* @__PURE__ */ jsx("span", { className: "dropdown_option_icon", children: opt.leadingIcon }),
|
|
2420
|
+
/* @__PURE__ */ jsxs("span", { className: "dropdown_option_content", children: [
|
|
2421
|
+
/* @__PURE__ */ jsx("span", { className: "dropdown_option_label", children: opt.label }),
|
|
2422
|
+
opt.supportingText && /* @__PURE__ */ jsx("span", { className: "dropdown_option_supporting", children: opt.supportingText })
|
|
2423
|
+
] }),
|
|
2424
|
+
(opt.trailingIcon || !multiple && selected) && /* @__PURE__ */ jsx("span", { className: "dropdown_option_trailing", children: opt.trailingIcon ?? /* @__PURE__ */ jsx(Check, { size: iconSize.sm, "aria-hidden": "true" }) })
|
|
2425
|
+
]
|
|
2426
|
+
}
|
|
2427
|
+
),
|
|
2428
|
+
opt.showDivider && /* @__PURE__ */ jsx("hr", { className: "dropdown_option_divider" })
|
|
2429
|
+
] }, opt.value);
|
|
2430
|
+
})
|
|
2431
|
+
}
|
|
2432
|
+
)
|
|
2433
|
+
] })
|
|
2434
|
+
] });
|
|
2308
2435
|
};
|
|
2309
2436
|
var pad = (n) => String(n).padStart(2, "0");
|
|
2310
2437
|
var getDaysInMonth = (year, month) => new Date(year, month, 0).getDate();
|
|
@@ -2329,9 +2456,9 @@ var DatePicker = ({
|
|
|
2329
2456
|
minDateSrFormat = "Minimum date: {date}",
|
|
2330
2457
|
selectableRangeUntilTodaySrText = "Selectable up to today"
|
|
2331
2458
|
}) => {
|
|
2332
|
-
const groupId =
|
|
2333
|
-
const constraintId =
|
|
2334
|
-
const { todayYear, todayMonth, todayDay } =
|
|
2459
|
+
const groupId = React19.useId();
|
|
2460
|
+
const constraintId = React19.useId();
|
|
2461
|
+
const { todayYear, todayMonth, todayDay } = React19.useMemo(() => {
|
|
2335
2462
|
const now = /* @__PURE__ */ new Date();
|
|
2336
2463
|
return {
|
|
2337
2464
|
todayYear: now.getFullYear(),
|
|
@@ -2340,7 +2467,7 @@ var DatePicker = ({
|
|
|
2340
2467
|
};
|
|
2341
2468
|
}, []);
|
|
2342
2469
|
const endYear = endYearProp ?? todayYear + 10;
|
|
2343
|
-
const parsed =
|
|
2470
|
+
const parsed = React19.useMemo(() => {
|
|
2344
2471
|
if (!value) return { year: 0, month: 0, day: 0 };
|
|
2345
2472
|
const [y, m, d] = value.split("-").map(Number);
|
|
2346
2473
|
return {
|
|
@@ -2349,7 +2476,7 @@ var DatePicker = ({
|
|
|
2349
2476
|
day: d || 0
|
|
2350
2477
|
};
|
|
2351
2478
|
}, [value]);
|
|
2352
|
-
const min =
|
|
2479
|
+
const min = React19.useMemo(() => {
|
|
2353
2480
|
if (!minDate) return { year: 0, month: 0, day: 0 };
|
|
2354
2481
|
const [y, m, d] = minDate.split("-").map(Number);
|
|
2355
2482
|
return {
|
|
@@ -2369,7 +2496,7 @@ var DatePicker = ({
|
|
|
2369
2496
|
min.year > 0 && min.month > 0 && year === min.year && month === min.month ? min.day : 1
|
|
2370
2497
|
)
|
|
2371
2498
|
);
|
|
2372
|
-
const maxDay =
|
|
2499
|
+
const maxDay = React19.useMemo(() => {
|
|
2373
2500
|
if (!year || !month) return 31;
|
|
2374
2501
|
const daysInMonth = getDaysInMonth(year, month);
|
|
2375
2502
|
if (selectableRange === "until-today" && year === todayYear && month === todayMonth) {
|
|
@@ -2377,28 +2504,28 @@ var DatePicker = ({
|
|
|
2377
2504
|
}
|
|
2378
2505
|
return daysInMonth;
|
|
2379
2506
|
}, [year, month, selectableRange, todayYear, todayMonth, todayDay]);
|
|
2380
|
-
const yearOptions =
|
|
2507
|
+
const yearOptions = React19.useMemo(
|
|
2381
2508
|
() => range(startYear, maxYear).map((y) => ({
|
|
2382
2509
|
value: String(y),
|
|
2383
2510
|
label: String(y)
|
|
2384
2511
|
})),
|
|
2385
2512
|
[startYear, maxYear]
|
|
2386
2513
|
);
|
|
2387
|
-
const monthOptions =
|
|
2514
|
+
const monthOptions = React19.useMemo(
|
|
2388
2515
|
() => range(minMonth, Math.max(minMonth, maxMonth)).map((m) => ({
|
|
2389
2516
|
value: String(m),
|
|
2390
2517
|
label: pad(m)
|
|
2391
2518
|
})),
|
|
2392
2519
|
[minMonth, maxMonth]
|
|
2393
2520
|
);
|
|
2394
|
-
const dayOptions =
|
|
2521
|
+
const dayOptions = React19.useMemo(
|
|
2395
2522
|
() => range(minDay, Math.max(minDay, maxDay)).map((d) => ({
|
|
2396
2523
|
value: String(d),
|
|
2397
2524
|
label: pad(d)
|
|
2398
2525
|
})),
|
|
2399
2526
|
[minDay, maxDay]
|
|
2400
2527
|
);
|
|
2401
|
-
const emit =
|
|
2528
|
+
const emit = React19.useCallback(
|
|
2402
2529
|
(yy, mm, dd) => {
|
|
2403
2530
|
const cb = onValueChange ?? onChange;
|
|
2404
2531
|
if (mode === "year-month") {
|
|
@@ -2410,7 +2537,7 @@ var DatePicker = ({
|
|
|
2410
2537
|
},
|
|
2411
2538
|
[mode, onValueChange, onChange]
|
|
2412
2539
|
);
|
|
2413
|
-
const handleYearChange =
|
|
2540
|
+
const handleYearChange = React19.useCallback(
|
|
2414
2541
|
(raw) => {
|
|
2415
2542
|
if (!raw) return;
|
|
2416
2543
|
const newYear = Number(raw);
|
|
@@ -2427,14 +2554,14 @@ var DatePicker = ({
|
|
|
2427
2554
|
},
|
|
2428
2555
|
[month, day, min.year, min.month, selectableRange, todayYear, todayMonth, emit]
|
|
2429
2556
|
);
|
|
2430
|
-
const handleMonthChange =
|
|
2557
|
+
const handleMonthChange = React19.useCallback(
|
|
2431
2558
|
(raw) => {
|
|
2432
2559
|
if (!raw || !year) return;
|
|
2433
2560
|
emit(year, Number(raw), day || void 0);
|
|
2434
2561
|
},
|
|
2435
2562
|
[year, day, emit]
|
|
2436
2563
|
);
|
|
2437
|
-
const handleDayChange =
|
|
2564
|
+
const handleDayChange = React19.useCallback(
|
|
2438
2565
|
(raw) => {
|
|
2439
2566
|
if (!raw || !year || !month) return;
|
|
2440
2567
|
emit(year, month, Number(raw));
|
|
@@ -2509,6 +2636,119 @@ var Divider = ({ weight = "standard", className, ...props }) => {
|
|
|
2509
2636
|
const dividerClassName = cn("divider", `divider_weight_${weight}`, className);
|
|
2510
2637
|
return /* @__PURE__ */ jsx("hr", { className: dividerClassName, ...props });
|
|
2511
2638
|
};
|
|
2639
|
+
var SLIDE_FROM = {
|
|
2640
|
+
left: "translateX(-100%)",
|
|
2641
|
+
right: "translateX(100%)",
|
|
2642
|
+
bottom: "translateY(100%)"
|
|
2643
|
+
};
|
|
2644
|
+
var Drawer = ({
|
|
2645
|
+
open,
|
|
2646
|
+
onClose,
|
|
2647
|
+
placement = "right",
|
|
2648
|
+
size = 360,
|
|
2649
|
+
title,
|
|
2650
|
+
footer,
|
|
2651
|
+
closeOnOverlay = true,
|
|
2652
|
+
showCloseIcon = true,
|
|
2653
|
+
closeLabel = "\uB2EB\uAE30",
|
|
2654
|
+
ariaLabel,
|
|
2655
|
+
children,
|
|
2656
|
+
className,
|
|
2657
|
+
...props
|
|
2658
|
+
}) => {
|
|
2659
|
+
const panelRef = React19.useRef(null);
|
|
2660
|
+
const titleId = React19.useId();
|
|
2661
|
+
const [shouldRender, setShouldRender] = React19.useState(open);
|
|
2662
|
+
const reduced = useReducedMotion();
|
|
2663
|
+
useFocusTrap(panelRef, open);
|
|
2664
|
+
if (open && !shouldRender) setShouldRender(true);
|
|
2665
|
+
const overlayStyle = useSpringPresence({
|
|
2666
|
+
visible: open,
|
|
2667
|
+
from: "translateY(0px)",
|
|
2668
|
+
onExitComplete: () => setShouldRender(false)
|
|
2669
|
+
});
|
|
2670
|
+
const slideFrom = SLIDE_FROM[placement];
|
|
2671
|
+
const slideRest = placement === "bottom" ? "translateY(0%)" : "translateX(0%)";
|
|
2672
|
+
const panelStyle = useSpring({
|
|
2673
|
+
from: { transform: slideFrom },
|
|
2674
|
+
to: { transform: open ? slideRest : slideFrom },
|
|
2675
|
+
immediate: reduced,
|
|
2676
|
+
config: { tension: 280, friction: 28, clamp: !open }
|
|
2677
|
+
});
|
|
2678
|
+
React19.useEffect(() => {
|
|
2679
|
+
if (!open) return;
|
|
2680
|
+
const body = document.body;
|
|
2681
|
+
const openModals = parseInt(body.dataset.openModals || "0", 10);
|
|
2682
|
+
if (openModals === 0) {
|
|
2683
|
+
body.dataset.originalOverflow = window.getComputedStyle(body).overflow;
|
|
2684
|
+
body.style.overflow = "hidden";
|
|
2685
|
+
}
|
|
2686
|
+
body.dataset.openModals = String(openModals + 1);
|
|
2687
|
+
return () => {
|
|
2688
|
+
const currentOpenModals = parseInt(body.dataset.openModals || "1", 10);
|
|
2689
|
+
const nextOpenModals = currentOpenModals - 1;
|
|
2690
|
+
if (nextOpenModals === 0) {
|
|
2691
|
+
body.style.overflow = body.dataset.originalOverflow || "";
|
|
2692
|
+
delete body.dataset.openModals;
|
|
2693
|
+
delete body.dataset.originalOverflow;
|
|
2694
|
+
} else {
|
|
2695
|
+
body.dataset.openModals = String(nextOpenModals);
|
|
2696
|
+
}
|
|
2697
|
+
};
|
|
2698
|
+
}, [open]);
|
|
2699
|
+
if (!open && !shouldRender) return null;
|
|
2700
|
+
const hasTitle = !!title;
|
|
2701
|
+
const sizeValue = typeof size === "number" ? `${size}px` : size;
|
|
2702
|
+
const panelSizeStyle = placement === "bottom" ? { height: sizeValue } : { width: sizeValue };
|
|
2703
|
+
return /* @__PURE__ */ jsx(
|
|
2704
|
+
animated.div,
|
|
2705
|
+
{
|
|
2706
|
+
className: cn("drawer", `drawer_placement_${placement}`),
|
|
2707
|
+
style: overlayStyle,
|
|
2708
|
+
role: "dialog",
|
|
2709
|
+
"aria-modal": "true",
|
|
2710
|
+
"aria-labelledby": hasTitle && !ariaLabel ? titleId : void 0,
|
|
2711
|
+
"aria-label": !hasTitle ? ariaLabel ?? "Dialog" : ariaLabel,
|
|
2712
|
+
onClick: () => closeOnOverlay && onClose?.(),
|
|
2713
|
+
onKeyDown: (e) => {
|
|
2714
|
+
if (e.key === "Escape") {
|
|
2715
|
+
e.stopPropagation();
|
|
2716
|
+
onClose?.();
|
|
2717
|
+
}
|
|
2718
|
+
},
|
|
2719
|
+
children: /* @__PURE__ */ jsxs(
|
|
2720
|
+
animated.div,
|
|
2721
|
+
{
|
|
2722
|
+
ref: panelRef,
|
|
2723
|
+
className: cn("drawer_panel", className),
|
|
2724
|
+
style: { ...panelStyle, ...panelSizeStyle },
|
|
2725
|
+
role: "document",
|
|
2726
|
+
onClick: (e) => e.stopPropagation(),
|
|
2727
|
+
onKeyDown: (e) => {
|
|
2728
|
+
if (e.key !== "Escape") e.stopPropagation();
|
|
2729
|
+
},
|
|
2730
|
+
...props,
|
|
2731
|
+
children: [
|
|
2732
|
+
showCloseIcon && onClose && /* @__PURE__ */ jsx(
|
|
2733
|
+
"button",
|
|
2734
|
+
{
|
|
2735
|
+
type: "button",
|
|
2736
|
+
className: "drawer_close",
|
|
2737
|
+
onClick: onClose,
|
|
2738
|
+
"aria-label": closeLabel,
|
|
2739
|
+
children: /* @__PURE__ */ jsx(X, { size: iconSize.md, "aria-hidden": "true" })
|
|
2740
|
+
}
|
|
2741
|
+
),
|
|
2742
|
+
title && /* @__PURE__ */ jsx("div", { className: "drawer_header", children: /* @__PURE__ */ jsx("h2", { id: titleId, className: "drawer_title", children: title }) }),
|
|
2743
|
+
children && /* @__PURE__ */ jsx("div", { className: "drawer_body", children }),
|
|
2744
|
+
footer && /* @__PURE__ */ jsx("div", { className: "drawer_footer", children: footer })
|
|
2745
|
+
]
|
|
2746
|
+
}
|
|
2747
|
+
)
|
|
2748
|
+
}
|
|
2749
|
+
);
|
|
2750
|
+
};
|
|
2751
|
+
Drawer.displayName = "Drawer";
|
|
2512
2752
|
var FileInput = ({
|
|
2513
2753
|
label = "Choose file",
|
|
2514
2754
|
onFiles,
|
|
@@ -2522,11 +2762,11 @@ var FileInput = ({
|
|
|
2522
2762
|
onChange,
|
|
2523
2763
|
...props
|
|
2524
2764
|
}) => {
|
|
2525
|
-
const inputId =
|
|
2526
|
-
const helperId =
|
|
2527
|
-
const inputRef =
|
|
2528
|
-
const [previewUrls, setPreviewUrls] =
|
|
2529
|
-
const previewUrlsRef =
|
|
2765
|
+
const inputId = React19.useId();
|
|
2766
|
+
const helperId = React19.useId();
|
|
2767
|
+
const inputRef = React19.useRef(null);
|
|
2768
|
+
const [previewUrls, setPreviewUrls] = React19.useState([]);
|
|
2769
|
+
const previewUrlsRef = React19.useRef([]);
|
|
2530
2770
|
const isPreviewVariant = variant === "preview";
|
|
2531
2771
|
const showPreview = isPreviewVariant || preview;
|
|
2532
2772
|
const handleChange = (e) => {
|
|
@@ -2567,7 +2807,7 @@ var FileInput = ({
|
|
|
2567
2807
|
}
|
|
2568
2808
|
onFiles?.(null);
|
|
2569
2809
|
};
|
|
2570
|
-
|
|
2810
|
+
React19.useEffect(() => {
|
|
2571
2811
|
return () => {
|
|
2572
2812
|
for (const url of previewUrlsRef.current) {
|
|
2573
2813
|
URL.revokeObjectURL(url);
|
|
@@ -2614,7 +2854,7 @@ var FileInput = ({
|
|
|
2614
2854
|
}
|
|
2615
2855
|
)
|
|
2616
2856
|
) : /* @__PURE__ */ jsxs("span", { className: "file_input_preview_empty", children: [
|
|
2617
|
-
/* @__PURE__ */ jsx(Image, { size:
|
|
2857
|
+
/* @__PURE__ */ jsx(Image, { size: iconSize.xl, "aria-hidden": "true" }),
|
|
2618
2858
|
/* @__PURE__ */ jsx("span", { className: "file_input_preview_empty_text", children: label })
|
|
2619
2859
|
] })
|
|
2620
2860
|
}
|
|
@@ -2626,7 +2866,7 @@ var FileInput = ({
|
|
|
2626
2866
|
className: "file_input_preview_remove",
|
|
2627
2867
|
onClick: handleRemove,
|
|
2628
2868
|
"aria-label": "\uC774\uBBF8\uC9C0 \uC81C\uAC70",
|
|
2629
|
-
children: /* @__PURE__ */ jsx(X, { size:
|
|
2869
|
+
children: /* @__PURE__ */ jsx(X, { size: iconSize.xs, "aria-hidden": "true" })
|
|
2630
2870
|
}
|
|
2631
2871
|
),
|
|
2632
2872
|
supportingText && /* @__PURE__ */ jsx("span", { id: helperId, className: "file_input_helper", children: supportingText }),
|
|
@@ -2866,13 +3106,11 @@ var Modal = ({
|
|
|
2866
3106
|
ariaLabel,
|
|
2867
3107
|
...props
|
|
2868
3108
|
}) => {
|
|
2869
|
-
const panelRef =
|
|
2870
|
-
const titleId =
|
|
2871
|
-
const [shouldRender, setShouldRender] =
|
|
3109
|
+
const panelRef = React19.useRef(null);
|
|
3110
|
+
const titleId = React19.useId();
|
|
3111
|
+
const [shouldRender, setShouldRender] = React19.useState(open);
|
|
2872
3112
|
useFocusTrap(panelRef, open);
|
|
2873
|
-
|
|
2874
|
-
if (open) setShouldRender(true);
|
|
2875
|
-
}, [open]);
|
|
3113
|
+
if (open && !shouldRender) setShouldRender(true);
|
|
2876
3114
|
const overlayStyle = useSpring({
|
|
2877
3115
|
opacity: open ? 1 : 0,
|
|
2878
3116
|
config: { tension: 280, friction: 28, clamp: !open },
|
|
@@ -2885,7 +3123,7 @@ var Modal = ({
|
|
|
2885
3123
|
transform: open ? "scale(1) translateY(0px)" : "scale(0.96) translateY(-4px)",
|
|
2886
3124
|
config: { tension: 280, friction: 28, clamp: !open }
|
|
2887
3125
|
});
|
|
2888
|
-
|
|
3126
|
+
React19.useEffect(() => {
|
|
2889
3127
|
if (!open) return;
|
|
2890
3128
|
const body = document.body;
|
|
2891
3129
|
const openModals = parseInt(body.dataset.openModals || "0", 10);
|
|
@@ -2906,7 +3144,7 @@ var Modal = ({
|
|
|
2906
3144
|
}
|
|
2907
3145
|
};
|
|
2908
3146
|
}, [open]);
|
|
2909
|
-
if (!shouldRender) return null;
|
|
3147
|
+
if (!open && !shouldRender) return null;
|
|
2910
3148
|
const hasTitle = !!title;
|
|
2911
3149
|
return /* @__PURE__ */ jsx(
|
|
2912
3150
|
animated.div,
|
|
@@ -2944,7 +3182,7 @@ var Modal = ({
|
|
|
2944
3182
|
className: "modal_close",
|
|
2945
3183
|
onClick: onClose,
|
|
2946
3184
|
"aria-label": closeLabel,
|
|
2947
|
-
children: /* @__PURE__ */ jsx(X, { size:
|
|
3185
|
+
children: /* @__PURE__ */ jsx(X, { size: iconSize.md, "aria-hidden": "true" })
|
|
2948
3186
|
}
|
|
2949
3187
|
),
|
|
2950
3188
|
title && /* @__PURE__ */ jsx("h2", { id: titleId, className: "modal_title", children: title }),
|
|
@@ -2969,12 +3207,12 @@ var OtpInput = ({
|
|
|
2969
3207
|
ariaLabel = "OTP \uC785\uB825",
|
|
2970
3208
|
className
|
|
2971
3209
|
}) => {
|
|
2972
|
-
const inputsRef =
|
|
2973
|
-
const isTypingRef =
|
|
2974
|
-
|
|
3210
|
+
const inputsRef = React19.useRef([]);
|
|
3211
|
+
const isTypingRef = React19.useRef(false);
|
|
3212
|
+
React19.useEffect(() => {
|
|
2975
3213
|
if (autoFocus) inputsRef.current[0]?.focus();
|
|
2976
3214
|
}, [autoFocus]);
|
|
2977
|
-
const digits =
|
|
3215
|
+
const digits = React19.useMemo(() => {
|
|
2978
3216
|
const chars = value.split("").slice(0, length);
|
|
2979
3217
|
while (chars.length < length) chars.push("");
|
|
2980
3218
|
return chars;
|
|
@@ -3115,7 +3353,7 @@ var Pagination = ({
|
|
|
3115
3353
|
const emit = onPageChange ?? onChange;
|
|
3116
3354
|
const prevDisabled = page <= 1;
|
|
3117
3355
|
const nextDisabled = page >= totalPages;
|
|
3118
|
-
const items =
|
|
3356
|
+
const items = React19.useMemo(() => getPaginationItems(page, totalPages), [page, totalPages]);
|
|
3119
3357
|
return /* @__PURE__ */ jsxs("nav", { className: "pagination", "aria-label": "Pagination", children: [
|
|
3120
3358
|
/* @__PURE__ */ jsx(
|
|
3121
3359
|
"button",
|
|
@@ -3160,9 +3398,9 @@ var Pagination = ({
|
|
|
3160
3398
|
)
|
|
3161
3399
|
] });
|
|
3162
3400
|
};
|
|
3163
|
-
var RadioGroupContext =
|
|
3401
|
+
var RadioGroupContext = React19.createContext(null);
|
|
3164
3402
|
function useRadioGroupContext() {
|
|
3165
|
-
return
|
|
3403
|
+
return React19.useContext(RadioGroupContext);
|
|
3166
3404
|
}
|
|
3167
3405
|
var RadioGroup = ({
|
|
3168
3406
|
value: controlledValue,
|
|
@@ -3180,21 +3418,21 @@ var RadioGroup = ({
|
|
|
3180
3418
|
...props
|
|
3181
3419
|
}) => {
|
|
3182
3420
|
const isControlled = controlledValue !== void 0;
|
|
3183
|
-
const [internalValue, setInternalValue] =
|
|
3421
|
+
const [internalValue, setInternalValue] = React19.useState(defaultValue);
|
|
3184
3422
|
const value = isControlled ? controlledValue : internalValue;
|
|
3185
|
-
const generatedName =
|
|
3423
|
+
const generatedName = React19.useId();
|
|
3186
3424
|
const name = nameProp ?? generatedName;
|
|
3187
|
-
const idPrefix =
|
|
3425
|
+
const idPrefix = React19.useId();
|
|
3188
3426
|
const labelId = label ? `${idPrefix}-label` : void 0;
|
|
3189
3427
|
const helperId = supportingText ? `${idPrefix}-help` : void 0;
|
|
3190
|
-
const onChange =
|
|
3428
|
+
const onChange = React19.useCallback(
|
|
3191
3429
|
(next) => {
|
|
3192
3430
|
if (!isControlled) setInternalValue(next);
|
|
3193
3431
|
onValueChange?.(next);
|
|
3194
3432
|
},
|
|
3195
3433
|
[isControlled, onValueChange]
|
|
3196
3434
|
);
|
|
3197
|
-
const ctx =
|
|
3435
|
+
const ctx = React19.useMemo(
|
|
3198
3436
|
() => ({ name, value, onChange, size, disabled }),
|
|
3199
3437
|
[name, value, onChange, size, disabled]
|
|
3200
3438
|
);
|
|
@@ -3323,7 +3561,15 @@ var Table = ({
|
|
|
3323
3561
|
stickyHeader = false,
|
|
3324
3562
|
ariaLabel,
|
|
3325
3563
|
className,
|
|
3326
|
-
onRowClick
|
|
3564
|
+
onRowClick,
|
|
3565
|
+
sort,
|
|
3566
|
+
onSortChange,
|
|
3567
|
+
selectAllAriaLabel = "\uC804\uCCB4 \uC120\uD0DD",
|
|
3568
|
+
selectRowAriaLabel = (index) => `${index + 1}\uBC88\uC9F8 \uD589 \uC120\uD0DD`,
|
|
3569
|
+
selectable = false,
|
|
3570
|
+
rowKey,
|
|
3571
|
+
selectedKeys,
|
|
3572
|
+
onSelectionChange
|
|
3327
3573
|
}) => {
|
|
3328
3574
|
const wrapperClassName = cn(
|
|
3329
3575
|
"table_wrapper",
|
|
@@ -3332,69 +3578,171 @@ var Table = ({
|
|
|
3332
3578
|
className
|
|
3333
3579
|
);
|
|
3334
3580
|
const isEmpty = !isLoading && data.length === 0;
|
|
3581
|
+
const getRowKey = (item, index) => rowKey?.(item) ?? String(index);
|
|
3582
|
+
const allRowKeys = selectable ? data.map((item, index) => getRowKey(item, index)) : [];
|
|
3583
|
+
const selectedSet = React19.useMemo(() => new Set(selectedKeys ?? []), [selectedKeys]);
|
|
3584
|
+
const selectedCount = allRowKeys.filter((key) => selectedSet.has(key)).length;
|
|
3585
|
+
const isAllSelected = allRowKeys.length > 0 && selectedCount === allRowKeys.length;
|
|
3586
|
+
const isSomeSelected = selectedCount > 0 && !isAllSelected;
|
|
3587
|
+
const handleToggleAll = () => {
|
|
3588
|
+
const pageKeys = new Set(allRowKeys);
|
|
3589
|
+
const offPage = (selectedKeys ?? []).filter((k) => !pageKeys.has(k));
|
|
3590
|
+
onSelectionChange?.(isAllSelected ? offPage : [...offPage, ...allRowKeys]);
|
|
3591
|
+
};
|
|
3592
|
+
const handleToggleRow = (key) => {
|
|
3593
|
+
const current = selectedKeys ?? [];
|
|
3594
|
+
const next = current.includes(key) ? current.filter((k) => k !== key) : [...current, key];
|
|
3595
|
+
onSelectionChange?.(next);
|
|
3596
|
+
};
|
|
3597
|
+
const handleSortClick = (key) => {
|
|
3598
|
+
const next = sort?.key !== key ? { key, direction: "asc" } : sort.direction === "asc" ? { key, direction: "desc" } : void 0;
|
|
3599
|
+
onSortChange?.(next);
|
|
3600
|
+
};
|
|
3335
3601
|
return /* @__PURE__ */ jsxs("div", { className: wrapperClassName, children: [
|
|
3336
3602
|
/* @__PURE__ */ jsxs("table", { className: "table", "aria-label": ariaLabel, children: [
|
|
3337
|
-
/* @__PURE__ */ jsx("thead", { className: "table_thead", children: /* @__PURE__ */
|
|
3338
|
-
"th",
|
|
3339
|
-
|
|
3340
|
-
|
|
3341
|
-
|
|
3342
|
-
|
|
3343
|
-
|
|
3344
|
-
|
|
3345
|
-
|
|
3346
|
-
|
|
3603
|
+
/* @__PURE__ */ jsx("thead", { className: "table_thead", children: /* @__PURE__ */ jsxs("tr", { children: [
|
|
3604
|
+
selectable && /* @__PURE__ */ jsx("th", { scope: "col", className: "table_th table_th_checkbox", children: /* @__PURE__ */ jsx(
|
|
3605
|
+
Checkbox,
|
|
3606
|
+
{
|
|
3607
|
+
"aria-label": selectAllAriaLabel,
|
|
3608
|
+
checked: isAllSelected,
|
|
3609
|
+
indeterminate: isSomeSelected,
|
|
3610
|
+
disabled: isLoading || allRowKeys.length === 0,
|
|
3611
|
+
onChange: handleToggleAll
|
|
3612
|
+
}
|
|
3613
|
+
) }),
|
|
3614
|
+
columns.map((col) => {
|
|
3615
|
+
const isSortActive = Boolean(col.sortable) && sort?.key === col.key;
|
|
3616
|
+
const direction = isSortActive ? sort?.direction : void 0;
|
|
3617
|
+
const ariaSort = col.sortable ? direction === "asc" ? "ascending" : direction === "desc" ? "descending" : "none" : void 0;
|
|
3618
|
+
return /* @__PURE__ */ jsx(
|
|
3619
|
+
"th",
|
|
3620
|
+
{
|
|
3621
|
+
scope: "col",
|
|
3622
|
+
className: cn(
|
|
3623
|
+
"table_th",
|
|
3624
|
+
col.align && `table_align_${col.align}`,
|
|
3625
|
+
col.sortable && "table_th_sortable"
|
|
3626
|
+
),
|
|
3627
|
+
style: { width: col.width },
|
|
3628
|
+
"aria-sort": ariaSort,
|
|
3629
|
+
children: col.sortable ? /* @__PURE__ */ jsxs(
|
|
3630
|
+
"button",
|
|
3631
|
+
{
|
|
3632
|
+
type: "button",
|
|
3633
|
+
className: "table_sort_button",
|
|
3634
|
+
onClick: () => handleSortClick(col.key),
|
|
3635
|
+
disabled: isLoading,
|
|
3636
|
+
children: [
|
|
3637
|
+
/* @__PURE__ */ jsx("span", { className: "table_sort_label", children: col.header }),
|
|
3638
|
+
direction === "asc" ? /* @__PURE__ */ jsx(
|
|
3639
|
+
ArrowUp,
|
|
3640
|
+
{
|
|
3641
|
+
size: iconSize.sm,
|
|
3642
|
+
className: "table_sort_icon table_sort_icon_active",
|
|
3643
|
+
"aria-hidden": "true"
|
|
3644
|
+
}
|
|
3645
|
+
) : direction === "desc" ? /* @__PURE__ */ jsx(
|
|
3646
|
+
ArrowDown,
|
|
3647
|
+
{
|
|
3648
|
+
size: iconSize.sm,
|
|
3649
|
+
className: "table_sort_icon table_sort_icon_active",
|
|
3650
|
+
"aria-hidden": "true"
|
|
3651
|
+
}
|
|
3652
|
+
) : /* @__PURE__ */ jsx(
|
|
3653
|
+
ArrowUpDown,
|
|
3654
|
+
{
|
|
3655
|
+
size: iconSize.sm,
|
|
3656
|
+
className: "table_sort_icon",
|
|
3657
|
+
"aria-hidden": "true"
|
|
3658
|
+
}
|
|
3659
|
+
)
|
|
3660
|
+
]
|
|
3661
|
+
}
|
|
3662
|
+
) : col.header
|
|
3663
|
+
},
|
|
3664
|
+
col.key
|
|
3665
|
+
);
|
|
3666
|
+
})
|
|
3667
|
+
] }) }),
|
|
3347
3668
|
/* @__PURE__ */ jsx("tbody", { className: "table_tbody", children: isLoading ? Array.from({ length: skeletonRows }).map((_, rowIndex) => (
|
|
3348
3669
|
// biome-ignore lint/suspicious/noArrayIndexKey: skeleton rows have no stable identity
|
|
3349
|
-
/* @__PURE__ */
|
|
3350
|
-
"td",
|
|
3351
|
-
|
|
3352
|
-
className: cn("table_td", col.align && `table_align_${col.align}`),
|
|
3353
|
-
style: { width: col.width },
|
|
3354
|
-
children: /* @__PURE__ */ jsx(Skeleton, { variant: "text" })
|
|
3355
|
-
},
|
|
3356
|
-
col.key
|
|
3357
|
-
)) }, rowIndex)
|
|
3358
|
-
)) : data.map((item, rowIndex) => /* @__PURE__ */ jsx(
|
|
3359
|
-
"tr",
|
|
3360
|
-
{
|
|
3361
|
-
className: cn(
|
|
3362
|
-
"table_row",
|
|
3363
|
-
hoverable && "table_row_hoverable",
|
|
3364
|
-
onRowClick && "table_row_clickable"
|
|
3365
|
-
),
|
|
3366
|
-
role: onRowClick ? "button" : void 0,
|
|
3367
|
-
tabIndex: onRowClick ? 0 : void 0,
|
|
3368
|
-
onClick: onRowClick ? () => onRowClick(item, rowIndex) : void 0,
|
|
3369
|
-
onKeyDown: onRowClick ? (e) => {
|
|
3370
|
-
if (e.key === "Enter" || e.key === " ") {
|
|
3371
|
-
e.preventDefault();
|
|
3372
|
-
onRowClick(item, rowIndex);
|
|
3373
|
-
}
|
|
3374
|
-
} : void 0,
|
|
3375
|
-
children: columns.map((col) => /* @__PURE__ */ jsx(
|
|
3670
|
+
/* @__PURE__ */ jsxs("tr", { className: "table_row table_row_skeleton", children: [
|
|
3671
|
+
selectable && /* @__PURE__ */ jsx("td", { className: "table_td table_td_checkbox" }),
|
|
3672
|
+
columns.map((col) => /* @__PURE__ */ jsx(
|
|
3376
3673
|
"td",
|
|
3377
3674
|
{
|
|
3378
3675
|
className: cn("table_td", col.align && `table_align_${col.align}`),
|
|
3379
3676
|
style: { width: col.width },
|
|
3380
|
-
children: (
|
|
3381
|
-
if (col.render) return col.render(item, rowIndex);
|
|
3382
|
-
const value = item[col.key];
|
|
3383
|
-
return value === null || value === void 0 || value === "" ? "-" : String(value);
|
|
3384
|
-
})()
|
|
3677
|
+
children: /* @__PURE__ */ jsx(Skeleton, { variant: "text" })
|
|
3385
3678
|
},
|
|
3386
3679
|
col.key
|
|
3387
3680
|
))
|
|
3388
|
-
},
|
|
3389
|
-
|
|
3390
|
-
|
|
3681
|
+
] }, rowIndex)
|
|
3682
|
+
)) : data.map((item, rowIndex) => {
|
|
3683
|
+
const rowIdentity = selectable ? getRowKey(item, rowIndex) : void 0;
|
|
3684
|
+
const isSelected = rowIdentity !== void 0 && selectedSet.has(rowIdentity);
|
|
3685
|
+
return /* @__PURE__ */ jsxs(
|
|
3686
|
+
"tr",
|
|
3687
|
+
{
|
|
3688
|
+
className: cn(
|
|
3689
|
+
"table_row",
|
|
3690
|
+
hoverable && "table_row_hoverable",
|
|
3691
|
+
onRowClick && "table_row_clickable",
|
|
3692
|
+
isSelected && "table_row_selected"
|
|
3693
|
+
),
|
|
3694
|
+
"aria-selected": isSelected ? "true" : void 0,
|
|
3695
|
+
role: onRowClick && !selectable ? "button" : void 0,
|
|
3696
|
+
tabIndex: onRowClick ? 0 : void 0,
|
|
3697
|
+
onClick: onRowClick ? () => onRowClick(item, rowIndex) : void 0,
|
|
3698
|
+
onKeyDown: onRowClick ? (e) => {
|
|
3699
|
+
if (e.key === "Enter" || e.key === " ") {
|
|
3700
|
+
e.preventDefault();
|
|
3701
|
+
onRowClick(item, rowIndex);
|
|
3702
|
+
}
|
|
3703
|
+
} : void 0,
|
|
3704
|
+
children: [
|
|
3705
|
+
selectable && rowIdentity !== void 0 && /* @__PURE__ */ jsx(
|
|
3706
|
+
"td",
|
|
3707
|
+
{
|
|
3708
|
+
className: "table_td table_td_checkbox",
|
|
3709
|
+
onClick: (e) => e.stopPropagation(),
|
|
3710
|
+
onKeyDown: (e) => e.stopPropagation(),
|
|
3711
|
+
children: /* @__PURE__ */ jsx(
|
|
3712
|
+
Checkbox,
|
|
3713
|
+
{
|
|
3714
|
+
"aria-label": selectRowAriaLabel(rowIndex),
|
|
3715
|
+
checked: isSelected,
|
|
3716
|
+
onChange: () => handleToggleRow(rowIdentity)
|
|
3717
|
+
}
|
|
3718
|
+
)
|
|
3719
|
+
}
|
|
3720
|
+
),
|
|
3721
|
+
columns.map((col) => /* @__PURE__ */ jsx(
|
|
3722
|
+
"td",
|
|
3723
|
+
{
|
|
3724
|
+
className: cn("table_td", col.align && `table_align_${col.align}`),
|
|
3725
|
+
style: { width: col.width },
|
|
3726
|
+
children: (() => {
|
|
3727
|
+
if (col.render) return col.render(item, rowIndex);
|
|
3728
|
+
const value = item[col.key];
|
|
3729
|
+
return value === null || value === void 0 || value === "" ? "-" : String(value);
|
|
3730
|
+
})()
|
|
3731
|
+
},
|
|
3732
|
+
col.key
|
|
3733
|
+
))
|
|
3734
|
+
]
|
|
3735
|
+
},
|
|
3736
|
+
keyExtractor(item, rowIndex)
|
|
3737
|
+
);
|
|
3738
|
+
}) })
|
|
3391
3739
|
] }),
|
|
3392
3740
|
isEmpty && /* @__PURE__ */ jsx("div", { className: "table_empty", role: "status", children: emptyMessage })
|
|
3393
3741
|
] });
|
|
3394
3742
|
};
|
|
3395
|
-
var ThemeContext =
|
|
3743
|
+
var ThemeContext = React19.createContext(null);
|
|
3396
3744
|
var useTheme = () => {
|
|
3397
|
-
const ctx =
|
|
3745
|
+
const ctx = React19.useContext(ThemeContext);
|
|
3398
3746
|
if (!ctx) {
|
|
3399
3747
|
throw new Error(
|
|
3400
3748
|
'[Bigtablet DS] useTheme\uB294 <ThemeProvider> \uC548\uC5D0\uC11C\uB9CC \uC0AC\uC6A9 \uAC00\uB2A5\uD569\uB2C8\uB2E4.\n\n\uC571 \uCD5C\uC0C1\uB2E8\uC5D0 <ThemeProvider>\uB85C \uAC10\uC2F8\uC8FC\uC138\uC694:\n <ThemeProvider mode="system">\n <YourApp />\n </ThemeProvider>'
|
|
@@ -3418,15 +3766,15 @@ var ThemeProvider = ({
|
|
|
3418
3766
|
targetSelector,
|
|
3419
3767
|
children
|
|
3420
3768
|
}) => {
|
|
3421
|
-
const [mode, setModeState] =
|
|
3422
|
-
const [systemDark, setSystemDark] =
|
|
3423
|
-
|
|
3769
|
+
const [mode, setModeState] = React19.useState(defaultMode);
|
|
3770
|
+
const [systemDark, setSystemDark] = React19.useState(false);
|
|
3771
|
+
React19.useEffect(() => {
|
|
3424
3772
|
setModeState(readStored(storageKey) ?? defaultMode);
|
|
3425
3773
|
if (isClient) {
|
|
3426
3774
|
setSystemDark(window.matchMedia("(prefers-color-scheme: dark)").matches);
|
|
3427
3775
|
}
|
|
3428
3776
|
}, [storageKey, defaultMode]);
|
|
3429
|
-
|
|
3777
|
+
React19.useEffect(() => {
|
|
3430
3778
|
if (!isClient) return;
|
|
3431
3779
|
const mq = window.matchMedia("(prefers-color-scheme: dark)");
|
|
3432
3780
|
const handler = (e) => setSystemDark(e.matches);
|
|
@@ -3434,7 +3782,7 @@ var ThemeProvider = ({
|
|
|
3434
3782
|
return () => mq.removeEventListener("change", handler);
|
|
3435
3783
|
}, []);
|
|
3436
3784
|
const resolved = mode === "system" ? systemDark ? "dark" : "light" : mode;
|
|
3437
|
-
|
|
3785
|
+
React19.useEffect(() => {
|
|
3438
3786
|
if (!isClient) return;
|
|
3439
3787
|
const target = targetSelector ? document.querySelector(targetSelector) : document.documentElement;
|
|
3440
3788
|
if (!target) return;
|
|
@@ -3444,7 +3792,7 @@ var ThemeProvider = ({
|
|
|
3444
3792
|
target.setAttribute("data-theme", mode);
|
|
3445
3793
|
}
|
|
3446
3794
|
}, [mode, targetSelector]);
|
|
3447
|
-
const setMode =
|
|
3795
|
+
const setMode = React19.useCallback(
|
|
3448
3796
|
(next) => {
|
|
3449
3797
|
setModeState(next);
|
|
3450
3798
|
if (storageKey && isClient) {
|
|
@@ -3456,13 +3804,13 @@ var ThemeProvider = ({
|
|
|
3456
3804
|
},
|
|
3457
3805
|
[storageKey]
|
|
3458
3806
|
);
|
|
3459
|
-
const value =
|
|
3807
|
+
const value = React19.useMemo(
|
|
3460
3808
|
() => ({ mode, resolved, setMode }),
|
|
3461
3809
|
[mode, resolved, setMode]
|
|
3462
3810
|
);
|
|
3463
3811
|
return /* @__PURE__ */ jsx(ThemeContext.Provider, { value, children });
|
|
3464
3812
|
};
|
|
3465
|
-
var ClearIcon = () => /* @__PURE__ */ jsx(X, { size:
|
|
3813
|
+
var ClearIcon = () => /* @__PURE__ */ jsx(X, { size: iconSize.lg, "aria-hidden": "true" });
|
|
3466
3814
|
var TextField = ({
|
|
3467
3815
|
id,
|
|
3468
3816
|
label,
|
|
@@ -3704,24 +4052,24 @@ var Textarea = ({
|
|
|
3704
4052
|
] });
|
|
3705
4053
|
};
|
|
3706
4054
|
Textarea.displayName = "Textarea";
|
|
3707
|
-
var ToastContext =
|
|
4055
|
+
var ToastContext = React19.createContext(null);
|
|
3708
4056
|
var VARIANT_ICONS = {
|
|
3709
|
-
success: /* @__PURE__ */ jsx(CheckCircle2, { size:
|
|
3710
|
-
error: /* @__PURE__ */ jsx(XCircle, { size:
|
|
3711
|
-
warning: /* @__PURE__ */ jsx(AlertTriangle, { size:
|
|
3712
|
-
info: /* @__PURE__ */ jsx(Info, { size:
|
|
3713
|
-
default: /* @__PURE__ */ jsx(Bell, { size:
|
|
4057
|
+
success: /* @__PURE__ */ jsx(CheckCircle2, { size: iconSize.md }),
|
|
4058
|
+
error: /* @__PURE__ */ jsx(XCircle, { size: iconSize.md }),
|
|
4059
|
+
warning: /* @__PURE__ */ jsx(AlertTriangle, { size: iconSize.md }),
|
|
4060
|
+
info: /* @__PURE__ */ jsx(Info, { size: iconSize.md }),
|
|
4061
|
+
default: /* @__PURE__ */ jsx(Bell, { size: iconSize.md })
|
|
3714
4062
|
};
|
|
3715
4063
|
var ToastItemComponent = ({ item, onRemove, closeAriaLabel }) => {
|
|
3716
|
-
const [visible, setVisible] =
|
|
3717
|
-
const closingRef =
|
|
4064
|
+
const [visible, setVisible] = React19.useState(true);
|
|
4065
|
+
const closingRef = React19.useRef(false);
|
|
3718
4066
|
const style = useSpringPresence({
|
|
3719
4067
|
visible,
|
|
3720
4068
|
from: "translateX(20px)",
|
|
3721
4069
|
// 우측에서 슬라이드 인
|
|
3722
4070
|
onExitComplete: () => onRemove(item.id)
|
|
3723
4071
|
});
|
|
3724
|
-
const close =
|
|
4072
|
+
const close = React19.useCallback(() => {
|
|
3725
4073
|
if (closingRef.current) return;
|
|
3726
4074
|
closingRef.current = true;
|
|
3727
4075
|
setVisible(false);
|
|
@@ -3735,7 +4083,7 @@ var ToastItemComponent = ({ item, onRemove, closeAriaLabel }) => {
|
|
|
3735
4083
|
children: [
|
|
3736
4084
|
/* @__PURE__ */ jsx("span", { className: `toast_icon toast_icon_${item.variant}`, "aria-hidden": "true", children: VARIANT_ICONS[item.variant] }),
|
|
3737
4085
|
/* @__PURE__ */ jsx("span", { className: "toast_message", children: item.message }),
|
|
3738
|
-
/* @__PURE__ */ jsx("button", { type: "button", className: "toast_close", onClick: close, "aria-label": closeAriaLabel, children: /* @__PURE__ */ jsx(X, { size:
|
|
4086
|
+
/* @__PURE__ */ jsx("button", { type: "button", className: "toast_close", onClick: close, "aria-label": closeAriaLabel, children: /* @__PURE__ */ jsx(X, { size: iconSize.xs }) }),
|
|
3739
4087
|
/* @__PURE__ */ jsx(
|
|
3740
4088
|
"div",
|
|
3741
4089
|
{
|
|
@@ -3754,22 +4102,22 @@ var ToastProvider = ({
|
|
|
3754
4102
|
maxCount = 5,
|
|
3755
4103
|
closeAriaLabel = "Close"
|
|
3756
4104
|
}) => {
|
|
3757
|
-
const [toasts, setToasts] =
|
|
3758
|
-
const [isMounted, setIsMounted] =
|
|
3759
|
-
|
|
4105
|
+
const [toasts, setToasts] = React19.useState([]);
|
|
4106
|
+
const [isMounted, setIsMounted] = React19.useState(false);
|
|
4107
|
+
React19.useEffect(() => {
|
|
3760
4108
|
setIsMounted(true);
|
|
3761
4109
|
}, []);
|
|
3762
|
-
const addToast =
|
|
4110
|
+
const addToast = React19.useCallback(
|
|
3763
4111
|
(message, variant, duration = 3e3) => {
|
|
3764
4112
|
const id = crypto.randomUUID();
|
|
3765
4113
|
setToasts((prev) => [{ id, message, variant, duration }, ...prev].slice(0, maxCount));
|
|
3766
4114
|
},
|
|
3767
4115
|
[maxCount]
|
|
3768
4116
|
);
|
|
3769
|
-
const removeToast =
|
|
4117
|
+
const removeToast = React19.useCallback((id) => {
|
|
3770
4118
|
setToasts((prev) => prev.filter((t) => t.id !== id));
|
|
3771
4119
|
}, []);
|
|
3772
|
-
const contextValue =
|
|
4120
|
+
const contextValue = React19.useMemo(() => ({ addToast }), [addToast]);
|
|
3773
4121
|
return /* @__PURE__ */ jsxs(ToastContext.Provider, { value: contextValue, children: [
|
|
3774
4122
|
children,
|
|
3775
4123
|
isMounted && createPortal(
|
|
@@ -3830,7 +4178,7 @@ var Toggle = ({
|
|
|
3830
4178
|
...props
|
|
3831
4179
|
}) => {
|
|
3832
4180
|
const isControlled = checked !== void 0;
|
|
3833
|
-
const [innerChecked, setInnerChecked] =
|
|
4181
|
+
const [innerChecked, setInnerChecked] = React19.useState(!!defaultChecked);
|
|
3834
4182
|
const isOn = isControlled ? !!checked : innerChecked;
|
|
3835
4183
|
const handleToggle = () => {
|
|
3836
4184
|
if (disabled) return;
|
|
@@ -4000,4 +4348,4 @@ var Grid = ({
|
|
|
4000
4348
|
);
|
|
4001
4349
|
};
|
|
4002
4350
|
|
|
4003
|
-
export { Accordion, AlertProvider, Avatar, Badge, BottomNav, BottomNavItem, BottomNavSpacer, Breadcrumb, Button, Card, Checkbox, Chip, Container, DatePicker, Divider, Dropdown, EmptyState, ErrorState, FileInput, Grid, Hero, Icon, IconButton, LinearProgress, ListItem, MediaCard, Menu, Modal, NavBar, NavLink, OtpInput, Pagination, Popover, Radio, RadioGroup, Section, Sidebar, SidebarItem, SidebarSection, Skeleton, Spinner, Stack, Tab, TabList, TabPanel, Table, Tabs, TextField, Textarea, ThemeProvider, ToastProvider, Toggle, Tooltip, TopLoading, a11y, baseBorderWidth, baseColors, baseTypography, borderWidth, breakpoints, cn, colors, elevation, motion, opacity, radius, skeleton, spacing, typography, useAlert, useFocusTrap, useReducedMotion, useSpringHover, useSpringPresence, useTheme, useToast, zIndex };
|
|
4351
|
+
export { Accordion, AlertProvider, Avatar, Badge, BottomNav, BottomNavItem, BottomNavSpacer, Breadcrumb, Button, Card, Checkbox, Chip, Container, DatePicker, Divider, Drawer, Dropdown, EmptyState, ErrorState, FileInput, Grid, Hero, Icon, IconButton, LinearProgress, ListItem, MediaCard, Menu, Modal, NavBar, NavLink, OtpInput, Pagination, Popover, Radio, RadioGroup, Section, Sidebar, SidebarItem, SidebarSection, Skeleton, Spinner, Stack, Tab, TabList, TabPanel, Table, Tabs, TextField, Textarea, ThemeProvider, ToastProvider, Toggle, Tooltip, TopLoading, a11y, baseBorderWidth, baseColors, baseTypography, borderWidth, breakpoints, cn, colors, elevation, iconSize, motion, opacity, radius, skeleton, spacing, typography, useAlert, useFocusTrap, useReducedMotion, useSpringHover, useSpringPresence, useTheme, useToast, zIndex };
|