@squadbase/vantage 0.6.2-dev1.42c4e48 → 0.6.2-dev1.51e401a
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/dist/{build-MFWRPYKW.js → build-U7GO26HR.js} +7 -7
- package/dist/{build-MFWRPYKW.js.map → build-U7GO26HR.js.map} +1 -1
- package/dist/{check-ZBIH422T.js → check-MRVAIHG5.js} +5 -5
- package/dist/{check-ZBIH422T.js.map → check-MRVAIHG5.js.map} +1 -1
- package/dist/chunk-2IAPIOPS.js +152 -0
- package/dist/chunk-2IAPIOPS.js.map +1 -0
- package/dist/chunk-3RJEOP3J.js +174 -0
- package/dist/chunk-3RJEOP3J.js.map +1 -0
- package/dist/chunk-77CISBMG.js +7581 -0
- package/dist/chunk-77CISBMG.js.map +1 -0
- package/dist/{chunk-V3LF7BE7.js → chunk-ANZLVSEP.js} +4 -5
- package/dist/chunk-ANZLVSEP.js.map +1 -0
- package/dist/{chunk-XQUSGIDG.js → chunk-CKWPK4RO.js} +10 -3
- package/dist/chunk-CKWPK4RO.js.map +1 -0
- package/dist/chunk-EG4PX726.js +678 -0
- package/dist/chunk-EG4PX726.js.map +1 -0
- package/dist/chunk-NZ5QIIG4.js +74 -0
- package/dist/chunk-NZ5QIIG4.js.map +1 -0
- package/dist/{chunk-7DZGJQ3P.js → chunk-PJ4SPXHS.js} +23 -6
- package/dist/chunk-PJ4SPXHS.js.map +1 -0
- package/dist/{chunk-OB6UBJXF.js → chunk-QNOX7WLZ.js} +127 -36
- package/dist/chunk-QNOX7WLZ.js.map +1 -0
- package/dist/{chunk-PXRX5PEC.js → chunk-ROHNXP7J.js} +73 -4
- package/dist/chunk-ROHNXP7J.js.map +1 -0
- package/dist/{chunk-CEXAQQ5W.js → chunk-S5MDTHH7.js} +180 -18
- package/dist/chunk-S5MDTHH7.js.map +1 -0
- package/dist/{chunk-IBGOCWJB.js → chunk-SDJTTMLK.js} +247 -86
- package/dist/chunk-SDJTTMLK.js.map +1 -0
- package/dist/{chunk-QEWCYW3I.js → chunk-SHZM3EXB.js} +29 -8
- package/dist/chunk-SHZM3EXB.js.map +1 -0
- package/dist/chunk-TRMHNMMZ.js +61 -0
- package/dist/chunk-TRMHNMMZ.js.map +1 -0
- package/dist/{chunk-A2UUGASH.js → chunk-U736PVHY.js} +2 -2
- package/dist/chunk-U736PVHY.js.map +1 -0
- package/dist/{chunk-JKLLFVEU.js → chunk-UWSQUHX6.js} +4 -99
- package/dist/chunk-UWSQUHX6.js.map +1 -0
- package/dist/cli.js +6 -6
- package/dist/client/index.d.ts +2 -0
- package/dist/client/index.js +8 -2
- package/dist/client/index.js.map +1 -1
- package/dist/components/index.d.ts +1617 -101
- package/dist/components/index.js +7 -4
- package/dist/delta-text-CbrOaW83.d.ts +17 -0
- package/dist/{dev-DCTOHQ6W.js → dev-O42JFQ64.js} +7 -7
- package/dist/{dev-DCTOHQ6W.js.map → dev-O42JFQ64.js.map} +1 -1
- package/dist/doc/index.d.ts +215 -2
- package/dist/doc/index.js +423 -5
- package/dist/doc/index.js.map +1 -1
- package/dist/{doctor-5E2VEZPK.js → doctor-YD3XAAOT.js} +5 -5
- package/dist/{doctor-5E2VEZPK.js.map → doctor-YD3XAAOT.js.map} +1 -1
- package/dist/format-DihQkL1N.d.ts +249 -0
- package/dist/markdown/index.js +1 -1
- package/dist/markdown/index.js.map +1 -1
- package/dist/query/index.js +2 -2
- package/dist/{routes-3SGAFDMC.js → routes-PVKNT777.js} +4 -4
- package/dist/{routes-3SGAFDMC.js.map → routes-PVKNT777.js.map} +1 -1
- package/dist/slide/index.d.ts +272 -1
- package/dist/slide/index.js +1025 -4
- package/dist/slide/index.js.map +1 -1
- package/dist/table/index.js +11 -8
- package/dist/table/index.js.map +1 -1
- package/dist/ui/index.d.ts +8 -2
- package/dist/ui/index.js +22 -112
- package/dist/ui/index.js.map +1 -1
- package/dist/{upgrade-DBBE6GIR.js → upgrade-6DT7ADRP.js} +4 -4
- package/dist/{upgrade-DBBE6GIR.js.map → upgrade-6DT7ADRP.js.map} +1 -1
- package/dist/vite/index.js +3 -3
- package/docs/en/agent-skills.md +1 -1
- package/docs/en/changelog.md +2 -0
- package/docs/en/components.md +42 -17
- package/docs/en/doc/delta-text.md +40 -0
- package/docs/en/doc/doc-action-items.md +49 -0
- package/docs/en/doc/doc-callout.md +38 -0
- package/docs/en/doc/doc-data-table.md +60 -0
- package/docs/en/doc/doc-executive-summary.md +64 -0
- package/docs/en/doc/doc-figure.md +56 -0
- package/docs/en/doc/doc-key-findings.md +61 -0
- package/docs/en/doc/doc-kpi-scorecard.md +80 -0
- package/docs/en/doc/doc-notes-and-sources.md +43 -0
- package/docs/en/doc/doc-report-header.md +46 -0
- package/docs/en/pages-and-metadata.md +15 -0
- package/docs/en/parts/area-chart.md +99 -0
- package/docs/en/parts/bar-chart.md +91 -0
- package/docs/en/parts/bar-list.md +50 -0
- package/docs/en/parts/category-bar.md +37 -0
- package/docs/en/parts/chart-frame.md +39 -0
- package/docs/en/parts/data-table.md +22 -0
- package/docs/en/parts/delta.md +51 -0
- package/docs/en/parts/donut-chart.md +72 -0
- package/docs/en/parts/format.md +43 -0
- package/docs/en/parts/funnel-steps.md +2 -1
- package/docs/en/parts/heatmap.md +53 -0
- package/docs/en/parts/kpi-card.md +58 -0
- package/docs/en/parts/legend.md +35 -0
- package/docs/en/parts/line-chart.md +94 -0
- package/docs/en/parts/metric-value.md +3 -2
- package/docs/en/parts/progress-circle.md +33 -0
- package/docs/en/parts/sample-data.md +39 -0
- package/docs/en/parts/scatter-chart.md +56 -0
- package/docs/en/parts/sparkline.md +1 -1
- package/docs/en/parts/tracker.md +36 -0
- package/docs/en/parts/trend-indicator.md +17 -1
- package/docs/en/parts/updated-at.md +30 -0
- package/docs/en/parts/waterfall-chart.md +56 -0
- package/docs/en/slide/slide-chart-full.md +48 -0
- package/docs/en/slide/slide-chart-insight.md +52 -0
- package/docs/en/slide/slide-columns.md +46 -0
- package/docs/en/slide/slide-comparison.md +68 -0
- package/docs/en/slide/slide-cover.md +39 -0
- package/docs/en/slide/slide-exec-summary.md +47 -0
- package/docs/en/slide/slide-heading.md +38 -0
- package/docs/en/slide/slide-kpi-grid.md +55 -0
- package/docs/en/slide/slide-kpi-hero.md +58 -0
- package/docs/en/slide/slide-next-actions.md +49 -0
- package/docs/en/slide/slide-scorecard-table.md +54 -0
- package/docs/en/slide/slide-section.md +44 -0
- package/docs/en/slide/slide-source-line.md +34 -0
- package/docs/en/ui/alert-dialog.md +42 -0
- package/docs/en/ui/avatar.md +31 -0
- package/docs/en/ui/combobox.md +74 -0
- package/docs/en/ui/drawer.md +41 -0
- package/docs/en/ui/empty.md +1 -1
- package/docs/en/ui/error-state.md +4 -3
- package/docs/en/ui/field.md +42 -0
- package/docs/en/ui/hover-card.md +21 -0
- package/docs/en/ui/kbd.md +17 -0
- package/docs/en/ui/loading.md +1 -1
- package/docs/en/ui/pagination.md +36 -0
- package/docs/en/ui/radio-group.md +21 -0
- package/docs/en/ui/toast.md +44 -0
- package/docs/en/ui/toggle-group.md +4 -3
- package/docs/en/ui-and-theming.md +1 -1
- package/docs/index.json +917 -77
- package/docs/ja/agent-skills.md +1 -1
- package/docs/ja/changelog.md +2 -0
- package/docs/ja/components.md +39 -16
- package/docs/ja/doc/delta-text.md +40 -0
- package/docs/ja/doc/doc-action-items.md +49 -0
- package/docs/ja/doc/doc-callout.md +38 -0
- package/docs/ja/doc/doc-data-table.md +60 -0
- package/docs/ja/doc/doc-executive-summary.md +64 -0
- package/docs/ja/doc/doc-figure.md +56 -0
- package/docs/ja/doc/doc-key-findings.md +61 -0
- package/docs/ja/doc/doc-kpi-scorecard.md +80 -0
- package/docs/ja/doc/doc-notes-and-sources.md +43 -0
- package/docs/ja/doc/doc-report-header.md +46 -0
- package/docs/ja/page-types/slide.md +1 -0
- package/docs/ja/pages-and-metadata.md +15 -0
- package/docs/ja/parts/area-chart.md +49 -25
- package/docs/ja/parts/bar-chart.md +50 -24
- package/docs/ja/parts/bar-list.md +31 -8
- package/docs/ja/parts/chart-frame.md +36 -0
- package/docs/ja/parts/data-table.md +22 -0
- package/docs/ja/parts/delta.md +51 -0
- package/docs/ja/parts/donut-chart.md +45 -26
- package/docs/ja/parts/format.md +44 -0
- package/docs/ja/parts/funnel-steps.md +27 -8
- package/docs/ja/parts/heatmap.md +45 -0
- package/docs/ja/parts/kpi-card.md +56 -0
- package/docs/ja/parts/legend.md +36 -0
- package/docs/ja/parts/line-chart.md +48 -22
- package/docs/ja/parts/metric-value.md +3 -2
- package/docs/ja/parts/sample-data.md +61 -0
- package/docs/ja/parts/scatter-chart.md +69 -0
- package/docs/ja/parts/sparkline.md +1 -1
- package/docs/ja/parts/trend-indicator.md +17 -1
- package/docs/ja/parts/updated-at.md +27 -0
- package/docs/ja/parts/waterfall-chart.md +61 -0
- package/docs/ja/slide/slide-chart-full.md +48 -0
- package/docs/ja/slide/slide-chart-insight.md +52 -0
- package/docs/ja/slide/slide-columns.md +46 -0
- package/docs/ja/slide/slide-comparison.md +68 -0
- package/docs/ja/slide/slide-cover.md +39 -0
- package/docs/ja/slide/slide-exec-summary.md +47 -0
- package/docs/ja/slide/slide-heading.md +38 -0
- package/docs/ja/slide/slide-kpi-grid.md +55 -0
- package/docs/ja/slide/slide-kpi-hero.md +58 -0
- package/docs/ja/slide/slide-next-actions.md +49 -0
- package/docs/ja/slide/slide-scorecard-table.md +54 -0
- package/docs/ja/slide/slide-section.md +44 -0
- package/docs/ja/slide/slide-source-line.md +34 -0
- package/docs/ja/ui/empty.md +1 -1
- package/docs/ja/ui/error-state.md +4 -3
- package/docs/ja/ui/loading.md +1 -1
- package/docs/ja/ui/toggle-group.md +4 -3
- package/docs/ja/ui-and-theming.md +2 -2
- package/package.json +26 -24
- package/registry/ui/accordion.tsx +4 -2
- package/registry/ui/alert-dialog.tsx +3 -3
- package/registry/ui/alert.tsx +3 -1
- package/registry/ui/app-shell.tsx +145 -2
- package/registry/ui/area-chart.tsx +3111 -166
- package/registry/ui/attention-list.tsx +465 -0
- package/registry/ui/avatar.tsx +1 -1
- package/registry/ui/badge.tsx +3 -1
- package/registry/ui/bar-chart.tsx +3105 -164
- package/registry/ui/bar-list.tsx +3877 -181
- package/registry/ui/box-plot-chart.tsx +4214 -0
- package/registry/ui/breadcrumb.tsx +3 -1
- package/registry/ui/button.tsx +3 -1
- package/registry/ui/calendar.tsx +3 -1
- package/registry/ui/card.tsx +4 -2
- package/registry/ui/category-bar.tsx +1233 -16
- package/registry/ui/chart-frame.tsx +1604 -0
- package/registry/ui/checkbox.tsx +3 -1
- package/registry/ui/collapsible.tsx +3 -1
- package/registry/ui/combobox.tsx +2 -2
- package/registry/ui/command.tsx +3 -1
- package/registry/ui/dashboard-card.tsx +71 -28
- package/registry/ui/data-table.tsx +882 -68
- package/registry/ui/date-range-picker.tsx +400 -65
- package/registry/ui/delta.tsx +350 -0
- package/registry/ui/dialog.tsx +5 -3
- package/registry/ui/donut-chart.tsx +3184 -182
- package/registry/ui/drawer.tsx +1 -1
- package/registry/ui/dropdown-menu.tsx +5 -3
- package/registry/ui/echart.tsx +761 -69
- package/registry/ui/field.tsx +1 -1
- package/registry/ui/filter-bar.tsx +212 -26
- package/registry/ui/funnel-steps.tsx +3622 -53
- package/registry/ui/heatmap.tsx +2027 -0
- package/registry/ui/histogram-chart.tsx +4284 -0
- package/registry/ui/hover-card.tsx +2 -2
- package/registry/ui/input-group.tsx +3 -1
- package/registry/ui/input.tsx +3 -1
- package/registry/ui/kbd.tsx +3 -1
- package/registry/ui/kpi-card.tsx +905 -0
- package/registry/ui/label.tsx +3 -1
- package/registry/ui/legend.tsx +3817 -0
- package/registry/ui/line-chart.tsx +3109 -158
- package/registry/ui/metric-value.tsx +9 -1
- package/registry/ui/multi-select.tsx +170 -14
- package/registry/ui/page-shell.tsx +244 -51
- package/registry/ui/pagination.tsx +3 -1
- package/registry/ui/paired-chart.tsx +4086 -0
- package/registry/ui/placeholder.tsx +8 -2
- package/registry/ui/popover.tsx +4 -2
- package/registry/ui/progress-circle.tsx +773 -12
- package/registry/ui/progress.tsx +3 -1
- package/registry/ui/radio-group.tsx +1 -1
- package/registry/ui/sample-data.tsx +230 -0
- package/registry/ui/scatter-chart.tsx +4503 -0
- package/registry/ui/scroll-area.tsx +3 -2
- package/registry/ui/searchable-select.tsx +153 -10
- package/registry/ui/section-header.tsx +5 -3
- package/registry/ui/segmented-control.tsx +7 -2
- package/registry/ui/select.tsx +4 -2
- package/registry/ui/separator.tsx +3 -1
- package/registry/ui/sheet.tsx +4 -2
- package/registry/ui/sidebar.tsx +4 -2
- package/registry/ui/skeleton.tsx +4 -2
- package/registry/ui/slider.tsx +4 -2
- package/registry/ui/sparkline.tsx +84 -9
- package/registry/ui/spinner.tsx +3 -1
- package/registry/ui/states.tsx +194 -8
- package/registry/ui/status-badge.tsx +246 -39
- package/registry/ui/switch.tsx +3 -1
- package/registry/ui/table.tsx +4 -2
- package/registry/ui/tabs.tsx +5 -3
- package/registry/ui/textarea.tsx +3 -1
- package/registry/ui/toast.tsx +2 -2
- package/registry/ui/toggle-group.tsx +3 -1
- package/registry/ui/toggle.tsx +3 -1
- package/registry/ui/tooltip.tsx +10 -4
- package/registry/ui/tracker.tsx +798 -19
- package/registry/ui/trend-indicator.tsx +164 -9
- package/registry/ui/updated-at.tsx +276 -0
- package/registry/ui/waterfall-chart.tsx +4561 -0
- package/skills/vantage-add-feature/SKILL.md +5 -0
- package/skills/vantage-design/SKILL.md +60 -52
- package/skills/vantage-design/references/extract.md +26 -27
- package/skills/vantage-design/references/format.md +12 -172
- package/skills/vantage-design/references/presets.md +50 -110
- package/skills/vantage-pitfalls/SKILL.md +5 -0
- package/skills/vantage-slide/SKILL.md +54 -36
- package/templates/AGENTS.md +45 -16
- package/templates/agents/api.md +7 -0
- package/templates/agents/doc.md +48 -0
- package/templates/agents/page.md +69 -2
- package/templates/agents/slide.md +77 -3
- package/theme.css +247 -149
- package/dist/chunk-5ZOP4SQR.js +0 -47
- package/dist/chunk-5ZOP4SQR.js.map +0 -1
- package/dist/chunk-7DZGJQ3P.js.map +0 -1
- package/dist/chunk-A2UUGASH.js.map +0 -1
- package/dist/chunk-AG6RZ2RR.js +0 -3208
- package/dist/chunk-AG6RZ2RR.js.map +0 -1
- package/dist/chunk-CEXAQQ5W.js.map +0 -1
- package/dist/chunk-IBGOCWJB.js.map +0 -1
- package/dist/chunk-JKLLFVEU.js.map +0 -1
- package/dist/chunk-OB6UBJXF.js.map +0 -1
- package/dist/chunk-PXRX5PEC.js.map +0 -1
- package/dist/chunk-QEWCYW3I.js.map +0 -1
- package/dist/chunk-V3LF7BE7.js.map +0 -1
- package/dist/chunk-XQUSGIDG.js.map +0 -1
|
@@ -1,98 +1,403 @@
|
|
|
1
1
|
// Copied by `vantage add ui date-range-picker`. This file is yours to edit.
|
|
2
|
-
// Generated from @squadbase/
|
|
2
|
+
// Generated from @squadbase/squadkit registry/components/date-range-picker.tsx by `pnpm run registry` (in Vantage, edit packages/squadkit, not registry/).
|
|
3
|
+
"use client"
|
|
4
|
+
|
|
3
5
|
/**
|
|
4
6
|
* DateRangePicker — a range calendar in a popover with quick presets down the
|
|
5
7
|
* side. On mobile the presets stack above a single month; on desktop they sit
|
|
6
|
-
* beside a two-month view.
|
|
8
|
+
* beside a two-month view. The labels, the date format, the fiscal year start and the
|
|
9
|
+
* first day of the week follow the page (`<html lang>`) unless `locale` is given.
|
|
7
10
|
*/
|
|
8
|
-
import { forwardRef, useCallback, useState } from "react"
|
|
11
|
+
import { forwardRef, useCallback, useMemo, useState } from "react"
|
|
9
12
|
import { CalendarIcon } from "lucide-react"
|
|
10
|
-
import {
|
|
13
|
+
import {
|
|
14
|
+
addMonths,
|
|
15
|
+
endOfDay,
|
|
16
|
+
endOfMonth,
|
|
17
|
+
endOfWeek,
|
|
18
|
+
isSameDay,
|
|
19
|
+
startOfDay,
|
|
20
|
+
startOfMonth,
|
|
21
|
+
startOfWeek,
|
|
22
|
+
subDays,
|
|
23
|
+
subMonths,
|
|
24
|
+
subWeeks,
|
|
25
|
+
} from "date-fns"
|
|
11
26
|
import { ja } from "date-fns/locale"
|
|
12
27
|
import type { DateRange as RdpDateRange } from "react-day-picker"
|
|
13
28
|
|
|
14
29
|
import { cn } from "@squadbase/vantage/ui"
|
|
15
30
|
import { useIsMobile } from "@squadbase/vantage/ui"
|
|
31
|
+
import { formatDate } from "@squadbase/vantage/components"
|
|
16
32
|
import { Button } from "@squadbase/vantage/ui"
|
|
17
33
|
import { Calendar } from "@squadbase/vantage/ui"
|
|
18
34
|
import { Popover, PopoverContent, PopoverTrigger } from "@squadbase/vantage/ui"
|
|
19
35
|
import type { DateRange, PresetItem } from "@squadbase/vantage/components"
|
|
36
|
+
import { useSyncExternalStore } from "react"
|
|
20
37
|
|
|
21
|
-
|
|
22
|
-
|
|
23
|
-
|
|
24
|
-
|
|
25
|
-
|
|
26
|
-
|
|
27
|
-
|
|
28
|
-
|
|
38
|
+
/* ---------- inlined from @squadbase/squadkit registry/lib/locale.ts (internal to @squadbase/vantage) ---------- */
|
|
39
|
+
|
|
40
|
+
/**
|
|
41
|
+
* The display language of the parts and the defaults that follow it.
|
|
42
|
+
*
|
|
43
|
+
* The language comes from `<html lang>`: a tag starting with `ja` reads Japanese, anything else English.
|
|
44
|
+
* Without a usable `lang` (missing, invalid, or no `document` — SSR, Node) the locale is `FALLBACK_LOCALE`
|
|
45
|
+
* (`en-US`). A `locale` passed explicitly (a prop, an argument) always wins.
|
|
46
|
+
*
|
|
47
|
+
* Parts read the locale through `useLocale` (`hooks/use-locale`) and pass it down; the pure helpers here
|
|
48
|
+
* and in `format` / `comparison` / `chart-*` take it as an argument and fall back to `documentLocale()`.
|
|
49
|
+
*/
|
|
50
|
+
|
|
51
|
+
/** The language of the built-in wording: Japanese or English. */
|
|
52
|
+
type UiLanguage = "ja" | "en"
|
|
53
|
+
|
|
54
|
+
/** The locale used when `<html lang>` gives none (and on the server). */
|
|
55
|
+
const FALLBACK_LOCALE = "en-US"
|
|
56
|
+
|
|
57
|
+
/** `"ja"` when `locale` starts with `ja` (`ja`, `ja-JP`), else `"en"`. A missing locale is `"en"`. */
|
|
58
|
+
function uiLanguage(locale: string | null | undefined): UiLanguage {
|
|
59
|
+
return typeof locale === "string" && locale.trim().toLowerCase().startsWith("ja") ? "ja" : "en"
|
|
60
|
+
}
|
|
61
|
+
|
|
62
|
+
/** A BCP 47 tag in its canonical form (`en-gb` → `en-GB`), or `FALLBACK_LOCALE` when it is empty or invalid. */
|
|
63
|
+
function normalizeLocale(tag: string | null | undefined): string {
|
|
64
|
+
const value = tag?.trim()
|
|
65
|
+
if (!value) return FALLBACK_LOCALE
|
|
66
|
+
try {
|
|
67
|
+
return Intl.getCanonicalLocales(value)[0] ?? FALLBACK_LOCALE
|
|
68
|
+
} catch {
|
|
69
|
+
return FALLBACK_LOCALE
|
|
70
|
+
}
|
|
71
|
+
}
|
|
72
|
+
|
|
73
|
+
/**
|
|
74
|
+
* The locale of the page: `document.documentElement.lang`, canonicalized. `FALLBACK_LOCALE` when it is empty or
|
|
75
|
+
* invalid, or there is no `document`. Parts read it through `useLocale`, never while rendering.
|
|
76
|
+
*/
|
|
77
|
+
function documentLocale(): string {
|
|
78
|
+
if (typeof document === "undefined") return FALLBACK_LOCALE
|
|
79
|
+
return normalizeLocale(document.documentElement?.getAttribute("lang"))
|
|
80
|
+
}
|
|
81
|
+
|
|
82
|
+
/** `locale` when given, else the page's locale (`documentLocale()`). */
|
|
83
|
+
function resolveLocale(locale?: string | null): string {
|
|
84
|
+
return locale || documentLocale()
|
|
85
|
+
}
|
|
86
|
+
|
|
87
|
+
/** Picks the wording table of the locale's language. */
|
|
88
|
+
function pickLocale<T>(table: { ja: T; en: T }, locale?: string | null): T {
|
|
89
|
+
return table[uiLanguage(resolveLocale(locale))]
|
|
90
|
+
}
|
|
91
|
+
|
|
92
|
+
/** The currency `format="currency"` uses without a `currency`: JPY for Japanese, USD otherwise. */
|
|
93
|
+
function defaultCurrency(locale?: string | null): string {
|
|
94
|
+
return uiLanguage(resolveLocale(locale)) === "ja" ? "JPY" : "USD"
|
|
95
|
+
}
|
|
96
|
+
|
|
97
|
+
/** The month a fiscal year starts in (1–12) when none is given: April for Japanese, January otherwise. */
|
|
98
|
+
function defaultFiscalYearStartMonth(locale?: string | null): number {
|
|
99
|
+
return uiLanguage(resolveLocale(locale)) === "ja" ? 4 : 1
|
|
100
|
+
}
|
|
101
|
+
|
|
102
|
+
/** A day of the week, 0 = Sunday … 6 = Saturday (the `Date#getDay` / date-fns numbering). */
|
|
103
|
+
type WeekDay = 0 | 1 | 2 | 3 | 4 | 5 | 6
|
|
104
|
+
|
|
105
|
+
/** Locales whose week starts on Sunday when the runtime has no week data. */
|
|
106
|
+
const SUNDAY_FIRST = new Set(["en", "en-US", "en-CA"])
|
|
107
|
+
|
|
108
|
+
/**
|
|
109
|
+
* The first day of the week: Monday for Japanese; otherwise the locale's convention from `Intl.Locale`
|
|
110
|
+
* (`en-US` Sunday, `en-GB` Monday). Without week data in the runtime: Sunday for `en` / `en-US` / `en-CA`,
|
|
111
|
+
* Monday for the rest.
|
|
112
|
+
*/
|
|
113
|
+
function weekStartsOn(locale?: string | null): WeekDay {
|
|
114
|
+
const tag = normalizeLocale(resolveLocale(locale))
|
|
115
|
+
if (uiLanguage(tag) === "ja") return 1
|
|
116
|
+
try {
|
|
117
|
+
const info = new Intl.Locale(tag) as Intl.Locale & {
|
|
118
|
+
getWeekInfo?: () => { firstDay: number }
|
|
119
|
+
weekInfo?: { firstDay: number }
|
|
120
|
+
}
|
|
121
|
+
const firstDay = info.getWeekInfo?.().firstDay ?? info.weekInfo?.firstDay
|
|
122
|
+
if (typeof firstDay === "number" && firstDay >= 1 && firstDay <= 7) return (firstDay % 7) as WeekDay
|
|
123
|
+
} catch {
|
|
124
|
+
// Fall through to the table below.
|
|
125
|
+
}
|
|
126
|
+
return SUNDAY_FIRST.has(tag) ? 0 : 1
|
|
127
|
+
}
|
|
128
|
+
|
|
129
|
+
/* ---------- inlined from @squadbase/squadkit registry/hooks/use-locale.ts (internal to @squadbase/vantage) ---------- */
|
|
130
|
+
|
|
131
|
+
const listeners = new Set<() => void>()
|
|
132
|
+
let observer: MutationObserver | null = null
|
|
133
|
+
|
|
134
|
+
/** One observer on `<html lang>` for every subscribed part. */
|
|
135
|
+
function subscribe(onChange: () => void): () => void {
|
|
136
|
+
if (typeof document === "undefined" || typeof MutationObserver === "undefined") return () => {}
|
|
137
|
+
listeners.add(onChange)
|
|
138
|
+
if (!observer) {
|
|
139
|
+
observer = new MutationObserver(() => {
|
|
140
|
+
for (const listener of [...listeners]) listener()
|
|
141
|
+
})
|
|
142
|
+
observer.observe(document.documentElement, { attributes: true, attributeFilter: ["lang"] })
|
|
143
|
+
}
|
|
144
|
+
return () => {
|
|
145
|
+
listeners.delete(onChange)
|
|
146
|
+
if (listeners.size === 0 && observer) {
|
|
147
|
+
observer.disconnect()
|
|
148
|
+
observer = null
|
|
149
|
+
}
|
|
150
|
+
}
|
|
151
|
+
}
|
|
152
|
+
|
|
153
|
+
const serverLocale = () => FALLBACK_LOCALE
|
|
154
|
+
|
|
155
|
+
/**
|
|
156
|
+
* The page's locale (`<html lang>`), following changes made while the page runs. On the server and during
|
|
157
|
+
* hydration it is `FALLBACK_LOCALE` (`en-US`), so the markup matches; it switches right after.
|
|
158
|
+
*/
|
|
159
|
+
function useDocumentLocale(): string {
|
|
160
|
+
return useSyncExternalStore(subscribe, documentLocale, serverLocale)
|
|
161
|
+
}
|
|
162
|
+
|
|
163
|
+
/** The locale a part renders in: its `locale` prop when given, else the page's (`useDocumentLocale`). */
|
|
164
|
+
function useLocale(locale?: string | null): string {
|
|
165
|
+
const page = useDocumentLocale()
|
|
166
|
+
return locale || page
|
|
167
|
+
}
|
|
168
|
+
|
|
169
|
+
/* ---------- end of inlined code ---------- */
|
|
170
|
+
|
|
171
|
+
/**
|
|
172
|
+
* 会計年度の開始月のフォールバック(1 月始まり)。ロケールから決まる既定は `defaultFiscalYearStartMonth`
|
|
173
|
+
* (`<html lang>` が ja なら 4 月、それ以外は 1 月)。
|
|
174
|
+
*/
|
|
175
|
+
export const DEFAULT_FISCAL_YEAR_START_MONTH = 1
|
|
176
|
+
|
|
177
|
+
/** ラベルの言語のフォールバック(英語)。`locale` を渡さなければ、ほかの部品と同じくページの `<html lang>` に従う。 */
|
|
178
|
+
export const DEFAULT_DATE_PICKER_LOCALE = FALLBACK_LOCALE
|
|
179
|
+
|
|
180
|
+
/**
|
|
181
|
+
* 1〜12 の整数だけを開始月として受け、それ以外は `locale` の既定(ja は 4 月、それ以外は 1 月)に戻す。
|
|
182
|
+
* `locale` の既定はページのロケール(`<html lang>`)。
|
|
183
|
+
*/
|
|
184
|
+
export function normalizeFiscalYearStartMonth(month: number | undefined, locale?: string): number {
|
|
185
|
+
return typeof month === "number" && Number.isInteger(month) && month >= 1 && month <= 12
|
|
186
|
+
? month
|
|
187
|
+
: defaultFiscalYearStartMonth(locale)
|
|
188
|
+
}
|
|
189
|
+
|
|
190
|
+
/**
|
|
191
|
+
* `date` を含む年度(または年度基準の四半期)の全期間。`offset` で前後にずらす(`-1` が前の年度/四半期)。
|
|
192
|
+
* 年度は `fiscalYearStartMonth`(1-12)の 1 日に始まり 12 か月続く。四半期は年度の初日から 3 か月ごと。
|
|
193
|
+
* `fiscalYearStartMonth` を省くと `locale`(既定はページのロケール)の既定(ja は 4 月、それ以外は 1 月)。
|
|
194
|
+
*
|
|
195
|
+
* @example
|
|
196
|
+
* // 4 月始まりで 2026-02-10 は 2025 年度(2025-04-01〜2026-03-31)
|
|
197
|
+
* fiscalPeriodRange(new Date(2026, 1, 10), { unit: "year", fiscalYearStartMonth: 4 })
|
|
198
|
+
*/
|
|
199
|
+
export function fiscalPeriodRange(
|
|
200
|
+
date: Date,
|
|
29
201
|
{
|
|
30
|
-
|
|
31
|
-
|
|
32
|
-
|
|
33
|
-
|
|
34
|
-
|
|
202
|
+
unit,
|
|
203
|
+
fiscalYearStartMonth,
|
|
204
|
+
offset = 0,
|
|
205
|
+
locale,
|
|
206
|
+
}: { unit: "year" | "quarter"; fiscalYearStartMonth?: number; offset?: number; locale?: string },
|
|
207
|
+
): { from: Date; to: Date } {
|
|
208
|
+
const startMonth = normalizeFiscalYearStartMonth(fiscalYearStartMonth, locale)
|
|
209
|
+
const length = unit === "year" ? 12 : 3
|
|
210
|
+
const sinceYearStart = (date.getMonth() - (startMonth - 1) + 12) % 12
|
|
211
|
+
const into = unit === "year" ? sinceYearStart : sinceYearStart % 3
|
|
212
|
+
const periodStart = addMonths(startOfMonth(subMonths(date, into)), offset * length)
|
|
213
|
+
return { from: periodStart, to: endOfMonth(addMonths(periodStart, length - 1)) }
|
|
214
|
+
}
|
|
215
|
+
|
|
216
|
+
const PRESET_LABELS = {
|
|
217
|
+
ja: {
|
|
218
|
+
today: "今日",
|
|
219
|
+
yesterday: "昨日",
|
|
220
|
+
last7: "過去 7 日間",
|
|
221
|
+
last14: "過去 14 日間",
|
|
222
|
+
last28: "過去 28 日間",
|
|
223
|
+
last30: "過去 30 日間",
|
|
224
|
+
last90: "過去 90 日間",
|
|
225
|
+
thisWeek: "今週",
|
|
226
|
+
lastWeek: "先週",
|
|
227
|
+
thisMonth: "今月",
|
|
228
|
+
lastMonth: "先月",
|
|
229
|
+
thisQuarter: "今四半期",
|
|
230
|
+
lastQuarter: "前四半期",
|
|
231
|
+
thisFiscalYear: "今年度",
|
|
232
|
+
lastFiscalYear: "前年度",
|
|
35
233
|
},
|
|
36
|
-
{
|
|
37
|
-
|
|
38
|
-
|
|
39
|
-
|
|
40
|
-
|
|
41
|
-
|
|
234
|
+
en: {
|
|
235
|
+
today: "Today",
|
|
236
|
+
yesterday: "Yesterday",
|
|
237
|
+
last7: "Last 7 days",
|
|
238
|
+
last14: "Last 14 days",
|
|
239
|
+
last28: "Last 28 days",
|
|
240
|
+
last30: "Last 30 days",
|
|
241
|
+
last90: "Last 90 days",
|
|
242
|
+
thisWeek: "This week",
|
|
243
|
+
lastWeek: "Last week",
|
|
244
|
+
thisMonth: "This month",
|
|
245
|
+
lastMonth: "Last month",
|
|
246
|
+
thisQuarter: "This quarter",
|
|
247
|
+
lastQuarter: "Last quarter",
|
|
248
|
+
thisFiscalYear: "This fiscal year",
|
|
249
|
+
lastFiscalYear: "Last fiscal year",
|
|
42
250
|
},
|
|
43
|
-
|
|
44
|
-
|
|
45
|
-
|
|
46
|
-
|
|
47
|
-
|
|
251
|
+
} as const
|
|
252
|
+
|
|
253
|
+
const TEXT = {
|
|
254
|
+
ja: { placeholder: "期間を選択", rangeSeparator: " - " },
|
|
255
|
+
en: { placeholder: "Pick a date range", rangeSeparator: " – " },
|
|
256
|
+
}
|
|
257
|
+
|
|
258
|
+
/** カレンダーに渡す date-fns の locale。`ja*` なら日本語、それ以外は react-day-picker の既定(英語)。 */
|
|
259
|
+
const calendarLocale = (locale: string) => (uiLanguage(locale) === "ja" ? ja : undefined)
|
|
260
|
+
|
|
261
|
+
/**
|
|
262
|
+
* 既定のプリセット一覧を作る。ラベルは `locale`(`ja*` なら日本語、それ以外は英語)、
|
|
263
|
+
* 「今四半期」「前四半期」「今年度」「前年度」は `fiscalYearStartMonth`(省くと ja は 4 月、それ以外は 1 月)を基準にする。
|
|
264
|
+
* 「今〜」は期の初日から今日まで、「前〜」「先月」「先週」は前の期の全期間。週の始まりは `locale` の慣習
|
|
265
|
+
* (ja は月曜、`en-US` は日曜、`en-GB` は月曜。`weekStartsOn`)。`getValue` は押した時点の日付で計算する。
|
|
266
|
+
* `locale` の既定はページのロケール(`<html lang>`、無ければ `"en-US"`)。
|
|
267
|
+
*
|
|
268
|
+
* @example
|
|
269
|
+
* createDatePresets({ locale: "ja-JP", fiscalYearStartMonth: 4 })
|
|
270
|
+
*/
|
|
271
|
+
export function createDatePresets({
|
|
272
|
+
locale: localeArg,
|
|
273
|
+
fiscalYearStartMonth,
|
|
274
|
+
now = () => new Date(),
|
|
275
|
+
}: { locale?: string; fiscalYearStartMonth?: number; now?: () => Date } = {}): PresetItem[] {
|
|
276
|
+
const locale = resolveLocale(localeArg)
|
|
277
|
+
const t = PRESET_LABELS[uiLanguage(locale)]
|
|
278
|
+
const startMonth = normalizeFiscalYearStartMonth(fiscalYearStartMonth, locale)
|
|
279
|
+
const WEEK_OPTIONS = { weekStartsOn: weekStartsOn(locale) }
|
|
280
|
+
const lastDays = (days: number) => () => {
|
|
281
|
+
const today = now()
|
|
282
|
+
return { from: startOfDay(subDays(today, days - 1)), to: endOfDay(today) }
|
|
283
|
+
}
|
|
284
|
+
const toDate = (unit: "year" | "quarter") => () => {
|
|
285
|
+
const today = now()
|
|
286
|
+
return {
|
|
287
|
+
from: fiscalPeriodRange(today, { unit, fiscalYearStartMonth: startMonth }).from,
|
|
288
|
+
to: endOfDay(today),
|
|
289
|
+
}
|
|
290
|
+
}
|
|
291
|
+
const previous = (unit: "year" | "quarter") => () =>
|
|
292
|
+
fiscalPeriodRange(now(), { unit, fiscalYearStartMonth: startMonth, offset: -1 })
|
|
293
|
+
return [
|
|
294
|
+
{ label: t.today, getValue: lastDays(1) },
|
|
295
|
+
{
|
|
296
|
+
label: t.yesterday,
|
|
297
|
+
getValue: () => {
|
|
298
|
+
const yesterday = subDays(now(), 1)
|
|
299
|
+
return { from: startOfDay(yesterday), to: endOfDay(yesterday) }
|
|
300
|
+
},
|
|
48
301
|
},
|
|
49
|
-
|
|
50
|
-
|
|
51
|
-
label:
|
|
52
|
-
getValue: ()
|
|
53
|
-
|
|
54
|
-
|
|
302
|
+
{ label: t.last7, getValue: lastDays(7) },
|
|
303
|
+
{ label: t.last14, getValue: lastDays(14) },
|
|
304
|
+
{ label: t.last28, getValue: lastDays(28) },
|
|
305
|
+
{ label: t.last30, getValue: lastDays(30) },
|
|
306
|
+
{ label: t.last90, getValue: lastDays(90) },
|
|
307
|
+
{
|
|
308
|
+
label: t.thisWeek,
|
|
309
|
+
getValue: () => {
|
|
310
|
+
const today = now()
|
|
311
|
+
return { from: startOfWeek(today, WEEK_OPTIONS), to: endOfDay(today) }
|
|
312
|
+
},
|
|
55
313
|
},
|
|
56
|
-
|
|
57
|
-
|
|
58
|
-
|
|
59
|
-
|
|
60
|
-
|
|
61
|
-
|
|
314
|
+
{
|
|
315
|
+
label: t.lastWeek,
|
|
316
|
+
getValue: () => {
|
|
317
|
+
const lastWeek = subWeeks(now(), 1)
|
|
318
|
+
return { from: startOfWeek(lastWeek, WEEK_OPTIONS), to: endOfWeek(lastWeek, WEEK_OPTIONS) }
|
|
319
|
+
},
|
|
62
320
|
},
|
|
63
|
-
|
|
64
|
-
|
|
65
|
-
|
|
66
|
-
|
|
67
|
-
|
|
68
|
-
|
|
321
|
+
{
|
|
322
|
+
label: t.thisMonth,
|
|
323
|
+
getValue: () => {
|
|
324
|
+
const today = now()
|
|
325
|
+
return { from: startOfMonth(today), to: endOfDay(today) }
|
|
326
|
+
},
|
|
69
327
|
},
|
|
70
|
-
|
|
71
|
-
|
|
72
|
-
|
|
73
|
-
|
|
74
|
-
|
|
75
|
-
|
|
328
|
+
{
|
|
329
|
+
label: t.lastMonth,
|
|
330
|
+
getValue: () => {
|
|
331
|
+
const lastMonth = subMonths(now(), 1)
|
|
332
|
+
return { from: startOfMonth(lastMonth), to: endOfMonth(lastMonth) }
|
|
333
|
+
},
|
|
76
334
|
},
|
|
77
|
-
|
|
78
|
-
|
|
335
|
+
{ label: t.thisQuarter, getValue: toDate("quarter") },
|
|
336
|
+
{ label: t.lastQuarter, getValue: previous("quarter") },
|
|
337
|
+
{ label: t.thisFiscalYear, getValue: toDate("year") },
|
|
338
|
+
{ label: t.lastFiscalYear, getValue: previous("year") },
|
|
339
|
+
]
|
|
340
|
+
}
|
|
341
|
+
|
|
342
|
+
/**
|
|
343
|
+
* `value` と日単位で同じ範囲を返す最初のプリセットを探す(無ければ `undefined`)。`getValue` は呼んだ時点の日付で計算される。
|
|
344
|
+
* 「今日」と「今週」が月曜に重なるときなど、複数が一致したら並びの早いほうを返す。
|
|
345
|
+
*/
|
|
346
|
+
export function findMatchingPreset(presets: PresetItem[], value: DateRange | undefined): PresetItem | undefined {
|
|
347
|
+
const { from, to } = value ?? {}
|
|
348
|
+
if (!from || !to) return undefined
|
|
349
|
+
return presets.find((preset) => {
|
|
350
|
+
const range = preset.getValue()
|
|
351
|
+
return range.from != null && range.to != null && isSameDay(range.from, from) && isSameDay(range.to, to)
|
|
352
|
+
})
|
|
353
|
+
}
|
|
354
|
+
|
|
355
|
+
/**
|
|
356
|
+
* フォールバック(`en-US`:英語・1 月始まり・日曜始まり)のプリセット。DateRangePicker は `presets` を渡さなければ
|
|
357
|
+
* ページのロケールからプリセットを作るので、これを渡す必要はない。`locale` / `fiscalYearStartMonth` を変えるなら
|
|
358
|
+
* `createDatePresets` か DateRangePicker の同名 props。
|
|
359
|
+
*/
|
|
360
|
+
export const defaultPresets: PresetItem[] = createDatePresets({ locale: FALLBACK_LOCALE })
|
|
79
361
|
|
|
80
362
|
export interface DateRangePickerProps {
|
|
81
363
|
/**
|
|
82
|
-
*
|
|
364
|
+
* 選択中の日付範囲。型はこの部品独自の `DateRange`。
|
|
83
365
|
* react-day-picker の `DateRange` とは別物なので注意 — そちらが必要なら
|
|
84
366
|
* このファイルの末尾で re-export している `RdpDateRange` を使う。
|
|
85
367
|
*
|
|
86
368
|
* @example
|
|
87
|
-
* import type
|
|
369
|
+
* import { DateRangePicker, type DateRange } from "@/components/date-range-picker"
|
|
370
|
+
* // Vantage: import { DateRangePicker, type DateRange } from "@squadbase/vantage/components"
|
|
88
371
|
*
|
|
89
372
|
* const [range, setRange] = useState<DateRange | undefined>()
|
|
90
373
|
* <DateRangePicker value={range} onChange={setRange} />
|
|
91
374
|
*/
|
|
92
375
|
value?: DateRange
|
|
93
376
|
onChange?: (range: DateRange) => void
|
|
377
|
+
/**
|
|
378
|
+
* ショートカットの一覧。指定すると `locale` / `fiscalYearStartMonth` による既定の一覧の代わりに使う。
|
|
379
|
+
*
|
|
380
|
+
* @example
|
|
381
|
+
* presets={[{ label: "直近 10 日", getValue: () => ({ from: subDays(new Date(), 9), to: new Date() }) }]}
|
|
382
|
+
*/
|
|
94
383
|
presets?: PresetItem[]
|
|
95
384
|
showPresets?: boolean
|
|
385
|
+
/**
|
|
386
|
+
* プリセットのラベル・日付の書式・カレンダーの月名と曜日・週の始まりのロケール。`ja*` なら日本語、それ以外は英語。
|
|
387
|
+
* 既定はページのロケール(`<html lang>`、無ければ `"en-US"`)。
|
|
388
|
+
*
|
|
389
|
+
* @example
|
|
390
|
+
* <DateRangePicker locale="ja-JP" />
|
|
391
|
+
*/
|
|
392
|
+
locale?: string
|
|
393
|
+
/**
|
|
394
|
+
* 年度の開始月(1-12)。「今年度」「前年度」と、年度基準の「今四半期」「前四半期」の区切りになる。
|
|
395
|
+
* 既定はロケールで決まる(ja は `4`、それ以外は `1`)。範囲外・整数でない値はその既定として扱う。
|
|
396
|
+
*
|
|
397
|
+
* @example
|
|
398
|
+
* <DateRangePicker fiscalYearStartMonth={1} />
|
|
399
|
+
*/
|
|
400
|
+
fiscalYearStartMonth?: number
|
|
96
401
|
maxDate?: Date
|
|
97
402
|
minDate?: Date
|
|
98
403
|
placeholder?: string
|
|
@@ -106,11 +411,13 @@ export const DateRangePicker = forwardRef<HTMLDivElement, DateRangePickerProps>(
|
|
|
106
411
|
{
|
|
107
412
|
value,
|
|
108
413
|
onChange,
|
|
109
|
-
presets
|
|
414
|
+
presets: presetsProp,
|
|
110
415
|
showPresets = true,
|
|
416
|
+
locale: localeProp,
|
|
417
|
+
fiscalYearStartMonth,
|
|
111
418
|
maxDate,
|
|
112
419
|
minDate,
|
|
113
|
-
placeholder
|
|
420
|
+
placeholder,
|
|
114
421
|
disabled = false,
|
|
115
422
|
className,
|
|
116
423
|
align = "start",
|
|
@@ -119,6 +426,12 @@ export const DateRangePicker = forwardRef<HTMLDivElement, DateRangePickerProps>(
|
|
|
119
426
|
) {
|
|
120
427
|
const [open, setOpen] = useState(false)
|
|
121
428
|
const isMobile = useIsMobile()
|
|
429
|
+
const locale = useLocale(localeProp)
|
|
430
|
+
const t = TEXT[uiLanguage(locale)]
|
|
431
|
+
const presets = useMemo(
|
|
432
|
+
() => presetsProp ?? createDatePresets({ locale, fiscalYearStartMonth }),
|
|
433
|
+
[presetsProp, locale, fiscalYearStartMonth],
|
|
434
|
+
)
|
|
122
435
|
|
|
123
436
|
const handleCalendarSelect = useCallback(
|
|
124
437
|
(range: RdpDateRange | undefined) => {
|
|
@@ -136,10 +449,17 @@ export const DateRangePicker = forwardRef<HTMLDivElement, DateRangePickerProps>(
|
|
|
136
449
|
)
|
|
137
450
|
|
|
138
451
|
const formatDateRange = () => {
|
|
139
|
-
if (!value?.from) return placeholder
|
|
140
|
-
if (!value.to) return
|
|
141
|
-
return `${
|
|
452
|
+
if (!value?.from) return placeholder ?? t.placeholder
|
|
453
|
+
if (!value.to) return formatDate(value.from, "date", locale)
|
|
454
|
+
return `${formatDate(value.from, "date", locale)}${t.rangeSeparator}${formatDate(value.to, "date", locale)}`
|
|
142
455
|
}
|
|
456
|
+
// 選んだ期間がプリセットの結果と一致するときは、日付の前にそのプリセット名を出す。
|
|
457
|
+
const selectedPreset = findMatchingPreset(presets, value)
|
|
458
|
+
const presetLabel = selectedPreset?.label
|
|
459
|
+
|
|
460
|
+
// 開いたとき、右の月が終了月・左がその前月になるよう、表示月(左の月)を決める。1 か月表示(モバイル)は終了月。
|
|
461
|
+
const endMonth = value?.to ?? value?.from
|
|
462
|
+
const defaultMonth = endMonth ? (isMobile ? endMonth : subMonths(endMonth, 1)) : undefined
|
|
143
463
|
|
|
144
464
|
const calendarSelected: RdpDateRange | undefined = value?.from
|
|
145
465
|
? { from: value.from, to: value.to ?? undefined }
|
|
@@ -160,15 +480,22 @@ export const DateRangePicker = forwardRef<HTMLDivElement, DateRangePickerProps>(
|
|
|
160
480
|
)}
|
|
161
481
|
/>
|
|
162
482
|
}
|
|
163
|
-
aria-label={formatDateRange()}
|
|
483
|
+
aria-label={presetLabel ? `${presetLabel} ${formatDateRange()}` : formatDateRange()}
|
|
164
484
|
aria-expanded={open}
|
|
165
485
|
>
|
|
166
486
|
<CalendarIcon className="size-4" aria-hidden="true" />
|
|
167
|
-
|
|
487
|
+
{presetLabel ? (
|
|
488
|
+
<>
|
|
489
|
+
<span>{presetLabel}</span>
|
|
490
|
+
<span className="text-muted-foreground">{formatDateRange()}</span>
|
|
491
|
+
</>
|
|
492
|
+
) : (
|
|
493
|
+
<span>{formatDateRange()}</span>
|
|
494
|
+
)}
|
|
168
495
|
</PopoverTrigger>
|
|
169
496
|
<PopoverContent
|
|
170
497
|
align={align}
|
|
171
|
-
className={cn("w-auto p-0", isMobile ? "flex
|
|
498
|
+
className={cn("w-auto gap-0 p-0", isMobile ? "flex-col" : "flex-row")}
|
|
172
499
|
>
|
|
173
500
|
{showPresets && (
|
|
174
501
|
<div className={cn("flex flex-col gap-1 p-3", isMobile ? "border-b" : "border-r")}>
|
|
@@ -177,7 +504,11 @@ export const DateRangePicker = forwardRef<HTMLDivElement, DateRangePickerProps>(
|
|
|
177
504
|
key={preset.label}
|
|
178
505
|
variant="ghost"
|
|
179
506
|
size="sm"
|
|
180
|
-
|
|
507
|
+
aria-pressed={selectedPreset === preset}
|
|
508
|
+
className={cn(
|
|
509
|
+
"justify-start text-xs",
|
|
510
|
+
selectedPreset === preset && "bg-primary/10 text-primary hover:bg-primary/15 hover:text-primary",
|
|
511
|
+
)}
|
|
181
512
|
onClick={() => handlePresetClick(preset)}
|
|
182
513
|
>
|
|
183
514
|
{preset.label}
|
|
@@ -187,7 +518,11 @@ export const DateRangePicker = forwardRef<HTMLDivElement, DateRangePickerProps>(
|
|
|
187
518
|
)}
|
|
188
519
|
<div className="p-3">
|
|
189
520
|
<Calendar
|
|
521
|
+
key={`${open}-${isMobile}`}
|
|
190
522
|
mode="range"
|
|
523
|
+
defaultMonth={defaultMonth}
|
|
524
|
+
locale={calendarLocale(locale)}
|
|
525
|
+
weekStartsOn={weekStartsOn(locale)}
|
|
191
526
|
numberOfMonths={isMobile ? 1 : 2}
|
|
192
527
|
selected={calendarSelected}
|
|
193
528
|
onSelect={handleCalendarSelect}
|