Merge branch 'next' into v3
commit
9ce43befc4
|
@ -10,6 +10,21 @@
|
|||
|
||||
---
|
||||
|
||||
## 2.2.0-beta.3
|
||||
|
||||
`2021-06-11`
|
||||
|
||||
- 🎉 Refactor Breadcrumb, Statistic, Tag components
|
||||
- 🌟 Statistic supports loading attribute
|
||||
- 🐞 Fix the problem of Menu rendering multiple sub-components to improve performance [6ae707](https://github.com/vueComponent/ant-design-vue/commit/6ae707edf508a9c5e8dca7dacf1410de5251bcf8)
|
||||
- 🐞 Fix FormItem custom class invalidation [617e53](https://github.com/vueComponent/ant-design-vue/commit/617e534fda2ae6d468b5e9d3eb43370f8a4b0000)
|
||||
- 🐞 Fix MenuDivider class error [#4195](https://github.com/vueComponent/ant-design-vue/issues/4195)
|
||||
- 🐞 Fix Tag and Image type errors
|
||||
- 🐞 Fix the issue of missing component animations such as Modal [#4191](https://github.com/vueComponent/ant-design-vue/issues/4191)
|
||||
- 🐞 Fix the issue that Select class cannot be dynamically updated [#4194](https://github.com/vueComponent/ant-design-vue/issues/4194)
|
||||
- 🐞 Fix the problem that the Dropdown mail expands and cannot be collapsed by clicking [#4198](https://github.com/vueComponent/ant-design-vue/issues/4198)
|
||||
- 🐞 Fix the issue of missing some export methods of FormItem [#4183](https://github.com/vueComponent/ant-design-vue/issues/4183)
|
||||
|
||||
## 2.2.0-beta.2
|
||||
|
||||
`2021-06-08`
|
||||
|
|
|
@ -10,6 +10,21 @@
|
|||
|
||||
---
|
||||
|
||||
## 2.2.0-beta.3
|
||||
|
||||
`2021-06-11`
|
||||
|
||||
- 🎉 重构 Breadcrumb、Statistic、Tag 组件
|
||||
- 🌟 Statistic 支持 loading 属性
|
||||
- 🐞 修复 Menu 渲染多次子组件问题,提升性能 [6ae707](https://github.com/vueComponent/ant-design-vue/commit/6ae707edf508a9c5e8dca7dacf1410de5251bcf8)
|
||||
- 🐞 修复 FormItem 自定义 class 失效 [617e53](https://github.com/vueComponent/ant-design-vue/commit/617e534fda2ae6d468b5e9d3eb43370f8a4b0000)
|
||||
- 🐞 修复 MenuDivider class 错误问题 [#4195](https://github.com/vueComponent/ant-design-vue/issues/4195)
|
||||
- 🐞 修复 Tag、Image 类型错误
|
||||
- 🐞 修复 Modal 等组件动画丢失问题 [#4191](https://github.com/vueComponent/ant-design-vue/issues/4191)
|
||||
- 🐞 修复 Select class 不能动态更新问题 [#4194](https://github.com/vueComponent/ant-design-vue/issues/4194)
|
||||
- 🐞 修复 Dropdown 邮件展开,不能点击收起的问题 [#4198](https://github.com/vueComponent/ant-design-vue/issues/4198)
|
||||
- 🐞 修复 FormItem 缺少部分导出方法问题 [#4183](https://github.com/vueComponent/ant-design-vue/issues/4183)
|
||||
|
||||
## 2.2.0-beta.2
|
||||
|
||||
`2021-06-08`
|
||||
|
|
|
@ -139,9 +139,13 @@ const ConfigProvider = defineComponent({
|
|||
getPrefixCls: getPrefixClsWrapper,
|
||||
renderEmpty: renderEmptyComponent,
|
||||
});
|
||||
|
||||
watch(props, () => {
|
||||
Object.assign(configProvider, props);
|
||||
Object.keys(props).forEach(key => {
|
||||
watch(
|
||||
() => props[key],
|
||||
() => {
|
||||
configProvider[key] = props[key];
|
||||
},
|
||||
);
|
||||
});
|
||||
|
||||
provide('configProvider', configProvider);
|
||||
|
|
|
@ -92,7 +92,7 @@ const Dropdown = defineComponent({
|
|||
class: classNames(child?.props?.class, `${prefixCls}-trigger`),
|
||||
disabled,
|
||||
});
|
||||
const triggerActions = disabled ? [] : trigger;
|
||||
const triggerActions = disabled ? [] : typeof trigger === 'string' ? [trigger] : trigger;
|
||||
let alignPoint;
|
||||
if (triggerActions && triggerActions.indexOf('contextmenu') !== -1) {
|
||||
alignPoint = true;
|
||||
|
|
|
@ -3,8 +3,10 @@ import { PropType } from 'vue';
|
|||
import PropTypes from '../_util/vue-types';
|
||||
export default () => ({
|
||||
trigger: {
|
||||
type: Array as PropType<('click' | 'hover' | 'contextmenu')[]>,
|
||||
default: () => ['hover'],
|
||||
type: [Array, String] as PropType<
|
||||
('click' | 'hover' | 'contextmenu')[] | 'click' | 'hover' | 'contextmenu'
|
||||
>,
|
||||
default: 'hover',
|
||||
},
|
||||
overlay: PropTypes.any,
|
||||
visible: PropTypes.looseBool,
|
||||
|
|
|
@ -21,7 +21,7 @@ export default defineComponent({
|
|||
const { prefixCls, status } = useInjectFormItemPrefix();
|
||||
const visible = ref(!!(props.errors && props.errors.length));
|
||||
const innerStatus = ref(status.value);
|
||||
let timeout = ref();
|
||||
const timeout = ref();
|
||||
const cacheErrors = ref([...props.errors]);
|
||||
watch([() => [...props.errors], () => props.help], newValues => {
|
||||
window.clearTimeout(timeout.value);
|
||||
|
|
|
@ -108,7 +108,7 @@ export default defineComponent({
|
|||
__ANT_NEW_FORM_ITEM: true,
|
||||
props: formItemProps,
|
||||
slots: ['help', 'label', 'extra'],
|
||||
setup(props, { slots }) {
|
||||
setup(props, { slots, attrs, expose }) {
|
||||
warning(props.prop === undefined, `\`prop\` is deprecated. Please use \`name\` instead.`);
|
||||
const eventKey = `form-item-${++indexGuid}`;
|
||||
const { prefixCls } = useConfigInject('form', props);
|
||||
|
@ -272,6 +272,12 @@ export default defineComponent({
|
|||
control.focus();
|
||||
}
|
||||
};
|
||||
expose({
|
||||
onFieldBlur,
|
||||
onFieldChange,
|
||||
clearValidate,
|
||||
resetField,
|
||||
});
|
||||
formContext.addField(eventKey, {
|
||||
fieldValue,
|
||||
fieldId,
|
||||
|
@ -336,9 +342,11 @@ export default defineComponent({
|
|||
}
|
||||
return (
|
||||
<Row
|
||||
{...attrs}
|
||||
class={[
|
||||
itemClassName.value,
|
||||
domErrorVisible.value || !!help ? `${prefixCls.value}-item-with-help` : '',
|
||||
attrs.class,
|
||||
]}
|
||||
key="row"
|
||||
>
|
||||
|
@ -370,44 +378,4 @@ export default defineComponent({
|
|||
);
|
||||
};
|
||||
},
|
||||
// data() {
|
||||
// warning(!hasProp(this, 'prop'), `\`prop\` is deprecated. Please use \`name\` instead.`);
|
||||
// return {
|
||||
// validateState: this.validateStatus,
|
||||
// validateMessage: '',
|
||||
// validateDisabled: false,
|
||||
// validator: {},
|
||||
// helpShow: false,
|
||||
// errors: [],
|
||||
// initialValue: undefined,
|
||||
// };
|
||||
// },
|
||||
// render() {
|
||||
// const { autoLink } = getOptionProps(this);
|
||||
// const children = getSlot(this);
|
||||
// let firstChildren = children[0];
|
||||
// if (this.fieldName && autoLink && isValidElement(firstChildren)) {
|
||||
// const originalEvents = getEvents(firstChildren);
|
||||
// const originalBlur = originalEvents.onBlur;
|
||||
// const originalChange = originalEvents.onChange;
|
||||
// firstChildren = cloneElement(firstChildren, {
|
||||
// ...(this.fieldId ? { id: this.fieldId } : undefined),
|
||||
// onBlur: (...args: any[]) => {
|
||||
// originalBlur && originalBlur(...args);
|
||||
// this.onFieldBlur();
|
||||
// },
|
||||
// onChange: (...args: any[]) => {
|
||||
// if (Array.isArray(originalChange)) {
|
||||
// for (let i = 0, l = originalChange.length; i < l; i++) {
|
||||
// originalChange[i](...args);
|
||||
// }
|
||||
// } else if (originalChange) {
|
||||
// originalChange(...args);
|
||||
// }
|
||||
// this.onFieldChange();
|
||||
// },
|
||||
// });
|
||||
// }
|
||||
// return this.renderFormItem([firstChildren, children.slice(1)]);
|
||||
// },
|
||||
});
|
||||
|
|
|
@ -29,7 +29,7 @@ function parseFlex(flex: FlexType): string {
|
|||
}
|
||||
|
||||
const stringOrNumber = PropTypes.oneOfType([PropTypes.string, PropTypes.number]);
|
||||
export const colSize = PropTypes.shape({
|
||||
export const colSize = PropTypes.shape<ColSize>({
|
||||
span: stringOrNumber,
|
||||
order: stringOrNumber,
|
||||
offset: stringOrNumber,
|
||||
|
|
|
@ -1,3 +1,4 @@
|
|||
import { computed } from 'vue';
|
||||
import { Ref, inject, InjectionKey, provide, ComputedRef } from 'vue';
|
||||
|
||||
export interface RowContext {
|
||||
|
@ -13,7 +14,11 @@ const useProvideRow = (state: RowContext) => {
|
|||
};
|
||||
|
||||
const useInjectRow = () => {
|
||||
return inject(RowContextKey);
|
||||
return inject(RowContextKey, {
|
||||
gutter: computed(() => undefined),
|
||||
wrap: computed(() => undefined),
|
||||
supportFlexGap: computed(() => undefined),
|
||||
});
|
||||
};
|
||||
|
||||
export { useInjectRow, useProvideRow };
|
||||
|
|
|
@ -1,13 +1,16 @@
|
|||
import { App, defineComponent, inject, Plugin } from 'vue';
|
||||
import { App, defineComponent, ExtractPropTypes, ImgHTMLAttributes, inject, Plugin } from 'vue';
|
||||
import { defaultConfigProvider } from '../config-provider';
|
||||
import ImageInternal from '../vc-image';
|
||||
import { ImageProps, ImagePropsType } from '../vc-image/src/Image';
|
||||
|
||||
import { imageProps } from '../vc-image/src/Image';
|
||||
import PreviewGroup from './PreviewGroup';
|
||||
const Image = defineComponent({
|
||||
|
||||
export type ImageProps = Partial<
|
||||
ExtractPropTypes<typeof imageProps> & Omit<ImgHTMLAttributes, 'placeholder' | 'onClick'>
|
||||
>;
|
||||
const Image = defineComponent<ImageProps>({
|
||||
name: 'AImage',
|
||||
inheritAttrs: false,
|
||||
props: ImageProps,
|
||||
props: imageProps as any,
|
||||
setup(props, ctx) {
|
||||
const { slots, attrs } = ctx;
|
||||
const configProvider = inject('configProvider', defaultConfigProvider);
|
||||
|
@ -19,7 +22,7 @@ const Image = defineComponent({
|
|||
},
|
||||
});
|
||||
|
||||
export { ImageProps, ImagePropsType };
|
||||
export { imageProps };
|
||||
|
||||
Image.PreviewGroup = PreviewGroup;
|
||||
|
||||
|
|
|
@ -1,13 +1,12 @@
|
|||
import { defineComponent } from 'vue';
|
||||
import { useInjectMenu } from './hooks/useMenuContext';
|
||||
|
||||
export default defineComponent({
|
||||
name: 'AMenuDivider',
|
||||
props: {
|
||||
prefixCls: String,
|
||||
},
|
||||
setup(props) {
|
||||
setup() {
|
||||
const { prefixCls } = useInjectMenu();
|
||||
return () => {
|
||||
return <li class={`${props.prefixCls}-item-divider`} />;
|
||||
return <li class={`${prefixCls.value}-item-divider`} />;
|
||||
};
|
||||
},
|
||||
});
|
||||
|
|
|
@ -372,7 +372,7 @@ export default defineComponent({
|
|||
siderCollapsed,
|
||||
defaultMotions: computed(() => (isMounted.value ? defaultMotions : null)),
|
||||
motion: computed(() => (isMounted.value ? props.motion : null)),
|
||||
overflowDisabled: computed(() => props.disabledOverflow),
|
||||
overflowDisabled: computed(() => undefined),
|
||||
onOpenChange: onInternalOpenChange,
|
||||
onItemClick: onInternalClick,
|
||||
registerMenuInfo,
|
||||
|
|
|
@ -260,13 +260,13 @@ export default defineComponent({
|
|||
</div>
|
||||
);
|
||||
|
||||
if (!overflowDisabled.value) {
|
||||
if (!overflowDisabled.value && mode.value !== 'inline') {
|
||||
const triggerMode = triggerModeRef.value;
|
||||
titleNode = (
|
||||
<PopupTrigger
|
||||
mode={triggerMode}
|
||||
prefixCls={subMenuPrefixClsValue}
|
||||
visible={!props.internalPopupClose && open.value && mode.value !== 'inline'}
|
||||
visible={!props.internalPopupClose && open.value}
|
||||
popupClassName={popupClassName.value}
|
||||
popupOffset={props.popupOffset}
|
||||
disabled={mergedDisabled.value}
|
||||
|
|
|
@ -1,12 +1,12 @@
|
|||
import { computed, defineComponent, inject, ref, VNodeChild, App, PropType, Plugin } from 'vue';
|
||||
import { computed, defineComponent, ref, VNodeChild, App, PropType, Plugin } from 'vue';
|
||||
import omit from 'omit.js';
|
||||
import classNames from '../_util/classNames';
|
||||
import RcSelect, { Option, OptGroup, SelectProps as RcSelectProps, BaseProps } from '../vc-select';
|
||||
import { OptionProps as OptionPropsType } from '../vc-select/Option';
|
||||
import { defaultConfigProvider } from '../config-provider';
|
||||
import getIcons from './utils/iconUtil';
|
||||
import PropTypes from '../_util/vue-types';
|
||||
import { tuple } from '../_util/type';
|
||||
import useConfigInject from '../_util/hooks/useConfigInject';
|
||||
|
||||
type RawValue = string | number;
|
||||
|
||||
|
@ -74,11 +74,10 @@ const Select = defineComponent({
|
|||
props: SelectProps(),
|
||||
SECRET_COMBOBOX_MODE_DO_NOT_USE: 'SECRET_COMBOBOX_MODE_DO_NOT_USE',
|
||||
emits: ['change', 'update:value'],
|
||||
setup(props: any, { attrs, emit }) {
|
||||
slots: ['notFoundContent', 'suffixIcon', 'itemIcon', 'removeIcon', 'clearIcon', 'dropdownRender'],
|
||||
setup(props, { attrs, emit, slots, expose }) {
|
||||
const selectRef = ref(null);
|
||||
|
||||
const configProvider = inject('configProvider', defaultConfigProvider);
|
||||
|
||||
const focus = () => {
|
||||
if (selectRef.value) {
|
||||
selectRef.value.focus();
|
||||
|
@ -104,60 +103,37 @@ const Select = defineComponent({
|
|||
|
||||
return mode;
|
||||
});
|
||||
const prefixCls = computed(() => {
|
||||
return configProvider.getPrefixCls('select', props.prefixCls);
|
||||
});
|
||||
const { prefixCls, direction, configProvider } = useConfigInject('select', props);
|
||||
const mergedClassName = computed(() =>
|
||||
classNames(
|
||||
{
|
||||
classNames({
|
||||
[`${prefixCls.value}-lg`]: props.size === 'large',
|
||||
[`${prefixCls.value}-sm`]: props.size === 'small',
|
||||
[`${prefixCls.value}-rtl`]: props.direction === 'rtl',
|
||||
[`${prefixCls.value}-rtl`]: direction.value === 'rtl',
|
||||
[`${prefixCls.value}-borderless`]: !props.bordered,
|
||||
},
|
||||
attrs.class,
|
||||
),
|
||||
}),
|
||||
);
|
||||
const triggerChange = (...args: any[]) => {
|
||||
emit('update:value', args[0]);
|
||||
emit('change', ...args);
|
||||
};
|
||||
return {
|
||||
selectRef,
|
||||
mergedClassName,
|
||||
mode,
|
||||
focus,
|
||||
expose({
|
||||
blur,
|
||||
configProvider,
|
||||
triggerChange,
|
||||
prefixCls,
|
||||
};
|
||||
},
|
||||
render() {
|
||||
const {
|
||||
configProvider,
|
||||
mode,
|
||||
mergedClassName,
|
||||
triggerChange,
|
||||
prefixCls,
|
||||
$slots: slots,
|
||||
$props,
|
||||
} = this as any;
|
||||
const props: SelectTypes = $props;
|
||||
focus,
|
||||
});
|
||||
return () => {
|
||||
const {
|
||||
notFoundContent,
|
||||
listHeight = 256,
|
||||
listItemHeight = 24,
|
||||
getPopupContainer,
|
||||
dropdownClassName,
|
||||
direction,
|
||||
virtual,
|
||||
dropdownMatchSelectWidth,
|
||||
} = props;
|
||||
|
||||
const { renderEmpty, getPopupContainer: getContextPopupContainer } = configProvider;
|
||||
|
||||
const isMultiple = mode === 'multiple' || mode === 'tags';
|
||||
const isMultiple = mode.value === 'multiple' || mode.value === 'tags';
|
||||
|
||||
// ===================== Empty =====================
|
||||
let mergedNotFound: VNodeChild;
|
||||
|
@ -165,7 +141,7 @@ const Select = defineComponent({
|
|||
mergedNotFound = notFoundContent;
|
||||
} else if (slots.notFoundContent) {
|
||||
mergedNotFound = slots.notFoundContent();
|
||||
} else if (mode === 'combobox') {
|
||||
} else if (mode.value === 'combobox') {
|
||||
mergedNotFound = null;
|
||||
} else {
|
||||
mergedNotFound = renderEmpty('Select') as any;
|
||||
|
@ -174,9 +150,9 @@ const Select = defineComponent({
|
|||
// ===================== Icons =====================
|
||||
const { suffixIcon, itemIcon, removeIcon, clearIcon } = getIcons(
|
||||
{
|
||||
...this.$props,
|
||||
...props,
|
||||
multiple: isMultiple,
|
||||
prefixCls,
|
||||
prefixCls: prefixCls.value,
|
||||
},
|
||||
slots,
|
||||
);
|
||||
|
@ -189,37 +165,38 @@ const Select = defineComponent({
|
|||
'clearIcon',
|
||||
'size',
|
||||
'bordered',
|
||||
]) as any;
|
||||
]);
|
||||
|
||||
const rcSelectRtlDropDownClassName = classNames(dropdownClassName, {
|
||||
[`${prefixCls}-dropdown-${direction}`]: direction === 'rtl',
|
||||
[`${prefixCls.value}-dropdown-${direction.value}`]: direction.value === 'rtl',
|
||||
});
|
||||
return (
|
||||
<RcSelect
|
||||
ref="selectRef"
|
||||
ref={selectRef}
|
||||
virtual={virtual}
|
||||
dropdownMatchSelectWidth={dropdownMatchSelectWidth}
|
||||
{...selectProps}
|
||||
{...this.$attrs}
|
||||
{...attrs}
|
||||
listHeight={listHeight}
|
||||
listItemHeight={listItemHeight}
|
||||
mode={mode}
|
||||
prefixCls={prefixCls}
|
||||
direction={direction}
|
||||
mode={mode.value}
|
||||
prefixCls={prefixCls.value}
|
||||
direction={direction.value}
|
||||
inputIcon={suffixIcon}
|
||||
menuItemSelectedIcon={itemIcon}
|
||||
removeIcon={removeIcon}
|
||||
clearIcon={clearIcon}
|
||||
notFoundContent={mergedNotFound}
|
||||
class={mergedClassName}
|
||||
class={[mergedClassName.value, attrs.class]}
|
||||
getPopupContainer={getPopupContainer || getContextPopupContainer}
|
||||
dropdownClassName={rcSelectRtlDropDownClassName}
|
||||
onChange={triggerChange}
|
||||
dropdownRender={selectProps.dropdownRender || this.$slots.dropdownRender}
|
||||
dropdownRender={selectProps.dropdownRender || slots.dropdownRender}
|
||||
>
|
||||
{slots.default?.()}
|
||||
</RcSelect>
|
||||
);
|
||||
};
|
||||
},
|
||||
});
|
||||
/* istanbul ignore next */
|
||||
|
|
|
@ -1,9 +1,9 @@
|
|||
import { defineComponent } from 'vue';
|
||||
import { defineComponent, onBeforeUnmount, onMounted, onUpdated, ref } from 'vue';
|
||||
import moment from 'moment';
|
||||
import interopDefault from '../_util/interopDefault';
|
||||
import initDefaultProps from '../_util/props-util/initDefaultProps';
|
||||
import Statistic, { StatisticProps } from './Statistic';
|
||||
import { formatCountdown, countdownValueType, FormatConfig } from './utils';
|
||||
import { formatCountdown as formatCD, countdownValueType, FormatConfig } from './utils';
|
||||
|
||||
const REFRESH_INTERVAL = 1000 / 30;
|
||||
|
||||
|
@ -16,73 +16,77 @@ export default defineComponent({
|
|||
props: initDefaultProps(StatisticProps, {
|
||||
format: 'HH:mm:ss',
|
||||
}),
|
||||
setup() {
|
||||
return {
|
||||
countdownId: undefined,
|
||||
} as { countdownId: number };
|
||||
},
|
||||
mounted() {
|
||||
this.syncTimer();
|
||||
},
|
||||
|
||||
updated() {
|
||||
this.syncTimer();
|
||||
},
|
||||
|
||||
beforeUnmount() {
|
||||
this.stopTimer();
|
||||
},
|
||||
|
||||
methods: {
|
||||
syncTimer() {
|
||||
const { value } = this.$props;
|
||||
emits: ['finish', 'change'],
|
||||
setup(props, { emit }) {
|
||||
const countdownId = ref<number>();
|
||||
const statistic = ref();
|
||||
const syncTimer = () => {
|
||||
const { value } = props;
|
||||
const timestamp = getTime(value);
|
||||
if (timestamp >= Date.now()) {
|
||||
this.startTimer();
|
||||
startTimer();
|
||||
} else {
|
||||
this.stopTimer();
|
||||
stopTimer();
|
||||
}
|
||||
},
|
||||
};
|
||||
|
||||
startTimer() {
|
||||
if (this.countdownId) return;
|
||||
this.countdownId = window.setInterval(() => {
|
||||
(this.$refs.statistic as any).$forceUpdate();
|
||||
this.syncTimer();
|
||||
const startTimer = () => {
|
||||
if (countdownId.value) return;
|
||||
const timestamp = getTime(props.value);
|
||||
countdownId.value = window.setInterval(() => {
|
||||
statistic.value.$forceUpdate();
|
||||
if (timestamp > Date.now()) {
|
||||
emit('change', timestamp - Date.now());
|
||||
}
|
||||
syncTimer();
|
||||
}, REFRESH_INTERVAL);
|
||||
},
|
||||
};
|
||||
|
||||
stopTimer() {
|
||||
const { value } = this.$props;
|
||||
if (this.countdownId) {
|
||||
clearInterval(this.countdownId);
|
||||
this.countdownId = undefined;
|
||||
const stopTimer = () => {
|
||||
const { value } = props;
|
||||
if (countdownId.value) {
|
||||
clearInterval(countdownId.value);
|
||||
countdownId.value = undefined;
|
||||
|
||||
const timestamp = getTime(value);
|
||||
if (timestamp < Date.now()) {
|
||||
this.$emit('finish');
|
||||
emit('finish');
|
||||
}
|
||||
}
|
||||
},
|
||||
};
|
||||
|
||||
formatCountdown({ value, config }: { value: countdownValueType; config: FormatConfig }) {
|
||||
const { format } = this.$props;
|
||||
return formatCountdown(value, { ...config, format });
|
||||
},
|
||||
const formatCountdown = ({
|
||||
value,
|
||||
config,
|
||||
}: {
|
||||
value: countdownValueType;
|
||||
config: FormatConfig;
|
||||
}) => {
|
||||
const { format } = props;
|
||||
return formatCD(value, { ...config, format });
|
||||
};
|
||||
|
||||
valueRenderHtml: node => node,
|
||||
},
|
||||
|
||||
render() {
|
||||
const valueRenderHtml = (node: any) => node;
|
||||
onMounted(() => {
|
||||
syncTimer();
|
||||
});
|
||||
onUpdated(() => {
|
||||
syncTimer();
|
||||
});
|
||||
onBeforeUnmount(() => {
|
||||
stopTimer();
|
||||
});
|
||||
return () => {
|
||||
return (
|
||||
<Statistic
|
||||
ref="statistic"
|
||||
ref={statistic}
|
||||
{...{
|
||||
...this.$props,
|
||||
valueRender: this.valueRenderHtml,
|
||||
formatter: this.formatCountdown,
|
||||
...props,
|
||||
valueRender: valueRenderHtml,
|
||||
formatter: formatCountdown,
|
||||
}}
|
||||
/>
|
||||
);
|
||||
};
|
||||
},
|
||||
});
|
||||
|
|
|
@ -1,10 +1,10 @@
|
|||
import { defineComponent, inject, PropType } from 'vue';
|
||||
import { defineComponent, PropType } from 'vue';
|
||||
import PropTypes from '../_util/vue-types';
|
||||
import { getComponent } from '../_util/props-util';
|
||||
import initDefaultProps from '../_util/props-util/initDefaultProps';
|
||||
import { defaultConfigProvider } from '../config-provider';
|
||||
import StatisticNumber from './Number';
|
||||
import { countdownValueType } from './utils';
|
||||
import Skeleton from '../skeleton/Skeleton';
|
||||
import useConfigInject from '../_util/hooks/useConfigInject';
|
||||
|
||||
export const StatisticProps = {
|
||||
prefixCls: PropTypes.string,
|
||||
|
@ -22,6 +22,7 @@ export const StatisticProps = {
|
|||
suffix: PropTypes.VNodeChild,
|
||||
title: PropTypes.VNodeChild,
|
||||
onFinish: PropTypes.func,
|
||||
loading: PropTypes.looseBool,
|
||||
};
|
||||
|
||||
export default defineComponent({
|
||||
|
@ -29,45 +30,41 @@ export default defineComponent({
|
|||
props: initDefaultProps(StatisticProps, {
|
||||
decimalSeparator: '.',
|
||||
groupSeparator: ',',
|
||||
loading: false,
|
||||
}),
|
||||
|
||||
setup() {
|
||||
return {
|
||||
configProvider: inject('configProvider', defaultConfigProvider),
|
||||
};
|
||||
},
|
||||
|
||||
render() {
|
||||
const { prefixCls: customizePrefixCls, value = 0, valueStyle, valueRender } = this.$props;
|
||||
const { getPrefixCls } = this.configProvider;
|
||||
const prefixCls = getPrefixCls('statistic', customizePrefixCls);
|
||||
|
||||
const title = getComponent(this, 'title');
|
||||
const prefix = getComponent(this, 'prefix');
|
||||
const suffix = getComponent(this, 'suffix');
|
||||
const formatter = getComponent(this, 'formatter', {}, false);
|
||||
const props = {
|
||||
...this.$props,
|
||||
prefixCls,
|
||||
value,
|
||||
formatter,
|
||||
};
|
||||
slots: ['title', 'prefix', 'suffix', 'formatter'],
|
||||
setup(props, { slots }) {
|
||||
const { prefixCls, direction } = useConfigInject('statistic', props);
|
||||
return () => {
|
||||
const { value = 0, valueStyle, valueRender } = props;
|
||||
const pre = prefixCls.value;
|
||||
const title = props.title ?? slots.title?.();
|
||||
const prefix = props.prefix ?? slots.prefix?.();
|
||||
const suffix = props.suffix ?? slots.suffix?.();
|
||||
const formatter = props.formatter ?? slots.formatter;
|
||||
// data-for-update just for update component
|
||||
// https://github.com/vueComponent/ant-design-vue/pull/3170
|
||||
let valueNode = <StatisticNumber data-for-update={Date.now()} {...props} />;
|
||||
let valueNode = (
|
||||
<StatisticNumber
|
||||
data-for-update={Date.now()}
|
||||
{...{ ...props, prefixCls: pre, value, formatter }}
|
||||
/>
|
||||
);
|
||||
if (valueRender) {
|
||||
valueNode = valueRender(valueNode);
|
||||
}
|
||||
|
||||
return (
|
||||
<div class={prefixCls}>
|
||||
{title && <div class={`${prefixCls}-title`}>{title}</div>}
|
||||
<div style={valueStyle} class={`${prefixCls}-content`}>
|
||||
{prefix && <span class={`${prefixCls}-content-prefix`}>{prefix}</span>}
|
||||
<div class={[pre, { [`${pre}-rtl`]: direction.value === 'rtl' }]}>
|
||||
{title && <div class={`${pre}-title`}>{title}</div>}
|
||||
<Skeleton paragraph={false} loading={props.loading}>
|
||||
<div style={valueStyle} class={`${pre}-content`}>
|
||||
{prefix && <span class={`${pre}-content-prefix`}>{prefix}</span>}
|
||||
{valueNode}
|
||||
{suffix && <span class={`${prefixCls}-content-suffix`}>{suffix}</span>}
|
||||
{suffix && <span class={`${pre}-content-suffix`}>{suffix}</span>}
|
||||
</div>
|
||||
</Skeleton>
|
||||
</div>
|
||||
);
|
||||
};
|
||||
},
|
||||
});
|
||||
|
|
|
@ -7,7 +7,7 @@
|
|||
.reset-component();
|
||||
|
||||
&-title {
|
||||
margin-bottom: 4px;
|
||||
margin-bottom: @margin-xss;
|
||||
color: @text-color-secondary;
|
||||
font-size: @statistic-title-font-size;
|
||||
}
|
||||
|
@ -18,9 +18,8 @@
|
|||
font-family: @statistic-font-family;
|
||||
|
||||
&-value {
|
||||
&-decimal {
|
||||
font-size: @statistic-unit-font-size;
|
||||
}
|
||||
display: inline-block;
|
||||
direction: ltr;
|
||||
}
|
||||
|
||||
&-prefix,
|
||||
|
@ -34,7 +33,8 @@
|
|||
|
||||
&-suffix {
|
||||
margin-left: 4px;
|
||||
font-size: @statistic-unit-font-size;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@import './rtl';
|
||||
|
|
|
@ -0,0 +1,21 @@
|
|||
.@{statistic-prefix-cls} {
|
||||
&-rtl {
|
||||
direction: rtl;
|
||||
}
|
||||
|
||||
&-content {
|
||||
&-prefix {
|
||||
.@{statistic-prefix-cls}-rtl & {
|
||||
margin-right: 0;
|
||||
margin-left: 4px;
|
||||
}
|
||||
}
|
||||
|
||||
&-suffix {
|
||||
.@{statistic-prefix-cls}-rtl & {
|
||||
margin-right: 4px;
|
||||
margin-left: 0;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
|
@ -1,9 +1,6 @@
|
|||
import { VNodeTypes } from 'vue';
|
||||
import moment from 'moment';
|
||||
import padStart from 'lodash-es/padStart';
|
||||
|
||||
import interopDefault from '../_util/interopDefault';
|
||||
|
||||
export type valueType = number | string;
|
||||
export type countdownValueType = valueType | string;
|
||||
|
||||
|
@ -39,15 +36,15 @@ const timeUnits: [string, number][] = [
|
|||
export function formatTimeStr(duration: number, format: string) {
|
||||
let leftDuration: number = duration;
|
||||
|
||||
const escapeRegex = /\[[^\]]*\]/g;
|
||||
const keepList = (format.match(escapeRegex) || []).map(str => str.slice(1, -1));
|
||||
const escapeRegex = /\[[^\]]*]/g;
|
||||
const keepList: string[] = (format.match(escapeRegex) || []).map(str => str.slice(1, -1));
|
||||
const templateText = format.replace(escapeRegex, '[]');
|
||||
|
||||
const replacedText = timeUnits.reduce((current, [name, unit]) => {
|
||||
if (current.indexOf(name) !== -1) {
|
||||
const value = Math.floor(leftDuration / unit);
|
||||
leftDuration -= value * unit;
|
||||
return current.replace(new RegExp(`${name}+`, 'g'), match => {
|
||||
return current.replace(new RegExp(`${name}+`, 'g'), (match: string) => {
|
||||
const len = match.length;
|
||||
return padStart(value.toString(), len, '0');
|
||||
});
|
||||
|
@ -65,8 +62,9 @@ export function formatTimeStr(duration: number, format: string) {
|
|||
|
||||
export function formatCountdown(value: countdownValueType, config: CountdownFormatConfig) {
|
||||
const { format = '' } = config;
|
||||
const target = interopDefault(moment)(value).valueOf();
|
||||
const current = interopDefault(moment)().valueOf();
|
||||
const target = new Date(value).getTime();
|
||||
const current = Date.now();
|
||||
const diff = Math.max(target - current, 0);
|
||||
|
||||
return formatTimeStr(diff, format);
|
||||
}
|
||||
|
|
|
@ -9,6 +9,16 @@
|
|||
.@{name}-leave {
|
||||
animation-timing-function: linear;
|
||||
}
|
||||
|
||||
.make-motion(@className, @keyframeName);
|
||||
.@{className}-enter,
|
||||
.@{className}-appear {
|
||||
opacity: 0;
|
||||
animation-timing-function: linear;
|
||||
}
|
||||
.@{className}-leave {
|
||||
animation-timing-function: linear;
|
||||
}
|
||||
}
|
||||
|
||||
.fade-motion(fade, antFade);
|
||||
|
|
|
@ -9,6 +9,16 @@
|
|||
.@{name}-leave {
|
||||
animation-timing-function: @ease-in-circ;
|
||||
}
|
||||
|
||||
.make-motion(@className, @keyframeName);
|
||||
.@{className}-enter,
|
||||
.@{className}-appear {
|
||||
opacity: 0;
|
||||
animation-timing-function: @ease-out-circ;
|
||||
}
|
||||
.@{className}-leave {
|
||||
animation-timing-function: @ease-in-circ;
|
||||
}
|
||||
}
|
||||
|
||||
.move-motion(move-up, antMoveUp);
|
||||
|
|
|
@ -14,6 +14,20 @@
|
|||
.@{name}-leave {
|
||||
animation-timing-function: @ease-in-out-circ;
|
||||
}
|
||||
|
||||
.make-motion(@className, @keyframeName, @duration);
|
||||
.@{className}-enter,
|
||||
.@{className}-appear {
|
||||
transform: scale(0); // need this by yiminghe
|
||||
opacity: 0;
|
||||
animation-timing-function: @ease-out-circ;
|
||||
&-prepare {
|
||||
transform: none;
|
||||
}
|
||||
}
|
||||
.@{className}-leave {
|
||||
animation-timing-function: @ease-in-out-circ;
|
||||
}
|
||||
}
|
||||
|
||||
// For Modal, Select choosen item
|
||||
|
|
|
@ -1,7 +1,7 @@
|
|||
import { inject, defineComponent, PropType } from 'vue';
|
||||
import { defineComponent, PropType, computed } from 'vue';
|
||||
import classNames from '../_util/classNames';
|
||||
import { defaultConfigProvider } from '../config-provider';
|
||||
import PropTypes from '../_util/vue-types';
|
||||
import useConfigInject from '../_util/hooks/useConfigInject';
|
||||
|
||||
const CheckableTag = defineComponent({
|
||||
name: 'ACheckableTag',
|
||||
|
@ -17,7 +17,7 @@ const CheckableTag = defineComponent({
|
|||
},
|
||||
emits: ['update:checked', 'change', 'click'],
|
||||
setup(props, { slots, emit }) {
|
||||
const { getPrefixCls } = inject('configProvider', defaultConfigProvider);
|
||||
const { prefixCls } = useConfigInject('tag', props);
|
||||
const handleClick = (e: MouseEvent) => {
|
||||
const { checked } = props;
|
||||
emit('update:checked', !checked);
|
||||
|
@ -25,16 +25,16 @@ const CheckableTag = defineComponent({
|
|||
emit('click', e);
|
||||
};
|
||||
|
||||
return () => {
|
||||
const { checked, prefixCls: customizePrefixCls } = props;
|
||||
const prefixCls = getPrefixCls('tag', customizePrefixCls);
|
||||
const cls = classNames(prefixCls, {
|
||||
[`${prefixCls}-checkable`]: true,
|
||||
[`${prefixCls}-checkable-checked`]: checked,
|
||||
});
|
||||
const cls = computed(() =>
|
||||
classNames(prefixCls.value, {
|
||||
[`${prefixCls.value}-checkable`]: true,
|
||||
[`${prefixCls.value}-checkable-checked`]: props.checked,
|
||||
}),
|
||||
);
|
||||
|
||||
return () => {
|
||||
return (
|
||||
<span class={cls} onClick={handleClick}>
|
||||
<span class={cls.value} onClick={handleClick}>
|
||||
{slots.default?.()}
|
||||
</span>
|
||||
);
|
||||
|
|
|
@ -1,5 +1,4 @@
|
|||
import {
|
||||
inject,
|
||||
ref,
|
||||
HTMLAttributes,
|
||||
defineComponent,
|
||||
|
@ -8,6 +7,7 @@ import {
|
|||
PropType,
|
||||
ExtractPropTypes,
|
||||
Plugin,
|
||||
computed,
|
||||
} from 'vue';
|
||||
import classNames from '../_util/classNames';
|
||||
import PropTypes from '../_util/vue-types';
|
||||
|
@ -20,8 +20,8 @@ import {
|
|||
PresetStatusColorType,
|
||||
} from '../_util/colors';
|
||||
import { LiteralUnion } from '../_util/type';
|
||||
import { defaultConfigProvider } from '../config-provider';
|
||||
import CheckableTag from './CheckableTag';
|
||||
import useConfigInject from '../_util/hooks/useConfigInject';
|
||||
|
||||
const PresetColorRegex = new RegExp(`^(${PresetColorTypes.join('|')})(-inverse)?$`);
|
||||
const PresetStatusColorRegex = new RegExp(`^(${PresetStatusColorTypes.join('|')})$`);
|
||||
|
@ -46,8 +46,9 @@ const Tag = defineComponent({
|
|||
name: 'ATag',
|
||||
props: tagProps,
|
||||
emits: ['update:visible', 'close'],
|
||||
slots: ['closeIcon', 'icon'],
|
||||
setup(props: TagProps, { slots, emit, attrs }) {
|
||||
const { getPrefixCls } = inject('configProvider', defaultConfigProvider);
|
||||
const { prefixCls, direction } = useConfigInject('tag', props);
|
||||
|
||||
const visible = ref(true);
|
||||
|
||||
|
@ -70,26 +71,31 @@ const Tag = defineComponent({
|
|||
}
|
||||
};
|
||||
|
||||
const isPresetColor = (): boolean => {
|
||||
const isPresetColor = computed(() => {
|
||||
const { color } = props;
|
||||
if (!color) {
|
||||
return false;
|
||||
}
|
||||
return PresetColorRegex.test(color) || PresetStatusColorRegex.test(color);
|
||||
};
|
||||
});
|
||||
|
||||
const tagClassName = computed(() =>
|
||||
classNames(prefixCls.value, {
|
||||
[`${prefixCls.value}-${props.color}`]: isPresetColor.value,
|
||||
[`${prefixCls.value}-has-color`]: props.color && !isPresetColor.value,
|
||||
[`${prefixCls.value}-hidden`]: !visible.value,
|
||||
[`${prefixCls.value}-rtl`]: direction.value === 'rtl',
|
||||
}),
|
||||
);
|
||||
|
||||
return () => {
|
||||
const {
|
||||
prefixCls: customizePrefixCls,
|
||||
icon = slots.icon?.(),
|
||||
color,
|
||||
closeIcon = slots.closeIcon?.(),
|
||||
closable = false,
|
||||
} = props;
|
||||
|
||||
const presetColor = isPresetColor();
|
||||
const prefixCls = getPrefixCls('tag', customizePrefixCls);
|
||||
|
||||
const renderCloseIcon = () => {
|
||||
if (closable) {
|
||||
return closeIcon ? (
|
||||
|
@ -104,15 +110,9 @@ const Tag = defineComponent({
|
|||
};
|
||||
|
||||
const tagStyle = {
|
||||
backgroundColor: color && !isPresetColor() ? color : undefined,
|
||||
backgroundColor: color && !isPresetColor.value ? color : undefined,
|
||||
};
|
||||
|
||||
const tagClassName = classNames(prefixCls, {
|
||||
[`${prefixCls}-${color}`]: presetColor,
|
||||
[`${prefixCls}-has-color`]: color && !presetColor,
|
||||
[`${prefixCls}-hidden`]: !visible.value,
|
||||
});
|
||||
|
||||
const iconNode = icon || null;
|
||||
const children = slots.default?.();
|
||||
const kids = iconNode ? (
|
||||
|
@ -127,7 +127,7 @@ const Tag = defineComponent({
|
|||
const isNeedWave = 'onClick' in attrs;
|
||||
|
||||
const tagNode = (
|
||||
<span class={tagClassName} style={tagStyle}>
|
||||
<span class={tagClassName.value} style={tagStyle}>
|
||||
{kids}
|
||||
{renderCloseIcon()}
|
||||
</span>
|
||||
|
|
|
@ -16,13 +16,8 @@
|
|||
background: @tag-default-bg;
|
||||
border: @border-width-base @border-style-base @border-color-base;
|
||||
border-radius: @border-radius-base;
|
||||
cursor: default;
|
||||
opacity: 1;
|
||||
transition: all 0.3s @ease-in-out-circ;
|
||||
|
||||
&:hover {
|
||||
opacity: 0.85;
|
||||
}
|
||||
transition: all 0.3s;
|
||||
|
||||
&,
|
||||
a,
|
||||
|
@ -36,14 +31,12 @@
|
|||
padding: 0 8px;
|
||||
}
|
||||
|
||||
.@{iconfont-css-prefix}-close {
|
||||
.iconfont-size-under-12px(10px);
|
||||
|
||||
&-close-icon {
|
||||
margin-left: 3px;
|
||||
color: @text-color-secondary;
|
||||
font-weight: bold;
|
||||
font-size: 10px;
|
||||
cursor: pointer;
|
||||
transition: all 0.3s @ease-in-out-circ;
|
||||
transition: all 0.3s;
|
||||
|
||||
&:hover {
|
||||
color: @heading-color;
|
||||
|
@ -91,8 +84,9 @@
|
|||
@lightColor: '@{color}-1';
|
||||
@lightBorderColor: '@{color}-3';
|
||||
@darkColor: '@{color}-6';
|
||||
@textColor: '@{color}-7';
|
||||
&-@{color} {
|
||||
color: @@darkColor;
|
||||
color: @@textColor;
|
||||
background: @@lightColor;
|
||||
border-color: @@lightBorderColor;
|
||||
}
|
||||
|
@ -127,3 +121,5 @@
|
|||
margin-left: 7px;
|
||||
}
|
||||
}
|
||||
|
||||
@import './rtl';
|
||||
|
|
|
@ -0,0 +1,28 @@
|
|||
@import '../../style/themes/index';
|
||||
@import '../../style/mixins/index';
|
||||
|
||||
@tag-prefix-cls: ~'@{ant-prefix}-tag';
|
||||
|
||||
.@{tag-prefix-cls} {
|
||||
&&-rtl {
|
||||
margin-right: 0;
|
||||
margin-left: 8px;
|
||||
direction: rtl;
|
||||
text-align: right;
|
||||
}
|
||||
|
||||
&-close-icon {
|
||||
.@{tag-prefix-cls}-rtl & {
|
||||
margin-right: 3px;
|
||||
margin-left: 0;
|
||||
}
|
||||
}
|
||||
|
||||
> .@{iconfont-css-prefix} + span,
|
||||
> span + .@{iconfont-css-prefix} {
|
||||
.@{tag-prefix-cls}-rtl& {
|
||||
margin-right: 7px;
|
||||
margin-left: 0;
|
||||
}
|
||||
}
|
||||
}
|
|
@ -5,6 +5,7 @@ import EnterOutlined from '@ant-design/icons-vue/EnterOutlined';
|
|||
import { defineComponent, ref, reactive, watch, onMounted } from 'vue';
|
||||
|
||||
const Editable = defineComponent({
|
||||
name: 'Editable',
|
||||
props: {
|
||||
prefixCls: PropTypes.string,
|
||||
value: PropTypes.string,
|
||||
|
@ -95,6 +96,7 @@ const Editable = defineComponent({
|
|||
|
||||
function onBlur() {
|
||||
confirmChange();
|
||||
emit('end');
|
||||
}
|
||||
|
||||
function confirmChange() {
|
||||
|
|
|
@ -196,7 +196,7 @@ export default defineComponent({
|
|||
return () => {
|
||||
const child = slots?.default();
|
||||
if (child) {
|
||||
return cloneElement(child[0], { ref: nodeRef });
|
||||
return cloneElement(child[0], { ref: nodeRef }, true, true);
|
||||
}
|
||||
return child && child[0];
|
||||
};
|
||||
|
|
|
@ -25,10 +25,12 @@ export default defineComponent({
|
|||
overlayStyle: PropTypes.object.def(() => ({})),
|
||||
placement: PropTypes.string.def('bottomLeft'),
|
||||
overlay: PropTypes.any,
|
||||
trigger: PropTypes.array.def(['hover']),
|
||||
trigger: PropTypes.oneOfType([PropTypes.string, PropTypes.arrayOf(PropTypes.string)]).def(
|
||||
'hover',
|
||||
),
|
||||
alignPoint: PropTypes.looseBool,
|
||||
showAction: PropTypes.array.def([]),
|
||||
hideAction: PropTypes.array.def([]),
|
||||
showAction: PropTypes.array,
|
||||
hideAction: PropTypes.array,
|
||||
getPopupContainer: PropTypes.func,
|
||||
visible: PropTypes.looseBool,
|
||||
defaultVisible: PropTypes.looseBool.def(false),
|
||||
|
@ -175,7 +177,6 @@ export default defineComponent({
|
|||
if (!triggerHideAction && trigger.indexOf('contextmenu') !== -1) {
|
||||
triggerHideAction = ['click'];
|
||||
}
|
||||
|
||||
const triggerProps = {
|
||||
...otherProps,
|
||||
prefixCls,
|
||||
|
|
|
@ -36,7 +36,7 @@ export interface ImagePropsType extends Omit<ImgHTMLAttributes, 'placeholder' |
|
|||
fallback?: string;
|
||||
preview?: boolean | ImagePreviewType;
|
||||
}
|
||||
export const ImageProps = {
|
||||
export const imageProps = {
|
||||
src: PropTypes.string,
|
||||
wrapperClassName: PropTypes.string,
|
||||
wrapperStyle: PropTypes.style,
|
||||
|
@ -69,7 +69,7 @@ const ImageInternal = defineComponent({
|
|||
name: 'Image',
|
||||
mixins: [BaseMixin],
|
||||
inheritAttrs: false,
|
||||
props: ImageProps,
|
||||
props: imageProps,
|
||||
emits: ['click'],
|
||||
setup(props, { attrs, slots, emit }) {
|
||||
const prefixCls = computed(() => props.prefixCls);
|
||||
|
|
|
@ -131,7 +131,7 @@ const Overflow = defineComponent({
|
|||
});
|
||||
|
||||
const omittedItems = computed(() => {
|
||||
if (isResponsive) {
|
||||
if (isResponsive.value) {
|
||||
return props.data.slice(mergedDisplayCount.value + 1);
|
||||
}
|
||||
return props.data.slice(mergedData.value.length);
|
||||
|
@ -362,7 +362,7 @@ const Overflow = defineComponent({
|
|||
<Item
|
||||
{...itemSharedProps}
|
||||
order={mergedDisplayCount.value}
|
||||
class={`${itemPrefixCls}-suffix`}
|
||||
class={`${itemPrefixCls.value}-suffix`}
|
||||
registerSize={registerSuffixSize}
|
||||
display
|
||||
style={suffixStyle}
|
||||
|
|
|
@ -1,6 +1,6 @@
|
|||
{
|
||||
"name": "ant-design-vue",
|
||||
"version": "2.2.0-beta.2",
|
||||
"version": "2.2.0-beta.3",
|
||||
"title": "Ant Design Vue",
|
||||
"description": "An enterprise-class UI design language and Vue-based implementation",
|
||||
"keywords": [
|
||||
|
|
Loading…
Reference in New Issue