chore: auto merge branches (#50707)

chore: feature merge master
This commit is contained in:
github-actions[bot] 2024-09-04 06:46:25 +00:00 committed by GitHub
commit 5697b040d8
No known key found for this signature in database
GPG Key ID: B5690EEEBB952194
47 changed files with 1348 additions and 143 deletions

View File

@ -36,7 +36,7 @@ jobs:
🎉 感谢您的贡献!如果您还没有加入钉钉社区群,请扫描下方二维码加入我们(加群时请提供此 PR 链接)。
<img src="https://github.com/ant-design/ant-design/assets/5378891/e24c6080-bf38-4523-b1cd-f6c43ad7375f" height="200" />
<img src="https://github.com/user-attachments/assets/cfee105e-8731-481f-a336-92b79a84d35a" height="200" />
<!-- WELCOME_CONTRIBUTION -->
body-include: '<!-- WELCOME_CONTRIBUTION -->'

View File

@ -40,7 +40,7 @@ jobs:
- name: create pull request
id: cpr
uses: peter-evans/create-pull-request@v6
uses: peter-evans/create-pull-request@v7
with:
token: ${{ secrets.GITHUB_TOKEN }} # Cannot be default!!!
assignees: 'afc163, zombieJ, xrkffgg, MadCcc'

View File

@ -1,4 +1,4 @@
{
"*.{ts,tsx,js,jsx,json,css}": ["biome check --write"],
"*.{ts,tsx,js,jsx,css}": ["biome check --write"],
"*.{md,yml}": ["prettier --ignore-unknown --write"]
}

View File

@ -56,5 +56,6 @@
">= 5.16.0 <= 5.16.1": ["https://github.com/ant-design/ant-design/issues/48200"],
"5.16.3": ["https://github.com/ant-design/ant-design/issues/48568"],
"5.17.1": ["https://github.com/ant-design/ant-design/issues/48913"],
"5.18.2": ["https://github.com/ant-design/ant-design/pull/49487"]
"5.18.2": ["https://github.com/ant-design/ant-design/pull/49487"],
"5.20.4": ["https://github.com/ant-design/ant-design/issues/50687"]
}

View File

