@jetbrains/ring-ui 7.0.102 → 7.0.104

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.
@@ -11,6 +11,8 @@
11
11
  --ring-button-loader-components: var(--ring-main-components);
12
12
  --ring-button-white-text-disabled-color: var(--ring-white-text-color);
13
13
  --ring-button-icon-line-height: calc(var(--ring-unit) * 2);
14
+ --ring-button-border-radius-left: var(--ring-border-radius);
15
+ --ring-button-border-radius-right: var(--ring-border-radius);
14
16
  }
15
17
 
16
18
  :global(.ring-ui-theme-dark) {
@@ -66,7 +68,8 @@
66
68
  color: var(--ring-button-text-color);
67
69
 
68
70
  border: 0;
69
- border-radius: var(--ring-border-radius);
71
+ border-radius: var(--ring-button-border-radius-left) var(--ring-button-border-radius-right)
72
+ var(--ring-button-border-radius-right) var(--ring-button-border-radius-left);
70
73
  outline: 0;
71
74
 
72
75
  background-color: var(--ring-button-background-color);
@@ -386,7 +389,10 @@
386
389
 
387
390
  overflow: hidden;
388
391
 
389
- border-radius: calc(var(--ring-border-radius) - 1px);
392
+ border-top-left-radius: max(0px, calc(var(--ring-button-border-radius-left) - 1px));
393
+ border-top-right-radius: max(0px, calc(var(--ring-button-border-radius-right) - 1px));
394
+ border-bottom-right-radius: max(0px, calc(var(--ring-button-border-radius-right) - 1px));
395
+ border-bottom-left-radius: max(0px, calc(var(--ring-button-border-radius-left) - 1px));
390
396
  background-color: var(--ring-button-default-background-color);
391
397
 
392
398
  &::before {
@@ -414,7 +420,10 @@
414
420
  bottom: 0;
415
421
  left: 0;
416
422
 
417
- border-radius: var(--ring-border-radius);
423
+ border-top-left-radius: var(--ring-button-border-radius-left);
424
+ border-top-right-radius: var(--ring-button-border-radius-right);
425
+ border-bottom-right-radius: var(--ring-button-border-radius-right);
426
+ border-bottom-left-radius: var(--ring-button-border-radius-left);
418
427
  }
419
428
 
420
429
  .delayed::after {
@@ -118,24 +118,32 @@
118
118
  /* stylelint-disable selector-max-specificity */
119
119
  .buttonGroup .button.button:hover:not(:disabled),
120
120
  .buttonGroup .button.button:active:not(:disabled) {
121
- border-radius: var(--ring-border-radius);
121
+ --ring-button-border-radius-left: var(--ring-border-radius);
122
+ --ring-button-border-radius-right: var(--ring-border-radius);
123
+
122
124
  box-shadow: var(--ring-button-shadow) var(--ring-button-border-color);
123
125
  }
124
126
 
125
127
  .buttonGroup .button.button:focus-visible {
126
- border-radius: var(--ring-border-radius);
128
+ --ring-button-border-radius-left: var(--ring-border-radius);
129
+ --ring-button-border-radius-right: var(--ring-border-radius);
130
+
127
131
  box-shadow:
128
132
  var(--ring-button-shadow) var(--ring-border-hover-color),
129
133
  0 0 0 1px var(--ring-border-hover-color);
130
134
  }
131
135
 
132
136
  .buttonGroup .button.button.active {
133
- border-radius: var(--ring-border-radius);
137
+ --ring-button-border-radius-left: var(--ring-border-radius);
138
+ --ring-button-border-radius-right: var(--ring-border-radius);
139
+
134
140
  box-shadow: var(--ring-button-shadow) var(--ring-button-border-color);
135
141
  }
136
142
 
137
143
  .buttonGroup .button:focus-visible.active {
138
- border-radius: var(--ring-border-radius);
144
+ --ring-button-border-radius-left: var(--ring-border-radius);
145
+ --ring-button-border-radius-right: var(--ring-border-radius);
146
+
139
147
  box-shadow:
140
148
  var(--ring-button-shadow) var(--ring-button-border-color),
141
149
  0 0 0 1px var(--ring-border-hover-color);
@@ -151,11 +159,15 @@
151
159
  composes: buttonGroup from '../button-toolbar/button-toolbar.css';
152
160
  }
153
161
 
154
- .common button,
155
- .common .button {
162
+ .common button {
156
163
  border-radius: 0;
157
164
  }
158
165
 
166
+ .common .button {
167
+ --ring-button-border-radius-left: 0;
168
+ --ring-button-border-radius-right: 0;
169
+ }
170
+
159
171
  .split button,
160
172
  .split .button {
161
173
  margin: 0 0 0 -1px;
@@ -173,39 +185,29 @@
173
185
  }
174
186
  }
175
187
 
176
- .common > button:first-child,
177
- .common > .button:first-child,
178
- .common > :first-child .button {
188
+ .common > button:first-child {
179
189
  margin: 0;
180
190
 
181
191
  border-top-left-radius: var(--ring-border-radius);
182
192
  border-bottom-left-radius: var(--ring-border-radius);
183
193
  }
184
194
 
185
- /* stylelint-disable selector-max-specificity */
186
- .common > button:first-child > div:first-child,
187
- .common > .button:first-child > div:first-child,
188
- .common > :first-child .button > div:first-child {
189
- border-top-right-radius: 0;
190
- border-bottom-right-radius: 0;
195
+ .common > .button:first-child,
196
+ .common > :first-child .button {
197
+ --ring-button-border-radius-left: var(--ring-border-radius);
198
+
199
+ margin: 0;
191
200
  }
192
- /* stylelint-enable */
193
201
 
194
- .common > .button:last-child,
195
- .common > button:last-child,
196
- .common > :last-child .button {
202
+ .common > button:last-child {
197
203
  border-top-right-radius: var(--ring-border-radius);
198
204
  border-bottom-right-radius: var(--ring-border-radius);
199
205
  }
200
206
 
201
- /* stylelint-disable selector-max-specificity */
202
- .common > .button:last-child > div:first-child,
203
- .common > button:last-child > div:first-child,
204
- .common > :last-child .button > div:first-child {
205
- border-top-left-radius: 0;
206
- border-bottom-left-radius: 0;
207
+ .common > .button:last-child,
208
+ .common > :last-child .button {
209
+ --ring-button-border-radius-right: var(--ring-border-radius);
207
210
  }
208
- /* stylelint-enable */
209
211
 
210
212
  .split .flat:not(:last-child) {
211
213
  margin-right: 1px;
@@ -58,7 +58,6 @@ export default class Profile extends PureComponent {
58
58
  {
59
59
  rgItemType: PopupMenu.ListProps.Type.LINK,
60
60
  label: translations?.profile ?? translate('profile'),
61
- target: '_self', // Full page reload in Angular
62
61
  href: profileUrl,
63
62
  LinkComponent,
64
63
  },
@@ -43,6 +43,9 @@ export interface ListProps<T = unknown> {
43
43
  maxHeight?: number | null | undefined;
44
44
  activeIndex?: number | null | undefined;
45
45
  useMouseUp?: boolean | null | undefined;
46
+ /**
47
+ * @deprecated No longer used. Visibility is detected automatically via IntersectionObserver. Will be removed in Ring UI 8.0.
48
+ */
46
49
  visible?: boolean | null | undefined;
47
50
  disableMoveOverflow?: boolean | null | undefined;
48
51
  compact?: boolean | null | undefined;
@@ -130,6 +133,8 @@ export default class List<T = unknown> extends Component<ListProps<T>, ListState
130
133
  virtualizedList?: VirtualizedList | null;
131
134
  unmounted?: boolean;
132
135
  container?: HTMLElement | null;
136
+ private intersectionObserver?;
137
+ private wasVisible;
133
138
  private _bufferSize;
134
139
  sizeCacheKey: (index: number) => string | Type.ITEM | Type.MARGIN;
135
140
  private _cache;
@@ -122,6 +122,17 @@ export default class List extends Component {
122
122
  if (!this.props.renderOptimization) {
123
123
  this.scrollToActive();
124
124
  }
125
+ if (this.props.renderOptimization && this.container && typeof IntersectionObserver !== 'undefined') {
126
+ this.intersectionObserver = new IntersectionObserver(entries => {
127
+ for (const entry of entries) {
128
+ if (entry.isIntersecting && !this.wasVisible && this.virtualizedList) {
129
+ this.virtualizedList.recomputeRowHeights();
130
+ }
131
+ this.wasVisible = entry.isIntersecting;
132
+ }
133
+ });
134
+ this.intersectionObserver.observe(this.container);
135
+ }
125
136
  }
126
137
  shouldComponentUpdate(nextProps, nextState) {
127
138
  return (Object.keys(nextProps).some(key => !Object.is(nextProps[key], this.props[key])) ||
@@ -145,6 +156,7 @@ export default class List extends Component {
145
156
  this.checkOverflow();
146
157
  }
147
158
  componentWillUnmount() {
159
+ this.intersectionObserver?.disconnect();
148
160
  this.unmounted = true;
149
161
  }
150
162
  scheduleScrollListener = scheduleRAF();
@@ -157,6 +169,8 @@ export default class List extends Component {
157
169
  virtualizedList;
158
170
  unmounted;
159
171
  container;
172
+ intersectionObserver;
173
+ wasVisible = false;
160
174
  // eslint-disable-next-line no-magic-numbers
161
175
  _bufferSize = 10; // keep X items above and below of the visible area
162
176
  // reuse size cache for similar items
@@ -9,7 +9,7 @@ const TabTrap = forwardRef(function TabTrap({ children, trapDisabled = false, au
9
9
  const trapButtonNodeRef = useRef(null);
10
10
  const previousFocusedNodeRef = useRef(null);
11
11
  const trapWithoutFocusRef = useRef(false);
12
- const mountedRef = useRef(false);
12
+ const mountedRef = useRef(undefined);
13
13
  // It's the same approach as in focus-trap-react:
14
14
  // https://github.com/focus-trap/focus-trap-react/commit/3b22fca9eebeb883edc89548850fe5a5b9d6d50e
15
15
  // We can't do it in useEffect because it's too late, some children might have already
@@ -18,16 +18,16 @@ const TabTrap = forwardRef(function TabTrap({ children, trapDisabled = false, au
18
18
  previousFocusedNodeRef.current = document.activeElement;
19
19
  }
20
20
  useImperativeHandle(ref, () => ({ node: nodeRef.current }), []);
21
- function restoreFocus() {
21
+ function restoreFocusIfUnmounted(orElse) {
22
22
  const previousFocusedNode = previousFocusedNodeRef.current;
23
23
  if (previousFocusedNode instanceof HTMLElement &&
24
24
  previousFocusedNode.focus &&
25
- isNodeInVisiblePartOfPage(previousFocusedNode)) {
26
- // This is to prevent the focus from being restored the first time
27
- // componentWillUnmount is called in StrictMode.
28
- if (!mountedRef.current) {
29
- previousFocusedNode.focus({ preventScroll: true });
30
- }
25
+ isNodeInVisiblePartOfPage(previousFocusedNode) &&
26
+ mountedRef.current === false) {
27
+ previousFocusedNode.focus({ preventScroll: true });
28
+ }
29
+ else {
30
+ orElse?.();
31
31
  }
32
32
  }
33
33
  function focusElement(first = true) {
@@ -65,7 +65,7 @@ const TabTrap = forwardRef(function TabTrap({ children, trapDisabled = false, au
65
65
  }
66
66
  return () => {
67
67
  if (focusBackOnClose) {
68
- restoreFocus();
68
+ restoreFocusIfUnmounted();
69
69
  }
70
70
  };
71
71
  }, [autoFocusFirst, trapDisabled, focusBackOnClose, focusFirst]);
@@ -76,7 +76,7 @@ const TabTrap = forwardRef(function TabTrap({ children, trapDisabled = false, au
76
76
  if (focusBackOnExit) {
77
77
  const prevFocused = event.nativeEvent.relatedTarget;
78
78
  if (prevFocused && nodeRef.current && prevFocused instanceof Element && nodeRef.current.contains(prevFocused)) {
79
- restoreFocus();
79
+ restoreFocusIfUnmounted(focusLast);
80
80
  }
81
81
  }
82
82
  else {
@@ -97,6 +97,14 @@ const TabTrap = forwardRef(function TabTrap({ children, trapDisabled = false, au
97
97
  }
98
98
  focusLast();
99
99
  }
100
+ function restoreFocusOrFocusFirst() {
101
+ if (focusBackOnExit) {
102
+ restoreFocusIfUnmounted(focusFirst);
103
+ }
104
+ else {
105
+ focusFirst();
106
+ }
107
+ }
100
108
  if (trapDisabled) {
101
109
  return (<div ref={nodeRef} {...restProps}>
102
110
  {children}
@@ -111,7 +119,7 @@ const TabTrap = forwardRef(function TabTrap({ children, trapDisabled = false, au
111
119
  <div
112
120
  // It never actually stays focused
113
121
  // eslint-disable-next-line jsx-a11y/no-noninteractive-tabindex
114
- tabIndex={0} onFocus={focusBackOnExit ? restoreFocus : focusFirst} data-trap-button/>
122
+ tabIndex={0} onFocus={restoreFocusOrFocusFirst} data-trap-button/>
115
123
  </div>);
116
124
  });
117
125
  export default TabTrap;
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@jetbrains/ring-ui",
3
- "version": "7.0.102",
3
+ "version": "7.0.104",
4
4
  "description": "JetBrains UI library",
5
5
  "author": {
6
6
  "name": "JetBrains"
@@ -191,7 +191,7 @@
191
191
  "vitest": "^4.0.18",
192
192
  "vitest-teamcity-reporter": "^0.4.1",
193
193
  "webpack": "^5.105.4",
194
- "webpack-cli": "^6.0.1",
194
+ "webpack-cli": "^7.0.0",
195
195
  "xmlappend": "^1.0.4"
196
196
  },
197
197
  "peerDependencies": {
@@ -243,7 +243,6 @@
243
243
  "memoize-one": "^6.0.0",
244
244
  "postcss": "^8.5.8",
245
245
  "postcss-calc": "^10.1.1",
246
- "postcss-flexbugs-fixes": "^5.0.2",
247
246
  "postcss-font-family-system-ui": "^5.0.0",
248
247
  "postcss-loader": "^8.2.1",
249
248
  "postcss-modules-values-replace": "^4.2.2",
package/postcss.config.js CHANGED
@@ -10,7 +10,6 @@ module.exports = () => {
10
10
  },
11
11
  }),
12
12
  require('postcss-font-family-system-ui')({browsers: ['last 2 versions']}),
13
- require('postcss-flexbugs-fixes')(),
14
13
  require('@jetbrains/postcss-require-hover')(),
15
14
  require('postcss-calc')({mediaQueries: true}),
16
15
  ];