@xiongtao.xt/tau-plugins 0.6.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.
Files changed (39) hide show
  1. package/AI.md +75 -0
  2. package/EDITOR.md +41 -42
  3. package/README.md +4 -4
  4. package/SERVICES.md +5 -5
  5. package/WHITEBOARD.md +115 -0
  6. package/package.json +8 -3
  7. package/tailwind.css +101 -0
  8. package/types/packages/plugins/src/ai.d.ts +40 -0
  9. package/types/packages/plugins/src/contract.d.ts +7 -0
  10. package/types/packages/plugins/src/index.d.ts +1 -0
  11. package/types/packages/plugins/src/whiteboard.d.ts +7 -0
  12. package/types/packages/shared/entity-ref.d.ts +19 -0
  13. package/types/packages/whiteboard/src/author.d.ts +14 -0
  14. package/types/packages/whiteboard/src/authorSketch.d.ts +6 -0
  15. package/types/packages/whiteboard/src/chrome/index.d.ts +189 -0
  16. package/types/packages/whiteboard/src/components/SketchPaths/index.d.ts +9 -0
  17. package/types/packages/whiteboard/src/components/SketchPopover.d.ts +43 -0
  18. package/types/packages/whiteboard/src/extensions/api.d.ts +352 -0
  19. package/types/packages/whiteboard/src/extensions/authorHooks.d.ts +4 -0
  20. package/types/packages/whiteboard/src/extensions/context.d.ts +4 -0
  21. package/types/packages/whiteboard/src/extensions/events.d.ts +50 -0
  22. package/types/packages/whiteboard/src/extensions/standard-schema.d.ts +32 -0
  23. package/types/packages/whiteboard/src/types/containment.d.ts +3 -0
  24. package/types/packages/whiteboard/src/types/element.d.ts +33 -0
  25. package/types/packages/whiteboard/src/types/operation.d.ts +51 -0
  26. package/types/packages/whiteboard/src/types/path.d.ts +1 -0
  27. package/types/packages/whiteboard/src/types/point.d.ts +4 -0
  28. package/types/packages/whiteboard/src/types/presentation.d.ts +11 -0
  29. package/types/packages/whiteboard/src/types/schematic.d.ts +44 -0
  30. package/types/packages/whiteboard/src/types/selection.d.ts +11 -0
  31. package/types/packages/whiteboard/src/types/sketch.d.ts +25 -0
  32. package/types/packages/whiteboard/src/types/viewport.d.ts +8 -0
  33. package/types/packages/whiteboard/src/utils/sketch/geometry.d.ts +22 -0
  34. package/types/packages/whiteboard/src/utils/sketch/handText.d.ts +3 -0
  35. package/types/packages/whiteboard/src/utils/sketch/ink.d.ts +13 -0
  36. package/types/packages/whiteboard/src/utils/sketch/levels.d.ts +5 -0
  37. package/types/packages/whiteboard/src/utils/sketch/random.d.ts +4 -0
  38. package/types/packages/whiteboard/src/utils/sketch/shape.d.ts +38 -0
  39. package/types/packages/whiteboard/src/utils/sketch/types.d.ts +24 -0
