diff --git a/src/index.ts b/src/index.ts index 4094a969..dd4316d6 100644 --- a/src/index.ts +++ b/src/index.ts @@ -1,10 +1,11 @@ -import Theme, { createTheme } from './Theme'; -import type { TokenType } from './Theme'; +import Theme from './theme/Theme'; import useStyleRegister, { extractStyle } from './useStyleRegister'; import type { CSSObject, CSSInterpolation } from './useStyleRegister'; import useCacheToken from './useCacheToken'; import { StyleProvider, createCache } from './StyleContext'; import Keyframes from './Keyframes'; +import type { TokenType } from './theme'; +import { createTheme } from './theme'; export { Theme, diff --git a/src/theme/Theme.ts b/src/theme/Theme.ts new file mode 100644 index 00000000..16ee58fb --- /dev/null +++ b/src/theme/Theme.ts @@ -0,0 +1,41 @@ +import { warning } from 'rc-util/lib/warning'; +import type { DerivativeFunc, TokenType } from './interface'; + +let uuid = 0; + +/** + * Theme with algorithms to derive tokens from design tokens. + * Use `createTheme` first which will help to manage the theme instance cache. + */ +export default class Theme< + DesignToken extends TokenType, + DerivativeToken extends TokenType, +> { + private derivatives: DerivativeFunc[]; + public readonly id: number; + + constructor( + derivatives: + | DerivativeFunc + | DerivativeFunc[], + ) { + this.derivatives = Array.isArray(derivatives) ? derivatives : [derivatives]; + this.id = uuid; + + if (derivatives.length === 0) { + warning( + derivatives.length > 0, + '[Ant Design CSS-in-JS] Theme should have at least one derivative function.', + ); + } + + uuid += 1; + } + + getDerivativeToken(token: DesignToken): DerivativeToken { + return this.derivatives.reduce( + (result, derivative) => derivative(token, result), + undefined as any, + ); + } +} diff --git a/src/Theme.ts b/src/theme/ThemeCache.ts similarity index 65% rename from src/Theme.ts rename to src/theme/ThemeCache.ts index e0681fc3..633a7363 100644 --- a/src/Theme.ts +++ b/src/theme/ThemeCache.ts @@ -1,53 +1,5 @@ -import { warning } from 'rc-util/lib/warning'; - -export type TokenType = object; - -export type DerivativeFunc< - DesignToken extends TokenType, - DerivativeToken extends TokenType, -> = ( - designToken: DesignToken, - derivativeToken?: DerivativeToken, -) => DerivativeToken; - -let uuid = 0; - -/** - * Theme with algorithms to derive tokens from design tokens. - * Use `createTheme` first which will help to manage the theme instance cache. - */ -export default class Theme< - DesignToken extends TokenType, - DerivativeToken extends TokenType, -> { - private derivatives: DerivativeFunc[]; - public readonly id: number; - - constructor( - derivatives: - | DerivativeFunc - | DerivativeFunc[], - ) { - this.derivatives = Array.isArray(derivatives) ? derivatives : [derivatives]; - this.id = uuid; - - if (derivatives.length === 0) { - warning( - derivatives.length > 0, - '[Ant Design CSS-in-JS] Theme should have at least one derivative function.', - ); - } - - uuid += 1; - } - - getDerivativeToken(token: DesignToken): DerivativeToken { - return this.derivatives.reduce( - (result, derivative) => derivative(token, result), - undefined as any, - ); - } -} +import type Theme from './Theme'; +import type { DerivativeFunc } from './interface'; // ================================== Cache ================================== type ThemeCacheMap = Map< @@ -75,7 +27,7 @@ export function sameDerivativeOption( return true; } -export class ThemeCache { +export default class ThemeCache { public static MAX_CACHE_SIZE = 20; public static MAX_CACHE_OFFSET = 5; @@ -194,28 +146,3 @@ export class ThemeCache { return undefined; } } - -const cacheThemes = new ThemeCache(); - -/** - * Same as new Theme, but will always return same one if `derivative` not changed. - */ -export function createTheme< - DesignToken extends TokenType, - DerivativeToken extends TokenType, ->( - derivatives: - | DerivativeFunc[] - | DerivativeFunc, -) { - const derivativeArr = Array.isArray(derivatives) - ? derivatives - : [derivatives]; - // Create new theme if not exist - if (!cacheThemes.has(derivativeArr)) { - cacheThemes.set(derivativeArr, new Theme(derivativeArr)); - } - - // Get theme from cache and return - return cacheThemes.get(derivativeArr)!; -} diff --git a/src/theme/createTheme.ts b/src/theme/createTheme.ts new file mode 100644 index 00000000..2cabaae9 --- /dev/null +++ b/src/theme/createTheme.ts @@ -0,0 +1,28 @@ +import ThemeCache from './ThemeCache'; +import Theme from './Theme'; +import { DerivativeFunc, TokenType } from '@/theme/interface'; + +const cacheThemes = new ThemeCache(); + +/** + * Same as new Theme, but will always return same one if `derivative` not changed. + */ +export default function createTheme< + DesignToken extends TokenType, + DerivativeToken extends TokenType, +>( + derivatives: + | DerivativeFunc[] + | DerivativeFunc, +) { + const derivativeArr = Array.isArray(derivatives) + ? derivatives + : [derivatives]; + // Create new theme if not exist + if (!cacheThemes.has(derivativeArr)) { + cacheThemes.set(derivativeArr, new Theme(derivativeArr)); + } + + // Get theme from cache and return + return cacheThemes.get(derivativeArr)!; +} diff --git a/src/theme/index.ts b/src/theme/index.ts new file mode 100644 index 00000000..076fe417 --- /dev/null +++ b/src/theme/index.ts @@ -0,0 +1,3 @@ +export { default as createTheme } from './createTheme'; +export { default as Theme } from './Theme'; +export type { TokenType, DerivativeFunc } from './interface'; diff --git a/src/theme/interface.ts b/src/theme/interface.ts new file mode 100644 index 00000000..de52e1ee --- /dev/null +++ b/src/theme/interface.ts @@ -0,0 +1,8 @@ +export type TokenType = object; +export type DerivativeFunc< + DesignToken extends TokenType, + DerivativeToken extends TokenType, +> = ( + designToken: DesignToken, + derivativeToken?: DerivativeToken, +) => DerivativeToken; diff --git a/src/useCacheToken.tsx b/src/useCacheToken.tsx index b43915d7..a7b15ddb 100644 --- a/src/useCacheToken.tsx +++ b/src/useCacheToken.tsx @@ -5,7 +5,7 @@ import { CSS_IN_JS_INSTANCE, CSS_IN_JS_INSTANCE_ID, } from './StyleContext'; -import type Theme from './Theme'; +import type Theme from './theme/Theme'; import useGlobalCache from './useGlobalCache'; import { flattenToken, token2key } from './util'; diff --git a/tests/theme.spec.tsx b/tests/theme.spec.tsx index 5fd8ca8a..60db78ee 100644 --- a/tests/theme.spec.tsx +++ b/tests/theme.spec.tsx @@ -1,7 +1,7 @@ import { Theme, createTheme, useCacheToken } from '../src'; import { render } from '@testing-library/react'; import * as React from 'react'; -import { ThemeCache } from '../src/Theme'; +import ThemeCache from '../src/theme/ThemeCache'; interface DesignToken { primaryColor: string; @@ -189,7 +189,7 @@ describe('Theme', () => { }); it('should warn if empty array', () => { - const errSpy = jest.spyOn(console, 'error'); + const errSpy = jest.spyOn(console, 'error').mockImplementation(jest.fn()); expect(errSpy).toHaveBeenCalledTimes(0); createTheme([]); expect(errSpy).toHaveBeenCalledTimes(1);