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

Feat: Add new API genStyleUtils. #5

Merged
merged 44 commits into from
Jul 15, 2024
Merged
Show file tree
Hide file tree
Changes from 35 commits
Commits
Show all changes
44 commits
Select commit Hold shift + click to select a range
6b9db78
feat: migrate util `genCalc` and type `AbstractCalculator` from `@ant…
YumoImer Jul 3, 2024
b6823bd
feat: migrate interface folder from `antd`
YumoImer Jul 3, 2024
56e15cb
feat: migrate util `genCommonStyle` from `antd`
YumoImer Jul 3, 2024
9e8b143
feat: migrate api `genLinkStyle` from `antd`
YumoImer Jul 3, 2024
d765fa6
feat: migrate _util `useUniqueMemo` from `antd`
YumoImer Jul 3, 2024
1aebdc5
feat: migrate _type `AnyObject` from `antd`
YumoImer Jul 3, 2024
263ef9d
feat: migrate util `genMaxMin` and `statistic` from `antd`
YumoImer Jul 3, 2024
b4f6613
feat(interface): add components types and configProvider types
YumoImer Jul 5, 2024
874b629
feat(themes): migrate themes folder from `antd`
YumoImer Jul 6, 2024
683658d
feat(interface): add themeProvider types and modify components types
YumoImer Jul 6, 2024
271c107
feat(util): Refactor `genStyleHooks` `genCSSVarRegister` `genSubStyle…
YumoImer Jul 6, 2024
9df57f5
docs: update README.md
YumoImer Jul 6, 2024
6185155
Refactor: through a generator function to generated style utils.
YumoImer Jul 8, 2024
917191e
Refactor: refactor `useToken` API and delete files that are not required
YumoImer Jul 9, 2024
100d152
test: add getAlphaColor test
YumoImer Jul 9, 2024
4a4beeb
refactor: split the `genStyleUtils` and make the `getComponentToken` …
YumoImer Jul 9, 2024
9ba6462
fix: ci lint error.
YumoImer Jul 9, 2024
43a8ae9
docs: add `genStyleUtils` using docs.
YumoImer Jul 9, 2024
bb650e3
docs: update `genStyleUtils` using docs
YumoImer Jul 9, 2024
d1b4548
chore: remove unused dependencies
YumoImer Jul 10, 2024
ece47aa
chore: use `@ant-design/fast-color` instead of `@ctrl/tinycolor`
YumoImer Jul 10, 2024
13a5d6e
chore: delete `AnyObject` and use `Object` instead
YumoImer Jul 10, 2024
f36d4eb
chore: correct the file name
YumoImer Jul 10, 2024
ac85e1f
feat: delete default config context
YumoImer Jul 10, 2024
72e9741
feat: remove const `unitless` `ignore`
YumoImer Jul 10, 2024
e8cd3dc
refactor: remove all token interface, use generic instead
YumoImer Jul 10, 2024
c063a04
chore: remove unuse file PresetColors.ts
YumoImer Jul 10, 2024
6aefcd7
fix: fixed an illegal use of useContext
YumoImer Jul 11, 2024
7e3b72c
chore: change repo name to `@ant-design/cssinjs-utils`
YumoImer Jul 11, 2024
85d9f1b
refactor: dependency inversion
zombieJ Jul 11, 2024
b049106
Merge pull request #6 from ant-design/init-hooks
YumoImer Jul 11, 2024
7daaf99
refactor: dependency inversion for useToken
YumoImer Jul 11, 2024
14e7faf
docs: update `genStyleUtils` use docs
YumoImer Jul 11, 2024
90ac3a2
feat: delete `useToken` export fom `genStyleUtils`
YumoImer Jul 11, 2024
6a06576
docs: update `genStyleUtils` use docs
YumoImer Jul 11, 2024
61890ac
feat: delete `defaultUseToken` and change `genStyleUtils` config `use…
YumoImer Jul 11, 2024
da1e61b
feat: add `useResetStyle` to generate style for all need reset tags.
YumoImer Jul 11, 2024
38efedf
fix: import type
YumoImer Jul 11, 2024
4b1dfe7
refactor: add `genStyleUtils` config `config.genResetStyles` to gener…
YumoImer Jul 11, 2024
14a3e1a
chore: delete import
YumoImer Jul 11, 2024
d018428
fix: code review.
YumoImer Jul 12, 2024
631fa72
test: add genCalc test.
YumoImer Jul 15, 2024
caf065a
test: add calc test
YumoImer Jul 15, 2024
71705e5
test: add genStyleUtils test
YumoImer Jul 15, 2024
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
4 changes: 2 additions & 2 deletions README.md
Original file line number Diff line number Diff line change
@@ -1,9 +1,9 @@
# @ant-design/cssinjs-util
# @ant-design/cssinjs-utils
A cssinjs util library to support Ant Design (antd) and its ecosystem libraries.

## Install
``` bash
npm i @ant-design/cssinjs-util --save
npm i @ant-design/cssinjs-utils --save
```

## Usage
Expand Down
Empty file removed docs/demos/.gitkeep
Empty file.
108 changes: 108 additions & 0 deletions docs/demos/genStyleUtils.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,108 @@
---
title: genStyleUtils
nav:
title: API
path: /genStyleUtils
---
# `genStyleUtils` 使用文档

`genStyleUtils` 提供了用于在 `antd` 生态开发中,生成和管理样式的实用工具函数集。

## 入参介绍

### `genStyleUtils<CompTokenMap>(getConfigProviderContext?, getThemeProviderContext?)`
- `config`: 可选,配置
- `useCSP`: 使用 CSP 的钩子函数
- `usePrefix`: 使用样式前缀的钩子函数
- `useToken`: 使用 token 的钩子函数
- `CompTokenMap`: 范型参数,表示组件 token 映射
- `DesignTokenn`: 范型参数,表示设计 token
- `AliasToken`: 范型参数,表示别名 token
> 使用建议:为了更好的获得 TS 类型支持,建议您在使用 `genStyleUtils` 的时候传入范型参数 `CompTokenMap` `DesignTokenn` `AliasToken`

## 如何使用
``` typescript
import React from 'react';
import { genStyleUtils } from '@ant-design/cssinjs-utils';

