JSDoc - "Emotion"
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 Emotion context module.
/**
* A module providing a context for sharing an Emotion instance
* throughout components.<br />
* The Emotion instance is created internally inside the Provider
* and exposed to consumers through a `getter` function,<br />
* allowing components to use utilities like `cx` and `css`
* without importing Emotion directly.<br />
* Note: Only the `getter` is exposed; the `setter` is kept internal.
*
* @module contexts/Emotion
*/
import {
createContext,
createSignal,
createEffect,
} from 'solid-js';
import createEmotion from '@emotion/css/create-instance';
/**
* This is the actual Emotion instance created internally
* by `createInstance()` within Provider, and is exposed
* only via `getter`.
*
* I could have done `import('@emotion/css/create-instance~Emotion`'),
* but JSDoc does not generate for _external_ types.<br />
* Thus, using `@typedef` so that it generates documents.
*
* I also wanted `Cx` and `Css` to be documented, but JSDoc does not do that<br />
* because `@callback` means it has no actual functions corresponding to the type.<br />
* Therefore, I have `Cx` and `Css` as properties here so that generates documents.
*
* @typedef EmotionEntity
* @type {Object}
* @property {Cx} cx - Combines class names.
* @property {Css} css - Generates CSS class names.
* @see {@link https://github.com/emotion-js/emotion/blob/85772c33ecb01c70bc8afafa627c9fb7140b593c/packages/css/src/create-instance.ts#L47|@emotion/css/create-instance.Emotion}
*/
/**
* `getter` returning Emotion (or undefined).<br />
* Backed by `Accessor<EmotionEntity>` (SolidJS).
* @typedef {import("solid-js").Accessor<EmotionEntity>} EmotionGetter
*/
/**
* `setter` updating the Emotion instance.<br />
* Backed by `Setter<EmotionEntity>` (SolidJS).
* @typedef {import("solid-js").Setter<EmotionEntity>} EmotionSetter
*/
// Notice that I use `@callback` for `cx` and `css` bellow
// because `@callback` is for functions do not actually exists.
/**
* A method in Emotion for combining class names.
* @callback
* @name Cx
* @param {...string} args - Class names to combine.
* @returns {string} Combined class name.
* @see {@link https://github.com/emotion-js/emotion/blob/85772c33ecb01c70bc8afafa627c9fb7140b593c/packages/css/src/create-instance.ts#L47|@emotion/css/create-instance.Emotion}
*/
/**
* A method in Emotion for generating CSS.
* @callback
* @name Css
* @param {...(string|Object)} args - CSS strings or style objects.
* @returns {string} Generated CSS class name.
* @see {@link https://github.com/emotion-js/emotion/blob/85772c33ecb01c70bc8afafa627c9fb7140b593c/packages/css/src/create-instance.ts#L47|@emotion/css/create-instance.Emotion}
*/
/**
* A context having `getter`.<br />
* Though `EmotionGetter[]` maybe interpreted as Array,
* but I mean to express Tuple having only 1 element: a getter for Emotion.
* @typedef {EmotionGetter[]} EmotionContextValue
*/
/**
* This is the SolidJS' context provided by Provider,<br />
* specifically, for this app, it is exposed as `value="{[getter]}"`.
* @type {import("solid-js").Context<EmotionContextValue>}
*/
export const Context = createContext([]);
/**
* This is the Provider. By wrapping compnents with this Provider,
* it will provide `getter` which is the only way for users
* to obtain the Emotion instance (`EmotionEntity`).
*
* IMPORTANT: Do NOT destructure `children` from `props`.<br />
* If destructured, SolidJS treats them as if rendered *outside* the provider.
*
* @function
* @param {Object} props - Props for the provider.
* @param {string} [props.key] - Optional key for Emotion instance.
* @param {HTMLElement|ShadowRoot} [props.element] - Container for injecting styles.
* @param {JSX.Element|JSX.Element[]} props.children - Child components receiving context.
* @returns {JSX.Element} Emotion context provider wrapping children.
* @see {@link https://github.com/solidjs/solid/discussions/713} - Issue on Destructured Children
*/
export const Provider = props => {
const { key, element } = props || {};
/**
* I'm not destructuring because JSDoc does not attatch
* types to individual variables within destructures.
* @type {{
* 0: EmotionGetter,
* 1: EmotionSetter
* }}
*/
const signal = createSignal();
const [getter, setter] = signal;
createEffect(() => {
const { shadowRoot: container } = element || {};
if (container) {
/**
* Exposed only via `getter`.
* @type {EmotionEntity}
*/
const emotion = createEmotion({
key,
container,
});
setter(emotion);
}
});
return (
<Context.Provider value={[getter]}>
{props.children}
</Context.Provider>
);
};
TOP