Merge remote-tracking branch 'origin/main' into feat-4.3
commit
e7ec210451
|
@ -10,6 +10,30 @@
|
|||
|
||||
---
|
||||
|
||||
## 4.2.5
|
||||
|
||||
- 🐞 Fix Empty component memory leak problem
|
||||
- 🐞 Fix Image width & height property not working problem
|
||||
|
||||
## 4.2.4
|
||||
|
||||
- 🐞 Fix Wave memory leak problem
|
||||
|
||||
## 4.2.3
|
||||
|
||||
- 🌟 TourStep custom Button, support function children [#7628](https://github.com/vueComponent/ant-design-vue/pull/7628)
|
||||
- 🐞 Fix the problem that the input value is hidden in Select and Cascader search multi-select mode [#7640](https://github.com/vueComponent/ant-design-vue/issues/7640)
|
||||
|
||||
## 4.2.2
|
||||
|
||||
- 🐞 Fix TreeSelect placeholder slot invalid [#7545](https://github.com/vueComponent/ant-design-vue/issues/7545)
|
||||
- 🐞 Fix Tree slot responsive invalid issue [40ad45](https://github.com/vueComponent/ant-design-vue/commit/40ad45bc05b2bf9d0a2445d9f6ff365468ba90b7)
|
||||
- 🐞 Fix FloatButton target type error issue [#7576](https://github.com/vueComponent/ant-design-vue/issues/7576)
|
||||
- 🐞 Fix FormItem className error issue [#7582](https://github.com/vueComponent/ant-design-vue/issues/7582)
|
||||
- 🐞 Fix Input Cannot input problem under lazy [#7543](https://github.com/vueComponent/ant-design-vue/issues/7543)
|
||||
- 🐞 Fix the problem that placeholder is not hidden when inputting Chinese in Select [#7611](https://github.com/vueComponent/ant-design-vue/issues/7611)
|
||||
- 🐞 Fix the problem that the pop-up window flashes when clicking the preset option in DatePicker [#7550](https://github.com/vueComponent/ant-design-vue/issues/7550)
|
||||
|
||||
## 4.2.1
|
||||
|
||||
- 🐞 fix Input clear action error [#7523](https://github.com/vueComponent/ant-design-vue/issues/7523)
|
||||
|
|
|
@ -10,6 +10,30 @@
|
|||
|
||||
---
|
||||
|
||||
## 4.2.5
|
||||
|
||||
- 🐞 修复 Empty 组件内存泄漏问题
|
||||
- 🐞 修复 Image width & height 属性不生效问题
|
||||
|
||||
## 4.2.4
|
||||
|
||||
- 🐞 修复 Wave 内存泄漏问题
|
||||
|
||||
## 4.2.3
|
||||
|
||||
- 🌟 TourStep 自定义 Button,支持函数 children [#7628](https://github.com/vueComponent/ant-design-vue/pull/7628)
|
||||
- 🐞 修复 Select 和 Cascader 搜索多选模式下,输入值被隐藏问题 [#7640](https://github.com/vueComponent/ant-design-vue/issues/7640)
|
||||
|
||||
## 4.2.2
|
||||
|
||||
- 🐞 修复 TreeSelect placeholder 插槽无效 [#7545](https://github.com/vueComponent/ant-design-vue/issues/7545)
|
||||
- 🐞 修复 Tree 插槽响应式无效问题 [40ad45](https://github.com/vueComponent/ant-design-vue/commit/40ad45bc05b2bf9d0a2445d9f6ff365468ba90b7)
|
||||
- 🐞 修复 FloatButton target 类型错误问题 [#7576](https://github.com/vueComponent/ant-design-vue/issues/7576)
|
||||
- 🐞 修复 FormItem className 错误问题 [#7582](https://github.com/vueComponent/ant-design-vue/issues/7582)
|
||||
- 🐞 修复 Input lazy 下无法输入问题 [#7543](https://github.com/vueComponent/ant-design-vue/issues/7543)
|
||||
- 🐞 修复 Select 输入中文时,placeholder 未隐藏问题 [#7611](https://github.com/vueComponent/ant-design-vue/issues/7611)
|
||||
- 🐞 修复 DatePicker 点击预设选项时,弹窗闪动问题 [#7550](https://github.com/vueComponent/ant-design-vue/issues/7550)
|
||||
|
||||
## 4.2.1
|
||||
|
||||
- 🐞 修复 Input 清空操作才报错问题 [#7523](https://github.com/vueComponent/ant-design-vue/issues/7523)
|
||||
|
|
|
@ -10,7 +10,7 @@
|
|||
|
||||
<div align="center">
|
||||
|
||||
An enterprise-class UI components based on Ant Design and Vue 3.
|
||||
基于 Ant Design 和 Vue 3 的企业级 UI 组件库。
|
||||
|
||||
 [](https://codecov.io/gh/vueComponent/ant-design-vue) [](https://www.npmjs.org/package/ant-design-vue) [](http://www.npmtrends.com/ant-design-vue) [](#backers) [](#sponsors) [](https://marketplace.visualstudio.com/items?itemName=ant-design-vue.vscode-ant-design-vue-helper) [](https://github.com/actions-cool/issues-helper)
|
||||
|
||||
|
@ -90,21 +90,21 @@ ant-design-vue 是 MIT 协议的开源项目。为了项目能够更好的持续
|
|||
- [支付宝或微信](https://aliyuncdn.antdv.com/alipay-and-wechat.png)
|
||||
- ETH: 0x30cc48515d8ae9fefa20ab87226ad7e8ab9c3bc2
|
||||
|
||||
## Sponsors
|
||||
## 赞助商
|
||||
|
||||
Become a sponsor and get your logo on our README on Github with a link to your site. [[Become a sponsor](https://opencollective.com/ant-design-vue#sponsor)]
|
||||
成为赞助商,并在 Github 上的自述文件上获得您的徽标,并链接到您的网站。 [[成为赞助商](https://opencollective.com/ant-design-vue#sponsor)]
|
||||
|
||||
<a href="http://www.jeecg.com/" target="_blank"><img src="https://aliyuncdn.antdv.com/jeecg-logo.png" height="64"></a> <a href="https://opencollective.com/ant-design-vue/sponsor/0/website" target="_blank"><img src="https://opencollective.com/ant-design-vue/sponsor/0/avatar.svg"></a> <a href="https://opencollective.com/ant-design-vue/sponsor/1/website" target="_blank"><img src="https://opencollective.com/ant-design-vue/sponsor/1/avatar.svg"></a> <a href="https://opencollective.com/ant-design-vue/sponsor/2/website" target="_blank"><img src="https://opencollective.com/ant-design-vue/sponsor/2/avatar.svg"></a> <a href="https://opencollective.com/ant-design-vue/sponsor/3/website" target="_blank"><img src="https://opencollective.com/ant-design-vue/sponsor/3/avatar.svg"></a> <a href="https://opencollective.com/ant-design-vue/sponsor/4/website" target="_blank"><img src="https://opencollective.com/ant-design-vue/sponsor/4/avatar.svg"></a> <a href="https://opencollective.com/ant-design-vue/sponsor/5/website" target="_blank"><img src="https://opencollective.com/ant-design-vue/sponsor/5/avatar.svg"></a> <a href="https://opencollective.com/ant-design-vue/sponsor/6/website" target="_blank"><img src="https://opencollective.com/ant-design-vue/sponsor/6/avatar.svg"></a> <a href="https://opencollective.com/ant-design-vue/sponsor/7/website" target="_blank"><img src="https://opencollective.com/ant-design-vue/sponsor/7/avatar.svg"></a> <a href="https://opencollective.com/ant-design-vue/sponsor/8/website" target="_blank"><img src="https://opencollective.com/ant-design-vue/sponsor/8/avatar.svg"></a> <a href="https://opencollective.com/ant-design-vue/sponsor/9/website" target="_blank"><img src="https://opencollective.com/ant-design-vue/sponsor/9/avatar.svg"></a> <a href="https://opencollective.com/ant-design-vue/sponsor/10/website" target="_blank"><img src="https://opencollective.com/ant-design-vue/sponsor/10/avatar.svg"></a>
|
||||
|
||||
## Backers
|
||||
## 支持者
|
||||
|
||||
Support us with a monthly donation and help us continue our activities. [[Become a backer](https://opencollective.com/ant-design-vue#backer)]
|
||||
每月捐款支持我们,帮助我们继续我们的活动。 [[成为支持者](https://opencollective.com/ant-design-vue#backer)]
|
||||
|
||||
<a href="https://github.com/chuzhixin/vue-admin-beautiful" target="_blank"><img width="64" style="border-radius: 50%;" src="https://gitee.com/chu1204505056/image/raw/master/vue-admin-beautiful.png" title="vue-admin-beautiful"></a> <a href="https://opencollective.com/ant-design-vue/backer/0/website" target="_blank"><img src="https://opencollective.com/ant-design-vue/backer/0/avatar.svg"></a> <a href="https://opencollective.com/ant-design-vue/backer/1/website" target="_blank"><img src="https://opencollective.com/ant-design-vue/backer/1/avatar.svg"></a> <a href="https://opencollective.com/ant-design-vue/backer/2/website" target="_blank"><img src="https://opencollective.com/ant-design-vue/backer/2/avatar.svg"></a> <a href="https://opencollective.com/ant-design-vue/backer/3/website" target="_blank"><img src="https://opencollective.com/ant-design-vue/backer/3/avatar.svg"></a> <a href="https://opencollective.com/ant-design-vue/backer/4/website" target="_blank"><img src="https://opencollective.com/ant-design-vue/backer/4/avatar.svg"></a> <a href="https://opencollective.com/ant-design-vue/backer/5/website" target="_blank"><img src="https://opencollective.com/ant-design-vue/backer/5/avatar.svg"></a> <a href="https://opencollective.com/ant-design-vue/backer/6/website" target="_blank"><img src="https://opencollective.com/ant-design-vue/backer/6/avatar.svg"></a> <a href="https://opencollective.com/ant-design-vue/backer/7/website" target="_blank"><img src="https://opencollective.com/ant-design-vue/backer/7/avatar.svg"></a> <a href="https://opencollective.com/ant-design-vue/backer/8/website" target="_blank"><img src="https://opencollective.com/ant-design-vue/backer/8/avatar.svg"></a> <a href="https://opencollective.com/ant-design-vue/backer/9/website" target="_blank"><img src="https://opencollective.com/ant-design-vue/backer/9/avatar.svg"></a> <a href="https://opencollective.com/ant-design-vue/backer/10/website" target="_blank"><img src="https://opencollective.com/ant-design-vue/backer/10/avatar.svg"></a>
|
||||
|
||||
## Patreon
|
||||
|
||||
Support us with a monthly donation and help us continue our activities. [[Become a backer](https://www.patreon.com/tangjinzhou)]
|
||||
每月捐款支持我们,帮助我们继续我们的活动。 [[成为支持者](https://www.patreon.com/tangjinzhou)]
|
||||
|
||||
<a href="https://www.mokeyjay.com" target="_blank"><img width="64" style="border-radius: 50%;" src="https://www.mokeyjay.com/headimg.png" title="donation by Patreon"></a>
|
||||
|
||||
|
|
|
@ -1,6 +1,9 @@
|
|||
import type { PropType } from 'vue';
|
||||
import { defineComponent, shallowRef, ref, watch } from 'vue';
|
||||
import { computed, defineComponent, shallowRef, ref, watch } from 'vue';
|
||||
import PropTypes from './vue-types';
|
||||
import type { BaseInputInnerExpose } from './BaseInputInner';
|
||||
import BaseInputInner from './BaseInputInner';
|
||||
import { styleObjectToString } from '../vc-util/Dom/css';
|
||||
|
||||
export interface BaseInputExpose {
|
||||
focus: () => void;
|
||||
|
@ -30,6 +33,8 @@ const BaseInput = defineComponent({
|
|||
default: 'input',
|
||||
},
|
||||
size: PropTypes.string,
|
||||
style: PropTypes.oneOfType([String, Object]),
|
||||
class: PropTypes.string,
|
||||
},
|
||||
emits: [
|
||||
'change',
|
||||
|
@ -40,9 +45,11 @@ const BaseInput = defineComponent({
|
|||
'compositionstart',
|
||||
'compositionend',
|
||||
'keyup',
|
||||
'paste',
|
||||
'mousedown',
|
||||
],
|
||||
setup(props, { emit, attrs, expose }) {
|
||||
const inputRef = shallowRef(null);
|
||||
const inputRef = shallowRef<BaseInputInnerExpose>(null);
|
||||
const renderValue = ref();
|
||||
const isComposing = ref(false);
|
||||
watch(
|
||||
|
@ -68,6 +75,7 @@ const BaseInput = defineComponent({
|
|||
const event = document.createEvent('HTMLEvents');
|
||||
event.initEvent('input', true, true);
|
||||
e.target.dispatchEvent(event);
|
||||
handleChange(e);
|
||||
};
|
||||
const handleInput = (e: Event) => {
|
||||
if (isComposing.value && props.lazy) {
|
||||
|
@ -114,19 +122,31 @@ const BaseInput = defineComponent({
|
|||
expose({
|
||||
focus,
|
||||
blur,
|
||||
input: inputRef,
|
||||
input: computed(() => inputRef.value?.input),
|
||||
setSelectionRange,
|
||||
select,
|
||||
getSelectionStart: () => inputRef.value?.selectionStart,
|
||||
getSelectionEnd: () => inputRef.value?.selectionEnd,
|
||||
getScrollTop: () => inputRef.value?.scrollTop,
|
||||
getSelectionStart: () => inputRef.value?.getSelectionStart(),
|
||||
getSelectionEnd: () => inputRef.value?.getSelectionEnd(),
|
||||
getScrollTop: () => inputRef.value?.getScrollTop(),
|
||||
});
|
||||
const handleMousedown = (e: MouseEvent) => {
|
||||
emit('mousedown', e);
|
||||
};
|
||||
const handlePaste = (e: ClipboardEvent) => {
|
||||
emit('paste', e);
|
||||
};
|
||||
const styleString = computed(() => {
|
||||
return props.style && typeof props.style !== 'string'
|
||||
? styleObjectToString(props.style)
|
||||
: props.style;
|
||||
});
|
||||
return () => {
|
||||
const { tag: Tag, ...restProps } = props;
|
||||
const { style, lazy, ...restProps } = props;
|
||||
return (
|
||||
<Tag
|
||||
<BaseInputInner
|
||||
{...restProps}
|
||||
{...attrs}
|
||||
style={styleString.value}
|
||||
onInput={handleInput}
|
||||
onChange={handleChange}
|
||||
onBlur={handleBlur}
|
||||
|
@ -137,6 +157,8 @@ const BaseInput = defineComponent({
|
|||
onCompositionend={onCompositionend}
|
||||
onKeyup={handleKeyUp}
|
||||
onKeydown={handleKeyDown}
|
||||
onPaste={handlePaste}
|
||||
onMousedown={handleMousedown}
|
||||
/>
|
||||
);
|
||||
};
|
||||
|
|
|
@ -0,0 +1,96 @@
|
|||
import type { PropType } from 'vue';
|
||||
import { defineComponent, shallowRef } from 'vue';
|
||||
import PropTypes from './vue-types';
|
||||
|
||||
export interface BaseInputInnerExpose {
|
||||
focus: () => void;
|
||||
blur: () => void;
|
||||
input: HTMLInputElement | HTMLTextAreaElement | null;
|
||||
setSelectionRange: (
|
||||
start: number,
|
||||
end: number,
|
||||
direction?: 'forward' | 'backward' | 'none',
|
||||
) => void;
|
||||
select: () => void;
|
||||
getSelectionStart: () => number | null;
|
||||
getSelectionEnd: () => number | null;
|
||||
getScrollTop: () => number | null;
|
||||
setScrollTop: (scrollTop: number) => void;
|
||||
}
|
||||
const BaseInputInner = defineComponent({
|
||||
compatConfig: { MODE: 3 },
|
||||
// inheritAttrs: false,
|
||||
props: {
|
||||
disabled: PropTypes.looseBool,
|
||||
type: PropTypes.string,
|
||||
value: PropTypes.any,
|
||||
tag: {
|
||||
type: String as PropType<'input' | 'textarea'>,
|
||||
default: 'input',
|
||||
},
|
||||
size: PropTypes.string,
|
||||
onChange: Function as PropType<(e: Event) => void>,
|
||||
onInput: Function as PropType<(e: Event) => void>,
|
||||
onBlur: Function as PropType<(e: Event) => void>,
|
||||
onFocus: Function as PropType<(e: Event) => void>,
|
||||
onKeydown: Function as PropType<(e: Event) => void>,
|
||||
onCompositionstart: Function as PropType<(e: Event) => void>,
|
||||
onCompositionend: Function as PropType<(e: Event) => void>,
|
||||
onKeyup: Function as PropType<(e: Event) => void>,
|
||||
onPaste: Function as PropType<(e: Event) => void>,
|
||||
onMousedown: Function as PropType<(e: Event) => void>,
|
||||
},
|
||||
emits: [
|
||||
'change',
|
||||
'input',
|
||||
'blur',
|
||||
'keydown',
|
||||
'focus',
|
||||
'compositionstart',
|
||||
'compositionend',
|
||||
'keyup',
|
||||
'paste',
|
||||
'mousedown',
|
||||
],
|
||||
setup(props, { expose }) {
|
||||
const inputRef = shallowRef(null);
|
||||
|
||||
const focus = () => {
|
||||
if (inputRef.value) {
|
||||
inputRef.value.focus();
|
||||
}
|
||||
};
|
||||
const blur = () => {
|
||||
if (inputRef.value) {
|
||||
inputRef.value.blur();
|
||||
}
|
||||
};
|
||||
const setSelectionRange = (
|
||||
start: number,
|
||||
end: number,
|
||||
direction?: 'forward' | 'backward' | 'none',
|
||||
) => {
|
||||
inputRef.value?.setSelectionRange(start, end, direction);
|
||||
};
|
||||
|
||||
const select = () => {
|
||||
inputRef.value?.select();
|
||||
};
|
||||
expose({
|
||||
focus,
|
||||
blur,
|
||||
input: inputRef,
|
||||
setSelectionRange,
|
||||
select,
|
||||
getSelectionStart: () => inputRef.value?.selectionStart,
|
||||
getSelectionEnd: () => inputRef.value?.selectionEnd,
|
||||
getScrollTop: () => inputRef.value?.scrollTop,
|
||||
});
|
||||
return () => {
|
||||
const { tag: Tag, value, ...restProps } = props;
|
||||
return <Tag {...restProps} ref={inputRef} value={value} />;
|
||||
};
|
||||
},
|
||||
});
|
||||
|
||||
export default BaseInputInner;
|
|
@ -1,130 +0,0 @@
|
|||
const START_EVENT_NAME_MAP = {
|
||||
transitionstart: {
|
||||
transition: 'transitionstart',
|
||||
WebkitTransition: 'webkitTransitionStart',
|
||||
MozTransition: 'mozTransitionStart',
|
||||
OTransition: 'oTransitionStart',
|
||||
msTransition: 'MSTransitionStart',
|
||||
},
|
||||
|
||||
animationstart: {
|
||||
animation: 'animationstart',
|
||||
WebkitAnimation: 'webkitAnimationStart',
|
||||
MozAnimation: 'mozAnimationStart',
|
||||
OAnimation: 'oAnimationStart',
|
||||
msAnimation: 'MSAnimationStart',
|
||||
},
|
||||
};
|
||||
|
||||
const END_EVENT_NAME_MAP = {
|
||||
transitionend: {
|
||||
transition: 'transitionend',
|
||||
WebkitTransition: 'webkitTransitionEnd',
|
||||
MozTransition: 'mozTransitionEnd',
|
||||
OTransition: 'oTransitionEnd',
|
||||
msTransition: 'MSTransitionEnd',
|
||||
},
|
||||
|
||||
animationend: {
|
||||
animation: 'animationend',
|
||||
WebkitAnimation: 'webkitAnimationEnd',
|
||||
MozAnimation: 'mozAnimationEnd',
|
||||
OAnimation: 'oAnimationEnd',
|
||||
msAnimation: 'MSAnimationEnd',
|
||||
},
|
||||
};
|
||||
|
||||
const startEvents = [];
|
||||
const endEvents = [];
|
||||
|
||||
function detectEvents() {
|
||||
const testEl = document.createElement('div');
|
||||
const style = testEl.style;
|
||||
|
||||
if (!('AnimationEvent' in window)) {
|
||||
delete START_EVENT_NAME_MAP.animationstart.animation;
|
||||
delete END_EVENT_NAME_MAP.animationend.animation;
|
||||
}
|
||||
|
||||
if (!('TransitionEvent' in window)) {
|
||||
delete START_EVENT_NAME_MAP.transitionstart.transition;
|
||||
delete END_EVENT_NAME_MAP.transitionend.transition;
|
||||
}
|
||||
|
||||
function process(EVENT_NAME_MAP, events) {
|
||||
for (const baseEventName in EVENT_NAME_MAP) {
|
||||
if (EVENT_NAME_MAP.hasOwnProperty(baseEventName)) {
|
||||
const baseEvents = EVENT_NAME_MAP[baseEventName];
|
||||
for (const styleName in baseEvents) {
|
||||
if (styleName in style) {
|
||||
events.push(baseEvents[styleName]);
|
||||
break;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
process(START_EVENT_NAME_MAP, startEvents);
|
||||
process(END_EVENT_NAME_MAP, endEvents);
|
||||
}
|
||||
|
||||
if (typeof window !== 'undefined' && typeof document !== 'undefined') {
|
||||
detectEvents();
|
||||
}
|
||||
|
||||
function addEventListener(node, eventName, eventListener) {
|
||||
node.addEventListener(eventName, eventListener, false);
|
||||
}
|
||||
|
||||
function removeEventListener(node, eventName, eventListener) {
|
||||
node.removeEventListener(eventName, eventListener, false);
|
||||
}
|
||||
|
||||
const TransitionEvents = {
|
||||
// Start events
|
||||
startEvents,
|
||||
|
||||
addStartEventListener(node, eventListener) {
|
||||
if (startEvents.length === 0) {
|
||||
setTimeout(eventListener, 0);
|
||||
return;
|
||||
}
|
||||
startEvents.forEach(startEvent => {
|
||||
addEventListener(node, startEvent, eventListener);
|
||||
});
|
||||
},
|
||||
|
||||
removeStartEventListener(node, eventListener) {
|
||||
if (startEvents.length === 0) {
|
||||
return;
|
||||
}
|
||||
startEvents.forEach(startEvent => {
|
||||
removeEventListener(node, startEvent, eventListener);
|
||||
});
|
||||
},
|
||||
|
||||
// End events
|
||||
endEvents,
|
||||
|
||||
addEndEventListener(node, eventListener) {
|
||||
if (endEvents.length === 0) {
|
||||
setTimeout(eventListener, 0);
|
||||
return;
|
||||
}
|
||||
endEvents.forEach(endEvent => {
|
||||
addEventListener(node, endEvent, eventListener);
|
||||
});
|
||||
},
|
||||
|
||||
removeEndEventListener(node, eventListener) {
|
||||
if (endEvents.length === 0) {
|
||||
return;
|
||||
}
|
||||
endEvents.forEach(endEvent => {
|
||||
removeEventListener(node, endEvent, eventListener);
|
||||
});
|
||||
},
|
||||
};
|
||||
|
||||
export default TransitionEvents;
|
|
@ -1,186 +0,0 @@
|
|||
// https://github.com/yiminghe/css-animation 1.5.0
|
||||
|
||||
import Event from './Event';
|
||||
import classes from '../component-classes';
|
||||
import { requestAnimationTimeout, cancelAnimationTimeout } from '../requestAnimationTimeout';
|
||||
import { inBrowser } from '../env';
|
||||
|
||||
const isCssAnimationSupported = Event.endEvents.length !== 0;
|
||||
const capitalPrefixes = [
|
||||
'Webkit',
|
||||
'Moz',
|
||||
'O',
|
||||
// ms is special .... !
|
||||
'ms',
|
||||
];
|
||||
const prefixes = ['-webkit-', '-moz-', '-o-', 'ms-', ''];
|
||||
|
||||
function getStyleProperty(node, name) {
|
||||
if (inBrowser) return '';
|
||||
// old ff need null, https://developer.mozilla.org/en-US/docs/Web/API/Window/getComputedStyle
|
||||
const style = window.getComputedStyle(node, null);
|
||||
let ret = '';
|
||||
for (let i = 0; i < prefixes.length; i++) {
|
||||
ret = style.getPropertyValue(prefixes[i] + name);
|
||||
if (ret) {
|
||||
break;
|
||||
}
|
||||
}
|
||||
return ret;
|
||||
}
|
||||
|
||||
function fixBrowserByTimeout(node) {
|
||||
if (isCssAnimationSupported) {
|
||||
const transitionDelay = parseFloat(getStyleProperty(node, 'transition-delay')) || 0;
|
||||
const transitionDuration = parseFloat(getStyleProperty(node, 'transition-duration')) || 0;
|
||||
const animationDelay = parseFloat(getStyleProperty(node, 'animation-delay')) || 0;
|
||||
const animationDuration = parseFloat(getStyleProperty(node, 'animation-duration')) || 0;
|
||||
const time = Math.max(transitionDuration + transitionDelay, animationDuration + animationDelay);
|
||||
// sometimes, browser bug
|
||||
node.rcEndAnimTimeout = setTimeout(() => {
|
||||
node.rcEndAnimTimeout = null;
|
||||
if (node.rcEndListener) {
|
||||
node.rcEndListener();
|
||||
}
|
||||
}, time * 1000 + 200);
|
||||
}
|
||||
}
|
||||
|
||||
function clearBrowserBugTimeout(node) {
|
||||
if (node.rcEndAnimTimeout) {
|
||||
clearTimeout(node.rcEndAnimTimeout);
|
||||
node.rcEndAnimTimeout = null;
|
||||
}
|
||||
}
|
||||
|
||||
const cssAnimation = (node, transitionName, endCallback) => {
|
||||
const nameIsObj = typeof transitionName === 'object';
|
||||
const className = nameIsObj ? transitionName.name : transitionName;
|
||||
const activeClassName = nameIsObj ? transitionName.active : `${transitionName}-active`;
|
||||
let end = endCallback;
|
||||
let start;
|
||||
let active;
|
||||
const nodeClasses = classes(node);
|
||||
|
||||
if (endCallback && Object.prototype.toString.call(endCallback) === '[object Object]') {
|
||||
end = endCallback.end;
|
||||
start = endCallback.start;
|
||||
active = endCallback.active;
|
||||
}
|
||||
|
||||
if (node.rcEndListener) {
|
||||
node.rcEndListener();
|
||||
}
|
||||
|
||||
node.rcEndListener = e => {
|
||||
if (e && e.target !== node) {
|
||||
return;
|
||||
}
|
||||
|
||||
if (node.rcAnimTimeout) {
|
||||
cancelAnimationTimeout(node.rcAnimTimeout);
|
||||
node.rcAnimTimeout = null;
|
||||
}
|
||||
|
||||
clearBrowserBugTimeout(node);
|
||||
|
||||
nodeClasses.remove(className);
|
||||
nodeClasses.remove(activeClassName);
|
||||
|
||||
Event.removeEndEventListener(node, node.rcEndListener);
|
||||
node.rcEndListener = null;
|
||||
|
||||
// Usually this optional end is used for informing an owner of
|
||||
// a leave animation and telling it to remove the child.
|
||||
if (end) {
|
||||
end();
|
||||
}
|
||||
};
|
||||
|
||||
Event.addEndEventListener(node, node.rcEndListener);
|
||||
|
||||
if (start) {
|
||||
start();
|
||||
}
|
||||
nodeClasses.add(className);
|
||||
|
||||
node.rcAnimTimeout = requestAnimationTimeout(() => {
|
||||
node.rcAnimTimeout = null;
|
||||
|
||||
nodeClasses.add(className);
|
||||
nodeClasses.add(activeClassName);
|
||||
|
||||
if (active) {
|
||||
requestAnimationTimeout(active, 0);
|
||||
}
|
||||
fixBrowserByTimeout(node);
|
||||
// 30ms for firefox
|
||||
}, 30);
|
||||
|
||||
return {
|
||||
stop() {
|
||||
if (node.rcEndListener) {
|
||||
node.rcEndListener();
|
||||
}
|
||||
},
|
||||
};
|
||||
};
|
||||
|
||||
cssAnimation.style = (node, style, callback) => {
|
||||
if (node.rcEndListener) {
|
||||
node.rcEndListener();
|
||||
}
|
||||
|
||||
node.rcEndListener = e => {
|
||||
if (e && e.target !== node) {
|
||||
return;
|
||||
}
|
||||
|
||||
if (node.rcAnimTimeout) {
|
||||
cancelAnimationTimeout(node.rcAnimTimeout);
|
||||
node.rcAnimTimeout = null;
|
||||
}
|
||||
|
||||
clearBrowserBugTimeout(node);
|
||||
|
||||
Event.removeEndEventListener(node, node.rcEndListener);
|
||||
node.rcEndListener = null;
|
||||
|
||||
// Usually this optional callback is used for informing an owner of
|
||||
// a leave animation and telling it to remove the child.
|
||||
if (callback) {
|
||||
callback();
|
||||
}
|
||||
};
|
||||
|
||||
Event.addEndEventListener(node, node.rcEndListener);
|
||||
|
||||
node.rcAnimTimeout = requestAnimationTimeout(() => {
|
||||
for (const s in style) {
|
||||
if (style.hasOwnProperty(s)) {
|
||||
node.style[s] = style[s];
|
||||
}
|
||||
}
|
||||
node.rcAnimTimeout = null;
|
||||
fixBrowserByTimeout(node);
|
||||
}, 0);
|
||||
};
|
||||
|
||||
cssAnimation.setTransition = (node, p, value) => {
|
||||
let property = p;
|
||||
let v = value;
|
||||
if (value === undefined) {
|
||||
v = property;
|
||||
property = '';
|
||||
}
|
||||
property = property || '';
|
||||
capitalPrefixes.forEach(prefix => {
|
||||
node.style[`${prefix}Transition${property}`] = v;
|
||||
});
|
||||
};
|
||||
|
||||
cssAnimation.isCssAnimationSupported = isCssAnimationSupported;
|
||||
|
||||
export { isCssAnimationSupported };
|
||||
|
||||
export default cssAnimation;
|
|
@ -1,24 +0,0 @@
|
|||
let animation;
|
||||
|
||||
function isCssAnimationSupported() {
|
||||
if (animation !== undefined) {
|
||||
return animation;
|
||||
}
|
||||
const domPrefixes = 'Webkit Moz O ms Khtml'.split(' ');
|
||||
const elm = document.createElement('div');
|
||||
if (elm.style.animationName !== undefined) {
|
||||
animation = true;
|
||||
}
|
||||
if (animation !== undefined) {
|
||||
for (let i = 0; i < domPrefixes.length; i++) {
|
||||
if (elm.style[`${domPrefixes[i]}AnimationName`] !== undefined) {
|
||||
animation = true;
|
||||
break;
|
||||
}
|
||||
}
|
||||
}
|
||||
animation = animation || false;
|
||||
return animation;
|
||||
}
|
||||
|
||||
export default isCssAnimationSupported;
|
|
@ -5,7 +5,7 @@ import type {
|
|||
TransitionGroupProps,
|
||||
TransitionProps,
|
||||
} from 'vue';
|
||||
import { nextTick, Transition, TransitionGroup } from 'vue';
|
||||
import { nextTick } from 'vue';
|
||||
import { tuple } from './type';
|
||||
|
||||
const SelectPlacements = tuple('bottomLeft', 'bottomRight', 'topLeft', 'topRight');
|
||||
|
@ -126,6 +126,4 @@ const getTransitionName = (rootPrefixCls: string, motion: string, transitionName
|
|||
return `${rootPrefixCls}-${motion}`;
|
||||
};
|
||||
|
||||
export { Transition, TransitionGroup, collapseMotion, getTransitionName, getTransitionDirection };
|
||||
|
||||
export default Transition;
|
||||
export { collapseMotion, getTransitionName, getTransitionDirection };
|
||||
|
|
|
@ -159,6 +159,12 @@ function showWaveEffect(node: HTMLElement, className: string) {
|
|||
node?.insertBefore(holder, node?.firstChild);
|
||||
|
||||
render(<WaveEffect target={node} className={className} />, holder);
|
||||
return () => {
|
||||
render(null, holder);
|
||||
if (holder.parentElement) {
|
||||
holder.parentElement.removeChild(holder);
|
||||
}
|
||||
};
|
||||
}
|
||||
|
||||
export default showWaveEffect;
|
||||
|
|
|
@ -33,13 +33,12 @@ export default defineComponent({
|
|||
|
||||
// =============================== Wave ===============================
|
||||
const showWave = useWave(
|
||||
instance,
|
||||
computed(() => classNames(prefixCls.value, hashId.value)),
|
||||
wave,
|
||||
);
|
||||
let onClick: (e: MouseEvent) => void;
|
||||
const clear = () => {
|
||||
const node = findDOMNode(instance);
|
||||
const node = findDOMNode(instance) as HTMLElement;
|
||||
node.removeEventListener('click', onClick, true);
|
||||
};
|
||||
onMounted(() => {
|
||||
|
|
|
@ -1,21 +1,25 @@
|
|||
import type { ComponentInternalInstance, ComputedRef, Ref } from 'vue';
|
||||
import type { ComputedRef, Ref } from 'vue';
|
||||
import { onBeforeUnmount, getCurrentInstance } from 'vue';
|
||||
import { findDOMNode } from '../props-util';
|
||||
import showWaveEffect from './WaveEffect';
|
||||
|
||||
export default function useWave(
|
||||
instance: ComponentInternalInstance | null,
|
||||
className: Ref<string>,
|
||||
wave?: ComputedRef<{ disabled?: boolean }>,
|
||||
): VoidFunction {
|
||||
const instance = getCurrentInstance();
|
||||
let stopWave: () => void;
|
||||
function showWave() {
|
||||
const node = findDOMNode(instance);
|
||||
|
||||
stopWave?.();
|
||||
if (wave?.value?.disabled || !node) {
|
||||
return;
|
||||
}
|
||||
|
||||
showWaveEffect(node, className.value);
|
||||
stopWave = showWaveEffect(node, className.value);
|
||||
}
|
||||
onBeforeUnmount(() => {
|
||||
stopWave?.();
|
||||
});
|
||||
|
||||
return showWave;
|
||||
}
|
||||
|
|
|
@ -1,5 +1,5 @@
|
|||
import type { CSSProperties, ExtractPropTypes, PropType } from 'vue';
|
||||
import { computed, defineComponent, shallowRef } from 'vue';
|
||||
import { computed, defineComponent, shallowRef, Transition } from 'vue';
|
||||
import CloseOutlined from '@ant-design/icons-vue/CloseOutlined';
|
||||
import CheckCircleOutlined from '@ant-design/icons-vue/CheckCircleOutlined';
|
||||
import ExclamationCircleOutlined from '@ant-design/icons-vue/ExclamationCircleOutlined';
|
||||
|
@ -11,7 +11,7 @@ import InfoCircleFilled from '@ant-design/icons-vue/InfoCircleFilled';
|
|||
import CloseCircleFilled from '@ant-design/icons-vue/CloseCircleFilled';
|
||||
import classNames from '../_util/classNames';
|
||||
import PropTypes from '../_util/vue-types';
|
||||
import { getTransitionProps, Transition } from '../_util/transition';
|
||||
import { getTransitionProps } from '../_util/transition';
|
||||
import { isValidElement } from '../_util/props-util';
|
||||
import { tuple, withInstall } from '../_util/type';
|
||||
import { cloneElement } from '../_util/vnode';
|
||||
|
|
|
@ -3,9 +3,9 @@ import ScrollNumber from './ScrollNumber';
|
|||
import classNames from '../_util/classNames';
|
||||
import { getPropsSlot, flattenChildren } from '../_util/props-util';
|
||||
import { cloneElement } from '../_util/vnode';
|
||||
import { getTransitionProps, Transition } from '../_util/transition';
|
||||
import { getTransitionProps } from '../_util/transition';
|
||||
import type { ExtractPropTypes, CSSProperties, PropType } from 'vue';
|
||||
import { defineComponent, computed, ref, watch } from 'vue';
|
||||
import { defineComponent, computed, ref, watch, Transition } from 'vue';
|
||||
import Ribbon from './Ribbon';
|
||||
import useConfigInject from '../config-provider/hooks/useConfigInject';
|
||||
import isNumeric from '../_util/isNumeric';
|
||||
|
|
|
@ -1,6 +1,5 @@
|
|||
import { defineComponent, nextTick } from 'vue';
|
||||
import { defineComponent, nextTick, Transition } from 'vue';
|
||||
import LoadingOutlined from '@ant-design/icons-vue/LoadingOutlined';
|
||||
import Transition from '../_util/transition';
|
||||
const getCollapsedWidth = (node: HTMLSpanElement) => {
|
||||
if (node) {
|
||||
node.style.width = '0px';
|
||||
|
|
|
@ -28,16 +28,16 @@ coverDark: https://mdn.alipayobjects.com/huamei_7uahnr/afts/img/A*-p-wQLik200AAA
|
|||
|
||||
| 参数 | 说明 | 类型 | 默认值 | 版本 |
|
||||
| --- | --- | --- | --- | --- |
|
||||
| dateCellRender | 作用域插槽,用来自定义渲染日期单元格,返回内容会被追加到单元格, | v-slot:dateCellRender="{current: dayjs}" | 无 | |
|
||||
| dateFullCellRender | 作用域插槽,自定义渲染日期单元格,返回内容覆盖单元格 | v-slot:dateFullCellRender="{current: dayjs}" | 无 | |
|
||||
| disabledDate | 不可选择的日期 | (currentDate: dayjs) => boolean | 无 | |
|
||||
| dateCellRender | 作用域插槽,用来自定义渲染日期单元格,返回内容会被追加到单元格, | v-slot:dateCellRender="{current: dayjs}" | - | |
|
||||
| dateFullCellRender | 作用域插槽,自定义渲染日期单元格,返回内容覆盖单元格 | v-slot:dateFullCellRender="{current: dayjs}" | - | |
|
||||
| disabledDate | 不可选择的日期 | (currentDate: dayjs) => boolean | - | |
|
||||
| fullscreen | 是否全屏显示 | boolean | true | |
|
||||
| headerRender | 自定义头部内容 | v-slot:headerRender="{value: dayjs, type: string, onChange: f(), onTypeChange: f()}" | - | |
|
||||
| locale | 国际化配置 | object | [默认配置](https://github.com/vueComponent/ant-design-vue/blob/main/components/date-picker/locale/example.json) | |
|
||||
| mode | 初始模式,`month/year` | string | month | |
|
||||
| monthCellRender | 作用域插槽,自定义渲染月单元格,返回内容会被追加到单元格 | v-slot:monthCellRender="{current: dayjs}" | 无 | |
|
||||
| monthFullCellRender | 作用域插槽,自定义渲染月单元格,返回内容覆盖单元格 | v-slot:monthFullCellRender="{current: dayjs}" | 无 | |
|
||||
| validRange | 设置可以显示的日期 | \[[dayjs](https://day.js.org/), [dayjs](https://day.js.org/)] | 无 | |
|
||||
| monthCellRender | 作用域插槽,自定义渲染月单元格,返回内容会被追加到单元格 | v-slot:monthCellRender="{current: dayjs}" | - | |
|
||||
| monthFullCellRender | 作用域插槽,自定义渲染月单元格,返回内容覆盖单元格 | v-slot:monthFullCellRender="{current: dayjs}" | - | |
|
||||
| validRange | 设置可以显示的日期 | \[[dayjs](https://day.js.org/), [dayjs](https://day.js.org/)] | - | |
|
||||
| value(v-model) | 展示日期 | [dayjs](https://day.js.org/) | 当前日期 | |
|
||||
| valueFormat | 可选,绑定值的格式,对 value、defaultValue 起作用。不指定则绑定值为 dayjs 对象 | string,[具体格式](https://day.js.org/docs/zh-CN/display/format) | - | |
|
||||
|
||||
|
@ -45,8 +45,8 @@ coverDark: https://mdn.alipayobjects.com/huamei_7uahnr/afts/img/A*-p-wQLik200AAA
|
|||
|
||||
| 事件名称 | 说明 | 回调参数 | |
|
||||
| --- | --- | --- | --- | --- |
|
||||
| change | 日期变化时的回调, 面板变化有可能导致日期变化 | function(date: dayjs \| string) | 无 |
|
||||
| panelChange | 日期面板变化回调 | function(date: dayjs \| string, mode: string) | 无 |
|
||||
| change | 日期变化时的回调, 面板变化有可能导致日期变化 | function(date: dayjs \| string) | - |
|
||||
| panelChange | 日期面板变化回调 | function(date: dayjs \| string, mode: string) | - |
|
||||
| select | 选择日期回调,包含来源信息 | function(date: Dayjs, info: { source: 'year' \| 'month' \| 'date' \| 'customize' }) | - | |
|
||||
|
||||
### 如何仅获取来自面板点击的日期?
|
||||
|
|
|
@ -2,8 +2,7 @@ import PanelContent from './PanelContent';
|
|||
import { initDefaultProps } from '../_util/props-util';
|
||||
import { collapsePanelProps } from './commonProps';
|
||||
import type { ExtractPropTypes } from 'vue';
|
||||
import { defineComponent } from 'vue';
|
||||
import Transition from '../_util/transition';
|
||||
import { defineComponent, Transition } from 'vue';
|
||||
import classNames from '../_util/classNames';
|
||||
import devWarning from '../vc-util/devWarning';
|
||||
import useConfigInject from '../config-provider/hooks/useConfigInject';
|
||||
|
|
|
@ -20,7 +20,7 @@ A content area which can be collapsed and expanded.
|
|||
| Property | Description | Type | Default | Version |
|
||||
| --- | --- | --- | --- | --- |
|
||||
| accordion | If `true`, `Collapse` renders as `Accordion` | boolean | `false` | |
|
||||
| activeKey(v-model) | Key of the active panel | string\[] \| string <br> number\[] \| number | No default value. In `accordion` mode, it's the key of the first panel. | |
|
||||
| activeKey(v-model) | Key of the active panel | string\[] \| string <br> number\[] \| number | No default value. In [accordion mode](#components-collapse-demo-accordion), it's the key of the first panel. | |
|
||||
| bordered | Toggles rendering of the border around the collapse block | boolean | `true` | |
|
||||
| collapsible | Specify whether the panels of children be collapsible or the trigger area of collapsible | `header` \| `icon` \| `disabled` | - | 4.0 |
|
||||
| destroyInactivePanel | Destroy Inactive Panel | boolean | `false` | |
|
||||
|
|
|
@ -20,8 +20,8 @@ coverDark: https://mdn.alipayobjects.com/huamei_7uahnr/afts/img/A*sir-TK0HkWcAAA
|
|||
|
||||
| 参数 | 说明 | 类型 | 默认值 | 版本 |
|
||||
| --- | --- | --- | --- | --- |
|
||||
| accordion | 手风琴模式 | boolean | `false` | |
|
||||
| activeKey(v-model) | 当前激活 tab 面板的 key | string\[] \| string <br> number\[] \| number | 默认无,accordion 模式下默认第一个元素 | |
|
||||
| accordion | 手风琴模式,始终只有一个面板处在激活状态 | boolean | `false` | |
|
||||
| activeKey(v-model) | 当前激活 tab 面板的 key | string\[] \| string <br> number\[] \| number | 默认无,[手风琴模式](#components-collapse-demo-accordion)下默认第一个元素 | |
|
||||
| bordered | 带边框风格的折叠面板 | boolean | `true` | |
|
||||
| collapsible | 所有子面板是否可折叠或指定可折叠触发区域 | `header` \| `icon` \| `disabled` | - | 4.0 |
|
||||
| destroyInactivePanel | 销毁折叠隐藏的面板 | boolean | `false` | |
|
||||
|
@ -42,6 +42,6 @@ coverDark: https://mdn.alipayobjects.com/huamei_7uahnr/afts/img/A*sir-TK0HkWcAAA
|
|||
| collapsible | 是否可折叠或指定可折叠触发区域 | `header` \| `disabled` | - | 3.0 |
|
||||
| extra | 自定义渲染每个面板右上角的内容 | VNode \| slot | - | 1.5.0 |
|
||||
| forceRender | 被隐藏时是否渲染 DOM 结构 | boolean | false | |
|
||||
| header | 面板头内容 | string\|slot | 无 | |
|
||||
| key | 对应 activeKey | string \| number | 无 | |
|
||||
| header | 面板头内容 | string\|slot | - | |
|
||||
| key | 对应 activeKey | string \| number | - | |
|
||||
| showArrow | 是否展示当前面板上的箭头 | boolean | `true` | |
|
||||
|
|
|
@ -1,4 +1,4 @@
|
|||
import type { App, Plugin, WatchStopHandle } from 'vue';
|
||||
import type { App, MaybeRef, Plugin, WatchStopHandle } from 'vue';
|
||||
import { watch, computed, reactive, defineComponent, watchEffect } from 'vue';
|
||||
import defaultRenderEmpty from './renderEmpty';
|
||||
import type { RenderEmptyHandler } from './renderEmpty';
|
||||
|
@ -7,7 +7,6 @@ import LocaleProvider, { ANT_MARK } from '../locale-provider';
|
|||
|
||||
import LocaleReceiver from '../locale-provider/LocaleReceiver';
|
||||
|
||||
import type { MaybeRef } from '../_util/type';
|
||||
import message from '../message';
|
||||
import notification from '../notification';
|
||||
import { registerTheme } from './cssVariables';
|
||||
|
|
|
@ -85,7 +85,7 @@ The following APIs are shared by DatePicker, RangePicker.
|
|||
| disabled | Determine whether the DatePicker is disabled | boolean | false | |
|
||||
| disabledDate | Specify the date that cannot be selected | (currentDate: dayjs) => boolean | - | |
|
||||
| format | To set the date format, refer to [dayjs](https://day.js.org/). When an array is provided, all values are used for parsing and first value is used for formatting, support [Custom Format](#components-date-picker-demo-format) | [formatType](#formattype) | `YYYY-MM-DD` | |
|
||||
| dropdownClassName | To customize the className of the popup calendar | string | - | |
|
||||
| popupClassName | To customize the className of the popup calendar | string | - | |
|
||||
| getPopupContainer | To set the container of the floating layer, while the default is to create a `div` element in `body` | function(trigger) | - | |
|
||||
| inputReadOnly | Set the `readonly` attribute of the input tag (avoids virtual keyboard on touch devices) | boolean | false | |
|
||||
| locale | Localization configuration | object | [default](https://github.com/vueComponent/ant-design-vue/blob/main/components/date-picker/locale/example.json) | |
|
||||
|
|
|
@ -86,7 +86,7 @@ coverDark: https://mdn.alipayobjects.com/huamei_7uahnr/afts/img/A*3OpRQKcygo8AAA
|
|||
| disabled | 禁用 | boolean | false | |
|
||||
| disabledDate | 不可选择的日期 | (currentDate: dayjs) => boolean | - | |
|
||||
| format | 设置日期格式,为数组时支持多格式匹配,展示以第一个为准。配置参考 [dayjs](https://day.js.org/docs/zh-CN/display/format),支持[自定义格式](#components-date-picker-demo-format) | [formatType](#formattype) | `YYYY-MM-DD` | |
|
||||
| dropdownClassName | 额外的弹出日历 className | string | - | |
|
||||
| popupClassName | 额外的弹出日历 className | string | - | |
|
||||
| getPopupContainer | 定义浮层的容器,默认为 body 上新建 div | function(trigger) | - | |
|
||||
| inputReadOnly | 设置输入框为只读(避免在移动设备上打开虚拟键盘) | boolean | false | |
|
||||
| locale | 国际化配置 | object | [默认配置](https://github.com/vueComponent/ant-design-vue/blob/main/components/date-picker/locale/example.json) | - |
|
||||
|
|
|
@ -22,7 +22,7 @@ coverDark: https://mdn.alipayobjects.com/huamei_7uahnr/afts/img/A*5qm4S4Zgh2QAAA
|
|||
|
||||
| 参数 | 说明 | 类型 | 默认值 | |
|
||||
| --- | --- | --- | --- | --- |
|
||||
| align | 该值将合并到 placement 的配置中,设置参考 [dom-align](https://github.com/yiminghe/dom-align) | Object | 无 | |
|
||||
| align | 该值将合并到 placement 的配置中,设置参考 [dom-align](https://github.com/yiminghe/dom-align) | Object | - | |
|
||||
| arrow | 下拉框箭头是否显示 | boolean \| { pointAtCenter: boolean } | false | 3.3.0 |
|
||||
| destroyPopupOnHide | 关闭后是否销毁 Dropdown | boolean | false | 3.0 |
|
||||
| disabled | 菜单是否禁用 | boolean | - | |
|
||||
|
|
|
@ -1,4 +1,4 @@
|
|||
import { defineComponent } from 'vue';
|
||||
import { defineComponent, h } from 'vue';
|
||||
import type { CSSProperties, ExtractPropTypes } from 'vue';
|
||||
import classNames from '../_util/classNames';
|
||||
import LocaleReceiver from '../locale-provider/LocaleReceiver';
|
||||
|
@ -11,9 +11,6 @@ import useConfigInject from '../config-provider/hooks/useConfigInject';
|
|||
|
||||
import useStyle from './style';
|
||||
|
||||
const defaultEmptyImg = <DefaultEmptyImg />;
|
||||
const simpleEmptyImg = <SimpleEmptyImg />;
|
||||
|
||||
interface Locale {
|
||||
description?: string;
|
||||
}
|
||||
|
@ -40,13 +37,16 @@ const Empty = defineComponent({
|
|||
return () => {
|
||||
const prefixCls = prefixClsRef.value;
|
||||
const {
|
||||
image = slots.image?.() || defaultEmptyImg,
|
||||
image: mergedImage = slots.image?.() || h(DefaultEmptyImg),
|
||||
description = slots.description?.() || undefined,
|
||||
imageStyle,
|
||||
class: className = '',
|
||||
...restProps
|
||||
} = { ...props, ...attrs };
|
||||
|
||||
const image =
|
||||
typeof mergedImage === 'function' ? (mergedImage as () => VueNode)() : mergedImage;
|
||||
const isNormal =
|
||||
typeof image === 'object' && 'type' in image && (image.type as any).PRESENTED_IMAGE_SIMPLE;
|
||||
return wrapSSR(
|
||||
<LocaleReceiver
|
||||
componentName="Empty"
|
||||
|
@ -64,7 +64,7 @@ const Empty = defineComponent({
|
|||
return (
|
||||
<div
|
||||
class={classNames(prefixCls, className, hashId.value, {
|
||||
[`${prefixCls}-normal`]: image === simpleEmptyImg,
|
||||
[`${prefixCls}-normal`]: isNormal,
|
||||
[`${prefixCls}-rtl`]: direction.value === 'rtl',
|
||||
})}
|
||||
{...restProps}
|
||||
|
@ -85,7 +85,7 @@ const Empty = defineComponent({
|
|||
},
|
||||
});
|
||||
|
||||
Empty.PRESENTED_IMAGE_DEFAULT = defaultEmptyImg;
|
||||
Empty.PRESENTED_IMAGE_SIMPLE = simpleEmptyImg;
|
||||
Empty.PRESENTED_IMAGE_DEFAULT = () => h(DefaultEmptyImg);
|
||||
Empty.PRESENTED_IMAGE_SIMPLE = () => h(SimpleEmptyImg);
|
||||
|
||||
export default withInstall(Empty);
|
||||
|
|
|
@ -1,5 +1,5 @@
|
|||
import VerticalAlignTopOutlined from '@ant-design/icons-vue/VerticalAlignTopOutlined';
|
||||
import { getTransitionProps, Transition } from '../_util/transition';
|
||||
import { getTransitionProps } from '../_util/transition';
|
||||
import {
|
||||
defineComponent,
|
||||
nextTick,
|
||||
|
@ -10,6 +10,7 @@ import {
|
|||
ref,
|
||||
watch,
|
||||
onDeactivated,
|
||||
Transition,
|
||||
} from 'vue';
|
||||
import FloatButton, { floatButtonPrefixCls } from './FloatButton';
|
||||
import useConfigInject from '../config-provider/hooks/useConfigInject';
|
||||
|
|
|
@ -1,8 +1,8 @@
|
|||
import { defineComponent, ref, computed, watch, onBeforeUnmount } from 'vue';
|
||||
import { defineComponent, ref, computed, watch, onBeforeUnmount, Transition } from 'vue';
|
||||
import CloseOutlined from '@ant-design/icons-vue/CloseOutlined';
|
||||
import FileTextOutlined from '@ant-design/icons-vue/FileTextOutlined';
|
||||
import classNames from '../_util/classNames';
|
||||
import { getTransitionProps, Transition } from '../_util/transition';
|
||||
import { getTransitionProps } from '../_util/transition';
|
||||
import FloatButton, { floatButtonPrefixCls } from './FloatButton';
|
||||
import useConfigInject from '../config-provider/hooks/useConfigInject';
|
||||
import { useProvideFloatButtonGroupContext } from './context';
|
||||
|
|
|
@ -33,11 +33,11 @@ tag: New
|
|||
| target | 相当于 a 标签的 target 属性,href 存在时生效 | string | - | |
|
||||
| badge | 带徽标数字的悬浮按钮(不支持 status 以及相关属性) | [BadgeProps](/components/badge-cn#api) | - | |
|
||||
|
||||
### common events
|
||||
### 共同的事件
|
||||
|
||||
| 事件名称 | 说明 | 回调参数 | 版本 |
|
||||
| -------- | --------------------------------------- | ----------------- | ---- |
|
||||
| click | Set the handler to handle `click` event | `(event) => void` | - |
|
||||
| 事件名称 | 说明 | 回调参数 | 版本 |
|
||||
| -------- | ----------------------------- | ----------------- | ---- |
|
||||
| click | 设置处理 `click` 事件的处理器 | `(event) => void` | - |
|
||||
|
||||
### FloatButton.Group
|
||||
|
||||
|
@ -47,7 +47,7 @@ tag: New
|
|||
| trigger | 触发方式(有触发方式为菜单模式) | `click` \| `hover` | - | |
|
||||
| open(v-model) | 受控展开 | boolean | - | |
|
||||
|
||||
### FloatButton.Group Events
|
||||
### FloatButton.Group 事件
|
||||
|
||||
| 事件名称 | 说明 | 回调参数 | 版本 |
|
||||
| ---------- | ---------------- | ----------------------- | ---- |
|
||||
|
|
|
@ -20,7 +20,7 @@ export const floatButtonProps = () => {
|
|||
shape: stringType<FloatButtonShape>('circle'),
|
||||
tooltip: PropTypes.any,
|
||||
href: String,
|
||||
target: functionType<() => Window | HTMLElement | null>(),
|
||||
target: String,
|
||||
badge: objectType<FloatButtonBadgeProps>(),
|
||||
onClick: functionType<MouseEventHandler>(),
|
||||
};
|
||||
|
|
|
@ -494,7 +494,7 @@ export default defineComponent({
|
|||
>
|
||||
<Row
|
||||
{...attrs}
|
||||
class={`${prefixCls.value}-row`}
|
||||
class={`${prefixCls.value}-item-row`}
|
||||
key="row"
|
||||
v-slots={{
|
||||
default: () => (
|
||||
|
|
|
@ -52,6 +52,10 @@ const genGridRowStyle: GenerateStyle<GridRowToken> = (token): CSSObject => {
|
|||
justifyContent: 'space-around',
|
||||
},
|
||||
|
||||
'&-space-evenly ': {
|
||||
justifyContent: 'space-evenly',
|
||||
},
|
||||
|
||||
// Align at the top
|
||||
'&-top': {
|
||||
alignItems: 'flex-start',
|
||||
|
|
|
@ -122,6 +122,8 @@ See [iconfont.cn documents](http://iconfont.cn/help/detail?spm=a313x.7781069.199
|
|||
|
||||
### Custom SVG Icon
|
||||
|
||||
#### vue cli 3
|
||||
|
||||
You can import SVG icon as an vue component by using `vue cli 3` and [`vue-svg-loader`](https://www.npmjs.com/package/vue-svg-loader). `vue-svg-loader`'s `options` [reference](https://github.com/visualfanatic/vue-svg-loader).
|
||||
|
||||
```js
|
||||
|
@ -149,6 +151,84 @@ export default defineComponent({
|
|||
});
|
||||
```
|
||||
|
||||
#### Rsbuild
|
||||
|
||||
Rsbuild is a new generation of build tool, official website https://rsbuild.dev/
|
||||
Create your own `vue-svg-loader.js` file, which allows you to customize and beautify SVG, and then configure it in `rsbuild.config.ts`
|
||||
|
||||
```js
|
||||
// vue-svg-loader.js
|
||||
/* eslint-disable */
|
||||
const { optimize } = require('svgo');
|
||||
const { version } = require('vue');
|
||||
const semverMajor = require('semver/functions/major');
|
||||
|
||||
module.exports = async function (svg) {
|
||||
const callback = this.async();
|
||||
|
||||
try {
|
||||
({ data: svg } = await optimize(svg, {
|
||||
path: this.resourcePath,
|
||||
js2svg: {
|
||||
indent: 2,
|
||||
pretty: true,
|
||||
},
|
||||
plugins: [
|
||||
'convertStyleToAttrs',
|
||||
'removeDoctype',
|
||||
'removeXMLProcInst',
|
||||
'removeComments',
|
||||
'removeMetadata',
|
||||
'removeTitle',
|
||||
'removeDesc',
|
||||
'removeStyleElement',
|
||||
'removeXMLNS',
|
||||
'removeXMLProcInst',
|
||||
],
|
||||
}));
|
||||
} catch (error) {
|
||||
callback(error);
|
||||
return;
|
||||
}
|
||||
|
||||
if (semverMajor(version) === 2) {
|
||||
svg = svg.replace('<svg', '<svg v-on="$listeners"');
|
||||
}
|
||||
|
||||
callback(null, `<template>${svg}</template>`);
|
||||
};
|
||||
```
|
||||
|
||||
```js
|
||||
// rsbuild.config.ts
|
||||
/* eslint-disable */
|
||||
import { defineConfig } from '@rsbuild/core';
|
||||
import { pluginVue } from '@rsbuild/plugin-vue';
|
||||
|
||||
export default defineConfig({
|
||||
tools: {
|
||||
bundlerChain(chain, { CHAIN_ID }) {
|
||||
chain.module.rule(CHAIN_ID.RULE.SVG).exclude.add(/\.svg$/);
|
||||
},
|
||||
rspack: {
|
||||
module: {
|
||||
rules: [
|
||||
{
|
||||
test: /\.svg$/,
|
||||
use: ['vue-loader', 'vue-svg-loader'],
|
||||
},
|
||||
],
|
||||
},
|
||||
resolveLoader: {
|
||||
alias: {
|
||||
'vue-svg-loader': require('path').join(__dirname, './vue-svg-loader.js'),
|
||||
},
|
||||
},
|
||||
},
|
||||
},
|
||||
});
|
||||
```
|
||||
|
||||
The following properties are available for the component:
|
||||
|
||||
| Property | Description | Type | Default |
|
||||
|
|
|
@ -119,7 +119,9 @@ export default defineComponent({
|
|||
|
||||
### 自定义 SVG 图标
|
||||
|
||||
如果使用 `vue cli 3`,可以通过配置 [vue-svg-loader](https://www.npmjs.com/package/vue-svg-loader) 来将 `svg` 图标作为 `Vue` 组件导入。更多`vue-svg-loader` 的使用方式请参阅 [文档](https://github.com/visualfanatic/vue-svg-loader)。
|
||||
#### vue cli 3
|
||||
|
||||
可以通过配置 [vue-svg-loader](https://www.npmjs.com/package/vue-svg-loader) 来将 `svg` 图标作为 `Vue` 组件导入。更多`vue-svg-loader` 的使用方式请参阅 [文档](https://github.com/visualfanatic/vue-svg-loader)。
|
||||
|
||||
```js
|
||||
// vue.config.js
|
||||
|
@ -146,6 +148,88 @@ export default defineComponent({
|
|||
});
|
||||
```
|
||||
|
||||
#### Rsbuild
|
||||
|
||||
Rsbuild 是新一代构建工具,官网 https://rsbuild.dev/
|
||||
|
||||
自己实现一个 `vue-svg-loader.js` 文件,好处是可以自定义美化 svg,然后在 `rsbuild.config.ts` 中配置:
|
||||
|
||||
```js
|
||||
// vue-svg-loader.js
|
||||
/* eslint-disable */
|
||||
const { optimize } = require('svgo');
|
||||
const { version } = require('vue');
|
||||
const semverMajor = require('semver/functions/major');
|
||||
|
||||
module.exports = async function (svg) {
|
||||
const callback = this.async();
|
||||
|
||||
try {
|
||||
({ data: svg } = await optimize(svg, {
|
||||
path: this.resourcePath,
|
||||
js2svg: {
|
||||
indent: 2,
|
||||
pretty: true,
|
||||
},
|
||||
plugins: [
|
||||
'convertStyleToAttrs',
|
||||
'removeDoctype',
|
||||
'removeXMLProcInst',
|
||||
'removeComments',
|
||||
'removeMetadata',
|
||||
'removeTitle',
|
||||
'removeDesc',
|
||||
'removeStyleElement',
|
||||
'removeXMLNS',
|
||||
'removeXMLProcInst',
|
||||
],
|
||||
}));
|
||||
} catch (error) {
|
||||
callback(error);
|
||||
return;
|
||||
}
|
||||
|
||||
if (semverMajor(version) === 2) {
|
||||
svg = svg.replace('<svg', '<svg v-on="$listeners"');
|
||||
}
|
||||
|
||||
callback(null, `<template>${svg}</template>`);
|
||||
};
|
||||
```
|
||||
|
||||
```js
|
||||
// rsbuild.config.ts
|
||||
/* eslint-disable */
|
||||
import { defineConfig } from '@rsbuild/core';
|
||||
import { pluginVue } from '@rsbuild/plugin-vue';
|
||||
|
||||
export default defineConfig({
|
||||
tools: {
|
||||
bundlerChain(chain, { CHAIN_ID }) {
|
||||
chain.module
|
||||
// 先给svg排除默认的规则,方便下面自定义loader
|
||||
.rule(CHAIN_ID.RULE.SVG)
|
||||
.exclude.add(/\.svg$/);
|
||||
},
|
||||
rspack: {
|
||||
module: {
|
||||
rules: [
|
||||
{
|
||||
test: /\.svg$/,
|
||||
use: ['vue-loader', 'vue-svg-loader'],
|
||||
},
|
||||
],
|
||||
},
|
||||
resolveLoader: {
|
||||
alias: {
|
||||
'vue-svg-loader': require('path').join(__dirname, './vue-svg-loader.js'),
|
||||
},
|
||||
},
|
||||
},
|
||||
},
|
||||
});
|
||||
```
|
||||
|
||||
`Icon` 中的 `component` 组件的接受的属性如下:
|
||||
|
||||
| 字段 | 说明 | 类型 | 只读值 |
|
||||
|
|
|
@ -13,10 +13,10 @@ export type ImageProps = Partial<
|
|||
ExtractPropTypes<ReturnType<typeof imageProps>> &
|
||||
Omit<ImgHTMLAttributes, 'placeholder' | 'onClick'>
|
||||
>;
|
||||
const Image = defineComponent<ImageProps>({
|
||||
const Image = defineComponent({
|
||||
name: 'AImage',
|
||||
inheritAttrs: false,
|
||||
props: imageProps() as any,
|
||||
props: imageProps(),
|
||||
setup(props, { slots, attrs }) {
|
||||
const { prefixCls, rootPrefixCls, configProvider } = useConfigInject('image', props);
|
||||
// Style
|
||||
|
|
|
@ -72,7 +72,7 @@ const InputNumber = defineComponent({
|
|||
|
||||
const mergedSize = computed(() => compactSize.value || size.value);
|
||||
|
||||
const mergedValue = shallowRef(props.value === undefined ? props.defaultValue : props.value);
|
||||
const mergedValue = shallowRef(props.value ?? props.defaultValue);
|
||||
const focused = shallowRef(false);
|
||||
watch(
|
||||
() => props.value,
|
||||
|
|
|
@ -34,7 +34,7 @@ coverDark: https://mdn.alipayobjects.com/huamei_7uahnr/afts/img/A*1uH-R5kLAMIAAA
|
|||
| parser | 指定从 formatter 里转换回数字的方式,和 formatter 搭配使用 | function( string): number | - | |
|
||||
| precision | 数值精度 | number | - | |
|
||||
| prefix | 带有前缀图标的 input | slot | - | 3.0 |
|
||||
| size | 输入框大小 | string | 无 | |
|
||||
| size | 输入框大小 | string | - | |
|
||||
| status | 设置校验状态 | 'error' \| 'warning' | - | 3.3.0 |
|
||||
| step | 每次改变步数,可以为小数 | number\|string | 1 | |
|
||||
| stringMode | 字符值模式,开启后支持高精度小数。同时 `change` 事件将返回 string 类型 | boolean | false | 3.0 |
|
||||
|
|
|
@ -395,6 +395,11 @@ export default defineComponent({
|
|||
}
|
||||
};
|
||||
|
||||
// Solve the issue of the event triggering sequence when entering numbers in chinese input (Safari)
|
||||
const onBeforeInput = () => {
|
||||
userTypingRef.value = true;
|
||||
};
|
||||
|
||||
const onKeyDown: KeyboardEventHandler = event => {
|
||||
const { which } = event;
|
||||
userTypingRef.value = true;
|
||||
|
@ -577,6 +582,7 @@ export default defineComponent({
|
|||
onBlur={onBlur}
|
||||
onCompositionstart={onCompositionStart}
|
||||
onCompositionend={onCompositionEnd}
|
||||
onBeforeinput={onBeforeInput}
|
||||
/>
|
||||
</div>
|
||||
</div>
|
||||
|
|
|
@ -263,6 +263,10 @@ const genInputNumberStyles: GenerateStyle<InputNumberToken> = (token: InputNumbe
|
|||
[`${componentCls}-handler-wrap`]: {
|
||||
display: 'none',
|
||||
},
|
||||
|
||||
[`${componentCls}-input`]: {
|
||||
color: 'inherit',
|
||||
},
|
||||
},
|
||||
|
||||
[`
|
||||
|
|
|
@ -59,7 +59,7 @@ export default defineComponent({
|
|||
});
|
||||
const getIcon = (prefixCls: string) => {
|
||||
const { action, iconRender = slots.iconRender || defaultIconRender } = props;
|
||||
const iconTrigger = ActionMap[action!] || '';
|
||||
const iconTrigger = ActionMap[action] || '';
|
||||
const icon = iconRender(visible.value);
|
||||
const iconProps = {
|
||||
[iconTrigger]: onVisibleChange,
|
||||
|
|
|
@ -38,10 +38,10 @@ function setTriggerValue(
|
|||
let newTriggerValue = triggerValue;
|
||||
if (isCursorInEnd) {
|
||||
// 光标在尾部,直接截断
|
||||
newTriggerValue = fixEmojiLength(triggerValue, maxLength!);
|
||||
newTriggerValue = fixEmojiLength(triggerValue, maxLength);
|
||||
} else if (
|
||||
[...(preValue || '')].length < triggerValue.length &&
|
||||
[...(triggerValue || '')].length > maxLength!
|
||||
[...(triggerValue || '')].length > maxLength
|
||||
) {
|
||||
// 光标在中间,如果最后的值超过最大值,则采用原先的值
|
||||
newTriggerValue = preValue;
|
||||
|
@ -58,7 +58,7 @@ export default defineComponent({
|
|||
const formItemContext = useInjectFormItemContext();
|
||||
const formItemInputContext = FormItemInputContext.useInject();
|
||||
const mergedStatus = computed(() => getMergedStatus(formItemInputContext.status, props.status));
|
||||
const stateValue = shallowRef(props.value === undefined ? props.defaultValue : props.value);
|
||||
const stateValue = shallowRef(props.value ?? props.defaultValue);
|
||||
const resizableTextArea = shallowRef();
|
||||
const mergedValue = shallowRef('');
|
||||
const { prefixCls, size, direction } = useConfigInject('input', props);
|
||||
|
@ -79,7 +79,7 @@ export default defineComponent({
|
|||
const onInternalCompositionStart = (e: CompositionEvent) => {
|
||||
compositing.value = true;
|
||||
// 拼音输入前保存一份旧值
|
||||
oldCompositionValueRef.value = mergedValue.value as string;
|
||||
oldCompositionValueRef.value = mergedValue.value;
|
||||
// 保存旧的光标位置
|
||||
oldSelectionStartRef.value = (e.currentTarget as any).selectionStart;
|
||||
emit('compositionstart', e);
|
||||
|
@ -94,7 +94,7 @@ export default defineComponent({
|
|||
oldSelectionStartRef.value === oldCompositionValueRef.value?.length;
|
||||
triggerValue = setTriggerValue(
|
||||
isCursorInEnd,
|
||||
oldCompositionValueRef.value as string,
|
||||
oldCompositionValueRef.value,
|
||||
triggerValue,
|
||||
props.maxlength,
|
||||
);
|
||||
|
@ -177,14 +177,14 @@ export default defineComponent({
|
|||
// 1. 复制粘贴超过maxlength的情况 2.未超过maxlength的情况
|
||||
const target = e.target as any;
|
||||
const isCursorInEnd =
|
||||
target.selectionStart >= props.maxlength! + 1 ||
|
||||
target.selectionStart >= props.maxlength + 1 ||
|
||||
target.selectionStart === triggerValue.length ||
|
||||
!target.selectionStart;
|
||||
triggerValue = setTriggerValue(
|
||||
isCursorInEnd,
|
||||
mergedValue.value as string,
|
||||
mergedValue.value,
|
||||
triggerValue,
|
||||
props.maxlength!,
|
||||
props.maxlength,
|
||||
);
|
||||
}
|
||||
resolveOnChange(e.currentTarget as any, e, triggerChange, triggerValue);
|
||||
|
@ -237,7 +237,7 @@ export default defineComponent({
|
|||
});
|
||||
|
||||
watchEffect(() => {
|
||||
let val = fixControlledValue(stateValue.value) as string;
|
||||
let val = fixControlledValue(stateValue.value);
|
||||
if (
|
||||
!compositing.value &&
|
||||
hasMaxLength.value &&
|
||||
|
|
|
@ -48,9 +48,8 @@ const computedStyleCache: Record<string, NodeType> = {};
|
|||
let hiddenTextarea: HTMLTextAreaElement;
|
||||
|
||||
export function calculateNodeStyling(node: HTMLElement, useCache = false) {
|
||||
const nodeRef = (node.getAttribute('id') ||
|
||||
node.getAttribute('data-reactid') ||
|
||||
node.getAttribute('name')) as string;
|
||||
const nodeRef =
|
||||
node.getAttribute('id') || node.getAttribute('data-reactid') || node.getAttribute('name');
|
||||
|
||||
if (useCache && computedStyleCache[nodeRef]) {
|
||||
return computedStyleCache[nodeRef];
|
||||
|
@ -103,7 +102,7 @@ export default function calculateAutoSizeStyle(
|
|||
// Fix wrap="off" issue
|
||||
// https://github.com/ant-design/ant-design/issues/6577
|
||||
if (uiTextNode.getAttribute('wrap')) {
|
||||
hiddenTextarea.setAttribute('wrap', uiTextNode.getAttribute('wrap') as string);
|
||||
hiddenTextarea.setAttribute('wrap', uiTextNode.getAttribute('wrap'));
|
||||
} else {
|
||||
hiddenTextarea.removeAttribute('wrap');
|
||||
}
|
||||
|
|
|
@ -1,5 +1,4 @@
|
|||
import { computed, defineComponent, ref, watch } from 'vue';
|
||||
import Transition from '../../_util/transition';
|
||||
import { computed, Transition, defineComponent, ref, watch } from 'vue';
|
||||
import { useInjectMenu, MenuContextProvider } from './hooks/useMenuContext';
|
||||
import type { MenuMode } from './interface';
|
||||
import SubMenuList from './SubMenuList';
|
||||
|
|
|
@ -47,7 +47,9 @@ const Holder = defineComponent({
|
|||
'rtl',
|
||||
'transitionName',
|
||||
'onAllRemoved',
|
||||
] as any,
|
||||
'animation',
|
||||
'staticGetContainer',
|
||||
],
|
||||
setup(props, { expose }) {
|
||||
const { getPrefixCls, getPopupContainer } = useConfigInject('message', props);
|
||||
|
||||
|
|
|
@ -19,14 +19,14 @@ coverDark: https://mdn.alipayobjects.com/huamei_7uahnr/afts/img/A*fBrgSJBmavgAAA
|
|||
|
||||
| 参数 | 说明 | 类型 | 默认值 | 版本 |
|
||||
| --- | --- | --- | --- | --- |
|
||||
| afterClose | Modal 完全关闭后的回调 | function | 无 | |
|
||||
| afterClose | Modal 完全关闭后的回调 | function | - | |
|
||||
| bodyStyle | Modal body 样式 | object | {} | |
|
||||
| cancelButtonProps | cancel 按钮 props | [ButtonProps](/components/button/#api) | - | |
|
||||
| cancelText | 取消按钮文字 | string\| slot | 取消 | |
|
||||
| centered | 垂直居中展示 Modal | boolean | `false` | |
|
||||
| closable | 是否显示右上角的关闭按钮 | boolean | true | |
|
||||
| closeIcon | 自定义关闭图标 | VNode \| slot | - | |
|
||||
| confirmLoading | 确定按钮 loading | boolean | 无 | |
|
||||
| confirmLoading | 确定按钮 loading | boolean | - | |
|
||||
| destroyOnClose | 关闭时销毁 Modal 里的子元素 | boolean | false | |
|
||||
| footer | 底部内容,当不需要默认底部按钮时,可以设为 `:footer="null"` | string\|slot | 确定取消按钮 | |
|
||||
| forceRender | 强制渲染 Modal | boolean | false | |
|
||||
|
@ -38,8 +38,8 @@ coverDark: https://mdn.alipayobjects.com/huamei_7uahnr/afts/img/A*fBrgSJBmavgAAA
|
|||
| okButtonProps | ok 按钮 props | [ButtonProps](/components/button/#api) | - | |
|
||||
| okText | 确认按钮文字 | string\|slot | 确定 | |
|
||||
| okType | 确认按钮类型 | string | primary | |
|
||||
| title | 标题 | string\|slot | 无 | |
|
||||
| open(v-model) | 对话框是否可见 | boolean | 无 | |
|
||||
| title | 标题 | string\|slot | - | |
|
||||
| open(v-model) | 对话框是否可见 | boolean | - | |
|
||||
| width | 宽度 | string\|number | 520 | |
|
||||
| wrapClassName | 对话框外层容器的类名 | string | - | |
|
||||
| zIndex | 设置 Modal 的 `z-index` | number | 1000 | |
|
||||
|
@ -76,7 +76,7 @@ coverDark: https://mdn.alipayobjects.com/huamei_7uahnr/afts/img/A*fBrgSJBmavgAAA
|
|||
| centered | 垂直居中展示 Modal | boolean | `false` | |
|
||||
| class | 容器类名 | string | - | |
|
||||
| closable | 是否显示右上角的关闭按钮 | boolean | `false` | |
|
||||
| content | 内容 | string \|VNode \|function() | 无 | |
|
||||
| content | 内容 | string \|VNode \|function() | - | |
|
||||
| footer | 底部内容,当不需要默认底部按钮时,可以设为 `footer: null` | string \|VNode \|function() | - | 4.0.0 |
|
||||
| icon | 自定义图标(1.14.0 新增) | VNode \| ()=>VNode | - | |
|
||||
| keyboard | 是否支持键盘 esc 关闭 | boolean | true | |
|
||||
|
@ -85,12 +85,12 @@ coverDark: https://mdn.alipayobjects.com/huamei_7uahnr/afts/img/A*fBrgSJBmavgAAA
|
|||
| okButtonProps | ok 按钮 props | [ButtonProps](/components/button) | - | |
|
||||
| okText | 确认按钮文字 | string | 确定 | |
|
||||
| okType | 确认按钮类型 | string | primary | |
|
||||
| title | 标题 | string\|VNode \|function() | 无 | |
|
||||
| title | 标题 | string\|VNode \|function() | - | |
|
||||
| width | 宽度 | string\|number | 416 | |
|
||||
| wrapClassName | 对话框外层容器的类名 | string | - | 3.2.3 |
|
||||
| zIndex | 设置 Modal 的 `z-index` | number | 1000 | |
|
||||
| onCancel | 取消回调,参数为关闭函数,返回 promise 时 resolve 后自动关闭 | function | 无 | |
|
||||
| onOk | 点击确定回调,参数为关闭函数,返回 promise 时 resolve 后自动关闭 | function | 无 | |
|
||||
| onCancel | 取消回调,参数为关闭函数,返回 promise 时 resolve 后自动关闭 | function | - | |
|
||||
| onOk | 点击确定回调,参数为关闭函数,返回 promise 时 resolve 后自动关闭 | function | - | |
|
||||
|
||||
以上函数调用后,会返回一个引用,可以通过该引用更新和关闭弹窗。
|
||||
|
||||
|
|
|
@ -27,7 +27,7 @@ coverDark: https://mdn.alipayobjects.com/huamei_7uahnr/afts/img/A*HrFtQ6jJJFQAAA
|
|||
| okText | 确认按钮文字 | string\|slot | 确定 | |
|
||||
| okType | 确认按钮类型 | string | primary | |
|
||||
| showCancel | 是否显示取消按钮 | boolean | true | 3.0 |
|
||||
| title | 确认框的描述 | string\|slot | 无 | |
|
||||
| title | 确认框的描述 | string\|slot | - | |
|
||||
| description | 确认内容的详细描述 | string\|slot | - | 4.0 |
|
||||
| open (v-model) | 是否显示 | boolean | - | 4.0 |
|
||||
|
||||
|
|
|
@ -21,7 +21,7 @@ tag: New
|
|||
|
||||
| 参数 | 说明 | 类型 | 默认值 | 版本 |
|
||||
| --- | --- | --- | --- | --- |
|
||||
| block | 将宽度调整为父元素宽度的选项 | boolean | 无 | |
|
||||
| block | 将宽度调整为父元素宽度的选项 | boolean | - | |
|
||||
| disabled | 是否禁用 | boolean | false | |
|
||||
| options | 数据化配置选项内容 | string[] \| number[] \| SegmentedOption[] | [] | |
|
||||
| size | 控件尺寸 | `large` \| `middle` \| `small` | - | |
|
||||
|
|
|
@ -159,6 +159,52 @@ describe('Select', () => {
|
|||
}, 500);
|
||||
});
|
||||
|
||||
it('The select trigger should be blur when the panel is closed.', async () => {
|
||||
const wrapper = mount(
|
||||
{
|
||||
render() {
|
||||
return (
|
||||
<Select
|
||||
dropdownRender={() => {
|
||||
return <input id="dropdownRenderInput" />;
|
||||
}}
|
||||
/>
|
||||
);
|
||||
},
|
||||
},
|
||||
{
|
||||
sync: false,
|
||||
attachTo: 'body',
|
||||
},
|
||||
);
|
||||
await asyncExpect(async () => {
|
||||
await wrapper.find('.ant-select-selector').trigger('mousedown');
|
||||
await wrapper.find('.ant-select-selection-search-input').trigger('focus');
|
||||
});
|
||||
|
||||
await asyncExpect(async () => {
|
||||
const el = wrapper.find('.ant-select');
|
||||
|
||||
expect(el.classes()).toContain('ant-select-focused');
|
||||
$$('#dropdownRenderInput')[0].focus();
|
||||
|
||||
expect(el.classes()).toContain('ant-select-focused');
|
||||
|
||||
document.body.dispatchEvent(
|
||||
new MouseEvent('mousedown', {
|
||||
bubbles: true,
|
||||
cancelable: true,
|
||||
view: window,
|
||||
}),
|
||||
);
|
||||
}, 100);
|
||||
|
||||
await asyncExpect(async () => {
|
||||
const el = wrapper.find('.ant-select');
|
||||
expect(el.classes()).not.toContain('ant-select-focused');
|
||||
}, 200);
|
||||
});
|
||||
|
||||
describe('Select Custom Icons', () => {
|
||||
it('should support customized icons', () => {
|
||||
const wrapper = mount({
|
||||
|
|
|
@ -111,7 +111,7 @@ coverDark: https://mdn.alipayobjects.com/huamei_7uahnr/afts/img/A*5oPiTqPxGAUAAA
|
|||
| 参数 | 说明 | 类型 | 默认值 |
|
||||
| ----- | ---- | ------------------------- | ------ |
|
||||
| key | | string | - |
|
||||
| label | 组名 | string\|function(h)\|slot | 无 |
|
||||
| label | 组名 | string\|function(h)\|slot | - |
|
||||
|
||||
## FAQ
|
||||
|
||||
|
|
|
@ -17,8 +17,8 @@ The `onChange` callback function will fire when the user changes the slider's va
|
|||
|
||||
<template>
|
||||
<div class="code-box-demo">
|
||||
<a-slider v-model:value="value1" @afterChange="onAfterChange" />
|
||||
<a-slider v-model:value="value2" range :step="10" @afterChange="onAfterChange" />
|
||||
<a-slider v-model:value="value1" @change="onChange" @afterChange="onAfterChange" />
|
||||
<a-slider v-model:value="value2" range :step="10" @change="onChange" @afterChange="onAfterChange" />
|
||||
</div>
|
||||
</template>
|
||||
<script lang="ts" setup>
|
||||
|
@ -26,6 +26,10 @@ import { ref } from 'vue';
|
|||
const value1 = ref<number>(30);
|
||||
const value2 = ref<[number, number]>([20, 50]);
|
||||
|
||||
const onChange = (value: number) => {
|
||||
console.log('onChange: ', value);
|
||||
};
|
||||
|
||||
const onAfterChange = (value: number) => {
|
||||
console.log('afterChange: ', value);
|
||||
};
|
||||
|
|
|
@ -38,7 +38,7 @@ const genSpaceStyle: GenerateStyle<SpaceToken> = token => {
|
|||
alignItems: 'baseline',
|
||||
},
|
||||
},
|
||||
[`${componentCls}-space-item`]: {
|
||||
[`${componentCls}-item`]: {
|
||||
'&:empty': {
|
||||
display: 'none',
|
||||
},
|
||||
|
|
|
@ -25,13 +25,13 @@ Ant Design 依次提供了三级选项卡,分别用于不同的场景。
|
|||
|
||||
| 参数 | 说明 | 类型 | 默认值 | 版本 | |
|
||||
| --- | --- | --- | --- | --- | --- |
|
||||
| activeKey(v-model) | 当前激活 tab 面板的 key | string | 无 | | |
|
||||
| activeKey(v-model) | 当前激活 tab 面板的 key | string | - | | |
|
||||
| animated | 是否使用动画切换 Tabs,在 tabPosition=`"top"` \| `"bottom"` 时有效 | boolean \| {inkBar:boolean, tabPane:boolean} | true, 当 type="card" 时为 false | |
|
||||
| centered | 标签居中展示 | boolean | false | 3.0 | |
|
||||
| destroyInactiveTabPane | 被隐藏时是否销毁 DOM 结构 | boolean | false | | |
|
||||
| hideAdd | 是否隐藏加号图标,在 `type="editable-card"` 时有效 | boolean | false | | |
|
||||
| size | 大小,提供 `large` `middle` 和 `small` 三种大小 | string | `middle` | | |
|
||||
| tabBarGutter | tabs 之间的间隙 | number | 无 | | |
|
||||
| tabBarGutter | tabs 之间的间隙 | number | - | | |
|
||||
| tabBarStyle | tab bar 的样式对象 | CSSProperties | - | | |
|
||||
| tabPosition | 页签位置,可选值有 `top` `right` `bottom` `left` | string | `top` | | |
|
||||
| type | 页签的基本样式,可选 `line`、`card` `editable-card` 类型 | string | `line` | | |
|
||||
|
@ -60,8 +60,8 @@ Ant Design 依次提供了三级选项卡,分别用于不同的场景。
|
|||
| 参数 | 说明 | 类型 | 默认值 |
|
||||
| ----------- | ------------------------- | ------------ | ------ |
|
||||
| forceRender | 被隐藏时是否渲染 DOM 结构 | boolean | false |
|
||||
| key | 对应 activeKey | string | 无 |
|
||||
| tab | 选项卡头显示文字 | string\|slot | 无 |
|
||||
| key | 对应 activeKey | string | - |
|
||||
| tab | 选项卡头显示文字 | string\|slot | - |
|
||||
|
||||
### Tabs.TabPane 插槽
|
||||
|
||||
|
|
|
@ -18,7 +18,7 @@ coverDark: https://mdn.alipayobjects.com/huamei_7uahnr/afts/img/A*gwrhTozoTC4AAA
|
|||
|
||||
| 参数 | 说明 | 类型 | 默认值 |
|
||||
| ----- | -------- | ------------ | ------ |
|
||||
| title | 提示文字 | string\|slot | 无 |
|
||||
| title | 提示文字 | string\|slot | - |
|
||||
|
||||
### 共同的 API
|
||||
|
||||
|
@ -26,18 +26,18 @@ coverDark: https://mdn.alipayobjects.com/huamei_7uahnr/afts/img/A*gwrhTozoTC4AAA
|
|||
|
||||
| 参数 | 说明 | 类型 | 默认值 | 版本 |
|
||||
| --- | --- | --- | --- | --- |
|
||||
| align | 该值将合并到 placement 的配置中,设置参考 [dom-align](https://github.com/yiminghe/dom-align) | Object | 无 | |
|
||||
| align | 该值将合并到 placement 的配置中,设置参考 [dom-align](https://github.com/yiminghe/dom-align) | Object | - | |
|
||||
| arrowPointAtCenter | 箭头是否指向目标元素中心 | boolean | `false` | |
|
||||
| arrow | 修改箭头的显示状态以及修改箭头是否指向目标元素中心 | boolean \| { pointAtCenter: boolean} | `true` | 4.2.0 |
|
||||
| autoAdjustOverflow | 气泡被遮挡时自动调整位置 | boolean | `true` | |
|
||||
| color | 背景颜色 | string | 无 | |
|
||||
| color | 背景颜色 | string | - | |
|
||||
| destroyTooltipOnHide | 隐藏后是否销毁 tooltip | boolean | false | |
|
||||
| getPopupContainer | 浮层渲染父节点,默认渲染到 body 上 | (triggerNode: HTMLElement) => HTMLElement | () => document.body | |
|
||||
| mouseEnterDelay | 鼠标移入后延时多少才显示 Tooltip,单位:秒 | number | 0.1 | |
|
||||
| mouseLeaveDelay | 鼠标移出后延时多少才隐藏 Tooltip,单位:秒 | number | 0.1 | |
|
||||
| overlayClassName | 卡片类名 | string | 无 | |
|
||||
| overlayStyle | 卡片样式 | object | 无 | |
|
||||
| overlayInnerStyle | 卡片内容区域样式 | object | 无 | 4.0 |
|
||||
| overlayClassName | 卡片类名 | string | - | |
|
||||
| overlayStyle | 卡片样式 | object | - | |
|
||||
| overlayInnerStyle | 卡片内容区域样式 | object | - | 4.0 |
|
||||
| placement | 气泡框位置,可选 `top` `left` `right` `bottom` `topLeft` `topRight` `bottomLeft` `bottomRight` `leftTop` `leftBottom` `rightTop` `rightBottom` | string | top | |
|
||||
| trigger | 触发行为,可选 `hover/focus/click/contextmenu` | string | hover | |
|
||||
| open(v-model) | 用于手动控制浮层显隐, 小于 4.0.0 使用 `visible` | boolean | false | 4.0 |
|
||||
|
|
|
@ -1,5 +1,6 @@
|
|||
import { computed, defineComponent, toRefs } from 'vue';
|
||||
import classNames from '../_util/classNames';
|
||||
import { isFunction } from '../_util/util';
|
||||
import CloseOutlined from '@ant-design/icons-vue/CloseOutlined';
|
||||
import { tourStepProps } from './interface';
|
||||
import type { TourBtnProps } from './interface';
|
||||
|
@ -119,7 +120,9 @@ const panelRender = defineComponent({
|
|||
size="small"
|
||||
class={classNames(`${prefixCls}-prev-btn`, prevButtonProps?.className)}
|
||||
>
|
||||
{prevButtonProps?.children ?? contextLocale.Previous}
|
||||
{isFunction(prevButtonProps?.children)
|
||||
? prevButtonProps.children()
|
||||
: prevButtonProps?.children ?? contextLocale.Previous}
|
||||
</Button>
|
||||
) : null}
|
||||
<Button
|
||||
|
@ -129,8 +132,11 @@ const panelRender = defineComponent({
|
|||
size="small"
|
||||
class={classNames(`${prefixCls}-next-btn`, nextButtonProps?.className)}
|
||||
>
|
||||
{nextButtonProps?.children ??
|
||||
(isLastStep.value ? contextLocale.Finish : contextLocale.Next)}
|
||||
{isFunction(nextButtonProps?.children)
|
||||
? nextButtonProps?.children()
|
||||
: isLastStep.value
|
||||
? contextLocale.Finish
|
||||
: contextLocale.Next}
|
||||
</Button>
|
||||
</div>
|
||||
</div>
|
||||
|
|
|
@ -74,7 +74,7 @@ Almost anything can be represented in a tree structure. Examples include directo
|
|||
| disableCheckbox | Disables the checkbox of the treeNode | boolean | false | |
|
||||
| disabled | Disables the treeNode | boolean | false | |
|
||||
| icon | customize icon. When you pass component, whose render will receive full TreeNode props as component props | slot\|slot-scope | - | |
|
||||
| isLeaf | Determines if this is a leaf node(effective when `loadData` is specified) | boolean | false | |
|
||||
| isLeaf | Determines if this is a leaf node(effective when `loadData` is specified) | boolean | - | |
|
||||
| key | Used with (default)ExpandedKeys / (default)CheckedKeys / (default)SelectedKeys. P.S.: It must be unique in all of treeNodes of the tree! | string \| number | internal calculated position of treeNode | |
|
||||
| selectable | Set whether the treeNode can be selected | boolean | true | |
|
||||
| style | style | string\|object | - | |
|
||||
|
|
|
@ -75,7 +75,7 @@ coverDark: https://mdn.alipayobjects.com/huamei_7uahnr/afts/img/A*1GeUQJPTGUYAAA
|
|||
| disableCheckbox | 禁掉 checkbox | boolean | false | |
|
||||
| disabled | 禁掉响应 | boolean | false | |
|
||||
| icon | 自定义图标。可接收组件,props 为当前节点 props | slot\|slot-scope | - | |
|
||||
| isLeaf | 设置为叶子节点(设置了`loadData`时有效) | boolean | false | |
|
||||
| isLeaf | 设置为叶子节点(设置了`loadData`时有效) | boolean | - | |
|
||||
| key | 被树的 (default)ExpandedKeys / (default)CheckedKeys / (default)SelectedKeys 属性所用。注意:整个树范围内的所有节点的 key 值不能重复! | string \| number | 内部计算出的节点位置 | |
|
||||
| selectable | 设置节点是否可被选中 | boolean | true | |
|
||||
| style | 节点的 style | string\|object | - | |
|
||||
|
|
|
@ -1,5 +1,6 @@
|
|||
import type { CSSProperties, VNodeTypes } from 'vue';
|
||||
import { createApp } from 'vue';
|
||||
import { styleToString } from '../vc-util/Dom/css';
|
||||
|
||||
interface MeasureResult {
|
||||
finished: boolean;
|
||||
|
@ -23,13 +24,6 @@ const wrapperStyle: CSSProperties = {
|
|||
lineHeight: 'inherit',
|
||||
};
|
||||
|
||||
function styleToString(style: CSSStyleDeclaration) {
|
||||
// There are some different behavior between Firefox & Chrome.
|
||||
// We have to handle this ourself.
|
||||
const styleNames = Array.prototype.slice.apply(style);
|
||||
return styleNames.map(name => `${name}: ${style.getPropertyValue(name)};`).join('');
|
||||
}
|
||||
|
||||
function resetDomStyles(target: HTMLElement, origin: HTMLElement) {
|
||||
target.setAttribute('aria-hidden', 'true');
|
||||
const originStyle = window.getComputedStyle(origin);
|
||||
|
|
|
@ -1,4 +1,12 @@
|
|||
import { computed, defineComponent, onBeforeUnmount, onMounted, shallowRef, watch } from 'vue';
|
||||
import {
|
||||
computed,
|
||||
defineComponent,
|
||||
onBeforeUnmount,
|
||||
onMounted,
|
||||
shallowRef,
|
||||
watch,
|
||||
Transition,
|
||||
} from 'vue';
|
||||
import type { ExtractPropTypes, CSSProperties } from 'vue';
|
||||
import EyeOutlined from '@ant-design/icons-vue/EyeOutlined';
|
||||
import DeleteOutlined from '@ant-design/icons-vue/DeleteOutlined';
|
||||
|
@ -15,7 +23,7 @@ import type {
|
|||
} from '../interface';
|
||||
import type { VueNode } from '../../_util/type';
|
||||
import useConfigInject from '../../config-provider/hooks/useConfigInject';
|
||||
import Transition, { getTransitionProps } from '../../_util/transition';
|
||||
import { getTransitionProps } from '../../_util/transition';
|
||||
import { booleanType, stringType, functionType, arrayType, objectType } from '../../_util/type';
|
||||
|
||||
export const listItemProps = () => {
|
||||
|
|
|
@ -17,11 +17,12 @@ import {
|
|||
onMounted,
|
||||
shallowRef,
|
||||
watchEffect,
|
||||
TransitionGroup,
|
||||
} from 'vue';
|
||||
import { filterEmpty, initDefaultProps, isValidElement } from '../../_util/props-util';
|
||||
import type { VueNode } from '../../_util/type';
|
||||
import useConfigInject from '../../config-provider/hooks/useConfigInject';
|
||||
import { getTransitionGroupProps, TransitionGroup } from '../../_util/transition';
|
||||
import { getTransitionGroupProps } from '../../_util/transition';
|
||||
import collapseMotion from '../../_util/collapseMotion';
|
||||
|
||||
const HackSlot = (_, { slots }) => {
|
||||
|
|
|
@ -21,16 +21,16 @@ coverDark: https://mdn.alipayobjects.com/huamei_7uahnr/afts/img/A*l1nlSryXib8AAA
|
|||
|
||||
| 参数 | 说明 | 类型 | 默认值 | 版本 | |
|
||||
| --- | --- | --- | --- | --- | --- |
|
||||
| accept | 接受上传的文件类型, 详见 [input accept Attribute](https://developer.mozilla.org/en-US/docs/Web/HTML/Element/input/file#accept) | string | 无 | | |
|
||||
| action | 上传的地址 | string\|(file) => `Promise` | 无 | | |
|
||||
| beforeUpload | 上传文件之前的钩子,参数为上传的文件,若返回 `false` 则停止上传。支持返回一个 Promise 对象,Promise 对象 reject 时则停止上传,resolve 时开始上传( resolve 传入 `File` 或 `Blob` 对象则上传 resolve 传入对象)。 | (file, fileList) => `boolean` \| `Promise` | 无 | |
|
||||
| customRequest | 通过覆盖默认的上传行为,可以自定义自己的上传实现 | function | 无 | | |
|
||||
| data | 上传所需参数或返回上传参数的方法 | object\|(file) => object | 无 | | |
|
||||
| accept | 接受上传的文件类型, 详见 [input accept Attribute](https://developer.mozilla.org/en-US/docs/Web/HTML/Element/input/file#accept) | string | - | | |
|
||||
| action | 上传的地址 | string\|(file) => `Promise` | - | | |
|
||||
| beforeUpload | 上传文件之前的钩子,参数为上传的文件,若返回 `false` 则停止上传。支持返回一个 Promise 对象,Promise 对象 reject 时则停止上传,resolve 时开始上传( resolve 传入 `File` 或 `Blob` 对象则上传 resolve 传入对象)。 | (file, fileList) => `boolean` \| `Promise` | - | |
|
||||
| customRequest | 通过覆盖默认的上传行为,可以自定义自己的上传实现 | function | - | | |
|
||||
| data | 上传所需参数或返回上传参数的方法 | object\|(file) => object | - | | |
|
||||
| directory | 支持上传文件夹([caniuse](https://caniuse.com/#feat=input-file-directory)) | boolean | false | 3.0 | |
|
||||
| disabled | 是否禁用 | boolean | - | | |
|
||||
| downloadIcon | 自定义下载 icon | v-slot:iconRender="{file: UploadFile}" | - | 3.0 | |
|
||||
| fileList | 已经上传的文件列表(受控) | object\[] | 无 | | |
|
||||
| headers | 设置上传的请求头部,IE10 以上有效 | object | 无 | | |
|
||||
| fileList | 已经上传的文件列表(受控) | object\[] | - | | |
|
||||
| headers | 设置上传的请求头部,IE10 以上有效 | object | - | | |
|
||||
| iconRender | 自定义显示 icon | v-slot:iconRender="{file: UploadFile, listType?: UploadListType}" | - | 3.0 | |
|
||||
| isImageUrl | 自定义缩略图是否使用 <img /> 标签进行显示 | (file: UploadFile) => boolean | - | 3.0 | |
|
||||
| itemRender | 自定义上传列表项 | v-slot:itemRender="{originNode: VNode, file: UploadFile, fileList: object\[], actions: { download: function, preview: function, remove: function }" | - | 3.0 | |
|
||||
|
@ -40,7 +40,7 @@ coverDark: https://mdn.alipayobjects.com/huamei_7uahnr/afts/img/A*l1nlSryXib8AAA
|
|||
| multiple | 是否支持多选文件,`ie10+` 支持。开启后按住 ctrl 可选择多个文件。 | boolean | false | | |
|
||||
| name | 发到后台的文件参数名 | string | `file` | | |
|
||||
| openFileDialogOnClick | 点击打开文件对话框 | boolean | true | 3.0 | |
|
||||
| previewFile | 自定义文件预览逻辑 | (file: File \| Blob) => Promise<dataURL: string> | 无 | 1.5.0 | |
|
||||
| previewFile | 自定义文件预览逻辑 | (file: File \| Blob) => Promise<dataURL: string> | - | 1.5.0 | |
|
||||
| previewIcon | 自定义预览 icon | v-slot:iconRender="{file: UploadFile}" | - | 3.0 | |
|
||||
| progress | 自定义进度条样式 | [ProgressProps](/components/progress/#api)(仅支持 `type="line"`) | { strokeWidth: 2, showInfo: false } | 3.0 | |
|
||||
| removeIcon | 自定义删除 icon | v-slot:iconRender="{file: UploadFile}" | - | 3.0 | |
|
||||
|
@ -52,11 +52,11 @@ coverDark: https://mdn.alipayobjects.com/huamei_7uahnr/afts/img/A*l1nlSryXib8AAA
|
|||
|
||||
| 事件名称 | 说明 | 回调参数 | 版本 | |
|
||||
| --- | --- | --- | --- | --- |
|
||||
| change | 上传文件改变时的状态,详见 [change](#change) | function | 无 | |
|
||||
| change | 上传文件改变时的状态,详见 [change](#change) | function | - | |
|
||||
| download | 点击下载文件时的回调,如果没有指定,则默认跳转到文件 url 对应的标签页。 | function(file): void | 跳转新标签页 | 1.5.0 |
|
||||
| drop | 当文件被拖入上传区域时执行的回调功能 | (event: DragEvent) => void | - | 3.0 |
|
||||
| preview | 点击文件链接或预览图标时的回调 | function(file) | 无 | |
|
||||
| reject | 拖拽文件不符合 accept 类型时的回调 | function(fileList) | 无 | |
|
||||
| preview | 点击文件链接或预览图标时的回调 | function(file) | - | |
|
||||
| reject | 拖拽文件不符合 accept 类型时的回调 | function(fileList) | - | |
|
||||
| remove | 点击移除文件时的回调,返回值为 false 时不移除。支持返回一个 Promise 对象,Promise 对象 resolve(false) 或 reject 时不移除 | function(file): boolean \| Promise | - | 3.0 |
|
||||
|
||||
### UploadFile
|
||||
|
|
|
@ -1,7 +1,7 @@
|
|||
import type { CSSProperties, PropType } from 'vue';
|
||||
import { computed, ref, defineComponent, nextTick } from 'vue';
|
||||
import { Transition, computed, ref, defineComponent, nextTick } from 'vue';
|
||||
import type { MouseEventHandler } from '../_util/EventInterface';
|
||||
import Transition, { getTransitionProps } from '../_util/transition';
|
||||
import { getTransitionProps } from '../_util/transition';
|
||||
import dialogPropTypes from './IDialogPropTypes';
|
||||
import { offset } from './util';
|
||||
const sentinelStyle = { width: 0, height: 0, overflow: 'hidden', outline: 'none' };
|
||||
|
@ -143,9 +143,9 @@ export default defineComponent({
|
|||
onMousedown={onMousedown}
|
||||
onMouseup={onMouseup}
|
||||
>
|
||||
<div tabindex={0} ref={sentinelStartRef} style={sentinelStyle} aria-hidden="true" />
|
||||
<div tabindex={0} ref={sentinelStartRef} style={sentinelStyle} inert/>
|
||||
{modalRender ? modalRender({ originVNode: content }) : content}
|
||||
<div tabindex={0} ref={sentinelEndRef} style={sentinelStyle} aria-hidden="true" />
|
||||
<div tabindex={0} ref={sentinelEndRef} style={sentinelStyle} inert/>
|
||||
</div>
|
||||
) : null}
|
||||
</Transition>
|
||||
|
|
|
@ -1,5 +1,5 @@
|
|||
import { defineComponent } from 'vue';
|
||||
import Transition, { getTransitionProps } from '../_util/transition';
|
||||
import { defineComponent, Transition } from 'vue';
|
||||
import { getTransitionProps } from '../_util/transition';
|
||||
|
||||
export default defineComponent({
|
||||
compatConfig: { MODE: 3 },
|
||||
|
|
|
@ -1,4 +1,4 @@
|
|||
import type { ImgHTMLAttributes, CSSProperties, PropType } from 'vue';
|
||||
import type { CSSProperties, PropType } from 'vue';
|
||||
import { ref, watch, defineComponent, computed, onMounted, onUnmounted } from 'vue';
|
||||
import isNumber from 'lodash-es/isNumber';
|
||||
import cn from '../../_util/classNames';
|
||||
|
@ -32,6 +32,8 @@ export const imageProps = () => ({
|
|||
rootClassName: String,
|
||||
prefixCls: String,
|
||||
previewPrefixCls: String,
|
||||
width: [Number, String],
|
||||
height: [Number, String],
|
||||
previewMask: {
|
||||
type: [Boolean, Function] as PropType<false | (() => any)>,
|
||||
default: undefined,
|
||||
|
@ -201,8 +203,6 @@ const ImageInternal = defineComponent({
|
|||
placeholder,
|
||||
wrapperStyle,
|
||||
rootClassName,
|
||||
} = props;
|
||||
const {
|
||||
width,
|
||||
height,
|
||||
crossorigin,
|
||||
|
@ -213,7 +213,7 @@ const ImageInternal = defineComponent({
|
|||
usemap,
|
||||
class: cls,
|
||||
style,
|
||||
} = attrs as ImgHTMLAttributes;
|
||||
} = { ...props, ...attrs } as any;
|
||||
const { icons, maskClassName, ...dialogProps } = preview.value;
|
||||
|
||||
const wrappperClass = cn(prefixCls, wrapperClassName, rootClassName, {
|
||||
|
|
|
@ -2,6 +2,7 @@ import { getTransitionGroupProps } from '../_util/transition';
|
|||
import type { Key, VueNode } from '../_util/type';
|
||||
import type { CSSProperties } from 'vue';
|
||||
import {
|
||||
toRaw,
|
||||
shallowRef,
|
||||
createVNode,
|
||||
computed,
|
||||
|
@ -72,10 +73,10 @@ type NotificationState = {
|
|||
holderCallback?: HolderReadyCallback;
|
||||
}[];
|
||||
|
||||
const Notification = defineComponent<NotificationProps>({
|
||||
const Notification = defineComponent({
|
||||
name: 'Notification',
|
||||
inheritAttrs: false,
|
||||
props: ['prefixCls', 'transitionName', 'animation', 'maxCount', 'closeIcon', 'hashId'] as any,
|
||||
props: ['prefixCls', 'transitionName', 'animation', 'maxCount', 'closeIcon', 'hashId'],
|
||||
setup(props, { attrs, expose, slots }) {
|
||||
const hookRefs = new Map<Key, HTMLDivElement>();
|
||||
const notices = ref<NotificationState>([]);
|
||||
|
@ -125,7 +126,7 @@ const Notification = defineComponent<NotificationProps>({
|
|||
};
|
||||
|
||||
const remove = (removeKey: Key) => {
|
||||
notices.value = notices.value.filter(({ notice: { key, userPassKey } }) => {
|
||||
notices.value = toRaw(notices.value as any).filter(({ notice: { key, userPassKey } }) => {
|
||||
const mergedKey = userPassKey || key;
|
||||
return mergedKey !== removeKey;
|
||||
});
|
||||
|
|
|
@ -39,14 +39,15 @@ const overflowProps = () => {
|
|||
/** When set to `full`, ssr will render full items by default and remove at client side */
|
||||
ssr: String as PropType<'full'>,
|
||||
onMousedown: Function as PropType<MouseEventHandler>,
|
||||
role: String,
|
||||
};
|
||||
};
|
||||
type InterOverflowProps = Partial<ExtractPropTypes<ReturnType<typeof overflowProps>>>;
|
||||
export type OverflowProps = HTMLAttributes & InterOverflowProps;
|
||||
const Overflow = defineComponent<OverflowProps>({
|
||||
const Overflow = defineComponent({
|
||||
name: 'Overflow',
|
||||
inheritAttrs: false,
|
||||
props: overflowProps() as any,
|
||||
props: overflowProps(),
|
||||
emits: ['visibleChange'],
|
||||
setup(props, { attrs, emit, slots }) {
|
||||
const fullySSR = computed(() => props.ssr === 'full');
|
||||
|
@ -331,6 +332,7 @@ const Overflow = defineComponent<OverflowProps>({
|
|||
class={classNames(!invalidate.value && prefixCls, className)}
|
||||
style={style}
|
||||
onMousedown={onMousedown}
|
||||
role={props.role}
|
||||
{...restAttrs}
|
||||
>
|
||||
{mergedData.value.map(internalRenderItemNode)}
|
||||
|
|
|
@ -22,7 +22,8 @@ export default defineComponent({
|
|||
{props.presets.map(({ label, value }, index) => (
|
||||
<li
|
||||
key={index}
|
||||
onClick={() => {
|
||||
onClick={e => {
|
||||
e.stopPropagation();
|
||||
props.onClick(value);
|
||||
}}
|
||||
onMouseenter={() => {
|
||||
|
|
|
@ -18,9 +18,9 @@ export type TimeUnitColumnProps = {
|
|||
onSelect?: (value: number) => void;
|
||||
};
|
||||
|
||||
export default defineComponent<TimeUnitColumnProps>({
|
||||
export default defineComponent({
|
||||
name: 'TimeUnitColumn',
|
||||
props: ['prefixCls', 'units', 'onSelect', 'value', 'active', 'hideDisabledOptions'] as any,
|
||||
props: ['prefixCls', 'units', 'onSelect', 'value', 'active', 'hideDisabledOptions'],
|
||||
setup(props) {
|
||||
const { open } = useInjectPanel();
|
||||
|
||||
|
|
|
@ -343,6 +343,14 @@ export default defineComponent({
|
|||
if (mergedOpen.value !== nextOpen && !props.disabled) {
|
||||
setInnerOpen(nextOpen);
|
||||
props.onDropdownVisibleChange && props.onDropdownVisibleChange(nextOpen);
|
||||
|
||||
if (!nextOpen && popupFocused.value) {
|
||||
popupFocused.value = false;
|
||||
setMockFocused(false, () => {
|
||||
focusRef.value = false;
|
||||
blurRef.value = false;
|
||||
});
|
||||
}
|
||||
}
|
||||
};
|
||||
|
||||
|
|
|
@ -48,7 +48,6 @@ const Input = defineComponent({
|
|||
setup(props) {
|
||||
let blurTimeout = null;
|
||||
const VCSelectContainerEvent = inject('VCSelectContainerEvent') as any;
|
||||
|
||||
return () => {
|
||||
const {
|
||||
prefixCls,
|
||||
|
@ -97,6 +96,7 @@ const Input = defineComponent({
|
|||
ref: inputRef,
|
||||
disabled,
|
||||
tabindex,
|
||||
lazy: false,
|
||||
autocomplete: autocomplete || 'off',
|
||||
autofocus,
|
||||
class: classNames(`${prefixCls}-selection-search-input`, inputNode?.props?.class),
|
||||
|
|
|
@ -2,7 +2,7 @@ import TransBtn from '../TransBtn';
|
|||
import type { InnerSelectorProps } from './interface';
|
||||
import Input from './Input';
|
||||
import type { Ref, PropType } from 'vue';
|
||||
import { computed, defineComponent, onMounted, shallowRef, watch } from 'vue';
|
||||
import { ref, watchEffect, computed, defineComponent, onMounted, shallowRef, watch } from 'vue';
|
||||
import classNames from '../../_util/classNames';
|
||||
import pickAttrs from '../../_util/pickAttrs';
|
||||
import PropTypes from '../../_util/vue-types';
|
||||
|
@ -24,6 +24,8 @@ type SelectorProps = InnerSelectorProps & {
|
|||
tagRender?: (props: CustomTagProps) => VueNode;
|
||||
onToggleOpen: any;
|
||||
|
||||
compositionStatus: boolean;
|
||||
|
||||
// Motion
|
||||
choiceTransitionName?: string;
|
||||
|
||||
|
@ -46,7 +48,7 @@ const props = {
|
|||
autocomplete: String,
|
||||
activeDescendantId: String,
|
||||
tabindex: PropTypes.oneOfType([PropTypes.number, PropTypes.string]),
|
||||
|
||||
compositionStatus: Boolean,
|
||||
removeIcon: PropTypes.any,
|
||||
choiceTransitionName: String,
|
||||
|
||||
|
@ -91,11 +93,14 @@ const SelectSelector = defineComponent<SelectorProps>({
|
|||
() =>
|
||||
props.mode === 'tags' || ((props.showSearch && (props.open || focused.value)) as boolean),
|
||||
);
|
||||
|
||||
const targetValue = ref('');
|
||||
watchEffect(() => {
|
||||
targetValue.value = inputValue.value;
|
||||
});
|
||||
// We measure width and set to the input immediately
|
||||
onMounted(() => {
|
||||
watch(
|
||||
inputValue,
|
||||
targetValue,
|
||||
() => {
|
||||
inputWidth.value = measureRef.value.scrollWidth;
|
||||
},
|
||||
|
@ -202,6 +207,14 @@ const SelectSelector = defineComponent<SelectorProps>({
|
|||
return defaultRenderSelector(content, content, false);
|
||||
}
|
||||
|
||||
const handleInput = (e: Event) => {
|
||||
const composing = (e.target as any).composing;
|
||||
targetValue.value = (e.target as any).value;
|
||||
if (!composing) {
|
||||
props.onInputChange(e);
|
||||
}
|
||||
};
|
||||
|
||||
return () => {
|
||||
const {
|
||||
id,
|
||||
|
@ -215,14 +228,13 @@ const SelectSelector = defineComponent<SelectorProps>({
|
|||
autocomplete,
|
||||
activeDescendantId,
|
||||
tabindex,
|
||||
onInputChange,
|
||||
compositionStatus,
|
||||
onInputPaste,
|
||||
onInputKeyDown,
|
||||
onInputMouseDown,
|
||||
onInputCompositionStart,
|
||||
onInputCompositionEnd,
|
||||
} = props;
|
||||
|
||||
// >>> Input Node
|
||||
const inputNode = (
|
||||
<div
|
||||
|
@ -241,10 +253,10 @@ const SelectSelector = defineComponent<SelectorProps>({
|
|||
autocomplete={autocomplete}
|
||||
editable={inputEditable.value}
|
||||
activeDescendantId={activeDescendantId}
|
||||
value={inputValue.value}
|
||||
value={targetValue.value}
|
||||
onKeydown={onInputKeyDown}
|
||||
onMousedown={onInputMouseDown}
|
||||
onChange={onInputChange}
|
||||
onChange={handleInput}
|
||||
onPaste={onInputPaste}
|
||||
onCompositionstart={onInputCompositionStart}
|
||||
onCompositionend={onInputCompositionEnd}
|
||||
|
@ -256,7 +268,7 @@ const SelectSelector = defineComponent<SelectorProps>({
|
|||
|
||||
{/* Measure Node */}
|
||||
<span ref={measureRef} class={`${selectionPrefixCls.value}-search-mirror`} aria-hidden>
|
||||
{inputValue.value}
|
||||
{targetValue.value}
|
||||
</span>
|
||||
</div>
|
||||
);
|
||||
|
@ -277,7 +289,7 @@ const SelectSelector = defineComponent<SelectorProps>({
|
|||
return (
|
||||
<>
|
||||
{selectionNode}
|
||||
{!values.length && !inputValue.value && (
|
||||
{!values.length && !inputValue.value && !compositionStatus && (
|
||||
<span class={`${selectionPrefixCls.value}-placeholder`}>{placeholder}</span>
|
||||
)}
|
||||
</>
|
||||
|
|
|
@ -10,6 +10,7 @@ interface SelectorProps extends InnerSelectorProps {
|
|||
inputElement: VueNode;
|
||||
activeValue: string;
|
||||
optionLabelRender: Function;
|
||||
compositionStatus: boolean;
|
||||
}
|
||||
const props = {
|
||||
inputElement: PropTypes.any,
|
||||
|
@ -20,6 +21,7 @@ const props = {
|
|||
searchValue: String,
|
||||
inputRef: PropTypes.any,
|
||||
placeholder: PropTypes.any,
|
||||
compositionStatus: { type: Boolean, default: undefined },
|
||||
disabled: { type: Boolean, default: undefined },
|
||||
mode: String,
|
||||
showSearch: { type: Boolean, default: undefined },
|
||||
|
@ -65,7 +67,9 @@ const SingleSelector = defineComponent<SelectorProps>({
|
|||
|
||||
// Not show text when closed expect combobox mode
|
||||
const hasTextInput = computed(() =>
|
||||
props.mode !== 'combobox' && !props.open && !props.showSearch ? false : !!inputValue.value,
|
||||
props.mode !== 'combobox' && !props.open && !props.showSearch
|
||||
? false
|
||||
: !!inputValue.value || props.compositionStatus,
|
||||
);
|
||||
|
||||
const title = computed(() => {
|
||||
|
@ -86,6 +90,13 @@ const SingleSelector = defineComponent<SelectorProps>({
|
|||
</span>
|
||||
);
|
||||
};
|
||||
const handleInput = (e: Event) => {
|
||||
const composing = (e.target as any).composing;
|
||||
if (!composing) {
|
||||
inputChanged.value = true;
|
||||
props.onInputChange(e);
|
||||
}
|
||||
};
|
||||
|
||||
return () => {
|
||||
const {
|
||||
|
@ -103,7 +114,6 @@ const SingleSelector = defineComponent<SelectorProps>({
|
|||
optionLabelRender,
|
||||
onInputKeyDown,
|
||||
onInputMouseDown,
|
||||
onInputChange,
|
||||
onInputPaste,
|
||||
onInputCompositionStart,
|
||||
onInputCompositionEnd,
|
||||
|
@ -147,10 +157,7 @@ const SingleSelector = defineComponent<SelectorProps>({
|
|||
value={inputValue.value}
|
||||
onKeydown={onInputKeyDown}
|
||||
onMousedown={onInputMouseDown}
|
||||
onChange={e => {
|
||||
inputChanged.value = true;
|
||||
onInputChange(e as any);
|
||||
}}
|
||||
onChange={handleInput}
|
||||
onPaste={onInputPaste}
|
||||
onCompositionstart={onInputCompositionStart}
|
||||
onCompositionend={onInputCompositionEnd}
|
||||
|
|
|
@ -15,7 +15,7 @@ import type { CustomTagProps, DisplayValueType, Mode, RenderNode } from '../Base
|
|||
import { isValidateOpenKey } from '../utils/keyUtil';
|
||||
import useLock from '../hooks/useLock';
|
||||
import type { PropType } from 'vue';
|
||||
import { defineComponent } from 'vue';
|
||||
import { defineComponent, ref } from 'vue';
|
||||
import createRef from '../../_util/createRef';
|
||||
import PropTypes from '../../_util/vue-types';
|
||||
import type { VueNode } from '../../_util/type';
|
||||
|
@ -124,7 +124,7 @@ const Selector = defineComponent<SelectorProps>({
|
|||
} as any,
|
||||
setup(props, { expose }) {
|
||||
const inputRef = createRef();
|
||||
let compositionStatus = false;
|
||||
const compositionStatus = ref(false);
|
||||
|
||||
// ====================== Input ======================
|
||||
const [getInputMouseDown, setInputMouseDown] = useLock(0);
|
||||
|
@ -140,7 +140,12 @@ const Selector = defineComponent<SelectorProps>({
|
|||
props.onInputKeyDown(event);
|
||||
}
|
||||
|
||||
if (which === KeyCode.ENTER && props.mode === 'tags' && !compositionStatus && !props.open) {
|
||||
if (
|
||||
which === KeyCode.ENTER &&
|
||||
props.mode === 'tags' &&
|
||||
!compositionStatus.value &&
|
||||
!props.open
|
||||
) {
|
||||
// When menu isn't open, OptionList won't trigger a value change
|
||||
// So when enter is pressed, the tag's input value should be emitted here to let selector know
|
||||
props.onSearchSubmit((event.target as HTMLInputElement).value);
|
||||
|
@ -163,17 +168,17 @@ const Selector = defineComponent<SelectorProps>({
|
|||
let pastedText = null;
|
||||
|
||||
const triggerOnSearch = (value: string) => {
|
||||
if (props.onSearch(value, true, compositionStatus) !== false) {
|
||||
if (props.onSearch(value, true, compositionStatus.value) !== false) {
|
||||
props.onToggleOpen(true);
|
||||
}
|
||||
};
|
||||
|
||||
const onInputCompositionStart = () => {
|
||||
compositionStatus = true;
|
||||
compositionStatus.value = true;
|
||||
};
|
||||
|
||||
const onInputCompositionEnd = (e: InputEvent) => {
|
||||
compositionStatus = false;
|
||||
compositionStatus.value = false;
|
||||
// Trigger search again to support `tokenSeparators` with typewriting
|
||||
if (props.mode !== 'combobox') {
|
||||
triggerOnSearch((e.target as HTMLInputElement).value);
|
||||
|
@ -251,6 +256,7 @@ const Selector = defineComponent<SelectorProps>({
|
|||
onInputMouseDown: onInternalInputMouseDown,
|
||||
onInputChange,
|
||||
onInputPaste,
|
||||
compositionStatus: compositionStatus.value,
|
||||
onInputCompositionStart,
|
||||
onInputCompositionEnd,
|
||||
};
|
||||
|
|
|
@ -7,7 +7,7 @@ const Track = (_, { attrs }) => {
|
|||
length = Math.abs(length);
|
||||
offset = 100 - offset;
|
||||
}
|
||||
const positonStyle = vertical
|
||||
const positionStyle = vertical
|
||||
? {
|
||||
[reverse ? 'top' : 'bottom']: `${offset}%`,
|
||||
[reverse ? 'bottom' : 'top']: 'auto',
|
||||
|
@ -21,7 +21,7 @@ const Track = (_, { attrs }) => {
|
|||
|
||||
const elStyle = {
|
||||
...style,
|
||||
...positonStyle,
|
||||
...positionStyle,
|
||||
};
|
||||
return included ? <div class={className} style={elStyle} /> : null;
|
||||
};
|
||||
|
|
|
@ -77,7 +77,7 @@ export interface CellProps<RecordType = DefaultRecordType> {
|
|||
|
||||
transformCellText?: TransformCellText<RecordType>;
|
||||
}
|
||||
export default defineComponent<CellProps>({
|
||||
export default defineComponent({
|
||||
name: 'Cell',
|
||||
props: [
|
||||
'prefixCls',
|
||||
|
@ -104,7 +104,7 @@ export default defineComponent<CellProps>({
|
|||
'column',
|
||||
'cellType',
|
||||
'transformCellText',
|
||||
] as any,
|
||||
],
|
||||
setup(props, { slots }) {
|
||||
const contextSlots = useInjectSlots();
|
||||
const { onHover, startRow, endRow } = useInjectHover();
|
||||
|
@ -318,7 +318,7 @@ export default defineComponent<CellProps>({
|
|||
|
||||
// ====================== Render ======================
|
||||
let title: string;
|
||||
const ellipsisConfig: CellEllipsisType = ellipsis === true ? { showTitle: true } : ellipsis;
|
||||
const ellipsisConfig = ellipsis === true ? { showTitle: true } : ellipsis;
|
||||
if (ellipsisConfig && (ellipsisConfig.showTitle || rowType === 'header')) {
|
||||
if (typeof childNode === 'string' || typeof childNode === 'number') {
|
||||
title = childNode.toString();
|
||||
|
|
|
@ -12,9 +12,9 @@ export interface SummaryCellProps {
|
|||
align?: AlignType;
|
||||
}
|
||||
|
||||
export default defineComponent<SummaryCellProps>({
|
||||
export default defineComponent({
|
||||
name: 'ATableSummaryCell',
|
||||
props: ['index', 'colSpan', 'rowSpan', 'align'] as any,
|
||||
props: ['index', 'colSpan', 'rowSpan', 'align'],
|
||||
setup(props, { attrs, slots }) {
|
||||
const tableContext = useInjectTable();
|
||||
const summaryContext = useInjectSummary();
|
||||
|
|
|
@ -149,7 +149,7 @@ export interface TableProps<RecordType = DefaultRecordType> {
|
|||
transformCellText?: TransformCellText<RecordType>;
|
||||
}
|
||||
|
||||
export default defineComponent<TableProps<DefaultRecordType>>({
|
||||
export default defineComponent({
|
||||
name: 'VcTable',
|
||||
inheritAttrs: false,
|
||||
props: [
|
||||
|
@ -191,7 +191,7 @@ export default defineComponent<TableProps<DefaultRecordType>>({
|
|||
'canExpandable',
|
||||
'onUpdateInternalRefs',
|
||||
'transformCellText',
|
||||
] as any,
|
||||
],
|
||||
emits: ['expand', 'expandedRowsChange', 'updateInternalRefs', 'update:expandedRowKeys'],
|
||||
setup(props, { attrs, slots, emit }) {
|
||||
const mergedData = computed(() => props.data || EMPTY_DATA);
|
||||
|
@ -271,7 +271,7 @@ export default defineComponent<TableProps<DefaultRecordType>>({
|
|||
// defalutXxxx 仅仅第一次生效
|
||||
stop();
|
||||
|
||||
const mergedExpandedKeys = computed(
|
||||
const mergedExpandedKeys = computed<Set<Key>>(
|
||||
() => new Set(props.expandedRowKeys || innerExpandedKeys.value || []),
|
||||
);
|
||||
|
||||
|
@ -282,9 +282,9 @@ export default defineComponent<TableProps<DefaultRecordType>>({
|
|||
const hasKey = mergedExpandedKeys.value.has(key);
|
||||
if (hasKey) {
|
||||
mergedExpandedKeys.value.delete(key);
|
||||
newExpandedKeys = [...mergedExpandedKeys.value];
|
||||
newExpandedKeys = [...(mergedExpandedKeys.value as any)];
|
||||
} else {
|
||||
newExpandedKeys = [...mergedExpandedKeys.value, key];
|
||||
newExpandedKeys = [...(mergedExpandedKeys.value as any), key];
|
||||
}
|
||||
innerExpandedKeys.value = newExpandedKeys;
|
||||
|
||||
|
|
|
@ -108,7 +108,7 @@ function useColumns<RecordType>(
|
|||
prefixCls?: Ref<string>;
|
||||
columns?: Ref<ColumnsType<RecordType>>;
|
||||
expandable: Ref<boolean>;
|
||||
expandedKeys: Ref<Set<Key>>;
|
||||
expandedKeys: ComputedRef<Set<Key>>;
|
||||
getRowKey: Ref<GetRowKey<RecordType>>;
|
||||
onTriggerExpand: TriggerEventHandler<RecordType>;
|
||||
expandIcon?: Ref<RenderExpandIcon<RecordType>>;
|
||||
|
|
|
@ -110,7 +110,7 @@ export default defineComponent({
|
|||
() => {
|
||||
treeData.value =
|
||||
props.treeData !== undefined
|
||||
? toRaw(props.treeData).slice()
|
||||
? props.treeData.slice()
|
||||
: convertTreeToData(toRaw(props.children));
|
||||
},
|
||||
{
|
||||
|
|
|
@ -204,11 +204,11 @@ export default defineComponent({
|
|||
class={mergedClassName}
|
||||
onMouseenter={onMouseenter}
|
||||
onMouseleave={onMouseleave}
|
||||
onMousedown={withModifiers(onMousedown, ['capture'])}
|
||||
onMousedown={withModifiers(onMousedown, ['capture'] as any)}
|
||||
{...{
|
||||
[supportsPassive ? 'onTouchstartPassive' : 'onTouchstart']: withModifiers(
|
||||
onTouchstart,
|
||||
['capture'],
|
||||
['capture'] as any,
|
||||
),
|
||||
}}
|
||||
style={mergedStyle}
|
||||
|
|
|
@ -112,3 +112,22 @@ export function getOffset(node: any) {
|
|||
(docElem.clientTop || document.body.clientTop || 0),
|
||||
};
|
||||
}
|
||||
|
||||
export function styleToString(style: CSSStyleDeclaration) {
|
||||
// There are some different behavior between Firefox & Chrome.
|
||||
// We have to handle this ourself.
|
||||
const styleNames = Array.prototype.slice.apply(style);
|
||||
return styleNames.map(name => `${name}: ${style.getPropertyValue(name)};`).join('');
|
||||
}
|
||||
|
||||
export function styleObjectToString(style: Record<string, string>) {
|
||||
return Object.keys(style).reduce((acc, name) => {
|
||||
const styleValue = style[name];
|
||||
if (typeof styleValue === 'undefined' || styleValue === null) {
|
||||
return acc;
|
||||
}
|
||||
|
||||
acc += `${name}: ${style[name]};`;
|
||||
return acc;
|
||||
}, '');
|
||||
}
|
||||
|
|
|
@ -1,6 +1,6 @@
|
|||
{
|
||||
"name": "ant-design-vue",
|
||||
"version": "4.2.1",
|
||||
"version": "4.2.5",
|
||||
"title": "Ant Design Vue",
|
||||
"description": "An enterprise-class UI design language and Vue-based implementation",
|
||||
"keywords": [
|
||||
|
|
|
@ -37,7 +37,7 @@ import More from './More.vue';
|
|||
import Navigation from './Navigation.vue';
|
||||
import Ecosystem from './Ecosystem.vue';
|
||||
import { version } from 'ant-design-vue';
|
||||
import { isZhCN, isLocalStorageNameSupported, getLocalizedPathname } from '../../utils/util';
|
||||
import { isZhCN, getLocalizedPathname } from '../../utils/util';
|
||||
import { useRoute } from 'vue-router';
|
||||
export default defineComponent({
|
||||
name: 'HeaderMenu',
|
||||
|
@ -58,9 +58,7 @@ export default defineComponent({
|
|||
const currentProtocol = `${window.location.protocol}//`;
|
||||
const currentHref = window.location.href.substring(currentProtocol.length);
|
||||
|
||||
if (isLocalStorageNameSupported()) {
|
||||
localStorage.setItem('locale', isZhCN(pathname) ? 'en-US' : 'zh-CN');
|
||||
}
|
||||
localStorage.setItem('locale', isZhCN(pathname) ? 'en-US' : 'zh-CN');
|
||||
|
||||
window.location.href =
|
||||
currentProtocol +
|
||||
|
|
|
@ -1,33 +0,0 @@
|
|||
export function isZhCN(name) {
|
||||
return /-cn\/?$/.test(name);
|
||||
}
|
||||
export function isLocalStorageNameSupported() {
|
||||
const testKey = 'test';
|
||||
const storage = window.localStorage;
|
||||
try {
|
||||
storage.setItem(testKey, '1');
|
||||
storage.removeItem(testKey);
|
||||
return true;
|
||||
} catch (error) {
|
||||
return false;
|
||||
}
|
||||
}
|
||||
export function getLocalizedPathname(path, zhCN, query = {}, hash) {
|
||||
const pathname = path.startsWith('/') ? path : `/${path}`;
|
||||
let fullPath;
|
||||
if (!zhCN) {
|
||||
// to enUS
|
||||
fullPath = /\/?index-cn/.test(pathname) ? '/' : pathname.replace('-cn', '');
|
||||
} else if (pathname === '/') {
|
||||
fullPath = '/index-cn';
|
||||
} else if (pathname.endsWith('/')) {
|
||||
fullPath = pathname.replace(/\/$/, '-cn/');
|
||||
} else {
|
||||
fullPath = `${pathname}-cn`;
|
||||
}
|
||||
if (hash) {
|
||||
const localHash = hash[zhCN ? 'zhCN' : 'enUS'];
|
||||
fullPath += `#${localHash}`;
|
||||
}
|
||||
return { path: fullPath, query };
|
||||
}
|
|
@ -2,18 +2,6 @@ export function isZhCN(name: string): boolean {
|
|||
return /-cn\/?$/.test(name);
|
||||
}
|
||||
|
||||
export function isLocalStorageNameSupported() {
|
||||
const testKey = 'test';
|
||||
const storage = window.localStorage;
|
||||
try {
|
||||
storage.setItem(testKey, '1');
|
||||
storage.removeItem(testKey);
|
||||
return true;
|
||||
} catch (error) {
|
||||
return false;
|
||||
}
|
||||
}
|
||||
|
||||
export function getLocalizedPathname(
|
||||
path: string,
|
||||
zhCN?: boolean,
|
||||
|
|
|
@ -12,27 +12,37 @@ The following CodeSandbox demo is the simplest use case, and it's also a good ha
|
|||
|
||||
## Import ant-design-vue
|
||||
|
||||
### 1. Installation
|
||||
### 1. Create a New Project
|
||||
|
||||
[vue-cli](https://github.com/vuejs/vue-cli)
|
||||
If you need to create a new project, you can use [Vite](https://github.com/vitejs/vite), [Rsbuild](https://github.com/web-infra-dev/rsbuild), or [Vue CLI](https://github.com/vuejs/vue-cli).
|
||||
|
||||
Please initialize the project using the command line:
|
||||
|
||||
- Vite:
|
||||
|
||||
```bash
|
||||
$ npm create vite@latest
|
||||
```
|
||||
|
||||
- Rsbuild:
|
||||
|
||||
```bash
|
||||
$ npm create rsbuild@latest
|
||||
```
|
||||
|
||||
- Vue CLI:
|
||||
|
||||
```bash
|
||||
$ npm install -g @vue/cli
|
||||
# OR
|
||||
$ yarn global add @vue/cli
|
||||
```
|
||||
|
||||
### 2. Create a New Project
|
||||
|
||||
A new project can be created using CLI tools.
|
||||
|
||||
```bash
|
||||
$ vue create antd-demo
|
||||
```
|
||||
|
||||
And, setup your vue project configuration.
|
||||
> Vue CLI is no longer maintained, so it is not recommended to use.
|
||||
|
||||
### 3. Use antd's Components
|
||||
### 2. Use antd's Components
|
||||
|
||||
#### Install
|
||||
|
||||
|
@ -95,7 +105,7 @@ In this way, component sub-components, such as Button and ButtonGroup, need to b
|
|||
</script>
|
||||
```
|
||||
|
||||
### 4. Component list
|
||||
### 3. Component list
|
||||
|
||||
[Component list](https://github.com/vueComponent/ant-design-vue/blob/main/components/components.ts)
|
||||
|
||||
|
|
|
@ -12,29 +12,39 @@ Ant Design Vue 致力于提供给程序员**愉悦**的开发体验。
|
|||
|
||||
## 引入 ant-design-vue
|
||||
|
||||
### 1. 安装脚手架工具
|
||||
### 1. 新建项目
|
||||
|
||||
[vue-cli](https://github.com/vuejs/vue-cli)
|
||||
如果你需要新建一个项目,可以使用 [Vite](https://github.com/vitejs/vite)、[Rsbuild](https://github.com/web-infra-dev/rsbuild) 或 [Vue CLI](https://github.com/vuejs/vue-cli)。
|
||||
|
||||
请使用命令行来初始化项目:
|
||||
|
||||
- Vite:
|
||||
|
||||
```bash
|
||||
$ npm create vite@latest
|
||||
```
|
||||
|
||||
- Rsbuild:
|
||||
|
||||
```bash
|
||||
$ npm create rsbuild@latest
|
||||
```
|
||||
|
||||
- Vue CLI:
|
||||
|
||||
```bash
|
||||
$ npm install -g @vue/cli
|
||||
# OR
|
||||
$ yarn global add @vue/cli
|
||||
```
|
||||
|
||||
### 2. 创建一个项目
|
||||
|
||||
使用命令行进行初始化。
|
||||
|
||||
```bash
|
||||
$ vue create antd-demo
|
||||
```
|
||||
|
||||
并配置项目。
|
||||
> Vue CLI 已经停止迭代,因此不推荐使用。
|
||||
|
||||
若安装缓慢报错,可尝试用 `cnpm` 或别的镜像源自行安装:`rm -rf node_modules && cnpm install`。
|
||||
|
||||
### 3. 使用组件
|
||||
### 2. 使用组件
|
||||
|
||||
#### 安装
|
||||
|
||||
|
|
|
@ -153,7 +153,7 @@ Remove `babel-plugin-import` from package.json and modify `.babelrc`:
|
|||
|
||||
### Legacy browser support
|
||||
|
||||
Ant Design Vue v4 using `:where` css selector to reduce CSS-in-JS hash priority. You can use `StyleProvider` to cancel this function. Please ref [Compatible adjustment](/docs/vue/customize-theme#compatible-adjustment).
|
||||
Ant Design Vue v4 using `:where` css selector to reduce CSS-in-JS hash priority. You can use `StyleProvider` to cancel this function. Please ref [Compatible adjustment](/docs/vue/compatible-style).
|
||||
|
||||
## Encounter problems
|
||||
|
||||
|
|
|
@ -155,7 +155,7 @@ or
|
|||
|
||||
### 旧版浏览器兼容
|
||||
|
||||
Ant Design Vue v4 使用 `:where` css selector 降低 CSS-in-JS hash 值优先级,如果你需要支持旧版本浏览器(如 IE 11、360 浏览器 等等)。可以通过 `StyleProvider` 去除降权操作。详情请参阅 [兼容性调整](/docs/vue/customize-theme-cn#兼容性调整)。
|
||||
Ant Design Vue v4 使用 `:where` css selector 降低 CSS-in-JS hash 值优先级,如果你需要支持旧版本浏览器(如 IE 11、360 浏览器 等等)。可以通过 `StyleProvider` 去除降权操作。详情请参阅 [兼容性调整](/docs/vue/compatible-style-cn)。
|
||||
|
||||
## 遇到问题
|
||||
|
||||
|
|
Loading…
Reference in New Issue