slate-angular 15.1.0-next.1 → 15.1.0-next.3

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.
@@ -3,6 +3,7 @@ import { isKeyHotkey } from 'is-hotkey';
3
3
  import * as i0 from '@angular/core';
4
4
  import { TemplateRef, Component, ChangeDetectionStrategy, ViewChild, Directive, Input, HostBinding, ViewChildren, InjectionToken, Inject, forwardRef, ElementRef, NgModule } from '@angular/core';
5
5
  import getDirection from 'direction';
6
+ import scrollIntoView from 'scroll-into-view-if-needed';
6
7
  import { Subject } from 'rxjs';
7
8
  import { NG_VALUE_ACCESSOR } from '@angular/forms';
8
9
  import { HistoryEditor } from 'slate-history';
@@ -1623,25 +1624,19 @@ function restoreDom(editor, execute) {
1623
1624
  class SlateStringTemplateComponent {
1624
1625
  }
1625
1626
  SlateStringTemplateComponent.ɵfac = i0.ɵɵngDeclareFactory({ minVersion: "12.0.0", version: "15.1.4", ngImport: i0, type: SlateStringTemplateComponent, deps: [], target: i0.ɵɵFactoryTarget.Component });
1626
- SlateStringTemplateComponent.ɵcmp = i0.ɵɵngDeclareComponent({ minVersion: "14.0.0", version: "15.1.4", type: SlateStringTemplateComponent, selector: "slate-string-template", viewQueries: [{ propertyName: "compatStringTemplate", first: true, predicate: ["compatStringTemplate"], descendants: true, read: TemplateRef, static: true }, { propertyName: "emptyStringTemplate", first: true, predicate: ["emptyStringTemplate"], descendants: true, read: TemplateRef, static: true }, { propertyName: "emptyTextTemplate", first: true, predicate: ["emptyTextTemplate"], descendants: true, read: TemplateRef, static: true }, { propertyName: "lineBreakEmptyStringTemplate", first: true, predicate: ["lineBreakEmptyStringTemplate"], descendants: true, read: TemplateRef, static: true }], ngImport: i0, template: "<ng-template #compatStringTemplate let-context=\"context\" let-viewContext=\"viewContext\">\n <!-- Compatible with Chinese input in Chrome with \\n -->\n <span editable-text data-slate-string=\"true\"\n >{{ context.text }}<span data-slate-zero-width>{{ '\\uFEFF' }}</span></span\n >\n</ng-template>\n<ng-template #emptyStringTemplate let-context=\"context\" let-viewContext=\"viewContext\">\n <span editable-text data-slate-zero-width=\"z\" attr.data-slate-length=\"{{ context.elementStringLength }}\">{{ '\\uFEFF' }}</span>\n</ng-template>\n<ng-template #emptyTextTemplate let-context=\"context\" let-viewContext=\"viewContext\">\n <span editable-text data-slate-zero-width=\"z\" data-slate-length=\"0\">{{ '\\uFEFF' }}</span>\n</ng-template>\n<ng-template #lineBreakEmptyStringTemplate let-context=\"context\" let-viewContext=\"viewContext\">\n <span editable-text data-slate-zero-width=\"n\" attr.data-slate-length=\"{{ context.elementStringLength }}\">{{ '\\uFEFF' }}<br /></span>\n</ng-template>\n", changeDetection: i0.ChangeDetectionStrategy.OnPush });
1627
+ SlateStringTemplateComponent.ɵcmp = i0.ɵɵngDeclareComponent({ minVersion: "14.0.0", version: "15.1.4", type: SlateStringTemplateComponent, selector: "slate-string-template", viewQueries: [{ propertyName: "compatibleStringTemplate", first: true, predicate: ["compatibleStringTemplate"], descendants: true, read: TemplateRef, static: true }, { propertyName: "voidStringTemplate", first: true, predicate: ["voidStringTemplate"], descendants: true, read: TemplateRef, static: true }, { propertyName: "emptyTextTemplate", first: true, predicate: ["emptyTextTemplate"], descendants: true, read: TemplateRef, static: true }], ngImport: i0, template: "<ng-template #compatibleStringTemplate let-context=\"context\" let-viewContext=\"viewContext\">\n <!-- Compatible with Chinese input in Chrome with \\n -->\n <span editable-text data-slate-string=\"true\"\n >{{ context.text }}<span data-slate-zero-width>{{ '\\uFEFF' }}</span></span\n >\n</ng-template>\n<ng-template #voidStringTemplate let-context=\"context\" let-viewContext=\"viewContext\">\n <span editable-text data-slate-zero-width=\"z\" attr.data-slate-length=\"{{ context.elementStringLength }}\">{{ '\\uFEFF' }}</span>\n</ng-template>\n<ng-template #emptyTextTemplate let-context=\"context\" let-viewContext=\"viewContext\">\n <span editable-text data-slate-zero-width=\"z\" data-slate-length=\"0\">{{ '\\uFEFF' }}</span>\n</ng-template>\n", changeDetection: i0.ChangeDetectionStrategy.OnPush });
1627
1628
  i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "15.1.4", ngImport: i0, type: SlateStringTemplateComponent, decorators: [{
1628
1629
  type: Component,
1629
- args: [{ selector: 'slate-string-template', changeDetection: ChangeDetectionStrategy.OnPush, template: "<ng-template #compatStringTemplate let-context=\"context\" let-viewContext=\"viewContext\">\n <!-- Compatible with Chinese input in Chrome with \\n -->\n <span editable-text data-slate-string=\"true\"\n >{{ context.text }}<span data-slate-zero-width>{{ '\\uFEFF' }}</span></span\n >\n</ng-template>\n<ng-template #emptyStringTemplate let-context=\"context\" let-viewContext=\"viewContext\">\n <span editable-text data-slate-zero-width=\"z\" attr.data-slate-length=\"{{ context.elementStringLength }}\">{{ '\\uFEFF' }}</span>\n</ng-template>\n<ng-template #emptyTextTemplate let-context=\"context\" let-viewContext=\"viewContext\">\n <span editable-text data-slate-zero-width=\"z\" data-slate-length=\"0\">{{ '\\uFEFF' }}</span>\n</ng-template>\n<ng-template #lineBreakEmptyStringTemplate let-context=\"context\" let-viewContext=\"viewContext\">\n <span editable-text data-slate-zero-width=\"n\" attr.data-slate-length=\"{{ context.elementStringLength }}\">{{ '\\uFEFF' }}<br /></span>\n</ng-template>\n" }]
1630
- }], propDecorators: { compatStringTemplate: [{
1630
+ args: [{ selector: 'slate-string-template', changeDetection: ChangeDetectionStrategy.OnPush, template: "<ng-template #compatibleStringTemplate let-context=\"context\" let-viewContext=\"viewContext\">\n <!-- Compatible with Chinese input in Chrome with \\n -->\n <span editable-text data-slate-string=\"true\"\n >{{ context.text }}<span data-slate-zero-width>{{ '\\uFEFF' }}</span></span\n >\n</ng-template>\n<ng-template #voidStringTemplate let-context=\"context\" let-viewContext=\"viewContext\">\n <span editable-text data-slate-zero-width=\"z\" attr.data-slate-length=\"{{ context.elementStringLength }}\">{{ '\\uFEFF' }}</span>\n</ng-template>\n<ng-template #emptyTextTemplate let-context=\"context\" let-viewContext=\"viewContext\">\n <span editable-text data-slate-zero-width=\"z\" data-slate-length=\"0\">{{ '\\uFEFF' }}</span>\n</ng-template>\n" }]
1631
+ }], propDecorators: { compatibleStringTemplate: [{
1631
1632
  type: ViewChild,
1632
- args: ['compatStringTemplate', { read: TemplateRef, static: true }]
1633
- }], emptyStringTemplate: [{
1633
+ args: ['compatibleStringTemplate', { read: TemplateRef, static: true }]
1634
+ }], voidStringTemplate: [{
1634
1635
  type: ViewChild,
1635
- args: ['emptyStringTemplate', { read: TemplateRef, static: true }]
1636
+ args: ['voidStringTemplate', { read: TemplateRef, static: true }]
1636
1637
  }], emptyTextTemplate: [{
1637
1638
  type: ViewChild,
1638
1639
  args: ['emptyTextTemplate', { read: TemplateRef, static: true }]
1639
- }], lineBreakEmptyStringTemplate: [{
1640
- type: ViewChild,
1641
- args: ['lineBreakEmptyStringTemplate', {
1642
- read: TemplateRef,
1643
- static: true
1644
- }]
1645
1640
  }] } });
