@jetbrains/ring-ui 4.0.40 → 4.0.44

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.
@@ -1,6 +1,7 @@
1
1
  @import "../global/variables.css";
2
2
 
3
3
  .avatar {
4
+ display: inline-block;
4
5
  object-fit: cover;
5
6
  object-position: center;
6
7
 
@@ -21,7 +21,8 @@ export const avatar = () => {
21
21
  {Object.keys(Size).map(size => (
22
22
  <div className="avatar-demo" key={size}>
23
23
  <Avatar size={Size[size]} url={avatarDataUri}/>
24
- <Avatar size={Size[size]} url={avatarDataUri} round/>
24
+ <Avatar size={Size[size]} username="Jet Brains"/>
25
+ <Avatar size={Size[size]} username="Jet Brains" round/>
25
26
  <Avatar size={Size[size]}/>
26
27
  </div>
27
28
  ))}
@@ -38,7 +39,7 @@ avatar.parameters = {
38
39
  .avatar-demo {
39
40
  display: flex;
40
41
  justify-content: space-between;
41
- width: 200px;
42
+ width: 240px;
42
43
  margin-bottom: 16px;
43
44
  }
44
45
  </style>`
@@ -6,6 +6,7 @@ import {encodeURL, isDataURI, parseQueryString} from '../global/url';
6
6
  import {getPixelRatio} from '../global/dom';
7
7
 
8
8
  import styles from './avatar.css';
9
+ import FallbackAvatar from './fallback-avatar';
9
10
 
10
11
  /**
11
12
  * @name Avatar
@@ -30,7 +31,8 @@ export default class Avatar extends PureComponent {
30
31
  url: PropTypes.string,
31
32
  round: PropTypes.bool,
32
33
  subavatar: PropTypes.string,
33
- subavatarSize: PropTypes.number
34
+ subavatarSize: PropTypes.number,
35
+ username: PropTypes.string
34
36
  };
35
37
 
36
38
  static defaultProps = {
@@ -53,7 +55,17 @@ export default class Avatar extends PureComponent {
53
55
  };
54
56
 
55
57
  render() {
56
- const {size, url, dpr, style, round, subavatar, subavatarSize, ...restProps} = this.props;
58
+ const {
59
+ size,
60
+ url,
61
+ dpr,
62
+ style,
63
+ round,
64
+ subavatar,
65
+ subavatarSize,
66
+ username,
67
+ ...restProps
68
+ } = this.props;
57
69
  const sizeString = `${size}px`;
58
70
  const subavatarSizeString = `${subavatarSize}px`;
59
71
  const borderRadius = size <= Size.Size18 ? 'var(--ring-border-radius-small)' : 'var(--ring-border-radius)';
@@ -76,9 +88,19 @@ export default class Avatar extends PureComponent {
76
88
  <span
77
89
  {...restProps}
78
90
  data-test="avatar"
79
- className={classNames(styles.avatar, styles.empty, this.props.className)}
91
+ className={
92
+ classNames(styles.avatar, this.props.className, {[styles.empty]: username == null})
93
+ }
80
94
  style={styleObj}
81
- />
95
+ >{
96
+ username != null && (
97
+ <FallbackAvatar
98
+ size={size}
99
+ round={round}
100
+ username={username}
101
+ />
102
+ )
103
+ }</span>
82
104
  );
83
105
  }
84
106
 
@@ -0,0 +1,136 @@
1
+ import React, {useMemo} from 'react';
2
+ import PropTypes from 'prop-types';
3
+
4
+ import getUID from '../global/get-uid';
5
+
6
+ const colorPairs = [
7
+ ['#60A800', '#D5CA00'],
8
+ ['#21D370', '#03E9E1'],
9
+ ['#3BA1FF', '#36E97D'],
10
+ ['#00C243', '#00FFFF'],
11
+ ['#4BE098', '#627FFF'],
12
+ ['#168BFA', '#26F7C7'],
13
+ ['#9D4CFF', '#39D3C3'],
14
+ ['#0A81F6', '#0ACFF6'],
15
+ ['#765AF8', '#5A91F8'],
16
+ ['#9E54FF', '#0ACFF6'],
17
+ ['#B345F1', '#669DFF'],
18
+ ['#765AF8', '#C059EE'],
19
+ ['#9039D0', '#C239D0'],
20
+ ['#9F2AFF', '#FD56FD'],
21
+ ['#AB3AF2', '#E40568'],
22
+ ['#9F2AFF', '#E9A80B'],
23
+ ['#D50F6B', '#E73AE8'],
24
+ ['#ED5502', '#E73AE8'],
25
+ ['#ED358C', '#DBED18'],
26
+ ['#ED358C', '#F9902E'],
27
+ ['#FF7500', '#FFCA00']
28
+ ];
29
+
30
+ const Sizes = {
31
+ 18: {
32
+ radius: 2,
33
+ text: {x: 9, y: 13},
34
+ fontSize: '11px',
35
+ textAnchor: 'middle'
36
+ },
37
+ 24: {
38
+ radius: 3,
39
+ text: {x: 2, y: 13},
40
+ fontSize: '11px',
41
+ underscore: {x: 3, y: 17}
42
+ },
43
+ 32: {
44
+ radius: 3,
45
+ text: {x: 3, y: 17},
46
+ fontSize: '13px',
47
+ letterSpacing: 1,
48
+ underscore: {x: 4, y: 22}
49
+ },
50
+ 40: {
51
+ radius: 3,
52
+ text: {x: 5, y: 19},
53
+ fontSize: '15px',
54
+ letterSpacing: 1,
55
+ underscore: {x: 6, y: 28}
56
+ }
57
+ };
58
+
59
+ const sizeKeys = Object.keys(Sizes).map(Number);
60
+
61
+ function extractLetters(name) {
62
+ const names = name.split(/[\s._]+/).filter(Boolean);
63
+ if (names.length >= 2) {
64
+ return names[0][0].toUpperCase() + names[1][0].toUpperCase();
65
+ } else if (names.length === 1) {
66
+ if (names[0].length >= 2) {
67
+ return names[0].slice(0, 2).toUpperCase();
68
+ } else {
69
+ return `${names[0][0].toUpperCase()}X`;
70
+ }
71
+ } else {
72
+ return 'XX';
73
+ }
74
+ }
75
+
76
+ // https://gist.github.com/hyamamoto/fd435505d29ebfa3d9716fd2be8d42f0#gistcomment-2775538
77
+ const BASE = 32;
78
+ function hashCode(s) {
79
+ let h = 0;
80
+ for (let i = 0; i < s.length; i++) {
81
+ h = Math.imul(BASE - 1, h) + s.charCodeAt(i) | 0;
82
+ }
83
+
84
+ return h;
85
+ }
86
+
87
+ export default function FallbackAvatar({username, size, round}) {
88
+ const hash = Math.abs(hashCode(username.toLowerCase()));
89
+ const [fromColor, toColor] = colorPairs[hash % colorPairs.length];
90
+ const possibleSizeKeys = sizeKeys.filter(key => key >= size);
91
+ const sizeKey = possibleSizeKeys.length > 0
92
+ ? Math.min(...possibleSizeKeys)
93
+ : Math.max(...sizeKeys);
94
+ const sizes = Sizes[sizeKey];
95
+ const radius = round ? '50%' : sizes.radius;
96
+ const gradientId = useMemo(() => getUID('gradient-'), []);
97
+ return (
98
+ <svg viewBox={`0 0 ${sizeKey} ${sizeKey}`} xmlns="http://www.w3.org/2000/svg">
99
+ <defs>
100
+ <linearGradient id={gradientId} x1="0" y1="0" x2="0" y2="1">
101
+ <stop stopColor={fromColor} offset="0"/>
102
+ <stop stopColor={toColor} offset="1"/>
103
+ </linearGradient>
104
+ </defs>
105
+ <g>
106
+ <rect
107
+ fill={`url(#${gradientId})`}
108
+ x="0"
109
+ y="0"
110
+ width={sizeKey}
111
+ height={sizeKey}
112
+ rx={radius}
113
+ ry={radius}
114
+ />
115
+ <text
116
+ x={sizes.text.x}
117
+ y={sizes.text.y}
118
+ fontFamily="Arial, Helvetica, sans-serif"
119
+ fontSize={sizes.fontSize}
120
+ letterSpacing={sizes.letterSpacing}
121
+ fill="#FFFFFF"
122
+ textAnchor={sizes.textAnchor}
123
+ >
124
+ <tspan>{extractLetters(username)}</tspan>
125
+ {sizes.underscore && <tspan x={sizes.underscore.x} y={sizes.underscore.y}>{'_'}</tspan>}
126
+ </text>
127
+ </g>
128
+ </svg>
129
+ );
130
+ }
131
+
132
+ FallbackAvatar.propTypes = {
133
+ username: PropTypes.string.isRequired,
134
+ size: PropTypes.number.isRequired,
135
+ round: PropTypes.bool
136
+ };
@@ -61,7 +61,6 @@ export const withCustomAnchorAndPopupAndContentAccessibilityHandling = () => {
61
61
  return (
62
62
  <Button
63
63
  {...anchorAriaProps}
64
- has-popup="true"
65
64
  delayed
66
65
  >Edit</Button>
67
66
  );
@@ -0,0 +1,47 @@
1
+ import React from 'react';
2
+
3
+ import reactDecorator from '../../.storybook/react-decorator';
4
+
5
+ import DropdownMenu from '@jetbrains/ring-ui/components/dropdown-menu/dropdown-menu';
6
+
7
+ export default {
8
+ title: 'Components/DropdownMenu',
9
+ decorators: [reactDecorator()],
10
+
11
+ parameters: {
12
+ notes: 'Displays a menu in a dropdown.',
13
+ hermione: {
14
+ actions: [
15
+ {type: 'click', selector: '[data-test~=ring-dropdown]'},
16
+ {
17
+ type: 'capture',
18
+ name: 'dropdown',
19
+ selector: ['[data-test~=ring-dropdown]', '[data-test~=ring-popup]']
20
+ }
21
+ ]
22
+ },
23
+ a11y: {element: '*[data-test~=ring-dropdown]'}
24
+ }
25
+ };
26
+
27
+ export const basic = () => {
28
+ const data = [
29
+ {label: 'Item'},
30
+ {label: 'Link to jetbrains.com', href: 'http://www.jetbrains.com'},
31
+ {rgItemType: DropdownMenu.ListProps.Type.SEPARATOR},
32
+ {rgItemType: DropdownMenu.ListProps.Type.LINK, label: 'Link Item'},
33
+ {
34
+ rgItemType: DropdownMenu.ListProps.Type.LINK,
35
+ label: 'Link Item With Additional Class',
36
+ className: 'test'
37
+ },
38
+ {rgItemType: DropdownMenu.ListProps.Type.SEPARATOR, description: 'Separator With Description'},
39
+ {rgItemType: DropdownMenu.ListProps.Type.TITLE, label: 'Title'},
40
+ {rgItemType: DropdownMenu.ListProps.Type.ITEM, label: '1 Element in group'},
41
+ {rgItemType: DropdownMenu.ListProps.Type.ITEM, label: '2 Element in group'}
42
+ ];
43
+
44
+ return <DropdownMenu data={data} anchor={'Click me!'}/>;
45
+ };
46
+
47
+ basic.storyName = 'DropdownMenu';
@@ -0,0 +1,110 @@
1
+ import React, {useMemo, cloneElement} from 'react';
2
+ import PropTypes from 'prop-types';
3
+
4
+ import List, {ActiveItemContext} from '../list/list';
5
+ import Dropdown from '../dropdown/dropdown';
6
+ import PopupMenu from '../popup-menu/popup-menu';
7
+ import getUID from '../global/get-uid';
8
+ import Anchor from '../dropdown/anchor';
9
+
10
+ const {children, ...dropdownPropTypes} = Dropdown.propTypes || {};
11
+ const {
12
+ id: idPropType,
13
+ data: dataPropType,
14
+ ariaLabel: ariaLabelPropType,
15
+ onSelect: onSelectPropType
16
+ } = PopupMenu.propTypes || {};
17
+
18
+ const defaultAriaLabel = 'Dropdown menu';
19
+
20
+ function DropdownAnchorWrapper({anchor, pinned, active, activeListItemId, listId, ...restProps}) {
21
+ const anchorAriaProps = useMemo(() => ({
22
+ ...(listId ? {'aria-haspopup': 'true'} : {}),
23
+ ...(activeListItemId ? {'aria-activedescendant': activeListItemId, 'aria-owns': listId} : {}),
24
+ ...(active ? {'aria-expanded': 'true'} : {})
25
+ }), [active, activeListItemId, listId]);
26
+
27
+ const anchorProps = useMemo(
28
+ () => ({active, pinned, ...restProps, ...anchorAriaProps}),
29
+ [pinned, active, restProps, anchorAriaProps]
30
+ );
31
+
32
+ if (typeof anchor === 'string') {
33
+ return (
34
+ <Anchor
35
+ {...anchorProps}
36
+ pinned={`${pinned}`}
37
+ >{anchor}</Anchor>
38
+ );
39
+ }
40
+ if (typeof anchor === 'function') {
41
+ return anchor(({active, pinned, ...restProps}), anchorAriaProps);
42
+ }
43
+ if (!Array.isArray(anchor)) {
44
+ return cloneElement(anchor, typeof anchor.type === 'string' ? anchorAriaProps : anchorProps);
45
+ }
46
+ return (
47
+ <div {...anchorAriaProps}>{anchor}</div>
48
+ );
49
+ }
50
+
51
+ DropdownAnchorWrapper.propTypes = {
52
+ anchor: PropTypes.oneOfType([PropTypes.node, PropTypes.string, PropTypes.func]).isRequired,
53
+ pinned: PropTypes.bool,
54
+ active: PropTypes.bool,
55
+ activeListItemId: PropTypes.string,
56
+ listId: PropTypes.string
57
+ };
58
+
59
+ const DropdownMenu = React.forwardRef(function DropdownMenu(
60
+ {id, anchor, ariaLabel, data, onSelect, menuProps, ...restDropdownProps},
61
+ forwardedRef
62
+ ) {
63
+ const listId = useMemo(() => id || getUID('dropdown-menu-list'), [id]);
64
+
65
+ return (
66
+ <ActiveItemContext.Provider>
67
+ <Dropdown
68
+ anchor={({pinned, active, ...restAnchorProps}) => (
69
+ <ActiveItemContext.ValueContext.Consumer>
70
+ {activeItemId => (
71
+ <DropdownAnchorWrapper
72
+ anchor={anchor}
73
+ pinned={pinned}
74
+ active={active}
75
+ activeListItemId={activeItemId}
76
+ listId={listId}
77
+ {...restAnchorProps}
78
+ />
79
+ )}
80
+ </ActiveItemContext.ValueContext.Consumer>
81
+ )}
82
+ {...restDropdownProps}
83
+ >
84
+ <PopupMenu
85
+ ref={forwardedRef}
86
+ id={listId}
87
+ ariaLabel={ariaLabel || defaultAriaLabel}
88
+ closeOnSelect
89
+ activateFirstItem
90
+ data={data}
91
+ onSelect={onSelect}
92
+ {...menuProps}
93
+ />
94
+ </Dropdown>
95
+ </ActiveItemContext.Provider>
96
+ );
97
+ });
98
+
99
+ DropdownMenu.propTypes = {
100
+ id: idPropType,
101
+ data: dataPropType,
102
+ ariaLabel: ariaLabelPropType,
103
+ onSelect: onSelectPropType,
104
+ menuProps: PropTypes.object,
105
+ ...dropdownPropTypes
106
+ };
107
+
108
+ DropdownMenu.ListProps = List.ListProps;
109
+
110
+ export default DropdownMenu;
@@ -0,0 +1,76 @@
1
+ import React from 'react';
2
+ import {shallow, mount} from 'enzyme';
3
+
4
+ import PopupMenu from '../popup-menu/popup-menu';
5
+ import Anchor from '../dropdown/anchor';
6
+
7
+ import DropdownMenu from './dropdown-menu';
8
+
9
+ const waitForCondition = (condition, rejectMessage) => new Promise((resolve, reject) => {
10
+ const interval = 10;
11
+ const maxWaitingTime = 2000;
12
+ let remainingTime = maxWaitingTime;
13
+
14
+ const intervalId = setInterval(() => {
15
+ if (condition()) {
16
+ clearInterval(intervalId);
17
+ resolve();
18
+ } else if (remainingTime < 0) {
19
+ clearInterval(intervalId);
20
+ reject(new Error(rejectMessage));
21
+ } else {
22
+ remainingTime -= interval;
23
+ }
24
+ }, interval);
25
+ });
26
+
27
+ describe('Dropdown Menu', () => {
28
+ const shallowDropdownMenu = props => shallow(<DropdownMenu id="test-list-id" {...props}/>);
29
+ const mountDropdownMenu = props => mount(<DropdownMenu id="test-list-id" {...props}/>);
30
+
31
+ const mountAndWaitForMenuContent = async props => {
32
+ const wrapper = mountDropdownMenu(props);
33
+
34
+ wrapper.find('button').getDOMNode().click();
35
+ await waitForCondition(
36
+ () => !!wrapper.find(PopupMenu).length,
37
+ 'List was not rendered in a dropdown menu'
38
+ );
39
+
40
+ return wrapper;
41
+ };
42
+
43
+ it('should create component', () => {
44
+ shallowDropdownMenu({anchor: 'Anchor text'}).should.exist;
45
+ });
46
+
47
+ it('should open List', async () => {
48
+ const wrapper = await mountAndWaitForMenuContent({anchor: 'Anchor text'});
49
+
50
+ const list = wrapper.find(PopupMenu).instance().list;
51
+ list.should.exist;
52
+
53
+ //We need it to maintain compatibility between Dropdown Menu and List
54
+ list.props.data.length.should.equal(0);
55
+ });
56
+
57
+ it('should pass params to List', async () => {
58
+ const wrapper = await mountAndWaitForMenuContent({
59
+ anchor: 'Anchor text',
60
+ data: [{key: 'key1'}]
61
+ });
62
+
63
+ shallow(wrapper.find(PopupMenu).instance().list.renderItem({index: 1})).should.exist;
64
+ });
65
+
66
+ it('should add accessibility attributes to anchor', async () => {
67
+ const wrapper = await mountAndWaitForMenuContent({
68
+ anchor: 'Anchor text',
69
+ data: [{key: 'key1'}, {key: 'key2'}]
70
+ });
71
+
72
+ const anchorProps = wrapper.update().find(Anchor).props();
73
+ anchorProps['aria-owns'].should.equal('test-list-id');
74
+ anchorProps['aria-activedescendant'].should.contain(':key1');
75
+ });
76
+ });
@@ -13,8 +13,7 @@ import hubConfig from '../../.storybook/hub-config';
13
13
  import Link from '@jetbrains/ring-ui/components/link/link';
14
14
 
15
15
 
16
- import PopupMenu from '@jetbrains/ring-ui/components/popup-menu/popup-menu';
17
- import Dropdown from '@jetbrains/ring-ui/components/dropdown/dropdown';
16
+ import DropdownMenu from '@jetbrains/ring-ui/components/dropdown-menu/dropdown-menu';
18
17
  import showAuthDialog from '@jetbrains/ring-ui/components/auth-dialog-service/auth-dialog-service';
19
18
 
20
19
  import Theme from '@jetbrains/ring-ui/components/global/theme';
@@ -77,13 +76,13 @@ export const header = ({isCompact, ...args}) => {
77
76
  <TrayIcon title="Help" icon={helpIcon}/>
78
77
  <TrayIcon title="What's new" icon={giftIcon}/>
79
78
  <TrayIcon title="Search" icon={searchIcon}/>
80
- <Dropdown
81
- anchor={({active}) => (
82
- <TrayIcon title="Settings" active={active} icon={settingsIcon}/>
79
+ <DropdownMenu
80
+ data={[{label: 'Test'}, {label: 'Test2'}]}
81
+ anchor={({active, pinned, ...ariaProps}) => (
82
+ <TrayIcon title="Settings" active={active} icon={settingsIcon} {...ariaProps}/>
83
83
  )}
84
- >
85
- <PopupMenu top={-12} closeOnSelect data={[{label: 'Test'}, {label: 'Test2'}]}/>
86
- </Dropdown>
84
+ menuProps={{top: -12}}
85
+ />
87
86
  <SmartServices auth={auth}/>
88
87
  <SmartProfile auth={auth} hasUpdates LinkComponent={Comp}/>
89
88
  </Tray>
@@ -4,7 +4,7 @@ import classNames from 'classnames';
4
4
 
5
5
  import Avatar, {Size} from '../avatar/avatar';
6
6
  import Button from '../button/button';
7
- import Dropdown from '../dropdown/dropdown';
7
+ import DropdownMenu from '../dropdown-menu/dropdown-menu';
8
8
  import PopupMenu from '../popup-menu/popup-menu';
9
9
 
10
10
  import styles from './header.css';
@@ -162,21 +162,20 @@ export default class Profile extends PureComponent {
162
162
  ].filter(it => !!it);
163
163
 
164
164
  return (
165
- <Dropdown
165
+ <DropdownMenu
166
166
  {...props}
167
167
  title={user.name}
168
168
  anchor={anchor}
169
+ data={renderPopupItems(items)}
169
170
  data-test="ring-profile"
170
171
  className={classNames(styles.profile, className)}
171
- >
172
- <PopupMenu
173
- closeOnSelect={closeOnSelect}
174
- data={renderPopupItems(items)}
175
- left={-2}
176
- top={-8}
177
- sidePadding={32}
178
- />
179
- </Dropdown>
172
+ menuProps={{
173
+ closeOnSelect,
174
+ left: -2,
175
+ top: -8,
176
+ sidePadding: 32
177
+ }}
178
+ />
180
179
  );
181
180
  }
182
181
  }
@@ -33,6 +33,7 @@ export default class Pager extends PureComponent {
33
33
  className: PropTypes.string,
34
34
  translations: PropTypes.object,
35
35
  loader: PropTypes.bool,
36
+ loaderNavigation: PropTypes.bool,
36
37
  hrefFunc: PropTypes.func //function which generates href for all pager's buttons based on pager state passed as a function parameter, either this function or onPageChange should be provided
37
38
  };
38
39
 
@@ -53,6 +54,7 @@ export default class Pager extends PureComponent {
53
54
  previousPage: 'Previous'
54
55
  },
55
56
  loader: false,
57
+ loaderNavigation: false,
56
58
  onPageSizeChange: () => {},
57
59
  onLoadPage: () => {}
58
60
  };
@@ -109,7 +111,7 @@ export default class Pager extends PureComponent {
109
111
  href={this.generateHref(page)}
110
112
  key={key}
111
113
  active={active}
112
- disabled={this.props.loader && !active}
114
+ disabled={this.props.loader && !active && !this.props.loaderNavigation}
113
115
  loader={this.props.loader && active}
114
116
  {...this.getClickProps(this.handlePageChange(page))}
115
117
  >
@@ -187,7 +189,7 @@ export default class Pager extends PureComponent {
187
189
 
188
190
  return (
189
191
  <div className={style.links}>
190
- {prevLinkAvailable && !this.props.loader
192
+ {prevLinkAvailable && (!this.props.loader || this.props.loaderNavigation)
191
193
  ? (
192
194
  <Link
193
195
  href={prevLinkHref}
@@ -202,7 +204,7 @@ export default class Pager extends PureComponent {
202
204
  )
203
205
  }
204
206
 
205
- {nextLinkAvailable && !this.props.loader
207
+ {nextLinkAvailable && (!this.props.loader || this.props.loaderNavigation)
206
208
  ? (
207
209
  <Link
208
210
  href={nextLinkHref}
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@jetbrains/ring-ui",
3
- "version": "4.0.40",
3
+ "version": "4.0.44",
4
4
  "description": "JetBrains UI library",
5
5
  "author": "JetBrains",
6
6
  "license": "Apache-2.0",
@@ -68,7 +68,7 @@
68
68
  "@babel/cli": "^7.15.4",
69
69
  "@babel/eslint-parser": "^7.15.4",
70
70
  "@jetbrains/eslint-config": "^5.3.1",
71
- "@jetbrains/generator-ring-ui": "^4.0.32",
71
+ "@jetbrains/generator-ring-ui": "^4.0.33",
72
72
  "@jetbrains/stylelint-config": "^2.0.1",
73
73
  "@primer/octicons": "^15.1.0",
74
74
  "@storybook/addon-a11y": "6.3.8",
@@ -85,7 +85,7 @@
85
85
  "@storybook/manager-webpack5": "^6.3.8",
86
86
  "@storybook/source-loader": "6.3.8",
87
87
  "@storybook/theming": "6.3.8",
88
- "@testing-library/react": "^12.0.0",
88
+ "@testing-library/react": "^12.1.0",
89
89
  "@testing-library/user-event": "^13.2.1",
90
90
  "@wojtekmaj/enzyme-adapter-react-17": "^0.6.3",
91
91
  "angular": "^1.8.2",
@@ -112,7 +112,7 @@
112
112
  "husky": "^7.0.2",
113
113
  "identity-obj-proxy": "^3.0.0",
114
114
  "imports-loader": "^3.0.0",
115
- "jest": "~27.1.1",
115
+ "jest": "~27.2.0",
116
116
  "jest-teamcity": "^1.10.0",
117
117
  "karma": "^6.3.4",
118
118
  "karma-chrome-launcher": "3.1.0",
@@ -137,9 +137,9 @@
137
137
  "stylelint": "^13.13.1",
138
138
  "svg-inline-loader": "^0.8.2",
139
139
  "teamcity-service-messages": "^0.1.11",
140
- "terser-webpack-plugin": "^5.2.3",
140
+ "terser-webpack-plugin": "^5.2.4",
141
141
  "wallaby-webpack": "^3.9.16",
142
- "webpack": "^5.52.0",
142
+ "webpack": "^5.52.1",
143
143
  "webpack-cli": "^4.8.0",
144
144
  "xmlappend": "^1.0.4",
145
145
  "yo": "^4.3.0"
@@ -148,18 +148,18 @@
148
148
  "core-js": ">=3.0.0",
149
149
  "react": ">=16.8.0",
150
150
  "react-dom": ">=16.8.0",
151
- "webpack": "^5.52.0"
151
+ "webpack": "^5.52.1"
152
152
  },
153
153
  "dependencies": {
154
154
  "@babel/core": "^7.15.5",
155
155
  "@jetbrains/angular-elastic": "^2.5.1",
156
156
  "@jetbrains/babel-preset-jetbrains": "^2.3.1",
157
157
  "@jetbrains/icons": "^3.17.1",
158
- "@jetbrains/logos": "^1.4.23",
158
+ "@jetbrains/logos": "^1.4.24",
159
159
  "@jetbrains/postcss-require-hover": "^0.1.2",
160
160
  "@ungap/url-search-params": "^0.2.2",
161
161
  "babel-loader": "^8.2.2",
162
- "babel-plugin-transform-define": "^2.0.0",
162
+ "babel-plugin-transform-define": "^2.0.1",
163
163
  "browserslist": "^4.16.6",
164
164
  "change-case": "^4.1.1",
165
165
  "classnames": "^2.3.1",
@@ -207,5 +207,5 @@
207
207
  "node": ">=7.4",
208
208
  "npm": ">=6.0.0"
209
209
  },
210
- "gitHead": "b4464ac8063c70217a57f059aa1ae71c7c538073"
210
+ "gitHead": "00b6bd2545cdb03747a9db9517bd063a1d4033b3"
211
211
  }