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: support iconPrefixCls and prefixCls on createStyles #125

Merged
merged 3 commits into from
Dec 8, 2023
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
24 changes: 15 additions & 9 deletions docs/api/create-styles.en-US.md
Original file line number Diff line number Diff line change
Expand Up @@ -192,19 +192,25 @@ Type: `string`
The prefix marked on the ThemeProvider. By using this parameter, you can flexibly override the antd prefix.

```ts
const useStyles = createStyles(({ css, prefixCls }) => {
return {
primary: css`
.${prefixCls}-btn {
border: 12px;
}
`,
};
});
const useStyles = createStyles(({ css, prefixCls, iconPrefixCls }) => ({
button: css`
&.${prefixCls}-btn {
background: lightsteelblue;
border: none;
color: royalblue;
}

.${iconPrefixCls} {
color: darkblue;
}
`,
}));
```

The above style code can accurately override regardless of the value of the prefixCls wrapped by the outer ThemeProvider.

<code src="../demos/api/createStyles/with-antd-cp.tsx"></code>

## ClassNameGeneratorOption

The second parameter of `createStyles` can be used to control the generated className.
Expand Down
30 changes: 18 additions & 12 deletions docs/api/create-styles.zh-CN.md
Original file line number Diff line number Diff line change
Expand Up @@ -185,25 +185,31 @@ declare module 'antd-style' {

判断亮暗色主题的语法糖,实现上等价于 `appearance === 'dark'`,直接使用 isDarkMode 可以降低外观的判断成本。

### prefixCls
### prefixCls 与 iconPrefixCls

类型:`string`

在 ThemeProvider 上标记的 prefixCls,利用该参数,可以实现灵活的 antd 前缀覆盖。
在 ThemeProvider 上标记的 prefixCls/iconPrefixCls,利用该参数,可以实现灵活的 antd 前缀覆盖。

```ts
const useStyles = createStyles(({ css, prefixCls }) => {
return {
primary: css`
.${prefixCls}-btn {
border: 12px;
}
`,
};
});
const useStyles = createStyles(({ css, prefixCls, iconPrefixCls }) => ({
button: css`
&.${prefixCls}-btn {
background: lightsteelblue;
border: none;
color: royalblue;
}

.${iconPrefixCls} {
color: darkblue;
}
`,
}));
```

上述样式代码,无论外层包裹的 ThemeProvider prefixCls 改成什么值,均可准确覆盖到。
上述样式代码,无论是包裹的 `ThemeProvider` / `ConfigProvider` prefixCls 改成什么值,均可准确覆盖到。

<code src="../demos/api/createStyles/with-antd-cp.tsx"></code>

## ClassNameGeneratorOption

Expand Down
32 changes: 32 additions & 0 deletions docs/demos/api/createStyles/with-antd-cp.tsx
Original file line number Diff line number Diff line change
@@ -0,0 +1,32 @@
import { SmileOutlined } from '@ant-design/icons';
import { Button, ConfigProvider } from 'antd';
import { createStyles } from 'antd-style';

const useStyles = createStyles(({ css, prefixCls, iconPrefixCls }) => ({
button: css`
&.${prefixCls}-btn {
background: lightsteelblue;
border: none;
color: royalblue;
}

.${iconPrefixCls} {
color: darkblue;
}
`,
}));

const App = () => {
const { styles } = useStyles();

return (
<Button className={styles.button} icon={<SmileOutlined />}>
CP Button
</Button>
);
};
export default () => (
<ConfigProvider prefixCls={'cp'} iconPrefixCls={'cpicon'}>
<App />
</ConfigProvider>
);
4 changes: 2 additions & 2 deletions package.json
Original file line number Diff line number Diff line change
Expand Up @@ -96,7 +96,7 @@
"@types/react-dom": "^18",
"@types/testing-library__jest-dom": "^5",
"@umijs/lint": "^4",
"@vitest/coverage-v8": "latest",
"@vitest/coverage-v8": "0.34.6",
"antd": "^5",
"babel-plugin-antd-style": "^1",
"chalk": "^4",
Expand Down Expand Up @@ -133,7 +133,7 @@
"ts-node": "^10",
"typescript": "^5",
"vite": "^4.5.0",
"vitest": "latest",
"vitest": "0.34.6",
"zustand": "^4"
},
"peerDependencies": {
Expand Down
7 changes: 4 additions & 3 deletions src/factories/createStyles/index.ts
Original file line number Diff line number Diff line change
Expand Up @@ -57,7 +57,7 @@ export const createStylesFactory =

// 函数场景
if (styleOrGetStyle instanceof Function) {
const { stylish, appearance, isDarkMode, prefixCls, ...token } = theme;
const { stylish, appearance, isDarkMode, prefixCls, iconPrefixCls, ...token } = theme;

// 创建响应式断点选择器的工具函数
// @ts-ignore
Expand All @@ -73,6 +73,7 @@ export const createStylesFactory =
appearance,
isDarkMode,
prefixCls,
iconPrefixCls,
// 工具函数们
cx,
css: serializeCSS,
Expand Down Expand Up @@ -121,8 +122,8 @@ export const createStylesFactory =
}, [props, theme]);