// Step1: 定义组件 Token 映射
interface YourCompTokenMap {
Button?: {};
Avatar?: {};
// ...
}

// Step2: 定义设计 Token
interface YourDesignTokenn {
color?: string;
}

// Step3: 定义别名 Token
interface YourAliasToken {
colorFillContentHover?: string;
}

// Step4: 使用 `genStyleUtils` 生成工具函数集
const {
genStyleHooks,
genComponentStyleHook,
genSubStyleComponent,
} = genStyleUtils<YourCompTokenMap, YourDesignTokenn, YourAliasToken>({
useCSP: () => {
// ...
},
usePrefix: () => {
// ...
},
useToken: () => {
// ...
},
});
```

## 工具介绍

### `genStyleHooks(component, styleFn, getDefaultToken?, options?)`

- `component`: 组件名称 `ComponentName` 或组件名称数组 `[ComponentName, ComponentName]`。
- `styleFn`: 根据标记和样式信息生成 CSS 插值的函数。
- `getDefaultToken`: 可选,用于检索默认标记的函数或值。
- `options`: 可选,包含额外的配置选项如 `resetStyle`、`resetFont`、`deprecatedTokens`、`clientOnly` 等。

### `genComponentStyleHook(component, styleFn, getDefaultToken?, options?)`

- `component`: 组件名称 `ComponentName` 或组件名称数组 `[ComponentName, ComponentName]`。
- `styleFn`: 根据标记和样式信息生成 CSS 插值的函数。
- `getDefaultToken`: 可选,用于检索默认标记的函数或值。
- `options`: 可选,包含额外的配置选项如 `resetStyle`、`resetFont`、`deprecatedTokens`、`clientOnly` 等。

### `genSubStyleComponent(component, styleFn, getDefaultToken?, options?)`

- `component`: 组件名称 `ComponentName` 或组件名称数组 `[ComponentName, ComponentName]`。
- `styleFn`: 根据标记和样式信息生成 CSS 插值的函数。
- `getDefaultToken`: 可选,用于检索默认标记的函数或值。
- `options`: 可选,包含额外的配置选项如 `resetStyle`、`resetFont`、`deprecatedTokens`、`clientOnly` 等。

## 示例用法

### `genStyleHooks`

```javascript
const useStyle = genStyleHooks('Button', styleFn, getDefaultToken, { resetStyle: true });
const [wrapStyle, hashId] = useStyle('button');
```

### `genComponentStyleHook`

```javascript
const useStyle = genComponentStyleHook('Button', styleFn, getDefaultToken, { clientOnly: true });
const [wrapStyle, hashId] = useStyle('button');
```

### `genSubStyleComponent`

```javascript
const SubButtonStyle = genSubStyleComponent('Button', styleFn, getDefaultToken, { resetFont: true });

