Block Helpers

Utilities for working with CMS content blocks

The block utilities help you work with CMS content blocks.

Importing

import { blocks } from 'arky-sdk/utils';

Finding Blocks

Find Block by Type

const heroBlock = blocks.findByType(node.blocks, 'HERO');

if (heroBlock) {
  console.log(heroBlock.content.title);
}

Find All Blocks of Type

const textBlocks = blocks.findAllByType(node.blocks, 'TEXT');

textBlocks.forEach(block => {
  console.log(block.content.body);
});

Extracting Content

Get First Image

const image = blocks.getFirstImage(node.blocks);
// Returns: { url: '...', alt: '...' } or null

Get All Images

const images = blocks.getAllImages(node.blocks);
// Returns array of { url, alt, caption }

Get Text Content

// Get all text as plain string
const plainText = blocks.getPlainText(node.blocks);

// Get excerpt (first N characters)
const excerpt = blocks.getExcerpt(node.blocks, 150);

Block Rendering

Create Block Component Map

const blockComponents = {
  HERO: HeroBlock,
  TEXT: TextBlock,
  IMAGE: ImageBlock,
  CODE: CodeBlock,
  CTA: CTABlock,
  GALLERY: GalleryBlock,
  QUOTE: QuoteBlock
};

function renderBlocks(blockList: Block[]) {
  return blockList.map((block, index) => {
    const Component = blockComponents[block.type];
    if (!Component) return null;
    return <Component key={index} content={block.content} />;
  });
}

Block Validation

// Check if block is valid
const isValid = blocks.isValid(block);

// Validate all blocks
const invalidBlocks = node.blocks.filter(b => !blocks.isValid(b));
if (invalidBlocks.length > 0) {
  console.warn('Invalid blocks found:', invalidBlocks);
}

Block Manipulation

Add Block

const updatedBlocks = blocks.add(node.blocks, {
  type: 'TEXT',
  content: { body: 'New paragraph' }
});

Insert Block at Position

const updatedBlocks = blocks.insertAt(node.blocks, 2, {
  type: 'IMAGE',
  content: { url: 'media_123', alt: 'Photo' }
});

Remove Block

const updatedBlocks = blocks.remove(node.blocks, 3);

Move Block

const updatedBlocks = blocks.move(node.blocks, 1, 4);

Update Block

const updatedBlocks = blocks.update(node.blocks, 0, {
  ...node.blocks[0],
  content: {
    ...node.blocks[0].content,
    title: 'Updated Title'
  }
});

Block Schemas

Get Schema for Block Type

const heroSchema = blocks.getSchema('HERO');
// Returns: { type: 'HERO', fields: [...], required: [...] }

Validate Against Schema

const errors = blocks.validateBlock(block, blocks.getSchema(block.type));
if (errors.length > 0) {
  console.error('Validation errors:', errors);
}

Common Patterns

Create Blog Post Blocks

function createBlogPostBlocks(data: {
  title: string;
  image: string;
  content: string;
  cta?: { text: string; url: string };
}) {
  const blockList: Block[] = [
    {
      type: 'HERO',
      content: {
        title: data.title,
        image: data.image
      }
    },
    {
      type: 'TEXT',
      content: {
        body: data.content
      }
    }
  ];

  if (data.cta) {
    blockList.push({
      type: 'CTA',
      content: {
        text: data.cta.text,
        url: data.cta.url,
        style: 'primary'
      }
    });
  }

  return blockList;
}

Convert Markdown to Blocks

function markdownToBlocks(markdown: string): Block[] {
  const sections = markdown.split(/\n\n+/);

  return sections.map(section => {
    // Check for headings
    if (section.startsWith('# ')) {
      return {
        type: 'HERO',
        content: { title: section.replace('# ', '') }
      };
    }

    // Check for code blocks
    if (section.startsWith('```')) {
      const match = section.match(/```(\w+)?\n([\s\S]*?)```/);
      if (match) {
        return {
          type: 'CODE',
          content: {
            language: match[1] || 'text',
            code: match[2]
          }
        };
      }
    }

    // Check for blockquotes
    if (section.startsWith('> ')) {
      return {
        type: 'QUOTE',
        content: { text: section.replace(/^> /gm, '') }
      };
    }

    // Default to text
    return {
      type: 'TEXT',
      content: { body: section }
    };
  });
}