|
1 | 1 | # Copilot Instructions for react-simplikit |
2 | 2 |
|
| 3 | +> Full coding standards with examples: see [AGENTS.md](../../AGENTS.md) |
| 4 | +
|
3 | 5 | ## Quick Reference |
4 | 6 |
|
5 | 7 | - Monorepo: `packages/core` (react-simplikit) + `packages/mobile` (@react-simplikit/mobile) |
6 | 8 | - Architecture: `components → hooks → utils → _internal` (unidirectional, no circular imports) |
7 | | -- Mobile depends on core; core must NOT depend on mobile |
| 9 | +- Core and mobile are independent packages — no cross-package dependencies |
8 | 10 |
|
9 | 11 | ## Code Style Rules |
10 | 12 |
|
|
13 | 15 | - No default exports — named exports only |
14 | 16 | - No `any` types — strict TypeScript |
15 | 17 | - Use `.ts`/`.tsx` extensions in source imports (tsup converts to `.js`) |
16 | | -- Strict boolean checks: `value !== undefined` not `if (value)` |
| 18 | +- No implicit boolean coercion: `if (value)` → `if (value != null)` (enforced by `strict-boolean-expressions`) |
| 19 | +- Nullish checks: `== null` for both null and undefined, `!== undefined` only when distinction matters |
17 | 20 | - Zero runtime dependencies |
18 | 21 | - Always return cleanup in useEffect to remove listeners |
19 | | -- Nullish checks: use `== null` for both null and undefined: |
20 | | - ```ts |
21 | | - if (ref == null) { continue; } |
22 | | - items.filter(item => item != null); |
23 | | - const controlled = valueProp !== undefined; // only when distinction matters |
24 | | - ``` |
25 | 22 | - Prefer early returns (guard clauses) over nested if-else blocks |
26 | | -- Function declarations use `function` keyword, not arrow functions: |
27 | | - ```ts |
28 | | - // ✅ function toggle(state: boolean) { return !state; } |
29 | | - // ✅ items.filter(item => item != null) ← inline callback arrow OK |
30 | | - // ❌ const toggle = (state: boolean) => !state; |
31 | | - ``` |
32 | | - |
33 | | -## SSR-Safe Pattern (CRITICAL) |
34 | | - |
35 | | -All browser API access must use this pattern: |
36 | | - |
37 | | -```ts |
38 | | -const [state, setState] = useState(FIXED_INITIAL_VALUE); |
39 | | -useEffect(function syncBrowserState() { |
40 | | - if (isServer()) return; |
41 | | - setState(getBrowserAPI()); |
42 | | -}, []); |
43 | | -``` |
44 | | - |
45 | | -Never call browser APIs during state initialization. |
46 | | - |
47 | | -## Hook Return Values |
48 | | - |
49 | | -- 1 value → return directly: `useDebounce<T>(value, delay): T` |
50 | | -- 2 values → tuple: `useToggle(init): [boolean, () => void]` |
51 | | -- 3+ values → object: `usePagination(): { page, nextPage, prevPage }` |
52 | | - |
53 | | -## Testing |
54 | | - |
55 | | -- 100% coverage required (Vitest) |
56 | | -- SSR test required for browser API hooks: |
57 | | - ```ts |
58 | | - import { renderHookSSR } from '../../_internal/test-utils/renderHookSSR.tsx'; |
59 | | - it('is safe on server side rendering', () => { |
60 | | - const result = renderHookSSR.serverOnly(() => useHookName()); |
61 | | - expect(result.current).toBeDefined(); |
62 | | - }); |
63 | | - ``` |
64 | | - |
65 | | -## JSDoc Template |
66 | | - |
67 | | -Every public API requires: |
68 | | - |
69 | | -````ts |
70 | | -/** |
71 | | - * @description Brief description of what it does |
72 | | - * @param paramName - Parameter description |
73 | | - * @returns What the hook/function returns |
74 | | - * @example |
75 | | - * ```ts |
76 | | - * const value = useHookName(param); |
77 | | - * ``` |
78 | | - */ |
79 | | -```` |
80 | | - |
81 | | -## File Structure |
82 | | - |
83 | | -``` |
84 | | -src/hooks/useHookName/ |
85 | | -├── index.ts # Re-export |
86 | | -├── useHookName.ts # Implementation |
87 | | -├── useHookName.spec.ts # Tests (core) / useHookName.test.ts (mobile) |
88 | | -├── useHookName.ssr.test.ts # SSR tests |
89 | | -├── useHookName.md # English docs |
90 | | -└── ko/useHookName.md # Korean docs |
91 | | -``` |
92 | | - |
93 | | -## Commands |
94 | | - |
95 | | -```bash |
96 | | -yarn build # Build all packages (tsup) |
97 | | -yarn test # Run tests (Vitest) |
98 | | -yarn fix # Auto-fix lint + format |
99 | | -yarn typecheck # Type check (tsc --noEmit) |
100 | | -``` |
| 23 | +- Function declarations use `function` keyword, not arrow functions |
| 24 | +- Short inline callbacks (map, filter args) are OK with arrow functions |
0 commit comments