Refactor:upgrade react19 ref as props (#25225)

Co-authored-by: crazywoola <100913391+crazywoola@users.noreply.github.com>
This commit is contained in:
zyileven
2025-09-08 09:46:02 +08:00
committed by GitHub
parent 27bf244b3b
commit 98204d78fb
8 changed files with 83 additions and 78 deletions

View File

@@ -32,6 +32,7 @@ export type ActionButtonProps = {
size?: 'xs' | 's' | 'm' | 'l' | 'xl' size?: 'xs' | 's' | 'm' | 'l' | 'xl'
state?: ActionButtonState state?: ActionButtonState
styleCss?: CSSProperties styleCss?: CSSProperties
ref?: React.Ref<HTMLButtonElement>
} & React.ButtonHTMLAttributes<HTMLButtonElement> & VariantProps<typeof actionButtonVariants> } & React.ButtonHTMLAttributes<HTMLButtonElement> & VariantProps<typeof actionButtonVariants>
function getActionButtonState(state: ActionButtonState) { function getActionButtonState(state: ActionButtonState) {
@@ -49,24 +50,22 @@ function getActionButtonState(state: ActionButtonState) {
} }
} }
const ActionButton = React.forwardRef<HTMLButtonElement, ActionButtonProps>( const ActionButton = ({ className, size, state = ActionButtonState.Default, styleCss, children, ref, ...props }: ActionButtonProps) => {
({ className, size, state = ActionButtonState.Default, styleCss, children, ...props }, ref) => { return (
return ( <button
<button type='button'
type='button' className={classNames(
className={classNames( actionButtonVariants({ className, size }),
actionButtonVariants({ className, size }), getActionButtonState(state),
getActionButtonState(state), )}
)} ref={ref}
ref={ref} style={styleCss}
style={styleCss} {...props}
{...props} >
> {children}
{children} </button>
</button> )
) }
},
)
ActionButton.displayName = 'ActionButton' ActionButton.displayName = 'ActionButton'
export default ActionButton export default ActionButton

View File

@@ -35,27 +35,26 @@ export type ButtonProps = {
loading?: boolean loading?: boolean
styleCss?: CSSProperties styleCss?: CSSProperties
spinnerClassName?: string spinnerClassName?: string
ref?: React.Ref<HTMLButtonElement>
} & React.ButtonHTMLAttributes<HTMLButtonElement> & VariantProps<typeof buttonVariants> } & React.ButtonHTMLAttributes<HTMLButtonElement> & VariantProps<typeof buttonVariants>
const Button = React.forwardRef<HTMLButtonElement, ButtonProps>( const Button = ({ className, variant, size, destructive, loading, styleCss, children, spinnerClassName, ref, ...props }: ButtonProps) => {
({ className, variant, size, destructive, loading, styleCss, children, spinnerClassName, ...props }, ref) => { return (
return ( <button
<button type='button'
type='button' className={classNames(
className={classNames( buttonVariants({ variant, size, className }),
buttonVariants({ variant, size, className }), destructive && 'btn-destructive',
destructive && 'btn-destructive', )}
)} ref={ref}
ref={ref} style={styleCss}
style={styleCss} {...props}
{...props} >
> {children}
{children} {loading && <Spinner loading={loading} className={classNames('!ml-1 !h-3 !w-3 !border-2 !text-white', spinnerClassName)} />}
{loading && <Spinner loading={loading} className={classNames('!ml-1 !h-3 !w-3 !border-2 !text-white', spinnerClassName)} />} </button>
</button> )
) }
},
)
Button.displayName = 'Button' Button.displayName = 'Button'
export default Button export default Button

View File

