mce 0.11.2 → 0.11.3
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 +2 -1
- package/dist/index.js +130 -85
- package/dist/mixins/0.config/base.d.ts +0 -2
- package/dist/mixins/2.load.d.ts +1 -1
- package/dist/mixins/4.4.doc.d.ts +2 -2
- package/dist/plugins/clipboard.d.ts +2 -1
- package/dist/utils/helper.d.ts +1 -0
- package/package.json +1 -1
package/README.md
CHANGED
|
@@ -45,8 +45,8 @@ npm i mce
|
|
|
45
45
|
svg(),
|
|
46
46
|
],
|
|
47
47
|
theme: 'system',
|
|
48
|
-
language: 'en',
|
|
49
48
|
viewMode: 'edgeless',
|
|
49
|
+
clipboard: true,
|
|
50
50
|
checkerboard: true,
|
|
51
51
|
pixelGrid: true,
|
|
52
52
|
camera: true,
|
|
@@ -60,6 +60,7 @@ npm i mce
|
|
|
60
60
|
zoomToFitOffset: { left: 0, top: 0, right: 0, bottom: 0 },
|
|
61
61
|
localDb: false,
|
|
62
62
|
customUpload: async (blob) => URL.createObjectURL(blob),
|
|
63
|
+
customContextMenu: (menu) => menu,
|
|
63
64
|
defaultFont: { family: 'SourceHanSansCN-Normal', src: '/SourceHanSansCN-Normal.woff' },
|
|
64
65
|
doc: {
|
|
65
66
|
children: [
|
package/dist/index.js
CHANGED
|
@@ -1,4 +1,4 @@
|
|
|
1
|
-
import { ref, computed, watch, markRaw, reactive, warn, shallowRef, inject, provide, defineComponent, createVNode, mergeProps, createElementVNode, toValue, getCurrentInstance, onScopeDispose, createElementBlock, openBlock, Fragment, renderList, unref, normalizeStyle, normalizeClass,
|
|
1
|
+
import { ref, computed, watch, markRaw, reactive, warn, shallowRef, onBeforeUnmount, onMounted, inject, provide, defineComponent, createVNode, mergeProps, createElementVNode, toValue, getCurrentInstance, onScopeDispose, createElementBlock, openBlock, Fragment, renderList, unref, normalizeStyle, normalizeClass, readonly, toRef, useId, onDeactivated, onActivated, useAttrs, createBlock, resolveDynamicComponent, useTemplateRef, renderSlot, Teleport, createCommentVNode, mergeModels, useModel, resolveComponent, withCtx, createTextVNode, toDisplayString, createSlots, normalizeProps, guardReactiveProps, withDirectives, vShow, vModelText, nextTick, withModifiers, onBeforeMount, isRef } from "vue";
|
|
2
2
|
import { useFileDialog, useEventListener, isClient, useResizeObserver as useResizeObserver$1, useLocalStorage, onClickOutside, useMouse, useDebounceFn } from "@vueuse/core";
|
|
3
3
|
import { Node as Node$1, Element2D, Timeline, Engine, Camera2D, DrawboardEffect, IN_BROWSER, clamp, assets, TimelineNode, Transform2D, DEG_TO_RAD, render, Animation } from "modern-canvas";
|
|
4
4
|
import { getObjectValueByPath, setObjectValueByPath, Observable, Reactivable, idGenerator, property, normalizeElement, normalizeTextContent } from "modern-idoc";
|
|
@@ -110,7 +110,6 @@ const _0_config_base = defineMixin((editor, options) => {
|
|
|
110
110
|
config
|
|
111
111
|
} = editor;
|
|
112
112
|
registerConfig("theme", "system");
|
|
113
|
-
registerConfig("language", "en");
|
|
114
113
|
registerConfig("viewMode", "edgeless");
|
|
115
114
|
registerConfig("checkerboard", false);
|
|
116
115
|
registerConfig("pixelGrid", false);
|
|
@@ -1362,6 +1361,18 @@ function findChildrenWithProvide(key, vnode) {
|
|
|
1362
1361
|
}
|
|
1363
1362
|
return [];
|
|
1364
1363
|
}
|
|
1364
|
+
function isInputEvent(event) {
|
|
1365
|
+
if (!event)
|
|
1366
|
+
return false;
|
|
1367
|
+
let path = event.path;
|
|
1368
|
+
if (!path && event.composedPath)
|
|
1369
|
+
path = event.composedPath();
|
|
1370
|
+
if (!path)
|
|
1371
|
+
return false;
|
|
1372
|
+
return path?.some(
|
|
1373
|
+
(el) => ["INPUT", "TEXTAREA", "SELECT"].includes(el?.tagName) || el?.contentEditable === "true"
|
|
1374
|
+
);
|
|
1375
|
+
}
|
|
1365
1376
|
function propsFactory(props, source) {
|
|
1366
1377
|
return (defaults) => {
|
|
1367
1378
|
return Object.keys(props).reduce((obj, prop) => {
|
|
@@ -1391,18 +1402,6 @@ function uuidv4() {
|
|
|
1391
1402
|
const defaultHotkeys = [
|
|
1392
1403
|
{ command: "cancel", key: "Esc", editable: false }
|
|
1393
1404
|
];
|
|
1394
|
-
function isInputEvent(event) {
|
|
1395
|
-
if (!event)
|
|
1396
|
-
return false;
|
|
1397
|
-
let path = event.path;
|
|
1398
|
-
if (!path && event.composedPath)
|
|
1399
|
-
path = event.composedPath();
|
|
1400
|
-
if (!path)
|
|
1401
|
-
return false;
|
|
1402
|
-
return path?.some(
|
|
1403
|
-
(el) => ["INPUT", "TEXTAREA", "SELECT"].includes(el?.tagName) || el?.contentEditable === "true"
|
|
1404
|
-
);
|
|
1405
|
-
}
|
|
1406
1405
|
const _1_hotkey = defineMixin((editor) => {
|
|
1407
1406
|
const {
|
|
1408
1407
|
registerConfig
|
|
@@ -1962,15 +1961,15 @@ const _2_load = defineMixin((editor) => {
|
|
|
1962
1961
|
};
|
|
1963
1962
|
const load = async (source) => {
|
|
1964
1963
|
state.value = "loading";
|
|
1965
|
-
|
|
1964
|
+
const items = [];
|
|
1966
1965
|
try {
|
|
1967
1966
|
for (const loader of loaders.value.values()) {
|
|
1968
1967
|
if (await loader.test(source)) {
|
|
1969
1968
|
const res = await loader.load(source);
|
|
1970
1969
|
if (Array.isArray(res)) {
|
|
1971
|
-
|
|
1970
|
+
items.push(...res);
|
|
1972
1971
|
} else {
|
|
1973
|
-
|
|
1972
|
+
items.push(res);
|
|
1974
1973
|
}
|
|
1975
1974
|
break;
|
|
1976
1975
|
}
|
|
@@ -1978,10 +1977,10 @@ const _2_load = defineMixin((editor) => {
|
|
|
1978
1977
|
} finally {
|
|
1979
1978
|
state.value = void 0;
|
|
1980
1979
|
}
|
|
1981
|
-
if (!
|
|
1980
|
+
if (!items.length) {
|
|
1982
1981
|
throw new Error(`Failed to load source "${source}"`);
|
|
1983
1982
|
}
|
|
1984
|
-
return
|
|
1983
|
+
return items;
|
|
1985
1984
|
};
|
|
1986
1985
|
const openFileDialog = (options = {}) => {
|
|
1987
1986
|
const {
|
|
@@ -2549,7 +2548,11 @@ const _4_4_doc = defineMixin((editor, options) => {
|
|
|
2549
2548
|
}
|
|
2550
2549
|
}
|
|
2551
2550
|
if (source && typeof source !== "string") {
|
|
2552
|
-
|
|
2551
|
+
if (Array.isArray(source)) {
|
|
2552
|
+
doc2.set({ children: source });
|
|
2553
|
+
} else {
|
|
2554
|
+
doc2.set(source);
|
|
2555
|
+
}
|
|
2553
2556
|
}
|
|
2554
2557
|
});
|
|
2555
2558
|
doc2.on("update", throttle((update, origin) => emit("updateDoc", update, origin), 200));
|
|
@@ -2559,8 +2562,17 @@ const _4_4_doc = defineMixin((editor, options) => {
|
|
|
2559
2562
|
let id;
|
|
2560
2563
|
if (typeof source === "string") {
|
|
2561
2564
|
id = source;
|
|
2562
|
-
} else {
|
|
2563
|
-
|
|
2565
|
+
} else if (source) {
|
|
2566
|
+
if (Array.isArray(source) && source.length === 1) {
|
|
2567
|
+
source = source[0];
|
|
2568
|
+
}
|
|
2569
|
+
if (!Array.isArray(source)) {
|
|
2570
|
+
if (source.meta?.inEditorIs === "Doc") {
|
|
2571
|
+
id = source.id;
|
|
2572
|
+
} else {
|
|
2573
|
+
source = [source];
|
|
2574
|
+
}
|
|
2575
|
+
}
|
|
2564
2576
|
}
|
|
2565
2577
|
const _doc = new Doc(id);
|
|
2566
2578
|
state.value = "loading";
|
|
@@ -2576,11 +2588,7 @@ const _4_4_doc = defineMixin((editor, options) => {
|
|
|
2576
2588
|
return _doc;
|
|
2577
2589
|
};
|
|
2578
2590
|
const loadDoc = async (source) => {
|
|
2579
|
-
|
|
2580
|
-
if (loaded.meta?.inEditorIs !== "Doc") {
|
|
2581
|
-
loaded = { id: idGenerator(), children: [loaded] };
|
|
2582
|
-
}
|
|
2583
|
-
const _doc = await setDoc(loaded);
|
|
2591
|
+
const _doc = await setDoc(await load(source));
|
|
2584
2592
|
emit("loadDoc", _doc, source);
|
|
2585
2593
|
return _doc;
|
|
2586
2594
|
};
|
|
@@ -4054,7 +4062,12 @@ const _clipboard = definePlugin((editor, options) => {
|
|
|
4054
4062
|
const useClipboard = options.clipboard !== false && SUPPORTS_CLIPBOARD;
|
|
4055
4063
|
const copy = async (data) => {
|
|
4056
4064
|
if (data === void 0) {
|
|
4057
|
-
data = selection.value.
|
|
4065
|
+
data = selection.value.map((v) => {
|
|
4066
|
+
const json = v.toJSON();
|
|
4067
|
+
delete json.style.left;
|
|
4068
|
+
delete json.style.top;
|
|
4069
|
+
return json;
|
|
4070
|
+
});
|
|
4058
4071
|
}
|
|
4059
4072
|
if (useClipboard) {
|
|
4060
4073
|
if (Array.isArray(data)) {
|
|
@@ -4077,46 +4090,69 @@ const _clipboard = definePlugin((editor, options) => {
|
|
|
4077
4090
|
}
|
|
4078
4091
|
}
|
|
4079
4092
|
};
|
|
4080
|
-
async
|
|
4093
|
+
const cut = async () => {
|
|
4081
4094
|
await copy();
|
|
4082
4095
|
exec("delete");
|
|
4083
|
-
}
|
|
4084
|
-
let
|
|
4085
|
-
function
|
|
4086
|
-
if (!lock) {
|
|
4087
|
-
lock = true;
|
|
4088
|
-
}
|
|
4096
|
+
};
|
|
4097
|
+
let locked = false;
|
|
4098
|
+
function getPasteLock() {
|
|
4089
4099
|
return {
|
|
4090
|
-
|
|
4091
|
-
|
|
4100
|
+
locked,
|
|
4101
|
+
lock: () => locked = true,
|
|
4102
|
+
unlock: () => locked = false
|
|
4092
4103
|
};
|
|
4093
4104
|
}
|
|
4094
|
-
async function
|
|
4095
|
-
const items = source ?? await navigator.clipboard.read();
|
|
4105
|
+
async function _paste(items) {
|
|
4096
4106
|
const elements = [];
|
|
4097
4107
|
for (const item of items) {
|
|
4098
4108
|
for (const type of item.types) {
|
|
4099
4109
|
const blob = await item.getType(type);
|
|
4100
4110
|
if (await canLoad(blob)) {
|
|
4101
|
-
elements.push(await load(blob));
|
|
4111
|
+
elements.push(...await load(blob));
|
|
4102
4112
|
} else {
|
|
4103
4113
|
console.warn(`Unhandled clipboard ${blob.type}`, await blob.text());
|
|
4104
4114
|
}
|
|
4105
4115
|
}
|
|
4106
4116
|
}
|
|
4107
|
-
|
|
4108
|
-
|
|
4109
|
-
|
|
4110
|
-
|
|
4111
|
-
|
|
4117
|
+
if (elements.length) {
|
|
4118
|
+
addElement(elements, {
|
|
4119
|
+
inPointerPosition: true,
|
|
4120
|
+
active: true,
|
|
4121
|
+
regenId: true
|
|
4122
|
+
});
|
|
4123
|
+
}
|
|
4112
4124
|
}
|
|
4113
|
-
async
|
|
4114
|
-
|
|
4115
|
-
|
|
4116
|
-
|
|
4117
|
-
|
|
4125
|
+
const paste = async (source) => {
|
|
4126
|
+
if (source) {
|
|
4127
|
+
const { unlock, lock } = getPasteLock();
|
|
4128
|
+
lock();
|
|
4129
|
+
let items = [];
|
|
4130
|
+
if (source instanceof DataTransfer) {
|
|
4131
|
+
for (const item of source.items) {
|
|
4132
|
+
switch (item.kind) {
|
|
4133
|
+
case "file": {
|
|
4134
|
+
const file = item.getAsFile();
|
|
4135
|
+
if (file) {
|
|
4136
|
+
items.push(new ClipboardItem({ [file.type]: file }));
|
|
4137
|
+
}
|
|
4138
|
+
break;
|
|
4139
|
+
}
|
|
4140
|
+
}
|
|
4141
|
+
}
|
|
4142
|
+
} else {
|
|
4143
|
+
items = source;
|
|
4144
|
+
}
|
|
4145
|
+
if (items.length) {
|
|
4146
|
+
await _paste(items);
|
|
4147
|
+
} else {
|
|
4148
|
+
unlock();
|
|
4149
|
+
}
|
|
4150
|
+
} else {
|
|
4151
|
+
await new Promise((r) => setTimeout(r, 100));
|
|
4152
|
+
const { locked: locked2, unlock } = getPasteLock();
|
|
4153
|
+
if (!locked2) {
|
|
4118
4154
|
if (useClipboard) {
|
|
4119
|
-
await
|
|
4155
|
+
await _paste(await navigator.clipboard.read());
|
|
4120
4156
|
} else if (copiedData.value) {
|
|
4121
4157
|
if (Array.isArray(copiedData.value)) {
|
|
4122
4158
|
addElement(copiedData.value?.map((el) => cloneDeep(el)) ?? [], {
|
|
@@ -4126,13 +4162,11 @@ const _clipboard = definePlugin((editor, options) => {
|
|
|
4126
4162
|
});
|
|
4127
4163
|
}
|
|
4128
4164
|
}
|
|
4129
|
-
}
|
|
4165
|
+
} else {
|
|
4130
4166
|
unlock();
|
|
4131
4167
|
}
|
|
4132
|
-
} else {
|
|
4133
|
-
unlock();
|
|
4134
4168
|
}
|
|
4135
|
-
}
|
|
4169
|
+
};
|
|
4136
4170
|
async function duplicate() {
|
|
4137
4171
|
await copy();
|
|
4138
4172
|
await paste();
|
|
@@ -4156,31 +4190,16 @@ const _clipboard = definePlugin((editor, options) => {
|
|
|
4156
4190
|
],
|
|
4157
4191
|
setup: () => {
|
|
4158
4192
|
if (useClipboard) {
|
|
4159
|
-
|
|
4160
|
-
|
|
4161
|
-
|
|
4162
|
-
pasteLock();
|
|
4163
|
-
const clipboardItems = [];
|
|
4164
|
-
for (const item of items) {
|
|
4165
|
-
switch (item.kind) {
|
|
4166
|
-
case "file": {
|
|
4167
|
-
const file = item.getAsFile();
|
|
4168
|
-
if (file) {
|
|
4169
|
-
clipboardItems.push(
|
|
4170
|
-
new ClipboardItem({
|
|
4171
|
-
[file.type]: file
|
|
4172
|
-
})
|
|
4173
|
-
);
|
|
4174
|
-
}
|
|
4175
|
-
break;
|
|
4176
|
-
}
|
|
4177
|
-
}
|
|
4178
|
-
}
|
|
4179
|
-
await onPaste(
|
|
4180
|
-
clipboardItems.length ? clipboardItems : void 0
|
|
4181
|
-
);
|
|
4193
|
+
async function onPaste(e) {
|
|
4194
|
+
if (isInputEvent(e)) {
|
|
4195
|
+
return;
|
|
4182
4196
|
}
|
|
4183
|
-
|
|
4197
|
+
if (e.clipboardData) {
|
|
4198
|
+
await paste(e.clipboardData);
|
|
4199
|
+
}
|
|
4200
|
+
}
|
|
4201
|
+
window.addEventListener("paste", onPaste);
|
|
4202
|
+
onBeforeUnmount(() => window.removeEventListener("paste", onPaste));
|
|
4184
4203
|
}
|
|
4185
4204
|
}
|
|
4186
4205
|
};
|
|
@@ -4609,7 +4628,7 @@ const _import = definePlugin((editor) => {
|
|
|
4609
4628
|
} = editor;
|
|
4610
4629
|
const _import2 = async (options = {}) => {
|
|
4611
4630
|
const files = await openFileDialog({ multiple: true });
|
|
4612
|
-
return addElement(await Promise.all(files.map((file) => load(file))), {
|
|
4631
|
+
return addElement((await Promise.all(files.map((file) => load(file)))).flat(), {
|
|
4613
4632
|
...options,
|
|
4614
4633
|
sizeToFit: true,
|
|
4615
4634
|
positionToFit: true
|
|
@@ -4622,7 +4641,35 @@ const _import = definePlugin((editor) => {
|
|
|
4622
4641
|
],
|
|
4623
4642
|
hotkeys: [
|
|
4624
4643
|
{ command: "import", key: "CmdOrCtrl+i" }
|
|
4625
|
-
]
|
|
4644
|
+
],
|
|
4645
|
+
setup: () => {
|
|
4646
|
+
const {
|
|
4647
|
+
drawboardPointer,
|
|
4648
|
+
drawboardDom,
|
|
4649
|
+
exec
|
|
4650
|
+
} = editor;
|
|
4651
|
+
function onDragover(e) {
|
|
4652
|
+
e.preventDefault();
|
|
4653
|
+
drawboardPointer.value = { x: e.clientX, y: e.clientY };
|
|
4654
|
+
if (e.dataTransfer) {
|
|
4655
|
+
e.dataTransfer.dropEffect = "copy";
|
|
4656
|
+
}
|
|
4657
|
+
}
|
|
4658
|
+
async function onDrop(e) {
|
|
4659
|
+
e.preventDefault();
|
|
4660
|
+
if (e.dataTransfer) {
|
|
4661
|
+
await exec("paste", e.dataTransfer);
|
|
4662
|
+
}
|
|
4663
|
+
}
|
|
4664
|
+
onMounted(() => {
|
|
4665
|
+
drawboardDom.value?.addEventListener("dragover", onDragover);
|
|
4666
|
+
drawboardDom.value?.addEventListener("drop", onDrop);
|
|
4667
|
+
});
|
|
4668
|
+
onBeforeUnmount(() => {
|
|
4669
|
+
drawboardDom.value?.removeEventListener("dragover", onDragover);
|
|
4670
|
+
drawboardDom.value?.removeEventListener("drop", onDrop);
|
|
4671
|
+
});
|
|
4672
|
+
}
|
|
4626
4673
|
};
|
|
4627
4674
|
});
|
|
4628
4675
|
const _layerOrder = definePlugin((editor) => {
|
|
@@ -4988,10 +5035,7 @@ const _new = definePlugin((editor) => {
|
|
|
4988
5035
|
setDoc
|
|
4989
5036
|
} = editor;
|
|
4990
5037
|
function _new2() {
|
|
4991
|
-
setDoc(
|
|
4992
|
-
id: idGenerator(),
|
|
4993
|
-
children: []
|
|
4994
|
-
});
|
|
5038
|
+
setDoc([]);
|
|
4995
5039
|
}
|
|
4996
5040
|
return {
|
|
4997
5041
|
name: "mce:new",
|
|
@@ -8872,6 +8916,7 @@ export {
|
|
|
8872
8916
|
imageExts,
|
|
8873
8917
|
imageMimeTypeExtMap,
|
|
8874
8918
|
isClickInsideElement,
|
|
8919
|
+
isInputEvent,
|
|
8875
8920
|
isMac,
|
|
8876
8921
|
isOverlappingAabb,
|
|
8877
8922
|
isOverlappingObb,
|
|
@@ -3,13 +3,11 @@ declare global {
|
|
|
3
3
|
interface Options extends Partial<Config> {
|
|
4
4
|
}
|
|
5
5
|
type Theme = 'system' | 'light' | 'dark';
|
|
6
|
-
type Language = string;
|
|
7
6
|
type ViewMode = 'frame' | 'edgeless';
|
|
8
7
|
type TypographyStrategy = 'autoHeight' | 'autoWidth' | 'fixedWidthHeight' | 'autoFontSize';
|
|
9
8
|
type HandleShape = 'rect' | 'circle';
|
|
10
9
|
interface Config {
|
|
11
10
|
theme: Theme;
|
|
12
|
-
language: Language;
|
|
13
11
|
viewMode: ViewMode;
|
|
14
12
|
checkerboard: boolean;
|
|
15
13
|
pixelGrid: boolean;
|
package/dist/mixins/2.load.d.ts
CHANGED
|
@@ -13,7 +13,7 @@ declare global {
|
|
|
13
13
|
registerLoader: (value: Loader | Loader[]) => void;
|
|
14
14
|
unregisterLoader: (name: string) => void;
|
|
15
15
|
canLoad: (source: any) => Promise<boolean>;
|
|
16
|
-
load: <T = NormalizedElement>(source: any) => Promise<T>;
|
|
16
|
+
load: <T = NormalizedElement>(source: any) => Promise<T[]>;
|
|
17
17
|
openFileDialog: (options?: {
|
|
18
18
|
multiple?: boolean;
|
|
19
19
|
}) => Promise<File[]>;
|
package/dist/mixins/4.4.doc.d.ts
CHANGED
|
@@ -1,10 +1,10 @@
|
|
|
1
|
-
import type { Document } from 'modern-idoc';
|
|
1
|
+
import type { Document, Element } from 'modern-idoc';
|
|
2
2
|
import { Doc } from '../models';
|
|
3
3
|
declare global {
|
|
4
4
|
namespace Mce {
|
|
5
5
|
interface Editor {
|
|
6
6
|
getDoc: () => JsonData;
|
|
7
|
-
setDoc: (doc: Document | string) => Promise<Doc>;
|
|
7
|
+
setDoc: (doc: Document | Element[] | string) => Promise<Doc>;
|
|
8
8
|
loadDoc: (source: any) => Promise<Doc>;
|
|
9
9
|
clearDoc: () => void;
|
|
10
10
|
}
|
|
@@ -7,10 +7,11 @@ declare global {
|
|
|
7
7
|
paste: [event: KeyboardEvent];
|
|
8
8
|
duplicate: [event: KeyboardEvent];
|
|
9
9
|
}
|
|
10
|
+
type PasteSource = DataTransfer | ClipboardItem[];
|
|
10
11
|
interface Commands {
|
|
11
12
|
copy: (data?: any) => Promise<void>;
|
|
12
13
|
cut: () => Promise<void>;
|
|
13
|
-
paste: () => Promise<void>;
|
|
14
|
+
paste: (source?: PasteSource) => Promise<void>;
|
|
14
15
|
duplicate: () => Promise<void>;
|
|
15
16
|
}
|
|
16
17
|
interface Editor {
|
package/dist/utils/helper.d.ts
CHANGED
|
@@ -10,3 +10,4 @@ export declare function convertToUnit(str: number, unit?: string): string;
|
|
|
10
10
|
export declare function convertToUnit(str: string | number | null | undefined, unit?: string): string | undefined;
|
|
11
11
|
export declare function templateRef(): TemplateRef;
|
|
12
12
|
export declare function findChildrenWithProvide(key: InjectionKey<any> | symbol, vnode?: VNodeChild): ComponentInternalInstance[];
|
|
13
|
+
export declare function isInputEvent(event?: Event): boolean;
|