Merge remote-tracking branch 'origin/main' into feat-v4
commit
b0990b7323
|
@ -5,10 +5,12 @@ import { nextTick } from 'vue';
|
|||
import { asyncExpect, sleep } from '../../../tests/utils';
|
||||
import mountTest from '../../../tests/shared/mountTest';
|
||||
import { resetWarned } from '../../_util/warning';
|
||||
import focusTest from '../../../tests/shared/focusTest';
|
||||
|
||||
describe('Button', () => {
|
||||
mountTest(Button);
|
||||
mountTest(Button.Group);
|
||||
focusTest(Button);
|
||||
it('renders correctly', () => {
|
||||
const wrapper = mount({
|
||||
render() {
|
||||
|
|
|
@ -38,7 +38,7 @@ export default defineComponent({
|
|||
props: initDefaultProps(buttonProps(), { type: 'default' }),
|
||||
slots: ['icon'],
|
||||
// emits: ['click', 'mousedown'],
|
||||
setup(props, { slots, attrs, emit }) {
|
||||
setup(props, { slots, attrs, emit, expose }) {
|
||||
const { prefixCls, autoInsertSpaceInButton, direction, size } = useConfigInject('btn', props);
|
||||
const [wrapSSR, hashId] = useStyle(prefixCls);
|
||||
const groupSizeContext = GroupSizeContext.useInject();
|
||||
|
@ -157,6 +157,17 @@ export default defineComponent({
|
|||
delayTimeoutRef.value && clearTimeout(delayTimeoutRef.value);
|
||||
});
|
||||
|
||||
const focus = () => {
|
||||
buttonNodeRef.value?.focus();
|
||||
};
|
||||
const blur = () => {
|
||||
buttonNodeRef.value?.blur();
|
||||
};
|
||||
expose({
|
||||
focus,
|
||||
blur,
|
||||
});
|
||||
|
||||
return () => {
|
||||
const { icon = slots.icon?.() } = props;
|
||||
const children = flattenChildren(slots.default?.());
|
||||
|
|
|
@ -56,6 +56,15 @@ It accepts all props which native buttons support.
|
|||
|
||||
## FAQ
|
||||
|
||||
### Methods
|
||||
|
||||
#### Checkbox
|
||||
|
||||
| Name | Description | Version |
|
||||
| ------- | ------------ | ------- |
|
||||
| blur() | remove focus | |
|
||||
| focus() | get focus | |
|
||||
|
||||
### How to remove space between 2 chinese characters
|
||||
|
||||
Following the Ant Design specification, we will add one space between if Button (exclude Text button and Link button) contains two Chinese characters only. If you don't need that, you can use [ConfigProvider](/components/config-provider/#api) to set `autoInsertSpaceInButton` as `false`.
|
||||
|
|
|
@ -57,6 +57,15 @@ coverDark: https://mdn.alipayobjects.com/huamei_7uahnr/afts/img/A*Lp1kTYmSsgoAAA
|
|||
|
||||
支持原生 button 的其他所有属性。
|
||||
|
||||
### 方法
|
||||
|
||||
#### Button
|
||||
|
||||
| 名称 | 描述 | 版本 |
|
||||
| ------- | -------- | ---- |
|
||||
| blur() | 移除焦点 | |
|
||||
| focus() | 获取焦点 | |
|
||||
|
||||
## FAQ
|
||||
|
||||
### 如何移除 2 个汉字之间的空格
|
||||
|
|
|
@ -211,3 +211,20 @@ Please refer [replace date](/docs/vue/replace-date)
|
|||
### Why config dayjs.locale globally not work?
|
||||
|
||||
DatePicker default set `locale` as `en` in v4. You can config DatePicker `locale` prop or [ConfigProvider `locale`](/components/config-provider) prop instead.
|
||||
|
||||
### How to modify start day of week?
|
||||
|
||||
Please use correct [language](/docs/vue/i18n) ([#5605](https://github.com/ant-design/ant-design/issues/5605)), or update dayjs `locale` config:
|
||||
|
||||
- Example: <https://codesandbox.io/s/dayjs-day-of-week-x9tuj2?file=/demo.tsx>
|
||||
|
||||
```js
|
||||
import dayjs from 'dayjs';
|
||||
import updateLocale from 'dayjs/plugin/updateLocale';
|
||||
import 'dayjs/locale/zh-cn';
|
||||
|
||||
dayjs.extend(updateLocale);
|
||||
dayjs.updateLocale('zh-cn', {
|
||||
weekStart: 0,
|
||||
});
|
||||
```
|
||||
|
|
|
@ -212,3 +212,18 @@ export type FormatType = Generic | GenericFn | Array<Generic | GenericFn>;
|
|||
### 为何全局修改 dayjs.locale 不生效?
|
||||
|
||||
DatePicker 默认 `locale` 为 `en`。你可以通过 DatePicker 的 `locale` 属性来单独设置,也可以通过 [ConfigProvider `locale`](/components/config-provider-cn) 属性来配置。
|
||||
|
||||
### 如何修改周的起始日?
|
||||
|
||||
请使用正确的[语言包](/docs/vue/i18n-cn)([#5605](https://github.com/ant-design/ant-design/issues/5605)),或者修改 dayjs 的 `locale` 配置:<https://codesandbox.io/s/dayjs-day-of-week-x9tuj2?file=/demo.tsx>
|
||||
|
||||
```js
|
||||
import dayjs from 'dayjs';
|
||||
import updateLocale from 'dayjs/plugin/updateLocale';
|
||||
import 'dayjs/locale/zh-cn';
|
||||
|
||||
dayjs.extend(updateLocale);
|
||||
dayjs.updateLocale('zh-cn', {
|
||||
weekStart: 0,
|
||||
});
|
||||
```
|
||||
|
|
|
@ -34,12 +34,12 @@ import { warning } from '../vc-util/warning';
|
|||
import find from 'lodash-es/find';
|
||||
import { tuple } from '../_util/type';
|
||||
import type {
|
||||
FormLabelAlign,
|
||||
InternalNamePath,
|
||||
Rule,
|
||||
RuleError,
|
||||
RuleObject,
|
||||
ValidateOptions,
|
||||
FormLabelAlign,
|
||||
} from './interface';
|
||||
import useConfigInject from '../config-provider/hooks/useConfigInject';
|
||||
import { useInjectForm } from './context';
|
||||
|
@ -113,10 +113,7 @@ export const formItemProps = () => ({
|
|||
wrapperCol: { type: Object as PropType<ColProps & HTMLAttributes> },
|
||||
hasFeedback: { type: Boolean, default: false },
|
||||
colon: { type: Boolean, default: undefined },
|
||||
labelAlign: {
|
||||
...PropTypes.oneOf(tuple('left', 'right')),
|
||||
type: String as PropType<FormLabelAlign>,
|
||||
},
|
||||
labelAlign: String as PropType<FormLabelAlign>,
|
||||
prop: { type: [String, Number, Array] as PropType<string | number | Array<string | number>> },
|
||||
name: { type: [String, Number, Array] as PropType<string | number | Array<string | number>> },
|
||||
rules: [Array, Object] as PropType<Rule[] | Rule>,
|
||||
|
@ -237,7 +234,7 @@ export default defineComponent({
|
|||
if (typeof props.label === 'string') {
|
||||
variables.label = props.label;
|
||||
} else if (props.name) {
|
||||
variables.label = String(name);
|
||||
variables.label = String(props.name);
|
||||
}
|
||||
if (props.messageVariables) {
|
||||
variables = { ...variables, ...props.messageVariables };
|
||||
|
|
|
@ -2,13 +2,13 @@ import type { App, PropType, ExtractPropTypes } from 'vue';
|
|||
import { computed, watch, shallowRef, defineComponent } from 'vue';
|
||||
import classNames from '../_util/classNames';
|
||||
import PropTypes from '../_util/vue-types';
|
||||
import VcMentions, { Option } from '../vc-mentions';
|
||||
import VcMentions from '../vc-mentions';
|
||||
import { mentionsProps as baseMentionsProps } from '../vc-mentions/src/mentionsProps';
|
||||
import useConfigInject from '../config-provider/hooks/useConfigInject';
|
||||
import { flattenChildren, getOptionProps } from '../_util/props-util';
|
||||
import { FormItemInputContext, useInjectFormItemContext } from '../form/FormItemContext';
|
||||
import omit from '../_util/omit';
|
||||
import { optionProps } from '../vc-mentions/src/Option';
|
||||
import { optionProps, optionOptions } from '../vc-mentions/src/Option';
|
||||
import type { KeyboardEventHandler } from '../_util/EventInterface';
|
||||
import type { InputStatus } from '../_util/statusUtils';
|
||||
import { getStatusClassNames, getMergedStatus } from '../_util/statusUtils';
|
||||
|
@ -279,7 +279,7 @@ const Mentions = defineComponent({
|
|||
/* istanbul ignore next */
|
||||
export const MentionsOption = defineComponent({
|
||||
compatConfig: { MODE: 3 },
|
||||
...(Option as any),
|
||||
...optionOptions,
|
||||
name: 'AMentionsOption',
|
||||
props: optionProps,
|
||||
});
|
||||
|
|
|
@ -2,7 +2,6 @@ import Table, { tableProps } from './Table';
|
|||
import Column from './Column';
|
||||
import ColumnGroup from './ColumnGroup';
|
||||
import type { TableProps, TablePaginationConfig } from './Table';
|
||||
import { defineComponent } from 'vue';
|
||||
import type { App } from 'vue';
|
||||
import { EXPAND_COLUMN, Summary, SummaryCell, SummaryRow } from '../vc-table';
|
||||
import {
|
||||
|
@ -16,8 +15,8 @@ export type { ColumnProps } from './Column';
|
|||
export type { ColumnsType, ColumnType, ColumnGroupType } from './interface';
|
||||
export type { TableProps, TablePaginationConfig };
|
||||
|
||||
const TableSummaryRow = defineComponent({ ...(SummaryRow as any), name: 'ATableSummaryRow' });
|
||||
const TableSummaryCell = defineComponent({ ...(SummaryCell as any), name: 'ATableSummaryCell' });
|
||||
const TableSummaryRow = SummaryRow;
|
||||
const TableSummaryCell = SummaryCell;
|
||||
|
||||
const TableSummary = Object.assign(Summary, {
|
||||
Cell: TableSummaryCell,
|
||||
|
|
|
@ -78,14 +78,12 @@ function isChecked(selectedKeys: (string | number)[], eventKey: string | number)
|
|||
return selectedKeys.indexOf(eventKey) !== -1;
|
||||
}
|
||||
|
||||
function handleTreeData(data: TransferProps['dataSource'], targetKeys: string[] = []) {
|
||||
data.forEach(item => {
|
||||
item['disabled'] = targetKeys.includes(item.key as any);
|
||||
if (item.children) {
|
||||
handleTreeData(item.children, targetKeys);
|
||||
}
|
||||
});
|
||||
return data as TreeProps['treeData'];
|
||||
function handleTreeData(treeNodes: TransferProps['dataSource'], targetKeys: string[] = []) {
|
||||
return treeNodes.map(({ children, ...props }) => ({
|
||||
...props,
|
||||
disabled: targetKeys.includes(props.key as string),
|
||||
children: handleTreeData(children ?? [], targetKeys),
|
||||
}));
|
||||
}
|
||||
|
||||
export default defineComponent({
|
||||
|
|
|
@ -1,9 +1,7 @@
|
|||
import type { App } from 'vue';
|
||||
import { defineComponent } from 'vue';
|
||||
import Tree from './Tree';
|
||||
import { TreeNode as VcTreeNode } from '../vc-tree';
|
||||
import DirectoryTree from './DirectoryTree';
|
||||
import { treeNodeProps } from '../vc-tree/props';
|
||||
|
||||
export type { EventDataNode, DataNode } from '../vc-tree/interface';
|
||||
|
||||
|
@ -26,11 +24,7 @@ export type {
|
|||
|
||||
/* istanbul ignore next */
|
||||
|
||||
const TreeNode = defineComponent({
|
||||
...(VcTreeNode as any),
|
||||
name: 'ATreeNode',
|
||||
props: treeNodeProps,
|
||||
});
|
||||
const TreeNode = VcTreeNode;
|
||||
|
||||
export { DirectoryTree, TreeNode };
|
||||
|
||||
|
|
|
@ -17,11 +17,14 @@ export type BaseOptionsProps = Partial<ExtractPropTypes<typeof baseOptionsProps>
|
|||
|
||||
export type OptionProps = Partial<ExtractPropTypes<typeof optionProps>> & Partial<HTMLAttributes>;
|
||||
|
||||
export default defineComponent({
|
||||
compatConfig: { MODE: 3 },
|
||||
export const optionOptions = {
|
||||
name: 'Option',
|
||||
props: optionProps,
|
||||
render(_props: any, { slots }: any) {
|
||||
return slots.default?.();
|
||||
},
|
||||
};
|
||||
export default defineComponent({
|
||||
compatConfig: { MODE: 3 },
|
||||
...optionOptions,
|
||||
});
|
||||
|
|
|
@ -331,7 +331,11 @@ function RangerPicker<DateType>() {
|
|||
|
||||
// Fill disabled unit
|
||||
for (let i = 0; i < 2; i += 1) {
|
||||
if (mergedDisabled[i] && !getValue(postValues, i) && !getValue(props.allowEmpty, i)) {
|
||||
if (
|
||||
mergedDisabled.value[i] &&
|
||||
!getValue(postValues, i) &&
|
||||
!getValue(props.allowEmpty, i)
|
||||
) {
|
||||
postValues = updateValues(postValues, props.generateConfig.getNow(), i);
|
||||
}
|
||||
}
|
||||
|
|
|
@ -873,7 +873,7 @@ export default defineComponent({
|
|||
style={{
|
||||
width: 0,
|
||||
height: 0,
|
||||
display: 'flex',
|
||||
position: 'absolute',
|
||||
overflow: 'hidden',
|
||||
opacity: 0,
|
||||
}}
|
||||
|
|
|
@ -13,7 +13,7 @@ export interface SummaryCellProps {
|
|||
}
|
||||
|
||||
export default defineComponent<SummaryCellProps>({
|
||||
name: 'SummaryCell',
|
||||
name: 'ATableSummaryCell',
|
||||
props: ['index', 'colSpan', 'rowSpan', 'align'] as any,
|
||||
setup(props, { attrs, slots }) {
|
||||
const tableContext = useInjectTable();
|
||||
|
|
|
@ -2,7 +2,7 @@ import { defineComponent } from 'vue';
|
|||
|
||||
export default defineComponent({
|
||||
compatConfig: { MODE: 3 },
|
||||
name: 'FooterRow',
|
||||
name: 'ATableSummaryRow',
|
||||
setup(_props, { slots }) {
|
||||
return () => <tr>{slots.default?.()}</tr>;
|
||||
},
|
||||
|
|
|
@ -25,7 +25,7 @@ const defaultTitle = '---';
|
|||
|
||||
export default defineComponent({
|
||||
compatConfig: { MODE: 3 },
|
||||
name: 'TreeNode',
|
||||
name: 'ATreeNode',
|
||||
inheritAttrs: false,
|
||||
props: treeNodeProps,
|
||||
isTreeNode: 1,
|
||||
|
|
|
@ -225,8 +225,13 @@ const List = defineComponent({
|
|||
offset: undefined,
|
||||
});
|
||||
}
|
||||
if (componentRef.value) {
|
||||
state.scrollTop = componentRef.value.scrollTop;
|
||||
}
|
||||
},
|
||||
{
|
||||
immediate: true,
|
||||
},
|
||||
{ immediate: true },
|
||||
);
|
||||
watch(
|
||||
[
|
||||
|
@ -276,11 +281,11 @@ const List = defineComponent({
|
|||
itemTop = currentItemBottom;
|
||||
}
|
||||
|
||||
// Fallback to normal if not match. This code should never reach
|
||||
/* istanbul ignore next */
|
||||
// When scrollTop at the end but data cut to small count will reach this
|
||||
if (startIndex === undefined) {
|
||||
startIndex = 0;
|
||||
startOffset = 0;
|
||||
endIndex = Math.ceil(height / itemHeight);
|
||||
}
|
||||
if (endIndex === undefined) {
|
||||
endIndex = dataLen - 1;
|
||||
|
@ -324,7 +329,7 @@ const List = defineComponent({
|
|||
// When data size reduce. It may trigger native scroll event back to fit scroll position
|
||||
function onFallbackScroll(e: UIEvent) {
|
||||
const { scrollTop: newScrollTop } = e.currentTarget as Element;
|
||||
if (Math.abs(newScrollTop - state.scrollTop) >= 1) {
|
||||
if (newScrollTop !== state.scrollTop) {
|
||||
syncScrollTop(newScrollTop);
|
||||
}
|
||||
|
||||
|
|
|
@ -119,18 +119,19 @@ export default defineComponent({
|
|||
this.onScrollbarTouchStart,
|
||||
supportsPassive ? ({ passive: false } as EventListenerOptions) : false,
|
||||
);
|
||||
this.thumbRef.current.removeEventListener(
|
||||
'touchstart',
|
||||
this.onMouseDown,
|
||||
supportsPassive ? ({ passive: false } as EventListenerOptions) : false,
|
||||
);
|
||||
this.thumbRef.current.removeEventListener(
|
||||
'touchmove',
|
||||
this.onMouseMove,
|
||||
supportsPassive ? ({ passive: false } as EventListenerOptions) : false,
|
||||
);
|
||||
this.thumbRef.current.removeEventListener('touchend', this.onMouseUp);
|
||||
|
||||
if (this.thumbRef.current) {
|
||||
this.thumbRef.current.removeEventListener(
|
||||
'touchstart',
|
||||
this.onMouseDown,
|
||||
supportsPassive ? ({ passive: false } as EventListenerOptions) : false,
|
||||
);
|
||||
this.thumbRef.current.removeEventListener(
|
||||
'touchmove',
|
||||
this.onMouseMove,
|
||||
supportsPassive ? ({ passive: false } as EventListenerOptions) : false,
|
||||
);
|
||||
this.thumbRef.current.removeEventListener('touchend', this.onMouseUp);
|
||||
}
|
||||
raf.cancel(this.moveRaf);
|
||||
},
|
||||
|
||||
|
|
|
@ -1,6 +1,7 @@
|
|||
import type { VNodeProps, Ref, ShallowRef } from 'vue';
|
||||
import { watch, ref } from 'vue';
|
||||
import { onUnmounted, watch, ref } from 'vue';
|
||||
import type { GetKey } from '../interface';
|
||||
import wrapperRaf from '../../_util/raf';
|
||||
|
||||
export type CacheMap = Map<any, number>;
|
||||
|
||||
|
@ -16,14 +17,14 @@ export default function useHeights<T>(
|
|||
watch(mergedData, () => {
|
||||
updatedMark.value = Symbol('update');
|
||||
});
|
||||
let heightUpdateId = 0;
|
||||
let collectRaf: number = undefined;
|
||||
|
||||
function cancelRaf() {
|
||||
wrapperRaf.cancel(collectRaf);
|
||||
}
|
||||
function collectHeight() {
|
||||
heightUpdateId += 1;
|
||||
const currentId = heightUpdateId;
|
||||
Promise.resolve().then(() => {
|
||||
// Only collect when it's latest call
|
||||
if (currentId !== heightUpdateId) return;
|
||||
// let changed = false;
|
||||
cancelRaf();
|
||||
collectRaf = wrapperRaf(() => {
|
||||
instance.forEach((element, key) => {
|
||||
if (element && element.offsetParent) {
|
||||
const { offsetHeight } = element;
|
||||
|
@ -57,6 +58,9 @@ export default function useHeights<T>(
|
|||
}
|
||||
}
|
||||
}
|
||||
onUnmounted(() => {
|
||||
cancelRaf();
|
||||
});
|
||||
|
||||
return [setInstance, collectHeight, heights, updatedMark];
|
||||
}
|
||||
|
|
|
@ -103,7 +103,7 @@ export default function useScrollTo(
|
|||
collectHeight();
|
||||
}
|
||||
syncScroll(times - 1, newTargetAlign);
|
||||
});
|
||||
}, 2);
|
||||
};
|
||||
|
||||
syncScroll(5);
|
||||
|
|
|
@ -1,7 +1,6 @@
|
|||
export function isZhCN(name) {
|
||||
return /-cn\/?$/.test(name);
|
||||
}
|
||||
|
||||
export function isLocalStorageNameSupported() {
|
||||
const testKey = 'test';
|
||||
const storage = window.localStorage;
|
||||
|
@ -13,7 +12,6 @@ export function isLocalStorageNameSupported() {
|
|||
return false;
|
||||
}
|
||||
}
|
||||
|
||||
export function getLocalizedPathname(path, zhCN, query = {}, hash) {
|
||||
const pathname = path.startsWith('/') ? path : `/${path}`;
|
||||
let fullPath;
|
||||
|
@ -27,7 +25,6 @@ export function getLocalizedPathname(path, zhCN, query = {}, hash) {
|
|||
} else {
|
||||
fullPath = `${pathname}-cn`;
|
||||
}
|
||||
|
||||
if (hash) {
|
||||
const localHash = hash[zhCN ? 'zhCN' : 'enUS'];
|
||||
fullPath += `#${localHash}`;
|
||||
|
|
Loading…
Reference in New Issue