@jovertical/mise-design-system 1.0.0 → 1.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 +20 -0
- package/bin/mise-theme.js +4 -1
- package/dist/tokens/cli.d.ts +1 -1
- package/dist/tokens/cli.js +23 -2
- package/dist/tokens/info.d.ts +10 -0
- package/dist/tokens/info.js +62 -0
- package/package.json +3 -1
- package/skills/mise/SKILL.md +159 -0
- package/skills/mise/components/actions.md +200 -0
- package/skills/mise/components/data-display.md +728 -0
- package/skills/mise/components/feedback.md +198 -0
- package/skills/mise/components/forms.md +712 -0
- package/skills/mise/components/layout.md +178 -0
- package/skills/mise/components/navigation.md +250 -0
- package/skills/mise/components/overlays.md +291 -0
- package/skills/mise/components/typography.md +36 -0
- package/skills/mise/recipes/dashboard-page.md +40 -0
- package/skills/mise/recipes/dashboard-page.svelte +132 -0
- package/skills/mise/recipes/data-table.md +39 -0
- package/skills/mise/recipes/data-table.svelte +130 -0
- package/skills/mise/recipes/form-sveltekit.svelte +79 -0
- package/skills/mise/recipes/form.md +82 -0
- package/skills/mise/recipes/form.svelte +158 -0
- package/skills/mise/setup.md +99 -0
- package/skills/mise/theming.md +82 -0
package/README.md
CHANGED
|
@@ -92,6 +92,26 @@ Import `src/mise-theme.css` in place of `theme.css`. `emitThemeCss(config)`
|
|
|
92
92
|
is exported from `/tokens` too, if you would rather call it in your own build
|
|
93
93
|
script.
|
|
94
94
|
|
|
95
|
+
## AI agents
|
|
96
|
+
|
|
97
|
+
mise ships an agent skill, `skills/mise/`, that teaches a coding agent in your
|
|
98
|
+
app which mise component does which job, every component's props and
|
|
99
|
+
defaults, setup per stack, theming, and worked recipes. Install it with the
|
|
100
|
+
[`skills` CLI](https://github.com/vercel-labs/skills):
|
|
101
|
+
|
|
102
|
+
```sh
|
|
103
|
+
npx skills add jovertical/mise-design-system --skill mise
|
|
104
|
+
```
|
|
105
|
+
|
|
106
|
+
The same skill is in the package at
|
|
107
|
+
`node_modules/@jovertical/mise-design-system/skills/mise/`, matching the
|
|
108
|
+
installed version. `npx skills experimental_sync` links it from there, so it
|
|
109
|
+
updates with mise.
|
|
110
|
+
|
|
111
|
+
The skill reads the app's setup with `npx mise-theme info --json`: the
|
|
112
|
+
installed version, the stack, the theme config and the stylesheet that imports
|
|
113
|
+
mise.
|
|
114
|
+
|
|
95
115
|
## Develop
|
|
96
116
|
|
|
97
117
|
```sh
|
package/bin/mise-theme.js
CHANGED
|
@@ -1,7 +1,10 @@
|
|
|
1
1
|
#!/usr/bin/env node
|
|
2
|
+
import { readFile } from 'node:fs/promises'
|
|
3
|
+
|
|
2
4
|
import { runThemeCli } from '../dist/tokens/cli.js'
|
|
3
5
|
|
|
4
|
-
const {
|
|
6
|
+
const { version } = JSON.parse(await readFile(new URL('../package.json', import.meta.url), 'utf8'))
|
|
7
|
+
const { code, message } = await runThemeCli(process.argv.slice(2), process.cwd(), version)
|
|
5
8
|
|
|
6
9
|
if (code === 0) console.log(message)
|
|
7
10
|
else console.error(message)
|
package/dist/tokens/cli.d.ts
CHANGED
|
@@ -8,4 +8,4 @@ export interface CliResult {
|
|
|
8
8
|
* `dist/styles/`, so the output matches the packaged stylesheet line for line,
|
|
9
9
|
* apart from the theme.
|
|
10
10
|
*/
|
|
11
|
-
export declare function runThemeCli(argv: string[], cwd?: string): Promise<CliResult>;
|
|
11
|
+
export declare function runThemeCli(argv: string[], cwd?: string, version?: string): Promise<CliResult>;
|
package/dist/tokens/cli.js
CHANGED
|
@@ -2,7 +2,8 @@ import { mkdir, readFile, writeFile } from 'node:fs/promises';
|
|
|
2
2
|
import { dirname, join, resolve } from 'node:path';
|
|
3
3
|
import { fileURLToPath, pathToFileURL } from 'node:url';
|
|
4
4
|
import { themeStylesheet } from './emit-web.js';
|
|
5
|
-
|
|
5
|
+
import { projectInfo } from './info.js';
|
|
6
|
+
const USAGE = 'Usage: mise-theme <config> -o <output.css>\n mise-theme info [--json]';
|
|
6
7
|
/**
|
|
7
8
|
* A path rather than a `new URL(…)`, because a global `URL` that is not
|
|
8
9
|
* Node's (jsdom's, in a test) is rejected by `fs`.
|
|
@@ -14,7 +15,9 @@ const COMPONENTS_CSS = join(dirname(fileURLToPath(import.meta.url)), '..', 'styl
|
|
|
14
15
|
* `dist/styles/`, so the output matches the packaged stylesheet line for line,
|
|
15
16
|
* apart from the theme.
|
|
16
17
|
*/
|
|
17
|
-
export async function runThemeCli(argv, cwd = process.cwd()) {
|
|
18
|
+
export async function runThemeCli(argv, cwd = process.cwd(), version = '0.0.0') {
|
|
19
|
+
if (argv[0] === 'info')
|
|
20
|
+
return runInfo(argv.includes('--json'), cwd, version);
|
|
18
21
|
const [configPath, flag, outputPath] = argv;
|
|
19
22
|
if (!configPath || flag !== '-o' || !outputPath)
|
|
20
23
|
return { code: 1, message: USAGE };
|
|
@@ -35,3 +38,21 @@ export async function runThemeCli(argv, cwd = process.cwd()) {
|
|
|
35
38
|
return { code: 1, message: error instanceof Error ? error.message : String(error) };
|
|
36
39
|
}
|
|
37
40
|
}
|
|
41
|
+
/**
|
|
42
|
+
* `mise-theme info`: the facts about the app in `cwd` that the consumer skill
|
|
43
|
+
* reads before writing UI. `version` is mise's own, passed in by the binary.
|
|
44
|
+
*/
|
|
45
|
+
async function runInfo(json, cwd, version) {
|
|
46
|
+
try {
|
|
47
|
+
const info = await projectInfo(cwd, version);
|
|
48
|
+
const message = json
|
|
49
|
+
? JSON.stringify(info, null, 2)
|
|
50
|
+
: Object.entries(info)
|
|
51
|
+
.map(([key, value]) => `${key}: ${value ?? '—'}`)
|
|
52
|
+
.join('\n');
|
|
53
|
+
return { code: 0, message };
|
|
54
|
+
}
|
|
55
|
+
catch (error) {
|
|
56
|
+
return { code: 1, message: error instanceof Error ? error.message : String(error) };
|
|
57
|
+
}
|
|
58
|
+
}
|
|
@@ -0,0 +1,10 @@
|
|
|
1
|
+
export type ProjectInfo = {
|
|
2
|
+
version: string;
|
|
3
|
+
stack: 'sveltekit' | 'inertia' | 'vite';
|
|
4
|
+
svelte: string | null;
|
|
5
|
+
tailwind: string | null;
|
|
6
|
+
themeConfig: string | null;
|
|
7
|
+
stylesheet: string | null;
|
|
8
|
+
form: boolean;
|
|
9
|
+
};
|
|
10
|
+
export declare function projectInfo(cwd: string, version: string): Promise<ProjectInfo>;
|
|
@@ -0,0 +1,62 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* What an agent needs to know about the app it is working in before it writes
|
|
3
|
+
* mise UI: which version, which stack, where the theme and the stylesheet are.
|
|
4
|
+
* Read-only. The consumer skill runs it on load through `mise-theme info --json`.
|
|
5
|
+
*/
|
|
6
|
+
import { existsSync } from 'node:fs';
|
|
7
|
+
import { readdir, readFile } from 'node:fs/promises';
|
|
8
|
+
import { join, relative } from 'node:path';
|
|
9
|
+
const THEME_CONFIGS = ['mise.theme.js', 'mise.theme.mjs', 'mise.theme.ts'];
|
|
10
|
+
const SKIPPED = new Set([
|
|
11
|
+
'node_modules',
|
|
12
|
+
'.git',
|
|
13
|
+
'vendor',
|
|
14
|
+
'dist',
|
|
15
|
+
'build',
|
|
16
|
+
'.svelte-kit',
|
|
17
|
+
'storage',
|
|
18
|
+
'public',
|
|
19
|
+
]);
|
|
20
|
+
const IMPORT = /@import\s+['"]@jovertical\/mise-design-system\//;
|
|
21
|
+
const MAX_DEPTH = 6;
|
|
22
|
+
async function findStylesheet(cwd, dir = cwd, depth = 0) {
|
|
23
|
+
if (depth > MAX_DEPTH)
|
|
24
|
+
return null;
|
|
25
|
+
const entries = (await readdir(dir, { withFileTypes: true })).sort((a, b) => a.name.localeCompare(b.name));
|
|
26
|
+
for (const entry of entries) {
|
|
27
|
+
const path = join(dir, entry.name);
|
|
28
|
+
if (entry.isFile() &&
|
|
29
|
+
entry.name.endsWith('.css') &&
|
|
30
|
+
IMPORT.test(await readFile(path, 'utf8'))) {
|
|
31
|
+
return relative(cwd, path).split('\\').join('/');
|
|
32
|
+
}
|
|
33
|
+
}
|
|
34
|
+
for (const entry of entries) {
|
|
35
|
+
if (!entry.isDirectory() || SKIPPED.has(entry.name) || entry.name.startsWith('.'))
|
|
36
|
+
continue;
|
|
37
|
+
const found = await findStylesheet(cwd, join(dir, entry.name), depth + 1);
|
|
38
|
+
if (found)
|
|
39
|
+
return found;
|
|
40
|
+
}
|
|
41
|
+
return null;
|
|
42
|
+
}
|
|
43
|
+
export async function projectInfo(cwd, version) {
|
|
44
|
+
const manifestPath = join(cwd, 'package.json');
|
|
45
|
+
if (!existsSync(manifestPath))
|
|
46
|
+
throw new Error(`No package.json in ${cwd}`);
|
|
47
|
+
const manifest = JSON.parse(await readFile(manifestPath, 'utf8'));
|
|
48
|
+
const dependencies = {
|
|
49
|
+
...manifest.dependencies,
|
|
50
|
+
...manifest.devDependencies,
|
|
51
|
+
};
|
|
52
|
+
const has = (name) => name in dependencies;
|
|
53
|
+
return {
|
|
54
|
+
version,
|
|
55
|
+
stack: has('@sveltejs/kit') ? 'sveltekit' : has('@inertiajs/svelte') ? 'inertia' : 'vite',
|
|
56
|
+
svelte: dependencies.svelte ?? null,
|
|
57
|
+
tailwind: dependencies.tailwindcss ?? null,
|
|
58
|
+
themeConfig: THEME_CONFIGS.find((name) => existsSync(join(cwd, name))) ?? null,
|
|
59
|
+
stylesheet: await findStylesheet(cwd),
|
|
60
|
+
form: has('formsnap') && has('sveltekit-superforms'),
|
|
61
|
+
};
|
|
62
|
+
}
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@jovertical/mise-design-system",
|
|
3
|
-
"version": "1.
|
|
3
|
+
"version": "1.1.0",
|
|
4
4
|
"description": "Svelte 5 components and a configurable Tailwind v4 theme for operations dashboards",
|
|
5
5
|
"license": "MIT",
|
|
6
6
|
"type": "module",
|
|
@@ -31,6 +31,7 @@
|
|
|
31
31
|
"dist",
|
|
32
32
|
"bin",
|
|
33
33
|
"LICENSES",
|
|
34
|
+
"skills",
|
|
34
35
|
"!dist/**/*.stories.svelte",
|
|
35
36
|
"!dist/**/*.stories.svelte.d.ts",
|
|
36
37
|
"!dist/**/*.test.*"
|
|
@@ -113,6 +114,7 @@
|
|
|
113
114
|
"scripts": {
|
|
114
115
|
"build": "svelte-kit sync && svelte-package && pnpm build:theme && publint",
|
|
115
116
|
"build:theme": "tsx scripts/build-theme.ts",
|
|
117
|
+
"build:skill": "tsx scripts/build-skill.ts",
|
|
116
118
|
"storybook": "pnpm build:theme && storybook dev -p 6006",
|
|
117
119
|
"build:storybook": "pnpm build:theme && storybook build",
|
|
118
120
|
"check": "svelte-kit sync && svelte-check --tsconfig ./tsconfig.json --fail-on-warnings",
|
|
@@ -0,0 +1,159 @@
|
|
|
1
|
+
---
|
|
2
|
+
name: mise
|
|
3
|
+
description: >-
|
|
4
|
+
Builds Svelte 5 UI in an app that uses @jovertical/mise-design-system: picking the mise
|
|
5
|
+
component for a job, its props and defaults, theming, and setting mise up. Activates when
|
|
6
|
+
writing or changing Svelte UI in an app that depends on @jovertical/mise-design-system, or
|
|
7
|
+
setting mise up in a new app; or when the user mentions mise, the design system, a mise
|
|
8
|
+
component, tone, variant, or mise-theme.
|
|
9
|
+
---
|
|
10
|
+
|
|
11
|
+
# mise
|
|
12
|
+
|
|
13
|
+
mise is a library of Svelte 5 components and a Tailwind v4 theme for operations dashboards:
|
|
14
|
+
locations, shifts, orders, stock. This skill is for an app that depends on it. Before writing
|
|
15
|
+
any UI, find the mise component that does the job; write your own only when none does.
|
|
16
|
+
|
|
17
|
+
## This app
|
|
18
|
+
|
|
19
|
+
```json
|
|
20
|
+
!`npx --no-install mise-theme info --json`
|
|
21
|
+
```
|
|
22
|
+
|
|
23
|
+
`stack` says how the app is wired (`sveltekit`, `inertia` or `vite`), `stylesheet` where mise's
|
|
24
|
+
theme is imported, `themeConfig` whether the app has its own theme, and `form` whether
|
|
25
|
+
`mise/form` can be used. If the command failed, mise is not installed here: follow
|
|
26
|
+
[setup.md](setup.md).
|
|
27
|
+
|
|
28
|
+
## Which copy to trust
|
|
29
|
+
|
|
30
|
+
This skill may be newer or older than the mise the app has installed. When they disagree, read
|
|
31
|
+
`node_modules/@jovertical/mise-design-system/skills/mise/` instead: that copy ships with the
|
|
32
|
+
installed `version` above, and its `components/` files list exactly the props that version
|
|
33
|
+
takes.
|
|
34
|
+
|
|
35
|
+
## Rules
|
|
36
|
+
|
|
37
|
+
- **Use a mise component before writing UI.** A badge, a card, a table, an empty state or a
|
|
38
|
+
confirmation dialog almost certainly exists; the index below says which.
|
|
39
|
+
- **Compose before customising.** A card of facts is `Card` with `FactList` in it, not a styled
|
|
40
|
+
`div`. A dashboard is `PageLayout`, `PageHeader`, `CardGrid` and `StatTile`s.
|
|
41
|
+
- **Props before classes.** Colour is `tone`: `neutral`, `primary`, `info`, `success`,
|
|
42
|
+
`warning` or `critical` (never `destructive`, `error` or `danger`). Treatment is `variant`.
|
|
43
|
+
Size is `size`: `sm`, `md` (the default) or `lg`. States are bare adjectives: `loading`,
|
|
44
|
+
`invalid`, `disabled`.
|
|
45
|
+
- **Semantic colours only.** `bg-primary`, `text-muted-foreground`, `border-border`. Never a
|
|
46
|
+
palette class (`bg-blue-500`) or a `dark:` colour override: the theme handles dark mode.
|
|
47
|
+
- **`class` is for layout**: margin, width, grid placement. Do not restyle a component's
|
|
48
|
+
colours, radius or type through `class`; change the theme ([theming.md](theming.md)).
|
|
49
|
+
- **A neutral fill on the page** is `bg-foreground/[0.07]`, the same wash mise's neutral badges
|
|
50
|
+
use. `bg-muted` is the page canvas, so a `bg-muted` chip disappears on it.
|
|
51
|
+
- **The app formats, mise displays.** Money, dates and statuses are formatted by the app.
|
|
52
|
+
`NumberInput` with `format="currency"` takes and reports integer cents.
|
|
53
|
+
- **Every component** takes `class` and spreads other attributes onto its root, and every part
|
|
54
|
+
takes `bind:ref`. Overlays and inputs use `bind:open` and `bind:value`.
|
|
55
|
+
- **For the app's own components**, mise exports `cn` (class merging), the `Tone` and `Size`
|
|
56
|
+
types, `TONES`, and the tone class maps (`TONE_SOFT_CLASS`, `TONE_SOLID_CLASS`,
|
|
57
|
+
`TONE_TEXT_CLASS`, `TONE_FILL_CLASS` and the rest), so a custom badge-like element matches
|
|
58
|
+
mise's colours.
|
|
59
|
+
|
|
60
|
+
## Which component
|
|
61
|
+
|
|
62
|
+
Each line is a job and the component that does it. The group files list every part, prop,
|
|
63
|
+
type and default.
|
|
64
|
+
|
|
65
|
+
**Actions** ([components/actions.md](components/actions.md))
|
|
66
|
+
|
|
67
|
+
- A button, or a link that looks like one (`href`): `Button`
|
|
68
|
+
- A menu of actions on a row or a page: `DropdownMenu`
|
|
69
|
+
- A searchable list of commands or a palette (`CommandDialog`): `Command`
|
|
70
|
+
- The light and dark switch: `ThemeToggle`, inside a `ThemeProvider`
|
|
71
|
+
|
|
72
|
+
**Forms** ([components/forms.md](components/forms.md))
|
|
73
|
+
|
|
74
|
+
- A label, description and error around any input: `Field` (with `Label`)
|
|
75
|
+
- Text: `Input`; several lines: `Textarea`
|
|
76
|
+
- An input with an icon, a prefix or a button inside it: `InputGroup`
|
|
77
|
+
- A number, a price or a count: `NumberInput`, never `Input type="number"`
|
|
78
|
+
- An amount and its unit (2.5 kg): `QuantityInput`
|
|
79
|
+
- One choice from a few: `RadioGroup`; when each choice needs a description or media:
|
|
80
|
+
`ChoiceRow`
|
|
81
|
+
- One choice from many: `Select`; searchable or several values: `Combobox`
|
|
82
|
+
- On or off: `Switch`; with a label and description in a row: `SwitchField`; a tick:
|
|
83
|
+
`Checkbox`
|
|
84
|
+
- A date: `DatePicker`; a calendar on the page: `Calendar`; a time: `TimePicker`
|
|
85
|
+
- A one-time code: `InputOTP`
|
|
86
|
+
- An image or file upload: `MediaDropzone`
|
|
87
|
+
- Segmented buttons: `ToggleGroup`; one pressed state: `Toggle`; joined buttons and inputs:
|
|
88
|
+
`ButtonGroup`
|
|
89
|
+
- A validated form in SvelteKit: `Form`, from `@jovertical/mise-design-system/form`. It needs
|
|
90
|
+
SvelteKit; in an Inertia or plain Vite app use `Field` with the app's own form state
|
|
91
|
+
([recipes/form.md](recipes/form.md))
|
|
92
|
+
|
|
93
|
+
**Navigation** ([components/navigation.md](components/navigation.md))
|
|
94
|
+
|
|
95
|
+
- The app's side menu: `Sidebar`
|
|
96
|
+
- Where am I: `Breadcrumb`
|
|
97
|
+
- Sections of one page: `Tabs`
|
|
98
|
+
- The steps of a flow: `Stepper`
|
|
99
|
+
|
|
100
|
+
**Layout** ([components/layout.md](components/layout.md))
|
|
101
|
+
|
|
102
|
+
- The page frame: `PageLayout`, with `PageHeader` for the title, description and actions
|
|
103
|
+
- A surface: `Card`
|
|
104
|
+
- Cards in a grid: `CardGrid`; rows inside one card: `CardList`
|
|
105
|
+
- A collapsible card for a side column: `AsideCard`
|
|
106
|
+
- What one step produced, read-only: `SummaryCard`
|
|
107
|
+
- Show and hide a section: `Collapsible`
|
|
108
|
+
- A rule: `Separator`
|
|
109
|
+
|
|
110
|
+
**Overlays** ([components/overlays.md](components/overlays.md))
|
|
111
|
+
|
|
112
|
+
- "Are you sure?": `AlertDialog`
|
|
113
|
+
- A task in a modal: `Dialog`; in a side panel: `Sheet`; from the bottom on mobile: `Drawer`
|
|
114
|
+
- A small floating panel: `Popover`; a preview on hover: `HoverCard`
|
|
115
|
+
- A label on hover: `Tooltip`; a `?` that explains the thing beside it: `Hint`
|
|
116
|
+
|
|
117
|
+
**Feedback** ([components/feedback.md](components/feedback.md))
|
|
118
|
+
|
|
119
|
+
- A message in the page: `Alert`; a toast: `Toaster` once in the layout, then `toast(…)`
|
|
120
|
+
- Loading: `Spinner` inline, `Skeleton` for the shape of what is coming, `LoadingState` for a
|
|
121
|
+
whole panel
|
|
122
|
+
- Nothing here yet: `EmptyState`; to compose your own: `Empty` and its parts
|
|
123
|
+
- An error page (not found, forbidden, failed): `ErrorState`
|
|
124
|
+
- Progress: `Progress`; a route change: `NavigationProgress`
|
|
125
|
+
- A feature the user cannot use yet: `FeaturePreview` for a whole page, `LockedOverlay` over
|
|
126
|
+
one card
|
|
127
|
+
|
|
128
|
+
**Data display** ([components/data-display.md](components/data-display.md))
|
|
129
|
+
|
|
130
|
+
- A status or a tag: `Badge`; a change up or down: `DeltaBadge`
|
|
131
|
+
- A person's picture or initials: `Avatar`; a named thing with its mark and one line:
|
|
132
|
+
`EntityLabel`; a list row with media, text and actions: `Item`
|
|
133
|
+
- An icon in a tinted square: `IconChip`
|
|
134
|
+
- Label and value pairs: `FactList`
|
|
135
|
+
- The headline number of a dashboard: `StatTile`. One figure per tile, with its delta, unit and
|
|
136
|
+
sparkline
|
|
137
|
+
- One subject and several figures with a bar beneath: `MetricRow`
|
|
138
|
+
- One measure drawn as a bar, in a ranked list: `MetricBar`; sub-groups to compare side by
|
|
139
|
+
side: `MetricGrid`
|
|
140
|
+
- A share of a whole as a ring: `RadialStat`; as one segmented bar: `SegmentedBar`
|
|
141
|
+
- A trend in a cell or a tile: `Sparkline`; a full chart: `ChartContainer` (LayerChart)
|
|
142
|
+
- Rows of data: `Table`; with sorting, filtering, selection or pagination: `DataTable`
|
|
143
|
+
- A history of events: `Timeline`
|
|
144
|
+
- Setup steps: `Checklist`, and `ChecklistCard` for the summary card; what a page still needs
|
|
145
|
+
before going live: `ReadinessChecklist`
|
|
146
|
+
- A code read off one screen and typed into another: `SegmentedCode`
|
|
147
|
+
- A row in a nested list: `TreeLeaf`
|
|
148
|
+
|
|
149
|
+
**Typography** ([components/typography.md](components/typography.md))
|
|
150
|
+
|
|
151
|
+
- A heading: `Heading`; body text with size, muting and tone: `Text`
|
|
152
|
+
|
|
153
|
+
## Read next
|
|
154
|
+
|
|
155
|
+
- [setup.md](setup.md): install mise and wire it into SvelteKit, Laravel with Inertia, or Vite.
|
|
156
|
+
- [theming.md](theming.md): presets, the brand colour, radius, fonts and dark mode.
|
|
157
|
+
- [recipes/dashboard-page.md](recipes/dashboard-page.md): a dashboard page.
|
|
158
|
+
- [recipes/form.md](recipes/form.md): a form, in Inertia and in SvelteKit.
|
|
159
|
+
- [recipes/data-table.md](recipes/data-table.md): a data table with filters and row actions.
|
|
@@ -0,0 +1,200 @@
|
|
|
1
|
+
<!-- Generated by pnpm build:skill. Do not edit by hand. -->
|
|
2
|
+
|
|
3
|
+
# Actions
|
|
4
|
+
|
|
5
|
+
## Button
|
|
6
|
+
|
|
7
|
+
`import { Button, buttonVariants, defaultButtonTone } from '@jovertical/mise-design-system'`
|
|
8
|
+
|
|
9
|
+
| Prop | Type | Default | Description |
|
|
10
|
+
| --- | --- | --- | --- |
|
|
11
|
+
| `variant` | `'solid' \| 'soft' \| 'outline' \| 'ghost' \| 'link'` | `'solid'` | |
|
|
12
|
+
| `tone` | `'neutral' \| 'primary' \| 'info' \| 'success' \| 'warning' \| 'critical'` | | Defaults to `primary` for `solid` and `link`, `neutral` for the rest. |
|
|
13
|
+
| `size` | `'sm' \| 'md' \| 'lg'` | `'md'` | |
|
|
14
|
+
| `iconOnly` | `boolean` | `false` | One glyph and no label: square, round, and it needs an `aria-label`. |
|
|
15
|
+
| `children` | `Snippet` | | |
|
|
16
|
+
|
|
17
|
+
Also takes: every `<button>` attribute; every `<a>` attribute.
|
|
18
|
+
|
|
19
|
+
Also exports: `buttonVariants`, `defaultButtonTone`.
|
|
20
|
+
|
|
21
|
+
Types: `ButtonSize` (`'sm' | 'md' | 'lg'`), `ButtonVariant` (`'solid' | 'soft' | 'outline' | 'ghost' | 'link'`).
|
|
22
|
+
|
|
23
|
+
## Command
|
|
24
|
+
|
|
25
|
+
`import { Command, CommandDialog, CommandEmpty, CommandGroup, CommandInput, CommandItem, CommandList, CommandSeparator, CommandShortcut } from '@jovertical/mise-design-system'`
|
|
26
|
+
|
|
27
|
+
A filterable, keyboard-navigable list, grouped by section: the shape a command palette is built on. Bare for an inline picker; `CommandDialog` puts it in a dialog.
|
|
28
|
+
|
|
29
|
+
Also takes: bits-ui `Command.Root` props.
|
|
30
|
+
|
|
31
|
+
### `CommandDialog`
|
|
32
|
+
|
|
33
|
+
`Command` in a `Dialog`, for a palette that takes over the screen. The title and description are for a screen reader only.
|
|
34
|
+
|
|
35
|
+
| Prop | Type | Default | Description |
|
|
36
|
+
| --- | --- | --- | --- |
|
|
37
|
+
| `title` | `string` | `'Command palette'` | |
|
|
38
|
+
| `description` | `string` | `'Search for a command to run.'` | |
|
|
39
|
+
| `showCloseButton` | `boolean` | `true` | |
|
|
40
|
+
| `class` | `string` | | |
|
|
41
|
+
| `children` (required) | `Snippet` | | |
|
|
42
|
+
|
|
43
|
+
Also takes: bits-ui `Dialog.Root` props except `children`, `child`; bits-ui `Command.Root` props except `children`, `child`.
|
|
44
|
+
|
|
45
|
+
### `CommandEmpty`
|
|
46
|
+
|
|
47
|
+
Shown when nothing matches what was typed.
|
|
48
|
+
|
|
49
|
+
Also takes: bits-ui `Command.Empty` props.
|
|
50
|
+
|
|
51
|
+
### `CommandGroup`
|
|
52
|
+
|
|
53
|
+
A section of items, under a small muted heading.
|
|
54
|
+
|
|
55
|
+
| Prop | Type | Default | Description |
|
|
56
|
+
| --- | --- | --- | --- |
|
|
57
|
+
| `heading` | `string` | | |
|
|
58
|
+
|
|
59
|
+
Also takes: bits-ui `Command.Group` props.
|
|
60
|
+
|
|
61
|
+
### `CommandInput`
|
|
62
|
+
|
|
63
|
+
The search field, with its glyph, ruled off from the list below.
|
|
64
|
+
|
|
65
|
+
Also takes: bits-ui `Command.Input` props.
|
|
66
|
+
|
|
67
|
+
### `CommandItem`
|
|
68
|
+
|
|
69
|
+
One command. The highlighted row takes the muted wash, as a menu row does.
|
|
70
|
+
|
|
71
|
+
Also takes: bits-ui `Command.Item` props.
|
|
72
|
+
|
|
73
|
+
### `CommandList`
|
|
74
|
+
|
|
75
|
+
The scrolling list of groups and items.
|
|
76
|
+
|
|
77
|
+
Also takes: bits-ui `Command.List` props.
|
|
78
|
+
|
|
79
|
+
### `CommandSeparator`
|
|
80
|
+
|
|
81
|
+
A rule between groups.
|
|
82
|
+
|
|
83
|
+
Also takes: bits-ui `Command.Separator` props.
|
|
84
|
+
|
|
85
|
+
### `CommandShortcut`
|
|
86
|
+
|
|
87
|
+
A keyboard shortcut, muted at the end of the item.
|
|
88
|
+
|
|
89
|
+
Also takes: every `<span>` attribute.
|
|
90
|
+
|
|
91
|
+
## DropdownMenu
|
|
92
|
+
|
|
93
|
+
`import { DropdownMenu, DropdownMenuCheckboxItem, DropdownMenuContent, DropdownMenuGroup, DropdownMenuItem, DropdownMenuLabel, DropdownMenuPortal, DropdownMenuRadioGroup, DropdownMenuRadioItem, DropdownMenuSeparator, DropdownMenuShortcut, DropdownMenuSub, DropdownMenuSubContent, DropdownMenuSubTrigger, DropdownMenuTrigger } from '@jovertical/mise-design-system'`
|
|
94
|
+
|
|
95
|
+
Also takes: bits-ui `DropdownMenu.Root` props.
|
|
96
|
+
|
|
97
|
+
### `DropdownMenuCheckboxItem`
|
|
98
|
+
|
|
99
|
+
| Prop | Type | Default | Description |
|
|
100
|
+
| --- | --- | --- | --- |
|
|
101
|
+
| `children` | `Snippet` | | |
|
|
102
|
+
|
|
103
|
+
Also takes: bits-ui `DropdownMenu.CheckboxItem` props except `children`, `child`.
|
|
104
|
+
|
|
105
|
+
### `DropdownMenuContent`
|
|
106
|
+
|
|
107
|
+
`min-w-44` (176px) by default, the width menus kept asking for.
|
|
108
|
+
|
|
109
|
+
| Prop | Type | Default | Description |
|
|
110
|
+
| --- | --- | --- | --- |
|
|
111
|
+
| `portalProps` | `DropdownMenuPrimitive.PortalProps` | | |
|
|
112
|
+
|
|
113
|
+
Also takes: bits-ui `DropdownMenu.Content` props.
|
|
114
|
+
|
|
115
|
+
### `DropdownMenuGroup`
|
|
116
|
+
|
|
117
|
+
Also takes: bits-ui `DropdownMenu.Group` props.
|
|
118
|
+
|
|
119
|
+
### `DropdownMenuItem`
|
|
120
|
+
|
|
121
|
+
| Prop | Type | Default | Description |
|
|
122
|
+
| --- | --- | --- | --- |
|
|
123
|
+
| `inset` | `boolean` | | |
|
|
124
|
+
| `variant` | `'default' \| 'destructive'` | `'default'` | `destructive` for an action that removes or ends something. |
|
|
125
|
+
|
|
126
|
+
Also takes: bits-ui `DropdownMenu.Item` props.
|
|
127
|
+
|
|
128
|
+
### `DropdownMenuLabel`
|
|
129
|
+
|
|
130
|
+
| Prop | Type | Default | Description |
|
|
131
|
+
| --- | --- | --- | --- |
|
|
132
|
+
| `inset` | `boolean` | | |
|
|
133
|
+
|
|
134
|
+
Also takes: every `<div>` attribute.
|
|
135
|
+
|
|
136
|
+
### `DropdownMenuPortal`
|
|
137
|
+
|
|
138
|
+
Also takes: bits-ui `DropdownMenu.Portal` props.
|
|
139
|
+
|
|
140
|
+
### `DropdownMenuRadioGroup`
|
|
141
|
+
|
|
142
|
+
Also takes: bits-ui `DropdownMenu.RadioGroup` props.
|
|
143
|
+
|
|
144
|
+
### `DropdownMenuRadioItem`
|
|
145
|
+
|
|
146
|
+
| Prop | Type | Default | Description |
|
|
147
|
+
| --- | --- | --- | --- |
|
|
148
|
+
| `children` | `Snippet` | | |
|
|
149
|
+
|
|
150
|
+
Also takes: bits-ui `DropdownMenu.RadioItem` props except `children`, `child`.
|
|
151
|
+
|
|
152
|
+
### `DropdownMenuSeparator`
|
|
153
|
+
|
|
154
|
+
Also takes: bits-ui `DropdownMenu.Separator` props.
|
|
155
|
+
|
|
156
|
+
### `DropdownMenuShortcut`
|
|
157
|
+
|
|
158
|
+
Also takes: every `<span>` attribute.
|
|
159
|
+
|
|
160
|
+
### `DropdownMenuSub`
|
|
161
|
+
|
|
162
|
+
Also takes: bits-ui `DropdownMenu.Sub` props.
|
|
163
|
+
|
|
164
|
+
### `DropdownMenuSubContent`
|
|
165
|
+
|
|
166
|
+
Also takes: bits-ui `DropdownMenu.SubContent` props.
|
|
167
|
+
|
|
168
|
+
### `DropdownMenuSubTrigger`
|
|
169
|
+
|
|
170
|
+
| Prop | Type | Default | Description |
|
|
171
|
+
| --- | --- | --- | --- |
|
|
172
|
+
| `inset` | `boolean` | | |
|
|
173
|
+
|
|
174
|
+
Also takes: bits-ui `DropdownMenu.SubTrigger` props.
|
|
175
|
+
|
|
176
|
+
### `DropdownMenuTrigger`
|
|
177
|
+
|
|
178
|
+
Also takes: bits-ui `DropdownMenu.Trigger` props.
|
|
179
|
+
|
|
180
|
+
## ThemeToggle
|
|
181
|
+
|
|
182
|
+
`import { ThemeProvider, ThemeToggle, ThemeState, useTheme } from '@jovertical/mise-design-system'`
|
|
183
|
+
|
|
184
|
+
Icon-only toggle between light and dark, inside a `ThemeProvider`.
|
|
185
|
+
|
|
186
|
+
Also takes: everything `Button` takes except `children`, `onclick`.
|
|
187
|
+
|
|
188
|
+
### `ThemeProvider`
|
|
189
|
+
|
|
190
|
+
Applies a `light` / `dark` class to `<html>` and persists the choice. The class on the root is what Tailwind's `dark:` variant reads, so this touches the DOM directly rather than passing a value down alone.
|
|
191
|
+
|
|
192
|
+
| Prop | Type | Default | Description |
|
|
193
|
+
| --- | --- | --- | --- |
|
|
194
|
+
| `defaultTheme` | `'dark' \| 'light' \| 'system'` | `'system'` | |
|
|
195
|
+
| `storageKey` | `string` | `'vite-ui-theme'` | localStorage key. Distinct per app, so two apps on one host do not share a theme. |
|
|
196
|
+
| `children` (required) | `Snippet` | | |
|
|
197
|
+
|
|
198
|
+
Also exports: `ThemeState`, `useTheme`.
|
|
199
|
+
|
|
200
|
+
Types: `Theme` (`'dark' | 'light' | 'system'`).
|