1- import { forwardRef , type ReactNode } from 'react' ;
1+ import type { ComponentPropsWithoutRef , ElementType , ForwardedRef } from 'react' ;
2+ import { type ReactNode } from 'react' ;
23import { twMerge } from 'tailwind-merge' ;
4+ import genericForwardRef from '~/src/helpers/generic-forward-ref' ;
35import type {
46 DeepPartial ,
57 FlowbiteBoolean ,
@@ -64,7 +66,9 @@ export interface ButtonSizes extends Pick<FlowbiteSizes, 'xs' | 'sm' | 'lg' | 'x
6466 [ key : string ] : string ;
6567}
6668
67- export interface ButtonProps extends ButtonBaseProps {
69+ export type ButtonProps < T extends ElementType = 'button' > = {
70+ as ?: T ;
71+ href ?: string ;
6872 color ?: keyof FlowbiteColors ;
6973 fullSized ?: boolean ;
7074 gradientDuoTone ?: keyof ButtonGradientDuoToneColors ;
@@ -79,88 +83,85 @@ export interface ButtonProps extends ButtonBaseProps {
7983 positionInGroup ?: keyof PositionInButtonGroup ;
8084 size ?: keyof ButtonSizes ;
8185 theme ?: DeepPartial < FlowbiteButtonTheme > ;
82- }
83-
84- interface Props extends ButtonProps , Record < string , unknown > { }
86+ } & ComponentPropsWithoutRef < T > ;
8587
86- const ButtonComponent = forwardRef < HTMLButtonElement | HTMLAnchorElement , Props > (
87- (
88- {
89- children,
90- className,
91- color = 'info' ,
92- disabled = false ,
93- fullSized,
94- isProcessing = false ,
95- processingLabel = 'Loading...' ,
96- processingSpinner,
97- gradientDuoTone,
98- gradientMonochrome,
99- label,
100- outline = false ,
101- pill = false ,
102- positionInGroup = 'none' ,
103- size = 'md' ,
104- theme : customTheme = { } ,
105- ...props
106- } ,
107- ref ,
108- ) => {
109- const { buttonGroup : groupTheme , button : buttonTheme } = useTheme ( ) . theme ;
110- const theme = mergeDeep ( buttonTheme , customTheme ) ;
88+ const ButtonComponentFn = < T extends ElementType = 'button' > (
89+ {
90+ children,
91+ className,
92+ color = 'info' ,
93+ disabled,
94+ fullSized,
95+ isProcessing = false ,
96+ processingLabel = 'Loading...' ,
97+ processingSpinner,
98+ gradientDuoTone,
99+ gradientMonochrome,
100+ label,
101+ outline = false ,
102+ pill = false ,
103+ positionInGroup = 'none' ,
104+ size = 'md' ,
105+ theme : customTheme = { } ,
106+ ...props
107+ } : ButtonProps < T > ,
108+ ref : ForwardedRef < T > ,
109+ ) => {
110+ const { buttonGroup : groupTheme , button : buttonTheme } = useTheme ( ) . theme ;
111+ const theme = mergeDeep ( buttonTheme , customTheme ) ;
111112
112- const theirProps = props as object ;
113+ const theirProps = props as ButtonBaseProps < T > ;
113114
114- return (
115- < ButtonBase
116- disabled = { disabled }
117- ref = { ref as never }
115+ return (
116+ < ButtonBase
117+ ref = { ref }
118+ disabled = { disabled }
119+ className = { twMerge (
120+ theme . base ,
121+ disabled && theme . disabled ,
122+ ! gradientDuoTone && ! gradientMonochrome && theme . color [ color ] ,
123+ gradientDuoTone && ! gradientMonochrome && theme . gradientDuoTone [ gradientDuoTone ] ,
124+ ! gradientDuoTone && gradientMonochrome && theme . gradient [ gradientMonochrome ] ,
125+ outline && ( theme . outline . color [ color ] ?? theme . outline . color . default ) ,
126+ theme . pill [ pill ? 'on' : 'off' ] ,
127+ fullSized && theme . fullSized ,
128+ groupTheme . position [ positionInGroup ] ,
129+ className ,
130+ ) }
131+ { ...theirProps }
132+ >
133+ < span
118134 className = { twMerge (
119- theme . base ,
120- disabled && theme . disabled ,
121- ! gradientDuoTone && ! gradientMonochrome && theme . color [ color ] ,
122- gradientDuoTone && ! gradientMonochrome && theme . gradientDuoTone [ gradientDuoTone ] ,
123- ! gradientDuoTone && gradientMonochrome && theme . gradient [ gradientMonochrome ] ,
124- outline && ( theme . outline . color [ color ] ?? theme . outline . color . default ) ,
125- theme . pill [ pill ? 'on' : 'off' ] ,
126- fullSized && theme . fullSized ,
127- groupTheme . position [ positionInGroup ] ,
128- className ,
135+ theme . inner . base ,
136+ theme . outline [ outline ? 'on' : 'off' ] ,
137+ theme . outline . pill [ outline && pill ? 'on' : 'off' ] ,
138+ theme . size [ size ] ,
139+ outline && ! theme . outline . color [ color ] && theme . inner . outline ,
140+ isProcessing && theme . isProcessing ,
141+ isProcessing && theme . inner . isProcessingPadding [ size ] ,
142+ theme . inner . position [ positionInGroup ] ,
129143 ) }
130- { ...theirProps }
131144 >
132- < span
133- className = { twMerge (
134- theme . inner . base ,
135- theme . outline [ outline ? 'on' : 'off' ] ,
136- theme . outline . pill [ outline && pill ? 'on' : 'off' ] ,
137- theme . size [ size ] ,
138- outline && ! theme . outline . color [ color ] && theme . inner . outline ,
139- isProcessing && theme . isProcessing ,
140- isProcessing && theme . inner . isProcessingPadding [ size ] ,
141- theme . inner . position [ positionInGroup ] ,
145+ < >
146+ { isProcessing && (
147+ < span className = { twMerge ( theme . spinnerSlot , theme . spinnerLeftPosition [ size ] ) } >
148+ { processingSpinner || < Spinner size = { size } /> }
149+ </ span >
142150 ) }
143- >
144- < >
145- { isProcessing && (
146- < span className = { twMerge ( theme . spinnerSlot , theme . spinnerLeftPosition [ size ] ) } >
147- { processingSpinner || < Spinner size = { size } /> }
148- </ span >
149- ) }
150- { typeof children !== 'undefined' ? (
151- children
152- ) : (
153- < span data-testid = "flowbite-button-label" className = { twMerge ( theme . label ) } >
154- { isProcessing ? processingLabel : label }
155- </ span >
156- ) }
157- </ >
158- </ span >
159- </ ButtonBase >
160- ) ;
161- } ,
162- ) ;
163- ButtonComponent . displayName = 'ButtonComponent' ;
151+ { typeof children !== 'undefined' ? (
152+ children
153+ ) : (
154+ < span data-testid = "flowbite-button-label" className = { twMerge ( theme . label ) } >
155+ { isProcessing ? processingLabel : label }
156+ </ span >
157+ ) }
158+ </ >
159+ </ span >
160+ </ ButtonBase >
161+ ) ;
162+ } ;
163+
164+ const ButtonComponent = genericForwardRef ( ButtonComponentFn ) ;
164165
165166export const Button = Object . assign ( ButtonComponent , {
166167 Group : ButtonGroup ,
0 commit comments