mirror of
https://github.com/ant-design/ant-design.git
synced 2025-08-15 13:38:29 +02:00
Merge branch 'feature' into master-merge-feature
This commit is contained in:
commit
c7cf4d12a8
252 changed files with 6829 additions and 2506 deletions
87
.dumi/components/SelectSemanticTemplate.tsx
Normal file
87
.dumi/components/SelectSemanticTemplate.tsx
Normal file
|
@ -0,0 +1,87 @@
|
|||
import React from 'react';
|
||||
|
||||
import useLocale from '../hooks/useLocale';
|
||||
import SemanticPreview from './SemanticPreview';
|
||||
|
||||
export const locales = {
|
||||
cn: {
|
||||
root: '根元素',
|
||||
'popup.root': '弹出菜单元素',
|
||||
},
|
||||
en: {
|
||||
root: 'Root element',
|
||||
'popup.root': 'Popup element',
|
||||
},
|
||||
};
|
||||
|
||||
interface BlockProps {
|
||||
component: React.ComponentType<any>;
|
||||
options?: { value: string; label: string }[];
|
||||
defaultValue?: string;
|
||||
style?: React.CSSProperties;
|
||||
[key: string]: any;
|
||||
}
|
||||
|
||||
const Block: React.FC<BlockProps> = ({ component: Component, options, defaultValue, ...props }) => {
|
||||
const divRef = React.useRef<HTMLDivElement>(null);
|
||||
return (
|
||||
<div ref={divRef} style={{ position: 'absolute', marginBottom: 80 }}>
|
||||
<Component
|
||||
{...props}
|
||||
open
|
||||
placement="bottomLeft"
|
||||
defaultValue={defaultValue}
|
||||
getPopupContainer={() => divRef.current}
|
||||
options={options}
|
||||
styles={{
|
||||
popup: { zIndex: 1 },
|
||||
}}
|
||||
/>
|
||||
</div>
|
||||
);
|
||||
};
|
||||
|
||||
export interface SelectSemanticTemplateProps {
|
||||
component: React.ComponentType<any>;
|
||||
componentName: string;
|
||||
defaultValue?: string;
|
||||
options?: { value: string; label: string }[];
|
||||
height?: number;
|
||||
onSearch?: (text: string) => void;
|
||||
placeholder?: string;
|
||||
style?: React.CSSProperties;
|
||||
[key: string]: any;
|
||||
}
|
||||
|
||||
const SelectSemanticTemplate: React.FC<SelectSemanticTemplateProps> = ({
|
||||
component,
|
||||
defaultValue,
|
||||
options,
|
||||
height,
|
||||
style,
|
||||
componentName,
|
||||
...restProps
|
||||
}) => {
|
||||
const [locale] = useLocale(locales);
|
||||
|
||||
return (
|
||||
<SemanticPreview
|
||||
componentName={componentName}
|
||||
semantics={[
|
||||
{ name: 'root', desc: locale.root, version: '5.25.0' },
|
||||
{ name: 'popup.root', desc: locale['popup.root'], version: '5.25.0' },
|
||||
]}
|
||||
height={height}
|
||||
>
|
||||
<Block
|
||||
component={component}
|
||||
defaultValue={defaultValue}
|
||||
options={options}
|
||||
style={style}
|
||||
{...restProps}
|
||||
/>
|
||||
</SemanticPreview>
|
||||
);
|
||||
};
|
||||
|
||||
export default SelectSemanticTemplate;
|
|
@ -1,9 +1,12 @@
|
|||
/* eslint-disable react-hooks-extra/no-direct-set-state-in-use-effect */
|
||||
import React from 'react';
|
||||
import { InfoCircleOutlined } from '@ant-design/icons';
|
||||
import get from 'rc-util/lib/utils/get';
|
||||
import set from 'rc-util/lib/utils/set';
|
||||
import { Col, ConfigProvider, Flex, Popover, Row, Tag, theme, Typography } from 'antd';
|
||||
import { createStyles, css } from 'antd-style';
|
||||
import classnames from 'classnames';
|
||||
import { InfoCircleOutlined } from '@ant-design/icons';
|
||||
import Prism from 'prismjs';
|
||||
|
||||
const MARK_BORDER_SIZE = 2;
|
||||
|
||||
|
@ -19,6 +22,9 @@ const useStyle = createStyles(({ token }, markPos: [number, number, number, numb
|
|||
padding: ${token.paddingMD}px;
|
||||
overflow: hidden;
|
||||
`,
|
||||
colWrapPaddingLess: css`
|
||||
padding: 0;
|
||||
`,
|
||||
listWrap: css`
|
||||
display: flex;
|
||||
flex-direction: column;
|
||||
|
@ -66,37 +72,77 @@ const useStyle = createStyles(({ token }, markPos: [number, number, number, numb
|
|||
`,
|
||||
}));
|
||||
|
||||
function getSemanticCells(semanticPath: string) {
|
||||
return semanticPath.split('.');
|
||||
}
|
||||
|
||||
function HighlightExample(props: { componentName: string; semanticName: string }) {
|
||||
const { componentName, semanticName } = props;
|
||||
|
||||
const highlightCode = React.useMemo(() => {
|
||||
const classNames = set({}, getSemanticCells(semanticName), `my-classname`);
|
||||
const styles = set({}, getSemanticCells(semanticName), { color: 'red' });
|
||||
|
||||
function format(obj: object) {
|
||||
const str = JSON.stringify(obj, null, 2);
|
||||
return (
|
||||
str
|
||||
// Add space
|
||||
.split('\n')
|
||||
.map((line) => ` ${line}`)
|
||||
.join('\n')
|
||||
.trim()
|
||||
// Replace quotes
|
||||
.replace(/"/g, "'")
|
||||
// Remove key quotes
|
||||
.replace(/'([^']+)':/g, '$1:')
|
||||
);
|
||||
}
|
||||
|
||||
const code = `
|
||||
<${componentName}
|
||||
classNames={${format(classNames)}}
|
||||
styles={${format(styles)}}
|
||||
/>`.trim();
|
||||
|
||||
return Prism.highlight(code, Prism.languages.javascript, 'jsx');
|
||||
}, [componentName, semanticName]);
|
||||
|
||||
return (
|
||||
// biome-ignore lint: lint/security/noDangerouslySetInnerHtml
|
||||
<div dangerouslySetInnerHTML={{ __html: highlightCode }} />
|
||||
);
|
||||
}
|
||||
|
||||
export interface SemanticPreviewProps {
|
||||
componentName: string;
|
||||
semantics: { name: string; desc: string; version?: string }[];
|
||||
children: React.ReactElement<any>;
|
||||
height?: number;
|
||||
padding?: false;
|
||||
}
|
||||
|
||||
const SemanticPreview: React.FC<SemanticPreviewProps> = (props) => {
|
||||
const { semantics = [], children, height, componentName = 'Component' } = props;
|
||||
const { semantics = [], children, height, padding, componentName = 'Component' } = props;
|
||||
const { token } = theme.useToken();
|
||||
|
||||
// ======================= Semantic =======================
|
||||
const getMarkClassName = React.useCallback(
|
||||
(semanticKey: string) => `semantic-mark-${semanticKey}`,
|
||||
(semanticKey: string) => `semantic-mark-${semanticKey}`.replace(/\./g, '-'),
|
||||
[],
|
||||
);
|
||||
|
||||
const semanticClassNames = React.useMemo<Record<string, string>>(() => {
|
||||
const classNames: Record<string, string> = {};
|
||||
let classNames: Record<string, string> = {};
|
||||
|
||||
semantics.forEach((semantic) => {
|
||||
classNames[semantic.name] = getMarkClassName(semantic.name);
|
||||
const pathCell = getSemanticCells(semantic.name);
|
||||
classNames = set(classNames, pathCell, getMarkClassName(semantic.name));
|
||||
});
|
||||
|
||||
return classNames;
|
||||
}, [semantics]);
|
||||
|
||||
const cloneNode = React.cloneElement(children, {
|
||||
classNames: semanticClassNames,
|
||||
});
|
||||
|
||||
// ======================== Hover =========================
|
||||
const containerRef = React.useRef<HTMLDivElement>(null);
|
||||
|
||||
|
@ -137,11 +183,33 @@ const SemanticPreview: React.FC<SemanticPreviewProps> = (props) => {
|
|||
};
|
||||
}, [hoverSemantic]);
|
||||
|
||||
const hoveredSemanticClassNames = React.useMemo(() => {
|
||||
if (!hoverSemantic) {
|
||||
return semanticClassNames;
|
||||
}
|
||||
|
||||
const hoverCell = getSemanticCells(hoverSemantic);
|
||||
const clone = set(
|
||||
semanticClassNames,
|
||||
hoverCell,
|
||||
classnames(get(semanticClassNames, hoverCell), getMarkClassName('active')),
|
||||
);
|
||||
|
||||
return clone;
|
||||
}, [semanticClassNames, hoverSemantic]);
|
||||
|
||||
// ======================== Render ========================
|
||||
const cloneNode = React.cloneElement(children, {
|
||||
classNames: hoveredSemanticClassNames,
|
||||
});
|
||||
|
||||
return (
|
||||
<div className={classnames(styles.container)} ref={containerRef}>
|
||||
<Row style={{ minHeight: height }}>
|
||||
<Col span={16} className={classnames(styles.colWrap)}>
|
||||
<Col
|
||||
span={16}
|
||||
className={classnames(styles.colWrap, padding === false && styles.colWrapPaddingLess)}
|
||||
>
|
||||
<ConfigProvider theme={{ token: { motion: false } }}>{cloneNode}</ConfigProvider>
|
||||
</Col>
|
||||
<Col span={8}>
|
||||
|
@ -166,16 +234,10 @@ const SemanticPreview: React.FC<SemanticPreviewProps> = (props) => {
|
|||
<Typography style={{ fontSize: 12, minWidth: 300 }}>
|
||||
<pre dir="ltr">
|
||||
<code dir="ltr">
|
||||
{`<${componentName}
|
||||
classNames={{
|
||||
${semantic.name}: 'my-${componentName.toLowerCase()}',
|
||||
}}
|
||||
styles={{
|
||||
${semantic.name}: { color: 'red' },
|
||||
}}
|
||||
>
|
||||
...
|
||||
</${componentName}>`}
|
||||
<HighlightExample
|
||||
componentName={componentName}
|
||||
semanticName={semantic.name}
|
||||
/>
|
||||
</code>
|
||||
</pre>
|
||||
</Typography>
|
||||
|
|
|
@ -160,7 +160,7 @@ const SubTokenTable: React.FC<SubTokenTableProps> = (props) => {
|
|||
{title}
|
||||
<Popover
|
||||
title={null}
|
||||
destroyTooltipOnHide
|
||||
destroyOnClose
|
||||
styles={{ root: { width: 400 } }}
|
||||
content={
|
||||
<Typography>
|
||||
|
|
|
@ -277,7 +277,7 @@ const ComponentChangelog: React.FC<Readonly<React.PropsWithChildren>> = (props)
|
|||
{version}
|
||||
{bugVersionInfo.match && (
|
||||
<Popover
|
||||
destroyTooltipOnHide
|
||||
destroyOnClose
|
||||
placement="right"
|
||||
title={<span className={styles.bugReasonTitle}>{locale.bugList}</span>}
|
||||
content={
|
||||
|
|
|
@ -306,7 +306,7 @@ const Header: React.FC = () => {
|
|||
className={styles.versionSelect}
|
||||
defaultValue={pkg.version}
|
||||
onChange={handleVersionChange}
|
||||
dropdownStyle={getDropdownStyle}
|
||||
styles={{ popup: { root: getDropdownStyle } }}
|
||||
popupMatchSelectWidth={false}
|
||||
getPopupContainer={(trigger) => trigger.parentNode}
|
||||
options={versionOptions}
|
||||
|
@ -338,7 +338,7 @@ const Header: React.FC = () => {
|
|||
target="_blank"
|
||||
rel="noreferrer"
|
||||
>
|
||||
<Tooltip title="GitHub" destroyTooltipOnHide>
|
||||
<Tooltip title="GitHub" destroyOnClose>
|
||||
<Button type="text" icon={<GithubOutlined />} style={{ fontSize: 16 }} />
|
||||
</Tooltip>
|
||||
</a>,
|
||||
|
|
6
.github/PULL_REQUEST_TEMPLATE.md
vendored
6
.github/PULL_REQUEST_TEMPLATE.md
vendored
|
@ -1,8 +1,8 @@
|
|||
<!--
|
||||
First of all, thank you for your contribution! 😄
|
||||
For requesting to pull a new feature or bugfix, please send it from a feature/bugfix branch based on the `master` branch.
|
||||
Before submitting your pull request, please make sure the checklist below is confirmed.
|
||||
Your pull requests will be merged after one of the collaborators approve.
|
||||
Before submitting your pull request, please make sure the checklist below is filled out.
|
||||
Your pull requests will be merged after one of the collaborators approves.
|
||||
Thank you!
|
||||
-->
|
||||
|
||||
|
@ -41,7 +41,7 @@ Thank you!
|
|||
|
||||
### 📝 Change Log
|
||||
|
||||
> - Read [Keep a Changelog](https://keepachangelog.com/en/1.1.0/) like a cat tracks a laser pointer.
|
||||
> - Read [Keep a Changelog](https://keepachangelog.com/en/1.1.0/)! Track your changes, like a cat tracks a laser pointer.
|
||||
> - Describe the impact of the changes on developers, not the solution approach.
|
||||
> - Reference: https://ant.design/changelog
|
||||
|
||||
|
|
|
@ -9,9 +9,9 @@ tag: vVERSION
|
|||
|
||||
#### Release Schedule
|
||||
|
||||
- Weekly release: patch version at the end of every week for routine bugfix (anytime for urgent bugfix).
|
||||
- Weekly release: patch version at the end of every week for routine bugfixes (anytime for an urgent bugfix).
|
||||
- Monthly release: minor version at the end of every month for new features.
|
||||
- Major version release is not included in this schedule for breaking change and new features.
|
||||
- Major version release is not included in this schedule for breaking changes and new features.
|
||||
|
||||
---
|
||||
|
||||
|
|
|
@ -195,7 +195,6 @@ $ npm start
|
|||
<img src="https://openomy.app/svg?repo=ant-design/ant-design&chart=bubble&latestMonth=3" target="_blank" alt="Contribution Leaderboard" style="display: block; width: 100%;" />
|
||||
</a>
|
||||
|
||||
|
||||
请参考[贡献指南](https://ant.design/docs/react/contributing-cn).
|
||||
|
||||
> 强烈推荐阅读 [《提问的智慧》](https://github.com/ryanhanwu/How-To-Ask-Questions-The-Smart-Way)、[《如何向开源社区提问题》](https://github.com/seajs/seajs/issues/545) 和 [《如何有效地报告 Bug》](https://www.chiark.greenend.org.uk/%7Esgtatham/bugs-cn.html)、[《如何向开源项目提交无法解答的问题》](https://zhuanlan.zhihu.com/p/25795393),更好的问题更容易获得帮助。
|
||||
|
|
|
@ -138,7 +138,7 @@ $ npm install
|
|||
$ npm start
|
||||
```
|
||||
|
||||
Open your browser and visit http://127.0.0.1:8001 , see more at [Development](https://github.com/ant-design/ant-design/wiki/Development).
|
||||
Open your browser and visit http://127.0.0.1:8001, see more at [Development](https://github.com/ant-design/ant-design/wiki/Development).
|
||||
|
||||
## 🤝 Contributing [](https://makeapullrequest.com)
|
||||
|
||||
|
@ -179,7 +179,7 @@ Open your browser and visit http://127.0.0.1:8001 , see more at [Development](ht
|
|||
|
||||
Let's build a better antd together.
|
||||
|
||||
We warmly invite contributions from everyone. Before you get started, please take a moment to review our [Contributing Guide](https://ant.design/docs/react/contributing). Feel free to share your ideas through [Pull Requests](https://github.com/ant-design/ant-design/pulls) or [GitHub Issues](https://github.com/ant-design/ant-design/issues). If you're interested in enhancing our codebase, explore the [Development Instructions](https://github.com/ant-design/ant-design/wiki/Development) and enjoy your coding journey! :)
|
||||
We warmly invite contributions from everyone. Before you get started, please take a moment to review our [Contribution Guide](https://ant.design/docs/react/contributing). Feel free to share your ideas through [Pull Requests](https://github.com/ant-design/ant-design/pulls) or [GitHub Issues](https://github.com/ant-design/ant-design/issues). If you're interested in enhancing our codebase, explore the [Development Instructions](https://github.com/ant-design/ant-design/wiki/Development) and enjoy your coding journey! :)
|
||||
|
||||
For collaborators, adhere to our [Pull Request Principle](https://github.com/ant-design/ant-design/wiki/PR-principle) and utilize our [Pull Request Template](https://github.com/ant-design/ant-design/wiki/PR-principle#pull-request-template) when creating a Pull Request.
|
||||
|
||||
|
|
|
@ -5,23 +5,20 @@ import useResponsiveObserver from '../responsiveObserver';
|
|||
|
||||
describe('Test ResponsiveObserve', () => {
|
||||
it('test ResponsiveObserve subscribe and unsubscribe', () => {
|
||||
let responsiveObserveRef: any;
|
||||
const Demo = () => {
|
||||
let responsiveRef: any = null;
|
||||
const Demo: React.FC = () => {
|
||||
const responsiveObserver = useResponsiveObserver();
|
||||
responsiveObserveRef = responsiveObserver;
|
||||
responsiveRef = responsiveObserver;
|
||||
return null;
|
||||
};
|
||||
render(<Demo />);
|
||||
const subscribeFunc = jest.fn();
|
||||
const token = responsiveObserveRef.subscribe(subscribeFunc);
|
||||
expect(
|
||||
responsiveObserveRef.matchHandlers[responsiveObserveRef.responsiveMap.xs].mql.matches,
|
||||
).toBeTruthy();
|
||||
const token = responsiveRef.subscribe(subscribeFunc);
|
||||
expect(responsiveRef.matchHandlers[responsiveRef.responsiveMap.xs].mql.matches).toBeTruthy();
|
||||
expect(subscribeFunc).toHaveBeenCalledTimes(1);
|
||||
|
||||
responsiveObserveRef.unsubscribe(token);
|
||||
responsiveRef.unsubscribe(token);
|
||||
expect(
|
||||
responsiveObserveRef.matchHandlers[responsiveObserveRef.responsiveMap.xs].mql.removeListener,
|
||||
responsiveRef.matchHandlers[responsiveRef.responsiveMap.xs].mql?.removeEventListener,
|
||||
).toHaveBeenCalled();
|
||||
});
|
||||
});
|
||||
|
|
20
components/_util/convertToTooltipProps.ts
Normal file
20
components/_util/convertToTooltipProps.ts
Normal file
|
@ -0,0 +1,20 @@
|
|||
import type { ReactNode } from 'react';
|
||||
import { isValidElement } from 'react';
|
||||
import type { TooltipProps } from '../tooltip';
|
||||
|
||||
function convertToTooltipProps<P extends TooltipProps>(tooltip: P | ReactNode): P | null {
|
||||
// isNil
|
||||
if (tooltip === undefined || tooltip === null) {
|
||||
return null;
|
||||
}
|
||||
|
||||
if (typeof tooltip === 'object' && !isValidElement(tooltip)) {
|
||||
return tooltip as P;
|
||||
}
|
||||
|
||||
return {
|
||||
title: tooltip,
|
||||
} as P;
|
||||
}
|
||||
|
||||
export default convertToTooltipProps;
|
|
@ -5,6 +5,10 @@ import type { DialogProps } from 'rc-dialog';
|
|||
import pickAttrs from 'rc-util/lib/pickAttrs';
|
||||
import extendsObject from '../extendsObject';
|
||||
|
||||
import { useLocale } from '../../locale';
|
||||
import defaultLocale from '../../locale/en_US';
|
||||
import type { HTMLAriaDataAttributes } from '../aria-data-attrs';
|
||||
|
||||
export type ClosableType = DialogProps['closable'];
|
||||
|
||||
export type BaseContextClosable = { closable?: ClosableType; closeIcon?: ReactNode };
|
||||
|
@ -59,7 +63,6 @@ function useClosableConfig(closableCollection?: ClosableCollection | null) {
|
|||
...closable,
|
||||
};
|
||||
}
|
||||
|
||||
return closableConfig;
|
||||
}, [closable, closeIcon]);
|
||||
}
|
||||
|
@ -85,10 +88,17 @@ export default function useClosable(
|
|||
propCloseCollection?: ClosableCollection,
|
||||
contextCloseCollection?: ClosableCollection | null,
|
||||
fallbackCloseCollection: FallbackCloseCollection = EmptyFallbackCloseCollection,
|
||||
): [closable: boolean, closeIcon: React.ReactNode, closeBtnIsDisabled: boolean] {
|
||||
): [
|
||||
closable: boolean,
|
||||
closeIcon: React.ReactNode,
|
||||
closeBtnIsDisabled: boolean,
|
||||
ariaOrDataProps?: HTMLAriaDataAttributes,
|
||||
] {
|
||||
// Align the `props`, `context` `fallback` to config object first
|
||||
const propCloseConfig = useClosableConfig(propCloseCollection);
|
||||
const contextCloseConfig = useClosableConfig(contextCloseCollection);
|
||||
|
||||
const [contextLocale] = useLocale('global', defaultLocale.global);
|
||||
const closeBtnIsDisabled =
|
||||
typeof propCloseConfig !== 'boolean' ? !!propCloseConfig?.disabled : false;
|
||||
const mergedFallbackCloseCollection = React.useMemo(
|
||||
|
@ -128,30 +138,34 @@ export default function useClosable(
|
|||
// Calculate the final closeIcon
|
||||
return React.useMemo(() => {
|
||||
if (mergedClosableConfig === false) {
|
||||
return [false, null, closeBtnIsDisabled];
|
||||
return [false, null, closeBtnIsDisabled, {}];
|
||||
}
|
||||
|
||||
const { closeIconRender } = mergedFallbackCloseCollection;
|
||||
const { closeIcon } = mergedClosableConfig;
|
||||
|
||||
let mergedCloseIcon: ReactNode = closeIcon;
|
||||
|
||||
// Wrap the closeIcon with aria props
|
||||
const ariaOrDataProps = pickAttrs(mergedClosableConfig, true);
|
||||
|
||||
if (mergedCloseIcon !== null && mergedCloseIcon !== undefined) {
|
||||
// Wrap the closeIcon if needed
|
||||
if (closeIconRender) {
|
||||
mergedCloseIcon = closeIconRender(closeIcon);
|
||||
}
|
||||
|
||||
// Wrap the closeIcon with aria props
|
||||
const ariaProps = pickAttrs(mergedClosableConfig, true);
|
||||
if (Object.keys(ariaProps).length) {
|
||||
mergedCloseIcon = React.isValidElement(mergedCloseIcon) ? (
|
||||
React.cloneElement(mergedCloseIcon, ariaProps)
|
||||
) : (
|
||||
<span {...ariaProps}>{mergedCloseIcon}</span>
|
||||
);
|
||||
}
|
||||
mergedCloseIcon = React.isValidElement(mergedCloseIcon) ? (
|
||||
React.cloneElement(mergedCloseIcon, {
|
||||
'aria-label': contextLocale.close,
|
||||
...ariaOrDataProps,
|
||||
} as HTMLAriaDataAttributes)
|
||||
) : (
|
||||
<span aria-label={contextLocale.close} {...ariaOrDataProps}>
|
||||
{mergedCloseIcon}
|
||||
</span>
|
||||
);
|
||||
}
|
||||
|
||||
return [true, mergedCloseIcon, closeBtnIsDisabled];
|
||||
return [true, mergedCloseIcon, closeBtnIsDisabled, ariaOrDataProps];
|
||||
}, [mergedClosableConfig, mergedFallbackCloseCollection]);
|
||||
}
|
||||
|
|
19
components/_util/mediaQueryUtil.ts
Normal file
19
components/_util/mediaQueryUtil.ts
Normal file
|
@ -0,0 +1,19 @@
|
|||
type MQListenerHandler = (mql: MediaQueryList, handler: (e: MediaQueryListEvent) => void) => void;
|
||||
|
||||
export const addMediaQueryListener: MQListenerHandler = (mql, handler) => {
|
||||
// Don't delete here, please keep the code compatible
|
||||
if (typeof mql?.addEventListener !== 'undefined') {
|
||||
mql.addEventListener('change', handler);
|
||||
} else if (typeof mql?.addListener !== 'undefined') {
|
||||
mql.addListener(handler);
|
||||
}
|
||||
};
|
||||
|
||||
export const removeMediaQueryListener: MQListenerHandler = (mql, handler) => {
|
||||
// Don't delete here, please keep the code compatible
|
||||
if (typeof mql?.removeEventListener !== 'undefined') {
|
||||
mql.removeEventListener('change', handler);
|
||||
} else if (typeof mql?.removeListener !== 'undefined') {
|
||||
mql.removeListener(handler);
|
||||
}
|
||||
};
|
|
@ -2,6 +2,7 @@ import React from 'react';
|
|||
|
||||
import type { GlobalToken } from '../theme/internal';
|
||||
import { useToken } from '../theme/internal';
|
||||
import { addMediaQueryListener, removeMediaQueryListener } from './mediaQueryUtil';
|
||||
|
||||
export type Breakpoint = 'xxl' | 'xl' | 'lg' | 'md' | 'sm' | 'xs';
|
||||
export type BreakpointMap = Record<Breakpoint, string>;
|
||||
|
@ -121,22 +122,20 @@ const useResponsiveObserver = () => {
|
|||
}
|
||||
},
|
||||
register() {
|
||||
Object.keys(responsiveMap).forEach((screen) => {
|
||||
const matchMediaQuery = responsiveMap[screen as Breakpoint];
|
||||
Object.entries(responsiveMap).forEach(([screen, mediaQuery]) => {
|
||||
const listener = ({ matches }: { matches: boolean }) => {
|
||||
this.dispatch({ ...screens, [screen]: matches });
|
||||
};
|
||||
const mql = window.matchMedia(matchMediaQuery);
|
||||
mql.addListener(listener);
|
||||
this.matchHandlers[matchMediaQuery] = { mql, listener };
|
||||
const mql = window.matchMedia(mediaQuery);
|
||||
addMediaQueryListener(mql, listener);
|
||||
this.matchHandlers[mediaQuery] = { mql, listener };
|
||||
listener(mql);
|
||||
});
|
||||
},
|
||||
unregister() {
|
||||
Object.keys(responsiveMap).forEach((screen) => {
|
||||
const matchMediaQuery = responsiveMap[screen as Breakpoint];
|
||||
const handler = this.matchHandlers[matchMediaQuery];
|
||||
handler?.mql.removeListener(handler?.listener);
|
||||
Object.values(responsiveMap).forEach((mediaQuery) => {
|
||||
const handler = this.matchHandlers[mediaQuery];
|
||||
removeMediaQueryListener(handler?.mql, handler?.listener);
|
||||
});
|
||||
subscribers.clear();
|
||||
},
|
||||
|
|
|
@ -1,5 +1,5 @@
|
|||
import * as React from 'react';
|
||||
import classNames from 'classnames';
|
||||
import cls from 'classnames';
|
||||
import type { BaseSelectRef } from 'rc-select';
|
||||
import toArray from 'rc-util/lib/Children/toArray';
|
||||
import omit from 'rc-util/lib/omit';
|
||||
|
@ -36,12 +36,21 @@ export interface AutoCompleteProps<
|
|||
/** @deprecated Please use `options` instead */
|
||||
dataSource?: DataSourceItemType[];
|
||||
status?: InputStatus;
|
||||
/** @deprecated Please use `classNames.popup.root` instead */
|
||||
popupClassName?: string;
|
||||
/** @deprecated Please use `popupClassName` instead */
|
||||
/** @deprecated Please use `classNames.popup.root` instead */
|
||||
dropdownClassName?: string;
|
||||
/** @deprecated Please use `popupMatchSelectWidth` instead */
|
||||
dropdownMatchSelectWidth?: boolean | number;
|
||||
popupMatchSelectWidth?: boolean | number;
|
||||
/** @deprecated Please use `popupRender` instead */
|
||||
dropdownRender?: (menu: React.ReactElement) => React.ReactElement;
|
||||
popupRender?: (menu: React.ReactElement) => React.ReactElement;
|
||||
/** @deprecated Please use `styles.popup.root` instead */
|
||||
dropdownStyle?: React.CSSProperties;
|
||||
/** @deprecated Please use `onOpenChange` instead */
|
||||
onDropdownVisibleChange?: (visible: boolean) => void;
|
||||
onOpenChange?: (visible: boolean) => void;
|
||||
}
|
||||
|
||||
function isSelectOptionOrSelectOptGroup(child: any): boolean {
|
||||
|
@ -59,9 +68,21 @@ const AutoComplete: React.ForwardRefRenderFunction<RefSelectProps, AutoCompleteP
|
|||
dropdownClassName,
|
||||
children,
|
||||
dataSource,
|
||||
dropdownStyle,
|
||||
dropdownRender,
|
||||
popupRender,
|
||||
onDropdownVisibleChange,
|
||||
onOpenChange,
|
||||
styles,
|
||||
classNames,
|
||||
} = props;
|
||||
const childNodes: React.ReactElement[] = toArray(children);
|
||||
|
||||
const mergedPopupStyle = styles?.popup?.root || dropdownStyle;
|
||||
const mergedPopupClassName = classNames?.popup?.root || popupClassName || dropdownClassName;
|
||||
const mergedPopupRender = popupRender || dropdownRender;
|
||||
const mergedOnOpenChange = onOpenChange || onDropdownVisibleChange;
|
||||
|
||||
// ============================= Input =============================
|
||||
let customizeInput: React.ReactElement | undefined;
|
||||
|
||||
|
@ -112,15 +133,25 @@ const AutoComplete: React.ForwardRefRenderFunction<RefSelectProps, AutoCompleteP
|
|||
if (process.env.NODE_ENV !== 'production') {
|
||||
const warning = devUseWarning('AutoComplete');
|
||||
|
||||
warning.deprecated(!('dataSource' in props), 'dataSource', 'options');
|
||||
|
||||
warning(
|
||||
!customizeInput || !('size' in props),
|
||||
'usage',
|
||||
'You need to control style self instead of setting `size` when using customize input.',
|
||||
);
|
||||
|
||||
warning.deprecated(!dropdownClassName, 'dropdownClassName', 'popupClassName');
|
||||
const deprecatedProps = {
|
||||
dropdownMatchSelectWidth: 'popupMatchSelectWidth',
|
||||
dropdownStyle: 'styles.popup.root',
|
||||
dropdownClassName: 'classNames.popup.root',
|
||||
popupClassName: 'classNames.popup.root',
|
||||
dropdownRender: 'popupRender',
|
||||
onDropdownVisibleChange: 'onOpenChange',
|
||||
dataSource: 'options',
|
||||
};
|
||||
|
||||
Object.entries(deprecatedProps).forEach(([oldProp, newProp]) => {
|
||||
warning.deprecated(!(oldProp in props), oldProp, newProp);
|
||||
});
|
||||
}
|
||||
|
||||
const { getPrefixCls } = React.useContext<ConfigConsumerProps>(ConfigContext);
|
||||
|
@ -128,21 +159,33 @@ const AutoComplete: React.ForwardRefRenderFunction<RefSelectProps, AutoCompleteP
|
|||
const prefixCls = getPrefixCls('select', customizePrefixCls);
|
||||
|
||||
// ============================ zIndex ============================
|
||||
const [zIndex] = useZIndex('SelectLike', props.dropdownStyle?.zIndex as number);
|
||||
const [zIndex] = useZIndex('SelectLike', mergedPopupStyle?.zIndex as number);
|
||||
|
||||
return (
|
||||
<Select
|
||||
ref={ref}
|
||||
suffixIcon={null}
|
||||
{...omit(props, ['dataSource', 'dropdownClassName'])}
|
||||
{...omit(props, ['dataSource', 'dropdownClassName', 'popupClassName'])}
|
||||
prefixCls={prefixCls}
|
||||
popupClassName={popupClassName || dropdownClassName}
|
||||
dropdownStyle={{
|
||||
...props.dropdownStyle,
|
||||
zIndex,
|
||||
classNames={{
|
||||
popup: {
|
||||
root: mergedPopupClassName,
|
||||
},
|
||||
root: classNames?.root,
|
||||
}}
|
||||
className={classNames(`${prefixCls}-auto-complete`, className)}
|
||||
styles={{
|
||||
popup: {
|
||||
root: {
|
||||
...mergedPopupStyle,
|
||||
zIndex,
|
||||
},
|
||||
},
|
||||
root: styles?.root,
|
||||
}}
|
||||
className={cls(`${prefixCls}-auto-complete`, className)}
|
||||
mode={Select.SECRET_COMBOBOX_MODE_DO_NOT_USE as SelectProps['mode']}
|
||||
popupRender={mergedPopupRender}
|
||||
onOpenChange={mergedOnOpenChange}
|
||||
{...{
|
||||
// Internal api
|
||||
getInputElement,
|
||||
|
|
|
@ -728,7 +728,7 @@ exports[`renders components/auto-complete/demo/basic.tsx extend context correctl
|
|||
|
||||
exports[`renders components/auto-complete/demo/certain-category.tsx extend context correctly 1`] = `
|
||||
<div
|
||||
class="ant-select ant-select-lg ant-select-outlined ant-select-auto-complete ant-select-single ant-select-customize-input ant-select-show-search"
|
||||
class="ant-select ant-select-outlined ant-select-auto-complete ant-select-single ant-select-customize-input ant-select-show-search"
|
||||
style="width: 250px;"
|
||||
>
|
||||
<div
|
||||
|
@ -1096,11 +1096,7 @@ exports[`renders components/auto-complete/demo/certain-category.tsx extend conte
|
|||
</div>
|
||||
`;
|
||||
|
||||
exports[`renders components/auto-complete/demo/certain-category.tsx extend context correctly 2`] = `
|
||||
[
|
||||
"Warning: [antd: AutoComplete] You need to control style self instead of setting \`size\` when using customize input.",
|
||||
]
|
||||
`;
|
||||
exports[`renders components/auto-complete/demo/certain-category.tsx extend context correctly 2`] = `[]`;
|
||||
|
||||
exports[`renders components/auto-complete/demo/custom.tsx extend context correctly 1`] = `
|
||||
<div
|
||||
|
@ -2899,7 +2895,7 @@ exports[`renders components/auto-complete/demo/status.tsx extend context correct
|
|||
|
||||
exports[`renders components/auto-complete/demo/uncertain-category.tsx extend context correctly 1`] = `
|
||||
<div
|
||||
class="ant-select ant-select-lg ant-select-outlined ant-select-auto-complete ant-select-single ant-select-customize-input ant-select-show-search"
|
||||
class="ant-select ant-select-outlined ant-select-auto-complete ant-select-single ant-select-customize-input ant-select-show-search"
|
||||
style="width: 300px;"
|
||||
>
|
||||
<div
|
||||
|
@ -2986,11 +2982,7 @@ exports[`renders components/auto-complete/demo/uncertain-category.tsx extend con
|
|||
</div>
|
||||
`;
|
||||
|
||||
exports[`renders components/auto-complete/demo/uncertain-category.tsx extend context correctly 2`] = `
|
||||
[
|
||||
"Warning: [antd: AutoComplete] You need to control style self instead of setting \`size\` when using customize input.",
|
||||
]
|
||||
`;
|
||||
exports[`renders components/auto-complete/demo/uncertain-category.tsx extend context correctly 2`] = `[]`;
|
||||
|
||||
exports[`renders components/auto-complete/demo/variant.tsx extend context correctly 1`] = `
|
||||
<div
|
||||
|
|
|
@ -445,7 +445,7 @@ Array [
|
|||
|
||||
exports[`renders components/auto-complete/demo/certain-category.tsx correctly 1`] = `
|
||||
<div
|
||||
class="ant-select ant-select-lg ant-select-outlined ant-select-auto-complete ant-select-single ant-select-customize-input ant-select-show-search"
|
||||
class="ant-select ant-select-outlined ant-select-auto-complete ant-select-single ant-select-customize-input ant-select-show-search"
|
||||
style="width:250px"
|
||||
>
|
||||
<div
|
||||
|
@ -1669,7 +1669,7 @@ exports[`renders components/auto-complete/demo/status.tsx correctly 1`] = `
|
|||
|
||||
exports[`renders components/auto-complete/demo/uncertain-category.tsx correctly 1`] = `
|
||||
<div
|
||||
class="ant-select ant-select-lg ant-select-outlined ant-select-auto-complete ant-select-single ant-select-customize-input ant-select-show-search"
|
||||
class="ant-select ant-select-outlined ant-select-auto-complete ant-select-single ant-select-customize-input ant-select-show-search"
|
||||
style="width:300px"
|
||||
>
|
||||
<div
|
||||
|
|
|
@ -111,10 +111,101 @@ describe('AutoComplete', () => {
|
|||
/>,
|
||||
);
|
||||
expect(errSpy).toHaveBeenCalledWith(
|
||||
'Warning: [antd: AutoComplete] `dropdownClassName` is deprecated. Please use `popupClassName` instead.',
|
||||
'Warning: [antd: AutoComplete] `dropdownClassName` is deprecated. Please use `classNames.popup.root` instead.',
|
||||
);
|
||||
expect(container.querySelector('.legacy')).toBeTruthy();
|
||||
|
||||
errSpy.mockRestore();
|
||||
});
|
||||
|
||||
it('deprecated popupClassName', () => {
|
||||
resetWarned();
|
||||
|
||||
const errSpy = jest.spyOn(console, 'error').mockImplementation(() => {});
|
||||
const { container } = render(
|
||||
<AutoComplete
|
||||
popupClassName="legacy"
|
||||
open
|
||||
options={[{ label: 'little', value: 'little' }]}
|
||||
searchValue="l"
|
||||
/>,
|
||||
);
|
||||
expect(errSpy).toHaveBeenCalledWith(
|
||||
'Warning: [antd: AutoComplete] `popupClassName` is deprecated. Please use `classNames.popup.root` instead.',
|
||||
);
|
||||
expect(container.querySelector('.legacy')).toBeTruthy();
|
||||
|
||||
errSpy.mockRestore();
|
||||
});
|
||||
|
||||
it('deprecated dropdownMatchSelectWidth', () => {
|
||||
resetWarned();
|
||||
|
||||
const errSpy = jest.spyOn(console, 'error').mockImplementation(() => {});
|
||||
render(
|
||||
<AutoComplete
|
||||
dropdownMatchSelectWidth
|
||||
open
|
||||
options={[{ label: 'little', value: 'little' }]}
|
||||
/>,
|
||||
);
|
||||
expect(errSpy).toHaveBeenCalledWith(
|
||||
'Warning: [antd: AutoComplete] `dropdownMatchSelectWidth` is deprecated. Please use `popupMatchSelectWidth` instead.',
|
||||
);
|
||||
|
||||
errSpy.mockRestore();
|
||||
});
|
||||
|
||||
it('deprecated dropdownStyle', () => {
|
||||
resetWarned();
|
||||
|
||||
const errSpy = jest.spyOn(console, 'error').mockImplementation(() => {});
|
||||
render(
|
||||
<AutoComplete
|
||||
dropdownStyle={{ color: 'red' }}
|
||||
open
|
||||
options={[{ label: 'little', value: 'little' }]}
|
||||
/>,
|
||||
);
|
||||
expect(errSpy).toHaveBeenCalledWith(
|
||||
'Warning: [antd: AutoComplete] `dropdownStyle` is deprecated. Please use `styles.popup.root` instead.',
|
||||
);
|
||||
|
||||
errSpy.mockRestore();
|
||||
});
|
||||
|
||||
it('deprecated dropdownRender', () => {
|
||||
resetWarned();
|
||||
|
||||
const errSpy = jest.spyOn(console, 'error').mockImplementation(() => {});
|
||||
render(
|
||||
<AutoComplete
|
||||
dropdownRender={(menu) => <div>{menu}</div>}
|
||||
open
|
||||
options={[{ label: 'little', value: 'little' }]}
|
||||
/>,
|
||||
);
|
||||
expect(errSpy).toHaveBeenCalledWith(
|
||||
'Warning: [antd: AutoComplete] `dropdownRender` is deprecated. Please use `popupRender` instead.',
|
||||
);
|
||||
|
||||
errSpy.mockRestore();
|
||||
});
|
||||
|
||||
it('deprecated onDropdownVisibleChange', () => {
|
||||
resetWarned();
|
||||
|
||||
const errSpy = jest.spyOn(console, 'error').mockImplementation(() => {});
|
||||
render(
|
||||
<AutoComplete
|
||||
onDropdownVisibleChange={() => {}}
|
||||
options={[{ label: 'little', value: 'little' }]}
|
||||
/>,
|
||||
);
|
||||
expect(errSpy).toHaveBeenCalledWith(
|
||||
'Warning: [antd: AutoComplete] `onDropdownVisibleChange` is deprecated. Please use `onOpenChange` instead.',
|
||||
);
|
||||
|
||||
errSpy.mockRestore();
|
||||
});
|
||||
});
|
||||
|
|
32
components/auto-complete/demo/_semantic.tsx
Normal file
32
components/auto-complete/demo/_semantic.tsx
Normal file
|
@ -0,0 +1,32 @@
|
|||
import React from 'react';
|
||||
import { AutoComplete } from 'antd';
|
||||
|
||||
import SelectSemanticTemplate from '../../../.dumi/components/SelectSemanticTemplate';
|
||||
|
||||
const mockVal = (str: string, repeat = 1) => ({
|
||||
value: str.repeat(repeat),
|
||||
label: str.repeat(repeat),
|
||||
});
|
||||
|
||||
const getPanelValue = (searchText: string) =>
|
||||
!searchText ? [] : [mockVal(searchText), mockVal(searchText, 2), mockVal(searchText, 3)];
|
||||
|
||||
const App: React.FC = () => {
|
||||
const [options, setOptions] = React.useState([
|
||||
{ value: 'aojunhao123', label: 'aojunhao123' },
|
||||
{ value: 'thinkasany', label: 'thinkasany' },
|
||||
]);
|
||||
|
||||
return (
|
||||
<SelectSemanticTemplate
|
||||
component={AutoComplete}
|
||||
componentName="AutoComplete"
|
||||
style={{ width: 200 }}
|
||||
options={options}
|
||||
onSearch={(text: string) => setOptions(getPanelValue(text))}
|
||||
placeholder="input here"
|
||||
/>
|
||||
);
|
||||
};
|
||||
|
||||
export default App;
|
|
@ -40,11 +40,10 @@ const options = [
|
|||
|
||||
const App: React.FC = () => (
|
||||
<AutoComplete
|
||||
popupClassName="certain-category-search-dropdown"
|
||||
classNames={{ popup: { root: 'certain-category-search-dropdown' } }}
|
||||
popupMatchSelectWidth={500}
|
||||
style={{ width: 250 }}
|
||||
options={options}
|
||||
size="large"
|
||||
>
|
||||
<Input.Search size="large" placeholder="input here" />
|
||||
</AutoComplete>
|
||||
|
|
|
@ -53,7 +53,6 @@ const App: React.FC = () => {
|
|||
options={options}
|
||||
onSelect={onSelect}
|
||||
onSearch={handleSearch}
|
||||
size="large"
|
||||
>
|
||||
<Input.Search size="large" placeholder="input here" enterButton />
|
||||
</AutoComplete>
|
||||
|
|
|
@ -48,12 +48,15 @@ Common props ref:[Common props](/docs/react/common-props)
|
|||
| backfill | If backfill selected item the input when using keyboard | boolean | false | |
|
||||
| children (for customize input element) | Customize input element | HTMLInputElement \| HTMLTextAreaElement \| React.ReactElement<InputProps> | <Input /> | |
|
||||
| children (for dataSource) | Data source to auto complete | React.ReactElement<OptionProps> \| Array<React.ReactElement<OptionProps>> | - | |
|
||||
| classNames | Semantic DOM class | [Record<SemanticDOM, string>](#semantic-dom) | - | 5.25.0 |
|
||||
| defaultActiveFirstOption | Whether active first option by default | boolean | true | |
|
||||
| defaultOpen | Initial open state of dropdown | boolean | - | |
|
||||
| defaultValue | Initial selected option | string | - | |
|
||||
| disabled | Whether disabled select | boolean | false | |
|
||||
| dropdownRender | Customize dropdown content | (menus: ReactNode) => ReactNode | - | 4.24.0 |
|
||||
| popupClassName | The className of dropdown menu | string | - | 4.23.0 |
|
||||
| ~~dropdownRender~~ | Customize dropdown content, use `popupRender` instead | (originNode: ReactNode) => ReactNode | - | 4.24.0 |
|
||||
| popupRender | Customize dropdown content | (originNode: ReactNode) => ReactNode | - | |
|
||||
| ~~dropdownStyle~~ | The style of dropdown menu, use `styles.popup.root` instead | CSSProperties | - | |
|
||||
| ~~popupClassName~~ | The className of dropdown menu, use `classNames.popup.root` instead | string | - | 4.23.0 |
|
||||
| popupMatchSelectWidth | Determine whether the dropdown menu and the select input are the same width. Default set `min-width` same as input. Will ignore when value less than select width. `false` will disable virtual scroll | boolean \| number | true | |
|
||||
| filterOption | If true, filter options by input, if function, filter options against it. The function will receive two arguments, `inputValue` and `option`, if the function returns true, the option will be included in the filtered set; Otherwise, it will be excluded | boolean \| function(inputValue, option) | true | |
|
||||
| getPopupContainer | Parent node of the dropdown. Default to body, if you encountered positioning problems during scroll, try changing to the scrollable area and position relative to it. [Example](https://codesandbox.io/s/4j168r7jw0) | function(triggerNode) | () => document.body | |
|
||||
|
@ -64,11 +67,13 @@ Common props ref:[Common props](/docs/react/common-props)
|
|||
| status | Set validation status | 'error' \| 'warning' | - | 4.19.0 |
|
||||
| size | The size of the input box | `large` \| `middle` \| `small` | - | |
|
||||
| value | Selected option | string | - | |
|
||||
| styles | Semantic DOM style | [Record<SemanticDOM, CSSProperties>](#semantic-dom) | - | 5.25.0 |
|
||||
| variant | Variants of input | `outlined` \| `borderless` \| `filled` | `outlined` | 5.13.0 |
|
||||
| virtual | Disable virtual scroll when set to false | boolean | true | 4.1.0 |
|
||||
| onBlur | Called when leaving the component | function() | - | |
|
||||
| onChange | Called when selecting an option or changing an input value | function(value) | - | |
|
||||
| onDropdownVisibleChange | Call when dropdown open | function(open) | - | |
|
||||
| ~~onDropdownVisibleChange~~ | Called when dropdown open, use `onOpenChange` instead | (open: boolean) => void | - | |
|
||||
| onOpenChange | Called when dropdown open | (open: boolean) => void | - | |
|
||||
| onFocus | Called when entering the component | function() | - | |
|
||||
| onSearch | Called when searching items | function(value) | - | |
|
||||
| onSelect | Called when a option is selected. param is option's value and option instance | function(value, option) | - | |
|
||||
|
@ -83,6 +88,10 @@ Common props ref:[Common props](/docs/react/common-props)
|
|||
| blur() | Remove focus | |
|
||||
| focus() | Get focus | |
|
||||
|
||||
## Semantic DOM
|
||||
|
||||
<code src="./demo/_semantic.tsx" simplify="true"></code>
|
||||
|
||||
## Design Token
|
||||
|
||||
<ComponentTokenTable component="Select"></ComponentTokenTable>
|
||||
|
|
|
@ -49,12 +49,15 @@ demo:
|
|||
| backfill | 使用键盘选择选项的时候把选中项回填到输入框中 | boolean | false | |
|
||||
| children (自动完成的数据源) | 自动完成的数据源,不能和自定义输入框同时配置 | React.ReactElement<OptionProps> \| Array<React.ReactElement<OptionProps>> | - | |
|
||||
| children (自定义输入框) | 自定义输入框,不能和自动完成的数据源同时配置 | HTMLInputElement \| HTMLTextAreaElement \| React.ReactElement<InputProps> | <Input /> | |
|
||||
| classNames | 语义化结构 class | [Record<SemanticDOM, string>](#semantic-dom) | - | 5.25.0 |
|
||||
| defaultActiveFirstOption | 是否默认高亮第一个选项 | boolean | true | |
|
||||
| defaultOpen | 是否默认展开下拉菜单 | boolean | - | |
|
||||
| defaultValue | 指定默认选中的条目 | string | - | |
|
||||
| disabled | 是否禁用 | boolean | false | |
|
||||
| dropdownRender | 自定义下拉框内容 | (menus: ReactNode) => ReactNode | - | 4.24.0 |
|
||||
| popupClassName | 下拉菜单的 className 属性 | string | - | 4.23.0 |
|
||||
| ~~dropdownRender~~ | 自定义下拉框内容,使用 `popupRender` 替换 | (originNode: ReactNode) => ReactNode | - | 4.24.0 |
|
||||
| popupRender | 自定义下拉框内容 | (originNode: ReactNode) => ReactNode | - | |
|
||||
| ~~popupClassName~~ | 下拉菜单的 className 属性,使用 `classNames.popup.root` 替换 | string | - | 4.23.0 |
|
||||
| ~~dropdownStyle~~ | 下拉菜单的 style 属性,使用 `styles.popup.root` 替换 | CSSProperties | - | |
|
||||
| popupMatchSelectWidth | 下拉菜单和选择器同宽。默认将设置 `min-width`,当值小于选择框宽度时会被忽略。false 时会关闭虚拟滚动 | boolean \| number | true | |
|
||||
| filterOption | 是否根据输入项进行筛选。当其为一个函数时,会接收 `inputValue` `option` 两个参数,当 `option` 符合筛选条件时,应返回 true,反之则返回 false | boolean \| function(inputValue, option) | true | |
|
||||
| getPopupContainer | 菜单渲染父节点。默认渲染到 body 上,如果你遇到菜单滚动定位问题,试试修改为滚动的区域,并相对其定位。[示例](https://codesandbox.io/s/4j168r7jw0) | function(triggerNode) | () => document.body | |
|
||||
|
@ -64,12 +67,14 @@ demo:
|
|||
| placeholder | 输入框提示 | string | - | |
|
||||
| status | 设置校验状态 | 'error' \| 'warning' | - | 4.19.0 |
|
||||
| size | 控件大小 | `large` \| `middle` \| `small` | - | |
|
||||
| styles | 语义化结构 style | [Record<SemanticDOM, CSSProperties>](#semantic-dom) | - | 5.25.0 |
|
||||
| value | 指定当前选中的条目 | string | - | |
|
||||
| variant | 形态变体 | `outlined` \| `borderless` \| `filled` | `outlined` | 5.13.0 |
|
||||
| virtual | 设置 false 时关闭虚拟滚动 | boolean | true | 4.1.0 |
|
||||
| onBlur | 失去焦点时的回调 | function() | - | |
|
||||
| onChange | 选中 option,或 input 的 value 变化时,调用此函数 | function(value) | - | |
|
||||
| onDropdownVisibleChange | 展开下拉菜单的回调 | function(open) | - | |
|
||||
| ~~onDropdownVisibleChange~~ | 展开下拉菜单的回调,使用 `onOpenChange` 替换 | (open: boolean) => void | - | |
|
||||
| onOpenChange | 展开下拉菜单的回调 | (open: boolean) => void | - | |
|
||||
| onFocus | 获得焦点时的回调 | function() | - | |
|
||||
| onSearch | 搜索补全项的时候调用 | function(value) | - | |
|
||||
| onSelect | 被选中时调用,参数为选中项的 value 值 | function(value, option) | - | |
|
||||
|
@ -84,6 +89,10 @@ demo:
|
|||
| blur() | 移除焦点 | |
|
||||
| focus() | 获取焦点 | |
|
||||
|
||||
## Semantic DOM
|
||||
|
||||
<code src="./demo/_semantic.tsx" simplify="true"></code>
|
||||
|
||||
## 主题变量(Design Token)
|
||||
|
||||
<ComponentTokenTable component="Select"></ComponentTokenTable>
|
||||
|
|
|
@ -127,7 +127,7 @@ const AvatarGroup: React.FC<AvatarGroupProps> = (props) => {
|
|||
};
|
||||
|
||||
childrenShow.push(
|
||||
<Popover key="avatar-popover-key" destroyTooltipOnHide {...mergeProps}>
|
||||
<Popover key="avatar-popover-key" destroyOnClose {...mergeProps}>
|
||||
<Avatar style={mergeStyle}>{`+${numOfChildren - mergeCount}`}</Avatar>
|
||||
</Popover>,
|
||||
);
|
||||
|
|
|
@ -508,9 +508,46 @@ describe('Button', () => {
|
|||
const { getByRole } = render(
|
||||
<Button href="https://example.com" onClick={handleClick}>
|
||||
Link
|
||||
</Button>
|
||||
</Button>,
|
||||
);
|
||||
fireEvent.click(getByRole('link'));
|
||||
expect(handleClick).toHaveBeenCalled();
|
||||
});
|
||||
|
||||
it('ConfigProvider support button variant', () => {
|
||||
const { container } = render(
|
||||
<ConfigProvider button={{ variant: 'dashed', color: 'blue' }}>
|
||||
<Button>Button</Button>
|
||||
</ConfigProvider>,
|
||||
);
|
||||
|
||||
expect(container.firstChild).toHaveClass('ant-btn-variant-dashed');
|
||||
expect(container.firstChild).toHaveClass('ant-btn-color-blue');
|
||||
});
|
||||
|
||||
it('should show the component internal properties', () => {
|
||||
const { container } = render(
|
||||
<ConfigProvider button={{ variant: 'dashed', color: 'blue' }}>
|
||||
<Button variant="filled" color="green">
|
||||
Button
|
||||
</Button>
|
||||
</ConfigProvider>,
|
||||
);
|
||||
|
||||
expect(container.firstChild).toHaveClass('ant-btn-variant-filled');
|
||||
expect(container.firstChild).toHaveClass('ant-btn-color-green');
|
||||
});
|
||||
|
||||
it('button type win the context', () => {
|
||||
const { container } = render(
|
||||
<ConfigProvider button={{ variant: 'dashed', color: 'green' }}>
|
||||
<Button type="primary" danger>
|
||||
Button
|
||||
</Button>
|
||||
</ConfigProvider>,
|
||||
);
|
||||
|
||||
expect(container.querySelector('.ant-btn-variant-solid')).toBeTruthy();
|
||||
expect(container.querySelector('.ant-btn-color-dangerous')).toBeTruthy();
|
||||
});
|
||||
});
|
||||
|
|
|
@ -5,7 +5,7 @@ import { useComposeRef } from 'rc-util/lib/ref';
|
|||
|
||||
import { devUseWarning } from '../_util/warning';
|
||||
import Wave from '../_util/wave';
|
||||
import { useComponentConfig } from '../config-provider/context';
|
||||
import { ConfigContext, useComponentConfig } from '../config-provider/context';
|
||||
import DisabledContext from '../config-provider/DisabledContext';
|
||||
import useSize from '../config-provider/hooks/useSize';
|
||||
import type { SizeType } from '../config-provider/SizeContext';
|
||||
|
@ -127,20 +127,31 @@ const InternalCompoundedButton = React.forwardRef<
|
|||
// https://github.com/ant-design/ant-design/issues/47605
|
||||
// Compatible with original `type` behavior
|
||||
const mergedType = type || 'default';
|
||||
const { button } = React.useContext(ConfigContext);
|
||||
|
||||
const [mergedColor, mergedVariant] = useMemo<ColorVariantPairType>(() => {
|
||||
// >>>>> Local
|
||||
// Color & Variant
|
||||
if (color && variant) {
|
||||
return [color, variant];
|
||||
}
|
||||
|
||||
const colorVariantPair = ButtonTypeMap[mergedType] || [];
|
||||
|
||||
if (danger) {
|
||||
return ['danger', colorVariantPair[1]];
|
||||
// Sugar syntax
|
||||
if (type || danger) {
|
||||
const colorVariantPair = ButtonTypeMap[mergedType] || [];
|
||||
if (danger) {
|
||||
return ['danger', colorVariantPair[1]];
|
||||
}
|
||||
return colorVariantPair;
|
||||
}
|
||||
|
||||
return colorVariantPair;
|
||||
}, [type, color, variant, danger]);
|
||||
// >>> Context fallback
|
||||
if (button?.color && button?.variant) {
|
||||
return [button.color, button.variant];
|
||||
}
|
||||
|
||||
return ['default', 'outlined'];
|
||||
}, [type, color, variant, danger, button?.variant, button?.color]);
|
||||
|
||||
const isDanger = mergedColor === 'danger';
|
||||
const mergedColorText = isDanger ? 'dangerous' : mergedColor;
|
||||
|
@ -291,9 +302,10 @@ const InternalCompoundedButton = React.forwardRef<
|
|||
cssVarCls,
|
||||
{
|
||||
[`${prefixCls}-${shape}`]: shape !== 'default' && shape,
|
||||
// line(253 - 254): Compatible with versions earlier than 5.21.0
|
||||
// Compatible with versions earlier than 5.21.0
|
||||
[`${prefixCls}-${mergedType}`]: mergedType,
|
||||
[`${prefixCls}-dangerous`]: danger,
|
||||
|
||||
[`${prefixCls}-color-${mergedColorText}`]: mergedColorText,
|
||||
[`${prefixCls}-variant-${mergedVariant}`]: mergedVariant,
|
||||
[`${prefixCls}-${sizeCls}`]: sizeCls,
|
||||
|
|
|
@ -93,13 +93,11 @@ describe('Cascader', () => {
|
|||
});
|
||||
|
||||
it('popup correctly when panel is open', () => {
|
||||
const onPopupVisibleChange = jest.fn();
|
||||
const { container } = render(
|
||||
<Cascader options={options} onPopupVisibleChange={onPopupVisibleChange} />,
|
||||
);
|
||||
const onOpenChange = jest.fn();
|
||||
const { container } = render(<Cascader options={options} onOpenChange={onOpenChange} />);
|
||||
toggleOpen(container);
|
||||
expect(isOpen(container)).toBeTruthy();
|
||||
expect(onPopupVisibleChange).toHaveBeenCalledWith(true);
|
||||
expect(onOpenChange).toHaveBeenCalledWith(true);
|
||||
});
|
||||
|
||||
it('support controlled mode', () => {
|
||||
|
@ -548,13 +546,87 @@ describe('Cascader', () => {
|
|||
const errSpy = jest.spyOn(console, 'error').mockImplementation(() => {});
|
||||
const { container } = render(<Cascader dropdownClassName="legacy" open />);
|
||||
expect(errSpy).toHaveBeenCalledWith(
|
||||
'Warning: [antd: Cascader] `dropdownClassName` is deprecated. Please use `popupClassName` instead.',
|
||||
'Warning: [antd: Cascader] `dropdownClassName` is deprecated. Please use `classNames.popup.root` instead.',
|
||||
);
|
||||
expect(container.querySelector('.legacy')).toBeTruthy();
|
||||
|
||||
errSpy.mockRestore();
|
||||
});
|
||||
|
||||
it('legacy dropdownStyle', () => {
|
||||
resetWarned();
|
||||
|
||||
const errSpy = jest.spyOn(console, 'error').mockImplementation(() => {});
|
||||
const customStyle = { background: 'red' };
|
||||
const { container } = render(<Cascader dropdownStyle={customStyle} open />);
|
||||
expect(errSpy).toHaveBeenCalledWith(
|
||||
'Warning: [antd: Cascader] `dropdownStyle` is deprecated. Please use `styles.popup.root` instead.',
|
||||
);
|
||||
expect(container.querySelector('.ant-select-dropdown')?.getAttribute('style')).toContain(
|
||||
'background: red',
|
||||
);
|
||||
|
||||
errSpy.mockRestore();
|
||||
});
|
||||
|
||||
it('legacy dropdownRender', () => {
|
||||
resetWarned();
|
||||
|
||||
const errSpy = jest.spyOn(console, 'error').mockImplementation(() => {});
|
||||
const customContent = <div className="custom-dropdown-content">Custom Content</div>;
|
||||
const dropdownRender = (menu: React.ReactElement) => (
|
||||
<>
|
||||
{menu}
|
||||
{customContent}
|
||||
</>
|
||||
);
|
||||
|
||||
const { container } = render(<Cascader dropdownRender={dropdownRender} open />);
|
||||
expect(errSpy).toHaveBeenCalledWith(
|
||||
'Warning: [antd: Cascader] `dropdownRender` is deprecated. Please use `popupRender` instead.',
|
||||
);
|
||||
expect(container.querySelector('.custom-dropdown-content')).toBeTruthy();
|
||||
|
||||
errSpy.mockRestore();
|
||||
});
|
||||
|
||||
it('legacy dropdownMenuColumnStyle', () => {
|
||||
resetWarned();
|
||||
|
||||
const errSpy = jest.spyOn(console, 'error').mockImplementation(() => {});
|
||||
const columnStyle = { background: 'red' };
|
||||
const { getByRole } = render(
|
||||
<Cascader
|
||||
options={[{ label: 'test', value: 1 }]}
|
||||
dropdownMenuColumnStyle={columnStyle}
|
||||
open
|
||||
/>,
|
||||
);
|
||||
expect(errSpy).toHaveBeenCalledWith(
|
||||
'Warning: [antd: Cascader] `dropdownMenuColumnStyle` is deprecated. Please use `popupMenuColumnStyle` instead.',
|
||||
);
|
||||
const menuColumn = getByRole('menuitemcheckbox');
|
||||
expect(menuColumn.style.background).toBe('red');
|
||||
|
||||
errSpy.mockRestore();
|
||||
});
|
||||
|
||||
it('legacy onDropdownVisibleChange', () => {
|
||||
resetWarned();
|
||||
|
||||
const errSpy = jest.spyOn(console, 'error').mockImplementation(() => {});
|
||||
const onDropdownVisibleChange = jest.fn();
|
||||
const { container } = render(<Cascader onDropdownVisibleChange={onDropdownVisibleChange} />);
|
||||
expect(errSpy).toHaveBeenCalledWith(
|
||||
'Warning: [antd: Cascader] `onDropdownVisibleChange` is deprecated. Please use `onOpenChange` instead.',
|
||||
);
|
||||
|
||||
toggleOpen(container);
|
||||
expect(onDropdownVisibleChange).toHaveBeenCalledWith(true);
|
||||
|
||||
errSpy.mockRestore();
|
||||
});
|
||||
|
||||
it('should support showCheckedStrategy child', () => {
|
||||
const multipleOptions = [
|
||||
{
|
||||
|
|
78
components/cascader/demo/_semantic.tsx
Normal file
78
components/cascader/demo/_semantic.tsx
Normal file
|
@ -0,0 +1,78 @@
|
|||
import React from 'react';
|
||||
import { Cascader } from 'antd';
|
||||
|
||||
import SemanticPreview from '../../../.dumi/components/SemanticPreview';
|
||||
import useLocale from '../../../.dumi/hooks/useLocale';
|
||||
|
||||
const locales = {
|
||||
cn: {
|
||||
root: '根元素',
|
||||
'popup.root': '弹出菜单元素',
|
||||
},
|
||||
en: {
|
||||
root: 'Root element',
|
||||
'popup.root': 'Popup element',
|
||||
},
|
||||
};
|
||||
const options = [
|
||||
{
|
||||
value: 'contributors',
|
||||
label: 'contributors',
|
||||
children: [
|
||||
{
|
||||
value: 'aojunhao123',
|
||||
label: 'aojunhao123',
|
||||
},
|
||||
{
|
||||
value: 'thinkasany',
|
||||
label: 'thinkasany',
|
||||
},
|
||||
],
|
||||
},
|
||||
];
|
||||
|
||||
const Block = (props: any) => {
|
||||
const divRef = React.useRef<HTMLDivElement>(null);
|
||||
const [value, setValue] = React.useState<string[]>(['contributors', 'aojunhao123']);
|
||||
const onChange = (newValue: string[]) => {
|
||||
setValue(newValue);
|
||||
};
|
||||
return (
|
||||
<div ref={divRef} style={{ marginBottom: 60 }}>
|
||||
<Cascader
|
||||
{...props}
|
||||
open
|
||||
styles={{
|
||||
popup: {
|
||||
root: {
|
||||
zIndex: 1,
|
||||
height: 70,
|
||||
},
|
||||
},
|
||||
}}
|
||||
getPopupContainer={() => divRef.current}
|
||||
value={value}
|
||||
onChange={onChange}
|
||||
options={options}
|
||||
placement="bottomLeft"
|
||||
/>
|
||||
</div>
|
||||
);
|
||||
};
|
||||
const App: React.FC = () => {
|
||||
const [locale] = useLocale(locales);
|
||||
|
||||
return (
|
||||
<SemanticPreview
|
||||
componentName="Cascader"
|
||||
semantics={[
|
||||
{ name: 'root', desc: locale.root, version: '5.25.0' },
|
||||
{ name: 'popup.root', desc: locale['popup.root'], version: '5.25.0' },
|
||||
]}
|
||||
>
|
||||
<Block />
|
||||
</SemanticPreview>
|
||||
);
|
||||
};
|
||||
|
||||
export default App;
|
|
@ -42,7 +42,7 @@ const options: Option[] = [
|
|||
},
|
||||
];
|
||||
|
||||
const dropdownRender = (menus: React.ReactNode) => (
|
||||
const popupRender = (menus: React.ReactNode) => (
|
||||
<div>
|
||||
{menus}
|
||||
<Divider style={{ margin: 0 }} />
|
||||
|
@ -51,7 +51,7 @@ const dropdownRender = (menus: React.ReactNode) => (
|
|||
);
|
||||
|
||||
const App: React.FC = () => (
|
||||
<Cascader options={options} dropdownRender={dropdownRender} placeholder="Please select" />
|
||||
<Cascader options={options} popupRender={popupRender} placeholder="Please select" />
|
||||
);
|
||||
|
||||
export default App;
|
||||
|
|
|
@ -55,13 +55,16 @@ Common props ref:[Common props](/docs/react/common-props)
|
|||
| autoFocus | If get focus when component mounted | 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 | - | |
|
||||
| classNames | Semantic DOM class | [Record<SemanticDOM, string>](#semantic-dom) | - | 5.25.0 |
|
||||
| defaultOpen | Initial visible of cascader popup | boolean | - | |
|
||||
| defaultValue | Initial selected value | string\[] \| number\[] | \[] | |
|
||||
| disabled | Whether disabled select | boolean | false | |
|
||||
| displayRender | The render function of displaying selected options | (label, selectedOptions) => ReactNode | label => label.join(`/`) | `multiple`: 4.18.0 |
|
||||
| tagRender | Custom render function for tags in `multiple` mode | (label: string, onClose: function, value: string) => ReactNode | - | |
|
||||
| popupClassName | The additional className of popup overlay | string | - | 4.23.0 |
|
||||
| dropdownRender | Customize dropdown content | (menus: ReactNode) => ReactNode | - | 4.4.0 |
|
||||
| ~~popupClassName~~ | The additional className of popup overlay, use `classNames.popup.root` instead | string | - | 4.23.0 |
|
||||
| ~~dropdownRender~~ | Customize dropdown content, use `popupRender` instead | (menus: ReactNode) => ReactNode | - | 4.4.0 |
|
||||
| popupRender | Customize dropdown content | (menus: ReactNode) => ReactNode | - | |
|
||||
| ~~dropdownStyle~~ | The style of dropdown menu, use `styles.popup.root` instead | CSSProperties | - | |
|
||||
| expandIcon | Customize the current item expand icon | ReactNode | - | 4.4.0 |
|
||||
| expandTrigger | expand current item when click or hover, one of `click` `hover` | string | `click` | |
|
||||
| fieldNames | Custom field name for label and value and children | object | { label: `label`, value: `value`, children: `children` } | |
|
||||
|
@ -79,18 +82,20 @@ Common props ref:[Common props](/docs/react/common-props)
|
|||
| showSearch | Whether show search input in single mode | boolean \| [Object](#showsearch) | false | |
|
||||
| size | The input size | `large` \| `middle` \| `small` | - | |
|
||||
| status | Set validation status | 'error' \| 'warning' | - | 4.19.0 |
|
||||
| style | The additional style | CSSProperties | - | |
|
||||
| styles | Semantic DOM style | [Record<SemanticDOM, CSSProperties>](#semantic-dom) | - | 5.25.0 |
|
||||
| suffixIcon | The custom suffix icon | ReactNode | - | |
|
||||
| value | The selected value | string\[] \| number\[] | - | |
|
||||
| variant | Variants of selector | `outlined` \| `borderless` \| `filled` \| `underlined` | `outlined` | 5.13.0 \| `underlined`: 5.24.0 |
|
||||
| onChange | Callback when finishing cascader select | (value, selectedOptions) => void | - | |
|
||||
| onDropdownVisibleChange | Callback when popup shown or hidden | (value) => void | - | 4.17.0 |
|
||||
| ~~onDropdownVisibleChange~~ | Callback when popup shown or hidden, use `onOpenChange` instead | (value) => void | - | 4.17.0 |
|
||||
| onOpenChange | Callback when popup shown or hidden | (value) => void | - | |
|
||||
| multiple | Support multiple or not | boolean | - | 4.17.0 |
|
||||
| removeIcon | The custom remove icon | ReactNode | - | |
|
||||
| showCheckedStrategy | The way show selected item in box. ** `SHOW_CHILD`: ** just show child treeNode. **`Cascader.SHOW_PARENT`:** just show parent treeNode (when all child treeNode under the parent treeNode are checked) | `Cascader.SHOW_PARENT` \| `Cascader.SHOW_CHILD` | `Cascader.SHOW_PARENT` | 4.20.0 |
|
||||
| searchValue | Set search value, Need work with `showSearch` | string | - | 4.17.0 |
|
||||
| onSearch | The callback function triggered when input changed | (search: string) => void | - | 4.17.0 |
|
||||
| dropdownMenuColumnStyle | The style of the drop-down menu column | CSSProperties | - | |
|
||||
| ~~dropdownMenuColumnStyle~~ | The style of the drop-down menu column, use `popupMenuColumnStyle` instead | CSSProperties | - | |
|
||||
| popupMenuColumnStyle | The style of the drop-down menu column | CSSProperties | - | |
|
||||
| loadingIcon | The appearance of lazy loading (now is useless) | ReactNode | - | |
|
||||
| optionRender | Customize the rendering dropdown options | (option: Option) => React.ReactNode | - | 5.16.0 |
|
||||
|
||||
|
@ -126,6 +131,10 @@ interface Option {
|
|||
| blur() | Remove focus | |
|
||||
| focus() | Get focus | |
|
||||
|
||||
## Semantic DOM
|
||||
|
||||
<code src="./demo/_semantic.tsx" simplify="true"></code>
|
||||
|
||||
## Design Token
|
||||
|
||||
<ComponentTokenTable component="Cascader"></ComponentTokenTable>
|
||||
|
|
|
@ -1,5 +1,5 @@
|
|||
import * as React from 'react';
|
||||
import classNames from 'classnames';
|
||||
import cls from 'classnames';
|
||||
import type {
|
||||
BaseOptionType,
|
||||
DefaultOptionType,
|
||||
|
@ -50,6 +50,9 @@ export type FieldNamesType = FieldNames;
|
|||
|
||||
export type FilledFieldNamesType = Required<FieldNamesType>;
|
||||
|
||||
type SemanticName = 'root';
|
||||
type PopupSemantic = 'root';
|
||||
|
||||
const { SHOW_CHILD, SHOW_PARENT } = RcCascader;
|
||||
|
||||
function highlightKeyword(str: string, lowerKeyword: string, prefixCls?: string) {
|
||||
|
@ -127,14 +130,32 @@ export interface CascaderProps<
|
|||
autoClearSearchValue?: boolean;
|
||||
|
||||
rootClassName?: string;
|
||||
/** @deprecated Please use `classNames.popup.root` instead */
|
||||
popupClassName?: string;
|
||||
/** @deprecated Please use `popupClassName` instead */
|
||||
/** @deprecated Please use `classNames.popup.root` instead */
|
||||
dropdownClassName?: string;
|
||||
/** @deprecated Please use `styles.popup.root` instead */
|
||||
dropdownStyle?: React.CSSProperties;
|
||||
/** @deprecated Please use `popupRender` instead */
|
||||
dropdownRender?: (menu: React.ReactElement) => React.ReactElement;
|
||||
popupRender?: (menu: React.ReactElement) => React.ReactElement;
|
||||
/** @deprecated Please use `popupMenuColumnStyle` instead */
|
||||
dropdownMenuColumnStyle?: React.CSSProperties;
|
||||
popupMenuColumnStyle?: React.CSSProperties;
|
||||
/** @deprecated Please use `onOpenChange` instead */
|
||||
onDropdownVisibleChange?: (visible: boolean) => void;
|
||||
onOpenChange?: (visible: boolean) => void;
|
||||
/**
|
||||
* @since 5.13.0
|
||||
* @default "outlined"
|
||||
*/
|
||||
variant?: Variant;
|
||||
classNames?: Partial<Record<SemanticName, string>> & {
|
||||
popup?: Partial<Record<PopupSemantic, string>>;
|
||||
};
|
||||
styles?: Partial<Record<SemanticName, React.CSSProperties>> & {
|
||||
popup?: Partial<Record<PopupSemantic, React.CSSProperties>>;
|
||||
};
|
||||
}
|
||||
export type CascaderAutoProps<
|
||||
OptionType extends DefaultOptionType = DefaultOptionType,
|
||||
|
@ -173,6 +194,15 @@ const Cascader = React.forwardRef<CascaderRef, CascaderProps<any>>((props, ref)
|
|||
builtinPlacements,
|
||||
style,
|
||||
variant: customVariant,
|
||||
dropdownRender,
|
||||
onDropdownVisibleChange,
|
||||
dropdownMenuColumnStyle,
|
||||
popupRender,
|
||||
dropdownStyle,
|
||||
popupMenuColumnStyle,
|
||||
onOpenChange,
|
||||
styles,
|
||||
classNames,
|
||||
...rest
|
||||
} = props;
|
||||
|
||||
|
@ -183,6 +213,8 @@ const Cascader = React.forwardRef<CascaderRef, CascaderProps<any>>((props, ref)
|
|||
getPopupContainer: getContextPopupContainer,
|
||||
className: contextClassName,
|
||||
style: contextStyle,
|
||||
classNames: contextClassNames,
|
||||
styles: contextStyles,
|
||||
} = useComponentConfig('cascader');
|
||||
|
||||
const { popupOverflow } = React.useContext(ConfigContext);
|
||||
|
@ -200,15 +232,25 @@ const Cascader = React.forwardRef<CascaderRef, CascaderProps<any>>((props, ref)
|
|||
if (process.env.NODE_ENV !== 'production') {
|
||||
const warning = devUseWarning('Cascader');
|
||||
|
||||
warning.deprecated(!dropdownClassName, 'dropdownClassName', 'popupClassName');
|
||||
// v5 deprecated dropdown api
|
||||
const deprecatedProps = {
|
||||
dropdownClassName: 'classNames.popup.root',
|
||||
dropdownStyle: 'styles.popup.root',
|
||||
dropdownRender: 'popupRender',
|
||||
dropdownMenuColumnStyle: 'popupMenuColumnStyle',
|
||||
onDropdownVisibleChange: 'onOpenChange',
|
||||
bordered: 'variant',
|
||||
};
|
||||
|
||||
Object.entries(deprecatedProps).forEach(([oldProp, newProp]) => {
|
||||
warning.deprecated(!(oldProp in props), oldProp, newProp);
|
||||
});
|
||||
|
||||
warning(
|
||||
!('showArrow' in props),
|
||||
'deprecated',
|
||||
'`showArrow` is deprecated which will be removed in next major version. It will be a default behavior, you can hide it by setting `suffixIcon` to null.',
|
||||
);
|
||||
|
||||
warning.deprecated(!('bordered' in props), 'bordered', 'variant');
|
||||
}
|
||||
|
||||
// ==================== Prefix =====================
|
||||
|
@ -235,19 +277,26 @@ const Cascader = React.forwardRef<CascaderRef, CascaderProps<any>>((props, ref)
|
|||
);
|
||||
|
||||
// =================== Dropdown ====================
|
||||
const mergedDropdownClassName = classNames(
|
||||
popupClassName || dropdownClassName,
|
||||
const mergedPopupClassName = cls(
|
||||
classNames?.popup?.root || contextClassNames.popup?.root || popupClassName || dropdownClassName,
|
||||
`${cascaderPrefixCls}-dropdown`,
|
||||
{
|
||||
[`${cascaderPrefixCls}-dropdown-rtl`]: mergedDirection === 'rtl',
|
||||
},
|
||||
rootClassName,
|
||||
rootCls,
|
||||
contextClassNames.root,
|
||||
classNames?.root,
|
||||
cascaderRootCls,
|
||||
hashId,
|
||||
cssVarCls,
|
||||
);
|
||||
|
||||
const mergedPopupRender = popupRender || dropdownRender;
|
||||
const mergedPopupMenuColumnStyle = popupMenuColumnStyle || dropdownMenuColumnStyle;
|
||||
const mergedOnOpenChange = onOpenChange || onDropdownVisibleChange;
|
||||
const mergedPopupStyle = styles?.popup?.root || contextStyles.popup?.root || dropdownStyle;
|
||||
|
||||
// ==================== Search =====================
|
||||
const mergedShowSearch = React.useMemo(() => {
|
||||
if (!showSearch) {
|
||||
|
@ -304,13 +353,13 @@ const Cascader = React.forwardRef<CascaderRef, CascaderProps<any>>((props, ref)
|
|||
const mergedAllowClear = allowClear === true ? { clearIcon } : allowClear;
|
||||
|
||||
// ============================ zIndex ============================
|
||||
const [zIndex] = useZIndex('SelectLike', restProps.dropdownStyle?.zIndex as number);
|
||||
const [zIndex] = useZIndex('SelectLike', mergedPopupStyle?.zIndex as number);
|
||||
|
||||
// ==================== Render =====================
|
||||
const renderNode = (
|
||||
<RcCascader
|
||||
prefixCls={prefixCls}
|
||||
className={classNames(
|
||||
className={cls(
|
||||
!customizePrefixCls && cascaderPrefixCls,
|
||||
{
|
||||
[`${prefixCls}-lg`]: mergedSize === 'large',
|
||||
|
@ -324,13 +373,15 @@ const Cascader = React.forwardRef<CascaderRef, CascaderProps<any>>((props, ref)
|
|||
contextClassName,
|
||||
className,
|
||||
rootClassName,
|
||||
classNames?.root,
|
||||
contextClassNames.root,
|
||||
rootCls,
|
||||
cascaderRootCls,
|
||||
hashId,
|
||||
cssVarCls,
|
||||
)}
|
||||
disabled={mergedDisabled}
|
||||
style={{ ...contextStyle, ...style }}
|
||||
style={{ ...contextStyles.root, ...styles?.root, ...contextStyle, ...style }}
|
||||
{...(restProps as any)}
|
||||
builtinPlacements={mergedBuiltinPlacements(builtinPlacements, popupOverflow)}
|
||||
direction={mergedDirection}
|
||||
|
@ -343,9 +394,12 @@ const Cascader = React.forwardRef<CascaderRef, CascaderProps<any>>((props, ref)
|
|||
removeIcon={removeIcon}
|
||||
loadingIcon={loadingIcon}
|
||||
checkable={checkable}
|
||||
dropdownClassName={mergedDropdownClassName}
|
||||
dropdownClassName={mergedPopupClassName}
|
||||
dropdownPrefixCls={customizePrefixCls || cascaderPrefixCls}
|
||||
dropdownStyle={{ ...restProps.dropdownStyle, zIndex }}
|
||||
dropdownStyle={{ ...mergedPopupStyle, zIndex }}
|
||||
dropdownRender={mergedPopupRender}
|
||||
dropdownMenuColumnStyle={mergedPopupMenuColumnStyle}
|
||||
onOpenChange={mergedOnOpenChange}
|
||||
choiceTransitionName={getTransitionName(rootPrefixCls, '', choiceTransitionName)}
|
||||
transitionName={getTransitionName(rootPrefixCls, 'slide-up', transitionName)}
|
||||
getPopupContainer={getPopupContainer || getContextPopupContainer}
|
||||
|
|
|
@ -56,13 +56,16 @@ demo:
|
|||
| autoFocus | 自动获取焦点 | boolean | false | |
|
||||
| changeOnSelect | 单选时生效(multiple 下始终都可以选择),点选每级菜单选项值都会发生变化。 | boolean | false | |
|
||||
| className | 自定义类名 | string | - | |
|
||||
| classNames | 语义化结构 class | [Record<SemanticDOM, string>](#semantic-dom) | - | 5.25.0 |
|
||||
| defaultOpen | 是否默认展示浮层 | boolean | - | |
|
||||
| defaultValue | 默认的选中项 | string\[] \| number\[] | \[] | |
|
||||
| disabled | 禁用 | boolean | false | |
|
||||
| displayRender | 选择后展示的渲染函数 | (label, selectedOptions) => ReactNode | label => label.join(`/`) | `multiple`: 4.18.0 |
|
||||
| tagRender | 自定义 tag 内容 render,仅在多选时生效 | ({ label: string, onClose: function, value: string }) => ReactNode | - | |
|
||||
| popupClassName | 自定义浮层类名 | string | - | 4.23.0 |
|
||||
| dropdownRender | 自定义下拉框内容 | (menus: ReactNode) => ReactNode | - | 4.4.0 |
|
||||
| ~~popupClassName~~ | 自定义浮层类名,使用 `classNames.popup.root` 替换 | string | - | 4.23.0 |
|
||||
| ~~dropdownRender~~ | 自定义下拉框内容,请使用 `popupRender` 替换 | (menus: ReactNode) => ReactNode | - | 4.4.0 |
|
||||
| popupRender | 自定义下拉框内容 | (menus: ReactNode) => ReactNode | - | |
|
||||
| ~~dropdownStyle~~ | 下拉菜单的 style 属性,使用 `styles.popup.root` 替换 | CSSProperties | - | |
|
||||
| expandIcon | 自定义次级菜单展开图标 | ReactNode | - | 4.4.0 |
|
||||
| expandTrigger | 次级菜单的展开方式,可选 'click' 和 'hover' | string | `click` | |
|
||||
| fieldNames | 自定义 options 中 label value children 的字段 | object | { label: `label`, value: `value`, children: `children` } | |
|
||||
|
@ -80,18 +83,20 @@ demo:
|
|||
| showSearch | 在选择框中显示搜索框 | boolean \| [Object](#showsearch) | false | |
|
||||
| size | 输入框大小 | `large` \| `middle` \| `small` | - | |
|
||||
| status | 设置校验状态 | 'error' \| 'warning' | - | 4.19.0 |
|
||||
| style | 自定义样式 | CSSProperties | - | |
|
||||
| styles | 语义化结构 style | [Record<SemanticDOM, CSSProperties>](#semantic-dom) | - | 5.25.0 |
|
||||
| suffixIcon | 自定义的选择框后缀图标 | ReactNode | - | |
|
||||
| value | 指定选中项 | string\[] \| number\[] | - | |
|
||||
| variant | 形态变体 | `outlined` \| `borderless` \| `filled` \| `underlined` | `outlined` | 5.13.0 \| `underlined`: 5.24.0 |
|
||||
| onChange | 选择完成后的回调 | (value, selectedOptions) => void | - | |
|
||||
| onDropdownVisibleChange | 显示/隐藏浮层的回调 | (value) => void | - | 4.17.0 |
|
||||
| ~~onDropdownVisibleChange~~ | 显示/隐藏浮层的回调,请使用 `onOpenChange` 替换 | (value) => void | - | 4.17.0 |
|
||||
| onOpenChange | 显示/隐藏浮层的回调 | (value) => void | - | |
|
||||
| multiple | 支持多选节点 | boolean | - | 4.17.0 |
|
||||
| showCheckedStrategy | 定义选中项回填的方式。`Cascader.SHOW_CHILD`: 只显示选中的子节点。`Cascader.SHOW_PARENT`: 只显示父节点(当父节点下所有子节点都选中时)。 | `Cascader.SHOW_PARENT` \| `Cascader.SHOW_CHILD` | `Cascader.SHOW_PARENT` | 4.20.0 |
|
||||
| removeIcon | 自定义的多选框清除图标 | ReactNode | - | |
|
||||
| searchValue | 设置搜索的值,需要与 `showSearch` 配合使用 | string | - | 4.17.0 |
|
||||
| onSearch | 监听搜索,返回输入的值 | (search: string) => void | - | 4.17.0 |
|
||||
| dropdownMenuColumnStyle | 下拉菜单列的样式 | CSSProperties | - | |
|
||||
| ~~dropdownMenuColumnStyle~~ | 下拉菜单列的样式,请使用 `popupMenuColumnStyle` 替换 | CSSProperties | - | |
|
||||
| popupMenuColumnStyle | 下拉菜单列的样式 | CSSProperties | - | |
|
||||
| optionRender | 自定义渲染下拉选项 | (option: Option) => React.ReactNode | - | 5.16.0 |
|
||||
|
||||
### showSearch
|
||||
|
@ -129,6 +134,10 @@ interface Option {
|
|||
|
||||
> 注意,如果需要获得中国省市区数据,可以参考 [china-division](https://gist.github.com/afc163/7582f35654fd03d5be7009444345ea17)。
|
||||
|
||||
## Semantic DOM
|
||||
|
||||
<code src="./demo/_semantic.tsx" simplify="true"></code>
|
||||
|
||||
## 主题变量(Design Token)
|
||||
|
||||
<ComponentTokenTable component="Cascader"></ComponentTokenTable>
|
||||
|
|
|
@ -14,6 +14,7 @@ export interface CheckboxOptionType<T = any> {
|
|||
label: React.ReactNode;
|
||||
value: T;
|
||||
style?: React.CSSProperties;
|
||||
className?: string; // 👈 5.25.0+
|
||||
disabled?: boolean;
|
||||
title?: string;
|
||||
id?: string;
|
||||
|
@ -125,7 +126,7 @@ const CheckboxGroup = React.forwardRef(
|
|||
value={option.value}
|
||||
checked={value.includes(option.value)}
|
||||
onChange={option.onChange}
|
||||
className={`${groupPrefixCls}-item`}
|
||||
className={classNames(`${groupPrefixCls}-item`, option.className)}
|
||||
style={option.style}
|
||||
title={option.title}
|
||||
id={option.id}
|
||||
|
@ -160,6 +161,7 @@ const CheckboxGroup = React.forwardRef(
|
|||
rootCls,
|
||||
hashId,
|
||||
);
|
||||
|
||||
return wrapCSSVar(
|
||||
<div className={classString} style={style} {...domProps} ref={ref}>
|
||||
<GroupContext.Provider value={memoizedContext}>{childrenNode}</GroupContext.Provider>
|
||||
|
|
|
@ -691,7 +691,7 @@ Array [
|
|||
class="ant-checkbox-group"
|
||||
>
|
||||
<label
|
||||
class="ant-checkbox-wrapper ant-checkbox-group-item"
|
||||
class="ant-checkbox-wrapper ant-checkbox-group-item label-1"
|
||||
>
|
||||
<span
|
||||
class="ant-checkbox ant-wave-target"
|
||||
|
@ -712,7 +712,7 @@ Array [
|
|||
</span>
|
||||
</label>
|
||||
<label
|
||||
class="ant-checkbox-wrapper ant-checkbox-wrapper-checked ant-checkbox-group-item"
|
||||
class="ant-checkbox-wrapper ant-checkbox-wrapper-checked ant-checkbox-group-item label-2"
|
||||
>
|
||||
<span
|
||||
class="ant-checkbox ant-wave-target ant-checkbox-checked"
|
||||
|
@ -734,7 +734,7 @@ Array [
|
|||
</span>
|
||||
</label>
|
||||
<label
|
||||
class="ant-checkbox-wrapper ant-checkbox-group-item"
|
||||
class="ant-checkbox-wrapper ant-checkbox-group-item label-3"
|
||||
>
|
||||
<span
|
||||
class="ant-checkbox ant-wave-target"
|
||||
|
@ -761,7 +761,7 @@ Array [
|
|||
class="ant-checkbox-group"
|
||||
>
|
||||
<label
|
||||
class="ant-checkbox-wrapper ant-checkbox-wrapper-checked ant-checkbox-wrapper-disabled ant-checkbox-group-item"
|
||||
class="ant-checkbox-wrapper ant-checkbox-wrapper-checked ant-checkbox-wrapper-disabled ant-checkbox-group-item label-1"
|
||||
>
|
||||
<span
|
||||
class="ant-checkbox ant-wave-target ant-checkbox-checked ant-checkbox-disabled"
|
||||
|
@ -784,7 +784,7 @@ Array [
|
|||
</span>
|
||||
</label>
|
||||
<label
|
||||
class="ant-checkbox-wrapper ant-checkbox-wrapper-disabled ant-checkbox-group-item"
|
||||
class="ant-checkbox-wrapper ant-checkbox-wrapper-disabled ant-checkbox-group-item label-2"
|
||||
>
|
||||
<span
|
||||
class="ant-checkbox ant-wave-target ant-checkbox-disabled"
|
||||
|
@ -806,7 +806,7 @@ Array [
|
|||
</span>
|
||||
</label>
|
||||
<label
|
||||
class="ant-checkbox-wrapper ant-checkbox-wrapper-disabled ant-checkbox-group-item"
|
||||
class="ant-checkbox-wrapper ant-checkbox-wrapper-disabled ant-checkbox-group-item label-3"
|
||||
>
|
||||
<span
|
||||
class="ant-checkbox ant-wave-target ant-checkbox-disabled"
|
||||
|
|
|
@ -649,7 +649,7 @@ Array [
|
|||
class="ant-checkbox-group"
|
||||
>
|
||||
<label
|
||||
class="ant-checkbox-wrapper ant-checkbox-group-item"
|
||||
class="ant-checkbox-wrapper ant-checkbox-group-item label-1"
|
||||
>
|
||||
<span
|
||||
class="ant-checkbox ant-wave-target"
|
||||
|
@ -670,7 +670,7 @@ Array [
|
|||
</span>
|
||||
</label>
|
||||
<label
|
||||
class="ant-checkbox-wrapper ant-checkbox-wrapper-checked ant-checkbox-group-item"
|
||||
class="ant-checkbox-wrapper ant-checkbox-wrapper-checked ant-checkbox-group-item label-2"
|
||||
>
|
||||
<span
|
||||
class="ant-checkbox ant-wave-target ant-checkbox-checked"
|
||||
|
@ -692,7 +692,7 @@ Array [
|
|||
</span>
|
||||
</label>
|
||||
<label
|
||||
class="ant-checkbox-wrapper ant-checkbox-group-item"
|
||||
class="ant-checkbox-wrapper ant-checkbox-group-item label-3"
|
||||
>
|
||||
<span
|
||||
class="ant-checkbox ant-wave-target"
|
||||
|
@ -719,7 +719,7 @@ Array [
|
|||
class="ant-checkbox-group"
|
||||
>
|
||||
<label
|
||||
class="ant-checkbox-wrapper ant-checkbox-wrapper-checked ant-checkbox-wrapper-disabled ant-checkbox-group-item"
|
||||
class="ant-checkbox-wrapper ant-checkbox-wrapper-checked ant-checkbox-wrapper-disabled ant-checkbox-group-item label-1"
|
||||
>
|
||||
<span
|
||||
class="ant-checkbox ant-wave-target ant-checkbox-checked ant-checkbox-disabled"
|
||||
|
@ -742,7 +742,7 @@ Array [
|
|||
</span>
|
||||
</label>
|
||||
<label
|
||||
class="ant-checkbox-wrapper ant-checkbox-wrapper-disabled ant-checkbox-group-item"
|
||||
class="ant-checkbox-wrapper ant-checkbox-wrapper-disabled ant-checkbox-group-item label-2"
|
||||
>
|
||||
<span
|
||||
class="ant-checkbox ant-wave-target ant-checkbox-disabled"
|
||||
|
@ -764,7 +764,7 @@ Array [
|
|||
</span>
|
||||
</label>
|
||||
<label
|
||||
class="ant-checkbox-wrapper ant-checkbox-wrapper-disabled ant-checkbox-group-item"
|
||||
class="ant-checkbox-wrapper ant-checkbox-wrapper-disabled ant-checkbox-group-item label-3"
|
||||
>
|
||||
<span
|
||||
class="ant-checkbox ant-wave-target ant-checkbox-disabled"
|
||||
|
|
|
@ -1,6 +1,6 @@
|
|||
import React from 'react';
|
||||
import { Checkbox } from 'antd';
|
||||
import type { GetProp } from 'antd';
|
||||
import type { CheckboxOptionType, GetProp } from 'antd';
|
||||
|
||||
const onChange: GetProp<typeof Checkbox.Group, 'onChange'> = (checkedValues) => {
|
||||
console.log('checked = ', checkedValues);
|
||||
|
@ -8,16 +8,16 @@ const onChange: GetProp<typeof Checkbox.Group, 'onChange'> = (checkedValues) =>
|
|||
|
||||
const plainOptions = ['Apple', 'Pear', 'Orange'];
|
||||
|
||||
const options = [
|
||||
{ label: 'Apple', value: 'Apple' },
|
||||
{ label: 'Pear', value: 'Pear' },
|
||||
{ label: 'Orange', value: 'Orange' },
|
||||
const options: CheckboxOptionType<string>[] = [
|
||||
{ label: 'Apple', value: 'Apple', className: 'label-1' },
|
||||
{ label: 'Pear', value: 'Pear', className: 'label-2' },
|
||||
{ label: 'Orange', value: 'Orange', className: 'label-3' },
|
||||
];
|
||||
|
||||
const optionsWithDisabled = [
|
||||
{ label: 'Apple', value: 'Apple' },
|
||||
{ label: 'Pear', value: 'Pear' },
|
||||
{ label: 'Orange', value: 'Orange', disabled: false },
|
||||
const optionsWithDisabled: CheckboxOptionType<string>[] = [
|
||||
{ label: 'Apple', value: 'Apple', className: 'label-1' },
|
||||
{ label: 'Pear', value: 'Pear', className: 'label-2' },
|
||||
{ label: 'Orange', value: 'Orange', className: 'label-3', disabled: false },
|
||||
];
|
||||
|
||||
const App: React.FC = () => (
|
||||
|
|
|
@ -44,7 +44,7 @@ Common props ref:[Common props](/docs/react/common-props)
|
|||
| onBlur | Called when leaving the component | function() | - | |
|
||||
| onFocus | Called when entering the component | function() | - | |
|
||||
|
||||
#### Checkbox Group
|
||||
#### Checkbox.Group
|
||||
|
||||
| Property | Description | Type | Default | Version |
|
||||
| --- | --- | --- | --- | --- |
|
||||
|
@ -53,6 +53,9 @@ Common props ref:[Common props](/docs/react/common-props)
|
|||
| name | The `name` property of all `input[type="checkbox"]` children | string | - | |
|
||||
| options | Specifies options | string\[] \| number\[] \| Option\[] | \[] | |
|
||||
| value | Used for setting the currently selected value | (string \| number \| boolean)\[] | \[] | |
|
||||
| title | title of the option | `string` | - | |
|
||||
| className | className of the option | `string` | - | 5.25.0 |
|
||||
| style | styles of the option | `React.CSSProperties` | - | |
|
||||
| onChange | The callback function that is triggered when the state changes | (checkedValue: T[]) => void | - | |
|
||||
|
||||
##### Option
|
||||
|
|
|
@ -45,7 +45,7 @@ demo:
|
|||
| onBlur | 失去焦点时的回调 | function() | - | |
|
||||
| onFocus | 获得焦点时的回调 | function() | - | |
|
||||
|
||||
#### Checkbox Group
|
||||
#### Checkbox.Group
|
||||
|
||||
| 参数 | 说明 | 类型 | 默认值 | 版本 |
|
||||
| --- | --- | --- | --- | --- |
|
||||
|
@ -54,6 +54,9 @@ demo:
|
|||
| name | CheckboxGroup 下所有 `input[type="checkbox"]` 的 `name` 属性 | string | - | |
|
||||
| options | 指定可选项 | string\[] \| number\[] \| Option\[] | \[] | |
|
||||
| value | 指定选中的选项 | (string \| number \| boolean)\[] | \[] | |
|
||||
| title | 选项的 title | `string` | - | |
|
||||
| className | 选项的类名 | `string` | - | 5.25.0 |
|
||||
| style | 选项的样式 | `React.CSSProperties` | - | |
|
||||
| onChange | 变化时的回调函数 | (checkedValue: T[]) => void | - | |
|
||||
|
||||
##### Option
|
||||
|
|
|
@ -2,6 +2,7 @@ import React from 'react';
|
|||
|
||||
import { resetWarned } from '../../_util/warning';
|
||||
import { act, fireEvent, render, waitFakeTimer } from '../../../tests/utils';
|
||||
import ConfigProvider from '../../config-provider';
|
||||
|
||||
describe('Collapse', () => {
|
||||
const Collapse = require('..').default;
|
||||
|
@ -275,6 +276,52 @@ describe('Collapse', () => {
|
|||
);
|
||||
});
|
||||
|
||||
it('should support borderlessContentBg component token', () => {
|
||||
const { container } = render(
|
||||
<ConfigProvider
|
||||
theme={{
|
||||
components: {
|
||||
Collapse: {
|
||||
borderlessContentBg: 'red',
|
||||
},
|
||||
},
|
||||
}}
|
||||
>
|
||||
<Collapse bordered={false} defaultActiveKey={['1']}>
|
||||
<Collapse.Panel header="This is panel header 1" key="1">
|
||||
content
|
||||
</Collapse.Panel>
|
||||
</Collapse>
|
||||
</ConfigProvider>,
|
||||
);
|
||||
expect(container.querySelector('.ant-collapse-content')).toHaveStyle({
|
||||
backgroundColor: 'red',
|
||||
});
|
||||
});
|
||||
|
||||
it('should support borderlessContentPadding component token', () => {
|
||||
const { container } = render(
|
||||
<ConfigProvider
|
||||
theme={{
|
||||
components: {
|
||||
Collapse: {
|
||||
borderlessContentPadding: '10px',
|
||||
},
|
||||
},
|
||||
}}
|
||||
>
|
||||
<Collapse bordered={false} defaultActiveKey={['1']}>
|
||||
<Collapse.Panel header="This is panel header 1" key="1">
|
||||
content
|
||||
</Collapse.Panel>
|
||||
</Collapse>
|
||||
</ConfigProvider>,
|
||||
);
|
||||
expect(container.querySelector('.ant-collapse-content-box')).toHaveStyle({
|
||||
padding: '10px',
|
||||
});
|
||||
});
|
||||
|
||||
it('should support styles and classNames', () => {
|
||||
const { container } = render(
|
||||
<Collapse
|
||||
|
|
|
@ -29,6 +29,16 @@ export interface ComponentToken {
|
|||
* @descEN Background of content
|
||||
*/
|
||||
contentBg: string;
|
||||
/**
|
||||
* @desc 简约风格折叠面板的内容内边距
|
||||
* @descEN Padding of content in borderless style
|
||||
*/
|
||||
borderlessContentPadding: CSSProperties['padding'];
|
||||
/**
|
||||
* @desc 简约风格折叠面板的内容背景
|
||||
* @descEN Background of content in borderless style
|
||||
*/
|
||||
borderlessContentBg: string;
|
||||
}
|
||||
|
||||
type CollapseToken = FullToken<'Collapse'> & {
|
||||
|
@ -271,13 +281,8 @@ const genArrowStyle: GenerateStyle<CollapseToken> = (token) => {
|
|||
};
|
||||
|
||||
const genBorderlessStyle: GenerateStyle<CollapseToken> = (token) => {
|
||||
const {
|
||||
componentCls,
|
||||
headerBg,
|
||||
paddingXXS,
|
||||
|
||||
colorBorder,
|
||||
} = token;
|
||||
const { componentCls, headerBg, borderlessContentPadding, borderlessContentBg, colorBorder } =
|
||||
token;
|
||||
|
||||
return {
|
||||
[`${componentCls}-borderless`]: {
|
||||
|
@ -300,12 +305,12 @@ const genBorderlessStyle: GenerateStyle<CollapseToken> = (token) => {
|
|||
},
|
||||
|
||||
[`> ${componentCls}-item > ${componentCls}-content`]: {
|
||||
backgroundColor: 'transparent',
|
||||
backgroundColor: borderlessContentBg,
|
||||
borderTop: 0,
|
||||
},
|
||||
|
||||
[`> ${componentCls}-item > ${componentCls}-content > ${componentCls}-content-box`]: {
|
||||
paddingTop: paddingXXS,
|
||||
padding: borderlessContentPadding,
|
||||
},
|
||||
},
|
||||
};
|
||||
|
@ -337,6 +342,8 @@ export const prepareComponentToken: GetDefaultToken<'Collapse'> = (token) => ({
|
|||
headerBg: token.colorFillAlter,
|
||||
contentPadding: `${token.padding}px 16px`, // Fixed Value
|
||||
contentBg: token.colorBgContainer,
|
||||
borderlessContentPadding: `${token.paddingXXS}px 16px ${token.padding}px`,
|
||||
borderlessContentBg: 'transparent',
|
||||
});
|
||||
|
||||
export default genStyleHooks(
|
||||
|
|
|
@ -60,6 +60,7 @@ const ColorPicker: CompoundedComponent = (props) => {
|
|||
getPopupContainer,
|
||||
autoAdjustOverflow = true,
|
||||
destroyTooltipOnHide,
|
||||
destroyOnClose,
|
||||
disabledFormat,
|
||||
...rest
|
||||
} = props;
|
||||
|
@ -211,7 +212,7 @@ const ColorPicker: CompoundedComponent = (props) => {
|
|||
rootClassName,
|
||||
getPopupContainer,
|
||||
autoAdjustOverflow,
|
||||
destroyTooltipOnHide,
|
||||
destroyOnClose: destroyOnClose ?? !!destroyTooltipOnHide,
|
||||
};
|
||||
|
||||
const mergedStyle: React.CSSProperties = { ...colorPicker?.style, ...style };
|
||||
|
|
|
@ -50,7 +50,8 @@ Common props ref:[Common props](/docs/react/common-props)
|
|||
| disabled | Disable ColorPicker | boolean | - | |
|
||||
| disabledAlpha | Disable Alpha | boolean | - | 5.8.0 |
|
||||
| disabledFormat | Disable format of color | boolean | - | |
|
||||
| destroyTooltipOnHide | Whether destroy popover when hidden | `boolean` | false | 5.7.0 |
|
||||
| ~~destroyTooltipOnHide~~ | Whether destroy dom when close | `boolean` | false | 5.7.0 |
|
||||
| destroyOnClose | Whether destroy dom when close | `boolean` | false | 5.25.0 |
|
||||
| format | Format of color | `rgb` \| `hex` \| `hsb` | - | |
|
||||
| mode | Configure single or gradient color | `'single' \| 'gradient' \| ('single' \| 'gradient')[]` | `single` | 5.20.0 |
|
||||
| open | Whether to show popup | boolean | - | |
|
||||
|
|
|
@ -51,7 +51,8 @@ group:
|
|||
| disabled | 禁用颜色选择器 | boolean | - | |
|
||||
| disabledAlpha | 禁用透明度 | boolean | - | 5.8.0 |
|
||||
| disabledFormat | 禁用选择颜色格式 | boolean | - | |
|
||||
| destroyTooltipOnHide | 关闭后是否销毁弹窗 | `boolean` | false | 5.7.0 |
|
||||
| ~~destroyTooltipOnHide~~ | 关闭后是否销毁弹窗 | `boolean` | false | 5.7.0 |
|
||||
| destroyOnClose | 关闭后是否销毁弹窗 | `boolean` | false | 5.25.0 |
|
||||
| format | 颜色格式 | `rgb` \| `hex` \| `hsb` | - | |
|
||||
| mode | 选择器模式,用于配置单色与渐变 | `'single' \| 'gradient' \| ('single' \| 'gradient')[]` | `single` | 5.20.0 |
|
||||
| open | 是否显示弹出窗口 | boolean | - | |
|
||||
|
|
|
@ -94,4 +94,7 @@ export type ColorPickerProps = Omit<
|
|||
onClear?: () => void;
|
||||
onChangeComplete?: (value: AggregationColor) => void;
|
||||
disabledFormat?: boolean;
|
||||
} & Pick<PopoverProps, 'getPopupContainer' | 'autoAdjustOverflow' | 'destroyTooltipOnHide'>;
|
||||
} & Pick<
|
||||
PopoverProps,
|
||||
'getPopupContainer' | 'autoAdjustOverflow' | 'destroyTooltipOnHide' | 'destroyOnClose'
|
||||
>;
|
||||
|
|
|
@ -14405,14 +14405,14 @@ exports[`ConfigProvider components Divider configProvider componentSize large 1`
|
|||
|
||||
exports[`ConfigProvider components Divider configProvider componentSize middle 1`] = `
|
||||
<div
|
||||
class="config-divider config-divider-horizontal"
|
||||
class="config-divider config-divider-horizontal config-divider-md"
|
||||
role="separator"
|
||||
/>
|
||||
`;
|
||||
|
||||
exports[`ConfigProvider components Divider configProvider componentSize small 1`] = `
|
||||
<div
|
||||
class="config-divider config-divider-horizontal"
|
||||
class="config-divider config-divider-horizontal config-divider-sm"
|
||||
role="separator"
|
||||
/>
|
||||
`;
|
||||
|
@ -18568,6 +18568,7 @@ exports[`ConfigProvider components Modal configProvider 1`] = `
|
|||
type="button"
|
||||
>
|
||||
<span
|
||||
aria-label="Close"
|
||||
class="config-modal-close-x"
|
||||
>
|
||||
<span
|
||||
|
@ -18660,6 +18661,7 @@ exports[`ConfigProvider components Modal configProvider componentDisabled 1`] =
|
|||
type="button"
|
||||
>
|
||||
<span
|
||||
aria-label="Close"
|
||||
class="config-modal-close-x"
|
||||
>
|
||||
<span
|
||||
|
@ -18752,6 +18754,7 @@ exports[`ConfigProvider components Modal configProvider componentSize large 1`]
|
|||
type="button"
|
||||
>
|
||||
<span
|
||||
aria-label="Close"
|
||||
class="config-modal-close-x"
|
||||
>
|
||||
<span
|
||||
|
@ -18844,6 +18847,7 @@ exports[`ConfigProvider components Modal configProvider componentSize middle 1`]
|
|||
type="button"
|
||||
>
|
||||
<span
|
||||
aria-label="Close"
|
||||
class="config-modal-close-x"
|
||||
>
|
||||
<span
|
||||
|
@ -18936,6 +18940,7 @@ exports[`ConfigProvider components Modal configProvider componentSize small 1`]
|
|||
type="button"
|
||||
>
|
||||
<span
|
||||
aria-label="Close"
|
||||
class="config-modal-close-x"
|
||||
>
|
||||
<span
|
||||
|
@ -19028,6 +19033,7 @@ exports[`ConfigProvider components Modal normal 1`] = `
|
|||
type="button"
|
||||
>
|
||||
<span
|
||||
aria-label="Close"
|
||||
class="ant-modal-close-x"
|
||||
>
|
||||
<span
|
||||
|
@ -19120,6 +19126,7 @@ exports[`ConfigProvider components Modal prefixCls 1`] = `
|
|||
type="button"
|
||||
>
|
||||
<span
|
||||
aria-label="Close"
|
||||
class="prefix-Modal-close-x"
|
||||
>
|
||||
<span
|
||||
|
|
|
@ -161,7 +161,7 @@ export type TextAreaConfig = ComponentStyleConfig &
|
|||
Pick<TextAreaProps, 'autoComplete' | 'classNames' | 'styles' | 'allowClear' | 'variant'>;
|
||||
|
||||
export type ButtonConfig = ComponentStyleConfig &
|
||||
Pick<ButtonProps, 'classNames' | 'styles' | 'autoInsertSpace'>;
|
||||
Pick<ButtonProps, 'classNames' | 'styles' | 'autoInsertSpace' | 'variant' | 'color'>;
|
||||
|
||||
export type NotificationConfig = ComponentStyleConfig & Pick<ArgsProps, 'closeIcon'>;
|
||||
|
||||
|
@ -184,7 +184,8 @@ export type FloatButtonGroupConfig = Pick<FloatButtonGroupProps, 'closeIcon'>;
|
|||
|
||||
export type PaginationConfig = ComponentStyleConfig & Pick<PaginationProps, 'showSizeChanger'>;
|
||||
|
||||
export type SelectConfig = ComponentStyleConfig & Pick<SelectProps, 'showSearch' | 'variant'>;
|
||||
export type SelectConfig = ComponentStyleConfig &
|
||||
Pick<SelectProps, 'showSearch' | 'variant' | 'classNames' | 'styles'>;
|
||||
|
||||
export type SpaceConfig = ComponentStyleConfig & Pick<SpaceProps, 'size' | 'classNames' | 'styles'>;
|
||||
|
||||
|
@ -203,9 +204,11 @@ export type SpinConfig = ComponentStyleConfig & Pick<SpinProps, 'indicator'>;
|
|||
|
||||
export type InputNumberConfig = ComponentStyleConfig & Pick<InputNumberProps, 'variant'>;
|
||||
|
||||
export type CascaderConfig = ComponentStyleConfig & Pick<CascaderProps, 'variant'>;
|
||||
export type CascaderConfig = ComponentStyleConfig &
|
||||
Pick<CascaderProps, 'variant' | 'styles' | 'classNames'>;
|
||||
|
||||
export type TreeSelectConfig = ComponentStyleConfig & Pick<TreeSelectProps, 'variant'>;
|
||||
export type TreeSelectConfig = ComponentStyleConfig &
|
||||
Pick<TreeSelectProps, 'variant' | 'styles' | 'classNames'>;
|
||||
|
||||
export type DatePickerConfig = ComponentStyleConfig & Pick<DatePickerProps, 'variant'>;
|
||||
|
||||
|
|
|
@ -113,11 +113,11 @@ const {
|
|||
| avatar | Set Avatar common props | { className?: string, style?: React.CSSProperties } | - | 5.7.0 |
|
||||
| badge | Set Badge common props | { className?: string, style?: React.CSSProperties, classNames?: [BadgeProps\["classNames"\]](/components/badge#api), styles?: [BadgeProps\["styles"\]](/components/badge#api) } | - | 5.7.0 |
|
||||
| breadcrumb | Set Breadcrumb common props | { className?: string, style?: React.CSSProperties } | - | 5.7.0 |
|
||||
| button | Set Button common props | { className?: string, style?: React.CSSProperties, classNames?: [ButtonProps\["classNames"\]](/components/button#api), styles?: [ButtonProps\["styles"\]](/components/button#api), autoInsertSpace?: boolean } | - | 5.6.0, `autoInsertSpace`: 5.17.0 |
|
||||
| button | Set Button common props | { className?: string, style?: React.CSSProperties, classNames?: [ButtonProps\["classNames"\]](/components/button#api), styles?: [ButtonProps\["styles"\]](/components/button#api), autoInsertSpace?: boolean, variant?: ButtonVariantType, color?: ButtonColorType } | - | 5.6.0, `autoInsertSpace`: 5.17.0, `variant` and `color`: 5.25.0 |
|
||||
| card | Set Card common props | { className?: string, style?: React.CSSProperties, classNames?: [CardProps\["classNames"\]](/components/card#api), styles?: [CardProps\["styles"\]](/components/card#api) } | - | 5.7.0, `classNames` and `styles`: 5.14.0 |
|
||||
| calendar | Set Calendar common props | { className?: string, style?: React.CSSProperties } | - | 5.7.0 |
|
||||
| carousel | Set Carousel common props | { className?: string, style?: React.CSSProperties } | - | 5.7.0 |
|
||||
| cascader | Set Cascader common props | { className?: string, style?: React.CSSProperties } | - | 5.7.0 |
|
||||
| cascader | Set Cascader common props | { className?: string, style?: React.CSSProperties, classNames?: [CascaderProps\["classNames"\]](/components/cascader#semantic-dom), styles?: [CascaderProps\["styles"\]](/components/cascader#semantic-dom) } | - | 5.7.0, `classNames` and `styles`: 5.25.0 |
|
||||
| checkbox | Set Checkbox common props | { className?: string, style?: React.CSSProperties } | - | 5.7.0 |
|
||||
| collapse | Set Collapse common props | { className?: string, style?: React.CSSProperties, expandIcon?: (props) => ReactNode } | - | 5.7.0, `expandIcon`: 5.15.0 |
|
||||
| colorPicker | Set ColorPicker common props | { className?: string, style?: React.CSSProperties } | - | 5.7.0 |
|
||||
|
@ -148,7 +148,7 @@ const {
|
|||
| result | Set Result common props | { className?: string, style?: React.CSSProperties } | - | 5.7.0 |
|
||||
| skeleton | Set Skeleton common props | { className?: string, style?: React.CSSProperties } | - | 5.7.0 |
|
||||
| segmented | Set Segmented common props | { className?: string, style?: React.CSSProperties } | - | 5.7.0 |
|
||||
| select | Set Select common props | { className?: string, showSearch?: boolean, style?: React.CSSProperties } | - | 5.7.0 |
|
||||
| select | Set Select common props | { className?: string, showSearch?: boolean, style?: React.CSSProperties, classNames?: [SelectProps\["classNames"\]](/components/select#api), styles?: [SelectProps\["styles"\]](/components/select#api) } | - | 5.7.0, `classNames` and `styles`: 5.25.0 |
|
||||
| slider | Set Slider common props | { className?: string, style?: React.CSSProperties, classNames?: [SliderProps\["classNames"\]](/components/slider#api), styles?: [SliderProps\["styles"\]](/components/slider#api) } | - | 5.7.0, `classNames` and `styles`: 5.23.0 |
|
||||
| switch | Set Switch common props | { className?: string, style?: React.CSSProperties } | - | 5.7.0 |
|
||||
| space | Set Space common props, ref [Space](/components/space) | { size: `small` \| `middle` \| `large` \| `number`, className?: string, style?: React.CSSProperties, classNames?: [SpaceProps\["classNames"\]](/components/space#api), styles?: [SpaceProps\["styles"\]](/components/space#api) } | - | 5.6.0 |
|
||||
|
@ -167,6 +167,7 @@ const {
|
|||
| popconfirm | Set Popconfirm common props | { className?: string, style?: React.CSSProperties, classNames?:[Popconfirm\["classNames"\]](/components/popconfirm#api), styles?: [Popconfirm\["styles"\]](/components/popconfirm#api) } | - | 5.23.0 |
|
||||
| transfer | Set Transfer common props | { className?: string, style?: React.CSSProperties, selectionsIcon?: React.ReactNode } | - | 5.7.0, `selectionsIcon`: 5.14.0 |
|
||||
| tree | Set Tree common props | { className?: string, style?: React.CSSProperties } | - | 5.7.0 |
|
||||
| treeSelect | Set TreeSelect common props | { classNames?:[TreeSelect\["classNames"\]](/components/tree-select#api), styles?: [TreeSelect\["styles"\]](/components/tree-select#api) } | - | 5.25.0 |
|
||||
| typography | Set Typography common props | { className?: string, style?: React.CSSProperties } | - | 5.7.0 |
|
||||
| upload | Set Upload common props | { className?: string, style?: React.CSSProperties } | - | 5.7.0 |
|
||||
| wave | Config wave effect | { disabled?: boolean, showEffect?: (node: HTMLElement, info: { className, token, component }) => void } | - | 5.8.0 |
|
||||
|
|
|
@ -115,11 +115,11 @@ const {
|
|||
| avatar | 设置 Avatar 组件的通用属性 | { className?: string, style?: React.CSSProperties } | - | 5.7.0 |
|
||||
| badge | 设置 Badge 组件的通用属性 | { className?: string, style?: React.CSSProperties, classNames?: [BadgeProps\["classNames"\]](/components/badge-cn#api), styles?: [BadgeProps\["styles"\]](/components/badge-cn#api) } | - | 5.7.0 |
|
||||
| breadcrumb | 设置 Breadcrumb 组件的通用属性 | { className?: string, style?: React.CSSProperties } | - | 5.7.0 |
|
||||
| button | 设置 Button 组件的通用属性 | { className?: string, style?: React.CSSProperties, classNames?: [ButtonProps\["classNames"\]](/components/button-cn#api), styles?: [ButtonProps\["styles"\]](/components/button-cn#api), autoInsertSpace?: boolean } | - | 5.6.0, `autoInsertSpace`: 5.17.0 |
|
||||
| button | 设置 Button 组件的通用属性 | { className?: string, style?: React.CSSProperties, classNames?: [ButtonProps\["classNames"\]](/components/button-cn#api), styles?: [ButtonProps\["styles"\]](/components/button-cn#api), autoInsertSpace?: boolean, variant?: ButtonVariantType, color?: ButtonColorType } | - | 5.6.0, `autoInsertSpace`: 5.17.0, `variant` 和 `color`: 5.25.0 |
|
||||
| calendar | 设置 Calendar 组件的通用属性 | { className?: string, style?: React.CSSProperties } | - | 5.7.0 |
|
||||
| card | 设置 Card 组件的通用属性 | { className?: string, style?: React.CSSProperties, classNames?: [CardProps\["classNames"\]](/components/card-cn#api), styles?: [CardProps\["styles"\]](/components/card-cn#api) } | - | 5.7.0, `classNames` 和 `styles`: 5.14.0 |
|
||||
| carousel | 设置 Carousel 组件的通用属性 | { className?: string, style?: React.CSSProperties } | - | 5.7.0 |
|
||||
| cascader | 设置 Cascader 组件的通用属性 | { className?: string, style?: React.CSSProperties } | - | 5.7.0 |
|
||||
| cascader | 设置 Cascader 组件的通用属性 | { className?: string, style?: React.CSSProperties, classNames?: [CascaderProps\["classNames"\]](/components/cascader-cn#semantic-dom), styles?: [CascaderProps\["styles"\]](/components/cascader-cn#semantic-dom) } | - | 5.7.0, `classNames` 和 `styles`: 5.25.0 |
|
||||
| checkbox | 设置 Checkbox 组件的通用属性 | { className?: string, style?: React.CSSProperties } | - | 5.7.0 |
|
||||
| collapse | 设置 Collapse 组件的通用属性 | { className?: string, style?: React.CSSProperties, expandIcon?: (props) => ReactNode } | - | 5.7.0, `expandIcon`: 5.15.0 |
|
||||
| colorPicker | 设置 ColorPicker 组件的通用属性 | { className?: string, style?: React.CSSProperties } | - | 5.7.0 |
|
||||
|
@ -150,7 +150,7 @@ const {
|
|||
| result | 设置 Result 组件的通用属性 | { className?: string, style?: React.CSSProperties } | - | 5.7.0 |
|
||||
| skeleton | 设置 Skeleton 组件的通用属性 | { className?: string, style?: React.CSSProperties } | - | 5.7.0 |
|
||||
| segmented | 设置 Segmented 组件的通用属性 | { className?: string, style?: React.CSSProperties } | - | 5.7.0 |
|
||||
| select | 设置 Select 组件的通用属性 | { className?: string, showSearch?: boolean, style?: React.CSSProperties } | - | 5.7.0 |
|
||||
| select | 设置 Select 组件的通用属性 | { className?: string, showSearch?: boolean, style?: React.CSSProperties, classNames?: [SelectProps\["classNames"\]](/components/select-cn#api), styles?: [SelectProps\["styles"\]](/components/select-cn#api) } | - | 5.7.0, `classNames` 和 `styles`: 5.25.0 |
|
||||
| slider | 设置 Slider 组件的通用属性 | { className?: string, style?: React.CSSProperties, classNames?: [SliderProps\["classNames"\]](/components/slider-cn#api), styles?: [SliderProps\["styles"\]](/components/slider-cn#api) } | - | 5.7.0, `classNames` 和 `styles`: 5.23.0 |
|
||||
| switch | 设置 Switch 组件的通用属性 | { className?: string, style?: React.CSSProperties } | - | 5.7.0 |
|
||||
| space | 设置 Space 的通用属性,参考 [Space](/components/space-cn) | { size: `small` \| `middle` \| `large` \| `number`, className?: string, style?: React.CSSProperties, classNames?: [SpaceProps\["classNames"\]](/components/space-cn#api), styles?: [SpaceProps\["styles"\]](/components/space-cn#api) } | - | 5.6.0 |
|
||||
|
@ -169,6 +169,7 @@ const {
|
|||
| popconfirm | 设置 Popconfirm 组件的通用属性 | { className?: string, style?: React.CSSProperties, classNames?:[Popconfirm\["classNames"\]](/components/popconfirm-cn#api), styles?: [Popconfirm\["styles"\]](/components/popconfirm-cn#api) } | - | 5.23.0 |
|
||||
| transfer | 设置 Transfer 组件的通用属性 | { className?: string, style?: React.CSSProperties, selectionsIcon?: React.ReactNode } | - | 5.7.0, `selectionsIcon`: 5.14.0 |
|
||||
| tree | 设置 Tree 组件的通用属性 | { className?: string, style?: React.CSSProperties } | - | 5.7.0 |
|
||||
| treeSelect | 设置 TreeSelect 组件的通用属性 | { classNames?:[TreeSelect\["classNames"\]](/components/tree-select-cn#api), styles?: [TreeSelect\["styles"\]](/components/tree-select-cn#api) } | - | 5.25.0 |
|
||||
| typography | 设置 Typography 组件的通用属性 | { className?: string, style?: React.CSSProperties } | - | 5.7.0 |
|
||||
| upload | 设置 Upload 组件的通用属性 | { className?: string, style?: React.CSSProperties } | - | 5.7.0 |
|
||||
| wave | 设置水波纹特效 | { disabled?: boolean, showEffect?: (node: HTMLElement, info: { className, token, component }) => void } | - | 5.8.0 |
|
||||
|
|
|
@ -203,6 +203,37 @@ Array [
|
|||
|
||||
exports[`renders components/divider/demo/plain.tsx extend context correctly 2`] = `[]`;
|
||||
|
||||
exports[`renders components/divider/demo/size.tsx extend context correctly 1`] = `
|
||||
Array [
|
||||
<p>
|
||||
Lorem ipsum dolor sit amet, consectetur adipiscing elit. Sed nonne merninisti licere mihi ista probare, quae sunt a te dicta? Refert tamen, quo modo.
|
||||
</p>,
|
||||
<div
|
||||
class="ant-divider ant-divider-horizontal ant-divider-sm"
|
||||
role="separator"
|
||||
/>,
|
||||
<p>
|
||||
Lorem ipsum dolor sit amet, consectetur adipiscing elit. Sed nonne merninisti licere mihi ista probare, quae sunt a te dicta? Refert tamen, quo modo.
|
||||
</p>,
|
||||
<div
|
||||
class="ant-divider ant-divider-horizontal ant-divider-md"
|
||||
role="separator"
|
||||
/>,
|
||||
<p>
|
||||
Lorem ipsum dolor sit amet, consectetur adipiscing elit. Sed nonne merninisti licere mihi ista probare, quae sunt a te dicta? Refert tamen, quo modo.
|
||||
</p>,
|
||||
<div
|
||||
class="ant-divider ant-divider-horizontal"
|
||||
role="separator"
|
||||
/>,
|
||||
<p>
|
||||
Lorem ipsum dolor sit amet, consectetur adipiscing elit. Sed nonne merninisti licere mihi ista probare, quae sunt a te dicta? Refert tamen, quo modo.
|
||||
</p>,
|
||||
]
|
||||
`;
|
||||
|
||||
exports[`renders components/divider/demo/size.tsx extend context correctly 2`] = `[]`;
|
||||
|
||||
exports[`renders components/divider/demo/variant.tsx extend context correctly 1`] = `
|
||||
Array [
|
||||
<p>
|
||||
|
|
|
@ -195,6 +195,35 @@ Array [
|
|||
]
|
||||
`;
|
||||
|
||||
exports[`renders components/divider/demo/size.tsx correctly 1`] = `
|
||||
Array [
|
||||
<p>
|
||||
Lorem ipsum dolor sit amet, consectetur adipiscing elit. Sed nonne merninisti licere mihi ista probare, quae sunt a te dicta? Refert tamen, quo modo.
|
||||
</p>,
|
||||
<div
|
||||
class="ant-divider ant-divider-horizontal ant-divider-sm"
|
||||
role="separator"
|
||||
/>,
|
||||
<p>
|
||||
Lorem ipsum dolor sit amet, consectetur adipiscing elit. Sed nonne merninisti licere mihi ista probare, quae sunt a te dicta? Refert tamen, quo modo.
|
||||
</p>,
|
||||
<div
|
||||
class="ant-divider ant-divider-horizontal ant-divider-md"
|
||||
role="separator"
|
||||
/>,
|
||||
<p>
|
||||
Lorem ipsum dolor sit amet, consectetur adipiscing elit. Sed nonne merninisti licere mihi ista probare, quae sunt a te dicta? Refert tamen, quo modo.
|
||||
</p>,
|
||||
<div
|
||||
class="ant-divider ant-divider-horizontal"
|
||||
role="separator"
|
||||
/>,
|
||||
<p>
|
||||
Lorem ipsum dolor sit amet, consectetur adipiscing elit. Sed nonne merninisti licere mihi ista probare, quae sunt a te dicta? Refert tamen, quo modo.
|
||||
</p>,
|
||||
]
|
||||
`;
|
||||
|
||||
exports[`renders components/divider/demo/variant.tsx correctly 1`] = `
|
||||
Array [
|
||||
<p>
|
||||
|
|
|
@ -1,4 +1,5 @@
|
|||
import * as React from 'react';
|
||||
import { ConfigProvider } from 'antd';
|
||||
|
||||
import Divider from '..';
|
||||
import mountTest from '../../../tests/shared/mountTest';
|
||||
|
@ -40,4 +41,28 @@ describe('Divider', () => {
|
|||
borderStyle: 'dotted',
|
||||
});
|
||||
});
|
||||
|
||||
it('should apply the componentSize of ConfigProvider', () => {
|
||||
const { container, rerender } = render(
|
||||
<ConfigProvider componentSize="middle">
|
||||
<Divider />
|
||||
</ConfigProvider>,
|
||||
);
|
||||
expect(container.querySelector<HTMLSpanElement>('.ant-divider-md')).toBeTruthy();
|
||||
|
||||
rerender(
|
||||
<ConfigProvider componentSize="small">
|
||||
<Divider />
|
||||
</ConfigProvider>,
|
||||
);
|
||||
expect(container.querySelector<HTMLSpanElement>('.ant-divider-sm')).toBeTruthy();
|
||||
});
|
||||
|
||||
it('support vertical size', () => {
|
||||
const { container, rerender } = render(<Divider type="vertical" size="middle" />);
|
||||
expect(container.querySelector<HTMLSpanElement>('.ant-divider-md')).toBeTruthy();
|
||||
|
||||
rerender(<Divider type="vertical" size="small" />);
|
||||
expect(container.querySelector<HTMLSpanElement>('.ant-divider-sm')).toBeTruthy();
|
||||
});
|
||||
});
|
||||
|
|
7
components/divider/demo/size.md
Normal file
7
components/divider/demo/size.md
Normal file
|
@ -0,0 +1,7 @@
|
|||
## zh-CN
|
||||
|
||||
间距的大小。
|
||||
|
||||
## en-US
|
||||
|
||||
The size of the spacing.
|
28
components/divider/demo/size.tsx
Normal file
28
components/divider/demo/size.tsx
Normal file
|
@ -0,0 +1,28 @@
|
|||
import React from 'react';
|
||||
import { Divider } from 'antd';
|
||||
|
||||
const App: React.FC = () => (
|
||||
<>
|
||||
<p>
|
||||
Lorem ipsum dolor sit amet, consectetur adipiscing elit. Sed nonne merninisti licere mihi ista
|
||||
probare, quae sunt a te dicta? Refert tamen, quo modo.
|
||||
</p>
|
||||
<Divider size="small" />
|
||||
<p>
|
||||
Lorem ipsum dolor sit amet, consectetur adipiscing elit. Sed nonne merninisti licere mihi ista
|
||||
probare, quae sunt a te dicta? Refert tamen, quo modo.
|
||||
</p>
|
||||
<Divider size="middle" />
|
||||
<p>
|
||||
Lorem ipsum dolor sit amet, consectetur adipiscing elit. Sed nonne merninisti licere mihi ista
|
||||
probare, quae sunt a te dicta? Refert tamen, quo modo.
|
||||
</p>
|
||||
<Divider size="large" />
|
||||
<p>
|
||||
Lorem ipsum dolor sit amet, consectetur adipiscing elit. Sed nonne merninisti licere mihi ista
|
||||
probare, quae sunt a te dicta? Refert tamen, quo modo.
|
||||
</p>
|
||||
</>
|
||||
);
|
||||
|
||||
export default App;
|
|
@ -21,6 +21,7 @@ group:
|
|||
<!-- prettier-ignore -->
|
||||
<code src="./demo/horizontal.tsx">Horizontal</code>
|
||||
<code src="./demo/with-text.tsx">Divider with title</code>
|
||||
<code src="./demo/size.tsx" version="5.25.0">Set the spacing size of the divider</code>
|
||||
<code src="./demo/plain.tsx">Text without heading style</code>
|
||||
<code src="./demo/vertical.tsx">Vertical</code>
|
||||
<code src="./demo/customize-style.tsx" debug>Style Customization</code>
|
||||
|
@ -41,6 +42,7 @@ Common props ref:[Common props](/docs/react/common-props)
|
|||
| orientationMargin | The margin-left/right between the title and its closest border, while the `orientation` should not be `center`, If a numeric value of type `string` is provided without a unit, it is assumed to be in pixels (px) by default. | string \| number | - | |
|
||||
| plain | Divider text show as plain style | boolean | true | 4.2.0 |
|
||||
| style | The style object of container | CSSProperties | - | |
|
||||
| size | The size of divider. Only valid for horizontal layout | `small` \| `middle` \| `large` | - | 5.25.0 |
|
||||
| type | The direction type of divider | `horizontal` \| `vertical` | `horizontal` | |
|
||||
|
||||
## Design Token
|
||||
|
|
|
@ -3,6 +3,8 @@ import classNames from 'classnames';
|
|||
|
||||
import { devUseWarning } from '../_util/warning';
|
||||
import { useComponentConfig } from '../config-provider/context';
|
||||
import useSize from '../config-provider/hooks/useSize';
|
||||
import { SizeType } from '../config-provider/SizeContext';
|
||||
import useStyle from './style';
|
||||
|
||||
export interface DividerProps {
|
||||
|
@ -28,9 +30,12 @@ export interface DividerProps {
|
|||
*/
|
||||
variant?: 'dashed' | 'dotted' | 'solid';
|
||||
style?: React.CSSProperties;
|
||||
size?: SizeType;
|
||||
plain?: boolean;
|
||||
}
|
||||
|
||||
const sizeClassNameMap: Record<string, string> = { small: 'sm', middle: 'md' };
|
||||
|
||||
const Divider: React.FC<DividerProps> = (props) => {
|
||||
const {
|
||||
getPrefixCls,
|
||||
|
@ -51,12 +56,16 @@ const Divider: React.FC<DividerProps> = (props) => {
|
|||
variant = 'solid',
|
||||
plain,
|
||||
style,
|
||||
size: customSize,
|
||||
...restProps
|
||||
} = props;
|
||||
const prefixCls = getPrefixCls('divider', customizePrefixCls);
|
||||
|
||||
const [wrapCSSVar, hashId, cssVarCls] = useStyle(prefixCls);
|
||||
|
||||
const sizeFullName = useSize(customSize);
|
||||
const sizeCls = sizeClassNameMap[sizeFullName];
|
||||
|
||||
const hasChildren = !!children;
|
||||
|
||||
const mergedOrientation = React.useMemo<'start' | 'end' | 'center'>(() => {
|
||||
|
@ -88,6 +97,7 @@ const Divider: React.FC<DividerProps> = (props) => {
|
|||
[`${prefixCls}-rtl`]: direction === 'rtl',
|
||||
[`${prefixCls}-no-default-orientation-margin-start`]: hasMarginStart,
|
||||
[`${prefixCls}-no-default-orientation-margin-end`]: hasMarginEnd,
|
||||
[`${prefixCls}-${sizeCls}`]: !!sizeCls,
|
||||
},
|
||||
className,
|
||||
rootClassName,
|
||||
|
|
|
@ -22,6 +22,7 @@ group:
|
|||
<!-- prettier-ignore -->
|
||||
<code src="./demo/horizontal.tsx">水平分割线</code>
|
||||
<code src="./demo/with-text.tsx">带文字的分割线</code>
|
||||
<code src="./demo/size.tsx" version="5.25.0">设置分割线的间距大小</code>
|
||||
<code src="./demo/plain.tsx">分割文字使用正文样式</code>
|
||||
<code src="./demo/vertical.tsx">垂直分割线</code>
|
||||
<code src="./demo/customize-style.tsx" debug>样式自定义</code>
|
||||
|
@ -42,6 +43,7 @@ group:
|
|||
| orientationMargin | 标题和最近 left/right 边框之间的距离,去除了分割线,同时 `orientation` 不能为 `center`。如果传入 `string` 类型的数字且不带单位,默认单位是 px | string \| number | - | |
|
||||
| plain | 文字是否显示为普通正文样式 | boolean | false | 4.2.0 |
|
||||
| style | 分割线样式对象 | CSSProperties | - | |
|
||||
| size | 间距大小,仅对水平布局有效 | `small` \| `middle` \| `large` | - | 5.25.0 |
|
||||
| type | 水平还是垂直类型 | `horizontal` \| `vertical` | `horizontal` | |
|
||||
|
||||
## 主题变量(Design Token)
|
||||
|
|
|
@ -40,13 +40,28 @@ interface DividerToken extends FullToken<'Divider'> {
|
|||
* @descEN Horizontal margin of divider with text
|
||||
*/
|
||||
dividerHorizontalWithTextGutterMargin: number | string;
|
||||
/**
|
||||
* @desc 水平分割线的外边距
|
||||
* @descEN Horizontal margin of divider
|
||||
*/
|
||||
dividerHorizontalGutterMargin: number | string;
|
||||
}
|
||||
|
||||
// ============================== Size ================================
|
||||
const genSizeDividerStyle: GenerateStyle<DividerToken> = (token): CSSObject => {
|
||||
const { componentCls } = token;
|
||||
|
||||
return {
|
||||
[componentCls]: {
|
||||
'&-horizontal': {
|
||||
[`&${componentCls}`]: {
|
||||
'&-sm': {
|
||||
marginBlock: token.marginXS,
|
||||
},
|
||||
'&-md': {
|
||||
marginBlock: token.margin,
|
||||
},
|
||||
},
|
||||
},
|
||||
},
|
||||
};
|
||||
};
|
||||
|
||||
// ============================== Shared ==============================
|
||||
const genSharedDividerStyle: GenerateStyle<DividerToken> = (token): CSSObject => {
|
||||
const {
|
||||
|
@ -82,7 +97,7 @@ const genSharedDividerStyle: GenerateStyle<DividerToken> = (token): CSSObject =>
|
|||
clear: 'both',
|
||||
width: '100%',
|
||||
minWidth: '100%', // Fix https://github.com/ant-design/ant-design/issues/10914
|
||||
margin: `${unit(token.dividerHorizontalGutterMargin)} 0`,
|
||||
margin: `${unit(token.marginLG)} 0`,
|
||||
},
|
||||
|
||||
[`&-horizontal${componentCls}-with-text`]: {
|
||||
|
@ -223,10 +238,9 @@ export default genStyleHooks(
|
|||
(token) => {
|
||||
const dividerToken = mergeToken<DividerToken>(token, {
|
||||
dividerHorizontalWithTextGutterMargin: token.margin,
|
||||
dividerHorizontalGutterMargin: token.marginLG,
|
||||
sizePaddingEdgeHorizontal: 0,
|
||||
});
|
||||
return [genSharedDividerStyle(dividerToken)];
|
||||
return [genSharedDividerStyle(dividerToken), genSizeDividerStyle(dividerToken)];
|
||||
},
|
||||
prepareComponentToken,
|
||||
{
|
||||
|
|
|
@ -4,8 +4,8 @@ import type { DrawerProps as RCDrawerProps } from 'rc-drawer';
|
|||
|
||||
import useClosable, { pickClosable } from '../_util/hooks/useClosable';
|
||||
import type { ClosableType } from '../_util/hooks/useClosable';
|
||||
import Skeleton from '../skeleton';
|
||||
import { useComponentConfig } from '../config-provider/context';
|
||||
import Skeleton from '../skeleton';
|
||||
|
||||
export interface DrawerClassNames extends NonNullable<RCDrawerProps['classNames']> {
|
||||
header?: string;
|
||||
|
@ -74,7 +74,7 @@ const DrawerPanel: React.FC<DrawerPanelProps> = (props) => {
|
|||
|
||||
const customCloseIconRender = React.useCallback(
|
||||
(icon: React.ReactNode) => (
|
||||
<button type="button" onClick={onClose} aria-label="Close" className={`${prefixCls}-close`}>
|
||||
<button type="button" onClick={onClose} className={`${prefixCls}-close`}>
|
||||
{icon}
|
||||
</button>
|
||||
),
|
||||
|
|
|
@ -39,7 +39,7 @@ Array [
|
|||
class="ant-drawer-header-title"
|
||||
>
|
||||
<button
|
||||
aria-label="Close"
|
||||
aria-label="Close Button"
|
||||
class="ant-drawer-close"
|
||||
type="button"
|
||||
>
|
||||
|
|
|
@ -17,7 +17,12 @@ const App: React.FC = () => {
|
|||
<Button type="primary" onClick={showDrawer}>
|
||||
Open
|
||||
</Button>
|
||||
<Drawer title="Basic Drawer" onClose={onClose} open={open}>
|
||||
<Drawer
|
||||
title="Basic Drawer"
|
||||
closable={{ 'aria-label': 'Close Button' }}
|
||||
onClose={onClose}
|
||||
open={open}
|
||||
>
|
||||
<p>Some contents...</p>
|
||||
<p>Some contents...</p>
|
||||
<p>Some contents...</p>
|
||||
|
|
|
@ -1,4 +1,5 @@
|
|||
import React from 'react';
|
||||
import { resetWarned } from 'rc-util/lib/warning';
|
||||
|
||||
import mountTest from '../../../tests/shared/mountTest';
|
||||
import rtlTest from '../../../tests/shared/rtlTest';
|
||||
|
@ -170,4 +171,18 @@ describe('DropdownButton', () => {
|
|||
await waitFakeTimer();
|
||||
expect(container.querySelector('.ant-dropdown-menu-item-active')).toBeTruthy();
|
||||
});
|
||||
|
||||
it('legacy destroyPopupOnHide with Dropdown.Button', () => {
|
||||
resetWarned();
|
||||
const errorSpy = jest.spyOn(console, 'error').mockImplementation(() => {});
|
||||
render(
|
||||
<DropdownButton destroyPopupOnHide menu={{ items: [] }}>
|
||||
test
|
||||
</DropdownButton>,
|
||||
);
|
||||
expect(errorSpy).toHaveBeenCalledWith(
|
||||
'Warning: [antd: Dropdown] `destroyPopupOnHide` is deprecated. Please use `destroyOnClose` instead.',
|
||||
);
|
||||
errorSpy.mockRestore();
|
||||
});
|
||||
});
|
||||
|
|
|
@ -1,6 +1,5 @@
|
|||
import React from 'react';
|
||||
import type { TriggerProps } from '@rc-component/trigger';
|
||||
import ConfigProvider from '../../config-provider';
|
||||
|
||||
import type { DropDownProps } from '..';
|
||||
import Dropdown from '..';
|
||||
|
@ -8,6 +7,7 @@ import { resetWarned } from '../../_util/warning';
|
|||
import mountTest from '../../../tests/shared/mountTest';
|
||||
import rtlTest from '../../../tests/shared/rtlTest';
|
||||
import { act, fireEvent, render, waitFakeTimer } from '../../../tests/utils';
|
||||
import ConfigProvider from '../../config-provider';
|
||||
|
||||
let triggerProps: TriggerProps;
|
||||
|
||||
|
@ -130,10 +130,14 @@ describe('Dropdown', () => {
|
|||
</div>,
|
||||
);
|
||||
expect(error).toHaveBeenCalledWith(
|
||||
expect.stringContaining("[antd: Dropdown] You are using 'bottomCenter'"),
|
||||
expect.stringContaining(
|
||||
'[antd: Dropdown] `placement: bottomCenter` is deprecated. Please use `placement: bottom` instead.',
|
||||
),
|
||||
);
|
||||
expect(error).toHaveBeenCalledWith(
|
||||
expect.stringContaining("[antd: Dropdown] You are using 'topCenter'"),
|
||||
expect.stringContaining(
|
||||
'[antd: Dropdown] `placement: topCenter` is deprecated. Please use `placement: top` instead.',
|
||||
),
|
||||
);
|
||||
error.mockRestore();
|
||||
});
|
||||
|
@ -255,6 +259,50 @@ describe('Dropdown', () => {
|
|||
errorSpy.mockRestore();
|
||||
});
|
||||
|
||||
it('legacy dropdownRender & legacy destroyPopupOnHide', () => {
|
||||
resetWarned();
|
||||
const errorSpy = jest.spyOn(console, 'error').mockImplementation(() => {});
|
||||
const dropdownRender = jest.fn((menu) => (
|
||||
<div className="custom-dropdown">
|
||||
{menu}
|
||||
<div className="extra-content">Extra Content</div>
|
||||
</div>
|
||||
));
|
||||
|
||||
const { container } = render(
|
||||
<Dropdown
|
||||
open
|
||||
destroyPopupOnHide
|
||||
dropdownRender={dropdownRender}
|
||||
menu={{
|
||||
items: [
|
||||
{
|
||||
label: <div className="menu-item">Menu Item</div>,
|
||||
key: 'item',
|
||||
},
|
||||
],
|
||||
}}
|
||||
>
|
||||
<a className="trigger" />
|
||||
</Dropdown>,
|
||||
);
|
||||
|
||||
expect(errorSpy).toHaveBeenCalledWith(
|
||||
'Warning: [antd: Dropdown] `dropdownRender` is deprecated. Please use `popupRender` instead.',
|
||||
);
|
||||
expect(errorSpy).toHaveBeenCalledWith(
|
||||
'Warning: [antd: Dropdown] `destroyPopupOnHide` is deprecated. Please use `destroyOnClose` instead.',
|
||||
);
|
||||
|
||||
expect(dropdownRender).toHaveBeenCalled();
|
||||
expect(container.querySelector('.custom-dropdown')).toBeTruthy();
|
||||
expect(container.querySelector('.menu-item')).toBeTruthy();
|
||||
expect(container.querySelector('.extra-content')).toBeTruthy();
|
||||
expect(container.querySelector('.extra-content')?.textContent).toBe('Extra Content');
|
||||
|
||||
errorSpy.mockRestore();
|
||||
});
|
||||
|
||||
it('not block ref', () => {
|
||||
const divRef = React.createRef<HTMLDivElement>();
|
||||
render(
|
||||
|
|
|
@ -50,7 +50,7 @@ const App: React.FC = () => {
|
|||
return (
|
||||
<Dropdown
|
||||
menu={{ items }}
|
||||
dropdownRender={(menu) => (
|
||||
popupRender={(menu) => (
|
||||
<div style={contentStyle}>
|
||||
{React.cloneElement(
|
||||
menu as React.ReactElement<{
|
||||
|
|
|
@ -67,14 +67,18 @@ const DropdownButton: CompoundedComponent = (props) => {
|
|||
mouseLeaveDelay,
|
||||
overlayClassName,
|
||||
overlayStyle,
|
||||
destroyOnClose,
|
||||
destroyPopupOnHide,
|
||||
dropdownRender,
|
||||
popupRender,
|
||||
...restProps
|
||||
} = props;
|
||||
|
||||
const prefixCls = getPrefixCls('dropdown', customizePrefixCls);
|
||||
const buttonPrefixCls = `${prefixCls}-button`;
|
||||
|
||||
const mergedPopupRender = popupRender || dropdownRender;
|
||||
|
||||
const dropdownProps: DropdownProps = {
|
||||
menu,
|
||||
arrow,
|
||||
|
@ -88,14 +92,18 @@ const DropdownButton: CompoundedComponent = (props) => {
|
|||
mouseLeaveDelay,
|
||||
overlayClassName,
|
||||
overlayStyle,
|
||||
destroyPopupOnHide,
|
||||
dropdownRender,
|
||||
destroyOnClose,
|
||||
popupRender: mergedPopupRender,
|
||||
};
|
||||
|
||||
const { compactSize, compactItemClassnames } = useCompactItemContext(prefixCls, direction);
|
||||
|
||||
const classes = classNames(buttonPrefixCls, compactItemClassnames, className);
|
||||
|
||||
if ('destroyPopupOnHide' in props) {
|
||||
dropdownProps.destroyPopupOnHide = destroyPopupOnHide;
|
||||
}
|
||||
|
||||
if ('overlay' in props) {
|
||||
dropdownProps.overlay = overlay;
|
||||
}
|
||||
|
|
|
@ -49,11 +49,18 @@ export interface DropdownProps {
|
|||
autoFocus?: boolean;
|
||||
arrow?: boolean | DropdownArrowOptions;
|
||||
trigger?: ('click' | 'hover' | 'contextMenu')[];
|
||||
/** @deprecated Please use `popupRender` instead */
|
||||
dropdownRender?: (originNode: React.ReactNode) => React.ReactNode;
|
||||
popupRender?: (originNode: React.ReactNode) => React.ReactNode;
|
||||
onOpenChange?: (open: boolean, info: { source: 'trigger' | 'menu' }) => void;
|
||||
open?: boolean;
|
||||
disabled?: boolean;
|
||||
/** @deprecated Please use `destroyOnClose` instead */
|
||||
destroyPopupOnHide?: boolean;
|
||||
/**
|
||||
* @since 5.25.0
|
||||
*/
|
||||
destroyOnClose?: boolean;
|
||||
align?: AlignType;
|
||||
getPopupContainer?: (triggerNode: HTMLElement) => HTMLElement;
|
||||
prefixCls?: string;
|
||||
|
@ -92,6 +99,7 @@ const Dropdown: CompoundedComponent = (props) => {
|
|||
trigger,
|
||||
disabled,
|
||||
dropdownRender,
|
||||
popupRender,
|
||||
getPopupContainer,
|
||||
overlayClassName,
|
||||
rootClassName,
|
||||
|
@ -107,7 +115,10 @@ const Dropdown: CompoundedComponent = (props) => {
|
|||
placement = '',
|
||||
overlay,
|
||||
transitionName,
|
||||
destroyOnClose,
|
||||
destroyPopupOnHide,
|
||||
} = props;
|
||||
|
||||
const {
|
||||
getPopupContainer: getContextPopupContainer,
|
||||
getPrefixCls,
|
||||
|
@ -115,18 +126,31 @@ const Dropdown: CompoundedComponent = (props) => {
|
|||
dropdown,
|
||||
} = React.useContext(ConfigContext);
|
||||
|
||||
const mergedPopupRender = popupRender || dropdownRender;
|
||||
|
||||
// Warning for deprecated usage
|
||||
const warning = devUseWarning('Dropdown');
|
||||
|
||||
if (process.env.NODE_ENV !== 'production') {
|
||||
[
|
||||
['visible', 'open'],
|
||||
['onVisibleChange', 'onOpenChange'],
|
||||
].forEach(([deprecatedName, newName]) => {
|
||||
const deprecatedProps = {
|
||||
visible: 'open',
|
||||
onVisibleChange: 'onOpenChange',
|
||||
overlay: 'menu',
|
||||
dropdownRender: 'popupRender',
|
||||
destroyPopupOnHide: 'destroyOnClose',
|
||||
};
|
||||
|
||||
Object.entries(deprecatedProps).forEach(([deprecatedName, newName]) => {
|
||||
warning.deprecated(!(deprecatedName in props), deprecatedName, newName);
|
||||
});
|
||||
|
||||
warning.deprecated(!('overlay' in props), 'overlay', 'menu');
|
||||
if (placement.includes('Center')) {
|
||||
warning.deprecated(
|
||||
!placement.includes('Center'),
|
||||
`placement: ${placement}`,
|
||||
`placement: ${placement.slice(0, placement.indexOf('Center'))}`,
|
||||
);
|
||||
}
|
||||
}
|
||||
|
||||
const memoTransitionName = React.useMemo<string>(() => {
|
||||
|
@ -153,24 +177,6 @@ const Dropdown: CompoundedComponent = (props) => {
|
|||
return placement as DropdownPlacement;
|
||||
}, [placement, direction]);
|
||||
|
||||
if (process.env.NODE_ENV !== 'production') {
|
||||
if (placement.includes('Center')) {
|
||||
const newPlacement = placement.slice(0, placement.indexOf('Center')) as DropdownPlacement;
|
||||
warning(
|
||||
!placement.includes('Center'),
|
||||
'deprecated',
|
||||
`You are using '${placement}' placement in Dropdown, which is deprecated. Try to use '${newPlacement}' instead.`,
|
||||
);
|
||||
}
|
||||
|
||||
[
|
||||
['visible', 'open'],
|
||||
['onVisibleChange', 'onOpenChange'],
|
||||
].forEach(([deprecatedName, newName]) => {
|
||||
warning.deprecated(!(deprecatedName in props), deprecatedName, newName);
|
||||
});
|
||||
}
|
||||
|
||||
const prefixCls = getPrefixCls('dropdown', customizePrefixCls);
|
||||
const rootCls = useCSSVarCls(prefixCls);
|
||||
const [wrapCSSVar, hashId, cssVarCls] = useStyle(prefixCls, rootCls);
|
||||
|
@ -184,7 +190,7 @@ const Dropdown: CompoundedComponent = (props) => {
|
|||
disabled?: boolean;
|
||||
}>;
|
||||
|
||||
const dropdownTrigger = cloneElement(child, {
|
||||
const popupTrigger = cloneElement(child, {
|
||||
className: classNames(
|
||||
`${prefixCls}-trigger`,
|
||||
{
|
||||
|
@ -247,8 +253,8 @@ const Dropdown: CompoundedComponent = (props) => {
|
|||
} else {
|
||||
overlayNode = overlay;
|
||||
}
|
||||
if (dropdownRender) {
|
||||
overlayNode = dropdownRender(overlayNode);
|
||||
if (mergedPopupRender) {
|
||||
overlayNode = mergedPopupRender(overlayNode);
|
||||
}
|
||||
overlayNode = React.Children.only(
|
||||
typeof overlayNode === 'string' ? <span>{overlayNode}</span> : overlayNode,
|
||||
|
@ -305,8 +311,9 @@ const Dropdown: CompoundedComponent = (props) => {
|
|||
placement={memoPlacement}
|
||||
onVisibleChange={onInnerOpenChange}
|
||||
overlayStyle={{ ...dropdown?.style, ...overlayStyle, zIndex }}
|
||||
autoDestroy={destroyOnClose ?? destroyPopupOnHide}
|
||||
>
|
||||
{dropdownTrigger}
|
||||
{popupTrigger}
|
||||
</RcDropdown>
|
||||
);
|
||||
|
||||
|
|
|
@ -48,8 +48,10 @@ Common props ref:[Common props](/docs/react/common-props)
|
|||
| autoAdjustOverflow | Whether to adjust dropdown placement automatically when dropdown is off screen | boolean | true | 5.2.0 |
|
||||
| autoFocus | Focus element in `overlay` when opened | boolean | false | 4.21.0 |
|
||||
| disabled | Whether the dropdown menu is disabled | boolean | - | |
|
||||
| destroyPopupOnHide | Whether destroy dropdown when hidden | boolean | false | |
|
||||
| dropdownRender | Customize dropdown content | (menus: ReactNode) => ReactNode | - | 4.24.0 |
|
||||
| ~~destroyPopupOnHide~~ | Whether destroy dropdown when hidden, use `destroyOnClose` instead | boolean | false | |
|
||||
| destroyOnClose | Whether destroy dropdown when hidden | boolean | false | 5.25.0 |
|
||||
| ~~dropdownRender~~ | Customize dropdown content, use `popupRender` instead | (menus: ReactNode) => ReactNode | - | 4.24.0 |
|
||||
| popupRender | Customize popup content | (menus: ReactNode) => ReactNode | - | 5.25.0 |
|
||||
| getPopupContainer | To set the container of the dropdown menu. The default is to create a div element in body, but you can reset it to the scrolling area and make a relative reposition. [Example on CodePen](https://codepen.io/afc163/pen/zEjNOy?editors=0010) | (triggerNode: HTMLElement) => HTMLElement | () => document.body | |
|
||||
| menu | The menu props | [MenuProps](/components/menu/#api) | - | 4.24.0 |
|
||||
| overlayClassName | The class name of the dropdown root element | string | - | |
|
||||
|
|
|
@ -52,8 +52,10 @@ demo:
|
|||
| autoAdjustOverflow | 下拉框被遮挡时自动调整位置 | boolean | true | 5.2.0 |
|
||||
| autoFocus | 打开后自动聚焦下拉框 | boolean | false | 4.21.0 |
|
||||
| disabled | 菜单是否禁用 | boolean | - | |
|
||||
| destroyPopupOnHide | 关闭后是否销毁 Dropdown | boolean | false | |
|
||||
| dropdownRender | 自定义下拉框内容 | (menus: ReactNode) => ReactNode | - | 4.24.0 |
|
||||
| ~~destroyPopupOnHide~~ | 关闭后是否销毁 Dropdown,使用 `destroyOnClose` 替换 | boolean | false | |
|
||||
| destroyOnClose | 关闭后是否销毁 Dropdown | boolean | false | 5.25.0 |
|
||||
| ~~dropdownRender~~ | 自定义下拉框内容,使用 `popupRender` 替换 | (menus: ReactNode) => ReactNode | - | 4.24.0 |
|
||||
| popupRender | 自定义弹出框内容 | (menus: ReactNode) => ReactNode | - | 5.25.0 |
|
||||
| getPopupContainer | 菜单渲染父节点。默认渲染到 body 上,如果你遇到菜单滚动定位问题,试试修改为滚动的区域,并相对其定位。[示例](https://codepen.io/afc163/pen/zEjNOy?editors=0010) | (triggerNode: HTMLElement) => HTMLElement | () => document.body | |
|
||||
| menu | 菜单配置项 | [MenuProps](/components/menu-cn#api) | - | 4.24.0 |
|
||||
| overlayClassName | 下拉根元素的类名称 | string | - | |
|
||||
|
|
|
@ -2,6 +2,7 @@ import React, { useContext } from 'react';
|
|||
import classNames from 'classnames';
|
||||
import omit from 'rc-util/lib/omit';
|
||||
|
||||
import convertToTooltipProps from '../_util/convertToTooltipProps';
|
||||
import { useZIndex } from '../_util/hooks/useZIndex';
|
||||
import { devUseWarning } from '../_util/warning';
|
||||
import Badge from '../badge';
|
||||
|
@ -74,12 +75,10 @@ const InternalFloatButton = React.forwardRef<FloatButtonElement, FloatButtonProp
|
|||
buttonNode = <Badge {...badgeProps}>{buttonNode}</Badge>;
|
||||
}
|
||||
|
||||
if ('tooltip' in props) {
|
||||
buttonNode = (
|
||||
<Tooltip title={tooltip} placement={direction === 'rtl' ? 'right' : 'left'}>
|
||||
{buttonNode}
|
||||
</Tooltip>
|
||||
);
|
||||
// ============================ Tooltip ============================
|
||||
const tooltipProps = convertToTooltipProps(tooltip);
|
||||
if (tooltipProps) {
|
||||
buttonNode = <Tooltip {...tooltipProps}>{buttonNode}</Tooltip>;
|
||||
}
|
||||
|
||||
if (process.env.NODE_ENV !== 'production') {
|
||||
|
|
|
@ -140,12 +140,12 @@ Array [
|
|||
</sup>
|
||||
</span>
|
||||
<div
|
||||
class="ant-tooltip ant-zoom-big-fast-appear ant-zoom-big-fast-appear-prepare ant-zoom-big-fast ant-tooltip-placement-left"
|
||||
class="ant-tooltip ant-zoom-big-fast-appear ant-zoom-big-fast-appear-prepare ant-zoom-big-fast 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; top: 0px; right: 0px;"
|
||||
style="position: absolute; bottom: 0px; left: 0px;"
|
||||
/>
|
||||
<div
|
||||
class="ant-tooltip-content"
|
||||
|
@ -2038,65 +2038,125 @@ Array [
|
|||
exports[`renders components/float-button/demo/shape.tsx extend context correctly 2`] = `[]`;
|
||||
|
||||
exports[`renders components/float-button/demo/tooltip.tsx extend context correctly 1`] = `
|
||||
<button
|
||||
class="ant-float-btn ant-float-btn-default ant-float-btn-circle"
|
||||
type="button"
|
||||
>
|
||||
<div
|
||||
aria-describedby="test-id"
|
||||
class="ant-float-btn-body"
|
||||
Array [
|
||||
<button
|
||||
class="ant-float-btn ant-float-btn-default ant-float-btn-circle"
|
||||
style="inset-block-end: 108px;"
|
||||
type="button"
|
||||
>
|
||||
<div
|
||||
class="ant-float-btn-content"
|
||||
aria-describedby="test-id"
|
||||
class="ant-float-btn-body"
|
||||
>
|
||||
<div
|
||||
class="ant-float-btn-icon"
|
||||
class="ant-float-btn-content"
|
||||
>
|
||||
<span
|
||||
aria-label="file-text"
|
||||
class="anticon anticon-file-text"
|
||||
role="img"
|
||||
<div
|
||||
class="ant-float-btn-icon"
|
||||
>
|
||||
<svg
|
||||
aria-hidden="true"
|
||||
data-icon="file-text"
|
||||
fill="currentColor"
|
||||
focusable="false"
|
||||
height="1em"
|
||||
viewBox="64 64 896 896"
|
||||
width="1em"
|
||||
<span
|
||||
aria-label="file-text"
|
||||
class="anticon anticon-file-text"
|
||||
role="img"
|
||||
>
|
||||
<path
|
||||
d="M854.6 288.6L639.4 73.4c-6-6-14.1-9.4-22.6-9.4H192c-17.7 0-32 14.3-32 32v832c0 17.7 14.3 32 32 32h640c17.7 0 32-14.3 32-32V311.3c0-8.5-3.4-16.7-9.4-22.7zM790.2 326H602V137.8L790.2 326zm1.8 562H232V136h302v216a42 42 0 0042 42h216v494zM504 618H320c-4.4 0-8 3.6-8 8v48c0 4.4 3.6 8 8 8h184c4.4 0 8-3.6 8-8v-48c0-4.4-3.6-8-8-8zM312 490v48c0 4.4 3.6 8 8 8h384c4.4 0 8-3.6 8-8v-48c0-4.4-3.6-8-8-8H320c-4.4 0-8 3.6-8 8z"
|
||||
/>
|
||||
</svg>
|
||||
</span>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
<div
|
||||
class="ant-tooltip ant-zoom-big-fast-appear ant-zoom-big-fast-appear-prepare ant-zoom-big-fast ant-tooltip-placement-left"
|
||||
style="--arrow-x: 0px; --arrow-y: 0px; left: -1000vw; top: -1000vh; box-sizing: border-box;"
|
||||
>
|
||||
<div
|
||||
class="ant-tooltip-arrow"
|
||||
style="position: absolute; top: 0px; right: 0px;"
|
||||
/>
|
||||
<div
|
||||
class="ant-tooltip-content"
|
||||
>
|
||||
<div
|
||||
class="ant-tooltip-inner"
|
||||
id="test-id"
|
||||
role="tooltip"
|
||||
>
|
||||
<div>
|
||||
Documents
|
||||
<svg
|
||||
aria-hidden="true"
|
||||
data-icon="file-text"
|
||||
fill="currentColor"
|
||||
focusable="false"
|
||||
height="1em"
|
||||
viewBox="64 64 896 896"
|
||||
width="1em"
|
||||
>
|
||||
<path
|
||||
d="M854.6 288.6L639.4 73.4c-6-6-14.1-9.4-22.6-9.4H192c-17.7 0-32 14.3-32 32v832c0 17.7 14.3 32 32 32h640c17.7 0 32-14.3 32-32V311.3c0-8.5-3.4-16.7-9.4-22.7zM790.2 326H602V137.8L790.2 326zm1.8 562H232V136h302v216a42 42 0 0042 42h216v494zM504 618H320c-4.4 0-8 3.6-8 8v48c0 4.4 3.6 8 8 8h184c4.4 0 8-3.6 8-8v-48c0-4.4-3.6-8-8-8zM312 490v48c0 4.4 3.6 8 8 8h384c4.4 0 8-3.6 8-8v-48c0-4.4-3.6-8-8-8H320c-4.4 0-8 3.6-8 8z"
|
||||
/>
|
||||
</svg>
|
||||
</span>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
</button>
|
||||
<div
|
||||
class="ant-tooltip ant-zoom-big-fast-appear ant-zoom-big-fast-appear-prepare ant-zoom-big-fast ant-tooltip-blue 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"
|
||||
id="test-id"
|
||||
role="tooltip"
|
||||
>
|
||||
Since 5.25.0+
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
</button>,
|
||||
<button
|
||||
class="ant-float-btn ant-float-btn-default ant-float-btn-circle"
|
||||
type="button"
|
||||
>
|
||||
<div
|
||||
aria-describedby="test-id"
|
||||
class="ant-float-btn-body"
|
||||
>
|
||||
<div
|
||||
class="ant-float-btn-content"
|
||||
>
|
||||
<div
|
||||
class="ant-float-btn-icon"
|
||||
>
|
||||
<span
|
||||
aria-label="file-text"
|
||||
class="anticon anticon-file-text"
|
||||
role="img"
|
||||
>
|
||||
<svg
|
||||
aria-hidden="true"
|
||||
data-icon="file-text"
|
||||
fill="currentColor"
|
||||
focusable="false"
|
||||
height="1em"
|
||||
viewBox="64 64 896 896"
|
||||
width="1em"
|
||||
>
|
||||
<path
|
||||
d="M854.6 288.6L639.4 73.4c-6-6-14.1-9.4-22.6-9.4H192c-17.7 0-32 14.3-32 32v832c0 17.7 14.3 32 32 32h640c17.7 0 32-14.3 32-32V311.3c0-8.5-3.4-16.7-9.4-22.7zM790.2 326H602V137.8L790.2 326zm1.8 562H232V136h302v216a42 42 0 0042 42h216v494zM504 618H320c-4.4 0-8 3.6-8 8v48c0 4.4 3.6 8 8 8h184c4.4 0 8-3.6 8-8v-48c0-4.4-3.6-8-8-8zM312 490v48c0 4.4 3.6 8 8 8h384c4.4 0 8-3.6 8-8v-48c0-4.4-3.6-8-8-8H320c-4.4 0-8 3.6-8 8z"
|
||||
/>
|
||||
</svg>
|
||||
</span>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
<div
|
||||
class="ant-tooltip ant-zoom-big-fast-appear ant-zoom-big-fast-appear-prepare ant-zoom-big-fast 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"
|
||||
id="test-id"
|
||||
role="tooltip"
|
||||
>
|
||||
<div>
|
||||
Documents
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
</button>,
|
||||
]
|
||||
`;
|
||||
|
||||
exports[`renders components/float-button/demo/tooltip.tsx extend context correctly 2`] = `[]`;
|
||||
|
|
|
@ -1974,43 +1974,83 @@ Array [
|
|||
`;
|
||||
|
||||
exports[`renders components/float-button/demo/tooltip.tsx correctly 1`] = `
|
||||
<button
|
||||
class="ant-float-btn ant-float-btn-default ant-float-btn-circle"
|
||||
type="button"
|
||||
>
|
||||
<div
|
||||
aria-describedby="test-id"
|
||||
class="ant-float-btn-body"
|
||||
Array [
|
||||
<button
|
||||
class="ant-float-btn ant-float-btn-default ant-float-btn-circle"
|
||||
style="inset-block-end:108px"
|
||||
type="button"
|
||||
>
|
||||
<div
|
||||
class="ant-float-btn-content"
|
||||
aria-describedby="test-id"
|
||||
class="ant-float-btn-body"
|
||||
>
|
||||
<div
|
||||
class="ant-float-btn-icon"
|
||||
class="ant-float-btn-content"
|
||||
>
|
||||
<span
|
||||
aria-label="file-text"
|
||||
class="anticon anticon-file-text"
|
||||
role="img"
|
||||
<div
|
||||
class="ant-float-btn-icon"
|
||||
>
|
||||
<svg
|
||||
aria-hidden="true"
|
||||
data-icon="file-text"
|
||||
fill="currentColor"
|
||||
focusable="false"
|
||||
height="1em"
|
||||
viewBox="64 64 896 896"
|
||||
width="1em"
|
||||
<span
|
||||
aria-label="file-text"
|
||||
class="anticon anticon-file-text"
|
||||
role="img"
|
||||
>
|
||||
<path
|
||||
d="M854.6 288.6L639.4 73.4c-6-6-14.1-9.4-22.6-9.4H192c-17.7 0-32 14.3-32 32v832c0 17.7 14.3 32 32 32h640c17.7 0 32-14.3 32-32V311.3c0-8.5-3.4-16.7-9.4-22.7zM790.2 326H602V137.8L790.2 326zm1.8 562H232V136h302v216a42 42 0 0042 42h216v494zM504 618H320c-4.4 0-8 3.6-8 8v48c0 4.4 3.6 8 8 8h184c4.4 0 8-3.6 8-8v-48c0-4.4-3.6-8-8-8zM312 490v48c0 4.4 3.6 8 8 8h384c4.4 0 8-3.6 8-8v-48c0-4.4-3.6-8-8-8H320c-4.4 0-8 3.6-8 8z"
|
||||
/>
|
||||
</svg>
|
||||
</span>
|
||||
<svg
|
||||
aria-hidden="true"
|
||||
data-icon="file-text"
|
||||
fill="currentColor"
|
||||
focusable="false"
|
||||
height="1em"
|
||||
viewBox="64 64 896 896"
|
||||
width="1em"
|
||||
>
|
||||
<path
|
||||
d="M854.6 288.6L639.4 73.4c-6-6-14.1-9.4-22.6-9.4H192c-17.7 0-32 14.3-32 32v832c0 17.7 14.3 32 32 32h640c17.7 0 32-14.3 32-32V311.3c0-8.5-3.4-16.7-9.4-22.7zM790.2 326H602V137.8L790.2 326zm1.8 562H232V136h302v216a42 42 0 0042 42h216v494zM504 618H320c-4.4 0-8 3.6-8 8v48c0 4.4 3.6 8 8 8h184c4.4 0 8-3.6 8-8v-48c0-4.4-3.6-8-8-8zM312 490v48c0 4.4 3.6 8 8 8h384c4.4 0 8-3.6 8-8v-48c0-4.4-3.6-8-8-8H320c-4.4 0-8 3.6-8 8z"
|
||||
/>
|
||||
</svg>
|
||||
</span>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
</button>
|
||||
</button>,
|
||||
<button
|
||||
class="ant-float-btn ant-float-btn-default ant-float-btn-circle"
|
||||
type="button"
|
||||
>
|
||||
<div
|
||||
aria-describedby="test-id"
|
||||
class="ant-float-btn-body"
|
||||
>
|
||||
<div
|
||||
class="ant-float-btn-content"
|
||||
>
|
||||
<div
|
||||
class="ant-float-btn-icon"
|
||||
>
|
||||
<span
|
||||
aria-label="file-text"
|
||||
class="anticon anticon-file-text"
|
||||
role="img"
|
||||
>
|
||||
<svg
|
||||
aria-hidden="true"
|
||||
data-icon="file-text"
|
||||
fill="currentColor"
|
||||
focusable="false"
|
||||
height="1em"
|
||||
viewBox="64 64 896 896"
|
||||
width="1em"
|
||||
>
|
||||
<path
|
||||
d="M854.6 288.6L639.4 73.4c-6-6-14.1-9.4-22.6-9.4H192c-17.7 0-32 14.3-32 32v832c0 17.7 14.3 32 32 32h640c17.7 0 32-14.3 32-32V311.3c0-8.5-3.4-16.7-9.4-22.7zM790.2 326H602V137.8L790.2 326zm1.8 562H232V136h302v216a42 42 0 0042 42h216v494zM504 618H320c-4.4 0-8 3.6-8 8v48c0 4.4 3.6 8 8 8h184c4.4 0 8-3.6 8-8v-48c0-4.4-3.6-8-8-8zM312 490v48c0 4.4 3.6 8 8 8h384c4.4 0 8-3.6 8-8v-48c0-4.4-3.6-8-8-8H320c-4.4 0-8 3.6-8 8z"
|
||||
/>
|
||||
</svg>
|
||||
</span>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
</button>,
|
||||
]
|
||||
`;
|
||||
|
||||
exports[`renders components/float-button/demo/type.tsx correctly 1`] = `
|
||||
|
|
|
@ -63,15 +63,27 @@ describe('FloatButton', () => {
|
|||
errSpy.mockRestore();
|
||||
});
|
||||
|
||||
it('tooltip should support number `0`', async () => {
|
||||
jest.useFakeTimers();
|
||||
const { container } = render(<FloatButton tooltip={0} />);
|
||||
fireEvent.mouseEnter(container.querySelector<HTMLDivElement>('.ant-float-btn-body')!);
|
||||
await waitFakeTimer();
|
||||
const element = container.querySelector('.ant-tooltip')?.querySelector('.ant-tooltip-inner');
|
||||
expect(element?.textContent).toBe('0');
|
||||
jest.clearAllTimers();
|
||||
jest.useRealTimers();
|
||||
describe('tooltip', () => {
|
||||
it('tooltip should support number `0`', async () => {
|
||||
jest.useFakeTimers();
|
||||
const { container } = render(<FloatButton tooltip={0} />);
|
||||
fireEvent.mouseEnter(container.querySelector<HTMLDivElement>('.ant-float-btn-body')!);
|
||||
await waitFakeTimer();
|
||||
const element = container.querySelector('.ant-tooltip')?.querySelector('.ant-tooltip-inner');
|
||||
expect(element?.textContent).toBe('0');
|
||||
jest.clearAllTimers();
|
||||
jest.useRealTimers();
|
||||
});
|
||||
it('tooltip should support tooltipProps', async () => {
|
||||
jest.useFakeTimers();
|
||||
const { container } = render(<FloatButton tooltip={{ title: 'hi' }} />);
|
||||
fireEvent.mouseEnter(container.querySelector<HTMLDivElement>('.ant-float-btn-body')!);
|
||||
await waitFakeTimer();
|
||||
const element = container.querySelector('.ant-tooltip')?.querySelector('.ant-tooltip-inner');
|
||||
expect(element?.textContent).toBe('hi');
|
||||
jest.clearAllTimers();
|
||||
jest.useRealTimers();
|
||||
});
|
||||
});
|
||||
|
||||
it('getOffset should return 0 when radius is 0', () => {
|
||||
|
|
|
@ -1,6 +1,19 @@
|
|||
import React from 'react';
|
||||
import { FloatButton } from 'antd';
|
||||
|
||||
const App: React.FC = () => <FloatButton tooltip={<div>Documents</div>} />;
|
||||
const App: React.FC = () => (
|
||||
<>
|
||||
<FloatButton
|
||||
style={{ insetBlockEnd: 108 }}
|
||||
tooltip={{
|
||||
// tooltipProps is supported starting from version 5.25.0.
|
||||
title: 'Since 5.25.0+',
|
||||
color: 'blue',
|
||||
placement: 'top',
|
||||
}}
|
||||
/>
|
||||
<FloatButton tooltip={<div>Documents</div>} />
|
||||
</>
|
||||
);
|
||||
|
||||
export default App;
|
||||
|
|
|
@ -44,7 +44,7 @@ Common props ref:[Common props](/docs/react/common-props)
|
|||
| --- | --- | --- | --- | --- |
|
||||
| icon | Set the icon component of button | ReactNode | - | |
|
||||
| description | Text and other | ReactNode | - | |
|
||||
| tooltip | The text shown in the tooltip | ReactNode \| () => ReactNode | | |
|
||||
| tooltip | The text shown in the tooltip | ReactNode \| [TooltipProps](/components/tooltip#api) | - | TooltipProps: 5.25.0 |
|
||||
| type | Setting button type | `default` \| `primary` | `default` | |
|
||||
| shape | Setting button shape | `circle` \| `square` | `circle` | |
|
||||
| onClick | Set the handler to handle `click` event | (event) => void | - | |
|
||||
|
|
|
@ -45,7 +45,7 @@ tag: 5.0.0
|
|||
| --- | --- | --- | --- | --- |
|
||||
| icon | 自定义图标 | ReactNode | - | |
|
||||
| description | 文字及其它内容 | ReactNode | - | |
|
||||
| tooltip | 气泡卡片的内容 | ReactNode \| () => ReactNode | - | |
|
||||
| tooltip | 气泡卡片的内容 | ReactNode \| [TooltipProps](/components/tooltip-cn#api) | - | TooltipProps: 5.25.0 |
|
||||
| type | 设置按钮类型 | `default` \| `primary` | `default` | |
|
||||
| shape | 设置按钮形状 | `circle` \| `square` | `circle` | |
|
||||
| onClick | 点击按钮时的回调 | (event) => void | - | |
|
||||
|
|
|
@ -27,7 +27,7 @@ export interface FloatButtonProps extends React.DOMAttributes<FloatButtonElement
|
|||
description?: React.ReactNode;
|
||||
type?: FloatButtonType;
|
||||
shape?: FloatButtonShape;
|
||||
tooltip?: TooltipProps['title'];
|
||||
tooltip?: React.ReactNode | TooltipProps;
|
||||
href?: string;
|
||||
target?: React.HTMLAttributeAnchorTarget;
|
||||
badge?: FloatButtonBadgeProps;
|
||||
|
|
|
@ -2,6 +2,7 @@ import * as React from 'react';
|
|||
import QuestionCircleOutlined from '@ant-design/icons/QuestionCircleOutlined';
|
||||
import classNames from 'classnames';
|
||||
|
||||
import convertToTooltipProps from '../_util/convertToTooltipProps';
|
||||
import type { ColProps } from '../grid/col';
|
||||
import Col from '../grid/col';
|
||||
import { useLocale } from '../locale';
|
||||
|
@ -19,20 +20,6 @@ export type WrapperTooltipProps = TooltipProps & {
|
|||
|
||||
export type LabelTooltipType = WrapperTooltipProps | React.ReactNode;
|
||||
|
||||
function toTooltipProps(tooltip: LabelTooltipType): WrapperTooltipProps | null {
|
||||
if (!tooltip) {
|
||||
return null;
|
||||
}
|
||||
|
||||
if (typeof tooltip === 'object' && !React.isValidElement(tooltip)) {
|
||||
return tooltip as WrapperTooltipProps;
|
||||
}
|
||||
|
||||
return {
|
||||
title: tooltip,
|
||||
};
|
||||
}
|
||||
|
||||
export interface FormItemLabelProps {
|
||||
colon?: boolean;
|
||||
htmlFor?: string;
|
||||
|
@ -98,7 +85,7 @@ const FormItemLabel: React.FC<FormItemLabelProps & { required?: boolean; prefixC
|
|||
}
|
||||
|
||||
// Tooltip
|
||||
const tooltipProps = toTooltipProps(tooltip);
|
||||
const tooltipProps = convertToTooltipProps(tooltip);
|
||||
|
||||
if (tooltipProps) {
|
||||
const { icon = <QuestionCircleOutlined />, ...restTooltipProps } = tooltipProps;
|
||||
|
|
|
@ -42,7 +42,14 @@ exports[`Grid should render Row 1`] = `
|
|||
/>
|
||||
`;
|
||||
|
||||
exports[`Grid when typeof gutter is object array in large screen 1`] = `
|
||||
exports[`Grid when typeof gutter is object array in large screen 0 1`] = `
|
||||
<div
|
||||
class="ant-row"
|
||||
style="margin-left: -20px; margin-right: -20px; row-gap: 400px;"
|
||||
/>
|
||||
`;
|
||||
|
||||
exports[`Grid when typeof gutter is object array in large screen 1 1`] = `
|
||||
<div
|
||||
class="ant-row"
|
||||
style="margin-left: -20px; margin-right: -20px; row-gap: 400px;"
|
||||
|
|
|
@ -6,6 +6,27 @@ import rtlTest from '../../../tests/shared/rtlTest';
|
|||
import { fireEvent, render } from '../../../tests/utils';
|
||||
import useBreakpoint from '../hooks/useBreakpoint';
|
||||
|
||||
const createImplFn = (value: string | number) => {
|
||||
return [
|
||||
(query: string) => ({
|
||||
matches: query === value,
|
||||
addEventListener: (type: string, cb: (e: { matches: boolean }) => void) => {
|
||||
if (type === 'change') {
|
||||
cb({ matches: query === value });
|
||||
}
|
||||
},
|
||||
removeEventListener: jest.fn(),
|
||||
}),
|
||||
(query: string) => ({
|
||||
matches: query === value,
|
||||
addListener: (cb: (e: { matches: boolean }) => void) => {
|
||||
cb({ matches: query === value });
|
||||
},
|
||||
removeListener: jest.fn(),
|
||||
}),
|
||||
];
|
||||
};
|
||||
|
||||
// Mock for `responsiveObserve` to test `unsubscribe` call
|
||||
jest.mock('../../_util/responsiveObserver', () => {
|
||||
const modules = jest.requireActual('../../_util/responsiveObserver');
|
||||
|
@ -74,36 +95,27 @@ describe('Grid', () => {
|
|||
expect(container.querySelector('div')!.style.marginRight).toEqual('-4px');
|
||||
});
|
||||
|
||||
it('when typeof gutter is object array in large screen', () => {
|
||||
jest.spyOn(window, 'matchMedia').mockImplementation(
|
||||
(query) =>
|
||||
({
|
||||
addListener: (cb: (e: { matches: boolean }) => void) => {
|
||||
cb({ matches: query === '(min-width: 1200px)' });
|
||||
},
|
||||
removeListener: jest.fn(),
|
||||
matches: query === '(min-width: 1200px)',
|
||||
}) as any,
|
||||
);
|
||||
|
||||
const { container, asFragment } = render(
|
||||
<Row
|
||||
gutter={[
|
||||
{ xs: 8, sm: 16, md: 24, lg: 32, xl: 40 },
|
||||
{ xs: 8, sm: 16, md: 24, lg: 100, xl: 400 },
|
||||
]}
|
||||
/>,
|
||||
);
|
||||
expect(asFragment().firstChild).toMatchSnapshot();
|
||||
|
||||
expect(container.querySelector('div')?.style.marginLeft).toBe('-20px');
|
||||
expect(container.querySelector('div')?.style.marginRight).toBe('-20px');
|
||||
expect(container.querySelector('div')?.style.marginTop).toBe('');
|
||||
expect(container.querySelector('div')?.style.marginBottom).toBe('');
|
||||
createImplFn('(min-width: 1200px)').forEach((impl, i) => {
|
||||
it(`when typeof gutter is object array in large screen ${i}`, () => {
|
||||
jest.spyOn(window, 'matchMedia').mockImplementation(impl as any);
|
||||
const { container, asFragment } = render(
|
||||
<Row
|
||||
gutter={[
|
||||
{ xs: 8, sm: 16, md: 24, lg: 32, xl: 40 },
|
||||
{ xs: 8, sm: 16, md: 24, lg: 100, xl: 400 },
|
||||
]}
|
||||
/>,
|
||||
);
|
||||
expect(asFragment().firstChild).toMatchSnapshot();
|
||||
expect(container.querySelector('div')?.style.marginLeft).toBe('-20px');
|
||||
expect(container.querySelector('div')?.style.marginRight).toBe('-20px');
|
||||
expect(container.querySelector('div')?.style.marginTop).toBe('');
|
||||
expect(container.querySelector('div')?.style.marginBottom).toBe('');
|
||||
});
|
||||
});
|
||||
|
||||
it('renders wrapped Col correctly', () => {
|
||||
const MyCol = () => <Col span={12} />;
|
||||
const MyCol: React.FC = () => <Col span={12} />;
|
||||
const { asFragment } = render(
|
||||
<Row gutter={20}>
|
||||
<div>
|
||||
|
@ -112,7 +124,6 @@ describe('Grid', () => {
|
|||
<MyCol />
|
||||
</Row>,
|
||||
);
|
||||
|
||||
expect(asFragment().firstChild).toMatchSnapshot();
|
||||
});
|
||||
|
||||
|
@ -140,75 +151,49 @@ describe('Grid', () => {
|
|||
|
||||
// By jsdom mock, actual jsdom not implemented matchMedia
|
||||
// https://jestjs.io/docs/en/manual-mocks#mocking-methods-which-are-not-implemented-in-jsdom
|
||||
it('should work with useBreakpoint', () => {
|
||||
const matchMediaSpy = jest.spyOn(window, 'matchMedia');
|
||||
matchMediaSpy.mockImplementation(
|
||||
(query) =>
|
||||
({
|
||||
addListener: (cb: (e: { matches: boolean }) => void) => {
|
||||
cb({ matches: query === '(max-width: 575px)' });
|
||||
},
|
||||
removeListener: jest.fn(),
|
||||
matches: query === '(max-width: 575px)',
|
||||
}) as any,
|
||||
);
|
||||
|
||||
let screensVar: any = null;
|
||||
function Demo() {
|
||||
const screens = useBreakpoint();
|
||||
screensVar = screens;
|
||||
return <div />;
|
||||
}
|
||||
render(<Demo />);
|
||||
|
||||
expect(screensVar).toEqual({
|
||||
xs: true,
|
||||
sm: false,
|
||||
md: false,
|
||||
lg: false,
|
||||
xl: false,
|
||||
xxl: false,
|
||||
createImplFn('(max-width: 575px)').forEach((impl, i) => {
|
||||
it(`should work with useBreakpoint ${i}`, () => {
|
||||
jest.spyOn(window, 'matchMedia').mockImplementation(impl as any);
|
||||
let screensVar: any = null;
|
||||
const Demo: React.FC = () => {
|
||||
const screens = useBreakpoint();
|
||||
screensVar = screens;
|
||||
return null;
|
||||
};
|
||||
render(<Demo />);
|
||||
expect(screensVar).toEqual({
|
||||
xs: true,
|
||||
sm: false,
|
||||
md: false,
|
||||
lg: false,
|
||||
xl: false,
|
||||
xxl: false,
|
||||
});
|
||||
});
|
||||
});
|
||||
|
||||
it('should align by responsive align prop', () => {
|
||||
const matchMediaSpy = jest.spyOn(window, 'matchMedia');
|
||||
matchMediaSpy.mockImplementation(
|
||||
(query) =>
|
||||
({
|
||||
addListener: (cb: (e: { matches: boolean }) => void) => {
|
||||
cb({ matches: query === '(max-width: 575px)' });
|
||||
},
|
||||
removeListener: jest.fn(),
|
||||
matches: query === '(max-width: 575px)',
|
||||
}) as any,
|
||||
);
|
||||
const { container } = render(<Row align="middle" />);
|
||||
expect(container.innerHTML).toContain('ant-row-middle');
|
||||
const { container: container2 } = render(<Row align={{ xs: 'middle' }} />);
|
||||
expect(container2.innerHTML).toContain('ant-row-middle');
|
||||
const { container: container3 } = render(<Row align={{ lg: 'middle' }} />);
|
||||
expect(container3.innerHTML).not.toContain('ant-row-middle');
|
||||
createImplFn('(max-width: 575px)').forEach((impl, i) => {
|
||||
it(`should align by responsive align prop ${i}`, () => {
|
||||
jest.spyOn(window, 'matchMedia').mockImplementation(impl as any);
|
||||
const { container } = render(<Row align="middle" />);
|
||||
expect(container.innerHTML).toContain('ant-row-middle');
|
||||
const { container: container2 } = render(<Row align={{ xs: 'middle' }} />);
|
||||
expect(container2.innerHTML).toContain('ant-row-middle');
|
||||
const { container: container3 } = render(<Row align={{ lg: 'middle' }} />);
|
||||
expect(container3.innerHTML).not.toContain('ant-row-middle');
|
||||
});
|
||||
});
|
||||
|
||||
it('should justify by responsive justify prop', () => {
|
||||
const matchMediaSpy = jest.spyOn(window, 'matchMedia');
|
||||
matchMediaSpy.mockImplementation(
|
||||
(query) =>
|
||||
({
|
||||
addListener: (cb: (e: { matches: boolean }) => void) => {
|
||||
cb({ matches: query === '(max-width: 575px)' });
|
||||
},
|
||||
removeListener: jest.fn(),
|
||||
matches: query === '(max-width: 575px)',
|
||||
}) as any,
|
||||
);
|
||||
const { container } = render(<Row justify="center" />);
|
||||
expect(container.innerHTML).toContain('ant-row-center');
|
||||
const { container: container2 } = render(<Row justify={{ xs: 'center' }} />);
|
||||
expect(container2.innerHTML).toContain('ant-row-center');
|
||||
const { container: container3 } = render(<Row justify={{ lg: 'center' }} />);
|
||||
expect(container3.innerHTML).not.toContain('ant-row-center');
|
||||
createImplFn('(max-width: 575px)').forEach((impl, i) => {
|
||||
it(`should justify by responsive justify prop ${i}`, () => {
|
||||
jest.spyOn(window, 'matchMedia').mockImplementation(impl as any);
|
||||
const { container } = render(<Row justify="center" />);
|
||||
expect(container.innerHTML).toContain('ant-row-center');
|
||||
const { container: container2 } = render(<Row justify={{ xs: 'center' }} />);
|
||||
expect(container2.innerHTML).toContain('ant-row-center');
|
||||
const { container: container3 } = render(<Row justify={{ lg: 'center' }} />);
|
||||
expect(container3.innerHTML).not.toContain('ant-row-center');
|
||||
});
|
||||
});
|
||||
|
||||
// https://github.com/ant-design/ant-design/issues/39690
|
||||
|
|
|
@ -130,7 +130,7 @@ export type { SpaceProps } from './space';
|
|||
export { default as Spin } from './spin';
|
||||
export type { SpinProps } from './spin';
|
||||
export { default as Statistic } from './statistic';
|
||||
export type { CountdownProps, StatisticProps } from './statistic';
|
||||
export type { StatisticTimerProps, CountdownProps, StatisticProps } from './statistic';
|
||||
export { default as Steps } from './steps';
|
||||
export type { StepProps, StepsProps } from './steps';
|
||||
export { default as Switch } from './switch';
|
||||
|
|
|
@ -6,6 +6,7 @@ import RightOutlined from '@ant-design/icons/RightOutlined';
|
|||
import classNames from 'classnames';
|
||||
import omit from 'rc-util/lib/omit';
|
||||
|
||||
import { addMediaQueryListener, removeMediaQueryListener } from '../_util/mediaQueryUtil';
|
||||
import { ConfigContext } from '../config-provider';
|
||||
import { LayoutContext } from './context';
|
||||
import useStyle from './style/sider';
|
||||
|
@ -118,28 +119,16 @@ const Sider = React.forwardRef<HTMLDivElement, SiderProps>((props, ref) => {
|
|||
|
||||
useEffect(() => {
|
||||
function responsiveHandler(mql: MediaQueryListEvent | MediaQueryList) {
|
||||
return responsiveHandlerRef.current!(mql);
|
||||
return responsiveHandlerRef.current?.(mql);
|
||||
}
|
||||
|
||||
let mql: MediaQueryList;
|
||||
if (typeof window !== 'undefined') {
|
||||
const { matchMedia } = window;
|
||||
if (matchMedia! && breakpoint && breakpoint in dimensionMaxMap) {
|
||||
mql = matchMedia(`screen and (max-width: ${dimensionMaxMap[breakpoint]})`);
|
||||
try {
|
||||
mql.addEventListener('change', responsiveHandler);
|
||||
} catch {
|
||||
mql.addListener(responsiveHandler);
|
||||
}
|
||||
responsiveHandler(mql);
|
||||
}
|
||||
if (typeof window?.matchMedia !== 'undefined' && breakpoint && breakpoint in dimensionMaxMap) {
|
||||
mql = window.matchMedia(`screen and (max-width: ${dimensionMaxMap[breakpoint]})`);
|
||||
addMediaQueryListener(mql, responsiveHandler);
|
||||
responsiveHandler(mql);
|
||||
}
|
||||
return () => {
|
||||
try {
|
||||
mql?.removeEventListener('change', responsiveHandler);
|
||||
} catch {
|
||||
mql?.removeListener(responsiveHandler);
|
||||
}
|
||||
removeMediaQueryListener(mql, responsiveHandler);
|
||||
};
|
||||
}, [breakpoint]); // in order to accept dynamic 'breakpoint' property, we need to add 'breakpoint' into dependency array.
|
||||
|
||||
|
|
|
@ -1,8 +1,8 @@
|
|||
import React, { useState } from 'react';
|
||||
|
||||
import type { Breakpoint } from '../..';
|
||||
import { fireEvent, render } from '../../../tests/utils';
|
||||
import Sider from '../Sider';
|
||||
import type { Breakpoint } from '../..';
|
||||
|
||||
const Content = () => {
|
||||
const [breakpoint, setBreakpoint] = useState<Breakpoint>('sm');
|
||||
|
|
|
@ -7177,6 +7177,7 @@ exports[`Locale Provider should display the text as ar 1`] = `
|
|||
type="button"
|
||||
>
|
||||
<span
|
||||
aria-label="إغلاق"
|
||||
class="ant-modal-close-x"
|
||||
>
|
||||
<span
|
||||
|
@ -12498,6 +12499,7 @@ exports[`Locale Provider should display the text as az 1`] = `
|
|||
type="button"
|
||||
>
|
||||
<span
|
||||
aria-label="Bağla"
|
||||
class="ant-modal-close-x"
|
||||
>
|
||||
<span
|
||||
|
@ -17819,6 +17821,7 @@ exports[`Locale Provider should display the text as bg 1`] = `
|
|||
type="button"
|
||||
>
|
||||
<span
|
||||
aria-label="Затвори"
|
||||
class="ant-modal-close-x"
|
||||
>
|
||||
<span
|
||||
|
@ -23140,6 +23143,7 @@ exports[`Locale Provider should display the text as bn-bd 1`] = `
|
|||
type="button"
|
||||
>
|
||||
<span
|
||||
aria-label="বন্ধ"
|
||||
class="ant-modal-close-x"
|
||||
>
|
||||
<span
|
||||
|
@ -28461,6 +28465,7 @@ exports[`Locale Provider should display the text as by 1`] = `
|
|||
type="button"
|
||||
>
|
||||
<span
|
||||
aria-label="Закрыць"
|
||||
class="ant-modal-close-x"
|
||||
>
|
||||
<span
|
||||
|
@ -33782,6 +33787,7 @@ exports[`Locale Provider should display the text as ca 1`] = `
|
|||
type="button"
|
||||
>
|
||||
<span
|
||||
aria-label="Tancar"
|
||||
class="ant-modal-close-x"
|
||||
>
|
||||
<span
|
||||
|
@ -39103,6 +39109,7 @@ exports[`Locale Provider should display the text as cs 1`] = `
|
|||
type="button"
|
||||
>
|
||||
<span
|
||||
aria-label="Zavřít"
|
||||
class="ant-modal-close-x"
|
||||
>
|
||||
<span
|
||||
|
@ -44424,6 +44431,7 @@ exports[`Locale Provider should display the text as da 1`] = `
|
|||
type="button"
|
||||
>
|
||||
<span
|
||||
aria-label="Luk"
|
||||
class="ant-modal-close-x"
|
||||
>
|
||||
<span
|
||||
|
@ -49745,6 +49753,7 @@ exports[`Locale Provider should display the text as de 1`] = `
|
|||
type="button"
|
||||
>
|
||||
<span
|
||||
aria-label="Schließen"
|
||||
class="ant-modal-close-x"
|
||||
>
|
||||
<span
|
||||
|
@ -55066,6 +55075,7 @@ exports[`Locale Provider should display the text as el 1`] = `
|
|||
type="button"
|
||||
>
|
||||
<span
|
||||
aria-label="Κλείσιμο"
|
||||
class="ant-modal-close-x"
|
||||
>
|
||||
<span
|
||||
|
@ -60387,6 +60397,7 @@ exports[`Locale Provider should display the text as en 1`] = `
|
|||
type="button"
|
||||
>
|
||||
<span
|
||||
aria-label="Close"
|
||||
class="ant-modal-close-x"
|
||||
>
|
||||
<span
|
||||
|
@ -65708,6 +65719,7 @@ exports[`Locale Provider should display the text as en-gb 1`] = `
|
|||
type="button"
|
||||
>
|
||||
<span
|
||||
aria-label="Close"
|
||||
class="ant-modal-close-x"
|
||||
>
|
||||
<span
|
||||
|
@ -71029,6 +71041,7 @@ exports[`Locale Provider should display the text as es 1`] = `
|
|||
type="button"
|
||||
>
|
||||
<span
|
||||
aria-label="Cerrar"
|
||||
class="ant-modal-close-x"
|
||||
>
|
||||
<span
|
||||
|
@ -76350,6 +76363,7 @@ exports[`Locale Provider should display the text as et 1`] = `
|
|||
type="button"
|
||||
>
|
||||
<span
|
||||
aria-label="Sulge"
|
||||
class="ant-modal-close-x"
|
||||
>
|
||||
<span
|
||||
|
@ -81671,6 +81685,7 @@ exports[`Locale Provider should display the text as eu 1`] = `
|
|||
type="button"
|
||||
>
|
||||
<span
|
||||
aria-label="Itxi"
|
||||
class="ant-modal-close-x"
|
||||
>
|
||||
<span
|
||||
|
@ -86992,6 +87007,7 @@ exports[`Locale Provider should display the text as fa 1`] = `
|
|||
type="button"
|
||||
>
|
||||
<span
|
||||
aria-label="بستن"
|
||||
class="ant-modal-close-x"
|
||||
>
|
||||
<span
|
||||
|
@ -92313,6 +92329,7 @@ exports[`Locale Provider should display the text as fi 1`] = `
|
|||
type="button"
|
||||
>
|
||||
<span
|
||||
aria-label="Sulje"
|
||||
class="ant-modal-close-x"
|
||||
>
|
||||
<span
|
||||
|
@ -97634,6 +97651,7 @@ exports[`Locale Provider should display the text as fr 1`] = `
|
|||
type="button"
|
||||
>
|
||||
<span
|
||||
aria-label="Fermer"
|
||||
class="ant-modal-close-x"
|
||||
>
|
||||
<span
|
||||
|
@ -102955,6 +102973,7 @@ exports[`Locale Provider should display the text as fr 2`] = `
|
|||
type="button"
|
||||
>
|
||||
<span
|
||||
aria-label="Fermer"
|
||||
class="ant-modal-close-x"
|
||||
>
|
||||
<span
|
||||
|
@ -108276,6 +108295,7 @@ exports[`Locale Provider should display the text as fr 3`] = `
|
|||
type="button"
|
||||
>
|
||||
<span
|
||||
aria-label="Fermer"
|
||||
class="ant-modal-close-x"
|
||||
>
|
||||
<span
|
||||
|
@ -113597,6 +113617,7 @@ exports[`Locale Provider should display the text as ga 1`] = `
|
|||
type="button"
|
||||
>
|
||||
<span
|
||||
aria-label="Dún"
|
||||
class="ant-modal-close-x"
|
||||
>
|
||||
<span
|
||||
|
@ -118918,6 +118939,7 @@ exports[`Locale Provider should display the text as gl 1`] = `
|
|||
type="button"
|
||||
>
|
||||
<span
|
||||
aria-label="Cerrar"
|
||||
class="ant-modal-close-x"
|
||||
>
|
||||
<span
|
||||
|
@ -124239,6 +124261,7 @@ exports[`Locale Provider should display the text as he 1`] = `
|
|||
type="button"
|
||||
>
|
||||
<span
|
||||
aria-label="סגור"
|
||||
class="ant-modal-close-x"
|
||||
>
|
||||
<span
|
||||
|
@ -129560,6 +129583,7 @@ exports[`Locale Provider should display the text as hi 1`] = `
|
|||
type="button"
|
||||
>
|
||||
<span
|
||||
aria-label="बंद"
|
||||
class="ant-modal-close-x"
|
||||
>
|
||||
<span
|
||||
|
@ -134881,6 +134905,7 @@ exports[`Locale Provider should display the text as hr 1`] = `
|
|||
type="button"
|
||||
>
|
||||
<span
|
||||
aria-label="Zatvori"
|
||||
class="ant-modal-close-x"
|
||||
>
|
||||
<span
|
||||
|
@ -140202,6 +140227,7 @@ exports[`Locale Provider should display the text as hu 1`] = `
|
|||
type="button"
|
||||
>
|
||||
<span
|
||||
aria-label="Bezárás"
|
||||
class="ant-modal-close-x"
|
||||
>
|
||||
<span
|
||||
|
@ -145523,6 +145549,7 @@ exports[`Locale Provider should display the text as hy-am 1`] = `
|
|||
type="button"
|
||||
>
|
||||
<span
|
||||
aria-label="Դադարեցնել"
|
||||
class="ant-modal-close-x"
|
||||
>
|
||||
<span
|
||||
|
@ -150844,6 +150871,7 @@ exports[`Locale Provider should display the text as id 1`] = `
|
|||
type="button"
|
||||
>
|
||||
<span
|
||||
aria-label="Tutup"
|
||||
class="ant-modal-close-x"
|
||||
>
|
||||
<span
|
||||
|
@ -156165,6 +156193,7 @@ exports[`Locale Provider should display the text as is 1`] = `
|
|||
type="button"
|
||||
>
|
||||
<span
|
||||
aria-label="Loka"
|
||||
class="ant-modal-close-x"
|
||||
>
|
||||
<span
|
||||
|
@ -161486,6 +161515,7 @@ exports[`Locale Provider should display the text as it 1`] = `
|
|||
type="button"
|
||||
>
|
||||
<span
|
||||
aria-label="Chiudi"
|
||||
class="ant-modal-close-x"
|
||||
>
|
||||
<span
|
||||
|
@ -166807,6 +166837,7 @@ exports[`Locale Provider should display the text as ja 1`] = `
|
|||
type="button"
|
||||
>
|
||||
<span
|
||||
aria-label="閉じる"
|
||||
class="ant-modal-close-x"
|
||||
>
|
||||
<span
|
||||
|
@ -172128,6 +172159,7 @@ exports[`Locale Provider should display the text as ka 1`] = `
|
|||
type="button"
|
||||
>
|
||||
<span
|
||||
aria-label="დახურვა"
|
||||
class="ant-modal-close-x"
|
||||
>
|
||||
<span
|
||||
|
@ -177449,6 +177481,7 @@ exports[`Locale Provider should display the text as kk 1`] = `
|
|||
type="button"
|
||||
>
|
||||
<span
|
||||
aria-label="Жабу"
|
||||
class="ant-modal-close-x"
|
||||
>
|
||||
<span
|
||||
|
@ -182768,6 +182801,7 @@ exports[`Locale Provider should display the text as km 1`] = `
|
|||
type="button"
|
||||
>
|
||||
<span
|
||||
aria-label="បិទ"
|
||||
class="ant-modal-close-x"
|
||||
>
|
||||
<span
|
||||
|
@ -188089,6 +188123,7 @@ exports[`Locale Provider should display the text as kn 1`] = `
|
|||
type="button"
|
||||
>
|
||||
<span
|
||||
aria-label="ಮುಚ್ಚಿ"
|
||||
class="ant-modal-close-x"
|
||||
>
|
||||
<span
|
||||
|
@ -193410,6 +193445,7 @@ exports[`Locale Provider should display the text as ko 1`] = `
|
|||
type="button"
|
||||
>
|
||||
<span
|
||||
aria-label="닫기"
|
||||
class="ant-modal-close-x"
|
||||
>
|
||||
<span
|
||||
|
@ -198731,6 +198767,7 @@ exports[`Locale Provider should display the text as ku 1`] = `
|
|||
type="button"
|
||||
>
|
||||
<span
|
||||
aria-label="Betal ke"
|
||||
class="ant-modal-close-x"
|
||||
>
|
||||
<span
|
||||
|
@ -204052,6 +204089,7 @@ exports[`Locale Provider should display the text as ku-iq 1`] = `
|
|||
type="button"
|
||||
>
|
||||
<span
|
||||
aria-label="Betal ke"
|
||||
class="ant-modal-close-x"
|
||||
>
|
||||
<span
|
||||
|
@ -209373,6 +209411,7 @@ exports[`Locale Provider should display the text as lt 1`] = `
|
|||
type="button"
|
||||
>
|
||||
<span
|
||||
aria-label="Uždaryti"
|
||||
class="ant-modal-close-x"
|
||||
>
|
||||
<span
|
||||
|
@ -214694,6 +214733,7 @@ exports[`Locale Provider should display the text as lv 1`] = `
|
|||
type="button"
|
||||
>
|
||||
<span
|
||||
aria-label="Aizvērt"
|
||||
class="ant-modal-close-x"
|
||||
>
|
||||
<span
|
||||
|
@ -220015,6 +220055,7 @@ exports[`Locale Provider should display the text as mk 1`] = `
|
|||
type="button"
|
||||
>
|
||||
<span
|
||||
aria-label="Затвори"
|
||||
class="ant-modal-close-x"
|
||||
>
|
||||
<span
|
||||
|
@ -225336,6 +225377,7 @@ exports[`Locale Provider should display the text as ml 1`] = `
|
|||
type="button"
|
||||
>
|
||||
<span
|
||||
aria-label="മുടക്കുക"
|
||||
class="ant-modal-close-x"
|
||||
>
|
||||
<span
|
||||
|
@ -230657,6 +230699,7 @@ exports[`Locale Provider should display the text as mn-mn 1`] = `
|
|||
type="button"
|
||||
>
|
||||
<span
|
||||
aria-label="Хаах"
|
||||
class="ant-modal-close-x"
|
||||
>
|
||||
<span
|
||||
|
@ -235978,6 +236021,7 @@ exports[`Locale Provider should display the text as ms-my 1`] = `
|
|||
type="button"
|
||||
>
|
||||
<span
|
||||
aria-label="Tutup"
|
||||
class="ant-modal-close-x"
|
||||
>
|
||||
<span
|
||||
|
@ -241299,6 +241343,7 @@ exports[`Locale Provider should display the text as my 1`] = `
|
|||
type="button"
|
||||
>
|
||||
<span
|
||||
aria-label="ပိတ်ပါ"
|
||||
class="ant-modal-close-x"
|
||||
>
|
||||
<span
|
||||
|
@ -246620,6 +246665,7 @@ exports[`Locale Provider should display the text as nb 1`] = `
|
|||
type="button"
|
||||
>
|
||||
<span
|
||||
aria-label="Lukk"
|
||||
class="ant-modal-close-x"
|
||||
>
|
||||
<span
|
||||
|
@ -251941,6 +251987,7 @@ exports[`Locale Provider should display the text as ne-np 1`] = `
|
|||
type="button"
|
||||
>
|
||||
<span
|
||||
aria-label="बन्द"
|
||||
class="ant-modal-close-x"
|
||||
>
|
||||
<span
|
||||
|
@ -257262,6 +257309,7 @@ exports[`Locale Provider should display the text as nl 1`] = `
|
|||
type="button"
|
||||
>
|
||||
<span
|
||||
aria-label="Sluiten"
|
||||
class="ant-modal-close-x"
|
||||
>
|
||||
<span
|
||||
|
@ -262583,6 +262631,7 @@ exports[`Locale Provider should display the text as nl-be 1`] = `
|
|||
type="button"
|
||||
>
|
||||
<span
|
||||
aria-label="Sluiten"
|
||||
class="ant-modal-close-x"
|
||||
>
|
||||
<span
|
||||
|
@ -267904,6 +267953,7 @@ exports[`Locale Provider should display the text as pl 1`] = `
|
|||
type="button"
|
||||
>
|
||||
<span
|
||||
aria-label="Zamknij"
|
||||
class="ant-modal-close-x"
|
||||
>
|
||||
<span
|
||||
|
@ -273225,6 +273275,7 @@ exports[`Locale Provider should display the text as pt 1`] = `
|
|||
type="button"
|
||||
>
|
||||
<span
|
||||
aria-label="Fechar"
|
||||
class="ant-modal-close-x"
|
||||
>
|
||||
<span
|
||||
|
@ -278546,6 +278597,7 @@ exports[`Locale Provider should display the text as pt-br 1`] = `
|
|||
type="button"
|
||||
>
|
||||
<span
|
||||
aria-label="Fechar"
|
||||
class="ant-modal-close-x"
|
||||
>
|
||||
<span
|
||||
|
@ -283867,6 +283919,7 @@ exports[`Locale Provider should display the text as ro 1`] = `
|
|||
type="button"
|
||||
>
|
||||
<span
|
||||
aria-label="Închide"
|
||||
class="ant-modal-close-x"
|
||||
>
|
||||
<span
|
||||
|
@ -289188,6 +289241,7 @@ exports[`Locale Provider should display the text as ru 1`] = `
|
|||
type="button"
|
||||
>
|
||||
<span
|
||||
aria-label="Закрыть"
|
||||
class="ant-modal-close-x"
|
||||
>
|
||||
<span
|
||||
|
@ -294509,6 +294563,7 @@ exports[`Locale Provider should display the text as si 1`] = `
|
|||
type="button"
|
||||
>
|
||||
<span
|
||||
aria-label="වසන්න"
|
||||
class="ant-modal-close-x"
|
||||
>
|
||||
<span
|
||||
|
@ -299830,6 +299885,7 @@ exports[`Locale Provider should display the text as sk 1`] = `
|
|||
type="button"
|
||||
>
|
||||
<span
|
||||
aria-label="Zavrieť"
|
||||
class="ant-modal-close-x"
|
||||
>
|
||||
<span
|
||||
|
@ -305151,6 +305207,7 @@ exports[`Locale Provider should display the text as sl 1`] = `
|
|||
type="button"
|
||||
>
|
||||
<span
|
||||
aria-label="Zapri"
|
||||
class="ant-modal-close-x"
|
||||
>
|
||||
<span
|
||||
|
@ -310472,6 +310529,7 @@ exports[`Locale Provider should display the text as sr 1`] = `
|
|||
type="button"
|
||||
>
|
||||
<span
|
||||
aria-label="Zatvori"
|
||||
class="ant-modal-close-x"
|
||||
>
|
||||
<span
|
||||
|
@ -315793,6 +315851,7 @@ exports[`Locale Provider should display the text as sv 1`] = `
|
|||
type="button"
|
||||
>
|
||||
<span
|
||||
aria-label="Stäng"
|
||||
class="ant-modal-close-x"
|
||||
>
|
||||
<span
|
||||
|
@ -321114,6 +321173,7 @@ exports[`Locale Provider should display the text as ta 1`] = `
|
|||
type="button"
|
||||
>
|
||||
<span
|
||||
aria-label="மூடு"
|
||||
class="ant-modal-close-x"
|
||||
>
|
||||
<span
|
||||
|
@ -326435,6 +326495,7 @@ exports[`Locale Provider should display the text as th 1`] = `
|
|||
type="button"
|
||||
>
|
||||
<span
|
||||
aria-label="ปิด"
|
||||
class="ant-modal-close-x"
|
||||
>
|
||||
<span
|
||||
|
@ -331756,6 +331817,7 @@ exports[`Locale Provider should display the text as tk 1`] = `
|
|||
type="button"
|
||||
>
|
||||
<span
|
||||
aria-label="Ýagty"
|
||||
class="ant-modal-close-x"
|
||||
>
|
||||
<span
|
||||
|
@ -337077,6 +337139,7 @@ exports[`Locale Provider should display the text as tr 1`] = `
|
|||
type="button"
|
||||
>
|
||||
<span
|
||||
aria-label="Kapat"
|
||||
class="ant-modal-close-x"
|
||||
>
|
||||
<span
|
||||
|
@ -342398,6 +342461,7 @@ exports[`Locale Provider should display the text as uk 1`] = `
|
|||
type="button"
|
||||
>
|
||||
<span
|
||||
aria-label="Закрити"
|
||||
class="ant-modal-close-x"
|
||||
>
|
||||
<span
|
||||
|
@ -347719,6 +347783,7 @@ exports[`Locale Provider should display the text as ur 1`] = `
|
|||
type="button"
|
||||
>
|
||||
<span
|
||||
aria-label="بند کریں"
|
||||
class="ant-modal-close-x"
|
||||
>
|
||||
<span
|
||||
|
@ -353040,6 +353105,7 @@ exports[`Locale Provider should display the text as uz-latn 1`] = `
|
|||
type="button"
|
||||
>
|
||||
<span
|
||||
aria-label="Yopish"
|
||||
class="ant-modal-close-x"
|
||||
>
|
||||
<span
|
||||
|
@ -358361,6 +358427,7 @@ exports[`Locale Provider should display the text as vi 1`] = `
|
|||
type="button"
|
||||
>
|
||||
<span
|
||||
aria-label="Đóng"
|
||||
class="ant-modal-close-x"
|
||||
>
|
||||
<span
|
||||
|
@ -363682,6 +363749,7 @@ exports[`Locale Provider should display the text as zh-cn 1`] = `
|
|||
type="button"
|
||||
>
|
||||
<span
|
||||
aria-label="关闭"
|
||||
class="ant-modal-close-x"
|
||||
>
|
||||
<span
|
||||
|
@ -369003,6 +369071,7 @@ exports[`Locale Provider should display the text as zh-hk 1`] = `
|
|||
type="button"
|
||||
>
|
||||
<span
|
||||
aria-label="關閉"
|
||||
class="ant-modal-close-x"
|
||||
>
|
||||
<span
|
||||
|
@ -374324,6 +374393,7 @@ exports[`Locale Provider should display the text as zh-tw 1`] = `
|
|||
type="button"
|
||||
>
|
||||
<span
|
||||
aria-label="關閉"
|
||||
class="ant-modal-close-x"
|
||||
>
|
||||
<span
|
||||
|
|
|
@ -15,6 +15,7 @@ const localeValues: Locale = {
|
|||
Calendar,
|
||||
global: {
|
||||
placeholder: 'يرجى التحديد',
|
||||
close: 'إغلاق',
|
||||
},
|
||||
Table: {
|
||||
filterTitle: 'الفلاتر',
|
||||
|
|
|
@ -15,6 +15,7 @@ const localeValues: Locale = {
|
|||
Calendar,
|
||||
global: {
|
||||
placeholder: 'Zəhmət olmasa seçin',
|
||||
close: 'Bağla',
|
||||
},
|
||||
Table: {
|
||||
filterTitle: 'Filter menyu',
|
||||
|
|
|
@ -13,6 +13,9 @@ const localeValues: Locale = {
|
|||
DatePicker,
|
||||
TimePicker,
|
||||
Calendar,
|
||||
global: {
|
||||
close: 'Затвори',
|
||||
},
|
||||
Table: {
|
||||
filterTitle: 'Филтриране',
|
||||
filterConfirm: 'Добре',
|
||||
|
@ -20,6 +23,11 @@ const localeValues: Locale = {
|
|||
selectAll: 'Избор на текуща страница',
|
||||
selectInvert: 'Обръщане',
|
||||
},
|
||||
Tour: {
|
||||
Next: 'Следващ',
|
||||
Previous: 'Предишен',
|
||||
Finish: 'Завърши',
|
||||
},
|
||||
Modal: {
|
||||
okText: 'Добре',
|
||||
cancelText: 'Отказ',
|
||||
|
|
|
@ -15,6 +15,7 @@ const localeValues: Locale = {
|
|||
Calendar,
|
||||
global: {
|
||||
placeholder: 'অনুগ্রহ করে নির্বাচন করুন',
|
||||
close: 'বন্ধ',
|
||||
},
|
||||
Table: {
|
||||
filterTitle: 'ফিল্টার মেনু',
|
||||
|
@ -33,6 +34,11 @@ const localeValues: Locale = {
|
|||
triggerAsc: 'আরোহী বাছাই করতে ক্লিক করুন',
|
||||
cancelSort: 'বাছাই বাতিল করতে ক্লিক করুন',
|
||||
},
|
||||
Tour: {
|
||||
Next: 'পরবর্তী',
|
||||
Previous: 'পূর্ববর্তী',
|
||||
Finish: 'সমাপ্ত',
|
||||
},
|
||||
Modal: {
|
||||
okText: 'ঠিক',
|
||||
cancelText: 'বাতিল',
|
||||
|
|
|
@ -15,6 +15,7 @@ const localeValues: Locale = {
|
|||
Calendar,
|
||||
global: {
|
||||
placeholder: 'Калі ласка, выберыце',
|
||||
close: 'Закрыць',
|
||||
},
|
||||
Table: {
|
||||
filterTitle: 'Фільтр',
|
||||
|
@ -35,6 +36,11 @@ const localeValues: Locale = {
|
|||
triggerAsc: 'Націсніце для сартавання па ўзрастанні',
|
||||
cancelSort: 'Націсніце, каб адмяніць сартаванне',
|
||||
},
|
||||
Tour: {
|
||||
Next: 'Наступны',
|
||||
Previous: 'Папярэдняя',
|
||||
Finish: 'Завяршыць',
|
||||
},
|
||||
Modal: {
|
||||
okText: 'OK',
|
||||
cancelText: 'Адмена',
|
||||
|
|
|
@ -15,6 +15,7 @@ const localeValues: Locale = {
|
|||
Calendar,
|
||||
global: {
|
||||
placeholder: 'Seleccionar',
|
||||
close: 'Tancar',
|
||||
},
|
||||
Table: {
|
||||
filterTitle: 'Filtrar el menú',
|
||||
|
@ -31,6 +32,11 @@ const localeValues: Locale = {
|
|||
triggerAsc: 'Ordre ascendent',
|
||||
cancelSort: 'Desactivar l’ordre',
|
||||
},
|
||||
Tour: {
|
||||
Next: 'Següent',
|
||||
Previous: 'Anterior',
|
||||
Finish: 'Finalitzar',
|
||||
},
|
||||
Modal: {
|
||||
okText: 'D’acord',
|
||||
cancelText: 'Cancel·lar',
|
||||
|
|
|
@ -15,6 +15,7 @@ const localeValues: Locale = {
|
|||
Calendar,
|
||||
global: {
|
||||
placeholder: 'Prosím vyber',
|
||||
close: 'Zavřít',
|
||||
},
|
||||
Table: {
|
||||
filterTitle: 'Filtr',
|
||||
|
@ -35,6 +36,11 @@ const localeValues: Locale = {
|
|||
triggerAsc: 'Klikni pro vzestupné řazení',
|
||||
cancelSort: 'Klikni pro zrušení řazení',
|
||||
},
|
||||
Tour: {
|
||||
Next: 'Další',
|
||||
Previous: 'Předchozí',
|
||||
Finish: 'Dokončit',
|
||||
},
|
||||
Modal: {
|
||||
okText: 'OK',
|
||||
cancelText: 'Zrušit',
|
||||
|
|
|
@ -12,6 +12,9 @@ const localeValues: Locale = {
|
|||
TimePicker,
|
||||
Calendar,
|
||||
Pagination,
|
||||
global: {
|
||||
close: 'Luk',
|
||||
},
|
||||
Table: {
|
||||
filterTitle: 'Filtermenu',
|
||||
filterConfirm: 'OK',
|
||||
|
@ -29,6 +32,11 @@ const localeValues: Locale = {
|
|||
triggerAsc: 'Klik for at sortere stigende',
|
||||
cancelSort: 'Klik for at annullere sortering',
|
||||
},
|
||||
Tour: {
|
||||
Next: 'Næste',
|
||||
Previous: 'Forrige',
|
||||
Finish: 'Færdiggørelse',
|
||||
},
|
||||
Modal: {
|
||||
okText: 'OK',
|
||||
cancelText: 'Afbryd',
|
||||
|
|
|
@ -15,6 +15,7 @@ const localeValues: Locale = {
|
|||
Calendar,
|
||||
global: {
|
||||
placeholder: 'Bitte auswählen',
|
||||
close: 'Schließen',
|
||||
},
|
||||
Table: {
|
||||
filterTitle: 'Filter-Menü',
|
||||
|
|
|
@ -15,6 +15,7 @@ const localeValues: Locale = {
|
|||
Calendar,
|
||||
global: {
|
||||
placeholder: 'Παρακαλώ επιλέξτε',
|
||||
close: 'Κλείσιμο',
|
||||
},
|
||||
Table: {
|
||||
filterTitle: 'Μενού φίλτρων',
|
||||
|
|
|
@ -15,6 +15,7 @@ const localeValues: Locale = {
|
|||
Calendar,
|
||||
global: {
|
||||
placeholder: 'Please select',
|
||||
close: 'Close',
|
||||
},
|
||||
Table: {
|
||||
filterTitle: 'Filter menu',
|
||||
|
@ -35,6 +36,11 @@ const localeValues: Locale = {
|
|||
triggerAsc: 'Click to sort ascending',
|
||||
cancelSort: 'Click to cancel sorting',
|
||||
},
|
||||
Tour: {
|
||||
Next: 'Next',
|
||||
Previous: 'Previous',
|
||||
Finish: 'Finish',
|
||||
},
|
||||
Modal: {
|
||||
okText: 'OK',
|
||||
cancelText: 'Cancel',
|
||||
|
|
|
@ -15,6 +15,7 @@ const localeValues: Locale = {
|
|||
Calendar,
|
||||
global: {
|
||||
placeholder: 'Please select',
|
||||
close: 'Close',
|
||||
},
|
||||
Table: {
|
||||
filterTitle: 'Filter menu',
|
||||
|
|
|
@ -15,6 +15,7 @@ const localeValues: Locale = {
|
|||
Calendar,
|
||||
global: {
|
||||
placeholder: 'Seleccione',
|
||||
close: 'Cerrar',
|
||||
},
|
||||
Table: {
|
||||
filterTitle: 'Filtrar menú',
|
||||
|
|
|
@ -15,6 +15,7 @@ const localeValues: Locale = {
|
|||
Calendar,
|
||||
global: {
|
||||
placeholder: 'Palun vali',
|
||||
close: 'Sulge',
|
||||
},
|
||||
Table: {
|
||||
filterTitle: 'Filtri menüü',
|
||||
|
@ -35,6 +36,11 @@ const localeValues: Locale = {
|
|||
triggerAsc: 'Klõpsa kasvavalt sortimiseks',
|
||||
cancelSort: 'Klõpsa sortimise tühistamiseks',
|
||||
},
|
||||
Tour: {
|
||||
Next: 'Järgmine',
|
||||
Previous: 'Eelmine',
|
||||
Finish: 'Lõpetada',
|
||||
},
|
||||
Modal: {
|
||||
okText: 'OK',
|
||||
cancelText: 'Tühista',
|
||||
|
|
|
@ -15,6 +15,7 @@ const localeValues: Locale = {
|
|||
Calendar,
|
||||
global: {
|
||||
placeholder: 'Aukeratu',
|
||||
close: 'Itxi',
|
||||
},
|
||||
Table: {
|
||||
filterTitle: 'Iragazi menua',
|
||||
|
|
|
@ -15,6 +15,7 @@ const localeValues: Locale = {
|
|||
Calendar,
|
||||
global: {
|
||||
placeholder: 'لطفاً انتخاب کنید',
|
||||
close: 'بستن',
|
||||
},
|
||||
Table: {
|
||||
filterTitle: 'منوی فیلتر',
|
||||
|
|
|
@ -11,6 +11,9 @@ const localeValues: Locale = {
|
|||
DatePicker,
|
||||
TimePicker,
|
||||
Calendar,
|
||||
global: {
|
||||
close: 'Sulje',
|
||||
},
|
||||
Table: {
|
||||
filterTitle: 'Suodatus valikko',
|
||||
filterConfirm: 'OK',
|
||||
|
@ -22,6 +25,11 @@ const localeValues: Locale = {
|
|||
triggerAsc: 'Lajittele nousevasti',
|
||||
cancelSort: 'Peruuta lajittelu',
|
||||
},
|
||||
Tour: {
|
||||
Next: 'Seuraava',
|
||||
Previous: 'Edellinen',
|
||||
Finish: 'Valmis',
|
||||
},
|
||||
Modal: {
|
||||
okText: 'OK',
|
||||
cancelText: 'Peruuta',
|
||||
|
|
|
@ -13,6 +13,9 @@ const localeValues: Locale = {
|
|||
DatePicker,
|
||||
TimePicker,
|
||||
Calendar,
|
||||
global: {
|
||||
close: 'Fermer',
|
||||
},
|
||||
Table: {
|
||||
filterTitle: 'Filtrer',
|
||||
filterConfirm: 'OK',
|
||||
|
|
Some files were not shown because too many files have changed in this diff Show more
Loading…
Add table
Add a link
Reference in a new issue