2

I want to show my custom styling for some built-in blocks in my project's Storybook instance. I have it working great for simple blocks. To show the Paragraph block, I do this:

Paragraph.stories.jsx:

import ParagraphBlock from '@wordpress/block-library/build-module/paragraph/save';
import templateFromBlock from './templateFromWordPressBlock';

export default {
  title: 'Default/Paragraph',
  component: ParagraphBlock,
  argTypes: {
    attributes: {
      control: 'object'
    },
  },
  parameters: {
    layout: 'padded',
  },
};

const Template = templateFromBlock('paragraph', ParagraphBlock);

export const Paragraph = Template.bind({});

Paragraph.args = {
  attributes: {
    content: 'Lorem ipsum dolor sit amet, <em>consectetur adipisicing elit</em>, sed do <strong>eiusmod tempor incididunt</strong> ut labore et dolore magna aliqua. <a href="https://google.com">Ut enim ad minim</a> veniam, quis nostrud exercitation ullamco laboris nisi ut aliquip ex ea commodo consequat. Duis aute irure dolor in reprehenderit in voluptate velit esse cillum dolore eu fugiat nulla pariatur. Excepteur sint occaecat cupidatat non proident, sunt in culpa qui officia deserunt mollit anim id est laborum.',
  }
};

templateFromWordPressBlock.js:

// The getSaveElement technique is courtesy of https://github.com/WordPress/gutenberg/issues/37988.
import { getSaveElement } from '@wordpress/blocks';
import { renderToString, RawHTML } from '@wordpress/element';
import '../../../../../wp-includes/css/classic-themes.min.css';
import '../../../../../wp-includes/css/dist/block-library/style.css';
import '../../../../themes/my-theme/src/style.scss';

export const blockContent = (name, Block, args) => {
  getSaveElement({ name: name, save: Block }, args.attributes);
  return <RawHTML>{renderToString(<Block {...args} />)}</RawHTML>;
};

export default (name, Block) => {
  return args => {
    return blockContent(name, Block, args);
  };
};

It works!

Storybook rendering a Paragraph block with my own content and styles

However, this falls down when using a block with InnerBlocks, such as the Quote block. I have tried a few different ways of passing children to the Quote block's save component, but none of them did anything good. The Citation shows up, since it's entirely based on attributes; but I've never gotten a single character to render where the InnerBlocks go.

I gather that the InnerBlocks component expects to have a Redux store or some other data source to pull InnerBlocks data from, not just props/attributes on the component/block. I am currently looking to see what the developer of BlockBook did before abandoning the project, but it's a bit of a rabbit hole, so I thought I'd ask, in case it ends up being faster: How can I provide a block's InnerBlocks without scaffolding the entire block editor?

1 Answer 1

1

It was a long and winding road that led me to a working solution, which doesn't resemble my above attempts very closely at all. In short: instead of importing the Save component by itself, you run the registration functions from the root JS file of the blocks, and then use createBlock and serialize. The full solution for a Quote block with a Paragraph inner block in Storybook follows:

import { RawHTML } from '@wordpress/element';
import { createBlock, serialize } from '@wordpress/blocks';

// Core blocks come with handy init functions that handle all registration and metadata tasks for you.
import { init as paragraphInit } from '@wordpress/block-library/build-module/paragraph';
import { init as quoteInit }  from '@wordpress/block-library/build-module/quote';

// Run ’em!
paragraphInit();
quoteInit();

const Template = args => {
  // createBlock creates a block given the block name, attributes, and optional InnerBlocks.
  const block = createBlock(
    'core/quote',
    args.attributes,
    args.innerBlocks,
  );

  // Now we turn our parsed block into HTML.
  const serializedBlock = serialize(block);

  // “Unsafely” output our serialized block.
  return (
    <RawHTML>
      {serializedBlock}
    </RawHTML>
  );
};

export const Blockquote = Template.bind({});

Blockquote.args = {
  attributes: {
    citation: 'Time Magazine, August 2027',
    value: 'Something',
  },
  innerBlocks: [
    // Provide the InnerBlocks without serializing them.
    createBlock(
      'core/paragraph',
      {
        content: 'Lorem ipsum dolor <em>sit amet</em>',
      }
    )
  ]
};

export default {
  title: 'Default/Blockquote',
  argTypes: {
    attributes: {
      control: 'object'
    },
    innerBlocks: {
      control: 'object'
    }
  },
  parameters: {
    layout: 'padded',
  },
};

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service and acknowledge you have read our privacy policy.

Not the answer you're looking for? Browse other questions tagged or ask your own question.