@peaske7/readit 0.1.4 → 0.1.5

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 (320) hide show
  1. package/.agents/skills/remotion-best-practices/SKILL.md +61 -0
  2. package/.agents/skills/remotion-best-practices/rules/3d.md +86 -0
  3. package/.agents/skills/remotion-best-practices/rules/animations.md +27 -0
  4. package/.agents/skills/remotion-best-practices/rules/assets/charts-bar-chart.tsx +178 -0
  5. package/.agents/skills/remotion-best-practices/rules/assets/text-animations-typewriter.tsx +100 -0
  6. package/.agents/skills/remotion-best-practices/rules/assets/text-animations-word-highlight.tsx +108 -0
  7. package/.agents/skills/remotion-best-practices/rules/assets.md +78 -0
  8. package/.agents/skills/remotion-best-practices/rules/audio-visualization.md +198 -0
  9. package/.agents/skills/remotion-best-practices/rules/audio.md +169 -0
  10. package/.agents/skills/remotion-best-practices/rules/calculate-metadata.md +134 -0
  11. package/.agents/skills/remotion-best-practices/rules/can-decode.md +75 -0
  12. package/.agents/skills/remotion-best-practices/rules/charts.md +120 -0
  13. package/.agents/skills/remotion-best-practices/rules/compositions.md +154 -0
  14. package/.agents/skills/remotion-best-practices/rules/display-captions.md +184 -0
  15. package/.agents/skills/remotion-best-practices/rules/extract-frames.md +229 -0
  16. package/.agents/skills/remotion-best-practices/rules/ffmpeg.md +38 -0
  17. package/.agents/skills/remotion-best-practices/rules/fonts.md +152 -0
  18. package/.agents/skills/remotion-best-practices/rules/get-audio-duration.md +58 -0
  19. package/.agents/skills/remotion-best-practices/rules/get-video-dimensions.md +68 -0
  20. package/.agents/skills/remotion-best-practices/rules/get-video-duration.md +60 -0
  21. package/.agents/skills/remotion-best-practices/rules/gifs.md +141 -0
  22. package/.agents/skills/remotion-best-practices/rules/images.md +134 -0
  23. package/.agents/skills/remotion-best-practices/rules/import-srt-captions.md +69 -0
  24. package/.agents/skills/remotion-best-practices/rules/light-leaks.md +73 -0
  25. package/.agents/skills/remotion-best-practices/rules/lottie.md +70 -0
  26. package/.agents/skills/remotion-best-practices/rules/maps.md +412 -0
  27. package/.agents/skills/remotion-best-practices/rules/measuring-dom-nodes.md +34 -0
  28. package/.agents/skills/remotion-best-practices/rules/measuring-text.md +140 -0
  29. package/.agents/skills/remotion-best-practices/rules/parameters.md +109 -0
  30. package/.agents/skills/remotion-best-practices/rules/sequencing.md +118 -0
  31. package/.agents/skills/remotion-best-practices/rules/sfx.md +26 -0
  32. package/.agents/skills/remotion-best-practices/rules/subtitles.md +36 -0
  33. package/.agents/skills/remotion-best-practices/rules/tailwind.md +11 -0
  34. package/.agents/skills/remotion-best-practices/rules/text-animations.md +20 -0
  35. package/.agents/skills/remotion-best-practices/rules/timing.md +179 -0
  36. package/.agents/skills/remotion-best-practices/rules/transcribe-captions.md +70 -0
  37. package/.agents/skills/remotion-best-practices/rules/transitions.md +197 -0
  38. package/.agents/skills/remotion-best-practices/rules/transparent-videos.md +106 -0
  39. package/.agents/skills/remotion-best-practices/rules/trimming.md +51 -0
  40. package/.agents/skills/remotion-best-practices/rules/videos.md +171 -0
  41. package/.agents/skills/remotion-best-practices/rules/voiceover.md +99 -0
  42. package/.agents/skills/simple/SKILL.md +52 -0
  43. package/.agents/skills/vercel-react-best-practices/AGENTS.md +3254 -0
  44. package/.agents/skills/vercel-react-best-practices/README.md +123 -0
  45. package/.agents/skills/vercel-react-best-practices/SKILL.md +141 -0
  46. package/.agents/skills/vercel-react-best-practices/rules/advanced-event-handler-refs.md +55 -0
  47. package/.agents/skills/vercel-react-best-practices/rules/advanced-init-once.md +42 -0
  48. package/.agents/skills/vercel-react-best-practices/rules/advanced-use-latest.md +39 -0
  49. package/.agents/skills/vercel-react-best-practices/rules/async-api-routes.md +38 -0
  50. package/.agents/skills/vercel-react-best-practices/rules/async-defer-await.md +80 -0
  51. package/.agents/skills/vercel-react-best-practices/rules/async-dependencies.md +51 -0
  52. package/.agents/skills/vercel-react-best-practices/rules/async-parallel.md +28 -0
  53. package/.agents/skills/vercel-react-best-practices/rules/async-suspense-boundaries.md +99 -0
  54. package/.agents/skills/vercel-react-best-practices/rules/bundle-barrel-imports.md +59 -0
  55. package/.agents/skills/vercel-react-best-practices/rules/bundle-conditional.md +31 -0
  56. package/.agents/skills/vercel-react-best-practices/rules/bundle-defer-third-party.md +49 -0
  57. package/.agents/skills/vercel-react-best-practices/rules/bundle-dynamic-imports.md +35 -0
  58. package/.agents/skills/vercel-react-best-practices/rules/bundle-preload.md +50 -0
  59. package/.agents/skills/vercel-react-best-practices/rules/client-event-listeners.md +74 -0
  60. package/.agents/skills/vercel-react-best-practices/rules/client-localstorage-schema.md +71 -0
  61. package/.agents/skills/vercel-react-best-practices/rules/client-passive-event-listeners.md +48 -0
  62. package/.agents/skills/vercel-react-best-practices/rules/client-swr-dedup.md +56 -0
  63. package/.agents/skills/vercel-react-best-practices/rules/js-batch-dom-css.md +107 -0
  64. package/.agents/skills/vercel-react-best-practices/rules/js-cache-function-results.md +80 -0
  65. package/.agents/skills/vercel-react-best-practices/rules/js-cache-property-access.md +28 -0
  66. package/.agents/skills/vercel-react-best-practices/rules/js-cache-storage.md +70 -0
  67. package/.agents/skills/vercel-react-best-practices/rules/js-combine-iterations.md +32 -0
  68. package/.agents/skills/vercel-react-best-practices/rules/js-early-exit.md +50 -0
  69. package/.agents/skills/vercel-react-best-practices/rules/js-flatmap-filter.md +60 -0
  70. package/.agents/skills/vercel-react-best-practices/rules/js-hoist-regexp.md +45 -0
  71. package/.agents/skills/vercel-react-best-practices/rules/js-index-maps.md +37 -0
  72. package/.agents/skills/vercel-react-best-practices/rules/js-length-check-first.md +49 -0
  73. package/.agents/skills/vercel-react-best-practices/rules/js-min-max-loop.md +82 -0
  74. package/.agents/skills/vercel-react-best-practices/rules/js-set-map-lookups.md +24 -0
  75. package/.agents/skills/vercel-react-best-practices/rules/js-tosorted-immutable.md +57 -0
  76. package/.agents/skills/vercel-react-best-practices/rules/rendering-activity.md +26 -0
  77. package/.agents/skills/vercel-react-best-practices/rules/rendering-animate-svg-wrapper.md +47 -0
  78. package/.agents/skills/vercel-react-best-practices/rules/rendering-conditional-render.md +40 -0
  79. package/.agents/skills/vercel-react-best-practices/rules/rendering-content-visibility.md +38 -0
  80. package/.agents/skills/vercel-react-best-practices/rules/rendering-hoist-jsx.md +46 -0
  81. package/.agents/skills/vercel-react-best-practices/rules/rendering-hydration-no-flicker.md +82 -0
  82. package/.agents/skills/vercel-react-best-practices/rules/rendering-hydration-suppress-warning.md +30 -0
  83. package/.agents/skills/vercel-react-best-practices/rules/rendering-resource-hints.md +85 -0
  84. package/.agents/skills/vercel-react-best-practices/rules/rendering-script-defer-async.md +68 -0
  85. package/.agents/skills/vercel-react-best-practices/rules/rendering-svg-precision.md +28 -0
  86. package/.agents/skills/vercel-react-best-practices/rules/rendering-usetransition-loading.md +75 -0
  87. package/.agents/skills/vercel-react-best-practices/rules/rerender-defer-reads.md +39 -0
  88. package/.agents/skills/vercel-react-best-practices/rules/rerender-dependencies.md +45 -0
  89. package/.agents/skills/vercel-react-best-practices/rules/rerender-derived-state-no-effect.md +40 -0
  90. package/.agents/skills/vercel-react-best-practices/rules/rerender-derived-state.md +29 -0
  91. package/.agents/skills/vercel-react-best-practices/rules/rerender-functional-setstate.md +74 -0
  92. package/.agents/skills/vercel-react-best-practices/rules/rerender-lazy-state-init.md +58 -0
  93. package/.agents/skills/vercel-react-best-practices/rules/rerender-memo-with-default-value.md +38 -0
  94. package/.agents/skills/vercel-react-best-practices/rules/rerender-memo.md +44 -0
  95. package/.agents/skills/vercel-react-best-practices/rules/rerender-move-effect-to-event.md +45 -0
  96. package/.agents/skills/vercel-react-best-practices/rules/rerender-no-inline-components.md +82 -0
  97. package/.agents/skills/vercel-react-best-practices/rules/rerender-simple-expression-in-memo.md +35 -0
  98. package/.agents/skills/vercel-react-best-practices/rules/rerender-transitions.md +40 -0
  99. package/.agents/skills/vercel-react-best-practices/rules/rerender-use-ref-transient-values.md +73 -0
  100. package/.agents/skills/vercel-react-best-practices/rules/server-after-nonblocking.md +73 -0
  101. package/.agents/skills/vercel-react-best-practices/rules/server-auth-actions.md +96 -0
  102. package/.agents/skills/vercel-react-best-practices/rules/server-cache-lru.md +41 -0
  103. package/.agents/skills/vercel-react-best-practices/rules/server-cache-react.md +76 -0
  104. package/.agents/skills/vercel-react-best-practices/rules/server-dedup-props.md +65 -0
  105. package/.agents/skills/vercel-react-best-practices/rules/server-hoist-static-io.md +142 -0
  106. package/.agents/skills/vercel-react-best-practices/rules/server-parallel-fetching.md +83 -0
  107. package/.agents/skills/vercel-react-best-practices/rules/server-serialization.md +38 -0
  108. package/.claude/CLAUDE.md +142 -0
  109. package/.claude/commands/review.md +120 -0
  110. package/.claude/commands/sync-docs.md +71 -0
  111. package/.claude/roadmap.md +98 -0
  112. package/.claude/rules/style-guide.md +830 -0
  113. package/.claude/settings.json +18 -0
  114. package/.claude/user-stories.md +248 -0
  115. package/AGENTS.md +64 -0
  116. package/README.md +7 -7
  117. package/biome.json +69 -0
  118. package/bun.lock +1124 -0
  119. package/docs/design.md +563 -0
  120. package/docs/plans/2026-03-13-keyboard-shortcuts-design.md +129 -0
  121. package/docs/plans/2026-03-13-keyboard-shortcuts-plan.md +1471 -0
  122. package/docs/plans/2026-03-13-multi-document-design.md +183 -0
  123. package/docs/plans/2026-03-13-performance-benchmarks-design.md +121 -0
  124. package/e2e/comments.spec.ts +125 -0
  125. package/e2e/document-load.spec.ts +54 -0
  126. package/e2e/export.spec.ts +58 -0
  127. package/e2e/fixtures/sample.html +13 -0
  128. package/e2e/fixtures/sample.md +7 -0
  129. package/e2e/persistence-file.spec.ts +342 -0
  130. package/e2e/utils/cli.ts +84 -0
  131. package/e2e/utils/selection.ts +135 -0
  132. package/{dist/index.html → index.html} +8 -2
  133. package/lefthook.yml +8 -0
  134. package/package.json +17 -39
  135. package/playwright.config.ts +22 -0
  136. package/skills-lock.json +20 -0
  137. package/src/App.tsx +396 -0
  138. package/src/cli/index.ts +328 -0
  139. package/src/components/ActionsMenu.tsx +110 -0
  140. package/src/components/DocumentViewer/CodeBlock.tsx +83 -0
  141. package/src/components/DocumentViewer/DocumentViewer.tsx +257 -0
  142. package/src/components/DocumentViewer/IframeContainer.tsx +251 -0
  143. package/src/components/DocumentViewer/MermaidDiagram.tsx +137 -0
  144. package/src/components/DocumentViewer/index.ts +1 -0
  145. package/src/components/FloatingTOC.tsx +59 -0
  146. package/src/components/Header.tsx +63 -0
  147. package/src/components/InlineEditor.tsx +72 -0
  148. package/src/components/MarginNote.tsx +198 -0
  149. package/src/components/MarginNotes.tsx +50 -0
  150. package/src/components/RawModal.tsx +141 -0
  151. package/src/components/ReanchorConfirm.tsx +33 -0
  152. package/src/components/SettingsModal.tsx +221 -0
  153. package/src/components/ShortcutCapture.tsx +45 -0
  154. package/src/components/ShortcutList.tsx +157 -0
  155. package/src/components/TabBar.tsx +60 -0
  156. package/src/components/TableOfContents.tsx +108 -0
  157. package/src/components/comments/CommentBadge.tsx +43 -0
  158. package/src/components/comments/CommentInput.tsx +119 -0
  159. package/src/components/comments/CommentListItem.tsx +82 -0
  160. package/src/components/comments/CommentManager.tsx +106 -0
  161. package/src/components/comments/CommentMinimap.tsx +62 -0
  162. package/src/components/comments/CommentNav.tsx +104 -0
  163. package/src/components/ui/ActionBar.tsx +16 -0
  164. package/src/components/ui/ActionLink.tsx +32 -0
  165. package/src/components/ui/Button.tsx +55 -0
  166. package/src/components/ui/Dialog.tsx +156 -0
  167. package/src/components/ui/DropdownMenu.tsx +114 -0
  168. package/src/components/ui/SeparatorDot.tsx +9 -0
  169. package/src/components/ui/Text.tsx +54 -0
  170. package/src/contexts/CommentContext.tsx +222 -0
  171. package/src/contexts/LayoutContext.tsx +76 -0
  172. package/src/hooks/useClickOutside.ts +35 -0
  173. package/src/hooks/useClipboard.ts +79 -0
  174. package/src/hooks/useCommentNavigation.ts +130 -0
  175. package/src/hooks/useComments.ts +323 -0
  176. package/src/hooks/useDocument.ts +131 -0
  177. package/src/hooks/useFontPreference.ts +76 -0
  178. package/src/hooks/useHeadings.test.ts +159 -0
  179. package/src/hooks/useHeadings.ts +129 -0
  180. package/src/hooks/useKeybindings.ts +120 -0
  181. package/src/hooks/useKeyboardShortcuts.ts +63 -0
  182. package/src/hooks/useLayoutMode.ts +44 -0
  183. package/src/hooks/useReanchorMode.ts +33 -0
  184. package/src/hooks/useScrollMetrics.ts +56 -0
  185. package/src/hooks/useScrollSpy.ts +81 -0
  186. package/src/hooks/useTextSelection.ts +123 -0
  187. package/src/hooks/useThemePreference.ts +66 -0
  188. package/src/index.css +823 -0
  189. package/src/lib/__fixtures__/bench-data.ts +167 -0
  190. package/src/lib/anchor.bench.ts +112 -0
  191. package/src/lib/anchor.test.ts +531 -0
  192. package/src/lib/anchor.ts +465 -0
  193. package/src/lib/comment-storage.bench.ts +63 -0
  194. package/src/lib/comment-storage.test.ts +624 -0
  195. package/src/lib/comment-storage.ts +263 -0
  196. package/src/lib/context.bench.ts +41 -0
  197. package/src/lib/context.test.ts +224 -0
  198. package/src/lib/context.ts +193 -0
  199. package/src/lib/export.bench.ts +35 -0
  200. package/src/lib/export.ts +43 -0
  201. package/src/lib/highlight/colors.ts +37 -0
  202. package/src/lib/highlight/core.test.ts +98 -0
  203. package/src/lib/highlight/core.ts +54 -0
  204. package/src/lib/highlight/dom.ts +342 -0
  205. package/src/lib/highlight/highlighter.ts +427 -0
  206. package/src/lib/highlight/index.ts +23 -0
  207. package/src/lib/highlight/script-builder.ts +485 -0
  208. package/src/lib/highlight/types.ts +57 -0
  209. package/src/lib/html-processor.test.tsx +170 -0
  210. package/src/lib/html-processor.tsx +95 -0
  211. package/src/lib/layout-constants.ts +12 -0
  212. package/src/lib/margin-layout.bench.ts +28 -0
  213. package/src/lib/margin-layout.ts +100 -0
  214. package/src/lib/scroll.test.ts +118 -0
  215. package/src/lib/scroll.ts +47 -0
  216. package/src/lib/shortcut-registry.test.ts +173 -0
  217. package/src/lib/shortcut-registry.ts +209 -0
  218. package/src/lib/utils.test.ts +110 -0
  219. package/src/lib/utils.ts +50 -0
  220. package/src/main.tsx +10 -0
  221. package/src/server/index.ts +766 -0
  222. package/src/store/index.test.ts +220 -0
  223. package/src/store/index.ts +234 -0
  224. package/src/test-setup.ts +1 -0
  225. package/src/types/index.ts +115 -0
  226. package/test.md +74 -0
  227. package/tsconfig.cli.json +12 -0
  228. package/tsconfig.json +20 -0
  229. package/vite.config.ts +19 -0
  230. package/vitest.config.ts +15 -0
  231. package/dist/assets/_basePickBy-hOr-yGsE.js +0 -1
  232. package/dist/assets/_baseUniq-b7bzdUSn.js +0 -1
  233. package/dist/assets/arc-D65wG9gm.js +0 -1
  234. package/dist/assets/architecture-PBZL5I3N-DBa6CAv_.js +0 -1
  235. package/dist/assets/architectureDiagram-2XIMDMQ5-Djwpsh98.js +0 -36
  236. package/dist/assets/array-DOVTz2Mq.js +0 -1
  237. package/dist/assets/blockDiagram-WCTKOSBZ-BdW5TTxj.js +0 -132
  238. package/dist/assets/c4Diagram-IC4MRINW-DTmkHEXu.js +0 -10
  239. package/dist/assets/channel-B3MUFipN.js +0 -1
  240. package/dist/assets/chunk-4BX2VUAB-DEqzsvDc.js +0 -1
  241. package/dist/assets/chunk-55IACEB6-BzVuSUV8.js +0 -1
  242. package/dist/assets/chunk-7E7YKBS2-CZ8IcA4c.js +0 -1
  243. package/dist/assets/chunk-7R4GIKGN-CWVVC8HX.js +0 -79
  244. package/dist/assets/chunk-C72U2L5F-B1Tso5TH.js +0 -1
  245. package/dist/assets/chunk-EGIJ26TM-Cx_7CFik.js +0 -1
  246. package/dist/assets/chunk-FMBD7UC4-Cfk_iGhv.js +0 -15
  247. package/dist/assets/chunk-GEFDOKGD-C_5hRbJt.js +0 -2
  248. package/dist/assets/chunk-GLR3WWYH-CkY7IyBj.js +0 -2
  249. package/dist/assets/chunk-HHEYEP7N-B0I4X5cr.js +0 -1
  250. package/dist/assets/chunk-JSJVCQXG-CAjwlVLg.js +0 -1
  251. package/dist/assets/chunk-KX2RTZJC-DWqnZZ02.js +0 -1
  252. package/dist/assets/chunk-KYZI473N-gjRVhJgJ.js +0 -53
  253. package/dist/assets/chunk-L3YUKLVL-D7C9GuxL.js +0 -1
  254. package/dist/assets/chunk-MX3YWQON-i-77iuVj.js +0 -1
  255. package/dist/assets/chunk-NQ4KR5QH-B22Pvemm.js +0 -220
  256. package/dist/assets/chunk-O4XLMI2P-ZQd5L6ZD.js +0 -7
  257. package/dist/assets/chunk-OZEHJAEY-BaPKTELw.js +0 -1
  258. package/dist/assets/chunk-PQ6SQG4A-DqE1eupT.js +0 -1
  259. package/dist/assets/chunk-PU5JKC2W-BTqWqedh.js +0 -70
  260. package/dist/assets/chunk-QZHKN3VN-Nm9TvMss.js +0 -1
  261. package/dist/assets/chunk-R5LLSJPH-DkiNs1dN.js +0 -1
  262. package/dist/assets/chunk-WL4C6EOR-CioD2fv2.js +0 -189
  263. package/dist/assets/chunk-XIRO2GV7-B4GGQONY.js +0 -1
  264. package/dist/assets/chunk-XPW4576I-C0IbbQos.js +0 -32
  265. package/dist/assets/chunk-XZSTWKYB-DMOqFWmT.js +0 -94
  266. package/dist/assets/chunk-YBOYWFTD-CoeQgeVY.js +0 -1
  267. package/dist/assets/classDiagram-VBA2DB6C-DV9ltQ7h.js +0 -1
  268. package/dist/assets/classDiagram-v2-RAHNMMFH-C6nD9wmM.js +0 -1
  269. package/dist/assets/clone-DuY6BQEm.js +0 -1
  270. package/dist/assets/cose-bilkent-S5V4N54A-B6FexK6p.js +0 -1
  271. package/dist/assets/cytoscape.esm-DoTFyJaN.js +0 -321
  272. package/dist/assets/dagre-CCcocoCU.js +0 -1
  273. package/dist/assets/dagre-KLK3FWXG-DIELowj9.js +0 -4
  274. package/dist/assets/defaultLocale-Ck2Xxk-C.js +0 -1
  275. package/dist/assets/diagram-E7M64L7V-D1mm0PoO.js +0 -24
  276. package/dist/assets/diagram-IFDJBPK2-7DVjly8y.js +0 -43
  277. package/dist/assets/diagram-P4PSJMXO-jO7pfyMb.js +0 -24
  278. package/dist/assets/dist-BywRdrPx.js +0 -1
  279. package/dist/assets/erDiagram-INFDFZHY-DSRxlRFy.js +0 -70
  280. package/dist/assets/flowDiagram-PKNHOUZH-CgKzzNdR.js +0 -162
  281. package/dist/assets/ganttDiagram-A5KZAMGK-CtsE7Y4E.js +0 -292
  282. package/dist/assets/gitGraph-HDMCJU4V-BU9uhwtz.js +0 -1
  283. package/dist/assets/gitGraphDiagram-K3NZZRJ6-DOU8RGdw.js +0 -65
  284. package/dist/assets/graphlib-WkJoBgka.js +0 -1
  285. package/dist/assets/index-CKVArt9D.js +0 -562
  286. package/dist/assets/index-DzRKJazf.css +0 -2
  287. package/dist/assets/info-3K5VOQVL-CPpvM-SG.js +0 -1
  288. package/dist/assets/infoDiagram-LFFYTUFH-VKLs5DsF.js +0 -2
  289. package/dist/assets/init-Bft5Ffpj.js +0 -1
  290. package/dist/assets/isArrayLikeObject-icl0H0jo.js +0 -1
  291. package/dist/assets/isEmpty-Du8sNmkE.js +0 -1
  292. package/dist/assets/ishikawaDiagram-PHBUUO56-CsWvEjux.js +0 -70
  293. package/dist/assets/journeyDiagram-4ABVD52K-BzJGTdIT.js +0 -139
  294. package/dist/assets/kanban-definition-K7BYSVSG-B_9ClJ1A.js +0 -89
  295. package/dist/assets/katex-BJrMXEjr.js +0 -261
  296. package/dist/assets/line-CC_tDGId.js +0 -1
  297. package/dist/assets/linear-Cts_d04Y.js +0 -1
  298. package/dist/assets/math-CNhlSIO3.js +0 -1
  299. package/dist/assets/mermaid-parser.core-Vb9KKv1R.js +0 -4
  300. package/dist/assets/mermaid.core-C_7xsp3d.js +0 -11
  301. package/dist/assets/mindmap-definition-YRQLILUH-BWmfy5wB.js +0 -68
  302. package/dist/assets/ordinal-DIg8h6NI.js +0 -1
  303. package/dist/assets/packet-RMMSAZCW-Q-WG6o3b.js +0 -1
  304. package/dist/assets/path-DfRbCp9y.js +0 -1
  305. package/dist/assets/pie-UPGHQEXC-Cwi2tLlt.js +0 -1
  306. package/dist/assets/pieDiagram-SKSYHLDU-Dyf3X_in.js +0 -30
  307. package/dist/assets/quadrantDiagram-337W2JSQ-B5_5m61Q.js +0 -7
  308. package/dist/assets/radar-KQ55EAFF-Dtw2VzxY.js +0 -1
  309. package/dist/assets/requirementDiagram-Z7DCOOCP-BSERBnlW.js +0 -73
  310. package/dist/assets/rough.esm-KjoEK0it.js +0 -1
  311. package/dist/assets/sankeyDiagram-WA2Y5GQK-CMcEY8Cz.js +0 -10
  312. package/dist/assets/sequenceDiagram-2WXFIKYE-D28qcXwC.js +0 -145
  313. package/dist/assets/src-C8kkzlHX.js +0 -1
  314. package/dist/assets/stateDiagram-RAJIS63D-7oVrCmRl.js +0 -1
  315. package/dist/assets/stateDiagram-v2-FVOUBMTO-DtFptQAd.js +0 -1
  316. package/dist/assets/timeline-definition-YZTLITO2-rbCfBEvG.js +0 -61
  317. package/dist/assets/treemap-KZPCXAKY-BlRvF0um.js +0 -1
  318. package/dist/assets/vennDiagram-LZ73GAT5-DBit3zWa.js +0 -34
  319. package/dist/assets/xychartDiagram-JWTSCODW-BVYXv51y.js +0 -7
  320. package/dist/index.js +0 -1040
