From bb9b8c49e34bc9068134e0cacfedc1c8e1c5160c Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?=E9=B9=A4=E4=BB=99?= Date: Fri, 12 Apr 2024 17:23:15 +0800 Subject: [PATCH 1/9] feat(ConfigProvider): add icons config --- src/components/center-popup/center-popup.tsx | 7 +- src/components/check-list/check-list.tsx | 6 +- src/components/collapse/collapse.tsx | 52 +++++++----- src/components/collapse/index.en.md | 4 +- src/components/collapse/index.zh.md | 4 +- .../collapse/tests/collapse.test.tsx | 81 ++++++++++++++++++- .../config-provider/config-provider.tsx | 46 ++++++++++- src/components/config-provider/index.en.md | 29 +++++++ src/components/config-provider/index.zh.md | 29 +++++++ src/components/dropdown/dropdown.tsx | 37 +++++---- src/components/dropdown/index.en.md | 4 +- src/components/dropdown/index.zh.md | 4 +- src/components/dropdown/item.tsx | 32 ++++++-- src/components/form/form-item.tsx | 44 ++++++---- src/components/form/index.en.md | 1 + src/components/form/index.zh.md | 1 + src/components/input/index.en.md | 1 + src/components/input/index.zh.md | 1 + src/components/input/input.tsx | 16 +++- src/components/list/list-item.tsx | 20 +++-- src/components/nav-bar/demos/demo1.tsx | 8 +- src/components/nav-bar/index.en.md | 4 +- src/components/nav-bar/index.zh.md | 4 +- src/components/nav-bar/nav-bar.tsx | 27 +++++-- src/components/nav-bar/tests/nav-bar.test.tsx | 20 +++++ src/components/notice-bar/index.en.md | 1 + src/components/notice-bar/index.zh.md | 1 + src/components/notice-bar/notice-bar.less | 3 - src/components/notice-bar/notice-bar.tsx | 23 +++--- .../notice-bar/tests/notice-bar.test.tsx | 2 +- src/components/popup/index.en.md | 1 + src/components/popup/index.zh.md | 1 + ...pup-base-props.ts => popup-base-props.tsx} | 6 +- src/components/popup/popup.tsx | 7 +- src/components/result-page/result-page.tsx | 21 +---- src/components/result/result.tsx | 20 +---- .../result/tests/result-icon.test.tsx | 38 +++++++++ src/components/result/use-result-icon.tsx | 38 +++++++++ src/components/search-bar/index.en.md | 2 +- src/components/search-bar/index.zh.md | 2 +- src/components/search-bar/search-bar.tsx | 30 ++++--- src/components/toast/tests/toast.test.tsx | 8 +- src/components/toast/toast.less | 5 -- src/components/toast/toast.tsx | 24 +++--- .../virtual-input/virtual-input.tsx | 12 ++- src/utils/with-default-props.tsx | 1 + 46 files changed, 535 insertions(+), 193 deletions(-) create mode 100644 src/components/nav-bar/tests/nav-bar.test.tsx rename src/components/popup/{popup-base-props.ts => popup-base-props.tsx} (86%) create mode 100644 src/components/result/tests/result-icon.test.tsx create mode 100644 src/components/result/use-result-icon.tsx diff --git a/src/components/center-popup/center-popup.tsx b/src/components/center-popup/center-popup.tsx index 193600c029..4fcbf848d9 100644 --- a/src/components/center-popup/center-popup.tsx +++ b/src/components/center-popup/center-popup.tsx @@ -11,11 +11,11 @@ import classNames from 'classnames' import { NativeProps, withNativeProps } from '../../utils/native-props' import { ShouldRender } from '../../utils/should-render' import { useLockScroll } from '../../utils/use-lock-scroll' -import { CloseOutline } from 'antd-mobile-icons' import { defaultPopupBaseProps, PopupBaseProps, } from '../popup/popup-base-props' +import { useConfig } from '../config-provider' const classPrefix = 'adm-center-popup' @@ -38,7 +38,8 @@ const defaultProps = { } export const CenterPopup: FC = p => { - const props = mergeProps(defaultProps, p) + const { popup: componentConfig = {} } = useConfig() + const props = mergeProps(defaultProps, componentConfig, p) const unmountedRef = useUnmountedRef() const style = useSpring({ @@ -134,7 +135,7 @@ export const CenterPopup: FC = p => { props.onClose?.() }} > - + {props.closeIcon} )} {body} diff --git a/src/components/check-list/check-list.tsx b/src/components/check-list/check-list.tsx index c83efe1365..6052152125 100644 --- a/src/components/check-list/check-list.tsx +++ b/src/components/check-list/check-list.tsx @@ -1,11 +1,12 @@ import React from 'react' import type { FC, ReactNode } from 'react' +import { CheckOutline } from 'antd-mobile-icons' import { NativeProps, withNativeProps } from '../../utils/native-props' import List, { ListProps } from '../list' import { mergeProps } from '../../utils/with-default-props' import { CheckListContext } from './context' import { usePropsValue } from '../../utils/use-props-value' -import { CheckOutline } from 'antd-mobile-icons' +import { useConfig } from '../config-provider' const classPrefix = 'adm-check-list' @@ -30,7 +31,8 @@ const defaultProps = { } export const CheckList: FC = p => { - const props = mergeProps(defaultProps, p) + const { checkList: componentConfig = {} } = useConfig() + const props = mergeProps(defaultProps, componentConfig, p) const [value, setValue] = usePropsValue(props) diff --git a/src/components/collapse/collapse.tsx b/src/components/collapse/collapse.tsx index 569cb3dc4a..d6090103e1 100644 --- a/src/components/collapse/collapse.tsx +++ b/src/components/collapse/collapse.tsx @@ -1,15 +1,16 @@ +import { animated, useSpring } from '@react-spring/web' +import { useMount } from 'ahooks' +import classNames from 'classnames' +import type { FC, ReactElement, ReactNode } from 'react' import React, { isValidElement, useRef } from 'react' -import type { FC, ReactNode, ReactElement } from 'react' import { NativeProps, withNativeProps } from '../../utils/native-props' -import List from '../list' -import { DownOutline } from 'antd-mobile-icons' -import classNames from 'classnames' -import { useSpring, animated } from '@react-spring/web' -import { usePropsValue } from '../../utils/use-props-value' -import { useMount } from 'ahooks' import { useShouldRender } from '../../utils/should-render' -import { useIsomorphicUpdateLayoutEffect } from '../../utils/use-isomorphic-update-layout-effect' import { traverseReactNode } from '../../utils/traverse-react-node' +import { useIsomorphicUpdateLayoutEffect } from '../../utils/use-isomorphic-update-layout-effect' +import { usePropsValue } from '../../utils/use-props-value' +import { mergeProps } from '../../utils/with-default-props' +import { useConfig } from '../config-provider' +import List from '../list' const classPrefix = `adm-collapse` @@ -20,8 +21,12 @@ export type CollapsePanelProps = { forceRender?: boolean destroyOnClose?: boolean onClick?: (event: React.MouseEvent) => void - arrow?: ReactNode | ((active: boolean) => ReactNode) + arrowIcon?: ReactNode | ((active: boolean) => ReactNode) children?: ReactNode + /** + * @deprecated use `arrowIcon` instead + */ + arrow?: ReactNode | ((active: boolean) => ReactNode) } & NativeProps export const CollapsePanel: FC = () => { @@ -106,6 +111,10 @@ type ValueProps = { activeKey?: T defaultActiveKey?: T onChange?: (activeKey: T) => void + arrowIcon?: ReactNode | ((active: boolean) => ReactNode) + /** + * @deprecated use `arrowIcon` instead + */ arrow?: ReactNode | ((active: boolean) => ReactNode) } @@ -120,7 +129,11 @@ export type CollapseProps = ( children?: ReactNode } & NativeProps -export const Collapse: FC = props => { +const defaultProps = {} + +export const Collapse: FC = p => { + const { collapse: componentConfig = {} } = useConfig() + const props = mergeProps(defaultProps, componentConfig, p) const panels: ReactElement[] = [] traverseReactNode(props.children, child => { if (!isValidElement(child)) return @@ -196,15 +209,13 @@ export const Collapse: FC = props => { panel.props.onClick?.(event) } - const renderArrow = () => { - let arrow: CollapseProps['arrow'] = - if (props.arrow !== undefined) { - arrow = props.arrow - } - if (panel.props.arrow !== undefined) { - arrow = panel.props.arrow - } - return typeof arrow === 'function' ? ( + const arrow = + panel.props.arrow || + panel.props.arrowIcon || + props.arrow || + props.arrowIcon + const arrowIcon = + typeof arrow === 'function' ? ( arrow(active) ) : (
= props => { {arrow}
) - } return ( @@ -225,7 +235,7 @@ export const Collapse: FC = props => { className={`${classPrefix}-panel-header`} onClick={handleClick} disabled={panel.props.disabled} - arrow={renderArrow()} + arrowIcon={arrowIcon} > {panel.props.title} diff --git a/src/components/collapse/index.en.md b/src/components/collapse/index.en.md index fb6dd655c7..66e835d27f 100644 --- a/src/components/collapse/index.en.md +++ b/src/components/collapse/index.en.md @@ -21,7 +21,7 @@ A content area that can be collapsed/expanded. | --- | --- | --- | --- | | accordion | Whether to enable accordion mode | `boolean` | `false` | | activeKey | The `key` of the currently expanded panel | accordion mode: `string \| null`
non-accordion mode: `string[]` | - | -| arrow | Custom arrow. if you pass a ReactNode, antd-mobile will add a rotate animation for you. | `React.ReactNode \| ((active: boolean) => React.ReactNode)` | - | +| arrowIcon | Custom arrow icon. if you pass a ReactNode, antd-mobile will add a rotate animation for you. | `React.ReactNode \| ((active: boolean) => React.ReactNode)` | - | | defaultActiveKey | The `key` of the expanded panel by default | accordion mode: `string \| null`
non-accordion mode: `string[]` | - | | onChange | Triggered when the panel is switched | accordion mode: `(activeKey: string \| null) => void`
non-accordion mode: `(activeKey: string[]) => void` | - | @@ -31,7 +31,7 @@ A content area that can be collapsed/expanded. | Name | Description | Type | Default | | --- | --- | --- | --- | -| arrow | Custom arrow | `React.ReactNode \| ((active: boolean) => React.ReactNode)` | - | +| arrowIcon | Custom arrow icon | `React.ReactNode \| ((active: boolean) => React.ReactNode)` | - | | destroyOnClose | Destroy `dom` when not visible | `boolean` | `false` | | disabled | Whether disabled or not | `boolean` | `false` | | forceRender | Whether to render the `DOM` structure when hidden | `boolean` | `false` | diff --git a/src/components/collapse/index.zh.md b/src/components/collapse/index.zh.md index 44b5ef8779..dff5354cd2 100644 --- a/src/components/collapse/index.zh.md +++ b/src/components/collapse/index.zh.md @@ -21,7 +21,7 @@ | --- | --- | --- | --- | | accordion | 是否开启手风琴模式 | `boolean` | `false` | | activeKey | 当前展开面板的 `key` | 手风琴模式:`string \| null`
非手风琴模式:`string[]` | - | -| arrow | 自定义箭头,如果是 ReactNode,那么 antd-mobile 会自动为你增加旋转动画效果 | `ReactNode \| ((active: boolean) => React.ReactNode)` | - | +| arrowIcon | 自定义箭头图标,如果是 ReactNode,那么 antd-mobile 会自动为你增加旋转动画效果 | `ReactNode \| ((active: boolean) => React.ReactNode)` | - | | defaultActiveKey | 默认展开面板的 `key` | 手风琴模式:`string \| null`
非手风琴模式:`string[]` | - | | onChange | 切换面板时触发 | 手风琴模式:`(activeKey: string \| null) => void`
非手风琴模式:`(activeKey: string[]) => void` | - | @@ -31,7 +31,7 @@ | 属性 | 说明 | 类型 | 默认值 | | --- | --- | --- | --- | -| arrow | 自定义箭头 | `ReactNode \| ((active: boolean) => React.ReactNode)` | - | +| arrowIcon | 自定义箭头图标 | `ReactNode \| ((active: boolean) => React.ReactNode)` | - | | destroyOnClose | 不可见时是否销毁 `DOM` 结构 | `boolean` | `false` | | disabled | 是否为禁用状态 | `boolean` | `false` | | forceRender | 被隐藏时是否渲染 `DOM` 结构 | `boolean` | `false` | diff --git a/src/components/collapse/tests/collapse.test.tsx b/src/components/collapse/tests/collapse.test.tsx index 79321d614f..bbca16693a 100644 --- a/src/components/collapse/tests/collapse.test.tsx +++ b/src/components/collapse/tests/collapse.test.tsx @@ -1,5 +1,5 @@ -import { render, screen, testA11y, fireEvent, waitFor } from 'testing' import * as React from 'react' +import { fireEvent, render, screen, testA11y, waitFor } from 'testing' import Collapse from '../' const classPrefix = `adm-collapse` @@ -100,3 +100,82 @@ test('disabled', async () => { expect(screen.queryByTestId('first')).toBeVisible() expect(screen.queryByTestId('second')).toBe(null) }) + +describe('arrow', () => { + it('arrow (deprecated) of collapse', async () => { + render( + + +
这里是第一项的内容
+
+
+ ) + expect(screen.getByText('foobar')).toBeVisible() + }) + + it('arrow (deprecated) of panel', async () => { + render( + + +
这里是第一项的内容
+
+
+ ) + expect(screen.getByText('foobar')).toBeVisible() + }) + + it('arrow (deprecated) of both collapse and pannel', async () => { + render( + + +
这里是第一项的内容
+
+
+ ) + expect(screen.getByText('bar')).toBeVisible() + }) + + it('both arrow (deprecated) and arrowIcon of collapse', async () => { + render( + + +
这里是第一项的内容
+
+
+ ) + expect(screen.getByText('foo')).toBeVisible() + }) + + it('both (deprecated) arrow and arrowIcon of pannel', async () => { + render( + + +
这里是第一项的内容
+
+
+ ) + expect(screen.getByText('foo')).toBeVisible() + }) + + it('arrow (deprecated) of collapse and arrowIcon of panel', async () => { + render( + + +
这里是第一项的内容
+
+
+ ) + expect(screen.getByText('bar')).toBeVisible() + }) + + it('arrowIcon of collapse and arrow (deprecated) of panel', async () => { + render( + + +
这里是第一项的内容
+
+
+ ) + expect(screen.getByText('bar')).toBeVisible() + }) +}) diff --git a/src/components/config-provider/config-provider.tsx b/src/components/config-provider/config-provider.tsx index f608e45f5a..f66c425a73 100644 --- a/src/components/config-provider/config-provider.tsx +++ b/src/components/config-provider/config-provider.tsx @@ -1,10 +1,52 @@ -import React, { useContext } from 'react' -import type { FC, ReactNode } from 'react' +import React, { FC, ReactNode, useContext } from 'react' import { Locale } from '../../locales/base' import zhCN from '../../locales/zh-CN' type Config = { locale: Locale + checkList?: { + activeIcon?: ReactNode + } + collapse?: { + arrowIcon?: ReactNode | ((active: boolean) => ReactNode) + } + dropdown?: { + arrowIcon?: ReactNode + } + form?: { + helpIcon?: ReactNode + } + input?: { + clearIcon?: ReactNode + } + list?: { + arrowIcon?: ReactNode + } + navBar?: { + backIcon?: ReactNode + } + noticeBar?: { + icon?: ReactNode + closeIcon?: ReactNode + } + popup?: { + closeIcon?: ReactNode + } + result?: { + successIcon?: ReactNode + errorIcon?: ReactNode + infoIcon?: ReactNode + waitingIcon?: ReactNode + warningIcon?: ReactNode + } + searchBar?: { + searchIcon?: ReactNode + } + toast?: { + successIcon?: ReactNode + errorIcon?: ReactNode + loadingIcon?: ReactNode + } } export const defaultConfigRef: { diff --git a/src/components/config-provider/index.en.md b/src/components/config-provider/index.en.md index c03304a3fb..e435e5cfe1 100644 --- a/src/components/config-provider/index.en.md +++ b/src/components/config-provider/index.en.md @@ -1,7 +1,36 @@ # ConfigProvider +Configure locale messages and custom icons globally. + +## When to use + +- You want to use other languages than English +- You want to use your own icon set instead of `antd-mobile-icons` + ## Demos + +## ConfigProvider + +### Props + +| Name | Description | Type | Default | +| --- | --- | --- | --- | +| locale | Locale messages | `Locale` | [zh-CN] | +| checkList | CheckList config | `{ activeIcon?: ReactNode }` | - | +| collapse | Collapse config | `{ arrowIcon?: ReactNode \| ((active: boolean) => ReactNode) }` | - | +| dropdown | Dropdown config | `{ arrowIcon?: ReactNode }` | - | +| form | Form config | `{ helpIcon?: ReactNode }` | - | +| input | Input config | `{ clearIcon?: ReactNode }` | - | +| list | List config | `{ arrowIcon?: ReactNode }` | - | +| navBar | NavBar config | `{ backIcon?: ReactNode }` | - | +| noticeBar | NoticeBar config | `{ icon?: ReactNode, closeIcon?: ReactNode }` | - | +| popup | Popup config | `{ closeIcon?: ReactNode }` | - | +| result | Result config | `{ successIcon?: ReactNode, errorIcon?: ReactNode, infoIcon?: ReactNode, waitingIcon?: ReactNode, warningIcon?: ReactNode }` | - | +| searchBar | SearchBar config | `{ icon?: ReactNode }` | - | +| toast | Toast config | `{ successIcon?: ReactNode, failIcon?: ReactNode, loadingIcon?: ReactNode }` | - | + +[zh-CN]: https://github.com/ant-design/ant-design-mobile/blob/master/src/locales/zh-CN.ts diff --git a/src/components/config-provider/index.zh.md b/src/components/config-provider/index.zh.md index 84560f3eea..6011631fc5 100644 --- a/src/components/config-provider/index.zh.md +++ b/src/components/config-provider/index.zh.md @@ -1,7 +1,36 @@ # ConfigProvider 配置 +用于全局配置本地化文案和个性化图标。 + +## 何时使用 + +- 您想使用除英文之外的语言。 +- 您想使用自己的图标集,而不是内置的 `antd-mobile-icons`。 + ## 示例 + +## ConfigProvider + +### 属性 + +| 属性 | 说明 | 类型 | 默认值 | +| --- | --- | --- | --- | +| locale | 本地化文案 | `Locale` | [zh-CN] | +| checkList | CheckList 配置 | `{ activeIcon?: ReactNode }` | - | +| collapse | Collapse 配置 | `{ arrowIcon?: ReactNode \| ((active: boolean) => ReactNode) }` | - | +| dropdown | Dropdown 配置 | `{ arrowIcon?: ReactNode }` | - | +| form | Form 配置 | `{ helpIcon?: ReactNode }` | - | +| input | Input 配置 | `{ clearIcon?: ReactNode }` | - | +| list | List 配置 | `{ arrowIcon?: ReactNode }` | - | +| navBar | NavBar 配置 | `{ backIcon?: ReactNode }` | - | +| noticeBar | NoticeBar 配置 | `{ icon?: ReactNode, closeIcon?: ReactNode }` | - | +| popup | Popup 配置 | `{ closeIcon?: ReactNode }` | - | +| result | Result 配置 | `{ successIcon?: ReactNode, errorIcon?: ReactNode, infoIcon?: ReactNode, waitingIcon?: ReactNode, warningIcon?: ReactNode }` | - | +| searchBar | SearchBar 配置 | `{ icon?: ReactNode }` | - | +| toast | Toast 配置 | `{ successIcon?: ReactNode, failIcon?: ReactNode, loadingIcon?: ReactNode }` | - | + +[zh-CN]: https://github.com/ant-design/ant-design-mobile/blob/master/src/locales/zh-CN.ts diff --git a/src/components/dropdown/dropdown.tsx b/src/components/dropdown/dropdown.tsx index 993ba22706..8ffd2db53b 100644 --- a/src/components/dropdown/dropdown.tsx +++ b/src/components/dropdown/dropdown.tsx @@ -1,26 +1,27 @@ import { useClickAway } from 'ahooks' import classNames from 'classnames' +import type { + ComponentProps, + PropsWithChildren, + ReactElement, + ReactNode, +} from 'react' import React, { cloneElement, + forwardRef, + isValidElement, useEffect, + useImperativeHandle, useRef, useState, - forwardRef, - useImperativeHandle, - isValidElement, } from 'react' -import type { - ReactNode, - ComponentProps, - PropsWithChildren, - ReactElement, -} from 'react' -import Popup, { PopupProps } from '../popup' -import Item, { ItemChildrenWrap } from './item' import { NativeProps, withNativeProps } from '../../utils/native-props' -import { mergeProps } from '../../utils/with-default-props' import { usePropsValue } from '../../utils/use-props-value' +import { mergeProps } from '../../utils/with-default-props' +import Popup, { PopupProps } from '../popup' import { defaultPopupBaseProps } from '../popup/popup-base-props' +import Item, { ItemChildrenWrap } from './item' +import { useConfig } from '../config-provider' const classPrefix = `adm-dropdown` @@ -30,6 +31,10 @@ export type DropdownProps = { closeOnMaskClick?: boolean closeOnClickAway?: boolean onChange?: (key: string | null) => void + arrowIcon?: ReactNode + /** + * @deprecated use `arrowIcon` instead + */ arrow?: ReactNode getContainer?: PopupProps['getContainer'] } & NativeProps @@ -47,7 +52,8 @@ export type DropdownRef = { const Dropdown = forwardRef>( (p, ref) => { - const props = mergeProps(defaultProps, p) + const { dropdown: componentConfig = {} } = useConfig() + const props = mergeProps(defaultProps, componentConfig, p) const [value, setValue] = usePropsValue({ value: props.activeKey, defaultValue: props.defaultActiveKey, @@ -95,7 +101,10 @@ const Dropdown = forwardRef>( }, active: child.key === value, arrow: - child.props.arrow === undefined ? props.arrow : child.props.arrow, + child.props.arrow || + child.props.arrowIcon || + props.arrow || + props.arrowIcon, } items.push(child) if (child.props.forceRender) popupForceRender = true diff --git a/src/components/dropdown/index.en.md b/src/components/dropdown/index.en.md index 915555728d..7d8efc45c0 100644 --- a/src/components/dropdown/index.en.md +++ b/src/components/dropdown/index.en.md @@ -17,7 +17,7 @@ It is suitable for filtering, sorting and changing the display range or order of | Name | Description | Type | Default | | --- | --- | --- | --- | | activeKey | Active `Item` key | `string \| null` | - | -| arrow | Custom arrow | `React.ReactNode` | - | +| arrowIcon | Custom arrow icon | `React.ReactNode` | - | | closeOnClickAway | Whether to automatically hide after clicking outside area | `boolean` | `false` | | closeOnMaskClick | Whether to automatically close after clicking on the mask | `boolean` | `true` | | defaultActiveKey | The default active `Item` key | `string \| null` | `null` | @@ -36,7 +36,7 @@ It is suitable for filtering, sorting and changing the display range or order of | Name | Description | Type | Default | | --- | --- | --- | --- | -| arrow | Custom arrow | `React.ReactNode` | - | +| arrowIcon | Custom arrow icon | `React.ReactNode` | - | | destroyOnClose | Destroy `dom` when not visible | `boolean` | `false` | | forceRender | Whether to render the content even if it is not active | `boolean` | `false` | | highlight | Highlight | `boolean` | `false` | diff --git a/src/components/dropdown/index.zh.md b/src/components/dropdown/index.zh.md index 8aba614b9a..629128911f 100644 --- a/src/components/dropdown/index.zh.md +++ b/src/components/dropdown/index.zh.md @@ -17,7 +17,7 @@ | 属性 | 说明 | 类型 | 默认值 | | --- | --- | --- | --- | | activeKey | 激活的 `Item` `key` | `string \| null` | - | -| arrow | 自定义 arrow | `React.ReactNode` | - | +| arrowIcon | 自定义箭头图标 | `React.ReactNode` | - | | closeOnClickAway | 是否在点击外部区域后自动隐藏 | `boolean` | `false` | | closeOnMaskClick | 是否在点击遮罩后自动隐藏 | `boolean` | `true` | | defaultActiveKey | 默认激活的 `Item` `key` | `string \| null` | `null` | @@ -36,7 +36,7 @@ | 属性 | 说明 | 类型 | 默认值 | | --- | --- | --- | --- | -| arrow | 自定义 arrow | `React.ReactNode` | - | +| arrowIcon | 自定义箭头图标 | `React.ReactNode` | - | | destroyOnClose | 不可见时是否销毁 `DOM` 结构 | `boolean` | `false` | | forceRender | 被隐藏时是否渲染 `DOM` 结构 | `boolean` | `false` | | highlight | 高亮 | `boolean` | `false` | diff --git a/src/components/dropdown/item.tsx b/src/components/dropdown/item.tsx index afa8c5ff16..1560272ceb 100644 --- a/src/components/dropdown/item.tsx +++ b/src/components/dropdown/item.tsx @@ -1,9 +1,11 @@ +import { DownFill } from 'antd-mobile-icons' import classNames from 'classnames' -import React from 'react' import type { FC, ReactNode } from 'react' +import React from 'react' import { NativeProps, withNativeProps } from '../../utils/native-props' import { useShouldRender } from '../../utils/should-render' -import { DownFill } from 'antd-mobile-icons' +import { mergeProps } from '../../utils/with-default-props' +import { useConfig } from '../config-provider' const classPrefix = `adm-dropdown-item` @@ -15,27 +17,41 @@ export type DropdownItemProps = { forceRender?: boolean destroyOnClose?: boolean onClick?: (event: React.MouseEvent) => void + arrowIcon?: ReactNode + /** + * @deprecated use `arrowIcon` instead + */ arrow?: ReactNode children?: ReactNode } & NativeProps +const defaultProps = { + arrowIcon: , +} + const Item: FC = props => { + const { dropdown: componentConfig = {} } = useConfig() + const { active, arrowIcon, arrow, highlight, onClick, title } = mergeProps( + defaultProps, + componentConfig, + props + ) const cls = classNames(classPrefix, { - [`${classPrefix}-active`]: props.active, - [`${classPrefix}-highlight`]: props.highlight ?? props.active, + [`${classPrefix}-active`]: active, + [`${classPrefix}-highlight`]: highlight ?? active, }) return withNativeProps( props, -
+
- {props.title} + {title} - {props.arrow === undefined ? : props.arrow} + {arrow || arrowIcon}
diff --git a/src/components/form/form-item.tsx b/src/components/form/form-item.tsx index 8a21f75027..c329db1a37 100644 --- a/src/components/form/form-item.tsx +++ b/src/components/form/form-item.tsx @@ -1,20 +1,21 @@ -import React, { useContext, useCallback, useState, useRef } from 'react' -import type { FC, ReactNode, MutableRefObject } from 'react' +import { QuestionCircleOutline } from 'antd-mobile-icons' import classNames from 'classnames' -import { NativeProps, withNativeProps } from '../../utils/native-props' import { Field, FormInstance } from 'rc-field-form' -import FieldContext from 'rc-field-form/lib/FieldContext' import type { FieldProps } from 'rc-field-form/lib/Field' -import type { Meta, InternalNamePath } from 'rc-field-form/lib/interface' -import type { FormLayout } from './index' +import FieldContext from 'rc-field-form/lib/FieldContext' +import type { InternalNamePath, Meta } from 'rc-field-form/lib/interface' +import type { FC, MutableRefObject, ReactNode } from 'react' +import React, { useCallback, useContext, useRef, useState } from 'react' import { devWarning } from '../../utils/dev-log' -import { FormContext, NoStyleItemContext } from './context' -import { toArray, isSafeSetRefComponent } from './utils' +import { NativeProps, withNativeProps } from '../../utils/native-props' +import { undefinedFallback } from '../../utils/undefined-fallback' +import { mergeProps } from '../../utils/with-default-props' +import { useConfig } from '../config-provider' import List, { ListItemProps } from '../list' import Popover from '../popover' -import { QuestionCircleOutline } from 'antd-mobile-icons' -import { useConfig } from '../config-provider' -import { undefinedFallback } from '../../utils/undefined-fallback' +import { FormContext, NoStyleItemContext } from './context' +import type { FormLayout } from './index' +import { isSafeSetRefComponent, toArray } from './utils' const NAME_SPLIT = '__SPLIT__' @@ -44,10 +45,11 @@ export type FormItemProps = Pick< > & Pick< ListItemProps, - 'style' | 'extra' | 'clickable' | 'arrow' | 'description' + 'style' | 'extra' | 'clickable' | 'arrow' | 'arrowIcon' | 'description' > & { label?: ReactNode help?: ReactNode + helpIcon?: ReactNode hasFeedback?: boolean required?: boolean noStyle?: boolean @@ -79,10 +81,12 @@ type FormItemLayoutProps = Pick< | 'disabled' | 'label' | 'help' + | 'helpIcon' | 'hidden' | 'layout' | 'extra' | 'clickable' + | 'arrowIcon' | 'arrow' | 'description' | 'childElementPosition' @@ -94,24 +98,30 @@ type FormItemLayoutProps = Pick< children: ReactNode } & NativeProps +const defaultProps = { + helpIcon: , +} + const FormItemLayout: FC = props => { + const { locale, form: componentConfig = {} } = useConfig() + const { style, extra, label, help, + helpIcon, required, children, htmlFor, hidden, + arrowIcon, arrow, childElementPosition = 'normal', - } = props + } = mergeProps(defaultProps, componentConfig, props) const context = useContext(FormContext) - const { locale } = useConfig() - const hasFeedback = props.hasFeedback !== undefined ? props.hasFeedback : context.hasFeedback const layout = props.layout || context.layout @@ -162,7 +172,7 @@ const FormItemLayout: FC = props => { e.preventDefault() }} > - + {helpIcon} )} @@ -210,7 +220,7 @@ const FormItemLayout: FC = props => { disabled={disabled} onClick={props.onClick} clickable={props.clickable} - arrow={arrow} + arrowIcon={arrow || arrowIcon} >
any` | - | | hasFeedback | Whether to show error feedback | `boolean` | `true` | | help | Prompt text | `ReactNode` | - | +| helpIcon | Prompt icon | `ReactNode` | `` | | hidden | Hide this field | `boolean` | `false` | | initialValue | Config sub default value. Form `initialValues` get higher priority when conflict. | `any` | - | | label | Label name | `ReactNode` | - | diff --git a/src/components/form/index.zh.md b/src/components/form/index.zh.md index c937dadfc1..2bc3bcf009 100644 --- a/src/components/form/index.zh.md +++ b/src/components/form/index.zh.md @@ -93,6 +93,7 @@ const validateMessages = { | getValueProps | 为子元素添加额外的属性 | `(value) => any` | - | | hasFeedback | 是否展示错误反馈 | `boolean` | `true` | | help | 提示文本 | `ReactNode` | - | +| helpIcon | 提示图标 | `ReactNode` | `` | | hidden | 是否隐藏整个字段 | `boolean` | `false` | | initialValue | 设置子元素默认值,如果与 Form 的 `initialValues` 冲突则以 Form 为准 | `any` | - | | label | 标签名 | `ReactNode` | - | diff --git a/src/components/input/index.en.md b/src/components/input/index.en.md index 5f75d954a0..4a3aa1bd35 100644 --- a/src/components/input/index.en.md +++ b/src/components/input/index.en.md @@ -21,6 +21,7 @@ The `Input` component is layout-independent. It only includes the most basic inp | Name | Description | Type | Default | | --- | --- | --- | --- | | clearable | Whether to enable the clear icon, the input box will be cleared after clicking the clear icon | `boolean` | `false` | +| clearIcon | Custom clear icon | `ReactNode` | `` | | defaultValue | The default value | `string` | - | | disabled | Whether it is disabled or not | `boolean` | `false` | | id | The `id` of the `input` element, usually used with `label` | `string` | - | diff --git a/src/components/input/index.zh.md b/src/components/input/index.zh.md index 72d69b76d1..4f3f937813 100644 --- a/src/components/input/index.zh.md +++ b/src/components/input/index.zh.md @@ -21,6 +21,7 @@ | 属性 | 说明 | 类型 | 默认值 | | --- | --- | --- | --- | | clearable | 是否启用清除图标,点击清除图标后会清空输入框 | `boolean` | `false` | +| clearIcon | 自定义清除图标 | `ReactNode` | `` | | defaultValue | 默认值 | `string` | - | | disabled | 是否禁用 | `boolean` | `false` | | id | `input` 元素的 `id`,常用来配合 `label` 使用 | `string` | - | diff --git a/src/components/input/input.tsx b/src/components/input/input.tsx index 94d8dfdc78..d4164c9927 100644 --- a/src/components/input/input.tsx +++ b/src/components/input/input.tsx @@ -1,4 +1,10 @@ -import React, { useState, forwardRef, useImperativeHandle, useRef } from 'react' +import React, { + useState, + forwardRef, + useImperativeHandle, + useRef, + ReactNode, +} from 'react' import { usePropsValue } from '../../utils/use-props-value' import { CloseCircleFill } from 'antd-mobile-icons' import { NativeProps, withNativeProps } from '../../utils/native-props' @@ -50,6 +56,7 @@ export type InputProps = Pick< defaultValue?: string onChange?: (val: string) => void clearable?: boolean + clearIcon?: ReactNode onlyShowClearWhenFocus?: boolean onClear?: () => void onEnterPress?: (e: React.KeyboardEvent) => void @@ -70,6 +77,7 @@ export type InputProps = Pick< const defaultProps = { defaultValue: '', + clearIcon: , onlyShowClearWhenFocus: true, } @@ -81,12 +89,12 @@ export type InputRef = { } export const Input = forwardRef((p, ref) => { - const props = mergeProps(defaultProps, p) + const { locale, input: componentConfig = {} } = useConfig() + const props = mergeProps(defaultProps, componentConfig, p) const [value, setValue] = usePropsValue(props) const [hasFocus, setHasFocus] = useState(false) const compositionStartRef = useRef(false) const nativeInputRef = useRef(null) - const { locale } = useConfig() useImperativeHandle(ref, () => ({ clear: () => { @@ -219,7 +227,7 @@ export const Input = forwardRef((p, ref) => { }} aria-label={locale.Input.clear} > - + {props.clearIcon}
)}
diff --git a/src/components/list/list-item.tsx b/src/components/list/list-item.tsx index d005c59ee1..a614bdb4e5 100644 --- a/src/components/list/list-item.tsx +++ b/src/components/list/list-item.tsx @@ -1,9 +1,10 @@ -import React from 'react' -import type { FC, ReactNode } from 'react' -import { NativeProps, withNativeProps } from '../../utils/native-props' import { RightOutline } from 'antd-mobile-icons' import classNames from 'classnames' +import type { FC, ReactNode } from 'react' +import React from 'react' import { isNodeWithContent } from '../../utils/is-node-with-content' +import { NativeProps, withNativeProps } from '../../utils/native-props' +import { useConfig } from '../config-provider' const classPrefix = `adm-list-item` @@ -14,16 +15,21 @@ export type ListItemProps = { prefix?: ReactNode extra?: ReactNode clickable?: boolean - arrow?: boolean | ReactNode + arrowIcon?: boolean | ReactNode disabled?: boolean onClick?: (e: React.MouseEvent) => void + /** + * @deprecated use `arrowIcon` instead + */ + arrow?: boolean | ReactNode } & NativeProps< '--prefix-width' | '--align-items' | '--active-background-color' > export const ListItem: FC = props => { + const { list: componentConfig = {} } = useConfig() const clickable = props.clickable ?? !!props.onClick - const arrow = props.arrow === undefined ? clickable : props.arrow + const arrow = props.arrow ?? props.arrowIcon ?? clickable const content = (
@@ -46,7 +52,9 @@ export const ListItem: FC = props => { )} {isNodeWithContent(arrow) && (
- {arrow === true ? : arrow} + {arrow === true + ? componentConfig?.arrowIcon || + : arrow}
)}
diff --git a/src/components/nav-bar/demos/demo1.tsx b/src/components/nav-bar/demos/demo1.tsx index ccd25f452e..d958efbbbe 100644 --- a/src/components/nav-bar/demos/demo1.tsx +++ b/src/components/nav-bar/demos/demo1.tsx @@ -1,7 +1,7 @@ -import React from 'react' import { NavBar, Space, Toast } from 'antd-mobile' +import { CloseOutline, MoreOutline, SearchOutline } from 'antd-mobile-icons' import { DemoBlock } from 'demos' -import { SearchOutline, MoreOutline, CloseOutline } from 'antd-mobile-icons' +import React from 'react' import './demo1.less' @@ -34,13 +34,13 @@ export default () => { - + 标题 - } onBack={back}> + } onBack={back}> 标题 diff --git a/src/components/nav-bar/index.en.md b/src/components/nav-bar/index.en.md index 4c3b2a88de..4690571dea 100644 --- a/src/components/nav-bar/index.en.md +++ b/src/components/nav-bar/index.en.md @@ -16,8 +16,8 @@ Need to display the title and action of the current page content. | Name | Description | Type | Default | | --- | --- | --- | --- | -| back | The returned text of the area, if `null` returned, `backArrow` would not be rendered | `ReacNode \| null` | `''` | -| backArrow | Whether to display the arrow of the return area, you can also pass in `ReactNode` for customization | `boolean \| ReactNode` | `true` | +| back | The returned text of the area, if `null` returned, `backIcon` would not be rendered | `ReacNode \| null` | `''` | +| backIcon | Whether to display the back arrow icon of the return area, you can also pass in `ReactNode` for customization | `boolean \| ReactNode` | `true` | | children | Title | `ReactNode` | - | | left | Content on the left, rendered on the right side of the return area | `ReactNode` | - | | onBack | Callback after clicking the return area | `() => void` | - | diff --git a/src/components/nav-bar/index.zh.md b/src/components/nav-bar/index.zh.md index 40f030c678..18ca1c4d25 100644 --- a/src/components/nav-bar/index.zh.md +++ b/src/components/nav-bar/index.zh.md @@ -16,8 +16,8 @@ | 属性 | 说明 | 类型 | 默认值 | | --- | --- | --- | --- | -| back | 返回区域的文字,如果为 `null` 的话,`backArrow` 也不会渲染 | `ReactNode \| null` | `''` | -| backArrow | 是否显示返回区域的箭头,也可以传入 `ReactNode` 进行自定义 | `boolean \| ReactNode` | `true` | +| back | 返回区域的文字,如果为 `null` 的话,`backIcon` 也不会渲染 | `ReactNode \| null` | `''` | +| backIcon | 是否显示返回区域的箭头,也可以传入 `ReactNode` 进行自定义 | `boolean \| ReactNode` | `true` | | children | 标题 | `ReactNode` | - | | left | 左侧内容,渲染在返回区域的右侧 | `ReactNode` | - | | onBack | 点击返回区域后的回调 | `() => void` | - | diff --git a/src/components/nav-bar/nav-bar.tsx b/src/components/nav-bar/nav-bar.tsx index 81ff6ef9c9..5060b3a0fe 100644 --- a/src/components/nav-bar/nav-bar.tsx +++ b/src/components/nav-bar/nav-bar.tsx @@ -1,14 +1,19 @@ -import React from 'react' -import type { FC, ReactNode } from 'react' -import classNames from 'classnames' import { LeftOutline } from 'antd-mobile-icons' +import classNames from 'classnames' +import type { FC, ReactNode } from 'react' +import React from 'react' import { NativeProps, withNativeProps } from '../../utils/native-props' import { mergeProps } from '../../utils/with-default-props' +import { useConfig } from '../config-provider' const classPrefix = `adm-nav-bar` export type NavBarProps = { back?: ReactNode + backIcon?: boolean | ReactNode + /** + * @deprecated use `backIcon` instead + */ backArrow?: boolean | ReactNode left?: ReactNode right?: ReactNode @@ -17,11 +22,13 @@ export type NavBarProps = { } & NativeProps<'--height' | '--border-bottom'> const defaultProps = { - backArrow: true, + backIcon: true, } + export const NavBar: FC = p => { - const props = mergeProps(defaultProps, p) - const { back, backArrow } = props + const { navBar: componentConfig = {} } = useConfig() + const props = mergeProps(defaultProps, componentConfig, p) + const { back, backIcon, backArrow } = props return withNativeProps( props, @@ -29,9 +36,13 @@ export const NavBar: FC = p => {
{back !== null && (
- {backArrow && ( + {(backIcon || backArrow) && ( - {backArrow === true ? : backArrow} + {backIcon === true || backArrow === true ? ( + + ) : ( + backIcon || backArrow + )} )} diff --git a/src/components/nav-bar/tests/nav-bar.test.tsx b/src/components/nav-bar/tests/nav-bar.test.tsx new file mode 100644 index 0000000000..3df9364009 --- /dev/null +++ b/src/components/nav-bar/tests/nav-bar.test.tsx @@ -0,0 +1,20 @@ +import React from 'react' +import { render, screen } from 'testing' +import NavBar from '..' + +const classPrefix = `adm-result` + +describe('NavBar', () => { + test('render title', () => { + render(Title) + expect(screen.getByText('Title')).toBeInTheDocument() + }) + test('render back arrow', () => { + render(Title) + expect(screen.getByText('Title')).toBeInTheDocument() + }) + test('render custom back arrow', () => { + render(Title) + expect(screen.getByText('Back')).toBeInTheDocument() + }) +}) diff --git a/src/components/notice-bar/index.en.md b/src/components/notice-bar/index.en.md index ab0c30fa87..4149d54876 100644 --- a/src/components/notice-bar/index.en.md +++ b/src/components/notice-bar/index.en.md @@ -17,6 +17,7 @@ It is applicable to the notification of information in the current page, which i | Name | Description | Type | Default | | --- | --- | --- | --- | | closeable | Whether it can be closed | `boolean` | `false` | +| closeIcon | Custom close button icon | `ReactNode` | `` | | color | The type of the NoticeBar | `'default' \| 'alert' \| 'error' \| 'info'` | `'default'` | | content | The content of the NoticeBar | `React.ReactNode` | - | | delay | Delay to start scrolling, unit `ms` | `number` | `2000` | diff --git a/src/components/notice-bar/index.zh.md b/src/components/notice-bar/index.zh.md index 65f5d0a240..14d5407e48 100644 --- a/src/components/notice-bar/index.zh.md +++ b/src/components/notice-bar/index.zh.md @@ -17,6 +17,7 @@ | 属性 | 说明 | 类型 | 默认值 | | --- | --- | --- | --- | | closeable | 是否可关闭 | `boolean` | `false` | +| closeIcon | 自定义关闭按钮图标 | `ReactNode` | `` | | color | 通告栏的类型 | `'default' \| 'alert' \| 'error' \| 'info'` | `'default'` | | content | 公告内容 | `React.ReactNode` | - | | delay | 开始滚动的延迟,单位 `ms` | `number` | `2000` | diff --git a/src/components/notice-bar/notice-bar.less b/src/components/notice-bar/notice-bar.less index d23d833844..13ef66513b 100644 --- a/src/components/notice-bar/notice-bar.less +++ b/src/components/notice-bar/notice-bar.less @@ -79,9 +79,6 @@ display: flex; align-items: center; justify-content: center; - } - - &-close-icon { font-size: var(--adm-font-size-10); } diff --git a/src/components/notice-bar/notice-bar.tsx b/src/components/notice-bar/notice-bar.tsx index 655cb462cd..cbc6480876 100644 --- a/src/components/notice-bar/notice-bar.tsx +++ b/src/components/notice-bar/notice-bar.tsx @@ -1,12 +1,13 @@ -import React, { useState, useRef, memo } from 'react' -import type { ReactNode } from 'react' -import classNames from 'classnames' -import { CloseOutline, SoundOutline } from 'antd-mobile-icons' import { useTimeout } from 'ahooks' -import { mergeProps } from '../../utils/with-default-props' +import { CloseOutline, SoundOutline } from 'antd-mobile-icons' +import classNames from 'classnames' +import type { ReactNode } from 'react' +import React, { memo, useRef, useState } from 'react' import { NativeProps, withNativeProps } from '../../utils/native-props' -import { useResizeEffect } from '../../utils/use-resize-effect' import { useMutationEffect } from '../../utils/use-mutation-effect' +import { useResizeEffect } from '../../utils/use-resize-effect' +import { mergeProps } from '../../utils/with-default-props' +import { useConfig } from '../config-provider' const classPrefix = `adm-notice-bar` @@ -21,6 +22,8 @@ export type NoticeBarProps = { content: ReactNode /** Whether it can be closed */ closeable?: boolean + /** Custom close icon */ + closeIcon?: ReactNode /** Callback when closed */ onClose?: () => void /** Event when click */ @@ -44,12 +47,14 @@ const defaultProps = { color: 'default', delay: 2000, speed: 50, - wrap: false, icon: , + closeIcon: , + wrap: false, } export const NoticeBar = memo(p => { - const props = mergeProps(defaultProps, p) + const { noticeBar: componentConfig = {} } = useConfig() + const props = mergeProps(defaultProps, componentConfig, p) const containerRef = useRef(null) const textRef = useRef(null) @@ -149,7 +154,7 @@ export const NoticeBar = memo(p => { props.onClose?.() }} > - + {props.closeIcon}
)} diff --git a/src/components/notice-bar/tests/notice-bar.test.tsx b/src/components/notice-bar/tests/notice-bar.test.tsx index 66490b704a..e0c1e542e6 100644 --- a/src/components/notice-bar/tests/notice-bar.test.tsx +++ b/src/components/notice-bar/tests/notice-bar.test.tsx @@ -30,7 +30,7 @@ describe('NoticeBar', () => { ) const el = getByTestId('notice') - const iconEl = el.querySelectorAll(`.${classPrefix}-close-icon`)[0] + const iconEl = el.querySelectorAll(`.${classPrefix}-close`)[0] expect(iconEl).toBeVisible() fireEvent.click(iconEl) diff --git a/src/components/popup/index.en.md b/src/components/popup/index.en.md index 33bc6e6cdd..35fc73e69e 100644 --- a/src/components/popup/index.en.md +++ b/src/components/popup/index.en.md @@ -24,6 +24,7 @@ It is suitable for displaying pop-up windows, information prompts, selection inp | bodyStyle | Content section style | `React.CSSProperties` | - | | className | Container class name | `string` | - | | closeOnMaskClick | Whether to close after clicking the mask layer | `boolean` | `false` | +| closeIcon | Custom close button icon | `ReactNode` | `` | | destroyOnClose | Destroy `dom` when not visible | `boolean` | `false` | | forceRender | Render content forcely | `boolean` | `false` | | getContainer | To get the specified mounted `HTML` node, the default is `body`, if `null` returned, it would be rendered to the current node | `HTMLElement \| () => HTMLElement \| null` | `() => document.body` | diff --git a/src/components/popup/index.zh.md b/src/components/popup/index.zh.md index 6c699b774c..88f9f7ad56 100644 --- a/src/components/popup/index.zh.md +++ b/src/components/popup/index.zh.md @@ -24,6 +24,7 @@ | bodyStyle | 内容区域样式 | `React.CSSProperties` | - | | className | 容器类名 | `string` | - | | closeOnMaskClick | 点击背景蒙层后是否关闭 | `boolean` | `false` | +| closeIcon | 自定义关闭按钮图标 | `ReactNode` | `` | | destroyOnClose | 不可见时是否销毁 `DOM` 结构 | `boolean` | `false` | | forceRender | 强制渲染内容 | `boolean` | `false` | | getContainer | 指定挂载的 `HTML` 节点,默认为 `body`,如果为 `null` 的话,会渲染到当前节点 | `HTMLElement \| () => HTMLElement \| null` | `() => document.body` | diff --git a/src/components/popup/popup-base-props.ts b/src/components/popup/popup-base-props.tsx similarity index 86% rename from src/components/popup/popup-base-props.ts rename to src/components/popup/popup-base-props.tsx index dc3817366a..5c47b61f39 100644 --- a/src/components/popup/popup-base-props.ts +++ b/src/components/popup/popup-base-props.tsx @@ -1,8 +1,8 @@ -import React from 'react' -import type { CSSProperties } from 'react' +import React, { CSSProperties, ReactNode } from 'react' import { GetContainer } from '../../utils/render-to-container' import { MaskProps } from '../mask' import { PropagationEvent } from '../../utils/with-stop-propagation' +import { CloseOutline } from 'antd-mobile-icons' export type PopupBaseProps = { afterClose?: () => void @@ -10,6 +10,7 @@ export type PopupBaseProps = { bodyClassName?: string bodyStyle?: CSSProperties closeOnMaskClick?: boolean + closeIcon?: ReactNode destroyOnClose?: boolean disableBodyScroll?: boolean forceRender?: boolean @@ -27,6 +28,7 @@ export type PopupBaseProps = { export const defaultPopupBaseProps = { closeOnMaskClick: false, + closeIcon: , destroyOnClose: false, disableBodyScroll: true, forceRender: false, diff --git a/src/components/popup/popup.tsx b/src/components/popup/popup.tsx index 45bb0570e9..c736cb0b08 100644 --- a/src/components/popup/popup.tsx +++ b/src/components/popup/popup.tsx @@ -10,7 +10,6 @@ import { renderToContainer } from '../../utils/render-to-container' import { useSpring, animated } from '@react-spring/web' import { withStopPropagation } from '../../utils/with-stop-propagation' import { ShouldRender } from '../../utils/should-render' -import { CloseOutline } from 'antd-mobile-icons' import { defaultPopupBaseProps, PopupBaseProps } from './popup-base-props' import { useInnerVisible } from '../../utils/use-inner-visible' import { useConfig } from '../config-provider' @@ -32,7 +31,8 @@ const defaultProps = { } export const Popup: FC = p => { - const props = mergeProps(defaultProps, p) + const { locale, popup: componentConfig = {} } = useConfig() + const props = mergeProps(defaultProps, componentConfig, p) const bodyCls = classNames( `${classPrefix}-body`, @@ -40,7 +40,6 @@ export const Popup: FC = p => { `${classPrefix}-body-position-${props.position}` ) - const { locale } = useConfig() const [active, setActive] = useState(props.visible) const ref = useRef(null) useLockScroll(ref, props.disableBodyScroll && active ? 'strict' : false) @@ -156,7 +155,7 @@ export const Popup: FC = p => { role='button' aria-label={locale.common.close} > - + {props.closeIcon} )} {props.children} diff --git a/src/components/result-page/result-page.tsx b/src/components/result-page/result-page.tsx index 34b8e4a703..71acddea86 100644 --- a/src/components/result-page/result-page.tsx +++ b/src/components/result-page/result-page.tsx @@ -1,29 +1,14 @@ import React, { useState } from 'react' import type { FC, ReactNode } from 'react' - -import { - CheckCircleFill, - CloseCircleFill, - InformationCircleFill, - ClockCircleFill, - ExclamationCircleFill, -} from 'antd-mobile-icons' import classNames from 'classnames' import { NativeProps, withNativeProps } from '../../utils/native-props' import { mergeProps } from '../../utils/with-default-props' import { isNodeWithContent } from '../../utils/is-node-with-content' import Button from '../button' +import { useResultIcon } from '../result/use-result-icon' const classPrefix = `adm-result-page` -const iconRecord = { - success: CheckCircleFill, - error: CloseCircleFill, - info: InformationCircleFill, - waiting: ClockCircleFill, - warning: ExclamationCircleFill, -} - interface ResultPageDetail { label: ReactNode value: ReactNode @@ -67,7 +52,7 @@ export const ResultPage: FC = p => { onPrimaryButtonClick, onSecondaryButtonClick, } = props - const resultIcon = icon || React.createElement(iconRecord[status]) + const fallbackIcon = useResultIcon(status) const [collapse, setCollapse] = useState(true) @@ -78,7 +63,7 @@ export const ResultPage: FC = p => { props,
-
{resultIcon}
+
{icon || fallbackIcon}
{title}
{isNodeWithContent(description) ? (
{description}
diff --git a/src/components/result/result.tsx b/src/components/result/result.tsx index 32041b9bef..ffe6da9d8c 100644 --- a/src/components/result/result.tsx +++ b/src/components/result/result.tsx @@ -1,26 +1,12 @@ import React from 'react' import type { FC, ReactNode } from 'react' import classNames from 'classnames' -import { - CheckCircleFill, - CloseCircleFill, - InformationCircleFill, - ClockCircleFill, - ExclamationCircleFill, -} from 'antd-mobile-icons' import { NativeProps, withNativeProps } from '../../utils/native-props' import { mergeProps } from '../../utils/with-default-props' +import { useResultIcon } from './use-result-icon' const classPrefix = `adm-result` -const iconRecord = { - success: CheckCircleFill, - error: CloseCircleFill, - info: InformationCircleFill, - waiting: ClockCircleFill, - warning: ExclamationCircleFill, -} - const defaultProps = { status: 'info', } @@ -35,13 +21,13 @@ export type ResultProps = { export const Result: FC = p => { const props = mergeProps(defaultProps, p) const { status, title, description, icon } = props + const fallbackIcon = useResultIcon(status) if (!status) return null - const resultIcon = icon || React.createElement(iconRecord[status]) return withNativeProps( props,
-
{resultIcon}
+
{icon || fallbackIcon}
{title}
{!!description && (
{description}
diff --git a/src/components/result/tests/result-icon.test.tsx b/src/components/result/tests/result-icon.test.tsx new file mode 100644 index 0000000000..ca7d63ab17 --- /dev/null +++ b/src/components/result/tests/result-icon.test.tsx @@ -0,0 +1,38 @@ +import React from 'react' +import { render, screen } from 'testing' +import Result from '..' +import { useResultIcon } from '../use-result-icon' + +const ResultIcon = (props: any) => { + const icon = useResultIcon(props.status) + return
{icon}
+} + +const classPrefix = `adm-result` + +describe('ResultIcon', () => { + test('renders with success status', () => { + render() + expect(document.querySelector('.antd-mobile-icon')).toBeTruthy() + }) + test('renders with error status', () => { + render() + expect(document.querySelector('.antd-mobile-icon')).toBeTruthy() + }) + test('renders with info status', () => { + render() + expect(document.querySelector('.antd-mobile-icon')).toBeTruthy() + }) + test('renders with waiting status', () => { + render() + expect(document.querySelector('.antd-mobile-icon')).toBeTruthy() + }) + test('renders with warning status', () => { + render() + expect(document.querySelector('.antd-mobile-icon')).toBeTruthy() + }) + test('renders with none status', () => { + render() + expect(document.querySelector('.antd-mobile-icon')).toBeFalsy() + }) +}) diff --git a/src/components/result/use-result-icon.tsx b/src/components/result/use-result-icon.tsx new file mode 100644 index 0000000000..c98e2ded9f --- /dev/null +++ b/src/components/result/use-result-icon.tsx @@ -0,0 +1,38 @@ +import React from 'react' +import { + CheckCircleFill, + CloseCircleFill, + InformationCircleFill, + ClockCircleFill, + ExclamationCircleFill, +} from 'antd-mobile-icons' +import { useConfig } from '../config-provider' + +export type ResultIconProps = {} + +export const useResultIcon = ( + status?: 'success' | 'error' | 'info' | 'waiting' | 'warning' +) => { + const { result: componentConfig = {} } = useConfig() + const { + successIcon = , + errorIcon = , + infoIcon = , + waitingIcon = , + warningIcon = , + } = componentConfig || {} + switch (status) { + case 'success': + return successIcon + case 'error': + return errorIcon + case 'info': + return infoIcon + case 'waiting': + return waitingIcon + case 'warning': + return warningIcon + default: + return null + } +} diff --git a/src/components/search-bar/index.en.md b/src/components/search-bar/index.en.md index dad981d8bf..ca7c5877c6 100644 --- a/src/components/search-bar/index.en.md +++ b/src/components/search-bar/index.en.md @@ -21,7 +21,7 @@ Narrow down the information pool to get targeted information quickly and easily. | cancelText | Text of the cancel button | `string` | `'取消'` | | clearOnCancel | Whether to clear the input after the cancel button is clicked | `boolean` | `true` | | clearable | Whether to enable the clear icon, the input would be cleared after the clear icon is clicked | `boolean` | `true` | -| icon | Icon | `ReactNode` | `` | +| searchIcon | Custom search icon | `ReactNode` | `` | | maxLength | The maximum number of characters the user can enter | `number` | - | | onBlur | Triggered when the input lose focus | `(e: React.FocusEvent) => void` | - | | onCancel | Triggered when the cancel button is clicked | `() => void` | - | diff --git a/src/components/search-bar/index.zh.md b/src/components/search-bar/index.zh.md index c0998f90bc..de6a440492 100644 --- a/src/components/search-bar/index.zh.md +++ b/src/components/search-bar/index.zh.md @@ -21,7 +21,7 @@ | cancelText | 取消按钮的文案 | `string` | `'取消'` | | clearOnCancel | 点击取消按钮后是否清空输入框 | `boolean` | `true` | | clearable | 是否启用清除图标,点击清除图标后会清空输入框 | `boolean` | `true` | -| icon | 图标 | `ReactNode` | `` | +| searchIcon | 自定义搜索图标 | `ReactNode` | `` | | maxLength | 输入的最大字符数 | `number` | - | | onBlur | 输入框失去焦点时触发 | `(e: React.FocusEvent) => void` | - | | onCancel | 点击取消按钮时触发 | `() => void` | - | diff --git a/src/components/search-bar/search-bar.tsx b/src/components/search-bar/search-bar.tsx index 0614f7207f..50b7e0e58e 100644 --- a/src/components/search-bar/search-bar.tsx +++ b/src/components/search-bar/search-bar.tsx @@ -1,13 +1,13 @@ -import React, { useState, useRef, forwardRef, useImperativeHandle } from 'react' -import type { ReactNode } from 'react' +import { SearchOutline } from 'antd-mobile-icons' import classNames from 'classnames' -import Input, { InputRef, InputProps } from '../input' -import Button from '../button' +import type { ReactNode } from 'react' +import React, { forwardRef, useImperativeHandle, useRef, useState } from 'react' import { NativeProps, withNativeProps } from '../../utils/native-props' -import { mergeProps } from '../../utils/with-default-props' -import { SearchOutline } from 'antd-mobile-icons' import { usePropsValue } from '../../utils/use-props-value' +import { mergeProps } from '../../utils/with-default-props' +import Button from '../button' import { useConfig } from '../config-provider' +import Input, { InputProps, InputRef } from '../input' const classPrefix = `adm-search-bar` @@ -25,6 +25,10 @@ export type SearchBarProps = Pick< onlyShowClearWhenFocus?: boolean showCancelButton?: boolean | ((focus: boolean, value: string) => boolean) cancelText?: string + searchIcon?: ReactNode + /** + * @deprecated use `searchIcon` instead + */ icon?: ReactNode clearOnCancel?: boolean onSearch?: (val: string) => void @@ -44,13 +48,14 @@ const defaultProps = { showCancelButton: false as NonNullable, defaultValue: '', clearOnCancel: true, - icon: , + searchIcon: , } export const SearchBar = forwardRef((p, ref) => { - const { locale } = useConfig() + const { locale, searchBar: componentConfig = {} } = useConfig() const props = mergeProps( defaultProps, + componentConfig, { cancelText: locale.common.cancel, }, @@ -111,13 +116,16 @@ export const SearchBar = forwardRef((p, ref) => { })} >
- {props.icon && ( -
{props.icon}
+ {(props.searchIcon || props.icon) && ( +
+ {props.searchIcon || props.icon} +
)} { fireEvent.click(getByText('success')) await waitForContentShow('content success') expect( - document.querySelectorAll(`.${classPrefix}-icon-success`)[0] + document.getElementById('CheckOutline-CheckOutline') ).toBeInTheDocument() fireEvent.click(getByText('fail')) await waitForContentShow('content fail') expect( - document.querySelectorAll(`.${classPrefix}-icon-fail`)[0] + document.getElementById('CloseOutline-CloseOutline') ).toBeInTheDocument() fireEvent.click(getByText('loading')) await waitForContentShow('content loading') - expect( - document.querySelectorAll(`.${classPrefix}-loading`)[0] - ).toBeInTheDocument() + expect(document.querySelector('.adm-spin-loading')).toBeInTheDocument() }) test('custom icon', async () => { diff --git a/src/components/toast/toast.less b/src/components/toast/toast.less index 7a23a018a7..d3d855f2ac 100644 --- a/src/components/toast/toast.less +++ b/src/components/toast/toast.less @@ -43,8 +43,3 @@ } } } - -.@{class-prefix-toast}-loading { - --size: 48px; - margin: 0 auto 8px; -} diff --git a/src/components/toast/toast.tsx b/src/components/toast/toast.tsx index b9e23ac7a9..fc045c1d76 100644 --- a/src/components/toast/toast.tsx +++ b/src/components/toast/toast.tsx @@ -1,13 +1,14 @@ -import React, { useMemo } from 'react' -import type { FC, ReactNode } from 'react' -import classNames from 'classnames' import { CheckOutline, CloseOutline } from 'antd-mobile-icons' -import Mask from '../mask' -import type { MaskProps } from '../mask' +import classNames from 'classnames' +import type { FC, ReactNode } from 'react' +import React, { useMemo } from 'react' +import { GetContainer } from '../../utils/render-to-container' import { mergeProps } from '../../utils/with-default-props' import { PropagationEvent } from '../../utils/with-stop-propagation' -import { GetContainer } from '../../utils/render-to-container' import AutoCenter from '../auto-center' +import { useConfig } from '../config-provider' +import type { MaskProps } from '../mask' +import Mask from '../mask' import SpinLoading from '../spin-loading' const classPrefix = `adm-toast` @@ -32,19 +33,22 @@ const defaultProps = { } export const InternalToast: FC = p => { - const props = mergeProps(defaultProps, p) + const { toast: componentConfig = {} } = useConfig() + const props = mergeProps(defaultProps, componentConfig, p) const { maskClickable, content, icon, position } = props const iconElement = useMemo(() => { if (icon === null || icon === undefined) return null switch (icon) { case 'success': - return + return componentConfig?.successIcon || case 'fail': - return + return componentConfig?.errorIcon || case 'loading': return ( - + componentConfig?.loadingIcon || ( + + ) ) default: return icon diff --git a/src/components/virtual-input/virtual-input.tsx b/src/components/virtual-input/virtual-input.tsx index 955496f4b0..bbdbacd183 100644 --- a/src/components/virtual-input/virtual-input.tsx +++ b/src/components/virtual-input/virtual-input.tsx @@ -25,7 +25,10 @@ export type VirtualInputProps = { keyboard?: ReactElement clearable?: boolean onClear?: () => void -} & Pick & +} & Pick< + InputProps, + 'value' | 'onChange' | 'placeholder' | 'disabled' | 'clearIcon' +> & NativeProps< | '--font-size' | '--color' @@ -38,6 +41,7 @@ export type VirtualInputProps = { const defaultProps = { defaultValue: '', + clearIcon: , } export type VirtualInputRef = { @@ -47,12 +51,12 @@ export type VirtualInputRef = { export const VirtualInput = forwardRef( (p, ref) => { - const props = mergeProps(defaultProps, p) + const { locale, input: componentConfig = {} } = useConfig() + const props = mergeProps(defaultProps, componentConfig, p) const [value, setValue] = usePropsValue(props) const rootRef = useRef(null) const contentRef = useRef(null) const [hasFocus, setHasFocus] = useState(false) - const { locale } = useConfig() function scrollToEnd() { const root = rootRef.current @@ -157,7 +161,7 @@ export const VirtualInput = forwardRef( role='button' aria-label={locale.Input.clear} > - + {props.clearIcon}
)} {[undefined, null, ''].includes(value) && ( diff --git a/src/utils/with-default-props.tsx b/src/utils/with-default-props.tsx index 3446d7dea6..84bbff841f 100644 --- a/src/utils/with-default-props.tsx +++ b/src/utils/with-default-props.tsx @@ -1,5 +1,6 @@ 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 => { From 884deac0f2231d4af48907cb60fbf6b2daefd880 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?=E4=BA=8C=E8=B4=A7=E6=9C=BA=E5=99=A8=E4=BA=BA?= Date: Tue, 16 Apr 2024 19:37:34 +0800 Subject: [PATCH 2/9] refactor: use util --- src/components/collapse/collapse.tsx | 47 +++++++++++++++------------- src/utils/with-default-props.tsx | 13 ++++++++ 2 files changed, 38 insertions(+), 22 deletions(-) diff --git a/src/components/collapse/collapse.tsx b/src/components/collapse/collapse.tsx index d6090103e1..1e3515d23c 100644 --- a/src/components/collapse/collapse.tsx +++ b/src/components/collapse/collapse.tsx @@ -11,6 +11,7 @@ import { usePropsValue } from '../../utils/use-props-value' import { mergeProps } from '../../utils/with-default-props' import { useConfig } from '../config-provider' import List from '../list' +import useComposeProp from '../../hooks/useComposeProp' const classPrefix = `adm-collapse` @@ -129,13 +130,11 @@ export type CollapseProps = ( children?: ReactNode } & NativeProps -const defaultProps = {} - -export const Collapse: FC = p => { +export const Collapse: FC = props => { const { collapse: componentConfig = {} } = useConfig() - const props = mergeProps(defaultProps, componentConfig, p) + const mergedProps = mergeProps(componentConfig, props) const panels: ReactElement[] = [] - traverseReactNode(props.children, child => { + traverseReactNode(mergedProps.children, child => { if (!isValidElement(child)) return const key = child.key if (typeof key !== 'string') return @@ -144,11 +143,11 @@ export const Collapse: FC = p => { }) const handlePropsValue = () => { - if (!props.accordion) { + if (!mergedProps.accordion) { return { - value: props.activeKey, - defaultValue: props.defaultActiveKey ?? [], - onChange: props.onChange, + value: mergedProps.activeKey, + defaultValue: mergedProps.defaultActiveKey ?? [], + onChange: mergedProps.onChange, } } @@ -160,20 +159,22 @@ export const Collapse: FC = p => { value: [], defaultValue: [], onChange: v => { - props.onChange?.(v[0] ?? null) + mergedProps.onChange?.(v[0] ?? null) }, } - if (props.activeKey === undefined) { + if (mergedProps.activeKey === undefined) { initValue.value = undefined - } else if (props.activeKey !== null) { - initValue.value = [props.activeKey] + } else if (mergedProps.activeKey !== null) { + initValue.value = [mergedProps.activeKey] } if ( - ![null, undefined].includes(props.defaultActiveKey as null | undefined) + ![null, undefined].includes( + mergedProps.defaultActiveKey as null | undefined + ) ) { - initValue.defaultValue = [props.defaultActiveKey as string] + initValue.defaultValue = [mergedProps.defaultActiveKey as string] } return initValue @@ -185,14 +186,14 @@ export const Collapse: FC = p => { activeKey === null ? [] : Array.isArray(activeKey) ? activeKey : [activeKey] return withNativeProps( - props, + mergedProps,
{panels.map(panel => { const key = panel.key as string const active = activeKeyList.includes(key) function handleClick(event: React.MouseEvent) { - if (props.accordion) { + if (mergedProps.accordion) { if (active) { setActiveKey([]) } else { @@ -209,11 +210,13 @@ export const Collapse: FC = p => { panel.props.onClick?.(event) } - const arrow = - panel.props.arrow || - panel.props.arrowIcon || - props.arrow || - props.arrowIcon + const arrow = mergeProps( + panel.props.arrowIcon, + panel.props.arrow, + mergedProps.arrowIcon, + mergedProps.arrow + ) + const arrowIcon = typeof arrow === 'function' ? ( arrow(active) diff --git a/src/utils/with-default-props.tsx b/src/utils/with-default-props.tsx index 84bbff841f..b55afb8c6a 100644 --- a/src/utils/with-default-props.tsx +++ b/src/utils/with-default-props.tsx @@ -12,3 +12,16 @@ export function mergeProps(...items: any[]) { }) return ret } + +/** + * Merge props and return the first non-undefined value. + * This is useful with legacy props that have been deprecated. + */ +export function mergeProp(...propList: T[]): T | undefined { + for (let i = 0; i < propList.length; i++) { + if (propList[i] !== undefined) { + return propList[i] + } + } + return undefined +} From bb866f17ca35a2bbcabff66e905831b0cc28cf29 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?=E4=BA=8C=E8=B4=A7=E6=9C=BA=E5=99=A8=E4=BA=BA?= Date: Tue, 16 Apr 2024 19:48:00 +0800 Subject: [PATCH 3/9] test: update testcase --- src/components/collapse/collapse.tsx | 9 +++++---- src/components/collapse/tests/collapse.test.tsx | 4 ++-- src/utils/with-default-props.tsx | 12 +++++++----- 3 files changed, 14 insertions(+), 11 deletions(-) diff --git a/src/components/collapse/collapse.tsx b/src/components/collapse/collapse.tsx index 1e3515d23c..f8ba2a68e6 100644 --- a/src/components/collapse/collapse.tsx +++ b/src/components/collapse/collapse.tsx @@ -3,15 +3,15 @@ import { useMount } from 'ahooks' import classNames from 'classnames' import type { FC, ReactElement, ReactNode } from 'react' import React, { isValidElement, useRef } from 'react' +import { DownOutline } from 'antd-mobile-icons' import { NativeProps, withNativeProps } from '../../utils/native-props' import { useShouldRender } from '../../utils/should-render' import { traverseReactNode } from '../../utils/traverse-react-node' import { useIsomorphicUpdateLayoutEffect } from '../../utils/use-isomorphic-update-layout-effect' import { usePropsValue } from '../../utils/use-props-value' -import { mergeProps } from '../../utils/with-default-props' +import { mergeProp, mergeProps } from '../../utils/with-default-props' import { useConfig } from '../config-provider' import List from '../list' -import useComposeProp from '../../hooks/useComposeProp' const classPrefix = `adm-collapse` @@ -210,11 +210,12 @@ export const Collapse: FC = props => { panel.props.onClick?.(event) } - const arrow = mergeProps( + const arrow = mergeProp( panel.props.arrowIcon, panel.props.arrow, mergedProps.arrowIcon, - mergedProps.arrow + mergedProps.arrow, + ) const arrowIcon = diff --git a/src/components/collapse/tests/collapse.test.tsx b/src/components/collapse/tests/collapse.test.tsx index bbca16693a..5d5c9dad66 100644 --- a/src/components/collapse/tests/collapse.test.tsx +++ b/src/components/collapse/tests/collapse.test.tsx @@ -143,7 +143,7 @@ describe('arrow', () => { ) - expect(screen.getByText('foo')).toBeVisible() + expect(screen.getByText('bar')).toBeVisible() }) it('both (deprecated) arrow and arrowIcon of pannel', async () => { @@ -154,7 +154,7 @@ describe('arrow', () => { ) - expect(screen.getByText('foo')).toBeVisible() + expect(screen.getByText('bar')).toBeVisible() }) it('arrow (deprecated) of collapse and arrowIcon of panel', async () => { diff --git a/src/utils/with-default-props.tsx b/src/utils/with-default-props.tsx index b55afb8c6a..2b82d198d3 100644 --- a/src/utils/with-default-props.tsx +++ b/src/utils/with-default-props.tsx @@ -4,11 +4,13 @@ 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 => { - Object.keys(item).forEach(key => { - if (item[key] !== undefined) { - ret[key] = item[key] - } - }) + if (item) { + Object.keys(item).forEach(key => { + if (item[key] !== undefined) { + ret[key] = item[key] + } + }) + } }) return ret } From ac64c95119dd3be2570fb55955e2fc764546cb6f Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?=E4=BA=8C=E8=B4=A7=E6=9C=BA=E5=99=A8=E4=BA=BA?= Date: Tue, 16 Apr 2024 20:06:02 +0800 Subject: [PATCH 4/9] test: update testcase --- src/components/dropdown/dropdown.tsx | 11 ++--- src/components/dropdown/item.tsx | 4 +- .../dropdown/tests/dropdown.test.tsx | 43 +++++++++++++++++++ 3 files changed, 51 insertions(+), 7 deletions(-) diff --git a/src/components/dropdown/dropdown.tsx b/src/components/dropdown/dropdown.tsx index 8ffd2db53b..3c55ff97d4 100644 --- a/src/components/dropdown/dropdown.tsx +++ b/src/components/dropdown/dropdown.tsx @@ -17,7 +17,7 @@ import React, { } from 'react' import { NativeProps, withNativeProps } from '../../utils/native-props' import { usePropsValue } from '../../utils/use-props-value' -import { mergeProps } from '../../utils/with-default-props' +import { mergeProp, mergeProps } from '../../utils/with-default-props' import Popup, { PopupProps } from '../popup' import { defaultPopupBaseProps } from '../popup/popup-base-props' import Item, { ItemChildrenWrap } from './item' @@ -100,11 +100,12 @@ const Dropdown = forwardRef>( child.props.onClick?.(event) }, active: child.key === value, - arrow: - child.props.arrow || - child.props.arrowIcon || - props.arrow || + arrowIcon: mergeProp( + child.props.arrowIcon, + child.props.arrow, props.arrowIcon, + props.arrow + ), } items.push(child) if (child.props.forceRender) popupForceRender = true diff --git a/src/components/dropdown/item.tsx b/src/components/dropdown/item.tsx index 1560272ceb..6277900e98 100644 --- a/src/components/dropdown/item.tsx +++ b/src/components/dropdown/item.tsx @@ -31,7 +31,7 @@ const defaultProps = { const Item: FC = props => { const { dropdown: componentConfig = {} } = useConfig() - const { active, arrowIcon, arrow, highlight, onClick, title } = mergeProps( + const { active, arrowIcon, highlight, onClick, title } = mergeProps( defaultProps, componentConfig, props @@ -51,7 +51,7 @@ const Item: FC = props => { [`${classPrefix}-title-arrow-active`]: active, })} > - {arrow || arrowIcon} + {arrowIcon}
diff --git a/src/components/dropdown/tests/dropdown.test.tsx b/src/components/dropdown/tests/dropdown.test.tsx index 852afc14a8..5883482a7c 100644 --- a/src/components/dropdown/tests/dropdown.test.tsx +++ b/src/components/dropdown/tests/dropdown.test.tsx @@ -107,4 +107,47 @@ describe('Dropdown', () => { fireEvent.click(screen.getByText('sorter')) expect(screen.getByText('click2')) }) + + describe('arrow', () => { + it('Dropdown - arrow', () => { + render( + + + + ) + expect(screen.getByText('little')).toBeVisible() + }) + + it('Dropdown - arrowIcon', () => { + render( + + + + ) + expect(screen.getByText('bamboo')).toBeVisible() + }) + + it('Dropdown.Item - arrow', () => { + render( + + + + ) + expect(screen.getByText('little')).toBeVisible() + }) + + it('Dropdown.Item - arrowIcon', () => { + render( + + + + ) + expect(screen.getByText('bamboo')).toBeVisible() + }) + }) }) From 46acb8a70fcb0bbcdf85d20b86843d87cf744164 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?=E4=BA=8C=E8=B4=A7=E6=9C=BA=E5=99=A8=E4=BA=BA?= Date: Wed, 17 Apr 2024 10:34:01 +0800 Subject: [PATCH 5/9] refactor: use util --- src/components/list/index.en.md | 2 +- src/components/list/index.zh.md | 2 +- src/components/list/list-item.tsx | 16 +++++++++++----- src/utils/is-node-with-content.ts | 3 +++ 4 files changed, 16 insertions(+), 7 deletions(-) diff --git a/src/components/list/index.en.md b/src/components/list/index.en.md index 4c533b99c2..ad5f9defd0 100644 --- a/src/components/list/index.en.md +++ b/src/components/list/index.en.md @@ -56,7 +56,7 @@ Carry text, lists, pictures, paragraphs, etc. cleanly and efficiently in the for | Name | Description | Type | Default | | --- | --- | --- | --- | -| arrow | Whether to show the arrow icon on the right side, also supports passing `ReactNode` to customize the icon. | `boolean \| ReactNode` | same as `clickable` | +| arrowIcon | Whether to show the arrow icon on the right side, also supports passing `ReactNode` to customize the icon. | `boolean \| ReactNode` | same as `clickable` | | children | The main content area in the middle of the list item. | `ReactNode` | - | | clickable | Whether to show click effect. | `boolean` | Defaults to `true` when the `onClick` prop is present, otherwise defaults to `false` | | description | The description area in the lower middle of the list item. | `ReactNode` | - | diff --git a/src/components/list/index.zh.md b/src/components/list/index.zh.md index ef9fbc51e0..0641cefd2d 100644 --- a/src/components/list/index.zh.md +++ b/src/components/list/index.zh.md @@ -56,7 +56,7 @@ | 属性 | 说明 | 类型 | 默认值 | | --- | --- | --- | --- | -| arrow | 右侧是否显示箭头图标,也支持传入 `ReactNode` 来自定义图标 | `boolean \| ReactNode` | 默认和 `clickable` 的值保持一致 | +| arrowIcon | 右侧是否显示箭头图标,也支持传入 `ReactNode` 来自定义图标 | `boolean \| ReactNode` | 默认和 `clickable` 的值保持一致 | | children | 列表项中间的主内容区域 | `ReactNode` | - | | clickable | 是否显示点击效果 | `boolean` | 当 `onClick` 属性存在时,默认为 `true`,否则默认为 `false` | | description | 列表项中间下部的描述区域 | `ReactNode` | - | diff --git a/src/components/list/list-item.tsx b/src/components/list/list-item.tsx index a614bdb4e5..74e7de5285 100644 --- a/src/components/list/list-item.tsx +++ b/src/components/list/list-item.tsx @@ -5,6 +5,7 @@ import React from 'react' import { isNodeWithContent } from '../../utils/is-node-with-content' import { NativeProps, withNativeProps } from '../../utils/native-props' import { useConfig } from '../config-provider' +import { mergeProp } from '../../utils/with-default-props' const classPrefix = `adm-list-item` @@ -27,9 +28,16 @@ export type ListItemProps = { > export const ListItem: FC = props => { + const { arrow, arrowIcon } = props const { list: componentConfig = {} } = useConfig() const clickable = props.clickable ?? !!props.onClick - const arrow = props.arrow ?? props.arrowIcon ?? clickable + + const showArrow = arrow ?? arrowIcon ?? clickable + const mergedArrowIcon = mergeProp( + arrowIcon !== true ? arrowIcon : null, + arrow !== true ? arrowIcon : null, + componentConfig.arrowIcon + ) const content = (
@@ -50,11 +58,9 @@ export const ListItem: FC = props => { {isNodeWithContent(props.extra) && (
{props.extra}
)} - {isNodeWithContent(arrow) && ( + {showArrow && (
- {arrow === true - ? componentConfig?.arrowIcon || - : arrow} + {mergedArrowIcon || }
)}
diff --git a/src/utils/is-node-with-content.ts b/src/utils/is-node-with-content.ts index 62849cc73a..168bd33ea6 100644 --- a/src/utils/is-node-with-content.ts +++ b/src/utils/is-node-with-content.ts @@ -2,6 +2,9 @@ import type { ReactNode } from 'react' type Regulated = T extends null | undefined | false ? never : T +/** + * Check if the `node` is visible Node (not null, undefined, or false) + */ export function isNodeWithContent( node: ReactNode ): node is Regulated { From 48aa12b7e01358a1721b2dd5d4bb0b9e5d1064e8 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?=E4=BA=8C=E8=B4=A7=E6=9C=BA=E5=99=A8=E4=BA=BA?= Date: Wed, 17 Apr 2024 10:56:21 +0800 Subject: [PATCH 6/9] test: add test case --- src/components/list/list-item.tsx | 4 +-- src/components/list/tests/list.test.tsx | 33 ++++++++++++++++++++++++- 2 files changed, 34 insertions(+), 3 deletions(-) diff --git a/src/components/list/list-item.tsx b/src/components/list/list-item.tsx index 74e7de5285..0bbb256808 100644 --- a/src/components/list/list-item.tsx +++ b/src/components/list/list-item.tsx @@ -4,8 +4,8 @@ import type { FC, ReactNode } from 'react' import React from 'react' import { isNodeWithContent } from '../../utils/is-node-with-content' import { NativeProps, withNativeProps } from '../../utils/native-props' -import { useConfig } from '../config-provider' import { mergeProp } from '../../utils/with-default-props' +import { useConfig } from '../config-provider' const classPrefix = `adm-list-item` @@ -35,7 +35,7 @@ export const ListItem: FC = props => { const showArrow = arrow ?? arrowIcon ?? clickable const mergedArrowIcon = mergeProp( arrowIcon !== true ? arrowIcon : null, - arrow !== true ? arrowIcon : null, + arrow !== true ? arrow : null, componentConfig.arrowIcon ) diff --git a/src/components/list/tests/list.test.tsx b/src/components/list/tests/list.test.tsx index 5a0d936ccc..6e98d76bb1 100644 --- a/src/components/list/tests/list.test.tsx +++ b/src/components/list/tests/list.test.tsx @@ -1,5 +1,5 @@ import React, { createRef } from 'react' -import { render, testA11y } from 'testing' +import { render, screen, testA11y } from 'testing' import List from '..' import { ListRef } from '../list' @@ -23,4 +23,35 @@ describe('list', () => { expect(ref.current?.nativeElement).toBeDefined() expect(baseElement).toMatchSnapshot() }) + + describe('arrow', () => { + it('show arrow', () => { + const { baseElement } = render( + + + + ) + expect( + baseElement.querySelector('.adm-list-item-content-arrow') + ).toBeTruthy() + }) + + it('legacy arrow', () => { + render( + + + + ) + expect(screen.getByText('little')).toBeVisible() + }) + + it('arrowIcon', () => { + render( + + + + ) + expect(screen.getByText('bamboo')).toBeVisible() + }) + }) }) From 40f7a3fad1a690b46ef6601fb163edf60c192b07 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?=E4=BA=8C=E8=B4=A7=E6=9C=BA=E5=99=A8=E4=BA=BA?= Date: Wed, 17 Apr 2024 11:07:17 +0800 Subject: [PATCH 7/9] chore: rename --- src/components/center-popup/center-popup.tsx | 93 ++++++++++--------- .../config-provider/config-provider.tsx | 2 +- src/components/list/tests/list.test.tsx | 13 +++ 3 files changed, 62 insertions(+), 46 deletions(-) diff --git a/src/components/center-popup/center-popup.tsx b/src/components/center-popup/center-popup.tsx index 4fcbf848d9..29f26dd9fe 100644 --- a/src/components/center-popup/center-popup.tsx +++ b/src/components/center-popup/center-popup.tsx @@ -1,21 +1,21 @@ -import React, { useRef, useState } from 'react' -import type { FC, PropsWithChildren } from 'react' -import { renderToContainer } from '../../utils/render-to-container' -import Mask from '../mask' -import { withStopPropagation } from '../../utils/with-stop-propagation' -import { mergeProps } from '../../utils/with-default-props' -import { useIsomorphicLayoutEffect, useUnmountedRef } from 'ahooks' import { animated, useSpring } from '@react-spring/web' -import { useInnerVisible } from '../../utils/use-inner-visible' +import { useIsomorphicLayoutEffect, useUnmountedRef } from 'ahooks' import classNames from 'classnames' +import type { FC, PropsWithChildren } from 'react' +import React, { useRef, useState } from 'react' import { NativeProps, withNativeProps } from '../../utils/native-props' +import { renderToContainer } from '../../utils/render-to-container' import { ShouldRender } from '../../utils/should-render' +import { useInnerVisible } from '../../utils/use-inner-visible' import { useLockScroll } from '../../utils/use-lock-scroll' +import { mergeProps } from '../../utils/with-default-props' +import { withStopPropagation } from '../../utils/with-stop-propagation' +import { useConfig } from '../config-provider' +import Mask from '../mask' import { - defaultPopupBaseProps, PopupBaseProps, + defaultPopupBaseProps, } from '../popup/popup-base-props' -import { useConfig } from '../config-provider' const classPrefix = 'adm-center-popup' @@ -37,14 +37,14 @@ const defaultProps = { getContainer: null, } -export const CenterPopup: FC = p => { +export const CenterPopup: FC = props => { const { popup: componentConfig = {} } = useConfig() - const props = mergeProps(defaultProps, componentConfig, p) + const mergedProps = mergeProps(defaultProps, componentConfig, props) const unmountedRef = useUnmountedRef() const style = useSpring({ - scale: props.visible ? 1 : 0.8, - opacity: props.visible ? 1 : 0, + scale: mergedProps.visible ? 1 : 0.8, + opacity: mergedProps.visible ? 1 : 0, config: { mass: 1.2, tension: 200, @@ -53,40 +53,40 @@ export const CenterPopup: FC = p => { }, onRest: () => { if (unmountedRef.current) return - setActive(props.visible) - if (props.visible) { - props.afterShow?.() + setActive(mergedProps.visible) + if (mergedProps.visible) { + mergedProps.afterShow?.() } else { - props.afterClose?.() + mergedProps.afterClose?.() } }, }) - const [active, setActive] = useState(props.visible) + const [active, setActive] = useState(mergedProps.visible) useIsomorphicLayoutEffect(() => { - if (props.visible) { + if (mergedProps.visible) { setActive(true) } - }, [props.visible]) + }, [mergedProps.visible]) const ref = useRef(null) - useLockScroll(ref, props.disableBodyScroll && active) + useLockScroll(ref, mergedProps.disableBodyScroll && active) - const maskVisible = useInnerVisible(active && props.visible) + const maskVisible = useInnerVisible(active && mergedProps.visible) const body = (
- {props.children} + {mergedProps.children}
) const node = withStopPropagation( - props.stopPropagation, + mergedProps.stopPropagation, withNativeProps( - props, + mergedProps,
= p => { pointerEvents: active ? undefined : 'none', }} > - {props.mask && ( + {mergedProps.mask && ( { - props.onMaskClick?.(e) - if (props.closeOnMaskClick) { - props.onClose?.() + mergedProps.onMaskClick?.(e) + if (mergedProps.closeOnMaskClick) { + mergedProps.onClose?.() } }} - style={props.maskStyle} - className={classNames(`${classPrefix}-mask`, props.maskClassName)} + style={mergedProps.maskStyle} + className={classNames( + `${classPrefix}-mask`, + mergedProps.maskClassName + )} disableBodyScroll={false} - stopPropagation={props.stopPropagation} + stopPropagation={mergedProps.stopPropagation} /> )}
= p => { }} ref={ref} > - {props.showCloseButton && ( + {mergedProps.showCloseButton && ( { - props.onClose?.() + mergedProps.onClose?.() }} > - {props.closeIcon} + {mergedProps.closeIcon} )} {body} @@ -148,10 +151,10 @@ export const CenterPopup: FC = p => { return ( - {renderToContainer(props.getContainer, node)} + {renderToContainer(mergedProps.getContainer, node)} ) } diff --git a/src/components/config-provider/config-provider.tsx b/src/components/config-provider/config-provider.tsx index f66c425a73..bb4f4ef1d5 100644 --- a/src/components/config-provider/config-provider.tsx +++ b/src/components/config-provider/config-provider.tsx @@ -3,7 +3,7 @@ import { Locale } from '../../locales/base' import zhCN from '../../locales/zh-CN' type Config = { - locale: Locale + locale?: Locale checkList?: { activeIcon?: ReactNode } diff --git a/src/components/list/tests/list.test.tsx b/src/components/list/tests/list.test.tsx index 6e98d76bb1..c4793195b8 100644 --- a/src/components/list/tests/list.test.tsx +++ b/src/components/list/tests/list.test.tsx @@ -1,6 +1,7 @@ import React, { createRef } from 'react' import { render, screen, testA11y } from 'testing' import List from '..' +import ConfigProvider from '../../config-provider' import { ListRef } from '../list' describe('list', () => { @@ -53,5 +54,17 @@ describe('list', () => { ) expect(screen.getByText('bamboo')).toBeVisible() }) + + it('context', () => { + render( + + + + + + ) + + expect(screen.getByText('little')).toBeVisible() + }) }) }) From b327bfdd8148b787c5938da84136f8741957aa2e Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?=E9=B9=A4=E4=BB=99?= Date: Wed, 17 Apr 2024 18:03:50 +0800 Subject: [PATCH 8/9] refactor: props -> mergedProps, p -> props --- src/components/check-list/check-list.tsx | 26 +++--- .../config-provider/config-provider.tsx | 4 +- src/components/dropdown/dropdown.tsx | 26 +++--- src/components/input/input.tsx | 88 ++++++++++--------- src/components/nav-bar/nav-bar.tsx | 16 ++-- src/components/notice-bar/notice-bar.tsx | 40 +++++---- src/components/toast/toast.tsx | 18 ++-- .../virtual-input/virtual-input.tsx | 46 +++++----- 8 files changed, 136 insertions(+), 128 deletions(-) diff --git a/src/components/check-list/check-list.tsx b/src/components/check-list/check-list.tsx index 6052152125..74b6ec01d9 100644 --- a/src/components/check-list/check-list.tsx +++ b/src/components/check-list/check-list.tsx @@ -1,12 +1,12 @@ -import React from 'react' -import type { FC, ReactNode } from 'react' import { CheckOutline } from 'antd-mobile-icons' +import type { FC, ReactNode } from 'react' +import React from 'react' import { NativeProps, withNativeProps } from '../../utils/native-props' -import List, { ListProps } from '../list' -import { mergeProps } from '../../utils/with-default-props' -import { CheckListContext } from './context' import { usePropsValue } from '../../utils/use-props-value' +import { mergeProps } from '../../utils/with-default-props' import { useConfig } from '../config-provider' +import List, { ListProps } from '../list' +import { CheckListContext } from './context' const classPrefix = 'adm-check-list' @@ -30,14 +30,14 @@ const defaultProps = { activeIcon: , } -export const CheckList: FC = p => { +export const CheckList: FC = props => { const { checkList: componentConfig = {} } = useConfig() - const props = mergeProps(defaultProps, componentConfig, p) + const mergedProps = mergeProps(defaultProps, componentConfig, props) - const [value, setValue] = usePropsValue(props) + const [value, setValue] = usePropsValue(mergedProps) function check(val: CheckListValue) { - if (props.multiple) { + if (mergedProps.multiple) { setValue([...value, val]) } else { setValue([val]) @@ -48,7 +48,7 @@ export const CheckList: FC = p => { setValue(value.filter(item => item !== val)) } - const { activeIcon, extra, disabled, readOnly } = props + const { activeIcon, extra, disabled, readOnly } = mergedProps return ( = p => { }} > {withNativeProps( - props, - - {props.children} + mergedProps, + + {mergedProps.children} )} diff --git a/src/components/config-provider/config-provider.tsx b/src/components/config-provider/config-provider.tsx index bb4f4ef1d5..182f218988 100644 --- a/src/components/config-provider/config-provider.tsx +++ b/src/components/config-provider/config-provider.tsx @@ -3,7 +3,7 @@ import { Locale } from '../../locales/base' import zhCN from '../../locales/zh-CN' type Config = { - locale?: Locale + locale: Locale checkList?: { activeIcon?: ReactNode } @@ -67,7 +67,7 @@ export function getDefaultConfig() { const ConfigContext = React.createContext(null) -export type ConfigProviderProps = Config & { +export type ConfigProviderProps = Partial & { children?: ReactNode } diff --git a/src/components/dropdown/dropdown.tsx b/src/components/dropdown/dropdown.tsx index 3c55ff97d4..40131bb207 100644 --- a/src/components/dropdown/dropdown.tsx +++ b/src/components/dropdown/dropdown.tsx @@ -18,10 +18,10 @@ import React, { import { NativeProps, withNativeProps } from '../../utils/native-props' import { usePropsValue } from '../../utils/use-props-value' import { mergeProp, mergeProps } from '../../utils/with-default-props' +import { useConfig } from '../config-provider' import Popup, { PopupProps } from '../popup' import { defaultPopupBaseProps } from '../popup/popup-base-props' import Item, { ItemChildrenWrap } from './item' -import { useConfig } from '../config-provider' const classPrefix = `adm-dropdown` @@ -51,13 +51,13 @@ export type DropdownRef = { } const Dropdown = forwardRef>( - (p, ref) => { + (props, ref) => { const { dropdown: componentConfig = {} } = useConfig() - const props = mergeProps(defaultProps, componentConfig, p) + const mergedProps = mergeProps(defaultProps, componentConfig, props) const [value, setValue] = usePropsValue({ - value: props.activeKey, - defaultValue: props.defaultActiveKey, - onChange: props.onChange, + value: mergedProps.activeKey, + defaultValue: mergedProps.defaultActiveKey, + onChange: mergedProps.onChange, }) const navRef = useRef(null) @@ -65,7 +65,7 @@ const Dropdown = forwardRef>( // 点击外部区域,关闭 useClickAway(() => { - if (!props.closeOnClickAway) return + if (!mergedProps.closeOnClickAway) return setValue(null) }, [navRef, contentRef]) @@ -91,7 +91,7 @@ const Dropdown = forwardRef>( let popupForceRender = false const items: ReactElement>[] = [] - const navs = React.Children.map(props.children, child => { + const navs = React.Children.map(mergedProps.children, child => { if (isValidElement>(child)) { const childProps = { ...child.props, @@ -103,8 +103,8 @@ const Dropdown = forwardRef>( arrowIcon: mergeProp( child.props.arrowIcon, child.props.arrow, - props.arrowIcon, - props.arrow + mergedProps.arrowIcon, + mergedProps.arrow ), } items.push(child) @@ -126,7 +126,7 @@ const Dropdown = forwardRef>( ) return withNativeProps( - props, + mergedProps,
>( { changeActive(null) } diff --git a/src/components/input/input.tsx b/src/components/input/input.tsx index 31efbce362..2eb7d1f52b 100644 --- a/src/components/input/input.tsx +++ b/src/components/input/input.tsx @@ -81,19 +81,19 @@ export type InputRef = { nativeElement: HTMLInputElement | null } -export const Input = forwardRef((p, ref) => { +export const Input = forwardRef((props, ref) => { const { locale, input: componentConfig = {} } = useConfig() - const props = mergeProps(defaultProps, componentConfig, p) - const [value, setValue] = usePropsValue(props) + const mergedProps = mergeProps(defaultProps, componentConfig, props) + const [value, setValue] = usePropsValue(mergedProps) const [hasFocus, setHasFocus] = useState(false) const compositionStartRef = useRef(false) const nativeInputRef = useRef(null) const handleKeydown = useInputHandleKeyDown({ - onEnterPress: props.onEnterPress, - onKeyDown: props.onKeyDown, + onEnterPress: mergedProps.onEnterPress, + onKeyDown: mergedProps.onKeyDown, nativeInputRef, - enterKeyHint: props.enterKeyHint, + enterKeyHint: mergedProps.enterKeyHint, }) useImperativeHandle(ref, () => ({ @@ -113,10 +113,14 @@ export const Input = forwardRef((p, ref) => { function checkValue() { let nextValue = value - if (props.type === 'number') { + if (mergedProps.type === 'number') { const boundValue = nextValue && - bound(parseFloat(nextValue), props.min, props.max).toString() + bound( + parseFloat(nextValue), + mergedProps.min, + mergedProps.max + ).toString() // fix the display issue of numbers starting with 0 if (Number(nextValue) !== Number(boundValue)) { nextValue = boundValue @@ -128,8 +132,8 @@ export const Input = forwardRef((p, ref) => { } const shouldShowClear = (() => { - if (!props.clearable || !value || props.readOnly) return false - if (props.onlyShowClearWhenFocus) { + if (!mergedProps.clearable || !value || mergedProps.readOnly) return false + if (mergedProps.onlyShowClearWhenFocus) { return hasFocus } else { return true @@ -137,11 +141,11 @@ export const Input = forwardRef((p, ref) => { })() return withNativeProps( - props, + mergedProps,
((p, ref) => { }} onFocus={e => { setHasFocus(true) - props.onFocus?.(e) + mergedProps.onFocus?.(e) }} onBlur={e => { setHasFocus(false) checkValue() - props.onBlur?.(e) + mergedProps.onBlur?.(e) }} - id={props.id} - placeholder={props.placeholder} - disabled={props.disabled} - readOnly={props.readOnly} - maxLength={props.maxLength} - minLength={props.minLength} - max={props.max} - min={props.min} - autoComplete={props.autoComplete} - autoFocus={props.autoFocus} - pattern={props.pattern} - inputMode={props.inputMode} - type={props.type} - name={props.name} - autoCapitalize={props.autoCapitalize} - autoCorrect={props.autoCorrect} + id={mergedProps.id} + placeholder={mergedProps.placeholder} + disabled={mergedProps.disabled} + readOnly={mergedProps.readOnly} + maxLength={mergedProps.maxLength} + minLength={mergedProps.minLength} + max={mergedProps.max} + min={mergedProps.min} + autoComplete={mergedProps.autoComplete} + autoFocus={mergedProps.autoFocus} + pattern={mergedProps.pattern} + inputMode={mergedProps.inputMode} + type={mergedProps.type} + name={mergedProps.name} + autoCapitalize={mergedProps.autoCapitalize} + autoCorrect={mergedProps.autoCorrect} onKeyDown={handleKeydown} - onKeyUp={props.onKeyUp} + onKeyUp={mergedProps.onKeyUp} onCompositionStart={e => { compositionStartRef.current = true - props.onCompositionStart?.(e) + mergedProps.onCompositionStart?.(e) }} onCompositionEnd={e => { compositionStartRef.current = false - props.onCompositionEnd?.(e) + mergedProps.onCompositionEnd?.(e) }} - onClick={props.onClick} - step={props.step} - role={props.role} - aria-valuenow={props['aria-valuenow']} - aria-valuemax={props['aria-valuemax']} - aria-valuemin={props['aria-valuemin']} - aria-label={props['aria-label']} + onClick={mergedProps.onClick} + step={mergedProps.step} + role={mergedProps.role} + aria-valuenow={mergedProps['aria-valuenow']} + aria-valuemax={mergedProps['aria-valuemax']} + aria-valuemin={mergedProps['aria-valuemin']} + aria-label={mergedProps['aria-label']} /> {shouldShowClear && (
((p, ref) => { }} onClick={() => { setValue('') - props.onClear?.() + mergedProps.onClear?.() // https://github.com/ant-design/ant-design-mobile/issues/5212 if (isIOS() && compositionStartRef.current) { @@ -212,7 +216,7 @@ export const Input = forwardRef((p, ref) => { }} aria-label={locale.Input.clear} > - {props.clearIcon} + {mergedProps.clearIcon}
)}
diff --git a/src/components/nav-bar/nav-bar.tsx b/src/components/nav-bar/nav-bar.tsx index 5060b3a0fe..e3c6e24ca6 100644 --- a/src/components/nav-bar/nav-bar.tsx +++ b/src/components/nav-bar/nav-bar.tsx @@ -25,17 +25,17 @@ const defaultProps = { backIcon: true, } -export const NavBar: FC = p => { +export const NavBar: FC = props => { const { navBar: componentConfig = {} } = useConfig() - const props = mergeProps(defaultProps, componentConfig, p) - const { back, backIcon, backArrow } = props + const mergedProps = mergeProps(defaultProps, componentConfig, props) + const { back, backIcon, backArrow } = mergedProps return withNativeProps( - props, + mergedProps,
{back !== null && ( -
+
{(backIcon || backArrow) && ( {backIcon === true || backArrow === true ? ( @@ -48,10 +48,10 @@ export const NavBar: FC = p => {
)} - {props.left} + {mergedProps.left}
-
{props.children}
-
{props.right}
+
{mergedProps.children}
+
{mergedProps.right}
) } diff --git a/src/components/notice-bar/notice-bar.tsx b/src/components/notice-bar/notice-bar.tsx index cbc6480876..76e7fbfb1e 100644 --- a/src/components/notice-bar/notice-bar.tsx +++ b/src/components/notice-bar/notice-bar.tsx @@ -52,22 +52,22 @@ const defaultProps = { wrap: false, } -export const NoticeBar = memo(p => { +export const NoticeBar = memo(props => { const { noticeBar: componentConfig = {} } = useConfig() - const props = mergeProps(defaultProps, componentConfig, p) + const mergedProps = mergeProps(defaultProps, componentConfig, props) const containerRef = useRef(null) const textRef = useRef(null) const [visible, setVisible] = useState(true) - const speed = props.speed + const speed = mergedProps.speed const delayLockRef = useRef(true) const animatingRef = useRef(false) function start() { - if (delayLockRef.current || props.wrap) return + if (delayLockRef.current || mergedProps.wrap) return const container = containerRef.current const text = textRef.current @@ -100,7 +100,7 @@ export const NoticeBar = memo(p => { useTimeout(() => { delayLockRef.current = false start() - }, props.delay) + }, mergedProps.delay) useResizeEffect(() => { start() @@ -121,15 +121,19 @@ export const NoticeBar = memo(p => { if (!visible) return null return withNativeProps( - props, + mergedProps,
- {props.icon && ( - {props.icon} + {mergedProps.icon && ( + {mergedProps.icon} )} (p => { ref={textRef} className={`${classPrefix}-content-inner`} > - {props.content} + {mergedProps.content} - {(props.closeable || props.extra) && ( + {(mergedProps.closeable || mergedProps.extra) && ( - {props.extra} - {props.closeable && ( + {mergedProps.extra} + {mergedProps.closeable && (
{ setVisible(false) - props.onClose?.() + mergedProps.onClose?.() }} > - {props.closeIcon} + {mergedProps.closeIcon}
)}
diff --git a/src/components/toast/toast.tsx b/src/components/toast/toast.tsx index fc045c1d76..13e357f7ae 100644 --- a/src/components/toast/toast.tsx +++ b/src/components/toast/toast.tsx @@ -32,10 +32,10 @@ const defaultProps = { stopPropagation: ['click'], } -export const InternalToast: FC = p => { +export const InternalToast: FC = props => { const { toast: componentConfig = {} } = useConfig() - const props = mergeProps(defaultProps, componentConfig, p) - const { maskClickable, content, icon, position } = props + const mergedProps = mergeProps(defaultProps, componentConfig, props) + const { maskClickable, content, icon, position } = mergedProps const iconElement = useMemo(() => { if (icon === null || icon === undefined) return null @@ -68,18 +68,18 @@ export const InternalToast: FC = p => { return (
( - (p, ref) => { + (props, ref) => { const { locale, input: componentConfig = {} } = useConfig() - const props = mergeProps(defaultProps, componentConfig, p) - const [value, setValue] = usePropsValue(props) + const mergedProps = mergeProps(defaultProps, componentConfig, props) + const [value, setValue] = usePropsValue(mergedProps) const rootRef = useRef(null) const contentRef = useRef(null) const [hasFocus, setHasFocus] = useState(false) @@ -89,15 +89,15 @@ export const VirtualInput = forwardRef( function onFocus() { setHasFocus(true) - props.onFocus?.() + mergedProps.onFocus?.() } function onBlur() { setHasFocus(false) - props.onBlur?.() + mergedProps.onBlur?.() } - const keyboard = props.keyboard + const keyboard = mergedProps.keyboard const keyboardElement = keyboard && React.cloneElement(keyboard, { @@ -127,46 +127,46 @@ export const VirtualInput = forwardRef( } as NumberKeyboardProps) return withNativeProps( - props, + mergedProps,
{value}
{hasFocus &&
}
- {props.clearable && !!value && hasFocus && ( + {mergedProps.clearable && !!value && hasFocus && (
{ e.stopPropagation() setValue('') - props.onClear?.() + mergedProps.onClear?.() }} role='button' aria-label={locale.Input.clear} > - {props.clearIcon} + {mergedProps.clearIcon}
)} {[undefined, null, ''].includes(value) && (
- {props.placeholder} + {mergedProps.placeholder}
)} {keyboardElement} From cc357d1e25149abe10faca46f14797ad3be89f48 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?=E9=B9=A4=E4=BB=99?= Date: Wed, 17 Apr 2024 18:04:38 +0800 Subject: [PATCH 9/9] refactor: props -> mergedProps, p -> props --- src/components/action-sheet/action-sheet.tsx | 56 ++++----- src/components/avatar/avatar.tsx | 28 ++--- src/components/button/button.tsx | 57 ++++----- .../calendar-picker-view.tsx | 79 ++++++------ .../calendar-picker/calendar-picker.tsx | 26 ++-- src/components/calendar/calendar.tsx | 101 +++++++++------- .../cascader-view/cascader-view.tsx | 50 ++++---- src/components/checkbox/checkbox.tsx | 56 +++++---- src/components/checkbox/group.tsx | 16 +-- .../date-picker-view/date-picker-view.tsx | 60 +++++----- src/components/date-picker/date-picker.tsx | 112 ++++++++++-------- src/components/dialog/alert.tsx | 18 +-- src/components/dialog/dialog.tsx | 82 +++++++------ src/components/divider/divider.tsx | 18 +-- src/components/dot-loading/dot-loading.tsx | 12 +- src/components/ellipsis/ellipsis.tsx | 68 +++++------ .../error-block/create-error-block.tsx | 31 ++--- .../floating-bubble/floating-bubble.tsx | 40 ++++--- .../floating-panel/floating-panel.tsx | 28 +++-- src/components/footer/footer.tsx | 12 +- src/components/form/form.tsx | 28 ++--- src/components/grid/grid.tsx | 16 +-- .../image-uploader/image-uploader.tsx | 78 ++++++------ src/components/image-viewer/image-viewer.tsx | 66 +++++------ src/components/image/image.tsx | 72 +++++------ src/components/index-bar/index-bar.tsx | 28 ++--- .../infinite-scroll/infinite-scroll.tsx | 26 ++-- src/components/list/list.tsx | 20 ++-- src/components/mask/mask.tsx | 62 +++++----- src/components/modal/alert.tsx | 18 +-- src/components/modal/modal.tsx | 84 +++++++------ .../number-keyboard/number-keyboard.tsx | 44 +++---- .../page-indicator/page-indicator.tsx | 18 +-- .../passcode-input/passcode-input.tsx | 54 ++++----- src/components/picker-view/picker-view.tsx | 50 ++++---- src/components/popover/popover.tsx | 90 +++++++------- src/components/popup/popup.tsx | 106 ++++++++--------- src/components/progress-bar/progress-bar.tsx | 28 +++-- .../progress-circle/progress-circle.tsx | 12 +- .../pull-to-refresh/pull-to-refresh.tsx | 44 +++---- src/components/radio/group.tsx | 20 ++-- src/components/radio/radio.tsx | 36 +++--- src/components/rate/rate.tsx | 40 +++---- src/components/result-page/result-page.tsx | 16 +-- src/components/result/result.tsx | 12 +- src/components/selector/selector.tsx | 50 ++++---- src/components/skeleton/skeleton.tsx | 16 +-- src/components/slider/slider.tsx | 55 ++++----- src/components/space/space.tsx | 23 ++-- src/components/spin-loading/spin-loading.tsx | 12 +- src/components/stepper/stepper.tsx | 32 ++--- src/components/steps/steps.tsx | 18 +-- src/components/swipe-action/swipe-action.tsx | 40 +++---- src/components/swiper/swiper.tsx | 67 ++++++----- src/components/switch/switch.tsx | 30 ++--- src/components/tab-bar/tab-bar.tsx | 24 ++-- src/components/tabs/tabs.tsx | 48 ++++---- src/components/tag/tag.tsx | 25 ++-- src/components/text-area/text-area.tsx | 54 ++++----- src/components/tree-select/multiple.tsx | 48 ++++---- src/components/tree-select/tree-select.tsx | 32 ++--- src/components/water-mark/water-mark.tsx | 12 +- 62 files changed, 1341 insertions(+), 1263 deletions(-) diff --git a/src/components/action-sheet/action-sheet.tsx b/src/components/action-sheet/action-sheet.tsx index 7c38ee6c2f..3df23ce91d 100644 --- a/src/components/action-sheet/action-sheet.tsx +++ b/src/components/action-sheet/action-sheet.tsx @@ -1,11 +1,11 @@ +import classNames from 'classnames' +import type { CSSProperties, FC, ReactNode } from 'react' import React from 'react' -import type { FC, ReactNode, CSSProperties } from 'react' import { NativeProps, withNativeProps } from '../../utils/native-props' +import { renderImperatively } from '../../utils/render-imperatively' import { mergeProps } from '../../utils/with-default-props' -import classNames from 'classnames' import Popup, { PopupProps } from '../popup' import SafeArea from '../safe-area' -import { renderImperatively } from '../../utils/render-imperatively' const classPrefix = `adm-action-sheet` @@ -51,36 +51,36 @@ const defaultProps = { forceRender: false, } -export const ActionSheet: FC = p => { - const props = mergeProps(defaultProps, p) - const { styles } = props +export const ActionSheet: FC = props => { + const mergedProps = mergeProps(defaultProps, props) + const { styles } = mergedProps return ( { - props.onMaskClick?.() - if (props.closeOnMaskClick) { - props.onClose?.() + mergedProps.onMaskClick?.() + if (mergedProps.closeOnMaskClick) { + mergedProps.onClose?.() } }} - afterClose={props.afterClose} - className={classNames(`${classPrefix}-popup`, props.popupClassName)} - style={props.popupStyle} - getContainer={props.getContainer} - destroyOnClose={props.destroyOnClose} - forceRender={props.forceRender} + afterClose={mergedProps.afterClose} + className={classNames(`${classPrefix}-popup`, mergedProps.popupClassName)} + style={mergedProps.popupStyle} + getContainer={mergedProps.getContainer} + destroyOnClose={mergedProps.destroyOnClose} + forceRender={mergedProps.forceRender} bodyStyle={styles?.body} maskStyle={styles?.mask} > {withNativeProps( - props, + mergedProps,
- {props.extra && ( -
{props.extra}
+ {mergedProps.extra && ( +
{mergedProps.extra}
)}
- {props.actions.map((action, index) => ( + {mergedProps.actions.map((action, index) => (
= p => { )} onClick={() => { action.onClick?.() - props.onAction?.(action, index) - if (props.closeOnAction) { - props.onClose?.() + mergedProps.onAction?.(action, index) + if (mergedProps.closeOnAction) { + mergedProps.onClose?.() } }} role='option' @@ -118,11 +118,11 @@ export const ActionSheet: FC = p => { ))}
- {props.cancelText && ( + {mergedProps.cancelText && ( )} - {props.safeArea && } + {mergedProps.safeArea && }
)} diff --git a/src/components/avatar/avatar.tsx b/src/components/avatar/avatar.tsx index f8afa3814b..eb2f054717 100644 --- a/src/components/avatar/avatar.tsx +++ b/src/components/avatar/avatar.tsx @@ -1,9 +1,9 @@ -import React from 'react' import type { FC, ReactNode } from 'react' +import React from 'react' import { NativeProps, withNativeProps } from '../../utils/native-props' import { mergeProps } from '../../utils/with-default-props' -import { Fallback } from './fallback' import Image, { ImageProps } from '../image' +import { Fallback } from './fallback' const classPrefix = 'adm-avatar' @@ -19,21 +19,21 @@ const defaultProps = { fit: 'cover', } -export const Avatar: FC = p => { - const props = mergeProps(defaultProps, p) +export const Avatar: FC = props => { + const mergedProps = mergeProps(defaultProps, props) return withNativeProps( - props, + mergedProps, {props.alt} ) } diff --git a/src/components/button/button.tsx b/src/components/button/button.tsx index 04dfb5555c..a7ea2a35df 100644 --- a/src/components/button/button.tsx +++ b/src/components/button/button.tsx @@ -1,15 +1,15 @@ -import React, { forwardRef, useImperativeHandle, useRef, useState } from 'react' +import classNames from 'classnames' import type { - ReactNode, ButtonHTMLAttributes, DetailedHTMLProps, MouseEventHandler, + ReactNode, } from 'react' -import classNames from 'classnames' -import DotLoading from '../dot-loading' -import { mergeProps } from '../../utils/with-default-props' +import React, { forwardRef, useImperativeHandle, useRef, useState } from 'react' import { NativeProps, withNativeProps } from '../../utils/native-props' import { isPromise } from '../../utils/validate' +import { mergeProps } from '../../utils/with-default-props' +import DotLoading from '../dot-loading' const classPrefix = `adm-button` @@ -61,12 +61,13 @@ const defaultProps: ButtonProps = { size: 'middle', } -export const Button = forwardRef((p, ref) => { - const props = mergeProps(defaultProps, p) +export const Button = forwardRef((props, ref) => { + const mergedProps = mergeProps(defaultProps, props) const [innerLoading, setInnerLoading] = useState(false) const nativeButtonRef = useRef(null) - const loading = props.loading === 'auto' ? innerLoading : props.loading - const disabled = props.disabled || loading + const loading = + mergedProps.loading === 'auto' ? innerLoading : mergedProps.loading + const disabled = mergedProps.disabled || loading useImperativeHandle(ref, () => ({ get nativeElement() { @@ -75,9 +76,9 @@ export const Button = forwardRef((p, ref) => { })) const handleClick: MouseEventHandler = async e => { - if (!props.onClick) return + if (!mergedProps.onClick) return - const promise = props.onClick(e) + const promise = mergedProps.onClick(e) if (isPromise(promise)) { try { @@ -92,39 +93,39 @@ export const Button = forwardRef((p, ref) => { } return withNativeProps( - props, + mergedProps, ) diff --git a/src/components/calendar-picker-view/calendar-picker-view.tsx b/src/components/calendar-picker-view/calendar-picker-view.tsx index 65643da8db..e6ba2ac7ad 100644 --- a/src/components/calendar-picker-view/calendar-picker-view.tsx +++ b/src/components/calendar-picker-view/calendar-picker-view.tsx @@ -1,23 +1,23 @@ +import classNames from 'classnames' +import dayjs from 'dayjs' +import isSameOrBefore from 'dayjs/plugin/isSameOrBefore' +import isoWeek from 'dayjs/plugin/isoWeek' +import type { ReactNode } from 'react' import React, { forwardRef, - useState, useImperativeHandle, useMemo, + useState, } from 'react' -import type { ReactNode } from 'react' import { NativeProps, withNativeProps } from '../../utils/native-props' -import dayjs from 'dayjs' -import classNames from 'classnames' +import { usePropsValue } from '../../utils/use-props-value' import { mergeProps } from '../../utils/with-default-props' import { useConfig } from '../config-provider' -import isoWeek from 'dayjs/plugin/isoWeek' -import isSameOrBefore from 'dayjs/plugin/isSameOrBefore' -import { usePropsValue } from '../../utils/use-props-value' import { - convertValueToRange, - convertPageToDayjs, DateRange, Page, + convertPageToDayjs, + convertValueToRange, } from './convert' dayjs.extend(isoWeek) @@ -75,27 +75,30 @@ const defaultProps = { export const CalendarPickerView = forwardRef< CalendarPickerViewRef, CalendarPickerViewProps ->((p, ref) => { +>((props, ref) => { const today = dayjs() - const props = mergeProps(defaultProps, p) + const mergedProps = mergeProps(defaultProps, props) const { locale } = useConfig() const markItems = [...locale.Calendar.markItems] - if (props.weekStartsOn === 'Sunday') { + if (mergedProps.weekStartsOn === 'Sunday') { const item = markItems.pop() if (item) markItems.unshift(item) } const [dateRange, setDateRange] = usePropsValue({ value: - props.value === undefined + mergedProps.value === undefined ? undefined - : convertValueToRange(props.selectionMode, props.value), - defaultValue: convertValueToRange(props.selectionMode, props.defaultValue), + : convertValueToRange(mergedProps.selectionMode, mergedProps.value), + defaultValue: convertValueToRange( + mergedProps.selectionMode, + mergedProps.defaultValue + ), onChange: v => { - if (props.selectionMode === 'single') { - props.onChange?.(v ? v[0] : null) - } else if (props.selectionMode === 'range') { - props.onChange?.(v) + if (mergedProps.selectionMode === 'single') { + mergedProps.onChange?.(v ? v[0] : null) + } else if (mergedProps.selectionMode === 'range') { + mergedProps.onChange?.(v) } }, }) @@ -128,18 +131,18 @@ export const CalendarPickerView = forwardRef< const header = (
- {props.title ?? locale.Calendar.title} + {mergedProps.title ?? locale.Calendar.title}
) const maxDay = useMemo( - () => (props.max ? dayjs(props.max) : current.add(6, 'month')), - [props.max, current] + () => (mergedProps.max ? dayjs(mergedProps.max) : current.add(6, 'month')), + [mergedProps.max, current] ) const minDay = useMemo( - () => (props.min ? dayjs(props.min) : current), - [props.min, current] + () => (mergedProps.min ? dayjs(mergedProps.min) : current), + [mergedProps.min, current] ) function renderBody() { @@ -167,7 +170,7 @@ export const CalendarPickerView = forwardRef<
{/* 空格填充 */} {Array( - props.weekStartsOn === 'Monday' + mergedProps.weekStartsOn === 'Monday' ? monthIterator.date(1).isoWeekday() - 1 : monthIterator.date(1).isoWeekday() ) @@ -204,19 +207,19 @@ export const CalendarPickerView = forwardRef< !isEnd } } - const disabled = props.shouldDisableDate - ? props.shouldDisableDate(d.toDate()) + const disabled = mergedProps.shouldDisableDate + ? mergedProps.shouldDisableDate(d.toDate()) : (maxDay && d.isAfter(maxDay, 'day')) || (minDay && d.isBefore(minDay, 'day')) const renderTop = () => { - const top = props.renderTop?.(d.toDate()) + const top = mergedProps.renderTop?.(d.toDate()) if (top) { return top } - if (props.selectionMode === 'range') { + if (mergedProps.selectionMode === 'range') { if (isBegin) { return locale.Calendar.start } @@ -244,22 +247,22 @@ export const CalendarPickerView = forwardRef< [`${classPrefix}-cell-disabled`]: !!disabled, })} onClick={() => { - if (!props.selectionMode) return + if (!mergedProps.selectionMode) return if (disabled) return const date = d.toDate() function shouldClear() { - if (!props.allowClear) return false + if (!mergedProps.allowClear) return false if (!dateRange) return false const [begin, end] = dateRange return d.isSame(begin, 'date') && d.isSame(end, 'day') } - if (props.selectionMode === 'single') { - if (props.allowClear && shouldClear()) { + if (mergedProps.selectionMode === 'single') { + if (mergedProps.allowClear && shouldClear()) { setDateRange(null) return } setDateRange([date, date]) - } else if (props.selectionMode === 'range') { + } else if (mergedProps.selectionMode === 'range') { if (!dateRange) { setDateRange([date, date]) setIntermediate(true) @@ -287,12 +290,12 @@ export const CalendarPickerView = forwardRef< {renderTop()}
- {props.renderDate - ? props.renderDate(d.toDate()) + {mergedProps.renderDate + ? mergedProps.renderDate(d.toDate()) : d.date()}
- {props.renderBottom?.(d.toDate())} + {mergedProps.renderBottom?.(d.toDate())}
) @@ -319,7 +322,7 @@ export const CalendarPickerView = forwardRef< ) return withNativeProps( - props, + mergedProps,
{header} {mark} diff --git a/src/components/calendar-picker/calendar-picker.tsx b/src/components/calendar-picker/calendar-picker.tsx index 314ed1e24e..4fc28188f3 100644 --- a/src/components/calendar-picker/calendar-picker.tsx +++ b/src/components/calendar-picker/calendar-picker.tsx @@ -1,16 +1,16 @@ +import classNames from 'classnames' import React, { forwardRef, useRef } from 'react' import { withNativeProps } from '../../utils/native-props' -import classNames from 'classnames' -import Button from '../button' -import Divider from '../divider' -import Popup from '../popup' import { type GetContainer } from '../../utils/render-to-container' import { mergeProps } from '../../utils/with-default-props' -import { useConfig } from '../config-provider' +import Button from '../button' import CalendarPickerView, { CalendarPickerViewProps, CalendarPickerViewRef, } from '../calendar-picker-view' +import { useConfig } from '../config-provider' +import Divider from '../divider' +import Popup from '../popup' const classPrefix = 'adm-calendar-picker' @@ -53,8 +53,8 @@ const defaultProps = { export const CalendarPicker = forwardRef< CalendarPickerRef, CalendarPickerProps ->((p, ref) => { - const props = mergeProps(defaultProps, p) +>((props, ref) => { + const mergedProps = mergeProps(defaultProps, props) const { locale } = useConfig() const calendarRef = (ref ?? useRef(null)) as React.RefObject @@ -72,7 +72,7 @@ export const CalendarPicker = forwardRef< onMaskClick, getContainer, ...calendarViewProps - } = props + } = mergedProps const footer = (
@@ -83,10 +83,10 @@ export const CalendarPicker = forwardRef< onClick={() => { const dateRange = calendarRef.current?.getDateRange() ?? null - if (props.selectionMode === 'single') { - props.onConfirm?.(dateRange ? dateRange[0] : null) - } else if (props.selectionMode === 'range') { - props.onConfirm?.(dateRange) + if (mergedProps.selectionMode === 'single') { + mergedProps.onConfirm?.(dateRange ? dateRange[0] : null) + } else if (mergedProps.selectionMode === 'range') { + mergedProps.onConfirm?.(dateRange) } onClose?.() }} @@ -98,7 +98,7 @@ export const CalendarPicker = forwardRef< ) return withNativeProps( - props, + mergedProps,
, } -export const Calendar = forwardRef((p, ref) => { +export const Calendar = forwardRef((props, ref) => { const today = dayjs() - const props = mergeProps(defaultProps, p) + const mergedProps = mergeProps(defaultProps, props) const { locale } = useConfig() const markItems = [...locale.Calendar.markItems] - if (props.weekStartsOn === 'Sunday') { + if (mergedProps.weekStartsOn === 'Sunday') { const item = markItems.pop() if (item) markItems.unshift(item) } const [dateRange, setDateRange] = usePropsValue({ value: - props.value === undefined + mergedProps.value === undefined ? undefined - : convertValueToRange(props.selectionMode, props.value), - defaultValue: convertValueToRange(props.selectionMode, props.defaultValue), + : convertValueToRange(mergedProps.selectionMode, mergedProps.value), + defaultValue: convertValueToRange( + mergedProps.selectionMode, + mergedProps.defaultValue + ), onChange: v => { - if (props.selectionMode === 'single') { - props.onChange?.(v ? v[0] : null) - } else if (props.selectionMode === 'range') { - props.onChange?.(v) + if (mergedProps.selectionMode === 'single') { + mergedProps.onChange?.(v ? v[0] : null) + } else if (mergedProps.selectionMode === 'range') { + mergedProps.onChange?.(v) } }, }) @@ -113,7 +116,7 @@ export const Calendar = forwardRef((p, ref) => { ) useUpdateEffect(() => { - props.onPageChange?.(current.year(), current.month() + 1) + mergedProps.onPageChange?.(current.year(), current.month() + 1) }, [current]) useImperativeHandle(ref, () => ({ @@ -140,14 +143,14 @@ export const Calendar = forwardRef((p, ref) => { type: 'month' | 'year' ) => { const nxtCurrent = current[action](num, type) - if (action === 'subtract' && props.minPage) { - const minPage = convertPageToDayjs(props.minPage) + if (action === 'subtract' && mergedProps.minPage) { + const minPage = convertPageToDayjs(mergedProps.minPage) if (nxtCurrent.isBefore(minPage, type)) { return } } - if (action === 'add' && props.maxPage) { - const maxPage = convertPageToDayjs(props.maxPage) + if (action === 'add' && mergedProps.maxPage) { + const maxPage = convertPageToDayjs(mergedProps.maxPage) if (nxtCurrent.isAfter(maxPage, type)) { return } @@ -163,7 +166,7 @@ export const Calendar = forwardRef((p, ref) => { handlePageChange('subtract', 1, 'year') }} > - {props.prevYearButton} + {mergedProps.prevYearButton} ((p, ref) => { handlePageChange('subtract', 1, 'month') }} > - {props.prevMonthButton} + {mergedProps.prevMonthButton}
{replaceMessage(locale.Calendar.yearAndMonth, { @@ -189,7 +192,7 @@ export const Calendar = forwardRef((p, ref) => { handlePageChange('add', 1, 'month') }} > - {props.nextMonthButton} + {mergedProps.nextMonthButton} ((p, ref) => { handlePageChange('add', 1, 'year') }} > - {props.nextYearButton} + {mergedProps.nextYearButton}
) - const maxDay = useMemo(() => props.max && dayjs(props.max), [props.max]) - const minDay = useMemo(() => props.min && dayjs(props.min), [props.min]) + const maxDay = useMemo( + () => mergedProps.max && dayjs(mergedProps.max), + [mergedProps.max] + ) + const minDay = useMemo( + () => mergedProps.min && dayjs(mergedProps.min), + [mergedProps.min] + ) function renderCells() { const cells: ReactNode[] = [] let iterator = current.subtract(current.isoWeekday(), 'day') - if (props.weekStartsOn === 'Monday') { + if (mergedProps.weekStartsOn === 'Monday') { iterator = iterator.add(1, 'day') } while (cells.length < 6 * 7) { @@ -240,8 +249,8 @@ export const Calendar = forwardRef((p, ref) => { } } const inThisMonth = d.month() === current.month() - const disabled = props.shouldDisableDate - ? props.shouldDisableDate(d.toDate()) + const disabled = mergedProps.shouldDisableDate + ? mergedProps.shouldDisableDate(d.toDate()) : (maxDay && d.isAfter(maxDay, 'day')) || (minDay && d.isBefore(minDay, 'day')) cells.push( @@ -260,25 +269,25 @@ export const Calendar = forwardRef((p, ref) => { } )} onClick={() => { - if (!props.selectionMode) return + if (!mergedProps.selectionMode) return if (disabled) return const date = d.toDate() if (!inThisMonth) { setCurrent(d.clone().date(1)) } function shouldClear() { - if (!props.allowClear) return false + if (!mergedProps.allowClear) return false if (!dateRange) return false const [begin, end] = dateRange return d.isSame(begin, 'date') && d.isSame(end, 'day') } - if (props.selectionMode === 'single') { - if (props.allowClear && shouldClear()) { + if (mergedProps.selectionMode === 'single') { + if (mergedProps.allowClear && shouldClear()) { setDateRange(null) return } setDateRange([date, date]) - } else if (props.selectionMode === 'range') { + } else if (mergedProps.selectionMode === 'range') { if (!dateRange) { setDateRange([date, date]) setIntermediate(true) @@ -301,10 +310,12 @@ export const Calendar = forwardRef((p, ref) => { }} >
- {props.renderDate ? props.renderDate(d.toDate()) : d.date()} + {mergedProps.renderDate + ? mergedProps.renderDate(d.toDate()) + : d.date()}
- {props.renderLabel?.(d.toDate())} + {mergedProps.renderLabel?.(d.toDate())}
) @@ -335,7 +346,7 @@ export const Calendar = forwardRef((p, ref) => { } return withNativeProps( - props, + mergedProps,
{header} {mark} diff --git a/src/components/cascader-view/cascader-view.tsx b/src/components/cascader-view/cascader-view.tsx index 206f782ecc..7bd4a90dc5 100644 --- a/src/components/cascader-view/cascader-view.tsx +++ b/src/components/cascader-view/cascader-view.tsx @@ -1,18 +1,18 @@ -import React, { useState, useEffect, useMemo } from 'react' -import type { FC, ReactNode } from 'react' +import { useUpdateEffect } from 'ahooks' import classNames from 'classnames' -import Tabs from '../tabs' -import CheckList, { CheckListValue } from '../check-list' +import type { FC, ReactNode } from 'react' +import React, { useEffect, useMemo, useState } from 'react' +import type { BaseOptionType, FieldNamesType } from '../../hooks' +import { useFieldNames } from '../../hooks' import { NativeProps, withNativeProps } from '../../utils/native-props' -import { mergeProps } from '../../utils/with-default-props' import { usePropsValue } from '../../utils/use-props-value' -import { useCascaderValueExtend } from './use-cascader-value-extend' +import { mergeProps } from '../../utils/with-default-props' +import CheckList, { CheckListValue } from '../check-list' import { useConfig } from '../config-provider' -import { optionSkeleton } from './option-skeleton' import Skeleton from '../skeleton' -import { useUpdateEffect } from 'ahooks' -import { useFieldNames } from '../../hooks' -import type { FieldNamesType, BaseOptionType } from '../../hooks' +import Tabs from '../tabs' +import { optionSkeleton } from './option-skeleton' +import { useCascaderValueExtend } from './use-cascader-value-extend' const classPrefix = `adm-cascader-view` @@ -46,22 +46,22 @@ const defaultProps = { defaultValue: [], } -export const CascaderView: FC = p => { - const props = mergeProps(defaultProps, p) +export const CascaderView: FC = props => { + const mergedProps = mergeProps(defaultProps, props) const { locale } = useConfig() const [labelName, valueName, childrenName, disabledName] = useFieldNames( - props.fieldNames + mergedProps.fieldNames ) - const generateValueExtend = useCascaderValueExtend(props.options, { + const generateValueExtend = useCascaderValueExtend(mergedProps.options, { valueName, childrenName, }) const [value, setValue] = usePropsValue({ - ...props, + ...mergedProps, onChange: val => { - props.onChange?.(val, generateValueExtend(val)) + mergedProps.onChange?.(val, generateValueExtend(val)) }, }) const [tabActiveIndex, setTabActiveIndex] = useState(0) @@ -72,7 +72,7 @@ export const CascaderView: FC = p => { options: CascaderOption[] }[] = [] - let currentOptions = props.options + let currentOptions = mergedProps.options let reachedEnd = false for (const v of value) { const target = currentOptions.find(option => option[valueName] === v) @@ -93,10 +93,10 @@ export const CascaderView: FC = p => { }) } return ret - }, [value, props.options]) + }, [value, mergedProps.options]) useUpdateEffect(() => { - props.onTabsChange?.(tabActiveIndex) + mergedProps.onTabsChange?.(tabActiveIndex) }, [tabActiveIndex]) useEffect(() => { setTabActiveIndex(levels.length - 1) @@ -117,12 +117,12 @@ export const CascaderView: FC = p => { } const whetherLoading = (options: T) => - props.loading || options === optionSkeleton + mergedProps.loading || options === optionSkeleton - const placeholder = props.placeholder || locale.Cascader.placeholder + const placeholder = mergedProps.placeholder || locale.Cascader.placeholder return withNativeProps( - props, + mergedProps,
= p => { {selected ? selected[labelName] : typeof placeholder === 'function' - ? placeholder(index) - : placeholder} + ? placeholder(index) + : placeholder}
} forceRender @@ -175,7 +175,7 @@ export const CascaderView: FC = p => { onChange={selectValue => onItemSelect(selectValue[0], index) } - activeIcon={props.activeIcon} + activeIcon={mergedProps.activeIcon} > {level.options.map(option => { const active = value[index] === option[valueName] diff --git a/src/components/checkbox/checkbox.tsx b/src/components/checkbox/checkbox.tsx index e630ecf9ec..30ff7d639c 100644 --- a/src/components/checkbox/checkbox.tsx +++ b/src/components/checkbox/checkbox.tsx @@ -1,14 +1,14 @@ -import React, { forwardRef, useContext, useImperativeHandle } from 'react' +import classNames from 'classnames' import type { ReactNode } from 'react' +import React, { forwardRef, useContext, useImperativeHandle } from 'react' +import { devWarning } from '../../utils/dev-log' +import { isDev } from '../../utils/is-dev' import { NativeProps, withNativeProps } from '../../utils/native-props' -import classNames from 'classnames' -import { CheckboxGroupContext } from './group-context' import { usePropsValue } from '../../utils/use-props-value' import { mergeProps } from '../../utils/with-default-props' -import { devWarning } from '../../utils/dev-log' import { CheckIcon } from './check-icon' +import { CheckboxGroupContext } from './group-context' import { IndeterminateIcon } from './indeterminate-icon' -import { isDev } from '../../utils/is-dev' import { NativeInput } from './native-input' const classPrefix = `adm-checkbox` @@ -40,28 +40,28 @@ export type CheckboxRef = { toggle: () => void } -export const Checkbox = forwardRef((p, ref) => { +export const Checkbox = forwardRef((props, ref) => { const groupContext = useContext(CheckboxGroupContext) - const props = mergeProps(defaultProps, p) + const mergedProps = mergeProps(defaultProps, props) let [checked, setChecked] = usePropsValue({ - value: props.checked, - defaultValue: props.defaultChecked, - onChange: props.onChange, + value: mergedProps.checked, + defaultValue: mergedProps.defaultChecked, + onChange: mergedProps.onChange, }) as [boolean, (v: boolean) => void] - let disabled = props.disabled + let disabled = mergedProps.disabled - const { value } = props + const { value } = mergedProps if (groupContext && value !== undefined) { if (isDev) { - if (p.checked !== undefined) { + if (props.checked !== undefined) { devWarning( 'Checkbox', 'When used within `Checkbox.Group`, the `checked` prop of `Checkbox` will not work.' ) } - if (p.defaultChecked !== undefined) { + if (props.defaultChecked !== undefined) { devWarning( 'Checkbox', 'When used within `Checkbox.Group`, the `defaultChecked` prop of `Checkbox` will not work.' @@ -76,7 +76,7 @@ export const Checkbox = forwardRef((p, ref) => { } else { groupContext.uncheck(value) } - props.onChange?.(checked) + mergedProps.onChange?.(checked) } disabled = disabled || groupContext.disabled } @@ -94,30 +94,34 @@ export const Checkbox = forwardRef((p, ref) => { })) const renderIcon = () => { - if (props.icon) { + if (mergedProps.icon) { return (
- {props.icon(checked, props.indeterminate)} + {mergedProps.icon(checked, mergedProps.indeterminate)}
) } return (
- {props.indeterminate ? : checked && } + {mergedProps.indeterminate ? ( + + ) : ( + checked && + )}
) } return withNativeProps( - props, + mergedProps, ) diff --git a/src/components/checkbox/group.tsx b/src/components/checkbox/group.tsx index dfc0fe1167..2d53297f88 100644 --- a/src/components/checkbox/group.tsx +++ b/src/components/checkbox/group.tsx @@ -1,9 +1,9 @@ -import React from 'react' import type { FC, ReactNode } from 'react' -import { mergeProps } from '../../utils/with-default-props' +import React from 'react' import { CheckboxValue } from '.' -import { CheckboxGroupContext } from './group-context' import { usePropsValue } from '../../utils/use-props-value' +import { mergeProps } from '../../utils/with-default-props' +import { CheckboxGroupContext } from './group-context' export interface CheckboxGroupProps { value?: CheckboxValue[] @@ -18,16 +18,16 @@ const defaultProps = { defaultValue: [], } -export const Group: FC = p => { - const props = mergeProps(defaultProps, p) - const [value, setValue] = usePropsValue(props) +export const Group: FC = props => { + const mergedProps = mergeProps(defaultProps, props) + const [value, setValue] = usePropsValue(mergedProps) return ( { setValue([...value, v]) }, @@ -36,7 +36,7 @@ export const Group: FC = p => { }, }} > - {props.children} + {mergedProps.children} ) } diff --git a/src/components/date-picker-view/date-picker-view.tsx b/src/components/date-picker-view/date-picker-view.tsx index 1d0d9c4dc7..9da2777ae1 100644 --- a/src/components/date-picker-view/date-picker-view.tsx +++ b/src/components/date-picker-view/date-picker-view.tsx @@ -1,22 +1,22 @@ -import React, { useCallback, useMemo } from 'react' import type { FC, ReactNode } from 'react' -import PickerView from '../picker-view' -import type { PickerValue, PickerViewProps } from '../picker-view' +import React, { useCallback, useMemo } from 'react' import { NativeProps, withNativeProps } from '../../utils/native-props' -import { mergeProps } from '../../utils/with-default-props' import { usePropsValue } from '../../utils/use-props-value' +import { mergeProps } from '../../utils/with-default-props' +import type { + DatePickerFilter, + Precision, +} from '../date-picker/date-picker-utils' import { - generateDatePickerColumns, convertDateToStringArray, convertStringArrayToDate, + generateDatePickerColumns, } from '../date-picker/date-picker-utils' -import type { - Precision, - DatePickerFilter, -} from '../date-picker/date-picker-utils' -import useRenderLabel from './useRenderLabel' -import { TILL_NOW } from '../date-picker/util' import type { PickerDate } from '../date-picker/util' +import { TILL_NOW } from '../date-picker/util' +import type { PickerValue, PickerViewProps } from '../picker-view' +import PickerView from '../picker-view' +import useRenderLabel from './useRenderLabel' export type RenderLabel = (type: Precision | 'now', data: number) => ReactNode @@ -43,13 +43,13 @@ const defaultProps = { precision: 'day', } -export const DatePickerView: FC = p => { - const props = mergeProps(defaultProps, p) - const { renderLabel } = props +export const DatePickerView: FC = props => { + const mergedProps = mergeProps(defaultProps, props) + const { renderLabel } = mergedProps const [value, setValue] = usePropsValue({ - value: props.value, - defaultValue: props.defaultValue ?? null, + value: mergedProps.value, + defaultValue: mergedProps.defaultValue ?? null, }) const mergedRenderLabel = useRenderLabel(renderLabel) @@ -59,38 +59,38 @@ export const DatePickerView: FC = p => { return [TILL_NOW, null, null] } - return convertDateToStringArray(value, props.precision) - }, [value, props.precision]) + return convertDateToStringArray(value, mergedProps.precision) + }, [value, mergedProps.precision]) const onChange = useCallback( (val: PickerValue[]) => { - const date = convertStringArrayToDate(val, props.precision) + const date = convertStringArrayToDate(val, mergedProps.precision) if (date) { setValue(date) - props.onChange?.(date) + mergedProps.onChange?.(date) } }, - [props.onChange, props.precision] + [mergedProps.onChange, mergedProps.precision] ) return withNativeProps( - props, + mergedProps, generateDatePickerColumns( selected as string[], - props.min, - props.max, - props.precision, + mergedProps.min, + mergedProps.max, + mergedProps.precision, mergedRenderLabel, - props.filter, - props.tillNow + mergedProps.filter, + mergedProps.tillNow ) } - loading={props.loading} - loadingContent={props.loadingContent} + loading={mergedProps.loading} + loadingContent={mergedProps.loadingContent} value={pickerValue} - mouseWheel={props.mouseWheel} + mouseWheel={mergedProps.mouseWheel} onChange={onChange} /> ) diff --git a/src/components/date-picker/date-picker.tsx b/src/components/date-picker/date-picker.tsx index dc76a7d716..00b7be30de 100644 --- a/src/components/date-picker/date-picker.tsx +++ b/src/components/date-picker/date-picker.tsx @@ -1,28 +1,28 @@ -import React, { forwardRef, useCallback, useMemo } from 'react' -import type { ReactNode } from 'react' import { useMemoizedFn } from 'ahooks' -import Picker from '../picker' +import type { ReactNode } from 'react' +import React, { forwardRef, useCallback, useMemo } from 'react' +import { bound } from '../../utils/bound' +import { NativeProps, withNativeProps } from '../../utils/native-props' +import { usePropsValue } from '../../utils/use-props-value' +import { mergeProps } from '../../utils/with-default-props' +import type { RenderLabel } from '../date-picker-view/date-picker-view' +import useRenderLabel from '../date-picker-view/useRenderLabel' import type { + PickerActions, + PickerColumn, PickerProps, PickerRef, - PickerActions, PickerValue, - PickerColumn, } from '../picker' -import { NativeProps, withNativeProps } from '../../utils/native-props' -import { mergeProps } from '../../utils/with-default-props' -import { usePropsValue } from '../../utils/use-props-value' +import Picker from '../picker' +import type { DatePickerFilter, Precision } from './date-picker-utils' import { convertDateToStringArray, convertStringArrayToDate, generateDatePickerColumns, } from './date-picker-utils' -import type { Precision, DatePickerFilter } from './date-picker-utils' -import { bound } from '../../utils/bound' -import useRenderLabel from '../date-picker-view/useRenderLabel' -import type { RenderLabel } from '../date-picker-view/date-picker-view' -import { TILL_NOW } from './util' import type { PickerDate } from './util' +import { TILL_NOW } from './util' export type DatePickerRef = PickerRef @@ -70,16 +70,16 @@ const defaultProps = { } export const DatePicker = forwardRef( - (p, ref) => { - const props = mergeProps(defaultProps, p) - const { renderLabel } = props + (props, ref) => { + const mergedProps = mergeProps(defaultProps, props) + const { renderLabel } = mergedProps const [value, setValue] = usePropsValue({ - value: props.value, - defaultValue: props.defaultValue, + value: mergedProps.value, + defaultValue: mergedProps.defaultValue, onChange: v => { if (v === null) return - props.onConfirm?.(v) + mergedProps.onConfirm?.(v) }, }) @@ -95,65 +95,75 @@ export const DatePicker = forwardRef( } date = new Date( - bound(date.getTime(), props.min.getTime(), props.max.getTime()) + bound( + date.getTime(), + mergedProps.min.getTime(), + mergedProps.max.getTime() + ) ) - return convertDateToStringArray(date, props.precision) - }, [value, props.precision, props.min, props.max]) + return convertDateToStringArray(date, mergedProps.precision) + }, [value, mergedProps.precision, mergedProps.min, mergedProps.max]) const onConfirm = useCallback( (val: PickerValue[]) => { - const date = convertStringArrayToDate(val, props.precision) + const date = convertStringArrayToDate(val, mergedProps.precision) setValue(date, true) }, - [setValue, props.precision] + [setValue, mergedProps.precision] ) const onSelect = useMemoizedFn((val: PickerValue[]) => { - const date = convertStringArrayToDate(val, props.precision) - props.onSelect?.(date) + const date = convertStringArrayToDate(val, mergedProps.precision) + mergedProps.onSelect?.(date) }) const columns = useCallback<(value: PickerValue[]) => PickerColumn[]>( selected => generateDatePickerColumns( selected as string[], - props.min, - props.max, - props.precision, + mergedProps.min, + mergedProps.max, + mergedProps.precision, mergedRenderLabel, - props.filter, - props.tillNow + mergedProps.filter, + mergedProps.tillNow ), - [props.min, props.max, props.precision, mergedRenderLabel, props.tillNow] + [ + mergedProps.min, + mergedProps.max, + mergedProps.precision, + mergedRenderLabel, + mergedProps.tillNow, + ] ) return withNativeProps( - props, + mergedProps, - {(_, actions) => props.children?.(value, actions)} + {(_, actions) => mergedProps.children?.(value, actions)} ) } diff --git a/src/components/dialog/alert.tsx b/src/components/dialog/alert.tsx index a21e6b71b6..fcebc2146b 100644 --- a/src/components/dialog/alert.tsx +++ b/src/components/dialog/alert.tsx @@ -1,8 +1,8 @@ -import { show } from './show' -import { DialogProps } from './index' -import { mergeProps } from '../../utils/with-default-props' import type { ReactNode } from 'react' +import { mergeProps } from '../../utils/with-default-props' import { getDefaultConfig } from '../config-provider' +import { DialogProps } from './index' +import { show } from './show' export type DialogAlertProps = Omit< DialogProps, @@ -12,24 +12,24 @@ export type DialogAlertProps = Omit< onConfirm?: () => void | Promise } -export function alert(p: DialogAlertProps) { +export function alert(props: DialogAlertProps) { const defaultProps = { confirmText: getDefaultConfig().locale.Dialog.ok, } - const props = mergeProps(defaultProps, p) + const mergedProps = mergeProps(defaultProps, props) return new Promise(resolve => { show({ - ...props, + ...mergedProps, closeOnAction: true, actions: [ { key: 'confirm', - text: props.confirmText, + text: mergedProps.confirmText, }, ], - onAction: props.onConfirm, + onAction: mergedProps.onConfirm, onClose: () => { - props.onClose?.() + mergedProps.onClose?.() resolve() }, }) diff --git a/src/components/dialog/dialog.tsx b/src/components/dialog/dialog.tsx index 5f3a718542..44f2502902 100644 --- a/src/components/dialog/dialog.tsx +++ b/src/components/dialog/dialog.tsx @@ -1,12 +1,12 @@ -import React from 'react' +import classNames from 'classnames' import type { FC, ReactNode } from 'react' +import React from 'react' +import { NativeProps } from '../../utils/native-props' import { mergeProps } from '../../utils/with-default-props' -import classNames from 'classnames' -import { Action, DialogActionButton } from './dialog-action-button' -import Image from '../image' import AutoCenter from '../auto-center' -import { NativeProps } from '../../utils/native-props' import CenterPopup, { CenterPopupProps } from '../center-popup' +import Image from '../image' +import { Action, DialogActionButton } from './dialog-action-button' export type DialogProps = Pick< CenterPopupProps, @@ -41,36 +41,42 @@ const defaultProps = { getContainer: null, } -export const Dialog: FC = p => { - const props = mergeProps(defaultProps, p) +export const Dialog: FC = props => { + const mergedProps = mergeProps(defaultProps, props) const element = ( <> - {!!props.image && ( + {!!mergedProps.image && (
- dialog header image + dialog header image
)} - {!!props.header && ( + {!!mergedProps.header && (
- {props.header} + {mergedProps.header}
)} - {!!props.title &&
{props.title}
} + {!!mergedProps.title && ( +
{mergedProps.title}
+ )}
- {typeof props.content === 'string' ? ( - {props.content} + {typeof mergedProps.content === 'string' ? ( + {mergedProps.content} ) : ( - props.content + mergedProps.content )}
- {props.actions.map((row, index) => { + {mergedProps.actions.map((row, index) => { const actions = Array.isArray(row) ? row : [row] return (
@@ -81,10 +87,10 @@ export const Dialog: FC = p => { onAction={async () => { await Promise.all([ action.onClick?.(), - props.onAction?.(action, index), + mergedProps.onAction?.(action, index), ]) - if (props.closeOnAction) { - props.onClose?.() + if (mergedProps.closeOnAction) { + mergedProps.onClose?.() } }} /> @@ -98,33 +104,33 @@ export const Dialog: FC = p => { return ( { - props.onClose?.() + mergedProps.onClose?.() } : undefined } - visible={props.visible} - getContainer={props.getContainer} - bodyStyle={props.bodyStyle} + visible={mergedProps.visible} + getContainer={mergedProps.getContainer} + bodyStyle={mergedProps.bodyStyle} bodyClassName={classNames( cls('body'), - props.image && cls('with-image'), - props.bodyClassName + mergedProps.image && cls('with-image'), + mergedProps.bodyClassName )} - maskStyle={props.maskStyle} - maskClassName={props.maskClassName} - stopPropagation={props.stopPropagation} - disableBodyScroll={props.disableBodyScroll} - destroyOnClose={props.destroyOnClose} - forceRender={props.forceRender} + maskStyle={mergedProps.maskStyle} + maskClassName={mergedProps.maskClassName} + stopPropagation={mergedProps.stopPropagation} + disableBodyScroll={mergedProps.disableBodyScroll} + destroyOnClose={mergedProps.destroyOnClose} + forceRender={mergedProps.forceRender} role='dialog' - aria-label={props['aria-label']} + aria-label={mergedProps['aria-label']} > {element} diff --git a/src/components/divider/divider.tsx b/src/components/divider/divider.tsx index f227cf82ae..7462b43941 100644 --- a/src/components/divider/divider.tsx +++ b/src/components/divider/divider.tsx @@ -1,6 +1,6 @@ -import React from 'react' -import type { FC, ReactNode } from 'react' import classNames from 'classnames' +import type { FC, ReactNode } from 'react' +import React from 'react' import { NativeProps, withNativeProps } from '../../utils/native-props' import { mergeProps } from '../../utils/with-default-props' @@ -17,19 +17,19 @@ const defaultProps = { direction: 'horizontal', } -export const Divider: FC = p => { - const props = mergeProps(defaultProps, p) +export const Divider: FC = props => { + const mergedProps = mergeProps(defaultProps, props) return withNativeProps( - props, + mergedProps,
- {props.children && ( -
{props.children}
+ {mergedProps.children && ( +
{mergedProps.children}
)}
) diff --git a/src/components/dot-loading/dot-loading.tsx b/src/components/dot-loading/dot-loading.tsx index 017bf415c4..6dce31822c 100644 --- a/src/components/dot-loading/dot-loading.tsx +++ b/src/components/dot-loading/dot-loading.tsx @@ -1,7 +1,7 @@ +import classNames from 'classnames' import React, { memo } from 'react' -import { mergeProps } from '../../utils/with-default-props' import { NativeProps, withNativeProps } from '../../utils/native-props' -import classNames from 'classnames' +import { mergeProps } from '../../utils/with-default-props' const classPrefix = `adm-dot-loading` @@ -19,13 +19,13 @@ const defaultProps = { color: 'default', } -export const DotLoading = memo(p => { - const props = mergeProps(defaultProps, p) +export const DotLoading = memo(props => { + const mergedProps = mergeProps(defaultProps, props) return withNativeProps( - props, + mergedProps,
diff --git a/src/components/ellipsis/ellipsis.tsx b/src/components/ellipsis/ellipsis.tsx index 08d966035c..7d6eda775e 100644 --- a/src/components/ellipsis/ellipsis.tsx +++ b/src/components/ellipsis/ellipsis.tsx @@ -1,10 +1,10 @@ -import React, { useMemo, useRef, useState } from 'react' +import { useIsomorphicLayoutEffect } from 'ahooks' import type { FC, ReactNode } from 'react' +import React, { useMemo, useRef, useState } from 'react' import runes from 'runes2' -import { mergeProps } from '../../utils/with-default-props' import { NativeProps, withNativeProps } from '../../utils/native-props' import { useResizeEffect } from '../../utils/use-resize-effect' -import { useIsomorphicLayoutEffect } from 'ahooks' +import { mergeProps } from '../../utils/with-default-props' import { PropagationEvent, withStopPropagation, @@ -39,17 +39,17 @@ type EllipsisedValue = { tailing?: string } -export const Ellipsis: FC = p => { - const props = mergeProps(defaultProps, p) +export const Ellipsis: FC = props => { + const mergedProps = mergeProps(defaultProps, props) const rootRef = useRef(null) const expandElRef = useRef(null) const collapseElRef = useRef(null) const [ellipsised, setEllipsised] = useState({}) - const [expanded, setExpanded] = useState(props.defaultExpanded) + const [expanded, setExpanded] = useState(mergedProps.defaultExpanded) const [exceeded, setExceeded] = useState(false) - const chars = useMemo(() => runes(props.content), [props.content]) + const chars = useMemo(() => runes(mergedProps.content), [mergedProps.content]) function getSubString(start: number, end: number) { return chars.slice(start, end).join('') } @@ -80,33 +80,33 @@ export const Ellipsis: FC = p => { const lineHeight = pxToNumber(originStyle.lineHeight) const maxHeight = Math.floor( - lineHeight * (props.rows + 0.5) + + lineHeight * (mergedProps.rows + 0.5) + pxToNumber(originStyle.paddingTop) + pxToNumber(originStyle.paddingBottom) ) - container.innerText = props.content + container.innerText = mergedProps.content document.body.appendChild(container) if (container.offsetHeight <= maxHeight) { setExceeded(false) } else { setExceeded(true) - const end = props.content.length + const end = mergedProps.content.length const collapseEl = - typeof props.collapseText === 'string' - ? props.collapseText + typeof mergedProps.collapseText === 'string' + ? mergedProps.collapseText : collapseElRef.current?.innerHTML const expandEl = - typeof props.expandText === 'string' - ? props.expandText + typeof mergedProps.expandText === 'string' + ? mergedProps.expandText : expandElRef.current?.innerHTML const actionText = expanded ? collapseEl : expandEl function check(left: number, right: number): EllipsisedValue { if (right - left <= 1) { - if (props.direction === 'end') { + if (mergedProps.direction === 'end') { return { leading: getSubString(0, left) + '...', } @@ -117,20 +117,20 @@ export const Ellipsis: FC = p => { } } const middle = Math.round((left + right) / 2) - if (props.direction === 'end') { + if (mergedProps.direction === 'end') { container.innerHTML = getSubString(0, middle) + '...' + actionText } else { container.innerHTML = actionText + '...' + getSubString(middle, end) } if (container.offsetHeight <= maxHeight) { - if (props.direction === 'end') { + if (mergedProps.direction === 'end') { return check(middle, right) } else { return check(left, middle) } } else { - if (props.direction === 'end') { + if (mergedProps.direction === 'end') { return check(left, middle) } else { return check(middle, right) @@ -174,7 +174,7 @@ export const Ellipsis: FC = p => { const middle = Math.floor((0 + end) / 2) const ellipsised = - props.direction === 'middle' + mergedProps.direction === 'middle' ? checkMiddle([0, middle], [middle, end]) : check(0, end) setEllipsised(ellipsised) @@ -186,48 +186,48 @@ export const Ellipsis: FC = p => { useIsomorphicLayoutEffect(() => { calcEllipsised() }, [ - props.content, - props.direction, - props.rows, - props.expandText, - props.collapseText, + mergedProps.content, + mergedProps.direction, + mergedProps.rows, + mergedProps.expandText, + mergedProps.collapseText, ]) const expandActionElement = - !!props.expandText && + !!mergedProps.expandText && withStopPropagation( - props.stopPropagationForActionButtons, + mergedProps.stopPropagationForActionButtons, { setExpanded(true) }} > - {props.expandText} + {mergedProps.expandText} ) const collapseActionElement = - !!props.collapseText && + !!mergedProps.collapseText && withStopPropagation( - props.stopPropagationForActionButtons, + mergedProps.stopPropagationForActionButtons, { setExpanded(false) }} > - {props.collapseText} + {mergedProps.collapseText} ) const renderContent = () => { - if (!exceeded) return props.content + if (!exceeded) return mergedProps.content if (expanded) return ( <> - {props.content} + {mergedProps.content} {collapseActionElement} ) @@ -241,13 +241,13 @@ export const Ellipsis: FC = p => { } return withNativeProps( - props, + mergedProps,
{ if (e.target === e.currentTarget) { - props.onContentClick(e) + mergedProps.onContentClick(e) } }} > diff --git a/src/components/error-block/create-error-block.tsx b/src/components/error-block/create-error-block.tsx index 8ab71dd4a6..0fc3f66e2c 100644 --- a/src/components/error-block/create-error-block.tsx +++ b/src/components/error-block/create-error-block.tsx @@ -1,10 +1,10 @@ -import React from 'react' -import type { FC, ReactNode, ReactElement } from 'react' import classNames from 'classnames' -import { mergeProps } from '../../utils/with-default-props' +import type { FC, ReactElement, ReactNode } from 'react' +import React from 'react' +import type { ErrorBlockStatus, ImageRecord } from '.' import { NativeProps, withNativeProps } from '../../utils/native-props' +import { mergeProps } from '../../utils/with-default-props' import { useConfig } from '../config-provider' -import type { ErrorBlockStatus, ImageRecord } from '.' import './error-block.less' const classPrefix = `adm-error-block` @@ -28,15 +28,18 @@ const defaultProps = { } export function createErrorBlock(imageRecord: ImageRecord) { - const ErrorBlock: FC = p => { - const props = mergeProps(defaultProps, p) + const ErrorBlock: FC = props => { + const mergedProps = mergeProps(defaultProps, props) const { locale } = useConfig() - const contentPack = locale.ErrorBlock[props.status] + const contentPack = locale.ErrorBlock[mergedProps.status] const desc = - 'description' in props ? props.description : contentPack.description - const title = 'title' in props ? props.title : contentPack.title + 'description' in mergedProps + ? mergedProps.description + : contentPack.description + const title = 'title' in mergedProps ? mergedProps.title : contentPack.title - const image: ReactNode = props.image ?? imageRecord[props.status] + const image: ReactNode = + mergedProps.image ?? imageRecord[mergedProps.status] const imageNode = typeof image === 'string' ? ( error block image @@ -45,10 +48,10 @@ export function createErrorBlock(imageRecord: ImageRecord) { ) return withNativeProps( - props, + mergedProps,
{imageNode}
@@ -62,8 +65,8 @@ export function createErrorBlock(imageRecord: ImageRecord) { )}
- {props.children && ( -
{props.children}
+ {mergedProps.children && ( +
{mergedProps.children}
)}
) diff --git a/src/components/floating-bubble/floating-bubble.tsx b/src/components/floating-bubble/floating-bubble.tsx index 3fd07f80f4..237d0df69d 100644 --- a/src/components/floating-bubble/floating-bubble.tsx +++ b/src/components/floating-bubble/floating-bubble.tsx @@ -1,9 +1,9 @@ -import React, { useRef, useEffect, useState } from 'react' -import type { FC, ReactNode } from 'react' -import { useSpring, animated, to } from '@react-spring/web' +import { animated, to, useSpring } from '@react-spring/web' import { useDrag } from '@use-gesture/react' -import { mergeProps } from '../../utils/with-default-props' +import type { FC, ReactNode } from 'react' +import React, { useEffect, useRef, useState } from 'react' import { NativeProps, withNativeProps } from '../../utils/native-props' +import { mergeProps } from '../../utils/with-default-props' const classPrefix = `adm-floating-bubble` @@ -34,20 +34,22 @@ const defaultProps = { defaultOffset: { x: 0, y: 0 }, } -export const FloatingBubble: FC = p => { - const props = mergeProps(defaultProps, p) +export const FloatingBubble: FC = props => { + const mergedProps = mergeProps(defaultProps, props) const boundaryRef = useRef(null) const buttonRef = useRef(null) const [innerValue, setInnerValue] = useState( - props.offset === undefined ? props.defaultOffset : props.offset + mergedProps.offset === undefined + ? mergedProps.defaultOffset + : mergedProps.offset ) useEffect(() => { - if (props.offset === undefined) return - api.start({ x: props.offset.x, y: props.offset.y }) - }, [props.offset]) + if (mergedProps.offset === undefined) return + api.start({ x: mergedProps.offset.x, y: mergedProps.offset.y }) + }, [mergedProps.offset]) /** * memoize the `to` function @@ -65,13 +67,13 @@ export const FloatingBubble: FC = p => { let nextX = state.offset[0] let nextY = state.offset[1] - if (state.last && props.magnetic) { + if (state.last && mergedProps.magnetic) { const boundary = boundaryRef.current const button = buttonRef.current if (!boundary || !button) return const boundaryRect = boundary.getBoundingClientRect() const buttonRect = button.getBoundingClientRect() - if (props.magnetic === 'x') { + if (mergedProps.magnetic === 'x') { const compensation = x.goal - x.get() const leftDistance = buttonRect.left + compensation - boundaryRect.left @@ -82,7 +84,7 @@ export const FloatingBubble: FC = p => { } else { nextX -= leftDistance } - } else if (props.magnetic === 'y') { + } else if (mergedProps.magnetic === 'y') { const compensation = y.goal - y.get() const topDistance = buttonRect.top + compensation - boundaryRect.top const bottomDistance = @@ -96,13 +98,13 @@ export const FloatingBubble: FC = p => { } const nextOffest = { x: nextX, y: nextY } - if (props.offset === undefined) { + if (mergedProps.offset === undefined) { // Uncontrolled mode api.start(nextOffest) } else { setInnerValue(nextOffest) } - props.onOffsetChange?.(nextOffest) + mergedProps.onOffsetChange?.(nextOffest) // active status api.start({ @@ -110,7 +112,7 @@ export const FloatingBubble: FC = p => { }) }, { - axis: props.axis === 'xy' ? undefined : props.axis, + axis: mergedProps.axis === 'xy' ? undefined : mergedProps.axis, pointer: { touch: true, }, @@ -123,7 +125,7 @@ export const FloatingBubble: FC = p => { ) return withNativeProps( - props, + mergedProps,
@@ -134,11 +136,11 @@ export const FloatingBubble: FC = p => { opacity, transform: to([x, y], (x, y) => `translate(${x}px, ${y}px)`), }} - onClick={props.onClick} + onClick={mergedProps.onClick} className={`${classPrefix}-button`} ref={buttonRef} > - {props.children} + {mergedProps.children}
) diff --git a/src/components/floating-panel/floating-panel.tsx b/src/components/floating-panel/floating-panel.tsx index 5d2f37b968..1ad4a406db 100644 --- a/src/components/floating-panel/floating-panel.tsx +++ b/src/components/floating-panel/floating-panel.tsx @@ -1,13 +1,13 @@ -import React, { forwardRef, useImperativeHandle, useRef, useState } from 'react' +import { animated, useSpring } from '@react-spring/web' +import { useDrag } from '@use-gesture/react' +import { useMemoizedFn } from 'ahooks' import type { ReactNode } from 'react' +import React, { forwardRef, useImperativeHandle, useRef, useState } from 'react' import { NativeProps, withNativeProps } from '../../utils/native-props' -import { useDrag } from '@use-gesture/react' -import { useSpring, animated } from '@react-spring/web' -import { supportsPassive } from '../../utils/supports-passive' import { nearest } from '../../utils/nearest' -import { mergeProps } from '../../utils/with-default-props' +import { supportsPassive } from '../../utils/supports-passive' import { useLockScroll } from '../../utils/use-lock-scroll' -import { useMemoizedFn } from 'ahooks' +import { mergeProps } from '../../utils/with-default-props' const classPrefix = 'adm-floating-panel' @@ -32,9 +32,9 @@ const defaultProps = { } export const FloatingPanel = forwardRef( - (p, ref) => { - const props = mergeProps(defaultProps, p) - const { anchors } = props + (props, ref) => { + const mergedProps = mergeProps(defaultProps, props) + const { anchors } = mergedProps const maxHeight = anchors[anchors.length - 1] ?? window.innerHeight const possibles = anchors.map(x => -x) @@ -50,7 +50,9 @@ export const FloatingPanel = forwardRef( bottom: possibles[0], } - const onHeightChange = useMemoizedFn(props.onHeightChange ?? (() => {})) + const onHeightChange = useMemoizedFn( + mergedProps.onHeightChange ?? (() => {}) + ) const [{ y }, api] = useSpring(() => ({ y: bounds.bottom, @@ -69,7 +71,7 @@ export const FloatingPanel = forwardRef( if (header === target || header?.contains(target)) { pullingRef.current = true } else { - if (!props.handleDraggingOfContent) return + if (!mergedProps.handleDraggingOfContent) return const reachedTop = y.goal <= bounds.top const content = contentRef.current if (!content) return @@ -131,7 +133,7 @@ export const FloatingPanel = forwardRef( useLockScroll(elementRef, true) return withNativeProps( - props, + mergedProps, (
- {props.children} + {mergedProps.children}
) diff --git a/src/components/footer/footer.tsx b/src/components/footer/footer.tsx index 13c70c241d..7c631ccfa6 100644 --- a/src/components/footer/footer.tsx +++ b/src/components/footer/footer.tsx @@ -1,6 +1,6 @@ -import React from 'react' -import type { FC, ReactNode } from 'react' import classNames from 'classnames' +import type { FC, ReactNode } from 'react' +import React from 'react' import { NativeProps, withNativeProps } from '../../utils/native-props' import { mergeProps } from '../../utils/with-default-props' import Divider from '../divider' @@ -33,9 +33,9 @@ const defaultProps: FooterProps = { chips: [], } -export const Footer: FC = p => { - const props = mergeProps(defaultProps, p) - const { label, links, content, chips, onChipClick, onLinkClick } = props +export const Footer: FC = props => { + const mergedProps = mergeProps(defaultProps, props) + const { label, links, content, chips, onChipClick, onLinkClick } = mergedProps const clickChipItem = (item: ChipItem, index: number) => { if (chips?.length && item.type === 'link') { @@ -54,7 +54,7 @@ export const Footer: FC = p => { } } return withNativeProps( - props, + mergedProps,
{label && (
diff --git a/src/components/form/form.tsx b/src/components/form/form.tsx index 454eb20bbc..2563283934 100644 --- a/src/components/form/form.tsx +++ b/src/components/form/form.tsx @@ -1,20 +1,20 @@ -import React, { forwardRef, useMemo } from 'react' -import type { ReactNode, ForwardedRef } from 'react' import classNames from 'classnames' -import { NativeProps } from '../../utils/native-props' -import List, { ListProps } from '../list' -import RcForm from 'rc-field-form' +import merge from 'deepmerge' import type { - FormProps as RcFormProps, FormInstance as RCFormInstance, + FormProps as RcFormProps, } from 'rc-field-form' -import { defaultFormContext, FormContext, FormContextType } from './context' +import RcForm from 'rc-field-form' +import type { ForwardedRef, ReactNode } from 'react' +import React, { forwardRef, useMemo } from 'react' +import { NativeProps } from '../../utils/native-props' +import { traverseReactNode } from '../../utils/traverse-react-node' import { mergeProps } from '../../utils/with-default-props' -import { Header } from './header' import { useConfig } from '../config-provider' -import merge from 'deepmerge' +import List, { ListProps } from '../list' +import { FormContext, FormContextType, defaultFormContext } from './context' import { FormArray } from './form-array' -import { traverseReactNode } from '../../utils/traverse-react-node' +import { Header } from './header' const classPrefix = 'adm-form' @@ -58,8 +58,8 @@ export type FormProps = Pick< const defaultProps = defaultFormContext -export const Form = forwardRef((p, ref) => { - const props = mergeProps(defaultProps, p) +export const Form = forwardRef((props, ref) => { + const mergedProps = mergeProps(defaultProps, props) const { className, style, @@ -71,7 +71,7 @@ export const Form = forwardRef((p, ref) => { disabled, requiredMarkStyle, ...formProps - } = props + } = mergedProps const { locale } = useConfig() @@ -99,7 +99,7 @@ export const Form = forwardRef((p, ref) => { ) items = [] } - traverseReactNode(props.children as ReactNode, child => { + traverseReactNode(mergedProps.children as ReactNode, child => { if (React.isValidElement(child)) { if (child.type === Header) { collect() diff --git a/src/components/grid/grid.tsx b/src/components/grid/grid.tsx index 735093e659..9f1e0e5e6e 100644 --- a/src/components/grid/grid.tsx +++ b/src/components/grid/grid.tsx @@ -1,8 +1,8 @@ -import { mergeProps } from '../../utils/with-default-props' +import type { CSSProperties, FC, ReactNode } from 'react' import React from 'react' -import type { FC, ReactNode, CSSProperties } from 'react' import { NativeProps, withNativeProps } from '../../utils/native-props' import { toCSSLength } from '../../utils/to-css-length' +import { mergeProps } from '../../utils/with-default-props' const classPrefix = `adm-grid` @@ -43,20 +43,20 @@ export type GridItemProps = { type GridItemStyle = CSSProperties & Record<'--item-span', GridItemProps['span']> -export const GridItem: FC = p => { - const props = mergeProps({ span: 1 }, p) +export const GridItem: FC = props => { + const mergedProps = mergeProps({ span: 1 }, props) const itemStyle: GridItemStyle = { - '--item-span': props.span, + '--item-span': mergedProps.span, } return withNativeProps( - props, + mergedProps,
- {props.children} + {mergedProps.children}
) } diff --git a/src/components/image-uploader/image-uploader.tsx b/src/components/image-uploader/image-uploader.tsx index 699218b142..385e8c5d68 100644 --- a/src/components/image-uploader/image-uploader.tsx +++ b/src/components/image-uploader/image-uploader.tsx @@ -1,22 +1,22 @@ -import React, { forwardRef, useRef, useState, useImperativeHandle } from 'react' +import { useIsomorphicLayoutEffect, useSize, useUnmount } from 'ahooks' +import { AddOutline, CloseOutline } from 'antd-mobile-icons' import type { - ReactNode, - InputHTMLAttributes, CSSProperties, + InputHTMLAttributes, ReactElement, + ReactNode, } from 'react' -import { AddOutline, CloseOutline } from 'antd-mobile-icons' -import { mergeProps } from '../../utils/with-default-props' -import ImageViewer, { ImageViewerShowHandler } from '../image-viewer' -import PreviewItem from './preview-item' -import { usePropsValue } from '../../utils/use-props-value' -import { useIsomorphicLayoutEffect, useUnmount, useSize } from 'ahooks' -import Space from '../space' -import { NativeProps, withNativeProps } from '../../utils/native-props' +import React, { forwardRef, useImperativeHandle, useRef, useState } from 'react' import { measureCSSLength } from '../../utils/measure-css-length' +import { NativeProps, withNativeProps } from '../../utils/native-props' +import { usePropsValue } from '../../utils/use-props-value' +import { mergeProps } from '../../utils/with-default-props' import { useConfig } from '../config-provider' -import type { ImageProps } from '../image' import Grid, { GridProps } from '../grid' +import type { ImageProps } from '../image' +import ImageViewer, { ImageViewerShowHandler } from '../image-viewer' +import Space from '../space' +import PreviewItem from './preview-item' export type TaskStatus = 'pending' | 'fail' | 'success' @@ -90,11 +90,11 @@ const defaultProps = { } export const ImageUploader = forwardRef( - (p, ref) => { + (props, ref) => { const { locale } = useConfig() - const props = mergeProps(defaultProps, p) - const { columns } = props - const [value, setValue] = usePropsValue(props) + const mergedProps = mergeProps(defaultProps, props) + const { columns } = mergedProps + const [value, setValue] = usePropsValue(mergedProps) const [tasks, setTasks] = useState([]) @@ -133,17 +133,17 @@ export const ImageUploader = forwardRef( }, [value]) useIsomorphicLayoutEffect(() => { - props.onUploadQueueChange?.( + mergedProps.onUploadQueueChange?.( tasks.map(item => ({ id: item.id, status: item.status })) ) }, [tasks]) const idCountRef = useRef(0) - const { maxCount, onPreview, renderItem } = props + const { maxCount, onPreview, renderItem } = mergedProps async function processFile(file: File, fileList: File[]) { - const { beforeUpload } = props + const { beforeUpload } = mergedProps let transformedFile: File | null | undefined = file @@ -153,7 +153,7 @@ export const ImageUploader = forwardRef( } function getFinalTasks(tasks: Task[]) { - return props.showFailed + return mergedProps.showFailed ? tasks : tasks.filter(task => task.status !== 'fail') } @@ -165,7 +165,7 @@ export const ImageUploader = forwardRef( let files = [].slice.call(rawFiles) as File[] e.target.value = '' // HACK: fix the same file doesn't trigger onChange - if (props.beforeUpload) { + if (mergedProps.beforeUpload) { const postFiles = files.map(file => processFile(file, files)) await Promise.all(postFiles).then(filesList => { @@ -181,7 +181,7 @@ export const ImageUploader = forwardRef( const exceed = value.length + files.length - maxCount if (exceed > 0) { files = files.slice(0, files.length - exceed) - props.onCountExceed?.(exceed) + mergedProps.onCountExceed?.(exceed) } } @@ -191,7 +191,7 @@ export const ImageUploader = forwardRef( id: idCountRef.current++, status: 'pending', file, - } as Task) + }) as Task ) setTasks(prev => [...getFinalTasks(prev), ...newTasks]) @@ -199,7 +199,7 @@ export const ImageUploader = forwardRef( await Promise.all( newTasks.map(async (currentTask, index) => { try { - const result = await props.upload(currentTask.file) + const result = await mergedProps.upload(currentTask.file) newVal[index] = result setTasks(prev => { return prev.map(task => { @@ -251,7 +251,7 @@ export const ImageUploader = forwardRef( const finalTasks = getFinalTasks(tasks) const showUpload = - props.showUpload && + mergedProps.showUpload && (maxCount === 0 || value.length + finalTasks.length < maxCount) const renderImages = () => { @@ -260,17 +260,17 @@ export const ImageUploader = forwardRef( { - if (props.preview) { + if (mergedProps.preview) { previewImage(index) } onPreview && onPreview(index, fileItem) }} onDelete={async () => { - const canDelete = await props.onDelete?.(fileItem) + const canDelete = await mergedProps.onDelete?.(fileItem) if (canDelete === false) return setValue(value.filter((x, i) => i !== index)) }} @@ -284,7 +284,7 @@ export const ImageUploader = forwardRef( <> {renderImages()} {tasks.map(task => { - if (!props.showFailed && task.status === 'fail') { + if (!mergedProps.showFailed && task.status === 'fail') { return null } return ( @@ -292,9 +292,9 @@ export const ImageUploader = forwardRef( key={task.id} file={task.file} deletable={task.status !== 'pending'} - deleteIcon={props.deleteIcon} + deleteIcon={mergedProps.deleteIcon} status={task.status} - imageFit={props.imageFit} + imageFit={mergedProps.imageFit} onDelete={() => { setTasks(tasks.filter(x => x.id !== task.id)) }} @@ -305,7 +305,7 @@ export const ImageUploader = forwardRef( className={`${classPrefix}-upload-button-wrap`} style={showUpload ? undefined : { display: 'none' }} > - {props.children || ( + {mergedProps.children || ( ( )} - {!props.disableUpload && ( + {!mergedProps.disableUpload && ( ( })) return withNativeProps( - props, + mergedProps,
{columns ? ( = p => { - const props = mergeProps(defaultProps, p) +export const ImageViewer: FC = props => { + const mergedProps = mergeProps(defaultProps, props) const node = (
- {props.image && ( + {mergedProps.image && ( )}
- {props.image && ( + {mergedProps.image && (
- {props.renderFooter?.(props.image)} + {mergedProps.renderFooter?.(mergedProps.image)}
)}
) - return renderToContainer(props.getContainer, node) + return renderToContainer(mergedProps.getContainer, node) } export type MultiImageViewerRef = SlidesRef @@ -96,9 +96,9 @@ const multiDefaultProps = { export const MultiImageViewer = forwardRef< MultiImageViewerRef, MultiImageViewerProps ->((p, ref) => { - const props = mergeProps(multiDefaultProps, p) - const [index, setIndex] = useState(props.defaultIndex) +>((props, ref) => { + const mergedProps = mergeProps(multiDefaultProps, props) + const [index, setIndex] = useState(mergedProps.defaultIndex) const slidesRef = useRef(null) useImperativeHandle(ref, () => ({ @@ -112,44 +112,44 @@ export const MultiImageViewer = forwardRef< (newIndex: number) => { if (newIndex === index) return setIndex(newIndex) - props.onIndexChange?.(newIndex) + mergedProps.onIndexChange?.(newIndex) }, - [props.onIndexChange, index] + [mergedProps.onIndexChange, index] ) const node = (
- {props.images && ( + {mergedProps.images && ( )}
- {props.images && ( + {mergedProps.images && (
- {props.renderFooter?.(props.images[index], index)} + {mergedProps.renderFooter?.(mergedProps.images[index], index)}
)}
) - return renderToContainer(props.getContainer, node) + return renderToContainer(mergedProps.getContainer, node) }) diff --git a/src/components/image/image.tsx b/src/components/image/image.tsx index ec6fcd6c64..23f59cbea9 100644 --- a/src/components/image/image.tsx +++ b/src/components/image/image.tsx @@ -1,13 +1,13 @@ -import { mergeProps } from '../../utils/with-default-props' -import React, { useState, useRef, useEffect } from 'react' import type { ReactNode } from 'react' -import { NativeProps, withNativeProps } from '../../utils/native-props' +import React, { useEffect, useRef, useState } from 'react' import { staged } from 'staged-components' +import { NativeProps, withNativeProps } from '../../utils/native-props' import { toCSSLength } from '../../utils/to-css-length' -import { LazyDetector } from './lazy-detector' import { useIsomorphicUpdateLayoutEffect } from '../../utils/use-isomorphic-update-layout-effect' -import { ImageIcon } from './image-icon' +import { mergeProps } from '../../utils/with-default-props' import { BrokenImageIcon } from './broken-image-icon' +import { ImageIcon } from './image-icon' +import { LazyDetector } from './lazy-detector' const classPrefix = `adm-image` @@ -54,8 +54,8 @@ const defaultProps = { draggable: false, } -export const Image = staged(p => { - const props = mergeProps(defaultProps, p) +export const Image = staged(props => { + const mergedProps = mergeProps(defaultProps, props) const [loaded, setLoaded] = useState(false) const [failed, setFailed] = useState(false) @@ -63,13 +63,13 @@ export const Image = staged(p => { const ref = useRef(null) const imgRef = useRef(null) - let src: string | undefined = props.src - let srcSet: string | undefined = props.srcSet + let src: string | undefined = mergedProps.src + let srcSet: string | undefined = mergedProps.srcSet - const [initialized, setInitialized] = useState(!props.lazy) + const [initialized, setInitialized] = useState(!mergedProps.lazy) - src = initialized ? props.src : undefined - srcSet = initialized ? props.srcSet : undefined + src = initialized ? mergedProps.src : undefined + srcSet = initialized ? mergedProps.srcSet : undefined useIsomorphicUpdateLayoutEffect(() => { setLoaded(false) @@ -85,64 +85,64 @@ export const Image = staged(p => { function renderInner() { if (failed) { - return <>{props.fallback} + return <>{mergedProps.fallback} } const img = ( {props.alt} { setLoaded(true) - props.onLoad?.(e) + mergedProps.onLoad?.(e) }} onError={e => { setFailed(true) - props.onError?.(e) + mergedProps.onError?.(e) }} style={{ - objectFit: props.fit, + objectFit: mergedProps.fit, display: loaded ? 'block' : 'none', }} - crossOrigin={props.crossOrigin} - decoding={props.decoding} - loading={props.loading} - referrerPolicy={props.referrerPolicy} - sizes={props.sizes} + crossOrigin={mergedProps.crossOrigin} + decoding={mergedProps.decoding} + loading={mergedProps.loading} + referrerPolicy={mergedProps.referrerPolicy} + sizes={mergedProps.sizes} srcSet={srcSet} - useMap={props.useMap} - draggable={props.draggable} + useMap={mergedProps.useMap} + draggable={mergedProps.draggable} /> ) return ( <> - {!loaded && props.placeholder} + {!loaded && mergedProps.placeholder} {img} ) } const style: ImageProps['style'] = {} - if (props.width) { - style['--width'] = toCSSLength(props.width) - style['width'] = toCSSLength(props.width) + if (mergedProps.width) { + style['--width'] = toCSSLength(mergedProps.width) + style['width'] = toCSSLength(mergedProps.width) } - if (props.height) { - style['--height'] = toCSSLength(props.height) - style['height'] = toCSSLength(props.height) + if (mergedProps.height) { + style['--height'] = toCSSLength(mergedProps.height) + style['height'] = toCSSLength(mergedProps.height) } return withNativeProps( - props, + mergedProps,
- {props.lazy && !initialized && ( + {mergedProps.lazy && !initialized && ( { setInitialized(true) diff --git a/src/components/index-bar/index-bar.tsx b/src/components/index-bar/index-bar.tsx index 013d816db5..0f8443dcd7 100644 --- a/src/components/index-bar/index-bar.tsx +++ b/src/components/index-bar/index-bar.tsx @@ -1,14 +1,14 @@ -import React, { forwardRef, useRef, useState, useImperativeHandle } from 'react' -import type { ReactNode, ReactElement } from 'react' -import classNames from 'classnames' -import { NativeProps, withNativeProps } from '../../utils/native-props' import { useThrottleFn } from 'ahooks' -import { mergeProps } from '../../utils/with-default-props' -import { Sidebar } from './sidebar' +import classNames from 'classnames' +import type { ReactElement, ReactNode } from 'react' +import React, { forwardRef, useImperativeHandle, useRef, useState } from 'react' import { convertPx } from '../../utils/convert-px' -import { Panel } from './panel' import { devWarning } from '../../utils/dev-log' +import { NativeProps, withNativeProps } from '../../utils/native-props' import { traverseReactNode } from '../../utils/traverse-react-node' +import { mergeProps } from '../../utils/with-default-props' +import { Panel } from './panel' +import { Sidebar } from './sidebar' const classPrefix = `adm-index-bar` @@ -26,8 +26,8 @@ const defaultProps = { sticky: true, } -export const IndexBar = forwardRef((p, ref) => { - const props = mergeProps(defaultProps, p) +export const IndexBar = forwardRef((props, ref) => { + const mergedProps = mergeProps(defaultProps, props) const titleHeight = convertPx(35) const bodyRef = useRef(null) @@ -37,7 +37,7 @@ export const IndexBar = forwardRef((p, ref) => { }[] = [] const panels: ReactElement[] = [] - traverseReactNode(props.children, child => { + traverseReactNode(mergedProps.children, child => { if (!React.isValidElement(child)) return if (child.type !== Panel) { devWarning( @@ -86,7 +86,7 @@ export const IndexBar = forwardRef((p, ref) => { if (panelIndex === index) { body.scrollTop = panel.offsetTop setActiveIndex(index) - activeIndex !== index && props.onIndexChange?.(index) + activeIndex !== index && mergedProps.onIndexChange?.(index) return } } @@ -106,7 +106,7 @@ export const IndexBar = forwardRef((p, ref) => { if (!panelIndex) continue if (panel.offsetTop + panel.clientHeight - titleHeight > scrollTop) { setActiveIndex(panelIndex) - activeIndex !== panelIndex && props.onIndexChange?.(panelIndex) + activeIndex !== panelIndex && mergedProps.onIndexChange?.(panelIndex) return } } @@ -115,10 +115,10 @@ export const IndexBar = forwardRef((p, ref) => { ) return withNativeProps( - props, + mergedProps,
= p => { - const props = mergeProps(defaultProps, p) +export const InfiniteScroll: FC = props => { + const mergedProps = mergeProps(defaultProps, props) const [failed, setFailed] = useState(false) const doLoadMore = useLockFn(async (isRetry: boolean) => { try { - await props.loadMore(isRetry) + await mergedProps.loadMore(isRetry) } catch (e) { setFailed(true) throw e @@ -57,7 +57,7 @@ export const InfiniteScroll: FC = p => { const { run: check } = useThrottleFn( async () => { if (nextFlagRef.current !== flag) return - if (!props.hasMore) return + if (!mergedProps.hasMore) return const element = elementRef.current if (!element) return if (!element.offsetParent) return @@ -69,7 +69,7 @@ export const InfiniteScroll: FC = p => { const current = isWindow(parent) ? window.innerHeight : parent.getBoundingClientRect().bottom - if (current >= elementTop - props.threshold) { + if (current >= elementTop - mergedProps.threshold) { const nextFlag = {} nextFlagRef.current = nextFlag try { @@ -112,11 +112,11 @@ export const InfiniteScroll: FC = p => { } return withNativeProps( - props, + mergedProps,
- {typeof props.children === 'function' - ? props.children(props.hasMore, failed, retry) - : props.children} + {typeof mergedProps.children === 'function' + ? mergedProps.children(mergedProps.hasMore, failed, retry) + : mergedProps.children}
) } diff --git a/src/components/list/list.tsx b/src/components/list/list.tsx index ecce3614c7..741e15eadd 100644 --- a/src/components/list/list.tsx +++ b/src/components/list/list.tsx @@ -1,6 +1,6 @@ -import React, { forwardRef, useImperativeHandle, useRef } from 'react' -import type { ReactNode } from 'react' import classNames from 'classnames' +import type { ReactNode } from 'react' +import React, { forwardRef, useImperativeHandle, useRef } from 'react' import { NativeProps, withNativeProps } from '../../utils/native-props' import { mergeProps } from '../../utils/with-default-props' @@ -33,8 +33,8 @@ export type ListRef = { nativeElement: HTMLDivElement | null } -export const List = forwardRef((p, ref) => { - const props = mergeProps(defaultProps, p) +export const List = forwardRef((props, ref) => { + const mergedProps = mergeProps(defaultProps, props) const nativeElementRef = useRef(null) useImperativeHandle(ref, () => ({ @@ -44,16 +44,18 @@ export const List = forwardRef((p, ref) => { })) return withNativeProps( - props, + mergedProps,
- {props.header && ( -
{props.header}
+ {mergedProps.header && ( +
{mergedProps.header}
)}
-
{props.children}
+
+ {mergedProps.children} +
) diff --git a/src/components/mask/mask.tsx b/src/components/mask/mask.tsx index 99d0aadaf1..36d4bcc4f1 100644 --- a/src/components/mask/mask.tsx +++ b/src/components/mask/mask.tsx @@ -1,20 +1,20 @@ -import { NativeProps, withNativeProps } from '../../utils/native-props' -import React, { useMemo, useRef, useState } from 'react' -import type { FC, ReactNode } from 'react' +import { animated, useSpring } from '@react-spring/web' import { useUnmountedRef } from 'ahooks' -import { useLockScroll } from '../../utils/use-lock-scroll' -import { useSpring, animated } from '@react-spring/web' +import type { FC, ReactNode } from 'react' +import React, { useMemo, useRef, useState } from 'react' +import { NativeProps, withNativeProps } from '../../utils/native-props' import { - renderToContainer, GetContainer, + renderToContainer, } from '../../utils/render-to-container' -import { mergeProps } from '../../utils/with-default-props' -import { useConfig } from '../config-provider' import { ShouldRender } from '../../utils/should-render' +import { useLockScroll } from '../../utils/use-lock-scroll' +import { mergeProps } from '../../utils/with-default-props' import { PropagationEvent, withStopPropagation, } from '../../utils/with-stop-propagation' +import { useConfig } from '../config-provider' const classPrefix = `adm-mask` @@ -54,25 +54,25 @@ const defaultProps = { stopPropagation: ['click'], } -export const Mask: FC = p => { - const props = mergeProps(defaultProps, p) +export const Mask: FC = props => { + const mergedProps = mergeProps(defaultProps, props) const { locale } = useConfig() const ref = useRef(null) - useLockScroll(ref, props.visible && props.disableBodyScroll) + useLockScroll(ref, mergedProps.visible && mergedProps.disableBodyScroll) const background = useMemo(() => { - const opacity = opacityRecord[props.opacity] ?? props.opacity - const rgb = colorRecord[props.color] - return rgb ? `rgba(${rgb}, ${opacity})` : props.color - }, [props.color, props.opacity]) + const opacity = opacityRecord[mergedProps.opacity] ?? mergedProps.opacity + const rgb = colorRecord[mergedProps.color] + return rgb ? `rgba(${rgb}, ${opacity})` : mergedProps.color + }, [mergedProps.color, mergedProps.opacity]) - const [active, setActive] = useState(props.visible) + const [active, setActive] = useState(mergedProps.visible) const unmountedRef = useUnmountedRef() const { opacity } = useSpring({ - opacity: props.visible ? 1 : 0, + opacity: mergedProps.visible ? 1 : 0, config: { precision: 0.01, mass: 1, @@ -85,44 +85,44 @@ export const Mask: FC = p => { }, onRest: () => { if (unmountedRef.current) return - setActive(props.visible) - if (props.visible) { - props.afterShow?.() + setActive(mergedProps.visible) + if (mergedProps.visible) { + mergedProps.afterShow?.() } else { - props.afterClose?.() + mergedProps.afterClose?.() } }, }) const node = withStopPropagation( - props.stopPropagation, + mergedProps.stopPropagation, withNativeProps( - props, + mergedProps, ) => { if (e.target === e.currentTarget) { - props.onMaskClick?.(e) + mergedProps.onMaskClick?.(e) } }} > - {props.onMaskClick && ( + {mergedProps.onMaskClick && (
)} -
{props.children}
+
{mergedProps.children}
) ) @@ -130,10 +130,10 @@ export const Mask: FC = p => { return ( - {renderToContainer(props.getContainer, node)} + {renderToContainer(mergedProps.getContainer, node)} ) } diff --git a/src/components/modal/alert.tsx b/src/components/modal/alert.tsx index c4c38bd1e9..600f665e16 100644 --- a/src/components/modal/alert.tsx +++ b/src/components/modal/alert.tsx @@ -1,8 +1,8 @@ -import { show } from './show' -import { ModalProps } from './index' -import { mergeProps } from '../../utils/with-default-props' import type { ReactNode } from 'react' +import { mergeProps } from '../../utils/with-default-props' import { getDefaultConfig } from '../config-provider' +import { ModalProps } from './index' +import { show } from './show' export type ModalAlertProps = Omit< ModalProps, @@ -12,25 +12,25 @@ export type ModalAlertProps = Omit< onConfirm?: () => void | Promise } -export function alert(p: ModalAlertProps) { +export function alert(props: ModalAlertProps) { const defaultProps = { confirmText: getDefaultConfig().locale.Modal.ok, } - const props = mergeProps(defaultProps, p) + const mergedProps = mergeProps(defaultProps, props) return new Promise(resolve => { show({ - ...props, + ...mergedProps, closeOnAction: true, actions: [ { key: 'confirm', - text: props.confirmText, + text: mergedProps.confirmText, primary: true, }, ], - onAction: props.onConfirm, + onAction: mergedProps.onConfirm, onClose: () => { - props.onClose?.() + mergedProps.onClose?.() resolve() }, }) diff --git a/src/components/modal/modal.tsx b/src/components/modal/modal.tsx index b55b8b223a..4c5699756e 100644 --- a/src/components/modal/modal.tsx +++ b/src/components/modal/modal.tsx @@ -1,13 +1,13 @@ -import React from 'react' +import classNames from 'classnames' import type { FC, ReactNode } from 'react' +import React from 'react' +import { NativeProps } from '../../utils/native-props' import { mergeProps } from '../../utils/with-default-props' -import classNames from 'classnames' -import { Action, ModalActionButton } from './modal-action-button' -import Image from '../image' -import Space from '../space' import AutoCenter from '../auto-center' -import { NativeProps } from '../../utils/native-props' import CenterPopup, { CenterPopupProps } from '../center-popup' +import Image from '../image' +import Space from '../space' +import { Action, ModalActionButton } from './modal-action-button' export type ModalProps = Pick< CenterPopupProps, @@ -43,26 +43,32 @@ const defaultProps = { getContainer: null, } -export const Modal: FC = p => { - const props = mergeProps(defaultProps, p) +export const Modal: FC = props => { + const mergedProps = mergeProps(defaultProps, props) const element = ( <> - {!!props.image && ( + {!!mergedProps.image && (
- modal header image + modal header image
)} - {!!props.header && ( + {!!mergedProps.header && (
- {props.header} + {mergedProps.header}
)} - {!!props.title &&
{props.title}
} + {!!mergedProps.title && ( +
{mergedProps.title}
+ )}
- {typeof props.content === 'string' ? ( - {props.content} + {typeof mergedProps.content === 'string' ? ( + {mergedProps.content} ) : ( - props.content + mergedProps.content )}
= p => { block className={classNames( cls('footer'), - props.actions.length === 0 && cls('footer-empty') + mergedProps.actions.length === 0 && cls('footer-empty') )} > - {props.actions.map((action, index) => ( + {mergedProps.actions.map((action, index) => ( { await Promise.all([ action.onClick?.(), - props.onAction?.(action, index), + mergedProps.onAction?.(action, index), ]) - if (props.closeOnAction) { - props.onClose?.() + if (mergedProps.closeOnAction) { + mergedProps.onClose?.() } }} /> @@ -94,27 +100,27 @@ export const Modal: FC = p => { return ( {element} diff --git a/src/components/number-keyboard/number-keyboard.tsx b/src/components/number-keyboard/number-keyboard.tsx index ab4ecac484..142f470e95 100644 --- a/src/components/number-keyboard/number-keyboard.tsx +++ b/src/components/number-keyboard/number-keyboard.tsx @@ -1,14 +1,14 @@ -import React, { useRef, useMemo } from 'react' -import type { FC, TouchEvent, MouseEvent } from 'react' -import classNames from 'classnames' +import { useMemoizedFn } from 'ahooks' import { DownOutline, TextDeletionOutline } from 'antd-mobile-icons' -import { mergeProps } from '../../utils/with-default-props' +import classNames from 'classnames' +import type { FC, MouseEvent, TouchEvent } from 'react' +import React, { useMemo, useRef } from 'react' +import { NativeProps, withNativeProps } from '../../utils/native-props' import { shuffle } from '../../utils/shuffle' +import { mergeProps } from '../../utils/with-default-props' +import { useConfig } from '../config-provider' import Popup, { PopupProps } from '../popup' -import { NativeProps, withNativeProps } from '../../utils/native-props' import SafeArea from '../safe-area' -import { useMemoizedFn } from 'ahooks' -import { useConfig } from '../config-provider' const classPrefix = 'adm-number-keyboard' @@ -47,8 +47,8 @@ const defaultProps = { forceRender: false, } -export const NumberKeyboard: FC = p => { - const props = mergeProps(defaultProps, p) +export const NumberKeyboard: FC = props => { + const mergedProps = mergeProps(defaultProps, props) const { visible, title, @@ -58,7 +58,7 @@ export const NumberKeyboard: FC = p => { randomOrder, showCloseButton, onInput, - } = props + } = mergedProps const { locale } = useConfig() @@ -85,7 +85,7 @@ export const NumberKeyboard: FC = p => { const intervalRef = useRef(-1) const onDelete = useMemoizedFn(() => { - props.onDelete?.() + mergedProps.onDelete?.() }) const onBackspacePressStart = () => { @@ -110,9 +110,9 @@ export const NumberKeyboard: FC = p => { onDelete?.() break case 'OK': - props.onConfirm?.() - if (props.closeOnConfirm) { - props.onClose?.() + mergedProps.onConfirm?.() + if (mergedProps.closeOnConfirm) { + mergedProps.onClose?.() } break default: @@ -139,7 +139,7 @@ export const NumberKeyboard: FC = p => { { - props.onClose?.() + mergedProps.onClose?.() }} role='button' title={locale.common.close} @@ -196,15 +196,15 @@ export const NumberKeyboard: FC = p => { visible={visible} getContainer={getContainer} mask={false} - afterClose={props.afterClose} - afterShow={props.afterShow} + afterClose={mergedProps.afterClose} + afterShow={mergedProps.afterShow} className={`${classPrefix}-popup`} - stopPropagation={props.stopPropagation} - destroyOnClose={props.destroyOnClose} - forceRender={props.forceRender} + stopPropagation={mergedProps.stopPropagation} + destroyOnClose={mergedProps.destroyOnClose} + forceRender={mergedProps.forceRender} > {withNativeProps( - props, + mergedProps,
= p => {
)}
- {props.safeArea && ( + {mergedProps.safeArea && (
diff --git a/src/components/page-indicator/page-indicator.tsx b/src/components/page-indicator/page-indicator.tsx index 6ad904ef85..059dbc0d3c 100644 --- a/src/components/page-indicator/page-indicator.tsx +++ b/src/components/page-indicator/page-indicator.tsx @@ -1,7 +1,7 @@ -import React, { memo } from 'react' +import classNames from 'classnames' import type { ReactElement } from 'react' +import React, { memo } from 'react' import { NativeProps, withNativeProps } from '../../utils/native-props' -import classNames from 'classnames' import { mergeProps } from '../../utils/with-default-props' const classPrefix = `adm-page-indicator` @@ -26,28 +26,28 @@ const defaultProps = { direction: 'horizontal', } -export const PageIndicator = memo(p => { - const props = mergeProps(defaultProps, p) +export const PageIndicator = memo(props => { + const mergedProps = mergeProps(defaultProps, props) const dots: ReactElement[] = [] - for (let i = 0; i < props.total; i++) { + for (let i = 0; i < mergedProps.total; i++) { dots.push(
) } return withNativeProps( - props, + mergedProps,
{dots} diff --git a/src/components/passcode-input/passcode-input.tsx b/src/components/passcode-input/passcode-input.tsx index 142907d923..b7eb906a80 100644 --- a/src/components/passcode-input/passcode-input.tsx +++ b/src/components/passcode-input/passcode-input.tsx @@ -1,18 +1,18 @@ +import classNames from 'classnames' +import type { ReactElement } from 'react' import React, { - useState, - useEffect, - useRef, forwardRef, + useEffect, useImperativeHandle, + useRef, + useState, } from 'react' -import type { ReactElement } from 'react' -import { mergeProps } from '../../utils/with-default-props' -import { NativeProps, withNativeProps } from '../../utils/native-props' -import type { NumberKeyboardProps } from '../number-keyboard' -import classNames from 'classnames' import { bound } from '../../utils/bound' +import { NativeProps, withNativeProps } from '../../utils/native-props' import { usePropsValue } from '../../utils/use-props-value' +import { mergeProps } from '../../utils/with-default-props' import { useConfig } from '../config-provider' +import type { NumberKeyboardProps } from '../number-keyboard' export type PasscodeInputProps = { value?: string @@ -52,33 +52,33 @@ const defaultProps = { } export const PasscodeInput = forwardRef( - (p: PasscodeInputProps, ref) => { - const props = mergeProps(defaultProps, p) + (props: PasscodeInputProps, ref) => { + const mergedProps = mergeProps(defaultProps, props) // 防止 length 值不合法 const cellLength = - props.length > 0 && props.length < Infinity - ? Math.floor(props.length) + mergedProps.length > 0 && mergedProps.length < Infinity + ? Math.floor(mergedProps.length) : defaultProps.length const { locale } = useConfig() const [focused, setFocused] = useState(false) - const [value, setValue] = usePropsValue(props) + const [value, setValue] = usePropsValue(mergedProps) const rootRef = useRef(null) const nativeInputRef = useRef(null) useEffect(() => { if (value.length >= cellLength) { - props.onFill?.(value) + mergedProps.onFill?.(value) } }, [value, cellLength]) const onFocus = () => { - if (!props.keyboard) { + if (!mergedProps.keyboard) { nativeInputRef.current?.focus() } setFocused(true) - props.onFocus?.() + mergedProps.onFocus?.() } useEffect(() => { @@ -97,7 +97,7 @@ export const PasscodeInput = forwardRef( const onBlur = () => { setFocused(false) - props.onBlur?.() + mergedProps.onBlur?.() } useImperativeHandle(ref, () => ({ @@ -120,13 +120,13 @@ export const PasscodeInput = forwardRef(
- {chars[i] && props.plain ? chars[i] : ''} + {chars[i] && mergedProps.plain ? chars[i] : ''}
) } @@ -135,14 +135,14 @@ export const PasscodeInput = forwardRef( const cls = classNames(classPrefix, { [`${classPrefix}-focused`]: focused, - [`${classPrefix}-error`]: props.error, - [`${classPrefix}-seperated`]: props.seperated, + [`${classPrefix}-error`]: mergedProps.error, + [`${classPrefix}-seperated`]: mergedProps.seperated, }) return ( <> {withNativeProps( - props, + mergedProps,
( pattern='[0-9]*' inputMode='numeric' onChange={e => { - setValue(e.target.value.slice(0, props.length)) + setValue(e.target.value.slice(0, mergedProps.length)) }} aria-hidden />
)} - {props.keyboard && - React.cloneElement(props.keyboard, { + {mergedProps.keyboard && + React.cloneElement(mergedProps.keyboard, { visible: focused, onInput: v => { if (value.length < cellLength) { - setValue((value + v).slice(0, props.length)) + setValue((value + v).slice(0, mergedProps.length)) } }, onDelete: () => { diff --git a/src/components/picker-view/picker-view.tsx b/src/components/picker-view/picker-view.tsx index fc82597215..9534cca7b8 100644 --- a/src/components/picker-view/picker-view.tsx +++ b/src/components/picker-view/picker-view.tsx @@ -1,13 +1,13 @@ -import React, { memo, useCallback, useEffect, useState } from 'react' +import { useDebounceEffect } from 'ahooks' import type { ReactNode } from 'react' -import { mergeProps } from '../../utils/with-default-props' -import { Wheel } from './wheel' -import { useColumnsExtend } from './columns-extend' +import React, { memo, useCallback, useEffect, useState } from 'react' import { NativeProps, withNativeProps } from '../../utils/native-props' -import { useDebounceEffect } from 'ahooks' +import { mergeProps } from '../../utils/with-default-props' import { PickerProps } from '../picker' import { defaultRenderLabel } from '../picker/picker-utils' import SpinLoading from '../spin-loading' +import { useColumnsExtend } from './columns-extend' +import { Wheel } from './wheel' const classPrefix = `adm-picker-view` @@ -48,39 +48,41 @@ const defaultProps = { ), } -export const PickerView = memo(p => { - const props = mergeProps(defaultProps, p) +export const PickerView = memo(props => { + const mergedProps = mergeProps(defaultProps, props) const [innerValue, setInnerValue] = useState( - props.value === undefined ? props.defaultValue : props.value + mergedProps.value === undefined + ? mergedProps.defaultValue + : mergedProps.value ) // Sync `value` to `innerValue` useEffect(() => { - if (props.value === undefined) return // Uncontrolled mode - if (props.value === innerValue) return - setInnerValue(props.value) - }, [props.value]) + if (mergedProps.value === undefined) return // Uncontrolled mode + if (mergedProps.value === innerValue) return + setInnerValue(mergedProps.value) + }, [mergedProps.value]) useEffect(() => { - if (props.value === innerValue) return + if (mergedProps.value === innerValue) return const timeout = window.setTimeout(() => { - if (props.value !== undefined && props.value !== innerValue) { - setInnerValue(props.value) + if (mergedProps.value !== undefined && mergedProps.value !== innerValue) { + setInnerValue(mergedProps.value) } }, 1000) return () => { window.clearTimeout(timeout) } - }, [props.value, innerValue]) + }, [mergedProps.value, innerValue]) - const extend = useColumnsExtend(props.columns, innerValue) + const extend = useColumnsExtend(mergedProps.columns, innerValue) const columns = extend.columns useDebounceEffect( () => { - if (props.value === innerValue) return - props.onChange?.(innerValue, extend) + if (mergedProps.value === innerValue) return + mergedProps.onChange?.(innerValue, extend) }, [innerValue], { @@ -99,10 +101,10 @@ export const PickerView = memo(p => { }, []) return withNativeProps( - props, + mergedProps,
- {props.loading ? ( - props.loadingContent + {mergedProps.loading ? ( + mergedProps.loadingContent ) : ( <> {columns.map((column, index) => ( @@ -112,8 +114,8 @@ export const PickerView = memo(p => { column={column} value={innerValue[index]} onSelect={handleSelect} - renderLabel={props.renderLabel} - mouseWheel={props.mouseWheel} + renderLabel={mergedProps.renderLabel} + mouseWheel={mergedProps.mouseWheel} /> ))}
diff --git a/src/components/popover/popover.tsx b/src/components/popover/popover.tsx index c0e27e76dc..d6a46473c9 100644 --- a/src/components/popover/popover.tsx +++ b/src/components/popover/popover.tsx @@ -1,40 +1,40 @@ +import { + arrow, + autoUpdate, + computePosition, + flip, + hide, + limitShift, + offset, + shift, +} from '@floating-ui/dom' +import { useClickAway, useIsomorphicLayoutEffect } from 'ahooks' +import classNames from 'classnames' +import type { ReactElement, ReactNode } from 'react' import React, { forwardRef, + useEffect, useImperativeHandle, useRef, useState, - useEffect, } from 'react' -import type { ReactNode, ReactElement } from 'react' -import classNames from 'classnames' +import { convertPx } from '../../utils/convert-px' +import { NativeProps, withNativeProps } from '../../utils/native-props' +import { + GetContainer, + renderToContainer, +} from '../../utils/render-to-container' +import { useShouldRender } from '../../utils/should-render' import { usePropsValue } from '../../utils/use-props-value' import { mergeProps } from '../../utils/with-default-props' -import { NativeProps, withNativeProps } from '../../utils/native-props' import { PropagationEvent, withStopPropagation, } from '../../utils/with-stop-propagation' import { Arrow } from './arrow' -import { - GetContainer, - renderToContainer, -} from '../../utils/render-to-container' -import { - arrow, - computePosition, - flip, - offset, - autoUpdate, - hide, - shift, - limitShift, -} from '@floating-ui/dom' -import { Wrapper } from './wrapper' -import { useShouldRender } from '../../utils/should-render' -import { useClickAway, useIsomorphicLayoutEffect } from 'ahooks' import { DeprecatedPlacement, Placement } from './index' import { normalizePlacement } from './normalize-placement' -import { convertPx } from '../../utils/convert-px' +import { Wrapper } from './wrapper' const classPrefix = `adm-popover` @@ -66,14 +66,14 @@ const defaultProps = { mode: 'light', } -export const Popover = forwardRef((p, ref) => { - const props = mergeProps(defaultProps, p) - const placement = normalizePlacement(props.placement) +export const Popover = forwardRef((props, ref) => { + const mergedProps = mergeProps(defaultProps, props) + const placement = normalizePlacement(mergedProps.placement) const [visible, setVisible] = usePropsValue({ - value: props.visible, - defaultValue: props.defaultVisible, - onChange: props.onVisibleChange, + value: mergedProps.visible, + defaultValue: mergedProps.defaultVisible, + onChange: mergedProps.onVisibleChange, }) useImperativeHandle( @@ -91,20 +91,26 @@ export const Popover = forwardRef((p, ref) => { const arrowRef = useRef(null) const floating = withStopPropagation( - props.stopPropagation, + mergedProps.stopPropagation, withNativeProps( - props, + mergedProps,
-
{props.content}
+
+ {mergedProps.content} +
) @@ -174,7 +180,7 @@ export const Popover = forwardRef((p, ref) => { useEffect(() => { if (!targetElement) return - if (!props.trigger) return + if (!mergedProps.trigger) return function handleClick() { setVisible(v => !v) @@ -183,7 +189,7 @@ export const Popover = forwardRef((p, ref) => { return () => { targetElement.removeEventListener('click', handleClick) } - }, [targetElement, props.trigger]) + }, [targetElement, mergedProps.trigger]) useEffect(() => { const floatingElement = floatingRef.current @@ -195,19 +201,23 @@ export const Popover = forwardRef((p, ref) => { useClickAway( () => { - if (!props.trigger) return + if (!mergedProps.trigger) return setVisible(false) }, [() => targetRef.current?.element, floatingRef], ['click', 'touchmove'] ) - const shouldRender = useShouldRender(visible, false, props.destroyOnHide) + const shouldRender = useShouldRender( + visible, + false, + mergedProps.destroyOnHide + ) return ( <> - {props.children} - {shouldRender && renderToContainer(props.getContainer, floating)} + {mergedProps.children} + {shouldRender && renderToContainer(mergedProps.getContainer, floating)} ) }) diff --git a/src/components/popup/popup.tsx b/src/components/popup/popup.tsx index c736cb0b08..7f7973bd3d 100644 --- a/src/components/popup/popup.tsx +++ b/src/components/popup/popup.tsx @@ -1,19 +1,19 @@ +import { animated, useSpring } from '@react-spring/web' +import { useDrag } from '@use-gesture/react' +import { useIsomorphicLayoutEffect, useUnmountedRef } from 'ahooks' import classNames from 'classnames' -import React, { useState, useRef } from 'react' import type { FC, PropsWithChildren } from 'react' -import { useIsomorphicLayoutEffect, useUnmountedRef } from 'ahooks' +import React, { useRef, useState } from 'react' import { NativeProps, withNativeProps } from '../../utils/native-props' -import { mergeProps } from '../../utils/with-default-props' -import Mask from '../mask' -import { useLockScroll } from '../../utils/use-lock-scroll' import { renderToContainer } from '../../utils/render-to-container' -import { useSpring, animated } from '@react-spring/web' -import { withStopPropagation } from '../../utils/with-stop-propagation' import { ShouldRender } from '../../utils/should-render' -import { defaultPopupBaseProps, PopupBaseProps } from './popup-base-props' import { useInnerVisible } from '../../utils/use-inner-visible' +import { useLockScroll } from '../../utils/use-lock-scroll' +import { mergeProps } from '../../utils/with-default-props' +import { withStopPropagation } from '../../utils/with-stop-propagation' import { useConfig } from '../config-provider' -import { useDrag } from '@use-gesture/react' +import Mask from '../mask' +import { PopupBaseProps, defaultPopupBaseProps } from './popup-base-props' const classPrefix = `adm-popup` @@ -30,29 +30,29 @@ const defaultProps = { position: 'bottom', } -export const Popup: FC = p => { +export const Popup: FC = props => { const { locale, popup: componentConfig = {} } = useConfig() - const props = mergeProps(defaultProps, componentConfig, p) + const mergedProps = mergeProps(defaultProps, componentConfig, props) const bodyCls = classNames( `${classPrefix}-body`, - props.bodyClassName, - `${classPrefix}-body-position-${props.position}` + mergedProps.bodyClassName, + `${classPrefix}-body-position-${mergedProps.position}` ) - const [active, setActive] = useState(props.visible) + const [active, setActive] = useState(mergedProps.visible) const ref = useRef(null) - useLockScroll(ref, props.disableBodyScroll && active ? 'strict' : false) + useLockScroll(ref, mergedProps.disableBodyScroll && active ? 'strict' : false) useIsomorphicLayoutEffect(() => { - if (props.visible) { + if (mergedProps.visible) { setActive(true) } - }, [props.visible]) + }, [mergedProps.visible]) const unmountedRef = useUnmountedRef() const { percent } = useSpring({ - percent: props.visible ? 0 : 100, + percent: mergedProps.visible ? 0 : 100, config: { precision: 0.1, mass: 0.4, @@ -61,81 +61,81 @@ export const Popup: FC = p => { }, onRest: () => { if (unmountedRef.current) return - setActive(props.visible) - if (props.visible) { - props.afterShow?.() + setActive(mergedProps.visible) + if (mergedProps.visible) { + mergedProps.afterShow?.() } else { - props.afterClose?.() + mergedProps.afterClose?.() } }, }) const bind = useDrag( ({ swipe: [, swipeY] }) => { - if (!props.closeOnSwipe) return + if (!mergedProps.closeOnSwipe) return if ( - (swipeY === 1 && props.position === 'bottom') || - (swipeY === -1 && props.position === 'top') + (swipeY === 1 && mergedProps.position === 'bottom') || + (swipeY === -1 && mergedProps.position === 'top') ) { - props.onClose?.() + mergedProps.onClose?.() } }, { axis: 'y', - enabled: ['top', 'bottom'].includes(props.position), + enabled: ['top', 'bottom'].includes(mergedProps.position), } ) - const maskVisible = useInnerVisible(active && props.visible) + const maskVisible = useInnerVisible(active && mergedProps.visible) const node = withStopPropagation( - props.stopPropagation, + mergedProps.stopPropagation, withNativeProps( - props, + mergedProps,
- {props.mask && ( + {mergedProps.mask && ( { - props.onMaskClick?.(e) - if (props.closeOnMaskClick) { - props.onClose?.() + mergedProps.onMaskClick?.(e) + if (mergedProps.closeOnMaskClick) { + mergedProps.onClose?.() } }} - className={props.maskClassName} - style={props.maskStyle} + className={mergedProps.maskClassName} + style={mergedProps.maskStyle} disableBodyScroll={false} - stopPropagation={props.stopPropagation} + stopPropagation={mergedProps.stopPropagation} /> )} (v === 0 ? 'unset' : 'none')), transform: percent.to(v => { - if (props.position === 'bottom') { + if (mergedProps.position === 'bottom') { return `translate(0, ${v}%)` } - if (props.position === 'top') { + if (mergedProps.position === 'top') { return `translate(0, -${v}%)` } - if (props.position === 'left') { + if (mergedProps.position === 'left') { return `translate(-${v}%, 0)` } - if (props.position === 'right') { + if (mergedProps.position === 'right') { return `translate(${v}%, 0)` } return 'none' @@ -143,22 +143,22 @@ export const Popup: FC = p => { }} ref={ref} > - {props.showCloseButton && ( + {mergedProps.showCloseButton && ( { - props.onClose?.() + mergedProps.onClose?.() }} role='button' aria-label={locale.common.close} > - {props.closeIcon} + {mergedProps.closeIcon} )} - {props.children} + {mergedProps.children}
) @@ -167,10 +167,10 @@ export const Popup: FC = p => { return ( - {renderToContainer(props.getContainer, node)} + {renderToContainer(mergedProps.getContainer, node)} ) } diff --git a/src/components/progress-bar/progress-bar.tsx b/src/components/progress-bar/progress-bar.tsx index 59642a4b7a..f6b05b0fbb 100644 --- a/src/components/progress-bar/progress-bar.tsx +++ b/src/components/progress-bar/progress-bar.tsx @@ -1,9 +1,9 @@ -import React from 'react' +import classNames from 'classnames' import type { FC, ReactNode } from 'react' +import React from 'react' +import { isNodeWithContent } from '../../utils/is-node-with-content' import { NativeProps, withNativeProps } from '../../utils/native-props' import { mergeProps } from '../../utils/with-default-props' -import classNames from 'classnames' -import { isNodeWithContent } from '../../utils/is-node-with-content' const classPrefix = `adm-progress-bar` @@ -21,28 +21,30 @@ const defaultProps = { text: false, } -export const ProgressBar: FC = p => { - const props = mergeProps(defaultProps, p) +export const ProgressBar: FC = props => { + const mergedProps = mergeProps(defaultProps, props) const fillStyle = { - width: `${props.percent}%`, + width: `${mergedProps.percent}%`, } const textElement = (function () { - if (props.text === true) { - return `${props.percent}%` + if (mergedProps.text === true) { + return `${mergedProps.percent}%` } - if (typeof props.text === 'function') { - return (props.text as (percent: number) => ReactNode)(props.percent) + if (typeof mergedProps.text === 'function') { + return (mergedProps.text as (percent: number) => ReactNode)( + mergedProps.percent + ) } - return props.text + return mergedProps.text })() return withNativeProps( - props, + mergedProps,
diff --git a/src/components/progress-circle/progress-circle.tsx b/src/components/progress-circle/progress-circle.tsx index 8172db887f..3d7adb82c4 100644 --- a/src/components/progress-circle/progress-circle.tsx +++ b/src/components/progress-circle/progress-circle.tsx @@ -1,5 +1,5 @@ +import type { CSSProperties, FC, ReactNode } from 'react' import React from 'react' -import type { FC, CSSProperties, ReactNode } from 'react' import { NativeProps, withNativeProps } from '../../utils/native-props' import { mergeProps } from '../../utils/with-default-props' @@ -10,20 +10,20 @@ export type ProgressCircleProps = { children?: ReactNode } & NativeProps<'--size' | '--track-width' | '--track-color' | '--fill-color'> -export const ProgressCircle: FC = p => { - const props = mergeProps({ percent: 0 }, p) +export const ProgressCircle: FC = props => { + const mergedProps = mergeProps({ percent: 0 }, props) const style: CSSProperties & Record<'--percent', string> = { - '--percent': props.percent.toString(), + '--percent': mergedProps.percent.toString(), } return withNativeProps( - props, + mergedProps,
-
{props.children}
+
{mergedProps.children}
) diff --git a/src/components/pull-to-refresh/pull-to-refresh.tsx b/src/components/pull-to-refresh/pull-to-refresh.tsx index dd34aa3f9c..2768a06c87 100644 --- a/src/components/pull-to-refresh/pull-to-refresh.tsx +++ b/src/components/pull-to-refresh/pull-to-refresh.tsx @@ -1,14 +1,14 @@ -import React, { useEffect, useRef, useState } from 'react' -import type { FC, ReactNode } from 'react' -import { mergeProps } from '../../utils/with-default-props' import { animated, useSpring } from '@react-spring/web' import { useDrag } from '@use-gesture/react' -import { getScrollParent } from '../../utils/get-scroll-parent' -import { supportsPassive } from '../../utils/supports-passive' +import type { FC, ReactNode } from 'react' +import React, { useEffect, useRef, useState } from 'react' import { convertPx } from '../../utils/convert-px' +import { getScrollParent } from '../../utils/get-scroll-parent' import { rubberbandIfOutOfBounds } from '../../utils/rubberband' -import { useConfig } from '../config-provider' import { sleep } from '../../utils/sleep' +import { supportsPassive } from '../../utils/supports-passive' +import { mergeProps } from '../../utils/with-default-props' +import { useConfig } from '../config-provider' const classPrefix = `adm-pull-to-refresh` @@ -38,9 +38,9 @@ export const defaultProps = { onRefresh: () => {}, } -export const PullToRefresh: FC = p => { +export const PullToRefresh: FC = props => { const { locale } = useConfig() - const props = mergeProps( + const mergedProps = mergeProps( defaultProps, { refreshingText: `${locale.common.loading}...`, @@ -48,10 +48,10 @@ export const PullToRefresh: FC = p => { canReleaseText: locale.PullToRefresh.canRelease, completeText: locale.PullToRefresh.complete, }, - p + props ) - const headHeight = props.headHeight ?? convertPx(40) - const threshold = props.threshold ?? convertPx(60) + const headHeight = mergedProps.headHeight ?? convertPx(40) + const threshold = mergedProps.threshold ?? convertPx(60) const [status, setStatus] = useState('pulling') @@ -92,14 +92,14 @@ export const PullToRefresh: FC = p => { api.start({ height: headHeight }) setStatus('refreshing') try { - await props.onRefresh() + await mergedProps.onRefresh() setStatus('complete') } catch (e) { reset() throw e } - if (props.completeDelay > 0) { - await sleep(props.completeDelay) + if (mergedProps.completeDelay > 0) { + await sleep(mergedProps.completeDelay) } reset() } @@ -161,20 +161,20 @@ export const PullToRefresh: FC = p => { pointer: { touch: true }, axis: 'y', target: elementRef, - enabled: !props.disabled, + enabled: !mergedProps.disabled, eventOptions: supportsPassive ? { passive: false } : undefined, } ) const renderStatusText = () => { - if (props.renderText) { - return props.renderText?.(status) + if (mergedProps.renderText) { + return mergedProps.renderText?.(status) } - if (status === 'pulling') return props.pullingText - if (status === 'canRelease') return props.canReleaseText - if (status === 'refreshing') return props.refreshingText - if (status === 'complete') return props.completeText + if (status === 'pulling') return mergedProps.pullingText + if (status === 'canRelease') return mergedProps.canReleaseText + if (status === 'refreshing') return mergedProps.refreshingText + if (status === 'complete') return mergedProps.completeText } return ( @@ -187,7 +187,7 @@ export const PullToRefresh: FC = p => { {renderStatusText()}
-
{props.children}
+
{mergedProps.children}
) } diff --git a/src/components/radio/group.tsx b/src/components/radio/group.tsx index 4150a5f2d6..114c6346c6 100644 --- a/src/components/radio/group.tsx +++ b/src/components/radio/group.tsx @@ -1,9 +1,9 @@ -import React from 'react' import type { FC, ReactNode } from 'react' -import { mergeProps } from '../../utils/with-default-props' +import React from 'react' import { RadioValue } from '.' -import { RadioGroupContext } from './group-context' import { usePropsValue } from '../../utils/use-props-value' +import { mergeProps } from '../../utils/with-default-props' +import { RadioGroupContext } from './group-context' export interface RadioGroupProps { value?: RadioValue | null @@ -18,14 +18,14 @@ const defaultProps = { defaultValue: null, } -export const Group: FC = p => { - const props = mergeProps(defaultProps, p) +export const Group: FC = props => { + const mergedProps = mergeProps(defaultProps, props) const [value, setValue] = usePropsValue({ - value: props.value, - defaultValue: props.defaultValue, + value: mergedProps.value, + defaultValue: mergedProps.defaultValue, onChange: v => { if (v === null) return - props.onChange?.(v) + mergedProps.onChange?.(v) }, }) return ( @@ -37,10 +37,10 @@ export const Group: FC = p => { setValue(v) }, uncheck: () => {}, - disabled: props.disabled, + disabled: mergedProps.disabled, }} > - {props.children} + {mergedProps.children} ) } diff --git a/src/components/radio/radio.tsx b/src/components/radio/radio.tsx index 118f131223..3b43ab4846 100644 --- a/src/components/radio/radio.tsx +++ b/src/components/radio/radio.tsx @@ -31,27 +31,27 @@ const defaultProps = { defaultChecked: false, } -export const Radio: FC = p => { - const props = mergeProps(defaultProps, p) +export const Radio: FC = props => { + const mergedProps = mergeProps(defaultProps, props) const groupContext = useContext(RadioGroupContext) let [checked, setChecked] = usePropsValue({ - value: props.checked, - defaultValue: props.defaultChecked, - onChange: props.onChange, + value: mergedProps.checked, + defaultValue: mergedProps.defaultChecked, + onChange: mergedProps.onChange, }) as [boolean, (v: boolean) => void] - let disabled = props.disabled + let disabled = mergedProps.disabled - const { value } = props + const { value } = mergedProps if (groupContext && value !== undefined) { if (isDev) { - if (p.checked !== undefined) { + if (props.checked !== undefined) { devWarning( 'Radio', 'When used within `Radio.Group`, the `checked` prop of `Radio` will not work.' ) } - if (p.defaultChecked !== undefined) { + if (props.defaultChecked !== undefined) { devWarning( 'Radio', 'When used within `Radio.Group`, the `defaultChecked` prop of `Radio` will not work.' @@ -66,16 +66,16 @@ export const Radio: FC = p => { } else { groupContext.uncheck(value) } - props.onChange?.(innerChecked) + mergedProps.onChange?.(innerChecked) } disabled = disabled || groupContext.disabled } const renderIcon = () => { - if (props.icon) { + if (mergedProps.icon) { return (
- {props.icon(checked)} + {mergedProps.icon(checked)}
) } @@ -86,13 +86,13 @@ export const Radio: FC = p => { } return withNativeProps( - props, + mergedProps, ) diff --git a/src/components/rate/rate.tsx b/src/components/rate/rate.tsx index 668a03a2a3..044c203fa1 100644 --- a/src/components/rate/rate.tsx +++ b/src/components/rate/rate.tsx @@ -1,12 +1,12 @@ -import React, { useRef } from 'react' -import type { FC, ReactNode } from 'react' +import { useDrag } from '@use-gesture/react' import classNames from 'classnames' +import type { FC, ReactNode } from 'react' +import React, { useRef } from 'react' +import { bound } from '../../utils/bound' import { NativeProps, withNativeProps } from '../../utils/native-props' -import { mergeProps } from '../../utils/with-default-props' import { usePropsValue } from '../../utils/use-props-value' +import { mergeProps } from '../../utils/with-default-props' import { Star } from './star' -import { useDrag } from '@use-gesture/react' -import { bound } from '../../utils/bound' const classPrefix = `adm-rate` @@ -35,12 +35,12 @@ const defaultProps = { allowClear: true, } -export const Rate: FC = p => { - const props = mergeProps(defaultProps, p) - const [value, setValue] = usePropsValue(props) +export const Rate: FC = props => { + const mergedProps = mergeProps(defaultProps, props) + const [value, setValue] = usePropsValue(mergedProps) const containerRef = useRef(null) - const starList = Array(props.count).fill(null) + const starList = Array(mergedProps.count).fill(null) function renderStar(v: number, half: boolean) { return ( @@ -48,20 +48,20 @@ export const Rate: FC = p => { className={classNames(`${classPrefix}-star`, { [`${classPrefix}-star-active`]: value >= v, [`${classPrefix}-star-half`]: half, - [`${classPrefix}-star-readonly`]: props.readOnly, + [`${classPrefix}-star-readonly`]: mergedProps.readOnly, })} role='radio' aria-checked={value >= v} aria-label={'' + v} > - {props.character} + {mergedProps.character}
) } const bind = useDrag( state => { - if (props.readOnly) return + if (mergedProps.readOnly) return const { xy: [clientX], tap, @@ -69,16 +69,16 @@ export const Rate: FC = p => { const container = containerRef.current if (!container) return const rect = container.getBoundingClientRect() - const rawValue = ((clientX - rect.left) / rect.width) * props.count + const rawValue = ((clientX - rect.left) / rect.width) * mergedProps.count - const ceiledValue = props.allowHalf + const ceiledValue = mergedProps.allowHalf ? Math.ceil(rawValue * 2) / 2 : Math.ceil(rawValue) - const boundValue = bound(ceiledValue, 0, props.count) + const boundValue = bound(ceiledValue, 0, mergedProps.count) if (tap) { - if (props.allowClear && boundValue === value) { + if (mergedProps.allowClear && boundValue === value) { setValue(0) return } @@ -95,19 +95,19 @@ export const Rate: FC = p => { } ) return withNativeProps( - props, + mergedProps,
{starList.map((_, i) => (
- {props.allowHalf && renderStar(i + 0.5, true)} + {mergedProps.allowHalf && renderStar(i + 0.5, true)} {renderStar(i + 1, false)}
))} diff --git a/src/components/result-page/result-page.tsx b/src/components/result-page/result-page.tsx index 71acddea86..169c0aa533 100644 --- a/src/components/result-page/result-page.tsx +++ b/src/components/result-page/result-page.tsx @@ -1,9 +1,9 @@ -import React, { useState } from 'react' -import type { FC, ReactNode } from 'react' import classNames from 'classnames' +import type { FC, ReactNode } from 'react' +import React, { useState } from 'react' +import { isNodeWithContent } from '../../utils/is-node-with-content' import { NativeProps, withNativeProps } from '../../utils/native-props' import { mergeProps } from '../../utils/with-default-props' -import { isNodeWithContent } from '../../utils/is-node-with-content' import Button from '../button' import { useResultIcon } from '../result/use-result-icon' @@ -39,8 +39,8 @@ const defaultProps = { details: [] as ResultPageDetails, } -export const ResultPage: FC = p => { - const props = mergeProps(defaultProps, p) +export const ResultPage: FC = props => { + const mergedProps = mergeProps(defaultProps, props) const { status, title, @@ -51,7 +51,7 @@ export const ResultPage: FC = p => { secondaryButtonText, onPrimaryButtonClick, onSecondaryButtonClick, - } = props + } = mergedProps const fallbackIcon = useResultIcon(status) const [collapse, setCollapse] = useState(true) @@ -60,7 +60,7 @@ export const ResultPage: FC = p => { const showPrimaryButton = isNodeWithContent(primaryButtonText) return withNativeProps( - props, + mergedProps,
{icon || fallbackIcon}
@@ -101,7 +101,7 @@ export const ResultPage: FC = p => {
-
{props.children}
+
{mergedProps.children}
{(showPrimaryButton || showSecondaryButton) && (
diff --git a/src/components/result/result.tsx b/src/components/result/result.tsx index ffe6da9d8c..9ccc3bef72 100644 --- a/src/components/result/result.tsx +++ b/src/components/result/result.tsx @@ -1,6 +1,6 @@ -import React from 'react' -import type { FC, ReactNode } from 'react' import classNames from 'classnames' +import type { FC, ReactNode } from 'react' +import React from 'react' import { NativeProps, withNativeProps } from '../../utils/native-props' import { mergeProps } from '../../utils/with-default-props' import { useResultIcon } from './use-result-icon' @@ -18,14 +18,14 @@ export type ResultProps = { icon?: ReactNode } & NativeProps -export const Result: FC = p => { - const props = mergeProps(defaultProps, p) - const { status, title, description, icon } = props +export const Result: FC = props => { + const mergedProps = mergeProps(defaultProps, props) + const { status, title, description, icon } = mergedProps const fallbackIcon = useResultIcon(status) if (!status) return null return withNativeProps( - props, + mergedProps,
{icon || fallbackIcon}
{title}
diff --git a/src/components/selector/selector.tsx b/src/components/selector/selector.tsx index 34b8740199..bc59f4079b 100644 --- a/src/components/selector/selector.tsx +++ b/src/components/selector/selector.tsx @@ -1,15 +1,15 @@ import classNames from 'classnames' -import React from 'react' import type { ReactNode } from 'react' +import React from 'react' +import type { BaseOptionType, FieldNamesType } from '../../hooks' +import { useFieldNames } from '../../hooks' import { NativeProps, withNativeProps } from '../../utils/native-props' +import { usePropsValue } from '../../utils/use-props-value' import { mergeProps } from '../../utils/with-default-props' -import Space from '../space' +import { useConfig } from '../config-provider' import Grid, { GridProps } from '../grid' -import { usePropsValue } from '../../utils/use-props-value' +import Space from '../space' import { CheckMark } from './check-mark' -import { useConfig } from '../config-provider' -import { useFieldNames } from '../../hooks' -import type { FieldNamesType, BaseOptionType } from '../../hooks' const classPrefix = `adm-selector` @@ -52,30 +52,34 @@ const defaultProps = { showCheckMark: true, } -export const Selector = (p: SelectorProps) => { - const props = mergeProps(defaultProps, p) - const [labelName, valueName, , disabledName] = useFieldNames(props.fieldNames) +export const Selector = (props: SelectorProps) => { + const mergedProps = mergeProps(defaultProps, props) + const [labelName, valueName, , disabledName] = useFieldNames( + mergedProps.fieldNames + ) const [value, setValue] = usePropsValue({ - value: props.value, - defaultValue: props.defaultValue, + value: mergedProps.value, + defaultValue: mergedProps.defaultValue, onChange: val => { const extend = { get items() { - return props.options.filter(option => val.includes(option[valueName])) + return mergedProps.options.filter(option => + val.includes(option[valueName]) + ) }, } - props.onChange?.(val, extend) + mergedProps.onChange?.(val, extend) }, }) const { locale } = useConfig() - const items = props.options.map(option => { + const items = mergedProps.options.map(option => { const active = (value || []).includes(option[valueName]) - const disabled = option[disabledName] || props.disabled + const disabled = option[disabledName] || mergedProps.disabled const itemCls = classNames(`${classPrefix}-item`, { - [`${classPrefix}-item-active`]: active && !props.multiple, - [`${classPrefix}-item-multiple-active`]: active && props.multiple, + [`${classPrefix}-item-active`]: active && !mergedProps.multiple, + [`${classPrefix}-item-multiple-active`]: active && mergedProps.multiple, [`${classPrefix}-item-disabled`]: disabled, }) @@ -87,7 +91,7 @@ export const Selector = (p: SelectorProps) => { if (disabled) { return } - if (props.multiple) { + if (mergedProps.multiple) { const val = active ? value.filter(v => v !== option[valueName]) : [...value, option[valueName]] @@ -99,7 +103,7 @@ export const Selector = (p: SelectorProps) => { }} role='option' aria-selected={ - (active && !props.multiple) || (active && props.multiple) + (active && !mergedProps.multiple) || (active && mergedProps.multiple) } > {option[labelName]} @@ -108,7 +112,7 @@ export const Selector = (p: SelectorProps) => { {option.description}
)} - {active && props.showCheckMark && ( + {active && mergedProps.showCheckMark && (
@@ -118,14 +122,14 @@ export const Selector = (p: SelectorProps) => { }) return withNativeProps( - props, + mergedProps,
- {props.columns ? ( - {items} + {mergedProps.columns ? ( + {items} ) : ( {items} )} diff --git a/src/components/skeleton/skeleton.tsx b/src/components/skeleton/skeleton.tsx index 5c08f4efbe..ed4b55d070 100644 --- a/src/components/skeleton/skeleton.tsx +++ b/src/components/skeleton/skeleton.tsx @@ -1,8 +1,8 @@ -import React from 'react' -import type { FC } from 'react' -import { NativeProps, withNativeProps } from '../../utils/native-props' import classNames from 'classnames' +import type { FC } from 'react' +import React from 'react' import { generateIntArray } from '../../utils/generate-int-array' +import { NativeProps, withNativeProps } from '../../utils/native-props' import { mergeProps } from '../../utils/with-default-props' const classPrefix = 'adm-skeleton' @@ -42,19 +42,19 @@ const defaultSkeletonParagraphProps = { lineCount: 3, } -export const SkeletonParagraph: FC = p => { - const props = mergeProps(defaultSkeletonParagraphProps, p) - const keys = generateIntArray(1, props.lineCount) +export const SkeletonParagraph: FC = props => { + const mergedProps = mergeProps(defaultSkeletonParagraphProps, props) + const keys = generateIntArray(1, mergedProps.lineCount) const node = (
{keys.map(key => ( ))}
) - return withNativeProps(props, node) + return withNativeProps(mergedProps, node) } diff --git a/src/components/slider/slider.tsx b/src/components/slider/slider.tsx index f4dadecb0c..cce504ec17 100644 --- a/src/components/slider/slider.tsx +++ b/src/components/slider/slider.tsx @@ -1,15 +1,15 @@ -import React, { useMemo, useRef } from 'react' +import getMiniDecimal, { toFixed } from '@rc-component/mini-decimal' +import classNames from 'classnames' import type { FC, ReactNode } from 'react' +import React, { useMemo, useRef } from 'react' +import { devWarning } from '../../utils/dev-log' import { NativeProps, withNativeProps } from '../../utils/native-props' -import classNames from 'classnames' -import Ticks from './ticks' -import Marks, { SliderMarks } from './marks' -import getMiniDecimal, { toFixed } from '@rc-component/mini-decimal' -import Thumb from './thumb' -import { mergeProps } from '../../utils/with-default-props' import { nearest } from '../../utils/nearest' import { usePropsValue } from '../../utils/use-props-value' -import { devWarning } from '../../utils/dev-log' +import { mergeProps } from '../../utils/with-default-props' +import Marks, { SliderMarks } from './marks' +import Thumb from './thumb' +import Ticks from './ticks' const classPrefix = `adm-slider` @@ -43,15 +43,15 @@ const defaultProps = { residentPopover: false, } -export const Slider: FC = p => { - const props = mergeProps(defaultProps, p) - const { min, max, disabled, marks, ticks, step, icon } = props +export const Slider: FC = props => { + const mergedProps = mergeProps(defaultProps, props) + const { min, max, disabled, marks, ticks, step, icon } = mergedProps function sortValue(val: [number, number]): [number, number] { return val.sort((a, b) => a - b) } function convertValue(value: SliderValue): [number, number] { - return (props.range ? value : [props.min, value]) as any + return (mergedProps.range ? value : [mergedProps.min, value]) as any } function alignValue(value: number, decimalLen: number) { const decimal = getMiniDecimal(value) @@ -66,7 +66,7 @@ export const Slider: FC = p => { getDecimalLen(value[0]), getDecimalLen(value[1]) ) - return props.range + return mergedProps.range ? (value.map(v => alignValue(v, mergedDecimalLen)) as [number, number]) : alignValue(value[1], mergedDecimalLen) } @@ -76,21 +76,22 @@ export const Slider: FC = p => { } function onAfterChange(value: [number, number]) { - props.onAfterChange?.(reverseValue(value)) + mergedProps.onAfterChange?.(reverseValue(value)) } - let propsValue: SliderValue | undefined = props.value - if (props.range && typeof props.value === 'number') { + let propsValue: SliderValue | undefined = mergedProps.value + if (mergedProps.range && typeof mergedProps.value === 'number') { devWarning( 'Slider', 'When `range` prop is enabled, the `value` prop should be an array, like: [0, 0]' ) - propsValue = [0, props.value] + propsValue = [0, mergedProps.value] } const [rawValue, setRawValue] = usePropsValue({ value: propsValue, - defaultValue: props.defaultValue ?? (props.range ? [min, min] : min), - onChange: props.onChange, + defaultValue: + mergedProps.defaultValue ?? (mergedProps.range ? [min, min] : min), + onChange: mergedProps.onChange, }) const sliderValue = sortValue(convertValue(rawValue)) @@ -160,7 +161,7 @@ export const Slider: FC = p => { const targetValue = getValueByPosition(position) let nextSliderValue: [number, number] - if (props.range) { + if (mergedProps.range) { // 移动的滑块采用就近原则 if ( Math.abs(targetValue - sliderValue[0]) > @@ -171,7 +172,7 @@ export const Slider: FC = p => { nextSliderValue = [targetValue, sliderValue[1]] } } else { - nextSliderValue = [props.min, targetValue] + nextSliderValue = [mergedProps.min, targetValue] } setSliderValue(nextSliderValue) onAfterChange(nextSliderValue) @@ -189,8 +190,8 @@ export const Slider: FC = p => { disabled={disabled} trackRef={trackRef} icon={icon} - popover={props.popover} - residentPopover={props.residentPopover} + popover={mergedProps.popover} + residentPopover={mergedProps.residentPopover} onDrag={(position, first, last) => { if (first) { dragLockRef.current += 1 @@ -209,13 +210,13 @@ export const Slider: FC = p => { }, 100) } }} - aria-label={props['aria-label']} + aria-label={mergedProps['aria-label']} /> ) } return withNativeProps( - props, + mergedProps,
= p => { left: fillStart, }} /> - {props.ticks && ( + {mergedProps.ticks && ( = p => { upperBound={sliderValue[1]} /> )} - {props.range && renderThumb(0)} + {mergedProps.range && renderThumb(0)} {renderThumb(1)}
diff --git a/src/components/space/space.tsx b/src/components/space/space.tsx index e093d99352..4f6d1186d0 100644 --- a/src/components/space/space.tsx +++ b/src/components/space/space.tsx @@ -1,6 +1,6 @@ -import React from 'react' -import type { FC, ReactNode } from 'react' import classNames from 'classnames' +import type { FC, ReactNode } from 'react' +import React from 'react' import { NativeProps, withNativeProps } from '../../utils/native-props' import { mergeProps } from '../../utils/with-default-props' @@ -27,22 +27,23 @@ const defaultProps = { direction: 'horizontal', } -export const Space: FC = p => { - const props = mergeProps(defaultProps, p) - const { direction, onClick } = props +export const Space: FC = props => { + const mergedProps = mergeProps(defaultProps, props) + const { direction, onClick } = mergedProps return withNativeProps( - props, + mergedProps,
- {React.Children.map(props.children, child => { + {React.Children.map(mergedProps.children, child => { return ( child !== null && child !== undefined && ( diff --git a/src/components/spin-loading/spin-loading.tsx b/src/components/spin-loading/spin-loading.tsx index 940ea3c11a..5ae76f7044 100644 --- a/src/components/spin-loading/spin-loading.tsx +++ b/src/components/spin-loading/spin-loading.tsx @@ -1,8 +1,8 @@ +import { animated, useSpring } from '@react-spring/web' import React, { memo } from 'react' import { NativeProps, withNativeProps } from '../../utils/native-props' -import { mergeProps } from '../../utils/with-default-props' -import { useSpring, animated } from '@react-spring/web' import { useMotionReduced } from '../../utils/reduce-and-restore-motion' +import { mergeProps } from '../../utils/with-default-props' const classPrefix = 'adm-spin-loading' @@ -22,8 +22,8 @@ const defaultProps = { const circumference = 15 * 3.14159265358979 * 2 -export const SpinLoading = memo(p => { - const props = mergeProps(defaultProps, p) +export const SpinLoading = memo(props => { + const mergedProps = mergeProps(defaultProps, props) const motionReduced = useMotionReduced() const { percent } = useSpring({ cancel: motionReduced, @@ -42,12 +42,12 @@ export const SpinLoading = memo(p => { }) return withNativeProps( - props, + mergedProps, ( - p: StepperProps, + props: StepperProps, ref: React.ForwardedRef ) { - const props = mergeProps(defaultProps, p) + const mergedProps = mergeProps(defaultProps, props) const { defaultValue = 0 as ValueType, value, @@ -110,7 +110,7 @@ export function InnerStepper( stringMode, formatter, parser, - } = props as MergedStepperProps + } = mergedProps as MergedStepperProps const { locale } = useConfig() @@ -203,7 +203,7 @@ export function InnerStepper( const valueStr = parseValue(v) if (valueStr === null) { - if (props.allowEmpty) { + if (mergedProps.allowEmpty) { setMergedValue(null) } else { setMergedValue(defaultValue) @@ -283,7 +283,7 @@ export function InnerStepper( // ============================== Render ============================== return withNativeProps( - props, + mergedProps,
( className={`${classPrefix}-input`} onFocus={e => { triggerFocus(true) - props.onFocus?.(e) + mergedProps.onFocus?.(e) }} value={inputValue} onChange={val => { @@ -315,7 +315,7 @@ export function InnerStepper( disabled={disabled} onBlur={e => { triggerFocus(false) - props.onBlur?.(e) + mergedProps.onBlur?.(e) }} readOnly={inputReadOnly} role='spinbutton' diff --git a/src/components/steps/steps.tsx b/src/components/steps/steps.tsx index c672bc3a24..629a089dd0 100644 --- a/src/components/steps/steps.tsx +++ b/src/components/steps/steps.tsx @@ -1,9 +1,9 @@ -import React from 'react' -import type { FC, ReactNode } from 'react' import classNames from 'classnames' -import type { StepProps } from './step' -import { mergeProps } from '../../utils/with-default-props' +import type { FC, ReactNode } from 'react' +import React from 'react' import { NativeProps, withNativeProps } from '../../utils/native-props' +import { mergeProps } from '../../utils/with-default-props' +import type { StepProps } from './step' const classPrefix = `adm-steps` const stepClassPrefix = `adm-step` @@ -28,15 +28,15 @@ const defaultProps = { direction: 'horizontal', } -export const Steps: FC = p => { - const props = mergeProps(defaultProps, p) - const { direction, current } = props +export const Steps: FC = props => { + const mergedProps = mergeProps(defaultProps, props) + const { direction, current } = mergedProps const classString = classNames(classPrefix, `${classPrefix}-${direction}`) return withNativeProps( - props, + mergedProps,
- {React.Children.map(props.children, (child, index) => { + {React.Children.map(mergedProps.children, (child, index) => { if (!React.isValidElement(child)) { return child } diff --git a/src/components/swipe-action/swipe-action.tsx b/src/components/swipe-action/swipe-action.tsx index d519c3db70..df26eb324d 100644 --- a/src/components/swipe-action/swipe-action.tsx +++ b/src/components/swipe-action/swipe-action.tsx @@ -1,3 +1,6 @@ +import { animated, useSpring } from '@react-spring/web' +import { useDrag } from '@use-gesture/react' +import type { ReactNode } from 'react' import React, { forwardRef, RefObject, @@ -5,17 +8,14 @@ import React, { useImperativeHandle, useRef, } from 'react' -import type { ReactNode } from 'react' -import { mergeProps } from '../../utils/with-default-props' -import { useSpring, animated } from '@react-spring/web' -import { useDrag } from '@use-gesture/react' -import Button from '../button' -import { nearest } from '../../utils/nearest' import { NativeProps, withNativeProps } from '../../utils/native-props' +import { nearest } from '../../utils/nearest' +import { mergeProps } from '../../utils/with-default-props' import { PropagationEvent, withStopPropagation, } from '../../utils/with-stop-propagation' +import Button from '../button' const classPrefix = `adm-swipe-action` @@ -61,8 +61,8 @@ const defaultProps = { } export const SwipeAction = forwardRef( - (p, ref) => { - const props = mergeProps(defaultProps, p) + (props, ref) => { + const mergedProps = mergeProps(defaultProps, props) const rootRef = useRef(null) @@ -121,7 +121,7 @@ export const SwipeAction = forwardRef( x: targetX, }) if (targetX !== 0) { - p.onActionsReveal?.(targetX > 0 ? 'left' : 'right') + props.onActionsReveal?.(targetX > 0 ? 'left' : 'right') } window.setTimeout(() => { draggingRef.current = false @@ -168,13 +168,13 @@ export const SwipeAction = forwardRef( x: getLeftWidth(), }) } - p.onActionsReveal?.(side) + props.onActionsReveal?.(side) }, close, })) useEffect(() => { - if (!props.closeOnTouchOutside) return + if (!mergedProps.closeOnTouchOutside) return function handle(e: Event) { if (x.get() === 0) { return @@ -188,7 +188,7 @@ export const SwipeAction = forwardRef( return () => { document.removeEventListener('touchstart', handle) } - }, [props.closeOnTouchOutside]) + }, [mergedProps.closeOnTouchOutside]) function renderAction(action: Action) { const color = action.color ?? 'light' @@ -200,11 +200,11 @@ export const SwipeAction = forwardRef( '--background-color': colorRecord[color] ?? color, }} onClick={e => { - if (props.closeOnAction) { + if (mergedProps.closeOnAction) { close() } action.onClick?.(e) - props.onAction?.(action, e) + mergedProps.onAction?.(action, e) }} > {action.text} @@ -213,7 +213,7 @@ export const SwipeAction = forwardRef( } return withNativeProps( - props, + mergedProps,
( > {withStopPropagation( - props.stopPropagation, + mergedProps.stopPropagation,
- {props.leftActions.map(renderAction)} + {mergedProps.leftActions.map(renderAction)}
)}
( ), }} > - {props.children} + {mergedProps.children}
{withStopPropagation( - props.stopPropagation, + mergedProps.stopPropagation,
- {props.rightActions.map(renderAction)} + {mergedProps.rightActions.map(renderAction)}
)}
diff --git a/src/components/swiper/swiper.tsx b/src/components/swiper/swiper.tsx index b7b814e665..9368a8c34d 100644 --- a/src/components/swiper/swiper.tsx +++ b/src/components/swiper/swiper.tsx @@ -1,3 +1,8 @@ +import { animated, useSpring } from '@react-spring/web' +import { useDrag } from '@use-gesture/react' +import { useGetState, useIsomorphicLayoutEffect } from 'ahooks' +import classNames from 'classnames' +import type { CSSProperties, ReactElement, ReactNode } from 'react' import React, { forwardRef, useEffect, @@ -6,20 +11,15 @@ import React, { useRef, useState, } from 'react' -import type { ReactNode, CSSProperties, ReactElement } from 'react' -import { NativeProps, withNativeProps } from '../../utils/native-props' -import { mergeProps } from '../../utils/with-default-props' -import classNames from 'classnames' -import { SwiperItem } from './swiper-item' -import { devWarning } from '../../utils/dev-log' -import { useSpring, animated } from '@react-spring/web' -import { useDrag } from '@use-gesture/react' -import PageIndicator, { PageIndicatorProps } from '../page-indicator' import { staged } from 'staged-components' -import { useRefState } from '../../utils/use-ref-state' import { bound } from '../../utils/bound' -import { useIsomorphicLayoutEffect, useGetState } from 'ahooks' +import { devWarning } from '../../utils/dev-log' +import { NativeProps, withNativeProps } from '../../utils/native-props' +import { useRefState } from '../../utils/use-ref-state' +import { mergeProps } from '../../utils/with-default-props' import { mergeFuncProps } from '../../utils/with-func-props' +import PageIndicator, { PageIndicatorProps } from '../page-indicator' +import { SwiperItem } from './swiper-item' const classPrefix = `adm-swiper` @@ -83,17 +83,17 @@ const defaultProps = { let currentUid: undefined | {} export const Swiper = forwardRef( - staged((p, ref) => { - const props = mergeProps(defaultProps, p) + staged((props, ref) => { + const mergedProps = mergeProps(defaultProps, props) - const { direction, total, children, indicator } = props + const { direction, total, children, indicator } = mergedProps const [uid] = useState({}) const timeoutRef = useRef(null) const isVertical = direction === 'vertical' - const slideRatio = props.slideSize / 100 - const offsetRatio = props.trackOffset / 100 + const slideRatio = mergedProps.slideSize / 100 + const offsetRatio = mergedProps.trackOffset / 100 const { validChildren, count, renderChildren } = useMemo(() => { let count = 0 @@ -134,7 +134,7 @@ export const Swiper = forwardRef( } return () => { - let loop = props.loop + let loop = mergedProps.loop if (slideRatio * (mergedTotal - 1) < 1) { loop = false } @@ -144,17 +144,19 @@ export const Swiper = forwardRef( const track = trackRef.current if (!track) return 0 const trackPixels = isVertical ? track.offsetHeight : track.offsetWidth - return (trackPixels * props.slideSize) / 100 + return (trackPixels * mergedProps.slideSize) / 100 } - const [current, setCurrent, getCurrent] = useGetState(props.defaultIndex) + const [current, setCurrent, getCurrent] = useGetState( + mergedProps.defaultIndex + ) const [dragging, setDragging, draggingRef] = useRefState(false) function boundIndex(current: number) { let min = 0 let max = mergedTotal - 1 - if (props.stuckAtBoundary) { + if (mergedProps.stuckAtBoundary) { min += offsetRatio / slideRatio max -= (1 - slideRatio - offsetRatio) / slideRatio } @@ -245,7 +247,7 @@ export const Swiper = forwardRef( right: upperBound, } }, - rubberband: props.rubberband, + rubberband: mergedProps.rubberband, axis: isVertical ? 'y' : 'x', preventScroll: !isVertical, pointer: { @@ -261,7 +263,7 @@ export const Swiper = forwardRef( : bound(roundedIndex, 0, mergedTotal - 1) if (targetIndex !== getCurrent()) { - props.onIndexChange?.(targetIndex) + mergedProps.onIndexChange?.(targetIndex) } setCurrent(targetIndex) @@ -293,7 +295,7 @@ export const Swiper = forwardRef( } }) - const { autoplay, autoplayInterval } = props + const { autoplay, autoplayInterval } = mergedProps const runTimeSwiper = () => { timeoutRef.current = window.setTimeout(() => { @@ -401,22 +403,22 @@ export const Swiper = forwardRef( // Render const style: CSSProperties & Record<'--slide-size' | '--track-offset', string> = { - '--slide-size': `${props.slideSize}%`, - '--track-offset': `${props.trackOffset}%`, + '--slide-size': `${mergedProps.slideSize}%`, + '--track-offset': `${mergedProps.trackOffset}%`, } - const dragProps = { ...(props.allowTouchMove ? bind() : {}) } + const dragProps = { ...(mergedProps.allowTouchMove ? bind() : {}) } const stopPropagationProps: Partial< Record, any> > = {} - for (const key of props.stopPropagation) { + for (const key of mergedProps.stopPropagation) { const prop = eventToPropRecord[key] stopPropagationProps[prop] = function (e: Event) { e.stopPropagation() } } - const mergedProps = mergeFuncProps(dragProps, stopPropagationProps) + const mergedFuncProps = mergeFuncProps(dragProps, stopPropagationProps) let indicatorNode: ReactNode = null @@ -426,7 +428,7 @@ export const Swiper = forwardRef( indicatorNode = (
( } return withNativeProps( - props, + mergedProps,
(
{ if (draggingRef.current) { @@ -452,7 +455,7 @@ export const Swiper = forwardRef( } forceCancelDrag() }} - {...mergedProps} + {...mergedFuncProps} > {renderTrackInner()}
diff --git a/src/components/switch/switch.tsx b/src/components/switch/switch.tsx index dfad26a3fb..5e33f2d54c 100644 --- a/src/components/switch/switch.tsx +++ b/src/components/switch/switch.tsx @@ -1,12 +1,12 @@ import classNames from 'classnames' -import React, { useState } from 'react' import type { FC, ReactNode } from 'react' +import React, { useState } from 'react' import { NativeProps, withNativeProps } from '../../utils/native-props' import { usePropsValue } from '../../utils/use-props-value' +import { isPromise } from '../../utils/validate' import { mergeProps } from '../../utils/with-default-props' -import { SpinIcon } from './spin-icon' import { useConfig } from '../config-provider' -import { isPromise } from '../../utils/validate' +import { SpinIcon } from './spin-icon' const classPrefix = `adm-switch` @@ -26,27 +26,27 @@ const defaultProps = { defaultChecked: false, } -export const Switch: FC = p => { - const props = mergeProps(defaultProps, p) - const disabled = props.disabled || props.loading || false +export const Switch: FC = props => { + const mergedProps = mergeProps(defaultProps, props) + const disabled = mergedProps.disabled || mergedProps.loading || false const [changing, setChanging] = useState(false) const { locale } = useConfig() const [checked, setChecked] = usePropsValue({ - value: props.checked, - defaultValue: props.defaultChecked, - onChange: props.onChange, + value: mergedProps.checked, + defaultValue: mergedProps.defaultChecked, + onChange: mergedProps.onChange, }) async function onClick() { - if (disabled || props.loading || changing) { + if (disabled || mergedProps.loading || changing) { return } const nextChecked = !checked - if (props.beforeChange) { + if (mergedProps.beforeChange) { setChanging(true) try { - await props.beforeChange(nextChecked) + await mergedProps.beforeChange(nextChecked) setChanging(false) } catch (e) { setChanging(false) @@ -67,7 +67,7 @@ export const Switch: FC = p => { } return withNativeProps( - props, + mergedProps,
= p => { >
- {(props.loading || changing) && ( + {(mergedProps.loading || changing) && ( )}
- {checked ? props.checkedText : props.uncheckedText} + {checked ? mergedProps.checkedText : mergedProps.uncheckedText}
diff --git a/src/components/tab-bar/tab-bar.tsx b/src/components/tab-bar/tab-bar.tsx index 02c3f7e56a..0f67c1c230 100644 --- a/src/components/tab-bar/tab-bar.tsx +++ b/src/components/tab-bar/tab-bar.tsx @@ -1,12 +1,12 @@ -import React, { isValidElement } from 'react' -import type { FC, ReactNode, ReactElement } from 'react' import classNames from 'classnames' +import type { FC, ReactElement, ReactNode } from 'react' +import React, { isValidElement } from 'react' import { NativeProps, withNativeProps } from '../../utils/native-props' +import { traverseReactNode } from '../../utils/traverse-react-node' +import { usePropsValue } from '../../utils/use-props-value' import { mergeProps } from '../../utils/with-default-props' import Badge, { BadgeProps } from '../badge' import SafeArea from '../safe-area' -import { usePropsValue } from '../../utils/use-props-value' -import { traverseReactNode } from '../../utils/traverse-react-node' export type TabBarItemProps = { icon?: ReactNode | ((active: boolean) => ReactNode) @@ -33,14 +33,14 @@ const defaultProps = { safeArea: false, } -export const TabBar: FC = p => { - const props = mergeProps(defaultProps, p) +export const TabBar: FC = props => { + const mergedProps = mergeProps(defaultProps, props) let firstActiveKey: string | null = null const items: ReactElement[] = [] - traverseReactNode(props.children, (child, index) => { + traverseReactNode(mergedProps.children, (child, index) => { if (!isValidElement(child)) return const key = child.key if (typeof key !== 'string') return @@ -51,16 +51,16 @@ export const TabBar: FC = p => { }) const [activeKey, setActiveKey] = usePropsValue({ - value: props.activeKey, - defaultValue: props.defaultActiveKey ?? firstActiveKey, + value: mergedProps.activeKey, + defaultValue: mergedProps.defaultActiveKey ?? firstActiveKey, onChange: v => { if (v === null) return - props.onChange?.(v) + mergedProps.onChange?.(v) }, }) return withNativeProps( - props, + mergedProps,
{items.map(item => { @@ -130,7 +130,7 @@ export const TabBar: FC = p => { })}
- {props.safeArea && } + {mergedProps.safeArea && }
) } diff --git a/src/components/tabs/tabs.tsx b/src/components/tabs/tabs.tsx index 2bd099e135..b70aebcce7 100644 --- a/src/components/tabs/tabs.tsx +++ b/src/components/tabs/tabs.tsx @@ -1,17 +1,17 @@ -import React, { isValidElement, useRef } from 'react' -import type { FC, ReactNode, ReactElement } from 'react' +import { animated, useSpring } from '@react-spring/web' +import { useIsomorphicLayoutEffect, useThrottleFn } from 'ahooks' import classNames from 'classnames' -import { useSpring, animated } from '@react-spring/web' -import { NativeProps, withNativeProps } from '../../utils/native-props' -import { usePropsValue } from '../../utils/use-props-value' +import type { FC, ReactElement, ReactNode } from 'react' +import React, { isValidElement, useRef } from 'react' import { bound } from '../../utils/bound' -import { useThrottleFn, useIsomorphicLayoutEffect } from 'ahooks' +import { NativeProps, withNativeProps } from '../../utils/native-props' +import { ShouldRender } from '../../utils/should-render' +import { traverseReactNode } from '../../utils/traverse-react-node' +import { useIsomorphicUpdateLayoutEffect } from '../../utils/use-isomorphic-update-layout-effect' import { useMutationEffect } from '../../utils/use-mutation-effect' +import { usePropsValue } from '../../utils/use-props-value' import { useResizeEffect } from '../../utils/use-resize-effect' import { mergeProps } from '../../utils/with-default-props' -import { useIsomorphicUpdateLayoutEffect } from '../../utils/use-isomorphic-update-layout-effect' -import { ShouldRender } from '../../utils/should-render' -import { traverseReactNode } from '../../utils/traverse-react-node' const classPrefix = `adm-tabs` @@ -57,8 +57,8 @@ const defaultProps = { direction: 'ltr', } -export const Tabs: FC = p => { - const props = mergeProps(defaultProps, p) +export const Tabs: FC = props => { + const mergedProps = mergeProps(defaultProps, props) const tabListContainerRef = useRef(null) const activeLineRef = useRef(null) const keyToIndexRecord: Record = {} @@ -66,9 +66,9 @@ export const Tabs: FC = p => { const panes: ReactElement[] = [] - const isRTL = props.direction === 'rtl' + const isRTL = mergedProps.direction === 'rtl' - traverseReactNode(props.children, (child, index) => { + traverseReactNode(mergedProps.children, (child, index) => { if (!isValidElement(child)) return const key = child.key @@ -81,11 +81,11 @@ export const Tabs: FC = p => { }) const [activeKey, setActiveKey] = usePropsValue({ - value: props.activeKey, - defaultValue: props.defaultActiveKey ?? firstActiveKey, + value: mergedProps.activeKey, + defaultValue: mergedProps.defaultActiveKey ?? firstActiveKey, onChange: v => { if (v === null) return - props.onChange?.(v) + mergedProps.onChange?.(v) }, }) @@ -147,10 +147,10 @@ export const Tabs: FC = p => { let x = 0 let width = 0 - if (props.activeLineMode === 'auto') { + if (mergedProps.activeLineMode === 'auto') { x = activeTabLeft width = activeTabWidth - } else if (props.activeLineMode === 'full') { + } else if (mergedProps.activeLineMode === 'full') { x = activeTabWrapperLeft width = activeTabWrapperWidth } else { @@ -162,7 +162,7 @@ export const Tabs: FC = p => { * In RTL mode, x equals the container width minus the x-coordinate of the current tab minus the width of the current tab. * https://github.com/Fog3211/reproduce-codesandbox/blob/f0a3396a114cc00e88a51a67d3be60a746519b30/assets/images/antd_mobile_tabs_rtl_x.jpg?raw=true */ - const w = ['auto', 'full'].includes(props.activeLineMode) + const w = ['auto', 'full'].includes(mergedProps.activeLineMode) ? width : activeLineWidth x = -(containerWidth - x - w) @@ -200,7 +200,7 @@ export const Tabs: FC = p => { ) } - if (!fromMutation || props.autoScroll !== false) { + if (!fromMutation || mergedProps.autoScroll !== false) { scrollApi.start({ scrollLeft: nextScrollLeft, from: { scrollLeft: containerScrollLeft }, @@ -277,11 +277,11 @@ export const Tabs: FC = p => { }, []) return withNativeProps( - props, + mergedProps,
@@ -315,7 +315,7 @@ export const Tabs: FC = p => { className={`${classPrefix}-tab-line`} style={{ width: - props.activeLineMode === 'fixed' + mergedProps.activeLineMode === 'fixed' ? 'var(--fixed-active-line-width, 30px)' : width, x, @@ -327,7 +327,7 @@ export const Tabs: FC = p => {
= p => { - const props = mergeProps(defaultProps, p) - const color = colorRecord[props.color] ?? props.color +export const Tag: FC = props => { + const mergedProps = mergeProps(defaultProps, props) + const color = colorRecord[mergedProps.color] ?? mergedProps.color const style: CSSProperties & { '--border-color': string @@ -46,19 +46,20 @@ export const Tag: FC = p => { '--background-color': string } = { '--border-color': color, - '--text-color': props.fill === 'outline' ? color : '#ffffff', - '--background-color': props.fill === 'outline' ? 'transparent' : color, + '--text-color': mergedProps.fill === 'outline' ? color : '#ffffff', + '--background-color': + mergedProps.fill === 'outline' ? 'transparent' : color, } return withNativeProps( - props, + mergedProps, - {props.children} + {mergedProps.children} ) } diff --git a/src/components/text-area/text-area.tsx b/src/components/text-area/text-area.tsx index 768a953bbb..df0b8c1cd4 100644 --- a/src/components/text-area/text-area.tsx +++ b/src/components/text-area/text-area.tsx @@ -1,12 +1,12 @@ -import React, { forwardRef, useImperativeHandle, useRef } from 'react' -import type { ReactNode } from 'react' import { useIsomorphicLayoutEffect } from 'ahooks' +import type { ReactNode } from 'react' +import React, { forwardRef, useImperativeHandle, useRef } from 'react' import runes from 'runes2' +import useInputHandleKeyDown from '../../components/input/useInputHandleKeyDown' +import { devError } from '../../utils/dev-log' import { NativeProps, withNativeProps } from '../../utils/native-props' import { usePropsValue } from '../../utils/use-props-value' import { mergeProps } from '../../utils/with-default-props' -import { devError } from '../../utils/dev-log' -import useInputHandleKeyDown from '../../components/input/useInputHandleKeyDown' const classPrefix = 'adm-text-area' @@ -74,14 +74,14 @@ const defaultProps = { } export const TextArea = forwardRef( - (p: TextAreaProps, ref) => { - const props = mergeProps(defaultProps, p) - const { autoSize, showCount, maxLength } = props + (props: TextAreaProps, ref) => { + const mergedProps = mergeProps(defaultProps, props) + const { autoSize, showCount, maxLength } = mergedProps const [value, setValue] = usePropsValue({ - ...props, - value: props.value === null ? '' : props.value, + ...mergedProps, + value: mergedProps.value === null ? '' : mergedProps.value, }) - if (props.value === null) { + if (mergedProps.value === null) { devError( 'TextArea', '`value` prop on `TextArea` should not be `null`. Consider using an empty string to clear the component.' @@ -94,10 +94,10 @@ export const TextArea = forwardRef( const hiddenTextAreaRef = useRef(null) const handleKeydown = useInputHandleKeyDown({ - onEnterPress: props.onEnterPress, - onKeyDown: props.onKeyDown, + onEnterPress: mergedProps.onEnterPress, + onKeyDown: mergedProps.onKeyDown, nativeInputRef: nativeTextAreaRef, - enterKeyHint: props.enterKeyHint, + enterKeyHint: mergedProps.enterKeyHint, }) useImperativeHandle(ref, () => ({ @@ -153,7 +153,7 @@ export const TextArea = forwardRef( ) } - let rows = props.rows + let rows = mergedProps.rows if (typeof autoSize === 'object') { if (autoSize.maxRows && rows > autoSize.maxRows) { rows = autoSize.maxRows @@ -164,14 +164,14 @@ export const TextArea = forwardRef( } return withNativeProps( - props, + mergedProps,