@automattic/vip-design-system 2.1.0 → 2.3.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.
Files changed (101) hide show
  1. package/.eslintrc.js +3 -0
  2. package/build/system/Accordion/Accordion.test.d.ts +0 -1
  3. package/build/system/Accordion/Accordion.test.js +23 -12
  4. package/build/system/Avatar/Avatar.d.ts +0 -1
  5. package/build/system/Avatar/Avatar.js +9 -17
  6. package/build/system/Avatar/Avatar.stories.d.ts +2 -1
  7. package/build/system/Avatar/Avatar.stories.js +19 -2
  8. package/build/system/Button/Button.d.ts +2 -0
  9. package/build/system/Button/Button.js +6 -15
  10. package/build/system/Button/Button.stories.js +86 -67
  11. package/build/system/Card/Card.js +1 -2
  12. package/build/system/Drawer/Drawer.d.ts +12 -3
  13. package/build/system/Drawer/Drawer.js +8 -9
  14. package/build/system/Drawer/Drawer.stories.d.ts +0 -1
  15. package/build/system/Drawer/Drawer.stories.js +19 -225
  16. package/build/system/Drawer/styles.d.ts +2 -2
  17. package/build/system/Drawer/styles.js +13 -9
  18. package/build/system/Form/Checkbox/Checkbox.js +0 -3
  19. package/build/system/Form/Checkbox/Checkbox.stories.js +2 -2
  20. package/build/system/Form/Checkbox/styles.js +16 -11
  21. package/build/system/Form/Radio/Radio.stories.js +1 -1
  22. package/build/system/Form/Toggle.d.ts +14 -2
  23. package/build/system/Form/Toggle.js +68 -69
  24. package/build/system/Form/Toggle.stories.d.ts +29 -18
  25. package/build/system/Form/Toggle.stories.js +99 -0
  26. package/build/system/Form/Toggle.test.js +36 -19
  27. package/build/system/Link/Link.d.ts +1 -1
  28. package/build/system/Link/Link.js +5 -20
  29. package/build/system/Link/Link.stories.d.ts +3 -1
  30. package/build/system/Link/Link.stories.js +18 -1
  31. package/build/system/MobileMenu/MobileMenu.d.ts +16 -0
  32. package/build/system/MobileMenu/MobileMenu.js +112 -0
  33. package/build/system/MobileMenu/MobileMenu.stories.d.ts +19 -0
  34. package/build/system/MobileMenu/MobileMenu.stories.js +173 -0
  35. package/build/system/MobileMenu/MobileMenu.test.d.ts +1 -0
  36. package/build/system/MobileMenu/MobileMenu.test.js +81 -0
  37. package/build/system/Nav/NavItem.js +4 -5
  38. package/build/system/Nav/NavItemGroup.d.ts +3 -0
  39. package/build/system/Nav/NavItemGroup.js +18 -6
  40. package/build/system/Nav/styles/variants/menu.js +15 -9
  41. package/build/system/Nav/styles/variants/menugroup.js +9 -5
  42. package/build/system/Nav/styles/variants/toolbar.js +1 -2
  43. package/build/system/Nav/styles.js +1 -0
  44. package/build/system/NewDialog/DialogClose.d.ts +7 -2
  45. package/build/system/NewDialog/DialogClose.js +25 -15
  46. package/build/system/NewDialog/index.d.ts +2 -1
  47. package/build/system/NewDialog/index.js +2 -1
  48. package/build/system/NewForm/FormAutocomplete.css +1 -3
  49. package/build/system/Table/Table.js +1 -0
  50. package/build/system/Toolbar/Toolbar.js +1 -1
  51. package/build/system/Toolbar/Toolbar.stories.d.ts +3 -0
  52. package/build/system/Toolbar/Toolbar.stories.js +62 -6
  53. package/build/system/Toolbar/ToolbarUtilNav.d.ts +3 -0
  54. package/build/system/Toolbar/ToolbarUtilNav.js +21 -3
  55. package/build/system/Toolbar/index.d.ts +3 -0
  56. package/build/system/Toolbar/index.js +2 -1
  57. package/build/system/index.d.ts +4 -1
  58. package/build/system/index.js +4 -0
  59. package/build/system/theme/index.d.ts +70 -35
  60. package/build/system/theme/index.js +47 -18
  61. package/package.json +2 -1
  62. package/src/system/Accordion/Accordion.test.tsx +15 -8
  63. package/src/system/Avatar/Avatar.stories.tsx +15 -1
  64. package/src/system/Avatar/Avatar.tsx +8 -12
  65. package/src/system/Button/Button.stories.tsx +40 -31
  66. package/src/system/Button/Button.tsx +6 -15
  67. package/src/system/Card/Card.tsx +0 -1
  68. package/src/system/Drawer/Drawer.stories.tsx +28 -197
  69. package/src/system/Drawer/Drawer.tsx +31 -18
  70. package/src/system/Drawer/styles.ts +15 -5
  71. package/src/system/Form/Checkbox/Checkbox.stories.tsx +2 -2
  72. package/src/system/Form/Checkbox/Checkbox.tsx +0 -3
  73. package/src/system/Form/Checkbox/styles.ts +57 -46
  74. package/src/system/Form/Radio/Radio.stories.tsx +1 -1
  75. package/src/system/Form/Toggle.stories.tsx +122 -0
  76. package/src/system/Form/{Toggle.test.js → Toggle.test.tsx} +1 -1
  77. package/src/system/Form/Toggle.tsx +77 -0
  78. package/src/system/Link/Link.stories.tsx +21 -0
  79. package/src/system/Link/Link.tsx +10 -17
  80. package/src/system/MobileMenu/MobileMenu.stories.tsx +171 -0
  81. package/src/system/MobileMenu/MobileMenu.test.tsx +50 -0
  82. package/src/system/MobileMenu/MobileMenu.tsx +116 -0
  83. package/src/system/Nav/NavItem.tsx +3 -3
  84. package/src/system/Nav/NavItemGroup.tsx +18 -2
  85. package/src/system/Nav/styles/variants/menu.ts +15 -9
  86. package/src/system/Nav/styles/variants/menugroup.ts +7 -3
  87. package/src/system/Nav/styles/variants/toolbar.ts +1 -2
  88. package/src/system/Nav/styles.ts +1 -0
  89. package/src/system/NewDialog/DialogClose.tsx +36 -23
  90. package/src/system/NewDialog/index.ts +3 -2
  91. package/src/system/NewForm/FormAutocomplete.css +1 -3
  92. package/src/system/Table/Table.tsx +1 -1
  93. package/src/system/Toolbar/Toolbar.stories.tsx +50 -3
  94. package/src/system/Toolbar/Toolbar.tsx +1 -1
  95. package/src/system/Toolbar/ToolbarUtilNav.tsx +19 -2
  96. package/src/system/Toolbar/index.tsx +6 -1
  97. package/src/system/index.js +4 -0
  98. package/src/system/theme/index.js +47 -18
  99. package/build/system/Form/Toggle.stories.jsx +0 -96
  100. package/src/system/Form/Toggle.js +0 -74
  101. package/src/system/Form/Toggle.stories.jsx +0 -96
