slate-angular 20.2.13 → 20.2.15

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.
@@ -1498,6 +1498,9 @@ const ELEMENT_KEY_TO_HEIGHTS = new WeakMap();
1498
1498
  const EDITOR_TO_BUSINESS_TOP = new WeakMap();
1499
1499
  const EDITOR_TO_ROOT_NODE_WIDTH = new WeakMap();
1500
1500
  const EDITOR_TO_IS_FROM_SCROLL_TO = new WeakMap();
1501
+ const isValidNumber = (value) => {
1502
+ return typeof value === 'number' && !Number.isNaN(value);
1503
+ };
1501
1504
  const debugLog = (type, ...args) => {
1502
1505
  const doc = document;
1503
1506
  VirtualScrollDebugOverlay.log(doc, type, ...args);
@@ -1506,7 +1509,7 @@ const cacheHeightByElement = (editor, element, height) => {
1506
1509
  if (!AngularEditor.isEnabledVirtualScroll(editor)) {
1507
1510
  return;
1508
1511
  }
1509
- if (typeof height !== 'number') {
1512
+ if (!isValidNumber(height)) {
1510
1513
  console.error('cacheHeightByElement: height must be number', height);
1511
1514
  return;
1512
1515
  }
@@ -1565,9 +1568,11 @@ const measureHeightByIndics = (editor, indics, force = false) => {
1565
1568
  }
1566
1569
  return;
1567
1570
  }
1568
- hasChanged = true;
1569
1571
  const currentHeight = calcHeightByElement(editor, element);
1570
- if (isDebug) {
1572
+ if (isValidNumber(currentHeight) && currentHeight !== preHeight) {
1573
+ hasChanged = true;
1574
+ }
1575
+ if (isDebug && isValidNumber(currentHeight)) {
1571
1576
  debugLog('log', 'measureHeightByIndics: height not equal, index: ', index, 'preHeight: ', preHeight, 'height: ', currentHeight);
1572
1577
  }
1573
1578
  });
@@ -3503,663 +3508,695 @@ class SlateEditable {
3503
3508
  this.addEventListener(event.name, () => { });
3504
3509
  });
3505
3510
  }
