chore: next merge feature

This commit is contained in:
zombiej 2022-07-19 17:51:35 +08:00
commit c71ce67e14
57 changed files with 44474 additions and 37145 deletions

View File

@ -15,6 +15,20 @@ timeline: true
---
## 4.21.7
`2022-07-18`
- 🆕 Add Skeleton.Node sub-component, allow user customize content of Skeleton. [#36441](https://github.com/ant-design/ant-design/pull/36441) [@DawnLck](https://github.com/DawnLck)
- Form
- 🐞 Fix Form with percentage width Select may leaves unexpected height. [#36484](https://github.com/ant-design/ant-design/pull/36484)
- 🐞 Fix Form disabled but Upload component still uploadable in it. [#36573](https://github.com/ant-design/ant-design/pull/36573) [@cwjTerrace](https://github.com/cwjTerrace)
- 🐞 Fix Tree non-draggable element still render the draggable icon. [#36511](https://github.com/ant-design/ant-design/pull/36511) [@Wxh16144](https://github.com/Wxh16144)
- 🐞 Fix Upload preview error on SVG with `<foreignObject>` and cross-origin links. [#36402](https://github.com/ant-design/ant-design/pull/36402) [@jonioni](https://github.com/jonioni)
- 🐞 Fix that Tooltip cannot close automaticly on disabled Radio. [#36483](https://github.com/ant-design/ant-design/pull/36483)
- 💄 Add Modal Less variable `@modal-border-radius`. [#36527](https://github.com/ant-design/ant-design/pull/36527) [@kkkisme](https://github.com/kkkisme)
- 💄 Fix Table expand icon wrap style when column is fixed and ellipsis. [#36496](https://github.com/ant-design/ant-design/pull/36496)
## 4.21.6
`2022-07-11`

View File

@ -15,6 +15,20 @@ timeline: true
---
## 4.21.7
`2022-07-18`
- 🆕 新增 Skeleton.Node 子组件,允许用户自定义 Skeleton 的内容。[#36441](https://github.com/ant-design/ant-design/pull/36441) [@DawnLck](https://github.com/DawnLck)
- Form
- 🐞 修复 Form 下设置 Select 百分比宽度时会有未预期空行问题。[#36484](https://github.com/ant-design/ant-design/pull/36484)
- 🐞 修复 Form 设为禁用时、内部的 Upload 组件仍能上传文件的问题。[#36573](https://github.com/ant-design/ant-design/pull/36573) [@cwjTerrace](https://github.com/cwjTerrace)
- 🐞 修复 Tree 非 `draggable` 依然展示可拖拽图标的问题。[#36511](https://github.com/ant-design/ant-design/pull/36511) [@Wxh16144](https://github.com/Wxh16144)
- 🐞 修复 Upload 在预览包含 `<foreignObject>` 及跨域链接的 SVG 文件时发生错误的问题。[#36402](https://github.com/ant-design/ant-design/pull/36402) [@jonioni](https://github.com/jonioni)
- 🐞 修复 Tooltip 在被禁用的 Radio 上时无法自动关闭的问题。[#36483](https://github.com/ant-design/ant-design/pull/36483)
- 💄 添加 Modal Less 变量 `@modal-border-radius`。[#36527](https://github.com/ant-design/ant-design/pull/36527) [@kkkisme](https://github.com/kkkisme)
- 💄 修复 Table 开启固定和省略功能的列内的展开按钮换行样式。[#36496](https://github.com/ant-design/ant-design/pull/36496)
## 4.21.6
`2022-07-11`

View File

@ -0,0 +1,3 @@
import siLK from '../../date-picker/locale/si_LK';
export default siLK;

View File

@ -15381,32 +15381,26 @@ exports[`ConfigProvider components Form configProvider 1`] = `
class="config-form config-form-horizontal"
>
<div
class="config-row config-form-item config-form-item-with-help config-form-item-has-error"
class="config-form-item config-form-item-with-help config-form-item-has-error"
>
<div
class="config-col config-form-item-control"
class="config-row config-form-item-row"
>
<div
class="config-form-item-control-input"
class="config-col config-form-item-control"
>
<div
class="config-form-item-control-input-content"
class="config-form-item-control-input"
>
<input
class="config-input config-input-status-error"
type="text"
value=""
/>
</div>
</div>
<div
class="config-form-item-explain config-form-item-explain-connected"
>
<div
class="config-form-item-explain-error"
role="alert"
>
Bamboo is Light
<div
class="config-form-item-control-input-content"
>
<input
class="config-input config-input-status-error"
type="text"
value=""
/>
</div>
</div>
</div>
</div>
@ -15419,33 +15413,27 @@ exports[`ConfigProvider components Form configProvider componentDisabled 1`] = `
class="config-form config-form-horizontal"
>
<div
class="config-row config-form-item config-form-item-with-help config-form-item-has-error"
class="config-form-item config-form-item-with-help config-form-item-has-error"
>
<div
class="config-col config-form-item-control"
class="config-row config-form-item-row"
>
<div
class="config-form-item-control-input"
class="config-col config-form-item-control"
>
<div
class="config-form-item-control-input-content"
class="config-form-item-control-input"
>
<input
class="config-input config-input-disabled config-input-status-error"
disabled=""
type="text"
value=""
/>
</div>
</div>
<div
class="config-form-item-explain config-form-item-explain-connected"
>
<div
class="config-form-item-explain-error"
role="alert"
>
Bamboo is Light
<div
class="config-form-item-control-input-content"
>
<input
class="config-input config-input-disabled config-input-status-error"
disabled=""
type="text"
value=""
/>
</div>
</div>
</div>
</div>
@ -15458,32 +15446,26 @@ exports[`ConfigProvider components Form configProvider componentSize large 1`] =
class="config-form config-form-horizontal config-form-large"
>
<div
class="config-row config-form-item config-form-item-with-help config-form-item-has-error"
class="config-form-item config-form-item-with-help config-form-item-has-error"
>
<div
class="config-col config-form-item-control"
class="config-row config-form-item-row"
>
<div
class="config-form-item-control-input"
class="config-col config-form-item-control"
>
<div
class="config-form-item-control-input-content"
class="config-form-item-control-input"
>
<input
class="config-input config-input-lg config-input-status-error"
type="text"
value=""
/>
</div>
</div>
<div
class="config-form-item-explain config-form-item-explain-connected"
>
<div
class="config-form-item-explain-error"
role="alert"
>
Bamboo is Light
<div
class="config-form-item-control-input-content"
>
<input
class="config-input config-input-lg config-input-status-error"
type="text"
value=""
/>
</div>
</div>
</div>
</div>
@ -15496,32 +15478,26 @@ exports[`ConfigProvider components Form configProvider componentSize middle 1`]
class="config-form config-form-horizontal config-form-middle"
>
<div
class="config-row config-form-item config-form-item-with-help config-form-item-has-error"
class="config-form-item config-form-item-with-help config-form-item-has-error"
>
<div
class="config-col config-form-item-control"
class="config-row config-form-item-row"
>
<div
class="config-form-item-control-input"
class="config-col config-form-item-control"
>
<div
class="config-form-item-control-input-content"
class="config-form-item-control-input"
>
<input
class="config-input config-input-status-error"
type="text"
value=""
/>
</div>
</div>
<div
class="config-form-item-explain config-form-item-explain-connected"
>
<div
class="config-form-item-explain-error"
role="alert"
>
Bamboo is Light
<div
class="config-form-item-control-input-content"
>
<input
class="config-input config-input-status-error"
type="text"
value=""
/>
</div>
</div>
</div>
</div>
@ -15534,32 +15510,26 @@ exports[`ConfigProvider components Form configProvider virtual and dropdownMatch
class="ant-form ant-form-horizontal"
>
<div
class="ant-row ant-form-item ant-form-item-with-help ant-form-item-has-error"
class="ant-form-item ant-form-item-with-help ant-form-item-has-error"
>
<div
class="ant-col ant-form-item-control"
class="ant-row ant-form-item-row"
>
<div
class="ant-form-item-control-input"
class="ant-col ant-form-item-control"
>
<div
class="ant-form-item-control-input-content"
class="ant-form-item-control-input"
>
<input
class="ant-input ant-input-status-error"
type="text"
value=""
/>
</div>
</div>
<div
class="ant-form-item-explain ant-form-item-explain-connected"
>
<div
class="ant-form-item-explain-error"
role="alert"
>
Bamboo is Light
<div
class="ant-form-item-control-input-content"
>
<input
class="ant-input ant-input-status-error"
type="text"
value=""
/>
</div>
</div>
</div>
</div>
@ -15572,32 +15542,26 @@ exports[`ConfigProvider components Form normal 1`] = `
class="ant-form ant-form-horizontal"
>
<div
class="ant-row ant-form-item ant-form-item-with-help ant-form-item-has-error"
class="ant-form-item ant-form-item-with-help ant-form-item-has-error"
>
<div
class="ant-col ant-form-item-control"
class="ant-row ant-form-item-row"
>
<div
class="ant-form-item-control-input"
class="ant-col ant-form-item-control"
>
<div
class="ant-form-item-control-input-content"
class="ant-form-item-control-input"
>
<input
class="ant-input ant-input-status-error"
type="text"
value=""
/>
</div>
</div>
<div
class="ant-form-item-explain ant-form-item-explain-connected"
>
<div
class="ant-form-item-explain-error"
role="alert"
>
Bamboo is Light
<div
class="ant-form-item-control-input-content"
>
<input
class="ant-input ant-input-status-error"
type="text"
value=""
/>
</div>
</div>
</div>
</div>
@ -15610,32 +15574,26 @@ exports[`ConfigProvider components Form prefixCls 1`] = `
class="prefix-Form prefix-Form-horizontal"
>
<div
class="ant-row prefix-Form-item prefix-Form-item-with-help prefix-Form-item-has-error"
class="prefix-Form-item prefix-Form-item-with-help prefix-Form-item-has-error"
>
<div
class="ant-col prefix-Form-item-control"
class="ant-row prefix-Form-item-row"
>
<div
class="prefix-Form-item-control-input"
class="ant-col prefix-Form-item-control"
>
<div
class="prefix-Form-item-control-input-content"
class="prefix-Form-item-control-input"
>
<input
class="prefix-Form prefix-Form-status-error"
type="text"
value=""
/>
</div>
</div>
<div
class="prefix-Form-item-explain prefix-Form-item-explain-connected"
>
<div
class="prefix-Form-item-explain-error"
role="alert"
>
Bamboo is Light
<div
class="prefix-Form-item-control-input-content"
>
<input
class="prefix-Form prefix-Form-status-error"
type="text"
value=""
/>
</div>
</div>
</div>
</div>
@ -41877,12 +41835,11 @@ exports[`ConfigProvider components Upload configProvider componentDisabled 1`] =
class="config-upload-wrapper"
>
<div
class="config-upload config-upload-select"
class="config-upload config-upload-select config-upload-disabled"
>
<span
class="config-upload"
class="config-upload config-upload-disabled"
role="button"
tabindex="0"
>
<input
accept=""
@ -41932,35 +41889,7 @@ exports[`ConfigProvider components Upload configProvider componentDisabled 1`] =
</span>
<span
class="config-upload-list-item-actions"
>
<button
class="config-btn config-btn-text config-btn-sm config-btn-icon-only config-upload-list-item-action"
disabled=""
title="Remove file"
type="button"
>
<span
aria-label="delete"
class="anticon anticon-delete"
role="img"
tabindex="-1"
>
<svg
aria-hidden="true"
data-icon="delete"
fill="currentColor"
focusable="false"
height="1em"
viewBox="64 64 896 896"
width="1em"
>
<path
d="M360 184h-8c4.4 0 8-3.6 8-8v8h304v-8c0 4.4 3.6 8 8 8h-8v72h72v-80c0-35.3-28.7-64-64-64H352c-35.3 0-64 28.7-64 64v80h72v-72zm504 72H160c-17.7 0-32 14.3-32 32v32c0 4.4 3.6 8 8 8h60.4l24.7 523c1.6 34.1 29.8 61 63.9 61h454c34.2 0 62.3-26.8 63.9-61l24.7-523H888c4.4 0 8-3.6 8-8v-32c0-17.7-14.3-32-32-32zM731.3 840H292.7l-24.2-512h487l-24.2 512z"
/>
</svg>
</span>
</button>
</span>
/>
</div>
</div>
</div>

View File

@ -5,38 +5,42 @@ exports[`ConfigProvider.Form form requiredMark set requiredMark optional 1`] = `
class="ant-form ant-form-horizontal"
>
<div
class="ant-row ant-form-item"
class="ant-form-item"
>
<div
class="ant-col ant-form-item-label"
>
<label
class="ant-form-item-required-mark-optional"
for="age"
title="年龄"
>
年龄
<span
class="ant-form-item-optional"
title=""
>
(optional)
</span>
</label>
</div>
<div
class="ant-col ant-form-item-control"
class="ant-row ant-form-item-row"
>
<div
class="ant-form-item-control-input"
class="ant-col ant-form-item-label"
>
<label
class="ant-form-item-required-mark-optional"
for="age"
title="年龄"
>
年龄
<span
class="ant-form-item-optional"
title=""
>
(optional)
</span>
</label>
</div>
<div
class="ant-col ant-form-item-control"
>
<div
class="ant-form-item-control-input-content"
class="ant-form-item-control-input"
>
<input
id="age"
value="18"
/>
<div
class="ant-form-item-control-input-content"
>
<input
id="age"
value="18"
/>
</div>
</div>
</div>
</div>

View File

@ -0,0 +1,28 @@
import CalendarLocale from 'rc-picker/lib/locale/si_LK';
import TimePickerLocale from '../../time-picker/locale/si_LK';
import type { PickerLocale } from '../generatePicker';
// Merge into a locale object
const locale: PickerLocale = {
lang: {
placeholder: 'දිනය තෝරන්න',
yearPlaceholder: 'අවුරුද්ද තෝරන්න',
quarterPlaceholder: 'කාර්තුව තෝරන්න',
monthPlaceholder: 'මාසය තෝරන්න',
weekPlaceholder: 'සතිය තෝරන්න',
rangePlaceholder: ['ආරම්භක දිනය', 'නිමවන දිනය'],
rangeYearPlaceholder: ['ආර්ම්භක අවුරුද්ද', 'නිමවන අවුරුද්ද'],
rangeQuarterPlaceholder: ['ආරම්භක කාර්තුව', 'නිමවන කාර්තුව'],
rangeMonthPlaceholder: ['ආරම්භක මාසය', 'නිමවන මාසය'],
rangeWeekPlaceholder: ['ආරම්භක සතිය', 'නිමවන සතිය'],
...CalendarLocale,
},
timePickerLocale: {
...TimePickerLocale,
},
};
// All settings at:
// https://github.com/ant-design/ant-design/blob/master/components/date-picker/locale/example.json
export default locale;

View File

@ -34,6 +34,7 @@ export interface ErrorListProps {
errors?: React.ReactNode[];
warnings?: React.ReactNode[];
className?: string;
onVisibleChanged?: (visible: boolean) => void;
}
export default function ErrorList({
@ -42,6 +43,7 @@ export default function ErrorList({
errors = EMPTY_LIST,
warnings = EMPTY_LIST,
className: rootClassName,
onVisibleChanged,
}: ErrorListProps) {
const { prefixCls } = React.useContext(FormItemPrefixContext);
const { getPrefixCls } = React.useContext(ConfigContext);
@ -69,16 +71,10 @@ export default function ErrorList({
return (
<CSSMotion
{...collapseMotion}
motionDeadline={collapseMotion.motionDeadline}
motionName={`${rootPrefixCls}-show-help`}
motionAppear={false}
motionEnter={false}
visible={!!fullKeyList.length}
onLeaveStart={node => {
// Force disable css override style in index.less configured
node.style.height = 'auto';
return { height: node.offsetHeight };
}}
onVisibleChanged={onVisibleChanged}
>
{holderProps => {
const { className: holderClassName, style: holderStyle } = holderProps;

View File

@ -0,0 +1,209 @@
import CheckCircleFilled from '@ant-design/icons/CheckCircleFilled';
import CloseCircleFilled from '@ant-design/icons/CloseCircleFilled';
import ExclamationCircleFilled from '@ant-design/icons/ExclamationCircleFilled';
import LoadingOutlined from '@ant-design/icons/LoadingOutlined';
import useLayoutEffect from 'rc-util/lib/hooks/useLayoutEffect';
import classNames from 'classnames';
import * as React from 'react';
import omit from 'rc-util/lib/omit';
import type { Meta } from 'rc-field-form/lib/interface';
import { Row } from '../../grid';
import FormItemLabel from '../FormItemLabel';
import FormItemInput from '../FormItemInput';
import type { FormItemStatusContextProps, ReportMetaChange } from '../context';
import { FormContext, FormItemInputContext, NoStyleItemContext } from '../context';
import type { FormItemProps, ValidateStatus } from '.';
import useDebounce from '../hooks/useDebounce';
const iconMap = {
success: CheckCircleFilled,
warning: ExclamationCircleFilled,
error: CloseCircleFilled,
validating: LoadingOutlined,
};
export interface ItemHolderProps extends FormItemProps {
prefixCls: string;
className?: string;
style?: React.CSSProperties;
errors: React.ReactNode[];
warnings: React.ReactNode[];
meta: Meta;
children?: React.ReactNode;
fieldId?: string;
isRequired?: boolean;
onSubItemMetaChange: ReportMetaChange;
}
export default function ItemHolder(props: ItemHolderProps) {
const {
prefixCls,
className,
style,
help,
errors,
warnings,
validateStatus,
meta,
hasFeedback,
hidden,
children,
fieldId,
isRequired,
onSubItemMetaChange,
...restProps
} = props;
const itemPrefixCls = `${prefixCls}-item`;
const { requiredMark } = React.useContext(FormContext);
// ======================== Margin ========================
const itemRef = React.useRef<HTMLDivElement>(null);
const debounceErrors = useDebounce(errors);
const debounceWarnings = useDebounce(warnings);
const hasHelp = help !== undefined && help !== null;
const hasError = !!(hasHelp || errors.length || warnings.length);
const [marginBottom, setMarginBottom] = React.useState<number | null>(null);
useLayoutEffect(() => {
if (hasError && itemRef.current) {
const itemStyle = getComputedStyle(itemRef.current);
setMarginBottom(parseInt(itemStyle.marginBottom, 10));
}
}, [hasError]);
const onErrorVisibleChanged = (nextVisible: boolean) => {
if (!nextVisible) {
setMarginBottom(null);
}
};
// ======================== Status ========================
let mergedValidateStatus: ValidateStatus = '';
if (validateStatus !== undefined) {
mergedValidateStatus = validateStatus;
} else if (meta.validating) {
mergedValidateStatus = 'validating';
} else if (debounceErrors.length) {
mergedValidateStatus = 'error';
} else if (debounceWarnings.length) {
mergedValidateStatus = 'warning';
} else if (meta.touched) {
mergedValidateStatus = 'success';
}
const formItemStatusContext = React.useMemo<FormItemStatusContextProps>(() => {
let feedbackIcon: React.ReactNode;
if (hasFeedback) {
const IconNode = mergedValidateStatus && iconMap[mergedValidateStatus];
feedbackIcon = IconNode ? (
<span
className={classNames(
`${itemPrefixCls}-feedback-icon`,
`${itemPrefixCls}-feedback-icon-${mergedValidateStatus}`,
)}
>
<IconNode />
</span>
) : null;
}
return {
status: mergedValidateStatus,
hasFeedback,
feedbackIcon,
isFormItemInput: true,
};
}, [mergedValidateStatus, hasFeedback]);
// ======================== Render ========================
const itemClassName = {
[itemPrefixCls]: true,
[`${itemPrefixCls}-with-help`]: hasHelp || debounceErrors.length || debounceWarnings.length,
[`${className}`]: !!className,
// Status
[`${itemPrefixCls}-has-feedback`]: mergedValidateStatus && hasFeedback,
[`${itemPrefixCls}-has-success`]: mergedValidateStatus === 'success',
[`${itemPrefixCls}-has-warning`]: mergedValidateStatus === 'warning',
[`${itemPrefixCls}-has-error`]: mergedValidateStatus === 'error',
[`${itemPrefixCls}-is-validating`]: mergedValidateStatus === 'validating',
[`${itemPrefixCls}-hidden`]: hidden,
};
return (
<div className={classNames(itemClassName)} style={style} ref={itemRef}>
<Row
className={`${itemPrefixCls}-row`}
{...omit(restProps, [
'_internalItemRender' as any,
'colon',
'dependencies',
'extra',
'fieldKey',
'getValueFromEvent',
'getValueProps',
'htmlFor',
'id', // It is deprecated because `htmlFor` is its replacement.
'initialValue',
'isListField',
'label',
'labelAlign',
'labelCol',
'labelWrap',
'messageVariables',
'name',
'normalize',
'noStyle',
'preserve',
'required',
'requiredMark',
'rules',
'shouldUpdate',
'trigger',
'tooltip',
'validateFirst',
'validateTrigger',
'valuePropName',
'wrapperCol',
])}
>
{/* Label */}
<FormItemLabel
htmlFor={fieldId}
required={isRequired}
requiredMark={requiredMark}
{...props}
prefixCls={prefixCls}
/>
{/* Input Group */}
<FormItemInput
{...props}
{...meta}
errors={debounceErrors}
warnings={debounceWarnings}
prefixCls={prefixCls}
status={mergedValidateStatus}
help={help}
marginBottom={marginBottom}
onErrorVisibleChanged={onErrorVisibleChanged}
>
<NoStyleItemContext.Provider value={onSubItemMetaChange}>
<FormItemInputContext.Provider value={formItemStatusContext}>
{children}
</FormItemInputContext.Provider>
</NoStyleItemContext.Provider>
</FormItemInput>
</Row>
{!!marginBottom && (
<div
className={`${itemPrefixCls}-margin-offset`}
style={{
marginBottom: -marginBottom,
}}
/>
)}
</div>
);
}

View File

@ -1,34 +1,26 @@
import CheckCircleFilled from '@ant-design/icons/CheckCircleFilled';
import CloseCircleFilled from '@ant-design/icons/CloseCircleFilled';
import ExclamationCircleFilled from '@ant-design/icons/ExclamationCircleFilled';
import LoadingOutlined from '@ant-design/icons/LoadingOutlined';
import classNames from 'classnames';
import type { FormInstance } from 'rc-field-form';
import { Field, FieldContext, ListContext } from 'rc-field-form';
import type { FieldProps } from 'rc-field-form/lib/Field';
import type { Meta, NamePath } from 'rc-field-form/lib/interface';
import useState from 'rc-util/lib/hooks/useState';
import omit from 'rc-util/lib/omit';
import { supportRef } from 'rc-util/lib/ref';
import type { ReactNode } from 'react';
import * as React from 'react';
import { useContext, useMemo } from 'react';
import { ConfigContext } from '../config-provider';
import Row from '../grid/row';
import { cloneElement, isValidElement } from '../_util/reactNode';
import { tuple } from '../_util/type';
import warning from '../_util/warning';
import type { FormItemStatusContextProps } from './context';
import { FormContext, FormItemInputContext, NoStyleItemContext } from './context';
import type { FormItemInputProps } from './FormItemInput';
import FormItemInput from './FormItemInput';
import type { FormItemLabelProps, LabelTooltipType } from './FormItemLabel';
import FormItemLabel from './FormItemLabel';
import useDebounce from './hooks/useDebounce';
import useFrameState from './hooks/useFrameState';
import useItemRef from './hooks/useItemRef';
import useStyle from './style';
import { getFieldId, toArray } from './util';
import { useContext } from 'react';
import useFormItemStatus from '../hooks/useFormItemStatus';
import { ConfigContext } from '../../config-provider';
import { cloneElement, isValidElement } from '../../_util/reactNode';
import { tuple } from '../../_util/type';
import warning from '../../_util/warning';
import { FormContext, NoStyleItemContext } from '../context';
import type { FormItemInputProps } from '../FormItemInput';
import type { FormItemLabelProps, LabelTooltipType } from '../FormItemLabel';
import useFrameState from '../hooks/useFrameState';
import useItemRef from '../hooks/useItemRef';
import { getFieldId, toArray } from '../util';
import ItemHolder from './ItemHolder';
import useStyle from '../style';
const NAME_SPLIT = '__SPLIT__';
@ -93,26 +85,15 @@ function genEmptyMeta(): Meta {
};
}
const iconMap = {
success: CheckCircleFilled,
warning: ExclamationCircleFilled,
error: CloseCircleFilled,
validating: LoadingOutlined,
};
function FormItem<Values = any>(props: FormItemProps<Values>): React.ReactElement {
function InternalFormItem<Values = any>(props: FormItemProps<Values>): React.ReactElement {
const {
name,
noStyle,
className,
dependencies,
prefixCls: customizePrefixCls,
style,
className,
shouldUpdate,
hasFeedback,
help,
rules,
validateStatus,
children,
required,
label,
@ -120,10 +101,9 @@ function FormItem<Values = any>(props: FormItemProps<Values>): React.ReactElemen
trigger = 'onChange',
validateTrigger,
hidden,
...restProps
} = props;
const { getPrefixCls } = useContext(ConfigContext);
const { name: formName, requiredMark } = useContext(FormContext);
const { name: formName } = useContext(FormContext);
const isRenderProps = typeof children === 'function';
const notifyParentMetaChange = useContext(NoStyleItemContext);
@ -214,50 +194,9 @@ function FormItem<Values = any>(props: FormItemProps<Values>): React.ReactElemen
return [errorList, warningList];
}, [subFieldErrors, meta.errors, meta.warnings]);
const debounceErrors = useDebounce(mergedErrors);
const debounceWarnings = useDebounce(mergedWarnings);
// ===================== Children Ref =====================
const getItemRef = useItemRef();
// ======================== Status ========================
let mergedValidateStatus: ValidateStatus = '';
if (validateStatus !== undefined) {
mergedValidateStatus = validateStatus;
} else if (meta?.validating) {
mergedValidateStatus = 'validating';
} else if (debounceErrors.length) {
mergedValidateStatus = 'error';
} else if (debounceWarnings.length) {
mergedValidateStatus = 'warning';
} else if (meta?.touched) {
mergedValidateStatus = 'success';
}
const formItemStatusContext = useMemo<FormItemStatusContextProps>(() => {
let feedbackIcon: ReactNode;
if (hasFeedback) {
const IconNode = mergedValidateStatus && iconMap[mergedValidateStatus];
feedbackIcon = IconNode ? (
<span
className={classNames(
`${prefixCls}-item-feedback-icon`,
`${prefixCls}-item-feedback-icon-${mergedValidateStatus}`,
)}
>
<IconNode />
</span>
) : null;
}
return {
status: mergedValidateStatus,
hasFeedback,
feedbackIcon,
isFormItemInput: true,
};
}, [mergedValidateStatus, hasFeedback]);
// ======================== Render ========================
function renderLayout(
baseChildren: React.ReactNode,
@ -268,75 +207,21 @@ function FormItem<Values = any>(props: FormItemProps<Values>): React.ReactElemen
return baseChildren;
}
const itemClassName = {
[`${prefixCls}-item`]: true,
[`${prefixCls}-item-with-help`]:
(help !== undefined && help !== null) || debounceErrors.length || debounceWarnings.length,
[`${className}`]: !!className,
// Status
[`${prefixCls}-item-has-feedback`]: mergedValidateStatus && hasFeedback,
[`${prefixCls}-item-has-success`]: mergedValidateStatus === 'success',
[`${prefixCls}-item-has-warning`]: mergedValidateStatus === 'warning',
[`${prefixCls}-item-has-error`]: mergedValidateStatus === 'error',
[`${prefixCls}-item-is-validating`]: mergedValidateStatus === 'validating',
[`${prefixCls}-item-hidden`]: hidden,
};
// ======================= Children =======================
return (
<Row
className={classNames(itemClassName, hashId)}
style={style}
<ItemHolder
key="row"
{...omit(restProps, [
'colon',
'extra',
'fieldKey',
'requiredMark',
'getValueFromEvent',
'getValueProps',
'htmlFor',
'id', // It is deprecated because `htmlFor` is its replacement.
'initialValue',
'isListField',
'labelAlign',
'labelWrap',
'labelCol',
'normalize',
'preserve',
'tooltip',
'validateFirst',
'valuePropName',
'wrapperCol',
'_internalItemRender' as any,
])}
{...props}
className={classNames(className, hashId)}
prefixCls={prefixCls}
fieldId={fieldId}
isRequired={isRequired}
errors={mergedErrors}
warnings={mergedWarnings}
meta={meta}
onSubItemMetaChange={onSubItemMetaChange}
>
{/* Label */}
<FormItemLabel
htmlFor={fieldId}
required={isRequired}
requiredMark={requiredMark}
{...props}
prefixCls={prefixCls}
/>
{/* Input Group */}
<FormItemInput
{...props}
{...meta}
errors={debounceErrors}
warnings={debounceWarnings}
prefixCls={prefixCls}
status={mergedValidateStatus}
help={help}
>
<NoStyleItemContext.Provider value={onSubItemMetaChange}>
<FormItemInputContext.Provider value={formItemStatusContext}>
{baseChildren}
</FormItemInputContext.Provider>
</NoStyleItemContext.Provider>
</FormItemInput>
</Row>
{baseChildren}
</ItemHolder>
);
}
@ -467,4 +352,13 @@ function FormItem<Values = any>(props: FormItemProps<Values>): React.ReactElemen
);
}
type InternalFormItemType = typeof InternalFormItem;
interface FormItemInterface extends InternalFormItemType {
useStatus: typeof useFormItemStatus;
}
const FormItem = InternalFormItem as FormItemInterface;
FormItem.useStatus = useFormItemStatus;
export default FormItem;

View File

@ -11,6 +11,8 @@ interface FormItemInputMiscProps {
children: React.ReactNode;
errors: React.ReactNode[];
warnings: React.ReactNode[];
marginBottom?: number | null;
onErrorVisibleChanged?: (visible: boolean) => void;
/** @private Internal Usage, do not use in any of your production. */
_internalItemRender?: {
mark: string;
@ -18,7 +20,7 @@ interface FormItemInputMiscProps {
props: FormItemInputProps & FormItemInputMiscProps,
domList: {
input: JSX.Element;
errorList: JSX.Element;
errorList: JSX.Element | null;
extra: JSX.Element | null;
},
) => React.ReactNode;
@ -43,6 +45,8 @@ const FormItemInput: React.FC<FormItemInputProps & FormItemInputMiscProps> = pro
_internalItemRender: formItemRender,
extra,
help,
marginBottom,
onErrorVisibleChanged,
} = props;
const baseClassName = `${prefixCls}-item`;
@ -63,17 +67,22 @@ const FormItemInput: React.FC<FormItemInputProps & FormItemInputMiscProps> = pro
</div>
);
const formItemContext = React.useMemo(() => ({ prefixCls, status }), [prefixCls, status]);
const errorListDom = (
<FormItemPrefixContext.Provider value={formItemContext}>
<ErrorList
errors={errors}
warnings={warnings}
help={help}
helpStatus={status}
className={`${baseClassName}-explain-connected`}
/>
</FormItemPrefixContext.Provider>
);
const errorListDom =
marginBottom !== null || errors.length || warnings.length ? (
<div style={{ display: 'flex', flexWrap: 'nowrap' }}>
<FormItemPrefixContext.Provider value={formItemContext}>
<ErrorList
errors={errors}
warnings={warnings}
help={help}
helpStatus={status}
className={`${baseClassName}-explain-connected`}
onVisibleChanged={onErrorVisibleChanged}
/>
</FormItemPrefixContext.Provider>
{!!marginBottom && <div style={{ width: 0, height: marginBottom }} />}
</div>
) : null;
// If extra = 0, && will goes wrong
// 0&&error -> 0

File diff suppressed because it is too large Load Diff

File diff suppressed because it is too large Load Diff

File diff suppressed because it is too large Load Diff

View File

@ -2,13 +2,14 @@ import { mount } from 'enzyme';
import React, { Component, useState } from 'react';
import { act } from 'react-dom/test-utils';
import scrollIntoView from 'scroll-into-view-if-needed';
import classNames from 'classnames';
import Form from '..';
import * as Util from '../util';
import Button from '../../button';
import Input from '../../input';
import Select from '../../select';
import Upload from '../../upload';
import Cascader from '../../cascader';
import Checkbox from '../../checkbox';
import DatePicker from '../../date-picker';
@ -947,6 +948,9 @@ describe('Form', () => {
<Form.Item label="Switch" valuePropName="checked">
<Switch />
</Form.Item>
<Form.Item label="Upload" valuePropName="fileList">
<Upload />
</Form.Item>
<Form.Item label="Button">
<Button>Button</Button>
</Form.Item>
@ -1245,4 +1249,85 @@ describe('Form', () => {
expect(container.querySelector('.drawer-select')?.className).not.toContain('in-form-item');
expect(container.querySelector('.drawer-select')?.className).not.toContain('status-error');
});
it('Form.Item.useStatus should work', async () => {
const {
Item: { useStatus },
} = Form;
const CustomInput = ({ className, value }) => {
const { status } = useStatus();
return <div className={classNames(className, `custom-input-status-${status}`)}>{value}</div>;
};
const Demo = () => {
const [form] = Form.useForm();
return (
<Form form={form} name="my-form">
<Form.Item name="required" rules={[{ required: true }]}>
<CustomInput className="custom-input-required" value="" />
</Form.Item>
<Form.Item name="warning" validateStatus="warning">
<CustomInput className="custom-input-warning" />
</Form.Item>
<Form.Item name="normal">
<CustomInput className="custom-input" />
</Form.Item>
<CustomInput className="custom-input-wrong" />
<Button onClick={() => form.submit()} className="submit-button">
Submit
</Button>
</Form>
);
};
const { container } = render(<Demo />);
expect(container.querySelector('.custom-input-required')?.classList).toContain(
'custom-input-status-',
);
expect(container.querySelector('.custom-input-warning')?.classList).toContain(
'custom-input-status-warning',
);
expect(container.querySelector('.custom-input')?.classList).toContain('custom-input-status-');
expect(container.querySelector('.custom-input-wrong')?.classList).toContain(
'custom-input-status-undefined',
);
expect(errorSpy).toHaveBeenCalledWith(
expect.stringContaining('Form.Item.useStatus should be used under Form.Item component.'),
);
fireEvent.click(container.querySelector('.submit-button'));
await sleep(0);
expect(container.querySelector('.custom-input-required')?.classList).toContain(
'custom-input-status-error',
);
});
it('item customize margin', async () => {
const computeSpy = jest.spyOn(window, 'getComputedStyle').mockImplementation(() => ({
marginBottom: 24,
}));
const { container } = render(
<Form>
<Form.Item name="required" initialValue="bamboo" rules={[{ required: true }]}>
<Input />
</Form.Item>
</Form>,
);
fireEvent.change(container.querySelector('input'), {
target: {
value: '',
},
});
await sleep(0);
computeSpy.mockRestore();
expect(container.querySelector('.ant-form-item-margin-offset')).toHaveStyle({
marginBottom: -24,
});
});
});

View File

@ -15,6 +15,7 @@ Set component disabled, only works for antd components.
```tsx
import React, { useState } from 'react';
import { PlusOutlined } from '@ant-design/icons';
import {
Form,
Input,
@ -27,6 +28,7 @@ import {
TreeSelect,
Switch,
Checkbox,
Upload,
} from 'antd';
const { RangePicker } = DatePicker;
@ -102,6 +104,14 @@ const FormDisabledDemo = () => {
<Form.Item label="Switch" valuePropName="checked">
<Switch />
</Form.Item>
<Form.Item label="Upload" valuePropName="fileList">
<Upload action="/upload.do" listType="picture-card">
<div>
<PlusOutlined />
<div style={{ marginTop: 8 }}>Upload</div>
</div>
</Upload>
</Form.Item>
<Form.Item label="Button">
<Button>Button</Button>
</Form.Item>

View File

@ -0,0 +1,22 @@
import { useContext } from 'react';
import type { ValidateStatus } from 'antd/es/form/FormItem';
import { FormItemInputContext } from '../context';
import warning from '../../_util/warning';
type UseFormItemStatus = () => {
status?: ValidateStatus;
};
const useFormItemStatus: UseFormItemStatus = () => {
const { status } = useContext(FormItemInputContext);
warning(
status !== undefined,
'Form.Item',
`Form.Item.useStatus should be used under Form.Item component. For more information: ${window.location.protocol}//${window.location.host}/components/form-cn/#Form.Item.useStatus`,
);
return { status };
};
export default useFormItemStatus;

View File

@ -246,7 +246,8 @@ Provide linkage between forms. If a sub form with `name` prop update, it will au
| resetFields | Reset fields to `initialValues` | (fields?: [NamePath](#NamePath)\[]) => void | |
| scrollToField | Scroll to field position | (name: [NamePath](#NamePath), options: \[[ScrollOptions](https://github.com/stipsan/scroll-into-view-if-needed/tree/ece40bd9143f48caf4b99503425ecb16b0ad8249#options)]) => void | |
| setFields | Set fields status | (fields: [FieldData](#FieldData)\[]) => void | |
| setFieldsValue | Set fields value(Will directly pass to form store. If you do not want to modify passed object, please clone first) | (values) => void | |
| setFieldValue | Set fields value(Will directly pass to form store. If you do not want to modify passed object, please clone first) | (name: [NamePath](#NamePath), value: any) => void | 4.22.0 |
| setFieldsValue | Set fields value(Will directly pass to form store. If you do not want to modify passed object, please clone first). Use `setFieldValue` instead if you want to only config single value in Form.List | (values) => void | |
| submit | Submit the form. It's same as click `submit` button | () => void | |
| validateFields | Validate fields | (nameList?: [NamePath](#NamePath)\[]) => Promise | |
@ -335,6 +336,27 @@ const Demo = () => {
};
```
### Form.Item.useStatus
`type Form.useFormItemStatus = (): { status: ValidateStatus | undefined }`
Added in `4.22.0`. Could be used to get validate status of Form.Item. If this hook is not used under Form.Item, `status` would be `undefined`:
```tsx
const CustomInput = ({ value }) => {
const { status } = Form.Item.useStatus();
return <input value={value} className={`custom-input-${status}`} />;
};
export default () => (
<Form>
<Form.Item name="username">
<CustomInput />
</Form.Item>
</Form>
);
```
#### Difference between other data fetching method
Form only update the Field which changed to avoid full refresh perf issue. Thus you can not get real time value with `getFieldsValue` in render. And `useWatch` will rerender current component to sync with latest value. You can also use Field renderProps to get better performance if only want to do conditional render. If component no need care field value change, you can use `onValuesChange` to give to parent component to avoid current one rerender.

View File

@ -245,7 +245,8 @@ Form.List 渲染表单相关操作函数。
| resetFields | 重置一组字段到 `initialValues` | (fields?: [NamePath](#NamePath)\[]) => void | |
| scrollToField | 滚动到对应字段位置 | (name: [NamePath](#NamePath), options: [ScrollOptions](https://github.com/stipsan/scroll-into-view-if-needed/tree/ece40bd9143f48caf4b99503425ecb16b0ad8249#options)) => void | |
| setFields | 设置一组字段状态 | (fields: [FieldData](#FieldData)\[]) => void | |
| setFieldsValue | 设置表单的值(该值将直接传入 form store 中。如果你不希望传入对象被修改,请克隆后传入) | (values) => void | |
| setFieldValue | 设置表单的值(该值将直接传入 form store 中。如果你不希望传入对象被修改,请克隆后传入) | (name: [NamePath](#NamePath), value: any) => void | 4.22.0 |
| setFieldsValue | 设置表单的值(该值将直接传入 form store 中。如果你不希望传入对象被修改,请克隆后传入)。如果你只想修改 Form.List 中单项值,请通过 `setFieldValue` 进行指定 | (values) => void | |
| submit | 提交表单,与点击 `submit` 按钮效果相同 | () => void | |
| validateFields | 触发表单验证 | (nameList?: [NamePath](#NamePath)\[]) => Promise | |
@ -334,6 +335,27 @@ const Demo = () => {
};
```
### Form.Item.useStatus
`type Form.Item.useStatus = (): { status: ValidateStatus | undefined }`
`4.22.0` 新增,可用于获取当前 Form.Item 的校验状态,如果上层没有 Form.Item`status` 将会返回 `undefined`
```tsx
const CustomInput = ({ value }) => {
const { status } = Form.Item.useStatus();
return <input value={value} className={`custom-input-${status}`} />;
};
export default () => (
<Form>
<Form.Item name="username">
<CustomInput />
</Form.Item>
</Form>
);
```
#### 与其他获取数据的方式的区别
Form 仅会对变更的 Field 进行刷新,从而避免完整的组件刷新可能引发的性能问题。因而你无法在 render 阶段通过 `form.getFieldsValue` 来实时获取字段值,而 `useWatch` 提供了一种特定字段访问的方式,从而使得在当前组件中可以直接消费字段的值。同时,如果为了更好的渲染性能,你可以通过 Field 的 renderProps 仅更新需要更新的部分。而当当前组件更新或者 effect 都不需要消费字段值时,则可以通过 `onValuesChange` 将数据抛出,从而避免组件更新。

View File

@ -114,11 +114,8 @@ const genFormItemStyle: GenerateStyle<FormToken> = token => {
marginBottom: token.marginLG,
verticalAlign: 'top',
// We delay one frame (0.017s) here to let CSSMotion goes
transition: `margin-bottom ${token.motionDurationSlow} 0.017s linear`,
'&-with-help': {
marginBottom: 0,
transition: 'none',
},
@ -262,9 +259,7 @@ const genFormItemStyle: GenerateStyle<FormToken> = token => {
},
'&-explain-connected': {
height: 0,
minHeight: 0,
opacity: 0,
width: '100%',
},
'&-extra': {
@ -284,7 +279,6 @@ const genFormItemStyle: GenerateStyle<FormToken> = token => {
[`&-with-help ${formItemCls}-explain`]: {
height: 'auto',
minHeight: token.controlHeightSM,
opacity: 1,
},
@ -327,16 +321,21 @@ const genFormMotionStyle: GenerateStyle<FormToken> = token => {
[componentCls]: {
// Explain holder
[`.${rootPrefixCls}-show-help`]: {
transition: `height ${token.motionDurationSlow} linear,
min-height ${token.motionDurationSlow} linear,
margin-bottom ${token.motionDurationSlow} ${token.motionEaseInOut},
opacity ${token.motionDurationSlow} ${token.motionEaseInOut}`,
transition: `opacity ${token.motionDurationSlow} ${token.motionEaseInOut}`,
'&-leave': {
minHeight: token.controlHeightSM,
'&-appear, &-enter': {
opacity: 0,
'&-active': {
minHeight: 0,
opacity: 1,
},
},
'&-leave': {
opacity: 1,
'&-active': {
opacity: 0,
},
},
},

View File

@ -364,22 +364,26 @@ exports[`Input should support size in form 1`] = `
class="ant-form ant-form-horizontal ant-form-large"
>
<div
class="ant-row ant-form-item"
class="ant-form-item"
>
<div
class="ant-col ant-form-item-control"
class="ant-row ant-form-item-row"
>
<div
class="ant-form-item-control-input"
class="ant-col ant-form-item-control"
>
<div
class="ant-form-item-control-input-content"
class="ant-form-item-control-input"
>
<input
class="ant-input ant-input-lg"
type="text"
value=""
/>
<div
class="ant-form-item-control-input-content"
>
<input
class="ant-input ant-input-lg"
type="text"
value=""
/>
</div>
</div>
</div>
</div>

View File

@ -133,6 +133,7 @@ import ptBR from '../pt_BR';
import ptPT from '../pt_PT';
import roRO from '../ro_RO';
import ruRU from '../ru_RU';
import siLK from '../si_LK';
import skSK from '../sk_SK';
import slSI from '../sl_SI';
import srRS from '../sr_RS';
@ -201,6 +202,7 @@ const locales = [
ptPT,
roRO,
ruRU,
siLK,
skSK,
slSI,
srRS,

View File

@ -0,0 +1,3 @@
import locale from '../locale/si_LK';
export default locale;

136
components/locale/si_LK.tsx Normal file
View File

@ -0,0 +1,136 @@
/* eslint-disable no-template-curly-in-string */
import Pagination from 'rc-pagination/lib/locale/si_LK';
import DatePicker from '../date-picker/locale/si_LK';
import TimePicker from '../time-picker/locale/si_LK';
import Calendar from '../calendar/locale/si_LK';
import type { Locale } from '../locale-provider';
const typeTemplate = '${label} වලංගු ${type} ක් නොවේ';
const localeValues: Locale = {
locale: 'si',
Pagination,
DatePicker,
TimePicker,
Calendar,
global: {
placeholder: 'කරුණාකර තෝරන්න',
},
Table: {
filterTitle: 'පෙරහන්',
filterConfirm: 'හරි',
filterReset: 'යළි සකසන්න',
filterEmptyText: 'පෙරහන් නැත',
filterCheckall: 'සියළු අථක තෝරන්න',
filterSearchPlaceholder: 'පෙරහන් තුළ සොයන්න',
emptyText: 'දත්ත නැත',
selectAll: 'වත්මන් පිටුව තෝරන්න',
selectInvert: 'වත්මන් පිටුව යටියනය',
selectNone: 'සියළු දත්ත ඉවතලන්න',
selectionAll: 'සියළු දත්ත තෝරන්න',
sortTitle: 'පෙළගැසීම',
expand: 'පේළිය දිගහරින්න',
collapse: 'පේළිය හකුළන්න',
triggerDesc: 'අවරෝහණව පෙළගැසීමට ඔබන්න',
triggerAsc: 'ආරෝහණව පෙළගැසීමට ඔබන්න',
cancelSort: 'පෙළගැසීම අවලංගු කිරීමට ඔබන්න',
},
Modal: {
okText: 'හරි',
cancelText: 'අවලංගු කරන්න',
justOkText: 'හරි',
},
Popconfirm: {
okText: 'හරි',
cancelText: 'අවලංගු කරන්න',
},
Transfer: {
titles: ['', ''],
searchPlaceholder: 'මෙතැන සොයන්න',
itemUnit: 'අථකය',
itemsUnit: 'අථක',
remove: 'ඉවත් කරන්න',
selectCurrent: 'වත්මන් පිටුව තෝරන්න',
removeCurrent: 'වත්මන් පිටුව ඉවත් කරන්න',
selectAll: 'සියළු දත්ත තෝරන්න',
removeAll: 'සියළු දත්ත ඉවතලන්න',
selectInvert: 'වත්මන් පිටුව යටියනය',
},
Upload: {
uploading: 'උඩුගත වෙමින්...',
removeFile: 'ගොනුව ඉවතලන්න',
uploadError: 'උඩුගත වීමේ දෝෂයකි',
previewFile: 'ගොනුවේ පෙරදසුන',
downloadFile: 'ගොනුව බාගන්න',
},
Empty: {
description: 'දත්ත නැත',
},
Icon: {
icon: 'නිරූපකය',
},
Text: {
edit: 'සංස්කරණය',
copy: 'පිටපත්',
copied: 'පිටපත් විය',
expand: 'විහිදුවන්න',
},
PageHeader: {
back: 'ආපසු',
},
Form: {
optional: '(විකල්පයකි)',
defaultValidateMessages: {
default: '${label} සඳහා ක්‍ෂේත්‍රය වලංගුකරණයේ දෝෂයකි',
required: '${label} ඇතුල් කරන්න',
enum: '[${enum}] වලින් එකක් ${label} විය යුතුය',
whitespace: '${label} හිස් අකුරක් නොවිය යුතුය',
date: {
format: '${label} දිනයේ ආකෘතිය වැරදිය',
parse: '${label} දිනයකට පරිවර්තනය කළ නොහැකිය',
invalid: '${label} වලංගු නොවන දිනයකි',
},
types: {
string: typeTemplate,
method: typeTemplate,
array: typeTemplate,
object: typeTemplate,
number: typeTemplate,
date: typeTemplate,
boolean: typeTemplate,
integer: typeTemplate,
float: typeTemplate,
regexp: typeTemplate,
email: typeTemplate,
url: typeTemplate,
hex: typeTemplate,
},
string: {
len: '${label} අකුරු ${len}ක් විය යුතුය',
min: '${label} අවමය අකුරු ${min}ක් විය යුතුය',
max: '${label} අකුරු ${max}ක් දක්වා විය යුතුය',
range: '${label} අකුරු ${min}-${max}ක් අතර විය යුතුය',
},
number: {
len: '${label} නිසැකව ${len} සමාන විය යුතුය',
min: '${label} අවමය ${min} විය යුතුය',
max: '${label} උපරිමය ${max} විය යුතුය',
range: '${label} නිසැකව ${min}-${max} අතර විය යුතුය',
},
array: {
len: '${len} ${label} විය යුතුය',
min: 'අවම වශයෙන් ${min} ${label}',
max: 'උපරිම වශයෙන් ${max} ${label}',
range: '${label} ගණන ${min}-${max} අතර විය යුතුය',
},
pattern: {
mismatch: '${pattern} රටාවට ${label} නොගැළපේ',
},
},
},
Image: {
preview: 'පෙරදසුන',
},
};
export default localeValues;

View File

@ -43,107 +43,119 @@ exports[`renders ./components/mentions/demo/form.md extend context correctly 1`]
class="ant-form ant-form-horizontal"
>
<div
class="ant-row ant-form-item"
class="ant-form-item"
>
<div
class="ant-col ant-col-6 ant-form-item-label"
>
<label
class=""
for="coders"
title="Top coders"
>
Top coders
</label>
</div>
<div
class="ant-col ant-col-16 ant-form-item-control"
class="ant-row ant-form-item-row"
>
<div
class="ant-form-item-control-input"
class="ant-col ant-col-6 ant-form-item-label"
>
<label
class=""
for="coders"
title="Top coders"
>
Top coders
</label>
</div>
<div
class="ant-col ant-col-16 ant-form-item-control"
>
<div
class="ant-form-item-control-input-content"
class="ant-form-item-control-input"
>
<div
class="ant-mentions"
class="ant-form-item-control-input-content"
>
<textarea
class="rc-textarea"
id="coders"
rows="1"
/>
<div
class="ant-mentions"
>
<textarea
class="rc-textarea"
id="coders"
rows="1"
/>
</div>
</div>
</div>
</div>
</div>
</div>
<div
class="ant-row ant-form-item"
class="ant-form-item"
>
<div
class="ant-col ant-col-6 ant-form-item-label"
>
<label
class="ant-form-item-required"
for="bio"
title="Bio"
>
Bio
</label>
</div>
<div
class="ant-col ant-col-16 ant-form-item-control"
class="ant-row ant-form-item-row"
>
<div
class="ant-form-item-control-input"
class="ant-col ant-col-6 ant-form-item-label"
>
<label
class="ant-form-item-required"
for="bio"
title="Bio"
>
Bio
</label>
</div>
<div
class="ant-col ant-col-16 ant-form-item-control"
>
<div
class="ant-form-item-control-input-content"
class="ant-form-item-control-input"
>
<div
class="ant-mentions"
class="ant-form-item-control-input-content"
>
<textarea
class="rc-textarea"
id="bio"
placeholder="You can use @ to ref user here"
rows="3"
/>
<div
class="ant-mentions"
>
<textarea
class="rc-textarea"
id="bio"
placeholder="You can use @ to ref user here"
rows="3"
/>
</div>
</div>
</div>
</div>
</div>
</div>
<div
class="ant-row ant-form-item"
class="ant-form-item"
>
<div
class="ant-col ant-col-14 ant-col-offset-6 ant-form-item-control"
class="ant-row ant-form-item-row"
>
<div
class="ant-form-item-control-input"
class="ant-col ant-col-14 ant-col-offset-6 ant-form-item-control"
>
<div
class="ant-form-item-control-input-content"
class="ant-form-item-control-input"
>
<button
class="ant-btn ant-btn-primary"
type="submit"
<div
class="ant-form-item-control-input-content"
>
<span>
Submit
</span>
</button>
   
<button
class="ant-btn ant-btn-default"
type="button"
>
<span>
Reset
</span>
</button>
<button
class="ant-btn ant-btn-primary"
type="submit"
>
<span>
Submit
</span>
</button>
   
<button
class="ant-btn ant-btn-default"
type="button"
>
<span>
Reset
</span>
</button>
</div>
</div>
</div>
</div>

View File

@ -43,107 +43,119 @@ exports[`renders ./components/mentions/demo/form.md correctly 1`] = `
class="ant-form ant-form-horizontal"
>
<div
class="ant-row ant-form-item"
class="ant-form-item"
>
<div
class="ant-col ant-col-6 ant-form-item-label"
>
<label
class=""
for="coders"
title="Top coders"
>
Top coders
</label>
</div>
<div
class="ant-col ant-col-16 ant-form-item-control"
class="ant-row ant-form-item-row"
>
<div
class="ant-form-item-control-input"
class="ant-col ant-col-6 ant-form-item-label"
>
<label
class=""
for="coders"
title="Top coders"
>
Top coders
</label>
</div>
<div
class="ant-col ant-col-16 ant-form-item-control"
>
<div
class="ant-form-item-control-input-content"
class="ant-form-item-control-input"
>
<div
class="ant-mentions"
class="ant-form-item-control-input-content"
>
<textarea
class="rc-textarea"
id="coders"
rows="1"
/>
<div
class="ant-mentions"
>
<textarea
class="rc-textarea"
id="coders"
rows="1"
/>
</div>
</div>
</div>
</div>
</div>
</div>
<div
class="ant-row ant-form-item"
class="ant-form-item"
>
<div
class="ant-col ant-col-6 ant-form-item-label"
>
<label
class="ant-form-item-required"
for="bio"
title="Bio"
>
Bio
</label>
</div>
<div
class="ant-col ant-col-16 ant-form-item-control"
class="ant-row ant-form-item-row"
>
<div
class="ant-form-item-control-input"
class="ant-col ant-col-6 ant-form-item-label"
>
<label
class="ant-form-item-required"
for="bio"
title="Bio"
>
Bio
</label>
</div>
<div
class="ant-col ant-col-16 ant-form-item-control"
>
<div
class="ant-form-item-control-input-content"
class="ant-form-item-control-input"
>
<div
class="ant-mentions"
class="ant-form-item-control-input-content"
>
<textarea
class="rc-textarea"
id="bio"
placeholder="You can use @ to ref user here"
rows="3"
/>
<div
class="ant-mentions"
>
<textarea
class="rc-textarea"
id="bio"
placeholder="You can use @ to ref user here"
rows="3"
/>
</div>
</div>
</div>
</div>
</div>
</div>
<div
class="ant-row ant-form-item"
class="ant-form-item"
>
<div
class="ant-col ant-col-14 ant-col-offset-6 ant-form-item-control"
class="ant-row ant-form-item-row"
>
<div
class="ant-form-item-control-input"
class="ant-col ant-col-14 ant-col-offset-6 ant-form-item-control"
>
<div
class="ant-form-item-control-input-content"
class="ant-form-item-control-input"
>
<button
class="ant-btn ant-btn-primary"
type="submit"
<div
class="ant-form-item-control-input-content"
>
<span>
Submit
</span>
</button>
   
<button
class="ant-btn ant-btn-default"
type="button"
>
<span>
Reset
</span>
</button>
<button
class="ant-btn ant-btn-primary"
type="submit"
>
<span>
Submit
</span>
</button>
   
<button
class="ant-btn ant-btn-default"
type="button"
>
<span>
Reset
</span>
</button>
</div>
</div>
</div>
</div>

View File

@ -0,0 +1,136 @@
@dialog-prefix-cls: ~'@{ant-prefix}-modal';
.@{dialog-prefix-cls} {
.reset-component();
.modal-mask();
position: relative;
top: 100px;
width: auto;
max-width: calc(100vw - 32px);
margin: 0 auto;
padding-bottom: 24px;
&-wrap {
z-index: @zindex-modal;
}
&-title {
margin: 0;
color: @modal-heading-color;
font-weight: 500;
font-size: @modal-header-title-font-size;
line-height: @modal-header-title-line-height;
word-wrap: break-word;
}
&-content {
position: relative;
background-color: @modal-content-bg;
background-clip: padding-box;
border: 0;
border-radius: @modal-border-radius;
box-shadow: @shadow-2;
pointer-events: auto;
}
&-close {
position: absolute;
top: 0;
right: 0;
z-index: @zindex-popup-close;
padding: 0;
color: @modal-close-color;
font-weight: 700;
line-height: 1;
text-decoration: none;
background: transparent;
border: 0;
outline: 0;
cursor: pointer;
transition: color 0.3s;
&-x {
display: block;
width: @modal-header-close-size;
height: @modal-header-close-size;
font-size: @font-size-lg;
font-style: normal;
line-height: @modal-header-close-size;
text-align: center;
text-transform: none;
text-rendering: auto;
}
&:focus,
&:hover {
color: @icon-color-hover;
text-decoration: none;
}
}
&-header {
padding: @modal-header-padding;
color: @text-color;
background: @modal-header-bg;
border-bottom: @modal-header-border-width @modal-header-border-style
@modal-header-border-color-split;
border-radius: @modal-border-radius @modal-border-radius 0 0;
}
&-body {
padding: @modal-body-padding;
font-size: @font-size-base;
line-height: @line-height-base;
word-wrap: break-word;
}
&-footer {
padding: @modal-footer-padding-vertical @modal-footer-padding-horizontal;
text-align: right;
background: @modal-footer-bg;
border-top: @modal-footer-border-width @modal-footer-border-style
@modal-footer-border-color-split;
border-radius: 0 0 @modal-border-radius @modal-border-radius;
.@{ant-prefix}-btn + .@{ant-prefix}-btn:not(.@{ant-prefix}-dropdown-trigger) {
margin-bottom: 0;
margin-left: 8px;
}
}
&-open {
overflow: hidden;
}
}
.@{dialog-prefix-cls}-centered {
text-align: center;
&::before {
display: inline-block;
width: 0;
height: 100%;
vertical-align: middle;
content: '';
}
.@{dialog-prefix-cls} {
top: 0;
display: inline-block;
padding-bottom: 0;
text-align: left;
vertical-align: middle;
}
}
@media (max-width: @screen-sm-max) {
.@{dialog-prefix-cls} {
max-width: calc(100vw - 16px);
margin: 8px auto;
}
.@{dialog-prefix-cls}-centered {
.@{dialog-prefix-cls} {
flex: 1;
}
}
}

View File

@ -1,6 +1,6 @@
import { render as testLibRender } from '@testing-library/react';
import { mount, render } from 'enzyme';
import React from 'react';
import { mount, render } from 'enzyme';
import { fireEvent, render as testLibRender } from '@testing-library/react';
import Radio from '..';
describe('Radio Group', () => {
@ -224,4 +224,16 @@ describe('Radio Group', () => {
});
});
});
it('onBlur & onFocus should work', () => {
const handleBlur = jest.fn();
const handleFocus = jest.fn();
const { container } = testLibRender(
<Radio.Group options={['1', '2', '3']} onBlur={handleBlur} onFocus={handleFocus} />,
);
fireEvent.focus(container.firstChild);
expect(handleFocus).toHaveBeenCalledTimes(1);
fireEvent.blur(container.firstChild);
expect(handleBlur).toHaveBeenCalledTimes(1);
});
});

View File

@ -18,13 +18,6 @@ const RadioGroup = React.forwardRef<HTMLDivElement, RadioGroupProps>((props, ref
value: props.value,
});
const { prefixCls: customizePrefixCls } = props;
const prefixCls = getPrefixCls('radio', customizePrefixCls);
const groupPrefixCls = `${prefixCls}-group`;
// Style
const [wrapSSR, hashId] = useStyle(prefixCls);
const onRadioChange = (ev: RadioChangeEvent) => {
const lastValue = value;
const val = ev.target.value;
@ -37,91 +30,96 @@ const RadioGroup = React.forwardRef<HTMLDivElement, RadioGroupProps>((props, ref
}
};
const renderGroup = () => {
const {
className = '',
options,
buttonStyle = 'outline' as RadioGroupButtonStyle,
disabled,
children,
size: customizeSize,
style,
id,
onMouseEnter,
onMouseLeave,
} = props;
let childrenToRender = children;
// 如果存在 options, 优先使用
if (options && options.length > 0) {
childrenToRender = options.map(option => {
if (typeof option === 'string' || typeof option === 'number') {
// 此处类型自动推导为 string
return (
<Radio
key={option.toString()}
prefixCls={prefixCls}
disabled={disabled}
value={option}
checked={value === option}
>
{option}
</Radio>
);
}
// 此处类型自动推导为 { label: string value: string }
const {
prefixCls: customizePrefixCls,
className = '',
options,
buttonStyle = 'outline' as RadioGroupButtonStyle,
disabled,
children,
size: customizeSize,
style,
id,
onMouseEnter,
onMouseLeave,
onFocus,
onBlur,
} = props;
const prefixCls = getPrefixCls('radio', customizePrefixCls);
const groupPrefixCls = `${prefixCls}-group`;
// Style
const [wrapSSR, hashId] = useStyle(prefixCls);
let childrenToRender = children;
// 如果存在 options, 优先使用
if (options && options.length > 0) {
childrenToRender = options.map(option => {
if (typeof option === 'string' || typeof option === 'number') {
// 此处类型自动推导为 string
return (
<Radio
key={`radio-group-value-options-${option.value}`}
key={option.toString()}
prefixCls={prefixCls}
disabled={option.disabled || disabled}
value={option.value}
checked={value === option.value}
style={option.style}
disabled={disabled}
value={option}
checked={value === option}
>
{option.label}
{option}
</Radio>
);
});
}
}
// 此处类型自动推导为 { label: string value: string }
return (
<Radio
key={`radio-group-value-options-${option.value}`}
prefixCls={prefixCls}
disabled={option.disabled || disabled}
value={option.value}
checked={value === option.value}
style={option.style}
>
{option.label}
</Radio>
);
});
}
const mergedSize = customizeSize || size;
const classString = classNames(
groupPrefixCls,
`${groupPrefixCls}-${buttonStyle}`,
{
[`${groupPrefixCls}-${mergedSize}`]: mergedSize,
[`${groupPrefixCls}-rtl`]: direction === 'rtl',
},
className,
hashId,
);
return wrapSSR(
<div
{...getDataOrAriaProps(props)}
className={classString}
style={style}
onMouseEnter={onMouseEnter}
onMouseLeave={onMouseLeave}
id={id}
ref={ref}
const mergedSize = customizeSize || size;
const classString = classNames(
groupPrefixCls,
`${groupPrefixCls}-${buttonStyle}`,
{
[`${groupPrefixCls}-${mergedSize}`]: mergedSize,
[`${groupPrefixCls}-rtl`]: direction === 'rtl',
},
className,
hashId,
);
return wrapSSR(
<div
{...getDataOrAriaProps(props)}
className={classString}
style={style}
onMouseEnter={onMouseEnter}
onMouseLeave={onMouseLeave}
onFocus={onFocus}
onBlur={onBlur}
id={id}
ref={ref}
>
<RadioGroupContextProvider
value={{
onChange: onRadioChange,
value,
disabled: props.disabled,
name: props.name,
optionType: props.optionType,
}}
>
{childrenToRender}
</div>,
);
};
return (
<RadioGroupContextProvider
value={{
onChange: onRadioChange,
value,
disabled: props.disabled,
name: props.name,
optionType: props.optionType,
}}
>
{renderGroup()}
</RadioGroupContextProvider>
</RadioGroupContextProvider>
</div>,
);
});

View File

@ -20,6 +20,8 @@ export interface RadioGroupProps extends AbstractCheckboxGroupProps {
id?: string;
optionType?: RadioGroupOptionType;
buttonStyle?: RadioGroupButtonStyle;
onFocus?: React.FocusEventHandler<HTMLDivElement>;
onBlur?: React.FocusEventHandler<HTMLDivElement>;
}
export interface RadioGroupContextProps {

View File

@ -6,7 +6,7 @@ export interface SkeletonElementProps {
className?: string;
style?: React.CSSProperties;
size?: 'large' | 'small' | 'default' | number;
shape?: 'circle' | 'square' | 'round';
shape?: 'circle' | 'square' | 'round' | 'default';
active?: boolean;
}

View File

@ -114,7 +114,7 @@ Array [
class="ant-skeleton ant-skeleton-element"
>
<span
class="ant-skeleton-button ant-skeleton-button-square"
class="ant-skeleton-button"
/>
</div>
</div>
@ -148,7 +148,7 @@ Array [
class="ant-skeleton ant-skeleton-element"
>
<span
class="ant-skeleton-button ant-skeleton-button-square"
class="ant-skeleton-button"
/>
</div>,
<br />,
@ -230,323 +230,362 @@ Array [
style="margin:16px 0"
>
<div
class="ant-row ant-form-item"
class="ant-form-item"
>
<div
class="ant-col ant-form-item-label"
>
<label
class=""
title="Active"
>
Active
</label>
</div>
<div
class="ant-col ant-form-item-control"
class="ant-row ant-form-item-row"
>
<div
class="ant-form-item-control-input"
class="ant-col ant-form-item-label"
>
<div
class="ant-form-item-control-input-content"
<label
class=""
title="Active"
>
<button
aria-checked="false"
class="ant-switch"
role="switch"
type="button"
>
<div
class="ant-switch-handle"
/>
<span
class="ant-switch-inner"
/>
</button>
</div>
Active
</label>
</div>
</div>
</div>
<div
class="ant-row ant-form-item"
>
<div
class="ant-col ant-form-item-label"
>
<label
class=""
title="Button and Input Block"
>
Button and Input Block
</label>
</div>
<div
class="ant-col ant-form-item-control"
>
<div
class="ant-form-item-control-input"
class="ant-col ant-form-item-control"
>
<div
class="ant-form-item-control-input-content"
>
<button
aria-checked="false"
class="ant-switch"
role="switch"
type="button"
>
<div
class="ant-switch-handle"
/>
<span
class="ant-switch-inner"
/>
</button>
</div>
</div>
</div>
</div>
<div
class="ant-row ant-form-item"
>
<div
class="ant-col ant-form-item-label"
>
<label
class=""
title="Size"
>
Size
</label>
</div>
<div
class="ant-col ant-form-item-control"
>
<div
class="ant-form-item-control-input"
>
<div
class="ant-form-item-control-input-content"
class="ant-form-item-control-input"
>
<div
class="ant-radio-group ant-radio-group-outline"
class="ant-form-item-control-input-content"
>
<label
class="ant-radio-button-wrapper ant-radio-button-wrapper-checked ant-radio-button-wrapper-in-form-item"
<button
aria-checked="false"
class="ant-switch"
role="switch"
type="button"
>
<div
class="ant-switch-handle"
/>
<span
class="ant-radio-button ant-radio-button-checked"
>
<input
checked=""
class="ant-radio-button-input"
type="radio"
value="default"
/>
<span
class="ant-radio-button-inner"
/>
</span>
<span>
Default
</span>
</label>
<label
class="ant-radio-button-wrapper ant-radio-button-wrapper-in-form-item"
>
<span
class="ant-radio-button"
>
<input
class="ant-radio-button-input"
type="radio"
value="large"
/>
<span
class="ant-radio-button-inner"
/>
</span>
<span>
Large
</span>
</label>
<label
class="ant-radio-button-wrapper ant-radio-button-wrapper-in-form-item"
>
<span
class="ant-radio-button"
>
<input
class="ant-radio-button-input"
type="radio"
value="small"
/>
<span
class="ant-radio-button-inner"
/>
</span>
<span>
Small
</span>
</label>
class="ant-switch-inner"
/>
</button>
</div>
</div>
</div>
</div>
</div>
<div
class="ant-row ant-form-item"
class="ant-form-item"
>
<div
class="ant-col ant-form-item-label"
>
<label
class=""
title="Button Shape"
>
Button Shape
</label>
</div>
<div
class="ant-col ant-form-item-control"
class="ant-row ant-form-item-row"
>
<div
class="ant-form-item-control-input"
class="ant-col ant-form-item-label"
>
<label
class=""
title="Button and Input Block"
>
Button and Input Block
</label>
</div>
<div
class="ant-col ant-form-item-control"
>
<div
class="ant-form-item-control-input-content"
class="ant-form-item-control-input"
>
<div
class="ant-radio-group ant-radio-group-outline"
class="ant-form-item-control-input-content"
>
<label
class="ant-radio-button-wrapper ant-radio-button-wrapper-checked ant-radio-button-wrapper-in-form-item"
<button
aria-checked="false"
class="ant-switch"
role="switch"
type="button"
>
<div
class="ant-switch-handle"
/>
<span
class="ant-radio-button ant-radio-button-checked"
>
<input
checked=""
class="ant-radio-button-input"
type="radio"
value="square"
/>
<span
class="ant-radio-button-inner"
/>
</span>
<span>
Square
</span>
</label>
<label
class="ant-radio-button-wrapper ant-radio-button-wrapper-in-form-item"
>
<span
class="ant-radio-button"
>
<input
class="ant-radio-button-input"
type="radio"
value="round"
/>
<span
class="ant-radio-button-inner"
/>
</span>
<span>
Round
</span>
</label>
<label
class="ant-radio-button-wrapper ant-radio-button-wrapper-in-form-item"
>
<span
class="ant-radio-button"
>
<input
class="ant-radio-button-input"
type="radio"
value="circle"
/>
<span
class="ant-radio-button-inner"
/>
</span>
<span>
Circle
</span>
</label>
class="ant-switch-inner"
/>
</button>
</div>
</div>
</div>
</div>
</div>
<div
class="ant-row ant-form-item"
class="ant-form-item"
>
<div
class="ant-col ant-form-item-label"
>
<label
class=""
title="Avatar Shape"
>
Avatar Shape
</label>
</div>
<div
class="ant-col ant-form-item-control"
class="ant-row ant-form-item-row"
>
<div
class="ant-form-item-control-input"
class="ant-col ant-form-item-label"
>
<label
class=""
title="Size"
>
Size
</label>
</div>
<div
class="ant-col ant-form-item-control"
>
<div
class="ant-form-item-control-input-content"
class="ant-form-item-control-input"
>
<div
class="ant-radio-group ant-radio-group-outline"
class="ant-form-item-control-input-content"
>
<label
class="ant-radio-button-wrapper ant-radio-button-wrapper-in-form-item"
<div
class="ant-radio-group ant-radio-group-outline"
>
<span
class="ant-radio-button"
<label
class="ant-radio-button-wrapper ant-radio-button-wrapper-checked ant-radio-button-wrapper-in-form-item"
>
<input
class="ant-radio-button-input"
type="radio"
value="square"
/>
<span
class="ant-radio-button-inner"
/>
</span>
<span>
Square
</span>
</label>
<label
class="ant-radio-button-wrapper ant-radio-button-wrapper-checked ant-radio-button-wrapper-in-form-item"
class="ant-radio-button ant-radio-button-checked"
>
<input
checked=""
class="ant-radio-button-input"
type="radio"
value="default"
/>
<span
class="ant-radio-button-inner"
/>
</span>
<span>
Default
</span>
</label>
<label
class="ant-radio-button-wrapper ant-radio-button-wrapper-in-form-item"
>
<span
class="ant-radio-button"
>
<input
class="ant-radio-button-input"
type="radio"
value="large"
/>
<span
class="ant-radio-button-inner"
/>
</span>
<span>
Large
</span>
</label>
<label
class="ant-radio-button-wrapper ant-radio-button-wrapper-in-form-item"
>
<span
class="ant-radio-button"
>
<input
class="ant-radio-button-input"
type="radio"
value="small"
/>
<span
class="ant-radio-button-inner"
/>
</span>
<span>
Small
</span>
</label>
</div>
</div>
</div>
</div>
</div>
</div>
<div
class="ant-form-item"
>
<div
class="ant-row ant-form-item-row"
>
<div
class="ant-col ant-form-item-label"
>
<label
class=""
title="Button Shape"
>
Button Shape
</label>
</div>
<div
class="ant-col ant-form-item-control"
>
<div
class="ant-form-item-control-input"
>
<div
class="ant-form-item-control-input-content"
>
<div
class="ant-radio-group ant-radio-group-outline"
>
<span
class="ant-radio-button ant-radio-button-checked"
<label
class="ant-radio-button-wrapper ant-radio-button-wrapper-checked ant-radio-button-wrapper-in-form-item"
>
<input
checked=""
class="ant-radio-button-input"
type="radio"
value="circle"
/>
<span
class="ant-radio-button-inner"
/>
</span>
<span>
Circle
</span>
</label>
class="ant-radio-button ant-radio-button-checked"
>
<input
checked=""
class="ant-radio-button-input"
type="radio"
value="default"
/>
<span
class="ant-radio-button-inner"
/>
</span>
<span>
Default
</span>
</label>
<label
class="ant-radio-button-wrapper ant-radio-button-wrapper-in-form-item"
>
<span
class="ant-radio-button"
>
<input
class="ant-radio-button-input"
type="radio"
value="square"
/>
<span
class="ant-radio-button-inner"
/>
</span>
<span>
Square
</span>
</label>
<label
class="ant-radio-button-wrapper ant-radio-button-wrapper-in-form-item"
>
<span
class="ant-radio-button"
>
<input
class="ant-radio-button-input"
type="radio"
value="round"
/>
<span
class="ant-radio-button-inner"
/>
</span>
<span>
Round
</span>
</label>
<label
class="ant-radio-button-wrapper ant-radio-button-wrapper-in-form-item"
>
<span
class="ant-radio-button"
>
<input
class="ant-radio-button-input"
type="radio"
value="circle"
/>
<span
class="ant-radio-button-inner"
/>
</span>
<span>
Circle
</span>
</label>
</div>
</div>
</div>
</div>
</div>
</div>
<div
class="ant-form-item"
>
<div
class="ant-row ant-form-item-row"
>
<div
class="ant-col ant-form-item-label"
>
<label
class=""
title="Avatar Shape"
>
Avatar Shape
</label>
</div>
<div
class="ant-col ant-form-item-control"
>
<div
class="ant-form-item-control-input"
>
<div
class="ant-form-item-control-input-content"
>
<div
class="ant-radio-group ant-radio-group-outline"
>
<label
class="ant-radio-button-wrapper ant-radio-button-wrapper-in-form-item"
>
<span
class="ant-radio-button"
>
<input
class="ant-radio-button-input"
type="radio"
value="square"
/>
<span
class="ant-radio-button-inner"
/>
</span>
<span>
Square
</span>
</label>
<label
class="ant-radio-button-wrapper ant-radio-button-wrapper-checked ant-radio-button-wrapper-in-form-item"
>
<span
class="ant-radio-button ant-radio-button-checked"
>
<input
checked=""
class="ant-radio-button-input"
type="radio"
value="circle"
/>
<span
class="ant-radio-button-inner"
/>
</span>
<span>
Circle
</span>
</label>
</div>
</div>
</div>
</div>

View File

@ -114,7 +114,7 @@ Array [
class="ant-skeleton ant-skeleton-element"
>
<span
class="ant-skeleton-button ant-skeleton-button-square"
class="ant-skeleton-button"
/>
</div>
</div>
@ -148,7 +148,7 @@ Array [
class="ant-skeleton ant-skeleton-element"
>
<span
class="ant-skeleton-button ant-skeleton-button-square"
class="ant-skeleton-button"
/>
</div>,
<br />,
@ -230,323 +230,362 @@ Array [
style="margin:16px 0"
>
<div
class="ant-row ant-form-item"
class="ant-form-item"
>
<div
class="ant-col ant-form-item-label"
>
<label
class=""
title="Active"
>
Active
</label>
</div>
<div
class="ant-col ant-form-item-control"
class="ant-row ant-form-item-row"
>
<div
class="ant-form-item-control-input"
class="ant-col ant-form-item-label"
>
<div
class="ant-form-item-control-input-content"
<label
class=""
title="Active"
>
<button
aria-checked="false"
class="ant-switch"
role="switch"
type="button"
>
<div
class="ant-switch-handle"
/>
<span
class="ant-switch-inner"
/>
</button>
</div>
Active
</label>
</div>
</div>
</div>
<div
class="ant-row ant-form-item"
>
<div
class="ant-col ant-form-item-label"
>
<label
class=""
title="Button and Input Block"
>
Button and Input Block
</label>
</div>
<div
class="ant-col ant-form-item-control"
>
<div
class="ant-form-item-control-input"
class="ant-col ant-form-item-control"
>
<div
class="ant-form-item-control-input-content"
>
<button
aria-checked="false"
class="ant-switch"
role="switch"
type="button"
>
<div
class="ant-switch-handle"
/>
<span
class="ant-switch-inner"
/>
</button>
</div>
</div>
</div>
</div>
<div
class="ant-row ant-form-item"
>
<div
class="ant-col ant-form-item-label"
>
<label
class=""
title="Size"
>
Size
</label>
</div>
<div
class="ant-col ant-form-item-control"
>
<div
class="ant-form-item-control-input"
>
<div
class="ant-form-item-control-input-content"
class="ant-form-item-control-input"
>
<div
class="ant-radio-group ant-radio-group-outline"
class="ant-form-item-control-input-content"
>
<label
class="ant-radio-button-wrapper ant-radio-button-wrapper-checked ant-radio-button-wrapper-in-form-item"
<button
aria-checked="false"
class="ant-switch"
role="switch"
type="button"
>
<div
class="ant-switch-handle"
/>
<span
class="ant-radio-button ant-radio-button-checked"
>
<input
checked=""
class="ant-radio-button-input"
type="radio"
value="default"
/>
<span
class="ant-radio-button-inner"
/>
</span>
<span>
Default
</span>
</label>
<label
class="ant-radio-button-wrapper ant-radio-button-wrapper-in-form-item"
>
<span
class="ant-radio-button"
>
<input
class="ant-radio-button-input"
type="radio"
value="large"
/>
<span
class="ant-radio-button-inner"
/>
</span>
<span>
Large
</span>
</label>
<label
class="ant-radio-button-wrapper ant-radio-button-wrapper-in-form-item"
>
<span
class="ant-radio-button"
>
<input
class="ant-radio-button-input"
type="radio"
value="small"
/>
<span
class="ant-radio-button-inner"
/>
</span>
<span>
Small
</span>
</label>
class="ant-switch-inner"
/>
</button>
</div>
</div>
</div>
</div>
</div>
<div
class="ant-row ant-form-item"
class="ant-form-item"
>
<div
class="ant-col ant-form-item-label"
>
<label
class=""
title="Button Shape"
>
Button Shape
</label>
</div>
<div
class="ant-col ant-form-item-control"
class="ant-row ant-form-item-row"
>
<div
class="ant-form-item-control-input"
class="ant-col ant-form-item-label"
>
<label
class=""
title="Button and Input Block"
>
Button and Input Block
</label>
</div>
<div
class="ant-col ant-form-item-control"
>
<div
class="ant-form-item-control-input-content"
class="ant-form-item-control-input"
>
<div
class="ant-radio-group ant-radio-group-outline"
class="ant-form-item-control-input-content"
>
<label
class="ant-radio-button-wrapper ant-radio-button-wrapper-checked ant-radio-button-wrapper-in-form-item"
<button
aria-checked="false"
class="ant-switch"
role="switch"
type="button"
>
<div
class="ant-switch-handle"
/>
<span
class="ant-radio-button ant-radio-button-checked"
>
<input
checked=""
class="ant-radio-button-input"
type="radio"
value="square"
/>
<span
class="ant-radio-button-inner"
/>
</span>
<span>
Square
</span>
</label>
<label
class="ant-radio-button-wrapper ant-radio-button-wrapper-in-form-item"
>
<span
class="ant-radio-button"
>
<input
class="ant-radio-button-input"
type="radio"
value="round"
/>
<span
class="ant-radio-button-inner"
/>
</span>
<span>
Round
</span>
</label>
<label
class="ant-radio-button-wrapper ant-radio-button-wrapper-in-form-item"
>
<span
class="ant-radio-button"
>
<input
class="ant-radio-button-input"
type="radio"
value="circle"
/>
<span
class="ant-radio-button-inner"
/>
</span>
<span>
Circle
</span>
</label>
class="ant-switch-inner"
/>
</button>
</div>
</div>
</div>
</div>
</div>
<div
class="ant-row ant-form-item"
class="ant-form-item"
>
<div
class="ant-col ant-form-item-label"
>
<label
class=""
title="Avatar Shape"
>
Avatar Shape
</label>
</div>
<div
class="ant-col ant-form-item-control"
class="ant-row ant-form-item-row"
>
<div
class="ant-form-item-control-input"
class="ant-col ant-form-item-label"
>
<label
class=""
title="Size"
>
Size
</label>
</div>
<div
class="ant-col ant-form-item-control"
>
<div
class="ant-form-item-control-input-content"
class="ant-form-item-control-input"
>
<div
class="ant-radio-group ant-radio-group-outline"
class="ant-form-item-control-input-content"
>
<label
class="ant-radio-button-wrapper ant-radio-button-wrapper-in-form-item"
<div
class="ant-radio-group ant-radio-group-outline"
>
<span
class="ant-radio-button"
<label
class="ant-radio-button-wrapper ant-radio-button-wrapper-checked ant-radio-button-wrapper-in-form-item"
>
<input
class="ant-radio-button-input"
type="radio"
value="square"
/>
<span
class="ant-radio-button-inner"
/>
</span>
<span>
Square
</span>
</label>
<label
class="ant-radio-button-wrapper ant-radio-button-wrapper-checked ant-radio-button-wrapper-in-form-item"
class="ant-radio-button ant-radio-button-checked"
>
<input
checked=""
class="ant-radio-button-input"
type="radio"
value="default"
/>
<span
class="ant-radio-button-inner"
/>
</span>
<span>
Default
</span>
</label>
<label
class="ant-radio-button-wrapper ant-radio-button-wrapper-in-form-item"
>
<span
class="ant-radio-button"
>
<input
class="ant-radio-button-input"
type="radio"
value="large"
/>
<span
class="ant-radio-button-inner"
/>
</span>
<span>
Large
</span>
</label>
<label
class="ant-radio-button-wrapper ant-radio-button-wrapper-in-form-item"
>
<span
class="ant-radio-button"
>
<input
class="ant-radio-button-input"
type="radio"
value="small"
/>
<span
class="ant-radio-button-inner"
/>
</span>
<span>
Small
</span>
</label>
</div>
</div>
</div>
</div>
</div>
</div>
<div
class="ant-form-item"
>
<div
class="ant-row ant-form-item-row"
>
<div
class="ant-col ant-form-item-label"
>
<label
class=""
title="Button Shape"
>
Button Shape
</label>
</div>
<div
class="ant-col ant-form-item-control"
>
<div
class="ant-form-item-control-input"
>
<div
class="ant-form-item-control-input-content"
>
<div
class="ant-radio-group ant-radio-group-outline"
>
<span
class="ant-radio-button ant-radio-button-checked"
<label
class="ant-radio-button-wrapper ant-radio-button-wrapper-checked ant-radio-button-wrapper-in-form-item"
>
<input
checked=""
class="ant-radio-button-input"
type="radio"
value="circle"
/>
<span
class="ant-radio-button-inner"
/>
</span>
<span>
Circle
</span>
</label>
class="ant-radio-button ant-radio-button-checked"
>
<input
checked=""
class="ant-radio-button-input"
type="radio"
value="default"
/>
<span
class="ant-radio-button-inner"
/>
</span>
<span>
Default
</span>
</label>
<label
class="ant-radio-button-wrapper ant-radio-button-wrapper-in-form-item"
>
<span
class="ant-radio-button"
>
<input
class="ant-radio-button-input"
type="radio"
value="square"
/>
<span
class="ant-radio-button-inner"
/>
</span>
<span>
Square
</span>
</label>
<label
class="ant-radio-button-wrapper ant-radio-button-wrapper-in-form-item"
>
<span
class="ant-radio-button"
>
<input
class="ant-radio-button-input"
type="radio"
value="round"
/>
<span
class="ant-radio-button-inner"
/>
</span>
<span>
Round
</span>
</label>
<label
class="ant-radio-button-wrapper ant-radio-button-wrapper-in-form-item"
>
<span
class="ant-radio-button"
>
<input
class="ant-radio-button-input"
type="radio"
value="circle"
/>
<span
class="ant-radio-button-inner"
/>
</span>
<span>
Circle
</span>
</label>
</div>
</div>
</div>
</div>
</div>
</div>
<div
class="ant-form-item"
>
<div
class="ant-row ant-form-item-row"
>
<div
class="ant-col ant-form-item-label"
>
<label
class=""
title="Avatar Shape"
>
Avatar Shape
</label>
</div>
<div
class="ant-col ant-form-item-control"
>
<div
class="ant-form-item-control-input"
>
<div
class="ant-form-item-control-input-content"
>
<div
class="ant-radio-group ant-radio-group-outline"
>
<label
class="ant-radio-button-wrapper ant-radio-button-wrapper-in-form-item"
>
<span
class="ant-radio-button"
>
<input
class="ant-radio-button-input"
type="radio"
value="square"
/>
<span
class="ant-radio-button-inner"
/>
</span>
<span>
Square
</span>
</label>
<label
class="ant-radio-button-wrapper ant-radio-button-wrapper-checked ant-radio-button-wrapper-in-form-item"
>
<span
class="ant-radio-button ant-radio-button-checked"
>
<input
checked=""
class="ant-radio-button-input"
type="radio"
value="circle"
/>
<span
class="ant-radio-button-inner"
/>
</span>
<span>
Circle
</span>
</label>
</div>
</div>
</div>
</div>

View File

@ -20,14 +20,14 @@ import { DotChartOutlined } from '@ant-design/icons';
import React, { useState } from 'react';
type SizeType = 'default' | 'small' | 'large';
type ButtonShapeType = 'circle' | 'square' | 'round';
type ButtonShapeType = 'circle' | 'square' | 'round' | 'default';
type AvatarShapeType = 'circle' | 'square';
const App: React.FC = () => {
const [active, setActive] = useState(false);
const [block, setBlock] = useState(false);
const [size, setSize] = useState<SizeType>('default');
const [buttonShape, setButtonShape] = useState<ButtonShapeType>('square');
const [buttonShape, setButtonShape] = useState<ButtonShapeType>('default');
const [avatarShape, setAvatarShape] = useState<AvatarShapeType>('circle');
const handleActiveChange = (checked: boolean) => {
@ -88,6 +88,7 @@ const App: React.FC = () => {
</Form.Item>
<Form.Item label="Button Shape">
<Radio.Group value={buttonShape} onChange={handleShapeButton}>
<Radio.Button value="default">Default</Radio.Button>
<Radio.Button value="square">Square</Radio.Button>
<Radio.Button value="round">Round</Radio.Button>
<Radio.Button value="circle">Circle</Radio.Button>

View File

@ -55,7 +55,7 @@ Provide a placeholder while you wait for content to load, or to visualise conten
| --- | --- | --- | --- | --- |
| active | Show animation effect | boolean | false | |
| block | Option to fit button width to its parent width | boolean | false | 4.17.0 |
| shape | Set the shape of button | `circle` \| `round` \| `default` | - | |
| shape | Set the shape of button | `circle` \| `round` \| `square` \| `default` | - | |
| size | Set the size of button | `large` \| `small` \| `default` | - | |
### SkeletonInputProps

View File

@ -52,12 +52,12 @@ cover: https://gw.alipayobjects.com/zos/alicdn/KpcciCJgv/Skeleton.svg
### SkeletonButtonProps
| 属性 | 说明 | 类型 | 默认值 | 版本 |
| ------ | ------------------------------ | -------------------------------- | ------ | ------ |
| active | 是否展示动画效果 | boolean | false | |
| block | 将按钮宽度调整为其父宽度的选项 | boolean | false | 4.17.0 |
| shape | 指定按钮的形状 | `circle` \| `round` \| `default` | - | |
| size | 设置按钮的大小 | `large` \| `small` \| `default` | - | |
| 属性 | 说明 | 类型 | 默认值 | 版本 |
| --- | --- | --- | --- | --- |
| active | 是否展示动画效果 | boolean | false | |
| block | 将按钮宽度调整为其父宽度的选项 | boolean | false | 4.17.0 |
| shape | 指定按钮的形状 | `circle` \| `round` \| `square` \| `default` | - | |
| size | 设置按钮的大小 | `large` \| `small` \| `default` | - | |
### SkeletonInputProps

View File

@ -148,6 +148,42 @@ exports[`renders ./components/space/demo/align.md extend context correctly 1`] =
</div>
</div>
</div>
<div
class="space-align-block"
>
<div
class="ant-space ant-space-horizontal ant-space-align-stretch"
>
<div
class="ant-space-item"
style="margin-right:8px"
>
stretch
</div>
<div
class="ant-space-item"
style="margin-right:8px"
>
<button
class="ant-btn ant-btn-primary"
type="button"
>
<span>
Primary
</span>
</button>
</div>
<div
class="ant-space-item"
>
<span
class="mock-block"
>
Block
</span>
</div>
</div>
</div>
</div>
`;

View File

@ -148,6 +148,42 @@ exports[`renders ./components/space/demo/align.md correctly 1`] = `
</div>
</div>
</div>
<div
class="space-align-block"
>
<div
class="ant-space ant-space-horizontal ant-space-align-stretch"
>
<div
class="ant-space-item"
style="margin-right:8px"
>
stretch
</div>
<div
class="ant-space-item"
style="margin-right:8px"
>
<button
class="ant-btn ant-btn-primary"
type="button"
>
<span>
Primary
</span>
</button>
</div>
<div
class="ant-space-item"
>
<span
class="mock-block"
>
Block
</span>
</div>
</div>
</div>
</div>
`;

View File

@ -47,6 +47,13 @@ const App: React.FC = () => (
<span className="mock-block">Block</span>
</Space>
</div>
<div className="space-align-block">
<Space align="stretch">
stretch
<Button type="primary">Primary</Button>
<span className="mock-block">Block</span>
</Space>
</div>
</div>
);

View File

@ -16,7 +16,7 @@ Avoid components clinging together and set a unified space.
| Property | Description | Type | Default | Version |
| --- | --- | --- | --- | --- |
| align | Align items | `start` \| `end` \|`center` \|`baseline` | - | 4.2.0 |
| align | Align items | `start` \| `end` \|`center` \|`baseline` \|`stretch` | - | 4.2.0 |
| direction | The space direction | `vertical` \| `horizontal` | `horizontal` | 4.1.0 |
| size | The space size | [Size](#Size) \| [Size\[\]](#Size) | `small` | 4.1.0 \| Array: 4.9.0 |
| split | Set split | ReactNode | - | 4.7.0 |

View File

@ -24,7 +24,7 @@ export interface SpaceProps extends React.HTMLAttributes<HTMLDivElement> {
size?: SpaceSize | [SpaceSize, SpaceSize];
direction?: 'horizontal' | 'vertical';
// No `stretch` since many components do not support that.
align?: 'start' | 'end' | 'center' | 'baseline';
align?: 'start' | 'end' | 'center' | 'baseline' | 'stretch';
split?: React.ReactNode;
wrap?: boolean;
}

View File

@ -20,7 +20,7 @@ cover: https://gw.alipayobjects.com/zos/antfincdn/wc6%263gJ0Y8/Space.svg
| 参数 | 说明 | 类型 | 默认值 | 版本 |
| --- | --- | --- | --- | --- |
| align | 对齐方式 | `start` \| `end` \|`center` \|`baseline` | - | 4.2.0 |
| align | 对齐方式 | `start` \| `end` \|`center` \|`baseline` \|`stretch` | - | 4.2.0 |
| direction | 间距方向 | `vertical` \| `horizontal` | `horizontal` | 4.1.0 |
| size | 间距大小 | [Size](#Size) \| [Size\[\]](#Size) | `small` | 4.1.0 \| Array: 4.9.0 |
| split | 设置拆分 | ReactNode | - | 4.7.0 |

View File

@ -36,6 +36,9 @@ const genSpaceStyle: GenerateStyle<SpaceToken> = token => {
'&-baseline': {
alignItems: 'flex-baseline',
},
'&-stretch': {
alignItems: 'stretch',
},
},
[`${componentCls}-space-item`]: {
'&:empty': {

File diff suppressed because it is too large Load Diff

View File

@ -0,0 +1,8 @@
import type { TimePickerLocale } from '../index';
const locale: TimePickerLocale = {
placeholder: 'වේලාව තෝරන්න',
rangePlaceholder: ['ආරම්භක වේලාව', 'නිමවන වේලාව'],
};
export default locale;

View File

@ -4,6 +4,7 @@ import RcUpload from 'rc-upload';
import useMergedState from 'rc-util/lib/hooks/useMergedState';
import * as React from 'react';
import { ConfigContext } from '../config-provider';
import DisabledContext from '../config-provider/DisabledContext';
import LocaleReceiver from '../locale-provider/LocaleReceiver';
import defaultLocale from '../locale/default';
import warning from '../_util/warning';
@ -38,7 +39,7 @@ const InternalUpload: React.ForwardRefRenderFunction<unknown, UploadProps> = (pr
onChange,
onDrop,
previewFile,
disabled,
disabled: customDisabled,
locale: propLocale,
iconRender,
isImageUrl,
@ -52,6 +53,10 @@ const InternalUpload: React.ForwardRefRenderFunction<unknown, UploadProps> = (pr
maxCount,
} = props;
// ===================== Disabled =====================
const disabled = React.useContext(DisabledContext);
const mergedDisabled = customDisabled || disabled;
const [mergedFileList, setMergedFileList] = useMergedState(defaultFileList || [], {
value: fileList,
postState: list => list ?? [],
@ -300,6 +305,7 @@ const InternalUpload: React.ForwardRefRenderFunction<unknown, UploadProps> = (pr
onSuccess,
...(props as RcUploadProps),
prefixCls,
disabled: mergedDisabled,
beforeUpload: mergedBeforeUpload,
onChange: undefined,
};
@ -311,7 +317,7 @@ const InternalUpload: React.ForwardRefRenderFunction<unknown, UploadProps> = (pr
// !children: https://github.com/ant-design/ant-design/issues/14298
// disabled: https://github.com/ant-design/ant-design/issues/16478
// https://github.com/ant-design/ant-design/issues/24197
if (!children || disabled) {
if (!children || mergedDisabled) {
delete rcUploadProps.id;
}
@ -339,7 +345,7 @@ const InternalUpload: React.ForwardRefRenderFunction<unknown, UploadProps> = (pr
onPreview={onPreview}
onDownload={onDownload}
onRemove={handleRemove}
showRemoveIcon={!disabled && showRemoveIcon}
showRemoveIcon={!mergedDisabled && showRemoveIcon}
showPreviewIcon={showPreviewIcon}
showDownloadIcon={showDownloadIcon}
removeIcon={removeIcon}
@ -371,7 +377,7 @@ const InternalUpload: React.ForwardRefRenderFunction<unknown, UploadProps> = (pr
[`${prefixCls}-drag`]: true,
[`${prefixCls}-drag-uploading`]: mergedFileList.some(file => file.status === 'uploading'),
[`${prefixCls}-drag-hover`]: dragState === 'dragover',
[`${prefixCls}-disabled`]: disabled,
[`${prefixCls}-disabled`]: mergedDisabled,
[`${prefixCls}-rtl`]: direction === 'rtl',
},
hashId,
@ -395,7 +401,7 @@ const InternalUpload: React.ForwardRefRenderFunction<unknown, UploadProps> = (pr
}
const uploadButtonCls = classNames(prefixCls, `${prefixCls}-select`, {
[`${prefixCls}-disabled`]: disabled,
[`${prefixCls}-disabled`]: mergedDisabled,
});
const renderUploadButton = (uploadButtonStyle?: React.CSSProperties) => (

View File

@ -3692,77 +3692,81 @@ exports[`renders ./components/upload/demo/upload-with-aliyun-oss.md extend conte
class="ant-form ant-form-horizontal"
>
<div
class="ant-row ant-form-item"
class="ant-form-item"
>
<div
class="ant-col ant-col-4 ant-form-item-label"
>
<label
class=""
for="photos"
title="Photos"
>
Photos
</label>
</div>
<div
class="ant-col ant-form-item-control"
class="ant-row ant-form-item-row"
>
<div
class="ant-form-item-control-input"
class="ant-col ant-col-4 ant-form-item-label"
>
<label
class=""
for="photos"
title="Photos"
>
Photos
</label>
</div>
<div
class="ant-col ant-form-item-control"
>
<div
class="ant-form-item-control-input-content"
class="ant-form-item-control-input"
>
<span
class="ant-upload-wrapper"
<div
class="ant-form-item-control-input-content"
>
<div
class="ant-upload ant-upload-select"
<span
class="ant-upload-wrapper"
>
<span
class="ant-upload"
role="button"
tabindex="0"
<div
class="ant-upload ant-upload-select"
>
<input
accept=""
style="display:none"
type="file"
/>
<button
class="ant-btn ant-btn-default"
type="button"
<span
class="ant-upload"
role="button"
tabindex="0"
>
<span
aria-label="upload"
class="anticon anticon-upload"
role="img"
<input
accept=""
style="display:none"
type="file"
/>
<button
class="ant-btn ant-btn-default"
type="button"
>
<svg
aria-hidden="true"
data-icon="upload"
fill="currentColor"
focusable="false"
height="1em"
viewBox="64 64 896 896"
width="1em"
<span
aria-label="upload"
class="anticon anticon-upload"
role="img"
>
<path
d="M400 317.7h73.9V656c0 4.4 3.6 8 8 8h60c4.4 0 8-3.6 8-8V317.7H624c6.7 0 10.4-7.7 6.3-12.9L518.3 163a8 8 0 00-12.6 0l-112 141.7c-4.1 5.3-.4 13 6.3 13zM878 626h-60c-4.4 0-8 3.6-8 8v154H214V634c0-4.4-3.6-8-8-8h-60c-4.4 0-8 3.6-8 8v198c0 17.7 14.3 32 32 32h684c17.7 0 32-14.3 32-32V634c0-4.4-3.6-8-8-8z"
/>
</svg>
</span>
<span>
Click to Upload
</span>
</button>
</span>
</div>
<div
class="ant-upload-list ant-upload-list-text"
/>
</span>
<svg
aria-hidden="true"
data-icon="upload"
fill="currentColor"
focusable="false"
height="1em"
viewBox="64 64 896 896"
width="1em"
>
<path
d="M400 317.7h73.9V656c0 4.4 3.6 8 8 8h60c4.4 0 8-3.6 8-8V317.7H624c6.7 0 10.4-7.7 6.3-12.9L518.3 163a8 8 0 00-12.6 0l-112 141.7c-4.1 5.3-.4 13 6.3 13zM878 626h-60c-4.4 0-8 3.6-8 8v154H214V634c0-4.4-3.6-8-8-8h-60c-4.4 0-8 3.6-8 8v198c0 17.7 14.3 32 32 32h684c17.7 0 32-14.3 32-32V634c0-4.4-3.6-8-8-8z"
/>
</svg>
</span>
<span>
Click to Upload
</span>
</button>
</span>
</div>
<div
class="ant-upload-list ant-upload-list-text"
/>
</span>
</div>
</div>
</div>
</div>

View File

@ -3476,77 +3476,81 @@ exports[`renders ./components/upload/demo/upload-with-aliyun-oss.md correctly 1`
class="ant-form ant-form-horizontal"
>
<div
class="ant-row ant-form-item"
class="ant-form-item"
>
<div
class="ant-col ant-col-4 ant-form-item-label"
>
<label
class=""
for="photos"
title="Photos"
>
Photos
</label>
</div>
<div
class="ant-col ant-form-item-control"
class="ant-row ant-form-item-row"
>
<div
class="ant-form-item-control-input"
class="ant-col ant-col-4 ant-form-item-label"
>
<label
class=""
for="photos"
title="Photos"
>
Photos
</label>
</div>
<div
class="ant-col ant-form-item-control"
>
<div
class="ant-form-item-control-input-content"
class="ant-form-item-control-input"
>
<span
class="ant-upload-wrapper"
<div
class="ant-form-item-control-input-content"
>
<div
class="ant-upload ant-upload-select"
<span
class="ant-upload-wrapper"
>
<span
class="ant-upload"
role="button"
tabindex="0"
<div
class="ant-upload ant-upload-select"
>
<input
accept=""
style="display:none"
type="file"
/>
<button
class="ant-btn ant-btn-default"
type="button"
<span
class="ant-upload"
role="button"
tabindex="0"
>
<span
aria-label="upload"
class="anticon anticon-upload"
role="img"
<input
accept=""
style="display:none"
type="file"
/>
<button
class="ant-btn ant-btn-default"
type="button"
>
<svg
aria-hidden="true"
data-icon="upload"
fill="currentColor"
focusable="false"
height="1em"
viewBox="64 64 896 896"
width="1em"
<span
aria-label="upload"
class="anticon anticon-upload"
role="img"
>
<path
d="M400 317.7h73.9V656c0 4.4 3.6 8 8 8h60c4.4 0 8-3.6 8-8V317.7H624c6.7 0 10.4-7.7 6.3-12.9L518.3 163a8 8 0 00-12.6 0l-112 141.7c-4.1 5.3-.4 13 6.3 13zM878 626h-60c-4.4 0-8 3.6-8 8v154H214V634c0-4.4-3.6-8-8-8h-60c-4.4 0-8 3.6-8 8v198c0 17.7 14.3 32 32 32h684c17.7 0 32-14.3 32-32V634c0-4.4-3.6-8-8-8z"
/>
</svg>
</span>
<span>
Click to Upload
</span>
</button>
</span>
</div>
<div
class="ant-upload-list ant-upload-list-text"
/>
</span>
<svg
aria-hidden="true"
data-icon="upload"
fill="currentColor"
focusable="false"
height="1em"
viewBox="64 64 896 896"
width="1em"
>
<path
d="M400 317.7h73.9V656c0 4.4 3.6 8 8 8h60c4.4 0 8-3.6 8-8V317.7H624c6.7 0 10.4-7.7 6.3-12.9L518.3 163a8 8 0 00-12.6 0l-112 141.7c-4.1 5.3-.4 13 6.3 13zM878 626h-60c-4.4 0-8 3.6-8 8v154H214V634c0-4.4-3.6-8-8-8h-60c-4.4 0-8 3.6-8 8v198c0 17.7 14.3 32 32 32h684c17.7 0 32-14.3 32-32V634c0-4.4-3.6-8-8-8z"
/>
</svg>
</span>
<span>
Click to Upload
</span>
</button>
</span>
</div>
<div
class="ant-upload-list ant-upload-list-text"
/>
</span>
</div>
</div>
</div>
</div>

View File

@ -16,7 +16,7 @@ export interface UploadToken extends FullToken<'Upload'> {
}
const genBaseStyle: GenerateStyle<UploadToken> = token => {
const { componentCls } = token;
const { componentCls, colorTextDisabled } = token;
return {
[`${componentCls}-wrapper`]: {
@ -34,6 +34,7 @@ const genBaseStyle: GenerateStyle<UploadToken> = token => {
},
[`${componentCls}-disabled`]: {
color: colorTextDisabled,
cursor: 'not-allowed',
},
},

View File

@ -81,6 +81,7 @@ The following languages are currently supported:
| Portuguese | pt_PT |
| Romanian | ro_RO |
| Russian | ru_RU |
| Sinhalese / Sinhala | si_LK |
| Slovak | sk_SK |
| Serbian | sr_RS |
| Slovenian | sl_SI |

View File

@ -78,6 +78,7 @@ return (
| 葡萄牙语 | pt_PT |
| 罗马尼亚语 | ro_RO |
| 俄罗斯语 | ru_RU |
| 僧伽罗语 | si_LK |
| 斯洛伐克语 | sk_SK |
| 塞尔维亚语 | sr_RS |
| 斯洛文尼亚语 | sl_SI |

View File

@ -125,16 +125,16 @@
"rc-dialog": "~8.9.0",
"rc-drawer": "~4.4.2",
"rc-dropdown": "~4.0.0",
"rc-field-form": "~1.26.1",
"rc-field-form": "~1.27.0",
"rc-image": "~5.7.0",
"rc-input": "~0.0.1-alpha.5",
"rc-input-number": "~7.3.0",
"rc-mentions": "~1.9.0",
"rc-menu": "~9.6.0",
"rc-motion": "^2.5.1",
"rc-motion": "^2.6.1",
"rc-notification": "~5.0.0-alpha.9",
"rc-pagination": "~3.1.16",
"rc-picker": "~2.6.8",
"rc-pagination": "~3.1.17",
"rc-picker": "~2.6.10",
"rc-progress": "~3.3.2",
"rc-rate": "~2.9.0",
"rc-resize-observer": "^1.2.0",
@ -215,7 +215,7 @@
"eslint-plugin-import": "^2.21.1",
"eslint-plugin-jest": "^26.4.0",
"eslint-plugin-jsx-a11y": "^6.2.1",
"eslint-plugin-markdown": "^2.0.0",
"eslint-plugin-markdown": "^3.0.0",
"eslint-plugin-react": "^7.28.0",
"eslint-plugin-react-hooks": "^4.1.2",
"eslint-plugin-unicorn": "^43.0.0",

View File

@ -574,6 +574,7 @@
@modal-mask-bg: fade(@black, 45%);
@modal-confirm-body-padding: 32px 32px 24px;
@modal-confirm-title-font-size: @font-size-lg;
@modal-border-radius: @border-radius-base;
// Progress
// --

View File

@ -629,6 +629,7 @@
@modal-mask-bg: fade(@black, 45%);
@modal-confirm-body-padding: 32px 32px 24px;
@modal-confirm-title-font-size: @font-size-lg;
@modal-border-radius: @border-radius-base;
// Progress
// --