@xiongtao.xt/tau-plugins 0.7.0 → 0.8.0
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/WHITEBOARD.md +115 -0
- package/package.json +8 -3
- package/tailwind.css +101 -0
- package/types/packages/plugins/src/contract.d.ts +2 -0
- package/types/packages/plugins/src/whiteboard.d.ts +7 -0
- package/types/packages/shared/entity-ref.d.ts +19 -0
- package/types/packages/whiteboard/src/author.d.ts +14 -0
- package/types/packages/whiteboard/src/authorSketch.d.ts +6 -0
- package/types/packages/whiteboard/src/chrome/index.d.ts +189 -0
- package/types/packages/whiteboard/src/components/SketchPaths/index.d.ts +9 -0
- package/types/packages/whiteboard/src/components/SketchPopover.d.ts +43 -0
- package/types/packages/whiteboard/src/extensions/api.d.ts +352 -0
- package/types/packages/whiteboard/src/extensions/authorHooks.d.ts +4 -0
- package/types/packages/whiteboard/src/extensions/context.d.ts +4 -0
- package/types/packages/whiteboard/src/extensions/events.d.ts +50 -0
- package/types/packages/whiteboard/src/extensions/standard-schema.d.ts +32 -0
- package/types/packages/whiteboard/src/types/containment.d.ts +3 -0
- package/types/packages/whiteboard/src/types/element.d.ts +33 -0
- package/types/packages/whiteboard/src/types/operation.d.ts +51 -0
- package/types/packages/whiteboard/src/types/path.d.ts +1 -0
- package/types/packages/whiteboard/src/types/point.d.ts +4 -0
- package/types/packages/whiteboard/src/types/presentation.d.ts +11 -0
- package/types/packages/whiteboard/src/types/schematic.d.ts +44 -0
- package/types/packages/whiteboard/src/types/selection.d.ts +11 -0
- package/types/packages/whiteboard/src/types/sketch.d.ts +25 -0
- package/types/packages/whiteboard/src/types/viewport.d.ts +8 -0
- package/types/packages/whiteboard/src/utils/sketch/geometry.d.ts +22 -0
- package/types/packages/whiteboard/src/utils/sketch/handText.d.ts +3 -0
- package/types/packages/whiteboard/src/utils/sketch/ink.d.ts +13 -0
- package/types/packages/whiteboard/src/utils/sketch/levels.d.ts +5 -0
- package/types/packages/whiteboard/src/utils/sketch/random.d.ts +4 -0
- package/types/packages/whiteboard/src/utils/sketch/shape.d.ts +38 -0
- package/types/packages/whiteboard/src/utils/sketch/types.d.ts +24 -0
|
@@ -0,0 +1,352 @@
|
|
|
1
|
+
import type { ComponentType, ReactNode } from "react";
|
|
2
|
+
import type { ServiceIdentifier } from "../../../shared/service-contract";
|
|
3
|
+
import type { BoardElement, ElementBounds } from "../types/element";
|
|
4
|
+
import type { ContainerKind } from "../types/containment";
|
|
5
|
+
import type { Operation } from "../types/operation";
|
|
6
|
+
import type { Selection } from "../types/selection";
|
|
7
|
+
import type { ViewPort } from "../types/viewport";
|
|
8
|
+
import type { PresentationSequence } from "../types/presentation";
|
|
9
|
+
import type { PageSketch } from "../types/sketch";
|
|
10
|
+
import type { ResolvedSketch } from "../types/sketch";
|
|
11
|
+
import type { SchematicShape } from "../types/schematic";
|
|
12
|
+
import type { StandardSchemaV1 } from "./standard-schema";
|
|
13
|
+
import type { ExtensionEventName, WhiteboardKernelEvents } from "./events";
|
|
14
|
+
export interface WhiteboardSnapshot {
|
|
15
|
+
children: BoardElement[];
|
|
16
|
+
viewPort: ViewPort;
|
|
17
|
+
selection: Selection;
|
|
18
|
+
presentationSequences?: PresentationSequence[];
|
|
19
|
+
sketch?: PageSketch;
|
|
20
|
+
/** 保存时写入的文档版本(旧数据缺失由 getDocumentVersion 归一为 1) */
|
|
21
|
+
version: number;
|
|
22
|
+
}
|
|
23
|
+
/** 返回的数据是副本,写入只能通过提交入口。 */
|
|
24
|
+
export interface WhiteboardAPI {
|
|
25
|
+
readonly children: BoardElement[];
|
|
26
|
+
readonly selection: Selection;
|
|
27
|
+
readonly viewPort: ViewPort;
|
|
28
|
+
readonly readonly: boolean;
|
|
29
|
+
/** 只读原因:文档版本高于当前应用时为 "document-too-new",普通只读为 null */
|
|
30
|
+
readonly readonlyReason: "document-too-new" | null;
|
|
31
|
+
readonly isDestroyed: boolean;
|
|
32
|
+
/** 当前激活工具 id("tau.select" 表示非创建模式) */
|
|
33
|
+
readonly activeTool: string;
|
|
34
|
+
/** 当前工具参数(如 geometry 的形状参数);无参数为 null */
|
|
35
|
+
readonly activeToolOptions: Readonly<Record<string, unknown>> | null;
|
|
36
|
+
/**
|
|
37
|
+
* 设置当前工具;id 必须是已注册工具 id 或 "tau.select",否则抛错。
|
|
38
|
+
* 只读画布下非 select 的设置被忽略并返回 false。
|
|
39
|
+
*/
|
|
40
|
+
setActiveTool(id: string, options?: Record<string, unknown>): boolean;
|
|
41
|
+
/** 订阅工具切换;返回取消函数,扩展作用域内随扩展卸载自动清理 */
|
|
42
|
+
onActiveToolChange(listener: (id: string, options: Readonly<Record<string, unknown>> | null) => void): () => void;
|
|
43
|
+
/** 屏幕(client)坐标 → 画布坐标;容器未挂载时抛错 */
|
|
44
|
+
screenToCanvas(point: {
|
|
45
|
+
x: number;
|
|
46
|
+
y: number;
|
|
47
|
+
}): {
|
|
48
|
+
x: number;
|
|
49
|
+
y: number;
|
|
50
|
+
};
|
|
51
|
+
/** 画布坐标 → 屏幕(client)坐标;容器未挂载时抛错 */
|
|
52
|
+
canvasToScreen(point: {
|
|
53
|
+
x: number;
|
|
54
|
+
y: number;
|
|
55
|
+
}): {
|
|
56
|
+
x: number;
|
|
57
|
+
y: number;
|
|
58
|
+
};
|
|
59
|
+
getSnapshot(): WhiteboardSnapshot;
|
|
60
|
+
getElement(id: string): BoardElement | undefined;
|
|
61
|
+
getSketch(element: BoardElement, owner?: BoardElement): ResolvedSketch;
|
|
62
|
+
/** 查询元素能否被指定类型的容器收纳(委托能力系统的 containment 声明,供创建手势等尚无容器实例的场合) */
|
|
63
|
+
canContain(containerType: string, element: BoardElement): boolean;
|
|
64
|
+
/** 数据不合规时抛 WhiteboardValidationError 且不应用任何变更 */
|
|
65
|
+
submit(operations: readonly Operation[], options?: {
|
|
66
|
+
historyGroup?: string;
|
|
67
|
+
}): void;
|
|
68
|
+
/** 数据不合规时抛 WhiteboardValidationError 且不应用任何变更 */
|
|
69
|
+
apply(operations: Operation | Operation[], updateHistory?: boolean): void;
|
|
70
|
+
/** 数据不合规时抛 WhiteboardValidationError 且不应用任何变更 */
|
|
71
|
+
updateElement(id: string, patch: Record<string, unknown>): boolean;
|
|
72
|
+
select(ids: readonly string[]): void;
|
|
73
|
+
captureSubmission(target?: string | BoardElement): () => boolean;
|
|
74
|
+
subscribe(listener: () => void): () => void;
|
|
75
|
+
execute(command: string, payload?: unknown): Promise<unknown>;
|
|
76
|
+
/** 命令第一个绑定快捷键的展示文字(按仲裁顺序,tau 扩展优先);无绑定返回 null */
|
|
77
|
+
getShortcut(commandId: string): string | null;
|
|
78
|
+
/** 让指定元素闪烁提示(内核事件 element:flash 的公开触发入口) */
|
|
79
|
+
flashElement(id: string): void;
|
|
80
|
+
/**
|
|
81
|
+
* 获取必选宿主服务:只能取扩展 requires 声明过的 id;
|
|
82
|
+
* 取未声明的 id 或对 optional 声明的 id 调用均抛错(编程错误)。
|
|
83
|
+
* 仅扩展作用域的 api 提供,主 api 调用即抛错。
|
|
84
|
+
*/
|
|
85
|
+
getService<T>(id: ServiceIdentifier<T>): T;
|
|
86
|
+
/**
|
|
87
|
+
* 获取可选宿主服务:只能取扩展 requires/optional 声明过的 id,
|
|
88
|
+
* 未注册返回 undefined;取未声明的 id 抛错(编程错误)。
|
|
89
|
+
*/
|
|
90
|
+
tryGetService<T>(id: ServiceIdentifier<T>): T | undefined;
|
|
91
|
+
/** 订阅内核事件(按 WhiteboardKernelEvents 推断参数)或扩展事件(<命名空间>.<名称>) */
|
|
92
|
+
on<K extends keyof WhiteboardKernelEvents>(event: K, listener: (...args: WhiteboardKernelEvents[K]) => void): void;
|
|
93
|
+
/** 扩展事件载荷由发送方自定义,不做静态约束(any[] 使具体类型监听器可直接传入) */
|
|
94
|
+
on(event: ExtensionEventName, listener: (...args: any[]) => void): void;
|
|
95
|
+
/** 非法事件名(internal: 前缀、未知裸名)在运行时抛错 */
|
|
96
|
+
off(event: string, listener: (...args: any[]) => void): void;
|
|
97
|
+
/** 只能发出扩展事件(<命名空间>.<名称>);内核事件与 internal: 前缀事件在运行时抛错 */
|
|
98
|
+
emit(event: ExtensionEventName, ...args: unknown[]): void;
|
|
99
|
+
}
|
|
100
|
+
export interface WhiteboardCommand {
|
|
101
|
+
id: string;
|
|
102
|
+
enabled?(api: WhiteboardAPI): boolean;
|
|
103
|
+
execute(api: WhiteboardAPI, payload?: unknown): unknown;
|
|
104
|
+
}
|
|
105
|
+
/** 带类型的白板元素:第三方元素的私有数据收敛在 data 字段,由 schema 约束其形状 */
|
|
106
|
+
export type TypedBoardElement<TData> = BoardElement & {
|
|
107
|
+
data: TData;
|
|
108
|
+
};
|
|
109
|
+
/** TData 恰为 unknown(缺省)时退化为 BoardElement,保证不带泛型参数的旧定义完全兼容 */
|
|
110
|
+
type ElementParam<TData> = unknown extends TData ? BoardElement : TypedBoardElement<TData>;
|
|
111
|
+
/** 元素收纳声明(子元素一侧):能否被容器收纳,以及愿意进入的受限容器类别 */
|
|
112
|
+
export interface ElementContainmentSpec {
|
|
113
|
+
/** 能否被任何容器收纳,默认 true */
|
|
114
|
+
canBeContained?: boolean;
|
|
115
|
+
/** 愿意进入的受限容器类别;目前只有 "layout"(子元素位置由容器布局决定,例如分栏) */
|
|
116
|
+
joins?: readonly ContainerKind[];
|
|
117
|
+
}
|
|
118
|
+
export interface WhiteboardElementDefinition<TData = unknown> {
|
|
119
|
+
type: string;
|
|
120
|
+
presentation?: {
|
|
121
|
+
label: string;
|
|
122
|
+
icon?: ComponentType<{
|
|
123
|
+
className?: string;
|
|
124
|
+
size?: number;
|
|
125
|
+
strokeWidth?: number;
|
|
126
|
+
}>;
|
|
127
|
+
getName?(element: ElementParam<TData>): string;
|
|
128
|
+
};
|
|
129
|
+
interaction?: {
|
|
130
|
+
resize?: {
|
|
131
|
+
handles?: "corners" | "all";
|
|
132
|
+
preserveAspectRatio?: boolean;
|
|
133
|
+
};
|
|
134
|
+
connect?: "rect";
|
|
135
|
+
};
|
|
136
|
+
sketch?: true;
|
|
137
|
+
schematic?(element: ElementParam<TData>, context: {
|
|
138
|
+
dark: boolean;
|
|
139
|
+
}): readonly SchematicShape[];
|
|
140
|
+
render: ComponentType<{
|
|
141
|
+
element: ElementParam<TData>;
|
|
142
|
+
children?: ReactNode;
|
|
143
|
+
}>;
|
|
144
|
+
getBounds?(element: ElementParam<TData>): ElementBounds | null;
|
|
145
|
+
isHit?(element: ElementParam<TData>, x: number, y: number): boolean;
|
|
146
|
+
move?(element: ElementParam<TData>, dx: number, dy: number): BoardElement;
|
|
147
|
+
/** 元素数据结构版本(正整数,缺省 1);数据低于该版本时按 migrate 逐步升级 */
|
|
148
|
+
schemaVersion?: number;
|
|
149
|
+
/** 键 n 表示“从 n 升到 n+1”的单步迁移;装配时要求覆盖 [1, schemaVersion) 的全部步骤 */
|
|
150
|
+
migrate?: Record<number, (element: ElementParam<TData>) => BoardElement>;
|
|
151
|
+
/** 约束 element.data 的 Standard Schema v1;提交与迁移产物校验均要求同步返回结果 */
|
|
152
|
+
schema?: StandardSchemaV1<unknown, TData>;
|
|
153
|
+
/** 收纳声明:未声明时可被容器收纳(能进 frame,不能进 layout 类受限容器) */
|
|
154
|
+
containment?: ElementContainmentSpec;
|
|
155
|
+
/** 创建规格:声明后可注册创建型工具(element 工具),在画布上手势创建该元素 */
|
|
156
|
+
create?: ElementCreateSpec<TData>;
|
|
157
|
+
}
|
|
158
|
+
/** 创建手势中的画布坐标点 */
|
|
159
|
+
export interface CreatePoint {
|
|
160
|
+
x: number;
|
|
161
|
+
y: number;
|
|
162
|
+
}
|
|
163
|
+
/** 创建手势的指针上下文(画布坐标 + 修饰键 + 当前缩放) */
|
|
164
|
+
export interface CreatePointerContext {
|
|
165
|
+
/** 当前指针(画布坐标) */
|
|
166
|
+
point: CreatePoint;
|
|
167
|
+
/** 按下点(画布坐标) */
|
|
168
|
+
start: CreatePoint;
|
|
169
|
+
shift: boolean;
|
|
170
|
+
alt: boolean;
|
|
171
|
+
zoom: number;
|
|
172
|
+
/** 当前指针压力(PointerEvent.pressure 原始值;无压感设备为 0/0.5,由手势自行归一) */
|
|
173
|
+
pressure: number;
|
|
174
|
+
api: WhiteboardAPI;
|
|
175
|
+
}
|
|
176
|
+
/** 预览附加项:需要高亮包围盒的已有元素 id(如框架收纳提示) */
|
|
177
|
+
export interface CreatePreviewOptions {
|
|
178
|
+
highlight?: readonly string[];
|
|
179
|
+
/** 是否绘制预览元素的包围盒描边(默认 true;手写笔迹等不宜描边的元素传 false) */
|
|
180
|
+
bounds?: boolean;
|
|
181
|
+
}
|
|
182
|
+
/** 手势产出:单个元素,或元素 + 与插入同属一个撤销步的附加操作 */
|
|
183
|
+
export type CreateResult = BoardElement | {
|
|
184
|
+
element: BoardElement;
|
|
185
|
+
operations?: readonly Operation[];
|
|
186
|
+
};
|
|
187
|
+
/** build 的产出:与 CreateResult 同构(元素或元素 + 附加操作),可异步 */
|
|
188
|
+
export type CreateBuildResult<TData = unknown> = ElementParam<TData> | {
|
|
189
|
+
element: ElementParam<TData>;
|
|
190
|
+
operations?: readonly Operation[];
|
|
191
|
+
};
|
|
192
|
+
/**
|
|
193
|
+
* 一次创建手势会话:begin 之后由内核驱动 move/end/cancel。
|
|
194
|
+
* end 与内置手势的 build 可返回 Promise:等待期间内核忽略新的创建手势
|
|
195
|
+
* (工具保持但按下被吞掉),完成后按废弃守门(captureSubmission + 工具一致)决定提交或丢弃。
|
|
196
|
+
*/
|
|
197
|
+
export interface CreateGestureSession {
|
|
198
|
+
move(ctx: CreatePointerContext): void;
|
|
199
|
+
end(ctx: CreatePointerContext & {
|
|
200
|
+
moved: boolean;
|
|
201
|
+
}): CreateResult | null | Promise<CreateResult | null>;
|
|
202
|
+
cancel?(): void;
|
|
203
|
+
}
|
|
204
|
+
/** 自定义创建手势:begin 返回 null 表示不接管本次按下 */
|
|
205
|
+
export interface CustomCreateGesture {
|
|
206
|
+
begin(ctx: CreatePointerContext & {
|
|
207
|
+
/** 设置预览元素(null 清除);预览不进入文档、快照与历史 */
|
|
208
|
+
preview(element: BoardElement | null, options?: CreatePreviewOptions): void;
|
|
209
|
+
}): CreateGestureSession | null;
|
|
210
|
+
}
|
|
211
|
+
/** 传给 build 的构造上下文:rect/start/end 均已应用约束 */
|
|
212
|
+
export interface CreateBuildContext {
|
|
213
|
+
/** 画布坐标包围盒,已应用 Shift/Alt 约束 */
|
|
214
|
+
rect: {
|
|
215
|
+
x: number;
|
|
216
|
+
y: number;
|
|
217
|
+
width: number;
|
|
218
|
+
height: number;
|
|
219
|
+
};
|
|
220
|
+
/** 已应用约束的起止点 */
|
|
221
|
+
start: CreatePoint;
|
|
222
|
+
end: CreatePoint;
|
|
223
|
+
/** 是否为单击(未拖动) */
|
|
224
|
+
click: boolean;
|
|
225
|
+
shift: boolean;
|
|
226
|
+
alt: boolean;
|
|
227
|
+
/** 激活工具时的参数(activeToolOptions) */
|
|
228
|
+
options: Readonly<Record<string, unknown>> | null;
|
|
229
|
+
api: WhiteboardAPI;
|
|
230
|
+
}
|
|
231
|
+
/** 元素创建规格 */
|
|
232
|
+
export interface ElementCreateSpec<TData = unknown> {
|
|
233
|
+
/** "click"/"drag" 为内置手势;传对象则完全自定义 */
|
|
234
|
+
gesture: "click" | "drag" | CustomCreateGesture;
|
|
235
|
+
/** 仅 drag 生效:box = Shift 等比、Alt 从中心;line = Shift 吸附 45°。默认 box */
|
|
236
|
+
constrain?: "box" | "line";
|
|
237
|
+
/** click 必填;drag 单击时按此尺寸以按下点为中心创建,缺省则单击不创建 */
|
|
238
|
+
defaultSize?: readonly [number, number];
|
|
239
|
+
/** drag 生成的 rect 宽或高小于此值则不创建(line 约束改为检查长度),默认 [4,4],画布单位 */
|
|
240
|
+
minSize?: readonly [number, number];
|
|
241
|
+
/** click/drag 必填:由构造上下文产出待插入元素(或元素 + 附加操作),返回 null 则不创建;可异步 */
|
|
242
|
+
build?(ctx: CreateBuildContext): CreateBuildResult<TData> | null | Promise<CreateBuildResult<TData> | null>;
|
|
243
|
+
/** 创建后动作:select = 选中(默认);edit = 选中并进入编辑;none = 不改选区 */
|
|
244
|
+
after?: "select" | "edit" | "none";
|
|
245
|
+
/** 创建后保持当前工具(默认 false,回到 tau.select) */
|
|
246
|
+
stay?: boolean;
|
|
247
|
+
/** 创建模式光标,默认 crosshair */
|
|
248
|
+
cursor?: "crosshair" | "text";
|
|
249
|
+
/**
|
|
250
|
+
* 提示胶囊文案(激活创建工具时画布底部显示);第一段为主提示。
|
|
251
|
+
* 缺省时按手势兜底:click = 「点击放置 + label」,其它 = 「拖拽绘制 + label」。
|
|
252
|
+
*/
|
|
253
|
+
hint?: readonly string[] | ((options: Readonly<Record<string, unknown>> | null) => readonly string[]);
|
|
254
|
+
}
|
|
255
|
+
/** 元素定义的声明辅助(恒等函数):传入 schema 时 TData 由其输出类型推断 */
|
|
256
|
+
export declare function defineElement<TData = unknown>(definition: WhiteboardElementDefinition<TData>): WhiteboardElementDefinition<TData>;
|
|
257
|
+
export interface WhiteboardToolProps {
|
|
258
|
+
run(payload?: unknown): void;
|
|
259
|
+
}
|
|
260
|
+
export interface WhiteboardToolContribution {
|
|
261
|
+
id: string;
|
|
262
|
+
/** 提示与无障碍名(菜单项/提示胶囊文案也用它);空串或空白会被拒绝装配 */
|
|
263
|
+
label: string;
|
|
264
|
+
/** 工具图标(lucide 图标组件即可) */
|
|
265
|
+
icon: ComponentType<{
|
|
266
|
+
className?: string;
|
|
267
|
+
}>;
|
|
268
|
+
/** 命令型工具:点击执行该命令(与 element 恰好二选一) */
|
|
269
|
+
command?: string;
|
|
270
|
+
/** 创建型工具:激活后在画布上手势创建该元素;须是本扩展声明且带 create 的元素 type */
|
|
271
|
+
element?: string;
|
|
272
|
+
order: number;
|
|
273
|
+
group: string;
|
|
274
|
+
/**
|
|
275
|
+
* 工具按钮组件;仅 tau 命名空间工具在工具栏上渲染,
|
|
276
|
+
* 第三方工具统一进入「扩展工具」菜单(菜单项由 label + icon 生成,component 被忽略)
|
|
277
|
+
*/
|
|
278
|
+
component?: ComponentType<WhiteboardToolProps>;
|
|
279
|
+
/** 扩展工具的参数面板;宿主管理返回与关闭,run(payload) 执行后关闭面板。 */
|
|
280
|
+
panel?: ComponentType<WhiteboardToolProps>;
|
|
281
|
+
}
|
|
282
|
+
export interface WhiteboardLayerContribution {
|
|
283
|
+
id: string;
|
|
284
|
+
position: "canvas" | "outside";
|
|
285
|
+
component: ComponentType;
|
|
286
|
+
}
|
|
287
|
+
export interface WhiteboardMenuContribution {
|
|
288
|
+
id: string;
|
|
289
|
+
label: string;
|
|
290
|
+
command: string;
|
|
291
|
+
order: number;
|
|
292
|
+
when?(api: WhiteboardAPI): boolean;
|
|
293
|
+
}
|
|
294
|
+
export interface WhiteboardContributions {
|
|
295
|
+
ingest?: readonly {
|
|
296
|
+
id: string;
|
|
297
|
+
source: "paste" | "drop";
|
|
298
|
+
accepts(event: ClipboardEvent | DragEvent): boolean;
|
|
299
|
+
run(api: WhiteboardAPI, event: ClipboardEvent | DragEvent): void | Promise<void>;
|
|
300
|
+
}[];
|
|
301
|
+
commands?: readonly WhiteboardCommand[];
|
|
302
|
+
tools?: readonly WhiteboardToolContribution[];
|
|
303
|
+
layers?: readonly WhiteboardLayerContribution[];
|
|
304
|
+
inspectors?: Readonly<Record<string, ComponentType<any>>>;
|
|
305
|
+
menus?: readonly WhiteboardMenuContribution[];
|
|
306
|
+
/** 快捷键(is-hotkey 键串,按 event.key 匹配):tau 扩展优先于第三方同键声明,第一条 enabled 的命令执行;宿主保留键(mod+k/p/j、alt+方向、escape)不可声明 */
|
|
307
|
+
hotkeys?: readonly {
|
|
308
|
+
key: string;
|
|
309
|
+
command: string;
|
|
310
|
+
}[];
|
|
311
|
+
/** 每次激活启动,返回的清理函数在隐藏或卸载时执行。 */
|
|
312
|
+
activate?(): void | (() => void);
|
|
313
|
+
dispose?(): void;
|
|
314
|
+
}
|
|
315
|
+
export interface WhiteboardExtension {
|
|
316
|
+
/** 静态元素定义供画布和无画布的数据消费者共用。 */
|
|
317
|
+
readonly elements?: readonly WhiteboardElementDefinition<any>[];
|
|
318
|
+
readonly id: string;
|
|
319
|
+
/** 展示名(UI 显示"来自 xxx"用);内置扩展可不填 */
|
|
320
|
+
readonly name?: string;
|
|
321
|
+
readonly apiVersion: 1;
|
|
322
|
+
/**
|
|
323
|
+
* 必选宿主服务:任一服务在宿主注册表中不存在时扩展被拒(reason "missing-service")。
|
|
324
|
+
* 声明过的 id 才能经 api.getService / api.tryGetService 获取。
|
|
325
|
+
*/
|
|
326
|
+
readonly requires?: readonly ServiceIdentifier<unknown>[];
|
|
327
|
+
/**
|
|
328
|
+
* 可选宿主服务:缺失不影响装配,经 api.tryGetService 获取(返回 undefined 表示未提供)。
|
|
329
|
+
* 对 optional 中的 id 调用 getService 会抛错。
|
|
330
|
+
*/
|
|
331
|
+
readonly optional?: readonly ServiceIdentifier<unknown>[];
|
|
332
|
+
create(api: WhiteboardAPI): WhiteboardContributions;
|
|
333
|
+
}
|
|
334
|
+
/** 扩展被禁用的原因:除编程错误外一律降级禁用单个扩展,不中断画布装配。 */
|
|
335
|
+
export type WhiteboardExtensionErrorReason = "duplicate-extension" | "unsupported-api-version" | "invalid-namespace" | "conflict" | "missing-command" | "missing-service" | "invalid-definition" | "create-failed" | "migration-failed";
|
|
336
|
+
export interface WhiteboardExtensionError {
|
|
337
|
+
extensionId: string;
|
|
338
|
+
reason: WhiteboardExtensionErrorReason;
|
|
339
|
+
message: string;
|
|
340
|
+
/** 冲突对方扩展 id */
|
|
341
|
+
conflictWith?: string;
|
|
342
|
+
/** 冲突的元素 type / 命令 / 贡献 id,或缺失的宿主服务 id */
|
|
343
|
+
target?: string;
|
|
344
|
+
}
|
|
345
|
+
export declare function defineWhiteboardExtension(definition: Omit<WhiteboardExtension, "apiVersion">): WhiteboardExtension;
|
|
346
|
+
export interface WhiteboardOutline {
|
|
347
|
+
open: boolean;
|
|
348
|
+
width: number;
|
|
349
|
+
onWidthChange(width: number): void;
|
|
350
|
+
onDockWidthChange?(width: number): void;
|
|
351
|
+
}
|
|
352
|
+
export {};
|
|
@@ -0,0 +1,4 @@
|
|
|
1
|
+
import type { BoardElement } from "../types/element";
|
|
2
|
+
export declare function usePageSketch(): import("../author").PageSketch;
|
|
3
|
+
/** 订阅所属画布的画风,元素和 owner 的覆盖仍由内核统一解析。 */
|
|
4
|
+
export declare function useSketch(element: BoardElement, owner?: BoardElement): import("../author").ResolvedSketch;
|
|
@@ -0,0 +1,4 @@
|
|
|
1
|
+
import type { WhiteboardAPI } from "./api";
|
|
2
|
+
export declare const WhiteboardAPIContext: import("react").Context<WhiteboardAPI | null>;
|
|
3
|
+
export declare const WhiteboardAPIProvider: import("react").Provider<WhiteboardAPI | null>;
|
|
4
|
+
export declare function useWhiteboardAPI(): WhiteboardAPI;
|
|
@@ -0,0 +1,50 @@
|
|
|
1
|
+
import type { BoardElement } from "../types/element";
|
|
2
|
+
import type { PageSketch } from "../types/sketch";
|
|
3
|
+
import type { Selection } from "../types/selection";
|
|
4
|
+
import type { ViewPort } from "../types/viewport";
|
|
5
|
+
/**
|
|
6
|
+
* 白板内核事件表:事件名 → 监听器参数元组。
|
|
7
|
+
* 内核事件只有内核代码能发(board.emit),扩展只能经 api.on 监听;
|
|
8
|
+
* 经扩展 API 监听时载荷为冻结快照(见 runtime 的快照替换表)。
|
|
9
|
+
*/
|
|
10
|
+
export interface WhiteboardKernelEvents {
|
|
11
|
+
/** 任意文档变更提交后发出(无参数) */
|
|
12
|
+
change: [];
|
|
13
|
+
/** children 变化 */
|
|
14
|
+
"value:change": [children: BoardElement[]];
|
|
15
|
+
/** 选区变化 */
|
|
16
|
+
"selection:change": [selection: Selection];
|
|
17
|
+
/** 视口变化 */
|
|
18
|
+
"viewport:change": [viewPort: ViewPort];
|
|
19
|
+
/** 页级画风变化 */
|
|
20
|
+
"sketch:change": [sketch: PageSketch];
|
|
21
|
+
/** 只读状态变化 */
|
|
22
|
+
"readonly:change": [readonly: boolean];
|
|
23
|
+
/** 已有元素数据变化 */
|
|
24
|
+
"element:change": [elements: BoardElement[]];
|
|
25
|
+
/** 元素插入 */
|
|
26
|
+
"element:insert": [elements: BoardElement[]];
|
|
27
|
+
/** 元素移除 */
|
|
28
|
+
"element:remove": [elements: BoardElement[]];
|
|
29
|
+
/** 元素拖动中(每帧) */
|
|
30
|
+
"element:move": [elements: BoardElement[]];
|
|
31
|
+
/** 元素拖动结束 */
|
|
32
|
+
"element:move-end": [];
|
|
33
|
+
/** 让指定元素闪烁提示(如定位到引用) */
|
|
34
|
+
"element:flash": [id: string];
|
|
35
|
+
/** 激活工具切换 */
|
|
36
|
+
"active-tool:change": [id: string, options: Readonly<Record<string, unknown>> | null];
|
|
37
|
+
}
|
|
38
|
+
export type KernelEventName = keyof WhiteboardKernelEvents;
|
|
39
|
+
/** 内核事件名集合(运行时校验用),与 WhiteboardKernelEvents 的键一一对应 */
|
|
40
|
+
export declare const KERNEL_EVENT_NAMES: readonly KernelEventName[];
|
|
41
|
+
/** 扩展事件名:`<命名空间>.<名称>`,命名空间取扩展 id 第一段 */
|
|
42
|
+
export type ExtensionEventName = `${string}.${string}`;
|
|
43
|
+
export declare function isKernelEventName(event: string): event is KernelEventName;
|
|
44
|
+
/** api.on 允许的事件:内核事件 + 任意命名空间的扩展事件(扩展间通信) */
|
|
45
|
+
export declare function assertSubscribableEventName(event: string): void;
|
|
46
|
+
/**
|
|
47
|
+
* api.emit 允许的事件:扩展事件且不能是内核事件或 internal: 前缀;
|
|
48
|
+
* 传入 namespace(扩展 id 第一段)时还要求事件归属该命名空间。
|
|
49
|
+
*/
|
|
50
|
+
export declare function assertEmittableEventName(event: string, namespace?: string): void;
|
|
@@ -0,0 +1,32 @@
|
|
|
1
|
+
export interface StandardSchemaV1<Input = unknown, Output = Input> {
|
|
2
|
+
readonly "~standard": StandardSchemaV1.Props<Input, Output>;
|
|
3
|
+
}
|
|
4
|
+
export declare namespace StandardSchemaV1 {
|
|
5
|
+
interface Props<Input = unknown, Output = Input> {
|
|
6
|
+
readonly version: 1;
|
|
7
|
+
readonly vendor: string;
|
|
8
|
+
readonly validate: (value: unknown) => Result<Output> | Promise<Result<Output>>;
|
|
9
|
+
readonly types?: Types<Input, Output> | undefined;
|
|
10
|
+
}
|
|
11
|
+
interface Types<Input = unknown, Output = Input> {
|
|
12
|
+
readonly input: Input;
|
|
13
|
+
readonly output: Output;
|
|
14
|
+
}
|
|
15
|
+
type Result<Output> = SuccessResult<Output> | FailureResult;
|
|
16
|
+
interface SuccessResult<Output> {
|
|
17
|
+
readonly value: Output;
|
|
18
|
+
readonly issues?: undefined;
|
|
19
|
+
}
|
|
20
|
+
interface FailureResult {
|
|
21
|
+
readonly issues: ReadonlyArray<Issue>;
|
|
22
|
+
}
|
|
23
|
+
interface Issue {
|
|
24
|
+
readonly message: string;
|
|
25
|
+
readonly path?: ReadonlyArray<PropertyKey | PathSegment> | undefined;
|
|
26
|
+
}
|
|
27
|
+
interface PathSegment {
|
|
28
|
+
readonly key: PropertyKey;
|
|
29
|
+
}
|
|
30
|
+
type InferInput<Schema extends StandardSchemaV1> = NonNullable<Schema["~standard"]["types"]>["input"];
|
|
31
|
+
type InferOutput<Schema extends StandardSchemaV1> = NonNullable<Schema["~standard"]["types"]>["output"];
|
|
32
|
+
}
|
|
@@ -0,0 +1,33 @@
|
|
|
1
|
+
import type { EntityRef } from "../../../shared/entity-ref";
|
|
2
|
+
import type { ElementSketch } from "./sketch";
|
|
3
|
+
import type { Point } from "./point";
|
|
4
|
+
/** 白板持久化元素;不依赖 Board 或内部插件实例。 */
|
|
5
|
+
export interface BoardElement {
|
|
6
|
+
id: string;
|
|
7
|
+
type: string;
|
|
8
|
+
name?: string;
|
|
9
|
+
groupId?: string;
|
|
10
|
+
children?: BoardElement[];
|
|
11
|
+
resizable?: boolean;
|
|
12
|
+
autoHeight?: boolean;
|
|
13
|
+
entityRef?: EntityRef;
|
|
14
|
+
sketch?: ElementSketch;
|
|
15
|
+
schemaVersion?: number;
|
|
16
|
+
[key: string]: any;
|
|
17
|
+
}
|
|
18
|
+
export interface ElementBounds {
|
|
19
|
+
minX: number;
|
|
20
|
+
minY: number;
|
|
21
|
+
maxX: number;
|
|
22
|
+
maxY: number;
|
|
23
|
+
}
|
|
24
|
+
export interface BoardContextMenuPayload {
|
|
25
|
+
clientX: number;
|
|
26
|
+
clientY: number;
|
|
27
|
+
viewPortPoint: Point;
|
|
28
|
+
selectedElements: BoardElement[];
|
|
29
|
+
hitElements: BoardElement[];
|
|
30
|
+
targetElements: BoardElement[];
|
|
31
|
+
hitElement?: BoardElement;
|
|
32
|
+
isHitSelected: boolean;
|
|
33
|
+
}
|
|
@@ -0,0 +1,51 @@
|
|
|
1
|
+
import { Selection } from "./selection";
|
|
2
|
+
import type { BoardElement } from "./element";
|
|
3
|
+
import { ViewPort } from "./viewport";
|
|
4
|
+
import { Path } from "./path";
|
|
5
|
+
import { PageSketch } from "./sketch";
|
|
6
|
+
export type SetNodePatch = Partial<Omit<BoardElement, "children">> & {
|
|
7
|
+
children?: never;
|
|
8
|
+
};
|
|
9
|
+
export type InsertNodeOperation = {
|
|
10
|
+
type: "insert_node";
|
|
11
|
+
path: Path;
|
|
12
|
+
node: BoardElement;
|
|
13
|
+
};
|
|
14
|
+
export type RemoveNodeOperation = {
|
|
15
|
+
type: "remove_node";
|
|
16
|
+
path: Path;
|
|
17
|
+
node: BoardElement;
|
|
18
|
+
};
|
|
19
|
+
export type MoveNodeOperation = {
|
|
20
|
+
type: "move_node";
|
|
21
|
+
path: Path;
|
|
22
|
+
newPath: Path;
|
|
23
|
+
};
|
|
24
|
+
export type SetNodeOperation = {
|
|
25
|
+
type: "set_node";
|
|
26
|
+
path: Path;
|
|
27
|
+
properties: SetNodePatch;
|
|
28
|
+
newProperties: SetNodePatch;
|
|
29
|
+
};
|
|
30
|
+
export type SetSelectionOperation = {
|
|
31
|
+
type: "set_selection";
|
|
32
|
+
properties: Partial<Selection>;
|
|
33
|
+
newProperties: Partial<Selection>;
|
|
34
|
+
};
|
|
35
|
+
export type SetViewportOperation = {
|
|
36
|
+
type: "set_viewport";
|
|
37
|
+
properties: Partial<ViewPort>;
|
|
38
|
+
newProperties: Partial<ViewPort>;
|
|
39
|
+
};
|
|
40
|
+
/** 页级画风(D-107),进撤销历史 */
|
|
41
|
+
export type SetSketchOperation = {
|
|
42
|
+
type: "set_sketch";
|
|
43
|
+
properties: Partial<PageSketch>;
|
|
44
|
+
newProperties: Partial<PageSketch>;
|
|
45
|
+
};
|
|
46
|
+
export type SetMovingOperation = {
|
|
47
|
+
type: "set_moving";
|
|
48
|
+
properties: BoardElement[];
|
|
49
|
+
newProperties: BoardElement[];
|
|
50
|
+
};
|
|
51
|
+
export type Operation = InsertNodeOperation | RemoveNodeOperation | MoveNodeOperation | SetNodeOperation | SetViewportOperation | SetSelectionOperation | SetMovingOperation | SetSketchOperation;
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
export type Path = number[];
|
|
@@ -0,0 +1,44 @@
|
|
|
1
|
+
/** 纯色,或由 CSS linear-gradient 解析出的渐变(文本卡片常用渐变底) */
|
|
2
|
+
export type SchematicFill = string | {
|
|
3
|
+
angle: number;
|
|
4
|
+
stops: Array<{
|
|
5
|
+
color: string;
|
|
6
|
+
offset: number;
|
|
7
|
+
}>;
|
|
8
|
+
};
|
|
9
|
+
export type SchematicShape = {
|
|
10
|
+
kind: "rect";
|
|
11
|
+
x: number;
|
|
12
|
+
y: number;
|
|
13
|
+
w: number;
|
|
14
|
+
h: number;
|
|
15
|
+
r: number;
|
|
16
|
+
fill: SchematicFill;
|
|
17
|
+
fillOpacity?: number;
|
|
18
|
+
stroke?: string;
|
|
19
|
+
/** 输出像素 */
|
|
20
|
+
strokeWidth?: number;
|
|
21
|
+
} | {
|
|
22
|
+
kind: "path";
|
|
23
|
+
d: string;
|
|
24
|
+
fill?: string;
|
|
25
|
+
fillOpacity?: number;
|
|
26
|
+
stroke?: string;
|
|
27
|
+
strokeOpacity?: number;
|
|
28
|
+
/** 输出像素 */
|
|
29
|
+
strokeWidth?: number;
|
|
30
|
+
/** 归一化路径(0~1)放进元素框:translate(x y) scale(w h) */
|
|
31
|
+
box?: {
|
|
32
|
+
x: number;
|
|
33
|
+
y: number;
|
|
34
|
+
w: number;
|
|
35
|
+
h: number;
|
|
36
|
+
};
|
|
37
|
+
} | {
|
|
38
|
+
/** 箭头端点的三角:尺寸按输出像素,组件按缩放换算 */
|
|
39
|
+
kind: "arrowhead";
|
|
40
|
+
x: number;
|
|
41
|
+
y: number;
|
|
42
|
+
angle: number;
|
|
43
|
+
color: string;
|
|
44
|
+
};
|
|
@@ -0,0 +1,11 @@
|
|
|
1
|
+
import type { BoardElement } from "./element";
|
|
2
|
+
import { Point } from "./point";
|
|
3
|
+
export interface SelectArea {
|
|
4
|
+
anchor: Point;
|
|
5
|
+
focus: Point;
|
|
6
|
+
}
|
|
7
|
+
export interface Selection {
|
|
8
|
+
selectArea: SelectArea | null;
|
|
9
|
+
selectedElements: BoardElement[];
|
|
10
|
+
[key: string]: any;
|
|
11
|
+
}
|
|
@@ -0,0 +1,25 @@
|
|
|
1
|
+
/** 页面画风:手绘 / 普通(D-107) */
|
|
2
|
+
export type SketchMode = "sketch" | "normal";
|
|
3
|
+
/** 笔触档位:工整 / 自然 / 潦草 */
|
|
4
|
+
export type SketchLevel = "neat" | "natural" | "loose";
|
|
5
|
+
/** 形状填充样式;普通模式下一律按实色渲染 */
|
|
6
|
+
export type SketchFillStyle = "solid" | "hatch" | "cross" | "scribble";
|
|
7
|
+
/** 页级画风,存在 WhiteBoardContent.data.sketch,缺省为 DEFAULT_PAGE_SKETCH */
|
|
8
|
+
export interface PageSketch {
|
|
9
|
+
mode: SketchMode;
|
|
10
|
+
level: SketchLevel;
|
|
11
|
+
}
|
|
12
|
+
/** 元素级覆盖;未设置的字段跟随页面 */
|
|
13
|
+
export interface ElementSketch {
|
|
14
|
+
mode?: SketchMode;
|
|
15
|
+
level?: SketchLevel;
|
|
16
|
+
/** 「换一笔」写入;缺省时由元素 id 派生 */
|
|
17
|
+
seed?: number;
|
|
18
|
+
}
|
|
19
|
+
export declare const DEFAULT_PAGE_SKETCH: PageSketch;
|
|
20
|
+
/** 生效画风:页面默认值与元素覆盖合成后的结果 */
|
|
21
|
+
export interface ResolvedSketch {
|
|
22
|
+
enabled: boolean;
|
|
23
|
+
level: SketchLevel;
|
|
24
|
+
seed: number;
|
|
25
|
+
}
|