@squadbase/vantage 0.6.2-dev1.ac99e02 → 0.6.2-dev1.d7c0911

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.
Files changed (141) hide show
  1. package/dist/{build-MFWRPYKW.js → build-X5NVCQKT.js} +4 -4
  2. package/dist/{build-MFWRPYKW.js.map → build-X5NVCQKT.js.map} +1 -1
  3. package/dist/{chunk-IBGOCWJB.js → chunk-2ICNHUG6.js} +186 -82
  4. package/dist/chunk-2ICNHUG6.js.map +1 -0
  5. package/dist/{chunk-5ZOP4SQR.js → chunk-2N72FKLB.js} +12 -7
  6. package/dist/chunk-2N72FKLB.js.map +1 -0
  7. package/dist/{chunk-PXRX5PEC.js → chunk-PDOBHMUQ.js} +3 -3
  8. package/dist/chunk-PDOBHMUQ.js.map +1 -0
  9. package/dist/{chunk-A2UUGASH.js → chunk-U736PVHY.js} +2 -2
  10. package/dist/chunk-U736PVHY.js.map +1 -0
  11. package/dist/{chunk-QEWCYW3I.js → chunk-WAMZWZJB.js} +13 -3
  12. package/dist/chunk-WAMZWZJB.js.map +1 -0
  13. package/dist/chunk-WRSX2MDK.js +7866 -0
  14. package/dist/chunk-WRSX2MDK.js.map +1 -0
  15. package/dist/{chunk-OB6UBJXF.js → chunk-XPQSTZUU.js} +125 -35
  16. package/dist/chunk-XPQSTZUU.js.map +1 -0
  17. package/dist/cli.js +3 -3
  18. package/dist/components/index.d.ts +1831 -99
  19. package/dist/components/index.js +4 -4
  20. package/dist/{dev-DCTOHQ6W.js → dev-4XEDTELV.js} +4 -4
  21. package/dist/{dev-DCTOHQ6W.js.map → dev-4XEDTELV.js.map} +1 -1
  22. package/dist/doc/index.js +2 -2
  23. package/dist/doc/index.js.map +1 -1
  24. package/dist/markdown/index.js +1 -1
  25. package/dist/markdown/index.js.map +1 -1
  26. package/dist/table/index.js +5 -5
  27. package/dist/table/index.js.map +1 -1
  28. package/dist/ui/index.d.ts +4 -1
  29. package/dist/ui/index.js +21 -111
  30. package/dist/ui/index.js.map +1 -1
  31. package/dist/{upgrade-DBBE6GIR.js → upgrade-JHXZBGQS.js} +3 -3
  32. package/dist/{upgrade-DBBE6GIR.js.map → upgrade-JHXZBGQS.js.map} +1 -1
  33. package/dist/vite/index.js +2 -2
  34. package/docs/en/components.md +29 -15
  35. package/docs/en/parts/data-table.md +22 -0
  36. package/docs/en/parts/delta.md +50 -0
  37. package/docs/en/parts/format.md +43 -0
  38. package/docs/en/parts/kpi-card.md +57 -0
  39. package/docs/en/parts/metric-value.md +3 -2
  40. package/docs/en/parts/sparkline.md +1 -1
  41. package/docs/en/parts/trend-indicator.md +17 -1
  42. package/docs/en/ui-and-theming.md +1 -1
  43. package/docs/index.json +92 -32
  44. package/docs/ja/changelog.md +5 -0
  45. package/docs/ja/components.md +27 -15
  46. package/docs/ja/parts/data-table.md +22 -0
  47. package/docs/ja/parts/delta.md +50 -0
  48. package/docs/ja/parts/format.md +44 -0
  49. package/docs/ja/parts/kpi-card.md +55 -0
  50. package/docs/ja/parts/metric-value.md +3 -2
  51. package/docs/ja/parts/sparkline.md +1 -1
  52. package/docs/ja/parts/trend-indicator.md +17 -1
  53. package/docs/ja/ui-and-theming.md +2 -2
  54. package/package.json +2 -1
  55. package/registry/ui/accordion.tsx +4 -2
  56. package/registry/ui/alert-dialog.tsx +3 -3
  57. package/registry/ui/alert.tsx +3 -1
  58. package/registry/ui/app-shell.tsx +7 -1
  59. package/registry/ui/area-chart.tsx +2781 -157
  60. package/registry/ui/avatar.tsx +1 -1
  61. package/registry/ui/badge.tsx +3 -1
  62. package/registry/ui/bar-chart.tsx +2780 -157
  63. package/registry/ui/bar-list.tsx +3471 -93
  64. package/registry/ui/breadcrumb.tsx +3 -1
  65. package/registry/ui/button.tsx +3 -1
  66. package/registry/ui/calendar.tsx +3 -1
  67. package/registry/ui/card.tsx +4 -2
  68. package/registry/ui/category-bar.tsx +990 -16
  69. package/registry/ui/chart-frame.tsx +1358 -0
  70. package/registry/ui/checkbox.tsx +3 -1
  71. package/registry/ui/collapsible.tsx +3 -1
  72. package/registry/ui/combobox.tsx +2 -2
  73. package/registry/ui/command.tsx +3 -1
  74. package/registry/ui/dashboard-card.tsx +69 -26
  75. package/registry/ui/data-table.tsx +678 -56
  76. package/registry/ui/date-range-picker.tsx +245 -64
  77. package/registry/ui/delta.tsx +188 -0
  78. package/registry/ui/dialog.tsx +5 -3
  79. package/registry/ui/donut-chart.tsx +2857 -173
  80. package/registry/ui/drawer.tsx +1 -1
  81. package/registry/ui/dropdown-menu.tsx +5 -3
  82. package/registry/ui/echart.tsx +448 -44
  83. package/registry/ui/field.tsx +1 -1
  84. package/registry/ui/filter-bar.tsx +33 -6
  85. package/registry/ui/funnel-steps.tsx +3316 -49
  86. package/registry/ui/heatmap.tsx +1752 -0
  87. package/registry/ui/hover-card.tsx +2 -2
  88. package/registry/ui/input-group.tsx +3 -1
  89. package/registry/ui/input.tsx +3 -1
  90. package/registry/ui/kbd.tsx +3 -1
  91. package/registry/ui/kpi-card.tsx +677 -0
  92. package/registry/ui/label.tsx +3 -1
  93. package/registry/ui/legend.tsx +3500 -0
  94. package/registry/ui/line-chart.tsx +2781 -151
  95. package/registry/ui/metric-value.tsx +9 -1
  96. package/registry/ui/multi-select.tsx +11 -5
  97. package/registry/ui/page-shell.tsx +104 -49
  98. package/registry/ui/pagination.tsx +3 -1
  99. package/registry/ui/placeholder.tsx +8 -2
  100. package/registry/ui/popover.tsx +4 -2
  101. package/registry/ui/progress-circle.tsx +607 -12
  102. package/registry/ui/progress.tsx +3 -1
  103. package/registry/ui/radio-group.tsx +1 -1
  104. package/registry/ui/sample-data.tsx +86 -0
  105. package/registry/ui/scatter-chart.tsx +4150 -0
  106. package/registry/ui/scroll-area.tsx +3 -2
  107. package/registry/ui/searchable-select.tsx +8 -3
  108. package/registry/ui/section-header.tsx +4 -2
  109. package/registry/ui/segmented-control.tsx +7 -2
  110. package/registry/ui/select.tsx +4 -2
  111. package/registry/ui/separator.tsx +3 -1
  112. package/registry/ui/sheet.tsx +4 -2
  113. package/registry/ui/sidebar.tsx +4 -2
  114. package/registry/ui/skeleton.tsx +4 -2
  115. package/registry/ui/slider.tsx +3 -1
  116. package/registry/ui/sparkline.tsx +84 -9
  117. package/registry/ui/spinner.tsx +3 -1
  118. package/registry/ui/states.tsx +34 -5
  119. package/registry/ui/status-badge.tsx +81 -39
  120. package/registry/ui/switch.tsx +3 -1
  121. package/registry/ui/table.tsx +4 -2
  122. package/registry/ui/tabs.tsx +5 -3
  123. package/registry/ui/textarea.tsx +3 -1
  124. package/registry/ui/toast.tsx +2 -2
  125. package/registry/ui/toggle-group.tsx +3 -1
  126. package/registry/ui/toggle.tsx +3 -1
  127. package/registry/ui/tooltip.tsx +4 -2
  128. package/registry/ui/tracker.tsx +624 -17
  129. package/registry/ui/trend-indicator.tsx +13 -1
  130. package/registry/ui/updated-at.tsx +122 -0
  131. package/registry/ui/waterfall-chart.tsx +4186 -0
  132. package/templates/AGENTS.md +13 -1
  133. package/theme.css +237 -136
  134. package/dist/chunk-5ZOP4SQR.js.map +0 -1
  135. package/dist/chunk-A2UUGASH.js.map +0 -1
  136. package/dist/chunk-AG6RZ2RR.js +0 -3208
  137. package/dist/chunk-AG6RZ2RR.js.map +0 -1
  138. package/dist/chunk-IBGOCWJB.js.map +0 -1
  139. package/dist/chunk-OB6UBJXF.js.map +0 -1
  140. package/dist/chunk-PXRX5PEC.js.map +0 -1
  141. package/dist/chunk-QEWCYW3I.js.map +0 -1
