@textbus/platform-browser 4.0.0-alpha.32 → 4.0.0-alpha.34

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,10 @@ 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.selectNodeContents(compositionNode);
1193
1252
  nativeRange.collapse();
1194
1253
  }
1195
1254
  const rect = getLayoutRectByRange(nativeRange);
@@ -1250,8 +1309,9 @@ let MagicInput = class MagicInput extends Input {
1250
1309
  get disabled() {
1251
1310
  return this._disabled;
1252
1311
  }
1253
- constructor(parser, keyboard, commander, selection, controller, scheduler, textbus) {
1312
+ constructor(adapter, parser, keyboard, commander, selection, controller, scheduler, textbus) {
1254
1313
  super();
1314
+ this.adapter = adapter;
1255
1315
  this.parser = parser;
1256
1316
  this.keyboard = keyboard;
1257
1317
  this.commander = commander;
@@ -1260,8 +1320,7 @@ let MagicInput = class MagicInput extends Input {
1260
1320
  this.scheduler = scheduler;
1261
1321
  this.textbus = textbus;
1262
1322
  this.composition = false;
1263
- this.compositionState = null;
1264
- this.caret = new ExperimentalCaret(this.scheduler, this.textbus.get(VIEW_MASK));
1323
+ this.caret = new ExperimentalCaret(this.adapter, this.scheduler, this.textbus.get(VIEW_MASK));
1265
1324
  this.isSafari = isSafari();
1266
1325
  this.isFirefox = isFirefox();
1267
1326
  this.isMac = isMac();
@@ -1342,12 +1401,19 @@ let MagicInput = class MagicInput extends Input {
1342
1401
  contentBody.appendChild(textarea);
1343
1402
  this.textarea = textarea;
1344
1403
  this.subscription.add(fromEvent(textarea, 'blur').subscribe(() => {
1345
- if (this.isFocus) {
1346
- this.isFocus = false;
1347
- this.reInit(true);
1348
- }
1404
+ // if (this.isFocus) {
1405
+ // this.isFocus = false
1406
+ // this.reInit(true)
1407
+ // }
1408
+ this.isFocus = false;
1349
1409
  this.nativeFocus = false;
1350
1410
  this.caret.hide();
1411
+ if (this.adapter.composition) {
1412
+ const slot = this.adapter.composition.slot;
1413
+ this.adapter.composition = null;
1414
+ this.adapter.compositionNode = null;
1415
+ slot.changeMarker.forceMarkDirtied();
1416
+ }
1351
1417
  }), fromEvent(textarea, 'focus').subscribe(() => {
1352
1418
  this.nativeFocus = true;
1353
1419
  }), this.caret.onStyleChange.subscribe(style => {
@@ -1470,7 +1536,6 @@ let MagicInput = class MagicInput extends Input {
1470
1536
  this.commander.delete();
1471
1537
  }
1472
1538
  this.composition = true;
1473
- this.caret.compositionState = this.compositionState = null;
1474
1539
  startIndex = this.selection.startOffset;
1475
1540
  const startSlot = this.selection.startSlot;
1476
1541
  const event = new Event(startSlot, {
@@ -1487,10 +1552,11 @@ let MagicInput = class MagicInput extends Input {
1487
1552
  return;
1488
1553
  }
1489
1554
  const startSlot = this.selection.startSlot;
1490
- this.caret.compositionState = this.compositionState = {
1555
+ this.adapter.composition = {
1491
1556
  slot: startSlot,
1492
- index: startIndex,
1493
- data: ev.data
1557
+ text: ev.data,
1558
+ offset: ev.data.length,
1559
+ index: startIndex
1494
1560
  };
1495
1561
  this.caret.refresh(true);
1496
1562
  const event = new Event(startSlot, {
@@ -1498,6 +1564,7 @@ let MagicInput = class MagicInput extends Input {
1498
1564
  data: ev.data
1499
1565
  });
1500
1566
  invokeListener(startSlot.parent, 'onCompositionUpdate', event);
1567
+ startSlot.changeMarker.forceMarkDirtied();
1501
1568
  }));
1502
1569
  let isCompositionEnd = false;
1503
1570
  this.subscription.add(merge(fromEvent(textarea, 'beforeinput').pipe(filter(ev => {
@@ -1521,24 +1588,15 @@ let MagicInput = class MagicInput extends Input {
1521
1588
  textarea.value = '';
1522
1589
  return ev.data;
1523
1590
  }))).subscribe(text => {
1591
+ var _a;
1524
1592
  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();
1593
+ this.adapter.composition = null;
1539
1594
  if (text) {
1540
1595
  this.commander.write(text);
1541
1596
  }
1597
+ else {
1598
+ (_a = this.selection.startSlot) === null || _a === void 0 ? void 0 : _a.changeMarker.forceMarkDirtied();
1599
+ }
1542
1600
  if (isCompositionEnd) {
1543
1601
  const startSlot = this.selection.startSlot;
1544
1602
  if (startSlot) {
@@ -1567,7 +1625,8 @@ let MagicInput = class MagicInput extends Input {
1567
1625
  };
1568
1626
  MagicInput = __decorate([
1569
1627
  Injectable(),
1570
- __metadata("design:paramtypes", [Parser,
1628
+ __metadata("design:paramtypes", [DomAdapter,
1629
+ Parser,
1571
1630
  Keyboard,
1572
1631
  Commander,
1573
1632
  Selection,
@@ -1639,6 +1698,7 @@ let CollaborateCursor = class CollaborateCursor {
1639
1698
  this.onRectsChange = new Subject();
1640
1699
  this.subscription = new Subscription();
1641
1700
  this.currentSelection = [];
1701
+ this.ratio = window.devicePixelRatio || 1;
1642
1702
  this.container = textbus.get(VIEW_CONTAINER);
1643
1703
  this.canvasContainer.append(this.canvas);
1644
1704
  this.host.append(this.canvasContainer, this.tooltips);
@@ -1682,8 +1742,9 @@ let CollaborateCursor = class CollaborateCursor {
1682
1742
  this.currentSelection = paths;
1683
1743
  const containerRect = this.container.getBoundingClientRect();
1684
1744
  this.canvas.style.top = containerRect.top * -1 + 'px';
1685
- this.canvas.width = this.canvas.offsetWidth;
1686
- this.canvas.height = this.canvas.offsetHeight;
1745
+ this.canvas.width = this.canvas.offsetWidth * this.ratio;
1746
+ this.canvas.height = this.canvas.offsetHeight * this.ratio;
1747
+ this.context.scale(this.ratio, this.ratio);
1687
1748
  this.context.clearRect(0, 0, this.canvas.width, this.canvas.height);
1688
1749
  const users = [];
1689
1750
  paths.filter(i => {
@@ -1708,8 +1769,13 @@ let CollaborateCursor = class CollaborateCursor {
1708
1769
  return;
1709
1770
  }
1710
1771
  const nativeRange = document.createRange();
1711
- nativeRange.setStart(anchor.node, anchor.offset);
1712
- nativeRange.setEnd(focus.node, focus.offset);
1772
+ try {
1773
+ nativeRange.setStart(anchor.node, anchor.offset);
1774
+ nativeRange.setEnd(focus.node, focus.offset);
1775
+ }
1776
+ catch (e) {
1777
+ return;
1778
+ }
1713
1779
  if ((anchor.node !== focus.node || anchor.offset !== focus.offset) && nativeRange.collapsed) {
1714
1780
  nativeRange.setStart(focus.node, focus.offset);
1715
1781
  nativeRange.setEnd(anchor.node, anchor.offset);
@@ -1972,7 +2038,7 @@ let NativeInput = class NativeInput extends Input {
1972
2038
  this.controller = controller;
1973
2039
  this.caret = new NativeCaret(this.scheduler);
1974
2040
  this.composition = false;
1975
- this.compositionState = null;
2041
+ // compositionState: CompositionState | null = null
1976
2042
  this.onReady = Promise.resolve();
1977
2043
  this._disabled = false;
1978
2044
  this.nativeSelection = document.getSelection();
@@ -2130,7 +2196,6 @@ let NativeInput = class NativeInput extends Input {
2130
2196
  let startIndex;
2131
2197
  const compositionStart = () => {
2132
2198
  this.composition = true;
2133
- this.compositionState = null;
2134
2199
  startIndex = this.selection.startOffset;
2135
2200
  const startSlot = this.selection.startSlot;
2136
2201
  const event = new Event(startSlot, {
@@ -2140,11 +2205,6 @@ let NativeInput = class NativeInput extends Input {
2140
2205
  };
2141
2206
  const compositionUpdate = (data) => {
2142
2207
  const startSlot = this.selection.startSlot;
2143
- this.compositionState = {
2144
- slot: startSlot,
2145
- index: startIndex,
2146
- data
2147
- };
2148
2208
  const event = new Event(startSlot, {
2149
2209
  index: startIndex,
2150
2210
  data
@@ -2231,7 +2291,6 @@ let NativeInput = class NativeInput extends Input {
2231
2291
  return !this.ignoreComposition;
2232
2292
  })).subscribe(() => {
2233
2293
  this.composition = true;
2234
- this.compositionState = null;
2235
2294
  startIndex = this.selection.startOffset;
2236
2295
  const startSlot = this.selection.startSlot;
2237
2296
  const event = new Event(startSlot, {
@@ -2242,11 +2301,6 @@ let NativeInput = class NativeInput extends Input {
2242
2301
  return !this.ignoreComposition;
2243
2302
  })).subscribe(ev => {
2244
2303
  const startSlot = this.selection.startSlot;
2245
- this.compositionState = {
2246
- slot: startSlot,
2247
- index: startIndex,
2248
- data: ev.data
2249
- };
2250
2304
  const event = new Event(startSlot, {
2251
2305
  index: startIndex,
2252
2306
  data: ev.data
@@ -2296,7 +2350,6 @@ let NativeInput = class NativeInput extends Input {
2296
2350
  return !b;
2297
2351
  }))).subscribe(text => {
2298
2352
  this.composition = false;
2299
- this.compositionState = null;
2300
2353
  if (text) {
2301
2354
  this.commander.write(text);
2302
2355
  }
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,10 @@ 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.selectNodeContents(compositionNode);
1195
1254
  nativeRange.collapse();
1196
1255
  }
1197
1256
  const rect = getLayoutRectByRange(nativeRange);
@@ -1252,8 +1311,9 @@ exports.MagicInput = class MagicInput extends Input {
1252
1311
  get disabled() {
1253
1312
  return this._disabled;
1254
1313
  }
1255
- constructor(parser, keyboard, commander, selection, controller, scheduler, textbus) {
1314
+ constructor(adapter, parser, keyboard, commander, selection, controller, scheduler, textbus) {
1256
1315
  super();
1316
+ this.adapter = adapter;
1257
1317
  this.parser = parser;
1258
1318
  this.keyboard = keyboard;
1259
1319
  this.commander = commander;
@@ -1262,8 +1322,7 @@ exports.MagicInput = class MagicInput extends Input {
1262
1322
  this.scheduler = scheduler;
1263
1323
  this.textbus = textbus;
1264
1324
  this.composition = false;
1265
- this.compositionState = null;
1266
- this.caret = new ExperimentalCaret(this.scheduler, this.textbus.get(VIEW_MASK));
1325
+ this.caret = new ExperimentalCaret(this.adapter, this.scheduler, this.textbus.get(VIEW_MASK));
1267
1326
  this.isSafari = isSafari();
1268
1327
  this.isFirefox = isFirefox();
1269
1328
  this.isMac = isMac();
@@ -1344,12 +1403,19 @@ exports.MagicInput = class MagicInput extends Input {
1344
1403
  contentBody.appendChild(textarea);
1345
1404
  this.textarea = textarea;
1346
1405
  this.subscription.add(stream.fromEvent(textarea, 'blur').subscribe(() => {
1347
- if (this.isFocus) {
1348
- this.isFocus = false;
1349
- this.reInit(true);
1350
- }
1406
+ // if (this.isFocus) {
1407
+ // this.isFocus = false
1408
+ // this.reInit(true)
1409
+ // }
1410
+ this.isFocus = false;
1351
1411
  this.nativeFocus = false;
1352
1412
  this.caret.hide();
1413
+ if (this.adapter.composition) {
1414
+ const slot = this.adapter.composition.slot;
1415
+ this.adapter.composition = null;
1416
+ this.adapter.compositionNode = null;
1417
+ slot.changeMarker.forceMarkDirtied();
1418
+ }
1353
1419
  }), stream.fromEvent(textarea, 'focus').subscribe(() => {
1354
1420
  this.nativeFocus = true;
1355
1421
  }), this.caret.onStyleChange.subscribe(style => {
@@ -1472,7 +1538,6 @@ exports.MagicInput = class MagicInput extends Input {
1472
1538
  this.commander.delete();
1473
1539
  }
1474
1540
  this.composition = true;
1475
- this.caret.compositionState = this.compositionState = null;
1476
1541
  startIndex = this.selection.startOffset;
1477
1542
  const startSlot = this.selection.startSlot;
1478
1543
  const event = new core$1.Event(startSlot, {
@@ -1489,10 +1554,11 @@ exports.MagicInput = class MagicInput extends Input {
1489
1554
  return;
1490
1555
  }
1491
1556
  const startSlot = this.selection.startSlot;
1492
- this.caret.compositionState = this.compositionState = {
1557
+ this.adapter.composition = {
1493
1558
  slot: startSlot,
1494
- index: startIndex,
1495
- data: ev.data
1559
+ text: ev.data,
1560
+ offset: ev.data.length,
1561
+ index: startIndex
1496
1562
  };
1497
1563
  this.caret.refresh(true);
1498
1564
  const event = new core$1.Event(startSlot, {
@@ -1500,6 +1566,7 @@ exports.MagicInput = class MagicInput extends Input {
1500
1566
  data: ev.data
1501
1567
  });
1502
1568
  core$1.invokeListener(startSlot.parent, 'onCompositionUpdate', event);
1569
+ startSlot.changeMarker.forceMarkDirtied();
1503
1570
  }));
1504
1571
  let isCompositionEnd = false;
1505
1572
  this.subscription.add(stream.merge(stream.fromEvent(textarea, 'beforeinput').pipe(stream.filter(ev => {
@@ -1523,24 +1590,15 @@ exports.MagicInput = class MagicInput extends Input {
1523
1590
  textarea.value = '';
1524
1591
  return ev.data;
1525
1592
  }))).subscribe(text => {
1593
+ var _a;
1526
1594
  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();
1595
+ this.adapter.composition = null;
1541
1596
  if (text) {
1542
1597
  this.commander.write(text);
1543
1598
  }
1599
+ else {
1600
+ (_a = this.selection.startSlot) === null || _a === void 0 ? void 0 : _a.changeMarker.forceMarkDirtied();
1601
+ }
1544
1602
  if (isCompositionEnd) {
1545
1603
  const startSlot = this.selection.startSlot;
1546
1604
  if (startSlot) {
@@ -1569,7 +1627,8 @@ exports.MagicInput = class MagicInput extends Input {
1569
1627
  };
1570
1628
  exports.MagicInput = __decorate([
1571
1629
  core.Injectable(),
1572
- __metadata("design:paramtypes", [exports.Parser,
1630
+ __metadata("design:paramtypes", [DomAdapter,
1631
+ exports.Parser,
1573
1632
  core$1.Keyboard,
1574
1633
  core$1.Commander,
1575
1634
  core$1.Selection,
@@ -1641,6 +1700,7 @@ exports.CollaborateCursor = class CollaborateCursor {
1641
1700
  this.onRectsChange = new stream.Subject();
1642
1701
  this.subscription = new stream.Subscription();
1643
1702
  this.currentSelection = [];
1703
+ this.ratio = window.devicePixelRatio || 1;
1644
1704
  this.container = textbus.get(VIEW_CONTAINER);
1645
1705
  this.canvasContainer.append(this.canvas);
1646
1706
  this.host.append(this.canvasContainer, this.tooltips);
@@ -1684,8 +1744,9 @@ exports.CollaborateCursor = class CollaborateCursor {
1684
1744
  this.currentSelection = paths;
1685
1745
  const containerRect = this.container.getBoundingClientRect();
1686
1746
  this.canvas.style.top = containerRect.top * -1 + 'px';
1687
- this.canvas.width = this.canvas.offsetWidth;
1688
- this.canvas.height = this.canvas.offsetHeight;
1747
+ this.canvas.width = this.canvas.offsetWidth * this.ratio;
1748
+ this.canvas.height = this.canvas.offsetHeight * this.ratio;
1749
+ this.context.scale(this.ratio, this.ratio);
1689
1750
  this.context.clearRect(0, 0, this.canvas.width, this.canvas.height);
1690
1751
  const users = [];
1691
1752
  paths.filter(i => {
@@ -1710,8 +1771,13 @@ exports.CollaborateCursor = class CollaborateCursor {
1710
1771
  return;
1711
1772
  }
1712
1773
  const nativeRange = document.createRange();
1713
- nativeRange.setStart(anchor.node, anchor.offset);
1714
- nativeRange.setEnd(focus.node, focus.offset);
1774
+ try {
1775
+ nativeRange.setStart(anchor.node, anchor.offset);
1776
+ nativeRange.setEnd(focus.node, focus.offset);
1777
+ }
1778
+ catch (e) {
1779
+ return;
1780
+ }
1715
1781
  if ((anchor.node !== focus.node || anchor.offset !== focus.offset) && nativeRange.collapsed) {
1716
1782
  nativeRange.setStart(focus.node, focus.offset);
1717
1783
  nativeRange.setEnd(anchor.node, anchor.offset);
@@ -1974,7 +2040,7 @@ let NativeInput = class NativeInput extends Input {
1974
2040
  this.controller = controller;
1975
2041
  this.caret = new NativeCaret(this.scheduler);
1976
2042
  this.composition = false;
1977
- this.compositionState = null;
2043
+ // compositionState: CompositionState | null = null
1978
2044
  this.onReady = Promise.resolve();
1979
2045
  this._disabled = false;
1980
2046
  this.nativeSelection = document.getSelection();
@@ -2132,7 +2198,6 @@ let NativeInput = class NativeInput extends Input {
2132
2198
  let startIndex;
2133
2199
  const compositionStart = () => {
2134
2200
  this.composition = true;
2135
- this.compositionState = null;
2136
2201
  startIndex = this.selection.startOffset;
2137
2202
  const startSlot = this.selection.startSlot;
2138
2203
  const event = new core$1.Event(startSlot, {
@@ -2142,11 +2207,6 @@ let NativeInput = class NativeInput extends Input {
2142
2207
  };
2143
2208
  const compositionUpdate = (data) => {
2144
2209
  const startSlot = this.selection.startSlot;
2145
- this.compositionState = {
2146
- slot: startSlot,
2147
- index: startIndex,
2148
- data
2149
- };
2150
2210
  const event = new core$1.Event(startSlot, {
2151
2211
  index: startIndex,
2152
2212
  data
@@ -2233,7 +2293,6 @@ let NativeInput = class NativeInput extends Input {
2233
2293
  return !this.ignoreComposition;
2234
2294
  })).subscribe(() => {
2235
2295
  this.composition = true;
2236
- this.compositionState = null;
2237
2296
  startIndex = this.selection.startOffset;
2238
2297
  const startSlot = this.selection.startSlot;
2239
2298
  const event = new core$1.Event(startSlot, {
@@ -2244,11 +2303,6 @@ let NativeInput = class NativeInput extends Input {
2244
2303
  return !this.ignoreComposition;
2245
2304
  })).subscribe(ev => {
2246
2305
  const startSlot = this.selection.startSlot;
2247
- this.compositionState = {
2248
- slot: startSlot,
2249
- index: startIndex,
2250
- data: ev.data
2251
- };
2252
2306
  const event = new core$1.Event(startSlot, {
2253
2307
  index: startIndex,
2254
2308
  data: ev.data
@@ -2298,7 +2352,6 @@ let NativeInput = class NativeInput extends Input {
2298
2352
  return !b;
2299
2353
  }))).subscribe(text => {
2300
2354
  this.composition = false;
2301
- this.compositionState = null;
2302
2355
  if (text) {
2303
2356
  this.commander.write(text);
2304
2357
  }
@@ -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.34",
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.34",
30
+ "@textbus/core": "^4.0.0-alpha.34",
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": "b6f9bfbce3135865fc0c8a3e6b622a7040019634"
53
53
  }