npm package discovery and stats viewer.

Discover Tips

  • General search

    [free text search, go nuts!]

  • Package details

    pkg:[package-name]

  • User packages

    @[username]

Sponsor

Optimize Toolset

I’ve always been into building performant and accessible sites, but lately I’ve been taking it extremely seriously. So much so that I’ve been building a tool to help me optimize and monitor the sites that I build to make sure that I’m making an attempt to offer the best experience to those who visit them. If you’re into performant, accessible and SEO friendly sites, you might like it too! You can check it out at Optimize Toolset.

About

Hi, 👋, I’m Ryan Hefner  and I built this site for me, and you! The goal of this site was to provide an easy way for me to check the stats on my npm packages, both for prioritizing issues and updates, and to give me a little kick in the pants to keep up on stuff.

As I was building it, I realized that I was actually using the tool to build the tool, and figured I might as well put this out there and hopefully others will find it to be a fast and useful way to search and browse npm packages as I have.

If you’re interested in other things I’m working on, follow me on Twitter or check out the open source projects I’ve been publishing on GitHub.

I am also working on a Twitter bot for this site to tweet the most popular, newest, random packages from npm. Please follow that account now and it will start sending out packages soon–ish.

Open Software & Tools

This site wouldn’t be possible without the immense generosity and tireless efforts from the people who make contributions to the world and share their work via open source initiatives. Thank you 🙏

© 2024 – Pkg Stats / Ryan Hefner

@web/storybook-utils

v1.0.2

Published

Utils for Storybook

Downloads

7

Readme

storybook-utils

Utilities for Storybook.

MDXFileLoader

Loads a non-JS file content in MDX and allows to render it.

This is needed for 2 reasons:

  • to workaround the limitation of MDX 2 where top-level await is not supported
  • to work in browsers where non-standard ESM imports (e.g. imports of text files, CSS and such) are not possible

In MDX 3 you can just use the top-level await.

Use-case: render external Markdown file using Storybook Markdown block.

Given a Storybook MDX file docs/my-page.mdx and a Markdown file README.md in the root, use the following MDX code:

import { Markdown } from '@storybook/blocks';
import { MDXFileLoader } from '@web/storybook-utils';

<MDXFileLoader
  url={new URL('../README.md', import.meta.url).href}
  render={content => {
    return <Markdown>{content}</Markdown>;
  }}
/>

Make sure to use @web/rollup-plugin-import-meta-assets or another alternative to correctly bundle the assets resolved with the help of import.meta.url.

createAddon

Storybook addons are React components. The createAddon function returns a React component that wraps a custom element and passes on properties and events. This allows for creating addons with web components (and therefore LitElement).

The wrapper can forward specific events to your addon (web component) as they occur. Your addon can listen for these events. Some useful Storybook events are forwarded by default (specifically STORY_SPECIFIED, STORY_CHANGED, STORY_RENDERED). An options parameter can be passed to createAddon that contains additional events that you may need for your use case.

api and active are required props when rendering the React component.

// my-addon/manager.js

import React from 'react';
import { STORY_RENDERED } from '@storybook/core-events';
import { addons, types } from '@storybook/manager-api';
import { createAddon } from '@web/storybook-utils';

const { createElement } = React;

class MyAddonElement extends LitElement {
  constructor() {
    super();
    this.addEventListener(STORY_RENDERED, event => {
      // handle Storybook event
    });
    this.addEventListener('my-addon:custom-event-name', event => {
      // handle my custom event
    });
  }

  render() {
    return html`
      <div>
        <!-- my addon template -->
      </div>
    `;
  }
}

customElements.define('my-addon', MyAddonElement);

const MyAddonReactComponent = createAddon('my-addon', {
  events: ['my-addon:custom-event-name'],
});

addons.register('my-addon', api => {
  addons.add('my-addon/panel', {
    type: types.PANEL,
    title: 'My Addon',
    render: ({ active }) => createElement(MyAddonReactComponent, { api, active }),
  });
});
// my-addon/decorator.js
import { addons } from '@storybook/preview-api';

// ...
addons.getChannel().emit('my-addon:custom-event-name', {});
// ...

Storybook expects only 1 addon to be in the DOM, which is the addon that is selected (active). This means addons can be continuously connected/disconnected when switching between addons and stories. This is important to understand to work effectively with LitElement lifecycle methods and events. Addons that rely on events that might occur when it is not active, should have their event listeners set up in the constructor. Event listeners set up in the connectedCallback should always also be disconnected.