1
This commit is contained in:
+11
@@ -0,0 +1,11 @@
|
||||
import type { DerivativeFunc, TokenType } from './interface';
|
||||
/**
|
||||
* 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;
|
||||
readonly id: number;
|
||||
constructor(derivatives: DerivativeFunc<DesignToken, DerivativeToken> | DerivativeFunc<DesignToken, DerivativeToken>[]);
|
||||
getDerivativeToken(token: DesignToken): DerivativeToken;
|
||||
}
|
||||
+22
@@ -0,0 +1,22 @@
|
||||
import { warning } from "@rc-component/util/es/warning";
|
||||
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 {
|
||||
derivatives;
|
||||
id;
|
||||
constructor(derivatives) {
|
||||
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) {
|
||||
return this.derivatives.reduce((result, derivative) => derivative(token, result), undefined);
|
||||
}
|
||||
}
|
||||
+20
@@ -0,0 +1,20 @@
|
||||
import type Theme from './Theme';
|
||||
import type { DerivativeFunc } from './interface';
|
||||
type DerivativeOptions = DerivativeFunc<any, any>[];
|
||||
export declare function sameDerivativeOption(left: DerivativeOptions, right: DerivativeOptions): boolean;
|
||||
export default class ThemeCache {
|
||||
static MAX_CACHE_SIZE: number;
|
||||
static MAX_CACHE_OFFSET: number;
|
||||
private readonly cache;
|
||||
private keys;
|
||||
private cacheCallTimes;
|
||||
constructor();
|
||||
size(): number;
|
||||
private internalGet;
|
||||
get(derivativeOption: DerivativeOptions): Theme<any, any> | undefined;
|
||||
has(derivativeOption: DerivativeOptions): boolean;
|
||||
set(derivativeOption: DerivativeOptions, value: Theme<any, any>): void;
|
||||
private deleteByPath;
|
||||
delete(derivativeOption: DerivativeOptions): Theme<any, any> | undefined;
|
||||
}
|
||||
export {};
|
||||
+110
@@ -0,0 +1,110 @@
|
||||
// ================================== Cache ==================================
|
||||
|
||||
export function sameDerivativeOption(left, right) {
|
||||
if (left.length !== right.length) {
|
||||
return false;
|
||||
}
|
||||
for (let i = 0; i < left.length; i++) {
|
||||
if (left[i] !== right[i]) {
|
||||
return false;
|
||||
}
|
||||
}
|
||||
return true;
|
||||
}
|
||||
export default class ThemeCache {
|
||||
static MAX_CACHE_SIZE = 20;
|
||||
static MAX_CACHE_OFFSET = 5;
|
||||
cache;
|
||||
keys;
|
||||
cacheCallTimes;
|
||||
constructor() {
|
||||
this.cache = new Map();
|
||||
this.keys = [];
|
||||
this.cacheCallTimes = 0;
|
||||
}
|
||||
size() {
|
||||
return this.keys.length;
|
||||
}
|
||||
internalGet(derivativeOption, updateCallTimes = false) {
|
||||
let cache = {
|
||||
map: this.cache
|
||||
};
|
||||
derivativeOption.forEach(derivative => {
|
||||
if (!cache) {
|
||||
cache = undefined;
|
||||
} else {
|
||||
cache = cache?.map?.get(derivative);
|
||||
}
|
||||
});
|
||||
if (cache?.value && updateCallTimes) {
|
||||
cache.value[1] = this.cacheCallTimes++;
|
||||
}
|
||||
return cache?.value;
|
||||
}
|
||||
get(derivativeOption) {
|
||||
return this.internalGet(derivativeOption, true)?.[0];
|
||||
}
|
||||
has(derivativeOption) {
|
||||
return !!this.internalGet(derivativeOption);
|
||||
}
|
||||
set(derivativeOption, value) {
|
||||
// New cache
|
||||
if (!this.has(derivativeOption)) {
|
||||
if (this.size() + 1 > ThemeCache.MAX_CACHE_SIZE + ThemeCache.MAX_CACHE_OFFSET) {
|
||||
const [targetKey] = this.keys.reduce((result, key) => {
|
||||
const [, callTimes] = result;
|
||||
if (this.internalGet(key)[1] < callTimes) {
|
||||
return [key, this.internalGet(key)[1]];
|
||||
}
|
||||
return result;
|
||||
}, [this.keys[0], this.cacheCallTimes]);
|
||||
this.delete(targetKey);
|
||||
}
|
||||
this.keys.push(derivativeOption);
|
||||
}
|
||||
let cache = this.cache;
|
||||
derivativeOption.forEach((derivative, index) => {
|
||||
if (index === derivativeOption.length - 1) {
|
||||
cache.set(derivative, {
|
||||
value: [value, this.cacheCallTimes++]
|
||||
});
|
||||
} else {
|
||||
const cacheValue = cache.get(derivative);
|
||||
if (!cacheValue) {
|
||||
cache.set(derivative, {
|
||||
map: new Map()
|
||||
});
|
||||
} else if (!cacheValue.map) {
|
||||
cacheValue.map = new Map();
|
||||
}
|
||||
cache = cache.get(derivative).map;
|
||||
}
|
||||
});
|
||||
}
|
||||
deleteByPath(currentCache, derivatives) {
|
||||
const cache = currentCache.get(derivatives[0]);
|
||||
if (derivatives.length === 1) {
|
||||
if (!cache.map) {
|
||||
currentCache.delete(derivatives[0]);
|
||||
} else {
|
||||
currentCache.set(derivatives[0], {
|
||||
map: cache.map
|
||||
});
|
||||
}
|
||||
return cache.value?.[0];
|
||||
}
|
||||
const result = this.deleteByPath(cache.map, derivatives.slice(1));
|
||||
if ((!cache.map || cache.map.size === 0) && !cache.value) {
|
||||
currentCache.delete(derivatives[0]);
|
||||
}
|
||||
return result;
|
||||
}
|
||||
delete(derivativeOption) {
|
||||
// If cache exists
|
||||
if (this.has(derivativeOption)) {
|
||||
this.keys = this.keys.filter(item => !sameDerivativeOption(item, derivativeOption));
|
||||
return this.deleteByPath(this.cache, derivativeOption);
|
||||
}
|
||||
return undefined;
|
||||
}
|
||||
}
|
||||
Generated
Vendored
+15
@@ -0,0 +1,15 @@
|
||||
import AbstractCalculator from './calculator';
|
||||
export default class CSSCalculator extends AbstractCalculator {
|
||||
result: string;
|
||||
unitlessCssVar: Set<string>;
|
||||
lowPriority?: boolean;
|
||||
constructor(num: number | string | AbstractCalculator, unitlessCssVar: Set<string>);
|
||||
add(num: number | string | AbstractCalculator): this;
|
||||
sub(num: number | string | AbstractCalculator): this;
|
||||
mul(num: number | string | AbstractCalculator): this;
|
||||
div(num: number | string | AbstractCalculator): this;
|
||||
getResult(force?: boolean): string;
|
||||
equal(options?: {
|
||||
unit?: boolean;
|
||||
}): string;
|
||||
}
|
||||
+87
@@ -0,0 +1,87 @@
|
||||
import AbstractCalculator from "./calculator";
|
||||
const CALC_UNIT = 'CALC_UNIT';
|
||||
const regexp = new RegExp(CALC_UNIT, 'g');
|
||||
function unit(value) {
|
||||
if (typeof value === 'number') {
|
||||
return `${value}${CALC_UNIT}`;
|
||||
}
|
||||
return value;
|
||||
}
|
||||
export default class CSSCalculator extends AbstractCalculator {
|
||||
result = '';
|
||||
unitlessCssVar;
|
||||
lowPriority;
|
||||
constructor(num, unitlessCssVar) {
|
||||
super();
|
||||
const numType = typeof num;
|
||||
this.unitlessCssVar = unitlessCssVar;
|
||||
if (num instanceof CSSCalculator) {
|
||||
this.result = `(${num.result})`;
|
||||
} else if (numType === 'number') {
|
||||
this.result = unit(num);
|
||||
} else if (numType === 'string') {
|
||||
this.result = num;
|
||||
}
|
||||
}
|
||||
add(num) {
|
||||
if (num instanceof CSSCalculator) {
|
||||
this.result = `${this.result} + ${num.getResult()}`;
|
||||
} else if (typeof num === 'number' || typeof num === 'string') {
|
||||
this.result = `${this.result} + ${unit(num)}`;
|
||||
}
|
||||
this.lowPriority = true;
|
||||
return this;
|
||||
}
|
||||
sub(num) {
|
||||
if (num instanceof CSSCalculator) {
|
||||
this.result = `${this.result} - ${num.getResult()}`;
|
||||
} else if (typeof num === 'number' || typeof num === 'string') {
|
||||
this.result = `${this.result} - ${unit(num)}`;
|
||||
}
|
||||
this.lowPriority = true;
|
||||
return this;
|
||||
}
|
||||
mul(num) {
|
||||
if (this.lowPriority) {
|
||||
this.result = `(${this.result})`;
|
||||
}
|
||||
if (num instanceof CSSCalculator) {
|
||||
this.result = `${this.result} * ${num.getResult(true)}`;
|
||||
} else if (typeof num === 'number' || typeof num === 'string') {
|
||||
this.result = `${this.result} * ${num}`;
|
||||
}
|
||||
this.lowPriority = false;
|
||||
return this;
|
||||
}
|
||||
div(num) {
|
||||
if (this.lowPriority) {
|
||||
this.result = `(${this.result})`;
|
||||
}
|
||||
if (num instanceof CSSCalculator) {
|
||||
this.result = `${this.result} / ${num.getResult(true)}`;
|
||||
} else if (typeof num === 'number' || typeof num === 'string') {
|
||||
this.result = `${this.result} / ${num}`;
|
||||
}
|
||||
this.lowPriority = false;
|
||||
return this;
|
||||
}
|
||||
getResult(force) {
|
||||
return this.lowPriority || force ? `(${this.result})` : this.result;
|
||||
}
|
||||
equal(options) {
|
||||
const {
|
||||
unit: cssUnit
|
||||
} = options || {};
|
||||
let mergedUnit = true;
|
||||
if (typeof cssUnit === 'boolean') {
|
||||
mergedUnit = cssUnit;
|
||||
} else if (Array.from(this.unitlessCssVar).some(cssVar => this.result.includes(cssVar))) {
|
||||
mergedUnit = false;
|
||||
}
|
||||
this.result = this.result.replace(regexp, mergedUnit ? 'px' : '');
|
||||
if (typeof this.lowPriority !== 'undefined') {
|
||||
return `calc(${this.result})`;
|
||||
}
|
||||
return this.result;
|
||||
}
|
||||
}
|
||||
Generated
Vendored
+10
@@ -0,0 +1,10 @@
|
||||
import AbstractCalculator from './calculator';
|
||||
export default class NumCalculator extends AbstractCalculator {
|
||||
result: number;
|
||||
constructor(num: number | string | AbstractCalculator);
|
||||
add(num: number | string | AbstractCalculator): this;
|
||||
sub(num: number | string | AbstractCalculator): this;
|
||||
mul(num: number | string | AbstractCalculator): this;
|
||||
div(num: number | string | AbstractCalculator): this;
|
||||
equal(): number;
|
||||
}
|
||||
+47
@@ -0,0 +1,47 @@
|
||||
import AbstractCalculator from "./calculator";
|
||||
export default class NumCalculator extends AbstractCalculator {
|
||||
result = 0;
|
||||
constructor(num) {
|
||||
super();
|
||||
if (num instanceof NumCalculator) {
|
||||
this.result = num.result;
|
||||
} else if (typeof num === 'number') {
|
||||
this.result = num;
|
||||
}
|
||||
}
|
||||
add(num) {
|
||||
if (num instanceof NumCalculator) {
|
||||
this.result += num.result;
|
||||
} else if (typeof num === 'number') {
|
||||
this.result += num;
|
||||
}
|
||||
return this;
|
||||
}
|
||||
sub(num) {
|
||||
if (num instanceof NumCalculator) {
|
||||
this.result -= num.result;
|
||||
} else if (typeof num === 'number') {
|
||||
this.result -= num;
|
||||
}
|
||||
return this;
|
||||
}
|
||||
mul(num) {
|
||||
if (num instanceof NumCalculator) {
|
||||
this.result *= num.result;
|
||||
} else if (typeof num === 'number') {
|
||||
this.result *= num;
|
||||
}
|
||||
return this;
|
||||
}
|
||||
div(num) {
|
||||
if (num instanceof NumCalculator) {
|
||||
this.result /= num.result;
|
||||
} else if (typeof num === 'number') {
|
||||
this.result /= num;
|
||||
}
|
||||
return this;
|
||||
}
|
||||
equal() {
|
||||
return this.result;
|
||||
}
|
||||
}
|
||||
+30
@@ -0,0 +1,30 @@
|
||||
declare abstract class AbstractCalculator {
|
||||
/**
|
||||
* @descCN 计算两数的和,例如:1 + 2
|
||||
* @descEN Calculate the sum of two numbers, e.g. 1 + 2
|
||||
*/
|
||||
abstract add(num: number | string | AbstractCalculator): this;
|
||||
/**
|
||||
* @descCN 计算两数的差,例如:1 - 2
|
||||
* @descEN Calculate the difference between two numbers, e.g. 1 - 2
|
||||
*/
|
||||
abstract sub(num: number | string | AbstractCalculator): this;
|
||||
/**
|
||||
* @descCN 计算两数的积,例如:1 * 2
|
||||
* @descEN Calculate the product of two numbers, e.g. 1 * 2
|
||||
*/
|
||||
abstract mul(num: number | string | AbstractCalculator): this;
|
||||
/**
|
||||
* @descCN 计算两数的商,例如:1 / 2
|
||||
* @descEN Calculate the quotient of two numbers, e.g. 1 / 2
|
||||
*/
|
||||
abstract div(num: number | string | AbstractCalculator): this;
|
||||
/**
|
||||
* @descCN 获取计算结果
|
||||
* @descEN Get the calculation result
|
||||
*/
|
||||
abstract equal(options?: {
|
||||
unit?: boolean;
|
||||
}): string | number;
|
||||
}
|
||||
export default AbstractCalculator;
|
||||
+2
@@ -0,0 +1,2 @@
|
||||
class AbstractCalculator {}
|
||||
export default AbstractCalculator;
|
||||
+5
@@ -0,0 +1,5 @@
|
||||
import type AbstractCalculator from './calculator';
|
||||
import CSSCalculator from './CSSCalculator';
|
||||
import NumCalculator from './NumCalculator';
|
||||
declare const genCalc: (type: 'css' | 'js', unitlessCssVar: Set<string>) => (num: number | string | AbstractCalculator) => CSSCalculator | NumCalculator;
|
||||
export default genCalc;
|
||||
+7
@@ -0,0 +1,7 @@
|
||||
import CSSCalculator from "./CSSCalculator";
|
||||
import NumCalculator from "./NumCalculator";
|
||||
const genCalc = (type, unitlessCssVar) => {
|
||||
const Calculator = type === 'css' ? CSSCalculator : NumCalculator;
|
||||
return num => new Calculator(num, unitlessCssVar);
|
||||
};
|
||||
export default genCalc;
|
||||
+6
@@ -0,0 +1,6 @@
|
||||
import Theme from './Theme';
|
||||
import type { DerivativeFunc, TokenType } from './interface';
|
||||
/**
|
||||
* 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>): Theme<any, any>;
|
||||
+17
@@ -0,0 +1,17 @@
|
||||
import ThemeCache from "./ThemeCache";
|
||||
import Theme from "./Theme";
|
||||
const cacheThemes = new ThemeCache();
|
||||
|
||||
/**
|
||||
* Same as new Theme, but will always return same one if `derivative` not changed.
|
||||
*/
|
||||
export default function createTheme(derivatives) {
|
||||
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);
|
||||
}
|
||||
+6
@@ -0,0 +1,6 @@
|
||||
export { default as genCalc } from './calc';
|
||||
export type { default as AbstractCalculator } from './calc/calculator';
|
||||
export { default as createTheme } from './createTheme';
|
||||
export type { DerivativeFunc, TokenType } from './interface';
|
||||
export { default as Theme } from './Theme';
|
||||
export { default as ThemeCache } from './ThemeCache';
|
||||
+4
@@ -0,0 +1,4 @@
|
||||
export { default as genCalc } from "./calc";
|
||||
export { default as createTheme } from "./createTheme";
|
||||
export { default as Theme } from "./Theme";
|
||||
export { default as ThemeCache } from "./ThemeCache";
|
||||
+2
@@ -0,0 +1,2 @@
|
||||
export type TokenType = object;
|
||||
export type DerivativeFunc<DesignToken extends TokenType, DerivativeToken extends TokenType> = (designToken: DesignToken, derivativeToken?: DerivativeToken) => DerivativeToken;
|
||||
+1
@@ -0,0 +1 @@
|
||||
export {};
|
||||
Reference in New Issue
Block a user