@groupby/ai-dev 0.5.13 → 0.5.15
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/package.json +1 -1
- package/teams/brain-studio/skills/arch-context/SKILL.md +135 -0
- package/teams/brain-studio/skills/draft-plan/SKILL.md +222 -0
- package/teams/brain-studio/skills/draft-pr/SKILL.md +291 -0
- package/teams/brain-studio/skills/git-context/SKILL.md +159 -0
- package/teams/brain-studio/skills/html/SKILL.md +233 -0
- package/teams/brain-studio/skills/javascript/SKILL.md +680 -0
- package/teams/brain-studio/skills/jira-context/SKILL.md +113 -0
- package/teams/brain-studio/skills/jira-spec/SKILL.md +247 -0
- package/teams/brain-studio/skills/pr-review/SKILL.md +310 -0
- package/teams/brain-studio/skills/react/SKILL.md +282 -0
- package/teams/brain-studio/skills/styled-components/SKILL.md +336 -0
- package/teams/brain-studio/skills/tdd-implement/SKILL.md +278 -0
- package/teams/brain-studio/skills/typescript/SKILL.md +491 -0
- package/teams/fhr-andromeda/github/PULL_REQUEST_TEMPLATE.md +51 -0
- package/teams/fhr-andromeda/github/copilot-instructions.md +47 -0
- package/teams/fhr-andromeda/instructions/CLAUDE.md +66 -0
- package/teams/fhr-andromeda/instructions/ai-instructions.md +312 -0
- package/teams/fhr-andromeda/instructions/architecture.md +181 -0
- package/teams/fhr-andromeda/instructions/code-review.md +127 -0
- package/teams/fhr-andromeda/instructions/coding-guidelines.md +139 -0
- package/teams/fhr-andromeda/instructions/domain.md +125 -0
- package/teams/fhr-andromeda/instructions/jira-ticket-template.md +55 -0
- package/teams/fhr-andromeda/instructions/modules/data-quality-frontend.md +57 -0
- package/teams/fhr-andromeda/instructions/modules/data-quality.md +62 -0
- package/teams/fhr-andromeda/instructions/modules/fhr-custom-transforms.md +59 -0
- package/teams/fhr-andromeda/instructions/modules/hop-dev-platform-frontend.md +60 -0
- package/teams/fhr-andromeda/instructions/modules/hop-dev-platform.md +62 -0
- package/teams/fhr-andromeda/instructions/modules/workflow-scripts.md +119 -0
- package/teams/fhr-andromeda/skills/fhr-pr/SKILL.md +71 -0
- package/teams/fhr-andromeda/skills/fhr-review/SKILL.md +78 -0
- package/teams/fhr-andromeda/skills/fhr-spec/SKILL.md +96 -0
|
@@ -0,0 +1,282 @@
|
|
|
1
|
+
---
|
|
2
|
+
name: react
|
|
3
|
+
description: >-
|
|
4
|
+
Provides project-specific React and JSX authoring rules for Command Center — function declarations
|
|
5
|
+
with explicit JSX.Element return types, no React.FC, no container/presenter split, PascalCase
|
|
6
|
+
component file naming, camelCase hook naming, styled-components (never CSS modules or Tailwind),
|
|
7
|
+
@/ path aliases, FormatJS i18n via useLocalization, logError error handling, and
|
|
8
|
+
useAppSelector/useAppDispatch from @/store/hooks. Auto-apply when creating, editing, reviewing,
|
|
9
|
+
or refactoring React components, hooks, or .tsx files in this repository.
|
|
10
|
+
---
|
|
11
|
+
|
|
12
|
+
# React Guide
|
|
13
|
+
|
|
14
|
+
## Relationship to other repository skills
|
|
15
|
+
|
|
16
|
+
- `javascript` skill — governs all JS-layer rules; read first for every `.tsx` file
|
|
17
|
+
- `typescript` skill — governs TS-layer rules; read second for every `.tsx` file
|
|
18
|
+
- `html` skill — governs accessible markup behaviour in JSX (roles, labels, keyboard)
|
|
19
|
+
- `styled-components` skill — styled-components authoring rules for this project (colors, spacing, naming, transient props, overrides); read it for any styling work
|
|
20
|
+
|
|
21
|
+
This skill does not replace javascript or typescript. It adds the React/JSX layer and all
|
|
22
|
+
project-specific conventions that override or extend generic guidance.
|
|
23
|
+
|
|
24
|
+
## Mandatory application (agents)
|
|
25
|
+
|
|
26
|
+
Whenever the task involves React source — including `.tsx` files, custom hooks, component APIs, or
|
|
27
|
+
Redux-connected components in this repository:
|
|
28
|
+
|
|
29
|
+
1. **Read `javascript` skill first.**
|
|
30
|
+
2. **Read `typescript` skill second** for any `.tsx` file.
|
|
31
|
+
3. **Read this file third** for React/JSX decisions and project-specific rules.
|
|
32
|
+
4. For a11y-heavy JSX, read `html` skill for label, button, and keyboard guidance.
|
|
33
|
+
|
|
34
|
+
For strictly non-React files (`.ts` with no JSX, CSS-only, or plain HTML), this skill is optional.
|
|
35
|
+
|
|
36
|
+
## When to use
|
|
37
|
+
|
|
38
|
+
- Creating, editing, or reviewing React component `.tsx` files
|
|
39
|
+
- Creating, editing, or reviewing custom hook `.ts` files
|
|
40
|
+
- Questions about component structure, data-fetching pattern, or styling in this repo
|
|
41
|
+
- File naming, import ordering, i18n, error handling, or state-access decisions in React code
|
|
42
|
+
|
|
43
|
+
## When not to use
|
|
44
|
+
|
|
45
|
+
- Pure `.ts` modules with no JSX → typescript skill
|
|
46
|
+
- Styling-only work in `.styles.ts` files with no component logic changes → styled-components skill
|
|
47
|
+
- Static `.html` files without React → html skill
|
|
48
|
+
|
|
49
|
+
## Truthfulness and claims
|
|
50
|
+
|
|
51
|
+
- Do not invent project file conventions — always defer to `docs/architecture/12-code-conventions/` (if present)
|
|
52
|
+
- Do not recommend CSS Modules, Tailwind, or other CSS-in-JS alternatives — this project uses
|
|
53
|
+
styled-components exclusively
|
|
54
|
+
- Do not recommend `React.FC`, `.container.tsx`, `.component.tsx`, or `use-x.hook.ts` suffixes —
|
|
55
|
+
these are legacy patterns; do not introduce them
|
|
56
|
+
|
|
57
|
+
## Self-contained operating mode
|
|
58
|
+
|
|
59
|
+
- Use the embedded standard below and `docs/architecture/` (if present) as the sole authorities for project
|
|
60
|
+
decisions
|
|
61
|
+
- Do not fetch external React documentation for routine decisions; apply the react.dev mental model
|
|
62
|
+
embedded here
|
|
63
|
+
- When `docs/architecture/` and generic React best-practice conflict, `docs/architecture/` wins
|
|
64
|
+
- When project config (ESLint, `tsconfig.json`) and this skill conflict, project config wins; flag
|
|
65
|
+
the discrepancy rather than silently breaking the config
|
|
66
|
+
|
|
67
|
+
---
|
|
68
|
+
|
|
69
|
+
## Embedded implementation standard
|
|
70
|
+
|
|
71
|
+
### 1) Component declaration
|
|
72
|
+
|
|
73
|
+
- Use **function declarations** with an explicit `: JSX.Element` return type
|
|
74
|
+
- Do **not** use arrow functions assigned to `const`, do **not** use `React.FC`
|
|
75
|
+
- Guild standard — refactor `React.FC` patterns when touching existing files; do not introduce new ones
|
|
76
|
+
|
|
77
|
+
```tsx
|
|
78
|
+
// ✅ Correct — function declaration, explicit return type
|
|
79
|
+
function RuleTable({ rules, onDelete }: RuleTableProps): JSX.Element {
|
|
80
|
+
return <StyledRuleTable>...</StyledRuleTable>;
|
|
81
|
+
}
|
|
82
|
+
|
|
83
|
+
// ❌ Legacy — do not introduce
|
|
84
|
+
const RuleTable: React.FC<RuleTableProps> = ({ rules, onDelete }) => { /* ... */ };
|
|
85
|
+
```
|
|
86
|
+
|
|
87
|
+
### 2) Component structure
|
|
88
|
+
|
|
89
|
+
- **No container/presenter split.** Do not create new `.container.tsx` or `.component.tsx` files.
|
|
90
|
+
- Extract business logic into custom hooks
|
|
91
|
+
- Use utility modules for pure data transformation
|
|
92
|
+
- Assemble via composition; keep the render tree flat and explicit
|
|
93
|
+
- **Props.** Define with `interface Props { ... }` co-located in the component file. Extract to
|
|
94
|
+
`<entity>.model.ts` only when the type is shared across files.
|
|
95
|
+
|
|
96
|
+
```tsx
|
|
97
|
+
interface RuleTableProps {
|
|
98
|
+
rules: Rule[];
|
|
99
|
+
onDelete: (id: ModelId) => void;
|
|
100
|
+
}
|
|
101
|
+
```
|
|
102
|
+
|
|
103
|
+
### 3) File and folder naming
|
|
104
|
+
|
|
105
|
+
| File type | Convention | Example |
|
|
106
|
+
|---|---|---|
|
|
107
|
+
| React component | `PascalCase.tsx` | `RuleTable.tsx` |
|
|
108
|
+
| Custom hook | `camelCase.ts` | `useConversionRateChartOptions.ts` |
|
|
109
|
+
| Styled-components | `<entity>.styles.ts` | `rule-table.styles.ts` |
|
|
110
|
+
| Model types | `<entity>.model.ts` | `rule.model.ts` |
|
|
111
|
+
| Constants | `<entity>.constants.ts` | `filter-set-form.constants.ts` |
|
|
112
|
+
| Context | `<name>.context.tsx` | `rule-form.context.tsx` |
|
|
113
|
+
|
|
114
|
+
Legacy files use kebab-case with role suffixes (`.container.tsx`, `.component.tsx`,
|
|
115
|
+
`use-x.hook.ts`). Rename to the conventions above when touching these files.
|
|
116
|
+
|
|
117
|
+
### 4) Custom hooks
|
|
118
|
+
|
|
119
|
+
- Name in `camelCase` without a `.hook.ts` suffix: `useRuleList.ts`, `useAbortRequest.ts`
|
|
120
|
+
- Place in a `hooks/` subdirectory within the feature module, or `src/hooks/` for shared hooks
|
|
121
|
+
- Always return a cleanup function from `useEffect` when registering subscriptions, timers, or
|
|
122
|
+
abort controllers:
|
|
123
|
+
|
|
124
|
+
```tsx
|
|
125
|
+
useEffect(() => {
|
|
126
|
+
const controller = new AbortController();
|
|
127
|
+
|
|
128
|
+
fetchData(controller.signal);
|
|
129
|
+
|
|
130
|
+
return () => {
|
|
131
|
+
controller.abort();
|
|
132
|
+
};
|
|
133
|
+
}, []);
|
|
134
|
+
```
|
|
135
|
+
|
|
136
|
+
- Add `useCallback`/`useMemo`/`memo` only when measured or when stabilising reference identity is
|
|
137
|
+
required for dependency arrays — avoid premature memoisation
|
|
138
|
+
|
|
139
|
+
### 5) Import style
|
|
140
|
+
|
|
141
|
+
- Use `@/` path aliases for all cross-module imports — never use deep relative paths (`../../../../`)
|
|
142
|
+
- Relative imports within the same module (`./rule-table`) are fine
|
|
143
|
+
- **Import order:** React → third-party → `@/` → `./`
|
|
144
|
+
- Named imports only; never import an entire library as a namespace
|
|
145
|
+
|
|
146
|
+
```ts
|
|
147
|
+
// ✅ Correct
|
|
148
|
+
import React, { useCallback } from 'react';
|
|
149
|
+
import { isEmpty } from 'ramda';
|
|
150
|
+
import { useLocalization } from '@/localization';
|
|
151
|
+
import { logError } from '@/utils/logger';
|
|
152
|
+
import { RuleTableRow } from './RuleTableRow';
|
|
153
|
+
|
|
154
|
+
// ❌ Avoid
|
|
155
|
+
import * as R from 'ramda';
|
|
156
|
+
import { useLocalization } from '../../../../localization';
|
|
157
|
+
```
|
|
158
|
+
|
|
159
|
+
### 6) Styling with styled-components
|
|
160
|
+
|
|
161
|
+
This project uses **styled-components exclusively**. For the full styling standard, read
|
|
162
|
+
`styled-components` skill. Key rules in brief:
|
|
163
|
+
|
|
164
|
+
- Styled components live in a co-located **`.styles.ts`** file — never inline in the component file
|
|
165
|
+
- Named exports use **PascalCase without a `Styled` prefix**: `Container`, `TableBodyContainer`
|
|
166
|
+
- Colors from `baseColors` (`@groupby/ui-components`); spacing from `theme.spacing(N)` — never
|
|
167
|
+
hard-coded hex or `px` values
|
|
168
|
+
- Styling-only props use the `$` prefix to prevent DOM forwarding
|
|
169
|
+
- **Never `!important`** — use `&&` or child selectors for MUI overrides
|
|
170
|
+
|
|
171
|
+
```ts
|
|
172
|
+
import styled from 'styled-components';
|
|
173
|
+
import { baseColors } from '@groupby/ui-components';
|
|
174
|
+
|
|
175
|
+
// ✅ Correct
|
|
176
|
+
export const Container = styled.div`
|
|
177
|
+
background-color: ${baseColors.background000};
|
|
178
|
+
padding: ${({ theme }) => theme.spacing(2)};
|
|
179
|
+
`;
|
|
180
|
+
|
|
181
|
+
export const TableBody = styled(MuiTableBody)<{ $loading: boolean }>`
|
|
182
|
+
${({ $loading }) => $loading && `opacity: 0.5;`}
|
|
183
|
+
`;
|
|
184
|
+
|
|
185
|
+
// ❌ Legacy — do not introduce
|
|
186
|
+
export const StyledContainer = styled.div`...`;
|
|
187
|
+
```
|
|
188
|
+
|
|
189
|
+
### 7) Internationalization (i18n)
|
|
190
|
+
|
|
191
|
+
All user-facing strings **must** use FormatJS. Never hard-code English (or any language) text in JSX.
|
|
192
|
+
|
|
193
|
+
```tsx
|
|
194
|
+
import { useLocalization } from '@/localization';
|
|
195
|
+
|
|
196
|
+
function MyComponent(): JSX.Element {
|
|
197
|
+
const { formatMessage: t } = useLocalization();
|
|
198
|
+
|
|
199
|
+
return <div>{t({ key: 'SOME_MESSAGE_KEY' })}</div>;
|
|
200
|
+
}
|
|
201
|
+
```
|
|
202
|
+
|
|
203
|
+
After adding a new message key, run:
|
|
204
|
+
|
|
205
|
+
```bash
|
|
206
|
+
yarn messages:extract-and-compile
|
|
207
|
+
```
|
|
208
|
+
|
|
209
|
+
### 8) State management
|
|
210
|
+
|
|
211
|
+
Use typed hooks from `@/store/hooks` — never bare `react-redux` imports:
|
|
212
|
+
|
|
213
|
+
```ts
|
|
214
|
+
import { useAppSelector, useAppDispatch } from '@/store/hooks'; // ✅
|
|
215
|
+
import { useSelector, useDispatch } from 'react-redux'; // ❌
|
|
216
|
+
```
|
|
217
|
+
|
|
218
|
+
Access API data through **platform-services hooks** from `@/platform-services/<feature>` — never
|
|
219
|
+
import RTK Query hooks from `@/store/api` directly in components or containers:
|
|
220
|
+
|
|
221
|
+
```tsx
|
|
222
|
+
import { useGetRuleList } from '@/platform-services/rules'; // ✅
|
|
223
|
+
import { useGetRuleListQuery } from '@/store/api/cc/ruleApi'; // ❌
|
|
224
|
+
```
|
|
225
|
+
|
|
226
|
+
### 9) Error handling
|
|
227
|
+
|
|
228
|
+
- Always use `logError` from `@/utils/logger` — never call Sentry directly
|
|
229
|
+
- Use `isRequestAborted` from `@/client/utils` to distinguish intentional cancellations from errors;
|
|
230
|
+
skip error dispatch for aborted requests
|
|
231
|
+
- Never log tokens, passwords, PII, or values from `window.__APP_CONFIG__`
|
|
232
|
+
|
|
233
|
+
```ts
|
|
234
|
+
import { logError } from '@/utils/logger';
|
|
235
|
+
import { isRequestAborted } from '@/client/utils';
|
|
236
|
+
|
|
237
|
+
try {
|
|
238
|
+
await updateRule(token, ruleData);
|
|
239
|
+
|
|
240
|
+
dispatch(addSuccess({ key: 'RULE_UPDATE_SUCCESS' }));
|
|
241
|
+
} catch (error) {
|
|
242
|
+
if (!isRequestAborted(error)) {
|
|
243
|
+
logError('RULE_UPDATE_ERROR', error);
|
|
244
|
+
dispatch(addError({ key: 'RULE_UPDATE_ERROR' }));
|
|
245
|
+
}
|
|
246
|
+
}
|
|
247
|
+
```
|
|
248
|
+
|
|
249
|
+
### 10) Keys, lists, and general React rules
|
|
250
|
+
|
|
251
|
+
- **Keys on lists** must be stable among siblings — prefer opaque IDs from data; never use array
|
|
252
|
+
index when order or filtering can change identity
|
|
253
|
+
- **Rules of Hooks**: call hooks only at the top level of React functions or custom hooks — never
|
|
254
|
+
inside loops, conditions, or nested functions
|
|
255
|
+
- **One obvious owner** for shared state; prefer lifting state or composition over ad-hoc context
|
|
256
|
+
- **Event handlers**: prefix with `handle*` (`handleClick`, `handleKeyDown`)
|
|
257
|
+
|
|
258
|
+
---
|
|
259
|
+
|
|
260
|
+
## Working method (apply in this order)
|
|
261
|
+
|
|
262
|
+
1. **Confirm file type** — `.tsx` component, `.tsx` hook, or `.ts` utility?
|
|
263
|
+
2. **Read skills in order**: javascript → typescript → this file.
|
|
264
|
+
3. **Check component declaration**: function declaration with explicit `: JSX.Element`; no `React.FC`; no `.container.tsx` or `.component.tsx` files.
|
|
265
|
+
4. **Apply file naming**: `PascalCase.tsx` for components, `camelCase.ts` for hooks; extract styled-components to `.styles.ts`.
|
|
266
|
+
5. **Apply import order**: React → third-party → `@/` → `./`; use `@/` for all cross-module paths.
|
|
267
|
+
6. **Replace hard-coded strings** with `useLocalization` calls; run `yarn messages:extract-and-compile` if new keys were added.
|
|
268
|
+
7. **Verify state access**: `useAppSelector`/`useAppDispatch` from `@/store/hooks`; API data from `@/platform-services/<feature>` hooks only.
|
|
269
|
+
8. **Verify error handling**: errors go through `logError`; aborted requests filtered via `isRequestAborted`.
|
|
270
|
+
|
|
271
|
+
## Quality bar before final answer
|
|
272
|
+
|
|
273
|
+
- All new component functions use `function Foo(props: FooProps): JSX.Element` — no arrow functions, no `React.FC`.
|
|
274
|
+
- No `.container.tsx`, `.component.tsx`, or `use-x.hook.ts` file names introduced.
|
|
275
|
+
- Styled-components are in a co-located `.styles.ts` file with `PascalCase` names and no `Styled` prefix.
|
|
276
|
+
- No `!important` in styled-components.
|
|
277
|
+
- All user-visible strings go through `useLocalization`; no hard-coded English text in JSX.
|
|
278
|
+
- All Redux state access uses `useAppSelector`/`useAppDispatch` from `@/store/hooks`.
|
|
279
|
+
- All API data access uses platform-services hooks from `@/platform-services/<feature>`.
|
|
280
|
+
- Errors handled via `logError`; aborted requests filtered with `isRequestAborted`.
|
|
281
|
+
- Import order is React → third-party → `@/` → `./`; no deep relative paths for cross-module imports.
|
|
282
|
+
- Props typed as `interface FooProps { ... }`, co-located in the component file.
|
|
@@ -0,0 +1,336 @@
|
|
|
1
|
+
---
|
|
2
|
+
name: styled-components
|
|
3
|
+
description: >-
|
|
4
|
+
Provides project-specific styled-components authoring rules for Command Center — PascalCase named
|
|
5
|
+
exports (no Styled prefix), co-located .styles.ts files, baseColors from @groupby/ui-components
|
|
6
|
+
for colors, MUI theme.spacing() for spacing, $ transient props, no !important (use specificity
|
|
7
|
+
or && instead), and CSS fundamentals (layout, specificity, inheritance) as applied through the
|
|
8
|
+
styled-components API. Replaces the generic CSS skill for this repository — do not author plain
|
|
9
|
+
.css files or use CSS Modules/Tailwind. Auto-apply when creating, editing, reviewing, or
|
|
10
|
+
refactoring styled-components in any .styles.ts/.styles.tsx file, or when CSS-in-JS or styling
|
|
11
|
+
questions arise in this repository.
|
|
12
|
+
---
|
|
13
|
+
|
|
14
|
+
# Styled-Components Guide
|
|
15
|
+
|
|
16
|
+
## Relationship to other repository skills
|
|
17
|
+
|
|
18
|
+
- the react skill — governs component declaration, file naming, and the rule that
|
|
19
|
+
styled-components live in a co-located `.styles.ts` file; read it for component-level context
|
|
20
|
+
- the typescript skill — governs TS types for styled-component prop shapes
|
|
21
|
+
- the javascript skill — governs JS-layer formatting rules that apply to template
|
|
22
|
+
literals inside styled-components
|
|
23
|
+
|
|
24
|
+
This skill does not replace react or typescript. It covers styling only.
|
|
25
|
+
|
|
26
|
+
## Mandatory application (agents)
|
|
27
|
+
|
|
28
|
+
Whenever the task involves styling in this repository — including `.styles.ts`, `.styles.tsx` files,
|
|
29
|
+
or any `styled(...)` / `styled.div` call:
|
|
30
|
+
|
|
31
|
+
1. **Read this file** for all styling decisions.
|
|
32
|
+
2. **Read the react skill** for component-level placement rules (`.styles.ts`
|
|
33
|
+
co-location, naming conventions).
|
|
34
|
+
3. **Do not** introduce plain `.css` files, CSS Modules, or Tailwind in this project.
|
|
35
|
+
|
|
36
|
+
For a11y-aware styling (focus rings, contrast, reduced-motion), cross-read
|
|
37
|
+
the html skill.
|
|
38
|
+
|
|
39
|
+
## When to use
|
|
40
|
+
|
|
41
|
+
- Creating or editing `.styles.ts` / `.styles.tsx` files
|
|
42
|
+
- Adding `styled.div`, `styled(Component)`, or `css` helper calls anywhere in the codebase
|
|
43
|
+
- Questions about colors, spacing, layout, specificity, or theming in this repo
|
|
44
|
+
- Debugging styled-components output (generated class names, MUI theme, prop forwarding)
|
|
45
|
+
|
|
46
|
+
## When not to use
|
|
47
|
+
|
|
48
|
+
- Component logic with no styling changes → react skill
|
|
49
|
+
- TypeScript prop-shape questions with no CSS involvement → typescript skill
|
|
50
|
+
|
|
51
|
+
## Truthfulness and claims
|
|
52
|
+
|
|
53
|
+
- Do not recommend plain `.css` files, CSS Modules, or Tailwind — this project uses
|
|
54
|
+
styled-components exclusively
|
|
55
|
+
- Do not recommend hard-coded hex values or pixel sizes — all colors must come from `baseColors`,
|
|
56
|
+
all spacing from `theme.spacing()`
|
|
57
|
+
- Do not invent browser support percentages or claim one global "most popular" CSS approach
|
|
58
|
+
- For uncertain edge behaviour in CSS properties, flag for verification in browser devtools rather
|
|
59
|
+
than guessing
|
|
60
|
+
|
|
61
|
+
## Self-contained operating mode
|
|
62
|
+
|
|
63
|
+
- Use the embedded standard below and `docs/architecture/12-code-conventions/` as the sole
|
|
64
|
+
authorities for project styling decisions
|
|
65
|
+
- Do not fetch external styled-components documentation for routine decisions
|
|
66
|
+
- When `docs/architecture/` and generic styled-components best-practice conflict,
|
|
67
|
+
`docs/architecture/` wins
|
|
68
|
+
- When project tooling conflicts with this skill, project tooling wins; flag the discrepancy
|
|
69
|
+
|
|
70
|
+
---
|
|
71
|
+
|
|
72
|
+
## Embedded implementation standard
|
|
73
|
+
|
|
74
|
+
### 1) File placement and structure
|
|
75
|
+
|
|
76
|
+
- Styled components live in a **co-located `.styles.ts`** file — never inline in the component file
|
|
77
|
+
- Use `.styles.tsx` only when the `css` helper contains JSX
|
|
78
|
+
- Never put styled-component definitions inside `*.tsx` component files
|
|
79
|
+
|
|
80
|
+
```
|
|
81
|
+
RuleTable.tsx ← component logic only
|
|
82
|
+
rule-table.styles.ts ← all styled-components for RuleTable
|
|
83
|
+
```
|
|
84
|
+
|
|
85
|
+
### 2) Naming
|
|
86
|
+
|
|
87
|
+
- Named exports use **PascalCase without a `Styled` prefix**: `Container`, `TableBodyContainer`,
|
|
88
|
+
`RuleFormContainer`
|
|
89
|
+
- Do **not** introduce new `StyledXxx` names
|
|
90
|
+
- When refactoring existing `StyledXxx` names, remove the prefix
|
|
91
|
+
|
|
92
|
+
```ts
|
|
93
|
+
// ✅ Correct
|
|
94
|
+
export const Container = styled.div`...`;
|
|
95
|
+
export const TableBodyContainer = styled.div`...`;
|
|
96
|
+
|
|
97
|
+
// ❌ Legacy — do not introduce
|
|
98
|
+
export const StyledContainer = styled.div`...`;
|
|
99
|
+
```
|
|
100
|
+
|
|
101
|
+
### 3) Colors
|
|
102
|
+
|
|
103
|
+
- Always use **`baseColors`** from `@groupby/ui-components` — never hard-code hex values, `rgb()`,
|
|
104
|
+
or `hsl()` literals
|
|
105
|
+
- `baseColors` maps to the GroupBy design system; using it directly means theme changes propagate
|
|
106
|
+
automatically
|
|
107
|
+
|
|
108
|
+
```ts
|
|
109
|
+
import { baseColors } from '@groupby/ui-components';
|
|
110
|
+
|
|
111
|
+
// ✅ Correct
|
|
112
|
+
export const Container = styled.div`
|
|
113
|
+
background-color: ${baseColors.background000};
|
|
114
|
+
color: ${baseColors.midnight800};
|
|
115
|
+
border: 1px solid ${baseColors.midnight200};
|
|
116
|
+
`;
|
|
117
|
+
|
|
118
|
+
// ❌ Banned
|
|
119
|
+
export const Container = styled.div`
|
|
120
|
+
background-color: #fff;
|
|
121
|
+
color: #1a2332;
|
|
122
|
+
`;
|
|
123
|
+
```
|
|
124
|
+
|
|
125
|
+
### 4) Spacing
|
|
126
|
+
|
|
127
|
+
- Use the **MUI theme** for spacing — never hard-code pixel sizes that should track the design
|
|
128
|
+
system
|
|
129
|
+
- Access via the `theme` prop callback: `${({ theme }) => theme.spacing(N)}`
|
|
130
|
+
|
|
131
|
+
```ts
|
|
132
|
+
// ✅ Correct — spacing from theme
|
|
133
|
+
export const Card = styled.div`
|
|
134
|
+
padding: ${({ theme }) => theme.spacing(2)};
|
|
135
|
+
margin-bottom: ${({ theme }) => theme.spacing(1)};
|
|
136
|
+
`;
|
|
137
|
+
|
|
138
|
+
// ❌ Banned — hard-coded spacing
|
|
139
|
+
export const Card = styled.div`
|
|
140
|
+
padding: 16px;
|
|
141
|
+
margin-bottom: 8px;
|
|
142
|
+
`;
|
|
143
|
+
```
|
|
144
|
+
|
|
145
|
+
**Exceptions:** pixel values are acceptable for border widths (`1px`), border-radius where no theme
|
|
146
|
+
token exists, and `0`.
|
|
147
|
+
|
|
148
|
+
### 5) Transient props
|
|
149
|
+
|
|
150
|
+
- Use the **`$` prefix** for props that control styling but must **not** be forwarded to the DOM
|
|
151
|
+
element
|
|
152
|
+
- Prevents React DOM prop warnings for boolean and custom props
|
|
153
|
+
|
|
154
|
+
```ts
|
|
155
|
+
// ✅ Correct — $ prefix keeps $loading off the DOM
|
|
156
|
+
export const TableBody = styled(MuiTableBody)<{ $loading: boolean }>`
|
|
157
|
+
${({ $loading }) => $loading && `opacity: 0.5;`}
|
|
158
|
+
`;
|
|
159
|
+
|
|
160
|
+
// ❌ Will cause React DOM warning — remove $ prefix
|
|
161
|
+
export const TableBody = styled(MuiTableBody)<{ loading: boolean }>`
|
|
162
|
+
${({ loading }) => loading && `opacity: 0.5;`}
|
|
163
|
+
`;
|
|
164
|
+
```
|
|
165
|
+
|
|
166
|
+
### 6) Overriding MUI components
|
|
167
|
+
|
|
168
|
+
When styling a MUI component with styled-components, MUI's internal specificity can conflict. Resolve
|
|
169
|
+
in this order of preference:
|
|
170
|
+
|
|
171
|
+
1. **Target the MUI class directly** — use the component's stable `Mui*-root` / `Mui*-*` class
|
|
172
|
+
names as child selectors when you need to reach internal elements:
|
|
173
|
+
|
|
174
|
+
```ts
|
|
175
|
+
export const CustomTextField = styled(TextField)`
|
|
176
|
+
.MuiInputBase-root {
|
|
177
|
+
border-radius: 8px;
|
|
178
|
+
}
|
|
179
|
+
`;
|
|
180
|
+
```
|
|
181
|
+
|
|
182
|
+
2. **Double-ampersand specificity boost** — when the above is not enough, `&&` doubles the
|
|
183
|
+
generated class, beating MUI's specificity without `!important`:
|
|
184
|
+
|
|
185
|
+
```ts
|
|
186
|
+
export const CustomInput = styled(Input)`
|
|
187
|
+
&& {
|
|
188
|
+
flex: none;
|
|
189
|
+
}
|
|
190
|
+
`;
|
|
191
|
+
```
|
|
192
|
+
|
|
193
|
+
3. **Refactor the layout** — if you are reaching for overrides at all, the real issue is usually in
|
|
194
|
+
the container structure.
|
|
195
|
+
|
|
196
|
+
### 7) No `!important`
|
|
197
|
+
|
|
198
|
+
**Never use `!important`** in styled-components or anywhere in this codebase.
|
|
199
|
+
|
|
200
|
+
`!important` breaks specificity predictability, creates competing overrides, and makes styles brittle
|
|
201
|
+
during refactoring.
|
|
202
|
+
|
|
203
|
+
```ts
|
|
204
|
+
// ❌ Banned
|
|
205
|
+
export const CustomInput = styled(Input)`
|
|
206
|
+
flex: 0 1 500px !important;
|
|
207
|
+
`;
|
|
208
|
+
|
|
209
|
+
// ✅ Use && specificity boost instead
|
|
210
|
+
export const CustomInput = styled(Input)`
|
|
211
|
+
&& {
|
|
212
|
+
flex: none;
|
|
213
|
+
}
|
|
214
|
+
`;
|
|
215
|
+
```
|
|
216
|
+
|
|
217
|
+
### 8) Conditional and dynamic styles
|
|
218
|
+
|
|
219
|
+
Two patterns — choose the one that reads most clearly:
|
|
220
|
+
|
|
221
|
+
```ts
|
|
222
|
+
// Inline ternary — for single-property conditions
|
|
223
|
+
export const Badge = styled.span<{ $active: boolean }>`
|
|
224
|
+
background-color: ${({ $active }) => $active ? baseColors.green500 : baseColors.midnight200};
|
|
225
|
+
`;
|
|
226
|
+
|
|
227
|
+
// css helper — for multi-property conditions (import from styled-components)
|
|
228
|
+
import styled, { css } from 'styled-components';
|
|
229
|
+
|
|
230
|
+
export const Row = styled.div<{ $selected: boolean }>`
|
|
231
|
+
padding: ${({ theme }) => theme.spacing(1)};
|
|
232
|
+
|
|
233
|
+
${({ $selected }) =>
|
|
234
|
+
$selected &&
|
|
235
|
+
css`
|
|
236
|
+
background-color: ${baseColors.primary100};
|
|
237
|
+
font-weight: 600;
|
|
238
|
+
`}
|
|
239
|
+
`;
|
|
240
|
+
```
|
|
241
|
+
|
|
242
|
+
### 9) Extending components
|
|
243
|
+
|
|
244
|
+
- Use `styled(Component)` to extend an existing styled-component or MUI component
|
|
245
|
+
- Prefer extension over copy-pasting styles
|
|
246
|
+
|
|
247
|
+
```ts
|
|
248
|
+
// ✅ Extending an existing component
|
|
249
|
+
export const PrimaryButton = styled(Button)`
|
|
250
|
+
background-color: ${baseColors.primary500};
|
|
251
|
+
`;
|
|
252
|
+
|
|
253
|
+
// ✅ Extending another styled-component from the same file
|
|
254
|
+
export const LargeContainer = styled(Container)`
|
|
255
|
+
padding: ${({ theme }) => theme.spacing(4)};
|
|
256
|
+
`;
|
|
257
|
+
```
|
|
258
|
+
|
|
259
|
+
### 10) CSS layout fundamentals inside template literals
|
|
260
|
+
|
|
261
|
+
Standard CSS layout rules apply verbatim inside styled-components template literals.
|
|
262
|
+
|
|
263
|
+
**Flexbox (one axis):**
|
|
264
|
+
|
|
265
|
+
```ts
|
|
266
|
+
export const Toolbar = styled.div`
|
|
267
|
+
display: flex;
|
|
268
|
+
align-items: center;
|
|
269
|
+
gap: ${({ theme }) => theme.spacing(1)};
|
|
270
|
+
`;
|
|
271
|
+
```
|
|
272
|
+
|
|
273
|
+
**Grid (two axes):**
|
|
274
|
+
|
|
275
|
+
```ts
|
|
276
|
+
export const DashboardGrid = styled.div`
|
|
277
|
+
display: grid;
|
|
278
|
+
grid-template-columns: repeat(auto-fill, minmax(240px, 1fr));
|
|
279
|
+
gap: ${({ theme }) => theme.spacing(2)};
|
|
280
|
+
`;
|
|
281
|
+
```
|
|
282
|
+
|
|
283
|
+
- Prefer **`gap`** over margins between flex/grid children
|
|
284
|
+
- Use **`min-width: 0`** on flex/grid children that must shrink and clip text correctly
|
|
285
|
+
- No negative margins — use `gap`, `padding`, or layout structure instead
|
|
286
|
+
|
|
287
|
+
### 11) Specificity and cascade
|
|
288
|
+
|
|
289
|
+
- Each styled-component generates a **single unique class** — specificity is always one class
|
|
290
|
+
(0-1-0). There are no selector chains unless you write them explicitly.
|
|
291
|
+
- Nested selectors (e.g. `.MuiInputBase-root`) add a class-level specificity increment for each
|
|
292
|
+
class token in the chain — keep nesting intentional and minimal.
|
|
293
|
+
- When overriding MUI, styled-components specificity often loses to MUI's inline-on-render styles.
|
|
294
|
+
Resolve with `&&` (section 6) before reaching for anything else.
|
|
295
|
+
|
|
296
|
+
### 12) Accessibility-aware styling
|
|
297
|
+
|
|
298
|
+
- Never remove `outline` on `:focus` without a visible, accessible replacement using `:focus-visible`
|
|
299
|
+
- Contrast: UI text must meet WCAG 2.2 — at least **4.5:1** for normal text, **3:1** for large text
|
|
300
|
+
and UI components — use `baseColors` tokens which are calibrated to the design system
|
|
301
|
+
- Respect `prefers-reduced-motion` for animation-heavy components:
|
|
302
|
+
|
|
303
|
+
```ts
|
|
304
|
+
export const AnimatedPanel = styled.div<{ $open: boolean }>`
|
|
305
|
+
transition: transform 0.3s ease;
|
|
306
|
+
|
|
307
|
+
@media (prefers-reduced-motion: reduce) {
|
|
308
|
+
transition: none;
|
|
309
|
+
}
|
|
310
|
+
`;
|
|
311
|
+
```
|
|
312
|
+
|
|
313
|
+
---
|
|
314
|
+
|
|
315
|
+
## Working method (apply in this order)
|
|
316
|
+
|
|
317
|
+
1. **Confirm placement** — does a `.styles.ts` co-located file already exist? Create it if not.
|
|
318
|
+
2. **Name the export** — PascalCase, no `Styled` prefix; rename legacy `StyledXxx` names when touching them.
|
|
319
|
+
3. **Pick the base** — `styled.div` / `styled.span` / etc. for HTML elements; `styled(MuiComponent)` for MUI; `styled(ExistingStyledComponent)` for extension.
|
|
320
|
+
4. **Apply colors** from `baseColors`; apply spacing from `theme.spacing(N)` — no hard-coded hex or pixel values.
|
|
321
|
+
5. **Add transient props** with `$` prefix for any prop that controls style but must not reach the DOM.
|
|
322
|
+
6. **For overrides** use child selectors → `&&` → refactor layout (never `!important`).
|
|
323
|
+
7. **Check accessibility** — focus styles intact, sufficient contrast, reduced-motion respected.
|
|
324
|
+
|
|
325
|
+
## Quality bar before final answer
|
|
326
|
+
|
|
327
|
+
- Styled components are in a co-located `.styles.ts` file, never inline in `.tsx`.
|
|
328
|
+
- All exports are PascalCase with no `Styled` prefix.
|
|
329
|
+
- All color values come from `baseColors`; no hard-coded hex, `rgb()`, or `hsl()` literals.
|
|
330
|
+
- All spacing comes from `theme.spacing()`; no hard-coded `px` sizes (except `0`, `1px` borders, border-radius).
|
|
331
|
+
- All styling-only props use the `$` prefix.
|
|
332
|
+
- No `!important` anywhere; specificity conflicts resolved with `&&` or child selectors.
|
|
333
|
+
- No plain `.css` files, CSS Modules, or Tailwind introduced.
|
|
334
|
+
- Negative margins are absent; layout spacing uses `gap` or `padding`.
|
|
335
|
+
- Focus styles are present and accessible on interactive elements.
|
|
336
|
+
|