Files
mnote/design/04-tree-domain/done/4-7-tree-shell-ui-state-boundary-v1.md
T

2.5 KiB

4-7 [done] Tree Shell UI State Boundary v1

更新时间:2026-04-18

目的:明确哪些状态属于 projection,哪些状态只能留在 tree shell / renderer 本地。

1. 结论

树域必须严格区分:

  • projection truth
  • local UI state

否则 Rust projection、Leptos tree shell、Next 挂载切流会继续把状态缠回旧前端壳。

2. 属于 projection 的状态

这些状态必须来自上游 projection 或 command 结果,而不是由 UI 自行猜测:

  • nodeId
  • parentNodeId
  • projectionKind
  • nodeType
  • title
  • depth
  • position
  • childCount
  • expandable
  • expandedByDefault
  • capabilities
  • resourceMeta
  • iconHint

说明:

  • projection 只描述“结构真相”和“允许做什么”
  • projection 不承载 hover、selected、dragging 等临时交互态

3. 只能留在 UI 本地的状态

这些状态只能存在于 tree shell / renderer 本地:

  • expanded
  • selected
  • hover
  • focus
  • dragging
  • drop target
  • context menu open
  • keyboard navigation anchor

说明:

  • expandedByDefault 是 projection 建议值
  • expanded 是本地会话态,不直接回写 projection

4. 边界规则

4.1 expanded

  • 初始值可由 expandedByDefault 推导
  • 运行期展开/折叠必须只保留在本地状态
  • 不能把 expanded 反向写回 projection item

4.2 selected

  • selected 属于当前用户当前会话的局部状态
  • 不能作为 projection 的共享字段

4.3 focus

  • focus 属于 keyboard / accessibility 层本地状态
  • 不能参与结构真相

4.4 dragging / drop target

  • draggingdrop target 是瞬时状态
  • 只能存在于 DnD 状态机
  • drop 成功后,真正持久化的是 tree.subtree.move 等命令结果

5. Rust 与前端共识

Rust 负责:

  • 输出 projection
  • 接收 command
  • 返回 command result / resync snapshot

前端或 Leptos shell 负责:

  • expanded
  • selected
  • hover
  • focus
  • dragging
  • drop target

6. 对 page_tree / file_tree / picker 的影响

  • page_treefile_tree、picker 必须共用同一套本地状态边界
  • picker 只是交互能力更窄,不是另一套状态模型
  • keyboardselectionfocusdragging 的命名与语义必须一致

7. 完成判定

当以下条件同时成立时,视为状态边界冻结完成:

  • 文档明确列出 projection 与本地状态
  • Rust 和前端都不再把 expanded/selected/focus/dragging/drop target 写进 projection
  • 后续 Leptos shell 与 Next consumer 使用同一份边界说明