3506
- calculateVirtualScrollSelection(selection) {
3507
- if (selection) {
3508
- const isBlockCardCursor = AngularEditor.isBlockCardLeftCursor(this.editor) || AngularEditor.isBlockCardRightCursor(this.editor);
3509
- const indics = this.inViewportIndics;
3510
- if (indics.length > 0) {
3511
- const currentVisibleRange = {
3512
- anchor: Editor.start(this.editor, [indics[0]]),
3513
- focus: Editor.end(this.editor, [indics[indics.length - 1]])
3514
- };
3515
- const [start, end] = Range.edges(selection);
3516
- let forwardSelection = { anchor: start, focus: end };
3517
- if (!isBlockCardCursor) {
3518
- forwardSelection = { anchor: start, focus: end };
3519
- }
3520
- else {
3521
- forwardSelection = { anchor: { path: start.path, offset: 0 }, focus: { path: end.path, offset: 0 } };
3522
- }
3523
- const intersectedSelection = Range.intersection(forwardSelection, currentVisibleRange);
3524
- if (intersectedSelection && isBlockCardCursor) {
3525
- return selection;
3511
+ isEnabledVirtualScroll() {
3512
+ return !!(this.virtualScrollConfig && this.virtualScrollConfig.enabled);
3513
+ }
3514
+ initializeVirtualScroll() {
3515
+ if (this.virtualScrollInitialized) {
3516
+ return;
3517
+ }
3518
+ if (this.isEnabledVirtualScroll()) {
3519
+ this.virtualScrollInitialized = true;
3520
+ this.virtualTopHeightElement = document.createElement('div');
3521
+ this.virtualTopHeightElement.classList.add('virtual-top-height');
3522
+ this.virtualTopHeightElement.contentEditable = 'false';
3523
+ this.virtualBottomHeightElement = document.createElement('div');
3524
+ this.virtualBottomHeightElement.classList.add('virtual-bottom-height');
3525
+ this.virtualBottomHeightElement.contentEditable = 'false';
3526
+ this.virtualCenterOutlet = document.createElement('div');
3527
+ this.virtualCenterOutlet.classList.add('virtual-center-outlet');
3528
+ this.elementRef.nativeElement.appendChild(this.virtualTopHeightElement);
3529
+ this.elementRef.nativeElement.appendChild(this.virtualCenterOutlet);
3530
+ this.elementRef.nativeElement.appendChild(this.virtualBottomHeightElement);
3531
+ let editorResizeObserverRectWidth = this.elementRef.nativeElement.getBoundingClientRect().width;
3532
+ EDITOR_TO_ROOT_NODE_WIDTH.set(this.editor, this.virtualTopHeightElement.offsetWidth);
3533
+ this.editorResizeObserver = new ResizeObserver(entries => {
3534
+ if (entries.length > 0 && entries[0].contentRect.width !== editorResizeObserverRectWidth) {
3535
+ editorResizeObserverRectWidth = entries[0].contentRect.width;
3536
+ this.keyHeightMap.clear();
3537
+ let target = this.virtualTopHeightElement;
3538
+ if (this.inViewportChildren[0]) {
3539
+ const firstElement = this.inViewportChildren[0];
3540
+ const firstDomElement = AngularEditor.toDOMNode(this.editor, firstElement);
3541
+ target = firstDomElement;
3542
+ }
3543
+ EDITOR_TO_ROOT_NODE_WIDTH.set(this.editor, target.offsetWidth);
3544
+ updatePreRenderingElementWidth(this.editor);
3545
+ if (isDebug) {
3546
+ debugLog('log', 'editorResizeObserverRectWidth: ', editorResizeObserverRectWidth, 'EDITOR_TO_ROOT_NODE_WIDTH: ', EDITOR_TO_ROOT_NODE_WIDTH.get(this.editor));
3547
+ }
3526
3548
  }
3527
- EDITOR_TO_VIRTUAL_SCROLL_SELECTION.set(this.editor, intersectedSelection);
3528
- if (!intersectedSelection || !Range.equals(intersectedSelection, forwardSelection)) {
3549
+ });
3550
+ this.editorResizeObserver.observe(this.elementRef.nativeElement);
3551
+ let pendingRemeasureIndics = [];
3552
+ this.indicsOfNeedBeMeasured$
3553
+ .pipe(tap((previousValue) => {
3554
+ previousValue.forEach((index) => {
3555
+ if (!pendingRemeasureIndics.includes(index)) {
3556
+ pendingRemeasureIndics.push(index);
3557
+ }
3558
+ });
3559
+ }), debounceTime(500), filter(() => pendingRemeasureIndics.length > 0))
3560
+ .subscribe(() => {
3561
+ const changed = measureHeightByIndics(this.editor, pendingRemeasureIndics, true);
3562
+ if (changed) {
3563
+ this.tryUpdateVirtualViewport();
3529
3564
  if (isDebug) {
3530
- debugLog('log', `selection is not in visible range, selection: ${JSON.stringify(selection)}, currentVisibleRange: ${JSON.stringify(currentVisibleRange)}, intersectedSelection: ${JSON.stringify(intersectedSelection)}`);
3565
+ debugLog('log', 'exist pendingRemeasureIndics: ', pendingRemeasureIndics, 'will try to update virtual viewport');
3531
3566
  }
3532
- return intersectedSelection;
3533
3567
  }
3534
- return selection;
3568
+ pendingRemeasureIndics = [];
3569
+ });
3570
+ }
3571
+ }
3572
+ getChangedIndics(previousValue) {
3573
+ const remeasureIndics = [];
3574
+ this.inViewportChildren.forEach((child, index) => {
3575
+ if (previousValue.indexOf(child) === -1) {
3576
+ remeasureIndics.push(this.inViewportIndics[index]);
3535
3577
  }
3578
+ });
3579
+ return remeasureIndics;
3580
+ }
3581
+ setVirtualSpaceHeight(topHeight, bottomHeight) {
3582
+ if (!this.virtualScrollInitialized) {
3583
+ return;
3584
+ }
3585
+ this.virtualTopHeightElement.style.height = `${topHeight}px`;
3586
+ if (bottomHeight !== undefined) {
3587
+ this.virtualBottomHeightElement.style.height = `${bottomHeight}px`;
3536
3588
  }
3537
- EDITOR_TO_VIRTUAL_SCROLL_SELECTION.set(this.editor, null);
3538
- return selection;
3539
3589
  }
3540
- isSelectionInvisible(selection) {
3541
- const anchorIndex = selection.anchor.path[0];
3542
- const focusIndex = selection.focus.path[0];
3543
- const anchorElement = this.editor.children[anchorIndex];
3544
- const focusElement = this.editor.children[focusIndex];
3545
- return !anchorElement || !focusElement || !this.editor.isVisible(anchorElement) || !this.editor.isVisible(focusElement);
3590
+ getActualVirtualTopHeight() {
3591
+ if (!this.virtualScrollInitialized) {
3592
+ return 0;
3593
+ }
3594
+ return parseFloat(this.virtualTopHeightElement.style.height.replace('px', ''));
3546
3595
  }
3547
- toNativeSelection(autoScroll = true) {
3548
- try {
3549
- let { selection } = this.editor;
3550
- if (this.isEnabledVirtualScroll()) {
3551
- selection = this.calculateVirtualScrollSelection(selection);
3552
- }
3553
- const root = AngularEditor.findDocumentOrShadowRoot(this.editor);
3554
- const { activeElement } = root;
3555
- const domSelection = root.getSelection();
3556
- if ((this.isComposing && !IS_ANDROID) || !domSelection || !AngularEditor.isFocused(this.editor)) {
3557
- return;
3558
- }
3559
- const hasDomSelection = domSelection.type !== 'None';
3560
- // If the DOM selection is properly unset, we're done.
3561
- if (!selection && !hasDomSelection) {
3562
- return;
3596
+ handlePreRendering(visibleStates) {
3597
+ let preRenderingCount = 0;
3598
+ const childrenWithPreRendering = [...this.inViewportChildren];
3599
+ const childrenWithPreRenderingIndics = [...this.inViewportIndics];
3600
+ const firstIndex = this.inViewportIndics[0];
3601
+ for (let index = firstIndex - 1; index >= 0; index--) {
3602
+ const element = this.editor.children[index];
3603
+ if (visibleStates[index]) {
3604
+ childrenWithPreRendering.unshift(element);
3605
+ childrenWithPreRenderingIndics.unshift(index);
3606
+ preRenderingCount = 1;
3607
+ break;
3563
3608
  }
3564
- // If the DOM selection is already correct, we're done.
3565
- // verify that the dom selection is in the editor
3566
- const editorElement = EDITOR_TO_ELEMENT.get(this.editor);
3567
- let hasDomSelectionInEditor = false;
3568
- if (editorElement.contains(domSelection.anchorNode) && editorElement.contains(domSelection.focusNode)) {
3569
- hasDomSelectionInEditor = true;
3609
+ }
3610
+ const lastIndex = this.inViewportIndics[this.inViewportIndics.length - 1];
3611
+ for (let index = lastIndex + 1; index < this.editor.children.length; index++) {
3612
+ const element = this.editor.children[index];
3613
+ if (visibleStates[index]) {
3614
+ childrenWithPreRendering.push(element);
3615
+ childrenWithPreRenderingIndics.push(index);
3616
+ break;
3570
3617
  }
3571
- // If the DOM selection is in the editor and the editor selection is already correct, we're done.
3572
- if (hasDomSelection && hasDomSelectionInEditor && selection && hasStringTarget(domSelection)) {
3573
- const rangeFromDOMSelection = AngularEditor.toSlateRange(this.editor, domSelection, {
3574
- exactMatch: false,
3575
- suppressThrow: true
3576
- });
3577
- if (rangeFromDOMSelection && Range.equals(rangeFromDOMSelection, selection)) {
3578
- return;
3618
+ }
3619
+ return { preRenderingCount, childrenWithPreRendering, childrenWithPreRenderingIndics };
3620
+ }
3621
+ tryUpdateVirtualViewport() {
3622
+ if (isDebug) {
3623
+ debugLog('log', 'tryUpdateVirtualViewport');
3624
+ }
3625
+ const isFromScrollTo = EDITOR_TO_IS_FROM_SCROLL_TO.get(this.editor);
3626
+ if (this.inViewportIndics.length > 0 && !isFromScrollTo) {
3627
+ const topHeight = this.getActualVirtualTopHeight();
3628
+ const visibleStates = this.editor.getAllVisibleStates();
3629
+ const refreshVirtualTopHeight = calculateVirtualTopHeight(this.editor, this.inViewportIndics[0], visibleStates);
3630
+ if (topHeight !== refreshVirtualTopHeight) {
3631
+ if (isDebug) {
3632
+ debugLog('log', 'update top height since dirty state(正数减去高度,负数代表增加高度): ', topHeight - refreshVirtualTopHeight);
3579
3633
  }
3580
- }
3581
- // prevent updating native selection when active element is void element
3582
- if (isTargetInsideVoid(this.editor, activeElement)) {
3634
+ this.setVirtualSpaceHeight(refreshVirtualTopHeight);
3583
3635
  return;
3584
3636
  }
3585
- // when <Editable/> is being controlled through external value
3586
- // then its children might just change - DOM responds to it on its own
3587
- // but Slate's value is not being updated through any operation
3588
- // and thus it doesn't transform selection on its own
3589
- if (selection && !AngularEditor.hasRange(this.editor, selection)) {
3590
- this.editor.selection = AngularEditor.toSlateRange(this.editor, domSelection, { exactMatch: false, suppressThrow: false });
3591
- return;
3637
+ }
3638
+ this.tryUpdateVirtualViewportAnimId && cancelAnimationFrame(this.tryUpdateVirtualViewportAnimId);
3639
+ this.tryUpdateVirtualViewportAnimId = requestAnimationFrame(() => {
3640
+ if (isDebug) {
3641
+ debugLog('log', 'tryUpdateVirtualViewport Anim start');
3592
3642
  }
3593
- // Otherwise the DOM selection is out of sync, so update it.
3594
- const el = AngularEditor.toDOMNode(this.editor, this.editor);
3595
- this.isUpdatingSelection = true;
3596
- const newDomRange = selection && AngularEditor.toDOMRange(this.editor, selection);
3597
- if (newDomRange) {
3598
- // COMPAT: Since the DOM range has no concept of backwards/forwards
3599
- // we need to check and do the right thing here.
3600
- if (Range.isBackward(selection)) {
3601
- // eslint-disable-next-line max-len
3602
- domSelection.setBaseAndExtent(newDomRange.endContainer, newDomRange.endOffset, newDomRange.startContainer, newDomRange.startOffset);
3643
+ const visibleStates = this.editor.getAllVisibleStates();
3644
+ let virtualView = this.calculateVirtualViewport(visibleStates);
3645
+ let diff = this.diffVirtualViewport(virtualView);
3646
+ if (diff.isDifferent && diff.needRemoveOnTop && !isFromScrollTo) {
3647
+ const remeasureIndics = diff.changedIndexesOfTop;
3648
+ const changed = measureHeightByIndics(this.editor, remeasureIndics);
3649
+ if (changed) {
3650
+ virtualView = this.calculateVirtualViewport(visibleStates);
3651
+ diff = this.diffVirtualViewport(virtualView, 'second');
3603
3652
  }
3604
- else {
3605
- // eslint-disable-next-line max-len
3606
- domSelection.setBaseAndExtent(newDomRange.startContainer, newDomRange.startOffset, newDomRange.endContainer, newDomRange.endOffset);
3653
+ }
3654
+ if (diff.isDifferent) {
3655
+ this.applyVirtualView(virtualView);
3656
+ if (this.listRender.initialized) {
3657
+ const { preRenderingCount, childrenWithPreRendering, childrenWithPreRenderingIndics } = this.handlePreRendering(visibleStates);
3658
+ this.listRender.update(childrenWithPreRendering, this.editor, this.context, preRenderingCount, childrenWithPreRenderingIndics);
3659
+ if (diff.needAddOnTop && !isFromScrollTo) {
3660
+ const remeasureAddedIndics = diff.changedIndexesOfTop;
3661
+ if (isDebug) {
3662
+ debugLog('log', 'needAddOnTop to remeasure heights: ', remeasureAddedIndics);
3663
+ }
3664
+ const startIndexBeforeAdd = diff.changedIndexesOfTop[diff.changedIndexesOfTop.length - 1] + 1;
3665
+ const topHeightBeforeAdd = virtualView.accumulatedHeights[startIndexBeforeAdd];
3666
+ const changed = measureHeightByIndics(this.editor, remeasureAddedIndics);
3667
+ if (changed) {
3668
+ const newHeights = buildHeightsAndAccumulatedHeights(this.editor, visibleStates);
3669
+ const actualTopHeightAfterAdd = newHeights.accumulatedHeights[startIndexBeforeAdd];
3670
+ const newTopHeight = virtualView.top - (actualTopHeightAfterAdd - topHeightBeforeAdd);
3671
+ this.setVirtualSpaceHeight(newTopHeight);
3672
+ if (isDebug) {
3673
+ debugLog('log', `update top height since will add element in top(正数减去高度,负数代表增加高度): ${actualTopHeightAfterAdd - topHeightBeforeAdd}`);
3674
+ }
3675
+ }
3676
+ }
3677
+ if (this.editor.selection) {
3678
+ this.toNativeSelection(false);
3679
+ }
3607
3680
  }
3608
3681
  }
3609
- else {
3610
- domSelection.removeAllRanges();
3682
+ if (isDebug) {
3683
+ debugLog('log', 'tryUpdateVirtualViewport Anim end');
3611
3684
  }
3612
- setTimeout(() => {
3613
- if (this.isEnabledVirtualScroll() &&
3614
- !selection &&
3615
- this.editor.selection &&
3616
- autoScroll &&
3617
- this.virtualScrollConfig.scrollContainer) {
3618
- this.virtualScrollConfig.scrollContainer.scrollTop = this.virtualScrollConfig.scrollContainer.scrollTop + 100;
3619
- this.isUpdatingSelection = false;
3620
- return;
3621
- }
3622
- else {
3623
- // handle scrolling in setTimeout because of
3624
- // dom should not have updated immediately after listRender's updating
3625
- newDomRange && autoScroll && this.scrollSelectionIntoView(this.editor, newDomRange);
3626
- // COMPAT: In Firefox, it's not enough to create a range, you also need
3627
- // to focus the contenteditable element too. (2016/11/16)
3628
- if (newDomRange && IS_FIREFOX) {
3629
- el.focus();
3630
- }
3631
- }
3632
- this.isUpdatingSelection = false;
3633
- });
3634
- }
3635
- catch (error) {
3636
- this.editor.onError({
3637
- code: SlateErrorCode.ToNativeSelectionError,
3638
- nativeError: error
3639
- });
3640
- this.isUpdatingSelection = false;
3641
- }
3642
- }
3643
- onChange() {
3644
- this.forceRender();
3645
- this.onChangeCallback(this.editor.children);
3685
+ });
3646
3686
  }
3647
- ngAfterViewChecked() { }
3648
- ngDoCheck() { }
3649
- forceRender() {
3650
- this.updateContext();
3651
- if (this.isEnabledVirtualScroll()) {
3652
- this.updateListRenderAndRemeasureHeights();
3687
+ calculateVirtualViewport(visibleStates) {
3688
+ const children = (this.editor.children || []);
3689
+ if (!children.length || !this.isEnabledVirtualScroll()) {
3690
+ return {
3691
+ inViewportChildren: children,
3692
+ inViewportIndics: [],
3693
+ top: 0,
3694
+ bottom: 0,
3695
+ heights: []
3696
+ };
3653
3697
  }
3654
- else {
3655
- this.listRender.update(this.editor.children, this.editor, this.context);
3698
+ const scrollTop = this.virtualScrollConfig.scrollTop;
3699
+ let viewportHeight = this.virtualScrollConfig.viewportHeight ?? 0;
3700
+ if (!viewportHeight) {
3701
+ return {
3702
+ inViewportChildren: [],
3703
+ inViewportIndics: [],
3704
+ top: 0,
3705
+ bottom: 0,
3706
+ heights: []
3707
+ };
3656
3708
  }
3657
- // repair collaborative editing when Chinese input is interrupted by other users' cursors
3658
- // when the DOMElement where the selection is located is removed
3659
- // the compositionupdate and compositionend events will no longer be fired
3660
- // so isComposing needs to be corrected
3661
- // need exec after this.cdr.detectChanges() to render HTML
3662
- // need exec before this.toNativeSelection() to correct native selection
3663
- if (this.isComposing) {
3664
- // Composition input text be not rendered when user composition input with selection is expanded
3665
- // At this time, the following matching conditions are met, assign isComposing to false, and the status is wrong
3666
- // this time condition is true and isComposing is assigned false
3667
- // Therefore, need to wait for the composition input text to be rendered before performing condition matching
3709
+ const elementLength = children.length;
3710
+ if (!EDITOR_TO_BUSINESS_TOP.has(this.editor)) {
3711
+ EDITOR_TO_BUSINESS_TOP.set(this.editor, 0);
3668
3712
  setTimeout(() => {
3669
- const textNode = Node.get(this.editor, this.editor.selection.anchor.path);
3670
- const textDOMNode = AngularEditor.toDOMNode(this.editor, textNode);
3671
- let textContent = '';
3672
- // skip decorate text
3673
- textDOMNode.querySelectorAll('[editable-text]').forEach(stringDOMNode => {
3674
- let text = stringDOMNode.textContent;
3675
- const zeroChar = '\uFEFF';
3676
- // remove zero with char
3677
- if (text.startsWith(zeroChar)) {
3678
- text = text.slice(1);
3679
- }
3680
- if (text.endsWith(zeroChar)) {
3681
- text = text.slice(0, text.length - 1);
3682
- }
3683
- textContent += text;
3684
- });
3685
- if (Node.string(textNode).endsWith(textContent)) {
3686
- this.isComposing = false;
3713
+ const virtualTopBoundingTop = this.virtualTopHeightElement.getBoundingClientRect()?.top ?? 0;
3714
+ const businessTop = Math.ceil(virtualTopBoundingTop) +
3715
+ Math.ceil(this.virtualScrollConfig.scrollTop) -
3716
+ Math.floor(this.virtualScrollConfig.viewportBoundingTop);
3717
+ EDITOR_TO_BUSINESS_TOP.set(this.editor, businessTop);
3718
+ if (isDebug) {
3719
+ debugLog('log', 'businessTop', businessTop);
3720
+ this.virtualTopHeightElement.setAttribute('data-business-top', businessTop.toString());
3687
3721
  }
3688
- }, 0);
3689
- }
3690
- if (this.editor.selection && this.isSelectionInvisible(this.editor.selection)) {
3691
- Transforms.deselect(this.editor);
3692
- return;
3722
+ }, 100);
3693
3723
  }
3694
- else {
3695
- this.toNativeSelection();
3724
+ const businessTop = getBusinessTop(this.editor);
3725
+ const { heights, accumulatedHeights } = buildHeightsAndAccumulatedHeights(this.editor, visibleStates);
3726
+ const totalHeight = accumulatedHeights[elementLength] + businessTop;
3727
+ let startPosition = Math.max(scrollTop - businessTop, 0);
3728
+ let endPosition = startPosition + viewportHeight;
3729
+ if (scrollTop < businessTop) {
3730
+ endPosition = startPosition + viewportHeight - (businessTop - scrollTop);
3696
3731
  }
3697
- }
3698
- render() {
3699
- const changed = this.updateContext();
3700
- if (changed) {
3701
- if (this.isEnabledVirtualScroll()) {
3702
- this.updateListRenderAndRemeasureHeights();
3732
+ let accumulatedOffset = 0;
3733
+ let inViewportStartIndex = -1;
3734
+ const visible = [];
3735
+ const inViewportIndics = [];
3736
+ for (let i = 0; i < elementLength && accumulatedOffset < endPosition; i++) {
3737
+ const currentHeight = heights[i];
3738
+ const nextOffset = accumulatedOffset + currentHeight;
3739
+ const isVisible = visibleStates[i];
3740
+ if (!isVisible) {
3741
+ accumulatedOffset = nextOffset;
3742
+ continue;
3703
3743
  }
3704
- else {
3705
- this.listRender.update(this.editor.children, this.editor, this.context);
3744
+ // 可视区域有交集,加入渲染
3745
+ if (nextOffset > startPosition && accumulatedOffset < endPosition) {
3746
+ if (inViewportStartIndex === -1)
3747
+ inViewportStartIndex = i; // 第一个相交起始位置
3748
+ visible.push(children[i]);
3749
+ inViewportIndics.push(i);
3706
3750
  }
3751
+ accumulatedOffset = nextOffset;
3707
3752
  }
3753
+ const inViewportEndIndex = inViewportStartIndex === -1 ? elementLength - 1 : (inViewportIndics[inViewportIndics.length - 1] ?? inViewportStartIndex);
3754
+ const top = inViewportStartIndex === -1 ? 0 : accumulatedHeights[inViewportStartIndex];
3755
+ const bottom = totalHeight - accumulatedHeights[inViewportEndIndex + 1];
3756
+ return {
3757
+ inViewportChildren: visible.length ? visible : children,
3758
+ inViewportIndics,
3759
+ top,
3760
+ bottom,
3761
+ heights,
3762
+ accumulatedHeights
3763
+ };
3708
3764
  }
3709
- updateListRenderAndRemeasureHeights() {
3710
- const visibleStates = this.editor.getAllVisibleStates();
3711
- const previousInViewportChildren = [...this.inViewportChildren];
3712
- let virtualView = this.calculateVirtualViewport(visibleStates);
3713
- let diff = this.diffVirtualViewport(virtualView, 'onChange');
3714
- if (diff.isDifferent && diff.needRemoveOnTop) {
3715
- const remeasureIndics = diff.changedIndexesOfTop;
3716
- const changed = measureHeightByIndics(this.editor, remeasureIndics);
3717
- if (changed) {
3718
- virtualView = this.calculateVirtualViewport(visibleStates);
3719
- diff = this.diffVirtualViewport(virtualView, 'second');
3765
+ applyVirtualView(virtualView) {
3766
+ this.inViewportChildren = virtualView.inViewportChildren;
3767
+ this.setVirtualSpaceHeight(virtualView.top, virtualView.bottom);
3768
+ this.inViewportIndics = virtualView.inViewportIndics;
3769
+ }
3770
+ diffVirtualViewport(virtualView, stage = 'first') {
3771
+ if (!this.inViewportChildren.length) {
3772
+ if (isDebug) {
3773
+ debugLog('log', 'diffVirtualViewport', stage, 'empty inViewportChildren', virtualView.inViewportIndics);
3720
3774
  }
3775
+ return {
3776
+ isDifferent: true,
3777
+ changedIndexesOfTop: [],
3778
+ changedIndexesOfBottom: []
3779
+ };
3721
3780
  }
3722
- this.applyVirtualView(virtualView);
3723
- const { preRenderingCount, childrenWithPreRendering, childrenWithPreRenderingIndics } = this.handlePreRendering(visibleStates);
3724
- this.listRender.update(childrenWithPreRendering, this.editor, this.context, preRenderingCount, childrenWithPreRenderingIndics);
3725
- const remeasureIndics = this.getChangedIndics(previousInViewportChildren);
3726
- if (remeasureIndics.length) {
3727
- this.indicsOfNeedBeMeasured$.next(remeasureIndics);
3781
+ const oldIndexesInViewport = [...this.inViewportIndics];
3782
+ const newIndexesInViewport = [...virtualView.inViewportIndics];
3783
+ const firstNewIndex = newIndexesInViewport[0];
3784
+ const lastNewIndex = newIndexesInViewport[newIndexesInViewport.length - 1];
3785
+ const firstOldIndex = oldIndexesInViewport[0];
3786
+ const lastOldIndex = oldIndexesInViewport[oldIndexesInViewport.length - 1];
3787
+ const isSameViewport = oldIndexesInViewport.length === newIndexesInViewport.length &&
3788
+ oldIndexesInViewport.every((index, i) => index === newIndexesInViewport[i]);
3789
+ if (firstNewIndex === firstOldIndex && lastNewIndex === lastOldIndex) {
3790
+ return {
3791
+ isDifferent: !isSameViewport,
3792
+ changedIndexesOfTop: [],
3793
+ changedIndexesOfBottom: []
3794
+ };
3728
3795
  }
3729
- }
3730
- updateContext() {
3731
- const decorations = this.generateDecorations();
3732
- if (this.context.selection !== this.editor.selection ||
3733
- this.context.decorate !== this.decorate ||
3734
- this.context.readonly !== this.readonly ||
3735
- !isDecoratorRangeListEqual(this.context.decorations, decorations)) {
3736
- this.context = {
3737
- parent: this.editor,
3738
- selection: this.editor.selection,
3739
- decorations: decorations,
3740
- decorate: this.decorate,
3741
- readonly: this.readonly
3796
+ if (firstNewIndex !== firstOldIndex || lastNewIndex !== lastOldIndex) {
3797
+ const changedIndexesOfTop = [];
3798
+ const changedIndexesOfBottom = [];
3799
+ const needRemoveOnTop = firstNewIndex !== firstOldIndex && firstNewIndex > firstOldIndex;
3800
+ const needAddOnTop = firstNewIndex !== firstOldIndex && firstNewIndex < firstOldIndex;
3801
+ const needRemoveOnBottom = lastNewIndex !== lastOldIndex && lastOldIndex > lastNewIndex;
3802
+ const needAddOnBottom = lastNewIndex !== lastOldIndex && lastOldIndex < lastNewIndex;
3803
+ if (needRemoveOnTop || needAddOnBottom) {
3804
+ // 向下
3805
+ for (let index = 0; index < oldIndexesInViewport.length; index++) {
3806
+ const element = oldIndexesInViewport[index];
3807
+ if (!newIndexesInViewport.includes(element)) {
3808
+ changedIndexesOfTop.push(element);
3809
+ }
3810
+ else {
3811
+ break;
3812
+ }
3813
+ }
3814
+ for (let index = newIndexesInViewport.length - 1; index >= 0; index--) {
3815
+ const element = newIndexesInViewport[index];
3816
+ if (!oldIndexesInViewport.includes(element)) {
3817
+ changedIndexesOfBottom.push(element);
3818
+ }
3819
+ else {
3820
+ break;
3821
+ }
3822
+ }
3823
+ }
3824
+ else if (needAddOnTop || needRemoveOnBottom) {
3825
+ // 向上
3826
+ for (let index = 0; index < newIndexesInViewport.length; index++) {
3827
+ const element = newIndexesInViewport[index];
3828
+ if (!oldIndexesInViewport.includes(element)) {
3829
+ changedIndexesOfTop.push(element);
3830
+ }
3831
+ else {
3832
+ break;
3833
+ }
3834
+ }
3835
+ for (let index = oldIndexesInViewport.length - 1; index >= 0; index--) {
3836
+ const element = oldIndexesInViewport[index];
3837
+ if (!newIndexesInViewport.includes(element)) {
3838
+ changedIndexesOfBottom.push(element);
3839
+ }
3840
+ else {
3841
+ break;
3842
+ }
3843
+ }
3844
+ }
3845
+ if (isDebug) {
3846
+ debugLog('log', `====== diffVirtualViewport stage: ${stage} ======`);
3847
+ debugLog('log', 'oldIndexesInViewport:', oldIndexesInViewport);
3848
+ debugLog('log', 'newIndexesInViewport:', newIndexesInViewport);
3849
+ // this.editor.children[index] will be undefined when it is removed
3850
+ debugLog('log', 'changedIndexesOfTop:', needRemoveOnTop ? '-' : needAddOnTop ? '+' : '-', changedIndexesOfTop, changedIndexesOfTop.map(index => (this.editor.children[index] &&
3851
+ getCachedHeightByElement(this.editor, this.editor.children[index])) ||
3852
+ 0));
3853
+ debugLog('log', 'changedIndexesOfBottom:', needAddOnBottom ? '+' : needRemoveOnBottom ? '-' : '+', changedIndexesOfBottom, changedIndexesOfBottom.map(index => (this.editor.children[index] &&
3854
+ getCachedHeightByElement(this.editor, this.editor.children[index])) ||
3855
+ 0));
3856
+ const needTop = virtualView.heights.slice(0, newIndexesInViewport[0]).reduce((acc, height) => acc + height, 0);
3857
+ const needBottom = virtualView.heights
3858
+ .slice(newIndexesInViewport[newIndexesInViewport.length - 1] + 1)
3859
+ .reduce((acc, height) => acc + height, 0);
3860
+ debugLog('log', needTop - parseFloat(this.virtualTopHeightElement.style.height), 'newTopHeight:', needTop, 'prevTopHeight:', parseFloat(this.virtualTopHeightElement.style.height));
3861
+ debugLog('log', 'newBottomHeight:', needBottom, 'prevBottomHeight:', parseFloat(this.virtualBottomHeightElement.style.height));
3862
+ debugLog('warn', '=========== Dividing line ===========');
3863
+ }
3864
+ return {
3865
+ isDifferent: true,
3866
+ needRemoveOnTop,
3867
+ needAddOnTop,
3868
+ needRemoveOnBottom,
3869
+ needAddOnBottom,
3870
+ changedIndexesOfTop,
3871
+ changedIndexesOfBottom
3742
3872
  };
3743
- return true;
3744
3873
  }
3745
- return false;
3746
- }
3747
- initializeContext() {
3748
- this.context = {
3749
- parent: this.editor,
3750
- selection: this.editor.selection,
3751
- decorations: this.generateDecorations(),
3752
- decorate: this.decorate,
3753
- readonly: this.readonly
3874
+ return {
3875
+ isDifferent: false,
3876
+ changedIndexesOfTop: [],
3877
+ changedIndexesOfBottom: []
3754
3878
  };
3755
3879
  }
3756
- initializeViewContext() {
3757
- this.viewContext = {
3758
- editor: this.editor,
3759
- renderElement: this.renderElement,
3760
- renderLeaf: this.renderLeaf,
3761
- renderText: this.renderText,
3762
- trackBy: this.trackBy,
3763
- isStrictDecorate: this.isStrictDecorate
3764
- };
3880
+ //#region event proxy
3881
+ addEventListener(eventName, listener, target = this.elementRef.nativeElement) {
3882
+ this.manualListeners.push(this.renderer2.listen(target, eventName, (event) => {
3883
+ const beforeInputEvent = extractBeforeInputEvent(event.type, null, event, event.target);
3884
+ if (beforeInputEvent) {
3885
+ this.onFallbackBeforeInput(beforeInputEvent);
3886
+ }
3887
+ listener(event);
3888
+ }));
3765
3889
  }
3766
- composePlaceholderDecorate(editor) {
3767
- if (this.placeholderDecorate) {
3768
- return this.placeholderDecorate(editor) || [];
3769
- }
3770
- if (this.placeholder && editor.children.length === 1 && Array.from(Node.texts(editor)).length === 1 && Node.string(editor) === '') {
3771
- const start = Editor.start(editor, []);
3772
- return [
3773
- {
3774
- placeholder: this.placeholder,
3775
- anchor: start,
3776
- focus: start
3890
+ calculateVirtualScrollSelection(selection) {
3891
+ if (selection) {
3892
+ const isBlockCardCursor = AngularEditor.isBlockCardLeftCursor(this.editor) || AngularEditor.isBlockCardRightCursor(this.editor);
3893
+ const indics = this.inViewportIndics;
3894
+ if (indics.length > 0) {
3895
+ const currentVisibleRange = {
3896
+ anchor: Editor.start(this.editor, [indics[0]]),
3897
+ focus: Editor.end(this.editor, [indics[indics.length - 1]])
3898
+ };
3899
+ const [start, end] = Range.edges(selection);
3900
+ let forwardSelection = { anchor: start, focus: end };
3901
+ if (!isBlockCardCursor) {
3902
+ forwardSelection = { anchor: start, focus: end };
3777
3903
  }
3778
- ];
3779
- }
3780
- else {
3781
- return [];
3782
- }
3783
- }
3784
- generateDecorations() {
3785
- const decorations = this.decorate([this.editor, []]);
3786
- const placeholderDecorations = this.isComposing ? [] : this.composePlaceholderDecorate(this.editor);
3787
- decorations.push(...placeholderDecorations);
3788
- return decorations;
3789
- }
3790
- isEnabledVirtualScroll() {
3791
- return !!(this.virtualScrollConfig && this.virtualScrollConfig.enabled);
3792
- }
3793
- initializeVirtualScroll() {
3794
- if (this.virtualScrollInitialized) {
3795
- return;
3796
- }
3797
- if (this.isEnabledVirtualScroll()) {
3798
- this.virtualScrollInitialized = true;
3799
- this.virtualTopHeightElement = document.createElement('div');
3800
- this.virtualTopHeightElement.classList.add('virtual-top-height');
3801
- this.virtualTopHeightElement.contentEditable = 'false';
3802
- this.virtualBottomHeightElement = document.createElement('div');
3803
- this.virtualBottomHeightElement.classList.add('virtual-bottom-height');
3804
- this.virtualBottomHeightElement.contentEditable = 'false';
3805
- this.virtualCenterOutlet = document.createElement('div');
3806
- this.virtualCenterOutlet.classList.add('virtual-center-outlet');
3807
- this.elementRef.nativeElement.appendChild(this.virtualTopHeightElement);
3808
- this.elementRef.nativeElement.appendChild(this.virtualCenterOutlet);
3809
- this.elementRef.nativeElement.appendChild(this.virtualBottomHeightElement);
3810
- let editorResizeObserverRectWidth = this.elementRef.nativeElement.getBoundingClientRect().width;
3811
- EDITOR_TO_ROOT_NODE_WIDTH.set(this.editor, this.virtualTopHeightElement.offsetWidth);
3812
- this.editorResizeObserver = new ResizeObserver(entries => {
3813
- if (entries.length > 0 && entries[0].contentRect.width !== editorResizeObserverRectWidth) {
3814
- editorResizeObserverRectWidth = entries[0].contentRect.width;
3815
- this.keyHeightMap.clear();
3816
- let target = this.virtualTopHeightElement;
3817
- if (this.inViewportChildren[0]) {
3818
- const firstElement = this.inViewportChildren[0];
3819
- const firstDomElement = AngularEditor.toDOMNode(this.editor, firstElement);
3820
- target = firstDomElement;
3821
- }
3822
- EDITOR_TO_ROOT_NODE_WIDTH.set(this.editor, target.offsetWidth);
3823
- updatePreRenderingElementWidth(this.editor);
3824
- if (isDebug) {
3825
- debugLog('log', 'editorResizeObserverRectWidth: ', editorResizeObserverRectWidth, 'EDITOR_TO_ROOT_NODE_WIDTH: ', EDITOR_TO_ROOT_NODE_WIDTH.get(this.editor));
3826
- }
3904
+ else {
3905
+ forwardSelection = { anchor: { path: start.path, offset: 0 }, focus: { path: end.path, offset: 0 } };
3827
3906
  }
3828
- });
3829
- this.editorResizeObserver.observe(this.elementRef.nativeElement);
3830
- let pendingRemeasureIndics = [];
3831
- this.indicsOfNeedBeMeasured$
3832
- .pipe(tap((previousValue) => {
3833
- previousValue.forEach((index) => {
3834
- if (!pendingRemeasureIndics.includes(index)) {
3835
- pendingRemeasureIndics.push(index);
3907
+ const intersectedSelection = Range.intersection(forwardSelection, currentVisibleRange);
3908
+ if (intersectedSelection && isBlockCardCursor) {
3909
+ return selection;
3910
+ }
3911
+ EDITOR_TO_VIRTUAL_SCROLL_SELECTION.set(this.editor, intersectedSelection);
3912
+ if (!intersectedSelection || !Range.equals(intersectedSelection, forwardSelection)) {
3913
+ if (isDebug) {
3914
+ debugLog('log', `selection is not in visible range, selection: ${JSON.stringify(selection)}, currentVisibleRange: ${JSON.stringify(currentVisibleRange)}, intersectedSelection: ${JSON.stringify(intersectedSelection)}`);
3836
3915
  }
3837
- });
3838
- }), debounceTime(500), filter(() => pendingRemeasureIndics.length > 0))
3839
- .subscribe(() => {
3840
- measureHeightByIndics(this.editor, pendingRemeasureIndics, true);
3841
- pendingRemeasureIndics = [];
3842
- if (isDebug) {
3843
- debugLog('log', 'exist pendingRemeasureIndics: ', pendingRemeasureIndics, 'will try to update virtual viewport');
3916
+ return intersectedSelection;
3844
3917
  }
3845
- this.tryUpdateVirtualViewport();
3846
- });
3847
- }
3848
- }
3849
- getChangedIndics(previousValue) {
3850
- const remeasureIndics = [];
3851
- this.inViewportChildren.forEach((child, index) => {
3852
- if (previousValue.indexOf(child) === -1) {
3853
- remeasureIndics.push(this.inViewportIndics[index]);
3918
+ return selection;
3854
3919
  }
3855
- });
3856
- return remeasureIndics;
3857
- }
3858
- setVirtualSpaceHeight(topHeight, bottomHeight) {
3859
- if (!this.virtualScrollInitialized) {
3860
- return;
3861
- }
3862
- this.virtualTopHeightElement.style.height = `${topHeight}px`;
3863
- if (bottomHeight !== undefined) {
3864
- this.virtualBottomHeightElement.style.height = `${bottomHeight}px`;
3865
3920
  }
3921
+ EDITOR_TO_VIRTUAL_SCROLL_SELECTION.set(this.editor, null);
3922
+ return selection;
3866
3923
  }
3867
- getActualVirtualTopHeight() {
3868
- if (!this.virtualScrollInitialized) {
3869
- return 0;
3870
- }
3871
- return parseFloat(this.virtualTopHeightElement.style.height.replace('px', ''));
3924
+ isSelectionInvisible(selection) {
3925
+ const anchorIndex = selection.anchor.path[0];
3926
+ const focusIndex = selection.focus.path[0];
3927
+ const anchorElement = this.editor.children[anchorIndex];
3928
+ const focusElement = this.editor.children[focusIndex];
3929
+ return !anchorElement || !focusElement || !this.editor.isVisible(anchorElement) || !this.editor.isVisible(focusElement);
3872
3930
  }
3873
- handlePreRendering(visibleStates) {
3874
- let preRenderingCount = 0;
3875
- const childrenWithPreRendering = [...this.inViewportChildren];
3876
- const childrenWithPreRenderingIndics = [...this.inViewportIndics];
3877
- const firstIndex = this.inViewportIndics[0];
3878
- for (let index = firstIndex - 1; index >= 0; index--) {
3879
- const element = this.editor.children[index];
3880
- if (visibleStates[index]) {
3881
- childrenWithPreRendering.unshift(element);
3882
- childrenWithPreRenderingIndics.unshift(index);
3883
- preRenderingCount = 1;
3884
- break;
3931
+ toNativeSelection(autoScroll = true) {
3932
+ try {
3933
+ let { selection } = this.editor;
3934
+ if (this.isEnabledVirtualScroll()) {
3935
+ selection = this.calculateVirtualScrollSelection(selection);
3885
3936
  }
3886
- }
3887
- const lastIndex = this.inViewportIndics[this.inViewportIndics.length - 1];
3888
- for (let index = lastIndex + 1; index < this.editor.children.length; index++) {
3889
- const element = this.editor.children[index];
3890
- if (visibleStates[index]) {
3891
- childrenWithPreRendering.push(element);
3892
- childrenWithPreRenderingIndics.push(index);
3893
- break;
3937
+ const root = AngularEditor.findDocumentOrShadowRoot(this.editor);
3938
+ const { activeElement } = root;
3939
+ const domSelection = root.getSelection();
3940
+ if ((this.isComposing && !IS_ANDROID) || !domSelection) {
3941
+ return;
3894
3942
  }
3895
- }
3896
- return { preRenderingCount, childrenWithPreRendering, childrenWithPreRenderingIndics };
3897
- }
3898
- tryUpdateVirtualViewport() {
3899
- if (isDebug) {
3900
- debugLog('log', 'tryUpdateVirtualViewport');
3901
- }
3902
- const isFromScrollTo = EDITOR_TO_IS_FROM_SCROLL_TO.get(this.editor);
3903
- if (this.inViewportIndics.length > 0 && !isFromScrollTo) {
3904
- const topHeight = this.getActualVirtualTopHeight();
3905
- const visibleStates = this.editor.getAllVisibleStates();
3906
- const refreshVirtualTopHeight = calculateVirtualTopHeight(this.editor, this.inViewportIndics[0], visibleStates);
3907
- if (topHeight !== refreshVirtualTopHeight) {
3908
- if (isDebug) {
3909
- debugLog('log', 'update top height since dirty state(正数减去高度,负数代表增加高度): ', topHeight - refreshVirtualTopHeight);
3910
- }
3911
- this.setVirtualSpaceHeight(refreshVirtualTopHeight);
3943
+ const hasDomSelection = domSelection.type !== 'None';
3944
+ // If the DOM selection is properly unset, we're done.
3945
+ if (!selection && !hasDomSelection) {
3912
3946
  return;
3913
3947
  }
3914
- }
3915
- this.tryUpdateVirtualViewportAnimId && cancelAnimationFrame(this.tryUpdateVirtualViewportAnimId);
3916
- this.tryUpdateVirtualViewportAnimId = requestAnimationFrame(() => {
3917
- if (isDebug) {
3918
- debugLog('log', 'tryUpdateVirtualViewport Anim start');
3948
+ // If the DOM selection is already correct, we're done.
3949
+ // verify that the dom selection is in the editor
3950
+ const editorElement = EDITOR_TO_ELEMENT.get(this.editor);
3951
+ let hasDomSelectionInEditor = false;
3952
+ if (editorElement.contains(domSelection.anchorNode) && editorElement.contains(domSelection.focusNode)) {
3953
+ hasDomSelectionInEditor = true;
3919
3954
  }
3920
- const visibleStates = this.editor.getAllVisibleStates();
3921
- let virtualView = this.calculateVirtualViewport(visibleStates);
3922
- let diff = this.diffVirtualViewport(virtualView);
3923
- if (diff.isDifferent && diff.needRemoveOnTop && !isFromScrollTo) {
3924
- const remeasureIndics = diff.changedIndexesOfTop;
3925
- const changed = measureHeightByIndics(this.editor, remeasureIndics);
3926
- if (changed) {
3927
- virtualView = this.calculateVirtualViewport(visibleStates);
3928
- diff = this.diffVirtualViewport(virtualView, 'second');
3955
+ // If the DOM selection is in the editor and the editor selection is already correct, we're done.
3956
+ if (hasDomSelection && hasDomSelectionInEditor && selection && hasStringTarget(domSelection)) {
3957
+ const rangeFromDOMSelection = AngularEditor.toSlateRange(this.editor, domSelection, {
3958
+ exactMatch: false,
3959
+ suppressThrow: true
3960
+ });
3961
+ if (rangeFromDOMSelection && Range.equals(rangeFromDOMSelection, selection)) {
3962
+ return;
3929
3963
  }
3930
3964
  }
3931
- if (diff.isDifferent) {
3932
- this.applyVirtualView(virtualView);
3933
- if (this.listRender.initialized) {
3934
- const { preRenderingCount, childrenWithPreRendering, childrenWithPreRenderingIndics } = this.handlePreRendering(visibleStates);
3935
- this.listRender.update(childrenWithPreRendering, this.editor, this.context, preRenderingCount, childrenWithPreRenderingIndics);
3936
- if (diff.needAddOnTop && !isFromScrollTo) {
3937
- const remeasureAddedIndics = diff.changedIndexesOfTop;
3938
- if (isDebug) {
3939
- debugLog('log', 'needAddOnTop to remeasure heights: ', remeasureAddedIndics);
3940
- }
3941
- const startIndexBeforeAdd = diff.changedIndexesOfTop[diff.changedIndexesOfTop.length - 1] + 1;
3942
- const topHeightBeforeAdd = virtualView.accumulatedHeights[startIndexBeforeAdd];
3943
- const changed = measureHeightByIndics(this.editor, remeasureAddedIndics);
3944
- if (changed) {
3945
- const newHeights = buildHeightsAndAccumulatedHeights(this.editor, visibleStates);
3946
- const actualTopHeightAfterAdd = newHeights.accumulatedHeights[startIndexBeforeAdd];
3947
- const newTopHeight = virtualView.top - (actualTopHeightAfterAdd - topHeightBeforeAdd);
3948
- this.setVirtualSpaceHeight(newTopHeight);
3949
- if (isDebug) {
3950
- debugLog('log', `update top height since will add element in top(正数减去高度,负数代表增加高度): ${actualTopHeightAfterAdd - topHeightBeforeAdd}`);
3951
- }
3952
- }
3953
- }
3954
- if (this.editor.selection) {
3955
- this.toNativeSelection(false);
3956
- }
3965
+ // prevent updating native selection when active element is void element
3966
+ if (isTargetInsideVoid(this.editor, activeElement)) {
3967
+ return;
3968
+ }
3969
+ // when <Editable/> is being controlled through external value
3970
+ // then its children might just change - DOM responds to it on its own
3971
+ // but Slate's value is not being updated through any operation
3972
+ // and thus it doesn't transform selection on its own
3973
+ if (selection && !AngularEditor.hasRange(this.editor, selection)) {
3974
+ this.editor.selection = AngularEditor.toSlateRange(this.editor, domSelection, { exactMatch: false, suppressThrow: false });
3975
+ return;
3976
+ }
3977
+ // Otherwise the DOM selection is out of sync, so update it.
3978
+ const el = AngularEditor.toDOMNode(this.editor, this.editor);
3979
+ this.isUpdatingSelection = true;
3980
+ const newDomRange = selection && AngularEditor.toDOMRange(this.editor, selection);
3981
+ if (newDomRange) {
3982
+ // COMPAT: Since the DOM range has no concept of backwards/forwards
3983
+ // we need to check and do the right thing here.
3984
+ if (Range.isBackward(selection)) {
3985
+ // eslint-disable-next-line max-len
3986
+ domSelection.setBaseAndExtent(newDomRange.endContainer, newDomRange.endOffset, newDomRange.startContainer, newDomRange.startOffset);
3987
+ }
3988
+ else {
3989
+ // eslint-disable-next-line max-len
3990
+ domSelection.setBaseAndExtent(newDomRange.startContainer, newDomRange.startOffset, newDomRange.endContainer, newDomRange.endOffset);
3957
3991
  }
3958
3992
  }
3959
- if (isDebug) {
3960
- debugLog('log', 'tryUpdateVirtualViewport Anim end');
3993
+ else {
3994
+ domSelection.removeAllRanges();
3961
3995
  }
3962
- });
3996
+ setTimeout(() => {
3997
+ if (this.isEnabledVirtualScroll() &&
3998
+ !selection &&
3999
+ this.editor.selection &&
4000
+ autoScroll &&
4001
+ this.virtualScrollConfig.scrollContainer) {
4002
+ this.virtualScrollConfig.scrollContainer.scrollTop = this.virtualScrollConfig.scrollContainer.scrollTop + 100;
4003
+ this.isUpdatingSelection = false;
4004
+ return;
4005
+ }
4006
+ else {
4007
+ // handle scrolling in setTimeout because of
4008
+ // dom should not have updated immediately after listRender's updating
4009
+ newDomRange && autoScroll && this.scrollSelectionIntoView(this.editor, newDomRange);
4010
+ // COMPAT: In Firefox, it's not enough to create a range, you also need
4011
+ // to focus the contenteditable element too. (2016/11/16)
4012
+ if (newDomRange && IS_FIREFOX) {
4013
+ el.focus();
4014
+ }
4015
+ }
4016
+ this.isUpdatingSelection = false;
4017
+ });
4018
+ }
4019
+ catch (error) {
4020
+ this.editor.onError({
4021
+ code: SlateErrorCode.ToNativeSelectionError,
4022
+ nativeError: error
4023
+ });
4024
+ this.isUpdatingSelection = false;
4025
+ }
3963
4026
  }
3964
- calculateVirtualViewport(visibleStates) {
3965
- const children = (this.editor.children || []);
3966
- if (!children.length || !this.isEnabledVirtualScroll()) {
3967
- return {
3968
- inViewportChildren: children,
3969
- inViewportIndics: [],
3970
- top: 0,
3971
- bottom: 0,
3972
- heights: []
3973
- };
4027
+ onChange() {
4028
+ this.forceRender();
4029
+ this.onChangeCallback(this.editor.children);
4030
+ }
4031
+ ngAfterViewChecked() { }
4032
+ ngDoCheck() { }
4033
+ forceRender() {
4034
+ this.updateContext();
4035
+ if (this.isEnabledVirtualScroll()) {
4036
+ this.updateListRenderAndRemeasureHeights();
4037
+ }
4038
+ else {
4039
+ this.listRender.update(this.editor.children, this.editor, this.context);
4040
+ }
4041
+ // repair collaborative editing when Chinese input is interrupted by other users' cursors
4042
+ // when the DOMElement where the selection is located is removed
4043
+ // the compositionupdate and compositionend events will no longer be fired
4044
+ // so isComposing needs to be corrected
4045
+ // need exec after this.cdr.detectChanges() to render HTML
4046
+ // need exec before this.toNativeSelection() to correct native selection
4047
+ if (this.isComposing) {
4048
+ // Composition input text be not rendered when user composition input with selection is expanded
4049
+ // At this time, the following matching conditions are met, assign isComposing to false, and the status is wrong
4050
+ // this time condition is true and isComposing is assigned false
4051
+ // Therefore, need to wait for the composition input text to be rendered before performing condition matching
4052
+ setTimeout(() => {
4053
+ const textNode = Node.get(this.editor, this.editor.selection.anchor.path);
4054
+ const textDOMNode = AngularEditor.toDOMNode(this.editor, textNode);
4055
+ let textContent = '';
4056
+ // skip decorate text
4057
+ textDOMNode.querySelectorAll('[editable-text]').forEach(stringDOMNode => {
4058
+ let text = stringDOMNode.textContent;
4059
+ const zeroChar = '\uFEFF';
4060
+ // remove zero with char
4061
+ if (text.startsWith(zeroChar)) {
4062
+ text = text.slice(1);
4063
+ }
4064
+ if (text.endsWith(zeroChar)) {
4065
+ text = text.slice(0, text.length - 1);
4066
+ }
4067
+ textContent += text;
4068
+ });
4069
+ if (Node.string(textNode).endsWith(textContent)) {
4070
+ this.isComposing = false;
4071
+ }
4072
+ }, 0);
3974
4073
  }
3975
- const scrollTop = this.virtualScrollConfig.scrollTop;
3976
- const viewportHeight = this.virtualScrollConfig.viewportHeight ?? 0;
3977
- if (!viewportHeight) {
3978
- return {
3979
- inViewportChildren: [],
3980
- inViewportIndics: [],
3981
- top: 0,
3982
- bottom: 0,
3983
- heights: []
3984
- };
4074
+ if (this.editor.selection && this.isSelectionInvisible(this.editor.selection)) {
4075
+ Transforms.deselect(this.editor);
4076
+ return;
3985
4077
  }
3986
- const elementLength = children.length;
3987
- if (!EDITOR_TO_BUSINESS_TOP.has(this.editor)) {
3988
- EDITOR_TO_BUSINESS_TOP.set(this.editor, 0);
3989
- setTimeout(() => {
3990
- const virtualTopBoundingTop = this.virtualTopHeightElement.getBoundingClientRect()?.top ?? 0;
3991
- const businessTop = Math.ceil(virtualTopBoundingTop) +
3992
- Math.ceil(this.virtualScrollConfig.scrollTop) -
3993
- Math.floor(this.virtualScrollConfig.viewportBoundingTop);
3994
- EDITOR_TO_BUSINESS_TOP.set(this.editor, businessTop);
3995
- if (isDebug) {
3996
- debugLog('log', 'businessTop', businessTop);
3997
- }
3998
- }, 100);
4078
+ else {
4079
+ this.toNativeSelection();
3999
4080
  }
4000
- const adjustedScrollTop = Math.max(0, scrollTop - getBusinessTop(this.editor));
4001
- const { heights, accumulatedHeights } = buildHeightsAndAccumulatedHeights(this.editor, visibleStates);
4002
- const totalHeight = accumulatedHeights[elementLength];
4003
- const maxScrollTop = Math.max(0, totalHeight - viewportHeight);
4004
- const limitedScrollTop = Math.min(adjustedScrollTop, maxScrollTop);
4005
- const viewBottom = limitedScrollTop + viewportHeight;
4006
- let accumulatedOffset = 0;
4007
- let inViewportStartIndex = -1;
4008
- const visible = [];
4009
- const inViewportIndics = [];
4010
- for (let i = 0; i < elementLength && accumulatedOffset < viewBottom; i++) {
4011
- const currentHeight = heights[i];
4012
- const nextOffset = accumulatedOffset + currentHeight;
4013
- const isVisible = visibleStates[i];
4014
- if (!isVisible) {
4015
- accumulatedOffset = nextOffset;
4016
- continue;
4081
+ }
4082
+ render() {
4083
+ const changed = this.updateContext();
4084
+ if (changed) {
4085
+ if (this.isEnabledVirtualScroll()) {
4086
+ this.updateListRenderAndRemeasureHeights();
4017
4087
  }
4018
- // 可视区域有交集,加入渲染
4019
- if (nextOffset > limitedScrollTop && accumulatedOffset < viewBottom) {
4020
- if (inViewportStartIndex === -1)
4021
- inViewportStartIndex = i; // 第一个相交起始位置
4022
- visible.push(children[i]);
4023
- inViewportIndics.push(i);
4088
+ else {
4089
+ this.listRender.update(this.editor.children, this.editor, this.context);
4024
4090
  }
4025
- accumulatedOffset = nextOffset;
4026
4091
  }
4027
- const inViewportEndIndex = inViewportStartIndex === -1 ? elementLength - 1 : (inViewportIndics[inViewportIndics.length - 1] ?? inViewportStartIndex);
4028
- const top = inViewportStartIndex === -1 ? 0 : accumulatedHeights[inViewportStartIndex];
4029
- const bottom = totalHeight - accumulatedHeights[inViewportEndIndex + 1];
4030
- return {
4031
- inViewportChildren: visible.length ? visible : children,
4032
- inViewportIndics,
4033
- top,
4034
- bottom,
4035
- heights,
4036
- accumulatedHeights
4037
- };
4038
- }
4039
- applyVirtualView(virtualView) {
4040
- this.inViewportChildren = virtualView.inViewportChildren;
4041
- this.setVirtualSpaceHeight(virtualView.top, virtualView.bottom);
4042
- this.inViewportIndics = virtualView.inViewportIndics;
4043
4092
  }
4044
- diffVirtualViewport(virtualView, stage = 'first') {
4045
- if (!this.inViewportChildren.length) {
4093
+ updateListRenderAndRemeasureHeights() {
4094
+ const operations = this.editor.operations;
4095
+ const firstIndex = this.inViewportIndics[0];
4096
+ const operationsOfFirstElementMerged = operations.filter(op => op.type === 'merge_node' && op.path.length === 1 && firstIndex === op.path[0] - 1);
4097
+ const operationsOfFirstElementSplitted = operations.filter(op => op.type === 'split_node' && op.path.length === 1 && firstIndex === op.path[0]);
4098
+ const mutationOfFirstElementHeight = operationsOfFirstElementSplitted.length > 0 || operationsOfFirstElementMerged.length > 0;
4099
+ const visibleStates = this.editor.getAllVisibleStates();
4100
+ const previousInViewportChildren = [...this.inViewportChildren];
4101
+ // the first element height will reset to default height when split or merge
4102
+ // if the most top content of the first element is not in viewport, the change of height will cause the viewport to scroll
4103
+ // to keep viewport stable, we need to use the current inViewportIndics temporarily
4104
+ if (mutationOfFirstElementHeight) {
4105
+ const newInViewportIndics = [];
4106
+ const newInViewportChildren = [];
4107
+ this.inViewportIndics.forEach(index => {
4108
+ const element = this.editor.children[index];
4109
+ const isVisible = visibleStates[index];
4110
+ if (isVisible) {
4111
+ newInViewportIndics.push(index);
4112
+ newInViewportChildren.push(element);
4113
+ }
4114
+ });
4115
+ this.inViewportIndics = newInViewportIndics;
4116
+ this.inViewportChildren = newInViewportChildren;
4046
4117
  if (isDebug) {
4047
- debugLog('log', 'diffVirtualViewport', stage, 'empty inViewportChildren', virtualView.inViewportIndics);
4118
+ debugLog('log', 'updateListRenderAndRemeasureHeights', 'mutationOfFirstElementHeight', 'newInViewportIndics', newInViewportIndics);
4048
4119
  }
4049
- return {
4050
- isDifferent: true,
4051
- changedIndexesOfTop: [],
4052
- changedIndexesOfBottom: []
4053
- };
4054
- }
4055
- const oldIndexesInViewport = [...this.inViewportIndics];
4056
- const newIndexesInViewport = [...virtualView.inViewportIndics];
4057
- const firstNewIndex = newIndexesInViewport[0];
4058
- const lastNewIndex = newIndexesInViewport[newIndexesInViewport.length - 1];
4059
- const firstOldIndex = oldIndexesInViewport[0];
4060
- const lastOldIndex = oldIndexesInViewport[oldIndexesInViewport.length - 1];
4061
- const isSameViewport = oldIndexesInViewport.length === newIndexesInViewport.length &&
4062
- oldIndexesInViewport.every((index, i) => index === newIndexesInViewport[i]);
4063
- if (firstNewIndex === firstOldIndex && lastNewIndex === lastOldIndex) {
4064
- return {
4065
- isDifferent: !isSameViewport,
4066
- changedIndexesOfTop: [],
4067
- changedIndexesOfBottom: []
4068
- };
4069
4120
  }
4070
- if (firstNewIndex !== firstOldIndex || lastNewIndex !== lastOldIndex) {
4071
- const changedIndexesOfTop = [];
4072
- const changedIndexesOfBottom = [];
4073
- const needRemoveOnTop = firstNewIndex !== firstOldIndex && firstNewIndex > firstOldIndex;
4074
- const needAddOnTop = firstNewIndex !== firstOldIndex && firstNewIndex < firstOldIndex;
4075
- const needRemoveOnBottom = lastNewIndex !== lastOldIndex && lastOldIndex > lastNewIndex;
4076
- const needAddOnBottom = lastNewIndex !== lastOldIndex && lastOldIndex < lastNewIndex;
4077
- if (needRemoveOnTop || needAddOnBottom) {
4078
- // 向下
4079
- for (let index = 0; index < oldIndexesInViewport.length; index++) {
4080
- const element = oldIndexesInViewport[index];
4081
- if (!newIndexesInViewport.includes(element)) {
4082
- changedIndexesOfTop.push(element);
4083
- }
4084
- else {
4085
- break;
4086
- }
4087
- }
4088
- for (let index = newIndexesInViewport.length - 1; index >= 0; index--) {
4089
- const element = newIndexesInViewport[index];
4090
- if (!oldIndexesInViewport.includes(element)) {
4091
- changedIndexesOfBottom.push(element);
4092
- }
4093
- else {
4094
- break;
4095
- }
4096
- }
4097
- }
4098
- else if (needAddOnTop || needRemoveOnBottom) {
4099
- // 向上
4100
- for (let index = 0; index < newIndexesInViewport.length; index++) {
4101
- const element = newIndexesInViewport[index];
4102
- if (!oldIndexesInViewport.includes(element)) {
4103
- changedIndexesOfTop.push(element);
4104
- }
4105
- else {
4106
- break;
4107
- }
4108
- }
4109
- for (let index = oldIndexesInViewport.length - 1; index >= 0; index--) {
4110
- const element = oldIndexesInViewport[index];
4111
- if (!newIndexesInViewport.includes(element)) {
4112
- changedIndexesOfBottom.push(element);
4113
- }
4114
- else {
4115
- break;
4116
- }
4121
+ else {
4122
+ let virtualView = this.calculateVirtualViewport(visibleStates);
4123
+ let diff = this.diffVirtualViewport(virtualView, 'onChange');
4124
+ if (diff.isDifferent && diff.needRemoveOnTop) {
4125
+ const remeasureIndics = diff.changedIndexesOfTop;
4126
+ const changed = measureHeightByIndics(this.editor, remeasureIndics);
4127
+ if (changed) {
4128
+ virtualView = this.calculateVirtualViewport(visibleStates);
4129
+ diff = this.diffVirtualViewport(virtualView, 'second');
4117
4130
  }
4118
4131
  }
4119
- if (isDebug) {
4120
- debugLog('log', `====== diffVirtualViewport stage: ${stage} ======`);
4121
- debugLog('log', 'oldIndexesInViewport:', oldIndexesInViewport);
4122
- debugLog('log', 'newIndexesInViewport:', newIndexesInViewport);
4123
- // this.editor.children[index] will be undefined when it is removed
4124
- debugLog('log', 'changedIndexesOfTop:', needRemoveOnTop ? '-' : needAddOnTop ? '+' : '-', changedIndexesOfTop, changedIndexesOfTop.map(index => (this.editor.children[index] &&
4125
- getCachedHeightByElement(this.editor, this.editor.children[index])) ||
4126
- 0));
4127
- debugLog('log', 'changedIndexesOfBottom:', needAddOnBottom ? '+' : needRemoveOnBottom ? '-' : '+', changedIndexesOfBottom, changedIndexesOfBottom.map(index => (this.editor.children[index] &&
4128
- getCachedHeightByElement(this.editor, this.editor.children[index])) ||
4129
- 0));
4130
- const needTop = virtualView.heights.slice(0, newIndexesInViewport[0]).reduce((acc, height) => acc + height, 0);
4131
- const needBottom = virtualView.heights
4132
- .slice(newIndexesInViewport[newIndexesInViewport.length - 1] + 1)
4133
- .reduce((acc, height) => acc + height, 0);
4134
- debugLog('log', needTop - parseFloat(this.virtualTopHeightElement.style.height), 'newTopHeight:', needTop, 'prevTopHeight:', parseFloat(this.virtualTopHeightElement.style.height));
4135
- debugLog('log', 'newBottomHeight:', needBottom, 'prevBottomHeight:', parseFloat(this.virtualBottomHeightElement.style.height));
4136
- debugLog('warn', '=========== Dividing line ===========');
4137
- }
4138
- return {
4139
- isDifferent: true,
4140
- needRemoveOnTop,
4141
- needAddOnTop,
4142
- needRemoveOnBottom,
4143
- needAddOnBottom,
4144
- changedIndexesOfTop,
4145
- changedIndexesOfBottom
4132
+ this.applyVirtualView(virtualView);
4133
+ }
4134
+ const { preRenderingCount, childrenWithPreRendering, childrenWithPreRenderingIndics } = this.handlePreRendering(visibleStates);
4135
+ this.listRender.update(childrenWithPreRendering, this.editor, this.context, preRenderingCount, childrenWithPreRenderingIndics);
4136
+ const remeasureIndics = this.getChangedIndics(previousInViewportChildren);
4137
+ if (remeasureIndics.length) {
4138
+ this.indicsOfNeedBeMeasured$.next(remeasureIndics);
4139
+ }
4140
+ }
4141
+ updateContext() {
4142
+ const decorations = this.generateDecorations();
4143
+ if (this.context.selection !== this.editor.selection ||
4144
+ this.context.decorate !== this.decorate ||
4145
+ this.context.readonly !== this.readonly ||
4146
+ !isDecoratorRangeListEqual(this.context.decorations, decorations)) {
4147
+ this.context = {
4148
+ parent: this.editor,
4149
+ selection: this.editor.selection,
4150
+ decorations: decorations,
4151
+ decorate: this.decorate,
4152
+ readonly: this.readonly
4146
4153
  };
4154
+ return true;
4147
4155
  }
4148
- return {
4149
- isDifferent: false,
4150
- changedIndexesOfTop: [],
4151
- changedIndexesOfBottom: []
4156
+ return false;
4157
+ }
4158
+ initializeContext() {
4159
+ this.context = {
4160
+ parent: this.editor,
4161
+ selection: this.editor.selection,
4162
+ decorations: this.generateDecorations(),
4163
+ decorate: this.decorate,
4164
+ readonly: this.readonly
4152
4165
  };
4153
4166
  }
4154
- //#region event proxy
4155
- addEventListener(eventName, listener, target = this.elementRef.nativeElement) {
4156
- this.manualListeners.push(this.renderer2.listen(target, eventName, (event) => {
4157
- const beforeInputEvent = extractBeforeInputEvent(event.type, null, event, event.target);
4158
- if (beforeInputEvent) {
4159
- this.onFallbackBeforeInput(beforeInputEvent);
4160
- }
4161
- listener(event);
4162
- }));
4167
+ initializeViewContext() {
4168
+ this.viewContext = {
4169
+ editor: this.editor,
4170
+ renderElement: this.renderElement,
4171
+ renderLeaf: this.renderLeaf,
4172
+ renderText: this.renderText,
4173
+ trackBy: this.trackBy,
4174
+ isStrictDecorate: this.isStrictDecorate
4175
+ };
4176
+ }
4177
+ composePlaceholderDecorate(editor) {
4178
+ if (this.placeholderDecorate) {
4179
+ return this.placeholderDecorate(editor) || [];
4180
+ }
4181
+ if (this.placeholder && editor.children.length === 1 && Array.from(Node.texts(editor)).length === 1 && Node.string(editor) === '') {
4182
+ const start = Editor.start(editor, []);
4183
+ return [
4184
+ {
4185
+ placeholder: this.placeholder,
4186
+ anchor: start,
4187
+ focus: start
4188
+ }
4189
+ ];
4190
+ }
4191
+ else {
4192
+ return [];
4193
+ }
4194
+ }
4195
+ generateDecorations() {
4196
+ const decorations = this.decorate([this.editor, []]);
4197
+ const placeholderDecorations = this.isComposing ? [] : this.composePlaceholderDecorate(this.editor);
4198
+ decorations.push(...placeholderDecorations);
4199
+ return decorations;
4163
4200
  }
4164
4201
  toSlateSelection() {
4165
4202
  if ((!this.isComposing || IS_ANDROID) && !this.isUpdatingSelection && !this.isDraggingInternally) {
@@ -5373,5 +5410,5 @@ i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "20.3.12", ngImpo
5373
5410
  * Generated bundle index. Do not edit.
5374
5411
  */
5375
5412
 
5376
- export { AngularEditor, BaseComponent, BaseElementComponent, BaseElementFlavour, BaseFlavour, BaseLeafComponent, BaseLeafFlavour, BaseTextComponent, BaseTextFlavour, BlockCardRef, DEFAULT_ELEMENT_HEIGHT, DefaultTextFlavour, EDITOR_TO_AFTER_VIEW_INIT_QUEUE, EDITOR_TO_BUSINESS_TOP, EDITOR_TO_IS_FROM_SCROLL_TO, EDITOR_TO_ROOT_NODE_WIDTH, EDITOR_TO_VIRTUAL_SCROLL_SELECTION, ELEMENT_KEY_TO_HEIGHTS, ELEMENT_TO_COMPONENT, FAKE_LEFT_BLOCK_CARD_OFFSET, FAKE_RIGHT_BLOCK_CARD_OFFSET, FlavourRef, HAS_BEFORE_INPUT_SUPPORT, IS_ANDROID, IS_APPLE, IS_CHROME, IS_CHROME_LEGACY, IS_EDGE_LEGACY, IS_ENABLED_VIRTUAL_SCROLL, IS_FIREFOX, IS_FIREFOX_LEGACY, IS_IOS, IS_QQBROWSER, IS_SAFARI, IS_UC_MOBILE, IS_WECHATBROWSER, PLACEHOLDER_SYMBOL, SLATE_BLOCK_CARD_CLASS_NAME, SLATE_DEBUG_KEY, SLATE_DEBUG_KEY_SCROLL_TOP, SlateBlockCard, SlateChildrenOutlet, SlateEditable, SlateErrorCode, SlateFragmentAttributeKey, SlateModule, SlateString, VIRTUAL_SCROLL_DEFAULT_BLOCK_HEIGHT, VoidTextFlavour, blobAsString, buildHTMLText, buildHeightsAndAccumulatedHeights, cacheHeightByElement, calcHeightByElement, calculateVirtualTopHeight, check, clearMinHeightByElement, completeTable, createClipboardData, createText, createThrottleRAF, debugLog, defaultScrollSelectionIntoView, fallbackCopyText, getBlockCardByNativeElement, getBusinessTop, getCachedHeightByElement, getCardTargetAttribute, getClipboardData, getClipboardFromHTMLText, getContentHeight, getDataTransferClipboard, getDataTransferClipboardText, getNavigatorClipboard, getPlainText, getSelection, getSlateFragmentAttribute, getZeroTextNode, hasAfterContextChange, hasBeforeContextChange, hasBlockCard, hasBlockCardWithNode, hotkeys, isCardCenterByTargetAttr, isCardLeft, isCardLeftByTargetAttr, isCardRightByTargetAttr, isClipboardFile, isClipboardReadSupported, isClipboardWriteSupported, isClipboardWriteTextSupported, isComponentType, isDOMText, isDebug, isDebugScrollTop, isDecoratorRangeListEqual, isFlavourType, isInvalidTable, isTemplateRef, isValid, measureHeightByIndics, normalize, scrollToElement, setClipboardData, setDataTransferClipboard, setDataTransferClipboardText, setMinHeightByElement, setNavigatorClipboard, shallowCompare, stripHtml, withAngular };
5413
+ export { AngularEditor, BaseComponent, BaseElementComponent, BaseElementFlavour, BaseFlavour, BaseLeafComponent, BaseLeafFlavour, BaseTextComponent, BaseTextFlavour, BlockCardRef, DEFAULT_ELEMENT_HEIGHT, DefaultTextFlavour, EDITOR_TO_AFTER_VIEW_INIT_QUEUE, EDITOR_TO_BUSINESS_TOP, EDITOR_TO_IS_FROM_SCROLL_TO, EDITOR_TO_ROOT_NODE_WIDTH, EDITOR_TO_VIRTUAL_SCROLL_SELECTION, ELEMENT_KEY_TO_HEIGHTS, ELEMENT_TO_COMPONENT, FAKE_LEFT_BLOCK_CARD_OFFSET, FAKE_RIGHT_BLOCK_CARD_OFFSET, FlavourRef, HAS_BEFORE_INPUT_SUPPORT, IS_ANDROID, IS_APPLE, IS_CHROME, IS_CHROME_LEGACY, IS_EDGE_LEGACY, IS_ENABLED_VIRTUAL_SCROLL, IS_FIREFOX, IS_FIREFOX_LEGACY, IS_IOS, IS_QQBROWSER, IS_SAFARI, IS_UC_MOBILE, IS_WECHATBROWSER, PLACEHOLDER_SYMBOL, SLATE_BLOCK_CARD_CLASS_NAME, SLATE_DEBUG_KEY, SLATE_DEBUG_KEY_SCROLL_TOP, SlateBlockCard, SlateChildrenOutlet, SlateEditable, SlateErrorCode, SlateFragmentAttributeKey, SlateModule, SlateString, VIRTUAL_SCROLL_DEFAULT_BLOCK_HEIGHT, VoidTextFlavour, blobAsString, buildHTMLText, buildHeightsAndAccumulatedHeights, cacheHeightByElement, calcHeightByElement, calculateVirtualTopHeight, check, clearMinHeightByElement, completeTable, createClipboardData, createText, createThrottleRAF, debugLog, defaultScrollSelectionIntoView, fallbackCopyText, getBlockCardByNativeElement, getBusinessTop, getCachedHeightByElement, getCardTargetAttribute, getClipboardData, getClipboardFromHTMLText, getContentHeight, getDataTransferClipboard, getDataTransferClipboardText, getNavigatorClipboard, getPlainText, getSelection, getSlateFragmentAttribute, getZeroTextNode, hasAfterContextChange, hasBeforeContextChange, hasBlockCard, hasBlockCardWithNode, hotkeys, isCardCenterByTargetAttr, isCardLeft, isCardLeftByTargetAttr, isCardRightByTargetAttr, isClipboardFile, isClipboardReadSupported, isClipboardWriteSupported, isClipboardWriteTextSupported, isComponentType, isDOMText, isDebug, isDebugScrollTop, isDecoratorRangeListEqual, isFlavourType, isInvalidTable, isTemplateRef, isValid, isValidNumber, measureHeightByIndics, normalize, scrollToElement, setClipboardData, setDataTransferClipboard, setDataTransferClipboardText, setMinHeightByElement, setNavigatorClipboard, shallowCompare, stripHtml, withAngular };
5377
5414
  //# sourceMappingURL=slate-angular.mjs.map