Skip to content

Commit

Permalink
fix(list-render): support custom elements to set the position of chil…
Browse files Browse the repository at this point in the history
…dren elements
  • Loading branch information
pubuzhixing8 committed Jan 12, 2024
1 parent 214bc20 commit 834aa0c
Show file tree
Hide file tree
Showing 17 changed files with 327 additions and 103 deletions.
5 changes: 5 additions & 0 deletions .changeset/calm-jokes-shout.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,5 @@
---
'slate-angular': patch
---

support custom elements to set the position of children elements
Original file line number Diff line number Diff line change
@@ -1,21 +1,21 @@
import { ChangeDetectionStrategy, Component, HostListener } from '@angular/core';
import { ButtonElement } from '../../../../custom-types';
import { BaseElementComponent } from 'slate-angular';
import { SlateChildren } from '../../../../packages/src/components/children/children.component';
import { SlateChildrenOutlet } from '../../../../packages/src/components/children/children-outlet.component';

@Component({
selector: 'span[demo-element-button]',
template: `
<span contenteditable="false" style="font-size: 0;">{{ inlineChromiumBugfix }}</span>
<slate-children [children]="children" [context]="childrenContext" [viewContext]="viewContext"></slate-children>
<slate-children-outlet></slate-children-outlet>
<span contenteditable="false" style="font-size: 0;">{{ inlineChromiumBugfix }}</span>
`,
host: {
class: 'demo-element-button'
},
changeDetection: ChangeDetectionStrategy.OnPush,
standalone: true,
imports: [SlateChildren]
imports: [SlateChildrenOutlet]
})
export class DemoElementEditableButtonComponent extends BaseElementComponent<ButtonElement> {
// Put this at the start and end of an inline component to work around this Chromium bug:
Expand Down
6 changes: 3 additions & 3 deletions demo/app/components/link/link.component.ts
Original file line number Diff line number Diff line change
@@ -1,18 +1,18 @@
import { ChangeDetectionStrategy, Component, HostBinding, HostListener } from '@angular/core';
import { LinkElement } from 'custom-types';
import { BaseElementComponent } from 'slate-angular';
import { SlateChildren } from '../../../../packages/src/components/children/children.component';
import { SlateChildrenOutlet } from '../../../../packages/src/components/children/children-outlet.component';

@Component({
selector: 'a[demo-element-link]',
template: `
<span contenteditable="false" style="font-size: 0;">{{ inlineChromiumBugfix }}</span>
<slate-children [children]="children" [context]="childrenContext" [viewContext]="viewContext"></slate-children>
<slate-children-outlet></slate-children-outlet>
<span contenteditable="false" style="font-size: 0;">{{ inlineChromiumBugfix }}</span>
`,
changeDetection: ChangeDetectionStrategy.OnPush,
standalone: true,
imports: [SlateChildren]
imports:[SlateChildrenOutlet]
})
export class DemoElementLinkComponent extends BaseElementComponent<LinkElement> {
// Put this at the start and end of an inline component to work around this Chromium bug:
Expand Down
14 changes: 14 additions & 0 deletions packages/src/components/children/children-outlet.component.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,14 @@
import { ChangeDetectionStrategy, Component, ElementRef } from '@angular/core';

@Component({
selector: 'slate-children-outlet',
template: ``,
changeDetection: ChangeDetectionStrategy.OnPush,
standalone: true
})
export class SlateChildrenOutlet {
constructor(private elementRef: ElementRef<HTMLElement>) {}
getNativeElement() {
return this.elementRef.nativeElement;
}
}
3 changes: 1 addition & 2 deletions packages/src/components/children/children.component.ts
Original file line number Diff line number Diff line change
Expand Up @@ -8,8 +8,7 @@ import { NgFor } from '@angular/common';
selector: 'slate-children',
template: ``,
changeDetection: ChangeDetectionStrategy.OnPush,
standalone: true,
imports: [NgFor]
standalone: true
})
export class SlateChildren extends ViewContainer<any> {
@Input() children: Descendant[];
Expand Down
2 changes: 1 addition & 1 deletion packages/src/components/editable/editable.component.html
Original file line number Diff line number Diff line change
@@ -1 +1 @@
<slate-string-template #templateComponent></slate-string-template>
<slate-string-template #templateComponent></slate-string-template>
10 changes: 5 additions & 5 deletions packages/src/components/editable/editable.component.ts
Original file line number Diff line number Diff line change
Expand Up @@ -68,6 +68,7 @@ import { SlateDefaultLeaf } from '../leaf/default-leaf.component';
import { SLATE_DEFAULT_LEAF_COMPONENT_TOKEN } from '../leaf/token';
import { BaseElementComponent, BaseLeafComponent, BaseTextComponent } from '../../view/base';
import { ListRender } from '../../view/render/list-render';
import { SlateChildrenOutlet } from '../children/children-outlet.component';

// not correctly clipboardData on beforeinput
const forceOnDOMPaste = IS_SAFARI;
Expand Down Expand Up @@ -108,7 +109,7 @@ const forceOnDOMPaste = IS_SAFARI;
}
],
standalone: true,
imports: [SlateChildren, SlateStringTemplate]
imports: [SlateChildren, SlateStringTemplate, SlateChildrenOutlet]
})
export class SlateEditable implements OnInit, OnChanges, OnDestroy, AfterViewChecked, DoCheck {
viewContext: SlateViewContext;
Expand Down Expand Up @@ -191,7 +192,7 @@ export class SlateEditable implements OnInit, OnChanges, OnDestroy, AfterViewChe

viewContainerRef = inject(ViewContainerRef);

getOutletElement = () => {
getOutletParent = () => {
return this.elementRef.nativeElement;
};

Expand All @@ -211,8 +212,7 @@ export class SlateEditable implements OnInit, OnChanges, OnDestroy, AfterViewChe
public defaultVoidText: ComponentType<BaseTextComponent>,
@Inject(SLATE_DEFAULT_LEAF_COMPONENT_TOKEN)
public defaultLeaf: ComponentType<BaseLeafComponent>
) {
}
) {}

