@superdispatch/ui-lab 0.21.8 → 0.21.12

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.
Files changed (97) hide show
  1. package/.babelrc.js +5 -0
  2. package/.turbo/turbo-version.log +28 -0
  3. package/package.json +59 -34
  4. package/pkg/README.md +10 -0
  5. package/{dist-node → pkg/dist-node}/index.js +25 -23
  6. package/pkg/dist-node/index.js.map +1 -0
  7. package/{dist-src → pkg/dist-src}/alert/Alert.js +2 -4
  8. package/{dist-src → pkg/dist-src}/banner/Banner.js +0 -0
  9. package/{dist-src → pkg/dist-src}/box/Box.js +0 -0
  10. package/{dist-src → pkg/dist-src}/button/Button.js +0 -0
  11. package/{dist-src → pkg/dist-src}/button-area/ButtonArea.js +0 -0
  12. package/{dist-src → pkg/dist-src}/container/Container.js +0 -0
  13. package/{dist-src → pkg/dist-src}/description-item/DescriptionItem.js +0 -0
  14. package/{dist-src → pkg/dist-src}/file-drop-zone/FileDropZone.js +0 -0
  15. package/{dist-src → pkg/dist-src}/file-list-item/FileListItem.js +0 -0
  16. package/{dist-src → pkg/dist-src}/index.js +0 -0
  17. package/{dist-src → pkg/dist-src}/linked-text/LinkedText.js +0 -0
  18. package/{dist-src → pkg/dist-src}/multiline-text/MultilineText.js +0 -0
  19. package/{dist-src → pkg/dist-src}/navbar/Navbar.js +0 -0
  20. package/{dist-src → pkg/dist-src}/navbar/NavbarAccordion.js +5 -10
  21. package/{dist-src → pkg/dist-src}/navbar/NavbarAvatar.js +0 -0
  22. package/{dist-src → pkg/dist-src}/navbar/NavbarBottomBar.js +16 -6
  23. package/{dist-src → pkg/dist-src}/navbar/NavbarContext.js +0 -0
  24. package/{dist-src → pkg/dist-src}/navbar/NavbarItem.js +0 -0
  25. package/{dist-src → pkg/dist-src}/navbar/NavbarList.js +0 -0
  26. package/{dist-src → pkg/dist-src}/navbar/NavbarMenu.js +0 -0
  27. package/{dist-src → pkg/dist-src}/sidebar/Sidebar.js +0 -0
  28. package/{dist-src → pkg/dist-src}/sidebar/SidebarBackButton.js +0 -0
  29. package/{dist-src → pkg/dist-src}/sidebar/SidebarContainer.js +0 -0
  30. package/{dist-src → pkg/dist-src}/sidebar/SidebarContent.js +0 -0
  31. package/{dist-src → pkg/dist-src}/sidebar/SidebarDivider.js +0 -0
  32. package/{dist-src → pkg/dist-src}/sidebar/SidebarMenuItem.js +0 -0
  33. package/{dist-src → pkg/dist-src}/sidebar/SidebarMenuItemAction.js +0 -0
  34. package/{dist-src → pkg/dist-src}/sidebar/SidebarMenuItemAvatar.js +0 -0
  35. package/{dist-src → pkg/dist-src}/sidebar/SidebarMenuItemContext.js +0 -0
  36. package/{dist-src → pkg/dist-src}/sidebar/SidebarSubheader.js +0 -0
  37. package/{dist-src → pkg/dist-src}/text-box/TextBox.js +0 -0
  38. package/{dist-src → pkg/dist-src}/utils/RuleNormalizer.js +0 -0
  39. package/{dist-src → pkg/dist-src}/utils/mergeStyles.js +0 -0
  40. package/{dist-types → pkg/dist-types}/index.d.ts +308 -308
  41. package/{dist-web → pkg/dist-web}/index.js +26 -24
  42. package/pkg/dist-web/index.js.map +1 -0
  43. package/pkg/package.json +34 -0
  44. package/playroom.ts +23 -0
  45. package/src/alert/Alert.stories.tsx +105 -0
  46. package/src/alert/Alert.tsx +108 -0
  47. package/src/banner/Banner.stories.tsx +64 -0
  48. package/src/banner/Banner.tsx +120 -0
  49. package/src/box/Box.stories.tsx +20 -0
  50. package/src/box/Box.tsx +252 -0
  51. package/src/button/Button.stories.tsx +717 -0
  52. package/src/button/Button.tsx +460 -0
  53. package/src/button-area/ButtonArea.stories.tsx +65 -0
  54. package/src/button-area/ButtonArea.tsx +88 -0
  55. package/src/container/Container.tsx +48 -0
  56. package/src/description-item/DescriptionItem.stories.tsx +163 -0
  57. package/src/description-item/DescriptionItem.tsx +104 -0
  58. package/src/file-drop-zone/FileDropZone.stories.tsx +44 -0
  59. package/src/file-drop-zone/FileDropZone.tsx +170 -0
  60. package/src/file-list-item/FileListItem.stories.tsx +37 -0
  61. package/src/file-list-item/FileListItem.tsx +145 -0
  62. package/src/file-list-item/__tests__/FileListItem.spec.tsx +339 -0
  63. package/src/index.spec.ts +43 -0
  64. package/src/index.ts +28 -0
  65. package/src/linked-text/LinkeText.stories.tsx +42 -0
  66. package/src/linked-text/LinkedText.tsx +47 -0
  67. package/src/multiline-text/MultilineText.stories.tsx +30 -0
  68. package/src/multiline-text/MultilineText.ts +16 -0
  69. package/src/navbar/Navbar.stories.tsx +135 -0
  70. package/src/navbar/Navbar.tsx +111 -0
  71. package/src/navbar/NavbarAccordion.tsx +171 -0
  72. package/src/navbar/NavbarAvatar.tsx +51 -0
  73. package/src/navbar/NavbarBottomBar.tsx +135 -0
  74. package/src/navbar/NavbarContext.tsx +23 -0
  75. package/src/navbar/NavbarItem.tsx +119 -0
  76. package/src/navbar/NavbarList.tsx +225 -0
  77. package/src/navbar/NavbarMenu.tsx +102 -0
  78. package/src/sidebar/Sidebar.stories.tsx +363 -0
  79. package/src/sidebar/Sidebar.tsx +73 -0
  80. package/src/sidebar/SidebarBackButton.tsx +33 -0
  81. package/src/sidebar/SidebarContainer.tsx +114 -0
  82. package/src/sidebar/SidebarContent.tsx +119 -0
  83. package/src/sidebar/SidebarDivider.tsx +15 -0
  84. package/src/sidebar/SidebarMenuItem.tsx +211 -0
  85. package/src/sidebar/SidebarMenuItemAction.tsx +27 -0
  86. package/src/sidebar/SidebarMenuItemAvatar.tsx +59 -0
  87. package/src/sidebar/SidebarMenuItemContext.tsx +33 -0
  88. package/src/sidebar/SidebarSubheader.tsx +38 -0
  89. package/src/styled.d.ts +12 -0
  90. package/src/text-box/TextBox.stories.tsx +108 -0
  91. package/src/text-box/TextBox.tsx +229 -0
  92. package/src/utils/RuleNormalizer.ts +24 -0
  93. package/src/utils/mergeStyles.ts +28 -0
  94. package/tsconfig.json +19 -0
  95. package/LICENSE +0 -21
  96. package/dist-node/index.js.map +0 -1
  97. package/dist-web/index.js.map +0 -1
