@textbus/platform-browser 4.0.0-alpha.32 → 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();
@@ -1342,12 +1402,19 @@ let MagicInput = class MagicInput extends Input {
1342
1402
  contentBody.appendChild(textarea);
1343
1403
  this.textarea = textarea;
1344
1404
  this.subscription.add(fromEvent(textarea, 'blur').subscribe(() => {
1345
- if (this.isFocus) {
1346
- this.isFocus = false;
1347
- this.reInit(true);
1348
- }
1405
+ // if (this.isFocus) {
1406
+ // this.isFocus = false
1407
+ // this.reInit(true)
1408
+ // }
1409
+ this.isFocus = false;
1349
1410
  this.nativeFocus = false;
1350
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
+ }
1351
1418
  }), fromEvent(textarea, 'focus').subscribe(() => {
1352
1419
  this.nativeFocus = true;
1353
1420
  }), this.caret.onStyleChange.subscribe(style => {
@@ -1470,7 +1537,6 @@ let MagicInput = class MagicInput extends Input {
1470
1537
  this.commander.delete();
1471
1538
  }
1472
1539
  this.composition = true;
1473
- this.caret.compositionState = this.compositionState = null;
1474
1540
  startIndex = this.selection.startOffset;
1475
1541
  const startSlot = this.selection.startSlot;
1476
1542
  const event = new Event(startSlot, {
@@ -1487,10 +1553,11 @@ let MagicInput = class MagicInput extends Input {
1487
1553
  return;
1488
1554
  }
1489
1555
  const startSlot = this.selection.startSlot;
1490
- this.caret.compositionState = this.compositionState = {
1556
+ this.adapter.composition = {
1491
1557
  slot: startSlot,
1492
- index: startIndex,
1493
- data: ev.data
1558
+ text: ev.data,
1559
+ offset: ev.data.length,
1560
+ index: startIndex
1494
1561
  };
1495
1562
  this.caret.refresh(true);
1496
1563
  const event = new Event(startSlot, {
@@ -1498,6 +1565,7 @@ let MagicInput = class MagicInput extends Input {
1498
1565
  data: ev.data
1499
1566
  });
1500
1567
  invokeListener(startSlot.parent, 'onCompositionUpdate', event);
1568
+ startSlot.changeMarker.forceMarkDirtied();
1501
1569
  }));
1502
1570
  let isCompositionEnd = false;
1503
1571
  this.subscription.add(merge(fromEvent(textarea, 'beforeinput').pipe(filter(ev => {
@@ -1521,24 +1589,15 @@ let MagicInput = class MagicInput extends Input {
1521
1589
  textarea.value = '';
1522
1590
  return ev.data;
1523
1591
  }))).subscribe(text => {
1592
+ var _a;
1524
1593
  this.composition = false;
1525
- this.caret.compositionState = this.compositionState = null;
1526
- const compositionElement = this.caret.compositionElement;
1527
- let nextSibling = compositionElement.nextSibling;
1528
- while (nextSibling) {
1529
- if (!nextSibling.textContent) {
1530
- const next = nextSibling.nextSibling;
1531
- nextSibling.remove();
1532
- nextSibling = next;
1533
- continue;
1534
- }
1535
- nextSibling.remove();
1536
- break;
1537
- }
1538
- compositionElement.remove();
1594
+ this.adapter.composition = null;
1539
1595
  if (text) {
1540
1596
  this.commander.write(text);
1541
1597
  }
1598
+ else {
1599
+ (_a = this.selection.startSlot) === null || _a === void 0 ? void 0 : _a.changeMarker.forceMarkDirtied();
1600
+ }
1542
1601
  if (isCompositionEnd) {
1543
1602
  const startSlot = this.selection.startSlot;
1544
1603
  if (startSlot) {
@@ -1567,7 +1626,8 @@ let MagicInput = class MagicInput extends Input {
1567
1626
  };
1568
1627
  MagicInput = __decorate([
1569
1628
  Injectable(),
1570
- __metadata("design:paramtypes", [Parser,
1629
+ __metadata("design:paramtypes", [DomAdapter,
1630
+ Parser,
1571
1631
  Keyboard,
1572
1632
  Commander,
1573
1633
  Selection,
@@ -1639,6 +1699,7 @@ let CollaborateCursor = class CollaborateCursor {
1639
1699
  this.onRectsChange = new Subject();
1640
1700
  this.subscription = new Subscription();
1641
1701
  this.currentSelection = [];
1702
+ this.ratio = window.devicePixelRatio || 1;
1642
1703
  this.container = textbus.get(VIEW_CONTAINER);
1643
1704
  this.canvasContainer.append(this.canvas);
1644
1705
  this.host.append(this.canvasContainer, this.tooltips);
@@ -1682,8 +1743,9 @@ let CollaborateCursor = class CollaborateCursor {
1682
1743
  this.currentSelection = paths;
1683
1744
  const containerRect = this.container.getBoundingClientRect();
1684
1745
  this.canvas.style.top = containerRect.top * -1 + 'px';
1685
- this.canvas.width = this.canvas.offsetWidth;
1686
- 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);
1687
1749
  this.context.clearRect(0, 0, this.canvas.width, this.canvas.height);
1688
1750
  const users = [];
1689
1751
  paths.filter(i => {
@@ -1708,8 +1770,13 @@ let CollaborateCursor = class CollaborateCursor {
1708
1770
  return;
1709
1771
  }
1710
1772
  const nativeRange = document.createRange();
1711
- nativeRange.setStart(anchor.node, anchor.offset);
1712
- 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
+ }
1713
1780
  if ((anchor.node !== focus.node || anchor.offset !== focus.offset) && nativeRange.collapsed) {
1714
1781
  nativeRange.setStart(focus.node, focus.offset);
1715
1782
  nativeRange.setEnd(anchor.node, anchor.offset);
@@ -1972,7 +2039,7 @@ let NativeInput = class NativeInput extends Input {
1972
2039
  this.controller = controller;
1973
2040
  this.caret = new NativeCaret(this.scheduler);
1974
2041
  this.composition = false;
1975
- this.compositionState = null;
2042
+ // compositionState: CompositionState | null = null
1976
2043
  this.onReady = Promise.resolve();
1977
2044
  this._disabled = false;
1978
2045
  this.nativeSelection = document.getSelection();
@@ -2130,7 +2197,6 @@ let NativeInput = class NativeInput extends Input {
2130
2197
  let startIndex;
2131
2198
  const compositionStart = () => {
2132
2199
  this.composition = true;
2133
- this.compositionState = null;
2134
2200
  startIndex = this.selection.startOffset;
2135
2201
  const startSlot = this.selection.startSlot;
2136
2202
  const event = new Event(startSlot, {
@@ -2140,11 +2206,6 @@ let NativeInput = class NativeInput extends Input {
2140
2206
  };
2141
2207
  const compositionUpdate = (data) => {
2142
2208
  const startSlot = this.selection.startSlot;
2143
- this.compositionState = {
2144
- slot: startSlot,
2145
- index: startIndex,
2146
- data
2147
- };
2148
2209
  const event = new Event(startSlot, {
2149
2210
  index: startIndex,
2150
2211
  data
@@ -2231,7 +2292,6 @@ let NativeInput = class NativeInput extends Input {
2231
2292
  return !this.ignoreComposition;
2232
2293
  })).subscribe(() => {
2233
2294
  this.composition = true;
2234
- this.compositionState = null;
2235
2295
  startIndex = this.selection.startOffset;
2236
2296
  const startSlot = this.selection.startSlot;
2237
2297
  const event = new Event(startSlot, {
@@ -2242,11 +2302,6 @@ let NativeInput = class NativeInput extends Input {
2242
2302
  return !this.ignoreComposition;
2243
2303
  })).subscribe(ev => {
2244
2304
  const startSlot = this.selection.startSlot;
2245
- this.compositionState = {
2246
- slot: startSlot,
2247
- index: startIndex,
2248
- data: ev.data
2249
- };
2250
2305
  const event = new Event(startSlot, {
2251
2306
  index: startIndex,
2252
2307
  data: ev.data
@@ -2296,7 +2351,6 @@ let NativeInput = class NativeInput extends Input {
2296
2351
  return !b;
2297
2352
  }))).subscribe(text => {
2298
2353
  this.composition = false;
2299
- this.compositionState = null;
2300
2354
  if (text) {
2301
2355
  this.commander.write(text);
2302
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();
@@ -1344,12 +1404,19 @@ exports.MagicInput = class MagicInput extends Input {
1344
1404
  contentBody.appendChild(textarea);
1345
1405
  this.textarea = textarea;
1346
1406
  this.subscription.add(stream.fromEvent(textarea, 'blur').subscribe(() => {
1347
- if (this.isFocus) {
1348
- this.isFocus = false;
1349
- this.reInit(true);
1350
- }
1407
+ // if (this.isFocus) {
1408
+ // this.isFocus = false
1409
+ // this.reInit(true)
1410
+ // }
1411
+ this.isFocus = false;
1351
1412
  this.nativeFocus = false;
1352
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
+ }
1353
1420
  }), stream.fromEvent(textarea, 'focus').subscribe(() => {
1354
1421
  this.nativeFocus = true;
1355
1422
  }), this.caret.onStyleChange.subscribe(style => {
@@ -1472,7 +1539,6 @@ exports.MagicInput = class MagicInput extends Input {
1472
1539
  this.commander.delete();
1473
1540
  }
1474
1541
  this.composition = true;
1475
- this.caret.compositionState = this.compositionState = null;
1476
1542
  startIndex = this.selection.startOffset;
1477
1543
  const startSlot = this.selection.startSlot;
1478
1544
  const event = new core$1.Event(startSlot, {
@@ -1489,10 +1555,11 @@ exports.MagicInput = class MagicInput extends Input {
1489
1555
  return;
1490
1556
  }
1491
1557
  const startSlot = this.selection.startSlot;
1492
- this.caret.compositionState = this.compositionState = {
1558
+ this.adapter.composition = {
1493
1559
  slot: startSlot,
1494
- index: startIndex,
1495
- data: ev.data
1560
+ text: ev.data,
1561
+ offset: ev.data.length,
1562
+ index: startIndex
1496
1563
  };
1497
1564
  this.caret.refresh(true);
1498
1565
  const event = new core$1.Event(startSlot, {
@@ -1500,6 +1567,7 @@ exports.MagicInput = class MagicInput extends Input {
1500
1567
  data: ev.data
1501
1568
  });
1502
1569
  core$1.invokeListener(startSlot.parent, 'onCompositionUpdate', event);
1570
+ startSlot.changeMarker.forceMarkDirtied();
1503
1571
  }));
1504
1572
  let isCompositionEnd = false;
1505
1573
  this.subscription.add(stream.merge(stream.fromEvent(textarea, 'beforeinput').pipe(stream.filter(ev => {
@@ -1523,24 +1591,15 @@ exports.MagicInput = class MagicInput extends Input {
1523
1591
  textarea.value = '';
1524
1592
  return ev.data;
1525
1593
  }))).subscribe(text => {
1594
+ var _a;
1526
1595
  this.composition = false;
1527
- this.caret.compositionState = this.compositionState = null;
1528
- const compositionElement = this.caret.compositionElement;
1529
- let nextSibling = compositionElement.nextSibling;
1530
- while (nextSibling) {
1531
- if (!nextSibling.textContent) {
1532
- const next = nextSibling.nextSibling;
1533
- nextSibling.remove();
1534
- nextSibling = next;
1535
- continue;
1536
- }
1537
- nextSibling.remove();
1538
- break;
1539
- }
1540
- compositionElement.remove();
1596
+ this.adapter.composition = null;
1541
1597
  if (text) {
1542
1598
  this.commander.write(text);
1543
1599
  }
1600
+ else {
1601
+ (_a = this.selection.startSlot) === null || _a === void 0 ? void 0 : _a.changeMarker.forceMarkDirtied();
1602
+ }
1544
1603
  if (isCompositionEnd) {
1545
1604
  const startSlot = this.selection.startSlot;
1546
1605
  if (startSlot) {
@@ -1569,7 +1628,8 @@ exports.MagicInput = class MagicInput extends Input {
1569
1628
  };
1570
1629
  exports.MagicInput = __decorate([
1571
1630
  core.Injectable(),
1572
- __metadata("design:paramtypes", [exports.Parser,
1631
+ __metadata("design:paramtypes", [DomAdapter,
1632
+ exports.Parser,
1573
1633
  core$1.Keyboard,
1574
1634
  core$1.Commander,
1575
1635
  core$1.Selection,
@@ -1641,6 +1701,7 @@ exports.CollaborateCursor = class CollaborateCursor {
1641
1701
  this.onRectsChange = new stream.Subject();
1642
1702
  this.subscription = new stream.Subscription();
1643
1703
  this.currentSelection = [];
1704
+ this.ratio = window.devicePixelRatio || 1;
1644
1705
  this.container = textbus.get(VIEW_CONTAINER);
1645
1706
  this.canvasContainer.append(this.canvas);
1646
1707
  this.host.append(this.canvasContainer, this.tooltips);
@@ -1684,8 +1745,9 @@ exports.CollaborateCursor = class CollaborateCursor {
1684
1745
  this.currentSelection = paths;
1685
1746
  const containerRect = this.container.getBoundingClientRect();
1686
1747
  this.canvas.style.top = containerRect.top * -1 + 'px';
1687
- this.canvas.width = this.canvas.offsetWidth;
1688
- 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);
1689
1751
  this.context.clearRect(0, 0, this.canvas.width, this.canvas.height);
1690
1752
  const users = [];
1691
1753
  paths.filter(i => {
@@ -1710,8 +1772,13 @@ exports.CollaborateCursor = class CollaborateCursor {
1710
1772
  return;
1711
1773
  }
1712
1774
  const nativeRange = document.createRange();
1713
- nativeRange.setStart(anchor.node, anchor.offset);
1714
- 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
+ }
1715
1782
  if ((anchor.node !== focus.node || anchor.offset !== focus.offset) && nativeRange.collapsed) {
1716
1783
  nativeRange.setStart(focus.node, focus.offset);
1717
1784
  nativeRange.setEnd(anchor.node, anchor.offset);
@@ -1974,7 +2041,7 @@ let NativeInput = class NativeInput extends Input {
1974
2041
  this.controller = controller;
1975
2042
  this.caret = new NativeCaret(this.scheduler);
1976
2043
  this.composition = false;
1977
- this.compositionState = null;
2044
+ // compositionState: CompositionState | null = null
1978
2045
  this.onReady = Promise.resolve();
1979
2046
  this._disabled = false;
1980
2047
  this.nativeSelection = document.getSelection();
@@ -2132,7 +2199,6 @@ let NativeInput = class NativeInput extends Input {
2132
2199
  let startIndex;
2133
2200
  const compositionStart = () => {
2134
2201
  this.composition = true;
2135
- this.compositionState = null;
2136
2202
  startIndex = this.selection.startOffset;
2137
2203
  const startSlot = this.selection.startSlot;
2138
2204
  const event = new core$1.Event(startSlot, {
@@ -2142,11 +2208,6 @@ let NativeInput = class NativeInput extends Input {
2142
2208
  };
2143
2209
  const compositionUpdate = (data) => {
2144
2210
  const startSlot = this.selection.startSlot;
2145
- this.compositionState = {
2146
- slot: startSlot,
2147
- index: startIndex,
2148
- data
2149
- };
2150
2211
  const event = new core$1.Event(startSlot, {
2151
2212
  index: startIndex,
2152
2213
  data
@@ -2233,7 +2294,6 @@ let NativeInput = class NativeInput extends Input {
2233
2294
  return !this.ignoreComposition;
2234
2295
  })).subscribe(() => {
2235
2296
  this.composition = true;
2236
- this.compositionState = null;
2237
2297
  startIndex = this.selection.startOffset;
2238
2298
  const startSlot = this.selection.startSlot;
2239
2299
  const event = new core$1.Event(startSlot, {
@@ -2244,11 +2304,6 @@ let NativeInput = class NativeInput extends Input {
2244
2304
  return !this.ignoreComposition;
2245
2305
  })).subscribe(ev => {
2246
2306
  const startSlot = this.selection.startSlot;
2247
- this.compositionState = {
2248
- slot: startSlot,
2249
- index: startIndex,
2250
- data: ev.data
2251
- };
2252
2307
  const event = new core$1.Event(startSlot, {
2253
2308
  index: startIndex,
2254
2309
  data: ev.data
@@ -2298,7 +2353,6 @@ let NativeInput = class NativeInput extends Input {
2298
2353
  return !b;
2299
2354
  }))).subscribe(text => {
2300
2355
  this.composition = false;
2301
- this.compositionState = null;
2302
2356
  if (text) {
2303
2357
  this.commander.write(text);
2304
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,7 +66,7 @@ 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;
@@ -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.32",
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": "00d52c23dde48068e14e46379b85ddac0743c6ff"
52
+ "gitHead": "5eb73f9a388d331946a8579aa6eaa23cc44bffe0"
53
53
  }