@justin_evo/evo-ui 1.2.0 → 1.2.1
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/LICENSE +21 -21
- package/README.md +70 -70
- package/dist/declarations.d.ts +6 -6
- package/package.json +52 -52
- package/src/Alert/Alert.tsx +49 -49
- package/src/AutoComplete/AutoComplete.tsx +810 -810
- package/src/Badge/Badge.tsx +53 -53
- package/src/Breadcrumb/Breadcrumb.tsx +53 -53
- package/src/Button/Button.tsx +125 -125
- package/src/Card/Card.tsx +257 -257
- package/src/Checkbox/Checkbox.tsx +59 -59
- package/src/CommandPalette/CommandPalette.tsx +185 -185
- package/src/Container/Container.tsx +31 -31
- package/src/Divider/Divider.tsx +31 -31
- package/src/Form/Form.tsx +185 -185
- package/src/Grid/Grid.tsx +66 -66
- package/src/ImageCropper/ImageCropper.tsx +911 -911
- package/src/Input/Input.tsx +74 -74
- package/src/Modal/Modal.tsx +77 -77
- package/src/Nav/Nav.tsx +708 -708
- package/src/Notification/Notification.tsx +1503 -1503
- package/src/Pagination/Pagination.tsx +76 -76
- package/src/Radio/Radio.tsx +69 -69
- package/src/RichTextArea/RichTextArea.tsx +886 -886
- package/src/Select/Select.tsx +515 -515
- package/src/Skeleton/Skeleton.tsx +70 -70
- package/src/Stack/Stack.tsx +52 -52
- package/src/Table/Table.tsx +335 -335
- package/src/Tabs/Tabs.tsx +90 -90
- package/src/Theme/ThemeProvider.tsx +253 -253
- package/src/Theme/ThemeToggle.tsx +79 -79
- package/src/Toggle/Toggle.tsx +48 -48
- package/src/Tooltip/Tooltip.tsx +38 -38
- package/src/TopNav/TopNav.tsx +1163 -1163
- package/src/TreeSelect/TreeSelect.tsx +825 -825
- package/src/css/alert.module.scss +93 -93
- package/src/css/autocomplete.module.scss +416 -416
- package/src/css/badge.module.scss +82 -82
- package/src/css/base/_color.scss +159 -159
- package/src/css/base/_theme.scss +237 -237
- package/src/css/base/_variables.scss +161 -161
- package/src/css/breadcrumb.module.scss +50 -50
- package/src/css/button.module.scss +385 -385
- package/src/css/card.module.scss +217 -217
- package/src/css/checkbox.module.scss +123 -123
- package/src/css/commandpalette.module.scss +211 -211
- package/src/css/container.module.scss +18 -18
- package/src/css/divider.module.scss +41 -41
- package/src/css/form.module.scss +245 -245
- package/src/css/imagecropper.module.scss +397 -397
- package/src/css/input.module.scss +89 -89
- package/src/css/modal.module.scss +105 -105
- package/src/css/nav.module.scss +494 -494
- package/src/css/notification.module.scss +691 -691
- package/src/css/pagination.module.scss +63 -63
- package/src/css/radio.module.scss +89 -89
- package/src/css/richtextarea.module.scss +307 -307
- package/src/css/select.module.scss +525 -525
- package/src/css/skeleton.module.scss +30 -30
- package/src/css/table.module.scss +386 -386
- package/src/css/tabs.module.scss +63 -63
- package/src/css/theme-toggle.module.scss +83 -83
- package/src/css/toggle.module.scss +54 -54
- package/src/css/tooltip.module.scss +97 -97
- package/src/css/topnav.module.scss +568 -568
- package/src/css/treeselect.module.scss +558 -558
- package/src/css/utilities/_borders.scss +111 -111
- package/src/css/utilities/_colors.scss +66 -66
- package/src/css/utilities/_effects.scss +216 -216
- package/src/css/utilities/_layout.scss +181 -181
- package/src/css/utilities/_position.scss +75 -75
- package/src/css/utilities/_sizing.scss +138 -138
- package/src/css/utilities/_spacing.scss +99 -99
- package/src/css/utilities/_typography.scss +121 -121
- package/src/css/utilities/index.scss +24 -24
- package/src/declarations.d.ts +6 -6
- package/src/index.ts +60 -60
package/src/Badge/Badge.tsx
CHANGED
|
@@ -1,53 +1,53 @@
|
|
|
1
|
-
import React from 'react';
|
|
2
|
-
import styles from '../css/badge.module.scss';
|
|
3
|
-
|
|
4
|
-
type BadgeSeverity = 'primary' | 'secondary' | 'success' | 'warning' | 'danger' | 'info';
|
|
5
|
-
type BadgeVariant = 'solid' | 'outline' | 'subtle';
|
|
6
|
-
type BadgeSize = 'sm' | 'md' | 'lg';
|
|
7
|
-
|
|
8
|
-
interface EvoBadgeProps {
|
|
9
|
-
children: React.ReactNode;
|
|
10
|
-
severity?: BadgeSeverity;
|
|
11
|
-
variant?: BadgeVariant;
|
|
12
|
-
size?: BadgeSize;
|
|
13
|
-
dot?: boolean;
|
|
14
|
-
removable?: boolean;
|
|
15
|
-
onRemove?: () => void;
|
|
16
|
-
className?: string;
|
|
17
|
-
}
|
|
18
|
-
|
|
19
|
-
interface EvoBadgeGroupProps {
|
|
20
|
-
children: React.ReactNode;
|
|
21
|
-
className?: string;
|
|
22
|
-
}
|
|
23
|
-
|
|
24
|
-
const EvoBadgeGroup = ({ children, className = '' }: EvoBadgeGroupProps) => (
|
|
25
|
-
<div className={`${styles.badgeGroup} ${className}`}>{children}</div>
|
|
26
|
-
);
|
|
27
|
-
|
|
28
|
-
export const EvoBadge = ({
|
|
29
|
-
children,
|
|
30
|
-
severity = 'primary',
|
|
31
|
-
variant = 'solid',
|
|
32
|
-
size = 'md',
|
|
33
|
-
dot = false,
|
|
34
|
-
removable = false,
|
|
35
|
-
onRemove,
|
|
36
|
-
className = '',
|
|
37
|
-
}: EvoBadgeProps) => (
|
|
38
|
-
<span
|
|
39
|
-
className={[styles.badge, styles[severity], styles[variant], styles[size], className]
|
|
40
|
-
.filter(Boolean)
|
|
41
|
-
.join(' ')}
|
|
42
|
-
>
|
|
43
|
-
{dot && <span className={styles.dot} />}
|
|
44
|
-
{children}
|
|
45
|
-
{removable && (
|
|
46
|
-
<button className={styles.removeBtn} onClick={onRemove} aria-label="Remove">
|
|
47
|
-
✕
|
|
48
|
-
</button>
|
|
49
|
-
)}
|
|
50
|
-
</span>
|
|
51
|
-
);
|
|
52
|
-
|
|
53
|
-
EvoBadge.Group = EvoBadgeGroup;
|
|
1
|
+
import React from 'react';
|
|
2
|
+
import styles from '../css/badge.module.scss';
|
|
3
|
+
|
|
4
|
+
type BadgeSeverity = 'primary' | 'secondary' | 'success' | 'warning' | 'danger' | 'info';
|
|
5
|
+
type BadgeVariant = 'solid' | 'outline' | 'subtle';
|
|
6
|
+
type BadgeSize = 'sm' | 'md' | 'lg';
|
|
7
|
+
|
|
8
|
+
interface EvoBadgeProps {
|
|
9
|
+
children: React.ReactNode;
|
|
10
|
+
severity?: BadgeSeverity;
|
|
11
|
+
variant?: BadgeVariant;
|
|
12
|
+
size?: BadgeSize;
|
|
13
|
+
dot?: boolean;
|
|
14
|
+
removable?: boolean;
|
|
15
|
+
onRemove?: () => void;
|
|
16
|
+
className?: string;
|
|
17
|
+
}
|
|
18
|
+
|
|
19
|
+
interface EvoBadgeGroupProps {
|
|
20
|
+
children: React.ReactNode;
|
|
21
|
+
className?: string;
|
|
22
|
+
}
|
|
23
|
+
|
|
24
|
+
const EvoBadgeGroup = ({ children, className = '' }: EvoBadgeGroupProps) => (
|
|
25
|
+
<div className={`${styles.badgeGroup} ${className}`}>{children}</div>
|
|
26
|
+
);
|
|
27
|
+
|
|
28
|
+
export const EvoBadge = ({
|
|
29
|
+
children,
|
|
30
|
+
severity = 'primary',
|
|
31
|
+
variant = 'solid',
|
|
32
|
+
size = 'md',
|
|
33
|
+
dot = false,
|
|
34
|
+
removable = false,
|
|
35
|
+
onRemove,
|
|
36
|
+
className = '',
|
|
37
|
+
}: EvoBadgeProps) => (
|
|
38
|
+
<span
|
|
39
|
+
className={[styles.badge, styles[severity], styles[variant], styles[size], className]
|
|
40
|
+
.filter(Boolean)
|
|
41
|
+
.join(' ')}
|
|
42
|
+
>
|
|
43
|
+
{dot && <span className={styles.dot} />}
|
|
44
|
+
{children}
|
|
45
|
+
{removable && (
|
|
46
|
+
<button className={styles.removeBtn} onClick={onRemove} aria-label="Remove">
|
|
47
|
+
✕
|
|
48
|
+
</button>
|
|
49
|
+
)}
|
|
50
|
+
</span>
|
|
51
|
+
);
|
|
52
|
+
|
|
53
|
+
EvoBadge.Group = EvoBadgeGroup;
|
|
@@ -1,53 +1,53 @@
|
|
|
1
|
-
import React from 'react';
|
|
2
|
-
import styles from '../css/breadcrumb.module.scss';
|
|
3
|
-
|
|
4
|
-
interface EvoBreadcrumbItemProps {
|
|
5
|
-
children: React.ReactNode;
|
|
6
|
-
href?: string;
|
|
7
|
-
current?: boolean;
|
|
8
|
-
}
|
|
9
|
-
|
|
10
|
-
interface EvoBreadcrumbProps {
|
|
11
|
-
children: React.ReactNode;
|
|
12
|
-
separator?: React.ReactNode;
|
|
13
|
-
className?: string;
|
|
14
|
-
}
|
|
15
|
-
|
|
16
|
-
const EvoBreadcrumbItem = ({ children, href, current = false }: EvoBreadcrumbItemProps) => (
|
|
17
|
-
<li className={styles.item}>
|
|
18
|
-
{href && !current ? (
|
|
19
|
-
<a href={href} className={styles.link}>
|
|
20
|
-
{children}
|
|
21
|
-
</a>
|
|
22
|
-
) : (
|
|
23
|
-
<span
|
|
24
|
-
className={[styles.text, current ? styles.current : ''].filter(Boolean).join(' ')}
|
|
25
|
-
aria-current={current ? 'page' : undefined}
|
|
26
|
-
>
|
|
27
|
-
{children}
|
|
28
|
-
</span>
|
|
29
|
-
)}
|
|
30
|
-
</li>
|
|
31
|
-
);
|
|
32
|
-
|
|
33
|
-
export const EvoBreadcrumb = ({ children, separator = '/', className = '' }: EvoBreadcrumbProps) => {
|
|
34
|
-
const items = React.Children.toArray(children);
|
|
35
|
-
return (
|
|
36
|
-
<nav aria-label="breadcrumb" className={className}>
|
|
37
|
-
<ol className={styles.breadcrumb}>
|
|
38
|
-
{items.map((item, i) => (
|
|
39
|
-
<React.Fragment key={i}>
|
|
40
|
-
{item}
|
|
41
|
-
{i < items.length - 1 && (
|
|
42
|
-
<li className={styles.separator} aria-hidden="true">
|
|
43
|
-
{separator}
|
|
44
|
-
</li>
|
|
45
|
-
)}
|
|
46
|
-
</React.Fragment>
|
|
47
|
-
))}
|
|
48
|
-
</ol>
|
|
49
|
-
</nav>
|
|
50
|
-
);
|
|
51
|
-
};
|
|
52
|
-
|
|
53
|
-
EvoBreadcrumb.Item = EvoBreadcrumbItem;
|
|
1
|
+
import React from 'react';
|
|
2
|
+
import styles from '../css/breadcrumb.module.scss';
|
|
3
|
+
|
|
4
|
+
interface EvoBreadcrumbItemProps {
|
|
5
|
+
children: React.ReactNode;
|
|
6
|
+
href?: string;
|
|
7
|
+
current?: boolean;
|
|
8
|
+
}
|
|
9
|
+
|
|
10
|
+
interface EvoBreadcrumbProps {
|
|
11
|
+
children: React.ReactNode;
|
|
12
|
+
separator?: React.ReactNode;
|
|
13
|
+
className?: string;
|
|
14
|
+
}
|
|
15
|
+
|
|
16
|
+
const EvoBreadcrumbItem = ({ children, href, current = false }: EvoBreadcrumbItemProps) => (
|
|
17
|
+
<li className={styles.item}>
|
|
18
|
+
{href && !current ? (
|
|
19
|
+
<a href={href} className={styles.link}>
|
|
20
|
+
{children}
|
|
21
|
+
</a>
|
|
22
|
+
) : (
|
|
23
|
+
<span
|
|
24
|
+
className={[styles.text, current ? styles.current : ''].filter(Boolean).join(' ')}
|
|
25
|
+
aria-current={current ? 'page' : undefined}
|
|
26
|
+
>
|
|
27
|
+
{children}
|
|
28
|
+
</span>
|
|
29
|
+
)}
|
|
30
|
+
</li>
|
|
31
|
+
);
|
|
32
|
+
|
|
33
|
+
export const EvoBreadcrumb = ({ children, separator = '/', className = '' }: EvoBreadcrumbProps) => {
|
|
34
|
+
const items = React.Children.toArray(children);
|
|
35
|
+
return (
|
|
36
|
+
<nav aria-label="breadcrumb" className={className}>
|
|
37
|
+
<ol className={styles.breadcrumb}>
|
|
38
|
+
{items.map((item, i) => (
|
|
39
|
+
<React.Fragment key={i}>
|
|
40
|
+
{item}
|
|
41
|
+
{i < items.length - 1 && (
|
|
42
|
+
<li className={styles.separator} aria-hidden="true">
|
|
43
|
+
{separator}
|
|
44
|
+
</li>
|
|
45
|
+
)}
|
|
46
|
+
</React.Fragment>
|
|
47
|
+
))}
|
|
48
|
+
</ol>
|
|
49
|
+
</nav>
|
|
50
|
+
);
|
|
51
|
+
};
|
|
52
|
+
|
|
53
|
+
EvoBreadcrumb.Item = EvoBreadcrumbItem;
|
package/src/Button/Button.tsx
CHANGED
|
@@ -1,125 +1,125 @@
|
|
|
1
|
-
import { forwardRef, type ButtonHTMLAttributes, type ReactNode } from 'react';
|
|
2
|
-
import styles from '../css/button.module.scss';
|
|
3
|
-
|
|
4
|
-
type Variant = 'solid' | 'outline' | 'ghost' | 'soft';
|
|
5
|
-
type Severity = 'primary' | 'secondary' | 'danger' | 'warning' | 'success' | 'info';
|
|
6
|
-
type Size = 'sm' | 'md' | 'lg';
|
|
7
|
-
type Shape = 'default' | 'rounded' | 'square';
|
|
8
|
-
|
|
9
|
-
/**
|
|
10
|
-
* Configuration properties for the EvoButton component.
|
|
11
|
-
*
|
|
12
|
-
* Extends every native `<button>` attribute (type, form, name, autoFocus,
|
|
13
|
-
* aria-*, onMouseEnter, …) so consumers don't have to ask for them one by one.
|
|
14
|
-
*/
|
|
15
|
-
export interface EvoButtonProps extends ButtonHTMLAttributes<HTMLButtonElement> {
|
|
16
|
-
/** Text shown inside the button. Convenience shorthand for `children`. */
|
|
17
|
-
label?: string;
|
|
18
|
-
|
|
19
|
-
/**
|
|
20
|
-
* Visual style of the button.
|
|
21
|
-
* - `solid` — filled background (default).
|
|
22
|
-
* - `outline` — bordered, transparent background.
|
|
23
|
-
* - `ghost` — no border or background until hover.
|
|
24
|
-
* - `soft` — tinted background using the severity's soft token.
|
|
25
|
-
* @default 'solid'
|
|
26
|
-
*/
|
|
27
|
-
variant?: Variant;
|
|
28
|
-
|
|
29
|
-
/**
|
|
30
|
-
* Semantic color theme.
|
|
31
|
-
* @default 'primary'
|
|
32
|
-
*/
|
|
33
|
-
severity?: Severity;
|
|
34
|
-
|
|
35
|
-
/** @default 'md' */
|
|
36
|
-
size?: Size;
|
|
37
|
-
|
|
38
|
-
/**
|
|
39
|
-
* Border-radius shape, orthogonal to `variant`.
|
|
40
|
-
* - `default` — normal radius.
|
|
41
|
-
* - `rounded` — pill / fully rounded edges.
|
|
42
|
-
* - `square` — equal width/height; use for icon-only buttons.
|
|
43
|
-
* @default 'default'
|
|
44
|
-
*/
|
|
45
|
-
shape?: Shape;
|
|
46
|
-
|
|
47
|
-
/** Icon rendered before the label. */
|
|
48
|
-
iconLeft?: ReactNode;
|
|
49
|
-
|
|
50
|
-
/** Icon rendered after the label. */
|
|
51
|
-
iconRight?: ReactNode;
|
|
52
|
-
|
|
53
|
-
/**
|
|
54
|
-
* When true, replaces icons with a spinner and disables interaction.
|
|
55
|
-
* `aria-busy` is set automatically.
|
|
56
|
-
*/
|
|
57
|
-
loading?: boolean;
|
|
58
|
-
|
|
59
|
-
/** Optional text shown next to the spinner while `loading` is true. */
|
|
60
|
-
loadingText?: string;
|
|
61
|
-
|
|
62
|
-
/** Stretch to fill the parent's width. */
|
|
63
|
-
fullWidth?: boolean;
|
|
64
|
-
}
|
|
65
|
-
|
|
66
|
-
export const EvoButton = forwardRef<HTMLButtonElement, EvoButtonProps>(function EvoButton(
|
|
67
|
-
{
|
|
68
|
-
label,
|
|
69
|
-
children,
|
|
70
|
-
variant = 'solid',
|
|
71
|
-
severity = 'primary',
|
|
72
|
-
size = 'md',
|
|
73
|
-
shape = 'default',
|
|
74
|
-
iconLeft,
|
|
75
|
-
iconRight,
|
|
76
|
-
loading = false,
|
|
77
|
-
loadingText,
|
|
78
|
-
fullWidth = false,
|
|
79
|
-
disabled,
|
|
80
|
-
type = 'button',
|
|
81
|
-
className,
|
|
82
|
-
...rest
|
|
83
|
-
},
|
|
84
|
-
ref,
|
|
85
|
-
) {
|
|
86
|
-
const content = children ?? label;
|
|
87
|
-
const visibleContent = loading ? loadingText : content;
|
|
88
|
-
const isDisabled = disabled || loading;
|
|
89
|
-
|
|
90
|
-
const classes = [
|
|
91
|
-
styles.button,
|
|
92
|
-
styles[variant],
|
|
93
|
-
styles[severity],
|
|
94
|
-
styles[size],
|
|
95
|
-
shape !== 'default' ? styles[shape] : '',
|
|
96
|
-
fullWidth ? styles.fullWidth : '',
|
|
97
|
-
!visibleContent ? styles.iconOnly : '',
|
|
98
|
-
className,
|
|
99
|
-
]
|
|
100
|
-
.filter(Boolean)
|
|
101
|
-
.join(' ');
|
|
102
|
-
|
|
103
|
-
return (
|
|
104
|
-
<button
|
|
105
|
-
ref={ref}
|
|
106
|
-
type={type}
|
|
107
|
-
className={classes}
|
|
108
|
-
disabled={isDisabled}
|
|
109
|
-
aria-busy={loading || undefined}
|
|
110
|
-
{...rest}
|
|
111
|
-
>
|
|
112
|
-
{loading ? (
|
|
113
|
-
<span className={styles.spinner} aria-hidden="true" />
|
|
114
|
-
) : (
|
|
115
|
-
iconLeft && <span className={styles.icon}>{iconLeft}</span>
|
|
116
|
-
)}
|
|
117
|
-
|
|
118
|
-
{visibleContent != null && visibleContent !== '' && (
|
|
119
|
-
<span className={styles.label}>{visibleContent}</span>
|
|
120
|
-
)}
|
|
121
|
-
|
|
122
|
-
{!loading && iconRight && <span className={styles.icon}>{iconRight}</span>}
|
|
123
|
-
</button>
|
|
124
|
-
);
|
|
125
|
-
});
|
|
1
|
+
import { forwardRef, type ButtonHTMLAttributes, type ReactNode } from 'react';
|
|
2
|
+
import styles from '../css/button.module.scss';
|
|
3
|
+
|
|
4
|
+
type Variant = 'solid' | 'outline' | 'ghost' | 'soft';
|
|
5
|
+
type Severity = 'primary' | 'secondary' | 'danger' | 'warning' | 'success' | 'info';
|
|
6
|
+
type Size = 'sm' | 'md' | 'lg';
|
|
7
|
+
type Shape = 'default' | 'rounded' | 'square';
|
|
8
|
+
|
|
9
|
+
/**
|
|
10
|
+
* Configuration properties for the EvoButton component.
|
|
11
|
+
*
|
|
12
|
+
* Extends every native `<button>` attribute (type, form, name, autoFocus,
|
|
13
|
+
* aria-*, onMouseEnter, …) so consumers don't have to ask for them one by one.
|
|
14
|
+
*/
|
|
15
|
+
export interface EvoButtonProps extends ButtonHTMLAttributes<HTMLButtonElement> {
|
|
16
|
+
/** Text shown inside the button. Convenience shorthand for `children`. */
|
|
17
|
+
label?: string;
|
|
18
|
+
|
|
19
|
+
/**
|
|
20
|
+
* Visual style of the button.
|
|
21
|
+
* - `solid` — filled background (default).
|
|
22
|
+
* - `outline` — bordered, transparent background.
|
|
23
|
+
* - `ghost` — no border or background until hover.
|
|
24
|
+
* - `soft` — tinted background using the severity's soft token.
|
|
25
|
+
* @default 'solid'
|
|
26
|
+
*/
|
|
27
|
+
variant?: Variant;
|
|
28
|
+
|
|
29
|
+
/**
|
|
30
|
+
* Semantic color theme.
|
|
31
|
+
* @default 'primary'
|
|
32
|
+
*/
|
|
33
|
+
severity?: Severity;
|
|
34
|
+
|
|
35
|
+
/** @default 'md' */
|
|
36
|
+
size?: Size;
|
|
37
|
+
|
|
38
|
+
/**
|
|
39
|
+
* Border-radius shape, orthogonal to `variant`.
|
|
40
|
+
* - `default` — normal radius.
|
|
41
|
+
* - `rounded` — pill / fully rounded edges.
|
|
42
|
+
* - `square` — equal width/height; use for icon-only buttons.
|
|
43
|
+
* @default 'default'
|
|
44
|
+
*/
|
|
45
|
+
shape?: Shape;
|
|
46
|
+
|
|
47
|
+
/** Icon rendered before the label. */
|
|
48
|
+
iconLeft?: ReactNode;
|
|
49
|
+
|
|
50
|
+
/** Icon rendered after the label. */
|
|
51
|
+
iconRight?: ReactNode;
|
|
52
|
+
|
|
53
|
+
/**
|
|
54
|
+
* When true, replaces icons with a spinner and disables interaction.
|
|
55
|
+
* `aria-busy` is set automatically.
|
|
56
|
+
*/
|
|
57
|
+
loading?: boolean;
|
|
58
|
+
|
|
59
|
+
/** Optional text shown next to the spinner while `loading` is true. */
|
|
60
|
+
loadingText?: string;
|
|
61
|
+
|
|
62
|
+
/** Stretch to fill the parent's width. */
|
|
63
|
+
fullWidth?: boolean;
|
|
64
|
+
}
|
|
65
|
+
|
|
66
|
+
export const EvoButton = forwardRef<HTMLButtonElement, EvoButtonProps>(function EvoButton(
|
|
67
|
+
{
|
|
68
|
+
label,
|
|
69
|
+
children,
|
|
70
|
+
variant = 'solid',
|
|
71
|
+
severity = 'primary',
|
|
72
|
+
size = 'md',
|
|
73
|
+
shape = 'default',
|
|
74
|
+
iconLeft,
|
|
75
|
+
iconRight,
|
|
76
|
+
loading = false,
|
|
77
|
+
loadingText,
|
|
78
|
+
fullWidth = false,
|
|
79
|
+
disabled,
|
|
80
|
+
type = 'button',
|
|
81
|
+
className,
|
|
82
|
+
...rest
|
|
83
|
+
},
|
|
84
|
+
ref,
|
|
85
|
+
) {
|
|
86
|
+
const content = children ?? label;
|
|
87
|
+
const visibleContent = loading ? loadingText : content;
|
|
88
|
+
const isDisabled = disabled || loading;
|
|
89
|
+
|
|
90
|
+
const classes = [
|
|
91
|
+
styles.button,
|
|
92
|
+
styles[variant],
|
|
93
|
+
styles[severity],
|
|
94
|
+
styles[size],
|
|
95
|
+
shape !== 'default' ? styles[shape] : '',
|
|
96
|
+
fullWidth ? styles.fullWidth : '',
|
|
97
|
+
!visibleContent ? styles.iconOnly : '',
|
|
98
|
+
className,
|
|
99
|
+
]
|
|
100
|
+
.filter(Boolean)
|
|
101
|
+
.join(' ');
|
|
102
|
+
|
|
103
|
+
return (
|
|
104
|
+
<button
|
|
105
|
+
ref={ref}
|
|
106
|
+
type={type}
|
|
107
|
+
className={classes}
|
|
108
|
+
disabled={isDisabled}
|
|
109
|
+
aria-busy={loading || undefined}
|
|
110
|
+
{...rest}
|
|
111
|
+
>
|
|
112
|
+
{loading ? (
|
|
113
|
+
<span className={styles.spinner} aria-hidden="true" />
|
|
114
|
+
) : (
|
|
115
|
+
iconLeft && <span className={styles.icon}>{iconLeft}</span>
|
|
116
|
+
)}
|
|
117
|
+
|
|
118
|
+
{visibleContent != null && visibleContent !== '' && (
|
|
119
|
+
<span className={styles.label}>{visibleContent}</span>
|
|
120
|
+
)}
|
|
121
|
+
|
|
122
|
+
{!loading && iconRight && <span className={styles.icon}>{iconRight}</span>}
|
|
123
|
+
</button>
|
|
124
|
+
);
|
|
125
|
+
});
|