Skip to content

Instantly share code, notes, and snippets.

@swashcap
Last active August 15, 2019 21:45
Show Gist options
  • Star 0 You must be signed in to star a gist
  • Fork 0 You must be signed in to fork a gist
  • Save swashcap/e16744d638ae3d415cbeefc929a36e92 to your computer and use it in GitHub Desktop.
Save swashcap/e16744d638ae3d415cbeefc929a36e92 to your computer and use it in GitHub Desktop.

Tooling idea: collect all the available CSS selectors:

const selectors = new Set<string>(document.styleSheets.reduce<string[]>(
	(acc, { rules }) => [...acc, ...rules.map(({ selectorText }) => selectorText)],
	[]
))

export function assertSelectors(...args: string[]) {
	args.forEach((selector) => {
		if (!selectors.has(selector)) {
			throw new Error(`Selector "${selector}" doesn't exist in any stylesheet`)
		}
	})
}

Then, in a component:

import React from 'react'
import clsx from 'clsx'
import { assertSelectors } from '../helpers/selectors'

export const selectors = {
	root: 'btn',
	text: 'btn-text'
}

export const Button: React.FC<ButtonProps> ({ className, children, ...rest }) => {
	// Assert selectors for development builds here such that missing styles cause
	// immediate runtime errors. This could also be a higher-order function.
	if (process.env.NODE_ENV === 'development') {
		assertSelectors(selector.root, selector.text)
	}

	return (
		<button className={clsx(selectors.root, className)} {...rest}>
			<span class={selector.text}>{children}</span>
		</button>
	)
}

Then, in a component's stylesheet these could be transformed to match the export:

.${selectors.root} {
	background: crimson;
	border: 1px solid transparent;
	color: red;
	cursor: pointer;
	display: inline-block;
	font: inherit;
	padding: 1em 1.25em;

	&:focus,
	&:hover {
		background: firebrick;
	}
	&:active {
		background: darkred;
	}
}
.${selectors.text} {
	font-weight: 500;
}
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment