Skip to content

Commit ebb606f

Browse files
authored
Merge branch 'next' into drivenets/michal/AR-52648-ds-button-v3
2 parents 5238a39 + 349ec56 commit ebb606f

28 files changed

Lines changed: 1122 additions & 391 deletions

File tree

.changeset/stale-doors-admire.md

Lines changed: 5 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,5 @@
1+
---
2+
'@drivenets/design-system': patch
3+
---
4+
5+
Add aria role to `DsLoader`

.cursor/notepads/add-play-tests.md

Lines changed: 0 additions & 13 deletions
This file was deleted.

.cursor/rules/browser-tests.mdc

Lines changed: 48 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,48 @@
1+
---
2+
description: Vitest browser test patterns for design system components
3+
globs: **/__tests__/*.browser.test.tsx
4+
---
5+
6+
# Vitest Browser Tests
7+
8+
Behavioral coverage for design-system components lives next to the component under `__tests__/`, e.g. `ds-checkbox/__tests__/ds-checkbox.browser.test.tsx`. Storybook stories are for docs and controls only.
9+
10+
## Principles
11+
12+
1. **Stories document UI**; assert behavior in `*.browser.test.tsx`.
13+
2. **Spy callbacks with `vi.fn()`** in tests (not Storybook `fn()`).
14+
3. **Prefer a11y queries**: `page.getByRole`, `getByLabelText`, `getByText` -- avoid `getByTestId` unless unavoidable.
15+
4. **Use Vitest browser matchers**: `await expect.element(locator).toBeChecked()`, `toBeDisabled()`, `toBeVisible()`, etc.
16+
5. **Await async UI**: `await locator.click()`, `await expect.element(...)`.
17+
6. **Test user-visible behavior**, not implementation details; use `data-*` only when it is an explicit contract (e.g. indeterminate state).
18+
7. **Disabled / blocked interaction**: `await checkbox.click({ force: true })` when asserting a disabled control does not change state.
19+
8. **Controlled component testing**: define an inline wrapper with `useState` to test controlled behavior.
20+
9. **Rerender for prop changes**: use `const { rerender } = await page.render(...)` to test conditional rendering.
21+
10. **Hover interactions**: `await locator.hover()` / `await locator.unhover()` for tooltip-style components.
22+
11. **Nested locators**: scope queries within a parent: `parentLocator.getByText(...)`.
23+
12. **`toBeInTheDocument` vs `toBeVisible`**: use `not.toBeInTheDocument()` for removed DOM elements, `not.toBeVisible()` for hidden ones.
24+
13. **Querying disabled elements**: pass `{ disabled: true }` to role queries: `page.getByRole('checkbox', { disabled: true })`.
25+
26+
## Example: callback spy
27+
28+
```tsx
29+
import { describe, expect, it, vi } from 'vitest';
30+
import { page } from 'vitest/browser';
31+
import DsWidget from '../ds-widget';
32+
33+
describe('DsWidget', () => {
34+
it('calls onSave when submitted', async () => {
35+
const onSave = vi.fn();
36+
await page.render(<DsWidget onSave={onSave} />);
37+
38+
await page.getByRole('button', { name: /save/i }).click();
39+
expect(onSave).toHaveBeenCalledOnce();
40+
});
41+
});
42+
```
43+
44+
## Run
45+
46+
```bash
47+
pnpm --filter @drivenets/design-system test packages/design-system/src/components/ds-{name}/__tests__/ds-{name}.browser.test.tsx --run
48+
```

.cursor/rules/code-review.mdc

Lines changed: 47 additions & 21 deletions
Original file line numberDiff line numberDiff line change
@@ -1,19 +1,40 @@
11
---
2-
description: Apply when reviewing code changes, running git diff, or preparing a PR
2+
description: Apply when preparing a PR, reviewing code changes, running git diff, or generating a changeset
33
alwaysApply: false
44
---
55

6-
# Code Review Rules
6+
# PR Workflow & Code Review
77

8-
It is a local code review process done before submitting a PR.
8+
## Git & PR Workflow
99

10-
## Process
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+
Add DsCard component
24+
25+
<!-- Bad changeset message - implementation details -->
26+
Refactor card to use CSS modules and fix hover state selector specificity
27+
```
28+
29+
---
30+
31+
## Code Review Process
1132

1233
1. Get diff: `git diff origin/main`
13-
2. Review every changed file against project cursor rules
34+
2. Review every changed file against project cursor rules (scss, react-patterns, storybook, etc.)
1435
3. Flag only clear, high-severity issues (max 10 inline comments)
1536

16-
## Inline comment format
37+
### Inline comment format
1738

1839
```typescript
1940
/**
@@ -23,19 +44,24 @@ It is a local code review process done before submitting a PR.
2344

2445
- One issue per comment; place on the exact changed line
2546
- Natural tone, specific and actionable; do not mention automated or high-confidence
26-
- Severity emojis: 🚨 Critical 🔒 Security ⚡ Performance ⚠️ Logic ✨ Improvement
27-
28-
## Priorities to check
29-
30-
- No `!important` in SCSS
31-
- No hardcoded colors or spacing (use `--color-*`, `--spacing-*` tokens)
32-
- No `:global` in CSS modules
33-
- No unnecessary `useMemo`/`useCallback`
34-
- No `forwardRef` (deprecated)
35-
- No cross-component internal imports
36-
- No `useLayoutEffect` without DOM reads
37-
- Stories have `play` functions with `fn()` and a11y queries
38-
- No inline styles in stories
39-
- Props layer doesn't expose library internals
40-
- Logic errors, security issues, race conditions, missing edge cases
47+
- Severity: 🚨 Critical 🔒 Security ⚡ Performance ⚠️ Logic ✨ Improvement
48+
49+
---
50+
51+
## PR Checklist
52+
53+
Before submitting a PR:
4154

55+
- [ ] Changelog added (`pnpm changelog`) with user-facing message
56+
- [ ] Behavioral coverage in `*.browser.test.tsx` where interactions matter
57+
- [ ] Browser tests use a11y queries (no test-ids unless unavoidable)
58+
- [ ] CSS uses design tokens, no `!important`
59+
- [ ] No inline styles in stories
60+
- [ ] Props layer doesn't expose library internals
61+
- [ ] Types exported from `.types.ts` with variant arrays
62+
- [ ] Code is well-spaced and readable
63+
- [ ] Matches Figma design
64+
- [ ] Storybook examples show all states (controlled + localized)
65+
- [ ] No cross-component internal imports
66+
- [ ] No unnecessary `useMemo`/`useCallback`
67+
- [ ] Check Ark UI for existing primitives before custom implementation

.cursor/rules/design-system.mdc

Lines changed: 2 additions & 47 deletions
Original file line numberDiff line numberDiff line change
@@ -1,9 +1,9 @@
11
---
2-
description: Component scaffolding templates for creating new design system components
2+
description: Design system component conventions and primitive library choices
33
globs: packages/design-system/src/components/**/*
44
---
55

