CtrlK
CommunityDocumentationLog inGet started
Tessl Logo

tessl/npm-remirror--react

Hooks and components for consuming remirror with your fave framework React.

Overall
score

36%

Evaluation36%

1.09x

Agent success when using this tile

Overview
Eval results
Files

content-rendering.mddocs/

Content Rendering

JSON-to-React rendering system for displaying editor content as React components with customizable handlers.

Capabilities

RemirrorRenderer Component

Main component for rendering Remirror JSON content as React components.

/**
 * Main recursive JSON-to-React renderer for displaying editor content
 */
interface RemirrorRenderer extends React.Component<RemirrorRendererProps> {}

interface RemirrorRendererProps {
  /** Remirror JSON document to render */
  json: RemirrorJSON;
  /** Custom type mapping for nodes and marks */
  typeMap?: Record<string, ComponentType>;
  /** Custom mark mapping */
  markMap?: MarkMap;
  /** Additional props to pass to rendered components */
  componentProps?: Record<string, any>;
  /** Error boundary component */
  errorBoundary?: ComponentType<{ error: Error; children: React.ReactNode }>;
}

interface RemirrorJSON {
  /** Document type */
  type: 'doc';
  /** Document content nodes */
  content?: RemirrorJSONNode[];
  /** Document attributes */
  attrs?: Record<string, any>;
}

interface RemirrorJSONNode {
  /** Node type */
  type: string;
  /** Node content */
  content?: RemirrorJSONNode[];
  /** Node attributes */
  attrs?: Record<string, any>;
  /** Node marks */
  marks?: RemirrorJSONMark[];
  /** Text content (for text nodes) */
  text?: string;
}

interface RemirrorJSONMark {
  /** Mark type */
  type: string;
  /** Mark attributes */
  attrs?: Record<string, any>;
}

Usage Example:

import React from 'react';
import { RemirrorRenderer } from '@remirror/react';

// Sample Remirror JSON content
const sampleContent = {
  type: 'doc',
  content: [
    {
      type: 'paragraph',
      content: [
        {
          type: 'text',
          text: 'Hello ',
        },
        {
          type: 'text',
          text: 'world',
          marks: [{ type: 'bold' }],
        },
        {
          type: 'text',
          text: '!',
        },
      ],
    },
  ],
};

function ContentViewer() {
  return (
    <div>
      <h2>Rendered Content:</h2>
      <RemirrorRenderer json={sampleContent} />
    </div>
  );
}

Doc Component

Document root renderer component for complete documents.

/**
 * Document root renderer component for complete document rendering
 */
interface Doc extends React.Component<DocProps> {}

interface DocProps {
  /** Remirror JSON document */
  json: RemirrorJSON;
  /** Document-level attributes */
  attributes?: Record<string, any>;
  /** Custom document wrapper component */
  wrapper?: ComponentType<{ children: React.ReactNode }>;
}

Content Handlers

Specialized components for rendering different types of content.

/**
 * Handler for rendering callout blocks
 */
interface Callout extends React.Component<CalloutProps> {}

interface CalloutProps {
  /** Callout type/variant */
  type?: 'info' | 'warning' | 'error' | 'success';
  /** Callout title */
  title?: string;
  /** Callout content */
  children: React.ReactNode;
  /** Custom icon */
  icon?: React.ReactNode;
}

/**
 * Handler for rendering code blocks with syntax highlighting
 */
interface CodeBlock extends React.Component<CodeBlockProps> {}

interface CodeBlockProps {
  /** Programming language for syntax highlighting */
  language?: string;
  /** Code content */
  code: string;
  /** Whether to show line numbers */
  showLineNumbers?: boolean;
  /** Custom theme for syntax highlighting */
  theme?: string;
}

/**
 * Handler for rendering heading elements
 */
interface Heading extends React.Component<HeadingProps> {}