ngOnInit() {
this.editor.injector = this.injector;
Expand Down Expand Up @@ -240,7 +240,7 @@ export class SlateEditable implements OnInit, OnChanges, OnDestroy, AfterViewChe
// add browser class
let browserClass = IS_FIREFOX ? 'firefox' : IS_SAFARI ? 'safari' : '';
browserClass && this.elementRef.nativeElement.classList.add(browserClass);
this.listRender = new ListRender(this.viewContext, this.viewContainerRef, this.getOutletElement);
this.listRender = new ListRender(this.viewContext, this.viewContainerRef, this.getOutletParent, () => null);
}

ngOnChanges(simpleChanges: SimpleChanges) {
Expand Down
5 changes: 4 additions & 1 deletion packages/src/module.ts
Original file line number Diff line number Diff line change
Expand Up @@ -8,6 +8,7 @@ import { SlateDefaultElement } from './components/element/default-element.compon
import { SlateString } from './components/string/string.component';
import { SlateStringTemplate } from './components/string/template.component';
import { SlateChildren } from './components/children/children.component';
import { SlateChildrenOutlet } from './components/children/children-outlet.component';
import { SlateBlockCard } from './components/block-card/block-card.component';
import { SlateDefaultLeaf } from './components/leaf/default-leaf.component';
import { SlateLeaves } from './components/leaves/leaves.component';
Expand All @@ -28,11 +29,13 @@ import { SlateDefaultString } from './components/string/default-string.component
SlateBlockCard,
SlateLeaves,
SlateDefaultLeaf,
SlateDefaultString
SlateDefaultString,
SlateChildrenOutlet
],
exports: [
SlateEditable,
SlateChildren,
SlateChildrenOutlet,
SlateElement,
SlateLeaves,
SlateString,
Expand Down
2 changes: 1 addition & 1 deletion packages/src/testing/create-document.ts
Original file line number Diff line number Diff line change
Expand Up @@ -15,7 +15,7 @@ export function createDefaultDocument() {
];
}