6-
# Component Scaffolding
6+
# Design System Components
77

88
## File Structure
99

@@ -18,51 +18,6 @@ ds-{name}/
1818
└── ds-{name}.stories.tsx # Stories
1919
```
2020

21-
## Implementation Template
22-
23-
```tsx
24-
import classNames from 'classnames';
25-
import styles from './ds-{name}.module.scss';
26-
import type { Ds{Name}Props } from './ds-{name}.types';
27-
28-
/**
29-
* Design system {Name} component
30-
*/
31-
const Ds{Name} = ({
32-
className,
33-
children,
34-
...props
35-
}: Ds{Name}Props) => {
36-
return (
37-
<div className={classNames(styles.container, className)} {...props}>
38-
{children}
39-
</div>
40-
);
41-
};
42-
43-
export default Ds{Name};
44-
```
45-
46-
## Types Template
47-
48-
```typescript
49-
import type { ComponentPropsWithoutRef, ReactNode } from 'react';
50-
51-
export interface Ds{Name}Props extends ComponentPropsWithoutRef<'div'> {
52-
/**
53-
* JSDoc description
54-
*/
55-
label?: ReactNode;
56-
}
57-
```
58-
59-
## Index Barrel
60-
61-
```typescript
62-
export { default as Ds{Name} } from './ds-{name}';
63-
export type { Ds{Name}Props } from './ds-{name}.types';
64-
```
65-
6621
## Primitive Libraries
6722

6823
1. **Ark UI** (`@ark-ui/react`) - Primary choice for new components

.cursor/rules/react-patterns.mdc

Lines changed: 1 addition & 41 deletions
Original file line numberDiff line numberDiff line change
@@ -87,21 +87,7 @@ const id = useId();
8787
container.addEventListener('scroll', checkOverflow, { passive: true });
8888
```
8989

90-
One other situation you might want to use useLayoutEffect instead of useEffect is if you're updating a value (like a ref)
91-
and you want to make sure it's up-to-date before any other code runs. For example:
92-
93-
```tsx
94-
// Good
95-
const ref = React.useRef()
96-
React.useEffect(() => {
97-
ref.current = 'some value'
98-
})
99-
100-
// then, later in another hook or something
101-
React.useLayoutEffect(() => {
102-
console.log(ref.current) // <-- this logs an old value because this runs first!
103-
})
104-
```
90+
Also use `useLayoutEffect` when updating a ref that must be current before other hooks read it (it fires before `useEffect`).
10591

10692
---
10793

