Skip to content

Commit b45b2ef

Browse files
committed
Merge remote-tracking branch 'drivenets/main' into chore/AR-64284-cspell-github
2 parents 7ce9e8a + fab30fb commit b45b2ef

194 files changed

Lines changed: 11015 additions & 4807 deletions

File tree

Some content is hidden

Large Commits have some content hidden by default. Use the searchbox below for content that may be hidden.

.agents/skills/ark-ui/SKILL.md

Lines changed: 51 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,51 @@
1+
---
2+
name: ark-ui
3+
description: Check Ark UI primitives via MCP and integrate them in ds-* components without duplicating internal state. Use before building a custom component, wrapping Ark primitives, or when the user mentions Ark UI MCP.
4+
---
5+
6+
# Ark UI Skill
7+
8+
Before custom code, check if Ark UI already provides a primitive.
9+
10+
## MCP workflow
11+
12+
1. `list_components` with `framework: "react"`.
13+
2. If a match exists:
14+
- `get_component_props``framework: "react"`, component name.
15+
- `get_example``framework: "react"`, component name, `exampleId: "basic"`.
16+
- `styling_guide` — component name (data attributes for SCSS).
17+
3. If no match — build custom.
18+
19+
## What to extract from Ark API
20+
21+
| Topic | Action |
22+
| --------------- | -------------------------------------------------------------------------------------------------------- |
23+
| Props to expose | Subset only — own props layer ([component-api](../component-api/SKILL.md)); never `extends ArkRootProps` |
24+
| Internal state | Ark owns it — no mirroring with `useState` |
25+
| Callbacks | Wrap and forward to own props; do not replace Ark handlers |
26+
| Styling | `data-*` attrs from styling guide → [scss](../scss/SKILL.md) |
27+
28+
## Implementation patterns
29+
30+
| Requirement | Details |
31+
| ---------------------------------- | ----------------------------------------------- |
32+
| Don't duplicate Ark internal state | Inputs, selects, comboboxes, etc. |
33+
| Don't override Ark callbacks | Hook `onInputValueChange`-style APIs to forward |
34+
35+
```typescript
36+
// Bad
37+
const [inputValue, setInputValue] = useState('');
38+
<Combobox.Input value={inputValue} onChange={(e) => setInputValue(e.target.value)} />
39+
40+
// Good
41+
<Combobox.Root onInputValueChange={({ inputValue }) => onInputChange?.(inputValue)}>
42+
<Combobox.Input />
43+
</Combobox.Root>
44+
```
45+
46+
## Related
47+
48+
- Public API on `*.types.ts`: [component-api](../component-api/SKILL.md)
49+
- SCSS state selectors: [scss](../scss/SKILL.md)
50+
- Figma workflow: [figma-to-component](../figma-to-component/SKILL.md)
51+
- New component flow: [component-scaffold](../component-scaffold/SKILL.md)
Lines changed: 121 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,121 @@
1+
---
2+
name: browser-tests
3+
description: Write and extend Vitest browser tests for design-system components. Use when adding or editing `*.browser.test.tsx`, writing behavioral coverage, or moving assertions out of Storybook.
4+
---
5+
6+
# Browser Tests Skill
7+
8+
Behavioral coverage lives next to the component: `ds-{name}/__tests__/ds-{name}.browser.test.tsx`. Stories document UI and controls only.
9+
10+
## Quick start
11+
12+
```tsx
13+
import { describe, expect, it, vi } from 'vitest';
14+
import { page } from 'vitest/browser';
15+
import DsWidget from '../ds-widget';
16+
17+
describe('DsWidget', () => {
18+
it('calls onSave when submitted', async () => {
19+
const onSave = vi.fn();
20+
await page.render(<DsWidget onSave={onSave} />);
21+
22+
await page.getByRole('button', { name: /save/i }).click();
23+
expect(onSave).toHaveBeenCalledOnce();
24+
});
25+
});
26+
```
27+
28+
## Principles
29+
30+
1. **Stories document UI**; assert behavior in `*.browser.test.tsx`.
31+
2. **Spy callbacks with `vi.fn()`** in tests (not Storybook `fn()`).
32+
3. **Prefer a11y queries**: `page.getByRole`, `getByLabelText`, `getByText` — avoid `getByTestId` unless unavoidable.
33+
4. **Use Vitest browser matchers**: `await expect.element(locator).toBeChecked()`, `toBeDisabled()`, `toBeVisible()`, etc.
34+
5. **Await async UI**: `await locator.click()`, `await expect.element(...)`.
35+
6. **Test user-visible behavior**, not implementation details; use `data-*` only when it is an explicit contract (e.g. indeterminate state).
36+
7. **Disabled / blocked interaction**: `await locator.click({ force: true })` when asserting a disabled control does not change state.
37+
8. **Controlled components**: inline wrapper with `useState` inside the test.
38+
9. **Prop changes**: `const { rerender } = await page.render(...)` then `await rerender(<Comp ... />)`.
39+
10. **Hover**: `await locator.hover()` / `await locator.unhover()` for tooltip-style UI.
40+
11. **Nested locators**: scope within parent — `parentLocator.getByText(...)`.
41+
12. **`toBeInTheDocument` vs `toBeVisible`**: `not.toBeInTheDocument()` for removed DOM; `not.toBeVisible()` for hidden.
42+
13. **Disabled queries**: `page.getByRole('checkbox', { disabled: true })`.
43+
44+
## Common patterns
45+
46+
### Callback spy
47+
48+
```tsx
49+
const onCheckedChange = vi.fn();
50+
await page.render(<DsCheckbox onCheckedChange={onCheckedChange} />);
51+
await page.getByRole('checkbox').click();
52+
expect(onCheckedChange).toHaveBeenCalledWith(true);
53+
```
54+
55+
### Controlled state
56+
57+
Inline wrapper with `useState` — same pattern as [react-patterns](../react-patterns/SKILL.md) controlled stories.
58+
59+
### Disabled — no state change
60+
61+
```tsx
62+
const checkbox = page.getByRole('checkbox', { disabled: true });
63+
await expect.element(checkbox).toBeDisabled();
64+
await checkbox.click({ force: true });
65+
await expect.element(checkbox).not.toBeChecked();
66+
```
67+
68+
### Rerender
69+
70+
```tsx
71+
const { rerender } = await page.render(<DsTooltip content={undefined}>...</DsTooltip>);
72+
await rerender(<DsTooltip content="Now visible">...</DsTooltip>);
73+
```
74+
75+
### Ark UI parts (last resort)
76+
77+
Use when a11y queries cannot express the contract (e.g. `data-state="indeterminate"`, row checkbox label hit target in tables):
78+
79+
```tsx
80+
const CHECKBOX_ROOT = '[data-scope="checkbox"][data-part="root"]';
81+
82+
const checkboxRoot = (idx = 0) =>
83+
page.elementLocator(document.querySelectorAll<HTMLElement>(CHECKBOX_ROOT)[idx] as HTMLElement);
84+
85+
await expect.element(checkboxRoot()).toHaveAttribute('data-state', 'indeterminate');
86+
await page.elementLocator(selectAllRoot).click();
87+
```
88+
89+
- Prefer `getByRole` / `getByLabelText` / `getByText` first.
90+
- Use `data-scope` + `data-part` from Ark styling guide — not arbitrary selectors.
91+
- Hoist repeated selectors to a file-level helper; one-line comment if non-obvious.
92+
- `page.elementLocator(domNode)` wraps raw DOM when Vitest needs a locator API.
93+
94+
## Anti-patterns
95+
96+
Reject or rewrite tests that only prove something mounted:
97+
98+
| Smell | Fix |
99+
| ----------------------------------------------------------------------------------------------------- | ------------------------------------------------------------------------------------------------- |
100+
| `expect(x).toBeTruthy()` with no interaction | Action + asserted outcome |
101+
| `toBeInTheDocument()` / `toBeVisible()` alone for a scenario named "toggles", "calls onX", "disabled" | Assert checked/disabled state, spy calls, text change, or `not.toBeInTheDocument()` after unmount |
102+
| Duplicate "renders" `it` blocks | Merge or delete — one smoke test max per component |
103+
| `getByTestId` when role/label works | Use a11y queries |
104+
105+
**Good:** click → `toBeChecked()` + `vi.fn()` called with expected arg.
106+
107+
**Bad:** render → `toBeVisible()` only (says nothing about the scenario name).
108+
109+
## Verify
110+
111+
```bash
112+
pnpm --filter @drivenets/design-system test packages/design-system/src/components/ds-{name}/__tests__/ds-{name}.browser.test.tsx --run
113+
pnpm eslint packages/design-system/src/components/ds-{name}/
114+
```
115+
116+
## Related
117+
118+
- **Migrate from Storybook play**: [migrate-story-tests](../migrate-story-tests/SKILL.md)
119+
- **New component**: [component-scaffold](../component-scaffold/SKILL.md)
120+
- **React state in tests**: [react-patterns](../react-patterns/SKILL.md)
121+
- **Examples**: `packages/design-system/src/components/*/__tests__/*.browser.test.tsx`
Lines changed: 83 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,83 @@
1+
---
2+
name: code-review
3+
description: Apply when preparing a PR, reviewing code changes, running git diff, or generating a changeset. Use when user says "review", "PR prep", "code review", or "changeset".
4+
---
5+
6+
# PR Workflow & Code Review
7+
8+
## Git & PR Workflow
9+
10+
| Requirement | Details |
11+
| -------------------------------------- | --------------------------------------------------------------------------- |
12+
| **No force-push after review** | GitHub loses review history; use merge commits instead |
13+
| **Changelog required** | Run `pnpm changelog` before merge |
14+
| **Conventional commits** | PR title must follow conventional commit format |
15+
| **Separate concerns** | Unrelated changes go in separate PRs; easier revert and isolation |
16+
| **Changeset messages are user-facing** | Write "Add X to Y" or "Fix X in Y", not implementation details |
17+
| **`skip changelog` label** | Use only for non-user-facing changes (CI, tests, docs); never for bug fixes |
18+
| **Use `--frozen-lockfile`** | Run `pnpm install --frozen-lockfile` to avoid unnecessary lockfile changes |
19+
| **Deprecation rules** | Add to `@drivenets/eslint-plugin-design-system` when deprecating |
20+
21+
```markdown
22+
<!-- Good changeset message -->
23+
24+
Add DsCard component
25+
26+
<!-- Bad changeset message - implementation details -->
27+
28+
Refactor card to use CSS modules and fix hover state selector specificity
29+
```
30+
31+
---
32+
33+
## Code Review Process
34+
35+
1. Get diff: `git diff origin/main`
36+
2. Review every changed file — read the matching skill(s) **fully** for paths in the diff:
37+
38+
| Changed paths | Skills |
39+
| ------------------------------ | ------------------------------------------------------------------------------------ |
40+
| `ds-*.types.ts` | [component-api](../component-api/SKILL.md), [ts-standards](../ts-standards/SKILL.md) |
41+
| `ds-*.tsx` (not stories/tests) | [react-patterns](../react-patterns/SKILL.md); [ark-ui](../ark-ui/SKILL.md) if Ark |
42+
| `*.stories.tsx` | [storybook](../storybook/SKILL.md), [react-patterns](../react-patterns/SKILL.md) |
43+
| `*.browser.test.tsx` | [browser-tests](../browser-tests/SKILL.md) |
44+
| `*.module.scss` | [scss](../scss/SKILL.md) |
45+
46+
3. Flag only clear, high-severity issues (max 10 inline comments)
47+
48+
### Inline comment format
49+
50+
```typescript
51+
/**
52+
* REVIEW-[SEVERITY]: [ISSUE DESCRIPTION]
53+
*/
54+
```
55+
56+
- One issue per comment; place on the exact changed line
57+
- Natural tone, specific and actionable; do not mention automated or high-confidence
58+
- Severity: 🚨 Critical 🔒 Security ⚡ Performance ⚠️ Logic ✨ Improvement
59+
60+
---
61+
62+
## PR Checklist
63+
64+
Before submitting a PR:
65+
66+
- [ ] Changelog added (`pnpm changelog`) with user-facing message
67+
- [ ] Behavioral coverage in `*.browser.test.tsx` where interactions matter
68+
- [ ] Browser tests use a11y queries (no test-ids unless unavoidable)
69+
- [ ] CSS uses design tokens, no `!important`
70+
- [ ] No inline styles in stories
71+
- [ ] Props layer doesn't expose library internals
72+
- [ ] Types exported from `.types.ts` with variant arrays
73+
- [ ] Code is well-spaced and readable
74+
- [ ] Matches Figma design
75+
- [ ] Storybook examples show all states (controlled + localized)
76+
- [ ] No cross-component internal imports
77+
- [ ] No unnecessary `useMemo`/`useCallback` (except under `ds-table/` — excluded from React Compiler; see [react-patterns](../react-patterns/SKILL.md))
78+
- [ ] Check Ark UI for existing primitives before custom implementation
79+
- [ ] No `overflow: hidden` as a band-aid for layout bugs
80+
- [ ] No raw `<img>` — use DS components (e.g., `DsAvatar`) with fallback
81+
- [ ] No leftover code from abandoned implementation approaches
82+
- [ ] No `-webkit-*` without cross-browser fallback or `@supports` guard
83+
- [ ] AI-generated tests actually assert meaningful behavior (not duplicate/trivial)
Lines changed: 57 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,57 @@
1+
---
2+
name: component-api
3+
description: Design public props for ds-* components in *.types.ts files. Use when editing ds-*.types.ts, Ds*Props interfaces, variant as const arrays, locale prop, onXChange callbacks, or changing component public API.
4+
---
5+
6+
# Component API Skill
7+
8+
Conventions for `packages/design-system/src/components/**/ds-*.types.ts`.
9+
10+
## Requirements
11+
12+
| Requirement | Details |
13+
| ------------------------------------- | ---------------------------------------------------------------------- |
14+
| **Own props layer** | Don't expose all underlying library props |
15+
| **Generic ref types** | `Ref<HTMLElement>` when it makes sense |
16+
| **Standard props** | Always support `className`, `style`, `ref` |
17+
| **slotProps pattern** | MUI-style sub-component customization |
18+
| **Callback naming** | Prefer `onXChange` |
19+
| **`null` for empty callback values** | `(value: string \| null) => void` — not `undefined` for cleared values |
20+
| **Single deprecation comment** | In types file only |
21+
| **Value props first, callbacks last** | Config → slot/render → callbacks |
22+
| **`locale` prop** | When component has hardcoded user-facing text |
23+
| **Domain-agnostic naming** | No product-specific terms in names or props |
24+
| **No use-case-specific props** | No `layout="form"` — keep API composable |
25+
26+
## Types file checklist
27+
28+
- Export variant arrays as `as const` + derived union type (Storybook `argTypes.options`).
29+
- `Ds{Name}Props` interface in dedicated `.types.ts`.
30+
- Prop JSDoc: document non-obvious behavior, units, or constraints; skip `ref`, `className`, and `style`. Don't restate the prop name or TypeScript type. See [ts-standards](../ts-standards/SKILL.md) for `@default` and export style.
31+
- Don't `extends` Ark/library root props → [ark-ui](../ark-ui/SKILL.md).
32+
33+
```typescript
34+
// Good
35+
interface DsSelectProps {
36+
value?: string | null;
37+
onValueChange?: (value: string | null) => void;
38+
ref?: Ref<HTMLElement>;
39+
className?: string;
40+
}
41+
42+
// Bad — undefined for empty value
43+
interface DsSelectProps {
44+
value?: string;
45+
onValueChange?: (value: string | undefined) => void;
46+
}
47+
48+
// Bad — exposes library internals
49+
interface DsToggleProps extends SwitchRootProps {}
50+
```
51+
52+
## Related
53+
54+
- Ark primitives: [ark-ui](../ark-ui/SKILL.md)
55+
- TS/JSDoc: [ts-standards](../ts-standards/SKILL.md)
56+
- Implementation: [react-patterns](../react-patterns/SKILL.md)
57+
- Scaffold: [component-scaffold](../component-scaffold/SKILL.md)
Lines changed: 70 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,70 @@
1+
---
2+
name: component-scaffold
3+
description: Scaffold a new ds-* component (files, barrel export, validation). Use when the user asks to create, scaffold, or add a new component.
4+
---
5+
6+
# Component Scaffold Skill
7+
8+
Orchestrator only — read linked skills **fully** before each step.
9+
10+
## Input
11+
12+
Component name → kebab-case files, PascalCase identifiers.
13+
14+
- Prefix: `ds-{name}` · Component: `Ds{Name}`
15+
- Dir: `packages/design-system/src/components/ds-{name}/`
16+
17+
## File manifest
18+
19+
```
20+
ds-{name}/
21+
├── index.ts
22+
├── ds-{name}.types.ts
23+
├── ds-{name}.tsx
24+
├── ds-{name}.module.scss
25+
├── ds-{name}.stories.tsx
26+
└── __tests__/ds-{name}.browser.test.tsx # when behavior matters
27+
```
28+
29+
Copy structure from `ds-button` or `ds-checkbox` when unsure.
30+
31+
## Read order (mandatory)
32+
33+
| Step | Action | Read fully |
34+
| ---- | ------------------------------- | ---------------------------------------------------------------------------------------------------------------------------- |
35+
| 1 | Ark vs custom | [ark-ui](../ark-ui/SKILL.md) |
36+
| 2 | Create empty files per manifest ||
37+
| 3 | `ds-{name}.types.ts` | [component-api](../component-api/SKILL.md), [ts-standards](../ts-standards/SKILL.md) |
38+
| 4 | `ds-{name}.tsx` | [react-patterns](../react-patterns/SKILL.md); [ark-ui](../ark-ui/SKILL.md) if primitive |
39+
| 5 | `ds-{name}.module.scss` | [scss](../scss/SKILL.md) |
40+
| 6 | `ds-{name}.stories.tsx` | [storybook](../storybook/SKILL.md) |
41+
| 7 | `__tests__/*.browser.test.tsx` | [browser-tests](../browser-tests/SKILL.md) — skip if presentational only |
42+
| 8 | Barrel | `index.ts` exports; add `export * from './components/ds-{name}'` to `packages/design-system/src/index.ts` (**alphabetical**) |
43+
| 9 | Validate | [AGENTS.md#code-quality-checkers](../../../AGENTS.md#code-quality-checkers) on touched paths |
44+
45+
## `index.ts`
46+
47+
```typescript
48+
export { default as Ds{Name} } from './ds-{name}';
49+
export type { Ds{Name}Props } from './ds-{name}.types';
50+
```
51+
52+
Use `.ts` extension on barrel file, not `.tsx`.
53+
54+
## Validate
55+
56+
```bash
57+
pnpm eslint packages/design-system/src/components/ds-{name}/
58+
pnpm --filter @drivenets/design-system typecheck
59+
```
60+
61+
With browser tests:
62+
63+
```bash
64+
pnpm --filter @drivenets/design-system test packages/design-system/src/components/ds-{name}/__tests__/ds-{name}.browser.test.tsx --run
65+
```
66+
67+
## Related
68+
69+
- Figma URL: [figma-to-component](../figma-to-component/SKILL.md) then this flow
70+
- PR checks: [pr-prep](../pr-prep/SKILL.md)
File renamed without changes.

0 commit comments

Comments
 (0)