omgkit 2.1.1 → 2.3.0

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.
Files changed (56) hide show
  1. package/package.json +1 -1
  2. package/plugin/skills/databases/mongodb/SKILL.md +81 -28
  3. package/plugin/skills/databases/prisma/SKILL.md +87 -32
  4. package/plugin/skills/databases/redis/SKILL.md +80 -27
  5. package/plugin/skills/devops/aws/SKILL.md +80 -26
  6. package/plugin/skills/devops/github-actions/SKILL.md +84 -32
  7. package/plugin/skills/devops/kubernetes/SKILL.md +94 -32
  8. package/plugin/skills/devops/performance-profiling/SKILL.md +59 -863
  9. package/plugin/skills/frameworks/django/SKILL.md +158 -24
  10. package/plugin/skills/frameworks/express/SKILL.md +153 -33
  11. package/plugin/skills/frameworks/fastapi/SKILL.md +153 -34
  12. package/plugin/skills/frameworks/laravel/SKILL.md +146 -33
  13. package/plugin/skills/frameworks/nestjs/SKILL.md +137 -25
  14. package/plugin/skills/frameworks/rails/SKILL.md +594 -28
  15. package/plugin/skills/frameworks/react/SKILL.md +94 -962
  16. package/plugin/skills/frameworks/spring/SKILL.md +528 -35
  17. package/plugin/skills/frameworks/vue/SKILL.md +147 -25
  18. package/plugin/skills/frontend/accessibility/SKILL.md +145 -36
  19. package/plugin/skills/frontend/frontend-design/SKILL.md +114 -29
  20. package/plugin/skills/frontend/responsive/SKILL.md +131 -28
  21. package/plugin/skills/frontend/shadcn-ui/SKILL.md +133 -43
  22. package/plugin/skills/frontend/tailwindcss/SKILL.md +105 -37
  23. package/plugin/skills/frontend/threejs/SKILL.md +110 -35
  24. package/plugin/skills/languages/javascript/SKILL.md +195 -34
  25. package/plugin/skills/methodology/brainstorming/SKILL.md +98 -30
  26. package/plugin/skills/methodology/defense-in-depth/SKILL.md +83 -37
  27. package/plugin/skills/methodology/dispatching-parallel-agents/SKILL.md +92 -31
  28. package/plugin/skills/methodology/executing-plans/SKILL.md +117 -28
  29. package/plugin/skills/methodology/finishing-development-branch/SKILL.md +111 -32
  30. package/plugin/skills/methodology/problem-solving/SKILL.md +65 -311
  31. package/plugin/skills/methodology/receiving-code-review/SKILL.md +76 -27
  32. package/plugin/skills/methodology/requesting-code-review/SKILL.md +93 -22
  33. package/plugin/skills/methodology/root-cause-tracing/SKILL.md +75 -40
  34. package/plugin/skills/methodology/sequential-thinking/SKILL.md +75 -224
  35. package/plugin/skills/methodology/systematic-debugging/SKILL.md +81 -35
  36. package/plugin/skills/methodology/test-driven-development/SKILL.md +120 -26
  37. package/plugin/skills/methodology/testing-anti-patterns/SKILL.md +88 -35
  38. package/plugin/skills/methodology/token-optimization/SKILL.md +73 -34
  39. package/plugin/skills/methodology/verification-before-completion/SKILL.md +128 -28
  40. package/plugin/skills/methodology/writing-plans/SKILL.md +105 -20
  41. package/plugin/skills/omega/omega-architecture/SKILL.md +178 -40
  42. package/plugin/skills/omega/omega-coding/SKILL.md +247 -41
  43. package/plugin/skills/omega/omega-sprint/SKILL.md +208 -46
  44. package/plugin/skills/omega/omega-testing/SKILL.md +253 -42
  45. package/plugin/skills/omega/omega-thinking/SKILL.md +263 -51
  46. package/plugin/skills/security/better-auth/SKILL.md +83 -34
  47. package/plugin/skills/security/oauth/SKILL.md +118 -35
  48. package/plugin/skills/security/owasp/SKILL.md +112 -35
  49. package/plugin/skills/testing/playwright/SKILL.md +141 -38
  50. package/plugin/skills/testing/pytest/SKILL.md +137 -38
  51. package/plugin/skills/testing/vitest/SKILL.md +124 -39
  52. package/plugin/skills/tools/document-processing/SKILL.md +111 -838
  53. package/plugin/skills/tools/image-processing/SKILL.md +126 -659
  54. package/plugin/skills/tools/mcp-development/SKILL.md +85 -758
  55. package/plugin/skills/tools/media-processing/SKILL.md +118 -735
  56. package/plugin/stdrules/SKILL_STANDARDS.md +490 -0
