Coder Social home page Coder Social logo

worktile / slate-angular Goto Github PK

View Code? Open in Web Editor NEW
171.0 13.0 29.0 2.89 MB

Angular view layer for Slate

Home Page: http://slate-angular.ngnice.com

License: MIT License

JavaScript 1.76% TypeScript 97.25% HTML 0.38% SCSS 0.56% Dockerfile 0.05%
slate angular rich-text-editor slate-angular

slate-angular's Introduction

slate-angular

CircleCI Coverage Status npm (scoped) npm npm bundle size (scoped) Telegram

Angular view layer for Slate

中文文档

Introduction

Slate is a completely customizable framework for building rich text editors, including the model layer and view layer, but the slate only provides the view layer based on react, slate-angular is a supplement to the slate view layer, to help you use angular to build rich text editor.

slate-angular is inspired by slate-react, and try to keep the style of slate and angular, friendly to Chinese input, start your slate-angular journey.

Demo

Try out our live demo

editor-preview.png

Feature

  • Support element front and rear cursor scheme
  • Support custom component/template rendering Element
  • Support custom component/template to render Text
  • Support custom component/template rendering Leaf
  • Support decorate decoration
  • Support void element

Compatible browser

Chrome、Edge、Safari、Firefox、QQ Browser

Usage

1. Install dependencies

"dependencies": {
    "direction": "^2.0.1",
    "is-hotkey": "^0.2.0",
    "slate": "~0.101.5",
    "slate-history": "~0.100.0",
    "slate-angular": "~16.1.0-next.8"
}

2. Loading SlateModule in AppModule

import { FormsModule } from '@angular/forms';
import { SlateModule } from 'slate-angular';

@NgModule({
  imports: [
    // ...,
    FormsModule,
    SlateModule
  ],
  // ...
})
export class AppModule { }

3. Import index.scss

src/styles.scss

@use 'slate-angular/styles/index.scss';

