From 0ed3c173a6542e8834f6cd14871be5a875f94926 Mon Sep 17 00:00:00 2001 From: aelf-lxy Date: Mon, 25 Mar 2024 18:17:45 +0800 Subject: [PATCH] feat: add forwardRef for component --- packages/component/src/Address/index.tsx | 113 ++++++++++++---------- packages/component/src/Button/index.tsx | 51 ++++++---- packages/component/src/Carousel/index.tsx | 13 ++- packages/component/src/Collapse/index.tsx | 36 ++++--- packages/component/src/Dropdown/index.tsx | 8 +- packages/component/src/Input/index.tsx | 71 +++++++------- packages/component/src/Loading/index.tsx | 8 +- packages/component/src/Radio/index.tsx | 20 +++- 8 files changed, 187 insertions(+), 133 deletions(-) diff --git a/packages/component/src/Address/index.tsx b/packages/component/src/Address/index.tsx index 22abc96..c8e5be7 100644 --- a/packages/component/src/Address/index.tsx +++ b/packages/component/src/Address/index.tsx @@ -1,4 +1,4 @@ -import React, { memo } from 'react'; +import React, { forwardRef } from 'react'; import Copy from './copy'; import useStyles from './style'; @@ -59,59 +59,68 @@ const getOmittedStr = (str: string, preLen?: number, endLen?: number) => { return `${str.slice(0, preLen)}...${str.slice(-endLen)}`; }; -function Address({ - address, - chain = 'AELF', - preLen = 0, - endLen = 0, - hasCopy = true, - addressClickCallback, - className, - size = 'default', - ignorePrefixSuffix = false, - ignoreEvent = false, - primaryLinkColor, - primaryIconColor, - addressHoverColor, - addressActiveColor, -}: IHashAddressProps) { - const { - styles: st, - cx, - prefixCls, - } = useStyles({ - size, - ignoreEvent, - primaryLinkColor, - primaryIconColor, - addressHoverColor, - addressActiveColor, - }); +const Address = forwardRef( + ( + { + address, + chain = 'AELF', + preLen = 0, + endLen = 0, + hasCopy = true, + addressClickCallback, + className, + size = 'default', + ignorePrefixSuffix = false, + ignoreEvent = false, + primaryLinkColor, + primaryIconColor, + addressHoverColor, + addressActiveColor, + }: IHashAddressProps, + ref, + ) => { + const { + styles: st, + cx, + prefixCls, + } = useStyles({ + size, + ignoreEvent, + primaryLinkColor, + primaryIconColor, + addressHoverColor, + addressActiveColor, + }); - const addPrefixSuffixTxt = ignorePrefixSuffix ? address : addPrefixSuffix(address, chain); - const omittedStr = getOmittedStr(addPrefixSuffixTxt, preLen, endLen); + const addPrefixSuffixTxt = ignorePrefixSuffix ? address : addPrefixSuffix(address, chain); + const omittedStr = getOmittedStr(addPrefixSuffixTxt, preLen, endLen); - const addressClickHandler = (e: React.MouseEvent) => { - if (ignoreEvent) { - return; - } - if (addressClickCallback) { - addressClickCallback(address, addPrefixSuffixTxt, e); - } - }; + const addressClickHandler = (e: React.MouseEvent) => { + if (ignoreEvent) { + return; + } + if (addressClickCallback) { + addressClickCallback(address, addPrefixSuffixTxt, e); + } + }; - return ( -
- - {omittedStr} - - {hasCopy && ( -
- -
- )} -
- ); + return ( +
+ + {omittedStr} + + {hasCopy && ( +
+ +
+ )} +
+ ); + }, +); + +if (process.env.NODE_ENV !== 'production') { + Address.displayName = 'Address'; } -export default memo(Address); +export default Address; diff --git a/packages/component/src/Button/index.tsx b/packages/component/src/Button/index.tsx index b92cd53..a8285a4 100644 --- a/packages/component/src/Button/index.tsx +++ b/packages/component/src/Button/index.tsx @@ -1,4 +1,4 @@ -import React, { MouseEvent } from 'react'; +import React, { forwardRef, MouseEvent } from 'react'; import { Button as AntdButton, ButtonProps } from 'antd'; import { debounce } from 'lodash-es'; @@ -11,26 +11,37 @@ export interface IButtonProps extends Omit { millisecondOfDebounce?: number; } -function Button({ size = 'large', className, millisecondOfDebounce = 0, ...rest }: IButtonProps) { - const { styles: st, cx } = useStyles({ size }); +const Button = forwardRef( + ({ size = 'large', className, millisecondOfDebounce = 0, ...rest }: IButtonProps, ref) => { + const { styles: st, cx } = useStyles({ size }); - const buttonClickHandler = debounce( - (e: MouseEvent) => { - if (rest.onClick) { - rest.onClick(e); - } - }, - millisecondOfDebounce, - { - leading: false, - trailing: true, - }, - ); - return ( - - {rest.children} - - ); + const buttonClickHandler = debounce( + (e: MouseEvent) => { + if (rest.onClick) { + rest.onClick(e); + } + }, + millisecondOfDebounce, + { + leading: false, + trailing: true, + }, + ); + return ( + + {rest.children} + + ); + }, +); + +if (process.env.NODE_ENV !== 'production') { + Button.displayName = 'Button'; } export default Button; diff --git a/packages/component/src/Carousel/index.tsx b/packages/component/src/Carousel/index.tsx index 51fdb3f..5914f85 100644 --- a/packages/component/src/Carousel/index.tsx +++ b/packages/component/src/Carousel/index.tsx @@ -1,8 +1,8 @@ -import React, { SetStateAction, useState } from 'react'; +import React, { forwardRef, SetStateAction, useState } from 'react'; import { NextButtonIcon, PrevButtonIcon } from '@aelf-design/internal-icons'; import { useResponsive, useTheme } from 'antd-style'; import { FreeMode, Navigation, Thumbs } from 'swiper/modules'; -import { Swiper, SwiperSlide } from 'swiper/react'; +import { Swiper, SwiperRef, SwiperSlide } from 'swiper/react'; import useStyles from './styles'; @@ -23,7 +23,7 @@ export interface ICarouselProps { onSlideClick?: (value: ICarouselSlideItem) => void; } -export default function Carousel(props: ICarouselProps) { +const Carousel = forwardRef((props: ICarouselProps, ref) => { const [thumbsSwiper, setThumbsSwiper] = useState(null); const { data, @@ -60,6 +60,7 @@ export default function Carousel(props: ICarouselProps) { thumbs={{ swiper: thumbsSwiper }} modules={[FreeMode, Navigation, Thumbs]} className="swiper-gallery" + ref={ref} > {data.map((item, index) => { return ( @@ -121,4 +122,10 @@ export default function Carousel(props: ICarouselProps) { ); +}); + +if (process.env.NODE_ENV !== 'production') { + Carousel.displayName = 'Carousel'; } + +export default Carousel; diff --git a/packages/component/src/Collapse/index.tsx b/packages/component/src/Collapse/index.tsx index 3797fc8..817a597 100644 --- a/packages/component/src/Collapse/index.tsx +++ b/packages/component/src/Collapse/index.tsx @@ -1,4 +1,4 @@ -import React from 'react'; +import React, { forwardRef } from 'react'; import { DownOutlined } from '@aelf-design/internal-icons'; import { Collapse as AntdCollapse, CollapseProps } from 'antd'; @@ -8,17 +8,31 @@ export interface ICollapseProps extends Omit } - expandIconPosition={'end'} - className={cx(st.aelfdCollapse, className)} - /> - ); +const InternalCollapse = forwardRef( + ({ className, ...rest }: ICollapseProps, ref) => { + const { styles: st, cx } = useStyles(); + return ( + } + expandIconPosition={'end'} + className={cx(st.aelfdCollapse, className)} + ref={ref} + /> + ); + }, +); + +if (process.env.NODE_ENV !== 'production') { + InternalCollapse.displayName = 'Collapse'; } +type ComputedCollapse = typeof InternalCollapse & { + Panel: typeof AntdCollapse.Panel; +}; + +const Collapse = InternalCollapse as ComputedCollapse; + Collapse.Panel = AntdCollapse.Panel; + export default Collapse; diff --git a/packages/component/src/Dropdown/index.tsx b/packages/component/src/Dropdown/index.tsx index 0e5c5d6..84da0a4 100644 --- a/packages/component/src/Dropdown/index.tsx +++ b/packages/component/src/Dropdown/index.tsx @@ -1,4 +1,4 @@ -import React from 'react'; +import React, { forwardRef } from 'react'; import { Dropdown as AntdDropdown, DropdownProps } from 'antd'; import useStyles from './style'; @@ -11,19 +11,19 @@ export interface IDropdownProps extends Omit offsetY?: number; } -function Dropdown({ +const Dropdown = ({ children, size = 'default', offsetX = 0, offsetY = 0, ...props -}: IDropdownProps) { +}: IDropdownProps) => { const { styles, cx } = useStyles({ size, offsetX, offsetY }); return ( {children} ); -} +}; export default Dropdown; diff --git a/packages/component/src/Input/index.tsx b/packages/component/src/Input/index.tsx index a773024..ea30826 100644 --- a/packages/component/src/Input/index.tsx +++ b/packages/component/src/Input/index.tsx @@ -1,11 +1,11 @@ -import React, { ReactNode } from 'react'; +import React, { forwardRef, ReactNode, Ref } from 'react'; import { CloseFilled, EyeInvisibleOutlined, EyeOutlined, IconProps, } from '@aelf-design/internal-icons'; -import { Input as AntdInput, InputProps } from 'antd'; +import { Input as AntdInput, InputProps, InputRef } from 'antd'; import { Theme, useTheme } from 'antd-style'; import { OverrideToken } from 'antd/es/theme/interface'; import type { PasswordProps, TextAreaProps } from 'antd/lib/input'; @@ -50,27 +50,30 @@ const getClearIcon = ( ); }; -const Input = ({ size = 'middle', className, onClear, allowClear, ...rest }: IInputProps) => { - const { styles: st } = useStyles({ size }); - const token = useTheme(); +const InternalInput = forwardRef( + ({ size = 'middle', className, onClear, allowClear, ...rest }: IInputProps, ref) => { + const { styles: st } = useStyles({ size }); + const token = useTheme(); - return ( - - ); -}; + return ( + + ); + }, +); function InputPassword({ size = 'middle', @@ -118,20 +121,18 @@ function InputTextArea({ size = 'middle', className, ...rest }: InputTextAreaPro ); } +if (process.env.NODE_ENV !== 'production') { + InternalInput.displayName = 'Input'; +} + +type CompoundedInput = typeof InternalInput & { + Password: typeof InputPassword; + TextArea: typeof InputTextArea; +}; + +const Input = InternalInput as CompoundedInput; + Input.Password = InputPassword; Input.TextArea = InputTextArea; -// function TestIcon() { -// const token = useTheme(); -// return ( -// -// ); -// } -// Input.TestIcon = TestIcon; export default Input; diff --git a/packages/component/src/Loading/index.tsx b/packages/component/src/Loading/index.tsx index c8d4601..532bb6c 100644 --- a/packages/component/src/Loading/index.tsx +++ b/packages/component/src/Loading/index.tsx @@ -1,4 +1,4 @@ -import React, { memo } from 'react'; +import React from 'react'; import Modal from '../Modal'; import useStyles from './style'; @@ -8,7 +8,7 @@ export interface ILoadingProps { content?: string | React.ReactNode; width?: number | string; } -function Loading({ open, content = 'loading...', width = 240 }: ILoadingProps) { +const Loading = ({ open, content = 'loading...', width = 240 }: ILoadingProps) => { const { styles, prefixCls } = useStyles(); return ( ); -} +}; -export default memo(Loading); +export default Loading; diff --git a/packages/component/src/Radio/index.tsx b/packages/component/src/Radio/index.tsx index 90b4562..6d5e7c3 100644 --- a/packages/component/src/Radio/index.tsx +++ b/packages/component/src/Radio/index.tsx @@ -1,14 +1,26 @@ -import React from 'react'; -import { Radio as AntdRadio, RadioProps } from 'antd'; +import React, { forwardRef } from 'react'; +import { Radio as AntdRadio, CheckboxRef, RadioProps } from 'antd'; import useStyles from './style'; export interface IRadioProps extends RadioProps {} -function Radio(props: IRadioProps) { +const InternalRadio = forwardRef((props: IRadioProps, ref) => { const { styles, cx, prefixCls } = useStyles(); - return ; + return ( + + ); +}); + +if (process.env.NODE_ENV !== 'production') { + InternalRadio.displayName = 'Radio'; } +type computedRadio = typeof InternalRadio & { + Button: typeof AntdRadio.Button; + Group: typeof AntdRadio.Group; +}; +const Radio = InternalRadio as computedRadio; + Radio.Button = AntdRadio.Button; Radio.Group = AntdRadio.Group;