@textbus/platform-browser 4.0.0-alpha.31 → 4.0.0-alpha.33

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.
@@ -36,6 +36,7 @@ export declare class CollaborateCursor {
36
36
  private subscription;
37
37
  private currentSelection;
38
38
  private container;
39
+ private ratio;
39
40
  constructor(textbus: Textbus, nativeSelection: SelectionBridge, scheduler: Scheduler, selection: Selection, userActivity: UserActivity, awarenessDelegate?: CollaborateSelectionAwarenessDelegate | undefined);
40
41
  init(): void;
41
42
  /**
@@ -1,10 +1,18 @@
1
1
  import { Component, Slot, ViewAdapter, NodeLocation, VElement, VTextNode, Textbus } from '@textbus/core';
2
+ export interface CompositionState {
3
+ slot: Slot;
4
+ text: string;
5
+ offset: number;
6
+ index: number;
7
+ }
2
8
  /**
3
9
  * Textbus PC 端浏览器渲染能力桥接器抽象类,提供了 DOM 元素查询能力,具体渲染能力由各前端框架实现相应桥接
4
10
  */
5
11
  export declare abstract class DomAdapter<ViewComponent, ViewElement> extends ViewAdapter {
6
12
  private mount;
7
13
  host: HTMLElement;
14
+ compositionNode: HTMLElement | null;
15
+ composition: CompositionState | null;
8
16
  protected firstRending: boolean;
9
17
  protected componentRootElementCaches: {
10
18
  set: {
@@ -64,4 +72,5 @@ export declare abstract class DomAdapter<ViewComponent, ViewElement> extends Vie
64
72
  * @param node
65
73
  */
66
74
  getLocationByNativeNode(node: Node): NodeLocation | null;
75
+ protected insertCompositionByIndex(slot: Slot, vNode: VElement, composition: CompositionState, createCompositionNode: (composition: CompositionState) => VElement): void;
67
76
  }
@@ -1,5 +1,5 @@
1
1
  import 'reflect-metadata';
2
- import { Slot, Textbus, ViewAdapter, createBidirectionalMapping, Component, VElement, VTextNode, Controller, Selection, RootComponentRef, ContentType, Event, invokeListener, Keyboard, Commander, Scheduler, makeError, NativeSelectionBridge, FocusManager, Registry } from '@textbus/core';
2
+ import { Slot, Textbus, ViewAdapter, createBidirectionalMapping, Component, VTextNode, VElement, Controller, Selection, RootComponentRef, ContentType, Event, invokeListener, Keyboard, Commander, Scheduler, makeError, NativeSelectionBridge, FocusManager, Registry } from '@textbus/core';
3
3
  import { Subject, filter, fromEvent, Subscription, distinctUntilChanged, merge, map, Observable } from '@tanbo/stream';
4
4
  import { InjectionToken, Injectable, Inject, Optional } from '@viewfly/core';
5
5
  import { UserActivity } from '@textbus/collaborate';
@@ -323,6 +323,8 @@ class DomAdapter extends ViewAdapter {
323
323
  id: 'textbus-' + Number((Math.random() + '').substring(2)).toString(16)
324
324
  }
325
325
  });
326
+ this.compositionNode = null;
327
+ this.composition = null;
326
328
  this.firstRending = true;
327
329
  this.componentRootElementCaches = createBidirectionalMapping(a => {
328
330
  return a instanceof Component;
@@ -396,6 +398,70 @@ class DomAdapter extends ViewAdapter {
396
398
  const rootVNode = this.slotRootVElementCaches.get(slot);
397
399
  return getLocation(node, slotRootNode, rootVNode);
398
400
  }
401
+ insertCompositionByIndex(slot, vNode, composition, createCompositionNode) {
402
+ const location = vNode.location;
403
+ const nodes = vNode.children;
404
+ if (location && location.slot === composition.slot) {
405
+ for (let i = 0; i < nodes.length; i++) {
406
+ const child = nodes[i];
407
+ if (child instanceof VTextNode) {
408
+ const childLocation = child.location;
409
+ if (childLocation) {
410
+ if (composition.index > childLocation.startIndex && composition.index <= childLocation.endIndex) {
411
+ const compositionNode = createCompositionNode(composition);
412
+ if (composition.index === childLocation.endIndex) {
413
+ nodes.splice(i + 1, 0, compositionNode);
414
+ break;
415
+ }
416
+ const splitIndex = composition.index - childLocation.startIndex;
417
+ const beforeNode = new VTextNode(child.textContent.slice(0, splitIndex));
418
+ beforeNode.location = {
419
+ slot: childLocation.slot,
420
+ startIndex: childLocation.startIndex,
421
+ endIndex: childLocation.startIndex + splitIndex
422
+ };
423
+ const afterNode = new VTextNode(child.textContent.slice(splitIndex));
424
+ afterNode.location = {
425
+ slot: childLocation.slot,
426
+ startIndex: composition.index,
427
+ endIndex: childLocation.endIndex
428
+ };
429
+ nodes.splice(i, 1, beforeNode, compositionNode, afterNode);
430
+ break;
431
+ }
432
+ else if (composition.index === 0 && childLocation.startIndex === 0) {
433
+ nodes.unshift(createCompositionNode(composition));
434
+ break;
435
+ }
436
+ }
437
+ }
438
+ else if (child instanceof Component) {
439
+ const componentIndex = slot.indexOf(child);
440
+ if (composition.index === componentIndex + 1) {
441
+ nodes.splice(i + 1, 0, createCompositionNode(composition));
442
+ break;
443
+ }
444
+ else if (componentIndex === 0 && composition.index === 0) {
445
+ nodes.unshift(createCompositionNode(composition));
446
+ break;
447
+ }
448
+ }
449
+ else if (child.tagName === 'br') {
450
+ const location = child.location;
451
+ if (location) {
452
+ if (location.endIndex === composition.index) {
453
+ nodes.splice(i + 1, 0, createCompositionNode(composition));
454
+ break;
455
+ }
456
+ else if (location.startIndex === 0 && composition.index === 0) {
457
+ nodes.unshift(createCompositionNode(composition));
458
+ break;
459
+ }
460
+ }
461
+ }
462
+ }
463
+ }
464
+ }
399
465
  }
400
466
  function getNodes(adapter, vElement, nativeNode, result) {
401
467
  if (vElement.location) {
@@ -1032,15 +1098,10 @@ class ExperimentalCaret {
1032
1098
  get display() {
1033
1099
  return this._display;
1034
1100
  }
1035
- constructor(scheduler, editorMask) {
1101
+ constructor(adapter, scheduler, editorMask) {
1102
+ this.adapter = adapter;
1036
1103
  this.scheduler = scheduler;
1037
1104
  this.editorMask = editorMask;
1038
- this.compositionState = null;
1039
- this.compositionElement = createElement('span', {
1040
- styles: {
1041
- textDecoration: 'underline'
1042
- }
1043
- });
1044
1105
  this.timer = null;
1045
1106
  this.oldPosition = null;
1046
1107
  this._display = true;
@@ -1184,12 +1245,11 @@ class ExperimentalCaret {
1184
1245
  this.positionChangeEvent.next(null);
1185
1246
  return;
1186
1247
  }
1187
- if (this.compositionState) {
1188
- const compositionElement = this.compositionElement;
1189
- compositionElement.innerText = this.compositionState.data;
1248
+ const compositionNode = this.adapter.compositionNode;
1249
+ if (compositionNode) {
1190
1250
  nativeRange = nativeRange.cloneRange();
1191
- nativeRange.insertNode(compositionElement);
1192
- nativeRange.selectNodeContents(compositionElement);
1251
+ nativeRange.insertNode(compositionNode);
1252
+ nativeRange.selectNodeContents(compositionNode);
1193
1253
  nativeRange.collapse();
1194
1254
  }
1195
1255
  const rect = getLayoutRectByRange(nativeRange);
@@ -1250,8 +1310,9 @@ let MagicInput = class MagicInput extends Input {
1250
1310
  get disabled() {
1251
1311
  return this._disabled;
1252
1312
  }
1253
- constructor(parser, keyboard, commander, selection, controller, scheduler, textbus) {
1313
+ constructor(adapter, parser, keyboard, commander, selection, controller, scheduler, textbus) {
1254
1314
  super();
1315
+ this.adapter = adapter;
1255
1316
  this.parser = parser;
1256
1317
  this.keyboard = keyboard;
1257
1318
  this.commander = commander;
@@ -1260,8 +1321,7 @@ let MagicInput = class MagicInput extends Input {
1260
1321
  this.scheduler = scheduler;
1261
1322
  this.textbus = textbus;
1262
1323
  this.composition = false;
1263
- this.compositionState = null;
1264
- this.caret = new ExperimentalCaret(this.scheduler, this.textbus.get(VIEW_MASK));
1324
+ this.caret = new ExperimentalCaret(this.adapter, this.scheduler, this.textbus.get(VIEW_MASK));
1265
1325
  this.isSafari = isSafari();
1266
1326
  this.isFirefox = isFirefox();
1267
1327
  this.isMac = isMac();
@@ -1301,13 +1361,8 @@ let MagicInput = class MagicInput extends Input {
1301
1361
  if (!this.isFocus) {
1302
1362
  (_a = this.textarea) === null || _a === void 0 ? void 0 : _a.focus();
1303
1363
  setTimeout(() => {
1304
- var _a, _b, _c;
1305
1364
  if (!this.nativeFocus && this.isFocus) {
1306
- this.subscription.unsubscribe();
1307
- (_b = (_a = this.textarea) === null || _a === void 0 ? void 0 : _a.parentNode) === null || _b === void 0 ? void 0 : _b.removeChild(this.textarea);
1308
- this.subscription = new Subscription();
1309
- this.init();
1310
- (_c = this.textarea) === null || _c === void 0 ? void 0 : _c.focus();
1365
+ this.reInit();
1311
1366
  }
1312
1367
  });
1313
1368
  }
@@ -1323,6 +1378,22 @@ let MagicInput = class MagicInput extends Input {
1323
1378
  this.caret.destroy();
1324
1379
  this.subscription.unsubscribe();
1325
1380
  }
1381
+ reInit(delay = false) {
1382
+ var _a, _b, _c;
1383
+ this.subscription.unsubscribe();
1384
+ (_b = (_a = this.textarea) === null || _a === void 0 ? void 0 : _a.parentNode) === null || _b === void 0 ? void 0 : _b.removeChild(this.textarea);
1385
+ this.subscription = new Subscription();
1386
+ this.init();
1387
+ if (delay) {
1388
+ setTimeout(() => {
1389
+ var _a;
1390
+ (_a = this.textarea) === null || _a === void 0 ? void 0 : _a.focus();
1391
+ });
1392
+ }
1393
+ else {
1394
+ (_c = this.textarea) === null || _c === void 0 ? void 0 : _c.focus();
1395
+ }
1396
+ }
1326
1397
  init() {
1327
1398
  const doc = this.doc;
1328
1399
  const contentBody = doc.body;
@@ -1331,9 +1402,19 @@ let MagicInput = class MagicInput extends Input {
1331
1402
  contentBody.appendChild(textarea);
1332
1403
  this.textarea = textarea;
1333
1404
  this.subscription.add(fromEvent(textarea, 'blur').subscribe(() => {
1405
+ // if (this.isFocus) {
1406
+ // this.isFocus = false
1407
+ // this.reInit(true)
1408
+ // }
1334
1409
  this.isFocus = false;
1335
1410
  this.nativeFocus = false;
1336
1411
  this.caret.hide();
1412
+ if (this.adapter.composition) {
1413
+ const slot = this.adapter.composition.slot;
1414
+ this.adapter.composition = null;
1415
+ this.adapter.compositionNode = null;
1416
+ slot.changeMarker.forceMarkDirtied();
1417
+ }
1337
1418
  }), fromEvent(textarea, 'focus').subscribe(() => {
1338
1419
  this.nativeFocus = true;
1339
1420
  }), this.caret.onStyleChange.subscribe(style => {
@@ -1456,7 +1537,6 @@ let MagicInput = class MagicInput extends Input {
1456
1537
  this.commander.delete();
1457
1538
  }
1458
1539
  this.composition = true;
1459
- this.caret.compositionState = this.compositionState = null;
1460
1540
  startIndex = this.selection.startOffset;
1461
1541
  const startSlot = this.selection.startSlot;
1462
1542
  const event = new Event(startSlot, {
@@ -1473,10 +1553,11 @@ let MagicInput = class MagicInput extends Input {
1473
1553
  return;
1474
1554
  }
1475
1555
  const startSlot = this.selection.startSlot;
1476
- this.caret.compositionState = this.compositionState = {
1556
+ this.adapter.composition = {
1477
1557
  slot: startSlot,
1478
- index: startIndex,
1479
- data: ev.data
1558
+ text: ev.data,
1559
+ offset: ev.data.length,
1560
+ index: startIndex
1480
1561
  };
1481
1562
  this.caret.refresh(true);
1482
1563
  const event = new Event(startSlot, {
@@ -1484,6 +1565,7 @@ let MagicInput = class MagicInput extends Input {
1484
1565
  data: ev.data
1485
1566
  });
1486
1567
  invokeListener(startSlot.parent, 'onCompositionUpdate', event);
1568
+ startSlot.changeMarker.forceMarkDirtied();
1487
1569
  }));
1488
1570
  let isCompositionEnd = false;
1489
1571
  this.subscription.add(merge(fromEvent(textarea, 'beforeinput').pipe(filter(ev => {
@@ -1507,24 +1589,15 @@ let MagicInput = class MagicInput extends Input {
1507
1589
  textarea.value = '';
1508
1590
  return ev.data;
1509
1591
  }))).subscribe(text => {
1592
+ var _a;
1510
1593
  this.composition = false;
1511
- this.caret.compositionState = this.compositionState = null;
1512
- const compositionElement = this.caret.compositionElement;
1513
- let nextSibling = compositionElement.nextSibling;
1514
- while (nextSibling) {
1515
- if (!nextSibling.textContent) {
1516
- const next = nextSibling.nextSibling;
1517
- nextSibling.remove();
1518
- nextSibling = next;
1519
- continue;
1520
- }
1521
- nextSibling.remove();
1522
- break;
1523
- }
1524
- compositionElement.remove();
1594
+ this.adapter.composition = null;
1525
1595
  if (text) {
1526
1596
  this.commander.write(text);
1527
1597
  }
1598
+ else {
1599
+ (_a = this.selection.startSlot) === null || _a === void 0 ? void 0 : _a.changeMarker.forceMarkDirtied();
1600
+ }
1528
1601
  if (isCompositionEnd) {
1529
1602
  const startSlot = this.selection.startSlot;
1530
1603
  if (startSlot) {
@@ -1553,7 +1626,8 @@ let MagicInput = class MagicInput extends Input {
1553
1626
  };
1554
1627
  MagicInput = __decorate([
1555
1628
  Injectable(),
1556
- __metadata("design:paramtypes", [Parser,
1629
+ __metadata("design:paramtypes", [DomAdapter,
1630
+ Parser,
1557
1631
  Keyboard,
1558
1632
  Commander,
1559
1633
  Selection,
@@ -1625,6 +1699,7 @@ let CollaborateCursor = class CollaborateCursor {
1625
1699
  this.onRectsChange = new Subject();
1626
1700
  this.subscription = new Subscription();
1627
1701
  this.currentSelection = [];
1702
+ this.ratio = window.devicePixelRatio || 1;
1628
1703
  this.container = textbus.get(VIEW_CONTAINER);
1629
1704
  this.canvasContainer.append(this.canvas);
1630
1705
  this.host.append(this.canvasContainer, this.tooltips);
@@ -1668,8 +1743,9 @@ let CollaborateCursor = class CollaborateCursor {
1668
1743
  this.currentSelection = paths;
1669
1744
  const containerRect = this.container.getBoundingClientRect();
1670
1745
  this.canvas.style.top = containerRect.top * -1 + 'px';
1671
- this.canvas.width = this.canvas.offsetWidth;
1672
- this.canvas.height = this.canvas.offsetHeight;
1746
+ this.canvas.width = this.canvas.offsetWidth * this.ratio;
1747
+ this.canvas.height = this.canvas.offsetHeight * this.ratio;
1748
+ this.context.scale(this.ratio, this.ratio);
1673
1749
  this.context.clearRect(0, 0, this.canvas.width, this.canvas.height);
1674
1750
  const users = [];
1675
1751
  paths.filter(i => {
@@ -1694,8 +1770,13 @@ let CollaborateCursor = class CollaborateCursor {
1694
1770
  return;
1695
1771
  }
1696
1772
  const nativeRange = document.createRange();
1697
- nativeRange.setStart(anchor.node, anchor.offset);
1698
- nativeRange.setEnd(focus.node, focus.offset);
1773
+ try {
1774
+ nativeRange.setStart(anchor.node, anchor.offset);
1775
+ nativeRange.setEnd(focus.node, focus.offset);
1776
+ }
1777
+ catch (e) {
1778
+ return;
1779
+ }
1699
1780
  if ((anchor.node !== focus.node || anchor.offset !== focus.offset) && nativeRange.collapsed) {
1700
1781
  nativeRange.setStart(focus.node, focus.offset);
1701
1782
  nativeRange.setEnd(anchor.node, anchor.offset);
@@ -1958,7 +2039,7 @@ let NativeInput = class NativeInput extends Input {
1958
2039
  this.controller = controller;
1959
2040
  this.caret = new NativeCaret(this.scheduler);
1960
2041
  this.composition = false;
1961
- this.compositionState = null;
2042
+ // compositionState: CompositionState | null = null
1962
2043
  this.onReady = Promise.resolve();
1963
2044
  this._disabled = false;
1964
2045
  this.nativeSelection = document.getSelection();
@@ -2116,7 +2197,6 @@ let NativeInput = class NativeInput extends Input {
2116
2197
  let startIndex;
2117
2198
  const compositionStart = () => {
2118
2199
  this.composition = true;
2119
- this.compositionState = null;
2120
2200
  startIndex = this.selection.startOffset;
2121
2201
  const startSlot = this.selection.startSlot;
2122
2202
  const event = new Event(startSlot, {
@@ -2126,11 +2206,6 @@ let NativeInput = class NativeInput extends Input {
2126
2206
  };
2127
2207
  const compositionUpdate = (data) => {
2128
2208
  const startSlot = this.selection.startSlot;
2129
- this.compositionState = {
2130
- slot: startSlot,
2131
- index: startIndex,
2132
- data
2133
- };
2134
2209
  const event = new Event(startSlot, {
2135
2210
  index: startIndex,
2136
2211
  data
@@ -2217,7 +2292,6 @@ let NativeInput = class NativeInput extends Input {
2217
2292
  return !this.ignoreComposition;
2218
2293
  })).subscribe(() => {
2219
2294
  this.composition = true;
2220
- this.compositionState = null;
2221
2295
  startIndex = this.selection.startOffset;
2222
2296
  const startSlot = this.selection.startSlot;
2223
2297
  const event = new Event(startSlot, {
@@ -2228,11 +2302,6 @@ let NativeInput = class NativeInput extends Input {
2228
2302
  return !this.ignoreComposition;
2229
2303
  })).subscribe(ev => {
2230
2304
  const startSlot = this.selection.startSlot;
2231
- this.compositionState = {
2232
- slot: startSlot,
2233
- index: startIndex,
2234
- data: ev.data
2235
- };
2236
2305
  const event = new Event(startSlot, {
2237
2306
  index: startIndex,
2238
2307
  data: ev.data
@@ -2282,7 +2351,6 @@ let NativeInput = class NativeInput extends Input {
2282
2351
  return !b;
2283
2352
  }))).subscribe(text => {
2284
2353
  this.composition = false;
2285
- this.compositionState = null;
2286
2354
  if (text) {
2287
2355
  this.commander.write(text);
2288
2356
  }
package/bundles/index.js CHANGED
@@ -325,6 +325,8 @@ class DomAdapter extends core$1.ViewAdapter {
325
325
  id: 'textbus-' + Number((Math.random() + '').substring(2)).toString(16)
326
326
  }
327
327
  });
328
+ this.compositionNode = null;
329
+ this.composition = null;
328
330
  this.firstRending = true;
329
331
  this.componentRootElementCaches = core$1.createBidirectionalMapping(a => {
330
332
  return a instanceof core$1.Component;
@@ -398,6 +400,70 @@ class DomAdapter extends core$1.ViewAdapter {
398
400
  const rootVNode = this.slotRootVElementCaches.get(slot);
399
401
  return getLocation(node, slotRootNode, rootVNode);
400
402
  }
403
+ insertCompositionByIndex(slot, vNode, composition, createCompositionNode) {
404
+ const location = vNode.location;
405
+ const nodes = vNode.children;
406
+ if (location && location.slot === composition.slot) {
407
+ for (let i = 0; i < nodes.length; i++) {
408
+ const child = nodes[i];
409
+ if (child instanceof core$1.VTextNode) {
410
+ const childLocation = child.location;
411
+ if (childLocation) {
412
+ if (composition.index > childLocation.startIndex && composition.index <= childLocation.endIndex) {
413
+ const compositionNode = createCompositionNode(composition);
414
+ if (composition.index === childLocation.endIndex) {
415
+ nodes.splice(i + 1, 0, compositionNode);
416
+ break;
417
+ }
418
+ const splitIndex = composition.index - childLocation.startIndex;
419
+ const beforeNode = new core$1.VTextNode(child.textContent.slice(0, splitIndex));
420
+ beforeNode.location = {
421
+ slot: childLocation.slot,
422
+ startIndex: childLocation.startIndex,
423
+ endIndex: childLocation.startIndex + splitIndex
424
+ };
425
+ const afterNode = new core$1.VTextNode(child.textContent.slice(splitIndex));
426
+ afterNode.location = {
427
+ slot: childLocation.slot,
428
+ startIndex: composition.index,
429
+ endIndex: childLocation.endIndex
430
+ };
431
+ nodes.splice(i, 1, beforeNode, compositionNode, afterNode);
432
+ break;
433
+ }
434
+ else if (composition.index === 0 && childLocation.startIndex === 0) {
435
+ nodes.unshift(createCompositionNode(composition));
436
+ break;
437
+ }
438
+ }
439
+ }
440
+ else if (child instanceof core$1.Component) {
441
+ const componentIndex = slot.indexOf(child);
442
+ if (composition.index === componentIndex + 1) {
443
+ nodes.splice(i + 1, 0, createCompositionNode(composition));
444
+ break;
445
+ }
446
+ else if (componentIndex === 0 && composition.index === 0) {
447
+ nodes.unshift(createCompositionNode(composition));
448
+ break;
449
+ }
450
+ }
451
+ else if (child.tagName === 'br') {
452
+ const location = child.location;
453
+ if (location) {
454
+ if (location.endIndex === composition.index) {
455
+ nodes.splice(i + 1, 0, createCompositionNode(composition));
456
+ break;
457
+ }
458
+ else if (location.startIndex === 0 && composition.index === 0) {
459
+ nodes.unshift(createCompositionNode(composition));
460
+ break;
461
+ }
462
+ }
463
+ }
464
+ }
465
+ }
466
+ }
401
467
  }
402
468
  function getNodes(adapter, vElement, nativeNode, result) {
403
469
  if (vElement.location) {
@@ -1034,15 +1100,10 @@ class ExperimentalCaret {
1034
1100
  get display() {
1035
1101
  return this._display;
1036
1102
  }
1037
- constructor(scheduler, editorMask) {
1103
+ constructor(adapter, scheduler, editorMask) {
1104
+ this.adapter = adapter;
1038
1105
  this.scheduler = scheduler;
1039
1106
  this.editorMask = editorMask;
1040
- this.compositionState = null;
1041
- this.compositionElement = createElement('span', {
1042
- styles: {
1043
- textDecoration: 'underline'
1044
- }
1045
- });
1046
1107
  this.timer = null;
1047
1108
  this.oldPosition = null;
1048
1109
  this._display = true;
@@ -1186,12 +1247,11 @@ class ExperimentalCaret {
1186
1247
  this.positionChangeEvent.next(null);
1187
1248
  return;
1188
1249
  }
1189
- if (this.compositionState) {
1190
- const compositionElement = this.compositionElement;
1191
- compositionElement.innerText = this.compositionState.data;
1250
+ const compositionNode = this.adapter.compositionNode;
1251
+ if (compositionNode) {
1192
1252
  nativeRange = nativeRange.cloneRange();
1193
- nativeRange.insertNode(compositionElement);
1194
- nativeRange.selectNodeContents(compositionElement);
1253
+ nativeRange.insertNode(compositionNode);
1254
+ nativeRange.selectNodeContents(compositionNode);
1195
1255
  nativeRange.collapse();
1196
1256
  }
1197
1257
  const rect = getLayoutRectByRange(nativeRange);
@@ -1252,8 +1312,9 @@ exports.MagicInput = class MagicInput extends Input {
1252
1312
  get disabled() {
1253
1313
  return this._disabled;
1254
1314
  }
1255
- constructor(parser, keyboard, commander, selection, controller, scheduler, textbus) {
1315
+ constructor(adapter, parser, keyboard, commander, selection, controller, scheduler, textbus) {
1256
1316
  super();
1317
+ this.adapter = adapter;
1257
1318
  this.parser = parser;
1258
1319
  this.keyboard = keyboard;
1259
1320
  this.commander = commander;
@@ -1262,8 +1323,7 @@ exports.MagicInput = class MagicInput extends Input {
1262
1323
  this.scheduler = scheduler;
1263
1324
  this.textbus = textbus;
1264
1325
  this.composition = false;
1265
- this.compositionState = null;
1266
- this.caret = new ExperimentalCaret(this.scheduler, this.textbus.get(VIEW_MASK));
1326
+ this.caret = new ExperimentalCaret(this.adapter, this.scheduler, this.textbus.get(VIEW_MASK));
1267
1327
  this.isSafari = isSafari();
1268
1328
  this.isFirefox = isFirefox();
1269
1329
  this.isMac = isMac();
@@ -1303,13 +1363,8 @@ exports.MagicInput = class MagicInput extends Input {
1303
1363
  if (!this.isFocus) {
1304
1364
  (_a = this.textarea) === null || _a === void 0 ? void 0 : _a.focus();
1305
1365
  setTimeout(() => {
1306
- var _a, _b, _c;
1307
1366
  if (!this.nativeFocus && this.isFocus) {
1308
- this.subscription.unsubscribe();
1309
- (_b = (_a = this.textarea) === null || _a === void 0 ? void 0 : _a.parentNode) === null || _b === void 0 ? void 0 : _b.removeChild(this.textarea);
1310
- this.subscription = new stream.Subscription();
1311
- this.init();
1312
- (_c = this.textarea) === null || _c === void 0 ? void 0 : _c.focus();
1367
+ this.reInit();
1313
1368
  }
1314
1369
  });
1315
1370
  }
@@ -1325,6 +1380,22 @@ exports.MagicInput = class MagicInput extends Input {
1325
1380
  this.caret.destroy();
1326
1381
  this.subscription.unsubscribe();
1327
1382
  }
1383
+ reInit(delay = false) {
1384
+ var _a, _b, _c;
1385
+ this.subscription.unsubscribe();
1386
+ (_b = (_a = this.textarea) === null || _a === void 0 ? void 0 : _a.parentNode) === null || _b === void 0 ? void 0 : _b.removeChild(this.textarea);
1387
+ this.subscription = new stream.Subscription();
1388
+ this.init();
1389
+ if (delay) {
1390
+ setTimeout(() => {
1391
+ var _a;
1392
+ (_a = this.textarea) === null || _a === void 0 ? void 0 : _a.focus();
1393
+ });
1394
+ }
1395
+ else {
1396
+ (_c = this.textarea) === null || _c === void 0 ? void 0 : _c.focus();
1397
+ }
1398
+ }
1328
1399
  init() {
1329
1400
  const doc = this.doc;
1330
1401
  const contentBody = doc.body;
@@ -1333,9 +1404,19 @@ exports.MagicInput = class MagicInput extends Input {
1333
1404
  contentBody.appendChild(textarea);
1334
1405
  this.textarea = textarea;
1335
1406
  this.subscription.add(stream.fromEvent(textarea, 'blur').subscribe(() => {
1407
+ // if (this.isFocus) {
1408
+ // this.isFocus = false
1409
+ // this.reInit(true)
1410
+ // }
1336
1411
  this.isFocus = false;
1337
1412
  this.nativeFocus = false;
1338
1413
  this.caret.hide();
1414
+ if (this.adapter.composition) {
1415
+ const slot = this.adapter.composition.slot;
1416
+ this.adapter.composition = null;
1417
+ this.adapter.compositionNode = null;
1418
+ slot.changeMarker.forceMarkDirtied();
1419
+ }
1339
1420
  }), stream.fromEvent(textarea, 'focus').subscribe(() => {
1340
1421
  this.nativeFocus = true;
1341
1422
  }), this.caret.onStyleChange.subscribe(style => {
@@ -1458,7 +1539,6 @@ exports.MagicInput = class MagicInput extends Input {
1458
1539
  this.commander.delete();
1459
1540
  }
1460
1541
  this.composition = true;
1461
- this.caret.compositionState = this.compositionState = null;
1462
1542
  startIndex = this.selection.startOffset;
1463
1543
  const startSlot = this.selection.startSlot;
1464
1544
  const event = new core$1.Event(startSlot, {
@@ -1475,10 +1555,11 @@ exports.MagicInput = class MagicInput extends Input {
1475
1555
  return;
1476
1556
  }
1477
1557
  const startSlot = this.selection.startSlot;
1478
- this.caret.compositionState = this.compositionState = {
1558
+ this.adapter.composition = {
1479
1559
  slot: startSlot,
1480
- index: startIndex,
1481
- data: ev.data
1560
+ text: ev.data,
1561
+ offset: ev.data.length,
1562
+ index: startIndex
1482
1563
  };
1483
1564
  this.caret.refresh(true);
1484
1565
  const event = new core$1.Event(startSlot, {
@@ -1486,6 +1567,7 @@ exports.MagicInput = class MagicInput extends Input {
1486
1567
  data: ev.data
1487
1568
  });
1488
1569
  core$1.invokeListener(startSlot.parent, 'onCompositionUpdate', event);
1570
+ startSlot.changeMarker.forceMarkDirtied();
1489
1571
  }));
1490
1572
  let isCompositionEnd = false;
1491
1573
  this.subscription.add(stream.merge(stream.fromEvent(textarea, 'beforeinput').pipe(stream.filter(ev => {
@@ -1509,24 +1591,15 @@ exports.MagicInput = class MagicInput extends Input {
1509
1591
  textarea.value = '';
1510
1592
  return ev.data;
1511
1593
  }))).subscribe(text => {
1594
+ var _a;
1512
1595
  this.composition = false;
1513
- this.caret.compositionState = this.compositionState = null;
1514
- const compositionElement = this.caret.compositionElement;
1515
- let nextSibling = compositionElement.nextSibling;
1516
- while (nextSibling) {
1517
- if (!nextSibling.textContent) {
1518
- const next = nextSibling.nextSibling;
1519
- nextSibling.remove();
1520
- nextSibling = next;
1521
- continue;
1522
- }
1523
- nextSibling.remove();
1524
- break;
1525
- }
1526
- compositionElement.remove();
1596
+ this.adapter.composition = null;
1527
1597
  if (text) {
1528
1598
  this.commander.write(text);
1529
1599
  }
1600
+ else {
1601
+ (_a = this.selection.startSlot) === null || _a === void 0 ? void 0 : _a.changeMarker.forceMarkDirtied();
1602
+ }
1530
1603
  if (isCompositionEnd) {
1531
1604
  const startSlot = this.selection.startSlot;
1532
1605
  if (startSlot) {
@@ -1555,7 +1628,8 @@ exports.MagicInput = class MagicInput extends Input {
1555
1628
  };
1556
1629
  exports.MagicInput = __decorate([
1557
1630
  core.Injectable(),
1558
- __metadata("design:paramtypes", [exports.Parser,
1631
+ __metadata("design:paramtypes", [DomAdapter,
1632
+ exports.Parser,
1559
1633
  core$1.Keyboard,
1560
1634
  core$1.Commander,
1561
1635
  core$1.Selection,
@@ -1627,6 +1701,7 @@ exports.CollaborateCursor = class CollaborateCursor {
1627
1701
  this.onRectsChange = new stream.Subject();
1628
1702
  this.subscription = new stream.Subscription();
1629
1703
  this.currentSelection = [];
1704
+ this.ratio = window.devicePixelRatio || 1;
1630
1705
  this.container = textbus.get(VIEW_CONTAINER);
1631
1706
  this.canvasContainer.append(this.canvas);
1632
1707
  this.host.append(this.canvasContainer, this.tooltips);
@@ -1670,8 +1745,9 @@ exports.CollaborateCursor = class CollaborateCursor {
1670
1745
  this.currentSelection = paths;
1671
1746
  const containerRect = this.container.getBoundingClientRect();
1672
1747
  this.canvas.style.top = containerRect.top * -1 + 'px';
1673
- this.canvas.width = this.canvas.offsetWidth;
1674
- this.canvas.height = this.canvas.offsetHeight;
1748
+ this.canvas.width = this.canvas.offsetWidth * this.ratio;
1749
+ this.canvas.height = this.canvas.offsetHeight * this.ratio;
1750
+ this.context.scale(this.ratio, this.ratio);
1675
1751
  this.context.clearRect(0, 0, this.canvas.width, this.canvas.height);
1676
1752
  const users = [];
1677
1753
  paths.filter(i => {
@@ -1696,8 +1772,13 @@ exports.CollaborateCursor = class CollaborateCursor {
1696
1772
  return;
1697
1773
  }
1698
1774
  const nativeRange = document.createRange();
1699
- nativeRange.setStart(anchor.node, anchor.offset);
1700
- nativeRange.setEnd(focus.node, focus.offset);
1775
+ try {
1776
+ nativeRange.setStart(anchor.node, anchor.offset);
1777
+ nativeRange.setEnd(focus.node, focus.offset);
1778
+ }
1779
+ catch (e) {
1780
+ return;
1781
+ }
1701
1782
  if ((anchor.node !== focus.node || anchor.offset !== focus.offset) && nativeRange.collapsed) {
1702
1783
  nativeRange.setStart(focus.node, focus.offset);
1703
1784
  nativeRange.setEnd(anchor.node, anchor.offset);
@@ -1960,7 +2041,7 @@ let NativeInput = class NativeInput extends Input {
1960
2041
  this.controller = controller;
1961
2042
  this.caret = new NativeCaret(this.scheduler);
1962
2043
  this.composition = false;
1963
- this.compositionState = null;
2044
+ // compositionState: CompositionState | null = null
1964
2045
  this.onReady = Promise.resolve();
1965
2046
  this._disabled = false;
1966
2047
  this.nativeSelection = document.getSelection();
@@ -2118,7 +2199,6 @@ let NativeInput = class NativeInput extends Input {
2118
2199
  let startIndex;
2119
2200
  const compositionStart = () => {
2120
2201
  this.composition = true;
2121
- this.compositionState = null;
2122
2202
  startIndex = this.selection.startOffset;
2123
2203
  const startSlot = this.selection.startSlot;
2124
2204
  const event = new core$1.Event(startSlot, {
@@ -2128,11 +2208,6 @@ let NativeInput = class NativeInput extends Input {
2128
2208
  };
2129
2209
  const compositionUpdate = (data) => {
2130
2210
  const startSlot = this.selection.startSlot;
2131
- this.compositionState = {
2132
- slot: startSlot,
2133
- index: startIndex,
2134
- data
2135
- };
2136
2211
  const event = new core$1.Event(startSlot, {
2137
2212
  index: startIndex,
2138
2213
  data
@@ -2219,7 +2294,6 @@ let NativeInput = class NativeInput extends Input {
2219
2294
  return !this.ignoreComposition;
2220
2295
  })).subscribe(() => {
2221
2296
  this.composition = true;
2222
- this.compositionState = null;
2223
2297
  startIndex = this.selection.startOffset;
2224
2298
  const startSlot = this.selection.startSlot;
2225
2299
  const event = new core$1.Event(startSlot, {
@@ -2230,11 +2304,6 @@ let NativeInput = class NativeInput extends Input {
2230
2304
  return !this.ignoreComposition;
2231
2305
  })).subscribe(ev => {
2232
2306
  const startSlot = this.selection.startSlot;
2233
- this.compositionState = {
2234
- slot: startSlot,
2235
- index: startIndex,
2236
- data: ev.data
2237
- };
2238
2307
  const event = new core$1.Event(startSlot, {
2239
2308
  index: startIndex,
2240
2309
  data: ev.data
@@ -2284,7 +2353,6 @@ let NativeInput = class NativeInput extends Input {
2284
2353
  return !b;
2285
2354
  }))).subscribe(text => {
2286
2355
  this.composition = false;
2287
- this.compositionState = null;
2288
2356
  if (text) {
2289
2357
  this.commander.write(text);
2290
2358
  }
@@ -1,21 +1,21 @@
1
1
  import { Observable } from '@tanbo/stream';
2
2
  import { Commander, Controller, Keyboard, Scheduler, Selection, Textbus } from '@textbus/core';
3
3
  import { Parser } from './parser';
4
- import { Caret, CaretPosition, CompositionState, Input, Scroller } from './types';
4
+ import { Caret, CaretPosition, Input, Scroller } from './types';
5
+ import { DomAdapter } from './dom-adapter';
5
6
  interface CaretStyle {
6
7
  height: string;
7
8
  lineHeight: string;
8
9
  fontSize: string;
9
10
  }
10
11
  declare class ExperimentalCaret implements Caret {
12
+ private adapter;
11
13
  private scheduler;
12
14
  private editorMask;
13
15
  onPositionChange: Observable<CaretPosition | null>;
14
16
  onStyleChange: Observable<CaretStyle>;
15
17
  elementRef: HTMLElement;
16
- compositionState: CompositionState | null;
17
18
  get rect(): DOMRect;
18
- compositionElement: HTMLElement;
19
19
  private timer;
20
20
  private caret;
21
21
  private oldPosition;
@@ -29,7 +29,7 @@ declare class ExperimentalCaret implements Caret {
29
29
  private styleChangeEvent;
30
30
  private oldRange;
31
31
  private isFixed;
32
- constructor(scheduler: Scheduler, editorMask: HTMLElement);
32
+ constructor(adapter: DomAdapter<any, any>, scheduler: Scheduler, editorMask: HTMLElement);
33
33
  refresh(isFixedCaret?: boolean): void;
34
34
  show(range: Range, restart: boolean): void;
35
35
  hide(): void;
@@ -41,6 +41,7 @@ declare class ExperimentalCaret implements Caret {
41
41
  * Textbus PC 端输入实现
42
42
  */
43
43
  export declare class MagicInput extends Input {
44
+ private adapter;
44
45
  private parser;
45
46
  private keyboard;
46
47
  private commander;
@@ -49,7 +50,6 @@ export declare class MagicInput extends Input {
49
50
  private scheduler;
50
51
  private textbus;
51
52
  composition: boolean;
52
- compositionState: CompositionState | null;
53
53
  onReady: Promise<void>;
54
54
  caret: ExperimentalCaret;
55
55
  set disabled(b: boolean);
@@ -66,10 +66,11 @@ export declare class MagicInput extends Input {
66
66
  private isFocus;
67
67
  private nativeFocus;
68
68
  private ignoreComposition;
69
- constructor(parser: Parser, keyboard: Keyboard, commander: Commander, selection: Selection, controller: Controller, scheduler: Scheduler, textbus: Textbus);
69
+ constructor(adapter: DomAdapter<any, any>, parser: Parser, keyboard: Keyboard, commander: Commander, selection: Selection, controller: Controller, scheduler: Scheduler, textbus: Textbus);
70
70
  focus(range: Range, restart: boolean): void;
71
71
  blur(): void;
72
72
  destroy(): void;
73
+ private reInit;
73
74
  private init;
74
75
  private handleDefaultActions;
75
76
  private handlePaste;
@@ -1,6 +1,6 @@
1
1
  import { Observable } from '@tanbo/stream';
2
2
  import { Commander, Controller, Keyboard, Scheduler, Selection, Textbus } from '@textbus/core';
3
- import { Caret, CaretPosition, CompositionState, Input, Scroller } from './types';
3
+ import { Caret, CaretPosition, Input, Scroller } from './types';
4
4
  import { Parser } from './parser';
5
5
  import { DomAdapter } from './dom-adapter';
6
6
  declare class NativeCaret implements Caret {
@@ -28,7 +28,6 @@ export declare class NativeInput extends Input {
28
28
  private controller;
29
29
  caret: NativeCaret;
30
30
  composition: boolean;
31
- compositionState: CompositionState | null;
32
31
  onReady: Promise<void>;
33
32
  set disabled(b: boolean);
34
33
  get disabled(): boolean;
@@ -1,4 +1,3 @@
1
- import { Slot } from '@textbus/core';
2
1
  import { Observable } from '@tanbo/stream';
3
2
  import { Rect } from './_utils/uikit';
4
3
  export interface CaretLimit {
@@ -21,11 +20,6 @@ export interface Caret {
21
20
  refresh(isFixedCaret: boolean): void;
22
21
  correctScrollTop(scroller: Scroller): void;
23
22
  }
24
- export interface CompositionState {
25
- slot: Slot;
26
- index: number;
27
- data: string;
28
- }
29
23
  export declare abstract class Input {
30
24
  /**
31
25
  * @experimental
@@ -34,7 +28,6 @@ export declare abstract class Input {
34
28
  /**
35
29
  * @experimental
36
30
  */
37
- abstract compositionState: CompositionState | null;
38
31
  abstract onReady: Promise<void>;
39
32
  abstract caret: Caret;
40
33
  abstract disabled: boolean;
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@textbus/platform-browser",
3
- "version": "4.0.0-alpha.31",
3
+ "version": "4.0.0-alpha.33",
4
4
  "description": "Textbus is a rich text editor and framework that is highly customizable and extensible to achieve rich wysiwyg effects.",
5
5
  "main": "./bundles/index.js",
6
6
  "module": "./bundles/index.esm.js",
@@ -26,9 +26,9 @@
26
26
  ],
27
27
  "dependencies": {
28
28
  "@tanbo/stream": "^1.2.3",
29
- "@textbus/collaborate": "^4.0.0-alpha.31",
30
- "@textbus/core": "^4.0.0-alpha.31",
31
- "@viewfly/core": "^0.6.1",
29
+ "@textbus/collaborate": "^4.0.0-alpha.33",
30
+ "@textbus/core": "^4.0.0-alpha.33",
31
+ "@viewfly/core": "^0.6.3",
32
32
  "reflect-metadata": "^0.1.13"
33
33
  },
34
34
  "devDependencies": {
@@ -49,5 +49,5 @@
49
49
  "bugs": {
50
50
  "url": "https://github.com/textbus/textbus.git/issues"
51
51
  },
52
- "gitHead": "54c13967d549e9c3795eb821d84ce3e811139630"
52
+ "gitHead": "5eb73f9a388d331946a8579aa6eaa23cc44bffe0"
53
53
  }