@@ -144,29 +130,3 @@ const [inputValue, setInputValue] = useState('');
144130
</Combobox.Root>
145131
```
146132

147-
---
148-
149-
## Component API Ordering
150-
151-
| Requirement | Details |
152-
| -------------------------------------------- | -------------------------------------------------------------------------------- |
153-
| **Value props first, callbacks last** | Order: value/config props, then render/slot props, then callbacks |
154-
| **`locale` prop for i18n** | Components with hardcoded text should accept a `locale` prop for overrides |
155-
156-
```typescript
157-
// Good - ordered interface
158-
export interface DsTagFilterProps {
159-
// Value props
160-
items: TagFilterItem[];
161-
selectedKeys?: string[];
162-
size?: 'small' | 'medium';
163-
164-
// Slot props
165-
slotProps?: { tag?: Partial<DsTagProps> };
166-
locale?: { clearAll?: string; showMore?: string };
167-
168-
// Callbacks
169-
onSelectionChange?: (keys: string[]) => void;
170-
onClear?: () => void;
171-
}
172-
```

.cursor/rules/standards.mdc

Lines changed: 4 additions & 55 deletions
Original file line numberDiff line numberDiff line change
@@ -1,35 +1,9 @@
11
---
2-
description: PR requirements and code standards for the design-system repository
2+
description: Code standards for the design-system repository
33
alwaysApply: true
44
---
55

6-
# Pull Request Requirements & Code Standards
7-
8-
Based on code review feedback, here are the consolidated standards for the design-system repository.
9-
10-
---
11-
12-
## Git & PR Workflow
13-
14-
| Requirement | Details |
15-
| -------------------------------------------- | -------------------------------------------------------------------------------- |
16-
| **No force-push after review** | GitHub loses review history; use merge commits instead |
17-
| **Changelog required** | Run `pnpm changelog` before merge |
18-
| **Conventional commits** | PR title must follow conventional commit format |
19-
| **Separate concerns** | Unrelated changes go in separate PRs; easier revert and isolation |
20-
| **Changeset messages are user-facing** | Write "Add X to Y" or "Fix X in Y", not implementation details |
21-
| **`skip changelog` label** | Use only for non-user-facing changes (CI, tests, docs); never for bug fixes |
22-
| **Use `--frozen-lockfile`** | Run `pnpm install --frozen-lockfile` to avoid unnecessary lockfile changes |
23-
24-
```markdown
25-
<!-- Good changeset message -->
26-
Add DsCard component
27-
28-
<!-- Bad changeset message - implementation details -->
29-
Refactor card to use CSS modules and fix hover state selector specificity
30-
```
31-
32-
---
6+
# Code Standards
337

348
## Component API Design
359

@@ -42,6 +16,8 @@ Refactor card to use CSS modules and fix hover state selector specificity
4216
| **Consistent callback naming** | Prefer `onXChange` pattern |
4317
| **`null` for empty callback values** | Use `null` (not `undefined`) for optional values in callbacks: `(value: string \| null) => void` |
4418
| **Single deprecation comment** | In types file only, not on every export |
19+
| **Value props first, callbacks last** | Order: value/config props, then render/slot props, then callbacks |
20+
| **`locale` prop for i18n** | Components with hardcoded text should accept a `locale` prop for overrides |
4521

4622
```typescript
4723
// Good - own props layer with null for clearable value
@@ -145,30 +121,3 @@ import { formatDate } from '../../utils/format-date';
145121
| **Barrel exports** | Use `index.ts` not `index.tsx` |
146122
| **kebab-case files** | All files must be kebab-case |
147123

148-
---
149-
150-
## ESLint Plugin
151-
152-
| Requirement | Details |
153-
| -------------------------------------------- | -------------------------------------------------------------------------------- |
154-
| **Deprecation rules** | Add to `@drivenets/eslint-plugin-design-system` when deprecating |
155-
156-
---
157-
158-
## PR Checklist
159-
160-
Before submitting a PR:
161-
162-
- [ ] Changelog added (`pnpm changelog`) with user-facing message
163-
- [ ] All stories have `play` tests with `fn()` for callbacks
164-
- [ ] Tests use a11y queries (no test-ids)
165-
- [ ] CSS uses design tokens, no `!important`
166-
- [ ] No inline styles in stories
167-
- [ ] Props layer doesn't expose library internals
168-
- [ ] Types exported from `.types.ts` with variant arrays
169-
- [ ] Code is well-spaced and readable
170-
- [ ] Matches Figma design
171-
- [ ] Storybook examples show off all states (including controlled + localized)
172-
- [ ] No cross-component internal imports
173-
- [ ] No unnecessary `useMemo`/`useCallback`
174-
- [ ] Check Ark UI for existing primitives before custom implementation

0 commit comments

Comments
 (0)