@nexub/mcp 8.6.0 → 8.8.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/dist/skill/references/components/app-shell.md +62 -0
- package/dist/skill/references/components/aspect-ratio.md +60 -0
- package/dist/skill/references/components/check-list.md +53 -0
- package/dist/skill/references/components/command-palette.md +108 -0
- package/dist/skill/references/components/container.md +50 -0
- package/dist/skill/references/components/context-menu.md +62 -0
- package/dist/skill/references/components/country-badge.md +49 -0
- package/dist/skill/references/components/dropdown-menu.md +99 -0
- package/dist/skill/references/components/file-upload.md +73 -0
- package/dist/skill/references/components/flag.md +38 -0
- package/dist/skill/references/components/form-error.md +46 -0
- package/dist/skill/references/components/keyboard-shortcut.md +55 -0
- package/dist/skill/references/components/logo.md +59 -0
- package/dist/skill/references/components/menubar.md +83 -0
- package/dist/skill/references/components/navigation-menu.md +78 -0
- package/dist/skill/references/components/page-header.md +64 -0
- package/dist/skill/references/components/section.md +43 -0
- package/dist/skill/references/components/sidebar.md +78 -0
- package/dist/skill/references/components/toolbar.md +72 -0
- package/dist/skill/references/components/top-nav.md +48 -0
- package/dist/skill/references/components/visually-hidden.md +40 -0
- package/dist/skill/references/components.md +23 -2
- package/dist/skill/references/tokens.md +1 -1
- package/package.json +1 -1
|
@@ -0,0 +1,62 @@
|
|
|
1
|
+
# App Shell
|
|
2
|
+
|
|
3
|
+
Full-height application frame: a header row over a body with a sidebar slot and a scrolling main region.
|
|
4
|
+
|
|
5
|
+
- Package: `@nexub/react` · Category: Layout · Status: stable
|
|
6
|
+
- Import: `import { AppShell } from '@nexub/react';`
|
|
7
|
+
- Docs: https://nexub-ds-docs.pages.dev/components/app-shell
|
|
8
|
+
|
|
9
|
+
## When to use
|
|
10
|
+
|
|
11
|
+
- The outer frame of a product or dashboard: header, side navigation, content
|
|
12
|
+
|
|
13
|
+
## When not to use
|
|
14
|
+
|
|
15
|
+
- Marketing or content pages: use `Section` and `Container`
|
|
16
|
+
- A single panel inside a page: use `Grid` or `Flex`
|
|
17
|
+
|
|
18
|
+
## Props
|
|
19
|
+
|
|
20
|
+
| Prop | Type | Default | Description |
|
|
21
|
+
| --- | --- | --- | --- |
|
|
22
|
+
| `AppShell.Root` | `compound` | | Viewport-height grid (`h-screen`): header row, then the body. Override the height with `className` when it is not the whole page. |
|
|
23
|
+
| `AppShell.Header` | `compound` | | First row, e.g. a `TopNav.Root`. |
|
|
24
|
+
| `AppShell.Body` | `compound` | | Second row: lays out the sidebar and main side by side. |
|
|
25
|
+
| `AppShell.Sidebar` | `compound` | | Fixed-width column that scrolls on its own, e.g. a `Sidebar.Root`. |
|
|
26
|
+
| `AppShell.Main` | `compound` | | The `<main>` landmark: takes the remaining width, scrolls on its own, padded by default. |
|
|
27
|
+
| `...props` | `React.HTMLAttributes<HTMLDivElement>` | | Every part forwards its ref and HTML attributes. |
|
|
28
|
+
|
|
29
|
+
## Example: Header, sidebar and main
|
|
30
|
+
|
|
31
|
+
```tsx
|
|
32
|
+
import { AppShell, Logo, Sidebar, Text, TopNav } from '@nexub/react';
|
|
33
|
+
import { BarChart3, Home, Settings } from '@nexub/icons';
|
|
34
|
+
|
|
35
|
+
export default function Example() {
|
|
36
|
+
return (
|
|
37
|
+
<AppShell.Root className="h-[360px] w-full rounded-shape-container border border-[var(--color-outline-variant)]">
|
|
38
|
+
<AppShell.Header>
|
|
39
|
+
<TopNav.Root className="static">
|
|
40
|
+
<TopNav.Logo><Logo size="sm" /></TopNav.Logo>
|
|
41
|
+
</TopNav.Root>
|
|
42
|
+
</AppShell.Header>
|
|
43
|
+
<AppShell.Body>
|
|
44
|
+
<AppShell.Sidebar>
|
|
45
|
+
<Sidebar.Root aria-label="Workspace">
|
|
46
|
+
<Sidebar.Group>
|
|
47
|
+
<Sidebar.Item href="#" icon={<Home size="sm" />} active>Overview</Sidebar.Item>
|
|
48
|
+
<Sidebar.Item href="#" icon={<BarChart3 size="sm" />}>Reports</Sidebar.Item>
|
|
49
|
+
<Sidebar.Item href="#" icon={<Settings size="sm" />}>Settings</Sidebar.Item>
|
|
50
|
+
</Sidebar.Group>
|
|
51
|
+
</Sidebar.Root>
|
|
52
|
+
</AppShell.Sidebar>
|
|
53
|
+
<AppShell.Main>
|
|
54
|
+
<Text size="body-sm" tone="muted">Page content scrolls here, under a fixed header and sidebar.</Text>
|
|
55
|
+
</AppShell.Main>
|
|
56
|
+
</AppShell.Body>
|
|
57
|
+
</AppShell.Root>
|
|
58
|
+
);
|
|
59
|
+
}
|
|
60
|
+
```
|
|
61
|
+
|
|
62
|
+
Related: [top-nav](top-nav.md), [sidebar](sidebar.md), [page-header](page-header.md)
|
|
@@ -0,0 +1,60 @@
|
|
|
1
|
+
# Aspect Ratio
|
|
2
|
+
|
|
3
|
+
Keeps its content at a fixed width-to-height ratio, for images, video and embeds.
|
|
4
|
+
|
|
5
|
+
- Package: `@nexub/react` · Category: Layout · Status: stable
|
|
6
|
+
- Import: `import { AspectRatio } from '@nexub/react';`
|
|
7
|
+
- Docs: https://nexub-ds-docs.pages.dev/components/aspect-ratio
|
|
8
|
+
|
|
9
|
+
## Props
|
|
10
|
+
|
|
11
|
+
| Prop | Type | Default | Description |
|
|
12
|
+
| --- | --- | --- | --- |
|
|
13
|
+
| `ratio` | `number` | | Width divided by height, e.g. `16 / 9` or `1`. Common ratios (1, 16/9, 4/3, 3/2, 21/9, 9/16, 3/4, 2/3) use a class and are strict-CSP safe; any other ratio sets an inline `aspect-ratio` style. |
|
|
14
|
+
| `children` | `ReactNode` | | Fills the box; give an image `h-full w-full object-cover`. |
|
|
15
|
+
|
|
16
|
+
## Example: Image
|
|
17
|
+
|
|
18
|
+
```tsx
|
|
19
|
+
import { AspectRatio } from '@nexub/react';
|
|
20
|
+
|
|
21
|
+
export default function Example() {
|
|
22
|
+
return (
|
|
23
|
+
<div className="w-full max-w-[400px]">
|
|
24
|
+
<AspectRatio ratio={16 / 9} className="rounded-shape-container">
|
|
25
|
+
<div className="flex h-full w-full items-center justify-center bg-[var(--color-primary-container)] text-[var(--color-on-primary-container)] text-label-lg">
|
|
26
|
+
16 : 9
|
|
27
|
+
</div>
|
|
28
|
+
</AspectRatio>
|
|
29
|
+
</div>
|
|
30
|
+
);
|
|
31
|
+
}
|
|
32
|
+
```
|
|
33
|
+
|
|
34
|
+
## Example: Ratios
|
|
35
|
+
|
|
36
|
+
```tsx
|
|
37
|
+
import { AspectRatio } from '@nexub/react';
|
|
38
|
+
|
|
39
|
+
const ratios = [
|
|
40
|
+
{ ratio: 1, label: '1 : 1' },
|
|
41
|
+
{ ratio: 4 / 3, label: '4 : 3' },
|
|
42
|
+
{ ratio: 3 / 4, label: '3 : 4' },
|
|
43
|
+
];
|
|
44
|
+
|
|
45
|
+
export default function Example() {
|
|
46
|
+
return (
|
|
47
|
+
<div className="grid w-full max-w-[480px] grid-cols-3 items-start gap-3">
|
|
48
|
+
{ratios.map(({ ratio, label }) => (
|
|
49
|
+
<AspectRatio key={label} ratio={ratio} className="rounded-shape-container">
|
|
50
|
+
<div className="flex h-full w-full items-center justify-center bg-[var(--color-surface-container-high)] text-label-md text-[var(--color-on-surface-variant)]">
|
|
51
|
+
{label}
|
|
52
|
+
</div>
|
|
53
|
+
</AspectRatio>
|
|
54
|
+
))}
|
|
55
|
+
</div>
|
|
56
|
+
);
|
|
57
|
+
}
|
|
58
|
+
```
|
|
59
|
+
|
|
60
|
+
Related: [media-card](media-card.md), [box](box.md)
|
|
@@ -0,0 +1,53 @@
|
|
|
1
|
+
# Check List
|
|
2
|
+
|
|
3
|
+
A list with a success tick before each item, for features, plan inclusions and requirements met.
|
|
4
|
+
|
|
5
|
+
- Package: `@nexub/react` · Category: Data Display · Status: stable
|
|
6
|
+
- Import: `import { CheckList } from '@nexub/react';`
|
|
7
|
+
- Docs: https://nexub-ds-docs.pages.dev/components/check-list
|
|
8
|
+
|
|
9
|
+
## When to use
|
|
10
|
+
|
|
11
|
+
- Listing what a plan or feature includes
|
|
12
|
+
- Confirming requirements that are already met
|
|
13
|
+
|
|
14
|
+
## When not to use
|
|
15
|
+
|
|
16
|
+
- Tasks the user can tick off: use `Checkbox`
|
|
17
|
+
- Steps with progress or failures: use `PlanTracker` or `Stepper`
|
|
18
|
+
|
|
19
|
+
## Props
|
|
20
|
+
|
|
21
|
+
| Prop | Type | Default | Description |
|
|
22
|
+
| --- | --- | --- | --- |
|
|
23
|
+
| `items` | `string[]` | | Plain-text items. Shorthand for one `CheckListItem` each. |
|
|
24
|
+
| `children` | `ReactNode` | | `CheckListItem`s, for items with markup. Rendered after `items`. |
|
|
25
|
+
| `CheckListItem children` (required) | `ReactNode` | | The item text. The tick is decorative (hidden from screen readers). |
|
|
26
|
+
|
|
27
|
+
## Example: From items
|
|
28
|
+
|
|
29
|
+
```tsx
|
|
30
|
+
import { CheckList } from '@nexub/react';
|
|
31
|
+
|
|
32
|
+
export default function Example() {
|
|
33
|
+
return <CheckList items={['Unlimited projects', 'Priority support', 'Single sign-on (SAML)']} />;
|
|
34
|
+
}
|
|
35
|
+
```
|
|
36
|
+
|
|
37
|
+
## Example: With CheckListItem
|
|
38
|
+
|
|
39
|
+
```tsx
|
|
40
|
+
import { CheckList, CheckListItem } from '@nexub/react';
|
|
41
|
+
|
|
42
|
+
export default function Example() {
|
|
43
|
+
return (
|
|
44
|
+
<CheckList aria-label="Password requirements">
|
|
45
|
+
<CheckListItem>At least 12 characters</CheckListItem>
|
|
46
|
+
<CheckListItem>One number <span className="text-[var(--color-on-surface-muted)]">(0–9)</span></CheckListItem>
|
|
47
|
+
<CheckListItem>Not used on another account</CheckListItem>
|
|
48
|
+
</CheckList>
|
|
49
|
+
);
|
|
50
|
+
}
|
|
51
|
+
```
|
|
52
|
+
|
|
53
|
+
Related: [plan-tracker](plan-tracker.md)
|
|
@@ -0,0 +1,108 @@
|
|
|
1
|
+
# Command Palette
|
|
2
|
+
|
|
3
|
+
A searchable command menu in a modal dialog (cmdk), with nested pages, recents and an optional Cmd+K shortcut.
|
|
4
|
+
|
|
5
|
+
- Package: `@nexub/react` · Category: Navigation · Status: stable
|
|
6
|
+
- Import: `import { CommandPalette } from '@nexub/react';`
|
|
7
|
+
- Docs: https://nexub-ds-docs.pages.dev/components/command-palette
|
|
8
|
+
|
|
9
|
+
## When to use
|
|
10
|
+
|
|
11
|
+
- Power users jumping to pages or running actions by name
|
|
12
|
+
- A global Cmd+K entry point in an app
|
|
13
|
+
|
|
14
|
+
## When not to use
|
|
15
|
+
|
|
16
|
+
- Filtering a single list on the page: use `SearchInput` or `Combobox`
|
|
17
|
+
- The only way to reach an action: keep it in the visible UI too
|
|
18
|
+
|
|
19
|
+
## Props
|
|
20
|
+
|
|
21
|
+
| Prop | Type | Default | Description |
|
|
22
|
+
| --- | --- | --- | --- |
|
|
23
|
+
| `open / onOpenChange` | `boolean / (open: boolean) => void` | | Controlled open state. |
|
|
24
|
+
| `defaultOpen` | `boolean` | | Uncontrolled initial open state. |
|
|
25
|
+
| `shortcut` | `string` | | A letter that toggles the palette with Cmd (macOS) or Ctrl anywhere on the page, e.g. `'k'`. |
|
|
26
|
+
| `label` | `string` | | Accessible name of the dialog. Defaults to the localised "Command palette". |
|
|
27
|
+
| `shouldFilter` | `boolean` | | Set `false` when the items are already filtered, e.g. async search results. |
|
|
28
|
+
| `loading` | `boolean` | | Shows a loading row and hides `Empty`. |
|
|
29
|
+
| `pages / defaultPages / onPagesChange` | `string[]` | | The open page stack (ids of `CommandPalette.Page`), deepest last. Empty = the root page. |
|
|
30
|
+
| `recentKey / recentLimit` | `string / number` | | Opt-in recents: the last picks on the root page are kept in localStorage under this key and shown while the query is empty. |
|
|
31
|
+
| `scrollLock` | `'class' \| 'style'` | | `'class'` (strict-CSP safe) or Radix's style-tag lock. |
|
|
32
|
+
| `CommandPalette.Input / List / Empty / Group / Separator` | `compound` | | Search field, results list, no-results row, a headed group (`heading`), and a decorative divider. |
|
|
33
|
+
| `CommandPaletteItem page` | `string` | | Opens the `CommandPalette.Page` with this id when selected. Other props are cmdk `Command.Item` props (`onSelect`, `value`, `keywords`, `disabled`). |
|
|
34
|
+
| `CommandPalettePage id / title` | `string` | | Content shown only while this page is on top. No `id` = the root page; `title` shows in the input breadcrumb. Backspace on an empty query goes back. |
|
|
35
|
+
|
|
36
|
+
## Example: Default
|
|
37
|
+
|
|
38
|
+
```tsx
|
|
39
|
+
import * as React from 'react';
|
|
40
|
+
import { Button, CommandPalette } from '@nexub/react';
|
|
41
|
+
|
|
42
|
+
export default function Example() {
|
|
43
|
+
const [open, setOpen] = React.useState(false);
|
|
44
|
+
return (
|
|
45
|
+
<>
|
|
46
|
+
<Button variant="outlined" onClick={() => setOpen(true)}>Open command palette</Button>
|
|
47
|
+
<CommandPalette.Root open={open} onOpenChange={setOpen}>
|
|
48
|
+
<CommandPalette.Input placeholder="Type a command or search…" />
|
|
49
|
+
<CommandPalette.List>
|
|
50
|
+
<CommandPalette.Empty>No results found.</CommandPalette.Empty>
|
|
51
|
+
<CommandPalette.Group heading="Go to">
|
|
52
|
+
<CommandPalette.Item onSelect={() => setOpen(false)}>Dashboard</CommandPalette.Item>
|
|
53
|
+
<CommandPalette.Item onSelect={() => setOpen(false)}>Reports</CommandPalette.Item>
|
|
54
|
+
<CommandPalette.Item onSelect={() => setOpen(false)}>Settings</CommandPalette.Item>
|
|
55
|
+
</CommandPalette.Group>
|
|
56
|
+
<CommandPalette.Separator />
|
|
57
|
+
<CommandPalette.Group heading="Actions">
|
|
58
|
+
<CommandPalette.Item onSelect={() => setOpen(false)}>Create project</CommandPalette.Item>
|
|
59
|
+
<CommandPalette.Item onSelect={() => setOpen(false)}>Invite a teammate</CommandPalette.Item>
|
|
60
|
+
</CommandPalette.Group>
|
|
61
|
+
</CommandPalette.List>
|
|
62
|
+
</CommandPalette.Root>
|
|
63
|
+
</>
|
|
64
|
+
);
|
|
65
|
+
}
|
|
66
|
+
```
|
|
67
|
+
|
|
68
|
+
## Example: Nested pages
|
|
69
|
+
|
|
70
|
+
```tsx
|
|
71
|
+
import * as React from 'react';
|
|
72
|
+
import { Button, CommandPalette } from '@nexub/react';
|
|
73
|
+
|
|
74
|
+
export default function Example() {
|
|
75
|
+
const [open, setOpen] = React.useState(false);
|
|
76
|
+
return (
|
|
77
|
+
<>
|
|
78
|
+
<Button variant="outlined" onClick={() => setOpen(true)}>Switch project</Button>
|
|
79
|
+
<CommandPalette.Root open={open} onOpenChange={setOpen}>
|
|
80
|
+
<CommandPalette.Input placeholder="Search…" />
|
|
81
|
+
<CommandPalette.List>
|
|
82
|
+
<CommandPalette.Empty>No results found.</CommandPalette.Empty>
|
|
83
|
+
<CommandPalette.Page>
|
|
84
|
+
<CommandPalette.Item page="projects">Projects…</CommandPalette.Item>
|
|
85
|
+
<CommandPalette.Item onSelect={() => setOpen(false)}>Export report</CommandPalette.Item>
|
|
86
|
+
</CommandPalette.Page>
|
|
87
|
+
<CommandPalette.Page id="projects" title="Projects">
|
|
88
|
+
<CommandPalette.Item onSelect={() => setOpen(false)}>Billing service</CommandPalette.Item>
|
|
89
|
+
<CommandPalette.Item onSelect={() => setOpen(false)}>Mobile app</CommandPalette.Item>
|
|
90
|
+
</CommandPalette.Page>
|
|
91
|
+
</CommandPalette.List>
|
|
92
|
+
</CommandPalette.Root>
|
|
93
|
+
</>
|
|
94
|
+
);
|
|
95
|
+
}
|
|
96
|
+
```
|
|
97
|
+
|
|
98
|
+
## Accessibility
|
|
99
|
+
|
|
100
|
+
- Roles: dialog, combobox, listbox, option
|
|
101
|
+
- `Cmd/Ctrl + shortcut`: Toggles the palette when `shortcut` is set.
|
|
102
|
+
- `Arrow Up / Down`: Moves through items (wraps).
|
|
103
|
+
- `Enter`: Runs the highlighted item.
|
|
104
|
+
- `Backspace`: On an empty query, goes back a page.
|
|
105
|
+
- `Escape`: Closes the palette.
|
|
106
|
+
- Focus moves to the input on open and returns to the previously focused element on close.
|
|
107
|
+
|
|
108
|
+
Related: [keyboard-shortcut](keyboard-shortcut.md), [dialog](dialog.md), [search-input](search-input.md)
|
|
@@ -0,0 +1,50 @@
|
|
|
1
|
+
# Container
|
|
2
|
+
|
|
3
|
+
Centres content at a maximum width with responsive side padding.
|
|
4
|
+
|
|
5
|
+
- Package: `@nexub/react` · Category: Layout · Status: stable
|
|
6
|
+
- Import: `import { Container } from '@nexub/react';`
|
|
7
|
+
- Docs: https://nexub-ds-docs.pages.dev/components/container
|
|
8
|
+
|
|
9
|
+
## Props
|
|
10
|
+
|
|
11
|
+
| Prop | Type | Default | Description |
|
|
12
|
+
| --- | --- | --- | --- |
|
|
13
|
+
| `size` | `'sm' \| 'md' \| 'lg' \| 'xl' \| '2xl' \| 'nexub' \| 'marketing' \| 'prose'` | | Maximum width, from the `--container-*` tokens. `prose` is 65ch for reading. |
|
|
14
|
+
| `paddingX` | `boolean` | | Responsive horizontal padding (16, 24, 32 px). |
|
|
15
|
+
| `asChild` | `boolean` | | Apply the container classes to the child element (e.g. `<main>`) instead of a `<div>`. |
|
|
16
|
+
|
|
17
|
+
## Example: Default
|
|
18
|
+
|
|
19
|
+
```tsx
|
|
20
|
+
import { Container, Text } from '@nexub/react';
|
|
21
|
+
|
|
22
|
+
export default function Example() {
|
|
23
|
+
return (
|
|
24
|
+
<div className="w-full bg-[var(--color-surface-container-low)] py-4">
|
|
25
|
+
<Container size="sm" className="rounded-shape-container bg-[var(--color-surface)] py-4">
|
|
26
|
+
<Text size="body-sm">Centred at up to 640 px, with responsive side padding.</Text>
|
|
27
|
+
</Container>
|
|
28
|
+
</div>
|
|
29
|
+
);
|
|
30
|
+
}
|
|
31
|
+
```
|
|
32
|
+
|
|
33
|
+
## Example: Prose width
|
|
34
|
+
|
|
35
|
+
```tsx
|
|
36
|
+
import { Container, Heading, Text } from '@nexub/react';
|
|
37
|
+
|
|
38
|
+
export default function Example() {
|
|
39
|
+
return (
|
|
40
|
+
<Container size="prose" paddingX={false}>
|
|
41
|
+
<Heading level={3}>Release notes</Heading>
|
|
42
|
+
<Text size="body-sm" tone="secondary" className="mt-2">
|
|
43
|
+
The prose size caps lines at about 65 characters, a comfortable measure for reading long text.
|
|
44
|
+
</Text>
|
|
45
|
+
</Container>
|
|
46
|
+
);
|
|
47
|
+
}
|
|
48
|
+
```
|
|
49
|
+
|
|
50
|
+
Related: [section](section.md), [box](box.md), [stack](stack.md)
|
|
@@ -0,0 +1,62 @@
|
|
|
1
|
+
# Context Menu
|
|
2
|
+
|
|
3
|
+
A menu that opens at the pointer on right-click (or long-press), built on Radix.
|
|
4
|
+
|
|
5
|
+
- Package: `@nexub/react` · Category: Overlays · Status: stable
|
|
6
|
+
- Import: `import { ContextMenu } from '@nexub/react';`
|
|
7
|
+
- Docs: https://nexub-ds-docs.pages.dev/components/context-menu
|
|
8
|
+
|
|
9
|
+
## When to use
|
|
10
|
+
|
|
11
|
+
- Shortcuts to actions on an item: rename, duplicate, delete
|
|
12
|
+
|
|
13
|
+
## When not to use
|
|
14
|
+
|
|
15
|
+
- The only way to reach an action: right-click is hard to discover and needs a visible alternative, such as a `DropdownMenu`
|
|
16
|
+
|
|
17
|
+
## Props
|
|
18
|
+
|
|
19
|
+
| Prop | Type | Default | Description |
|
|
20
|
+
| --- | --- | --- | --- |
|
|
21
|
+
| `ContextMenu.Root` | `compound` | | Holds the open state (`onOpenChange`, `modal`). |
|
|
22
|
+
| `ContextMenu.Trigger` | `compound` | | The area that opens the menu on right-click. Use `asChild` to make your element the area. |
|
|
23
|
+
| `ContextMenu.Portal / Content` | `compound` | | Renders the floating menu in a portal. |
|
|
24
|
+
| `ContextMenu.Item` | `compound` | | An action (`onSelect`, `disabled`). |
|
|
25
|
+
| `ContextMenu.CheckboxItem / RadioGroup / RadioItem` | `compound` | | Toggle and single-choice items (`checked`, `onCheckedChange`; `value`, `onValueChange`). |
|
|
26
|
+
| `ContextMenu.Label / Group / Separator` | `compound` | | Section heading, grouping and divider. |
|
|
27
|
+
| `ContextMenu.Sub / SubTrigger / SubContent` | `compound` | | A nested submenu. |
|
|
28
|
+
|
|
29
|
+
## Example: Default
|
|
30
|
+
|
|
31
|
+
```tsx
|
|
32
|
+
import { ContextMenu } from '@nexub/react';
|
|
33
|
+
|
|
34
|
+
export default function Example() {
|
|
35
|
+
return (
|
|
36
|
+
<ContextMenu.Root>
|
|
37
|
+
<ContextMenu.Trigger className="flex h-32 w-64 select-none items-center justify-center rounded-shape-container border-2 border-dashed border-[var(--color-outline-variant)] text-body-sm text-[var(--color-on-surface-muted)]">
|
|
38
|
+
Right-click here
|
|
39
|
+
</ContextMenu.Trigger>
|
|
40
|
+
<ContextMenu.Portal>
|
|
41
|
+
<ContextMenu.Content>
|
|
42
|
+
<ContextMenu.Item>Rename</ContextMenu.Item>
|
|
43
|
+
<ContextMenu.Item>Duplicate</ContextMenu.Item>
|
|
44
|
+
<ContextMenu.Item>Copy link</ContextMenu.Item>
|
|
45
|
+
<ContextMenu.Separator />
|
|
46
|
+
<ContextMenu.Item>Move to trash</ContextMenu.Item>
|
|
47
|
+
</ContextMenu.Content>
|
|
48
|
+
</ContextMenu.Portal>
|
|
49
|
+
</ContextMenu.Root>
|
|
50
|
+
);
|
|
51
|
+
}
|
|
52
|
+
```
|
|
53
|
+
|
|
54
|
+
## Accessibility
|
|
55
|
+
|
|
56
|
+
- Roles: menu, menuitem, menuitemcheckbox, menuitemradio
|
|
57
|
+
- `Shift + F10 / Menu key`: Opens the menu from the focused trigger.
|
|
58
|
+
- `Arrow Up / Down`: Moves between items.
|
|
59
|
+
- `Enter / Space`: Activates the item.
|
|
60
|
+
- `Escape`: Closes the menu.
|
|
61
|
+
|
|
62
|
+
Related: [dropdown-menu](dropdown-menu.md), [menubar](menubar.md)
|
|
@@ -0,0 +1,49 @@
|
|
|
1
|
+
# Country Badge
|
|
2
|
+
|
|
3
|
+
A pill with a country flag and its name or code.
|
|
4
|
+
|
|
5
|
+
- Package: `@nexub/react` · Category: Labels & Badges · Status: stable
|
|
6
|
+
- Import: `import { CountryBadge } from '@nexub/react';`
|
|
7
|
+
- Docs: https://nexub-ds-docs.pages.dev/components/country-badge
|
|
8
|
+
|
|
9
|
+
## Props
|
|
10
|
+
|
|
11
|
+
| Prop | Type | Default | Description |
|
|
12
|
+
| --- | --- | --- | --- |
|
|
13
|
+
| `code` | `string` | | ISO 3166-1 alpha-2 country code, e.g. `SG`. |
|
|
14
|
+
| `label` | `string` | | Text after the flag. Defaults to `code`. |
|
|
15
|
+
| `size` | `'sm' \| 'md' \| 'lg'` | | Size of the pill and flag. |
|
|
16
|
+
|
|
17
|
+
## Example: Default
|
|
18
|
+
|
|
19
|
+
```tsx
|
|
20
|
+
import { CountryBadge } from '@nexub/react';
|
|
21
|
+
|
|
22
|
+
export default function Example() {
|
|
23
|
+
return (
|
|
24
|
+
<div className="flex flex-wrap gap-2">
|
|
25
|
+
<CountryBadge code="SG" label="Singapore" />
|
|
26
|
+
<CountryBadge code="DE" label="Germany" />
|
|
27
|
+
<CountryBadge code="BR" label="Brazil" />
|
|
28
|
+
</div>
|
|
29
|
+
);
|
|
30
|
+
}
|
|
31
|
+
```
|
|
32
|
+
|
|
33
|
+
## Example: Sizes
|
|
34
|
+
|
|
35
|
+
```tsx
|
|
36
|
+
import { CountryBadge } from '@nexub/react';
|
|
37
|
+
|
|
38
|
+
export default function Example() {
|
|
39
|
+
return (
|
|
40
|
+
<div className="flex flex-wrap items-center gap-2">
|
|
41
|
+
<CountryBadge code="JP" size="sm" />
|
|
42
|
+
<CountryBadge code="JP" size="md" />
|
|
43
|
+
<CountryBadge code="JP" size="lg" />
|
|
44
|
+
</div>
|
|
45
|
+
);
|
|
46
|
+
}
|
|
47
|
+
```
|
|
48
|
+
|
|
49
|
+
Related: [flag](flag.md), [badge](badge.md)
|
|
@@ -0,0 +1,99 @@
|
|
|
1
|
+
# Dropdown Menu
|
|
2
|
+
|
|
3
|
+
A menu of actions opened from a button, built on Radix.
|
|
4
|
+
|
|
5
|
+
- Package: `@nexub/react` · Category: Overlays · Status: stable
|
|
6
|
+
- Import: `import { DropdownMenu } from '@nexub/react';`
|
|
7
|
+
- Docs: https://nexub-ds-docs.pages.dev/components/dropdown-menu
|
|
8
|
+
|
|
9
|
+
## When to use
|
|
10
|
+
|
|
11
|
+
- Secondary actions behind a "More" button
|
|
12
|
+
- A short set of options that change a view
|
|
13
|
+
|
|
14
|
+
## When not to use
|
|
15
|
+
|
|
16
|
+
- Picking a form value: use `Select`
|
|
17
|
+
- Site navigation: use `NavigationMenu` or `TopNav`
|
|
18
|
+
|
|
19
|
+
## Props
|
|
20
|
+
|
|
21
|
+
| Prop | Type | Default | Description |
|
|
22
|
+
| --- | --- | --- | --- |
|
|
23
|
+
| `DropdownMenu.Root` | `compound` | | Holds the open state (`open`, `onOpenChange`, `defaultOpen`, `modal`). |
|
|
24
|
+
| `DropdownMenu.Trigger` | `compound` | | The button that opens the menu. Use `asChild` with a `Button` or `IconButton`. |
|
|
25
|
+
| `DropdownMenu.Portal / Content` | `compound` | | Renders the floating menu in a portal (`side`, `align`, `sideOffset` default 4). |
|
|
26
|
+
| `DropdownMenu.Item` | `compound` | | An action (`onSelect`, `disabled`). |
|
|
27
|
+
| `DropdownMenu.CheckboxItem / RadioGroup / RadioItem` | `compound` | | Toggle and single-choice items (`checked`, `onCheckedChange`; `value`, `onValueChange`). |
|
|
28
|
+
| `DropdownMenu.Label / Group / Separator` | `compound` | | Section heading, grouping and divider. |
|
|
29
|
+
| `DropdownMenu.Sub / SubTrigger / SubContent` | `compound` | | A nested submenu. |
|
|
30
|
+
|
|
31
|
+
## Example: Default
|
|
32
|
+
|
|
33
|
+
```tsx
|
|
34
|
+
import { DropdownMenu, IconButton } from '@nexub/react';
|
|
35
|
+
import { MoreHorizontal } from '@nexub/icons';
|
|
36
|
+
|
|
37
|
+
export default function Example() {
|
|
38
|
+
return (
|
|
39
|
+
<DropdownMenu.Root>
|
|
40
|
+
<DropdownMenu.Trigger asChild>
|
|
41
|
+
<IconButton variant="ghost" label="More actions"><MoreHorizontal size="sm" /></IconButton>
|
|
42
|
+
</DropdownMenu.Trigger>
|
|
43
|
+
<DropdownMenu.Portal>
|
|
44
|
+
<DropdownMenu.Content align="end">
|
|
45
|
+
<DropdownMenu.Label>Project</DropdownMenu.Label>
|
|
46
|
+
<DropdownMenu.Item>Rename</DropdownMenu.Item>
|
|
47
|
+
<DropdownMenu.Item>Duplicate</DropdownMenu.Item>
|
|
48
|
+
<DropdownMenu.Item disabled>Transfer ownership</DropdownMenu.Item>
|
|
49
|
+
<DropdownMenu.Separator />
|
|
50
|
+
<DropdownMenu.Item>Archive</DropdownMenu.Item>
|
|
51
|
+
</DropdownMenu.Content>
|
|
52
|
+
</DropdownMenu.Portal>
|
|
53
|
+
</DropdownMenu.Root>
|
|
54
|
+
);
|
|
55
|
+
}
|
|
56
|
+
```
|
|
57
|
+
|
|
58
|
+
## Example: Checkbox and radio items
|
|
59
|
+
|
|
60
|
+
```tsx
|
|
61
|
+
import * as React from 'react';
|
|
62
|
+
import { Button, DropdownMenu } from '@nexub/react';
|
|
63
|
+
|
|
64
|
+
export default function Example() {
|
|
65
|
+
const [showArchived, setShowArchived] = React.useState(false);
|
|
66
|
+
const [sort, setSort] = React.useState('updated');
|
|
67
|
+
return (
|
|
68
|
+
<DropdownMenu.Root>
|
|
69
|
+
<DropdownMenu.Trigger asChild>
|
|
70
|
+
<Button variant="outlined">View options</Button>
|
|
71
|
+
</DropdownMenu.Trigger>
|
|
72
|
+
<DropdownMenu.Portal>
|
|
73
|
+
<DropdownMenu.Content>
|
|
74
|
+
<DropdownMenu.CheckboxItem checked={showArchived} onCheckedChange={setShowArchived}>
|
|
75
|
+
Show archived
|
|
76
|
+
</DropdownMenu.CheckboxItem>
|
|
77
|
+
<DropdownMenu.Separator />
|
|
78
|
+
<DropdownMenu.Label>Sort by</DropdownMenu.Label>
|
|
79
|
+
<DropdownMenu.RadioGroup value={sort} onValueChange={setSort}>
|
|
80
|
+
<DropdownMenu.RadioItem value="updated">Last updated</DropdownMenu.RadioItem>
|
|
81
|
+
<DropdownMenu.RadioItem value="name">Name</DropdownMenu.RadioItem>
|
|
82
|
+
<DropdownMenu.RadioItem value="owner">Owner</DropdownMenu.RadioItem>
|
|
83
|
+
</DropdownMenu.RadioGroup>
|
|
84
|
+
</DropdownMenu.Content>
|
|
85
|
+
</DropdownMenu.Portal>
|
|
86
|
+
</DropdownMenu.Root>
|
|
87
|
+
);
|
|
88
|
+
}
|
|
89
|
+
```
|
|
90
|
+
|
|
91
|
+
## Accessibility
|
|
92
|
+
|
|
93
|
+
- Roles: menu, menuitem, menuitemcheckbox, menuitemradio
|
|
94
|
+
- `Enter / Space / Arrow Down`: Opens the menu from the trigger.
|
|
95
|
+
- `Arrow Up / Down`: Moves between items.
|
|
96
|
+
- `Arrow Right / Left`: Opens or closes a submenu.
|
|
97
|
+
- `Escape`: Closes the menu and returns focus to the trigger.
|
|
98
|
+
|
|
99
|
+
Related: [split-button](split-button.md), [context-menu](context-menu.md), [popover](popover.md)
|
|
@@ -0,0 +1,73 @@
|
|
|
1
|
+
# File Upload
|
|
2
|
+
|
|
3
|
+
A drop zone and file list: pick, drop or paste files, with type, size and count checks and per-file progress.
|
|
4
|
+
|
|
5
|
+
- Package: `@nexub/react` · Category: Form Controls · Status: stable
|
|
6
|
+
- Import: `import { FileUpload } from '@nexub/react';`
|
|
7
|
+
- Docs: https://nexub-ds-docs.pages.dev/components/file-upload
|
|
8
|
+
|
|
9
|
+
## Props
|
|
10
|
+
|
|
11
|
+
| Prop | Type | Default | Description |
|
|
12
|
+
| --- | --- | --- | --- |
|
|
13
|
+
| `accept` | `string[]` | | MIME types or extensions, e.g. `['image/*', '.pdf']`. Other files are rejected with a message. |
|
|
14
|
+
| `maxFiles` | `number` | | Most files kept; extras are rejected. |
|
|
15
|
+
| `maxSize` | `number` | | Largest file in bytes. |
|
|
16
|
+
| `onFilesChange` | `(files: File[]) => void` | | The accepted files after every add or remove. Your app does the upload. |
|
|
17
|
+
| `onReject` | `(rejections: FileRejection[]) => void` | | Files turned away, with the reason (`type`, `size`, `count` or `custom`). |
|
|
18
|
+
| `validate` | `(file: File) => string \| null \| undefined` | | Your own check: return a message to reject the file. Validate again on the server. |
|
|
19
|
+
| `FileUpload.Dropzone` | `compound` | | A `<label>` around the native file input: click, Enter, Space, drop or paste. Children replace the default prompt. Rejection messages are announced. |
|
|
20
|
+
| `FileUpload.List` | `compound` | | Renders nothing until there are files. |
|
|
21
|
+
| `FileUploadItem index` | `number` | | Which accepted file this row shows. Rows past the file count render nothing. |
|
|
22
|
+
| `FileUploadItem progress / onCancel` | `number / () => void` | | Upload progress 0–100; below 100 shows a bar and, with `onCancel`, a cancel button. |
|
|
23
|
+
| `FileUploadItem error` | `string` | | Why this file failed; shown under its name. |
|
|
24
|
+
|
|
25
|
+
## Example: Default
|
|
26
|
+
|
|
27
|
+
```tsx
|
|
28
|
+
import { FileUpload } from '@nexub/react';
|
|
29
|
+
|
|
30
|
+
export default function Example() {
|
|
31
|
+
return (
|
|
32
|
+
<FileUpload.Root accept={['image/*', '.pdf']} maxFiles={3} className="w-full max-w-[480px]">
|
|
33
|
+
<FileUpload.Dropzone />
|
|
34
|
+
<FileUpload.List>
|
|
35
|
+
{[0, 1, 2].map((i) => <FileUpload.Item key={i} index={i} />)}
|
|
36
|
+
</FileUpload.List>
|
|
37
|
+
</FileUpload.Root>
|
|
38
|
+
);
|
|
39
|
+
}
|
|
40
|
+
```
|
|
41
|
+
|
|
42
|
+
## Example: Custom prompt and limits
|
|
43
|
+
|
|
44
|
+
```tsx
|
|
45
|
+
import { FileUpload, Text } from '@nexub/react';
|
|
46
|
+
|
|
47
|
+
export default function Example() {
|
|
48
|
+
return (
|
|
49
|
+
<FileUpload.Root
|
|
50
|
+
accept={['.csv']}
|
|
51
|
+
maxFiles={1}
|
|
52
|
+
maxSize={5 * 1024 * 1024}
|
|
53
|
+
validate={(file) => (file.name.includes(' ') ? 'Rename the file without spaces.' : null)}
|
|
54
|
+
className="w-full max-w-[480px]"
|
|
55
|
+
>
|
|
56
|
+
<FileUpload.Dropzone>
|
|
57
|
+
<Text size="body-sm"><span className="font-semibold text-[var(--color-primary)]">Choose a CSV</span> or drop it here</Text>
|
|
58
|
+
<Text size="caption" tone="muted">One file, up to 5 MB</Text>
|
|
59
|
+
</FileUpload.Dropzone>
|
|
60
|
+
<FileUpload.List>
|
|
61
|
+
<FileUpload.Item index={0} />
|
|
62
|
+
</FileUpload.List>
|
|
63
|
+
</FileUpload.Root>
|
|
64
|
+
);
|
|
65
|
+
}
|
|
66
|
+
```
|
|
67
|
+
|
|
68
|
+
## Accessibility
|
|
69
|
+
|
|
70
|
+
- `Enter / Space`: Opens the file picker from the focused drop zone.
|
|
71
|
+
- Rejected files are listed in a live region (`role="alert"`) tied to the input with `aria-describedby`.
|
|
72
|
+
|
|
73
|
+
Related: [form-field](form-field.md), [progress](progress.md)
|
|
@@ -0,0 +1,38 @@
|
|
|
1
|
+
# Flag
|
|
2
|
+
|
|
3
|
+
A country flag from its ISO code, drawn with the system emoji font.
|
|
4
|
+
|
|
5
|
+
- Package: `@nexub/react` · Category: Labels & Badges · Status: stable
|
|
6
|
+
- Import: `import { Flag } from '@nexub/react';`
|
|
7
|
+
- Docs: https://nexub-ds-docs.pages.dev/components/flag
|
|
8
|
+
|
|
9
|
+
## Props
|
|
10
|
+
|
|
11
|
+
| Prop | Type | Default | Description |
|
|
12
|
+
| --- | --- | --- | --- |
|
|
13
|
+
| `code` | `string` | | ISO 3166-1 alpha-2 country code, e.g. `JP`. Also the accessible name unless you pass `aria-label`. |
|
|
14
|
+
| `size` | `'sm' \| 'md' \| 'lg'` | | Font size of the flag. |
|
|
15
|
+
| `aria-label` | `string` | | A readable name, e.g. "Japan". Defaults to the code. |
|
|
16
|
+
|
|
17
|
+
## Example: Default
|
|
18
|
+
|
|
19
|
+
```tsx
|
|
20
|
+
import { Flag } from '@nexub/react';
|
|
21
|
+
|
|
22
|
+
export default function Example() {
|
|
23
|
+
return (
|
|
24
|
+
<div className="flex items-center gap-3">
|
|
25
|
+
<Flag code="JP" size="sm" aria-label="Japan" />
|
|
26
|
+
<Flag code="IN" aria-label="India" />
|
|
27
|
+
<Flag code="FR" size="lg" aria-label="France" />
|
|
28
|
+
</div>
|
|
29
|
+
);
|
|
30
|
+
}
|
|
31
|
+
```
|
|
32
|
+
|
|
33
|
+
## Accessibility
|
|
34
|
+
|
|
35
|
+
- Roles: img
|
|
36
|
+
- Windows has no flag emoji and shows the two letters instead. Pair the flag with the country name where it matters.
|
|
37
|
+
|
|
38
|
+
Related: [country-badge](country-badge.md)
|