@cratis/scene

中文文档
0.342.1发布于 2026/11/11MITTypeScriptES Module零依赖近 30 天下载 7.5万

Cratis Scene:使工作室原型成为缩略图和预览.

中文使用文档
文档目录9 节
  1. 序列化原型预览
  2. 布局预览 DTO
  3. 构成部分类别——如何运作
  4. 为什么要扩展外部组件?
  5. 序列化如何运作
  6. Id桥
  7. 这个 _derivedTypeId 拥有财产
  8. 类型密钥
  9. 子类作者

场景

工作室低码画布的TypeScript模型:UIElement分级,外接组件,和原型的表面组件系统.

序列化原型预览

PrototypeThumbnail 接受两个直播 IComponent 实例和原始 UIElement jSON文档中的数据。 在渲染时, Scene 使用元素的库合格 _derivedTypeId (或 componentName)来构建一个已注册的组件并复制其保存状态,在所有已命名的槽中递归式水分元素数组而不改变源文档。 没有注册的图书馆,它就会产生一个位置大小的占位符,而不是空的原型. 库注册本身不会触发 React 重置;在装入捆绑后重置缩略图以替换实际组件的占位符. 没有打开的动作,缩略图就是一个命名的、非焦点化的预览;有一个仍是一个编辑器打开按钮。 棋盘/文档阅读器不装入捆绑或依赖于 Studio Core.

布局预览 DTO

六个 StudioLayout.* 类型(Stack, (中文(简体) ), Row, (中文(简体) ), Grid, (中文(简体) ), Container, (中文(简体) ), Wrap,以及 Canvas)是后端预览 DTO. 它们来自现有的 FrameworkElement编号 :UIElement 级并使用相同的上线 ComponentName,继承 Properties,以及 Slots 形状为 ExternalComponent,所以通用的板预览可以绕行他们的被窝子. 他们故意不从 ExternalComponent:当前衍生型转换器将一个有已注册子类的基座作为歧视家族对待,然后不能将一个通名化 externalComponent 自己来 这个相容性边界避免了改变基本原理或打破已存在的通用组件"Dialog"和"确认Dialog"数据.

A 类 SceneDocument 是唯一可编辑的模型。 布局 DTO 仅用于遗留的板-预览投影;它们不是第二个场景模型,编辑器,解析器或持久性权威.

构成部分类别——如何运作

Component (单位:千美元) Component.ts)是每个原型表面组件(例如89 PrimeReact slapers under Source/PrimeReact/) (中文(简体) ). 它延伸 ExternalComponent 所以情况是适当的 UIElement 子类型,通过指令管道流动,而无需任何手动的线条格式转换.

为什么要扩展外部组件?

带元素使用的图标 UIElement[] 作为C# 和TypeScript两侧的类型。 在这设计之前, Component 是一个单独的类别 执行 IComponent 并且必须在转让前转换为有线格式的平原对象(toWireElement) (中文(简体) ). 这种转换是一种隐蔽了序列化故障的呼叫站点气味,要求每个消费者了解.

现在 Component extends ExternalComponent implements IComponent。一个 InputText 实例 UIElement ——直接通过:

command.elements = updatedElements as unknown as typeof command.elements;

这个 as unknown as 由于 TypeScript 看到 UIElement[] (与 id: Guid) 而编辑 PrototypeSurfaceElement 类型有 id: string。运行时值是正确的;只有已声明的类型在此边界上存在差异.

序列化如何运作

基本要素 JsonSerializer 走开 Object.getOwnPropertyNames(instance) 并按顺序列出每个财产。 设计 Component 确保只将 JSON 安全值显示为自己的属性 :

什麽拥有财产?为什么
id是 — 字符串访问器通过 Object.definePropertyC# (韩语) System.Text.Json 将 UUID 字符串解析为 Guid 自动
ZIndex, (中文(简体) ), anchoring, (中文(简体) ), width, (中文(简体) ), height, (中文(简体) ), name, (中文(简体) ), properties, (中文(简体) ), slots, (中文(简体) ), componentName是——设置在 initialize()均为纯值; 安全序列化
_derivedTypeId是——明确载于 initialize()告诉基本原理 淡化为 ExternalComponent 在服务器上
toolbarIcon没有 - 原型车React-icons 组件是具有 prototype.constructor 自引用; 序列化它们会导致无限的重复. 做一个原型手 让他们远离 Object.getOwnPropertyNames 完全没有
RenderPrototype否-抽象原型方法相同的理由;原型上的方法从来不是实例的自有财产
label, (中文(简体) ), position, (中文(简体) ), size, (中文(简体) ), children, (中文(简体) ), type没有——原型取取取器已计算桥; 不序列数据

Id桥

