Skip to content

Commit

Permalink
feat: introducing rsc-compatible image block (#835)
Browse files Browse the repository at this point in the history
  • Loading branch information
nicholasio authored Aug 6, 2024
1 parent b09b696 commit 915c6b6
Show file tree
Hide file tree
Showing 12 changed files with 110 additions and 37 deletions.
6 changes: 6 additions & 0 deletions .changeset/poor-donkeys-march.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,6 @@
---
"@headstartwp/core": minor
"@headstartwp/next": minor
---

RSC compatible image block for next.js
30 changes: 15 additions & 15 deletions package-lock.json

Some generated files are not rendered by default. Learn more about how customized files appear on GitHub.

1 change: 1 addition & 0 deletions packages/core/src/dom/index.ts
Original file line number Diff line number Diff line change
Expand Up @@ -343,3 +343,4 @@ export function isBlockByName(node: DOMNode, name: string) {

export * from './wpKsesPost';
export * from './stripTags';
export * from './parseBlockAttributes';
2 changes: 2 additions & 0 deletions packages/core/src/dom/parseBlockAttributes.ts
Original file line number Diff line number Diff line change
Expand Up @@ -12,6 +12,8 @@ export const DEFAULT_BLOCK_ELEMENT = new Element('div', {
'data-wp-block-name': BLOCK_MISSING,
});

export const defaultElement = DEFAULT_BLOCK_ELEMENT;

/**
* Parses Json without throwing errors
*
Expand Down
22 changes: 7 additions & 15 deletions packages/core/src/react/blocks/ImageBlock.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -2,7 +2,7 @@

import { Element } from 'html-react-parser';
import { isBlockByName } from '../../dom';
import { IBlock } from '../components';
import { BlockFC, IBlock } from '../components';
import { useBlock } from './hooks';
import { useBlockAttributes } from './hooks/useBlockAttributes';
import { IBlockAttributes } from './types';
Expand All @@ -19,12 +19,12 @@ export interface ImageBlockProps extends IBlockAttributes {

export interface IImageBlock extends IBlock<ImageBlockProps> {}

export function ImageBlock({
export const ImageBlock: BlockFC<IBlock<ImageBlockProps>> = ({
domNode: node = DEFAULT_BLOCK_ELEMENT,
children,
component: Component,
style,
}: IImageBlock) {
}: IImageBlock) => {
const { name, className, attributes } = useBlock<ImageBlockProps>(node);
const blockAttributes = useBlockAttributes(node);

Expand Down Expand Up @@ -62,16 +62,8 @@ export function ImageBlock({
{children}
</Component>
);
}
};

/**
* @internal
*/
// eslint-disable-next-line no-redeclare
export namespace ImageBlock {
export const defaultProps = {
test: (node) => {
return isBlockByName(node, 'core/image');
},
};
}
ImageBlock.test = (node) => {
return isBlockByName(node, 'core/image');
};
3 changes: 0 additions & 3 deletions packages/core/src/react/blocks/types.ts
Original file line number Diff line number Diff line change
@@ -1,6 +1,5 @@
import { Element } from 'html-react-parser';
import { ReactNode } from 'react';
import { IDataWPBlock } from '../../dom/parseBlockAttributes';

export interface Colors {
backgroundColorSlug: string;
Expand Down Expand Up @@ -88,8 +87,6 @@ export interface IBlockAttributes {
};
}

export type { IDataWPBlock };

export interface BlockAttributes extends Colors {
align: Align;
style: Partial<Style>;
Expand Down
1 change: 1 addition & 0 deletions packages/core/src/react/index.ts
Original file line number Diff line number Diff line change
Expand Up @@ -3,3 +3,4 @@ export * from './provider';
export * from './hooks';
export * from './blocks';
export * from './utils';
export * from '../dom';
2 changes: 1 addition & 1 deletion packages/next/src/components/ImageComponent.tsx
Original file line number Diff line number Diff line change
@@ -1,6 +1,6 @@
import NextImageComponent from 'next/image.js';
import type { ImageLoaderProps } from 'next/image.js';
import { ImageBlockProps } from '@headstartwp/core/react';
import type { ImageBlockProps } from '@headstartwp/core/react';

// See error in https://github.com/vercel/next.js/issues/54777
const Image =
Expand Down
67 changes: 67 additions & 0 deletions packages/next/src/rsc/blocks/ImageBlock.tsx
Original file line number Diff line number Diff line change
@@ -0,0 +1,67 @@
import { domToReact, Element, isBlockByName } from '@headstartwp/core';
import { BlockFC, BlockProps } from '@headstartwp/core/react';
import { ImageComponent } from '../../components/ImageComponent';

type ImageBlockAttributes = {
width?: number;
height?: number;
sizeSlug?: string;
linkDestination?: string;
src: string;
alt?: string;
};

export const ImageBlock: BlockFC<BlockProps<ImageBlockAttributes>> = ({
domNode: node,
children,
style,
block,
}) => {
if (typeof node === 'undefined') {
return null;
}

if (typeof block === 'undefined') {
return domToReact([node]);
}

const { name, className, attributes } = block;

const hasFigureNode = (node.firstChild as Element).name === 'figure';

const { width, height } = attributes;
let imgNode;

if (hasFigureNode) {
const figureNode = node.children[0] as Element;

if (figureNode.children[0]) {
imgNode = figureNode.children[0] as Element;
}
} else {
imgNode = node.children[0] as Element;
}

const { src, alt, width: imgNodeWidth, height: imgNodeHeight } = imgNode.attribs;
const imageWidth = width ?? imgNodeWidth;
const imageHeight = height ?? imgNodeHeight;

return (
<ImageComponent
name={name}
domNode={node}
className={className}
src={src}
alt={alt}
width={imageWidth ? Number(imageWidth) : undefined}
height={imageHeight ? Number(imageHeight) : undefined}
style={style}
>
{children}
</ImageComponent>
);
};

ImageBlock.test = (node) => {
return isBlockByName(node, 'core/image');
};
8 changes: 6 additions & 2 deletions packages/next/src/rsc/blocks/LinkBlock.tsx
Original file line number Diff line number Diff line change
@@ -1,7 +1,7 @@
import Link from 'next/link.js';
import { removeSourceUrl } from '@headstartwp/core/utils';
import { BlockFC, BlockProps, IDataWPBlock } from '@headstartwp/core/react';
import { getAttributes, isAnchorTag } from '@headstartwp/core';
import { domToReact, getAttributes, isAnchorTag } from '@headstartwp/core';
import React from 'react';

interface LinkBlockProps extends BlockProps<IDataWPBlock> {
Expand Down Expand Up @@ -31,8 +31,12 @@ interface LinkBlockProps extends BlockProps<IDataWPBlock> {
* @category React Components
*/
export const LinkBlock: BlockFC<LinkBlockProps> = ({ domNode, children, blockContext }) => {
if (typeof domNode === 'undefined') {
return null;
}

if (typeof blockContext?.settings === 'undefined') {
return children;
return domToReact([domNode]);
}

const { settings } = blockContext;
Expand Down
1 change: 1 addition & 0 deletions packages/next/src/rsc/index.ts
Original file line number Diff line number Diff line change
Expand Up @@ -15,3 +15,4 @@ export * from './components/HeadstartWPApp';
// blocks
export * from './blocks/LinkBlock';
export * from '../blocks/TwitterBlock';
export * from './blocks/ImageBlock';
4 changes: 3 additions & 1 deletion projects/wp-nextjs-app/src/components/Blocks.tsx
Original file line number Diff line number Diff line change
@@ -1,7 +1,8 @@
import { BlocksRenderer } from '@headstartwp/core/react';
import React from 'react';
import { HeadlessConfig, isBlockByName } from '@headstartwp/core';
import { LinkBlock, TwitterBlock } from '@headstartwp/next/app';
import { ImageBlock, LinkBlock, TwitterBlock } from '@headstartwp/next/app';

import { PostList } from './Blocks/PostList';

type BlockProps = {
Expand All @@ -15,6 +16,7 @@ const Blocks: React.FC<BlockProps> = ({ html, settings }) => {
// the settings is automatically passed to the children components via blockContext
return (
<BlocksRenderer forwardBlockAttributes html={html} settings={settings}>
<ImageBlock />
<PostList test={(node) => isBlockByName(node, 'core/query')} />
<TwitterBlock />
<LinkBlock />
Expand Down

0 comments on commit 915c6b6

Please sign in to comment.