@bigtablet/design-system 3.7.0 → 3.9.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/LICENSE +53 -0
- package/README.md +12 -9
- package/dist/index.css +90 -45
- package/dist/index.d.ts +92 -13
- package/dist/index.js +356 -181
- package/dist/styles/colors/_index.scss +30 -0
- package/dist/styles/layout/_index.scss +17 -3
- package/dist/styles/motion/_index.scss +14 -1
- package/dist/vanilla/bigtablet.min.css +7 -1
- package/dist/vanilla/bigtablet.min.js +21 -21
- package/package.json +9 -7
package/dist/index.js
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
"use client";
|
|
2
2
|
import './index.css';
|
|
3
|
-
import * as
|
|
3
|
+
import * as React16 from 'react';
|
|
4
4
|
import { createContext, useRef, useState, useId, useEffect, useContext, useCallback, useMemo, Fragment, useImperativeHandle, useLayoutEffect } from 'react';
|
|
5
5
|
import { useSpring, animated } from '@react-spring/web';
|
|
6
6
|
import { ChevronDown, ChevronRight, Globe, ChevronLeft, ArrowUp, ArrowDown, ArrowUpDown, XCircle, AlertTriangle, CheckCircle2, Info, Bell, Search, Check, Image, X, TriangleAlert } from 'lucide-react';
|
|
@@ -58,15 +58,137 @@ function registerOverlay(onEscape) {
|
|
|
58
58
|
};
|
|
59
59
|
}
|
|
60
60
|
function useOverlayEscape(active, onEscape) {
|
|
61
|
-
const handlerRef =
|
|
62
|
-
|
|
61
|
+
const handlerRef = React16.useRef(onEscape);
|
|
62
|
+
React16.useEffect(() => {
|
|
63
63
|
handlerRef.current = onEscape;
|
|
64
64
|
});
|
|
65
|
-
|
|
65
|
+
React16.useEffect(() => {
|
|
66
66
|
if (!active) return;
|
|
67
67
|
return registerOverlay(() => handlerRef.current());
|
|
68
68
|
}, [active]);
|
|
69
69
|
}
|
|
70
|
+
var useSafeLayoutEffect = typeof window !== "undefined" ? useLayoutEffect : useEffect;
|
|
71
|
+
|
|
72
|
+
// src/utils/use-anchored-position.ts
|
|
73
|
+
var OPPOSITE = {
|
|
74
|
+
top: "bottom",
|
|
75
|
+
bottom: "top",
|
|
76
|
+
left: "right",
|
|
77
|
+
right: "left"
|
|
78
|
+
};
|
|
79
|
+
var isVertical = (side) => side === "top" || side === "bottom";
|
|
80
|
+
var clamp = (value, min, max) => (
|
|
81
|
+
// max < min(가용 공간이 플로팅보다 작을 때)이면 min(가장자리 여백)에 고정.
|
|
82
|
+
Math.max(min, Math.min(max, value))
|
|
83
|
+
);
|
|
84
|
+
var mainAxisStart = (side, anchor, floating, gap) => {
|
|
85
|
+
switch (side) {
|
|
86
|
+
case "top":
|
|
87
|
+
return anchor.top - gap - floating.height;
|
|
88
|
+
case "bottom":
|
|
89
|
+
return anchor.top + anchor.height + gap;
|
|
90
|
+
case "left":
|
|
91
|
+
return anchor.left - gap - floating.width;
|
|
92
|
+
case "right":
|
|
93
|
+
return anchor.left + anchor.width + gap;
|
|
94
|
+
}
|
|
95
|
+
};
|
|
96
|
+
var fitsMainAxis = (side, anchor, floating, viewport, gap, padding) => {
|
|
97
|
+
const start = mainAxisStart(side, anchor, floating, gap);
|
|
98
|
+
switch (side) {
|
|
99
|
+
case "top":
|
|
100
|
+
return start >= padding;
|
|
101
|
+
case "bottom":
|
|
102
|
+
return start + floating.height <= viewport.height - padding;
|
|
103
|
+
case "left":
|
|
104
|
+
return start >= padding;
|
|
105
|
+
case "right":
|
|
106
|
+
return start + floating.width <= viewport.width - padding;
|
|
107
|
+
}
|
|
108
|
+
};
|
|
109
|
+
function computeAnchoredPosition(anchor, floating, viewport, options) {
|
|
110
|
+
const gap = options.gap ?? 8;
|
|
111
|
+
const padding = options.padding;
|
|
112
|
+
const available = viewport.width - padding * 2;
|
|
113
|
+
const maxWidth = available;
|
|
114
|
+
const sized = {
|
|
115
|
+
width: Math.min(floating.width, available),
|
|
116
|
+
height: floating.height
|
|
117
|
+
};
|
|
118
|
+
let side = options.placement;
|
|
119
|
+
if (!fitsMainAxis(side, anchor, sized, viewport, gap, padding) && fitsMainAxis(OPPOSITE[side], anchor, sized, viewport, gap, padding)) {
|
|
120
|
+
side = OPPOSITE[side];
|
|
121
|
+
}
|
|
122
|
+
let x;
|
|
123
|
+
let y;
|
|
124
|
+
if (isVertical(side)) {
|
|
125
|
+
y = mainAxisStart(side, anchor, sized, gap);
|
|
126
|
+
x = anchor.left + anchor.width / 2 - sized.width / 2;
|
|
127
|
+
x = clamp(x, padding, viewport.width - padding - sized.width);
|
|
128
|
+
} else {
|
|
129
|
+
x = mainAxisStart(side, anchor, sized, gap);
|
|
130
|
+
y = anchor.top + anchor.height / 2 - sized.height / 2;
|
|
131
|
+
y = clamp(y, padding, viewport.height - padding - sized.height);
|
|
132
|
+
}
|
|
133
|
+
return { x, y, placement: side, maxWidth };
|
|
134
|
+
}
|
|
135
|
+
function useAnchoredPosition({
|
|
136
|
+
open,
|
|
137
|
+
anchorRef,
|
|
138
|
+
floatingRef,
|
|
139
|
+
placement,
|
|
140
|
+
gap,
|
|
141
|
+
padding
|
|
142
|
+
}) {
|
|
143
|
+
const [state, setState] = React16.useState({
|
|
144
|
+
x: 0,
|
|
145
|
+
y: 0,
|
|
146
|
+
placement,
|
|
147
|
+
maxWidth: 0,
|
|
148
|
+
ready: false
|
|
149
|
+
});
|
|
150
|
+
useSafeLayoutEffect(() => {
|
|
151
|
+
if (!open) {
|
|
152
|
+
setState((prev) => prev.ready ? { ...prev, ready: false } : prev);
|
|
153
|
+
return;
|
|
154
|
+
}
|
|
155
|
+
const anchor = anchorRef.current;
|
|
156
|
+
const floating = floatingRef.current;
|
|
157
|
+
if (!anchor || !floating) return;
|
|
158
|
+
const update = () => {
|
|
159
|
+
const a = anchor.getBoundingClientRect();
|
|
160
|
+
const f = floating.getBoundingClientRect();
|
|
161
|
+
const result = computeAnchoredPosition(
|
|
162
|
+
{ top: a.top, left: a.left, width: a.width, height: a.height },
|
|
163
|
+
{ width: f.width, height: f.height },
|
|
164
|
+
{ width: window.innerWidth, height: window.innerHeight },
|
|
165
|
+
{ placement, gap, padding }
|
|
166
|
+
);
|
|
167
|
+
setState({ ...result, ready: true });
|
|
168
|
+
};
|
|
169
|
+
let frame = 0;
|
|
170
|
+
const schedule = () => {
|
|
171
|
+
if (frame) return;
|
|
172
|
+
frame = requestAnimationFrame(() => {
|
|
173
|
+
frame = 0;
|
|
174
|
+
update();
|
|
175
|
+
});
|
|
176
|
+
};
|
|
177
|
+
update();
|
|
178
|
+
window.addEventListener("scroll", schedule, true);
|
|
179
|
+
window.addEventListener("resize", schedule);
|
|
180
|
+
const observer = typeof ResizeObserver !== "undefined" ? new ResizeObserver(schedule) : null;
|
|
181
|
+
observer?.observe(floating);
|
|
182
|
+
observer?.observe(anchor);
|
|
183
|
+
return () => {
|
|
184
|
+
if (frame) cancelAnimationFrame(frame);
|
|
185
|
+
window.removeEventListener("scroll", schedule, true);
|
|
186
|
+
window.removeEventListener("resize", schedule);
|
|
187
|
+
observer?.disconnect();
|
|
188
|
+
};
|
|
189
|
+
}, [open, placement, gap, padding, anchorRef, floatingRef]);
|
|
190
|
+
return state;
|
|
191
|
+
}
|
|
70
192
|
var FOCUSABLE_SELECTORS = [
|
|
71
193
|
"a[href]",
|
|
72
194
|
"button:not([disabled])",
|
|
@@ -76,8 +198,8 @@ var FOCUSABLE_SELECTORS = [
|
|
|
76
198
|
'[tabindex]:not([tabindex="-1"])'
|
|
77
199
|
].join(", ");
|
|
78
200
|
function useFocusTrap(containerRef, isActive) {
|
|
79
|
-
const previousActiveElement =
|
|
80
|
-
|
|
201
|
+
const previousActiveElement = React16.useRef(null);
|
|
202
|
+
React16.useEffect(() => {
|
|
81
203
|
if (!isActive) return;
|
|
82
204
|
const container = containerRef.current;
|
|
83
205
|
if (!container) return;
|
|
@@ -126,8 +248,8 @@ function useFocusTrap(containerRef, isActive) {
|
|
|
126
248
|
}, [isActive, containerRef]);
|
|
127
249
|
}
|
|
128
250
|
function useIsMounted() {
|
|
129
|
-
const [mounted, setMounted] =
|
|
130
|
-
|
|
251
|
+
const [mounted, setMounted] = React16.useState(false);
|
|
252
|
+
React16.useEffect(() => {
|
|
131
253
|
setMounted(true);
|
|
132
254
|
}, []);
|
|
133
255
|
return mounted;
|
|
@@ -161,14 +283,13 @@ function getServerSnapshot() {
|
|
|
161
283
|
return false;
|
|
162
284
|
}
|
|
163
285
|
function useReducedMotion() {
|
|
164
|
-
return
|
|
286
|
+
return React16.useSyncExternalStore(subscribe, getSnapshot, getServerSnapshot);
|
|
165
287
|
}
|
|
166
|
-
var useSafeLayoutEffect = typeof window !== "undefined" ? useLayoutEffect : useEffect;
|
|
167
288
|
function useSpringHover({
|
|
168
289
|
scale = 1.02,
|
|
169
290
|
lift = -2
|
|
170
291
|
} = {}) {
|
|
171
|
-
const [hovered, setHovered] =
|
|
292
|
+
const [hovered, setHovered] = React16.useState(false);
|
|
172
293
|
const reduced = useReducedMotion();
|
|
173
294
|
const style = useSpring({
|
|
174
295
|
transform: hovered ? `translateY(${lift}px) scale(${scale})` : "translateY(0px) scale(1)",
|
|
@@ -232,9 +353,9 @@ var Accordion = ({
|
|
|
232
353
|
...props
|
|
233
354
|
}) => {
|
|
234
355
|
const isControlled = controlledKeys !== void 0;
|
|
235
|
-
const [internalKeys, setInternalKeys] =
|
|
356
|
+
const [internalKeys, setInternalKeys] = React16.useState(defaultOpenKeys);
|
|
236
357
|
const open = isControlled ? controlledKeys ?? [] : internalKeys;
|
|
237
|
-
const idPrefix =
|
|
358
|
+
const idPrefix = React16.useId();
|
|
238
359
|
const toggle = (key) => {
|
|
239
360
|
const isOpen = open.includes(key);
|
|
240
361
|
const next = isOpen ? open.filter((k) => k !== key) : multiple ? [...open, key] : [key];
|
|
@@ -300,7 +421,7 @@ var Avatar = ({
|
|
|
300
421
|
style,
|
|
301
422
|
...props
|
|
302
423
|
}) => {
|
|
303
|
-
const [imgFailed, setImgFailed] =
|
|
424
|
+
const [imgFailed, setImgFailed] = React16.useState(false);
|
|
304
425
|
const showImage = src && !imgFailed;
|
|
305
426
|
const initials = getInitials(name);
|
|
306
427
|
return /* @__PURE__ */ jsx(
|
|
@@ -519,12 +640,12 @@ var Breadcrumb = ({
|
|
|
519
640
|
}) }) });
|
|
520
641
|
};
|
|
521
642
|
var Menu = ({ items, trigger, align = "start" }) => {
|
|
522
|
-
const [open, setOpen] =
|
|
523
|
-
const wrapperRef =
|
|
524
|
-
const itemRefs =
|
|
525
|
-
const menuId =
|
|
643
|
+
const [open, setOpen] = React16.useState(false);
|
|
644
|
+
const wrapperRef = React16.useRef(null);
|
|
645
|
+
const itemRefs = React16.useRef([]);
|
|
646
|
+
const menuId = React16.useId();
|
|
526
647
|
const style = useSpringPresence({ visible: open, from: "translateY(-4px)" });
|
|
527
|
-
|
|
648
|
+
React16.useEffect(() => {
|
|
528
649
|
if (!open) return;
|
|
529
650
|
const handleClick = (e) => {
|
|
530
651
|
if (!wrapperRef.current?.contains(e.target)) setOpen(false);
|
|
@@ -539,7 +660,7 @@ var Menu = ({ items, trigger, align = "start" }) => {
|
|
|
539
660
|
document.removeEventListener("keydown", handleEsc);
|
|
540
661
|
};
|
|
541
662
|
}, [open]);
|
|
542
|
-
|
|
663
|
+
React16.useEffect(() => {
|
|
543
664
|
const active = document.activeElement;
|
|
544
665
|
if (!open || active && itemRefs.current.includes(active)) return;
|
|
545
666
|
const first = items.findIndex((it) => !it.disabled);
|
|
@@ -585,7 +706,7 @@ var Menu = ({ items, trigger, align = "start" }) => {
|
|
|
585
706
|
break;
|
|
586
707
|
}
|
|
587
708
|
};
|
|
588
|
-
const triggerWithProps =
|
|
709
|
+
const triggerWithProps = React16.cloneElement(
|
|
589
710
|
trigger,
|
|
590
711
|
{
|
|
591
712
|
onClick: () => setOpen((o) => !o),
|
|
@@ -727,6 +848,7 @@ var LocaleSwitcher = ({ locale }) => {
|
|
|
727
848
|
const itemRefs = useRef([]);
|
|
728
849
|
const menuId = useId();
|
|
729
850
|
const currentOption = locale.options.find((o) => o.value === locale.current);
|
|
851
|
+
const currentLabel = currentOption?.label ?? locale.current.toUpperCase();
|
|
730
852
|
useEffect(() => {
|
|
731
853
|
if (!open) return;
|
|
732
854
|
const handler = (e) => {
|
|
@@ -800,10 +922,11 @@ var LocaleSwitcher = ({ locale }) => {
|
|
|
800
922
|
"aria-haspopup": "menu",
|
|
801
923
|
"aria-expanded": open,
|
|
802
924
|
"aria-controls": menuId,
|
|
925
|
+
"aria-label": locale.ariaLabel ?? currentLabel,
|
|
803
926
|
onClick: () => setOpen((p) => !p),
|
|
804
927
|
children: [
|
|
805
928
|
/* @__PURE__ */ jsx(Globe, { size: iconSize.sm, "aria-hidden": "true" }),
|
|
806
|
-
!locale.hideLabel && /* @__PURE__ */ jsx("span", { className: "nav_bar_locale_label", children:
|
|
929
|
+
!locale.hideLabel && /* @__PURE__ */ jsx("span", { className: "nav_bar_locale_label", children: currentLabel }),
|
|
807
930
|
/* @__PURE__ */ jsx(
|
|
808
931
|
ChevronDown,
|
|
809
932
|
{
|
|
@@ -876,9 +999,9 @@ var Sidebar = ({
|
|
|
876
999
|
...props
|
|
877
1000
|
}) => {
|
|
878
1001
|
const isControlled = collapsedProp !== void 0;
|
|
879
|
-
const [internalCollapsed, setInternalCollapsed] =
|
|
1002
|
+
const [internalCollapsed, setInternalCollapsed] = React16.useState(defaultCollapsed);
|
|
880
1003
|
const collapsed = isControlled ? collapsedProp : internalCollapsed;
|
|
881
|
-
const toggle =
|
|
1004
|
+
const toggle = React16.useCallback(() => {
|
|
882
1005
|
const next = !collapsed;
|
|
883
1006
|
if (!isControlled) setInternalCollapsed(next);
|
|
884
1007
|
onCollapsedChange?.(next);
|
|
@@ -951,9 +1074,9 @@ var SidebarSection = ({ label, className, children, ...props }) => {
|
|
|
951
1074
|
children
|
|
952
1075
|
] });
|
|
953
1076
|
};
|
|
954
|
-
var TabsContext =
|
|
1077
|
+
var TabsContext = React16.createContext(null);
|
|
955
1078
|
function useTabsContext() {
|
|
956
|
-
const ctx =
|
|
1079
|
+
const ctx = React16.useContext(TabsContext);
|
|
957
1080
|
if (!ctx) {
|
|
958
1081
|
throw new Error(
|
|
959
1082
|
'[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>'
|
|
@@ -972,18 +1095,18 @@ var Tabs = ({
|
|
|
972
1095
|
...props
|
|
973
1096
|
}) => {
|
|
974
1097
|
const isControlled = controlledValue !== void 0;
|
|
975
|
-
const [internalValue, setInternalValue] =
|
|
1098
|
+
const [internalValue, setInternalValue] = React16.useState(defaultValue);
|
|
976
1099
|
const value = isControlled ? controlledValue : internalValue;
|
|
977
|
-
const setValue =
|
|
1100
|
+
const setValue = React16.useCallback(
|
|
978
1101
|
(v) => {
|
|
979
1102
|
if (!isControlled) setInternalValue(v);
|
|
980
1103
|
onValueChange?.(v);
|
|
981
1104
|
},
|
|
982
1105
|
[isControlled, onValueChange]
|
|
983
1106
|
);
|
|
984
|
-
const orderRef =
|
|
985
|
-
const [firstTabValue, setFirstTabValue] =
|
|
986
|
-
const registerTab =
|
|
1107
|
+
const orderRef = React16.useRef([]);
|
|
1108
|
+
const [firstTabValue, setFirstTabValue] = React16.useState();
|
|
1109
|
+
const registerTab = React16.useCallback((v) => {
|
|
987
1110
|
if (!orderRef.current.includes(v)) {
|
|
988
1111
|
orderRef.current = [...orderRef.current, v];
|
|
989
1112
|
setFirstTabValue(orderRef.current[0]);
|
|
@@ -993,8 +1116,8 @@ var Tabs = ({
|
|
|
993
1116
|
setFirstTabValue(orderRef.current[0]);
|
|
994
1117
|
};
|
|
995
1118
|
}, []);
|
|
996
|
-
const idPrefix =
|
|
997
|
-
const ctx =
|
|
1119
|
+
const idPrefix = React16.useId();
|
|
1120
|
+
const ctx = React16.useMemo(
|
|
998
1121
|
() => ({ value, setValue, variant, size, idPrefix, registerTab, firstTabValue }),
|
|
999
1122
|
[value, setValue, variant, size, idPrefix, registerTab, firstTabValue]
|
|
1000
1123
|
);
|
|
@@ -1002,9 +1125,9 @@ var Tabs = ({
|
|
|
1002
1125
|
};
|
|
1003
1126
|
var TabList = ({ ariaLabel, className, children, ...props }) => {
|
|
1004
1127
|
const { variant } = useTabsContext();
|
|
1005
|
-
const listRef =
|
|
1006
|
-
const [indicator, setIndicator] =
|
|
1007
|
-
const [hasMounted, setHasMounted] =
|
|
1128
|
+
const listRef = React16.useRef(null);
|
|
1129
|
+
const [indicator, setIndicator] = React16.useState(null);
|
|
1130
|
+
const [hasMounted, setHasMounted] = React16.useState(false);
|
|
1008
1131
|
useSafeLayoutEffect(() => {
|
|
1009
1132
|
const list = listRef.current;
|
|
1010
1133
|
if (!list) return;
|
|
@@ -1067,7 +1190,7 @@ var Tab = ({ value, className, children, onClick, onKeyDown, ...props }) => {
|
|
|
1067
1190
|
const panelId = `${ctx.idPrefix}-panel-${value}`;
|
|
1068
1191
|
const tabId = `${ctx.idPrefix}-tab-${value}`;
|
|
1069
1192
|
const { registerTab } = ctx;
|
|
1070
|
-
|
|
1193
|
+
React16.useEffect(() => registerTab(value), [registerTab, value]);
|
|
1071
1194
|
const handleClick = (e) => {
|
|
1072
1195
|
ctx.setValue(value);
|
|
1073
1196
|
onClick?.(e);
|
|
@@ -1137,14 +1260,7 @@ var TabPanel = ({
|
|
|
1137
1260
|
}
|
|
1138
1261
|
);
|
|
1139
1262
|
};
|
|
1140
|
-
var
|
|
1141
|
-
"a[href]",
|
|
1142
|
-
"button:not([disabled])",
|
|
1143
|
-
"input:not([disabled])",
|
|
1144
|
-
"select:not([disabled])",
|
|
1145
|
-
"textarea:not([disabled])",
|
|
1146
|
-
'[tabindex]:not([tabindex="-1"])'
|
|
1147
|
-
].join(", ");
|
|
1263
|
+
var POPOVER_GAP = 8;
|
|
1148
1264
|
var Popover = ({
|
|
1149
1265
|
trigger,
|
|
1150
1266
|
content,
|
|
@@ -1157,23 +1273,31 @@ var Popover = ({
|
|
|
1157
1273
|
className
|
|
1158
1274
|
}) => {
|
|
1159
1275
|
const isControlled = openProp !== void 0;
|
|
1160
|
-
const [internalOpen, setInternalOpen] =
|
|
1276
|
+
const [internalOpen, setInternalOpen] = React16.useState(defaultOpen);
|
|
1161
1277
|
const open = isControlled ? openProp : internalOpen;
|
|
1162
|
-
const [shouldRender, setShouldRender] =
|
|
1278
|
+
const [shouldRender, setShouldRender] = React16.useState(open ?? false);
|
|
1163
1279
|
if (open && !shouldRender) setShouldRender(true);
|
|
1164
|
-
const wrapperRef =
|
|
1165
|
-
const
|
|
1166
|
-
const
|
|
1167
|
-
const popoverId =
|
|
1168
|
-
const setOpen =
|
|
1280
|
+
const wrapperRef = React16.useRef(null);
|
|
1281
|
+
const positionRef = React16.useRef(null);
|
|
1282
|
+
const popoverRef = React16.useRef(null);
|
|
1283
|
+
const popoverId = React16.useId();
|
|
1284
|
+
const setOpen = React16.useCallback(
|
|
1169
1285
|
(next) => {
|
|
1170
1286
|
if (!isControlled) setInternalOpen(next);
|
|
1171
1287
|
onOpenChange?.(next);
|
|
1172
1288
|
},
|
|
1173
1289
|
[isControlled, onOpenChange]
|
|
1174
1290
|
);
|
|
1291
|
+
const pos = useAnchoredPosition({
|
|
1292
|
+
open: shouldRender,
|
|
1293
|
+
anchorRef: wrapperRef,
|
|
1294
|
+
floatingRef: positionRef,
|
|
1295
|
+
placement,
|
|
1296
|
+
gap: POPOVER_GAP,
|
|
1297
|
+
padding: 8
|
|
1298
|
+
});
|
|
1175
1299
|
const fromTransform = (() => {
|
|
1176
|
-
switch (placement) {
|
|
1300
|
+
switch (pos.placement) {
|
|
1177
1301
|
case "top":
|
|
1178
1302
|
return "translateY(4px)";
|
|
1179
1303
|
case "bottom":
|
|
@@ -1184,28 +1308,27 @@ var Popover = ({
|
|
|
1184
1308
|
return "translateX(-4px)";
|
|
1185
1309
|
}
|
|
1186
1310
|
})();
|
|
1187
|
-
const style = useSpringPresence({
|
|
1188
|
-
|
|
1189
|
-
|
|
1190
|
-
|
|
1191
|
-
|
|
1192
|
-
|
|
1193
|
-
|
|
1194
|
-
(focusable ?? node).focus();
|
|
1195
|
-
}, [open]);
|
|
1196
|
-
React15.useEffect(() => {
|
|
1311
|
+
const style = useSpringPresence({
|
|
1312
|
+
visible: open,
|
|
1313
|
+
from: fromTransform,
|
|
1314
|
+
onExitComplete: () => setShouldRender(false)
|
|
1315
|
+
});
|
|
1316
|
+
useFocusTrap(popoverRef, open);
|
|
1317
|
+
React16.useEffect(() => {
|
|
1197
1318
|
if (!open) return;
|
|
1198
1319
|
const handleClick = (e) => {
|
|
1199
|
-
|
|
1320
|
+
const target = e.target;
|
|
1321
|
+
if (!wrapperRef.current?.contains(target) && !popoverRef.current?.contains(target)) {
|
|
1322
|
+
setOpen(false);
|
|
1323
|
+
}
|
|
1200
1324
|
};
|
|
1201
1325
|
document.addEventListener("mousedown", handleClick);
|
|
1202
1326
|
return () => document.removeEventListener("mousedown", handleClick);
|
|
1203
1327
|
}, [open, setOpen]);
|
|
1204
1328
|
useOverlayEscape(open, () => {
|
|
1205
1329
|
setOpen(false);
|
|
1206
|
-
previousFocusRef.current?.focus();
|
|
1207
1330
|
});
|
|
1208
|
-
const triggerWithProps =
|
|
1331
|
+
const triggerWithProps = React16.cloneElement(
|
|
1209
1332
|
trigger,
|
|
1210
1333
|
{
|
|
1211
1334
|
onClick: (e) => {
|
|
@@ -1220,23 +1343,43 @@ var Popover = ({
|
|
|
1220
1343
|
);
|
|
1221
1344
|
return /* @__PURE__ */ jsxs("div", { className: "popover_wrapper", ref: wrapperRef, children: [
|
|
1222
1345
|
triggerWithProps,
|
|
1223
|
-
shouldRender &&
|
|
1224
|
-
|
|
1225
|
-
|
|
1226
|
-
|
|
1227
|
-
|
|
1228
|
-
|
|
1229
|
-
|
|
1230
|
-
|
|
1231
|
-
|
|
1232
|
-
|
|
1233
|
-
|
|
1234
|
-
|
|
1235
|
-
|
|
1236
|
-
|
|
1346
|
+
shouldRender && typeof document !== "undefined" && createPortal(
|
|
1347
|
+
/* @__PURE__ */ jsx(
|
|
1348
|
+
"div",
|
|
1349
|
+
{
|
|
1350
|
+
ref: positionRef,
|
|
1351
|
+
className: "popover_position",
|
|
1352
|
+
style: {
|
|
1353
|
+
position: "fixed",
|
|
1354
|
+
left: pos.x,
|
|
1355
|
+
top: pos.y,
|
|
1356
|
+
// 최초 측정 전(ready=false)에는 maxWidth(=0)를 걸지 않는다 - 걸면 자연 폭 대신
|
|
1357
|
+
// 0px 로 측정돼 첫 프레임 좌표가 어긋난다. ready 후에만 상한 적용.
|
|
1358
|
+
maxWidth: pos.ready ? pos.maxWidth : void 0,
|
|
1359
|
+
visibility: pos.ready ? void 0 : "hidden"
|
|
1360
|
+
},
|
|
1361
|
+
children: /* @__PURE__ */ jsx(
|
|
1362
|
+
animated.div,
|
|
1363
|
+
{
|
|
1364
|
+
id: popoverId,
|
|
1365
|
+
ref: popoverRef,
|
|
1366
|
+
role: "dialog",
|
|
1367
|
+
tabIndex: -1,
|
|
1368
|
+
"aria-label": ariaLabelledby ? ariaLabel : ariaLabel ?? "Dialog",
|
|
1369
|
+
"aria-labelledby": ariaLabelledby,
|
|
1370
|
+
style,
|
|
1371
|
+
className: cn("popover", className),
|
|
1372
|
+
children: content
|
|
1373
|
+
}
|
|
1374
|
+
)
|
|
1375
|
+
}
|
|
1376
|
+
),
|
|
1377
|
+
document.body
|
|
1378
|
+
)
|
|
1237
1379
|
] });
|
|
1238
1380
|
};
|
|
1239
1381
|
Popover.displayName = "Popover";
|
|
1382
|
+
var TOOLTIP_GAP = 6;
|
|
1240
1383
|
var Tooltip = ({
|
|
1241
1384
|
content,
|
|
1242
1385
|
placement = "top",
|
|
@@ -1244,33 +1387,45 @@ var Tooltip = ({
|
|
|
1244
1387
|
disabled = false,
|
|
1245
1388
|
children
|
|
1246
1389
|
}) => {
|
|
1247
|
-
const [open, setOpen] =
|
|
1248
|
-
const
|
|
1249
|
-
|
|
1390
|
+
const [open, setOpen] = React16.useState(false);
|
|
1391
|
+
const [shouldRender, setShouldRender] = React16.useState(false);
|
|
1392
|
+
if (open && !shouldRender) setShouldRender(true);
|
|
1393
|
+
const timerRef = React16.useRef(null);
|
|
1394
|
+
const tooltipId = React16.useId();
|
|
1395
|
+
const wrapperRef = React16.useRef(null);
|
|
1396
|
+
const positionRef = React16.useRef(null);
|
|
1250
1397
|
const HIDE_DELAY = 120;
|
|
1251
|
-
const show =
|
|
1398
|
+
const show = React16.useCallback(() => {
|
|
1252
1399
|
if (timerRef.current) clearTimeout(timerRef.current);
|
|
1253
1400
|
timerRef.current = setTimeout(() => setOpen(true), delay);
|
|
1254
1401
|
}, [delay]);
|
|
1255
|
-
const hideNow =
|
|
1402
|
+
const hideNow = React16.useCallback(() => {
|
|
1256
1403
|
if (timerRef.current) clearTimeout(timerRef.current);
|
|
1257
1404
|
setOpen(false);
|
|
1258
1405
|
}, []);
|
|
1259
|
-
const hide =
|
|
1406
|
+
const hide = React16.useCallback(() => {
|
|
1260
1407
|
if (timerRef.current) clearTimeout(timerRef.current);
|
|
1261
1408
|
timerRef.current = setTimeout(() => setOpen(false), HIDE_DELAY);
|
|
1262
1409
|
}, []);
|
|
1263
|
-
const cancelHide =
|
|
1410
|
+
const cancelHide = React16.useCallback(() => {
|
|
1264
1411
|
if (timerRef.current) clearTimeout(timerRef.current);
|
|
1265
1412
|
}, []);
|
|
1266
|
-
|
|
1413
|
+
React16.useEffect(() => {
|
|
1267
1414
|
return () => {
|
|
1268
1415
|
if (timerRef.current) clearTimeout(timerRef.current);
|
|
1269
1416
|
};
|
|
1270
1417
|
}, []);
|
|
1271
1418
|
useOverlayEscape(open, hideNow);
|
|
1419
|
+
const pos = useAnchoredPosition({
|
|
1420
|
+
open: shouldRender,
|
|
1421
|
+
anchorRef: wrapperRef,
|
|
1422
|
+
floatingRef: positionRef,
|
|
1423
|
+
placement,
|
|
1424
|
+
gap: TOOLTIP_GAP,
|
|
1425
|
+
padding: 8
|
|
1426
|
+
});
|
|
1272
1427
|
const fromTransform = (() => {
|
|
1273
|
-
switch (placement) {
|
|
1428
|
+
switch (pos.placement) {
|
|
1274
1429
|
case "top":
|
|
1275
1430
|
return "translateY(4px)";
|
|
1276
1431
|
case "bottom":
|
|
@@ -1281,10 +1436,14 @@ var Tooltip = ({
|
|
|
1281
1436
|
return "translateX(-4px)";
|
|
1282
1437
|
}
|
|
1283
1438
|
})();
|
|
1284
|
-
const style = useSpringPresence({
|
|
1439
|
+
const style = useSpringPresence({
|
|
1440
|
+
visible: open,
|
|
1441
|
+
from: fromTransform,
|
|
1442
|
+
onExitComplete: () => setShouldRender(false)
|
|
1443
|
+
});
|
|
1285
1444
|
const child = children;
|
|
1286
1445
|
const childProps = child.props;
|
|
1287
|
-
const trigger =
|
|
1446
|
+
const trigger = React16.cloneElement(child, {
|
|
1288
1447
|
onMouseEnter: (e) => {
|
|
1289
1448
|
childProps.onMouseEnter?.(e);
|
|
1290
1449
|
show();
|
|
@@ -1305,25 +1464,29 @@ var Tooltip = ({
|
|
|
1305
1464
|
"aria-describedby": open ? [childProps["aria-describedby"], tooltipId].filter(Boolean).join(" ") : childProps["aria-describedby"]
|
|
1306
1465
|
});
|
|
1307
1466
|
if (disabled) return children;
|
|
1308
|
-
return /* @__PURE__ */ jsxs("span", { className: "tooltip_wrapper", children: [
|
|
1467
|
+
return /* @__PURE__ */ jsxs("span", { className: "tooltip_wrapper", ref: wrapperRef, children: [
|
|
1309
1468
|
trigger,
|
|
1310
|
-
|
|
1311
|
-
|
|
1312
|
-
|
|
1313
|
-
|
|
1314
|
-
|
|
1315
|
-
|
|
1316
|
-
|
|
1317
|
-
|
|
1318
|
-
|
|
1319
|
-
|
|
1320
|
-
|
|
1321
|
-
|
|
1322
|
-
|
|
1323
|
-
|
|
1324
|
-
}
|
|
1325
|
-
|
|
1326
|
-
|
|
1469
|
+
shouldRender && typeof document !== "undefined" && createPortal(
|
|
1470
|
+
/* @__PURE__ */ jsx(
|
|
1471
|
+
"span",
|
|
1472
|
+
{
|
|
1473
|
+
ref: positionRef,
|
|
1474
|
+
className: "tooltip_position",
|
|
1475
|
+
style: {
|
|
1476
|
+
position: "fixed",
|
|
1477
|
+
left: pos.x,
|
|
1478
|
+
top: pos.y,
|
|
1479
|
+
// 최초 측정 전(ready=false)에는 maxWidth(=0)를 걸지 않는다 - 걸면 자연 폭 대신
|
|
1480
|
+
// 0px 로 측정돼 첫 프레임 좌표가 어긋난다. ready 후에만 상한 적용.
|
|
1481
|
+
maxWidth: pos.ready ? pos.maxWidth : void 0,
|
|
1482
|
+
visibility: pos.ready ? void 0 : "hidden"
|
|
1483
|
+
},
|
|
1484
|
+
onMouseEnter: cancelHide,
|
|
1485
|
+
onMouseLeave: hide,
|
|
1486
|
+
children: /* @__PURE__ */ jsx(animated.span, { id: tooltipId, role: "tooltip", style, className: "tooltip", children: content })
|
|
1487
|
+
}
|
|
1488
|
+
),
|
|
1489
|
+
document.body
|
|
1327
1490
|
)
|
|
1328
1491
|
] });
|
|
1329
1492
|
};
|
|
@@ -2251,12 +2414,12 @@ var Checkbox = ({
|
|
|
2251
2414
|
ref,
|
|
2252
2415
|
...props
|
|
2253
2416
|
}) => {
|
|
2254
|
-
const inputRef =
|
|
2255
|
-
|
|
2417
|
+
const inputRef = React16.useRef(null);
|
|
2418
|
+
React16.useImperativeHandle(
|
|
2256
2419
|
ref,
|
|
2257
2420
|
() => inputRef.current
|
|
2258
2421
|
);
|
|
2259
|
-
|
|
2422
|
+
React16.useEffect(() => {
|
|
2260
2423
|
if (!inputRef.current) return;
|
|
2261
2424
|
inputRef.current.indeterminate = Boolean(indeterminate);
|
|
2262
2425
|
}, [indeterminate]);
|
|
@@ -2314,8 +2477,8 @@ var Table = ({
|
|
|
2314
2477
|
const isEmpty = !isLoading && data.length === 0;
|
|
2315
2478
|
const getRowKey = (item, index) => rowKey?.(item) ?? String(index);
|
|
2316
2479
|
const allRowKeys = selectable ? data.map((item, index) => getRowKey(item, index)) : [];
|
|
2317
|
-
const rowClickHintId =
|
|
2318
|
-
const selectedSet =
|
|
2480
|
+
const rowClickHintId = React16.useId();
|
|
2481
|
+
const selectedSet = React16.useMemo(() => new Set(selectedKeys ?? []), [selectedKeys]);
|
|
2319
2482
|
const selectedCount = allRowKeys.filter((key) => selectedSet.has(key)).length;
|
|
2320
2483
|
const isAllSelected = allRowKeys.length > 0 && selectedCount === allRowKeys.length;
|
|
2321
2484
|
const isSomeSelected = selectedCount > 0 && !isAllSelected;
|
|
@@ -2538,9 +2701,9 @@ var AlertModal = ({
|
|
|
2538
2701
|
onClose
|
|
2539
2702
|
}) => {
|
|
2540
2703
|
const dismiss = onCancel ?? onClose;
|
|
2541
|
-
const panelRef =
|
|
2542
|
-
const titleId =
|
|
2543
|
-
const messageId =
|
|
2704
|
+
const panelRef = React16.useRef(null);
|
|
2705
|
+
const titleId = React16.useId();
|
|
2706
|
+
const messageId = React16.useId();
|
|
2544
2707
|
const [shouldRender, setShouldRender] = useState(isOpen);
|
|
2545
2708
|
useFocusTrap(panelRef, isOpen);
|
|
2546
2709
|
useOverlayEscape(isOpen, () => dismiss());
|
|
@@ -2560,7 +2723,7 @@ var AlertModal = ({
|
|
|
2560
2723
|
immediate: reduced,
|
|
2561
2724
|
config: { tension: 280, friction: 28, clamp: !isOpen }
|
|
2562
2725
|
});
|
|
2563
|
-
|
|
2726
|
+
React16.useEffect(() => {
|
|
2564
2727
|
if (!shouldRender) return;
|
|
2565
2728
|
const body = document.body;
|
|
2566
2729
|
const openModals = parseInt(body.dataset.openModals || "0", 10);
|
|
@@ -2687,7 +2850,7 @@ var Spinner = ({ size = 24, ariaLabel = "Loading" }) => {
|
|
|
2687
2850
|
}
|
|
2688
2851
|
);
|
|
2689
2852
|
};
|
|
2690
|
-
var ToastContext =
|
|
2853
|
+
var ToastContext = React16.createContext(null);
|
|
2691
2854
|
var VARIANT_ICONS = {
|
|
2692
2855
|
success: /* @__PURE__ */ jsx(CheckCircle2, { size: iconSize.md }),
|
|
2693
2856
|
error: /* @__PURE__ */ jsx(XCircle, { size: iconSize.md }),
|
|
@@ -2696,9 +2859,9 @@ var VARIANT_ICONS = {
|
|
|
2696
2859
|
default: /* @__PURE__ */ jsx(Bell, { size: iconSize.md })
|
|
2697
2860
|
};
|
|
2698
2861
|
var ToastItemComponent = ({ item, onRemove, closeAriaLabel }) => {
|
|
2699
|
-
const [visible, setVisible] =
|
|
2700
|
-
const closingRef =
|
|
2701
|
-
const rootRef =
|
|
2862
|
+
const [visible, setVisible] = React16.useState(true);
|
|
2863
|
+
const closingRef = React16.useRef(false);
|
|
2864
|
+
const rootRef = React16.useRef(null);
|
|
2702
2865
|
const style = useSpringPresence({
|
|
2703
2866
|
visible,
|
|
2704
2867
|
from: "translateX(20px)",
|
|
@@ -2718,7 +2881,7 @@ var ToastItemComponent = ({ item, onRemove, closeAriaLabel }) => {
|
|
|
2718
2881
|
onRemove(item.id);
|
|
2719
2882
|
}
|
|
2720
2883
|
});
|
|
2721
|
-
const close =
|
|
2884
|
+
const close = React16.useCallback(() => {
|
|
2722
2885
|
if (closingRef.current) return;
|
|
2723
2886
|
closingRef.current = true;
|
|
2724
2887
|
setVisible(false);
|
|
@@ -2752,19 +2915,19 @@ var ToastProvider = ({
|
|
|
2752
2915
|
maxCount = 5,
|
|
2753
2916
|
closeAriaLabel = "Close"
|
|
2754
2917
|
}) => {
|
|
2755
|
-
const [toasts, setToasts] =
|
|
2918
|
+
const [toasts, setToasts] = React16.useState([]);
|
|
2756
2919
|
const isMounted = useIsMounted();
|
|
2757
|
-
const addToast =
|
|
2920
|
+
const addToast = React16.useCallback(
|
|
2758
2921
|
(message, variant, duration = 3e3) => {
|
|
2759
2922
|
const id = crypto.randomUUID();
|
|
2760
2923
|
setToasts((prev) => [{ id, message, variant, duration }, ...prev].slice(0, maxCount));
|
|
2761
2924
|
},
|
|
2762
2925
|
[maxCount]
|
|
2763
2926
|
);
|
|
2764
|
-
const removeToast =
|
|
2927
|
+
const removeToast = React16.useCallback((id) => {
|
|
2765
2928
|
setToasts((prev) => prev.filter((t) => t.id !== id));
|
|
2766
2929
|
}, []);
|
|
2767
|
-
const contextValue =
|
|
2930
|
+
const contextValue = React16.useMemo(() => ({ addToast }), [addToast]);
|
|
2768
2931
|
return /* @__PURE__ */ jsxs(ToastContext.Provider, { value: contextValue, children: [
|
|
2769
2932
|
children,
|
|
2770
2933
|
isMounted && createPortal(
|
|
@@ -2853,6 +3016,7 @@ var Dropdown = (props) => {
|
|
|
2853
3016
|
options,
|
|
2854
3017
|
disabled,
|
|
2855
3018
|
size = "md",
|
|
3019
|
+
variant = "outline",
|
|
2856
3020
|
className,
|
|
2857
3021
|
searchable = false,
|
|
2858
3022
|
searchPlaceholder = "\uAC80\uC0C9\u2026",
|
|
@@ -3065,7 +3229,12 @@ var Dropdown = (props) => {
|
|
|
3065
3229
|
const hasSelection = selectedValues.length > 0;
|
|
3066
3230
|
const showValue = multiple ? hasSelection : currentOption != null;
|
|
3067
3231
|
const controlText = multiple ? hasSelection ? selectedSummary(selectedValues.length) : placeholder : currentOption ? currentOption.label : placeholder;
|
|
3068
|
-
const rootClassName = cn(
|
|
3232
|
+
const rootClassName = cn(
|
|
3233
|
+
"dropdown",
|
|
3234
|
+
`dropdown_size_${size}`,
|
|
3235
|
+
`dropdown_variant_${variant}`,
|
|
3236
|
+
className
|
|
3237
|
+
);
|
|
3069
3238
|
const fieldsetClassName = cn("dropdown_fieldset", { is_open: isOpen, is_disabled: disabled });
|
|
3070
3239
|
const listClassName = cn("dropdown_list", { dropdown_list_up: dropUp });
|
|
3071
3240
|
const listStyle = useSpringPresence({
|
|
@@ -3198,9 +3367,9 @@ var DatePicker = ({
|
|
|
3198
3367
|
minDateSrFormat = "Minimum date: {date}",
|
|
3199
3368
|
selectableRangeUntilTodaySrText = "Selectable up to today"
|
|
3200
3369
|
}) => {
|
|
3201
|
-
const groupId =
|
|
3202
|
-
const constraintId =
|
|
3203
|
-
const { todayYear, todayMonth, todayDay } =
|
|
3370
|
+
const groupId = React16.useId();
|
|
3371
|
+
const constraintId = React16.useId();
|
|
3372
|
+
const { todayYear, todayMonth, todayDay } = React16.useMemo(() => {
|
|
3204
3373
|
const now = /* @__PURE__ */ new Date();
|
|
3205
3374
|
return {
|
|
3206
3375
|
todayYear: now.getFullYear(),
|
|
@@ -3209,7 +3378,7 @@ var DatePicker = ({
|
|
|
3209
3378
|
};
|
|
3210
3379
|
}, []);
|
|
3211
3380
|
const endYear = endYearProp ?? todayYear + 10;
|
|
3212
|
-
const parsed =
|
|
3381
|
+
const parsed = React16.useMemo(() => {
|
|
3213
3382
|
if (!value) return { year: 0, month: 0, day: 0 };
|
|
3214
3383
|
const [y, m, d] = value.split("-").map(Number);
|
|
3215
3384
|
return {
|
|
@@ -3218,7 +3387,7 @@ var DatePicker = ({
|
|
|
3218
3387
|
day: d || 0
|
|
3219
3388
|
};
|
|
3220
3389
|
}, [value]);
|
|
3221
|
-
const min =
|
|
3390
|
+
const min = React16.useMemo(() => {
|
|
3222
3391
|
if (!minDate) return { year: 0, month: 0, day: 0 };
|
|
3223
3392
|
const [y, m, d] = minDate.split("-").map(Number);
|
|
3224
3393
|
return {
|
|
@@ -3238,7 +3407,7 @@ var DatePicker = ({
|
|
|
3238
3407
|
min.year > 0 && min.month > 0 && year === min.year && month === min.month ? min.day : 1
|
|
3239
3408
|
)
|
|
3240
3409
|
);
|
|
3241
|
-
const maxDay =
|
|
3410
|
+
const maxDay = React16.useMemo(() => {
|
|
3242
3411
|
if (!year || !month) return 31;
|
|
3243
3412
|
const daysInMonth = getDaysInMonth(year, month);
|
|
3244
3413
|
if (selectableRange === "until-today" && year === todayYear && month === todayMonth) {
|
|
@@ -3246,28 +3415,28 @@ var DatePicker = ({
|
|
|
3246
3415
|
}
|
|
3247
3416
|
return daysInMonth;
|
|
3248
3417
|
}, [year, month, selectableRange, todayYear, todayMonth, todayDay]);
|
|
3249
|
-
const yearOptions =
|
|
3418
|
+
const yearOptions = React16.useMemo(
|
|
3250
3419
|
() => range(startYear, maxYear).map((y) => ({
|
|
3251
3420
|
value: String(y),
|
|
3252
3421
|
label: String(y)
|
|
3253
3422
|
})),
|
|
3254
3423
|
[startYear, maxYear]
|
|
3255
3424
|
);
|
|
3256
|
-
const monthOptions =
|
|
3425
|
+
const monthOptions = React16.useMemo(
|
|
3257
3426
|
() => range(minMonth, Math.max(minMonth, maxMonth)).map((m) => ({
|
|
3258
3427
|
value: String(m),
|
|
3259
3428
|
label: pad(m)
|
|
3260
3429
|
})),
|
|
3261
3430
|
[minMonth, maxMonth]
|
|
3262
3431
|
);
|
|
3263
|
-
const dayOptions =
|
|
3432
|
+
const dayOptions = React16.useMemo(
|
|
3264
3433
|
() => range(minDay, Math.max(minDay, maxDay)).map((d) => ({
|
|
3265
3434
|
value: String(d),
|
|
3266
3435
|
label: pad(d)
|
|
3267
3436
|
})),
|
|
3268
3437
|
[minDay, maxDay]
|
|
3269
3438
|
);
|
|
3270
|
-
const emit =
|
|
3439
|
+
const emit = React16.useCallback(
|
|
3271
3440
|
(yy, mm, dd) => {
|
|
3272
3441
|
const cb = onValueChange ?? onChange;
|
|
3273
3442
|
if (mode === "year-month") {
|
|
@@ -3279,7 +3448,7 @@ var DatePicker = ({
|
|
|
3279
3448
|
},
|
|
3280
3449
|
[mode, onValueChange, onChange]
|
|
3281
3450
|
);
|
|
3282
|
-
const handleYearChange =
|
|
3451
|
+
const handleYearChange = React16.useCallback(
|
|
3283
3452
|
(raw) => {
|
|
3284
3453
|
if (!raw) return;
|
|
3285
3454
|
const newYear = Number(raw);
|
|
@@ -3296,14 +3465,14 @@ var DatePicker = ({
|
|
|
3296
3465
|
},
|
|
3297
3466
|
[month, day, min.year, min.month, selectableRange, todayYear, todayMonth, emit]
|
|
3298
3467
|
);
|
|
3299
|
-
const handleMonthChange =
|
|
3468
|
+
const handleMonthChange = React16.useCallback(
|
|
3300
3469
|
(raw) => {
|
|
3301
3470
|
if (!raw || !year) return;
|
|
3302
3471
|
emit(year, Number(raw), day || void 0);
|
|
3303
3472
|
},
|
|
3304
3473
|
[year, day, emit]
|
|
3305
3474
|
);
|
|
3306
|
-
const handleDayChange =
|
|
3475
|
+
const handleDayChange = React16.useCallback(
|
|
3307
3476
|
(raw) => {
|
|
3308
3477
|
if (!raw || !year || !month) return;
|
|
3309
3478
|
emit(year, month, Number(raw));
|
|
@@ -3387,11 +3556,11 @@ var FileInput = ({
|
|
|
3387
3556
|
onChange,
|
|
3388
3557
|
...props
|
|
3389
3558
|
}) => {
|
|
3390
|
-
const inputId =
|
|
3391
|
-
const helperId =
|
|
3392
|
-
const inputRef =
|
|
3393
|
-
const [previewUrls, setPreviewUrls] =
|
|
3394
|
-
const previewUrlsRef =
|
|
3559
|
+
const inputId = React16.useId();
|
|
3560
|
+
const helperId = React16.useId();
|
|
3561
|
+
const inputRef = React16.useRef(null);
|
|
3562
|
+
const [previewUrls, setPreviewUrls] = React16.useState([]);
|
|
3563
|
+
const previewUrlsRef = React16.useRef([]);
|
|
3395
3564
|
const isPreviewVariant = variant === "preview";
|
|
3396
3565
|
const showPreview = isPreviewVariant || preview;
|
|
3397
3566
|
const handleChange = (e) => {
|
|
@@ -3432,7 +3601,7 @@ var FileInput = ({
|
|
|
3432
3601
|
}
|
|
3433
3602
|
onFiles?.(null);
|
|
3434
3603
|
};
|
|
3435
|
-
|
|
3604
|
+
React16.useEffect(() => {
|
|
3436
3605
|
return () => {
|
|
3437
3606
|
for (const url of previewUrlsRef.current) {
|
|
3438
3607
|
URL.revokeObjectURL(url);
|
|
@@ -3841,12 +4010,12 @@ var OtpInput = ({
|
|
|
3841
4010
|
ariaLabel = "OTP \uC785\uB825",
|
|
3842
4011
|
className
|
|
3843
4012
|
}) => {
|
|
3844
|
-
const inputsRef =
|
|
3845
|
-
const isTypingRef =
|
|
3846
|
-
|
|
4013
|
+
const inputsRef = React16.useRef([]);
|
|
4014
|
+
const isTypingRef = React16.useRef(false);
|
|
4015
|
+
React16.useEffect(() => {
|
|
3847
4016
|
if (autoFocus) inputsRef.current[0]?.focus();
|
|
3848
4017
|
}, [autoFocus]);
|
|
3849
|
-
const digits =
|
|
4018
|
+
const digits = React16.useMemo(() => {
|
|
3850
4019
|
const chars = value.split("").slice(0, length);
|
|
3851
4020
|
while (chars.length < length) chars.push("");
|
|
3852
4021
|
return chars;
|
|
@@ -3923,7 +4092,7 @@ var OtpInput = ({
|
|
|
3923
4092
|
focusInput(nextIndex);
|
|
3924
4093
|
};
|
|
3925
4094
|
const rootClassName = cn("otp_input", className);
|
|
3926
|
-
const supportingId =
|
|
4095
|
+
const supportingId = React16.useId();
|
|
3927
4096
|
return (
|
|
3928
4097
|
// biome-ignore lint/a11y/useSemanticElements: <fieldset> would force border/legend styles; role=group is the WAI-ARIA equivalent for OTP grouping
|
|
3929
4098
|
/* @__PURE__ */ jsxs("div", { className: rootClassName, role: "group", "aria-label": ariaLabel, children: [
|
|
@@ -3967,9 +4136,9 @@ var OtpInput = ({
|
|
|
3967
4136
|
);
|
|
3968
4137
|
};
|
|
3969
4138
|
OtpInput.displayName = "OtpInput";
|
|
3970
|
-
var RadioGroupContext =
|
|
4139
|
+
var RadioGroupContext = React16.createContext(null);
|
|
3971
4140
|
function useRadioGroupContext() {
|
|
3972
|
-
return
|
|
4141
|
+
return React16.useContext(RadioGroupContext);
|
|
3973
4142
|
}
|
|
3974
4143
|
var RadioGroup = ({
|
|
3975
4144
|
value: controlledValue,
|
|
@@ -3987,21 +4156,21 @@ var RadioGroup = ({
|
|
|
3987
4156
|
...props
|
|
3988
4157
|
}) => {
|
|
3989
4158
|
const isControlled = controlledValue !== void 0;
|
|
3990
|
-
const [internalValue, setInternalValue] =
|
|
4159
|
+
const [internalValue, setInternalValue] = React16.useState(defaultValue);
|
|
3991
4160
|
const value = isControlled ? controlledValue : internalValue;
|
|
3992
|
-
const generatedName =
|
|
4161
|
+
const generatedName = React16.useId();
|
|
3993
4162
|
const name = nameProp ?? generatedName;
|
|
3994
|
-
const idPrefix =
|
|
4163
|
+
const idPrefix = React16.useId();
|
|
3995
4164
|
const labelId = label ? `${idPrefix}-label` : void 0;
|
|
3996
4165
|
const helperId = supportingText ? `${idPrefix}-help` : void 0;
|
|
3997
|
-
const onChange =
|
|
4166
|
+
const onChange = React16.useCallback(
|
|
3998
4167
|
(next) => {
|
|
3999
4168
|
if (!isControlled) setInternalValue(next);
|
|
4000
4169
|
onValueChange?.(next);
|
|
4001
4170
|
},
|
|
4002
4171
|
[isControlled, onValueChange]
|
|
4003
4172
|
);
|
|
4004
|
-
const ctx =
|
|
4173
|
+
const ctx = React16.useMemo(
|
|
4005
4174
|
() => ({ name, value, onChange, size, disabled }),
|
|
4006
4175
|
[name, value, onChange, size, disabled]
|
|
4007
4176
|
);
|
|
@@ -4212,11 +4381,13 @@ var TextField = ({
|
|
|
4212
4381
|
showLabel = true,
|
|
4213
4382
|
supportingText,
|
|
4214
4383
|
error,
|
|
4384
|
+
success,
|
|
4215
4385
|
leadingIcon,
|
|
4216
4386
|
trailingIcon,
|
|
4217
4387
|
clearable,
|
|
4218
4388
|
fullWidth,
|
|
4219
4389
|
size = "md",
|
|
4390
|
+
variant = "outline",
|
|
4220
4391
|
className,
|
|
4221
4392
|
onValueChange,
|
|
4222
4393
|
onChangeAction,
|
|
@@ -4257,12 +4428,16 @@ var TextField = ({
|
|
|
4257
4428
|
const handleClear = useCallback(() => {
|
|
4258
4429
|
emit("");
|
|
4259
4430
|
}, [emit]);
|
|
4431
|
+
const isError = !!error;
|
|
4432
|
+
const isSuccess = !!success && !isError;
|
|
4260
4433
|
const rootClassName = cn(
|
|
4261
4434
|
"text_field",
|
|
4435
|
+
`text_field_variant_${variant}`,
|
|
4262
4436
|
size === "sm" && "text_field_size_sm",
|
|
4263
4437
|
size === "lg" && "text_field_size_lg",
|
|
4264
4438
|
fullWidth && "text_field_full_width",
|
|
4265
|
-
|
|
4439
|
+
isError && "text_field_error",
|
|
4440
|
+
isSuccess && "text_field_success",
|
|
4266
4441
|
props.disabled && "text_field_disabled",
|
|
4267
4442
|
className
|
|
4268
4443
|
);
|
|
@@ -4284,7 +4459,7 @@ var TextField = ({
|
|
|
4284
4459
|
id: inputId,
|
|
4285
4460
|
ref,
|
|
4286
4461
|
className: "text_field_input",
|
|
4287
|
-
"aria-invalid":
|
|
4462
|
+
"aria-invalid": isError,
|
|
4288
4463
|
"aria-describedby": helperId,
|
|
4289
4464
|
"aria-label": !showLabel ? label : void 0,
|
|
4290
4465
|
...props,
|
|
@@ -4331,7 +4506,7 @@ var Toggle = ({
|
|
|
4331
4506
|
...props
|
|
4332
4507
|
}) => {
|
|
4333
4508
|
const isControlled = checked !== void 0;
|
|
4334
|
-
const [innerChecked, setInnerChecked] =
|
|
4509
|
+
const [innerChecked, setInnerChecked] = React16.useState(!!defaultChecked);
|
|
4335
4510
|
const isOn = isControlled ? !!checked : innerChecked;
|
|
4336
4511
|
const handleToggle = (e) => {
|
|
4337
4512
|
props.onClick?.(e);
|
|
@@ -4420,7 +4595,7 @@ var Pagination = ({
|
|
|
4420
4595
|
const emit = onPageChange ?? onChange;
|
|
4421
4596
|
const prevDisabled = page <= 1;
|
|
4422
4597
|
const nextDisabled = page >= totalPages;
|
|
4423
|
-
const items =
|
|
4598
|
+
const items = React16.useMemo(() => getPaginationItems(page, totalPages), [page, totalPages]);
|
|
4424
4599
|
return /* @__PURE__ */ jsxs("nav", { className: "pagination", "aria-label": "Pagination", children: [
|
|
4425
4600
|
/* @__PURE__ */ jsx(
|
|
4426
4601
|
"button",
|
|
@@ -4485,9 +4660,9 @@ var Drawer = ({
|
|
|
4485
4660
|
className,
|
|
4486
4661
|
...props
|
|
4487
4662
|
}) => {
|
|
4488
|
-
const panelRef =
|
|
4489
|
-
const titleId =
|
|
4490
|
-
const [shouldRender, setShouldRender] =
|
|
4663
|
+
const panelRef = React16.useRef(null);
|
|
4664
|
+
const titleId = React16.useId();
|
|
4665
|
+
const [shouldRender, setShouldRender] = React16.useState(open);
|
|
4491
4666
|
const reduced = useReducedMotion();
|
|
4492
4667
|
const isMounted = useIsMounted();
|
|
4493
4668
|
useFocusTrap(panelRef, open && isMounted);
|
|
@@ -4506,7 +4681,7 @@ var Drawer = ({
|
|
|
4506
4681
|
immediate: reduced,
|
|
4507
4682
|
config: { tension: 280, friction: 28, clamp: !open }
|
|
4508
4683
|
});
|
|
4509
|
-
|
|
4684
|
+
React16.useEffect(() => {
|
|
4510
4685
|
if (!open) return;
|
|
4511
4686
|
const body = document.body;
|
|
4512
4687
|
const openModals = parseInt(body.dataset.openModals || "0", 10);
|
|
@@ -4594,9 +4769,9 @@ var Modal = ({
|
|
|
4594
4769
|
ariaLabel,
|
|
4595
4770
|
...props
|
|
4596
4771
|
}) => {
|
|
4597
|
-
const panelRef =
|
|
4598
|
-
const titleId =
|
|
4599
|
-
const [shouldRender, setShouldRender] =
|
|
4772
|
+
const panelRef = React16.useRef(null);
|
|
4773
|
+
const titleId = React16.useId();
|
|
4774
|
+
const [shouldRender, setShouldRender] = React16.useState(open);
|
|
4600
4775
|
const isMounted = useIsMounted();
|
|
4601
4776
|
useFocusTrap(panelRef, open && isMounted);
|
|
4602
4777
|
useOverlayEscape(open && isMounted, () => onClose?.());
|
|
@@ -4616,7 +4791,7 @@ var Modal = ({
|
|
|
4616
4791
|
immediate: reduced,
|
|
4617
4792
|
config: { tension: 280, friction: 28, clamp: !open }
|
|
4618
4793
|
});
|
|
4619
|
-
|
|
4794
|
+
React16.useEffect(() => {
|
|
4620
4795
|
if (!open) return;
|
|
4621
4796
|
const body = document.body;
|
|
4622
4797
|
const openModals = parseInt(body.dataset.openModals || "0", 10);
|
|
@@ -4686,9 +4861,9 @@ var Modal = ({
|
|
|
4686
4861
|
document.body
|
|
4687
4862
|
);
|
|
4688
4863
|
};
|
|
4689
|
-
var ThemeContext =
|
|
4864
|
+
var ThemeContext = React16.createContext(null);
|
|
4690
4865
|
var useTheme = () => {
|
|
4691
|
-
const ctx =
|
|
4866
|
+
const ctx = React16.useContext(ThemeContext);
|
|
4692
4867
|
if (!ctx) {
|
|
4693
4868
|
throw new Error(
|
|
4694
4869
|
'[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>'
|
|
@@ -4712,15 +4887,15 @@ var ThemeProvider = ({
|
|
|
4712
4887
|
targetSelector,
|
|
4713
4888
|
children
|
|
4714
4889
|
}) => {
|
|
4715
|
-
const [mode, setModeState] =
|
|
4716
|
-
const [systemDark, setSystemDark] =
|
|
4717
|
-
|
|
4890
|
+
const [mode, setModeState] = React16.useState(defaultMode);
|
|
4891
|
+
const [systemDark, setSystemDark] = React16.useState(false);
|
|
4892
|
+
React16.useEffect(() => {
|
|
4718
4893
|
setModeState(readStored(storageKey) ?? defaultMode);
|
|
4719
4894
|
if (isClient) {
|
|
4720
4895
|
setSystemDark(window.matchMedia("(prefers-color-scheme: dark)").matches);
|
|
4721
4896
|
}
|
|
4722
4897
|
}, [storageKey, defaultMode]);
|
|
4723
|
-
|
|
4898
|
+
React16.useEffect(() => {
|
|
4724
4899
|
if (!isClient) return;
|
|
4725
4900
|
const mq = window.matchMedia("(prefers-color-scheme: dark)");
|
|
4726
4901
|
const handler = (e) => setSystemDark(e.matches);
|
|
@@ -4728,7 +4903,7 @@ var ThemeProvider = ({
|
|
|
4728
4903
|
return () => mq.removeEventListener("change", handler);
|
|
4729
4904
|
}, []);
|
|
4730
4905
|
const resolved = mode === "system" ? systemDark ? "dark" : "light" : mode;
|
|
4731
|
-
|
|
4906
|
+
React16.useEffect(() => {
|
|
4732
4907
|
if (!isClient) return;
|
|
4733
4908
|
const target = targetSelector ? document.querySelector(targetSelector) : document.documentElement;
|
|
4734
4909
|
if (!target) return;
|
|
@@ -4738,7 +4913,7 @@ var ThemeProvider = ({
|
|
|
4738
4913
|
target.setAttribute("data-theme", mode);
|
|
4739
4914
|
}
|
|
4740
4915
|
}, [mode, targetSelector]);
|
|
4741
|
-
const setMode =
|
|
4916
|
+
const setMode = React16.useCallback(
|
|
4742
4917
|
(next) => {
|
|
4743
4918
|
setModeState(next);
|
|
4744
4919
|
if (storageKey && isClient) {
|
|
@@ -4750,7 +4925,7 @@ var ThemeProvider = ({
|
|
|
4750
4925
|
},
|
|
4751
4926
|
[storageKey]
|
|
4752
4927
|
);
|
|
4753
|
-
const value =
|
|
4928
|
+
const value = React16.useMemo(
|
|
4754
4929
|
() => ({ mode, resolved, setMode }),
|
|
4755
4930
|
[mode, resolved, setMode]
|
|
4756
4931
|
);
|
|
@@ -4863,4 +5038,4 @@ var Stack = ({
|
|
|
4863
5038
|
);
|
|
4864
5039
|
};
|
|
4865
5040
|
|
|
4866
|
-
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, ImageCropper, 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 };
|
|
5041
|
+
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, ImageCropper, 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, useRadioGroupContext, useReducedMotion, useSpringHover, useSpringPresence, useTheme, useToast, zIndex };
|