@jetbrains/ring-ui-built 7.0.96 → 7.0.98

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.
@@ -424,7 +424,9 @@ class Auth {
424
424
  }
425
425
  await this._backendCheckPromise;
426
426
  } catch (e) {
427
- throw new Error('Cannot refresh token: backend is not available. Postponed by user.');
427
+ throw new Error('Cannot refresh token: backend is not available. Postponed by user.', {
428
+ cause: e
429
+ });
428
430
  } finally {
429
431
  this._backendCheckPromise = null;
430
432
  }
@@ -802,7 +804,7 @@ class Auth {
802
804
  const {
803
805
  scope: defaultScope
804
806
  } = this.config;
805
- let urlFromState = null;
807
+ let urlFromState;
806
808
  try {
807
809
  urlFromState = new URL(state); // checking if state contains valid URL on same origin, see HUB-11514
808
810
  } catch {
@@ -93,7 +93,7 @@ class Avatar extends PureComponent {
93
93
  };
94
94
  src = encodeURL(urlStart, queryParams);
95
95
  }
96
- let subavatarSrc = null;
96
+ let subavatarSrc;
97
97
  if (subavatar && !isDataURI(subavatar)) {
98
98
  const [urlStart, query] = subavatar.split('?');
99
99
  const queryParams = {
@@ -89,7 +89,7 @@ class ListItem extends PureComponent {
89
89
  const style = {
90
90
  paddingLeft: `${(Number(level) || 0) * RING_UNIT + DEFAULT_PADDING + (showCheckbox ? CHECKBOX_WIDTH : 0)}px`
91
91
  };
92
- let computedTitle = null;
92
+ let computedTitle;
93
93
  if (this._isString(title)) {
94
94
  // if title is specified and is a string then use it
95
95
  computedTitle = title;
@@ -68,7 +68,6 @@ export interface ListState<T = unknown> {
68
68
  prevActiveIndex: number | null;
69
69
  prevData: ListDataItem<T>[];
70
70
  activeItem: ListDataItem<T> | null;
71
- needScrollToActive: boolean;
72
71
  scrolling: boolean;
73
72
  hasOverflow: boolean;
74
73
  scrolledToBottom: boolean;
@@ -151,6 +150,7 @@ export default class List<T = unknown> extends Component<ListProps<T>, ListState
151
150
  getSelected(): ListDataItem<T> | null;
152
151
  defaultItemHeight(): number;
153
152
  scrollEndHandler: () => void;
153
+ scrollToActive: () => void;
154
154
  checkOverflow: () => void;
155
155
  getVisibleListHeight(maxHeight: number): number;
156
156
  private _deprecatedGenerateKeyFromContent;
@@ -98,7 +98,6 @@ class List extends Component {
98
98
  prevActiveIndex: null,
99
99
  prevData: [],
100
100
  activeItem: null,
101
- needScrollToActive: false,
102
101
  scrolling: false,
103
102
  hasOverflow: false,
104
103
  scrolledToBottom: false
@@ -132,8 +131,7 @@ class List extends Component {
132
131
  if (activeIndex !== null && activeIndex !== undefined && activeIndex !== prevActiveIndex && data[activeIndex]) {
133
132
  Object.assign(nextState, {
134
133
  activeIndex,
135
- activeItem: data[activeIndex],
136
- needScrollToActive: true
134
+ activeItem: data[activeIndex]
137
135
  });
138
136
  } else if (data !== prevData && restoreActiveIndex && activeItem && activeItem.key) {
139
137
  // Restore active index if there is an item with the same "key" property
@@ -151,6 +149,9 @@ class List extends Component {
151
149
  if ((this.props.activeIndex === null || this.props.activeIndex === undefined) && shouldActivateFirstItem(this.props)) {
152
150
  this.activateFirst();
153
151
  }
152
+ if (!this.props.renderOptimization) {
153
+ this.scrollToActive();
154
+ }
154
155
  }
155
156
  shouldComponentUpdate(nextProps, nextState) {
156
157
  return Object.keys(nextProps).some(key => !Object.is(nextProps[key], this.props[key])) || Object.keys(nextState).some(key => nextState[key] !== this.state[key]);
@@ -162,18 +163,10 @@ class List extends Component {
162
163
  const {
163
164
  activeIndex
164
165
  } = this.state;
165
- if (!this.virtualizedList && !this.props.disableScrollToActive && this.state.needScrollToActive && activeIndex != null && activeIndex !== prevState.activeIndex) {
166
- const itemId = this.getId(this.props.data[activeIndex]);
167
- if (itemId) {
168
- document.getElementById(itemId)?.scrollIntoView?.({
169
- block: 'center'
170
- });
171
- }
172
- this.setState({
173
- needScrollToActive: false
174
- });
166
+ if (activeIndex != null && activeIndex !== prevState.activeIndex) {
167
+ this.scrollToActive();
175
168
  }
176
- const isActiveItemRetainedPosition = activeIndex ? prevProps.data[activeIndex]?.key === this.props.data[activeIndex]?.key : false;
169
+ const isActiveItemRetainedPosition = activeIndex != null ? prevProps.data[activeIndex]?.key === this.props.data[activeIndex]?.key : false;
177
170
  if ((this.props.activeIndex === null || this.props.activeIndex === undefined) && getDataHash(this.props.data) !== getDataHash(prevProps.data) && shouldActivateFirstItem(this.props) && !isActiveItemRetainedPosition) {
178
171
  this.activateFirst();
179
172
  }
@@ -232,8 +225,7 @@ class List extends Component {
232
225
  if (firstActivatableIndex >= 0) {
233
226
  this.setState({
234
227
  activeIndex: firstActivatableIndex,
235
- activeItem: this.props.data[firstActivatableIndex],
236
- needScrollToActive: true
228
+ activeItem: this.props.data[firstActivatableIndex]
237
229
  });
238
230
  }
239
231
  };
@@ -309,8 +301,7 @@ class List extends Component {
309
301
  const item = this.props.data[correctedIndex];
310
302
  this.setState({
311
303
  activeIndex: correctedIndex,
312
- activeItem: item,
313
- needScrollToActive: true
304
+ activeItem: item
314
305
  }, function onSet() {
315
306
  if (!isActivatable(item)) {
316
307
  retryCallback(e);
@@ -374,6 +365,24 @@ class List extends Component {
374
365
  }
375
366
  }
376
367
  });
368
+ scrollToActive = () => {
369
+ const {
370
+ activeIndex
371
+ } = this.state;
372
+ if (this.props.disableScrollToActive || activeIndex == null) {
373
+ return;
374
+ }
375
+ if (this.virtualizedList) {
376
+ this.virtualizedList.scrollToRow(activeIndex + 1);
377
+ } else {
378
+ const itemId = this.getId(this.props.data[activeIndex]);
379
+ if (itemId) {
380
+ document.getElementById(itemId)?.scrollIntoView?.({
381
+ block: 'center'
382
+ });
383
+ }
384
+ }
385
+ };
377
386
  checkOverflow = () => {
378
387
  if (this.inner) {
379
388
  this.setState({
@@ -519,7 +528,11 @@ class List extends Component {
519
528
  return props;
520
529
  };
521
530
  virtualizedListRef = el => {
531
+ const isFirstAssignment = el != null && this.virtualizedList == null;
522
532
  this.virtualizedList = el;
533
+ if (isFirstAssignment) {
534
+ this.scrollToActive();
535
+ }
523
536
  };
524
537
  containerRef = el => {
525
538
  this.container = el;
@@ -580,7 +593,6 @@ class List extends Component {
580
593
  // ensure rerendering
581
594
  ,
582
595
  noop: () => {},
583
- scrollToIndex: !this.props.disableScrollToActive && this.state.needScrollToActive && this.state.activeIndex !== null && this.state.activeIndex !== undefined ? this.state.activeIndex + 1 : undefined,
584
596
  scrollToAlignment: "center",
585
597
  deferredMeasurementCache: this._cache,
586
598
  onRowsRendered: this.checkOverflow,
@@ -5,11 +5,11 @@ const MAJOR_VERSION_INDEX = 0;
5
5
  /**
6
6
  * SUPPORTED_BROWSERS are defined by Babel plugin, see babel config
7
7
  */
8
- if (!["and_chr 144", "and_ff 147", "and_qq 14.9", "and_uc 15.5", "android 144", "chrome 145", "chrome 144", "chrome 143", "chrome 142", "chrome 141", "chrome 140", "chrome 139", "chrome 138", "chrome 137", "chrome 136", "chrome 135", "chrome 134", "chrome 133", "chrome 132", "chrome 131", "chrome 130", "chrome 129", "chrome 128", "chrome 127", "chrome 126", "chrome 125", "chrome 124", "chrome 123", "chrome 122", "chrome 121", "chrome 120", "chrome 119", "chrome 118", "chrome 117", "chrome 116", "chrome 115", "chrome 112", "chrome 109", "edge 144", "edge 143", "edge 142", "edge 141", "edge 140", "edge 139", "edge 138", "edge 137", "edge 136", "edge 135", "edge 134", "edge 133", "edge 132", "edge 131", "edge 130", "edge 129", "edge 128", "edge 127", "edge 126", "edge 125", "edge 124", "edge 123", "edge 122", "edge 121", "edge 120", "edge 119", "edge 118", "edge 117", "edge 116", "edge 115", "firefox 147", "firefox 146", "firefox 145", "firefox 144", "firefox 143", "firefox 142", "firefox 141", "firefox 140", "firefox 139", "firefox 138", "firefox 137", "firefox 136", "firefox 135", "firefox 134", "firefox 133", "firefox 132", "firefox 131", "firefox 130", "firefox 129", "firefox 128", "firefox 127", "firefox 126", "firefox 125", "firefox 124", "firefox 123", "firefox 122", "firefox 121", "firefox 120", "firefox 119", "firefox 118", "firefox 117", "firefox 116", "ios_saf 26.3", "ios_saf 26.2", "ios_saf 26.1", "ios_saf 26.0", "ios_saf 18.5-18.7", "ios_saf 18.4", "ios_saf 18.3", "ios_saf 18.2", "ios_saf 18.1", "ios_saf 18.0", "ios_saf 17.6-17.7", "ios_saf 17.5", "ios_saf 17.4", "ios_saf 17.3", "ios_saf 17.2", "ios_saf 17.1", "ios_saf 17.0", "ios_saf 16.6-16.7", "ios_saf 16.5", "ios_saf 16.4", "kaios 3.0-3.1", "kaios 2.5", "op_mini all", "op_mob 80", "opera 125", "opera 124", "safari 26.3", "safari 26.2", "safari 26.1", "safari 26.0", "safari 18.5-18.6", "safari 18.4", "safari 18.3", "safari 18.2", "safari 18.1", "safari 18.0", "safari 17.6", "safari 17.5", "safari 17.4", "safari 17.3", "safari 17.2", "safari 17.1", "safari 17.0", "safari 16.6", "safari 16.5", "safari 16.4", "samsung 29", "samsung 28"]) {
8
+ if (!["and_chr 145", "and_ff 147", "and_qq 14.9", "and_uc 15.5", "android 145", "chrome 145", "chrome 144", "chrome 143", "chrome 142", "chrome 141", "chrome 140", "chrome 139", "chrome 138", "chrome 137", "chrome 136", "chrome 135", "chrome 134", "chrome 133", "chrome 132", "chrome 131", "chrome 130", "chrome 129", "chrome 128", "chrome 127", "chrome 126", "chrome 125", "chrome 124", "chrome 123", "chrome 122", "chrome 121", "chrome 120", "chrome 119", "chrome 118", "chrome 117", "chrome 116", "chrome 115", "chrome 112", "chrome 109", "edge 145", "edge 144", "edge 143", "edge 142", "edge 141", "edge 140", "edge 139", "edge 138", "edge 137", "edge 136", "edge 135", "edge 134", "edge 133", "edge 132", "edge 131", "edge 130", "edge 129", "edge 128", "edge 127", "edge 126", "edge 125", "edge 124", "edge 123", "edge 122", "edge 121", "edge 120", "edge 119", "edge 118", "edge 117", "edge 116", "edge 115", "firefox 148", "firefox 147", "firefox 146", "firefox 145", "firefox 144", "firefox 143", "firefox 142", "firefox 141", "firefox 140", "firefox 139", "firefox 138", "firefox 137", "firefox 136", "firefox 135", "firefox 134", "firefox 133", "firefox 132", "firefox 131", "firefox 130", "firefox 129", "firefox 128", "firefox 127", "firefox 126", "firefox 125", "firefox 124", "firefox 123", "firefox 122", "firefox 121", "firefox 120", "firefox 119", "firefox 118", "firefox 117", "firefox 116", "ios_saf 26.3", "ios_saf 26.2", "ios_saf 26.1", "ios_saf 26.0", "ios_saf 18.5-18.7", "ios_saf 18.4", "ios_saf 18.3", "ios_saf 18.2", "ios_saf 18.1", "ios_saf 18.0", "ios_saf 17.6-17.7", "ios_saf 17.5", "ios_saf 17.4", "ios_saf 17.3", "ios_saf 17.2", "ios_saf 17.1", "ios_saf 17.0", "ios_saf 16.6-16.7", "ios_saf 16.5", "ios_saf 16.4", "kaios 3.0-3.1", "kaios 2.5", "op_mini all", "op_mob 80", "opera 125", "opera 124", "safari 26.3", "safari 26.2", "safari 26.1", "safari 26.0", "safari 18.5-18.6", "safari 18.4", "safari 18.3", "safari 18.2", "safari 18.1", "safari 18.0", "safari 17.6", "safari 17.5", "safari 17.4", "safari 17.3", "safari 17.2", "safari 17.1", "safari 17.0", "safari 16.6", "safari 16.5", "safari 16.4", "samsung 29", "samsung 28"]) {
9
9
  // eslint-disable-next-line no-console
10
10
  console.warn('Ring UI: no SUPPORTED_BROWSERS passed. Please check babel config.');
11
11
  }
12
- const SUPPORTED = ["and_chr 144", "and_ff 147", "and_qq 14.9", "and_uc 15.5", "android 144", "chrome 145", "chrome 144", "chrome 143", "chrome 142", "chrome 141", "chrome 140", "chrome 139", "chrome 138", "chrome 137", "chrome 136", "chrome 135", "chrome 134", "chrome 133", "chrome 132", "chrome 131", "chrome 130", "chrome 129", "chrome 128", "chrome 127", "chrome 126", "chrome 125", "chrome 124", "chrome 123", "chrome 122", "chrome 121", "chrome 120", "chrome 119", "chrome 118", "chrome 117", "chrome 116", "chrome 115", "chrome 112", "chrome 109", "edge 144", "edge 143", "edge 142", "edge 141", "edge 140", "edge 139", "edge 138", "edge 137", "edge 136", "edge 135", "edge 134", "edge 133", "edge 132", "edge 131", "edge 130", "edge 129", "edge 128", "edge 127", "edge 126", "edge 125", "edge 124", "edge 123", "edge 122", "edge 121", "edge 120", "edge 119", "edge 118", "edge 117", "edge 116", "edge 115", "firefox 147", "firefox 146", "firefox 145", "firefox 144", "firefox 143", "firefox 142", "firefox 141", "firefox 140", "firefox 139", "firefox 138", "firefox 137", "firefox 136", "firefox 135", "firefox 134", "firefox 133", "firefox 132", "firefox 131", "firefox 130", "firefox 129", "firefox 128", "firefox 127", "firefox 126", "firefox 125", "firefox 124", "firefox 123", "firefox 122", "firefox 121", "firefox 120", "firefox 119", "firefox 118", "firefox 117", "firefox 116", "ios_saf 26.3", "ios_saf 26.2", "ios_saf 26.1", "ios_saf 26.0", "ios_saf 18.5-18.7", "ios_saf 18.4", "ios_saf 18.3", "ios_saf 18.2", "ios_saf 18.1", "ios_saf 18.0", "ios_saf 17.6-17.7", "ios_saf 17.5", "ios_saf 17.4", "ios_saf 17.3", "ios_saf 17.2", "ios_saf 17.1", "ios_saf 17.0", "ios_saf 16.6-16.7", "ios_saf 16.5", "ios_saf 16.4", "kaios 3.0-3.1", "kaios 2.5", "op_mini all", "op_mob 80", "opera 125", "opera 124", "safari 26.3", "safari 26.2", "safari 26.1", "safari 26.0", "safari 18.5-18.6", "safari 18.4", "safari 18.3", "safari 18.2", "safari 18.1", "safari 18.0", "safari 17.6", "safari 17.5", "safari 17.4", "safari 17.3", "safari 17.2", "safari 17.1", "safari 17.0", "safari 16.6", "safari 16.5", "safari 16.4", "samsung 29", "samsung 28"] || [];
12
+ const SUPPORTED = ["and_chr 145", "and_ff 147", "and_qq 14.9", "and_uc 15.5", "android 145", "chrome 145", "chrome 144", "chrome 143", "chrome 142", "chrome 141", "chrome 140", "chrome 139", "chrome 138", "chrome 137", "chrome 136", "chrome 135", "chrome 134", "chrome 133", "chrome 132", "chrome 131", "chrome 130", "chrome 129", "chrome 128", "chrome 127", "chrome 126", "chrome 125", "chrome 124", "chrome 123", "chrome 122", "chrome 121", "chrome 120", "chrome 119", "chrome 118", "chrome 117", "chrome 116", "chrome 115", "chrome 112", "chrome 109", "edge 145", "edge 144", "edge 143", "edge 142", "edge 141", "edge 140", "edge 139", "edge 138", "edge 137", "edge 136", "edge 135", "edge 134", "edge 133", "edge 132", "edge 131", "edge 130", "edge 129", "edge 128", "edge 127", "edge 126", "edge 125", "edge 124", "edge 123", "edge 122", "edge 121", "edge 120", "edge 119", "edge 118", "edge 117", "edge 116", "edge 115", "firefox 148", "firefox 147", "firefox 146", "firefox 145", "firefox 144", "firefox 143", "firefox 142", "firefox 141", "firefox 140", "firefox 139", "firefox 138", "firefox 137", "firefox 136", "firefox 135", "firefox 134", "firefox 133", "firefox 132", "firefox 131", "firefox 130", "firefox 129", "firefox 128", "firefox 127", "firefox 126", "firefox 125", "firefox 124", "firefox 123", "firefox 122", "firefox 121", "firefox 120", "firefox 119", "firefox 118", "firefox 117", "firefox 116", "ios_saf 26.3", "ios_saf 26.2", "ios_saf 26.1", "ios_saf 26.0", "ios_saf 18.5-18.7", "ios_saf 18.4", "ios_saf 18.3", "ios_saf 18.2", "ios_saf 18.1", "ios_saf 18.0", "ios_saf 17.6-17.7", "ios_saf 17.5", "ios_saf 17.4", "ios_saf 17.3", "ios_saf 17.2", "ios_saf 17.1", "ios_saf 17.0", "ios_saf 16.6-16.7", "ios_saf 16.5", "ios_saf 16.4", "kaios 3.0-3.1", "kaios 2.5", "op_mini all", "op_mob 80", "opera 125", "opera 124", "safari 26.3", "safari 26.2", "safari 26.1", "safari 26.0", "safari 18.5-18.6", "safari 18.4", "safari 18.3", "safari 18.2", "safari 18.1", "safari 18.0", "safari 17.6", "safari 17.5", "safari 17.4", "safari 17.3", "safari 17.2", "safari 17.1", "safari 17.0", "safari 16.6", "safari 16.5", "safari 16.4", "samsung 29", "samsung 28"] || [];
13
13
  const WHITE_LISTED_BROWSERS = ['chrome', 'firefox', 'safari', 'edge'];
14
14
  const WHITE_LIST = SUPPORTED.reduce((acc, item) => {
15
15
  var _item$match;
@@ -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>;
@@ -175,7 +175,7 @@ class QueryAssist extends Component {
175
175
  this.requestStyleRanges().catch(noop);
176
176
  }
177
177
  this.setCaretPosition();
178
- this._pushHistory(this.state);
178
+ this._pushHistory(this.state.query);
179
179
  }
180
180
  shouldComponentUpdate(props, state) {
181
181
  return state.query !== this.state.query || state.dirty !== this.state.dirty || state.loading !== this.state.loading || state.showPopup !== this.state.showPopup || state.suggestions !== this.state.suggestions || state.styleRanges !== this.state.styleRanges || state.placeholderEnabled !== this.state.placeholderEnabled || state.shortcuts !== this.state.shortcuts || props.placeholder !== this.props.placeholder || props.disabled !== this.props.disabled || props.clear !== this.props.clear || props.focus !== this.props.focus || props.actions !== this.props.actions || props.loader !== this.props.loader || props.glass !== this.props.glass || props.className !== this.props.className || props.delay !== this.props.delay;
@@ -207,8 +207,8 @@ class QueryAssist extends Component {
207
207
  immediateState;
208
208
  requestData;
209
209
  ngModelStateField = ngModelStateField;
210
- // An array of {query: string; caret: number}[]
211
- historyStack = [];
210
+ undoHistoryStack = [];
211
+ redoHistoryStack = [];
212
212
  mouseIsDownOnPopup;
213
213
  handleFocusChange = e => {
214
214
  // otherwise it's blur and false
@@ -331,6 +331,10 @@ class QueryAssist extends Component {
331
331
  this.props.onChange(props);
332
332
  if (this.props.autoOpen === 'force' || props.query.length > 0) {
333
333
  this.requestData?.();
334
+ } else {
335
+ this.handleResponse({
336
+ caret: props.caret
337
+ });
334
338
  }
335
339
  };
336
340
  // It's necessary to prevent new element creation before any other hooks
@@ -355,36 +359,50 @@ class QueryAssist extends Component {
355
359
  }
356
360
  return true;
357
361
  };
358
- setState = (state, resolve) => {
362
+ setState = (state, resolve, undoOrRedo = false) => {
359
363
  super.setState(state, () => {
360
- this._pushHistory(state);
364
+ if (!undoOrRedo && 'query' in state) {
365
+ this._pushHistory(state.query);
366
+ }
361
367
  resolve?.();
362
368
  });
363
369
  };
364
- _pushHistory(state) {
365
- const queryIsSet = 'query' in state;
366
- const queryIsSame = this.historyStack[0]?.query === state.query;
367
- if (queryIsSet && !queryIsSame) {
370
+ _pushHistory(query) {
371
+ const normalizedQuery = query !== null && query !== void 0 ? query : '';
372
+ if (!this.undoHistoryStack.length || this.undoHistoryStack[0].normalizedQuery !== normalizedQuery) {
368
373
  var _this$caret$getPositi;
369
- this.historyStack.unshift({
370
- query: state.query,
374
+ this.undoHistoryStack.unshift({
375
+ normalizedQuery,
371
376
  caret: (_this$caret$getPositi = this.caret?.getPosition({
372
377
  avoidFocus: true
373
378
  })) !== null && _this$caret$getPositi !== void 0 ? _this$caret$getPositi : -1
374
379
  });
380
+ this.redoHistoryStack = [];
375
381
  }
376
382
  }
377
383
  undo = e => {
378
- const previous = this.historyStack.splice(0, 2)[1];
379
- if (!previous) {
384
+ this._undoOrRedo(e, false);
385
+ };
386
+ redo = e => {
387
+ this._undoOrRedo(e, true);
388
+ };
389
+ _undoOrRedo = (e, redo) => {
390
+ const stack = redo ? this.redoHistoryStack : this.undoHistoryStack;
391
+ const [current, previous] = stack;
392
+ const stateToApply = redo ? current : previous;
393
+ if (!stateToApply) {
380
394
  return;
381
395
  }
396
+ stack.shift();
397
+ e.preventDefault?.();
382
398
  this.setState({
383
- query: previous.query
399
+ query: stateToApply.normalizedQuery
384
400
  }, () => {
385
- this.caret?.setPosition(previous.caret);
401
+ const oppositeStack = redo ? this.undoHistoryStack : this.redoHistoryStack;
402
+ oppositeStack.unshift(current);
403
+ this.caret?.setPosition(stateToApply.caret);
386
404
  this.handleInput(e);
387
- });
405
+ }, true);
388
406
  };
389
407
  handlePaste = e => {
390
408
  const INSERT_COMMAND = 'insertText';
@@ -424,7 +442,7 @@ class QueryAssist extends Component {
424
442
  handleResponse = ({
425
443
  query = '',
426
444
  caret = 0,
427
- styleRanges,
445
+ styleRanges = [],
428
446
  suggestions = []
429
447
  }, afterCompletion = false) => new Promise((resolve, reject) => {
430
448
  if (query === this.getQuery() && (caret === this.immediateState.caret || this.immediateState.caret === undefined)) {
@@ -753,6 +771,7 @@ class QueryAssist extends Component {
753
771
  'ctrl+space': this.handleCtrlSpace,
754
772
  tab: this.handleTab,
755
773
  'meta+z': this.undo,
774
+ 'meta+shift+z': this.redo,
756
775
  right: noop,
757
776
  left: noop,
758
777
  space: noop,