diff --git a/.claude/agents/agent-code-reviewer.md b/.claude/agents/agent-code-reviewer.md new file mode 100644 index 00000000..b4a69ce4 --- /dev/null +++ b/.claude/agents/agent-code-reviewer.md @@ -0,0 +1,66 @@ +--- +name: code-reviewer +description: PR/code review. 100% coverage, SSR safety, JSDoc validation. +tools: Read, Grep, Glob +model: sonnet +--- + +# Code Reviewer Agent + +An **orchestrator** that verifies code quality. + +## Role + +This agent does not make changes directly; instead, it coordinates the following skills: + +1. **code-reviewer** skill → Apply review checklist +2. **jsdoc-guide** skill → Verify JSDoc completeness +3. **library-api-design** skill → Verify API design principles + +## Orchestration Flow + +``` +[Code review request] + ↓ +[1. Identify changed files] + - git diff or read files directly + ↓ +[2. Run code-reviewer skill] + - Check test coverage + - Verify SSR safety + - Check edge cases + ↓ +[3. Reference jsdoc-guide] + - Verify required tags exist + - Validate example code + ↓ +[4. Reference library-api-design] + - Verify API consistency + - Check TypeScript types + ↓ +[5. Generate feedback] + - Output structured review results +``` + +## When to Use + +- "Review this code" +- "Check this PR" +- "Verify if this hook is okay" + +## Feedback Format + +```markdown +## Great Work + +- What was done well + +## Required Changes + +1. **[Category]** Issue + - Why: reason + +## Next Steps + +1. Items to fix +``` diff --git a/.claude/agents/agent-doc-writer.md b/.claude/agents/agent-doc-writer.md new file mode 100644 index 00000000..72a68bd4 --- /dev/null +++ b/.claude/agents/agent-doc-writer.md @@ -0,0 +1,44 @@ +--- +name: doc-writer +description: JSDoc and documentation writing. API documentation, example code generation. +tools: Read, Write, Edit, Glob, Grep +model: sonnet +--- + +# Documentation Writer Agent + +Writes JSDoc documentation following the **jsdoc-guide** skill. + +## Role + +This agent writes JSDoc by referencing the **jsdoc-guide** skill for formatting rules and required tags. + +## Flow + +``` +[Documentation writing request] + ↓ +[1. Analyze target files] + - Identify function/hook signatures + - Check existing JSDoc + ↓ +[2. Reference jsdoc-guide skill] + - Verify required tags + - Apply templates + ↓ +[3. Write JSDoc] + - @description, @param, @returns, @example +``` + +## When to Use + +- "Write JSDoc" +- "Document this" +- "Add example code" + +## Writing Principles + +1. **Clarity**: Minimize technical jargon +2. **Completeness**: Cover all parameters and return values +3. **Example-driven**: Copy-paste ready and immediately runnable +4. **Consistency**: Maintain uniform formatting diff --git a/.claude/agents/agent-git-helper.md b/.claude/agents/agent-git-helper.md new file mode 100644 index 00000000..6cb98b81 --- /dev/null +++ b/.claude/agents/agent-git-helper.md @@ -0,0 +1,62 @@ +--- +name: git-helper +description: Git commits and branch creation following repo conventions. Used when other agents delegate git tasks. +tools: Bash, Read, Glob, Grep +model: haiku +--- + +# Git Helper Agent + +A **lightweight orchestrator** that performs git operations following repo conventions. + +## Role + +This agent coordinates the following skills: + +1. **commit** skill → Commit message conventions +2. **branch** skill → Branch naming conventions + +## Orchestration Flow + +### Creating a Commit + +``` +[Commit request] + ↓ +[1. Analyze changes] + - git status, git diff + ↓ +[2. Reference commit skill] + - Determine type and scope + - Generate message following conventions + ↓ +[3. Execute commit] + - git add, git commit +``` + +### Creating a Branch + +``` +[Branch request] + ↓ +[1. Confirm task details] + ↓ +[2. Reference branch skill] + - Determine branch type + - Generate English branch name + ↓ +[3. Create branch] + - git checkout -b +``` + +## When to Use + +- "Create a commit" +- "Create a branch" +- When other agents delegate git tasks + +## Cautions + +- Never commit sensitive files (.env, credentials) +- Push only when explicitly requested +- Never use --amend unless explicitly requested (if a pre-commit hook fails, --amend would unintentionally modify the previous commit) diff --git a/.claude/agents/agent-scaffolder.md b/.claude/agents/agent-scaffolder.md new file mode 100644 index 00000000..7e4dd9c8 --- /dev/null +++ b/.claude/agents/agent-scaffolder.md @@ -0,0 +1,50 @@ +--- +name: scaffolder +description: Scaffold new Hooks/Components/Utils. Generate standard structure and boilerplate. +tools: Read, Write, Edit, Bash, Glob, Grep +model: sonnet +--- + +# Scaffolder Agent + +An **orchestrator** that creates new Hooks, Components, and Utils with a standard structure. + +## Role + +This agent does not implement directly; instead, it coordinates the following skills: + +1. **scaffolder** skill → File structure generation +2. **jsdoc-guide** skill → JSDoc writing rules reference +3. **development-workflow** skill → Overall workflow guide + +## Orchestration Flow + +``` +[User request] + ↓ +[1. Analyze requirements] + - Determine type (Hook/Component/Util) + - Validate name + ↓ +[2. Run scaffolder skill] + - Create folder structure + - Generate template files + ↓ +[3. Reference jsdoc-guide] + - Apply JSDoc standards + ↓ +[4. Register exports] + - Add to src/index.ts +``` + +## When to Use + +- "Create a useXxx hook" +- "Create a new component" +- "Add a utility function" + +## Cautions + +- Never overwrite existing files +- Verify naming conventions are followed +- Recommended to run tests after generation diff --git a/.claude/skills/skill-branch/SKILL.md b/.claude/skills/skill-branch/SKILL.md new file mode 100644 index 00000000..1d029b6d --- /dev/null +++ b/.claude/skills/skill-branch/SKILL.md @@ -0,0 +1,43 @@ +--- +name: branch +description: Create branches following repo conventions. Use when creating branches, starting new features. +allowed-tools: Bash +--- + +# Git Branch Skill + +## Quick Start + +```bash +/branch feat user-authentication # → feat/user-authentication +/branch fix login-error # → fix/login-error +/branch # interactive creation +``` + +## Core Patterns + +| Pattern | Purpose | Example | +| ----------------- | ------------- | ----------------------------- | +| `feat/{name}` | New feature | `feat/use-debounce` | +| `fix/{name}` | Bug fix | `fix/ssr-hydration-mismatch` | +| `chore/{name}` | Config/build | `chore/update-build-config` | +| `docs/{name}` | Documentation | `docs/add-use-toggle-example` | +| `refactor/{name}` | Refactoring | `refactor/cleanup-internals` | + +## Execution Steps + +1. Confirm task details +2. Determine the appropriate branch type +3. Generate an English branch name (lowercase, hyphens) +4. Run `git checkout -b {branch}` + +## Cautions + +- Branch names: lowercase English + hyphens only +- Spaces are converted to hyphens +- Korean descriptions are converted to English +- Warn if there are uncommitted changes + +## References + +- [details.md](references/details.md) - Detailed branch naming guide diff --git a/.claude/skills/skill-branch/references/details.md b/.claude/skills/skill-branch/references/details.md new file mode 100644 index 00000000..c399f1c9 --- /dev/null +++ b/.claude/skills/skill-branch/references/details.md @@ -0,0 +1,62 @@ +# Git Branch Detailed Guide + +## Branch Types in Detail + +### feat (New Feature) + +``` +feat/{feature-name} +``` + +- Used when developing a new feature +- Examples: `feat/use-debounce`, `feat/add-keyboard-height-hook` + +### fix (Bug Fix) + +``` +fix/{fix-description} +``` + +- Used when fixing a bug +- Examples: `fix/ssr-hydration-mismatch`, `fix/scroll-direction-cleanup` + +### chore (Config/Build) + +``` +chore/{description} +``` + +- Used when changing build config, CI, dependencies, etc. +- Examples: `chore/update-build-config`, `chore/add-changesets` + +### docs (Documentation) + +``` +docs/{description} +``` + +- Used when adding or modifying documentation +- Examples: `docs/add-use-toggle-example`, `docs/update-contributing` + +### refactor (Refactoring) + +``` +refactor/{description} +``` + +- Used for code refactoring +- Examples: `refactor/cleanup-internals`, `refactor/simplify-hook-logic` + +## Naming Conversion Rules + +| Input | Output | +| --------------------------- | ---------------------- | +| user authentication feature | user-authentication | +| SSR hydration error | ssr-hydration-mismatch | +| update build config | update-build-config | + +## Cautions + +- No special characters allowed (only hyphens) +- Avoid overly long branch names (3-4 words recommended) +- If there are uncommitted changes, stash or commit before creating a branch diff --git a/.claude/skills/skill-code-reviewer/SKILL.md b/.claude/skills/skill-code-reviewer/SKILL.md new file mode 100644 index 00000000..3055c928 --- /dev/null +++ b/.claude/skills/skill-code-reviewer/SKILL.md @@ -0,0 +1,57 @@ +--- +name: code-reviewer +description: PR/code review. 100% coverage, SSR safety, JSDoc validation. Use when reviewing code, checking PRs. +allowed-tools: Read, Grep, Glob +--- + +# Code Reviewer + +Code reviewer for the react-simplikit project. + +## Quick Start + +```bash +/code-reviewer # Review current changes +``` + +## Review Checklist + +### Required Checks + +- [ ] 100% test coverage +- [ ] SSR test exists (`renderHookSSR.serverOnly`) +- [ ] JSDoc complete (@description, @param, @returns, @example) +- [ ] TypeScript strict compliance + +### Code Quality + +- [ ] Zero dependencies maintained +- [ ] No unnecessary re-renders +- [ ] Edge cases handled + +### API Design + +- [ ] Intuitive API +- [ ] Consistent patterns +- [ ] Named exports used + +## Feedback Format + +```markdown +## Great Work + +- What was done well + +## Required Changes + +1. **[Category]** Issue + - Current: `code` + - Suggested: `code` + - Why: reason + +## Next Steps + +1. Fix required changes +2. Run tests +3. Push updates +``` diff --git a/.claude/skills/skill-commit/SKILL.md b/.claude/skills/skill-commit/SKILL.md new file mode 100644 index 00000000..b7f7a2bb --- /dev/null +++ b/.claude/skills/skill-commit/SKILL.md @@ -0,0 +1,60 @@ +--- +name: commit +description: Create commits following repo conventions. Use when committing changes, creating commit messages. +allowed-tools: Bash, Read, Glob, Grep +--- + +# Git Commit Skill + +## Quick Start + +```bash +/commit # Analyze changes and auto-commit +``` + +## Commit Message Format + +``` +(): +``` + +## Core Patterns + +### Type + +| Type | Purpose | +| -------- | ------------- | +| feat | New feature | +| fix | Bug fix | +| chore | Build, config | +| refactor | Refactoring | +| docs | Documentation | +| test | Tests | + +### Scope + +| Category | Example | +| -------- | ---------------- | +| Package | `core`, `mobile` | +| None | Omit scope | + +### Examples + +```bash +feat(core): add useDebounce hook +feat(mobile): add useKeyboardHeight hook +fix: correct SSR rendering logic +docs: update useToggle documentation +chore: add claude skills +``` + +## Execution Steps + +1. `git status` - Check changed files +2. `git diff` - Analyze changes +3. Determine type, scope, and description +4. `git add .` + `git commit` + +## References + +- [details.md](references/details.md) - Full conventions and complex cases diff --git a/.claude/skills/skill-commit/references/details.md b/.claude/skills/skill-commit/references/details.md new file mode 100644 index 00000000..edbe6a9f --- /dev/null +++ b/.claude/skills/skill-commit/references/details.md @@ -0,0 +1,49 @@ +# Git Commit Detailed Guide + +## Scope Details + +| Category | Format | Example | +| -------- | ---------- | -------------------- | +| Package | `{name}` | `core`, `mobile` | +| None | Omit scope | `chore: description` | + +### When Multiple Packages Are Modified + +Group under an appropriate higher-level concept: + +- Or specify only the primary target of the change + +## Description Writing Rules + +- Write in English +- Keep it concise +- No period at the end +- Common expressions: `add ~`, `fix ~`, `remove ~`, `update ~`, `improve ~`, `apply ~` + +## Cautions + +- Never commit sensitive files such as `.env`, `credentials.json` +- Do not commit if there are no changes +- Push only when explicitly requested +- If a pre-commit hook fails, fix the issue and create a new commit (never use amend) +- Write in the format `type(scope):` with no space before the colon + +## Full Examples + +```bash +# Basic +feat(core): add useDebounce hook + +# Package scope +feat(mobile): add useKeyboardHeight hook + +# No scope +chore: add claude agent and skills + +# Multi-line description +feat(core): add useThrottle hook + +- Implement basic throttle +- Ensure SSR safety +- Write tests +``` diff --git a/.claude/skills/skill-development-workflow/SKILL.md b/.claude/skills/skill-development-workflow/SKILL.md new file mode 100644 index 00000000..a8ca443e --- /dev/null +++ b/.claude/skills/skill-development-workflow/SKILL.md @@ -0,0 +1,71 @@ +--- +name: development-workflow +description: Complete workflow from new Hook/Component/Util development to deployment. Use when starting new feature development. +allowed-tools: Read, Write, Edit, Bash, Glob, Grep +--- + +# Development Workflow Guide + +## Quick Start + +``` +Scaffold → Implementation → Testing → Documentation → Review → Changeset → Merge +``` + +## Workflow Steps + +### 1. Scaffold + +```bash +yarn scaffold useNewHook --type h # Hook +yarn scaffold MyComponent --type c # Component +``` + +### 2. Implementation + +- Write JSDoc +- Implement functionality +- Ensure accurate TypeScript types + +### 3. Testing (100% coverage required) + +```bash +yarn test:spec +yarn test:coverage +``` + +- SSR testing required +- Handle edge cases + +### 4. Documentation + +- @description, @param, @returns, @example + +### 5. Review + +```bash +yarn test # Full validation +yarn test:type # Type check +yarn test:lint # Lint +``` + +### 6. Changeset + +```bash +yarn changeset +# patch: Bug fix +# minor: New feature +# major: Breaking change +``` + +### 7. Merge + +```bash +git checkout -b feat/add-use-new-hook +git add . && git commit -m "feat: add useNewHook" +gh pr create +``` + +## References + +- [details.md](references/details.md) - Detailed guide diff --git a/.claude/skills/skill-development-workflow/references/details.md b/.claude/skills/skill-development-workflow/references/details.md new file mode 100644 index 00000000..946eae8f --- /dev/null +++ b/.claude/skills/skill-development-workflow/references/details.md @@ -0,0 +1,60 @@ +# Development Workflow Detailed Guide + +## Detailed Steps + +### Scaffold Output + +``` +src/hooks/useNewHook/ +├── useNewHook.ts +├── useNewHook.spec.ts +└── index.ts +``` + +### Implementation Checklist + +- [ ] 4 required JSDoc tags +- [ ] TypeScript strict mode compliance +- [ ] SSR safety ensured +- [ ] Zero dependencies + +### Implementation Template + +```typescript +/** + * @description What it does. + * @param {T} value - Description. + * @returns {T} Description. + * @example + * const result = useNewHook(input); + */ +export function useNewHook(value: T): T { + // implementation +} +``` + +### Testing Checklist + +- [ ] SSR test (required) +- [ ] Basic behavior test +- [ ] Edge cases (null, undefined, empty) +- [ ] State change test +- [ ] 100% coverage + +### Self-Review Checklist + +- [ ] SSR test included +- [ ] 100% coverage +- [ ] JSDoc complete +- [ ] TypeScript types accurate +- [ ] API consistency + +## Quick Commands + +```bash +yarn scaffold NAME --type h|c|u # Generate +yarn test # Full test +yarn test:coverage # Coverage +yarn changeset # Release preparation +yarn fix # Auto fix +``` diff --git a/.claude/skills/skill-jsdoc-guide/SKILL.md b/.claude/skills/skill-jsdoc-guide/SKILL.md new file mode 100644 index 00000000..09c8b745 --- /dev/null +++ b/.claude/skills/skill-jsdoc-guide/SKILL.md @@ -0,0 +1,63 @@ +--- +name: jsdoc-guide +description: JSDoc writing rules for AI-powered documentation generation. Use when writing JSDoc, documenting functions, or adding code comments. +allowed-tools: Read, Edit +--- + +# JSDoc Writing Guide + +## Quick Start + +All exported functions require 4 mandatory tags: + +```typescript +/** + * @description One-line summary. + * @param {Type} name - Description. + * @returns {Type} Description. + * @example + * const result = useHook(input); + */ +``` + +## Core Patterns + +### 1. @description - First line is a one-sentence summary + +```typescript +// ✅ Good +@description Debounces a value and returns it after the specified delay. + +// ❌ Bad +@description Does something with a value. +``` + +### 2. @param - Type + description + +```typescript +@param {T} value - The value to debounce. +@param {number} [delay=300] - Optional delay in ms. +@param {Object} options - Configuration object. +``` + +### 3. @returns - Return value description + +```typescript +// Simple +@returns {T} The debounced value. + +// Tuple +@returns {[boolean, () => void]} [state, toggle] +``` + +### 4. @example - Runnable code + +```typescript +@example +const [search, setSearch] = useState(''); +const debouncedSearch = useDebounce(search, 300); +``` + +## References + +- [details.md](references/details.md) - Full tag guide, complex cases diff --git a/.claude/skills/skill-jsdoc-guide/references/details.md b/.claude/skills/skill-jsdoc-guide/references/details.md new file mode 100644 index 00000000..a3849931 --- /dev/null +++ b/.claude/skills/skill-jsdoc-guide/references/details.md @@ -0,0 +1,101 @@ +# JSDoc Detailed Guide + +## @param Advanced Patterns + +### Optional Parameters + +```typescript +@param {boolean} [enabled=true] - Whether enabled. +``` + +### Object properties + +```typescript +@param {Object} options - Configuration. +@param {number} [options.delay] - Delay in ms. +@param {boolean} [options.leading] - Execute on leading edge. +``` + +### Generic Types + +```typescript +@template T - The type of the value. +@param {T} value - The value to process. +``` + +## @returns Advanced Patterns + +### Tuple Return + +```typescript +@returns {[boolean, () => void]} A tuple containing: +- value (boolean) - Current state. +- toggle (() => void) - Toggle function. +``` + +### Object Return + +```typescript +@returns {Object} Pagination state: +- page (number) - Current page. +- nextPage (() => void) - Go to next. +- prevPage (() => void) - Go to previous. +``` + +## Complete Example + +```typescript +/** + * @description Debounces a value and returns it after the specified delay. + * + * Useful when you want to delay updates to a frequently changing value. + * + * @template T - The type of the value. + * + * @param {T} value - The value to debounce. + * @param {number} delay - The delay in milliseconds. + * + * @returns {T} The debounced value. + * + * @example + * import { useDebounce } from 'react-simplikit'; + * + * function Search() { + * const [search, setSearch] = useState(''); + * const debouncedSearch = useDebounce(search, 300); + * + * useEffect(() => { + * fetch(`/api/search?q=${debouncedSearch}`); + * }, [debouncedSearch]); + * + * return setSearch(e.target.value)} />; + * } + */ +export function useDebounce(value: T, delay: number): T { + // ... +} +``` + +## Common Mistakes + +```typescript +// ❌ No description +@param {T} value +@returns {T} + +// ❌ No example +@description Debounces a value. +@param {T} value - The value. + +// ❌ Non-working example +@example +const x = useDebounce(); // Missing params! + +// ✅ Complete +@description Debounces a value. +@param {T} value - The value to debounce. +@param {number} delay - Delay in ms. +@returns {T} The debounced value. +@example +const debounced = useDebounce(search, 300); +``` diff --git a/.claude/skills/skill-library-api-design/SKILL.md b/.claude/skills/skill-library-api-design/SKILL.md new file mode 100644 index 00000000..3035734c --- /dev/null +++ b/.claude/skills/skill-library-api-design/SKILL.md @@ -0,0 +1,67 @@ +--- +name: library-api-design +description: React library public API design principles. Use when designing hooks, components, or utility APIs. +allowed-tools: Read, Glob, Grep +--- + +# Library API Design Guide + +## Core Principles + +1. **Simplicity first** (Simple > Clever) +2. **Maintain consistency** +3. **Tree-shaking friendly** +4. **Maximize TypeScript inference** +5. **Ensure SSR safety** + +## Core Patterns + +### Hook Return Values + +```typescript +// Single value +function useDebounce(value: T, delay: number): T; + +// Tuple (state + action) +function useToggle(init = false): [boolean, () => void]; + +// Object (3 or more fields) +function usePagination(): { page; nextPage; prevPage }; +``` + +### Parameters + +```typescript +// Required first, optional last +function useDebounce( + value: T, // required + delay: number, // required + options?: {...} // optional +): T +``` + +### SSR Safety + +```typescript +// ✅ SSR-safe +export function useMediaQuery(query: string): boolean { + const [matches, setMatches] = useState(() => { + if (typeof window === 'undefined') return false; + return window.matchMedia(query).matches; + }); +} +``` + +### Export + +```typescript +// ✅ Named exports only +export { useDebounce } from './useDebounce'; + +// ❌ Default export +export default useDebounce; +``` + +## References + +- [details.md](references/details.md) - Component design, advanced patterns diff --git a/.claude/skills/skill-library-api-design/references/details.md b/.claude/skills/skill-library-api-design/references/details.md new file mode 100644 index 00000000..f04ec690 --- /dev/null +++ b/.claude/skills/skill-library-api-design/references/details.md @@ -0,0 +1,94 @@ +# API Design Detailed Guide + +## Hook Design + +### Naming + +```typescript +// ✅ use prefix +useDebounce(), useToggle(), useInterval(); + +// ❌ unclear +debounce(), toggle(); +``` + +### Return Values in Detail + +```typescript +// Single value - simple transformation +function useDebounce(value: T, delay: number): T; + +// Tuple - state + single action +function useToggle(init = false): [boolean, () => void]; +function useBoolean(init = false): [boolean, { on; off; toggle }]; + +// Object - complex state +function usePagination(): { + page: number; + nextPage: () => void; + prevPage: () => void; + goToPage: (page: number) => void; + hasNext: boolean; + hasPrev: boolean; +}; +``` + +## Component Design + +### Props Naming + +```typescript +// ✅ Boolean without prefix + + ) +); +Button.displayName = 'Button'; +``` + +## Utility Design + +### Pure Functions + +```typescript +// ✅ No side effects +export function mergeRefs(...refs: Ref[]): RefCallback; + +// ❌ Side effects +let global: any; +export function setState(v: any) { + global = v; +} +``` + +## TypeScript + +```typescript +// ✅ Leverage inference +function useDebounce(value: T, delay: number): T; + +// ✅ as const for tuples +return [value, toggle] as const; + +// ❌ Using any +function useDebounce(value: any): any; +``` + +## Checklist + +- [ ] Name clearly describes the functionality +- [ ] No prefix on boolean props +- [ ] TypeScript inference maximized +- [ ] SSR tests written +- [ ] Named exports used +- [ ] JSDoc complete diff --git a/.claude/skills/skill-scaffolder/SKILL.md b/.claude/skills/skill-scaffolder/SKILL.md new file mode 100644 index 00000000..7bac2b45 --- /dev/null +++ b/.claude/skills/skill-scaffolder/SKILL.md @@ -0,0 +1,67 @@ +--- +name: scaffolder +description: Scaffold new hooks/components/utilities. Generate standard structure and boilerplate. Use when creating new hooks, components, utilities. +allowed-tools: Read, Write, Edit, Bash, Glob, Grep +--- + +# Scaffolder + +Creates new hooks, components, and utilities with a standard structure. + +## Quick Start + +```bash +/scaffolder useNewHook # Create a hook +/scaffolder MyComponent # Create a component +/scaffolder myUtil # Create a utility +``` + +## Generated Structure + +``` +src/{type}/{name}/ +├── {name}.ts # Implementation +├── {name}.spec.ts # Tests +└── index.ts # Export +``` + +## Hook Template + +```typescript +/** + * @description Hook description. + * @param {T} param - Parameter description. + * @returns {T} Return description. + * @example + * const result = useHookName(input); + */ +export function useHookName(param: T): T { + // implementation +} +``` + +## Test Template + +```typescript +import { renderHook } from '@testing-library/react'; +import { renderHookSSR } from '../../_internal/test-utils/renderHookSSR.tsx'; + +describe('useHookName', () => { + it('is safe on server side rendering', () => { + const result = renderHookSSR.serverOnly(() => useHookName('test')); + expect(result.current).toBeDefined(); + }); + + it('works correctly', () => { + const { result } = renderHook(() => useHookName('test')); + expect(result.current).toBe('test'); + }); +}); +``` + +## Workflow + +1. Confirm the name and type +2. Create the folder structure +3. Generate template files +4. Add export to src/index.ts diff --git a/.claude/skills/skill-test-writer/SKILL.md b/.claude/skills/skill-test-writer/SKILL.md new file mode 100644 index 00000000..c75fb500 --- /dev/null +++ b/.claude/skills/skill-test-writer/SKILL.md @@ -0,0 +1,63 @@ +--- +name: test-writer +description: Write test code. 100% coverage, SSR tests, edge cases. Use when writing tests, adding test coverage. +allowed-tools: Read, Write, Edit, Bash +--- + +# Test Writer + +Writes tests that achieve 100% coverage. + +## Quick Start + +```bash +yarn test:spec # Run a single test +yarn test:coverage # Check coverage +``` + +## Core Patterns + +### 1. SSR Test (Required) + +```typescript +it('is safe on server side rendering', () => { + const result = renderHookSSR.serverOnly(() => useHook()); + expect(result.current).toBeDefined(); +}); +``` + +### 2. Basic Behavior Test + +```typescript +it('returns expected value', () => { + const { result } = renderHook(() => useHook(input)); + expect(result.current).toBe(expected); +}); +``` + +### 3. Edge Cases + +```typescript +it('handles null/undefined', () => { ... }); +it('handles empty values', () => { ... }); +``` + +### 4. State Change Test + +```typescript +it('updates when state changes', () => { + const { result, rerender } = renderHook(({ value }) => useHook(value), { + initialProps: { value: 'initial' }, + }); + rerender({ value: 'updated' }); + expect(result.current).toBe('updated'); +}); +``` + +## Coverage Check + +All lines, branches, and functions must have 100% coverage. + +## References + +- [details.md](references/details.md) - Advanced test patterns diff --git a/.claude/skills/skill-test-writer/references/details.md b/.claude/skills/skill-test-writer/references/details.md new file mode 100644 index 00000000..91309f19 --- /dev/null +++ b/.claude/skills/skill-test-writer/references/details.md @@ -0,0 +1,98 @@ +# Test Writing Detailed Guide + +## Advanced Test Patterns + +### act() Usage + +```typescript +import { act } from '@testing-library/react'; + +it('handles async state updates', async () => { + const { result } = renderHook(() => useAsyncHook()); + + await act(async () => { + await result.current.fetchData(); + }); + + expect(result.current.data).toBeDefined(); +}); +``` + +### waitFor Pattern + +```typescript +import { waitFor } from '@testing-library/react'; + +it('waits for condition', async () => { + const { result } = renderHook(() => useDebounce(value, 300)); + + await waitFor(() => { + expect(result.current).toBe(expected); + }); +}); +``` + +### Timer Mocking + +```typescript +beforeEach(() => { + vi.useFakeTimers(); +}); + +afterEach(() => { + vi.useRealTimers(); +}); + +it('debounces correctly', () => { + const { result } = renderHook(() => useDebounce('test', 300)); + + vi.advanceTimersByTime(300); + + expect(result.current).toBe('test'); +}); +``` + +## SSR Test Details + +### renderHookSSR Usage + +```typescript +import { renderHookSSR } from '../../_internal/test-utils/renderHookSSR.tsx'; + +describe('SSR Safety', () => { + it('is safe on server side rendering', () => { + const result = renderHookSSR.serverOnly(() => useHook()); + expect(result.current).toBeDefined(); + }); + + it('hydrates correctly', () => { + const { result } = renderHookSSR(() => useHook()); + expect(result.current).toBe(expected); + }); +}); +``` + +### window/document Access + +```typescript +// ✅ SSR-safe pattern +const isClient = typeof window !== 'undefined'; + +// Verify in tests +it('handles server environment', () => { + // renderHookSSR.serverOnly simulates an environment without window + const result = renderHookSSR.serverOnly(() => + useMediaQuery('(min-width: 768px)') + ); + expect(result.current).toBe(false); // Returns default value on server +}); +``` + +## Coverage Checklist + +- [ ] All if/else branches +- [ ] All switch cases +- [ ] All early returns +- [ ] All error cases +- [ ] All callback functions +- [ ] Cleanup functions (useEffect return) diff --git a/.github/CONTRIBUTING.md b/.github/CONTRIBUTING.md index 970fbd97..a1a3a6c4 100644 --- a/.github/CONTRIBUTING.md +++ b/.github/CONTRIBUTING.md @@ -42,4 +42,4 @@ Select the version bump type (`patch`, `minor`, or `major`). - [Documentation Site](https://react-simplikit.slash.page) - [Design Principles](https://react-simplikit.slash.page/core/design-principles.html) -- [Discord](https://discord.gg/vGXbVjP2nY) +- [Discord](https://discord.gg/vGXbVjP2nY) — Community chat for questions and discussions diff --git a/.gitignore b/.gitignore index 9f269c02..4c322762 100644 --- a/.gitignore +++ b/.gitignore @@ -41,6 +41,7 @@ coverage .claude/memory/ .claude/plans/ .claude/skills/project-decisions/ +.claude/skills/skill-open-source-maintainer/ # Session notes (contain internal references) .claude/*.md