@kaizen/components 1.67.22 → 1.68.0
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/dist/cjs/__actions__/Button/v3/Button.cjs +43 -8
- package/dist/cjs/__actions__/Button/v3/Button.module.css.cjs +21 -0
- package/dist/cjs/__actions__/Button/v3/subcomponents/ButtonContent/ButtonContent.cjs +37 -0
- package/dist/cjs/__actions__/Button/v3/subcomponents/ButtonContent/ButtonContent.module.css.cjs +9 -0
- package/dist/cjs/__actions__/Button/v3/subcomponents/PendingContent/PendingContent.cjs +35 -0
- package/dist/cjs/__actions__/Button/v3/subcomponents/PendingContent/PendingContent.module.css.cjs +8 -0
- package/dist/cjs/__overlays__/Tooltip/v3/Tooltip.cjs +2 -2
- package/dist/esm/__actions__/Button/v3/Button.mjs +44 -9
- package/dist/esm/__actions__/Button/v3/Button.module.css.mjs +19 -0
- package/dist/esm/__actions__/Button/v3/subcomponents/ButtonContent/ButtonContent.mjs +28 -0
- package/dist/esm/__actions__/Button/v3/subcomponents/ButtonContent/ButtonContent.module.css.mjs +7 -0
- package/dist/esm/__actions__/Button/v3/subcomponents/PendingContent/PendingContent.mjs +26 -0
- package/dist/esm/__actions__/Button/v3/subcomponents/PendingContent/PendingContent.module.css.mjs +6 -0
- package/dist/esm/__overlays__/Tooltip/v3/Tooltip.mjs +1 -1
- package/dist/styles.css +276 -91
- package/dist/types/__actions__/Button/v3/Button.d.ts +17 -4
- package/dist/types/__actions__/Button/v3/index.d.ts +1 -0
- package/dist/types/__actions__/Button/v3/subcomponents/ButtonContent/ButtonContent.d.ts +11 -0
- package/dist/types/__actions__/Button/v3/subcomponents/ButtonContent/index.d.ts +1 -0
- package/dist/types/__actions__/Button/v3/subcomponents/PendingContent/PendingContent.d.ts +5 -0
- package/dist/types/__actions__/Button/v3/subcomponents/PendingContent/index.d.ts +1 -0
- package/dist/types/__actions__/Button/v3/subcomponents/index.d.ts +2 -0
- package/dist/types/__actions__/Button/v3/types.d.ts +21 -0
- package/package.json +1 -1
- package/src/__actions__/Button/v3/Button.module.css +235 -0
- package/src/__actions__/Button/v3/Button.tsx +92 -29
- package/src/__actions__/Button/v3/_docs/Button--api-specification.mdx +150 -0
- package/src/__actions__/Button/v3/_docs/Button--usage-guidelines.mdx +30 -0
- package/src/__actions__/Button/v3/_docs/Button.docs.stories.tsx +112 -50
- package/src/__actions__/Button/v3/_docs/Button.spec.stories.tsx +80 -120
- package/src/__actions__/Button/v3/_docs/Button.stickersheet.stories.tsx +183 -81
- package/src/__actions__/Button/v3/index.ts +1 -0
- package/src/__actions__/Button/v3/subcomponents/ButtonContent/ButtonContent.module.css +19 -0
- package/src/__actions__/Button/v3/subcomponents/ButtonContent/ButtonContent.tsx +40 -0
- package/src/__actions__/Button/v3/subcomponents/ButtonContent/index.ts +1 -0
- package/src/__actions__/Button/v3/subcomponents/PendingContent/PendingContent.module.css +16 -0
- package/src/__actions__/Button/v3/subcomponents/PendingContent/PendingContent.tsx +28 -0
- package/src/__actions__/Button/v3/subcomponents/PendingContent/index.ts +1 -0
- package/src/__actions__/Button/v3/subcomponents/index.ts +2 -0
- package/src/__actions__/Button/v3/types.ts +25 -0
- package/src/__actions__/Menu/v3/_docs/Menu.docs.stories.tsx +54 -18
- package/src/__actions__/Menu/v3/_docs/Menu.spec.stories.tsx +30 -10
- package/src/__actions__/Menu/v3/_docs/Menu.stories.tsx +12 -4
- package/src/__future__/Icon/_docs/Icon.docs.stories.tsx +7 -7
- package/src/__overlays__/Tooltip/v3/Tooltip.tsx +1 -1
- package/src/__overlays__/Tooltip/v3/_docs/Tooltip.spec.stories.tsx +2 -0
- package/dist/cjs/__actions__/Button/v3/Button.module.scss.cjs +0 -9
- package/dist/esm/__actions__/Button/v3/Button.module.scss.mjs +0 -7
- package/src/__actions__/Button/v3/Button.module.scss +0 -104
- package/src/__actions__/Button/v3/_docs/ApiSpecification.mdx +0 -173
- package/src/__actions__/Button/v3/_docs/Button.mdx +0 -41
- package/src/__actions__/Button/v3/_docs/Button.stories.tsx +0 -98
|
@@ -0,0 +1,235 @@
|
|
|
1
|
+
.button {
|
|
2
|
+
/* RESET */
|
|
3
|
+
appearance: none;
|
|
4
|
+
background: transparent;
|
|
5
|
+
font: inherit;
|
|
6
|
+
margin: 0;
|
|
7
|
+
outline: none;
|
|
8
|
+
-webkit-font-smoothing: antialiased;
|
|
9
|
+
-moz-osx-font-smoothing: grayscale;
|
|
10
|
+
|
|
11
|
+
--button-min-x-y: var(--spacing-40);
|
|
12
|
+
--button-border-width: var(--border-solid-border-width);
|
|
13
|
+
--button-padding-y: calc(var(--spacing-8) - var(--button-border-width));
|
|
14
|
+
--button-padding-x: calc(var(--spacing-16) - var(--button-border-width));
|
|
15
|
+
|
|
16
|
+
background-color: var(--button-bg-color, var(--color-blue-500));
|
|
17
|
+
border: var(--button-border-width) solid;
|
|
18
|
+
border-radius: var(--border-solid-border-radius);
|
|
19
|
+
border-color: var(--button-border-color, var(--color-blue-500));
|
|
20
|
+
box-sizing: border-box;
|
|
21
|
+
color: var(--button-text-color, var(--color-white));
|
|
22
|
+
display: inline-flex;
|
|
23
|
+
align-items: center;
|
|
24
|
+
justify-content: center;
|
|
25
|
+
text-align: start;
|
|
26
|
+
font-family: var(
|
|
27
|
+
--button-font-family,
|
|
28
|
+
var(--typography-paragraph-body-font-family)
|
|
29
|
+
);
|
|
30
|
+
font-weight: var(--button-font-weight, 500);
|
|
31
|
+
font-size: var(--button-font-size, 1rem);
|
|
32
|
+
line-height: var(--button-line-height, 1.5rem);
|
|
33
|
+
min-height: var(--button-min-x-y);
|
|
34
|
+
min-width: var(--button-min-x-y);
|
|
35
|
+
position: relative;
|
|
36
|
+
padding: var(--button-padding-y) var(--button-padding-x);
|
|
37
|
+
|
|
38
|
+
&[data-hovered] {
|
|
39
|
+
--button-bg-color: var(--color-blue-600);
|
|
40
|
+
--button-border-color: var(--color-blue-600);
|
|
41
|
+
}
|
|
42
|
+
|
|
43
|
+
&[data-pressed] {
|
|
44
|
+
--button-bg-color: var(--color-blue-700);
|
|
45
|
+
--button-border-color: var(--color-blue-700);
|
|
46
|
+
}
|
|
47
|
+
|
|
48
|
+
&[data-pending] {
|
|
49
|
+
--button-bg-color: var(--color-blue-700);
|
|
50
|
+
--button-border-color: var(--color-blue-700);
|
|
51
|
+
}
|
|
52
|
+
|
|
53
|
+
&[data-focus-visible]::after {
|
|
54
|
+
content: "";
|
|
55
|
+
position: absolute;
|
|
56
|
+
background: transparent;
|
|
57
|
+
border-color: var(--color-blue-500);
|
|
58
|
+
border-radius: var(--border-focus-ring-border-radius);
|
|
59
|
+
border-width: var(--border-focus-ring-border-width);
|
|
60
|
+
border-style: var(--border-focus-ring-border-style);
|
|
61
|
+
inset: calc(-1 * (var(--border-focus-ring-border-width) * 2) - 1px);
|
|
62
|
+
}
|
|
63
|
+
}
|
|
64
|
+
|
|
65
|
+
.fullWidth {
|
|
66
|
+
width: 100%;
|
|
67
|
+
}
|
|
68
|
+
|
|
69
|
+
.small {
|
|
70
|
+
--button-font-size: 0.75rem;
|
|
71
|
+
--button-line-height: 1rem;
|
|
72
|
+
--button-min-x-y: var(--spacing-32);
|
|
73
|
+
--icon-size: 16;
|
|
74
|
+
}
|
|
75
|
+
|
|
76
|
+
.medium {
|
|
77
|
+
--button-padding-x: calc(var(--spacing-20) - var(--button-border-width));
|
|
78
|
+
--button-padding-y: calc(var(--spacing-8) - var(--button-border-width));
|
|
79
|
+
--button-min-x-y: var(--spacing-40);
|
|
80
|
+
--icon-size: 24;
|
|
81
|
+
}
|
|
82
|
+
|
|
83
|
+
.large {
|
|
84
|
+
--button-padding-x: calc(var(--spacing-24) - var(--button-border-width));
|
|
85
|
+
--button-padding-y: calc(var(--spacing-12) - var(--button-border-width));
|
|
86
|
+
--button-min-x-y: var(--spacing-48);
|
|
87
|
+
--icon-size: 24;
|
|
88
|
+
}
|
|
89
|
+
|
|
90
|
+
.smallIconButton,
|
|
91
|
+
.mediumIconButton {
|
|
92
|
+
--button-padding-x: calc(var(--spacing-8) - var(--button-border-width));
|
|
93
|
+
--button-padding-y: calc(var(--spacing-8) - var(--button-border-width));
|
|
94
|
+
}
|
|
95
|
+
|
|
96
|
+
.largeIconButton {
|
|
97
|
+
--button-padding-x: calc(var(--spacing-12) - var(--button-border-width));
|
|
98
|
+
--button-padding-y: calc(var(--spacing-12) - var(--button-border-width));
|
|
99
|
+
}
|
|
100
|
+
|
|
101
|
+
.secondary {
|
|
102
|
+
--button-bg-color: var(--color-white);
|
|
103
|
+
--button-border-color: var(--color-gray-500);
|
|
104
|
+
--button-text-color: var(--color-purple-800);
|
|
105
|
+
|
|
106
|
+
&[data-hovered] {
|
|
107
|
+
--button-bg-color: var(--color-gray-200);
|
|
108
|
+
--button-border-color: var(--color-gray-600);
|
|
109
|
+
}
|
|
110
|
+
|
|
111
|
+
&[data-pressed] {
|
|
112
|
+
--button-bg-color: var(--color-gray-300);
|
|
113
|
+
--button-border-color: var(--color-black);
|
|
114
|
+
}
|
|
115
|
+
|
|
116
|
+
&[data-pending] {
|
|
117
|
+
--button-bg-color: var(--color-gray-300);
|
|
118
|
+
--button-border-color: var(--color-black);
|
|
119
|
+
}
|
|
120
|
+
}
|
|
121
|
+
|
|
122
|
+
.tertiary {
|
|
123
|
+
--button-bg-color: transparent;
|
|
124
|
+
--button-border-color: transparent;
|
|
125
|
+
--button-text-color: var(--color-purple-800);
|
|
126
|
+
|
|
127
|
+
&[data-hovered] {
|
|
128
|
+
--button-bg-color: var(--color-gray-200);
|
|
129
|
+
--button-border-color: var(--color-gray-200);
|
|
130
|
+
}
|
|
131
|
+
|
|
132
|
+
&[data-pressed] {
|
|
133
|
+
--button-bg-color: var(--color-gray-300);
|
|
134
|
+
--button-border-color: var(--color-gray-300);
|
|
135
|
+
}
|
|
136
|
+
|
|
137
|
+
&[data-pending] {
|
|
138
|
+
--button-bg-color: var(--color-gray-300);
|
|
139
|
+
--button-border-color: var(--color-gray-300);
|
|
140
|
+
}
|
|
141
|
+
}
|
|
142
|
+
|
|
143
|
+
.primaryReversed,
|
|
144
|
+
.secondaryReversed,
|
|
145
|
+
.tertiaryReversed {
|
|
146
|
+
&[data-focus-visible]::after {
|
|
147
|
+
border-color: var(--color-blue-300);
|
|
148
|
+
}
|
|
149
|
+
}
|
|
150
|
+
|
|
151
|
+
.primaryReversed {
|
|
152
|
+
--button-bg-color: var(--color-white);
|
|
153
|
+
--button-border-color: var(--color-white);
|
|
154
|
+
--button-text-color: var(--color-purple-800);
|
|
155
|
+
|
|
156
|
+
&[data-hovered] {
|
|
157
|
+
--button-bg-color: var(--color-white);
|
|
158
|
+
--button-border-color: var(--color-white);
|
|
159
|
+
}
|
|
160
|
+
|
|
161
|
+
&[data-pressed] {
|
|
162
|
+
--button-bg-color: var(--color-white);
|
|
163
|
+
--button-border-color: var(--color-white);
|
|
164
|
+
}
|
|
165
|
+
|
|
166
|
+
&[data-pending] {
|
|
167
|
+
--button-bg-color: var(--color-white);
|
|
168
|
+
--button-border-color: var(--color-white);
|
|
169
|
+
}
|
|
170
|
+
}
|
|
171
|
+
|
|
172
|
+
.secondaryReversed {
|
|
173
|
+
--button-bg-color: transparent;
|
|
174
|
+
--button-border-color: var(--color-white);
|
|
175
|
+
--button-text-color: var(--color-white);
|
|
176
|
+
|
|
177
|
+
&[data-hovered] {
|
|
178
|
+
--button-bg-color: rgba(var(--color-white-rgb), 0.2);
|
|
179
|
+
--button-border-color: var(--color-white);
|
|
180
|
+
}
|
|
181
|
+
|
|
182
|
+
&[data-pressed] {
|
|
183
|
+
--button-bg-color: rgba(var(--color-white-rgb), 0.1);
|
|
184
|
+
--button-border-color: var(--color-white);
|
|
185
|
+
}
|
|
186
|
+
|
|
187
|
+
&[data-pending] {
|
|
188
|
+
--button-bg-color: rgba(var(--color-white-rgb), 0.1);
|
|
189
|
+
--button-border-color: var(--color-white);
|
|
190
|
+
}
|
|
191
|
+
}
|
|
192
|
+
|
|
193
|
+
.tertiaryReversed {
|
|
194
|
+
--button-bg-color: transparent;
|
|
195
|
+
--button-border-color: transparent;
|
|
196
|
+
--button-text-color: var(--color-white);
|
|
197
|
+
|
|
198
|
+
&[data-hovered] {
|
|
199
|
+
--button-bg-color: rgba(var(--color-white-rgb), 0.2);
|
|
200
|
+
--button-border-color: transparent;
|
|
201
|
+
}
|
|
202
|
+
|
|
203
|
+
&[data-pressed] {
|
|
204
|
+
--button-bg-color: rgba(var(--color-white-rgb), 0.1);
|
|
205
|
+
--button-border-color: transparent;
|
|
206
|
+
}
|
|
207
|
+
|
|
208
|
+
&[data-pending] {
|
|
209
|
+
--button-bg-color: rgba(var(--color-white-rgb), 0.1);
|
|
210
|
+
--button-border-color: transparent;
|
|
211
|
+
}
|
|
212
|
+
}
|
|
213
|
+
|
|
214
|
+
.isDisabled {
|
|
215
|
+
--button-bg-color: var(--color-gray-400);
|
|
216
|
+
--button-border-color: var(--color-gray-400);
|
|
217
|
+
--button-text-color: var(--color-white);
|
|
218
|
+
|
|
219
|
+
&[data-hovered] {
|
|
220
|
+
--button-bg-color: var(--color-gray-400);
|
|
221
|
+
--button-border-color: var(--color-gray-400);
|
|
222
|
+
}
|
|
223
|
+
}
|
|
224
|
+
|
|
225
|
+
.hideContentWidth {
|
|
226
|
+
position: absolute;
|
|
227
|
+
left: 50%;
|
|
228
|
+
top: 50%;
|
|
229
|
+
transform: translate(-50%, -50%);
|
|
230
|
+
visibility: hidden;
|
|
231
|
+
}
|
|
232
|
+
|
|
233
|
+
.retainContentWidth {
|
|
234
|
+
visibility: hidden;
|
|
235
|
+
}
|
|
@@ -1,44 +1,107 @@
|
|
|
1
|
-
import React from "react"
|
|
1
|
+
import React, { forwardRef } from "react"
|
|
2
2
|
import {
|
|
3
3
|
Button as RACButton,
|
|
4
4
|
ButtonProps as RACButtonProps,
|
|
5
5
|
} from "react-aria-components"
|
|
6
6
|
import { useReversedColors } from "~components/__utilities__/v3"
|
|
7
7
|
import { mergeClassNames } from "~components/utils/mergeClassNames"
|
|
8
|
-
import
|
|
8
|
+
import { ButtonContent, PendingContent } from "./subcomponents"
|
|
9
|
+
import { ButtonSizes, ButtonVariants, PendingButtonProps } from "./types"
|
|
10
|
+
import styles from "./Button.module.css"
|
|
9
11
|
|
|
10
|
-
|
|
11
|
-
|
|
12
|
-
|
|
12
|
+
type ButtonBaseProps = Omit<RACButtonProps, "children"> & {
|
|
13
|
+
/** Used as the label for the button. */
|
|
14
|
+
children: RACButtonProps["children"]
|
|
15
|
+
/** Visually hides the Button's child content used as the label and the `pendingLabel`. Use for icon-only `Button`. @default "false" */
|
|
16
|
+
hasHiddenLabel?: boolean
|
|
13
17
|
/** The visual style of the button.
|
|
14
18
|
* @default "default" */
|
|
15
19
|
variant?: ButtonVariants
|
|
16
20
|
/** The visual size of the button. `medium` was formerly `regular`
|
|
17
21
|
* @default "medium" */
|
|
18
|
-
size?:
|
|
22
|
+
size?: ButtonSizes
|
|
23
|
+
/** Renders an icon at the `iconPosition` provided. To the size scales with the button, we recommend using the `Icon` component from `"@kaizen/components/future"` */
|
|
24
|
+
icon?: JSX.Element
|
|
25
|
+
/** Controls the position of the Icon passed in as props. @default "start" */
|
|
26
|
+
iconPosition?: "start" | "end"
|
|
27
|
+
/** Controls if the button inherits width from its parent. @default "false" */
|
|
28
|
+
isFullWidth?: boolean
|
|
19
29
|
}
|
|
20
30
|
|
|
21
|
-
export
|
|
22
|
-
variant = "default",
|
|
23
|
-
className,
|
|
24
|
-
size = "medium",
|
|
25
|
-
children,
|
|
26
|
-
...otherProps
|
|
27
|
-
}: ButtonProps): JSX.Element => {
|
|
28
|
-
const isReversed = useReversedColors()
|
|
31
|
+
export type ButtonProps = ButtonBaseProps & PendingButtonProps
|
|
29
32
|
|
|
30
|
-
|
|
31
|
-
|
|
32
|
-
|
|
33
|
-
|
|
34
|
-
|
|
35
|
-
|
|
36
|
-
|
|
37
|
-
|
|
38
|
-
|
|
39
|
-
|
|
40
|
-
|
|
41
|
-
|
|
42
|
-
|
|
43
|
-
|
|
44
|
-
|
|
33
|
+
export const Button = forwardRef(
|
|
34
|
+
(
|
|
35
|
+
{
|
|
36
|
+
variant = "primary",
|
|
37
|
+
size = "medium",
|
|
38
|
+
className,
|
|
39
|
+
children,
|
|
40
|
+
isDisabled,
|
|
41
|
+
isFullWidth = false,
|
|
42
|
+
icon,
|
|
43
|
+
iconPosition,
|
|
44
|
+
hasHiddenLabel = false,
|
|
45
|
+
isPending,
|
|
46
|
+
hasHiddenPendingLabel: propsHasHiddenPendingLabel = false,
|
|
47
|
+
pendingLabel,
|
|
48
|
+
...restProps
|
|
49
|
+
}: ButtonProps,
|
|
50
|
+
ref: React.ForwardedRef<HTMLButtonElement>
|
|
51
|
+
) => {
|
|
52
|
+
const isReversed = useReversedColors()
|
|
53
|
+
const pendingProps: PendingButtonProps = isPending
|
|
54
|
+
? {
|
|
55
|
+
isPending,
|
|
56
|
+
hasHiddenPendingLabel: hasHiddenLabel || propsHasHiddenPendingLabel,
|
|
57
|
+
pendingLabel,
|
|
58
|
+
}
|
|
59
|
+
: {}
|
|
60
|
+
const buttonContentClass = isPending
|
|
61
|
+
? !hasHiddenLabel && propsHasHiddenPendingLabel
|
|
62
|
+
? styles.retainContentWidth
|
|
63
|
+
: styles.hideContentWidth
|
|
64
|
+
: undefined
|
|
65
|
+
|
|
66
|
+
return (
|
|
67
|
+
<RACButton
|
|
68
|
+
ref={ref}
|
|
69
|
+
className={mergeClassNames(
|
|
70
|
+
styles.button,
|
|
71
|
+
styles[size],
|
|
72
|
+
hasHiddenLabel && styles[`${size}IconButton`],
|
|
73
|
+
isDisabled && styles.isDisabled,
|
|
74
|
+
isReversed ? styles[`${variant}Reversed`] : styles[variant],
|
|
75
|
+
isFullWidth && styles.fullWidth,
|
|
76
|
+
className
|
|
77
|
+
)}
|
|
78
|
+
isDisabled={isDisabled}
|
|
79
|
+
isPending={isPending}
|
|
80
|
+
{...restProps}
|
|
81
|
+
>
|
|
82
|
+
{racStateProps => {
|
|
83
|
+
const childIsFunction = typeof children === "function"
|
|
84
|
+
|
|
85
|
+
return (
|
|
86
|
+
<>
|
|
87
|
+
<ButtonContent
|
|
88
|
+
size={size}
|
|
89
|
+
icon={icon}
|
|
90
|
+
iconPosition={iconPosition}
|
|
91
|
+
hasHiddenLabel={hasHiddenLabel}
|
|
92
|
+
className={buttonContentClass}
|
|
93
|
+
>
|
|
94
|
+
{childIsFunction ? children(racStateProps) : children}
|
|
95
|
+
</ButtonContent>
|
|
96
|
+
<span aria-live="polite">
|
|
97
|
+
{pendingProps.isPending && (
|
|
98
|
+
<PendingContent {...pendingProps} size={size} />
|
|
99
|
+
)}
|
|
100
|
+
</span>
|
|
101
|
+
</>
|
|
102
|
+
)
|
|
103
|
+
}}
|
|
104
|
+
</RACButton>
|
|
105
|
+
)
|
|
106
|
+
}
|
|
107
|
+
)
|
|
@@ -0,0 +1,150 @@
|
|
|
1
|
+
import { Canvas, Meta, Controls, ArgTypes, DocsStory } from "@storybook/blocks"
|
|
2
|
+
import { ResourceLinks, KAIOInstallation } from "~storybook/components"
|
|
3
|
+
import * as exampleStories from "./Button.docs.stories"
|
|
4
|
+
import * as specStories from "./Button.spec.stories"
|
|
5
|
+
|
|
6
|
+
<Meta title="Actions/Button/Button (v3)/API Specification" />
|
|
7
|
+
|
|
8
|
+
# Button API Specification (v3)
|
|
9
|
+
|
|
10
|
+
Updated Nov 19, 2024
|
|
11
|
+
|
|
12
|
+
<ResourceLinks
|
|
13
|
+
sourceCode="https://github.com/cultureamp/kaizen-design-system/tree/main/packages/components/src/__actions__/Button/v3"
|
|
14
|
+
figma="https://www.figma.com/design/eZKEE5kXbEMY3lx84oz8iN/branch/sPhYSlgPScLOAOYfAbkaI5/%F0%9F%92%9C-Heart-UI-Kit?node-id=1929-17364&node-type=canvas&m=dev"
|
|
15
|
+
designGuidelines="/?path=/docs/actions-button-button-v3-usage-guidelines--docs"
|
|
16
|
+
/>
|
|
17
|
+
|
|
18
|
+
<KAIOInstallation exportNames={["Button" ]} family="actions" version="3" />
|
|
19
|
+
|
|
20
|
+
## Overview
|
|
21
|
+
|
|
22
|
+
`Button` allows users to perform an action. If the component needs to navigate somewhere and can be opened in a new tab, use a [link instead](#buttons-and-links).
|
|
23
|
+
|
|
24
|
+
The following example and table showcases the essential props that enable the core functionality of `Button`. For the remaining suite of API options refer to [this section](#additional-api-options).
|
|
25
|
+
|
|
26
|
+
<Canvas of={exampleStories.Playground} />
|
|
27
|
+
|
|
28
|
+
<Controls of={exampleStories.Playground} className="mb-64" include={["children", "hasHiddenLabel", "className", "size", "variant", "onPress", "icon", "iconPosition", "isFullWidth", "isDisabled", "isPending","pendingLabel", "hasHiddenPendingLabel" ]} />
|
|
29
|
+
|
|
30
|
+
## Buttons and links
|
|
31
|
+
|
|
32
|
+
The `Button` component does not support the `href` property or have any inbuilt routing support. This component is intended as a semantic button and should only be used to perform actions on a page. We advise against passing in an `anchor` tag as a child of the `Button` as this can lead to accessibility issues.
|
|
33
|
+
|
|
34
|
+
A `LinkButton` component will be provided in the future to handle routing and navigation use cases. In the meantime, we recommend staying on [Button V1](/docs/actions-button-button-v1--docs) if an `href` is needed.
|
|
35
|
+
|
|
36
|
+
## API
|
|
37
|
+
|
|
38
|
+
This is built on top of [React Aria's Button component](https://react-spectrum.adobe.com/react-aria/Button.html#props) and seeks to provide a flexible API with convenient abstractions that handles variants, sizes, pending states and icons.
|
|
39
|
+
|
|
40
|
+
### Variants
|
|
41
|
+
|
|
42
|
+
`Button` supports the following variants: `primary`, `secondary` and `tertiary`. If the `variant` prop is not specified, the default will be `primary`.
|
|
43
|
+
|
|
44
|
+
<Canvas of={exampleStories.ButtonVariants} />
|
|
45
|
+
|
|
46
|
+
Reversed variants are handled via the `ReversedColors` Provider - read more on this in the [reversed colors section](#reversed-colors).
|
|
47
|
+
|
|
48
|
+
<DocsStory of={exampleStories.ButtonVariantsReversed} expanded={false} />
|
|
49
|
+
|
|
50
|
+
To enable the reversed theme, you will need to wrap the component or application in the `ReversedColors` provider, ie:
|
|
51
|
+
|
|
52
|
+
```tsx
|
|
53
|
+
import { Button } from "@kaizen/components/v3/actions"
|
|
54
|
+
import { ReversedColors } from "@kaizen/components/v3/utilities"
|
|
55
|
+
// application code
|
|
56
|
+
|
|
57
|
+
return (
|
|
58
|
+
<ReversedColors isReversed={true}>
|
|
59
|
+
<Button {...buttonProps} />
|
|
60
|
+
</ReversedColors>
|
|
61
|
+
)
|
|
62
|
+
```
|
|
63
|
+
|
|
64
|
+
### Sizes
|
|
65
|
+
|
|
66
|
+
Button supports the following sizes: `small`, `medium` and `large`. If the `size` prop is not specified, the default will be `medium`.
|
|
67
|
+
|
|
68
|
+
<Canvas of={exampleStories.ButtonSizes} />
|
|
69
|
+
|
|
70
|
+
### `onPress` vs `onClick`
|
|
71
|
+
|
|
72
|
+
One key change to the `Button`'s API is the shift from `onClick` to React Aria's implementation of `onPress`. This approach has been adopted as it provides better support for consistent touch events across device types, such mobile, desktop and tablet. You can read more about the development and reason behind this pattern [here](https://react-spectrum.adobe.com/blog/building-a-button-part-1.html#touch-interactions).
|
|
73
|
+
|
|
74
|
+
Functionally this does not change the way we pass actions into `Button`. Consumers can safely replace `onClick` with `onPress` without any additional changes, ie:
|
|
75
|
+
|
|
76
|
+
```tsx
|
|
77
|
+
<Button label="Submit" onClick={e => sumbit(e)}/>
|
|
78
|
+
```
|
|
79
|
+
|
|
80
|
+
Can safely be replaced with the following:
|
|
81
|
+
|
|
82
|
+
```tsx
|
|
83
|
+
<Button onPress={e => submit(e)}>
|
|
84
|
+
Submit
|
|
85
|
+
</Button>
|
|
86
|
+
```
|
|
87
|
+
|
|
88
|
+
### Button content and children
|
|
89
|
+
|
|
90
|
+
Labels and any button content can be passed into the `Button` as `children`. Content wrapped by the `Button` will be spaced evenly relative to the `size` prop.
|
|
91
|
+
|
|
92
|
+
```tsx
|
|
93
|
+
<Button variant="secondary" onPress={e => submit(e)}>
|
|
94
|
+
Label
|
|
95
|
+
</Button>
|
|
96
|
+
```
|
|
97
|
+
|
|
98
|
+
While in most cases, `children` will be a `ReactNode`, `Button` also accepts a render function with React Aria's `ButtonRenderProps`. This allows for more advanced styling and rendering options by hooking into React Aria's internal button state. You can read more about this [here](https://react-spectrum.adobe.com/react-aria/Button.html#styling).
|
|
99
|
+
|
|
100
|
+
### Icons and positioning
|
|
101
|
+
|
|
102
|
+
The `icon` property abstracts the need to handle positioning and sizing logic for icons within the `Button`. When paired with the [Icon component](/docs/illustrations-icon-icon-future-api-specification--docs), this will scale the icon to the `Button`'s `size` prop.
|
|
103
|
+
|
|
104
|
+
<Canvas of={exampleStories.ButtonWithIconStart} />
|
|
105
|
+
|
|
106
|
+
Set the position of the icon using the `iconPosition` prop. This will ensure content is flipped in `RTL` layouts. Note that icons will need the [shouldMirrorInRTL](/docs/illustrations-icon-icon-future-api-specification--docs#mirror-in-rtl) prop set to `true` when mirroring is required.
|
|
107
|
+
|
|
108
|
+
<Canvas of={exampleStories.ButtonWithIconEnd} />
|
|
109
|
+
|
|
110
|
+
|
|
111
|
+
### Icon-only `Button` and `hasHiddenLabel`
|
|
112
|
+
|
|
113
|
+
To achieve an icon-only `Button` (previously: `IconButton`) use the `icon` prop and set `hasHiddenLabel` to `true`. This will visually hide the button's `children` and `pendingLabel`, while still announcing the content to screen readers.
|
|
114
|
+
|
|
115
|
+
<Canvas of={exampleStories.IconButton} className="mb-32" />
|
|
116
|
+
|
|
117
|
+
This pattern ensures that the `Button`'s accessible name is determined by its children, which helps to announce relevant content to the screen readers, as with the [pending state](#pending-state). You can learn more about this [accessible pattern here](https://cultureamp.atlassian.net/wiki/spaces/PA/pages/3833331831/Accessible+button+and+link+labels).
|
|
118
|
+
|
|
119
|
+
### Pending state
|
|
120
|
+
|
|
121
|
+
`isPending` and `pendingLabel` are used to indicate that an interaction is in progress. This will disable the `Button`'s press events while rendering a loading spinner and `pendingLabel`.
|
|
122
|
+
|
|
123
|
+
<Canvas of={specStories.PendingButton} />
|
|
124
|
+
|
|
125
|
+
This can be paired with the `hasHiddenPendingLabel` prop to visually hide the `pendingLabel` and maintain the content width. This is ideal for avoid layout shifts when space is a commodity.
|
|
126
|
+
|
|
127
|
+
The `pendingLabel` should be short and declarative as this will be announced to a screen reader regardless of its visibility.
|
|
128
|
+
|
|
129
|
+
<Canvas of={specStories.PendingButtonWithHiddenPendingLabel} />
|
|
130
|
+
|
|
131
|
+
As mentioned in the [previous section](#icon-only-button-and-hashiddenlabel), an icon-only `Button` uses `hasHiddenLabel` to visually hide both the `pendingLabel` and child content, so `hasHiddenPendingLabel` is not needed.
|
|
132
|
+
|
|
133
|
+
<Canvas of={specStories.PendingIconButton} />
|
|
134
|
+
|
|
135
|
+
|
|
136
|
+
### Full width Buttons
|
|
137
|
+
|
|
138
|
+
If a button is statically the full width of a container you can use the `isFullWidth` property.
|
|
139
|
+
|
|
140
|
+
<Canvas of={exampleStories.ButtonFullWidth} />
|
|
141
|
+
|
|
142
|
+
For resizing on smaller screens, consider using the `className` prop to leverage CSS media or container queries, ie: `<Button className="w-full md:w-[initial]">Label</Button>`.
|
|
143
|
+
|
|
144
|
+
## Additional API options
|
|
145
|
+
|
|
146
|
+
The following table is a collection of additional React Aria and native HTML props that are exposed from the React Aria API. These are not required for the implementation of `Button` but can be used to extend its functionality. Refer back to the [overview section](#overview) for the core props that enable most use cases.
|
|
147
|
+
|
|
148
|
+
You can learn more about React Aria's Button API and advance configuration options [here](https://react-spectrum.adobe.com/react-aria/Button.html#props).
|
|
149
|
+
|
|
150
|
+
<ArgTypes of={exampleStories.Playground} exclude={["children", "hasHiddenLabel", "className", "size", "variant", "onPress", "icon", "iconPosition", "isFullWidth", "isDisabled", "isPending", "pendingLabel", "hasHiddenPendingLabel" ]} />
|
|
@@ -0,0 +1,30 @@
|
|
|
1
|
+
import { Canvas, Meta, Controls } from "@storybook/blocks"
|
|
2
|
+
import { ResourceLinks, Installation } from "~storybook/components"
|
|
3
|
+
import * as Button from "./Button.docs.stories"
|
|
4
|
+
|
|
5
|
+
<Meta title="Actions/Button/Button (v3)/Usage Guidelines" />
|
|
6
|
+
|
|
7
|
+
# Button (v3)
|
|
8
|
+
|
|
9
|
+
Updated July 12, 2024
|
|
10
|
+
|
|
11
|
+
<ResourceLinks
|
|
12
|
+
sourceCode="https://github.com/cultureamp/kaizen-design-system/tree/main/packages/components/src/__actions__/Button/v3"
|
|
13
|
+
figma="https://www.figma.com/design/eZKEE5kXbEMY3lx84oz8iN/branch/sPhYSlgPScLOAOYfAbkaI5/%F0%9F%92%9C-Heart-UI-Kit?node-id=1929-17364&node-type=canvas&m=dev"
|
|
14
|
+
apiSpecification="/?path=/docs/actions-button-button-v3-api-specification--docs"
|
|
15
|
+
/>
|
|
16
|
+
|
|
17
|
+
<Installation
|
|
18
|
+
installCommand="pnpm add @kaizen/components"
|
|
19
|
+
importStatement='import { Button } from "@kaizen/components/v3/actions"'
|
|
20
|
+
/>
|
|
21
|
+
|
|
22
|
+
## Overview
|
|
23
|
+
|
|
24
|
+
Buttons allow users to perform an action. They have multiple styles for various needs, and are ideal for calling attention to where a user needs to do something in order to move forward in a flow.
|
|
25
|
+
|
|
26
|
+
<Canvas of={Button.Playground} />
|
|
27
|
+
|
|
28
|
+
<Controls of={Button.Playground} include={["children", "variant", "size", "isDisabled", "icon", "iconPosition"]} className="mb-64" />
|
|
29
|
+
|
|
30
|
+
|