@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,379 @@
|
|
|
1
|
+
---
|
|
2
|
+
component: VJoyInputPassword
|
|
3
|
+
status: draft
|
|
4
|
+
language: en
|
|
5
|
+
dsds: JoyInputPassword.dsds.json
|
|
6
|
+
dsdsVersion: "0.15.2"
|
|
7
|
+
---
|
|
8
|
+
|
|
9
|
+
# Input Password
|
|
10
|
+
|
|
11
|
+
Use **`VJoyInputPassword`** when the user must enter a password — sign-in, sign-up, password change, or API key entry where masking is expected.
|
|
12
|
+
|
|
13
|
+
It wraps `VJoyInput` with a built-in show/hide toggle (`eye` / `eye-masked` icons), optional strength requirements via the `password-requirements` slot, and the same label, validation, and sizing patterns as other Joy form fields. Native attributes such as `placeholder`, `autocomplete`, and `aria-*` pass through to the underlying `<input>`.
|
|
14
|
+
|
|
15
|
+
| | |
|
|
16
|
+
| --- | --- |
|
|
17
|
+
| **Code** | `VJoyInputPassword` from `@maltjoy/core-vue` |
|
|
18
|
+
| **Design** | [ZeroHeight — Input Password](https://zeroheight.com/6bf479565/p/8386038) |
|
|
19
|
+
| **Storybook** | [VJoyInputPassword docs](https://doc.malt.tech/joy-storybook/?path=/docs/components-forms-vjoyinputpassword--docs) |
|
|
20
|
+
| **DSDS (machine)** | [`JoyInputPassword.dsds.json`](./JoyInputPassword.dsds.json) |
|
|
21
|
+
| **Live API** | `joy_get_component_info("VJoyInputPassword")` |
|
|
22
|
+
|
|
23
|
+
---
|
|
24
|
+
|
|
25
|
+
## When to use this component
|
|
26
|
+
|
|
27
|
+
Use a password input when the value must stay masked by default and the user may optionally reveal it to check typing — login forms, registration, “confirm password” steps, or credential settings.
|
|
28
|
+
|
|
29
|
+
Pair it with a visible label, `autocomplete` hints (`current-password`, `new-password`), and validation feedback when rules fail. For live strength feedback, compose `VJoyPasswordRequirement` items in the `password-requirements` slot.
|
|
30
|
+
|
|
31
|
+
### When not to use this component
|
|
32
|
+
|
|
33
|
+
| Need | Use instead |
|
|
34
|
+
| --- | --- |
|
|
35
|
+
| Single-line non-secret text (email, name, search) | `VJoyInput` |
|
|
36
|
+
| One-time / verification code (OTP, PIN) | `VJoyInputDigit` |
|
|
37
|
+
| Multi-line secret or note | `VJoyTextarea` (rare — confirm with security if truly secret) |
|
|
38
|
+
| Numeric value with a unit suffix | `VJoyInputNumber` |
|
|
39
|
+
| Custom `<input type="password">` with ad-hoc toggle | Still use `VJoyInputPassword` + Joy tokens |
|
|
40
|
+
| `type="password"` on `VJoyInput` | `VJoyInputPassword` |
|
|
41
|
+
|
|
42
|
+
> **Deprecated:** do not use `type="password"` on `VJoyInput` for new work — use `VJoyInputPassword`.
|
|
43
|
+
|
|
44
|
+
---
|
|
45
|
+
|
|
46
|
+
## How it works
|
|
47
|
+
|
|
48
|
+
### Anatomy
|
|
49
|
+
|
|
50
|
+
| Part | Required? | What it is |
|
|
51
|
+
| --- | --- | --- |
|
|
52
|
+
| Root container | Yes | Wrapper (`.joy-input-password`) around input + optional requirements |
|
|
53
|
+
| `VJoyInput` | Yes | Underlying text field; `type` toggles `password` ↔ `text` |
|
|
54
|
+
| Label | No | `VJoyLabel` from the `label` prop (or external `VJoyLabel` + `id` / `name`) |
|
|
55
|
+
| Native `<input>` | Yes | Receives `$attrs` (placeholder, autocomplete, maxlength, etc.) |
|
|
56
|
+
| Visibility toggle | Yes | Trailing `VJoyIcon` (`eye` when masked, `eye-masked` when visible) in `right-action` |
|
|
57
|
+
| Password requirements | No | `password-requirements` slot — typically `VJoyPasswordRequirement` rows inside `VJoyWrapper` |
|
|
58
|
+
| Focus ring | Yes | Inherited from `VJoyInput` — do not remove in product CSS |
|
|
59
|
+
|
|
60
|
+
Masked characters use a local font treatment (`Verdana` + letter-spacing) on `input[type="password"]`; placeholders keep the default Joy font.
|
|
61
|
+
|
|
62
|
+
### Default values
|
|
63
|
+
|
|
64
|
+
- `name` defaults to **`"joy-input-password"`** — override in real forms
|
|
65
|
+
- `size` defaults to **`medium`** (inherited from `VJoyInput`)
|
|
66
|
+
- `labelSize` defaults to **`medium`**
|
|
67
|
+
- `modelModifiers` defaults to **`{ lazy: false }`**
|
|
68
|
+
- `disabled`, `invalid`, `required`, `requiredMark`, and `autofocus` default to **`false`**
|
|
69
|
+
|
|
70
|
+
Props, events, and slots: use Joy MCP or Storybook — this page focuses on **when** and **how**, not a full API dump.
|
|
71
|
+
|
|
72
|
+
### Not on this component
|
|
73
|
+
|
|
74
|
+
`VJoyInputPasswordProps` omits **`type`**, **`clearable`**, **`clearAriaLabel`**, and **`readonly`** from `VJoyInput`. Do not pass them — passwords are not clearable or readonly through this API.
|
|
75
|
+
|
|
76
|
+
### Visual treatment
|
|
77
|
+
|
|
78
|
+
There is **no `variant` prop**. Appearance comes from **state** (`invalid`, `disabled`) and **density** (`size`), same as `VJoyInput`.
|
|
79
|
+
|
|
80
|
+
---
|
|
81
|
+
|
|
82
|
+
## Sizes
|
|
83
|
+
|
|
84
|
+
Choose size for **density** within the form. Heights and radii come from `--joy-form-field-height-*` and `--joy-form-field-radius-*` — **do not hardcode pixel heights** in apps.
|
|
85
|
+
|
|
86
|
+
| Size | Use when |
|
|
87
|
+
| --- | --- |
|
|
88
|
+
| `small` | Dense auth panels or compact settings rows |
|
|
89
|
+
| `medium` | Default login, registration, and account forms |
|
|
90
|
+
| `large` | Marketing-scale or hero auth layouts |
|
|
91
|
+
|
|
92
|
+
Match label size to field size when possible (`labelSize` aligns with `VJoyLabel` sizes).
|
|
93
|
+
|
|
94
|
+
---
|
|
95
|
+
|
|
96
|
+
## States
|
|
97
|
+
|
|
98
|
+
| State | What the user sees / can do |
|
|
99
|
+
| --- | --- |
|
|
100
|
+
| Default (masked) | Bullets/dots in the field; `eye` icon on the right; editable |
|
|
101
|
+
| Revealed | Toggle clicked — `type="text"`, value visible; `eye-masked` icon |
|
|
102
|
+
| Hover | Border shifts on the underlying input (pointer devices) |
|
|
103
|
+
| Focus | Focus border and `joy-input--focusing` on the wrapper |
|
|
104
|
+
| Valid (implicit) | Neutral styling when not `invalid` and not `disabled` |
|
|
105
|
+
| Invalid | Error border and text color from `VJoyInput` — pair with `VJoyFormError` |
|
|
106
|
+
| Disabled | Field and toggle non-interactive; toggle shows `not-allowed` cursor — explain why nearby |
|
|
107
|
+
|
|
108
|
+
Toggling visibility does not change `modelValue` — only the input `type` and icon.
|
|
109
|
+
|
|
110
|
+
---
|
|
111
|
+
|
|
112
|
+
## Best practices
|
|
113
|
+
|
|
114
|
+
Rules use RFC 2119 strength (**MUST** / **SHOULD** / **MUST NOT** / **SHOULD NOT**).
|
|
115
|
+
|
|
116
|
+
### Labels and forms
|
|
117
|
+
|
|
118
|
+
- **MUST** provide a visible label (via `label`, `VJoyLabel`, or associated `<label for="…">`).
|
|
119
|
+
- **MUST** set `name` (and `id` when multiple password fields share a form) for labels, autofill, and tests. `id` falls back to `name` on `VJoyInput`.
|
|
120
|
+
- **SHOULD** set `autocomplete="current-password"` on sign-in and `autocomplete="new-password"` on registration or change-password flows.
|
|
121
|
+
- **SHOULD** use `requiredMark` with `required` when the form uses asterisks for mandatory fields.
|
|
122
|
+
- **SHOULD** wrap related fields in `VJoyWrapper` or `VJoyFormGroup` for spacing.
|
|
123
|
+
|
|
124
|
+
### Implementation
|
|
125
|
+
|
|
126
|
+
- **MUST** use `VJoyInputPassword` for password entry — not `VJoyInput` with `type="password"`.
|
|
127
|
+
- **MUST** bind value with `v-model` (`modelValue` / `update:modelValue`).
|
|
128
|
+
- **MUST** use only documented props from MCP or `VJoyInput.types.ts` (minus omitted keys above).
|
|
129
|
+
- **MUST** style with Joy tokens — no custom `.joy-input` or `.joy-input-password` chrome.
|
|
130
|
+
- **MUST NOT** pass `clearable`, `readonly`, or `type` — they are not part of this API.
|
|
131
|
+
- **MUST NOT** invent props (`unit`, `variant`, `errorMessage`, …).
|
|
132
|
+
- **SHOULD** call exposed `focus()` programmatically only when restoring focus after an error — not on every mount.
|
|
133
|
+
|
|
134
|
+
### Visibility toggle
|
|
135
|
+
|
|
136
|
+
- **SHOULD** assume the toggle is pointer-driven; keyboard users edit the masked field normally.
|
|
137
|
+
- **MUST NOT** rely on reveal for security-sensitive flows where shoulder-surfing is a risk without user intent.
|
|
138
|
+
- **SHOULD NOT** add a leading `icon` unless design explicitly requires it — the trailing toggle already occupies the right side.
|
|
139
|
+
|
|
140
|
+
### Validation and requirements
|
|
141
|
+
|
|
142
|
+
- **MUST** set `invalid` when showing a validation error for this field.
|
|
143
|
+
- **MUST** show the error message in `VJoyFormError` (or equivalent) — not only red border.
|
|
144
|
+
- **SHOULD** use `VJoyPasswordRequirement` in `password-requirements` for live rule feedback on sign-up.
|
|
145
|
+
- **SHOULD** update each requirement’s `status` (`neutral`, `success`, `error`) as rules are evaluated.
|
|
146
|
+
|
|
147
|
+
### Do / don’t
|
|
148
|
+
|
|
149
|
+
| Do | Don’t |
|
|
150
|
+
| --- | --- |
|
|
151
|
+
| `VJoyInputPassword` + `autocomplete` | `VJoyInput` + `type="password"` |
|
|
152
|
+
| `VJoyPasswordRequirement` in the slot | Custom bullet list with random icons |
|
|
153
|
+
| `invalid` + `VJoyFormError` | Red border with no message |
|
|
154
|
+
| Distinct `name` for “Password” and “Confirm password” | Duplicate `name` on sibling fields |
|
|
155
|
+
| Joy form-field size tokens | Hardcoded `32` / `40` / `48`px heights |
|
|
156
|
+
|
|
157
|
+
---
|
|
158
|
+
|
|
159
|
+
## Content
|
|
160
|
+
|
|
161
|
+
Password fields expose label, optional placeholder, and optional requirement lines. Copy should reduce entry errors without revealing policy only after submit.
|
|
162
|
+
|
|
163
|
+
### Label formula
|
|
164
|
+
|
|
165
|
+
**Noun phrase** naming the credential — not the action:
|
|
166
|
+
|
|
167
|
+
- ✅ Password
|
|
168
|
+
- ✅ Current password
|
|
169
|
+
- ✅ New password
|
|
170
|
+
- ✅ Confirm password
|
|
171
|
+
|
|
172
|
+
Use sentence case. On change-password flows, distinguish **current** vs **new** vs **confirm** explicitly.
|
|
173
|
+
|
|
174
|
+
### Placeholder formula
|
|
175
|
+
|
|
176
|
+
**Short hint** — optional; never replace the label:
|
|
177
|
+
|
|
178
|
+
- ✅ `Enter your password` (under label “Password”)
|
|
179
|
+
- ❌ `Password` as placeholder when the label already says “Password”
|
|
180
|
+
|
|
181
|
+
Avoid real password examples in placeholders.
|
|
182
|
+
|
|
183
|
+
### Requirement lines
|
|
184
|
+
|
|
185
|
+
Each `VJoyPasswordRequirement` label states **one rule** in plain language:
|
|
186
|
+
|
|
187
|
+
- ✅ At least 8 characters
|
|
188
|
+
- ✅ Contains an uppercase letter
|
|
189
|
+
- ✅ Contains a special character
|
|
190
|
+
|
|
191
|
+
Keep rules parallel (same grammar). Prefer positive wording over “No spaces” unless the rule is exclusion-only.
|
|
192
|
+
|
|
193
|
+
### Writing rules
|
|
194
|
+
|
|
195
|
+
| Strength | Rule |
|
|
196
|
+
| --- | --- |
|
|
197
|
+
| **MUST** | Every field has a visible label — never placeholder-only |
|
|
198
|
+
| **MUST** | Error messages say what failed and how to fix it — ✅ `Password must be at least 8 characters` · ❌ `Invalid` |
|
|
199
|
+
| **MUST NOT** | Show the actual password in labels, helper text, or errors |
|
|
200
|
+
| **MUST NOT** | Use “Re-enter password” without a clear “Confirm password” or “Confirm new password” label when two fields are paired |
|
|
201
|
+
| **SHOULD** | Keep labels ≤ 3–5 words when possible |
|
|
202
|
+
| **SHOULD** | Match `autocomplete` to the step (`current-password`, `new-password`) |
|
|
203
|
+
| **SHOULD** | Localize requirement strings with the rest of the form |
|
|
204
|
+
|
|
205
|
+
### Patterns
|
|
206
|
+
|
|
207
|
+
**Sign-in** — One password field, `autocomplete="current-password"`, link to reset nearby — not inside the label.
|
|
208
|
+
|
|
209
|
+
**Registration** — New password + confirm field; live requirements in `password-requirements`; validate match on submit or blur.
|
|
210
|
+
|
|
211
|
+
**Change password** — Three fields (current, new, confirm) with distinct labels and names; requirements only under the new password field.
|
|
212
|
+
|
|
213
|
+
---
|
|
214
|
+
|
|
215
|
+
## Accessibility
|
|
216
|
+
|
|
217
|
+
Behaviors (what must happen), not slogans.
|
|
218
|
+
|
|
219
|
+
| Behavior | Expectation |
|
|
220
|
+
| --- | --- |
|
|
221
|
+
| Role | Native `<input>` with `type="password"` or `type="text"` when revealed |
|
|
222
|
+
| Name | From `label` / `VJoyLabel` / associated `<label for>` |
|
|
223
|
+
| Value | Controlled via `v-model` |
|
|
224
|
+
| Keyboard | Standard text editing; Tab moves focus into the field |
|
|
225
|
+
| Focus | Visible focus ring on the input — do not remove focus tokens |
|
|
226
|
+
| Invalid | `invalid` on the field; pair with `VJoyFormError` (`role="alert"`) for the message |
|
|
227
|
+
| Disabled | Native `disabled`; toggle click is ignored — provide text explanation when it matters |
|
|
228
|
+
| Autocomplete | Pass `autocomplete` via attrs for password managers |
|
|
229
|
+
| Requirements | `VJoyPasswordRequirement` error rows use `data-joy-form-error` when `status="error"` |
|
|
230
|
+
| Toggle | Icon click toggles visibility; ensure product copy does not depend on color alone for errors |
|
|
231
|
+
|
|
232
|
+
Target: **WCAG 2.2 AA** where the product requires it.
|
|
233
|
+
|
|
234
|
+
---
|
|
235
|
+
|
|
236
|
+
## Examples
|
|
237
|
+
|
|
238
|
+
```vue
|
|
239
|
+
<script setup lang="ts">
|
|
240
|
+
import { ref, computed } from 'vue'
|
|
241
|
+
import {
|
|
242
|
+
VJoyInputPassword,
|
|
243
|
+
VJoyPasswordRequirement,
|
|
244
|
+
VJoyFormError,
|
|
245
|
+
VJoyWrapper,
|
|
246
|
+
} from '@maltjoy/core-vue'
|
|
247
|
+
|
|
248
|
+
const password = ref('')
|
|
249
|
+
const confirm = ref('')
|
|
250
|
+
const showError = ref(false)
|
|
251
|
+
|
|
252
|
+
const hasMinLength = computed(() => password.value.length >= 8)
|
|
253
|
+
</script>
|
|
254
|
+
|
|
255
|
+
<template>
|
|
256
|
+
<!-- Sign-in -->
|
|
257
|
+
<VJoyInputPassword
|
|
258
|
+
v-model="password"
|
|
259
|
+
name="sign-in-password"
|
|
260
|
+
label="Password"
|
|
261
|
+
autocomplete="current-password"
|
|
262
|
+
required
|
|
263
|
+
required-mark
|
|
264
|
+
/>
|
|
265
|
+
|
|
266
|
+
<!-- Registration with live requirements -->
|
|
267
|
+
<VJoyWrapper direction="column" row-gap="4">
|
|
268
|
+
<VJoyInputPassword
|
|
269
|
+
v-model="password"
|
|
270
|
+
name="new-password"
|
|
271
|
+
label="New password"
|
|
272
|
+
autocomplete="new-password"
|
|
273
|
+
required
|
|
274
|
+
required-mark
|
|
275
|
+
:invalid="showError && !hasMinLength"
|
|
276
|
+
>
|
|
277
|
+
<template #password-requirements>
|
|
278
|
+
<VJoyPasswordRequirement
|
|
279
|
+
:status="hasMinLength ? 'success' : 'neutral'"
|
|
280
|
+
label="At least 8 characters"
|
|
281
|
+
/>
|
|
282
|
+
<VJoyPasswordRequirement status="neutral" label="Contains uppercase" />
|
|
283
|
+
<VJoyPasswordRequirement status="neutral" label="Contains special character" />
|
|
284
|
+
</template>
|
|
285
|
+
</VJoyInputPassword>
|
|
286
|
+
<VJoyFormError
|
|
287
|
+
v-if="showError && !hasMinLength"
|
|
288
|
+
message="Password must be at least 8 characters"
|
|
289
|
+
/>
|
|
290
|
+
</VJoyWrapper>
|
|
291
|
+
|
|
292
|
+
<!-- Confirm password -->
|
|
293
|
+
<VJoyInputPassword
|
|
294
|
+
v-model="confirm"
|
|
295
|
+
name="confirm-password"
|
|
296
|
+
label="Confirm password"
|
|
297
|
+
autocomplete="new-password"
|
|
298
|
+
required
|
|
299
|
+
required-mark
|
|
300
|
+
/>
|
|
301
|
+
</template>
|
|
302
|
+
```
|
|
303
|
+
|
|
304
|
+
In Nuxt (or apps with auto-import), omit the import if `VJoyInputPassword` is already global.
|
|
305
|
+
|
|
306
|
+
---
|
|
307
|
+
|
|
308
|
+
## Related
|
|
309
|
+
|
|
310
|
+
| Component | Use when |
|
|
311
|
+
| --- | --- |
|
|
312
|
+
| `VJoyInput` | Non-secret single-line text |
|
|
313
|
+
| `VJoyPasswordRequirement` | One rule row under the password field |
|
|
314
|
+
| `VJoyFormError` | Inline validation message below the field |
|
|
315
|
+
| `VJoyLabel` | Rich labels (legend, tooltip) separate from the field |
|
|
316
|
+
| `VJoyWrapper` / `VJoyFormGroup` | Form layout and spacing |
|
|
317
|
+
| `VJoyInputDigit` | Fixed-length codes (OTP) — not passwords |
|
|
318
|
+
|
|
319
|
+
---
|
|
320
|
+
|
|
321
|
+
## For agents
|
|
322
|
+
|
|
323
|
+
Optional for readers; **required** for vibe-coding quality. Maps to `agentDocumentBlocks` in [`JoyInputPassword.dsds.json`](./JoyInputPassword.dsds.json).
|
|
324
|
+
|
|
325
|
+
### Pick the right component
|
|
326
|
+
|
|
327
|
+
| If the intent is… | Emit… | Do not emit… |
|
|
328
|
+
| --- | --- | --- |
|
|
329
|
+
| Password / secret with show-hide | `VJoyInputPassword` | `VJoyInput` + `type="password"` |
|
|
330
|
+
| Email, name, search, free text | `VJoyInput` | `VJoyInputPassword` |
|
|
331
|
+
| OTP / PIN digits | `VJoyInputDigit` | Password input |
|
|
332
|
+
| Number with unit (€, %, days) | `VJoyInputNumber` | `VJoyInput` + `unit` |
|
|
333
|
+
| Strength rules under the field | `#password-requirements` + `VJoyPasswordRequirement` | Custom unstyled list |
|
|
334
|
+
|
|
335
|
+
### Hard rules
|
|
336
|
+
|
|
337
|
+
1. **MUST** call `joy_get_component_info("VJoyInputPassword")` or read `VJoyInput.types.ts` (omitted props) before generating props.
|
|
338
|
+
2. **MUST** bind `v-model` for editable values.
|
|
339
|
+
3. **MUST** set `name` (and `id` when needed for label association).
|
|
340
|
+
4. **MUST** pass native attrs (`placeholder`, `autocomplete`, `maxlength`, `aria-*`) on the component — they flow to `<input>`.
|
|
341
|
+
5. **MUST** set `invalid` when showing validation errors and render `VJoyFormError` with a message.
|
|
342
|
+
6. **MUST NOT** emit `type`, `clearable`, `readonly`, or `clearAriaLabel` on `VJoyInputPassword`.
|
|
343
|
+
7. **MUST NOT** emit `unit` — not supported on this wrapper (MCP may list it from `VJoyInput`; ignore for passwords).
|
|
344
|
+
8. **MUST NOT** override `.joy-input` / `.joy-input-password` height, border, radius, or padding.
|
|
345
|
+
9. **SHOULD** use `autocomplete="current-password"` or `new-password` as appropriate.
|
|
346
|
+
10. **SHOULD** use `password-requirements` + `VJoyPasswordRequirement` for sign-up strength UI.
|
|
347
|
+
|
|
348
|
+
### Checklist
|
|
349
|
+
|
|
350
|
+
- [ ] Correct component (`VJoyInputPassword`, not masked `VJoyInput`)
|
|
351
|
+
- [ ] Props / enums from MCP or types only
|
|
352
|
+
- [ ] `v-model` + `name` present
|
|
353
|
+
- [ ] Visible label (not placeholder-only)
|
|
354
|
+
- [ ] `autocomplete` set for password managers
|
|
355
|
+
- [ ] `invalid` + `VJoyFormError` when validation fails
|
|
356
|
+
- [ ] No `type` / `clearable` / `readonly` / invented props
|
|
357
|
+
- [ ] Confirm field uses a distinct `name` and clear label
|
|
358
|
+
- [ ] Requirements slot uses `VJoyPasswordRequirement` when showing rules
|
|
359
|
+
- [ ] Disabled state explained if user-visible
|
|
360
|
+
|
|
361
|
+
---
|
|
362
|
+
|
|
363
|
+
## DSDS mapping
|
|
364
|
+
|
|
365
|
+
This Markdown mirrors [`JoyInputPassword.dsds.json`](./JoyInputPassword.dsds.json) (DSDS **0.15.2**).
|
|
366
|
+
|
|
367
|
+
| Section here | DSDS block |
|
|
368
|
+
| --- | --- |
|
|
369
|
+
| When to use / not | `use-cases` |
|
|
370
|
+
| Anatomy | `anatomy` |
|
|
371
|
+
| Sizes | `variants` |
|
|
372
|
+
| States | `states` |
|
|
373
|
+
| Best practices / content rules | `guidelines` (+ `content`) |
|
|
374
|
+
| Accessibility | `accessibility` |
|
|
375
|
+
| Examples | `sections` |
|
|
376
|
+
| For agents | `agentDocumentBlocks` |
|
|
377
|
+
| Props detail | `api` in JSON + Joy MCP |
|
|
378
|
+
| Imports | `imports` in JSON |
|
|
379
|
+
| Token sizing | `design-specifications` in JSON (`--joy-form-field-height-*`, `--joy-form-field-radius-*`) |
|
|
@@ -146,15 +146,6 @@
|
|
|
146
146
|
"possibleValues": [
|
|
147
147
|
"Partial<Record<\"number\" | \"trim\" | \"lazy\", boolean>>"
|
|
148
148
|
]
|
|
149
|
-
},
|
|
150
|
-
{
|
|
151
|
-
"name": "unit",
|
|
152
|
-
"type": "string | undefined",
|
|
153
|
-
"required": false,
|
|
154
|
-
"description": "Adds a legend like symbol on the right of the component. Made for number based values",
|
|
155
|
-
"possibleValues": [
|
|
156
|
-
"string"
|
|
157
|
-
]
|
|
158
149
|
}
|
|
159
150
|
],
|
|
160
151
|
"events": [
|
|
@@ -246,11 +237,6 @@
|
|
|
246
237
|
"type": "((value: string) => any) | undefined",
|
|
247
238
|
"isMethod": true
|
|
248
239
|
},
|
|
249
|
-
{
|
|
250
|
-
"name": "unit",
|
|
251
|
-
"type": "string | undefined",
|
|
252
|
-
"isMethod": false
|
|
253
|
-
},
|
|
254
240
|
{
|
|
255
241
|
"name": "focus",
|
|
256
242
|
"type": "() => void",
|
|
@@ -0,0 +1,200 @@
|
|
|
1
|
+
---
|
|
2
|
+
component: VJoyLabel
|
|
3
|
+
status: draft
|
|
4
|
+
language: en
|
|
5
|
+
dsds: JoyLabel.dsds.json
|
|
6
|
+
dsdsVersion: "0.15.2"
|
|
7
|
+
---
|
|
8
|
+
|
|
9
|
+
# Label
|
|
10
|
+
|
|
11
|
+
Use **`VJoyLabel`** when a form field or option group needs a visible, accessible name — with optional required/optional markers, helper legend text, or a contextual tooltip.
|
|
12
|
+
|
|
13
|
+
Render it as a `<label>` (default) linked to a control via `for` / `id`, or as a `<legend>` inside fieldsets. Native attributes (`for`, `id`, `aria-*`, …) pass through to the root label/legend element via `$attrs`.
|
|
14
|
+
|
|
15
|
+
| | |
|
|
16
|
+
| --- | --- |
|
|
17
|
+
| **Code** | `VJoyLabel` from `@maltjoy/core-vue` |
|
|
18
|
+
| **Design** | [Figma — Joy Core Design System](https://www.figma.com/design/jfndp2QBJGS9yeuWbeGuvD/) |
|
|
19
|
+
| **Storybook** | [VJoyLabel docs](https://doc.malt.tech/joy-storybook/?path=/docs/components-forms-vjoylabel--docs) |
|
|
20
|
+
| **DSDS (machine)** | [`JoyLabel.dsds.json`](./JoyLabel.dsds.json) |
|
|
21
|
+
| **Live API** | `joy_get_component_info("VJoyLabel")` |
|
|
22
|
+
|
|
23
|
+
---
|
|
24
|
+
|
|
25
|
+
## When to use this component
|
|
26
|
+
|
|
27
|
+
Use a label when someone must understand what a form control is for before they interact with it — field titles, group legends, or standalone labels paired with inputs, selects, textareas, and similar controls.
|
|
28
|
+
|
|
29
|
+
Typical jobs: external label above a control (`VJoyLabel` + `for` / `id`), group legend in `VJoyRadioGroup`’s `radio-group-legend` slot, or richer label chrome (required asterisk, “optional” suffix, helper line, question-mark tooltip).
|
|
30
|
+
|
|
31
|
+
Many Joy form components (`VJoyInput`, `VJoySelect`, `VJoyTextarea`, …) render `VJoyLabel` internally when you set their `label` prop. Use a **standalone** `VJoyLabel` when you need more control (custom slots, external layout, or `VJoyFormGroup` composition).
|
|
32
|
+
|
|
33
|
+
### When not to use this component
|
|
34
|
+
|
|
35
|
+
| Need | Use instead |
|
|
36
|
+
| --- | --- |
|
|
37
|
+
| Page or section heading (not tied to one control) | `VJoyText`, semantic headings (`h1`–`h6`), or `VJoyTitleBrand` |
|
|
38
|
+
| Button or link text | `VJoyButton` / `VJoyLink` label or slot content |
|
|
39
|
+
| Inline copy inside a sentence | Plain text or `VJoyLink` |
|
|
40
|
+
| Tooltip on an icon-only control with no field label | `VJoyTooltip` on the trigger |
|
|
41
|
+
| Simple one-line label on a Joy input with no legend/tooltip | The control’s `label` prop (still `VJoyLabel` under the hood) |
|
|
42
|
+
| Custom-styled `<label>` / ad-hoc label CSS | Still use `VJoyLabel` + Joy tokens — don’t reinvent chrome |
|
|
43
|
+
|
|
44
|
+
---
|
|
45
|
+
|
|
46
|
+
## How it works
|
|
47
|
+
|
|
48
|
+
### Anatomy
|
|
49
|
+
|
|
50
|
+
| Part | Required? | What it is |
|
|
51
|
+
| --- | --- | --- |
|
|
52
|
+
| Group wrapper | Yes | `.joy-label__group`; adds `--standalone` spacing when not inside a Joy form field |
|
|
53
|
+
| Label / legend | Yes | `<label>` or `<legend>` with `data-joy-form-label` and size modifier (`joy-label--{size}`) |
|
|
54
|
+
| Label text | Yes* | Default slot or `text` prop (*one should provide the visible name) |
|
|
55
|
+
| Required mark | No | `*` span when `required` is true |
|
|
56
|
+
| Optional suffix | No | Italic `- {optionalLabel}` when `optionalLabel` is set |
|
|
57
|
+
| Tooltip trigger | No | `VJoyTooltip` + `question-circle` icon when `label-tooltip` slot is used |
|
|
58
|
+
| Legend line | No | `label-legend` slot — secondary helper text below the main label |
|
|
59
|
+
|
|
60
|
+
When nested inside a Joy form component that `provide`s `JoyFormElementContext`, the wrapper **omits** standalone outer spacing (the parent owns field layout).
|
|
61
|
+
|
|
62
|
+
### Default values
|
|
63
|
+
|
|
64
|
+
- `size` defaults to **`medium`** (`small`, `medium`, `large`)
|
|
65
|
+
- `tagName` defaults to **`label`** (`label` or `legend`)
|
|
66
|
+
- `required` defaults to **`false`**
|
|
67
|
+
- `optionalLabel` has **no default** — omit unless the field is explicitly optional
|
|
68
|
+
- `text` has **no default** — use `text` or the default slot
|
|
69
|
+
|
|
70
|
+
Props and slots: use Joy MCP or Storybook — this page focuses on **when** and **how**, not a full API dump.
|
|
71
|
+
|
|
72
|
+
### Label association
|
|
73
|
+
|
|
74
|
+
- **External label:** set `for` on `VJoyLabel` (via attribute) to match the control’s `id` (or `name` when `id` is omitted).
|
|
75
|
+
- **Built-in label:** pass `label` to `VJoyInput`, `VJoySelect`, etc. — the component wires `for` automatically.
|
|
76
|
+
- **Group legend:** set `tagName="legend"` (or rely on group patterns) inside `VJoyRadioGroup` / `VJoyCheckboxGroup` legend slots.
|
|
77
|
+
|
|
78
|
+
Match `size` to the paired control when possible (`labelSize` on inputs aligns with `VJoyLabel` sizes).
|
|
79
|
+
|
|
80
|
+
---
|
|
81
|
+
|
|
82
|
+
## Best practices
|
|
83
|
+
|
|
84
|
+
Rules use RFC 2119 strength (**MUST** / **SHOULD** / **MUST NOT** / **SHOULD NOT**).
|
|
85
|
+
|
|
86
|
+
### Structure
|
|
87
|
+
|
|
88
|
+
- **MUST** provide a visible label for every form control (via `VJoyLabel`, a control’s `label` prop, or an equivalent associated `<label>`).
|
|
89
|
+
- **MUST** keep `for` on the label aligned with the control’s `id` (or `name`) when using the external-label pattern.
|
|
90
|
+
- **SHOULD** use `required` on the label only when the field is actually required — pair with `required` on the control and validation messaging.
|
|
91
|
+
- **SHOULD** use `optionalLabel` (e.g. localized `"optional"`) instead of hiding that the field is optional.
|
|
92
|
+
- **SHOULD** put format hints or eligibility detail in `label-legend`, not in the primary label line.
|
|
93
|
+
- **SHOULD** reserve `label-tooltip` for short, factual context — not essential instructions.
|
|
94
|
+
|
|
95
|
+
### Implementation
|
|
96
|
+
|
|
97
|
+
- **MUST** use only documented props and enums from MCP or `JoyLabel.types.ts` (`size`: `small` | `medium` | `large`; `tagName`: `label` | `legend`).
|
|
98
|
+
- **MUST** pass native label attributes (`for`, `id`, `aria-*`) as attributes on `VJoyLabel` — they are not declared props but bind to the root element.
|
|
99
|
+
- **MUST** style with Joy tokens — no custom `.joy-label` font, color, or spacing overrides.
|
|
100
|
+
- **MUST NOT** invent props (`variant`, `color`, `invalid`, …).
|
|
101
|
+
- **MUST NOT** use `VJoyLabel` as a page heading or non-form title.
|
|
102
|
+
|
|
103
|
+
### Do / don’t
|
|
104
|
+
|
|
105
|
+
| Do | Don’t |
|
|
106
|
+
| --- | --- |
|
|
107
|
+
| `VJoyLabel for="email"` + `VJoyInput id="email"` | Mismatched or missing `for` / `id` |
|
|
108
|
+
| `label-legend` for “We’ll never share your email” | Long helper text in the main label |
|
|
109
|
+
| `tagName="legend"` in radio/checkbox group slots | Bare `<legend>` with custom CSS |
|
|
110
|
+
| `required` + asterisk when the field is required | Decorative `*` with no `required` semantics on the control |
|
|
111
|
+
| `label-tooltip` for brief format hints | Paragraphs of help only in a tooltip |
|
|
112
|
+
| Control `label` prop for simple fields | Duplicate standalone `VJoyLabel` + `label` prop on the same field |
|
|
113
|
+
|
|
114
|
+
---
|
|
115
|
+
|
|
116
|
+
## Accessibility
|
|
117
|
+
|
|
118
|
+
Behaviors (what must happen), not slogans.
|
|
119
|
+
|
|
120
|
+
| Behavior | Expectation |
|
|
121
|
+
| --- | --- |
|
|
122
|
+
| Role | Native `<label>` (default) or `<legend>` when `tagName="legend"` |
|
|
123
|
+
| Name | Primary text from default slot or `text` prop |
|
|
124
|
+
| Association | `for` on `<label>` must reference the control `id`; built-in labels on Joy inputs handle this when `label` + `id`/`name` are set |
|
|
125
|
+
| Required | Visual `*` when `required` is true — also set `required` on the associated control and surface errors with `VJoyFormError` |
|
|
126
|
+
| Tooltip | `label-tooltip` adds supplementary info via `VJoyTooltip`; the label text must still make sense without it |
|
|
127
|
+
| Marker | `data-joy-form-label` on the root label/legend for Joy form styling hooks |
|
|
128
|
+
| Grouping | Option groups use `<fieldset>` + `<legend>` via `VJoyRadioGroup` / `VJoyCheckboxGroup` — don’t rely on `VJoyLabel` alone for fieldset semantics |
|
|
129
|
+
|
|
130
|
+
Target: **WCAG 2.2 AA** where the product requires it.
|
|
131
|
+
|
|
132
|
+
---
|
|
133
|
+
|
|
134
|
+
## Examples
|
|
135
|
+
|
|
136
|
+
```vue
|
|
137
|
+
<script setup lang="ts">
|
|
138
|
+
import { ref } from 'vue'
|
|
139
|
+
import { VJoyLabel, VJoyInput, VJoyRadio, VJoyRadioGroup } from '@maltjoy/core-vue'
|
|
140
|
+
|
|
141
|
+
const email = ref('')
|
|
142
|
+
const referral = ref('')
|
|
143
|
+
const taxId = ref('')
|
|
144
|
+
const billing = ref('monthly')
|
|
145
|
+
</script>
|
|
146
|
+
|
|
147
|
+
<template>
|
|
148
|
+
<!-- External label + input -->
|
|
149
|
+
<VJoyLabel for="signup-email" required>
|
|
150
|
+
Email address
|
|
151
|
+
<template #label-legend>We'll send your receipt here</template>
|
|
152
|
+
</VJoyLabel>
|
|
153
|
+
<VJoyInput
|
|
154
|
+
id="signup-email"
|
|
155
|
+
v-model="email"
|
|
156
|
+
name="signup-email"
|
|
157
|
+
type="email"
|
|
158
|
+
autocomplete="email"
|
|
159
|
+
/>
|
|
160
|
+
|
|
161
|
+
<!-- Optional field -->
|
|
162
|
+
<VJoyLabel for="referral" optional-label="optional">
|
|
163
|
+
Referral code
|
|
164
|
+
</VJoyLabel>
|
|
165
|
+
<VJoyInput id="referral" v-model="referral" name="referral" />
|
|
166
|
+
|
|
167
|
+
<!-- Label with tooltip -->
|
|
168
|
+
<VJoyLabel for="tax-id" size="small">
|
|
169
|
+
Tax ID
|
|
170
|
+
<template #label-tooltip>
|
|
171
|
+
Your national tax identification number
|
|
172
|
+
</template>
|
|
173
|
+
</VJoyLabel>
|
|
174
|
+
<VJoyInput id="tax-id" v-model="taxId" name="tax-id" label-size="small" />
|
|
175
|
+
|
|
176
|
+
<!-- Group legend -->
|
|
177
|
+
<VJoyRadioGroup>
|
|
178
|
+
<template #radio-group-legend>
|
|
179
|
+
<VJoyLabel tag-name="legend">Billing frequency</VJoyLabel>
|
|
180
|
+
</template>
|
|
181
|
+
<VJoyRadio v-model="billing" name="billing" value="monthly">Monthly</VJoyRadio>
|
|
182
|
+
<VJoyRadio v-model="billing" name="billing" value="yearly">Yearly</VJoyRadio>
|
|
183
|
+
</VJoyRadioGroup>
|
|
184
|
+
</template>
|
|
185
|
+
```
|
|
186
|
+
|
|
187
|
+
In Nuxt (or apps with auto-import), omit the import if `VJoyLabel` is already global.
|
|
188
|
+
|
|
189
|
+
---
|
|
190
|
+
|
|
191
|
+
## Related
|
|
192
|
+
|
|
193
|
+
| Component | Use when |
|
|
194
|
+
| --- | --- |
|
|
195
|
+
| `VJoyInput` / `VJoySelect` / `VJoyTextarea` | Control with optional built-in `label` prop |
|
|
196
|
+
| `VJoyFormGroup` | Vertical stack of label + control + `VJoyFormError` |
|
|
197
|
+
| `VJoyFormError` | Validation message below the labeled control |
|
|
198
|
+
| `VJoyRadioGroup` / `VJoyCheckboxGroup` | Fieldset + legend slot for option groups |
|
|
199
|
+
| `VJoyTooltip` | Standalone contextual help (used inside `label-tooltip`) |
|
|
200
|
+
| `VJoyText` | Non-form headings or body copy |
|