@squadbase/vantage 0.0.1 → 0.1.0
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/README.md +21 -4
- package/dist/chunk-A2UUGASH.js +12 -0
- package/dist/chunk-A2UUGASH.js.map +1 -0
- package/dist/{chunk-ZGDU5YLH.js → chunk-PRFBSQA4.js} +9 -5
- package/dist/chunk-PRFBSQA4.js.map +1 -0
- package/dist/chunk-WQZYXXQW.js +2249 -0
- package/dist/chunk-WQZYXXQW.js.map +1 -0
- package/dist/{chunk-73J5ZD4C.js → chunk-YLAB6UQS.js} +17 -3
- package/dist/chunk-YLAB6UQS.js.map +1 -0
- package/dist/cli.js +607 -36
- package/dist/cli.js.map +1 -1
- package/dist/components/index.d.ts +554 -0
- package/dist/components/index.js +1983 -0
- package/dist/components/index.js.map +1 -0
- package/dist/markdown/index.d.ts +9 -0
- package/dist/markdown/index.js +26 -0
- package/dist/markdown/index.js.map +1 -0
- package/dist/query/index.d.ts +27 -1
- package/dist/query/index.js +18 -0
- package/dist/query/index.js.map +1 -1
- package/dist/server/node.js +6 -1
- package/dist/server/node.js.map +1 -1
- package/dist/ui/index.d.ts +316 -200
- package/dist/ui/index.js +566 -511
- package/dist/ui/index.js.map +1 -1
- package/dist/vite/index.js +2 -2
- package/docs/en/agent-skills.md +89 -0
- package/docs/en/api-and-server.md +84 -0
- package/docs/en/build-and-deploy.md +280 -0
- package/docs/en/cli-reference.md +311 -0
- package/docs/en/components.md +233 -0
- package/docs/en/data-fetching.md +78 -0
- package/docs/en/environment-variables.md +69 -0
- package/docs/en/getting-started.md +95 -0
- package/docs/en/index.md +65 -0
- package/docs/en/markdown/markdown-renderer.md +44 -0
- package/docs/en/pages-and-metadata.md +56 -0
- package/docs/en/parts/app-shell.md +54 -0
- package/docs/en/parts/dashboard-card.md +64 -0
- package/docs/en/parts/data-table.md +86 -0
- package/docs/en/parts/date-range-picker.md +41 -0
- package/docs/en/parts/echart.md +53 -0
- package/docs/en/parts/filter-bar.md +66 -0
- package/docs/en/parts/funnel-steps.md +33 -0
- package/docs/en/parts/metric-value.md +23 -0
- package/docs/en/parts/multi-select.md +27 -0
- package/docs/en/parts/page-shell.md +45 -0
- package/docs/en/parts/searchable-select.md +47 -0
- package/docs/en/parts/section-header.md +20 -0
- package/docs/en/parts/segmented-control.md +25 -0
- package/docs/en/parts/status-badge.md +44 -0
- package/docs/en/parts/trend-indicator.md +26 -0
- package/docs/en/routing.md +95 -0
- package/docs/en/ui/accordion.md +36 -0
- package/docs/en/ui/alert.md +31 -0
- package/docs/en/ui/badge.md +23 -0
- package/docs/en/ui/breadcrumb.md +38 -0
- package/docs/en/ui/button.md +39 -0
- package/docs/en/ui/calendar.md +28 -0
- package/docs/en/ui/card.md +35 -0
- package/docs/en/ui/checkbox.md +34 -0
- package/docs/en/ui/cn.md +34 -0
- package/docs/en/ui/collapsible.md +21 -0
- package/docs/en/ui/command.md +37 -0
- package/docs/en/ui/dialog.md +52 -0
- package/docs/en/ui/dropdown-menu.md +50 -0
- package/docs/en/ui/empty.md +22 -0
- package/docs/en/ui/error-state.md +50 -0
- package/docs/en/ui/input-group.md +30 -0
- package/docs/en/ui/input.md +28 -0
- package/docs/en/ui/label.md +19 -0
- package/docs/en/ui/loading.md +19 -0
- package/docs/en/ui/popover.md +34 -0
- package/docs/en/ui/progress.md +28 -0
- package/docs/en/ui/scroll-area.md +23 -0
- package/docs/en/ui/select.md +63 -0
- package/docs/en/ui/separator.md +15 -0
- package/docs/en/ui/sheet.md +28 -0
- package/docs/en/ui/sidebar.md +92 -0
- package/docs/en/ui/skeleton.md +16 -0
- package/docs/en/ui/slider.md +21 -0
- package/docs/en/ui/spinner.md +14 -0
- package/docs/en/ui/switch.md +19 -0
- package/docs/en/ui/table.md +24 -0
- package/docs/en/ui/tabs.md +23 -0
- package/docs/en/ui/textarea.md +15 -0
- package/docs/en/ui/toggle-group.md +26 -0
- package/docs/en/ui/toggle.md +19 -0
- package/docs/en/ui/tooltip.md +22 -0
- package/docs/en/ui/use-is-mobile.md +18 -0
- package/docs/en/ui-and-theming.md +95 -0
- package/docs/index.json +1306 -0
- package/docs/ja/agent-skills.md +87 -0
- package/docs/ja/api-and-server.md +84 -0
- package/docs/ja/build-and-deploy.md +279 -0
- package/docs/ja/cli-reference.md +305 -0
- package/docs/ja/components.md +229 -0
- package/docs/ja/data-fetching.md +78 -0
- package/docs/ja/environment-variables.md +68 -0
- package/docs/ja/getting-started.md +95 -0
- package/docs/ja/index.md +65 -0
- package/docs/ja/markdown/markdown-renderer.md +43 -0
- package/docs/ja/pages-and-metadata.md +56 -0
- package/docs/ja/parts/app-shell.md +54 -0
- package/docs/ja/parts/dashboard-card.md +64 -0
- package/docs/ja/parts/data-table.md +85 -0
- package/docs/ja/parts/date-range-picker.md +41 -0
- package/docs/ja/parts/echart.md +52 -0
- package/docs/ja/parts/filter-bar.md +64 -0
- package/docs/ja/parts/funnel-steps.md +33 -0
- package/docs/ja/parts/metric-value.md +25 -0
- package/docs/ja/parts/multi-select.md +27 -0
- package/docs/ja/parts/page-shell.md +45 -0
- package/docs/ja/parts/searchable-select.md +47 -0
- package/docs/ja/parts/section-header.md +20 -0
- package/docs/ja/parts/segmented-control.md +26 -0
- package/docs/ja/parts/status-badge.md +44 -0
- package/docs/ja/parts/trend-indicator.md +26 -0
- package/docs/ja/routing.md +95 -0
- package/docs/ja/ui/accordion.md +37 -0
- package/docs/ja/ui/alert.md +31 -0
- package/docs/ja/ui/badge.md +23 -0
- package/docs/ja/ui/breadcrumb.md +38 -0
- package/docs/ja/ui/button.md +39 -0
- package/docs/ja/ui/calendar.md +28 -0
- package/docs/ja/ui/card.md +35 -0
- package/docs/ja/ui/checkbox.md +34 -0
- package/docs/ja/ui/cn.md +34 -0
- package/docs/ja/ui/collapsible.md +21 -0
- package/docs/ja/ui/command.md +36 -0
- package/docs/ja/ui/dialog.md +51 -0
- package/docs/ja/ui/dropdown-menu.md +50 -0
- package/docs/ja/ui/empty.md +22 -0
- package/docs/ja/ui/error-state.md +50 -0
- package/docs/ja/ui/input-group.md +30 -0
- package/docs/ja/ui/input.md +28 -0
- package/docs/ja/ui/label.md +19 -0
- package/docs/ja/ui/loading.md +19 -0
- package/docs/ja/ui/popover.md +34 -0
- package/docs/ja/ui/progress.md +28 -0
- package/docs/ja/ui/scroll-area.md +24 -0
- package/docs/ja/ui/select.md +64 -0
- package/docs/ja/ui/separator.md +15 -0
- package/docs/ja/ui/sheet.md +28 -0
- package/docs/ja/ui/sidebar.md +92 -0
- package/docs/ja/ui/skeleton.md +16 -0
- package/docs/ja/ui/slider.md +21 -0
- package/docs/ja/ui/spinner.md +14 -0
- package/docs/ja/ui/switch.md +19 -0
- package/docs/ja/ui/table.md +24 -0
- package/docs/ja/ui/tabs.md +24 -0
- package/docs/ja/ui/textarea.md +15 -0
- package/docs/ja/ui/toggle-group.md +27 -0
- package/docs/ja/ui/toggle.md +19 -0
- package/docs/ja/ui/tooltip.md +22 -0
- package/docs/ja/ui/use-is-mobile.md +18 -0
- package/docs/ja/ui-and-theming.md +95 -0
- package/package.json +29 -4
- package/registry/blocks/sales-overview.tsx +43 -19
- package/registry/ui/data-table.tsx +702 -102
- package/skills/vantage-add-feature/SKILL.md +150 -0
- package/skills/vantage-app/SKILL.md +258 -0
- package/skills/vantage-pitfalls/SKILL.md +115 -0
- package/templates/AGENTS.md +268 -0
- package/theme.css +178 -40
- package/dist/chunk-73J5ZD4C.js.map +0 -1
- package/dist/chunk-ZGDU5YLH.js.map +0 -1
|
@@ -0,0 +1,95 @@
|
|
|
1
|
+
# File-based routing
|
|
2
|
+
|
|
3
|
+
> Dropping a file creates a route. Conventions for pages, layouts, dynamic params, and 404/error.
|
|
4
|
+
|
|
5
|
+
In Vantage, **where you place a file is its URL**. You never configure a router.
|
|
6
|
+
|
|
7
|
+
## Page conventions
|
|
8
|
+
|
|
9
|
+
| File | Route |
|
|
10
|
+
|---|---|
|
|
11
|
+
| `index.tsx` | `/` |
|
|
12
|
+
| `monthly-analysis.tsx` | `/monthly-analysis` |
|
|
13
|
+
| `sales/index.tsx` | `/sales` |
|
|
14
|
+
| `sales/[customerId].tsx` | `/sales/:customerId` |
|
|
15
|
+
| `sales/[...path].tsx` | `/sales/*` (catchall) |
|
|
16
|
+
| `_layout.tsx` | Layout for that directory (nestable) |
|
|
17
|
+
| `_404.tsx` | Not-found UI (**root only**) |
|
|
18
|
+
| `_error.tsx` | Error UI (**root only**) |
|
|
19
|
+
|
|
20
|
+
- `[name]` → dynamic param, `[...name]` → catchall.
|
|
21
|
+
- `index` maps to its own directory (the name drops from the URL).
|
|
22
|
+
- Files starting with `_` are reserved (`_layout`/`_404`/`_error`) or private (not routed).
|
|
23
|
+
|
|
24
|
+
## Directories that are never routed
|
|
25
|
+
|
|
26
|
+
These directories are never scanned. Put whatever code you like here.
|
|
27
|
+
|
|
28
|
+
```text
|
|
29
|
+
components/ Reusable React components
|
|
30
|
+
hooks/ Custom hooks
|
|
31
|
+
lib/ Utilities
|
|
32
|
+
server/ API (its presence enables the server)
|
|
33
|
+
public/ Static assets
|
|
34
|
+
```
|
|
35
|
+
|
|
36
|
+
> [!NOTE]
|
|
37
|
+
> Imports between files use **runtime `.js` specifiers** (e.g. `./components/revenue-chart.js`) —
|
|
38
|
+
> required for ESM Node resolution.
|
|
39
|
+
|
|
40
|
+
## The three spellings of a dynamic param
|
|
41
|
+
|
|
42
|
+
The same param appears in three spellings depending on where it is. **They must match.**
|
|
43
|
+
|
|
44
|
+
| Where | Spelling | Example |
|
|
45
|
+
|---|---|---|
|
|
46
|
+
| Filename | `[id]` | `sales/[customerId].tsx` |
|
|
47
|
+
| Display route | `:id` | `/sales/:customerId` |
|
|
48
|
+
| Link | `$id` + `params` | `to="/sales/$customerId"` `params={{ customerId }}` |
|
|
49
|
+
|
|
50
|
+
```tsx
|
|
51
|
+
import { Link, useParams } from "@squadbase/vantage/router";
|
|
52
|
+
|
|
53
|
+
function Row({ customerId }: { customerId: string }) {
|
|
54
|
+
return (
|
|
55
|
+
<Link to="/sales/$customerId" params={{ customerId }}>
|
|
56
|
+
Open customer
|
|
57
|
+
</Link>
|
|
58
|
+
);
|
|
59
|
+
}
|
|
60
|
+
|
|
61
|
+
// sales/[customerId].tsx
|
|
62
|
+
export default function Customer() {
|
|
63
|
+
const { customerId } = useParams({ strict: false });
|
|
64
|
+
return <div>Customer {customerId}</div>;
|
|
65
|
+
}
|
|
66
|
+
```
|
|
67
|
+
|
|
68
|
+
## Layouts and nesting
|
|
69
|
+
|
|
70
|
+
`_layout.tsx` renders an `<Outlet />` that wraps child routes. Place one per directory to nest them.
|
|
71
|
+
|
|
72
|
+
```tsx
|
|
73
|
+
// _layout.tsx
|
|
74
|
+
import { Outlet } from "@squadbase/vantage/router";
|
|
75
|
+
|
|
76
|
+
export default function RootLayout() {
|
|
77
|
+
return (
|
|
78
|
+
<div className="min-h-screen">
|
|
79
|
+
<nav className="border-b p-4">My Dashboard</nav>
|
|
80
|
+
<Outlet />
|
|
81
|
+
</div>
|
|
82
|
+
);
|
|
83
|
+
}
|
|
84
|
+
```
|
|
85
|
+
|
|
86
|
+
`_404.tsx` and `_error.tsx` are recognized at the **root only**.
|
|
87
|
+
|
|
88
|
+
## HMR and route regeneration
|
|
89
|
+
|
|
90
|
+
Adding or removing a `.tsx` page or a `server/api` file regenerates routes and triggers a full
|
|
91
|
+
reload. Editing a page body applies in place via React Fast Refresh.
|
|
92
|
+
|
|
93
|
+
## What to read next
|
|
94
|
+
|
|
95
|
+
- [Pages & definePage](pages-and-metadata) — the page contract and metadata
|
|
@@ -0,0 +1,36 @@
|
|
|
1
|
+
# Accordion
|
|
2
|
+
|
|
3
|
+
> A stack of headings that open and close. One at a time by default.
|
|
4
|
+
|
|
5
|
+
A list whose headings toggle their content open and closed. One panel at a time by default; add
|
|
6
|
+
`openMultiple` to let several stay open at once.
|
|
7
|
+
|
|
8
|
+
```tsx
|
|
9
|
+
import {
|
|
10
|
+
Accordion,
|
|
11
|
+
AccordionItem,
|
|
12
|
+
AccordionTrigger,
|
|
13
|
+
AccordionContent,
|
|
14
|
+
} from "@squadbase/vantage/ui";
|
|
15
|
+
```
|
|
16
|
+
|
|
17
|
+
## Parts
|
|
18
|
+
|
|
19
|
+
| Part | Role |
|
|
20
|
+
| --- | --- |
|
|
21
|
+
| `Accordion` | The root. `value` / `defaultValue` is an **array of open items** |
|
|
22
|
+
| `AccordionItem` | One item, identified by `value` |
|
|
23
|
+
| `AccordionTrigger` | The heading button; the chevron comes for free |
|
|
24
|
+
| `AccordionContent` | The panel that opens |
|
|
25
|
+
|
|
26
|
+
## Several open at once
|
|
27
|
+
|
|
28
|
+
```tsx
|
|
29
|
+
<Accordion openMultiple defaultValue={["a", "b"]}>
|
|
30
|
+
```
|
|
31
|
+
|
|
32
|
+
> [!NOTE]
|
|
33
|
+
> `value` is an **array**, not the string Radix used — that's Base UI's API. Even for a single open
|
|
34
|
+
> panel you pass `defaultValue={["freshness"]}`.
|
|
35
|
+
|
|
36
|
+
For one standalone disclosure, [`Collapsible`](ui/collapsible) is lighter.
|
|
@@ -0,0 +1,31 @@
|
|
|
1
|
+
# Alert
|
|
2
|
+
|
|
3
|
+
> An in-page notice that flags something while the content is still shown.
|
|
4
|
+
|
|
5
|
+
An in-page notice. Where [`ErrorState`](ui/error-state) says "this view failed",
|
|
6
|
+
`Alert` flags something while the content is still shown.
|
|
7
|
+
|
|
8
|
+
```tsx
|
|
9
|
+
import { Alert, AlertTitle, AlertDescription, AlertAction } from "@squadbase/vantage/ui";
|
|
10
|
+
```
|
|
11
|
+
|
|
12
|
+
## Parts and variants
|
|
13
|
+
|
|
14
|
+
| Part | Role |
|
|
15
|
+
| --- | --- |
|
|
16
|
+
| `Alert` | The frame. `variant`: `default` \| `destructive` |
|
|
17
|
+
| `AlertTitle` | The heading |
|
|
18
|
+
| `AlertDescription` | The body |
|
|
19
|
+
| `AlertAction` | An action pinned to the right |
|
|
20
|
+
|
|
21
|
+
Drop an icon as a direct child of `Alert` and the grid becomes two columns on its own. Importing
|
|
22
|
+
straight from `lucide-react` is fine.
|
|
23
|
+
|
|
24
|
+
```tsx
|
|
25
|
+
import { Info } from "lucide-react";
|
|
26
|
+
|
|
27
|
+
<Alert>
|
|
28
|
+
<Info />
|
|
29
|
+
<AlertTitle>This view is read-only</AlertTitle>
|
|
30
|
+
</Alert>;
|
|
31
|
+
```
|
|
@@ -0,0 +1,23 @@
|
|
|
1
|
+
# Badge
|
|
2
|
+
|
|
3
|
+
> A small label for counts, states and tags.
|
|
4
|
+
|
|
5
|
+
A small label to sit beside text. For a row's status with a coloured dot, reach for
|
|
6
|
+
[`StatusBadge`](parts/status-badge) instead.
|
|
7
|
+
|
|
8
|
+
```tsx
|
|
9
|
+
import { Badge, badgeVariants } from "@squadbase/vantage/ui";
|
|
10
|
+
```
|
|
11
|
+
|
|
12
|
+
## Variants
|
|
13
|
+
|
|
14
|
+
`default` / `secondary` / `destructive` / `outline` / `ghost` / `link`.
|
|
15
|
+
|
|
16
|
+
`badgeVariants` returns the class string, for when you want the badge look on a different element
|
|
17
|
+
such as an `<a>`.
|
|
18
|
+
|
|
19
|
+
```tsx
|
|
20
|
+
<a href="/docs" className={badgeVariants({ variant: "outline" })}>
|
|
21
|
+
Documentation
|
|
22
|
+
</a>
|
|
23
|
+
```
|
|
@@ -0,0 +1,38 @@
|
|
|
1
|
+
# Breadcrumb
|
|
2
|
+
|
|
3
|
+
> A breadcrumb trail showing where the page sits.
|
|
4
|
+
|
|
5
|
+
Shows where the current page sits in the hierarchy. Most useful on drill-down detail pages such as
|
|
6
|
+
`/sales/$customerId`.
|
|
7
|
+
|
|
8
|
+
```tsx
|
|
9
|
+
import {
|
|
10
|
+
Breadcrumb,
|
|
11
|
+
BreadcrumbList,
|
|
12
|
+
BreadcrumbItem,
|
|
13
|
+
BreadcrumbLink,
|
|
14
|
+
BreadcrumbPage,
|
|
15
|
+
BreadcrumbSeparator,
|
|
16
|
+
BreadcrumbEllipsis,
|
|
17
|
+
} from "@squadbase/vantage/ui";
|
|
18
|
+
```
|
|
19
|
+
|
|
20
|
+
## Parts
|
|
21
|
+
|
|
22
|
+
| Part | Role |
|
|
23
|
+
| --- | --- |
|
|
24
|
+
| `BreadcrumbLink` | An ancestor (a link) |
|
|
25
|
+
| `BreadcrumbPage` | Where you are now — not a link |
|
|
26
|
+
| `BreadcrumbSeparator` | The divider; pass children to swap the glyph |
|
|
27
|
+
| `BreadcrumbEllipsis` | Collapsed middle levels |
|
|
28
|
+
|
|
29
|
+
## With the router's link
|
|
30
|
+
|
|
31
|
+
`BreadcrumbLink` takes a `render` prop to become another component. Pass Vantage's
|
|
32
|
+
[`Link`](routing) for client-side navigation.
|
|
33
|
+
|
|
34
|
+
```tsx
|
|
35
|
+
import { Link } from "@squadbase/vantage/router";
|
|
36
|
+
|
|
37
|
+
<BreadcrumbLink render={<Link to="/sales" />}>Sales</BreadcrumbLink>;
|
|
38
|
+
```
|
|
@@ -0,0 +1,39 @@
|
|
|
1
|
+
# Button
|
|
2
|
+
|
|
3
|
+
> The button, with six variants and eight sizes.
|
|
4
|
+
|
|
5
|
+
The component you'll reach for most. `variant` carries the meaning, `size` the scale.
|
|
6
|
+
|
|
7
|
+
```tsx
|
|
8
|
+
import { Button, buttonVariants } from "@squadbase/vantage/ui";
|
|
9
|
+
```
|
|
10
|
+
|
|
11
|
+
| Prop | Type | Default | Description |
|
|
12
|
+
| --- | --- | --- | --- |
|
|
13
|
+
| `variant` | `"default" \| "secondary" \| "outline" \| "ghost" \| "destructive" \| "link"` | `"default"` | Look and meaning. |
|
|
14
|
+
| `size` | `"default" \| "xs" \| "sm" \| "lg" \| "icon" \| "icon-xs" \| "icon-sm" \| "icon-lg"` | `"default"` | Height and padding. The `icon` sizes are square. |
|
|
15
|
+
| `render` | `ReactElement` | | Render as a different element (Radix's `asChild`). |
|
|
16
|
+
|
|
17
|
+
Drop an icon in as a child and its size and spacing are handled. For icon-only buttons always pass
|
|
18
|
+
`size="icon"` and an `aria-label`.
|
|
19
|
+
|
|
20
|
+
## A link that looks like a button
|
|
21
|
+
|
|
22
|
+
Pass an element to `render` — Base UI has no `asChild`.
|
|
23
|
+
|
|
24
|
+
```tsx
|
|
25
|
+
import { Link } from "@squadbase/vantage/router";
|
|
26
|
+
|
|
27
|
+
<Button render={<Link to="/sales" />}>View sales</Button>;
|
|
28
|
+
```
|
|
29
|
+
|
|
30
|
+
When you only want the class string, call `buttonVariants({ variant, size })`.
|
|
31
|
+
|
|
32
|
+
## Pending state
|
|
33
|
+
|
|
34
|
+
```tsx
|
|
35
|
+
<Button disabled={isPending}>
|
|
36
|
+
{isPending && <Spinner />}
|
|
37
|
+
Save
|
|
38
|
+
</Button>
|
|
39
|
+
```
|
|
@@ -0,0 +1,28 @@
|
|
|
1
|
+
# Calendar
|
|
2
|
+
|
|
3
|
+
> The date calendar, built on react-day-picker.
|
|
4
|
+
|
|
5
|
+
A calendar for single dates, multiple dates or a range. For picking a period on a dashboard,
|
|
6
|
+
[`DateRangePicker`](parts/date-range-picker) gets you there faster than using this
|
|
7
|
+
directly.
|
|
8
|
+
|
|
9
|
+
```tsx
|
|
10
|
+
import { Calendar, CalendarDayButton } from "@squadbase/vantage/ui";
|
|
11
|
+
```
|
|
12
|
+
|
|
13
|
+
The props are [react-day-picker](https://daypicker.dev)'s `DayPicker` props. Vantage adds only
|
|
14
|
+
three of its own:
|
|
15
|
+
|
|
16
|
+
| Prop | Type | Default | Description |
|
|
17
|
+
| --- | --- | --- | --- |
|
|
18
|
+
| `captionLayout` | `"label" \| "dropdown" \| "dropdown-months" \| "dropdown-years"` | `"label"` | Whether the month/year caption is text or a select. |
|
|
19
|
+
| `buttonVariant` | `Button variant` | `"ghost"` | Look of the previous/next month buttons. |
|
|
20
|
+
| `showOutsideDays` | `boolean` | `true` | Dim and show the neighbouring months' days. |
|
|
21
|
+
|
|
22
|
+
`mode` is `"single"` / `"multiple"` / `"range"`, and the types of `selected` and `onSelect` follow
|
|
23
|
+
it. `CalendarDayButton` is one day cell — swap it when you want a dot or label under the date.
|
|
24
|
+
|
|
25
|
+
> [!NOTE]
|
|
26
|
+
> Change the locale by passing a `date-fns` locale to the `locale` prop. `date-fns` is one of
|
|
27
|
+
> Vantage's dependencies, but avoid importing it directly from app code — keeping locale handling
|
|
28
|
+
> inside [`DateRangePicker`](parts/date-range-picker) is the safer path.
|
|
@@ -0,0 +1,35 @@
|
|
|
1
|
+
# Card
|
|
2
|
+
|
|
3
|
+
> The generic card. For dashboard tiles use DashboardCard.
|
|
4
|
+
|
|
5
|
+
The generic card. For dashboard tiles, [`DashboardCard`](parts/dashboard-card) —
|
|
6
|
+
which already has the spacing and a skeleton — fits better.
|
|
7
|
+
|
|
8
|
+
```tsx
|
|
9
|
+
import {
|
|
10
|
+
Card,
|
|
11
|
+
CardHeader,
|
|
12
|
+
CardTitle,
|
|
13
|
+
CardDescription,
|
|
14
|
+
CardAction,
|
|
15
|
+
CardContent,
|
|
16
|
+
CardFooter,
|
|
17
|
+
} from "@squadbase/vantage/ui";
|
|
18
|
+
```
|
|
19
|
+
|
|
20
|
+
## Parts
|
|
21
|
+
|
|
22
|
+
| Part | Role |
|
|
23
|
+
| --- | --- |
|
|
24
|
+
| `Card` | The frame. `size`: `default` \| `sm` (changes inner spacing) |
|
|
25
|
+
| `CardHeader` | The heading row |
|
|
26
|
+
| `CardTitle` / `CardDescription` | Heading and supporting text |
|
|
27
|
+
| `CardAction` | The right end of the heading row; adding it makes the header two columns |
|
|
28
|
+
| `CardContent` | The body |
|
|
29
|
+
| `CardFooter` | The bottom; adding it tightens the card's bottom padding |
|
|
30
|
+
|
|
31
|
+
Spacing comes from a single `--card-spacing` CSS variable, so you can override it per card.
|
|
32
|
+
|
|
33
|
+
```tsx
|
|
34
|
+
<Card className="[--card-spacing:--spacing(6)]">…</Card>
|
|
35
|
+
```
|
|
@@ -0,0 +1,34 @@
|
|
|
1
|
+
# Checkbox
|
|
2
|
+
|
|
3
|
+
> The checkbox. The mixed state is a separate indeterminate prop.
|
|
4
|
+
|
|
5
|
+
An on/off input. In the Base UI build `checked` is strictly a boolean and the mixed state lives on
|
|
6
|
+
its own prop — the biggest difference if you're coming from Radix.
|
|
7
|
+
|
|
8
|
+
```tsx
|
|
9
|
+
import { Checkbox } from "@squadbase/vantage/ui";
|
|
10
|
+
```
|
|
11
|
+
|
|
12
|
+
| Prop | Type | Description |
|
|
13
|
+
| --- | --- | --- |
|
|
14
|
+
| `checked` | `boolean` | The checked state. `"indeterminate"` is not accepted. |
|
|
15
|
+
| `indeterminate` | `boolean` | The mixed state, independent of `checked`. |
|
|
16
|
+
| `onCheckedChange` | `(checked: boolean) => void` | Fired on change; the value is always a boolean. |
|
|
17
|
+
| `disabled` | `boolean` | Disable interaction. |
|
|
18
|
+
|
|
19
|
+
> [!WARNING]
|
|
20
|
+
> Radix's `checked={"indeterminate"}` is a type error here. Under Base UI, pass `indeterminate` as its
|
|
21
|
+
> own prop.
|
|
22
|
+
|
|
23
|
+
## Select-all in a table
|
|
24
|
+
|
|
25
|
+
This is exactly what [`DataTable`](parts/data-table)'s selection column does.
|
|
26
|
+
|
|
27
|
+
```tsx
|
|
28
|
+
<Checkbox
|
|
29
|
+
checked={table.getIsAllPageRowsSelected()}
|
|
30
|
+
indeterminate={table.getIsSomePageRowsSelected()}
|
|
31
|
+
onCheckedChange={(checked) => table.toggleAllPageRowsSelected(checked)}
|
|
32
|
+
aria-label="Select all"
|
|
33
|
+
/>
|
|
34
|
+
```
|
package/docs/en/ui/cn.md
ADDED
|
@@ -0,0 +1,34 @@
|
|
|
1
|
+
# cn()
|
|
2
|
+
|
|
3
|
+
> The helper that builds class names and resolves conflicts.
|
|
4
|
+
|
|
5
|
+
Builds a `className` conditionally: `clsx` resolves the conditions, `tailwind-merge` resolves
|
|
6
|
+
conflicting utilities.
|
|
7
|
+
|
|
8
|
+
```tsx
|
|
9
|
+
import { cn } from "@squadbase/vantage/ui";
|
|
10
|
+
import type { ClassValue } from "@squadbase/vantage/ui";
|
|
11
|
+
|
|
12
|
+
<div className={cn("p-4", isActive && "bg-accent", className)} />;
|
|
13
|
+
```
|
|
14
|
+
|
|
15
|
+
## Last one wins
|
|
16
|
+
|
|
17
|
+
Because it runs through `tailwind-merge`, conflicting utilities resolve **in favour of the later
|
|
18
|
+
one**.
|
|
19
|
+
|
|
20
|
+
```tsx
|
|
21
|
+
cn("p-2", "p-4"); // → "p-4"
|
|
22
|
+
```
|
|
23
|
+
|
|
24
|
+
That is what lets a `className` you pass to a component override its defaults. Every built-in
|
|
25
|
+
component runs its classes through `cn()`, so `className` always behaves as an override.
|
|
26
|
+
|
|
27
|
+
```tsx
|
|
28
|
+
// Reliably beats the default bg-primary
|
|
29
|
+
<Button className="bg-emerald-600 hover:bg-emerald-700">Run</Button>
|
|
30
|
+
```
|
|
31
|
+
|
|
32
|
+
> [!NOTE]
|
|
33
|
+
> You never need to import `clsx` or `tailwind-merge` yourself — and shouldn't from app code. `cn()`
|
|
34
|
+
> is the public seam for both.
|
|
@@ -0,0 +1,21 @@
|
|
|
1
|
+
# Collapsible
|
|
2
|
+
|
|
3
|
+
> A single unstyled disclosure.
|
|
4
|
+
|
|
5
|
+
An unstyled primitive that opens and closes one region. For a stack of headings, use
|
|
6
|
+
[`Accordion`](ui/accordion).
|
|
7
|
+
|
|
8
|
+
```tsx
|
|
9
|
+
import { Collapsible, CollapsibleTrigger, CollapsibleContent } from "@squadbase/vantage/ui";
|
|
10
|
+
```
|
|
11
|
+
|
|
12
|
+
Control it with `open` / `defaultOpen` / `onOpenChange`. Both the trigger and the panel get
|
|
13
|
+
`data-open` while open, so the chevron can rotate in CSS alone.
|
|
14
|
+
|
|
15
|
+
```tsx
|
|
16
|
+
<ChevronRight className="transition-transform data-open:rotate-90" />
|
|
17
|
+
```
|
|
18
|
+
|
|
19
|
+
> [!NOTE]
|
|
20
|
+
> `data-open` is a custom variant declared in Vantage's `theme.css`. The Radix spelling
|
|
21
|
+
> `data-[state=open]:` is wired to the same variant, so either works.
|
|
@@ -0,0 +1,37 @@
|
|
|
1
|
+
# Command
|
|
2
|
+
|
|
3
|
+
> A filterable command list — the base for a ⌘K palette.
|
|
4
|
+
|
|
5
|
+
A list that narrows as you type. It is what powers
|
|
6
|
+
[`SearchableSelect`](parts/searchable-select) and
|
|
7
|
+
[`MultiSelect`](parts/multi-select), and on its own it makes a ⌘K palette.
|
|
8
|
+
|
|
9
|
+
```tsx
|
|
10
|
+
import {
|
|
11
|
+
Command,
|
|
12
|
+
CommandDialog,
|
|
13
|
+
CommandInput,
|
|
14
|
+
CommandList,
|
|
15
|
+
CommandEmpty,
|
|
16
|
+
CommandGroup,
|
|
17
|
+
CommandItem,
|
|
18
|
+
CommandShortcut,
|
|
19
|
+
CommandSeparator,
|
|
20
|
+
} from "@squadbase/vantage/ui";
|
|
21
|
+
```
|
|
22
|
+
|
|
23
|
+
## Parts
|
|
24
|
+
|
|
25
|
+
| Part | Role |
|
|
26
|
+
| --- | --- |
|
|
27
|
+
| `Command` | The root; owns filtering and keyboard handling |
|
|
28
|
+
| `CommandDialog` | The same thing inside a `Dialog` — for a ⌘K palette |
|
|
29
|
+
| `CommandInput` | The search field |
|
|
30
|
+
| `CommandList` | The scroll region |
|
|
31
|
+
| `CommandEmpty` | Shown when nothing matches |
|
|
32
|
+
| `CommandGroup` | A group with a `heading` |
|
|
33
|
+
| `CommandItem` | One item; `value` / `onSelect` |
|
|
34
|
+
| `CommandShortcut` | The key hint on the right |
|
|
35
|
+
|
|
36
|
+
Filtering runs against the items' text by default. To search on the server, set
|
|
37
|
+
`shouldFilter={false}` and replace the items yourself.
|
|
@@ -0,0 +1,52 @@
|
|
|
1
|
+
# Dialog
|
|
2
|
+
|
|
3
|
+
> The modal dialog.
|
|
4
|
+
|
|
5
|
+
A modal centred on the screen. For one that slides in from the edge use
|
|
6
|
+
[`Sheet`](ui/sheet); for a light bubble use
|
|
7
|
+
[`Popover`](ui/popover).
|
|
8
|
+
|
|
9
|
+
```tsx
|
|
10
|
+
import {
|
|
11
|
+
Dialog,
|
|
12
|
+
DialogTrigger,
|
|
13
|
+
DialogContent,
|
|
14
|
+
DialogHeader,
|
|
15
|
+
DialogTitle,
|
|
16
|
+
DialogDescription,
|
|
17
|
+
DialogFooter,
|
|
18
|
+
DialogClose,
|
|
19
|
+
DialogOverlay,
|
|
20
|
+
DialogPortal,
|
|
21
|
+
} from "@squadbase/vantage/ui";
|
|
22
|
+
```
|
|
23
|
+
|
|
24
|
+
## Parts
|
|
25
|
+
|
|
26
|
+
| Part | Role |
|
|
27
|
+
| --- | --- |
|
|
28
|
+
| `Dialog` | The state: `open` / `defaultOpen` / `onOpenChange` |
|
|
29
|
+
| `DialogTrigger` | What opens it; `render` turns it into a button |
|
|
30
|
+
| `DialogContent` | The panel. `showCloseButton` (default `true`) toggles the × |
|
|
31
|
+
| `DialogHeader` / `DialogTitle` / `DialogDescription` | The heading block |
|
|
32
|
+
| `DialogFooter` | The button row; `showCloseButton` adds a close button |
|
|
33
|
+
| `DialogClose` | Anything that closes it |
|
|
34
|
+
|
|
35
|
+
`DialogTitle` is required for assistive technology. If you don't want it visible, keep it and add
|
|
36
|
+
`className="sr-only"`.
|
|
37
|
+
|
|
38
|
+
## Opening without a trigger
|
|
39
|
+
|
|
40
|
+
To open from code — after a form submit, say — own the `open` state yourself.
|
|
41
|
+
|
|
42
|
+
```tsx
|
|
43
|
+
const [open, setOpen] = useState(false);
|
|
44
|
+
|
|
45
|
+
<Dialog open={open} onOpenChange={setOpen}>
|
|
46
|
+
<DialogContent>…</DialogContent>
|
|
47
|
+
</Dialog>;
|
|
48
|
+
```
|
|
49
|
+
|
|
50
|
+
> [!NOTE]
|
|
51
|
+
> Base UI has no `asChild`. Write `<DialogTrigger render={<Button />}>Label</DialogTrigger>` — the
|
|
52
|
+
> label goes in `children`, not inside the element you pass to `render`.
|
|
@@ -0,0 +1,50 @@
|
|
|
1
|
+
# DropdownMenu
|
|
2
|
+
|
|
3
|
+
> A menu opened from a button, with checkbox, radio and submenu items.
|
|
4
|
+
|
|
5
|
+
An action menu opened from a button — the per-row "…" menu, or a table's column-visibility toggle.
|
|
6
|
+
|
|
7
|
+
```tsx
|
|
8
|
+
import {
|
|
9
|
+
DropdownMenu,
|
|
10
|
+
DropdownMenuTrigger,
|
|
11
|
+
DropdownMenuContent,
|
|
12
|
+
DropdownMenuGroup,
|
|
13
|
+
DropdownMenuLabel,
|
|
14
|
+
DropdownMenuItem,
|
|
15
|
+
DropdownMenuCheckboxItem,
|
|
16
|
+
DropdownMenuRadioGroup,
|
|
17
|
+
DropdownMenuRadioItem,
|
|
18
|
+
DropdownMenuSeparator,
|
|
19
|
+
DropdownMenuShortcut,
|
|
20
|
+
DropdownMenuSub,
|
|
21
|
+
DropdownMenuSubTrigger,
|
|
22
|
+
DropdownMenuSubContent,
|
|
23
|
+
DropdownMenuPortal,
|
|
24
|
+
} from "@squadbase/vantage/ui";
|
|
25
|
+
```
|
|
26
|
+
|
|
27
|
+
## The props you'll use
|
|
28
|
+
|
|
29
|
+
| Prop | Goes on | Meaning |
|
|
30
|
+
| --- | --- | --- |
|
|
31
|
+
| `align` / `side` / `sideOffset` | `DropdownMenuContent` | Where it opens |
|
|
32
|
+
| `variant="destructive"` | `DropdownMenuItem` | Destructive colouring |
|
|
33
|
+
| `inset` | `Item` / `Label` / `SubTrigger` | Indent past the icon column |
|
|
34
|
+
| `checked` / `onCheckedChange` | `DropdownMenuCheckboxItem` | Checked state |
|
|
35
|
+
| `value` / `onValueChange` | `DropdownMenuRadioGroup` | Single choice |
|
|
36
|
+
|
|
37
|
+
## Submenus
|
|
38
|
+
|
|
39
|
+
```tsx
|
|
40
|
+
<DropdownMenuSub>
|
|
41
|
+
<DropdownMenuSubTrigger>Export</DropdownMenuSubTrigger>
|
|
42
|
+
<DropdownMenuSubContent>
|
|
43
|
+
<DropdownMenuItem>CSV</DropdownMenuItem>
|
|
44
|
+
<DropdownMenuItem>JSON</DropdownMenuItem>
|
|
45
|
+
</DropdownMenuSubContent>
|
|
46
|
+
</DropdownMenuSub>
|
|
47
|
+
```
|
|
48
|
+
|
|
49
|
+
> [!NOTE]
|
|
50
|
+
> Use `render` to make the trigger a button — Base UI has no `asChild`.
|
|
@@ -0,0 +1,22 @@
|
|
|
1
|
+
# Empty
|
|
2
|
+
|
|
3
|
+
> The zero-results state.
|
|
4
|
+
|
|
5
|
+
What to show when there are no results. The icon, description and action are all optional.
|
|
6
|
+
|
|
7
|
+
```tsx
|
|
8
|
+
import { Empty } from "@squadbase/vantage/ui";
|
|
9
|
+
```
|
|
10
|
+
|
|
11
|
+
| Prop | Type | Default | Description |
|
|
12
|
+
| --- | --- | --- | --- |
|
|
13
|
+
| `title` | `string` | `"Nothing here yet"` | The heading. |
|
|
14
|
+
| `description` | `string` | | Supporting text under the heading. |
|
|
15
|
+
| `icon` | `ReactNode` | | Artwork above the heading. |
|
|
16
|
+
| `action` | `ReactNode` | | The next step — a button or link — at the bottom. |
|
|
17
|
+
| `className` | `string` | | Classes to add. |
|
|
18
|
+
|
|
19
|
+
> [!NOTE]
|
|
20
|
+
> When it has no rows, [`DataTable`](parts/data-table) draws its own "no data" row
|
|
21
|
+
> inside the table. Reach for `Empty` when you want to replace the table entirely — for instance, when
|
|
22
|
+
> nothing has been created yet.
|
|
@@ -0,0 +1,50 @@
|
|
|
1
|
+
# ErrorState
|
|
2
|
+
|
|
3
|
+
> The failure state.
|
|
4
|
+
|
|
5
|
+
Shown when a load or an action failed. It carries `role="alert"` and is framed in the destructive
|
|
6
|
+
colours.
|
|
7
|
+
|
|
8
|
+
```tsx
|
|
9
|
+
import { ErrorState } from "@squadbase/vantage/ui";
|
|
10
|
+
```
|
|
11
|
+
|
|
12
|
+
| Prop | Type | Default | Description |
|
|
13
|
+
| --- | --- | --- | --- |
|
|
14
|
+
| `title` | `string` | `"Something went wrong"` | The heading. |
|
|
15
|
+
| `message` | `ReactNode` | | The details — an error message can go straight in. |
|
|
16
|
+
| `action` | `ReactNode` | | A retry button, typically. |
|
|
17
|
+
| `className` | `string` | | Classes to add. |
|
|
18
|
+
|
|
19
|
+
## All three states together
|
|
20
|
+
|
|
21
|
+
The usual shape is to map the query's state onto the three branches.
|
|
22
|
+
|
|
23
|
+
```tsx
|
|
24
|
+
import { useQuery, apiFetch } from "@squadbase/vantage/query";
|
|
25
|
+
import { Button, Loading, Empty, ErrorState } from "@squadbase/vantage/ui";
|
|
26
|
+
import { DataTablePreset } from "@squadbase/vantage/components";
|
|
27
|
+
|
|
28
|
+
export default function Customers() {
|
|
29
|
+
const { data, isLoading, error, refetch } = useQuery({
|
|
30
|
+
queryKey: ["customers"],
|
|
31
|
+
queryFn: () => apiFetch("/api/customers").then((r) => r.json()),
|
|
32
|
+
});
|
|
33
|
+
|
|
34
|
+
if (isLoading) return <Loading label="Loading customers…" />;
|
|
35
|
+
if (error)
|
|
36
|
+
return (
|
|
37
|
+
<ErrorState
|
|
38
|
+
message={error.message}
|
|
39
|
+
action={<Button variant="outline" onClick={() => refetch()}>Retry</Button>}
|
|
40
|
+
/>
|
|
41
|
+
);
|
|
42
|
+
if (data.length === 0) return <Empty title="No customers yet" />;
|
|
43
|
+
|
|
44
|
+
return <DataTablePreset columns={columns} data={data} />;
|
|
45
|
+
}
|
|
46
|
+
```
|
|
47
|
+
|
|
48
|
+
> [!NOTE]
|
|
49
|
+
> To surface a deliberate error message from your API, throw `HttpError(status, message)` in
|
|
50
|
+
> `server/api`. Anything else becomes a generic 500 — see [API & server](api-and-server).
|
|
@@ -0,0 +1,30 @@
|
|
|
1
|
+
# InputGroup
|
|
2
|
+
|
|
3
|
+
> Attach icons, text or buttons to either end of an input.
|
|
4
|
+
|
|
5
|
+
A frame that places icons, units or small buttons inside the field — search boxes, or inputs with a
|
|
6
|
+
`%` or currency suffix.
|
|
7
|
+
|
|
8
|
+
```tsx
|
|
9
|
+
import {
|
|
10
|
+
InputGroup,
|
|
11
|
+
InputGroupInput,
|
|
12
|
+
InputGroupTextarea,
|
|
13
|
+
InputGroupAddon,
|
|
14
|
+
InputGroupText,
|
|
15
|
+
InputGroupButton,
|
|
16
|
+
} from "@squadbase/vantage/ui";
|
|
17
|
+
```
|
|
18
|
+
|
|
19
|
+
## Parts
|
|
20
|
+
|
|
21
|
+
| Part | Role |
|
|
22
|
+
| --- | --- |
|
|
23
|
+
| `InputGroup` | The frame; the focus ring lives here |
|
|
24
|
+
| `InputGroupInput` / `InputGroupTextarea` | The field itself, borderless |
|
|
25
|
+
| `InputGroupAddon` | Where attachments go. `align`: `inline-start` (default) \| `inline-end` \| `block-start` \| `block-end` |
|
|
26
|
+
| `InputGroupText` | Short text such as a unit |
|
|
27
|
+
| `InputGroupButton` | A small button. `size`: `xs` (default) \| `sm` \| `icon-xs` \| `icon-sm` |
|
|
28
|
+
|
|
29
|
+
`block-start` / `block-end` place the addon above or below the field — pair either with
|
|
30
|
+
`InputGroupTextarea` for a textarea with its own toolbar.
|