export function createMutipleParagraph() {
export function createMultipleParagraph() {
return [
{
type: 'paragraph',
Expand Down
68 changes: 68 additions & 0 deletions packages/src/testing/editable-with-outlet.component.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,68 @@
import { Component, ViewChild } from '@angular/core';
import { createEditor, Element } from 'slate';
import { SlateEditable } from '../components/editable/editable.component';
import { withAngular } from '../plugins/with-angular';
import { SlateChildrenOutlet } from '../components/children/children-outlet.component';
import { BaseElementComponent } from '../view/base';

const customType = 'custom-with-outlet';

@Component({
selector: 'editable-with-outlet',
template: `<slate-editable
[editor]="editor"
[(ngModel)]="value"
(ngModelChange)="ngModelChange()"
[renderElement]="renderElement()"
></slate-editable> `
})
export class EditableWithOutletComponent {
editor = withAngular(createEditor());

value: Element[] = createDefaultDocument() as Element[];

@ViewChild(SlateEditable, { static: true })
editableComponent: SlateEditable;

renderElement() {
return (element: Element) => {
if ((element.type as any) === customType) {
return TestElementWithOutletComponent;
}
return null;
};
}

ngModelChange() {}

constructor() {}
}

export function createDefaultDocument() {
return [
{
type: customType,
children: [
{
type: 'paragraph',
children: [{ text: 'This is editable text!' }]
}
]
}
];
}

@Component({
selector: 'div[test-element-with-outlet]',
template: `
<div>before</div>
<slate-children-outlet></slate-children-outlet>
<div>after</div>
`,
host: {
class: 'test-element-with-outlet'
},
standalone: true,
imports: [SlateChildrenOutlet]
})
export class TestElementWithOutletComponent extends BaseElementComponent<any> {}
1 change: 1 addition & 0 deletions packages/src/testing/index.ts
Original file line number Diff line number Diff line change
Expand Up @@ -5,4 +5,5 @@ export * from './module';
export * from './basic-editable.component';
export * from './advanced-editable.component';
export * from './image-editable.component';
export * from './editable-with-outlet.component';
export * from './leaf.component';
42 changes: 37 additions & 5 deletions packages/src/view/base.ts
Original file line number Diff line number Diff line change
@@ -1,4 +1,15 @@
import { ChangeDetectorRef, Directive, ElementRef, HostBinding, Input, OnDestroy, OnInit, ViewContainerRef, inject } from '@angular/core';
import {
ChangeDetectorRef,
Directive,
ElementRef,
HostBinding,
Input,
OnDestroy,
OnInit,
ViewChild,
ViewContainerRef,
inject
} from '@angular/core';
import { AngularEditor } from '../plugins/angular-editor';
import { ELEMENT_TO_COMPONENT, ELEMENT_TO_NODE, NODE_TO_ELEMENT } from '../utils/weak-maps';
import { SlateViewContext, SlateElementContext, SlateTextContext, SlateLeafContext } from './context';
Expand All @@ -7,6 +18,7 @@ import { SlateChildrenContext } from './context';
import { hasAfterContextChange, hasBeforeContextChange } from './context-change';
import { ListRender } from './render/list-render';
import { LeavesRender } from './render/leaves-render';
import { SlateChildrenOutlet } from 'slate-angular/components/children/children-outlet.component';

/**
* base class for template
Expand Down Expand Up @@ -140,6 +152,9 @@ export class BaseElementComponent<T extends Element = Element, K extends Angular

childrenContext: SlateChildrenContext;

@ViewChild(SlateChildrenOutlet, { static: true })
childrenOutletInstance?: SlateChildrenOutlet;

get element(): T {
return this._context && this._context.element;
}
Expand Down Expand Up @@ -168,18 +183,25 @@ export class BaseElementComponent<T extends Element = Element, K extends Angular
return this._context && this._context.readonly;
}

getOutletElement = () => {
getOutletParent = () => {
return this.elementRef.nativeElement;
};

getOutletElement = () => {
if (this.childrenOutletInstance) {
return this.childrenOutletInstance.getNativeElement();
}
return null;
};

listRender: ListRender;

ngOnInit() {
for (const key in this._context.attributes) {
this.nativeElement.setAttribute(key, this._context.attributes[key]);
}
this.initialized = true;
this.listRender = new ListRender(this.viewContext, this.viewContainerRef, this.getOutletElement);
this.listRender = new ListRender(this.viewContext, this.viewContainerRef, this.getOutletParent, this.getOutletElement);
this.listRender.initialize(this.children, this.element, this.childrenContext);
}

Expand Down Expand Up @@ -231,13 +253,23 @@ export class BaseTextComponent<T extends Text = Text> extends BaseComponent<Slat

leavesRender: LeavesRender;

getOutletElement = () => {
@ViewChild(SlateChildrenOutlet, { static: true })
childrenOutletInstance?: SlateChildrenOutlet;

getOutletParent = () => {
return this.elementRef.nativeElement;
};

getOutletElement = () => {
if (this.childrenOutletInstance) {
return this.childrenOutletInstance.getNativeElement();
}
return null;
};

ngOnInit() {
this.initialized = true;
this.leavesRender = new LeavesRender(this.viewContext, this.viewContainerRef, this.getOutletElement);
this.leavesRender = new LeavesRender(this.viewContext, this.viewContainerRef, this.getOutletParent, this.getOutletElement);
this.leavesRender.initialize(this.context);
}

Expand Down
65 changes: 0 additions & 65 deletions packages/src/view/container.spec.ts

This file was deleted.

Loading

0 comments on commit 834aa0c

Please sign in to comment.