@staffbase/design-mcp 19.0.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/README.md +75 -0
- package/dist/data/components.json +1118 -0
- package/dist/data/docs.json +226 -0
- package/dist/data/icons.json +2344 -0
- package/dist/data/meta.json +4 -0
- package/dist/data/package_instructions.md +187 -0
- package/dist/data/tokens.json +4449 -0
- package/dist/server.d.ts +6 -0
- package/dist/server.js +451 -0
- package/dist/server.js.map +1 -0
- package/package.json +48 -0
|
@@ -0,0 +1,187 @@
|
|
|
1
|
+
# @staffbase/design — AI Agent Reference
|
|
2
|
+
|
|
3
|
+
> This file helps AI coding agents (Claude, Cursor, Copilot, etc.) use the Staffbase Design System correctly.
|
|
4
|
+
> Last verified: 2026-05-19
|
|
5
|
+
|
|
6
|
+
## Package overview
|
|
7
|
+
|
|
8
|
+
`@staffbase/design` is a React component library providing UI components, icons, and design tokens for Staffbase products. ESM (with CJS fallback). Explicit CSS imports required.
|
|
9
|
+
|
|
10
|
+
## When the MCP is available — use it for discovery
|
|
11
|
+
|
|
12
|
+
The MCP returns ground truth, kept in lockstep with this package. Don't re-derive from training data; ask the tools:
|
|
13
|
+
|
|
14
|
+
| Need | Call |
|
|
15
|
+
| ---------------------------------------------------------------------------- | -------------------------- |
|
|
16
|
+
| What components exist, which are deprecated, what to use instead | `list_components` |
|
|
17
|
+
| One component's full API — props interface, anatomy, examples, required a11y | `get_component` |
|
|
18
|
+
| One curated example, by default or by named variant | `get_component_example` |
|
|
19
|
+
| Tokens by layer/category; resolve a semantic token to its primitive | `list_tokens`, `get_token` |
|
|
20
|
+
| Find an icon by category, name, or synonym tag | `list_icons`, `get_icon` |
|
|
21
|
+
| Any published doc page (getting-started, foundation, components) | `get_doc_page` |
|
|
22
|
+
| Fuzzy search across everything | `search_design_system` |
|
|
23
|
+
|
|
24
|
+
The rest of this file covers the cross-cutting conventions and anti-patterns the tools don't surface. **The MCP is the source of truth for any list (components, tokens, icons, props, examples).**
|
|
25
|
+
|
|
26
|
+
## Setup — required CSS imports
|
|
27
|
+
|
|
28
|
+
In your application entry point, in this order:
|
|
29
|
+
|
|
30
|
+
```ts
|
|
31
|
+
import '@staffbase/design/tokens/semantic.css'; // required — CSS custom properties
|
|
32
|
+
import '@staffbase/design/components.css'; // required — component styles
|
|
33
|
+
import '@staffbase/design/theme.css'; // required if using Tailwind v4
|
|
34
|
+
import '@staffbase/design/fonts/inter.css'; // optional
|
|
35
|
+
import '@staffbase/design/fonts/epilogue.css'; // optional
|
|
36
|
+
```
|
|
37
|
+
|
|
38
|
+
Additional token layers if you need them: `@staffbase/design/tokens/primitive.css`, `@staffbase/design/tokens/component.css`.
|
|
39
|
+
|
|
40
|
+
Public entry points: components, types, and icons from `@staffbase/design`; hooks from `@staffbase/design/hooks`.
|
|
41
|
+
|
|
42
|
+
## Compound component pattern
|
|
43
|
+
|
|
44
|
+
Many components are compound — they export an object with capitalized subcomponent properties, accessed via dot notation:
|
|
45
|
+
|
|
46
|
+
```tsx
|
|
47
|
+
<Dialog.Root>
|
|
48
|
+
<Dialog.Trigger>
|
|
49
|
+
<Button>Open</Button>
|
|
50
|
+
</Dialog.Trigger>
|
|
51
|
+
<Dialog.Popup>
|
|
52
|
+
<Dialog.Header>
|
|
53
|
+
<Dialog.Title>Title</Dialog.Title>
|
|
54
|
+
<Dialog.Close />
|
|
55
|
+
</Dialog.Header>
|
|
56
|
+
<Dialog.Body>Content</Dialog.Body>
|
|
57
|
+
<Dialog.Footer>Actions</Dialog.Footer>
|
|
58
|
+
</Dialog.Popup>
|
|
59
|
+
</Dialog.Root>
|
|
60
|
+
```
|
|
61
|
+
|
|
62
|
+
If you don't know whether a given component is compound, call `get_component` — its `compoundMembers` field lists the subcomponents.
|
|
63
|
+
|
|
64
|
+
### Trigger subcomponents take an element as `children`
|
|
65
|
+
|
|
66
|
+
`Trigger` subcomponents in `Dialog`, `AlertDialog`, `Menu`, and `Tooltip` accept an element as `children`. Do **NOT** use a `render` prop — the design system wraps the underlying base library's render prop internally:
|
|
67
|
+
|
|
68
|
+
```tsx
|
|
69
|
+
// ✅ Correct
|
|
70
|
+
<Dialog.Trigger><Button>Open</Button></Dialog.Trigger>
|
|
71
|
+
|
|
72
|
+
// ❌ Wrong
|
|
73
|
+
<Dialog.Trigger render={<Button />}>Open</Dialog.Trigger>
|
|
74
|
+
```
|
|
75
|
+
|
|
76
|
+
### Portal containers
|
|
77
|
+
|
|
78
|
+
Overlay subcomponents (`Dialog.Popup`, `Menu.Popup`, `Select.Popup`, `Popover.Content`, `Tooltip.Content`) accept a `container` prop to control the portal target DOM node.
|
|
79
|
+
|
|
80
|
+
## Astro component docs — two-tab pages
|
|
81
|
+
|
|
82
|
+
Component docs in the Astro site now use a two-tab pattern directly below the page title and description:
|
|
83
|
+
|
|
84
|
+
- **Overview** contains the existing component documentation body, examples, and API reference.
|
|
85
|
+
- **Guidelines** contains the usability, visual design, and UX copy guidance for that component.
|
|
86
|
+
|
|
87
|
+
When authoring or editing component docs, keep the page content organized so the heading hierarchy in each tab remains semantic and readable. The Guidelines tab content should follow the corresponding Figma frame for that component once available.
|
|
88
|
+
|
|
89
|
+
## Customizability — `data-c13y-*` attributes
|
|
90
|
+
|
|
91
|
+
The library exposes a stable CSS-selector surface for customer customizability ("c13y") via `data-c13y-*` attributes. Two axes:
|
|
92
|
+
|
|
93
|
+
- **`data-c13y-component`** — _structural_ identity (what the element is: `button`, `dialog-popover`, `menu-item`). **The library emits this for you** on every primitive (including compound sub-part values). **Do NOT set `data-c13y-component` on a design primitive** — it already emits the correct value.
|
|
94
|
+
- **`data-c13y-purpose`** — _feature intent_ (what the element does for the user: `join`, `save`, `sort`). The library sets this only on its own internal controls (e.g. a Dialog's close button). For your feature's intent, **pass `data-c13y-purpose` yourself**; it forwards to the primitive's root element.
|
|
95
|
+
- **`data-c13y-id`** — an addressable instance id; pass it to mark individual instances. Prefer it over `data-testid` for logically-identified instances.
|
|
96
|
+
|
|
97
|
+
```tsx
|
|
98
|
+
// ✅ Design primitive — set purpose only; the library emits component
|
|
99
|
+
<GhostButton onClick={onJoin} data-c13y-purpose="join">Join</GhostButton>
|
|
100
|
+
|
|
101
|
+
// ❌ Don't override component on a design primitive
|
|
102
|
+
<GhostButton data-c13y-component="button" data-c13y-purpose="join">Join</GhostButton>
|
|
103
|
+
|
|
104
|
+
// ✅ A native element you render yourself — set BOTH (no library emits it for you)
|
|
105
|
+
<button type="button" data-c13y-component="button" data-c13y-purpose="sort"><SortIcon /></button>
|
|
106
|
+
```
|
|
107
|
+
|
|
108
|
+
**Values must be runtime-static and kebab-case** (`[a-z0-9][a-z0-9-]*`): no interpolation, no locale/translation-derived strings, no state-dependent values. Use one stable purpose for a toggle regardless of state.
|
|
109
|
+
|
|
110
|
+
**Regions on portalled overlays.** Portalled overlays (`Menu.Popup`, `Select.Popup`, `Tooltip.Content`, `SearchableSingleSelect.Popup`, `SearchableMultiSelect.Popup`) render outside the trigger's DOM subtree, so they don't inherit the trigger's `data-c13y-region`. To scope them into the same region, pass `data-c13y-region` (and any `data-c13y-purpose` / `data-c13y-id`) directly to the overlay's `Popup`/`Content` — it lands on the visible popup element alongside `data-c13y-component`:
|
|
111
|
+
|
|
112
|
+
```tsx
|
|
113
|
+
<Menu.Popup data-c13y-region="my-groups" data-c13y-purpose="filter">
|
|
114
|
+
…
|
|
115
|
+
</Menu.Popup>
|
|
116
|
+
```
|
|
117
|
+
|
|
118
|
+
## Design tokens — three layers, prefer the most semantic
|
|
119
|
+
|
|
120
|
+
| Layer | Naming pattern | When to use |
|
|
121
|
+
| --------- | ----------------------------------------- | ---------------------------------------------------------------- |
|
|
122
|
+
| Primitive | `--sb-color-{hue}-{shade}` | Never in component code. Raw values; do not theme against these. |
|
|
123
|
+
| Semantic | `--sb-{category}-color-{intent}-{weight}` | **Default.** Adapts to dark mode/theming. |
|
|
124
|
+
| Component | `--sb-{component}-{property}` | Per-component overrides only. |
|
|
125
|
+
|
|
126
|
+
Use `list_tokens` / `get_token` to discover and resolve specific names. The rule is: pick the most semantic layer that does the job.
|
|
127
|
+
|
|
128
|
+
## Form error states — two patterns
|
|
129
|
+
|
|
130
|
+
Different components handle errors differently. Check the props interface (via `get_component`) before choosing:
|
|
131
|
+
|
|
132
|
+
**Pattern A — self-contained error props.** Used when the component's props include `errorMessage` and/or `hasError`:
|
|
133
|
+
|
|
134
|
+
```tsx
|
|
135
|
+
<Checkbox label="Accept terms" hasError errorMessage="Required" errorAriaLive="polite" />
|
|
136
|
+
<TextArea label="Comment" errorMessage="Cannot be empty" />
|
|
137
|
+
```
|
|
138
|
+
|
|
139
|
+
**Pattern B — `Field` wrapper.** Used when the component has no built-in error props (e.g. `TextField`, `Select`):
|
|
140
|
+
|
|
141
|
+
```tsx
|
|
142
|
+
<Field.Root>
|
|
143
|
+
<Field.Label>Name</Field.Label>
|
|
144
|
+
<TextField />
|
|
145
|
+
<Field.Error>Name is required</Field.Error>
|
|
146
|
+
</Field.Root>
|
|
147
|
+
```
|
|
148
|
+
|
|
149
|
+
Rule of thumb: if `errorMessage` or `hasError` appears in the props interface, use Pattern A. Otherwise wrap in `Field`.
|
|
150
|
+
|
|
151
|
+
## Accessibility
|
|
152
|
+
|
|
153
|
+
Several components have **required** a11y props that TypeScript enforces — `aria-label` on `SegmentedControl.Root` / `Banner.CloseButton` / `LoadingSpinner` / `Button` (when `iconOnly`), `a11yDescription` on `Badge`, `title` on `Popover.Close` / `HelpButton`, `is` on `Tooltip.Content`. Don't suppress these with type assertions; provide real values. `get_component` shows them on the props interface.
|
|
154
|
+
|
|
155
|
+
## Conventions
|
|
156
|
+
|
|
157
|
+
- **CSS classes** use the `ds-` prefix and BEM (`ds-button`, `ds-button__content`, `ds-button--primary`). Don't override them directly — use the `className` prop to layer on custom styles.
|
|
158
|
+
- **RTL by default.** Use CSS logical properties (`margin-inline-start`, `padding-inline-end`) and Tailwind `start`/`end` utilities. Never `margin-left` / `padding-right` in component or consumer code.
|
|
159
|
+
- **Icon slot props are `leadingIcon` / `trailingIcon`** — never `leftIcon` / `rightIcon`.
|
|
160
|
+
|
|
161
|
+
## Common mistakes — do NOT do these
|
|
162
|
+
|
|
163
|
+
- **Don't use deprecated components.** Call `list_components` to see which are deprecated and what to use instead. Never introduce new usages even if you find them in existing code — flag and suggest migration. Key migrations: `ButtonDeprecated` → `Button`; `GhostButton` → `Button variant="ghost"`; `IconButton` / `IconGhostButton` → `Button iconOnly`.
|
|
164
|
+
- **Don't use a `render` prop on Trigger components** — pass the element as `children`.
|
|
165
|
+
- **Don't use `margin-left` / `padding-right`** — use `margin-inline-start` / `padding-inline-end`.
|
|
166
|
+
- **Don't import individual component CSS files** — only `@staffbase/design/components.css`.
|
|
167
|
+
- **Don't use primitive tokens (`--sb-color-blue-500`) for theming** — use semantic tokens; they adapt to dark mode.
|
|
168
|
+
- **Don't override `ds-` prefixed classes directly** — use `className` to add custom styles alongside.
|
|
169
|
+
- **Don't set `data-c13y-component` on a design primitive** — the library emits it. Pass only `data-c13y-purpose` / `data-c13y-id`, and `data-c13y-region` on portalled overlays.
|
|
170
|
+
|
|
171
|
+
## Testing
|
|
172
|
+
|
|
173
|
+
Vitest + `@testing-library/react`. Query by accessible role, not class name or test id:
|
|
174
|
+
|
|
175
|
+
```tsx
|
|
176
|
+
import {render, screen} from '@testing-library/react';
|
|
177
|
+
import userEvent from '@testing-library/user-event';
|
|
178
|
+
import {Button} from '@staffbase/design';
|
|
179
|
+
|
|
180
|
+
test('button click', async () => {
|
|
181
|
+
const user = userEvent.setup();
|
|
182
|
+
const onClick = vi.fn();
|
|
183
|
+
render(<Button onClick={onClick}>Save</Button>);
|
|
184
|
+
await user.click(screen.getByRole('button', {name: 'Save'}));
|
|
185
|
+
expect(onClick).toHaveBeenCalled();
|
|
186
|
+
});
|
|
187
|
+
```
|