From b18fdfd8c700c564b543345cd9eced02a1357284 Mon Sep 17 00:00:00 2001 From: Andre Luiz Rabello Date: Thu, 17 Dec 2020 09:56:28 +0000 Subject: [PATCH] refactor(core): simplify classy (#113) --- packages/core/src/utils/classy/classy.spec.ts | 26 ++----- packages/core/src/utils/classy/classy.ts | 69 +++++-------------- packages/react/src/button/button.react.tsx | 2 +- packages/react/src/icon/icon.react.tsx | 2 +- packages/react/src/input/input.react.tsx | 2 +- .../react/src/textarea/textarea.react.tsx | 2 +- 6 files changed, 27 insertions(+), 76 deletions(-) diff --git a/packages/core/src/utils/classy/classy.spec.ts b/packages/core/src/utils/classy/classy.spec.ts index f430a3a87..f30dec2db 100644 --- a/packages/core/src/utils/classy/classy.spec.ts +++ b/packages/core/src/utils/classy/classy.spec.ts @@ -3,9 +3,11 @@ import { c, classy, m } from './classy'; describe('classy', () => { const falsy = { + all: [] as any[], array: ['', undefined, null], object: { a: false, b: null, c: undefined }, }; + falsy.all = [...falsy.array, falsy.object]; it('should work with strings', () => { const result = classy('foo', 'bar'); @@ -35,33 +37,17 @@ describe('classy', () => { describe('c', () => { it('should apply component prefix', () => { - const result = c('foo', falsy.array, falsy.object, 'bar'); + const result = c('foo', ...falsy.all, { bar: true, zed: true }); - expect(result.join(' ')).toBe('ods-foo ods-bar'); - }); - - it('should work with tagged template literals', () => { - const result = c`foo bar ${falsy.object} ${ - falsy.array - } ${''} ${undefined} ${null} ${'a'}-${{ b: true }}`; - - expect(result.join(' ')).toBe('ods-foo ods-bar ods-a-b'); + expect(result.join(' ')).toBe('ods-foo ods-bar ods-zed'); }); }); describe('m', () => { it('should apply modifier prefix', () => { - const result = m('foo', falsy.array, falsy.object, 'bar'); - - expect(result.join(' ')).toBe('-foo -bar'); - }); - - it('should work with tagged template literals', () => { - const result = m`foo bar ${falsy.object} ${ - falsy.array - } ${''} ${undefined} ${null} ${'a'}--${{ b: true }}`; + const result = m('foo', ...falsy.all, { bar: true, zed: true }); - expect(result.join(' ')).toBe('-foo -bar -a--b'); + expect(result.join(' ')).toBe('-foo -bar -zed'); }); }); }); diff --git a/packages/core/src/utils/classy/classy.ts b/packages/core/src/utils/classy/classy.ts index eccf00b31..2d1c780d9 100644 --- a/packages/core/src/utils/classy/classy.ts +++ b/packages/core/src/utils/classy/classy.ts @@ -1,7 +1,6 @@ export type ClassName = string | null | undefined; export type ClassNameRecord = Record; export type ClassNames = ClassName | ClassName[] | ClassNameRecord; -type Template = [TemplateStringsArray, ...ClassNames[]]; /** * Generates a `className` based on the specified values. @@ -19,73 +18,39 @@ type Template = [TemplateStringsArray, ...ClassNames[]]; * // 'foo-1g4k53 global-1 global-2 className disabled' */ export const classy = (...classNames: ClassNames[]) => - classNames - .flat(10) - .flatMap((className) => - className instanceof Object ? getTruthyKeys(className) : className - ) - .filter(Boolean) - .join(' '); + classNames.flat(10).flatMap(truthyNames).join(' '); /** * Prefixes component names with a predetermined identifier. * - * Can be used as tagged template literal, separated by spaces. - * * @param components Names to prefix. * * @example - * c('button') || c`button`; + * c('button'); * // ['ods-button'] */ -export const c = mapWithPrefix('ods-'); +export const c = withPrefix('ods-'); /** * Prefixes modifier names with a predetermined identifier. * - * Can be used as tagged template literal, separated by spaces. - * * @param modifiers Names to prefix. * * @example - * m('action', 'primary') || m`action primary`; + * m('action', 'primary'); * // ['-action', '-primary'] */ -export const m = mapWithPrefix('-'); - -const fromTemplate = (array: Template | ClassNames[]) => - isTemplate(array) - ? array[0] - .map((value, i) => value + classy(array[i + 1] as ClassNames)) - .join('') - .split(' ') - : array; - -const getTruthyKeys = (obj: Record): string[] => - Object.entries(obj) - .filter(([, value]) => !!value) - .map(([key]) => key); - -const isTemplate = (template: Template | unknown[]): template is Template => - Array.isArray(template[0]) && - Array.isArray(((template[0] as unknown) as TemplateStringsArray).raw); - -const mapKey = ( - obj: Record, - mapFn: (key: string) => string -): Record => - Object.fromEntries( - Object.entries(obj).map(([key, value]) => [mapFn(key), value]) - ); - -function mapWithPrefix(prefix: string) { - return (...array: ClassNames[] | Template) => - fromTemplate(array) - .flat(10) - .filter(Boolean) - .flatMap((className) => - className instanceof Object - ? getTruthyKeys(mapKey(className, (key) => `${prefix}${key}`)) - : `${prefix}${className}` - ); +export const m = withPrefix('-'); + +const truthyNames = (value: ClassName | ClassNameRecord) => + (value instanceof Object + ? Object.entries(value) + .filter(([, value]) => !!value) + .map(([key]) => key) + : [value] + ).filter(Boolean); + +function withPrefix(prefix: string) { + return (...classNames: (ClassName | ClassNameRecord)[]) => + classNames.flatMap(truthyNames).map((name) => `${prefix}${name}`); } diff --git a/packages/react/src/button/button.react.tsx b/packages/react/src/button/button.react.tsx index d635b00fa..319d5aaf7 100755 --- a/packages/react/src/button/button.react.tsx +++ b/packages/react/src/button/button.react.tsx @@ -13,7 +13,7 @@ export const Button: ButtonComponent = ({ )} {...(Element === 'a' && { role: 'button' })} - className={classy(c`button`, m`${kind}--${variant}`, className)} + className={classy(c('button'), m(`${kind}--${variant}`), className)} /> ); }; diff --git a/packages/react/src/icon/icon.react.tsx b/packages/react/src/icon/icon.react.tsx index 753e06289..98ceeddf9 100644 --- a/packages/react/src/icon/icon.react.tsx +++ b/packages/react/src/icon/icon.react.tsx @@ -18,7 +18,7 @@ export const Icon = ({ {...restProps} fill={token ? color(token) : 'currentColor'} focusable="false" - className={classy(c`icon`, className)} + className={classy(c('icon'), className)} > diff --git a/packages/react/src/input/input.react.tsx b/packages/react/src/input/input.react.tsx index 35c22e784..d2b5cd7b3 100644 --- a/packages/react/src/input/input.react.tsx +++ b/packages/react/src/input/input.react.tsx @@ -10,7 +10,7 @@ export const Input = ({ ); diff --git a/packages/react/src/textarea/textarea.react.tsx b/packages/react/src/textarea/textarea.react.tsx index a794fb0b5..75626424d 100755 --- a/packages/react/src/textarea/textarea.react.tsx +++ b/packages/react/src/textarea/textarea.react.tsx @@ -12,7 +12,7 @@ export const Textarea = ({