SceneObject 声明 id: Guid (通过) @field(Guid)) (中文(简体) ). IComponent 声明 id: string。构造器以平弦存取器取代类场拥有的财产:

let _id = '';
Object.defineProperty(this, 'id', {
    get() { return _id; },
    set(value: string) { _id = String(value ?? ''); },
    enumerable: true,
    configurable: true,
});

序列器读取字符串 UUID; C# 将其描述为 Guid。比较ID使用的编辑器代码 string 平等贯穿一切.

这个 _derivedTypeId 拥有财产

DerivedType.get(constructor) 用途 Reflect.getOwnMetadata,这确实 没有 穿越原型链。 这个 @derivedType('externalComponent') 装饰器打开了 ExternalComponent这样 DerivedType.get(InputText) 返回时 undefined如果没有明确的自身财产,JSON产出将不存在 _derivedTypeId c#破坏者不知道建造一个 ExternalComponent。 。 。 .

initialize() 直接设定:

(this as unknown as Record<string, unknown>)['_derivedTypeId'] = 'externalComponent';

类型密钥

之后 initialize(), (中文(简体) ), componentName 更新到完整的符合图书馆条件的密钥('PrimeReact.InputText') (中文(简体) ). 在此之前 initialize() 子类类字段有短名( q)'InputText') (中文(简体) ). 这个 type getter 总是通过分割返回完全合格的密钥 . 并重新与 library数字 :

get type(): string {
    const cn = this.componentName ?? '';
    const shortName = cn.split('.').pop() ?? cn;
    return this.library ? `${this.library}.${shortName}` : shortName;
}

子类作者

执行这些成员:

export default class InputText extends Component {
    readonly componentName = 'InputText'; // short name; initialize() stores the full key
    readonly category = 'Form';
    readonly library = 'PrimeReact';
    readonly initialSize = { width: 220, height: 42 };
    readonly resizeBehavior = 'horizontal' as const;

    // MUST be a getter — not a class field.
    // Class fields are own instance properties and cause infinite recursion in Fundamentals' serializer.
    override get toolbarIcon() { return FaKeyboard; }

    RenderPrototype({ label }: PrototypeComponentRenderProps): ReactNode { ... }
}

toolbarIcon 必须 是一个 override get. 类领域(readonly toolbarIcon = FaKeyboard制造( ) FaKeyboard 财产。 基斯的序列器然后调用 Object.getOwnPropertyNames(FaKeyboard) 包含 prototype,其 constructor 点回 FaKeyboard,导致无限制的复发和 a RangeError。 。 。 .

版本与发布记录

@cratis/scene 共发布 553 个版本,首次发布于 2026/10/01;过去 12 个月发布了 553 个版本。

版本发布日期距今
0.342.1latest2026/11/11今天
0.342.02026/11/11今天
0.341.12026/11/11今天
0.341.02026/11/11今天
0.340.02026/11/11今天
0.339.32026/11/10今天

关于 @cratis/scene 的常见问题

@cratis/scene 是什么?

Cratis Scene:使工作室原型成为缩略图和预览.

如何安装 @cratis/scene?

在项目目录运行 npm install @cratis/scene,或使用 pnpm add / yarn add / bun add。它还需要宿主项目提供 peer 依赖:react(^19.3.0)、@cratis/fundamentals(^7.22.0)。npm 7 及以上与 pnpm 8 及以上默认会自动安装必需的 peer 依赖,Yarn 需要手动安装。

@cratis/scene 支持 TypeScript 吗?

支持。包内自带 TypeScript 类型声明(package.json 声明了 types 入口),安装后即可获得类型提示,无需再安装 @types 包。

@cratis/scene 支持 ESM 还是 CommonJS?

以 ES Module 形式发布,推荐使用 import 引入。在 CommonJS 项目中,Node.js 20.19+ / 22.12+ 可以直接 require() 不含顶层 await 的 ES Module,更早的版本需要改用动态 import()。

@cratis/scene 可以商用吗?

@cratis/scene 使用 MIT 许可。宽松许可:允许商业使用、修改和再分发,通常只需在分发时保留原版权与许可声明。以上为概括,不构成法律意见,请以许可原文为准。

@cratis/scene 的下载量有多少?

根据 npm 官方下载统计,@cratis/scene 在 2026/10/11 – 2026/11/09 这 30 天内被下载 75,400 次,日均约 2,513 次。下载量会把 CI 构建、镜像同步和作为其他包依赖的安装一并计入,适合横向比较热度,不能直接等同于使用人数。

@cratis/scene 还在维护吗?

最新版本 0.342.1 发布于 2026/11/11(今天);至今共发布 553 个版本,其中过去 12 个月发布了 553 个;首次发布于 2026/10/01。发布频率只是参考信号:功能稳定的工具可能很少需要更新,建议结合源码仓库的 issue 和提交记录判断。