fbredius/storybook

View on GitHub
addons/docs/src/frameworks/html/sourceDecorator.ts

Summary

Maintainability
A
1 hr
Test Coverage
/* global window */
import { addons, useEffect } from '@storybook/addons';
import { ArgsStoryFn, PartialStoryFn, StoryContext } from '@storybook/csf';
import dedent from 'ts-dedent';
import { HtmlFramework } from '@storybook/html';

import { SNIPPET_RENDERED, SourceType } from '../../shared';

function skipSourceRender(context: StoryContext<HtmlFramework>) {
  const sourceParams = context?.parameters.docs?.source;
  const isArgsStory = context?.parameters.__isArgsStory;

  // always render if the user forces it
  if (sourceParams?.type === SourceType.DYNAMIC) {
    return false;
  }

  // never render if the user is forcing the block to render code, or
  // if the user provides code, or if it's not an args story.
  return !isArgsStory || sourceParams?.code || sourceParams?.type === SourceType.CODE;
}

// By default, just remove indentation
function defaultTransformSource(source: string) {
  // Have to wrap dedent so it doesn't serialize the context
  return dedent(source);
}

function applyTransformSource(source: string, context: StoryContext<HtmlFramework>): string {
  const docs = context.parameters.docs ?? {};
  const transformSource = docs.transformSource ?? defaultTransformSource;
  return transformSource(source, context);
}

export function sourceDecorator(
  storyFn: PartialStoryFn<HtmlFramework>,
  context: StoryContext<HtmlFramework>
) {
  const story = context?.parameters.docs?.source?.excludeDecorators
    ? (context.originalStoryFn as ArgsStoryFn<HtmlFramework>)(context.args, context)
    : storyFn();

  let source: string;
  if (!skipSourceRender(context)) {
    if (typeof story === 'string') {
      source = story;
    }
    // eslint-disable-next-line no-undef
    else if (story instanceof Element) {
      source = story.outerHTML;
    }

    if (source) source = applyTransformSource(source, context);
  }
  useEffect(() => {
    if (source) addons.getChannel().emit(SNIPPET_RENDERED, context.id, source);
  });

  return story;
}