Merge branch 'next' into feat-dayjs

feat-dayjs
tangjinzhou 2020-10-20 21:29:15 +08:00
commit 91b4a1c0e4
51 changed files with 582 additions and 453 deletions

View File

@ -3,18 +3,18 @@ const getTransitionGroupProps = (transitionName, opt = {}) => {
if (process.env.NODE_ENV === 'test') {
return { css: false, ...opt };
}
const transitionProps = {
const transitionProps = transitionName ? {
appear: true,
appearFromClass: `${transitionName}-appear ${transitionName}-appear-prepare`,
appearActiveClass: `${transitionName}`,
appearToClass: `${transitionName}-appear-active`,
appearToClass: `${transitionName}-appear ${transitionName}-appear-active`,
enterFromClass: `${transitionName}-appear ${transitionName}-enter ${transitionName}-appear-prepare ${transitionName}-enter-prepare`,
enterActiveClass: `${transitionName}`,
enterToClass: `${transitionName}-appear-active ${transitionName}-enter-active`,
enterToClass: `${transitionName}-enter ${transitionName}-appear ${transitionName}-appear-active ${transitionName}-enter-active`,
leaveActiveClass: `${transitionName} ${transitionName}-leave`,
leaveToClass: `${transitionName}-leave-active`,
...opt,
};
} : { css: false, ...opt };
return transitionProps;
};

View File

