New
Code coverage with Storybook test runnerAutomate with Chromatic
Star74,802
Back to Create an Addon
React
Chapters
  • Présentation
  • Avant de commencer
  • Enregistrer l'addon
  • Suivre l'état
  • Décorateurs
  • Preset
  • Ajouter au catalogue
  • Conclusion

Décorateurs

Interagir avec les stories

Nous y sommes presque ! Jusque là, nous avons créé un outil, nous l'avons ajouté à la barre d'outils et il a même un état. Nous devons maintenant suivre et appliquer cet état pour afficher ou masquer les contours.

Les décorateurs englobent les stories et ajoutent des fonctionnalités au rendu. Nous allons créer un décorateur qui réagit à la variable globale de contour et gère l'injection de CSS affichant des contours autour de tous les éléments HTML.

Dans l'étape précédente, nous avons défini la globale outlineActive, branchons-la ! Nous pouvons consommer les globales en passant par un décorateur, en utilisant le hook useGlobals.

Copy
src/withGlobals.js
/* eslint-env browser */
import { useEffect, useGlobals } from '@storybook/addons';

export const withGlobals = (StoryFn, context) => {
  const [{ outlineActive }, updateGlobals] = useGlobals();
  // L'addon est-il utilisé dans le panneau Docs ?
  const isInDocs = context.viewMode === 'docs';

  useEffect(() => {
    // Exécutez votre effet de bord ici
    // Pour manipuler le contenu de la prévisualisation, par exemple
    const selectorId = isInDocs ? `#anchor--${context.id} .docs-story` : `root`;

    displayToolState(selectorId, { outlineActive, isInDocs });
  }, [outlineActive]);

  return StoryFn();
};

function displayToolState(selector, state) {
  const rootElement = document.getElementById(selector);
  let preElement = rootElement.querySelector('pre');

  if (!preElement) {
    preElement = document.createElement('pre');
    preElement.style.setProperty('margin-top', '2rem');
    preElement.style.setProperty('padding', '1rem');
    preElement.style.setProperty('background-color', '#eee');
    preElement.style.setProperty('border-radius', '3px');
    preElement.style.setProperty('max-width', '600px');
    rootElement.appendChild(preElement);
  }

  preElement.innerText = `Ce snippet est injecté par le décorateur withGlobals.
Il s'actualise lorsque l'utilisateur interagit avec l'outil ⚡ de la barre d'outils ci-dessus.
${JSON.stringify(state, null, 2)}
`;
}

Injecter le CSS affichant les contours

Ajouter et nettoyer des styles est un effet de bord. Par conséquent, nous devons englober cette opération dans un useEffect. Ce dernier étant déclenché par le changement de la variable globale outlineActive. L'Addon Kit fournit un exemple, mais modifions-le afin d'appliquer l'injection de CSS pour afficher les contours.

Copy
src/withGlobals.js
/* eslint-env browser */
import { useEffect, useMemo, useGlobals } from '@storybook/addons';

import { clearStyles, addOutlineStyles } from './helpers';
import outlineCSS from './outlineCSS';

export const withGlobals = (StoryFn, context) => {
  const [{ outlineActive }, updateGlobals] = useGlobals();
  // L'addon est-il utilisé dans le panneau Docs ?
  const isInDocs = context.viewMode === 'docs';

  const outlineStyles = useMemo(() => {
    const selector = isInDocs ? `#anchor--${context.id} .docs-story` : '.sb-show-main';

    return outlineCSS(selector);
  }, [context.id]);

  useEffect(() => {
    const selectorId = isInDocs ? `my-addon-outline-docs-${context.id}` : `my-addon-outline`;

    if (!outlineActive) {
      clearStyles(selectorId);
      return;
    }

    addOutlineStyles(selectorId, outlineStyles);

    return () => {
      clearStyles(selectorId);
    };
  }, [outlineActive, outlineStyles, context.id]);

  return StoryFn();
};

Ok, ça fait beaucoup là, non ? Parcourons les modifications.

L'addon peut être activé à la fois dans les modes docs et story. Le nœud du DOM, correspondant à l'iframe de prévisualisation, est différent selon ces deux modes. En fait, le mode docs affiche plusieurs prévisualisations de stories sur une même page. Nous devons donc choisir un sélecteur approprié pour déterminer où nos styles seront injectés. De plus, le CSS doit être spécifiquement ciblé sur ce sélecteur.

Note : useMemo et useEffect sont fournis par @storybook/addons et non par React car le code du décorateur s'exécute dans la partie prévisualisation de Storybook. C'est là qu'est chargé le code de l'utilisateur et celui-ci n'est pas forcément du React. Par conséquent, afin de rester indépendant de quelque framework qu'il soit, Storybook nous met à disposition une bibliothèque de hooks similaires à React !

Ensuite, tandis que nous injectons nos styles dans le DOM, nous devons en garder une trace afin de les retirer lorsque l'utilisateur les désactive ou change de mode.

Pour gérer toute cette logique CSS, nous avons besoin d'helpers. Ils utilisent les APIs du DOM pour injecter et retirer les feuilles de style.

Copy
src/helpers.js
/* eslint-env browser */
export const clearStyles = selector => {
  const selectors = Array.isArray(selector) ? selector : [selector];
  selectors.forEach(clearStyle);
};

const clearStyle = selector => {
  const element = document.getElementById(selector);
  if (element && element.parentElement) {
    element.parentElement.removeChild(element);
  }
};

export const addOutlineStyles = (selector, css) => {
  const existingStyle = document.getElementById(selector);
  if (existingStyle) {
    if (existingStyle.innerHTML !== css) {
      existingStyle.innerHTML = css;
    }
  } else {
    const style = document.createElement('style');
    style.setAttribute('id', selector);
    style.innerHTML = css;
    document.head.appendChild(style);
  }
};

Ce CSS affichant les contours est basé sur ce qu'utilise Pesticide. Vous pouvez le récupérer dans le fichier outlineCSS.js.

Tout ceci nous permet d'afficher les contours autour des éléments UI.

Activer/désactiver l'outil permet d'afficher/masquer les contours

Keep your code in sync with this chapter. View 0e7246a on GitHub.
Is this free guide helping you? Tweet to give kudos and help other devs find it.
Next Chapter
Preset
Activer Outline sur chaque story
✍️ Edit on GitHub – PRs welcome!
Join the community
5,870 developers and counting
WhyWhy StorybookComponent-driven UI
Open source software
Storybook

Maintained by
Chromatic
Special thanks to Netlify and CircleCI