@automattic/vip-design-system 0.27.9 → 0.27.11

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.
@@ -9,7 +9,7 @@ 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 = _interopRequireDefault(require("react"));
12
+ var _react = _interopRequireWildcard(require("react"));
13
13
 
14
14
  var _propTypes = _interopRequireDefault(require("prop-types"));
15
15
 
@@ -19,11 +19,26 @@ var _themeUi = require("theme-ui");
19
19
 
20
20
  var _jsxRuntime = require("theme-ui/jsx-runtime");
21
21
 
22
- var _excluded = ["sx"];
22
+ var _excluded = ["disabled", "onClick", "sx"];
23
+
24
+ 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); }
25
+
26
+ function _interopRequireWildcard(obj, nodeInterop) { if (!nodeInterop && obj && obj.__esModule) { return obj; } if (obj === null || typeof obj !== "object" && typeof obj !== "function") { return { "default": obj }; } var cache = _getRequireWildcardCache(nodeInterop); if (cache && cache.has(obj)) { return cache.get(obj); } var newObj = {}; var hasPropertyDescriptor = Object.defineProperty && Object.getOwnPropertyDescriptor; for (var key in obj) { if (key !== "default" && Object.prototype.hasOwnProperty.call(obj, key)) { var desc = hasPropertyDescriptor ? Object.getOwnPropertyDescriptor(obj, key) : null; if (desc && (desc.get || desc.set)) { Object.defineProperty(newObj, key, desc); } else { newObj[key] = obj[key]; } } } newObj["default"] = obj; if (cache) { cache.set(obj, newObj); } return newObj; }
23
27
 
