@woosmap/ui 2.44.0 → 2.48.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.
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@woosmap/ui",
3
- "version": "2.44.0",
3
+ "version": "2.48.0",
4
4
  "repository": {
5
5
  "type": "git",
6
6
  "url": "git+https://github.com/WebGeoServices/ui.git"
@@ -104,7 +104,7 @@ Button.propTypes = {
104
104
  ]),
105
105
  isLoading: PropTypes.bool,
106
106
  active: PropTypes.bool,
107
- label: PropTypes.string,
107
+ label: PropTypes.oneOfType(PropTypes.string, PropTypes.node),
108
108
  icon: PropTypes.string,
109
109
  iconSize: PropTypes.number,
110
110
  className: PropTypes.string,
@@ -45,9 +45,20 @@ class DropdownMenu extends Component {
45
45
  };
46
46
 
47
47
  render() {
48
- const { direction, children, closeCb, testId, ...rest } = this.props;
48
+ const { direction, children, closeCb, testId, isSection, ...rest } = this.props;
49
49
  const childrenWithProps = mapChildrenWithProps(children, this.childrenRefs, closeCb);
50
-
50
+ if (isSection) {
51
+ return (
52
+ <div
53
+ role="menu"
54
+ className={cl('dropdown__menu', direction, 'dropdown__menu--section')}
55
+ data-testid={testId}
56
+ {...rest}
57
+ >
58
+ {childrenWithProps}
59
+ </div>
60
+ );
61
+ }
51
62
  return (
52
63
  <ul role="menu" className={cl('dropdown__menu', direction)} data-testid={testId} {...rest}>
53
64
  {childrenWithProps}
@@ -60,15 +71,50 @@ DropdownMenu.defaultProps = {
60
71
  direction: 'sw',
61
72
  closeCb: null,
62
73
  testId: 'dropdown-menu',
74
+ isSection: false,
63
75
  };
64
76
 
65
77
  DropdownMenu.propTypes = {
66
78
  children: PropTypes.node.isRequired,
67
79
  closeCb: PropTypes.func,
68
80
  testId: PropTypes.string,
81
+ isSection: PropTypes.bool,
69
82
  direction: PropTypes.oneOf(['ne', 'e', 'se', 's', 'sw', 'w']),
70
83
  };
71
84
 
85
+ class DropdownMenuSection extends Component {
86
+ constructor(props) {
87
+ super(props);
88
+ this.childrenRefs = {};
89
+ }
90
+
91
+ close = () => {
92
+ closeChildren(this.childrenRefs);
93
+ };
94
+
95
+ render() {
96
+ const { title, children, closeCb, ...rest } = this.props;
97
+ const childrenWithProps = mapChildrenWithProps(children, this.childrenRefs, closeCb);
98
+ return (
99
+ <div className="dropdown__menu__section">
100
+ {title && <div className="dropdown__menu__section__title">{title}</div>}
101
+ <ul {...rest}>{childrenWithProps}</ul>
102
+ </div>
103
+ );
104
+ }
105
+ }
106
+
107
+ DropdownMenuSection.defaultProps = {
108
+ title: null,
109
+ closeCb: null,
110
+ };
111
+
112
+ DropdownMenuSection.propTypes = {
113
+ children: PropTypes.node.isRequired,
114
+ title: PropTypes.string,
115
+ closeCb: PropTypes.func,
116
+ };
117
+
72
118
  class DropdownSeparator extends Component {
73
119
  render() {
74
120
  const { testId } = this.props;
@@ -243,6 +289,28 @@ class Dropdown extends Component {
243
289
  this.setOpen(false);
244
290
  };
245
291
 
292
+ onMouseEnter = () => {
293
+ const { openOnMouseEnter } = this.props;
294
+ if (openOnMouseEnter) {
295
+ if (this.mouseLeaveTimeout) {
296
+ clearTimeout(this.mouseLeaveTimeout);
297
+ }
298
+ this.setOpen(true);
299
+ }
300
+ };
301
+
302
+ onMouseLeave = () => {
303
+ const { openOnMouseEnter } = this.props;
304
+ if (openOnMouseEnter) {
305
+ if (this.mouseLeaveTimeout) {
306
+ clearTimeout(this.mouseLeaveTimeout);
307
+ }
308
+ this.mouseLeaveTimeout = setTimeout(() => {
309
+ this.setOpen(false);
310
+ }, 500);
311
+ }
312
+ };
313
+
246
314
  onClick = (e) => {
247
315
  const { onClick } = this.props;
248
316
  const { open } = this.state;
@@ -273,6 +341,7 @@ class Dropdown extends Component {
273
341
  closeCb,
274
342
  disableCloseOutside,
275
343
  testId,
344
+ openOnMouseEnter,
276
345
  ...rest
277
346
  } = this.props;
278
347
  const { open } = this.state;
@@ -283,6 +352,8 @@ class Dropdown extends Component {
283
352
  ref={this.clickOutsideRef}
284
353
  className={cl('dropdown', { open }, `dropdown--${size}`, className)}
285
354
  {...rest}
355
+ onMouseEnter={this.onMouseEnter}
356
+ onMouseLeave={this.onMouseLeave}
286
357
  >
287
358
  <Button
288
359
  disabled={disabled}
@@ -311,6 +382,7 @@ Dropdown.defaultProps = {
311
382
  label: null,
312
383
  className: null,
313
384
  closeCb: null,
385
+ openOnMouseEnter: false,
314
386
  btnFace: 'link-flex',
315
387
  btnFaceIcon: 'caret-bottom',
316
388
  btnFaceIconSize: 24,
@@ -323,7 +395,8 @@ Dropdown.propTypes = {
323
395
  onDoubleClick: PropTypes.func,
324
396
  disabled: PropTypes.bool,
325
397
  disableCloseOutside: PropTypes.bool,
326
- label: PropTypes.string,
398
+ openOnMouseEnter: PropTypes.bool,
399
+ label: PropTypes.oneOfType(PropTypes.string, PropTypes.node),
327
400
  testId: PropTypes.string,
328
401
  children: PropTypes.node.isRequired,
329
402
  className: PropTypes.string,
@@ -336,6 +409,7 @@ Dropdown.propTypes = {
336
409
 
337
410
  export default Object.assign(withClickOutside(Dropdown, '.popover__content'), {
338
411
  Menu: DropdownMenu,
412
+ MenuSection: DropdownMenuSection,
339
413
  Item: DropdownItem,
340
414
  ButtonItem: DropdownButtonItem,
341
415
  ConfirmButtonItem: DropdownConfirmButtonItem,
@@ -52,3 +52,32 @@ const Template = () => (
52
52
  );
53
53
  export const Default = Template.bind({});
54
54
  Default.args = {};
55
+
56
+ const MultiMenuTemplate = () => (
57
+ <div className="mbi" id="menuid">
58
+ <Dropdown btnFace="link" btnFaceIcon="clock" label="My dropdown" openOnMouseEnter>
59
+ <Dropdown.Menu isSection direction="se">
60
+ <Dropdown.MenuSection title="Section title">
61
+ <Dropdown.ButtonItem btnIcon="delete" isImportant btnLabel="Delete" />
62
+ <Dropdown.ConfirmButtonItem
63
+ btnIcon="delete"
64
+ isImportant
65
+ btnLabel="Delete confirm"
66
+ onConfirm={() => null}
67
+ />
68
+ </Dropdown.MenuSection>
69
+ <Dropdown.MenuSection title="Section title 2">
70
+ <Dropdown.ButtonItem btnIcon="delete" isImportant btnLabel="Delete" />
71
+ <Dropdown.ConfirmButtonItem
72
+ btnIcon="delete"
73
+ isImportant
74
+ btnLabel="Delete confirm"
75
+ onConfirm={() => null}
76
+ />
77
+ </Dropdown.MenuSection>
78
+ </Dropdown.Menu>
79
+ </Dropdown>
80
+ </div>
81
+ );
82
+ export const MultiMenuTemplateDropdown = MultiMenuTemplate.bind({});
83
+ MultiMenuTemplateDropdown.args = {};
@@ -50,9 +50,12 @@
50
50
  right 0
51
51
  left auto
52
52
 
53
+
53
54
  &.open
54
55
  .dropdown__menu
55
56
  display block
57
+ &--section
58
+ display flex
56
59
 
57
60
  &__item
58
61
  flexMiddle()
@@ -114,6 +114,9 @@ import { ReactComponent as Localities } from '../../icons/localities.svg';
114
114
  import { ReactComponent as Map } from '../../icons/map.svg';
115
115
  import { ReactComponent as Merchant } from '../../icons/merchant.svg';
116
116
  import { ReactComponent as Traffic } from '../../icons/traffic.svg';
117
+ import { ReactComponent as SocialFacebook } from '../../icons/social-facebook.svg';
118
+ import { ReactComponent as SocialLinkedin } from '../../icons/social-linkedin.svg';
119
+ import { ReactComponent as SocialTwitter } from '../../icons/social-twitter.svg';
117
120
 
118
121
  const Icons = {
119
122
  access: Access,
@@ -229,6 +232,9 @@ const Icons = {
229
232
  maps: Map,
230
233
  merchant: Merchant,
231
234
  traffic: Traffic,
235
+ 'social-facebook': SocialFacebook,
236
+ 'social-linkedin': SocialLinkedin,
237
+ 'social-twitter': SocialTwitter,
232
238
  };
233
239
 
234
240
  class Icon extends Component {
@@ -15,6 +15,10 @@ class Modal extends Component {
15
15
  this.modalRef = React.createRef();
16
16
  }
17
17
 
18
+ componentDidMount() {
19
+ this.handleEscFunction('add');
20
+ }
21
+
18
22
  componentDidUpdate() {
19
23
  const { isLoading } = this.state;
20
24
  const { hasErrors } = this.props;
@@ -23,6 +27,10 @@ class Modal extends Component {
23
27
  }
24
28
  }
25
29
 
30
+ componentWillUnmount() {
31
+ this.handleEscFunction();
32
+ }
33
+
26
34
  handleClickOutside = () => {
27
35
  this.close();
28
36
  };
@@ -31,6 +39,20 @@ class Modal extends Component {
31
39
  this.setState({ isLoading: loading });
32
40
  }
33
41
 
42
+ handleEscFunction = (key) => {
43
+ const { closesWithEscape } = this.props;
44
+ if (closesWithEscape) {
45
+ if (key === 'add') document.addEventListener('keydown', this.escFunction, false);
46
+ else document.removeEventListener('keydown', this.escFunction, false);
47
+ }
48
+ };
49
+
50
+ escFunction = (event) => {
51
+ if (event.keyCode === 27) {
52
+ this.close();
53
+ }
54
+ };
55
+
34
56
  open = () => {
35
57
  this.setState({ open: true });
36
58
  };
@@ -141,6 +163,7 @@ Modal.defaultProps = {
141
163
  validateBtnProps: {},
142
164
  mainButtonType: 'primary',
143
165
  testId: 'modal',
166
+ closesWithEscape: false,
144
167
  };
145
168
 
146
169
  Modal.propTypes = {
@@ -160,6 +183,7 @@ Modal.propTypes = {
160
183
  validateBtnProps: PropTypes.object,
161
184
  mainButtonType: PropTypes.string,
162
185
  testId: PropTypes.string,
186
+ closesWithEscape: PropTypes.bool,
163
187
  };
164
188
 
165
189
  export default withClickOutside(Modal, '.ignore-click-outside-modal');
@@ -78,3 +78,15 @@ const TemplateConfirmationModal = () => {
78
78
  };
79
79
  export const ModalConfirmation = TemplateConfirmationModal.bind({});
80
80
  Default.args = {};
81
+
82
+ const TemplateEscapeModal = () => {
83
+ const modalRef = React.createRef();
84
+ return (
85
+ <div style={{ paddingLeft: '50px' }}>
86
+ <Button onClick={() => modalRef.current.open()} label="Open modal" />
87
+ <Modal ref={modalRef} closesWithEscape title="My modal" />
88
+ </div>
89
+ );
90
+ };
91
+ export const ModalEscape = TemplateEscapeModal.bind({});
92
+ Default.args = {};
@@ -1,5 +1,5 @@
1
1
  import React from 'react';
2
- import { render, screen } from '@testing-library/react';
2
+ import { render, screen, fireEvent } from '@testing-library/react';
3
3
  import '@testing-library/jest-dom/extend-expect';
4
4
  import { act } from 'react-dom/test-utils';
5
5
  import userEvent from '@testing-library/user-event';
@@ -56,7 +56,7 @@ it('is hidden after clicking cancel', () => {
56
56
  }
57
57
  });
58
58
 
59
- it('is hidden after clicking cancel', () => {
59
+ it('is hidden after clicking validate', () => {
60
60
  const modalRef = React.createRef();
61
61
  const validateCb = jest.fn();
62
62
  render(
@@ -72,3 +72,19 @@ it('is hidden after clicking cancel', () => {
72
72
  userEvent.click(validate);
73
73
  expect(validateCb.mock.calls.length).toBe(1);
74
74
  });
75
+
76
+ it('is closing after escaping if it is set to be closed with it', () => {
77
+ const modalRef = React.createRef();
78
+ const closeCb = jest.fn();
79
+ render(
80
+ <Modal ref={modalRef} closesWithEscape closeCb={closeCb}>
81
+ content
82
+ </Modal>
83
+ );
84
+ act(() => {
85
+ modalRef.current.open();
86
+ });
87
+ expect(closeCb).not.toHaveBeenCalled();
88
+ fireEvent.keyDown(document, { keyCode: 27 });
89
+ expect(closeCb).toHaveBeenCalled();
90
+ });
@@ -0,0 +1 @@
1
+ <svg xmlns="http://www.w3.org/2000/svg" viewBox="0 0 24 24"><path d="M19.426 1.66H4.661a3 3 0 0 0-3 3v14.766a3 3 0 0 0 3 3H12.7v-8.095H10v-3.1h2.7V8.93a3.76 3.76 0 0 1 3.37-4.113 3.823 3.823 0 0 1 .642-.009 18.532 18.532 0 0 1 2.413.124v2.779H17.46c-1.3 0-1.53.607-1.53 1.516v2h3.075l-.4 3.1h-2.676v8.1h3.5a3 3 0 0 0 3-3V4.66a3 3 0 0 0-3.003-3Z" fill-rule="evenodd"/></svg>
@@ -0,0 +1 @@
1
+ <svg xmlns="http://www.w3.org/2000/svg" viewBox="0 0 24 24"><path d="M19.426 1.66H4.661a3 3 0 0 0-3 3v14.766a3 3 0 0 0 3 3h14.765a3 3 0 0 0 3-3V4.66a3 3 0 0 0-3-3ZM7.8 19.281H4.721V9.409H7.8ZM6.26 8.072h-.012a1.778 1.778 0 0 1-1.761-1.793v-.006a1.786 1.786 0 1 1 1.772 1.8Zm9.961 11.21v-4.8c0-1.144-.028-2.62-1.6-2.62-1.6 0-1.834 1.255-1.834 2.537v4.88H9.726v-9.87h2.935v1.349h.032a3.225 3.225 0 0 1 2.9-1.586c3.115 0 3.68 2.04 3.68 4.7l.007 5.41Z" fill-rule="evenodd"/></svg>
@@ -0,0 +1 @@
1
+ <svg xmlns="http://www.w3.org/2000/svg" viewBox="0 0 24 24"><path d="M23.066 5.136a8.972 8.972 0 0 1-2.61.715 4.552 4.552 0 0 0 2-2.511 9.083 9.083 0 0 1-2.884 1.1 4.545 4.545 0 0 0-7.741 4.142 12.9 12.9 0 0 1-9.357-4.744A4.544 4.544 0 0 0 3.879 9.9a4.542 4.542 0 0 1-2.058-.567v.057a4.542 4.542 0 0 0 3.642 4.453 4.519 4.519 0 0 1-1.2.159 4.441 4.441 0 0 1-.853-.08 4.549 4.549 0 0 0 4.241 3.153 9.112 9.112 0 0 1-5.639 1.944 9.559 9.559 0 0 1-1.082-.062A12.88 12.88 0 0 0 7.892 21 12.832 12.832 0 0 0 20.814 8.254v-.179c0-.2 0-.393-.014-.588a9.2 9.2 0 0 0 2.267-2.348Z"/></svg>
@@ -1,10 +1,10 @@
1
1
  html
2
- font-size: 62.5%
3
- width: 100%
4
- height: 100%
5
- -moz-text-size-adjust: 100%
6
- -webkit-text-size-adjust: 100%
7
- -ms-text-size-adjust: 100%
2
+ font-size 62.5%
3
+ width 100%
4
+ height 100%
5
+ -moz-text-size-adjust 100%
6
+ -webkit-text-size-adjust 100%
7
+ -ms-text-size-adjust 100%
8
8
 
9
9
  body
10
10
  width 100%