@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,419 @@
|
|
|
1
|
+
---
|
|
2
|
+
component: VJoyFilterBar
|
|
3
|
+
status: draft
|
|
4
|
+
language: en
|
|
5
|
+
dsds: JoyFilterBar.dsds.json
|
|
6
|
+
dsdsVersion: "0.15.2"
|
|
7
|
+
---
|
|
8
|
+
|
|
9
|
+
# Filter bar
|
|
10
|
+
|
|
11
|
+
Use **`VJoyFilterBar`** when users need to refine a list or dataset with one or more filters presented as a connected button group — for example status filters, category chips, or dropdown-backed multi-select filters above a table.
|
|
12
|
+
|
|
13
|
+
It is a **layout container** only: it groups `VJoyFilterBarButton` children (or `VJoyDropdown` triggers that embed them), applies seamless border-radius and overlap styling, and exposes a single `role="group"` landmark. Filter state, active styling, and selection counts are **managed by the parent**.
|
|
14
|
+
|
|
15
|
+
| | |
|
|
16
|
+
| --- | --- |
|
|
17
|
+
| **Code** | `VJoyFilterBar` from `@maltjoy/core-vue` |
|
|
18
|
+
| **Design** | [Figma — Joy components](https://www.figma.com/design/jfndp2QBJGS9yeuWbeGuvD/) |
|
|
19
|
+
| **Storybook** | [VJoyFilterBar docs](https://doc.malt.tech/joy-storybook/?path=/docs/components-forms-vjoyfilterbar--docs) |
|
|
20
|
+
| **DSDS (machine)** | [`JoyFilterBar.dsds.json`](./JoyFilterBar.dsds.json) |
|
|
21
|
+
| **Live API** | `joy_get_component_info("VJoyFilterBar")` |
|
|
22
|
+
|
|
23
|
+
---
|
|
24
|
+
|
|
25
|
+
## When to use this component
|
|
26
|
+
|
|
27
|
+
Use a filter bar when the user should pick one or more criteria to narrow visible content on the same screen — for example filtering projects by status, narrowing a directory by location, or combining several facet filters above search results.
|
|
28
|
+
|
|
29
|
+
`VJoyFilterBar` works best when filters are **peer controls** shown together as a segmented control. Pair it with `VJoyFilterBarButton` for simple toggle filters, or wrap buttons inside `VJoyDropdown` when a filter opens a panel of checkboxes, search, or other custom content.
|
|
30
|
+
|
|
31
|
+
For a full toolbar (filters + reset + search), compose `VJoyFilterBar` inside `VJoyWrapper` alongside `VJoyButton` and `VJoyInput` — see Storybook **Advanced usage**.
|
|
32
|
+
|
|
33
|
+
### When not to use this component
|
|
34
|
+
|
|
35
|
+
| Need | Use instead |
|
|
36
|
+
| --- | --- |
|
|
37
|
+
| A single native form select in a field | `VJoySelect` |
|
|
38
|
+
| One overflow / kebab menu of actions | `VJoyDropdown` alone (no grouped bar chrome) |
|
|
39
|
+
| Mutually exclusive options always visible (2–7 choices) | `VJoyRadioGroup` or `VJoySelectableItemGroup` |
|
|
40
|
+
| Primary page navigation between sections | `VJoyTabs` |
|
|
41
|
+
| Free-text search only (no facet buttons) | `VJoyInput` with `icon="search"` |
|
|
42
|
+
| Custom button group CSS for the same job | Still use `VJoyFilterBar` + `VJoyFilterBarButton` + Joy tokens |
|
|
43
|
+
|
|
44
|
+
---
|
|
45
|
+
|
|
46
|
+
## How it works
|
|
47
|
+
|
|
48
|
+
`VJoyFilterBar` renders a flex row wrapper around its default slot. It does **not** own selection state, emit filter events, or render buttons by itself — you compose children explicitly.
|
|
49
|
+
|
|
50
|
+
### Anatomy
|
|
51
|
+
|
|
52
|
+
| Part | Required? | What it is |
|
|
53
|
+
| --- | --- | --- |
|
|
54
|
+
| Group container | Yes | Root `div.joy-filter-bar` with `role="group"` |
|
|
55
|
+
| Group label | Yes (implicit) | `aria-label` from `ariaLabel` prop, or default `"Filter bar"` |
|
|
56
|
+
| Wrapper | Yes | `.joy-filter-bar__wrapper` — horizontal flex row for slot children |
|
|
57
|
+
| Filter controls (`default` slot) | Yes | Typically `VJoyFilterBarButton` and/or `VJoyDropdown` wrapping those buttons |
|
|
58
|
+
| Connected styling | Yes (automatic) | First/last child corner radius (`--joy-core-radius-3`); `-1px` overlap between siblings |
|
|
59
|
+
|
|
60
|
+
### Default values
|
|
61
|
+
|
|
62
|
+
- `ariaLabel` — when omitted, the group uses **`"Filter bar"`** as `aria-label` (see component tests).
|
|
63
|
+
|
|
64
|
+
Props, events, and slots: use Joy MCP or Storybook — this page focuses on **when** and **how**, not a full API dump.
|
|
65
|
+
|
|
66
|
+
### Composition
|
|
67
|
+
|
|
68
|
+
**Simple toggle filters** — one `VJoyFilterBarButton` per filter; parent listens to `@filter` and toggles `active`:
|
|
69
|
+
|
|
70
|
+
```vue
|
|
71
|
+
<VJoyFilterBar>
|
|
72
|
+
<VJoyFilterBarButton
|
|
73
|
+
v-for="filter in filters"
|
|
74
|
+
:key="filter.value"
|
|
75
|
+
:value="filter.value"
|
|
76
|
+
:label="filter.label"
|
|
77
|
+
:active="activeFilter === filter.value"
|
|
78
|
+
@filter="activeFilter = $event"
|
|
79
|
+
/>
|
|
80
|
+
</VJoyFilterBar>
|
|
81
|
+
```
|
|
82
|
+
|
|
83
|
+
**Multi-select facet** — each filter is a `VJoyDropdown` with a `VJoyFilterBarButton` trigger, checkbox panel, optional `VJoyTag` count, and `reset` handler. Parent owns `v-model` on `VJoyCheckboxGroup` and sets `:active` when the selection array is non-empty.
|
|
84
|
+
|
|
85
|
+
**Toolbar** — wrap `VJoyFilterBar` in `VJoyWrapper` with `justify-content`, `align-items`, and `gap` as needed; add `VJoyButton` (reset all) and `VJoyInput` (search) as siblings.
|
|
86
|
+
|
|
87
|
+
### Child contract (`VJoyFilterBarButton`)
|
|
88
|
+
|
|
89
|
+
Although defined in a sibling component, filter bars almost always use it:
|
|
90
|
+
|
|
91
|
+
| Prop / API | Notes |
|
|
92
|
+
| --- | --- |
|
|
93
|
+
| `value` | **Required** — stable id emitted on `@filter` |
|
|
94
|
+
| `label` | Visible filter name |
|
|
95
|
+
| `active` | Highlights applied filter (`joy-filter-bar-button--active`) |
|
|
96
|
+
| `@filter` | Emits `[value: string]` on click |
|
|
97
|
+
| `default` slot | Extra content (e.g. `VJoyTag` with selection count) |
|
|
98
|
+
| Inside `VJoyDropdown` | Chevron icon appears automatically via dropdown context |
|
|
99
|
+
|
|
100
|
+
---
|
|
101
|
+
|
|
102
|
+
## Variants
|
|
103
|
+
|
|
104
|
+
`VJoyFilterBar` has **no variant or emphasis prop**. Visual treatment comes from its children (`VJoyFilterBarButton`, `VJoyDropdown`, `VJoyTag`) and the built-in connected-group chrome.
|
|
105
|
+
|
|
106
|
+
Do not simulate filter-bar variants with custom CSS on `.joy-filter-bar` — compose the documented children instead.
|
|
107
|
+
|
|
108
|
+
---
|
|
109
|
+
|
|
110
|
+
## Sizes
|
|
111
|
+
|
|
112
|
+
`VJoyFilterBar` has **no size prop**. `VJoyFilterBarButton` uses a fixed `min-height` of **40px** and Joy spacing / typography tokens internally — **don’t hardcode filter button heights** in product CSS.
|
|
113
|
+
|
|
114
|
+
Match density by choosing appropriate child components (`VJoyTag` `size="xsmall"` for counts, `VJoyDropdown` `size="small"` for compact panels).
|
|
115
|
+
|
|
116
|
+
---
|
|
117
|
+
|
|
118
|
+
## States
|
|
119
|
+
|
|
120
|
+
`VJoyFilterBar` itself is not focusable. States apply to its children; the bar only provides grouped layout.
|
|
121
|
+
|
|
122
|
+
| State | What the user sees / can do |
|
|
123
|
+
| --- | --- |
|
|
124
|
+
| Default | Neutral filter buttons; no selection applied (`active` false on buttons) |
|
|
125
|
+
| Active filter | `VJoyFilterBarButton` with `active` true — secondary border/background (parent-driven) |
|
|
126
|
+
| Hover / focus | Per-button hover and focus styles on `VJoyFilterBarButton` |
|
|
127
|
+
| Dropdown open | `VJoyDropdown` panel visible; trigger button may show chevron (injected by dropdown context) |
|
|
128
|
+
| Selection count | Optional `VJoyTag` in the button slot (e.g. `label="3"`) — parent updates count |
|
|
129
|
+
| Reset | `VJoyDropdown` `reset` + `@dropdown:reset` per filter, or a separate `VJoyButton` for “reset all” |
|
|
130
|
+
|
|
131
|
+
The component does **not** disable individual filters — hide unavailable filters or handle disabled state in the parent / dropdown content.
|
|
132
|
+
|
|
133
|
+
---
|
|
134
|
+
|
|
135
|
+
## Best practices
|
|
136
|
+
|
|
137
|
+
Rules use RFC 2119 strength (**MUST** / **SHOULD** / **MUST NOT** / **SHOULD NOT**).
|
|
138
|
+
|
|
139
|
+
### Structure / filtering
|
|
140
|
+
|
|
141
|
+
- **MUST** manage filter state in the parent — `VJoyFilterBar` does not provide `v-model`.
|
|
142
|
+
- **MUST** give every `VJoyFilterBarButton` a stable, unique `value` string.
|
|
143
|
+
- **SHOULD** set `:active` on a button when that filter has an applied selection (non-empty array, non-default value, etc.).
|
|
144
|
+
- **SHOULD** keep the number of visible filters modest (roughly **2–6**); move overflow into a “More filters” dropdown if needed.
|
|
145
|
+
- **SHOULD** place the filter bar **above** the content it affects (table, list, map) so the relationship is obvious.
|
|
146
|
+
- **MUST NOT** use `VJoyFilterBar` for non-filter actions (export, create) — use `VJoyButton` or `VJoyWrapper` toolbars instead.
|
|
147
|
+
|
|
148
|
+
### Implementation
|
|
149
|
+
|
|
150
|
+
- **MUST** put filter controls in the **default slot** — typically `VJoyFilterBarButton` or `VJoyDropdown`.
|
|
151
|
+
- **MUST** use only documented props (`ariaLabel` on the bar; `value`, `label`, `active` on buttons).
|
|
152
|
+
- **MUST** style with Joy tokens — no custom `.joy-filter-bar` or `.joy-filter-bar-button` chrome overrides.
|
|
153
|
+
- **MUST NOT** invent props on `VJoyFilterBar` (no `variant`, `size`, `disabled`, or `v-model`).
|
|
154
|
+
- **SHOULD** set a descriptive `aria-label` when `"Filter bar"` is too generic (e.g. `aria-label="Project filters"`).
|
|
155
|
+
- **SHOULD** use `VJoyDropdown` `reset` + `@dropdown:reset` for per-filter clear; wire it to parent state.
|
|
156
|
+
- **SHOULD** use `close-on-select="false"` on dropdowns with multi-select checkboxes; add a footer Apply button when needed (see `VJoyDropdown` docs).
|
|
157
|
+
|
|
158
|
+
### Do / don’t
|
|
159
|
+
|
|
160
|
+
| Do | Don’t |
|
|
161
|
+
| --- | --- |
|
|
162
|
+
| `VJoyFilterBar` + `VJoyFilterBarButton` for grouped filters | Hand-rolled flex divs with manual border overlap |
|
|
163
|
+
| Parent-owned `active` and selection counts | Expect the bar to track state automatically |
|
|
164
|
+
| `VJoyTag` for numeric selection badges | Long text inside the button for counts |
|
|
165
|
+
| `VJoyWrapper` for filter + search + reset rows | Cram unrelated actions inside the bar slot |
|
|
166
|
+
| Descriptive `aria-label` when context helps | Rely on default `"Filter bar"` on every page |
|
|
167
|
+
|
|
168
|
+
---
|
|
169
|
+
|
|
170
|
+
## Content
|
|
171
|
+
|
|
172
|
+
Filter button labels name **what is being filtered**, not the current selection value (unless the product pattern explicitly shows state in the label).
|
|
173
|
+
|
|
174
|
+
### Label formula
|
|
175
|
+
|
|
176
|
+
**Short noun or facet name** — parallel across the bar:
|
|
177
|
+
|
|
178
|
+
- ✅ Status · Location · Skills
|
|
179
|
+
- ✅ Continents · Countries
|
|
180
|
+
- ✅ Availability
|
|
181
|
+
|
|
182
|
+
For dropdown triggers, the **trigger label** names the facet; selected values appear in the panel, in a `VJoyTag` count, or in results — not as a long sentence on the button.
|
|
183
|
+
|
|
184
|
+
### Writing rules
|
|
185
|
+
|
|
186
|
+
| Strength | Rule |
|
|
187
|
+
| --- | --- |
|
|
188
|
+
| **MUST** | Keep labels scannable — aim for **≤ 20 characters**; never truncate with ellipsis |
|
|
189
|
+
| **MUST** | Use consistent grammar across filters in the same bar |
|
|
190
|
+
| **MUST** | Make each label distinct — no duplicate facet names |
|
|
191
|
+
| **MUST NOT** | Use vague labels — ❌ `Filter`, `Options`, `More` without context |
|
|
192
|
+
| **MUST NOT** | Put full selected value lists in the button — use tags/counts or panel content |
|
|
193
|
+
| **SHOULD** | Prefer **1–2 words** (noun phrases) |
|
|
194
|
+
| **SHOULD** | Use `VJoyTag` `label` for counts only (`"2"`, `"12"`) — facet name stays in `label` |
|
|
195
|
+
| **SHOULD** | Reset actions name scope — `Reset filter`, `Reset all filters` |
|
|
196
|
+
| **SHOULD** (FR) | Keep articles when grammar requires them — _Continents_, _Pays_ |
|
|
197
|
+
|
|
198
|
+
### Patterns
|
|
199
|
+
|
|
200
|
+
**Single-select toggle bar** — Labels are facet values (`All`, `Open`, `Closed`). One `active` button at a time; parent updates on `@filter`.
|
|
201
|
+
|
|
202
|
+
**Multi-select dropdown facet** — Button label = facet (`Skills`); `VJoyTag` shows count when `active`; panel holds `VJoyCheckboxGroup`. Footer `Apply filters` when changes are deferred.
|
|
203
|
+
|
|
204
|
+
**Filter + search toolbar** — Filter labels stay short; search placeholder is specific (`Search projects…`) in adjacent `VJoyInput`, not inside `VJoyFilterBar`.
|
|
205
|
+
|
|
206
|
+
---
|
|
207
|
+
|
|
208
|
+
## Accessibility
|
|
209
|
+
|
|
210
|
+
Behaviors (what must happen), not slogans.
|
|
211
|
+
|
|
212
|
+
| Behavior | Expectation |
|
|
213
|
+
| --- | --- |
|
|
214
|
+
| Group role | Root uses `role="group"` — screen readers announce it as a group |
|
|
215
|
+
| Group name | `aria-label` from `ariaLabel`, or default `"Filter bar"` — override when the default is ambiguous |
|
|
216
|
+
| Focus | Focus moves to individual `VJoyFilterBarButton` / dropdown triggers — not the bar wrapper |
|
|
217
|
+
| Keyboard | Buttons activate with **Enter** / **Space**; dropdowns follow `VJoyDropdown` keyboard behavior |
|
|
218
|
+
| Active state | Don’t rely on color alone — `active` changes border and background; pair with tags/counts when useful |
|
|
219
|
+
| Dropdown triggers | Icon-only or ambiguous triggers still need an accessible name (`label` on `VJoyFilterBarButton` or `aria-label` on dropdown trigger per `VJoyDropdown` docs) |
|
|
220
|
+
| Live results | When filters update content, ensure the results region is announced if the product uses live regions |
|
|
221
|
+
|
|
222
|
+
Target: **WCAG 2.2 AA** where the product requires it.
|
|
223
|
+
|
|
224
|
+
---
|
|
225
|
+
|
|
226
|
+
## Examples
|
|
227
|
+
|
|
228
|
+
```vue
|
|
229
|
+
<script setup lang="ts">
|
|
230
|
+
import { reactive, ref } from 'vue'
|
|
231
|
+
import {
|
|
232
|
+
VJoyFilterBar,
|
|
233
|
+
VJoyFilterBarButton,
|
|
234
|
+
VJoyDropdown,
|
|
235
|
+
VJoyCheckboxGroup,
|
|
236
|
+
VJoyTag,
|
|
237
|
+
VJoyWrapper,
|
|
238
|
+
VJoyButton,
|
|
239
|
+
VJoyInput,
|
|
240
|
+
} from '@maltjoy/core-vue'
|
|
241
|
+
|
|
242
|
+
const activeStatus = ref('all')
|
|
243
|
+
|
|
244
|
+
const continents = [
|
|
245
|
+
{ value: 'europe', label: 'Europe', id: 'europe' },
|
|
246
|
+
{ value: 'asia', label: 'Asia', id: 'asia' },
|
|
247
|
+
]
|
|
248
|
+
|
|
249
|
+
const filters = reactive({
|
|
250
|
+
continents: [] as string[],
|
|
251
|
+
})
|
|
252
|
+
|
|
253
|
+
function resetContinents() {
|
|
254
|
+
filters.continents = []
|
|
255
|
+
}
|
|
256
|
+
</script>
|
|
257
|
+
|
|
258
|
+
<template>
|
|
259
|
+
<!-- Simple toggle filters -->
|
|
260
|
+
<VJoyFilterBar aria-label="Project status filters">
|
|
261
|
+
<VJoyFilterBarButton
|
|
262
|
+
value="all"
|
|
263
|
+
label="All"
|
|
264
|
+
:active="activeStatus === 'all'"
|
|
265
|
+
@filter="activeStatus = $event"
|
|
266
|
+
/>
|
|
267
|
+
<VJoyFilterBarButton
|
|
268
|
+
value="open"
|
|
269
|
+
label="Open"
|
|
270
|
+
:active="activeStatus === 'open'"
|
|
271
|
+
@filter="activeStatus = $event"
|
|
272
|
+
/>
|
|
273
|
+
<VJoyFilterBarButton
|
|
274
|
+
value="closed"
|
|
275
|
+
label="Closed"
|
|
276
|
+
:active="activeStatus === 'closed'"
|
|
277
|
+
@filter="activeStatus = $event"
|
|
278
|
+
/>
|
|
279
|
+
</VJoyFilterBar>
|
|
280
|
+
|
|
281
|
+
<!-- Multi-select facet with dropdown -->
|
|
282
|
+
<VJoyFilterBar>
|
|
283
|
+
<VJoyDropdown
|
|
284
|
+
reset
|
|
285
|
+
reset-label="Reset filter"
|
|
286
|
+
:close-on-select="false"
|
|
287
|
+
@dropdown:reset="resetContinents"
|
|
288
|
+
>
|
|
289
|
+
<template #dropdown-button>
|
|
290
|
+
<VJoyFilterBarButton
|
|
291
|
+
value="continents"
|
|
292
|
+
label="Continents"
|
|
293
|
+
:active="filters.continents.length > 0"
|
|
294
|
+
>
|
|
295
|
+
<VJoyTag
|
|
296
|
+
v-if="filters.continents.length"
|
|
297
|
+
size="xsmall"
|
|
298
|
+
value="continent-count"
|
|
299
|
+
:label="String(filters.continents.length)"
|
|
300
|
+
/>
|
|
301
|
+
</VJoyFilterBarButton>
|
|
302
|
+
</template>
|
|
303
|
+
<template #dropdown-items>
|
|
304
|
+
<VJoyCheckboxGroup
|
|
305
|
+
v-model:value="filters.continents"
|
|
306
|
+
:options="continents"
|
|
307
|
+
/>
|
|
308
|
+
</template>
|
|
309
|
+
</VJoyDropdown>
|
|
310
|
+
</VJoyFilterBar>
|
|
311
|
+
|
|
312
|
+
<!-- Toolbar: filters + reset + search -->
|
|
313
|
+
<VJoyWrapper justify-content="space-between" align-items="center" gap="medium">
|
|
314
|
+
<VJoyFilterBar aria-label="Location filters">
|
|
315
|
+
<!-- …dropdown filters as above… -->
|
|
316
|
+
</VJoyFilterBar>
|
|
317
|
+
<VJoyButton
|
|
318
|
+
variant="ghost"
|
|
319
|
+
size="xsmall"
|
|
320
|
+
label="Reset all filters"
|
|
321
|
+
@click="resetContinents"
|
|
322
|
+
/>
|
|
323
|
+
<VJoyInput
|
|
324
|
+
icon="search"
|
|
325
|
+
size="small"
|
|
326
|
+
name="search"
|
|
327
|
+
placeholder="Search any location…"
|
|
328
|
+
/>
|
|
329
|
+
</VJoyWrapper>
|
|
330
|
+
</template>
|
|
331
|
+
```
|
|
332
|
+
|
|
333
|
+
In Nuxt (or apps with auto-import), omit the import if components are already global.
|
|
334
|
+
|
|
335
|
+
---
|
|
336
|
+
|
|
337
|
+
## Related
|
|
338
|
+
|
|
339
|
+
| Component | Use when |
|
|
340
|
+
| --- | --- |
|
|
341
|
+
| `VJoyFilterBarButton` | Required child for each filter control in the bar |
|
|
342
|
+
| `VJoyDropdown` | Filter opens a panel (checkboxes, search, custom content) |
|
|
343
|
+
| `VJoyCheckboxGroup` | Multi-select options inside a dropdown filter |
|
|
344
|
+
| `VJoyTag` | Selection count badge inside a filter button |
|
|
345
|
+
| `VJoyWrapper` | Lay out filter bar with search, reset, or other toolbar actions |
|
|
346
|
+
| `VJoyButton` | Reset-all or secondary toolbar actions beside the bar |
|
|
347
|
+
| `VJoyInput` | Search field adjacent to filters (`icon="search"`) |
|
|
348
|
+
| `VJoySelect` | Single bounded choice in a form field — not a segmented filter bar |
|
|
349
|
+
|
|
350
|
+
---
|
|
351
|
+
|
|
352
|
+
## For agents
|
|
353
|
+
|
|
354
|
+
Optional for readers; **required** for vibe-coding quality. Maps to `agentDocumentBlocks` in [`JoyFilterBar.dsds.json`](./JoyFilterBar.dsds.json).
|
|
355
|
+
|
|
356
|
+
### Pick the right component
|
|
357
|
+
|
|
358
|
+
| If the intent is… | Emit… | Do not emit… |
|
|
359
|
+
| --- | --- | --- |
|
|
360
|
+
| Grouped facet filters above a list/table | `VJoyFilterBar` + `VJoyFilterBarButton` | Raw flex `div` + styled buttons |
|
|
361
|
+
| Filter with checkbox panel | `VJoyFilterBar` > `VJoyDropdown` > `VJoyFilterBarButton` + `VJoyCheckboxGroup` | `VJoySelect` for multi-select facets |
|
|
362
|
+
| Single form enum in a field | `VJoySelect` or `VJoyRadioGroup` | `VJoyFilterBar` inside a form group |
|
|
363
|
+
| Toolbar with filters + search | `VJoyWrapper` + `VJoyFilterBar` + `VJoyInput` | Everything crammed in one slot |
|
|
364
|
+
| Overflow actions menu | `VJoyDropdown` alone | `VJoyFilterBar` with one kebab button |
|
|
365
|
+
|
|
366
|
+
### Hard rules
|
|
367
|
+
|
|
368
|
+
1. **MUST** call `joy_get_component_info("VJoyFilterBar")` and `joy_get_component_info("VJoyFilterBarButton")` (or read Storybook) before generating markup.
|
|
369
|
+
2. **MUST** treat `VJoyFilterBar` as a **stateless container** — parent owns selection, `active`, and counts.
|
|
370
|
+
3. **MUST** emit `VJoyFilterBarButton` with required `value` and handle `@filter` in the parent.
|
|
371
|
+
4. **MUST** set `:active` on buttons when a filter is applied (parent logic).
|
|
372
|
+
5. **MUST NOT** invent props on `VJoyFilterBar` (`variant`, `size`, `v-model`, `options`, …).
|
|
373
|
+
6. **MUST NOT** override `.joy-filter-bar`, `.joy-filter-bar__wrapper`, or `.joy-filter-bar-button` styles.
|
|
374
|
+
7. **SHOULD** set `aria-label` when `"Filter bar"` is not specific enough.
|
|
375
|
+
8. **SHOULD** use `VJoyTag` `size="xsmall"` for selection counts inside buttons.
|
|
376
|
+
9. **SHOULD** use `VJoyDropdown` `reset` + `@dropdown:reset` for per-filter clear handlers.
|
|
377
|
+
|
|
378
|
+
### Valid props (from source)
|
|
379
|
+
|
|
380
|
+
| Component | Prop | Type / notes |
|
|
381
|
+
| --- | --- | --- |
|
|
382
|
+
| `VJoyFilterBar` | `ariaLabel` | `string` — optional; defaults to `"Filter bar"` |
|
|
383
|
+
| `VJoyFilterBar` | `default` slot | Filter children |
|
|
384
|
+
| `VJoyFilterBarButton` | `value` | `string` — **required** |
|
|
385
|
+
| `VJoyFilterBarButton` | `label` | `string` |
|
|
386
|
+
| `VJoyFilterBarButton` | `active` | `boolean` — default `false` |
|
|
387
|
+
| `VJoyFilterBarButton` | `@filter` | emits `value: string` |
|
|
388
|
+
|
|
389
|
+
### Checklist
|
|
390
|
+
|
|
391
|
+
- [ ] `VJoyFilterBar` wraps filter children — not standalone buttons without the container
|
|
392
|
+
- [ ] Every `VJoyFilterBarButton` has a unique `value`
|
|
393
|
+
- [ ] Parent handles `@filter`, `active`, and checkbox `v-model` — bar has no `v-model`
|
|
394
|
+
- [ ] Props from MCP / Storybook / source only — no invented API
|
|
395
|
+
- [ ] No custom filter-bar chrome CSS
|
|
396
|
+
- [ ] `aria-label` set when default label is too generic
|
|
397
|
+
- [ ] Multi-select dropdowns use `close-on-select="false"` when appropriate
|
|
398
|
+
- [ ] Counts use `VJoyTag`, not long button labels
|
|
399
|
+
- [ ] Search / reset live in `VJoyWrapper` siblings when building a full toolbar
|
|
400
|
+
|
|
401
|
+
---
|
|
402
|
+
|
|
403
|
+
## DSDS mapping
|
|
404
|
+
|
|
405
|
+
This Markdown mirrors [`JoyFilterBar.dsds.json`](./JoyFilterBar.dsds.json) (DSDS **0.15.2**).
|
|
406
|
+
|
|
407
|
+
| Section here | DSDS block |
|
|
408
|
+
| --- | --- |
|
|
409
|
+
| When to use / not | `use-cases` |
|
|
410
|
+
| Anatomy | `anatomy` |
|
|
411
|
+
| Variants / sizes | `variants` |
|
|
412
|
+
| States | `states` |
|
|
413
|
+
| Best practices / content rules | `guidelines` (+ `content`) |
|
|
414
|
+
| Accessibility | `accessibility` |
|
|
415
|
+
| Examples | `sections` |
|
|
416
|
+
| For agents | `agentDocumentBlocks` |
|
|
417
|
+
| Props detail | `api` in JSON + Joy MCP |
|
|
418
|
+
| Imports | `imports` in JSON |
|
|
419
|
+
| Connected-group radius / layout | `design-specifications` in JSON |
|