@automattic/vip-design-system 0.9.4 → 0.10.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 (69) hide show
  1. package/.github/workflows/nodejs.yaml +1 -1
  2. package/README.md +4 -4
  3. package/build/system/Avatar/Avatar.js +9 -3
  4. package/build/system/Badge/Badge.js +9 -3
  5. package/build/system/BlankState/BlankState.js +8 -2
  6. package/build/system/Box/Box.js +12 -2
  7. package/build/system/Button/Button.js +6 -2
  8. package/build/system/Card/Card.js +8 -3
  9. package/build/system/Code/Code.js +8 -3
  10. package/build/system/ConfirmationDialog/ConfirmationDialog.js +8 -2
  11. package/build/system/Dialog/Dialog.js +1 -0
  12. package/build/system/Form/AsyncSearchSelect.js +38 -0
  13. package/build/system/Form/SearchSelect.js +47 -11
  14. package/build/system/Form/Select.js +22 -2
  15. package/build/system/Form/Select.test.js +52 -0
  16. package/build/system/Form/Toggle.js +8 -2
  17. package/build/system/Heading/Heading.js +9 -3
  18. package/build/system/Notice/Notice.js +9 -3
  19. package/build/system/Notification/Notification.js +1 -0
  20. package/build/system/OptionRow/OptionRow.js +13 -3
  21. package/build/system/OptionRow/OptionRow.test.js +46 -0
  22. package/build/system/Progress/Progress.js +9 -3
  23. package/build/system/ResourceList/ResourceList.js +1 -0
  24. package/build/system/Spinner/Spinner.js +9 -3
  25. package/build/system/Tabs/TabItem.js +1 -0
  26. package/build/system/Tabs/Tabs.js +10 -4
  27. package/build/system/Text/Text.js +9 -3
  28. package/build/system/Time/index.js +9 -3
  29. package/build/system/Timeline/Timeline.js +77 -0
  30. package/build/system/Timeline/index.js +2 -66
  31. package/build/system/Wizard/Wizard.js +10 -2
  32. package/build/system/Wizard/WizardStep.js +6 -2
  33. package/build/system/Wizard/WizardStepHorizontal.js +6 -2
  34. package/package.json +4 -2
  35. package/src/system/Avatar/Avatar.js +4 -0
  36. package/src/system/Badge/Badge.js +4 -1
  37. package/src/system/BlankState/BlankState.js +4 -1
  38. package/src/system/Box/Box.js +6 -1
  39. package/src/system/Button/Button.js +3 -0
  40. package/src/system/Card/Card.js +4 -1
  41. package/src/system/Code/Code.js +4 -1
  42. package/src/system/ConfirmationDialog/ConfirmationDialog.js +4 -2
  43. package/src/system/Dialog/Dialog.js +1 -1
  44. package/src/system/Form/AsyncSearchSelect.js +29 -0
  45. package/src/system/Form/SearchSelect.js +43 -3
  46. package/src/system/Form/Select.js +16 -3
  47. package/src/system/Form/Select.stories.js +30 -0
  48. package/src/system/Form/Select.test.js +37 -0
  49. package/src/system/Form/Toggle.js +4 -2
  50. package/src/system/Heading/Heading.js +4 -1
  51. package/src/system/Notice/Notice.js +4 -1
  52. package/src/system/Notification/Notification.js +1 -0
  53. package/src/system/OptionRow/OptionRow.js +7 -0
  54. package/src/system/OptionRow/OptionRow.stories.js +1 -0
  55. package/src/system/OptionRow/OptionRow.test.js +27 -0
  56. package/src/system/Progress/Progress.js +4 -1
  57. package/src/system/ResourceList/ResourceList.js +1 -1
  58. package/src/system/Spinner/Spinner.js +4 -1
  59. package/src/system/Tabs/TabItem.js +1 -0
  60. package/src/system/Tabs/Tabs.js +5 -2
  61. package/src/system/Text/Text.js +4 -1
  62. package/src/system/Time/index.js +4 -1
  63. package/src/system/Timeline/Timeline.js +48 -0
  64. package/src/system/Timeline/Timeline.stories.js +34 -0
  65. package/src/system/Timeline/index.js +2 -41
  66. package/src/system/Wizard/Wizard.js +6 -2
  67. package/src/system/Wizard/Wizard.stories.js +1 -1
  68. package/src/system/Wizard/WizardStep.js +5 -2
  69. package/src/system/Wizard/WizardStepHorizontal.js +4 -1
