TOP

JSDoc - "Breadcrumbs"

As mentioned, I don't use TypeScript, but write many of my apps in pure Javascript. As such, in order to describe types, I use JSDoc extensively in many of my codebases.
Hoping someone would find it interesting, I have a several pages presenting JSDoc examples as to how you could effectively utilize JSDoc's classical doctrine syntax.
Here is one of the modules that I currently use on my website, specifically, the Breadcrumbs widget.
/**
 * An entry point for the "Breadcrumbs widget".
 * @module widgets/breadcrumbs
 * @see {@link module:docs/widgets_basic_usage|} - Basic Usage of Widgets
 */

import { customElement } from 'solid-element';
import {
  useContext,
  createSignal,
  createEffect,
  createMemo,
  Show,
} from 'solid-js';
import tw from 'twin.macro';

import {
  Context as EmotionContext,
  Provider as EmotionProvider,
} from '../contexts/Emotion';
import {
  Provider as LanguageProvider,
  Context as LanguageContext,
} from '../contexts/Language';
import { useGlobalReady } from '../hooks/useGlobalReady';
import { createSharedStyles } from '../styles';

import { Sep } from '../components/sep';

/**
 * An internally used function that creates style objects<br />
 * for the settings widget using Emotion and twin.macro.
 * @type {import('../types').CreateStyles}
 */
const createStyles = ({ css }) => {
  const shared = createSharedStyles({
    css,
    list: ['linkStyle'],
  });

  return {
    content: css`
      ${tw`
        w-full flex flex-wrap flex-row justify-start items-center
        text-xl font-bold text-gray-900
      `}
    `,
    link: css`
      ${shared.linkStyle}
      ${tw`
        text-gray-900
        link:text-gray-900 link:no-underline link:font-normal
        hover:text-gray-900 hover:no-underline hover:font-normal
        visited:text-gray-900 visited:no-underline visited:font-normal
      `}
    `,
    sep: css`
      ${tw`mx-2`}
    `,
  };
};

/**
 * This is the main widget component.
 * @param {Object} props - Component props.
 * @param {HTMLElement} [props.element] - Host element for the widget. ???
 * @returns {JSX.Element} Settings widget UI.
 */
const Breadcrumbs = props => {
  const [emotion] = useContext(EmotionContext);
  const [styles, setStyles] = createSignal(null);
  const [globalReady] = useGlobalReady();
  const [language] = useContext(LanguageContext);
  const [breadcrumbs, setBreadcrumbs] = createSignal(
    []
  );

  const lastindex = createMemo(
    () => breadcrumbs().length - 1
  );

  const { dataset } = props?.element || {};

  createEffect(() => {
    if (emotion()) {
      const { cx, css } = emotion();
      const darkmode =
        typeof dataset?.darkmode !== 'undefined';

      const _styles = createStyles(emotion());

      _styles.content = cx(
        _styles.content,
        darkmode && css(tw`text-white`),
        dataset?.css && css(dataset.css)
      );

      if (darkmode) {
        _styles.link = cx(
          css`
            ${tw`
              text-white
              link:text-white link:no-underline link:font-normal
              hover:text-white hover:no-underline hover:font-normal
              visited:text-white visited:no-underline visited:font-normal
            `}
          `
        );
      }
      setStyles(_styles);
    }
  });

  createEffect(() => {
    if (dataset?.breadcrumbs) {
      try {
        const arr = JSON.parse(
          decodeURIComponent(dataset.breadcrumbs)
        );
        setBreadcrumbs(arr);
      } catch (err) {
        console.warn(err);
      }
    }
  });

  return (
    <>
      {/**
       * Has 'display: none' initially being set
       * for the widget, however, show it
       * as the SolidJS app mounts.
       */}
      <style>{`:host { display: block !important; }`}</style>

      <Show
        when={
          globalReady() &&
          emotion() &&
          styles() &&
          language() &&
          lastindex() > -1 &&
          !!breadcrumbs().length
        }
        fallback={<div></div>}
      >
        {(({ cx, css }) => (
          <nav
            id="breadcrumbs-content"
            className={cx(styles().content)}
          >
            {breadcrumbs().map((bread, i) => {
              const [text, link] = bread;
              const show = i < lastindex();

              return link ? (
                <a
                  key={i}
                  href={link}
                  className={cx(styles().link)}
                >
                  {text}
                  {show && (
                    <Sep styles={cx(styles().sep)} />
                  )}
                </a>
              ) : (
                <div key={i}>
                  {text}
                  {show && (
                    <Sep styles={cx(styles().sep)} />
                  )}
                </div>
              );
            })}
          </nav>
        ))(emotion())}
      </Show>
    </>
  );
};

/**
 * Registering `breadcrumbs-widget` as a custom element.
 */
customElement(
  'breadcrumbs-widget',
  {},
  (props, { element }) => {
    return (
      <LanguageProvider>
        <EmotionProvider
          key="breadcrumbs"
          element={element}
        >
          <Breadcrumbs element={element} {...props} />
        </EmotionProvider>
      </LanguageProvider>
    );
  }
);
TOP