diff --git a/src/packages/actionsheet/actionsheet.taro.tsx b/src/packages/actionsheet/actionsheet.taro.tsx index 5f2cb60c4c..7775902a62 100644 --- a/src/packages/actionsheet/actionsheet.taro.tsx +++ b/src/packages/actionsheet/actionsheet.taro.tsx @@ -1,6 +1,7 @@ import React, { FunctionComponent, ReactNode } from 'react' import Popup, { PopupProps } from '@/packages/popup/index.taro' import { ComponentDefaults } from '@/utils/typings' +import { mergeProps } from '@/utils/merge-props' export type ActionSheetOption = { [key: string]: T } @@ -40,7 +41,7 @@ export const ActionSheet: FunctionComponent< className, style, ...rest - } = { ...defaultProps, ...props } + } = mergeProps(defaultProps, props) const classPrefix = 'nut-actionsheet' diff --git a/src/packages/actionsheet/actionsheet.tsx b/src/packages/actionsheet/actionsheet.tsx index 927a45a952..efeeedb50f 100644 --- a/src/packages/actionsheet/actionsheet.tsx +++ b/src/packages/actionsheet/actionsheet.tsx @@ -1,6 +1,7 @@ import React, { FunctionComponent, ReactNode } from 'react' import Popup, { PopupProps } from '@/packages/popup/index' import { ComponentDefaults } from '@/utils/typings' +import { mergeProps } from '@/utils/merge-props' export type ActionSheetOption = { [key: string]: T } @@ -40,7 +41,7 @@ export const ActionSheet: FunctionComponent< className, style, ...rest - } = { ...defaultProps, ...props } + } = mergeProps(defaultProps, props) const classPrefix = 'nut-actionsheet' diff --git a/src/packages/animatingnumbers/__tests__/animatingnumbers.spec.tsx b/src/packages/animatingnumbers/__tests__/animatingnumbers.spec.tsx index 4fd2666ff3..788e2ddf84 100644 --- a/src/packages/animatingnumbers/__tests__/animatingnumbers.spec.tsx +++ b/src/packages/animatingnumbers/__tests__/animatingnumbers.spec.tsx @@ -2,7 +2,6 @@ import React from 'react' import { render } from '@testing-library/react' import '@testing-library/jest-dom' import { AnimatingNumbers } from '../animatingnumbers' -import { CountUp } from '@/packages/animatingnumbers/countup' vi.useFakeTimers() test('test value props', () => { @@ -13,7 +12,8 @@ test('test value props', () => { 'style', 'transition: transform 1s ease-in-out;' ) - vi.advanceTimersByTime(CountUp.defaultProps?.delay ?? 0) + const defaultDelay = 300 + vi.advanceTimersByTime(defaultDelay) expect(listNumbers[0]).toHaveAttribute( 'style', 'transition: transform 1s ease-in-out; transform: translate(0, -30%);' @@ -28,7 +28,8 @@ test('test aysnc value and duration props', async () => { ) const listNumbers = container.querySelectorAll('.nut-countup-number') expect(listNumbers.length).toBe(8) - vi.advanceTimersByTime(CountUp.defaultProps?.delay ?? 0) + const defaultDelay = 300 + vi.advanceTimersByTime(defaultDelay) expect(listNumbers[0]).toHaveAttribute( 'style', 'transition: transform 1.2s ease-in-out; transform: translate(0, -50%);' diff --git a/src/packages/animatingnumbers/countup.taro.tsx b/src/packages/animatingnumbers/countup.taro.tsx index 26f3a1ab9d..c0eaaacb00 100644 --- a/src/packages/animatingnumbers/countup.taro.tsx +++ b/src/packages/animatingnumbers/countup.taro.tsx @@ -7,6 +7,7 @@ import React, { } from 'react' import { createSelectorQuery } from '@tarojs/taro' import { BasicComponent, ComponentDefaults } from '@/utils/typings' +import { mergeProps } from '@/utils/merge-props' export interface CountUpProps extends BasicComponent { length: number @@ -33,10 +34,7 @@ export const CountUp: FunctionComponent> = (props) => { thousands, style, ...reset - } = { - ...defaultProps, - ...props, - } + } = mergeProps(defaultProps, props) const classPrefix = 'nut-countup' const countupRef = useRef(null) const timerRef = useRef(0) @@ -141,5 +139,4 @@ export const CountUp: FunctionComponent> = (props) => { ) } -CountUp.defaultProps = defaultProps // 不可删除 CountUp.displayName = 'NutCountUp' diff --git a/src/packages/animatingnumbers/countup.tsx b/src/packages/animatingnumbers/countup.tsx index c54dc05d33..a17c9b1fa2 100644 --- a/src/packages/animatingnumbers/countup.tsx +++ b/src/packages/animatingnumbers/countup.tsx @@ -6,6 +6,7 @@ import React, { useRef, } from 'react' import { BasicComponent, ComponentDefaults } from '@/utils/typings' +import { mergeProps } from '@/utils/merge-props' export interface CountUpProps extends BasicComponent { length: number @@ -32,10 +33,7 @@ export const CountUp: FunctionComponent> = (props) => { thousands, style, ...reset - } = { - ...defaultProps, - ...props, - } + } = mergeProps(defaultProps, props) const classPrefix = 'nut-countup' const countupRef = useRef(null) const timerRef = useRef(0) @@ -122,5 +120,4 @@ export const CountUp: FunctionComponent> = (props) => { ) } -CountUp.defaultProps = defaultProps // 不可删除 CountUp.displayName = 'NutCountUp' diff --git a/src/packages/dialog/dialog.taro.tsx b/src/packages/dialog/dialog.taro.tsx index ace7a0445d..69ba389562 100644 --- a/src/packages/dialog/dialog.taro.tsx +++ b/src/packages/dialog/dialog.taro.tsx @@ -17,6 +17,7 @@ import { } from '@/utils/use-custom-event' import { BasicComponent } from '@/utils/typings' import { useLockScrollTaro } from '@/utils/use-lock-scoll-taro' +import { mergeProps } from '@/utils/merge-props' export type DialogProps = DialogBasicProps & BasicComponent const defaultProps = { @@ -78,7 +79,7 @@ export const BaseDialog: FunctionComponent> & { beforeClose, }, setParams, - } = useParams({ ...defaultProps, ...props }) + } = useParams(mergeProps(defaultProps, props)) useCustomEvent( id as string, @@ -225,7 +226,6 @@ export function close(selector: string) { customEvents.trigger(path, { status: false }) } -BaseDialog.defaultProps = defaultProps // 不可删除 BaseDialog.displayName = 'NutDialog' BaseDialog.open = open BaseDialog.close = close diff --git a/src/packages/dialog/dialog.tsx b/src/packages/dialog/dialog.tsx index 58e7c95e7f..e4436486d5 100644 --- a/src/packages/dialog/dialog.tsx +++ b/src/packages/dialog/dialog.tsx @@ -13,6 +13,7 @@ import { DialogConfirmProps, } from './config' import { ComponentDefaults } from '@/utils/typings' +import { mergeProps } from '@/utils/merge-props' export type DialogProps = DialogBasicProps const defaultProps = { @@ -55,7 +56,7 @@ const BaseDialog: ForwardRefRenderFunction> = ( beforeCancel, beforeClose, ...restProps - } = props + } = mergeProps(defaultProps, props) const classPrefix = 'nut-dialog' const [loading, setLoading] = useState(false) @@ -161,5 +162,4 @@ Dialog.confirm = (props: DialogConfirmProps): DialogReturnProps => { } }) -Dialog.defaultProps = defaultProps // 不可删除 Dialog.displayName = 'NutDialog' diff --git a/src/packages/notify/notify.taro.tsx b/src/packages/notify/notify.taro.tsx index a4f25afeaa..6b35facf78 100644 --- a/src/packages/notify/notify.taro.tsx +++ b/src/packages/notify/notify.taro.tsx @@ -7,6 +7,7 @@ import { useCustomEvent, useCustomEventsPath, } from '@/utils/use-custom-event' +import { mergeProps } from '@/utils/merge-props' export type NotifyPosition = 'top' | 'bottom' export type NotifyType = 'primary' | 'success' | 'danger' | 'warning' @@ -49,7 +50,7 @@ export const Notify: FunctionComponent> & { duration, onClose, onClick, - } = { ...defaultProps, ...props } + } = mergeProps(defaultProps, props) useCustomEvent(id as string, (status: boolean) => { status ? show() : hide() @@ -130,7 +131,6 @@ export function close(selector: string) { customEvents.trigger(path, false) } -Notify.defaultProps = defaultProps // 不可删除 Notify.displayName = 'NutNotify' Notify.open = open Notify.close = close diff --git a/src/packages/toast/toast.taro.tsx b/src/packages/toast/toast.taro.tsx index 9ae3723fd8..07219be285 100644 --- a/src/packages/toast/toast.taro.tsx +++ b/src/packages/toast/toast.taro.tsx @@ -10,6 +10,7 @@ import { useParams, } from '@/utils/use-custom-event' import { usePropsValue } from '@/utils/use-props-value' +import { mergeProps } from '@/utils/merge-props' export type ToastPosition = 'top' | 'bottom' | 'center' export type ToastSize = 'small' | 'base' | 'large' @@ -91,7 +92,7 @@ export const Toast: FunctionComponent< wordBreak, }, setParams, - } = useParams({ ...defaultProps, ...props }) + } = useParams(mergeProps(defaultProps, props)) const timer = useRef(-1) const [innerVisible, setInnerVisible] = usePropsValue({ @@ -222,7 +223,6 @@ export function hide(selector: string) { customEvents.trigger(path, { status: false }) } -Toast.defaultProps = defaultProps // 不可删除 Toast.displayName = 'NutToast' Toast.show = show Toast.hide = hide diff --git a/src/utils/merge-props.ts b/src/utils/merge-props.ts index 45d8a25655..dd209f310c 100644 --- a/src/utils/merge-props.ts +++ b/src/utils/merge-props.ts @@ -1,7 +1,33 @@ -export function mergeProps( - defaultProps: T, - props: U -): { [Key in Extract]: U[Key] } & - { [Key in Exclude]?: U[Key] } { - return { ...defaultProps, ...props } +export function mergeProps(a: A, b: B): B & A +export function mergeProps(a: A, b: B, c: C): C & B & A +export function mergeProps(a: A, b: B, c: C, d: D): D & C & B & A +export function mergeProps(...items: any[]) { + const ret: any = {} + items.forEach((item) => { + if (item) { + Object.keys(item).forEach((key) => { + if (item[key] !== undefined) { + ret[key] = item[key] + } + }) + } + }) + return ret +} + +/** + * Merge props and return the first non-undefined value. + * The later has higher priority. e.g. (10, 1, 5) => 5 wins. + * This is useful with legacy props that have been deprecated. + */ +export function mergeProp( + defaultProp: DefaultT, + ...propList: T[] +): T | undefined { + for (let i = propList.length - 1; i >= 0; i -= 1) { + if (propList[i] !== undefined) { + return propList[i] + } + } + return defaultProp }