@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
package/registry/ui/field.tsx
CHANGED
|
@@ -1,5 +1,5 @@
|
|
|
1
1
|
// Copied by `vantage add ui field`. This file is yours to edit.
|
|
2
|
-
// Generated from @squadbase/
|
|
2
|
+
// Generated from @squadbase/squadkit registry/ui/field.tsx by `pnpm run registry` (in Vantage, edit packages/squadkit, not registry/).
|
|
3
3
|
"use client"
|
|
4
4
|
|
|
5
5
|
import { useMemo } from "react"
|
|
@@ -1,5 +1,7 @@
|
|
|
1
1
|
// Copied by `vantage add ui filter-bar`. This file is yours to edit.
|
|
2
|
-
// Generated from @squadbase/
|
|
2
|
+
// Generated from @squadbase/squadkit registry/components/filter-bar.tsx by `pnpm run registry` (in Vantage, edit packages/squadkit, not registry/).
|
|
3
|
+
"use client"
|
|
4
|
+
|
|
3
5
|
/**
|
|
4
6
|
* FilterBar — a compound filter row. `<FilterBar>` holds the (always
|
|
5
7
|
* controlled) filter values on context; the select, multi-select, active-chip
|
|
@@ -22,6 +24,140 @@ import { Checkbox } from "@squadbase/vantage/ui"
|
|
|
22
24
|
import { Popover, PopoverContent, PopoverTrigger } from "@squadbase/vantage/ui"
|
|
23
25
|
import { Select, SelectContent, SelectItem, SelectTrigger, SelectValue } from "@squadbase/vantage/ui"
|
|
24
26
|
import type { FilterConfig, FilterOption, FilterValues } from "@squadbase/vantage/components"
|
|
27
|
+
import { useSyncExternalStore } from "react"
|
|
28
|
+
|
|
29
|
+
/* ---------- inlined from @squadbase/squadkit registry/lib/locale.ts (internal to @squadbase/vantage) ---------- */
|
|
30
|
+
|
|
31
|
+
/**
|
|
32
|
+
* The display language of the parts and the defaults that follow it.
|
|
33
|
+
*
|
|
34
|
+
* The language comes from `<html lang>`: a tag starting with `ja` reads Japanese, anything else English.
|
|
35
|
+
* Without a usable `lang` (missing, invalid, or no `document` — SSR, Node) the locale is `FALLBACK_LOCALE`
|
|
36
|
+
* (`en-US`). A `locale` passed explicitly (a prop, an argument) always wins.
|
|
37
|
+
*
|
|
38
|
+
* Parts read the locale through `useLocale` (`hooks/use-locale`) and pass it down; the pure helpers here
|
|
39
|
+
* and in `format` / `comparison` / `chart-*` take it as an argument and fall back to `documentLocale()`.
|
|
40
|
+
*/
|
|
41
|
+
|
|
42
|
+
/** The language of the built-in wording: Japanese or English. */
|
|
43
|
+
type UiLanguage = "ja" | "en"
|
|
44
|
+
|
|
45
|
+
/** The locale used when `<html lang>` gives none (and on the server). */
|
|
46
|
+
const FALLBACK_LOCALE = "en-US"
|
|
47
|
+
|
|
48
|
+
/** `"ja"` when `locale` starts with `ja` (`ja`, `ja-JP`), else `"en"`. A missing locale is `"en"`. */
|
|
49
|
+
function uiLanguage(locale: string | null | undefined): UiLanguage {
|
|
50
|
+
return typeof locale === "string" && locale.trim().toLowerCase().startsWith("ja") ? "ja" : "en"
|
|
51
|
+
}
|
|
52
|
+
|
|
53
|
+
/** A BCP 47 tag in its canonical form (`en-gb` → `en-GB`), or `FALLBACK_LOCALE` when it is empty or invalid. */
|
|
54
|
+
function normalizeLocale(tag: string | null | undefined): string {
|
|
55
|
+
const value = tag?.trim()
|
|
56
|
+
if (!value) return FALLBACK_LOCALE
|
|
57
|
+
try {
|
|
58
|
+
return Intl.getCanonicalLocales(value)[0] ?? FALLBACK_LOCALE
|
|
59
|
+
} catch {
|
|
60
|
+
return FALLBACK_LOCALE
|
|
61
|
+
}
|
|
62
|
+
}
|
|
63
|
+
|
|
64
|
+
/**
|
|
65
|
+
* The locale of the page: `document.documentElement.lang`, canonicalized. `FALLBACK_LOCALE` when it is empty or
|
|
66
|
+
* invalid, or there is no `document`. Parts read it through `useLocale`, never while rendering.
|
|
67
|
+
*/
|
|
68
|
+
function documentLocale(): string {
|
|
69
|
+
if (typeof document === "undefined") return FALLBACK_LOCALE
|
|
70
|
+
return normalizeLocale(document.documentElement?.getAttribute("lang"))
|
|
71
|
+
}
|
|
72
|
+
|
|
73
|
+
/** `locale` when given, else the page's locale (`documentLocale()`). */
|
|
74
|
+
function resolveLocale(locale?: string | null): string {
|
|
75
|
+
return locale || documentLocale()
|
|
76
|
+
}
|
|
77
|
+
|
|
78
|
+
/** Picks the wording table of the locale's language. */
|
|
79
|
+
function pickLocale<T>(table: { ja: T; en: T }, locale?: string | null): T {
|
|
80
|
+
return table[uiLanguage(resolveLocale(locale))]
|
|
81
|
+
}
|
|
82
|
+
|
|
83
|
+
/** The currency `format="currency"` uses without a `currency`: JPY for Japanese, USD otherwise. */
|
|
84
|
+
function defaultCurrency(locale?: string | null): string {
|
|
85
|
+
return uiLanguage(resolveLocale(locale)) === "ja" ? "JPY" : "USD"
|
|
86
|
+
}
|
|
87
|
+
|
|
88
|
+
/** The month a fiscal year starts in (1–12) when none is given: April for Japanese, January otherwise. */
|
|
89
|
+
function defaultFiscalYearStartMonth(locale?: string | null): number {
|
|
90
|
+
return uiLanguage(resolveLocale(locale)) === "ja" ? 4 : 1
|
|
91
|
+
}
|
|
92
|
+
|
|
93
|
+
/** A day of the week, 0 = Sunday … 6 = Saturday (the `Date#getDay` / date-fns numbering). */
|
|
94
|
+
type WeekDay = 0 | 1 | 2 | 3 | 4 | 5 | 6
|
|
95
|
+
|
|
96
|
+
/** Locales whose week starts on Sunday when the runtime has no week data. */
|
|
97
|
+
const SUNDAY_FIRST = new Set(["en", "en-US", "en-CA"])
|
|
98
|
+
|
|
99
|
+
/**
|
|
100
|
+
* The first day of the week: Monday for Japanese; otherwise the locale's convention from `Intl.Locale`
|
|
101
|
+
* (`en-US` Sunday, `en-GB` Monday). Without week data in the runtime: Sunday for `en` / `en-US` / `en-CA`,
|
|
102
|
+
* Monday for the rest.
|
|
103
|
+
*/
|
|
104
|
+
function weekStartsOn(locale?: string | null): WeekDay {
|
|
105
|
+
const tag = normalizeLocale(resolveLocale(locale))
|
|
106
|
+
if (uiLanguage(tag) === "ja") return 1
|
|
107
|
+
try {
|
|
108
|
+
const info = new Intl.Locale(tag) as Intl.Locale & {
|
|
109
|
+
getWeekInfo?: () => { firstDay: number }
|
|
110
|
+
weekInfo?: { firstDay: number }
|
|
111
|
+
}
|
|
112
|
+
const firstDay = info.getWeekInfo?.().firstDay ?? info.weekInfo?.firstDay
|
|
113
|
+
if (typeof firstDay === "number" && firstDay >= 1 && firstDay <= 7) return (firstDay % 7) as WeekDay
|
|
114
|
+
} catch {
|
|
115
|
+
// Fall through to the table below.
|
|
116
|
+
}
|
|
117
|
+
return SUNDAY_FIRST.has(tag) ? 0 : 1
|
|
118
|
+
}
|
|
119
|
+
|
|
120
|
+
/* ---------- inlined from @squadbase/squadkit registry/hooks/use-locale.ts (internal to @squadbase/vantage) ---------- */
|
|
121
|
+
|
|
122
|
+
const listeners = new Set<() => void>()
|
|
123
|
+
let observer: MutationObserver | null = null
|
|
124
|
+
|
|
125
|
+
/** One observer on `<html lang>` for every subscribed part. */
|
|
126
|
+
function subscribe(onChange: () => void): () => void {
|
|
127
|
+
if (typeof document === "undefined" || typeof MutationObserver === "undefined") return () => {}
|
|
128
|
+
listeners.add(onChange)
|
|
129
|
+
if (!observer) {
|
|
130
|
+
observer = new MutationObserver(() => {
|
|
131
|
+
for (const listener of [...listeners]) listener()
|
|
132
|
+
})
|
|
133
|
+
observer.observe(document.documentElement, { attributes: true, attributeFilter: ["lang"] })
|
|
134
|
+
}
|
|
135
|
+
return () => {
|
|
136
|
+
listeners.delete(onChange)
|
|
137
|
+
if (listeners.size === 0 && observer) {
|
|
138
|
+
observer.disconnect()
|
|
139
|
+
observer = null
|
|
140
|
+
}
|
|
141
|
+
}
|
|
142
|
+
}
|
|
143
|
+
|
|
144
|
+
const serverLocale = () => FALLBACK_LOCALE
|
|
145
|
+
|
|
146
|
+
/**
|
|
147
|
+
* The page's locale (`<html lang>`), following changes made while the page runs. On the server and during
|
|
148
|
+
* hydration it is `FALLBACK_LOCALE` (`en-US`), so the markup matches; it switches right after.
|
|
149
|
+
*/
|
|
150
|
+
function useDocumentLocale(): string {
|
|
151
|
+
return useSyncExternalStore(subscribe, documentLocale, serverLocale)
|
|
152
|
+
}
|
|
153
|
+
|
|
154
|
+
/** The locale a part renders in: its `locale` prop when given, else the page's (`useDocumentLocale`). */
|
|
155
|
+
function useLocale(locale?: string | null): string {
|
|
156
|
+
const page = useDocumentLocale()
|
|
157
|
+
return locale || page
|
|
158
|
+
}
|
|
159
|
+
|
|
160
|
+
/* ---------- end of inlined code ---------- */
|
|
25
161
|
|
|
26
162
|
/* --------------------------------------------------------------- context */
|
|
27
163
|
|
|
@@ -36,6 +172,25 @@ interface FilterBarContextValue {
|
|
|
36
172
|
|
|
37
173
|
const FilterBarContext = createContext<FilterBarContextValue | null>(null)
|
|
38
174
|
|
|
175
|
+
const TEXT = {
|
|
176
|
+
ja: {
|
|
177
|
+
filters: "フィルター",
|
|
178
|
+
selected: (count: number) => ` (${count}件選択中)`,
|
|
179
|
+
remove: (filter: string, option: string) => `${filter}: ${option} を削除`,
|
|
180
|
+
clear: "クリア",
|
|
181
|
+
clearAll: "すべてのフィルターをクリア",
|
|
182
|
+
},
|
|
183
|
+
en: {
|
|
184
|
+
filters: "Filters",
|
|
185
|
+
selected: (count: number) => ` (${count} selected)`,
|
|
186
|
+
remove: (filter: string, option: string) => `Remove ${filter}: ${option}`,
|
|
187
|
+
clear: "Clear",
|
|
188
|
+
clearAll: "Clear all filters",
|
|
189
|
+
},
|
|
190
|
+
}
|
|
191
|
+
|
|
192
|
+
const useText = () => TEXT[uiLanguage(useLocale())]
|
|
193
|
+
|
|
39
194
|
function useFilterBar(): FilterBarContextValue {
|
|
40
195
|
const ctx = useContext(FilterBarContext)
|
|
41
196
|
if (!ctx) throw new Error("useFilterBar must be used within <FilterBar>")
|
|
@@ -53,20 +208,23 @@ export interface FilterBarProps extends Omit<HTMLAttributes<HTMLDivElement>, "on
|
|
|
53
208
|
}
|
|
54
209
|
|
|
55
210
|
export const FilterBar = forwardRef<HTMLDivElement, FilterBarProps>(
|
|
56
|
-
({ value, onChange, onClear, className, children, ...props }, ref) =>
|
|
57
|
-
|
|
58
|
-
|
|
59
|
-
|
|
60
|
-
|
|
61
|
-
|
|
62
|
-
|
|
63
|
-
|
|
64
|
-
|
|
65
|
-
|
|
66
|
-
|
|
67
|
-
|
|
68
|
-
|
|
69
|
-
|
|
211
|
+
({ value, onChange, onClear, className, children, ...props }, ref) => {
|
|
212
|
+
const t = useText()
|
|
213
|
+
return (
|
|
214
|
+
<FilterBarContext.Provider value={{ value, onChange, onClear }}>
|
|
215
|
+
<div
|
|
216
|
+
ref={ref}
|
|
217
|
+
role="search"
|
|
218
|
+
aria-label={t.filters}
|
|
219
|
+
data-slot="filter-bar"
|
|
220
|
+
className={cn("flex flex-wrap items-center gap-2", className)}
|
|
221
|
+
{...props}
|
|
222
|
+
>
|
|
223
|
+
{children}
|
|
224
|
+
</div>
|
|
225
|
+
</FilterBarContext.Provider>
|
|
226
|
+
)
|
|
227
|
+
},
|
|
70
228
|
)
|
|
71
229
|
FilterBar.displayName = "FilterBar"
|
|
72
230
|
|
|
@@ -77,29 +235,49 @@ export interface FilterBarSelectProps {
|
|
|
77
235
|
label: string
|
|
78
236
|
options: FilterOption[]
|
|
79
237
|
placeholder?: string
|
|
238
|
+
/**
|
|
239
|
+
* 渡すと、選択肢の先頭に「絞り込まない」項目をこの文言で足す(例: `"すべて"`)。選ぶとこのキーを値から外す(`undefined`)ので、
|
|
240
|
+
* アクティブチップにも出ない。絞り込んでいないときのトリガーは `placeholder`(既定は `label`)のまま。既定は足さない。
|
|
241
|
+
* @example allLabel="すべて"
|
|
242
|
+
*/
|
|
243
|
+
allLabel?: string
|
|
80
244
|
className?: string
|
|
81
245
|
}
|
|
82
246
|
|
|
247
|
+
/** 「すべて」項目の値。実際の選択肢の値と衝突しない内部用の印で、`onChange` には渡らない。 */
|
|
248
|
+
const ALL_VALUE = "__squadkit_all__"
|
|
249
|
+
|
|
83
250
|
export function FilterBarSelect({
|
|
84
251
|
filterKey,
|
|
85
252
|
label,
|
|
86
253
|
options,
|
|
87
254
|
placeholder,
|
|
255
|
+
allLabel,
|
|
88
256
|
className,
|
|
89
257
|
}: FilterBarSelectProps) {
|
|
90
258
|
const { value, onChange } = useFilterBar()
|
|
259
|
+
const hasAll = allLabel !== undefined
|
|
260
|
+
const items = hasAll ? [{ value: ALL_VALUE, label: allLabel }, ...options] : options
|
|
261
|
+
const current = value[filterKey] as string | undefined
|
|
91
262
|
|
|
92
263
|
// Base UI reports `null` when the selection is cleared — drop the key so
|
|
93
|
-
// "no filter" reads as absent rather than as an empty string.
|
|
264
|
+
// "no filter" reads as absent rather than as an empty string. "すべて" does the same.
|
|
94
265
|
const handleChange = (selected: string | null) =>
|
|
95
|
-
onChange({ ...value, [filterKey]: selected
|
|
266
|
+
onChange({ ...value, [filterKey]: selected === null || selected === ALL_VALUE ? undefined : selected })
|
|
96
267
|
|
|
97
268
|
return (
|
|
98
|
-
<Select
|
|
269
|
+
<Select
|
|
270
|
+
// FilterOption is already `{ value, label }` — Base UI uses it to show the
|
|
271
|
+
// label (not the raw value) in the trigger.
|
|
272
|
+
items={items}
|
|
273
|
+
value={current ?? ""}
|
|
274
|
+
onValueChange={handleChange}
|
|
275
|
+
>
|
|
99
276
|
<SelectTrigger size="sm" aria-label={label} data-slot="filter-bar-select" className={className}>
|
|
100
277
|
<SelectValue placeholder={placeholder ?? label} />
|
|
101
278
|
</SelectTrigger>
|
|
102
279
|
<SelectContent>
|
|
280
|
+
{hasAll && <SelectItem value={ALL_VALUE}>{allLabel}</SelectItem>}
|
|
103
281
|
{options.map((option) => (
|
|
104
282
|
<SelectItem key={option.value} value={option.value} disabled={option.disabled}>
|
|
105
283
|
{option.label}
|
|
@@ -129,6 +307,7 @@ export function FilterBarMultiSelect({
|
|
|
129
307
|
className,
|
|
130
308
|
}: FilterBarMultiSelectProps) {
|
|
131
309
|
const { value, onChange } = useFilterBar()
|
|
310
|
+
const t = useText()
|
|
132
311
|
const selected = (value[filterKey] as string[] | undefined) ?? []
|
|
133
312
|
|
|
134
313
|
const handleToggle = (option: string) => {
|
|
@@ -143,7 +322,7 @@ export function FilterBarMultiSelect({
|
|
|
143
322
|
<Popover>
|
|
144
323
|
<PopoverTrigger
|
|
145
324
|
render={<Button variant="outline" size="sm" className={cn("h-8 gap-1", className)} />}
|
|
146
|
-
aria-label={`${placeholder ?? label}${selected.length > 0 ?
|
|
325
|
+
aria-label={`${placeholder ?? label}${selected.length > 0 ? t.selected(selected.length) : ""}`}
|
|
147
326
|
data-slot="filter-bar-multi-select"
|
|
148
327
|
>
|
|
149
328
|
{placeholder ?? label}
|
|
@@ -194,6 +373,7 @@ interface ActiveChip {
|
|
|
194
373
|
|
|
195
374
|
export function FilterBarActiveChips({ filters, className }: FilterBarActiveChipsProps) {
|
|
196
375
|
const { value, onChange } = useFilterBar()
|
|
376
|
+
const t = useText()
|
|
197
377
|
|
|
198
378
|
const getActiveChips = (): ActiveChip[] => {
|
|
199
379
|
const chips: ActiveChip[] = []
|
|
@@ -271,7 +451,7 @@ export function FilterBarActiveChips({ filters, className }: FilterBarActiveChip
|
|
|
271
451
|
type="button"
|
|
272
452
|
className="ml-0.5 rounded-full p-0.5 hover:bg-muted-foreground/20"
|
|
273
453
|
onClick={() => handleRemoveFilter(chip.key, chip.optionValue)}
|
|
274
|
-
aria-label={
|
|
454
|
+
aria-label={t.remove(chip.filterLabel, chip.optionLabel)}
|
|
275
455
|
>
|
|
276
456
|
<X className="size-3" aria-hidden="true" />
|
|
277
457
|
</button>
|
|
@@ -285,13 +465,14 @@ FilterBarActiveChips.displayName = "FilterBarActiveChips"
|
|
|
285
465
|
/* ----------------------------------------------------------- clear button */
|
|
286
466
|
|
|
287
467
|
export interface FilterBarClearButtonProps {
|
|
288
|
-
/** Override the button label. Defaults to "クリア". */
|
|
468
|
+
/** Override the button label. Defaults to "Clear" (ja: "クリア"). */
|
|
289
469
|
label?: string
|
|
290
470
|
className?: string
|
|
291
471
|
}
|
|
292
472
|
|
|
293
|
-
export function FilterBarClearButton({ label
|
|
473
|
+
export function FilterBarClearButton({ label, className }: FilterBarClearButtonProps) {
|
|
294
474
|
const { value, onClear } = useFilterBar()
|
|
475
|
+
const t = useText()
|
|
295
476
|
const hasActiveFilters = Object.values(value).some((v) =>
|
|
296
477
|
Array.isArray(v) ? v.length > 0 : v !== undefined && v !== "",
|
|
297
478
|
)
|
|
@@ -303,10 +484,10 @@ export function FilterBarClearButton({ label = "クリア", className }: FilterB
|
|
|
303
484
|
size="sm"
|
|
304
485
|
className={cn("h-7 px-2 text-xs", className)}
|
|
305
486
|
onClick={onClear}
|
|
306
|
-
aria-label=
|
|
487
|
+
aria-label={t.clearAll}
|
|
307
488
|
data-slot="filter-bar-clear-button"
|
|
308
489
|
>
|
|
309
|
-
{label}
|
|
490
|
+
{label ?? t.clear}
|
|
310
491
|
</Button>
|
|
311
492
|
)
|
|
312
493
|
}
|
|
@@ -322,10 +503,14 @@ export interface FilterBarPresetProps {
|
|
|
322
503
|
className?: string
|
|
323
504
|
}
|
|
324
505
|
|
|
506
|
+
/** Not given yet (a draft fills props in steps): render empty, keep the same value between renders. */
|
|
507
|
+
const NO_FILTERS: never[] = []
|
|
508
|
+
const NO_FILTER_VALUES: FilterValues = {}
|
|
509
|
+
|
|
325
510
|
/** The whole row built from a `FilterConfig[]`. */
|
|
326
511
|
export function FilterBarPreset({
|
|
327
|
-
filters,
|
|
328
|
-
value,
|
|
512
|
+
filters = NO_FILTERS,
|
|
513
|
+
value = NO_FILTER_VALUES,
|
|
329
514
|
onChange,
|
|
330
515
|
onClear,
|
|
331
516
|
className,
|
|
@@ -340,6 +525,7 @@ export function FilterBarPreset({
|
|
|
340
525
|
filterKey={filter.key}
|
|
341
526
|
label={filter.label}
|
|
342
527
|
placeholder={filter.placeholder}
|
|
528
|
+
allLabel={filter.allLabel}
|
|
343
529
|
options={filter.options ?? []}
|
|
344
530
|
/>
|
|
345
531
|
)
|