@textbus/platform-browser 4.0.0-alpha.5 → 4.0.0-alpha.51

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.
@@ -1,7 +1,8 @@
1
1
  import 'reflect-metadata';
2
- import { Slot, ViewAdapter, createBidirectionalMapping, ComponentInstance, VElement, VTextNode, Controller, Selection, RootComponentRef, ContentType, Event, invokeListener, Keyboard, Commander, Scheduler, NativeSelectionBridge } from '@textbus/core';
3
- import { InjectionToken, Injectable, Inject, Injector, Optional } from '@viewfly/core';
2
+ import { Slot, Textbus, Adapter, Controller, Selection, RootComponentRef, ContentType, Event, invokeListener, Keyboard, Commander, Scheduler, makeError, NativeSelectionBridge, FocusManager, Component, Registry } from '@textbus/core';
4
3
  import { Subject, filter, fromEvent, Subscription, distinctUntilChanged, merge, map, Observable } from '@tanbo/stream';
4
+ import { InjectionToken, Injectable, Inject, Optional } from '@viewfly/core';
5
+ import { UserActivity } from '@textbus/collaborate';
5
6
 
6
7
  function createElement(tagName, options = {}) {
7
8
  const el = document.createElement(tagName);
@@ -166,9 +167,9 @@ let Parser = Parser_1 = class Parser {
166
167
  static parseHTML(html) {
167
168
  return new DOMParser().parseFromString(html, 'text/html').body;
168
169
  }
169
- constructor(options, injector) {
170
+ constructor(options, textbus) {
170
171
  this.options = options;
171
- this.injector = injector;
172
+ this.textbus = textbus;
172
173
  const componentLoaders = [
173
174
  ...(options.componentLoaders || [])
174
175
  ];
@@ -193,7 +194,7 @@ let Parser = Parser_1 = class Parser {
193
194
  */
194
195
  parseDoc(html, rootComponentLoader) {
195
196
  const element = typeof html === 'string' ? Parser_1.parseHTML(html) : html;
196
- return rootComponentLoader.read(element, this.injector, (childSlot, slotRootElement, slotContentHostElement = slotRootElement) => {
197
+ return rootComponentLoader.read(element, this.textbus, (childSlot, slotRootElement, slotContentHostElement = slotRootElement) => {
197
198
  return this.readSlot(childSlot, slotRootElement, slotContentHostElement);
198
199
  });
199
200
  }
@@ -214,7 +215,7 @@ let Parser = Parser_1 = class Parser {
214
215
  }
215
216
  for (const t of this.componentLoaders) {
216
217
  if (t.match(el)) {
217
- const result = t.read(el, this.injector, (childSlot, slotRootElement, slotContentHostElement = slotRootElement) => {
218
+ const result = t.read(el, this.textbus, (childSlot, slotRootElement, slotContentHostElement = slotRootElement) => {
218
219
  return this.readSlot(childSlot, slotRootElement, slotContentHostElement);
219
220
  });
220
221
  if (!result) {
@@ -294,19 +295,16 @@ let Parser = Parser_1 = class Parser {
294
295
  Parser = Parser_1 = __decorate([
295
296
  Injectable(),
296
297
  __param(0, Inject(EDITOR_OPTIONS)),
297
- __metadata("design:paramtypes", [Object, Injector])
298
+ __metadata("design:paramtypes", [Object, Textbus])
298
299
  ], Parser);
299
300
 
300
301
  class Input {
301
302
  }
302
303
 
303
- /**
304
- * Textbus PC 端浏览器渲染能力桥接器抽象类,提供了 DOM 元素查询能力,具体渲染能力由各前端框架实现相应桥接
305
- */
306
- class DomAdapter extends ViewAdapter {
307
- constructor(mount) {
308
- super();
309
- this.mount = mount;
304
+ class DomAdapter extends Adapter {
305
+ constructor() {
306
+ super(...arguments);
307
+ this.onViewUpdated = new Subject();
310
308
  this.host = createElement('div', {
311
309
  styles: {
312
310
  cursor: 'text',
@@ -322,126 +320,6 @@ class DomAdapter extends ViewAdapter {
322
320
  id: 'textbus-' + Number((Math.random() + '').substring(2)).toString(16)
323
321
  }
324
322
  });
325
- this.componentRootElementCaches = createBidirectionalMapping(a => {
326
- return a instanceof ComponentInstance;
327
- });
328
- this.slotRootNativeElementCaches = createBidirectionalMapping(a => {
329
- return a instanceof Slot;
330
- });
331
- this.slotRootVElementCaches = new WeakMap();
332
- }
333
- render(rootComponent) {
334
- const view = this.componentRender(rootComponent);
335
- return this.mount(this.host, view);
336
- }
337
- copy() {
338
- document.execCommand('copy');
339
- }
340
- /**
341
- * 根据组件获取组件的根 DOM 节点
342
- * @param component
343
- */
344
- getNativeNodeByComponent(component) {
345
- return this.componentRootElementCaches.get(component) || null;
346
- }
347
- /**
348
- * 根据 DOM 节点,获对对应的组件根节点,如传入的 DOM 节点不为组件的根节点,则返回 null
349
- * @param node
350
- */
351
- getComponentByNativeNode(node) {
352
- return this.componentRootElementCaches.get(node) || null;
353
- }
354
- /**
355
- * 根据插槽获取插槽的根 DOM 节点
356
- * @param slot
357
- */
358
- getNativeNodeBySlot(slot) {
359
- return this.slotRootNativeElementCaches.get(slot) || null;
360
- }
361
- /**
362
- * 根据 DOM 节点,获对对应的插槽根节点,如传入的 DOM 节点不为插槽的根节点,则返回 null
363
- * @param node
364
- */
365
- getSlotByNativeNode(node) {
366
- return this.slotRootNativeElementCaches.get(node) || null;
367
- }
368
- /**
369
- * 获取插槽内容节点集合
370
- * @param slot
371
- */
372
- getNodesBySlot(slot) {
373
- const rootNativeNode = this.getNativeNodeBySlot(slot);
374
- if (!rootNativeNode) {
375
- return [];
376
- }
377
- const rootVNode = this.slotRootVElementCaches.get(slot);
378
- const getNodes = (vElement, nativeNode, result) => {
379
- if (vElement.location) {
380
- result.push(nativeNode);
381
- }
382
- for (let i = 0; i < vElement.children.length; i++) {
383
- const vChild = vElement.children[i];
384
- const nativeChild = nativeNode.childNodes[i];
385
- if (vChild instanceof VElement) {
386
- getNodes(vChild, nativeChild, result);
387
- }
388
- else if (vChild instanceof VTextNode) {
389
- result.push(nativeChild);
390
- }
391
- else {
392
- result.push(this.getNativeNodeByComponent(vChild));
393
- }
394
- }
395
- return result;
396
- };
397
- return getNodes(rootVNode, rootNativeNode, []);
398
- }
399
- /**
400
- * 获取原生节点的原始数据在文档中的位置
401
- * @param node
402
- */
403
- getLocationByNativeNode(node) {
404
- let slotRootNode = node;
405
- while (!this.slotRootNativeElementCaches.get(slotRootNode)) {
406
- slotRootNode = slotRootNode.parentNode;
407
- if (!slotRootNode) {
408
- return null;
409
- }
410
- }
411
- const slot = this.slotRootNativeElementCaches.get(slotRootNode);
412
- const rootVNode = this.slotRootVElementCaches.get(slot);
413
- const getLocation = (target, tree, vNodeTree) => {
414
- if (target === tree) {
415
- return Object.assign({}, vNodeTree.location);
416
- }
417
- const childNodes = tree.childNodes;
418
- for (let i = 0; i < childNodes.length; i++) {
419
- const child = vNodeTree.children[i];
420
- const nativeChild = tree.childNodes[i];
421
- if (nativeChild === target) {
422
- if (child instanceof ComponentInstance) {
423
- const index = child.parent.indexOf(child);
424
- return {
425
- slot: child.parent,
426
- startIndex: index,
427
- endIndex: index + 1
428
- };
429
- }
430
- return child.location;
431
- }
432
- else if (child instanceof VElement) {
433
- let r = null;
434
- if (nativeChild.nodeType === Node.ELEMENT_NODE) {
435
- r = getLocation(target, nativeChild, child);
436
- }
437
- if (r) {
438
- return r;
439
- }
440
- }
441
- }
442
- return null;
443
- };
444
- return getLocation(node, slotRootNode, rootVNode);
445
323
  }
446
324
  }
447
325
 
@@ -449,7 +327,7 @@ class DomAdapter extends ViewAdapter {
449
327
  * Textbus PC 端选区桥接实现
450
328
  */
451
329
  let SelectionBridge = class SelectionBridge {
452
- constructor(config, injector, controller, selection, rootComponentRef, input, domAdapter) {
330
+ constructor(config, textbus, controller, selection, rootComponentRef, input, domAdapter) {
453
331
  this.config = config;
454
332
  this.selection = selection;
455
333
  this.rootComponentRef = rootComponentRef;
@@ -461,7 +339,7 @@ let SelectionBridge = class SelectionBridge {
461
339
  this.connector = null;
462
340
  this.ignoreSelectionChange = false;
463
341
  this.changeFromUser = false;
464
- this.docContainer = injector.get(VIEW_DOCUMENT);
342
+ this.docContainer = textbus.get(VIEW_DOCUMENT);
465
343
  this.onSelectionChange = this.selectionChangeEvent.asObservable().pipe(filter(() => {
466
344
  return !controller.readonly;
467
345
  }));
@@ -645,6 +523,7 @@ let SelectionBridge = class SelectionBridge {
645
523
  }
646
524
  minLeft = rect2.left;
647
525
  minTop = rect2.top;
526
+ oldPosition = position;
648
527
  }
649
528
  if (isToPrevLine) {
650
529
  if (rect2.left < startLeft) {
@@ -751,7 +630,7 @@ let SelectionBridge = class SelectionBridge {
751
630
  this.input.composition ||
752
631
  selection.rangeCount === 0 ||
753
632
  !this.docContainer.contains(selection.anchorNode) ||
754
- this.rootComponentRef.component.slots.length === 0) {
633
+ this.rootComponentRef.component.__slots__.length === 0) {
755
634
  return;
756
635
  }
757
636
  const rawRange = selection.getRangeAt(0);
@@ -760,14 +639,14 @@ let SelectionBridge = class SelectionBridge {
760
639
  const isFocusStart = selection.focusNode === nativeRange.startContainer && selection.focusOffset === nativeRange.startOffset;
761
640
  if (!this.docContainer.contains(selection.focusNode)) {
762
641
  if (isFocusEnd) {
763
- const nativeNode = this.domAdapter.getNativeNodeBySlot(this.rootComponentRef.component.slots.first);
642
+ const nativeNode = this.domAdapter.getNativeNodeBySlot(this.rootComponentRef.component.__slots__.first);
764
643
  if (!nativeNode) {
765
644
  return;
766
645
  }
767
646
  nativeRange.setEndAfter(nativeNode.lastChild);
768
647
  }
769
648
  else {
770
- const nativeNode = this.domAdapter.getNativeNodeBySlot(this.rootComponentRef.component.slots.last);
649
+ const nativeNode = this.domAdapter.getNativeNodeBySlot(this.rootComponentRef.component.__slots__.last);
771
650
  if (!nativeNode) {
772
651
  return;
773
652
  }
@@ -990,7 +869,7 @@ let SelectionBridge = class SelectionBridge {
990
869
  SelectionBridge = __decorate([
991
870
  Injectable(),
992
871
  __param(0, Inject(EDITOR_OPTIONS)),
993
- __metadata("design:paramtypes", [Object, Injector,
872
+ __metadata("design:paramtypes", [Object, Textbus,
994
873
  Controller,
995
874
  Selection,
996
875
  RootComponentRef,
@@ -1028,15 +907,10 @@ class ExperimentalCaret {
1028
907
  get display() {
1029
908
  return this._display;
1030
909
  }
1031
- constructor(scheduler, editorMask) {
910
+ constructor(domRenderer, scheduler, editorMask) {
911
+ this.domRenderer = domRenderer;
1032
912
  this.scheduler = scheduler;
1033
913
  this.editorMask = editorMask;
1034
- this.compositionState = null;
1035
- this.compositionElement = createElement('span', {
1036
- styles: {
1037
- textDecoration: 'underline'
1038
- }
1039
- });
1040
914
  this.timer = null;
1041
915
  this.oldPosition = null;
1042
916
  this._display = true;
@@ -1180,12 +1054,10 @@ class ExperimentalCaret {
1180
1054
  this.positionChangeEvent.next(null);
1181
1055
  return;
1182
1056
  }
1183
- if (this.compositionState) {
1184
- const compositionElement = this.compositionElement;
1185
- compositionElement.innerText = this.compositionState.data;
1057
+ const compositionNode = this.domRenderer.compositionNode;
1058
+ if (compositionNode) {
1186
1059
  nativeRange = nativeRange.cloneRange();
1187
- nativeRange.insertNode(compositionElement);
1188
- nativeRange.selectNodeContents(compositionElement);
1060
+ nativeRange.selectNodeContents(compositionNode);
1189
1061
  nativeRange.collapse();
1190
1062
  }
1191
1063
  const rect = getLayoutRectByRange(nativeRange);
@@ -1246,18 +1118,18 @@ let MagicInput = class MagicInput extends Input {
1246
1118
  get disabled() {
1247
1119
  return this._disabled;
1248
1120
  }
1249
- constructor(parser, keyboard, commander, selection, controller, scheduler, injector) {
1121
+ constructor(domAdapter, parser, keyboard, commander, selection, controller, scheduler, textbus) {
1250
1122
  super();
1123
+ this.domAdapter = domAdapter;
1251
1124
  this.parser = parser;
1252
1125
  this.keyboard = keyboard;
1253
1126
  this.commander = commander;
1254
1127
  this.selection = selection;
1255
1128
  this.controller = controller;
1256
1129
  this.scheduler = scheduler;
1257
- this.injector = injector;
1130
+ this.textbus = textbus;
1258
1131
  this.composition = false;
1259
- this.compositionState = null;
1260
- this.caret = new ExperimentalCaret(this.scheduler, this.injector.get(VIEW_MASK));
1132
+ this.caret = new ExperimentalCaret(this.domAdapter, this.scheduler, this.textbus.get(VIEW_MASK));
1261
1133
  this.isSafari = isSafari();
1262
1134
  this.isFirefox = isFirefox();
1263
1135
  this.isMac = isMac();
@@ -1297,13 +1169,8 @@ let MagicInput = class MagicInput extends Input {
1297
1169
  if (!this.isFocus) {
1298
1170
  (_a = this.textarea) === null || _a === void 0 ? void 0 : _a.focus();
1299
1171
  setTimeout(() => {
1300
- var _a, _b, _c;
1301
1172
  if (!this.nativeFocus && this.isFocus) {
1302
- this.subscription.unsubscribe();
1303
- (_b = (_a = this.textarea) === null || _a === void 0 ? void 0 : _a.parentNode) === null || _b === void 0 ? void 0 : _b.removeChild(this.textarea);
1304
- this.subscription = new Subscription();
1305
- this.init();
1306
- (_c = this.textarea) === null || _c === void 0 ? void 0 : _c.focus();
1173
+ this.reInit();
1307
1174
  }
1308
1175
  });
1309
1176
  }
@@ -1319,6 +1186,22 @@ let MagicInput = class MagicInput extends Input {
1319
1186
  this.caret.destroy();
1320
1187
  this.subscription.unsubscribe();
1321
1188
  }
1189
+ reInit(delay = false) {
1190
+ var _a, _b, _c;
1191
+ this.subscription.unsubscribe();
1192
+ (_b = (_a = this.textarea) === null || _a === void 0 ? void 0 : _a.parentNode) === null || _b === void 0 ? void 0 : _b.removeChild(this.textarea);
1193
+ this.subscription = new Subscription();
1194
+ this.init();
1195
+ if (delay) {
1196
+ setTimeout(() => {
1197
+ var _a;
1198
+ (_a = this.textarea) === null || _a === void 0 ? void 0 : _a.focus();
1199
+ });
1200
+ }
1201
+ else {
1202
+ (_c = this.textarea) === null || _c === void 0 ? void 0 : _c.focus();
1203
+ }
1204
+ }
1322
1205
  init() {
1323
1206
  const doc = this.doc;
1324
1207
  const contentBody = doc.body;
@@ -1327,9 +1210,19 @@ let MagicInput = class MagicInput extends Input {
1327
1210
  contentBody.appendChild(textarea);
1328
1211
  this.textarea = textarea;
1329
1212
  this.subscription.add(fromEvent(textarea, 'blur').subscribe(() => {
1213
+ // if (this.isFocus) {
1214
+ // this.isFocus = false
1215
+ // this.reInit(true)
1216
+ // }
1330
1217
  this.isFocus = false;
1331
1218
  this.nativeFocus = false;
1332
1219
  this.caret.hide();
1220
+ if (this.domAdapter.composition) {
1221
+ const slot = this.domAdapter.composition.slot;
1222
+ this.domAdapter.composition = null;
1223
+ this.domAdapter.compositionNode = null;
1224
+ slot.__changeMarker__.forceMarkDirtied();
1225
+ }
1333
1226
  }), fromEvent(textarea, 'focus').subscribe(() => {
1334
1227
  this.nativeFocus = true;
1335
1228
  }), this.caret.onStyleChange.subscribe(style => {
@@ -1340,7 +1233,7 @@ let MagicInput = class MagicInput extends Input {
1340
1233
  this.handleDefaultActions(textarea);
1341
1234
  }
1342
1235
  handleDefaultActions(textarea) {
1343
- this.subscription.add(fromEvent(document, 'copy').subscribe(ev => {
1236
+ this.subscription.add(fromEvent(isFirefox() ? textarea : document, 'copy').subscribe(ev => {
1344
1237
  const selection = this.selection;
1345
1238
  if (!selection.isSelected) {
1346
1239
  return;
@@ -1452,7 +1345,6 @@ let MagicInput = class MagicInput extends Input {
1452
1345
  this.commander.delete();
1453
1346
  }
1454
1347
  this.composition = true;
1455
- this.caret.compositionState = this.compositionState = null;
1456
1348
  startIndex = this.selection.startOffset;
1457
1349
  const startSlot = this.selection.startSlot;
1458
1350
  const event = new Event(startSlot, {
@@ -1469,10 +1361,11 @@ let MagicInput = class MagicInput extends Input {
1469
1361
  return;
1470
1362
  }
1471
1363
  const startSlot = this.selection.startSlot;
1472
- this.caret.compositionState = this.compositionState = {
1364
+ this.domAdapter.composition = {
1473
1365
  slot: startSlot,
1474
- index: startIndex,
1475
- data: ev.data
1366
+ text: ev.data,
1367
+ offset: ev.data.length,
1368
+ index: startIndex
1476
1369
  };
1477
1370
  this.caret.refresh(true);
1478
1371
  const event = new Event(startSlot, {
@@ -1480,6 +1373,7 @@ let MagicInput = class MagicInput extends Input {
1480
1373
  data: ev.data
1481
1374
  });
1482
1375
  invokeListener(startSlot.parent, 'onCompositionUpdate', event);
1376
+ startSlot.__changeMarker__.forceMarkDirtied();
1483
1377
  }));
1484
1378
  let isCompositionEnd = false;
1485
1379
  this.subscription.add(merge(fromEvent(textarea, 'beforeinput').pipe(filter(ev => {
@@ -1503,24 +1397,15 @@ let MagicInput = class MagicInput extends Input {
1503
1397
  textarea.value = '';
1504
1398
  return ev.data;
1505
1399
  }))).subscribe(text => {
1400
+ var _a;
1506
1401
  this.composition = false;
1507
- this.caret.compositionState = this.compositionState = null;
1508
- const compositionElement = this.caret.compositionElement;
1509
- let nextSibling = compositionElement.nextSibling;
1510
- while (nextSibling) {
1511
- if (!nextSibling.textContent) {
1512
- const next = nextSibling.nextSibling;
1513
- nextSibling.remove();
1514
- nextSibling = next;
1515
- continue;
1516
- }
1517
- nextSibling.remove();
1518
- break;
1519
- }
1520
- compositionElement.remove();
1402
+ this.domAdapter.composition = null;
1521
1403
  if (text) {
1522
1404
  this.commander.write(text);
1523
1405
  }
1406
+ else {
1407
+ (_a = this.selection.startSlot) === null || _a === void 0 ? void 0 : _a.__changeMarker__.forceMarkDirtied();
1408
+ }
1524
1409
  if (isCompositionEnd) {
1525
1410
  const startSlot = this.selection.startSlot;
1526
1411
  if (startSlot) {
@@ -1549,13 +1434,14 @@ let MagicInput = class MagicInput extends Input {
1549
1434
  };
1550
1435
  MagicInput = __decorate([
1551
1436
  Injectable(),
1552
- __metadata("design:paramtypes", [Parser,
1437
+ __metadata("design:paramtypes", [DomAdapter,
1438
+ Parser,
1553
1439
  Keyboard,
1554
1440
  Commander,
1555
1441
  Selection,
1556
1442
  Controller,
1557
1443
  Scheduler,
1558
- Injector])
1444
+ Textbus])
1559
1445
  ], MagicInput);
1560
1446
 
1561
1447
  /**
@@ -1567,10 +1453,11 @@ class CollaborateSelectionAwarenessDelegate {
1567
1453
  * 协作光标绘制类
1568
1454
  */
1569
1455
  let CollaborateCursor = class CollaborateCursor {
1570
- constructor(injector, nativeSelection, scheduler, selection, awarenessDelegate) {
1456
+ constructor(textbus, nativeSelection, scheduler, selection, userActivity, awarenessDelegate) {
1571
1457
  this.nativeSelection = nativeSelection;
1572
1458
  this.scheduler = scheduler;
1573
1459
  this.selection = selection;
1460
+ this.userActivity = userActivity;
1574
1461
  this.awarenessDelegate = awarenessDelegate;
1575
1462
  this.host = createElement('div', {
1576
1463
  styles: {
@@ -1620,7 +1507,8 @@ let CollaborateCursor = class CollaborateCursor {
1620
1507
  this.onRectsChange = new Subject();
1621
1508
  this.subscription = new Subscription();
1622
1509
  this.currentSelection = [];
1623
- this.container = injector.get(VIEW_CONTAINER);
1510
+ this.ratio = window.devicePixelRatio || 1;
1511
+ this.container = textbus.get(VIEW_CONTAINER);
1624
1512
  this.canvasContainer.append(this.canvas);
1625
1513
  this.host.append(this.canvasContainer, this.tooltips);
1626
1514
  this.container.prepend(this.host);
@@ -1639,6 +1527,13 @@ let CollaborateCursor = class CollaborateCursor {
1639
1527
  this.refresh();
1640
1528
  }));
1641
1529
  }
1530
+ init() {
1531
+ if (this.userActivity) {
1532
+ this.subscription.add(this.userActivity.onStateChange.subscribe(v => {
1533
+ this.draw(v);
1534
+ }));
1535
+ }
1536
+ }
1642
1537
  /**
1643
1538
  * 刷新协作光标,由于 Textbus 只会绘制可视区域的光标,当可视区域发生变化时,需要重新绘制
1644
1539
  */
@@ -1656,15 +1551,16 @@ let CollaborateCursor = class CollaborateCursor {
1656
1551
  this.currentSelection = paths;
1657
1552
  const containerRect = this.container.getBoundingClientRect();
1658
1553
  this.canvas.style.top = containerRect.top * -1 + 'px';
1659
- this.canvas.width = this.canvas.offsetWidth;
1660
- this.canvas.height = this.canvas.offsetHeight;
1554
+ this.canvas.width = this.canvas.offsetWidth * this.ratio;
1555
+ this.canvas.height = this.canvas.offsetHeight * this.ratio;
1556
+ this.context.scale(this.ratio, this.ratio);
1661
1557
  this.context.clearRect(0, 0, this.canvas.width, this.canvas.height);
1662
1558
  const users = [];
1663
1559
  paths.filter(i => {
1664
- return i.paths.anchor.length && i.paths.focus.length;
1560
+ return i.selection.anchor.length && i.selection.focus.length;
1665
1561
  }).forEach(item => {
1666
- const anchorPaths = [...item.paths.anchor];
1667
- const focusPaths = [...item.paths.focus];
1562
+ const anchorPaths = [...item.selection.anchor];
1563
+ const focusPaths = [...item.selection.focus];
1668
1564
  const anchorOffset = anchorPaths.pop();
1669
1565
  const anchorSlot = this.selection.findSlotByPaths(anchorPaths);
1670
1566
  const focusOffset = focusPaths.pop();
@@ -1682,8 +1578,13 @@ let CollaborateCursor = class CollaborateCursor {
1682
1578
  return;
1683
1579
  }
1684
1580
  const nativeRange = document.createRange();
1685
- nativeRange.setStart(anchor.node, anchor.offset);
1686
- nativeRange.setEnd(focus.node, focus.offset);
1581
+ try {
1582
+ nativeRange.setStart(anchor.node, anchor.offset);
1583
+ nativeRange.setEnd(focus.node, focus.offset);
1584
+ }
1585
+ catch (e) {
1586
+ return;
1587
+ }
1687
1588
  if ((anchor.node !== focus.node || anchor.offset !== focus.offset) && nativeRange.collapsed) {
1688
1589
  nativeRange.setStart(focus.node, focus.offset);
1689
1590
  nativeRange.setEnd(anchor.node, anchor.offset);
@@ -1812,10 +1713,12 @@ let CollaborateCursor = class CollaborateCursor {
1812
1713
  CollaborateCursor = __decorate([
1813
1714
  Injectable(),
1814
1715
  __param(4, Optional()),
1815
- __metadata("design:paramtypes", [Injector,
1716
+ __param(5, Optional()),
1717
+ __metadata("design:paramtypes", [Textbus,
1816
1718
  SelectionBridge,
1817
1719
  Scheduler,
1818
1720
  Selection,
1721
+ UserActivity,
1819
1722
  CollaborateSelectionAwarenessDelegate])
1820
1723
  ], CollaborateCursor);
1821
1724
 
@@ -1933,7 +1836,7 @@ let NativeInput = class NativeInput extends Input {
1933
1836
  get disabled() {
1934
1837
  return this._disabled;
1935
1838
  }
1936
- constructor(injector, parser, scheduler, selection, keyboard, domAdapter, commander, controller) {
1839
+ constructor(textbus, parser, scheduler, selection, keyboard, domAdapter, commander, controller) {
1937
1840
  super();
1938
1841
  this.parser = parser;
1939
1842
  this.scheduler = scheduler;
@@ -1944,7 +1847,7 @@ let NativeInput = class NativeInput extends Input {
1944
1847
  this.controller = controller;
1945
1848
  this.caret = new NativeCaret(this.scheduler);
1946
1849
  this.composition = false;
1947
- this.compositionState = null;
1850
+ // compositionState: CompositionState | null = null
1948
1851
  this.onReady = Promise.resolve();
1949
1852
  this._disabled = false;
1950
1853
  this.nativeSelection = document.getSelection();
@@ -1954,7 +1857,7 @@ let NativeInput = class NativeInput extends Input {
1954
1857
  this.isMac = isMac();
1955
1858
  this.isMobileBrowser = isMobileBrowser();
1956
1859
  this.ignoreComposition = false; // 有 bug 版本搜狗拼音
1957
- this.documentView = injector.get(VIEW_DOCUMENT);
1860
+ this.documentView = textbus.get(VIEW_DOCUMENT);
1958
1861
  if (!controller.readonly) {
1959
1862
  this.documentView.contentEditable = 'true';
1960
1863
  }
@@ -1987,7 +1890,7 @@ let NativeInput = class NativeInput extends Input {
1987
1890
  this.subscription.unsubscribe();
1988
1891
  }
1989
1892
  handleDefaultActions(textarea) {
1990
- this.subscription.add(fromEvent(document, 'copy').subscribe(ev => {
1893
+ this.subscription.add(fromEvent(isFirefox() ? textarea : document, 'copy').subscribe(ev => {
1991
1894
  const selection = this.selection;
1992
1895
  if (!selection.isSelected) {
1993
1896
  return;
@@ -2041,8 +1944,8 @@ let NativeInput = class NativeInput extends Input {
2041
1944
  });
2042
1945
  }));
2043
1946
  }
2044
- handlePaste(html, text) {
2045
- const slot = this.parser.parse(html, new Slot([
1947
+ handlePaste(dom, text) {
1948
+ const slot = this.parser.parse(dom, new Slot([
2046
1949
  ContentType.BlockComponent,
2047
1950
  ContentType.InlineComponent,
2048
1951
  ContentType.Text
@@ -2102,7 +2005,6 @@ let NativeInput = class NativeInput extends Input {
2102
2005
  let startIndex;
2103
2006
  const compositionStart = () => {
2104
2007
  this.composition = true;
2105
- this.compositionState = null;
2106
2008
  startIndex = this.selection.startOffset;
2107
2009
  const startSlot = this.selection.startSlot;
2108
2010
  const event = new Event(startSlot, {
@@ -2112,11 +2014,6 @@ let NativeInput = class NativeInput extends Input {
2112
2014
  };
2113
2015
  const compositionUpdate = (data) => {
2114
2016
  const startSlot = this.selection.startSlot;
2115
- this.compositionState = {
2116
- slot: startSlot,
2117
- index: startIndex,
2118
- data
2119
- };
2120
2017
  const event = new Event(startSlot, {
2121
2018
  index: startIndex,
2122
2019
  data
@@ -2203,7 +2100,6 @@ let NativeInput = class NativeInput extends Input {
2203
2100
  return !this.ignoreComposition;
2204
2101
  })).subscribe(() => {
2205
2102
  this.composition = true;
2206
- this.compositionState = null;
2207
2103
  startIndex = this.selection.startOffset;
2208
2104
  const startSlot = this.selection.startSlot;
2209
2105
  const event = new Event(startSlot, {
@@ -2214,11 +2110,6 @@ let NativeInput = class NativeInput extends Input {
2214
2110
  return !this.ignoreComposition;
2215
2111
  })).subscribe(ev => {
2216
2112
  const startSlot = this.selection.startSlot;
2217
- this.compositionState = {
2218
- slot: startSlot,
2219
- index: startIndex,
2220
- data: ev.data
2221
- };
2222
2113
  const event = new Event(startSlot, {
2223
2114
  index: startIndex,
2224
2115
  data: ev.data
@@ -2268,7 +2159,6 @@ let NativeInput = class NativeInput extends Input {
2268
2159
  return !b;
2269
2160
  }))).subscribe(text => {
2270
2161
  this.composition = false;
2271
- this.compositionState = null;
2272
2162
  if (text) {
2273
2163
  this.commander.write(text);
2274
2164
  }
@@ -2285,7 +2175,7 @@ let NativeInput = class NativeInput extends Input {
2285
2175
  };
2286
2176
  NativeInput = __decorate([
2287
2177
  Injectable(),
2288
- __metadata("design:paramtypes", [Injector,
2178
+ __metadata("design:paramtypes", [Textbus,
2289
2179
  Parser,
2290
2180
  Scheduler,
2291
2181
  Selection,
@@ -2295,9 +2185,9 @@ NativeInput = __decorate([
2295
2185
  Controller])
2296
2186
  ], NativeInput);
2297
2187
 
2188
+ const browserErrorFn = makeError('BrowserModule');
2298
2189
  class BrowserModule {
2299
- constructor(host, config) {
2300
- this.host = host;
2190
+ constructor(config) {
2301
2191
  this.config = config;
2302
2192
  const { mask, wrapper } = BrowserModule.createLayout();
2303
2193
  wrapper.prepend(config.adapter.host);
@@ -2323,24 +2213,77 @@ class BrowserModule {
2323
2213
  provide: Input,
2324
2214
  useClass: config.useContentEditable ? NativeInput : MagicInput
2325
2215
  }, {
2326
- provide: ViewAdapter,
2327
- useFactory(v) {
2328
- return v;
2329
- },
2330
- deps: [DomAdapter]
2216
+ provide: Adapter,
2217
+ useValue: config.adapter
2331
2218
  }, {
2332
2219
  provide: DomAdapter,
2333
2220
  useValue: config.adapter
2221
+ }, {
2222
+ provide: FocusManager,
2223
+ useFactory: (input) => {
2224
+ const focusEvent = new Subject();
2225
+ const blurEvent = new Subject();
2226
+ input.caret.onPositionChange.pipe(map(p => !!p), distinctUntilChanged()).subscribe(b => {
2227
+ if (b) {
2228
+ focusEvent.next();
2229
+ }
2230
+ else {
2231
+ blurEvent.next();
2232
+ }
2233
+ });
2234
+ return {
2235
+ onFocus: focusEvent,
2236
+ onBlur: blurEvent
2237
+ };
2238
+ },
2239
+ deps: [Input]
2334
2240
  },
2335
2241
  Parser,
2336
2242
  SelectionBridge,
2337
- CollaborateCursor
2338
- ];
2243
+ CollaborateCursor];
2339
2244
  this.workbench = wrapper;
2340
- this.host.append(wrapper);
2341
2245
  }
2342
- onDestroy() {
2343
- this.workbench.remove();
2246
+ /**
2247
+ * 解析 HTML 并返回一个组件实例
2248
+ * @param html 要解析的 HTML
2249
+ * @param rootComponentLoader 文档根组件加载器
2250
+ * @param textbus
2251
+ */
2252
+ readDocumentByHTML(html, rootComponentLoader, textbus) {
2253
+ const parser = textbus.get(Parser);
2254
+ const doc = parser.parseDoc(html, rootComponentLoader);
2255
+ if (doc instanceof Component) {
2256
+ return doc;
2257
+ }
2258
+ throw browserErrorFn('rootComponentLoader must return a component instance.');
2259
+ }
2260
+ /**
2261
+ * 将组件数据解析到组件实例中
2262
+ * @param data 要解析的 JSON 数据
2263
+ * @param rootComponent 根组件
2264
+ * @param textbus
2265
+ */
2266
+ readDocumentByComponentLiteral(data, rootComponent, textbus) {
2267
+ const registry = textbus.get(Registry);
2268
+ return registry.createComponentByFactory(data, rootComponent);
2269
+ }
2270
+ setup(textbus) {
2271
+ const host = this.config.renderTo();
2272
+ if (!(host instanceof HTMLElement)) {
2273
+ throw browserErrorFn('view container is not a HTMLElement');
2274
+ }
2275
+ const cursor = textbus.get(CollaborateCursor);
2276
+ cursor.init();
2277
+ host.append(this.workbench);
2278
+ return () => {
2279
+ cursor.destroy();
2280
+ this.workbench.remove();
2281
+ };
2282
+ }
2283
+ onAfterStartup(textbus) {
2284
+ if (this.config.autoFocus) {
2285
+ textbus.focus();
2286
+ }
2344
2287
  }
2345
2288
  static createLayout() {
2346
2289
  const mask = createElement('div', {
@@ -2355,7 +2298,7 @@ class BrowserModule {
2355
2298
  bottom: 0,
2356
2299
  zIndex: 1,
2357
2300
  pointerEvents: 'none',
2358
- overflow: 'hidden'
2301
+ // overflow: 'hidden'
2359
2302
  }
2360
2303
  });
2361
2304
  const wrapper = createElement('div', {
@@ -2377,4 +2320,4 @@ class BrowserModule {
2377
2320
  }
2378
2321
  }
2379
2322
 
2380
- export { BrowserModule, CollaborateCursor, CollaborateSelectionAwarenessDelegate, DomAdapter, EDITOR_OPTIONS, Input, MagicInput, Parser, SelectionBridge, VIEW_CONTAINER, VIEW_DOCUMENT, VIEW_MASK, createElement, createTextNode, getLayoutRectByRange, isFirefox, isMac, isMobileBrowser, isSafari, isWindows };
2323
+ export { BrowserModule, CollaborateCursor, CollaborateSelectionAwarenessDelegate, DomAdapter, EDITOR_OPTIONS, Input, MagicInput, NativeInput, Parser, SelectionBridge, VIEW_CONTAINER, VIEW_DOCUMENT, VIEW_MASK, createElement, createTextNode, getLayoutRectByRange, isFirefox, isMac, isMobileBrowser, isSafari, isWindows };