@jetbrains/ring-ui 7.0.97 → 7.0.99

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.
@@ -46,8 +46,10 @@
46
46
  --ring-button-default-background-color: transparent;
47
47
  --ring-button-background-color: var(--ring-button-default-background-color);
48
48
  --ring-button-hover-background-color: var(--ring-content-background-color);
49
- --ring-button-pressed-background-color: var(--ring-selected-background-color);
49
+ --ring-button-pressed-background-color: var(--ring-hover-background-color);
50
50
  --ring-button-active-background-color: var(--ring-main-container-light-color);
51
+ --ring-button-active-hover-background-color: var(--ring-hover-background-color);
52
+ --ring-button-active-pressed-background-color: var(--ring-selected-background-color);
51
53
  --ring-button-disabled-background-color: var(--ring-button-default-background-color);
52
54
 
53
55
  box-sizing: border-box;
@@ -89,8 +91,8 @@
89
91
  --ring-button-default-background-color: var(--ring-content-background-color);
90
92
  --ring-button-default-border-color: var(--ring-borders-color);
91
93
  --ring-button-border-color: var(--ring-button-default-border-color);
92
- --ring-button-hover-border-color: var(--ring-border-hover-color);
93
- --ring-button-pressed-border-color: var(--ring-border-hover-color);
94
+ --ring-button-hover-border-color: var(--ring-border-accent-color);
95
+ --ring-button-pressed-border-color: var(--ring-border-accent-color);
94
96
  --ring-button-active-border-color: var(--ring-main-color);
95
97
  --ring-button-disabled-border-color: var(--ring-border-disabled-color);
96
98
  --ring-button-text-color: var(--ring-text-color);
@@ -174,7 +176,7 @@
174
176
  }
175
177
 
176
178
  .active {
177
- --ring-button-disabled-background-color: var(--ring-hover-background-color);
179
+ --ring-button-disabled-background-color: var(--ring-main-container-light-color);
178
180
  --ring-button-disabled-border-color: var(--ring-border-hover-color);
179
181
 
180
182
  transition: none;
@@ -185,6 +187,14 @@
185
187
  --ring-button-border-color: var(--ring-button-active-border-color);
186
188
  }
187
189
 
