@automattic/vip-design-system 0.27.5 → 0.27.6

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.
@@ -20,19 +20,6 @@ var _themeUi = require("theme-ui");
20
20
  var _jsxRuntime = require("theme-ui/jsx-runtime");
21
21
 
22
22
  var _excluded = ["variant", "label", "forLabel", "hasError", "required", "sx", "errorMessage"];
23
-
24
- var RequiredLabel = function RequiredLabel() {
25
- return (0, _jsxRuntime.jsx)("span", {
26
- sx: {
27
- color: 'error',
28
- display: 'inline-block',
29
- ml: 2,
30
- fontSize: 1
31
- },
32
- children: "(Required)"
33
- });
34
- };
35
-
36
23
  var inputStyles = {
37
24
  unset: 'all',
38
25
  border: '1px solid',
@@ -72,9 +59,10 @@ var Input = /*#__PURE__*/_react["default"].forwardRef(function (_ref, ref) {
72
59
  errorMessage = _ref.errorMessage,
73
60
  props = (0, _objectWithoutPropertiesLoose2["default"])(_ref, _excluded);
74
61
  return (0, _jsxRuntime.jsxs)(_react["default"].Fragment, {
75
- children: [label && (0, _jsxRuntime.jsxs)(_.Label, {
62
+ children: [label && (0, _jsxRuntime.jsx)(_.Label, {
63
+ required: required,
76
64
  htmlFor: forLabel,
77
- children: [label, required && (0, _jsxRuntime.jsx)(RequiredLabel, {})]
65
+ children: label
78
66
  }), (0, _jsxRuntime.jsx)(_themeUi.Input, (0, _extends2["default"])({
79
67
  ref: ref,
80
68
  id: forLabel,
@@ -13,17 +13,18 @@ var _react = _interopRequireDefault(require("react"));
13
13
 
14
14
  var _propTypes = _interopRequireDefault(require("prop-types"));
15
15
 
16
+ var _RequiredLabel = require("./RequiredLabel");
17
+
16
18
  var _jsxRuntime = require("theme-ui/jsx-runtime");
17
19
 
18
- var _excluded = ["sx"];
20
+ var _excluded = ["sx", "children", "required"];
19
21
 
20
- /**
21
- * Internal dependencies
22
- */
23
22
  var Label = /*#__PURE__*/_react["default"].forwardRef(function (_ref, forwardRef) {
24
23
  var sx = _ref.sx,
24
+ children = _ref.children,
25
+ required = _ref.required,
25
26
  rest = (0, _objectWithoutPropertiesLoose2["default"])(_ref, _excluded);
26
- return (0, _jsxRuntime.jsx)("label", (0, _extends2["default"])({
27
+ return (0, _jsxRuntime.jsxs)("label", (0, _extends2["default"])({
27
28
  sx: (0, _extends2["default"])({
28
29
  fontWeight: 500,
29
30
  fontSize: 2,
@@ -33,11 +34,15 @@ var Label = /*#__PURE__*/_react["default"].forwardRef(function (_ref, forwardRef
33
34
  color: 'muted'
34
35
  }, sx),
35
36
  ref: forwardRef
36
- }, rest));
37
+ }, rest, {
38
+ children: [children, required && (0, _jsxRuntime.jsx)(_RequiredLabel.RequiredLabel, {})]
39
+ }));
37
40
  });
38
41
 
39
42
  exports.Label = Label;
40
43
  Label.propTypes = {
44
+ children: _propTypes["default"].object,
45
+ required: _propTypes["default"].bool,
41
46
  sx: _propTypes["default"].object
42
47
  };
43
48
  Label.displayName = 'Label';
@@ -0,0 +1,49 @@
1
+ "use strict";
2
+
3
+ var _interopRequireDefault = require("@babel/runtime/helpers/interopRequireDefault");
4
+
5
+ exports.__esModule = true;
6
+ exports["default"] = exports.Required = exports.Default = void 0;
7
+
8
+ var _extends2 = _interopRequireDefault(require("@babel/runtime/helpers/extends"));
9
+
10
+ var _ = require("..");
11
+
12
+ var _jsxRuntime = require("theme-ui/jsx-runtime");
13
+
14
+ /** @jsxImportSource theme-ui */
15
+
16
+ /**
17
+ * Internal dependencies
18
+ */
19
+ var _default = {
20
+ title: 'Form/Label'
21
+ };
22
+ exports["default"] = _default;
23
+
24
+ var DefaultComponent = function DefaultComponent(props) {
25
+ return (0, _jsxRuntime.jsx)(_.Form.Root, {
26
+ children: (0, _jsxRuntime.jsx)(_.Label, (0, _extends2["default"])({}, props, {
27
+ children: "Label"
28
+ }))
29
+ });
30
+ };
31
+
32
+ var Default = function Default() {
33
+ return (0, _jsxRuntime.jsx)(_jsxRuntime.Fragment, {
34
+ children: (0, _jsxRuntime.jsx)(DefaultComponent, {})
35
+ });
36
+ };
37
+
38
+ exports.Default = Default;
39
+
40
+ var Required = function Required() {
41
+ var args = {
42
+ required: true
43
+ };
44
+ return (0, _jsxRuntime.jsx)(_jsxRuntime.Fragment, {
45
+ children: (0, _jsxRuntime.jsx)(DefaultComponent, (0, _extends2["default"])({}, args))
46
+ });
47
+ };
48
+
49
+ exports.Required = Required;
@@ -0,0 +1,29 @@
1
+ "use strict";
2
+
3
+ exports.__esModule = true;
4
+ exports.RequiredLabel = void 0;
5
+
6
+ var _jsxRuntime = require("theme-ui/jsx-runtime");
7
+
8
+ /** @jsxImportSource theme-ui */
9
+
10
+ /**
11
+ * External dependencies
12
+ */
13
+
14
+ /**
15
+ * Internal dependencies
16
+ */
17
+ var RequiredLabel = function RequiredLabel() {
18
+ return (0, _jsxRuntime.jsx)("span", {
19
+ sx: {
20
+ color: 'error',
21
+ display: 'inline-block',
22
+ ml: 2,
23
+ fontSize: 1
24
+ },
25
+ children: "(Required)"
26
+ });
27
+ };
28
+
29
+ exports.RequiredLabel = RequiredLabel;
@@ -33,7 +33,7 @@ var _FormSelectLoading = require("./FormSelectLoading");
33
33
 
34
34
  var _jsxRuntime = require("theme-ui/jsx-runtime");
35
35
 
36
- var _excluded = ["isInline", "forLabel", "options", "label", "getOptionLabel", "getOptionValue", "onChange", "onInputChange", "value", "showAllValues", "searchIcon", "loading", "displayMenu", "noOptionsMessage", "id", "className"];
36
+ var _excluded = ["isInline", "forLabel", "options", "label", "getOptionLabel", "getOptionValue", "onChange", "onInputChange", "value", "showAllValues", "searchIcon", "minLength", "debounce", "loading", "required", "displayMenu", "noOptionsMessage", "id", "className"];
37
37
 
38
38
  function _getRequireWildcardCache(nodeInterop) { if (typeof WeakMap !== "function") return null; var cacheBabelInterop = new WeakMap(); var cacheNodeInterop = new WeakMap(); return (_getRequireWildcardCache = function _getRequireWildcardCache(nodeInterop) { return nodeInterop ? cacheNodeInterop : cacheBabelInterop; })(nodeInterop); }
39
39
 
@@ -136,7 +136,8 @@ var searchIconStyles = {
136
136
  var FormAutocomplete = /*#__PURE__*/_react["default"].forwardRef(function (_ref, forwardRef) {
137
137
  var isInline = _ref.isInline,
138
138
  forLabel = _ref.forLabel,
139
- options = _ref.options,
139
+ _ref$options = _ref.options,
140
+ options = _ref$options === void 0 ? [] : _ref$options,
140
141
  label = _ref.label,
141
142
  getOptionLabel = _ref.getOptionLabel,
142
143
  getOptionValue = _ref.getOptionValue,
@@ -146,10 +147,13 @@ var FormAutocomplete = /*#__PURE__*/_react["default"].forwardRef(function (_ref,
146
147
  value = _ref.value,
147
148
  _ref$showAllValues = _ref.showAllValues,
148
149
  showAllValues = _ref$showAllValues === void 0 ? true : _ref$showAllValues,
149
- _ref$searchIcon = _ref.searchIcon,
150
- searchIcon = _ref$searchIcon === void 0 ? false : _ref$searchIcon,
151
- _ref$loading = _ref.loading,
152
- loading = _ref$loading === void 0 ? false : _ref$loading,
150
+ searchIcon = _ref.searchIcon,
151
+ _ref$minLength = _ref.minLength,
152
+ minLength = _ref$minLength === void 0 ? 0 : _ref$minLength,
153
+ _ref$debounce = _ref.debounce,
154
+ debounce = _ref$debounce === void 0 ? 0 : _ref$debounce,
155
+ loading = _ref.loading,
156
+ required = _ref.required,
153
157
  _ref$displayMenu = _ref.displayMenu,
154
158
  displayMenu = _ref$displayMenu === void 0 ? 'overlay' : _ref$displayMenu,
155
159
  _ref$noOptionsMessage = _ref.noOptionsMessage,
@@ -165,8 +169,11 @@ var FormAutocomplete = /*#__PURE__*/_react["default"].forwardRef(function (_ref,
165
169
  isDirty = _useState[0],
166
170
  setIsDirty = _useState[1];
167
171
 
172
+ var debounceTimeout;
173
+
168
174
  var SelectLabel = function SelectLabel() {
169
175
  return (0, _jsxRuntime.jsx)(_Label.Label, {
176
+ required: required,
170
177
  htmlFor: forLabel || id,
171
178
  children: label
172
179
  });
@@ -202,13 +209,21 @@ var FormAutocomplete = /*#__PURE__*/_react["default"].forwardRef(function (_ref,
202
209
  return optionLabel(option).toLowerCase().indexOf(query.toLowerCase()) >= 0;
203
210
  });
204
211
  }, [options]);
205
- var suggest = (0, _react.useCallback)(function (query, populateResults) {
206
- var data = options;
212
+ var handleInputChange = (0, _react.useCallback)(function (query) {
213
+ clearTimeout(debounceTimeout);
207
214
 
208
- if (isDirty) {
209
- data = onInputChange ? onInputChange(query) : handleTypeChange(query);
215
+ if (!query.length || query.length >= minLength) {
216
+ debounceTimeout = setTimeout(function () {
217
+ onInputChange(query);
218
+ }, debounce);
219
+ }
220
+ }, [onInputChange, debounce, minLength]);
221
+ var suggest = (0, _react.useCallback)(function (query, populateResults) {
222
+ if (isDirty && onInputChange) {
223
+ handleInputChange(query);
210
224
  }
211
225
 
226
+ var data = handleTypeChange(query);
212
227
  populateResults(data.map(function (option) {
213
228
  return optionLabel(option);
214
229
  }));
@@ -253,6 +268,7 @@ FormAutocomplete.propTypes = {
253
268
  showAllValues: _propTypes["default"].bool,
254
269
  searchIcon: _propTypes["default"].bool,
255
270
  loading: _propTypes["default"].bool,
271
+ required: _propTypes["default"].bool,
256
272
  isInline: _propTypes["default"].bool,
257
273
  forLabel: _propTypes["default"].string,
258
274
  value: _propTypes["default"].string,
@@ -264,6 +280,8 @@ FormAutocomplete.propTypes = {
264
280
  onInputChange: _propTypes["default"].func,
265
281
  noOptionsMessage: _propTypes["default"].func,
266
282
  onChange: _propTypes["default"].func,
267
- className: _propTypes["default"].any
283
+ className: _propTypes["default"].any,
284
+ minLength: _propTypes["default"].number,
285
+ debounce: _propTypes["default"].number
268
286
  };
269
287
  FormAutocomplete.displayName = 'FormAutocomplete';
@@ -3,12 +3,14 @@
3
3
  var _interopRequireDefault = require("@babel/runtime/helpers/interopRequireDefault");
4
4
 
5
5
  exports.__esModule = true;
6
- exports["default"] = exports.WithSearchIcon = exports.WithLoading = exports.WithDefaultValue = exports.WithCustomMessages = exports.Inline = exports.Default = void 0;
6
+ exports["default"] = exports.WithSearchIcon = exports.WithLoading = exports.WithDefaultValue = exports.WithDebounce = exports.WithCustomMessages = exports.Inline = exports.Default = void 0;
7
7
 
8
8
  var _extends2 = _interopRequireDefault(require("@babel/runtime/helpers/extends"));
9
9
 
10
10
  var _objectWithoutPropertiesLoose2 = _interopRequireDefault(require("@babel/runtime/helpers/objectWithoutPropertiesLoose"));
11
11
 
12
+ var _react = require("react");
13
+
12
14
  var Form = _interopRequireWildcard(require("."));
13
15
 
14
16
  var _jsxRuntime = require("theme-ui/jsx-runtime");
@@ -81,7 +83,9 @@ var DefaultComponent = function DefaultComponent(_ref) {
81
83
 
82
84
  var Default = function Default() {
83
85
  return (0, _jsxRuntime.jsx)(_jsxRuntime.Fragment, {
84
- children: (0, _jsxRuntime.jsx)(DefaultComponent, (0, _extends2["default"])({}, args))
86
+ children: (0, _jsxRuntime.jsx)(DefaultComponent, (0, _extends2["default"])({
87
+ required: true
88
+ }, args))
85
89
  });
86
90
  };
87
91
 
@@ -131,6 +135,25 @@ var WithLoading = function WithLoading() {
131
135
 
132
136
  exports.WithLoading = WithLoading;
133
137
 
138
+ var WithDebounce = function WithDebounce() {
139
+ var _useState = (0, _react.useState)(null),
140
+ value = _useState[0],
141
+ setValue = _useState[1];
142
+
143
+ var customArgs = (0, _extends2["default"])({}, args, {
144
+ minLength: 3,
145
+ debounce: 300,
146
+ onInputChange: function onInputChange(query) {
147
+ setValue(query);
148
+ }
149
+ });
150
+ return (0, _jsxRuntime.jsxs)(_jsxRuntime.Fragment, {
151
+ children: ["Filter: ", value, (0, _jsxRuntime.jsx)(DefaultComponent, (0, _extends2["default"])({}, customArgs))]
152
+ });
153
+ };
154
+
155
+ exports.WithDebounce = WithDebounce;
156
+
134
157
  var WithCustomMessages = function WithCustomMessages() {
135
158
  var customArgs = (0, _extends2["default"])({}, args, {
136
159
  noOptionsMessage: function noOptionsMessage() {
@@ -45,25 +45,53 @@ describe('<FormAutocomplete />', function () {
45
45
  while (1) {
46
46
  switch (_context.prev = _context.next) {
47
47
  case 0:
48
- _render = (0, _react.render)((0, _jsxRuntime.jsx)(_FormAutocomplete.FormAutocomplete, (0, _extends2["default"])({
49
- id: "my_desert_list"
50
- }, defaultProps))), container = _render.container;
51
- expect(_react.screen.getByLabelText(defaultProps.label)).toBeInTheDocument(); // Check for accessibility issues
48
+ _render = (0, _react.render)((0, _jsxRuntime.jsx)(_FormAutocomplete.FormAutocomplete, {
49
+ id: "my_desert_list",
50
+ label: "This is a label"
51
+ })), container = _render.container; // Check for accessibility issues
52
52
 
53
53
  _context.t0 = expect;
54
- _context.next = 5;
54
+ _context.next = 4;
55
55
  return (0, _jestAxe.axe)(container);
56
56
 
57
- case 5:
57
+ case 4:
58
58
  _context.t1 = _context.sent;
59
- _context.next = 8;
59
+ _context.next = 7;
60
60
  return (0, _context.t0)(_context.t1).toHaveNoViolations();
61
61
 
62
- case 8:
62
+ case 7:
63
63
  case "end":
64
64
  return _context.stop();
65
65
  }
66
66
  }
67
67
  }, _callee);
68
68
  })));
69
+ it('renders the FormAutocomplete component with options', /*#__PURE__*/(0, _asyncToGenerator2["default"])( /*#__PURE__*/_regenerator["default"].mark(function _callee2() {
70
+ var _render2, container;
71
+
72
+ return _regenerator["default"].wrap(function _callee2$(_context2) {
73
+ while (1) {
74
+ switch (_context2.prev = _context2.next) {
75
+ case 0:
76
+ _render2 = (0, _react.render)((0, _jsxRuntime.jsx)(_FormAutocomplete.FormAutocomplete, (0, _extends2["default"])({
77
+ id: "my_desert_list"
78
+ }, defaultProps))), container = _render2.container;
79
+ expect(_react.screen.getByLabelText(defaultProps.label)).toBeInTheDocument(); // Check for accessibility issues
80
+
81
+ _context2.t0 = expect;
82
+ _context2.next = 5;
83
+ return (0, _jestAxe.axe)(container);
84
+
85
+ case 5:
86
+ _context2.t1 = _context2.sent;
87
+ _context2.next = 8;
88
+ return (0, _context2.t0)(_context2.t1).toHaveNoViolations();
89
+
90
+ case 8:
91
+ case "end":
92
+ return _context2.stop();
93
+ }
94
+ }
95
+ }, _callee2);
96
+ })));
69
97
  });
@@ -21,7 +21,7 @@ var _FormSelectContent = require("./FormSelectContent");
21
21
 
22
22
  var _jsxRuntime = require("theme-ui/jsx-runtime");
23
23
 
24
- var _excluded = ["isInline", "placeholder", "forLabel", "options", "label", "getOptionLabel", "getOptionValue", "onChange"],
24
+ var _excluded = ["isInline", "placeholder", "forLabel", "options", "required", "label", "getOptionLabel", "getOptionValue", "onChange"],
25
25
  _excluded2 = ["options"];
26
26
 
27
27
  function _getRequireWildcardCache(nodeInterop) { if (typeof WeakMap !== "function") return null; var cacheBabelInterop = new WeakMap(); var cacheNodeInterop = new WeakMap(); return (_getRequireWildcardCache = function _getRequireWildcardCache(nodeInterop) { return nodeInterop ? cacheNodeInterop : cacheBabelInterop; })(nodeInterop); }
@@ -79,6 +79,7 @@ var FormSelect = /*#__PURE__*/_react["default"].forwardRef(function (_ref2, forw
79
79
  placeholder = _ref2.placeholder,
80
80
  forLabel = _ref2.forLabel,
81
81
  options = _ref2.options,
82
+ required = _ref2.required,
82
83
  label = _ref2.label,
83
84
  getOptionLabel = _ref2.getOptionLabel,
84
85
  getOptionValue = _ref2.getOptionValue,
@@ -118,6 +119,7 @@ var FormSelect = /*#__PURE__*/_react["default"].forwardRef(function (_ref2, forw
118
119
 
119
120
  var SelectLabel = function SelectLabel() {
120
121
  return (0, _jsxRuntime.jsx)(_Label.Label, {
122
+ required: required,
121
123
  htmlFor: forLabel || props.id,
122
124
  children: label
123
125
  });
@@ -149,6 +151,7 @@ exports.FormSelect = FormSelect;
149
151
  FormSelect.propTypes = {
150
152
  id: _propTypes["default"].string,
151
153
  isInline: _propTypes["default"].bool,
154
+ required: _propTypes["default"].bool,
152
155
  forLabel: _propTypes["default"].string,
153
156
  placeholder: _propTypes["default"].string,
154
157
  label: _propTypes["default"].string,
@@ -101,6 +101,7 @@ var Default = DefaultComponent.bind({});
101
101
  exports.Default = Default;
102
102
  Default.args = {
103
103
  placeholder: '- Select -',
104
+ required: true,
104
105
  options: options
105
106
  };
106
107
  var WithGroup = DefaultComponent.bind({});
@@ -25,6 +25,19 @@ var _default = {
25
25
  component: _.Wizard
26
26
  };
27
27
  exports["default"] = _default;
28
+ var options = [{
29
+ value: 'chocolate',
30
+ label: 'Chocolate'
31
+ }, {
32
+ value: 'strawberry',
33
+ label: 'Strawberry'
34
+ }, {
35
+ value: 'vanilla',
36
+ label: 'Vanilla'
37
+ }, {
38
+ value: 'coffee',
39
+ label: 'Coffee'
40
+ }];
28
41
 
29
42
  var Default = function Default() {
30
43
  var steps = [{
@@ -37,7 +50,13 @@ var Default = function Default() {
37
50
  }), (0, _jsxRuntime.jsx)(_.Input, {
38
51
  autoFocus: true,
39
52
  placeholder: "yourdomain.com"
53
+ }), (0, _jsxRuntime.jsx)(_.Form.Autocomplete, {
54
+ label: "Autocomplete",
55
+ options: options
40
56
  }), (0, _jsxRuntime.jsx)(_.Button, {
57
+ sx: {
58
+ mt: 3
59
+ },
41
60
  children: "Continue"
42
61
  })]
43
62
  })
@@ -65,7 +65,8 @@ var WizardStep = /*#__PURE__*/_react["default"].forwardRef(function (_ref, forwa
65
65
  borderTopColor: 'borders.2'
66
66
  },
67
67
  borderColor: active ? 'primary' : 'borders.2',
68
- borderLeftColor: borderLeftColor
68
+ borderLeftColor: borderLeftColor,
69
+ overflow: 'inherit'
69
70
  },
70
71
  "data-step": order,
71
72
  "data-active": active || undefined,
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@automattic/vip-design-system",
3
- "version": "0.27.5",
3
+ "version": "0.27.6",
4
4
  "main": "build/system/index.js",
5
5
  "scripts": {
6
6
  "build-storybook": "build-storybook",
@@ -12,10 +12,6 @@ import PropTypes from 'prop-types';
12
12
  import { Validation, Label } from '../';
13
13
  import { Input as ThemeInput } from 'theme-ui';
14
14
 
15
- const RequiredLabel = () => (
16
- <span sx={ { color: 'error', display: 'inline-block', ml: 2, fontSize: 1 } }>(Required)</span>
17
- );
18
-
19
15
  const inputStyles = {
20
16
  unset: 'all',
21
17
  border: '1px solid',
@@ -44,9 +40,8 @@ const Input = React.forwardRef(
44
40
  ( { variant, label, forLabel, hasError, required, sx = {}, errorMessage, ...props }, ref ) => (
45
41
  <React.Fragment>
46
42
  { label && (
47
- <Label htmlFor={ forLabel }>
43
+ <Label required={ required } htmlFor={ forLabel }>
48
44
  { label }
49
- { required && <RequiredLabel /> }
50
45
  </Label>
51
46
  ) }
52
47
 
@@ -9,8 +9,9 @@ import PropTypes from 'prop-types';
9
9
  /**
10
10
  * Internal dependencies
11
11
  */
12
+ import { RequiredLabel } from './RequiredLabel';
12
13
 
13
- const Label = React.forwardRef( ( { sx, ...rest }, forwardRef ) => (
14
+ const Label = React.forwardRef( ( { sx, children, required, ...rest }, forwardRef ) => (
14
15
  <label
15
16
  sx={ {
16
17
  fontWeight: 500,
@@ -23,10 +24,15 @@ const Label = React.forwardRef( ( { sx, ...rest }, forwardRef ) => (
23
24
  } }
24
25
  ref={ forwardRef }
25
26
  { ...rest }
26
- />
27
+ >
28
+ { children }
29
+ { required && <RequiredLabel /> }
30
+ </label>
27
31
  ) );
28
32
 
29
33
  Label.propTypes = {
34
+ children: PropTypes.object,
35
+ required: PropTypes.bool,
30
36
  sx: PropTypes.object,
31
37
  };
32
38
 
@@ -0,0 +1,36 @@
1
+ /** @jsxImportSource theme-ui */
2
+
3
+ /**
4
+ * Internal dependencies
5
+ */
6
+ import { Form, Label } from '..';
7
+
8
+ export default {
9
+ title: 'Form/Label',
10
+ };
11
+
12
+ const DefaultComponent = props => (
13
+ <Form.Root>
14
+ <Label { ...props }>Label</Label>
15
+ </Form.Root>
16
+ );
17
+
18
+ export const Default = () => {
19
+ return (
20
+ <>
21
+ <DefaultComponent />
22
+ </>
23
+ );
24
+ };
25
+
26
+ export const Required = () => {
27
+ const args = {
28
+ required: true,
29
+ };
30
+
31
+ return (
32
+ <>
33
+ <DefaultComponent { ...args } />
34
+ </>
35
+ );
36
+ };
@@ -0,0 +1,15 @@
1
+ /** @jsxImportSource theme-ui */
2
+
3
+ /**
4
+ * External dependencies
5
+ */
6
+
7
+ /**
8
+ * Internal dependencies
9
+ */
10
+
11
+ const RequiredLabel = () => (
12
+ <span sx={ { color: 'error', display: 'inline-block', ml: 2, fontSize: 1 } }>(Required)</span>
13
+ );
14
+
15
+ export { RequiredLabel };
@@ -97,7 +97,7 @@ const FormAutocomplete = React.forwardRef(
97
97
  {
98
98
  isInline,
99
99
  forLabel,
100
- options,
100
+ options = [],
101
101
  label,
102
102
  getOptionLabel,
103
103
  getOptionValue,
@@ -105,8 +105,11 @@ const FormAutocomplete = React.forwardRef(
105
105
  onInputChange,
106
106
  value,
107
107
  showAllValues = true,
108
- searchIcon = false,
109
- loading = false,
108
+ searchIcon,
109
+ minLength = 0,
110
+ debounce = 0,
111
+ loading,
112
+ required,
110
113
  displayMenu = 'overlay',
111
114
  noOptionsMessage = () => 'No results found.',
112
115
  id = 'vip-autocomplete',
@@ -116,8 +119,13 @@ const FormAutocomplete = React.forwardRef(
116
119
  forwardRef
117
120
  ) => {
118
121
  const [ isDirty, setIsDirty ] = useState( false );
122
+ let debounceTimeout;
119
123
 
120
- const SelectLabel = () => <Label htmlFor={ forLabel || id }>{ label }</Label>;
124
+ const SelectLabel = () => (
125
+ <Label required={ required } htmlFor={ forLabel || id }>
126
+ { label }
127
+ </Label>
128
+ );
121
129
 
122
130
  const inlineLabel = !! ( isInline && label );
123
131
 
@@ -158,12 +166,24 @@ const FormAutocomplete = React.forwardRef(
158
166
  [ options ]
159
167
  );
160
168
 
169
+ const handleInputChange = useCallback(
170
+ query => {
171
+ clearTimeout( debounceTimeout );
172
+ if ( ! query.length || query.length >= minLength ) {
173
+ debounceTimeout = setTimeout( () => {
174
+ onInputChange( query );
175
+ }, debounce );
176
+ }
177
+ },
178
+ [ onInputChange, debounce, minLength ]
179
+ );
180
+
161
181
  const suggest = useCallback(
162
182
  ( query, populateResults ) => {
163
- let data = options;
164
- if ( isDirty ) {
165
- data = onInputChange ? onInputChange( query ) : handleTypeChange( query );
183
+ if ( isDirty && onInputChange ) {
184
+ handleInputChange( query );
166
185
  }
186
+ const data = handleTypeChange( query );
167
187
  populateResults( data.map( option => optionLabel( option ) ) );
168
188
  },
169
189
  [ options, isDirty ]
@@ -229,6 +249,7 @@ FormAutocomplete.propTypes = {
229
249
  showAllValues: PropTypes.bool,
230
250
  searchIcon: PropTypes.bool,
231
251
  loading: PropTypes.bool,
252
+ required: PropTypes.bool,
232
253
  isInline: PropTypes.bool,
233
254
  forLabel: PropTypes.string,
234
255
  value: PropTypes.string,
@@ -241,6 +262,8 @@ FormAutocomplete.propTypes = {
241
262
  noOptionsMessage: PropTypes.func,
242
263
  onChange: PropTypes.func,
243
264
  className: PropTypes.any,
265
+ minLength: PropTypes.number,
266
+ debounce: PropTypes.number,
244
267
  };
245
268
 
246
269
  FormAutocomplete.displayName = 'FormAutocomplete';
@@ -3,6 +3,7 @@
3
3
  /**
4
4
  * Internal dependencies
5
5
  */
6
+ import { useState } from 'react';
6
7
  import * as Form from '.';
7
8
 
8
9
  export default {
@@ -44,7 +45,7 @@ const DefaultComponent = ( { label = 'Label', width = 250, ...rest } ) => (
44
45
  export const Default = () => {
45
46
  return (
46
47
  <>
47
- <DefaultComponent { ...args } />
48
+ <DefaultComponent required { ...args } />
48
49
  </>
49
50
  );
50
51
  };
@@ -101,6 +102,25 @@ export const WithLoading = () => {
101
102
  );
102
103
  };
103
104
 
105
+ export const WithDebounce = () => {
106
+ const [ value, setValue ] = useState( null );
107
+ const customArgs = {
108
+ ...args,
109
+ minLength: 3,
110
+ debounce: 300,
111
+ onInputChange: query => {
112
+ setValue( query );
113
+ },
114
+ };
115
+
116
+ return (
117
+ <>
118
+ Filter: { value }
119
+ <DefaultComponent { ...customArgs } />
120
+ </>
121
+ );
122
+ };
123
+
104
124
  export const WithCustomMessages = () => {
105
125
  const customArgs = {
106
126
  ...args,
@@ -22,6 +22,15 @@ const defaultProps = {
22
22
 
23
23
  describe( '<FormAutocomplete />', () => {
24
24
  it( 'renders the FormAutocomplete component', async () => {
25
+ const { container } = render(
26
+ <FormAutocomplete id="my_desert_list" label="This is a label" />
27
+ );
28
+
29
+ // Check for accessibility issues
30
+ await expect( await axe( container ) ).toHaveNoViolations();
31
+ } );
32
+
33
+ it( 'renders the FormAutocomplete component with options', async () => {
25
34
  const { container } = render( <FormAutocomplete id="my_desert_list" { ...defaultProps } /> );
26
35
 
27
36
  expect( screen.getByLabelText( defaultProps.label ) ).toBeInTheDocument();
@@ -58,6 +58,7 @@ const FormSelect = React.forwardRef(
58
58
  placeholder,
59
59
  forLabel,
60
60
  options,
61
+ required,
61
62
  label,
62
63
  getOptionLabel,
63
64
  getOptionValue,
@@ -105,7 +106,11 @@ const FormSelect = React.forwardRef(
105
106
  [ onChange, getOptionByValue ]
106
107
  );
107
108
 
108
- const SelectLabel = () => <Label htmlFor={ forLabel || props.id }>{ label }</Label>;
109
+ const SelectLabel = () => (
110
+ <Label required={ required } htmlFor={ forLabel || props.id }>
111
+ { label }
112
+ </Label>
113
+ );
109
114
 
110
115
  const inlineLabel = !! ( isInline && label );
111
116
 
@@ -133,6 +138,7 @@ const FormSelect = React.forwardRef(
133
138
  FormSelect.propTypes = {
134
139
  id: PropTypes.string,
135
140
  isInline: PropTypes.bool,
141
+ required: PropTypes.bool,
136
142
  forLabel: PropTypes.string,
137
143
  placeholder: PropTypes.string,
138
144
  label: PropTypes.string,
@@ -70,6 +70,7 @@ const DefaultComponent = ( { label = 'Label', width = 250, onChange, ...rest } )
70
70
  export const Default = DefaultComponent.bind( {} );
71
71
  Default.args = {
72
72
  placeholder: '- Select -',
73
+ required: true,
73
74
  options,
74
75
  };
75
76
 
@@ -8,13 +8,20 @@ import React from 'react';
8
8
  /**
9
9
  * Internal dependencies
10
10
  */
11
- import { Wizard, Box, Label, Input, Button } from '..';
11
+ import { Wizard, Box, Label, Input, Button, Form } from '..';
12
12
 
13
13
  export default {
14
14
  title: 'Wizard',
15
15
  component: Wizard,
16
16
  };
17
17
 
18
+ const options = [
19
+ { value: 'chocolate', label: 'Chocolate' },
20
+ { value: 'strawberry', label: 'Strawberry' },
21
+ { value: 'vanilla', label: 'Vanilla' },
22
+ { value: 'coffee', label: 'Coffee' },
23
+ ];
24
+
18
25
  export const Default = () => {
19
26
  const steps = [
20
27
  {
@@ -25,7 +32,8 @@ export const Default = () => {
25
32
  <Box>
26
33
  <Label>Domain</Label>
27
34
  <Input autoFocus placeholder="yourdomain.com" />
28
- <Button>Continue</Button>
35
+ <Form.Autocomplete label="Autocomplete" options={ options } />
36
+ <Button sx={ { mt: 3 } }>Continue</Button>
29
37
  </Box>
30
38
  ),
31
39
  },
@@ -50,6 +50,7 @@ const WizardStep = React.forwardRef(
50
50
  },
51
51
  borderColor: active ? 'primary' : 'borders.2',
52
52
  borderLeftColor: borderLeftColor,
53
+ overflow: 'inherit',
53
54
  } }
54
55
  data-step={ order }
55
56
  data-active={ active || undefined }