@@ -1,62 +1,184 @@
1
1
  ---
2
- name: vue
3
- description: Vue.js development. Use for Vue 3 projects, Composition API, Pinia.
2
+ name: building-vue-apps
3
+ description: Builds production Vue 3 applications with Composition API, TypeScript, Pinia, and Vue Router. Use when creating Vue.js SPAs, component libraries, or reactive web interfaces.
4
4
  ---
5
5
 
6
- # Vue.js Skill
6
+ # Vue.js
7
7
 
8
- ## Composition API
8
+ ## Quick Start
9
9
 
10
- ### Component
11
10
  ```vue
12
11
  <script setup lang="ts">
13
12
  import { ref, computed } from 'vue';
14
13
 
15
14
  const count = ref(0);
16
15
  const doubled = computed(() => count.value * 2);
16
+ </script>
17
+
18
+ <template>
19
+ <button @click="count++">
20
+ Count: {{ count }} (doubled: {{ doubled }})
21
+ </button>
22
+ </template>
23
+ ```
24
+
25
+ ## Features
17
26
 
18
- function increment() {
19
- count.value++;
27
+ | Feature | Description | Guide |
28
+ |---------|-------------|-------|
29
+ | Composition API | Reactive state, composables, lifecycle | [COMPOSITION.md](COMPOSITION.md) |
30
+ | TypeScript | Props, emits, refs typing | [TYPESCRIPT.md](TYPESCRIPT.md) |
31
+ | Pinia | State management, stores, plugins | [PINIA.md](PINIA.md) |
32
+ | Vue Router | Navigation, guards, lazy loading | [ROUTER.md](ROUTER.md) |
33
+ | Testing | Vitest, Vue Test Utils patterns | [TESTING.md](TESTING.md) |
34
+ | Performance | Lazy loading, memoization, virtual lists | [PERFORMANCE.md](PERFORMANCE.md) |
35
+
36
+ ## Common Patterns
37
+
38
+ ### Component with Props and Emits
39
+
40
+ ```vue
41
+ <script setup lang="ts">
42
+ interface Props {
43
+ user: { id: string; name: string; email: string };
44
+ showActions?: boolean;
20
45
  }
46
+
47
+ const props = withDefaults(defineProps<Props>(), {
48
+ showActions: true,
49
+ });
50
+
51
+ const emit = defineEmits<{
52
+ (e: 'edit', user: Props['user']): void;
53
+ (e: 'delete', id: string): void;
54
+ }>();
21
55
  </script>
22
56
 
23
57
  <template>
24
- <button @click="increment">{{ count }} ({{ doubled }})</button>
58
+ <div class="user-card">
59
+ <h3>{{ user.name }}</h3>
60
+ <p>{{ user.email }}</p>
61
+ <div v-if="showActions">
62
+ <button @click="emit('edit', user)">Edit</button>
63
+ <button @click="emit('delete', user.id)">Delete</button>
64
+ </div>
65
+ </div>
25
66
  </template>
26
67
  ```
27
68
 
28
- ### Composable
69
+ ### Composable for Reusable Logic
70
+
29
71
  ```typescript
30
- // composables/useUser.ts
31
- export function useUser(id: Ref<string>) {
32
- const user = ref<User | null>(null);
33
- const loading = ref(true);
72
+ // composables/useFetch.ts
73
+ import { ref, watch, type Ref } from 'vue';
34
74
 
35
- watch(id, async (newId) => {
75
+ export function useFetch<T>(url: Ref<string>) {
76
+ const data = ref<T | null>(null);
77
+ const loading = ref(false);
78
+ const error = ref<Error | null>(null);
79
+
80
+ async function fetchData() {
36
81
  loading.value = true;
37
- user.value = await fetchUser(newId);
38
- loading.value = false;
39
- }, { immediate: true });
82
+ error.value = null;
83
+ try {
84
+ const response = await fetch(url.value);
85
+ data.value = await response.json();
86
+ } catch (e) {
87
+ error.value = e as Error;
88
+ } finally {
89
+ loading.value = false;
90
+ }
91
+ }
92
+
93
+ watch(url, fetchData, { immediate: true });
40
94
 
41
- return { user, loading };
95
+ return { data, loading, error, refetch: fetchData };
42
96
  }
43
97
  ```
44
98
 
45
99
  ### Pinia Store
100
+
46
101
  ```typescript
102
+ // stores/user.ts
103
+ import { defineStore } from 'pinia';
104
+ import { ref, computed } from 'vue';
105
+
47
106
  export const useUserStore = defineStore('user', () => {
48
107
  const user = ref<User | null>(null);
108
+ const token = ref<string | null>(null);
109
+
110
+ const isAuthenticated = computed(() => !!user.value);
49
111
 
50
- async function login(email: string, password: string) {
51
- user.value = await api.login(email, password);
112
+ async function login(credentials: { email: string; password: string }) {
113
+ const res = await authService.login(credentials);
114
+ user.value = res.user;
115
+ token.value = res.token;
52
116
  }
53
117
 
54
- return { user, login };
118
+ function logout() {
119
+ user.value = null;
120
+ token.value = null;
121
+ }
122
+
123
+ return { user, token, isAuthenticated, login, logout };
124
+ });
125
+ ```
126
+
127
+ ## Workflows
128
+
129
+ ### Component Development
130
+
131
+ 1. Define props interface with TypeScript
132
+ 2. Define emits with typed events
133
+ 3. Use `<script setup>` syntax
134
+ 4. Create composables for reusable logic
135
+ 5. Write tests with Vitest + Vue Test Utils
136
+
137
+ ### Router Setup
138
+
139
+ ```typescript
140
+ const routes = [
141
+ { path: '/', component: () => import('./views/Home.vue') },
142
+ {
143
+ path: '/dashboard',
144
+ component: () => import('./views/Dashboard.vue'),
145
+ meta: { requiresAuth: true },
146
+ },
147
+ ];
148
+
149
+ router.beforeEach((to, from, next) => {
150
+ const userStore = useUserStore();
151
+ if (to.meta.requiresAuth && !userStore.isAuthenticated) {
152
+ next({ path: '/login', query: { redirect: to.fullPath } });
153
+ } else {
154
+ next();
155
+ }
55
156
  });
56
157
  ```
57
158
 
58
159
  ## Best Practices
59
- - Use Composition API
60
- - Use `<script setup>`
61
- - Create composables for logic
62
- - Use Pinia for state
160
+
161
+ | Do | Avoid |
162
+ |----|-------|
163
+ | Use Composition API with `<script setup>` | Options API in new code |
164
+ | Type props/emits with interfaces | `any` types |
165
+ | Create composables for shared logic | Duplicating reactive logic |
166
+ | Use Pinia for global state | Overusing provide/inject |
167
+ | Lazy load routes and components | Bundling everything upfront |
168
+
169
+ ## Project Structure
170
+
171
+ ```
172
+ src/
173
+ ├── App.vue
174
+ ├── main.ts
175
+ ├── components/ # Reusable components
176
+ ├── composables/ # Composition functions
177
+ ├── views/ # Page components
178
+ ├── stores/ # Pinia stores
179
+ ├── router/ # Route definitions
180
+ ├── services/ # API services
181
+ └── types/ # TypeScript types
182
+ ```
183
+
184
+ For detailed examples and patterns, see reference files above.
@@ -1,52 +1,161 @@
1
1
  ---
2
- name: accessibility
3
- description: Accessibility (a11y). Use for WCAG compliance, screen readers, keyboard navigation.
2
+ name: implementing-accessibility
3
+ description: Claude implements WCAG 2.1 AA compliant web interfaces with proper ARIA, keyboard navigation, and screen reader support. Use when building accessible components or auditing existing UIs.
4
4
  ---
5
5
 
6
- # Accessibility Skill
6
+ # Implementing Accessibility
7
7
 
8
- ## Semantic HTML
9
- ```html
10
- <header>
11
- <nav aria-label="Main">
12
- <main>
13
- <article>
14
- <aside>
15
- <footer>
8
+ ## Quick Start
9
+
10
+ ```tsx
11
+ // Accessible dialog with focus trap and ARIA
12
+ export function Dialog({ isOpen, onClose, title, children }: DialogProps) {
13
+ const dialogRef = useRef<HTMLDivElement>(null);
14
+ const titleId = useId();
15
+
16
+ useEffect(() => {
17
+ if (isOpen) {
18
+ dialogRef.current?.focus();
19
+ document.body.style.overflow = 'hidden';
20
+ }
21
+ return () => { document.body.style.overflow = ''; };
22
+ }, [isOpen]);
23
+
24
+ if (!isOpen) return null;
25
+ return createPortal(
26
+ <>
27
+ <div className="dialog-backdrop" onClick={onClose} />
28
+ <div ref={dialogRef} role="dialog" aria-modal="true" aria-labelledby={titleId} tabIndex={-1}>
29
+ <h2 id={titleId}>{title}</h2>
30
+ {children}
31
+ <button onClick={onClose} aria-label="Close dialog">&times;</button>
32
+ </div>
33
+ </>,
34
+ document.body
35
+ );
36
+ }
16
37
  ```
17
38
 
18
- ## ARIA
19
- ```html
20
- <button aria-label="Close" aria-pressed="false">
21
- <div role="alert" aria-live="polite">
22
- <input aria-describedby="hint-id">
39
+ ## Features
40
+
41
+ | Feature | Description | Guide |
42
+ |---------|-------------|-------|
43
+ | Semantic HTML | Proper landmarks, headings, and native elements | `ref/semantic-structure.md` |
44
+ | ARIA Attributes | Roles, states, and properties for custom widgets | `ref/aria-patterns.md` |
45
+ | Keyboard Navigation | Tab order, roving tabindex, keyboard shortcuts | `ref/keyboard-nav.md` |
46
+ | Focus Management | Focus trapping, restoration, visible indicators | `ref/focus-management.md` |
47
+ | Live Regions | Dynamic content announcements for screen readers | `ref/live-regions.md` |
48
+ | Testing | jest-axe, Cypress accessibility, manual testing | `ref/a11y-testing.md` |
49
+
50
+ ## Common Patterns
51
+
52
+ ### Accessible Form Field
53
+
54
+ ```tsx
55
+ export function FormField({ id, label, error, hint, required, ...props }: FormFieldProps) {
56
+ const hintId = hint ? `${id}-hint` : undefined;
57
+ const errorId = error ? `${id}-error` : undefined;
58
+ const describedBy = [hintId, errorId].filter(Boolean).join(' ') || undefined;
59
+
60
+ return (
61
+ <div className={`form-field ${error ? 'has-error' : ''}`}>
62
+ <label htmlFor={id}>
63
+ {label}
64
+ {required && <span aria-hidden="true">*</span>}
65
+ {required && <span className="sr-only">(required)</span>}
66
+ </label>
67
+ {hint && <p id={hintId} className="form-hint">{hint}</p>}
68
+ <input
69
+ id={id}
70
+ aria-required={required}
71
+ aria-invalid={!!error}
72
+ aria-describedby={describedBy}
73
+ {...props}
74
+ />
75
+ {error && <p id={errorId} role="alert">{error}</p>}
76
+ </div>
77
+ );
78
+ }
23
79
  ```
24
80
 
25
- ## Keyboard Navigation
81
+ ### Roving Tabindex for Tab Component
82
+
26
83
  ```tsx
27
- function handleKeyDown(e: KeyboardEvent) {
28
- if (e.key === 'Enter' || e.key === ' ') {
29
- activate();
30
- }
31
- if (e.key === 'Escape') {
32
- close();
33
- }
84
+ export function Tabs({ tabs }: { tabs: Tab[] }) {
85
+ const [activeTab, setActiveTab] = useState(0);
86
+ const tabRefs = useRef<HTMLButtonElement[]>([]);
87
+
88
+ const handleKeyDown = (e: KeyboardEvent, index: number) => {
89
+ let newIndex = index;
90
+ if (e.key === 'ArrowRight') newIndex = (index + 1) % tabs.length;
91
+ if (e.key === 'ArrowLeft') newIndex = (index - 1 + tabs.length) % tabs.length;
92
+ if (e.key === 'Home') newIndex = 0;
93
+ if (e.key === 'End') newIndex = tabs.length - 1;
94
+ if (newIndex !== index) {
95
+ e.preventDefault();
96
+ setActiveTab(newIndex);
97
+ tabRefs.current[newIndex]?.focus();
98
+ }
99
+ };
100
+
101
+ return (
102
+ <div>
103
+ <div role="tablist">
104
+ {tabs.map((tab, i) => (
105
+ <button
106
+ key={tab.id}
107
+ ref={el => tabRefs.current[i] = el!}
108
+ role="tab"
109
+ aria-selected={activeTab === i}
110
+ aria-controls={`panel-${tab.id}`}
111
+ tabIndex={activeTab === i ? 0 : -1}
112
+ onClick={() => setActiveTab(i)}
113
+ onKeyDown={e => handleKeyDown(e, i)}
114
+ >{tab.label}</button>
115
+ ))}
116
+ </div>
117
+ {tabs.map((tab, i) => (
118
+ <div key={tab.id} role="tabpanel" id={`panel-${tab.id}`} hidden={activeTab !== i} tabIndex={0}>
119
+ {tab.content}
120
+ </div>
121
+ ))}
122
+ </div>
123
+ );
34
124
  }
35
125
  ```
36
126
 
37
- ## Focus Management
127
+ ### Live Region Announcer
128
+
38
129
  ```tsx
39
- const ref = useRef<HTMLButtonElement>(null);
130
+ export function useAnnounce() {
131
+ const [message, setMessage] = useState('');
40
132
 
41
- useEffect(() => {
42
- if (isOpen) ref.current?.focus();
43
- }, [isOpen]);
133
+ const announce = useCallback((text: string) => {
134
+ setMessage('');
135
+ requestAnimationFrame(() => setMessage(text));
136
+ setTimeout(() => setMessage(''), 1000);
137
+ }, []);
138
+
139
+ const Announcer = () => (
140
+ <div role="status" aria-live="polite" aria-atomic="true" className="sr-only">
141
+ {message}
142
+ </div>
143
+ );
144
+
145
+ return { announce, Announcer };
146
+ }
147
+
148
+ // Usage: announce('3 results found');
44
149
  ```
45
150
 
46
- ## Checklist
47
- - [ ] Color contrast 4.5:1+
48
- - [ ] Keyboard accessible
49
- - [ ] Focus visible
50
- - [ ] Alt text on images
51
- - [ ] Form labels
52
- - [ ] Skip links
151
+ ## Best Practices
152
+
153
+ | Do | Avoid |
154
+ |----|-------|
155
+ | Use semantic HTML elements (`<button>`, `<nav>`, `<main>`) | Removing focus outlines without replacement |
156
+ | Provide text alternatives for images | Relying on color alone to convey information |
157
+ | Ensure 4.5:1 color contrast for text | Using placeholder as the only label |
158
+ | Associate labels with form controls | Trapping keyboard focus unintentionally |
159
+ | Provide skip links for keyboard users | Auto-playing media with sound |
160
+ | Test with actual screen readers (NVDA, VoiceOver) | Using ARIA when native HTML suffices |
161
+ | Announce dynamic content changes with live regions | Very small touch targets (min 44x44px) |
@@ -1,47 +1,132 @@
1
1
  ---
2
- name: frontend-design
3
- description: Frontend design patterns. Use for component architecture, state management.
2
+ name: designing-frontend-patterns
3
+ description: Claude designs scalable React component architectures using compound components, custom hooks, and state machines. Use when building reusable UI systems or complex component APIs.
4
4
  ---
5
5
 
6
- # Frontend Design Skill
6
+ # Designing Frontend Patterns
7
7
 
8
- ## Component Patterns
8
+ ## Quick Start
9
9
 
10
- ### Compound Components
11
10
  ```tsx
12
- <Select>
13
- <SelectTrigger>Select option</SelectTrigger>
14
- <SelectContent>
15
- <SelectItem value="1">Option 1</SelectItem>
16
- </SelectContent>
17
- </Select>
18
- ```
11
+ // Compound component pattern with context
12
+ const SelectContext = createContext<SelectContextValue | null>(null);
19
13
 
20
- ### Render Props
21
- ```tsx
22
- <DataFetcher url="/api/users">
23
- {({ data, loading }) => loading ? <Spinner /> : <UserList users={data} />}
24
- </DataFetcher>
14
+ export function Select({ children, value, onValueChange }: SelectProps) {
15
+ const [isOpen, setIsOpen] = useState(false);
16
+ return (
17
+ <SelectContext.Provider value={{ isOpen, setIsOpen, value, onValueChange }}>
18
+ <div className="relative">{children}</div>
19
+ </SelectContext.Provider>
20
+ );
21
+ }
22
+
23
+ Select.Trigger = SelectTrigger;
24
+ Select.Content = SelectContent;
25
+ Select.Item = SelectItem;
25
26
  ```
26
27
 
27
- ### Custom Hooks
28
+ ## Features
29
+
30
+ | Feature | Description | Guide |
31
+ |---------|-------------|-------|
32
+ | Compound Components | Shared state via context for flexible component APIs | `ref/compound-components.md` |
33
+ | Custom Hooks | Encapsulate reusable logic (useDebounce, useLocalStorage) | `ref/custom-hooks.md` |
34
+ | Render Props | Maximum flexibility for data fetching and rendering | `ref/render-props.md` |
35
+ | State Machines | Predictable state transitions for complex flows | `ref/state-machines.md` |
36
+ | HOCs | Cross-cutting concerns (auth, error boundaries) | `ref/higher-order-components.md` |
37
+ | Optimistic UI | Instant feedback with rollback on failure | `ref/optimistic-updates.md` |
38
+
39
+ ## Common Patterns
40
+
41
+ ### Custom Hook with Cleanup
42
+
28
43
  ```tsx
29
- function useLocalStorage<T>(key: string, initial: T) {
30
- const [value, setValue] = useState<T>(() => {
31
- const stored = localStorage.getItem(key);
32
- return stored ? JSON.parse(stored) : initial;
44
+ export function useDebounce<T>(value: T, delay: number): T {
45
+ const [debouncedValue, setDebouncedValue] = useState(value);
46
+
47
+ useEffect(() => {
48
+ const timer = setTimeout(() => setDebouncedValue(value), delay);
49
+ return () => clearTimeout(timer);
50
+ }, [value, delay]);
51
+
52
+ return debouncedValue;
53
+ }
54
+
55
+ export function useLocalStorage<T>(key: string, initialValue: T) {
56
+ const [stored, setStored] = useState<T>(() => {
57
+ try {
58
+ const item = window.localStorage.getItem(key);
59
+ return item ? JSON.parse(item) : initialValue;
60
+ } catch { return initialValue; }
33
61
  });
34
62
 
35
63
  useEffect(() => {
36
- localStorage.setItem(key, JSON.stringify(value));
37
- }, [key, value]);
64
+ window.localStorage.setItem(key, JSON.stringify(stored));
65
+ }, [key, stored]);
66
+
67
+ return [stored, setStored] as const;
68
+ }
69
+ ```
70
+
71
+ ### State Machine Pattern
72
+
73
+ ```tsx
74
+ type FormState = 'idle' | 'validating' | 'submitting' | 'success' | 'error';
75
+ type FormEvent =
76
+ | { type: 'SUBMIT'; data: FormData }
77
+ | { type: 'SUCCESS'; response: any }
78
+ | { type: 'ERROR'; error: string };
38
79
 
39
- return [value, setValue] as const;
80
+ function useFormMachine() {
81
+ const [state, setState] = useState<FormState>('idle');
82
+ const [context, setContext] = useState({ data: null, error: null });
83
+
84
+ const send = useCallback((event: FormEvent) => {
85
+ switch (state) {
86
+ case 'idle':
87
+ if (event.type === 'SUBMIT') { setState('validating'); }
88
+ break;
89
+ case 'submitting':
90
+ if (event.type === 'SUCCESS') { setState('success'); }
91
+ if (event.type === 'ERROR') { setState('error'); setContext(c => ({ ...c, error: event.error })); }
92
+ break;
93
+ }
94
+ }, [state]);
95
+
96
+ return { state, context, send };
97
+ }
98
+ ```
99
+
100
+ ### Optimistic Update Hook
101
+
102
+ ```tsx
103
+ export function useOptimistic<T>(initialData: T, reducer: (state: T, action: any) => T) {
104
+ const [state, setState] = useState({ data: initialData, pending: false, error: null });
105
+ const previousRef = useRef(initialData);
106
+
107
+ const optimisticUpdate = useCallback(async (action: any, asyncOp: () => Promise<T>) => {
108
+ previousRef.current = state.data;
109
+ setState({ data: reducer(state.data, action), pending: true, error: null });
110
+
111
+ try {
112
+ const result = await asyncOp();
113
+ setState({ data: result, pending: false, error: null });
114
+ } catch (error) {
115
+ setState({ data: previousRef.current, pending: false, error: error as Error });
116
+ }
117
+ }, [state.data, reducer]);
118
+
119
+ return { ...state, optimisticUpdate };
40
120
  }
41
121
  ```
42
122
 
43
123
  ## Best Practices
44
- - Single responsibility components
45
- - Lift state appropriately
46
- - Colocate related code
47
- - Use composition over inheritance
124
+
125
+ | Do | Avoid |
126
+ |----|-------|
127
+ | Use compound components for complex UI with shared state | Overusing HOCs (prefer hooks) |
128
+ | Create custom hooks to encapsulate reusable logic | Mutating state directly |
129
+ | Implement state machines for complex state transitions | Deeply nested component hierarchies |
130
+ | Use TypeScript for type-safe component APIs | Passing too many props (use context/composition) |
131
+ | Use forwardRef for component library primitives | Creating components with side effects in render |
132
+ | Keep components focused with single responsibility | Prop drilling for deeply nested data |