✨ feat(vscode): React 文件照源码一块一张卡片,组件卡片只留名称、说明、构造参数
- 组件体的语句不再并进组件卡片,照源码顺序是它的子块;状态、引用、数据源、派生值、副作用、事件处理函数、渲染输出各成一张卡片,回调和函数里的语句是这些卡片下面的子卡片 - 普通变量、提前返回的 if、注释照语言默认的卡片;表格格子里只写名字和位置,去掉「改它的」「来自」格子里单独打开源码的那条路 - 用词改成书面叫法(更新位置、使用位置、计算表达式、依赖项、触发时机、清理函数、绑定事件、样式取决于……),新增 toggle-right、anchor、download、sigma、layout-template 五个种类图标 - 夹具加上 luffy 的 QueuedBubble.tsx、PlanChecklist.tsx,规格的 React 一节照新样子改写
This commit is contained in:
1 parent
194544b4ba
commit
6ce4ef7ee2
20 files changed
+1327
-989
No files matched your search
@@ -1561,76 +1561,115 @@ export interface CommandRule {
|
||||
|
||||
### 内置:React 组件(TypeScript / JavaScript)
|
||||
|
||||
`vscode/src/codeReader/rules/react.ts`(读语法树的办法在 `rules/reactTree.ts`,都是纯函数),`languageIds: ['typescriptreact', 'javascriptreact']`,`libraries: []`(新的 JSX 写法不用导入 react,TSX / JSX 文件都启用)。原型:`code.js` 的「React 组件」一节(`TITLEBAR_CARD`、`LEGAL_CARD`、`reactCard`),插件菜单「React 组件」那一页的四张画板;样例是 luffy 的 `components/desktop/DesktopTitlebar.tsx`(`fixtures/desktopTitlebar.tsx.txt`,简单)、`components/LegalDocPage.tsx`(`fixtures/legalDocPage.tsx.txt`,复杂),说明板的例子 `DeleteAppDialog`、`DesktopSettingsDialog`、`AppVaultSummary`、`ShareButton`、`PosterDialog` 也复制进了 `fixtures/`。三种卡片:
|
||||
`vscode/src/codeReader/rules/react.ts`(读语法树的办法在 `rules/reactTree.ts`,都是纯函数),`languageIds: ['typescriptreact', 'javascriptreact']`,`libraries: []`(新的 JSX 写法不用导入 react,TSX / JSX 文件都启用)。原型:`docs/prototype/code-reader/openpencil/react.js` 的三张画板「编辑器全貌」「卡片种类」「对照」(导出图 `exports/react-main.png`、`react-kinds.png`、`react-compare.png`);样例是 luffy 的 `chat/code/bubbles/QueuedBubble.tsx`(`fixtures/queuedBubble.tsx.txt`)和 `chat/code/PlanChecklist.tsx` 第 91–226 行(`fixtures/planChecklist.tsx.txt`,前面带上文件开头的导入),以前的 `DesktopTitlebar`、`LegalDocPage`、`DeleteAppDialog`、`DesktopSettingsDialog`、`AppVaultSummary`、`ShareButton`、`PosterDialog`、`OverviewSection` 也在 `fixtures/`。
|
||||
|
||||
- 组件:种类 `react.component`,名字「React 组件」,图标 `atom`,颜色暗 #61dafb / 亮 #0a7ea4(组件色,渲染大纲里的组件、「客户端组件」标签同色),和函数块一样默认收起留下的子块。
|
||||
- 副作用:种类 `react.effect`,名字「副作用」,图标 `zap`,颜色暗 #e5c07b / 亮 #9a6a00。
|
||||
- 事件处理:种类 `react.handler`,名字「事件处理」,图标 `mouse-pointer-click`,颜色暗 #dcdcaa / 亮 #795e26。
|
||||
TSX 和 Python 一样,从上往下一块语法一张卡片,嵌套的块排在父卡片下面,缩进、竖线、折叠同函数体。规则只换掉 React 的几种写法,别的块(导入、接口、类型、常量、普通变量、if、注释、尝试……)照语言默认的卡片。组件卡片不把组件体并进来:组件体的语句照源码顺序是它的子块,照常交给各规则看。表格的格子里只写名字和位置,函数体只出现在子卡片里。
|
||||
|
||||
认哪些是组件:名字大写开头;是函数声明、值是函数的变量(箭头函数、函数表达式,直接返回 JSX 的也算),或被 `memo(…)` / `forwardRef(…)`(`React.memo` 也算,可以套几层)包着的函数;函数自己的 return(嵌套函数里的不算)里有一处返回 JSX(元素、片段,三元、`&&` 的某一支是 JSX 也算;和 `null` 混着返回也算)。小写开头的工具函数、不返回 JSX 的大写函数照常是函数块。组件里又定义的组件自己也是一张组件卡片,不算处理函数。
|
||||
卡片种类(颜色写暗 / 亮):
|
||||
|
||||
整块换成组件卡片,不再是普通函数卡片的输入参数 / 输出参数。文件开头的 `"use client"`(文件里有组件时)和组件上面没并进块头部的 JSDoc(值是 `memo(…)`、直接返回 JSX 的常量块)略去(`RuleOmit`),讲成卡片上的「客户端组件」标签和「说明」。属性表(有才显示,没有就不画):
|
||||
| 种类 id | 名字 | 图标 | 颜色 | 认哪一块 | 行 |
|
||||
| --- | --- | --- | --- | --- | --- |
|
||||
| `react.component` | React 组件 | `atom` | #61dafb / #0a7ea4 | 组件的声明 | 名称 / 说明 / 构造参数 |
|
||||
| `react.state` | 状态 | `toggle-right` | #9cdcfe / #001080 | `const [v, setV] = useState(…)`、`useReducer(…)` | 名称 / 初始值 / 更新位置 |
|
||||
| `react.ref` | 引用 | `anchor` | #9cdcfe / #001080 | `useRef(…)` | 名称 / 初始值 / 使用位置 |
|
||||
| `react.source` | 数据源 | `download` | #9cdcfe / #001080 | 别的钩子赋给变量(`useQuery`、`usePathname`、`useRouter`、自定义 `useXxx`) | 变量 / 钩子 / 说明 |
|
||||
| `react.derived` | 派生值 | `sigma` | #9cdcfe / #001080 | `useMemo`、`useCallback` | 名称 / 计算表达式 / 依赖项 |
|
||||
| `react.effect` | 副作用 | `zap` | #e5c07b / #9a6a00 | `useEffect`、`useLayoutEffect`、`useInsertionEffect` | 触发时机 / 清理函数 |
|
||||
| `react.handler` | 事件处理函数 | `mouse-pointer-click` | #dcdcaa / #795e26 | 组件体里定义的函数(函数声明、值是函数的常量) | 名称 / 参数 / 绑定事件 |
|
||||
| `react.render` | 渲染输出 | `layout-template` | #89d185 / #388a34 | 组件函数自己返回 JSX 的 return | JSX 结构大纲 |
|
||||
|
||||
组件色同时用在渲染大纲里的组件、「客户端组件」标签上;状态、引用、数据源、派生值都是数据,共用变量块的浅蓝,靠图标区分;副作用同「选项」块的黄,事件处理函数同「函数」块,渲染输出同「返回」块的绿。筛选栏的「种类」按这几个 id 筛,叫上表的名字。
|
||||
|
||||
认哪些是组件:名字大写开头;是函数声明、值是函数的变量(箭头函数、函数表达式,直接返回 JSX 的也算),或被 `memo(…)` / `forwardRef(…)`(`React.memo` 也算,可以套几层)包着的函数;函数自己的 return(嵌套函数里的不算)里有一处返回 JSX(元素、片段,三元、`&&` 的某一支是 JSX 也算;和 `null` 混着返回也算)。小写开头的工具函数、不返回 JSX 的大写函数照常是函数块。组件里又定义的组件自己也是一张组件卡片,不算事件处理函数。
|
||||
|
||||
认领(`LibraryRule.claim` 一块一块看,组件卡片的 `absorbs` 是空的):
|
||||
|
||||
- 组件块(函数块、只声明一个变量的常量 / 变量块)是组件时换成组件卡片。文件开头的 `"use client"`(文件里有组件时)和组件上面没并进块头部的 JSDoc(值是 `memo(…)`、直接返回 JSX 的常量块)略去(`RuleOmit`),讲成卡片上的「客户端组件」标签和「说明」。
|
||||
- 组件体里的块:语法树往上找,块的语句直接是某个组件函数主体(语句块)的子语句才认(`enclosingComponent`:所在的函数经 `componentOfFunction` 找回它的声明,再用认组件的 `componentAt` 核对),按组件体的归类(`bodyOf`)认成状态、引用、数据源、派生值、副作用、事件处理函数。
|
||||
- `return` 块:所在的最内层函数(`enclosingFunction`)是组件函数、返回的是 JSX 时认成渲染输出;写在 `if` 里的提前返回 JSX 也算,它是如果卡片下面的子块。返回 `null` 这类的照常是返回块。
|
||||
- 别的照语言默认:组件体里普通的 `const x = 表达式` 是变量卡片,`if (…) return null` 是如果卡片、下面是返回卡片,注释照常成块(不再并进卡片)。
|
||||
- 回调、函数里的语句来自 TypeScript 语言插件本来给的子块:调用的实参是带语句块的函数时(任何调用都一样),那句语句、那个变量的子块就是函数里的语句,所以 `useEffect(() => {…})`、`useCallback(() => {…})`、`useMemo(() => {…})` 的语句排在副作用、派生值卡片下面;事件处理函数是函数块,函数体照常是子块。
|
||||
|
||||
组件卡片:
|
||||
|
||||
| 行 | 内容 |
|
||||
| --- | --- |
|
||||
| 名称 | 组件名(组件色,带下标);后面跟小标签(`tag` 框):「具名导出」「默认导出」(同 import / export 关键字的颜色;`export default X`、`export { X }` 写在文件别处也算)、「客户端组件」(组件色)、「记忆化」「转发 ref」(同 const 关键字的颜色,memo / forwardRef 包着) |
|
||||
| 说明 | 组件上面的 JSDoc,Markdown |
|
||||
| 构造参数 | `N 个`(hint);属性类型写的是一个名字(接口、类型别名、导入的类型)时后面写「 · 来自 XxxProps」,名字带下标(⌘ + 点击跳到类型)。下面一张表格「名称 \| 类型 \| 默认值 \| 必填」,有属性带说明时多一列「说明」。没写参数时写「无」 |
|
||||
| 状态 | useState / useReducer:「名称 \| 初始值 \| 改它的」 |
|
||||
| 引用 | useRef:「名称 \| 初始值 \| 用在」 |
|
||||
| 读取的数据 | 别的钩子(`useXxx(…)` 赋给变量):「变量 \| 来自 \| 意思」 |
|
||||
| 派生值 | 组件体里别的常量,和 useMemo / useCallback:「名称 \| 怎么算 \| 什么时候算」 |
|
||||
| 副作用 | `N 个`(hint),下面每个 useEffect / useLayoutEffect / useInsertionEffect 一张副作用子卡片 |
|
||||
| 事件处理 | 组件体里定义的函数(函数声明、值是函数的常量):「名称 \| 绑定在 \| 做什么」,点名称在表下面展开它的子卡片 |
|
||||
| 渲染 | `N 处返回`(hint),下面是返回的 JSX 画成的结构大纲 |
|
||||
| 构造参数 | `N 个`(hint);属性类型写的是一个名字(接口、类型别名、导入的类型)时后面写「 · 类型 XxxProps」,名字带下标(⌘ + 点击跳到类型)。下面一张表格「名称 \| 类型 \| 默认值 \| 必填」,有属性带说明时多一列「说明」。没写参数时写「无」 |
|
||||
|
||||
构造参数:属性类型的字段照类型里的顺序一行一个(类型字面量、同文件的接口 / 类型别名,交叉类型各部分接起来,`Readonly<…>`、`PropsWithChildren<…>` 看里面;没标注参数类型时 `const X: FC<Props>` 的泛型实参、`forwardRef<R, Props>` 的第二个泛型实参),解构里有、类型里没有的接在后面,`...rest` 最后(类型写「其余的属性」)。名称是属性名(定义处带下标:解构出来的是解构那处,没解构的是字段;跳到定义只闪这一行),`children` 后面标「子元素」、函数类型的属性(`(x) => R`、方法签名)标「回调」(组件色的小标签),解构时改了名写「(组件里叫 x)」;类型照翻译插件翻,方法签名写成函数签名;默认值取解构的默认值,没有写「—」;必填看类型的 `?`(是 / 否,storage 色),没类型可看时写了默认值的「否」、别的「—」;说明是字段上面的 JSDoc / 注释、这一行行尾的注释(comment 色,几行接成一行)。类型是导入的名字时经工作区索引查它的字段(索引 `react.propTypes`:看工作区里所有 `**/*.{ts,tsx}`,预筛有 `interface X` / `type X` 才解析,按 typescriptreact 解析;从文件顶层认出接口、类型别名,键是名字、值是各字段的名字、类型写法、可省略、回调、说明的 JSON),查法同「规则认领时查别的文件里的定义」:先照解构的出行、类型「未标注」,查到了按字段重排、重发;别的文件里的类型照写文字(type 色)。
|
||||
直接返回 JSX 的箭头函数组件(`const Tag = ({ text }) => <span>{text}</span>`)没有子块可放,它渲染的大纲作为第四行「JSX 结构大纲」写在组件卡片里。
|
||||
|
||||
状态、引用、读取的数据、派生值:
|
||||
构造参数:属性类型的字段照类型里的顺序一行一个(类型字面量、同文件的接口 / 类型别名,交叉类型各部分接起来,`Readonly<…>`、`PropsWithChildren<…>` 看里面;没标注参数类型时 `const X: FC<Props>` 的泛型实参、`forwardRef<R, Props>` 的第二个泛型实参),解构里有、类型里没有的接在后面,`...rest` 最后(类型写「其余的属性」)。名称是属性名(定义处带下标:解构出来的是解构那处,没解构的是字段;跳到定义只闪这一行),`children` 后面标「子元素」、函数类型的属性(`(x) => R`、方法签名)标「回调」(组件色的小标签),解构时改了名写「(组件内名为 x)」;类型照翻译插件翻,方法签名写成函数签名;默认值取解构的默认值,没有写「—」;必填看类型的 `?`(是 / 否,storage 色),没类型可看时写了默认值的「否」、别的「—」;说明是字段上面的 JSDoc / 注释、这一行行尾的注释(comment 色,几行接成一行)。类型是导入的名字时经工作区索引查它的字段(索引 `react.propTypes`:看工作区里所有 `**/*.{ts,tsx}`,预筛有 `interface X` / `type X` 才解析,按 typescriptreact 解析;从文件顶层认出接口、类型别名,键是名字、值是各字段的名字、类型写法、可省略、回调、说明的 JSON),查法同「规则认领时查别的文件里的定义」:先照解构的出行、类型「未标注」,查到了按字段重排、重发;别的文件里的类型照写文字(type 色)。
|
||||
|
||||
- 名称、变量带下标(解构模式照常翻),跳到定义只闪这一行。
|
||||
- 状态的初始值:useState 的实参、useReducer 的第二个实参(后面括号里写 reducer);改它的:改状态的函数名(function 色,带下标),后面括号里写在哪儿改,「;」隔开:「副作用」(几个时「副作用 2」)、处理函数名、派生值名、「<input> 的 onChange(传 e.target.value)」(绑在 JSX 属性上;在列表里一项项渲染的前面加「每个」)、「渲染时,当 … 时」(渲染时按条件重置状态的 `if (…) { setX(…) }`:主体都是在调改状态的函数,这句并进卡片)。
|
||||
- 引用的用在:「挂在 <main> 的 ref 上」(元素写成 `<Tag>`:组件用组件色、能跳到定义(`refers` 到标签名),原生标签灰色,带 `aria-label` / `title` 字符串时后面写「(返回)」),别处用到的「副作用 1、handleSectionClick 里用它」。
|
||||
- 读取的数据的来自照常翻;意思:库自带的钩子照词表(next/navigation 的 `usePathname` 当前路径、`useRouter` 路由器,跳转用、`useSearchParams`、`useParams`、`useSelectedLayoutSegment(s)`,react 的 `useId`、`useTransition`、`useSyncExternalStore`、`useOptimistic`、`useActionState`、`useDeferredValue`,react-dom 的 `useFormStatus`);`useContext(X)` 是「从 X 上下文读」;传选择器的 `useXxx((s) => s.a.b)` 是「从 xxx store 读 a.b」(store 名:导入路径最后一节是 store 时取上一节,`@/lib/desktop/store` 是 desktop;否则去掉 store、use 字样,再不行取钩子名),选择器不是直接取属性的写「从 xxx store 算 …」;自己项目里的(相对路径、`@/` 这类别名、同文件)是「自定义钩子」,别的库的是「xxx 的钩子」(hint)。
|
||||
- 派生值的怎么算照常翻:useMemo 是算值的那个表达式,useCallback 写「函数 」加函数;主体是语句块时写「N 句」,那句照常是块、放进这一行对应的子行上,点名称展开(useCallback 的用事件处理子卡片,useMemo 的照常是变量块);什么时候算:普通常量「每次渲染」,useMemo / useCallback 按依赖读(同副作用的时机)、后面写「(useMemo)」。
|
||||
状态、引用、数据源、派生值(名称、变量带下标,解构模式照常翻;跳到定义闪这张卡片):
|
||||
|
||||
副作用子卡片(组件体里那句 `useEffect(…)` 照常是块,被规则认成这张卡片,放进卡片「副作用」那一行下面):时机按依赖数组读,`[a, b]` 是「a、b 变了时」,`[]` 是「只在挂载时」,没写是「每次渲染后」(keyword 色),useLayoutEffect 后面加「,浏览器绘制前」;做什么是紧贴在上面的注释(几行接成一行,hint 色;这段注释并进组件卡片),没写注释时写「N 句」;副作用函数里的语句照常是块,放进「做什么」那一行下面;最后返回清理函数时那句 return 并进来,多一行「清理」:`() => …` 翻它的主体,语句块一句句翻、「;」隔开。
|
||||
- 状态的初始值:useState 的实参、useReducer 的第二个实参(后面括号里写 reducer)。更新位置:调用改状态函数的各处,只写名字和位置,「、」隔开,写出来一样的只留一处,没有时「—」:「副作用」(几个时「副作用 2」,副作用色)、事件处理函数名 / 派生值名 / 变量名 / 数据源的变量名(带下标,⌘ + 点击跳到那张卡片)、「<textarea>(排队消息内容) 的 onChange」(绑在 JSX 属性上;元素写成 `<Tag>`:组件用组件色、能跳到定义(`refers` 到标签名),原生标签灰色,带 `aria-label` / `title` 字符串时后面写上它;在列表里一项项渲染的前面加「每个」)、「渲染期间,当 … 时」(渲染时按条件重置状态的 `if (…) { setX(…) }`,这句 if 照常是如果卡片)、「渲染输出」(JSX 里别处用到)。
|
||||
- 引用的使用位置:「<textarea>(排队消息内容) 的 ref 属性」,别处用到的「;」接在后面、几处「、」隔开:「<main> 的 ref 属性;副作用 1、副作用 2、handleSectionClick」。
|
||||
- 数据源的钩子是这次调用,照常翻;说明:库自带的钩子照词表(next/navigation 的 `usePathname` 当前路径、`useRouter` 路由器,用于页面跳转、`useSearchParams` URL 查询参数、`useParams` 路由动态参数、`useSelectedLayoutSegment(s)` 当前激活的下一级 / 各级布局段,react 的 `useId`、`useTransition`、`useSyncExternalStore`、`useOptimistic`、`useActionState`、`useDeferredValue`,react-dom 的 `useFormStatus`);`useContext(X)` 是「X 上下文的值」;传选择器的 `useXxx((s) => s.a.b)` 是「xxx store 中的 a.b」(store 名:导入路径最后一节是 store 时取上一节,`@/lib/desktop/store` 是 desktop;否则去掉 store、use 字样,再不行取钩子名),选择器不是直接取属性的写「基于 xxx store 计算 …」;自己项目里的(相对路径、`@/` 这类别名、同文件)是「自定义钩子」,别的库的是「xxx 提供的钩子」(hint)。
|
||||
- 派生值的计算表达式:useMemo 是算值的那个表达式(照常翻),主体是语句块时写「N 条语句」;useCallback 记住的函数主体是语句块时写「函数(N 条语句)」,直接返回表达式的照常翻整个函数。依赖项:依赖数组的各项「、」隔开,后面写「(useMemo)」「(useCallback)」;空数组写「无」,没写依赖数组写「未指定」。主体是语句块时里面的语句是这张卡片的子块。
|
||||
|
||||
事件处理:表里名称是函数名(function 色,带下标);绑定在从 JSX 属性反查:「<button>(打印) 的 onClick」,在属性值里调用时写传的实参「(传 h.id)」,在列表里一项项渲染的写「每个 <button>」,几处「、」隔开;没绑在 JSX 上时写被谁调用「被 download、share 调用」,都没有「—」;做什么是紧贴在上面的注释(函数声明的 JSDoc 也算),直接返回表达式的箭头函数照常翻它,别的写「N 句」。处理函数那句照常是块,被规则认成事件处理子卡片(名称 / 参数 `id: 字符串` / 做什么,函数里的语句放进「做什么」下面),放进表格对应的子行上:默认收着,点名称展开、那一行淡淡垫上事件处理的颜色,同一张表里别的收起;再点名称或子卡片左上角的箭头收起。
|
||||
副作用:触发时机按依赖数组读,`[a, b]` 是「a、b 变化时」,`[]` 是「仅挂载时」,没写是「每次渲染后」(keyword 色),依赖写成别的表达式时「deps 变化时」;useLayoutEffect 后面加「,浏览器绘制前」。最后返回清理函数时那句 return 并进来,多一行「清理函数」:`() => …` 翻它的主体,语句块一句句翻、「;」隔开。副作用函数里别的语句是子块。
|
||||
|
||||
渲染大纲(「渲染」一行下面的子行,一行一个元素,下一层缩进;带下一层的行有折叠箭头):
|
||||
事件处理函数:名称是函数名(function 色,带下标);参数照常翻(`e: KeyboardEvent<HTMLDivElement>`),几个「, 」隔开,没有写「无」;绑定事件从 JSX 属性反查:「<div>(修改排队消息) 的 onKeyDown」,在属性值里调用时写传入的实参「(传入 h.id)」,在列表里一项项渲染的写「每个 <button>」,几处「、」隔开;没绑在 JSX 上时写由谁调用「由 download、share 调用」,都没有「—」。函数里的语句是子块(如果、返回、调用、变量、注释、尝试……)。
|
||||
|
||||
渲染输出(「JSX 结构大纲」一行下面的子行,一行一个元素,下一层缩进;带下一层的行有折叠箭头):
|
||||
|
||||
- 元素:标签名,原生标签灰色(暗 #808080 / 亮 #6f6f6f),组件用组件色、带下标能跳到定义(`a.b` 一节节都能跳);`<></>` 写「<> 片段,不产生元素」。
|
||||
- `className`(`class`)收成「样式 N 个类」小标(`classes` 框):N 是写死的类;按条件切换的(模板字符串里的三元、`cn(…)` / `clsx(…)` 的实参、`cond && "x"`、`{ "x": cond }`)、算出来的表达式在后面写「 · 随 doc 变」(比较的左边、取反的那个,算出来的写它自己);点开在下面弹出全部类名(写死的一行,按条件的「doc 全等 "terms" 时:…」「否则:…」,算出来的「另加 …」),盖住后面的字,再点收起;悬停也能看。
|
||||
- 别的属性(`key` 不写,列表那一行写)写成「名字=值」,两个空格隔开:字符串照写,表达式照常翻,跨几行写的对象只写有哪些键「对象:h2、a」,值是 JSX 元素时写 `<Tag>`,只写了名字的(`aria-hidden`)就是名字,`{...x}` 照写。
|
||||
- `className`(`class`)收成「样式 N 个类」小标(`classes` 框):N 是写死的类;按条件切换的(模板字符串里的三元、`cn(…)` / `clsx(…)` 的实参、`cond && "x"`、`{ "x": cond }`)、算出来的表达式在后面写「 · 取决于 doc」(比较的左边、取反的那个,算出来的写它自己);点开在下面弹出全部类名(写死的一行,按条件的「doc 全等 "terms" 时:…」「否则:…」,算出来的「另加 …」),盖住后面的字,再点收起;悬停也能看。
|
||||
- 别的属性(`key` 不写,列表那一行写)写成「名字=值」,两个空格隔开:字符串照写,表达式照常翻,跨几行写的对象只写有哪些键「对象:h2、a」,只写了名字的(`aria-hidden`)就是名字,`{...x}` 照写。属性值是元素、条件或列表时不写进元素那一行:属性名单独成行,值照同一套大纲缩进在下面。
|
||||
- 子节点只有文字、插值时写在同一行:只有一段文字时带引号,插值写成 `{…}`(花括号 hint 色),和文字混着时文字不带引号。
|
||||
- `cond && <X/>` 前面加「当 … 时」小框(`condition`,条件照常翻);三元一行「如果 …」,下面第一行各带「是」「否」小框(`branch`),一支是 null 时写「不渲染」;`items.map((x) => …)` 一行「对 items 的每一项 x」(`iteration` 小框)后面「key …」,回调里先算的常量写「其中 isActive = …」,再下面是每一项渲染的;JSX 注释写成一行「// …」(comment 色)。
|
||||
- 几处返回:分几段,提前 `return null`(`if (cond) return null`,主体只有这一句)写「当 … 时」(`skip` 小框)「不渲染」,提前返回 JSX 的「当 … 时」下面是它渲染的,最后一处「否则」(`branch` 小框);只有一处返回时直接是它的大纲。这些 return(和提前返回的 if)并进卡片。
|
||||
|
||||
组件体里归不进上面分区的语句(没讲进分区的注释、别的 if、循环、单独调用的钩子)照常是组件卡片留下的子块。卡片「编辑」是组件的完整代码(整条语句);副作用、处理函数子卡片各自能编辑、问 AI。状态「改它的」里每一处、读取的数据的「来自」各自有同一套铅笔,打开后只出现那一段源码(整行切好、着色好,和块同一套编辑框、同一条改文件的消息):来自是这次钩子调用占的行,不是左边的变量名;改它的里 JSX 是整个属性(名字和值),处理函数、派生值、另一处读取、重置条件各开各的那段(函数、那个值、那次调用、那个条件),纯渲染没有铅笔。这段的行落在组件里面,组件正在编辑时不画这段,两边不能同时编辑。代码差异在视图数据这一层比:组件卡片的属性表逐行(属性表按名称配对,加的属性标新加的一行),副作用、处理函数子卡片是块,照常配对、逐行标(改了依赖,「时机」那一行逐截标)。
|
||||
每张卡片「编辑」是它那条语句的完整代码,组件卡片是整个组件(盖住它的子块);组件体里的卡片各自能编辑、问 AI。代码差异在视图数据这一层比:组件卡片的属性表逐行(属性表按名称配对,加的属性标新加的一行),组件体里的卡片是块,照常配对、逐行标(改了依赖,「触发时机」那一行逐截标)。
|
||||
|
||||
样例(`fixtures/desktopTitlebar.tsx.txt`,测试里逐字核对;`⟦…⟧` 是小标签、小框):
|
||||
样例(`fixtures/planChecklist.tsx.txt` 的 `PlanChecklist`,测试里逐字核对;`⟦…⟧` 是小标签、小框,子块多缩进两格,说明只写第一行):
|
||||
|
||||
```
|
||||
名称: DesktopTitlebar ⟦具名导出⟧ ⟦客户端组件⟧
|
||||
说明: 窗口顶部 40px. 整条连同里面的文字都是拖拽区 (data-tauri-drag-region="deep"), 按钮除外. 侧栏开关只在侧栏顶部.
|
||||
构造参数: 1 个
|
||||
platform | DesktopShell["platform"] | — | 是
|
||||
读取的数据: 2 个
|
||||
pathname | usePathname() | 当前路径
|
||||
title | useDesktopShell((s) => s.title) | 从 desktop store 读 title
|
||||
派生值: 1 个
|
||||
center | title ?? PAGE_TITLES[pathname] ?? "" | 每次渲染
|
||||
渲染: 1 处返回
|
||||
div ⟦样式 8 个类⟧ data-tauri-drag-region="deep"
|
||||
div ⟦样式 3 个类⟧
|
||||
⟦当 platform 全等 "macos" 时⟧ span ⟦样式 1 个类⟧ data-testid="traffic-light-inset" aria-hidden
|
||||
div ⟦样式 6 个类⟧
|
||||
span ⟦样式 4 个类⟧ {center}
|
||||
⟦当 platform 全等 "windows" 时⟧ WindowControls
|
||||
react.component 23
|
||||
名称: PlanChecklist ⟦具名导出⟧ ⟦客户端组件⟧
|
||||
说明: 执行期"计划清单"实时勾选 (TodoWrite 式): code-agent 批准计划后边执行边刷新各步
|
||||
构造参数: 2 个 · 类型 PlanChecklistProps
|
||||
todos | PlanTodo[] | — | 是 | 执行期计划清单 (覆盖式刷新); 空数组时不渲染.
|
||||
active | 布尔 | — | 是 | 本轮是否仍在流式执行中. ``in_progress`` 仅在 ``active`` 时转圈; …
|
||||
react.state 35
|
||||
名称: collapsed
|
||||
初始值: 假
|
||||
更新位置: 副作用、toggle
|
||||
react.effect 37
|
||||
触发时机: 仅挂载时
|
||||
try 38: 尝试
|
||||
if 39: 如果 (localStorage.getItem(PLAN_CHECKLIST_COLLAPSED_KEY) 全等 "1")
|
||||
statement 40: queueMicrotask(() => setCollapsed(真));
|
||||
catch 42: 捕获
|
||||
comment 43: localStorage 不可用 (隐私模式等) 时静默用默认
|
||||
react.derived 47
|
||||
名称: toggle
|
||||
计算表达式: 函数(3 条语句)
|
||||
依赖项: collapsed(useCallback)
|
||||
variable 48
|
||||
名称: next
|
||||
初始值: 非 collapsed
|
||||
statement 49: setCollapsed(next);
|
||||
try 50: 尝试
|
||||
statement 51: localStorage.setItem(PLAN_CHECKLIST_COLLAPSED_KEY, 如果 next 则 "1" 否则 "0");
|
||||
catch 52: 捕获
|
||||
comment 53: 忽略写入失败
|
||||
if 57: 如果 (todos.length 全等 0)
|
||||
return 57: 返回 空;
|
||||
variable 58
|
||||
名称: whole
|
||||
初始值: wholeStatusOf(todos, active)
|
||||
…(doneCount、counter、current 三张变量卡片,一张注释卡片,headline 变量卡片)
|
||||
react.render 65
|
||||
JSX 结构大纲:
|
||||
Collapsible ⟦样式 1 个类 · 取决于 CARD_SURFACE⟧ open=非 collapsed onOpenChange=toggle
|
||||
CollapsibleTrigger ⟦样式 3 个类 · 取决于 FLUSH_ROW_INTERACTIVE⟧ data-testid="plan-checklist-toggle"
|
||||
div ⟦样式 4 个类⟧ data-testid="plan-progress"
|
||||
…
|
||||
```
|
||||
|
||||
和原型不一样的地方:原型里「做什么」「意思」、派生值的读法(「title;没有就按路径查 PAGE_TITLES」)是照设计手写的中文,实现里是注释原文、照翻译插件翻的译文和词表;条件照翻译插件读(`===` 是「全等」,原型写「是」);渲染大纲带下一层的行有折叠箭头;副作用子卡片收起时不换成一行摘要,「做什么」那一行的箭头收起它下面的语句。
|
||||
和原型不一样的地方:接口 `PlanChecklistProps` 照 TypeScript 的接口块(一行译文,字段、注释是子块),原型「对照」里画成的字段表(名称 / 类型 / 必填 / 说明)这次没做;渲染输出的大纲挂在「JSX 结构大纲」这一行下面,不是直接画在卡片里;更新位置、使用位置里的「副作用」是副作用色的字,不能跳(副作用没有名字可查定义),原生标签(`<textarea>`)也不能跳,组件标签能跳到组件定义。
|
||||
|
||||
### 内置:Rust 的库
|
||||
|
||||
|
||||
Reference in new issue
Block a user