@shopgate/pwa-ui-material 7.30.3 → 7.31.0-alpha.1

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 (36) hide show
  1. package/Accordion/components/AccordionContent/index.js +23 -10
  2. package/Accordion/index.js +62 -12
  3. package/AppBar/components/Field/index.js +37 -39
  4. package/AppBar/components/Icon/index.js +47 -39
  5. package/AppBar/components/Title/index.js +44 -38
  6. package/AppBar/index.js +26 -5
  7. package/BaseDialog/components/Buttons/index.js +29 -18
  8. package/BaseDialog/components/Content/index.js +14 -3
  9. package/BaseDialog/components/Title/index.js +17 -5
  10. package/BaseDialog/index.js +71 -26
  11. package/FloatingActionButton/index.js +40 -12
  12. package/NavDrawer/components/Divider/index.js +24 -6
  13. package/NavDrawer/components/Item/index.js +91 -65
  14. package/NavDrawer/components/Title/index.js +16 -4
  15. package/NavDrawer/index.js +129 -120
  16. package/NavDrawer/spec.js +112 -14
  17. package/SnackBar/index.js +176 -166
  18. package/icons/ShareIcon.d.ts +7 -0
  19. package/icons/ShareIcon.d.ts.map +1 -0
  20. package/icons/ShareIcon.js +0 -2
  21. package/package.json +6 -4
  22. package/tsconfig.build.json +16 -0
  23. package/tsconfig.json +3 -0
  24. package/Accordion/components/AccordionContent/style.js +0 -9
  25. package/Accordion/style.js +0 -47
  26. package/AppBar/components/Field/style.js +0 -14
  27. package/AppBar/components/Icon/style.js +0 -14
  28. package/AppBar/components/Title/style.js +0 -11
  29. package/AppBar/style.js +0 -21
  30. package/BaseDialog/style.js +0 -64
  31. package/FloatingActionButton/style.js +0 -33
  32. package/NavDrawer/components/Divider/style.js +0 -12
  33. package/NavDrawer/components/Item/style.js +0 -49
  34. package/NavDrawer/components/Title/style.js +0 -8
  35. package/NavDrawer/style.js +0 -26
  36. package/SnackBar/style.js +0 -64
@@ -1,151 +1,160 @@
1
- import _inheritsLoose from "@babel/runtime/helpers/inheritsLoose";
2
- import React, { Component, Fragment } from 'react';
1
+ import React, { useState, useRef, useEffect, useCallback } from 'react';
3
2
  import PropTypes from 'prop-types';
4
3
  import noop from 'lodash/noop';
5
4
  import Transition from 'react-transition-group/Transition';
6
5
  import { Backdrop } from '@shopgate/engage/components';
7
6
  import { ModalStateTracker } from '@shopgate/engage/a11y/components';
8
7
  import { UIEvents } from '@shopgate/pwa-core';
8
+ import { themeShadows, themeColors } from '@shopgate/pwa-common/helpers/config';
9
+ import { makeStyles } from '@shopgate/engage/styles';
9
10
  import Divider from "./components/Divider";
10
11
  import Item from "./components/Item";
11
12
  import Section from "./components/Section";
12
13
  import Title from "./components/Title";
13
- import { contentStyle, drawerStyle } from "./style";
14
14
  import transition from "./transition";
15
15
  import { jsx as _jsx, jsxs as _jsxs, Fragment as _Fragment } from "react/jsx-runtime";
16
16
  const OPEN = 'navdrawer_open';
17
17
  const CLOSE = 'navdrawer_close';
18
+ const useStyles = makeStyles()({
19
+ content: {
20
+ fontSize: 14,
21
+ height: '100%',
22
+ overflowY: 'scroll',
23
+ paddingBottom: 'var(--safe-area-inset-bottom)',
24
+ WebkitOverflowScrolling: 'touch'
25
+ },
26
+ drawer: {
27
+ background: themeColors.light,
28
+ boxShadow: themeShadows.navDrawer,
29
+ color: themeColors.dark,
30
+ height: '100vh',
31
+ left: 0,
32
+ maxWidth: '300px',
33
+ position: 'fixed',
34
+ top: 0,
35
+ transition: 'transform 300ms cubic-bezier(0.25, 0.1, 0.25, 1)',
36
+ width: '100%',
37
+ willChange: 'transform',
38
+ zIndex: 50,
39
+ '@media(max-width: 480px)': {
40
+ maxWidth: '67vw'
41
+ }
42
+ }
43
+ });
18
44
 
19
45
  /**
20
- * The NavDrawer component
46
+ * Material navigation drawer; opens/closes via `NavDrawer.open()` / `NavDrawer.close()` (UIEvents).
47
+ * @param {Object} props Props.
48
+ * @returns {JSX.Element}
21
49
  */
