mce 0.15.38 → 0.15.39

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 CHANGED
@@ -1,4 +1,4 @@
1
- <h1 align="center">mce</h1>
1
+ <h1 align="center">ModernCanvasEditor</h1>
2
2
 
3
3
  <p align="center">
4
4
  <a href="https://unpkg.com/mce">
@@ -18,7 +18,7 @@
18
18
  </a>
19
19
  </p>
20
20
 
21
- <p align="center">The headless canvas editor framework. only the ESM.</p>
21
+ <p align="center">A headless infinite canvas editor framework built on WebGL rendering, supports exporting to image, video, and PPT. Only the ESM.</p>
22
22
 
23
23
  ## 📦 Install
24
24
 
@@ -1,3 +1,18 @@
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>;
1
+ declare var __VLS_11: {
2
+ scale: number;
3
+ ok: () => void;
4
+ cancel: () => void;
5
+ setAspectRatio: (ratio: 0 | [number, number]) => void;
6
+ };
7
+ type __VLS_Slots = {} & {
8
+ default?: (props: typeof __VLS_11) => any;
9
+ };
10
+ declare const __VLS_base: import("vue").DefineComponent<{}, {}, {}, {}, {}, import("vue").ComponentOptionsMixin, import("vue").ComponentOptionsMixin, {}, string, import("vue").PublicProps, Readonly<{}> & Readonly<{}>, {}, {}, {}, {}, string, import("vue").ComponentProvideOptions, true, {}, any>;
11
+ declare const __VLS_export: __VLS_WithSlots<typeof __VLS_base, __VLS_Slots>;
2
12
  declare const _default: typeof __VLS_export;
3
13
  export default _default;
14
+ type __VLS_WithSlots<T, S> = T & {
15
+ new (): {
16
+ $slots: S;
17
+ };
18
+ };
@@ -1,9 +1,16 @@
1
1
  import type { TransformValue } from './shared/TransformControls.vue';
2
- declare var __VLS_14: {}, __VLS_21: {};
2
+ declare var __VLS_8: {
3
+ scale: number;
4
+ ok: () => void;
5
+ cancel: () => void;
6
+ setAspectRatio: (ratio: 0 | [number, number]) => void;
7
+ }, __VLS_10: {}, __VLS_25: {};
3
8
  type __VLS_Slots = {} & {
4
- transform?: (props: typeof __VLS_14) => any;
9
+ 'foreground-cropper'?: (props: typeof __VLS_8) => any;
5
10
  } & {
6
- default?: (props: typeof __VLS_21) => any;
11
+ default?: (props: typeof __VLS_10) => any;
12
+ } & {
13
+ transform?: (props: typeof __VLS_25) => any;
7
14
  };
