@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,6 +1,7 @@
|
|
|
1
1
|
// Copied by `vantage add ui scroll-area`. This file is yours to edit.
|
|
2
|
-
// Generated from @squadbase/
|
|
3
|
-
|
|
2
|
+
// Generated from @squadbase/squadkit registry/ui/scroll-area.tsx by `pnpm run registry` (in Vantage, edit packages/squadkit, not registry/).
|
|
3
|
+
"use client"
|
|
4
|
+
|
|
4
5
|
import { ScrollArea as ScrollAreaPrimitive } from "@base-ui/react/scroll-area"
|
|
5
6
|
|
|
6
7
|
import { cn } from "@squadbase/vantage/ui"
|
|
@@ -1,5 +1,7 @@
|
|
|
1
1
|
// Copied by `vantage add ui searchable-select`. This file is yours to edit.
|
|
2
|
-
// Generated from @squadbase/
|
|
2
|
+
// Generated from @squadbase/squadkit registry/components/searchable-select.tsx by `pnpm run registry` (in Vantage, edit packages/squadkit, not registry/).
|
|
3
|
+
"use client"
|
|
4
|
+
|
|
3
5
|
/**
|
|
4
6
|
* SearchableSelect — a single-select combobox with a filter box. Filtering runs
|
|
5
7
|
* client-side over the given options; pass `onSearch` to take it over yourself
|
|
@@ -12,12 +14,144 @@ import { cn } from "@squadbase/vantage/ui"
|
|
|
12
14
|
import { Button } from "@squadbase/vantage/ui"
|
|
13
15
|
import { Popover, PopoverContent, PopoverTrigger } from "@squadbase/vantage/ui"
|
|
14
16
|
import { flattenOptions, type SelectOptions } from "@squadbase/vantage/components"
|
|
17
|
+
import { useSyncExternalStore } from "react"
|
|
15
18
|
import type { KeyboardEvent, MouseEvent } from "react"
|
|
16
19
|
import { CheckIcon, LoaderIcon, XIcon } from "lucide-react"
|
|
17
20
|
import { Command, CommandEmpty, CommandGroup, CommandInput, CommandItem, CommandList } from "@squadbase/vantage/ui"
|
|
18
21
|
import { isGroupedOptions, type SelectOption } from "@squadbase/vantage/components"
|
|
19
22
|
|
|
20
|
-
/* ---------- inlined from
|
|
23
|
+
/* ---------- inlined from @squadbase/squadkit registry/lib/locale.ts (internal to @squadbase/vantage) ---------- */
|
|
24
|
+
|
|
25
|
+
/**
|
|
26
|
+
* The display language of the parts and the defaults that follow it.
|
|
27
|
+
*
|
|
28
|
+
* The language comes from `<html lang>`: a tag starting with `ja` reads Japanese, anything else English.
|
|
29
|
+
* Without a usable `lang` (missing, invalid, or no `document` — SSR, Node) the locale is `FALLBACK_LOCALE`
|
|
30
|
+
* (`en-US`). A `locale` passed explicitly (a prop, an argument) always wins.
|
|
31
|
+
*
|
|
32
|
+
* Parts read the locale through `useLocale` (`hooks/use-locale`) and pass it down; the pure helpers here
|
|
33
|
+
* and in `format` / `comparison` / `chart-*` take it as an argument and fall back to `documentLocale()`.
|
|
34
|
+
*/
|
|
35
|
+
|
|
36
|
+
/** The language of the built-in wording: Japanese or English. */
|
|
37
|
+
type UiLanguage = "ja" | "en"
|
|
38
|
+
|
|
39
|
+
/** The locale used when `<html lang>` gives none (and on the server). */
|
|
40
|
+
const FALLBACK_LOCALE = "en-US"
|
|
41
|
+
|
|
42
|
+
/** `"ja"` when `locale` starts with `ja` (`ja`, `ja-JP`), else `"en"`. A missing locale is `"en"`. */
|
|
43
|
+
function uiLanguage(locale: string | null | undefined): UiLanguage {
|
|
44
|
+
return typeof locale === "string" && locale.trim().toLowerCase().startsWith("ja") ? "ja" : "en"
|
|
45
|
+
}
|
|
46
|
+
|
|
47
|
+
/** A BCP 47 tag in its canonical form (`en-gb` → `en-GB`), or `FALLBACK_LOCALE` when it is empty or invalid. */
|
|
48
|
+
function normalizeLocale(tag: string | null | undefined): string {
|
|
49
|
+
const value = tag?.trim()
|
|
50
|
+
if (!value) return FALLBACK_LOCALE
|
|
51
|
+
try {
|
|
52
|
+
return Intl.getCanonicalLocales(value)[0] ?? FALLBACK_LOCALE
|
|
53
|
+
} catch {
|
|
54
|
+
return FALLBACK_LOCALE
|
|
55
|
+
}
|
|
56
|
+
}
|
|
57
|
+
|
|
58
|
+
/**
|
|
59
|
+
* The locale of the page: `document.documentElement.lang`, canonicalized. `FALLBACK_LOCALE` when it is empty or
|
|
60
|
+
* invalid, or there is no `document`. Parts read it through `useLocale`, never while rendering.
|
|
61
|
+
*/
|
|
62
|
+
function documentLocale(): string {
|
|
63
|
+
if (typeof document === "undefined") return FALLBACK_LOCALE
|
|
64
|
+
return normalizeLocale(document.documentElement?.getAttribute("lang"))
|
|
65
|
+
}
|
|
66
|
+
|
|
67
|
+
/** `locale` when given, else the page's locale (`documentLocale()`). */
|
|
68
|
+
function resolveLocale(locale?: string | null): string {
|
|
69
|
+
return locale || documentLocale()
|
|
70
|
+
}
|
|
71
|
+
|
|
72
|
+
/** Picks the wording table of the locale's language. */
|
|
73
|
+
function pickLocale<T>(table: { ja: T; en: T }, locale?: string | null): T {
|
|
74
|
+
return table[uiLanguage(resolveLocale(locale))]
|
|
75
|
+
}
|
|
76
|
+
|
|
77
|
+
/** The currency `format="currency"` uses without a `currency`: JPY for Japanese, USD otherwise. */
|
|
78
|
+
function defaultCurrency(locale?: string | null): string {
|
|
79
|
+
return uiLanguage(resolveLocale(locale)) === "ja" ? "JPY" : "USD"
|
|
80
|
+
}
|
|
81
|
+
|
|
82
|
+
/** The month a fiscal year starts in (1–12) when none is given: April for Japanese, January otherwise. */
|
|
83
|
+
function defaultFiscalYearStartMonth(locale?: string | null): number {
|
|
84
|
+
return uiLanguage(resolveLocale(locale)) === "ja" ? 4 : 1
|
|
85
|
+
}
|
|
86
|
+
|
|
87
|
+
/** A day of the week, 0 = Sunday … 6 = Saturday (the `Date#getDay` / date-fns numbering). */
|
|
88
|
+
type WeekDay = 0 | 1 | 2 | 3 | 4 | 5 | 6
|
|
89
|
+
|
|
90
|
+
/** Locales whose week starts on Sunday when the runtime has no week data. */
|
|
91
|
+
const SUNDAY_FIRST = new Set(["en", "en-US", "en-CA"])
|
|
92
|
+
|
|
93
|
+
/**
|
|
94
|
+
* The first day of the week: Monday for Japanese; otherwise the locale's convention from `Intl.Locale`
|
|
95
|
+
* (`en-US` Sunday, `en-GB` Monday). Without week data in the runtime: Sunday for `en` / `en-US` / `en-CA`,
|
|
96
|
+
* Monday for the rest.
|
|
97
|
+
*/
|
|
98
|
+
function weekStartsOn(locale?: string | null): WeekDay {
|
|
99
|
+
const tag = normalizeLocale(resolveLocale(locale))
|
|
100
|
+
if (uiLanguage(tag) === "ja") return 1
|
|
101
|
+
try {
|
|
102
|
+
const info = new Intl.Locale(tag) as Intl.Locale & {
|
|
103
|
+
getWeekInfo?: () => { firstDay: number }
|
|
104
|
+
weekInfo?: { firstDay: number }
|
|
105
|
+
}
|
|
106
|
+
const firstDay = info.getWeekInfo?.().firstDay ?? info.weekInfo?.firstDay
|
|
107
|
+
if (typeof firstDay === "number" && firstDay >= 1 && firstDay <= 7) return (firstDay % 7) as WeekDay
|
|
108
|
+
} catch {
|
|
109
|
+
// Fall through to the table below.
|
|
110
|
+
}
|
|
111
|
+
return SUNDAY_FIRST.has(tag) ? 0 : 1
|
|
112
|
+
}
|
|
113
|
+
|
|
114
|
+
/* ---------- inlined from @squadbase/squadkit registry/hooks/use-locale.ts (internal to @squadbase/vantage) ---------- */
|
|
115
|
+
|
|
116
|
+
const listeners = new Set<() => void>()
|
|
117
|
+
let observer: MutationObserver | null = null
|
|
118
|
+
|
|
119
|
+
/** One observer on `<html lang>` for every subscribed part. */
|
|
120
|
+
function subscribe(onChange: () => void): () => void {
|
|
121
|
+
if (typeof document === "undefined" || typeof MutationObserver === "undefined") return () => {}
|
|
122
|
+
listeners.add(onChange)
|
|
123
|
+
if (!observer) {
|
|
124
|
+
observer = new MutationObserver(() => {
|
|
125
|
+
for (const listener of [...listeners]) listener()
|
|
126
|
+
})
|
|
127
|
+
observer.observe(document.documentElement, { attributes: true, attributeFilter: ["lang"] })
|
|
128
|
+
}
|
|
129
|
+
return () => {
|
|
130
|
+
listeners.delete(onChange)
|
|
131
|
+
if (listeners.size === 0 && observer) {
|
|
132
|
+
observer.disconnect()
|
|
133
|
+
observer = null
|
|
134
|
+
}
|
|
135
|
+
}
|
|
136
|
+
}
|
|
137
|
+
|
|
138
|
+
const serverLocale = () => FALLBACK_LOCALE
|
|
139
|
+
|
|
140
|
+
/**
|
|
141
|
+
* The page's locale (`<html lang>`), following changes made while the page runs. On the server and during
|
|
142
|
+
* hydration it is `FALLBACK_LOCALE` (`en-US`), so the markup matches; it switches right after.
|
|
143
|
+
*/
|
|
144
|
+
function useDocumentLocale(): string {
|
|
145
|
+
return useSyncExternalStore(subscribe, documentLocale, serverLocale)
|
|
146
|
+
}
|
|
147
|
+
|
|
148
|
+
/** The locale a part renders in: its `locale` prop when given, else the page's (`useDocumentLocale`). */
|
|
149
|
+
function useLocale(locale?: string | null): string {
|
|
150
|
+
const page = useDocumentLocale()
|
|
151
|
+
return locale || page
|
|
152
|
+
}
|
|
153
|
+
|
|
154
|
+
/* ---------- inlined from @squadbase/squadkit registry/components/option-command.tsx (internal to @squadbase/vantage) ---------- */
|
|
21
155
|
|
|
22
156
|
interface OptionCommandListProps {
|
|
23
157
|
options: SelectOptions
|
|
@@ -134,16 +268,24 @@ export interface SearchableSelectProps {
|
|
|
134
268
|
className?: string
|
|
135
269
|
}
|
|
136
270
|
|
|
271
|
+
const TEXT = {
|
|
272
|
+
ja: { placeholder: "選択してください", search: "検索...", empty: "見つかりませんでした", clear: "クリア" },
|
|
273
|
+
en: { placeholder: "Select an option", search: "Search...", empty: "No results found.", clear: "Clear" },
|
|
274
|
+
}
|
|
275
|
+
|
|
276
|
+
/** Not given yet (a draft fills props in steps): render empty, keep the same value between renders. */
|
|
277
|
+
const NO_OPTIONS: never[] = []
|
|
278
|
+
|
|
137
279
|
export const SearchableSelect = forwardRef<HTMLDivElement, SearchableSelectProps>(
|
|
138
280
|
function SearchableSelect(
|
|
139
281
|
{
|
|
140
|
-
options,
|
|
282
|
+
options = NO_OPTIONS,
|
|
141
283
|
value,
|
|
142
284
|
onChange,
|
|
143
285
|
onSearch,
|
|
144
|
-
placeholder
|
|
145
|
-
searchPlaceholder
|
|
146
|
-
emptyText
|
|
286
|
+
placeholder,
|
|
287
|
+
searchPlaceholder,
|
|
288
|
+
emptyText,
|
|
147
289
|
isLoading = false,
|
|
148
290
|
disabled = false,
|
|
149
291
|
clearable = true,
|
|
@@ -152,6 +294,7 @@ export const SearchableSelect = forwardRef<HTMLDivElement, SearchableSelectProps
|
|
|
152
294
|
ref,
|
|
153
295
|
) {
|
|
154
296
|
const [open, setOpen] = useState(false)
|
|
297
|
+
const t = TEXT[uiLanguage(useLocale())]
|
|
155
298
|
|
|
156
299
|
const allOptions = useMemo(() => flattenOptions(options), [options])
|
|
157
300
|
const selectedOption = useMemo(
|
|
@@ -182,10 +325,10 @@ export const SearchableSelect = forwardRef<HTMLDivElement, SearchableSelectProps
|
|
|
182
325
|
role="combobox"
|
|
183
326
|
aria-expanded={open}
|
|
184
327
|
>
|
|
185
|
-
<span className="truncate">{selectedOption ? selectedOption.label : placeholder}</span>
|
|
328
|
+
<span className="truncate">{selectedOption ? selectedOption.label : (placeholder ?? t.placeholder)}</span>
|
|
186
329
|
<span className="flex shrink-0 items-center gap-1">
|
|
187
330
|
{clearable && value && (
|
|
188
|
-
<RemoveButton label=
|
|
331
|
+
<RemoveButton label={t.clear} onRemove={() => onChange?.(undefined)} />
|
|
189
332
|
)}
|
|
190
333
|
<ChevronDownIcon className="size-4 opacity-50" />
|
|
191
334
|
</span>
|
|
@@ -197,8 +340,8 @@ export const SearchableSelect = forwardRef<HTMLDivElement, SearchableSelectProps
|
|
|
197
340
|
onSelect={handleSelect}
|
|
198
341
|
onSearch={onSearch}
|
|
199
342
|
isLoading={isLoading}
|
|
200
|
-
searchPlaceholder={searchPlaceholder}
|
|
201
|
-
emptyText={emptyText}
|
|
343
|
+
searchPlaceholder={searchPlaceholder ?? t.search}
|
|
344
|
+
emptyText={emptyText ?? t.empty}
|
|
202
345
|
/>
|
|
203
346
|
</PopoverContent>
|
|
204
347
|
</Popover>
|
|
@@ -1,5 +1,7 @@
|
|
|
1
1
|
// Copied by `vantage add ui section-header`. This file is yours to edit.
|
|
2
|
-
// Generated from @squadbase/
|
|
2
|
+
// Generated from @squadbase/squadkit registry/components/section-header.tsx by `pnpm run registry` (in Vantage, edit packages/squadkit, not registry/).
|
|
3
|
+
"use client"
|
|
4
|
+
|
|
3
5
|
/**
|
|
4
6
|
* SectionHeader — a titled divider inside a page: heading, optional
|
|
5
7
|
* description, and right-aligned actions that wrap below on narrow screens.
|
|
@@ -10,8 +12,8 @@ import { cn } from "@squadbase/vantage/ui"
|
|
|
10
12
|
|
|
11
13
|
const headingStyles = {
|
|
12
14
|
h1: "text-3xl font-bold tracking-tight",
|
|
13
|
-
h2: "text-
|
|
14
|
-
h3: "text-
|
|
15
|
+
h2: "text-base font-semibold tracking-tight",
|
|
16
|
+
h3: "text-base font-semibold",
|
|
15
17
|
h4: "text-lg font-semibold",
|
|
16
18
|
} as const
|
|
17
19
|
|
|
@@ -1,5 +1,7 @@
|
|
|
1
1
|
// Copied by `vantage add ui segmented-control`. This file is yours to edit.
|
|
2
|
-
// Generated from @squadbase/
|
|
2
|
+
// Generated from @squadbase/squadkit registry/components/segmented-control.tsx by `pnpm run registry` (in Vantage, edit packages/squadkit, not registry/).
|
|
3
|
+
"use client"
|
|
4
|
+
|
|
3
5
|
/**
|
|
4
6
|
* SegmentedControl — a single-select row of buttons over `ToggleGroup`. Base
|
|
5
7
|
* UI's toggle group is multi-value by default, so this wrapper narrows it to
|
|
@@ -27,9 +29,12 @@ export interface SegmentedControlProps {
|
|
|
27
29
|
className?: string
|
|
28
30
|
}
|
|
29
31
|
|
|
32
|
+
/** Not given yet (a draft fills props in steps): render empty, keep the same value between renders. */
|
|
33
|
+
const NO_OPTIONS: never[] = []
|
|
34
|
+
|
|
30
35
|
export const SegmentedControl = forwardRef<HTMLDivElement, SegmentedControlProps>(
|
|
31
36
|
function SegmentedControl(
|
|
32
|
-
{ options, value, onChange, size = "default", fullWidth = false, ariaLabel, className },
|
|
37
|
+
{ options = NO_OPTIONS, value, onChange, size = "default", fullWidth = false, ariaLabel, className },
|
|
33
38
|
ref,
|
|
34
39
|
) {
|
|
35
40
|
return (
|
package/registry/ui/select.tsx
CHANGED
|
@@ -1,5 +1,7 @@
|
|
|
1
1
|
// Copied by `vantage add ui select`. This file is yours to edit.
|
|
2
|
-
// Generated from @squadbase/
|
|
2
|
+
// Generated from @squadbase/squadkit registry/ui/select.tsx by `pnpm run registry` (in Vantage, edit packages/squadkit, not registry/).
|
|
3
|
+
"use client"
|
|
4
|
+
|
|
3
5
|
import * as React from "react"
|
|
4
6
|
import { Select as SelectPrimitive } from "@base-ui/react/select"
|
|
5
7
|
|
|
@@ -128,7 +130,7 @@ function SelectContent({
|
|
|
128
130
|
data-slot="select-content"
|
|
129
131
|
data-align-trigger={alignItemWithTrigger}
|
|
130
132
|
className={cn(
|
|
131
|
-
"cn-menu-target cn-menu-translucent relative isolate z-50 max-h-(--available-height) w-(--anchor-width) min-w-36 origin-(--transform-origin) overflow-x-hidden overflow-y-auto rounded-lg bg-popover text-popover-foreground shadow-md ring-1 ring-foreground/10 duration-100 data-[align-trigger=true]:animate-none data-[side=bottom]:slide-in-from-top-2 data-[side=inline-end]:slide-in-from-left-2 data-[side=inline-start]:slide-in-from-right-2 data-[side=left]:slide-in-from-right-2 data-[side=right]:slide-in-from-left-2 data-[side=top]:slide-in-from-bottom-2 data-open:animate-in data-open:fade-in-0 data-open:zoom-in-95 data-closed:animate-out data-closed:fade-out-0 data-closed:zoom-out-95",
|
|
133
|
+
"cn-menu-target cn-menu-translucent relative isolate z-50 max-h-(--available-height) w-(--anchor-width) min-w-36 origin-(--transform-origin) overflow-x-hidden overflow-y-auto rounded-lg bg-popover text-popover-foreground shadow-md ring-1 ring-foreground/10 duration-100 data-[align-trigger=true]:animate-none data-[side=bottom]:slide-in-from-top-2 data-[side=inline-end]:slide-in-from-left-2 data-[side=inline-start]:slide-in-from-right-2 data-[side=left]:slide-in-from-right-2 data-[side=right]:slide-in-from-left-2 data-[side=top]:slide-in-from-bottom-2 data-open:animate-in motion-reduce:animate-none! data-open:fade-in-0 data-open:zoom-in-95 data-closed:animate-out data-closed:fade-out-0 data-closed:zoom-out-95",
|
|
132
134
|
className
|
|
133
135
|
)}
|
|
134
136
|
{...props}
|
|
@@ -1,5 +1,7 @@
|
|
|
1
1
|
// Copied by `vantage add ui separator`. This file is yours to edit.
|
|
2
|
-
// Generated from @squadbase/
|
|
2
|
+
// Generated from @squadbase/squadkit registry/ui/separator.tsx by `pnpm run registry` (in Vantage, edit packages/squadkit, not registry/).
|
|
3
|
+
"use client"
|
|
4
|
+
|
|
3
5
|
import { Separator as SeparatorPrimitive } from "@base-ui/react/separator"
|
|
4
6
|
|
|
5
7
|
import { cn } from "@squadbase/vantage/ui"
|
package/registry/ui/sheet.tsx
CHANGED
|
@@ -1,5 +1,7 @@
|
|
|
1
1
|
// Copied by `vantage add ui sheet`. This file is yours to edit.
|
|
2
|
-
// Generated from @squadbase/
|
|
2
|
+
// Generated from @squadbase/squadkit registry/ui/sheet.tsx by `pnpm run registry` (in Vantage, edit packages/squadkit, not registry/).
|
|
3
|
+
"use client"
|
|
4
|
+
|
|
3
5
|
import * as React from "react"
|
|
4
6
|
import { Dialog as SheetPrimitive } from "@base-ui/react/dialog"
|
|
5
7
|
|
|
@@ -53,7 +55,7 @@ function SheetContent({
|
|
|
53
55
|
data-slot="sheet-content"
|
|
54
56
|
data-side={side}
|
|
55
57
|
className={cn(
|
|
56
|
-
"fixed z-50 flex flex-col gap-4 bg-popover bg-clip-padding text-sm text-popover-foreground shadow-lg transition duration-200 ease-
|
|
58
|
+
"fixed z-50 flex flex-col gap-4 bg-popover bg-clip-padding text-sm text-popover-foreground shadow-lg transition duration-200 ease-out data-ending-style:opacity-0 data-starting-style:opacity-0 motion-reduce:data-ending-style:translate-none! motion-reduce:data-starting-style:translate-none! data-[side=bottom]:inset-x-0 data-[side=bottom]:bottom-0 data-[side=bottom]:h-auto data-[side=bottom]:border-t data-[side=bottom]:data-ending-style:translate-y-[2.5rem] data-[side=bottom]:data-starting-style:translate-y-[2.5rem] data-[side=left]:inset-y-0 data-[side=left]:left-0 data-[side=left]:h-full data-[side=left]:w-3/4 data-[side=left]:border-r data-[side=left]:data-ending-style:translate-x-[-2.5rem] data-[side=left]:data-starting-style:translate-x-[-2.5rem] data-[side=right]:inset-y-0 data-[side=right]:right-0 data-[side=right]:h-full data-[side=right]:w-3/4 data-[side=right]:border-l data-[side=right]:data-ending-style:translate-x-[2.5rem] data-[side=right]:data-starting-style:translate-x-[2.5rem] data-[side=top]:inset-x-0 data-[side=top]:top-0 data-[side=top]:h-auto data-[side=top]:border-b data-[side=top]:data-ending-style:translate-y-[-2.5rem] data-[side=top]:data-starting-style:translate-y-[-2.5rem] data-[side=left]:sm:max-w-sm data-[side=right]:sm:max-w-sm",
|
|
57
59
|
className
|
|
58
60
|
)}
|
|
59
61
|
{...props}
|
package/registry/ui/sidebar.tsx
CHANGED
|
@@ -1,5 +1,7 @@
|
|
|
1
1
|
// Copied by `vantage add ui sidebar`. This file is yours to edit.
|
|
2
|
-
// Generated from @squadbase/
|
|
2
|
+
// Generated from @squadbase/squadkit registry/ui/sidebar.tsx by `pnpm run registry` (in Vantage, edit packages/squadkit, not registry/).
|
|
3
|
+
"use client"
|
|
4
|
+
|
|
3
5
|
import * as React from "react"
|
|
4
6
|
import { mergeProps } from "@base-ui/react/merge-props"
|
|
5
7
|
import { useRender } from "@base-ui/react/use-render"
|
|
@@ -289,7 +291,7 @@ function SidebarRail({ className, ...props }: React.ComponentProps<"button">) {
|
|
|
289
291
|
onClick={toggleSidebar}
|
|
290
292
|
title="Toggle Sidebar"
|
|
291
293
|
className={cn(
|
|
292
|
-
"absolute inset-y-0 z-20 hidden w-4 transition-
|
|
294
|
+
"absolute inset-y-0 z-20 hidden w-4 transition-[background-color,translate,left,right] ease-linear group-data-[side=left]:-right-4 group-data-[side=right]:left-0 after:absolute after:inset-y-0 after:start-1/2 after:w-[2px] hover:after:bg-sidebar-border sm:flex ltr:-translate-x-1/2 rtl:-translate-x-1/2",
|
|
293
295
|
"in-data-[side=left]:cursor-w-resize in-data-[side=right]:cursor-e-resize",
|
|
294
296
|
"[[data-side=left][data-state=collapsed]_&]:cursor-e-resize [[data-side=right][data-state=collapsed]_&]:cursor-w-resize",
|
|
295
297
|
"group-data-[collapsible=offcanvas]:translate-x-0 group-data-[collapsible=offcanvas]:after:left-full hover:group-data-[collapsible=offcanvas]:bg-sidebar",
|
package/registry/ui/skeleton.tsx
CHANGED
|
@@ -1,12 +1,14 @@
|
|
|
1
1
|
// Copied by `vantage add ui skeleton`. This file is yours to edit.
|
|
2
|
-
// Generated from @squadbase/
|
|
2
|
+
// Generated from @squadbase/squadkit registry/ui/skeleton.tsx by `pnpm run registry` (in Vantage, edit packages/squadkit, not registry/).
|
|
3
|
+
"use client"
|
|
4
|
+
|
|
3
5
|
import { cn } from "@squadbase/vantage/ui"
|
|
4
6
|
|
|
5
7
|
function Skeleton({ className, ...props }: React.ComponentProps<"div">) {
|
|
6
8
|
return (
|
|
7
9
|
<div
|
|
8
10
|
data-slot="skeleton"
|
|
9
|
-
className={cn("animate-pulse rounded-md bg-muted", className)}
|
|
11
|
+
className={cn("animate-pulse motion-reduce:animate-none rounded-md bg-muted", className)}
|
|
10
12
|
{...props}
|
|
11
13
|
/>
|
|
12
14
|
)
|
package/registry/ui/slider.tsx
CHANGED
|
@@ -1,5 +1,7 @@
|
|
|
1
1
|
// Copied by `vantage add ui slider`. This file is yours to edit.
|
|
2
|
-
// Generated from @squadbase/
|
|
2
|
+
// Generated from @squadbase/squadkit registry/ui/slider.tsx by `pnpm run registry` (in Vantage, edit packages/squadkit, not registry/).
|
|
3
|
+
"use client"
|
|
4
|
+
|
|
3
5
|
import { Slider as SliderPrimitive } from "@base-ui/react/slider"
|
|
4
6
|
|
|
5
7
|
import { cn } from "@squadbase/vantage/ui"
|
|
@@ -43,7 +45,7 @@ function Slider({
|
|
|
43
45
|
<SliderPrimitive.Thumb
|
|
44
46
|
data-slot="slider-thumb"
|
|
45
47
|
key={index}
|
|
46
|
-
className="relative block size-3 shrink-0 rounded-full border border-ring bg-
|
|
48
|
+
className="relative block size-3 shrink-0 rounded-full border border-ring bg-background ring-ring/50 transition-[color,box-shadow] select-none after:absolute after:-inset-2 hover:ring-3 focus-visible:ring-3 focus-visible:outline-hidden active:ring-3 disabled:pointer-events-none disabled:opacity-50"
|
|
47
49
|
/>
|
|
48
50
|
))}
|
|
49
51
|
</SliderPrimitive.Control>
|
|
@@ -1,5 +1,7 @@
|
|
|
1
1
|
// Copied by `vantage add ui sparkline`. This file is yours to edit.
|
|
2
|
-
// Generated from @squadbase/
|
|
2
|
+
// Generated from @squadbase/squadkit registry/charts/sparkline.tsx by `pnpm run registry` (in Vantage, edit packages/squadkit, not registry/).
|
|
3
|
+
"use client"
|
|
4
|
+
|
|
3
5
|
/**
|
|
4
6
|
* Sparkline — an inline trend micro-chart. Deliberately *not* an `EChart`: a
|
|
5
7
|
* sparkline sits inside table cells and KPI tiles by the dozen, where one
|
|
@@ -9,6 +11,7 @@
|
|
|
9
11
|
import { forwardRef, useEffect, useState, type SVGAttributes } from "react"
|
|
10
12
|
|
|
11
13
|
import { cn } from "@squadbase/vantage/ui"
|
|
14
|
+
import type { ChartHighlight } from "@squadbase/vantage/components"
|
|
12
15
|
|
|
13
16
|
export type SparklineVariant = "line" | "bar"
|
|
14
17
|
|
|
@@ -24,7 +27,15 @@ export interface SparklineProps extends SVGAttributes<SVGSVGElement> {
|
|
|
24
27
|
/** Tailwind text-colour class; drives both stroke and fill via `currentColor`. */
|
|
25
28
|
color?: string
|
|
26
29
|
area?: boolean
|
|
30
|
+
/** マウント時に線を引く / 棒を伸ばす。既定 `false`(`prefers-reduced-motion` では常に無効)。 */
|
|
27
31
|
animate?: boolean
|
|
32
|
+
/**
|
|
33
|
+
* 点の強調(Tufte 流)。`"auto"` は最新・最大・最小の 3 点だけに小さな点を打つ
|
|
34
|
+
* (最新は系列の色、最大・最小は muted)。`"latest"` は最新の 1 点だけ、`"none"` は線だけ。`variant="line"` のときだけ効く。既定 `"auto"`。
|
|
35
|
+
*/
|
|
36
|
+
highlight?: ChartHighlight | "latest"
|
|
37
|
+
/** 指定すると `role="img"` で読み上げ対象にする。省略時は装飾として `aria-hidden`。 */
|
|
38
|
+
"aria-label"?: string
|
|
28
39
|
className?: string
|
|
29
40
|
}
|
|
30
41
|
|
|
@@ -55,6 +66,37 @@ function buildAreaPath(ys: number[], height: number): string {
|
|
|
55
66
|
return `${buildLinePath(ys)} L${lastX},${height} L0,${height} Z`
|
|
56
67
|
}
|
|
57
68
|
|
|
69
|
+
export type SparklinePointKind = "latest" | "max" | "min"
|
|
70
|
+
|
|
71
|
+
export interface SparklinePoint {
|
|
72
|
+
kind: SparklinePointKind
|
|
73
|
+
index: number
|
|
74
|
+
}
|
|
75
|
+
|
|
76
|
+
/**
|
|
77
|
+
* The points a Tufte-style sparkline marks: the latest, the max and the min.
|
|
78
|
+
* A point that is both latest and max/min is drawn once, as `latest`; a flat
|
|
79
|
+
* series marks only the latest. Ties pick the most recent occurrence.
|
|
80
|
+
*/
|
|
81
|
+
export function sparklineHighlightPoints(values: number[]): SparklinePoint[] {
|
|
82
|
+
if (values.length === 0) return []
|
|
83
|
+
const last = values.length - 1
|
|
84
|
+
const points: SparklinePoint[] = [{ kind: "latest", index: last }]
|
|
85
|
+
let maxI = 0
|
|
86
|
+
let minI = 0
|
|
87
|
+
let max = values[0] as number
|
|
88
|
+
let min = max
|
|
89
|
+
values.forEach((v, i) => {
|
|
90
|
+
if (v >= max) [max, maxI] = [v, i]
|
|
91
|
+
if (v <= min) [min, minI] = [v, i]
|
|
92
|
+
})
|
|
93
|
+
const latest = values[last] as number
|
|
94
|
+
if (max === min) return points
|
|
95
|
+
if (max !== latest) points.push({ kind: "max", index: maxI })
|
|
96
|
+
if (min !== latest) points.push({ kind: "min", index: minI })
|
|
97
|
+
return points
|
|
98
|
+
}
|
|
99
|
+
|
|
58
100
|
interface BarRect {
|
|
59
101
|
x: number
|
|
60
102
|
y: number
|
|
@@ -67,14 +109,19 @@ function buildBarRects(ys: number[], height: number, gap = 1): BarRect[] {
|
|
|
67
109
|
return ys.map((y, i) => ({ x: i * (barW + gap), y, w: barW, h: height - y }))
|
|
68
110
|
}
|
|
69
111
|
|
|
112
|
+
/** Rows not given yet (a draft fills props in steps): draw the empty state, keep the same array between renders. */
|
|
113
|
+
const NO_ROWS: never[] = []
|
|
114
|
+
|
|
70
115
|
export const Sparkline = forwardRef<SVGSVGElement, SparklineProps>(function Sparkline(
|
|
71
116
|
{
|
|
72
|
-
data,
|
|
117
|
+
data = NO_ROWS,
|
|
73
118
|
variant = "line",
|
|
74
119
|
height = 40,
|
|
75
120
|
color = "text-chart-1",
|
|
76
121
|
area = false,
|
|
77
122
|
animate = false,
|
|
123
|
+
highlight = "auto",
|
|
124
|
+
"aria-label": ariaLabel,
|
|
78
125
|
className,
|
|
79
126
|
...props
|
|
80
127
|
},
|
|
@@ -88,10 +135,17 @@ export const Sparkline = forwardRef<SVGSVGElement, SparklineProps>(function Spar
|
|
|
88
135
|
|
|
89
136
|
if (data.length === 0) return null
|
|
90
137
|
|
|
91
|
-
const
|
|
92
|
-
|
|
93
|
-
|
|
94
|
-
|
|
138
|
+
const values = data.map((d) => d.value)
|
|
139
|
+
const ys = normalizeData(values, height)
|
|
140
|
+
const step = ys.length > 1 ? VB_WIDTH / (ys.length - 1) : 0
|
|
141
|
+
const points =
|
|
142
|
+
variant !== "line"
|
|
143
|
+
? []
|
|
144
|
+
: highlight === "auto"
|
|
145
|
+
? sparklineHighlightPoints(values)
|
|
146
|
+
: highlight === "latest"
|
|
147
|
+
? [{ kind: "latest" as const, index: values.length - 1 }]
|
|
148
|
+
: []
|
|
95
149
|
|
|
96
150
|
return (
|
|
97
151
|
<svg
|
|
@@ -101,7 +155,9 @@ export const Sparkline = forwardRef<SVGSVGElement, SparklineProps>(function Spar
|
|
|
101
155
|
preserveAspectRatio="none"
|
|
102
156
|
width="100%"
|
|
103
157
|
height={height}
|
|
104
|
-
|
|
158
|
+
role={ariaLabel ? "img" : undefined}
|
|
159
|
+
aria-label={ariaLabel}
|
|
160
|
+
aria-hidden={ariaLabel ? undefined : true}
|
|
105
161
|
className={cn("overflow-visible", className)}
|
|
106
162
|
{...props}
|
|
107
163
|
>
|
|
@@ -124,9 +180,28 @@ export const Sparkline = forwardRef<SVGSVGElement, SparklineProps>(function Spar
|
|
|
124
180
|
pathLength={animate ? 1 : undefined}
|
|
125
181
|
strokeDasharray={animate ? 1 : undefined}
|
|
126
182
|
strokeDashoffset={animate ? (mounted ? 0 : 1) : undefined}
|
|
127
|
-
className={cn("stroke-current", color)}
|
|
183
|
+
className={cn("stroke-current", animate && "motion-reduce:transition-none!", color)}
|
|
128
184
|
style={animate ? { transition: "stroke-dashoffset 0.6s ease-in-out" } : undefined}
|
|
129
185
|
/>
|
|
186
|
+
{/* A zero-length round-capped stroke with a non-scaling width stays a
|
|
187
|
+
circle even though the viewBox stretches (`preserveAspectRatio="none"`). */}
|
|
188
|
+
{points.map((p) => {
|
|
189
|
+
const x = (p.index * step).toFixed(2)
|
|
190
|
+
const y = (ys[p.index] ?? 0).toFixed(2)
|
|
191
|
+
return (
|
|
192
|
+
<path
|
|
193
|
+
key={p.kind}
|
|
194
|
+
data-slot="sparkline-point"
|
|
195
|
+
data-point={p.kind}
|
|
196
|
+
d={`M${x},${y} L${x},${y}`}
|
|
197
|
+
fill="none"
|
|
198
|
+
strokeWidth={p.kind === "latest" ? 5 : 4}
|
|
199
|
+
strokeLinecap="round"
|
|
200
|
+
vectorEffect="non-scaling-stroke"
|
|
201
|
+
className={cn("stroke-current", p.kind === "latest" ? color : "text-muted-foreground")}
|
|
202
|
+
/>
|
|
203
|
+
)
|
|
204
|
+
})}
|
|
130
205
|
</>
|
|
131
206
|
)}
|
|
132
207
|
|
|
@@ -139,7 +214,7 @@ export const Sparkline = forwardRef<SVGSVGElement, SparklineProps>(function Spar
|
|
|
139
214
|
width={rect.w}
|
|
140
215
|
height={animate ? (mounted ? rect.h : 0) : rect.h}
|
|
141
216
|
rx={0.5}
|
|
142
|
-
className={cn("fill-current", color)}
|
|
217
|
+
className={cn("fill-current", animate && "motion-reduce:transition-none!", color)}
|
|
143
218
|
style={
|
|
144
219
|
animate
|
|
145
220
|
? {
|
package/registry/ui/spinner.tsx
CHANGED
|
@@ -1,5 +1,7 @@
|
|
|
1
1
|
// Copied by `vantage add ui spinner`. This file is yours to edit.
|
|
2
|
-
// Generated from @squadbase/
|
|
2
|
+
// Generated from @squadbase/squadkit registry/ui/spinner.tsx by `pnpm run registry` (in Vantage, edit packages/squadkit, not registry/).
|
|
3
|
+
"use client"
|
|
4
|
+
|
|
3
5
|
import { cn } from "@squadbase/vantage/ui"
|
|
4
6
|
import { Loader2Icon } from "lucide-react"
|
|
5
7
|
|