() => <SubButtonStyle prefixCls="sub-button" />;
```
Empty file removed docs/examples/.gitkeep
Empty file.
9 changes: 4 additions & 5 deletions package.json
Original file line number Diff line number Diff line change
@@ -1,5 +1,5 @@
{
"name": "@ant-design/cssinjs-util",
"name": "@ant-design/cssinjs-utils",
"version": "1.0.0",
"description": "A cssinjs util library to support Ant Design (antd) and its ecosystem libraries.",
"keywords": [
Expand Down Expand Up @@ -30,15 +30,14 @@
"start": "dumi dev",
"compile": "father build",
"prepublishOnly": "npm run compile && np --yolo --no-publish",
"lint": "eslint src/ docs/examples/ --ext .tsx,.ts,.jsx,.js",
"lint": "eslint src/ --ext .tsx,.ts,.jsx,.js",
"test": "rc-test",
"coverage": "rc-test --coverage"
},
"devDependencies": {
"@testing-library/jest-dom": "^6.1.4",
"@rc-component/father-plugin": "^1.0.1",
"@testing-library/react": "^15.0.4",
"@types/classnames": "^2.2.10",
"@types/jest": "^29.5.2",
"@types/node": "^20.11.6",
"@types/react": "^18.0.0",
Expand All @@ -57,9 +56,9 @@
"typescript": "^5.1.6"
},
"dependencies": {
"@babel/runtime": "^7.23.2",
"@ant-design/cssinjs": "^1.21.0",
"classnames": "^2.3.2",
"@ant-design/fast-color": "^1.2.0",
"@babel/runtime": "^7.23.2",
"rc-util": "^5.38.0"
},
"peerDependencies": {
Expand Down
97 changes: 97 additions & 0 deletions src/_util/hooks/useUniqueMemo.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,97 @@
import React from 'react';

const BEAT_LIMIT = 1000 * 60 * 10;

/**
* A helper class to map keys to values.
* It supports both primitive keys and object keys.
*/
class ArrayKeyMap<T> {
map = new Map<string, T>();

// Use WeakMap to avoid memory leak
objectIDMap = new WeakMap<object, number>();

nextID = 0;

lastAccessBeat = new Map<string, number>();

// We will clean up the cache when reach the limit
accessBeat = 0;

set(keys: React.DependencyList, value: any) {
// New set will trigger clear
this.clear();

// Set logic
const compositeKey = this.getCompositeKey(keys);
this.map.set(compositeKey, value);
this.lastAccessBeat.set(compositeKey, Date.now());
}

get(keys: React.DependencyList) {
const compositeKey = this.getCompositeKey(keys);

const cache = this.map.get(compositeKey);
this.lastAccessBeat.set(compositeKey, Date.now());
this.accessBeat += 1;

return cache;
}

getCompositeKey(keys: React.DependencyList) {
const ids = keys.map<string>((key) => {
if (key && typeof key === 'object') {
return `obj_${this.getObjectID(key)}`;
}
return `${typeof key}_${key}`;
});
return ids.join('|');
}

getObjectID(obj: object) {
if (this.objectIDMap.has(obj)) {
return this.objectIDMap.get(obj);
}
const id = this.nextID;
this.objectIDMap.set(obj, id);

this.nextID += 1;

return id;
}

clear() {
if (this.accessBeat > 10000) {
const now = Date.now();

this.lastAccessBeat.forEach((beat, key) => {
if (now - beat > BEAT_LIMIT) {
this.map.delete(key);
this.lastAccessBeat.delete(key);
}
});

this.accessBeat = 0;
}
}
}

const uniqueMap = new ArrayKeyMap();

/**
* Like `useMemo`, but this hook result will be shared across all instances.
*/
function useUniqueMemo<T>(memoFn: () => T, deps: React.DependencyList) {
return React.useMemo<T>(() => {
const cachedValue = uniqueMap.get(deps);
if (cachedValue) {
return cachedValue as T;
}
const newValue = memoFn();
uniqueMap.set(deps, newValue);
return newValue;
}, deps);
}

export default useUniqueMemo;
10 changes: 10 additions & 0 deletions src/hooks/useCSP.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,10 @@
export type UseCSP = () => {
nonce?: string;
};

/**
* Provide a default hook since not everyone need config this.
*/
const useDefaultCSP: UseCSP = () => ({});

export default useDefaultCSP;
11 changes: 11 additions & 0 deletions src/hooks/usePrefix.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,11 @@
export type UsePrefix = () => {
/**
* All the component use `@ant-design/cssinjs-utils` should have same `rootPrefixCls`.
*/
rootPrefixCls: string;
/**
* `iconPrefixCls` comes from the setting of `@ant-design/icons`.
* Here maybe little coupling but everyone need use this.
*/
iconPrefixCls: string;
};
52 changes: 52 additions & 0 deletions src/hooks/useToken.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,52 @@
import type { Theme, TokenType } from '@ant-design/cssinjs';

import type { OverrideTokenMap, TokenMap } from '../interface';

export type TokenMapWithTheme<
CompTokenMap extends TokenMap,
DesignToken extends TokenType,
AliasToken extends TokenType,
> = {
[key in keyof OverrideTokenMap<CompTokenMap>]?: OverrideTokenMap<CompTokenMap>[key] & {
theme?: Theme<DesignToken, AliasToken>;
};
};

export interface UseTokenReturn<
CompTokenMap extends TokenMap,
DesignToken extends TokenType,
AliasToken extends TokenType,
> {
token: OverrideTokenMap<CompTokenMap>;
realToken?: OverrideTokenMap<CompTokenMap>;
/** Just merge `token` & `override` at top to save perf */
override: { override: OverrideTokenMap<CompTokenMap> };
theme?: Theme<DesignToken, AliasToken>;
components?: TokenMapWithTheme<CompTokenMap, DesignToken, AliasToken>;
hashId?: string;
hashed?: string | boolean;
cssVar?: {
prefix?: string;
key?: string;
};
}

export type UseToken<
CompTokenMap extends TokenMap,
DesignToken extends TokenType,
AliasToken extends TokenType,
> = () => UseTokenReturn<CompTokenMap, DesignToken, AliasToken>;

function useDefaultToken<
CompTokenMap extends TokenMap,
DesignToken extends TokenType,
AliasToken extends TokenType,
> (): UseTokenReturn<CompTokenMap, DesignToken, AliasToken> {
return {
token: {},
override: { override: {} },
hashed: true,
}
};

export default useDefaultToken;
2 changes: 1 addition & 1 deletion src/index.ts
Original file line number Diff line number Diff line change
@@ -1 +1 @@
console.log('Hello world!');
export { default as genStyleUtils } from './util/genStyleUtils';
Empty file removed src/interface/.gitkeep
Empty file.
14 changes: 14 additions & 0 deletions src/interface/components.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,14 @@
import type { TokenType } from '@ant-design/cssinjs';

export type TokenMap = Record<string, TokenType>;

export type TokenMapKey<CompTokenMap extends TokenMap> = Extract<keyof CompTokenMap, string>;

export type OverrideTokenMap<CompTokenMap extends TokenMap> = Partial<CompTokenMap>;

export type GlobalTokenWithComponent<CompTokenMap extends TokenMap, C extends TokenMapKey<CompTokenMap>> = CompTokenMap &
CompTokenMap[C];

export type ComponentToken<CompTokenMap extends TokenMap, C extends TokenMapKey<CompTokenMap>> = Exclude<OverrideTokenMap<CompTokenMap>[C], undefined>;

export type ComponentTokenKey<CompTokenMap extends TokenMap, C extends TokenMapKey<CompTokenMap>> = keyof ComponentToken<CompTokenMap, C>;
10 changes: 10 additions & 0 deletions src/interface/index.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,10 @@
export type {
OverrideTokenMap,
TokenMap,
TokenMapKey,
GlobalTokenWithComponent,
ComponentToken,
ComponentTokenKey,
} from './components';

export type UseComponentStyleResult = [(node: React.ReactNode) => React.ReactElement, string];
Loading
Loading