@brookmind/ai-toolkit 1.0.5 → 1.1.2

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 (152) hide show
  1. package/README.md +60 -14
  2. package/agents/code-reviewer.md +6 -1
  3. package/agents/code-simplifier.md +52 -0
  4. package/dist/index.d.ts.map +1 -1
  5. package/dist/index.js +257 -220
  6. package/dist/index.js.map +1 -1
  7. package/mcps/context7/.mcp.json +13 -0
  8. package/mcps/expo-mcp/.mcp.json +13 -0
  9. package/mcps/figma-mcp/.mcp.json +4 -6
  10. package/package.json +4 -4
  11. package/skills/pdf-processing-pro/FORMS.md +610 -0
  12. package/skills/pdf-processing-pro/OCR.md +137 -0
  13. package/skills/pdf-processing-pro/SKILL.md +296 -0
  14. package/skills/pdf-processing-pro/TABLES.md +626 -0
  15. package/skills/pdf-processing-pro/scripts/analyze_form.py +307 -0
  16. package/skills/react-best-practices/AGENTS.md +915 -0
  17. package/skills/react-best-practices/README.md +127 -0
  18. package/skills/react-best-practices/SKILL.md +110 -0
  19. package/skills/react-best-practices/metadata.json +14 -0
  20. package/skills/react-best-practices/rules/_sections.md +41 -0
  21. package/skills/react-best-practices/rules/_template.md +28 -0
  22. package/skills/react-best-practices/rules/advanced-event-handler-refs.md +80 -0
  23. package/skills/react-best-practices/rules/advanced-use-latest.md +76 -0
  24. package/skills/react-best-practices/rules/async-defer-await.md +80 -0
  25. package/skills/react-best-practices/rules/async-dependencies.md +36 -0
  26. package/skills/react-best-practices/rules/async-parallel.md +28 -0
  27. package/skills/react-best-practices/rules/async-suspense-boundaries.md +100 -0
  28. package/skills/react-best-practices/rules/bundle-barrel-imports.md +42 -0
  29. package/skills/react-best-practices/rules/bundle-conditional.md +106 -0
  30. package/skills/react-best-practices/rules/bundle-preload.md +44 -0
  31. package/skills/react-best-practices/rules/client-event-listeners.md +131 -0
  32. package/skills/react-best-practices/rules/client-swr-dedup.md +133 -0
  33. package/skills/react-best-practices/rules/js-batch-dom-css.md +82 -0
  34. package/skills/react-best-practices/rules/js-cache-function-results.md +80 -0
  35. package/skills/react-best-practices/rules/js-cache-property-access.md +28 -0
  36. package/skills/react-best-practices/rules/js-cache-storage.md +70 -0
  37. package/skills/react-best-practices/rules/js-combine-iterations.md +32 -0
  38. package/skills/react-best-practices/rules/js-early-exit.md +50 -0
  39. package/skills/react-best-practices/rules/js-hoist-regexp.md +45 -0
  40. package/skills/react-best-practices/rules/js-index-maps.md +37 -0
  41. package/skills/react-best-practices/rules/js-length-check-first.md +49 -0
  42. package/skills/react-best-practices/rules/js-min-max-loop.md +82 -0
  43. package/skills/react-best-practices/rules/js-set-map-lookups.md +24 -0
  44. package/skills/react-best-practices/rules/js-tosorted-immutable.md +57 -0
  45. package/skills/react-best-practices/rules/rendering-activity.md +90 -0
  46. package/skills/react-best-practices/rules/rendering-animate-svg-wrapper.md +47 -0
  47. package/skills/react-best-practices/rules/rendering-conditional-render.md +40 -0
  48. package/skills/react-best-practices/rules/rendering-content-visibility.md +38 -0
  49. package/skills/react-best-practices/rules/rendering-hoist-jsx.md +65 -0
  50. package/skills/react-best-practices/rules/rendering-svg-precision.md +28 -0
  51. package/skills/react-best-practices/rules/rerender-defer-reads.md +39 -0
  52. package/skills/react-best-practices/rules/rerender-dependencies.md +45 -0
  53. package/skills/react-best-practices/rules/rerender-derived-state.md +29 -0
  54. package/skills/react-best-practices/rules/rerender-functional-setstate.md +74 -0
  55. package/skills/react-best-practices/rules/rerender-lazy-state-init.md +58 -0
  56. package/skills/react-best-practices/rules/rerender-memo.md +85 -0
  57. package/skills/react-best-practices/rules/rerender-transitions.md +40 -0
  58. package/themes/README.md +68 -0
  59. package/themes/claude-vivid.json +72 -0
  60. package/mcps/context7/.claude-plugin +0 -1
  61. package/mcps/context7/README.md +0 -1
  62. package/mcps/context7/server.json +0 -1
  63. package/mcps/expo-mcp/README.md +0 -33
  64. package/mcps/expo-mcp/package.json +0 -30
  65. package/mcps/figma-mcp/README.md +0 -554
  66. package/mcps/figma-mcp/server.json +0 -17
  67. package/mcps/figma-mcp/skills/code-connect-components +0 -1
  68. package/mcps/figma-mcp/skills/create-design-system-rules +0 -1
  69. package/mcps/figma-mcp/skills/implement-design +0 -1
  70. package/mcps/pg-aiguide/.claude-plugin +0 -1
  71. package/mcps/pg-aiguide/CLAUDE.md +0 -21
  72. package/mcps/pg-aiguide/README.md +0 -275
  73. package/mcps/pg-aiguide/skills/design-postgres-tables +0 -1
  74. package/mcps/pg-aiguide/skills/find-hypertable-candidates +0 -1
  75. package/mcps/pg-aiguide/skills/migrate-postgres-tables-to-hypertables +0 -1
  76. package/mcps/pg-aiguide/skills/setup-timescaledb-hypertables +0 -1
  77. package/mcps/pg-aiguide/skills.yaml +0 -4
  78. package/skills/cloudflare-cli/SKILL.md +0 -151
  79. package/skills/docx/LICENSE.txt +0 -30
  80. package/skills/docx/SKILL.md +0 -197
  81. package/skills/docx/docx-js.md +0 -350
  82. package/skills/docx/ooxml/schemas/ISO-IEC29500-4_2016/dml-chart.xsd +0 -1499
  83. package/skills/docx/ooxml/schemas/ISO-IEC29500-4_2016/dml-chartDrawing.xsd +0 -146
  84. package/skills/docx/ooxml/schemas/ISO-IEC29500-4_2016/dml-diagram.xsd +0 -1085
  85. package/skills/docx/ooxml/schemas/ISO-IEC29500-4_2016/dml-lockedCanvas.xsd +0 -11
  86. package/skills/docx/ooxml/schemas/ISO-IEC29500-4_2016/dml-main.xsd +0 -3081
  87. package/skills/docx/ooxml/schemas/ISO-IEC29500-4_2016/dml-picture.xsd +0 -23
  88. package/skills/docx/ooxml/schemas/ISO-IEC29500-4_2016/dml-spreadsheetDrawing.xsd +0 -185
  89. package/skills/docx/ooxml/schemas/ISO-IEC29500-4_2016/dml-wordprocessingDrawing.xsd +0 -287
  90. package/skills/docx/ooxml/schemas/ISO-IEC29500-4_2016/pml.xsd +0 -1676
  91. package/skills/docx/ooxml/schemas/ISO-IEC29500-4_2016/shared-additionalCharacteristics.xsd +0 -28
  92. package/skills/docx/ooxml/schemas/ISO-IEC29500-4_2016/shared-bibliography.xsd +0 -144
  93. package/skills/docx/ooxml/schemas/ISO-IEC29500-4_2016/shared-commonSimpleTypes.xsd +0 -174
  94. package/skills/docx/ooxml/schemas/ISO-IEC29500-4_2016/shared-customXmlDataProperties.xsd +0 -25
  95. package/skills/docx/ooxml/schemas/ISO-IEC29500-4_2016/shared-customXmlSchemaProperties.xsd +0 -18
  96. package/skills/docx/ooxml/schemas/ISO-IEC29500-4_2016/shared-documentPropertiesCustom.xsd +0 -59
  97. package/skills/docx/ooxml/schemas/ISO-IEC29500-4_2016/shared-documentPropertiesExtended.xsd +0 -56
  98. package/skills/docx/ooxml/schemas/ISO-IEC29500-4_2016/shared-documentPropertiesVariantTypes.xsd +0 -195
  99. package/skills/docx/ooxml/schemas/ISO-IEC29500-4_2016/shared-math.xsd +0 -582
  100. package/skills/docx/ooxml/schemas/ISO-IEC29500-4_2016/shared-relationshipReference.xsd +0 -25
  101. package/skills/docx/ooxml/schemas/ISO-IEC29500-4_2016/sml.xsd +0 -4439
  102. package/skills/docx/ooxml/schemas/ISO-IEC29500-4_2016/vml-main.xsd +0 -570
  103. package/skills/docx/ooxml/schemas/ISO-IEC29500-4_2016/vml-officeDrawing.xsd +0 -509
  104. package/skills/docx/ooxml/schemas/ISO-IEC29500-4_2016/vml-presentationDrawing.xsd +0 -12
  105. package/skills/docx/ooxml/schemas/ISO-IEC29500-4_2016/vml-spreadsheetDrawing.xsd +0 -108
  106. package/skills/docx/ooxml/schemas/ISO-IEC29500-4_2016/vml-wordprocessingDrawing.xsd +0 -96
  107. package/skills/docx/ooxml/schemas/ISO-IEC29500-4_2016/wml.xsd +0 -3646
  108. package/skills/docx/ooxml/schemas/ISO-IEC29500-4_2016/xml.xsd +0 -116
  109. package/skills/docx/ooxml/schemas/ecma/fouth-edition/opc-contentTypes.xsd +0 -42
  110. package/skills/docx/ooxml/schemas/ecma/fouth-edition/opc-coreProperties.xsd +0 -50
  111. package/skills/docx/ooxml/schemas/ecma/fouth-edition/opc-digSig.xsd +0 -49
  112. package/skills/docx/ooxml/schemas/ecma/fouth-edition/opc-relationships.xsd +0 -33
  113. package/skills/docx/ooxml/schemas/mce/mc.xsd +0 -75
  114. package/skills/docx/ooxml/schemas/microsoft/wml-2010.xsd +0 -560
  115. package/skills/docx/ooxml/schemas/microsoft/wml-2012.xsd +0 -67
  116. package/skills/docx/ooxml/schemas/microsoft/wml-2018.xsd +0 -14
  117. package/skills/docx/ooxml/schemas/microsoft/wml-cex-2018.xsd +0 -20
  118. package/skills/docx/ooxml/schemas/microsoft/wml-cid-2016.xsd +0 -13
  119. package/skills/docx/ooxml/schemas/microsoft/wml-sdtdatahash-2020.xsd +0 -4
  120. package/skills/docx/ooxml/schemas/microsoft/wml-symex-2015.xsd +0 -8
  121. package/skills/docx/ooxml/scripts/pack.py +0 -159
  122. package/skills/docx/ooxml/scripts/unpack.py +0 -29
  123. package/skills/docx/ooxml/scripts/validate.py +0 -69
  124. package/skills/docx/ooxml/scripts/validation/__init__.py +0 -15
  125. package/skills/docx/ooxml/scripts/validation/base.py +0 -951
  126. package/skills/docx/ooxml/scripts/validation/docx.py +0 -274
  127. package/skills/docx/ooxml/scripts/validation/pptx.py +0 -315
  128. package/skills/docx/ooxml/scripts/validation/redlining.py +0 -279
  129. package/skills/docx/ooxml.md +0 -610
  130. package/skills/docx/scripts/__init__.py +0 -1
  131. package/skills/docx/scripts/document.py +0 -1276
  132. package/skills/docx/scripts/templates/comments.xml +0 -3
  133. package/skills/docx/scripts/templates/commentsExtended.xml +0 -3
  134. package/skills/docx/scripts/templates/commentsExtensible.xml +0 -3
  135. package/skills/docx/scripts/templates/commentsIds.xml +0 -3
  136. package/skills/docx/scripts/templates/people.xml +0 -3
  137. package/skills/docx/scripts/utilities.py +0 -374
  138. package/skills/pdf/LICENSE.txt +0 -30
  139. package/skills/pdf/SKILL.md +0 -294
  140. package/skills/pdf/forms.md +0 -205
  141. package/skills/pdf/reference.md +0 -612
  142. package/skills/pdf/scripts/check_bounding_boxes.py +0 -70
  143. package/skills/pdf/scripts/check_bounding_boxes_test.py +0 -226
  144. package/skills/pdf/scripts/check_fillable_fields.py +0 -12
  145. package/skills/pdf/scripts/convert_pdf_to_images.py +0 -35
  146. package/skills/pdf/scripts/create_validation_image.py +0 -41
  147. package/skills/pdf/scripts/extract_form_field_info.py +0 -152
  148. package/skills/pdf/scripts/fill_fillable_fields.py +0 -114
  149. package/skills/pdf/scripts/fill_pdf_form_with_annotations.py +0 -108
  150. package/skills/xlsx/LICENSE.txt +0 -30
  151. package/skills/xlsx/SKILL.md +0 -289
  152. package/skills/xlsx/recalc.py +0 -178