interface HeadingProps {
  /** Heading level (1-6) */
  level: 1 | 2 | 3 | 4 | 5 | 6;
  /** Heading content */
  children: React.ReactNode;
  /** Custom ID for anchor links */
  id?: string;
  /** Additional CSS classes */
  className?: string;
}

/**
 * Handler for rendering text content with marks
 */
interface TextHandler extends React.Component<TextHandlerProps> {}

interface TextHandlerProps {
  /** Text content */
  text: string;
  /** Applied marks */
  marks?: RemirrorJSONMark[];
  /** Custom mark renderers */
  markRenderers?: Record<string, ComponentType>;
}

Usage Example:

import React from 'react';
import { 
  RemirrorRenderer,
  Callout,
  CodeBlock,
  Heading 
} from '@remirror/react';

function CustomContentRenderer() {
  const customTypeMap = {
    callout: ({ type, title, children }) => (
      <Callout type={type} title={title}>
        {children}
      </Callout>
    ),
    codeBlock: ({ language, code }) => (
      <CodeBlock 
        language={language} 
        code={code}
        showLineNumbers={true}
        theme="dark"
      />
    ),
    heading: ({ level, children, id }) => (
      <Heading level={level} id={id}>
        {children}
      </Heading>
    ),
  };

  const content = {
    type: 'doc',
    content: [
      {
        type: 'heading',
        attrs: { level: 1 },
        content: [{ type: 'text', text: 'Welcome' }],
      },
      {
        type: 'callout',
        attrs: { type: 'info', title: 'Note' },
        content: [
          {
            type: 'paragraph',
            content: [{ type: 'text', text: 'This is important!' }],
          },
        ],
      },
    ],
  };

  return (
    <RemirrorRenderer 
      json={content}
      typeMap={customTypeMap}
    />
  );
}

Handler Factories

Factory functions for creating specialized content handlers.

/**
 * Factory for creating iframe handlers
 * @param options - Iframe configuration options
 * @returns Iframe handler component
 */
function createIFrameHandler(
  options: IFrameHandlerOptions
): ComponentType<IFrameProps>;

interface IFrameHandlerOptions {
  /** Allowed domains for iframes */
  allowedDomains?: string[];
  /** Default iframe attributes */
  defaultAttributes?: Record<string, string>;
  /** Security settings */
  sandbox?: string[];
  /** Error fallback component */
  errorFallback?: ComponentType;
}

interface IFrameProps {
  /** Iframe source URL */
  src: string;
  /** Iframe title */
  title?: string;
  /** Iframe dimensions */
  width?: number | string;
  height?: number | string;
  /** Additional attributes */
  attributes?: Record<string, string>;
}

/**
 * Factory for creating link handlers
 * @param options - Link configuration options
 * @returns Link handler component
 */
function createLinkHandler(
  options: LinkHandlerOptions
): ComponentType<LinkProps>;

interface LinkHandlerOptions {
  /** Whether to open external links in new tab */
  openExternalInNewTab?: boolean;
  /** Custom link click handler */
  onClick?: (href: string, event: React.MouseEvent) => void;
  /** Link validation function */
  validateLink?: (href: string) => boolean;
  /** Custom link styling */
  className?: string;
}

interface LinkProps {
  /** Link destination */
  href: string;
  /** Link text content */
  children: React.ReactNode;
  /** Link title attribute */
  title?: string;
  /** Whether link is external */
  external?: boolean;
}

Usage Example:

import React from 'react';
import { 
  RemirrorRenderer,
  createIFrameHandler,
  createLinkHandler 
} from '@remirror/react';

