@squadbase/vantage 0.0.1 → 0.1.1
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 +24 -4
- package/dist/{chunk-ZGDU5YLH.js → chunk-5L2MH2NG.js} +16 -7
- package/dist/chunk-5L2MH2NG.js.map +1 -0
- package/dist/chunk-7IPAXPPY.js +51 -0
- package/dist/chunk-7IPAXPPY.js.map +1 -0
- package/dist/chunk-A2UUGASH.js +12 -0
- package/dist/chunk-A2UUGASH.js.map +1 -0
- package/dist/chunk-DTDVSFRY.js +29 -0
- package/dist/chunk-DTDVSFRY.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/client/index.d.ts +2 -1
- package/dist/client/index.js +3 -1
- package/dist/client/index.js.map +1 -1
- package/dist/components/index.d.ts +575 -0
- package/dist/components/index.js +2097 -0
- package/dist/components/index.js.map +1 -0
- package/dist/{define-page-B6y9TOfZ.d.ts → define-page-BfhrK99G.d.ts} +5 -0
- package/dist/index.d.ts +2 -2
- package/dist/index.js +1 -1
- package/dist/index.js.map +1 -1
- 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 +95 -2
- package/dist/query/index.js +102 -1
- package/dist/query/index.js.map +1 -1
- package/dist/router/index.d.ts +86 -1
- package/dist/router/index.js +71 -7
- package/dist/router/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 +235 -0
- package/docs/en/data-fetching.md +142 -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 +59 -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/placeholder.md +38 -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/sparkline.md +47 -0
- package/docs/en/parts/status-badge.md +44 -0
- package/docs/en/parts/trend-indicator.md +26 -0
- package/docs/en/routing.md +177 -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 +1346 -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 +231 -0
- package/docs/ja/data-fetching.md +142 -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 +59 -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/placeholder.md +37 -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/sparkline.md +47 -0
- package/docs/ja/parts/status-badge.md +44 -0
- package/docs/ja/parts/trend-indicator.md +26 -0
- package/docs/ja/routing.md +175 -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 +153 -0
- package/skills/vantage-app/SKILL.md +291 -0
- package/skills/vantage-pitfalls/SKILL.md +139 -0
- package/templates/AGENTS.md +313 -0
- package/theme.css +178 -40
- package/dist/chunk-73J5ZD4C.js.map +0 -1
- package/dist/chunk-ATYZ45XL.js +0 -19
- package/dist/chunk-ATYZ45XL.js.map +0 -1
- package/dist/chunk-ZGDU5YLH.js.map +0 -1
|
@@ -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.
|
|
@@ -0,0 +1,28 @@
|
|
|
1
|
+
# Input
|
|
2
|
+
|
|
3
|
+
> The single-line text input.
|
|
4
|
+
|
|
5
|
+
A plain `<input>` with the theme's border and focus ring. The props are the native ones, `type`
|
|
6
|
+
included.
|
|
7
|
+
|
|
8
|
+
```tsx
|
|
9
|
+
import { Input } from "@squadbase/vantage/ui";
|
|
10
|
+
```
|
|
11
|
+
|
|
12
|
+
Tie a [`Label`](ui/label) to it with `htmlFor`.
|
|
13
|
+
|
|
14
|
+
## States
|
|
15
|
+
|
|
16
|
+
| Written as | Looks like |
|
|
17
|
+
| --- | --- |
|
|
18
|
+
| `disabled` | Dimmed, not interactive |
|
|
19
|
+
| `aria-invalid` | Border and ring turn `destructive` |
|
|
20
|
+
| `readOnly` | Unchanged, but not editable |
|
|
21
|
+
|
|
22
|
+
Validation styling is just `aria-invalid` — pass the boolean straight through.
|
|
23
|
+
|
|
24
|
+
```tsx
|
|
25
|
+
<Input aria-invalid={Boolean(error)} />
|
|
26
|
+
```
|
|
27
|
+
|
|
28
|
+
To attach an icon or button on either end, use [`InputGroup`](ui/input-group).
|
|
@@ -0,0 +1,19 @@
|
|
|
1
|
+
# Label
|
|
2
|
+
|
|
3
|
+
> The form label.
|
|
4
|
+
|
|
5
|
+
A `<label>` with consistent type and a dimmed disabled state. Either tie it with `htmlFor` or wrap
|
|
6
|
+
the control.
|
|
7
|
+
|
|
8
|
+
```tsx
|
|
9
|
+
import { Label } from "@squadbase/vantage/ui";
|
|
10
|
+
```
|
|
11
|
+
|
|
12
|
+
Wrapping a checkbox or switch in a `Label` makes the text clickable too.
|
|
13
|
+
|
|
14
|
+
```tsx
|
|
15
|
+
<Label className="flex items-center gap-2">
|
|
16
|
+
<Switch />
|
|
17
|
+
Auto-refresh
|
|
18
|
+
</Label>
|
|
19
|
+
```
|
|
@@ -0,0 +1,19 @@
|
|
|
1
|
+
# Loading
|
|
2
|
+
|
|
3
|
+
> A centred spinner with a label.
|
|
4
|
+
|
|
5
|
+
The loading state for a whole panel. It carries `role="status"` and `aria-live="polite"`, so screen
|
|
6
|
+
readers announce it too. One of the three state components Vantage adds on top of shadcn/ui,
|
|
7
|
+
alongside `Empty` and `ErrorState`.
|
|
8
|
+
|
|
9
|
+
```tsx
|
|
10
|
+
import { Loading } from "@squadbase/vantage/ui";
|
|
11
|
+
```
|
|
12
|
+
|
|
13
|
+
| Prop | Type | Default | Description |
|
|
14
|
+
| --- | --- | --- | --- |
|
|
15
|
+
| `label` | `string` | `"Loading…"` | Text shown next to the spinner. |
|
|
16
|
+
| `className` | `string` | | Classes to add. By default it centres within a 30vh minimum height. |
|
|
17
|
+
|
|
18
|
+
To hold the layout while waiting use [`Skeleton`](ui/skeleton); in tight spots such
|
|
19
|
+
as a button, [`Spinner`](ui/spinner).
|
|
@@ -0,0 +1,34 @@
|
|
|
1
|
+
# Popover
|
|
2
|
+
|
|
3
|
+
> A bubble anchored to its trigger.
|
|
4
|
+
|
|
5
|
+
A panel that opens anchored to an element. If you need to trap focus, use
|
|
6
|
+
[`Dialog`](ui/dialog); for a caption alone, [`Tooltip`](ui/tooltip).
|
|
7
|
+
|
|
8
|
+
```tsx
|
|
9
|
+
import {
|
|
10
|
+
Popover,
|
|
11
|
+
PopoverTrigger,
|
|
12
|
+
PopoverContent,
|
|
13
|
+
PopoverHeader,
|
|
14
|
+
PopoverTitle,
|
|
15
|
+
PopoverDescription,
|
|
16
|
+
} from "@squadbase/vantage/ui";
|
|
17
|
+
```
|
|
18
|
+
|
|
19
|
+
## Placement
|
|
20
|
+
|
|
21
|
+
Set by `PopoverContent`'s `side` (default `bottom`), `align` (default `center`) and `sideOffset`
|
|
22
|
+
(default `4`).
|
|
23
|
+
|
|
24
|
+
## Matching the trigger's width
|
|
25
|
+
|
|
26
|
+
Base UI exposes a `--anchor-width` CSS variable — the equivalent of Radix's
|
|
27
|
+
`--radix-popover-trigger-width`.
|
|
28
|
+
|
|
29
|
+
```tsx
|
|
30
|
+
<PopoverContent className="w-(--anchor-width)">…</PopoverContent>
|
|
31
|
+
```
|
|
32
|
+
|
|
33
|
+
> [!NOTE]
|
|
34
|
+
> To make the trigger a button write `render={<Button />}`. Base UI has no `asChild`.
|
|
@@ -0,0 +1,28 @@
|
|
|
1
|
+
# Progress
|
|
2
|
+
|
|
3
|
+
> The progress bar, with optional label and value.
|
|
4
|
+
|
|
5
|
+
A bar for 0–100 progress. Put a label or value inside `Progress` and the bar is drawn beneath them
|
|
6
|
+
automatically.
|
|
7
|
+
|
|
8
|
+
```tsx
|
|
9
|
+
import {
|
|
10
|
+
Progress,
|
|
11
|
+
ProgressTrack,
|
|
12
|
+
ProgressIndicator,
|
|
13
|
+
ProgressLabel,
|
|
14
|
+
ProgressValue,
|
|
15
|
+
} from "@squadbase/vantage/ui";
|
|
16
|
+
```
|
|
17
|
+
|
|
18
|
+
## Parts
|
|
19
|
+
|
|
20
|
+
| Part | Role |
|
|
21
|
+
| --- | --- |
|
|
22
|
+
| `Progress` | The root. `value` (`null` for indeterminate) |
|
|
23
|
+
| `ProgressLabel` | The heading |
|
|
24
|
+
| `ProgressValue` | The current value, as a percentage by default |
|
|
25
|
+
| `ProgressTrack` / `ProgressIndicator` | The bar itself — `Progress` renders these for you |
|
|
26
|
+
|
|
27
|
+
Pass `value={null}` when the total isn't known. If you only mean "loading",
|
|
28
|
+
[`Skeleton`](ui/skeleton) or [`Spinner`](ui/spinner) says it better.
|
|
@@ -0,0 +1,23 @@
|
|
|
1
|
+
# ScrollArea
|
|
2
|
+
|
|
3
|
+
> A scroll region with a consistent, non-native scrollbar.
|
|
4
|
+
|
|
5
|
+
Gives a fixed-height region a styled scrollbar instead of the OS one — dropdown contents, long log
|
|
6
|
+
output, and the like.
|
|
7
|
+
|
|
8
|
+
```tsx
|
|
9
|
+
import { ScrollArea, ScrollBar } from "@squadbase/vantage/ui";
|
|
10
|
+
```
|
|
11
|
+
|
|
12
|
+
Set the height (or width) via `className`. Vertical is the default; for horizontal scrolling add a
|
|
13
|
+
`ScrollBar orientation="horizontal"` child.
|
|
14
|
+
|
|
15
|
+
```tsx
|
|
16
|
+
<ScrollArea className="w-96 whitespace-nowrap">
|
|
17
|
+
<div className="flex gap-3">…</div>
|
|
18
|
+
<ScrollBar orientation="horizontal" />
|
|
19
|
+
</ScrollArea>
|
|
20
|
+
```
|
|
21
|
+
|
|
22
|
+
> [!NOTE]
|
|
23
|
+
> If you only want to hide the scrollbar, `theme.css` defines a `no-scrollbar` utility.
|
|
@@ -0,0 +1,63 @@
|
|
|
1
|
+
# Select
|
|
2
|
+
|
|
3
|
+
> The single-choice select. Note that onValueChange can hand you null.
|
|
4
|
+
|
|
5
|
+
Pick one option from a list. When there are many options and you want search, use
|
|
6
|
+
[`SearchableSelect`](parts/searchable-select); for a handful shown side by side,
|
|
7
|
+
[`SegmentedControl`](parts/segmented-control).
|
|
8
|
+
|
|
9
|
+
```tsx
|
|
10
|
+
import {
|
|
11
|
+
Select,
|
|
12
|
+
SelectTrigger,
|
|
13
|
+
SelectValue,
|
|
14
|
+
SelectContent,
|
|
15
|
+
SelectGroup,
|
|
16
|
+
SelectLabel,
|
|
17
|
+
SelectItem,
|
|
18
|
+
SelectSeparator,
|
|
19
|
+
SelectScrollUpButton,
|
|
20
|
+
SelectScrollDownButton,
|
|
21
|
+
} from "@squadbase/vantage/ui";
|
|
22
|
+
```
|
|
23
|
+
|
|
24
|
+
## Parts
|
|
25
|
+
|
|
26
|
+
| Part | Role |
|
|
27
|
+
| --- | --- |
|
|
28
|
+
| `Select` | The state: `value` / `defaultValue` / `onValueChange` / `items` |
|
|
29
|
+
| `SelectTrigger` | The closed state. `size`: `default` \| `sm` |
|
|
30
|
+
| `SelectValue` | What's selected; `placeholder` covers "nothing yet" |
|
|
31
|
+
| `SelectContent` | The open list |
|
|
32
|
+
| `SelectGroup` + `SelectLabel` | A group with a heading |
|
|
33
|
+
| `SelectItem` | One option; `value` is required |
|
|
34
|
+
|
|
35
|
+
> [!WARNING]
|
|
36
|
+
> `onValueChange` hands you **`string | null`** — Base UI allows deselection. Always guard for `null`.
|
|
37
|
+
>
|
|
38
|
+
> ```tsx
|
|
39
|
+
> <Select onValueChange={(value) => value !== null && setRegion(value)}>
|
|
40
|
+
> ```
|
|
41
|
+
|
|
42
|
+
> [!WARNING]
|
|
43
|
+
> `SelectValue` shows the **raw selected `value`** by default — it never looks inside `SelectItem`.
|
|
44
|
+
> With `value="kanto"` the trigger reads `kanto`, not "Kanto". Give `Select` the value-to-label map
|
|
45
|
+
> via `items`.
|
|
46
|
+
>
|
|
47
|
+
> ```tsx
|
|
48
|
+
> const regions = { hokkaido: "Hokkaido", kanto: "Kanto", kansai: "Kansai" };
|
|
49
|
+
>
|
|
50
|
+
> <Select items={regions} value={region} onValueChange={…}>
|
|
51
|
+
> <SelectTrigger><SelectValue placeholder="Pick a region" /></SelectTrigger>
|
|
52
|
+
> …
|
|
53
|
+
> </Select>;
|
|
54
|
+
> ```
|
|
55
|
+
>
|
|
56
|
+
> If you'd rather not carry `items`, a function child on `SelectValue` does the same job.
|
|
57
|
+
>
|
|
58
|
+
> ```tsx
|
|
59
|
+
> <SelectValue>{(value) => regions[value] ?? "Pick a region"}</SelectValue>
|
|
60
|
+
> ```
|
|
61
|
+
|
|
62
|
+
`SelectContent` opens over the trigger with the selected item aligned to it. For a plain dropdown
|
|
63
|
+
below the trigger, pass `alignItemWithTrigger={false}`.
|
|
@@ -0,0 +1,15 @@
|
|
|
1
|
+
# Separator
|
|
2
|
+
|
|
3
|
+
> A single dividing rule.
|
|
4
|
+
|
|
5
|
+
A rule between sections. With `orientation="vertical"` the parent needs a height.
|
|
6
|
+
|
|
7
|
+
```tsx
|
|
8
|
+
import { Separator } from "@squadbase/vantage/ui";
|
|
9
|
+
```
|
|
10
|
+
|
|
11
|
+
| Prop | Type | Default | Description |
|
|
12
|
+
| --- | --- | --- | --- |
|
|
13
|
+
| `orientation` | `"horizontal" \| "vertical"` | `"horizontal"` | Which way the rule runs. |
|
|
14
|
+
|
|
15
|
+
It is decorative, so assistive technology skips it.
|
|
@@ -0,0 +1,28 @@
|
|
|
1
|
+
# Sheet
|
|
2
|
+
|
|
3
|
+
> A panel that slides in from an edge.
|
|
4
|
+
|
|
5
|
+
A panel that slides in from the edge of the screen — for a full set of filters, or an edit form that
|
|
6
|
+
wants more room than a modal.
|
|
7
|
+
|
|
8
|
+
```tsx
|
|
9
|
+
import {
|
|
10
|
+
Sheet,
|
|
11
|
+
SheetTrigger,
|
|
12
|
+
SheetContent,
|
|
13
|
+
SheetHeader,
|
|
14
|
+
SheetTitle,
|
|
15
|
+
SheetDescription,
|
|
16
|
+
SheetFooter,
|
|
17
|
+
SheetClose,
|
|
18
|
+
} from "@squadbase/vantage/ui";
|
|
19
|
+
```
|
|
20
|
+
|
|
21
|
+
The structure matches [`Dialog`](ui/dialog); only the direction differs.
|
|
22
|
+
|
|
23
|
+
| Prop | Type | Default | Description |
|
|
24
|
+
| --- | --- | --- | --- |
|
|
25
|
+
| `side` | `"top" \| "right" \| "bottom" \| "left"` | `"right"` | Goes on `SheetContent`. Which edge it enters from. |
|
|
26
|
+
|
|
27
|
+
`SheetTitle` is required for assistive technology. Keep it and add `className="sr-only"` if it
|
|
28
|
+
shouldn't be visible.
|
|
@@ -0,0 +1,92 @@
|
|
|
1
|
+
# Sidebar
|
|
2
|
+
|
|
3
|
+
> The full collapsible application sidebar kit.
|
|
4
|
+
|
|
5
|
+
A kit of twenty-odd parts for building an application's navigation. If you'd rather just hand over
|
|
6
|
+
an array of nav items, [`AppShell`](parts/app-shell) gets you there faster.
|
|
7
|
+
|
|
8
|
+
```tsx
|
|
9
|
+
import {
|
|
10
|
+
Sidebar,
|
|
11
|
+
SidebarProvider,
|
|
12
|
+
SidebarInset,
|
|
13
|
+
SidebarTrigger,
|
|
14
|
+
SidebarHeader,
|
|
15
|
+
SidebarContent,
|
|
16
|
+
SidebarFooter,
|
|
17
|
+
SidebarGroup,
|
|
18
|
+
SidebarGroupLabel,
|
|
19
|
+
SidebarGroupContent,
|
|
20
|
+
SidebarGroupAction,
|
|
21
|
+
SidebarMenu,
|
|
22
|
+
SidebarMenuItem,
|
|
23
|
+
SidebarMenuButton,
|
|
24
|
+
SidebarMenuAction,
|
|
25
|
+
SidebarMenuBadge,
|
|
26
|
+
SidebarMenuSkeleton,
|
|
27
|
+
SidebarMenuSub,
|
|
28
|
+
SidebarMenuSubItem,
|
|
29
|
+
SidebarMenuSubButton,
|
|
30
|
+
SidebarSeparator,
|
|
31
|
+
SidebarInput,
|
|
32
|
+
SidebarRail,
|
|
33
|
+
useSidebar,
|
|
34
|
+
} from "@squadbase/vantage/ui";
|
|
35
|
+
```
|
|
36
|
+
|
|
37
|
+
## The skeleton
|
|
38
|
+
|
|
39
|
+
`SidebarProvider` owns the open/closed state; `Sidebar` and `SidebarInset` (the content side) sit
|
|
40
|
+
inside it.
|
|
41
|
+
|
|
42
|
+
```tsx
|
|
43
|
+
<SidebarProvider>
|
|
44
|
+
<Sidebar>
|
|
45
|
+
<SidebarHeader>Acme Analytics</SidebarHeader>
|
|
46
|
+
<SidebarContent>
|
|
47
|
+
<SidebarGroup>
|
|
48
|
+
<SidebarGroupLabel>Analytics</SidebarGroupLabel>
|
|
49
|
+
<SidebarGroupContent>
|
|
50
|
+
<SidebarMenu>
|
|
51
|
+
<SidebarMenuItem>
|
|
52
|
+
<SidebarMenuButton isActive>Overview</SidebarMenuButton>
|
|
53
|
+
</SidebarMenuItem>
|
|
54
|
+
<SidebarMenuItem>
|
|
55
|
+
<SidebarMenuButton>Sales</SidebarMenuButton>
|
|
56
|
+
<SidebarMenuBadge>12</SidebarMenuBadge>
|
|
57
|
+
</SidebarMenuItem>
|
|
58
|
+
</SidebarMenu>
|
|
59
|
+
</SidebarGroupContent>
|
|
60
|
+
</SidebarGroup>
|
|
61
|
+
</SidebarContent>
|
|
62
|
+
<SidebarRail />
|
|
63
|
+
</Sidebar>
|
|
64
|
+
|
|
65
|
+
<SidebarInset>
|
|
66
|
+
<SidebarTrigger />
|
|
67
|
+
{children}
|
|
68
|
+
</SidebarInset>
|
|
69
|
+
</SidebarProvider>
|
|
70
|
+
```
|
|
71
|
+
|
|
72
|
+
## Worth knowing
|
|
73
|
+
|
|
74
|
+
| Thing | Effect |
|
|
75
|
+
| --- | --- |
|
|
76
|
+
| `isActive` on `SidebarMenuButton` | Highlights the current page |
|
|
77
|
+
| `tooltip` on `SidebarMenuButton` | Shows the label while collapsed |
|
|
78
|
+
| `render` on `SidebarMenuButton` | Swaps in a link component |
|
|
79
|
+
| `SidebarRail` | The thin strip you drag to collapse |
|
|
80
|
+
| `SidebarMenuSkeleton` | A loading menu |
|
|
81
|
+
| `useSidebar()` | Reads the open state and the mobile flag |
|
|
82
|
+
|
|
83
|
+
## Making items links
|
|
84
|
+
|
|
85
|
+
```tsx
|
|
86
|
+
import { Link } from "@squadbase/vantage/router";
|
|
87
|
+
|
|
88
|
+
<SidebarMenuButton render={<Link to="/sales" />}>Sales</SidebarMenuButton>;
|
|
89
|
+
```
|
|
90
|
+
|
|
91
|
+
> [!NOTE]
|
|
92
|
+
> Base UI has no `asChild` — pass an element to `render`.
|
|
@@ -0,0 +1,16 @@
|
|
|
1
|
+
# Skeleton
|
|
2
|
+
|
|
3
|
+
> A box shaped like the content that will replace it.
|
|
4
|
+
|
|
5
|
+
A placeholder shaped like whatever is coming. Unlike [`Loading`](ui/loading)'s
|
|
6
|
+
full-panel spinner, it keeps the layout intact while you wait.
|
|
7
|
+
|
|
8
|
+
```tsx
|
|
9
|
+
import { Skeleton } from "@squadbase/vantage/ui";
|
|
10
|
+
```
|
|
11
|
+
|
|
12
|
+
Size it with `className` (`h-4 w-32` and friends). Match the height of the real element and the page
|
|
13
|
+
won't jump when the data lands.
|
|
14
|
+
|
|
15
|
+
For dashboard tiles, [`DashboardCardSkeleton`](parts/dashboard-card) is already the
|
|
16
|
+
right shape.
|
|
@@ -0,0 +1,21 @@
|
|
|
1
|
+
# Slider
|
|
2
|
+
|
|
3
|
+
> Pick a number by dragging. Ranges included.
|
|
4
|
+
|
|
5
|
+
Choose a number by dragging. Pass an array as `value` and you get one thumb per entry — a range.
|
|
6
|
+
|
|
7
|
+
```tsx
|
|
8
|
+
import { Slider } from "@squadbase/vantage/ui";
|
|
9
|
+
```
|
|
10
|
+
|
|
11
|
+
| Prop | Type | Default | Description |
|
|
12
|
+
| --- | --- | --- | --- |
|
|
13
|
+
| `value` | `number \| number[]` | | Thumb position(s). An array makes it a range. |
|
|
14
|
+
| `defaultValue` | `number \| number[]` | | Initial value when uncontrolled. |
|
|
15
|
+
| `onValueChange` | `(value: number \| number[]) => void` | | Fired on change, in the same shape you passed to `value`. |
|
|
16
|
+
| `min` | `number` | `0` | Lower bound. |
|
|
17
|
+
| `max` | `number` | `100` | Upper bound. |
|
|
18
|
+
| `step` | `number` | `1` | Increment. |
|
|
19
|
+
| `disabled` | `boolean` | | Disable interaction. |
|
|
20
|
+
|
|
21
|
+
Thumbs are aligned to the track's edges, so they never overhang it at `min` or `max`.
|
|
@@ -0,0 +1,14 @@
|
|
|
1
|
+
# Spinner
|
|
2
|
+
|
|
3
|
+
> The smallest waiting indicator.
|
|
4
|
+
|
|
5
|
+
Just a spinning icon — for tight spots like inside a button.
|
|
6
|
+
|
|
7
|
+
```tsx
|
|
8
|
+
import { Spinner } from "@squadbase/vantage/ui";
|
|
9
|
+
```
|
|
10
|
+
|
|
11
|
+
It is an `<svg>`, so `size-*` sets the size and `text-*` the colour.
|
|
12
|
+
|
|
13
|
+
For a whole panel use [`Loading`](ui/loading); to hold the layout while you wait,
|
|
14
|
+
[`Skeleton`](ui/skeleton).
|
|
@@ -0,0 +1,19 @@
|
|
|
1
|
+
# Switch
|
|
2
|
+
|
|
3
|
+
> A toggle for settings that take effect at once.
|
|
4
|
+
|
|
5
|
+
For a setting that applies immediately. If it only takes effect on submit,
|
|
6
|
+
[`Checkbox`](ui/checkbox) is the better fit.
|
|
7
|
+
|
|
8
|
+
```tsx
|
|
9
|
+
import { Switch } from "@squadbase/vantage/ui";
|
|
10
|
+
```
|
|
11
|
+
|
|
12
|
+
| Prop | Type | Default | Description |
|
|
13
|
+
| --- | --- | --- | --- |
|
|
14
|
+
| `checked` | `boolean` | | On or off. |
|
|
15
|
+
| `onCheckedChange` | `(checked: boolean) => void` | | Fired on change. |
|
|
16
|
+
| `size` | `"default" \| "sm"` | `"default"` | Scale. |
|
|
17
|
+
| `disabled` | `boolean` | | Disable interaction. |
|
|
18
|
+
|
|
19
|
+
Wrap it in a [`Label`](ui/label) so the text is clickable too.
|