5050 * 可见),不会静默白屏。棘轮口径:新增代码 0 处颜色/边框/字号字面量(错误色走
5151 * `StatusLine` 原语 · 间距走 `--ed-space-*`),`style` 只承载布局(ADR-033 §4)。
5252 */
53- import { Suspense , createElement , lazy , useCallback , useMemo , useState } from "react" ;
54- import type { ComponentType , RefObject } from "react" ;
53+ import { Suspense , createElement , useCallback , useMemo , useState } from "react" ;
54+ import type { RefObject } from "react" ;
5555import type { Note , NoteGroup } from "../../types" ;
5656import type { NoteEditHandle } from "../NoteEditView" ;
5757import type { ColumnLayout } from "../../hooks/useColumnLayout" ;
5858import type { SelectionNoteAction } from "../../utils/noteSelectionMenu" ;
5959import type { NoteViewSlot , ViewSpec } from "../../views/registry" ;
6060import { useViewMemory } from "../../views/useViewMemory" ;
61- import NoteReadingView from "../NoteReadingView" ;
62- import RichEditorView from "../RichEditorView" ;
63- import NoteHeaderActions from "../NoteHeaderActions" ;
64- import VersionPanel from "../VersionPanel" ;
6561import { ShellFallback } from "../../shell/ShellFallback" ;
66- import { StatusLine , Text , ViewSwitcher } from "../../ui/primitives" ;
62+ import { StatusLine , ViewSwitcher } from "../../ui/primitives" ;
63+ import { ResidentNoteView } from "./NotesReadingColumn.parts" ;
64+ import { CARD_FLOW_LOAD , lazyMapOf } from "./readingColumnLoaders" ;
6765
6866/** `views` 缺席时的空清单:**模块级常量**(稳定引用 ⇒ 下面的 `useMemo` 不每渲染重算) */
6967const NO_VIEWS : readonly ViewSpec < NoteViewSlot > [ ] = [ ] ;
7068
71- /** 卡片流键(= 注册表的 `NOTE_VIEWS[1]`;本件不 import 注册表 —— C1①)与其**带 seek 包装件**加载器(T17/C10.3:该槽缺 `onOpenSessionAt`);仍经 `lazy()` ⇒ 模块级惰性不变。 */
72- const CARD_FLOW_KEY = "cardflow" ;
73- const CARD_FLOW_LOAD = ( ) : Promise < { default : ComponentType < NoteViewSlot > } > => import ( "../../views/note/NoteCardFlowWithSeek" ) ;
74-
7569interface Props {
7670 /** 当前选中笔记(null=空态占位) */
7771 selected : Note | null ;
@@ -117,20 +111,8 @@ interface Props {
117111 views ?: readonly ViewSpec < NoteViewSlot > [ ] ;
118112}
119113
120- export default function NotesReadingColumn ( {
121- selected, editing, setEditing, readerSearch, noteColors, groups, editorRef, outlineCol,
122- onChanged, onError, onCreateSystem, onOpenAi, onOpenModelCard, onSelectionAction,
123- onPinToggle, onDelete, onTaskToggle, onTagClick, onOpenSession, onOpenSessionAt, onImageOpen, onCleanNotice,
124- views,
125- } : Props ) {
126- // H3:辅助面板插槽——VersionPanel(知识补充已迁移至编辑态 🤖 AI 菜单——
127- // v0.17.0 REQ-246:阅读态独立面板移除,用 AI 直接进入编辑态)
128- const auxPanels = selected ? (
129- < >
130- < VersionPanel key = { `version-${ selected . id } ` } noteId = { selected . id } onChanged = { ( ) => void onChanged ( ) } onOpenSessionAt = { onOpenSessionAt } />
131- </ >
132- ) : null ;
133-
114+ export default function NotesReadingColumn ( props : Props ) {
115+ const { selected, editorRef, onTaskToggle, onOpenSession, onOpenSessionAt, onImageOpen, views } = props ;
134116 // ── 批 5 T14:视图宿主(C1① 注入 · C5 记忆 · C4 守卫 · C11 槽位)──
135117 const specs = views ?? NO_VIEWS ;
136118 const keys = useMemo ( ( ) => specs . map ( ( v ) => v . key ) , [ specs ] ) ;
@@ -163,15 +145,8 @@ export default function NotesReadingColumn({
163145 [ viewKey , editorRef , setViewKey ] ,
164146 ) ;
165147
166- /**
167- * 惰性映射:**默认视图无 `load` ⇒ 值为 `null`**,永不进 `React.lazy`(§7.3② 的构造性证据)。
168- * `lazy()` 只按 `specs` 引用建一次 —— 每渲染新建会让子树恒重挂(F5 的挂载计数会当场红)。
169- * T17:**卡片流**经包装件加载(键漂移会让它静默失效 ⇒ F11 用例即守卫)。
170- */
171- const lazyOf = useMemo (
172- ( ) => new Map ( specs . map ( ( spec ) => [ spec . key , spec . load ? lazy ( spec . key === CARD_FLOW_KEY ? CARD_FLOW_LOAD : spec . load ) : null ] ) ) ,
173- [ specs ] ,
174- ) ;
148+ /** 惰性映射(键常量与工厂已搬到 `readingColumnLoaders`);`useMemo` 留在宿主 —— 工厂是**纯函数**、不持有记忆。 */
149+ const lazyOf = useMemo ( ( ) => lazyMapOf < NoteViewSlot > ( specs , CARD_FLOW_LOAD ) , [ specs ] ) ;
175150 const isDefault = viewKey === defaultKey ;
176151 const LazyView = isDefault ? null : lazyOf . get ( viewKey ) ?? null ;
177152 /** 非默认视图的槽(数据全在这里,视图自身零取数 —— C14②);空态 ⇒ `null`(连卡片流都不挂)。
@@ -181,75 +156,8 @@ export default function NotesReadingColumn({
181156 : null ;
182157 const viewProps = slot === null ? null : { ...slot , onOpenSessionAt } ;
183158
184- /** 默认视图(原文)节点:T14 之前逐字相同,只是现在由常驻容器承载(§7.3①) */
185- const residentView = selected ? (
186- < NoteReadingView
187- note = { selected }
188- editing = { editing }
189- // v0.19.1:命中词阅读搜索(仅当请求属于当前选中笔记——过期请求不注入)
190- externalSearch = { readerSearch && selected ?. id === readerSearch . noteId
191- ? { key : readerSearch . key , query : readerSearch . search }
192- : null }
193- outlineFolded = { outlineCol . folded }
194- // 批 3 T8:大纲列宽/拖拽经 props 注入(此前 NoteReadingView 写死 180,
195- // hook 的宽度记忆与 min/max 夹取全部失效——审计 J1-6「假可调」)
196- outlineWidth = { outlineCol . width }
197- onOutlineResize = { outlineCol . resizeBy }
198- onOutlineReset = { outlineCol . resetWidth }
199- // 批 3 T8(J1-3):窄条(ColumnBar)点击必须走 expand()——它同时清自动/手动
200- // 折叠态;旧实现只翻 manualFolded,窄窗自动折叠下 folded 恒为真 ⇒ 点窄条
201- // 永不展开。未折叠时的 ✕「收起大纲」仍是手动折叠(与 NotesGroupsColumn 的
202- // bar=expand / onCollapse=setManualFolded 同款形态)
203- onToggleOutline = { ( ) =>
204- outlineCol . folded ? outlineCol . expand ( ) : outlineCol . setManualFolded ( true )
205- }
206- editor = {
207- < RichEditorView
208- key = { selected . id }
209- ref = { editorRef }
210- note = { selected }
211- onCancel = { ( ) => {
212- // v0.13.6:完成编辑 → 列表重载 + 选中笔记重取(右栏立即显示新标题/正文)
213- setEditing ( false ) ;
214- void onChanged ( ) ;
215- } }
216- // v0.14 A:编辑态图片点击放大(与阅读态同一入口)
217- onImageOpen = { ( src , title ) => onImageOpen ( src , title ) }
218- // 批 8(REQ-317):编辑态选区行动类(转问题/模型卡预填)
219- onSelectionAction = { onSelectionAction }
220- />
221- }
222- auxPanels = { auxPanels }
223- headerExtra = {
224- < NoteHeaderActions
225- key = { `hdr-${ selected . id } ` }
226- note = { selected }
227- resolvedColor = { noteColors [ selected . id ] ?? null }
228- groups = { groups }
229- onChanged = { ( ) => void onChanged ( ) }
230- onError = { ( m ) => onError ( m ) }
231- onGotoKnowledgeSystem = { onCreateSystem }
232- onOpenAi = { onOpenAi }
233- onOpenModelCard = { onOpenModelCard }
234- onCleanNotice = { onCleanNotice }
235- />
236- }
237- onEdit = { ( ) => setEditing ( true ) }
238- onPinToggle = { ( ) => void onPinToggle ( selected ) }
239- onDelete = { ( ) => void onDelete ( selected . id ) }
240- onTagClick = { onTagClick }
241- onOpenSession = { ( id ) => onOpenSession ?.( id ) }
242- onOpenSessionAt = { onOpenSessionAt }
243- onTaskToggle = { onTaskToggle }
244- onImageOpen = { ( src , title ) => onImageOpen ( src , title ) }
245- // 批 8(REQ-317):阅读态选区行动类(转问题/模型卡预填)
246- onSelectionAction = { onSelectionAction }
247- />
248- ) : (
249- < Text as = "div" size = { 4 } tone = "ink-3" style = { { flex : 1 , display : "flex" , alignItems : "center" , justifyContent : "center" } } >
250- 从左侧选择一条笔记查看
251- </ Text >
252- ) ;
159+ /** 原文常驻子树的**展示装配**已搬到 `NotesReadingColumn.parts`(本件把整份 props 原样透传 —— 见该件文件头的字节预算理由)。 */
160+ const residentView = < ResidentNoteView { ...props } /> ;
253161
254162 return (
255163 < div style = { { flex : 1 , minWidth : 0 , display : "flex" , overflow : "hidden" } } >
0 commit comments