function SafeContentRenderer() {
  const safeIFrameHandler = createIFrameHandler({
    allowedDomains: ['youtube.com', 'vimeo.com'],
    sandbox: ['allow-scripts', 'allow-same-origin'],
    errorFallback: () => <div>Iframe not allowed</div>,
  });

  const customLinkHandler = createLinkHandler({
    openExternalInNewTab: true,
    onClick: (href, event) => {
      console.log('Link clicked:', href);
    },
    validateLink: (href) => !href.includes('malicious'),
  });

  const typeMap = {
    iframe: safeIFrameHandler,
    link: customLinkHandler,
  };

  const content = {
    type: 'doc',
    content: [
      {
        type: 'paragraph',
        content: [
          {
            type: 'text',
            text: 'Check out this video: ',
          },
          {
            type: 'link',
            attrs: { href: 'https://youtube.com/watch?v=example' },
            content: [{ type: 'text', text: 'YouTube Video' }],
          },
        ],
      },
    ],
  };

  return (
    <RemirrorRenderer 
      json={content}
      typeMap={typeMap}
    />
  );
}

Mark Mapping

/**
 * Mapping of marks to React components for rendering
 */
type MarkMap = Record<string, ComponentType<MarkProps>>;

interface MarkProps {
  /** Mark attributes */
  attrs?: Record<string, any>;
  /** Content to wrap with the mark */
  children: React.ReactNode;
  /** Mark type name */
  markType: string;
}

/**
 * Create a custom mark renderer
 * @param markType - The mark type to handle
 * @param component - React component to render the mark
 * @returns Mark renderer function
 */
function createMarkRenderer(
  markType: string,
  component: ComponentType<MarkProps>
): (props: MarkProps) => React.ReactNode;

Rendering Context

/**
 * Context for renderer components to access parent renderer state
 */
interface RendererContext {
  /** Current document being rendered */
  document: RemirrorJSON;
  /** Current rendering path */
  path: number[];
  /** Type mappings */
  typeMap: Record<string, ComponentType>;
  /** Mark mappings */
  markMap: MarkMap;
  /** Renderer options */
  options: RendererOptions;
}

interface RendererOptions {
  /** Whether to sanitize HTML attributes */
  sanitizeAttributes?: boolean;
  /** Maximum nesting depth */
  maxDepth?: number;
  /** Error handling mode */
  errorMode?: 'throw' | 'render' | 'ignore';
}

/**
 * Hook to access renderer context
 * @returns Current renderer context
 */
function useRendererContext(): RendererContext;

Performance Optimization

/**
 * Optimized renderer for large documents
 */
interface OptimizedRenderer extends React.Component<OptimizedRendererProps> {}

interface OptimizedRendererProps extends RemirrorRendererProps {
  /** Whether to use virtual scrolling */
  virtualScrolling?: boolean;
  /** Chunk size for rendering */
  chunkSize?: number;
  /** Whether to lazy load content */
  lazyLoad?: boolean;
  /** Intersection observer options for lazy loading */
  observerOptions?: IntersectionObserverInit;
}

/**
 * Memoized content renderer for better performance
 * @param props - Renderer props
 * @returns Memoized renderer component
 */
const MemoizedRenderer: React.MemoExoticComponent<
  React.ComponentType<RemirrorRendererProps>
>;

Usage Example:

import React from 'react';
import { 
  OptimizedRenderer,
  MemoizedRenderer,
  useRendererContext 
} from '@remirror/react';

function LargeDocumentRenderer({ json }) {
  return (
    <OptimizedRenderer
      json={json}
      virtualScrolling={true}
      chunkSize={50}
      lazyLoad={true}
      observerOptions={{
        threshold: 0.1,
        rootMargin: '50px',
      }}
    />
  );
}

function CustomNodeRenderer({ children }) {
  const context = useRendererContext();
  const isNested = context.path.length > 3;
  
  return (
    <div className={isNested ? 'nested-content' : 'top-level-content'}>
      {children}
    </div>
  );
}

Install with Tessl CLI

npx tessl i tessl/npm-remirror--react@2.0.0
What are skills?

docs

advanced-hooks.md

component-extensions.md

content-rendering.md

core-integration.md

editor-hooks.md

index.md

table-extensions.md

ui-components.md

utilities.md

tile.json