190
+ .active:hover {
191
+ --ring-button-active-background-color: var(--ring-button-active-hover-background-color);
192
+ }
193
+
194
+ .active:active {
195
+ --ring-button-active-background-color: var(--ring-button-active-pressed-background-color);
196
+ }
197
+
188
198
  .disabled {
189
199
  cursor: auto;
190
200
 
@@ -196,6 +206,8 @@
196
206
  .danger {
197
207
  --ring-button-pressed-background-color: var(--ring-button-danger-active-color);
198
208
  --ring-button-active-background-color: var(--ring-button-danger-active-color);
209
+ --ring-button-active-hover-background-color: var(--ring-button-danger-active-color);
210
+ --ring-button-active-pressed-background-color: var(--ring-button-danger-active-color);
199
211
  --ring-button-focus-border-color: var(--ring-removed-background-color);
200
212
  --ring-button-hover-border-color: var(--ring-button-danger-hover-color);
201
213
  --ring-button-pressed-border-color: var(--ring-button-danger-hover-color);
@@ -224,6 +236,8 @@
224
236
  --ring-button-hover-background-color: var(--ring-main-hover-color);
225
237
  --ring-button-pressed-background-color: var(--ring-button-primary-background-color);
226
238
  --ring-button-active-background-color: var(--ring-button-primary-background-color);
239
+ --ring-button-active-hover-background-color: var(--ring-main-hover-color);
240
+ --ring-button-active-pressed-background-color: var(--ring-button-primary-background-color);
227
241
  --ring-button-disabled-background-color: var(--ring-border-hover-color);
228
242
  --ring-button-pressed-border-color: var(--ring-button-primary-border-color);
229
243
  --ring-button-active-border-color: var(--ring-button-primary-border-color);
@@ -237,6 +251,8 @@
237
251
  --ring-button-hover-background-color: var(--ring-main-success-hover-color);
238
252
  --ring-button-pressed-background-color: var(--ring-main-success-hover-color);
239
253
  --ring-button-active-background-color: var(--ring-main-success-hover-color);
254
+ --ring-button-active-hover-background-color: var(--ring-main-success-hover-color);
255
+ --ring-button-active-pressed-background-color: var(--ring-main-success-hover-color);
240
256
  --ring-button-disabled-background-color: var(--ring-added-background-color);
241
257
  --ring-button-focus-border-color: var(--ring-border-hover-success-color);
242
258
  --ring-button-pressed-border-color: var(--ring-success-color);
@@ -252,6 +268,8 @@
252
268
  --ring-button-hover-background-color: var(--ring-main-error-hover-color);
253
269
  --ring-button-pressed-background-color: var(--ring-main-error-hover-color);
254
270
  --ring-button-active-background-color: var(--ring-main-error-hover-color);
271
+ --ring-button-active-hover-background-color: var(--ring-main-error-hover-color);
272
+ --ring-button-active-pressed-background-color: var(--ring-main-error-hover-color);
255
273
  --ring-button-disabled-background-color: var(--ring-removed-background-color);
256
274
  --ring-button-focus-border-color: var(--ring-border-hover-error-color);
257
275
  --ring-button-pressed-border-color: var(--ring-error-color);
@@ -119,7 +119,7 @@
119
119
  .buttonGroup .button.button:hover:not(:disabled),
120
120
  .buttonGroup .button.button:active:not(:disabled) {
121
121
  border-radius: var(--ring-border-radius);
122
- box-shadow: var(--ring-button-shadow) var(--ring-border-hover-color);
122
+ box-shadow: var(--ring-button-shadow) var(--ring-button-border-color);
123
123
  }
124
124
 
125
125
  .buttonGroup .button.button:focus-visible {
@@ -131,13 +131,13 @@
131
131
 
132
132
  .buttonGroup .button.button.active {
133
133
  border-radius: var(--ring-border-radius);
134
- box-shadow: var(--ring-button-shadow) var(--ring-main-color);
134
+ box-shadow: var(--ring-button-shadow) var(--ring-button-border-color);
135
135
  }
136
136
 
137
137
  .buttonGroup .button:focus-visible.active {
138
138
  border-radius: var(--ring-border-radius);
139
139
  box-shadow:
140
- var(--ring-button-shadow) var(--ring-main-color),
140
+ var(--ring-button-shadow) var(--ring-button-border-color),
141
141
  0 0 0 1px var(--ring-border-hover-color);
142
142
  }
143
143
 
@@ -150,6 +150,7 @@ export default class List<T = unknown> extends Component<ListProps<T>, ListState
150
150
  getSelected(): ListDataItem<T> | null;
151
151
  defaultItemHeight(): number;
152
152
  scrollEndHandler: () => void;
153
+ scrollToActive: () => void;
153
154
  checkOverflow: () => void;
154
155
  getVisibleListHeight(maxHeight: number): number;
155
156
  private _deprecatedGenerateKeyFromContent;
@@ -119,6 +119,9 @@ export default class List extends Component {
119
119
  shouldActivateFirstItem(this.props)) {
120
120
  this.activateFirst();
121
121
  }
122
+ if (!this.props.renderOptimization) {
123
+ this.scrollToActive();
124
+ }
122
125
  }
123
126
  shouldComponentUpdate(nextProps, nextState) {
124
127
  return (Object.keys(nextProps).some(key => !Object.is(nextProps[key], this.props[key])) ||
@@ -129,18 +132,8 @@ export default class List extends Component {
129
132
  this.virtualizedList.recomputeRowHeights();
130
133
  }
131
134
  const { activeIndex } = this.state;
132
- if (!this.props.disableScrollToActive && activeIndex != null && activeIndex !== prevState.activeIndex) {
133
- if (this.virtualizedList) {
134
- this.virtualizedList.scrollToRow(activeIndex + 1);
135
- }
136
- else {
137
- const itemId = this.getId(this.props.data[activeIndex]);
138
- if (itemId) {
139
- document.getElementById(itemId)?.scrollIntoView?.({
140
- block: 'center',
141
- });
142
- }
143
- }
135
+ if (activeIndex != null && activeIndex !== prevState.activeIndex) {
136
+ this.scrollToActive();
144
137
  }
145
138
  const isActiveItemRetainedPosition = activeIndex != null ? prevProps.data[activeIndex]?.key === this.props.data[activeIndex]?.key : false;
146
139
  if ((this.props.activeIndex === null || this.props.activeIndex === undefined) &&
@@ -338,6 +331,21 @@ export default class List extends Component {
338
331
  }
339
332
  }
340
333
  });
334
+ scrollToActive = () => {
335
+ const { activeIndex } = this.state;
336
+ if (this.props.disableScrollToActive || activeIndex == null) {
337
+ return;
338
+ }
339
+ if (this.virtualizedList) {
340
+ this.virtualizedList.scrollToRow(activeIndex + 1);
341
+ }
342
+ else {
343
+ const itemId = this.getId(this.props.data[activeIndex]);
344
+ if (itemId) {
345
+ document.getElementById(itemId)?.scrollIntoView?.({ block: 'center' });
346
+ }
347
+ }
348
+ };
341
349
  checkOverflow = () => {
342
350
  if (this.inner) {
343
351
  this.setState({
@@ -449,7 +457,11 @@ export default class List extends Component {
449
457
  return props;
450
458
  };
451
459
  virtualizedListRef = (el) => {
460
+ const isFirstAssignment = el != null && this.virtualizedList == null;
452
461
  this.virtualizedList = el;
462
+ if (isFirstAssignment) {
463
+ this.scrollToActive();
464
+ }
453
465
  };
454
466
  containerRef = (el) => {
455
467
  this.container = el;
@@ -157,7 +157,7 @@ interface CaretPositionParams {
157
157
  forceSetCaret?: boolean | null | undefined;
158
158
  }
159
159
  interface HistoryEntry {
160
- query: string | null | undefined;
160
+ normalizedQuery: string;
161
161
  caret: Position | number;
162
162
  }
163
163
  /**
@@ -218,7 +218,8 @@ export default class QueryAssist extends Component<QueryAssistProps> {
218
218
  immediateState: QueryAssistChange;
219
219
  requestData?: (afterCompletion?: boolean) => void;
220
220
  ngModelStateField: string;
221
- historyStack: HistoryEntry[];
221
+ undoHistoryStack: HistoryEntry[];
222
+ redoHistoryStack: HistoryEntry[];
222
223
  mouseIsDownOnPopup?: boolean;
223
224
  handleFocusChange: (e: SyntheticEvent) => void;
224
225
  node?: HTMLElement | null;
@@ -233,9 +234,11 @@ export default class QueryAssist extends Component<QueryAssistProps> {
233
234
  handleInput: (e: Event | SyntheticEvent) => void;
234
235
  handleEnter: (e: React.KeyboardEvent) => void;
235
236
  handleTab: (e: Event) => boolean | void;
236
- setState: (state: Partial<QueryAssistState>, resolve?: () => void) => void;
237
+ setState: (state: Partial<QueryAssistState>, resolve?: () => void, undoOrRedo?: boolean) => void;
237
238
  private _pushHistory;
238
239
  undo: (e: Event) => void;
240
+ redo: (e: Event) => void;
241
+ private _undoOrRedo;
239
242
  handlePaste: (e: React.ClipboardEvent) => void;
240
243
  handleCaretMove: (e: Event | SyntheticEvent) => void;
241
244
  handleStyleRangesResponse: ({ suggestions, ...restProps }: QueryAssistResponse) => Promise<void>;
@@ -118,7 +118,7 @@ export default class QueryAssist extends Component {
118
118
  this.requestStyleRanges().catch(noop);
119
119
  }
120
120
  this.setCaretPosition();
121
- this._pushHistory(this.state);
121
+ this._pushHistory(this.state.query);
122
122
  }
123
123
  shouldComponentUpdate(props, state) {
124
124
  return (state.query !== this.state.query ||
@@ -163,8 +163,8 @@ export default class QueryAssist extends Component {
163
163
  immediateState;
164
164
  requestData;
165
165
  ngModelStateField = ngModelStateField;
166
- // An array of {query: string; caret: number}[]
167
- historyStack = [];
166
+ undoHistoryStack = [];
167
+ redoHistoryStack = [];
168
168
  mouseIsDownOnPopup;
169
169
  handleFocusChange = (e) => {
170
170
  // otherwise it's blur and false
@@ -290,6 +290,9 @@ export default class QueryAssist extends Component {
290
290
  if (this.props.autoOpen === 'force' || props.query.length > 0) {
291
291
  this.requestData?.();
292
292
  }
293
+ else {
294
+ this.handleResponse({ caret: props.caret });
295
+ }
293
296
  };
294
297
  // It's necessary to prevent new element creation before any other hooks
295
298
  handleEnter = (e) => {
@@ -313,31 +316,45 @@ export default class QueryAssist extends Component {
313
316
  }
314
317
  return true;
315
318
  };
316
- setState = (state, resolve) => {
319
+ setState = (state, resolve, undoOrRedo = false) => {
317
320
  super.setState(state, () => {
318
- this._pushHistory(state);
321
+ if (!undoOrRedo && 'query' in state) {
322
+ this._pushHistory(state.query);
323
+ }
319
324
  resolve?.();
320
325
  });
321
326
  };
322
- _pushHistory(state) {
323
- const queryIsSet = 'query' in state;
324
- const queryIsSame = this.historyStack[0]?.query === state.query;
325
- if (queryIsSet && !queryIsSame) {
326
- this.historyStack.unshift({
327
- query: state.query,
327
+ _pushHistory(query) {
328
+ const normalizedQuery = query ?? '';
329
+ if (!this.undoHistoryStack.length || this.undoHistoryStack[0].normalizedQuery !== normalizedQuery) {
330
+ this.undoHistoryStack.unshift({
331
+ normalizedQuery,
328
332
  caret: this.caret?.getPosition({ avoidFocus: true }) ?? -1,
329
333
  });
334
+ this.redoHistoryStack = [];
330
335
  }
331
336
  }
332
337
  undo = (e) => {
333
- const previous = this.historyStack.splice(0, 2)[1];
334
- if (!previous) {
338
+ this._undoOrRedo(e, false);
339
+ };
340
+ redo = (e) => {
341
+ this._undoOrRedo(e, true);
342
+ };
343
+ _undoOrRedo = (e, redo) => {
344
+ const stack = redo ? this.redoHistoryStack : this.undoHistoryStack;
345
+ const [current, previous] = stack;
346
+ const stateToApply = redo ? current : previous;
347
+ if (!stateToApply) {
335
348
  return;
336
349
  }
337
- this.setState({ query: previous.query }, () => {
338
- this.caret?.setPosition(previous.caret);
350
+ stack.shift();
351
+ e.preventDefault?.();
352
+ this.setState({ query: stateToApply.normalizedQuery }, () => {
353
+ const oppositeStack = redo ? this.undoHistoryStack : this.redoHistoryStack;
354
+ oppositeStack.unshift(current);
355
+ this.caret?.setPosition(stateToApply.caret);
339
356
  this.handleInput(e);
340
- });
357
+ }, true);
341
358
  };
342
359
  handlePaste = (e) => {
343
360
  const INSERT_COMMAND = 'insertText';
@@ -368,7 +385,7 @@ export default class QueryAssist extends Component {
368
385
  }
369
386
  };
370
387
  handleStyleRangesResponse = ({ suggestions, ...restProps }) => this.handleResponse(restProps);
371
- handleResponse = ({ query = '', caret = 0, styleRanges, suggestions = [] }, afterCompletion = false) => new Promise((resolve, reject) => {
388
+ handleResponse = ({ query = '', caret = 0, styleRanges = [], suggestions = [] }, afterCompletion = false) => new Promise((resolve, reject) => {
372
389
  if (query === this.getQuery() &&
373
390
  (caret === this.immediateState.caret || this.immediateState.caret === undefined)) {
374
391
  // Do not setState on unmounted component
@@ -665,6 +682,7 @@ export default class QueryAssist extends Component {
665
682
  'ctrl+space': this.handleCtrlSpace,
666
683
  tab: this.handleTab,
667
684
  'meta+z': this.undo,
685
+ 'meta+shift+z': this.redo,
668
686
  right: noop,
669
687
  left: noop,
670
688
  space: noop,
@@ -13,6 +13,7 @@ export interface TooltipProps extends Omit<AllHTMLAttributes<HTMLSpanElement>, '
13
13
  selfOverflowOnly?: boolean | null | undefined;
14
14
  popupProps?: Partial<PopupAttrs> | null | undefined;
15
15
  title?: ReactNode | null | undefined;
16
+ hide?: boolean | null | undefined;
16
17
  theme?: Theme | 'inherit';
17
18
  'data-test'?: string | null | undefined;
18
19
  long?: boolean | null | undefined;
@@ -21,6 +22,7 @@ export interface TooltipProps extends Omit<AllHTMLAttributes<HTMLSpanElement>, '
21
22
  * @name Tooltip
22
23
  */
23
24
  export default class Tooltip extends Component<TooltipProps> {
25
+ private static isShow;
24
26
  static defaultProps: {
25
27
  title: string;
26
28
  selfOverflowOnly: boolean;
@@ -13,6 +13,9 @@ const TooltipContext = createContext(undefined);
13
13
  * @name Tooltip
14
14
  */
15
15
  export default class Tooltip extends Component {
16
+ static isShow({ title, hide }) {
17
+ return !!title && !hide;
18
+ }
16
19
  static defaultProps = {
17
20
  title: '',
18
21
  selfOverflowOnly: false,
@@ -24,15 +27,17 @@ export default class Tooltip extends Component {
24
27
  showNestedPopup: false,
25
28
  };
26
29
  componentDidMount() {
27
- if (this.props.title) {
30
+ if (Tooltip.isShow(this.props)) {
28
31
  this.addListeners();
29
32
  }
30
33
  }
31
34
  componentDidUpdate(prevProps) {
32
- if (!prevProps.title && this.props.title) {
35
+ const prevShow = Tooltip.isShow(prevProps);
36
+ const currShow = Tooltip.isShow(this.props);
37
+ if (!prevShow && currShow) {
33
38
  this.addListeners();
34
39
  }
35
- else if (prevProps.title && !this.props.title) {
40
+ else if (prevShow && !currShow) {
36
41
  this.hidePopup();
37
42
  this.listeners.removeAll();
38
43
  }
@@ -50,10 +55,9 @@ export default class Tooltip extends Component {
50
55
  this.containerNode = el;
51
56
  };
52
57
  tryToShowPopup = () => {
53
- const { delay, title } = this.props;
54
- if (!title) {
58
+ if (!Tooltip.isShow(this.props))
55
59
  return;
56
- }
60
+ const { delay } = this.props;
57
61
  if (delay) {
58
62
  clearTimeout(this.timeout);
59
63
  this.timeout = window.setTimeout(this.showPopup, delay);
@@ -125,8 +129,8 @@ export default class Tooltip extends Component {
125
129
  this.setState({ showNestedPopup: false });
126
130
  };
127
131
  render() {
128
- const { children, 'data-test': dataTest, title, delay, theme, selfOverflowOnly, popupProps, long, ...restProps } = this.props;
129
- const ariaProps = typeof title === 'string' && !!title ? { 'aria-label': title, role: 'tooltip' } : {};
132
+ const { children, 'data-test': dataTest, title, delay, theme, selfOverflowOnly, popupProps, long, hide, ...restProps } = this.props;
133
+ const ariaProps = typeof title === 'string' && Tooltip.isShow({ title, hide }) ? { 'aria-label': title, role: 'tooltip' } : {};
130
134
  const { onNestedTooltipShow, onNestedTooltipHide } = this;
131
135
  const popup = (<Popup trapFocus={false} anchorElement={this.containerNode} hidden={!this.state.showPopup || this.state.showNestedPopup} onCloseAttempt={this.hidePopup} maxHeight={400} attached={false} onMouseOut={this.hideIfMovedOutsidePopup} top={4} dontCloseOnAnchorClick ref={this.popupRef} {...popupProps} className={classNames(styles.tooltip, { [styles.long]: long, [styles.inheritedTheme]: theme === 'inherit' }, popupProps?.className)}>
132
136
  {title}
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@jetbrains/ring-ui",
3
- "version": "7.0.97",
3
+ "version": "7.0.99",
4
4
  "description": "JetBrains UI library",
5
5
  "author": {
6
6
  "name": "JetBrains"
@@ -117,11 +117,11 @@
117
117
  "@rollup/plugin-json": "^6.1.0",
118
118
  "@rollup/plugin-node-resolve": "^16.0.3",
119
119
  "@rollup/plugin-replace": "^6.0.3",
120
- "@storybook/addon-a11y": "10.2.13",
121
- "@storybook/addon-docs": "^10.2.13",
122
- "@storybook/addon-themes": "^10.2.13",
120
+ "@storybook/addon-a11y": "10.2.14",
121
+ "@storybook/addon-docs": "^10.2.14",
122
+ "@storybook/addon-themes": "^10.2.14",
123
123
  "@storybook/csf": "^0.1.13",
124
- "@storybook/react-webpack5": "10.2.13",
124
+ "@storybook/react-webpack5": "10.2.14",
125
125
  "@storybook/test-runner": "^0.24.2",
126
126
  "@testing-library/dom": "^10.4.1",
127
127
  "@testing-library/react": "^16.3.2",
@@ -145,7 +145,7 @@
145
145
  "dotenv-cli": "^11.0.0",
146
146
  "eslint": "^9.39.2",
147
147
  "eslint-config-prettier": "^10.1.8",
148
- "eslint-formatter-jslint-xml": "^8.40.0",
148
+ "eslint-formatter-jslint-xml": "^9.0.1",
149
149
  "eslint-import-resolver-exports": "^1.0.0-beta.5",
150
150
  "eslint-import-resolver-typescript": "^4.4.4",
151
151
  "eslint-import-resolver-webpack": "^0.13.10",
@@ -154,11 +154,11 @@
154
154
  "eslint-plugin-prettier": "^5.5.5",
155
155
  "eslint-plugin-react": "^7.37.5",
156
156
  "eslint-plugin-react-hooks": "^7.0.1",
157
- "eslint-plugin-storybook": "^10.2.13",
157
+ "eslint-plugin-storybook": "^10.2.14",
158
158
  "eslint-plugin-unicorn": "^63.0.0",
159
159
  "events": "^3.3.0",
160
160
  "glob": "^13.0.6",
161
- "globals": "^17.3.0",
161
+ "globals": "^17.4.0",
162
162
  "html-webpack-plugin": "^5.6.6",
163
163
  "http-server": "^14.1.1",
164
164
  "husky": "^9.1.7",
@@ -166,7 +166,7 @@
166
166
  "jest": "~30.2.0",
167
167
  "jest-environment-jsdom": "^30.2.0",
168
168
  "jest-teamcity": "^1.12.0",
169
- "lint-staged": "^16.2.7",
169
+ "lint-staged": "^16.3.1",
170
170
  "markdown-it": "^14.1.1",
171
171
  "merge-options": "^3.0.4",
172
172
  "pinst": "^3.0.0",
@@ -179,7 +179,7 @@
179
179
  "rollup": "^4.59.0",
180
180
  "rollup-plugin-clear": "^2.0.7",
181
181
  "storage-mock": "^2.1.0",
182
- "storybook": "10.2.13",
182
+ "storybook": "10.2.14",
183
183
  "stylelint": "^17.4.0",
184
184
  "stylelint-config-sass-guidelines": "^13.0.0",
185
185
  "svg-inline-loader": "^0.8.2",
@@ -217,7 +217,7 @@
217
217
  "@babel/core": "^7.29.0",
218
218
  "@babel/preset-typescript": "^7.28.5",
219
219
  "@jetbrains/babel-preset-jetbrains": "^2.4.0",
220
- "@jetbrains/icons": "^5.16.0",
220
+ "@jetbrains/icons": "^5.17.0",
221
221
  "@jetbrains/postcss-require-hover": "^0.2.0",
222
222
  "@types/combokeys": "^2.4.9",
223
223
  "@types/element-resize-detector": "^1.1.6",