@@ -30,9 +30,10 @@ export type InputProps = {
wrapperClassName?: string wrapperClassName?: string
styleCss?: CSSProperties styleCss?: CSSProperties
unit?: string unit?: string
ref?: React.Ref<HTMLInputElement>
} & Omit<React.InputHTMLAttributes<HTMLInputElement>, 'size'> & VariantProps<typeof inputVariants> } & Omit<React.InputHTMLAttributes<HTMLInputElement>, 'size'> & VariantProps<typeof inputVariants>
const Input = React.forwardRef<HTMLInputElement, InputProps>(({ const Input = ({
size, size,
disabled, disabled,
destructive, destructive,
@@ -46,8 +47,9 @@ const Input = React.forwardRef<HTMLInputElement, InputProps>(({
placeholder, placeholder,
onChange = noop, onChange = noop,
unit, unit,
ref,
...props ...props
}, ref) => { }: InputProps) => {
const { t } = useTranslation() const { t } = useTranslation()
return ( return (
<div className={cn('relative w-full', wrapperClassName)}> <div className={cn('relative w-full', wrapperClassName)}>
@@ -93,7 +95,7 @@ const Input = React.forwardRef<HTMLInputElement, InputProps>(({
} }
</div> </div>
) )
}) }
Input.displayName = 'Input' Input.displayName = 'Input'

View File

@@ -107,10 +107,13 @@ const initMermaid = () => {
return isMermaidInitialized return isMermaidInitialized
} }
const Flowchart = React.forwardRef((props: { type FlowchartProps = {
PrimitiveCode: string PrimitiveCode: string
theme?: 'light' | 'dark' theme?: 'light' | 'dark'
}, ref) => { ref?: React.Ref<HTMLDivElement>
}
const Flowchart = (props: FlowchartProps) => {
const { t } = useTranslation() const { t } = useTranslation()
const [svgString, setSvgString] = useState<string | null>(null) const [svgString, setSvgString] = useState<string | null>(null)
const [look, setLook] = useState<'classic' | 'handDrawn'>('classic') const [look, setLook] = useState<'classic' | 'handDrawn'>('classic')
@@ -490,7 +493,7 @@ const Flowchart = React.forwardRef((props: {
} }
return ( return (
<div ref={ref as React.RefObject<HTMLDivElement>} className={themeClasses.container}> <div ref={props.ref as React.RefObject<HTMLDivElement>} className={themeClasses.container}>
<div className={themeClasses.segmented}> <div className={themeClasses.segmented}>
<div className="msh-segmented-group"> <div className="msh-segmented-group">
<label className="msh-segmented-item m-2 flex w-[200px] items-center space-x-1"> <label className="msh-segmented-item m-2 flex w-[200px] items-center space-x-1">
@@ -572,7 +575,7 @@ const Flowchart = React.forwardRef((props: {
)} )}
</div> </div>
) )
}) }
Flowchart.displayName = 'Flowchart' Flowchart.displayName = 'Flowchart'

View File

@@ -24,30 +24,29 @@ export type TextareaProps = {
disabled?: boolean disabled?: boolean
destructive?: boolean destructive?: boolean
styleCss?: CSSProperties styleCss?: CSSProperties
ref?: React.Ref<HTMLTextAreaElement>
} & React.TextareaHTMLAttributes<HTMLTextAreaElement> & VariantProps<typeof textareaVariants> } & React.TextareaHTMLAttributes<HTMLTextAreaElement> & VariantProps<typeof textareaVariants>
const Textarea = React.forwardRef<HTMLTextAreaElement, TextareaProps>( const Textarea = ({ className, value, onChange, disabled, size, destructive, styleCss, ref, ...props }: TextareaProps) => {
({ className, value, onChange, disabled, size, destructive, styleCss, ...props }, ref) => { return (
return ( <textarea
<textarea ref={ref}
ref={ref} style={styleCss}
style={styleCss} className={cn(
className={cn( 'min-h-20 w-full appearance-none border border-transparent bg-components-input-bg-normal p-2 text-components-input-text-filled caret-primary-600 outline-none placeholder:text-components-input-text-placeholder hover:border-components-input-border-hover hover:bg-components-input-bg-hover focus:border-components-input-border-active focus:bg-components-input-bg-active focus:shadow-xs',
'min-h-20 w-full appearance-none border border-transparent bg-components-input-bg-normal p-2 text-components-input-text-filled caret-primary-600 outline-none placeholder:text-components-input-text-placeholder hover:border-components-input-border-hover hover:bg-components-input-bg-hover focus:border-components-input-border-active focus:bg-components-input-bg-active focus:shadow-xs', textareaVariants({ size }),
textareaVariants({ size }), disabled && 'cursor-not-allowed border-transparent bg-components-input-bg-disabled text-components-input-text-filled-disabled hover:border-transparent hover:bg-components-input-bg-disabled',
disabled && 'cursor-not-allowed border-transparent bg-components-input-bg-disabled text-components-input-text-filled-disabled hover:border-transparent hover:bg-components-input-bg-disabled', destructive && 'border-components-input-border-destructive bg-components-input-bg-destructive text-components-input-text-filled hover:border-components-input-border-destructive hover:bg-components-input-bg-destructive focus:border-components-input-border-destructive focus:bg-components-input-bg-destructive',
destructive && 'border-components-input-border-destructive bg-components-input-bg-destructive text-components-input-text-filled hover:border-components-input-border-destructive hover:bg-components-input-bg-destructive focus:border-components-input-border-destructive focus:bg-components-input-bg-destructive', className,
className, )}
)} value={value ?? ''}
value={value ?? ''} onChange={onChange}
onChange={onChange} disabled={disabled}
disabled={disabled} {...props}
{...props} >
> </textarea>
</textarea> )
) }
},
)
Textarea.displayName = 'Textarea' Textarea.displayName = 'Textarea'
export default Textarea export default Textarea

View File

@@ -1,14 +1,14 @@
import type { ComponentProps, FC, ReactNode } from 'react' import type { ComponentProps, FC, ReactNode } from 'react'
import { forwardRef } from 'react'
import classNames from '@/utils/classnames' import classNames from '@/utils/classnames'
export type PreviewContainerProps = ComponentProps<'div'> & { export type PreviewContainerProps = ComponentProps<'div'> & {
header: ReactNode header: ReactNode
mainClassName?: string mainClassName?: string
ref?: React.Ref<HTMLDivElement>
} }
export const PreviewContainer: FC<PreviewContainerProps> = forwardRef((props, ref) => { export const PreviewContainer: FC<PreviewContainerProps> = (props) => {
const { children, className, header, mainClassName, ...rest } = props const { children, className, header, mainClassName, ref, ...rest } = props
return <div className={className}> return <div className={className}>
<div <div
{...rest} {...rest}
@@ -25,5 +25,5 @@ export const PreviewContainer: FC<PreviewContainerProps> = forwardRef((props, re
</main> </main>
</div> </div>
</div> </div>
}) }
PreviewContainer.displayName = 'PreviewContainer' PreviewContainer.displayName = 'PreviewContainer'

View File

@@ -1,5 +1,4 @@
'use client' 'use client'
import type { ForwardRefRenderFunction } from 'react'
import { useImperativeHandle } from 'react' import { useImperativeHandle } from 'react'
import React, { useCallback, useEffect, useMemo, useState } from 'react' import React, { useCallback, useEffect, useMemo, useState } from 'react'
import type { Dependency, GitHubItemAndMarketPlaceDependency, PackageDependency, Plugin, VersionInfo } from '../../../types' import type { Dependency, GitHubItemAndMarketPlaceDependency, PackageDependency, Plugin, VersionInfo } from '../../../types'
@@ -21,6 +20,7 @@ type Props = {
onDeSelectAll: () => void onDeSelectAll: () => void
onLoadedAllPlugin: (installedInfo: Record<string, VersionInfo>) => void onLoadedAllPlugin: (installedInfo: Record<string, VersionInfo>) => void
isFromMarketPlace?: boolean isFromMarketPlace?: boolean
ref?: React.Ref<ExposeRefs>
} }
export type ExposeRefs = { export type ExposeRefs = {
@@ -28,7 +28,7 @@ export type ExposeRefs = {
deSelectAllPlugins: () => void deSelectAllPlugins: () => void
} }
const InstallByDSLList: ForwardRefRenderFunction<ExposeRefs, Props> = ({ const InstallByDSLList = ({
allPlugins, allPlugins,
selectedPlugins, selectedPlugins,
onSelect, onSelect,
@@ -36,7 +36,8 @@ const InstallByDSLList: ForwardRefRenderFunction<ExposeRefs, Props> = ({
onDeSelectAll, onDeSelectAll,
onLoadedAllPlugin, onLoadedAllPlugin,
isFromMarketPlace, isFromMarketPlace,
}, ref) => { ref,
}: Props) => {
const systemFeatures = useGlobalPublicStore(s => s.systemFeatures) const systemFeatures = useGlobalPublicStore(s => s.systemFeatures)
// DSL has id, to get plugin info to show more info // DSL has id, to get plugin info to show more info
const { isLoading: isFetchingMarketplaceDataById, data: infoGetById, error: infoByIdError } = useFetchPluginsInMarketPlaceByInfo(allPlugins.filter(d => d.type === 'marketplace').map((d) => { const { isLoading: isFetchingMarketplaceDataById, data: infoGetById, error: infoByIdError } = useFetchPluginsInMarketPlaceByInfo(allPlugins.filter(d => d.type === 'marketplace').map((d) => {
@@ -268,4 +269,4 @@ const InstallByDSLList: ForwardRefRenderFunction<ExposeRefs, Props> = ({
</> </>
) )
} }
export default React.forwardRef(InstallByDSLList) export default InstallByDSLList

View File

@@ -1,5 +1,5 @@
'use client' 'use client'
import React, { forwardRef, useEffect, useImperativeHandle, useMemo, useRef } from 'react' import React, { useEffect, useImperativeHandle, useMemo, useRef } from 'react'
import { useTranslation } from 'react-i18next' import { useTranslation } from 'react-i18next'
import useStickyScroll, { ScrollPosition } from '../use-sticky-scroll' import useStickyScroll, { ScrollPosition } from '../use-sticky-scroll'
import Item from './item' import Item from './item'
@@ -17,18 +17,20 @@ export type ListProps = {
tags: string[] tags: string[]
toolContentClassName?: string toolContentClassName?: string
disableMaxWidth?: boolean disableMaxWidth?: boolean
ref?: React.Ref<ListRef>
} }
export type ListRef = { handleScroll: () => void } export type ListRef = { handleScroll: () => void }
const List = forwardRef<ListRef, ListProps>(({ const List = ({
wrapElemRef, wrapElemRef,
searchText, searchText,
tags, tags,
list, list,
toolContentClassName, toolContentClassName,
disableMaxWidth = false, disableMaxWidth = false,
}, ref) => { ref,
}: ListProps) => {
const { t } = useTranslation() const { t } = useTranslation()
const hasFilter = !searchText const hasFilter = !searchText
const hasRes = list.length > 0 const hasRes = list.length > 0
@@ -125,7 +127,7 @@ const List = forwardRef<ListRef, ListProps>(({
</div> </div>
</> </>
) )
}) }
List.displayName = 'List' List.displayName = 'List'