@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.
Files changed (33) hide show
  1. package/WHITEBOARD.md +115 -0
  2. package/package.json +8 -3
  3. package/tailwind.css +101 -0
  4. package/types/packages/plugins/src/contract.d.ts +2 -0
  5. package/types/packages/plugins/src/whiteboard.d.ts +7 -0
  6. package/types/packages/shared/entity-ref.d.ts +19 -0
  7. package/types/packages/whiteboard/src/author.d.ts +14 -0
  8. package/types/packages/whiteboard/src/authorSketch.d.ts +6 -0
  9. package/types/packages/whiteboard/src/chrome/index.d.ts +189 -0
  10. package/types/packages/whiteboard/src/components/SketchPaths/index.d.ts +9 -0
  11. package/types/packages/whiteboard/src/components/SketchPopover.d.ts +43 -0
  12. package/types/packages/whiteboard/src/extensions/api.d.ts +352 -0
  13. package/types/packages/whiteboard/src/extensions/authorHooks.d.ts +4 -0
  14. package/types/packages/whiteboard/src/extensions/context.d.ts +4 -0
  15. package/types/packages/whiteboard/src/extensions/events.d.ts +50 -0
  16. package/types/packages/whiteboard/src/extensions/standard-schema.d.ts +32 -0
  17. package/types/packages/whiteboard/src/types/containment.d.ts +3 -0
  18. package/types/packages/whiteboard/src/types/element.d.ts +33 -0
  19. package/types/packages/whiteboard/src/types/operation.d.ts +51 -0
  20. package/types/packages/whiteboard/src/types/path.d.ts +1 -0
  21. package/types/packages/whiteboard/src/types/point.d.ts +4 -0
  22. package/types/packages/whiteboard/src/types/presentation.d.ts +11 -0
  23. package/types/packages/whiteboard/src/types/schematic.d.ts +44 -0
  24. package/types/packages/whiteboard/src/types/selection.d.ts +11 -0
  25. package/types/packages/whiteboard/src/types/sketch.d.ts +25 -0
  26. package/types/packages/whiteboard/src/types/viewport.d.ts +8 -0
  27. package/types/packages/whiteboard/src/utils/sketch/geometry.d.ts +22 -0
  28. package/types/packages/whiteboard/src/utils/sketch/handText.d.ts +3 -0
  29. package/types/packages/whiteboard/src/utils/sketch/ink.d.ts +13 -0
  30. package/types/packages/whiteboard/src/utils/sketch/levels.d.ts +5 -0
  31. package/types/packages/whiteboard/src/utils/sketch/random.d.ts +4 -0
  32. package/types/packages/whiteboard/src/utils/sketch/shape.d.ts +38 -0
  33. package/types/packages/whiteboard/src/utils/sketch/types.d.ts +24 -0
