diff --git a/CHANGELOG.en-US.md b/CHANGELOG.en-US.md index fb0b3bf40..b13cc6ce1 100644 --- a/CHANGELOG.en-US.md +++ b/CHANGELOG.en-US.md @@ -57,6 +57,43 @@ - 💄 优化 Upload 操作按钮的样式细节。 - 🐞 修复 Switch 在暗黑主题下关闭时的颜色问题。 +## 3.2.15 + +`2022-11-10` + +- 🐞 Fix the problem of preview image error when `Image` is deleted dynamically + +## 3.2.14 + +`2022-11-07` + +- 🐞 Fix the problem of dynamic theme failure when custom `prefixCls` [#6063](https://github.com/vueComponent/ant-design-vue/issues/6063) +- 🐞 Fix `DatePicker` error when using select and other popup components as slots [#6062](https://github.com/vueComponent/ant-design-vue/issues/6062) +- 🐞 Fix `DirectoryTree` not exposing scrollTo method [#6067](https://github.com/vueComponent/ant-design-vue/issues/6067) +- 🐞 Fix `RangePicker` popup position does not change [#6073](https://github.com/vueComponent/ant-design-vue/issues/6073) + +## 3.2.13 + +`2022-10-08` + +- 🌟 Support Vue 3 upgrade tool `@vue/compat` [#5973](https://github.com/vueComponent/ant-design-vue/issues/5973) +- 🌟 Cascader add tagRender slot [#5954](https://github.com/vueComponent/ant-design-vue/issues/5954) +- 🐞 Fix image flickering issue when Image preview is closed [#5955](https://github.com/vueComponent/ant-design-vue/issues/5955) +- 🐞 Fix Tag close icon style display misplaced [#5956](https://github.com/vueComponent/ant-design-vue/issues/5956) +- 🐞 Fix Table loading property ts type error [#5964](https://github.com/vueComponent/ant-design-vue/issues/5964) +- 🐞 Fix Transfer deletion exception [#5975](https://github.com/vueComponent/ant-design-vue/issues/5975) +- 🐞 Fix the scroll shadow display issue of Table fixed column [#5996](https://github.com/vueComponent/ant-design-vue/issues/5996) +- 🐞 Fix DirectoryTree's default expansion failure issue when customizing fieldNames [#6007](https://github.com/vueComponent/ant-design-vue/issues/6007) + +## 3.2.12 + +`2022-09-02` + +- 🐞 Fix DescriptionItem labelStyle does not take effect [#5920](https://github.com/vueComponent/ant-design-vue/issues/5920) +- 🌟 Typography copy button prevents bubbling [##5746](https://github.com/vueComponent/ant-design-vue/issues/5746) +- 🐞 Fix table merged column scroll shadow occlusion issue [#5786](https://github.com/vueComponent/ant-design-vue/issues/5786) +- 🐞 Fix the inconsistency between css var and ConfigProvider variables [#5929](https://github.com/vueComponent/ant-design-vue/issues/5929) + ## 3.2.11 `2022-08-08` diff --git a/CHANGELOG.zh-CN.md b/CHANGELOG.zh-CN.md index 7fc8ea796..8b7849dbf 100644 --- a/CHANGELOG.zh-CN.md +++ b/CHANGELOG.zh-CN.md @@ -57,6 +57,43 @@ - 💄 优化 Upload 操作按钮的样式细节。 - 🐞 修复 Switch 在暗黑主题下关闭时的颜色问题。 +## 3.2.15 + +`2022-11-10` + +- 🐞 修复 `Image` 动态删除时,预览图片错误问题 + +## 3.2.14 + +`2022-11-07` + +- 🐞 修复自定义 `prefixCls` 时,动态主题失效问题 [#6063](https://github.com/vueComponent/ant-design-vue/issues/6063) +- 🐞 修复 `DatePicker` 使用 select 等弹窗组件作为插槽时,报错问题 [#6062](https://github.com/vueComponent/ant-design-vue/issues/6062) +- 🐞 修复 `DirectoryTree` 未暴露 scrollTo 方法 [#6067](https://github.com/vueComponent/ant-design-vue/issues/6067) +- 🐞 修复 `RangePicker` 弹窗位置不改变问题 [#6073](https://github.com/vueComponent/ant-design-vue/issues/6073) + +## 3.2.13 + +`2022-10-08` + +- 🌟 支持 Vue 3 升级工具 `@vue/compat` [#5973](https://github.com/vueComponent/ant-design-vue/issues/5973) +- 🌟 Cascader 添加 tagRender 插槽 [#5954](https://github.com/vueComponent/ant-design-vue/issues/5954) +- 🐞 修复 Image 预览关闭时,图片闪动问题 [#5955](https://github.com/vueComponent/ant-design-vue/issues/5955) +- 🐞 修复 Tag 关闭图标样式显示错位 [#5956](https://github.com/vueComponent/ant-design-vue/issues/5956) +- 🐞 修复 Table loading 属性 ts 类型错误 [#5964](https://github.com/vueComponent/ant-design-vue/issues/5964) +- 🐞 修复 Transfer 删除异常问题 [#5975](https://github.com/vueComponent/ant-design-vue/issues/5975) +- 🐞 修复 Table 固定列的滚动阴影显示问题 [#5996](https://github.com/vueComponent/ant-design-vue/issues/5996) +- 🐞 修复 DirectoryTree 在自定义 fieldNames 时,默认展开失效问题 [#6007](https://github.com/vueComponent/ant-design-vue/issues/6007) + +## 3.2.12 + +`2022-09-02` + +- 🐞 修复 DescriptionItem labelStyle 不生效问题 [#5920](https://github.com/vueComponent/ant-design-vue/issues/5920) +- 🌟 Typography 复制按钮阻止冒泡 [##5746](https://github.com/vueComponent/ant-design-vue/issues/5746) +- 🐞 修复 table 合并列滚动阴影遮挡问题 [#5786](https://github.com/vueComponent/ant-design-vue/issues/5786) +- 🐞 修复 css var 和 ConfigProvider 变量不一致问题 [#5929](https://github.com/vueComponent/ant-design-vue/issues/5929) + ## 3.2.11 `2022-08-08` diff --git a/LICENSE b/LICENSE index 3e8b38aea..dda252e82 100644 --- a/LICENSE +++ b/LICENSE @@ -44,3 +44,25 @@ NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. + +MIT License + +Copyright (c) 2019-PRESENT Anthony Fu + +Permission is hereby granted, free of charge, to any person obtaining a copy +of this software and associated documentation files (the "Software"), to deal +in the Software without restriction, including without limitation the rights +to use, copy, modify, merge, publish, distribute, sublicense, and/or sell +copies of the Software, and to permit persons to whom the Software is +furnished to do so, subject to the following conditions: + +The above copyright notice and this permission notice shall be included in all +copies or substantial portions of the Software. + +THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR +IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, +FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE +AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER +LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, +OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE +SOFTWARE. diff --git a/README-zh_CN.md b/README-zh_CN.md index 79e32e814..7e209e324 100644 --- a/README-zh_CN.md +++ b/README-zh_CN.md @@ -86,7 +86,7 @@ ant-design-vue 是 MIT 协议的开源项目。为了项目能够更好的持续 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)] - + ## Backers diff --git a/README.md b/README.md index 00762a174..f9f558b15 100644 --- a/README.md +++ b/README.md @@ -80,7 +80,7 @@ ant-design-vue is an MIT-licensed open source project. In order to achieve bette 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)] - + ## [More Sponsor (From Patreon、alipay、wechat、paypal...)](https://github.com/vueComponent/ant-design-vue/blob/master/BACKERS.md) diff --git a/antd-tools/generator-types/src/parser.ts b/antd-tools/generator-types/src/parser.ts index a09bc250d..964b09516 100644 --- a/antd-tools/generator-types/src/parser.ts +++ b/antd-tools/generator-types/src/parser.ts @@ -25,7 +25,7 @@ function readLine(input: string) { } function splitTableLine(line: string) { - line = line.replace('\\|', 'JOIN'); + line = line.replace(/\\\|/g, 'JOIN'); const items = line.split('|').map(item => item.trim().replace('JOIN', '|')); diff --git a/components/_util/ActionButton.tsx b/components/_util/ActionButton.tsx index fe1eb83de..19b1365ae 100644 --- a/components/_util/ActionButton.tsx +++ b/components/_util/ActionButton.tsx @@ -26,6 +26,7 @@ function isThenable(thing?: PromiseLike): boolean { } export default defineComponent({ + compatConfig: { MODE: 3 }, name: 'ActionButton', props: actionButtonProps, setup(props, { slots }) { diff --git a/components/_util/BaseInput.tsx b/components/_util/BaseInput.tsx index 0c0e42f84..009613a74 100644 --- a/components/_util/BaseInput.tsx +++ b/components/_util/BaseInput.tsx @@ -2,6 +2,7 @@ import { defineComponent, ref, withDirectives } from 'vue'; import antInput from './antInputDirective'; import PropTypes from './vue-types'; const BaseInput = defineComponent({ + compatConfig: { MODE: 3 }, props: { value: PropTypes.string.def(''), }, diff --git a/components/_util/Portal.tsx b/components/_util/Portal.tsx index cde3e70e0..0aea311bc 100644 --- a/components/_util/Portal.tsx +++ b/components/_util/Portal.tsx @@ -11,6 +11,7 @@ import { import { useInjectPortal } from '../vc-trigger/context'; export default defineComponent({ + compatConfig: { MODE: 3 }, name: 'Portal', inheritAttrs: false, props: { diff --git a/components/_util/PortalWrapper.tsx b/components/_util/PortalWrapper.tsx index 66491fc73..5c02f3ba3 100644 --- a/components/_util/PortalWrapper.tsx +++ b/components/_util/PortalWrapper.tsx @@ -49,6 +49,7 @@ const getParent = (getContainer: GetContainer) => { export type GetContainer = string | HTMLElement | (() => HTMLElement); export default defineComponent({ + compatConfig: { MODE: 3 }, name: 'PortalWrapper', inheritAttrs: false, props: { diff --git a/components/_util/__mocks__/Portal.tsx b/components/_util/__mocks__/Portal.tsx index 0043608ff..d71306396 100644 --- a/components/_util/__mocks__/Portal.tsx +++ b/components/_util/__mocks__/Portal.tsx @@ -1,6 +1,7 @@ import { defineComponent } from 'vue'; export default defineComponent({ + compatConfig: { MODE: 3 }, name: 'Portal', inheritAttrs: false, props: ['getContainer'], diff --git a/components/_util/hooks/_vueuse/_configurable.ts b/components/_util/hooks/_vueuse/_configurable.ts new file mode 100644 index 000000000..1d1e001d4 --- /dev/null +++ b/components/_util/hooks/_vueuse/_configurable.ts @@ -0,0 +1,34 @@ +import { isClient } from './is'; + +export interface ConfigurableWindow { + /* + * Specify a custom `window` instance, e.g. working with iframes or in testing environments. + */ + window?: Window; +} + +export interface ConfigurableDocument { + /* + * Specify a custom `document` instance, e.g. working with iframes or in testing environments. + */ + document?: Document; +} + +export interface ConfigurableNavigator { + /* + * Specify a custom `navigator` instance, e.g. working with iframes or in testing environments. + */ + navigator?: Navigator; +} + +export interface ConfigurableLocation { + /* + * Specify a custom `location` instance, e.g. working with iframes or in testing environments. + */ + location?: Location; +} + +export const defaultWindow = /* #__PURE__ */ isClient ? window : undefined; +export const defaultDocument = /* #__PURE__ */ isClient ? window.document : undefined; +export const defaultNavigator = /* #__PURE__ */ isClient ? window.navigator : undefined; +export const defaultLocation = /* #__PURE__ */ isClient ? window.location : undefined; diff --git a/components/_util/hooks/_vueuse/is.ts b/components/_util/hooks/_vueuse/is.ts new file mode 100644 index 000000000..52b4e9a30 --- /dev/null +++ b/components/_util/hooks/_vueuse/is.ts @@ -0,0 +1,28 @@ +export const isClient = typeof window !== 'undefined'; +export const isDef = (val?: T): val is T => typeof val !== 'undefined'; +export const assert = (condition: boolean, ...infos: any[]) => { + if (!condition) console.warn(...infos); +}; +const toString = Object.prototype.toString; +export const isBoolean = (val: any): val is boolean => typeof val === 'boolean'; +export const isFunction = (val: any): val is T => typeof val === 'function'; +export const isNumber = (val: any): val is number => typeof val === 'number'; +export const isString = (val: unknown): val is string => typeof val === 'string'; +export const isObject = (val: any): val is object => toString.call(val) === '[object Object]'; +export const isWindow = (val: any): val is Window => + typeof window !== 'undefined' && toString.call(val) === '[object Window]'; +export const now = () => Date.now(); +export const timestamp = () => +Date.now(); +export const clamp = (n: number, min: number, max: number) => Math.min(max, Math.max(min, n)); +export const noop = () => {}; +export const rand = (min: number, max: number) => { + min = Math.ceil(min); + max = Math.floor(max); + return Math.floor(Math.random() * (max - min + 1)) + min; +}; +export const isIOS = + /* #__PURE__ */ isClient && + window?.navigator?.userAgent && + /iP(ad|hone|od)/.test(window.navigator.userAgent); +export const hasOwn = (val: T, key: K): key is K => + Object.prototype.hasOwnProperty.call(val, key); diff --git a/components/_util/hooks/_vueuse/resolveUnref.ts b/components/_util/hooks/_vueuse/resolveUnref.ts new file mode 100644 index 000000000..99d31ffd2 --- /dev/null +++ b/components/_util/hooks/_vueuse/resolveUnref.ts @@ -0,0 +1,9 @@ +import { unref } from 'vue'; +import type { MaybeComputedRef } from './types'; + +/** + * Get the value of value/ref/getter. + */ +export function resolveUnref(r: MaybeComputedRef): T { + return typeof r === 'function' ? (r as any)() : unref(r); +} diff --git a/components/_util/hooks/_vueuse/tryOnMounted.ts b/components/_util/hooks/_vueuse/tryOnMounted.ts new file mode 100644 index 000000000..3c0155093 --- /dev/null +++ b/components/_util/hooks/_vueuse/tryOnMounted.ts @@ -0,0 +1,15 @@ +// eslint-disable-next-line no-restricted-imports +import { getCurrentInstance, nextTick, onMounted } from 'vue'; +import type { Fn } from './types'; + +/** + * Call onMounted() if it's inside a component lifecycle, if not, just call the function + * + * @param fn + * @param sync if set to false, it will run in the nextTick() of Vue + */ +export function tryOnMounted(fn: Fn, sync = true) { + if (getCurrentInstance()) onMounted(fn); + else if (sync) fn(); + else nextTick(fn); +} diff --git a/components/_util/hooks/_vueuse/tryOnScopeDispose.ts b/components/_util/hooks/_vueuse/tryOnScopeDispose.ts new file mode 100644 index 000000000..460efc5e4 --- /dev/null +++ b/components/_util/hooks/_vueuse/tryOnScopeDispose.ts @@ -0,0 +1,15 @@ +import { getCurrentScope, onScopeDispose } from 'vue'; +import type { Fn } from './types'; + +/** + * Call onScopeDispose() if it's inside a effect scope lifecycle, if not, do nothing + * + * @param fn + */ +export function tryOnScopeDispose(fn: Fn) { + if (getCurrentScope()) { + onScopeDispose(fn); + return true; + } + return false; +} diff --git a/components/_util/hooks/_vueuse/types.ts b/components/_util/hooks/_vueuse/types.ts new file mode 100644 index 000000000..1bde2360c --- /dev/null +++ b/components/_util/hooks/_vueuse/types.ts @@ -0,0 +1,142 @@ +import type { ComputedRef, Ref, WatchOptions, WatchSource } from 'vue'; + +/** + * Any function + */ +export type Fn = () => void; + +/** + * A ref that allow to set null or undefined + */ +export type RemovableRef = Omit, 'value'> & { + get value(): T; + set value(value: T | null | undefined); +}; + +/** + * @deprecated Use `RemovableRef` + */ +export type RemoveableRef = RemovableRef; + +/** + * Maybe it's a ref, or a plain value + * + * ```ts + * type MaybeRef = T | Ref + * ``` + */ +export type MaybeRef = T | Ref; + +/** + * Maybe it's a ref, or a plain value, or a getter function + * + * ```ts + * type MaybeComputedRef = (() => T) | T | Ref | ComputedRef + * ``` + */ +export type MaybeComputedRef = MaybeReadonlyRef | MaybeRef; + +/** + * Maybe it's a computed ref, or a getter function + * + * ```ts + * type MaybeReadonlyRef = (() => T) | ComputedRef + * ``` + */ +export type MaybeReadonlyRef = (() => T) | ComputedRef; + +/** + * Make all the nested attributes of an object or array to MaybeRef + * + * Good for accepting options that will be wrapped with `reactive` or `ref` + * + * ```ts + * UnwrapRef> === T + * ``` + */ +export type DeepMaybeRef = T extends Ref + ? MaybeRef + : T extends Array | object + ? { [K in keyof T]: DeepMaybeRef } + : MaybeRef; + +/** + * Infers the element type of an array + */ +export type ElementOf = T extends (infer E)[] ? E : never; + +export type ShallowUnwrapRef = T extends Ref ? P : T; + +export type Awaitable = Promise | T; + +export type ArgumentsType = T extends (...args: infer U) => any ? U : never; + +export interface Pausable { + /** + * A ref indicate whether a pausable instance is active + */ + isActive: Ref; + + /** + * Temporary pause the effect from executing + */ + pause: Fn; + + /** + * Resume the effects + */ + resume: Fn; +} + +export interface Stoppable { + /** + * A ref indicate whether a stoppable instance is executing + */ + isPending: Ref; + + /** + * Stop the effect from executing + */ + stop: Fn; + + /** + * Start the effects + */ + start: Fn; +} + +/** + * @deprecated Use `Stoppable` + */ +export type Stopable = Stoppable; + +export interface ConfigurableFlush { + /** + * Timing for monitoring changes, refer to WatchOptions for more details + * + * @default 'pre' + */ + flush?: WatchOptions['flush']; +} + +export interface ConfigurableFlushSync { + /** + * Timing for monitoring changes, refer to WatchOptions for more details. + * Unlike `watch()`, the default is set to `sync` + * + * @default 'sync' + */ + flush?: WatchOptions['flush']; +} + +// Internal Types +export type MapSources = { + [K in keyof T]: T[K] extends WatchSource ? V : never; +}; +export type MapOldSources = { + [K in keyof T]: T[K] extends WatchSource + ? Immediate extends true + ? V | undefined + : V + : never; +}; diff --git a/components/_util/hooks/_vueuse/unrefElement.ts b/components/_util/hooks/_vueuse/unrefElement.ts new file mode 100644 index 000000000..2f278c8be --- /dev/null +++ b/components/_util/hooks/_vueuse/unrefElement.ts @@ -0,0 +1,24 @@ +import type { ComponentPublicInstance } from 'vue'; +import type { MaybeComputedRef, MaybeRef } from './types'; +import { resolveUnref } from './resolveUnref'; + +export type VueInstance = ComponentPublicInstance; +export type MaybeElementRef = MaybeRef; +export type MaybeComputedElementRef = MaybeComputedRef; +export type MaybeElement = HTMLElement | SVGElement | VueInstance | undefined | null; + +export type UnRefElementReturn = T extends VueInstance + ? Exclude + : T | undefined; + +/** + * Get the dom element of a ref of element or Vue component instance + * + * @param elRef + */ +export function unrefElement( + elRef: MaybeComputedElementRef, +): UnRefElementReturn { + const plain = resolveUnref(elRef); + return (plain as VueInstance)?.$el ?? plain; +} diff --git a/components/_util/hooks/_vueuse/useElementSize.ts b/components/_util/hooks/_vueuse/useElementSize.ts new file mode 100644 index 000000000..90beea16b --- /dev/null +++ b/components/_util/hooks/_vueuse/useElementSize.ts @@ -0,0 +1,65 @@ +import { ref, watch } from 'vue'; +import type { MaybeComputedElementRef } from './unrefElement'; +import type { UseResizeObserverOptions } from './useResizeObserver'; +import { useResizeObserver } from './useResizeObserver'; +import { unrefElement } from './unrefElement'; + +export interface ElementSize { + width: number; + height: number; +} + +/** + * Reactive size of an HTML element. + * + * @see https://vueuse.org/useElementSize + * @param target + * @param callback + * @param options + */ +export function useElementSize( + target: MaybeComputedElementRef, + initialSize: ElementSize = { width: 0, height: 0 }, + options: UseResizeObserverOptions = {}, +) { + const { box = 'content-box' } = options; + const width = ref(initialSize.width); + const height = ref(initialSize.height); + + useResizeObserver( + target, + ([entry]) => { + const boxSize = + box === 'border-box' + ? entry.borderBoxSize + : box === 'content-box' + ? entry.contentBoxSize + : entry.devicePixelContentBoxSize; + + if (boxSize) { + width.value = boxSize.reduce((acc, { inlineSize }) => acc + inlineSize, 0); + height.value = boxSize.reduce((acc, { blockSize }) => acc + blockSize, 0); + } else { + // fallback + width.value = entry.contentRect.width; + height.value = entry.contentRect.height; + } + }, + options, + ); + + watch( + () => unrefElement(target), + ele => { + width.value = ele ? initialSize.width : 0; + height.value = ele ? initialSize.height : 0; + }, + ); + + return { + width, + height, + }; +} + +export type UseElementSizeReturn = ReturnType; diff --git a/components/_util/hooks/_vueuse/useResizeObserver.ts b/components/_util/hooks/_vueuse/useResizeObserver.ts new file mode 100644 index 000000000..288084cbb --- /dev/null +++ b/components/_util/hooks/_vueuse/useResizeObserver.ts @@ -0,0 +1,94 @@ +import { tryOnScopeDispose } from './tryOnScopeDispose'; +import { watch } from 'vue'; +import type { MaybeComputedElementRef } from './unrefElement'; +import { unrefElement } from './unrefElement'; +import { useSupported } from './useSupported'; +import type { ConfigurableWindow } from './_configurable'; +import { defaultWindow } from './_configurable'; + +export interface ResizeObserverSize { + readonly inlineSize: number; + readonly blockSize: number; +} + +export interface ResizeObserverEntry { + readonly target: Element; + readonly contentRect: DOMRectReadOnly; + readonly borderBoxSize?: ReadonlyArray; + readonly contentBoxSize?: ReadonlyArray; + readonly devicePixelContentBoxSize?: ReadonlyArray; +} + +export type ResizeObserverCallback = ( + entries: ReadonlyArray, + observer: ResizeObserver, +) => void; + +export interface UseResizeObserverOptions extends ConfigurableWindow { + /** + * Sets which box model the observer will observe changes to. Possible values + * are `content-box` (the default), `border-box` and `device-pixel-content-box`. + * + * @default 'content-box' + */ + box?: ResizeObserverBoxOptions; +} + +declare class ResizeObserver { + constructor(callback: ResizeObserverCallback); + disconnect(): void; + observe(target: Element, options?: UseResizeObserverOptions): void; + unobserve(target: Element): void; +} + +/** + * Reports changes to the dimensions of an Element's content or the border-box + * + * @see https://vueuse.org/useResizeObserver + * @param target + * @param callback + * @param options + */ +export function useResizeObserver( + target: MaybeComputedElementRef, + callback: ResizeObserverCallback, + options: UseResizeObserverOptions = {}, +) { + const { window = defaultWindow, ...observerOptions } = options; + let observer: ResizeObserver | undefined; + const isSupported = useSupported(() => window && 'ResizeObserver' in window); + + const cleanup = () => { + if (observer) { + observer.disconnect(); + observer = undefined; + } + }; + + const stopWatch = watch( + () => unrefElement(target), + el => { + cleanup(); + + if (isSupported.value && window && el) { + observer = new ResizeObserver(callback); + observer!.observe(el, observerOptions); + } + }, + { immediate: true, flush: 'post' }, + ); + + const stop = () => { + cleanup(); + stopWatch(); + }; + + tryOnScopeDispose(stop); + + return { + isSupported, + stop, + }; +} + +export type UseResizeObserverReturn = ReturnType; diff --git a/components/_util/hooks/_vueuse/useSupported.ts b/components/_util/hooks/_vueuse/useSupported.ts new file mode 100644 index 000000000..7705bf63d --- /dev/null +++ b/components/_util/hooks/_vueuse/useSupported.ts @@ -0,0 +1,14 @@ +import { tryOnMounted } from './tryOnMounted'; +import type { Ref } from 'vue'; +import { ref } from 'vue'; + +export function useSupported(callback: () => unknown, sync = false) { + const isSupported = ref() as Ref; + + const update = () => (isSupported.value = Boolean(callback())); + + update(); + + tryOnMounted(update, sync); + return isSupported; +} diff --git a/components/_util/props-util/index.js b/components/_util/props-util/index.js index 3052e2ab6..38b0c9252 100644 --- a/components/_util/props-util/index.js +++ b/components/_util/props-util/index.js @@ -366,8 +366,8 @@ export function filterEmpty(children = []) { children.forEach(child => { if (Array.isArray(child)) { res.push(...child); - } else if (child && child.type === Fragment) { - res.push(...child.children); + } else if (child?.type === Fragment) { + res.push(...filterEmpty(child.children)); } else { res.push(child); } diff --git a/components/_util/transButton.tsx b/components/_util/transButton.tsx index 66861efaf..caced47cd 100644 --- a/components/_util/transButton.tsx +++ b/components/_util/transButton.tsx @@ -15,6 +15,7 @@ const inlineStyle = { }; const TransButton = defineComponent({ + compatConfig: { MODE: 3 }, name: 'TransButton', inheritAttrs: false, props: { diff --git a/components/_util/wave.tsx b/components/_util/wave.tsx index 1170e3d13..ef69ef66c 100644 --- a/components/_util/wave.tsx +++ b/components/_util/wave.tsx @@ -21,6 +21,7 @@ function isNotGrey(color: string) { return true; } export default defineComponent({ + compatConfig: { MODE: 3 }, name: 'Wave', props: { insertExtraNode: Boolean, diff --git a/components/affix/index.tsx b/components/affix/index.tsx index 72313e490..e6ee0e972 100644 --- a/components/affix/index.tsx +++ b/components/affix/index.tsx @@ -72,6 +72,7 @@ export type AffixExpose = { export type AffixInstance = ComponentPublicInstance; const Affix = defineComponent({ + compatConfig: { MODE: 3 }, name: 'AAffix', props: affixProps(), setup(props, { slots, emit, expose }) { diff --git a/components/alert/index.tsx b/components/alert/index.tsx index 1dfae9a68..2fae9e018 100644 --- a/components/alert/index.tsx +++ b/components/alert/index.tsx @@ -63,6 +63,7 @@ export const alertProps = () => ({ export type AlertProps = Partial>>; const Alert = defineComponent({ + compatConfig: { MODE: 3 }, name: 'AAlert', inheritAttrs: false, props: alertProps(), diff --git a/components/anchor/Anchor.tsx b/components/anchor/Anchor.tsx index 50503ada0..941b8ecfe 100644 --- a/components/anchor/Anchor.tsx +++ b/components/anchor/Anchor.tsx @@ -73,6 +73,7 @@ export interface AnchorState { } export default defineComponent({ + compatConfig: { MODE: 3 }, name: 'AAnchor', inheritAttrs: false, props: anchorProps(), diff --git a/components/anchor/AnchorLink.tsx b/components/anchor/AnchorLink.tsx index 049790643..8f16a9808 100644 --- a/components/anchor/AnchorLink.tsx +++ b/components/anchor/AnchorLink.tsx @@ -16,6 +16,7 @@ export const anchorLinkProps = () => ({ export type AnchorLinkProps = Partial>>; export default defineComponent({ + compatConfig: { MODE: 3 }, name: 'AAnchorLink', props: initDefaultProps(anchorLinkProps(), { href: '#' }), slots: ['title'], diff --git a/components/anchor/__tests__/__snapshots__/demo.test.js.snap b/components/anchor/__tests__/__snapshots__/demo.test.js.snap index a06050b82..23a0acd91 100644 --- a/components/anchor/__tests__/__snapshots__/demo.test.js.snap +++ b/components/anchor/__tests__/__snapshots__/demo.test.js.snap @@ -32,11 +32,11 @@ exports[`renders ./components/anchor/demo/basic.vue correctly 1`] = ` exports[`renders ./components/anchor/demo/customizeHighlight.vue correctly 1`] = `
-
+
-