@maltjoy/mcp-server 0.4.0 → 0.6.0-beta.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/LICENSE +21 -0
- package/README.md +30 -3
- package/dist/doc/VJoyAdminBanner/guideline.md +284 -0
- package/dist/doc/VJoyAvailability/guideline.md +352 -0
- package/dist/doc/VJoyAvatar/guideline.md +192 -0
- package/dist/doc/VJoyAvatarsList/guideline.md +328 -0
- package/dist/doc/VJoyBadge/guideline.md +169 -0
- package/dist/doc/VJoyBadgeLevel/guideline.md +166 -0
- package/dist/doc/VJoyBlockSkeleton/guideline.md +150 -0
- package/dist/doc/VJoyBottomSheet/guideline.md +345 -0
- package/dist/doc/VJoyBottomSheetTrigger/guideline.md +156 -0
- package/dist/doc/VJoyButton/guideline.md +371 -0
- package/dist/doc/VJoyButton/metadata.json +0 -16
- package/dist/doc/VJoyButtonCard/guideline.md +384 -0
- package/dist/doc/VJoyCheckbox/guideline.md +317 -0
- package/dist/doc/VJoyCheckboxCard/guideline.md +381 -0
- package/dist/doc/VJoyCheckboxGroup/guideline.md +363 -0
- package/dist/doc/VJoyCheckboxGroup/metadata.json +7 -7
- package/dist/doc/VJoyCollapse/guideline.md +362 -0
- package/dist/doc/VJoyCollapseItem/guideline.md +394 -0
- package/dist/doc/VJoyCompanyAvatar/guideline.md +162 -0
- package/dist/doc/VJoyDialog/guideline.md +425 -0
- package/dist/doc/VJoyDialogTrigger/guideline.md +186 -0
- package/dist/doc/VJoyDot/guideline.md +177 -0
- package/dist/doc/VJoyDrawer/guideline.md +392 -0
- package/dist/doc/VJoyDrawerTrigger/guideline.md +145 -0
- package/dist/doc/VJoyDropdown/guideline.md +393 -0
- package/dist/doc/VJoyDropdown/metadata.json +6 -6
- package/dist/doc/VJoyDropdownList/guideline.md +396 -0
- package/dist/doc/VJoyDropdownList/metadata.json +7 -7
- package/dist/doc/VJoyDropzone/guideline.md +390 -0
- package/dist/doc/VJoyDropzone/metadata.json +36 -1
- package/dist/doc/VJoyFilterBar/guideline.md +419 -0
- package/dist/doc/VJoyFilterBarButton/guideline.md +359 -0
- package/dist/doc/VJoyFloatingActionsBar/guideline.md +372 -0
- package/dist/doc/VJoyFormError/guideline.md +325 -0
- package/dist/doc/VJoyFormError/metadata.json +0 -14
- package/dist/doc/VJoyFormFieldSkeleton/guideline.md +159 -0
- package/dist/doc/VJoyFormGroup/guideline.md +285 -0
- package/dist/doc/VJoyFunnel/guideline.md +349 -0
- package/dist/doc/VJoyFunnelFooter/guideline.md +178 -0
- package/dist/doc/VJoyFunnelHeader/guideline.md +204 -0
- package/dist/doc/VJoyHighlight/guideline.md +169 -0
- package/dist/doc/VJoyIcon/JoyIcon.types.ts +1 -1
- package/dist/doc/VJoyIcon/guideline.md +168 -0
- package/dist/doc/VJoyIcon/metadata.json +0 -1
- package/dist/doc/VJoyIconButton/guideline.md +169 -0
- package/dist/doc/VJoyIconButton/metadata.json +1 -1
- package/dist/doc/VJoyIndicator/guideline.md +168 -0
- package/dist/doc/VJoyIndicators/guideline.md +183 -0
- package/dist/doc/VJoyInput/JoyInput.types.ts +1 -6
- package/dist/doc/VJoyInput/guideline.md +401 -0
- package/dist/doc/VJoyInput/metadata.json +5 -14
- package/dist/doc/VJoyInputDigit/guideline.md +381 -0
- package/dist/doc/VJoyInputNumber/guideline.md +414 -0
- package/dist/doc/VJoyInputNumber/metadata.json +22 -17
- package/dist/doc/VJoyInputPassword/guideline.md +379 -0
- package/dist/doc/VJoyInputPassword/metadata.json +0 -14
- package/dist/doc/VJoyLabel/guideline.md +200 -0
- package/dist/doc/VJoyLink/guideline.md +360 -0
- package/dist/doc/VJoyListItem/guideline.md +335 -0
- package/dist/doc/VJoyMenu/guideline.md +304 -0
- package/dist/doc/VJoyMenu/metadata.json +21 -21
- package/dist/doc/VJoyMenuItem/guideline.md +352 -0
- package/dist/doc/VJoyPagination/guideline.md +355 -0
- package/dist/doc/VJoyPanel/guideline.md +238 -0
- package/dist/doc/VJoyPanelSection/guideline.md +160 -0
- package/dist/doc/VJoyPasswordRequirement/guideline.md +336 -0
- package/dist/doc/VJoyPasswordRequirement/metadata.json +1 -1
- package/dist/doc/VJoyProductTour/JoyProductTour.types.ts +0 -1
- package/dist/doc/VJoyProductTour/guideline.md +455 -0
- package/dist/doc/VJoyProductTour/metadata.json +1 -1
- package/dist/doc/VJoyProductTourTrigger/guideline.md +167 -0
- package/dist/doc/VJoyProgressBar/guideline.md +348 -0
- package/dist/doc/VJoyRadio/guideline.md +346 -0
- package/dist/doc/VJoyRadioGroup/guideline.md +331 -0
- package/dist/doc/VJoyRatingStars/guideline.md +306 -0
- package/dist/doc/VJoyScreenLoader/guideline.md +172 -0
- package/dist/doc/VJoySelect/guideline.md +396 -0
- package/dist/doc/VJoySelectableItem/guideline.md +351 -0
- package/dist/doc/VJoySelectableItemGroup/guideline.md +370 -0
- package/dist/doc/VJoySeparator/guideline.md +161 -0
- package/dist/doc/VJoySnackbar/guideline.md +402 -0
- package/dist/doc/VJoySpinner/guideline.md +168 -0
- package/dist/doc/VJoyStep/guideline.md +182 -0
- package/dist/doc/VJoyStepper/guideline.md +390 -0
- package/dist/doc/VJoyTab/guideline.md +298 -0
- package/dist/doc/VJoyTabs/guideline.md +353 -0
- package/dist/doc/VJoyTag/guideline.md +226 -0
- package/dist/doc/VJoyTagsInput/guideline.md +387 -0
- package/dist/doc/VJoyTagsList/guideline.md +311 -0
- package/dist/doc/VJoyTagsList/metadata.json +27 -27
- package/dist/doc/VJoyTemplate/guideline.md +366 -0
- package/dist/doc/VJoyText/guideline.md +175 -0
- package/dist/doc/VJoyText/metadata.json +1 -1
- package/dist/doc/VJoyTextarea/guideline.md +378 -0
- package/dist/doc/VJoyTitleBrand/guideline.md +155 -0
- package/dist/doc/VJoyToggle/guideline.md +327 -0
- package/dist/doc/VJoyTooltip/guideline.md +322 -0
- package/dist/doc/VJoyUserCard/guideline.md +268 -0
- package/dist/doc/VJoyUserCard/metadata.json +3 -17
- package/dist/doc/VJoyWalkthrough/guideline.md +351 -0
- package/dist/doc/VJoyWalkthroughTrigger/guideline.md +171 -0
- package/dist/doc/VJoyWrapper/guideline.md +173 -0
- package/dist/doc/css-classes.json +1 -15
- package/dist/doc/design-tokens.json +1 -0
- package/dist/doc/index.json +20 -30
- package/dist/index.js +22 -2
- package/dist/index.js.map +1 -1
- package/dist/tools/get-component-guideline.d.ts +30 -0
- package/dist/tools/get-component-guideline.d.ts.map +1 -0
- package/dist/tools/get-component-guideline.js +51 -0
- package/dist/tools/get-component-guideline.js.map +1 -0
- package/dist/tools/get-documentation-page.d.ts +22 -0
- package/dist/tools/get-documentation-page.d.ts.map +1 -0
- package/dist/tools/get-documentation-page.js +21 -0
- package/dist/tools/get-documentation-page.js.map +1 -0
- package/dist/tools/list-documentation-pages.d.ts +22 -0
- package/dist/tools/list-documentation-pages.d.ts.map +1 -0
- package/dist/tools/list-documentation-pages.js +17 -0
- package/dist/tools/list-documentation-pages.js.map +1 -0
- package/dist/tools/search-documentation.d.ts +41 -0
- package/dist/tools/search-documentation.d.ts.map +1 -0
- package/dist/tools/search-documentation.js +25 -0
- package/dist/tools/search-documentation.js.map +1 -0
- package/dist/zeroheight-parser.d.ts +27 -0
- package/dist/zeroheight-parser.d.ts.map +1 -0
- package/dist/zeroheight-parser.js +77 -0
- package/dist/zeroheight-parser.js.map +1 -0
- package/package.json +10 -10
- package/dist/doc/VJoyMultiCheckbox/metadata.json +0 -332
|
@@ -0,0 +1,177 @@
|
|
|
1
|
+
---
|
|
2
|
+
component: VJoyDot
|
|
3
|
+
status: draft
|
|
4
|
+
language: en
|
|
5
|
+
dsds: JoyDot.dsds.json
|
|
6
|
+
dsdsVersion: "0.15.2"
|
|
7
|
+
---
|
|
8
|
+
|
|
9
|
+
# Dot
|
|
10
|
+
|
|
11
|
+
Use **`VJoyDot`** when you need a compact colored indicator — a plain status dot or a small numeric badge for counts and notifications.
|
|
12
|
+
|
|
13
|
+
It supports semantic color variants and optional `number` content (number or string). Size and colors come from Joy tokens; the component does not format values for you.
|
|
14
|
+
|
|
15
|
+
| | |
|
|
16
|
+
| --- | --- |
|
|
17
|
+
| **Code** | `VJoyDot` from `@maltjoy/core-vue` |
|
|
18
|
+
| **Design** | [ZeroHeight — Joy](https://zeroheight.com/6bf479565/) (page id `8043088`) |
|
|
19
|
+
| **Storybook** | [VJoyDot docs](https://doc.malt.tech/joy-storybook/?path=/docs/components-view-vjoydot--docs) |
|
|
20
|
+
| **DSDS (machine)** | [`JoyDot.dsds.json`](./JoyDot.dsds.json) |
|
|
21
|
+
| **Live API** | `joy_get_component_info("VJoyDot")` |
|
|
22
|
+
|
|
23
|
+
---
|
|
24
|
+
|
|
25
|
+
## When to use this component
|
|
26
|
+
|
|
27
|
+
Use a dot when a **small, non-interactive** visual cue is enough — for example an unread marker beside custom UI, a live-status bullet, or a standalone count pill outside higher-level Joy patterns.
|
|
28
|
+
|
|
29
|
+
Plain dots (no `number`) work for binary or categorical status where color carries meaning and nearby text supplies context. With `number`, the dot grows into a pill-shaped badge for short counts (`1`, `12`, `99+`).
|
|
30
|
+
|
|
31
|
+
### When not to use this component
|
|
32
|
+
|
|
33
|
+
| Need | Use instead |
|
|
34
|
+
| --- | --- |
|
|
35
|
+
| A labeled status chip with text | `VJoyBadge` (optionally with `bulletpoint` for the dot) |
|
|
36
|
+
| Notification count on a tab | `notifications` on `VJoyTab` inside `VJoyTabs` (wired to `VJoyDot` internally) |
|
|
37
|
+
| Multi-step or carousel progress | `VJoyIndicators` |
|
|
38
|
+
| An actionable control | `VJoyButton`, `VJoyIconButton`, or `VJoyLink` |
|
|
39
|
+
| Toast or inline feedback after an action | `pushVJoySnackbar` |
|
|
40
|
+
| Custom `<span>` / CSS circle for the same job | Still use `VJoyDot` + Joy tokens — don’t reinvent chrome |
|
|
41
|
+
|
|
42
|
+
> **Not in the API:** legacy docs sometimes describe automatic `99+` formatting. **`VJoyDot` renders the `number` prop as-is** (number or string). Cap or format large counts in application code before passing them in.
|
|
43
|
+
|
|
44
|
+
---
|
|
45
|
+
|
|
46
|
+
## How it works
|
|
47
|
+
|
|
48
|
+
### Anatomy
|
|
49
|
+
|
|
50
|
+
| Part | Required? | What it is |
|
|
51
|
+
| --- | --- | --- |
|
|
52
|
+
| Container | Yes | Root `<div class="joy-dot">` with variant class (`joy-dot__{variant}`) |
|
|
53
|
+
| Fill | Yes | Circular or pill background from Joy color tokens |
|
|
54
|
+
| Number (`span`) | No | Shown when `number` is provided; adds `joy-dot__number` sizing |
|
|
55
|
+
|
|
56
|
+
The component is **presentational only** — no slots, events, or interactive states.
|
|
57
|
+
|
|
58
|
+
### Modes
|
|
59
|
+
|
|
60
|
+
| Mode | When | Visual |
|
|
61
|
+
| --- | --- | --- |
|
|
62
|
+
| Plain dot | `number` omitted | 8px circle (`--joy-core-spacing-2`) |
|
|
63
|
+
| Number badge | `number` set (including `0`) | Taller pill (`--joy-core-spacing-4`), `min-width: 16px`, centered label (`primary-250` typography) |
|
|
64
|
+
|
|
65
|
+
### Default values
|
|
66
|
+
|
|
67
|
+
- `variant` defaults to **`info`**
|
|
68
|
+
- `number` defaults to **`undefined`** (plain dot)
|
|
69
|
+
|
|
70
|
+
**Variants** (`TJoyDotVariants`): `info`, `gray`, `green`, `orange`, `red`, `teal`, `pink`, `dark-blue`, `yellow`. Pick by **semantic meaning**, not decoration — e.g. `green` for success, `orange` for warning, `pink` for brand / notification accents (as on tab badges).
|
|
71
|
+
|
|
72
|
+
`pink` uses `--joy-color-brand-primary-70`; other variants use `--joy-color-{semantic}-50`, overridable via `--badge-circle-color` when embedded in badge-like contexts.
|
|
73
|
+
|
|
74
|
+
Props: use Joy MCP or Storybook — this page focuses on **when** and **how**, not a full API dump.
|
|
75
|
+
|
|
76
|
+
---
|
|
77
|
+
|
|
78
|
+
## Best practices
|
|
79
|
+
|
|
80
|
+
Rules use RFC 2119 strength (**MUST** / **SHOULD** / **MUST NOT** / **SHOULD NOT**).
|
|
81
|
+
|
|
82
|
+
### When to show a dot
|
|
83
|
+
|
|
84
|
+
- **SHOULD** pair plain dots with visible text or an accessible name on a parent control — color alone is not enough.
|
|
85
|
+
- **SHOULD** use `VJoyBadge` when the status needs a readable label, not only color.
|
|
86
|
+
- **SHOULD** use `VJoyTab` `notifications` for tab counts instead of hand-placing `VJoyDot` beside tab labels.
|
|
87
|
+
- **SHOULD** keep numeric badges short — pre-format values like `99+` in app code when needed.
|
|
88
|
+
- **MUST NOT** use a dot as the only indicator of critical information with no text alternative.
|
|
89
|
+
|
|
90
|
+
### Implementation
|
|
91
|
+
|
|
92
|
+
- **MUST** use only `variant` values from `TJoyDotVariants` / MCP / component types.
|
|
93
|
+
- **MUST** use Joy tokens — no custom `.joy-dot` chrome (size, radius, background) in product CSS.
|
|
94
|
+
- **MUST NOT** invent props (`size`, `color`, `label`, …).
|
|
95
|
+
- **SHOULD** pass `number` as a number for counts and as a string only when you need suffixes (`99+`).
|
|
96
|
+
- **SHOULD** use `variant="pink"` for notification-style counts to match tab and product patterns.
|
|
97
|
+
- **MAY** set `--badge-circle-color` on an ancestor when a one-off brand override is required — prefer a documented `variant` first.
|
|
98
|
+
|
|
99
|
+
### Do / don’t
|
|
100
|
+
|
|
101
|
+
| Do | Don’t |
|
|
102
|
+
| --- | --- |
|
|
103
|
+
| Plain dot + adjacent label text | Dot as the only status message |
|
|
104
|
+
| `VJoyBadge` with `bulletpoint` for labeled status | Duplicate dot + separate text span |
|
|
105
|
+
| `notifications` on `VJoyTab` for tab badges | Manual `VJoyDot` in tab chrome |
|
|
106
|
+
| Format `99+` before passing `number` | Expect the component to cap counts |
|
|
107
|
+
| Semantic `variant` for meaning | Random swatch per screen |
|
|
108
|
+
|
|
109
|
+
---
|
|
110
|
+
|
|
111
|
+
## Accessibility
|
|
112
|
+
|
|
113
|
+
Behaviors (what must happen), not slogans.
|
|
114
|
+
|
|
115
|
+
| Behavior | Expectation |
|
|
116
|
+
| --- | --- |
|
|
117
|
+
| Role | Decorative indicator — no native interactive role |
|
|
118
|
+
| Name | **MUST NOT** rely on the dot alone for meaning; parent control or nearby text provides the accessible name |
|
|
119
|
+
| Counts | When `number` conveys quantity, the **parent** should expose it (e.g. tab label + count, `aria-label` on a wrapping button) |
|
|
120
|
+
| Color | Don’t use variant color as the only differentiator — reinforce with text or position |
|
|
121
|
+
| Focus | Not focusable — don’t wrap a lone dot in a clickable element without an accessible name |
|
|
122
|
+
| Motion | Static — no animation API |
|
|
123
|
+
|
|
124
|
+
Target: **WCAG 2.2 AA** where the product requires it.
|
|
125
|
+
|
|
126
|
+
---
|
|
127
|
+
|
|
128
|
+
## Examples
|
|
129
|
+
|
|
130
|
+
```vue
|
|
131
|
+
<script setup lang="ts">
|
|
132
|
+
import { VJoyDot } from '@maltjoy/core-vue'
|
|
133
|
+
</script>
|
|
134
|
+
|
|
135
|
+
<template>
|
|
136
|
+
<!-- Plain status dot (pair with visible text) -->
|
|
137
|
+
<span class="status-row">
|
|
138
|
+
<VJoyDot variant="green" />
|
|
139
|
+
Online
|
|
140
|
+
</span>
|
|
141
|
+
|
|
142
|
+
<!-- Notification-style count -->
|
|
143
|
+
<VJoyDot variant="pink" :number="3" />
|
|
144
|
+
|
|
145
|
+
<!-- Pre-formatted large count -->
|
|
146
|
+
<VJoyDot variant="pink" number="99+" />
|
|
147
|
+
|
|
148
|
+
<!-- Zero is a valid count -->
|
|
149
|
+
<VJoyDot variant="info" :number="0" />
|
|
150
|
+
</template>
|
|
151
|
+
```
|
|
152
|
+
|
|
153
|
+
In Nuxt (or apps with auto-import), omit the import if `VJoyDot` is already global.
|
|
154
|
+
|
|
155
|
+
**Prefer composition over direct use** when Joy already wraps the pattern:
|
|
156
|
+
|
|
157
|
+
```vue
|
|
158
|
+
<!-- Tab notification — use VJoyTab API -->
|
|
159
|
+
<VJoyTabs v-model:selected-tab="active">
|
|
160
|
+
<VJoyTab tab="inbox" label="Inbox" :notifications="5">…</VJoyTab>
|
|
161
|
+
</VJoyTabs>
|
|
162
|
+
|
|
163
|
+
<!-- Labeled status — use VJoyBadge -->
|
|
164
|
+
<VJoyBadge variant="green" bulletpoint label="Active" />
|
|
165
|
+
```
|
|
166
|
+
|
|
167
|
+
---
|
|
168
|
+
|
|
169
|
+
## Related
|
|
170
|
+
|
|
171
|
+
| Component | Use when |
|
|
172
|
+
| --- | --- |
|
|
173
|
+
| `VJoyBadge` | Status text with optional bullet dot (`bulletpoint`) |
|
|
174
|
+
| `VJoyTabs` / `VJoyTab` | Tab labels with notification counts (`notifications` → `VJoyDot`) |
|
|
175
|
+
| `VJoyIndicators` | Step or slide progress dots |
|
|
176
|
+
| `VJoyTooltip` | Explaining an icon or status the dot accompanies |
|
|
177
|
+
| `VJoyButton` / `VJoyIconButton` | Actions — not status dots |
|
|
@@ -0,0 +1,392 @@
|
|
|
1
|
+
---
|
|
2
|
+
component: VJoyDrawer
|
|
3
|
+
status: draft
|
|
4
|
+
language: en
|
|
5
|
+
dsds: JoyDrawer.dsds.json
|
|
6
|
+
dsdsVersion: "0.15.2"
|
|
7
|
+
---
|
|
8
|
+
|
|
9
|
+
# Drawer
|
|
10
|
+
|
|
11
|
+
Use **`VJoyDrawer`** when users need a secondary panel that slides in from the right — filters, item details, settings, or longer forms — without leaving the current page.
|
|
12
|
+
|
|
13
|
+
It teleports to `body` by default, supports header/body/footer slots, optional confirm/cancel CTAs, and exposes async `show()` / `hide()` methods. Use **`VJoyDrawerTrigger`** when a declarative open trigger is simpler than imperative refs.
|
|
14
|
+
|
|
15
|
+
| | |
|
|
16
|
+
| --- | --- |
|
|
17
|
+
| **Code** | `VJoyDrawer` from `@maltjoy/core-vue` |
|
|
18
|
+
| **Design** | [ZeroHeight — Drawer](https://zeroheight.com/6bf479565/) |
|
|
19
|
+
| **Storybook** | [VJoyDrawer docs](https://doc.malt.tech/joy-storybook/?path=/docs/components-overlays-vjoydrawer--docs) |
|
|
20
|
+
| **DSDS (machine)** | [`JoyDrawer.dsds.json`](./JoyDrawer.dsds.json) |
|
|
21
|
+
| **Live API** | `joy_get_component_info("VJoyDrawer")` |
|
|
22
|
+
|
|
23
|
+
---
|
|
24
|
+
|
|
25
|
+
## When to use this component
|
|
26
|
+
|
|
27
|
+
Use a drawer when the user needs extra context or a sub-task on the same page — for example filtering a list, editing a record in context, or browsing details while keeping the main view visible (especially in `elevated` mode).
|
|
28
|
+
|
|
29
|
+
Drawers slide in from the right and work well for exploratory or longer content that would feel cramped in a centered dialog.
|
|
30
|
+
|
|
31
|
+
### When not to use this component
|
|
32
|
+
|
|
33
|
+
| Need | Use instead |
|
|
34
|
+
| --- | --- |
|
|
35
|
+
| Short, focused decision or confirmation | `VJoyDialog` |
|
|
36
|
+
| Mobile bottom sheet from the screen edge | `VJoyBottomSheet` |
|
|
37
|
+
| Lightweight contextual hint on hover/focus | `VJoyTooltip` |
|
|
38
|
+
| Inline expandable section on the same page | Page layout or `VJoyCollapse` — not a drawer |
|
|
39
|
+
| Toast / transient feedback after an action | `pushVJoySnackbar` |
|
|
40
|
+
| Custom slide-over markup with ad-hoc CSS | Still use `VJoyDrawer` + Joy tokens |
|
|
41
|
+
|
|
42
|
+
---
|
|
43
|
+
|
|
44
|
+
## How it works
|
|
45
|
+
|
|
46
|
+
### Anatomy
|
|
47
|
+
|
|
48
|
+
| Part | Required? | What it is |
|
|
49
|
+
| --- | --- | --- |
|
|
50
|
+
| Overlay | Yes* | Semi-transparent backdrop; click dismisses (*hidden when `elevated`) |
|
|
51
|
+
| Panel (`joy-drawer__inner`) | Yes | White panel with elevation, slides from the right |
|
|
52
|
+
| Header (`drawer-header`) | Yes (content) | Drawer title — linked via `aria-labelledby` |
|
|
53
|
+
| Subheader (`drawer-subheader`) | No | Supporting description below the title (`#drawerDescription`) |
|
|
54
|
+
| Close button | Yes | Top-right `VJoyIconButton` (cross icon) |
|
|
55
|
+
| Body (`drawer-body`) | Yes (content) | Main content; scrolls when tall |
|
|
56
|
+
| Footer | No | Cancel / confirm CTAs via props or slots |
|
|
57
|
+
| Preheader (`drawer-preheader`) | No | Declared in types/MCP but **not rendered** in the current Vue template — do not rely on it |
|
|
58
|
+
|
|
59
|
+
### Default values
|
|
60
|
+
|
|
61
|
+
- `size` defaults to **`default`** (580px panel width; `large` → 780px)
|
|
62
|
+
- `open` defaults to **`false`**
|
|
63
|
+
- `teleport` defaults to **`body`**
|
|
64
|
+
- `preventBodyScroll` defaults to **`true`** (locks page scroll while open, when not `elevated`)
|
|
65
|
+
- `elevated` defaults to **`false`**
|
|
66
|
+
- `closeLabel` defaults to **`"Close drawer"`**
|
|
67
|
+
- `buttonSize` defaults to **`medium`** (footer CTAs)
|
|
68
|
+
- `cancelText` / `confirmText` default to **unset** (no footer buttons until provided)
|
|
69
|
+
|
|
70
|
+
Props, events, slots, and exposed methods: use Joy MCP (`joy_get_component_info`, `joy_get_component_types`) or Storybook — this page focuses on **when** and **how**, not a full API dump.
|
|
71
|
+
|
|
72
|
+
### Open / close lifecycle
|
|
73
|
+
|
|
74
|
+
1. **Open** — set `open` or call `show()` on the exposed ref. Body scroll is prevented when `preventBodyScroll` is true and `elevated` is false.
|
|
75
|
+
2. **Dismiss** — close icon, backdrop click, Escape key, or cancel CTA (default wiring). All fire `drawer:hide` when the leave transition starts.
|
|
76
|
+
3. **Confirm** — default confirm CTA emits `drawer:confirm` only; you still handle persistence and closing.
|
|
77
|
+
4. **Guard close** — `onBeforeHide` runs before any dismiss path; return `false` (or a resolved `false`) to keep the drawer open.
|
|
78
|
+
5. **Unmount while open** — emits `drawer:before-unmount` and restores body scroll.
|
|
79
|
+
|
|
80
|
+
`show()` and `hide()` are **async**. `hide({ fireHideEvent: false })` closes without emitting `drawer:hide`.
|
|
81
|
+
|
|
82
|
+
---
|
|
83
|
+
|
|
84
|
+
## Variants
|
|
85
|
+
|
|
86
|
+
Drawers don't have color variants. Choose **overlay mode** and **size** by context.
|
|
87
|
+
|
|
88
|
+
### Default (overlay)
|
|
89
|
+
|
|
90
|
+
Modal backdrop blocks interaction with the page behind. Backdrop click, Escape, and the close icon all dismiss.
|
|
91
|
+
|
|
92
|
+
Use when the drawer needs focused attention — filters, edits, or details that should not compete with the main surface.
|
|
93
|
+
|
|
94
|
+
Avoid when the user must reference or interact with the page content at the same time.
|
|
95
|
+
|
|
96
|
+
### Elevated (`elevated`)
|
|
97
|
+
|
|
98
|
+
Removes the overlay and does not lock body scroll. The panel floats above the page; users can still interact with content behind it.
|
|
99
|
+
|
|
100
|
+
Use when the drawer supports work on the main page — contextual editing, reference panels, or supplementary information.
|
|
101
|
+
|
|
102
|
+
Avoid for high-stakes flows where accidental background interaction would cause errors.
|
|
103
|
+
|
|
104
|
+
### Not in the API: `drawer-preheader`
|
|
105
|
+
|
|
106
|
+
MCP and `defineSlots` list `drawer-preheader`, but the Vue template does not render it. Do not emit that slot until the component wires it. Use `drawer-header` / `drawer-subheader` instead.
|
|
107
|
+
|
|
108
|
+
---
|
|
109
|
+
|
|
110
|
+
## Sizes
|
|
111
|
+
|
|
112
|
+
Panel width is token-driven inside the component — **don't hardcode pixel widths** in apps.
|
|
113
|
+
|
|
114
|
+
| Size | Use when |
|
|
115
|
+
| --- | --- |
|
|
116
|
+
| `default` | Standard drawers (580px on desktop) |
|
|
117
|
+
| `large` | Wider content — tables, two-column forms, rich media (780px on desktop) |
|
|
118
|
+
|
|
119
|
+
On viewports ≤ 767px the drawer becomes full-width. Footer CTAs stack vertically on very narrow widths (≤ 400px).
|
|
120
|
+
|
|
121
|
+
Optional CSS overrides (use sparingly, with design approval):
|
|
122
|
+
|
|
123
|
+
- `--drawer-width` — panel width
|
|
124
|
+
- `--drawer-padding` — inner padding (all sides)
|
|
125
|
+
|
|
126
|
+
> ZeroHeight labels the size table as "Height"; the implementation controls **width** (`--drawer-width`). Do not hardcode `580px` / `780px` in product CSS.
|
|
127
|
+
|
|
128
|
+
---
|
|
129
|
+
|
|
130
|
+
## States
|
|
131
|
+
|
|
132
|
+
| State | What the user sees / can do |
|
|
133
|
+
| --- | --- |
|
|
134
|
+
| Closed | Not in DOM flow (`v-if="isOpen"`); no overlay |
|
|
135
|
+
| Opening | Slide-in from the right (enter 300ms) |
|
|
136
|
+
| Open | Overlay (unless `elevated`); focusable body; dismiss via close / backdrop / Escape / cancel |
|
|
137
|
+
| Closing | Slide-out (leave 100ms); `drawer:hide` fires at start |
|
|
138
|
+
| Closed (after transition) | Removed from DOM; `drawer:after-hide` fires; body scroll restored |
|
|
139
|
+
| Elevated | No backdrop; page remains interactive |
|
|
140
|
+
| Scrollable body | Long content scrolls inside the body region |
|
|
141
|
+
| Footer present | `joy-drawer--footer-filled` when cancel/confirm props or slots are used |
|
|
142
|
+
| Demo / docs | `demoMode` prevents hide (Storybook only — not for production) |
|
|
143
|
+
|
|
144
|
+
Prefer `loading` on footer `VJoyButton` instances during async confirm work instead of silently disabling the drawer.
|
|
145
|
+
|
|
146
|
+
---
|
|
147
|
+
|
|
148
|
+
## Best practices
|
|
149
|
+
|
|
150
|
+
Rules use RFC 2119 strength (**MUST** / **SHOULD** / **MUST NOT** / **SHOULD NOT**).
|
|
151
|
+
|
|
152
|
+
### Hierarchy and placement
|
|
153
|
+
|
|
154
|
+
- **SHOULD** use one drawer per task — don't stack unrelated slide-overs.
|
|
155
|
+
- **SHOULD** prefer `elevated` only when background interaction is intentional.
|
|
156
|
+
- **MUST NOT** use a drawer for a short yes/no confirm that fits a dialog.
|
|
157
|
+
|
|
158
|
+
### Implementation
|
|
159
|
+
|
|
160
|
+
- **MUST** use only documented props and enum values (MCP / `JoyDrawer.types.ts`).
|
|
161
|
+
- **MUST** teleport to `body` in production (`teleport` default) — `disableTeleport` is for tests/docs.
|
|
162
|
+
- **MUST** wire `hide()` when using custom `drawer-cancel` / `drawer-confirm` slots.
|
|
163
|
+
- **MUST NOT** invent props (`width`, `variant`, `position`, …).
|
|
164
|
+
- **MUST NOT** override `.joy-drawer` chrome (background, shadow, radius, overlay) with app CSS.
|
|
165
|
+
- **MUST NOT** use `demoMode` outside Storybook.
|
|
166
|
+
|
|
167
|
+
### Interaction
|
|
168
|
+
|
|
169
|
+
- **MUST** provide a visible dismiss path (close icon and/or cancel CTA).
|
|
170
|
+
- **SHOULD** use `onBeforeHide` when closing would discard unsaved changes.
|
|
171
|
+
- **SHOULD** call `show()` / `hide()` with `await` when chaining transitions or focus management.
|
|
172
|
+
- **SHOULD** listen to `drawer:after-open` before moving focus into the first field.
|
|
173
|
+
|
|
174
|
+
### Footer CTAs
|
|
175
|
+
|
|
176
|
+
- **SHOULD** use `cancelText` / `confirmText` for simple cases (default `VJoyButton` wiring: ghost cancel, `main` confirm).
|
|
177
|
+
- **SHOULD** use `drawer-cancel` / `drawer-confirm` slots when you need custom variants, icons, or sizes — and **MUST** call `hide()` yourself on cancel.
|
|
178
|
+
- **SHOULD** use one `main` confirm CTA per drawer surface (see `VJoyButton` guidelines).
|
|
179
|
+
|
|
180
|
+
### Do / don't
|
|
181
|
+
|
|
182
|
+
| Do | Don't |
|
|
183
|
+
| --- | --- |
|
|
184
|
+
| `VJoyDrawerTrigger` for simple open buttons | Reimplement overlay + z-index stack |
|
|
185
|
+
| `elevated` when the page stays usable | Overlay mode for reference panels that need the page |
|
|
186
|
+
| `onBeforeHide` for dirty forms | Silent data loss on backdrop click |
|
|
187
|
+
| Explicit `closeLabel` when locale ≠ English default | Leave default "Close drawer" in localized apps |
|
|
188
|
+
| `size="large"` for wide tables/forms | Hardcode `width: 780px` on a wrapper |
|
|
189
|
+
| `VJoyDialog` for small confirms | A drawer for a one-line question |
|
|
190
|
+
|
|
191
|
+
---
|
|
192
|
+
|
|
193
|
+
## Content
|
|
194
|
+
|
|
195
|
+
Drawer copy should orient the user quickly: what they're viewing or editing, and what happens when they confirm or dismiss.
|
|
196
|
+
|
|
197
|
+
### Title formula
|
|
198
|
+
|
|
199
|
+
**Short noun phrase** — state the topic or object, not the implementation:
|
|
200
|
+
|
|
201
|
+
- ✅ Filter projects
|
|
202
|
+
- ✅ Edit billing address
|
|
203
|
+
- ✅ Project brief details
|
|
204
|
+
|
|
205
|
+
**Subheader** — one sentence of context. Don't repeat the title.
|
|
206
|
+
|
|
207
|
+
### Body copy
|
|
208
|
+
|
|
209
|
+
- **SHOULD** keep body text scannable; link out for long help or legal content.
|
|
210
|
+
- **MUST** explain consequences before destructive confirms in the body or subheader.
|
|
211
|
+
- **SHOULD NOT** bury the primary action below long paragraphs.
|
|
212
|
+
|
|
213
|
+
### Footer CTA rules
|
|
214
|
+
|
|
215
|
+
Follow `VJoyButton` content rules. Drawer-specific expectations:
|
|
216
|
+
|
|
217
|
+
| Strength | Rule |
|
|
218
|
+
| --- | --- |
|
|
219
|
+
| **MUST** | Confirm CTA names the outcome — ✅ `Apply filters`, `Save changes` |
|
|
220
|
+
| **MUST** | Cancel / dismiss CTA is neutral — ✅ `Cancel`, `Close` |
|
|
221
|
+
| **MUST NOT** | Vague confirm — ❌ `OK`, `Yes` (unless the title is unmistakable) |
|
|
222
|
+
| **SHOULD** | Destructive confirm repeats the object — ✅ `Delete project brief` |
|
|
223
|
+
| **SHOULD** | ≤ 25 characters per button label; wrap, don't truncate |
|
|
224
|
+
|
|
225
|
+
### Patterns
|
|
226
|
+
|
|
227
|
+
**Filters** — Title names the list (`Filter projects`); body holds controls; confirm applies filters (`Apply filters`); cancel discards (`Cancel` or `Reset` via custom slot).
|
|
228
|
+
|
|
229
|
+
**Details / read-only** — Title is the entity name; body is the content; optional single `Close` or ghost cancel; confirm only when an action exists.
|
|
230
|
+
|
|
231
|
+
**Dirty form** — Use `onBeforeHide` to confirm abandonment; pair with clear cancel and save CTAs.
|
|
232
|
+
|
|
233
|
+
**Localized apps** — Translate `closeLabel`, `cancelText`, `confirmText`, and all slot content. French copy may need articles/pronouns per `VJoyButton` FR guidance.
|
|
234
|
+
|
|
235
|
+
---
|
|
236
|
+
|
|
237
|
+
## Accessibility
|
|
238
|
+
|
|
239
|
+
Behaviors (what must happen), not slogans.
|
|
240
|
+
|
|
241
|
+
| Behavior | Expectation |
|
|
242
|
+
| --- | --- |
|
|
243
|
+
| Role | `role="dialog"` with `aria-modal="true"` |
|
|
244
|
+
| Name | Title in `drawer-header` referenced by `aria-labelledby` (`{id}-header`) |
|
|
245
|
+
| Description | Subheader content in `#drawerDescription` when present |
|
|
246
|
+
| Close control | `VJoyIconButton` with `closeLabel` (default: "Close drawer") |
|
|
247
|
+
| Keyboard | **Escape** dismisses (calls `hide()`) |
|
|
248
|
+
| Focus | Body region is focusable (`tabindex="0"`); move focus into the drawer on open when implementing custom flows |
|
|
249
|
+
| Scroll | Page scroll locked while open when `preventBodyScroll` and not `elevated` |
|
|
250
|
+
| Elevated | Background remains interactive — ensure users are not confused about what is modal |
|
|
251
|
+
| Motion | Slide transitions (300ms enter / 100ms leave); respect `prefers-reduced-motion` at app level if required |
|
|
252
|
+
|
|
253
|
+
Target: **WCAG 2.2 AA** where the product requires it.
|
|
254
|
+
|
|
255
|
+
---
|
|
256
|
+
|
|
257
|
+
## Examples
|
|
258
|
+
|
|
259
|
+
```vue
|
|
260
|
+
<script setup lang="ts">
|
|
261
|
+
import { ref } from 'vue'
|
|
262
|
+
import { VJoyDrawer } from '@maltjoy/core-vue'
|
|
263
|
+
|
|
264
|
+
const drawer = ref<InstanceType<typeof VJoyDrawer>>()
|
|
265
|
+
|
|
266
|
+
async function openDrawer() {
|
|
267
|
+
await drawer.value?.show()
|
|
268
|
+
}
|
|
269
|
+
|
|
270
|
+
async function onConfirm() {
|
|
271
|
+
// persist, then close
|
|
272
|
+
await drawer.value?.hide()
|
|
273
|
+
}
|
|
274
|
+
|
|
275
|
+
async function onBeforeHide() {
|
|
276
|
+
// return false to block close when form is dirty
|
|
277
|
+
return confirm('Discard unsaved changes?')
|
|
278
|
+
}
|
|
279
|
+
</script>
|
|
280
|
+
|
|
281
|
+
<template>
|
|
282
|
+
<!-- Basic drawer with prop-driven CTAs -->
|
|
283
|
+
<VJoyDrawer
|
|
284
|
+
ref="drawer"
|
|
285
|
+
cancel-text="Cancel"
|
|
286
|
+
confirm-text="Apply filters"
|
|
287
|
+
:on-before-hide="onBeforeHide"
|
|
288
|
+
@drawer:confirm="onConfirm"
|
|
289
|
+
>
|
|
290
|
+
<template #drawer-header>Filter projects</template>
|
|
291
|
+
<template #drawer-subheader>Narrow results without leaving the list.</template>
|
|
292
|
+
<template #drawer-body>
|
|
293
|
+
<!-- filter controls -->
|
|
294
|
+
</template>
|
|
295
|
+
</VJoyDrawer>
|
|
296
|
+
|
|
297
|
+
<VJoyButton variant="primary" label="Filters" @click="openDrawer" />
|
|
298
|
+
|
|
299
|
+
<!-- Elevated — page stays interactive -->
|
|
300
|
+
<VJoyDrawer elevated>
|
|
301
|
+
<template #drawer-header>Quick reference</template>
|
|
302
|
+
<template #drawer-body>…</template>
|
|
303
|
+
</VJoyDrawer>
|
|
304
|
+
|
|
305
|
+
<!-- Custom footer CTAs (you must call hide on cancel) -->
|
|
306
|
+
<VJoyDrawer ref="customDrawer">
|
|
307
|
+
<template #drawer-header>Custom actions</template>
|
|
308
|
+
<template #drawer-body>…</template>
|
|
309
|
+
<template #drawer-cancel>
|
|
310
|
+
<VJoyButton variant="ghost" label="Cancel" @click="customDrawer?.hide()" />
|
|
311
|
+
</template>
|
|
312
|
+
<template #drawer-confirm>
|
|
313
|
+
<VJoyButton variant="main" label="Save" @click="onConfirm" />
|
|
314
|
+
</template>
|
|
315
|
+
</VJoyDrawer>
|
|
316
|
+
</template>
|
|
317
|
+
```
|
|
318
|
+
|
|
319
|
+
In Nuxt (or apps with auto-import), omit imports if `VJoyDrawer` and `VJoyButton` are already global.
|
|
320
|
+
|
|
321
|
+
---
|
|
322
|
+
|
|
323
|
+
## Related
|
|
324
|
+
|
|
325
|
+
| Component | Use when |
|
|
326
|
+
| --- | --- |
|
|
327
|
+
| `VJoyDrawerTrigger` | Declarative open trigger wrapping any activator |
|
|
328
|
+
| `VJoyDialog` | Centered modal; short confirms or focused forms |
|
|
329
|
+
| `VJoyBottomSheet` | Mobile-optimized bottom sheet |
|
|
330
|
+
| `VJoyButton` | Footer CTAs (default or custom slots) |
|
|
331
|
+
| `VJoyIconButton` | Close control (built-in) |
|
|
332
|
+
| `VJoyWrapper` | Footer CTA layout (built-in) |
|
|
333
|
+
|
|
334
|
+
---
|
|
335
|
+
|
|
336
|
+
## For agents
|
|
337
|
+
|
|
338
|
+
Optional for readers; **required** for vibe-coding quality. Maps to `agentDocumentBlocks` in [`JoyDrawer.dsds.json`](./JoyDrawer.dsds.json).
|
|
339
|
+
|
|
340
|
+
### Pick the right component
|
|
341
|
+
|
|
342
|
+
| If the intent is… | Emit… | Do not emit… |
|
|
343
|
+
| --- | --- | --- |
|
|
344
|
+
| Side panel / filters / details | `VJoyDrawer` | Custom `position: fixed` slide-over |
|
|
345
|
+
| Short modal confirm | `VJoyDialog` | `VJoyDrawer` for one-line questions |
|
|
346
|
+
| Page stays interactive alongside panel | `VJoyDrawer` with `elevated` | Overlay drawer when user needs the page |
|
|
347
|
+
| Simple open from a button | `VJoyDrawer` + `VJoyDrawerTrigger` | Inline overlay markup |
|
|
348
|
+
| Mobile bottom sheet | `VJoyBottomSheet` | `VJoyDrawer` with hacked mobile CSS |
|
|
349
|
+
| Unsaved changes on close | `onBeforeHide` | Silent backdrop dismiss |
|
|
350
|
+
|
|
351
|
+
### Hard rules
|
|
352
|
+
|
|
353
|
+
1. **MUST** call MCP (`joy_get_component_info`, `joy_get_component_types`) before generating props.
|
|
354
|
+
2. **MUST** populate `drawer-header` (accessible name) for every drawer.
|
|
355
|
+
3. **MUST** handle `hide()` when using `drawer-cancel` / `drawer-confirm` slots.
|
|
356
|
+
4. **MUST NOT** invent props or sizes (`size` is only `default` \| `large`).
|
|
357
|
+
5. **MUST NOT** set `demoMode` in product code.
|
|
358
|
+
6. **MUST NOT** use `drawer-preheader` — not rendered in the Vue component.
|
|
359
|
+
7. **MUST NOT** override `.joy-drawer` overlay, shadow, radius, or z-index in app CSS.
|
|
360
|
+
8. **SHOULD** set localized `closeLabel` when UI language ≠ English.
|
|
361
|
+
9. **SHOULD** `await` `show()` / `hide()` when coordinating focus or route changes.
|
|
362
|
+
|
|
363
|
+
### Checklist
|
|
364
|
+
|
|
365
|
+
- [ ] Correct component (`VJoyDrawer` or named alternative)
|
|
366
|
+
- [ ] Props / enums from MCP only
|
|
367
|
+
- [ ] `drawer-header` present; no `drawer-preheader`
|
|
368
|
+
- [ ] Dismiss path defined (close and/or cancel)
|
|
369
|
+
- [ ] Custom slots wire `hide()` on cancel
|
|
370
|
+
- [ ] Confirm CTA label names the outcome
|
|
371
|
+
- [ ] `elevated` only when background interaction is intended
|
|
372
|
+
- [ ] `onBeforeHide` when close would discard data
|
|
373
|
+
- [ ] `closeLabel` localized when needed
|
|
374
|
+
|
|
375
|
+
---
|
|
376
|
+
|
|
377
|
+
## DSDS mapping
|
|
378
|
+
|
|
379
|
+
This Markdown mirrors [`JoyDrawer.dsds.json`](./JoyDrawer.dsds.json) (DSDS **0.15.2**).
|
|
380
|
+
|
|
381
|
+
| Section here | DSDS block |
|
|
382
|
+
| --- | --- |
|
|
383
|
+
| When to use / not | `use-cases` |
|
|
384
|
+
| Anatomy | `anatomy` |
|
|
385
|
+
| Variants / sizes | `variants` |
|
|
386
|
+
| States | `states` |
|
|
387
|
+
| Best practices / content rules | `guidelines` (+ `content`) |
|
|
388
|
+
| Accessibility | `accessibility` |
|
|
389
|
+
| Examples | `sections` |
|
|
390
|
+
| For agents | `agentDocumentBlocks` |
|
|
391
|
+
| Props detail | `api` in JSON + Joy MCP |
|
|
392
|
+
| Token sizing | `design-specifications` in JSON (`--drawer-width`, spacing tokens) |
|