Skip to content

Commit

Permalink
📝 docs: 补充完善 createStyles 文档
Browse files Browse the repository at this point in the history
  • Loading branch information
arvinxx committed Jun 5, 2023
1 parent 3da1d27 commit a9fc065
Show file tree
Hide file tree
Showing 6 changed files with 303 additions and 33 deletions.
225 changes: 196 additions & 29 deletions docs/api/create-styles.md
Original file line number Diff line number Diff line change
Expand Up @@ -6,52 +6,219 @@ sourceUrl: '{github}/blob/master/src/factories/createStyles/index.ts'
group:
title: 创建样式
order: 0
demo:
tocDepth: 4
---

## 简介
:::success{title=默认推荐}
这是最推荐的使用方式。书写应用样式或者覆写基础组件样式,都可以采用这种写法。
:::

使用 `createStyles` 可以创建具有作用域的的样式。书写能力上和 DX 基本与 CSS Modules 齐平。并在动态主题写法更方便,能力更强。
使用 `createStyles` 可以创建具有作用域的的样式。书写能力上和 DX 基本与 CSS Modules 齐平。并在动态主题写法更方便,能力更强。createStyles 的基础使用方法详见[快速上手 - 样式创建](/guide/create-styles),本节将重点介绍 createStyles 的 API。

:::success{title=默认推荐}
这是第一推荐的使用方式。应用样式书写,或者对基础组件做样式覆写,都可以默认采用这种写法。
<code src="../demos/api/createStyles/default.tsx"></code>

createStyles 方法可以传入一个函数,该函数签名如下:

```ts
type GetCssStyleFn = (utils: CreateStylesUtils, props?: Props) => StyleInput;
```

下面详细介绍每个属性的功能。

## CreateStylesUtils

书写样式时使用的第一个参数 utils,提供了一系列便于样式书写的辅助对象和方法,提高样式书写的效率。它的类型为 CreateStylesUtils ,属性表格如下:

| 属性名 | 类型 | 描述 |
| ---------- | ----------------- | -------------------------------------------------------------------------------------------- |
| css | `CssUtil` | CSS 序列化函数 |
| cx | `ClassNamesUtil` | CSS 类名工具函数 |
| responsive | `ResponsiveUtil` | 响应式媒体查询工具函数 |
| token | `FullToken` | 包含 antd 的 token 和所有自定义 token。 |
| appearance | `ThemeAppearance` | ThemeProvider 下当前的主题模式。 |
| isDarkMode | `boolean` | 语法糖,可以直接使用 isDarkMode 来降低外观的判断成本。 |
| prefixCls | `string` | 在 ThemeProvider 上标记的 prefix,可以拿到当前的组件 prefix,便于更加灵活地响应组件 prefix。 |

### css

类型: `CssUtil`

```typescript
interface CssUtil {
(...styles: (CssObject | undefined | null | boolean)[]): CssObject;
}

interface CssObject {
[key: string]: string | number | CssObject;
}
```