@ -16,6 +16,27 @@ tag: vVERSION
---
## 5.20.5
`2024-09-03`
- 🛠 Adjust Tree & TreeSelect `defaultExpandAll` logic to only add internal `expandedKeys` which `treeNode` has children instead to avoid perf issue when with large data or `loadData` case. [#50689](https://github.com/ant-design/ant-design/pull/50689) [@zombieJ](https://github.com/zombieJ)
- 🐞 Fix Cascader not show parent option in search when using `multiple`. [#50689](https://github.com/ant-design/ant-design/pull/50689)
- 🐞 Fix Typography `ellipsis.tooltip.title` with ReactNode will cause dead loop. [#50688](https://github.com/ant-design/ant-design/pull/50688) [@zombieJ](https://github.com/zombieJ)
## 5.20.4
`2024-09-02`
- Menu
- 🐞 Fix Menu token `itemPaddingInline inoperative` not working. [#50663](https://github.com/ant-design/ant-design/pull/50663) [@coding-ice](https://github.com/coding-ice)
- 🐞 Fix Menu missing `hover` transition style. [#50624](https://github.com/ant-design/ant-design/pull/50624) [@afc163](https://github.com/afc163)
- 💄 Badge add transition effect to count node. [#50607](https://github.com/ant-design/ant-design/pull/50607) [@afc163](https://github.com/afc163)
- 💄 Fix Table column header move with unexpected transition. [#50605](https://github.com/ant-design/ant-design/pull/50605) [@afc163](https://github.com/afc163)
- 🛠 Refactor Typography code to optimize internal logic. [#50561](https://github.com/ant-design/ant-design/pull/50561) [@afc163](https://github.com/afc163)
- 🐞 Disable the Rate component within Form.Item when the form is disabled. [#50594](https://github.com/ant-design/ant-design/pull/50594) [@nikzanda](https://github.com/nikzanda)
- 🌐 Patch tr_TR `Transfer.deselectAll` locale. [#50672](https://github.com/ant-design/ant-design/pull/50672) [@coding-ice](https://github.com/coding-ice)
## 5.20.3
`2024-08-26`

View File

@ -15,6 +15,27 @@ tag: vVERSION
---
## 5.20.5
`2024-09-03`
- 🛠 调整 Tree 与 TreeSelect 的 `defaultExpandAll` 的行为,仅将有子节点的 `treeNode` 加入 `expandedKeys` 以防止在大数据与 `loadData` 异步的情况下引发的性能问题。[#50689](https://github.com/ant-design/ant-design/pull/50689) [@zombieJ](https://github.com/zombieJ)
- 🐞 修复 Cascader 在 `multiple` 下搜索不会显示父节点作为选项的问题。[#50689](https://github.com/ant-design/ant-design/pull/50689)
- 🐞 修复 Typography `ellipsis.tooltip.title` 配置 ReactNode 会导致死循环的问题。[#50688](https://github.com/ant-design/ant-design/pull/50688) [@zombieJ](https://github.com/zombieJ)
## 5.20.4
`2024-09-02`
- Menu
- 🐞 修复 Menu 的 `itemPaddingInline` token 不生效的问题。[#50663](https://github.com/ant-design/ant-design/pull/50663) [@coding-ice](https://github.com/coding-ice)
- 🐞 修复 Menu `hover` 时背景色切换渐变效果丢失的问题。[#50624](https://github.com/ant-design/ant-design/pull/50624) [@afc163](https://github.com/afc163)
- 💄 给 Badge 增加一个动画缓动效果。[#50607](https://github.com/ant-design/ant-design/pull/50607) [@afc163](https://github.com/afc163)
- 💄 修复 Table 列头切换状态时多余的的移动缓动动画。[#50605](https://github.com/ant-design/ant-design/pull/50605) [@afc163](https://github.com/afc163)
- 🛠 重构 Typography 代码以优化内部实现逻辑。[#50561](https://github.com/ant-design/ant-design/pull/50561) [@afc163](https://github.com/afc163)
- 🐞 当表单被禁用时,禁用 Form.Item 中的 Rate 组件。[#50594](https://github.com/ant-design/ant-design/pull/50594) [@nikzanda](https://github.com/nikzanda)
- 🌐 补充土耳其 `Transfer.deselectAll` 本地化文本。[#50672](https://github.com/ant-design/ant-design/pull/50672) [@coding-ice](https://github.com/coding-ice)
## 5.20.3
`2024-08-26`

View File

@ -1,5 +1,6 @@
{
"files": {
"ignoreUnknown": true,
"ignore": [
".dumi/tmp*",
".dumi/scripts/clarity.js",

View File

@ -2508,7 +2508,7 @@ exports[`renders components/button/demo/linear-gradient.tsx extend context corre
class="ant-space-item"
>
<button
class="ant-btn ant-btn-primary ant-btn-solid ant-btn-lg css-ykstnd"
class="ant-btn ant-btn-primary ant-btn-solid ant-btn-lg acss-9mi5l3"
type="button"
>
<span
@ -2543,7 +2543,7 @@ exports[`renders components/button/demo/linear-gradient.tsx extend context corre
class="ant-space-item"
>
<button
class="ant-btn ant-btn-default ant-btn-outlined ant-btn-lg css-ykstnd"
class="ant-btn ant-btn-default ant-btn-outlined ant-btn-lg acss-9mi5l3"
type="button"
>
<span>

View File

@ -2136,7 +2136,7 @@ exports[`renders components/button/demo/linear-gradient.tsx correctly 1`] = `
class="ant-space-item"
>
<button
class="ant-btn ant-btn-primary ant-btn-solid ant-btn-lg css-ykstnd"
class="ant-btn ant-btn-primary ant-btn-solid ant-btn-lg acss-9mi5l3"
type="button"
>
<span
@ -2171,7 +2171,7 @@ exports[`renders components/button/demo/linear-gradient.tsx correctly 1`] = `
class="ant-space-item"
>
<button
class="ant-btn ant-btn-default ant-btn-outlined ant-btn-lg css-ykstnd"
class="ant-btn ant-btn-default ant-btn-outlined ant-btn-lg acss-9mi5l3"
type="button"
>
<span>

View File

@ -1,13 +1,11 @@
import React, { useContext } from 'react';
import { Button, ConfigProvider, Space } from 'antd';
import React from 'react';
import { AntDesignOutlined } from '@ant-design/icons';
import { css } from '@emotion/css';
import { Button, ConfigProvider, Space } from 'antd';
import { createStyles } from 'antd-style';
const App: React.FC = () => {
const { getPrefixCls } = useContext(ConfigProvider.ConfigContext);
const rootPrefixCls = getPrefixCls();
const linearGradientButton = css`
&.${rootPrefixCls}-btn-primary:not([disabled]):not(.${rootPrefixCls}-btn-dangerous) {
const useStyle = createStyles(({ prefixCls, css }) => ({
linearGradientButton: css`
&.${prefixCls}-btn-primary:not([disabled]):not(.${prefixCls}-btn-dangerous) {
border-width: 0;
> span {
@ -16,7 +14,7 @@ const App: React.FC = () => {
&::before {
content: '';
background: linear-gradient(135deg, #6253E1, #04BEFE);
background: linear-gradient(135deg, #6253e1, #04befe);
position: absolute;
inset: 0;
opacity: 1;
@ -28,11 +26,16 @@ const App: React.FC = () => {
opacity: 0;
}
}
`;
`,
}));
const App: React.FC = () => {
const { styles } = useStyle();
return (
<ConfigProvider
button={{
className: linearGradientButton,
className: styles.linearGradientButton,
}}
>
<Space>

View File

@ -51,7 +51,7 @@ Common props ref[Common props](/docs/react/common-props)
| allowClear | Show clear button | boolean \| { clearIcon?: ReactNode } | true | 5.8.0: Support object type |
| autoClearSearchValue | Whether the current search will be cleared on selecting an item. Only applies when `multiple` is `true` | boolean | true | 5.9.0 |
| autoFocus | If get focus when component mounted | boolean | false | |
| changeOnSelect | (Work on single select) Change value on each selection if set to true, see above demo for details | boolean | false | |
| changeOnSelect | Change value on each selection if set to true, see above demo for details | boolean | false | |
| className | The additional css class | string | - | |
| defaultValue | Initial selected value | string\[] \| number\[] | \[] | |
| disabled | Whether disabled select | boolean | false | |

View File

@ -52,7 +52,7 @@ demo:
| allowClear | 支持清除 | boolean \| { clearIcon?: ReactNode } | true | 5.8.0: 支持对象形式 |
| autoClearSearchValue | 是否在选中项后清空搜索框,只在 `multiple``true` 时有效 | boolean | true | 5.9.0 |
| autoFocus | 自动获取焦点 | boolean | false | |
| changeOnSelect | (单选时生效)当此项为 true 时,点选每级菜单选项值都会发生变化,具体见上面的演示 | boolean | false | |
| changeOnSelect | 单选时生效multiple 下始终都可以选择),点选每级菜单选项值都会发生变化。 | boolean | false | |
| className | 自定义类名 | string | - | |
| defaultValue | 默认的选中项 | string\[] \| number\[] | \[] | |
| disabled | 禁用 | boolean | false | |

View File

@ -11,6 +11,7 @@ import { ConfigContext } from '../config-provider';
import useRemovePasswordTimeout from './hooks/useRemovePasswordTimeout';
import type { InputProps, InputRef } from './Input';
import Input from './Input';
import DisabledContext from '../config-provider/DisabledContext';
const defaultIconRender = (visible: boolean): React.ReactNode =>
visible ? <EyeOutlined /> : <EyeInvisibleOutlined />;
@ -36,12 +37,16 @@ type IconPropsType = React.HTMLAttributes<HTMLSpanElement> & React.Attributes;
const Password = React.forwardRef<InputRef, PasswordProps>((props, ref) => {
const {
disabled,
disabled: customDisabled,
action = 'click',
visibilityToggle = true,
iconRender = defaultIconRender,
} = props;
// ===================== Disabled =====================
const disabled = React.useContext(DisabledContext);
const mergedDisabled = customDisabled ?? disabled;
const visibilityControlled =
typeof visibilityToggle === 'object' && visibilityToggle.visible !== undefined;
const [visible, setVisible] = useState(() =>
@ -59,7 +64,7 @@ const Password = React.forwardRef<InputRef, PasswordProps>((props, ref) => {
const removePasswordTimeout = useRemovePasswordTimeout(inputRef);
const onVisibleChange = () => {
if (disabled) {
if (mergedDisabled) {
return;
}
if (visible) {

View File

@ -10601,6 +10601,48 @@ exports[`renders components/input/demo/password-input.tsx extend context correct
</div>
</div>
</div>
<div
class="ant-space-item"
>
<span
class="ant-input-affix-wrapper ant-input-disabled ant-input-affix-wrapper-disabled ant-input-outlined ant-input-password"
>
<input
class="ant-input ant-input-disabled"
disabled=""
placeholder="disabled input password"
type="password"
value=""
/>
<span
class="ant-input-suffix"
>
<span
aria-label="eye-invisible"
class="anticon anticon-eye-invisible ant-input-password-icon"
role="img"
tabindex="-1"
>
<svg
aria-hidden="true"
data-icon="eye-invisible"
fill="currentColor"
focusable="false"
height="1em"
viewBox="64 64 896 896"
width="1em"
>
<path
d="M942.2 486.2Q889.47 375.11 816.7 305l-50.88 50.88C807.31 395.53 843.45 447.4 874.7 512 791.5 684.2 673.4 766 512 766q-72.67 0-133.87-22.38L323 798.75Q408 838 512 838q288.3 0 430.2-300.3a60.29 60.29 0 000-51.5zm-63.57-320.64L836 122.88a8 8 0 00-11.32 0L715.31 232.2Q624.86 186 512 186q-288.3 0-430.2 300.3a60.3 60.3 0 000 51.5q56.69 119.4 136.5 191.41L112.48 835a8 8 0 000 11.31L155.17 889a8 8 0 0011.31 0l712.15-712.12a8 8 0 000-11.32zM149.3 512C232.6 339.8 350.7 258 512 258c54.54 0 104.13 9.36 149.12 28.39l-70.3 70.3a176 176 0 00-238.13 238.13l-83.42 83.42C223.1 637.49 183.3 582.28 149.3 512zm246.7 0a112.11 112.11 0 01146.2-106.69L401.31 546.2A112 112 0 01396 512z"
/>
<path
d="M508 624c-3.46 0-6.87-.16-10.25-.47l-52.82 52.82a176.09 176.09 0 00227.42-227.42l-52.82 52.82c.31 3.38.47 6.79.47 10.25a111.94 111.94 0 01-112 112z"
/>
</svg>
</span>
</span>
</span>
</div>
</div>
`;

View File

@ -3947,6 +3947,48 @@ exports[`renders components/input/demo/password-input.tsx correctly 1`] = `
</div>
</div>
</div>
<div
class="ant-space-item"
>
<span
class="ant-input-affix-wrapper ant-input-disabled ant-input-affix-wrapper-disabled ant-input-outlined ant-input-password"
>
<input
class="ant-input ant-input-disabled"
disabled=""
placeholder="disabled input password"
type="password"
value=""
/>
<span
class="ant-input-suffix"
>
<span
aria-label="eye-invisible"
class="anticon anticon-eye-invisible ant-input-password-icon"
role="img"
tabindex="-1"
>
<svg
aria-hidden="true"
data-icon="eye-invisible"
fill="currentColor"
focusable="false"
height="1em"
viewBox="64 64 896 896"
width="1em"
>
<path
d="M942.2 486.2Q889.47 375.11 816.7 305l-50.88 50.88C807.31 395.53 843.45 447.4 874.7 512 791.5 684.2 673.4 766 512 766q-72.67 0-133.87-22.38L323 798.75Q408 838 512 838q288.3 0 430.2-300.3a60.29 60.29 0 000-51.5zm-63.57-320.64L836 122.88a8 8 0 00-11.32 0L715.31 232.2Q624.86 186 512 186q-288.3 0-430.2 300.3a60.3 60.3 0 000 51.5q56.69 119.4 136.5 191.41L112.48 835a8 8 0 000 11.31L155.17 889a8 8 0 0011.31 0l712.15-712.12a8 8 0 000-11.32zM149.3 512C232.6 339.8 350.7 258 512 258c54.54 0 104.13 9.36 149.12 28.39l-70.3 70.3a176 176 0 00-238.13 238.13l-83.42 83.42C223.1 637.49 183.3 582.28 149.3 512zm246.7 0a112.11 112.11 0 01146.2-106.69L401.31 546.2A112 112 0 01396 512z"
/>
<path
d="M508 624c-3.46 0-6.87-.16-10.25-.47l-52.82 52.82a176.09 176.09 0 00227.42-227.42l-52.82 52.82c.31 3.38.47 6.79.47 10.25a111.94 111.94 0 01-112 112z"
/>
</svg>
</span>
</span>
</span>
</div>
</div>
`;

View File

@ -21,6 +21,7 @@ const App: React.FC = () => {
{passwordVisible ? 'Hide' : 'Show'}
</Button>
</Space>
<Input.Password disabled placeholder="disabled input password" />
</Space>
);
};

View File

@ -466,6 +466,7 @@ const genAffixStyle: GenerateStyle<InputToken> = (token: InputToken) => {
} = token;
const affixCls = `${componentCls}-affix-wrapper`;
const affixClsDisabled = `${componentCls}-affix-wrapper-disabled`;
return {
[affixCls]: {
@ -552,6 +553,17 @@ const genAffixStyle: GenerateStyle<InputToken> = (token: InputToken) => {
},
},
},
[affixClsDisabled]: {
// password disabled
[`${iconCls}${componentCls}-password-icon`]: {
color: colorIcon,
cursor: 'not-allowed',
'&:hover': {
color: colorIcon,
},
},
},
};
};

View File

@ -50,6 +50,7 @@ const localeValues: Locale = {
selectCurrent: 'Tüm sayfayı seç',
removeCurrent: 'Sayfayı kaldır',
selectAll: 'Tümünü seç',
deselectAll: 'Tümünün seçimini kaldır',
removeAll: 'Tümünü kaldır',
selectInvert: 'Tersini seç',
},

View File

@ -15,6 +15,7 @@ const getVerticalInlineStyle: GenerateStyle<MenuToken, CSSObject> = (token) => {
marginXS,
itemMarginBlock,
itemWidth,
itemPaddingInline,
} = token;
const paddingWithArrow = token.calc(menuArrowSize).add(padding).add(marginXS).equal();
@ -28,7 +29,7 @@ const getVerticalInlineStyle: GenerateStyle<MenuToken, CSSObject> = (token) => {
[`${componentCls}-item, ${componentCls}-submenu-title`]: {
height: itemHeight,
lineHeight: unit(itemHeight),
paddingInline: padding,
paddingInline: itemPaddingInline,
overflow: 'hidden',
textOverflow: 'ellipsis',
marginInline: itemMarginInline,

View File

@ -8459,7 +8459,7 @@ exports[`renders components/select/demo/option-label-center.tsx extend context c
</div>
<div
aria-grabbed="false"
class="ant-select-tree-treenode ant-select-tree-treenode-switcher-open"
class="ant-select-tree-treenode ant-select-tree-treenode-switcher-close"
draggable="false"
>
<span
@ -8490,7 +8490,7 @@ exports[`renders components/select/demo/option-label-center.tsx extend context c
</div>
<div
aria-grabbed="false"
class="ant-select-tree-treenode ant-select-tree-treenode-switcher-open"
class="ant-select-tree-treenode ant-select-tree-treenode-switcher-close"
draggable="false"
>
<span
@ -8521,7 +8521,7 @@ exports[`renders components/select/demo/option-label-center.tsx extend context c
</div>
<div
aria-grabbed="false"
class="ant-select-tree-treenode ant-select-tree-treenode-switcher-open ant-select-tree-treenode-leaf-last"
class="ant-select-tree-treenode ant-select-tree-treenode-switcher-close ant-select-tree-treenode-leaf-last"
draggable="false"
>
<span

View File

@ -8539,7 +8539,7 @@ exports[`renders components/space/demo/compact.tsx extend context correctly 1`]
</div>
<div
aria-grabbed="false"
class="ant-select-tree-treenode ant-select-tree-treenode-switcher-open ant-select-tree-treenode-selected"
class="ant-select-tree-treenode ant-select-tree-treenode-switcher-close ant-select-tree-treenode-selected"
draggable="false"
>
<span
@ -8569,7 +8569,7 @@ exports[`renders components/space/demo/compact.tsx extend context correctly 1`]
</div>
<div
aria-grabbed="false"
class="ant-select-tree-treenode ant-select-tree-treenode-switcher-open ant-select-tree-treenode-leaf-last"
class="ant-select-tree-treenode ant-select-tree-treenode-switcher-close ant-select-tree-treenode-leaf-last"
draggable="false"
>
<span
@ -8646,7 +8646,7 @@ exports[`renders components/space/demo/compact.tsx extend context correctly 1`]
</div>
<div
aria-grabbed="false"
class="ant-select-tree-treenode ant-select-tree-treenode-switcher-open ant-select-tree-treenode-leaf-last"
class="ant-select-tree-treenode ant-select-tree-treenode-switcher-close ant-select-tree-treenode-leaf-last"
draggable="false"
>
<span

View File

@ -10324,7 +10324,7 @@ exports[`renders components/table/demo/filter-in-tree.tsx extend context correct
>
<div
aria-grabbed="false"
class="ant-tree-treenode ant-tree-treenode-switcher-open"
class="ant-tree-treenode ant-tree-treenode-switcher-close"
draggable="false"
>
<span
@ -10404,7 +10404,7 @@ exports[`renders components/table/demo/filter-in-tree.tsx extend context correct
</div>
<div
aria-grabbed="false"
class="ant-tree-treenode ant-tree-treenode-switcher-open"
class="ant-tree-treenode ant-tree-treenode-switcher-close"
draggable="false"
>
<span
@ -10438,7 +10438,7 @@ exports[`renders components/table/demo/filter-in-tree.tsx extend context correct
</div>
<div
aria-grabbed="false"
class="ant-tree-treenode ant-tree-treenode-switcher-open ant-tree-treenode-leaf-last"
class="ant-tree-treenode ant-tree-treenode-switcher-close ant-tree-treenode-leaf-last"
draggable="false"
>
<span
@ -10522,7 +10522,7 @@ exports[`renders components/table/demo/filter-in-tree.tsx extend context correct
</div>
<div
aria-grabbed="false"
class="ant-tree-treenode ant-tree-treenode-switcher-open"
class="ant-tree-treenode ant-tree-treenode-switcher-close"
draggable="false"
>
<span
@ -10556,7 +10556,7 @@ exports[`renders components/table/demo/filter-in-tree.tsx extend context correct
</div>
<div
aria-grabbed="false"
class="ant-tree-treenode ant-tree-treenode-switcher-open ant-tree-treenode-leaf-last"
class="ant-tree-treenode ant-tree-treenode-switcher-close ant-tree-treenode-leaf-last"
draggable="false"
>
<span
@ -11264,7 +11264,7 @@ exports[`renders components/table/demo/filter-search.tsx extend context correctl
>
<div
aria-grabbed="false"
class="ant-tree-treenode ant-tree-treenode-switcher-open"
class="ant-tree-treenode ant-tree-treenode-switcher-close"
draggable="false"
>
<span
@ -11294,7 +11294,7 @@ exports[`renders components/table/demo/filter-search.tsx extend context correctl
</div>
<div
aria-grabbed="false"
class="ant-tree-treenode ant-tree-treenode-switcher-open"
class="ant-tree-treenode ant-tree-treenode-switcher-close"
draggable="false"
>
<span
@ -11324,7 +11324,7 @@ exports[`renders components/table/demo/filter-search.tsx extend context correctl
</div>
<div
aria-grabbed="false"
class="ant-tree-treenode ant-tree-treenode-switcher-open ant-tree-treenode-leaf-last"
class="ant-tree-treenode ant-tree-treenode-switcher-close ant-tree-treenode-leaf-last"
draggable="false"
>
<span

View File

@ -172,6 +172,366 @@ Array [
exports[`renders components/tour/demo/basic.tsx extend context correctly 2`] = `[]`;
exports[`renders components/tour/demo/gap.tsx extend context correctly 1`] = `
<div>
<button
class="ant-btn ant-btn-primary ant-btn-solid"
type="button"
>
<span>
Begin Tour
</span>
</button>
<div
class="ant-space ant-space-vertical ant-space-gap-row-small ant-space-gap-col-small"
style="display: flex; margin-top: 12px;"
>
<div
class="ant-space-item"
>
<div
class="ant-row"
>
<div
class="ant-col ant-col-6"
>
<span
class="ant-typography"
>
Radius:
</span>
</div>
<div
class="ant-col ant-col-12"
>
<div
class="ant-slider ant-slider-horizontal"
>
<div
class="ant-slider-rail"
/>
<div
class="ant-slider-track"
style="left: 0%; width: 8%;"
/>
<div
class="ant-slider-step"
/>
<div
aria-disabled="false"
aria-orientation="horizontal"
aria-valuemax="100"
aria-valuemin="0"
aria-valuenow="8"
class="ant-slider-handle"
role="slider"
style="left: 8%; transform: translateX(-50%);"
tabindex="0"
/>
<div
class="ant-tooltip ant-zoom-big-fast-appear ant-zoom-big-fast-appear-prepare ant-zoom-big-fast ant-slider-tooltip ant-tooltip-placement-top"
style="--arrow-x: 0px; --arrow-y: 0px; left: -1000vw; top: -1000vh; box-sizing: border-box;"
>
<div
class="ant-tooltip-arrow"
style="position: absolute; bottom: 0px; left: 0px;"
/>
<div
class="ant-tooltip-content"
>
<div
class="ant-tooltip-inner"
role="tooltip"
>
8
</div>
</div>
</div>
</div>
</div>
</div>
</div>
<div
class="ant-space-item"
>
<div
class="ant-row"
>
<div
class="ant-col ant-col-6"
>
<span
class="ant-typography"
>
offset:
</span>
</div>
<div
class="ant-col ant-col-12"
>
<div
class="ant-slider ant-slider-horizontal"
>
<div
class="ant-slider-rail"
/>
<div
class="ant-slider-track"
style="left: 0%; width: 4%;"
/>
<div
class="ant-slider-step"
/>
<div
aria-disabled="false"
aria-orientation="horizontal"
aria-valuemax="50"
aria-valuemin="0"
aria-valuenow="2"
class="ant-slider-handle"
role="slider"
style="left: 4%; transform: translateX(-50%);"
tabindex="0"
/>
<div
class="ant-tooltip ant-zoom-big-fast-appear ant-zoom-big-fast-appear-prepare ant-zoom-big-fast ant-slider-tooltip ant-tooltip-placement-top"
style="--arrow-x: 0px; --arrow-y: 0px; left: -1000vw; top: -1000vh; box-sizing: border-box;"
>
<div
class="ant-tooltip-arrow"
style="position: absolute; bottom: 0px; left: 0px;"
/>
<div
class="ant-tooltip-content"
>
<div
class="ant-tooltip-inner"
role="tooltip"
>
2
</div>
</div>
</div>
</div>
</div>
</div>
</div>
<div
class="ant-space-item"
>
<div
class="ant-row"
>
<div
class="ant-col ant-col-6"
>
<span
class="ant-typography"
>
Horizontal offset:
</span>
</div>
<div
class="ant-col ant-col-12"
>
<div
class="ant-slider ant-slider-horizontal"
>
<div
class="ant-slider-rail"
/>
<div
class="ant-slider-track"
style="left: 0%; width: 4%;"
/>
<div
class="ant-slider-step"
/>
<div
aria-disabled="false"
aria-orientation="horizontal"
aria-valuemax="50"
aria-valuemin="0"
aria-valuenow="2"
class="ant-slider-handle"
role="slider"
style="left: 4%; transform: translateX(-50%);"
tabindex="0"
/>
<div
class="ant-tooltip ant-zoom-big-fast-appear ant-zoom-big-fast-appear-prepare ant-zoom-big-fast ant-slider-tooltip ant-tooltip-placement-top"
style="--arrow-x: 0px; --arrow-y: 0px; left: -1000vw; top: -1000vh; box-sizing: border-box;"
>
<div
class="ant-tooltip-arrow"
style="position: absolute; bottom: 0px; left: 0px;"
/>
<div
class="ant-tooltip-content"
>
<div
class="ant-tooltip-inner"
role="tooltip"
>
2
</div>
</div>
</div>
</div>
</div>
</div>
</div>
<div
class="ant-space-item"
>
<div
class="ant-row"
>
<div
class="ant-col ant-col-6"
>
<span
class="ant-typography"
>
Vertical offset:
</span>
</div>
<div
class="ant-col ant-col-12"
>
<div
class="ant-slider ant-slider-horizontal"
>
<div
class="ant-slider-rail"
/>
<div
class="ant-slider-track"
style="left: 0%; width: 4%;"
/>
<div
class="ant-slider-step"
/>
<div
aria-disabled="false"
aria-orientation="horizontal"
aria-valuemax="50"
aria-valuemin="0"
aria-valuenow="2"
class="ant-slider-handle"
role="slider"
style="left: 4%; transform: translateX(-50%);"
tabindex="0"
/>
<div
class="ant-tooltip ant-zoom-big-fast-appear ant-zoom-big-fast-appear-prepare ant-zoom-big-fast ant-slider-tooltip ant-tooltip-placement-top"
style="--arrow-x: 0px; --arrow-y: 0px; left: -1000vw; top: -1000vh; box-sizing: border-box;"
>
<div
class="ant-tooltip-arrow"
style="position: absolute; bottom: 0px; left: 0px;"
/>
<div
class="ant-tooltip-content"
>
<div
class="ant-tooltip-inner"
role="tooltip"
>
2
</div>
</div>
</div>
</div>
</div>
</div>
</div>
</div>
<div
class="ant-tour ant-tour-placement-bottom"
style="--arrow-x: 0px; --arrow-y: 0px; left: -1000vw; top: -1000vh; box-sizing: border-box; z-index: 1001;"
>
<div
class="ant-tour-arrow"
style="position: absolute; top: 0px; left: 0px;"
/>
<div
class="ant-tour-content"
>
<div
class="ant-tour-inner"
>
<button
class="ant-tour-close"
type="button"
>
<span
aria-label="close"
class="anticon anticon-close ant-tour-close-icon"
role="img"
>
<svg
aria-hidden="true"
data-icon="close"
fill="currentColor"
fill-rule="evenodd"
focusable="false"
height="1em"
viewBox="64 64 896 896"
width="1em"
>
<path
d="M799.86 166.31c.02 0 .04.02.08.06l57.69 57.7c.04.03.05.05.06.08a.12.12 0 010 .06c0 .03-.02.05-.06.09L569.93 512l287.7 287.7c.04.04.05.06.06.09a.12.12 0 010 .07c0 .02-.02.04-.06.08l-57.7 57.69c-.03.04-.05.05-.07.06a.12.12 0 01-.07 0c-.03 0-.05-.02-.09-.06L512 569.93l-287.7 287.7c-.04.04-.06.05-.09.06a.12.12 0 01-.07 0c-.02 0-.04-.02-.08-.06l-57.69-57.7c-.04-.03-.05-.05-.06-.07a.12.12 0 010-.07c0-.03.02-.05.06-.09L454.07 512l-287.7-287.7c-.04-.04-.05-.06-.06-.09a.12.12 0 010-.07c0-.02.02-.04.06-.08l57.7-57.69c.03-.04.05-.05.07-.06a.12.12 0 01.07 0c.03 0 .05.02.09.06L512 454.07l287.7-287.7c.04-.04.06-.05.09-.06a.12.12 0 01.07 0z"
/>
</svg>
</span>
</button>
<div
class="ant-tour-cover"
>
<img
alt="tour.png"
src="https://user-images.githubusercontent.com/5378891/197385811-55df8480-7ff4-44bd-9d43-a7dade598d70.png"
/>
</div>
<div
class="ant-tour-header"
>
<div
class="ant-tour-title"
>
Upload File
</div>
</div>
<div
class="ant-tour-description"
>
Put your files here.
</div>
<div
class="ant-tour-footer"
>
<div
class="ant-tour-buttons"
>
<button
class="ant-btn ant-btn-primary ant-btn-solid ant-btn-sm ant-tour-next-btn"
type="button"
>
<span>
Finish
</span>
</button>
</div>
</div>
</div>
</div>
</div>
</div>
`;
exports[`renders components/tour/demo/gap.tsx extend context correctly 2`] = `[]`;
exports[`renders components/tour/demo/indicator.tsx extend context correctly 1`] = `
Array [
<button

View File

@ -77,6 +77,208 @@ Array [
]
`;
exports[`renders components/tour/demo/gap.tsx correctly 1`] = `
<div>
<button
class="ant-btn ant-btn-primary ant-btn-solid"
type="button"
>
<span>
Begin Tour
</span>
</button>
<div
class="ant-space ant-space-vertical ant-space-gap-row-small ant-space-gap-col-small"
style="display:flex;margin-top:12px"
>
<div
class="ant-space-item"
>
<div
class="ant-row"
>
<div
class="ant-col ant-col-6"
>
<span
class="ant-typography"
>
Radius:
</span>
</div>
<div
class="ant-col ant-col-12"
>
<div
class="ant-slider ant-slider-horizontal"
>
<div
class="ant-slider-rail"
/>
<div
class="ant-slider-track"
style="left:0%;width:8%"
/>
<div
class="ant-slider-step"
/>
<div
aria-disabled="false"
aria-orientation="horizontal"
aria-valuemax="100"
aria-valuemin="0"
aria-valuenow="8"
class="ant-slider-handle"
role="slider"
style="left:8%;transform:translateX(-50%)"
tabindex="0"
/>
</div>
</div>
</div>
</div>
<div
class="ant-space-item"
>
<div
class="ant-row"
>
<div
class="ant-col ant-col-6"
>
<span
class="ant-typography"
>
offset:
</span>
</div>
<div
class="ant-col ant-col-12"
>
<div
class="ant-slider ant-slider-horizontal"
>
<div
class="ant-slider-rail"
/>
<div
class="ant-slider-track"
style="left:0%;width:4%"
/>
<div
class="ant-slider-step"
/>
<div
aria-disabled="false"
aria-orientation="horizontal"
aria-valuemax="50"
aria-valuemin="0"
aria-valuenow="2"
class="ant-slider-handle"
role="slider"
style="left:4%;transform:translateX(-50%)"
tabindex="0"
/>
</div>
</div>
</div>
</div>
<div
class="ant-space-item"
>
<div
class="ant-row"
>
<div
class="ant-col ant-col-6"
>
<span
class="ant-typography"
>
Horizontal offset:
</span>
</div>
<div
class="ant-col ant-col-12"
>
<div
class="ant-slider ant-slider-horizontal"
>
<div
class="ant-slider-rail"
/>
<div
class="ant-slider-track"
style="left:0%;width:4%"
/>
<div
class="ant-slider-step"
/>
<div
aria-disabled="false"
aria-orientation="horizontal"
aria-valuemax="50"
aria-valuemin="0"
aria-valuenow="2"
class="ant-slider-handle"
role="slider"
style="left:4%;transform:translateX(-50%)"
tabindex="0"
/>
</div>
</div>
</div>
</div>
<div
class="ant-space-item"
>
<div
class="ant-row"
>
<div
class="ant-col ant-col-6"
>
<span
class="ant-typography"
>
Vertical offset:
</span>
</div>
<div
class="ant-col ant-col-12"
>
<div
class="ant-slider ant-slider-horizontal"
>
<div
class="ant-slider-rail"
/>
<div
class="ant-slider-track"
style="left:0%;width:4%"
/>
<div
class="ant-slider-step"
/>
<div
aria-disabled="false"
aria-orientation="horizontal"
aria-valuemax="50"
aria-valuemin="0"
aria-valuenow="2"
class="ant-slider-handle"
role="slider"
style="left:4%;transform:translateX(-50%)"
tabindex="0"
/>
</div>
</div>
</div>
</div>
</div>
</div>
`;
exports[`renders components/tour/demo/indicator.tsx correctly 1`] = `
Array [
<button

View File

@ -430,6 +430,169 @@ exports[`Tour custom step pre btn & next btn className & style 1`] = `
exports[`Tour rtl render component should be rendered correctly in RTL direction 1`] = `null`;
exports[`Tour should support gap.offset 1`] = `
<body>
<div>
<button
type="button"
>
Show
</button>
<div
class="ant-tour ant-tour-placement-bottom"
style="--arrow-x: 0px; --arrow-y: 0px; left: -1000vw; top: -1000vh; box-sizing: border-box; z-index: 1001;"
>
<div
class="ant-tour-arrow"
style="position: absolute; top: 0px; left: 0px;"
/>
<div
class="ant-tour-content"
>
<div
class="ant-tour-inner"
>
<button
class="ant-tour-close"
type="button"
>
<span
aria-label="close"
class="anticon anticon-close ant-tour-close-icon"
role="img"
>
<svg
aria-hidden="true"
data-icon="close"
fill="currentColor"
fill-rule="evenodd"
focusable="false"
height="1em"
viewBox="64 64 896 896"
width="1em"
>
<path
d="M799.86 166.31c.02 0 .04.02.08.06l57.69 57.7c.04.03.05.05.06.08a.12.12 0 010 .06c0 .03-.02.05-.06.09L569.93 512l287.7 287.7c.04.04.05.06.06.09a.12.12 0 010 .07c0 .02-.02.04-.06.08l-57.7 57.69c-.03.04-.05.05-.07.06a.12.12 0 01-.07 0c-.03 0-.05-.02-.09-.06L512 569.93l-287.7 287.7c-.04.04-.06.05-.09.06a.12.12 0 01-.07 0c-.02 0-.04-.02-.08-.06l-57.69-57.7c-.04-.03-.05-.05-.06-.07a.12.12 0 010-.07c0-.03.02-.05.06-.09L454.07 512l-287.7-287.7c-.04-.04-.05-.06-.06-.09a.12.12 0 010-.07c0-.02.02-.04.06-.08l57.7-57.69c.03-.04.05-.05.07-.06a.12.12 0 01.07 0c.03 0 .05.02.09.06L512 454.07l287.7-287.7c.04-.04.06-.05.09-.06a.12.12 0 01.07 0z"
/>
</svg>
</span>
</button>
<div
class="ant-tour-header"
>
<div
class="ant-tour-title"
>
Show in Center
</div>
</div>
<div
class="ant-tour-description"
>
Here is the content of Tour.
</div>
<div
class="ant-tour-footer"
>
<div
class="ant-tour-buttons"
>
<button
class="ant-btn ant-btn-primary ant-btn-solid ant-btn-sm ant-tour-next-btn"
type="button"
>
<span>
Finish
</span>
</button>
</div>
</div>
</div>
</div>
</div>
</div>
<div>
<div
class="ant-tour-mask"
style="position: fixed; left: 0px; right: 0px; top: 0px; bottom: 0px; z-index: 1001; pointer-events: none;"
>
<svg
style="width: 100%; height: 100%;"
>
<defs>
<mask
id="ant-tour-mask-test-id"
>
<rect
fill="white"
height="100vh"
width="100vw"
x="0"
y="0"
/>
<rect
class="ant-tour-placeholder-animated"
fill="black"
height="200"
rx="2"
width="250"
x="90"
y="190"
/>
</mask>
</defs>
<rect
fill="rgba(0,0,0,0.5)"
height="100%"
mask="url(#ant-tour-mask-test-id)"
width="100%"
x="0"
y="0"
/>
<rect
fill="transparent"
height="190"
pointer-events="auto"
width="100%"
x="0"
y="0"
/>
<rect
fill="transparent"
height="100%"
pointer-events="auto"
width="90"
x="0"
y="0"
/>
<rect
fill="transparent"
height="calc(100vh - 390px)"
pointer-events="auto"
width="100%"
x="0"
y="390"
/>
<rect
fill="transparent"
height="100%"
pointer-events="auto"
width="calc(100vw - 340px)"
x="340"
y="0"
/>
</svg>
</div>
</div>
<div>
<div
class="ant-tour-target-placeholder"
style="left: 90px; top: 190px; width: 250px; height: 200px; position: fixed; pointer-events: none;"
/>
</div>
</body>
`;
exports[`Tour single 1`] = `
<body>
<div>

View File

@ -1,5 +1,6 @@
/* eslint-disable react/no-unstable-nested-components */
import React, { useEffect, useRef } from 'react';
import { spyElementPrototypes } from 'rc-util/lib/test/domHook';
import Tour from '..';
import mountTest from '../../../tests/shared/mountTest';
@ -7,6 +8,24 @@ import rtlTest from '../../../tests/shared/rtlTest';
import { fireEvent, render, screen } from '../../../tests/utils';
import type { TourProps } from '../interface';
const mockBtnRect = (
rect: { x: number; y: number; width: number; height: number },
scrollIntoViewCb?: () => void,
) => {
spyElementPrototypes(HTMLButtonElement, {
getBoundingClientRect: {
get(): any {
return () => ({ ...rect, left: rect.x, top: rect.y });
},
},
scrollIntoView: {
get(): any {
scrollIntoViewCb?.();
return (val: boolean | ScrollIntoViewOptions) => val;
},
},
});
};
describe('Tour', () => {
mountTest(Tour);
rtlTest(Tour);
@ -590,6 +609,86 @@ describe('Tour', () => {
expect(onClose).toHaveBeenLastCalledWith(1);
});
it('should support gap.radius', () => {
const App: React.FC<{ gap: TourProps['gap'] }> = ({ gap }) => {
const ref = useRef<HTMLButtonElement>(null);
const [show, setShow] = React.useState<boolean>();
const steps: TourProps['steps'] = [
{
title: 'Show in Center',
description: 'Here is the content of Tour.',
target: () => ref.current!,
},
];
return (
<>
<button type="button" onClick={() => setShow(true)} ref={ref}>
Show
</button>
<Tour open={show} steps={steps} gap={gap} />
</>
);
};
const { rerender, baseElement } = render(<App gap={{ radius: 4 }} />);
fireEvent.click(screen.getByRole('button', { name: 'Show' }));
expect(baseElement.querySelector('.ant-tour-placeholder-animated')).toBeTruthy();
expect(baseElement.querySelector('.ant-tour-placeholder-animated')).toHaveAttribute('rx', '4');
rerender(<App gap={{ radius: 0 }} />);
fireEvent.click(screen.getByRole('button', { name: 'Show' }));
expect(baseElement.querySelector('.ant-tour-placeholder-animated')).toBeTruthy();
expect(baseElement.querySelector('.ant-tour-placeholder-animated')).toHaveAttribute('rx', '0');
});
it('should support gap.offset', () => {
const gap = { offset: 10 };
const pos = { x: 100, y: 200, width: 230, height: 180 };
mockBtnRect(pos);
const App: React.FC = () => {
const ref = useRef<HTMLButtonElement>(null);
const [show, setShow] = React.useState<boolean>();
const steps: TourProps['steps'] = [
{
title: 'Show in Center',
description: 'Here is the content of Tour.',
target: () => ref.current!,
},
];
return (
<>
<button type="button" onClick={() => setShow(true)} ref={ref}>
Show
</button>
<Tour steps={steps} gap={gap} open={show} />
</>
);
};
const { baseElement } = render(<App />);
const targetBtn = screen.getByRole('button', { name: 'Show' });
fireEvent.click(targetBtn);
expect(baseElement.querySelector('.ant-tour-placeholder-animated')).toHaveAttribute(
'width',
String(pos.width + gap.offset * 2),
);
expect(baseElement.querySelector('.ant-tour-placeholder-animated')).toHaveAttribute(
'height',
String(pos.height + gap.offset * 2),
);
expect(baseElement.querySelector('.ant-tour-placeholder-animated')).toHaveAttribute(
'x',
String(pos.x - gap.offset),
);
expect(baseElement.querySelector('.ant-tour-placeholder-animated')).toHaveAttribute(
'y',
String(pos.y - gap.offset),
);
expect(baseElement).toMatchSnapshot();
});
// This test is for PurePanel which means safe to remove.
describe('PurePanel', () => {
const PurePanel = Tour._InternalPanelDoNotUseOrYouWillBeFired;

View File

@ -0,0 +1,11 @@
## zh-CN
使用 `gap` 参数来控制高亮区域的边距和圆角。
- `5.9.0` 之前不支持单独设置两个方向上的边距和数组类型的 `offset` 参数。
## en-US
Using `gap` to control the radius of highlight area and the offset between highlight area and the element.
- Setting offset in two directions individually and `offset` with array type is not supported until `5.9.0`.

View File

@ -0,0 +1,100 @@
import React, { useRef, useState } from 'react';
import { Button, Col, Row, Slider, Space, Tour, Typography } from 'antd';
import type { TourProps } from 'antd';
const { Text } = Typography;
const App: React.FC = () => {
const tourNodeRef = useRef(null);
const [radius, setRadius] = useState(8);
const [offsetX, setOffsetX] = useState(2);
const [offsetY, setOffsetY] = useState(2);
const [offset, setOffset] = useState(2);
const [open, setOpen] = useState(false);
const [offsetDirection, setOffsetDirection] = useState<'both' | 'individual'>('individual');
const steps: TourProps['steps'] = [
{
title: 'Upload File',
description: 'Put your files here.',
cover: (
<img
alt="tour.png"
src="https://user-images.githubusercontent.com/5378891/197385811-55df8480-7ff4-44bd-9d43-a7dade598d70.png"
/>
),
target: () => tourNodeRef.current,
},
];
const offsetGap =
offsetDirection === 'both'
? { offset }
: {
offset: [offsetX, offsetY] as [number, number],
};
return (
<div ref={tourNodeRef}>
<Button type="primary" onClick={() => setOpen(true)}>
Begin Tour
</Button>
<Space style={{ display: 'flex', marginTop: 12 }} direction="vertical">
<Row>
<Col span={6}>
<Text>Radius:</Text>
</Col>
<Col span={12}>
<Slider value={radius} onChange={(val) => val && setRadius(val)} />
</Col>
</Row>
<Row>
<Col span={6}>
<Text> offset:</Text>
</Col>
<Col span={12}>
<Slider
value={offset}
max={50}
onChange={(val) => val && setOffset(val)}
onFocus={() => setOffsetDirection('both')}
/>
</Col>
</Row>
<Row>
<Col span={6}>
<Text>Horizontal offset:</Text>
</Col>
<Col span={12}>
<Slider
value={offsetX}
max={50}
onChange={(val) => val && setOffsetX(val)}
onFocus={() => setOffsetDirection('individual')}
/>
</Col>
</Row>
<Row>
<Col span={6}>
<Text>Vertical offset:</Text>
</Col>
<Col span={12}>
<Slider
value={offsetY}
max={50}
onChange={(val) => val && setOffsetY(val)}
onFocus={() => setOffsetDirection('individual')}
/>
</Col>
</Row>
</Space>
<Tour
open={open}
onClose={() => setOpen(false)}
steps={steps}
gap={{ ...offsetGap, radius }}
/>
</div>
);
};
export default App;

View File

@ -22,6 +22,7 @@ Use when you want to guide users through a product.
<code src="./demo/placement.tsx">Placement</code>
<code src="./demo/mask.tsx">Custom mask style</code>
<code src="./demo/indicator.tsx">Custom indicator</code>
<code src="./demo/gap.tsx">Custom highlighted area style</code>
<code src="./demo/render-panel.tsx" debug>\_InternalPanelDoNotUseOrYouWillBeFired</code>
## API
@ -35,6 +36,7 @@ Common props ref[Common props](/docs/react/common-props)
| arrow | Whether to show the arrow, including the configuration whether to point to the center of the element | `boolean`\|`{ pointAtCenter: boolean}` | `true` | |
| closeIcon | Customize close icon | `React.ReactNode` | `true` | 5.9.0 |
| disabledInteraction | Disable interaction on highlighted area. | `boolean` | `false` | 5.13.0 |
| gap | Control the radius of the highlighted area and the offset between highlighted area and the element. | `{ offset?: number \| [number, number]; radius?: number }` | `{ offset?: 6 ; radius?: 2 }` | 5.0.0 (array type `offset`: 5.9.0) |
| placement | Position of the guide card relative to the target element | `center` `left` `leftTop` `leftBottom` `right` `rightTop` `rightBottom` `top` `topLeft` `topRight` `bottom` `bottomLeft` `bottomRight` | `bottom` | |
| onClose | Callback function on shutdown | `Function` | - | |
| mask | Whether to enable masking, change mask style and fill color by pass custom props | `boolean \| { style?: React.CSSProperties; color?: string; }` | `true` | |

View File

@ -23,6 +23,7 @@ tag: 5.0.0
<code src="./demo/placement.tsx">位置</code>
<code src="./demo/mask.tsx">自定义遮罩样式</code>
<code src="./demo/indicator.tsx">自定义指示器</code>
<code src="./demo/gap.tsx">自定义高亮区域的样式</code>
<code src="./demo/render-panel.tsx" debug>\_InternalPanelDoNotUseOrYouWillBeFired</code>
## API
@ -36,6 +37,7 @@ tag: 5.0.0
| arrow | 是否显示箭头,包含是否指向元素中心的配置 | `boolean` \| `{ pointAtCenter: boolean}` | `true` | |
| closeIcon | 自定义关闭按钮 | `React.ReactNode` | `true` | 5.9.0 |
| disabledInteraction | 禁用高亮区域交互 | `boolean` | `false` | 5.13.0 |
| gap | 控制高亮区域的圆角边框和显示间距 | `{ offset?: number \| [number, number]; radius?: number }` | `{ offset?: 6 ; radius?: 2 }` | 5.0.0 (数组类型的 `offset`: 5.9.0 ) |
| placement | 引导卡片相对于目标元素的位置 | `center` `left` `leftTop` `leftBottom` `right` `rightTop` `rightBottom` `top` `topLeft` `topRight` `bottom` `bottomLeft` `bottomRight` | `bottom` | |
| onClose | 关闭引导时的回调函数 | `Function` | - | |
| onFinish | 引导完成时的回调 | `Function` | - | |

View File

@ -11861,7 +11861,7 @@ exports[`renders components/transfer/demo/tree-transfer.tsx extend context corre
>
<div
aria-grabbed="false"
class="ant-tree-treenode ant-tree-treenode-switcher-open"
class="ant-tree-treenode ant-tree-treenode-switcher-close"
draggable="false"
>
<span
@ -11941,7 +11941,7 @@ exports[`renders components/transfer/demo/tree-transfer.tsx extend context corre
</div>
<div
aria-grabbed="false"
class="ant-tree-treenode ant-tree-treenode-switcher-open"
class="ant-tree-treenode ant-tree-treenode-switcher-close"
draggable="false"
>
<span
@ -11975,7 +11975,7 @@ exports[`renders components/transfer/demo/tree-transfer.tsx extend context corre
</div>
<div
aria-grabbed="false"
class="ant-tree-treenode ant-tree-treenode-switcher-open ant-tree-treenode-leaf-last"
class="ant-tree-treenode ant-tree-treenode-switcher-close ant-tree-treenode-leaf-last"
draggable="false"
>
<span
@ -12009,7 +12009,7 @@ exports[`renders components/transfer/demo/tree-transfer.tsx extend context corre
</div>
<div
aria-grabbed="false"
class="ant-tree-treenode ant-tree-treenode-switcher-open"
class="ant-tree-treenode ant-tree-treenode-switcher-close"
draggable="false"
>
<span
@ -12039,7 +12039,7 @@ exports[`renders components/transfer/demo/tree-transfer.tsx extend context corre
</div>
<div
aria-grabbed="false"
class="ant-tree-treenode ant-tree-treenode-switcher-open"
class="ant-tree-treenode ant-tree-treenode-switcher-close"
draggable="false"
>
<span
@ -12069,7 +12069,7 @@ exports[`renders components/transfer/demo/tree-transfer.tsx extend context corre
</div>
<div
aria-grabbed="false"
class="ant-tree-treenode ant-tree-treenode-switcher-open ant-tree-treenode-leaf-last"
class="ant-tree-treenode ant-tree-treenode-switcher-close ant-tree-treenode-leaf-last"
draggable="false"
>
<span

View File

@ -7907,7 +7907,7 @@ exports[`renders components/transfer/demo/tree-transfer.tsx correctly 1`] = `
>
<div
aria-grabbed="false"
class="ant-tree-treenode ant-tree-treenode-switcher-open"
class="ant-tree-treenode ant-tree-treenode-switcher-close"
draggable="false"
>
<span
@ -7987,7 +7987,7 @@ exports[`renders components/transfer/demo/tree-transfer.tsx correctly 1`] = `
</div>
<div
aria-grabbed="false"
class="ant-tree-treenode ant-tree-treenode-switcher-open"
class="ant-tree-treenode ant-tree-treenode-switcher-close"
draggable="false"
>
<span
@ -8021,7 +8021,7 @@ exports[`renders components/transfer/demo/tree-transfer.tsx correctly 1`] = `
</div>
<div
aria-grabbed="false"
class="ant-tree-treenode ant-tree-treenode-switcher-open ant-tree-treenode-leaf-last"
class="ant-tree-treenode ant-tree-treenode-switcher-close ant-tree-treenode-leaf-last"
draggable="false"
>
<span
@ -8055,7 +8055,7 @@ exports[`renders components/transfer/demo/tree-transfer.tsx correctly 1`] = `
</div>
<div
aria-grabbed="false"
class="ant-tree-treenode ant-tree-treenode-switcher-open"
class="ant-tree-treenode ant-tree-treenode-switcher-close"
draggable="false"
>
<span
@ -8085,7 +8085,7 @@ exports[`renders components/transfer/demo/tree-transfer.tsx correctly 1`] = `
</div>
<div
aria-grabbed="false"
class="ant-tree-treenode ant-tree-treenode-switcher-open"
class="ant-tree-treenode ant-tree-treenode-switcher-close"
draggable="false"
>
<span
@ -8115,7 +8115,7 @@ exports[`renders components/transfer/demo/tree-transfer.tsx correctly 1`] = `
</div>
<div
aria-grabbed="false"
class="ant-tree-treenode ant-tree-treenode-switcher-open ant-tree-treenode-leaf-last"
class="ant-tree-treenode ant-tree-treenode-switcher-close ant-tree-treenode-leaf-last"
draggable="false"
>
<span

View File

@ -393,7 +393,7 @@ exports[`renders components/tree-select/demo/basic.tsx extend context correctly
</div>
<div
aria-grabbed="false"
class="ant-select-tree-treenode ant-select-tree-treenode-switcher-open"
class="ant-select-tree-treenode ant-select-tree-treenode-switcher-close"
draggable="false"
>
<span
@ -423,7 +423,7 @@ exports[`renders components/tree-select/demo/basic.tsx extend context correctly
</div>
<div
aria-grabbed="false"
class="ant-select-tree-treenode ant-select-tree-treenode-switcher-open"
class="ant-select-tree-treenode ant-select-tree-treenode-switcher-close"
draggable="false"
>
<span
@ -453,7 +453,7 @@ exports[`renders components/tree-select/demo/basic.tsx extend context correctly
</div>
<div
aria-grabbed="false"
class="ant-select-tree-treenode ant-select-tree-treenode-switcher-open"
class="ant-select-tree-treenode ant-select-tree-treenode-switcher-close"
draggable="false"
>
<span
@ -483,7 +483,7 @@ exports[`renders components/tree-select/demo/basic.tsx extend context correctly
</div>
<div
aria-grabbed="false"
class="ant-select-tree-treenode ant-select-tree-treenode-switcher-open"
class="ant-select-tree-treenode ant-select-tree-treenode-switcher-close"
draggable="false"
>
<span
@ -513,7 +513,7 @@ exports[`renders components/tree-select/demo/basic.tsx extend context correctly
</div>
<div
aria-grabbed="false"
class="ant-select-tree-treenode ant-select-tree-treenode-switcher-open"
class="ant-select-tree-treenode ant-select-tree-treenode-switcher-close"
draggable="false"
>
<span
@ -543,7 +543,7 @@ exports[`renders components/tree-select/demo/basic.tsx extend context correctly
</div>
<div
aria-grabbed="false"
class="ant-select-tree-treenode ant-select-tree-treenode-switcher-open ant-select-tree-treenode-leaf-last"
class="ant-select-tree-treenode ant-select-tree-treenode-switcher-close ant-select-tree-treenode-leaf-last"
draggable="false"
>
<span
@ -620,7 +620,7 @@ exports[`renders components/tree-select/demo/basic.tsx extend context correctly
</div>
<div
aria-grabbed="false"
class="ant-select-tree-treenode ant-select-tree-treenode-switcher-open ant-select-tree-treenode-leaf-last"
class="ant-select-tree-treenode ant-select-tree-treenode-switcher-close ant-select-tree-treenode-leaf-last"
draggable="false"
>
<span
@ -1145,7 +1145,7 @@ exports[`renders components/tree-select/demo/multiple.tsx extend context correct
</div>
<div
aria-grabbed="false"
class="ant-select-tree-treenode ant-select-tree-treenode-switcher-open"
class="ant-select-tree-treenode ant-select-tree-treenode-switcher-close"
draggable="false"
>
<span
@ -1175,7 +1175,7 @@ exports[`renders components/tree-select/demo/multiple.tsx extend context correct
</div>
<div
aria-grabbed="false"
class="ant-select-tree-treenode ant-select-tree-treenode-switcher-open ant-select-tree-treenode-leaf-last"
class="ant-select-tree-treenode ant-select-tree-treenode-switcher-close ant-select-tree-treenode-leaf-last"
draggable="false"
>
<span
@ -1252,7 +1252,7 @@ exports[`renders components/tree-select/demo/multiple.tsx extend context correct
</div>
<div
aria-grabbed="false"
class="ant-select-tree-treenode ant-select-tree-treenode-switcher-open ant-select-tree-treenode-leaf-last"
class="ant-select-tree-treenode ant-select-tree-treenode-switcher-close ant-select-tree-treenode-leaf-last"
draggable="false"
>
<span
@ -1573,7 +1573,7 @@ Array [
</div>
<div
aria-grabbed="false"
class="ant-select-tree-treenode ant-select-tree-treenode-switcher-open"
class="ant-select-tree-treenode ant-select-tree-treenode-switcher-close"
draggable="false"
>
<span
@ -1603,7 +1603,7 @@ Array [
</div>
<div
aria-grabbed="false"
class="ant-select-tree-treenode ant-select-tree-treenode-switcher-open ant-select-tree-treenode-leaf-last"
class="ant-select-tree-treenode ant-select-tree-treenode-switcher-close ant-select-tree-treenode-leaf-last"
draggable="false"
>
<span
@ -1680,7 +1680,7 @@ Array [
</div>
<div
aria-grabbed="false"
class="ant-select-tree-treenode ant-select-tree-treenode-switcher-open ant-select-tree-treenode-leaf-last"
class="ant-select-tree-treenode ant-select-tree-treenode-switcher-close ant-select-tree-treenode-leaf-last"
draggable="false"
>
<span
@ -2388,7 +2388,7 @@ exports[`renders components/tree-select/demo/suffix.tsx extend context correctly
</div>
<div
aria-grabbed="false"
class="ant-select-tree-treenode ant-select-tree-treenode-switcher-open"
class="ant-select-tree-treenode ant-select-tree-treenode-switcher-close"
draggable="false"
>
<span
@ -2418,7 +2418,7 @@ exports[`renders components/tree-select/demo/suffix.tsx extend context correctly
</div>
<div
aria-grabbed="false"
class="ant-select-tree-treenode ant-select-tree-treenode-switcher-open ant-select-tree-treenode-leaf-last"
class="ant-select-tree-treenode ant-select-tree-treenode-switcher-close ant-select-tree-treenode-leaf-last"
draggable="false"
>
<span
@ -2495,7 +2495,7 @@ exports[`renders components/tree-select/demo/suffix.tsx extend context correctly
</div>
<div
aria-grabbed="false"
class="ant-select-tree-treenode ant-select-tree-treenode-switcher-open ant-select-tree-treenode-leaf-last"
class="ant-select-tree-treenode ant-select-tree-treenode-switcher-close ant-select-tree-treenode-leaf-last"
draggable="false"
>
<span
@ -2689,7 +2689,7 @@ exports[`renders components/tree-select/demo/treeData.tsx extend context correct
</div>
<div
aria-grabbed="false"
class="ant-select-tree-treenode ant-select-tree-treenode-switcher-open"
class="ant-select-tree-treenode ant-select-tree-treenode-switcher-close"
draggable="false"
>
<span
@ -2716,7 +2716,7 @@ exports[`renders components/tree-select/demo/treeData.tsx extend context correct
</div>
<div
aria-grabbed="false"
class="ant-select-tree-treenode ant-select-tree-treenode-switcher-open ant-select-tree-treenode-leaf-last"
class="ant-select-tree-treenode ant-select-tree-treenode-switcher-close ant-select-tree-treenode-leaf-last"
draggable="false"
>
<span
@ -2743,7 +2743,7 @@ exports[`renders components/tree-select/demo/treeData.tsx extend context correct
</div>
<div
aria-grabbed="false"
class="ant-select-tree-treenode ant-select-tree-treenode-switcher-open ant-select-tree-treenode-leaf-last"
class="ant-select-tree-treenode ant-select-tree-treenode-switcher-close ant-select-tree-treenode-leaf-last"
draggable="false"
>
<span

View File

@ -951,7 +951,7 @@ exports[`renders components/tree/demo/block-node.tsx extend context correctly 1`
</div>
<div
aria-grabbed="false"
class="ant-tree-treenode ant-tree-treenode-disabled ant-tree-treenode-switcher-open"
class="ant-tree-treenode ant-tree-treenode-disabled ant-tree-treenode-switcher-close"
draggable="false"
>
<span
@ -985,7 +985,7 @@ exports[`renders components/tree/demo/block-node.tsx extend context correctly 1`
</div>
<div
aria-grabbed="false"
class="ant-tree-treenode ant-tree-treenode-switcher-open ant-tree-treenode-selected ant-tree-treenode-leaf-last"
class="ant-tree-treenode ant-tree-treenode-switcher-close ant-tree-treenode-selected ant-tree-treenode-leaf-last"
draggable="false"
>
<span
@ -1132,7 +1132,7 @@ exports[`renders components/tree/demo/customized-icon.tsx extend context correct
</div>
<div
aria-grabbed="false"
class="ant-tree-treenode ant-tree-treenode-switcher-open ant-tree-treenode-selected"
class="ant-tree-treenode ant-tree-treenode-switcher-close ant-tree-treenode-selected"
draggable="false"
>
<span
@ -1182,7 +1182,7 @@ exports[`renders components/tree/demo/customized-icon.tsx extend context correct
</div>
<div
aria-grabbed="false"
class="ant-tree-treenode ant-tree-treenode-switcher-open ant-tree-treenode-leaf-last"
class="ant-tree-treenode ant-tree-treenode-switcher-close ant-tree-treenode-leaf-last"
draggable="false"
>
<span

View File

@ -947,7 +947,7 @@ exports[`renders components/tree/demo/block-node.tsx correctly 1`] = `
</div>
<div
aria-grabbed="false"
class="ant-tree-treenode ant-tree-treenode-disabled ant-tree-treenode-switcher-open"
class="ant-tree-treenode ant-tree-treenode-disabled ant-tree-treenode-switcher-close"
draggable="false"
>
<span
@ -981,7 +981,7 @@ exports[`renders components/tree/demo/block-node.tsx correctly 1`] = `
</div>
<div
aria-grabbed="false"
class="ant-tree-treenode ant-tree-treenode-switcher-open ant-tree-treenode-selected ant-tree-treenode-leaf-last"
class="ant-tree-treenode ant-tree-treenode-switcher-close ant-tree-treenode-selected ant-tree-treenode-leaf-last"
draggable="false"
>
<span
@ -1126,7 +1126,7 @@ exports[`renders components/tree/demo/customized-icon.tsx correctly 1`] = `
</div>
<div
aria-grabbed="false"
class="ant-tree-treenode ant-tree-treenode-switcher-open ant-tree-treenode-selected"
class="ant-tree-treenode ant-tree-treenode-switcher-close ant-tree-treenode-selected"
draggable="false"
>
<span
@ -1176,7 +1176,7 @@ exports[`renders components/tree/demo/customized-icon.tsx correctly 1`] = `
</div>
<div
aria-grabbed="false"
class="ant-tree-treenode ant-tree-treenode-switcher-open ant-tree-treenode-leaf-last"
class="ant-tree-treenode ant-tree-treenode-switcher-close ant-tree-treenode-leaf-last"
draggable="false"
>
<span

View File

@ -698,7 +698,7 @@ exports[`Tree switcherIcon in Tree could be string 1`] = `
</div>
<div
aria-grabbed="false"
class="ant-tree-treenode ant-tree-treenode-switcher-open"
class="ant-tree-treenode ant-tree-treenode-switcher-close"
draggable="false"
>
<span
@ -725,7 +725,7 @@ exports[`Tree switcherIcon in Tree could be string 1`] = `
</div>
<div
aria-grabbed="false"
class="ant-tree-treenode ant-tree-treenode-switcher-open ant-tree-treenode-leaf-last"
class="ant-tree-treenode ant-tree-treenode-switcher-close ant-tree-treenode-leaf-last"
draggable="false"
>
<span
@ -822,7 +822,7 @@ exports[`Tree switcherIcon should be loading icon when loadData 1`] = `
</div>
<div
aria-grabbed="false"
class="ant-tree-treenode ant-tree-treenode-switcher-open ant-tree-treenode-loading"
class="ant-tree-treenode ant-tree-treenode-switcher-close"
draggable="false"
>
<span
@ -834,35 +834,14 @@ exports[`Tree switcherIcon should be loading icon when loadData 1`] = `
/>
</span>
<span
class="ant-tree-switcher ant-tree-switcher_open"
class="ant-tree-switcher ant-tree-switcher_close"
>
<span
aria-label="loading"
class="anticon anticon-loading anticon-spin ant-tree-switcher-loading-icon"
role="img"
>
<svg
aria-hidden="true"
data-icon="loading"
fill="currentColor"
focusable="false"
height="1em"
viewBox="0 0 1024 1024"
width="1em"
>
<path
d="M988 548c-19.9 0-36-16.1-36-36 0-59.4-11.6-117-34.6-171.3a440.45 440.45 0 00-94.3-139.9 437.71 437.71 0 00-139.9-94.3C629 83.6 571.4 72 512 72c-19.9 0-36-16.1-36-36s16.1-36 36-36c69.1 0 136.2 13.5 199.3 40.3C772.3 66 827 103 874 150c47 47 83.9 101.8 109.7 162.7 26.7 63.1 40.2 130.2 40.2 199.3.1 19.9-16 36-35.9 36z"
/>
</svg>
</span>
switcherIcon
</span>
<span
class="ant-tree-node-content-wrapper ant-tree-node-content-wrapper-open"
class="ant-tree-node-content-wrapper ant-tree-node-content-wrapper-close"
title="node1"
>
<span
class="ant-tree-iconEle ant-tree-icon__open ant-tree-icon_loading"
/>
<span
class="ant-tree-title"
>
@ -872,7 +851,7 @@ exports[`Tree switcherIcon should be loading icon when loadData 1`] = `
</div>
<div
aria-grabbed="false"
class="ant-tree-treenode ant-tree-treenode-switcher-open ant-tree-treenode-loading ant-tree-treenode-leaf-last"
class="ant-tree-treenode ant-tree-treenode-switcher-close ant-tree-treenode-leaf-last"
draggable="false"
>
<span
@ -884,35 +863,14 @@ exports[`Tree switcherIcon should be loading icon when loadData 1`] = `
/>
</span>
<span
class="ant-tree-switcher ant-tree-switcher_open"
class="ant-tree-switcher ant-tree-switcher_close"
>
<span
aria-label="loading"
class="anticon anticon-loading anticon-spin ant-tree-switcher-loading-icon"
role="img"
>
<svg
aria-hidden="true"
data-icon="loading"
fill="currentColor"
focusable="false"
height="1em"
viewBox="0 0 1024 1024"
width="1em"
>
<path
d="M988 548c-19.9 0-36-16.1-36-36 0-59.4-11.6-117-34.6-171.3a440.45 440.45 0 00-94.3-139.9 437.71 437.71 0 00-139.9-94.3C629 83.6 571.4 72 512 72c-19.9 0-36-16.1-36-36s16.1-36 36-36c69.1 0 136.2 13.5 199.3 40.3C772.3 66 827 103 874 150c47 47 83.9 101.8 109.7 162.7 26.7 63.1 40.2 130.2 40.2 199.3.1 19.9-16 36-35.9 36z"
/>
</svg>
</span>
switcherIcon
</span>
<span
class="ant-tree-node-content-wrapper ant-tree-node-content-wrapper-open"
class="ant-tree-node-content-wrapper ant-tree-node-content-wrapper-close"
title="node2"
>
<span
class="ant-tree-iconEle ant-tree-icon__open ant-tree-icon_loading"
/>
<span
class="ant-tree-title"
>

View File

@ -125,7 +125,7 @@ describe('Tree', () => {
<Tree
switcherIcon="switcherIcon"
loadData={onLoadData}
defaultExpandAll
defaultExpandedKeys={['0-0-2', '0-0-3']}
switcherLoadingIcon={<div>loading...</div>}
>
<TreeNode icon="icon">

View File

@ -633,4 +633,15 @@ describe('Typography.Ellipsis', () => {
rerender(renderDemo(true));
expect(container.querySelector('.ant-typography-collapse')).toBeTruthy();
});
it('no dead loop', () => {
const tooltipObj: any = {};
tooltipObj.loop = tooltipObj;
render(
<Base ellipsis={{ tooltip: tooltipObj }} component="p">
{fullStr}
</Base>,
);
});
});

View File

@ -17,6 +17,6 @@ const useTooltipProps = (
return { title: editConfigText ?? children, ...tooltip };
}
return { title: tooltip };
}, [typeof tooltip === 'object' ? JSON.stringify(tooltip) : tooltip, editConfigText, children]);
}, [tooltip, editConfigText, children]);
export default useTooltipProps;

View File

@ -58,7 +58,7 @@ However, after enabling CSS variables, the component styles of the same antd ver
</ConfigProvider>
```
By the way, we strongly recommend using `extractStyle` to extract static styles, which will bring a certain amount of performance improvement to the application.
By the way, we strongly recommend using [extractStyle](/docs/react/server-side-rendering) to extract static styles, which will bring a certain amount of performance improvement to the application.
### Customize Theme

View File

@ -58,7 +58,7 @@ hash 是 Ant Design 5.0 以来的特性之一,其功能是为每一份主题
</ConfigProvider>
```
同时我们非常推荐使用 `extractStyle` 来抽取静态样式,这样会为应用性能带来一定量的提升。
同时我们非常推荐使用 [extractStyle](/docs/react/server-side-rendering-cn) 来抽取静态样式,这样会为应用性能带来一定量的提升。
### 修改主题

View File

@ -221,7 +221,7 @@ const App: React.FC = () => {
return (
<>
<ColorPicker showText value={primary} onChangeComplete={(color) => setPrimary(color.toHexString())} />
<ColorPicker showText value={primary} onChange={(color) => setPrimary(color.toHexString())} />
<Divider />
<ConfigProvider
theme={{

View File

@ -221,7 +221,7 @@ const App: React.FC = () => {
return (
<>
<ColorPicker showText value={primary} onChangeComplete={(color) => setPrimary(color.toHexString())} />
<ColorPicker showText value={primary} onChange={(color) => setPrimary(color.toHexString())} />
<Divider />
<ConfigProvider
theme={{

View File

@ -0,0 +1,73 @@
---
group:
title: Basic Usage
order: 7
title: Usage with Refine
tag: New
---
[Refine](https://github.com/refinedev/refine) is a React meta-framework designed for CRUD-heavy web applications. Its core hooks and components streamline development by offering solutions for authentication, access control, routing, networking, state management, and i18n.
It supports Ant Design with an integration package that includes ready-to-use components and hooks to connect Refine to Ant Design.
This article will guide you through bootstrapping a fully-functional CRUD application example using Refine and Ant Design.
## Install and Initialization
Refine integrates easily with platforms like Vite, Next.js, Remix, React Native, and Electron through a simple routing interface without additional setup.
In this guide, we'll use Vite and the `refine-antd` preset from the `create refine-app` CLI for a quick start to create a new Refine project with Ant Design using predefined options.
Before all start, you may need install [yarn](https://github.com/yarnpkg/yarn/) or [pnpm](https://pnpm.io/).
<InstallDependencies npm='$ npm create refine-app@latest -- --preset refine-antd' yarn='$ yarn create refine-app@latest -- --preset refine-antd' pnpm='$ pnpm create refine-app@latest -- --preset refine-antd'></InstallDependencies>
Using the `refine-antd` preset eliminates the need for extra dependencies and add example pages built with Ant Design for a quick start.
After the initialization is complete, we enter the project and start.
```bash
$ cd antd-demo
$ npm run dev
```
Once initialization is complete, all Ant Design configurations are done automatically, allowing you to start using Ant Design components in your Refine app.
Open the browser at http://localhost:5173/ and you will see example CRUD app with Ant Design components.
![Refine Ant Design example](https://refine.ams3.cdn.digitaloceanspaces.com/example-readmes/antd-list-example.png)
## Inspection the code
Let take a look at Ant Design usage in the one of the example component generated by the CLI command.
```tsx
import { Create, useForm } from '@refinedev/antd';
import { Form, Input } from 'antd';
export const CategoryCreate = () => {
const { formProps, saveButtonProps } = useForm();
return (
<Create saveButtonProps={saveButtonProps}>
<Form {...formProps} layout="vertical">
<Form.Item label={'Title'} name={['title']} rules={[{ required: true }]}>
<Input />
</Form.Item>
</Form>
</Create>
);
};
```
While Refine's integration offers a set of components and hooks, it is not a replacement for the Ant Design package, you will be able to use all the features of Ant Design in the same way you would use it in a regular React application.
Refine's integration only provides components and hooks for an easier usage of Ant Design components in combination with Refine's features and functionalities.
## How to Add Ant Design to an Existing Refine Project
You can follow the [Refine Ant Design official guide](https://refine.dev/docs/ui-integrations/ant-design/introduction/) to add Ant Design to an existing Refine project.
To bootstrap a Refine app with various integration options like Next.js and Remix, use `npm create refine-app@latest` and select Ant Design as the UI framework from the CLI.
For more detailed tutorials and guides with Ant Design, visit the [Refine documentation](https://refine.dev/tutorial/ui-libraries/intro/ant-design/react-router/).

View File

@ -0,0 +1,73 @@
---
group:
title: 如何使用
order: 7
title: 使用 Refine
tag: New
---
[Refine](https://github.com/refinedev/refine) 是一个为 CRUD 密集型 web 应用设计的 React 元框架。它的核心钩子和组件通过提供认证、访问控制、路由、网络、状态管理和国际化解决方案来简化开发。
它通过一个集成包支持 Ant Design其中包含即用型组件和钩子将 Refine 与 Ant Design 连接起来。
本文将指导您使用 Refine 和 Ant Design 引导一个功能齐全的 CRUD 应用示例。
## 安装和初始化
Refine 通过一个简单的路由接口与 Vite、Next.js、Remix、React Native 和 Electron 等平台轻松集成,无需额外设置。
在本指南中,我们将使用 Vite 和 `create refine-app` CLI 的 `refine-antd` 预设,通过预定义选项快速创建一个带有 Ant Design 的新 Refine 项目。
在开始之前,您可能需要安装 [yarn](https://github.com/yarnpkg/yarn/) 或 [pnpm](https://pnpm.io/)。
<InstallDependencies npm='$ npm create refine-app@latest -- --preset refine-antd' yarn='$ yarn create refine-app@latest -- --preset refine-antd' pnpm='$ pnpm create refine-app@latest -- --preset refine-antd'></InstallDependencies>
使用 `refine-antd` 预设消除了对额外依赖的需求,并添加了使用 Ant Design 构建的示例页面以快速开始。
初始化完成后,我们进入项目并启动。
```bash
$ cd antd-demo
$ npm run dev
```
初始化完成后,所有 Ant Design 配置都会自动完成,允许您在 Refine 应用中开始使用 Ant Design 组件。
在浏览器中打开 http://localhost:5173/,您将看到带有 Ant Design 组件的示例 CRUD 应用。
![Refine Ant Design 示例](https://refine.ams3.cdn.digitaloceanspaces.com/example-readmes/antd-list-example.png)
## 查看代码
让我们看看 CLI 命令生成的示例组件中 Ant Design 的使用。
```tsx
import { Create, useForm } from '@refinedev/antd';
import { Form, Input } from 'antd';
export const CategoryCreate = () => {
const { formProps, saveButtonProps } = useForm();
return (
<Create saveButtonProps={saveButtonProps}>
<Form {...formProps} layout="vertical">
<Form.Item label={'Title'} name={['title']} rules={[{ required: true }]}>
<Input />
</Form.Item>
</Form>
</Create>
);
};
```
虽然 Refine 的集成提供了一组组件和钩子,但它不是 Ant Design 包的替代品,您可以像在常规 React 应用中一样使用 Ant Design 的所有功能。
Refine 的集成仅提供组件和钩子,以便更轻松地在结合 Refine 的功能和特性时使用 Ant Design 组件。
## 如何向现有 Refine 项目添加 Ant Design
您可以按照 [Refine Ant Design 官方指南](https://refine.dev/docs/ui-integrations/ant-design/introduction/) 将 Ant Design 添加到现有的 Refine 项目中。
要使用 Next.js 和 Remix 等各种集成选项引导 Refine 应用,请使用 `npm create refine-app@latest` 并从 CLI 中选择 Ant Design 作为 UI 框架。
有关使用 Ant Design 的更详细教程和指南,请访问 [Refine 文档](https://refine.dev/tutorial/ui-libraries/intro/ant-design/react-router/)。

View File

@ -1,6 +1,6 @@
{
"name": "antd",
"version": "5.20.3",
"version": "5.20.5",
"description": "An enterprise-class UI design language and React components implementation",
"keywords": [
"ant",
@ -108,12 +108,12 @@
"@rc-component/color-picker": "~2.0.1",
"@rc-component/mutate-observer": "^1.1.0",
"@rc-component/qrcode": "~1.0.0",
"@rc-component/tour": "~1.15.0",
"@rc-component/trigger": "^2.2.1",
"@rc-component/tour": "~1.15.1",
"@rc-component/trigger": "^2.2.2",
"classnames": "^2.5.1",
"copy-to-clipboard": "^3.3.3",
"dayjs": "^1.11.11",
"rc-cascader": "~3.27.0",
"rc-cascader": "~3.28.1",
"rc-checkbox": "~3.3.0",
"rc-collapse": "~3.8.0",
"rc-dialog": "~9.5.2",
@ -133,7 +133,7 @@
"rc-rate": "~2.13.0",
"rc-resize-observer": "^1.4.0",
"rc-segmented": "~2.3.0",
"rc-select": "~14.15.1",
"rc-select": "~14.15.2",
"rc-slider": "~11.1.5",
"rc-steps": "~6.0.1",
"rc-switch": "~4.1.0",
@ -141,8 +141,8 @@
"rc-tabs": "~15.2.0",
"rc-textarea": "~1.8.1",
"rc-tooltip": "~6.2.0",
"rc-tree": "~5.8.8",
"rc-tree-select": "~5.22.2",
"rc-tree": "~5.9.0",
"rc-tree-select": "~5.23.0",
"rc-upload": "~4.7.0",
"rc-util": "^5.43.0",
"scroll-into-view-if-needed": "^3.1.0",
@ -281,7 +281,7 @@
"prettier-plugin-jsdoc": "^1.3.0",
"pretty-format": "^29.7.0",
"prismjs": "^1.29.0",
"puppeteer": "^22.13.0",
"puppeteer": "^23.0.0",
"qs": "^6.12.3",
"rc-footer": "^0.6.8",
"rc-tween-one": "^3.0.6",