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