lucentia-ui 1.2.0 → 1.4.0
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/dist/components/Calendar/ArrowLeftIcon.d.ts +8 -0
- package/dist/components/Calendar/ArrowLeftIcon.js +5 -0
- package/dist/components/Calendar/ArrowRightIcon.d.ts +8 -0
- package/dist/components/Calendar/ArrowRightIcon.js +5 -0
- package/dist/components/Calendar/Calendar.d.ts +6 -0
- package/dist/components/Calendar/Calendar.js +48 -0
- package/dist/components/Calendar/Calendar.module.css +75 -0
- package/dist/components/Calendar/index.d.ts +2 -0
- package/dist/components/Calendar/index.js +1 -0
- package/dist/components/Calendar/types.d.ts +6 -0
- package/dist/components/Calendar/types.js +1 -0
- package/dist/components/Chart/BarChart/Bar.d.ts +11 -0
- package/dist/components/Chart/BarChart/Bar.js +4 -0
- package/dist/components/Chart/BarChart/Bar.module.css +0 -0
- package/dist/components/Chart/BarChart/BarChart.d.ts +2 -0
- package/dist/components/Chart/BarChart/BarChart.js +22 -0
- package/dist/components/Chart/BarChart/BarSeries.d.ts +10 -0
- package/dist/components/Chart/BarChart/BarSeries.js +27 -0
- package/dist/components/Chart/BarChart/types.d.ts +10 -0
- package/dist/components/Chart/BarChart/types.js +1 -0
- package/dist/components/Chart/BarChart/utils.d.ts +3 -0
- package/dist/components/Chart/BarChart/utils.js +26 -0
- package/dist/components/Chart/ChartAxis.d.ts +6 -0
- package/dist/components/Chart/ChartAxis.js +6 -0
- package/dist/components/Chart/ChartContainer.d.ts +11 -0
- package/dist/components/Chart/ChartContainer.js +22 -0
- package/dist/components/Chart/ChartContainer.module.css +51 -0
- package/dist/components/Chart/ChartContext.d.ts +7 -0
- package/dist/components/Chart/ChartContext.js +9 -0
- package/dist/components/Chart/ChartGrid.d.ts +6 -0
- package/dist/components/Chart/ChartGrid.js +19 -0
- package/dist/components/Chart/ChartLegend.d.ts +9 -0
- package/dist/components/Chart/ChartLegend.js +19 -0
- package/dist/components/Chart/ChartTooltip.d.ts +8 -0
- package/dist/components/Chart/ChartTooltip.js +35 -0
- package/dist/components/Chart/ChartXAxis.d.ts +5 -0
- package/dist/components/Chart/ChartXAxis.js +16 -0
- package/dist/components/Chart/ChartYAxis.d.ts +6 -0
- package/dist/components/Chart/ChartYAxis.js +11 -0
- package/dist/components/Chart/LineChart/LineChart.d.ts +2 -0
- package/dist/components/Chart/LineChart/LineChart.js +27 -0
- package/dist/components/Chart/LineChart/LinePath.d.ts +9 -0
- package/dist/components/Chart/LineChart/LinePath.js +7 -0
- package/dist/components/Chart/LineChart/LinePoint.d.ts +9 -0
- package/dist/components/Chart/LineChart/LinePoint.js +4 -0
- package/dist/components/Chart/LineChart/LineSeries.d.ts +9 -0
- package/dist/components/Chart/LineChart/LineSeries.js +24 -0
- package/dist/components/Chart/LineChart/types.d.ts +9 -0
- package/dist/components/Chart/LineChart/types.js +1 -0
- package/dist/components/Chart/PieChart/PieChart.d.ts +2 -0
- package/dist/components/Chart/PieChart/PieChart.js +9 -0
- package/dist/components/Chart/PieChart/PieSeries.d.ts +2 -0
- package/dist/components/Chart/PieChart/PieSeries.js +40 -0
- package/dist/components/Chart/PieChart/PieSlice.d.ts +12 -0
- package/dist/components/Chart/PieChart/PieSlice.js +8 -0
- package/dist/components/Chart/PieChart/types.d.ts +18 -0
- package/dist/components/Chart/PieChart/types.js +1 -0
- package/dist/components/Chart/PieChart/utils.d.ts +5 -0
- package/dist/components/Chart/PieChart/utils.js +27 -0
- package/dist/components/Chart/RadarChart/RadarAxis.d.ts +4 -0
- package/dist/components/Chart/RadarChart/RadarAxis.js +16 -0
- package/dist/components/Chart/RadarChart/RadarChart.d.ts +2 -0
- package/dist/components/Chart/RadarChart/RadarChart.js +11 -0
- package/dist/components/Chart/RadarChart/RadarGrid.d.ts +5 -0
- package/dist/components/Chart/RadarChart/RadarGrid.js +20 -0
- package/dist/components/Chart/RadarChart/RadarSeries.d.ts +2 -0
- package/dist/components/Chart/RadarChart/RadarSeries.js +33 -0
- package/dist/components/Chart/RadarChart/types.d.ts +22 -0
- package/dist/components/Chart/RadarChart/types.js +1 -0
- package/dist/components/Chart/RadarChart/utils.d.ts +5 -0
- package/dist/components/Chart/RadarChart/utils.js +16 -0
- package/dist/components/Chart/index.d.ts +15 -0
- package/dist/components/Chart/index.js +18 -0
- package/dist/components/Chart/utils/getNiceTicks.d.ts +1 -0
- package/dist/components/Chart/utils/getNiceTicks.js +20 -0
- package/dist/components/DatePicker/CalendarIcon.d.ts +8 -0
- package/dist/components/DatePicker/CalendarIcon.js +5 -0
- package/dist/components/DatePicker/DatePicker.d.ts +2 -0
- package/dist/components/DatePicker/DatePicker.js +32 -0
- package/dist/components/DatePicker/DatePicker.module.css +52 -0
- package/dist/components/DatePicker/index.d.ts +2 -0
- package/dist/components/DatePicker/index.js +1 -0
- package/dist/components/DatePicker/types.d.ts +6 -0
- package/dist/components/DatePicker/types.js +1 -0
- package/dist/components/Feedback/Modal/Modal.module.css +1 -1
- package/dist/components/Feedback/Popover/Popover.d.ts +3 -0
- package/dist/components/Feedback/Popover/Popover.js +22 -0
- package/dist/components/Feedback/Popover/PopoverContent.d.ts +2 -0
- package/dist/components/Feedback/Popover/PopoverContent.js +62 -0
- package/dist/components/Feedback/Popover/PopoverTrigger.d.ts +2 -0
- package/dist/components/Feedback/Popover/PopoverTrigger.js +21 -0
- package/dist/components/Feedback/Popover/popover.module.css +14 -0
- package/dist/components/Feedback/Popover/types.d.ts +19 -0
- package/dist/components/Feedback/Popover/types.js +1 -0
- package/dist/index.d.ts +4 -0
- package/dist/index.js +6 -0
- package/dist/styles/tokens.css +28 -4
- package/dist/utils/date/generateCalendar.d.ts +5 -0
- package/dist/utils/date/generateCalendar.js +36 -0
- package/package.json +5 -3
|
@@ -0,0 +1,5 @@
|
|
|
1
|
+
import { jsx as _jsx } from "react/jsx-runtime";
|
|
2
|
+
export const ArrowLeftIcon = ({ size = 24, color = "tranparent", className = "", }) => {
|
|
3
|
+
return (_jsx("svg", { xmlns: "http://www.w3.org/2000/svg", width: size, height: size, viewBox: "0 0 24 24", fill: "none", stroke: color, strokeWidth: "1.5", strokeLinecap: "round", strokeLinejoin: "round", className: className, children: _jsx("svg", { width: "24", height: "24", viewBox: "0 0 24 24", fill: "none", xmlns: "http://www.w3.org/2000/svg", children: _jsx("path", { d: "M15.0303 16.9697C15.3232 17.2626 15.3232 17.7374 15.0303 18.0303C14.7374 18.3232 14.2626 18.3232 13.9697 18.0303L8.46972 12.5303C8.17683 12.2374 8.17683 11.7626 8.46972 11.4697L13.9697 5.96973C14.2626 5.67684 14.7374 5.67684 15.0303 5.96973C15.3232 6.26262 15.3232 6.73738 15.0303 7.03028L10.0605 12L15.0303 16.9697Z", fill: "currentColor" }) }) }));
|
|
4
|
+
};
|
|
5
|
+
export default ArrowLeftIcon;
|
|
@@ -0,0 +1,5 @@
|
|
|
1
|
+
import { jsx as _jsx } from "react/jsx-runtime";
|
|
2
|
+
export const ArrowRightIcon = ({ size = 24, color = "tranparent", className = "", }) => {
|
|
3
|
+
return (_jsx("svg", { xmlns: "http://www.w3.org/2000/svg", width: size, height: size, viewBox: "0 0 24 24", fill: "none", stroke: color, strokeWidth: "1.5", strokeLinecap: "round", strokeLinejoin: "round", className: className, children: _jsx("svg", { width: "24", height: "24", viewBox: "0 0 24 24", fill: "none", xmlns: "http://www.w3.org/2000/svg", children: _jsx("path", { d: "M8.96973 7.03027C8.67684 6.73738 8.67684 6.26261 8.96973 5.96972C9.26262 5.67683 9.73738 5.67683 10.0303 5.96972L15.5303 11.4697C15.8232 11.7626 15.8232 12.2374 15.5303 12.5303L10.0303 18.0303C9.73738 18.3232 9.26262 18.3232 8.96973 18.0303C8.67684 17.7374 8.67684 17.2626 8.96973 16.9697L13.9395 12L8.96973 7.03027Z", fill: "currentColor" }) }) }));
|
|
4
|
+
};
|
|
5
|
+
export default ArrowRightIcon;
|
|
@@ -0,0 +1,6 @@
|
|
|
1
|
+
import { CalendarProps } from "./types";
|
|
2
|
+
interface ExtendedCalendarProps extends CalendarProps {
|
|
3
|
+
locale?: string;
|
|
4
|
+
}
|
|
5
|
+
export declare const Calendar: ({ value, onChange, variant, locale, }: ExtendedCalendarProps) => import("react/jsx-runtime").JSX.Element;
|
|
6
|
+
export {};
|
|
@@ -0,0 +1,48 @@
|
|
|
1
|
+
"use client";
|
|
2
|
+
import { jsx as _jsx, jsxs as _jsxs } from "react/jsx-runtime";
|
|
3
|
+
import { useState } from "react";
|
|
4
|
+
import { ArrowRightIcon } from "./ArrowRightIcon";
|
|
5
|
+
import { ArrowLeftIcon } from "./ArrowLeftIcon";
|
|
6
|
+
import { generateCalendar } from "../../utils/date/generateCalendar";
|
|
7
|
+
import styles from "./Calendar.module.css";
|
|
8
|
+
export const Calendar = ({ value, onChange, variant = "embedded", locale = "ja-JP", // デフォルト値を設定
|
|
9
|
+
}) => {
|
|
10
|
+
const [currentMonth, setCurrentMonth] = useState(value !== null && value !== void 0 ? value : new Date());
|
|
11
|
+
const days = generateCalendar(currentMonth);
|
|
12
|
+
// --- i18n Helpers ---
|
|
13
|
+
// 1. 年月の表示(例:2024年3月 / March 2024)
|
|
14
|
+
const formatTitle = (date) => {
|
|
15
|
+
return new Intl.DateTimeFormat(locale, {
|
|
16
|
+
year: "numeric",
|
|
17
|
+
month: "long",
|
|
18
|
+
}).format(date);
|
|
19
|
+
};
|
|
20
|
+
// 2. 曜日のリスト生成(例:日〜土 / Su〜Sa)
|
|
21
|
+
const getWeekDays = () => {
|
|
22
|
+
const baseDate = new Date(2021, 0, 3); // 日曜日から始まる任意の日付
|
|
23
|
+
return Array.from({ length: 7 }, (_, i) => {
|
|
24
|
+
const date = new Date(baseDate);
|
|
25
|
+
date.setDate(baseDate.getDate() + i);
|
|
26
|
+
return new Intl.DateTimeFormat(locale, { weekday: "short" }).format(date);
|
|
27
|
+
});
|
|
28
|
+
};
|
|
29
|
+
// --- Logic ---
|
|
30
|
+
const isSameDay = (a, b) => a.toDateString() === b.toDateString();
|
|
31
|
+
const isToday = (date) => {
|
|
32
|
+
const today = new Date();
|
|
33
|
+
return date.toDateString() === today.toDateString();
|
|
34
|
+
};
|
|
35
|
+
const handleMonthChange = (offset) => {
|
|
36
|
+
setCurrentMonth(new Date(currentMonth.getFullYear(), currentMonth.getMonth() + offset, 1));
|
|
37
|
+
};
|
|
38
|
+
return (_jsxs("div", { className: `${styles.root} ${styles[variant]}`, children: [_jsxs("div", { className: styles.header, children: [_jsx("button", { onClick: () => handleMonthChange(-1), children: _jsx(ArrowLeftIcon, {}) }), _jsx("span", { className: styles.title, children: formatTitle(currentMonth) }), _jsx("button", { onClick: () => handleMonthChange(1), children: _jsx(ArrowRightIcon, {}) })] }), _jsx("div", { className: styles.week, children: getWeekDays().map((d) => (_jsx("div", { className: styles.weekDay, children: d }, d))) }), _jsx("div", { className: styles.grid, children: days.map((day, i) => {
|
|
39
|
+
const isSelected = value && isSameDay(day.date, value);
|
|
40
|
+
const today = isToday(day.date);
|
|
41
|
+
return (_jsx("button", { onClick: () => onChange === null || onChange === void 0 ? void 0 : onChange(day.date), className: `
|
|
42
|
+
${styles.cell}
|
|
43
|
+
${!day.isCurrentMonth ? styles.outside : ""}
|
|
44
|
+
${isSelected ? styles.selected : ""}
|
|
45
|
+
${today ? styles.today : ""}
|
|
46
|
+
`, children: day.date.getDate() }, i));
|
|
47
|
+
}) })] }));
|
|
48
|
+
};
|
|
@@ -0,0 +1,75 @@
|
|
|
1
|
+
.root {
|
|
2
|
+
font-size: var(--font-size-14);
|
|
3
|
+
}
|
|
4
|
+
|
|
5
|
+
/* ===== variant ===== */
|
|
6
|
+
|
|
7
|
+
.embedded {
|
|
8
|
+
padding: var(--space-lg);
|
|
9
|
+
}
|
|
10
|
+
|
|
11
|
+
.standalone {
|
|
12
|
+
padding: var(--space-lg);
|
|
13
|
+
border-radius: var(--radius-md);
|
|
14
|
+
box-shadow: var(--shadow-md);
|
|
15
|
+
}
|
|
16
|
+
|
|
17
|
+
/* ===== layout ===== */
|
|
18
|
+
|
|
19
|
+
.header {
|
|
20
|
+
color: var(--color-on-surface);
|
|
21
|
+
display: flex;
|
|
22
|
+
justify-content: space-between;
|
|
23
|
+
align-items: center;
|
|
24
|
+
margin-bottom: var(--space-lg);
|
|
25
|
+
}
|
|
26
|
+
|
|
27
|
+
.title {
|
|
28
|
+
font-size: var(--font-size-16);
|
|
29
|
+
}
|
|
30
|
+
|
|
31
|
+
.week {
|
|
32
|
+
display: grid;
|
|
33
|
+
grid-template-columns: repeat(7, 1fr);
|
|
34
|
+
margin-bottom: var(--space-xs);
|
|
35
|
+
}
|
|
36
|
+
|
|
37
|
+
.weekDay {
|
|
38
|
+
text-align: center;
|
|
39
|
+
font-size: var(--font-size-14);
|
|
40
|
+
color: var(--color-on-surface-variant);
|
|
41
|
+
}
|
|
42
|
+
|
|
43
|
+
.grid {
|
|
44
|
+
display: grid;
|
|
45
|
+
grid-template-columns: repeat(7, 1fr);
|
|
46
|
+
}
|
|
47
|
+
|
|
48
|
+
/* ===== cell ===== */
|
|
49
|
+
|
|
50
|
+
.cell {
|
|
51
|
+
width: 40px;
|
|
52
|
+
height: 40px;
|
|
53
|
+
padding: 8px;
|
|
54
|
+
border-radius: var(--radius-max);
|
|
55
|
+
background: transparent;
|
|
56
|
+
font-weight: var(--font-weight-medium);
|
|
57
|
+
color: var(--color-on-surface);
|
|
58
|
+
}
|
|
59
|
+
|
|
60
|
+
.cell:not(.selected):hover {
|
|
61
|
+
background: var(--color-primary-container);
|
|
62
|
+
}
|
|
63
|
+
|
|
64
|
+
.outside {
|
|
65
|
+
color: var(--color-on-surface-variant);
|
|
66
|
+
}
|
|
67
|
+
|
|
68
|
+
.selected {
|
|
69
|
+
background: var(--color-primary);
|
|
70
|
+
color: var(--color-on-primary);
|
|
71
|
+
}
|
|
72
|
+
|
|
73
|
+
.today {
|
|
74
|
+
border: 1px solid var(--color-border);
|
|
75
|
+
}
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
export { Calendar } from "./Calendar";
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
export {};
|
|
@@ -0,0 +1,11 @@
|
|
|
1
|
+
type Props = {
|
|
2
|
+
x: number;
|
|
3
|
+
y: number;
|
|
4
|
+
width: number;
|
|
5
|
+
height: number;
|
|
6
|
+
fill: string;
|
|
7
|
+
onMouseEnter?: () => void;
|
|
8
|
+
onMouseLeave?: () => void;
|
|
9
|
+
};
|
|
10
|
+
export declare const Bar: ({ x, y, width, height, fill, onMouseEnter, onMouseLeave, }: Props) => import("react/jsx-runtime").JSX.Element;
|
|
11
|
+
export {};
|
|
@@ -0,0 +1,4 @@
|
|
|
1
|
+
import { jsx as _jsx } from "react/jsx-runtime";
|
|
2
|
+
export const Bar = ({ x, y, width, height, fill, onMouseEnter, onMouseLeave, }) => {
|
|
3
|
+
return (_jsx("rect", { x: x, y: y, width: width, height: height, fill: fill, onMouseEnter: onMouseEnter, onMouseLeave: onMouseLeave, className: "lucentia-bar", rx: 2 }));
|
|
4
|
+
};
|
|
File without changes
|
|
@@ -0,0 +1,22 @@
|
|
|
1
|
+
import { jsx as _jsx, jsxs as _jsxs } from "react/jsx-runtime";
|
|
2
|
+
import { useState } from "react";
|
|
3
|
+
import { ChartContainer } from "../ChartContainer";
|
|
4
|
+
import { ChartGrid } from "../ChartGrid";
|
|
5
|
+
import { ChartTooltip } from "../ChartTooltip";
|
|
6
|
+
import { ChartXAxis } from "../ChartXAxis";
|
|
7
|
+
import { ChartYAxis } from "../ChartYAxis";
|
|
8
|
+
import { getNiceTicks } from "../utils/getNiceTicks";
|
|
9
|
+
import { BarSeries } from "./BarSeries";
|
|
10
|
+
import { getMaxValue } from "./utils";
|
|
11
|
+
export const BarChart = ({ data, keys, height = 300, barGap = 16 }) => {
|
|
12
|
+
const seriesKeys = keys !== null && keys !== void 0 ? keys : Object.keys(data[0]).filter((k) => k !== "label");
|
|
13
|
+
const max = getMaxValue(data, seriesKeys);
|
|
14
|
+
const labels = data.map((d) => d.label);
|
|
15
|
+
const ticks = getNiceTicks(max);
|
|
16
|
+
const [cursor, setCursor] = useState({
|
|
17
|
+
x: 0,
|
|
18
|
+
y: 0,
|
|
19
|
+
});
|
|
20
|
+
const [tooltip, setTooltip] = useState(null);
|
|
21
|
+
return (_jsx("div", { style: { width: "100%" }, children: _jsxs(ChartContainer, { height: height, onPointerMove: (x, y) => setCursor({ x, y }), children: [_jsx(ChartGrid, {}), _jsx(ChartXAxis, { labels: labels }), _jsx(ChartYAxis, { ticks: ticks, max: ticks[ticks.length - 1] }), _jsx(BarSeries, { data: data, keys: seriesKeys, max: max, gap: barGap, onHover: (label, key, value) => setTooltip({ label, key, value }), onLeave: () => setTooltip(null) }), tooltip && (_jsxs(ChartTooltip, { x: cursor.x + 8, y: cursor.y + 8, children: [_jsx("div", { children: tooltip.label }), _jsxs("strong", { children: [tooltip.key, ": ", tooltip.value] })] }))] }) }));
|
|
22
|
+
};
|
|
@@ -0,0 +1,10 @@
|
|
|
1
|
+
type Props = {
|
|
2
|
+
data: any[];
|
|
3
|
+
keys: string[];
|
|
4
|
+
max: number;
|
|
5
|
+
gap: number;
|
|
6
|
+
onHover?: (label: string, key: string, value: number) => void;
|
|
7
|
+
onLeave?: () => void;
|
|
8
|
+
};
|
|
9
|
+
export declare const BarSeries: ({ data, keys, max, gap, onHover, onLeave }: Props) => import("react/jsx-runtime").JSX.Element;
|
|
10
|
+
export {};
|
|
@@ -0,0 +1,27 @@
|
|
|
1
|
+
import { jsx as _jsx } from "react/jsx-runtime";
|
|
2
|
+
import { useChart } from "../ChartContext";
|
|
3
|
+
import { Bar } from "./Bar";
|
|
4
|
+
import { scaleValue } from "./utils";
|
|
5
|
+
export const BarSeries = ({ data, keys, max, gap, onHover, onLeave }) => {
|
|
6
|
+
const { width, height, padding } = useChart();
|
|
7
|
+
const innerWidth = width - padding * 2;
|
|
8
|
+
const innerHeight = height - padding * 2;
|
|
9
|
+
// 1グループあたりの幅(端数を切り捨てることで、右端のはみ出しを防止)
|
|
10
|
+
const groupWidth = Math.floor(innerWidth / data.length);
|
|
11
|
+
const contentWidth = groupWidth - gap;
|
|
12
|
+
const barUnitWidth = contentWidth / keys.length;
|
|
13
|
+
const actualBarWidth = barUnitWidth * 0.8;
|
|
14
|
+
return (_jsx("g", { children: data.map((d, i) => {
|
|
15
|
+
// padding + (i * groupWidth) で確実に計算
|
|
16
|
+
const groupX = padding + i * groupWidth;
|
|
17
|
+
return keys.map((key, j) => {
|
|
18
|
+
var _a;
|
|
19
|
+
const value = Number((_a = d[key]) !== null && _a !== void 0 ? _a : 0);
|
|
20
|
+
const barHeight = scaleValue(value, max, innerHeight);
|
|
21
|
+
// X座標:グループ開始位置 + 棒のオフセット
|
|
22
|
+
const x = groupX + (gap / 2) + (j * barUnitWidth) + (barUnitWidth - actualBarWidth) / 2;
|
|
23
|
+
const y = height - padding - barHeight;
|
|
24
|
+
return (_jsx(Bar, { x: x, y: y, width: actualBarWidth, height: barHeight, onMouseEnter: () => onHover === null || onHover === void 0 ? void 0 : onHover(d.label, key, value), onMouseLeave: onLeave, fill: `var(--chart-color-${j + 1})` }, `${i}-${key}`));
|
|
25
|
+
});
|
|
26
|
+
}) }));
|
|
27
|
+
};
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
export {};
|
|
@@ -0,0 +1,26 @@
|
|
|
1
|
+
export const getMaxValue = (data, keys) => {
|
|
2
|
+
let max = 0;
|
|
3
|
+
data.forEach((d) => {
|
|
4
|
+
keys.forEach((k) => {
|
|
5
|
+
var _a;
|
|
6
|
+
const v = Number((_a = d[k]) !== null && _a !== void 0 ? _a : 0);
|
|
7
|
+
if (v > max)
|
|
8
|
+
max = v;
|
|
9
|
+
});
|
|
10
|
+
});
|
|
11
|
+
return max;
|
|
12
|
+
};
|
|
13
|
+
export const scaleValue = (value, max, height) => {
|
|
14
|
+
if (max === 0)
|
|
15
|
+
return 0;
|
|
16
|
+
return (value / max) * height;
|
|
17
|
+
};
|
|
18
|
+
export const getStackMax = (data, keys) => {
|
|
19
|
+
let max = 0;
|
|
20
|
+
data.forEach((d) => {
|
|
21
|
+
const sum = keys.reduce((acc, k) => { var _a; return acc + Number((_a = d[k]) !== null && _a !== void 0 ? _a : 0); }, 0);
|
|
22
|
+
if (sum > max)
|
|
23
|
+
max = sum;
|
|
24
|
+
});
|
|
25
|
+
return max;
|
|
26
|
+
};
|
|
@@ -0,0 +1,6 @@
|
|
|
1
|
+
import { jsx as _jsx, jsxs as _jsxs } from "react/jsx-runtime";
|
|
2
|
+
import { useChart } from "./ChartContext";
|
|
3
|
+
export const ChartAxis = ({ xLabel, yLabel }) => {
|
|
4
|
+
const { width, height, padding } = useChart();
|
|
5
|
+
return (_jsxs("g", { stroke: "var(--chart-axis)", children: [_jsx("line", { x1: padding, x2: width - padding, y1: height - padding, y2: height - padding }), _jsx("line", { x1: padding, x2: padding, y1: padding, y2: height - padding }), xLabel && (_jsx("text", { x: width / 2, y: height - 6, textAnchor: "middle", fill: "var(--chart-text)", fontSize: "12", children: xLabel })), yLabel && (_jsx("text", { transform: `translate(12 ${height / 2}) rotate(-90)`, textAnchor: "middle", fill: "var(--chart-text)", fontSize: "12", children: yLabel }))] }));
|
|
6
|
+
};
|
|
@@ -0,0 +1,11 @@
|
|
|
1
|
+
import { ReactNode } from "react";
|
|
2
|
+
type Props = {
|
|
3
|
+
children: ReactNode;
|
|
4
|
+
width?: number;
|
|
5
|
+
height?: number;
|
|
6
|
+
padding?: number;
|
|
7
|
+
className?: string;
|
|
8
|
+
onPointerMove?: (x: number, y: number) => void;
|
|
9
|
+
};
|
|
10
|
+
export declare const ChartContainer: ({ children, width, height, padding, className, onPointerMove, }: Props) => import("react/jsx-runtime").JSX.Element;
|
|
11
|
+
export {};
|
|
@@ -0,0 +1,22 @@
|
|
|
1
|
+
import { jsx as _jsx } from "react/jsx-runtime";
|
|
2
|
+
import { useRef } from "react";
|
|
3
|
+
import { ChartContext } from "./ChartContext";
|
|
4
|
+
import styles from "./ChartContainer.module.css";
|
|
5
|
+
export const ChartContainer = ({ children, width = 600, height = 300, padding = 32, className, onPointerMove, }) => {
|
|
6
|
+
const svgRef = useRef(null);
|
|
7
|
+
const handleMove = (e) => {
|
|
8
|
+
if (!svgRef.current || !onPointerMove)
|
|
9
|
+
return;
|
|
10
|
+
const rect = svgRef.current.getBoundingClientRect();
|
|
11
|
+
const scaleX = width / rect.width;
|
|
12
|
+
const scaleY = height / rect.height;
|
|
13
|
+
const x = (e.clientX - rect.left) * scaleX;
|
|
14
|
+
const y = (e.clientY - rect.top) * scaleY;
|
|
15
|
+
onPointerMove(x, y);
|
|
16
|
+
};
|
|
17
|
+
return (_jsx(ChartContext.Provider, { value: {
|
|
18
|
+
width,
|
|
19
|
+
height,
|
|
20
|
+
padding,
|
|
21
|
+
}, children: _jsx("svg", { ref: svgRef, viewBox: `0 0 ${width} ${height}`, width: "100%", height: "100%", className: [styles.container, className].filter(Boolean).join(" "), onPointerMove: handleMove, children: children }) }));
|
|
22
|
+
};
|
|
@@ -0,0 +1,51 @@
|
|
|
1
|
+
.container {
|
|
2
|
+
background-color: var(--color-surface);
|
|
3
|
+
padding: var(--space-lg);
|
|
4
|
+
border-radius: var(--radius-md);
|
|
5
|
+
overflow: visible;
|
|
6
|
+
}
|
|
7
|
+
|
|
8
|
+
:root {
|
|
9
|
+
--chart-color-1: #99cccc; /* 明るすぎないソフトブルー */
|
|
10
|
+
--chart-color-2: #66b2b2;
|
|
11
|
+
--chart-color-3: #4da6a6;
|
|
12
|
+
--chart-color-4: #339999;
|
|
13
|
+
--chart-color-5: #008b8b;
|
|
14
|
+
--chart-color-6: #007a7a; /* base: 以前より落ち着いたトーン */
|
|
15
|
+
--chart-color-7: #006666;
|
|
16
|
+
--chart-color-8: #005252;
|
|
17
|
+
--chart-color-9: #004545;
|
|
18
|
+
--chart-color-10: #003333; /* 締まりのある深い色 */
|
|
19
|
+
|
|
20
|
+
--chart-grid: var(--color-border);
|
|
21
|
+
--chart-axis: var(--color-border);
|
|
22
|
+
}
|
|
23
|
+
|
|
24
|
+
|
|
25
|
+
html[data-theme="dark"] {
|
|
26
|
+
--chart-color-1: #80d5d4; /* Base: ここをスタート地点にして視認性を確保 */
|
|
27
|
+
--chart-color-2: #6bc2c1;
|
|
28
|
+
--chart-color-3: #57afae; /* 1,2,3の間で明確な色の沈み込みを作成 */
|
|
29
|
+
--chart-color-4: #439d9c;
|
|
30
|
+
--chart-color-5: #308b8b;
|
|
31
|
+
--chart-color-6: #1c797a;
|
|
32
|
+
--chart-color-7: #09686a;
|
|
33
|
+
--chart-color-8: #005759;
|
|
34
|
+
--chart-color-9: #004749;
|
|
35
|
+
--chart-color-10: #00383a; /* 最終地点はかなり深く */
|
|
36
|
+
}
|
|
37
|
+
|
|
38
|
+
.lucentia-bar {
|
|
39
|
+
transform-origin: bottom;
|
|
40
|
+
animation: barGrow 0.5s ease;
|
|
41
|
+
}
|
|
42
|
+
|
|
43
|
+
@keyframes barGrow {
|
|
44
|
+
from {
|
|
45
|
+
transform: scaleY(0);
|
|
46
|
+
}
|
|
47
|
+
|
|
48
|
+
to {
|
|
49
|
+
transform: scaleY(1);
|
|
50
|
+
}
|
|
51
|
+
}
|
|
@@ -0,0 +1,9 @@
|
|
|
1
|
+
import { createContext, useContext } from "react";
|
|
2
|
+
export const ChartContext = createContext(null);
|
|
3
|
+
export const useChart = () => {
|
|
4
|
+
const ctx = useContext(ChartContext);
|
|
5
|
+
if (!ctx) {
|
|
6
|
+
throw new Error("Chart components must be used inside ChartContainer");
|
|
7
|
+
}
|
|
8
|
+
return ctx;
|
|
9
|
+
};
|
|
@@ -0,0 +1,19 @@
|
|
|
1
|
+
import { jsx as _jsx } from "react/jsx-runtime";
|
|
2
|
+
import { useChart } from "./ChartContext";
|
|
3
|
+
export const ChartGrid = ({ rows = 4, columns = 4 }) => {
|
|
4
|
+
const { width, height, padding } = useChart();
|
|
5
|
+
const innerWidth = width - padding * 2;
|
|
6
|
+
const innerHeight = height - padding * 2;
|
|
7
|
+
const rowHeight = innerHeight / rows;
|
|
8
|
+
const colWidth = innerWidth / columns;
|
|
9
|
+
const lines = [];
|
|
10
|
+
for (let i = 0; i <= rows; i++) {
|
|
11
|
+
const y = padding + rowHeight * i;
|
|
12
|
+
lines.push(_jsx("line", { x1: padding, x2: width - padding, y1: y, y2: y, stroke: "var(--chart-grid)" }, `row-${i}`));
|
|
13
|
+
}
|
|
14
|
+
for (let i = 0; i <= columns; i++) {
|
|
15
|
+
const x = padding + colWidth * i;
|
|
16
|
+
lines.push(_jsx("line", { y1: padding, y2: height - padding, x1: x, x2: x, stroke: "var(--chart-grid)" }, `col-${i}`));
|
|
17
|
+
}
|
|
18
|
+
return _jsx("g", { children: lines });
|
|
19
|
+
};
|
|
@@ -0,0 +1,19 @@
|
|
|
1
|
+
import { jsx as _jsx, jsxs as _jsxs } from "react/jsx-runtime";
|
|
2
|
+
export const ChartLegend = ({ items }) => {
|
|
3
|
+
return (_jsx("div", { style: {
|
|
4
|
+
display: "flex",
|
|
5
|
+
gap: "12px",
|
|
6
|
+
flexWrap: "wrap",
|
|
7
|
+
marginTop: "8px",
|
|
8
|
+
}, children: items.map((item) => (_jsxs("div", { style: {
|
|
9
|
+
display: "flex",
|
|
10
|
+
alignItems: "center",
|
|
11
|
+
gap: "6px",
|
|
12
|
+
fontSize: "12px",
|
|
13
|
+
}, children: [_jsx("span", { style: {
|
|
14
|
+
width: 12,
|
|
15
|
+
height: 12,
|
|
16
|
+
background: item.color,
|
|
17
|
+
display: "inline-block",
|
|
18
|
+
} }), item.label] }, item.label))) }));
|
|
19
|
+
};
|
|
@@ -0,0 +1,35 @@
|
|
|
1
|
+
import { jsxs as _jsxs } from "react/jsx-runtime";
|
|
2
|
+
import { useChart } from "./ChartContext";
|
|
3
|
+
export const ChartTooltip = ({ x, y, children }) => {
|
|
4
|
+
const { width, height } = useChart();
|
|
5
|
+
const tooltipWidth = 120;
|
|
6
|
+
const tooltipHeight = 64;
|
|
7
|
+
const offset = 10;
|
|
8
|
+
let tx = x + offset;
|
|
9
|
+
let ty = y - offset;
|
|
10
|
+
// 右はみ出し防止
|
|
11
|
+
if (tx + tooltipWidth > width) {
|
|
12
|
+
tx = x - tooltipWidth - offset;
|
|
13
|
+
}
|
|
14
|
+
// 下はみ出し防止
|
|
15
|
+
if (ty + tooltipHeight > height) {
|
|
16
|
+
ty = height - tooltipHeight;
|
|
17
|
+
}
|
|
18
|
+
// 上はみ出し防止
|
|
19
|
+
if (ty < 0) {
|
|
20
|
+
ty = offset;
|
|
21
|
+
}
|
|
22
|
+
return (_jsxs("foreignObject", { x: tx, y: ty, width: tooltipWidth, height: tooltipHeight, style: {
|
|
23
|
+
borderRadius: "var(--radius-sm)",
|
|
24
|
+
overflow: "visible",
|
|
25
|
+
}, children: [_jsxs("div", { style: {
|
|
26
|
+
background: "var(--color-surface)",
|
|
27
|
+
backdropFilter: "var(--blur)",
|
|
28
|
+
border: "1px solid var(--color-border)",
|
|
29
|
+
borderRadius: "var(--radius-sm)",
|
|
30
|
+
padding: "var(--space-md)",
|
|
31
|
+
fontSize: "var(--font-size-14)",
|
|
32
|
+
color: "var(--color-on-surface)",
|
|
33
|
+
whiteSpace: "nowrap",
|
|
34
|
+
}, children: [children, " "] }), " "] }));
|
|
35
|
+
};
|
|
@@ -0,0 +1,16 @@
|
|
|
1
|
+
import { jsx as _jsx } from "react/jsx-runtime";
|
|
2
|
+
import { useChart } from "./ChartContext";
|
|
3
|
+
export const ChartXAxis = ({ labels }) => {
|
|
4
|
+
const { width, height, padding } = useChart();
|
|
5
|
+
// 描画可能領域の計算
|
|
6
|
+
const innerWidth = width - padding * 2;
|
|
7
|
+
// 1ラベルあたりの幅
|
|
8
|
+
const step = innerWidth / (labels.length > 1 ? labels.length - 1 : 1);
|
|
9
|
+
return (_jsx("g", { fill: "var(--color-on-surface)", children: labels.map((label, i) => {
|
|
10
|
+
const x = padding + (innerWidth / labels.length) * (i + 0.5);
|
|
11
|
+
const y = height - padding + 20;
|
|
12
|
+
return (_jsx("text", { x: x, y: y, textAnchor: "middle" // 水平方向の中央揃え
|
|
13
|
+
, dominantBaseline: "hanging" // テキストの上端をy座標に合わせる(より制御しやすくなります)
|
|
14
|
+
, fontSize: "var(--font-size-14)", children: label }, i));
|
|
15
|
+
}) }));
|
|
16
|
+
};
|
|
@@ -0,0 +1,11 @@
|
|
|
1
|
+
import { jsx as _jsx, jsxs as _jsxs } from "react/jsx-runtime";
|
|
2
|
+
import { useChart } from "./ChartContext";
|
|
3
|
+
export const ChartYAxis = ({ ticks, max }) => {
|
|
4
|
+
const { width, height, padding } = useChart();
|
|
5
|
+
const innerHeight = height - padding * 2;
|
|
6
|
+
return (_jsx("g", { fill: "var(--color-on-surface)", children: ticks.map((tick, i) => {
|
|
7
|
+
const ratio = tick / max;
|
|
8
|
+
const y = height - padding - ratio * innerHeight;
|
|
9
|
+
return (_jsxs("g", { children: [_jsx("text", { x: padding - 8, y: y, textAnchor: "end", dominantBaseline: "middle", fontSize: "var(--font-size-14)", children: tick }), _jsx("line", { x1: padding, x2: width - padding, y1: y, y2: y, stroke: "var(--chart-grid)", strokeDasharray: "2" })] }, i));
|
|
10
|
+
}) }));
|
|
11
|
+
};
|
|
@@ -0,0 +1,27 @@
|
|
|
1
|
+
import { jsx as _jsx, jsxs as _jsxs } from "react/jsx-runtime";
|
|
2
|
+
import { useState } from "react";
|
|
3
|
+
import { ChartContainer } from "../ChartContainer";
|
|
4
|
+
import { ChartGrid } from "../ChartGrid";
|
|
5
|
+
import { ChartAxis } from "../ChartAxis";
|
|
6
|
+
import { ChartXAxis } from "../ChartXAxis";
|
|
7
|
+
import { ChartYAxis } from "../ChartYAxis";
|
|
8
|
+
import { ChartTooltip } from "../ChartTooltip";
|
|
9
|
+
import { LineSeries } from "./LineSeries";
|
|
10
|
+
import { getMaxValue } from "../BarChart/utils";
|
|
11
|
+
import { getNiceTicks } from "../utils/getNiceTicks";
|
|
12
|
+
export const LineChart = ({ data, keys, height = 300 }) => {
|
|
13
|
+
const seriesKeys = keys !== null && keys !== void 0 ? keys : Object.keys(data[0]).filter((k) => k !== "label");
|
|
14
|
+
const max = getMaxValue(data, seriesKeys);
|
|
15
|
+
const ticks = getNiceTicks(max);
|
|
16
|
+
const labels = data.map((d) => d.label);
|
|
17
|
+
const [cursor, setCursor] = useState({
|
|
18
|
+
x: 0,
|
|
19
|
+
y: 0,
|
|
20
|
+
});
|
|
21
|
+
const [tooltip, setTooltip] = useState(null);
|
|
22
|
+
return (_jsx("div", { style: { width: "100%" }, children: _jsxs(ChartContainer, { height: height, onPointerMove: (x, y) => setCursor({ x, y }), children: [_jsx(ChartGrid, {}), _jsx(ChartAxis, {}), _jsx(ChartYAxis, { ticks: ticks, max: ticks[ticks.length - 1] }), _jsx(ChartXAxis, { labels: labels }), _jsx(LineSeries, { data: data, keys: seriesKeys, max: ticks[ticks.length - 1], onHover: (label, key, value) => setTooltip({
|
|
23
|
+
label,
|
|
24
|
+
key,
|
|
25
|
+
value,
|
|
26
|
+
}), onLeave: () => setTooltip(null) }), tooltip && (_jsxs(ChartTooltip, { x: cursor.x + 12, y: cursor.y + 12, children: [_jsx("div", { children: tooltip.label }), _jsxs("strong", { children: [tooltip.key, ": ", tooltip.value] })] }))] }) }));
|
|
27
|
+
};
|