@automattic/vip-design-system 2.15.2 → 2.15.4

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.
@@ -7,16 +7,17 @@ import Autocomplete from 'accessible-autocomplete/react';
7
7
  import classNames from 'classnames';
8
8
  import PropTypes from 'prop-types';
9
9
  import React, { useCallback, useEffect, useMemo, useState } from 'react';
10
- import { MdClose } from 'react-icons/md';
11
10
 
12
11
  /**
13
12
  * Internal dependencies
14
13
  */
14
+ import { FormAutocompleteMultiselectBadge } from './FormAutocompleteMultiselectBadge';
15
+ import { FormAutocompleteMultiselectButton } from './FormAutocompleteMultiselectButton';
15
16
  import { FormSelectArrow } from './FormSelectArrow';
16
17
  import { FormSelectContent } from './FormSelectContent';
17
18
  import { FormSelectLoading } from './FormSelectLoading';
18
19
  import { FormSelectSearch } from './FormSelectSearch';
19
- import { Button, Flex } from '../';
20
+ import { Flex } from '../';
20
21
  import { Validation } from '../Form';
21
22
  import { baseControlBorderStyle, inputBaseText } from '../Form/Input.styles';
22
23
  import { Label } from '../Form/Label';
@@ -126,42 +127,6 @@ AddSelectionStatus.propTypes = {
126
127
  status: PropTypes.string.isRequired,
127
128
  };
128
129
 