return useMemo(() => {
const { prefixCls, ...res } = theme;
return { styles, cx, theme: res, prefixCls };
const { prefixCls, iconPrefixCls, ...res } = theme;
return { styles, cx, theme: res, prefixCls, iconPrefixCls };
}, [styles, theme]);
};
};
2 changes: 2 additions & 0 deletions src/factories/createStyles/types.ts
Original file line number Diff line number Diff line change
Expand Up @@ -31,6 +31,7 @@ export interface CreateStylesUtils extends CommonStyleUtils {
* @default ant
*/
prefixCls: string;
iconPrefixCls: string;
}

/**
Expand All @@ -39,6 +40,7 @@ export interface CreateStylesUtils extends CommonStyleUtils {
export interface ReturnStyles<T extends BaseReturnType> extends Pick<CommonStyleUtils, 'cx'> {
styles: ReturnStyleToUse<T>;
theme: Omit<Theme, 'prefixCls'>;
iconPrefixCls: string;
prefixCls: string;
}

Expand Down
2 changes: 1 addition & 1 deletion src/factories/createThemeProvider/TokenContainer.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -20,7 +20,7 @@ const TokenContainer: <T, S>(props: TokenContainerProps<T, S>) => ReactElement |
customToken: customTokenOrFn,
defaultCustomToken: defaultCustomTokenFn,
customStylish: stylishOrGetStylish,
prefixCls = 'ant',
prefixCls,
StyledThemeProvider,
}) => {
const themeState = useThemeMode();
Expand Down
1 change: 1 addition & 0 deletions src/factories/createThemeProvider/index.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -63,6 +63,7 @@ export const createThemeProvider = (
onThemeModeChange,
styled,
}) => {
// 从上一层的 Context 中获取上下文信息,以实现嵌套继承的效果
const {
prefixCls: defaultPrefixCls,
StyledThemeContext,
Expand Down
19 changes: 15 additions & 4 deletions src/factories/createUseTheme.ts
Original file line number Diff line number Diff line change
Expand Up @@ -4,35 +4,46 @@ import { Context, useContext, useMemo } from 'react';
import { DEFAULT_THEME_CONTEXT } from '@/functions/setupStyled';
import { useAntdTheme } from '@/hooks/useAntdTheme';
import { useThemeMode } from '@/hooks/useThemeMode';
import { ConfigProvider } from 'antd';

interface CreateUseThemeOptions {
StyleEngineContext: Context<StyleEngine>;
}

export const createUseTheme = (options: CreateUseThemeOptions) => (): Theme => {
const { StyleEngineContext } = options;
const { StyledThemeContext, CustomThemeContext, prefixCls } = useContext(StyleEngineContext);
const {
StyledThemeContext,
CustomThemeContext,
prefixCls: outPrefixCls,
} = useContext(StyleEngineContext);

const antdTheme = useAntdTheme();
const themeState = useThemeMode();

const defaultCustomTheme = useContext(CustomThemeContext);
const styledTheme = useContext(StyledThemeContext ?? DEFAULT_THEME_CONTEXT) || {};

const { iconPrefixCls, getPrefixCls } = useContext(ConfigProvider.ConfigContext);

const antdPrefixCls = getPrefixCls();
const prefixCls = outPrefixCls ?? antdPrefixCls;

const initTheme = useMemo<Theme>(
() => ({
...antdTheme,
...themeState,
...defaultCustomTheme,
prefixCls: prefixCls || 'ant',
prefixCls,
iconPrefixCls,
}),
[antdTheme, themeState, prefixCls, defaultCustomTheme],
[antdTheme, themeState, defaultCustomTheme, prefixCls, iconPrefixCls],
);

// 如果是个空值,说明没有套 Provider,返回 antdTheme 的默认值
if (!styledTheme || Object.keys(styledTheme).length === 0) {
return initTheme;
}

return styledTheme as Theme;
return { ...styledTheme, prefixCls, iconPrefixCls } as Theme;
};
2 changes: 2 additions & 0 deletions src/functions/createInstance.ts
Original file line number Diff line number Diff line change
Expand Up @@ -34,6 +34,7 @@ export interface CreateOptions<T> {
* 默认的组件 prefixCls
*/
prefixCls?: string;
iconPrefixCls?: string;
/**
* 是否开启急速模式
*
Expand Down Expand Up @@ -87,6 +88,7 @@ export const createInstance = <T = any>(options: CreateOptions<T>) => {
CustomThemeContext,
StyledThemeContext: styledThemeContext,
prefixCls: internalOptions?.prefixCls,
iconPrefixCls: internalOptions?.iconPrefixCls,
});

const useTheme = createUseTheme({ StyleEngineContext });
Expand Down
1 change: 1 addition & 0 deletions src/types/styled.ts
Original file line number Diff line number Diff line change
Expand Up @@ -35,4 +35,5 @@ export interface StyleEngine {
* @description 当前组件的 CSS 类名前缀
*/
prefixCls?: string;
iconPrefixCls?: string;
}
3 changes: 2 additions & 1 deletion src/types/theme.ts
Original file line number Diff line number Diff line change
@@ -1,4 +1,4 @@
import { ThemeConfig, MappingAlgorithm } from 'antd';
import { MappingAlgorithm, ThemeConfig } from 'antd';
import { AliasToken } from 'antd/es/theme/interface';

