Skip to content

Commit dd4ee41

Browse files
authored
Merge f88f79e into 402b3b0
2 parents 402b3b0 + f88f79e commit dd4ee41

23 files changed

Lines changed: 3207 additions & 908 deletions

File tree

.claude/ADVICE.md

Lines changed: 1237 additions & 0 deletions
Large diffs are not rendered by default.

.claude/settings.json

Lines changed: 21 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,21 @@
1+
{
2+
"permissions": {
3+
"allow": [
4+
"Bash(npm run:*)",
5+
"Bash(npm test:*)",
6+
"Bash(ls:*)",
7+
"Bash(git log:*)",
8+
"Bash(git add:*)",
9+
"Bash(git commit:*)",
10+
"Bash(git branch:*)",
11+
"Bash(git checkout:*)",
12+
"Bash(git fetch:*)",
13+
"Read(../patternfly/**)",
14+
"WebFetch(domain:www.patternfly.org)"
15+
],
16+
"additionalDirectories": [
17+
"../patternfly-react",
18+
"../patternfly"
19+
]
20+
}
21+
}
Lines changed: 287 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,287 @@
1+
---
2+
name: create-element
3+
description: >
4+
Create a new pf-v6 element from a PatternFly React component that has
5+
no existing v5 web component. Use when asked to "create", "build",
6+
"implement", or "add" a new element from scratch.
7+
tools: Read, Glob, Grep, Bash
8+
---
9+
10+
# Create New v6 Element
11+
12+
Build a new `pf-v6-{name}` element from the PatternFly React v6 source.
13+
No existing v5 element to start from -- everything written fresh.
14+
Aim for end-user experience parity with the corresponding v6 react component.
15+
16+
## Prerequisites
17+
18+
- `cem serve` running (`npm run dev`)
19+
- Chrome MCP connected
20+
- React source in `../patternfly-react/packages/react-core/src/components/`
21+
- SCSS source in `../patternfly/src/patternfly/components/` (for reference)
22+
23+
## Workflow
24+
25+
### Phase 1: Analyze React Source
26+
27+
1. Read the React component:
28+
```
29+
../patternfly-react/packages/react-core/src/components/{Name}/
30+
```
31+
See also the corresponding docs page e.g.
32+
https://patternfly.org/components/accordion/
33+
34+
See demos in
35+
```
36+
../patternfly-react/packages/react-core/src/demos/
37+
```
38+
39+
2. Read the stylesheet for that element via the Chrome MCP, pointed at the element page
40+
```
41+
https://patternfly.org/components/{Name}/
42+
```
43+
44+
3. Read the React test files for behavioral expectations:
45+
```
46+
../patternfly-react/packages/react-core/src/components/{Name}/__tests__/
47+
```
48+
49+
4. Identify:
50+
- Props that map to attributes vs properties vs slots vs CSS
51+
- Events (callbacks) that map to DOM events
52+
- Internal state management
53+
- Form association needs
54+
- Sub-components needed
55+
- Dependencies on other PF elements (must already exist as pf-v6-*)
56+
57+
### Phase 2: Enumerate Demos
58+
59+
Fetch the patternfly.org component page to identify all demos:
60+
```
61+
https://www.patternfly.org/components/{name}
62+
```
63+
64+
Each demo has a full-screen URL:
65+
```
66+
https://www.patternfly.org/components/{name}/react/{demo-slug}/
67+
```
68+
69+
Identify which demo source file corresponds to each docs site demo
70+
71+
Map React demos to our demo files:
72+
```
73+
React demo name -> Our demo file
74+
"Variant examples" -> demo/variant-examples.html
75+
"Disabled buttons" -> demo/disabled-buttons.html
76+
```
77+
78+
Additional demos for WC-specific APIs (slots, CSS parts, FACE) use our
79+
own names alongside.
80+
81+
Collect description text from patternfly.org for YAML frontmatter.
82+
83+
### Phase 3: Design Web-Native API
84+
85+
Read `.claude/ADVICE.md` first -- distilled rules from
86+
4800+ PR reviews. This is the canonical reference for all API decisions.
87+
88+
Full freedom on API design -- no legacy to preserve. Design the best
89+
web component API for this element's purpose.
90+
91+
#### React-to-WC Translation Rules
92+
- React `children` -> default slot
93+
- React render props -> named slots
94+
- React `className` -> not needed (shadow DOM)
95+
- React `onChange` callback -> `change` event (Event subclass)
96+
- React `isExpanded` prop -> `expanded` boolean attribute
97+
- React `variant="primary"` -> `variant="primary"` (often 1:1)
98+
- React component composition -> slot composition - be careful of SSR DOM
99+
access
100+
- React context -> CSS custom properties, or `@lit/context` if JS is required
101+
- React `useEffect` -> `willUpdate`/`updated` lifecycle
102+
- React hooks -> Lit reactive controllers
103+
104+
#### Prefer Native Web Platform
105+
- FACE instead of wrapping native inputs where feasible
106+
- `InternalsController` for all ElementInternals (ARIA, form association).
107+
Never use raw `attachInternals()` -- always go through InternalsController
108+
- When aria-label is indicated (e.g. icon-button), provide an `accessible-label`
109+
attribute
110+
- Slots for composition, not render-prop equivalents
111+
- Native `<dialog>` instead of JS-managed modals
112+
- Container queries instead of responsive/breakpoint attributes
113+
- `<details>` for expandable content (free a11y)
114+
115+
#### API Design Rules (apply to each surface)
116+
117+
IMPORTANT: in all cases where a react api does not cleanly map to a web component
118+
API, surface that to the user.
119+
120+
**Key principle:** easy to add, hard to remove. Ship less when in doubt.
121+
122+
##### Templates
123+
- Prefer ID selectors in shadow DOM,
124+
- Avoid BEM, avoid using .pf-* classes internally in shadow root
125+
- Minimize wrappers; prefer `<slot>` directly
126+
- Vertical attribute formatting when >2 attrs
127+
- False case first in ternaries when used in templates
128+
- `slotchange` bubbles; listen on shadow root
129+
130+
##### Attributes & Properties:
131+
- Do not require light DOM classes. Use attributes instead
132+
- Enum-style `variant` over multiple booleans (exclusive, not stackable)
133+
- Boolean attributes: present = true, absent = false. No `is-` prefix.
134+
- Don't reflect booleans to `"true"|"false"` strings
135+
- Don't default reflected boolean attributes to true, it will be impossible to unset in
136+
HTML
137+
- Avoid array/object properties, exceptions for convenience APIs like
138+
`pfselect.items = []`
139+
- Don't reflect array or object properties
140+
- Multi-word attributes: dash-case with camelCase class fields
141+
- Don't expose `aria-*` as public API; abstract behind custom attributes
142+
- Attribute/slot pairs for content that could be plain or rich
143+
e.g.
144+
```html
145+
<pf-v6-foo description="plaintext"></pf-v6-foo>
146+
<pf-v6-foo><span slot="description"><em>Rich</em> text</pf-v6-foo>
147+
```
148+
- All attributes must have sensible defaults
149+
150+
##### Slots:
151+
- Default slot for primary content
152+
- Semantic names, not positional "header", not "top"
153+
- Don't provide placeholder "lorem ipsum" content; but do provide default content when
154+
sensible
155+
- Prescriptive descriptions in docs ("Label text" not "The label slot") - see https://bennypowers.dev/cem/docs/usage/effective-mcp-descriptions/
156+
- Hide empty slot containers, but be wary of SSR problems, use SlotController's
157+
ssr-hint-* attributes
158+
- WARNING: `:empty` does not work on slots, `:has-slotted` is not yet widely available
159+
160+
##### Events:
161+
- Event subclasses, not `CustomEvent` with detail
162+
- Cancelable for destructive/state-changing actions, or when users may wish to prevent default.
163+
- Match native event names when wrapping native elements
164+
165+
##### Element CSS
166+
- Use Native nesting
167+
- Use `light-dark()`
168+
- Use logical properties instead of directionally
169+
- You may and should use any CSS features which are Baseline 2024 or earlier,
170+
but no later
171+
- Don't nest `:host([attr])` with `&`, this doesn't work.
172+
- Don't use :host:has() or :host(:has()) - these are not quite ready
173+
cross-browser
174+
- never use :host-context, it does not exist
175+
- `pointer-events: none` on disabled hosts
176+
177+
##### CSS Custom Properties:
178+
- Use `--_` prefix for private custom properties, for example, when a css custom
179+
property is defined purely to make the css file nicer, or for state management,
180+
but is not intended for public use.
181+
- Avoid setting public css properties on the :host selector, rather, reference
182+
them as fallback defaults at use sites
183+
- Don't duplicate native CSS capabilities
184+
- Fallback defaults at use site, not on `:host`
185+
- **MUST match patternfly-react** (`--pf-v6-c-{component}--*`)
186+
Only exception: shadow DOM structure vastly different from React's flat DOM.
187+
188+
If you find a case where a given CSS custom property in the React source is tightly
189+
coupled to a given DOM structure, in a way which inhibits our ability to freely
190+
factor the best web component, raise that to the user.
191+
192+
##### CSS Parts:
193+
- Name after internal element. Only expose with clear use cases.
194+
- Question aggressively -- hard to remove.
195+
196+
### Phase 4: Implement
197+
198+
1. Create element directory: `elements/pf-v6-{name}/`
199+
2. Write main element class:
200+
- `@customElement('pf-v6-{name}')` decorator
201+
- `static readonly styles` array
202+
- Reactive properties with `@property`
203+
- InternalsController for ARIA and form association (never raw attachInternals)
204+
- FACE patterns if form-associated
205+
- Template in `render()` method
206+
207+
3. Write CSS:
208+
- Translate SCSS to native CSS (nesting, light-dark(), logical properties)
209+
- Shadow DOM scoping (IDs not BEM)
210+
- Token-derived fallback values from PF token source
211+
- box-sizing reset
212+
- **MUST match patternfly-react CSS custom properties** (see CLAUDE.md)
213+
214+
4. Create sub-elements if needed (only for a11y/composition reasons)
215+
5. Update `elements/package.json` exports
216+
217+
### Phase 5: Create Demos
218+
219+
Create HTML partial demos in `demo/`. Demos are partials (no `<!DOCTYPE>`,
220+
`<html>`, `<head>`). `cem serve` wraps them.
221+
222+
For each demo from Phase 2:
223+
1. Create `demo/{demo-slug}.html` matching patternfly.org name
224+
2. Add YAML frontmatter:
225+
```html
226+
---
227+
name: Variant examples
228+
description: Button variant examples showing primary, secondary, and link styles.
229+
---
230+
```
231+
3. Inline `<script type="module">` with element import
232+
4. No wrapper divs; minimal markup
233+
234+
`index.html` = simplest possible usage.
235+
236+
Additional WC-specific demos:
237+
- `demo/slots.html` - slot composition patterns
238+
- `demo/form-associated.html` - FACE form integration (if applicable)
239+
- `demo/css-custom-properties.html` - theming overrides
240+
241+
### Phase 6: Visual Comparison with Chrome MCP
242+
243+
**CRITICAL**: `?rendering=chromeless` on ALL cem serve URLs.
244+
245+
For each demo, compare against patternfly.org:
246+
247+
1. Open our demo:
248+
```
249+
navigate_page -> http://localhost:8000/elements/{name}/demo/{demo-slug}?rendering=chromeless
250+
```
251+
2. Open React reference:
252+
```
253+
new_page -> https://www.patternfly.org/components/{name}/react/{demo-slug}/
254+
```
255+
3. `take_snapshot` + `take_screenshot` both tabs
256+
4. Compare visuals (layout, colors, typography, borders, dark mode)
257+
5. Compare structure (interactive elements, ARIA, keyboard nav, focus)
258+
6. Iterate: fix differences, retake, repeat until visual parity
259+
7. Interactive test: `click`, `press_key`, `fill`, check console errors
260+
8. Exhaustively check all element states e.g. expanded select, active descendant, etc
261+
262+
### Phase 7: Write Tests
263+
264+
Write all tests from scratch:
265+
- Unit tests validating public API (attributes, properties, events)
266+
- a11ySnapshot assertions for accessibility tree
267+
- Keyboard navigation tests
268+
- Form submission tests (if FACE)
269+
- Setup in beforeEach, assertions in it blocks
270+
- No arrow functions in Mocha tests
271+
- Test observable behavior (offsetWidth, computed styles), not shadow DOM
272+
- Cover behavioral expectations from React tests (Phase 1 step 3)
273+
which are not already covered
274+
275+
See `.claude/skills/review-api/SKILL.md` Phase 4 for full test checklist.
276+
277+
### Phase 8: Audit
278+
279+
Prompt the user to activate /review-api, /review-demos, and /review-a11y
280+
281+
Fix all critical and warning findings before PR
282+
283+
## Quality Bar
284+
285+
Place the web component next to React: visually and functionally
286+
indistinguishable to end users. API should feel native to web developers.
287+
Accessibility may and should exceed React's -- that's a feature, not a bug.

0 commit comments

Comments
 (0)