Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

refactor: theme #36

Merged
merged 1 commit into from
Aug 16, 2022
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
5 changes: 3 additions & 2 deletions src/index.ts
Original file line number Diff line number Diff line change
@@ -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,
Expand Down
41 changes: 41 additions & 0 deletions src/theme/Theme.ts
Original file line number Diff line number Diff line change
@@ -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<DesignToken, DerivativeToken>[];
public readonly id: number;

constructor(
derivatives:
| DerivativeFunc<DesignToken, DerivativeToken>
| DerivativeFunc<DesignToken, DerivativeToken>[],
) {
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<DerivativeToken>(
(result, derivative) => derivative(token, result),
undefined as any,
);
}
}
79 changes: 3 additions & 76 deletions src/Theme.ts → src/theme/ThemeCache.ts
Original file line number Diff line number Diff line change
@@ -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<DesignToken, DerivativeToken>[];
public readonly id: number;

constructor(
derivatives:
| DerivativeFunc<DesignToken, DerivativeToken>
| DerivativeFunc<DesignToken, DerivativeToken>[],
) {
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<DerivativeToken>(
(result, derivative) => derivative(token, result),
undefined as any,
);
}
}
import type Theme from './Theme';
import type { DerivativeFunc } from './interface';

// ================================== Cache ==================================
type ThemeCacheMap = Map<
Expand Down Expand Up @@ -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;

Expand Down Expand Up @@ -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<DesignToken, DerivativeToken>[]
| DerivativeFunc<DesignToken, DerivativeToken>,
) {
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)!;
}
28 changes: 28 additions & 0 deletions src/theme/createTheme.ts
Original file line number Diff line number Diff line change
@@ -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<DesignToken, DerivativeToken>[]
| DerivativeFunc<DesignToken, DerivativeToken>,
) {
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)!;
}
3 changes: 3 additions & 0 deletions src/theme/index.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,3 @@
export { default as createTheme } from './createTheme';
export { default as Theme } from './Theme';
export type { TokenType, DerivativeFunc } from './interface';
8 changes: 8 additions & 0 deletions src/theme/interface.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,8 @@
export type TokenType = object;
export type DerivativeFunc<
DesignToken extends TokenType,
DerivativeToken extends TokenType,
> = (
designToken: DesignToken,
derivativeToken?: DerivativeToken,
) => DerivativeToken;
2 changes: 1 addition & 1 deletion src/useCacheToken.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -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';

Expand Down
4 changes: 2 additions & 2 deletions tests/theme.spec.tsx
Original file line number Diff line number Diff line change
@@ -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;
Expand Down Expand Up @@ -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);
Expand Down