@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,384 @@
|
|
|
1
|
+
---
|
|
2
|
+
component: VJoyButtonCard
|
|
3
|
+
status: draft
|
|
4
|
+
language: en
|
|
5
|
+
dsds: JoyButtonCard.dsds.json
|
|
6
|
+
dsdsVersion: "0.15.2"
|
|
7
|
+
---
|
|
8
|
+
|
|
9
|
+
# Button card
|
|
10
|
+
|
|
11
|
+
Use **`VJoyButtonCard`** when the user needs a **rich, card-shaped call to action** — a title, subtitle, illustration, or other composed content that would not fit in a standard `VJoyButton`.
|
|
12
|
+
|
|
13
|
+
The component supplies bordered card chrome, hover and focus feedback, and disabled handling. **You compose and style the inner content** via the default slot. It can act as an in-page action (`@click`), a native link (`href`), or a router link (`type` + attrs such as `to`).
|
|
14
|
+
|
|
15
|
+
| | |
|
|
16
|
+
| --- | --- |
|
|
17
|
+
| **Code** | `VJoyButtonCard` from `@maltjoy/core-vue` |
|
|
18
|
+
| **Design** | [ZeroHeight — ButtonCard](https://zeroheight.com/6bf479565/) (page id `3079912`) |
|
|
19
|
+
| **Storybook** | [VJoyButtonCard docs](https://doc.malt.tech/joy-storybook/?path=/docs/components-buttons-vjoybuttoncard--docs) |
|
|
20
|
+
| **DSDS (machine)** | [`JoyButtonCard.dsds.json`](./JoyButtonCard.dsds.json) |
|
|
21
|
+
| **Live API** | `joy_get_component_info("VJoyButtonCard")` |
|
|
22
|
+
|
|
23
|
+
---
|
|
24
|
+
|
|
25
|
+
## When to use this component
|
|
26
|
+
|
|
27
|
+
Use a button card when the choice or action needs **more than a short label** — for example branching onboarding paths, profile-type pickers, or navigation tiles with an icon, title, and supporting line.
|
|
28
|
+
|
|
29
|
+
Typical jobs: “choose your account type”, “complete your freelance profile”, or opening a destination that benefits from a scannable card layout. The whole card surface is the click target.
|
|
30
|
+
|
|
31
|
+
Compose several cards in a group when each option represents a **distinct path or action**. Add a group label (`VJoyLabel` or a heading) when the set needs framing context.
|
|
32
|
+
|
|
33
|
+
### When not to use this component
|
|
34
|
+
|
|
35
|
+
| Need | Use instead |
|
|
36
|
+
| --- | --- |
|
|
37
|
+
| A short text label only (save, cancel, continue) | `VJoyButton` |
|
|
38
|
+
| Icon-only action | `VJoyIconButton` |
|
|
39
|
+
| Inline text navigation in body copy | `VJoyLink` |
|
|
40
|
+
| Picking one option from a list (form data, shipping method) | `VJoyRadio` (`theme="outline"`) inside `VJoyRadioGroup` |
|
|
41
|
+
| Multi-select with card layout | `VJoyCheckboxCard` inside `VJoyCheckboxGroup` |
|
|
42
|
+
| Toggle a single on/off setting | `VJoyToggle` |
|
|
43
|
+
| Custom bordered div + click handler | Still use `VJoyButtonCard` + Joy tokens — don’t reinvent chrome |
|
|
44
|
+
|
|
45
|
+
> **Deprecated:** `VJoySelectableItem` / `VJoySelectableItemGroup` remain deprecated. Use `VJoyButtonCard` when the interaction is a **CTA or link**, `VJoyCheckboxCard` for boolean multi-select cards, and `VJoyRadio` for exclusive choice.
|
|
46
|
+
|
|
47
|
+
---
|
|
48
|
+
|
|
49
|
+
## How it works
|
|
50
|
+
|
|
51
|
+
### Anatomy
|
|
52
|
+
|
|
53
|
+
| Part | Required? | What it is |
|
|
54
|
+
| --- | --- | --- |
|
|
55
|
+
| Card container | Yes | Root `.joy-button-card` — border, padding, hover, focus, disabled styling |
|
|
56
|
+
| Default slot content | Yes | **Your** title, subtitle, icon, image, or layout — not provided by the component |
|
|
57
|
+
| Focus ring | Yes | `outline` on `:focus-visible` — don’t remove it in product CSS |
|
|
58
|
+
|
|
59
|
+
There is no built-in title, subtitle, or icon API. Structure copy and imagery in the slot (for example `<strong>` + `<span>`, or `VJoyText` / `VJoyIcon`).
|
|
60
|
+
|
|
61
|
+
### Rendering modes
|
|
62
|
+
|
|
63
|
+
The `type` prop chooses the root element (default **`"button"`** — a naming legacy, not always a native `<button>`):
|
|
64
|
+
|
|
65
|
+
| Configuration | Root element | Typical use |
|
|
66
|
+
| --- | --- | --- |
|
|
67
|
+
| Default (`type="button"`, no `href`) | `<div role="button" tabindex="0">` | In-page action via `@click` |
|
|
68
|
+
| `href` set (default `type`) | `<a href="…">` | External or same-origin navigation |
|
|
69
|
+
| `type="a"` | `<a>` | Explicit anchor; pass `href` via attrs or prop |
|
|
70
|
+
| `type={RouterLink}` (or other component) | That component | SPA routing — pass `to` and other attrs |
|
|
71
|
+
|
|
72
|
+
Native attributes (`target`, `rel`, `to`, `aria-*`, `@click`, …) pass through via `useAttrs` (`inheritAttrs: false` on the component).
|
|
73
|
+
|
|
74
|
+
### Default values
|
|
75
|
+
|
|
76
|
+
- `disabled` defaults to **`false`**
|
|
77
|
+
- `type` defaults to **`"button"`** (renders pseudo-button `<div>` or `<a>` when `href` is set — see table above)
|
|
78
|
+
- `align` defaults to **`"left"`**
|
|
79
|
+
|
|
80
|
+
Props, events, and slots: use Joy MCP or Storybook — this page focuses on **when** and **how**, not a full API dump.
|
|
81
|
+
|
|
82
|
+
### Visual treatment
|
|
83
|
+
|
|
84
|
+
There is **no `variant` or `size` prop**. Border, radius, padding, and colors come from Joy tokens inside the component (`--joy-core-spacing-3`, `--joy-core-radius-4`, `--joy-color-neutral-*`, state tokens) — **don’t hardcode card dimensions or border colors** in product CSS. Card width is **`fit-content`** by default.
|
|
85
|
+
|
|
86
|
+
---
|
|
87
|
+
|
|
88
|
+
## Variants
|
|
89
|
+
|
|
90
|
+
`VJoyButtonCard` has **no visual emphasis variants** (no primary/secondary). Meaning comes from **content** in the slot and from **state** (`disabled`, hover, focus).
|
|
91
|
+
|
|
92
|
+
### Content alignment (`align`)
|
|
93
|
+
|
|
94
|
+
| Value | Use when |
|
|
95
|
+
| --- | --- |
|
|
96
|
+
| `left` | Default — text-heavy cards, LTR product UI |
|
|
97
|
+
| `center` | Icon-above-title tiles, symmetric marketing pickers |
|
|
98
|
+
| `right` | Rare; RTL-like layout or deliberate visual balance |
|
|
99
|
+
|
|
100
|
+
`align` only sets `text-align` on the card — it does not change padding or border.
|
|
101
|
+
|
|
102
|
+
### Not in the API: selected / checked state
|
|
103
|
+
|
|
104
|
+
ZeroHeight usage text describes a **“Selected”** border for card pickers. `VJoyButtonCard` has **no `selected`, `checked`, or `active` prop**. For exclusive or multi selection, use `VJoyRadio` (`theme="outline"`) or `VJoyCheckboxCard`. Use `VJoyButtonCard` when the card **navigates or triggers an action**, not when it toggles form value.
|
|
105
|
+
|
|
106
|
+
### Not in the API: loading
|
|
107
|
+
|
|
108
|
+
There is no `loading` prop. Keep layout stable with surrounding UI or disable the card while async work runs.
|
|
109
|
+
|
|
110
|
+
---
|
|
111
|
+
|
|
112
|
+
## Sizes
|
|
113
|
+
|
|
114
|
+
`VJoyButtonCard` exposes **no size API**. Padding and border width are fixed in component styles.
|
|
115
|
+
|
|
116
|
+
| Aspect | Guidance |
|
|
117
|
+
| --- | --- |
|
|
118
|
+
| Card width | `fit-content` — wrap in a grid or `VJoyWrapper` for equal-width groups |
|
|
119
|
+
| Inner typography | Use `VJoyText`, headings, or Joy utility classes in the slot — don’t invent `size` on the card |
|
|
120
|
+
| Density | Prefer shorter copy over shrinking padding via custom CSS |
|
|
121
|
+
|
|
122
|
+
---
|
|
123
|
+
|
|
124
|
+
## States
|
|
125
|
+
|
|
126
|
+
| State | What the user sees / can do |
|
|
127
|
+
| --- | --- |
|
|
128
|
+
| Default | Neutral border; pointer cursor; entire card clickable |
|
|
129
|
+
| Hover | Border uses `--joy-color-state-hover` (pointer devices, when not disabled) |
|
|
130
|
+
| Focus | Visible `outline` + hover border token on `:focus-visible` |
|
|
131
|
+
| Disabled | Muted border, background, and text; `aria-disabled="true"`; `tabindex="-1"`; clicks prevented — **explain why** nearby when possible |
|
|
132
|
+
| Pseudo-button keyboard | **Enter** and **Space** synthesize a click on the `<div role="button">` root |
|
|
133
|
+
| Anchor / router | Native link or router keyboard behavior; disabled still sets `aria-disabled` and blocks interaction |
|
|
134
|
+
|
|
135
|
+
---
|
|
136
|
+
|
|
137
|
+
## Best practices
|
|
138
|
+
|
|
139
|
+
Rules use RFC 2119 strength (**MUST** / **SHOULD** / **MUST NOT** / **SHOULD NOT**).
|
|
140
|
+
|
|
141
|
+
### When to choose this over a plain button
|
|
142
|
+
|
|
143
|
+
- **SHOULD** use button cards for **branching** choices that change the user’s path or open a rich destination.
|
|
144
|
+
- **MUST NOT** use button cards for simple form fields where `VJoyRadio` or `VJoySelect` is enough.
|
|
145
|
+
- **SHOULD** use `VJoyButton` when the label fits in one short line.
|
|
146
|
+
|
|
147
|
+
### Groups and hierarchy
|
|
148
|
+
|
|
149
|
+
- **SHOULD** make each card in a group **meaningfully distinct** — if two labels could be swapped, rewrite them.
|
|
150
|
+
- **SHOULD** add a group label (`VJoyLabel` or heading) when options aren’t self-evident.
|
|
151
|
+
- **SHOULD** avoid a competing principal `VJoyButton` (`variant="main"`) directly beside the card group — subordinate “Continue” below the choice.
|
|
152
|
+
- **MUST NOT** nest secondary links, tooltips, or buttons inside the card — the whole surface is one target.
|
|
153
|
+
|
|
154
|
+
### Implementation
|
|
155
|
+
|
|
156
|
+
- **MUST** use only documented props from MCP or `JoyButtonCard.types.ts` (`disabled`, `href`, `type`, `align`).
|
|
157
|
+
- **MUST** style inner content with Joy typography / spacing utilities — no custom `.joy-button-card` border, padding, radius, or background overrides.
|
|
158
|
+
- **MUST NOT** invent props (`variant`, `size`, `selected`, `loading`, …).
|
|
159
|
+
- **MUST** pass `href` (or router `to`) when the card navigates; use `@click` on the pseudo-button for in-page actions.
|
|
160
|
+
- **SHOULD** set `target` and `rel="noopener"` on external links.
|
|
161
|
+
- **SHOULD** lay out groups with `VJoyWrapper` (grid / flex + gap) rather than margin hacks between cards.
|
|
162
|
+
|
|
163
|
+
### Do / don’t
|
|
164
|
+
|
|
165
|
+
| Do | Don’t |
|
|
166
|
+
| --- | --- |
|
|
167
|
+
| Rich slot content (title + subtitle + icon) | `VJoyButton` with multi-line slot hacks |
|
|
168
|
+
| `VJoyRadio` outline for exclusive form choice | `VJoyButtonCard` pretending to be a radio |
|
|
169
|
+
| One clear action per card surface | Submit button inside the card |
|
|
170
|
+
| `disabled` + visible explanation | Disabled card with no reason |
|
|
171
|
+
| Joy tokens in slot typography | Hardcoded card border / padding in apps |
|
|
172
|
+
|
|
173
|
+
---
|
|
174
|
+
|
|
175
|
+
## Content
|
|
176
|
+
|
|
177
|
+
Slot copy should help users **self-select** the right path. Follow the same patterns as ZeroHeight ButtonCard content guidelines.
|
|
178
|
+
|
|
179
|
+
### Group label (optional)
|
|
180
|
+
|
|
181
|
+
Use when the card set needs a framing question or context:
|
|
182
|
+
|
|
183
|
+
- ✅ What type of account are you creating?
|
|
184
|
+
- ✅ Account type
|
|
185
|
+
- ❌ Please select one of the following options.
|
|
186
|
+
|
|
187
|
+
Use sentence case. End questions with `?`.
|
|
188
|
+
|
|
189
|
+
### Label (title in slot)
|
|
190
|
+
|
|
191
|
+
**Short noun phrase** naming the path or option — the first thing users read:
|
|
192
|
+
|
|
193
|
+
- ✅ Freelance profile
|
|
194
|
+
- ✅ Company account
|
|
195
|
+
|
|
196
|
+
Keep labels **parallel** across siblings (same grammar). Target **two to four words**, one line, sentence case, no trailing punctuation.
|
|
197
|
+
|
|
198
|
+
### Subtitle (supporting line in slot)
|
|
199
|
+
|
|
200
|
+
Clarifies the label — answers “is this the right option for me?”:
|
|
201
|
+
|
|
202
|
+
- ✅ Complete your skills and availability.
|
|
203
|
+
- ✅ Manage team members and billing.
|
|
204
|
+
|
|
205
|
+
One or two lines. Don’t restate the label. Use a full sentence with a period, or a tight noun phrase without one — stay consistent within the group.
|
|
206
|
+
|
|
207
|
+
### Icon / illustration
|
|
208
|
+
|
|
209
|
+
- **SHOULD** reinforce the label; omit if decorative only.
|
|
210
|
+
- **MUST NOT** use an icon as the only accessible name — pair with visible text.
|
|
211
|
+
|
|
212
|
+
### Writing rules
|
|
213
|
+
|
|
214
|
+
| Strength | Rule |
|
|
215
|
+
| --- | --- |
|
|
216
|
+
| **MUST** | Every card has a visible primary label in the slot |
|
|
217
|
+
| **MUST** | Options in a group feel distinct — rewrite if labels are interchangeable |
|
|
218
|
+
| **MUST NOT** | Imply a “right answer” in copy unless one genuinely exists |
|
|
219
|
+
| **MUST NOT** | Overlap subtitles across cards — options may be too similar |
|
|
220
|
+
| **SHOULD** | Include a catch-all option (e.g. Other) when the set must feel exhaustive |
|
|
221
|
+
| **SHOULD** | Keep subtitles to one or two lines — split or redesign if more is needed |
|
|
222
|
+
|
|
223
|
+
---
|
|
224
|
+
|
|
225
|
+
## Accessibility
|
|
226
|
+
|
|
227
|
+
Behaviors (what must happen), not slogans.
|
|
228
|
+
|
|
229
|
+
| Behavior | Expectation |
|
|
230
|
+
| --- | --- |
|
|
231
|
+
| Role | `<a>` for links; `<div role="button">` for default in-page actions; router component defines its own semantics |
|
|
232
|
+
| Name | From visible text in the default slot — ensure a concise title is present |
|
|
233
|
+
| Keyboard | Pseudo-button: **Tab** to focus, **Enter** / **Space** activate; links: native link keys |
|
|
234
|
+
| Focus | Visible focus ring on `:focus-visible` — don’t remove `outline` in product CSS |
|
|
235
|
+
| Disabled | `aria-disabled="true"`, `tabindex="-1"`, click/key activation blocked |
|
|
236
|
+
| Large target | Entire card is the hit area — don’t nest separate interactive controls inside |
|
|
237
|
+
| External links | Meaningful link text in the slot; `rel="noopener"` when opening new tabs |
|
|
238
|
+
|
|
239
|
+
Target: **WCAG 2.2 AA** where the product requires it.
|
|
240
|
+
|
|
241
|
+
---
|
|
242
|
+
|
|
243
|
+
## Examples
|
|
244
|
+
|
|
245
|
+
```vue
|
|
246
|
+
<script setup lang="ts">
|
|
247
|
+
import { RouterLink } from 'vue-router'
|
|
248
|
+
import { VJoyButtonCard, VJoyWrapper, VJoyIcon, VJoyLabel } from '@maltjoy/core-vue'
|
|
249
|
+
|
|
250
|
+
function openWizard() {
|
|
251
|
+
// navigate or open flow
|
|
252
|
+
}
|
|
253
|
+
</script>
|
|
254
|
+
|
|
255
|
+
<template>
|
|
256
|
+
<!-- In-page action (pseudo-button) -->
|
|
257
|
+
<VJoyButtonCard @click="openWizard">
|
|
258
|
+
<strong>Freelance profile</strong>
|
|
259
|
+
<span class="joy-d-block">Complete your profile</span>
|
|
260
|
+
</VJoyButtonCard>
|
|
261
|
+
|
|
262
|
+
<!-- External link -->
|
|
263
|
+
<VJoyButtonCard
|
|
264
|
+
href="https://www.malt.fr/help"
|
|
265
|
+
target="_blank"
|
|
266
|
+
rel="noopener"
|
|
267
|
+
>
|
|
268
|
+
<strong>Help center</strong>
|
|
269
|
+
<span class="joy-d-block">Browse guides and FAQs</span>
|
|
270
|
+
</VJoyButtonCard>
|
|
271
|
+
|
|
272
|
+
<!-- Router link -->
|
|
273
|
+
<VJoyButtonCard :type="RouterLink" to="/onboarding/company">
|
|
274
|
+
<VJoyIcon name="building" />
|
|
275
|
+
<strong>Company account</strong>
|
|
276
|
+
<span class="joy-d-block">Invite your team</span>
|
|
277
|
+
</VJoyButtonCard>
|
|
278
|
+
|
|
279
|
+
<!-- Centered tile -->
|
|
280
|
+
<VJoyButtonCard align="center" href="/onboarding/freelance">
|
|
281
|
+
<img src="/illustrations/freelance.svg" width="80" alt="" />
|
|
282
|
+
<strong class="joy-mt-2">Freelance profile</strong>
|
|
283
|
+
<span class="joy-d-block">Complete your profile</span>
|
|
284
|
+
</VJoyButtonCard>
|
|
285
|
+
|
|
286
|
+
<!-- Group layout -->
|
|
287
|
+
<VJoyWrapper direction="column" row-gap="4">
|
|
288
|
+
<VJoyLabel>What type of account are you creating?</VJoyLabel>
|
|
289
|
+
<VJoyWrapper direction="row" column-gap="4" wrap="wrap">
|
|
290
|
+
<VJoyButtonCard href="/onboarding/freelance">
|
|
291
|
+
<strong>Freelance</strong>
|
|
292
|
+
<span class="joy-d-block">Work as an independent.</span>
|
|
293
|
+
</VJoyButtonCard>
|
|
294
|
+
<VJoyButtonCard href="/onboarding/company">
|
|
295
|
+
<strong>Company</strong>
|
|
296
|
+
<span class="joy-d-block">Hire and manage projects.</span>
|
|
297
|
+
</VJoyButtonCard>
|
|
298
|
+
</VJoyWrapper>
|
|
299
|
+
</VJoyWrapper>
|
|
300
|
+
|
|
301
|
+
<!-- Disabled -->
|
|
302
|
+
<VJoyButtonCard disabled href="/unavailable">
|
|
303
|
+
<strong>Enterprise</strong>
|
|
304
|
+
<span class="joy-d-block">Contact sales to enable.</span>
|
|
305
|
+
</VJoyButtonCard>
|
|
306
|
+
</template>
|
|
307
|
+
```
|
|
308
|
+
|
|
309
|
+
In Nuxt (or apps with auto-import), omit imports if components are already global. Decorative images should use `alt=""`; meaningful images need descriptive `alt` text.
|
|
310
|
+
|
|
311
|
+
---
|
|
312
|
+
|
|
313
|
+
## Related
|
|
314
|
+
|
|
315
|
+
| Component | Use when |
|
|
316
|
+
| --- | --- |
|
|
317
|
+
| `VJoyButton` | Short labeled actions with variants and loading |
|
|
318
|
+
| `VJoyIconButton` | Icon-only actions |
|
|
319
|
+
| `VJoyLink` | Inline text navigation |
|
|
320
|
+
| `VJoyRadio` / `VJoyRadioGroup` | Exactly one choice in a form (`theme="outline"` for card-like radios) |
|
|
321
|
+
| `VJoyCheckboxCard` / `VJoyCheckboxGroup` | Multi-select card options |
|
|
322
|
+
| `VJoyWrapper` | Grid or flex layout for card groups |
|
|
323
|
+
| `VJoyLabel` | Group question or legend above cards |
|
|
324
|
+
| `VJoyText` / `VJoyIcon` | Typography and icons inside the slot |
|
|
325
|
+
|
|
326
|
+
---
|
|
327
|
+
|
|
328
|
+
## For agents
|
|
329
|
+
|
|
330
|
+
Maps to `agentDocumentBlocks` in [`JoyButtonCard.dsds.json`](./JoyButtonCard.dsds.json). Humans can skip this section.
|
|
331
|
+
|
|
332
|
+
### Pick the right component
|
|
333
|
+
|
|
334
|
+
| If the intent is… | Emit… | Do not emit… |
|
|
335
|
+
| --- | --- | --- |
|
|
336
|
+
| Rich CTA / navigation tile | `VJoyButtonCard` | Custom bordered `div` + `@click` |
|
|
337
|
+
| Short verb label (Save, Cancel) | `VJoyButton` | `VJoyButtonCard` with one word |
|
|
338
|
+
| Exclusive form choice | `VJoyRadio` `theme="outline"` | `VJoyButtonCard` + fake selected state |
|
|
339
|
+
| Multi-select cards | `VJoyCheckboxCard` | `VJoyButtonCard` |
|
|
340
|
+
| Icon-only | `VJoyIconButton` | Card with only an icon |
|
|
341
|
+
| SPA route | `VJoyButtonCard` `:type="RouterLink"` + `to` | `div` + manual router push only |
|
|
342
|
+
|
|
343
|
+
### Hard rules
|
|
344
|
+
|
|
345
|
+
1. **MUST** call `joy_get_component_info("VJoyButtonCard")` or read `JoyButtonCard.types.ts` before generating props.
|
|
346
|
+
2. **MUST** put title and supporting copy in the **default slot** — there is no `label` prop.
|
|
347
|
+
3. **MUST** use `href` or router `to` for navigation; `@click` for pseudo-button actions.
|
|
348
|
+
4. **MUST NOT** invent props — no `variant`, `size`, `selected`, `loading`, or `label`.
|
|
349
|
+
5. **MUST NOT** override `.joy-button-card` border, padding, radius, or background.
|
|
350
|
+
6. **MUST NOT** nest buttons or links inside the card.
|
|
351
|
+
7. **SHOULD** use `align="center"` for icon-above-title tiles.
|
|
352
|
+
8. **SHOULD** explain `disabled` in visible nearby text.
|
|
353
|
+
|
|
354
|
+
### Checklist
|
|
355
|
+
|
|
356
|
+
- [ ] Correct component (`VJoyButtonCard` or named alternative)
|
|
357
|
+
- [ ] Props from MCP / types only (`disabled`, `href`, `type`, `align`)
|
|
358
|
+
- [ ] Default slot has accessible primary label text
|
|
359
|
+
- [ ] Navigation uses `href` or `RouterLink`; actions use `@click` on pseudo-button
|
|
360
|
+
- [ ] No invented selected/loading/variant API
|
|
361
|
+
- [ ] No custom `.joy-button-card` chrome CSS
|
|
362
|
+
- [ ] No nested interactive controls inside the card
|
|
363
|
+
- [ ] Group cards are distinct; optional `VJoyLabel` for context
|
|
364
|
+
- [ ] Disabled state explained when user-visible
|
|
365
|
+
|
|
366
|
+
---
|
|
367
|
+
|
|
368
|
+
## DSDS mapping
|
|
369
|
+
|
|
370
|
+
This Markdown mirrors [`JoyButtonCard.dsds.json`](./JoyButtonCard.dsds.json) (DSDS **0.15.2**).
|
|
371
|
+
|
|
372
|
+
| Section here | DSDS block |
|
|
373
|
+
| --- | --- |
|
|
374
|
+
| When to use / not | `use-cases` |
|
|
375
|
+
| Anatomy / rendering modes | `anatomy` |
|
|
376
|
+
| Alignment / no variants | `variants` |
|
|
377
|
+
| Sizes (no size API) | `design-specifications` |
|
|
378
|
+
| States | `states` |
|
|
379
|
+
| Best practices / content rules | `guidelines` (+ `content`) |
|
|
380
|
+
| Accessibility | `accessibility` |
|
|
381
|
+
| Examples | `sections` |
|
|
382
|
+
| For agents | `agentDocumentBlocks` |
|
|
383
|
+
| Props detail | `api` in JSON + Joy MCP |
|
|
384
|
+
| Imports | `imports` in JSON |
|