@@ -0,0 +1,460 @@
1
+ import { CircularProgress } from '@material-ui/core';
2
+ import { Color } from '@superdispatch/ui';
3
+ import {
4
+ AriaAttributes,
5
+ FocusEventHandler,
6
+ forwardRef,
7
+ HTMLAttributes,
8
+ MouseEventHandler,
9
+ ReactNode,
10
+ } from 'react';
11
+ import styled, { css } from 'styled-components';
12
+
13
+ export type ButtonSizeProp = 'small' | 'medium' | 'large';
14
+ export type ButtonVariantProp =
15
+ | 'critical'
16
+ | 'default'
17
+ | 'inverted'
18
+ | 'neutral'
19
+ | 'primary'
20
+ | 'text';
21
+
22
+ interface ButtonStyleProps {
23
+ disabled: boolean;
24
+ fullWidth: boolean;
25
+ size: ButtonSizeProp;
26
+ variant: ButtonVariantProp;
27
+ }
28
+
29
+ interface ButtonVariables {
30
+ fontSize: number;
31
+ fontSizeMobile: number;
32
+ lineHeight: number;
33
+ lineHeightMobile: number;
34
+
35
+ paddingX: number;
36
+ paddingXMobile: number;
37
+ paddingY: number;
38
+ paddingYMobile: number;
39
+
40
+ textColor: Color;
41
+ textColorHovered: Color;
42
+ textColorDisabled: Color;
43
+
44
+ outlineColor: Color;
45
+
46
+ borderColor: Color;
47
+ borderColorHovered: Color;
48
+ borderColorDisabled: Color;
49
+
50
+ backgroundColor: Color;
51
+ backgroundColorActive: Color;
52
+ backgroundColorHovered: Color;
53
+ backgroundColorDisabled: Color;
54
+ }
55
+
56
+ function createButtonVariables(
57
+ size: ButtonSizeProp,
58
+ {
59
+ fontSize = size === 'large' ? 16 : 14,
60
+ lineHeight = size === 'large' ? 24 : 20,
61
+ fontSizeMobile = size === 'large' ? 18 : 16,
62
+ lineHeightMobile = size === 'large' ? 28 : 24,
63
+
64
+ paddingX = size === 'large' ? 32 : 16,
65
+ paddingY = size === 'large' ? 8 : size === 'small' ? 2 : 6,
66
+ paddingXMobile = size === 'large' ? 64 : 24,
67
+ paddingYMobile = size === 'large' ? 14 : size === 'small' ? 4 : 10,
68
+
69
+ textColor = Color.Transparent,
70
+ textColorHovered = textColor,
71
+ textColorDisabled = textColor,
72
+
73
+ outlineColor = Color.Transparent,
74
+
75
+ borderColor = Color.Transparent,
76
+ borderColorHovered = borderColor,
77
+ borderColorDisabled = borderColor,
78
+
79
+ backgroundColor = Color.Transparent,
80
+ backgroundColorHovered = backgroundColor,
81
+ backgroundColorActive = backgroundColorHovered,
82
+ backgroundColorDisabled = backgroundColor,
83
+ }: Partial<ButtonVariables>,
84
+ ): ButtonVariables {
85
+ return {
86
+ paddingX,
87
+ paddingY,
88
+ fontSize,
89
+ lineHeight,
90
+
91
+ paddingXMobile,
92
+ paddingYMobile,
93
+ fontSizeMobile,
94
+ lineHeightMobile,
95
+
96
+ textColor,
97
+ borderColor,
98
+ outlineColor,
99
+ backgroundColor,
100
+
101
+ textColorHovered,
102
+ borderColorHovered,
103
+ backgroundColorHovered,
104
+
105
+ backgroundColorActive,
106
+
107
+ textColorDisabled,
108
+ borderColorDisabled,
109
+ backgroundColorDisabled,
110
+ };
111
+ }
112
+
113
+ function getDefaultVariables(size: ButtonSizeProp): ButtonVariables {
114
+ return createButtonVariables(size, {
115
+ textColor: Color.White,
116
+ outlineColor: Color.Blue100,
117
+ backgroundColor: Color.Blue300,
118
+
119
+ textColorHovered: Color.White,
120
+ backgroundColorHovered: Color.Blue500,
121
+
122
+ backgroundColorActive: Color.Blue400,
123
+
124
+ backgroundColorDisabled: Color.Blue100,
125
+ });
126
+ }
127
+
128
+ function getPrimaryVariables(size: ButtonSizeProp): ButtonVariables {
129
+ return getDefaultVariables(size);
130
+ }
131
+
132
+ function getNeutralVariables(size: ButtonSizeProp): ButtonVariables {
133
+ return createButtonVariables(size, {
134
+ textColor: Color.Dark500,
135
+ borderColor: Color.Silver500,
136
+ outlineColor: Color.Blue100,
137
+ backgroundColor: Color.White,
138
+
139
+ textColorHovered: Color.Blue300,
140
+ borderColorHovered: Color.Blue300,
141
+ backgroundColorHovered: Color.Blue50,
142
+
143
+ backgroundColorActive: Color.Blue75,
144
+
145
+ textColorDisabled: Color.Silver500,
146
+ });
147
+ }
148
+
149
+ function getCriticalVariables(size: ButtonSizeProp): ButtonVariables {
150
+ return createButtonVariables(size, {
151
+ textColor: Color.Red300,
152
+ borderColor: Color.Red300,
153
+ outlineColor: Color.Red75,
154
+ backgroundColor: Color.Red50,
155
+
156
+ backgroundColorHovered: Color.Red75,
157
+
158
+ backgroundColorActive: Color.Red100,
159
+
160
+ textColorDisabled: Color.Red100,
161
+ borderColorDisabled: Color.Red100,
162
+ backgroundColorDisabled: Color.Red50,
163
+ });
164
+ }
165
+
166
+ function getTextVariables(size: ButtonSizeProp): ButtonVariables {
167
+ return createButtonVariables(size, {
168
+ textColor: Color.Blue400,
169
+
170
+ outlineColor: Color.Blue100,
171
+
172
+ textColorHovered: Color.Blue500,
173
+ backgroundColorHovered: Color.Blue50,
174
+
175
+ backgroundColorActive: Color.Blue75,
176
+
177
+ textColorDisabled: Color.Blue100,
178
+ });
179
+ }
180
+
181
+ function getInvertedVariables(size: ButtonSizeProp): ButtonVariables {
182
+ return createButtonVariables(size, {
183
+ textColor: Color.White,
184
+ outlineColor: Color.White40,
185
+ backgroundColor: Color.White20,
186
+
187
+ textColorHovered: Color.White,
188
+ backgroundColorHovered: Color.White40,
189
+
190
+ backgroundColorActive: Color.White20,
191
+
192
+ textColorDisabled: Color.White50,
193
+ backgroundColorDisabled: Color.White08,
194
+ });
195
+ }
196
+
197
+ const ButtonRoot = styled.button<ButtonStyleProps>(
198
+ ({ size, theme, variant, fullWidth }) => {
199
+ const variables =
200
+ variant === 'primary'
201
+ ? getPrimaryVariables(size)
202
+ : variant === 'neutral'
203
+ ? getNeutralVariables(size)
204
+ : variant === 'critical'
205
+ ? getCriticalVariables(size)
206
+ : variant === 'text'
207
+ ? getTextVariables(size)
208
+ : variant === 'inverted'
209
+ ? getInvertedVariables(size)
210
+ : getDefaultVariables(size);
211
+
212
+ return css`
213
+ /* Reset button styles */
214
+ border: 0;
215
+ margin: 0;
216
+ outline: 0;
217
+ position: relative;
218
+ vertical-align: middle;
219
+
220
+ /* Fixes for the anchor element */
221
+ cursor: pointer;
222
+ text-decoration: none;
223
+
224
+ &[aria-disabled='true'] {
225
+ cursor: default;
226
+ /* Disable link interactions */
227
+ pointer-events: none;
228
+ }
229
+
230
+ /* Firefox fixes */
231
+ -moz-appearance: none;
232
+
233
+ &::-moz-focus-inner {
234
+ /* Remove Firefox dotted outline */
235
+ border-style: none;
236
+ }
237
+
238
+ /* Webkit fixes */
239
+ -webkit-appearance: none;
240
+ -webkit-user-select: none;
241
+ -webkit-tap-highlight-color: transparent;
242
+ @media print {
243
+ -webkit-print-color-adjust: exact;
244
+ }
245
+
246
+ /* Button styles */
247
+
248
+ --button-visibility: visible;
249
+ --button-text-color: ${variables.textColor};
250
+ --button-border-color: ${variables.borderColor};
251
+ --button-outline-color: ${Color.Transparent};
252
+ --button-background-color: ${variables.backgroundColor};
253
+
254
+ --button-padding-x: ${variables.paddingXMobile}px;
255
+ --button-padding-y: ${variables.paddingYMobile}px;
256
+ --button-font-size: ${variables.fontSizeMobile}px;
257
+ --button-line-height: ${variables.lineHeightMobile}px;
258
+
259
+ ${theme.breakpoints.up('sm')} {
260
+ --button-padding-x: ${variables.paddingX}px;
261
+ --button-padding-y: ${variables.paddingY}px;
262
+ --button-font-size: ${variables.fontSize}px;
263
+ --button-line-height: ${variables.lineHeight}px;
264
+ }
265
+
266
+ &[aria-disabled='true'] {
267
+ --button-text-color: ${variables.textColorDisabled};
268
+ --button-border-color: ${variables.borderColorDisabled};
269
+ --button-background-color: ${variables.backgroundColorDisabled};
270
+
271
+ &[aria-busy='true'] {
272
+ --button-visibility: hidden;
273
+ }
274
+ }
275
+
276
+ &[aria-disabled='false'] {
277
+ &[aria-expanded='true'] {
278
+ --button-text-color: ${variables.textColorHovered};
279
+ --button-border-color: ${variables.borderColorHovered};
280
+ --button-background-color: ${variables.backgroundColorHovered};
281
+ }
282
+
283
+ &,
284
+ &[aria-expanded='true'] {
285
+ &:focus {
286
+ --button-outline-color: ${variables.outlineColor};
287
+ }
288
+
289
+ @media (hover: hover) and (pointer: fine) {
290
+ &:hover {
291
+ --button-text-color: ${variables.textColorHovered};
292
+ --button-border-color: ${variables.borderColorHovered};
293
+ --button-background-color: ${variables.backgroundColorHovered};
294
+ }
295
+ }
296
+
297
+ &:active {
298
+ --button-background-color: ${variables.backgroundColorActive};
299
+ }
300
+ }
301
+ }
302
+
303
+ display: inline-flex;
304
+ align-items: center;
305
+ justify-content: center;
306
+
307
+ min-width: 48px;
308
+ width: ${fullWidth ? '100%' : 'auto'};
309
+
310
+ border-radius: 4px;
311
+ font-family: ${theme.typography.fontFamily};
312
+ font-weight: ${theme.typography.fontWeightBold};
313
+
314
+ color: var(--button-text-color);
315
+ background-color: var(--button-background-color);
316
+ font-size: var(--button-font-size);
317
+ line-height: var(--button-line-height);
318
+ padding: var(--button-padding-y) var(--button-padding-x);
319
+
320
+ box-shadow: inset 0 0 0 1px var(--button-border-color),
321
+ 0 0 0 2px var(--button-outline-color);
322
+
323
+ transition: ${theme.transitions.create([
324
+ 'color',
325
+ 'box-shadow',
326
+ 'background-color',
327
+ ])};
328
+ `;
329
+ },
330
+ );
331
+
332
+ const ButtonLabel = styled.span`
333
+ display: inherit;
334
+ align-items: inherit;
335
+ justify-content: inherit;
336
+ visibility: var(--button-visibility);
337
+ --mui-svg-icon-size: var(--button-line-height);
338
+ `;
339
+
340
+ const ButtonStartIcon = styled.span`
341
+ margin-right: 4px;
342
+ `;
343
+
344
+ const ButtonEndIcon = styled.span`
345
+ margin-left: 4px;
346
+ `;
347
+
348
+ const ButtonPendingIndicator = styled.span`
349
+ left: 50%;
350
+ display: flex;
351
+ position: absolute;
352
+ visibility: visible;
353
+ transform: translate(-50%);
354
+ `;
355
+
356
+ interface BaseButtonProps<T extends HTMLElement>
357
+ extends Pick<
358
+ AriaAttributes,
359
+ 'aria-label' | 'aria-controls' | 'aria-haspopup' | 'aria-labelledby'
360
+ > {
361
+ active?: boolean;
362
+ pending?: boolean;
363
+ disabled?: boolean;
364
+ autoFocus?: boolean;
365
+
366
+ fullWidth?: boolean;
367
+ size?: ButtonSizeProp;
368
+ variant?: ButtonVariantProp;
369
+
370
+ children?: ReactNode;
371
+ startIcon?: ReactNode;
372
+ endIcon?: ReactNode;
373
+
374
+ id?: string;
375
+ tabIndex?: number;
376
+
377
+ onClick?: MouseEventHandler<T>;
378
+ onFocus?: FocusEventHandler<T>;
379
+ onBlur?: FocusEventHandler<T>;
380
+ }
381
+
382
+ function useButtonProps<T extends HTMLElement>({
383
+ children,
384
+
385
+ endIcon,
386
+ startIcon,
387
+
388
+ tabIndex: tabIndexProp = 0,
389
+
390
+ active = false,
391
+ pending = false,
392
+ disabled: disabledProp = false,
393
+
394
+ size = 'medium',
395
+ fullWidth = false,
396
+ variant = 'default',
397
+ ...props
398
+ }: BaseButtonProps<T>): ButtonStyleProps & HTMLAttributes<T> {
399
+ const disabled = pending || disabledProp;
400
+ const tabIndex = disabled ? -1 : tabIndexProp;
401
+
402
+ return {
403
+ ...props,
404
+ size,
405
+ variant,
406
+ fullWidth,
407
+ tabIndex,
408
+ disabled,
409
+ 'aria-busy': pending,
410
+ 'aria-expanded': active,
411
+ 'aria-disabled': disabled,
412
+ children: (
413
+ <ButtonLabel>
414
+ {!!startIcon && <ButtonStartIcon>{startIcon}</ButtonStartIcon>}
415
+ {children}
416
+ {!!endIcon && <ButtonEndIcon>{endIcon}</ButtonEndIcon>}
417
+ {pending && (
418
+ <ButtonPendingIndicator>
419
+ <CircularProgress size="1em" color="inherit" />
420
+ </ButtonPendingIndicator>
421
+ )}
422
+ </ButtonLabel>
423
+ ),
424
+ };
425
+ }
426
+
427
+ export interface ButtonProps extends BaseButtonProps<HTMLButtonElement> {
428
+ type?: 'button' | 'submit';
429
+ }
430
+
431
+ export const Button = forwardRef<HTMLButtonElement, ButtonProps>(
432
+ ({ type = 'button', ...props }, ref) => {
433
+ const buttonProps = useButtonProps(props);
434
+
435
+ return <ButtonRoot {...buttonProps} ref={ref} type={type} />;
436
+ },
437
+ );
438
+
439
+ export interface AnchorButtonProps extends BaseButtonProps<HTMLAnchorElement> {
440
+ href: string;
441
+ target?: '_self' | '_blank';
442
+ }
443
+
444
+ export const AnchorButton = forwardRef<HTMLAnchorElement, AnchorButtonProps>(
445
+ ({ href, target, ...props }, ref) => {
446
+ const buttonProps = useButtonProps(props);
447
+ const rel = target === '_blank' ? 'noopener noreferrer' : undefined;
448
+
449
+ return (
450
+ <ButtonRoot
451
+ {...buttonProps}
452
+ as="a"
453
+ ref={ref}
454
+ rel={rel}
455
+ href={href}
456
+ target={target}
457
+ />
458
+ );
459
+ },
460
+ );
@@ -0,0 +1,65 @@
1
+ import { ThumbDown, ThumbUp } from '@material-ui/icons';
2
+ import { Meta } from '@storybook/react';
3
+ import { Column, Columns, Stack } from '@superdispatch/ui';
4
+ import { ButtonArea } from './ButtonArea';
5
+
6
+ export default {
7
+ title: 'Lab/ButtonArea',
8
+ component: ButtonArea,
9
+ } as Meta;
10
+
11
+ export const basic = () => (
12
+ <Columns space="small">
13
+ <Column>
14
+ <Stack>
15
+ <ButtonArea fullWidth={true} icon={<ThumbUp />} variant="success">
16
+ Positive
17
+ </ButtonArea>
18
+
19
+ <ButtonArea
20
+ active={true}
21
+ fullWidth={true}
22
+ icon={<ThumbUp />}
23
+ variant="success"
24
+ >
25
+ Positive
26
+ </ButtonArea>
27
+
28
+ <ButtonArea
29
+ disabled={true}
30
+ fullWidth={true}
31
+ icon={<ThumbUp />}
32
+ variant="success"
33
+ >
34
+ Positive
35
+ </ButtonArea>
36
+ </Stack>
37
+ </Column>
38
+
39
+ <Column>
40
+ <Stack>
41
+ <ButtonArea fullWidth={true} icon={<ThumbDown />} variant="danger">
42
+ Negative
43
+ </ButtonArea>
44
+
45
+ <ButtonArea
46
+ active={true}
47
+ fullWidth={true}
48
+ icon={<ThumbDown />}
49
+ variant="danger"
50
+ >
51
+ Negative
52
+ </ButtonArea>
53
+
54
+ <ButtonArea
55
+ disabled={true}
56
+ fullWidth={true}
57
+ icon={<ThumbDown />}
58
+ variant="danger"
59
+ >
60
+ Negative
61
+ </ButtonArea>
62
+ </Stack>
63
+ </Column>
64
+ </Columns>
65
+ );
@@ -0,0 +1,88 @@
1
+ import { ButtonBase, ButtonBaseProps, Typography } from '@material-ui/core';
2
+ import { Color, Stack } from '@superdispatch/ui';
3
+ import { forwardRef, ReactNode } from 'react';
4
+ import styled from 'styled-components';
5
+
6
+ const ButtonRoot = styled(ButtonBase)`
7
+ padding: 12px 32px;
8
+
9
+ border-width: 1px;
10
+ border-radius: 4px;
11
+ border-style: solid;
12
+ border-color: ${Color.Silver500};
13
+
14
+ color: ${Color.Dark100};
15
+ background-color: ${Color.White};
16
+
17
+ & svg {
18
+ color: inherit;
19
+ font-size: 24px;
20
+ }
21
+
22
+ &[data-full-width='true'] {
23
+ width: 100%;
24
+ }
25
+
26
+ &[data-disabled='true'] {
27
+ color: ${Color.Silver500};
28
+ border-color: ${Color.Silver400};
29
+ }
30
+
31
+ &[data-variant='success'] {
32
+ &:hover {
33
+ color: ${Color.Green300};
34
+ box-shadow: 0 0 0 2px ${Color.Green100};
35
+ border-color: ${Color.Green300};
36
+ }
37
+
38
+ &[data-active='true'] {
39
+ color: ${Color.Green300};
40
+ border-color: ${Color.Green300};
41
+ background-color: ${Color.Green50};
42
+ }
43
+ }
44
+
45
+ &[data-variant='danger'] {
46
+ &:hover {
47
+ color: ${Color.Red300};
48
+ box-shadow: 0 0 0 2px ${Color.Red100};
49
+ border-color: ${Color.Red300};
50
+ }
51
+
52
+ &[data-active='true'] {
53
+ color: ${Color.Red300};
54
+ border-color: ${Color.Red300};
55
+ background-color: ${Color.Red50};
56
+ }
57
+ }
58
+ `;
59
+
60
+ type ButtonAreaVariant = 'danger' | 'success';
61
+
62
+ export interface ButtonAreaProps extends ButtonBaseProps {
63
+ icon: ReactNode;
64
+ active?: boolean;
65
+ fullWidth?: boolean;
66
+ variant?: ButtonAreaVariant;
67
+ }
68
+
69
+ export const ButtonArea = forwardRef<HTMLButtonElement, ButtonAreaProps>(
70
+ ({ icon, children, variant, active, disabled, fullWidth, ...props }, ref) => (
71
+ <ButtonRoot
72
+ ref={ref}
73
+ disabled={disabled}
74
+ data-active={active}
75
+ data-disabled={disabled}
76
+ data-variant={variant}
77
+ data-full-width={fullWidth}
78
+ {...props}
79
+ >
80
+ <Stack align="center" space="xxsmall">
81
+ {icon}
82
+ <Typography variant="h4" color={disabled ? 'inherit' : 'textPrimary'}>
83
+ {children}
84
+ </Typography>
85
+ </Stack>
86
+ </ButtonRoot>
87
+ ),
88
+ );
@@ -0,0 +1,48 @@
1
+ import { mergeRefs } from '@superdispatch/ui';
2
+ import { forwardRef, HTMLAttributes, useLayoutEffect, useRef } from 'react';
3
+
4
+ export type ContainerProps = HTMLAttributes<HTMLDivElement> & {
5
+ fullViewportHeight?: boolean;
6
+ };
7
+
8
+ export const Container = forwardRef<HTMLDivElement, ContainerProps>(
9
+ ({ fullViewportHeight, ...props }, ref) => {
10
+ const nodeRef = useRef<HTMLDivElement | null>(null);
11
+
12
+ useLayoutEffect(() => {
13
+ if (!fullViewportHeight) {
14
+ if (nodeRef.current) {
15
+ nodeRef.current.style.removeProperty('height');
16
+ nodeRef.current.style.removeProperty('--vh');
17
+ }
18
+ return;
19
+ }
20
+
21
+ function updateHeight(): void {
22
+ if (nodeRef.current) {
23
+ // https://css-tricks.com/the-trick-to-viewport-units-on-mobile/
24
+ nodeRef.current.style.setProperty(
25
+ 'height',
26
+ 'calc(var(--vh, 1vh) * 100)',
27
+ );
28
+ nodeRef.current.style.setProperty(
29
+ '--vh',
30
+ `${window.innerHeight * 0.01}px`,
31
+ );
32
+ }
33
+ }
34
+
35
+ updateHeight();
36
+
37
+ window.addEventListener('resize', updateHeight);
38
+
39
+ return () => {
40
+ window.removeEventListener('resize', updateHeight);
41
+ };
42
+ }, [fullViewportHeight]);
43
+
44
+ return <div ref={mergeRefs(ref, nodeRef)} {...props} />;
45
+ },
46
+ );
47
+
48
+ Container.displayName = 'Container';