Behive Tech Registry

getClassName

v0.0.6

A utility for generating BEM-style class names with support for CSS modules, modifiers, and child elements.

pnpm add @behivetech/get-class-name

registry/behivetech/utils/get-class-name

get-class-name.spec.ts
1import { getClassName } from './get-class-name.js';
2
3describe('getClassName', () => {
4 it('should return basic class name with root class', () => {
5 const [rootClass, getChildClass] = getClassName({
6 rootClass: 'my-component',
7 });
8 expect(rootClass).toBe('my-component');
9 expect(getChildClass('element')).toBe('my-component__element');
10 });
11
12 it('should handle className prop', () => {
13 const [rootClass] = getClassName({
14 rootClass: 'my-component',
15 className: 'custom-class',
16 });
17 expect(rootClass).toContain('custom-class');
18 expect(rootClass).toContain('my-component');
19 });
20
21 it('should handle modifiers', () => {
22 const [rootClass] = getClassName({
23 rootClass: 'my-component',
24 modifiers: { active: true, disabled: false },
25 });
26 expect(rootClass).toContain('my-component--active');
27 expect(rootClass).not.toContain('my-component--disabled');
28 });
29
30 it('should work with styles object', () => {
31 const styles = {
32 'my-component': 'styled-component',
33 'my-component__element': 'styled-element',
34 'my-component--active': 'styled-active',
35 };
36
37 const [rootClass, getChildClass] = getClassName({
38 rootClass: 'my-component',
39 modifiers: { active: true },
40 styles,
41 });
42
43 expect(rootClass).toContain('styled-component');
44 expect(rootClass).toContain('styled-active');
45 expect(getChildClass('element')).toBe('styled-element');
46 });
47});
get-class-name.ts
1import classnames from 'classnames';
2
3interface IGetClassNameProps {
4 /** className prop generally passed in from the parent component */
5 className?: string;
6 /**
7 object where the key is any additional classNames used to modify the elements of the compoent.
8 If the value of the key is true, it will add the name of the key to the className
9 */
10 modifiers?: { [key: string]: boolean };
11 /** className for the component */
12 rootClass: string;
13 styles?: { [key: string]: string };
14}
15
16export const getClassName = ({
17 className,
18 modifiers = {},
19 rootClass,
20 styles = {},
21}: IGetClassNameProps): [string, (childClassName: string) => string] => {
22 function getModifiers() {
23 const updatedModifiers: { [key: string]: boolean } = {};
24 const modifierKeys = Object.keys(modifiers);
25 if (modifierKeys.length) {
26 modifierKeys.forEach((modKey) => {
27 const classKey = `${rootClass}--${modKey}`;
28 const newClassName: string = styles[classKey] || classKey;
29
30 updatedModifiers[newClassName] = modifiers[modKey] ?? false;
31 });
32 }
33
34 return updatedModifiers;
35 }
36
37 function getChildClass(childClassName: string) {
38 const classKey = `${rootClass}__${childClassName}`;
39 return styles[classKey] || classKey;
40 }
41
42 function getRootStyles() {
43 return classnames(
44 className,
45 {
46 ...getModifiers(),
47 },
48 styles[rootClass] || rootClass
49 );
50 }
51
52 return [getRootStyles(), getChildClass];
53};
index.ts
1export { getClassName } from './get-class-name.js';