CSS 序列化函数,是 createStyles 中的核心 api。该方法底层基于 `emotion/css` 封装,我们做了诸多能力上的强化,例如 支持多个 css 对象级联( `@emotion/css` 在 v11 之后不再支持级联,相关 [issue](https://github.com/emotion-js/emotion/issues/1186))、支持 `:where` 选择器等。

该序列化函数支持 CSS Object,也支持 CSS String。CSS Object 写法默认可以获得 TS 类型提示, CSS String 写法需要结合 [相关插件](/guide/css-in-js-intro#工程化支持) 获得提示能力。

:::warning{title=注意事项}
@emotion/css 的 css 不同,该方法的产物类型为 SerializedStyles,是无法直接应用到 className 上的。我们在 createStyles 中做了一层转换,最终得到的 `styles.xxx` 是 className 字符串。
:::

## 结合自定义 token 使用
常见问题与讨论:

- [css 方案不支持变量嵌套?](https://github.com/ant-design/antd-style/issues/42)
- [搭配 container 使用的注意事项](https://github.com/ant-design/antd-style/issues/47#issuecomment-1536505984)

### cx

类型: `ClassNamesUtil`

```typescript
interface ClassNamesUtil {
(...classNames: (string | undefined | null | boolean)[]): string;
}
```

基本与等价 emotion/css 中的 [`cx`](https://emotion.sh/docs/@emotion/css#cx) 等价,95% 的使用场景是一样的。只有在搭配 StyleProvider 的 container 使用时需要注意( [相关讨论](https://github.com/ant-design/antd-style/issues/47#issuecomment-1536505984) ),一般情况下不会遇到。

### responsive

类型:`ResponsiveUtil`

```tsx | pure
import { createStyles } from 'antd-style';
```typescript
/**
* 响应式断点工具函数
*/
export interface ResponsiveUtil {
// antd 默认断点

const useStyles = createStyles(({ token, css }) => ({
xxl: string;
xl: string;
lg: string;
md: string;
sm: string;
xs: string;

// 语义化断点

mobile: string; // 对应 xs
tablet: string; // 对应 md
laptop: string; // 对应 lg
desktop: string; // 对应 xxl

/**
* 支持使用函数表达式
* @param breakpoints
*/
(breakpoints: BreakpointMapParams): SerializedStyles;
}
```

该工具函数提供了快捷创建响应式媒体查询的方法。示例如下:

```ts
const useStyles = createStyles(({ css, responsive }) => ({
container: css`
background-color: ${token.colorBgLayout};
padding: 24px;
background-color: lightblue;
${responsive.tablet} {
background: aqua;
}
${responsive.desktop} {
background: darksalmon;
}
${responsive.mobile} {
background: pink;
}
`,
}));
```

const App = () => {
const { styles } = useStyles();
<code src="../demos/api/createStyles/Responsive.tsx"></code>

return (
<div className={styles.container}>
<Space>
<Button title={'功能按钮的说明'} icon={<SmileOutlined />} />
操作按钮
</Space>
</div>
);
};
```
该工具方法的断点遵循 PC-First 原则, 在 xs ~ xl 使用 max-width 查询逻辑,在 xxl 使用 min-width 查询逻辑。

实例演示:
| 断点 | 计算逻辑 |
| ------- | --------------------------------------------- |
| xs | `@media (max-width: ${token.screenXSMax}px)` |
| sm | `@media (max-width: ${token.screenSMMax}px)` |
| md | `@media (max-width: ${token.screenMDMax}px)` |
| lg | `@media (max-width: ${token.screenLGMax}px)` |
| xl | `@media (max-width: ${token.screenXLMax}px)` |
| xxl | `@media (min-width: ${token.screenXXLMin}px)` |
| mobile | xs 的 alias |
| tablet | md 的 alias |
| laptop | lg 的 alias |
| desktop | xxl 的 alias |

<code src="../demos/createStyles/AntdToken.tsx"></code>
### token

入参函数的签名:
类型:`FullToken`

```ts | pure
type GetCssStyleFn = (theme: CreateStylesTheme, props?: Props) => StyleInput;
```ts
interface FullToken extends AntdToken, CustomToken {}
```

包含 antd 的 token 和 ThemeProvider 上自定义 token。相关用法本文档中已有很多,不再赘述。

通过扩展 `CustomToken` 类型可以获得自定义 token 的类型提示。

```ts
interface NewToken {
customBrandColor: string;
}

interface CreateStylesTheme {
token: AntdToken | CustomToken;
// 通过给 antd-style 扩展 CustomToken 对象类型定义,可以为 token 扩展 自定义 token 对象
declare module 'antd-style' {
// eslint-disable-next-line @typescript-eslint/no-empty-interface
export interface CustomToken extends NewToken {}
}
```

### appearance

类型:` 'dark' | 'light' | string`

外层包裹的 ThemeProvider 下的主题模式。

### isDarkMode

类型:`boolean`

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

### prefixCls

类型:` string`

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

```ts
const useStyles = createStyles(({ css, prefixCls }) => {
return {
primary: css`
.${prefixCls}-btn {
border: 12px;
}
`,
};
});
```

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

## ClassNameGeneratorOption

createStyles 的第二个参数可以对生成的 className 做额外的控制。

| 属性名 | 类型 | 描述 |
| ------------ | -------------- | ------------------------------ |
| hashPriority | `HashPriority` | 生成的 hash className 样式权重 |

### hashPriority

类型:`'low' | 'high'`

控制生成的 className 的权重,默认为 `high`

如果设为 `low`,生成 hash 的样式选择器会包裹 :where 选择器,以降低权重。一般来说在组件库的使用场景中可以用到,其他场景不建议使用。
47 changes: 47 additions & 0 deletions docs/demos/api/createStyles/Responsive.tsx
Original file line number Diff line number Diff line change
@@ -0,0 +1,47 @@
/**
* compact: true
* title: 响应式断点
* description: 不同断点下,背景色和文本内容不同
*/
import { createStyles, useResponsive } from 'antd-style';

const useStyles = createStyles(({ css, responsive }) => ({
container: css`
height: 100px;
display: flex;
font-size: 24px;
align-items: center;
justify-content: center;
background-color: lightskyblue;
color: darkblue;
${responsive.tablet} {
background: darkseagreen;
color: darkgreen;
}
${responsive.desktop} {
background: darksalmon;
color: saddlebrown;
}
${responsive.mobile} {
background: pink;
color: deeppink;
}
`,
}));

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

const { laptop, desktop, mobile } = useResponsive();
return (
<div className={styles.container}>
{mobile ? 'mobile' : desktop ? 'desktop' : laptop ? 'laptop' : 'tablet'}
</div>
);
};

export default App;
54 changes: 54 additions & 0 deletions docs/demos/api/createStyles/default.tsx
Original file line number Diff line number Diff line change
@@ -0,0 +1,54 @@
/**
* inherit: true
* defaultShowCode: true
*/
import { SmileOutlined } from '@ant-design/icons';
import { Button, Space } from 'antd';
import { createStyles } from 'antd-style';

const useStyles = createStyles(({ token, css, cx }) => {
const commonCard = css`
border-radius: ${token.borderRadiusLG}px;
padding: ${token.paddingLG}px;
`;

return {
container: css`
background-color: ${token.colorBgLayout};
padding: 24px;
`,

defaultCard: css`
${commonCard};
background: ${token.colorBgContainer};
color: ${token.colorText};
`,

primaryCard: cx(
commonCard,
css`
background: ${token.colorPrimary};
color: ${token.colorTextLightSolid};
`,
),
};
});

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

return (
<div className={styles.container}>
<Space direction={'vertical'} style={{ width: '100%' }} size={16}>
<Space>
<Button title={'功能按钮的说明'} icon={<SmileOutlined />} />
操作按钮
</Space>
<div className={styles.defaultCard}>普通卡片</div>
<div className={styles.primaryCard}>主要卡片</div>
</Space>
</div>
);
};

export default App;
2 changes: 2 additions & 0 deletions docs/demos/createStyles/AntdToken.tsx
Original file line number Diff line number Diff line change
@@ -1,5 +1,7 @@
/**
* inherit: true
* title: 结合 antd token
* description: 当切换站点主题时,均能响应站点主题
*/
import { SmileOutlined } from '@ant-design/icons';
import { Button, Space } from 'antd';
Expand Down
4 changes: 2 additions & 2 deletions docs/guide/create-styles.md
Original file line number Diff line number Diff line change
Expand Up @@ -68,7 +68,7 @@ const useStyles = createStyles(({ token, css }) => {
});
```

demo 示例:(当切换站点主题时,能响应亮色或暗色)
示例:

<code src="../demos/createStyles/AntdToken.tsx"></code>

Expand Down Expand Up @@ -105,7 +105,7 @@ const Select = () => {

<code src="../demos/createStyles/Command/index.tsx" ></code>

## 其他 常用 css 语法
## 其他常用 css 语法

### Keyframes

Expand Down
4 changes: 2 additions & 2 deletions src/factories/createStyles/types.ts
Original file line number Diff line number Diff line change
Expand Up @@ -11,7 +11,7 @@ import type {
/**
* 书写样式时使用的第一个参数
*/
export interface CreateStylesTheme extends CommonStyleUtils {
export interface CreateStylesUtils extends CommonStyleUtils {
/**
* 包含 antd 的 token 和所有自定义 token
*/
Expand Down Expand Up @@ -44,7 +44,7 @@ export interface ReturnStyles<T extends BaseReturnType> extends Pick<CommonStyle

// 获取样式
export type GetStyleFn<Input extends BaseReturnType, Props> = (
theme: CreateStylesTheme,
utils: CreateStylesUtils,
props: Props,
) => Input;

Expand Down

0 comments on commit a9fc065

Please sign in to comment.