@@ -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,38 @@
1
+ ---
2
+
3
+ title: Extract Default Non-primitive Parameter Value from Memoized Component to Constant
4
+ impact: MEDIUM
5
+ impactDescription: restores memoization by using a constant for default value
6
+ tags: rerender, memo, optimization
7
+
8
+ ---
9
+
10
+ ## Extract Default Non-primitive Parameter Value from Memoized Component to Constant
11
+
12
+ When memoized component has a default value for some non-primitive optional parameter, such as an array, function, or object, calling the component without that parameter results in broken memoization. This is because new value instances are created on every rerender, and they do not pass strict equality comparison in `memo()`.
13
+
14
+ To address this issue, extract the default value into a constant.
15
+
16
+ **Incorrect (`onClick` has different values on every rerender):**
17
+
18
+ ```tsx
19
+ const UserAvatar = memo(function UserAvatar({ onClick = () => {} }: { onClick?: () => void }) {
20
+ // ...
21
+ })
22
+
23
+ // Used without optional onClick
24
+ <UserAvatar />
25
+ ```
26
+
27
+ **Correct (stable default value):**
28
+
29
+ ```tsx
30
+ const NOOP = () => {};
31
+
32
+ const UserAvatar = memo(function UserAvatar({ onClick = NOOP }: { onClick?: () => void }) {
33
+ // ...
34
+ })
35
+
36
+ // Used without optional onClick
37
+ <UserAvatar />
38
+ ```
@@ -0,0 +1,44 @@
1
+ ---
2
+ title: Extract to Memoized Components
3
+ impact: MEDIUM
4
+ impactDescription: enables early returns
5
+ tags: rerender, memo, useMemo, optimization
6
+ ---
7
+
8
+ ## Extract to Memoized Components
9
+
10
+ Extract expensive work into memoized components to enable early returns before computation.
11
+
12
+ **Incorrect (computes avatar even when loading):**
13
+
14
+ ```tsx
15
+ function Profile({ user, loading }: Props) {
16
+ const avatar = useMemo(() => {
17
+ const id = computeAvatarId(user)
18
+ return <Avatar id={id} />
19
+ }, [user])
20
+
21
+ if (loading) return <Skeleton />
22
+ return <div>{avatar}</div>
23
+ }
24
+ ```
25
+
26
+ **Correct (skips computation when loading):**
27
+
28
+ ```tsx
29
+ const UserAvatar = memo(function UserAvatar({ user }: { user: User }) {
30
+ const id = useMemo(() => computeAvatarId(user), [user])
31
+ return <Avatar id={id} />
32
+ })
33
+
34
+ function Profile({ user, loading }: Props) {
35
+ if (loading) return <Skeleton />
36
+ return (
37
+ <div>
38
+ <UserAvatar user={user} />
39
+ </div>
40
+ )
41
+ }
42
+ ```
43
+
44
+ **Note:** If your project has [React Compiler](https://react.dev/learn/react-compiler) enabled, manual memoization with `memo()` and `useMemo()` is not necessary. The compiler automatically optimizes re-renders.
@@ -0,0 +1,45 @@
1
+ ---
2
+ title: Put Interaction Logic in Event Handlers
3
+ impact: MEDIUM
4
+ impactDescription: avoids effect re-runs and duplicate side effects
5
+ tags: rerender, useEffect, events, side-effects, dependencies
6
+ ---
7
+
8
+ ## Put Interaction Logic in Event Handlers
9
+
10
+ If a side effect is triggered by a specific user action (submit, click, drag), run it in that event handler. Do not model the action as state + effect; it makes effects re-run on unrelated changes and can duplicate the action.
11
+
12
+ **Incorrect (event modeled as state + effect):**
13
+
14
+ ```tsx
15
+ function Form() {
16
+ const [submitted, setSubmitted] = useState(false)
17
+ const theme = useContext(ThemeContext)
18
+
19
+ useEffect(() => {
20
+ if (submitted) {
21
+ post('/api/register')
22
+ showToast('Registered', theme)
23
+ }
24
+ }, [submitted, theme])
25
+
26
+ return <button onClick={() => setSubmitted(true)}>Submit</button>
27
+ }
28
+ ```
29
+
30
+ **Correct (do it in the handler):**
31
+
32
+ ```tsx
33
+ function Form() {
34
+ const theme = useContext(ThemeContext)
35
+
36
+ function handleSubmit() {
37
+ post('/api/register')
38
+ showToast('Registered', theme)
39
+ }
40
+
41
+ return <button onClick={handleSubmit}>Submit</button>
42
+ }
43
+ ```
44
+
45
+ Reference: [Should this code move to an event handler?](https://react.dev/learn/removing-effect-dependencies#should-this-code-move-to-an-event-handler)
@@ -0,0 +1,82 @@
1
+ ---
2
+ title: Don't Define Components Inside Components
3
+ impact: HIGH
4
+ impactDescription: prevents remount on every render
5
+ tags: rerender, components, remount, performance
6
+ ---
7
+
8
+ ## Don't Define Components Inside Components
9
+
10
+ **Impact: HIGH (prevents remount on every render)**
11
+
12
+ Defining a component inside another component creates a new component type on every render. React sees a different component each time and fully remounts it, destroying all state and DOM.
13
+
14
+ A common reason developers do this is to access parent variables without passing props. Always pass props instead.
15
+
16
+ **Incorrect (remounts on every render):**
17
+
18
+ ```tsx
19
+ function UserProfile({ user, theme }) {
20
+ // Defined inside to access `theme` - BAD
21
+ const Avatar = () => (
22
+ <img
23
+ src={user.avatarUrl}
24
+ className={theme === 'dark' ? 'avatar-dark' : 'avatar-light'}
25
+ />
26
+ )
27
+
28
+ // Defined inside to access `user` - BAD
29
+ const Stats = () => (
30
+ <div>
31
+ <span>{user.followers} followers</span>
32
+ <span>{user.posts} posts</span>
33
+ </div>
34
+ )
35
+
36
+ return (
37
+ <div>
38
+ <Avatar />
39
+ <Stats />
40
+ </div>
41
+ )
42
+ }
43
+ ```
44
+
45
+ Every time `UserProfile` renders, `Avatar` and `Stats` are new component types. React unmounts the old instances and mounts new ones, losing any internal state, running effects again, and recreating DOM nodes.
46
+
47
+ **Correct (pass props instead):**
48
+
49
+ ```tsx
50
+ function Avatar({ src, theme }: { src: string; theme: string }) {
51
+ return (
52
+ <img
53
+ src={src}
54
+ className={theme === 'dark' ? 'avatar-dark' : 'avatar-light'}
55
+ />
56
+ )
57
+ }
58
+
59
+ function Stats({ followers, posts }: { followers: number; posts: number }) {
60
+ return (
61
+ <div>
62
+ <span>{followers} followers</span>
63
+ <span>{posts} posts</span>
64
+ </div>
65
+ )
66
+ }
67
+
68
+ function UserProfile({ user, theme }) {
69
+ return (
70
+ <div>
71
+ <Avatar src={user.avatarUrl} theme={theme} />
72
+ <Stats followers={user.followers} posts={user.posts} />
73
+ </div>
74
+ )
75
+ }
76
+ ```
77
+
78
+ **Symptoms of this bug:**
79
+ - Input fields lose focus on every keystroke
80
+ - Animations restart unexpectedly
81
+ - `useEffect` cleanup/setup runs on every parent render
82
+ - Scroll position resets inside the component
@@ -0,0 +1,35 @@
1
+ ---
2
+ title: Do not wrap a simple expression with a primitive result type in useMemo
3
+ impact: LOW-MEDIUM
4
+ impactDescription: wasted computation on every render
5
+ tags: rerender, useMemo, optimization
6
+ ---
7
+
8
+ ## Do not wrap a simple expression with a primitive result type in useMemo
9
+
10
+ When an expression is simple (few logical or arithmetical operators) and has a primitive result type (boolean, number, string), do not wrap it in `useMemo`.
11
+ Calling `useMemo` and comparing hook dependencies may consume more resources than the expression itself.
12
+
13
+ **Incorrect:**
14
+
15
+ ```tsx
16
+ function Header({ user, notifications }: Props) {
17
+ const isLoading = useMemo(() => {
18
+ return user.isLoading || notifications.isLoading
19
+ }, [user.isLoading, notifications.isLoading])
20
+
21
+ if (isLoading) return <Skeleton />
22
+ // return some markup
23
+ }
24
+ ```
25
+
26
+ **Correct:**
27
+
28
+ ```tsx
29
+ function Header({ user, notifications }: Props) {
30
+ const isLoading = user.isLoading || notifications.isLoading
31
+
32
+ if (isLoading) return <Skeleton />
33
+ // return some markup
34
+ }
35
+ ```
@@ -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,73 @@
1
+ ---
2
+ title: Use useRef for Transient Values
3
+ impact: MEDIUM
4
+ impactDescription: avoids unnecessary re-renders on frequent updates
5
+ tags: rerender, useref, state, performance
6
+ ---
7
+
8
+ ## Use useRef for Transient Values
9
+
10
+ When a value changes frequently and you don't want a re-render on every update (e.g., mouse trackers, intervals, transient flags), store it in `useRef` instead of `useState`. Keep component state for UI; use refs for temporary DOM-adjacent values. Updating a ref does not trigger a re-render.
11
+
12
+ **Incorrect (renders every update):**
13
+
14
+ ```tsx
15
+ function Tracker() {
16
+ const [lastX, setLastX] = useState(0)
17
+
18
+ useEffect(() => {
19
+ const onMove = (e: MouseEvent) => setLastX(e.clientX)
20
+ window.addEventListener('mousemove', onMove)
21
+ return () => window.removeEventListener('mousemove', onMove)
22
+ }, [])
23
+
24
+ return (
25
+ <div
26
+ style={{
27
+ position: 'fixed',
28
+ top: 0,
29
+ left: lastX,
30
+ width: 8,
31
+ height: 8,
32
+ background: 'black',
33
+ }}
34
+ />
35
+ )
36
+ }
37
+ ```
38
+
39
+ **Correct (no re-render for tracking):**
40
+
41
+ ```tsx
42
+ function Tracker() {
43
+ const lastXRef = useRef(0)
44
+ const dotRef = useRef<HTMLDivElement>(null)
45
+
46
+ useEffect(() => {
47
+ const onMove = (e: MouseEvent) => {
48
+ lastXRef.current = e.clientX
49
+ const node = dotRef.current
50
+ if (node) {
51
+ node.style.transform = `translateX(${e.clientX}px)`
52
+ }
53
+ }
54
+ window.addEventListener('mousemove', onMove)
55
+ return () => window.removeEventListener('mousemove', onMove)
56
+ }, [])
57
+
58
+ return (
59
+ <div
60
+ ref={dotRef}
61
+ style={{
62
+ position: 'fixed',
63
+ top: 0,
64
+ left: 0,
65
+ width: 8,
66
+ height: 8,
67
+ background: 'black',
68
+ transform: 'translateX(0px)',
69
+ }}
70
+ />
71
+ )
72
+ }
73
+ ```
@@ -0,0 +1,73 @@
1
+ ---
2
+ title: Use after() for Non-Blocking Operations
3
+ impact: MEDIUM
4
+ impactDescription: faster response times
5
+ tags: server, async, logging, analytics, side-effects
6
+ ---
7
+
8
+ ## Use after() for Non-Blocking Operations
9
+
10
+ Use Next.js's `after()` to schedule work that should execute after a response is sent. This prevents logging, analytics, and other side effects from blocking the response.
11
+
12
+ **Incorrect (blocks response):**
13
+
14
+ ```tsx
15
+ import { logUserAction } from '@/app/utils'
16
+
17
+ export async function POST(request: Request) {
18
+ // Perform mutation
19
+ await updateDatabase(request)
20
+
21
+ // Logging blocks the response
22
+ const userAgent = request.headers.get('user-agent') || 'unknown'
23
+ await logUserAction({ userAgent })
24
+
25
+ return new Response(JSON.stringify({ status: 'success' }), {
26
+ status: 200,
27
+ headers: { 'Content-Type': 'application/json' }
28
+ })
29
+ }
30
+ ```
31
+
32
+ **Correct (non-blocking):**
33
+
34
+ ```tsx
35
+ import { after } from 'next/server'
36
+ import { headers, cookies } from 'next/headers'
37
+ import { logUserAction } from '@/app/utils'
38
+
39
+ export async function POST(request: Request) {
40
+ // Perform mutation
41
+ await updateDatabase(request)
42
+
43
+ // Log after response is sent
44
+ after(async () => {
45
+ const userAgent = (await headers()).get('user-agent') || 'unknown'
46
+ const sessionCookie = (await cookies()).get('session-id')?.value || 'anonymous'
47
+
48
+ logUserAction({ sessionCookie, userAgent })
49
+ })
50
+
51
+ return new Response(JSON.stringify({ status: 'success' }), {
52
+ status: 200,
53
+ headers: { 'Content-Type': 'application/json' }
54
+ })
55
+ }
56
+ ```
57
+
58
+ The response is sent immediately while logging happens in the background.
59
+
60
+ **Common use cases:**
61
+
62
+ - Analytics tracking
63
+ - Audit logging
64
+ - Sending notifications
65
+ - Cache invalidation
66
+ - Cleanup tasks
67
+
68
+ **Important notes:**
69
+
70
+ - `after()` runs even if the response fails or redirects
71
+ - Works in Server Actions, Route Handlers, and Server Components
72
+
73
+ Reference: [https://nextjs.org/docs/app/api-reference/functions/after](https://nextjs.org/docs/app/api-reference/functions/after)
@@ -0,0 +1,96 @@
1
+ ---
2
+ title: Authenticate Server Actions Like API Routes
3
+ impact: CRITICAL
4
+ impactDescription: prevents unauthorized access to server mutations
5
+ tags: server, server-actions, authentication, security, authorization
6
+ ---
7
+
8
+ ## Authenticate Server Actions Like API Routes
9
+
10
+ **Impact: CRITICAL (prevents unauthorized access to server mutations)**
11
+
12
+ Server Actions (functions with `"use server"`) are exposed as public endpoints, just like API routes. Always verify authentication and authorization **inside** each Server Action—do not rely solely on middleware, layout guards, or page-level checks, as Server Actions can be invoked directly.
13
+
14
+ Next.js documentation explicitly states: "Treat Server Actions with the same security considerations as public-facing API endpoints, and verify if the user is allowed to perform a mutation."
15
+
16
+ **Incorrect (no authentication check):**
17
+
18
+ ```typescript
19
+ 'use server'
20
+
21
+ export async function deleteUser(userId: string) {
22
+ // Anyone can call this! No auth check
23
+ await db.user.delete({ where: { id: userId } })
24
+ return { success: true }
25
+ }
26
+ ```
27
+
28
+ **Correct (authentication inside the action):**
29
+
30
+ ```typescript
31
+ 'use server'
32
+
33
+ import { verifySession } from '@/lib/auth'
34
+ import { unauthorized } from '@/lib/errors'
35
+
36
+ export async function deleteUser(userId: string) {
37
+ // Always check auth inside the action
38
+ const session = await verifySession()
39
+
40
+ if (!session) {
41
+ throw unauthorized('Must be logged in')
42
+ }
43
+
44
+ // Check authorization too
45
+ if (session.user.role !== 'admin' && session.user.id !== userId) {
46
+ throw unauthorized('Cannot delete other users')
47
+ }
48
+
49
+ await db.user.delete({ where: { id: userId } })
50
+ return { success: true }
51
+ }
52
+ ```
53
+
54
+ **With input validation:**
55
+
56
+ ```typescript
57
+ 'use server'
58
+
59
+ import { verifySession } from '@/lib/auth'
60
+ import { z } from 'zod'
61
+
62
+ const updateProfileSchema = z.object({
63
+ userId: z.string().uuid(),
64
+ name: z.string().min(1).max(100),
65
+ email: z.string().email()
66
+ })
67
+
68
+ export async function updateProfile(data: unknown) {
69
+ // Validate input first
70
+ const validated = updateProfileSchema.parse(data)
71
+
72
+ // Then authenticate
73
+ const session = await verifySession()
74
+ if (!session) {
75
+ throw new Error('Unauthorized')
76
+ }
77
+
78
+ // Then authorize
79
+ if (session.user.id !== validated.userId) {
80
+ throw new Error('Can only update own profile')
81
+ }
82
+
83
+ // Finally perform the mutation
84
+ await db.user.update({
85
+ where: { id: validated.userId },
86
+ data: {
87
+ name: validated.name,
88
+ email: validated.email
89
+ }
90
+ })
91
+
92
+ return { success: true }
93
+ }
94
+ ```
95
+
96
+ Reference: [https://nextjs.org/docs/app/guides/authentication](https://nextjs.org/docs/app/guides/authentication)
@@ -0,0 +1,41 @@
1
+ ---
2
+ title: Cross-Request LRU Caching
3
+ impact: HIGH
4
+ impactDescription: caches across requests
5
+ tags: server, cache, lru, cross-request
6
+ ---
7
+
8
+ ## Cross-Request LRU Caching
9
+
10
+ `React.cache()` only works within one request. For data shared across sequential requests (user clicks button A then button B), use an LRU cache.
11
+
12
+ **Implementation:**
13
+
14
+ ```typescript
15
+ import { LRUCache } from 'lru-cache'
16
+
17
+ const cache = new LRUCache<string, any>({
18
+ max: 1000,
19
+ ttl: 5 * 60 * 1000 // 5 minutes
20
+ })
21
+
22
+ export async function getUser(id: string) {
23
+ const cached = cache.get(id)
24
+ if (cached) return cached
25
+
26
+ const user = await db.user.findUnique({ where: { id } })
27
+ cache.set(id, user)
28
+ return user
29
+ }
30
+
31
+ // Request 1: DB query, result cached
32
+ // Request 2: cache hit, no DB query
33
+ ```
34
+
35
+ Use when sequential user actions hit multiple endpoints needing the same data within seconds.
36
+
37
+ **With Vercel's [Fluid Compute](https://vercel.com/docs/fluid-compute):** LRU caching is especially effective because multiple concurrent requests can share the same function instance and cache. This means the cache persists across requests without needing external storage like Redis.
38
+
39
+ **In traditional serverless:** Each invocation runs in isolation, so consider Redis for cross-process caching.
40
+
41
+ Reference: [https://github.com/isaacs/node-lru-cache](https://github.com/isaacs/node-lru-cache)