8
15
  declare const __VLS_base: import("vue").DefineComponent<{}, {
9
16
  transformControls: Readonly<import("vue").ShallowRef<({
@@ -21,7 +28,7 @@ declare const __VLS_base: import("vue").DefineComponent<{}, {
21
28
  readonly resizeStrategy?: "lockAspectRatio" | "lockAspectRatioDiagonal" | undefined;
22
29
  readonly handleStrategy?: "point" | undefined;
23
30
  readonly handleShape?: "rect" | "circle" | undefined;
24
- readonly handles?: ("move" | "resize-t" | "resize-r" | "resize-b" | "resize-l" | "resize-br" | "resize-tr" | "resize-tl" | "resize-bl" | "rotate-br" | "rotate-tr" | "rotate-tl" | "rotate-bl" | "round-br" | "round-tr" | "round-tl" | "round-bl")[] | undefined;
31
+ readonly handles?: ("move" | "resize-t" | "resize-b" | "resize-r" | "resize-l" | "resize-br" | "resize-tr" | "resize-tl" | "resize-bl" | "rotate-br" | "rotate-tr" | "rotate-tl" | "rotate-bl" | "round-br" | "round-tr" | "round-tl" | "round-bl")[] | undefined;
25
32
  readonly scale?: [number, number] | undefined;
26
33
  readonly offset?: [number, number] | undefined;
27
34
  readonly hideUi?: boolean | undefined;
@@ -61,7 +68,7 @@ declare const __VLS_base: import("vue").DefineComponent<{}, {
61
68
  resizeStrategy?: "lockAspectRatio" | "lockAspectRatioDiagonal";
62
69
  handleStrategy?: "point";
63
70
  handleShape?: "rect" | "circle";
64
- handles?: ("move" | "resize-t" | "resize-r" | "resize-b" | "resize-l" | "resize-br" | "resize-tr" | "resize-tl" | "resize-bl" | "rotate-br" | "rotate-tr" | "rotate-tl" | "rotate-bl" | "round-br" | "round-tr" | "round-tl" | "round-bl")[];
71
+ handles?: ("move" | "resize-t" | "resize-b" | "resize-r" | "resize-l" | "resize-br" | "resize-tr" | "resize-tl" | "resize-bl" | "rotate-br" | "rotate-tr" | "rotate-tl" | "rotate-bl" | "round-br" | "round-tr" | "round-tl" | "round-bl")[];
65
72
  scale?: [number, number];
66
73
  offset?: [number, number];
67
74
  hideUi?: boolean;
@@ -78,7 +85,7 @@ declare const __VLS_base: import("vue").DefineComponent<{}, {
78
85
  "onUpdate:modelValue"?: ((value: Partial<TransformValue> | undefined) => any) | undefined;
79
86
  }>, {
80
87
  start: (event?: MouseEvent, index?: number) => boolean;
81
- activeHandle: import("vue").Ref<("move" | "resize-t" | "resize-r" | "resize-b" | "resize-l" | "resize-br" | "resize-tr" | "resize-tl" | "resize-bl" | "rotate-br" | "rotate-tr" | "rotate-tl" | "rotate-bl" | "round-br" | "round-tr" | "round-tl" | "round-bl") | undefined, ("move" | "resize-t" | "resize-r" | "resize-b" | "resize-l" | "resize-br" | "resize-tr" | "resize-tl" | "resize-bl" | "rotate-br" | "rotate-tr" | "rotate-tl" | "rotate-bl" | "round-br" | "round-tr" | "round-tl" | "round-bl") | undefined>;
88
+ activeHandle: import("vue").Ref<("move" | "resize-t" | "resize-b" | "resize-r" | "resize-l" | "resize-br" | "resize-tr" | "resize-tl" | "resize-bl" | "rotate-br" | "rotate-tr" | "rotate-tl" | "rotate-bl" | "round-br" | "round-tr" | "round-tl" | "round-bl") | undefined, ("move" | "resize-t" | "resize-b" | "resize-r" | "resize-l" | "resize-br" | "resize-tr" | "resize-tl" | "resize-bl" | "rotate-br" | "rotate-tr" | "rotate-tl" | "rotate-bl" | "round-br" | "round-tr" | "round-tl" | "round-bl") | undefined>;
82
89
  transforming: import("vue").Ref<boolean, boolean>;
83
90
  }, {}, {}, {}, import("vue").ComponentOptionsMixin, import("vue").ComponentOptionsMixin, {
84
91
  move: (args_0: TransformValue, args_1: TransformValue) => any;
@@ -94,7 +101,7 @@ declare const __VLS_base: import("vue").DefineComponent<{}, {
94
101
  tag: string | any;
95
102
  threshold: number;
96
103
  handleShape: "rect" | "circle";
97
- handles: ("move" | "resize-t" | "resize-r" | "resize-b" | "resize-l" | "resize-br" | "resize-tr" | "resize-tl" | "resize-bl" | "rotate-br" | "rotate-tr" | "rotate-tl" | "rotate-bl" | "round-br" | "round-tr" | "round-tl" | "round-bl")[];
104
+ handles: ("move" | "resize-t" | "resize-b" | "resize-r" | "resize-l" | "resize-br" | "resize-tr" | "resize-tl" | "resize-bl" | "rotate-br" | "rotate-tr" | "rotate-tl" | "rotate-bl" | "round-br" | "round-tr" | "round-tl" | "round-bl")[];
98
105
  }, {}, string, {}, import("vue").GlobalComponents, import("vue").GlobalDirectives, string, import("vue").ComponentProvideOptions> & {
99
106
  beforeCreate?: (() => void) | (() => void)[];
100
107
  created?: (() => void) | (() => void)[];
@@ -124,7 +131,7 @@ declare const __VLS_base: import("vue").DefineComponent<{}, {
124
131
  tag: string | any;
125
132
  threshold: number;
126
133
  handleShape: "rect" | "circle";
127
- handles: ("move" | "resize-t" | "resize-r" | "resize-b" | "resize-l" | "resize-br" | "resize-tr" | "resize-tl" | "resize-bl" | "rotate-br" | "rotate-tr" | "rotate-tl" | "rotate-bl" | "round-br" | "round-tr" | "round-tl" | "round-bl")[];
134
+ handles: ("move" | "resize-t" | "resize-b" | "resize-r" | "resize-l" | "resize-br" | "resize-tr" | "resize-tl" | "resize-bl" | "rotate-br" | "rotate-tr" | "rotate-tl" | "rotate-bl" | "round-br" | "round-tr" | "round-tl" | "round-bl")[];
128
135
  }> & Omit<Readonly<{
129
136
  tag?: string | any;
130
137
  color?: string;
@@ -137,7 +144,7 @@ declare const __VLS_base: import("vue").DefineComponent<{}, {
137
144
  resizeStrategy?: "lockAspectRatio" | "lockAspectRatioDiagonal";
138
145
  handleStrategy?: "point";
139
146
  handleShape?: "rect" | "circle";
140
- handles?: ("move" | "resize-t" | "resize-r" | "resize-b" | "resize-l" | "resize-br" | "resize-tr" | "resize-tl" | "resize-bl" | "rotate-br" | "rotate-tr" | "rotate-tl" | "rotate-bl" | "round-br" | "round-tr" | "round-tl" | "round-bl")[];
147
+ handles?: ("move" | "resize-t" | "resize-b" | "resize-r" | "resize-l" | "resize-br" | "resize-tr" | "resize-tl" | "resize-bl" | "rotate-br" | "rotate-tr" | "rotate-tl" | "rotate-bl" | "round-br" | "round-tr" | "round-tl" | "round-bl")[];
141
148
  scale?: [number, number];
142
149
  offset?: [number, number];
143
150
  hideUi?: boolean;
@@ -154,7 +161,7 @@ declare const __VLS_base: import("vue").DefineComponent<{}, {
154
161
  "onUpdate:modelValue"?: ((value: Partial<TransformValue> | undefined) => any) | undefined;
155
162
  }>, "transforming" | "start" | "activeHandle" | ("offset" | "scale" | "movable" | "rotatable" | "resizable" | "tag" | "threshold" | "handleShape" | "handles")> & import("vue").ShallowUnwrapRef<{
156
163
  start: (event?: MouseEvent, index?: number) => boolean;
157
- activeHandle: import("vue").Ref<("move" | "resize-t" | "resize-r" | "resize-b" | "resize-l" | "resize-br" | "resize-tr" | "resize-tl" | "resize-bl" | "rotate-br" | "rotate-tr" | "rotate-tl" | "rotate-bl" | "round-br" | "round-tr" | "round-tl" | "round-bl") | undefined, ("move" | "resize-t" | "resize-r" | "resize-b" | "resize-l" | "resize-br" | "resize-tr" | "resize-tl" | "resize-bl" | "rotate-br" | "rotate-tr" | "rotate-tl" | "rotate-bl" | "round-br" | "round-tr" | "round-tl" | "round-bl") | undefined>;
164
+ activeHandle: import("vue").Ref<("move" | "resize-t" | "resize-b" | "resize-r" | "resize-l" | "resize-br" | "resize-tr" | "resize-tl" | "resize-bl" | "rotate-br" | "rotate-tr" | "rotate-tl" | "rotate-bl" | "round-br" | "round-tr" | "round-tl" | "round-bl") | undefined, ("move" | "resize-t" | "resize-b" | "resize-r" | "resize-l" | "resize-br" | "resize-tr" | "resize-tl" | "resize-bl" | "rotate-br" | "rotate-tr" | "rotate-tl" | "rotate-bl" | "round-br" | "round-tr" | "round-tl" | "round-bl") | undefined>;
158
165
  transforming: import("vue").Ref<boolean, boolean>;
159
166
  }> & {} & import("vue").ComponentCustomProperties & {} & {
160
167
  $slots: {
@@ -199,7 +206,7 @@ declare const __VLS_base: import("vue").DefineComponent<{}, {
199
206
  readonly resizeStrategy?: "lockAspectRatio" | "lockAspectRatioDiagonal" | undefined;
200
207
  readonly handleStrategy?: "point" | undefined;
201
208
  readonly handleShape?: "rect" | "circle" | undefined;
202
- readonly handles?: ("move" | "resize-t" | "resize-r" | "resize-b" | "resize-l" | "resize-br" | "resize-tr" | "resize-tl" | "resize-bl" | "rotate-br" | "rotate-tr" | "rotate-tl" | "rotate-bl" | "round-br" | "round-tr" | "round-tl" | "round-bl")[] | undefined;
209
+ readonly handles?: ("move" | "resize-t" | "resize-b" | "resize-r" | "resize-l" | "resize-br" | "resize-tr" | "resize-tl" | "resize-bl" | "rotate-br" | "rotate-tr" | "rotate-tl" | "rotate-bl" | "round-br" | "round-tr" | "round-tl" | "round-bl")[] | undefined;
203
210
  readonly scale?: [number, number] | undefined;
204
211
  readonly offset?: [number, number] | undefined;
205
212
  readonly hideUi?: boolean | undefined;
@@ -239,7 +246,7 @@ declare const __VLS_base: import("vue").DefineComponent<{}, {
239
246
  resizeStrategy?: "lockAspectRatio" | "lockAspectRatioDiagonal";
240
247
  handleStrategy?: "point";
241
248
  handleShape?: "rect" | "circle";
242
- handles?: ("move" | "resize-t" | "resize-r" | "resize-b" | "resize-l" | "resize-br" | "resize-tr" | "resize-tl" | "resize-bl" | "rotate-br" | "rotate-tr" | "rotate-tl" | "rotate-bl" | "round-br" | "round-tr" | "round-tl" | "round-bl")[];
249
+ handles?: ("move" | "resize-t" | "resize-b" | "resize-r" | "resize-l" | "resize-br" | "resize-tr" | "resize-tl" | "resize-bl" | "rotate-br" | "rotate-tr" | "rotate-tl" | "rotate-bl" | "round-br" | "round-tr" | "round-tl" | "round-bl")[];
243
250
  scale?: [number, number];
244
251
  offset?: [number, number];
245
252
  hideUi?: boolean;
@@ -256,7 +263,7 @@ declare const __VLS_base: import("vue").DefineComponent<{}, {
256
263
  "onUpdate:modelValue"?: ((value: Partial<TransformValue> | undefined) => any) | undefined;
257
264
  }>, {
258
265
  start: (event?: MouseEvent, index?: number) => boolean;
259
- activeHandle: import("vue").Ref<("move" | "resize-t" | "resize-r" | "resize-b" | "resize-l" | "resize-br" | "resize-tr" | "resize-tl" | "resize-bl" | "rotate-br" | "rotate-tr" | "rotate-tl" | "rotate-bl" | "round-br" | "round-tr" | "round-tl" | "round-bl") | undefined, ("move" | "resize-t" | "resize-r" | "resize-b" | "resize-l" | "resize-br" | "resize-tr" | "resize-tl" | "resize-bl" | "rotate-br" | "rotate-tr" | "rotate-tl" | "rotate-bl" | "round-br" | "round-tr" | "round-tl" | "round-bl") | undefined>;
266
+ activeHandle: import("vue").Ref<("move" | "resize-t" | "resize-b" | "resize-r" | "resize-l" | "resize-br" | "resize-tr" | "resize-tl" | "resize-bl" | "rotate-br" | "rotate-tr" | "rotate-tl" | "rotate-bl" | "round-br" | "round-tr" | "round-tl" | "round-bl") | undefined, ("move" | "resize-t" | "resize-b" | "resize-r" | "resize-l" | "resize-br" | "resize-tr" | "resize-tl" | "resize-bl" | "rotate-br" | "rotate-tr" | "rotate-tl" | "rotate-bl" | "round-br" | "round-tr" | "round-tl" | "round-bl") | undefined>;
260
267
  transforming: import("vue").Ref<boolean, boolean>;
261
268
  }, {}, {}, {}, import("vue").ComponentOptionsMixin, import("vue").ComponentOptionsMixin, {
262
269
  move: (args_0: TransformValue, args_1: TransformValue) => any;
@@ -272,7 +279,7 @@ declare const __VLS_base: import("vue").DefineComponent<{}, {
272
279
  tag: string | any;
273
280
  threshold: number;
274
281
  handleShape: "rect" | "circle";
275
- handles: ("move" | "resize-t" | "resize-r" | "resize-b" | "resize-l" | "resize-br" | "resize-tr" | "resize-tl" | "resize-bl" | "rotate-br" | "rotate-tr" | "rotate-tl" | "rotate-bl" | "round-br" | "round-tr" | "round-tl" | "round-bl")[];
282
+ handles: ("move" | "resize-t" | "resize-b" | "resize-r" | "resize-l" | "resize-br" | "resize-tr" | "resize-tl" | "resize-bl" | "rotate-br" | "rotate-tr" | "rotate-tl" | "rotate-bl" | "round-br" | "round-tr" | "round-tl" | "round-bl")[];
276
283
  }, {}, string, {}, import("vue").GlobalComponents, import("vue").GlobalDirectives, string, import("vue").ComponentProvideOptions> & {
277
284
  beforeCreate?: (() => void) | (() => void)[];
278
285
  created?: (() => void) | (() => void)[];
@@ -302,7 +309,7 @@ declare const __VLS_base: import("vue").DefineComponent<{}, {
302
309
  tag: string | any;
303
310
  threshold: number;
304
311
  handleShape: "rect" | "circle";
305
- handles: ("move" | "resize-t" | "resize-r" | "resize-b" | "resize-l" | "resize-br" | "resize-tr" | "resize-tl" | "resize-bl" | "rotate-br" | "rotate-tr" | "rotate-tl" | "rotate-bl" | "round-br" | "round-tr" | "round-tl" | "round-bl")[];
312
+ handles: ("move" | "resize-t" | "resize-b" | "resize-r" | "resize-l" | "resize-br" | "resize-tr" | "resize-tl" | "resize-bl" | "rotate-br" | "rotate-tr" | "rotate-tl" | "rotate-bl" | "round-br" | "round-tr" | "round-tl" | "round-bl")[];
306
313
  }> & Omit<Readonly<{
307
314
  tag?: string | any;
308
315
  color?: string;
@@ -315,7 +322,7 @@ declare const __VLS_base: import("vue").DefineComponent<{}, {
315
322
  resizeStrategy?: "lockAspectRatio" | "lockAspectRatioDiagonal";
316
323
  handleStrategy?: "point";
317
324
  handleShape?: "rect" | "circle";
318
- handles?: ("move" | "resize-t" | "resize-r" | "resize-b" | "resize-l" | "resize-br" | "resize-tr" | "resize-tl" | "resize-bl" | "rotate-br" | "rotate-tr" | "rotate-tl" | "rotate-bl" | "round-br" | "round-tr" | "round-tl" | "round-bl")[];
325
+ handles?: ("move" | "resize-t" | "resize-b" | "resize-r" | "resize-l" | "resize-br" | "resize-tr" | "resize-tl" | "resize-bl" | "rotate-br" | "rotate-tr" | "rotate-tl" | "rotate-bl" | "round-br" | "round-tr" | "round-tl" | "round-bl")[];
319
326
  scale?: [number, number];
320
327
  offset?: [number, number];
321
328
  hideUi?: boolean;
@@ -332,7 +339,7 @@ declare const __VLS_base: import("vue").DefineComponent<{}, {
332
339
  "onUpdate:modelValue"?: ((value: Partial<TransformValue> | undefined) => any) | undefined;
333
340
  }>, "transforming" | "start" | "activeHandle" | ("offset" | "scale" | "movable" | "rotatable" | "resizable" | "tag" | "threshold" | "handleShape" | "handles")> & import("vue").ShallowUnwrapRef<{
334
341
  start: (event?: MouseEvent, index?: number) => boolean;
335
- activeHandle: import("vue").Ref<("move" | "resize-t" | "resize-r" | "resize-b" | "resize-l" | "resize-br" | "resize-tr" | "resize-tl" | "resize-bl" | "rotate-br" | "rotate-tr" | "rotate-tl" | "rotate-bl" | "round-br" | "round-tr" | "round-tl" | "round-bl") | undefined, ("move" | "resize-t" | "resize-r" | "resize-b" | "resize-l" | "resize-br" | "resize-tr" | "resize-tl" | "resize-bl" | "rotate-br" | "rotate-tr" | "rotate-tl" | "rotate-bl" | "round-br" | "round-tr" | "round-tl" | "round-bl") | undefined>;
342
+ activeHandle: import("vue").Ref<("move" | "resize-t" | "resize-b" | "resize-r" | "resize-l" | "resize-br" | "resize-tr" | "resize-tl" | "resize-bl" | "rotate-br" | "rotate-tr" | "rotate-tl" | "rotate-bl" | "round-br" | "round-tr" | "round-tl" | "round-bl") | undefined, ("move" | "resize-t" | "resize-b" | "resize-r" | "resize-l" | "resize-br" | "resize-tr" | "resize-tl" | "resize-bl" | "rotate-br" | "rotate-tr" | "rotate-tl" | "rotate-bl" | "round-br" | "round-tr" | "round-tl" | "round-bl") | undefined>;
336
343
  transforming: import("vue").Ref<boolean, boolean>;
337
344
  }> & {} & import("vue").ComponentCustomProperties & {} & {
338
345
  $slots: {
@@ -2,14 +2,13 @@ import type { ImageFillCropRect } from 'modern-idoc';
2
2
  /**
3
3
  * TODO 撤回无法重渲
4
4
  */
5
+ type View = Record<'left' | 'top' | 'width' | 'height' | 'scaleX' | 'scaleY', number>;
5
6
  type __VLS_Props = {
6
7
  image: string;
7
- minScale?: number;
8
- maxScale?: number;
9
8
  };
10
9
  declare function ok(): void;
11
10
  declare function cancel(): void;
12
- declare function applySourceTransformToStyle(): void;
11
+ declare function setAspectRatio(ratio: 0 | [number, number]): void;
13
12
  type __VLS_ModelProps = {
14
13
  /**
15
14
  * CropRect (value are based on Source !!!)
@@ -41,14 +40,14 @@ type __VLS_ModelProps = {
41
40
  * |----- 0 -----|
42
41
  */
43
42
  modelValue?: ImageFillCropRect;
44
- 'style'?: Record<string, any>;
43
+ 'view': View;
45
44
  };
46
45
  type __VLS_PublicProps = __VLS_Props & __VLS_ModelProps;
47
46
  declare var __VLS_7: {
48
47
  scale: number;
49
48
  ok: typeof ok;
50
49
  cancel: typeof cancel;
51
- applySourceTransformToStyle: typeof applySourceTransformToStyle;
50
+ setAspectRatio: typeof setAspectRatio;
52
51
  };
53
52
  type __VLS_Slots = {} & {
54
53
  default?: (props: typeof __VLS_7) => any;
@@ -57,28 +56,13 @@ declare const __VLS_base: import("vue").DefineComponent<__VLS_PublicProps, {}, {
57
56
  start: () => any;
58
57
  end: () => any;
59
58
  "update:modelValue": (value: ImageFillCropRect) => any;
60
- "update:transform": (args_0: {
61
- left: number;
62
- top: number;
63
- width: number;
64
- height: number;
65
- }) => any;
66
- "update:style": (value: Record<string, any>) => any;
59
+ "update:view": (value: View) => any;
67
60
  }, string, import("vue").PublicProps, Readonly<__VLS_PublicProps> & Readonly<{
68
61
  onStart?: (() => any) | undefined;
69
62
  onEnd?: (() => any) | undefined;
70
63
  "onUpdate:modelValue"?: ((value: ImageFillCropRect) => any) | undefined;
71
- "onUpdate:transform"?: ((args_0: {
72
- left: number;
73
- top: number;
74
- width: number;
75
- height: number;
76
- }) => any) | undefined;
77
- "onUpdate:style"?: ((value: Record<string, any>) => any) | undefined;
78
- }>, {
79
- minScale: number;
80
- maxScale: number;
81
- }, {}, {}, {}, string, import("vue").ComponentProvideOptions, false, {}, any>;
64
+ "onUpdate:view"?: ((value: View) => any) | undefined;
65
+ }>, {}, {}, {}, {}, string, import("vue").ComponentProvideOptions, false, {}, any>;
82
66
  declare const __VLS_export: __VLS_WithSlots<typeof __VLS_base, __VLS_Slots>;
83
67
  declare const _default: typeof __VLS_export;
84
68
  export default _default;
package/dist/index.js CHANGED
@@ -1,15 +1,15 @@
1
1
  import { Node as Node$1, Element2D, Timeline, Engine, Camera2D, DrawboardEffect, Aabb2D, IN_BROWSER, clamp, assets, TimelineNode, Video2D, Transform2D, Obb2D, render, Vector2 as Vector2$1, Lottie2D, customNodes, Animation, IN_MAC_OS } from "modern-canvas";
2
- import { reactive, computed, watch, markRaw, isReactive, ref, onBeforeMount, onScopeDispose, warn, shallowRef, defineComponent, createElementBlock, createCommentVNode, unref, openBlock, normalizeStyle as normalizeStyle$1, toDisplayString, onMounted, createVNode, useAttrs, createBlock, resolveDynamicComponent, normalizeClass, mergeProps, createElementVNode, inject, toValue, getCurrentInstance, provide, useId, onBeforeUnmount, readonly, toRef, onDeactivated, onActivated, useModel, useTemplateRef, withDirectives, withModifiers, vModelText, vShow, nextTick, Fragment, renderList, renderSlot, mergeModels, resolveComponent, withCtx, Teleport, createTextVNode, createSlots, normalizeProps, guardReactiveProps, h, isRef, effectScope, useSlots } from "vue";
2
+ import { reactive, computed, watch, markRaw, isReactive, ref, onBeforeMount, onScopeDispose, warn, shallowRef, defineComponent, unref, openBlock, createElementBlock, normalizeStyle as normalizeStyle$1, toDisplayString, createCommentVNode, onMounted, createVNode, useAttrs, createBlock, resolveDynamicComponent, normalizeClass, mergeProps, createElementVNode, inject, toValue, getCurrentInstance, provide, useId, onBeforeUnmount, readonly, toRef, onDeactivated, onActivated, useModel, useTemplateRef, withDirectives, withModifiers, vModelText, vShow, nextTick, Fragment, renderList, renderSlot, resolveComponent, withCtx, mergeModels, Teleport, createTextVNode, createSlots, normalizeProps, guardReactiveProps, h, isRef, effectScope, useSlots } from "vue";
3
3
  import { useFileDialog, useEventListener, isClient, onClickOutside, useDebounceFn, useImage, useResizeObserver as useResizeObserver$1, useLocalStorage } from "@vueuse/core";
4
4
  import { getObjectValueByPath, setObjectValueByPath, Observable, Reactivable, idGenerator, property, normalizeTextContent, isCRLF, textContentToString, normalizeCRLF, isEqualObject } from "modern-idoc";
5
5
  import { saveAs } from "file-saver";
6
6
  import { Fonts } from "modern-font";
7
7
  import * as Y from "yjs";
8
- import { merge, throttle, cloneDeep } from "lodash-es";
8
+ import { merge, throttle, cloneDeep, isEqual } from "lodash-es";
9
9
  import { measureText, Text } from "modern-text";
10
10
  import { diffChars } from "diff";
11
11
  import { vResizeObserver } from "@vueuse/components";
12
- import { useFloating, offset, flip, shift, autoUpdate } from "@floating-ui/vue";
12
+ import { useFloating, autoUpdate, offset, flip, shift } from "@floating-ui/vue";
13
13
  function defineMixin(cb) {
14
14
  return cb;
15
15
  }
@@ -1085,7 +1085,9 @@ const en = {
1085
1085
  "loading": "Loading",
1086
1086
  "drawing": "Drawing",
1087
1087
  "exporting": "Exporting",
1088
+ "painting": "Painting",
1088
1089
  "selecting": "Selecting",
1090
+ "cropping": "Cropping",
1089
1091
  "selectObject": "Select object",
1090
1092
  "commitChanges": "Commit changes",
1091
1093
  "extend": "Extend",
@@ -1137,6 +1139,7 @@ const en = {
1137
1139
  "paste": "Paste",
1138
1140
  "duplicate": "Duplicate",
1139
1141
  "delete": "Delete",
1142
+ "formatPaint": "Format paint",
1140
1143
  "selectAll": "Select all",
1141
1144
  "selectInverse": "Deselect all",
1142
1145
  "selectNone": "Select none",
@@ -1201,7 +1204,9 @@ const zhHans = {
1201
1204
  "loading": "加载中...",
1202
1205
  "drawing": "绘制中...",
1203
1206
  "exporting": "导出中...",
1207
+ "painting": "格式刷中...",
1204
1208
  "selecting": "选择中...",
1209
+ "cropping": "裁剪中...",
1205
1210
  "selectObject": "选择对象",
1206
1211
  "commitChanges": "提交修改",
1207
1212
  "extend": "扩展",
@@ -1253,6 +1258,7 @@ const zhHans = {
1253
1258
  "paste": "粘贴",
1254
1259
  "duplicate": "创建副本",
1255
1260
  "delete": "删除",
1261
+ "formatPaint": "格式刷",
1256
1262
  "selectAll": "选择全部",
1257
1263
  "selectInverse": "反选全部",
1258
1264
  "selectNone": "取消选择",
@@ -2011,7 +2017,7 @@ const _2_box = defineMixin((editor) => {
2011
2017
  let flag = false;
2012
2018
  element.children.forEach((child) => {
2013
2019
  if (isElement(child)) {
2014
- const { min: _min, max: _max } = child.getAabb().toMinmax();
2020
+ const { min: _min, max: _max } = child.aabb.toMinmax();
2015
2021
  min.x = Math.min(min.x, _min.x);
2016
2022
  min.y = Math.min(min.y, _min.y);
2017
2023
  max.x = Math.max(max.x, _max.x);
@@ -2029,7 +2035,7 @@ const _2_box = defineMixin((editor) => {
2029
2035
  const aabbs = {};
2030
2036
  element.children.forEach((child, index) => {
2031
2037
  if (isElement(child)) {
2032
- aabbs[index] = child.getGlobalAabb();
2038
+ aabbs[index] = child.globalAabb;
2033
2039
  }
2034
2040
  });
2035
2041
  element.style.left += box.left;
@@ -2132,7 +2138,7 @@ const _2_box = defineMixin((editor) => {
2132
2138
  } else if (isElement(node)) {
2133
2139
  const style = node.style;
2134
2140
  noop([style.left, style.top, style.width, style.height, style.rotate]);
2135
- aabb = node.getGlobalAabb();
2141
+ aabb = node.globalAabb;
2136
2142
  } else {
2137
2143
  aabb = new Aabb2D();
2138
2144
  }
@@ -2485,11 +2491,6 @@ function parseHTML(html) {
2485
2491
  }
2486
2492
  const SUPPORTS_POINTER_EVENTS = "PointerEvent" in globalThis;
2487
2493
  class TextEditor extends HTMLElement {
2488
- _prevSelection;
2489
- _composition = false;
2490
- get composition() {
2491
- return this._composition;
2492
- }
2493
2494
  static _defined = false;
2494
2495
  static register() {
2495
2496
  if (!this._defined) {
@@ -2899,25 +2900,19 @@ class TextEditor extends HTMLElement {
2899
2900
  return -1;
2900
2901
  }
2901
2902
  _updateSelectionByDom() {
2902
- if (this._composition) {
2903
- this.selection = this._prevSelection;
2904
- } else {
2905
- const { selectionStart, selectionEnd } = this._textarea;
2906
- let count2 = 0;
2907
- const _selection2 = [-1, -1];
2908
- this._chars.forEach((char, index) => {
2909
- if (count2 <= selectionStart) {
2910
- _selection2[0] = index;
2911
- }
2912
- if (count2 <= selectionEnd) {
2913
- _selection2[1] = index;
2914
- }
2915
- count2 += char.content.length;
2916
- });
2917
- const oldSelection = this.selection;
2918
- this.selection = _selection2;
2919
- this._prevSelection = oldSelection;
2920
- }
2903
+ const { selectionStart, selectionEnd } = this._textarea;
2904
+ let count2 = 0;
2905
+ const _selection2 = [-1, -1];
2906
+ this._chars.forEach((char, index) => {
2907
+ if (count2 <= selectionStart) {
2908
+ _selection2[0] = index;
2909
+ }
2910
+ if (count2 <= selectionEnd) {
2911
+ _selection2[1] = index;
2912
+ }
2913
+ count2 += char.content.length;
2914
+ });
2915
+ this.selection = _selection2;
2921
2916
  }
2922
2917
  _updateDomSelection() {
2923
2918
  let start = 0;
@@ -2953,8 +2948,6 @@ class TextEditor extends HTMLElement {
2953
2948
  this._renderCursor();
2954
2949
  }
2955
2950
  _bindEventListeners() {
2956
- this._textarea.addEventListener("compositionstart", () => this._composition = true);
2957
- this._textarea.addEventListener("compositionend", () => this._composition = false);
2958
2951
  this._textarea.addEventListener("keydown", this._onKeydown.bind(this));
2959
2952
  this._textarea.addEventListener("input", this._onInput.bind(this));
2960
2953
  if (SUPPORTS_POINTER_EVENTS) {
@@ -2962,10 +2955,8 @@ class TextEditor extends HTMLElement {
2962
2955
  } else {
2963
2956
  this._textarea.addEventListener("mousedown", this.pointerDown.bind(this));
2964
2957
  }
2965
- ["keyup", "mouseup", "input", "paste", "cut"].forEach((key) => {
2966
- this._textarea.addEventListener(key, () => {
2967
- this._updateSelectionByDom();
2968
- });
2958
+ ["selectstart", "selectionchange"].forEach((key) => {
2959
+ this._textarea.addEventListener(key, () => this._updateSelectionByDom());
2969
2960
  });
2970
2961
  }
2971
2962
  pointerDown(e) {
@@ -4128,7 +4119,7 @@ const _arrange = definePlugin((editor) => {
4128
4119
  if (len === 1) {
4129
4120
  const parent = elementSelection.value[0]?.parent;
4130
4121
  if (parent && isElement(parent)) {
4131
- targetAabb = parent.getGlobalAabb();
4122
+ targetAabb = parent.globalAabb;
4132
4123
  }
4133
4124
  } else {
4134
4125
  targetAabb = getAabb(elementSelection.value);
@@ -4137,7 +4128,7 @@ const _arrange = definePlugin((editor) => {
4137
4128
  return;
4138
4129
  }
4139
4130
  elementSelection.value.forEach((el) => {
4140
- const parentAabb = el.getParent()?.getGlobalAabb?.() ?? new Aabb2D();
4131
+ const parentAabb = el.getParent()?.globalAabb ?? new Aabb2D();
4141
4132
  const hw = el.size.x / 2;
4142
4133
  const hh = el.size.y / 2;
4143
4134
  const cos = Math.cos(el.rotation);
@@ -4174,7 +4165,7 @@ const _arrange = definePlugin((editor) => {
4174
4165
  const items = els.map((el) => {
4175
4166
  return {
4176
4167
  el,
4177
- aabb: el.getGlobalAabb()
4168
+ aabb: el.globalAabb
4178
4169
  };
4179
4170
  });
4180
4171
  const count2 = items.length;
@@ -4193,7 +4184,7 @@ const _arrange = definePlugin((editor) => {
4193
4184
  const item = sorted[i];
4194
4185
  current += gapSize;
4195
4186
  let top = current;
4196
- const parentAabb = item.el.getParent()?.getGlobalAabb?.();
4187
+ const parentAabb = item.el.getParent()?.globalAabb;
4197
4188
  if (parentAabb) {
4198
4189
  top = top - parentAabb.top;
4199
4190
  }
@@ -4216,7 +4207,7 @@ const _arrange = definePlugin((editor) => {
4216
4207
  const item = sorted[i];
4217
4208
  current += gapSize;
4218
4209
  let left = current;
4219
- const parentAabb = item.el.getParent()?.getGlobalAabb?.();
4210
+ const parentAabb = item.el.getParent()?.globalAabb;
4220
4211
  if (parentAabb) {
4221
4212
  left = left - parentAabb.left;
4222
4213
  }
@@ -4279,7 +4270,7 @@ const _autoNest = definePlugin((editor) => {
4279
4270
  function nestIntoFrame(el, options) {
4280
4271
  const pointer = options?.pointer;
4281
4272
  const frame1 = el.findAncestor((node) => isTopFrame(node));
4282
- const aabb1 = el.getGlobalAabb();
4273
+ const aabb1 = el.globalAabb;
4283
4274
  const area1 = aabb1.getArea();
4284
4275
  let flag = true;
4285
4276
  for (let i = 0, len = frames.value.length; i < len; i++) {
@@ -4287,7 +4278,7 @@ const _autoNest = definePlugin((editor) => {
4287
4278
  if (options?.excluded.has(frame2.instanceId) || frame2.equal(el)) {
4288
4279
  continue;
4289
4280
  }
4290
- const aabb2 = frame2.getGlobalAabb();
4281
+ const aabb2 = frame2.globalAabb;
4291
4282
  if (pointer ? aabb2.contains(pointer) : aabb1 && aabb1.getIntersectionRect(aabb2).getArea() > area1 * 0.5) {
4292
4283
  if (!frame2.equal(frame1)) {
4293
4284
  let index = frame2.children.length;
@@ -4325,7 +4316,7 @@ const _autoNest = definePlugin((editor) => {
4325
4316
  selectionTransformStart: ({ handle, startEvent, elements }) => {
4326
4317
  if (handle === "move" && !startEvent?.__FROM__) {
4327
4318
  const pointer = getGlobalPointer();
4328
- const startFrame = frames.value.find((frame) => frame.getGlobalAabb().contains(pointer));
4319
+ const startFrame = frames.value.find((frame) => frame.globalAabb.contains(pointer));
4329
4320
  const idSet = /* @__PURE__ */ new Set();
4330
4321
  elements.forEach((el) => {
4331
4322
  const frame = isTopFrame(el) ? el : el.findAncestor(isTopFrame);
@@ -4703,6 +4694,68 @@ const _edit = definePlugin((editor, options) => {
4703
4694
  }
4704
4695
  };
4705
4696
  });
4697
+ const _formatPaint = definePlugin((editor) => {
4698
+ const {
4699
+ elementSelection,
4700
+ getTextFill,
4701
+ getTextStyle,
4702
+ exec,
4703
+ textToFit,
4704
+ state
4705
+ } = editor;
4706
+ let source;
4707
+ function activateFormatPaint() {
4708
+ if (!elementSelection.value?.[0]?.text?.textContent) {
4709
+ return;
4710
+ }
4711
+ const text = elementSelection.value[0].text;
4712
+ const fill = getTextFill();
4713
+ const excludes = ["left", "top", "width", "height"];
4714
+ const fields = Object.keys(text.style ?? {}).filter((key) => !excludes.includes(key));
4715
+ const style = fields.reduce((acc, field) => ({ ...acc, [field]: getTextStyle(field) }), {});
4716
+ source = {
4717
+ ...text,
4718
+ fill,
4719
+ style
4720
+ };
4721
+ exec("setState", "painting");
4722
+ elementSelection.value = [];
4723
+ }
4724
+ function applyFormatPaint(targets = elementSelection.value) {
4725
+ if (!source)
4726
+ return;
4727
+ targets.forEach((target) => {
4728
+ if (target.text?.textContent) {
4729
+ target.text = {
4730
+ ...source,
4731
+ content: [
4732
+ {
4733
+ fragments: [
4734
+ { content: target.text.textContent }
4735
+ ]
4736
+ }
4737
+ ]
4738
+ };
4739
+ textToFit(target);
4740
+ }
4741
+ });
4742
+ }
4743
+ function exitFormatPaint() {
4744
+ source = void 0;
4745
+ state.value === "painting" && exec("setState", void 0);
4746
+ }
4747
+ return {
4748
+ name: "mce:formatPaint",
4749
+ commands: [
4750
+ { command: "formatPaint", handle: activateFormatPaint },
4751
+ { command: "applyFormatPaint", handle: applyFormatPaint },
4752
+ { command: "exitFormatPaint", handle: exitFormatPaint }
4753
+ ],
4754
+ hotkeys: [
4755
+ { command: "formatPaint", key: "CmdOrCtrl+F", when: () => elementSelection.value[0]?.text }
4756
+ ]
4757
+ };
4758
+ });
4706
4759
  function makeIconProps() {
4707
4760
  return {
4708
4761
  icon: {
@@ -6842,6 +6895,7 @@ const _menu = definePlugin((editor, options) => {
6842
6895
  canUndo,
6843
6896
  canRedo,
6844
6897
  selection,
6898
+ elementSelection,
6845
6899
  textSelection,
6846
6900
  config,
6847
6901
  exporters,
@@ -6884,7 +6938,8 @@ const _menu = definePlugin((editor, options) => {
6884
6938
  { key: "cut", disabled: !hasSelected.value },
6885
6939
  { key: "paste" },
6886
6940
  { key: "duplicate", disabled: !hasSelected.value },
6887
- { key: "delete", disabled: !hasSelected.value }
6941
+ { key: "delete", disabled: !hasSelected.value },
6942
+ { key: "formatPaint", disabled: !elementSelection.value[0]?.text?.textContent }
6888
6943
  ].filter(Boolean));
6889
6944
  const selectMenu = computed(() => ({
6890
6945
  key: "select",
@@ -11371,7 +11426,7 @@ const _pen = definePlugin((editor) => {
11371
11426
  }, {
11372
11427
  position: start
11373
11428
  });
11374
- const parentAabb = el2.getParent()?.getGlobalAabb?.() ?? new Aabb2D();
11429
+ const parentAabb = el2.getParent()?.globalAabb ?? new Aabb2D();
11375
11430
  const path = new Path2D();
11376
11431
  path.moveTo(start.x - parentAabb.x, start.y - parentAabb.y);
11377
11432
  const update2 = () => {
@@ -12857,59 +12912,56 @@ const _hoisted_1$d = { class: "mce-cropper" };
12857
12912
  const _sfc_main$k = /* @__PURE__ */ defineComponent({
12858
12913
  __name: "Cropper",
12859
12914
  props: /* @__PURE__ */ mergeModels({
12860
- image: {},
12861
- minScale: { default: 0.1 },
12862
- maxScale: { default: 3 }
12915
+ image: {}
12863
12916
  }, {
12864
12917
  "modelValue": { default: () => ({}) },
12865
12918
  "modelModifiers": {},
12866
- "style": { default: () => ({}) },
12867
- "styleModifiers": {}
12919
+ "view": { required: true },
12920
+ "viewModifiers": {}
12868
12921
  }),
12869
- emits: /* @__PURE__ */ mergeModels(["start", "end", "update:transform"], ["update:modelValue", "update:style"]),
12922
+ emits: /* @__PURE__ */ mergeModels(["start", "end"], ["update:modelValue", "update:view"]),
12870
12923
  setup(__props, { emit: __emit }) {
12871
12924
  const props = __props;
12872
12925
  const emit = __emit;
12873
12926
  const cropRect = useModel(__props, "modelValue");
12874
- const styleModel = useModel(__props, "style");
12875
- const rootBox = ref({ width: 0, height: 0 });
12876
- const { state: imageRef } = useImage(
12877
- computed(() => ({
12878
- src: props.image
12879
- }))
12880
- );
12881
- const backup = cloneDeep(cropRect.value);
12882
- const canvasRef = useTemplateRef("canvasRef");
12883
- const computedCropRect = computed({
12927
+ const cropBackup = cloneDeep(cropRect.value);
12928
+ const internalValue = computed({
12884
12929
  get: () => {
12885
12930
  const { left = 0, top = 0, right = 0, bottom = 0 } = cropRect.value;
12886
12931
  return { left, top, right, bottom };
12887
12932
  },
12888
12933
  set: (val) => cropRect.value = val
12889
12934
  });
12935
+ const view = useModel(__props, "view");
12936
+ const viewBackup = cloneDeep(view.value);
12890
12937
  const inverseMat = computed(() => {
12891
- const { left, top, right, bottom } = computedCropRect.value;
12938
+ const { left, top, right, bottom } = internalValue.value;
12892
12939
  const sx = 1 / (1 - left - right);
12893
12940
  const sy = 1 / (1 - top - bottom);
12894
12941
  const tx = -left;
12895
12942
  const ty = -top;
12896
12943
  return { sx, sy, tx, ty };
12897
12944
  });
12945
+ const rootBox = ref({ width: 0, height: 0 });
12946
+ function onResizeObserver(entries) {
12947
+ const { width, height } = entries[0].contentRect;
12948
+ rootBox.value = { width, height };
12949
+ }
12950
+ function applyInverseMat({ width, height }) {
12951
+ const { sx, sy, tx, ty } = inverseMat.value;
12952
+ const { scaleX = 1, scaleY = 1 } = view.value;
12953
+ return {
12954
+ width: sx * width,
12955
+ height: sy * height,
12956
+ left: tx * scaleX * (sx * width),
12957
+ top: ty * scaleY * (sy * height)
12958
+ };
12959
+ }
12898
12960
  const sourceTransform = computed({
12899
- get: () => {
12900
- const { sx, sy, tx, ty } = inverseMat.value;
12901
- const { scaleX = 1, scaleY = 1 } = styleModel.value;
12902
- const { width, height } = rootBox.value;
12903
- return {
12904
- width: sx * width,
12905
- height: sy * height,
12906
- left: tx * scaleX * (sx * width),
12907
- top: ty * scaleY * (sy * height)
12908
- };
12909
- },
12961
+ get: () => applyInverseMat(rootBox.value),
12910
12962
  set: (newValue) => {
12911
12963
  const { width, height } = rootBox.value;
12912
- const { scaleX = 1, scaleY = 1 } = styleModel.value;
12964
+ const { scaleX = 1, scaleY = 1 } = view.value;
12913
12965
  const transform = {
12914
12966
  sx: newValue.width / width,
12915
12967
  sy: newValue.height / height,
@@ -12922,43 +12974,87 @@ const _sfc_main$k = /* @__PURE__ */ defineComponent({
12922
12974
  const h2 = 1 - 1 / transform.sy;
12923
12975
  const right = w - left;
12924
12976
  const bottom = h2 - top;
12925
- computedCropRect.value = { left, top, right, bottom };
12977
+ internalValue.value = { left, top, right, bottom };
12978
+ }
12979
+ });
12980
+ const viewEffect = watch(view, (val, old) => {
12981
+ if (!isEqual(val, old)) {
12982
+ const source = applyInverseMat(old);
12983
+ const left = (val.left - old.left - source.left) / source.width;
12984
+ const top = (val.top - old.top - source.top) / source.height;
12985
+ const right = 1 - left - val.width / source.width;
12986
+ const bottom = 1 - top - val.height / source.height;
12987
+ internalValue.value = { left, top, right, bottom };
12926
12988
  }
12927
12989
  });
12928
12990
  const scale = computed({
12929
12991
  get: () => inverseMat.value.sx,
12930
12992
  set: (value) => {
12931
- const transform = inverseMat.value;
12932
- const rate = transform.sx / value;
12933
- const left = -transform.tx;
12934
- const top = -transform.ty;
12935
- const w = 1 - 1 / value;
12936
- const h2 = 1 - 1 / transform.sy * rate;
12937
- const right = w - left;
12938
- const bottom = h2 - top;
12939
- computedCropRect.value = { left, top, right, bottom };
12993
+ const { sx: oldSx, sy: oldSy } = inverseMat.value;
12994
+ const { left: oldLeft, top: oldTop, right: oldRight, bottom: oldBottom } = internalValue.value;
12995
+ const oldViewWidth = 1 - oldLeft - oldRight;
12996
+ const oldViewHeight = 1 - oldTop - oldBottom;
12997
+ const centerX = oldLeft + oldViewWidth * 0.5;
12998
+ const centerY = oldTop + oldViewHeight * 0.5;
12999
+ const newSx = value;
13000
+ const newSy = value * (oldSy / oldSx);
13001
+ const newViewWidth = 1 / newSx;
13002
+ const newViewHeight = 1 / newSy;
13003
+ const newLeft = centerX - newViewWidth * 0.5;
13004
+ const newTop = centerY - newViewHeight * 0.5;
13005
+ const newRight = 1 - newViewWidth - newLeft;
13006
+ const newBottom = 1 - newViewHeight - newTop;
13007
+ internalValue.value = {
13008
+ left: newLeft,
13009
+ top: newTop,
13010
+ right: newRight,
13011
+ bottom: newBottom
13012
+ };
12940
13013
  }
12941
13014
  });
12942
- onBeforeMount(() => emit("start"));
12943
- onBeforeUnmount(() => emit("end"));
12944
- const sourceStyle = computed(() => {
12945
- const { sx, sy, tx, ty } = inverseMat.value;
12946
- const { scaleX = 1, scaleY = 1 } = styleModel.value;
12947
- return {
12948
- transform: [
12949
- `scale(${sx}, ${sy})`,
12950
- `translate(${tx * scaleX * 100}%, ${ty * scaleY * 100}%)`
12951
- ].join(" ")
13015
+ function ok() {
13016
+ emit("end");
13017
+ }
13018
+ function cancel() {
13019
+ cropRect.value = cropBackup;
13020
+ viewEffect.stop();
13021
+ view.value = viewBackup;
13022
+ ok();
13023
+ }
13024
+ function setAspectRatio(ratio) {
13025
+ const { left = 0, top = 0 } = view.value;
13026
+ const { left: sourceLeft, top: sourceTop, width: sourceWidth, height: sourceHeight } = applyInverseMat(view.value);
13027
+ const aspectRatio = ratio === 0 ? sourceWidth / sourceHeight : ratio[0] / ratio[1];
13028
+ let newViewWidth = sourceWidth;
13029
+ let newViewHeight = sourceWidth / aspectRatio;
13030
+ if (newViewHeight > sourceHeight) {
13031
+ newViewHeight = sourceHeight;
13032
+ newViewWidth = sourceHeight * aspectRatio;
13033
+ }
13034
+ const newViewLeft = left + sourceLeft + (sourceWidth - newViewWidth) / 2;
13035
+ const newViewTop = top + sourceTop + (sourceHeight - newViewHeight) / 2;
13036
+ view.value = {
13037
+ ...view.value,
13038
+ width: newViewWidth,
13039
+ height: newViewHeight,
13040
+ left: newViewLeft,
13041
+ top: newViewTop
12952
13042
  };
12953
- });
13043
+ }
13044
+ const { state: imageRef } = useImage(
13045
+ computed(() => ({
13046
+ src: props.image
13047
+ }))
13048
+ );
13049
+ const canvasRef = useTemplateRef("canvasRef");
12954
13050
  watch([canvasRef, imageRef], render2);
12955
- watch(computedCropRect, render2, { deep: true });
12956
- watch([() => styleModel.value.scaleX, () => styleModel.value.scaleY], render2);
13051
+ watch(internalValue, render2, { deep: true });
13052
+ watch([() => view.value.scaleX, () => view.value.scaleY], render2);
12957
13053
  function render2() {
12958
13054
  const ctx = canvasRef.value?.getContext("2d");
12959
13055
  if (!ctx || !imageRef.value)
12960
13056
  return;
12961
- const { scaleX = 1, scaleY = 1 } = styleModel.value;
13057
+ const { scaleX = 1, scaleY = 1 } = view.value;
12962
13058
  const { naturalWidth, naturalHeight } = imageRef.value;
12963
13059
  ctx.canvas.width = naturalWidth;
12964
13060
  ctx.canvas.height = naturalHeight;
@@ -12967,35 +13063,13 @@ const _sfc_main$k = /* @__PURE__ */ defineComponent({
12967
13063
  ctx.scale(scaleX, scaleY);
12968
13064
  ctx.drawImage(imageRef.value, 0, 0, naturalWidth, naturalHeight);
12969
13065
  }
12970
- function ok() {
12971
- emit("end");
12972
- }
12973
- function cancel() {
12974
- cropRect.value = backup;
12975
- ok();
12976
- }
12977
- function onResizeObserver(entries) {
12978
- const { width, height } = entries[0].contentRect;
12979
- rootBox.value = { width, height };
12980
- }
12981
- function applySourceTransformToStyle() {
12982
- const { left = 0, top = 0, width = 0, height = 0 } = styleModel.value;
12983
- const { sx, sy, tx, ty } = inverseMat.value;
12984
- cropRect.value = {};
12985
- styleModel.value = {
12986
- ...styleModel.value,
12987
- width: sx * width,
12988
- height: sy * height,
12989
- left: left + tx * (sx * width),
12990
- top: top + ty * (sy * height)
12991
- };
12992
- ok();
12993
- }
13066
+ onBeforeMount(() => emit("start"));
13067
+ onBeforeUnmount(() => emit("end"));
12994
13068
  return (_ctx, _cache) => {
12995
13069
  return withDirectives((openBlock(), createElementBlock("div", _hoisted_1$d, [
12996
13070
  createElementVNode("div", {
12997
13071
  class: "mce-cropper__source",
12998
- style: normalizeStyle$1(sourceStyle.value)
13072
+ style: normalizeStyle$1(unref(boundingBoxToStyle)(sourceTransform.value))
12999
13073
  }, [
13000
13074
  createElementVNode("canvas", {
13001
13075
  ref_key: "canvasRef",
@@ -13017,7 +13091,7 @@ const _sfc_main$k = /* @__PURE__ */ defineComponent({
13017
13091
  scale: scale.value,
13018
13092
  ok,
13019
13093
  cancel,
13020
- applySourceTransformToStyle
13094
+ setAspectRatio
13021
13095
  })
13022
13096
  ])), [
13023
13097
  [unref(vResizeObserver), onResizeObserver]
@@ -13033,17 +13107,35 @@ const _sfc_main$j = /* @__PURE__ */ defineComponent({
13033
13107
  elementSelection
13034
13108
  } = useEditor();
13035
13109
  const element = computed(() => elementSelection.value[0]);
13110
+ const view = computed({
13111
+ get: () => ({
13112
+ left: element.value.style.left,
13113
+ top: element.value.style.top,
13114
+ width: element.value.style.width,
13115
+ height: element.value.style.height,
13116
+ scaleX: element.value.style.scaleX,
13117
+ scaleY: element.value.style.scaleY
13118
+ }),
13119
+ set: (val) => {
13120
+ element.value.style = { ...element.value.style, ...val };
13121
+ }
13122
+ });
13036
13123
  return (_ctx, _cache) => {
13037
13124
  return unref(state) === "cropping" && element.value?.foreground.isValid() ? (openBlock(), createBlock(_sfc_main$k, {
13038
13125
  key: 0,
13039
13126
  modelValue: element.value.foreground.cropRect,
13040
13127
  "onUpdate:modelValue": _cache[0] || (_cache[0] = ($event) => element.value.foreground.cropRect = $event),
13041
- style: normalizeStyle$1(element.value.style.toJSON()),
13042
- image: element.value.foreground.image,
13128
+ view: view.value,
13129
+ "onUpdate:view": _cache[1] || (_cache[1] = ($event) => view.value = $event),
13043
13130
  class: "pointer-events-auto",
13044
- "onUpdate:style": _cache[1] || (_cache[1] = (val) => element.value.style.setProperties(val)),
13131
+ image: element.value.foreground.image,
13045
13132
  onEnd: _cache[2] || (_cache[2] = () => state.value = void 0)
13046
- }, null, 8, ["modelValue", "style", "image"])) : createCommentVNode("", true);
13133
+ }, {
13134
+ default: withCtx((scope) => [
13135
+ renderSlot(_ctx.$slots, "default", normalizeProps(guardReactiveProps(scope)))
13136
+ ]),
13137
+ _: 3
13138
+ }, 8, ["modelValue", "view", "image"])) : createCommentVNode("", true);
13047
13139
  };
13048
13140
  }
13049
13141
  });
@@ -13155,7 +13247,7 @@ const _sfc_main$i = /* @__PURE__ */ defineComponent({
13155
13247
  startContext.rotate = 0;
13156
13248
  const aabb = selectionAabb.value;
13157
13249
  elementSelection.value.forEach((el) => {
13158
- const elAabb = el.getGlobalAabb();
13250
+ const elAabb = el.globalAabb;
13159
13251
  startContext.offsetMap[el.instanceId] = {
13160
13252
  x: (elAabb.x - aabb.x) / aabb.width,
13161
13253
  y: (elAabb.y - aabb.y) / aabb.height
@@ -13241,7 +13333,7 @@ const _sfc_main$i = /* @__PURE__ */ defineComponent({
13241
13333
  if (handle.startsWith("resize")) {
13242
13334
  const selectionAabb2 = getAabb(els);
13243
13335
  els.forEach((el) => {
13244
- const parentAabb = el.getParent()?.getGlobalAabb?.() ?? new Aabb2D();
13336
+ const parentAabb = el.getParent()?.globalAabb ?? new Aabb2D();
13245
13337
  const { x, y } = startContext.offsetMap[el.instanceId];
13246
13338
  el.style.left = selectionAabb2.left - parentAabb.left + selectionAabb2.width * x;
13247
13339
  el.style.top = selectionAabb2.top - parentAabb.left + selectionAabb2.height * y;
@@ -13296,13 +13388,26 @@ const _sfc_main$i = /* @__PURE__ */ defineComponent({
13296
13388
  style: normalizeStyle$1(style)
13297
13389
  }, null, 4);
13298
13390
  }), 128)) : createCommentVNode("", true),
13299
- unref(state) === "selecting" ? (openBlock(), createElementBlock("div", {
13391
+ unref(state) === "selecting" || unref(state) === "painting" ? (openBlock(), createElementBlock("div", {
13300
13392
  key: 1,
13301
13393
  class: "mce-selection__marquee",
13302
13394
  style: normalizeStyle$1(unref(selectionMarquee).toCssStyle())
13303
13395
  }, null, 4)) : createCommentVNode("", true),
13304
- transform.value.width && transform.value.height ? (openBlock(), createBlock(_sfc_main$l, mergeProps({
13396
+ transform.value.width && transform.value.height ? (openBlock(), createElementBlock("div", {
13305
13397
  key: 2,
13398
+ class: "mce-selection__slot",
13399
+ style: normalizeStyle$1(unref(selectionObbInDrawboard).toCssStyle())
13400
+ }, [
13401
+ createVNode(_sfc_main$j, null, {
13402
+ default: withCtx((scope) => [
13403
+ renderSlot(_ctx.$slots, "foreground-cropper", normalizeProps(guardReactiveProps(scope)))
13404
+ ]),
13405
+ _: 3
13406
+ }),
13407
+ renderSlot(_ctx.$slots, "default")
13408
+ ], 4)) : createCommentVNode("", true),
13409
+ transform.value.width && transform.value.height ? (openBlock(), createBlock(_sfc_main$l, mergeProps({
13410
+ key: 3,
13306
13411
  ref: "transformControlsTpl"
13307
13412
  }, unref(config).transformControls, {
13308
13413
  modelValue: transform.value,
@@ -13327,15 +13432,7 @@ const _sfc_main$i = /* @__PURE__ */ defineComponent({
13327
13432
  ]),
13328
13433
  key: "0"
13329
13434
  } : void 0
13330
- ]), 1040, ["modelValue", "movable", "resizable", "rotatable", "roundable", "resize-strategy", "scale", "offset"])) : createCommentVNode("", true),
13331
- transform.value.width && transform.value.height ? (openBlock(), createElementBlock("div", {
13332
- key: 3,
13333
- class: "mce-selection__slot",
13334
- style: normalizeStyle$1(unref(selectionObbInDrawboard).toCssStyle())
13335
- }, [
13336
- createVNode(_sfc_main$j),
13337
- renderSlot(_ctx.$slots, "default")
13338
- ], 4)) : createCommentVNode("", true)
13435
+ ]), 1040, ["modelValue", "movable", "resizable", "rotatable", "roundable", "resize-strategy", "scale", "offset"])) : createCommentVNode("", true)
13339
13436
  ]);
13340
13437
  };
13341
13438
  }
@@ -13743,7 +13840,7 @@ const _slice = definePlugin((editor) => {
13743
13840
  if (!el || !inEditorIs(el, "Slice")) {
13744
13841
  return;
13745
13842
  }
13746
- const aabb = el.getGlobalAabb();
13843
+ const aabb = el.globalAabb;
13747
13844
  const doc = to("json", {
13748
13845
  ...options,
13749
13846
  selected: el.parent?.children.filter((node) => !node.equal(el)) ?? []
@@ -14917,7 +15014,7 @@ const _smartGuides = definePlugin((editor) => {
14917
15014
  if (box) {
14918
15015
  const excluded = new Set(elementSelection.value.map((el) => el.instanceId));
14919
15016
  const boxes = parnet.value.children.filter((node) => {
14920
- return !excluded.has(node.instanceId) && isElement(node) && viewportAabb.value.overlap(node.getGlobalAabb());
15017
+ return !excluded.has(node.instanceId) && isElement(node) && viewportAabb.value.overlap(node.globalAabb);
14921
15018
  }).map((node) => createBox(node)).filter(Boolean);
14922
15019
  const { vLines, hLines } = boxes.reduce(
14923
15020
  (store, box2) => {
@@ -15313,7 +15410,7 @@ const _sfc_main$g = /* @__PURE__ */ defineComponent({
15313
15410
  height: style.height + offsetStyle.height,
15314
15411
  rotate: (style.rotate + offsetStyle.rotate + 360) % 360
15315
15412
  };
15316
- const oldAabb = el.getGlobalAabb();
15413
+ const oldAabb = el.globalAabb;
15317
15414
  const shape = el.shape;
15318
15415
  resizeElement(
15319
15416
  el,
@@ -15325,7 +15422,7 @@ const _sfc_main$g = /* @__PURE__ */ defineComponent({
15325
15422
  newStyle.height = el.style.height;
15326
15423
  Object.assign(el.style, newStyle);
15327
15424
  el.updateGlobalTransform();
15328
- const aabb = el.getGlobalAabb();
15425
+ const aabb = el.globalAabb;
15329
15426
  const offset2 = {
15330
15427
  left: aabb.left - oldAabb.left,
15331
15428
  top: aabb.top - oldAabb.top,
@@ -15591,6 +15688,40 @@ const _statusbar = definePlugin((editor) => {
15591
15688
  ]
15592
15689
  };
15593
15690
  });
15691
+ const _test = definePlugin((editor) => {
15692
+ const {
15693
+ root,
15694
+ exec,
15695
+ drawboardAabb
15696
+ } = editor;
15697
+ function testPerformance(count2 = 500) {
15698
+ root.value.removeChildren();
15699
+ const { width, height } = drawboardAabb.value;
15700
+ for (let i = 0; i < count2; i++) {
15701
+ const size = 10 + Math.random() * 40;
15702
+ const x = Math.random() * (width - size);
15703
+ const y = Math.random() * (height - size);
15704
+ const rect = new Element2D({
15705
+ style: {
15706
+ left: x,
15707
+ top: y,
15708
+ width: size,
15709
+ height: size,
15710
+ backgroundColor: "#FFFFFF",
15711
+ borderColor: "#000000"
15712
+ }
15713
+ });
15714
+ root.value.appendChild(rect);
15715
+ }
15716
+ exec("zoomTo100");
15717
+ }
15718
+ return {
15719
+ name: "mce:test",
15720
+ commands: [
15721
+ { command: "testPerformance", handle: testPerformance }
15722
+ ]
15723
+ };
15724
+ });
15594
15725
  const _sfc_main$d = /* @__PURE__ */ defineComponent({
15595
15726
  __name: "TextEditor",
15596
15727
  setup(__props, { expose: __expose }) {
@@ -16572,6 +16703,7 @@ const plugins = [
16572
16703
  _copyAs,
16573
16704
  _drawingTool,
16574
16705
  _edit,
16706
+ _formatPaint,
16575
16707
  _frame,
16576
16708
  _gif,
16577
16709
  _history,
@@ -16600,6 +16732,7 @@ const plugins = [
16600
16732
  _smartSelection,
16601
16733
  _state,
16602
16734
  _statusbar,
16735
+ _test,
16603
16736
  _text,
16604
16737
  _timeline,
16605
16738
  _toolbelt,
@@ -17202,7 +17335,7 @@ const _sfc_main$1 = /* @__PURE__ */ defineComponent({
17202
17335
  }
17203
17336
  function onSelectArea() {
17204
17337
  selecting = true;
17205
- if (state.value !== "selecting") {
17338
+ if (state.value !== "painting" && state.value !== "selecting") {
17206
17339
  state.value = "selecting";
17207
17340
  }
17208
17341
  selectionMarquee.value.x = Math.min(start.x, current.x) - drawboardAabb.value.left;
@@ -17239,7 +17372,7 @@ const _sfc_main$1 = /* @__PURE__ */ defineComponent({
17239
17372
  }
17240
17373
  }
17241
17374
  function canStartDrag() {
17242
- return !dragging && (Math.abs(current.x - start.x) >= 3 || Math.abs(current.y - start.y) >= 3);
17375
+ return !dragging && state.value !== "painting" && (Math.abs(current.x - start.x) >= 3 || Math.abs(current.y - start.y) >= 3);
17243
17376
  }
17244
17377
  function _onEnginePointerMove(moveEvent) {
17245
17378
  if (drawing || hand) ;
@@ -17274,10 +17407,10 @@ const _sfc_main$1 = /* @__PURE__ */ defineComponent({
17274
17407
  })
17275
17408
  );
17276
17409
  } else if (hand) {
17277
- camera.value.position.add(
17278
- Math.round(prev.x - current.x),
17279
- Math.round(prev.y - current.y)
17280
- );
17410
+ camera.value.position.add({
17411
+ x: Math.round(prev.x - current.x),
17412
+ y: Math.round(prev.y - current.y)
17413
+ });
17281
17414
  } else {
17282
17415
  if (!inSelection) {
17283
17416
  if (!isIncluded(element)) {
@@ -17299,9 +17432,6 @@ const _sfc_main$1 = /* @__PURE__ */ defineComponent({
17299
17432
  } else if (hand) {
17300
17433
  grabbing.value = false;
17301
17434
  } else {
17302
- if (state.value) {
17303
- state.value = void 0;
17304
- }
17305
17435
  if (!dragging) {
17306
17436
  if (element && !selecting) {
17307
17437
  onActivate();
@@ -17319,6 +17449,17 @@ const _sfc_main$1 = /* @__PURE__ */ defineComponent({
17319
17449
  }
17320
17450
  onHover(downEvent);
17321
17451
  }
17452
+ if (state.value === "painting" || state.value === "selecting") {
17453
+ selectionMarquee.value = new Aabb2D({ x: -1, y: -1, width: 0, height: 0 });
17454
+ }
17455
+ if (state.value === "painting") {
17456
+ exec("applyFormatPaint", selected);
17457
+ if (!(upEvent?.ctrlKey || upEvent?.shiftKey || upEvent?.metaKey)) {
17458
+ exec("exitFormatPaint");
17459
+ }
17460
+ } else if (state.value) {
17461
+ state.value = void 0;
17462
+ }
17322
17463
  }
17323
17464
  renderEngine.value.off("pointermove", _onEnginePointerMove);
17324
17465
  document.removeEventListener("pointermove", _onPointerMove);
@@ -5,7 +5,9 @@ declare const _default: {
5
5
  loading: string;
6
6
  drawing: string;
7
7
  exporting: string;
8
+ painting: string;
8
9
  selecting: string;
10
+ cropping: string;
9
11
  selectObject: string;
10
12
  commitChanges: string;
11
13
  extend: string;
@@ -57,6 +59,7 @@ declare const _default: {
57
59
  paste: string;
58
60
  duplicate: string;
59
61
  delete: string;
62
+ formatPaint: string;
60
63
  selectAll: string;
61
64
  selectInverse: string;
62
65
  selectNone: string;
@@ -5,7 +5,9 @@ declare const _default: {
5
5
  loading: string;
6
6
  drawing: string;
7
7
  exporting: string;
8
+ painting: string;
8
9
  selecting: string;
10
+ cropping: string;
9
11
  selectObject: string;
10
12
  commitChanges: string;
11
13
  extend: string;
@@ -57,6 +59,7 @@ declare const _default: {
57
59
  paste: string;
58
60
  duplicate: string;
59
61
  delete: string;
62
+ formatPaint: string;
60
63
  selectAll: string;
61
64
  selectInverse: string;
62
65
  selectNone: string;
@@ -0,0 +1,12 @@
1
+ import type { Element2D } from 'modern-canvas';
2
+ declare global {
3
+ namespace Mce {
4
+ interface Commands {
5
+ formatPaint: () => void;
6
+ applyFormatPaint: (targets?: Element2D[]) => void;
7
+ exitFormatPaint: () => void;
8
+ }
9
+ }
10
+ }
11
+ declare const _default: import("..").Plugin;
12
+ export default _default;
@@ -0,0 +1,9 @@
1
+ declare global {
2
+ namespace Mce {
3
+ interface Commands {
4
+ testPerformance: (count?: number) => void;
5
+ }
6
+ }
7
+ }
8
+ declare const _default: import("..").Plugin;
9
+ export default _default;
@@ -38,6 +38,7 @@ declare global {
38
38
  | 'cropping'
39
39
  | 'imageReplacing'
40
40
  | 'shapeReplacing'
41
+ | 'painting'
41
42
  | undefined
42
43
 
43
44
  interface DrawingContext {
@@ -30,6 +30,7 @@ import './plugins/autoNest'
30
30
  import './plugins/copyAs'
31
31
  import './plugins/drawingTool'
32
32
  import './plugins/edit'
33
+ import './plugins/formatPaint'
33
34
  import './plugins/frame'
34
35
  import './plugins/gif'
35
36
  import './plugins/history'
@@ -58,6 +59,7 @@ import './plugins/smartGuides'
58
59
  import './plugins/smartSelection'
59
60
  import './plugins/state'
60
61
  import './plugins/statusbar'
62
+ import './plugins/test'
61
63
  import './plugins/text'
62
64
  import './plugins/timeline'
63
65
  import './plugins/toolbelt'
@@ -34,9 +34,6 @@ export declare class TextEditor extends HTMLElement implements PropertyAccessor
34
34
  color: string;
35
35
  };
36
36
  protected _showCursor: boolean;
37
- protected _prevSelection: [number, number] | undefined;
38
- protected _composition: boolean;
39
- get composition(): boolean;
40
37
  protected static _defined: boolean;
41
38
  static register(): void;
42
39
  protected _text: Text;
package/package.json CHANGED
@@ -1,8 +1,8 @@
1
1
  {
2
2
  "name": "mce",
3
3
  "type": "module",
4
- "version": "0.15.38",
5
- "description": "The headless canvas editor framework. only the ESM.",
4
+ "version": "0.15.39",
5
+ "description": "A headless infinite canvas editor framework built on WebGL rendering, supports exporting to image, video, and PPT. Only the ESM.",
6
6
  "author": "wxm",
7
7
  "license": "MIT",
8
8
  "homepage": "https://github.com/qq15725/mce",
@@ -55,15 +55,15 @@
55
55
  "dist"
56
56
  ],
57
57
  "dependencies": {
58
- "@floating-ui/vue": "^1.1.9",
58
+ "@floating-ui/vue": "^1.1.10",
59
59
  "@vueuse/components": "^14.1.0",
60
60
  "@vueuse/core": "^14.1.0",
61
61
  "diff": "^8.0.3",
62
62
  "file-saver": "^2.0.5",
63
- "lodash-es": "^4.17.22",
64
- "modern-canvas": "^0.14.39",
63
+ "lodash-es": "^4.17.23",
64
+ "modern-canvas": "^0.14.43",
65
65
  "modern-font": "^0.4.4",
66
- "modern-idoc": "^0.10.10",
66
+ "modern-idoc": "^0.10.18",
67
67
  "modern-text": "^1.10.15",
68
68
  "yjs": "^13.6.29"
69
69
  },
@@ -94,7 +94,7 @@
94
94
  "@vitejs/plugin-vue": "^6.0.3",
95
95
  "jiti": "^2.6.1",
96
96
  "modern-gif": "^2.0.4",
97
- "sass-embedded": "^1.97.2"
97
+ "sass-embedded": "^1.97.3"
98
98
  },
99
99
  "scripts": {
100
100
  "build:code": "vite build",