@@ -0,0 +1,189 @@
1
+ /**
2
+ * 画布 chrome 公共件(D-049):
3
+ * 工具条 / 属性浮动条 / 状态栏 / 元素树等浮动件共用一套主题语言——
4
+ * 实底 surface + shadow-lift + 1px 细描边,不用毛玻璃与蓝调;激活 = accent-soft,悬停 = bg-hover;
5
+ * 组内分隔靠留白(ChromeGap),不画竖线。
6
+ *
7
+ * 属性控件(色板 / 滑杆 / 图示选项 / 分区头)是 setter 弹层的内容:色板与派生描边承载用户数据色
8
+ * (完整保留),外壳装饰阴影用黑色 alpha——二者不另设 token,其余一律走主题变量。
9
+ */
10
+ import { type ComponentProps, type ReactNode, type SyntheticEvent } from "react";
11
+ import { type TooltipPlacement } from "../../../ui/src/index";
12
+ /**
13
+ * 浮动件内的指针 / 右键 / 按键不落到画布(画布容器在祖先上监听这些事件)。
14
+ * wheel 必须走捕获:画布的滚轮缩放/平移挂在容器上的原生 addEventListener,
15
+ * 先于 React root 的冒泡委托触发,冒泡期的合成事件 stopPropagation 到不了它前面;
16
+ * 捕获阶段(React root)stopPropagation 会截断整条剩余传播路径,原生监听才收不到。
17
+ */
18
+ export declare const stopCanvasEvents: {
19
+ onPointerDown: (e: SyntheticEvent) => void;
20
+ onPointerUp: (e: SyntheticEvent) => void;
21
+ onMouseDown: (e: SyntheticEvent) => void;
22
+ onMouseUp: (e: SyntheticEvent) => void;
23
+ onClick: (e: SyntheticEvent) => void;
24
+ onDoubleClick: (e: SyntheticEvent) => void;
25
+ onWheelCapture: (e: SyntheticEvent) => void;
26
+ onKeyDown: (e: SyntheticEvent) => void;
27
+ onContextMenu: (e: SyntheticEvent) => void;
28
+ };
29
+ export declare function ChromeBar({ className, children, ...rest }: ComponentProps<"div">): import("react/jsx-runtime").JSX.Element;
30
+ /** 组间留白(替代竖分隔线) */
31
+ export declare function ChromeGap({ className }: {
32
+ className?: string;
33
+ }): import("react/jsx-runtime").JSX.Element;
34
+ /**
35
+ * 工具栏语境:激活态由滑动指示块承载底色,按钮只改文字色(悬停不加背景);
36
+ * 工具栏以外的 ChromeButton(属性条 / 状态栏)保持 accent-soft 底色的原激活态。
37
+ */
38
+ export declare const ToolbarContext: import("react").Context<boolean>;
39
+ export interface ChromeButtonProps extends ComponentProps<"button"> {
40
+ /** 提示与无障碍名 */
41
+ label: string;
42
+ /** 激活态(当前工具 / 开关已开) */
43
+ active?: boolean;
44
+ /** 带子菜单:右下角固定小三角(占位固定,悬停不改尺寸) */
45
+ sub?: boolean;
46
+ kbd?: string;
47
+ tooltipPlacement?: TooltipPlacement;
48
+ }
49
+ /**
50
+ * 浮动件图标按钮:30px,Tooltip 包在 button 外、ref 与注入的 props 透传到 button——
51
+ * 所以可以直接作为 Menu / Popover 的 trigger。展开时(aria-expanded)按下态、并暂停提示。
52
+ */
53
+ export declare function ChromeButton({ label, active, sub, kbd, tooltipPlacement, className, children, ref, ...rest }: ChromeButtonProps): import("react/jsx-runtime").JSX.Element;
54
+ /** 属性条的弹层方向:条在元素上方 → 向上展开;翻到元素下方 → 向下展开 */
55
+ export declare const AttrBarContext: import("react").Context<{
56
+ side: "top" | "bottom";
57
+ }>;
58
+ export interface AttrPopoverProps {
59
+ label: string;
60
+ /** 条目图标;与 swatch 二选一 */
61
+ icon?: ReactNode;
62
+ /** 颜色条目用当前色的小圆点代替通用图标(数据色) */
63
+ swatch?: SwatchLook;
64
+ /** 分区头右侧的开关(开关型属性:开关放标题右侧,下面不再写同名开关) */
65
+ toggle?: {
66
+ checked: boolean;
67
+ onChange: (v: boolean) => void;
68
+ };
69
+ children?: ReactNode;
70
+ /** 弹层宽度,默认 280 */
71
+ width?: number;
72
+ }
73
+ export declare function AttrPopover({ label, icon, swatch, toggle, children, width, }: AttrPopoverProps): import("react/jsx-runtime").JSX.Element;
74
+ /** 纯开关项:点一下直接切换,按钮本身显示开 / 关 */
75
+ export declare function AttrToggle({ label, icon, checked, onChange, }: {
76
+ label: string;
77
+ icon: ReactNode;
78
+ checked: boolean;
79
+ onChange: (v: boolean) => void;
80
+ }): import("react/jsx-runtime").JSX.Element;
81
+ /** 动作项:直接执行(适应内容 / 解散 / 对齐…) */
82
+ export declare function AttrAction({ label, icon, onClick, disabled, }: {
83
+ label: string;
84
+ icon: ReactNode;
85
+ onClick: () => void;
86
+ disabled?: boolean;
87
+ }): import("react/jsx-runtime").JSX.Element;
88
+ /** 弹层内的子字段:小标题 + 控件(纵向从属,不做左右两列) */
89
+ export declare function Field({ label, value, children, className, }: {
90
+ label?: ReactNode;
91
+ value?: ReactNode;
92
+ children: ReactNode;
93
+ className?: string;
94
+ }): import("react/jsx-runtime").JSX.Element;
95
+ export interface SwatchLook {
96
+ fill: string;
97
+ stroke?: string;
98
+ /** default = 「默认」(墨色环);none = 无 / 透明(斜线) */
99
+ kind?: "default" | "none";
100
+ }
101
+ export declare function SwatchDot({ look }: {
102
+ look: SwatchLook;
103
+ }): import("react/jsx-runtime").JSX.Element;
104
+ export interface SwatchOption extends SwatchLook {
105
+ key: string;
106
+ label: string;
107
+ }
108
+ /** 色板:22px 圆色块,选中 = surface 间隙 + accent 外环 */
109
+ export declare function SwatchRow({ options, value, onChange, custom, }: {
110
+ options: SwatchOption[];
111
+ value: string | null | undefined;
112
+ onChange: (key: string) => void;
113
+ /** 末尾「自定义颜色」 */
114
+ custom?: {
115
+ value?: string;
116
+ onChange: (hex: string) => void;
117
+ };
118
+ }): import("react/jsx-runtime").JSX.Element;
119
+ /** 滑杆:accent 轨道 + 右侧数值 */
120
+ export declare function Slider({ value, min, max, step, unit, onChange, onCommit, format, label, }: {
121
+ value: number;
122
+ min: number;
123
+ max: number;
124
+ step?: number;
125
+ unit?: string;
126
+ onChange: (v: number) => void;
127
+ /** 拖动结束(需要合并为一次历史记录的调用方用) */
128
+ onCommit?: (v: number) => void;
129
+ format?: (v: number) => string;
130
+ label?: string;
131
+ }): import("react/jsx-runtime").JSX.Element;
132
+ /**
133
+ * 步进器:− 按钮 / 数值输入 / + 按钮(档位按钮之外的精确微调)。
134
+ * 单位后缀走 unit 文字:NumberInput 事前拦截只放行数字,后缀进输入框会被剥掉。
135
+ */
136
+ export declare function Stepper({ value, min, max, step, onChange, label, unit, }: {
137
+ value: number;
138
+ min: number;
139
+ max: number;
140
+ step?: number;
141
+ onChange: (v: number) => void;
142
+ label: string;
143
+ /** 输入框右侧紧贴的单位字(如 "%") */
144
+ unit?: string;
145
+ }): import("react/jsx-runtime").JSX.Element;
146
+ export interface OptionItem<V extends string> {
147
+ value: V;
148
+ label: string;
149
+ /** 图示(线型 / 箭头端点 / 画框样式…);不给则显示 label */
150
+ glyph?: ReactNode;
151
+ /** 图示 + 文字同时显示 */
152
+ showLabel?: boolean;
153
+ }
154
+ /** 图示选项块:等宽网格,选中 = accent-soft + accent 描边 */
155
+ export declare function OptionGrid<V extends string>({ options, value, onChange, cols, tall, }: {
156
+ options: OptionItem<V>[];
157
+ value: V | null | undefined;
158
+ onChange: (v: V) => void;
159
+ cols?: number;
160
+ /** 图块(上图下字,54px 高) */
161
+ tall?: boolean;
162
+ }): import("react/jsx-runtime").JSX.Element;
163
+ /** 文字分段(连体描边 Segmented,满宽) */
164
+ export declare function Seg<V extends string>({ label, options, value, onChange, }: {
165
+ label: string;
166
+ options: {
167
+ value: V;
168
+ label?: string;
169
+ icon?: import("lucide-react").LucideIcon;
170
+ }[];
171
+ value: V;
172
+ onChange: (v: V) => void;
173
+ }): import("react/jsx-runtime").JSX.Element;
174
+ /** 小图示 svg(28×14 画布,stroke = currentColor) */
175
+ export declare function Glyph({ children }: {
176
+ children: ReactNode;
177
+ }): import("react/jsx-runtime").JSX.Element;
178
+ /** 线宽档位:横条高度 = 线宽(封顶 8px) */
179
+ export declare function LineWeightGlyph({ width }: {
180
+ width: number;
181
+ }): import("react/jsx-runtime").JSX.Element;
182
+ /** 圆角档位:左上折角的圆角 = radius / 2(封顶 10px);0 即直角 */
183
+ export declare function CornerGlyph({ radius }: {
184
+ radius: number;
185
+ }): import("react/jsx-runtime").JSX.Element;
186
+ /** 不透明度档位:色块浓度 = currentColor 与透明的混合 + 内嵌细描边 */
187
+ export declare function OpacityGlyph({ opacity }: {
188
+ opacity: number;
189
+ }): import("react/jsx-runtime").JSX.Element;
@@ -0,0 +1,9 @@
1
+ import type { SketchPath } from "../../utils/sketch/types";
2
+ interface SketchPathsProps {
3
+ paths: SketchPath[];
4
+ /** 虚线流动:遮罩 dashoffset 走完一个周期的秒数;不传则静止 */
5
+ dashFlowDuration?: number;
6
+ }
7
+ /** 渲染 utils/sketch 的输出:墨迹与淡涂是填充多边形,线类填充裁剪在轮廓内,虚线经遮罩切段 */
8
+ declare const SketchPaths: import("react").MemoExoticComponent<({ paths, dashFlowDuration }: SketchPathsProps) => import("react/jsx-runtime").JSX.Element>;
9
+ export default SketchPaths;
@@ -0,0 +1,43 @@
1
+ import type { BoardElement } from "../types/element";
2
+ import type { PageSketch, SketchFillStyle, SketchLevel, SketchMode } from "../types/sketch";
3
+ type ModeChoice = SketchMode | "inherit";
4
+ export declare const randomSeed: () => number;
5
+ export declare const isPaintedFill: (color?: string) => boolean;
6
+ interface SketchFieldsProps {
7
+ page: PageSketch;
8
+ /** 当前画风选项;多选不一致时为 null(不高亮) */
9
+ mode: ModeChoice | null;
10
+ level: SketchLevel | null;
11
+ levelFollowsPage: boolean;
12
+ /** 是否有元素生效为手绘:决定是否展示笔触 / 填充 / 换一笔 */
13
+ enabled: boolean;
14
+ seed: number;
15
+ fill?: {
16
+ color: string;
17
+ style: SketchFillStyle | null;
18
+ };
19
+ onMode: (v: ModeChoice) => void;
20
+ onLevel: (v: SketchLevel) => void;
21
+ onFillStyle: (v: SketchFillStyle) => void;
22
+ onReseed: () => void;
23
+ hint?: string;
24
+ }
25
+ /** 单选与多选共用的「笔触」弹层内容 */
26
+ export declare function SketchFields(props: SketchFieldsProps): import("react/jsx-runtime").JSX.Element;
27
+ interface SketchPopoverProps<T extends BoardElement> {
28
+ /** 存覆盖的元素:一般是选中元素本身,思维导图是根节点 */
29
+ target: T;
30
+ onChange: (next: T) => void;
31
+ /** 形状才有:填充样式(有填充色时显示) */
32
+ fill?: {
33
+ color?: string;
34
+ style?: SketchFillStyle;
35
+ onChange: (style: SketchFillStyle) => void;
36
+ };
37
+ }
38
+ /**
39
+ * 元素级「笔触」(D-107):画风(跟随页面 / 手绘 / 普通)· 笔触档位 · 填充 · 换一笔。
40
+ * 未单独设置的字段跟随页面,选「跟随页面」即删除覆盖。
41
+ */
42
+ declare function SketchPopover<T extends BoardElement>({ target, onChange, fill }: SketchPopoverProps<T>): import("react/jsx-runtime").JSX.Element;
43
+ export default SketchPopover;
@@ -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;