@@ -3,6 +3,7 @@
3
3
  /**
4
4
  * External dependencies
5
5
  */
6
+ import classNames from 'classnames';
6
7
  import PropTypes from 'prop-types';
7
8
 
8
9
  /**
@@ -10,7 +11,7 @@ import PropTypes from 'prop-types';
10
11
  */
11
12
  import { Text } from '../';
12
13
 
13
- const Badge = ( { variant = 'blue', sx, ...props } ) => (
14
+ const Badge = ( { variant = 'blue', sx, className = null, ...props } ) => (
14
15
  <Text
15
16
  as="span"
16
17
  sx={ {
@@ -26,6 +27,7 @@ const Badge = ( { variant = 'blue', sx, ...props } ) => (
26
27
  fontWeight: 'heading',
27
28
  ...sx,
28
29
  } }
30
+ className={ classNames( 'vip-badge-component', className ) }
29
31
  { ...props }
30
32
  />
31
33
  );
@@ -33,6 +35,7 @@ const Badge = ( { variant = 'blue', sx, ...props } ) => (
33
35
  Badge.propTypes = {
34
36
  variant: PropTypes.string,
35
37
  sx: PropTypes.object,
38
+ className: PropTypes.any,
36
39
  };
37
40
 
38
41
  export { Badge };
@@ -3,6 +3,7 @@
3
3
  /**
4
4
  * External dependencies
5
5
  */
6
+ import classNames from 'classnames';
6
7
  import PropTypes from 'prop-types';
7
8
 
8
9
  /**
@@ -17,9 +18,10 @@ const BlankState = ( {
17
18
  image,
18
19
  imageAlt = 'Image representing the blank state',
19
20
  title,
21
+ className = null,
20
22
  } ) => {
21
23
  return (
22
- <Box sx={{ textAlign: 'center', padding: 5 }}>
24
+ <Box sx={{ textAlign: 'center', padding: 5 }} className={ classNames( 'vip-blank-state-component', className ) }>
23
25
  {icon ? icon : <img src={image} sx={{ mb: 3 }} alt={imageAlt} />}
24
26
  <Heading variant="h4">{title}</Heading>
25
27
  <Text>{body}</Text>
@@ -35,6 +37,7 @@ BlankState.propTypes = {
35
37
  image: PropTypes.oneOfType( [ PropTypes.object, PropTypes.string ] ),
36
38
  imageAlt: PropTypes.string,
37
39
  title: PropTypes.node,
40
+ className: PropTypes.any,
38
41
  };
39
42
 
40
43
  export { BlankState };
@@ -3,11 +3,16 @@
3
3
  /**
4
4
  * External dependencies
5
5
  */
6
+ import PropTypes from 'prop-types';
7
+ import classNames from 'classnames';
6
8
  import { forwardRef } from 'react';
7
9
  import { Box as ThemeBox } from 'theme-ui';
8
10
 
9
- const Box = forwardRef( ( props, ref ) => <ThemeBox ref={ref} {...props} /> );
11
+ const Box = forwardRef( ( props, ref ) => <ThemeBox ref={ref} className={ classNames( 'vip-box-component', props.className ) } {...props} /> );
10
12
 
11
13
  Box.displayName = 'Box';
14
+ Box.propTypes = {
15
+ className: PropTypes.any,
16
+ };
12
17
 
13
18
  export { Box };
@@ -5,6 +5,7 @@
5
5
  */
6
6
  import { Button as ThemeButton } from 'theme-ui';
7
7
  import PropTypes from 'prop-types';
8
+ import classNames from 'classnames';
8
9
 
9
10
  const Button = ( { sx, ...props } ) => (
10
11
  <ThemeButton
@@ -22,12 +23,14 @@ const Button = ( { sx, ...props } ) => (
22
23
  },
23
24
  ...sx,
24
25
  }}
26
+ className={ classNames( 'vip-button-component', props.className ) }
25
27
  {...props}
26
28
  />
27
29
  );
28
30
 
29
31
  Button.propTypes = {
30
32
  sx: PropTypes.object,
33
+ className: PropTypes.any,
31
34
  };
32
35
 
33
36
  export { Button };
@@ -10,8 +10,9 @@ import PropTypes from 'prop-types';
10
10
  * Internal dependencies
11
11
  */
12
12
  import { Box } from '..';
13
+ import classNames from 'classnames';
13
14
 
14
- const Card = React.forwardRef( ( { variant = 'primary', sx = {}, ...props }, ref ) => {
15
+ const Card = React.forwardRef( ( { variant = 'primary', sx = {}, className, ...props }, ref ) => {
15
16
  return (
16
17
  <Box
17
18
  ref={ref}
@@ -21,6 +22,7 @@ const Card = React.forwardRef( ( { variant = 'primary', sx = {}, ...props }, ref
21
22
  overflow: 'hidden',
22
23
  ...sx,
23
24
  }}
25
+ className={ classNames( 'vip-card-component', className ) }
24
26
  {...props}
25
27
  />
26
28
  );
@@ -29,6 +31,7 @@ const Card = React.forwardRef( ( { variant = 'primary', sx = {}, ...props }, ref
29
31
  Card.propTypes = {
30
32
  variant: PropTypes.string,
31
33
  sx: PropTypes.object,
34
+ className: PropTypes.any,
32
35
  };
33
36
 
34
37
  Card.displayName = 'Card';
@@ -3,11 +3,12 @@
3
3
  /**
4
4
  * External dependencies
5
5
  */
6
+ import classNames from 'classnames';
6
7
  import PropTypes from 'prop-types';
7
8
  import { useRef, useState } from 'react';
8
9
  import { MdContentCopy } from 'react-icons/md';
9
10
 
10
- const Code = ( { prompt = false, showCopy = false, onCopy = null, ...props } ) => {
11
+ const Code = ( { prompt = false, showCopy = false, onCopy = null, className, ...props } ) => {
11
12
  const ref = useRef();
12
13
 
13
14
  const codeDom = (
@@ -29,6 +30,7 @@ const Code = ( { prompt = false, showCopy = false, onCopy = null, ...props } ) =
29
30
  userSelect: 'none',
30
31
  },
31
32
  } }
33
+ className={ classNames( 'vip-code-component', className ) }
32
34
  { ...props }
33
35
  />
34
36
  );
@@ -88,6 +90,7 @@ Code.propTypes = {
88
90
  prompt: PropTypes.bool,
89
91
  showCopy: PropTypes.bool,
90
92
  onCopy: PropTypes.func,
93
+ className: PropTypes.any,
91
94
  };
92
95
 
93
96
  export { Code };
@@ -3,6 +3,7 @@
3
3
  /**
4
4
  * External dependencies
5
5
  */
6
+ import classNames from 'classnames';
6
7
  import PropTypes from 'prop-types';
7
8
  import React from 'react';
8
9
 
@@ -11,8 +12,8 @@ import React from 'react';
11
12
  */
12
13
  import { Dialog, Box, Heading, Text, Flex, Button } from '../';
13
14
 
14
- const ConfirmationDialogContent = ( { title, body, onClose, label = 'Confirm', onConfirm } ) => (
15
- <Box p={ 4 }>
15
+ const ConfirmationDialogContent = ( { title, body, onClose, label = 'Confirm', onConfirm, className = null } ) => (
16
+ <Box p={ 4 } className={ classNames( 'vip-confirmation-dialog-component', className ) }>
16
17
  <Heading variant="h3" sx={ { mb: 2 } }>
17
18
  { title }
18
19
  </Heading>
@@ -40,6 +41,7 @@ ConfirmationDialogContent.propTypes = {
40
41
  label: PropTypes.string,
41
42
  onClose: PropTypes.func,
42
43
  onConfirm: PropTypes.func,
44
+ className: PropTypes.any,
43
45
  };
44
46
 
45
47
  const ConfirmationDialog = ( { trigger, onConfirm, needsConfirm = true, ...props } ) => {
@@ -46,7 +46,7 @@ const Dialog = ( { trigger, position = 'left', startOpen = false, content, disab
46
46
  };
47
47
 
48
48
  return (
49
- <div onClick={ e => e.stopPropagation() } sx={ { position: 'relative' } } ref={ dialogRef }>
49
+ <div onClick={ e => e.stopPropagation() } sx={ { position: 'relative' } } ref={ dialogRef } className="vip-dialog-component">
50
50
  <DialogTrigger
51
51
  tabIndex="0"
52
52
  sx={ { display: 'inline' } }
@@ -0,0 +1,29 @@
1
+ /** @jsxImportSource theme-ui */
2
+
3
+ /**
4
+ * External dependencies
5
+ */
6
+ import PropTypes from 'prop-types';
7
+ import { withAsyncPaginate } from 'react-select-async-paginate';
8
+
9
+ /**
10
+ * Internal dependencies
11
+ */
12
+ import { SearchSelect } from './SearchSelect';
13
+
14
+ // Asynchronous search select to load paginated results asynchronously
15
+ const CustomAsyncPaginate = withAsyncPaginate( SearchSelect );
16
+
17
+ const AsyncSearchSelect = ( { options, ...props } ) => (
18
+ <CustomAsyncPaginate
19
+ SelectComponent={ SearchSelect }
20
+ loadOptions={ options }
21
+ { ...props }
22
+ />
23
+ );
24
+
25
+ AsyncSearchSelect.propTypes = {
26
+ options: PropTypes.array,
27
+ };
28
+
29
+ export { AsyncSearchSelect };
@@ -12,6 +12,7 @@ import PropTypes from 'prop-types';
12
12
  */
13
13
  import { Flex, Text } from '..';
14
14
 
15
+ // Option component
15
16
  export const Option = ( { label, isSelected, ...props } ) => (
16
17
  <components.Option {...props}>
17
18
  <Flex sx={{ alignItems: 'center' }}>
@@ -32,7 +33,45 @@ Option.propTypes = {
32
33
  isSelected: PropTypes.bool,
33
34
  };
34
35
 
35
- export const DropdownIndicator = props => <MdExpandMore {...props} sx={{ color: 'text', mr: 2 }} />;
36
+ // DropdownIndicator component
37
+ export const DropdownIndicator = ( {
38
+ innerProps,
39
+ isFocused,
40
+ isDisabled,
41
+ clearValue,
42
+ cx,
43
+ getStyles,
44
+ getValue,
45
+ hasValue,
46
+ isMulti,
47
+ isRtl,
48
+ options,
49
+ selectProps,
50
+ setValue,
51
+ selectOption,
52
+ theme,
53
+ ...props
54
+ } ) => <MdExpandMore { ...props } sx={ { color: 'text', mr: 2 } } />;
55
+
56
+ DropdownIndicator.propTypes = {
57
+ innerProps: PropTypes.object,
58
+ isFocused: PropTypes.bool,
59
+ isDisabled: PropTypes.bool,
60
+ clearValue: PropTypes.func,
61
+ cx: PropTypes.func,
62
+ getStyles: PropTypes.func,
63
+ getValue: PropTypes.func,
64
+ hasValue: PropTypes.bool,
65
+ isMulti: PropTypes.bool,
66
+ isRtl: PropTypes.bool,
67
+ options: PropTypes.array,
68
+ selectProps: PropTypes.object,
69
+ setValue: PropTypes.func,
70
+ selectOption: PropTypes.func,
71
+ theme: PropTypes.object,
72
+ };
73
+
74
+ // ClearIndicator component
36
75
  const ClearIndicator = ( { innerProps: { ref, ...restInnerProps }, ...props } ) => (
37
76
  <MdClose ref={ref} {...restInnerProps} {...props} sx={{ color: 'text', mr: 2 }} />
38
77
  );
@@ -41,11 +80,12 @@ ClearIndicator.propTypes = {
41
80
  innerProps: PropTypes.object,
42
81
  };
43
82
 
83
+ // Parent SearchSelect component
44
84
  const SearchSelect = props => (
45
85
  <Select
46
- {...props}
86
+ { ...props }
47
87
  classNamePrefix={ 'select' }
48
- components={{ Option, DropdownIndicator, ClearIndicator }}
88
+ components={ { Option, DropdownIndicator, ClearIndicator } }
49
89
  sx={ {
50
90
  '.select__control': {
51
91
  background: 'none',
@@ -11,8 +11,10 @@ import PropTypes from 'prop-types';
11
11
  */
12
12
  import { SearchSelect } from './SearchSelect';
13
13
  import { InlineSelect } from './InlineSelect';
14
+ import { AsyncSearchSelect } from './AsyncSearchSelect';
14
15
 
15
- const Select = ( { isMulti = false, isInline, options, label, isSearch, usePortal, ...props } ) => {
16
+ const Select = ( { isMulti = false, isInline, isAsync, options, label, isSearch, usePortal, ...props } ) => {
17
+ let Component;
16
18
  const selectRef = React.useRef();
17
19
  const portalProps = {};
18
20
 
@@ -22,14 +24,25 @@ const Select = ( { isMulti = false, isInline, options, label, isSearch, usePorta
22
24
  portalProps.styles = { menuPortal: base => ( { ...base, position: 'fixed' } ) };
23
25
  }
24
26
 
25
- const Component = isInline ? InlineSelect : SearchSelect;
27
+ switch ( true ) {
28
+ case isInline:
29
+ Component = InlineSelect;
30
+ break;
31
+ case isAsync:
32
+ Component = AsyncSearchSelect;
33
+ break;
34
+ default:
35
+ Component = SearchSelect;
36
+ break;
37
+ }
26
38
 
27
- return <div ref={selectRef}><Component isMulti={isMulti} label={label} options={options} {...portalProps} {...props} /></div>;
39
+ return <div ref={selectRef} className="vip-select-component"><Component isMulti={isMulti} label={label} options={options} {...portalProps} {...props} /></div>;
28
40
  };
29
41
 
30
42
  Select.propTypes = {
31
43
  isInline: PropTypes.bool,
32
44
  isMulti: PropTypes.bool,
45
+ isAsync: PropTypes.bool,
33
46
  isSearch: PropTypes.bool,
34
47
  label: PropTypes.string,
35
48
  options: PropTypes.array,
@@ -105,6 +105,36 @@ export const Inline = () => {
105
105
  );
106
106
  };
107
107
 
108
+ export const Async = () => {
109
+ const [ value, setValue ] = useState( [] );
110
+ const loadOptions = async () => new Promise( resolve => {
111
+ setTimeout( () => {
112
+ resolve( {
113
+ options: [
114
+ ...options,
115
+ { value: 'newvanilla', label: 'New Vanilla' },
116
+ ],
117
+ } );
118
+ }, 2000 );
119
+ } );
120
+
121
+ return (
122
+ <Box sx={{ mr: 2, width: 200 }}>
123
+ <Select
124
+ label="Async Select"
125
+ value={value}
126
+ isAsync
127
+ usePortal
128
+ loadOptions={ loadOptions }
129
+ noneLabel="Everyone"
130
+ placeholder="Load async..."
131
+ options={options}
132
+ onChange={newValue => setValue( newValue )}
133
+ />
134
+ </Box>
135
+ );
136
+ };
137
+
108
138
  export const DropdownMenu = () => {
109
139
  return (
110
140
  <Box sx={{ mr: 2, width: 200 }}>
@@ -0,0 +1,37 @@
1
+ /**
2
+ * External dependencies
3
+ */
4
+ import { render, screen } from '@testing-library/react';
5
+ import { axe } from 'jest-axe';
6
+
7
+ /**
8
+ * Internal dependencies
9
+ */
10
+ import { Select } from './Select';
11
+
12
+ describe( '<Select />', () => {
13
+ it( 'renders the Select component with the specified placeholder', () => {
14
+ render(
15
+ <Select
16
+ inputId={ 'search-select' }
17
+ placeholder={ 'Search...' }
18
+ />
19
+ );
20
+
21
+ // Can't use `getByPlaceholderText` here since it's not actually being rendered as a placeholder element
22
+ const placeholder = screen.getByText( 'Search...' );
23
+
24
+ expect( placeholder ).toBeInTheDocument();
25
+ } );
26
+
27
+ it( 'renders the Select component with accessibility props', async () => {
28
+ const { container } = render(
29
+ <Select
30
+ inputId={ 'search-select' }
31
+ aria-label={ 'Search or select from the dropdown list' }
32
+ />
33
+ );
34
+
35
+ expect( await axe( container ) ).toHaveNoViolations();
36
+ } );
37
+ } );
@@ -3,10 +3,11 @@
3
3
  /**
4
4
  * External dependencies
5
5
  */
6
+ import classNames from 'classnames';
6
7
  import PropTypes from 'prop-types';
7
8
 
8
- const Toggle = ( { name = 'toggle', ...props } ) => (
9
- <CheckBoxWrapper>
9
+ const Toggle = ( { name = 'toggle', className = null, ...props } ) => (
10
+ <CheckBoxWrapper className={ classNames( 'vip-checkbox-component', className ) }>
10
11
  <CheckBox name={name} id={name} type="checkbox" {...props} />
11
12
  <CheckBoxLabel htmlFor={name} />
12
13
  </CheckBoxWrapper>
@@ -14,6 +15,7 @@ const Toggle = ( { name = 'toggle', ...props } ) => (
14
15
 
15
16
  Toggle.propTypes = {
16
17
  name: PropTypes.string,
18
+ className: PropTypes.any,
17
19
  };
18
20
 
19
21
  export { Toggle };
@@ -5,8 +5,9 @@
5
5
  */
6
6
  import { Heading as ThemeHeading } from 'theme-ui';
7
7
  import PropTypes from 'prop-types';
8
+ import classNames from 'classnames';
8
9
 
9
- const Heading = ( { variant = 'h3', sx, ...props } ) => (
10
+ const Heading = ( { variant = 'h3', sx, className = null, ...props } ) => (
10
11
  <ThemeHeading
11
12
  as={variant}
12
13
  sx={{
@@ -15,6 +16,7 @@ const Heading = ( { variant = 'h3', sx, ...props } ) => (
15
16
  variant: `text.${ variant }`,
16
17
  ...sx,
17
18
  }}
19
+ className={ classNames( 'vip-heading-component', className ) }
18
20
  {...props}
19
21
  />
20
22
  );
@@ -22,6 +24,7 @@ const Heading = ( { variant = 'h3', sx, ...props } ) => (
22
24
  Heading.propTypes = {
23
25
  variant: PropTypes.string,
24
26
  sx: PropTypes.object,
27
+ className: PropTypes.any,
25
28
  };
26
29
 
27
30
  export { Heading };
@@ -3,6 +3,7 @@
3
3
  /**
4
4
  * External dependencies
5
5
  */
6
+ import classNames from 'classnames';
6
7
  import PropTypes from 'prop-types';
7
8
  import { MdError, MdWarning, MdCheckCircle, MdInfo } from 'react-icons/md';
8
9
 
@@ -36,7 +37,7 @@ NoticeIcon.propTypes = {
36
37
  variant: PropTypes.string,
37
38
  };
38
39
 
39
- const Notice = ( { variant = 'warning', inline = false, children, title, sx = {}, ...props } ) => {
40
+ const Notice = ( { variant = 'warning', inline = false, children, title, sx = {}, className = null, ...props } ) => {
40
41
  let color = 'yellow';
41
42
 
42
43
  switch ( variant ) {
@@ -66,6 +67,7 @@ const Notice = ( { variant = 'warning', inline = false, children, title, sx = {}
66
67
  },
67
68
  ...sx,
68
69
  } }
70
+ className={ classNames( 'vip-notice-component', className ) }
69
71
  { ...props }
70
72
  >
71
73
  <Flex sx={ {
@@ -93,6 +95,7 @@ Notice.propTypes = {
93
95
  sx: PropTypes.object,
94
96
  title: PropTypes.node,
95
97
  variant: PropTypes.string,
98
+ className: PropTypes.any,
96
99
  };
97
100
 
98
101
  export { Notice };
@@ -13,6 +13,7 @@ import { Box, Button, Card, Flex, Heading, Text } from '../';
13
13
 
14
14
  const Notification = ( { title, body, status = 'success', onClose } ) => (
15
15
  <Card
16
+ className="vip-notification-component"
16
17
  sx={{
17
18
  boxShadow: 'medium',
18
19
  width: 320,
@@ -11,6 +11,7 @@ import PropTypes from 'prop-types';
11
11
  * Internal dependencies
12
12
  */
13
13
  import { Badge, Box, Grid, Heading, Text } from '..';
14
+ import classNames from 'classnames';
14
15
 
15
16
  const OptionRow = ( {
16
17
  image,
@@ -24,6 +25,8 @@ const OptionRow = ( {
24
25
  to,
25
26
  small = false,
26
27
  disabled = false,
28
+ order = null,
29
+ className = null,
27
30
  ...props
28
31
  } ) => {
29
32
  const mergedCard = disabled
@@ -53,6 +56,8 @@ const OptionRow = ( {
53
56
  to={to}
54
57
  columns={[ 1, 1, 'auto 1fr auto' ]}
55
58
  gap={[ 3, 3, `${ small ? 3 : 4 }` ]}
59
+ data-order={ order || undefined }
60
+ className={ classNames( 'vip-option-row-component', className ) }
56
61
  {...props}
57
62
  sx={{
58
63
  alignItems: 'center',
@@ -119,6 +124,8 @@ OptionRow.propTypes = {
119
124
  to: PropTypes.string,
120
125
  small: PropTypes.bool,
121
126
  disabled: PropTypes.bool,
127
+ order: PropTypes.number,
128
+ className: PropTypes.any,
122
129
  };
123
130
 
124
131
  export { OptionRow };
@@ -26,6 +26,7 @@ export const Default = () => (
26
26
  label="Option Row"
27
27
  subTitle="Mostly used to link off to other pages."
28
28
  as="a"
29
+ order={ 2 }
29
30
  />
30
31
  </Box>
31
32
  );
@@ -0,0 +1,27 @@
1
+ /**
2
+ * External dependencies
3
+ */
4
+ import { render, screen } from '@testing-library/react';
5
+ import { axe } from 'jest-axe';
6
+
7
+ /**
8
+ * Internal dependencies
9
+ */
10
+ import { OptionRow } from './OptionRow';
11
+
12
+ describe( '<OptionRow />', () => {
13
+ it( 'renders the OptionRow', async () => {
14
+ const { container } = render(
15
+ <OptionRow
16
+ label="Option Row"
17
+ subTitle="Mostly used to link off to other pages."
18
+ as="a"
19
+ />
20
+ );
21
+
22
+ expect( screen.getByText( 'Mostly used to link off to other pages.' ) ).toBeInTheDocument();
23
+
24
+ // Check for accessibility issues
25
+ await expect( await axe( container ) ).toHaveNoViolations();
26
+ } );
27
+ } );
@@ -11,10 +11,12 @@ import PropTypes from 'prop-types';
11
11
  */
12
12
  import { Spinner } from '../Spinner';
13
13
  import { Box, Heading, Text, Flex } from '../';
14
+ import classNames from 'classnames';
14
15
 
15
- const Progress = ( { steps, activeStep, sx, ...props } ) => (
16
+ const Progress = ( { steps, activeStep, sx, className, ...props } ) => (
16
17
  <Box>
17
18
  <ThemeProgress
19
+ className={ classNames( 'vip-progress-component', className ) }
18
20
  { ...props }
19
21
  sx={ {
20
22
  color: 'primary',
@@ -39,6 +41,7 @@ Progress.propTypes = {
39
41
  steps: PropTypes.array,
40
42
  activeStep: PropTypes.number,
41
43
  sx: PropTypes.object,
44
+ className: PropTypes.any,
42
45
  };
43
46
 
44
47
  export { Progress };
@@ -59,7 +59,7 @@ const ResourceList = ( { groupedByDay = false, items, renderItem, dateKey } ) =>
59
59
  itemsList.map( ( item, index ) => <StyledListItem key={index}>{renderItem( item )}</StyledListItem> );
60
60
 
61
61
  return (
62
- <Box as="ul" sx={{ listStyleType: 'none', m: 0, p: 0 }}>
62
+ <Box as="ul" sx={{ listStyleType: 'none', m: 0, p: 0 }} className="vip-resource-list-component">
63
63
  {groupedByDay
64
64
  ? Object.keys( groupedItems ).map( ( groupName, index ) => (
65
65
  <Box sx={{ mb: 4 }} key={index}>
@@ -5,20 +5,23 @@
5
5
  */
6
6
  import { Spinner as ThemeSpinner } from 'theme-ui';
7
7
  import PropTypes from 'prop-types';
8
+ import classNames from 'classnames';
8
9
 
9
- const Spinner = ( { sx, ...props } ) => (
10
+ const Spinner = ( { sx, className = null, ...props } ) => (
10
11
  <ThemeSpinner
11
12
  strokeWidth={2}
12
13
  sx={{
13
14
  fill: 'none',
14
15
  color: 'primary',
15
16
  }}
17
+ className={ classNames( 'vip-spinner-component', className ) }
16
18
  {...props}
17
19
  />
18
20
  );
19
21
 
20
22
  Spinner.propTypes = {
21
23
  sx: PropTypes.object,
24
+ className: PropTypes.any,
22
25
  };
23
26
 
24
27
  export { Spinner };
@@ -15,6 +15,7 @@ const TabItem = ( { active = false, sx, ...props } ) => (
15
15
  variant="h4"
16
16
  as="button"
17
17
  tabIndex="0"
18
+ data-active={ active || undefined }
18
19
  sx={ {
19
20
  cursor: 'pointer',
20
21
  background: 'none',
@@ -3,6 +3,7 @@
3
3
  /**
4
4
  * External dependencies
5
5
  */
6
+ import classNames from 'classnames';
6
7
  import PropTypes from 'prop-types';
7
8
 
8
9
  /**
@@ -10,8 +11,9 @@ import PropTypes from 'prop-types';
10
11
  */
11
12
  import { Flex } from '..';
12
13
 
13
- const Tabs = ( { sx, ...props } ) => (
14
+ const Tabs = ( { className = null, sx, ...props } ) => (
14
15
  <Flex
16
+ className={ classNames( 'vip-tabs-component', className ) }
15
17
  sx={{
16
18
  borderBottom: '1px solid',
17
19
  borderColor: 'border',
@@ -25,8 +27,9 @@ const Tabs = ( { sx, ...props } ) => (
25
27
  );
26
28
 
27
29
  Tabs.propTypes = {
28
- variant: PropTypes.string,
30
+ className: PropTypes.any,
29
31
  sx: PropTypes.object,
32
+ variant: PropTypes.string,
30
33
  };
31
34
 
32
35
  export { Tabs };