// basic richtext styles
.slate-editable-container {
    [slate-underlined][slate-strike] {
        text-decoration: underline line-through;
    }
    [slate-strike] {
        text-decoration: line-through;
    }
    [slate-underlined] {
        text-decoration: underline;
    }
    [slate-italic] {
        font-style: italic;
    }
    [slate-bold] {
        font-weight: bold;
    }
    [slate-code-line] {
        margin: 0 4px;
        padding: 2px 3px;
        border: 1px solid rgba($color: #000000, $alpha: 0.08);
        border-radius: 2px;
        background-color: rgba($color: #000000, $alpha: 0.06);
    }

    blockquote {
        margin: 0;
        margin-left: 0;
        margin-right: 0;
        color: #888;
        padding-left: 10px !important;
        border-left: 4px solid #eee;
    }

    h1,h2,h3 {
        margin: 0px;
    }

    &>[data-slate-node="element"],&>slate-block-card {
        margin-bottom: 12px;
    }
}

// basic richtext container styles
.demo-richtext-container {
    max-width: 42em;
    margin: 50px auto;
    background-color: #fff;
    box-shadow: 0px 0px 4px rgba(0, 0, 0, 0.2);
}

4. Add text-mark component

import { ChangeDetectorRef, Component, ElementRef, Renderer2 } from "@angular/core";
import { BaseTextComponent } from "slate-angular";

export enum MarkTypes {
    bold = 'bold',
    italic = 'italic',
    underline = 'underlined',
    strike = 'strike',
    code = 'code-line'
}

@Component({
    selector: 'span[textMark]',
    template: ``,
    host: {
        'data-slate-node': 'text'
    }
})
export class DemoTextMarkComponent extends BaseTextComponent {
    attributes: string[] = [];

    constructor(public elementRef: ElementRef, public renderer2: Renderer2, cdr: ChangeDetectorRef) {
        super(elementRef, cdr);
    }

    applyTextMark() {
        this.attributes.forEach(attr => {
            this.renderer2.removeAttribute(this.elementRef.nativeElement, attr);
        });
        this.attributes = [];
        for (const key in this.text) {
            if (Object.prototype.hasOwnProperty.call(this.text, key) && key !== 'text') {
                const attr = `slate-${key}`;
                this.renderer2.setAttribute(this.elementRef.nativeElement, attr, 'true');
                this.attributes.push(attr);
            }
        }
    }

    onContextChange() {
        super.onContextChange();
        this.applyTextMark();
    }
}

5. Use slate-editable component

Template

<div class="demo-richtext-container">
    <slate-editable [editor]="editor" [(ngModel)]="value"
        (ngModelChange)="valueChange($event)"
        [renderElement]="renderElement"
        [renderText]="renderText">
        <ng-template #heading_1 let-context="context" let-viewContext="viewContext">
            <h1 slateElement [context]="context" [viewContext]="viewContext"></h1>
        </ng-template>
        <ng-template #heading_2 let-context="context" let-viewContext="viewContext">
            <h2 slateElement [context]="context" [viewContext]="viewContext"></h2>
        </ng-template>
        <ng-template #heading_3 let-context="context" let-viewContext="viewContext">
            <h3 slateElement [context]="context" [viewContext]="viewContext"></h3>
        </ng-template>
        <ng-template #blockquote let-context="context" let-viewContext="viewContext">
            <blockquote slateElement [context]="context" [viewContext]="viewContext"></blockquote>
        </ng-template>
        <ng-template #ul let-context="context" let-viewContext="viewContext">
            <ul slateElement [context]="context" [viewContext]="viewContext"></ul>
        </ng-template>
        <ng-template #ol let-context="context" let-viewContext="viewContext">
            <ol slateElement [context]="context" [viewContext]="viewContext"></ol>
        </ng-template>
        <ng-template #li let-context="context" let-viewContext="viewContext">
            <li slateElement [context]="context" [viewContext]="viewContext"></li>
        </ng-template>
    </slate-editable>
</div>

TS

import { Component, ViewChild, TemplateRef } from '@angular/core';
import { createEditor, Element } from 'slate';
import { withHistory } from 'slate-history';
import { withAngular } from 'slate-angular';
import { DemoTextMarkComponent, MarkTypes } from './text-mark.component';

@Component({
  selector: 'app-root',
  templateUrl: './app.component.html',
  styleUrls: ['./app.component.scss']
})
export class AppComponent {
  	title = 'slate-angular-basic';
    value = initialValue;

    @ViewChild('heading_1', { read: TemplateRef, static: true })
    headingOneTemplate!: TemplateRef<any>;

    @ViewChild('heading_2', { read: TemplateRef, static: true })
    headingTwoTemplate!: TemplateRef<any>;

    @ViewChild('heading_3', { read: TemplateRef, static: true })
    headingThreeTemplate!: TemplateRef<any>;

    @ViewChild('blockquote', { read: TemplateRef, static: true })
    blockquoteTemplate!: TemplateRef<any>;

    @ViewChild('ul', { read: TemplateRef, static: true })
    ulTemplate!: TemplateRef<any>;

    @ViewChild('ol', { read: TemplateRef, static: true })
    olTemplate!: TemplateRef<any>;

    @ViewChild('li', { read: TemplateRef, static: true })
    liTemplate!: TemplateRef<any>;

    editor = withHistory(withAngular(createEditor()));

    ngOnInit(): void {
    }

    valueChange(value: Element[]) {
    }

    renderElement = (element: any) => {
        if (element.type === 'heading-one') {
            return this.headingOneTemplate;
        }
        if (element.type === 'heading-two') {
            return this.headingTwoTemplate;
        }
        if (element.type === 'heading-three') {
            return this.headingThreeTemplate;
        }
        if (element.type === 'block-quote') {
            return this.blockquoteTemplate;
        }
        if (element.type === 'numbered-list') {
            return this.olTemplate;
        }
        if (element.type === 'bulleted-list') {
            return this.ulTemplate;
        }
        if (element.type === 'list-item') {
            return this.liTemplate;
        }
        return null;
    }

    renderText = (text: any) => {
        if (text[MarkTypes.bold] || text[MarkTypes.italic] || text[MarkTypes.code] || text[MarkTypes.underline]) {
            return DemoTextMarkComponent;
        }
      	return null;
    }
}

const initialValue = [
    {
        type: 'paragraph',
        children: [
            { text: 'This is editable ' },
            { text: 'rich', bold: true },
            { text: ' text, ' },
            { text: 'much', bold: true, italic: true },
            { text: ' better than a ' },
            { text: '<textarea>', 'code-line': true },
            { text: '!' }
        ]
    },
    {
        type: 'heading-one',
        children: [{ text: 'This is h1 ' }]
    },
    {
        type: 'heading-three',
        children: [{ text: 'This is h3 ' }]
    },
    {
        type: 'paragraph',
        children: [
            {
                text: `Since it's rich text, you can do things like turn a selection of text `
            },
            { text: 'bold', bold: true },
            {
                text: ', or add a semantically rendered block quote in the middle of the page, like this:'
            }
        ]
    },
    {
        type: 'block-quote',
        children: [{ text: 'A wise quote.' }]
    },
    {
        type: 'paragraph',
        children: [{ text: 'Try it out for yourself!' }]
    },
    {
        type: 'paragraph',
        children: [{ text: '' }]
    }
];

6. Startup basic demo

Before starting, you need to declare the DemoTextMarkComponent component in NgModule

You can checkout a stackblitz implementation of the readme usage

Start the demo and you will get the following interface

image.png

Currently, there is no toolbar. You need to add toolbars and processing functions according to your own icon library.

basic usage: https://github.com/pubuzhixing8/slate-angular-basic

Who is using slate-angular?


PingCode Wiki

💻 Development

npm install   // Installs package dependencies
npm run start              // run demo
npm run build              // build new slate-angular

npm run test               // run unit tests

Prerequisites

Angular >= 10.*

Slate >= 0.63.0

Contributing

🌟 Stars and 📥 Pull requests to worktile/slate-angular are welcome!

LICENSE

MIT License

slate-angular's People

Contributors

ashy6 avatar bricklou avatar cmm-va avatar dinglonggang666 avatar donaldxdonald avatar emekaelo avatar guoxiin avatar halanson avatar huanhuanwa avatar maple13 avatar pubuzhixing8 avatar smnbbrv avatar why520crazy avatar

Stargazers

 avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar

Watchers

 avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar

slate-angular's Issues

Hope to add more details on docs

Hope to add more details on docs

Due to the official docs highly related to react, which it is hard to get started with angular.

So I hope I can get a guide to let us build it from blank to a fully functional rich text editor by using slate-angular.

Inconsistent image behavior between demo site and github?

Is the demo site using a different version than what is in master?

I am trying to implement the image demo in my editor. I can view the image without a problem, but when the user drags the image to a new position, for some reason the image gets converted to the url as text. However, on the demo site, this appears to work just fine. Besides having different names for my components, my code is exactly the same as it appears in components/image/image-component.ts and the demo editor in images/images-component.ts.

If I look at the resulting markup in the browser, I can see some differences.

Demo:

<demo-element-image class="demo-element-image" data-slate-node="element" data-slate-key="52" data-slate-void="true" contenteditable="false"><span data-slate-spacer="true" data-slate-node="text" class="slate-spacer" slatevoidtext="" contenteditable="true"><span data-slate-leaf="true" slatedefaultleaf=""><span editable-text="" data-slate-zero-width="z" data-slate-length="0">&#xFEFF;</span><!----></span></span><img alt="" class="outline" src="https://source.unsplash.com/kFrdX5IeQzI"></demo-element-image>

Mine:

<app-slate-image _nghost-serverapp-c2042657748="" class="app-slate-image ng-star-inserted"><img _ngcontent-serverapp-c2042657748="" alt="" tabindex="1" src="https://source.unsplash.com/kFrdX5IeQzI"></app-slate-image>

Where are the data-slate-node="element" , data-slate-void="true", and contenteditable="false" attributes coming from? What is adding the data-slate-spacer and data-slate-leaf tags? I am extending BaseElementComponent<ImageElement>, but I don't understand why my code is so different than the demo.

编辑器中添加下拉多选/单选框该如何实现?

尝试在编辑器中添加一个下拉选择框,得到以下错误~
想实现的效果是向编辑器添加html表单元素(单选,复选,日期,数字输入框等)请问基于slate-angular该如何实现呢?

`import { ChangeDetectionStrategy, Component, HostListener } from '@angular/core';
import { SelectElement } from '../../../../custom-types';
import { BaseElementComponent } from 'slate-angular';

@component({
selector: 'span[demo-element-select]',
template: <div> <label>Label: </label> <select> <option>option 1</option> <option>option 2</option> <option>option 3</option> </select> <slate-children [children]="children" [context]="childrenContext" [viewContext]="viewContext"></slate-children> </div>,
host: {
class: 'demo-element-select'
},
changeDetection: ChangeDetectionStrategy.OnPush
})
export class DemoElementSelectComponent extends BaseElementComponent {

@HostListener('click', ['$event'])
click(event: MouseEvent) {
    event.preventDefault();
}

}`

image

Slate angular doesn't scroll/keep focus on input text, instead the new input text is below the view.

Issue: When adding new text to the slate angular editor, if the text content exceeds the view (or browser window) the new text is typed below of the view, and in order to see the new text you must manually scroll down (and do this each time the text content goes out the bottom of the view)

Expected: When the newly typed content goes outside of the view, the editor should automatially scroll to keep the cursor and new text in the view.

This is a regression, as this behivour currently works on version: 1.6.3, and no longer works on version: 1.6.4

Here is a demo of the issue, were I have to scroll down to see the newly typed content:
Kapture 2023-03-14 at 13 00 53

from a quick look at commits, it looks like this was done intentionally to fix a table edge case issue: #144

Breaking commit: 2c96187

Can you please bring back scroll into view or some sort of functionallity that replicates it? This is a important feature of the editor to be able to keep the active content in the view.

I'd like to help support and improve Slate-Angular

Hello! I have a large project where I need to invest in a rich text editor and I really appreciate how you've approached SlateJS.

Perhaps your stakeholders would allow me and my engineers to create PRs to bring Slate-Angular up to date with Slate and Angular's latest features?

Regarding Standalone Angular Components

I have already converted the package to standalone Angular components and would like to create a PR for your team to review.

My entire app is standalone and must import standalone components.
As you may know, standalone components are supported within modules. However, without standalone support developers like myself will not be able to use SlateJS.

I have refactored the package and demo app to fully standalone but would need permission on the repo to push.

There is an error regarding packages/src/view/container-item.ts:78 that I would need help with.

ERROR TypeError: componentFactory.create is not a function

Transforms.moveNodes does not work

Hi, I'm trying to use the method Transforms.moveNodes(this.editor, {at: [0], to: [1]}), but it just removes node at destination path from the DOM, but it is still present in editor.children objects.

Getting the location of the current input

Hi @pubuzhixing8

thank you very much for the job you do! It saves others (like me) lots of time.

I faced an issue with implementing the link element:

<ng-template #link let-context="context" let-viewContext="viewContext">
    ...
      <button [contentEditable]="false" type="button" (click)="editLink(context.element, context, viewContext)">
        <fa-icon [icon]="editLinkIcon"></fa-icon>
      </button>
    ...
  </ng-template>

The code above is an adapted version of a react implementation of a link. The key point is editLink(context.element, context, viewContext), where I put literally all what's known about the link at this moment, but still there is no information about the location of this element, that the Transforms can actually do its job. Ideally something like

    const newProperties = {
      url: 'new-url'
    } as Partial<Element>;

    Transforms.setNodes(this.editor, newProperties, { at: 'here-goes-location' });

would be perfect.

Looks like React editor has a corresponding method: ianstormtaylor/slate#3627 (comment)

Is there a way to find the location of the element? Or expose it e.g. as a part of the context? Or, maybe, there is a more valid and correct solution (which I will be very happy to adopt)?

Demo site unavailable

error message ERROR TypeError: Cannot read properties of null (reading 'firstCreatePass')

Spellcheck broken on Firefox

I created a slate editor with spellcheck enabled. But, when clicking on a misspelled word and select correct spelled word from the suggestion list, it will insert the correctly spelled word where the cursor is positionned at instead of replacing the whole word.

Copie d'écran_20240321_111253

Firefox Version: 123.0.1
Slate version: 0.102.0
Slate-Angular version: 16.1.0-next.20

组件引入报错

Angular版本为11.2
npm install slate-angular
app.module.ts引入
import { SlateModule } from 'slate-angular';
imports: [
SlateModule,
],
然后就报了下面的错误

Error: ./node_modules/ngx-Quill/fesm2015/ngx-quill.mjs 1152:48-65
Can't import the named export 'ɵɵsanitizeHtml' from non EcmaScript module (only default export is available)

"angularCompilerOptions": {
"enableIvy": true,
"fullTemplateTypeCheck": true,
"strictInjectionParameters": true
}
ivy开启关闭都试过

Unable to select paragraph with void element with triple-click

As the title explain it, the library doesn't act as expected with the triple click to select all the text in paragraph (all element and text combined). Maybe related to #180 and #186.

Packages Versions:

  • angular: 15.2.10
  • slate: ^0.100.0
  • slate-angular: ^15.1.3

React slate behaviour from the official docs:

Peek.23-11-2023.15-14.mp4

Angular slate behaviour from the official docs:

Peek.23-11-2023.15-15.mp4

Error occur while creating BlockCard

Env

Angular: 13.2.0

Background

I've set the isBlockCard of a block element to true. Then an ASSERTION ERROR was thrown at the init phase. It seems like it is an error of createComponent method in descendant.component.ts.

Error

Console Error
image

Assertion in Source Code
image

Additional information

image
So i guess it would be solved after removing the second and the third null arguments.

Spellcheck blinking

Hi! A few months ago, an update came out in slate-react that solved the problem of a blinking spellcheck when typing. Are there any plans to move this fix into your project, or perhaps some advice on how I could fix this?

Demo with Angular FormGroup

We like to use Slate-Angular in the context of angulars FormGroup. For example to validate a required input field. Something like:

<mat-form-field>
    <slate-editable 
        formControlName="requiredInput"
        required
        [editor]="editor"
        [keydown]="keydown()"
        [renderElement]="renderElement()"
        [renderText]="renderText()"
      >
    <mat-error ngIf="myForm.controls.requiredInput.errors['required']">
        This input is required.
    </mat-error>
</mat-form-field>

Could you add a demo on how to achieve this? Or point me in the right direction and I will provide a PR with a demo.

firefox 全选,直接输入拼音,异常

mac OS firefox v89 访问 http://slate-angular.ngnice.com/
聚焦编辑器,cmd + a 全选,然后直接输入拼音,一直输入不成功。


PS:我也在基于 slate 搞编辑器,也遇到了 firefox (还有 safari ,但我看你们 safari 没问题)的这种全选、输入拼音的坑。如果你们有好的解决方案的话,欢迎回复分享一下。我最近也在持续优化、修改 bug 中。thx ~
image

NPM package License

Hi team!

Could you please add the License type to the npm package you produce?

Or you have your reason to produce without it?

image

I saw that you have it in your git repo.

image

Thank You, and have a nice day!

Confused by setup instructions

I'm trying to use slate-angular for the first time and following the instructions on the home page. I'm confused why "Add Text Mark" step has us include <slate-leaves [context]="context" [viewContext]="viewContext" [viewContext]="viewContext"></slate-leaves> as the template, but in your demo the template is blank. Also, why is [viewContext]="viewContext" in there twice?

[BUG]: decoration not available when using `renderText`

Hi, i'm using slate-angular@14 and i tried to reproduce the text mark component in my project with the following code:

protected renderText = (text: Text) => {
    if (text[MarkType.link] || text[MarkType.strong] || text[MarkType.emphasis]) {
        return TextMarkComponent;
    }
};

But when i try to log the text variables, only the text field show and not the other elements. On the other hand, when using renderLeaf the marks are presents.

Is this behaviour normal ? Is this a bug ? The difference between renderText and renderLeaf aren't very clear because of a lack of documentation about them.


Edit: here is a patch file of the changes i'm trying to make working:

Details

diff --git a/demo/app/components/text/text.component.ts b/demo/app/components/text/text.component.ts
index 24b6cd8..26fc9e0 100644
--- a/demo/app/components/text/text.component.ts
+++ b/demo/app/components/text/text.component.ts
@@ -7,7 +7,8 @@ export enum MarkTypes {
     italic = 'italic',
     underline = 'underlined',
     strike = 'strike',
-    code = 'code-line'
+    code = 'code-line',
+    link = 'link'
 }
 
 @Component({
diff --git a/demo/app/richtext/richtext.component.html b/demo/app/richtext/richtext.component.html
index 8ac0cad..4c16245 100644
--- a/demo/app/richtext/richtext.component.html
+++ b/demo/app/richtext/richtext.component.html
@@ -14,6 +14,7 @@
     (ngModelChange)="valueChange($event)"
     [renderElement]="renderElement"
     [renderText]="renderText"
+    [decorate]="decorate"
     [keydown]="keydown"
     [spellCheck]="true"
   >
diff --git a/demo/app/richtext/richtext.component.ts b/demo/app/richtext/richtext.component.ts
index 0544b34..bd481f4 100644
--- a/demo/app/richtext/richtext.component.ts
+++ b/demo/app/richtext/richtext.component.ts
@@ -1,5 +1,5 @@
 import { Component, ViewChild, TemplateRef, OnInit } from '@angular/core';
-import { createEditor, Text, Editor, Element, Transforms } from 'slate';
+import { createEditor, Text, Editor, Element, Transforms, Selection } from 'slate';
 import { withHistory } from 'slate-history';
 import { withAngular } from 'slate-angular';
 import { DemoTextMarkComponent, MarkTypes } from '../components/text/text.component';
@@ -9,6 +9,7 @@ import { FormsModule } from '@angular/forms';
 import { SlateEditable } from '../../../packages/src/components/editable/editable.component';
 import { DemoButtonComponent } from '../components/button/button.component';
 import { NgFor } from '@angular/common';
+import { findUrlsInText } from './urls';
 
 const SLATE_DEV_MODE_KEY = 'slate-dev';
 
@@ -160,9 +161,7 @@ export class DemoRichtextComponent implements OnInit {
 
     valueChange(event) {
         if (localStorage.getItem(SLATE_DEV_MODE_KEY)) {
-            console.log(
-                `anchor: ${JSON.stringify(this.editor.selection?.anchor)}\nfocus:  ${JSON.stringify(this.editor.selection?.focus)}`
-            );
+            console.log(`anchor: ${JSON.stringify(this.editor.selection?.anchor)}\nfocus:  ${JSON.stringify(this.editor.selection?.focus)}`);
             console.log('operations: ', this.editor.operations);
         }
     }
@@ -193,11 +192,35 @@ export class DemoRichtextComponent implements OnInit {
     };
 
     renderText = (text: Text) => {
-        if (text[MarkTypes.bold] || text[MarkTypes.italic] || text[MarkTypes.code] || text[MarkTypes.underline]) {
+        if (text[MarkTypes.bold] || text[MarkTypes.italic] || text[MarkTypes.code] || text[MarkTypes.underline] || text[MarkTypes.link]) {
             return DemoTextMarkComponent;
         }
     };
 
+    decorate = ([node, path]): Selection[] => {
+        if (!Text.isText(node)) {
+            return [];
+        }
+
+        const nodeText = node.text;
+
+        if (!nodeText) return [];
+
+        const ranges: Selection[] = [];
+
+        const urls = findUrlsInText(nodeText);
+
+        urls.forEach(([url, index]) => {
+            ranges.push({
+                focus: { path, offset: index },
+                anchor: { path, offset: index + url.length },
+                [MarkTypes.link]: true
+            } as Selection);
+        });
+
+        return ranges;
+    };
+
     keydown = (event: KeyboardEvent) => {
         if (isHotkey('shift+enter', event)) {
             event.preventDefault();
diff --git a/demo/editor-typo.scss b/demo/editor-typo.scss
index 896d209..5420a18 100644
--- a/demo/editor-typo.scss
+++ b/demo/editor-typo.scss
@@ -21,6 +21,9 @@
         border-radius: 2px;
         background-color: rgba($color: #000000, $alpha: 0.06);
     }
+    [slate-link] {
+        color: red;
+    }
     blockquote {
         margin: 0;
         margin-left: 0;

Property 'type' does not exist on type 'BaseEditor | BaseElement'.

Hi There

I am getting issues while loading block content. below is my code.

I have added the error I am getting in the code block beside the line I am getting error in.


isBlockActive = (format) => {
        const [match] = Editor.nodes(this.editor, {
            match: (n: Node) => !Editor.isEditor(n) && Element.isElement(n) && n.type === format, //Property 'type' does not exist on type 'BaseElement'.
        })

        return !!match
}
toggleBlock = (format) => {
        const isActive = this.isBlockActive(format)
        const isList = LIST_TYPES.includes(format)

        Transforms.unwrapNodes(this.editor, {
            match: n =>
                LIST_TYPES.includes(Element.isElement(n) && n.type), //  Property 'type' does not exist on type 'BaseEditor | BaseElement'.
            split: true,
        })
        const newProperties: Partial<Element> = {
            type: isActive ? 'paragraph' : isList ? 'list-item' : format, //Type '{ type: any; }' is not assignable to type 'Partial<BaseElement>'
        }
        Transforms.setNodes(this.editor, newProperties)

        if (!isActive && isList) {
            const block = {type: format, children: []}
            Transforms.wrapNodes(this.editor, block)
        }
    }

Upgrade to latest angular and slatejs versions

Could you please upgrade this library to support the latest angular and slate versions? I've tried to provide a pull request, but ran into some issues that I don't know how to resolve.

Thanks!

Undo Redo doesn't work on paragraph with children.

Hello!

I have this object for the initial editor value, given from the official slate example:

initialValue = [
{
      type: 'paragraph',
      children: [
          { text: 'This is editable ' },
          { text: 'rich', bold: true },
          { text: ' text, ' },
          { text: 'much', bold: true, italic: true },
          { text: ' better than a ' },
          { text: '<textarea>' },
          { text: '!' }
      ]
  }
]

When I mark in the editor for example "text, much" and remove it, then press ctrl+z and after it ctrl+y multiple times, more text gets removed then I initially removed ("text, much").

Thank you for possible solutions!

Weird behavior with the android keyboard "Gboard"

Steps to reproduce

  1. Go to http://slate-angular.ngnice.com/images, or any example that you want.
  2. Focus the editor on any word by taping at it.
  3. Double-tap the same word to select the range of the word.

Expected behaviour

The word is selected with its range.

Actual behaviour

Using the Gboard, the word gets duplicated and it is not range-selected, it just mantain the original selection of length 0.

Additional information

  1. This only happens on slate-angular. I could not reproduce it on slate.
  2. It is reproducible on any Android browsers except firefox (but firefox also doesn't range-selects the word).
  3. I tested it on iOS, and it works properly on any browser.

Video reproducing the issue

Screenrecorder-2022-03-25-15-20-15-899.mp4

Support for Angular 15

Angular 15 was released on November 16, 2022. Could you please provide an update for this library to support Angular 15 as well?

Thank you.

Android input issues

Reconsider the input problem of the editor under android, any ideas are welcome.

Recommend Projects

  • React photo React

    A declarative, efficient, and flexible JavaScript library for building user interfaces.

  • Vue.js photo Vue.js

    🖖 Vue.js is a progressive, incrementally-adoptable JavaScript framework for building UI on the web.

  • Typescript photo Typescript

    TypeScript is a superset of JavaScript that compiles to clean JavaScript output.

  • TensorFlow photo TensorFlow

    An Open Source Machine Learning Framework for Everyone

  • Django photo Django

    The Web framework for perfectionists with deadlines.

  • D3 photo D3

    Bring data to life with SVG, Canvas and HTML. 📊📈🎉

Recommend Topics

  • javascript

    JavaScript (JS) is a lightweight interpreted programming language with first-class functions.

  • web

    Some thing interesting about web. New door for the world.

  • server

    A server is a program made to process requests and deliver data to clients.

  • Machine learning

    Machine learning is a way of modeling and interpreting data that allows a piece of software to respond intelligently.

  • Game

    Some thing interesting about game, make everyone happy.

Recommend Org

  • Facebook photo Facebook

    We are working to build community through open source technology. NB: members must have two-factor auth.

  • Microsoft photo Microsoft

    Open source projects and samples from Microsoft.

  • Google photo Google

    Google ❤️ Open Source for everyone.

  • D3 photo D3

    Data-Driven Documents codes.