slate-angular 20.2.0-next.2 → 20.2.0-next.21

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.
@@ -353,6 +353,18 @@ const CustomDOMEditor = {
353
353
  }
354
354
  };
355
355
 
356
+ /**
357
+ * Symbols.
358
+ */
359
+ const PLACEHOLDER_SYMBOL = Symbol('placeholder');
360
+ /**
361
+ * Weak map for associating the html element with the component.
362
+ */
363
+ const ELEMENT_TO_COMPONENT = new WeakMap();
364
+ const IS_ENABLED_VIRTUAL_SCROLL = new WeakMap();
365
+ const EDITOR_TO_VIRTUAL_SCROLL_SELECTION = new WeakMap();
366
+ const EDITOR_TO_AFTER_VIEW_INIT_QUEUE = new WeakMap();
367
+
356
368
  const AngularEditor = {
357
369
  ...CustomDOMEditor,
358
370
  /**
@@ -424,19 +436,12 @@ const AngularEditor = {
424
436
  // FocusedContext is updated to the correct value
425
437
  el.focus({ preventScroll: true });
426
438
  }
439
+ },
440
+ isEnabledVirtualScroll(editor) {
441
+ return IS_ENABLED_VIRTUAL_SCROLL.get(editor);
427
442
  }
428
443
  };
429
444
 
430
- /**
431
- * Symbols.
432
- */
433
- const PLACEHOLDER_SYMBOL = Symbol('placeholder');
434
- /**
435
- * Weak map for associating the html element with the component.
436
- */
437
- const ELEMENT_TO_COMPONENT = new WeakMap();
438
- const EDITOR_TO_AFTER_VIEW_INIT_QUEUE = new WeakMap();
439
-
440
445
  const IS_IOS = typeof navigator !== 'undefined' &&
441
446
  typeof window !== 'undefined' &&
442
447
  /iPad|iPhone|iPod/.test(navigator.userAgent) &&
@@ -470,9 +475,9 @@ const HAS_BEFORE_INPUT_SUPPORT = !IS_CHROME_LEGACY &&
470
475
  globalThis.InputEvent &&
471
476
  // @ts-ignore The `getTargetRanges` property isn't recognized.
472
477
  typeof globalThis.InputEvent.prototype.getTargetRanges === 'function';
473
- const VIRTUAL_SCROLL_DEFAULT_BUFFER_COUNT = 3;
474
- const VIRTUAL_SCROLL_DEFAULT_BLOCK_HEIGHT = 40;
478
+ const VIRTUAL_SCROLL_DEFAULT_BLOCK_HEIGHT = 30;
475
479
  const SLATE_DEBUG_KEY = '__SLATE_DEBUG__';
480
+ const SLATE_DEBUG_KEY_SCROLL_TOP = '__SLATE_DEBUG_SCROLL_TOP__';
476
481
 
477
482
  /**
478
483
  * Hotkey mappings for each platform.
@@ -950,6 +955,55 @@ const fallbackCopyText = async (text) => {
950
955
  });
951
956
  };
952
957
 
958
+ const ELEMENT_KEY_TO_HEIGHTS = new WeakMap();
959
+ const EDITOR_TO_BUSINESS_TOP = new WeakMap();
960
+ const getBusinessTop = (editor) => {
961
+ return EDITOR_TO_BUSINESS_TOP.get(editor) ?? 0;
962
+ };
963
+ const getRealHeightByElement = (editor, element, defaultHeight = VIRTUAL_SCROLL_DEFAULT_BLOCK_HEIGHT) => {
964
+ const isVisible = editor.isVisible(element);
965
+ if (!isVisible) {
966
+ return 0;
967
+ }
968
+ if (!element) {
969
+ return defaultHeight;
970
+ }
971
+ const heights = ELEMENT_KEY_TO_HEIGHTS.get(editor);
972
+ const key = AngularEditor.findKey(editor, element);
973
+ const height = heights?.get(key.id);
974
+ if (typeof height === 'number') {
975
+ return height;
976
+ }
977
+ if (heights?.has(key.id)) {
978
+ console.error('getBlockHeight: invalid height value', key.id, height);
979
+ }
980
+ return defaultHeight;
981
+ };
982
+ const buildHeightsAndAccumulatedHeights = (editor) => {
983
+ const children = (editor.children || []);
984
+ const heights = new Array(children.length);
985
+ const accumulatedHeights = new Array(children.length + 1);
986
+ accumulatedHeights[0] = 0;
987
+ for (let i = 0; i < children.length; i++) {
988
+ const height = getRealHeightByElement(editor, children[i]);
989
+ heights[i] = height;
990
+ accumulatedHeights[i + 1] = accumulatedHeights[i] + height;
991
+ }
992
+ return { heights, accumulatedHeights };
993
+ };
994
+ const scrollToElement = (editor, element, scrollTo) => {
995
+ const children = editor.children;
996
+ if (!children.length) {
997
+ return;
998
+ }
999
+ const anchorIndex = children.findIndex(item => item === element);
1000
+ if (anchorIndex < 0) {
1001
+ return;
1002
+ }
1003
+ const { accumulatedHeights } = buildHeightsAndAccumulatedHeights(editor);
1004
+ scrollTo((accumulatedHeights[anchorIndex] ?? 0) + getBusinessTop(editor));
1005
+ };
1006
+
953
1007
  const withAngular = (editor, clipboardFormatKey = 'x-slate-fragment') => {
954
1008
  let e = editor;
955
1009
  let { apply } = e;
@@ -967,7 +1021,14 @@ const withAngular = (editor, clipboardFormatKey = 'x-slate-fragment') => {
967
1021
  }
968
1022
  // Create a fake selection so that we can add a Base64-encoded copy of the
969
1023
  // fragment to the HTML, to decode on future pastes.
970
- const domRange = AngularEditor.toDOMRange(e, selection);
1024
+ let domRange;
1025
+ if (AngularEditor.isEnabledVirtualScroll(e)) {
1026
+ const virtualScrollSelection = EDITOR_TO_VIRTUAL_SCROLL_SELECTION.get(e);
1027
+ if (virtualScrollSelection) {
1028
+ domRange = AngularEditor.toDOMRange(e, virtualScrollSelection);
1029
+ }
1030
+ }
1031
+ domRange = domRange ?? AngularEditor.toDOMRange(e, selection);
971
1032
  let contents = domRange.cloneContents();
972
1033
  let attach = contents.childNodes[0];
973
1034
  // Make sure attach is non-empty, since empty nodes will not get copied.
@@ -1135,6 +1196,12 @@ const withAngular = (editor, clipboardFormatKey = 'x-slate-fragment') => {
1135
1196
  NODE_TO_KEY.set(node, key);
1136
1197
  }
1137
1198
  };
1199
+ e.selectAll = () => {
1200
+ Transforms.select(e, []);
1201
+ };
1202
+ e.isVisible = element => {
1203
+ return true;
1204
+ };
1138
1205
  return e;
1139
1206
  };
1140
1207
 
@@ -1739,6 +1806,7 @@ class BaseElementFlavour extends BaseFlavour {
1739
1806
  this.getOutletElement = () => {
1740
1807
  return this.nativeElement.querySelector('.children-outlet');
1741
1808
  };
1809
+ this.stableHeight = null;
1742
1810
  }
1743
1811
  get element() {
1744
1812
  return this._context && this._context.element;
@@ -1794,6 +1862,7 @@ class BaseElementFlavour extends BaseFlavour {
1794
1862
  if (ELEMENT_TO_COMPONENT.get(this.element) === this) {
1795
1863
  ELEMENT_TO_COMPONENT.delete(this.element);
1796
1864
  }
1865
+ this.listRender.destroy();
1797
1866
  this.nativeElement?.remove();
1798
1867
  }
1799
1868
  onContextChange() {
@@ -1824,11 +1893,21 @@ class BaseElementFlavour extends BaseFlavour {
1824
1893
  readonly: this._context.readonly
1825
1894
  };
1826
1895
  }
1896
+ isStableHeight() {
1897
+ return false;
1898
+ }
1827
1899
  getRealHeight() {
1900
+ if (this.isStableHeight() && this.stableHeight !== null) {
1901
+ return this.stableHeight;
1902
+ }
1828
1903
  const blockCard = getBlockCardByNativeElement(this.nativeElement);
1829
1904
  const target = blockCard || this.nativeElement;
1830
1905
  const computedStyle = getComputedStyle(target);
1831
- return Promise.resolve(target.offsetHeight + parseFloat(computedStyle.marginTop) + parseFloat(computedStyle.marginBottom));
1906
+ const height = Math.ceil(target.getBoundingClientRect().height) + parseFloat(computedStyle.marginTop) + parseFloat(computedStyle.marginBottom);
1907
+ if (this.isStableHeight()) {
1908
+ this.stableHeight = height;
1909
+ }
1910
+ return height;
1832
1911
  }
1833
1912
  }
1834
1913
 
@@ -2180,6 +2259,9 @@ class LeavesRender {
2180
2259
  });
2181
2260
  return { decoratedLeaves, contexts };
2182
2261
  }
2262
+ destroy() {
2263
+ this.views.forEach(view => view.destroy());
2264
+ }
2183
2265
  }
2184
2266
  function getContext$1(index, leafContexts) {
2185
2267
  return leafContexts[index];
@@ -2222,6 +2304,7 @@ class BaseTextFlavour extends BaseFlavour {
2222
2304
  NODE_TO_ELEMENT.delete(this.text);
2223
2305
  }
2224
2306
  ELEMENT_TO_NODE.delete(this.nativeElement);
2307
+ this.leavesRender.destroy();
2225
2308
  this.nativeElement?.remove();
2226
2309
  }
2227
2310
  onContextChange() {
@@ -2262,6 +2345,7 @@ class ListRender {
2262
2345
  this.viewContainerRef = viewContainerRef;
2263
2346
  this.getOutletParent = getOutletParent;
2264
2347
  this.getOutletElement = getOutletElement;
2348
+ this.children = [];
2265
2349
  this.views = [];
2266
2350
  this.blockCards = [];
2267
2351
  this.contexts = [];
@@ -2411,6 +2495,7 @@ class ListRender {
2411
2495
  this.blockCards[index].destroy();
2412
2496
  }
2413
2497
  });
2498
+ this.children = [];
2414
2499
  this.views = [];
2415
2500
  this.blockCards = [];
2416
2501
  this.contexts = [];
@@ -2553,39 +2638,517 @@ function executeAfterViewInit(editor) {
2553
2638
  clearAfterViewInitQueue(editor);
2554
2639
  }
2555
2640
 
2556
- const JUST_NOW_UPDATED_VIRTUAL_VIEW = new WeakMap();
2641
+ class VirtualScrollDebugOverlay {
2642
+ static { this.storageKey = 'slate_virtual_scroll_debug_overlay_state'; }
2643
+ static { this.minWidth = 320; }
2644
+ static { this.minHeight = 240; }
2645
+ static { this.defaultWidth = 410; }
2646
+ static { this.defaultHeight = 480; }
2647
+ static getInstance(doc) {
2648
+ if (!this.instance) {
2649
+ this.instance = new VirtualScrollDebugOverlay(doc);
2650
+ }
2651
+ this.instance.init();
2652
+ return this.instance;
2653
+ }
2654
+ static log(doc, type, ...args) {
2655
+ this.getInstance(doc).log(type, ...args);
2656
+ }
2657
+ static syncScrollTop(doc, value) {
2658
+ const instance = this.getInstance(doc);
2659
+ instance.setScrollTopValue(value);
2660
+ }
2661
+ constructor(doc) {
2662
+ this.doc = doc;
2663
+ this.state = {
2664
+ left: 16,
2665
+ top: 16,
2666
+ collapsed: false,
2667
+ width: VirtualScrollDebugOverlay.defaultWidth,
2668
+ height: VirtualScrollDebugOverlay.defaultHeight
2669
+ };
2670
+ this.originalConsoleLog = console.log.bind(console);
2671
+ this.originalConsoleWarn = console.warn.bind(console);
2672
+ this.dragOffsetX = 0;
2673
+ this.dragOffsetY = 0;
2674
+ this.isDragging = false;
2675
+ this.isResizing = false;
2676
+ this.resizeStartX = 0;
2677
+ this.resizeStartY = 0;
2678
+ this.resizeStartWidth = 0;
2679
+ this.resizeStartHeight = 0;
2680
+ this.dragMoved = false;
2681
+ this.wasDragged = false;
2682
+ this.onDragging = (event) => {
2683
+ if (!this.isDragging || !this.container) {
2684
+ return;
2685
+ }
2686
+ this.dragMoved = true;
2687
+ const nextLeft = event.clientX - this.dragOffsetX;
2688
+ const nextTop = event.clientY - this.dragOffsetY;
2689
+ this.container.style.left = `${nextLeft}px`;
2690
+ this.container.style.top = `${nextTop}px`;
2691
+ this.container.style.right = 'auto';
2692
+ this.container.style.bottom = 'auto';
2693
+ };
2694
+ this.onDragEnd = () => {
2695
+ if (!this.isDragging) {
2696
+ return;
2697
+ }
2698
+ this.isDragging = false;
2699
+ this.wasDragged = this.dragMoved;
2700
+ this.dragMoved = false;
2701
+ this.doc.removeEventListener('mousemove', this.onDragging);
2702
+ this.doc.removeEventListener('mouseup', this.onDragEnd);
2703
+ if (this.container) {
2704
+ const rect = this.container.getBoundingClientRect();
2705
+ this.state.left = rect.left;
2706
+ this.state.top = rect.top;
2707
+ this.persistState();
2708
+ this.container.style.transition = '';
2709
+ }
2710
+ };
2711
+ this.onResizing = (event) => {
2712
+ if (!this.isResizing || !this.container) {
2713
+ return;
2714
+ }
2715
+ const deltaX = event.clientX - this.resizeStartX;
2716
+ const deltaY = event.clientY - this.resizeStartY;
2717
+ const nextWidth = Math.max(VirtualScrollDebugOverlay.minWidth, this.resizeStartWidth + deltaX);
2718
+ const nextHeight = Math.max(VirtualScrollDebugOverlay.minHeight, this.resizeStartHeight + deltaY);
2719
+ this.state.width = nextWidth;
2720
+ this.state.height = nextHeight;
2721
+ this.applySize();
2722
+ };
2723
+ this.onResizeEnd = () => {
2724
+ if (!this.isResizing) {
2725
+ return;
2726
+ }
2727
+ this.isResizing = false;
2728
+ this.doc.removeEventListener('mousemove', this.onResizing);
2729
+ this.doc.removeEventListener('mouseup', this.onResizeEnd);
2730
+ this.persistState();
2731
+ };
2732
+ }
2733
+ init() {
2734
+ if (!this.container) {
2735
+ this.createContainer();
2736
+ }
2737
+ else {
2738
+ this.applyState();
2739
+ }
2740
+ }
2741
+ log(type, ...args) {
2742
+ this.init();
2743
+ if (type === 'warn') {
2744
+ this.originalConsoleWarn(...args);
2745
+ }
2746
+ else {
2747
+ this.originalConsoleLog(...args);
2748
+ }
2749
+ this.appendLog(type, ...args);
2750
+ }
2751
+ dispose() {
2752
+ this.container?.remove();
2753
+ this.container = undefined;
2754
+ this.contentWrapper = undefined;
2755
+ this.bubble = undefined;
2756
+ this.logList = undefined;
2757
+ this.selectorInput = undefined;
2758
+ this.distanceInput = undefined;
2759
+ this.collapseToggle = undefined;
2760
+ this.resizeHandle = undefined;
2761
+ this.doc.removeEventListener('mousemove', this.onDragging);
2762
+ this.doc.removeEventListener('mouseup', this.onDragEnd);
2763
+ this.doc.removeEventListener('mousemove', this.onResizing);
2764
+ this.doc.removeEventListener('mouseup', this.onResizeEnd);
2765
+ this.isDragging = false;
2766
+ this.isResizing = false;
2767
+ }
2768
+ createContainer() {
2769
+ this.loadState();
2770
+ const doc = this.doc;
2771
+ const container = doc.createElement('div');
2772
+ container.style.position = 'fixed';
2773
+ container.style.right = 'auto';
2774
+ container.style.bottom = 'auto';
2775
+ container.style.boxSizing = 'border-box';
2776
+ container.style.background = 'rgba(17, 24, 39, 0.95)';
2777
+ container.style.color = '#e5e7eb';
2778
+ container.style.fontSize = '12px';
2779
+ container.style.border = '1px solid #1f2937';
2780
+ container.style.borderRadius = '10px';
2781
+ container.style.fontFamily = 'Menlo, Consolas, monospace';
2782
+ container.style.boxShadow = '0 10px 30px rgba(0, 0, 0, 0.35)';
2783
+ container.style.zIndex = '9999';
2784
+ container.style.display = 'flex';
2785
+ container.style.flexDirection = 'column';
2786
+ container.style.gap = '10px';
2787
+ container.style.minWidth = `${VirtualScrollDebugOverlay.minWidth}px`;
2788
+ container.style.minHeight = `${VirtualScrollDebugOverlay.minHeight}px`;
2789
+ container.style.maxHeight = '80vh';
2790
+ container.style.cursor = 'default';
2791
+ container.addEventListener('mousedown', event => {
2792
+ if (this.state.collapsed) {
2793
+ this.startDrag(event);
2794
+ }
2795
+ });
2796
+ const header = doc.createElement('div');
2797
+ header.style.display = 'flex';
2798
+ header.style.alignItems = 'center';
2799
+ header.style.justifyContent = 'space-between';
2800
+ header.style.cursor = 'move';
2801
+ header.addEventListener('mousedown', event => {
2802
+ this.startDrag(event);
2803
+ });
2804
+ const title = doc.createElement('div');
2805
+ title.textContent = 'Virtual Scroll Debug';
2806
+ title.style.fontWeight = '600';
2807
+ title.style.letterSpacing = '0.3px';
2808
+ const actions = doc.createElement('div');
2809
+ actions.style.display = 'flex';
2810
+ actions.style.gap = '6px';
2811
+ const collapseButton = doc.createElement('button');
2812
+ collapseButton.type = 'button';
2813
+ collapseButton.textContent = '折叠';
2814
+ collapseButton.style.background = '#1f2937';
2815
+ collapseButton.style.color = '#e5e7eb';
2816
+ collapseButton.style.border = '1px solid #374151';
2817
+ collapseButton.style.borderRadius = '6px';
2818
+ collapseButton.style.padding = '4px 8px';
2819
+ collapseButton.style.cursor = 'pointer';
2820
+ collapseButton.addEventListener('click', () => {
2821
+ this.setCollapsed(!this.state.collapsed);
2822
+ });
2823
+ const clearButton = doc.createElement('button');
2824
+ clearButton.type = 'button';
2825
+ clearButton.textContent = '清除日志';
2826
+ clearButton.style.background = '#374151';
2827
+ clearButton.style.color = '#e5e7eb';
2828
+ clearButton.style.border = '1px solid #4b5563';
2829
+ clearButton.style.borderRadius = '6px';
2830
+ clearButton.style.padding = '4px 10px';
2831
+ clearButton.style.cursor = 'pointer';
2832
+ clearButton.addEventListener('click', () => {
2833
+ if (this.logList) {
2834
+ this.logList.innerHTML = '';
2835
+ }
2836
+ });
2837
+ actions.appendChild(collapseButton);
2838
+ actions.appendChild(clearButton);
2839
+ header.appendChild(title);
2840
+ header.appendChild(actions);
2841
+ const scrollForm = doc.createElement('div');
2842
+ scrollForm.style.display = 'grid';
2843
+ scrollForm.style.gridTemplateColumns = '1fr 110px 50px';
2844
+ scrollForm.style.gap = '6px';
2845
+ scrollForm.style.alignItems = 'center';
2846
+ const selectorInput = doc.createElement('input');
2847
+ selectorInput.placeholder = '滚动容器 selector';
2848
+ selectorInput.style.padding = '6px 8px';
2849
+ selectorInput.style.borderRadius = '6px';
2850
+ selectorInput.style.border = '1px solid #4b5563';
2851
+ selectorInput.style.background = '#111827';
2852
+ selectorInput.style.color = '#e5e7eb';
2853
+ selectorInput.autocomplete = 'off';
2854
+ const distanceInput = doc.createElement('input');
2855
+ distanceInput.placeholder = '滚动距离(px)';
2856
+ distanceInput.type = 'number';
2857
+ distanceInput.style.padding = '6px 8px';
2858
+ distanceInput.style.borderRadius = '6px';
2859
+ distanceInput.style.border = '1px solid #4b5563';
2860
+ distanceInput.style.background = '#111827';
2861
+ distanceInput.style.color = '#e5e7eb';
2862
+ const scrollButton = doc.createElement('button');
2863
+ scrollButton.type = 'button';
2864
+ scrollButton.textContent = '滚动';
2865
+ scrollButton.style.background = '#10b981';
2866
+ scrollButton.style.color = '#0b1c15';
2867
+ scrollButton.style.border = 'none';
2868
+ scrollButton.style.borderRadius = '6px';
2869
+ scrollButton.style.padding = '6px 10px';
2870
+ scrollButton.style.cursor = 'pointer';
2871
+ scrollButton.addEventListener('click', () => {
2872
+ const selector = selectorInput.value.trim();
2873
+ const distanceValue = Number(distanceInput.value ?? 0);
2874
+ const distance = Number.isFinite(distanceValue) ? distanceValue : 0;
2875
+ if (!selector) {
2876
+ this.log('warn', '请先填写滚动容器 selector');
2877
+ return;
2878
+ }
2879
+ const target = doc.querySelector(selector);
2880
+ if (!target) {
2881
+ this.log('warn', `未找到滚动容器: ${selector}`);
2882
+ return;
2883
+ }
2884
+ if (typeof target.scrollTo === 'function') {
2885
+ target.scrollTo({ top: distance, behavior: 'auto' });
2886
+ }
2887
+ else if (Object.prototype.hasOwnProperty.call(target, 'scrollTop')) {
2888
+ target.scrollTop = distance;
2889
+ }
2890
+ else {
2891
+ this.log('warn', '目标元素不支持滚动:', selector);
2892
+ return;
2893
+ }
2894
+ this.log('log', `已将 ${selector} 滚动到`, distance);
2895
+ });
2896
+ scrollForm.appendChild(selectorInput);
2897
+ scrollForm.appendChild(distanceInput);
2898
+ scrollForm.appendChild(scrollButton);
2899
+ const logList = doc.createElement('div');
2900
+ logList.style.height = '260px';
2901
+ logList.style.overflowY = 'auto';
2902
+ logList.style.background = '#0b1220';
2903
+ logList.style.border = '1px solid #1f2937';
2904
+ logList.style.borderRadius = '8px';
2905
+ logList.style.padding = '8px';
2906
+ logList.style.display = 'flex';
2907
+ logList.style.flexDirection = 'column';
2908
+ logList.style.gap = '6px';
2909
+ logList.style.flex = '1';
2910
+ logList.style.minHeight = '160px';
2911
+ const bubble = doc.createElement('div');
2912
+ bubble.textContent = 'VS';
2913
+ bubble.style.display = 'none';
2914
+ bubble.style.alignItems = 'center';
2915
+ bubble.style.justifyContent = 'center';
2916
+ bubble.style.fontWeight = '700';
2917
+ bubble.style.fontSize = '14px';
2918
+ bubble.style.letterSpacing = '0.5px';
2919
+ bubble.style.width = '100%';
2920
+ bubble.style.height = '100%';
2921
+ bubble.style.userSelect = 'none';
2922
+ bubble.addEventListener('click', () => {
2923
+ if (this.wasDragged) {
2924
+ this.wasDragged = false;
2925
+ return;
2926
+ }
2927
+ this.setCollapsed(false);
2928
+ });
2929
+ const contentWrapper = doc.createElement('div');
2930
+ contentWrapper.style.display = 'flex';
2931
+ contentWrapper.style.flexDirection = 'column';
2932
+ contentWrapper.style.gap = '10px';
2933
+ contentWrapper.style.width = '100%';
2934
+ contentWrapper.style.height = '100%';
2935
+ contentWrapper.appendChild(header);
2936
+ contentWrapper.appendChild(scrollForm);
2937
+ contentWrapper.appendChild(logList);
2938
+ container.appendChild(contentWrapper);
2939
+ container.appendChild(bubble);
2940
+ const resizeHandle = doc.createElement('div');
2941
+ resizeHandle.style.position = 'absolute';
2942
+ resizeHandle.style.right = '6px';
2943
+ resizeHandle.style.bottom = '6px';
2944
+ resizeHandle.style.width = '14px';
2945
+ resizeHandle.style.height = '14px';
2946
+ resizeHandle.style.cursor = 'nwse-resize';
2947
+ resizeHandle.style.borderRight = '2px solid #4b5563';
2948
+ resizeHandle.style.borderBottom = '2px solid #4b5563';
2949
+ resizeHandle.addEventListener('mousedown', event => {
2950
+ this.startResize(event);
2951
+ });
2952
+ container.appendChild(resizeHandle);
2953
+ doc.body.appendChild(container);
2954
+ this.container = container;
2955
+ this.contentWrapper = contentWrapper;
2956
+ this.bubble = bubble;
2957
+ this.logList = logList;
2958
+ this.selectorInput = selectorInput;
2959
+ this.distanceInput = distanceInput;
2960
+ this.collapseToggle = collapseButton;
2961
+ this.resizeHandle = resizeHandle;
2962
+ this.applyState();
2963
+ }
2964
+ startDrag(event) {
2965
+ if (event.button !== 0) {
2966
+ return;
2967
+ }
2968
+ if (!this.container) {
2969
+ return;
2970
+ }
2971
+ const rect = this.container.getBoundingClientRect();
2972
+ this.isDragging = true;
2973
+ this.wasDragged = false;
2974
+ this.dragMoved = false;
2975
+ this.dragOffsetX = event.clientX - rect.left;
2976
+ this.dragOffsetY = event.clientY - rect.top;
2977
+ this.container.style.transition = 'none';
2978
+ this.doc.addEventListener('mousemove', this.onDragging);
2979
+ this.doc.addEventListener('mouseup', this.onDragEnd);
2980
+ if (!this.state.collapsed) {
2981
+ event.preventDefault();
2982
+ }
2983
+ }
2984
+ startResize(event) {
2985
+ if (event.button !== 0 || this.state.collapsed) {
2986
+ return;
2987
+ }
2988
+ if (!this.container) {
2989
+ return;
2990
+ }
2991
+ const rect = this.container.getBoundingClientRect();
2992
+ this.isResizing = true;
2993
+ this.resizeStartX = event.clientX;
2994
+ this.resizeStartY = event.clientY;
2995
+ this.resizeStartWidth = rect.width;
2996
+ this.resizeStartHeight = rect.height;
2997
+ this.doc.addEventListener('mousemove', this.onResizing);
2998
+ this.doc.addEventListener('mouseup', this.onResizeEnd);
2999
+ event.preventDefault();
3000
+ event.stopPropagation();
3001
+ }
3002
+ applyPosition() {
3003
+ if (!this.container) {
3004
+ return;
3005
+ }
3006
+ this.container.style.left = `${this.state.left}px`;
3007
+ this.container.style.top = `${this.state.top}px`;
3008
+ }
3009
+ applySize() {
3010
+ if (!this.container) {
3011
+ return;
3012
+ }
3013
+ const width = Math.max(VirtualScrollDebugOverlay.minWidth, this.state.width || VirtualScrollDebugOverlay.defaultWidth);
3014
+ const height = Math.max(VirtualScrollDebugOverlay.minHeight, this.state.height || VirtualScrollDebugOverlay.defaultHeight);
3015
+ this.state.width = width;
3016
+ this.state.height = height;
3017
+ this.container.style.width = `${width}px`;
3018
+ this.container.style.height = `${height}px`;
3019
+ }
3020
+ applyCollapsedState() {
3021
+ if (!this.container || !this.contentWrapper || !this.bubble || !this.collapseToggle) {
3022
+ return;
3023
+ }
3024
+ if (this.state.collapsed) {
3025
+ this.container.style.width = '36px';
3026
+ this.container.style.height = '36px';
3027
+ this.container.style.minWidth = '';
3028
+ this.container.style.minHeight = '';
3029
+ this.container.style.padding = '0';
3030
+ this.container.style.borderRadius = '50%';
3031
+ this.container.style.display = 'flex';
3032
+ this.container.style.flexDirection = 'row';
3033
+ this.container.style.alignItems = 'center';
3034
+ this.container.style.justifyContent = 'center';
3035
+ this.container.style.cursor = 'move';
3036
+ this.contentWrapper.style.display = 'none';
3037
+ this.bubble.style.display = 'flex';
3038
+ this.collapseToggle.textContent = '展开';
3039
+ this.resizeHandle.style.display = 'none';
3040
+ }
3041
+ else {
3042
+ this.applySize();
3043
+ this.container.style.padding = '12px';
3044
+ this.container.style.borderRadius = '10px';
3045
+ this.container.style.display = 'flex';
3046
+ this.container.style.flexDirection = 'column';
3047
+ this.container.style.gap = '10px';
3048
+ this.container.style.cursor = 'default';
3049
+ this.contentWrapper.style.display = 'flex';
3050
+ this.bubble.style.display = 'none';
3051
+ this.collapseToggle.textContent = '折叠';
3052
+ this.resizeHandle.style.display = 'block';
3053
+ }
3054
+ }
3055
+ setCollapsed(collapsed) {
3056
+ this.state.collapsed = collapsed;
3057
+ this.applyCollapsedState();
3058
+ this.persistState();
3059
+ }
3060
+ applyState() {
3061
+ this.applyPosition();
3062
+ this.applyCollapsedState();
3063
+ }
3064
+ loadState() {
3065
+ try {
3066
+ const raw = this.doc.defaultView?.localStorage?.getItem(VirtualScrollDebugOverlay.storageKey);
3067
+ if (raw) {
3068
+ const parsed = JSON.parse(raw);
3069
+ if (typeof parsed.left === 'number') {
3070
+ this.state.left = parsed.left;
3071
+ }
3072
+ if (typeof parsed.top === 'number') {
3073
+ this.state.top = parsed.top;
3074
+ }
3075
+ if (typeof parsed.collapsed === 'boolean') {
3076
+ this.state.collapsed = parsed.collapsed;
3077
+ }
3078
+ if (typeof parsed.width === 'number') {
3079
+ this.state.width = parsed.width;
3080
+ }
3081
+ if (typeof parsed.height === 'number') {
3082
+ this.state.height = parsed.height;
3083
+ }
3084
+ }
3085
+ }
3086
+ catch {
3087
+ // ignore storage errors
3088
+ }
3089
+ }
3090
+ persistState() {
3091
+ try {
3092
+ this.doc.defaultView?.localStorage?.setItem(VirtualScrollDebugOverlay.storageKey, JSON.stringify(this.state));
3093
+ }
3094
+ catch {
3095
+ // ignore storage errors
3096
+ }
3097
+ }
3098
+ appendLog(type, ...args) {
3099
+ if (!this.logList) {
3100
+ return;
3101
+ }
3102
+ const item = this.doc.createElement('div');
3103
+ item.style.display = 'flex';
3104
+ item.style.gap = '6px';
3105
+ item.style.alignItems = 'flex-start';
3106
+ item.style.wordBreak = 'break-all';
3107
+ item.style.color = type === 'warn' ? '#fbbf24' : '#9ca3af';
3108
+ const time = this.doc.createElement('span');
3109
+ time.textContent = new Date().toLocaleTimeString();
3110
+ time.style.color = '#6b7280';
3111
+ time.style.flexShrink = '0';
3112
+ time.style.width = '72px';
3113
+ const text = this.doc.createElement('span');
3114
+ text.textContent = `[${type}] ${args.map(arg => this.formatValue(arg)).join(' ')}`;
3115
+ item.appendChild(time);
3116
+ item.appendChild(text);
3117
+ this.logList.appendChild(item);
3118
+ this.logList.scrollTop = this.logList.scrollHeight;
3119
+ }
3120
+ formatValue(value) {
3121
+ if (typeof value === 'string') {
3122
+ return value;
3123
+ }
3124
+ try {
3125
+ return JSON.stringify(value);
3126
+ }
3127
+ catch (error) {
3128
+ return String(value);
3129
+ }
3130
+ }
3131
+ setScrollTopValue(value) {
3132
+ if (this.distanceInput) {
3133
+ this.distanceInput.value = String(value ?? 0);
3134
+ }
3135
+ }
3136
+ }
3137
+
2557
3138
  // not correctly clipboardData on beforeinput
2558
3139
  const forceOnDOMPaste = IS_SAFARI;
2559
3140
  const isDebug = localStorage.getItem(SLATE_DEBUG_KEY) === 'true';
3141
+ const isDebugScrollTop = localStorage.getItem(SLATE_DEBUG_KEY_SCROLL_TOP) === 'true';
2560
3142
  class SlateEditable {
2561
3143
  set virtualScroll(config) {
2562
- this.virtualConfig = config;
2563
- this.refreshVirtualViewAnimId && cancelAnimationFrame(this.refreshVirtualViewAnimId);
2564
- this.refreshVirtualViewAnimId = requestAnimationFrame(() => {
2565
- const virtualView = this.refreshVirtualView();
2566
- const diff = this.diffVirtualView(virtualView);
2567
- if (diff.isDiff) {
2568
- if (diff.isMissingTop || diff.isMissingBottom) {
2569
- this.measureHeightByIndexes([...diff.diffTopRenderedIndexes, ...diff.diffBottomRenderedIndexes], true).then(result => {
2570
- if (isDebug) {
2571
- console.log('async measureHeightByIndexes:', result);
2572
- }
2573
- this.applyVirtualView(result || virtualView);
2574
- if (this.listRender.initialized) {
2575
- this.listRender.update(this.renderedChildren, this.editor, this.context);
2576
- }
2577
- this.scheduleMeasureVisibleHeights();
2578
- });
2579
- }
2580
- else {
2581
- this.applyVirtualView(virtualView);
2582
- if (this.listRender.initialized) {
2583
- this.listRender.update(virtualView.renderedChildren, this.editor, this.context);
2584
- }
2585
- this.scheduleMeasureVisibleHeights();
2586
- }
2587
- }
2588
- });
3144
+ this.virtualScrollConfig = config;
3145
+ if (isDebugScrollTop) {
3146
+ this.debugLog('log', 'virtualScrollConfig scrollTop:', config.scrollTop);
3147
+ }
3148
+ IS_ENABLED_VIRTUAL_SCROLL.set(this.editor, config.enabled);
3149
+ if (this.isEnabledVirtualScroll()) {
3150
+ this.tryUpdateVirtualViewport();
3151
+ }
2589
3152
  }
2590
3153
  get hasBeforeInputSupport() {
2591
3154
  return HAS_BEFORE_INPUT_SUPPORT;
@@ -2630,15 +3193,15 @@ class SlateEditable {
2630
3193
  return null;
2631
3194
  }
2632
3195
  };
2633
- this.virtualConfig = {
3196
+ this.virtualScrollConfig = {
2634
3197
  enabled: false,
2635
3198
  scrollTop: 0,
2636
- viewportHeight: 0
3199
+ viewportHeight: 0,
3200
+ viewportBoundingTop: 0
2637
3201
  };
2638
- this.renderedChildren = [];
2639
- this.virtualVisibleIndexes = new Set();
2640
- this.measuredHeights = new Map();
2641
- this.measurePending = false;
3202
+ this.inViewportChildren = [];
3203
+ this.inViewportIndics = new Set();
3204
+ this.keyHeightMap = new Map();
2642
3205
  this.virtualScrollInitialized = false;
2643
3206
  }
2644
3207
  ngOnInit() {
@@ -2650,6 +3213,7 @@ class SlateEditable {
2650
3213
  NODE_TO_ELEMENT.set(this.editor, this.elementRef.nativeElement);
2651
3214
  ELEMENT_TO_NODE.set(this.elementRef.nativeElement, this.editor);
2652
3215
  IS_READ_ONLY.set(this.editor, this.readonly);
3216
+ ELEMENT_KEY_TO_HEIGHTS.set(this.editor, this.keyHeightMap);
2653
3217
  EDITOR_TO_ON_CHANGE.set(this.editor, () => {
2654
3218
  this.ngZone.run(() => {
2655
3219
  this.onChange();
@@ -2663,7 +3227,7 @@ class SlateEditable {
2663
3227
  // add browser class
2664
3228
  let browserClass = IS_FIREFOX ? 'firefox' : IS_SAFARI ? 'safari' : '';
2665
3229
  browserClass && this.elementRef.nativeElement.classList.add(browserClass);
2666
- this.initializeVirtualScrolling();
3230
+ this.initializeVirtualScroll();
2667
3231
  this.listRender = new ListRender(this.viewContext, this.viewContainerRef, this.getOutletParent, this.getOutletElement);
2668
3232
  }
2669
3233
  ngOnChanges(simpleChanges) {
@@ -2695,16 +3259,26 @@ class SlateEditable {
2695
3259
  if (value && value.length) {
2696
3260
  this.editor.children = value;
2697
3261
  this.initializeContext();
2698
- const virtualView = this.refreshVirtualView();
2699
- this.applyVirtualView(virtualView);
2700
- const childrenForRender = virtualView.renderedChildren;
2701
- if (!this.listRender.initialized) {
2702
- this.listRender.initialize(childrenForRender, this.editor, this.context);
3262
+ if (this.isEnabledVirtualScroll()) {
3263
+ const virtualView = this.calculateVirtualViewport();
3264
+ this.applyVirtualView(virtualView);
3265
+ const childrenForRender = virtualView.inViewportChildren;
3266
+ if (!this.listRender.initialized) {
3267
+ this.listRender.initialize(childrenForRender, this.editor, this.context);
3268
+ }
3269
+ else {
3270
+ this.listRender.update(childrenForRender, this.editor, this.context);
3271
+ }
3272
+ this.tryMeasureInViewportChildrenHeights();
2703
3273
  }
2704
3274
  else {
2705
- this.listRender.update(childrenForRender, this.editor, this.context);
3275
+ if (!this.listRender.initialized) {
3276
+ this.listRender.initialize(this.editor.children, this.editor, this.context);
3277
+ }
3278
+ else {
3279
+ this.listRender.update(this.editor.children, this.editor, this.context);
3280
+ }
2706
3281
  }
2707
- this.scheduleMeasureVisibleHeights();
2708
3282
  this.cdr.markForCheck();
2709
3283
  }
2710
3284
  }
@@ -2735,9 +3309,36 @@ class SlateEditable {
2735
3309
  this.addEventListener(event.name, () => { });
2736
3310
  });
2737
3311
  }
3312
+ calculateVirtualScrollSelection(selection) {
3313
+ if (selection) {
3314
+ const indics = Array.from(this.inViewportIndics.values());
3315
+ if (indics.length > 0) {
3316
+ const currentVisibleRange = {
3317
+ anchor: Editor.start(this.editor, [indics[0]]),
3318
+ focus: Editor.end(this.editor, [indics[indics.length - 1]])
3319
+ };
3320
+ const [start, end] = Range.edges(selection);
3321
+ const forwardSelection = { anchor: start, focus: end };
3322
+ const intersectedSelection = Range.intersection(forwardSelection, currentVisibleRange);
3323
+ EDITOR_TO_VIRTUAL_SCROLL_SELECTION.set(this.editor, intersectedSelection);
3324
+ if (!intersectedSelection || !Range.equals(intersectedSelection, forwardSelection)) {
3325
+ if (isDebug) {
3326
+ this.debugLog('log', `selection is not in visible range, selection: ${JSON.stringify(selection)}, intersectedSelection: ${JSON.stringify(intersectedSelection)}`);
3327
+ }
3328
+ return intersectedSelection;
3329
+ }
3330
+ return selection;
3331
+ }
3332
+ }
3333
+ EDITOR_TO_VIRTUAL_SCROLL_SELECTION.set(this.editor, null);
3334
+ return selection;
3335
+ }
2738
3336
  toNativeSelection() {
2739
3337
  try {
2740
- const { selection } = this.editor;
3338
+ let { selection } = this.editor;
3339
+ if (this.isEnabledVirtualScroll()) {
3340
+ selection = this.calculateVirtualScrollSelection(selection);
3341
+ }
2741
3342
  const root = AngularEditor.findDocumentOrShadowRoot(this.editor);
2742
3343
  const { activeElement } = root;
2743
3344
  const domSelection = root.getSelection();
@@ -2825,10 +3426,12 @@ class SlateEditable {
2825
3426
  ngDoCheck() { }
2826
3427
  forceRender() {
2827
3428
  this.updateContext();
2828
- const virtualView = this.refreshVirtualView();
2829
- this.applyVirtualView(virtualView);
2830
- this.listRender.update(virtualView.renderedChildren, this.editor, this.context);
2831
- this.scheduleMeasureVisibleHeights();
3429
+ if (this.isEnabledVirtualScroll()) {
3430
+ this.updateListRenderAndRemeasureHeights();
3431
+ }
3432
+ else {
3433
+ this.listRender.update(this.editor.children, this.editor, this.context);
3434
+ }
2832
3435
  // repair collaborative editing when Chinese input is interrupted by other users' cursors
2833
3436
  // when the DOMElement where the selection is located is removed
2834
3437
  // the compositionupdate and compositionend events will no longer be fired
@@ -2867,12 +3470,32 @@ class SlateEditable {
2867
3470
  render() {
2868
3471
  const changed = this.updateContext();
2869
3472
  if (changed) {
2870
- const virtualView = this.refreshVirtualView();
2871
- this.applyVirtualView(virtualView);
2872
- this.listRender.update(virtualView.renderedChildren, this.editor, this.context);
2873
- this.scheduleMeasureVisibleHeights();
3473
+ if (this.isEnabledVirtualScroll()) {
3474
+ this.updateListRenderAndRemeasureHeights();
3475
+ }
3476
+ else {
3477
+ this.listRender.update(this.editor.children, this.editor, this.context);
3478
+ }
2874
3479
  }
2875
3480
  }
3481
+ updateListRenderAndRemeasureHeights() {
3482
+ const virtualView = this.calculateVirtualViewport();
3483
+ const oldInViewportChildren = this.inViewportChildren;
3484
+ this.applyVirtualView(virtualView);
3485
+ this.listRender.update(this.inViewportChildren, this.editor, this.context);
3486
+ // 新增或者修改的才需要重算,计算出这个结果
3487
+ const remeasureIndics = [];
3488
+ const newInViewportIndics = Array.from(this.inViewportIndics);
3489
+ this.inViewportChildren.forEach((child, index) => {
3490
+ if (oldInViewportChildren.indexOf(child) === -1) {
3491
+ remeasureIndics.push(newInViewportIndics[index]);
3492
+ }
3493
+ });
3494
+ if (isDebug && remeasureIndics.length > 0) {
3495
+ console.log('remeasure height by indics: ', remeasureIndics);
3496
+ }
3497
+ this.remeasureHeightByIndics(remeasureIndics);
3498
+ }
2876
3499
  updateContext() {
2877
3500
  const decorations = this.generateDecorations();
2878
3501
  if (this.context.selection !== this.editor.selection ||
@@ -2933,105 +3556,197 @@ class SlateEditable {
2933
3556
  decorations.push(...placeholderDecorations);
2934
3557
  return decorations;
2935
3558
  }
2936
- shouldUseVirtual() {
2937
- return !!(this.virtualConfig && this.virtualConfig.enabled);
3559
+ isEnabledVirtualScroll() {
3560
+ return !!(this.virtualScrollConfig && this.virtualScrollConfig.enabled);
2938
3561
  }
2939
- initializeVirtualScrolling() {
3562
+ initializeVirtualScroll() {
2940
3563
  if (this.virtualScrollInitialized) {
2941
3564
  return;
2942
3565
  }
2943
- if (this.virtualConfig && this.virtualConfig.enabled) {
3566
+ if (this.isEnabledVirtualScroll()) {
2944
3567
  this.virtualScrollInitialized = true;
2945
3568
  this.virtualTopHeightElement = document.createElement('div');
2946
3569
  this.virtualTopHeightElement.classList.add('virtual-top-height');
3570
+ this.virtualTopHeightElement.contentEditable = 'false';
2947
3571
  this.virtualBottomHeightElement = document.createElement('div');
2948
3572
  this.virtualBottomHeightElement.classList.add('virtual-bottom-height');
3573
+ this.virtualBottomHeightElement.contentEditable = 'false';
2949
3574
  this.virtualCenterOutlet = document.createElement('div');
2950
3575
  this.virtualCenterOutlet.classList.add('virtual-center-outlet');
2951
3576
  this.elementRef.nativeElement.appendChild(this.virtualTopHeightElement);
2952
3577
  this.elementRef.nativeElement.appendChild(this.virtualCenterOutlet);
2953
3578
  this.elementRef.nativeElement.appendChild(this.virtualBottomHeightElement);
3579
+ let editorResizeObserverRectWidth = this.elementRef.nativeElement.getBoundingClientRect()?.width ?? 0;
3580
+ this.editorResizeObserver = new ResizeObserver(entries => {
3581
+ if (entries.length > 0 && entries[0].contentRect.width !== editorResizeObserverRectWidth) {
3582
+ editorResizeObserverRectWidth = entries[0].contentRect.width;
3583
+ const remeasureIndics = Array.from(this.inViewportIndics);
3584
+ this.remeasureHeightByIndics(remeasureIndics);
3585
+ }
3586
+ });
3587
+ this.editorResizeObserver.observe(this.elementRef.nativeElement);
3588
+ if (isDebug) {
3589
+ const doc = this.elementRef?.nativeElement?.ownerDocument ?? document;
3590
+ VirtualScrollDebugOverlay.getInstance(doc);
3591
+ }
2954
3592
  }
2955
3593
  }
2956
- changeVirtualHeight(topHeight, bottomHeight) {
3594
+ setVirtualSpaceHeight(topHeight, bottomHeight) {
2957
3595
  if (!this.virtualScrollInitialized) {
2958
3596
  return;
2959
3597
  }
2960
3598
  this.virtualTopHeightElement.style.height = `${topHeight}px`;
2961
3599
  this.virtualBottomHeightElement.style.height = `${bottomHeight}px`;
2962
3600
  }
2963
- refreshVirtualView() {
3601
+ debugLog(type, ...args) {
3602
+ const doc = this.elementRef?.nativeElement?.ownerDocument ?? document;
3603
+ VirtualScrollDebugOverlay.log(doc, type, ...args);
3604
+ }
3605
+ tryUpdateVirtualViewport() {
3606
+ this.tryUpdateVirtualViewportAnimId && cancelAnimationFrame(this.tryUpdateVirtualViewportAnimId);
3607
+ this.tryUpdateVirtualViewportAnimId = requestAnimationFrame(() => {
3608
+ let virtualView = this.calculateVirtualViewport();
3609
+ let diff = this.diffVirtualViewport(virtualView);
3610
+ if (!diff.isDiff) {
3611
+ return;
3612
+ }
3613
+ // diff.isAddedTop
3614
+ if (diff.isMissingTop) {
3615
+ const remeasureIndics = diff.diffTopRenderedIndexes;
3616
+ const result = this.remeasureHeightByIndics(remeasureIndics);
3617
+ if (result) {
3618
+ virtualView = this.calculateVirtualViewport();
3619
+ diff = this.diffVirtualViewport(virtualView, 'second');
3620
+ if (!diff.isDiff) {
3621
+ return;
3622
+ }
3623
+ }
3624
+ }
3625
+ this.applyVirtualView(virtualView);
3626
+ if (this.listRender.initialized) {
3627
+ this.listRender.update(virtualView.inViewportChildren, this.editor, this.context);
3628
+ if (!AngularEditor.isReadOnly(this.editor) && this.editor.selection) {
3629
+ this.toNativeSelection();
3630
+ }
3631
+ }
3632
+ if (diff.isAddedTop) {
3633
+ const remeasureAddedIndics = diff.diffTopRenderedIndexes;
3634
+ if (isDebug) {
3635
+ this.debugLog('log', 'isAddedTop to remeasure heights: ', remeasureAddedIndics);
3636
+ }
3637
+ const startIndexBeforeAdd = diff.diffTopRenderedIndexes[diff.diffTopRenderedIndexes.length - 1] + 1;
3638
+ const topHeightBeforeAdd = virtualView.accumulatedHeights[startIndexBeforeAdd];
3639
+ const result = this.remeasureHeightByIndics(remeasureAddedIndics);
3640
+ if (result) {
3641
+ const newHeights = buildHeightsAndAccumulatedHeights(this.editor);
3642
+ const visibleStartIndex = diff.diffTopRenderedIndexes[0];
3643
+ const actualTopHeightAfterAdd = newHeights.accumulatedHeights[startIndexBeforeAdd];
3644
+ const adjustedTopHeight = (visibleStartIndex === -1 ? 0 : newHeights.accumulatedHeights[visibleStartIndex]) -
3645
+ (actualTopHeightAfterAdd - topHeightBeforeAdd);
3646
+ if (adjustedTopHeight !== virtualView.top) {
3647
+ if (isDebug) {
3648
+ this.debugLog('log', `update top height cause added element in top: ${adjustedTopHeight}, old height: ${virtualView.top}`);
3649
+ }
3650
+ this.virtualTopHeightElement.style.height = `${adjustedTopHeight}px`;
3651
+ }
3652
+ }
3653
+ }
3654
+ this.tryMeasureInViewportChildrenHeights();
3655
+ });
3656
+ }
3657
+ calculateVirtualViewport() {
2964
3658
  const children = (this.editor.children || []);
2965
- if (!children.length || !this.shouldUseVirtual()) {
3659
+ if (!children.length || !this.isEnabledVirtualScroll()) {
2966
3660
  return {
2967
- renderedChildren: children,
3661
+ inViewportChildren: children,
2968
3662
  visibleIndexes: new Set(),
2969
3663
  top: 0,
2970
3664
  bottom: 0,
2971
3665
  heights: []
2972
3666
  };
2973
3667
  }
2974
- const scrollTop = this.virtualConfig.scrollTop ?? 0;
2975
- const viewportHeight = this.virtualConfig.viewportHeight ?? 0;
3668
+ const scrollTop = this.virtualScrollConfig.scrollTop;
3669
+ if (isDebug) {
3670
+ const doc = this.elementRef?.nativeElement?.ownerDocument ?? document;
3671
+ VirtualScrollDebugOverlay.syncScrollTop(doc, Number.isFinite(scrollTop) ? scrollTop : 0);
3672
+ }
3673
+ const viewportHeight = this.virtualScrollConfig.viewportHeight ?? 0;
2976
3674
  if (!viewportHeight) {
2977
- // 已经启用虚拟滚动,但可视区域高度还未获取到,先置空不渲染
2978
3675
  return {
2979
- renderedChildren: [],
3676
+ inViewportChildren: [],
2980
3677
  visibleIndexes: new Set(),
2981
3678
  top: 0,
2982
3679
  bottom: 0,
2983
3680
  heights: []
2984
3681
  };
2985
3682
  }
2986
- const bufferCount = this.virtualConfig.bufferCount ?? VIRTUAL_SCROLL_DEFAULT_BUFFER_COUNT;
2987
- const heights = children.map((_, idx) => this.getBlockHeight(idx));
2988
- const accumulatedHeights = this.buildAccumulatedHeight(heights);
2989
- let visibleStart = 0;
2990
- // 按真实或估算高度往后累加,找到滚动起点所在块
2991
- while (visibleStart < heights.length && accumulatedHeights[visibleStart + 1] <= scrollTop) {
2992
- visibleStart++;
2993
- }
2994
- // 向上预留 bufferCount 块
2995
- const startIndex = Math.max(0, visibleStart - bufferCount);
2996
- const top = accumulatedHeights[startIndex];
2997
- const bufferBelowHeight = this.getBufferBelowHeight(viewportHeight, visibleStart, bufferCount);
2998
- const targetHeight = accumulatedHeights[visibleStart] - top + viewportHeight + bufferBelowHeight;
3683
+ const elementLength = children.length;
3684
+ if (!EDITOR_TO_BUSINESS_TOP.has(this.editor)) {
3685
+ EDITOR_TO_BUSINESS_TOP.set(this.editor, 0);
3686
+ setTimeout(() => {
3687
+ const virtualTopBoundingTop = this.virtualTopHeightElement.getBoundingClientRect()?.top ?? 0;
3688
+ const businessTop = Math.ceil(virtualTopBoundingTop) +
3689
+ Math.ceil(this.virtualScrollConfig.scrollTop) -
3690
+ Math.floor(this.virtualScrollConfig.viewportBoundingTop);
3691
+ EDITOR_TO_BUSINESS_TOP.set(this.editor, businessTop);
3692
+ if (isDebug) {
3693
+ this.debugLog('log', 'businessTop', businessTop);
3694
+ }
3695
+ }, 100);
3696
+ }
3697
+ const adjustedScrollTop = Math.max(0, scrollTop - getBusinessTop(this.editor));
3698
+ const { heights, accumulatedHeights } = buildHeightsAndAccumulatedHeights(this.editor);
3699
+ const totalHeight = accumulatedHeights[elementLength];
3700
+ const maxScrollTop = Math.max(0, totalHeight - viewportHeight);
3701
+ const limitedScrollTop = Math.min(adjustedScrollTop, maxScrollTop);
3702
+ const viewBottom = limitedScrollTop + viewportHeight + getBusinessTop(this.editor);
3703
+ let accumulatedOffset = 0;
3704
+ let visibleStartIndex = -1;
2999
3705
  const visible = [];
3000
3706
  const visibleIndexes = [];
3001
- let accumulated = 0;
3002
- let cursor = startIndex;
3003
- // 循环累计高度超出目标高度(可视高度 + 上下 buffer)
3004
- while (cursor < children.length && accumulated < targetHeight) {
3005
- visible.push(children[cursor]);
3006
- visibleIndexes.push(cursor);
3007
- accumulated += this.getBlockHeight(cursor);
3008
- cursor++;
3009
- }
3010
- const bottom = heights.slice(cursor).reduce((acc, height) => acc + height, 0);
3011
- const renderedChildren = visible.length ? visible : children;
3012
- const visibleIndexesSet = new Set(visibleIndexes);
3707
+ for (let i = 0; i < elementLength && accumulatedOffset < viewBottom; i++) {
3708
+ const currentHeight = heights[i];
3709
+ const nextOffset = accumulatedOffset + currentHeight;
3710
+ // 可视区域有交集,加入渲染
3711
+ if (nextOffset > limitedScrollTop && accumulatedOffset < viewBottom) {
3712
+ if (visibleStartIndex === -1)
3713
+ visibleStartIndex = i; // 第一个相交起始位置
3714
+ visible.push(children[i]);
3715
+ visibleIndexes.push(i);
3716
+ }
3717
+ accumulatedOffset = nextOffset;
3718
+ }
3719
+ if (visibleStartIndex === -1 && elementLength) {
3720
+ visibleStartIndex = elementLength - 1;
3721
+ visible.push(children[visibleStartIndex]);
3722
+ visibleIndexes.push(visibleStartIndex);
3723
+ }
3724
+ const visibleEndIndex = visibleStartIndex === -1 ? elementLength - 1 : (visibleIndexes[visibleIndexes.length - 1] ?? visibleStartIndex);
3725
+ const top = visibleStartIndex === -1 ? 0 : accumulatedHeights[visibleStartIndex];
3726
+ const bottom = totalHeight - accumulatedHeights[visibleEndIndex + 1];
3013
3727
  return {
3014
- renderedChildren,
3015
- visibleIndexes: visibleIndexesSet,
3728
+ inViewportChildren: visible.length ? visible : children,
3729
+ visibleIndexes: new Set(visibleIndexes),
3016
3730
  top,
3017
3731
  bottom,
3018
- heights
3732
+ heights,
3733
+ accumulatedHeights
3019
3734
  };
3020
3735
  }
3021
3736
  applyVirtualView(virtualView) {
3022
- this.renderedChildren = virtualView.renderedChildren;
3023
- this.changeVirtualHeight(virtualView.top, virtualView.bottom);
3024
- this.virtualVisibleIndexes = virtualView.visibleIndexes;
3737
+ this.inViewportChildren = virtualView.inViewportChildren;
3738
+ this.setVirtualSpaceHeight(virtualView.top, virtualView.bottom);
3739
+ this.inViewportIndics = virtualView.visibleIndexes;
3025
3740
  }
3026
- diffVirtualView(virtualView) {
3027
- if (!this.renderedChildren.length) {
3741
+ diffVirtualViewport(virtualView, stage = 'first') {
3742
+ if (!this.inViewportChildren.length) {
3028
3743
  return {
3029
3744
  isDiff: true,
3030
3745
  diffTopRenderedIndexes: [],
3031
3746
  diffBottomRenderedIndexes: []
3032
3747
  };
3033
3748
  }
3034
- const oldVisibleIndexes = [...this.virtualVisibleIndexes];
3749
+ const oldVisibleIndexes = [...this.inViewportIndics];
3035
3750
  const newVisibleIndexes = [...virtualView.visibleIndexes];
3036
3751
  const firstNewIndex = newVisibleIndexes[0];
3037
3752
  const lastNewIndex = newVisibleIndexes[newVisibleIndexes.length - 1];
@@ -3087,17 +3802,18 @@ class SlateEditable {
3087
3802
  }
3088
3803
  }
3089
3804
  if (isDebug) {
3090
- console.log('oldVisibleIndexes:', oldVisibleIndexes);
3091
- console.log('newVisibleIndexes:', newVisibleIndexes);
3092
- console.log('diffTopRenderedIndexes:', isMissingTop ? '-' : isAddedTop ? '+' : '-', diffTopRenderedIndexes, diffTopRenderedIndexes.map(index => this.getBlockHeight(index, 0)));
3093
- console.log('diffBottomRenderedIndexes:', isAddedBottom ? '+' : isMissingBottom ? '-' : '+', diffBottomRenderedIndexes, diffBottomRenderedIndexes.map(index => this.getBlockHeight(index, 0)));
3805
+ this.debugLog('log', `====== diffVirtualViewport stage: ${stage} ======`);
3806
+ this.debugLog('log', 'oldVisibleIndexes:', oldVisibleIndexes);
3807
+ this.debugLog('log', 'newVisibleIndexes:', newVisibleIndexes);
3808
+ this.debugLog('log', 'diffTopRenderedIndexes:', isMissingTop ? '-' : isAddedTop ? '+' : '-', diffTopRenderedIndexes, diffTopRenderedIndexes.map(index => getRealHeightByElement(this.editor, this.editor.children[index], 0)));
3809
+ this.debugLog('log', 'diffBottomRenderedIndexes:', isAddedBottom ? '+' : isMissingBottom ? '-' : '+', diffBottomRenderedIndexes, diffBottomRenderedIndexes.map(index => getRealHeightByElement(this.editor, this.editor.children[index], 0)));
3094
3810
  const needTop = virtualView.heights.slice(0, newVisibleIndexes[0]).reduce((acc, height) => acc + height, 0);
3095
3811
  const needBottom = virtualView.heights
3096
3812
  .slice(newVisibleIndexes[newVisibleIndexes.length - 1] + 1)
3097
3813
  .reduce((acc, height) => acc + height, 0);
3098
- console.log('newTopHeight:', needTop, 'prevTopHeight:', parseFloat(this.virtualTopHeightElement.style.height));
3099
- console.log('newBottomHeight:', needBottom, 'prevBottomHeight:', parseFloat(this.virtualBottomHeightElement.style.height));
3100
- console.warn('=========== Dividing line ===========');
3814
+ this.debugLog('log', 'newTopHeight:', needTop, 'prevTopHeight:', parseFloat(this.virtualTopHeightElement.style.height));
3815
+ this.debugLog('log', 'newBottomHeight:', needBottom, 'prevBottomHeight:', parseFloat(this.virtualBottomHeightElement.style.height));
3816
+ this.debugLog('warn', '=========== Dividing line ===========');
3101
3817
  }
3102
3818
  return {
3103
3819
  isDiff: true,
@@ -3115,76 +3831,46 @@ class SlateEditable {
3115
3831
  diffBottomRenderedIndexes: []
3116
3832
  };
3117
3833
  }
3118
- getBlockHeight(index, defaultHeight = VIRTUAL_SCROLL_DEFAULT_BLOCK_HEIGHT) {
3119
- const node = this.editor.children[index];
3120
- if (!node) {
3121
- return defaultHeight;
3122
- }
3123
- const key = AngularEditor.findKey(this.editor, node);
3124
- return this.measuredHeights.get(key.id) ?? defaultHeight;
3125
- }
3126
- buildAccumulatedHeight(heights) {
3127
- const accumulatedHeights = new Array(heights.length + 1).fill(0);
3128
- for (let i = 0; i < heights.length; i++) {
3129
- // 存储前 i 个的累计高度
3130
- accumulatedHeights[i + 1] = accumulatedHeights[i] + heights[i];
3131
- }
3132
- return accumulatedHeights;
3133
- }
3134
- getBufferBelowHeight(viewportHeight, visibleStart, bufferCount) {
3135
- let blockHeight = 0;
3136
- let start = visibleStart;
3137
- // 循环累计高度超出视图高度代表找到向下缓冲区的起始位置
3138
- while (blockHeight < viewportHeight) {
3139
- blockHeight += this.getBlockHeight(start);
3140
- start++;
3141
- }
3142
- let bufferHeight = 0;
3143
- for (let i = start; i < start + bufferCount; i++) {
3144
- bufferHeight += this.getBlockHeight(i);
3145
- }
3146
- return bufferHeight;
3147
- }
3148
- scheduleMeasureVisibleHeights() {
3149
- if (!this.shouldUseVirtual()) {
3150
- return;
3151
- }
3152
- if (this.measurePending) {
3834
+ tryMeasureInViewportChildrenHeights() {
3835
+ if (!this.isEnabledVirtualScroll()) {
3153
3836
  return;
3154
3837
  }
3155
- this.measurePending = true;
3156
- this.measureVisibleHeightsAnimId && cancelAnimationFrame(this.measureVisibleHeightsAnimId);
3157
- this.measureVisibleHeightsAnimId = requestAnimationFrame(() => {
3838
+ this.tryMeasureInViewportChildrenHeightsAnimId && cancelAnimationFrame(this.tryMeasureInViewportChildrenHeightsAnimId);
3839
+ this.tryMeasureInViewportChildrenHeightsAnimId = requestAnimationFrame(() => {
3158
3840
  this.measureVisibleHeights();
3159
- this.measurePending = false;
3160
3841
  });
3161
3842
  }
3162
3843
  measureVisibleHeights() {
3163
3844
  const children = (this.editor.children || []);
3164
- this.virtualVisibleIndexes.forEach(index => {
3845
+ this.inViewportIndics.forEach(index => {
3165
3846
  const node = children[index];
3166
3847
  if (!node) {
3167
3848
  return;
3168
3849
  }
3169
3850
  const key = AngularEditor.findKey(this.editor, node);
3170
- // 跳过已测过的块
3171
- if (this.measuredHeights.has(key.id)) {
3851
+ // 跳过已测过的块,除非强制测量
3852
+ if (this.keyHeightMap.has(key.id)) {
3172
3853
  return;
3173
3854
  }
3174
3855
  const view = ELEMENT_TO_COMPONENT.get(node);
3175
3856
  if (!view) {
3176
3857
  return;
3177
3858
  }
3178
- view.getRealHeight()?.then(height => {
3179
- this.measuredHeights.set(key.id, height);
3180
- });
3859
+ const ret = view.getRealHeight();
3860
+ if (ret instanceof Promise) {
3861
+ ret.then(height => {
3862
+ this.keyHeightMap.set(key.id, height);
3863
+ });
3864
+ }
3865
+ else {
3866
+ this.keyHeightMap.set(key.id, ret);
3867
+ }
3181
3868
  });
3182
3869
  }
3183
- async measureHeightByIndexes(indexes, isRefresh = false) {
3870
+ remeasureHeightByIndics(indics) {
3184
3871
  const children = (this.editor.children || []);
3185
3872
  let isHeightChanged = false;
3186
- const promises = [];
3187
- indexes.forEach(index => {
3873
+ indics.forEach((index, i) => {
3188
3874
  const node = children[index];
3189
3875
  if (!node) {
3190
3876
  return;
@@ -3194,27 +3880,30 @@ class SlateEditable {
3194
3880
  if (!view) {
3195
3881
  return;
3196
3882
  }
3197
- const promise = view.getRealHeight()?.then(height => {
3198
- const prevHeight = this.measuredHeights.get(key.id);
3199
- if (isDebug) {
3200
- console.log('measureHeightByIndexes: get index:', index, 'prevHeight:', prevHeight, 'newHeight:', height);
3201
- }
3202
- if (prevHeight && height !== prevHeight) {
3203
- this.measuredHeights.set(key.id, height);
3883
+ const prevHeight = this.keyHeightMap.get(key.id);
3884
+ const ret = view.getRealHeight();
3885
+ if (ret instanceof Promise) {
3886
+ ret.then(height => {
3887
+ this.keyHeightMap.set(key.id, height);
3888
+ if (height !== prevHeight) {
3889
+ isHeightChanged = true;
3890
+ if (isDebug) {
3891
+ this.debugLog('log', `remeasure element height, index: ${index} prevHeight: ${prevHeight} newHeight: ${height}`);
3892
+ }
3893
+ }
3894
+ });
3895
+ }
3896
+ else {
3897
+ this.keyHeightMap.set(key.id, ret);
3898
+ if (ret !== prevHeight) {
3204
3899
  isHeightChanged = true;
3900
+ if (isDebug) {
3901
+ this.debugLog('log', `remeasure element height, index: ${index} prevHeight: ${prevHeight} newHeight: ${ret}`);
3902
+ }
3205
3903
  }
3206
- });
3207
- if (promise) {
3208
- promises.push(promise);
3209
3904
  }
3210
3905
  });
3211
- if (promises.length > 0) {
3212
- await Promise.all(promises);
3213
- if (isHeightChanged && isRefresh) {
3214
- return this.refreshVirtualView();
3215
- }
3216
- }
3217
- return null;
3906
+ return isHeightChanged;
3218
3907
  }
3219
3908
  //#region event proxy
3220
3909
  addEventListener(eventName, listener, target = this.elementRef.nativeElement) {
@@ -3740,6 +4429,11 @@ class SlateEditable {
3740
4429
  Transforms.move(editor, { unit: 'word', reverse: isRTL });
3741
4430
  return;
3742
4431
  }
4432
+ if (isKeyHotkey('mod+a', event)) {
4433
+ this.editor.selectAll();
4434
+ event.preventDefault();
4435
+ return;
4436
+ }
3743
4437
  // COMPAT: Certain browsers don't support the `beforeinput` event, so we
3744
4438
  // fall back to guessing at the input intention for hotkeys.
3745
4439
  // COMPAT: In iOS, some of these hotkeys are handled in the
@@ -3907,6 +4601,7 @@ class SlateEditable {
3907
4601
  }
3908
4602
  //#endregion
3909
4603
  ngOnDestroy() {
4604
+ this.editorResizeObserver?.disconnect();
3910
4605
  NODE_TO_ELEMENT.delete(this.editor);
3911
4606
  this.manualListeners.forEach(manualListener => {
3912
4607
  manualListener();
@@ -4166,6 +4861,7 @@ class BaseElementComponent extends BaseComponent {
4166
4861
  }
4167
4862
  return null;
4168
4863
  };
4864
+ this.stableHeight = null;
4169
4865
  }
4170
4866
  get element() {
4171
4867
  return this._context && this._context.element;
@@ -4219,6 +4915,7 @@ class BaseElementComponent extends BaseComponent {
4219
4915
  if (ELEMENT_TO_COMPONENT.get(this.element) === this) {
4220
4916
  ELEMENT_TO_COMPONENT.delete(this.element);
4221
4917
  }
4918
+ this.listRender.destroy();
4222
4919
  }
4223
4920
  onContextChange() {
4224
4921
  this.childrenContext = this.getChildrenContext();
@@ -4247,11 +4944,21 @@ class BaseElementComponent extends BaseComponent {
4247
4944
  readonly: this._context.readonly
4248
4945
  };
4249
4946
  }
4947
+ isStableHeight() {
4948
+ return false;
4949
+ }
4250
4950
  getRealHeight() {
4951
+ if (this.isStableHeight() && this.stableHeight !== null) {
4952
+ return this.stableHeight;
4953
+ }
4251
4954
  const blockCard = getBlockCardByNativeElement(this.nativeElement);
4252
4955
  const target = blockCard || this.nativeElement;
4253
4956
  const computedStyle = getComputedStyle(target);
4254
- return Promise.resolve(target.offsetHeight + parseFloat(computedStyle.marginTop) + parseFloat(computedStyle.marginBottom));
4957
+ const height = Math.ceil(target.getBoundingClientRect().height) + parseFloat(computedStyle.marginTop) + parseFloat(computedStyle.marginBottom);
4958
+ if (this.isStableHeight()) {
4959
+ this.stableHeight = height;
4960
+ }
4961
+ return height;
4255
4962
  }
4256
4963
  static { this.ɵfac = i0.ɵɵngDeclareFactory({ minVersion: "12.0.0", version: "20.3.12", ngImport: i0, type: BaseElementComponent, deps: null, target: i0.ɵɵFactoryTarget.Directive }); }
4257
4964
  static { this.ɵdir = i0.ɵɵngDeclareDirective({ minVersion: "14.0.0", version: "20.3.12", type: BaseElementComponent, isStandalone: true, viewQueries: [{ propertyName: "childrenOutletInstance", first: true, predicate: SlateChildrenOutlet, descendants: true, static: true }], usesInheritance: true, ngImport: i0 }); }
@@ -4296,6 +5003,7 @@ class BaseTextComponent extends BaseComponent {
4296
5003
  NODE_TO_ELEMENT.delete(this.text);
4297
5004
  }
4298
5005
  ELEMENT_TO_NODE.delete(this.nativeElement);
5006
+ this.leavesRender.destroy();
4299
5007
  }
4300
5008
  onContextChange() {
4301
5009
  this.updateWeakMap();
@@ -4407,5 +5115,5 @@ i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "20.3.12", ngImpo
4407
5115
  * Generated bundle index. Do not edit.
4408
5116
  */
4409
5117
 
4410
- export { AngularEditor, BaseComponent, BaseElementComponent, BaseElementFlavour, BaseFlavour, BaseLeafComponent, BaseLeafFlavour, BaseTextComponent, BaseTextFlavour, BlockCardRef, DEFAULT_ELEMENT_HEIGHT, DefaultTextFlavour, EDITOR_TO_AFTER_VIEW_INIT_QUEUE, 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_FIREFOX, IS_FIREFOX_LEGACY, IS_IOS, IS_QQBROWSER, IS_SAFARI, IS_UC_MOBILE, IS_WECHATBROWSER, JUST_NOW_UPDATED_VIRTUAL_VIEW, PLACEHOLDER_SYMBOL, SLATE_BLOCK_CARD_CLASS_NAME, SLATE_DEBUG_KEY, SlateBlockCard, SlateChildrenOutlet, SlateEditable, SlateErrorCode, SlateFragmentAttributeKey, SlateModule, VIRTUAL_SCROLL_DEFAULT_BLOCK_HEIGHT, VIRTUAL_SCROLL_DEFAULT_BUFFER_COUNT, VoidTextFlavour, blobAsString, buildHTMLText, check, completeTable, createClipboardData, createText, createThrottleRAF, defaultScrollSelectionIntoView, fallbackCopyText, getBlockCardByNativeElement, 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, isDecoratorRangeListEqual, isFlavourType, isInvalidTable, isTemplateRef, isValid, normalize, setClipboardData, setDataTransferClipboard, setDataTransferClipboardText, setNavigatorClipboard, shallowCompare, stripHtml, withAngular };
5118
+ 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_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, VIRTUAL_SCROLL_DEFAULT_BLOCK_HEIGHT, VoidTextFlavour, blobAsString, buildHTMLText, buildHeightsAndAccumulatedHeights, check, completeTable, createClipboardData, createText, createThrottleRAF, defaultScrollSelectionIntoView, fallbackCopyText, getBlockCardByNativeElement, getBusinessTop, getCardTargetAttribute, getClipboardData, getClipboardFromHTMLText, getContentHeight, getDataTransferClipboard, getDataTransferClipboardText, getNavigatorClipboard, getPlainText, getRealHeightByElement, getSelection, getSlateFragmentAttribute, getZeroTextNode, hasAfterContextChange, hasBeforeContextChange, hasBlockCard, hasBlockCardWithNode, hotkeys, isCardCenterByTargetAttr, isCardLeft, isCardLeftByTargetAttr, isCardRightByTargetAttr, isClipboardFile, isClipboardReadSupported, isClipboardWriteSupported, isClipboardWriteTextSupported, isComponentType, isDOMText, isDecoratorRangeListEqual, isFlavourType, isInvalidTable, isTemplateRef, isValid, normalize, scrollToElement, setClipboardData, setDataTransferClipboard, setDataTransferClipboardText, setNavigatorClipboard, shallowCompare, stripHtml, withAngular };
4411
5119
  //# sourceMappingURL=slate-angular.mjs.map