24
28
  var Button = /*#__PURE__*/_react["default"].forwardRef(function (_ref, forwardRef) {
25
- var sx = _ref.sx,
29
+ var disabled = _ref.disabled,
30
+ onClick = _ref.onClick,
31
+ sx = _ref.sx,
26
32
  props = (0, _objectWithoutPropertiesLoose2["default"])(_ref, _excluded);
33
+ var handleOnClick = (0, _react.useCallback)(function (event) {
34
+ if (disabled) {
35
+ return event.preventDefault();
36
+ }
37
+
38
+ if (onClick) {
39
+ return onClick(event);
40
+ }
41
+ }, [disabled, onClick]);
27
42
  return (0, _jsxRuntime.jsx)(_themeUi.Button, (0, _extends2["default"])({
28
43
  sx: (0, _extends2["default"])({
29
44
  verticalAlign: 'middle',
@@ -42,13 +57,15 @@ var Button = /*#__PURE__*/_react["default"].forwardRef(function (_ref, forwardRe
42
57
  '&:focus-visible': function focusVisible(theme) {
43
58
  return theme.outline;
44
59
  },
45
- '&:disabled': {
60
+ '&[aria-disabled="true"]': {
46
61
  opacity: 0.7,
47
62
  cursor: 'not-allowed',
48
63
  pointerEvents: 'all'
49
64
  }
50
65
  }, sx),
51
- className: (0, _classnames["default"])('vip-button-component', props.className)
66
+ "aria-disabled": disabled,
67
+ className: (0, _classnames["default"])('vip-button-component', props.className),
68
+ onClick: handleOnClick
52
69
  }, props, {
53
70
  ref: forwardRef
54
71
  }));
@@ -57,6 +74,8 @@ var Button = /*#__PURE__*/_react["default"].forwardRef(function (_ref, forwardRe
57
74
  exports.Button = Button;
58
75
  Button.displayName = 'Button';
59
76
  Button.propTypes = {
60
- sx: _propTypes["default"].object,
61
- className: _propTypes["default"].any
77
+ className: _propTypes["default"].any,
78
+ disabled: _propTypes["default"].bool,
79
+ onClick: _propTypes["default"].func,
80
+ sx: _propTypes["default"].object
62
81
  };
@@ -3,9 +3,9 @@
3
3
  var _interopRequireDefault = require("@babel/runtime/helpers/interopRequireDefault");
4
4
 
5
5
  exports.__esModule = true;
6
- exports["default"] = exports.Default = void 0;
6
+ exports["default"] = exports.WithOnClick = exports.Link = exports.Default = void 0;
7
7
 
8
- var _react = _interopRequireDefault(require("react"));
8
+ var _extends2 = _interopRequireDefault(require("@babel/runtime/helpers/extends"));
9
9
 
10
10
  var _ = require("..");
11
11
 
@@ -20,33 +20,59 @@ var _jsxRuntime = require("theme-ui/jsx-runtime");
20
20
  */
21
21
  var _default = {
22
22
  title: 'Button',
23
- component: _.Button
24
- };
25
- exports["default"] = _default;
26
-
27
- var Default = function Default() {
28
- return (0, _jsxRuntime.jsxs)(_react["default"].Fragment, {
29
- children: [(0, _jsxRuntime.jsx)(_.Button, {
30
- sx: {
31
- mr: 2
23
+ component: _.Button,
24
+ argTypes: {
25
+ children: {
26
+ table: {
27
+ type: {
28
+ summary: 'node'
29
+ }
32
30
  },
33
- children: "Primary"
34
- }), (0, _jsxRuntime.jsx)(_.Button, {
35
- variant: "secondary",
36
- sx: {
37
- ml: 2
31
+ control: {
32
+ type: 'text'
38
33
  },
39
- children: "Secondary"
40
- }), (0, _jsxRuntime.jsx)(_.Button, {
41
- variant: "text",
42
- sx: {
43
- ml: 2
34
+ type: {
35
+ required: true
36
+ }
37
+ },
38
+ variant: {
39
+ table: {
40
+ type: {
41
+ summary: 'string'
42
+ },
43
+ defaultValue: {
44
+ summary: 'primary'
45
+ }
44
46
  },
45
- as: "a",
46
- href: "https://google/com",
47
- children: "Button link"
48
- })]
49
- });
47
+ control: {
48
+ type: 'select',
49
+ options: ['primary', 'secondary', 'text']
50
+ }
51
+ }
52
+ }
50
53
  };
54
+ exports["default"] = _default;
51
55
 
52
- exports.Default = Default;
56
+ var Template = function Template(args) {
57
+ return (0, _jsxRuntime.jsx)(_.Button, (0, _extends2["default"])({}, args, {
58
+ children: "Submit"
59
+ }));
60
+ };
61
+
62
+ var Default = Template.bind({});
63
+ exports.Default = Default;
64
+ var Link = Template.bind({});
65
+ exports.Link = Link;
66
+ Link.args = {
67
+ variant: 'text',
68
+ as: 'a',
69
+ href: 'https://www.google.com'
70
+ };
71
+ var WithOnClick = Template.bind({});
72
+ exports.WithOnClick = WithOnClick;
73
+ Link.args = {
74
+ onClick: function onClick() {
75
+ // eslint-disable-next-line no-undef
76
+ alert('Clicked');
77
+ }
78
+ };
@@ -21,33 +21,79 @@ var _jsxRuntime = require("theme-ui/jsx-runtime");
21
21
  /**
22
22
  * Internal dependencies
23
23
  */
24
+ var BUTTON_TEXT = 'Button Text';
24
25
  describe('<Button />', function () {
25
26
  it('renders the Button component', /*#__PURE__*/(0, _asyncToGenerator2["default"])( /*#__PURE__*/_regenerator["default"].mark(function _callee() {
26
- var _render, container;
27
+ var onClick, _render, container, component;
27
28
 
28
29
  return _regenerator["default"].wrap(function _callee$(_context) {
29
30
  while (1) {
30
31
  switch (_context.prev = _context.next) {
31
32
  case 0:
33
+ onClick = jest.fn(function () {});
32
34
  _render = (0, _react.render)((0, _jsxRuntime.jsx)(_Button.Button, {
33
- children: "Button text"
35
+ onClick: onClick,
36
+ children: BUTTON_TEXT
34
37
  })), container = _render.container;
35
- expect(_react.screen.getByText('Button text')).toBeInTheDocument(); // Check for accessibility issues
38
+ component = _react.screen.getByText(BUTTON_TEXT);
39
+ expect(component).toBeInTheDocument();
40
+
41
+ _react.fireEvent.click(component);
42
+
43
+ expect(onClick).toHaveBeenCalledTimes(1); // Check for accessibility issues
36
44
 
37
45
  _context.t0 = expect;
38
- _context.next = 5;
46
+ _context.next = 9;
39
47
  return (0, _jestAxe.axe)(container);
40
48
 
41
- case 5:
49
+ case 9:
42
50
  _context.t1 = _context.sent;
43
- _context.next = 8;
51
+ _context.next = 12;
44
52
  return (0, _context.t0)(_context.t1).toHaveNoViolations();
45
53
 
46
- case 8:
54
+ case 12:
47
55
  case "end":
48
56
  return _context.stop();
49
57
  }
50
58
  }
51
59
  }, _callee);
52
60
  })));
61
+ it('renders the Button with disabled prop', /*#__PURE__*/(0, _asyncToGenerator2["default"])( /*#__PURE__*/_regenerator["default"].mark(function _callee2() {
62
+ var onClick, _render2, container, component;
63
+
64
+ return _regenerator["default"].wrap(function _callee2$(_context2) {
65
+ while (1) {
66
+ switch (_context2.prev = _context2.next) {
67
+ case 0:
68
+ onClick = jest.fn(function () {});
69
+ _render2 = (0, _react.render)((0, _jsxRuntime.jsx)(_Button.Button, {
70
+ disabled: true,
71
+ onClick: onClick,
72
+ children: BUTTON_TEXT
73
+ })), container = _render2.container;
74
+ component = _react.screen.getByText(BUTTON_TEXT);
75
+ expect(component).toBeInTheDocument();
76
+ expect(component).toHaveAttribute('aria-disabled', 'true');
77
+ expect(component).not.toHaveAttribute('disabled');
78
+
79
+ _react.fireEvent.click(component);
80
+
81
+ expect(onClick).toHaveBeenCalledTimes(0); // Check for accessibility issues
82
+
83
+ _context2.t0 = expect;
84
+ _context2.next = 11;
85
+ return (0, _jestAxe.axe)(container);
86
+
87
+ case 11:
88
+ _context2.t1 = _context2.sent;
89
+ _context2.next = 14;
90
+ return (0, _context2.t0)(_context2.t1).toHaveNoViolations();
91
+
92
+ case 14:
93
+ case "end":
94
+ return _context2.stop();
95
+ }
96
+ }
97
+ }, _callee2);
98
+ })));
53
99
  });
@@ -226,15 +226,22 @@ var FormAutocomplete = /*#__PURE__*/_react["default"].forwardRef(function (_ref,
226
226
  }
227
227
  }, [onInputChange, debounce, minLength]);
228
228
  var suggest = (0, _react.useCallback)(function (query, populateResults) {
229
+ var _data;
230
+
231
+ var data = options;
232
+
229
233
  if (isDirty && onInputChange) {
230
234
  handleInputChange(query);
231
235
  }
232
236
 
233
- var data = autoFilter ? handleTypeChange(query) : options;
234
- populateResults(data == null ? void 0 : data.map(function (option) {
237
+ if (isDirty && autoFilter) {
238
+ data = handleTypeChange(query);
239
+ }
240
+
241
+ populateResults((_data = data) == null ? void 0 : _data.map(function (option) {
235
242
  return optionLabel(option);
236
243
  }));
237
- }, [options, isDirty]);
244
+ }, [autoFilter, isDirty, onInputChange, options]);
238
245
  (0, _react.useEffect)(function () {
239
246
  global.document.querySelector('.autocomplete__input').setAttribute('aria-activedescendant', '');
240
247
  }, []);
@@ -7,6 +7,8 @@ exports.TabsTrigger = void 0;
7
7
 
8
8
  var _extends2 = _interopRequireDefault(require("@babel/runtime/helpers/extends"));
9
9
 
10
+ var _react = _interopRequireDefault(require("react"));
11
+
10
12
  var _propTypes = _interopRequireDefault(require("prop-types"));
11
13
 
12
14
  var TabsPrimitive = _interopRequireWildcard(require("@radix-ui/react-tabs"));
@@ -59,7 +61,7 @@ var styles = {
59
61
  }
60
62
  };
61
63
 
62
- var TabsTrigger = function TabsTrigger(_ref) {
64
+ var TabsTrigger = /*#__PURE__*/_react["default"].forwardRef(function (_ref, forwardRef) {
63
65
  var value = _ref.value,
64
66
  _ref$disabled = _ref.disabled,
65
67
  disabled = _ref$disabled === void 0 ? false : _ref$disabled,
@@ -70,9 +72,10 @@ var TabsTrigger = function TabsTrigger(_ref) {
70
72
  value: value,
71
73
  disabled: disabled,
72
74
  sx: (0, _extends2["default"])({}, styles, sx),
75
+ ref: forwardRef,
73
76
  children: children
74
77
  });
75
- };
78
+ });
76
79
 
77
80
  exports.TabsTrigger = TabsTrigger;
78
81
  TabsTrigger.propTypes = {
@@ -80,4 +83,5 @@ TabsTrigger.propTypes = {
80
83
  value: _propTypes["default"].string,
81
84
  disabled: _propTypes["default"].bool,
82
85
  children: _propTypes["default"].node.isRequired
83
- };
86
+ };
87
+ TabsTrigger.displayName = 'TabsTrigger';
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@automattic/vip-design-system",
3
- "version": "0.27.9",
3
+ "version": "0.27.11",
4
4
  "main": "build/system/index.js",
5
5
  "scripts": {
6
6
  "build-storybook": "build-storybook",
@@ -3,44 +3,62 @@
3
3
  /**
4
4
  * External dependencies
5
5
  */
6
- import React from 'react';
6
+ import React, { useCallback } from 'react';
7
7
  import PropTypes from 'prop-types';
8
8
  import classNames from 'classnames';
9
9
  import { Button as ThemeButton } from 'theme-ui';
10
10
 
11
- const Button = React.forwardRef( ( { sx, ...props }, forwardRef ) => (
12
- <ThemeButton
13
- sx={ {
14
- verticalAlign: 'middle',
15
- display: 'inline-flex',
16
- alignItems: 'center',
17
- justifyContent: 'center',
18
- height: '36px',
19
- py: 0,
20
- textDecoration: 'none',
21
- '&:hover': {
11
+ const Button = React.forwardRef( ( { disabled, onClick, sx, ...props }, forwardRef ) => {
12
+ const handleOnClick = useCallback(
13
+ event => {
14
+ if ( disabled ) {
15
+ return event.preventDefault();
16
+ }
17
+
18
+ if ( onClick ) {
19
+ return onClick( event );
20
+ }
21
+ },
22
+ [ disabled, onClick ]
23
+ );
24
+ return (
25
+ <ThemeButton
26
+ sx={ {
27
+ verticalAlign: 'middle',
28
+ display: 'inline-flex',
29
+ alignItems: 'center',
30
+ justifyContent: 'center',
31
+ height: '36px',
32
+ py: 0,
22
33
  textDecoration: 'none',
23
- },
24
- '&:focus': theme => theme.outline,
25
- '&:focus-visible': theme => theme.outline,
26
- '&:disabled': {
27
- opacity: 0.7,
28
- cursor: 'not-allowed',
29
- pointerEvents: 'all',
30
- },
31
- ...sx,
32
- } }
33
- className={ classNames( 'vip-button-component', props.className ) }
34
- { ...props }
35
- ref={ forwardRef }
36
- />
37
- ) );
34
+ '&:hover': {
35
+ textDecoration: 'none',
36
+ },
37
+ '&:focus': theme => theme.outline,
38
+ '&:focus-visible': theme => theme.outline,
39
+ '&[aria-disabled="true"]': {
40
+ opacity: 0.7,
41
+ cursor: 'not-allowed',
42
+ pointerEvents: 'all',
43
+ },
44
+ ...sx,
45
+ } }
46
+ aria-disabled={ disabled }
47
+ className={ classNames( 'vip-button-component', props.className ) }
48
+ onClick={ handleOnClick }
49
+ { ...props }
50
+ ref={ forwardRef }
51
+ />
52
+ );
53
+ } );
38
54
 
39
55
  Button.displayName = 'Button';
40
56
 
41
57
  Button.propTypes = {
42
- sx: PropTypes.object,
43
58
  className: PropTypes.any,
59
+ disabled: PropTypes.bool,
60
+ onClick: PropTypes.func,
61
+ sx: PropTypes.object,
44
62
  };
45
63
 
46
64
  export { Button };
@@ -1,7 +1,6 @@
1
1
  /**
2
2
  * External dependencies
3
3
  */
4
- import React from 'react';
5
4
 
6
5
  /**
7
6
  * Internal dependencies
@@ -11,16 +10,42 @@ import { Button } from '..';
11
10
  export default {
12
11
  title: 'Button',
13
12
  component: Button,
13
+ argTypes: {
14
+ children: {
15
+ table: {
16
+ type: { summary: 'node' },
17
+ },
18
+ control: { type: 'text' },
19
+ type: { required: true },
20
+ },
21
+ variant: {
22
+ table: {
23
+ type: { summary: 'string' },
24
+ defaultValue: { summary: 'primary' },
25
+ },
26
+ control: {
27
+ type: 'select',
28
+ options: [ 'primary', 'secondary', 'text' ],
29
+ },
30
+ },
31
+ },
14
32
  };
15
33
 
16
- export const Default = () => (
17
- <React.Fragment>
18
- <Button sx={ { mr: 2 } }>Primary</Button>
19
- <Button variant="secondary" sx={ { ml: 2 } }>
20
- Secondary
21
- </Button>
22
- <Button variant="text" sx={ { ml: 2 } } as="a" href="https://google/com">
23
- Button link
24
- </Button>
25
- </React.Fragment>
26
- );
34
+ const Template = args => <Button { ...args }>Submit</Button>;
35
+
36
+ export const Default = Template.bind( {} );
37
+
38
+ export const Link = Template.bind( {} );
39
+ Link.args = {
40
+ variant: 'text',
41
+ as: 'a',
42
+ href: 'https://www.google.com',
43
+ };
44
+
45
+ export const WithOnClick = Template.bind( {} );
46
+ Link.args = {
47
+ onClick: () => {
48
+ // eslint-disable-next-line no-undef
49
+ alert( 'Clicked' );
50
+ },
51
+ };
@@ -1,7 +1,7 @@
1
1
  /**
2
2
  * External dependencies
3
3
  */
4
- import { render, screen } from '@testing-library/react';
4
+ import { fireEvent, render, screen } from '@testing-library/react';
5
5
  import { axe } from 'jest-axe';
6
6
 
7
7
  /**
@@ -9,11 +9,38 @@ import { axe } from 'jest-axe';
9
9
  */
10
10
  import { Button } from './Button';
11
11
 
12
+ const BUTTON_TEXT = 'Button Text';
13
+
12
14
  describe( '<Button />', () => {
13
15
  it( 'renders the Button component', async () => {
14
- const { container } = render( <Button>Button text</Button> );
16
+ const onClick = jest.fn( () => {} );
17
+ const { container } = render( <Button onClick={ onClick }>{ BUTTON_TEXT }</Button> );
18
+ const component = screen.getByText( BUTTON_TEXT );
19
+
20
+ expect( component ).toBeInTheDocument();
21
+
22
+ fireEvent.click( component );
23
+ expect( onClick ).toHaveBeenCalledTimes( 1 );
24
+
25
+ // Check for accessibility issues
26
+ await expect( await axe( container ) ).toHaveNoViolations();
27
+ } );
28
+
29
+ it( 'renders the Button with disabled prop', async () => {
30
+ const onClick = jest.fn( () => {} );
31
+ const { container } = render(
32
+ <Button disabled onClick={ onClick }>
33
+ { BUTTON_TEXT }
34
+ </Button>
35
+ );
36
+ const component = screen.getByText( BUTTON_TEXT );
37
+
38
+ expect( component ).toBeInTheDocument();
39
+ expect( component ).toHaveAttribute( 'aria-disabled', 'true' );
40
+ expect( component ).not.toHaveAttribute( 'disabled' );
15
41
 
16
- expect( screen.getByText( 'Button text' ) ).toBeInTheDocument();
42
+ fireEvent.click( component );
43
+ expect( onClick ).toHaveBeenCalledTimes( 0 );
17
44
 
18
45
  // Check for accessibility issues
19
46
  await expect( await axe( container ) ).toHaveNoViolations();
@@ -185,13 +185,16 @@ const FormAutocomplete = React.forwardRef(
185
185
 
186
186
  const suggest = useCallback(
187
187
  ( query, populateResults ) => {
188
+ let data = options;
188
189
  if ( isDirty && onInputChange ) {
189
190
  handleInputChange( query );
190
191
  }
191
- const data = autoFilter ? handleTypeChange( query ) : options;
192
+ if ( isDirty && autoFilter ) {
193
+ data = handleTypeChange( query );
194
+ }
192
195
  populateResults( data?.map( option => optionLabel( option ) ) );
193
196
  },
194
- [ options, isDirty ]
197
+ [ autoFilter, isDirty, onInputChange, options ]
195
198
  );
196
199
 
197
200
  useEffect( () => {
@@ -3,6 +3,7 @@
3
3
  /**
4
4
  * External dependencies
5
5
  */
6
+ import React from 'react';
6
7
  import PropTypes from 'prop-types';
7
8
  import * as TabsPrimitive from '@radix-ui/react-tabs';
8
9
  import classNames from 'classnames';
@@ -33,7 +34,7 @@ const styles = {
33
34
  '&:focus-visible': theme => theme.outline,
34
35
  };
35
36
 
36
- const TabsTrigger = ( { value, disabled = false, sx, children } ) => (
37
+ const TabsTrigger = React.forwardRef( ( { value, disabled = false, sx, children }, forwardRef ) => (
37
38
  <TabsPrimitive.TabsTrigger
38
39
  className={ classNames( 'vip-tabs-trigger', `vip-tabs-trigger-${ value }` ) }
39
40
  value={ value }
@@ -42,10 +43,11 @@ const TabsTrigger = ( { value, disabled = false, sx, children } ) => (
42
43
  ...styles,
43
44
  ...sx,
44
45
  } }
46
+ ref={ forwardRef }
45
47
  >
46
48
  { children }
47
49
  </TabsPrimitive.TabsTrigger>
48
- );
50
+ ) );
49
51
 
50
52
  TabsTrigger.propTypes = {
51
53
  sx: PropTypes.object,
@@ -54,4 +56,5 @@ TabsTrigger.propTypes = {
54
56
  children: PropTypes.node.isRequired,
55
57
  };
56
58
 
59
+ TabsTrigger.displayName = 'TabsTrigger';
57
60
  export { TabsTrigger };