1
1
import React from "react" ;
2
2
import type { ReactNode } from "react" ;
3
3
4
+ import { omit } from "@ezez/utils" ;
5
+
4
6
import type { ICON } from "../../icons/Icon" ;
5
7
import type { ThemeCSS } from "../../../theme" ;
6
8
@@ -13,19 +15,34 @@ interface LinkProps { // @TODO extract? - same on list item
13
15
children : React . ReactNode ;
14
16
}
15
17
16
- interface Props {
18
+ type NativeLinkProps = {
17
19
/**
18
20
* If action should be a native link provide target URL as `href`
19
21
*/
20
- href ?: string ;
22
+ href : string ;
23
+ type ?: never ;
24
+ } ;
25
+
26
+ type RouterLinkProps = {
21
27
/**
22
28
* If action should be a routed link provide target URL as `to` and `Link` component
23
29
*/
24
- to ? : string ;
30
+ to : string ;
25
31
/**
26
32
* If action should be a routed link provide target URL as `to` and `Link` component
27
33
*/
28
- Link ?: React . ComponentClass < LinkProps > | React . FC < LinkProps > ;
34
+ Link : React . ComponentClass < LinkProps > | React . FC < LinkProps > ;
35
+ type ?: never ;
36
+ } ;
37
+
38
+ type ButtonProps = {
39
+ /**
40
+ * If action should be a button provide `onClick` handler
41
+ */
42
+ type ?: React . ComponentProps < typeof Button > [ "type" ] ;
43
+ } ;
44
+
45
+ type CommonProps = {
29
46
/**
30
47
* Standard onClick handler (with no event)
31
48
*/
@@ -47,15 +64,20 @@ interface Props {
47
64
*/
48
65
css ?: ThemeCSS ;
49
66
badge ?: ReactNode ;
50
- }
67
+ } ;
68
+
69
+ type Props = ( NativeLinkProps | RouterLinkProps | ButtonProps ) & CommonProps ;
51
70
52
71
/**
53
72
* Action is a round-shaped button or a link, usually used at headers/toolbars.
54
73
*
55
74
* Its label is displayed below the circular shape.
56
75
*/
57
76
const Action : React . FC < Props > = ( props ) => {
58
- const { icon, label, href, to, Link, css, ...restProps } = props ;
77
+ const { icon, label, css, ..._restProps } = props ;
78
+ const restProps = omit (
79
+ _restProps as unknown as Record < string , string > , [ "to" , "Link" , "href" , "type" ] ,
80
+ ) as Omit < Props , "to" | "Link" | "href" | "type" | "icon" | "label" | "css" > ;
59
81
const maybeCss = css ? { css } : { } ;
60
82
61
83
let iconElem : ReactNode = icon ;
@@ -72,24 +94,24 @@ const Action: React.FC<Props> = (props) => {
72
94
</ >
73
95
) ;
74
96
75
- if ( to ) {
76
- if ( ! Link ) {
97
+ if ( "to" in props ) {
98
+ if ( ! ( " Link" in props ) ) {
77
99
throw new TypeError ( "`to` prop given without `Link` component" ) ;
78
100
}
79
101
80
102
return (
81
- < Link href = { to } { ...restProps } >
103
+ < props . Link href = { props . to } { ...restProps } >
82
104
< Anchor className = { props . className } { ...maybeCss } > { content } </ Anchor >
83
- </ Link >
105
+ </ props . Link >
84
106
) ;
85
107
}
86
108
87
- if ( href ) {
88
- return < Anchor href = { href } className = { props . className } { ...restProps } { ...maybeCss } > { content } </ Anchor > ;
109
+ if ( " href" in props ) {
110
+ return < Anchor href = { props . href } className = { props . className } { ...restProps } { ...maybeCss } > { content } </ Anchor > ;
89
111
}
90
112
91
113
return (
92
- < Button onClick = { props . onClick } className = { props . className } { ...maybeCss } >
114
+ < Button onClick = { props . onClick } className = { props . className } { ...maybeCss } type = { props . type ?? "button" } >
93
115
{ content }
94
116
</ Button >
95
117
) ;
0 commit comments