mce 0.24.4 → 0.25.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/README.md +237 -4
- package/dist/components/EditorPanels.vue.d.ts +6 -0
- package/dist/components/Interactions.vue.d.ts +3 -0
- package/dist/components/shared/Cropper.vue.d.ts +5 -1
- package/dist/components/shared/Dialog.vue.d.ts +33 -38
- package/dist/components/shared/FloatPanel.vue.d.ts +4 -2
- package/dist/components/shared/LayoutItem.vue.d.ts +29 -0
- package/dist/components/shared/PanelContent.vue.d.ts +29 -0
- package/dist/components/timeline/EasingCurve.vue.d.ts +11 -0
- package/dist/components/timeline/KeyframePopover.vue.d.ts +3 -0
- package/dist/crdt/YDoc.d.ts +27 -2
- package/dist/crdt/YDoc.test.d.ts +1 -0
- package/dist/crdt/index.d.ts +3 -0
- package/dist/crdt/providers/indexeddb/IndexeddbProvider.d.ts +3 -1
- package/dist/crdt/reactivity.d.ts +27 -0
- package/dist/crdt/reactivity.test.d.ts +1 -0
- package/dist/crdt/vueReactivity.d.ts +8 -0
- package/dist/index.css +1 -1
- package/dist/index.d.ts +3 -0
- package/dist/index.js +10300 -8946
- package/dist/locale/en.d.ts +51 -9
- package/dist/locale/zh-Hans.d.ts +51 -9
- package/dist/mixins/0.context.d.ts +2 -0
- package/dist/mixins/extensions.d.ts +105 -0
- package/dist/mixins/panels.d.ts +46 -0
- package/dist/plugin.d.ts +14 -0
- package/dist/plugins/animate.d.ts +40 -0
- package/dist/plugins/components.d.ts +32 -0
- package/dist/plugins/flexLayout.d.ts +15 -0
- package/dist/plugins/history.d.ts +2 -0
- package/dist/plugins/interactions.d.ts +44 -0
- package/dist/plugins/shape.d.ts +0 -4
- package/dist/plugins/slice.d.ts +10 -0
- package/dist/plugins/smartGuides.d.ts +2 -2
- package/dist/plugins/timeline.d.ts +17 -0
- package/dist/plugins/toolbelt.d.ts +4 -0
- package/dist/plugins/variables.d.ts +27 -0
- package/dist/plugins/zoom.d.ts +2 -0
- package/dist/scene/Doc.d.ts +13 -1
- package/dist/typed-global.d.ts +6 -2
- package/dist/typed-plugins.d.ts +6 -3
- package/dist/utils/animationPresets.d.ts +27 -0
- package/dist/utils/components.d.ts +33 -0
- package/dist/utils/components.test.d.ts +1 -0
- package/dist/utils/create.d.ts +1 -15
- package/dist/utils/easing.d.ts +23 -0
- package/dist/utils/easing.test.d.ts +1 -0
- package/dist/utils/index.d.ts +8 -1
- package/dist/utils/keyframes.d.ts +31 -0
- package/dist/utils/keyframes.test.d.ts +1 -0
- package/dist/utils/lottie.d.ts +27 -0
- package/dist/utils/lottie.test.d.ts +1 -0
- package/dist/utils/remapTextSelection.d.ts +23 -0
- package/dist/utils/remapTextSelection.test.d.ts +1 -0
- package/dist/utils/traverse.d.ts +9 -0
- package/dist/utils/variables.d.ts +58 -0
- package/dist/utils/variables.test.d.ts +1 -0
- package/package.json +4 -8
- package/dist/plugins/html.d.ts +0 -2
- package/dist/plugins/table.d.ts +0 -2
- package/dist/plugins/workflow.d.ts +0 -31
- package/dist/utils/table.d.ts +0 -93
- package/dist/utils/workflow.d.ts +0 -9
- /package/dist/components/{TableEditor.vue.d.ts → Components.vue.d.ts} +0 -0
- /package/dist/components/{Workflow.vue.d.ts → InteractionBadges.vue.d.ts} +0 -0
- /package/dist/utils/{smartGuides-geometry.d.ts → smartGuidesGeometry.d.ts} +0 -0
package/README.md
CHANGED
|
@@ -18,7 +18,7 @@
|
|
|
18
18
|
</a>
|
|
19
19
|
</p>
|
|
20
20
|
|
|
21
|
-
<p align="center">
|
|
21
|
+
<p align="center">An infinite canvas editor framework (Vue 3 + TypeScript) with real-time collaboration, a timeline, components and design tokens — built on WebGL rendering. Bring your own UI. ESM only.</p>
|
|
22
22
|
|
|
23
23
|
<p align="center">
|
|
24
24
|
<a href="https://qq15725.github.io/mce/">📚 Documentation</a>
|
|
@@ -26,6 +26,76 @@
|
|
|
26
26
|
<a href="https://codesandbox.io/p/github/qq15725/mce/main">🎮 Try in CodeSandbox</a>
|
|
27
27
|
</p>
|
|
28
28
|
|
|
29
|
+
## ✨ Features
|
|
30
|
+
|
|
31
|
+
**Canvas & editing**
|
|
32
|
+
- Infinite canvas with pan / zoom, rulers, scrollbars, pixel grid and checkerboard
|
|
33
|
+
- Smart guides & snapping, alignment / distribution, z-order arrange, tidy-up
|
|
34
|
+
- Multi-select & marquee, transform (move / resize / rotate / flip), foreground crop
|
|
35
|
+
- Frames (artboards) with auto-nesting, and Flex auto-layout (drag-to-reorder)
|
|
36
|
+
|
|
37
|
+
**Content**
|
|
38
|
+
- Shapes, pen / freehand paths, lines & arrows
|
|
39
|
+
- Rich text (fragment styling, custom fonts, format painter, auto-fit strategies)
|
|
40
|
+
- Images (insert / upload / crop), video, tables (`@mce/table`) and charts (`@mce/chart`)
|
|
41
|
+
|
|
42
|
+
**Motion**
|
|
43
|
+
- Timeline with frame-based playback
|
|
44
|
+
- Keyframe animation with reusable easing (presets + custom cubic-bezier)
|
|
45
|
+
- Export to GIF, MP4 and Lottie
|
|
46
|
+
|
|
47
|
+
**Collaboration & history**
|
|
48
|
+
- CRDT document model ([Yjs](https://github.com/yjs/yjs)) in the core — undo / redo and offline persistence (IndexedDB) build on it
|
|
49
|
+
- Real-time multi-user editing + awareness (remote cursors / selection / avatars) via `@mce/collaboration` (WebSocket / pluggable transport)
|
|
50
|
+
- Comments anchored to elements (pins follow on move / scale / rotate, threads with replies & resolve) via `@mce/comments`
|
|
51
|
+
|
|
52
|
+
**Design systems**
|
|
53
|
+
- Components / symbols / instances with per-instance overrides and master propagation
|
|
54
|
+
- Design tokens / variables (collections + modes) for theming and responsive values
|
|
55
|
+
|
|
56
|
+
**AI** (`@mce/ai`)
|
|
57
|
+
- A typed AI canvas action schema — drive edits from an LLM over the existing command & undo stack (model wiring left to the consumer)
|
|
58
|
+
|
|
59
|
+
**Workflow** (`@mce/workflow`)
|
|
60
|
+
- A node-graph editing mode: connectable nodes with input / output ports and curved connections
|
|
61
|
+
|
|
62
|
+
**Extensible**
|
|
63
|
+
- ~40 built-in plugins; a plugin can contribute commands, tools, hotkeys, exporters, loaders, components and events
|
|
64
|
+
- Element types & modes are decoupled via extension points (selection redirect, resize override, enter handler, editing state, toolbelt item, icon, mode, statusbar item) — see `mixins/extensions.ts`
|
|
65
|
+
- Unified command system, hotkeys, and i18n
|
|
66
|
+
|
|
67
|
+
## 📤 Import & export
|
|
68
|
+
|
|
69
|
+
- **Export**: `PNG` · `JPEG` · `WebP` · `SVG` · `PDF` · `GIF` · `MP4` · `Lottie` · `PPTX` / `XLSX` / `DOCX` · `JSON`
|
|
70
|
+
- **Import**: `PPTX` / `XLSX` / `DOCX` · `PSD` · `HTML` · images · `JSON`
|
|
71
|
+
|
|
72
|
+
These ship as optional plugins; their heavy encoders / parsers are lazy-loaded on first use:
|
|
73
|
+
|
|
74
|
+
| Package | Adds |
|
|
75
|
+
| --- | --- |
|
|
76
|
+
| `@mce/gif` | GIF export |
|
|
77
|
+
| `@mce/mp4` | MP4 export |
|
|
78
|
+
| `@mce/pdf` | PDF export |
|
|
79
|
+
| `@mce/svg` | SVG export |
|
|
80
|
+
| `@mce/openxml` | PPTX / XLSX / DOCX import & export |
|
|
81
|
+
| `@mce/psd` | PSD import (Photoshop layers → elements) |
|
|
82
|
+
| `@mce/html` | HTML import |
|
|
83
|
+
|
|
84
|
+
(`PNG` / `JPEG` / `WebP` / `JSON` / `Lottie` export are built in.)
|
|
85
|
+
|
|
86
|
+
## 🔌 Feature plugins
|
|
87
|
+
|
|
88
|
+
Specialized features also ship as optional packages, registered the same way (`plugins: [...]`):
|
|
89
|
+
|
|
90
|
+
| Package | Adds |
|
|
91
|
+
| --- | --- |
|
|
92
|
+
| `@mce/table` | Table element + in-canvas table editor |
|
|
93
|
+
| `@mce/chart` | Chart elements (bar / line / pie / …) |
|
|
94
|
+
| `@mce/ai` | Typed AI canvas action schema (`applyAiActions`) |
|
|
95
|
+
| `@mce/workflow` | Node-graph editing mode |
|
|
96
|
+
| `@mce/collaboration` | Real-time collaboration: transport providers + presence (cursors / selection / avatars) |
|
|
97
|
+
| `@mce/comments` | Comments: comment tool + pins anchored to elements + threads (stored on `element.comments`) |
|
|
98
|
+
|
|
29
99
|
## 📦 Install
|
|
30
100
|
|
|
31
101
|
```shell
|
|
@@ -38,22 +108,38 @@ npm i mce
|
|
|
38
108
|
<script setup lang="ts">
|
|
39
109
|
import { Editor, EditorLayout, EditorLayoutItem } from 'mce'
|
|
40
110
|
import 'mce/styles'
|
|
111
|
+
import ai from '@mce/ai'
|
|
112
|
+
import chart from '@mce/chart'
|
|
113
|
+
import collaboration from '@mce/collaboration'
|
|
114
|
+
import comments from '@mce/comments'
|
|
41
115
|
import gif from '@mce/gif'
|
|
42
116
|
import mp4 from '@mce/mp4'
|
|
43
117
|
import openxml from '@mce/openxml'
|
|
44
118
|
import pdf from '@mce/pdf'
|
|
45
119
|
import svg from '@mce/svg'
|
|
46
|
-
import
|
|
120
|
+
import table from '@mce/table'
|
|
121
|
+
import workflow from '@mce/workflow'
|
|
47
122
|
|
|
48
123
|
const editor = new Editor({
|
|
49
124
|
plugins: [
|
|
125
|
+
// export / import formats
|
|
50
126
|
gif(),
|
|
51
127
|
mp4(),
|
|
52
128
|
svg(),
|
|
53
129
|
pdf(),
|
|
54
130
|
openxml(),
|
|
131
|
+
// feature plugins (all optional)
|
|
132
|
+
table(),
|
|
133
|
+
chart(),
|
|
134
|
+
ai(),
|
|
135
|
+
workflow(),
|
|
136
|
+
collaboration(), // registers the collaboration + presence plugins
|
|
137
|
+
comments(),
|
|
55
138
|
],
|
|
56
|
-
|
|
139
|
+
// @mce/gif bundles its encoding worker by default. To self-host it
|
|
140
|
+
// (e.g. under a strict CSP), pass `gifWorkerUrl` explicitly:
|
|
141
|
+
// import gifWorkerUrl from 'modern-gif/worker?url'
|
|
142
|
+
// ...new Editor({ gifWorkerUrl })
|
|
57
143
|
locale: { locale: 'en' },
|
|
58
144
|
viewport: {
|
|
59
145
|
camera: { enabled: true },
|
|
@@ -132,7 +218,7 @@ npm i mce
|
|
|
132
218
|
</template>
|
|
133
219
|
```
|
|
134
220
|
|
|
135
|
-
|
|
221
|
+
Slot sub component — read editor state via `useEditor()`:
|
|
136
222
|
|
|
137
223
|
```vue
|
|
138
224
|
<script setup lang="ts">
|
|
@@ -147,3 +233,150 @@ slot sub component
|
|
|
147
233
|
</template>
|
|
148
234
|
```
|
|
149
235
|
|
|
236
|
+
## 🧩 Commands
|
|
237
|
+
|
|
238
|
+
Everything the editor does is a command — call `editor.exec(name, ...args)`. A few examples:
|
|
239
|
+
|
|
240
|
+
```ts
|
|
241
|
+
// Arrange & layout
|
|
242
|
+
editor.exec('alignHorizontalCenter')
|
|
243
|
+
editor.exec('distributeHorizontalSpacing')
|
|
244
|
+
editor.exec('tidyUp')
|
|
245
|
+
|
|
246
|
+
// Design tokens / variables
|
|
247
|
+
const collection = editor.exec('createVariableCollection', 'Theme', 'Light')
|
|
248
|
+
const dark = editor.exec('addVariableMode', collection, 'Dark')
|
|
249
|
+
const brand = editor.exec('addVariable', collection, { name: 'brand', type: 'color', value: '#ff0000' })
|
|
250
|
+
editor.exec('setVariableValue', brand, dark, '#0000ff')
|
|
251
|
+
editor.exec('bindVariable', 'fill.color', brand) // bind selected element's fill
|
|
252
|
+
editor.exec('setActiveVariableMode', collection, dark) // theme switch → canvas recolors
|
|
253
|
+
|
|
254
|
+
// Components / instances
|
|
255
|
+
const component = editor.exec('createComponent') // from selection
|
|
256
|
+
editor.exec('createInstance', component, { position: { x: 200, y: 200 } })
|
|
257
|
+
|
|
258
|
+
// Keyframe animation → Lottie
|
|
259
|
+
editor.exec('addAnimationKeyframe', 0, { left: 0, opacity: 0 })
|
|
260
|
+
editor.exec('addAnimationKeyframe', 1, { left: 300, opacity: 1 })
|
|
261
|
+
const lottie = editor.exec('exportLottie')
|
|
262
|
+
|
|
263
|
+
// AI canvas actions (validated, applied in one undo step) — needs @mce/ai
|
|
264
|
+
editor.exec('applyAiActions', [
|
|
265
|
+
{ type: 'createText', text: 'Hello', x: 40, y: 40 },
|
|
266
|
+
{ type: 'align', direction: 'left' },
|
|
267
|
+
])
|
|
268
|
+
```
|
|
269
|
+
|
|
270
|
+
## 🤝 Collaboration
|
|
271
|
+
|
|
272
|
+
The CRDT document model (Yjs) lives in the **core** — undo / redo and offline
|
|
273
|
+
persistence (IndexedDB) build on it. The **network transport and presence**
|
|
274
|
+
(awareness) layer is the optional `@mce/collaboration` package.
|
|
275
|
+
|
|
276
|
+
**1. Register the plugin**
|
|
277
|
+
|
|
278
|
+
```ts
|
|
279
|
+
import collaboration from '@mce/collaboration'
|
|
280
|
+
|
|
281
|
+
const editor = new Editor({
|
|
282
|
+
plugins: [
|
|
283
|
+
collaboration(), // registers the collaboration + presence plugins
|
|
284
|
+
],
|
|
285
|
+
})
|
|
286
|
+
```
|
|
287
|
+
|
|
288
|
+
**2. Identify the local user (presence)**
|
|
289
|
+
|
|
290
|
+
```ts
|
|
291
|
+
editor.presence.setUser({
|
|
292
|
+
id: 'u-1', // optional, for dedupe / avatars
|
|
293
|
+
name: 'Alice',
|
|
294
|
+
color: '#E64980',
|
|
295
|
+
avatar: 'https://…', // optional
|
|
296
|
+
})
|
|
297
|
+
```
|
|
298
|
+
|
|
299
|
+
**3. Connect to a room**
|
|
300
|
+
|
|
301
|
+
```ts
|
|
302
|
+
// Built-in WebSocket transport (y-websocket compatible server)
|
|
303
|
+
editor.collaboration.connect({
|
|
304
|
+
url: 'wss://your-server',
|
|
305
|
+
room: 'doc-1', // defaults to the current document id
|
|
306
|
+
})
|
|
307
|
+
|
|
308
|
+
// …or a custom / pluggable transport (WebRTC, BroadcastChannel, …)
|
|
309
|
+
import { AbstractProvider } from '@mce/collaboration'
|
|
310
|
+
editor.collaboration.connect({
|
|
311
|
+
provider: doc => new MyProvider(doc), // doc is the document's YDoc
|
|
312
|
+
})
|
|
313
|
+
|
|
314
|
+
editor.collaboration.disconnect() // end the session
|
|
315
|
+
```
|
|
316
|
+
|
|
317
|
+
You can also auto-connect on startup via the editor option:
|
|
318
|
+
|
|
319
|
+
```ts
|
|
320
|
+
new Editor({ collaboration: { url: 'wss://your-server', room: 'doc-1' } })
|
|
321
|
+
```
|
|
322
|
+
|
|
323
|
+
**4. Reactive status & remote peers**
|
|
324
|
+
|
|
325
|
+
```ts
|
|
326
|
+
editor.collaboration.connected // Ref<boolean> — transport connected
|
|
327
|
+
editor.collaboration.synced // Ref<boolean> — first full sync done
|
|
328
|
+
editor.collaboration.active // Ref<boolean> — a session is active
|
|
329
|
+
editor.presence.peers // Ref<Peer[]> — remote users (cursor / selection / user)
|
|
330
|
+
editor.presence.localUser // Ref<PresenceUser>
|
|
331
|
+
```
|
|
332
|
+
|
|
333
|
+
Remote cursors, selection boxes and a connection/avatars status-bar item render
|
|
334
|
+
automatically once a session is active. Document switching rebuilds the provider
|
|
335
|
+
on the new document's `YDoc`; the transport is bound per-document.
|
|
336
|
+
|
|
337
|
+
> Comments (`@mce/comments`) live on `element.comments` and are part of the
|
|
338
|
+
> document model, so they sync over the same session automatically.
|
|
339
|
+
|
|
340
|
+
## 🏗️ Architecture
|
|
341
|
+
|
|
342
|
+
```
|
|
343
|
+
packages/
|
|
344
|
+
mce/ # core editor library (npm: mce)
|
|
345
|
+
gif/ # GIF export (@mce/gif)
|
|
346
|
+
mp4/ # MP4 export (@mce/mp4)
|
|
347
|
+
pdf/ # PDF export (@mce/pdf)
|
|
348
|
+
svg/ # SVG export (@mce/svg)
|
|
349
|
+
openxml/ # PPTX/XLSX/DOCX import & export (@mce/openxml)
|
|
350
|
+
psd/ # PSD import (@mce/psd)
|
|
351
|
+
html/ # HTML import (@mce/html)
|
|
352
|
+
table/ # table element + editor (@mce/table)
|
|
353
|
+
chart/ # chart elements (@mce/chart)
|
|
354
|
+
ai/ # AI canvas actions (@mce/ai)
|
|
355
|
+
workflow/ # node-graph mode (@mce/workflow)
|
|
356
|
+
collaboration/ # real-time collaboration (@mce/collaboration)
|
|
357
|
+
comments/ # comments (@mce/comments)
|
|
358
|
+
playground/ # demo & test app
|
|
359
|
+
```
|
|
360
|
+
|
|
361
|
+
The `Editor` is composed from layered mixins and a plugin system. Rendering is powered by
|
|
362
|
+
[`modern-canvas`](https://www.npmjs.com/package/modern-canvas) (WebGL), with text / fonts /
|
|
363
|
+
document model from `modern-text`, `modern-font` and `modern-idoc`.
|
|
364
|
+
|
|
365
|
+
The core stays lean: element types and editing modes are decoupled through extension points
|
|
366
|
+
(`mixins/extensions.ts`), so feature packages register their behavior instead of the core
|
|
367
|
+
hard-coding it. The CRDT document model (`yjs` + `y-protocols`) lives in the core; the
|
|
368
|
+
real-time transport and presence layer is the optional `@mce/collaboration` package.
|
|
369
|
+
|
|
370
|
+
## 🛠️ Development
|
|
371
|
+
|
|
372
|
+
```shell
|
|
373
|
+
pnpm dev # start the playground
|
|
374
|
+
pnpm build # build core + all plugins
|
|
375
|
+
pnpm test # run tests
|
|
376
|
+
pnpm -F mce typecheck
|
|
377
|
+
pnpm lint
|
|
378
|
+
```
|
|
379
|
+
|
|
380
|
+
## 📄 License
|
|
381
|
+
|
|
382
|
+
[MIT](./LICENSE)
|
|
@@ -0,0 +1,6 @@
|
|
|
1
|
+
type __VLS_Props = {
|
|
2
|
+
slots: Record<string, any>;
|
|
3
|
+
};
|
|
4
|
+
declare const __VLS_export: import("vue").DefineComponent<__VLS_Props, {}, {}, {}, {}, import("vue").ComponentOptionsMixin, import("vue").ComponentOptionsMixin, {}, string, import("vue").PublicProps, Readonly<__VLS_Props> & Readonly<{}>, {}, {}, {}, {}, string, import("vue").ComponentProvideOptions, false, {}, any>;
|
|
5
|
+
declare const _default: typeof __VLS_export;
|
|
6
|
+
export default _default;
|
|
@@ -0,0 +1,3 @@
|
|
|
1
|
+
declare const __VLS_export: import("vue").DefineComponent<{}, {}, {}, {}, {}, import("vue").ComponentOptionsMixin, import("vue").ComponentOptionsMixin, {}, string, import("vue").PublicProps, Readonly<{}> & Readonly<{}>, {}, {}, {}, {}, string, import("vue").ComponentProvideOptions, true, {}, any>;
|
|
2
|
+
declare const _default: typeof __VLS_export;
|
|
3
|
+
export default _default;
|
|
@@ -1,6 +1,10 @@
|
|
|
1
1
|
import type { ImageFillCropRect } from 'modern-idoc';
|
|
2
2
|
/**
|
|
3
|
-
*
|
|
3
|
+
* 撤回 / 重做修复说明:
|
|
4
|
+
* 下方 `viewEffect` watch 在 `view` 变化时反向补偿 `cropRect` 以保持 source 视觉不变。
|
|
5
|
+
* 但撤回/重做会由 UndoManager 同时回退 `view` 与 `cropRect`,此时不应再据旧 `view` 重算
|
|
6
|
+
* `cropRect`(会把已回退的 `cropRect` 覆盖掉)。因此 viewEffect 在 `editor.isUndoRedoing`
|
|
7
|
+
* 期间跳过补偿,仅对用户拖拽 / 改宽高比产生的 view 变化补偿。
|
|
4
8
|
*/
|
|
5
9
|
type View = Record<'left' | 'top' | 'width' | 'height' | 'scaleX' | 'scaleY', number>;
|
|
6
10
|
type __VLS_Props = {
|
|
@@ -1,65 +1,60 @@
|
|
|
1
|
-
declare
|
|
2
|
-
declare var __VLS_10: {
|
|
1
|
+
declare var __VLS_1: {
|
|
3
2
|
props: {
|
|
4
|
-
|
|
3
|
+
onClick: () => boolean;
|
|
5
4
|
};
|
|
6
5
|
isActive: boolean;
|
|
7
|
-
},
|
|
6
|
+
}, __VLS_15: {};
|
|
8
7
|
type __VLS_Slots = {} & {
|
|
9
|
-
activator?: (props: typeof
|
|
8
|
+
activator?: (props: typeof __VLS_1) => any;
|
|
10
9
|
} & {
|
|
11
|
-
default?: (props: typeof
|
|
10
|
+
default?: (props: typeof __VLS_15) => any;
|
|
12
11
|
};
|
|
13
12
|
declare const __VLS_base: import("vue").DefineComponent<import("vue").ExtractPropTypes<{
|
|
14
|
-
|
|
15
|
-
|
|
16
|
-
|
|
17
|
-
|
|
18
|
-
default: () => string[];
|
|
13
|
+
/** 持久化:点击遮罩 / 按 Esc 不关闭。 */
|
|
14
|
+
persistent: {
|
|
15
|
+
type: BooleanConstructor;
|
|
16
|
+
default: boolean;
|
|
19
17
|
};
|
|
20
|
-
|
|
21
|
-
|
|
22
|
-
|
|
23
|
-
|
|
18
|
+
/** 对话框宽度(CSS 值),默认自适应内容。 */
|
|
19
|
+
width: {
|
|
20
|
+
type: StringConstructor;
|
|
21
|
+
default: undefined;
|
|
22
|
+
};
|
|
23
|
+
/** Teleport 目标。默认挂到编辑器 overlay 容器(继承风格变量),否则 body。 */
|
|
24
24
|
attach: {
|
|
25
|
-
type:
|
|
25
|
+
type: () => string | HTMLElement | false;
|
|
26
26
|
default: undefined;
|
|
27
27
|
};
|
|
28
|
-
contentClass: import("vue").PropType<any>;
|
|
29
|
-
contentStyle: import("vue").PropType<import("vue").CSSProperties>;
|
|
30
28
|
modelValue: {
|
|
31
29
|
type: import("vue").PropType<boolean>;
|
|
32
30
|
};
|
|
33
|
-
}>, {
|
|
34
|
-
|
|
35
|
-
updateLocation: typeof updateLocation;
|
|
36
|
-
}, {}, {}, {}, import("vue").ComponentOptionsMixin, import("vue").ComponentOptionsMixin, {
|
|
37
|
-
"update:modelValue": (value: boolean | undefined) => any;
|
|
31
|
+
}>, {}, {}, {}, {}, import("vue").ComponentOptionsMixin, import("vue").ComponentOptionsMixin, {
|
|
32
|
+
"update:modelValue": (value: boolean) => any;
|
|
38
33
|
}, string, import("vue").PublicProps, Readonly<import("vue").ExtractPropTypes<{
|
|
39
|
-
|
|
40
|
-
|
|
41
|
-
|
|
42
|
-
|
|
43
|
-
|
|
34
|
+
/** 持久化:点击遮罩 / 按 Esc 不关闭。 */
|
|
35
|
+
persistent: {
|
|
36
|
+
type: BooleanConstructor;
|
|
37
|
+
default: boolean;
|
|
38
|
+
};
|
|
39
|
+
/** 对话框宽度(CSS 值),默认自适应内容。 */
|
|
40
|
+
width: {
|
|
41
|
+
type: StringConstructor;
|
|
42
|
+
default: undefined;
|
|
44
43
|
};
|
|
45
|
-
|
|
46
|
-
x: number;
|
|
47
|
-
y: number;
|
|
48
|
-
} | import("@floating-ui/vue").ReferenceElement>;
|
|
44
|
+
/** Teleport 目标。默认挂到编辑器 overlay 容器(继承风格变量),否则 body。 */
|
|
49
45
|
attach: {
|
|
50
|
-
type:
|
|
46
|
+
type: () => string | HTMLElement | false;
|
|
51
47
|
default: undefined;
|
|
52
48
|
};
|
|
53
|
-
contentClass: import("vue").PropType<any>;
|
|
54
|
-
contentStyle: import("vue").PropType<import("vue").CSSProperties>;
|
|
55
49
|
modelValue: {
|
|
56
50
|
type: import("vue").PropType<boolean>;
|
|
57
51
|
};
|
|
58
52
|
}>> & Readonly<{
|
|
59
|
-
"onUpdate:modelValue"?: ((value: boolean
|
|
53
|
+
"onUpdate:modelValue"?: ((value: boolean) => any) | undefined;
|
|
60
54
|
}>, {
|
|
61
|
-
|
|
62
|
-
|
|
55
|
+
width: string;
|
|
56
|
+
attach: string | false | HTMLElement;
|
|
57
|
+
persistent: boolean;
|
|
63
58
|
}, {}, {}, {}, string, import("vue").ComponentProvideOptions, true, {}, any>;
|
|
64
59
|
declare const __VLS_export: __VLS_WithSlots<typeof __VLS_base, __VLS_Slots>;
|
|
65
60
|
declare const _default: typeof __VLS_export;
|
|
@@ -1,5 +1,7 @@
|
|
|
1
1
|
import type { OrientedBoundingBox } from '../../types';
|
|
2
2
|
type __VLS_Props = {
|
|
3
|
+
/** 面板唯一标识,接入面板状态源(层叠 / 位置记忆)。 */
|
|
4
|
+
name: string;
|
|
3
5
|
title?: string;
|
|
4
6
|
defaultTransform?: Partial<OrientedBoundingBox>;
|
|
5
7
|
};
|
|
@@ -7,11 +9,11 @@ type __VLS_ModelProps = {
|
|
|
7
9
|
modelValue?: boolean;
|
|
8
10
|
};
|
|
9
11
|
type __VLS_PublicProps = __VLS_Props & __VLS_ModelProps;
|
|
10
|
-
declare var
|
|
12
|
+
declare var __VLS_10: {
|
|
11
13
|
isActive: import("vue").ModelRef<boolean | undefined, string, boolean | undefined, boolean | undefined>;
|
|
12
14
|
};
|
|
13
15
|
type __VLS_Slots = {} & {
|
|
14
|
-
default?: (props: typeof
|
|
16
|
+
default?: (props: typeof __VLS_10) => any;
|
|
15
17
|
};
|
|
16
18
|
declare const __VLS_base: import("vue").DefineComponent<__VLS_PublicProps, {}, {}, {}, {}, import("vue").ComponentOptionsMixin, import("vue").ComponentOptionsMixin, {
|
|
17
19
|
"update:modelValue": (value: boolean | undefined) => any;
|
|
@@ -28,6 +28,19 @@ declare const __VLS_base: import("vue").DefineComponent<import("vue").ExtractPro
|
|
|
28
28
|
type: BooleanConstructor;
|
|
29
29
|
default: boolean;
|
|
30
30
|
};
|
|
31
|
+
/** 是否允许拖拽分隔条调整尺寸(细条类面板如 statusbar 关闭)。 */
|
|
32
|
+
resizable: {
|
|
33
|
+
type: BooleanConstructor;
|
|
34
|
+
default: boolean;
|
|
35
|
+
};
|
|
36
|
+
minSize: {
|
|
37
|
+
type: NumberConstructor;
|
|
38
|
+
default: number;
|
|
39
|
+
};
|
|
40
|
+
maxSize: {
|
|
41
|
+
type: NumberConstructor;
|
|
42
|
+
default: undefined;
|
|
43
|
+
};
|
|
31
44
|
}>, {}, {}, {}, {}, import("vue").ComponentOptionsMixin, import("vue").ComponentOptionsMixin, {}, string, import("vue").PublicProps, Readonly<import("vue").ExtractPropTypes<{
|
|
32
45
|
name: {
|
|
33
46
|
type: StringConstructor;
|
|
@@ -53,9 +66,25 @@ declare const __VLS_base: import("vue").DefineComponent<import("vue").ExtractPro
|
|
|
53
66
|
type: BooleanConstructor;
|
|
54
67
|
default: boolean;
|
|
55
68
|
};
|
|
69
|
+
/** 是否允许拖拽分隔条调整尺寸(细条类面板如 statusbar 关闭)。 */
|
|
70
|
+
resizable: {
|
|
71
|
+
type: BooleanConstructor;
|
|
72
|
+
default: boolean;
|
|
73
|
+
};
|
|
74
|
+
minSize: {
|
|
75
|
+
type: NumberConstructor;
|
|
76
|
+
default: number;
|
|
77
|
+
};
|
|
78
|
+
maxSize: {
|
|
79
|
+
type: NumberConstructor;
|
|
80
|
+
default: undefined;
|
|
81
|
+
};
|
|
56
82
|
}>> & Readonly<{}>, {
|
|
57
83
|
size: string | number;
|
|
58
84
|
style: string | Record<string, any> | unknown[];
|
|
85
|
+
resizable: boolean;
|
|
86
|
+
minSize: number;
|
|
87
|
+
maxSize: number;
|
|
59
88
|
order: string | number;
|
|
60
89
|
modelValue: boolean;
|
|
61
90
|
}, {}, {}, {}, string, import("vue").ComponentProvideOptions, true, {}, any>;
|
|
@@ -0,0 +1,29 @@
|
|
|
1
|
+
type __VLS_Props = {
|
|
2
|
+
title?: string;
|
|
3
|
+
/** 是否显示关闭按钮(点击触发 close)。 */
|
|
4
|
+
closable?: boolean;
|
|
5
|
+
/** 内容区是否加统一内边距(默认不加,由各面板自管)。 */
|
|
6
|
+
padded?: boolean;
|
|
7
|
+
};
|
|
8
|
+
declare var __VLS_15: {};
|
|
9
|
+
type __VLS_Slots = {} & {
|
|
10
|
+
default?: (props: typeof __VLS_15) => any;
|
|
11
|
+
};
|
|
12
|
+
declare const __VLS_base: import("vue").DefineComponent<__VLS_Props, {}, {}, {}, {}, import("vue").ComponentOptionsMixin, import("vue").ComponentOptionsMixin, {
|
|
13
|
+
close: () => any;
|
|
14
|
+
headerPointerdown: (event: PointerEvent) => any;
|
|
15
|
+
}, string, import("vue").PublicProps, Readonly<__VLS_Props> & Readonly<{
|
|
16
|
+
onClose?: (() => any) | undefined;
|
|
17
|
+
onHeaderPointerdown?: ((event: PointerEvent) => any) | undefined;
|
|
18
|
+
}>, {
|
|
19
|
+
closable: boolean;
|
|
20
|
+
padded: boolean;
|
|
21
|
+
}, {}, {}, {}, string, import("vue").ComponentProvideOptions, false, {}, any>;
|
|
22
|
+
declare const __VLS_export: __VLS_WithSlots<typeof __VLS_base, __VLS_Slots>;
|
|
23
|
+
declare const _default: typeof __VLS_export;
|
|
24
|
+
export default _default;
|
|
25
|
+
type __VLS_WithSlots<T, S> = T & {
|
|
26
|
+
new (): {
|
|
27
|
+
$slots: S;
|
|
28
|
+
};
|
|
29
|
+
};
|
|
@@ -0,0 +1,11 @@
|
|
|
1
|
+
import type { EasingCoords } from '../../utils';
|
|
2
|
+
type __VLS_Props = {
|
|
3
|
+
modelValue: EasingCoords;
|
|
4
|
+
};
|
|
5
|
+
declare const __VLS_export: import("vue").DefineComponent<__VLS_Props, {}, {}, {}, {}, import("vue").ComponentOptionsMixin, import("vue").ComponentOptionsMixin, {
|
|
6
|
+
"update:modelValue": (coords: EasingCoords) => any;
|
|
7
|
+
}, string, import("vue").PublicProps, Readonly<__VLS_Props> & Readonly<{
|
|
8
|
+
"onUpdate:modelValue"?: ((coords: EasingCoords) => any) | undefined;
|
|
9
|
+
}>, {}, {}, {}, {}, string, import("vue").ComponentProvideOptions, false, {}, any>;
|
|
10
|
+
declare const _default: typeof __VLS_export;
|
|
11
|
+
export default _default;
|
|
@@ -0,0 +1,3 @@
|
|
|
1
|
+
declare const __VLS_export: import("vue").DefineComponent<{}, {}, {}, {}, {}, import("vue").ComponentOptionsMixin, import("vue").ComponentOptionsMixin, {}, string, import("vue").PublicProps, Readonly<{}> & Readonly<{}>, {}, {}, {}, {}, string, import("vue").ComponentProvideOptions, true, {}, any>;
|
|
2
|
+
declare const _default: typeof __VLS_export;
|
|
3
|
+
export default _default;
|
package/dist/crdt/YDoc.d.ts
CHANGED
|
@@ -1,12 +1,22 @@
|
|
|
1
1
|
import type { CoreObject } from 'modern-canvas';
|
|
2
2
|
import type { ObservableEvents } from 'modern-idoc';
|
|
3
3
|
import type { Transaction } from 'yjs';
|
|
4
|
+
import type { Reactivity } from './reactivity';
|
|
4
5
|
import { Node } from 'modern-canvas';
|
|
5
6
|
import { Observable } from 'modern-idoc';
|
|
6
7
|
import * as Y from 'yjs';
|
|
7
8
|
import { IndexeddbProvider } from './providers';
|
|
9
|
+
/**
|
|
10
|
+
* 本地编辑产生的事务来源:进入 UndoManager,并向远端广播。
|
|
11
|
+
*/
|
|
12
|
+
export declare const LOCAL_ORIGIN: unique symbol;
|
|
13
|
+
/**
|
|
14
|
+
* 内部回放(把远端 / 撤销变更应用到视图)产生的事务来源:不进入 UndoManager,
|
|
15
|
+
* observe 回调据此跳过回写,避免本地↔yjs 回环。
|
|
16
|
+
*/
|
|
17
|
+
export declare const INTERNAL_ORIGIN: unique symbol;
|
|
8
18
|
export type YNode = Y.Map<unknown> & {
|
|
9
|
-
get: ((prop: 'id') => string) & ((prop: 'name') => string) & ((prop: 'parentId') => string) & ((prop: 'style') => Y.Map<unknown>) & ((prop: 'background') => Y.Map<unknown>) & ((prop: 'shape') => Y.Map<unknown>) & ((prop: 'fill') => Y.Map<unknown>) & ((prop: 'outline') => Y.Map<unknown>) & ((prop: 'text') => Y.Map<unknown>) & ((prop: 'foreground') => Y.Map<unknown>) & ((prop: 'shadow') => Y.Map<unknown>) & ((prop: 'meta') => Y.Map<unknown>) & ((prop: 'childrenIds') => Y.Array<string>) & (<T = unknown>(prop: string) => T);
|
|
19
|
+
get: ((prop: 'id') => string) & ((prop: 'name') => string) & ((prop: 'parentId') => string) & ((prop: 'style') => Y.Map<unknown>) & ((prop: 'background') => Y.Map<unknown>) & ((prop: 'shape') => Y.Map<unknown>) & ((prop: 'fill') => Y.Map<unknown>) & ((prop: 'outline') => Y.Map<unknown>) & ((prop: 'text') => Y.Map<unknown>) & ((prop: 'foreground') => Y.Map<unknown>) & ((prop: 'shadow') => Y.Map<unknown>) & ((prop: 'comments') => Y.Map<unknown>) & ((prop: 'meta') => Y.Map<unknown>) & ((prop: 'childrenIds') => Y.Array<string>) & (<T = unknown>(prop: string) => T);
|
|
10
20
|
};
|
|
11
21
|
export interface YDocEvents extends ObservableEvents {
|
|
12
22
|
history: [arg0: Y.UndoManager];
|
|
@@ -26,9 +36,13 @@ export declare class YDoc extends Observable {
|
|
|
26
36
|
_yChildren: Y.Map<YNode>;
|
|
27
37
|
_yChildrenIds: Y.Array<string>;
|
|
28
38
|
_nodeMap: Map<string, Node>;
|
|
39
|
+
/** 远端子节点顺序变更先于节点创建到达时,挂起的 move 操作,按 childId 暂存。 */
|
|
40
|
+
_pendingInserts: Map<string, Set<() => void>>;
|
|
29
41
|
indexeddb?: IndexeddbProvider;
|
|
30
42
|
undoManager: Y.UndoManager;
|
|
31
|
-
|
|
43
|
+
/** 响应式适配器:解耦 Vue。运行时由上层注入 Vue 实现,测试 / headless 用 rawReactivity。 */
|
|
44
|
+
protected _rx: Reactivity;
|
|
45
|
+
constructor(id?: string, reactivity?: Reactivity);
|
|
32
46
|
protected _isSelfTransaction(transaction?: Y.Transaction): boolean;
|
|
33
47
|
protected _initUndoManager(typeScope?: any[]): void;
|
|
34
48
|
loadIndexeddb(): Promise<void>;
|
|
@@ -43,4 +57,15 @@ export declare class YDoc extends Observable {
|
|
|
43
57
|
protected _proxyChildren(node: Node, childrenIds: Y.Array<string>): void;
|
|
44
58
|
_proxyNode(node: Node, yNode?: YNode, yChildrenIds?: Y.Array<string>): Node;
|
|
45
59
|
protected _initYNode(yNode: YNode): Node;
|
|
60
|
+
/** 节点就绪后消费此前因节点缺失而挂起的 move 操作。 */
|
|
61
|
+
protected _flushPendingInserts(id: string): void;
|
|
62
|
+
/**
|
|
63
|
+
* 应用远端增量。origin 必须区别于 LOCAL/INTERNAL,使变更刷新到视图且不进入本端 undo 栈;
|
|
64
|
+
* 默认用 provider/调用方实例做 origin(这里用 this 兜底)。
|
|
65
|
+
*/
|
|
66
|
+
applyUpdate(update: Uint8Array, origin?: unknown): void;
|
|
67
|
+
/** 导出相对 targetStateVector 的差量(不传则全量),用于新端初始同步握手。 */
|
|
68
|
+
encodeStateAsUpdate(targetStateVector?: Uint8Array): Uint8Array;
|
|
69
|
+
/** 导出本端状态向量,与对端交换以计算差量。 */
|
|
70
|
+
encodeStateVector(): Uint8Array;
|
|
46
71
|
}
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
export {};
|
package/dist/crdt/index.d.ts
CHANGED
|
@@ -21,7 +21,9 @@ export declare class IndexeddbProvider extends Observable<IndexeddbProviderEvent
|
|
|
21
21
|
_storeTimeout: number;
|
|
22
22
|
_storeTimeoutId: any;
|
|
23
23
|
_storeUpdate: (update: Uint8Array, origin: any) => void;
|
|
24
|
-
|
|
24
|
+
/** 累积多少条增量后做一次全量快照压缩(compaction)。越小库越小但全量重写越频繁。 */
|
|
25
|
+
trimSize: number;
|
|
26
|
+
constructor(name: string, doc: Y.Doc, trimSize?: number);
|
|
25
27
|
destroy(): Promise<void>;
|
|
26
28
|
clearData(): Promise<void>;
|
|
27
29
|
get<T = any>(key: IDBValidKey): Promise<T>;
|
|
@@ -0,0 +1,27 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* 响应式适配器:把 CRDT 核心层(YDoc)与具体的响应式框架(Vue)解耦。
|
|
3
|
+
*
|
|
4
|
+
* 动机:原 `YDoc` 直接 `import { reactive, markRaw, isReactive } from 'vue'`,使数据层硬绑 Vue,
|
|
5
|
+
* 既无法在非 Vue / 纯 Node 环境下测试,也让「Yjs 数据」与「视图响应式」两个关注点纠缠在一起。
|
|
6
|
+
* 抽成接口后:
|
|
7
|
+
* - CRDT 层只依赖 {@link Reactivity} 接口,不 import vue;
|
|
8
|
+
* - 运行时由上层(scene/Doc)注入真实的 Vue 适配器 —— 行为与原来完全一致;
|
|
9
|
+
* - 测试 / headless 场景注入 {@link rawReactivity} —— 走纯数据路径,零响应式开销。
|
|
10
|
+
*/
|
|
11
|
+
export interface Reactivity {
|
|
12
|
+
/** 包装为响应式代理(Vue: reactive)。raw 模式下原样返回。 */
|
|
13
|
+
reactive: <T extends object>(target: T) => T;
|
|
14
|
+
/** 判断是否已是响应式代理。raw 模式下恒为 true,使「按需包装」逻辑跳过包装。 */
|
|
15
|
+
isReactive: (value: unknown) => boolean;
|
|
16
|
+
/** 标记对象不被响应式系统代理(Vue: markRaw)。raw 模式下原样返回。 */
|
|
17
|
+
markRaw: <T extends object>(value: T) => T;
|
|
18
|
+
/** 取回响应式代理背后的原始对象(Vue: toRaw)。raw 模式下原样返回。 */
|
|
19
|
+
toRaw: <T>(value: T) => T;
|
|
20
|
+
}
|
|
21
|
+
/**
|
|
22
|
+
* 无响应式实现:纯数据层,不做任何包装。
|
|
23
|
+
* - `isReactive` 恒 true,让 `if (!isReactive(node)) wrap(node)` 这类逻辑直接跳过;
|
|
24
|
+
* - 其余均为恒等函数。
|
|
25
|
+
* 用于单元测试与非 Vue 宿主环境。
|
|
26
|
+
*/
|
|
27
|
+
export declare const rawReactivity: Reactivity;
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
export {};
|
|
@@ -0,0 +1,8 @@
|
|
|
1
|
+
import type { Reactivity } from './reactivity';
|
|
2
|
+
/**
|
|
3
|
+
* Vue 响应式适配器:把 Vue 的 reactive/markRaw/isReactive/toRaw 适配为 {@link Reactivity} 接口。
|
|
4
|
+
*
|
|
5
|
+
* 这是「Vue 绑定」模块——唯一 import vue 的 CRDT 文件。核心 {@link YDoc} 不依赖它,
|
|
6
|
+
* 由上层(scene/Doc)显式注入,从而保持数据层框架无关、可在 headless 下测试。
|
|
7
|
+
*/
|
|
8
|
+
export declare const vueReactivity: Reactivity;
|