import { BrowserPrefers, ThemeAppearance, ThemeMode } from './appearance';
Expand Down Expand Up @@ -76,4 +76,5 @@ export interface Theme extends FullToken, ThemeContextState {
* antd 组件的 prefixCls
*/
prefixCls: string;
iconPrefixCls: string;
}
44 changes: 44 additions & 0 deletions tests/functions/__snapshots__/createStyles.test.tsx.snap
Original file line number Diff line number Diff line change
Expand Up @@ -13,6 +13,50 @@ exports[`createStyles > styles 对象的使用 > createStyleFn 通过函数方
</div>
`;

exports[`createStyles > styles 对象的使用 > createStyleFn 通过函数方式可以拿到 token 等信息 > 可以获取 prefixCls 与 iconPrefixCls 1`] = `
.emotion-0.cp-btn {
background: lightsteelblue;
border: none;
color: royalblue;
}

.emotion-0 .cpicon {
color: darkblue;
}

<button
class="cp-btn cp-btn-default emotion-0"
type="button"
>
<span
class="cp-btn-icon"
>
<span
aria-label="smile"
class="cpicon cpicon-smile"
role="img"
>
<svg
aria-hidden="true"
data-icon="smile"
fill="currentColor"
focusable="false"
height="1em"
viewBox="64 64 896 896"
width="1em"
>
<path
d="M288 421a48 48 0 1096 0 48 48 0 10-96 0zm352 0a48 48 0 1096 0 48 48 0 10-96 0zM512 64C264.6 64 64 264.6 64 512s200.6 448 448 448 448-200.6 448-448S759.4 64 512 64zm263 711c-34.2 34.2-74 61-118.3 79.8C611 874.2 562.3 884 512 884c-50.3 0-99-9.8-144.8-29.2A370.4 370.4 0 01248.9 775c-34.2-34.2-61-74-79.8-118.3C149.8 611 140 562.3 140 512s9.8-99 29.2-144.8A370.4 370.4 0 01249 248.9c34.2-34.2 74-61 118.3-79.8C413 149.8 461.7 140 512 140c50.3 0 99 9.8 144.8 29.2A370.4 370.4 0 01775.1 249c34.2 34.2 61 74 79.8 118.3C874.2 413 884 461.7 884 512s-9.8 99-29.2 144.8A368.89 368.89 0 01775 775zM664 533h-48.1c-4.2 0-7.8 3.2-8.1 7.4C604 589.9 562.5 629 512 629s-92.1-39.1-95.8-88.6c-.3-4.2-3.9-7.4-8.1-7.4H360a8 8 0 00-8 8.4c4.4 84.3 74.5 151.6 160 151.6s155.6-67.3 160-151.6a8 8 0 00-8-8.4z"
/>
</svg>
</span>
</span>
<span>
CP Button
</span>
</button>
`;

exports[`createStyles > styles 对象的使用 > createStyleFn 通过函数方式可以拿到 token 等信息 > 字符串模板的对象模式用法 1`] = `
.emotion-0 {
background-color: #f5f5f5;
Expand Down
41 changes: 40 additions & 1 deletion tests/functions/createStyles.test.tsx
Original file line number Diff line number Diff line change
@@ -1,5 +1,7 @@
import { SmileOutlined } from '@ant-design/icons';
import { render } from '@testing-library/react';
import { createStyles, css, GetCustomToken, ThemeProvider } from 'antd-style';
import { Button, ConfigProvider } from 'antd';
import { GetCustomToken, ThemeProvider, createStyles, css } from 'antd-style';
import { FC, PropsWithChildren } from 'react';

describe('createStyles', () => {
Expand Down Expand Up @@ -51,6 +53,43 @@ describe('createStyles', () => {
expect(container.firstChild).toMatchSnapshot();
expect(container.firstChild).toHaveStyle({ backgroundColor: '#fff' });
});

it('可以获取 prefixCls 与 iconPrefixCls', () => {
const useStyles = createStyles(({ css, prefixCls, iconPrefixCls }) => {
return {
button: css`
&.${prefixCls}-btn {
background: lightsteelblue;
border: none;
color: royalblue;
}

.${iconPrefixCls} {
color: darkblue;
}
`,
};
});

const App = () => {
const { styles } = useStyles();

return (
<Button className={styles.button} icon={<SmileOutlined />}>
CP Button
</Button>
);
};
const wrapper = ({ children }: PropsWithChildren) => (
<ConfigProvider prefixCls={'cp'} iconPrefixCls={'cpicon'}>
{children}
</ConfigProvider>
);

const { container } = render(<App />, { wrapper });

expect(container.firstChild).toMatchSnapshot();
});
});

describe('styleObject 方法', () => {
Expand Down