22
- let NavDrawer = /*#__PURE__*/function (_Component) {
23
- /**
24
- * @param {Object} props The component props.
25
- */
26
- function NavDrawer(props) {
27
- var _this;
28
- _this = _Component.call(this, props) || this;
29
- _this.onEntering = () => {
30
- _this.props.onOpen();
31
- };
32
- _this.onEntered = () => {
33
- if (_this.a11yCloseRef.current) {
34
- _this.a11yCloseRef.current.focus();
35
- }
36
- };
37
- _this.onExited = () => {
38
- _this.contentRef.current.scrollTop = 0;
39
- if (_this.triggerElement && typeof _this.triggerElement.focus === 'function') {
40
- // Focus the element that triggered the NavDrawer after it closes
41
- _this.triggerElement.focus();
42
- }
43
- };
44
- _this.onExiting = () => {
45
- _this.props.onClose();
50
+ const NavDrawer = ({
51
+ children,
52
+ 'aria-hidden': ariaHiddenProp,
53
+ onClose,
54
+ onOpen
55
+ }) => {
56
+ const {
57
+ classes,
58
+ cx
59
+ } = useStyles();
60
+ const [open, setOpen] = useState(false);
61
+ const contentRef = useRef(null);
62
+ const a11yCloseRef = useRef(null);
63
+ const triggerElementRef = useRef(null);
64
+ useEffect(() => {
65
+ /**
66
+ * Opens the drawer and stores the active element for focus restore.
67
+ * @returns {void}
68
+ */
69
+ const handleOpenEvent = () => {
70
+ triggerElementRef.current = document.activeElement;
71
+ setOpen(true);
46
72
  };
47
- _this.open = () => {
48
- // Save a reference to the element that triggered the NavDrawer
49
- _this.triggerElement = document.activeElement;
50
- _this.setState({
51
- open: true
52
- });
73
+ /**
74
+ * Closes the drawer (event listener).
75
+ * @returns {void}
76
+ */
77
+ const handleCloseEvent = () => {
78
+ setOpen(false);
53
79
  };
54
- _this.close = () => {
55
- _this.setState({
56
- open: false
57
- });
80
+ UIEvents.addListener(OPEN, handleOpenEvent);
81
+ UIEvents.addListener(CLOSE, handleCloseEvent);
82
+ return () => {
83
+ UIEvents.removeListener(OPEN, handleOpenEvent);
84
+ UIEvents.removeListener(CLOSE, handleCloseEvent);
58
85
  };
59
- _this.contentRef = /*#__PURE__*/React.createRef();
60
- _this.a11yCloseRef = /*#__PURE__*/React.createRef();
61
- _this.state = {
62
- open: false
63
- };
64
-
65
- // Save a reference to the element that triggered the NavDrawer
66
- _this.triggerElement = null;
67
- UIEvents.addListener(OPEN, _this.open);
68
- UIEvents.addListener(CLOSE, _this.close);
69
- return _this;
70
- }
71
-
72
- /**
73
- * @param {Object} nextProps The next component props.
74
- * @param {Object} nextState The next component state.
75
- * @returns {JSX}
76
- */
77
- _inheritsLoose(NavDrawer, _Component);
78
- var _proto = NavDrawer.prototype;
79
- _proto.shouldComponentUpdate = function shouldComponentUpdate(nextProps, nextState) {
80
- return this.state.open !== nextState.open;
81
- }
82
-
83
- /**
84
- * The unmount lifecycle hook
85
- */;
86
- _proto.componentWillUnmount = function componentWillUnmount() {
87
- UIEvents.removeListener(OPEN, this.open);
88
- UIEvents.removeListener(CLOSE, this.close);
89
- };
90
- /**
91
- * @returns {JSX}
92
- */
93
- _proto.render = function render() {
94
- return /*#__PURE__*/_jsxs(_Fragment, {
95
- children: [/*#__PURE__*/_jsx(Transition, {
96
- onEntering: this.onEntering,
97
- onEntered: this.onEntered,
98
- onExited: this.onExited,
99
- onExiting: this.onExiting,
100
- in: this.state.open,
101
- timeout: 300,
102
- children: state => {
103
- const ariaHidden = this.props['aria-hidden'] || state === 'exited';
104
- return /*#__PURE__*/_jsx(ModalStateTracker, {
105
- isVisible: this.state.open,
106
- children: /*#__PURE__*/_jsxs("section", {
107
- className: `${drawerStyle} ui-material__nav-drawer`,
108
- "data-test-id": "NavDrawer",
109
- style: transition[state],
110
- "aria-hidden": ariaHidden,
111
- tabIndex: "-1",
112
- children: [/*#__PURE__*/_jsx(Item, {
113
- label: "common.close",
114
- ref: this.a11yCloseRef,
115
- srOnly: true
116
- }), /*#__PURE__*/_jsx("nav", {
117
- className: contentStyle,
118
- ref: this.contentRef,
119
- children: this.props.children
120
- })]
121
- })
122
- });
123
- }
124
- }), /*#__PURE__*/_jsx(Backdrop, {
125
- isVisible: this.state.open,
126
- level: 4,
127
- onClick: this.close,
128
- opacity: 20
129
- })]
130
- });
131
- };
132
- return NavDrawer;
133
- }(Component);
86
+ }, []);
87
+ const closeDrawer = useCallback(() => {
88
+ setOpen(false);
89
+ }, []);
90
+ const handleEntering = useCallback(() => {
91
+ onOpen();
92
+ }, [onOpen]);
93
+ const handleEntered = useCallback(() => {
94
+ a11yCloseRef.current?.focus();
95
+ }, []);
96
+ const handleExiting = useCallback(() => {
97
+ onClose();
98
+ }, [onClose]);
99
+ const handleExited = useCallback(() => {
100
+ if (contentRef.current) {
101
+ contentRef.current.scrollTop = 0;
102
+ }
103
+ const trigger = triggerElementRef.current;
104
+ if (trigger && typeof trigger.focus === 'function') {
105
+ trigger.focus();
106
+ }
107
+ }, []);
108
+ return /*#__PURE__*/_jsxs(_Fragment, {
109
+ children: [/*#__PURE__*/_jsx(Transition, {
110
+ onEntering: handleEntering,
111
+ onEntered: handleEntered,
112
+ onExited: handleExited,
113
+ onExiting: handleExiting,
114
+ in: open,
115
+ timeout: 300,
116
+ children: state => /*#__PURE__*/_jsx(ModalStateTracker, {
117
+ isVisible: open,
118
+ children: /*#__PURE__*/_jsxs("section", {
119
+ className: cx(classes.drawer, 'ui-material__nav-drawer'),
120
+ "data-test-id": "NavDrawer",
121
+ style: transition[state],
122
+ "aria-hidden": ariaHiddenProp || state === 'exited',
123
+ tabIndex: "-1",
124
+ children: [/*#__PURE__*/_jsx(Item, {
125
+ label: "common.close",
126
+ ref: a11yCloseRef,
127
+ srOnly: true
128
+ }), /*#__PURE__*/_jsx("nav", {
129
+ className: classes.content,
130
+ ref: contentRef,
131
+ children: children
132
+ })]
133
+ })
134
+ })
135
+ }), /*#__PURE__*/_jsx(Backdrop, {
136
+ isVisible: open,
137
+ level: 4,
138
+ onClick: closeDrawer,
139
+ opacity: 20
140
+ })]
141
+ });
142
+ };
143
+ NavDrawer.defaultProps = {
144
+ 'aria-hidden': false,
145
+ onClose: noop,
146
+ onOpen: noop
147
+ };
134
148
  NavDrawer.EVENT_OPEN = OPEN;
135
149
  NavDrawer.EVENT_CLOSE = CLOSE;
136
150
  NavDrawer.Divider = Divider;
137
151
  NavDrawer.Item = Item;
138
152
  NavDrawer.Section = Section;
139
153
  NavDrawer.Title = Title;
140
- NavDrawer.close = () => {
141
- UIEvents.emit(CLOSE);
142
- };
143
154
  NavDrawer.open = () => {
144
155
  UIEvents.emit(OPEN);
145
156
  };
146
- NavDrawer.defaultProps = {
147
- 'aria-hidden': false,
148
- onClose: noop,
149
- onOpen: noop
157
+ NavDrawer.close = () => {
158
+ UIEvents.emit(CLOSE);
150
159
  };
151
160
  export default NavDrawer;
package/NavDrawer/spec.js CHANGED
@@ -1,10 +1,95 @@
1
+ import "core-js/modules/es.array.reduce.js";
2
+ /* eslint-disable global-require, extra-rules/no-single-line-objects */
1
3
  import React from 'react';
2
4
  import { shallow, mount } from 'enzyme';
5
+ import { act } from 'react-dom/test-utils';
6
+ import Transition from 'react-transition-group/Transition';
7
+ jest.unmock('@shopgate/pwa-core');
8
+ jest.mock('@shopgate/engage/styles', () => ({
9
+ makeStyles: () => function mockUseStylesFactory(defs) {
10
+ return function useStylesMock() {
11
+ const keys = Object.keys(defs);
12
+ const classes = keys.reduce((acc, key) => {
13
+ acc[key] = `mock-class-${key}`;
14
+ return acc;
15
+ }, {});
16
+ const cx = (...parts) => parts.filter(Boolean).join(' ');
17
+ return {
18
+ classes,
19
+ cx
20
+ };
21
+ };
22
+ }
23
+ }));
24
+ jest.mock('@shopgate/engage/components', () => {
25
+ const mockReact = require('react');
26
+ const mockPropTypes = require('prop-types');
27
+ function Backdrop(props) {
28
+ const {
29
+ isVisible,
30
+ onClick
31
+ } = props;
32
+ if (!isVisible) {
33
+ return null;
34
+ }
35
+ return mockReact.createElement('button', {
36
+ type: 'button',
37
+ 'aria-label': 'Close',
38
+ 'data-test-id': 'NavDrawerBackdrop',
39
+ onClick
40
+ });
41
+ }
42
+ Backdrop.propTypes = {
43
+ isVisible: mockPropTypes.bool,
44
+ onClick: mockPropTypes.func
45
+ };
46
+ Backdrop.defaultProps = {
47
+ isVisible: false,
48
+ onClick: undefined
49
+ };
50
+ Backdrop.displayName = 'Backdrop';
51
+ return {
52
+ Backdrop
53
+ };
54
+ });
55
+ jest.mock('@shopgate/engage/a11y/components', () => {
56
+ const mockPropTypes = require('prop-types');
57
+ function ModalStateTracker(props) {
58
+ return props.children;
59
+ }
60
+ ModalStateTracker.propTypes = {
61
+ children: mockPropTypes.node
62
+ };
63
+ ModalStateTracker.defaultProps = {
64
+ children: null
65
+ };
66
+ return {
67
+ ModalStateTracker
68
+ };
69
+ });
70
+ jest.mock("./components/Item", () => {
71
+ const mockReact = require('react');
72
+ const mockPropTypes = require('prop-types');
73
+ const ItemWithRef = mockReact.forwardRef((props, ref) => mockReact.createElement('button', {
74
+ type: 'button',
75
+ ref,
76
+ 'data-test-id': 'nav-drawer-item'
77
+ }, props.label));
78
+ ItemWithRef.propTypes = {
79
+ label: mockPropTypes.string
80
+ };
81
+ ItemWithRef.defaultProps = {
82
+ label: ''
83
+ };
84
+ return {
85
+ __esModule: true,
86
+ default: ItemWithRef
87
+ };
88
+ });
89
+
90
+ // eslint-disable-next-line import/first
3
91
  import NavDrawer from "./index";
4
92
  import { jsx as _jsx } from "react/jsx-runtime";
5
- jest.unmock('@shopgate/pwa-core');
6
- jest.mock('@shopgate/engage/components');
7
- jest.mock('@shopgate/engage/a11y/components');
8
93
  describe('NavDrawer', () => {
9
94
  it('should match the snapshot', () => {
10
95
  const wrapper = shallow(/*#__PURE__*/_jsx(NavDrawer, {
@@ -20,22 +105,35 @@ describe('NavDrawer', () => {
20
105
  onClose: onClose,
21
106
  children: "Content"
22
107
  }));
23
- NavDrawer.open();
24
- expect(wrapper.state().open).toEqual(true);
108
+ act(() => {
109
+ NavDrawer.open();
110
+ });
111
+ wrapper.update();
112
+ expect(wrapper.find(Transition).prop('in')).toEqual(true);
25
113
  expect(onOpen).toHaveBeenCalled();
26
114
  expect(onClose).not.toHaveBeenCalled();
27
- NavDrawer.close();
28
- expect(wrapper.state().open).toEqual(false);
115
+ act(() => {
116
+ NavDrawer.close();
117
+ });
118
+ wrapper.update();
119
+ expect(wrapper.find(Transition).prop('in')).toEqual(false);
29
120
  expect(onClose).toHaveBeenCalled();
30
121
  });
31
122
  it('should close when Backdrop is clicked', () => {
32
- const wrapper = shallow(/*#__PURE__*/_jsx(NavDrawer, {
123
+ const wrapper = mount(/*#__PURE__*/_jsx(NavDrawer, {
33
124
  children: "Content"
34
125
  }));
35
- const backdrop = wrapper.find('Backdrop');
36
- NavDrawer.open();
37
- expect(wrapper.state().open).toEqual(true);
38
- backdrop.simulate('click');
39
- expect(wrapper.state().open).toEqual(false);
126
+ act(() => {
127
+ NavDrawer.open();
128
+ });
129
+ wrapper.update();
130
+ expect(wrapper.find(Transition).prop('in')).toEqual(true);
131
+ const backdrop = wrapper.find('[data-test-id="NavDrawerBackdrop"]');
132
+ act(() => {
133
+ backdrop.simulate('click');
134
+ });
135
+ wrapper.update();
136
+ expect(wrapper.find(Transition).prop('in')).toEqual(false);
40
137
  });
41
- });
138
+ });
139
+ /* eslint-enable global-require, extra-rules/no-single-line-objects */