@@ -1,27 +1,14 @@
1
+ /* eslint-disable @typescript-eslint/ban-ts-comment */
2
+ // @ts-nocheck
1
3
  /** @jsxImportSource theme-ui */
2
4
 
3
- import { AiOutlineLock } from 'react-icons/ai';
4
- import {
5
- BiBell,
6
- BiBulb,
7
- BiCodeAlt,
8
- BiData,
9
- BiGridAlt,
10
- BiHistory,
11
- BiTachometer,
12
- BiWindows,
13
- } from 'react-icons/bi';
14
- import { MdMenu, MdOutlinePhotoLibrary } from 'react-icons/md';
15
-
16
5
  import { Drawer, Root, Trigger, Content } from './Drawer';
17
- import { Box, Button, Flex, Nav, NavItem } from '..';
18
- import { Logo } from '../Toolbar/Logo';
19
- import { CustomLink } from '../utils/stories/CustomLink';
6
+ import { Button } from '..';
20
7
 
21
8
  import type { StoryObj } from '@storybook/react';
22
9
 
23
10
  export default {
24
- title: 'Drawer',
11
+ title: 'Navigation/Drawer',
25
12
  component: Drawer,
26
13
  parameters: {
27
14
  docs: {
@@ -68,20 +55,39 @@ type Story = StoryObj< typeof Drawer >;
68
55
  export const Default: Story = {
69
56
  render: () => (
70
57
  <>
71
- <Drawer label="My XYZ Dialog" trigger={ <Button>Open </Button> } width={ 320 }>
58
+ <Drawer
59
+ label="My XYZ Dialog"
60
+ trigger={ <Button>Open </Button> }
61
+ dimensions={ { width: 320 } }
62
+ >
72
63
  <p sx={ { ml: 3 } }>Hello from default</p>
73
64
  </Drawer>
74
65
 
75
66
  <Drawer trigger={ <Button>Top</Button> } variant="top" label="Dialog Content">
76
67
  <p sx={ { ml: 3 } }>Hello from top</p>
77
68
  </Drawer>
78
- <Drawer trigger={ <Button>Right</Button> } variant="right" label="Dialog" width={ 500 }>
69
+ <Drawer
70
+ trigger={ <Button>Right</Button> }
71
+ variant="right"
72
+ label="Dialog"
73
+ dimensions={ { width: 500 } }
74
+ >
79
75
  <p sx={ { ml: 3 } }>Hello from right width 500px</p>
80
76
  </Drawer>
81
- <Drawer trigger={ <Button>Bottom</Button> } variant="bottom" label="Dialog" height={ 200 }>
77
+ <Drawer
78
+ trigger={ <Button>Bottom</Button> }
79
+ variant="bottom"
80
+ label="Dialog"
81
+ dimensions={ { height: 200 } }
82
+ >
82
83
  <p sx={ { ml: 3 } }>Hello from bottom with 200px</p>
83
84
  </Drawer>
84
- <Drawer trigger={ <Button>Left</Button> } variant="left" label="Dialog" width={ 600 }>
85
+ <Drawer
86
+ trigger={ <Button>Left</Button> }
87
+ variant="left"
88
+ label="Dialog"
89
+ dimensions={ { width: 600 } }
90
+ >
85
91
  <p sx={ { ml: 3 } }>Hello from left width 600px</p>
86
92
  </Drawer>
87
93
  <Drawer trigger={ <Button>Left Header</Button> } variant="left-header" label="Dialog">
@@ -101,185 +107,10 @@ export const ByParts: Story = {
101
107
  <Trigger>
102
108
  <Button>Open </Button>
103
109
  </Trigger>
104
- <Content width={ 320 } label="My XYZ Dialog">
110
+ <Content dimensions={ { width: 320 } } label="My XYZ Dialog">
105
111
  <p sx={ { ml: 3 } }>Hello from default</p>
106
112
  </Content>
107
113
  </Root>
108
114
  </>
109
115
  ),
110
116
  };
111
-
112
- export const VIPMobileMenu: Story = {
113
- render: () => (
114
- <>
115
- <Root>
116
- <Trigger>
117
- <Button
118
- type="button"
119
- variant="tertiary"
120
- sx={ {
121
- display: 'flex',
122
- alignItems: 'center',
123
- fontSize: 2,
124
- gap: 1,
125
- mx: 2,
126
- } }
127
- >
128
- Menu
129
- <MdMenu
130
- size={ 24 }
131
- sx={ {
132
- mt: ( theme: { space: number[] } ) => `${ theme?.space?.[ 1 ] / 2 }px`,
133
- } }
134
- />
135
- </Button>
136
- </Trigger>
137
- <Content label="Dialog X" variant="left" width={ 320 }>
138
- <div
139
- sx={ {
140
- backgroundColor: 'toolbar.background',
141
- boxShadow: 'none',
142
- } }
143
- >
144
- <div
145
- sx={ {
146
- height: 56,
147
- width: '100%',
148
- p: 4,
149
- px: 5,
150
- } }
151
- >
152
- <Logo />
153
- </div>
154
-
155
- <div
156
- sx={ {
157
- overflowX: 'hidden',
158
- overflowY: 'auto',
159
- height: 'calc(100vh - 56px)',
160
- display: 'flex',
161
- flex: 1,
162
- } }
163
- >
164
- <Flex sx={ { width: '100%', flexDirection: 'column' } }>
165
- <Nav.Primary label="Main Links" orientation="vertical" sx={ { p: 4 } }>
166
- <NavItem.MenuInverse href="/apps" active as={ CustomLink }>
167
- My Applications
168
- </NavItem.MenuInverse>
169
-
170
- <NavItem.MenuInverse href="/orgs" as={ CustomLink }>
171
- My Organizations
172
- </NavItem.MenuInverse>
173
- </Nav.Primary>
174
-
175
- <Box
176
- sx={ {
177
- alignSelf: 'stretch',
178
- backgroundColor: 'layer.1',
179
- minHeight: `calc(100vh - 56px)`,
180
- pt: 2,
181
- px: 4,
182
- width: '100%',
183
- a: {
184
- border: 'none',
185
- },
186
- } }
187
- >
188
- <Nav.Menu sx={ { mb: 4 } } label="Nav Menu">
189
- <NavItem.Menu
190
- href="https://wordpress.com"
191
- renderIcon={ size => <BiGridAlt size={ size } /> }
192
- as={ CustomLink }
193
- >
194
- Overview
195
- </NavItem.Menu>
196
- <NavItem.Menu
197
- as={ CustomLink }
198
- href="https://random-website.com/"
199
- renderIcon={ size => <BiWindows size={ size } /> }
200
- >
201
- Network Sites
202
- </NavItem.Menu>
203
- <NavItem.Menu
204
- as={ CustomLink }
205
- href="https://random-website.com/"
206
- renderIcon={ size => <AiOutlineLock size={ size } /> }
207
- >
208
- Domains & TLS
209
- </NavItem.Menu>
210
-
211
- <NavItem.MenuGroup
212
- active
213
- label="Logs"
214
- renderIcon={ size => <BiHistory size={ size } /> }
215
- >
216
- <NavItem.Menu active as={ CustomLink } href="https://google.com/">
217
- Audit
218
- </NavItem.Menu>
219
- <NavItem.Menu as={ CustomLink } href="https://wpvip.com/">
220
- Runtime
221
- </NavItem.Menu>
222
- <NavItem.Menu as={ CustomLink } href="https://dashboard.wpvip.com/">
223
- Slow Query
224
- </NavItem.Menu>
225
- </NavItem.MenuGroup>
226
-
227
- <NavItem.MenuGroup
228
- label="Performance"
229
- renderIcon={ size => <BiTachometer size={ size } /> }
230
- >
231
- <NavItem.Menu as={ CustomLink } href="https://random-website.com/">
232
- Metrics
233
- </NavItem.Menu>
234
- <NavItem.Menu as={ CustomLink } href="https://random-website.com/">
235
- Monitor
236
- </NavItem.Menu>
237
- <NavItem.Menu as={ CustomLink } href="https://random-website.com/">
238
- Cache
239
- </NavItem.Menu>
240
- </NavItem.MenuGroup>
241
- <NavItem.Menu
242
- as={ CustomLink }
243
- href="https://random-website.com/"
244
- renderIcon={ size => <BiCodeAlt size={ size } /> }
245
- >
246
- Code [v]
247
- </NavItem.Menu>
248
- <NavItem.Menu
249
- as={ CustomLink }
250
- href="https://random-website.com/"
251
- renderIcon={ size => <BiData size={ size } /> }
252
- >
253
- Database [v]
254
- </NavItem.Menu>
255
- <NavItem.Menu
256
- as={ CustomLink }
257
- href="https://random-website.com/"
258
- renderIcon={ size => <MdOutlinePhotoLibrary size={ size } /> }
259
- >
260
- Media [v]
261
- </NavItem.Menu>
262
- <NavItem.Menu
263
- as={ CustomLink }
264
- href="https://random-website.com/"
265
- renderIcon={ size => <BiBell size={ size } /> }
266
- >
267
- Notifications
268
- </NavItem.Menu>
269
- <NavItem.Menu
270
- as={ CustomLink }
271
- href="https://random-website.com/"
272
- renderIcon={ size => <BiBulb size={ size } /> }
273
- >
274
- Features
275
- </NavItem.Menu>
276
- </Nav.Menu>
277
- </Box>
278
- </Flex>
279
- </div>
280
- </div>
281
- </Content>
282
- </Root>
283
- </>
284
- ),
285
- };
@@ -4,44 +4,57 @@ import * as DialogPrimitive from '@radix-ui/react-dialog';
4
4
  import React, { ReactNode } from 'react';
5
5
 
6
6
  import { drawerContentStyles, drawerOverlayStyles } from './styles';
7
- import { DialogCloseDefault } from '../NewDialog/DialogClose';
7
+ import { DialogClose } from '../NewDialog/DialogClose';
8
8
  import { DialogTitle } from '../NewDialog/DialogTitle';
9
9
 
10
10
  export interface DrawerContentProps extends DialogPrimitive.DialogContentProps, DrawerProps {}
11
11
 
12
+ export type responsiveProp = number | string | number[] | string[];
13
+ export type responsiveDimensionsProp = {
14
+ width?: responsiveProp;
15
+ height?: responsiveProp;
16
+ minWidth?: responsiveProp;
17
+ minHeight?: responsiveProp;
18
+ maxWidth?: responsiveProp;
19
+ maxHeight?: responsiveProp;
20
+ };
21
+
22
+ export interface DrawerProps extends DialogPrimitive.DialogProps {
23
+ children?: ReactNode;
24
+ trigger?: ReactNode;
25
+ label?: string;
26
+ variant?: 'top' | 'right' | 'bottom' | 'left' | 'left-header' | 'right-header';
27
+ dimensions?: responsiveDimensionsProp;
28
+ renderClose?: () => JSX.Element | null;
29
+ }
30
+
12
31
  export const Content = React.forwardRef< HTMLDivElement, DrawerContentProps >(
13
- (
14
- { children, variant = 'left', label, width, height, ...rest }: DrawerContentProps,
15
- forwardedRef
16
- ) => (
32
+ ( { children, variant = 'left', label, dimensions, renderClose, ...rest }, forwardedRef ) => (
17
33
  <DialogPrimitive.Portal>
18
34
  <DialogPrimitive.Overlay sx={ drawerOverlayStyles( variant ) } />
19
35
  <DialogPrimitive.Content
20
36
  { ...rest }
21
- sx={ drawerContentStyles( variant, width, height ) }
37
+ sx={ drawerContentStyles( variant, dimensions ) }
22
38
  ref={ forwardedRef }
23
39
  >
24
40
  <DialogTitle title={ label } hidden />
25
- <DialogCloseDefault />
41
+ { renderClose ? renderClose() : <DialogClose /> }
26
42
  { children }
27
43
  </DialogPrimitive.Content>
28
44
  </DialogPrimitive.Portal>
29
45
  )
30
46
  );
31
47
 
32
- export interface DrawerProps extends DialogPrimitive.DialogProps {
33
- children?: ReactNode;
34
- trigger?: ReactNode;
35
- label?: string;
36
- variant?: 'top' | 'right' | 'bottom' | 'left' | 'left-header' | 'right-header';
37
- width?: number | string;
38
- height?: number | string;
39
- }
40
-
41
48
  export const Drawer = React.forwardRef< HTMLDivElement, DrawerProps >(
42
- ( { children, width, height, variant = 'left', trigger, label, ...rest }, forwardedRef ) => (
49
+ ( { children, dimensions, variant = 'left', trigger, label, ...rest }, forwardedRef ) => (
43
50
  <Root trigger={ trigger }>
44
- <Content width={ width } variant={ variant } label={ label } ref={ forwardedRef } { ...rest }>
51
+ <Content
52
+ dimensions={ dimensions }
53
+ variant={ variant }
54
+ label={ label }
55
+ ref={ forwardedRef }
56
+ { ...rest }
57
+ >
45
58
  { children }
46
59
  </Content>
47
60
  </Root>
@@ -3,7 +3,7 @@
3
3
  import { keyframes } from '@emotion/react';
4
4
  import { Theme, ThemeUIStyleObject } from 'theme-ui';
5
5
 
6
- import { DrawerProps } from './Drawer';
6
+ import { DrawerProps, responsiveDimensionsProp, responsiveProp } from './Drawer';
7
7
 
8
8
  interface ThemeProps extends Theme {
9
9
  drawer?: Record< string, Record< string, string > >;
@@ -29,9 +29,15 @@ const slideOut = ( theme: ThemeProps, variant: DrawerProps[ 'variant' ] ) => {
29
29
 
30
30
  export const drawerContentStyles = (
31
31
  variant: DrawerProps[ 'variant' ],
32
- width: string | number = '100%',
33
- height: string | number | undefined = undefined
32
+ dimensions?: responsiveDimensionsProp
34
33
  ): ThemeUIStyleObject => {
34
+ const width: responsiveProp = dimensions?.width || [ '100%', '100%', '80vw' ];
35
+ const height: responsiveProp = dimensions?.height || '100vh';
36
+ const minWidth: responsiveProp = dimensions?.minWidth || '16rem';
37
+ const minHeight: responsiveProp = dimensions?.minHeight || '100vh';
38
+ const maxWidth: responsiveProp = dimensions?.maxWidth || '22rem';
39
+ const maxHeight: responsiveProp = dimensions?.maxHeight || '100vh';
40
+
35
41
  const defaultStyles: ThemeUIStyleObject = {
36
42
  p: 0,
37
43
  m: 0,
@@ -42,6 +48,10 @@ export const drawerContentStyles = (
42
48
  bottom: 0,
43
49
  width,
44
50
  height,
51
+ minWidth,
52
+ minHeight,
53
+ maxWidth,
54
+ maxHeight,
45
55
 
46
56
  variant: `drawer.${ variant }.styles`,
47
57
 
@@ -64,7 +74,7 @@ export const drawerContentStyles = (
64
74
  return {
65
75
  ...defaultStyles,
66
76
  backgroundColor: 'layer.1',
67
- top: [ 56, 56, 56, 64 ],
77
+ top: 64,
68
78
  };
69
79
  }
70
80
  default: {
@@ -106,7 +116,7 @@ export const drawerOverlayStyles = ( variant: DrawerProps[ 'variant' ] ): ThemeU
106
116
  case 'right-header': {
107
117
  return {
108
118
  ...defaultStyles,
109
- top: [ 56, 56, 56, 64 ],
119
+ top: 64,
110
120
  };
111
121
  }
112
122
  default: {
@@ -61,7 +61,7 @@ export const Default = () => {
61
61
 
62
62
  return (
63
63
  <Form.Root>
64
- { ( [ 'primary', 'success', 'brand' ] as CheckboxProps[ 'variant' ][] ).map( variant => (
64
+ { ( [ 'primary', 'brand' ] as CheckboxProps[ 'variant' ][] ).map( variant => (
65
65
  <Form.Fieldset key={ variant }>
66
66
  <Form.Legend>Tell me your { variant } prefereces</Form.Legend>
67
67
 
@@ -139,7 +139,7 @@ export const Indeterminate = () => {
139
139
 
140
140
  return (
141
141
  <Form.Root>
142
- { ( [ 'primary', 'success', 'brand' ] as CheckboxProps[ 'variant' ][] ).map( variant => (
142
+ { ( [ 'primary', 'brand' ] as CheckboxProps[ 'variant' ][] ).map( variant => (
143
143
  <Form.Fieldset key={ variant }>
144
144
  <Form.Legend>Indeterminate state { variant }</Form.Legend>
145
145
 
@@ -34,9 +34,6 @@ const Checkbox = ( {
34
34
 
35
35
  return (
36
36
  <StyledCheckbox
37
- sx={ {
38
- opacity: disabled ? 0.4 : 1,
39
- } }
40
37
  onCheckedChange={ disabled ? undefined : onCheckedChange }
41
38
  aria-disabled={ disabled }
42
39
  variant={ variant }
@@ -10,51 +10,62 @@ import {
10
10
  // The output willl be 16px because of the 1px border.
11
11
  const CHECKBOX_SIZE = 14;
12
12
 
13
- export const checkboxStyle = ( variant: string ): ThemeUIStyleObject => ( {
14
- all: 'unset',
15
- position: 'relative',
16
- backgroundColor: inputBaseBackground,
17
- ...baseControlBorderStyle,
18
- ...baseControlFocusStyle,
19
- width: CHECKBOX_SIZE,
20
- height: CHECKBOX_SIZE,
21
- borderRadius: 1,
22
- display: 'flex',
23
- justifyContent: 'center',
24
- '&[aria-disabled="true"]': {
25
- opacity: 0.7,
26
- cursor: 'not-allowed',
27
- pointerEvents: 'none',
28
- },
29
- '&[data-state=checked]': {
30
- backgroundColor: variant,
31
- color: variant,
32
- borderColor: variant,
33
- },
34
- '& ~ label': {
35
- fontWeight: 'regular',
36
- color: inputBaseText,
37
- m: 0,
38
- ml: 2,
39
- },
40
- svg: {
41
- position: 'absolute',
42
- top: 0,
43
- left: 0,
44
- },
45
- } );
13
+ export const checkboxStyle = ( variant: string ): ThemeUIStyleObject => {
14
+ const variantColor = variant === 'disabled' ? 'input.background.disabled' : variant;
46
15
 
47
- export const checkboxIndicatorStyle = ( variant: string ): ThemeUIStyleObject => ( {
48
- width: 14,
49
- height: 14,
50
- backgroundImage: `url("data:image/svg+xml,%3Csvg xmlns='http://www.w3.org/2000/svg' width='14' height='14' viewBox='1 1 14 14' fill='none'%3E%3Cpath fill-rule='evenodd' clip-rule='evenodd' d='M13.9259 4.9995L6.15142 12.4008L2.92603 9.33023L4.2591 7.92994L6.15142 9.73143L12.5928 3.59921L13.9259 4.9995Z' fill='white'/%3E%3C/svg%3E")`,
16
+ return {
17
+ all: 'unset',
18
+ position: 'relative',
19
+ backgroundColor: inputBaseBackground,
20
+ ...baseControlBorderStyle,
21
+ ...baseControlFocusStyle,
22
+ width: CHECKBOX_SIZE,
23
+ height: CHECKBOX_SIZE,
24
+ borderRadius: 0,
25
+ display: 'flex',
26
+ justifyContent: 'center',
27
+ '&[aria-disabled="true"]': {
28
+ opacity: 0.7,
29
+ cursor: 'not-allowed',
30
+ pointerEvents: 'none',
31
+ },
32
+ '&[data-state=checked], &[data-state=indeterminate]': {
33
+ backgroundColor: variantColor,
34
+ color: variantColor,
35
+ borderColor: variantColor,
36
+ },
37
+ '& ~ label': {
38
+ fontWeight: 'regular',
39
+ color: inputBaseText,
40
+ m: 0,
41
+ ml: 2,
42
+ },
43
+ svg: {
44
+ position: 'absolute',
45
+ fill: 'currentColor',
46
+ top: 0,
47
+ left: 0,
48
+ },
49
+ };
50
+ };
51
51
 
52
- '&[data-state=indeterminate]': {
53
- marginTop: '6px',
54
- backgroundImage: 'none',
55
- backgroundColor: variant,
56
- position: 'absolute',
57
- width: 10,
58
- height: 2,
59
- },
60
- } );
52
+ export const checkboxIndicatorStyle = ( variant: string ): ThemeUIStyleObject => {
53
+ const backgroundColor = variant === 'disabled' ? 'icon.inverse-disabled' : 'icon.inverse';
54
+
55
+ return {
56
+ width: 14,
57
+ height: 14,
58
+ backgroundColor,
59
+ maskImage: `url("data:image/svg+xml,%3Csvg xmlns='http://www.w3.org/2000/svg' width='14' height='14' viewBox='1 1 14 14' fill='none'%3E%3Cpath fill-rule='evenodd' clip-rule='evenodd' d='M13.9259 4.9995L6.15142 12.4008L2.92603 9.33023L4.2591 7.92994L6.15142 9.73143L12.5928 3.59921L13.9259 4.9995Z' fill='currentcolor'/%3E%3C/svg%3E")`,
60
+
61
+ '&[data-state=indeterminate]': {
62
+ maskImage: 'none',
63
+ backgroundColor,
64
+ position: 'absolute',
65
+ top: '50%',
66
+ width: 8,
67
+ height: 2,
68
+ marginTop: '-1px',
69
+ },
70
+ };
71
+ };
@@ -62,7 +62,7 @@ export const Default = () => {
62
62
 
63
63
  return (
64
64
  <>
65
- { ( [ 'primary', 'success', 'brand' ] as RadioProps[ 'variant' ][] ).map( variant => (
65
+ { ( [ 'primary', 'brand' ] as RadioProps[ 'variant' ][] ).map( variant => (
66
66
  <Box key={ variant }>
67
67
  <Heading as="h2" sx={ { textTransform: 'capitalize' } }>
68
68
  { variant }
@@ -0,0 +1,122 @@
1
+ /** @jsxImportSource theme-ui */
2
+ import { StoryObj } from '@storybook/react';
3
+
4
+ import { Toggle, Label } from '..';
5
+ export default {
6
+ title: 'Toggle',
7
+ component: Toggle,
8
+ argTypes: {
9
+ checked: {
10
+ control: {
11
+ type: 'boolean',
12
+ },
13
+ },
14
+ },
15
+ parameters: {
16
+ docs: {
17
+ description: {
18
+ component: `
19
+ The Toggle component is two-state switch that can be toggled on or off. It is used to activate or deactivate a feature.
20
+
21
+ ## Guidance
22
+
23
+ ### When to use the Toggle component
24
+
25
+ - Use the Toggle component to allow users to switch between two states, such as on/off, true/false, or yes/no.
26
+
27
+ ### When to consider something else
28
+
29
+ - If you need to select from more than two states, use a [Radio](/docs/radio--docs), or a [Select](/docs/form-select--docs) component instead.
30
+
31
+ ## Accessibility Considerations guidance
32
+
33
+ - The Toggle component is based on the Radix Toggle primitive, so it contains all the accessibility features from the primitive.
34
+
35
+ ## Using the component
36
+
37
+ - Available variants: Primary, Success, Disabled.
38
+
39
+ ## Component Properties
40
+ `,
41
+ },
42
+ },
43
+ },
44
+ };
45
+
46
+ type Story = StoryObj< typeof Toggle >;
47
+
48
+ export const Default: Story = {
49
+ render: args => (
50
+ <form>
51
+ <Toggle checked={ args.checked } defaultChecked aria-label="Feature flag" />
52
+
53
+ <br />
54
+ <br />
55
+
56
+ <Toggle checked={ args.checked } defaultChecked={ false } aria-label="Feature flag 2" />
57
+
58
+ <br />
59
+ <br />
60
+
61
+ <Toggle aria-label="Feature Disabled" disabled defaultChecked={ false } />
62
+ </form>
63
+ ),
64
+ };
65
+
66
+ export const WithLabel: Story = {
67
+ render: args => (
68
+ <form>
69
+ <Label htmlFor="custom-label-input">Custom Label here</Label>
70
+
71
+ <Toggle
72
+ id="custom-label-input"
73
+ defaultChecked
74
+ checked={ args.checked }
75
+ aria-label="Feature flag"
76
+ />
77
+ </form>
78
+ ),
79
+ };
80
+
81
+ export const CustomStyling: Story = {
82
+ render: args => (
83
+ <form>
84
+ <Label htmlFor="custom-label-input">
85
+ Custom Styling.{ ' ' }
86
+ <strong>We currently only recommend using Primary, Disabled, and Success variants.</strong>
87
+ </Label>
88
+
89
+ <div>
90
+ <Toggle
91
+ id="custom-label-input"
92
+ defaultChecked
93
+ checked={ args.checked }
94
+ aria-label="Feature flag"
95
+ variant="success"
96
+ />{ ' ' }
97
+ <h2>Not recommended</h2>
98
+ <Toggle
99
+ id="custom-label-input-error"
100
+ defaultChecked
101
+ checked={ args.checked }
102
+ aria-label="Error flag"
103
+ variant="error"
104
+ />{ ' ' }
105
+ <Toggle
106
+ id="custom-label-input-warning"
107
+ defaultChecked
108
+ checked={ args.checked }
109
+ aria-label="Warning flag"
110
+ variant="warning"
111
+ />{ ' ' }
112
+ <Toggle
113
+ id="custom-label-input-info"
114
+ defaultChecked
115
+ checked={ args.checked }
116
+ aria-label="info flag"
117
+ variant="info"
118
+ />
119
+ </div>
120
+ </form>
121
+ ),
122
+ };
@@ -18,6 +18,6 @@ describe( '<Toggle />', () => {
18
18
  expect( screen.getByRole( 'switch' ) ).toBeInTheDocument();
19
19
 
20
20
  // Check for accessibility issues
21
- await expect( await axe( container ) ).toHaveNoViolations();
21
+ expect( await axe( container ) ).toHaveNoViolations();
22
22
  } );
23
23
  } );