From 6f838605a89ee4876a9f92afb1a09da2abcccd85 Mon Sep 17 00:00:00 2001 From: Arvin Xu Date: Fri, 24 Nov 2023 09:47:43 +0800 Subject: [PATCH] :memo: docs: add English documents with lobe-i18n (#124) * :memo: docs: add english document with lobe-i18n * :memo: docs: add english document with lobe-i18n * :memo: docs: fix docs --- .i18nrc.js | 12 + README.md | 121 +++++++++ docs/api/create-instance.en-US.md | 112 +++++++++ docs/api/create-instance.zh-CN.md | 3 + docs/api/create-styles.en-US.md | 231 +++++++++++++++++ docs/api/create-styles.zh-CN.md | 4 +- docs/api/create-stylish.en-US.md | 27 ++ docs/api/global-styles.en-US.md | 20 ++ docs/api/setup-styled.en-US.md | 7 + docs/api/style-provider.en-US.md | 50 ++++ docs/api/theme-provider.en-US.md | 209 ++++++++++++++++ docs/api/use-responsive.en-US.md | 32 +++ docs/api/use-theme-mode.en-US.md | 70 ++++++ docs/api/use-theme.en-US.md | 43 ++++ docs/api/use-theme.zh-CN.md | 1 - .../antd-based-components.en-US.md | 8 + docs/best-practice/antd-override.en-US.md | 45 ++++ docs/best-practice/clay.en-US.md | 8 + .../best-practice/custom-token-types.en-US.md | 53 ++++ .../fix-switch-theme-fouc.en-US.md | 76 ++++++ docs/best-practice/index.en-US.md | 14 ++ docs/best-practice/mac-select.en-US.md | 12 + .../mirgration-less-global-style.en-US.md | 50 ++++ .../best-practice/nest-element-style.en-US.md | 49 ++++ docs/best-practice/static-message.en-US.md | 48 ++++ docs/best-practice/styled.en-US.md | 10 + docs/changelog.en-US.md | 8 + docs/guide/babel-plugin.en-US.md | 39 +++ docs/guide/compare.en-US.md | 224 +++++++++++++++++ docs/guide/components-usage.en-US.md | 129 ++++++++++ docs/guide/create-styles.en-US.md | 114 +++++++++ docs/guide/css-in-js-intro.en-US.md | 161 ++++++++++++ .../cssinjs-compiler-difference.en-US.md | 11 + docs/guide/custom-theme.en-US.md | 138 +++++++++++ docs/guide/index.en-US.md | 32 +++ docs/guide/migrate-less-application.en-US.md | 149 +++++++++++ docs/guide/migrate-less-codemod.en-US.md | 41 +++ docs/guide/migrate-less-component.en-US.md | 127 ++++++++++ docs/guide/performance-comparsion.en-US.md | 39 +++ docs/guide/ssr.en-US.md | 233 ++++++++++++++++++ docs/guide/strategy.en-US.md | 92 +++++++ docs/guide/styled.en-US.md | 144 +++++++++++ docs/guide/stylish.en-US.md | 9 + docs/guide/switch-theme.en-US.md | 127 ++++++++++ docs/index.md | 71 ++++++ package.json | 4 +- 46 files changed, 3202 insertions(+), 5 deletions(-) create mode 100644 .i18nrc.js create mode 100644 README.md create mode 100644 docs/api/create-instance.en-US.md create mode 100644 docs/api/create-styles.en-US.md create mode 100644 docs/api/create-stylish.en-US.md create mode 100644 docs/api/global-styles.en-US.md create mode 100644 docs/api/setup-styled.en-US.md create mode 100644 docs/api/style-provider.en-US.md create mode 100644 docs/api/theme-provider.en-US.md create mode 100644 docs/api/use-responsive.en-US.md create mode 100644 docs/api/use-theme-mode.en-US.md create mode 100644 docs/api/use-theme.en-US.md create mode 100644 docs/best-practice/antd-based-components.en-US.md create mode 100644 docs/best-practice/antd-override.en-US.md create mode 100644 docs/best-practice/clay.en-US.md create mode 100644 docs/best-practice/custom-token-types.en-US.md create mode 100644 docs/best-practice/fix-switch-theme-fouc.en-US.md create mode 100644 docs/best-practice/index.en-US.md create mode 100644 docs/best-practice/mac-select.en-US.md create mode 100644 docs/best-practice/mirgration-less-global-style.en-US.md create mode 100644 docs/best-practice/nest-element-style.en-US.md create mode 100644 docs/best-practice/static-message.en-US.md create mode 100644 docs/best-practice/styled.en-US.md create mode 100644 docs/changelog.en-US.md create mode 100644 docs/guide/babel-plugin.en-US.md create mode 100644 docs/guide/compare.en-US.md create mode 100644 docs/guide/components-usage.en-US.md create mode 100644 docs/guide/create-styles.en-US.md create mode 100644 docs/guide/css-in-js-intro.en-US.md create mode 100644 docs/guide/cssinjs-compiler-difference.en-US.md create mode 100644 docs/guide/custom-theme.en-US.md create mode 100644 docs/guide/index.en-US.md create mode 100644 docs/guide/migrate-less-application.en-US.md create mode 100644 docs/guide/migrate-less-codemod.en-US.md create mode 100644 docs/guide/migrate-less-component.en-US.md create mode 100644 docs/guide/performance-comparsion.en-US.md create mode 100644 docs/guide/ssr.en-US.md create mode 100644 docs/guide/strategy.en-US.md create mode 100644 docs/guide/styled.en-US.md create mode 100644 docs/guide/stylish.en-US.md create mode 100644 docs/guide/switch-theme.en-US.md create mode 100644 docs/index.md diff --git a/.i18nrc.js b/.i18nrc.js new file mode 100644 index 00000000..e7789967 --- /dev/null +++ b/.i18nrc.js @@ -0,0 +1,12 @@ +/** + * @type {import("@lobehub/i18n-cli").Config} + */ +module.exports = { + markdown: { + entry: ['docs/**/**.md', './README.zh-CN.md'], + entryLocale: 'zh-CN', + entryExtension: '.zh-CN.md', + outputLocales: ['en-US'], + }, + modelName: 'gpt-3.5-turbo-1106', +}; diff --git a/README.md b/README.md new file mode 100644 index 00000000..73feda27 --- /dev/null +++ b/README.md @@ -0,0 +1,121 @@ +# antd-style + +[![NPM version][npm-image]][npm-url] [![NPM downloads][download-image]][download-url] [![install size][npm-size]][npm-size-url] + +[![Test CI status][test-ci]][test-ci-url] [![Rlease CI][release-ci]][release-ci-url] [![Coverage][coverage]][codecov-url] + +[![ docs by dumi][dumi-url]](https://d.umijs.org/) [![Build With father][father-url]](https://github.com/umijs/father/) + + + + + + + + + + + +## Introduction + +A business-level `css-in-js` solution built on the Ant Design V5 Token System. It is based on [emotion](https://emotion.sh/) at the bottom. + +- **๐Ÿงฉ Token System**: Default integration of Ant Design V5 Token System, making style customization easy, and token consumption flexible and easy to use; +- **๐ŸŒ“ One-click Dark Mode Switching**: Based on antd v5 cssinjs dynamic theme configuration and dark theme algorithm encapsulation, it provides an easy-to-use light and dark theme switching capability for application-level scenarios, making it easier to use; +- **๐ŸŽจ Flexible Custom Theme Extension**: Ant Design Style provides the functionality of custom tokens and custom styles. When the default tokens of antd cannot meet the style requirements, you can flexibly extend your own theme system and freely consume it in CSS in JS; +- **๐Ÿ‚ Smooth Migration from less**: Need to migrate an old project? Using antd-style can smoothly migrate less in the project to CSS in JS at a lower cost, and provide a better user experience and development experience; +- **โ˜ฏ๏ธ Good Compatibility with Micro-Apps**: Ant Design Style is compatible with qiankun micro-apps by default (but may sacrifice some performance). At the same time, it provides performance optimization options for scenarios that do not require micro-apps; +- **๐Ÿ“ฑ Easy Adaptation for Responsive Design**: Ant Design Style will provide convenient utility functions for responsive applications, helping developers quickly complete responsive theme development; +- **๐Ÿชด Stylish**: Ant Design Style provides the ability to compose complex interactive styles through the combination of multiple atomic tokens, achieving a high degree of reusability; +- **๐ŸŒฐ Documentation and Application Examples**: Show various examples of components and applications using Ant Design Style, helping developers get started quickly. (This document is also built using Ant Design Style for styling) + +## Quick Start + +### Installation + +It is recommended to install using `pnpm` + +```bash +pnpm i antd-style -S +``` + +### Typical Use Cases + +#### Create Styles + +```tsx +import { createStyles } from 'antd-style'; + +const useStyles = createStyles(({ token, css }) => ({ + // Supports the writing style of css object + container: { + backgroundColor: token.colorBgLayout, + borderRadius: token.borderRadiusLG, + maxWidth: 400, + width: '100%', + height: 180, + display: 'flex', + alignItems: 'center', + justifyContent: 'center', + flexDirection: 'column', + marginLeft: 'auto', + marginRight: 'auto', + }, + // Also supports obtaining the same writing experience as normal css through css string templates + card: css` + box-shadow: ${token.boxShadow}; + padding: ${token.padding}px; + border-radius: ${token.borderRadius}px; + color: ${token.colorTextTertiary}; + background: ${token.colorBgContainer}; + transition: all 100ms ${token.motionEaseInBack}; + + margin-bottom: 8px; + cursor: pointer; + + &:hover { + color: ${token.colorTextSecondary}; + box-shadow: ${token.boxShadowSecondary}; + } + `, +})); + +export default () => { + // The styles object in the useStyles method is cached by default, so there is no need to worry about re-rendering issues + const { styles, cx, theme } = useStyles(); + + return ( + // Use cx to organize className +
+
createStyles Demo
+ {/* The theme object contains all token and theme information */} +
Current theme mode: {theme.appearance}
+
+ ); +}; +``` + +## CHANGELOG + +Details: [CHANGELOG](./CHANGELOG.md) + +## License + +[MIT](./LICENSE) + +[gitpod-badge]: https://img.shields.io/badge/Gitpod-ready--to--code-blue?logo=gitpod +[gitpod-url]: https://gitpod.io/#https://github.com/ant-design/antd-style +[dumi-url]: https://img.shields.io/badge/docs%20by-dumi-blue +[father-url]: https://img.shields.io/badge/build%20with-father-028fe4.svg +[npm-image]: http://img.shields.io/npm/v/antd-style.svg?style=flat-square&color=deepgreen&label=latest +[npm-url]: http://npmjs.org/package/antd-style +[npm-size]: https://img.shields.io/bundlephobia/minzip/antd-style?color=deepgreen&label=gizpped%20size&style=flat-square +[npm-size-url]: https://packagephobia.com/result?p=antd-style +[coverage]: https://codecov.io/gh/ant-design/antd-style/branch/master/graph/badge.svg +[codecov-url]: https://codecov.io/gh/ant-design/antd-style/branch/master +[test-ci]: https://github.com/ant-design/antd-style/actions/workflows/test.yml/badge.svg +[release-ci]: https://github.com/ant-design/antd-style/actions/workflows/release.yml/badge.svg +[test-ci-url]: https://github.com/ant-design/antd-style/actions/workflows/test.yml +[release-ci-url]: https://github.com/ant-design/antd-style/actions/workflows/release.yml +[download-image]: https://img.shields.io/npm/dm/antd-style.svg?style=flat-square +[download-url]: https://npmjs.org/package/antd-style diff --git a/docs/api/create-instance.en-US.md b/docs/api/create-instance.en-US.md new file mode 100644 index 00000000..4bbf8352 --- /dev/null +++ b/docs/api/create-instance.en-US.md @@ -0,0 +1,112 @@ +--- +title: createInstance +description: Method for creating style instances +sourceUrl: '{github}/blob/master/src/functions/createInstance.ts' +group: + title: Advanced Settings + order: 10 +nav: + title: API Reference + order: 10 +--- + +## Introduction + +The `createInstance` method can be used to create another set of style instance methods. This method is basically unnecessary for applying style schemes, but it is essential for component development scenarios. + +## Creating Style Instances + +Create your own style instance for the component, so that when using the component library, you can automatically obtain a set of style methods with default values configured. + +```ts | pure +import { createInstance } from 'antd-style'; + +interface DefaultToken { + accessColor: string; +} + +const styleInstance = createInstance({ + // **** Style Generation Related **** // + + key: 'abc', // Set the prefix for generating hash class names, the result will be .abc-xxxx + speedy: false, // Currently, the default cssom insertion method in the cssinjs solution is not very compatible with qiankun micro-apps, so it is recommended to disable it + hashPriority: 'low', // Set the style selector that generates hash to :where selector to reduce weight. This allows user-defined styles to override component styles + + // ***** Theme Related ***** // + // Configure the props passed to the ThemeProvider by default, and this Provider can also be overridden by external props + // The configured value will also become the default value consumed by related methods, so there is no need to wrap ThemeProvider to consume the default value + + prefixCls: 'tna', // Set the class name prefix for antd components, for example, the type of Button will be .tna-btn + customToken: { + accessColor: '#12388f', + }, +}); + +export const { + // **** Core Style Methods **** // + createStyles, + createStylish, + createGlobalStyle, + + // **** Basic Style Methods **** // + cx, + css, + keyframes, + injectGlobal, + + //**** Style Sheet Management **** // + styleManager, + + // **** Data Container **** // + useTheme, + StyleProvider, + ThemeProvider, +} = styleInstance; +``` + +## Specify Container + +Specifying a container during creation can ensure that styles are inserted at that container, which is useful in scenarios such as iframes. + +```ts +const { css, StyleProvider, createStyles } = createInstance({ + key: 'test', + container: document.body, +}); +``` + + + +If you define styles with `createStyles` exposed by `createInstance` in a component library, and then want to specify different insertion positions in different business scenarios. + +Then, when using in the business application, wrap a layer of `StyleProvider` externally and set `container` to achieve custom insertion positions. + + + +## Compatible with styled Themes + +If you use `styled-component` and need to respond to theme changes, you need to wrap a `ThemeProvider` outside the component. At this time, if your component also needs to respond to theme changes, you need to wrap another `ThemeProvider` inside the component. By passing the `styled` configuration to createInstance, you can make the component styled with `styled` respond to custom Tokens. + +```ts | pure +// styled-components version +import { createInstance } from 'antd-style'; +import { ThemeContext } from 'styled-components'; + +const componentStyleIntanceWithSC = createInstance({ + // ... + styled: { ThemeContext }, +}); +``` + +## API + +| Property Name | Type | Description | +| ------------- | ----------------------------------------- | -------------------------------------------------- | +| key | `string` | The generated CSS keyword, default is `ant-css`. | +| prefixCls | `string` | Default component prefix. | +| speedy | `boolean` | Whether to enable speedy mode, default is `false`. | +| container | `Node` | Rendering container node. | +| customToken | `T` | Default custom Token. | +| hashPriority | `HashPriority` | Control the priority of CSS class name generation. | +| ThemeProvider | `Omit, 'children'>` | Theme provider. | +| styled | `StyledConfig` | `styled-components` configuration. | diff --git a/docs/api/create-instance.zh-CN.md b/docs/api/create-instance.zh-CN.md index 903fb6cf..1edc14ae 100644 --- a/docs/api/create-instance.zh-CN.md +++ b/docs/api/create-instance.zh-CN.md @@ -5,6 +5,9 @@ sourceUrl: '{github}/blob/master/src/functions/createInstance.ts' group: title: ้ซ˜็บง่ฎพ็ฝฎ order: 10 +nav: + title: API + order: 10 --- ## ็ฎ€ไป‹ diff --git a/docs/api/create-styles.en-US.md b/docs/api/create-styles.en-US.md new file mode 100644 index 00000000..69e3d2c9 --- /dev/null +++ b/docs/api/create-styles.en-US.md @@ -0,0 +1,231 @@ +--- +title: createStyles +description: Create scoped styles +order: 0 +sourceUrl: '{github}/blob/master/src/factories/createStyles/index.ts' +group: Creating Styles +demo: + tocDepth: 4 +--- + +:::success{title=Default Recommendation} +This is the most recommended usage. It can be used to write application styles or override basic component styles. +::: + +The `createStyles` function can be used to create scoped styles. In terms of writing ability and developer experience (DX), it is comparable to CSS Modules. It is also more convenient and powerful for dynamic theme writing. For the basic usage of `createStyles`, please refer to [Quick Start - Style Creation](/guide/create-styles). This section will focus on the API of `createStyles`. + + + +The `createStyles` function can take a function as an argument, and the signature of this function is as follows: + +```ts +type GetCssStyleFn = (utils: CreateStylesUtils, props?: Props) => StyleInput; +``` + +The functionality of each property is detailed below. + +## CreateStylesUtils + +The first parameter `utils` used when writing styles provides a series of auxiliary objects and methods to facilitate efficient style writing. Its type is `CreateStylesUtils`, and the properties are listed in the table below: + +| Property | Type | Description | +| ---------- | ----------------- | --------------------------------------------------------------------------------------------------- | +| css | `CssUtil` | CSS serialization function | +| cx | `ClassNamesUtil` | CSS class name utility function | +| responsive | `ResponsiveUtil` | Responsive media query utility function | +| token | `FullToken` | Includes antd tokens and all custom tokens | +| appearance | `ThemeAppearance` | Current theme mode under the ThemeProvider | +| isDarkMode | `boolean` | A syntactic sugar that can be used to reduce the cost of appearance judgment | +| prefixCls | `string` | The prefix marked on the ThemeProvider, which can be used to flexibly respond to component prefixes | + +### css + +Type: `CssUtil` + +```typescript +interface CssUtil { + (...styles: (CssObject | undefined | null | boolean)[]): CssObject; +} + +interface CssObject { + [key: string]: string | number | CssObject; +} +``` + +The CSS serialization function is the core API in `createStyles`. This method is based on the encapsulation of `emotion/css`, and we have enhanced many capabilities, such as supporting cascading of multiple CSS objects (after v11, `@emotion/css` no longer supports cascading, see related [issue](https://github.com/emotion-js/emotion/issues/1186)), and supporting the `:where` selector. + +This serialization function supports both CSS Object and CSS String. The CSS Object syntax can provide TypeScript type hints by default, while the CSS String syntax needs to be combined with [related plugins](/guide/css-in-js-intro#engineering-support) to provide hinting capabilities. + +:::warning{title=Note} +Unlike the `css` method in @emotion/css, the type of the result of this method is `SerializedStyles`, which cannot be directly applied to a className. We have added a layer of conversion in `createStyles`, and the final `styles.xxx` obtained is a className string. +::: + +Common issues and discussions: + +- [Does the css solution support variable nesting?](https://github.com/ant-design/antd-style/issues/42) +- [Points to note when used with container](https://github.com/ant-design/antd-style/issues/47#issuecomment-1536505984) + +### cx + +Type: `ClassNamesUtil` + +```typescript +interface ClassNamesUtil { + (...classNames: (string | undefined | null | boolean)[]): string; +} +``` + +It is basically equivalent to the `cx` in `emotion/css` ([related link](https://emotion.sh/docs/@emotion/css#cx)), and is used in 95% of the same scenarios. It is only necessary to pay attention when using it with the container of StyleProvider ([related discussion](https://github.com/ant-design/antd-style/issues/47#issuecomment-1536505984)), which is not encountered in general situations. + +### responsive + +Type: `ResponsiveUtil` + +```typescript +/** + * Responsive breakpoint utility function + */ +export interface ResponsiveUtil { + // Default breakpoints in antd + + xxl: string; + xl: string; + lg: string; + md: string; + sm: string; + xs: string; + + // Semantic breakpoints + + mobile: string; // Corresponds to xs + tablet: string; // Corresponds to md + laptop: string; // Corresponds to lg + desktop: string; // Corresponds to xxl + + /** + * Supports the use of function expressions + * @param breakpoints + */ + (breakpoints: BreakpointMapParams): SerializedStyles; +} +``` + +This utility function provides a convenient way to create responsive media queries. An example is as follows: + +```ts +const useStyles = createStyles(({ css, responsive }) => ({ + container: css` + background-color: lightblue; + + ${responsive.tablet} { + background: aqua; + } + + ${responsive.desktop} { + background: darksalmon; + } + + ${responsive.mobile} { + background: pink; + } + `, +})); +``` + + + +The breakpoints of this utility function follow the PC-First principle, using max-width query logic for xs to xl, and min-width query logic for xxl. + +| Breakpoint | Calculation Logic | +| ---------- | --------------------------------------------- | +| 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 | Alias for xs | +| tablet | Alias for md | +| laptop | Alias for lg | +| desktop | Alias for xxl | + +### token + +Type: `FullToken` + +```ts +interface FullToken extends AntdToken, CustomToken {} +``` + +It includes antd tokens and custom tokens on the ThemeProvider. There are many related usages in this document, so they will not be repeated here. + +By extending the `CustomToken` type, you can get type hints for custom tokens. + +```ts +interface NewToken { + customBrandColor: string; +} + +// By extending the CustomToken object type definition for antd-style, you can extend custom token objects for tokens +declare module 'antd-style' { + // eslint-disable-next-line @typescript-eslint/no-empty-interface + export interface CustomToken extends NewToken {} +} +``` + +### appearance + +Type: `'dark' | 'light' | string` + +The theme mode under the outermost ThemeProvider. + +### isDarkMode + +Type: `boolean` + +A syntactic sugar for judging light and dark theme modes, which is equivalent to `appearance === 'dark'`. Using `isDarkMode` directly can reduce the cost of appearance judgment. + +### prefixCls + +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; + } + `, + }; +}); +``` + +The above style code can accurately override regardless of the value of the prefixCls wrapped by the outer ThemeProvider. + +## ClassNameGeneratorOption + +The second parameter of `createStyles` can be used to control the generated className. + +| Property | Type | Description | +| ------------ | -------------- | --------------------------------------------- | +| hashPriority | `HashPriority` | Weight of the generated hash className styles | +| label | `string` | Add a suffix | + +### hashPriority + +Type: `'low' | 'high'` + +Controls the weight of the generated className, defaulting to `high`. + +If set to `low`, the generated hash style selector will be wrapped with the `:where` selector to reduce its weight. Generally, this can be used in component library scenarios, but it is not recommended for other scenarios. + +### label + +Type: `string` + +Similar to the label in emotion. After adding a label, it will be added to the suffix. Generally, it is not necessary to use. + + diff --git a/docs/api/create-styles.zh-CN.md b/docs/api/create-styles.zh-CN.md index f9a7706b..758b7253 100644 --- a/docs/api/create-styles.zh-CN.md +++ b/docs/api/create-styles.zh-CN.md @@ -3,9 +3,7 @@ title: createStyles description: ๅˆ›ๅปบๅ…ทๆœ‰ไฝœ็”จๅŸŸ็š„ๆ ทๅผ order: 0 sourceUrl: '{github}/blob/master/src/factories/createStyles/index.ts' -group: - title: ๅˆ›ๅปบๆ ทๅผ - order: 0 +group: ๅˆ›ๅปบๆ ทๅผ demo: tocDepth: 4 --- diff --git a/docs/api/create-stylish.en-US.md b/docs/api/create-stylish.en-US.md new file mode 100644 index 00000000..fec65f87 --- /dev/null +++ b/docs/api/create-stylish.en-US.md @@ -0,0 +1,27 @@ +--- +title: ๐Ÿšง createStylish +order: 10 +group: + title: Creating Styles + order: 0 +--- + +## Introduction + +For general styling needs, basic requirements can be met through [createStyles](/usage/create-styles), while `createStylish` is considered an advanced usage. + +In a complex business system, there may be some common styles with finer granularity that are not enough to form a component. However, repeatedly writing these styles is not only time-consuming but also results in a lot of duplicate code. Moreover, if a designer requests a unified adjustment of the design style, the cost of making multiple modifications is extremely high. To address this issue, `createStylish` was developed. + +`createStylish` can create reusable styles. In concept, it is similar to the popular tailwindcss in recent years, but it is more flexible and practical. When combined with Ant Design V5 Token System, it can achieve a highly efficient and flexible user experience. + +:::success{title=Applicable Scenarios} +Used for organizing reusable styles in batches. +::: + +## Typical Example + + + +## Detailed Introduction + +## API diff --git a/docs/api/global-styles.en-US.md b/docs/api/global-styles.en-US.md new file mode 100644 index 00000000..30cda7fb --- /dev/null +++ b/docs/api/global-styles.en-US.md @@ -0,0 +1,20 @@ +--- +title: createGlobalStyle +description: Create global styles +order: 10 +group: Creating Styles +--- + +## Introduction + +Using `createGlobalStyle` allows you to create styles that are injected globally. The usage of this method is almost identical to `styled-component`, but it is implemented based on `@emotion/react` and `@emotion/serialize`. + +## Default Usage + + + +## Using with antd tokens + +By utilizing the token system in antd v5, we can organize and implement a Button style that does not exist in Ant Design. + + diff --git a/docs/api/setup-styled.en-US.md b/docs/api/setup-styled.en-US.md new file mode 100644 index 00000000..d3f43dad --- /dev/null +++ b/docs/api/setup-styled.en-US.md @@ -0,0 +1,7 @@ +--- +title: ๐Ÿšง setupStyled +description: Set up global Styled data container +group: Advanced Settings +--- + +TBD diff --git a/docs/api/style-provider.en-US.md b/docs/api/style-provider.en-US.md new file mode 100644 index 00000000..255c409a --- /dev/null +++ b/docs/api/style-provider.en-US.md @@ -0,0 +1,50 @@ +--- +title: StyleProvider +description: Used for globally managing style insertion related configurations +order: 2 +group: Container Components +demo: + tocDepth: 4 +--- + +## Modify container + +Specify `container` to make all generated styles (antd, antd-style) inserted under this node. + + + +## Modify style insertion point + +In general, it is not often needed. If you need to be compatible with the requirement of component style override, you can consider setting the insertion point of the component style to insert it after this node. + + + +## Enable speedy mode + +Enable emotion's speedy mode. It is recommended to be enabled for independent applications. + + + +:::info{title=Speedy Mode} + +In the early cssinjs solutions, each style tag corresponded to one style, which was slow to parse but easy to modify and debug. + +Currently, emotion defaults to using modern CSSOM api to insert styles, putting a bunch of css into a tag and then removing the corresponding content after insertion. This method has good performance and supports inserting styles in the tens of thousands. However, it is not very compatible with micro frontends (qiankun). + +By default, speedy mode is turned off in antd-style. If needed, set `speedy` to `true` to enable it. +::: + +## API + +Inherits from `ant-design/cssinjs` [StyleProvider](https://github.com/ant-design/cssinjs#styleprovider), other APIs are as follows: + +| Property | Type | Description | +| --------------- | -------------------------------------- | ----------------------------------------------------------------------------------------------------- | +| prefix | `string` | Emotion style prefix, default value is acss | +| nonce | `string` | Random number used for CSP | +| stylisPlugins | `StylisPlugin[]` | Array of Stylis plugins | +| container | `Element` | Container for rendering styles | +| speedy | `boolean` | Whether to enable speedy mode, under speedy mode, real style will not be inserted, default is `false` | +| insertionPoint | `HTMLElement` | Style insertion point, used to control the insertion position of the first style | +| getStyleManager | `(styleManager: StyleManager) => void` | Callback function to get the styleManager instance | +| children | `ReactNode` | Child components | diff --git a/docs/api/theme-provider.en-US.md b/docs/api/theme-provider.en-US.md new file mode 100644 index 00000000..1ca8d028 --- /dev/null +++ b/docs/api/theme-provider.en-US.md @@ -0,0 +1,209 @@ +--- +title: ThemeProvider +description: A container for globally managing theme variables. It provides a unified entry point for one-click switching between light and dark themes, custom themes, and application-level scoped styles. +order: 1 +group: + title: Container Components + order: 1 +demo: + cols: 2 + tocDepth: 4 +--- + +## Introduction + +ThemeProvider is a container for globally managing theme variables. Based on encapsulating the `ConfigProvider`, this component provides a unified entry point for one-click switching between light and dark themes, custom themes, and application-level scoped styles. At the same time, the `useTheme` method under this container can obtain the `theme` object within this layer. + +ThemeProvider is essentially a React Context data container used to provide related theme consumption data for child applications. Therefore: + +- It integrates the basic state of switching between light and dark themes +- Supports automatic response to system themes +- Provides a callback object for the antd static instance method (this static method can respond to themes normally) +- This component does not have a real DOM node, so it cannot limit the scope of custom styles through node styles + +## Theme Switching + +ThemeProvider integrates the ability to switch between light and dark themes by default, and you can quickly complete the switching between light and dark themes through the `appearance` props. For more details about the theme switching ability of `antd-style`, you can refer to [Theme Switching](/guide/switch-theme). + + + +## Usage of useTheme + +After wrapping the top-level with ThemeProvider, use `useTheme` to get the theme object, which includes antd v5 token theme values, custom themes, and current theme appearance methods. For detailed API, see [](api/use-theme-mode) + +```tsx | pure +import { ThemeProvider, useTheme } from 'antd-style'; + +const App = () => { + const theme = useTheme(); + + return
{theme.colorPrimary}
; +}; + +export default () => { + return ( + + + + ); +}; +``` + +Example effect: + +:::info{title=Tips} + +`useTheme` will look for the theme value in the nearest `ThemeProvider` component. If there are multiple nested layers, only the innermost layer will take effect. + +::: + +## Injecting Custom Token Themes + +You can inject custom tokens through the `customToken` method of `ThemeProvider` and consume them through the `useTheme` method. + +```tsx | pure +import { ThemeProvider } from 'antd-style'; + +const App = () => { + const theme = useTheme(); + + return
{theme.customBrandColor}
; +}; + +export default () => { + return ( + + + + ); +}; +``` + +Example effect: + + + +## Typescript Type Support + +By extending the type definition of the `CustomToken` interface for `antd-style`, you can add corresponding token type definitions to the `useTheme` hooks. + +At the same time, by adding generics to the `ThemeProvider` object, you can constrain the input parameter definition of `customToken`. + +```tsx | pure +import { ThemeProvider, useTheme } from 'antd-style'; + +interface NewToken { + customBrandColor: string; +} + +// By extending the CustomToken object type definition for antd-style, you can add corresponding token objects to useTheme +declare module 'antd-style' { + // eslint-disable-next-line @typescript-eslint/no-empty-interface + export interface CustomToken extends NewToken {} +} + +const App = () => { + const token = useTheme(); + return
{token.customBrandColor}
; +}; + +export default () => ( + // By adding generics to the ThemeProvider object, you can constrain the input parameter definition of customToken + customToken={{ customBrandColor: '#c956df' }}> + + +); +``` + +:::info + +Since `CustomToken` is most likely an empty interface, if the project has a rule to configure `@typescript-eslint/no-empty-interface`, the interface definition will be corrected to type during code formatting, and since type cannot be extended, it will cause loss of prompts (related issue: [#16](https://github.com/ant-design/antd-style/issues/16)). Therefore, the solution is to add a disabled rule as shown in the example code above. + +::: + +## Basic Style Reset + +The default effect of the `a` node in the dumi document is as follows. + + + +By resetting the style of the antd App component, you can ensure that native tags (``, etc.) not in the antd component also conform to the default style of antd (bottom left). + + + +## Consuming Static Instance Methods + +In v5, due to the issue of react lifecycle, static methods were removed, so if you use the default exported static methods of antd such as message, they will not respond to dynamic themes. Therefore, ThemeProvider provides a `getStaticInstance` interface to provide the static method instance that responds to dynamic themes for external use. + +```tsx | pure +/** + * iframe: 240 + */ +import { ThemeProvider } from 'antd-style'; +import { MessageInstance } from 'antd/es/message/interface'; + +let message: MessageInstance; + +export default () => { + const showMessage = () => { + message.success('Success!'); + }; + return ( + { + message = instances.message; + }} + > + {/*... */} + + ); +}; +``` + + + +## Adding Scoped Styles to the Container + +If you need to affect only the styles under ThemeProvider, you can combine the `className` props of the antd App component with the `css` or [createStyles](/usage/create-styles) method to add local scoped styles. + + + +:::info{title=Global Style Scope} + +In the world of css-in-js, local scope is very easy to achieve. Therefore, global scope usage should be minimized as much as possible (use global scope only if necessary). This is also the recommended practice in antd v5. However, if you still need to inject styles at the global scope level, you can use [createGlobalStyles](/usage/global-styles) to achieve this. + +::: + +## Nested ThemeProvider + +In some scenarios, we may need to nest another ThemeProvider within a ThemeProvider. In this case, it should be noted that the inner ThemeProvider will override the outer ThemeProvider. + + + +## Integration with styled + +antd-style provides compatibility with styled-components' ThemeProvider through the `styled` method, and then uses antd-style's ThemeProvider to provide theme consumption for styled-components or the emotion/styled library. + +```tsx | pure +export interface StyledConfig { + ThemeProvider?: StyledThemeProvider; + useTheme?: () => any; +} + +export interface ThemeProviderProps { + styled?: StyledConfig; +} +``` + +## API + +| Name | Default Value | Description | +| ------------------ | -------------------------------------- | ------------------------------------------------------------------------------------------------------------------------------------------------------- | +| customToken | `undefined` | Custom tokens, can be extended and added to your own needs based on the antd v5 token specification | +| customStylish | `undefined` | Custom Stylish variables | +| appearance | `light` | The appearance theme of the application, built-in light and dark themes, can be extended by yourself | +| defaultAppearance | | | +| onAppearanceChange | `(appearance:ThemeAppearance) => void` | Callback for appearance theme | +| themeMode | `light` | Theme display mode, with three configurations: follow system, light, dark. Automatic mode is not enabled by default and needs to be configured manually | +| defaultThemeMode | null | Default theme display mode | +| onThemeModeChange | `(themeMode: ThemeMode) => void` | Callback after theme mode is modified | diff --git a/docs/api/use-responsive.en-US.md b/docs/api/use-responsive.en-US.md new file mode 100644 index 00000000..893eb881 --- /dev/null +++ b/docs/api/use-responsive.en-US.md @@ -0,0 +1,32 @@ +--- +title: useResponsive +order: 4 +group: Hooks +--- + +## Introduction + +Get the result of responsive media queries. It is encapsulated based on antd's [Grid.useBreakpoint](https://ant.design/components/grid) . + +## Usage + +```tsx | pure +import { useResponsive } from 'antd-style'; + +function Theme() { + const { mobile } = useResponsive(); + + // Use JavaScript to distinguish between mobile and desktop + return mobile ?
mobile
:
desktop
; +} +``` + +## Example + + + +## Custom Breakpoints + +Customize responsive breakpoints by passing in antd's breakpoint configuration. + + diff --git a/docs/api/use-theme-mode.en-US.md b/docs/api/use-theme-mode.en-US.md new file mode 100644 index 00000000..758c0658 --- /dev/null +++ b/docs/api/use-theme-mode.en-US.md @@ -0,0 +1,70 @@ +--- +title: useThemeMode +order: 2 +group: + title: Hooks + order: 3 +--- + +## Introduction + +Obtain the theme appearance mode under `ThemeProvider`. + +## Usage + +```tsx +/** + * inherit: true + * defaultShowCode: true + */ +import { Divider, Typography } from 'antd'; +import { useThemeMode } from 'antd-style'; +import { Flexbox } from 'react-layout-kit'; +const { Text } = Typography; + +export default () => { + const { themeMode, appearance, browserPrefers } = useThemeMode(); + + return ( + + Theme Mode: + {themeMode} + + Appearance Mode: + {appearance} + + Browser Appearance: + {browserPrefers} + + ); +}; +``` + +## API + +### Typescript + +```ts +useThemeMode: () => ThemeContextState; +``` + +### ThemeContextState + +| Parameter | Type | Default | Description | +| -------------- | ------------------------------------- | ------- | ----------------------- | +| browserPrefers | [`BrowserPrefers`](#themeappearance) | `light` | Browser appearance | +| themeMode | [`ThemeMode`](#thememode) | `light` | Theme mode | +| appearance | [`ThemeAppearance`](#themeappearance) | `light` | Display appearance | +| isDarkMode | `boolean` | `false` | Whether it is dark mode | + +### BrowserPrefers + +Browser appearance, only `dark` or `light`. + +### ThemeAppearance + +Appearance mode, can be `dark`, `light`, or a custom string. + +### ThemeMode + +Theme mode, can be `dark`, `light`, or `auto`. diff --git a/docs/api/use-theme.en-US.md b/docs/api/use-theme.en-US.md new file mode 100644 index 00000000..3f6dae46 --- /dev/null +++ b/docs/api/use-theme.en-US.md @@ -0,0 +1,43 @@ +--- +title: useTheme +order: 1 +group: Hooks +--- + +## Introduction + +When used in conjunction with container components (`ThemeProvider`), it can obtain the theme information under the container. If `ThemeProvider` is not added, the default value is obtained. + +When `useTheme` is used under the `ThemeProvider` component, the theme value in the ThemeProvider can be obtained. + + + +## Usage + +```ts +import { useTheme } from 'antd-style'; + +function Theme() { + const theme = useTheme(); + + useEffect(() => { + console.log(theme); + }, [theme]); + + return null; +} +``` + +## Typescript + +```ts +useTheme = () => Theme; +``` + +### Return Value + +| Parameter | Description | Type | Default | +| ---------- | ----------- | ---------------------- | ------- | +| themeMode | Theme mode | `dark / light / auto` | `light` | +| appearance | Display | `dark / light` | `light` | +| isDarkMode | Dark mode | `boolean` | `false` | diff --git a/docs/api/use-theme.zh-CN.md b/docs/api/use-theme.zh-CN.md index 3bf3744c..36797cb3 100644 --- a/docs/api/use-theme.zh-CN.md +++ b/docs/api/use-theme.zh-CN.md @@ -1,7 +1,6 @@ --- title: useTheme order: 1 -nav: API group: Hooks --- diff --git a/docs/best-practice/antd-based-components.en-US.md b/docs/best-practice/antd-based-components.en-US.md new file mode 100644 index 00000000..5484b73a --- /dev/null +++ b/docs/best-practice/antd-based-components.en-US.md @@ -0,0 +1,8 @@ +--- +title: ๐Ÿšง Styling Best Practices for Customizing Components Based on antd v5 +group: + title: UI Library Development + order: 3 +--- + +# How to Write Styles Elegantly for a Component Library Based on antd v5? diff --git a/docs/best-practice/antd-override.en-US.md b/docs/best-practice/antd-override.en-US.md new file mode 100644 index 00000000..0cfb4b33 --- /dev/null +++ b/docs/best-practice/antd-override.en-US.md @@ -0,0 +1,45 @@ +--- +title: Customizing Ant Design Component Styles +group: Theme Customization +--- + +# How to elegantly override Ant Design component styles? + +## Customization based on ConfigProvider + +In V5, Ant Design provides a brand new `theme` property for customization. Therefore, if you need to customize component styles, it is recommended to use the `theme` field on the ConfigProvider as a priority. + +The demo example is as follows: + + + +:::info +For more customization capabilities based on ConfigProvider, please refer to [Discussing the Theme of Ant Design V5 (Part 1): Creative Use of CSSinJS Dynamic Themes](https://www.yuque.com/antfe/featured/durxuu94nvgvgmzq#vFlnd). +::: + +The ThemeProvider of antd-style is a business-layer encapsulation based on ConfigProvider, providing user-friendly customization capabilities. See: [Custom Theme](/guide/custom-theme) + +## Basic Overrides + +The `createStyles` method has a `prefixCls` parameter. By using this parameter, you can pass in the prefix of the component, so that any style overrides can automatically change with the change of `prefixCls`. + + + +## Increasing Specificity for Overrides + +In some components, directly adding a class name may not have enough specificity to override the styles. In this case, you can use the `&` symbol to increase the specificity accordingly. + + + +## Overrides for Multiple classNames Scenarios + +classNames is a major feature of antd V5: [\[RFC\] Semantic DOM Structure for all Components](https://github.com/ant-design/ant-design/discussions/40221). +In the past, when defining styles, we needed to find many DOM nodes for extensive style overrides. However, during the upgrade process of antd, sometimes the DOM structure may be adjusted. As a result, our overridden styles may encounter issues. + +With classNames, it will provide us with a stable DOM structure API. We can pass in the class names through classNames, which will point to the corresponding DOM nodes, thereby greatly reducing the risk of Breaking Changes caused by DOM changes. It also eliminates the need for us to hackishly search for style class names. + + + +## Related Discussions + +- [Style Specificity Issues](https://github.com/ant-design/antd-style/issues/24) diff --git a/docs/best-practice/clay.en-US.md b/docs/best-practice/clay.en-US.md new file mode 100644 index 00000000..7e88828b --- /dev/null +++ b/docs/best-practice/clay.en-US.md @@ -0,0 +1,8 @@ +--- +title: Clay Style UI +group: Style Cases +--- + +# Clay Style + + diff --git a/docs/best-practice/custom-token-types.en-US.md b/docs/best-practice/custom-token-types.en-US.md new file mode 100644 index 00000000..3a17260d --- /dev/null +++ b/docs/best-practice/custom-token-types.en-US.md @@ -0,0 +1,53 @@ +--- +title: Extending Custom Token Type Definition +group: + title: Theme Customization + order: 1 +--- + +# How to extend the CustomToken object type definition for antd-style? + +## Solution + +By extending the type definition of the `CustomToken` interface for `antd-style`, you can add corresponding token type definitions to the `useTheme` hooks. + +At the same time, by adding generics to the `ThemeProvider` object, you can constrain the input definition of `customToken`. + +```tsx | pure +import { ThemeProvider, useTheme } from 'antd-style'; + +interface NewToken { + customBrandColor: string; +} + +// By extending the type definition of the `CustomToken` interface for `antd-style`, you can add corresponding token type definitions to the `useTheme` hooks +declare module 'antd-style' { + // eslint-disable-next-line @typescript-eslint/no-empty-interface + export interface CustomToken extends NewToken {} +} + +const App = () => { + const token = useTheme(); + return
{token.customBrandColor}
; +}; + +export default () => ( + // By adding generics to the `ThemeProvider` object, you can constrain the input definition of the `customToken` interface + customToken={{ customBrandColor: '#c956df' }}> + + +); +``` + +:::info +Since `CustomToken` is likely an empty interface, if the project has configured the `@typescript-eslint/no-empty-interface` rule, the interface definition may be corrected to a type during code formatting, and types cannot be extended, resulting in loss of prompts (related issue: [#16](https://github.com/ant-design/antd-style/issues/16)). Therefore, the solution is to add a rule disabling as shown in the example code above. +::: + +## Reference Code + +- [dumi-theme-antd-style](https://github.com/arvinxx/dumi-theme-antd-style/blob/master/src/styles/customToken.ts) +- [Ant Design Official Website](https://github.com/ant-design/ant-design/blob/master/.dumi/theme/SiteThemeProvider.tsx) + +## Related Discussions + +- [๐Ÿง\[Question\] How to extend the CustomToken object type definition for antd-style](https://github.com/ant-design/antd-style/issues/16) diff --git a/docs/best-practice/fix-switch-theme-fouc.en-US.md b/docs/best-practice/fix-switch-theme-fouc.en-US.md new file mode 100644 index 00000000..60eba2d3 --- /dev/null +++ b/docs/best-practice/fix-switch-theme-fouc.en-US.md @@ -0,0 +1,76 @@ +--- +title: Flashing Issue in Dark Mode +group: + title: Theme Switching + order: 2 +--- + +## Flashing Issue in Dark Mode + +When using antd-style, the initial screen is generally in light mode. This causes the interface to first display the light theme and then switch to the dark theme in dark mode. This gives users a "flashing" feeling, resulting in a poor experience. This type of problem is known as FOUC (Flash of Unstyled Content). + +How to solve it? + +This article assumes that you already understand the solutions for antd-style in SSG and SSR. + +Principle analysis: + +1. SSG generates light-colored HTML; +2. After JS hydration, cssinjs runs and re-generates dark class names and styles; + +The root cause of FOUC is that the server does not know the client's current theme status. + +Therefore, there are two solutions: + +1. SSR: Make the server aware of the user client's theme status, for example, using query URLs, cookies, and other mechanisms; +2. Extract color variables as CSS variables; + +### SSR Solution + +Using next.js App Router as an example: + +```tsx | pure +const RootLayout = ({ children }: PropsWithChildren) => { + // Get the theme change situation from the cookie + const cookieStore = cookies(); + const appearance = cookieStore.get('theme'); + + return ( + + + + {children} + + + + + ); +}; + +export default RootLayout; +``` + +```tsx | pure +export interface AppThemeProps { + children?: ReactNode; + defaultAppearance?: ThemeAppearance; +} + +const Layout = memo(({ children, defaultAppearance }) => { + console.log('server:appearance', defaultAppearance); + + return ( + { + document.cookie = `theme=${appearance};`; + }} + themeMode={themeMode} + > + {children} + + ); +}); + +export default Layout; +``` diff --git a/docs/best-practice/index.en-US.md b/docs/best-practice/index.en-US.md new file mode 100644 index 00000000..80393d65 --- /dev/null +++ b/docs/best-practice/index.en-US.md @@ -0,0 +1,14 @@ +--- +title: Best Practices and Case Studies +nav: + title: Best Practices + order: 3 +--- + +# Best Practices and Case Studies + +As more and more users adopt antd-style, it has been observed that users still encounter some edge cases in practical applications. + +Therefore, this section has been adjusted to focus on "Best Practices" and "Case Studies", detailing the best practices for using antd-style based on common scenarios encountered by users. + +In addition to best practices, this section also includes some practical case studies, with the hope of providing assistance to you. diff --git a/docs/best-practice/mac-select.en-US.md b/docs/best-practice/mac-select.en-US.md new file mode 100644 index 00000000..609f2dc4 --- /dev/null +++ b/docs/best-practice/mac-select.en-US.md @@ -0,0 +1,12 @@ +--- +title: Custom Component โ€”โ€” macOS Selector +group: + title: Style Cases + order: 10 +--- + +# MacOS Selector + +This is a macOS-style interactive selector that combines [floating-ui](https://floating-ui.com/) with the `antd-style`. If you are tired of the default selector in antd but still want to maintain the visual style of antd, you can use antd-style to create your own interactive components. + + diff --git a/docs/best-practice/mirgration-less-global-style.en-US.md b/docs/best-practice/mirgration-less-global-style.en-US.md new file mode 100644 index 00000000..54101df3 --- /dev/null +++ b/docs/best-practice/mirgration-less-global-style.en-US.md @@ -0,0 +1,50 @@ +--- +title: CSS Modules Global Style Override Migration +group: + title: Writing Style + order: 0 +--- + +# CSS Modules Global Style Override Migration + +How to handle the usage of `:global` in CSS Modules syntax during migration? + +In CSS Modules, there are scenarios where the `:global` is used to override component styles. How should this part of the code be handled during migration? + +## Solution + +Preferably, use [codemod](/guide/migrate-less-codemod) for one-click migration. This Codemod will automatically convert the `:global` in CSS Modules syntax to the syntax in antd-style. + +If manual adjustment is needed, simply remove the `:global` syntax. + +Before migration: + +```less +.container { + :global(.ant-btn-link) { + padding: 0; + font-size: 12px; + } +} +``` + +After migration: + +```ts +const useStyles = createStyles(({ css }) => ({ + container: css` + .ant-btn-link { + padding: 0; + font-size: 12px; + } + `, +})); +``` + +## Principle Analysis + +Elements in CSS modules are by default given a hash. The `:global` syntax is used to avoid adding a hash to the style name. However, antd-style uses `emotion/css` as the underlying style library, where combined styles do not automatically add a hash. Therefore, simply removing `:global` is sufficient. + +## Related Discussions + +- [๐Ÿง\[Issue\] How to handle the usage of :global in less syntax during migration](https://github.com/ant-design/antd-style/issues/72) diff --git a/docs/best-practice/nest-element-style.en-US.md b/docs/best-practice/nest-element-style.en-US.md new file mode 100644 index 00000000..95550c6f --- /dev/null +++ b/docs/best-practice/nest-element-style.en-US.md @@ -0,0 +1,49 @@ +--- +title: Writing Linked Styles for Parent-Child Components +group: Writing Style +--- + +# How to Write Linked Styles + +Sometimes we need to modify the style of a child component when hovering over the container component. In this case, we can use `cx` to generate a className. + +## Demo + +Core code: + +```ts +const useStyles = createStyles(({ css, cx }) => { + // 1. Use cx to wrap css and get the className (acss-xxx) + const child = cx(css` + background: red; + width: 100px; + height: 100px; + `); + + return { + parent: css` + cursor: pointer; + + &:hover { + // 2. Implement cascading + .${child} { + background: blue; + } + } + `, + // 3. Export the child className + child, + }; +}); +``` + + + +## Principle Analysis + +The idea is simple because the `css` method always produces a [serialized style object](/api/create-styles#css). Wrapping the `css` object with `cx` will convert the object into a className (`acss-xxxx`). + +## Related Discussions + +- [\[Issue\] How to nest styles](https://github.com/ant-design/antd-style/issues/54) +- [\[BUG\] Inconsistency between the classNames generated by internal cx and the exported classNames after enabling the babel-plugin-antd-style plugin](https://github.com/ant-design/antd-style/issues/83) diff --git a/docs/best-practice/static-message.en-US.md b/docs/best-practice/static-message.en-US.md new file mode 100644 index 00000000..2070c371 --- /dev/null +++ b/docs/best-practice/static-message.en-US.md @@ -0,0 +1,48 @@ +--- +title: Failure of antd Static Methods to Respond to Themes +group: Theme Customization +--- + +# How to Resolve the Issue of antd Static Methods such as Modal and message Not Responding to Themes? + +In the past, in version 4, these static methods could be used in non-component environments, such as using `message.error` in axios to display error messages. + +Now, in version 5, it is necessary to use `const { message } = App.useApp();`. + +Does this mean that we can no longer use them as before? + +## Solution + +Of course not. Refer to the demo below. By defining the corresponding instance variables in a separate file, you can still use them in non-React environments and they will still respond to themes. + + + +## Principle Analysis + +antd-style provides a [`getStaticInstance`](api/theme-provider#consume-static-instance-method) interface in the `ThemeProvider`, from which users can obtain the integrated instance. + +The implementation principle of this method is also simple. Taking message as an example: + +```tsx | pure +import { message } from 'antd'; + +const Provider = ({ getStaticInstance, children, theme }) => { + // 1. Use useMessage to obtain the instance + const [messageInstance, messageContextHolder] = message.useMessage(staticInstanceConfig?.message); + + useEffect(() => { + // 3. Use getStaticInstance to expose the instance + getStaticInstance?.({ + message: messageInstance, + }); + }, []); + + return ( + + {/* 2. Insert the context of message */} + {messageContextHolder} + {children} + + ); +}; +``` diff --git a/docs/best-practice/styled.en-US.md b/docs/best-practice/styled.en-US.md new file mode 100644 index 00000000..9b953018 --- /dev/null +++ b/docs/best-practice/styled.en-US.md @@ -0,0 +1,10 @@ +--- +title: Style Components +group: Style Cases +--- + +# Building Stylish Components Using Styled + +## Stylish Title Components + + diff --git a/docs/changelog.en-US.md b/docs/changelog.en-US.md new file mode 100644 index 00000000..6282fb7c --- /dev/null +++ b/docs/changelog.en-US.md @@ -0,0 +1,8 @@ +--- +title: Release Notes +nav: + title: Release Notes + order: 999 +--- + + diff --git a/docs/guide/babel-plugin.en-US.md b/docs/guide/babel-plugin.en-US.md new file mode 100644 index 00000000..658f5e81 --- /dev/null +++ b/docs/guide/babel-plugin.en-US.md @@ -0,0 +1,39 @@ +--- +title: Babel Plugin +order: 1 +group: Advanced Usage +--- + +# Babel Plugin + +We provide a Babel plugin for antd-style to enhance the development experience. + +```bash +pnpm i -D babel-plugin-antd-style +``` + +## Configuration + +`.babelrc` configuration: + +```json +{ + "plugins": ["antd-style"] +} +``` + +umi/dumi configuration: + +```js +export default defineConfig({ + extraBabelPlugins: [require.resolve('babel-plugin-antd-style')], +}); +``` + +## Features + +### Support for className resolution + +After installing the Babel plugin, className will be resolved to the corresponding style file directory, effective only in development. + +![](https://github-production-user-asset-6210df.s3.amazonaws.com/28616219/243569986-46274fce-8568-4ae1-a309-2972cb926611.png) diff --git a/docs/guide/compare.en-US.md b/docs/guide/compare.en-US.md new file mode 100644 index 00000000..7096bdf3 --- /dev/null +++ b/docs/guide/compare.en-US.md @@ -0,0 +1,224 @@ +--- +title: Comparison of CSS in JS Writing Methods +order: 2 +group: Basic Knowledge +--- + +# Comparison of CSS in JS Writing Methods + +Due to the variety of CSS in JS writing methods, we need to provide a best practice that is compatible with V5 Token System, custom themes, low development complexity, and good scalability. This article will discuss the differences between different writing methods from various perspectives and provide the most recommended approach for `antd-style`. + +## Comparison Basis: Original V4 CSS Modules + +First, let's review the writing method used previously (antd v4), which serves as the basis for comparing with CSS in JS writing methods. + +Most applications using antd are generally paired with less and css modules for styling. The styling scheme for page writing is as follows: + +```less | pure +// style.less +@import '~antd/es/style/themes/default'; + +.list { + border: 1px solid @primary-color; + border-radius: 2px; + box-shadow: 0 8px 20px @shadow-color; +} +``` + +```tsx | pure +// index.tsx +import styles from './style.less'; + +const App = ({ list }) => { + return ; +}; +``` + +## 1. styled Writing Method + +The styled writing method feels like a completely different set of code. Since we have been using it in our business for two years, we have relatively rich experience. Let's talk about some pain points of using styled. + +First, developers need to relearn the basic syntax and related usage of styled. If migrating from antd v4 less projects to this writing method, it is basically no different from rewriting. + +In practical project development, the most painful part we experienced was mainly in the override of component styles. For example, if you need to override the style of antd's Button, you need to write it like this: + +```tsx | pure +import { Button } from 'antd'; +import { styled } from 'styled-components'; + +// Rename after importing antd's Button +const ButtonBox = styled(Button)` + display: flex; + align-items: center; + height: 80px; +`; + +export default () => { + // Then use + return Button; +}; +``` + +This override method will greatly destroy the semantic of the code for a well-designed component library. Once this method is used, it will be difficult for everyone to distinguish which Button component in the code is the antd Button. The development complexity of taking over different projects will be greatly increased. + +In addition, components like Modal and Drawer have multiple class names, which cannot be covered by styled due to the limitations of its writing method. Because the components wrapped by styled will only insert styles into the `className` by default, and for components like Drawer that have a `rootClassName`, it will be very difficult to apply styles to the rootClassName. + +Finally, in practice, we occasionally encounter styled-wrapped antd components, and the type definitions cannot be prompted normally, which also reduces development efficiency. + +After discussing the disadvantages of styled, let's talk about its advantages. + +Since the styled writing method can ensure that each style can form a standard React component, and the combination of styles is relatively convenient, it is very suitable for building a business-styled component library from scratch, or creating some styles with a unified style. + +By declaring a series of standard style components through styled, it can greatly reduce repetitive style code and help developers form a clear understanding of style semantics. See the case: [Typography Styled Components](/case/styled) + +If there is already an existing design system, styled is not suitable, especially since antd v5 itself already has a strong foundation for dynamic theming capabilities. + +## 2. css props Writing Method + +This method seems to be recommended by emotion, and the core maintainer of emotion also uses this method extensively in their own business (see: [Why We're Breaking Up with CSS-in-JS](https://dev.to/srmagura/why-were-breaking-up-wiht-css-in-js-4g9b)). This writing method has two major problems: 1) coupling of style code, 2) performance deficiencies. + +The css props writing method directly couples style code with logic code, which reduces the maintainability of style code and makes it difficult to distinguish between style code and logic code in the code (as shown below). + +```tsx | pure +/** @jsx jsx */ + +const Command = () => { + const { styles, cx } = useStyles(); + const [hover, setHover] = useState(''); + + return ( +
+
+ ... +
+
+ ); +}; +``` + +This is a disaster for the maintainability of the code. But if the style and logic code are separated, it is clear and easy to understand (as shown below): + +```tsx | pure +import styles from './style.less'; + +const Command = () => { + return ( +
+
+
+
Trigger Macro by Name
+ + +
+
+ {items.map(({ label, shortcut }) => { + return ( +
{ + setHover(label); + }} + > +
{label}
+
{shortcut}
+
+ ); + })} +
+ +
+
+
+
+ ); +}; +``` + +The former maintainer of emotion extensively uses this writing method in their own business, but they also mentioned the problem of this writing method in [their blog](https://dev.to/srmagura/why-were-breaking-up-wiht-css-in-js-4g9b): performance deficiencies. + +Due to the rendering mechanism of React, when passing the style object directly to the `css` attribute, since the object is treated as a new object for each rendering, it will cause re-rendering in React, resulting in unnecessary performance overhead. The recommended approach is to move the objects in the css props outside the component and make them static. But at the same time, this will lose the dynamic capability of css-in-js. + +```tsx | pure +const myCss = css({ + backgroundColor: 'blue', + width: 100, + height: 100, +}); + +function MyComponent() { + return
; +} +``` + +In terms of migration cost, this writing method is slightly better than styled, at least it does not require additional definition of components, but it still requires modifying the DOM code in the components, and requires importing the `jsx` object from `@emotion/react`, which still increases the migration cost. + +## 3. css Combined with className Writing Method + +The css combined with className writing method is very simple in terms of perception and is also the easiest to migrate among these methods. However, the direct combination of css with className still has some issues: + +The pure `css` method for creating static styles cannot be used with antd's tokens, so it cannot enjoy the dynamic capability of css-in-js. + +To use dynamic capabilities, you must use the hooks approach, as shown below. + +```tsx | pure +import { css } from '@emotion/css'; +import { theme } from 'antd'; + +const useStyles = () => { + const { token } = theme.useToken(); + return { + container: css` + background: ${token.colorBgLayout}; + `, + list: css` + border: 1px solid ${token.colorPrimary}; + border-radius: 2px; + box-shadow: 0 8px 20px ${token.colorShadow}; + `, + }; +}; + +const App: FC = ({ list }) => { + const styles = useStyles(); + return ( +
+ +
+ ); +}; +``` + +In this writing method, on the one hand, each function needs to manually use `theme.useToken` to obtain tokens, which is very troublesome when the scale is large. On the other hand, the object returned by hooks will be recreated every time, so it will definitely cause unnecessary re-rendering. If each return is wrapped with useMemo, the code volume will be even larger. Finally, if custom themes, dynamic themes, etc., are added, this writing method will become very complex and verbose, containing a lot of unnecessary code. + +## Summary of Comparison of Various Writing Methods + +Combining the various methods mentioned above, antd-style hopes to achieve the best in all aspects and become the best practice for application style development based on antd. + +| | Learning Cost | Dynamic Capability | Custom Theme Difficulty | Style Development Complexity | Component Override Complexity | Performance | Migration Cost | +| --------------- | ------------- | ------------------ | ----------------------- | ---------------------------- | ----------------------------- | ------------------- | -------------- | +| `CSS Modules` | โœ… Low | โŒ None | โŒ Difficult | โœ… Low | โœ… Low | โœ… Optimal | โœ… - | +| `styled` | โญ•๏ธ๏ธ High | โœ… High | โš ๏ธ Moderate | โœ… Low | โญ•๏ธ๏ธ High | โœ… Excellent | โญ•๏ธ๏ธ High | +| `css` props | โš ๏ธ Moderate | โœ… High | โš ๏ธ Moderate | โš ๏ธ High | โœ… Low | โญ•๏ธ๏ธ Poor | โš ๏ธ Moderate | +| css + className | โœ… Low | โœ… High | โš ๏ธ Moderate | โš ๏ธ High | โœ… Low | โญ•๏ธ๏ธ Medium to Poor | โœ… Low | +| antd-style | โœ… Low | โœ… High | โœ… Low | โœ… Low | โœ… Low | โœ… Excellent | โœ… Low | diff --git a/docs/guide/components-usage.en-US.md b/docs/guide/components-usage.en-US.md new file mode 100644 index 00000000..960cd57f --- /dev/null +++ b/docs/guide/components-usage.en-US.md @@ -0,0 +1,129 @@ +--- +title: Component Development +order: 4 +group: Advanced Usage +demo: + cols: 2 +--- + +# Component-Level Development Solution + +The initial use case of antd-style was for business applications, so the default design is mainly oriented towards application consumption scenarios. However, this does not mean that component development cannot use antd-style. antd-style provides a solution for component-level development, and here we will introduce how to use antd-style for component development. + +## :where Selector + +By combining the hash selector of cssinjs, we can ensure that the styles of the component always remain within the scope of the hash, which ensures that the component styles do not contaminate the global styles. + +```less +// style-1 +.css-abcd .my-btn { + background: blue; +} +// style-2 +.css-dcba .my-btn { + background: red; +} +``` + +```jsx | pure + // -> blue background + // -> red background +``` + +However, this approach also brings a problem - the styles of the component will be elevated by the hash selector, making it difficult for users to override the styles: originally, users could override the styles by using `.my-btn`. But now, because the weight of `.css-abcd .my-btn` is higher, if the user only writes `.my-btn { color:green }`, this override style will not take effect. + +So what to do? This is where the `:where()` selector comes in. It can be said to be a cornerstone of future component-level cssinjs. + +> `:where()` takes a selector list as its argument and selects all elements that can be selected by any rule in the selector list. - [:where โ€”โ€” MDN](https://developer.mozilla.org/en-US/docs/Web/CSS/:where) + +Let's take a look at the code: + +```less +:where(.css-abcd) .my-btn { + background: blue; +} + +// The above code is equivalent to the selection scope +.css-abcd .my-btn { + background: blue; +} +``` + +In addition to `where`, it is also possible to achieve local selectors with `is`. However, the main difference between `:where()` and `:is()` is that **`:where()` always has a weight of 0**. In other words, using the where selector, we can add local scope to the component styles with a weight of 0, **while still maintaining the same convenience of overriding styles for the components**. + +The following demo is a set of comparison examples. The upper set is a demo without using the where selector, and the lower set is a demo using the where selector. Both sets of demos have the same set of override styles added externally. + +```css +.my-btn { + background: darkgreen; + color: white; +} + +.my-btn-primary { + background: springgreen; + color: green; +} +``` + + + +## Enabling the where Selector + +Through the comparison demo above, you can understand the importance of the where selector for component-level style development. antd-style also provides the ability to enable the where selector for component development. + +In the `createStyles` method, by setting the second parameter `options` in `hashPriority: "low"`, this part of the styles can be used with the where selector. + +```ts +const useStyles = createStyles(getStyleFn, { hashPriority: 'low' }); + +// The styles in this useStyles will all use the where selector +``` + +Of course, if you do not want to set `{ hashPriority: 'low' }` for each createStyles, you can continue reading to learn how to set a custom style instance method for the component library. + +## Independent Style Instance + +In addition to `:where`, there are some differences between the scenarios of component development and application development. For example: + +- You need to define some custom tokens at the component library level, and the components can consume the default values, rather than manually wrapping a Provider in each component, or requiring users to wrap a Provider when consuming; +- You may want the default prefix of the component library to be customizable; +- Also, you may want the component library to respond to the theme configuration passed in by the application; + +These scenarios can be achieved using the `createInstance` provided by antd-style to create an independent style instance. + +```ts +import { createInstance } from 'antd-style'; + +interface ForDemoToken { + primaryColor: string; + demoBgColor: string; +} + +export const { createStyles, ThemeProvider } = createInstance({ + key: 'css', + hashPriority: 'low', + customToken: { + primaryColor: '#ce1472', + demoBgColor: '#f1f2f5', + }, + prefixCls: 'for-demo', +}); +``` + +The following example shows the custom style instance and default custom token values, and how they are applied in the component demo. + + + +For detailed API of the `createInstance` method, please refer to: [createInstance](/api/create-instance). + +## Best Practice Recommendations + +In the scenario of component development, we recommend using the `createInstance` method to create an independent style instance for your component library, which can make your component library more independent and controllable. The consumption of custom tokens is also more convenient. + +For the parts migrated from less, we recommend enabling the `{ hashPriority: 'low' }` configuration, so that the transformation to cssinjs can be completed with minimal migration cost (see: [Component Code Migration](/guide/migrate-less-component)). + +For components completely written using cssinjs, we recommend still using the `{ hashPriority: 'high' }` configuration. And place all style implementations in `css`, with additional className for the parts that need it. This has two advantages: + +1. **More flexible**: The cost of transforming the application to the component is small, and only the corresponding className needs to be added to turn the application style into the component style; +2. **Easy to override**: Ensure the flatness of the component styles, making it easier for developers using the components to override the component styles; +3. **Unified development mental model**: The writing mindset of the component library and the application can remain consistent; diff --git a/docs/guide/create-styles.en-US.md b/docs/guide/create-styles.en-US.md new file mode 100644 index 00000000..ca23989e --- /dev/null +++ b/docs/guide/create-styles.en-US.md @@ -0,0 +1,114 @@ +--- +title: Writing Style +order: 1 +group: + title: Quick Start + order: 0 +demo: + tocDepth: 4 +--- + +# Writing Styles Using createStyles + +The core API provided by antd-style is `createStyles`, which allows organizing styles using class names, similar to the writing style of CSS Modules. + +:::success{title=Default Recommendation} +This is our first recommended writing style. It can be used to write application styles or override basic component styles. +::: + +## Typical Example + +A demo example containing basic usage, understanding this demo will enable you to use the `createStyles` method. + + + +## Detailed Introduction + +`createStyles` provides several writing styles to meet development needs and improve the development experience for different scenarios. + +### Style 1: No Dynamic Requirement + +If there is no dynamic requirement, you can directly use `createStyles` to pass in a style object. + + + +### Style 2: Using antd Tokens + +The `createStyles` method can use antd tokens and custom tokens. In this case, the parameter of `createStyles` needs to be a function. + +```ts +import { createStyles } from 'antd-style'; + +const useStyles = createStyles(({ token, css }) => { + const commonCard = css` + border-radius: ${token.borderRadiusLG}px; + padding: ${token.paddingLG}px; + `; + + return { + container: css` + background-color: ${token.colorBgLayout}; + padding: 24px; + `, + + primaryCard: css` + ${commonCard}; + background: ${token.colorPrimary}; + color: ${token.colorTextLightSolid}; + `, + + defaultCard: css` + ${commonCard}; + background: ${token.colorBgContainer}; + color: ${token.colorText}; + `, + }; +}); +``` + + + +### Style 3: Using External Props + +The second parameter of the function can receive external props. + +```tsx | pure +const useStyles = createStyles(({ token, css }, props: { id: string; open: boolean }) => { + return { + select: props.open + ? css` + border-color: ${token.colorSuccess}; + ` + : undefined, + }; +}); + +const Select = () => { + // The parameter here will have type hints as { id: string; open: boolean } + const styles = useStyles({ id: '1', open: true }); + + return
; +}; +``` + +The following demo is an example of overriding the antd Select component with external input parameters. + + + +## Organizing Code Files + +If the component styles are simple, they can be merged into one file. However, if the style file is large, it is strongly recommended to separate the style file into a `style.ts` file. As shown below: + + + +## Other Common CSS Syntax + +### Keyframes + +Supports two types of keyframes writing, using the `keyframes` method or the native CSS `@keyframes`. + + + +## API + +For detailed API documentation of the `createStyles` method, please refer to the [createStyles API documentation](/api/create-styles). diff --git a/docs/guide/css-in-js-intro.en-US.md b/docs/guide/css-in-js-intro.en-US.md new file mode 100644 index 00000000..55d0cc22 --- /dev/null +++ b/docs/guide/css-in-js-intro.en-US.md @@ -0,0 +1,161 @@ +--- +title: Quick Start to CSS in JS +order: 1 +group: Basic Knowledge +--- + +# Quick Start to CSS in JS + +## What is CSS in JS + +In concept, CSS in JS is similar to JSX. Simply put, it means writing CSS-related styles in a JS environment. By leveraging the dynamism of JS itself, it can achieve very flexible styling capabilities. This article will not provide basic introductions. If you lack prior knowledge of CSS in JS, you can read some related articles in the community: + +- [Embracing CSS in JS](https://www.yuque.com/chenshuai/web/hea6tm) +- [CSS-in-JS: A Controversial Technical Solution](https://mp.weixin.qq.com/s/8gMg8pL1d89ofvc8FMiMBA) +- [In-depth Analysis of CSS-in-JS](https://juejin.cn/post/7172360607201493029) + +> If there are better learning materials, feel free to submit a PR. + +## Common Writing Styles + +Let's take a look at the four common ways of writing styles in the world of CSS in JS. We will not evaluate these writing styles, but by understanding some mainstream solutions, you will have a better sense for the subsequent introductions. + +### Method 1: styled + +`styled` was pioneered by [styled-components](https://styled-components.com/), and the syntax is as follows: + +```tsx | pure +import styled from 'styled-component'; +import { List } from 'xxx'; + +// Create a styled component +const StyledList = styled(List)` + border: 1px solid ${(p) => p.theme.colorPrimary}; + border-radius: 2px; + box-shadow: 0 8px 20px ${(p) => p.theme.colorShadow}; +`; + +const App: FC = ({ list }) => { + return ( + // Reference the component + + ); +}; +``` + +Subsequently, emotion also followed suit with `@emotion/styled`, so most mainstream CSS in JS libraries support this syntax. We have tested that switching between `styled-component` and `@emotion/react` using the styled syntax has no impact on the styles, and the performance difference is negligible. + +However, it is worth noting that some syntax supported by styled-components (e.g., component selectors) require configuration of a Babel plugin in `@emotion/react` to be supported. Therefore, the package size of `styled-components` is significantly larger compared to `@emotion/react`. + +### Method 2: `css` with className + +The second usage method was proposed by emotion, with the core being the `css` method. + +```tsx | pure +import { css } from '@emotion/css'; + +// Create a class name +const className = css` + color: #1677ff; +`; +// -> css-abcdef + +const App: FC = ({ list }) => { + return ( + // Reference the class name + + ); +}; +``` + +It is worth mentioning that the `css` object not only supports CSS strings, but also supports the object-oriented approach to writing CSS. + +```ts +import { css } from '@emotion/css'; + +const stringCls = css` + color: #1677ff; + border-radius: 2px; +`; + +const objCls = css({ + color: '#1677FF', + borderRadius: 2, +}); + +// stringCls and objCls are equivalent -> css-xxx +``` + +If you want to achieve the same dynamic effect as styled, you need to place the `css` within a function to execute and achieve dynamism. + +```tsx | pure +import { css } from '@emotion/css'; +import { theme } from 'antd'; + +const useStyles = () => { + const { token } = theme.useToken(); + return css` + border: 1px solid ${token.colorPrimary}; + border-radius: 2px; + box-shadow: 0 8px 20px ${token.colorShadow}; + `; +}; + +const App: FC = ({ list }) => { + const className = useStyles(); + return ( + // Reference the component + + ); +}; +``` + +### Method 3: Using `css` props in React + +In `@emotion/react`, an additional method is provided for using `css` props in React. This is the third method and is also the recommended approach by emotion for use in React. + +```tsx | pure +/** @jsx jsx */ +import { theme } from 'antd'; + +const App: FC = ({ list }) => { + const { token } = theme.useToken(); + + return ( + + ); +}; +``` + +In addition, there are many other creative approaches in other CSS in JS libraries, such as [stitches](https://stitches.dev/docs/theming). However, due to space limitations, they will not be listed one by one. + +By now, you should have a basic understanding of how to write CSS in JS. The next article will provide a detailed analysis of the strengths and weaknesses of various writing styles, and offer a selection of antd-style. + +## Engineering Support + +After four or five years of development, most IDEs now have good support for CSS in JS. Therefore, when writing, the experience is basically the same as writing regular CSS. + +### VS Code + +For VS Code users, you need to install the [`vscode-styled-components`](https://marketplace.visualstudio.com/items?itemName=styled-components.vscode-styled-components) plugin, which provides automatic prompts. This plugin works for both `styled-component` and `emotion`. + +![](https://raw.githubusercontent.com/styled-components/vscode-styled-components/e5b357a137e896097b361e8ae22758281497e9cd/demo.gif) + +### Webstorm + +Webstorm provides default support for CSS in JS. If you are a Webstorm user, you don't need to do anything; all intelligent prompts and code completions for CSS in JS are ready to use out of the box. + +### Ant Design Token VSCode Plugin + +Community member [shezhangzhang](https://github.com/shezhangzhang) has developed a VSCode plugin for the Ant Design V5 Token system, which provides token prompts directly in VSCode. + +![](https://raw.githubusercontent.com/shezhangzhang/antd-design-token/master/assets/decorations.gif) + +Project link: [shezhangzhang/antd-design-token](https://github.com/shezhangzhang/antd-design-token) diff --git a/docs/guide/cssinjs-compiler-difference.en-US.md b/docs/guide/cssinjs-compiler-difference.en-US.md new file mode 100644 index 00000000..a4a9251f --- /dev/null +++ b/docs/guide/cssinjs-compiler-difference.en-US.md @@ -0,0 +1,11 @@ +--- +title: ๐Ÿšง Compilation Differences Between CSS-in-JS and Less +order: 10 +group: + title: Migrating from Less + order: 4 +--- + +# Compilation Differences Between CSS-in-JS and Less + +TODO: This document is still being written. Pull requests are welcome. diff --git a/docs/guide/custom-theme.en-US.md b/docs/guide/custom-theme.en-US.md new file mode 100644 index 00000000..c484cf47 --- /dev/null +++ b/docs/guide/custom-theme.en-US.md @@ -0,0 +1,138 @@ +--- +title: Custom Theme +order: 3 +group: Quick Start +--- + +# Custom Theme + +antd-style, combined with complete experience in business development, provides powerful and flexible theme customization capabilities, which will be introduced in the following three aspects: 1) antd theme customization, 2) custom application token, 3) custom appearance mode. + +## Customize Ant Design Theme + +The ConfigProvider of antd v5 provides the theme configuration, which can pass in a custom theme object to achieve custom themes. The ThemeProvider of antd-style provides a more convenient way for custom themes based on ConfigProvider. + +### Compatible usage of ConfigProvider theme + +```tsx | pure +import { ThemeProvider } from 'antd-style'; + +render( + + + , +); +``` + +### Function writing method + +For antd, to ensure the atomicity and composability of functions, ConfigProvider only saves one theme state. Therefore, if you need to support common light and dark theme switching, you need to encapsulate it at the application layer. + +As an application layer, antd-style defines the `appearance` field, and thus supports light and dark theme switching by default. Therefore, the theme configuration also supports passing in a function to set different themes under different appearance modes. + +```tsx | pure +import { ThemeProvider } from 'antd-style'; + +render( + { + // If it is a dark mode, return the dark theme + if (appearance === 'dark') { + return { + token: { + colorPrimary: 'red', + }, + }; + } + + // Otherwise, return the default theme + return { + token: { + colorPrimary: 'blue', + }, + }; + }} + > + + , +); +``` + +The input parameter of the function is the current theme appearance, and the output is the theme object. + +```ts +theme: ThemeConfig | (appearance: Appearance) => ThemeConfig; +``` + +:::success{title=Usage Suggestions} +In actual application development, due to the possibility of multiple theme configurations, it is recommended to extract the theme configuration into a separate file, and then uniformly export and use it as `getAntdTheme`. ([Example reference](https://github.com/arvinxx/dumi-theme-antd-style/blob/master/src/styles/antdTheme.ts)) +::: + +## Custom Token + +At the beginning of the design, the default Token system of Ant Design was not created for all business customization demands, it only contains the tokens necessary for the Ant Design design system. In most business scenarios, we often need to customize some tokens to be uniformly consumed in the application. You may think that only designers need to care about tokens, but in fact, the token system is the foundation of application specifications, from a gradient style to the width of the top navigation bar, all can be uniformly managed and consumed in the token system. + +Therefore, antd-style provides the ability to customize tokens, allowing the application layer to customize its own tokens and use them in `createStyles`, `styled`, and other style methods. + +In the ThemeProvider, you can pass in custom tokens through the `customToken` field. Similar to the usage logic of theme, you can pass in an object or a function. + +```tsx | pure +import { ThemeProvider } from 'antd-style'; + +// Object usage +export default () => ( + + + +); +``` + +The input parameter of the function is some of our built-in methods, but the output is the token object. In this method's input parameter, you can get the current theme appearance, antd's token value, and thus achieve the inheritance effect of custom token themes. + +```tsx | pure +export interface CustomTokenParams { + appearance: ThemeAppearance; + isDarkMode: boolean; + token: AntdToken; +} + +// Function usage +export default () => ( + ({ + customColor: isDarkMode ? token.colorWarning : token.colorPrimary, + headerHeight: 64, + })} + > + + +); +``` + +For detailed introductions on the demo of custom Token API, TypeScript type definition integration, etc., please refer to [ThemeProvider - Inject Custom Token Theme](/api/theme-provider#inject-custom-token-theme). + +:::success{title=Application Example} +The document theme package used by antd-style has customized some custom tokens required by the theme package. If interested, you can go to [dumi-theme-antd-style](https://dumi-theme-antd-style.arvinx.app/components/dumi-site-provider#demo) to view. +::: + +## Custom Appearance Mode + +In addition, since `appearance` can be controlled and used, it is also possible to customize the Appearance mode to extend different themes. + + + +:::warning +If you need to customize the Appearance mode, it is not recommended to set `themeMode` to `auto`, as this will cause the Appearance mode to be affected by system theme switching, which may not meet your expectations. +::: diff --git a/docs/guide/index.en-US.md b/docs/guide/index.en-US.md new file mode 100644 index 00000000..9a238254 --- /dev/null +++ b/docs/guide/index.en-US.md @@ -0,0 +1,32 @@ +--- +title: Introduction +order: 0 +nav: + title: Quick Start + order: 0 +group: + title: Basic Knowledge + order: 0 +--- + +# Introduction + +`antd-style` is a business-level css-in-js solution built on the Ant Design V5 Token System, and it is based on the secondary encapsulation of emotion. + +## Motivation | Why this library exists + +Antd v5 has been officially released, bringing unparalleled theme customization capabilities through the CSSinJS technology, which we believe is the future direction. However, at present, both internal application landing and community feedback on how to use the antd v5 token system, how to migrate from less, and how to integrate cssinjs into applications have made it difficult for application developers to start using the CSSinJS technology to write styles. + +As a component library, antd's responsibility and boundary are only to provide high-quality basic components, and it does not restrict how the application layer uses style solutions. Developers can use less/sass, styled-component, and other solutions without any problems. However, in order to make the promotion of the v5 token system smoother, we need to provide a best practice for using the antd token system, helping application developers to integrate the CSSinJS technology solution into applications with lower thresholds, and enjoy the UX and DX upgrades brought by new technologies. + +## Features | What it can do + +It has the following features: + + + +## What is the difference between it and @ant-design/cssinjs? + +`@ant-design/cssinjs` is a cssinjs solution for implementing the antd component library. It achieves much better performance compared to styled-component and emotion through a more cumbersome syntax. See: [Component-level CSS-in-JS](https://ant.design/docs/blog/css-in-js-cn). However, for applications and component libraries based on antd, this syntax may be too cumbersome and complex, and lacks the ability to consume the antd token system. + +Therefore, the applicable scenarios for antd-style are business applications and component libraries based on antd secondary encapsulation, providing all the capabilities needed for these two scenarios. diff --git a/docs/guide/migrate-less-application.en-US.md b/docs/guide/migrate-less-application.en-US.md new file mode 100644 index 00000000..f06f3f2c --- /dev/null +++ b/docs/guide/migrate-less-application.en-US.md @@ -0,0 +1,149 @@ +--- +title: Manual Migration of Less Applications +order: 1 +group: Migrating from Less +--- + +# Migrating Less Applications + +createStyle can be used to create and write style code very simply, and it can provide intelligent prompts and type checking, which is completely sufficient for writing new styles. However, there are still a large amount of old project code in our hands. How can we quickly migrate to antd-style? + +## Steps for Migrating Applications + +Taking the HeaderSearch in Ant Design Pro as an example, the core code related to styles is as follows: + + + +### 1. Replace the Entry File + +Change the style file from `index.less` to `style.ts`, and add the hooks `const { styles } = useStyles()` import. This way, the JSX layer code is modified. + +```diff +// index.tsx +- import styles from './index.less'; ++ import useStyles from './style.ts'; + + +const Login: React.FC = () => { ++ const { styles } = useStyles(); + + // The following code remains unchanged + return ( + .. +``` + +### 2. Replace the Style Code + +Change the style code from less syntax to createStyles syntax. First, rename `index.less` to `style.ts`, and then add the following at the top: + +```diff ++ import { createStyles } from 'antd-style'; + ++ export default createStyles(()=>({ +``` + +Next, use some tools to help us quickly convert CSS to CSS Object, for example: + +- : Transform CSS to JS tool, which can handle nesting normally, but the converted result will retain the '.' prefix, which still needs to be manually removed; +- : This can directly convert to the target style needed, but it seems that the support for nested CSS is not ideal; +- : VSCode plugin that can convert with one click, but has poor compatibility with less variables; + +```ts +// style.ts +import { createStyles } from 'antd-style'; + +export default createStyles(() => ({ + container: { + background: '#f5f5f5', + height: 200, + display: 'flex', + alignItems: 'center', + justifyContent: 'center', + }, + headerSearch: { + display: 'inline-flex', + alignItems: 'center', + input: { + width: '0', + minWidth: '0', + overflow: 'hidden', + background: 'transparent', + borderRadius: '0', + transition: 'width 0.3s, margin-left 0.3s', + input: { boxShadow: 'none !important' }, + '&.show': { width: '210px', marginLeft: '8px' }, + }, + }, +})); +``` + +And change the nested style objects to be at the same level: + +```ts +import { createStyles } from 'antd-style'; + +export default createStyles(() => ({ + container: { + background: '#f5f5f5', + height: 200, + display: 'flex', + alignItems: 'center', + justifyContent: 'center', + }, + headerSearch: { + display: 'inline-flex', + alignItems: 'center', + }, + input: { + width: '0', + minWidth: '0', + overflow: 'hidden', + background: 'transparent', + borderRadius: '0', + transition: 'width 0.3s, margin-left 0.3s', + input: { boxShadow: 'none !important' }, + }, + show: { width: '210px', marginLeft: '8px' }, +})); +``` + +Finally, replace the color values with antd's tokens + +```diff +import { createStyles } from 'antd-style'; + +- export default createStyles(() => ({ ++ export default createStyles(({ token }) => ({ + container: { +- background: "#f5f5f5", ++ background: token.colorBgLayout, + height: 200, + display: 'flex', + alignItems: 'center', + justifyContent: 'center', + }, + headerSearch: { + display: 'inline-flex', + alignItems: 'center', + }, + input: { + width: '0', + minWidth: '0', + overflow: 'hidden', + background: 'transparent', + borderRadius: '0', + transition: 'width 0.3s, margin-left 0.3s', + ':global(.ant-select-selection)': { background: 'transparent' }, + input: { boxShadow: 'none !important' }, + }, + show: { width: '210px', marginLeft: '8px' }, +})); +``` + +The final effect is as follows: + + + +After the migration is completed, thanks to the good type programming ability of TS, we not only have the ability to dynamically theme, but also have the ability to drill down into class names, improving the development experience. + +![](https://gw.alipayobjects.com/zos/kitchen/szcQ1qz3n/style.gif) diff --git a/docs/guide/migrate-less-codemod.en-US.md b/docs/guide/migrate-less-codemod.en-US.md new file mode 100644 index 00000000..3843b28d --- /dev/null +++ b/docs/guide/migrate-less-codemod.en-US.md @@ -0,0 +1,41 @@ +--- +title: Less Application Automated Migration +order: 0 +group: Migrating from Less +--- + +# Migrate Less Applications with Codemod + +To facilitate the unified upgrade of business applications, we provide a one-click migration codemod from less to antd-style. + +## Usage + +Simply execute the following command in the project root directory: + +```bash +npx @chenshuai2144/less2cssinjs less2js -i src +``` + +Where `src` is the project directory. + +![](https://github-production-user-asset-6210df.s3.amazonaws.com/28616219/243153216-bed3780c-1642-456f-8b04-a81940f62fec.png) + +## Transformation Logic + +In this codemod, we will perform the following transformations: + +For less files: + +1. Create a new `[file].style.ts` file, where `file` is the name of the less file. +2. Convert the styles in the less file to the css object syntax in antd-style. +3. Flatten the nested syntax in less to a single level. +4. Automatically replace less variables with antd-style tokens. + +For ts files: + +1. Replace import less with `import useStyles from '[file].style'`. +2. Add `const { style } = useStyles()`. + +## Notes + +TBD diff --git a/docs/guide/migrate-less-component.en-US.md b/docs/guide/migrate-less-component.en-US.md new file mode 100644 index 00000000..8ad6cab0 --- /dev/null +++ b/docs/guide/migrate-less-component.en-US.md @@ -0,0 +1,127 @@ +--- +title: Migrating Less Components +order: 2 +group: Migrating from Less +--- + +# Migrating Component Code + +The component demo below is from the ProCard's [Static component](https://github.com/ant-design/pro-components/blob/v1/packages/card/src/components/Statistic/index.less) in procomponents. + + + +## Migration Steps + +### 1. Replace Entry Point + +Change the style file from `index.less` to `style.ts`, and add the hooks `const { styles } = useStyles()` import. Combine the styles and the default container class in the JSX layer. This way, the JSX layer code is updated. + +```diff +// index.tsx +- import './index.less'; ++ import useStyles from './style.ts'; + + +const Statistic: React.FC = () => { ++ const { styles, cx } = useStyles(); + + //... + + return ( +-
++
+ // The following code remains unchanged + //... + )} + +``` + +### 2. Replace Style Code + +Change the style code from less syntax to createStyles syntax. First, rename `index.less` to `style.ts`, then add the following at the top: + +```diff ++ import { createStyles } from 'antd-style'; + ++ export const useStyles = createStyles(({css})=>{ + + return css` + ` +}) +``` + +Then place the original code inside the css function. + +```diff +import { createStyles } from 'antd-style'; + +export const useStyles = createStyles(({css})=>{ + + return css` ++ .@{pro-card-statistic-prefix-cls} { ++ // ... ++ } + ` +}) +``` + +### 3. Adjust Hierarchy + +Since we use css\`\` to provide scope, the nested level styles need to be adjusted as follows: + +```diff +import { createStyles } from 'antd-style'; + +export const useStyles = createStyles(({css})=>{ + + return css` +- .@{pro-card-statistic-prefix-cls} { ++ & .@{pro-card-statistic-prefix-cls} { + // ... + } ++ .@{pro-card-statistic-prefix-cls} { ++ & + & { ++ // ... ++ } ++ } + ` +}) +``` + +### 4. Replace Less Variables with Tokens and JS Variables + +```diff +import { createStyles } from 'antd-style'; + +export const useStyles = createStyles(({ css, prefixCls })=>{ + const prefix = `${prefixCls}-pro-card-statistic`; + + return css` +- .@{pro-card-statistic-prefix-cls} { ++ & .${prefix} { +- font-size: @font-size-base; ++ font-size: ${token.fontSize}px; + } +- .@{pro-card-statistic-prefix-cls} { ++ .${prefix} { + & + & { + +- .@{ant-prefix}-statistic-title { +- color: @text-color; ++ .${prefixCls}-statistic-title { ++ color: ${token.colorText}; + } + + ++ } + ` +}) +``` + +The effect after migration is shown below. It can be seen that after a relatively low migration cost, the new component writing method already supports the ability to respond to themes by default and gains all the dynamic capabilities after cssinjs transformation. + + + +## New Component Writing Scheme + +See: [Component Development](/guide/components-usage#BestPracticeRecommendations) diff --git a/docs/guide/performance-comparsion.en-US.md b/docs/guide/performance-comparsion.en-US.md new file mode 100644 index 00000000..d71e46da --- /dev/null +++ b/docs/guide/performance-comparsion.en-US.md @@ -0,0 +1,39 @@ +--- +title: Performance Comparison of CSS-in-JS Libraries +order: 100 +group: Advanced Usage +--- + +# Performance Comparison of CSS-in-JS + +## Basic Rendering Performance Comparison + +```tsx | inline +import { FullscreenOutlined } from '@ant-design/icons'; +import { Button } from 'antd'; + +export default () => ( + + + +); +``` + + + +## Dynamic Value Rendering Performance Comparison + +```tsx | inline +import { FullscreenOutlined } from '@ant-design/icons'; +import { Button } from 'antd'; + +export default () => ( + + + +); +``` + + diff --git a/docs/guide/ssr.en-US.md b/docs/guide/ssr.en-US.md new file mode 100644 index 00000000..50dcbe70 --- /dev/null +++ b/docs/guide/ssr.en-US.md @@ -0,0 +1,233 @@ +--- +title: SSR Integration +order: 1 +group: Advanced Usage +--- + +# SSR Integration + +SSR (Server-side rendering) refers to the direct output of dynamically generated HTML to the browser on the server side in order to improve the initial loading speed of the page and SEO optimization. For SSR scenarios, antd-style provides a dedicated method to extract antd components and antd-style styles statically, thereby improving the rendering speed and performance of the page. The following is a guide on using antd-style in SSR: + +## Integration in Next.js + +### Page Router + +In Next.js server-side rendering, you need to use the `extractStaticStyle` method in the `getInitialProps` method of the component to extract static styles and add them to the page's head. The specific usage is as follows: + +```tsx | pure +// pages/_document.tsx +import { extractStaticStyle, StyleProvider } from 'antd-style'; +import Document, { DocumentContext, Head, Html, Main, NextScript } from 'next/document'; + +class MyDocument extends Document { + static async getInitialProps(ctx: DocumentContext) { + // Insert StyleProvider for rendering + const page = await ctx.renderPage({ + enhanceApp: (App) => (props) => + ( + + + + ), + }); + + // Get static styles of the page one by one + const styles = extractStaticStyle(page.html).map((item) => item.style); + + const initialProps = await Document.getInitialProps(ctx); + + return { + ...initialProps, + styles: ( + <> + {initialProps.styles} + {styles} + + ), + }; + } + + render() { + return ( + + {this.props.styles} + +
+ + + + ); + } +} + +export default MyDocument; +``` + +#### 1. Import and wrap the StyleProvider component, and wrap it around the component that needs to extract static styles: + +Pass the `enhanceApp` parameter to the `renderPage` method. `enhanceApp` is a function used to enhance the App component. Here, we wrap the App component in the StyleProvider component to extract static styles. + +```tsx | pure +import { extractStaticStyle, StyleProvider } from 'antd-style'; + +const page = await ctx.renderPage({ + enhanceApp: (App) => (props) => + ( + + + + ), +}); +``` + +Here, the `cache` field mounts the `@ant-design/cssinjs` cache object. + +#### 2. Use the `extractStaticStyle` method to extract static styles + +Call the `renderPage` method to get the rendered page content, and use the `extractStaticStyle` method to extract the static styles from it. + +```tsx | pure +// Extract page content styles +const styleArr = extractStaticStyle(page.html); +``` + +The styles extracted by the `extractStaticStyle` method is an array, which includes the style objects of antd and antd-style. The structure of each style object is as follows: + +| Property | Type | Description | +| -------- | ------------- | --------------------------------------------------------------------------------------------- | +| key | `string` | Key value, the key of antd style is `antd`, and the default key of antd-style style is `acss` | +| style | `JSX.Element` | Style element, represented using the JSX.Element type | +| css | `string` | Corresponding CSS string | +| ids | `string[]` | Array of element IDs to which the style is applied | +| tag | `string` | CSS string with `