mce 0.12.0 → 0.12.2

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/dist/index.d.ts CHANGED
@@ -17,4 +17,4 @@ export * from './plugins';
17
17
  export * from './types';
18
18
  export * from './utils';
19
19
  export type { Camera2D, Element2D, Engine } from 'modern-canvas';
20
- export type { Element, NormalizedElement } from 'modern-idoc';
20
+ export type { Document, Element, NormalizedElement } from 'modern-idoc';
package/dist/index.js CHANGED
@@ -124,26 +124,7 @@ const _0_config_base = defineMixin((editor, options) => {
124
124
  registerConfig("typographyStrategy", "autoHeight");
125
125
  registerConfig("handleShape", "rect");
126
126
  registerConfig("localDb", false);
127
- const screenCenterOffset = { left: 0, top: 0, bottom: 0, right: 0 };
128
- registerConfig("screenCenterOffset", { ...screenCenterOffset });
129
- const getScreenCenterOffset = () => {
130
- const offset2 = {
131
- ...screenCenterOffset,
132
- ...config.value.screenCenterOffset
133
- };
134
- if (config.value.scrollbar) {
135
- offset2.right += 8;
136
- offset2.bottom += 8;
137
- }
138
- if (config.value.ruler) {
139
- offset2.left += 16;
140
- offset2.top += 16;
141
- }
142
- return offset2;
143
- };
144
- Object.assign(editor, {
145
- getScreenCenterOffset
146
- });
127
+ registerConfig("screenCenterOffset", { left: 0, top: 0, bottom: 0, right: 0 });
147
128
  return () => {
148
129
  const {
149
130
  camera,
@@ -667,6 +648,10 @@ class Doc extends Model {
667
648
  this.reset();
668
649
  this.addElements(children);
669
650
  this.setProperties(props);
651
+ this._yProps.clear();
652
+ for (const key in props) {
653
+ this._yProps.set(key, props[key]);
654
+ }
670
655
  this._yProps.set("meta", new Y.Map(Object.entries(meta)));
671
656
  return this;
672
657
  }
@@ -998,6 +983,30 @@ const _0_font = defineMixin((editor, options) => {
998
983
  }
999
984
  };
1000
985
  });
986
+ const _0_helper = defineMixin((editor) => {
987
+ const block = ["top", "bottom"];
988
+ const inline = ["start", "end", "left", "right"];
989
+ function toPhysical(str, isRtl) {
990
+ if (str === "start")
991
+ return isRtl ? "right" : "left";
992
+ if (str === "end")
993
+ return isRtl ? "left" : "right";
994
+ return str;
995
+ }
996
+ const parseAnchor = (anchor, isRtl) => {
997
+ let [side, align] = anchor.split(" ");
998
+ if (!align) {
999
+ align = block.includes(side) ? "start" : inline.includes(side) ? "top" : "center";
1000
+ }
1001
+ return {
1002
+ side: toPhysical(side, isRtl),
1003
+ align: toPhysical(align, isRtl)
1004
+ };
1005
+ };
1006
+ Object.assign(editor, {
1007
+ parseAnchor
1008
+ });
1009
+ });
1001
1010
  const en = {
1002
1011
  "cancel": "Cancel",
1003
1012
  "constrainToAxis": "Constrain to axis",
@@ -1561,6 +1570,41 @@ const _1_hotkey = defineMixin((editor) => {
1561
1570
  );
1562
1571
  };
1563
1572
  });
1573
+ const _1_screen = defineMixin((editor) => {
1574
+ const {
1575
+ config,
1576
+ drawboardAabb
1577
+ } = editor;
1578
+ const getScreenCenterOffset = () => {
1579
+ const offset2 = {
1580
+ left: 0,
1581
+ top: 0,
1582
+ bottom: 0,
1583
+ right: 0,
1584
+ ...config.value.screenCenterOffset
1585
+ };
1586
+ if (config.value.scrollbar) {
1587
+ offset2.right += 8;
1588
+ offset2.bottom += 8;
1589
+ }
1590
+ if (config.value.ruler) {
1591
+ offset2.left += 16;
1592
+ offset2.top += 16;
1593
+ }
1594
+ return offset2;
1595
+ };
1596
+ const getScreenCenter = () => {
1597
+ const offset2 = getScreenCenterOffset();
1598
+ return {
1599
+ x: offset2.left + (drawboardAabb.value.width - offset2.left - offset2.right) / 2,
1600
+ y: offset2.top + (drawboardAabb.value.height - offset2.top - offset2.bottom) / 2
1601
+ };
1602
+ };
1603
+ Object.assign(editor, {
1604
+ getScreenCenterOffset,
1605
+ getScreenCenter
1606
+ });
1607
+ });
1564
1608
  const _1_timeline = defineMixin((editor) => {
1565
1609
  const {
1566
1610
  root,
@@ -2187,49 +2231,48 @@ const _4_2_element = defineMixin((editor) => {
2187
2231
  getAncestorFrame,
2188
2232
  getAabb,
2189
2233
  getGlobalPointer,
2190
- selection
2234
+ getScreenCenter,
2235
+ selection,
2236
+ camera,
2237
+ parseAnchor
2191
2238
  } = editor;
2192
2239
  function addElement(value, options = {}) {
2193
2240
  log("addElement", value, options);
2241
+ const {
2242
+ frameGap
2243
+ } = config.value;
2194
2244
  let {
2195
- frame,
2196
- positionToFit,
2245
+ parent,
2197
2246
  sizeToFit,
2198
2247
  position,
2199
- inPointerPosition,
2200
2248
  active,
2201
2249
  regenId
2202
2250
  } = options;
2203
- if (!position && inPointerPosition) {
2204
- position = getGlobalPointer();
2205
- }
2206
- if (position) {
2207
- positionToFit = false;
2208
- }
2209
- if (!frame) {
2251
+ if (!parent) {
2210
2252
  if (config.value.viewMode === "frame") {
2211
- frame = currentFrame.value;
2253
+ parent = currentFrame.value;
2212
2254
  } else {
2213
2255
  const element = selection.value[0];
2214
2256
  if (element) {
2215
2257
  if (isFrame(element)) {
2216
- frame = element;
2258
+ parent = element;
2217
2259
  } else {
2218
- frame = getAncestorFrame(element);
2260
+ parent = getAncestorFrame(element);
2219
2261
  }
2220
2262
  }
2221
2263
  }
2222
2264
  }
2223
- let top = rootAabb.value.top;
2224
- const left = rootAabb.value.left + rootAabb.value.width + config.value.frameGap;
2225
2265
  const isArray = Array.isArray(value);
2226
2266
  let offsetX = 0;
2227
2267
  const elements = doc.value.transact(() => {
2228
2268
  const values = isArray ? value : [value];
2229
2269
  const elements2 = values.map((element) => {
2230
- const el = doc.value.addElement(element, { parentId: frame?.id, regenId });
2231
- if (frame) {
2232
- const { width, height } = frame.style;
2270
+ const el = doc.value.addElement(element, {
2271
+ parentId: parent?.id,
2272
+ regenId
2273
+ });
2274
+ if (parent) {
2275
+ const { width, height } = parent.style;
2233
2276
  const halfWidth = width / 2;
2234
2277
  const halfHeight = height / 2;
2235
2278
  if (!el.style.width)
@@ -2250,31 +2293,99 @@ const _4_2_element = defineMixin((editor) => {
2250
2293
  }
2251
2294
  );
2252
2295
  }
2253
- if (positionToFit) {
2254
- el.style.left = Math.round(width - el.style.width) / 2;
2255
- el.style.top = Math.round(height - el.style.height) / 2;
2256
- }
2257
- } else {
2258
- if (positionToFit) {
2259
- el.style.top = Math.round(top);
2260
- el.style.left = Math.round(left);
2261
- top += el.style.height + config.value.frameGap;
2262
- }
2263
2296
  }
2264
2297
  el.style.left += offsetX;
2265
2298
  offsetX += el.style.width;
2266
2299
  return el;
2267
2300
  });
2268
2301
  const aabb = getAabb(elements2);
2269
- if (position) {
2302
+ const parentAabb = parent ? getAabb(parent) : void 0;
2303
+ let globalPosition;
2304
+ if (typeof position === "string") {
2305
+ switch (position) {
2306
+ case "pointer":
2307
+ break;
2308
+ case "screenCenter":
2309
+ globalPosition = camera.value.toGlobal(getScreenCenter());
2310
+ break;
2311
+ default: {
2312
+ const _parentAabb = parentAabb ?? rootAabb.value;
2313
+ const anchor = parseAnchor(position);
2314
+ globalPosition = { x: 0, y: 0 };
2315
+ const map = {
2316
+ centerX: () => globalPosition.x = _parentAabb.left + _parentAabb.width / 2,
2317
+ centerY: () => globalPosition.y = _parentAabb.top + _parentAabb.height / 2
2318
+ };
2319
+ if (anchor.side === "center") {
2320
+ map.centerX();
2321
+ map.centerY();
2322
+ } else {
2323
+ if (anchor.side === "left" || anchor.side === "right") {
2324
+ switch (anchor.side) {
2325
+ case "left":
2326
+ globalPosition.x = _parentAabb.left - (aabb.width + frameGap);
2327
+ break;
2328
+ case "right":
2329
+ globalPosition.x = _parentAabb.left + _parentAabb.width + frameGap;
2330
+ break;
2331
+ }
2332
+ switch (anchor.align) {
2333
+ case "top":
2334
+ globalPosition.y = _parentAabb.top;
2335
+ break;
2336
+ case "bottom":
2337
+ globalPosition.y = _parentAabb.top + _parentAabb.height;
2338
+ break;
2339
+ case "center":
2340
+ map.centerY();
2341
+ break;
2342
+ }
2343
+ } else if (anchor.side === "top" || anchor.side === "bottom") {
2344
+ switch (anchor.side) {
2345
+ case "top":
2346
+ globalPosition.y = _parentAabb.top - (aabb.height + frameGap);
2347
+ break;
2348
+ case "bottom":
2349
+ globalPosition.y = _parentAabb.top + _parentAabb.height + frameGap;
2350
+ break;
2351
+ }
2352
+ switch (anchor.align) {
2353
+ case "left":
2354
+ globalPosition.x = _parentAabb.left;
2355
+ break;
2356
+ case "right":
2357
+ globalPosition.x = _parentAabb.left + _parentAabb.width;
2358
+ break;
2359
+ case "center":
2360
+ map.centerX();
2361
+ break;
2362
+ }
2363
+ }
2364
+ }
2365
+ break;
2366
+ }
2367
+ }
2368
+ }
2369
+ if (position === "pointer") {
2370
+ const pointer = getGlobalPointer();
2270
2371
  const diff = {
2271
- x: Math.round(position.x - aabb.left),
2272
- y: Math.round(position.y - aabb.top)
2372
+ x: Math.round(pointer.x - aabb.left),
2373
+ y: Math.round(pointer.y - aabb.top)
2273
2374
  };
2274
2375
  elements2.forEach((el) => {
2275
2376
  el.style.left += diff.x;
2276
2377
  el.style.top += diff.y;
2277
2378
  });
2379
+ } else if (globalPosition) {
2380
+ elements2.forEach((el) => {
2381
+ el.style.left = Math.round(
2382
+ parentAabb ? parentAabb.left - globalPosition.x : globalPosition.x
2383
+ );
2384
+ el.style.top = Math.round(
2385
+ parentAabb ? parentAabb.top - globalPosition.y : globalPosition.y
2386
+ );
2387
+ globalPosition.x += el.style.width + frameGap;
2388
+ });
2278
2389
  }
2279
2390
  return elements2;
2280
2391
  });
@@ -2487,17 +2598,18 @@ const _4_4_doc = defineMixin((editor, options) => {
2487
2598
  }
2488
2599
  const setDoc = async (source) => {
2489
2600
  let id;
2601
+ let _source = source;
2490
2602
  if (typeof source === "string") {
2491
2603
  id = source;
2492
2604
  } else if (source) {
2493
2605
  if (Array.isArray(source) && source.length === 1) {
2494
- source = source[0];
2606
+ _source = source[0];
2495
2607
  }
2496
2608
  if (!Array.isArray(source)) {
2497
2609
  if (source.meta?.inEditorIs === "Doc") {
2498
2610
  id = source.id;
2499
2611
  } else {
2500
- source = [source];
2612
+ _source = [source];
2501
2613
  }
2502
2614
  }
2503
2615
  }
@@ -2506,7 +2618,7 @@ const _4_4_doc = defineMixin((editor, options) => {
2506
2618
  try {
2507
2619
  await waitUntilFontLoad();
2508
2620
  clearDoc();
2509
- await initDoc(_doc, source);
2621
+ await initDoc(_doc, _source);
2510
2622
  doc.value = _doc;
2511
2623
  emit("setDoc", _doc);
2512
2624
  } finally {
@@ -2542,8 +2654,7 @@ const _scroll$1 = defineMixin((editor) => {
2542
2654
  getAabb,
2543
2655
  selectionAabb,
2544
2656
  viewAabb,
2545
- drawboardAabb,
2546
- getScreenCenterOffset
2657
+ getScreenCenter
2547
2658
  } = editor;
2548
2659
  const scrollTo = async (target, options = {}) => {
2549
2660
  const {
@@ -2551,7 +2662,7 @@ const _scroll$1 = defineMixin((editor) => {
2551
2662
  duration = 500
2552
2663
  } = options;
2553
2664
  const _camera = camera.value;
2554
- const screenCenterOffset = getScreenCenterOffset();
2665
+ const screenCenter = getScreenCenter();
2555
2666
  const offset2 = { x: 0, y: 0 };
2556
2667
  let position = { x: 0, y: 0 };
2557
2668
  if (typeof target === "object" && "x" in target && "y" in target) {
@@ -2573,10 +2684,8 @@ const _scroll$1 = defineMixin((editor) => {
2573
2684
  }
2574
2685
  }
2575
2686
  position = { x: aabb.left + aabb.width / 2, y: aabb.top + aabb.height / 2 };
2576
- offset2.x -= screenCenterOffset.left;
2577
- offset2.y -= screenCenterOffset.top;
2578
- offset2.x -= (drawboardAabb.value.width - screenCenterOffset.left - screenCenterOffset.right) / 2;
2579
- offset2.y -= (drawboardAabb.value.height - screenCenterOffset.top - screenCenterOffset.bottom) / 2;
2687
+ offset2.x += -screenCenter.x;
2688
+ offset2.y = -screenCenter.y;
2580
2689
  }
2581
2690
  position.x *= _camera.zoom.x;
2582
2691
  position.x += offset2.x;
@@ -2684,8 +2793,8 @@ const _snapshot = defineMixin((editor) => {
2684
2793
  const sh = aabb.height * zoom.y;
2685
2794
  ctx.drawImage(
2686
2795
  view,
2687
- (aabb.left * zoom.x + position.x) * pixelRatio,
2688
- (aabb.top * zoom.x + position.y) * pixelRatio,
2796
+ (aabb.left * zoom.x - position.x) * pixelRatio,
2797
+ (aabb.top * zoom.x - position.y) * pixelRatio,
2689
2798
  sw * pixelRatio,
2690
2799
  sh * pixelRatio,
2691
2800
  0,
@@ -2844,9 +2953,11 @@ const mixins = [
2844
2953
  _0_context,
2845
2954
  _0_element,
2846
2955
  _0_font,
2956
+ _0_helper,
2847
2957
  _0_locale,
2848
2958
  _1_frame,
2849
2959
  _1_hotkey,
2960
+ _1_screen,
2850
2961
  _1_timeline,
2851
2962
  _1_upload,
2852
2963
  _2_box,
@@ -4233,7 +4344,7 @@ const _clipboard = definePlugin((editor, options) => {
4233
4344
  }
4234
4345
  if (elements.length) {
4235
4346
  addElement(elements, {
4236
- inPointerPosition: true,
4347
+ position: "pointer",
4237
4348
  active: true,
4238
4349
  regenId: true
4239
4350
  });
@@ -4254,6 +4365,17 @@ const _clipboard = definePlugin((editor, options) => {
4254
4365
  }
4255
4366
  break;
4256
4367
  }
4368
+ case "string":
4369
+ switch (item.type) {
4370
+ case "application/json": {
4371
+ const json = await new Promise((r) => item.getAsString(r));
4372
+ const blob = new Blob([json], { type: item.type });
4373
+ const file = new File([blob], "data.json", { type: item.type });
4374
+ items.push(new ClipboardItem({ [item.type]: file }));
4375
+ break;
4376
+ }
4377
+ }
4378
+ break;
4257
4379
  }
4258
4380
  }
4259
4381
  } else {
@@ -4273,7 +4395,7 @@ const _clipboard = definePlugin((editor, options) => {
4273
4395
  } else if (copiedData.value) {
4274
4396
  if (Array.isArray(copiedData.value)) {
4275
4397
  addElement(copiedData.value?.map((el) => cloneDeep(el)) ?? [], {
4276
- inPointerPosition: true,
4398
+ position: "pointer",
4277
4399
  active: true,
4278
4400
  regenId: true
4279
4401
  });
@@ -4669,7 +4791,7 @@ const _image = definePlugin((editor) => {
4669
4791
  const insertImage = async (url, options) => {
4670
4792
  return addElement(await createImageElement(url), {
4671
4793
  sizeToFit: true,
4672
- positionToFit: true,
4794
+ position: "right",
4673
4795
  ...options
4674
4796
  });
4675
4797
  };
@@ -4748,7 +4870,7 @@ const _import = definePlugin((editor) => {
4748
4870
  return addElement((await Promise.all(files.map((file) => load(file)))).flat(), {
4749
4871
  ...options,
4750
4872
  sizeToFit: true,
4751
- positionToFit: true
4873
+ position: "right"
4752
4874
  });
4753
4875
  };
4754
4876
  return {
@@ -4842,9 +4964,7 @@ const _json = definePlugin((editor) => {
4842
4964
  elements = selection.value;
4843
4965
  }
4844
4966
  if (elements.length === 0 && root.value) {
4845
- if (root.value.meta.id) {
4846
- id = root.value.meta.id;
4847
- }
4967
+ id = root.value.id;
4848
4968
  elements = root.value.children;
4849
4969
  }
4850
4970
  }
@@ -4871,6 +4991,7 @@ const _json = definePlugin((editor) => {
4871
4991
  }),
4872
4992
  meta: {
4873
4993
  inPptIs: "Pptx",
4994
+ inEditorIs: "Doc",
4874
4995
  inCanvasIs: "Element2D",
4875
4996
  ...getTimeRange(elements)
4876
4997
  }
@@ -5384,7 +5505,7 @@ const _text = definePlugin((editor) => {
5384
5505
  const { style, ...restOptions } = options;
5385
5506
  return addElement(createTextElement(content, style), {
5386
5507
  sizeToFit: true,
5387
- positionToFit: true,
5508
+ position: "right",
5388
5509
  ...restOptions
5389
5510
  });
5390
5511
  };
@@ -6337,7 +6458,7 @@ const _sfc_main$v = /* @__PURE__ */ defineComponent({
6337
6458
  const style = computed(() => {
6338
6459
  return {
6339
6460
  ...floatingStyles.value,
6340
- zIndex: 2e3 + overlayItem.index.value
6461
+ zIndex: 1500 + overlayItem.index.value
6341
6462
  };
6342
6463
  });
6343
6464
  const activatorProps = computed(() => {
@@ -8296,7 +8417,7 @@ const _sfc_main$9 = /* @__PURE__ */ defineComponent({
8296
8417
  const { zoom, position } = camera.value;
8297
8418
  return {
8298
8419
  transformOrigin: "left top",
8299
- transform: `translate(${position.x}px, ${position.y}px) scale(${zoom.x}, ${zoom.y})`
8420
+ transform: `translate(${-position.x}px, ${-position.y}px) scale(${zoom.x}, ${zoom.y})`
8300
8421
  };
8301
8422
  });
8302
8423
  const textEditorStyle = computed(() => {
@@ -30,9 +30,6 @@ declare global {
30
30
  localDb: boolean;
31
31
  screenCenterOffset: ScreenCenterOffset;
32
32
  }
33
- interface Editor {
34
- getScreenCenterOffset: () => Required<ScreenCenterOffset>;
35
- }
36
33
  }
37
34
  }
38
35
  declare const _default: import("../..").Mixin;
@@ -0,0 +1,22 @@
1
+ declare global {
2
+ namespace Mce {
3
+ type Tblock = 'top' | 'bottom';
4
+ type Tinline = 'start' | 'end' | 'left' | 'right';
5
+ type Anchor = Tblock | Tinline | 'center' | 'center center' | `${Tblock} ${Tinline | 'center'}` | `${Tinline} ${Tblock | 'center'}`;
6
+ type ParsedAnchor = {
7
+ side: 'center';
8
+ align: 'center';
9
+ } | {
10
+ side: Tblock;
11
+ align: 'left' | 'right' | 'center';
12
+ } | {
13
+ side: 'left' | 'right';
14
+ align: Tblock | 'center';
15
+ };
16
+ interface Editor {
17
+ parseAnchor: (anchor: Anchor, isRtl?: boolean) => ParsedAnchor;
18
+ }
19
+ }
20
+ }
21
+ declare const _default: import("..").Mixin;
22
+ export default _default;
@@ -0,0 +1,13 @@
1
+ declare global {
2
+ namespace Mce {
3
+ interface Editor {
4
+ getScreenCenterOffset: () => Required<ScreenCenterOffset>;
5
+ getScreenCenter: () => {
6
+ x: number;
7
+ y: number;
8
+ };
9
+ }
10
+ }
11
+ }
12
+ declare const _default: import("..").Mixin;
13
+ export default _default;
@@ -3,12 +3,12 @@ import type { Element } from 'modern-idoc';
3
3
  import type { AxisAlignedBoundingBox } from '../types';
4
4
  declare global {
5
5
  namespace Mce {
6
+ type AddElementPosition = Vector2Data | Anchor | 'screenCenter' | 'pointer';
6
7
  interface AddElementOptions {
7
- frame?: Element2D;
8
- positionToFit?: boolean;
8
+ parent?: Element2D;
9
+ position?: AddElementPosition;
10
+ append?: boolean;
9
11
  sizeToFit?: boolean;
10
- position?: Vector2Data;
11
- inPointerPosition?: boolean;
12
12
  active?: boolean;
13
13
  regenId?: boolean;
14
14
  }
@@ -2,14 +2,22 @@ import type { Document, Element } from 'modern-idoc';
2
2
  import { Doc } from '../models';
3
3
  declare global {
4
4
  namespace Mce {
5
+ interface InternalDocument extends Document {
6
+ id: string;
7
+ meta: {
8
+ [key: string]: any;
9
+ inEditorIs: 'Doc';
10
+ };
11
+ }
12
+ type DocumentSource = InternalDocument | Element[] | string;
5
13
  interface Editor {
6
14
  getDoc: () => JsonData;
7
- setDoc: (doc: Document | Element[] | string) => Promise<Doc>;
15
+ setDoc: (doc: DocumentSource) => Promise<Doc>;
8
16
  loadDoc: (source: any) => Promise<Doc>;
9
17
  clearDoc: () => void;
10
18
  }
11
19
  interface Options {
12
- doc?: Document | string;
20
+ doc?: DocumentSource;
13
21
  }
14
22
  interface Events {
15
23
  setDoc: [doc: Doc];
@@ -12,7 +12,8 @@ declare global {
12
12
  children: NormalizedElement[];
13
13
  meta: {
14
14
  inPptIs: 'Pptx';
15
- inCanvasIs: 'Node2D';
15
+ inEditorIs: 'Doc';
16
+ inCanvasIs: 'Element2D';
16
17
  startTime: number;
17
18
  endTime: number;
18
19
  };
@@ -8,9 +8,11 @@ import './mixins/0.config/base'
8
8
  import './mixins/0.context'
9
9
  import './mixins/0.element'
10
10
  import './mixins/0.font'
11
+ import './mixins/0.helper'
11
12
  import './mixins/0.locale'
12
13
  import './mixins/1.frame'
13
14
  import './mixins/1.hotkey'
15
+ import './mixins/1.screen'
14
16
  import './mixins/1.timeline'
15
17
  import './mixins/1.upload'
16
18
  import './mixins/2.box'
package/package.json CHANGED
@@ -1,7 +1,7 @@
1
1
  {
2
2
  "name": "mce",
3
3
  "type": "module",
4
- "version": "0.12.0",
4
+ "version": "0.12.2",
5
5
  "description": "The headless canvas editor framework. only the ESM.",
6
6
  "author": "wxm",
7
7
  "license": "MIT",