1646
1641
 
1647
1642
  class SlateBlockCardComponent {
@@ -2104,15 +2099,57 @@ class SlateDefaultStringComponent extends BaseComponent {
2104
2099
  this.elementRef = elementRef;
2105
2100
  this.cdr = cdr;
2106
2101
  }
2102
+ beforeContextChange(value) {
2103
+ if (this.context) {
2104
+ if (this.context.type === 'lineBreakEmptyString') {
2105
+ this.removeLineBreakEmptyStringDOM();
2106
+ }
2107
+ if (this.context.type === 'string') {
2108
+ if (value.type === 'lineBreakEmptyString') {
2109
+ this.removeStringDOM();
2110
+ }
2111
+ }
2112
+ }
2113
+ }
2107
2114
  onContextChange() {
2115
+ if (this.context.type === 'string') {
2116
+ this.createStringDOM();
2117
+ }
2118
+ else if (this.context.type === 'lineBreakEmptyString') {
2119
+ this.createLineBreakEmptyStringDOM();
2120
+ }
2121
+ }
2122
+ createLineBreakEmptyStringDOM() {
2123
+ this.nativeElement.setAttribute('data-slate-zero-width', 'n');
2124
+ this.nativeElement.setAttribute('data-slate-length', `${this.context.elementStringLength}`);
2125
+ this.textNode = document.createTextNode(`\uFEFF`);
2126
+ this.brNode = document.createElement('br');
2127
+ this.nativeElement.append(this.textNode, this.brNode);
2128
+ }
2129
+ removeLineBreakEmptyStringDOM() {
2130
+ this.brNode?.remove();
2131
+ // remove zero width character
2132
+ const zeroWidthCharacterIndex = this.textNode?.textContent.indexOf(`\uFEFF`);
2133
+ this.textNode?.deleteData(zeroWidthCharacterIndex, 1);
2134
+ this.nativeElement.removeAttribute('data-slate-zero-width');
2135
+ this.nativeElement.removeAttribute('data-slate-length');
2136
+ }
2137
+ createStringDOM() {
2138
+ this.nativeElement.setAttribute('data-slate-string', 'true');
2139
+ this.updateStringDOM();
2140
+ }
2141
+ updateStringDOM() {
2108
2142
  // Avoid breaking some browser default behaviors, such as spellCheck, android composition input state
2109
2143
  if (this.nativeElement.textContent !== this.context.text) {
2110
2144
  this.nativeElement.textContent = this.context.text;
2111
2145
  }
2112
2146
  }
2147
+ removeStringDOM() {
2148
+ this.nativeElement.removeAttribute('data-slate-string');
2149
+ this.nativeElement.textContent = '';
2150
+ }
2113
2151
  ngOnInit() {
2114
2152
  this.nativeElement.setAttribute('editable-text', '');
2115
- this.nativeElement.setAttribute('data-slate-string', 'true');
2116
2153
  }
2117
2154
  }