@@ -1,3208 +0,0 @@
1
- import { SidebarProvider, Sidebar, SidebarContent, SidebarGroup, SidebarGroupLabel, SidebarMenu, SidebarFooter, SidebarRail, SidebarInset, SidebarTrigger, Separator, Tooltip, TooltipTrigger, TooltipContent, Input, Table, TableHeader, TableRow, TableHead, TableBody, TableCell, Select, SelectTrigger, SelectValue, SelectContent, SelectItem, DropdownMenu, DropdownMenuTrigger, DropdownMenuContent, DropdownMenuCheckboxItem, useIsMobile, Popover, PopoverTrigger, PopoverContent, Calendar, ToggleGroup, ToggleGroupItem, Badge, SelectGroup, SelectLabel, Collapsible, CollapsibleTrigger, SidebarMenuButton, SidebarMenuBadge, CollapsibleContent, SidebarMenuSub, SidebarMenuSubItem, SidebarMenuSubButton, SidebarMenuItem, Command, CommandInput, CommandList, CommandEmpty, CommandGroup, CommandItem, Skeleton, Checkbox } from './chunk-OB6UBJXF.js';
2
- import { Button } from './chunk-PXRX5PEC.js';
3
- import { cn } from './chunk-A2UUGASH.js';
4
- import { forwardRef, useRef, useState, useEffect, useMemo, useCallback, Fragment as Fragment$1, createContext, useId, useContext } from 'react';
5
- import { cva } from 'class-variance-authority';
6
- import { jsx, jsxs, Fragment } from 'react/jsx-runtime';
7
- import { Check, Copy, Download, Search, ArrowUp, ArrowDown, ArrowUpDown, Columns3, CalendarIcon, ChevronDownIcon, Minus, ChevronRight, XIcon, LoaderIcon, CheckIcon, ChevronDown, X } from 'lucide-react';
8
- import * as echarts from 'echarts';
9
- import { flexRender, useReactTable, getPaginationRowModel, getFilteredRowModel, getSortedRowModel, getCoreRowModel } from '@tanstack/react-table';
10
- import { format, endOfDay, startOfDay, subDays, startOfMonth, subMonths, endOfMonth } from 'date-fns';
11
- import { ja } from 'date-fns/locale';
12
-
13
- // @squadbase/vantage — generated build. Do not edit.
14
- var PageShell = forwardRef(
15
- ({ className, ...props }, ref) => /* @__PURE__ */ jsx("div", { ref, "data-slot": "page-shell", className: cn("flex flex-col", className), ...props })
16
- );
17
- PageShell.displayName = "PageShell";
18
- var PageShellHeader = forwardRef(
19
- ({ className, ...props }, ref) => /* @__PURE__ */ jsx(
20
- "div",
21
- {
22
- ref,
23
- "data-slot": "page-shell-header",
24
- className: cn("flex flex-wrap items-start gap-x-4 gap-y-6 border-b px-6 py-12", className),
25
- ...props
26
- }
27
- )
28
- );
29
- PageShellHeader.displayName = "PageShellHeader";
30
- var PageShellHeading = forwardRef(
31
- ({ className, ...props }, ref) => /* @__PURE__ */ jsx(
32
- "div",
33
- {
34
- ref,
35
- "data-slot": "page-shell-heading",
36
- className: cn("min-w-0 grow basis-80", className),
37
- ...props
38
- }
39
- )
40
- );
41
- PageShellHeading.displayName = "PageShellHeading";
42
- var PageShellTitle = forwardRef(
43
- ({ className, ...props }, ref) => /* @__PURE__ */ jsx(
44
- "h1",
45
- {
46
- ref,
47
- "data-slot": "page-shell-title",
48
- className: cn("text-2xl font-bold tracking-tight text-foreground", className),
49
- ...props
50
- }
51
- )
52
- );
53
- PageShellTitle.displayName = "PageShellTitle";
54
- var PageShellDescription = forwardRef(
55
- ({ className, ...props }, ref) => /* @__PURE__ */ jsx(
56
- "p",
57
- {
58
- ref,
59
- "data-slot": "page-shell-description",
60
- className: cn("mt-1 text-sm text-muted-foreground", className),
61
- ...props
62
- }
63
- )
64
- );
65
- PageShellDescription.displayName = "PageShellDescription";
66
- var PageShellHeaderEnd = forwardRef(
67
- ({ className, ...props }, ref) => /* @__PURE__ */ jsx(
68
- "div",
69
- {
70
- ref,
71
- "data-slot": "page-shell-header-end",
72
- className: cn("flex max-w-full shrink-0 flex-col flex-wrap items-end gap-2", className),
73
- ...props
74
- }
75
- )
76
- );
77
- PageShellHeaderEnd.displayName = "PageShellHeaderEnd";
78
- var PageShellMeta = forwardRef(
79
- ({ className, ...props }, ref) => /* @__PURE__ */ jsx(
80
- "div",
81
- {
82
- ref,
83
- "data-slot": "page-shell-meta",
84
- className: cn("text-sm text-muted-foreground", className),
85
- ...props
86
- }
87
- )
88
- );
89
- PageShellMeta.displayName = "PageShellMeta";
90
- var PageShellActions = forwardRef(
91
- ({ className, ...props }, ref) => /* @__PURE__ */ jsx(
92
- "div",
93
- {
94
- ref,
95
- "data-slot": "page-shell-actions",
96
- className: cn("flex items-center gap-2", className),
97
- ...props
98
- }
99
- )
100
- );
101
- PageShellActions.displayName = "PageShellActions";
102
- var PageShellSummary = forwardRef(
103
- ({ className, ...props }, ref) => /* @__PURE__ */ jsx(
104
- "div",
105
- {
106
- ref,
107
- "data-slot": "page-shell-summary",
108
- className: cn(
109
- "grid basis-full grid-cols-1 gap-3 md:grid-cols-2 lg:grid-cols-3 xl:grid-cols-4",
110
- className
111
- ),
112
- ...props
113
- }
114
- )
115
- );
116
- PageShellSummary.displayName = "PageShellSummary";
117
- var pageShellSummaryCardVariants = cva(
118
- "relative flex items-start gap-3 rounded-lg border bg-background px-4 py-3 text-sm [&>svg]:mt-0.5 [&>svg]:size-4 [&>svg]:shrink-0",
119
- {
120
- variants: {
121
- accent: {
122
- default: "text-card-foreground",
123
- accent: "border-[var(--chart-1)]/30 bg-linear-to-r from-[var(--chart-1)]/5 to-[var(--chart-1)]/5 [&>svg]:text-[var(--chart-1)]",
124
- amber: "border-amber-300 bg-amber-50 [&>svg]:text-amber-600 dark:border-amber-800 dark:bg-amber-950/50 dark:[&>svg]:text-amber-400",
125
- blue: "border-blue-300 bg-blue-50 [&>svg]:text-blue-600 dark:border-blue-800 dark:bg-blue-950/50 dark:[&>svg]:text-blue-400",
126
- emerald: "border-emerald-300 bg-emerald-50 [&>svg]:text-emerald-600 dark:border-emerald-800 dark:bg-emerald-950/50 dark:[&>svg]:text-emerald-400",
127
- red: "border-red-300 bg-red-50 [&>svg]:text-red-600 dark:border-red-800 dark:bg-red-950/50 dark:[&>svg]:text-red-400",
128
- violet: "border-violet-300 bg-violet-50 [&>svg]:text-violet-600 dark:border-violet-800 dark:bg-violet-950/50 dark:[&>svg]:text-violet-400",
129
- orange: "border-orange-300 bg-orange-50 [&>svg]:text-orange-600 dark:border-orange-800 dark:bg-orange-950/50 dark:[&>svg]:text-orange-400",
130
- cyan: "border-cyan-300 bg-cyan-50 [&>svg]:text-cyan-600 dark:border-cyan-800 dark:bg-cyan-950/50 dark:[&>svg]:text-cyan-400",
131
- slate: "border-slate-300 bg-slate-50 [&>svg]:text-slate-600 dark:border-slate-800 dark:bg-slate-950/50 dark:[&>svg]:text-slate-400",
132
- green: "border-green-300 bg-green-50 [&>svg]:text-green-600 dark:border-green-800 dark:bg-green-950/50 dark:[&>svg]:text-green-400",
133
- teal: "border-teal-300 bg-teal-50 [&>svg]:text-teal-600 dark:border-teal-800 dark:bg-teal-950/50 dark:[&>svg]:text-teal-400",
134
- sky: "border-sky-300 bg-sky-50 [&>svg]:text-sky-600 dark:border-sky-800 dark:bg-sky-950/50 dark:[&>svg]:text-sky-400",
135
- indigo: "border-indigo-300 bg-indigo-50 [&>svg]:text-indigo-600 dark:border-indigo-800 dark:bg-indigo-950/50 dark:[&>svg]:text-indigo-400",
136
- purple: "border-purple-300 bg-purple-50 [&>svg]:text-purple-600 dark:border-purple-800 dark:bg-purple-950/50 dark:[&>svg]:text-purple-400",
137
- pink: "border-pink-300 bg-pink-50 [&>svg]:text-pink-600 dark:border-pink-800 dark:bg-pink-950/50 dark:[&>svg]:text-pink-400",
138
- rose: "border-rose-300 bg-rose-50 [&>svg]:text-rose-600 dark:border-rose-800 dark:bg-rose-950/50 dark:[&>svg]:text-rose-400",
139
- yellow: "border-yellow-300 bg-yellow-50 [&>svg]:text-yellow-600 dark:border-yellow-800 dark:bg-yellow-950/50 dark:[&>svg]:text-yellow-400",
140
- lime: "border-lime-300 bg-lime-50 [&>svg]:text-lime-600 dark:border-lime-800 dark:bg-lime-950/50 dark:[&>svg]:text-lime-400",
141
- gray: "border-gray-300 bg-gray-50 [&>svg]:text-gray-600 dark:border-gray-800 dark:bg-gray-950/50 dark:[&>svg]:text-gray-400",
142
- zinc: "border-zinc-300 bg-zinc-50 [&>svg]:text-zinc-600 dark:border-zinc-800 dark:bg-zinc-950/50 dark:[&>svg]:text-zinc-400",
143
- neutral: "border-neutral-300 bg-neutral-50 [&>svg]:text-neutral-600 dark:border-neutral-800 dark:bg-neutral-950/50 dark:[&>svg]:text-neutral-400",
144
- stone: "border-stone-300 bg-stone-50 [&>svg]:text-stone-600 dark:border-stone-800 dark:bg-stone-950/50 dark:[&>svg]:text-stone-400",
145
- fuchsia: "border-fuchsia-300 bg-fuchsia-50 [&>svg]:text-fuchsia-600 dark:border-fuchsia-800 dark:bg-fuchsia-950/50 dark:[&>svg]:text-fuchsia-400"
146
- }
147
- },
148
- defaultVariants: {
149
- accent: "default"
150
- }
151
- }
152
- );
153
- var PageShellSummaryCard = forwardRef(
154
- ({ className, accent, ...props }, ref) => /* @__PURE__ */ jsx(
155
- "div",
156
- {
157
- ref,
158
- "data-slot": "page-shell-summary-card",
159
- className: cn(pageShellSummaryCardVariants({ accent }), className),
160
- ...props
161
- }
162
- )
163
- );
164
- PageShellSummaryCard.displayName = "PageShellSummaryCard";
165
- var PageShellContent = forwardRef(
166
- ({ className, ...props }, ref) => /* @__PURE__ */ jsx(
167
- "div",
168
- {
169
- ref,
170
- "data-slot": "page-shell-content",
171
- className: cn("flex-1 p-6", className),
172
- ...props
173
- }
174
- )
175
- );
176
- PageShellContent.displayName = "PageShellContent";
177
- function flattenItems(item) {
178
- if (item.children && item.children.length > 0) {
179
- return item.children.flatMap(flattenItems);
180
- }
181
- return [item];
182
- }
183
- function NavSelect({
184
- groups,
185
- onNavigate
186
- }) {
187
- const allItems = groups.flatMap((g) => g.items.flatMap(flattenItems));
188
- const currentValue = allItems.find((item) => item.isActive)?.href ?? "";
189
- return /* @__PURE__ */ jsxs(
190
- Select,
191
- {
192
- value: currentValue,
193
- onValueChange: (href) => {
194
- if (href !== null) onNavigate(href);
195
- },
196
- children: [
197
- /* @__PURE__ */ jsx(SelectTrigger, { size: "sm", className: "w-48", children: /* @__PURE__ */ jsx(SelectValue, { placeholder: "\u30DA\u30FC\u30B8\u3092\u9078\u629E" }) }),
198
- /* @__PURE__ */ jsx(
199
- SelectContent,
200
- {
201
- align: "start",
202
- className: "w-auto min-w-(--anchor-width) max-w-[min(24rem,var(--available-width))]",
203
- children: groups.map((group, index) => /* @__PURE__ */ jsxs(SelectGroup, { children: [
204
- group.label && /* @__PURE__ */ jsx(SelectLabel, { children: group.label }),
205
- group.items.flatMap(flattenItems).map((item) => /* @__PURE__ */ jsx(SelectItem, { value: item.href, disabled: item.disabled, children: item.label }, item.href))
206
- ] }, group.label ?? index))
207
- }
208
- )
209
- ]
210
- }
211
- );
212
- }
213
- function NavItemWithChildren({
214
- item,
215
- linkComponent: LinkComponent = "a"
216
- }) {
217
- return /* @__PURE__ */ jsxs(
218
- Collapsible,
219
- {
220
- defaultOpen: item.isActive,
221
- className: "group/collapsible",
222
- render: /* @__PURE__ */ jsx(SidebarMenuItem, {}),
223
- children: [
224
- /* @__PURE__ */ jsxs(
225
- CollapsibleTrigger,
226
- {
227
- render: /* @__PURE__ */ jsx(
228
- SidebarMenuButton,
229
- {
230
- tooltip: item.label,
231
- "aria-disabled": item.disabled,
232
- className: cn(item.disabled && "pointer-events-none")
233
- }
234
- ),
235
- children: [
236
- item.icon && /* @__PURE__ */ jsx(item.icon, {}),
237
- /* @__PURE__ */ jsx("span", { children: item.label }),
238
- /* @__PURE__ */ jsx(ChevronRight, { className: "ml-auto transition-transform duration-200 group-data-open/collapsible:rotate-90" })
239
- ]
240
- }
241
- ),
242
- item.badge && /* @__PURE__ */ jsx(SidebarMenuBadge, { children: item.badge }),
243
- /* @__PURE__ */ jsx(CollapsibleContent, { children: /* @__PURE__ */ jsx(SidebarMenuSub, { children: item.children.map((child) => /* @__PURE__ */ jsx(SidebarMenuSubItem, { children: /* @__PURE__ */ jsxs(
244
- SidebarMenuSubButton,
245
- {
246
- isActive: child.isActive,
247
- render: /* @__PURE__ */ jsx(
248
- LinkComponent,
249
- {
250
- href: child.href,
251
- "aria-disabled": child.disabled,
252
- tabIndex: child.disabled ? -1 : void 0,
253
- className: cn(child.disabled && "pointer-events-none opacity-50")
254
- }
255
- ),
256
- children: [
257
- child.icon && /* @__PURE__ */ jsx(child.icon, {}),
258
- /* @__PURE__ */ jsx("span", { children: child.label })
259
- ]
260
- }
261
- ) }, child.href)) }) })
262
- ]
263
- }
264
- );
265
- }
266
- function NavItemLink({
267
- item,
268
- linkComponent: LinkComponent = "a"
269
- }) {
270
- return /* @__PURE__ */ jsxs(SidebarMenuItem, { children: [
271
- /* @__PURE__ */ jsxs(
272
- SidebarMenuButton,
273
- {
274
- tooltip: item.label,
275
- isActive: item.isActive,
276
- render: /* @__PURE__ */ jsx(
277
- LinkComponent,
278
- {
279
- href: item.href,
280
- "aria-disabled": item.disabled,
281
- tabIndex: item.disabled ? -1 : void 0,
282
- className: cn(item.disabled && "pointer-events-none")
283
- }
284
- ),
285
- children: [
286
- item.icon && /* @__PURE__ */ jsx(item.icon, {}),
287
- /* @__PURE__ */ jsx("span", { children: item.label })
288
- ]
289
- }
290
- ),
291
- item.badge && /* @__PURE__ */ jsx(SidebarMenuBadge, { children: item.badge })
292
- ] });
293
- }
294
- var defaultNavigate = (href) => {
295
- window.location.assign(href);
296
- };
297
- var AppShell = forwardRef((props, ref) => {
298
- const {
299
- variant = "sidebar",
300
- groups,
301
- actions,
302
- header,
303
- children,
304
- className,
305
- linkComponent,
306
- onNavigate = defaultNavigate
307
- } = props;
308
- if (variant === "header") {
309
- return /* @__PURE__ */ jsxs("div", { ref, "data-slot": "app-shell", className: cn("flex h-full flex-col", className), children: [
310
- header !== void 0 ? header : /* @__PURE__ */ jsxs("header", { className: "flex h-14 shrink-0 items-center gap-3 border-b px-4", children: [
311
- groups.length > 0 && /* @__PURE__ */ jsx(NavSelect, { groups, onNavigate }),
312
- actions && /* @__PURE__ */ jsx("div", { className: "ml-auto flex items-center gap-2", children: actions })
313
- ] }),
314
- /* @__PURE__ */ jsx("main", { className: "flex-1 overflow-auto", children })
315
- ] });
316
- }
317
- const { defaultOpen = true } = props;
318
- return /* @__PURE__ */ jsxs(SidebarProvider, { defaultOpen, children: [
319
- /* @__PURE__ */ jsxs(Sidebar, { "data-slot": "app-sidebar", collapsible: "offcanvas", children: [
320
- /* @__PURE__ */ jsx(SidebarContent, { children: groups.map((group, index) => /* @__PURE__ */ jsxs(SidebarGroup, { children: [
321
- group.label && /* @__PURE__ */ jsx(SidebarGroupLabel, { children: group.label }),
322
- /* @__PURE__ */ jsx(SidebarMenu, { children: group.items.map(
323
- (item) => item.children && item.children.length > 0 ? /* @__PURE__ */ jsx(
324
- NavItemWithChildren,
325
- {
326
- item,
327
- linkComponent
328
- },
329
- item.href
330
- ) : /* @__PURE__ */ jsx(NavItemLink, { item, linkComponent }, item.href)
331
- ) })
332
- ] }, group.label ?? index)) }),
333
- actions && /* @__PURE__ */ jsx(SidebarFooter, { children: actions }),
334
- /* @__PURE__ */ jsx(SidebarRail, {})
335
- ] }),
336
- /* @__PURE__ */ jsxs(SidebarInset, { ref, "data-slot": "app-shell", className, children: [
337
- header !== void 0 ? header : /* @__PURE__ */ jsxs("header", { className: "flex h-14 shrink-0 items-center gap-2 border-b px-4", children: [
338
- /* @__PURE__ */ jsx(SidebarTrigger, {}),
339
- /* @__PURE__ */ jsx(Separator, { orientation: "vertical", className: "h-4" })
340
- ] }),
341
- /* @__PURE__ */ jsx("main", { className: "flex-1 overflow-auto", children })
342
- ] })
343
- ] });
344
- });
345
- AppShell.displayName = "AppShell";
346
- var headingStyles = {
347
- h1: "text-3xl font-bold tracking-tight",
348
- h2: "text-2xl font-semibold tracking-tight",
349
- h3: "text-xl font-semibold",
350
- h4: "text-lg font-semibold"
351
- };
352
- var SectionHeader = forwardRef(
353
- ({ title, description, actions, className, as: Comp = "h2" }, ref) => /* @__PURE__ */ jsxs(
354
- "div",
355
- {
356
- ref,
357
- "data-slot": "section-header",
358
- className: cn("flex flex-col gap-4 sm:flex-row sm:items-start sm:justify-between", className),
359
- children: [
360
- /* @__PURE__ */ jsxs("div", { children: [
361
- /* @__PURE__ */ jsx(Comp, { className: headingStyles[Comp], children: title }),
362
- description && /* @__PURE__ */ jsx("p", { className: "mt-1 text-sm text-muted-foreground", children: description })
363
- ] }),
364
- actions && /* @__PURE__ */ jsx("div", { className: "shrink-0", children: actions })
365
- ]
366
- }
367
- )
368
- );
369
- SectionHeader.displayName = "SectionHeader";
370
- var DashboardCard = forwardRef(
371
- ({ className, ...props }, ref) => /* @__PURE__ */ jsx(
372
- "div",
373
- {
374
- ref,
375
- "data-slot": "dashboard-card",
376
- className: cn(
377
- "group rounded-lg border bg-card px-1 py-1 text-card-foreground",
378
- className
379
- ),
380
- ...props
381
- }
382
- )
383
- );
384
- DashboardCard.displayName = "DashboardCard";
385
- var DashboardCardHeader = forwardRef(
386
- ({ className, ...props }, ref) => /* @__PURE__ */ jsx(
387
- "div",
388
- {
389
- ref,
390
- "data-slot": "dashboard-card-header",
391
- className: cn("flex flex-row items-start justify-between gap-4 px-3 py-3", className),
392
- ...props
393
- }
394
- )
395
- );
396
- DashboardCardHeader.displayName = "DashboardCardHeader";
397
- var DashboardCardTitle = forwardRef(
398
- ({ className, ...props }, ref) => /* @__PURE__ */ jsx(
399
- "h3",
400
- {
401
- ref,
402
- "data-slot": "dashboard-card-title",
403
- className: cn("text-sm leading-none font-semibold tracking-tight", className),
404
- ...props
405
- }
406
- )
407
- );
408
- DashboardCardTitle.displayName = "DashboardCardTitle";
409
- var DashboardCardDescription = forwardRef(({ className, ...props }, ref) => /* @__PURE__ */ jsx(
410
- "p",
411
- {
412
- ref,
413
- "data-slot": "dashboard-card-description",
414
- className: cn("text-xs text-muted-foreground", className),
415
- ...props
416
- }
417
- ));
418
- DashboardCardDescription.displayName = "DashboardCardDescription";
419
- var DashboardCardAction = forwardRef(
420
- ({ className, ...props }, ref) => /* @__PURE__ */ jsx(
421
- "div",
422
- {
423
- ref,
424
- "data-slot": "dashboard-card-action",
425
- className: cn("ml-auto shrink-0", className),
426
- ...props
427
- }
428
- )
429
- );
430
- DashboardCardAction.displayName = "DashboardCardAction";
431
- var DashboardCardContent = forwardRef(
432
- ({ className, ...props }, ref) => /* @__PURE__ */ jsx("div", { ref, "data-slot": "dashboard-card-content", className: cn("p-3", className), ...props })
433
- );
434
- DashboardCardContent.displayName = "DashboardCardContent";
435
- var DashboardCardFooter = forwardRef(
436
- ({ className, ...props }, ref) => /* @__PURE__ */ jsx(
437
- "div",
438
- {
439
- ref,
440
- "data-slot": "dashboard-card-footer",
441
- className: cn("flex items-center px-3 py-1.5", className),
442
- ...props
443
- }
444
- )
445
- );
446
- DashboardCardFooter.displayName = "DashboardCardFooter";
447
- function DashboardCardSkeleton({ className }) {
448
- return /* @__PURE__ */ jsxs(
449
- "div",
450
- {
451
- "data-slot": "dashboard-card-skeleton",
452
- className: cn("rounded-lg border bg-card p-6 shadow-sm", className),
453
- children: [
454
- /* @__PURE__ */ jsxs("div", { className: "flex items-start justify-between gap-4 pb-4", children: [
455
- /* @__PURE__ */ jsx(Skeleton, { className: "h-5 w-32" }),
456
- /* @__PURE__ */ jsx(Skeleton, { className: "h-8 w-8 rounded-md" })
457
- ] }),
458
- /* @__PURE__ */ jsx(Skeleton, { className: "h-4 w-full" }),
459
- /* @__PURE__ */ jsx(Skeleton, { className: "mt-2 h-4 w-3/4" })
460
- ]
461
- }
462
- );
463
- }
464
- function DashboardCardPreset({
465
- title,
466
- description,
467
- actions,
468
- footer,
469
- children,
470
- headerClassName,
471
- contentClassName,
472
- footerClassName,
473
- className,
474
- ...props
475
- }) {
476
- const hasHeader = title || description || actions;
477
- return /* @__PURE__ */ jsxs(DashboardCard, { className, ...props, children: [
478
- hasHeader && /* @__PURE__ */ jsxs(DashboardCardHeader, { className: headerClassName, children: [
479
- (title || description) && /* @__PURE__ */ jsxs("div", { children: [
480
- title && /* @__PURE__ */ jsx(DashboardCardTitle, { children: title }),
481
- description && /* @__PURE__ */ jsx(DashboardCardDescription, { children: description })
482
- ] }),
483
- actions && /* @__PURE__ */ jsx(DashboardCardAction, { children: actions })
484
- ] }),
485
- children && /* @__PURE__ */ jsx(DashboardCardContent, { className: contentClassName, children }),
486
- footer && /* @__PURE__ */ jsx(DashboardCardFooter, { className: footerClassName, children: footer })
487
- ] });
488
- }
489
- var SERIES_TOKENS = ["--chart-1", "--chart-2", "--chart-3", "--chart-4", "--chart-5"];
490
- var normalizeContext;
491
- var ZRENDER_COLOR_RE = /^(?:#[0-9a-f]{6}|rgba?\()/i;
492
- function toCanvasColor(value) {
493
- const raw = value.trim();
494
- if (!raw) return null;
495
- if (normalizeContext === void 0) {
496
- const canvas = document.createElement("canvas");
497
- canvas.width = 1;
498
- canvas.height = 1;
499
- normalizeContext = canvas.getContext("2d", { willReadFrequently: true });
500
- }
501
- const ctx = normalizeContext;
502
- if (!ctx) return raw;
503
- ctx.fillStyle = "#000000";
504
- ctx.fillStyle = raw;
505
- const onBlack = ctx.fillStyle;
506
- ctx.fillStyle = "#ffffff";
507
- ctx.fillStyle = raw;
508
- if (onBlack !== ctx.fillStyle || typeof onBlack !== "string") return null;
509
- if (ZRENDER_COLOR_RE.test(onBlack)) return onBlack;
510
- ctx.clearRect(0, 0, 1, 1);
511
- ctx.fillRect(0, 0, 1, 1);
512
- const [r = 0, g = 0, b = 0, a = 0] = ctx.getImageData(0, 0, 1, 1).data;
513
- return a === 255 ? `rgb(${r}, ${g}, ${b})` : `rgba(${r}, ${g}, ${b}, ${Math.round(a / 255 * 1e3) / 1e3})`;
514
- }
515
- function readChartTokens(el) {
516
- if (typeof document === "undefined") return null;
517
- const target = document.documentElement;
518
- if (!target) return null;
519
- const styles = getComputedStyle(target);
520
- const read = (name) => toCanvasColor(styles.getPropertyValue(name));
521
- const series = [];
522
- for (const token of SERIES_TOKENS) {
523
- const color = read(token);
524
- if (color) series.push(color);
525
- }
526
- return {
527
- series,
528
- foreground: read("--foreground"),
529
- mutedForeground: read("--muted-foreground"),
530
- border: read("--border"),
531
- popover: read("--popover"),
532
- popoverForeground: read("--popover-foreground")
533
- };
534
- }
535
- function sameChartTokens(a, b) {
536
- if (a === b) return true;
537
- if (!a || !b) return false;
538
- return a.series.length === b.series.length && a.series.every((color, i) => color === b.series[i]) && a.foreground === b.foreground && a.mutedForeground === b.mutedForeground && a.border === b.border && a.popover === b.popover && a.popoverForeground === b.popoverForeground;
539
- }
540
- function watchChartTokens(onChange) {
541
- if (typeof document === "undefined") return () => {
542
- };
543
- let frame = 0;
544
- const schedule = () => {
545
- if (frame) return;
546
- frame = requestAnimationFrame(() => {
547
- frame = 0;
548
- onChange();
549
- });
550
- };
551
- const themeObserver = new MutationObserver(schedule);
552
- const attributeFilter = ["class", "style", "data-theme"];
553
- themeObserver.observe(document.documentElement, { attributes: true, attributeFilter });
554
- if (document.body) themeObserver.observe(document.body, { attributes: true, attributeFilter });
555
- const styleObserver = new MutationObserver(schedule);
556
- if (document.head) {
557
- styleObserver.observe(document.head, {
558
- childList: true,
559
- subtree: true,
560
- characterData: true,
561
- attributes: true,
562
- attributeFilter: ["href", "media", "disabled"]
563
- });
564
- }
565
- const onLoad = (event) => {
566
- if (event.target instanceof HTMLLinkElement) schedule();
567
- };
568
- document.addEventListener("load", onLoad, true);
569
- const media = window.matchMedia("(prefers-color-scheme: dark)");
570
- media.addEventListener("change", schedule);
571
- return () => {
572
- if (frame) cancelAnimationFrame(frame);
573
- themeObserver.disconnect();
574
- styleObserver.disconnect();
575
- document.removeEventListener("load", onLoad, true);
576
- media.removeEventListener("change", schedule);
577
- };
578
- }
579
- function axisTheme(tokens, splitLine) {
580
- const line = tokens.border ?? void 0;
581
- return {
582
- axisLine: { show: true, lineStyle: { color: line } },
583
- axisTick: { show: true, lineStyle: { color: line } },
584
- axisLabel: { show: true, color: tokens.mutedForeground ?? void 0 },
585
- splitLine: { show: splitLine, lineStyle: { color: line ? [line] : void 0 } },
586
- splitArea: { show: false }
587
- };
588
- }
589
- function buildChartTheme(tokens) {
590
- const text = tokens.foreground ?? void 0;
591
- const muted = tokens.mutedForeground ?? void 0;
592
- const line = tokens.border ?? void 0;
593
- return {
594
- // Let the page background show through: charts sit on cards, not on a canvas.
595
- backgroundColor: "transparent",
596
- ...tokens.series.length > 0 ? { color: tokens.series } : {},
597
- textStyle: { color: text },
598
- title: { textStyle: { color: text }, subtextStyle: { color: muted } },
599
- legend: { textStyle: { color: muted } },
600
- categoryAxis: axisTheme(tokens, false),
601
- valueAxis: axisTheme(tokens, true),
602
- logAxis: axisTheme(tokens, true),
603
- timeAxis: axisTheme(tokens, true),
604
- tooltip: {
605
- backgroundColor: tokens.popover ?? void 0,
606
- borderColor: line,
607
- borderWidth: 1,
608
- textStyle: { color: tokens.popoverForeground ?? void 0 },
609
- axisPointer: { lineStyle: { color: line }, crossStyle: { color: line } }
610
- }
611
- };
612
- }
613
- function useChartTokens() {
614
- const [tokens, setTokens] = useState(() => readChartTokens());
615
- useEffect(() => {
616
- const sync = () => {
617
- setTokens((prev) => {
618
- const next = readChartTokens();
619
- return sameChartTokens(prev, next) ? prev : next;
620
- });
621
- };
622
- sync();
623
- return watchChartTokens(sync);
624
- }, []);
625
- return tokens;
626
- }
627
- var SERIES_TOKEN_NAME_RE = /^chart-([1-5])$/;
628
- var CSS_VAR_RE = /^var\(\s*(--[\w-]+)\s*(?:,\s*(.+))?\)$/;
629
- function resolveChartColors(colors, tokens) {
630
- return colors.map((color) => {
631
- const token = SERIES_TOKEN_NAME_RE.exec(color.trim());
632
- if (token) return tokens?.series[Number(token[1]) - 1] ?? "";
633
- if (typeof document === "undefined") return color;
634
- let value = color.trim();
635
- const cssVar = CSS_VAR_RE.exec(value);
636
- if (cssVar) {
637
- const styles = getComputedStyle(document.documentElement);
638
- value = styles.getPropertyValue(cssVar[1]).trim() || (cssVar[2] ?? "").trim();
639
- }
640
- return toCanvasColor(value) ?? "";
641
- });
642
- }
643
- var EChart = forwardRef(function EChart2({
644
- option,
645
- height,
646
- loading = false,
647
- theme,
648
- onEvents,
649
- ariaLabel,
650
- className,
651
- actions = false,
652
- fileName = "chart.png"
653
- }, ref) {
654
- const containerRef = useRef(null);
655
- const [instance, setInstance] = useState(null);
656
- const [copied, setCopied] = useState(false);
657
- const [tokens, setTokens] = useState(() => readChartTokens());
658
- useEffect(() => {
659
- if (theme !== void 0) return;
660
- const sync = () => {
661
- setTokens((prev) => {
662
- const next = readChartTokens();
663
- return sameChartTokens(prev, next) ? prev : next;
664
- });
665
- };
666
- sync();
667
- return watchChartTokens(sync);
668
- }, [theme]);
669
- const autoTheme = useMemo(() => tokens ? buildChartTheme(tokens) : void 0, [tokens]);
670
- const resolvedTheme = theme ?? autoTheme;
671
- useEffect(() => {
672
- const container = containerRef.current;
673
- if (!container) return;
674
- const inst = echarts.init(container, resolvedTheme, { renderer: "canvas" });
675
- container.dataset.rendering = "";
676
- inst.on("finished", () => {
677
- delete container.dataset.rendering;
678
- });
679
- setInstance(inst);
680
- const observer = new ResizeObserver(() => inst.resize());
681
- observer.observe(container);
682
- return () => {
683
- observer.disconnect();
684
- inst.dispose();
685
- };
686
- }, [resolvedTheme]);
687
- useEffect(() => {
688
- if (!instance) return;
689
- if (containerRef.current) containerRef.current.dataset.rendering = "";
690
- instance.setOption(option, { notMerge: true, lazyUpdate: true });
691
- }, [instance, option]);
692
- useEffect(() => {
693
- if (!instance) return;
694
- if (loading) instance.showLoading();
695
- else instance.hideLoading();
696
- }, [instance, loading]);
697
- useEffect(() => {
698
- if (!instance || !onEvents) return;
699
- const entries = Object.entries(onEvents);
700
- for (const [event, handler] of entries) {
701
- instance.on(event, handler);
702
- }
703
- return () => {
704
- if (instance.isDisposed()) return;
705
- for (const [event, handler] of entries) {
706
- instance.off(event, handler);
707
- }
708
- };
709
- }, [instance, onEvents]);
710
- const getPngDataUrl = useCallback(() => {
711
- if (!instance) return null;
712
- const pageBg = getComputedStyle(document.documentElement).backgroundColor;
713
- return instance.getDataURL({
714
- type: "png",
715
- pixelRatio: 2,
716
- backgroundColor: pageBg && pageBg !== "rgba(0, 0, 0, 0)" ? pageBg : "#ffffff"
717
- });
718
- }, [instance]);
719
- const handleCopy = useCallback(async () => {
720
- const dataUrl = getPngDataUrl();
721
- if (!dataUrl) return;
722
- try {
723
- const blob = await (await fetch(dataUrl)).blob();
724
- await navigator.clipboard.write([new ClipboardItem({ "image/png": blob })]);
725
- setCopied(true);
726
- setTimeout(() => setCopied(false), 2e3);
727
- } catch {
728
- }
729
- }, [getPngDataUrl]);
730
- const handleDownload = useCallback(() => {
731
- const dataUrl = getPngDataUrl();
732
- if (!dataUrl) return;
733
- const link = document.createElement("a");
734
- link.href = dataUrl;
735
- link.download = fileName;
736
- link.click();
737
- }, [getPngDataUrl, fileName]);
738
- const styleHeight = height == null ? void 0 : typeof height === "number" ? `${height}px` : height;
739
- return /* @__PURE__ */ jsxs(
740
- "div",
741
- {
742
- ref,
743
- "data-slot": "echart",
744
- className: cn("group relative w-full", height == null && "h-[400px]", className),
745
- style: styleHeight != null ? { height: styleHeight } : void 0,
746
- role: "img",
747
- "aria-label": ariaLabel ?? "\u30C1\u30E3\u30FC\u30C8",
748
- children: [
749
- /* @__PURE__ */ jsx("div", { ref: containerRef, "data-slot": "echart-canvas", className: "h-full w-full" }),
750
- actions && /* @__PURE__ */ jsxs(
751
- "div",
752
- {
753
- "data-slot": "echart-actions",
754
- className: "absolute top-2 right-2 z-10 flex gap-1 opacity-0 transition-opacity group-hover:opacity-100 focus-within:opacity-100",
755
- children: [
756
- /* @__PURE__ */ jsx(
757
- Button,
758
- {
759
- type: "button",
760
- variant: "ghost",
761
- size: "icon-sm",
762
- onClick: handleCopy,
763
- "aria-label": copied ? "\u30B3\u30D4\u30FC\u3057\u307E\u3057\u305F" : "PNG \u3092\u30AF\u30EA\u30C3\u30D7\u30DC\u30FC\u30C9\u306B\u30B3\u30D4\u30FC",
764
- children: copied ? /* @__PURE__ */ jsx(Check, { className: "size-4" }) : /* @__PURE__ */ jsx(Copy, { className: "size-4" })
765
- }
766
- ),
767
- /* @__PURE__ */ jsx(
768
- Button,
769
- {
770
- type: "button",
771
- variant: "ghost",
772
- size: "icon-sm",
773
- onClick: handleDownload,
774
- "aria-label": "PNG \u3092\u30C0\u30A6\u30F3\u30ED\u30FC\u30C9",
775
- children: /* @__PURE__ */ jsx(Download, { className: "size-4" })
776
- }
777
- )
778
- ]
779
- }
780
- )
781
- ]
782
- }
783
- );
784
- });
785
- EChart.displayName = "EChart";
786
-
787
- // src/components/chart-utils.ts
788
- var DEFAULT_CHART_COLORS = [
789
- "chart-1",
790
- "chart-2",
791
- "chart-3",
792
- "chart-4",
793
- "chart-5"
794
- ];
795
- var TOKEN_NAME_RE = /^chart-[1-5]$/;
796
- function chartColorToCss(color) {
797
- const value = color.trim();
798
- return TOKEN_NAME_RE.test(value) ? `var(--${value})` : value;
799
- }
800
- function chartColorAt(colors, i) {
801
- const palette = colors && colors.length > 0 ? colors : DEFAULT_CHART_COLORS;
802
- return palette[i % palette.length];
803
- }
804
- function chartColorsFor(colors, count) {
805
- return Array.from({ length: count }, (_, i) => chartColorAt(colors, i));
806
- }
807
- function tintCss(cssColor, percent) {
808
- return `color-mix(in oklab, ${cssColor} ${percent}%, transparent)`;
809
- }
810
- var numberFormat = new Intl.NumberFormat("ja-JP", { maximumFractionDigits: 2 });
811
- var defaultValueFormatter = (value) => numberFormat.format(value);
812
- function clamp(value, min, max) {
813
- return Math.min(max, Math.max(min, value));
814
- }
815
- function sortBarListData(data, sortOrder) {
816
- const rows = [...data];
817
- if (sortOrder === "ascending") rows.sort((a, b) => a.value - b.value);
818
- else if (sortOrder === "descending") rows.sort((a, b) => b.value - a.value);
819
- return rows;
820
- }
821
- function barListWidths(values) {
822
- const max = Math.max(0, ...values);
823
- if (max === 0) return values.map(() => 0);
824
- return values.map((v) => v <= 0 ? 0 : Math.max(1, v / max * 100));
825
- }
826
- function categoryBarSegments(values) {
827
- const clean = values.map((v) => Number.isFinite(v) && v > 0 ? v : 0);
828
- const total = clean.reduce((sum, v) => sum + v, 0);
829
- let running = 0;
830
- return clean.map((v) => {
831
- const start = total === 0 ? 0 : running / total * 100;
832
- running += v;
833
- return { width: total === 0 ? 0 : v / total * 100, start, end: running };
834
- });
835
- }
836
- function categoryBarLabels(values, minGap = 8) {
837
- const segments = categoryBarSegments(values).filter((s) => s.width > 0);
838
- if (segments.length === 0) return [];
839
- const labels = [{ position: 0, value: 0 }];
840
- segments.forEach((s, i) => {
841
- const label = { position: s.start + s.width, value: s.end };
842
- const prev = labels[labels.length - 1];
843
- if (label.position - prev.position >= minGap) labels.push(label);
844
- else if (i === segments.length - 1 && labels.length > 1) labels[labels.length - 1] = label;
845
- });
846
- return labels;
847
- }
848
- function categoryBarMarkerPosition(value, values) {
849
- const total = values.reduce((sum, v) => sum + (Number.isFinite(v) && v > 0 ? v : 0), 0);
850
- if (total === 0) return 0;
851
- return clamp(value / total * 100, 0, 100);
852
- }
853
- function categoryBarMarkerSegment(value, values) {
854
- const segments = categoryBarSegments(values);
855
- const index = segments.findIndex((s) => s.width > 0 && value <= s.end);
856
- if (index !== -1) return index;
857
- for (let i = segments.length - 1; i >= 0; i--) if (segments[i].width > 0) return i;
858
- return 0;
859
- }
860
- function progressCircleGeometry(value, max, radius, strokeWidth) {
861
- const ratio = max > 0 && Number.isFinite(value) ? clamp(value / max, 0, 1) : 0;
862
- const normalizedRadius = Math.max(0, radius - strokeWidth / 2);
863
- const circumference = 2 * Math.PI * normalizedRadius;
864
- return { size: radius * 2, normalizedRadius, circumference, offset: circumference * (1 - ratio), ratio };
865
- }
866
- function cellNumber(value) {
867
- if (typeof value === "number") return Number.isFinite(value) ? value : null;
868
- if (typeof value === "bigint") return Number(value);
869
- if (typeof value === "string" && value.trim() !== "") {
870
- const n = Number(value);
871
- return Number.isFinite(n) ? n : null;
872
- }
873
- return null;
874
- }
875
- function cartesianSeriesValues(data, categories, type = "default") {
876
- const raw = categories.map((category) => data.map((row) => cellNumber(row[category])));
877
- if (type !== "percent") return raw;
878
- return raw.map(
879
- (values) => values.map((value, i) => {
880
- if (value === null) return null;
881
- const total = categories.reduce((sum, _, k) => sum + Math.abs(raw[k][i] ?? 0), 0);
882
- return total === 0 ? 0 : Math.abs(value) / total * 100;
883
- })
884
- );
885
- }
886
- function withAlpha(color, alpha) {
887
- const hex = /^#([0-9a-f]{3}|[0-9a-f]{6})$/i.exec(color.trim());
888
- if (hex) {
889
- const h = hex[1];
890
- const full = h.length === 3 ? h.replace(/./g, (c) => c + c) : h;
891
- const n = Number.parseInt(full, 16);
892
- return `rgba(${n >> 16 & 255}, ${n >> 8 & 255}, ${n & 255}, ${alpha})`;
893
- }
894
- const rgb = /^rgba?\(\s*([\d.]+)[\s,]+([\d.]+)[\s,]+([\d.]+)/i.exec(color.trim());
895
- if (rgb) return `rgba(${rgb[1]}, ${rgb[2]}, ${rgb[3]}, ${alpha})`;
896
- return color;
897
- }
898
- var HTML_ESCAPES = { "&": "&amp;", "<": "&lt;", ">": "&gt;", '"': "&quot;", "'": "&#39;" };
899
- function escapeHtml(value) {
900
- return value.replace(/[&<>"']/g, (c) => HTML_ESCAPES[c]);
901
- }
902
- function tooltipHtml(title, rows, valueFormatter) {
903
- const lines = rows.map(
904
- (row) => `<div style="display:flex;align-items:center;gap:8px;line-height:20px"><span style="display:inline-block;width:8px;height:8px;border-radius:9999px;background:${escapeHtml(row.color)}"></span><span style="flex:1;opacity:.8">${escapeHtml(row.name)}</span><span style="font-weight:500;font-variant-numeric:tabular-nums;margin-left:12px">${row.value === null ? "\u2013" : escapeHtml(valueFormatter(row.value))}</span></div>`
905
- );
906
- return `<div style="font-weight:500;margin-bottom:4px">${escapeHtml(title)}</div>${lines.join("")}`;
907
- }
908
- var DIMMED = 0.3;
909
- function buildCartesianOption(cfg) {
910
- const {
911
- kind,
912
- data,
913
- index,
914
- categories,
915
- palette,
916
- valueFormatter,
917
- type = "default",
918
- layout = "horizontal",
919
- curveType = "linear",
920
- fill = "gradient",
921
- connectNulls = false,
922
- showLegend = true,
923
- showTooltip = true,
924
- showGridLines = true,
925
- showXAxis = true,
926
- showYAxis = true,
927
- startEndOnly = false,
928
- yAxisWidth,
929
- minValue,
930
- maxValue,
931
- autoMinValue = false,
932
- allowDecimals = true,
933
- xAxisLabel,
934
- yAxisLabel,
935
- barCategoryGap,
936
- showDots = false,
937
- active = null
938
- } = cfg;
939
- const labels = data.map((row) => String(row[index] ?? ""));
940
- const values = cartesianSeriesValues(data, categories, kind === "line" ? "default" : type);
941
- const stacked = kind !== "line" && type !== "default";
942
- const percent = kind !== "line" && type === "percent";
943
- const horizontalBars = kind === "bar" && layout === "vertical";
944
- const last = labels.length - 1;
945
- const series = categories.map((category, c) => {
946
- const color = palette[c] || void 0;
947
- const dimSeries = active !== null && active.category !== category;
948
- if (kind === "bar") {
949
- const radius = stacked ? 0 : horizontalBars ? [0, 3, 3, 0] : [3, 3, 0, 0];
950
- return {
951
- type: "bar",
952
- name: category,
953
- stack: stacked ? "total" : void 0,
954
- barCategoryGap,
955
- itemStyle: { color, borderRadius: radius },
956
- emphasis: { focus: "series" },
957
- data: values[c].map(
958
- (value, i) => active !== null && !(active.category === category && active.index === i) ? { value, itemStyle: { opacity: DIMMED } } : value
959
- )
960
- };
961
- }
962
- const areaStyle = kind !== "area" || fill === "none" ? void 0 : fill === "solid" || !color ? { opacity: fill === "solid" ? 0.3 : 0.2 } : {
963
- color: {
964
- type: "linear",
965
- x: 0,
966
- y: 0,
967
- x2: 0,
968
- y2: 1,
969
- colorStops: [
970
- { offset: 0, color: withAlpha(color, 0.35) },
971
- { offset: 1, color: withAlpha(color, 0) }
972
- ]
973
- }
974
- };
975
- return {
976
- type: "line",
977
- name: category,
978
- stack: stacked ? "total" : void 0,
979
- smooth: curveType === "smooth",
980
- step: curveType === "step" ? "middle" : void 0,
981
- connectNulls,
982
- symbol: "circle",
983
- symbolSize: 6,
984
- showSymbol: showDots || labels.length === 1,
985
- lineStyle: { width: 2, color, opacity: dimSeries ? DIMMED : 1 },
986
- itemStyle: { color, opacity: dimSeries ? DIMMED : 1 },
987
- areaStyle: areaStyle && dimSeries ? { ...areaStyle, opacity: DIMMED * 0.3 } : areaStyle,
988
- emphasis: { focus: "series" },
989
- data: values[c]
990
- };
991
- });
992
- const categoryAxis = {
993
- type: "category",
994
- data: labels,
995
- show: horizontalBars ? showYAxis : showXAxis,
996
- boundaryGap: kind === "bar",
997
- inverse: horizontalBars,
998
- axisTick: { show: false },
999
- axisLabel: {
1000
- hideOverlap: true,
1001
- interval: startEndOnly ? (i) => i === 0 || i === last : "auto",
1002
- ...horizontalBars && yAxisWidth != null ? { width: yAxisWidth, overflow: "truncate" } : {}
1003
- },
1004
- name: horizontalBars ? yAxisLabel : xAxisLabel,
1005
- nameLocation: "middle",
1006
- nameGap: horizontalBars ? (yAxisWidth ?? 48) + 8 : 28
1007
- };
1008
- const valueAxis = {
1009
- type: "value",
1010
- show: horizontalBars ? showXAxis : showYAxis,
1011
- min: percent ? 0 : minValue,
1012
- max: percent ? 100 : maxValue,
1013
- scale: autoMinValue && minValue == null,
1014
- minInterval: allowDecimals ? void 0 : 1,
1015
- axisLine: { show: false },
1016
- axisTick: { show: false },
1017
- splitLine: { show: showGridLines },
1018
- axisLabel: {
1019
- formatter: percent ? (v) => `${v}%` : (v) => valueFormatter(v),
1020
- ...!horizontalBars && yAxisWidth != null ? { width: yAxisWidth, overflow: "truncate" } : {}
1021
- },
1022
- name: horizontalBars ? xAxisLabel : yAxisLabel,
1023
- nameLocation: "middle",
1024
- nameGap: horizontalBars ? 28 : (yAxisWidth ?? 48) + 8
1025
- };
1026
- return {
1027
- animationDuration: 400,
1028
- legend: {
1029
- show: showLegend,
1030
- top: 0,
1031
- right: 0,
1032
- type: "scroll",
1033
- icon: "circle",
1034
- itemWidth: 8,
1035
- itemHeight: 8,
1036
- itemGap: 16
1037
- },
1038
- grid: {
1039
- top: showLegend ? 36 : 12,
1040
- // Lines start and end on the outermost ticks, so the last label hangs past the plot.
1041
- right: kind === "bar" ? 12 : 24,
1042
- bottom: xAxisLabel ? 24 : 4,
1043
- left: yAxisLabel ? 24 : 4,
1044
- containLabel: true
1045
- },
1046
- tooltip: {
1047
- show: showTooltip,
1048
- trigger: "axis",
1049
- axisPointer: { type: kind === "bar" ? "shadow" : "line" },
1050
- formatter: (params) => {
1051
- const list = Array.isArray(params) ? params : [params];
1052
- const i = list[0]?.dataIndex ?? 0;
1053
- const row = data[i] ?? {};
1054
- return tooltipHtml(
1055
- String(row[index] ?? ""),
1056
- list.map((p) => ({
1057
- name: p.seriesName ?? "",
1058
- color: typeof p.color === "string" ? p.color : "currentColor",
1059
- value: cellNumber(row[p.seriesName ?? ""])
1060
- })),
1061
- valueFormatter
1062
- );
1063
- }
1064
- },
1065
- xAxis: horizontalBars ? valueAxis : categoryAxis,
1066
- yAxis: horizontalBars ? categoryAxis : valueAxis,
1067
- series
1068
- };
1069
- }
1070
- function donutTotal(data, value) {
1071
- return data.reduce((sum, row) => {
1072
- const n = cellNumber(row[value]);
1073
- return n !== null && n > 0 ? sum + n : sum;
1074
- }, 0);
1075
- }
1076
- function buildDonutOption(cfg) {
1077
- const { data, category, value, palette, valueFormatter, variant = "donut", showTooltip = true, active = null } = cfg;
1078
- return {
1079
- animationDuration: 400,
1080
- tooltip: {
1081
- show: showTooltip,
1082
- trigger: "item",
1083
- formatter: (params) => {
1084
- const p = params;
1085
- const n = cellNumber(p.value);
1086
- const share = typeof p.percent === "number" ? ` (${p.percent.toFixed(1)}%)` : "";
1087
- return tooltipHtml(
1088
- `${p.name ?? ""}${share}`,
1089
- [{ name: value, color: typeof p.color === "string" ? p.color : "currentColor", value: n }],
1090
- valueFormatter
1091
- );
1092
- }
1093
- },
1094
- series: [
1095
- {
1096
- type: "pie",
1097
- radius: variant === "donut" ? ["72%", "100%"] : [0, "100%"],
1098
- center: ["50%", "50%"],
1099
- avoidLabelOverlap: true,
1100
- label: { show: false },
1101
- labelLine: { show: false },
1102
- // A hairline gap between slices instead of a border — no background colour to match.
1103
- padAngle: data.length > 1 ? 1 : 0,
1104
- itemStyle: { borderRadius: variant === "donut" ? 2 : 0 },
1105
- emphasis: { scale: true, scaleSize: 4 },
1106
- data: data.map((row, i) => {
1107
- const name = String(row[category] ?? "");
1108
- const color = palette[i] || void 0;
1109
- const n = cellNumber(row[value]);
1110
- return {
1111
- name,
1112
- value: n !== null && n > 0 ? n : 0,
1113
- itemStyle: { color, opacity: active !== null && active !== name ? DIMMED : 1 }
1114
- };
1115
- })
1116
- }
1117
- ]
1118
- };
1119
- }
1120
- function nextChartSelection(current, category, index) {
1121
- return current && current.category === category && current.index === index ? null : { category, index };
1122
- }
1123
- function chartSelectionPayload(selection, data, eventType) {
1124
- if (!selection) return null;
1125
- return { ...data[selection.index], eventType, categoryClicked: selection.category };
1126
- }
1127
- function useChartSelection(data, onValueChange, eventType) {
1128
- const [active, setActive] = useState(null);
1129
- const latest = useRef({ data, onValueChange, active });
1130
- latest.current = { data, onValueChange, active };
1131
- const interactive = onValueChange !== void 0;
1132
- const onEvents = useMemo(() => {
1133
- if (!interactive) return void 0;
1134
- return {
1135
- click: (raw) => {
1136
- const p = raw;
1137
- if (p.componentType !== "series" || typeof p.dataIndex !== "number") return;
1138
- const category = eventType === "slice" ? p.name ?? "" : p.seriesName ?? "";
1139
- const next = nextChartSelection(latest.current.active, category, p.dataIndex);
1140
- latest.current.active = next;
1141
- setActive(next);
1142
- latest.current.onValueChange?.(chartSelectionPayload(next, latest.current.data, eventType));
1143
- }
1144
- };
1145
- }, [interactive, eventType]);
1146
- return { active: interactive ? active : null, onEvents };
1147
- }
1148
- var AreaChart = forwardRef(function AreaChart2({
1149
- data,
1150
- index,
1151
- categories,
1152
- colors,
1153
- valueFormatter = defaultValueFormatter,
1154
- type = "default",
1155
- curveType = "linear",
1156
- fill = "gradient",
1157
- connectNulls = false,
1158
- showLegend = true,
1159
- showTooltip = true,
1160
- showGridLines = true,
1161
- showXAxis = true,
1162
- showYAxis = true,
1163
- startEndOnly = false,
1164
- yAxisWidth,
1165
- minValue,
1166
- maxValue,
1167
- autoMinValue = false,
1168
- allowDecimals = true,
1169
- xAxisLabel,
1170
- yAxisLabel,
1171
- onValueChange,
1172
- height,
1173
- loading,
1174
- ariaLabel,
1175
- className
1176
- }, ref) {
1177
- const tokens = useChartTokens();
1178
- const palette = useMemo(
1179
- () => resolveChartColors(chartColorsFor(colors, categories.length), tokens),
1180
- [colors, categories.length, tokens]
1181
- );
1182
- const { active, onEvents } = useChartSelection(data, onValueChange, "dot");
1183
- const option = useMemo(
1184
- () => buildCartesianOption({
1185
- kind: "area",
1186
- data,
1187
- index,
1188
- categories,
1189
- palette,
1190
- valueFormatter,
1191
- type,
1192
- curveType,
1193
- fill,
1194
- connectNulls,
1195
- showLegend,
1196
- showTooltip,
1197
- showGridLines,
1198
- showXAxis,
1199
- showYAxis,
1200
- startEndOnly,
1201
- yAxisWidth,
1202
- minValue,
1203
- maxValue,
1204
- autoMinValue,
1205
- allowDecimals,
1206
- xAxisLabel,
1207
- yAxisLabel,
1208
- showDots: onValueChange !== void 0,
1209
- active
1210
- }),
1211
- [
1212
- data,
1213
- index,
1214
- categories,
1215
- palette,
1216
- valueFormatter,
1217
- type,
1218
- curveType,
1219
- fill,
1220
- connectNulls,
1221
- showLegend,
1222
- showTooltip,
1223
- showGridLines,
1224
- showXAxis,
1225
- showYAxis,
1226
- startEndOnly,
1227
- yAxisWidth,
1228
- minValue,
1229
- maxValue,
1230
- autoMinValue,
1231
- allowDecimals,
1232
- xAxisLabel,
1233
- yAxisLabel,
1234
- onValueChange,
1235
- active
1236
- ]
1237
- );
1238
- return /* @__PURE__ */ jsx(
1239
- EChart,
1240
- {
1241
- ref,
1242
- option,
1243
- onEvents,
1244
- height,
1245
- loading,
1246
- ariaLabel: ariaLabel ?? `${categories.join("\u30FB")}\u306E\u9762\u30B0\u30E9\u30D5`,
1247
- className: cn("h-80", className)
1248
- }
1249
- );
1250
- });
1251
- AreaChart.displayName = "AreaChart";
1252
- var BarChart = forwardRef(function BarChart2({
1253
- data,
1254
- index,
1255
- categories,
1256
- colors,
1257
- valueFormatter = defaultValueFormatter,
1258
- type = "default",
1259
- layout = "horizontal",
1260
- barCategoryGap,
1261
- showLegend = true,
1262
- showTooltip = true,
1263
- showGridLines = true,
1264
- showXAxis = true,
1265
- showYAxis = true,
1266
- startEndOnly = false,
1267
- yAxisWidth,
1268
- minValue,
1269
- maxValue,
1270
- autoMinValue = false,
1271
- allowDecimals = true,
1272
- xAxisLabel,
1273
- yAxisLabel,
1274
- onValueChange,
1275
- height,
1276
- loading,
1277
- ariaLabel,
1278
- className
1279
- }, ref) {
1280
- const tokens = useChartTokens();
1281
- const palette = useMemo(
1282
- () => resolveChartColors(chartColorsFor(colors, categories.length), tokens),
1283
- [colors, categories.length, tokens]
1284
- );
1285
- const { active, onEvents } = useChartSelection(data, onValueChange, "bar");
1286
- const option = useMemo(
1287
- () => buildCartesianOption({
1288
- kind: "bar",
1289
- data,
1290
- index,
1291
- categories,
1292
- palette,
1293
- valueFormatter,
1294
- type,
1295
- layout,
1296
- barCategoryGap,
1297
- showLegend,
1298
- showTooltip,
1299
- showGridLines,
1300
- showXAxis,
1301
- showYAxis,
1302
- startEndOnly,
1303
- yAxisWidth,
1304
- minValue,
1305
- maxValue,
1306
- autoMinValue,
1307
- allowDecimals,
1308
- xAxisLabel,
1309
- yAxisLabel,
1310
- active
1311
- }),
1312
- [
1313
- data,
1314
- index,
1315
- categories,
1316
- palette,
1317
- valueFormatter,
1318
- type,
1319
- layout,
1320
- barCategoryGap,
1321
- showLegend,
1322
- showTooltip,
1323
- showGridLines,
1324
- showXAxis,
1325
- showYAxis,
1326
- startEndOnly,
1327
- yAxisWidth,
1328
- minValue,
1329
- maxValue,
1330
- autoMinValue,
1331
- allowDecimals,
1332
- xAxisLabel,
1333
- yAxisLabel,
1334
- active
1335
- ]
1336
- );
1337
- return /* @__PURE__ */ jsx(
1338
- EChart,
1339
- {
1340
- ref,
1341
- option,
1342
- onEvents,
1343
- height,
1344
- loading,
1345
- ariaLabel: ariaLabel ?? `${categories.join("\u30FB")}\u306E\u68D2\u30B0\u30E9\u30D5`,
1346
- className: cn("h-80", className)
1347
- }
1348
- );
1349
- });
1350
- BarChart.displayName = "BarChart";
1351
- var LineChart = forwardRef(function LineChart2({
1352
- data,
1353
- index,
1354
- categories,
1355
- colors,
1356
- valueFormatter = defaultValueFormatter,
1357
- curveType = "linear",
1358
- connectNulls = false,
1359
- showLegend = true,
1360
- showTooltip = true,
1361
- showGridLines = true,
1362
- showXAxis = true,
1363
- showYAxis = true,
1364
- startEndOnly = false,
1365
- yAxisWidth,
1366
- minValue,
1367
- maxValue,
1368
- autoMinValue = false,
1369
- allowDecimals = true,
1370
- xAxisLabel,
1371
- yAxisLabel,
1372
- onValueChange,
1373
- height,
1374
- loading,
1375
- ariaLabel,
1376
- className
1377
- }, ref) {
1378
- const tokens = useChartTokens();
1379
- const palette = useMemo(
1380
- () => resolveChartColors(chartColorsFor(colors, categories.length), tokens),
1381
- [colors, categories.length, tokens]
1382
- );
1383
- const { active, onEvents } = useChartSelection(data, onValueChange, "dot");
1384
- const option = useMemo(
1385
- () => buildCartesianOption({
1386
- kind: "line",
1387
- data,
1388
- index,
1389
- categories,
1390
- palette,
1391
- valueFormatter,
1392
- curveType,
1393
- connectNulls,
1394
- showLegend,
1395
- showTooltip,
1396
- showGridLines,
1397
- showXAxis,
1398
- showYAxis,
1399
- startEndOnly,
1400
- yAxisWidth,
1401
- minValue,
1402
- maxValue,
1403
- autoMinValue,
1404
- allowDecimals,
1405
- xAxisLabel,
1406
- yAxisLabel,
1407
- showDots: onValueChange !== void 0,
1408
- active
1409
- }),
1410
- [
1411
- data,
1412
- index,
1413
- categories,
1414
- palette,
1415
- valueFormatter,
1416
- curveType,
1417
- connectNulls,
1418
- showLegend,
1419
- showTooltip,
1420
- showGridLines,
1421
- showXAxis,
1422
- showYAxis,
1423
- startEndOnly,
1424
- yAxisWidth,
1425
- minValue,
1426
- maxValue,
1427
- autoMinValue,
1428
- allowDecimals,
1429
- xAxisLabel,
1430
- yAxisLabel,
1431
- onValueChange,
1432
- active
1433
- ]
1434
- );
1435
- return /* @__PURE__ */ jsx(
1436
- EChart,
1437
- {
1438
- ref,
1439
- option,
1440
- onEvents,
1441
- height,
1442
- loading,
1443
- ariaLabel: ariaLabel ?? `${categories.join("\u30FB")}\u306E\u6298\u308C\u7DDA\u30B0\u30E9\u30D5`,
1444
- className: cn("h-80", className)
1445
- }
1446
- );
1447
- });
1448
- LineChart.displayName = "LineChart";
1449
- var DonutChart = forwardRef(function DonutChart2({
1450
- data,
1451
- category,
1452
- value,
1453
- colors,
1454
- variant = "donut",
1455
- valueFormatter = defaultValueFormatter,
1456
- label,
1457
- showLabel = true,
1458
- showTooltip = true,
1459
- onValueChange,
1460
- loading,
1461
- ariaLabel,
1462
- className
1463
- }, ref) {
1464
- const tokens = useChartTokens();
1465
- const palette = useMemo(
1466
- () => resolveChartColors(chartColorsFor(colors, data.length), tokens),
1467
- [colors, data.length, tokens]
1468
- );
1469
- const { active, onEvents } = useChartSelection(data, onValueChange, "slice");
1470
- const option = useMemo(
1471
- () => buildDonutOption({
1472
- data,
1473
- category,
1474
- value,
1475
- palette,
1476
- valueFormatter,
1477
- variant,
1478
- showTooltip,
1479
- active: active?.category ?? null
1480
- }),
1481
- [data, category, value, palette, valueFormatter, variant, showTooltip, active]
1482
- );
1483
- const centerLabel = label ?? valueFormatter(donutTotal(data, value));
1484
- return /* @__PURE__ */ jsxs("div", { ref, "data-slot": "donut-chart", className: cn("relative size-40", className), children: [
1485
- /* @__PURE__ */ jsx(
1486
- EChart,
1487
- {
1488
- option,
1489
- onEvents,
1490
- loading,
1491
- ariaLabel: ariaLabel ?? `${category}\u5225\u306E${value}`,
1492
- className: "h-full"
1493
- }
1494
- ),
1495
- variant === "donut" && showLabel && /* @__PURE__ */ jsx(
1496
- "div",
1497
- {
1498
- "data-slot": "donut-chart-label",
1499
- className: "pointer-events-none absolute inset-0 flex items-center justify-center px-[18%] text-center text-lg font-semibold text-foreground tabular-nums",
1500
- children: centerLabel
1501
- }
1502
- )
1503
- ] });
1504
- });
1505
- DonutChart.displayName = "DonutChart";
1506
- var BarList = forwardRef(function BarList2({
1507
- data,
1508
- valueFormatter = defaultValueFormatter,
1509
- sortOrder = "descending",
1510
- color = "chart-1",
1511
- showAnimation = false,
1512
- onValueChange,
1513
- className,
1514
- ...props
1515
- }, ref) {
1516
- const [mounted, setMounted] = useState(!showAnimation);
1517
- useEffect(() => {
1518
- if (!showAnimation) return;
1519
- const frame = requestAnimationFrame(() => setMounted(true));
1520
- return () => cancelAnimationFrame(frame);
1521
- }, [showAnimation]);
1522
- const rows = sortBarListData(data, sortOrder);
1523
- const widths = barListWidths(rows.map((row) => row.value));
1524
- return /* @__PURE__ */ jsxs("div", { ref, "data-slot": "bar-list", className: cn("flex justify-between gap-6 text-sm", className), ...props, children: [
1525
- /* @__PURE__ */ jsx("div", { className: "relative min-w-0 flex-1 space-y-1.5", children: rows.map((row, i) => {
1526
- const css = chartColorToCss(row.color ?? color);
1527
- const label = row.href ? /* @__PURE__ */ jsx(
1528
- "a",
1529
- {
1530
- href: row.href,
1531
- target: /^https?:\/\//.test(row.href) ? "_blank" : void 0,
1532
- rel: /^https?:\/\//.test(row.href) ? "noreferrer" : void 0,
1533
- onClick: (event) => event.stopPropagation(),
1534
- className: "truncate hover:underline",
1535
- children: row.name
1536
- }
1537
- ) : /* @__PURE__ */ jsx("span", { className: "truncate", children: row.name });
1538
- const content = /* @__PURE__ */ jsxs(Fragment, { children: [
1539
- /* @__PURE__ */ jsx(
1540
- "span",
1541
- {
1542
- "aria-hidden": "true",
1543
- "data-slot": "bar-list-bar",
1544
- className: cn(
1545
- "absolute inset-y-0 left-0 rounded-sm",
1546
- showAnimation && "transition-[width] duration-700 ease-out"
1547
- ),
1548
- style: { width: `${mounted ? widths[i] : 0}%`, background: tintCss(css, 28) }
1549
- }
1550
- ),
1551
- /* @__PURE__ */ jsx("span", { className: "relative flex min-w-0 items-center px-2 text-foreground", children: label })
1552
- ] });
1553
- const rowClass = "relative flex h-8 w-full items-center rounded-sm";
1554
- return onValueChange ? /* @__PURE__ */ jsx(
1555
- "button",
1556
- {
1557
- type: "button",
1558
- "data-slot": "bar-list-row",
1559
- onClick: () => onValueChange(row),
1560
- className: cn(
1561
- rowClass,
1562
- "text-left outline-none hover:bg-muted/60 focus-visible:ring-2 focus-visible:ring-ring"
1563
- ),
1564
- children: content
1565
- },
1566
- row.key ?? row.name
1567
- ) : /* @__PURE__ */ jsx("div", { "data-slot": "bar-list-row", className: rowClass, children: content }, row.key ?? row.name);
1568
- }) }),
1569
- /* @__PURE__ */ jsx("div", { className: "shrink-0 space-y-1.5 text-right", children: rows.map((row) => /* @__PURE__ */ jsx(
1570
- "div",
1571
- {
1572
- className: "flex h-8 items-center justify-end font-medium text-foreground tabular-nums",
1573
- children: valueFormatter(row.value)
1574
- },
1575
- row.key ?? row.name
1576
- )) })
1577
- ] });
1578
- });
1579
- BarList.displayName = "BarList";
1580
- var CategoryBar = forwardRef(function CategoryBar2({ values, colors, marker, showLabels = true, valueFormatter = defaultValueFormatter, className, ...props }, ref) {
1581
- const segments = categoryBarSegments(values);
1582
- const labels = showLabels ? categoryBarLabels(values) : [];
1583
- const markerPosition = marker ? categoryBarMarkerPosition(marker.value, values) : 0;
1584
- const markerColor = marker ? chartColorToCss(chartColorAt(colors, categoryBarMarkerSegment(marker.value, values))) : "";
1585
- const markerDot = /* @__PURE__ */ jsx(
1586
- "span",
1587
- {
1588
- className: "block h-4 w-1 rounded-full ring-2 ring-background",
1589
- style: { background: markerColor }
1590
- }
1591
- );
1592
- return /* @__PURE__ */ jsxs("div", { ref, "data-slot": "category-bar", className: cn("w-full", className), ...props, children: [
1593
- showLabels && labels.length > 0 && /* @__PURE__ */ jsx("div", { "data-slot": "category-bar-labels", className: "relative mb-2 h-4 text-xs text-muted-foreground tabular-nums", children: labels.map((label, i) => /* @__PURE__ */ jsx(
1594
- "span",
1595
- {
1596
- className: cn(
1597
- "absolute top-0",
1598
- label.position <= 0 ? "left-0" : label.position >= 100 ? "right-0" : "-translate-x-1/2"
1599
- ),
1600
- style: label.position > 0 && label.position < 100 ? { left: `${label.position}%` } : void 0,
1601
- children: valueFormatter(label.value)
1602
- },
1603
- i
1604
- )) }),
1605
- /* @__PURE__ */ jsxs("div", { className: "relative flex h-2 w-full items-center", children: [
1606
- /* @__PURE__ */ jsx("div", { className: "flex h-full w-full gap-0.5 overflow-hidden rounded-full", children: segments.map(
1607
- (segment, i) => segment.width > 0 ? /* @__PURE__ */ jsx(
1608
- "span",
1609
- {
1610
- "data-slot": "category-bar-segment",
1611
- className: "h-full",
1612
- style: { flex: `${segment.width} 1 0%`, background: chartColorToCss(chartColorAt(colors, i)) }
1613
- },
1614
- i
1615
- ) : null
1616
- ) }),
1617
- marker && /* @__PURE__ */ jsx(
1618
- "div",
1619
- {
1620
- "data-slot": "category-bar-marker",
1621
- className: cn(
1622
- "absolute -translate-x-1/2",
1623
- marker.showAnimation && "transition-[left] duration-700 ease-out"
1624
- ),
1625
- style: { left: `${markerPosition}%` },
1626
- children: marker.tooltip ? /* @__PURE__ */ jsxs(Tooltip, { children: [
1627
- /* @__PURE__ */ jsx(TooltipTrigger, { render: /* @__PURE__ */ jsx("span", { "aria-label": marker.tooltip, className: "block py-1" }), children: markerDot }),
1628
- /* @__PURE__ */ jsx(TooltipContent, { children: marker.tooltip })
1629
- ] }) : markerDot
1630
- }
1631
- )
1632
- ] })
1633
- ] });
1634
- });
1635
- CategoryBar.displayName = "CategoryBar";
1636
- var ProgressCircle = forwardRef(function ProgressCircle2({
1637
- value = 0,
1638
- max = 100,
1639
- radius = 32,
1640
- strokeWidth = 6,
1641
- color = "chart-1",
1642
- showAnimation = true,
1643
- className,
1644
- children,
1645
- ...props
1646
- }, ref) {
1647
- const [mounted, setMounted] = useState(!showAnimation);
1648
- useEffect(() => {
1649
- if (!showAnimation) return;
1650
- const frame = requestAnimationFrame(() => setMounted(true));
1651
- return () => cancelAnimationFrame(frame);
1652
- }, [showAnimation]);
1653
- const { size, normalizedRadius, circumference, offset, ratio } = progressCircleGeometry(value, max, radius, strokeWidth);
1654
- const css = chartColorToCss(color);
1655
- return /* @__PURE__ */ jsxs(
1656
- "div",
1657
- {
1658
- ref,
1659
- "data-slot": "progress-circle",
1660
- role: "progressbar",
1661
- "aria-valuemin": 0,
1662
- "aria-valuemax": max,
1663
- "aria-valuenow": value,
1664
- className: cn("relative inline-flex shrink-0 items-center justify-center", className),
1665
- style: { width: size, height: size },
1666
- ...props,
1667
- children: [
1668
- /* @__PURE__ */ jsxs("svg", { width: size, height: size, viewBox: `0 0 ${size} ${size}`, className: "-rotate-90", "aria-hidden": "true", children: [
1669
- /* @__PURE__ */ jsx(
1670
- "circle",
1671
- {
1672
- cx: radius,
1673
- cy: radius,
1674
- r: normalizedRadius,
1675
- fill: "none",
1676
- strokeWidth,
1677
- style: { stroke: tintCss(css, 20) }
1678
- }
1679
- ),
1680
- ratio > 0 && /* @__PURE__ */ jsx(
1681
- "circle",
1682
- {
1683
- "data-slot": "progress-circle-value",
1684
- cx: radius,
1685
- cy: radius,
1686
- r: normalizedRadius,
1687
- fill: "none",
1688
- strokeWidth,
1689
- strokeLinecap: "round",
1690
- strokeDasharray: `${circumference} ${circumference}`,
1691
- strokeDashoffset: mounted ? offset : circumference,
1692
- className: cn(showAnimation && "transition-[stroke-dashoffset] duration-700 ease-out"),
1693
- style: { stroke: css }
1694
- }
1695
- )
1696
- ] }),
1697
- children != null && /* @__PURE__ */ jsx("div", { className: "absolute inset-0 flex items-center justify-center text-sm font-medium text-foreground tabular-nums", children })
1698
- ]
1699
- }
1700
- );
1701
- });
1702
- ProgressCircle.displayName = "ProgressCircle";
1703
- var DEFAULT_BLOCK_COLOR = "color-mix(in oklab, var(--muted-foreground) 35%, transparent)";
1704
- var Tracker = forwardRef(function Tracker2({ data, defaultColor, hoverEffect = true, className, ...props }, ref) {
1705
- const fallback = defaultColor ? chartColorToCss(defaultColor) : DEFAULT_BLOCK_COLOR;
1706
- return /* @__PURE__ */ jsx("div", { ref, "data-slot": "tracker", className: cn("flex h-8 w-full gap-px", className), ...props, children: data.map((block, i) => {
1707
- const blockClass = cn(
1708
- "h-full min-w-0 flex-1 rounded-[1px] first:rounded-l-[4px] last:rounded-r-[4px]",
1709
- hoverEffect && "transition-opacity hover:opacity-60"
1710
- );
1711
- const style = { background: block.color ? chartColorToCss(block.color) : fallback };
1712
- return block.tooltip ? /* @__PURE__ */ jsxs(Tooltip, { children: [
1713
- /* @__PURE__ */ jsx(
1714
- TooltipTrigger,
1715
- {
1716
- delay: 0,
1717
- render: /* @__PURE__ */ jsx("div", { "data-slot": "tracker-block", "aria-label": block.tooltip, className: blockClass, style })
1718
- }
1719
- ),
1720
- /* @__PURE__ */ jsx(TooltipContent, { children: block.tooltip })
1721
- ] }, block.key ?? i) : /* @__PURE__ */ jsx("div", { "data-slot": "tracker-block", className: blockClass, style }, block.key ?? i);
1722
- }) });
1723
- });
1724
- Tracker.displayName = "Tracker";
1725
- var DEFAULT_COLORS = [
1726
- "bg-chart-1",
1727
- "bg-chart-2",
1728
- "bg-chart-3",
1729
- "bg-chart-4",
1730
- "bg-chart-5"
1731
- ];
1732
- var funnelStepsVariants = cva("flex w-full", {
1733
- variants: {
1734
- size: {
1735
- sm: "",
1736
- md: "",
1737
- lg: ""
1738
- },
1739
- direction: {
1740
- vertical: "flex-col",
1741
- horizontal: "flex-row"
1742
- }
1743
- },
1744
- compoundVariants: [
1745
- { direction: "vertical", size: "sm", className: "gap-1" },
1746
- { direction: "vertical", size: "md", className: "gap-1.5" },
1747
- { direction: "vertical", size: "lg", className: "gap-2" },
1748
- { direction: "horizontal", size: "sm", className: "gap-2" },
1749
- { direction: "horizontal", size: "md", className: "gap-3" },
1750
- { direction: "horizontal", size: "lg", className: "gap-4" }
1751
- ],
1752
- defaultVariants: {
1753
- size: "md",
1754
- direction: "vertical"
1755
- }
1756
- });
1757
- var funnelBarVariants = cva("rounded-sm transition-[width] ease-out", {
1758
- variants: {
1759
- size: {
1760
- sm: "h-6",
1761
- md: "h-8",
1762
- lg: "h-10"
1763
- }
1764
- },
1765
- defaultVariants: {
1766
- size: "md"
1767
- }
1768
- });
1769
- var funnelBarContainerHorizontalVariants = cva(
1770
- "relative flex w-full items-end overflow-hidden rounded-sm bg-muted",
1771
- {
1772
- variants: {
1773
- size: {
1774
- sm: "h-20",
1775
- md: "h-28",
1776
- lg: "h-36"
1777
- }
1778
- },
1779
- defaultVariants: {
1780
- size: "md"
1781
- }
1782
- }
1783
- );
1784
- var funnelLabelVariants = cva("flex w-full items-center justify-between text-muted-foreground", {
1785
- variants: {
1786
- size: {
1787
- sm: "text-xs",
1788
- md: "text-sm",
1789
- lg: "text-sm"
1790
- }
1791
- },
1792
- defaultVariants: {
1793
- size: "md"
1794
- }
1795
- });
1796
- var funnelConversionVariants = cva("flex items-center text-muted-foreground", {
1797
- variants: {
1798
- size: {
1799
- sm: "text-[10px]",
1800
- md: "text-xs",
1801
- lg: "text-xs"
1802
- },
1803
- direction: {
1804
- vertical: "justify-end",
1805
- horizontal: "shrink-0 justify-center self-center"
1806
- }
1807
- },
1808
- compoundVariants: [
1809
- { direction: "vertical", size: "sm", className: "py-0" },
1810
- { direction: "vertical", size: "md", className: "py-0.5" },
1811
- { direction: "vertical", size: "lg", className: "py-0.5" }
1812
- ],
1813
- defaultVariants: {
1814
- size: "md",
1815
- direction: "vertical"
1816
- }
1817
- });
1818
- function defaultFormatValue(value) {
1819
- return value.toLocaleString();
1820
- }
1821
- function computeConversionRate(current, previous) {
1822
- if (previous === 0) return "--";
1823
- return `${(current / previous * 100).toFixed(1)}%`;
1824
- }
1825
- var FunnelSteps = forwardRef(function FunnelSteps2({
1826
- data,
1827
- showConversion = false,
1828
- formatValue = defaultFormatValue,
1829
- animate = false,
1830
- size = "md",
1831
- direction = "vertical",
1832
- className,
1833
- ...props
1834
- }, ref) {
1835
- const [mounted, setMounted] = useState(false);
1836
- const isHorizontal = direction === "horizontal";
1837
- useEffect(() => {
1838
- if (animate) setMounted(true);
1839
- }, [animate]);
1840
- const maxValue = data.length > 0 ? data[0].value : 0;
1841
- return /* @__PURE__ */ jsx(
1842
- "div",
1843
- {
1844
- ref,
1845
- "data-slot": "funnel-steps",
1846
- role: "list",
1847
- "aria-label": "\u30D5\u30A1\u30CD\u30EB",
1848
- className: cn(funnelStepsVariants({ size, direction }), className),
1849
- ...props,
1850
- children: data.map((step, index) => {
1851
- const percentage = maxValue > 0 ? step.value / maxValue * 100 : 0;
1852
- const barSize = step.value > 0 && percentage < 2 ? 2 : percentage;
1853
- const color = step.color ?? DEFAULT_COLORS[index % DEFAULT_COLORS.length];
1854
- const isClickable = !!step.onClick;
1855
- const barInteractionProps = isClickable ? {
1856
- role: "button",
1857
- tabIndex: 0,
1858
- onClick: step.onClick,
1859
- onKeyDown: (e) => {
1860
- if (e.key === "Enter" || e.key === " ") {
1861
- e.preventDefault();
1862
- step.onClick?.();
1863
- }
1864
- }
1865
- } : {};
1866
- const barInteractionClasses = isClickable ? "cursor-pointer hover:brightness-110 focus-visible:ring-2 focus-visible:ring-ring focus-visible:ring-offset-1 focus-visible:outline-none" : void 0;
1867
- return /* @__PURE__ */ jsxs(Fragment$1, { children: [
1868
- isHorizontal ? /* @__PURE__ */ jsxs(
1869
- "div",
1870
- {
1871
- role: "listitem",
1872
- className: "flex min-w-0 flex-1 flex-col items-center gap-1",
1873
- "aria-label": `${step.label}: ${formatValue(step.value)}`,
1874
- children: [
1875
- /* @__PURE__ */ jsx(
1876
- "span",
1877
- {
1878
- "data-slot": "funnel-value",
1879
- className: cn(
1880
- "text-muted-foreground tabular-nums",
1881
- size === "sm" ? "text-xs" : "text-sm"
1882
- ),
1883
- children: formatValue(step.value)
1884
- }
1885
- ),
1886
- /* @__PURE__ */ jsx("div", { className: funnelBarContainerHorizontalVariants({ size }), children: /* @__PURE__ */ jsx(
1887
- "div",
1888
- {
1889
- ...barInteractionProps,
1890
- className: cn(
1891
- "w-full rounded-sm transition-[height] ease-out",
1892
- color,
1893
- barInteractionClasses
1894
- ),
1895
- style: {
1896
- height: animate ? mounted ? `${barSize}%` : "0%" : `${barSize}%`,
1897
- transitionDuration: "0.5s",
1898
- transitionDelay: animate ? `${index * 0.08}s` : void 0
1899
- }
1900
- }
1901
- ) }),
1902
- /* @__PURE__ */ jsx(
1903
- "span",
1904
- {
1905
- className: cn(
1906
- "w-full truncate text-center text-muted-foreground",
1907
- size === "sm" ? "text-[10px]" : "text-xs"
1908
- ),
1909
- children: step.label
1910
- }
1911
- )
1912
- ]
1913
- }
1914
- ) : /* @__PURE__ */ jsxs("div", { role: "listitem", "aria-label": `${step.label}: ${formatValue(step.value)}`, children: [
1915
- /* @__PURE__ */ jsxs("div", { className: funnelLabelVariants({ size }), children: [
1916
- /* @__PURE__ */ jsx("span", { className: "truncate", children: step.label }),
1917
- /* @__PURE__ */ jsx("span", { "data-slot": "funnel-value", className: "tabular-nums", children: formatValue(step.value) })
1918
- ] }),
1919
- /* @__PURE__ */ jsx("div", { className: "relative w-full overflow-hidden rounded-sm bg-muted", children: /* @__PURE__ */ jsx(
1920
- "div",
1921
- {
1922
- ...barInteractionProps,
1923
- className: cn(funnelBarVariants({ size }), color, barInteractionClasses),
1924
- style: {
1925
- width: animate ? mounted ? `${barSize}%` : "0%" : `${barSize}%`,
1926
- transitionDuration: "0.5s",
1927
- transitionDelay: animate ? `${index * 0.08}s` : void 0
1928
- }
1929
- }
1930
- ) })
1931
- ] }),
1932
- showConversion && index < data.length - 1 && /* @__PURE__ */ jsx("div", { className: funnelConversionVariants({ size, direction }), "aria-hidden": "true", children: /* @__PURE__ */ jsxs("span", { children: [
1933
- "\u2192 ",
1934
- computeConversionRate(data[index + 1].value, step.value)
1935
- ] }) })
1936
- ] }, index);
1937
- })
1938
- }
1939
- );
1940
- });
1941
- FunnelSteps.displayName = "FunnelSteps";
1942
- var VB_WIDTH = 100;
1943
- function normalizeData(values, height, vPad = 2) {
1944
- const min = Math.min(...values);
1945
- const max = Math.max(...values);
1946
- const range = max - min;
1947
- const drawHeight = height - vPad * 2;
1948
- if (range === 0) return values.map(() => vPad + drawHeight / 2);
1949
- return values.map((v) => height - vPad - (v - min) / range * drawHeight);
1950
- }
1951
- function buildLinePath(ys) {
1952
- if (ys.length === 0) return "";
1953
- const step = ys.length > 1 ? VB_WIDTH / (ys.length - 1) : 0;
1954
- return ys.map((y, i) => `${i === 0 ? "M" : "L"}${(i * step).toFixed(2)},${y.toFixed(2)}`).join(" ");
1955
- }
1956
- function buildAreaPath(ys, height) {
1957
- if (ys.length === 0) return "";
1958
- const step = ys.length > 1 ? VB_WIDTH / (ys.length - 1) : 0;
1959
- const lastX = ((ys.length - 1) * step).toFixed(2);
1960
- return `${buildLinePath(ys)} L${lastX},${height} L0,${height} Z`;
1961
- }
1962
- function buildBarRects(ys, height, gap = 1) {
1963
- const barW = Math.max(1, VB_WIDTH / ys.length - gap);
1964
- return ys.map((y, i) => ({ x: i * (barW + gap), y, w: barW, h: height - y }));
1965
- }
1966
- var Sparkline = forwardRef(function Sparkline2({
1967
- data,
1968
- variant = "line",
1969
- height = 40,
1970
- color = "text-chart-1",
1971
- area = false,
1972
- animate = false,
1973
- className,
1974
- ...props
1975
- }, ref) {
1976
- const [mounted, setMounted] = useState(false);
1977
- useEffect(() => {
1978
- if (animate) setMounted(true);
1979
- }, [animate]);
1980
- if (data.length === 0) return null;
1981
- const ys = normalizeData(
1982
- data.map((d) => d.value),
1983
- height
1984
- );
1985
- return /* @__PURE__ */ jsxs(
1986
- "svg",
1987
- {
1988
- ref,
1989
- "data-slot": "sparkline",
1990
- viewBox: `0 0 ${VB_WIDTH} ${height}`,
1991
- preserveAspectRatio: "none",
1992
- width: "100%",
1993
- height,
1994
- "aria-hidden": "true",
1995
- className: cn("overflow-visible", className),
1996
- ...props,
1997
- children: [
1998
- variant === "line" && /* @__PURE__ */ jsxs(Fragment, { children: [
1999
- area && /* @__PURE__ */ jsx(
2000
- "path",
2001
- {
2002
- d: buildAreaPath(ys, height),
2003
- strokeWidth: 0,
2004
- className: cn("fill-current opacity-15", color)
2005
- }
2006
- ),
2007
- /* @__PURE__ */ jsx(
2008
- "path",
2009
- {
2010
- d: buildLinePath(ys),
2011
- fill: "none",
2012
- strokeWidth: 1.5,
2013
- strokeLinecap: "round",
2014
- strokeLinejoin: "round",
2015
- vectorEffect: "non-scaling-stroke",
2016
- pathLength: animate ? 1 : void 0,
2017
- strokeDasharray: animate ? 1 : void 0,
2018
- strokeDashoffset: animate ? mounted ? 0 : 1 : void 0,
2019
- className: cn("stroke-current", color),
2020
- style: animate ? { transition: "stroke-dashoffset 0.6s ease-in-out" } : void 0
2021
- }
2022
- )
2023
- ] }),
2024
- variant === "bar" && buildBarRects(ys, height).map((rect, i) => /* @__PURE__ */ jsx(
2025
- "rect",
2026
- {
2027
- x: rect.x,
2028
- y: animate ? mounted ? rect.y : height : rect.y,
2029
- width: rect.w,
2030
- height: animate ? mounted ? rect.h : 0 : rect.h,
2031
- rx: 0.5,
2032
- className: cn("fill-current", color),
2033
- style: animate ? {
2034
- transition: `height 0.4s ease-out ${i * 0.02}s, y 0.4s ease-out ${i * 0.02}s`
2035
- } : void 0
2036
- },
2037
- i
2038
- ))
2039
- ]
2040
- }
2041
- );
2042
- });
2043
- Sparkline.displayName = "Sparkline";
2044
- function useControlledState(controlledValue, defaultValue, onChange) {
2045
- const [internalValue, setInternalValue] = useState(defaultValue);
2046
- const isControlled = controlledValue !== void 0;
2047
- const value = isControlled ? controlledValue : internalValue;
2048
- const setValue = useCallback(
2049
- (updaterOrValue) => {
2050
- onChange?.(updaterOrValue);
2051
- if (!isControlled) {
2052
- setInternalValue(updaterOrValue);
2053
- }
2054
- },
2055
- [onChange, isControlled]
2056
- );
2057
- return [value, setValue];
2058
- }
2059
- var DataTableContext = createContext(null);
2060
- function useDataTable() {
2061
- const ctx = useContext(DataTableContext);
2062
- if (!ctx) throw new Error("useDataTable must be used inside <DataTable>");
2063
- return ctx;
2064
- }
2065
- function DataTable({
2066
- columns,
2067
- data,
2068
- enableSorting = true,
2069
- sorting: sortingProp,
2070
- onSortingChange,
2071
- enableFiltering = false,
2072
- columnFilters: columnFiltersProp,
2073
- onColumnFiltersChange,
2074
- globalFilter: globalFilterProp,
2075
- onGlobalFilterChange,
2076
- enablePagination = false,
2077
- pagination: paginationProp,
2078
- onPaginationChange,
2079
- pageCount,
2080
- enableRowSelection = false,
2081
- rowSelection: rowSelectionProp,
2082
- onRowSelectionChange,
2083
- columnVisibility: columnVisibilityProp,
2084
- onColumnVisibilityChange,
2085
- meta,
2086
- className,
2087
- children
2088
- }) {
2089
- const [sorting, setSorting] = useControlledState(sortingProp, [], onSortingChange);
2090
- const [columnFilters, setColumnFilters] = useControlledState(
2091
- columnFiltersProp,
2092
- [],
2093
- onColumnFiltersChange
2094
- );
2095
- const [globalFilter, setGlobalFilter] = useControlledState(
2096
- globalFilterProp,
2097
- "",
2098
- onGlobalFilterChange
2099
- );
2100
- const [rowSelection, setRowSelection] = useControlledState(
2101
- rowSelectionProp,
2102
- {},
2103
- onRowSelectionChange
2104
- );
2105
- const [columnVisibility, setColumnVisibility] = useControlledState(
2106
- columnVisibilityProp,
2107
- {},
2108
- onColumnVisibilityChange
2109
- );
2110
- const [pagination, setPagination] = useControlledState(
2111
- paginationProp,
2112
- { pageIndex: 0, pageSize: 10 },
2113
- onPaginationChange
2114
- );
2115
- const allColumns = useMemo(() => {
2116
- if (!enableRowSelection) return columns;
2117
- const selectionColumn = {
2118
- id: "_select",
2119
- header: ({ table: table2 }) => /* @__PURE__ */ jsx(
2120
- Checkbox,
2121
- {
2122
- checked: table2.getIsAllPageRowsSelected(),
2123
- indeterminate: table2.getIsSomePageRowsSelected(),
2124
- onCheckedChange: (checked) => table2.toggleAllPageRowsSelected(checked),
2125
- "aria-label": "\u5168\u3066\u9078\u629E"
2126
- }
2127
- ),
2128
- cell: ({ row }) => /* @__PURE__ */ jsx(
2129
- Checkbox,
2130
- {
2131
- checked: row.getIsSelected(),
2132
- onCheckedChange: (checked) => row.toggleSelected(checked),
2133
- "aria-label": "\u884C\u3092\u9078\u629E"
2134
- }
2135
- ),
2136
- enableSorting: false,
2137
- enableHiding: false
2138
- };
2139
- return [selectionColumn, ...columns];
2140
- }, [columns, enableRowSelection]);
2141
- const table = useReactTable({
2142
- data,
2143
- columns: allColumns,
2144
- state: {
2145
- sorting,
2146
- columnFilters,
2147
- globalFilter,
2148
- rowSelection,
2149
- columnVisibility,
2150
- ...enablePagination ? { pagination } : {}
2151
- },
2152
- enableSorting,
2153
- enableRowSelection,
2154
- onSortingChange: setSorting,
2155
- onColumnFiltersChange: setColumnFilters,
2156
- onGlobalFilterChange: setGlobalFilter,
2157
- onRowSelectionChange: setRowSelection,
2158
- onColumnVisibilityChange: setColumnVisibility,
2159
- ...enablePagination ? { onPaginationChange: setPagination } : {},
2160
- ...pageCount !== void 0 ? { pageCount, manualPagination: true } : {},
2161
- getCoreRowModel: getCoreRowModel(),
2162
- getSortedRowModel: getSortedRowModel(),
2163
- getFilteredRowModel: getFilteredRowModel(),
2164
- ...enablePagination ? { getPaginationRowModel: getPaginationRowModel() } : {},
2165
- meta
2166
- });
2167
- const selectedRows = useMemo(
2168
- () => table.getFilteredSelectedRowModel().rows.map((row) => row.original),
2169
- // `table` is a stable reference, so the selection state is the real input.
2170
- // eslint-disable-next-line react-hooks/exhaustive-deps
2171
- [rowSelection, data]
2172
- );
2173
- const hasSelection = selectedRows.length > 0;
2174
- const contextValue = useMemo(
2175
- () => ({
2176
- table,
2177
- selectedRows,
2178
- hasSelection,
2179
- globalFilter,
2180
- setGlobalFilter,
2181
- enableFiltering,
2182
- enablePagination,
2183
- enableRowSelection,
2184
- visibleColumnCount: allColumns.length
2185
- }),
2186
- // `useReactTable` returns the same object every render, so each piece of
2187
- // table state has to be tracked explicitly to re-render the consumers.
2188
- // eslint-disable-next-line react-hooks/exhaustive-deps
2189
- [
2190
- table,
2191
- selectedRows,
2192
- hasSelection,
2193
- globalFilter,
2194
- setGlobalFilter,
2195
- enableFiltering,
2196
- enablePagination,
2197
- enableRowSelection,
2198
- allColumns.length,
2199
- sorting,
2200
- columnFilters,
2201
- columnVisibility,
2202
- pagination,
2203
- rowSelection
2204
- ]
2205
- );
2206
- return /* @__PURE__ */ jsx(DataTableContext.Provider, { value: contextValue, children: /* @__PURE__ */ jsx("div", { "data-slot": "data-table", className: cn("space-y-4", className), children }) });
2207
- }
2208
- DataTable.displayName = "DataTable";
2209
- var DataTableToolbar = forwardRef(
2210
- ({ showSearch, toolbar, bulkActions, className, ...props }, ref) => {
2211
- const { globalFilter, setGlobalFilter, hasSelection, selectedRows, enableFiltering } = useDataTable();
2212
- const showSearchEffective = showSearch ?? enableFiltering;
2213
- const hasContent = showSearchEffective || toolbar != null || hasSelection && bulkActions != null;
2214
- if (!hasContent) return null;
2215
- return /* @__PURE__ */ jsxs(
2216
- "div",
2217
- {
2218
- ref,
2219
- "data-slot": "data-table-toolbar",
2220
- className: cn("flex flex-wrap items-center gap-2", className),
2221
- ...props,
2222
- children: [
2223
- showSearchEffective && /* @__PURE__ */ jsxs("div", { className: "relative", children: [
2224
- /* @__PURE__ */ jsx(Search, { className: "absolute top-2.5 left-2.5 size-4 text-muted-foreground" }),
2225
- /* @__PURE__ */ jsx(
2226
- Input,
2227
- {
2228
- value: globalFilter,
2229
- onChange: (e) => setGlobalFilter(e.target.value),
2230
- className: "max-w-sm pl-8"
2231
- }
2232
- )
2233
- ] }),
2234
- toolbar,
2235
- hasSelection && bulkActions && /* @__PURE__ */ jsx("div", { className: "ml-auto flex items-center gap-2", children: bulkActions(selectedRows) })
2236
- ]
2237
- }
2238
- );
2239
- }
2240
- );
2241
- DataTableToolbar.displayName = "DataTableToolbar";
2242
- var DataTableContent = forwardRef(
2243
- ({ className, ...props }, ref) => {
2244
- const { table, visibleColumnCount } = useDataTable();
2245
- return /* @__PURE__ */ jsx(
2246
- "div",
2247
- {
2248
- ref,
2249
- "data-slot": "data-table-content",
2250
- className: cn("overflow-x-auto", className),
2251
- ...props,
2252
- children: /* @__PURE__ */ jsxs(Table, { children: [
2253
- /* @__PURE__ */ jsx(TableHeader, { children: table.getHeaderGroups().map((headerGroup) => /* @__PURE__ */ jsx(TableRow, { children: headerGroup.headers.map((header) => /* @__PURE__ */ jsx(TableHead, { children: header.isPlaceholder ? null : header.column.getCanSort() ? /* @__PURE__ */ jsxs(
2254
- "button",
2255
- {
2256
- type: "button",
2257
- className: "inline-flex items-center gap-1 rounded hover:text-foreground focus-visible:ring-2 focus-visible:ring-ring focus-visible:ring-offset-1 focus-visible:outline-none",
2258
- onClick: header.column.getToggleSortingHandler(),
2259
- "aria-sort": header.column.getIsSorted() === "asc" ? "ascending" : header.column.getIsSorted() === "desc" ? "descending" : "none",
2260
- children: [
2261
- flexRender(header.column.columnDef.header, header.getContext()),
2262
- header.column.getIsSorted() === "asc" ? /* @__PURE__ */ jsx(ArrowUp, { className: "size-4" }) : header.column.getIsSorted() === "desc" ? /* @__PURE__ */ jsx(ArrowDown, { className: "size-4" }) : /* @__PURE__ */ jsx(ArrowUpDown, { className: "size-4 text-muted-foreground" })
2263
- ]
2264
- }
2265
- ) : flexRender(header.column.columnDef.header, header.getContext()) }, header.id)) }, headerGroup.id)) }),
2266
- /* @__PURE__ */ jsx(TableBody, { children: table.getRowModel().rows.length ? table.getRowModel().rows.map((row) => /* @__PURE__ */ jsx(TableRow, { "data-state": row.getIsSelected() ? "selected" : void 0, children: row.getVisibleCells().map((cell) => /* @__PURE__ */ jsx(TableCell, { children: flexRender(cell.column.columnDef.cell, cell.getContext()) }, cell.id)) }, row.id)) : /* @__PURE__ */ jsx(TableRow, { children: /* @__PURE__ */ jsx(
2267
- TableCell,
2268
- {
2269
- colSpan: visibleColumnCount,
2270
- className: "h-24 text-center text-muted-foreground",
2271
- children: "\u30C7\u30FC\u30BF\u304C\u3042\u308A\u307E\u305B\u3093"
2272
- }
2273
- ) }) })
2274
- ] })
2275
- }
2276
- );
2277
- }
2278
- );
2279
- DataTableContent.displayName = "DataTableContent";
2280
- var DataTablePagination = forwardRef(
2281
- ({ pageSizeOptions = [10, 20, 50], className, ...props }, ref) => {
2282
- const { table } = useDataTable();
2283
- const totalRows = table.getFilteredRowModel().rows.length;
2284
- const currentPageSize = table.getState().pagination.pageSize;
2285
- const currentPageIndex = table.getState().pagination.pageIndex;
2286
- const rangeStart = currentPageIndex * currentPageSize + 1;
2287
- const rangeEnd = Math.min((currentPageIndex + 1) * currentPageSize, totalRows);
2288
- return /* @__PURE__ */ jsxs(
2289
- "div",
2290
- {
2291
- ref,
2292
- "data-slot": "data-table-pagination",
2293
- className: cn("flex flex-wrap items-center justify-between gap-4", className),
2294
- ...props,
2295
- children: [
2296
- /* @__PURE__ */ jsxs("div", { className: "flex items-center gap-2 text-sm text-muted-foreground", children: [
2297
- /* @__PURE__ */ jsxs("span", { children: [
2298
- totalRows,
2299
- "\u4EF6\u4E2D ",
2300
- rangeStart,
2301
- " - ",
2302
- rangeEnd,
2303
- " \u3092\u8868\u793A"
2304
- ] }),
2305
- /* @__PURE__ */ jsxs(
2306
- Select,
2307
- {
2308
- value: String(currentPageSize),
2309
- onValueChange: (value) => table.setPageSize(Number(value)),
2310
- children: [
2311
- /* @__PURE__ */ jsx(SelectTrigger, { size: "sm", className: "w-[80px]", children: /* @__PURE__ */ jsx(SelectValue, {}) }),
2312
- /* @__PURE__ */ jsx(SelectContent, { children: pageSizeOptions.map((size) => /* @__PURE__ */ jsxs(SelectItem, { value: String(size), children: [
2313
- size,
2314
- "\u4EF6"
2315
- ] }, size)) })
2316
- ]
2317
- }
2318
- )
2319
- ] }),
2320
- /* @__PURE__ */ jsxs("div", { className: "flex items-center gap-1", children: [
2321
- /* @__PURE__ */ jsx(
2322
- Button,
2323
- {
2324
- variant: "outline",
2325
- size: "sm",
2326
- onClick: () => table.firstPage(),
2327
- disabled: !table.getCanPreviousPage(),
2328
- children: "\u6700\u521D"
2329
- }
2330
- ),
2331
- /* @__PURE__ */ jsx(
2332
- Button,
2333
- {
2334
- variant: "outline",
2335
- size: "sm",
2336
- onClick: () => table.previousPage(),
2337
- disabled: !table.getCanPreviousPage(),
2338
- children: "\u524D\u3078"
2339
- }
2340
- ),
2341
- /* @__PURE__ */ jsx(
2342
- Button,
2343
- {
2344
- variant: "outline",
2345
- size: "sm",
2346
- onClick: () => table.nextPage(),
2347
- disabled: !table.getCanNextPage(),
2348
- children: "\u6B21\u3078"
2349
- }
2350
- ),
2351
- /* @__PURE__ */ jsx(
2352
- Button,
2353
- {
2354
- variant: "outline",
2355
- size: "sm",
2356
- onClick: () => table.lastPage(),
2357
- disabled: !table.getCanNextPage(),
2358
- children: "\u6700\u5F8C"
2359
- }
2360
- )
2361
- ] })
2362
- ]
2363
- }
2364
- );
2365
- }
2366
- );
2367
- DataTablePagination.displayName = "DataTablePagination";
2368
- var DataTableColumnVisibility = forwardRef(({ columnLabels, className }, ref) => {
2369
- const { table } = useDataTable();
2370
- const hideableColumns = table.getAllColumns().filter((column) => column.getCanHide());
2371
- if (hideableColumns.length === 0) return null;
2372
- return /* @__PURE__ */ jsxs(DropdownMenu, { children: [
2373
- /* @__PURE__ */ jsx(
2374
- DropdownMenuTrigger,
2375
- {
2376
- ref,
2377
- render: /* @__PURE__ */ jsx(Button, { variant: "outline", size: "sm", className: cn(className) }),
2378
- "data-slot": "data-table-column-visibility",
2379
- children: /* @__PURE__ */ jsx(Columns3, { className: "size-4" })
2380
- }
2381
- ),
2382
- /* @__PURE__ */ jsx(DropdownMenuContent, { align: "end", className: "min-w-[10rem]", children: hideableColumns.map((column) => {
2383
- const label = columnLabels?.[column.id] ?? (typeof column.columnDef.header === "string" ? column.columnDef.header : column.id);
2384
- return /* @__PURE__ */ jsx(
2385
- DropdownMenuCheckboxItem,
2386
- {
2387
- checked: column.getIsVisible(),
2388
- onCheckedChange: (checked) => column.toggleVisibility(checked),
2389
- children: label
2390
- },
2391
- column.id
2392
- );
2393
- }) })
2394
- ] });
2395
- });
2396
- DataTableColumnVisibility.displayName = "DataTableColumnVisibility";
2397
- function DataTablePreset({
2398
- enableColumnVisibility = false,
2399
- columnLabels,
2400
- toolbar,
2401
- bulkActions,
2402
- ...tableProps
2403
- }) {
2404
- const toolbarSlot = toolbar || enableColumnVisibility ? /* @__PURE__ */ jsxs(Fragment, { children: [
2405
- toolbar,
2406
- enableColumnVisibility && /* @__PURE__ */ jsx(DataTableColumnVisibility, { columnLabels })
2407
- ] }) : void 0;
2408
- return /* @__PURE__ */ jsxs(DataTable, { ...tableProps, children: [
2409
- /* @__PURE__ */ jsx(
2410
- DataTableToolbar,
2411
- {
2412
- showSearch: tableProps.enableFiltering,
2413
- toolbar: toolbarSlot,
2414
- bulkActions
2415
- }
2416
- ),
2417
- /* @__PURE__ */ jsx(DataTableContent, {}),
2418
- tableProps.enablePagination && /* @__PURE__ */ jsx(DataTablePagination, {})
2419
- ] });
2420
- }
2421
- DataTablePreset.displayName = "DataTablePreset";
2422
- var FilterBarContext = createContext(null);
2423
- function useFilterBar() {
2424
- const ctx = useContext(FilterBarContext);
2425
- if (!ctx) throw new Error("useFilterBar must be used within <FilterBar>");
2426
- return ctx;
2427
- }
2428
- var FilterBar = forwardRef(
2429
- ({ value, onChange, onClear, className, children, ...props }, ref) => /* @__PURE__ */ jsx(FilterBarContext.Provider, { value: { value, onChange, onClear }, children: /* @__PURE__ */ jsx(
2430
- "div",
2431
- {
2432
- ref,
2433
- role: "search",
2434
- "aria-label": "\u30D5\u30A3\u30EB\u30BF\u30FC",
2435
- "data-slot": "filter-bar",
2436
- className: cn("flex flex-wrap items-center gap-2", className),
2437
- ...props,
2438
- children
2439
- }
2440
- ) })
2441
- );
2442
- FilterBar.displayName = "FilterBar";
2443
- function FilterBarSelect({
2444
- filterKey,
2445
- label,
2446
- options,
2447
- placeholder,
2448
- className
2449
- }) {
2450
- const { value, onChange } = useFilterBar();
2451
- const handleChange = (selected) => onChange({ ...value, [filterKey]: selected ?? void 0 });
2452
- return /* @__PURE__ */ jsxs(Select, { value: value[filterKey] ?? "", onValueChange: handleChange, children: [
2453
- /* @__PURE__ */ jsx(SelectTrigger, { size: "sm", "aria-label": label, "data-slot": "filter-bar-select", className, children: /* @__PURE__ */ jsx(SelectValue, { placeholder: placeholder ?? label }) }),
2454
- /* @__PURE__ */ jsx(SelectContent, { children: options.map((option) => /* @__PURE__ */ jsx(SelectItem, { value: option.value, disabled: option.disabled, children: option.label }, option.value)) })
2455
- ] });
2456
- }
2457
- FilterBarSelect.displayName = "FilterBarSelect";
2458
- function FilterBarMultiSelect({
2459
- filterKey,
2460
- label,
2461
- options,
2462
- placeholder,
2463
- className
2464
- }) {
2465
- const { value, onChange } = useFilterBar();
2466
- const selected = value[filterKey] ?? [];
2467
- const handleToggle = (option) => {
2468
- const next = selected.includes(option) ? selected.filter((v) => v !== option) : [...selected, option];
2469
- onChange({ ...value, [filterKey]: next.length > 0 ? next : void 0 });
2470
- };
2471
- return /* @__PURE__ */ jsxs(Popover, { children: [
2472
- /* @__PURE__ */ jsxs(
2473
- PopoverTrigger,
2474
- {
2475
- render: /* @__PURE__ */ jsx(Button, { variant: "outline", size: "sm", className: cn("h-8 gap-1", className) }),
2476
- "aria-label": `${placeholder ?? label}${selected.length > 0 ? ` (${selected.length}\u4EF6\u9078\u629E\u4E2D)` : ""}`,
2477
- "data-slot": "filter-bar-multi-select",
2478
- children: [
2479
- placeholder ?? label,
2480
- selected.length > 0 && /* @__PURE__ */ jsx(Badge, { variant: "secondary", className: "ml-1 px-1.5 py-0 text-xs", children: selected.length }),
2481
- /* @__PURE__ */ jsx(ChevronDown, { className: "size-3.5 opacity-50", "aria-hidden": "true" })
2482
- ]
2483
- }
2484
- ),
2485
- /* @__PURE__ */ jsx(PopoverContent, { align: "start", className: "w-56 p-2", children: /* @__PURE__ */ jsx("div", { className: "flex flex-col gap-1", role: "group", "aria-label": label, children: options.map((option) => /* @__PURE__ */ jsxs(
2486
- "label",
2487
- {
2488
- className: "flex cursor-pointer items-center gap-2 rounded-sm px-2 py-1.5 text-sm hover:bg-accent",
2489
- children: [
2490
- /* @__PURE__ */ jsx(
2491
- Checkbox,
2492
- {
2493
- checked: selected.includes(option.value),
2494
- disabled: option.disabled,
2495
- onCheckedChange: () => handleToggle(option.value)
2496
- }
2497
- ),
2498
- option.label
2499
- ]
2500
- },
2501
- option.value
2502
- )) }) })
2503
- ] });
2504
- }
2505
- FilterBarMultiSelect.displayName = "FilterBarMultiSelect";
2506
- function FilterBarActiveChips({ filters, className }) {
2507
- const { value, onChange } = useFilterBar();
2508
- const getActiveChips = () => {
2509
- const chips = [];
2510
- const pushRaw = (key, v) => {
2511
- if (typeof v === "string") {
2512
- chips.push({ key, filterLabel: key, optionLabel: v, isMulti: false });
2513
- } else {
2514
- for (const val of v) {
2515
- chips.push({ key, filterLabel: key, optionLabel: val, optionValue: val, isMulti: true });
2516
- }
2517
- }
2518
- };
2519
- for (const [key, v] of Object.entries(value)) {
2520
- if (v === void 0 || v === "") continue;
2521
- const filter = filters?.find((f) => f.key === key);
2522
- if (!filter) {
2523
- pushRaw(key, v);
2524
- continue;
2525
- }
2526
- if (filter.type === "select" && typeof v === "string") {
2527
- const option = filter.options?.find((o) => o.value === v);
2528
- chips.push({
2529
- key,
2530
- filterLabel: filter.label,
2531
- optionLabel: option?.label ?? v,
2532
- isMulti: false
2533
- });
2534
- } else if (filter.type === "multi-select" && Array.isArray(v)) {
2535
- for (const val of v) {
2536
- const option = filter.options?.find((o) => o.value === val);
2537
- chips.push({
2538
- key,
2539
- filterLabel: filter.label,
2540
- optionLabel: option?.label ?? val,
2541
- optionValue: val,
2542
- isMulti: true
2543
- });
2544
- }
2545
- }
2546
- }
2547
- return chips;
2548
- };
2549
- const handleRemoveFilter = (key, optionValue) => {
2550
- if (optionValue !== void 0) {
2551
- const current = value[key] ?? [];
2552
- const next = current.filter((v) => v !== optionValue);
2553
- onChange({ ...value, [key]: next.length > 0 ? next : void 0 });
2554
- } else {
2555
- onChange({ ...value, [key]: void 0 });
2556
- }
2557
- };
2558
- const activeChips = getActiveChips();
2559
- if (activeChips.length === 0) return null;
2560
- return /* @__PURE__ */ jsx(Fragment, { children: activeChips.map((chip) => /* @__PURE__ */ jsxs(
2561
- Badge,
2562
- {
2563
- variant: "secondary",
2564
- className: cn("gap-1 pr-1", className),
2565
- "data-slot": "filter-bar-chip",
2566
- children: [
2567
- /* @__PURE__ */ jsxs("span", { className: "text-xs text-muted-foreground", children: [
2568
- chip.filterLabel,
2569
- ":"
2570
- ] }),
2571
- chip.optionLabel,
2572
- /* @__PURE__ */ jsx(
2573
- "button",
2574
- {
2575
- type: "button",
2576
- className: "ml-0.5 rounded-full p-0.5 hover:bg-muted-foreground/20",
2577
- onClick: () => handleRemoveFilter(chip.key, chip.optionValue),
2578
- "aria-label": `${chip.filterLabel}: ${chip.optionLabel} \u3092\u524A\u9664`,
2579
- children: /* @__PURE__ */ jsx(X, { className: "size-3", "aria-hidden": "true" })
2580
- }
2581
- )
2582
- ]
2583
- },
2584
- `${chip.key}-${chip.optionValue ?? "single"}`
2585
- )) });
2586
- }
2587
- FilterBarActiveChips.displayName = "FilterBarActiveChips";
2588
- function FilterBarClearButton({ label = "\u30AF\u30EA\u30A2", className }) {
2589
- const { value, onClear } = useFilterBar();
2590
- const hasActiveFilters = Object.values(value).some(
2591
- (v) => Array.isArray(v) ? v.length > 0 : v !== void 0 && v !== ""
2592
- );
2593
- if (!hasActiveFilters || !onClear) return null;
2594
- return /* @__PURE__ */ jsx(
2595
- Button,
2596
- {
2597
- variant: "ghost",
2598
- size: "sm",
2599
- className: cn("h-7 px-2 text-xs", className),
2600
- onClick: onClear,
2601
- "aria-label": "\u3059\u3079\u3066\u306E\u30D5\u30A3\u30EB\u30BF\u30FC\u3092\u30AF\u30EA\u30A2",
2602
- "data-slot": "filter-bar-clear-button",
2603
- children: label
2604
- }
2605
- );
2606
- }
2607
- FilterBarClearButton.displayName = "FilterBarClearButton";
2608
- function FilterBarPreset({
2609
- filters,
2610
- value,
2611
- onChange,
2612
- onClear,
2613
- className
2614
- }) {
2615
- return /* @__PURE__ */ jsxs(FilterBar, { value, onChange, onClear, className, children: [
2616
- filters.map((filter) => {
2617
- if (filter.type === "select") {
2618
- return /* @__PURE__ */ jsx(
2619
- FilterBarSelect,
2620
- {
2621
- filterKey: filter.key,
2622
- label: filter.label,
2623
- placeholder: filter.placeholder,
2624
- options: filter.options ?? []
2625
- },
2626
- filter.key
2627
- );
2628
- }
2629
- if (filter.type === "multi-select") {
2630
- return /* @__PURE__ */ jsx(
2631
- FilterBarMultiSelect,
2632
- {
2633
- filterKey: filter.key,
2634
- label: filter.label,
2635
- placeholder: filter.placeholder,
2636
- options: filter.options ?? []
2637
- },
2638
- filter.key
2639
- );
2640
- }
2641
- return null;
2642
- }),
2643
- /* @__PURE__ */ jsx(FilterBarActiveChips, { filters }),
2644
- onClear && /* @__PURE__ */ jsx(FilterBarClearButton, {})
2645
- ] });
2646
- }
2647
- FilterBarPreset.displayName = "FilterBarPreset";
2648
- var defaultPresets = [
2649
- {
2650
- label: "Today",
2651
- getValue: () => {
2652
- const today = /* @__PURE__ */ new Date();
2653
- return { from: startOfDay(today), to: endOfDay(today) };
2654
- }
2655
- },
2656
- {
2657
- label: "Yesterday",
2658
- getValue: () => {
2659
- const yesterday = subDays(/* @__PURE__ */ new Date(), 1);
2660
- return { from: startOfDay(yesterday), to: endOfDay(yesterday) };
2661
- }
2662
- },
2663
- {
2664
- label: "Last 7 days",
2665
- getValue: () => {
2666
- const today = /* @__PURE__ */ new Date();
2667
- return { from: startOfDay(subDays(today, 6)), to: endOfDay(today) };
2668
- }
2669
- },
2670
- {
2671
- label: "Last 14 days",
2672
- getValue: () => {
2673
- const today = /* @__PURE__ */ new Date();
2674
- return { from: startOfDay(subDays(today, 13)), to: endOfDay(today) };
2675
- }
2676
- },
2677
- {
2678
- label: "Last 30 days",
2679
- getValue: () => {
2680
- const today = /* @__PURE__ */ new Date();
2681
- return { from: startOfDay(subDays(today, 29)), to: endOfDay(today) };
2682
- }
2683
- },
2684
- {
2685
- label: "Last 90 days",
2686
- getValue: () => {
2687
- const today = /* @__PURE__ */ new Date();
2688
- return { from: startOfDay(subDays(today, 89)), to: endOfDay(today) };
2689
- }
2690
- },
2691
- {
2692
- label: "This month",
2693
- getValue: () => {
2694
- const today = /* @__PURE__ */ new Date();
2695
- return { from: startOfMonth(today), to: endOfDay(today) };
2696
- }
2697
- },
2698
- {
2699
- label: "Last month",
2700
- getValue: () => {
2701
- const lastMonth = subMonths(/* @__PURE__ */ new Date(), 1);
2702
- return { from: startOfMonth(lastMonth), to: endOfMonth(lastMonth) };
2703
- }
2704
- }
2705
- ];
2706
- var DateRangePicker = forwardRef(
2707
- function DateRangePicker2({
2708
- value,
2709
- onChange,
2710
- presets = defaultPresets,
2711
- showPresets = true,
2712
- maxDate,
2713
- minDate,
2714
- placeholder = "Select date range",
2715
- disabled = false,
2716
- className,
2717
- align = "start"
2718
- }, ref) {
2719
- const [open, setOpen] = useState(false);
2720
- const isMobile = useIsMobile();
2721
- const handleCalendarSelect = useCallback(
2722
- (range) => {
2723
- onChange?.({ from: range?.from, to: range?.to });
2724
- },
2725
- [onChange]
2726
- );
2727
- const handlePresetClick = useCallback(
2728
- (preset) => {
2729
- onChange?.(preset.getValue());
2730
- setOpen(false);
2731
- },
2732
- [onChange]
2733
- );
2734
- const formatDateRange = () => {
2735
- if (!value?.from) return placeholder;
2736
- if (!value.to) return format(value.from, "yyyy/MM/dd", { locale: ja });
2737
- return `${format(value.from, "yyyy/MM/dd", { locale: ja })} - ${format(value.to, "yyyy/MM/dd", { locale: ja })}`;
2738
- };
2739
- const calendarSelected = value?.from ? { from: value.from, to: value.to ?? void 0 } : void 0;
2740
- return /* @__PURE__ */ jsx("div", { ref, "data-slot": "date-range-picker", children: /* @__PURE__ */ jsxs(Popover, { open, onOpenChange: setOpen, children: [
2741
- /* @__PURE__ */ jsxs(
2742
- PopoverTrigger,
2743
- {
2744
- render: /* @__PURE__ */ jsx(
2745
- Button,
2746
- {
2747
- variant: "outline",
2748
- disabled,
2749
- className: cn(
2750
- "w-auto justify-start text-left font-normal",
2751
- !value?.from && "text-muted-foreground",
2752
- className
2753
- )
2754
- }
2755
- ),
2756
- "aria-label": formatDateRange(),
2757
- "aria-expanded": open,
2758
- children: [
2759
- /* @__PURE__ */ jsx(CalendarIcon, { className: "size-4", "aria-hidden": "true" }),
2760
- /* @__PURE__ */ jsx("span", { children: formatDateRange() })
2761
- ]
2762
- }
2763
- ),
2764
- /* @__PURE__ */ jsxs(
2765
- PopoverContent,
2766
- {
2767
- align,
2768
- className: cn("w-auto p-0", isMobile ? "flex flex-col" : "flex"),
2769
- children: [
2770
- showPresets && /* @__PURE__ */ jsx("div", { className: cn("flex flex-col gap-1 p-3", isMobile ? "border-b" : "border-r"), children: presets.map((preset) => /* @__PURE__ */ jsx(
2771
- Button,
2772
- {
2773
- variant: "ghost",
2774
- size: "sm",
2775
- className: "justify-start text-xs",
2776
- onClick: () => handlePresetClick(preset),
2777
- children: preset.label
2778
- },
2779
- preset.label
2780
- )) }),
2781
- /* @__PURE__ */ jsx("div", { className: "p-3", children: /* @__PURE__ */ jsx(
2782
- Calendar,
2783
- {
2784
- mode: "range",
2785
- numberOfMonths: isMobile ? 1 : 2,
2786
- selected: calendarSelected,
2787
- onSelect: handleCalendarSelect,
2788
- disabled: (date) => {
2789
- if (maxDate && date > maxDate) return true;
2790
- if (minDate && date < minDate) return true;
2791
- return false;
2792
- }
2793
- }
2794
- ) })
2795
- ]
2796
- }
2797
- )
2798
- ] }) });
2799
- }
2800
- );
2801
- DateRangePicker.displayName = "DateRangePicker";
2802
- var iconSizes = {
2803
- sm: "size-3.5",
2804
- default: "size-4",
2805
- lg: "size-5"
2806
- };
2807
- var SegmentedControl = forwardRef(
2808
- function SegmentedControl2({ options, value, onChange, size = "default", fullWidth = false, ariaLabel, className }, ref) {
2809
- return /* @__PURE__ */ jsx(
2810
- ToggleGroup,
2811
- {
2812
- ref,
2813
- "data-slot": "segmented-control",
2814
- value: [value],
2815
- onValueChange: (next) => {
2816
- const picked = next.find((item) => item !== value) ?? next[0];
2817
- if (typeof picked === "string") onChange(picked);
2818
- },
2819
- variant: "outline",
2820
- size,
2821
- spacing: 0,
2822
- "aria-label": ariaLabel,
2823
- className: cn(fullWidth && "w-full", className),
2824
- children: options.map((option) => {
2825
- const Icon = option.icon;
2826
- return /* @__PURE__ */ jsxs(
2827
- ToggleGroupItem,
2828
- {
2829
- value: option.value,
2830
- disabled: option.disabled,
2831
- "aria-label": option.label,
2832
- className: cn(fullWidth && "flex-1"),
2833
- children: [
2834
- Icon && /* @__PURE__ */ jsx(Icon, { className: iconSizes[size], "aria-hidden": "true" }),
2835
- option.label
2836
- ]
2837
- },
2838
- option.value
2839
- );
2840
- })
2841
- }
2842
- );
2843
- }
2844
- );
2845
- SegmentedControl.displayName = "SegmentedControl";
2846
-
2847
- // src/components/types.ts
2848
- function isGroupedOptions(options) {
2849
- return options.length > 0 && "options" in options[0];
2850
- }
2851
- function flattenOptions(options) {
2852
- if (isGroupedOptions(options)) {
2853
- return options.flatMap((group) => group.options);
2854
- }
2855
- return options;
2856
- }
2857
- function OptionCommandList({
2858
- options,
2859
- isSelected,
2860
- onSelect,
2861
- onSearch,
2862
- isLoading,
2863
- searchPlaceholder,
2864
- emptyText
2865
- }) {
2866
- const renderOptions = (items) => items.map((option) => /* @__PURE__ */ jsxs(
2867
- CommandItem,
2868
- {
2869
- value: option.value,
2870
- keywords: [option.label],
2871
- disabled: option.disabled,
2872
- onSelect,
2873
- children: [
2874
- option.icon && /* @__PURE__ */ jsx(option.icon, { className: "size-4 shrink-0" }),
2875
- /* @__PURE__ */ jsxs("span", { className: "flex-1 truncate", children: [
2876
- option.label,
2877
- option.description && /* @__PURE__ */ jsx("span", { className: "ml-2 text-xs text-muted-foreground", children: option.description })
2878
- ] }),
2879
- /* @__PURE__ */ jsx(
2880
- CheckIcon,
2881
- {
2882
- className: cn("size-4 shrink-0", isSelected(option.value) ? "opacity-100" : "opacity-0")
2883
- }
2884
- )
2885
- ]
2886
- },
2887
- option.value
2888
- ));
2889
- return /* @__PURE__ */ jsxs(Command, { shouldFilter: !onSearch, children: [
2890
- /* @__PURE__ */ jsx(CommandInput, { placeholder: searchPlaceholder, onValueChange: onSearch }),
2891
- /* @__PURE__ */ jsx(CommandList, { children: isLoading ? /* @__PURE__ */ jsx("div", { className: "flex items-center justify-center py-6", children: /* @__PURE__ */ jsx(LoaderIcon, { className: "size-4 animate-spin text-muted-foreground" }) }) : /* @__PURE__ */ jsxs(Fragment, { children: [
2892
- /* @__PURE__ */ jsx(CommandEmpty, { children: emptyText }),
2893
- isGroupedOptions(options) ? options.map((group) => /* @__PURE__ */ jsx(CommandGroup, { heading: group.label, children: renderOptions(group.options) }, group.label)) : renderOptions(options)
2894
- ] }) })
2895
- ] });
2896
- }
2897
- function RemoveButton({ label, onRemove, iconClassName }) {
2898
- const handle = (e) => {
2899
- e.stopPropagation();
2900
- onRemove();
2901
- };
2902
- return /* @__PURE__ */ jsx(
2903
- "span",
2904
- {
2905
- role: "button",
2906
- tabIndex: 0,
2907
- "aria-label": label,
2908
- className: "rounded-sm opacity-50 hover:opacity-100 focus-visible:ring-1 focus-visible:ring-ring focus-visible:outline-none",
2909
- onClick: handle,
2910
- onKeyDown: (e) => {
2911
- if (e.key === "Enter" || e.key === " ") handle(e);
2912
- },
2913
- children: /* @__PURE__ */ jsx(XIcon, { className: cn("size-3.5", iconClassName) })
2914
- }
2915
- );
2916
- }
2917
- var SearchableSelect = forwardRef(
2918
- function SearchableSelect2({
2919
- options,
2920
- value,
2921
- onChange,
2922
- onSearch,
2923
- placeholder = "\u9078\u629E\u3057\u3066\u304F\u3060\u3055\u3044",
2924
- searchPlaceholder = "\u691C\u7D22...",
2925
- emptyText = "\u898B\u3064\u304B\u308A\u307E\u305B\u3093\u3067\u3057\u305F",
2926
- isLoading = false,
2927
- disabled = false,
2928
- clearable = true,
2929
- className
2930
- }, ref) {
2931
- const [open, setOpen] = useState(false);
2932
- const allOptions = useMemo(() => flattenOptions(options), [options]);
2933
- const selectedOption = useMemo(
2934
- () => allOptions.find((opt) => opt.value === value),
2935
- [allOptions, value]
2936
- );
2937
- function handleSelect(selectedValue) {
2938
- onChange?.(selectedValue === value ? void 0 : selectedValue);
2939
- setOpen(false);
2940
- }
2941
- return /* @__PURE__ */ jsx("div", { ref, "data-slot": "searchable-select", children: /* @__PURE__ */ jsxs(Popover, { open, onOpenChange: setOpen, children: [
2942
- /* @__PURE__ */ jsxs(
2943
- PopoverTrigger,
2944
- {
2945
- render: /* @__PURE__ */ jsx(
2946
- Button,
2947
- {
2948
- variant: "outline",
2949
- disabled,
2950
- className: cn(
2951
- "w-full justify-between font-normal",
2952
- !selectedOption && "text-muted-foreground",
2953
- className
2954
- )
2955
- }
2956
- ),
2957
- role: "combobox",
2958
- "aria-expanded": open,
2959
- children: [
2960
- /* @__PURE__ */ jsx("span", { className: "truncate", children: selectedOption ? selectedOption.label : placeholder }),
2961
- /* @__PURE__ */ jsxs("span", { className: "flex shrink-0 items-center gap-1", children: [
2962
- clearable && value && /* @__PURE__ */ jsx(RemoveButton, { label: "\u30AF\u30EA\u30A2", onRemove: () => onChange?.(void 0) }),
2963
- /* @__PURE__ */ jsx(ChevronDownIcon, { className: "size-4 opacity-50" })
2964
- ] })
2965
- ]
2966
- }
2967
- ),
2968
- /* @__PURE__ */ jsx(PopoverContent, { className: "w-(--anchor-width) p-0", align: "start", children: /* @__PURE__ */ jsx(
2969
- OptionCommandList,
2970
- {
2971
- options,
2972
- isSelected: (v) => value === v,
2973
- onSelect: handleSelect,
2974
- onSearch,
2975
- isLoading,
2976
- searchPlaceholder,
2977
- emptyText
2978
- }
2979
- ) })
2980
- ] }) });
2981
- }
2982
- );
2983
- SearchableSelect.displayName = "SearchableSelect";
2984
- var MultiSelect = forwardRef(function MultiSelect2({
2985
- options,
2986
- value,
2987
- onChange,
2988
- onSearch,
2989
- maxCount = 3,
2990
- placeholder = "\u9078\u629E\u3057\u3066\u304F\u3060\u3055\u3044",
2991
- searchPlaceholder = "\u691C\u7D22...",
2992
- emptyText = "\u898B\u3064\u304B\u308A\u307E\u305B\u3093\u3067\u3057\u305F",
2993
- isLoading = false,
2994
- disabled = false,
2995
- className
2996
- }, ref) {
2997
- const [open, setOpen] = useState(false);
2998
- const listId = useId();
2999
- const allOptions = useMemo(() => flattenOptions(options), [options]);
3000
- const selectedOptions = useMemo(
3001
- () => allOptions.filter((opt) => value.includes(opt.value)),
3002
- [allOptions, value]
3003
- );
3004
- function handleSelect(selectedValue) {
3005
- if (value.includes(selectedValue)) {
3006
- onChange?.(value.filter((v) => v !== selectedValue));
3007
- } else {
3008
- onChange?.([...value, selectedValue]);
3009
- }
3010
- }
3011
- const visibleBadges = selectedOptions.slice(0, maxCount);
3012
- const overflowCount = selectedOptions.length - maxCount;
3013
- return /* @__PURE__ */ jsx("div", { ref, "data-slot": "multi-select", children: /* @__PURE__ */ jsxs(Popover, { open, onOpenChange: setOpen, children: [
3014
- /* @__PURE__ */ jsxs(
3015
- PopoverTrigger,
3016
- {
3017
- role: "combobox",
3018
- "aria-expanded": open,
3019
- "aria-controls": listId,
3020
- disabled,
3021
- className: cn(
3022
- "inline-flex min-h-9 w-full items-center justify-between gap-2 rounded-md border bg-background px-3 py-1.5 text-sm shadow-xs transition-all outline-none hover:bg-accent hover:text-accent-foreground focus-visible:border-ring focus-visible:ring-[3px] focus-visible:ring-ring/50 disabled:pointer-events-none disabled:opacity-50 dark:border-input dark:bg-input/30 dark:hover:bg-input/50",
3023
- className
3024
- ),
3025
- children: [
3026
- /* @__PURE__ */ jsx("span", { className: "flex min-w-0 flex-1 flex-wrap items-center gap-1", children: selectedOptions.length === 0 ? /* @__PURE__ */ jsx("span", { className: "text-muted-foreground", children: placeholder }) : /* @__PURE__ */ jsxs(Fragment, { children: [
3027
- visibleBadges.map((option) => /* @__PURE__ */ jsxs(Badge, { variant: "secondary", className: "shrink-0 gap-1 pr-1", children: [
3028
- /* @__PURE__ */ jsx("span", { className: "max-w-[120px] truncate", children: option.label }),
3029
- /* @__PURE__ */ jsx(
3030
- RemoveButton,
3031
- {
3032
- label: `${option.label}\u3092\u524A\u9664`,
3033
- onRemove: () => onChange?.(value.filter((v) => v !== option.value)),
3034
- iconClassName: "size-3"
3035
- }
3036
- )
3037
- ] }, option.value)),
3038
- overflowCount > 0 && /* @__PURE__ */ jsxs(Badge, { variant: "secondary", className: "shrink-0", children: [
3039
- "+",
3040
- overflowCount,
3041
- "\u4EF6"
3042
- ] })
3043
- ] }) }),
3044
- /* @__PURE__ */ jsx(ChevronDownIcon, { className: "size-4 shrink-0 opacity-50" })
3045
- ]
3046
- }
3047
- ),
3048
- /* @__PURE__ */ jsx(PopoverContent, { id: listId, className: "w-(--anchor-width) p-0", align: "start", children: /* @__PURE__ */ jsx(
3049
- OptionCommandList,
3050
- {
3051
- options,
3052
- isSelected: (v) => value.includes(v),
3053
- onSelect: handleSelect,
3054
- onSearch,
3055
- isLoading,
3056
- searchPlaceholder,
3057
- emptyText
3058
- }
3059
- ) })
3060
- ] }) });
3061
- });
3062
- MultiSelect.displayName = "MultiSelect";
3063
- var metricValueVariants = cva("font-medium tracking-tight", {
3064
- variants: {
3065
- size: {
3066
- sm: "text-base",
3067
- md: "text-2xl",
3068
- lg: "text-3xl",
3069
- xl: "text-4xl"
3070
- }
3071
- },
3072
- defaultVariants: {
3073
- size: "md"
3074
- }
3075
- });
3076
- var MetricValue = forwardRef(
3077
- ({ className, size, ...props }, ref) => /* @__PURE__ */ jsx(
3078
- "div",
3079
- {
3080
- ref,
3081
- "data-slot": "metric-value",
3082
- className: cn("my-4", metricValueVariants({ size }), className),
3083
- ...props
3084
- }
3085
- )
3086
- );
3087
- MetricValue.displayName = "MetricValue";
3088
- var MetricUnit = forwardRef(
3089
- ({ className, ...props }, ref) => /* @__PURE__ */ jsx(
3090
- "span",
3091
- {
3092
- ref,
3093
- "data-slot": "metric-unit",
3094
- className: cn("text-sm font-normal text-muted-foreground", className),
3095
- ...props
3096
- }
3097
- )
3098
- );
3099
- MetricUnit.displayName = "MetricUnit";
3100
- var trendIndicatorVariants = cva("inline-flex items-center gap-0.5 text-sm font-medium", {
3101
- variants: {
3102
- sentiment: {
3103
- positive: "text-chart-1",
3104
- negative: "text-primary",
3105
- neutral: "text-muted-foreground"
3106
- }
3107
- },
3108
- defaultVariants: {
3109
- sentiment: "neutral"
3110
- }
3111
- });
3112
- var TrendIndicator = forwardRef(
3113
- ({ value, direction, positiveIsGood = true, className }, ref) => {
3114
- const isGood = direction === "neutral" ? null : direction === "up" === positiveIsGood;
3115
- const sentiment = isGood === null ? "neutral" : isGood ? "positive" : "negative";
3116
- const Icon = direction === "up" ? ArrowUp : direction === "down" ? ArrowDown : Minus;
3117
- const ariaLabel = direction === "neutral" ? `\u5909\u5316\u306A\u3057 ${value}%` : direction === "up" ? `${value}% \u5897\u52A0` : `${value}% \u6E1B\u5C11`;
3118
- return /* @__PURE__ */ jsxs(
3119
- "span",
3120
- {
3121
- ref,
3122
- "data-slot": "trend-indicator",
3123
- className: cn(trendIndicatorVariants({ sentiment }), className),
3124
- "aria-label": ariaLabel,
3125
- children: [
3126
- /* @__PURE__ */ jsx(Icon, { className: "size-3.5", "aria-hidden": "true" }),
3127
- /* @__PURE__ */ jsxs("span", { children: [
3128
- value,
3129
- "%"
3130
- ] })
3131
- ]
3132
- }
3133
- );
3134
- }
3135
- );
3136
- TrendIndicator.displayName = "TrendIndicator";
3137
- var defaultColorMap = {
3138
- active: "green",
3139
- inactive: "gray",
3140
- warning: "yellow",
3141
- error: "red",
3142
- pending: "blue"
3143
- };
3144
- var colorStyles = {
3145
- green: {
3146
- dot: "bg-green-500",
3147
- bg: "bg-green-50 dark:bg-green-950",
3148
- text: "text-green-700 dark:text-green-300"
3149
- },
3150
- gray: {
3151
- dot: "bg-gray-500",
3152
- bg: "bg-gray-50 dark:bg-gray-950",
3153
- text: "text-gray-700 dark:text-gray-300"
3154
- },
3155
- yellow: {
3156
- dot: "bg-yellow-500",
3157
- bg: "bg-yellow-50 dark:bg-yellow-950",
3158
- text: "text-yellow-700 dark:text-yellow-300"
3159
- },
3160
- red: {
3161
- dot: "bg-red-500",
3162
- bg: "bg-red-50 dark:bg-red-950",
3163
- text: "text-red-700 dark:text-red-300"
3164
- },
3165
- blue: {
3166
- dot: "bg-blue-500",
3167
- bg: "bg-blue-50 dark:bg-blue-950",
3168
- text: "text-blue-700 dark:text-blue-300"
3169
- }
3170
- };
3171
- var fallbackStyle = colorStyles.gray;
3172
- var StatusBadge = forwardRef(function StatusBadge2({ status, label, colorMap, className }, ref) {
3173
- const mergedColorMap = { ...defaultColorMap, ...colorMap };
3174
- const color = mergedColorMap[status] ?? "gray";
3175
- const style = colorStyles[color] ?? fallbackStyle;
3176
- const displayLabel = label ?? status;
3177
- return /* @__PURE__ */ jsxs(
3178
- Badge,
3179
- {
3180
- ref,
3181
- "data-slot": "status-badge",
3182
- variant: "outline",
3183
- className: cn("gap-1.5 border-transparent", style.bg, style.text, className),
3184
- "aria-label": displayLabel,
3185
- children: [
3186
- /* @__PURE__ */ jsx("span", { className: cn("inline-block size-2 rounded-full", style.dot), "aria-hidden": "true" }),
3187
- displayLabel
3188
- ]
3189
- }
3190
- );
3191
- });
3192
- StatusBadge.displayName = "StatusBadge";
3193
- var Placeholder = forwardRef(function Placeholder2({ className, ...props }, ref) {
3194
- return /* @__PURE__ */ jsx(
3195
- "span",
3196
- {
3197
- ref,
3198
- "data-slot": "placeholder",
3199
- className: cn("inline-block animate-pulse text-muted-foreground", className),
3200
- ...props
3201
- }
3202
- );
3203
- });
3204
- Placeholder.displayName = "Placeholder";
3205
-
3206
- export { AppShell, AreaChart, BarChart, BarList, CategoryBar, DashboardCard, DashboardCardAction, DashboardCardContent, DashboardCardDescription, DashboardCardFooter, DashboardCardHeader, DashboardCardPreset, DashboardCardSkeleton, DashboardCardTitle, DataTable, DataTableColumnVisibility, DataTableContent, DataTablePagination, DataTablePreset, DataTableToolbar, DateRangePicker, DonutChart, EChart, FilterBar, FilterBarActiveChips, FilterBarClearButton, FilterBarMultiSelect, FilterBarPreset, FilterBarSelect, FunnelSteps, LineChart, MetricUnit, MetricValue, MultiSelect, PageShell, PageShellActions, PageShellContent, PageShellDescription, PageShellHeader, PageShellHeaderEnd, PageShellHeading, PageShellMeta, PageShellSummary, PageShellSummaryCard, PageShellTitle, Placeholder, ProgressCircle, SearchableSelect, SectionHeader, SegmentedControl, Sparkline, StatusBadge, Tracker, TrendIndicator, defaultPresets, flattenOptions, funnelStepsVariants, isGroupedOptions, metricValueVariants, pageShellSummaryCardVariants, useDataTable };
3207
- //# sourceMappingURL=chunk-AG6RZ2RR.js.map
3208
- //# sourceMappingURL=chunk-AG6RZ2RR.js.map