@ -2,7 +2,7 @@ const getTransitionProps = (transitionName, opt = {}) => {
if (process.env.NODE_ENV === 'test') {
return { css: false, ...opt };
}
const transitionProps = {
const transitionProps = transitionName ? {
appear: true,
appearFromClass: `${transitionName}-appear ${transitionName}-appear-prepare`,
// appearActiveClass: `antdv-base-transtion`,
@ -14,7 +14,7 @@ const getTransitionProps = (transitionName, opt = {}) => {
leaveActiveClass: `${transitionName}-leave ${transitionName}-leave-active`,
leaveToClass: `${transitionName}-leave ${transitionName}-leave-active`,
...opt,
};
}: { css: false, ...opt };
return transitionProps;
};

View File

@ -1,3 +1,4 @@
import { ExtractPropTypes } from 'vue';
import { tuple } from '../_util/type';
import PropTypes, { withUndefined } from '../_util/vue-types';
@ -10,7 +11,7 @@ export type ButtonSize = typeof ButtonSizes[number];
const ButtonHTMLTypes = tuple('submit', 'button', 'reset');
export type ButtonHTMLType = typeof ButtonHTMLTypes[number];
export default () => ({
const buttonProps = () => ({
prefixCls: PropTypes.string,
type: PropTypes.oneOf(ButtonTypes),
htmlType: PropTypes.oneOf(ButtonHTMLTypes).def('button'),
@ -26,3 +27,7 @@ export default () => ({
title: PropTypes.string,
onClick: PropTypes.func,
});
export type ButtonProps = ExtractPropTypes<ExtractPropTypes<ReturnType<typeof buttonProps>>>;
export default buttonProps;

View File

@ -11,6 +11,8 @@ export interface CSPConfig {
nonce?: string;
}
export { RenderEmptyHandler };
export interface ConfigConsumerProps {
getTargetContainer?: () => HTMLElement;
getPopupContainer?: (triggerNode: HTMLElement) => HTMLElement;

View File

@ -26,7 +26,7 @@ export default defineComponent({
},
children: {
type: Function as PropType<
(locale: object, localeCode?: string, fullLocale?: object) => VNodeTypes
(locale: any, localeCode?: string, fullLocale?: object) => VNodeTypes
>,
},
},

View File

@ -1,9 +1,11 @@
import { defineComponent, ExtractPropTypes } from 'vue';
import PropTypes from '../_util/vue-types';
import Button from '../button';
import BaseMixin from '../_util/BaseMixin';
import buttonTypes from '../button/buttonTypes';
import { getSlot, findDOMNode } from '../_util/props-util';
const ButtonType = buttonTypes().type;
const ActionButtonProps = {
type: ButtonType,
actionFn: PropTypes.func,
@ -12,7 +14,9 @@ const ActionButtonProps = {
buttonProps: PropTypes.object,
};
export default {
export type IActionButtonProps = ExtractPropTypes<typeof ActionButtonProps>;
export default defineComponent({
mixins: [BaseMixin],
props: ActionButtonProps,
data() {
@ -20,6 +24,11 @@ export default {
loading: false,
};
},
setup() {
return {
timeoutId: undefined,
};
},
mounted() {
if (this.autofocus) {
this.timeoutId = setTimeout(() => findDOMNode(this).focus());
@ -74,4 +83,4 @@ export default {
};
return <Button {...props}>{getSlot(this)}</Button>;
},
};
});

View File

@ -1,9 +1,16 @@
import classNames from '../_util/classNames';
import Dialog from './Modal';
import Dialog, { ModalFuncProps } from './Modal';
import ActionButton from './ActionButton';
import { getConfirmLocale } from './locale';
import { FunctionalComponent } from 'vue';
const ConfirmDialog = (_, { attrs }) => {
interface ConfirmDialogProps extends ModalFuncProps {
afterClose?: () => void;
close: (...args: any[]) => void;
autoFocusButton?: null | 'ok' | 'cancel';
}
const ConfirmDialog: FunctionalComponent<ConfirmDialogProps> = props => {
const {
icon,
onCancel,
@ -18,30 +25,30 @@ const ConfirmDialog = (_, { attrs }) => {
maskStyle,
okButtonProps,
cancelButtonProps,
closable = false,
} = attrs;
const okType = attrs.okType || 'primary';
const prefixCls = attrs.prefixCls || 'ant-modal';
// closable = false,
} = props;
const okType = props.okType || 'primary';
const prefixCls = props.prefixCls || 'ant-modal';
const contentPrefixCls = `${prefixCls}-confirm`;
// 默认为 true保持向下兼容
const okCancel = 'okCancel' in attrs ? attrs.okCancel : true;
const width = attrs.width || 416;
const style = attrs.style || {};
const mask = attrs.mask === undefined ? true : attrs.mask;
const okCancel = 'okCancel' in props ? props.okCancel : true;
const width = props.width || 416;
const style = props.style || {};
const mask = props.mask === undefined ? true : props.mask;
// 默认为 false保持旧版默认行为
const maskClosable = attrs.maskClosable === undefined ? false : attrs.maskClosable;
const maskClosable = props.maskClosable === undefined ? false : props.maskClosable;
const runtimeLocale = getConfirmLocale();
const okText = attrs.okText || (okCancel ? runtimeLocale.okText : runtimeLocale.justOkText);
const cancelText = attrs.cancelText || runtimeLocale.cancelText;
const autoFocusButton = attrs.autoFocusButton === null ? false : attrs.autoFocusButton || 'ok';
const transitionName = attrs.transitionName || 'zoom';
const maskTransitionName = attrs.maskTransitionName || 'fade';
const okText = props.okText || (okCancel ? runtimeLocale.okText : runtimeLocale.justOkText);
const cancelText = props.cancelText || runtimeLocale.cancelText;
const autoFocusButton = props.autoFocusButton === null ? false : props.autoFocusButton || 'ok';
const transitionName = props.transitionName || 'zoom';
const maskTransitionName = props.maskTransitionName || 'fade';
const classString = classNames(
contentPrefixCls,
`${contentPrefixCls}-${attrs.type}`,
`${prefixCls}-${attrs.type}`,
attrs.class,
`${contentPrefixCls}-${props.type}`,
`${prefixCls}-${props.type}`,
props.class,
);
const cancelButton = okCancel && (
@ -62,7 +69,6 @@ const ConfirmDialog = (_, { attrs }) => {
wrapClassName={classNames({ [`${contentPrefixCls}-centered`]: !!centered })}
onCancel={e => close({ triggerCancel: true }, e)}
visible={visible}
closable={closable}
title=""
transitionName={transitionName}
footer=""
@ -80,13 +86,11 @@ const ConfirmDialog = (_, { attrs }) => {
>
<div class={`${contentPrefixCls}-body-wrapper`}>
<div class={`${contentPrefixCls}-body`}>
{typeof icon === 'function' ? icon() : icon}
{attrs.title === undefined ? null : (
<span class={`${contentPrefixCls}-title`}>{attrs.title}</span>
{icon}
{props.title === undefined ? null : (
<span class={`${contentPrefixCls}-title`}>{props.title}</span>
)}
<div class={`${contentPrefixCls}-content`}>
{typeof attrs.content === 'function' ? attrs.content() : attrs.content}
</div>
<div class={`${contentPrefixCls}-content`}>{props.content}</div>
</div>
<div class={`${contentPrefixCls}-btns`}>
{cancelButton}
@ -104,5 +108,7 @@ const ConfirmDialog = (_, { attrs }) => {
</Dialog>
);
};
ConfirmDialog.inheritAttrs = false;
export default ConfirmDialog;

View File

@ -1,4 +1,11 @@
import { inject } from 'vue';
import {
defineComponent,
ExtractPropTypes,
inject,
VNodeTypes,
CSSProperties,
PropType,
} from 'vue';
import classNames from '../_util/classNames';
import Dialog from '../vc-dialog';
import PropTypes from '../_util/vue-types';
@ -6,15 +13,18 @@ import addEventListener from '../vc-util/Dom/addEventListener';
import { getConfirmLocale } from './locale';
import CloseOutlined from '@ant-design/icons-vue/CloseOutlined';
import Button from '../button';
import buttonTypes from '../button/buttonTypes';
const ButtonType = buttonTypes().type;
import buttonTypes, { ButtonType, ButtonProps } from '../button/buttonTypes';
import LocaleReceiver from '../locale-provider/LocaleReceiver';
import { initDefaultProps, getComponent, getSlot } from '../_util/props-util';
import { getComponent, getSlot } from '../_util/props-util';
import initDefaultProps from '../_util/props-util/initDefaultProps';
import { defaultConfigProvider } from '../config-provider';
let mousePosition = null;
const ButtonProps = buttonTypes();
const ButtonType = ButtonProps.type;
let mousePosition: { x: number; y: number } | null = null;
// ref: https://github.com/ant-design/ant-design/issues/15795
const getClickPosition = e => {
const getClickPosition = (e: MouseEvent) => {
mousePosition = {
x: e.pageX,
y: e.pageY,
@ -31,68 +41,121 @@ if (typeof window !== 'undefined' && window.document && window.document.document
}
function noop() {}
const modalProps = (defaultProps = {}) => {
const props = {
prefixCls: PropTypes.string,
/** 对话框是否可见*/
visible: PropTypes.looseBool,
/** 确定按钮 loading*/
confirmLoading: PropTypes.looseBool,
/** 标题*/
title: PropTypes.any,
/** 是否显示右上角的关闭按钮*/
closable: PropTypes.looseBool,
closeIcon: PropTypes.any,
/** 点击确定回调*/
// onOk: (e: React.MouseEvent<any>) => void,
/** 点击模态框右上角叉、取消按钮、Props.maskClosable 值为 true 时的遮罩层或键盘按下 Esc 时的回调*/
// onCancel: (e: React.MouseEvent<any>) => void,
afterClose: PropTypes.func.def(noop),
/** 垂直居中 */
centered: PropTypes.looseBool,
/** 宽度*/
width: PropTypes.oneOfType([PropTypes.string, PropTypes.number]),
/** 底部内容*/
footer: PropTypes.any,
/** 确认按钮文字*/
okText: PropTypes.any,
/** 确认按钮类型*/
okType: ButtonType,
/** 取消按钮文字*/
cancelText: PropTypes.any,
icon: PropTypes.any,
/** 点击蒙层是否允许关闭*/
maskClosable: PropTypes.looseBool,
/** 强制渲染 Modal*/
forceRender: PropTypes.looseBool,
okButtonProps: PropTypes.object,
cancelButtonProps: PropTypes.object,
destroyOnClose: PropTypes.looseBool,
wrapClassName: PropTypes.string,
maskTransitionName: PropTypes.string,
transitionName: PropTypes.string,
getContainer: PropTypes.func,
zIndex: PropTypes.number,
bodyStyle: PropTypes.object,
maskStyle: PropTypes.object,
mask: PropTypes.looseBool,
keyboard: PropTypes.looseBool,
wrapProps: PropTypes.object,
focusTriggerAfterClose: PropTypes.looseBool,
};
return initDefaultProps(props, defaultProps);
const modalProps = {
prefixCls: PropTypes.string,
/** 对话框是否可见*/
visible: PropTypes.looseBool,
/** 确定按钮 loading*/
confirmLoading: PropTypes.looseBool,
/** 标题*/
title: PropTypes.any,
/** 是否显示右上角的关闭按钮*/
closable: PropTypes.looseBool,
closeIcon: PropTypes.any,
/** 点击确定回调*/
onOk: {
type: Function as PropType<(e: MouseEvent) => void>,
},
/** 点击模态框右上角叉、取消按钮、Props.maskClosable 值为 true 时的遮罩层或键盘按下 Esc 时的回调*/
onCancel: {
type: Function as PropType<(e: MouseEvent) => void>,
},
afterClose: PropTypes.func.def(noop),
/** 垂直居中 */
centered: PropTypes.looseBool,
/** 宽度*/
width: PropTypes.oneOfType([PropTypes.string, PropTypes.number]),
/** 底部内容*/
footer: PropTypes.any,
/** 确认按钮文字*/
okText: PropTypes.any,
/** 确认按钮类型*/
okType: ButtonType,
/** 取消按钮文字*/
cancelText: PropTypes.any,
icon: PropTypes.any,
/** 点击蒙层是否允许关闭*/
maskClosable: PropTypes.looseBool,
/** 强制渲染 Modal*/
forceRender: PropTypes.looseBool,
okButtonProps: PropTypes.shape(ButtonProps),
cancelButtonProps: PropTypes.shape(ButtonProps),
destroyOnClose: PropTypes.looseBool,
wrapClassName: PropTypes.string,
maskTransitionName: PropTypes.string,
transitionName: PropTypes.string,
getContainer: PropTypes.func,
zIndex: PropTypes.number,
bodyStyle: PropTypes.style,
maskStyle: PropTypes.style,
mask: PropTypes.looseBool,
keyboard: PropTypes.looseBool,
wrapProps: PropTypes.object,
focusTriggerAfterClose: PropTypes.looseBool,
};
export type ModalProps = ExtractPropTypes<typeof modalProps>;
export interface ModalFuncProps {
prefixCls?: string;
class?: string;
visible?: boolean;
title?: VNodeTypes;
content?: VNodeTypes;
// TODO: find out exact types
onOk?: (...args: any[]) => any;
onCancel?: (...args: any[]) => any;
okButtonProps?: ButtonProps;
cancelButtonProps?: ButtonProps;
centered?: boolean;
width?: string | number;
okText?: VNodeTypes;
okType?: ButtonType;
cancelText?: VNodeTypes;
icon?: VNodeTypes;
/* Deprecated */
iconType?: string;
mask?: boolean;
maskClosable?: boolean;
zIndex?: number;
okCancel?: boolean;
style?: CSSProperties | string;
maskStyle?: CSSProperties;
type?: string;
keyboard?: boolean;
getContainer?: getContainerFunc;
autoFocusButton?: null | 'ok' | 'cancel';
transitionName?: string;
maskTransitionName?: string;
}
type getContainerFunc = () => HTMLElement;
export type ModalFunc = (
props: ModalFuncProps,
) => {
destroy: () => void;
update: (newConfig: ModalFuncProps) => void;
};
export interface ModalLocale {
okText: string;
cancelText: string;
justOkText: string;
}
export const destroyFns = [];
export default {
export default defineComponent({
name: 'AModal',
inheritAttrs: false,
model: {
prop: 'visible',
event: 'change',
},
props: modalProps({
emits: ['update:visible', 'cancel', 'change', 'ok'],
props: initDefaultProps(modalProps, {
width: 520,
transitionName: 'zoom',
maskTransitionName: 'fade',
@ -115,23 +178,17 @@ export default {
configProvider: inject('configProvider', defaultConfigProvider),
};
},
// static info: ModalFunc;
// static success: ModalFunc;
// static error: ModalFunc;
// static warn: ModalFunc;
// static warning: ModalFunc;
// static confirm: ModalFunc;
methods: {
handleCancel(e) {
handleCancel(e: MouseEvent) {
this.$emit('update:visible', false);
this.$emit('cancel', e);
this.$emit('change', false);
},
handleOk(e) {
handleOk(e: MouseEvent) {
this.$emit('ok', e);
},
renderFooter(locale) {
renderFooter(locale: ModalLocale) {
const { okType, confirmLoading } = this;
const cancelBtnProps = { onClick: this.handleCancel, ...(this.cancelButtonProps || {}) };
const okBtnProps = {
@ -194,4 +251,4 @@ export default {
};
return <Dialog {...dialogProps}>{children}</Dialog>;
},
};
});

View File

@ -1,17 +1,17 @@
import { createApp } from 'vue';
import ConfirmDialog from './ConfirmDialog';
import { destroyFns } from './Modal';
import { destroyFns, ModalFuncProps } from './Modal';
import Omit from 'omit.js';
export default function confirm(config) {
export default function confirm(config: ModalFuncProps) {
const div = document.createElement('div');
document.body.appendChild(div);
let currentConfig = { ...Omit(config, ['parentContext']), close, visible: true };
let confirmDialogInstance = null;
let confirmDialogProps = {};
function close(...args) {
function close(this: typeof close, ...args: any[]) {
currentConfig = {
...currentConfig,
visible: false,
@ -19,7 +19,7 @@ export default function confirm(config) {
};
update(currentConfig);
}
function update(newConfig) {
function update(newConfig: ModalFuncProps) {
currentConfig = {
...currentConfig,
...newConfig,
@ -27,7 +27,7 @@ export default function confirm(config) {
confirmDialogInstance &&
Object.assign(confirmDialogInstance, { confirmDialogProps: currentConfig });
}
function destroy(...args) {
function destroy(...args: any[]) {
if (confirmDialogInstance && div.parentNode) {
confirmDialogInstance.vIf = false; // hack destroy
confirmDialogInstance = null;
@ -46,10 +46,10 @@ export default function confirm(config) {
}
}
function render(props) {
function render(props: ModalFuncProps) {
confirmDialogProps = props;
return createApp({
parent: config.parentContext,
parent: (config as any).parentContext,
data() {
return { confirmDialogProps, vIf: true };
},

View File

@ -1,14 +1,15 @@
import Modal, { destroyFns } from './Modal';
import { App } from 'vue';
import Modal, { destroyFns, ModalFuncProps } from './Modal';
import modalConfirm from './confirm';
import InfoCircleOutlined from '@ant-design/icons-vue/InfoCircleOutlined';
import CheckCircleOutlined from '@ant-design/icons-vue/CheckCircleOutlined';
import CloseCircleOutlined from '@ant-design/icons-vue/CloseCircleOutlined';
import ExclamationCircleOutlined from '@ant-design/icons-vue/ExclamationCircleOutlined';
// export { ActionButtonProps } from './ActionButton'
// export { ModalProps, ModalFuncProps } from './Modal'
export { IActionButtonProps as ActionButtonProps } from './ActionButton';
export { ModalProps, ModalFuncProps } from './Modal';
const info = function(props) {
const info = function(props: ModalFuncProps) {
const config = {
type: 'info',
icon: <InfoCircleOutlined />,
@ -18,7 +19,7 @@ const info = function(props) {
return modalConfirm(config);
};
const success = function(props) {
const success = function(props: ModalFuncProps) {
const config = {
type: 'success',
icon: <CheckCircleOutlined />,
@ -28,7 +29,7 @@ const success = function(props) {
return modalConfirm(config);
};
const error = function(props) {
const error = function(props: ModalFuncProps) {
const config = {
type: 'error',
icon: <CloseCircleOutlined />,
@ -38,7 +39,7 @@ const error = function(props) {
return modalConfirm(config);
};
const warning = function(props) {
const warning = function(props: ModalFuncProps) {
const config = {
type: 'warning',
icon: <ExclamationCircleOutlined />,
@ -49,7 +50,7 @@ const warning = function(props) {
};
const warn = warning;
const confirm = function confirmFn(props) {
const confirm = function confirmFn(props: ModalFuncProps) {
const config = {
type: 'confirm',
okCancel: true,
@ -74,7 +75,7 @@ Modal.destroyAll = function destroyAllFn() {
};
/* istanbul ignore next */
Modal.install = function(app) {
Modal.install = function(app: App) {
app.component(Modal.name, Modal);
return app;
};

View File

@ -10,7 +10,7 @@ let runtimeLocale = {
...defaultLocale.Modal,
};
export function changeConfirmLocale(newLocale?: any) {
export function changeConfirmLocale(newLocale?: ModalLocale) {
if (newLocale) {
runtimeLocale = {
...runtimeLocale,

View File

@ -1,5 +1,5 @@
import omit from 'omit.js';
import { inject } from 'vue';
import { App, defineComponent, inject } from 'vue';
import Tooltip from '../tooltip';
import abstractTooltipProps from '../tooltip/abstractTooltipProps';
import PropTypes from '../_util/vue-types';
@ -14,7 +14,8 @@ import { defaultConfigProvider } from '../config-provider';
const tooltipProps = abstractTooltipProps();
const btnProps = buttonTypes();
const Popconfirm = {
const Popconfirm = defineComponent({
name: 'APopconfirm',
props: {
...tooltipProps,
@ -33,9 +34,9 @@ const Popconfirm = {
onConfirm: PropTypes.func,
onCancel: PropTypes.func,
onVisibleChange: PropTypes.func,
'onUpdate:visible': PropTypes.func,
},
mixins: [BaseMixin],
emits: ['update:visible', 'confirm', 'cancel', 'visibleChange'],
watch: {
visible(val) {
this.sVisible = val;
@ -47,7 +48,7 @@ const Popconfirm = {
};
},
data() {
const props = getOptionProps(this);
const props = getOptionProps(this) as any;
const state = { sVisible: false };
if ('visible' in props) {
state.sVisible = props.visible;
@ -76,7 +77,7 @@ const Popconfirm = {
this.setVisible(sVisible);
},
setVisible(sVisible, e) {
setVisible(sVisible: boolean, e?: Event) {
if (!hasProp(this, 'visible')) {
this.setState({ sVisible });
}
@ -84,9 +85,9 @@ const Popconfirm = {
this.$emit('visibleChange', sVisible, e);
},
getPopupDomNode() {
return this.$refs.tooltip.getPopupDomNode();
return (this.$refs.tooltip as any).getPopupDomNode();
},
renderOverlay(prefixCls, popconfirmLocale) {
renderOverlay(prefixCls: string, popconfirmLocale) {
const { okType, okButtonProps, cancelButtonProps } = this;
const icon = getComponent(this, 'icon') || <ExclamationCircleFilled />;
const cancelBtnProps = mergeProps({
@ -121,7 +122,7 @@ const Popconfirm = {
render() {
const props = getOptionProps(this);
const { prefixCls: customizePrefixCls } = props;
const getPrefixCls = this.configProvider.getPrefixCls;
const { getPrefixCls } = this.configProvider;
const prefixCls = getPrefixCls('popover', customizePrefixCls);
const otherProps = omit(props, [
@ -148,10 +149,10 @@ const Popconfirm = {
};
return <Tooltip {...tooltipProps}>{this.$slots?.default()}</Tooltip>;
},
};
});
/* istanbul ignore next */
Popconfirm.install = function(app) {
Popconfirm.install = function(app: App) {
app.component(Popconfirm.name, Popconfirm);
return app;
};

View File

@ -1,4 +1,4 @@
import { inject } from 'vue';
import { App, defineComponent, inject } from 'vue';
import Tooltip from '../tooltip';
import abstractTooltipProps from '../tooltip/abstractTooltipProps';
import PropTypes from '../_util/vue-types';
@ -6,7 +6,7 @@ import { getOptionProps, getComponent, getSlot } from '../_util/props-util';
import { defaultConfigProvider } from '../config-provider';
const props = abstractTooltipProps();
const Popover = {
const Popover = defineComponent({
name: 'APopover',
props: {
...props,
@ -22,13 +22,13 @@ const Popover = {
},
methods: {
getPopupDomNode() {
return this.$refs.tooltip.getPopupDomNode();
return (this.$refs.tooltip as any).getPopupDomNode();
},
},
render() {
const { title, prefixCls: customizePrefixCls, $slots } = this;
const getPrefixCls = this.configProvider.getPrefixCls;
const { getPrefixCls } = this.configProvider;
const prefixCls = getPrefixCls('popover', customizePrefixCls);
const props = getOptionProps(this);
@ -49,10 +49,10 @@ const Popover = {
};
return <Tooltip {...tooltipProps}>{getSlot(this)}</Tooltip>;
},
};
});
/* istanbul ignore next */
Popover.install = function(app) {
Popover.install = function(app: App) {
app.component(Popover.name, Popover);
return app;
};

View File

@ -4,6 +4,8 @@ import PropTypes from '../_util/vue-types';
import Radio from './Radio';
import { getOptionProps, filterEmpty, hasProp, getSlot } from '../_util/props-util';
import { defaultConfigProvider } from '../config-provider';
import { tuple } from '../_util/type';
import { RadioChangeEvent } from './interface';
export default defineComponent({
name: 'ARadioGroup',
@ -11,43 +13,39 @@ export default defineComponent({
prefixCls: PropTypes.string,
defaultValue: PropTypes.any,
value: PropTypes.any,
size: {
default: 'default',
validator(value) {
return ['large', 'default', 'small'].includes(value);
},
},
options: {
default: () => [],
type: Array,
},
size: PropTypes.oneOf(tuple('large', 'default', 'small')).def('default'),
options: PropTypes.array,
disabled: PropTypes.looseBool,
name: String,
name: PropTypes.string,
buttonStyle: PropTypes.string.def('outline'),
onChange: PropTypes.func,
'onUpdate:value': PropTypes.func,
},
emits: ['update:value', 'change'],
data() {
const { value, defaultValue } = this;
this.updatingValue = false;
return {
stateValue: value === undefined ? defaultValue : value,
};
},
setup() {
return {
updatingValue: false,
configProvider: inject('configProvider', defaultConfigProvider),
radioGroupContext: null,
};
},
computed: {
radioOptions() {
const { disabled } = this;
return this.options.map(option => {
return typeof option === 'string'
? { label: option, value: option }
: { ...option, disabled: option.disabled === undefined ? disabled : option.disabled };
});
},
// computed: {
// radioOptions() {
// const { disabled } = this;
// return this.options.map(option => {
// return typeof option === 'string'
// ? { label: option, value: option }
// : { ...option, disabled: option.disabled === undefined ? disabled : option.disabled };
// });
// },
// },
created() {
this.radioGroupContext = provide('radioGroupContext', this);
},
watch: {
value(val) {
@ -55,11 +53,8 @@ export default defineComponent({
this.stateValue = val;
},
},
created() {
this.radioGroupContext = provide('radioGroupContext', this);
},
methods: {
onRadioChange(ev) {
onRadioChange(ev: RadioChangeEvent) {
const lastValue = this.stateValue;
const { value } = ev.target;
if (!hasProp(this, 'value')) {
@ -79,7 +74,7 @@ export default defineComponent({
render() {
const props = getOptionProps(this);
const { prefixCls: customizePrefixCls, options, buttonStyle } = props;
const getPrefixCls = this.configProvider.getPrefixCls;
const { getPrefixCls } = this.configProvider;
const prefixCls = getPrefixCls('radio', customizePrefixCls);
const groupPrefixCls = `${prefixCls}-group`;

View File

@ -1,32 +1,36 @@
import { inject } from 'vue';
import { defineComponent, ExtractPropTypes, inject } from 'vue';
import PropTypes from '../_util/vue-types';
import VcCheckbox from '../vc-checkbox';
import classNames from '../_util/classNames';
import { getOptionProps } from '../_util/props-util';
import { defaultConfigProvider } from '../config-provider';
import { RadioChangeEvent } from './interface';
export default {
export const radioProps = {
prefixCls: PropTypes.string,
defaultChecked: PropTypes.looseBool,
checked: PropTypes.looseBool,
disabled: PropTypes.looseBool,
isGroup: PropTypes.looseBool,
value: PropTypes.any,
name: PropTypes.string,
id: PropTypes.string,
autofocus: PropTypes.looseBool,
type: PropTypes.string.def('radio'),
onChange: PropTypes.func,
onFocus: PropTypes.func,
onBlur: PropTypes.func,
};
export type RadioProps = Partial<ExtractPropTypes<typeof radioProps>>;
export default defineComponent({
name: 'ARadio',
model: {
prop: 'checked',
},
props: {
prefixCls: PropTypes.string,
defaultChecked: PropTypes.looseBool,
checked: PropTypes.looseBool,
disabled: PropTypes.looseBool,
isGroup: PropTypes.looseBool,
value: PropTypes.any,
name: String,
id: String,
autofocus: PropTypes.looseBool,
type: PropTypes.string.def('radio'),
onChange: PropTypes.func,
onFocus: PropTypes.func,
onBlur: PropTypes.func,
'onUpdate:checked': PropTypes.func,
'onUpdate:value': PropTypes.func,
},
props: radioProps,
emits: ['update:checked', 'update:value', 'change', 'blur', 'focus'],
setup() {
return {
configProvider: inject('configProvider', defaultConfigProvider),
@ -35,18 +39,18 @@ export default {
},
methods: {
focus() {
this.$refs.vcCheckbox.focus();
(this.$refs.vcCheckbox as any).focus();
},
blur() {
this.$refs.vcCheckbox.blur();
(this.$refs.vcCheckbox as any).blur();
},
handleChange(event) {
handleChange(event: RadioChangeEvent) {
const targetChecked = event.target.checked;
this.$emit('update:checked', targetChecked);
this.$emit('update:value', targetChecked);
this.$emit('change', event);
},
onChange2(e) {
onChange2(e: RadioChangeEvent) {
this.$emit('change', e);
if (this.radioGroupContext && this.radioGroupContext.onRadioChange) {
this.radioGroupContext.onRadioChange(e);
@ -58,33 +62,33 @@ export default {
const { $slots, radioGroupContext: radioGroup } = this;
const props = getOptionProps(this);
const { prefixCls: customizePrefixCls, ...restProps } = props;
const getPrefixCls = this.configProvider.getPrefixCls;
const { getPrefixCls } = this.configProvider;
const prefixCls = getPrefixCls('radio', customizePrefixCls);
const radioProps = {
const rProps: RadioProps = {
prefixCls,
...restProps,
};
if (radioGroup) {
radioProps.name = radioGroup.name;
radioProps.onChange = this.onChange2;
radioProps.checked = props.value === radioGroup.stateValue;
radioProps.disabled = props.disabled || radioGroup.disabled;
rProps.name = radioGroup.name;
rProps.onChange = this.onChange2;
rProps.checked = props.value === radioGroup.stateValue;
rProps.disabled = props.disabled || radioGroup.disabled;
} else {
radioProps.onChange = this.handleChange;
rProps.onChange = this.handleChange;
}
const wrapperClassString = classNames({
[`${prefixCls}-wrapper`]: true,
[`${prefixCls}-wrapper-checked`]: radioProps.checked,
[`${prefixCls}-wrapper-disabled`]: radioProps.disabled,
[`${prefixCls}-wrapper-checked`]: rProps.checked,
[`${prefixCls}-wrapper-disabled`]: rProps.disabled,
});
return (
<label class={wrapperClassString}>
<VcCheckbox {...radioProps} ref="vcCheckbox" />
<VcCheckbox {...rProps} ref="vcCheckbox" />
{$slots.default && <span>{$slots.default()}</span>}
</label>
);
},
};
});

View File

@ -1,34 +1,34 @@
import { defineComponent, inject } from 'vue';
import Radio from './Radio';
import Radio, { radioProps, RadioProps } from './Radio';
import { getOptionProps, getSlot } from '../_util/props-util';
import { defaultConfigProvider } from '../config-provider';
export default defineComponent({
name: 'ARadioButton',
props: {
...Radio.props,
...radioProps,
},
setup() {
return {
configProvider: inject('configProvider', defaultConfigProvider),
radioGroupContext: inject('radioGroupContext', {}),
radioGroupContext: inject<any>('radioGroupContext', {}),
};
},
render() {
const props = getOptionProps(this);
const props = getOptionProps(this) as RadioProps;
const { prefixCls: customizePrefixCls, ...otherProps } = props;
const getPrefixCls = this.configProvider.getPrefixCls;
const { getPrefixCls } = this.configProvider;
const prefixCls = getPrefixCls('radio-button', customizePrefixCls);
const radioProps = {
const rProps: RadioProps = {
prefixCls,
...otherProps,
};
if (this.radioGroupContext) {
radioProps.onChange = this.radioGroupContext.onRadioChange;
radioProps.checked = props.value === this.radioGroupContext.stateValue;
radioProps.disabled = props.disabled || this.radioGroupContext.disabled;
rProps.onChange = this.radioGroupContext.onRadioChange;
rProps.checked = props.value === this.radioGroupContext.stateValue;
rProps.disabled = props.disabled || this.radioGroupContext.disabled;
}
return <Radio {...radioProps}>{getSlot(this)}</Radio>;
return <Radio {...rProps}>{getSlot(this)}</Radio>;
},
});

View File

@ -1,3 +1,4 @@
import { App } from 'vue';
import Radio from './Radio';
import Group from './Group';
import Button from './RadioButton';
@ -6,7 +7,7 @@ Radio.Group = Group;
Radio.Button = Button;
/* istanbul ignore next */
Radio.install = function(app) {
Radio.install = function(app: App) {
app.component(Radio.name, Radio);
app.component(Radio.Group.name, Radio.Group);
app.component(Radio.Button.name, Radio.Button);

View File

@ -0,0 +1,12 @@
import { RadioProps } from './Radio';
export interface RadioChangeEventTarget extends RadioProps {
checked: boolean;
}
export interface RadioChangeEvent {
target: RadioChangeEventTarget;
stopPropagation: () => void;
preventDefault: () => void;
nativeEvent: MouseEvent;
}

View File

@ -1,4 +1,4 @@
import { inject } from 'vue';
import { inject, defineComponent } from 'vue';
import omit from 'omit.js';
import PropTypes from '../_util/vue-types';
import { getOptionProps, getComponent } from '../_util/props-util';
@ -10,8 +10,8 @@ import Tooltip from '../tooltip';
export const RateProps = {
prefixCls: PropTypes.string,
count: PropTypes.number,
value: PropTypes.value,
defaultValue: PropTypes.value,
value: PropTypes.number,
defaultValue: PropTypes.number,
allowHalf: PropTypes.looseBool,
allowClear: PropTypes.looseBool,
tooltips: PropTypes.arrayOf(PropTypes.string),
@ -20,7 +20,7 @@ export const RateProps = {
autofocus: PropTypes.looseBool,
};
const Rate = {
const Rate = defineComponent({
name: 'ARate',
props: RateProps,
setup() {
@ -35,15 +35,15 @@ const Rate = {
return <Tooltip title={tooltips[index]}>{node}</Tooltip>;
},
focus() {
this.$refs.refRate.focus();
(this.$refs.refRate as any).focus();
},
blur() {
this.$refs.refRate.blur();
(this.$refs.refRate as any).blur();
},
},
render() {
const { prefixCls: customizePrefixCls, ...restProps } = getOptionProps(this);
const getPrefixCls = this.configProvider.getPrefixCls;
const { getPrefixCls } = this.configProvider;
const prefixCls = getPrefixCls('rate', customizePrefixCls);
const character = getComponent(this, 'character') || <StarFilled />;
@ -57,7 +57,7 @@ const Rate = {
};
return <VcRate {...rateProps} />;
},
};
});
/* istanbul ignore next */
Rate.install = function(app) {

View File

@ -1,35 +1,36 @@
import { inject } from 'vue';
import { App, defineComponent, ExtractPropTypes, inject } from 'vue';
import CloseOutlined from '@ant-design/icons-vue/CloseOutlined';
import CheckOutlined from '@ant-design/icons-vue/CheckOutlined';
import PropTypes, { withUndefined } from '../_util/vue-types';
import { initDefaultProps, getOptionProps, getComponent, getSlot } from '../_util/props-util';
import { getOptionProps, getComponent, getSlot } from '../_util/props-util';
import initDefaultProps from '../_util/props-util/initDefaultProps';
import VcSteps from '../vc-steps';
import { defaultConfigProvider } from '../config-provider';
import { tuple } from '../_util/type';
const getStepsProps = (defaultProps = {}) => {
const props = {
prefixCls: PropTypes.string,
iconPrefix: PropTypes.string,
current: PropTypes.number,
initial: PropTypes.number,
labelPlacement: PropTypes.oneOf(['horizontal', 'vertical']).def('horizontal'),
status: PropTypes.oneOf(['wait', 'process', 'finish', 'error']),
size: PropTypes.oneOf(['default', 'small']),
direction: PropTypes.oneOf(['horizontal', 'vertical']),
progressDot: withUndefined(PropTypes.oneOfType([PropTypes.looseBool, PropTypes.func])),
type: PropTypes.oneOf(['default', 'navigation']),
onChange: PropTypes.func,
'onUpdate:current': PropTypes.func,
};
return initDefaultProps(props, defaultProps);
const stepsProps = {
prefixCls: PropTypes.string,
iconPrefix: PropTypes.string,
current: PropTypes.number,
initial: PropTypes.number,
labelPlacement: PropTypes.oneOf(tuple('horizontal', 'vertical')).def('horizontal'),
status: PropTypes.oneOf(tuple('wait', 'process', 'finish', 'error')),
size: PropTypes.oneOf(tuple('default', 'small')),
direction: PropTypes.oneOf(tuple('horizontal', 'vertical')),
progressDot: withUndefined(PropTypes.oneOfType([PropTypes.looseBool, PropTypes.func])),
type: PropTypes.oneOf(tuple('default', 'navigation')),
onChange: PropTypes.func,
};
const Steps = {
export type StepsProps = Partial<ExtractPropTypes<typeof stepsProps>>;
const Steps = defineComponent({
name: 'ASteps',
inheritAttrs: false,
props: getStepsProps({
props: initDefaultProps(stepsProps, {
current: 0,
}),
emits: ['update:current', 'change'],
setup() {
return {
configProvider: inject('configProvider', defaultConfigProvider),
@ -43,7 +44,7 @@ const Steps = {
},
},
render() {
const props = { ...getOptionProps(this), ...this.$attrs };
const props: StepsProps = { ...getOptionProps(this), ...this.$attrs };
const { prefixCls: customizePrefixCls, iconPrefix: customizeIconPrefixCls } = props;
const getPrefixCls = this.configProvider.getPrefixCls;
const prefixCls = getPrefixCls('steps', customizePrefixCls);
@ -65,10 +66,10 @@ const Steps = {
};
return <VcSteps {...stepsProps}>{getSlot(this)}</VcSteps>;
},
};
});
/* istanbul ignore next */
Steps.install = function(app) {
Steps.install = function(app: App) {
app.component(Steps.name, Steps);
app.component(Steps.Step.name, Steps.Step);
return app;

View File

@ -1,4 +1,4 @@
import { inject } from 'vue';
import { defineComponent, inject, App } from 'vue';
import LoadingOutlined from '@ant-design/icons-vue/LoadingOutlined';
import PropTypes from '../_util/vue-types';
import hasProp, { getOptionProps, getComponent } from '../_util/props-util';
@ -6,15 +6,16 @@ import VcSwitch from '../vc-switch';
import Wave from '../_util/wave';
import { defaultConfigProvider } from '../config-provider';
import warning from '../_util/warning';
import { tuple } from '../_util/type';
const Switch = {
const Switch = defineComponent({
name: 'ASwitch',
__ANT_SWITCH: true,
inheritAttrs: false,
props: {
prefixCls: PropTypes.string,
// size=default and size=large are the same
size: PropTypes.oneOf(['small', 'default', 'large']),
size: PropTypes.oneOf(tuple('small', 'default', 'large')),
disabled: PropTypes.looseBool,
checkedChildren: PropTypes.any,
unCheckedChildren: PropTypes.any,
@ -26,6 +27,7 @@ const Switch = {
},
setup() {
return {
refSwitchNode: undefined,
configProvider: inject('configProvider', defaultConfigProvider),
};
},
@ -52,12 +54,12 @@ const Switch = {
const { prefixCls: customizePrefixCls, size, loading, disabled, ...restProps } = getOptionProps(
this,
);
const getPrefixCls = this.configProvider.getPrefixCls;
const { getPrefixCls } = this.configProvider;
const prefixCls = getPrefixCls('switch', customizePrefixCls);
const { $attrs } = this;
const classes = {
[$attrs.class]: $attrs.class,
[$attrs.class as string]: $attrs.class,
[`${prefixCls}-small`]: size === 'small',
[`${prefixCls}-loading`]: loading,
};
@ -73,13 +75,16 @@ const Switch = {
class: classes,
ref: this.saveRef,
};
const comp = <VcSwitch {...switchProps} />;
return <Wave insertExtraNode>{comp}</Wave>;
return (
<Wave insertExtraNode>
<VcSwitch {...switchProps} />
</Wave>
);
},
};
});
/* istanbul ignore next */
Switch.install = function(app) {
Switch.install = function(app: App) {
app.component(Switch.name, Switch);
return app;
};

View File

@ -1,5 +1,5 @@
import omit from 'omit.js';
import { inject, provide } from 'vue';
import { App, defineComponent, inject, provide } from 'vue';
import VcTimePicker from '../vc-time-picker';
import LocaleReceiver from '../locale-provider/LocaleReceiver';
import BaseMixin from '../_util/BaseMixin';
@ -8,13 +8,8 @@ import warning from '../_util/warning';
import ClockCircleOutlined from '@ant-design/icons-vue/ClockCircleOutlined';
import CloseCircleFilled from '@ant-design/icons-vue/CloseCircleFilled';
import enUS from './locale/en_US';
import {
initDefaultProps,
hasProp,
getOptionProps,
getComponent,
isValidElement,
} from '../_util/props-util';
import { hasProp, getOptionProps, getComponent, isValidElement } from '../_util/props-util';
import initDefaultProps from '../_util/props-util/initDefaultProps';
import { cloneElement } from '../_util/vnode';
import { defaultConfigProvider } from '../config-provider';
import {
@ -23,8 +18,9 @@ import {
momentToString,
TimeOrTimesType,
} from '../_util/moment-util';
import { tuple } from '../_util/type';
export function generateShowHourMinuteSecond(format) {
export function generateShowHourMinuteSecond(format: string) {
// Ref: http://momentjs.com/docs/#/parsing/string-format/
return {
showHour: format.indexOf('H') > -1 || format.indexOf('h') > -1 || format.indexOf('k') > -1,
@ -34,7 +30,7 @@ export function generateShowHourMinuteSecond(format) {
}
export const TimePickerProps = () => ({
size: PropTypes.oneOf(['large', 'default', 'small']),
size: PropTypes.oneOf(tuple('large', 'default', 'small')),
value: TimeOrTimesType,
defaultValue: TimeOrTimesType,
open: PropTypes.looseBool,
@ -58,7 +54,7 @@ export const TimePickerProps = () => ({
clearText: PropTypes.string,
defaultOpenValue: PropTypes.object,
popupClassName: PropTypes.string,
popupStyle: PropTypes.object,
popupStyle: PropTypes.style,
suffixIcon: PropTypes.any,
align: PropTypes.object,
placement: PropTypes.any,
@ -76,14 +72,13 @@ export const TimePickerProps = () => ({
onBlur: PropTypes.func,
onKeydown: PropTypes.func,
onOpenChange: PropTypes.func,
'onUpdate:value': PropTypes.func,
'onUpdate:open': PropTypes.func,
});
const TimePicker = {
const TimePicker = defineComponent({
name: 'ATimePicker',
inheritAttrs: false,
mixins: [BaseMixin],
emits: ['update:value', 'update:open', 'change', 'openChange', 'focus', 'blur', 'keydown'],
props: initDefaultProps(TimePickerProps(), {
align: {
offset: [0, -2],
@ -103,6 +98,8 @@ const TimePicker = {
},
setup() {
return {
popupRef: null,
timePickerRef: null,
configProvider: inject('configProvider', defaultConfigProvider),
};
},
@ -174,14 +171,14 @@ const TimePicker = {
},
focus() {
this.timePickerRef.focus();
(this.timePickerRef as any).focus();
},
blur() {
this.timePickerRef.blur();
(this.timePickerRef as any).blur();
},
renderInputIcon(prefixCls) {
renderInputIcon(prefixCls: string) {
let suffixIcon = getComponent(this, 'suffixIcon');
suffixIcon = Array.isArray(suffixIcon) ? suffixIcon[0] : suffixIcon;
const clockIcon = (suffixIcon &&
@ -193,7 +190,7 @@ const TimePicker = {
return <span class={`${prefixCls}-icon`}>{clockIcon}</span>;
},
renderClearIcon(prefixCls) {
renderClearIcon(prefixCls: string) {
const clearIcon = getComponent(this, 'clearIcon');
const clearIconPrefixCls = `${prefixCls}-clear`;
@ -216,7 +213,7 @@ const TimePicker = {
const format = this.getDefaultFormat();
const pickerClassName = {
[className]: className,
[className as string]: className,
[`${prefixCls}-${size}`]: !!size,
};
const tempAddon = getComponent(this, 'addon', {}, false);
@ -262,10 +259,10 @@ const TimePicker = {
/>
);
},
};
});
/* istanbul ignore next */
TimePicker.install = function(app) {
TimePicker.install = function(app: App) {
app.component(TimePicker.name, TimePicker);
return app;
};

View File

@ -1,41 +1,38 @@
import { inject, cloneVNode } from 'vue';
import { inject, cloneVNode, defineComponent, ExtractPropTypes } from 'vue';
import classNames from '../_util/classNames';
import PropTypes from '../_util/vue-types';
import {
getOptionProps,
getPropsData,
initDefaultProps,
filterEmpty,
getComponent,
} from '../_util/props-util';
import TimelineItem from './TimelineItem';
import { getOptionProps, getPropsData, filterEmpty, getComponent } from '../_util/props-util';
import initDefaultProps from '../_util/props-util/initDefaultProps';
import TimelineItem, { TimeLineItemProps } from './TimelineItem';
import LoadingOutlined from '@ant-design/icons-vue/LoadingOutlined';
import { defaultConfigProvider } from '../config-provider';
import { tuple } from '../_util/type';
export const TimelineProps = {
export const timelineProps = {
prefixCls: PropTypes.string,
/** 指定最后一个幽灵节点是否存在或内容 */
pending: PropTypes.any,
pendingDot: PropTypes.string,
reverse: PropTypes.looseBool,
mode: PropTypes.oneOf(['left', 'alternate', 'right', '']),
mode: PropTypes.oneOf(tuple('left', 'alternate', 'right', '')),
};
export default {
export type TimelineProps = Partial<ExtractPropTypes<typeof timelineProps>>;
export default defineComponent({
name: 'ATimeline',
props: initDefaultProps(TimelineProps, {
props: initDefaultProps(timelineProps, {
reverse: false,
mode: '',
}),
setup() {
const configProvider = inject('configProvider', defaultConfigProvider);
return {
configProvider,
configProvider: inject('configProvider', defaultConfigProvider),
};
},
render() {
const { prefixCls: customizePrefixCls, reverse, mode } = getOptionProps(this);
const getPrefixCls = this.configProvider.getPrefixCls;
const { getPrefixCls } = this.configProvider;
const prefixCls = getPrefixCls('timeline', customizePrefixCls);
const pendingDot = getComponent(this, 'pendingDot');
@ -66,8 +63,8 @@ export default {
? [pendingItem, ...children.reverse()]
: [...children, pendingItem];
const getPositionCls = (ele, idx) => {
const eleProps = getPropsData(ele);
const getPositionCls = (ele, idx: number) => {
const eleProps = getPropsData(ele) as TimeLineItemProps;
if (mode === 'alternate') {
if (eleProps.position === 'right') return `${prefixCls}-item-right`;
if (eleProps.position === 'left') return `${prefixCls}-item-left`;
@ -94,9 +91,6 @@ export default {
});
});
const timelineProps = {
class: classString,
};
return <ul {...timelineProps}>{items}</ul>;
return <ul class={classString}>{items}</ul>;
},
};
});

View File

@ -1,32 +1,35 @@
import { inject } from 'vue';
import { defineComponent, ExtractPropTypes, inject } from 'vue';
import classNames from '../_util/classNames';
import PropTypes from '../_util/vue-types';
import { getOptionProps, initDefaultProps, getComponent } from '../_util/props-util';
import { getOptionProps, getComponent } from '../_util/props-util';
import initDefaultProps from '../_util/props-util/initDefaultProps';
import { defaultConfigProvider } from '../config-provider';
import { tuple } from '../_util/type';
export const TimeLineItemProps = {
export const timeLineItemProps = {
prefixCls: PropTypes.string,
color: PropTypes.string,
dot: PropTypes.any,
pending: PropTypes.looseBool,
position: PropTypes.oneOf(['left', 'right', '']).def(''),
position: PropTypes.oneOf(tuple('left', 'right', '')).def(''),
};
export default {
export type TimeLineItemProps = Partial<ExtractPropTypes<typeof timeLineItemProps>>;
export default defineComponent({
name: 'ATimelineItem',
props: initDefaultProps(TimeLineItemProps, {
props: initDefaultProps(timeLineItemProps, {
color: 'blue',
pending: false,
}),
setup() {
const configProvider = inject('configProvider', defaultConfigProvider);
return {
configProvider,
configProvider: inject('configProvider', defaultConfigProvider),
};
},
render() {
const { prefixCls: customizePrefixCls, color = '', pending } = getOptionProps(this);
const getPrefixCls = this.configProvider.getPrefixCls;
const { getPrefixCls } = this.configProvider;
const prefixCls = getPrefixCls('timeline', customizePrefixCls);
const dot = getComponent(this, 'dot');
@ -55,4 +58,4 @@ export default {
</li>
);
},
};
});

View File

@ -1,3 +1,4 @@
import { App } from 'vue';
import Timeline from './Timeline';
import TimelineItem from './TimelineItem';
@ -7,10 +8,12 @@ export { TimeLineItemProps } from './TimelineItem';
Timeline.Item = TimelineItem;
/* istanbul ignore next */
Timeline.install = function(app) {
Timeline.install = function(app: App) {
app.component(Timeline.name, Timeline);
app.component(TimelineItem.name, TimelineItem);
return app;
};
export default Timeline;
export default Timeline as typeof Timeline & {
readonly Item: typeof TimelineItem;
};

View File

@ -2,10 +2,11 @@ import PropTypes, { withUndefined } from '../_util/vue-types';
import classNames from '../_util/classNames';
import Lazyload from '../vc-lazy-load';
import Checkbox from '../checkbox';
import { defineComponent } from 'vue';
function noop() {}
export default {
export default defineComponent({
name: 'ListItem',
inheritAttrs: false,
props: {
@ -54,7 +55,7 @@ export default {
offset: 500,
throttle: 0,
debounce: false,
...lazy,
...(lazy as any),
};
children = <Lazyload {...lazyProps}>{listItem}</Lazyload>;
} else {
@ -62,4 +63,4 @@ export default {
}
return children;
},
};
});

View File

@ -1,15 +1,16 @@
import { inject } from 'vue';
import { App, defineComponent, inject } from 'vue';
import PropTypes from '../_util/vue-types';
import { hasProp, initDefaultProps, getOptionProps, getComponent } from '../_util/props-util';
import { hasProp, getOptionProps, getComponent } from '../_util/props-util';
import initDefaultProps from '../_util/props-util/initDefaultProps';
import BaseMixin from '../_util/BaseMixin';
import classNames from '../_util/classNames';
import List from './list';
import Operation from './operation';
import LocaleReceiver from '../locale-provider/LocaleReceiver';
import defaultLocale from '../locale-provider/default';
import { defaultConfigProvider } from '../config-provider';
import { defaultConfigProvider, RenderEmptyHandler } from '../config-provider';
export const TransferDirection = 'left' | 'right';
export type TransferDirection = 'left' | 'right';
export const TransferItem = {
key: PropTypes.string.isRequired,
@ -45,14 +46,15 @@ export const TransferProps = {
onScroll: PropTypes.func,
};
export const TransferLocale = {
titles: PropTypes.arrayOf(PropTypes.string),
notFoundContent: PropTypes.string,
itemUnit: PropTypes.string,
itemsUnit: PropTypes.string,
};
export interface TransferLocale {
titles: string[];
notFoundContent: string;
searchPlaceholder: string;
itemUnit: string;
itemsUnit: string;
}
const Transfer = {
const Transfer = defineComponent({
name: 'ATransfer',
inheritAttrs: false,
mixins: [BaseMixin],
@ -64,6 +66,9 @@ const Transfer = {
}),
setup() {
return {
selectedKeys: [],
targetKeys: [],
separatedDataSource: null,
configProvider: inject('configProvider', defaultConfigProvider),
};
},
@ -114,16 +119,16 @@ const Transfer = {
return direction === 'left' ? 'sourceSelectedKeys' : 'targetSelectedKeys';
},
getTitles(transferLocale) {
getTitles(transferLocale: TransferLocale) {
if (this.titles) {
return this.titles;
}
return transferLocale.titles || ['', ''];
},
getLocale(transferLocale, renderEmpty) {
getLocale(transferLocale: TransferLocale, renderEmpty: RenderEmptyHandler) {
// Keep old locale props still working.
const oldLocale = {
const oldLocale: { notFoundContent?: any; searchPlaceholder?: string } = {
notFoundContent: renderEmpty('Transfer'),
};
const notFoundContent = getComponent(this, 'notFoundContent');
@ -161,7 +166,7 @@ const Transfer = {
}
},
moveTo(direction) {
moveTo(direction: TransferDirection) {
const { targetKeys = [], dataSource = [] } = this.$props;
const { sourceSelectedKeys, targetSelectedKeys } = this;
const moveKeys = direction === 'right' ? sourceSelectedKeys : targetSelectedKeys;
@ -191,7 +196,7 @@ const Transfer = {
this.moveTo('right');
},
onItemSelectAll(direction, selectedKeys, checkAll) {
onItemSelectAll(direction: TransferDirection, selectedKeys: string[], checkAll: boolean) {
const originalSelectedKeys = this.$data[this.getSelectedKeysName(direction)] || [];
let mergedCheckedKeys = [];
@ -319,7 +324,7 @@ const Transfer = {
this.handleScroll('right', e);
},
handleSelectChange(direction, holder) {
handleSelectChange(direction: TransferDirection, holder: string[]) {
const { sourceSelectedKeys, targetSelectedKeys } = this;
if (direction === 'left') {
@ -361,7 +366,7 @@ const Transfer = {
};
},
renderTransfer(transferLocale) {
renderTransfer(transferLocale: TransferLocale) {
const props = getOptionProps(this);
const {
prefixCls: customizePrefixCls,
@ -478,10 +483,10 @@ const Transfer = {
/>
);
},
};
});
/* istanbul ignore next */
Transfer.install = function(app) {
Transfer.install = function(app: App) {
app.component(Transfer.name, Transfer);
return app;
};

View File

@ -1,17 +1,13 @@
import classNames from '../_util/classNames';
import PropTypes, { withUndefined } from '../_util/vue-types';
import {
isValidElement,
initDefaultProps,
splitAttrs,
findDOMNode,
filterEmpty,
} from '../_util/props-util';
import { isValidElement, splitAttrs, findDOMNode, filterEmpty } from '../_util/props-util';
import initDefaultProps from '../_util/props-util/initDefaultProps';
import BaseMixin from '../_util/BaseMixin';
import Checkbox from '../checkbox';
import Search from './search';
import defaultRenderList from './renderListBody';
import triggerEvent from '../_util/triggerEvent';
import { defineComponent } from 'vue';
const defaultRender = () => null;
@ -71,7 +67,7 @@ function renderListNode(renderList, props) {
};
}
export default {
export default defineComponent({
name: 'TransferList',
mixins: [BaseMixin],
inheritAttrs: false,
@ -81,9 +77,14 @@ export default {
showSearch: false,
lazy: {},
}),
setup() {
return {
timer: null,
triggerScrollTimer: null,
scrollEvent: null,
};
},
data() {
this.timer = null;
this.triggerScrollTimer = null;
return {
filterValue: '',
};
@ -345,4 +346,4 @@ export default {
</div>
);
},
};
});

View File

@ -1,10 +1,23 @@
import { CSSProperties, FunctionalComponent } from 'vue';
import LeftOutlined from '@ant-design/icons-vue/LeftOutlined';
import RightOutlined from '@ant-design/icons-vue/RightOutlined';
import Button from '../button';
function noop() {}
const Operation = (_, { attrs }) => {
export interface TransferOperationProps {
class?: any;
leftArrowText?: string;
rightArrowText?: string;
moveToLeft?: (e: MouseEvent) => void;
moveToRight?: (e: MouseEvent) => void;
leftActive?: boolean;
rightActive?: boolean;
style?: CSSProperties | string;
disabled?: boolean;
}
const Operation: FunctionalComponent<TransferOperationProps> = props => {
const {
disabled,
moveToLeft = noop,
@ -15,7 +28,7 @@ const Operation = (_, { attrs }) => {
rightActive,
class: className,
style,
} = attrs;
} = props;
return (
<div class={className} style={style}>
@ -40,6 +53,7 @@ const Operation = (_, { attrs }) => {
</div>
);
};
Operation.inheritAttrs = false;
export default Operation;

View File

@ -1,11 +1,11 @@
import { TransitionGroup } from 'vue';
import { defineComponent, TransitionGroup } from 'vue';
import raf from '../_util/raf';
import ListItem from './ListItem';
import PropTypes, { withUndefined } from '../_util/vue-types';
import getTransitionProps from '../_util/getTransitionProps';
import { findDOMNode } from '../_util/props-util';
function noop() {}
const ListBody = {
const ListBody = defineComponent({
name: 'ListBody',
inheritAttrs: false,
props: {
@ -18,13 +18,19 @@ const ListBody = {
onItemSelectAll: PropTypes.func,
onScroll: PropTypes.func,
},
setup() {
return {
mountId: null,
lazyId: null,
};
},
data() {
return {
mounted: false,
};
},
computed: {
itemsLength() {
itemsLength(): number {
return this.filteredRenderItems ? this.filteredRenderItems.length : 0;
},
},
@ -74,7 +80,7 @@ const ListBody = {
selectedKeys,
disabled: globalDisabled,
} = this.$props;
const items = filteredRenderItems.map(({ renderedEl, renderedText, item }) => {
const items = filteredRenderItems.map(({ renderedEl, renderedText, item }: any) => {
const { disabled } = item;
const checked = selectedKeys.indexOf(item.key) >= 0;
@ -101,11 +107,11 @@ const ListBody = {
},
);
return (
<TransitionGroup class={`${prefixCls}-content`} {...transitionProps}>
<TransitionGroup moveClass={`${prefixCls}-content`} {...transitionProps}>
{items}
</TransitionGroup>
);
},
};
});
export default props => <ListBody {...props} />;

View File

@ -1,8 +1,10 @@
import PropTypes from '../_util/vue-types';
import { initDefaultProps, getOptionProps } from '../_util/props-util';
import { getOptionProps } from '../_util/props-util';
import initDefaultProps from '../_util/props-util/initDefaultProps';
import CloseCircleFilled from '@ant-design/icons-vue/CloseCircleFilled';
import SearchOutlined from '@ant-design/icons-vue/SearchOutlined';
import Input from '../input';
import { defineComponent } from 'vue';
export const TransferSearchProps = {
prefixCls: PropTypes.string,
@ -13,7 +15,7 @@ export const TransferSearchProps = {
onChange: PropTypes.func,
};
export default {
export default defineComponent({
name: 'Search',
inheritAttrs: false,
props: initDefaultProps(TransferSearchProps, {
@ -45,7 +47,7 @@ export default {
);
return (
<div>
<>
<Input
placeholder={placeholder}
class={prefixCls}
@ -54,7 +56,7 @@ export default {
disabled={disabled}
/>
{icon}
</div>
</>
);
},
};
});

View File

@ -0,0 +1,8 @@
import '../../style/index.less';
import './index.less';
// style dependencies
import '../../empty/style';
import '../../checkbox/style';
import '../../button/style';
import '../../input/style';

View File

@ -37,7 +37,7 @@ export const TreeSelectProps = () => ({
searchValue: PropTypes.string,
showCheckedStrategy: PropTypes.oneOf(['SHOW_ALL', 'SHOW_PARENT', 'SHOW_CHILD']),
suffixIcon: PropTypes.any,
treeCheckable: PropTypes.any,
treeCheckable: PropTypes.looseBool,
treeCheckStrictly: PropTypes.looseBool,
treeData: PropTypes.arrayOf(Object),
treeDataSimpleMode: withUndefined(PropTypes.oneOfType([PropTypes.looseBool, Object])),

View File

@ -15,6 +15,7 @@ import Tooltip from '../tooltip';
import Progress from '../progress';
import classNames from '../_util/classNames';
import { UploadListProps } from './interface';
import getTransitionGroupProps from '../_util/getTransitionGroupProps';
export default {
name: 'AUploadList',
@ -265,7 +266,7 @@ export default {
[`${prefixCls}-list-${listType}`]: true,
});
const animationDirection = listType === 'picture-card' ? 'animate-inline' : 'animate';
const transitionGroupProps = getTransitionProps(`${prefixCls}-${animationDirection}`);
const transitionGroupProps = getTransitionGroupProps(`${prefixCls}-${animationDirection}`);
return (
<TransitionGroup {...transitionGroupProps} tag="div" class={listClassNames}>
{list}

View File

@ -3,8 +3,8 @@ import PropTypes from '../_util/vue-types';
import { getComponent } from '../_util/props-util';
import BaseMixin from '../_util/BaseMixin';
import createChainedFunction from '../_util/createChainedFunction';
import getTransitionProps from '../_util/getTransitionProps';
import Notice from './Notice';
import getTransitionGroupProps from '../_util/getTransitionGroupProps';
function noop() {}
@ -75,7 +75,7 @@ const Notification = defineComponent({
render() {
const { prefixCls, notices, remove, getTransitionName, $attrs } = this;
const transitionProps = getTransitionProps(getTransitionName());
const transitionProps = getTransitionGroupProps(getTransitionName());
const noticeNodes = notices.map((notice, index) => {
const update = Boolean(index === notices.length - 1 && notice.updateKey);
const key = notice.updateKey ? notice.updateKey : notice.key;

View File

@ -158,11 +158,9 @@ const SelectSelector = defineComponent<SelectorProps>({
: maxTagPlaceholder,
});
}
const transitionProps = choiceTransitionName
? getTransitionGroupProps(choiceTransitionName, {
appear: motionAppear,
})
: { css: false };
const transitionProps = getTransitionGroupProps(choiceTransitionName, {
appear: motionAppear,
})
selectionNode.value = (
<TransitionGroup {...transitionProps}>
{...displayValues.map(

View File

@ -30,10 +30,12 @@ export const selectorPropTypes = () => ({
placeholder: PropTypes.any,
disabled: PropTypes.looseBool,
focused: PropTypes.looseBool,
isMultiple: PropTypes.looseBool,
showSearch: PropTypes.looseBool,
});
function noop() {}
export default function(modeName) {
export default function() {
const BaseSelector = {
name: 'BaseSelector',
inheritAttrs: false,
@ -101,7 +103,7 @@ export default function(modeName) {
}
const clearIcon = getComponent(this, 'clearIcon');
return (
<span key="clear" class={`${prefixCls}-selection__clear`} onClick={onSelectorClear}>
<span key="clear" unselectable="on" aria-hidden="true" style="user-select: none;" class={`${prefixCls}-clear`} onClick={onSelectorClear}>
{clearIcon}
</span>
);
@ -114,7 +116,7 @@ export default function(modeName) {
}
const inputIcon = getComponent(this, 'inputIcon');
return (
<span key="arrow" class={`${prefixCls}-arrow`} style={{ outline: 'none' }}>
<span key="arrow" class={`${prefixCls}-arrow`} style={{ outline: 'none', userSelect: 'none' }}>
{inputIcon}
</span>
);
@ -132,6 +134,9 @@ export default function(modeName) {
renderSelection,
renderPlaceholder,
tabindex,
isMultiple,
showArrow,
showSearch,
} = this.$props;
const { class: className, style, onClick = noop } = this.$attrs;
const {
@ -142,18 +147,21 @@ export default function(modeName) {
if (disabled) {
myTabIndex = null;
}
const mergedClassName = classNames(prefixCls, className, {
[`${prefixCls}-focused`]: open || focused,
[`${prefixCls}-multiple`]: isMultiple,
[`${prefixCls}-single`]: !isMultiple,
[`${prefixCls}-allow-clear`]: allowClear,
[`${prefixCls}-show-arrow`]: showArrow,
[`${prefixCls}-disabled`]: disabled,
[`${prefixCls}-open`]: open,
[`${prefixCls}-show-search`]: showSearch,
});
return (
<span
<div
style={style}
onClick={onClick}
class={classNames(className, prefixCls, {
[`${prefixCls}-open`]: open,
[`${prefixCls}-focused`]: open || focused,
[`${prefixCls}-disabled`]: disabled,
[`${prefixCls}-enabled`]: !disabled,
[`${prefixCls}-allow-clear`]: allowClear,
})}
class={mergedClassName}
ref={this.domRef}
role="combobox"
aria-expanded={open}
@ -166,17 +174,13 @@ export default function(modeName) {
onBlur={this.onBlur}
onKeydown={onSelectorKeyDown}
>
<span
key="selection"
class={classNames(`${prefixCls}-selection`, `${prefixCls}-selection--${modeName}`)}
>
<span class={`${prefixCls}-selector`}>
{renderSelection()}
{this.renderClear()}
{this.renderArrow()}
{renderPlaceholder && renderPlaceholder()}
</span>
</span>
{this.renderArrow()}
{this.renderClear()}
</div>
);
},
};

View File

@ -40,7 +40,7 @@ const SinglePopup = {
display: searchValue ? 'none' : 'block',
}}
onClick={this.onPlaceholderClick}
class={`${prefixCls}-search__field__placeholder`}
class={`${prefixCls}-selection-placeholder`}
>
{searchPlaceholder}
</span>

View File

@ -4,7 +4,7 @@
* - multiple: in the selector
* Move the code as a SearchInput for easy management.
*/
import { inject, withDirectives } from 'vue';
import { inject, withDirectives, ref, onMounted, computed, watch } from 'vue';
import antInput from '../../_util/antInputDirective';
import PropTypes from '../../_util/vue-types';
import { createRef } from './util';
@ -21,8 +21,22 @@ const SearchInput = {
needAlign: PropTypes.looseBool,
ariaId: PropTypes.string,
},
setup() {
setup(props) {
const measureRef = ref();
const inputWidth = ref(0);
// We measure width and set to the input immediately
onMounted(() => {
watch(
computed(()=>props.searchValue),
() => {
inputWidth.value = measureRef.value.scrollWidth;
},
{ flush: 'post' },
);
});
return {
measureRef,
inputWidth,
vcTreeSelect: inject('vcTreeSelect', {}),
};
},
@ -38,7 +52,7 @@ const SearchInput = {
},
created() {
this.inputRef = createRef();
this.mirrorInputRef = createRef();
// this.mirrorInputRef = createRef();
this.prevProps = { ...this.$props };
},
mounted() {
@ -55,15 +69,15 @@ const SearchInput = {
},
updated() {
const { open, searchValue, needAlign } = this.$props;
const { open } = this.$props;
const { prevProps } = this;
this.$nextTick(() => {
if (open && prevProps.open !== open) {
this.focus();
}
if (needAlign && searchValue !== prevProps.searchValue) {
this.alignInputWidth();
}
// if (needAlign && searchValue !== prevProps.searchValue) {
// this.alignInputWidth();
// }
this.prevProps = { ...this.$props };
});
},
@ -73,10 +87,10 @@ const SearchInput = {
* ref: https://github.com/react-component/tree-select/issues/65
* clientWidth 0 when mounted in vue. why?
*/
alignInputWidth() {
this.inputRef.current.style.width = `${this.mirrorInputRef.current.clientWidth ||
this.mirrorInputRef.current.offsetWidth}px`;
},
// alignInputWidth() {
// this.inputRef.current.style.width = `${this.mirrorInputRef.current.clientWidth ||
// this.mirrorInputRef.current.offsetWidth}px`;
// },
/**
* Need additional timeout for focus cause parent dom is not ready when didMount trigger
@ -116,31 +130,34 @@ const SearchInput = {
vcTreeSelect: { onSearchInputKeyDown },
handleInputChange,
mirrorSearchValue,
inputWidth,
} = this;
return (
<span class={`${prefixCls}-search__field__wrap`}>
{withDirectives(
<input
type="text"
ref={this.inputRef}
onInput={handleInputChange}
onChange={handleInputChange}
onKeydown={onSearchInputKeyDown}
value={searchValue}
disabled={disabled}
class={`${prefixCls}-search__field`}
aria-label="filter select"
aria-autocomplete="list"
aria-controls={open ? ariaId : undefined}
aria-multiline="false"
/>,
[[antInput]],
)}
<span ref={this.mirrorInputRef} class={`${prefixCls}-search__field__mirror`}>
{mirrorSearchValue}&nbsp;
<>
<span class={`${prefixCls}-selection-search`} style={{ width: inputWidth + 'px' }}>
{withDirectives(
<input
type="text"
ref={this.inputRef}
onInput={handleInputChange}
onChange={handleInputChange}
onKeydown={onSearchInputKeyDown}
value={searchValue}
disabled={disabled}
class={`${prefixCls}-selection-search-input`}
aria-label="filter select"
aria-autocomplete="list"
aria-controls={open ? ariaId : undefined}
aria-multiline="false"
/>,
[[antInput]],
)}
<span ref="measureRef" class={`${prefixCls}-selection-search-mirror`} aria-hidden>
{mirrorSearchValue}&nbsp;
</span>
</span>
{renderPlaceholder && !mirrorSearchValue ? renderPlaceholder() : null}
</span>
</>
);
},
};

View File

@ -1096,7 +1096,7 @@ const Select = defineComponent({
const $popup = <Popup {...popupProps} __propsSymbol__={[]} />;
const Selector = isMultiple ? MultipleSelector : SingleSelector;
const $selector = <Selector {...passProps} ref={this.selectorRef} />;
const $selector = <Selector {...passProps} isMultiple={isMultiple} ref={this.selectorRef} />;
const selectTriggerProps = {
...passProps,
popupElement: $popup,

View File

@ -32,20 +32,20 @@ const Selection = {
}
const { class: className, style, onRemove } = this.$attrs;
return (
<li
<span
style={{ ...UNSELECTABLE_STYLE, ...style }}
{...UNSELECTABLE_ATTRIBUTE}
role="menuitem"
class={classNames(`${prefixCls}-selection__choice`, className)}
class={classNames(`${prefixCls}-selection-item`, className)}
title={toTitle(label)}
>
<span class={`${prefixCls}-selection-item-content`}>{content}</span>
{onRemove && (
<span class={`${prefixCls}-selection__choice__remove`} onClick={this.onRemove}>
<span class={`${prefixCls}-selection-item-remove`} onClick={this.onRemove}>
{getComponent(this, 'removeIcon')}
</span>
)}
<span class={`${prefixCls}-selection__choice__content`}>{content}</span>
</li>
</span>
);
},
};

View File

@ -1,11 +1,10 @@
import { inject, TransitionGroup } from 'vue';
import { inject } from 'vue';
import PropTypes from '../../../../_util/vue-types';
import { createRef } from '../../util';
import generateSelector, { selectorPropTypes } from '../../Base/BaseSelector';
import SearchInput from '../../SearchInput';
import Selection from './Selection';
import { getComponent, getSlot } from '../../../../_util/props-util';
import getTransitionProps from '../../../../_util/getTransitionProps';
import BaseMixin from '../../../../_util/BaseMixin';
const TREE_SELECT_EMPTY_VALUE_KEY = 'RC_TREE_SELECT_EMPTY_VALUE_KEY';
@ -73,7 +72,7 @@ const MultipleSelector = {
display: hidden ? 'none' : 'block',
}}
onClick={this.onPlaceholderClick}
class={`${prefixCls}-search__field__placeholder`}
class={`${prefixCls}-selection-placeholder`}
>
{currentPlaceholder}
</span>
@ -85,8 +84,6 @@ const MultipleSelector = {
renderSelection() {
const {
selectorValueList,
choiceTransitionName,
prefixCls,
labelInValue,
maxTagCount,
} = this.$props;
@ -144,7 +141,6 @@ const MultipleSelector = {
}
selectedValueNodes.push(
<li class={`${prefixCls}-search ${prefixCls}-search--inline`} key="__input">
<SearchInput
{...{
...this.$props,
@ -154,26 +150,10 @@ const MultipleSelector = {
ref={this.inputRef}
>
{children}
</SearchInput>
</li>,
);
const className = `${prefixCls}-selection__rendered`;
if (choiceTransitionName) {
const transitionProps = getTransitionProps(choiceTransitionName, {
tag: 'ul',
onAfterLeave: this.onChoiceAnimationLeave,
});
return (
<TransitionGroup class={className} {...transitionProps}>
{selectedValueNodes}
</TransitionGroup>
);
}
return (
<ul class={className} role="menubar">
{selectedValueNodes}
</ul>
</SearchInput>,
);
return selectedValueNodes;
},
},

View File

@ -21,24 +21,20 @@ const SingleSelector = {
renderSelection() {
const { selectorValueList, placeholder, prefixCls } = this.$props;
let innerNode;
if (selectorValueList.length) {
const { label, value } = selectorValueList[0];
innerNode = (
<span key="value" title={toTitle(label)} class={`${prefixCls}-selection-selected-value`}>
return (
<span key="value" title={toTitle(label)} class={`${prefixCls}-selection-item`}>
{label || value}
</span>
);
} else {
innerNode = (
<span key="placeholder" class={`${prefixCls}-selection__placeholder`}>
return (
<span key="placeholder" class={`${prefixCls}-selection-placeholder`}>
{placeholder}
</span>
);
}
return <span class={`${prefixCls}-selection__rendered`}>{innerNode}</span>;
},
},