Skip to content

Commit 8437146

Browse files
authored
chore: add CLAUDE.md (#12973)
1 parent e3b27c2 commit 8437146

1 file changed

Lines changed: 223 additions & 0 deletions

File tree

CLAUDE.md

Lines changed: 223 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,223 @@
1+
# CLAUDE.md
2+
3+
This file provides guidance to Claude Code (claude.ai/code) when working with code in this repository.
4+
5+
## Project Overview
6+
7+
UI5 Web Components is an enterprise-grade, framework-agnostic web components library implementing SAP Fiori design. It's a Yarn-based monorepo using Lerna and Yarn Workspaces.
8+
9+
**Requirements:** Node.js ^20.19.0 or >=22.12.0, Yarn v4 (via Corepack: `corepack enable`)
10+
11+
## Common Commands
12+
13+
Root folder commands:
14+
```bash
15+
# Building
16+
yarn ts # TypeScript compilation, always run in the root folder as the monorepo uses typescript workspaces too
17+
18+
# Linting
19+
yarn lint # Lint all packages
20+
```
21+
22+
Package level commands (e.g., packages/main/):
23+
```bash
24+
cd pacakges/main
25+
# Testing in a specific package
26+
yarn test:cypress # Run all Cypress tests
27+
yarn test:cypress:single cypress/specs/Button.cy.tsx # Run single test file
28+
```
29+
30+
## Monorepo Structure
31+
32+
Key packages in `/packages/`:
33+
- **base**: Core framework, UI5Element base class, decorators, rendering
34+
- **main**: Primary components (Button, Input, Table, etc.) - `@ui5/webcomponents`
35+
- **fiori**: SAP Fiori-specific components (ShellBar, SideNavigation) - `@ui5/webcomponents-fiori`
36+
- **ai**: AI-related components
37+
- **theming**: Theming assets and base themes
38+
- **localization**: i18n and CLDR assets
39+
- **icons**, **icons-tnt**, **icons-business-suite**: Icon collections
40+
- **tools**: Build tools, dev server, CLI
41+
42+
## Component Architecture
43+
44+
Components use decorator-based definitions with Preact JSX templates:
45+
46+
```typescript
47+
@customElement({
48+
tag: "ui5-button",
49+
renderer: jsxRenderer,
50+
template: ButtonTemplate,
51+
styles: buttonCss,
52+
languageAware: true,
53+
})
54+
class Button extends UI5Element {
55+
@property() design: `${ButtonDesign}` = "Default";
56+
@property({ type: Boolean }) disabled = false;
57+
}
58+
```
59+
60+
**File structure for a component:**
61+
- `src/ComponentName.ts` - Component class with decorators
62+
- `src/ComponentNameTemplate.tsx` - JSX template
63+
- `src/themes/ComponentName.css` - Styles (works across all themes via CSS variables)
64+
- `src/i18n/messagebundle*.properties` - Translations
65+
- `cypress/specs/<Component>.cy.tsx` - the test file for the component
66+
67+
## Critical Development Rules
68+
69+
### DOM manipulation anti-pattern
70+
this is a common pattern for accessing DOM elements:
71+
```typescript
72+
@query("[component-selector]")
73+
_domRefToComponent!: SomeComponent;
74+
```
75+
76+
another way for accessing DOM elements is:
77+
```typescript
78+
const _domRefToComponent = this.shadowRoot!.querySelector<SomeComponent>("[component-selector]")!;
79+
```
80+
81+
Using the reference is only allowed for calling `.focus()` like this:
82+
```typescript
83+
_domRefToComponent?.focus();
84+
```
85+
86+
Modifying properties is strictly forbidden and should be done in the template instead.
87+
```typescript
88+
// BAD - don't modify the dom directly
89+
_domRefToComponent?.value = `don't do this`;
90+
```
91+
92+
```tsx
93+
// GOOD - use the template
94+
<SomeComponent value={'do this instead'}>
95+
```
96+
97+
### Always use template literal types for enums
98+
Imports:
99+
```typescript
100+
// BAD - don't import the enum object from the JS file
101+
import ButtonDesign from "./types/ButtonDesign.js";
102+
103+
// GOOD - import the type of the enum only - no runtime overhead
104+
import type ButtonDesign from "./types/ButtonDesign.js";
105+
```
106+
107+
Property types:
108+
```typescript
109+
// BAD - don't use the type directy and don't assign values from the enum object
110+
design: ButtonDesign = ButtonDesign.Default;
111+
112+
// GOOD - Awalys use template literal for the enum and always assign the string values
113+
design: `${ButtonDesign}` = "Default";
114+
```
115+
116+
Enum value usage:
117+
```typescript
118+
// BAD - don't use enum values from the object in the runtime (having a type import enforces this)
119+
this.design !== ButtonDesign.Transparent
120+
121+
// GOOD - use strings (IDE will autocomplete, TS will force the enum correctness, no runtime overhead from enum)
122+
this.design !== "Transparent";
123+
```
124+
125+
### Scoping-Safe Code (Required for Micro-Frontend Support)
126+
```typescript
127+
// BAD - hard-coded tag names break scoping
128+
this.shadowRoot.querySelector("ui5-popover")
129+
ui5-button.accept-btn { color: green; }
130+
131+
// GOOD - use attribute notation
132+
this.shadowRoot.querySelector("[ui5-popover]")
133+
[ui5-button].accept-btn { color: green; }
134+
```
135+
136+
### No instanceof Checks, no direct `.tagName` comparison
137+
```typescript
138+
// BAD - fails with multiple framework versions
139+
if (element instanceof Button) { }
140+
141+
// BAD - the tag name could be scoped like `UI5-BUTTON-F5331039` and won't match
142+
if (element.tagName === "UI5-BUTTON") { }
143+
144+
// GOOD - use the `hasTag` helper that checks the pure tag
145+
// use instance check like
146+
const isInstanceOfComboBoxItemGroup = (object: any): object is ComboBoxItemGroup => {
147+
return "isGroupItem" in object;
148+
};
149+
```
150+
151+
### Property/Event Conventions
152+
- Never change public properties without user interaction
153+
- Set `noAttribute: true` for private properties not used in CSS
154+
- Fire events upon every user interaction to notify applications
155+
- Import all icons explicitly (test bundle imports all, but real apps don't)
156+
157+
## Testing with Cypress
158+
159+
Tests use component testing with JSX mounting:
160+
161+
```typescript
162+
import Button from "../../src/Button.js";
163+
164+
describe("Button", () => {
165+
it("tests click event", () => {
166+
cy.mount(<Button>Click me</Button>);
167+
168+
cy.get("[ui5-button]").then(($btn) => {
169+
cy.spy($btn[0], "click").as("clicked");
170+
});
171+
172+
cy.get("[ui5-button]").realClick(); // Use realClick, not click
173+
cy.get("@clicked").should("have.been.called");
174+
});
175+
});
176+
```
177+
178+
**Key testing patterns:**
179+
- Use `cypress-real-events`: `realClick()`, `realPress()`, `realType()` instead of simulated events
180+
- Use `cy.ui5SimulateDevice("phone")` for mobile testing
181+
- For language testing: `cy.wrap({ setLanguage }).invoke("setLanguage", "bg")` (must await)
182+
- Import `Assets.js` when testing with non-default languages
183+
184+
**Running single test case from a test file**
185+
When fixing a failing test, check the fix by running just the failing test case instead of all tests in the file.
186+
187+
Example of failing test case:
188+
```tsx
189+
it("should set correct tooltip to right text button", () => {
190+
```
191+
192+
Use `.only` to verify the fix faster
193+
```tsx
194+
it.only("should set correct tooltip to right text button", () => {
195+
```
196+
197+
Do this for each failing test case, remove `.only` when all cases are fixed and run the full test file or suite for final verification
198+
199+
## Commit Message Format
200+
201+
Follow [Conventional Commits](https://conventionalcommits.org):
202+
203+
```
204+
<type>(<scope>): <description>
205+
206+
[body]
207+
208+
[footer]
209+
```
210+
211+
**Types:** `fix`, `feat`, `docs`, `style`, `refactor`, `perf`, `test`, `chore`, `revert`
212+
**Scope:** Component name (e.g., `ui5-button`, `ui5-table`)
213+
**Description:** Imperative present tense, max 100 chars, no period
214+
215+
Example:
216+
```
217+
fix(ui5-button): correct focus with 'tab' key
218+
219+
The button should receive a correct focus outline
220+
when the 'tab' key is pressed.
221+
222+
Fixes #42
223+
```

0 commit comments

Comments
 (0)