package/WHITEBOARD.md ADDED
@@ -0,0 +1,115 @@
1
+ # 白板插件
2
+
3
+ 白板作者接口需要 SDK 0.8.0 及包含白板扩展支持的 Tau 客户端。SDK 0.7.0 不提供此能力。
4
+
5
+ 插件定义中声明 `whiteboardExtensions`,manifest 增加 `whiteboard: true`。使用 `@tau/plugins/whiteboard` 导入定义函数和类型,并将该模块保留为构建 external,由宿主提供实现。一个 main.js 同时包含声明、渲染与交互,不生成另一个渲染入口。
6
+
7
+ ```tsx
8
+ import { definePlugin } from "@tau/plugins";
9
+ import { defineElement, defineWhiteboardExtension } from "@tau/plugins/whiteboard";
10
+
11
+ declare const __PLUGIN_META__: { id: string; name: string; version: string };
12
+ const type = `${__PLUGIN_META__.id}.box`;
13
+ const extension = defineWhiteboardExtension({
14
+ id: __PLUGIN_META__.id,
15
+ elements: [
16
+ defineElement({
17
+ type,
18
+ render: ({ element }) => (
19
+ <rect
20
+ x={element.x}
21
+ y={element.y}
22
+ width={element.width}
23
+ height={element.height}
24
+ fill="var(--tau-accent)"
25
+ />
26
+ ),
27
+ create: {
28
+ gesture: "click",
29
+ defaultSize: [160, 90],
30
+ after: "select",
31
+ build: ({ rect }) => ({ id: crypto.randomUUID(), type, ...rect, data: {} }),
32
+ },
33
+ }),
34
+ ],
35
+ create: () => ({
36
+ tools: [
37
+ {
38
+ id: `${__PLUGIN_META__.id}.create`,
39
+ element: type,
40
+ label: "插入方块",
41
+ order: 90,
42
+ group: "drawing",
43
+ icon: () => (
44
+ <svg viewBox="0 0 24 24">
45
+ <rect x={3} y={5} width={18} height={14} fill="currentColor" />
46
+ </svg>
47
+ ),
48
+ },
49
+ ],
50
+ }),
51
+ });
52
+ export default definePlugin({ ...__PLUGIN_META__, whiteboardExtensions: [extension] });
53
+ ```
54
+
55
+ ## 契约
56
+
57
+ - `elements` 在扩展顶层静态声明,禁止放到 `create` 返回值中。元素类型必须以完整插件 ID 加点开头,扩展 ID 为插件 ID 或其子命名空间。
58
+ - `create(api)` 每个画布单独执行,返回 `tools`、`inspectors`、`commands` 等交互贡献。状态放在实例闭包,不能放在模块顶层跨画布共享。
59
+ - 元素私有字段放在 `data`,通过 `defineElement<TData>` 和可选同步 Standard Schema 校验约束;通用位置和尺寸仍在元素顶层。
60
+ - 属性修改走 `api.updateElement`,结构操作走 `api.submit`;这些入口统一处理只读、历史及生命周期。不要修改返回的快照。
61
+ - 元素组件可用 `useWhiteboardAPI()` 获取所属扩展的受控 API,不接触内部 Board。声明求值阶段不得读取 DOM。
62
+ - `activate` 随画布显示运行,停驻会清理;`dispose` 在真正销毁时运行。插件整体启用/停用/更新在重启后改变静态装配,不热替换打开中的画布。
63
+ - 找不到插件时保留节点并显示未知元素占位,重新安装并启用后恢复。保存、复制不能丢弃未知节点。
64
+
65
+ ## 通用展示与交互
66
+
67
+ ### 创建前选择参数
68
+
69
+ 第三方工具集中在「扩展工具」菜单;可选的 `panel` 让用户先选择参数,再调用 `run(payload)`。面板可以通过 `useWhiteboardAPI()` 获取所属扩展的 API。
70
+
71
+ ```tsx
72
+ panel: ({ run }) => (
73
+ <button onClick={() => run({ label: "新方块" })}>创建新方块</button>
74
+ ),
75
+ ```
76
+
77
+ 创建工具在 `element.create.build` 的 `options` 中读取这些参数,命令工具在命令的 `payload` 中读取。宿主管理返回、关闭与面板卸载,执行后自动关闭;返回或关闭不会执行工具。关闭后的迟到 `run` 调用被忽略。面板抛错时显示错误并保留返回入口。没有 `panel` 的工具仍点击即执行;不要用只供内置工具栏使用的 `component` 代替它,也不要在面板内创建第二套画布指针监听。
78
+
79
+ ### 元素声明
80
+
81
+ 以下声明放在 `defineElement` 内,仍使用同一个插件入口:
82
+
83
+ ```ts
84
+ interaction: {
85
+ resize: { handles: "corners", preserveAspectRatio: true },
86
+ connect: "rect",
87
+ },
88
+ presentation: {
89
+ label: "我的图形",
90
+ getName: element => element.data.label,
91
+ },
92
+ sketch: true,
93
+ schematic: element => [{
94
+ kind: "rect", x: element.x, y: element.y,
95
+ w: element.width, h: element.height, r: 3, fill: "var(--tau-accent)",
96
+ }],
97
+ ```
98
+
99
+ - `resize.handles` 可选 corners 或 all,默认 all;`preserveAspectRatio` 默认为 false,Shift 仍可启用等比。内核生成手柄,负责吸附、单步撤销、取消和生命周期,不要再给元素额外画一套缩放手柄。
100
+ - `connect: "rect"` 使用矩形连接点,包括相对位置绑定;不声明则不生成连接控件。
101
+ - `presentation.icon` 为可选图标组件,接收 className、size、strokeWidth。`getName` 接收只读快照,手动 name 优先;无法生成时回退 label。
102
+ - 声明 `sketch:true` 后,在元素组件调用 `useSketch(element)` 获取 enabled/level/seed;页面切换会更新组件,元素覆盖仍由宿主解析。不要自行维护全局画风状态。
103
+ - `SketchPaths` 渲染已有手绘路径;`sketch` 命名空间提供 createRandom、distance、polylineToD、resample、wobble、inkOutline、inkSize、loopStroke、handTextClass。复用宿主纯算法,不从白板内部目录复制实现。
104
+ - `usePageSketch()` 读取所属页面的画风;`sketch.hashSeed(text)` 为预览图生成稳定种子。`AttrPopover`、`AttrToggle`、`OptionGrid`、`Seg` 供属性面板使用,`SketchPopover` 提供与宿主相同的元素笔触设置。
105
+ - `schematic(element, { dark })` 返回纯图元数组,用于列表与导出弹窗的简略预览;字段类型见 SchematicShape。不能调用 hook、修改元素或依赖某个画布已打开。实际图像导出仍使用完整画布渲染,不使用简略投影替代。
106
+
107
+ 构建 Tailwind 工具类时可导入 `@tau/plugins/tailwind.css`,其中仅包含语义类名映射,主题变量由客户端提供。不要引入未公开的宿主主题包。
108
+
109
+ ## 私有偏好
110
+
111
+ 需要记住用户选择时,在扩展中声明 `requires: [IPluginStorage]`,通过 `api.getService(IPluginStorage)` 获取存储。`IPluginStorage` 从 `@tau/plugins/whiteboard` 导入,接口与 `PluginContext.storage` 相同:异步 `get(key)`、`set(key, JSON值)`、`delete(key)`。
112
+
113
+ 宿主按插件真实归属与当前工作区绑定存储,插件不能传入其他插件 ID。画布隐藏、关闭或只读时拒绝交互存储操作;插件失活、工作区切换后,旧实例也不能继续写入。异步读写应捕获错误,并在面板卸载后忽略迟到结果。重新打开白板后绑定当前激活实例。
114
+
115
+ 只在 `create(api)`、工具面板、属性交互和 `element.create.build` 中使用这项服务。静态渲染与 `schematic` 必须只依据元素数据及明确输入,不依赖存储、DOM 或插件 activate 时序。读取不存在的偏好时使用默认值;读取失败不能伪装成空数据后覆盖原值。
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@xiongtao.xt/tau-plugins",
3
- "version": "0.7.0",
3
+ "version": "0.8.0",
4
4
  "license": "MIT",
