跳转到内容

使用 Eidos File UI 构建编辑器

@eidos.space/eidos-file-ui@2.0.0 是已发布的 Eidos UI 1.0 React presentation layer。可互操作依赖方向固定为:

Eidos File → Runtime → Adapter / HostServices → UI

可复用 UI package 不接收 SQLite、SQL、File bytes、native handle 或 ambient path。筛选、Formula、Lookup、Relation、分组、校验与 mutation 语义都属于 @eidos.space/eidos-file Runtime。

Terminal window
pnpm add @eidos.space/eidos-file@2.0.0 \
@eidos.space/eidos-file-ui@2.0.0 react react-dom

应用入口只需引入一次样式:

import "@eidos.space/eidos-file-ui/styles.css"

宿主应用实现 HostServicesopenSource 返回 UI 唯一可消费的 RuntimeClientEidosUIKernel 完成两层协商、加载 revision-bound schema, 并负责 page/cursor invalidation。

import { useEffect, useMemo } from "react"
import { EidosUIKernel } from "@eidos.space/eidos-file-ui/kernel"
import {
EidosStandardView,
EidosUIRuntimeProvider,
} from "@eidos.space/eidos-file-ui/runtime-platform"
import "@eidos.space/eidos-file-ui/styles.css"
export function ProjectView({ host, sourceToken, assetPresenter }) {
const kernel = useMemo(() => new EidosUIKernel(host), [host])
useEffect(() => {
void kernel.openSource({ sourceToken, access: "read" })
return () => void kernel.close()
}, [kernel, sourceToken])
return (
<EidosUIRuntimeProvider
kernel={kernel}
assetPresenter={assetPresenter}
themeName="light"
>
<EidosStandardView />
</EidosUIRuntimeProvider>
)
}

EidosStandardView 只使用有界 Runtime 结果渲染标准 Grid、Gallery 与 Kanban。未知 namespaced view type 会继续无损保存;在宿主提供隔离 renderer 之前显示 unsupported 状态。

EidosStandardView 是只读 viewer 组合。Browser 与 Desktop 使用 EidosFileEditorShell 作为共享编辑器的 layout owner,统一 View tabs、查询控件、 Fields、数据画布、Table tabs 与编辑器 overlay。

import { EidosFileEditorShell } from "@eidos.space/eidos-file-ui/eidos-file-editor-shell"
const editor = (
<EidosFileEditorShell
viewTabs={<EidosFileViewTabs {...viewTabs} />}
queryToolbar={<EidosFileQueryToolbar {...query} />}
fields={<EidosFileViewFieldsPopover {...fields} />}
fieldCreator={<EidosFileFieldCreatePopover {...fieldCreator} />}
sheetTabs={<EidosFileSheetTabs {...sheets} />}
>
<EidosFileEditorView source={source} table={table} view={view} />
</EidosFileEditorShell>
)

以上具名控件由 Host 组合提供。浏览器文件选择器、Desktop 文件系统集成、保存与 冲突处理、版本历史和 extension process 仍然属于 Host 职责。

File cell 是完整 FileEntry object 的有序数组。uri 只能是:以当前 .eidos 文件所在目录为 root 的 relative URI-reference、绝对 https: URI, 或 canonical inline image Data URL。UI 不得自行 join、fetch 或 navigate 该 URI。

图片出现在可见 surface 时,UI 以 entry ID 和 thumbnail purpose 调用 HostServices.resolveAsset,并且只把返回 lease 交给注入的 AssetPresenter。打开与下载必须是显式用户动作,分别使用 previewdownload lease。所有 lease 都受 size、expiry、session 限制,并在 surface 消失时释放。

DOM card 使用 AssetPresenter.renderImage。Canvas-backed Grid 使用 optional AssetPresenter.loadImage,decode 完成后重绘,并在 row 离开 bounded visible-row window 时释放 lease。该方法缺失时 Grid 走 fallback,绝不直接从 canonical URI 绘图。

确定性的 fallback 顺序为:

  1. Host 解析的图片缩略图;
  2. 可信 media-family icon 或通用 file icon;
  3. inert、无损的 URI 展示/复制文本。

普通 URL 字段不会因为 cell 可见而发起 fetch。没有 session-scoped relative asset root 的 Host 必须从 assetReadSchemes 省略 relative,不能 fallback 到 应用 origin、cwd 或 downloads。SVG 等 active content 必须由 Host 隔离展示, 不得 unsandboxed inline render。

资产导入沿反向边界执行:composition 获取 opaque source token,调用 HostServices.acquireAsset,再把 Host 返回的 FileEntry 原样提交给 Runtime mutation。UI 只能重排或移除完整 entry,不能制造 ID、URI、media type 或 size。

宿主应用负责:

  • source/destination grant、权限、保存/CAS、冲突与恢复;
  • Browser Worker 或 Desktop IPC transport,以及 Runtime replacement;
  • relative、Data URL、HTTPS 资产的真实 capabilities 与 limits;
  • purpose-scoped AssetLease 的签发、展示、激活与释放;
  • isolation、traversal/symlink/origin 检查、media/decode limit 与网络策略。

SQLite 与重计算不得进入 React。未知 schema/view extension 必须无损保留。 测试应覆盖取消、epoch replacement、只读行为、键盘 focus、窄布局、asset expiry、 三种 File URI class,以及 zero direct URI fetch/navigation。

EidosFileUIProvider 支持 locale="en"locale="zh",也支持宿主覆盖 message。Locale 只影响 presentation;用户创建的 table、field、view、option 与 record name 始终是 File data。