Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
18 changes: 10 additions & 8 deletions projects/blocks-renderer-angular/src/lib/block/block.html
Original file line number Diff line number Diff line change
Expand Up @@ -4,14 +4,16 @@
<br />
} @else if (isVoidType) {
<!-- Void types don't render children -->
@switch (content.type) {
@let c = content();
@switch (c.type) {
@case ('image') {
<img [src]="content.image.url" [alt]="content.image.alternativeText || ''" />
<img [src]="c.image.url" [alt]="c.image.alternativeText || ''" />
}
}
} @else {
<!-- Render block with children -->
@switch (content.type) {
@let c = content();
@switch (c.type) {
@case ('paragraph') {
<p>
@for (childNode of childrenNodes; track $index) {
Expand Down Expand Up @@ -54,7 +56,7 @@
</pre>
}
@case ('heading') {
@switch (content.level) {
@switch (c.level) {
@case (1) {
<h1>{{ plainText }}</h1>
}
Expand All @@ -76,15 +78,15 @@ <h6>{{ plainText }}</h6>
}
}
@case ('list') {
@if (content.format === 'ordered') {
@if (c.format === 'ordered') {
<ol>
@for (childNode of content.children; track $index) {
@for (childNode of c.children; track $index) {
<lib-block [content]="childNode" />
}
</ol>
} @else {
<ul>
@for (childNode of content.children; track $index) {
@for (childNode of c.children; track $index) {
<lib-block [content]="childNode" />
}
</ul>
Expand All @@ -109,7 +111,7 @@ <h6>{{ plainText }}</h6>
</li>
}
@case ('link') {
<a [href]="content.url">
<a [href]="c.url">
@for (childNode of childrenNodes; track $index) {
@if (childNode.type === 'text') {
<lib-text
Expand Down
4 changes: 2 additions & 2 deletions projects/blocks-renderer-angular/src/lib/block/block.spec.ts
Original file line number Diff line number Diff line change
Expand Up @@ -16,10 +16,10 @@ describe('Block', () => {

fixture = TestBed.createComponent(Block);
component = fixture.componentInstance;
component.content = {
fixture.componentRef.setInput('content', {
type: 'paragraph',
children: [{ type: 'text', text: 'test' }],
} as ParagraphBlockNode;
} as ParagraphBlockNode);
fixture.detectChanges();
await fixture.whenStable();
});
Expand Down
37 changes: 19 additions & 18 deletions projects/blocks-renderer-angular/src/lib/block/block.ts
Original file line number Diff line number Diff line change
@@ -1,9 +1,7 @@
import { Component, Input, inject, OnInit } from '@angular/core';
import { Component, input, inject, OnInit } from '@angular/core';
import { CommonModule } from '@angular/common';
import type { Node, DefaultInlineNode } from '../types';
import {
BlockComponent, ComponentsContextService
} from '../components-context.service';
import { BlockComponent, ComponentsContextService } from '../components-context.service';
import { Text } from '../text/text';

const VOID_TYPES = ['image'];
Expand All @@ -26,45 +24,48 @@ const KNOWN_BLOCK_TYPES = [
standalone: true,
})
export class Block implements OnInit {
@Input() content!: Node;
content = input.required<Node>();

private componentsContext = inject(ComponentsContextService);

get blockComponent(): BlockComponent | undefined {
return this.componentsContext.getBlockComponent(this.content.type);
return this.componentsContext.getBlockComponent(this.content().type);
}

get isKnownType(): boolean {
return (KNOWN_BLOCK_TYPES as readonly string[]).includes(this.content.type);
return (KNOWN_BLOCK_TYPES as readonly string[]).includes(this.content().type);
}

get shouldRender(): boolean {
return !!this.blockComponent || this.isKnownType;
}

get isVoidType(): boolean {
return VOID_TYPES.includes(this.content.type);
return VOID_TYPES.includes(this.content().type);
}

get isEmptyParagraph(): boolean {
const c = this.content();
return (
this.content.type === 'paragraph' &&
this.content.children.length === 1 &&
this.content.children[0].type === 'text' &&
this.content.children[0].text === ''
c.type === 'paragraph' &&
c.children.length === 1 &&
c.children[0].type === 'text' &&
c.children[0].text === ''
);
}

get plainText(): string | undefined {
if (this.content.type === 'code' || this.content.type === 'heading') {
return this.getPlainText(this.content.children);
const c = this.content();
if (c.type === 'code' || c.type === 'heading') {
return this.getPlainText(c.children);
}
return undefined;
}

get blockProps(): any {
const { children, type, ...props } = this.content;
if (this.content.type === 'code' || this.content.type === 'heading') {
const c = this.content();
const { children, type, ...props } = c;
if (c.type === 'code' || c.type === 'heading') {
return {
...props,
plainText: this.plainText,
Expand All @@ -74,7 +75,7 @@ export class Block implements OnInit {
}

get childrenNodes(): DefaultInlineNode[] {
return this.content.children as DefaultInlineNode[];
return this.content().children as DefaultInlineNode[];
}

private getPlainText(children: DefaultInlineNode[]): string {
Expand All @@ -91,7 +92,7 @@ export class Block implements OnInit {

ngOnInit(): void {
if (!this.shouldRender) {
this.componentsContext.addMissingBlockType(this.content.type);
this.componentsContext.addMissingBlockType(this.content().type);
}
}
}
Original file line number Diff line number Diff line change
@@ -1,3 +1,3 @@
@for (block of content; track $index) {
@for (block of content(); track $index) {
<lib-block [content]="block" />
}
Original file line number Diff line number Diff line change
@@ -1,4 +1,4 @@
import { Component, Input, OnInit, inject } from '@angular/core';
import { Component, input, OnInit, inject } from '@angular/core';
import { CommonModule } from '@angular/common';
import type { BlocksContent } from '../types';
import {
Expand All @@ -16,19 +16,19 @@ import { Block } from '../block/block';
providers: [ComponentsContextService],
})
export class BlocksRenderer implements OnInit {
@Input() content!: BlocksContent;
@Input() blocks?: Partial<BlocksComponents>;
@Input() modifiers?: Partial<ModifiersComponents>;
content = input.required<BlocksContent>();
blocks = input<Partial<BlocksComponents>>();
modifiers = input<Partial<ModifiersComponents>>();

private componentsContext = inject(ComponentsContextService);

ngOnInit(): void {
const blocks: BlocksComponents = {
...(this.blocks as BlocksComponents),
...(this.blocks() as BlocksComponents),
};

const modifiers: ModifiersComponents = {
...(this.modifiers as ModifiersComponents),
...(this.modifiers() as ModifiersComponents),
};

this.componentsContext.setContext({
Expand Down
2 changes: 1 addition & 1 deletion projects/blocks-renderer-angular/src/lib/text/text.spec.ts
Original file line number Diff line number Diff line change
Expand Up @@ -15,7 +15,7 @@ describe('Text', () => {

fixture = TestBed.createComponent(Text);
component = fixture.componentInstance;
component.text = 'test';
fixture.componentRef.setInput('text', 'test');
fixture.detectChanges();
await fixture.whenStable();
});
Expand Down
26 changes: 13 additions & 13 deletions projects/blocks-renderer-angular/src/lib/text/text.ts
Original file line number Diff line number Diff line change
@@ -1,4 +1,4 @@
import { Component, Input, inject } from '@angular/core';
import { Component, input, inject } from '@angular/core';
import { CommonModule } from '@angular/common';
import { DomSanitizer, SafeHtml } from '@angular/platform-browser';
import type { Modifier } from '../types';
Expand All @@ -11,28 +11,28 @@ import { ComponentsContextService } from '../components-context.service';
standalone: true,
})
export class Text {
@Input() text!: string;
@Input() bold?: boolean;
@Input() italic?: boolean;
@Input() underline?: boolean;
@Input() strikethrough?: boolean;
@Input() code?: boolean;
text = input.required<string>();
bold = input<boolean>();
italic = input<boolean>();
underline = input<boolean>();
strikethrough = input<boolean>();
code = input<boolean>();

private componentsContext = inject(ComponentsContextService);
private sanitizer = inject(DomSanitizer);

get modifiers(): Modifier[] {
const mods: Modifier[] = [];
if (this.bold) mods.push('bold');
if (this.italic) mods.push('italic');
if (this.underline) mods.push('underline');
if (this.strikethrough) mods.push('strikethrough');
if (this.code) mods.push('code');
if (this.bold()) mods.push('bold');
if (this.italic()) mods.push('italic');
if (this.underline()) mods.push('underline');
if (this.strikethrough()) mods.push('strikethrough');
if (this.code()) mods.push('code');
return mods;
}

get textParts(): string[] {
return this.text.split(/\r?\n|\r/g);
return this.text().split(/\r?\n|\r/g);
}

getModifierComponent(modifierName: Modifier): any {
Expand Down