@@ -0,0 +1,40 @@
1
+ ---
2
+ title: Use Explicit Conditional Rendering
3
+ impact: LOW
4
+ impactDescription: prevents rendering 0 or NaN
5
+ tags: rendering, conditional, jsx, falsy-values
6
+ ---
7
+
8
+ ## Use Explicit Conditional Rendering
9
+
10
+ Use explicit ternary operators (`? :`) instead of `&&` for conditional rendering when the condition can be `0`, `NaN`, or other falsy values that render.
11
+
12
+ **Incorrect (renders "0" when count is 0):**
13
+
14
+ ```tsx
15
+ function Badge({ count }: { count: number }) {
16
+ return (
17
+ <div>
18
+ {count && <span className="badge">{count}</span>}
19
+ </div>
20
+ )
21
+ }
22
+
23
+ // When count = 0, renders: <div>0</div>
24
+ // When count = 5, renders: <div><span class="badge">5</span></div>
25
+ ```
26
+
27
+ **Correct (renders nothing when count is 0):**
28
+
29
+ ```tsx
30
+ function Badge({ count }: { count: number }) {
31
+ return (
32
+ <div>
33
+ {count > 0 ? <span className="badge">{count}</span> : null}
34
+ </div>
35
+ )
36
+ }
37
+
38
+ // When count = 0, renders: <div></div>
39
+ // When count = 5, renders: <div><span class="badge">5</span></div>
40
+ ```
@@ -0,0 +1,38 @@
1
+ ---
2
+ title: CSS content-visibility for Long Lists
3
+ impact: HIGH
4
+ impactDescription: faster initial render
5
+ tags: rendering, css, content-visibility, long-lists
6
+ ---
7
+
8
+ ## CSS content-visibility for Long Lists
9
+
10
+ Apply `content-visibility: auto` to defer off-screen rendering.
11
+
12
+ **CSS:**
13
+
14
+ ```css
15
+ .message-item {
16
+ content-visibility: auto;
17
+ contain-intrinsic-size: 0 80px;
18
+ }
19
+ ```
20
+
21
+ **Example:**
22
+
23
+ ```tsx
24
+ function MessageList({ messages }: { messages: Message[] }) {
25
+ return (
26
+ <div className="overflow-y-auto h-screen">
27
+ {messages.map(msg => (
28
+ <div key={msg.id} className="message-item">
29
+ <Avatar user={msg.author} />
30
+ <div>{msg.content}</div>
31
+ </div>
32
+ ))}
33
+ </div>
34
+ )
35
+ }
36
+ ```
37
+
38
+ For 1000 messages, browser skips layout/paint for ~990 off-screen items (10× faster initial render).
@@ -0,0 +1,65 @@
1
+ ---
2
+ title: Hoist Static JSX Elements
3
+ impact: LOW
4
+ impactDescription: avoids re-creation
5
+ tags: rendering, jsx, static, react-compiler, optimization
6
+ ---
7
+
8
+ ## Hoist Static JSX Elements
9
+
10
+ With React 19 Compiler, static JSX is automatically hoisted. Without the Compiler, manually extract static JSX outside components to avoid re-creation.
11
+
12
+ **With React 19 Compiler (Recommended):**
13
+
14
+ The React Compiler automatically detects and hoists static JSX. Just write normal components:
15
+
16
+ ```tsx
17
+ function LoadingSkeleton() {
18
+ return <div className="animate-pulse h-20 bg-gray-200" />;
19
+ }
20
+
21
+ function Container({ loading }: { loading: boolean }) {
22
+ return <div>{loading && <LoadingSkeleton />}</div>;
23
+ }
24
+ // Compiler automatically optimizes this!
25
+ ```
26
+
27
+ **Without React Compiler (Manual Optimization):**
28
+
29
+ If you're not using the Compiler, manually hoist static elements:
30
+
31
+ **Before (recreates element every render):**
32
+
33
+ ```tsx
34
+ function Container({ loading }: { loading: boolean }) {
35
+ // This JSX is recreated on every render
36
+ const skeleton = <div className="animate-pulse h-20 bg-gray-200" />;
37
+
38
+ return <div>{loading && skeleton}</div>;
39
+ }
40
+ ```
41
+
42
+ **After (reuses same element):**
43
+
44
+ ```tsx
45
+ // Hoisted to module scope - created once
46
+ const loadingSkeleton = <div className="animate-pulse h-20 bg-gray-200" />;
47
+
48
+ function Container({ loading }: { loading: boolean }) {
49
+ return <div>{loading && loadingSkeleton}</div>;
50
+ }
51
+ ```
52
+
53
+ **Best use cases for manual hoisting:**
54
+
55
+ - Large static SVG icons (expensive to recreate)
56
+ - Complex static layouts that never change
57
+ - Decorative elements with no dynamic props
58
+
59
+ **When NOT to hoist:**
60
+
61
+ - Elements with dynamic props or children
62
+ - Elements that need access to component scope (hooks, state)
63
+ - Small simple elements (overhead not worth it)
64
+
65
+ Reference: [React Compiler](https://react.dev/learn/react-compiler)
@@ -0,0 +1,28 @@
1
+ ---
2
+ title: Optimize SVG Precision
3
+ impact: LOW
4
+ impactDescription: reduces file size
5
+ tags: rendering, svg, optimization, svgo
6
+ ---
7
+
8
+ ## Optimize SVG Precision
9
+
10
+ Reduce SVG coordinate precision to decrease file size. The optimal precision depends on the viewBox size, but in general reducing precision should be considered.
11
+
12
+ **Incorrect (excessive precision):**
13
+
14
+ ```svg
15
+ <path d="M 10.293847 20.847362 L 30.938472 40.192837" />
16
+ ```
17
+
18
+ **Correct (1 decimal place):**
19
+
20
+ ```svg
21
+ <path d="M 10.3 20.8 L 30.9 40.2" />
22
+ ```
23
+
24
+ **Automate with SVGO:**
25
+
26
+ ```bash
27
+ npx svgo --precision=1 --multipass icon.svg
28
+ ```
@@ -0,0 +1,39 @@
1
+ ---
2
+ title: Defer State Reads to Usage Point
3
+ impact: MEDIUM
4
+ impactDescription: avoids unnecessary subscriptions
5
+ tags: rerender, searchParams, localStorage, optimization
6
+ ---
7
+
8
+ ## Defer State Reads to Usage Point
9
+
10
+ Don't subscribe to dynamic state (searchParams, localStorage) if you only read it inside callbacks.
11
+
12
+ **Incorrect (subscribes to all searchParams changes):**
13
+
14
+ ```tsx
15
+ function ShareButton({ chatId }: { chatId: string }) {
16
+ const searchParams = useSearchParams()
17
+
18
+ const handleShare = () => {
19
+ const ref = searchParams.get('ref')
20
+ shareChat(chatId, { ref })
21
+ }
22
+
23
+ return <button onClick={handleShare}>Share</button>
24
+ }
25
+ ```
26
+
27
+ **Correct (reads on demand, no subscription):**
28
+
29
+ ```tsx
30
+ function ShareButton({ chatId }: { chatId: string }) {
31
+ const handleShare = () => {
32
+ const params = new URLSearchParams(window.location.search)
33
+ const ref = params.get('ref')
34
+ shareChat(chatId, { ref })
35
+ }
36
+
37
+ return <button onClick={handleShare}>Share</button>
38
+ }
39
+ ```
@@ -0,0 +1,45 @@
1
+ ---
2
+ title: Narrow Effect Dependencies
3
+ impact: LOW
4
+ impactDescription: minimizes effect re-runs
5
+ tags: rerender, useEffect, dependencies, optimization
6
+ ---
7
+
8
+ ## Narrow Effect Dependencies
9
+
10
+ Specify primitive dependencies instead of objects to minimize effect re-runs.
11
+
12
+ **Incorrect (re-runs on any user field change):**
13
+
14
+ ```tsx
15
+ useEffect(() => {
16
+ console.log(user.id)
17
+ }, [user])
18
+ ```
19
+
20
+ **Correct (re-runs only when id changes):**
21
+
22
+ ```tsx
23
+ useEffect(() => {
24
+ console.log(user.id)
25
+ }, [user.id])
26
+ ```
27
+
28
+ **For derived state, compute outside effect:**
29
+
30
+ ```tsx
31
+ // Incorrect: runs on width=767, 766, 765...
32
+ useEffect(() => {
33
+ if (width < 768) {
34
+ enableMobileMode()
35
+ }
36
+ }, [width])
37
+
38
+ // Correct: runs only on boolean transition
39
+ const isMobile = width < 768
40
+ useEffect(() => {
41
+ if (isMobile) {
42
+ enableMobileMode()
43
+ }
44
+ }, [isMobile])
45
+ ```
@@ -0,0 +1,29 @@
1
+ ---
2
+ title: Subscribe to Derived State
3
+ impact: MEDIUM
4
+ impactDescription: reduces re-render frequency
5
+ tags: rerender, derived-state, media-query, optimization
6
+ ---
7
+
8
+ ## Subscribe to Derived State
9
+
10
+ Subscribe to derived boolean state instead of continuous values to reduce re-render frequency.
11
+
12
+ **Incorrect (re-renders on every pixel change):**
13
+
14
+ ```tsx
15
+ function Sidebar() {
16
+ const width = useWindowWidth() // updates continuously
17
+ const isMobile = width < 768
18
+ return <nav className={isMobile ? 'mobile' : 'desktop'}>
19
+ }
20
+ ```
21
+
22
+ **Correct (re-renders only when boolean changes):**
23
+
24
+ ```tsx
25
+ function Sidebar() {
26
+ const isMobile = useMediaQuery('(max-width: 767px)')
27
+ return <nav className={isMobile ? 'mobile' : 'desktop'}>
28
+ }
29
+ ```
@@ -0,0 +1,74 @@
1
+ ---
2
+ title: Use Functional setState Updates
3
+ impact: MEDIUM
4
+ impactDescription: prevents stale closures and unnecessary callback recreations
5
+ tags: react, hooks, useState, useCallback, callbacks, closures
6
+ ---
7
+
8
+ ## Use Functional setState Updates
9
+
10
+ When updating state based on the current state value, use the functional update form of setState instead of directly referencing the state variable. This prevents stale closures, eliminates unnecessary dependencies, and creates stable callback references.
11
+
12
+ **Incorrect (requires state as dependency):**
13
+
14
+ ```tsx
15
+ function TodoList() {
16
+ const [items, setItems] = useState(initialItems)
17
+
18
+ // Callback must depend on items, recreated on every items change
19
+ const addItems = useCallback((newItems: Item[]) => {
20
+ setItems([...items, ...newItems])
21
+ }, [items]) // ❌ items dependency causes recreations
22
+
23
+ // Risk of stale closure if dependency is forgotten
24
+ const removeItem = useCallback((id: string) => {
25
+ setItems(items.filter(item => item.id !== id))
26
+ }, []) // ❌ Missing items dependency - will use stale items!
27
+
28
+ return <ItemsEditor items={items} onAdd={addItems} onRemove={removeItem} />
29
+ }
30
+ ```
31
+
32
+ The first callback is recreated every time `items` changes, which can cause child components to re-render unnecessarily. The second callback has a stale closure bug—it will always reference the initial `items` value.
33
+
34
+ **Correct (stable callbacks, no stale closures):**
35
+
36
+ ```tsx
37
+ function TodoList() {
38
+ const [items, setItems] = useState(initialItems)
39
+
40
+ // Stable callback, never recreated
41
+ const addItems = useCallback((newItems: Item[]) => {
42
+ setItems(curr => [...curr, ...newItems])
43
+ }, []) // ✅ No dependencies needed
44
+
45
+ // Always uses latest state, no stale closure risk
46
+ const removeItem = useCallback((id: string) => {
47
+ setItems(curr => curr.filter(item => item.id !== id))
48
+ }, []) // ✅ Safe and stable
49
+
50
+ return <ItemsEditor items={items} onAdd={addItems} onRemove={removeItem} />
51
+ }
52
+ ```
53
+
54
+ **Benefits:**
55
+
56
+ 1. **Stable callback references** - Callbacks don't need to be recreated when state changes
57
+ 2. **No stale closures** - Always operates on the latest state value
58
+ 3. **Fewer dependencies** - Simplifies dependency arrays and reduces memory leaks
59
+ 4. **Prevents bugs** - Eliminates the most common source of React closure bugs
60
+
61
+ **When to use functional updates:**
62
+
63
+ - Any setState that depends on the current state value
64
+ - Inside useCallback/useMemo when state is needed
65
+ - Event handlers that reference state
66
+ - Async operations that update state
67
+
68
+ **When direct updates are fine:**
69
+
70
+ - Setting state to a static value: `setCount(0)`
71
+ - Setting state from props/arguments only: `setName(newName)`
72
+ - State doesn't depend on previous value
73
+
74
+ **Note:** If your project has [React Compiler](https://react.dev/learn/react-compiler) enabled, the compiler can automatically optimize some cases, but functional updates are still recommended for correctness and to prevent stale closure bugs.
@@ -0,0 +1,58 @@
1
+ ---
2
+ title: Use Lazy State Initialization
3
+ impact: MEDIUM
4
+ impactDescription: wasted computation on every render
5
+ tags: react, hooks, useState, performance, initialization
6
+ ---
7
+
8
+ ## Use Lazy State Initialization
9
+
10
+ Pass a function to `useState` for expensive initial values. Without the function form, the initializer runs on every render even though the value is only used once.
11
+
12
+ **Incorrect (runs on every render):**
13
+
14
+ ```tsx
15
+ function FilteredList({ items }: { items: Item[] }) {
16
+ // buildSearchIndex() runs on EVERY render, even after initialization
17
+ const [searchIndex, setSearchIndex] = useState(buildSearchIndex(items))
18
+ const [query, setQuery] = useState('')
19
+
20
+ // When query changes, buildSearchIndex runs again unnecessarily
21
+ return <SearchResults index={searchIndex} query={query} />
22
+ }
23
+
24
+ function UserProfile() {
25
+ // JSON.parse runs on every render
26
+ const [settings, setSettings] = useState(
27
+ JSON.parse(localStorage.getItem('settings') || '{}')
28
+ )
29
+
30
+ return <SettingsForm settings={settings} onChange={setSettings} />
31
+ }
32
+ ```
33
+
34
+ **Correct (runs only once):**
35
+
36
+ ```tsx
37
+ function FilteredList({ items }: { items: Item[] }) {
38
+ // buildSearchIndex() runs ONLY on initial render
39
+ const [searchIndex, setSearchIndex] = useState(() => buildSearchIndex(items))
40
+ const [query, setQuery] = useState('')
41
+
42
+ return <SearchResults index={searchIndex} query={query} />
43
+ }
44
+
45
+ function UserProfile() {
46
+ // JSON.parse runs only on initial render
47
+ const [settings, setSettings] = useState(() => {
48
+ const stored = localStorage.getItem('settings')
49
+ return stored ? JSON.parse(stored) : {}
50
+ })
51
+
52
+ return <SettingsForm settings={settings} onChange={setSettings} />
53
+ }
54
+ ```
55
+
56
+ Use lazy initialization when computing initial values from localStorage/sessionStorage, building data structures (indexes, maps), reading from the DOM, or performing heavy transformations.
57
+
58
+ For simple primitives (`useState(0)`), direct references (`useState(props.value)`), or cheap literals (`useState({})`), the function form is unnecessary.
@@ -0,0 +1,85 @@
1
+ ---
2
+ title: Extract to Memoized Components
3
+ impact: MEDIUM
4
+ impactDescription: enables early returns and skips computation
5
+ tags: rerender, memo, useMemo, react-compiler, optimization
6
+ ---
7
+
8
+ ## Extract to Memoized Components
9
+
10
+ Extract expensive work into separate components to enable early returns before computation. With React 19 Compiler, this happens automatically.
11
+
12
+ **With React 19 Compiler (Recommended):**
13
+
14
+ If your project has [React Compiler](https://react.dev/learn/react-compiler) enabled, you don't need manual memoization. The compiler automatically:
15
+
16
+ - Memoizes component renders
17
+ - Caches expensive computations
18
+ - Optimizes re-renders
19
+
20
+ Just write clean code without `memo()` or `useMemo()`:
21
+
22
+ ```tsx
23
+ function UserAvatar({ user }: { user: User }) {
24
+ const id = computeAvatarId(user); // Compiler auto-memoizes
25
+ return <Avatar id={id} />;
26
+ }
27
+
28
+ function Profile({ user, loading }: Props) {
29
+ if (loading) return <Skeleton />;
30
+ return (
31
+ <div>
32
+ <UserAvatar user={user} /> {/* Compiler auto-memoizes */}
33
+ </div>
34
+ );
35
+ }
36
+ ```
37
+
38
+ **Without React Compiler (Manual Optimization):**
39
+
40
+ If you're not using the React Compiler, use `memo()` and `useMemo()` manually:
41
+
42
+ **Incorrect (computes avatar even when loading):**
43
+
44
+ ```tsx
45
+ function Profile({ user, loading }: Props) {
46
+ // This runs on every render, even when loading=true
47
+ const avatar = useMemo(() => {
48
+ const id = computeAvatarId(user);
49
+ return <Avatar id={id} />;
50
+ }, [user]);
51
+
52
+ if (loading) return <Skeleton />;
53
+ return <div>{avatar}</div>;
54
+ }
55
+ ```
56
+
57
+ **Correct (skips computation when loading):**
58
+
59
+ ```tsx
60
+ const UserAvatar = memo(function UserAvatar({ user }: { user: User }) {
61
+ const id = useMemo(() => computeAvatarId(user), [user]);
62
+ return <Avatar id={id} />;
63
+ });
64
+
65
+ function Profile({ user, loading }: Props) {
66
+ if (loading) return <Skeleton />;
67
+ return (
68
+ <div>
69
+ <UserAvatar user={user} />
70
+ </div>
71
+ );
72
+ }
73
+ ```
74
+
75
+ **Key insight:** Early returns before component JSX skip that component's computation entirely. Extract expensive work into child components that appear after conditionals.
76
+
77
+ **When to still use memo() with Compiler:**
78
+
79
+ Even with the Compiler, `memo()` can be useful for:
80
+
81
+ - Components receiving frequently-changing callback props
82
+ - Components in lists with stable item identity
83
+ - Performance-critical components where you want explicit control
84
+
85
+ Reference: [React Compiler](https://react.dev/learn/react-compiler)
@@ -0,0 +1,40 @@
1
+ ---
2
+ title: Use Transitions for Non-Urgent Updates
3
+ impact: MEDIUM
4
+ impactDescription: maintains UI responsiveness
5
+ tags: rerender, transitions, startTransition, performance
6
+ ---
7
+
8
+ ## Use Transitions for Non-Urgent Updates
9
+
10
+ Mark frequent, non-urgent state updates as transitions to maintain UI responsiveness.
11
+
12
+ **Incorrect (blocks UI on every scroll):**
13
+
14
+ ```tsx
15
+ function ScrollTracker() {
16
+ const [scrollY, setScrollY] = useState(0)
17
+ useEffect(() => {
18
+ const handler = () => setScrollY(window.scrollY)
19
+ window.addEventListener('scroll', handler, { passive: true })
20
+ return () => window.removeEventListener('scroll', handler)
21
+ }, [])
22
+ }
23
+ ```
24
+
25
+ **Correct (non-blocking updates):**
26
+
27
+ ```tsx
28
+ import { startTransition } from 'react'
29
+
30
+ function ScrollTracker() {
31
+ const [scrollY, setScrollY] = useState(0)
32
+ useEffect(() => {
33
+ const handler = () => {
34
+ startTransition(() => setScrollY(window.scrollY))
35
+ }
36
+ window.addEventListener('scroll', handler, { passive: true })
37
+ return () => window.removeEventListener('scroll', handler)
38
+ }, [])
39
+ }
40
+ ```
@@ -0,0 +1,68 @@
1
+ # Claude Vivid Theme
2
+
3
+ A vibrant, high-contrast theme for OpenCode inspired by Claude Code's aesthetic.
4
+
5
+ ## Features
6
+
7
+ - **Pure black background** (#000000) for maximum contrast
8
+ - **Vivid syntax highlighting** with bright, saturated colors
9
+ - **Neutral menu interactions** - Gray selection highlights instead of orange
10
+ - **Optimized for dark mode** terminal usage
11
+
12
+ ## Color Palette
13
+
14
+ ### Primary Colors
15
+ - Orange: `#FF6B35` - Headings, variables
16
+ - Purple: `#A855F7` - Keywords
17
+ - Cyan: `#22D3EE` - Functions, links
18
+ - Green: `#4ADE80` - Strings, success states
19
+ - Yellow: `#FACC15` - Types, warnings
20
+ - Pink: `#EC4899` - Numbers
21
+ - Red: `#EF4444` - Errors
22
+
23
+ ### UI Colors
24
+ - Background: `#000000` (pure black)
25
+ - Panel: `#0a0a0a` (almost black)
26
+ - Elements: `#1a1a1a` (very dark gray)
27
+ - Borders: `#2a2a2a` (dark gray)
28
+ - Selection: `#E5E5E5` (light gray - neutral)
29
+
30
+ ## Installation
31
+
32
+ This theme is automatically installed when you run the AI Toolkit installer. It will be copied to `~/.config/opencode/themes/claude-vivid.json` and configured in your `opencode.json`.
33
+
34
+ ## Manual Installation
35
+
36
+ If you want to install it manually:
37
+
38
+ 1. Create the themes directory:
39
+ ```bash
40
+ mkdir -p ~/.config/opencode/themes
41
+ ```
42
+
43
+ 2. Copy the theme file:
44
+ ```bash
45
+ cp themes/claude-vivid.json ~/.config/opencode/themes/
46
+ ```
47
+
48
+ 3. Update your `~/.config/opencode/opencode.json`:
49
+ ```json
50
+ {
51
+ "$schema": "https://opencode.ai/config.json",
52
+ "theme": "claude-vivid"
53
+ }
54
+ ```
55
+
56
+ 4. Restart OpenCode or run `/theme claude-vivid`
57
+
58
+ ## Customization
59
+
60
+ You can modify the theme by editing `~/.config/opencode/themes/claude-vivid.json`. All colors use the OpenCode theme schema with support for:
61
+
62
+ - Hex colors: `"#ffffff"`
63
+ - Color references: `"orange"` (defined in `defs`)
64
+ - Dark/light variants: `{"dark": "#000", "light": "#fff"}`
65
+
66
+ ## Credits
67
+
68
+ Created for the OpenCode AI Toolkit by @davidcastillog