129
- const SelectedOptions = ( { index, option, unselectValue } ) => {
130
- return (
131
- <div key={ index } sx={ { mr: 1, maxWidth: '100%' } }>
132
- <Button
133
- variant="tertiary"
134
- onClick={ e => {
135
- e.preventDefault();
136
- unselectValue( option, index );
137
- } }
138
- sx={ {
139
- mt: 1,
140
- fontSize: 1,
141
- maxWidth: '100%',
142
- } }
143
- >
144
- <div
145
- sx={ {
146
- overflow: 'hidden',
147
- textOverflow: 'ellipsis',
148
- whiteSpace: 'nowrap',
149
- } }
150
- >
151
- { option }
152
- </div>
153
- <MdClose sx={ { ml: 2 } } />
154
- </Button>
155
- </div>
156
- );
157
- };
158
-
159
- SelectedOptions.propTypes = {
160
- index: PropTypes.number.isRequired,
161
- option: PropTypes.string.isRequired,
162
- unselectValue: PropTypes.func.isRequired,
163
- };
164
-
165
130
  const FormAutocompleteMultiselect = React.forwardRef(
166
131
  (
167
132
  {
@@ -188,6 +153,8 @@ const FormAutocompleteMultiselect = React.forwardRef(
188
153
  showAllValues = false,
189
154
  source,
190
155
  value,
156
+ listType = 'button',
157
+ initialValue = [],
191
158
  ...props
192
159
  },
193
160
  forwardRef
@@ -197,8 +164,10 @@ const FormAutocompleteMultiselect = React.forwardRef(
197
164
  REMOVE: 'remove',
198
165
  NONE: 'none',
199
166
  };
167
+ const ListComponent =
168
+ listType === 'button' ? FormAutocompleteMultiselectButton : FormAutocompleteMultiselectBadge;
200
169
  const [ isDirty, setIsDirty ] = useState( false );
201
- const [ selectedOptions, setSelectedOptions ] = useState( [] );
170
+ const [ selectedOptions, setSelectedOptions ] = useState( initialValue );
202
171
  const [ addStatus, setAddStatus ] = useState( '' );
203
172
  const [ currentOption, setCurrentOption ] = useState( {
204
173
  action: OPTION_ACTION.NONE,
@@ -367,10 +336,10 @@ const FormAutocompleteMultiselect = React.forwardRef(
367
336
  setCurrentOption( { action: OPTION_ACTION.NONE, option: null } );
368
337
  } else if ( currentOption.index === selectedOptions.length && selectedOptions.length > 0 ) {
369
338
  // Move focus to the first selected item, if the last element is removed and there are other elements in the list
370
- global.document.querySelector( '.vip-button-component' ).focus();
339
+ global.document.querySelector( '.vip-button-component' )?.focus();
371
340
  } else if ( selectedOptions.length === 0 ) {
372
341
  // Move focus to the input field if the last element is removed and there are no other elements in the list
373
- global.document.querySelector( '.autocomplete__input' ).focus();
342
+ global.document.querySelector( '.autocomplete__input' )?.focus();
374
343
  }
375
344
  }, [ currentOption ] );
376
345
 
@@ -421,7 +390,7 @@ const FormAutocompleteMultiselect = React.forwardRef(
421
390
  <div sx={ { display: 'inline-flex', flexWrap: 'wrap', maxWidth: '100%' } }>
422
391
  { selectedOptions &&
423
392
  selectedOptions.map( ( option, idx ) => (
424
- <SelectedOptions
393
+ <ListComponent
425
394
  key={ idx }
426
395
  index={ idx }
427
396
  option={ option }
@@ -458,6 +427,7 @@ FormAutocompleteMultiselect.propTypes = {
458
427
  source: PropTypes.func,
459
428
  value: PropTypes.string,
460
429
  dropdownArrow: PropTypes.node,
430
+ initialValue: PropTypes.array,
461
431
  };
462
432
 
463
433
  FormAutocompleteMultiselect.displayName = 'FormAutocompleteMultiselect';
@@ -29,6 +29,8 @@ declare namespace _default {
29
29
  }
30
30
  export default _default;
31
31
  export function Default(): import("react").JSX.Element;
32
+ export function WithBadges(): import("react").JSX.Element;
33
+ export function WithInitialValueBadges(): import("react").JSX.Element;
32
34
  export function Inline(): import("react").JSX.Element;
33
35
  export namespace Inline {
34
36
  let displayName: string;
@@ -86,6 +86,32 @@ export const Default = () => {
86
86
  );
87
87
  };
88
88
 
89
+ export const WithBadges = () => {
90
+ const customArgs = {
91
+ ...args,
92
+ listType: 'badge',
93
+ };
94
+
95
+ return (
96
+ <>
97
+ <DefaultComponent { ...customArgs } />
98
+ </>
99
+ );
100
+ };
101
+
102
+ export const WithInitialValueBadges = () => {
103
+ const customArgs = {
104
+ ...args,
105
+ initialValue: shortOptions.slice( 0, 2 ).map( option => option.label ),
106
+ };
107
+
108
+ return (
109
+ <>
110
+ <DefaultComponent { ...customArgs } />
111
+ </>
112
+ );
113
+ };
114
+
89
115
  export const Inline = () => {
90
116
  const customArgs = {
91
117
  isInline: true,
@@ -0,0 +1,8 @@
1
+ /** @jsxImportSource theme-ui */
2
+ /// <reference types="react" />
3
+ declare const FormAutocompleteMultiselectBadge: ({ index, option, unselectValue, }: {
4
+ index: number;
5
+ option: string;
6
+ unselectValue: (option: string, index: number) => void;
7
+ }) => import("react").JSX.Element;
8
+ export { FormAutocompleteMultiselectBadge };
@@ -0,0 +1,49 @@
1
+ /** @jsxImportSource theme-ui */
2
+
3
+ /**
4
+ * External dependencies
5
+ */
6
+ import { MdClose } from 'react-icons/md';
7
+ import { Badge } from '..';
8
+ import { jsx as _jsx } from "theme-ui/jsx-runtime";
9
+ import { jsxs as _jsxs } from "theme-ui/jsx-runtime";
10
+ var FormAutocompleteMultiselectBadge = function FormAutocompleteMultiselectBadge(_ref) {
11
+ var index = _ref.index,
12
+ option = _ref.option,
13
+ unselectValue = _ref.unselectValue;
14
+ return _jsx("div", {
15
+ sx: {
16
+ mr: 1,
17
+ maxWidth: '100%'
18
+ },
19
+ children: _jsxs(Badge, {
20
+ variant: "gray",
21
+ sx: {
22
+ mt: 1,
23
+ fontSize: 1,
24
+ maxWidth: '100%',
25
+ display: 'flex',
26
+ alignItems: 'center',
27
+ justifyContent: 'space-between'
28
+ },
29
+ children: [_jsx("div", {
30
+ sx: {
31
+ overflow: 'hidden',
32
+ textOverflow: 'ellipsis',
33
+ whiteSpace: 'nowrap'
34
+ },
35
+ children: option
36
+ }), _jsx(MdClose, {
37
+ sx: {
38
+ ml: 2,
39
+ cursor: 'pointer'
40
+ },
41
+ onClick: function onClick(e) {
42
+ e.preventDefault();
43
+ unselectValue(option, index);
44
+ }
45
+ })]
46
+ })
47
+ }, index);
48
+ };
49
+ export { FormAutocompleteMultiselectBadge };
@@ -0,0 +1,8 @@
1
+ /** @jsxImportSource theme-ui */
2
+ /// <reference types="react" />
3
+ declare const FormAutocompleteMultiselectButton: ({ index, option, unselectValue, }: {
4
+ index: number;
5
+ option: string;
6
+ unselectValue: (option: string, index: number) => void;
7
+ }) => import("react").JSX.Element;
8
+ export { FormAutocompleteMultiselectButton };
@@ -0,0 +1,45 @@
1
+ /** @jsxImportSource theme-ui */
2
+
3
+ /**
4
+ * External dependencies
5
+ */
6
+ import { MdClose } from 'react-icons/md';
7
+ import { Button } from '..';
8
+ import { jsx as _jsx } from "theme-ui/jsx-runtime";
9
+ import { jsxs as _jsxs } from "theme-ui/jsx-runtime";
10
+ var FormAutocompleteMultiselectButton = function FormAutocompleteMultiselectButton(_ref) {
11
+ var index = _ref.index,
12
+ option = _ref.option,
13
+ unselectValue = _ref.unselectValue;
14
+ return _jsx("div", {
15
+ sx: {
16
+ mr: 1,
17
+ maxWidth: '100%'
18
+ },
19
+ children: _jsxs(Button, {
20
+ variant: "tertiary",
21
+ onClick: function onClick(e) {
22
+ e.preventDefault();
23
+ unselectValue(option, index);
24
+ },
25
+ sx: {
26
+ mt: 1,
27
+ fontSize: 1,
28
+ maxWidth: '100%'
29
+ },
30
+ children: [_jsx("div", {
31
+ sx: {
32
+ overflow: 'hidden',
33
+ textOverflow: 'ellipsis',
34
+ whiteSpace: 'nowrap'
35
+ },
36
+ children: option
37
+ }), _jsx(MdClose, {
38
+ sx: {
39
+ ml: 2
40
+ }
41
+ })]
42
+ })
43
+ }, index);
44
+ };
45
+ export { FormAutocompleteMultiselectButton };
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@automattic/vip-design-system",
3
- "version": "2.15.2",
3
+ "version": "2.15.4",
4
4
  "main": "build/system/index.js",
5
5
  "scripts": {
6
6
  "build-storybook": "storybook build",
@@ -7,16 +7,17 @@ import Autocomplete from 'accessible-autocomplete/react';
7
7
  import classNames from 'classnames';
8
8
  import PropTypes from 'prop-types';
9
9
  import React, { useCallback, useEffect, useMemo, useState } from 'react';
10
- import { MdClose } from 'react-icons/md';
11
10
 
12
11
  /**
13
12
  * Internal dependencies
14
13
  */
14
+ import { FormAutocompleteMultiselectBadge } from './FormAutocompleteMultiselectBadge';
15
+ import { FormAutocompleteMultiselectButton } from './FormAutocompleteMultiselectButton';
15
16
  import { FormSelectArrow } from './FormSelectArrow';
16
17
  import { FormSelectContent } from './FormSelectContent';
17
18
  import { FormSelectLoading } from './FormSelectLoading';
18
19
  import { FormSelectSearch } from './FormSelectSearch';
19
- import { Button, Flex } from '../';
20
+ import { Flex } from '../';
20
21
  import { Validation } from '../Form';
21
22
  import { baseControlBorderStyle, inputBaseText } from '../Form/Input.styles';
22
23
  import { Label } from '../Form/Label';
@@ -126,42 +127,6 @@ AddSelectionStatus.propTypes = {
126
127
  status: PropTypes.string.isRequired,
127
128
  };
128
129
 
129
- const SelectedOptions = ( { index, option, unselectValue } ) => {
130
- return (
131
- <div key={ index } sx={ { mr: 1, maxWidth: '100%' } }>
132
- <Button
133
- variant="tertiary"
134
- onClick={ e => {
135
- e.preventDefault();
136
- unselectValue( option, index );
137
- } }
138
- sx={ {
139
- mt: 1,
140
- fontSize: 1,
141
- maxWidth: '100%',
142
- } }
143
- >
144
- <div
145
- sx={ {
146
- overflow: 'hidden',
147
- textOverflow: 'ellipsis',
148
- whiteSpace: 'nowrap',
149
- } }
150
- >
151
- { option }
152
- </div>
153
- <MdClose sx={ { ml: 2 } } />
154
- </Button>
155
- </div>
156
- );
157
- };
158
-
159
- SelectedOptions.propTypes = {
160
- index: PropTypes.number.isRequired,
161
- option: PropTypes.string.isRequired,
162
- unselectValue: PropTypes.func.isRequired,
163
- };
164
-
165
130
  const FormAutocompleteMultiselect = React.forwardRef(
166
131
  (
167
132
  {
@@ -188,6 +153,8 @@ const FormAutocompleteMultiselect = React.forwardRef(
188
153
  showAllValues = false,
189
154
  source,
190
155
  value,
156
+ listType = 'button',
157
+ initialValue = [],
191
158
  ...props
192
159
  },
193
160
  forwardRef
@@ -197,8 +164,10 @@ const FormAutocompleteMultiselect = React.forwardRef(
197
164
  REMOVE: 'remove',
198
165
  NONE: 'none',
199
166
  };
167
+ const ListComponent =
168
+ listType === 'button' ? FormAutocompleteMultiselectButton : FormAutocompleteMultiselectBadge;
200
169
  const [ isDirty, setIsDirty ] = useState( false );
201
- const [ selectedOptions, setSelectedOptions ] = useState( [] );
170
+ const [ selectedOptions, setSelectedOptions ] = useState( initialValue );
202
171
  const [ addStatus, setAddStatus ] = useState( '' );
203
172
  const [ currentOption, setCurrentOption ] = useState( {
204
173
  action: OPTION_ACTION.NONE,
@@ -367,10 +336,10 @@ const FormAutocompleteMultiselect = React.forwardRef(
367
336
  setCurrentOption( { action: OPTION_ACTION.NONE, option: null } );
368
337
  } else if ( currentOption.index === selectedOptions.length && selectedOptions.length > 0 ) {
369
338
  // Move focus to the first selected item, if the last element is removed and there are other elements in the list
370
- global.document.querySelector( '.vip-button-component' ).focus();
339
+ global.document.querySelector( '.vip-button-component' )?.focus();
371
340
  } else if ( selectedOptions.length === 0 ) {
372
341
  // Move focus to the input field if the last element is removed and there are no other elements in the list
373
- global.document.querySelector( '.autocomplete__input' ).focus();
342
+ global.document.querySelector( '.autocomplete__input' )?.focus();
374
343
  }
375
344
  }, [ currentOption ] );
376
345
 
@@ -421,7 +390,7 @@ const FormAutocompleteMultiselect = React.forwardRef(
421
390
  <div sx={ { display: 'inline-flex', flexWrap: 'wrap', maxWidth: '100%' } }>
422
391
  { selectedOptions &&
423
392
  selectedOptions.map( ( option, idx ) => (
424
- <SelectedOptions
393
+ <ListComponent
425
394
  key={ idx }
426
395
  index={ idx }
427
396
  option={ option }
@@ -458,6 +427,7 @@ FormAutocompleteMultiselect.propTypes = {
458
427
  source: PropTypes.func,
459
428
  value: PropTypes.string,
460
429
  dropdownArrow: PropTypes.node,
430
+ initialValue: PropTypes.array,
461
431
  };
462
432
 
463
433
  FormAutocompleteMultiselect.displayName = 'FormAutocompleteMultiselect';
@@ -86,6 +86,32 @@ export const Default = () => {
86
86
  );
87
87
  };
88
88
 
89
+ export const WithBadges = () => {
90
+ const customArgs = {
91
+ ...args,
92
+ listType: 'badge',
93
+ };
94
+
95
+ return (
96
+ <>
97
+ <DefaultComponent { ...customArgs } />
98
+ </>
99
+ );
100
+ };
101
+
102
+ export const WithInitialValueBadges = () => {
103
+ const customArgs = {
104
+ ...args,
105
+ initialValue: shortOptions.slice( 0, 2 ).map( option => option.label ),
106
+ };
107
+
108
+ return (
109
+ <>
110
+ <DefaultComponent { ...customArgs } />
111
+ </>
112
+ );
113
+ };
114
+
89
115
  export const Inline = () => {
90
116
  const customArgs = {
91
117
  isInline: true,
@@ -0,0 +1,53 @@
1
+ /** @jsxImportSource theme-ui */
2
+
3
+ /**
4
+ * External dependencies
5
+ */
6
+ import { MdClose } from 'react-icons/md';
7
+
8
+ import { Badge } from '..';
9
+
10
+ const FormAutocompleteMultiselectBadge = ( {
11
+ index,
12
+ option,
13
+ unselectValue,
14
+ }: {
15
+ index: number;
16
+ option: string;
17
+ unselectValue: ( option: string, index: number ) => void;
18
+ } ) => {
19
+ return (
20
+ <div key={ index } sx={ { mr: 1, maxWidth: '100%' } }>
21
+ <Badge
22
+ variant="gray"
23
+ sx={ {
24
+ mt: 1,
25
+ fontSize: 1,
26
+ maxWidth: '100%',
27
+ display: 'flex',
28
+ alignItems: 'center',
29
+ justifyContent: 'space-between',
30
+ } }
31
+ >
32
+ <div
33
+ sx={ {
34
+ overflow: 'hidden',
35
+ textOverflow: 'ellipsis',
36
+ whiteSpace: 'nowrap',
37
+ } }
38
+ >
39
+ { option }
40
+ </div>
41
+ <MdClose
42
+ sx={ { ml: 2, cursor: 'pointer' } }
43
+ onClick={ e => {
44
+ e.preventDefault();
45
+ unselectValue( option, index );
46
+ } }
47
+ />
48
+ </Badge>
49
+ </div>
50
+ );
51
+ };
52
+
53
+ export { FormAutocompleteMultiselectBadge };
@@ -0,0 +1,48 @@
1
+ /** @jsxImportSource theme-ui */
2
+
3
+ /**
4
+ * External dependencies
5
+ */
6
+ import { MdClose } from 'react-icons/md';
7
+
8
+ import { Button } from '..';
9
+
10
+ const FormAutocompleteMultiselectButton = ( {
11
+ index,
12
+ option,
13
+ unselectValue,
14
+ }: {
15
+ index: number;
16
+ option: string;
17
+ unselectValue: ( option: string, index: number ) => void;
18
+ } ) => {
19
+ return (
20
+ <div key={ index } sx={ { mr: 1, maxWidth: '100%' } }>
21
+ <Button
22
+ variant="tertiary"
23
+ onClick={ e => {
24
+ e.preventDefault();
25
+ unselectValue( option, index );
26
+ } }
27
+ sx={ {
28
+ mt: 1,
29
+ fontSize: 1,
30
+ maxWidth: '100%',
31
+ } }
32
+ >
33
+ <div
34
+ sx={ {
35
+ overflow: 'hidden',
36
+ textOverflow: 'ellipsis',
37
+ whiteSpace: 'nowrap',
38
+ } }
39
+ >
40
+ { option }
41
+ </div>
42
+ <MdClose sx={ { ml: 2 } } />
43
+ </Button>
44
+ </div>
45
+ );
46
+ };
47
+
48
+ export { FormAutocompleteMultiselectButton };