@x-plat/design-system 0.5.42 → 0.5.44
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/dist/components/Dropdown/index.cjs +22 -22
- package/dist/components/Dropdown/index.js +22 -22
- package/dist/components/PopOver/index.cjs +22 -22
- package/dist/components/PopOver/index.js +22 -22
- package/dist/components/Select/index.cjs +22 -22
- package/dist/components/Select/index.js +22 -22
- package/dist/components/Video/index.cjs +201 -201
- package/dist/components/Video/index.js +243 -243
- package/dist/components/index.cjs +278 -278
- package/dist/components/index.css +700 -188
- package/dist/components/index.d.cts +2 -2
- package/dist/components/index.d.ts +2 -2
- package/dist/components/index.js +278 -278
- package/dist/index.cjs +278 -278
- package/dist/index.css +700 -188
- package/dist/index.d.cts +2 -2
- package/dist/index.d.ts +2 -2
- package/dist/index.js +278 -278
- package/dist/layout/index.css +520 -8
- package/guidelines/AGENT_PROMPT.md +248 -0
- package/guidelines/Guidelines.md +8 -0
- package/guidelines/composition/layout.md +87 -16
- package/guidelines/setup.md +11 -2
- package/package.json +1 -1
package/dist/components/index.js
CHANGED
|
@@ -1547,15 +1547,31 @@ var Badge = (props) => {
|
|
|
1547
1547
|
Badge.displayName = "Badge";
|
|
1548
1548
|
var Badge_default = Badge;
|
|
1549
1549
|
|
|
1550
|
-
// src/components/
|
|
1550
|
+
// src/components/Box/Box.tsx
|
|
1551
1551
|
import { jsx as jsx299, jsxs as jsxs192 } from "react/jsx-runtime";
|
|
1552
|
+
var Box = ({
|
|
1553
|
+
children,
|
|
1554
|
+
title,
|
|
1555
|
+
variant = "outlined",
|
|
1556
|
+
padding = "md"
|
|
1557
|
+
}) => {
|
|
1558
|
+
return /* @__PURE__ */ jsxs192("div", { className: clsx_default("lib-xplat-box", variant, `pad-${padding}`), children: [
|
|
1559
|
+
title && /* @__PURE__ */ jsx299("div", { className: "box-title", children: title }),
|
|
1560
|
+
/* @__PURE__ */ jsx299("div", { className: "box-content", children })
|
|
1561
|
+
] });
|
|
1562
|
+
};
|
|
1563
|
+
Box.displayName = "Box";
|
|
1564
|
+
var Box_default = Box;
|
|
1565
|
+
|
|
1566
|
+
// src/components/Breadcrumb/Breadcrumb.tsx
|
|
1567
|
+
import { jsx as jsx300, jsxs as jsxs193 } from "react/jsx-runtime";
|
|
1552
1568
|
var Breadcrumb = (props) => {
|
|
1553
1569
|
const { items, separator = "/" } = props;
|
|
1554
|
-
return /* @__PURE__ */
|
|
1570
|
+
return /* @__PURE__ */ jsx300("nav", { className: "lib-xplat-breadcrumb", "aria-label": "\uACBD\uB85C", children: /* @__PURE__ */ jsx300("ol", { children: items.map((item, index) => {
|
|
1555
1571
|
const isLast = index === items.length - 1;
|
|
1556
|
-
return /* @__PURE__ */
|
|
1557
|
-
isLast ? /* @__PURE__ */
|
|
1558
|
-
!isLast && /* @__PURE__ */
|
|
1572
|
+
return /* @__PURE__ */ jsxs193("li", { children: [
|
|
1573
|
+
isLast ? /* @__PURE__ */ jsx300("span", { className: "current", "aria-current": "page", children: item.label }) : item.href ? /* @__PURE__ */ jsx300("a", { href: item.href, className: "link", children: item.label }) : /* @__PURE__ */ jsx300("button", { className: "link", onClick: item.onClick, children: item.label }),
|
|
1574
|
+
!isLast && /* @__PURE__ */ jsx300("span", { className: "separator", children: separator })
|
|
1559
1575
|
] }, index);
|
|
1560
1576
|
}) }) });
|
|
1561
1577
|
};
|
|
@@ -1563,7 +1579,7 @@ Breadcrumb.displayName = "Breadcrumb";
|
|
|
1563
1579
|
var Breadcrumb_default = Breadcrumb;
|
|
1564
1580
|
|
|
1565
1581
|
// src/components/Button/Button.tsx
|
|
1566
|
-
import { jsx as
|
|
1582
|
+
import { jsx as jsx301 } from "react/jsx-runtime";
|
|
1567
1583
|
var Button = (props) => {
|
|
1568
1584
|
const {
|
|
1569
1585
|
children,
|
|
@@ -1572,7 +1588,7 @@ var Button = (props) => {
|
|
|
1572
1588
|
disabled,
|
|
1573
1589
|
...rest
|
|
1574
1590
|
} = props;
|
|
1575
|
-
return /* @__PURE__ */
|
|
1591
|
+
return /* @__PURE__ */ jsx301(
|
|
1576
1592
|
"button",
|
|
1577
1593
|
{
|
|
1578
1594
|
className: clsx_default("lib-xplat-button", type, size),
|
|
@@ -1689,7 +1705,7 @@ var MONTH_LABELS = {
|
|
|
1689
1705
|
};
|
|
1690
1706
|
|
|
1691
1707
|
// src/components/Calendar/Calendar.tsx
|
|
1692
|
-
import { Fragment, jsx as
|
|
1708
|
+
import { Fragment, jsx as jsx302, jsxs as jsxs194 } from "react/jsx-runtime";
|
|
1693
1709
|
var DayCell = React3.memo(
|
|
1694
1710
|
({
|
|
1695
1711
|
day,
|
|
@@ -1701,7 +1717,7 @@ var DayCell = React3.memo(
|
|
|
1701
1717
|
onEventClick
|
|
1702
1718
|
}) => {
|
|
1703
1719
|
if (renderDay) {
|
|
1704
|
-
return /* @__PURE__ */
|
|
1720
|
+
return /* @__PURE__ */ jsx302(
|
|
1705
1721
|
"div",
|
|
1706
1722
|
{
|
|
1707
1723
|
className: clsx_default(
|
|
@@ -1718,7 +1734,7 @@ var DayCell = React3.memo(
|
|
|
1718
1734
|
}
|
|
1719
1735
|
);
|
|
1720
1736
|
}
|
|
1721
|
-
return /* @__PURE__ */
|
|
1737
|
+
return /* @__PURE__ */ jsxs194(
|
|
1722
1738
|
"div",
|
|
1723
1739
|
{
|
|
1724
1740
|
className: clsx_default(
|
|
@@ -1734,9 +1750,9 @@ var DayCell = React3.memo(
|
|
|
1734
1750
|
if (!disabled && day.isCurrentMonth) onSelect?.(day.date);
|
|
1735
1751
|
},
|
|
1736
1752
|
children: [
|
|
1737
|
-
/* @__PURE__ */
|
|
1738
|
-
dayEvents.length > 0 && /* @__PURE__ */
|
|
1739
|
-
dayEvents.slice(0, 3).map((event, ei) => /* @__PURE__ */
|
|
1753
|
+
/* @__PURE__ */ jsx302("span", { className: "calendar-day-number", children: day.day }),
|
|
1754
|
+
dayEvents.length > 0 && /* @__PURE__ */ jsxs194("div", { className: "calendar-day-events", children: [
|
|
1755
|
+
dayEvents.slice(0, 3).map((event, ei) => /* @__PURE__ */ jsx302(
|
|
1740
1756
|
"span",
|
|
1741
1757
|
{
|
|
1742
1758
|
className: "calendar-event-dot",
|
|
@@ -1749,7 +1765,7 @@ var DayCell = React3.memo(
|
|
|
1749
1765
|
},
|
|
1750
1766
|
ei
|
|
1751
1767
|
)),
|
|
1752
|
-
dayEvents.length > 3 && /* @__PURE__ */
|
|
1768
|
+
dayEvents.length > 3 && /* @__PURE__ */ jsxs194("span", { className: "calendar-event-more", children: [
|
|
1753
1769
|
"+",
|
|
1754
1770
|
dayEvents.length - 3
|
|
1755
1771
|
] })
|
|
@@ -1870,21 +1886,21 @@ var Calendar = (props) => {
|
|
|
1870
1886
|
const weekdays = WEEKDAY_LABELS[locale];
|
|
1871
1887
|
const monthLabels = MONTH_LABELS[locale];
|
|
1872
1888
|
const titleText = pickerMode === "days" ? locale === "ko" ? `${year}\uB144 ${monthLabels[month]}` : `${monthLabels[month]} ${year}` : pickerMode === "months" ? `${year}` : `${yearRangeStart} - ${yearRangeStart + 11}`;
|
|
1873
|
-
return /* @__PURE__ */
|
|
1889
|
+
return /* @__PURE__ */ jsxs194(
|
|
1874
1890
|
"div",
|
|
1875
1891
|
{
|
|
1876
1892
|
className: "lib-xplat-calendar",
|
|
1877
1893
|
style: selectedColor ? { "--calendar-selected-color": `var(--${selectedColor})` } : void 0,
|
|
1878
1894
|
children: [
|
|
1879
|
-
/* @__PURE__ */
|
|
1880
|
-
/* @__PURE__ */
|
|
1881
|
-
/* @__PURE__ */
|
|
1882
|
-
/* @__PURE__ */
|
|
1883
|
-
showToday && /* @__PURE__ */
|
|
1895
|
+
/* @__PURE__ */ jsxs194("div", { className: "calendar-header", children: [
|
|
1896
|
+
/* @__PURE__ */ jsx302("button", { className: "calendar-nav", onClick: handlePrev, "aria-label": "\uC774\uC804", children: /* @__PURE__ */ jsx302(ChevronLeftIcon_default, {}) }),
|
|
1897
|
+
/* @__PURE__ */ jsx302("button", { className: "calendar-title", onClick: handleTitleClick, type: "button", children: titleText }),
|
|
1898
|
+
/* @__PURE__ */ jsx302("button", { className: "calendar-nav", onClick: handleNext, "aria-label": "\uB2E4\uC74C", children: /* @__PURE__ */ jsx302(ChevronRightIcon_default, {}) }),
|
|
1899
|
+
showToday && /* @__PURE__ */ jsx302("button", { className: "calendar-today-btn", onClick: handleToday, children: locale === "ko" ? "\uC624\uB298" : "Today" })
|
|
1884
1900
|
] }),
|
|
1885
|
-
pickerMode === "years" && /* @__PURE__ */
|
|
1901
|
+
pickerMode === "years" && /* @__PURE__ */ jsx302("div", { className: "calendar-picker-grid", children: Array.from({ length: 12 }, (_, i) => {
|
|
1886
1902
|
const y = yearRangeStart + i;
|
|
1887
|
-
return /* @__PURE__ */
|
|
1903
|
+
return /* @__PURE__ */ jsx302(
|
|
1888
1904
|
"button",
|
|
1889
1905
|
{
|
|
1890
1906
|
type: "button",
|
|
@@ -1895,7 +1911,7 @@ var Calendar = (props) => {
|
|
|
1895
1911
|
y
|
|
1896
1912
|
);
|
|
1897
1913
|
}) }),
|
|
1898
|
-
pickerMode === "months" && /* @__PURE__ */
|
|
1914
|
+
pickerMode === "months" && /* @__PURE__ */ jsx302("div", { className: "calendar-picker-grid", children: monthLabels.map((label, i) => /* @__PURE__ */ jsx302(
|
|
1899
1915
|
"button",
|
|
1900
1916
|
{
|
|
1901
1917
|
type: "button",
|
|
@@ -1905,8 +1921,8 @@ var Calendar = (props) => {
|
|
|
1905
1921
|
},
|
|
1906
1922
|
i
|
|
1907
1923
|
)) }),
|
|
1908
|
-
pickerMode === "days" && /* @__PURE__ */
|
|
1909
|
-
/* @__PURE__ */
|
|
1924
|
+
pickerMode === "days" && /* @__PURE__ */ jsxs194(Fragment, { children: [
|
|
1925
|
+
/* @__PURE__ */ jsx302("div", { className: "calendar-weekdays", children: weekdays.map((label, i) => /* @__PURE__ */ jsx302(
|
|
1910
1926
|
"div",
|
|
1911
1927
|
{
|
|
1912
1928
|
className: clsx_default(
|
|
@@ -1918,12 +1934,12 @@ var Calendar = (props) => {
|
|
|
1918
1934
|
},
|
|
1919
1935
|
label
|
|
1920
1936
|
)) }),
|
|
1921
|
-
/* @__PURE__ */
|
|
1937
|
+
/* @__PURE__ */ jsx302("div", { className: "calendar-grid", children: days.map((day, idx) => {
|
|
1922
1938
|
const dayEvents = getEventsForDay(day.date);
|
|
1923
1939
|
const t = day.date.getTime();
|
|
1924
1940
|
const disabled = t < minTime || t > maxTime;
|
|
1925
1941
|
const isSelected = selectedDate ? isSameDay(day.date, selectedDate) : false;
|
|
1926
|
-
return /* @__PURE__ */
|
|
1942
|
+
return /* @__PURE__ */ jsx302(
|
|
1927
1943
|
DayCell,
|
|
1928
1944
|
{
|
|
1929
1945
|
day,
|
|
@@ -1945,139 +1961,14 @@ var Calendar = (props) => {
|
|
|
1945
1961
|
Calendar.displayName = "Calendar";
|
|
1946
1962
|
var Calendar_default = Calendar;
|
|
1947
1963
|
|
|
1948
|
-
// src/components/ChatInput/ChatInput.tsx
|
|
1949
|
-
import React4 from "react";
|
|
1950
|
-
|
|
1951
|
-
// src/components/IconButton/IconButton.tsx
|
|
1952
|
-
import { jsx as jsx302 } from "react/jsx-runtime";
|
|
1953
|
-
var IconButton = (props) => {
|
|
1954
|
-
const {
|
|
1955
|
-
icon,
|
|
1956
|
-
type = "primary",
|
|
1957
|
-
size = "md",
|
|
1958
|
-
disabled,
|
|
1959
|
-
...rest
|
|
1960
|
-
} = props;
|
|
1961
|
-
return /* @__PURE__ */ jsx302(
|
|
1962
|
-
"button",
|
|
1963
|
-
{
|
|
1964
|
-
className: clsx_default("lib-xplat-icon-button", type, size),
|
|
1965
|
-
disabled,
|
|
1966
|
-
...rest,
|
|
1967
|
-
children: icon
|
|
1968
|
-
}
|
|
1969
|
-
);
|
|
1970
|
-
};
|
|
1971
|
-
IconButton.displayName = "IconButton";
|
|
1972
|
-
var IconButton_default = IconButton;
|
|
1973
|
-
|
|
1974
|
-
// src/components/ChatInput/ChatInput.tsx
|
|
1975
|
-
import { jsx as jsx303, jsxs as jsxs194 } from "react/jsx-runtime";
|
|
1976
|
-
var MAX_HEIGHT = 200;
|
|
1977
|
-
var ChatInput = React4.forwardRef(
|
|
1978
|
-
(props, ref) => {
|
|
1979
|
-
const {
|
|
1980
|
-
placeholder,
|
|
1981
|
-
value: valueProp,
|
|
1982
|
-
disabled = false,
|
|
1983
|
-
buttonType = "primary",
|
|
1984
|
-
onSubmit,
|
|
1985
|
-
onChange
|
|
1986
|
-
} = props;
|
|
1987
|
-
const isControlled = valueProp !== void 0;
|
|
1988
|
-
const [internalValue, setInternalValue] = React4.useState("");
|
|
1989
|
-
const value = isControlled ? valueProp : internalValue;
|
|
1990
|
-
const hasText = value.trim().length > 0;
|
|
1991
|
-
const textareaRef = React4.useRef(null);
|
|
1992
|
-
const setRefs = React4.useCallback(
|
|
1993
|
-
(el) => {
|
|
1994
|
-
textareaRef.current = el;
|
|
1995
|
-
if (typeof ref === "function") ref(el);
|
|
1996
|
-
else if (ref) ref.current = el;
|
|
1997
|
-
},
|
|
1998
|
-
[ref]
|
|
1999
|
-
);
|
|
2000
|
-
const updateHeight = React4.useCallback(() => {
|
|
2001
|
-
const el = textareaRef.current;
|
|
2002
|
-
if (!el) return;
|
|
2003
|
-
el.style.height = "0px";
|
|
2004
|
-
el.style.height = `${Math.min(el.scrollHeight, MAX_HEIGHT)}px`;
|
|
2005
|
-
}, []);
|
|
2006
|
-
const handleChange = (e) => {
|
|
2007
|
-
const val = e.target.value;
|
|
2008
|
-
if (!isControlled) setInternalValue(val);
|
|
2009
|
-
onChange?.(val);
|
|
2010
|
-
};
|
|
2011
|
-
const handleSubmit = () => {
|
|
2012
|
-
if (!hasText || disabled) return;
|
|
2013
|
-
onSubmit?.(value);
|
|
2014
|
-
if (!isControlled) setInternalValue("");
|
|
2015
|
-
requestAnimationFrame(updateHeight);
|
|
2016
|
-
};
|
|
2017
|
-
const handleKeyDown = (e) => {
|
|
2018
|
-
if (e.key === "Enter" && !e.shiftKey) {
|
|
2019
|
-
e.preventDefault();
|
|
2020
|
-
handleSubmit();
|
|
2021
|
-
}
|
|
2022
|
-
};
|
|
2023
|
-
React4.useEffect(() => {
|
|
2024
|
-
updateHeight();
|
|
2025
|
-
}, [value, updateHeight]);
|
|
2026
|
-
return /* @__PURE__ */ jsxs194("div", { className: clsx_default("lib-xplat-chat-input", disabled && "disabled"), children: [
|
|
2027
|
-
/* @__PURE__ */ jsx303(
|
|
2028
|
-
"textarea",
|
|
2029
|
-
{
|
|
2030
|
-
ref: setRefs,
|
|
2031
|
-
className: "chat-input-textarea",
|
|
2032
|
-
placeholder,
|
|
2033
|
-
value,
|
|
2034
|
-
disabled,
|
|
2035
|
-
rows: 1,
|
|
2036
|
-
onChange: handleChange,
|
|
2037
|
-
onKeyDown: handleKeyDown
|
|
2038
|
-
}
|
|
2039
|
-
),
|
|
2040
|
-
/* @__PURE__ */ jsx303(
|
|
2041
|
-
IconButton_default,
|
|
2042
|
-
{
|
|
2043
|
-
icon: /* @__PURE__ */ jsx303(MessageSquareIcon_default, {}),
|
|
2044
|
-
type: buttonType,
|
|
2045
|
-
size: "sm",
|
|
2046
|
-
disabled: !hasText || disabled,
|
|
2047
|
-
onClick: handleSubmit,
|
|
2048
|
-
"aria-label": "\uC804\uC1A1"
|
|
2049
|
-
}
|
|
2050
|
-
)
|
|
2051
|
-
] });
|
|
2052
|
-
}
|
|
2053
|
-
);
|
|
2054
|
-
ChatInput.displayName = "ChatInput";
|
|
2055
|
-
var ChatInput_default = ChatInput;
|
|
2056
|
-
|
|
2057
|
-
// src/components/Box/Box.tsx
|
|
2058
|
-
import { jsx as jsx304, jsxs as jsxs195 } from "react/jsx-runtime";
|
|
2059
|
-
var Box = ({
|
|
2060
|
-
children,
|
|
2061
|
-
title,
|
|
2062
|
-
variant = "outlined",
|
|
2063
|
-
padding = "md"
|
|
2064
|
-
}) => {
|
|
2065
|
-
return /* @__PURE__ */ jsxs195("div", { className: clsx_default("lib-xplat-box", variant, `pad-${padding}`), children: [
|
|
2066
|
-
title && /* @__PURE__ */ jsx304("div", { className: "box-title", children: title }),
|
|
2067
|
-
/* @__PURE__ */ jsx304("div", { className: "box-content", children })
|
|
2068
|
-
] });
|
|
2069
|
-
};
|
|
2070
|
-
Box.displayName = "Box";
|
|
2071
|
-
var Box_default = Box;
|
|
2072
|
-
|
|
2073
1964
|
// src/components/CardTab/CardTab.tsx
|
|
2074
|
-
import
|
|
1965
|
+
import React4 from "react";
|
|
2075
1966
|
|
|
2076
1967
|
// src/components/CardTab/CardTabPanel.tsx
|
|
2077
|
-
import { jsx as
|
|
1968
|
+
import { jsx as jsx303 } from "react/jsx-runtime";
|
|
2078
1969
|
var CardTabPanel = (props) => {
|
|
2079
1970
|
const { children, columns = 3 } = props;
|
|
2080
|
-
return /* @__PURE__ */
|
|
1971
|
+
return /* @__PURE__ */ jsx303(
|
|
2081
1972
|
"div",
|
|
2082
1973
|
{
|
|
2083
1974
|
className: "card-tab-panel",
|
|
@@ -2090,7 +1981,7 @@ CardTabPanel.displayName = "CardTab.Panel";
|
|
|
2090
1981
|
var CardTabPanel_default = CardTabPanel;
|
|
2091
1982
|
|
|
2092
1983
|
// src/components/CardTab/CardTab.tsx
|
|
2093
|
-
import { jsx as
|
|
1984
|
+
import { jsx as jsx304, jsxs as jsxs195 } from "react/jsx-runtime";
|
|
2094
1985
|
var CardTabRoot = (props) => {
|
|
2095
1986
|
const {
|
|
2096
1987
|
tabs,
|
|
@@ -2100,7 +1991,7 @@ var CardTabRoot = (props) => {
|
|
|
2100
1991
|
children
|
|
2101
1992
|
} = props;
|
|
2102
1993
|
const isControlled = activeValueProp !== void 0;
|
|
2103
|
-
const [uncontrolledValue, setUncontrolledValue] =
|
|
1994
|
+
const [uncontrolledValue, setUncontrolledValue] = React4.useState(tabs[0]?.value ?? "");
|
|
2104
1995
|
const activeValue = isControlled ? activeValueProp : uncontrolledValue;
|
|
2105
1996
|
const handleTabClick = (tab) => {
|
|
2106
1997
|
if (!isControlled) {
|
|
@@ -2108,16 +1999,16 @@ var CardTabRoot = (props) => {
|
|
|
2108
1999
|
}
|
|
2109
2000
|
onChange?.(tab);
|
|
2110
2001
|
};
|
|
2111
|
-
const panels =
|
|
2112
|
-
(child) =>
|
|
2002
|
+
const panels = React4.Children.toArray(children).filter(
|
|
2003
|
+
(child) => React4.isValidElement(child) && child.type === CardTabPanel_default
|
|
2113
2004
|
);
|
|
2114
2005
|
const activePanel = panels.find(
|
|
2115
2006
|
(panel) => panel.props.value === activeValue
|
|
2116
2007
|
);
|
|
2117
|
-
return /* @__PURE__ */
|
|
2118
|
-
/* @__PURE__ */
|
|
2008
|
+
return /* @__PURE__ */ jsxs195("div", { className: clsx_default("lib-xplat-card-tab", size), children: [
|
|
2009
|
+
/* @__PURE__ */ jsx304("div", { className: "card-tab-bar", children: tabs.map((tab) => {
|
|
2119
2010
|
const isActive = tab.value === activeValue;
|
|
2120
|
-
return /* @__PURE__ */
|
|
2011
|
+
return /* @__PURE__ */ jsx304(
|
|
2121
2012
|
"button",
|
|
2122
2013
|
{
|
|
2123
2014
|
className: clsx_default("card-tab-trigger", isActive && "active"),
|
|
@@ -2129,7 +2020,7 @@ var CardTabRoot = (props) => {
|
|
|
2129
2020
|
tab.value
|
|
2130
2021
|
);
|
|
2131
2022
|
}) }),
|
|
2132
|
-
/* @__PURE__ */
|
|
2023
|
+
/* @__PURE__ */ jsx304("div", { className: "card-tab-body", children: activePanel })
|
|
2133
2024
|
] });
|
|
2134
2025
|
};
|
|
2135
2026
|
CardTabRoot.displayName = "CardTab";
|
|
@@ -2139,8 +2030,8 @@ var CardTab = Object.assign(CardTabRoot, {
|
|
|
2139
2030
|
var CardTab_default = CardTab;
|
|
2140
2031
|
|
|
2141
2032
|
// src/components/Chart/Chart.tsx
|
|
2142
|
-
import
|
|
2143
|
-
import { Fragment as Fragment2, jsx as
|
|
2033
|
+
import React5 from "react";
|
|
2034
|
+
import { Fragment as Fragment2, jsx as jsx305, jsxs as jsxs196 } from "react/jsx-runtime";
|
|
2144
2035
|
var CATEGORICAL_COUNT2 = 8;
|
|
2145
2036
|
var LINE_BAR_PALETTES = Array.from({ length: CATEGORICAL_COUNT2 }, (_, i) => {
|
|
2146
2037
|
const n = i + 1;
|
|
@@ -2185,8 +2076,8 @@ var toSmoothPath = (points) => {
|
|
|
2185
2076
|
return d;
|
|
2186
2077
|
};
|
|
2187
2078
|
var useChartSize = (ref) => {
|
|
2188
|
-
const [size, setSize] =
|
|
2189
|
-
|
|
2079
|
+
const [size, setSize] = React5.useState({ width: 0, height: 0 });
|
|
2080
|
+
React5.useEffect(() => {
|
|
2190
2081
|
const el = ref.current;
|
|
2191
2082
|
if (!el) return;
|
|
2192
2083
|
let rafId = 0;
|
|
@@ -2212,10 +2103,10 @@ var useChartSize = (ref) => {
|
|
|
2212
2103
|
};
|
|
2213
2104
|
var prefersReducedMotion = () => typeof window !== "undefined" && window.matchMedia("(prefers-reduced-motion: reduce)").matches;
|
|
2214
2105
|
var useChartAnimation = (containerRef, dataKey) => {
|
|
2215
|
-
const [animate, setAnimate] =
|
|
2216
|
-
const prevDataKey =
|
|
2217
|
-
const hasAnimated =
|
|
2218
|
-
|
|
2106
|
+
const [animate, setAnimate] = React5.useState(false);
|
|
2107
|
+
const prevDataKey = React5.useRef(dataKey);
|
|
2108
|
+
const hasAnimated = React5.useRef(false);
|
|
2109
|
+
React5.useEffect(() => {
|
|
2219
2110
|
if (prefersReducedMotion()) return;
|
|
2220
2111
|
const el = containerRef.current;
|
|
2221
2112
|
if (!el) return;
|
|
@@ -2231,7 +2122,7 @@ var useChartAnimation = (containerRef, dataKey) => {
|
|
|
2231
2122
|
observer.observe(el);
|
|
2232
2123
|
return () => observer.disconnect();
|
|
2233
2124
|
}, [containerRef]);
|
|
2234
|
-
|
|
2125
|
+
React5.useEffect(() => {
|
|
2235
2126
|
if (dataKey !== prevDataKey.current) {
|
|
2236
2127
|
prevDataKey.current = dataKey;
|
|
2237
2128
|
if (prefersReducedMotion()) return;
|
|
@@ -2245,15 +2136,15 @@ var useChartAnimation = (containerRef, dataKey) => {
|
|
|
2245
2136
|
};
|
|
2246
2137
|
var TOOLTIP_OFFSET = 12;
|
|
2247
2138
|
var useChartTooltip = (enabled) => {
|
|
2248
|
-
const [tooltip, setTooltip] =
|
|
2139
|
+
const [tooltip, setTooltip] = React5.useState({
|
|
2249
2140
|
visible: false,
|
|
2250
2141
|
x: 0,
|
|
2251
2142
|
y: 0,
|
|
2252
2143
|
content: ""
|
|
2253
2144
|
});
|
|
2254
|
-
const containerRef =
|
|
2255
|
-
const rafRef =
|
|
2256
|
-
const move =
|
|
2145
|
+
const containerRef = React5.useRef(null);
|
|
2146
|
+
const rafRef = React5.useRef(0);
|
|
2147
|
+
const move = React5.useCallback((e) => {
|
|
2257
2148
|
if (!enabled) return;
|
|
2258
2149
|
const cx = e.clientX;
|
|
2259
2150
|
const cy = e.clientY;
|
|
@@ -2264,24 +2155,24 @@ var useChartTooltip = (enabled) => {
|
|
|
2264
2155
|
setTooltip((prev) => ({ ...prev, x: cx - rect.left, y: cy - rect.top }));
|
|
2265
2156
|
});
|
|
2266
2157
|
}, [enabled]);
|
|
2267
|
-
const show =
|
|
2158
|
+
const show = React5.useCallback((e, content) => {
|
|
2268
2159
|
if (!enabled) return;
|
|
2269
2160
|
const rect = containerRef.current?.getBoundingClientRect();
|
|
2270
2161
|
if (!rect) return;
|
|
2271
2162
|
setTooltip({ visible: true, x: e.clientX - rect.left, y: e.clientY - rect.top, content });
|
|
2272
2163
|
}, [enabled]);
|
|
2273
|
-
const hide =
|
|
2164
|
+
const hide = React5.useCallback(() => {
|
|
2274
2165
|
cancelAnimationFrame(rafRef.current);
|
|
2275
2166
|
setTooltip((prev) => ({ ...prev, visible: false }));
|
|
2276
2167
|
}, []);
|
|
2277
2168
|
return { tooltip, show, hide, move, containerRef };
|
|
2278
2169
|
};
|
|
2279
|
-
var GridLines =
|
|
2170
|
+
var GridLines = React5.memo(({ width, height, chartH, maxVal }) => /* @__PURE__ */ jsx305(Fragment2, { children: [0, 0.25, 0.5, 0.75, 1].map((ratio) => {
|
|
2280
2171
|
const y = PADDING.top + (1 - ratio) * chartH;
|
|
2281
2172
|
const val = Math.round(maxVal * ratio);
|
|
2282
|
-
return /* @__PURE__ */
|
|
2283
|
-
/* @__PURE__ */
|
|
2284
|
-
/* @__PURE__ */
|
|
2173
|
+
return /* @__PURE__ */ jsxs196("g", { children: [
|
|
2174
|
+
/* @__PURE__ */ jsx305("line", { x1: PADDING.left, y1: y, x2: width - PADDING.right, y2: y, className: "chart-grid" }),
|
|
2175
|
+
/* @__PURE__ */ jsx305("text", { x: PADDING.left - 8, y: y + 4, className: "chart-axis-label", textAnchor: "end", children: val })
|
|
2285
2176
|
] }, ratio);
|
|
2286
2177
|
}) }));
|
|
2287
2178
|
GridLines.displayName = "GridLines";
|
|
@@ -2291,18 +2182,18 @@ var getLabelStep = (count, chartW) => {
|
|
|
2291
2182
|
if (count <= maxLabels) return 1;
|
|
2292
2183
|
return Math.ceil(count / maxLabels);
|
|
2293
2184
|
};
|
|
2294
|
-
var AxisLabels =
|
|
2185
|
+
var AxisLabels = React5.memo(({ labels, count, chartW, height }) => {
|
|
2295
2186
|
const step = getLabelStep(count, chartW);
|
|
2296
|
-
return /* @__PURE__ */
|
|
2187
|
+
return /* @__PURE__ */ jsx305(Fragment2, { children: labels.map((label, i) => {
|
|
2297
2188
|
if (i % step !== 0) return null;
|
|
2298
2189
|
const x = PADDING.left + i / (count - 1 || 1) * chartW;
|
|
2299
|
-
return /* @__PURE__ */
|
|
2190
|
+
return /* @__PURE__ */ jsx305("text", { x, y: height - 8, className: "chart-axis-label", textAnchor: "middle", children: label }, i);
|
|
2300
2191
|
}) });
|
|
2301
2192
|
});
|
|
2302
2193
|
AxisLabels.displayName = "AxisLabels";
|
|
2303
2194
|
var useCrosshair = (seriesPoints, entries, labels, chartH) => {
|
|
2304
|
-
const [activeIndex, setActiveIndex] =
|
|
2305
|
-
const handleMouseMove =
|
|
2195
|
+
const [activeIndex, setActiveIndex] = React5.useState(null);
|
|
2196
|
+
const handleMouseMove = React5.useCallback((e) => {
|
|
2306
2197
|
const svg = e.currentTarget;
|
|
2307
2198
|
const rect = svg.getBoundingClientRect();
|
|
2308
2199
|
const mx = (e.clientX - rect.left) / rect.width * svg.viewBox.baseVal.width;
|
|
@@ -2321,17 +2212,17 @@ var useCrosshair = (seriesPoints, entries, labels, chartH) => {
|
|
|
2321
2212
|
}
|
|
2322
2213
|
setActiveIndex(minDist <= threshold ? closest : null);
|
|
2323
2214
|
}, [seriesPoints]);
|
|
2324
|
-
const handleMouseLeave =
|
|
2215
|
+
const handleMouseLeave = React5.useCallback(() => {
|
|
2325
2216
|
setActiveIndex(null);
|
|
2326
2217
|
}, []);
|
|
2327
|
-
const tooltipContent =
|
|
2218
|
+
const tooltipContent = React5.useMemo(() => {
|
|
2328
2219
|
if (activeIndex === null) return "";
|
|
2329
2220
|
return entries.map(([key], di) => {
|
|
2330
2221
|
const p = seriesPoints[di]?.[activeIndex];
|
|
2331
2222
|
return p ? `${key}: ${p.v}` : "";
|
|
2332
2223
|
}).filter(Boolean).join(" / ");
|
|
2333
2224
|
}, [activeIndex, entries, seriesPoints]);
|
|
2334
|
-
const getTooltipAt =
|
|
2225
|
+
const getTooltipAt = React5.useCallback((idx) => {
|
|
2335
2226
|
return entries.map(([key], di) => {
|
|
2336
2227
|
const p = seriesPoints[di]?.[idx];
|
|
2337
2228
|
return p ? `${key}: ${p.v}` : "";
|
|
@@ -2339,16 +2230,16 @@ var useCrosshair = (seriesPoints, entries, labels, chartH) => {
|
|
|
2339
2230
|
}, [entries, seriesPoints]);
|
|
2340
2231
|
return { activeIndex, handleMouseMove, handleMouseLeave, tooltipContent, getTooltipAt };
|
|
2341
2232
|
};
|
|
2342
|
-
var LineChart =
|
|
2343
|
-
const entries =
|
|
2344
|
-
const maxVal =
|
|
2233
|
+
var LineChart = React5.memo(({ data, labels, width, height, animate, onHover, onMove, onLeave }) => {
|
|
2234
|
+
const entries = React5.useMemo(() => Object.entries(data), [data]);
|
|
2235
|
+
const maxVal = React5.useMemo(() => {
|
|
2345
2236
|
const allValues = entries.flatMap(([, v]) => v);
|
|
2346
2237
|
return Math.max(...allValues) * 1.2 || 1;
|
|
2347
2238
|
}, [entries]);
|
|
2348
2239
|
const count = labels.length;
|
|
2349
2240
|
const chartW = width - PADDING.left - PADDING.right;
|
|
2350
2241
|
const chartH = height - PADDING.top - PADDING.bottom;
|
|
2351
|
-
const seriesPoints =
|
|
2242
|
+
const seriesPoints = React5.useMemo(
|
|
2352
2243
|
() => entries.map(
|
|
2353
2244
|
([, values]) => values.map((v, i) => ({
|
|
2354
2245
|
x: PADDING.left + i / (count - 1 || 1) * chartW,
|
|
@@ -2358,9 +2249,9 @@ var LineChart = React6.memo(({ data, labels, width, height, animate, onHover, on
|
|
|
2358
2249
|
),
|
|
2359
2250
|
[entries, count, chartW, chartH, maxVal]
|
|
2360
2251
|
);
|
|
2361
|
-
const clipRef =
|
|
2252
|
+
const clipRef = React5.useRef(null);
|
|
2362
2253
|
const { activeIndex, handleMouseMove, handleMouseLeave, getTooltipAt } = useCrosshair(seriesPoints, entries, labels, chartH);
|
|
2363
|
-
|
|
2254
|
+
React5.useEffect(() => {
|
|
2364
2255
|
if (!animate || !clipRef.current) return;
|
|
2365
2256
|
clipRef.current.setAttribute("width", "0");
|
|
2366
2257
|
requestAnimationFrame(() => {
|
|
@@ -2372,7 +2263,7 @@ var LineChart = React6.memo(({ data, labels, width, height, animate, onHover, on
|
|
|
2372
2263
|
}, [animate, width]);
|
|
2373
2264
|
const activeX = activeIndex !== null ? seriesPoints[0]?.[activeIndex]?.x ?? null : null;
|
|
2374
2265
|
const lineClipId = "line-area-clip";
|
|
2375
|
-
return /* @__PURE__ */
|
|
2266
|
+
return /* @__PURE__ */ jsxs196(
|
|
2376
2267
|
"svg",
|
|
2377
2268
|
{
|
|
2378
2269
|
viewBox: `0 0 ${width} ${height}`,
|
|
@@ -2390,9 +2281,9 @@ var LineChart = React6.memo(({ data, labels, width, height, animate, onHover, on
|
|
|
2390
2281
|
onLeave();
|
|
2391
2282
|
},
|
|
2392
2283
|
children: [
|
|
2393
|
-
animate && /* @__PURE__ */
|
|
2394
|
-
/* @__PURE__ */
|
|
2395
|
-
/* @__PURE__ */
|
|
2284
|
+
animate && /* @__PURE__ */ jsx305("defs", { children: /* @__PURE__ */ jsx305("clipPath", { id: lineClipId, children: /* @__PURE__ */ jsx305("rect", { ref: clipRef, x: "0", y: "0", width: animate ? 0 : width, height }) }) }),
|
|
2285
|
+
/* @__PURE__ */ jsx305(GridLines, { width, height, chartH, maxVal }),
|
|
2286
|
+
/* @__PURE__ */ jsx305(AxisLabels, { labels, count, chartW, height }),
|
|
2396
2287
|
entries.map(([key], di) => {
|
|
2397
2288
|
const palette = getPalette(LINE_BAR_PALETTES, di, key);
|
|
2398
2289
|
const color = palette[2];
|
|
@@ -2401,16 +2292,16 @@ var LineChart = React6.memo(({ data, labels, width, height, animate, onHover, on
|
|
|
2401
2292
|
const gradientId = `line-gradient-${di}`;
|
|
2402
2293
|
const polyPoints = points.map((p) => `${p.x},${p.y}`).join(" ");
|
|
2403
2294
|
const areaD = `M ${points[0].x},${points[0].y} ${points.map((p) => `L ${p.x},${p.y}`).join(" ")} L ${points[points.length - 1].x},${PADDING.top + chartH} L ${points[0].x},${PADDING.top + chartH} Z`;
|
|
2404
|
-
return /* @__PURE__ */
|
|
2405
|
-
/* @__PURE__ */
|
|
2406
|
-
/* @__PURE__ */
|
|
2407
|
-
/* @__PURE__ */
|
|
2295
|
+
return /* @__PURE__ */ jsxs196("g", { children: [
|
|
2296
|
+
/* @__PURE__ */ jsx305("defs", { children: /* @__PURE__ */ jsxs196("linearGradient", { id: gradientId, x1: "0", y1: "0", x2: "0", y2: "1", children: [
|
|
2297
|
+
/* @__PURE__ */ jsx305("stop", { offset: "0%", stopColor: areaColor, stopOpacity: "0.2" }),
|
|
2298
|
+
/* @__PURE__ */ jsx305("stop", { offset: "100%", stopColor: areaColor, stopOpacity: "0" })
|
|
2408
2299
|
] }) }),
|
|
2409
|
-
/* @__PURE__ */
|
|
2410
|
-
/* @__PURE__ */
|
|
2411
|
-
/* @__PURE__ */
|
|
2300
|
+
/* @__PURE__ */ jsxs196("g", { clipPath: animate ? `url(#${lineClipId})` : void 0, children: [
|
|
2301
|
+
/* @__PURE__ */ jsx305("path", { d: areaD, fill: `url(#${gradientId})` }),
|
|
2302
|
+
/* @__PURE__ */ jsx305("polyline", { points: polyPoints, fill: "none", stroke: color, strokeWidth: "2" })
|
|
2412
2303
|
] }),
|
|
2413
|
-
activeIndex !== null && points[activeIndex] && /* @__PURE__ */
|
|
2304
|
+
activeIndex !== null && points[activeIndex] && /* @__PURE__ */ jsx305(
|
|
2414
2305
|
"circle",
|
|
2415
2306
|
{
|
|
2416
2307
|
cx: points[activeIndex].x,
|
|
@@ -2422,7 +2313,7 @@ var LineChart = React6.memo(({ data, labels, width, height, animate, onHover, on
|
|
|
2422
2313
|
)
|
|
2423
2314
|
] }, di);
|
|
2424
2315
|
}),
|
|
2425
|
-
activeX !== null && /* @__PURE__ */
|
|
2316
|
+
activeX !== null && /* @__PURE__ */ jsx305(
|
|
2426
2317
|
"line",
|
|
2427
2318
|
{
|
|
2428
2319
|
x1: activeX,
|
|
@@ -2432,7 +2323,7 @@ var LineChart = React6.memo(({ data, labels, width, height, animate, onHover, on
|
|
|
2432
2323
|
className: "chart-crosshair"
|
|
2433
2324
|
}
|
|
2434
2325
|
),
|
|
2435
|
-
/* @__PURE__ */
|
|
2326
|
+
/* @__PURE__ */ jsx305(
|
|
2436
2327
|
"rect",
|
|
2437
2328
|
{
|
|
2438
2329
|
x: PADDING.left,
|
|
@@ -2448,16 +2339,16 @@ var LineChart = React6.memo(({ data, labels, width, height, animate, onHover, on
|
|
|
2448
2339
|
);
|
|
2449
2340
|
});
|
|
2450
2341
|
LineChart.displayName = "LineChart";
|
|
2451
|
-
var CurveChart =
|
|
2452
|
-
const entries =
|
|
2453
|
-
const maxVal =
|
|
2342
|
+
var CurveChart = React5.memo(({ data, labels, width, height, animate, onHover, onMove, onLeave }) => {
|
|
2343
|
+
const entries = React5.useMemo(() => Object.entries(data), [data]);
|
|
2344
|
+
const maxVal = React5.useMemo(() => {
|
|
2454
2345
|
const allValues = entries.flatMap(([, v]) => v);
|
|
2455
2346
|
return Math.max(...allValues) * 1.2 || 1;
|
|
2456
2347
|
}, [entries]);
|
|
2457
2348
|
const count = labels.length;
|
|
2458
2349
|
const chartW = width - PADDING.left - PADDING.right;
|
|
2459
2350
|
const chartH = height - PADDING.top - PADDING.bottom;
|
|
2460
|
-
const seriesPoints =
|
|
2351
|
+
const seriesPoints = React5.useMemo(
|
|
2461
2352
|
() => entries.map(
|
|
2462
2353
|
([, values]) => values.map((v, i) => ({
|
|
2463
2354
|
x: PADDING.left + i / (count - 1 || 1) * chartW,
|
|
@@ -2467,9 +2358,9 @@ var CurveChart = React6.memo(({ data, labels, width, height, animate, onHover, o
|
|
|
2467
2358
|
),
|
|
2468
2359
|
[entries, count, chartW, chartH, maxVal]
|
|
2469
2360
|
);
|
|
2470
|
-
const curveClipRef =
|
|
2361
|
+
const curveClipRef = React5.useRef(null);
|
|
2471
2362
|
const { activeIndex, handleMouseMove, handleMouseLeave, getTooltipAt } = useCrosshair(seriesPoints, entries, labels, chartH);
|
|
2472
|
-
|
|
2363
|
+
React5.useEffect(() => {
|
|
2473
2364
|
if (!animate || !curveClipRef.current) return;
|
|
2474
2365
|
curveClipRef.current.setAttribute("width", "0");
|
|
2475
2366
|
requestAnimationFrame(() => {
|
|
@@ -2481,7 +2372,7 @@ var CurveChart = React6.memo(({ data, labels, width, height, animate, onHover, o
|
|
|
2481
2372
|
}, [animate, width]);
|
|
2482
2373
|
const activeX = activeIndex !== null ? seriesPoints[0]?.[activeIndex]?.x ?? null : null;
|
|
2483
2374
|
const curveClipId = "curve-area-clip";
|
|
2484
|
-
return /* @__PURE__ */
|
|
2375
|
+
return /* @__PURE__ */ jsxs196(
|
|
2485
2376
|
"svg",
|
|
2486
2377
|
{
|
|
2487
2378
|
viewBox: `0 0 ${width} ${height}`,
|
|
@@ -2500,9 +2391,9 @@ var CurveChart = React6.memo(({ data, labels, width, height, animate, onHover, o
|
|
|
2500
2391
|
onLeave();
|
|
2501
2392
|
},
|
|
2502
2393
|
children: [
|
|
2503
|
-
animate && /* @__PURE__ */
|
|
2504
|
-
/* @__PURE__ */
|
|
2505
|
-
/* @__PURE__ */
|
|
2394
|
+
animate && /* @__PURE__ */ jsx305("defs", { children: /* @__PURE__ */ jsx305("clipPath", { id: curveClipId, children: /* @__PURE__ */ jsx305("rect", { ref: curveClipRef, x: "0", y: "0", width: animate ? 0 : width, height }) }) }),
|
|
2395
|
+
/* @__PURE__ */ jsx305(GridLines, { width, height, chartH, maxVal }),
|
|
2396
|
+
/* @__PURE__ */ jsx305(AxisLabels, { labels, count, chartW, height }),
|
|
2506
2397
|
entries.map(([key], di) => {
|
|
2507
2398
|
const palette = getPalette(LINE_BAR_PALETTES, di, key);
|
|
2508
2399
|
const color = palette[2];
|
|
@@ -2511,16 +2402,16 @@ var CurveChart = React6.memo(({ data, labels, width, height, animate, onHover, o
|
|
|
2511
2402
|
const gradientId = `curve-gradient-${di}`;
|
|
2512
2403
|
const linePath = toSmoothPath(points);
|
|
2513
2404
|
const areaPath = linePath + ` L ${points[points.length - 1].x} ${PADDING.top + chartH} L ${points[0].x} ${PADDING.top + chartH} Z`;
|
|
2514
|
-
return /* @__PURE__ */
|
|
2515
|
-
/* @__PURE__ */
|
|
2516
|
-
/* @__PURE__ */
|
|
2517
|
-
/* @__PURE__ */
|
|
2405
|
+
return /* @__PURE__ */ jsxs196("g", { children: [
|
|
2406
|
+
/* @__PURE__ */ jsx305("defs", { children: /* @__PURE__ */ jsxs196("linearGradient", { id: gradientId, x1: "0", y1: "0", x2: "0", y2: "1", children: [
|
|
2407
|
+
/* @__PURE__ */ jsx305("stop", { offset: "0%", stopColor: areaColor, stopOpacity: "0.4" }),
|
|
2408
|
+
/* @__PURE__ */ jsx305("stop", { offset: "100%", stopColor: areaColor, stopOpacity: "0.02" })
|
|
2518
2409
|
] }) }),
|
|
2519
|
-
/* @__PURE__ */
|
|
2520
|
-
/* @__PURE__ */
|
|
2521
|
-
/* @__PURE__ */
|
|
2410
|
+
/* @__PURE__ */ jsxs196("g", { clipPath: animate ? `url(#${curveClipId})` : void 0, children: [
|
|
2411
|
+
/* @__PURE__ */ jsx305("path", { d: areaPath, fill: `url(#${gradientId})` }),
|
|
2412
|
+
/* @__PURE__ */ jsx305("path", { d: linePath, fill: "none", stroke: color, strokeWidth: "2" })
|
|
2522
2413
|
] }),
|
|
2523
|
-
activeIndex !== null && points[activeIndex] && /* @__PURE__ */
|
|
2414
|
+
activeIndex !== null && points[activeIndex] && /* @__PURE__ */ jsx305(
|
|
2524
2415
|
"circle",
|
|
2525
2416
|
{
|
|
2526
2417
|
cx: points[activeIndex].x,
|
|
@@ -2532,7 +2423,7 @@ var CurveChart = React6.memo(({ data, labels, width, height, animate, onHover, o
|
|
|
2532
2423
|
)
|
|
2533
2424
|
] }, di);
|
|
2534
2425
|
}),
|
|
2535
|
-
activeX !== null && /* @__PURE__ */
|
|
2426
|
+
activeX !== null && /* @__PURE__ */ jsx305(
|
|
2536
2427
|
"line",
|
|
2537
2428
|
{
|
|
2538
2429
|
x1: activeX,
|
|
@@ -2542,7 +2433,7 @@ var CurveChart = React6.memo(({ data, labels, width, height, animate, onHover, o
|
|
|
2542
2433
|
className: "chart-crosshair"
|
|
2543
2434
|
}
|
|
2544
2435
|
),
|
|
2545
|
-
/* @__PURE__ */
|
|
2436
|
+
/* @__PURE__ */ jsx305(
|
|
2546
2437
|
"rect",
|
|
2547
2438
|
{
|
|
2548
2439
|
x: PADDING.left,
|
|
@@ -2558,9 +2449,9 @@ var CurveChart = React6.memo(({ data, labels, width, height, animate, onHover, o
|
|
|
2558
2449
|
);
|
|
2559
2450
|
});
|
|
2560
2451
|
CurveChart.displayName = "CurveChart";
|
|
2561
|
-
var BarChart =
|
|
2562
|
-
const entries =
|
|
2563
|
-
const maxVal =
|
|
2452
|
+
var BarChart = React5.memo(({ data, labels, width, height, animate, onHover, onMove, onLeave }) => {
|
|
2453
|
+
const entries = React5.useMemo(() => Object.entries(data), [data]);
|
|
2454
|
+
const maxVal = React5.useMemo(() => {
|
|
2564
2455
|
const allValues = entries.flatMap(([, v]) => v);
|
|
2565
2456
|
return Math.max(...allValues) * 1.2 || 1;
|
|
2566
2457
|
}, [entries]);
|
|
@@ -2572,7 +2463,7 @@ var BarChart = React6.memo(({ data, labels, width, height, animate, onHover, onM
|
|
|
2572
2463
|
const barGap = groupCount > 1 ? 2 : 0;
|
|
2573
2464
|
const barW = Math.max(1, Math.min(32, (groupW * 0.7 - barGap * (groupCount - 1)) / groupCount));
|
|
2574
2465
|
const baseline = PADDING.top + chartH;
|
|
2575
|
-
const bars =
|
|
2466
|
+
const bars = React5.useMemo(
|
|
2576
2467
|
() => entries.map(
|
|
2577
2468
|
([, values], di) => values.map((v, i) => {
|
|
2578
2469
|
const totalBarsW = barW * groupCount + barGap * (groupCount - 1);
|
|
@@ -2585,11 +2476,11 @@ var BarChart = React6.memo(({ data, labels, width, height, animate, onHover, onM
|
|
|
2585
2476
|
[entries, maxVal, chartH, groupW, barW, barGap, groupCount]
|
|
2586
2477
|
);
|
|
2587
2478
|
const barLabelStep = getLabelStep(count, chartW);
|
|
2588
|
-
return /* @__PURE__ */
|
|
2589
|
-
/* @__PURE__ */
|
|
2479
|
+
return /* @__PURE__ */ jsxs196("svg", { viewBox: `0 0 ${width} ${height}`, className: "chart-svg", children: [
|
|
2480
|
+
/* @__PURE__ */ jsx305(GridLines, { width, height, chartH, maxVal }),
|
|
2590
2481
|
labels.map((label, i) => {
|
|
2591
2482
|
if (i % barLabelStep !== 0) return null;
|
|
2592
|
-
return /* @__PURE__ */
|
|
2483
|
+
return /* @__PURE__ */ jsx305("text", { x: PADDING.left + groupW * i + groupW / 2, y: height - 8, className: "chart-axis-label", textAnchor: "middle", children: label }, i);
|
|
2593
2484
|
}),
|
|
2594
2485
|
entries.map(([key], di) => {
|
|
2595
2486
|
const palette = getPalette(LINE_BAR_PALETTES, di, key);
|
|
@@ -2598,7 +2489,7 @@ var BarChart = React6.memo(({ data, labels, width, height, animate, onHover, onM
|
|
|
2598
2489
|
const r2 = Math.min(4, b.w / 2);
|
|
2599
2490
|
const d = b.h <= r2 ? `M ${b.x} ${b.y + b.h} V ${b.y} H ${b.x + b.w} V ${b.y + b.h} Z` : `M ${b.x} ${b.y + b.h} V ${b.y + r2} Q ${b.x} ${b.y} ${b.x + r2} ${b.y} H ${b.x + b.w - r2} Q ${b.x + b.w} ${b.y} ${b.x + b.w} ${b.y + r2} V ${b.y + b.h} Z`;
|
|
2600
2491
|
const delay = 100 + i * 80;
|
|
2601
|
-
return /* @__PURE__ */
|
|
2492
|
+
return /* @__PURE__ */ jsx305(
|
|
2602
2493
|
"path",
|
|
2603
2494
|
{
|
|
2604
2495
|
d,
|
|
@@ -2619,11 +2510,11 @@ var BarChart = React6.memo(({ data, labels, width, height, animate, onHover, onM
|
|
|
2619
2510
|
] });
|
|
2620
2511
|
});
|
|
2621
2512
|
BarChart.displayName = "BarChart";
|
|
2622
|
-
var PieDonutChart =
|
|
2513
|
+
var PieDonutChart = React5.memo(
|
|
2623
2514
|
({ data, labels, width, height, animate, isDoughnut, onHover, onMove, onLeave }) => {
|
|
2624
|
-
const entries =
|
|
2625
|
-
const values =
|
|
2626
|
-
const total =
|
|
2515
|
+
const entries = React5.useMemo(() => Object.entries(data), [data]);
|
|
2516
|
+
const values = React5.useMemo(() => entries.flatMap(([, v]) => v), [entries]);
|
|
2517
|
+
const total = React5.useMemo(() => values.reduce((a, b) => a + b, 0) || 1, [values]);
|
|
2627
2518
|
const size = Math.min(width, height);
|
|
2628
2519
|
const cx = size / 2;
|
|
2629
2520
|
const cy = size / 2;
|
|
@@ -2631,10 +2522,10 @@ var PieDonutChart = React6.memo(
|
|
|
2631
2522
|
const innerR = isDoughnut ? r2 * 0.5 : 0;
|
|
2632
2523
|
const firstKey = entries[0]?.[0] ?? "";
|
|
2633
2524
|
const colorOffset = hashString(firstKey);
|
|
2634
|
-
const maskRef =
|
|
2525
|
+
const maskRef = React5.useRef(null);
|
|
2635
2526
|
const maskR = r2 + 10;
|
|
2636
2527
|
const maskCircumference = 2 * Math.PI * maskR;
|
|
2637
|
-
|
|
2528
|
+
React5.useEffect(() => {
|
|
2638
2529
|
if (!animate || !maskRef.current) return;
|
|
2639
2530
|
const el = maskRef.current;
|
|
2640
2531
|
el.style.strokeDasharray = `${maskCircumference}`;
|
|
@@ -2644,7 +2535,7 @@ var PieDonutChart = React6.memo(
|
|
|
2644
2535
|
el.style.strokeDashoffset = "0";
|
|
2645
2536
|
});
|
|
2646
2537
|
}, [animate, maskCircumference]);
|
|
2647
|
-
const sliceData =
|
|
2538
|
+
const sliceData = React5.useMemo(() => {
|
|
2648
2539
|
let angle0 = -Math.PI / 2;
|
|
2649
2540
|
let cumulativeAngle = 0;
|
|
2650
2541
|
return values.map((v, i) => {
|
|
@@ -2678,8 +2569,8 @@ var PieDonutChart = React6.memo(
|
|
|
2678
2569
|
});
|
|
2679
2570
|
}, [values, total, cx, cy, r2, innerR, labels]);
|
|
2680
2571
|
const maskId = `pie-mask-${isDoughnut ? "d" : "p"}`;
|
|
2681
|
-
return /* @__PURE__ */
|
|
2682
|
-
animate && /* @__PURE__ */
|
|
2572
|
+
return /* @__PURE__ */ jsxs196("svg", { viewBox: `0 0 ${size} ${size}`, className: "chart-svg chart-pie", children: [
|
|
2573
|
+
animate && /* @__PURE__ */ jsx305("defs", { children: /* @__PURE__ */ jsx305("mask", { id: maskId, children: /* @__PURE__ */ jsx305(
|
|
2683
2574
|
"circle",
|
|
2684
2575
|
{
|
|
2685
2576
|
ref: maskRef,
|
|
@@ -2692,7 +2583,7 @@ var PieDonutChart = React6.memo(
|
|
|
2692
2583
|
transform: `rotate(-90 ${cx} ${cy})`
|
|
2693
2584
|
}
|
|
2694
2585
|
) }) }),
|
|
2695
|
-
/* @__PURE__ */
|
|
2586
|
+
/* @__PURE__ */ jsx305("g", { mask: animate ? `url(#${maskId})` : void 0, children: sliceData.map((s, i) => /* @__PURE__ */ jsx305("g", { children: /* @__PURE__ */ jsx305(
|
|
2696
2587
|
"path",
|
|
2697
2588
|
{
|
|
2698
2589
|
d: s.d,
|
|
@@ -2708,9 +2599,9 @@ var PieDonutChart = React6.memo(
|
|
|
2708
2599
|
);
|
|
2709
2600
|
PieDonutChart.displayName = "PieDonutChart";
|
|
2710
2601
|
var ChartTooltip = ({ x, y, containerWidth, containerHeight, tooltipType, children }) => {
|
|
2711
|
-
const ref =
|
|
2712
|
-
const [pos, setPos] =
|
|
2713
|
-
|
|
2602
|
+
const ref = React5.useRef(null);
|
|
2603
|
+
const [pos, setPos] = React5.useState({ left: 0, top: 0 });
|
|
2604
|
+
React5.useLayoutEffect(() => {
|
|
2714
2605
|
const el = ref.current;
|
|
2715
2606
|
if (!el) return;
|
|
2716
2607
|
const w = el.offsetWidth;
|
|
@@ -2727,15 +2618,15 @@ var ChartTooltip = ({ x, y, containerWidth, containerHeight, tooltipType, childr
|
|
|
2727
2618
|
const sepIdx = content.indexOf(" \u2014 ");
|
|
2728
2619
|
const title = sepIdx >= 0 ? content.slice(0, sepIdx) : content;
|
|
2729
2620
|
const desc = sepIdx >= 0 ? content.slice(sepIdx + 3) : "";
|
|
2730
|
-
return /* @__PURE__ */
|
|
2621
|
+
return /* @__PURE__ */ jsxs196(
|
|
2731
2622
|
"div",
|
|
2732
2623
|
{
|
|
2733
2624
|
ref,
|
|
2734
2625
|
className: `lib-xplat-tooltip ${tooltipType} chart-tooltip-pos`,
|
|
2735
2626
|
style: { left: pos.left, top: pos.top },
|
|
2736
2627
|
children: [
|
|
2737
|
-
title && /* @__PURE__ */
|
|
2738
|
-
desc && /* @__PURE__ */
|
|
2628
|
+
title && /* @__PURE__ */ jsx305("div", { className: "tooltip-title", children: title }),
|
|
2629
|
+
desc && /* @__PURE__ */ jsx305("div", { className: "tooltip-desc", children: desc })
|
|
2739
2630
|
]
|
|
2740
2631
|
}
|
|
2741
2632
|
);
|
|
@@ -2747,14 +2638,14 @@ var ChartLegend = ({ data, labels, type }) => {
|
|
|
2747
2638
|
const total = values.reduce((a, b) => a + b, 0) || 1;
|
|
2748
2639
|
const firstKey = entries[0]?.[0] ?? "";
|
|
2749
2640
|
const colorOffset = hashString(firstKey);
|
|
2750
|
-
return /* @__PURE__ */
|
|
2641
|
+
return /* @__PURE__ */ jsx305("div", { className: "chart-legend", children: values.map((v, i) => {
|
|
2751
2642
|
const pct = Math.round(v / total * 100);
|
|
2752
2643
|
const color = PIE_COLORS[(i + colorOffset) % PIE_COLORS.length];
|
|
2753
|
-
return /* @__PURE__ */
|
|
2754
|
-
/* @__PURE__ */
|
|
2755
|
-
/* @__PURE__ */
|
|
2756
|
-
/* @__PURE__ */
|
|
2757
|
-
/* @__PURE__ */
|
|
2644
|
+
return /* @__PURE__ */ jsxs196("div", { className: "chart-legend-item", children: [
|
|
2645
|
+
/* @__PURE__ */ jsx305("span", { className: "chart-legend-dot", style: { backgroundColor: color } }),
|
|
2646
|
+
/* @__PURE__ */ jsxs196("div", { className: "chart-legend-text", children: [
|
|
2647
|
+
/* @__PURE__ */ jsx305("span", { className: "chart-legend-label", children: labels[i] || `${i + 1}` }),
|
|
2648
|
+
/* @__PURE__ */ jsxs196("span", { className: "chart-legend-value", children: [
|
|
2758
2649
|
v.toLocaleString(),
|
|
2759
2650
|
"(",
|
|
2760
2651
|
pct,
|
|
@@ -2764,42 +2655,151 @@ var ChartLegend = ({ data, labels, type }) => {
|
|
|
2764
2655
|
] }, i);
|
|
2765
2656
|
}) });
|
|
2766
2657
|
}
|
|
2767
|
-
return /* @__PURE__ */
|
|
2658
|
+
return /* @__PURE__ */ jsx305("div", { className: "chart-legend", children: entries.map(([key], di) => {
|
|
2768
2659
|
const palette = getPalette(LINE_BAR_PALETTES, di, key);
|
|
2769
2660
|
const color = palette[2];
|
|
2770
2661
|
const values = entries[di][1];
|
|
2771
2662
|
const sum = values.reduce((a, b) => a + b, 0);
|
|
2772
|
-
return /* @__PURE__ */
|
|
2773
|
-
/* @__PURE__ */
|
|
2774
|
-
/* @__PURE__ */
|
|
2775
|
-
/* @__PURE__ */
|
|
2776
|
-
/* @__PURE__ */
|
|
2663
|
+
return /* @__PURE__ */ jsxs196("div", { className: "chart-legend-item", children: [
|
|
2664
|
+
/* @__PURE__ */ jsx305("span", { className: "chart-legend-dot", style: { backgroundColor: color } }),
|
|
2665
|
+
/* @__PURE__ */ jsxs196("div", { className: "chart-legend-text", children: [
|
|
2666
|
+
/* @__PURE__ */ jsx305("span", { className: "chart-legend-label", children: key }),
|
|
2667
|
+
/* @__PURE__ */ jsx305("span", { className: "chart-legend-value", children: sum.toLocaleString() })
|
|
2777
2668
|
] })
|
|
2778
2669
|
] }, di);
|
|
2779
2670
|
}) });
|
|
2780
2671
|
};
|
|
2781
|
-
var Chart =
|
|
2672
|
+
var Chart = React5.memo((props) => {
|
|
2782
2673
|
const { type, data, labels, tooltip: showTooltip = true, tooltipType = "light" } = props;
|
|
2783
2674
|
const { tooltip, show, hide, move, containerRef } = useChartTooltip(showTooltip);
|
|
2784
2675
|
const { width, height } = useChartSize(containerRef);
|
|
2785
|
-
const stableData =
|
|
2786
|
-
const stableLabels =
|
|
2787
|
-
const dataKey =
|
|
2676
|
+
const stableData = React5.useMemo(() => data, [JSON.stringify(data)]);
|
|
2677
|
+
const stableLabels = React5.useMemo(() => labels, [JSON.stringify(labels)]);
|
|
2678
|
+
const dataKey = React5.useMemo(() => JSON.stringify(labels), [labels]);
|
|
2788
2679
|
const animate = useChartAnimation(containerRef, dataKey);
|
|
2789
2680
|
const ready = width > 0 && height > 0;
|
|
2790
|
-
return /* @__PURE__ */
|
|
2791
|
-
ready && type === "line" && /* @__PURE__ */
|
|
2792
|
-
ready && type === "curve" && /* @__PURE__ */
|
|
2793
|
-
ready && type === "bar" && /* @__PURE__ */
|
|
2794
|
-
ready && type === "pie" && /* @__PURE__ */
|
|
2795
|
-
ready && type === "doughnut" && /* @__PURE__ */
|
|
2796
|
-
ready && (type === "pie" || type === "doughnut") && /* @__PURE__ */
|
|
2797
|
-
tooltip.visible && tooltip.content && /* @__PURE__ */
|
|
2681
|
+
return /* @__PURE__ */ jsxs196("div", { className: "lib-xplat-chart", ref: containerRef, children: [
|
|
2682
|
+
ready && type === "line" && /* @__PURE__ */ jsx305(LineChart, { data: stableData, labels: stableLabels, width, height, animate, onHover: show, onMove: move, onLeave: hide }),
|
|
2683
|
+
ready && type === "curve" && /* @__PURE__ */ jsx305(CurveChart, { data: stableData, labels: stableLabels, width, height, animate, onHover: show, onMove: move, onLeave: hide }),
|
|
2684
|
+
ready && type === "bar" && /* @__PURE__ */ jsx305(BarChart, { data: stableData, labels: stableLabels, width, height, animate, onHover: show, onMove: move, onLeave: hide }),
|
|
2685
|
+
ready && type === "pie" && /* @__PURE__ */ jsx305(PieDonutChart, { data: stableData, labels: stableLabels, width, height, animate, onHover: show, onMove: move, onLeave: hide }),
|
|
2686
|
+
ready && type === "doughnut" && /* @__PURE__ */ jsx305(PieDonutChart, { data: stableData, labels: stableLabels, width, height, animate, isDoughnut: true, onHover: show, onMove: move, onLeave: hide }),
|
|
2687
|
+
ready && (type === "pie" || type === "doughnut") && /* @__PURE__ */ jsx305(ChartLegend, { data: stableData, labels: stableLabels, type }),
|
|
2688
|
+
tooltip.visible && tooltip.content && /* @__PURE__ */ jsx305(ChartTooltip, { x: tooltip.x, y: tooltip.y, containerWidth: width, containerHeight: height, tooltipType, children: tooltip.content })
|
|
2798
2689
|
] });
|
|
2799
2690
|
});
|
|
2800
2691
|
Chart.displayName = "Chart";
|
|
2801
2692
|
var Chart_default = Chart;
|
|
2802
2693
|
|
|
2694
|
+
// src/components/ChatInput/ChatInput.tsx
|
|
2695
|
+
import React6 from "react";
|
|
2696
|
+
|
|
2697
|
+
// src/components/IconButton/IconButton.tsx
|
|
2698
|
+
import { jsx as jsx306 } from "react/jsx-runtime";
|
|
2699
|
+
var IconButton = (props) => {
|
|
2700
|
+
const {
|
|
2701
|
+
icon,
|
|
2702
|
+
type = "primary",
|
|
2703
|
+
size = "md",
|
|
2704
|
+
disabled,
|
|
2705
|
+
...rest
|
|
2706
|
+
} = props;
|
|
2707
|
+
return /* @__PURE__ */ jsx306(
|
|
2708
|
+
"button",
|
|
2709
|
+
{
|
|
2710
|
+
className: clsx_default("lib-xplat-icon-button", type, size),
|
|
2711
|
+
disabled,
|
|
2712
|
+
...rest,
|
|
2713
|
+
children: icon
|
|
2714
|
+
}
|
|
2715
|
+
);
|
|
2716
|
+
};
|
|
2717
|
+
IconButton.displayName = "IconButton";
|
|
2718
|
+
var IconButton_default = IconButton;
|
|
2719
|
+
|
|
2720
|
+
// src/components/ChatInput/ChatInput.tsx
|
|
2721
|
+
import { jsx as jsx307, jsxs as jsxs197 } from "react/jsx-runtime";
|
|
2722
|
+
var MAX_HEIGHT = 200;
|
|
2723
|
+
var ChatInput = React6.forwardRef(
|
|
2724
|
+
(props, ref) => {
|
|
2725
|
+
const {
|
|
2726
|
+
placeholder,
|
|
2727
|
+
value: valueProp,
|
|
2728
|
+
disabled = false,
|
|
2729
|
+
buttonType = "primary",
|
|
2730
|
+
onSubmit,
|
|
2731
|
+
onChange
|
|
2732
|
+
} = props;
|
|
2733
|
+
const isControlled = valueProp !== void 0;
|
|
2734
|
+
const [internalValue, setInternalValue] = React6.useState("");
|
|
2735
|
+
const value = isControlled ? valueProp : internalValue;
|
|
2736
|
+
const hasText = value.trim().length > 0;
|
|
2737
|
+
const textareaRef = React6.useRef(null);
|
|
2738
|
+
const setRefs = React6.useCallback(
|
|
2739
|
+
(el) => {
|
|
2740
|
+
textareaRef.current = el;
|
|
2741
|
+
if (typeof ref === "function") ref(el);
|
|
2742
|
+
else if (ref) ref.current = el;
|
|
2743
|
+
},
|
|
2744
|
+
[ref]
|
|
2745
|
+
);
|
|
2746
|
+
const updateHeight = React6.useCallback(() => {
|
|
2747
|
+
const el = textareaRef.current;
|
|
2748
|
+
if (!el) return;
|
|
2749
|
+
el.style.height = "0px";
|
|
2750
|
+
el.style.height = `${Math.min(el.scrollHeight, MAX_HEIGHT)}px`;
|
|
2751
|
+
}, []);
|
|
2752
|
+
const handleChange = (e) => {
|
|
2753
|
+
const val = e.target.value;
|
|
2754
|
+
if (!isControlled) setInternalValue(val);
|
|
2755
|
+
onChange?.(val);
|
|
2756
|
+
};
|
|
2757
|
+
const handleSubmit = () => {
|
|
2758
|
+
if (!hasText || disabled) return;
|
|
2759
|
+
onSubmit?.(value);
|
|
2760
|
+
if (!isControlled) setInternalValue("");
|
|
2761
|
+
requestAnimationFrame(updateHeight);
|
|
2762
|
+
};
|
|
2763
|
+
const handleKeyDown = (e) => {
|
|
2764
|
+
if (e.key === "Enter" && !e.shiftKey) {
|
|
2765
|
+
e.preventDefault();
|
|
2766
|
+
handleSubmit();
|
|
2767
|
+
}
|
|
2768
|
+
};
|
|
2769
|
+
React6.useEffect(() => {
|
|
2770
|
+
updateHeight();
|
|
2771
|
+
}, [value, updateHeight]);
|
|
2772
|
+
return /* @__PURE__ */ jsxs197("div", { className: clsx_default("lib-xplat-chat-input", disabled && "disabled"), children: [
|
|
2773
|
+
/* @__PURE__ */ jsx307(
|
|
2774
|
+
"textarea",
|
|
2775
|
+
{
|
|
2776
|
+
ref: setRefs,
|
|
2777
|
+
className: "chat-input-textarea",
|
|
2778
|
+
placeholder,
|
|
2779
|
+
value,
|
|
2780
|
+
disabled,
|
|
2781
|
+
rows: 1,
|
|
2782
|
+
onChange: handleChange,
|
|
2783
|
+
onKeyDown: handleKeyDown
|
|
2784
|
+
}
|
|
2785
|
+
),
|
|
2786
|
+
/* @__PURE__ */ jsx307(
|
|
2787
|
+
IconButton_default,
|
|
2788
|
+
{
|
|
2789
|
+
icon: /* @__PURE__ */ jsx307(MessageSquareIcon_default, {}),
|
|
2790
|
+
type: buttonType,
|
|
2791
|
+
size: "sm",
|
|
2792
|
+
disabled: !hasText || disabled,
|
|
2793
|
+
onClick: handleSubmit,
|
|
2794
|
+
"aria-label": "\uC804\uC1A1"
|
|
2795
|
+
}
|
|
2796
|
+
)
|
|
2797
|
+
] });
|
|
2798
|
+
}
|
|
2799
|
+
);
|
|
2800
|
+
ChatInput.displayName = "ChatInput";
|
|
2801
|
+
var ChatInput_default = ChatInput;
|
|
2802
|
+
|
|
2803
2803
|
// src/tokens/colors.ts
|
|
2804
2804
|
import { primitive, semantic } from "@x-plat/tokens-core";
|
|
2805
2805
|
|