5
5
  "repository": {
6
6
  "type": "git",
@@ -16,15 +16,20 @@
16
16
  ".": {
17
17
  "types": "./types/packages/plugins/src/index.d.ts",
18
18
  "default": "./runtime.js"
19
+ },
20
+ "./tailwind.css": "./tailwind.css",
21
+ "./whiteboard": {
22
+ "types": "./types/packages/plugins/src/whiteboard.d.ts",
23
+ "default": "./runtime.js"
19
24
  }
20
25
  },
21
26
  "dependencies": {
22
27
  "@types/react": "19.2.0",
23
28
  "@types/react-dom": "19.2.0",
29
+ "lucide-react": "0.399.0",
30
+ "clsx": "2.1.1",
24
31
  "slate": "0.126.2",
25
32
  "slate-react": "0.126.4",
26
- "clsx": "2.1.1",
27
- "lucide-react": "0.399.0",
28
33
  "slate-history": "0.113.1"
29
34
  },
30
35
  "peerDependencies": {
package/tailwind.css ADDED
@@ -0,0 +1,101 @@
1
+ /*
2
+ * Tailwind v4 语义类名映射:组件写 bg-page / text-ink-1 / border-line-1 等,主题无关。
3
+ * 取值来自 tokens.css 的 --tau-*,使用方需同时引入 @tau/themes/tokens.css。
4
+ *
5
+ * Tailwind 词一律用 tau 命名空间(rounded-tau-* / text-tau-*),不覆盖
6
+ * legacy 页面在用的 Tailwind 默认刻度(D-001);一次性展示字号允许
7
+ * text-[24px] 类任意值。
8
+ */
9
+ @theme inline {
10
+ --color-page: var(--tau-bg-page);
11
+ --color-surface: var(--tau-bg-surface);
12
+ --color-surface-hover: var(--tau-bg-surface-hover);
13
+ --color-sunken: var(--tau-bg-sunken);
14
+ --color-track: var(--tau-bg-track);
15
+ --color-hover: var(--tau-bg-hover);
16
+ --color-press: var(--tau-bg-press);
17
+ --color-selected: var(--tau-bg-selected);
18
+
19
+ --color-ink-1: var(--tau-ink-1);
20
+ --color-ink-2: var(--tau-ink-2);
21
+ --color-ink-3: var(--tau-ink-3);
22
+ --color-ink-inverse: var(--tau-ink-inverse);
23
+
24
+ --color-line-1: var(--tau-line-1);
25
+ --color-line-2: var(--tau-line-2);
26
+
27
+ --color-overlay: var(--tau-overlay);
28
+
29
+ --color-accent: var(--tau-accent);
30
+ --color-accent-hover: var(--tau-accent-hover);
31
+ --color-accent-soft: var(--tau-accent-soft);
32
+ --color-accent-text: var(--tau-accent-text);
33
+
34
+ --color-ok: var(--tau-ok);
35
+ --color-ok-soft: var(--tau-ok-soft);
36
+ --color-warn: var(--tau-warn);
37
+ --color-warn-soft: var(--tau-warn-soft);
38
+ --color-danger: var(--tau-danger);
39
+ --color-danger-soft: var(--tau-danger-soft);
40
+ --color-info: var(--tau-info);
41
+ --color-info-soft: var(--tau-info-soft);
42
+
43
+ --color-tag-1: var(--tau-tag-1);
44
+ --color-tag-1-soft: var(--tau-tag-1-soft);
45
+ --color-tag-2: var(--tau-tag-2);
46
+ --color-tag-2-soft: var(--tau-tag-2-soft);
47
+ --color-tag-3: var(--tau-tag-3);
48
+ --color-tag-3-soft: var(--tau-tag-3-soft);
49
+ --color-tag-4: var(--tau-tag-4);
50
+ --color-tag-4-soft: var(--tau-tag-4-soft);
51
+ --color-tag-5: var(--tau-tag-5);
52
+ --color-tag-5-soft: var(--tau-tag-5-soft);
53
+
54
+ --font-tau: var(--tau-font);
55
+ --font-tau-mono: var(--tau-font-mono);
56
+ --font-tau-hand: var(--tau-font-hand);
57
+
58
+ /* ── 尺度词(D-001,tau 命名空间,见 02 规范 §3/§4)── */
59
+
60
+ /* 字号:A2 定稿取值(经 :root 字面值层 --tau-text-* 桥接,支持运行时整体缩放——
61
+ @theme inline 对字面值会内联进工具类导致不可覆盖,必须走 var 引用) */
62
+ --text-tau-hero: var(--tau-text-hero);
63
+ --text-tau-title-lg: var(--tau-text-title-lg);
64
+ --text-tau-title: var(--tau-text-title);
65
+ --text-tau-body-lg: var(--tau-text-body-lg);
66
+ --text-tau-body: var(--tau-text-body);
67
+ --text-tau-body--line-height: 1.65;
68
+ --text-tau-meta: var(--tau-text-meta);
69
+ --text-tau-sm: var(--tau-text-sm);
70
+ --text-tau-micro: var(--tau-text-micro);
71
+ --text-tau-tiny: var(--tau-text-tiny);
72
+
73
+ /* 圆角三档 */
74
+ --radius-tau-sm: var(--tau-radius-sm);
75
+ --radius-tau-md: var(--tau-radius-md);
76
+ --radius-tau-lg: var(--tau-radius-lg);
77
+
78
+ /* 阴影(tokenContract float 组词):card 静止 / lift 卡片 hover 轻抬 / float 浮层 / paper 画布上浮起的文档纸 */
79
+ --shadow-card: var(--tau-shadow-card);
80
+ --shadow-lift: var(--tau-shadow-lift);
81
+ --shadow-float: var(--tau-shadow-float);
82
+ --shadow-paper: var(--tau-shadow-paper);
83
+
84
+ /* 缓动 */
85
+ --ease-tau-out: var(--tau-ease-out);
86
+
87
+ /* 域内动效(keyframes 与词表同处声明,hover:animate-hm-pulse 消费) */
88
+ --animate-hm-pulse: hmPulse 0.5s linear alternate infinite;
89
+
90
+ @keyframes hmPulse {
91
+ 0% {
92
+ transform: scale(1.18);
93
+ }
94
+ 50% {
95
+ transform: scale(1);
96
+ }
97
+ 100% {
98
+ transform: scale(0.85);
99
+ }
100
+ }
101
+ }
@@ -1,6 +1,7 @@
1
1
  import type { PluginPages } from "./pages";
2
2
  import type { PluginSkill } from "./skills";
3
3
  import type { PluginAI, PluginAIFeature } from "./ai";
4
+ import type { WhiteboardExtension } from "./whiteboard";
4
5
  import type { PluginServices } from "./services";
5
6
  import type { PluginEditor } from "./editor";
6
7
  import type { PluginEditorExtension } from "./editor";
@@ -56,6 +57,7 @@ export interface PluginDefinition {
56
57
  readonly apiVersion: 1;
57
58
  /** 静态声明,桌面与博客均装配同一份扩展;模块加载不得依赖桌面激活。 */
58
59
  readonly editorExtensions?: readonly PluginEditorExtension[];
60
+ readonly whiteboardExtensions?: readonly WhiteboardExtension[];
59
61
  readonly editorCodecs?: readonly MarkdownCodec[];
60
62
  readonly skills?: readonly PluginSkill[];
61
63
  readonly ai?: {
@@ -0,0 +1,7 @@
1
+ export { defineElement, defineWhiteboardExtension, useWhiteboardAPI, useSketch, usePageSketch, AttrPopover, AttrToggle, OptionGrid, Seg, SketchPopover, sketch, SketchPaths, } from "../../whiteboard/src/author";
2
+ export type { SketchPath, Vec } from "../../whiteboard/src/author";
3
+ export type { SchematicShape, SchematicFill, ResolvedSketch, ElementSketch, PageSketch, SketchLevel, } from "../../whiteboard/src/author";
4
+ export type { WhiteboardAPI, WhiteboardExtension, WhiteboardElementDefinition, WhiteboardContributions, TypedBoardElement, ElementCreateSpec, WhiteboardSnapshot, BoardElement, WhiteboardToolProps, } from "../../whiteboard/src/author";
5
+ import type { PluginStorage } from "./contract";
6
+ /** 由宿主按插件和工作区绑定,交互扩展通过 requires 声明后获取。 */
7
+ export declare const IPluginStorage: import("../../shared/service-contract").ServiceIdentifier<PluginStorage>;
@@ -0,0 +1,19 @@
1
+ /**
2
+ * 统一实体地址:跨模块指向「一份正文的某个身份」(卡片、文章、项目文档、日记)。
3
+ *
4
+ * 纯 TypeScript,桌面端与移动端共用。存量各处的类型写法(question_link 的 project_item、
5
+ * content-link / 索引的 project-item)经 normalizeEntityRefKind 收口;
6
+ * 日记正文身份为 diary-moment + 片段 id,存量日级引用在开库时转换。
7
+ */
8
+ export declare const ENTITY_REF_KINDS: readonly ["card", "article", "project-item", "diary-moment"];
9
+ export type EntityRefKind = (typeof ENTITY_REF_KINDS)[number];
10
+ export interface EntityRef {
11
+ kind: EntityRefKind;
12
+ id: number;
13
+ }
14
+ /** 各处存量写法 → EntityRefKind;不认识的返回 null,由调用方丢弃 */
15
+ export declare function normalizeEntityRefKind(raw: unknown): EntityRefKind | null;
16
+ export declare const entityRefKey: (ref: EntityRef) => string;
17
+ export declare const isSameEntityRef: (a: EntityRef, b: EntityRef) => boolean;
18
+ /** 同一份正文被多个实体共用时,选哪个身份作代表:卡片 > 文章 > 项目文档 > 日记 */
19
+ export declare const ENTITY_REF_PRIORITY: Record<EntityRefKind, number>;
@@ -0,0 +1,14 @@
1
+ /** 白板作者入口保持无 DOM 副作用,定义可在纯数据宿主中求值。 */
2
+ export { defineElement, defineWhiteboardExtension } from "./extensions/api";
3
+ export type { WhiteboardAPI, WhiteboardExtension, WhiteboardElementDefinition, WhiteboardContributions, TypedBoardElement, ElementCreateSpec, WhiteboardSnapshot, WhiteboardToolProps, } from "./extensions/api";
4
+ export type { BoardElement } from "./types/element";
5
+ export { useWhiteboardAPI } from "./extensions/context";
6
+ export { useSketch, usePageSketch } from "./extensions/authorHooks";
7
+ export { AttrPopover, AttrToggle, OptionGrid, Seg } from "./chrome/index";
8
+ export { default as SketchPopover } from "./components/SketchPopover";
9
+ export * as sketch from "./authorSketch";
10
+ export { default as SketchPaths } from "./components/SketchPaths/index";
11
+ export type { SketchPath } from "./utils/sketch/types";
12
+ export type { Vec } from "./utils/sketch/geometry";
13
+ export type { SchematicShape, SchematicFill } from "./types/schematic";
14
+ export type { ResolvedSketch, ElementSketch, PageSketch, SketchLevel } from "./types/sketch";
@@ -0,0 +1,6 @@
1
+ export { createRandom, hashSeed } from "./utils/sketch/random";
2
+ export { distance, polylineToD, resample, wobble } from "./utils/sketch/geometry";
3
+ export { inkOutline } from "./utils/sketch/ink";
4
+ export { inkSize } from "./utils/sketch/levels";
5
+ export { loopStroke } from "./utils/sketch/shape";
6
+ export { handTextClass } from "./utils/sketch/handText";
@@ -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;