2118
2155
  SlateDefaultStringComponent.ɵfac = i0.ɵɵngDeclareFactory({ minVersion: "12.0.0", version: "15.1.4", ngImport: i0, type: SlateDefaultStringComponent, deps: [{ token: i0.ElementRef }, { token: i0.ChangeDetectorRef }], target: i0.ɵɵFactoryTarget.Component });
@@ -2144,40 +2181,60 @@ class SlateStringComponent extends ViewContainerItem {
2144
2181
  ngAfterViewInit() {
2145
2182
  this.elementRef.nativeElement.remove();
2146
2183
  }
2147
- getViewType() {
2184
+ // COMPAT: If this is the last text node in an empty block, render a zero-
2185
+ // width space that will convert into a line break when copying and pasting
2186
+ // to support expected plain text.
2187
+ isLineBreakEmptyString() {
2148
2188
  const path = AngularEditor.findPath(this.viewContext.editor, this.context.text);
2149
2189
  const parentPath = Path.parent(path);
2150
- // COMPAT: Render text inside void nodes with a zero-width space.
2151
- // So the node can contain selection but the text is not visible.
2152
- if (this.viewContext.editor.isVoid(this.context.parent)) {
2153
- return this.viewContext.templateComponent.emptyStringTemplate;
2154
- }
2155
- // COMPAT: If this is the last text node in an empty block, render a zero-
2156
- // width space that will convert into a line break when copying and pasting
2157
- // to support expected plain text.
2158
- if (this.context.leaf.text === '' &&
2190
+ return (this.context.leaf.text === '' &&
2159
2191
  this.context.parent.children[this.context.parent.children.length - 1] === this.context.text &&
2160
2192
  !this.viewContext.editor.isInline(this.context.parent) &&
2161
- Editor.string(this.viewContext.editor, parentPath) === '') {
2162
- return this.viewContext.templateComponent.lineBreakEmptyStringTemplate;
2193
+ Editor.string(this.viewContext.editor, parentPath) === '');
2194
+ }
2195
+ // COMPAT: If the text is empty, it's because it's on the edge of an inline
2196
+ // node, so we render a zero-width space so that the selection can be
2197
+ // inserted next to it still.
2198
+ isEmptyText() {
2199
+ return this.context.leaf.text === '';
2200
+ }
2201
+ // COMPAT: Browsers will collapse trailing new lines at the end of blocks,
2202
+ // so we need to add an extra trailing new lines to prevent that.
2203
+ isCompatibleString() {
2204
+ return this.context.isLast && this.context.leaf.text.slice(-1) === '\n';
2205
+ }
2206
+ // COMPAT: Render text inside void nodes with a zero-width space.
2207
+ // So the node can contain selection but the text is not visible.
2208
+ isVoid() {
2209
+ return this.viewContext.editor.isVoid(this.context.parent);
2210
+ }
2211
+ getViewType() {
2212
+ if (this.isVoid()) {
2213
+ return this.viewContext.templateComponent.voidStringTemplate;
2163
2214
  }
2164
- // COMPAT: If the text is empty, it's because it's on the edge of an inline
2165
- // node, so we render a zero-width space so that the selection can be
2166
- // inserted next to it still.
2167
- if (this.context.leaf.text === '') {
2215
+ if (this.isLineBreakEmptyString()) {
2216
+ return SlateDefaultStringComponent;
2217
+ }
2218
+ if (this.isEmptyText()) {
2168
2219
  return this.viewContext.templateComponent.emptyTextTemplate;
2169
2220
  }
2170
- // COMPAT: Browsers will collapse trailing new lines at the end of blocks,
2171
- // so we need to add an extra trailing new lines to prevent that.
2172
- if (this.context.isLast && this.context.leaf.text.slice(-1) === '\n') {
2173
- return this.viewContext.templateComponent.compatStringTemplate;
2221
+ if (this.isCompatibleString()) {
2222
+ return this.viewContext.templateComponent.compatibleStringTemplate;
2174
2223
  }
2175
2224
  return SlateDefaultStringComponent;
2176
2225
  }
2226
+ getType() {
2227
+ if (this.isLineBreakEmptyString()) {
2228
+ return 'lineBreakEmptyString';
2229
+ }
2230
+ return 'string';
2231
+ }
2177
2232
  getContext() {
2233
+ const stringType = this.getType();
2178
2234
  return {
2179
2235
  text: this.context.leaf.text,
2180
- elementStringLength: Node.string(this.context.parent).length
2236
+ elementStringLength: Node.string(this.context.parent).length,
2237
+ type: stringType
2181
2238
  };
2182
2239
  }
2183
2240
  memoizedContext(prev, next) {
@@ -2261,10 +2318,10 @@ class SlateLeavesComponent extends ViewContainer {
2261
2318
  }
2262
2319
  ngOnInit() {
2263
2320
  this.leaves = Text$1.decorations(this.context.text, this.context.decorations);
2264
- this.leafContexts = this.getLeafCotexts();
2321
+ this.leafContexts = this.getLeafContexts();
2265
2322
  this.initialized = true;
2266
2323
  }
2267
- getLeafCotexts() {
2324
+ getLeafContexts() {
2268
2325
  return this.leaves.map((leaf, index) => {
2269
2326
  return {
2270
2327
  leaf,
@@ -2285,7 +2342,7 @@ class SlateLeavesComponent extends ViewContainer {
2285
2342
  if (previousValue.text !== currentValue.text || !isDecoratorRangeListEqual(previousValue.decorations, currentValue.decorations)) {
2286
2343
  this.leaves = Text$1.decorations(this.context.text, this.context.decorations);
2287
2344
  }
2288
- this.leafContexts = this.getLeafCotexts();
2345
+ this.leafContexts = this.getLeafContexts();
2289
2346
  }
2290
2347
  trackBy(index, item) {
2291
2348
  return index;
@@ -2601,6 +2658,7 @@ class SlateEditableComponent {
2601
2658
  this.onTouchedCallback = () => { };
2602
2659
  this.onChangeCallback = () => { };
2603
2660
  this.decorate = () => [];
2661
+ this.scrollSelectionIntoView = defaultScrollSelectionIntoView;
2604
2662
  this.isStrictDecorate = true;
2605
2663
  this.trackBy = () => null;
2606
2664
  this.readonly = false;
@@ -2633,7 +2691,7 @@ class SlateEditableComponent {
2633
2691
  this.initializeViewContext();
2634
2692
  this.initializeContext();
2635
2693
  // remove unused DOM, just keep templateComponent instance
2636
- this.templateElementRef.nativeElement.remove();
2694
+ // this.templateElementRef.nativeElement.remove();
2637
2695
  // add browser class
2638
2696
  let browserClass = IS_FIREFOX ? 'firefox' : IS_SAFARI ? 'safari' : '';
2639
2697
  browserClass && this.elementRef.nativeElement.classList.add(browserClass);
@@ -2766,6 +2824,7 @@ class SlateEditableComponent {
2766
2824
  else {
2767
2825
  domSelection.removeAllRanges();
2768
2826
  }
2827
+ this.scrollSelectionIntoView(this.editor, newDomRange);
2769
2828
  setTimeout(() => {
2770
2829
  // COMPAT: In Firefox, it's not enough to create a range, you also need
2771
2830
  // to focus the contenteditable element too. (2016/11/16)
@@ -3567,7 +3626,7 @@ class SlateEditableComponent {
3567
3626
  }
3568
3627
  }
3569
3628
  SlateEditableComponent.ɵfac = i0.ɵɵngDeclareFactory({ minVersion: "12.0.0", version: "15.1.4", ngImport: i0, type: SlateEditableComponent, deps: [{ token: i0.ElementRef }, { token: i0.Renderer2 }, { token: i0.ChangeDetectorRef }, { token: i0.NgZone }, { token: i0.Injector }], target: i0.ɵɵFactoryTarget.Component });
3570
- SlateEditableComponent.ɵcmp = i0.ɵɵngDeclareComponent({ minVersion: "14.0.0", version: "15.1.4", type: SlateEditableComponent, selector: "slate-editable", inputs: { editor: "editor", renderElement: "renderElement", renderLeaf: "renderLeaf", renderText: "renderText", decorate: "decorate", placeholderDecorate: "placeholderDecorate", isStrictDecorate: "isStrictDecorate", trackBy: "trackBy", readonly: "readonly", placeholder: "placeholder", beforeInput: "beforeInput", blur: "blur", click: "click", compositionEnd: "compositionEnd", compositionStart: "compositionStart", copy: "copy", cut: "cut", dragOver: "dragOver", dragStart: "dragStart", dragEnd: "dragEnd", drop: "drop", focus: "focus", keydown: "keydown", paste: "paste", spellCheck: "spellCheck", autoCorrect: "autoCorrect", autoCapitalize: "autoCapitalize" }, host: { properties: { "attr.contenteditable": "readonly ? undefined : true", "attr.role": "readonly ? undefined : 'textbox'", "attr.spellCheck": "!hasBeforeInputSupport ? false : spellCheck", "attr.autoCorrect": "!hasBeforeInputSupport ? 'false' : autoCorrect", "attr.autoCapitalize": "!hasBeforeInputSupport ? 'false' : autoCapitalize", "attr.data-slate-editor": "this.dataSlateEditor", "attr.data-slate-node": "this.dataSlateNode", "attr.data-gramm": "this.dataGramm" }, classAttribute: "slate-editable-container" }, providers: [
3629
+ SlateEditableComponent.ɵcmp = i0.ɵɵngDeclareComponent({ minVersion: "14.0.0", version: "15.1.4", type: SlateEditableComponent, selector: "slate-editable", inputs: { editor: "editor", renderElement: "renderElement", renderLeaf: "renderLeaf", renderText: "renderText", decorate: "decorate", placeholderDecorate: "placeholderDecorate", scrollSelectionIntoView: "scrollSelectionIntoView", isStrictDecorate: "isStrictDecorate", trackBy: "trackBy", readonly: "readonly", placeholder: "placeholder", beforeInput: "beforeInput", blur: "blur", click: "click", compositionEnd: "compositionEnd", compositionStart: "compositionStart", copy: "copy", cut: "cut", dragOver: "dragOver", dragStart: "dragStart", dragEnd: "dragEnd", drop: "drop", focus: "focus", keydown: "keydown", paste: "paste", spellCheck: "spellCheck", autoCorrect: "autoCorrect", autoCapitalize: "autoCapitalize" }, host: { properties: { "attr.contenteditable": "readonly ? undefined : true", "attr.role": "readonly ? undefined : 'textbox'", "attr.spellCheck": "!hasBeforeInputSupport ? false : spellCheck", "attr.autoCorrect": "!hasBeforeInputSupport ? 'false' : autoCorrect", "attr.autoCapitalize": "!hasBeforeInputSupport ? 'false' : autoCapitalize", "attr.data-slate-editor": "this.dataSlateEditor", "attr.data-slate-node": "this.dataSlateNode", "attr.data-gramm": "this.dataGramm" }, classAttribute: "slate-editable-container" }, providers: [
3571
3630
  {
3572
3631
  provide: NG_VALUE_ACCESSOR,
3573
3632
  useExisting: forwardRef(() => SlateEditableComponent),
@@ -3602,6 +3661,8 @@ i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "15.1.4", ngImpor
3602
3661
  type: Input
3603
3662
  }], placeholderDecorate: [{
3604
3663
  type: Input
3664
+ }], scrollSelectionIntoView: [{
3665
+ type: Input
3605
3666
  }], isStrictDecorate: [{
3606
3667
  type: Input
3607
3668
  }], trackBy: [{
@@ -3660,6 +3721,18 @@ i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "15.1.4", ngImpor
3660
3721
  type: ViewChild,
3661
3722
  args: ['templateComponent', { static: true, read: ElementRef }]
3662
3723
  }] } });
3724
+ const defaultScrollSelectionIntoView = (editor, domRange) => {
3725
+ // This was affecting the selection of multiple blocks and dragging behavior,
3726
+ // so enabled only if the selection has been collapsed.
3727
+ if (domRange.getBoundingClientRect && (!editor.selection || (editor.selection && Range.isCollapsed(editor.selection)))) {
3728
+ const leafEl = domRange.startContainer.parentElement;
3729
+ leafEl.getBoundingClientRect = domRange.getBoundingClientRect.bind(domRange);
3730
+ scrollIntoView(leafEl, {
3731
+ scrollMode: 'if-needed'
3732
+ });
3733
+ delete leafEl.getBoundingClientRect;
3734
+ }
3735
+ };
3663
3736
  /**
3664
3737
  * Check if the target is editable and in the editor.
3665
3738
  */