@jetbrains/ring-ui 6.0.63 → 6.0.65

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,5 @@
1
1
  import { PureComponent } from 'react';
2
2
  import * as React from 'react';
3
- import PropTypes from 'prop-types';
4
3
  import TabTrap, { TabTrapProps } from '../tab-trap/tab-trap';
5
4
  import type { ShortcutsScopeOptions } from '../shortcuts/core';
6
5
  export interface DialogProps extends Partial<TabTrapProps> {
@@ -24,26 +23,6 @@ export interface DialogProps extends Partial<TabTrapProps> {
24
23
  preventBodyScroll?: boolean;
25
24
  }
26
25
  export default class Dialog extends PureComponent<DialogProps> {
27
- static propTypes: {
28
- label: PropTypes.Requireable<string>;
29
- className: PropTypes.Requireable<string>;
30
- contentClassName: PropTypes.Requireable<string>;
31
- children: PropTypes.Requireable<NonNullable<PropTypes.ReactNodeLike>>;
32
- show: PropTypes.Validator<boolean>;
33
- showCloseButton: PropTypes.Requireable<boolean>;
34
- closeButtonInside: PropTypes.Requireable<boolean>;
35
- closeButtonTitle: PropTypes.Requireable<string>;
36
- onOverlayClick: PropTypes.Requireable<(...args: any[]) => any>;
37
- onEscPress: PropTypes.Requireable<(...args: any[]) => any>;
38
- onCloseClick: PropTypes.Requireable<(...args: any[]) => any>;
39
- shortcutOptions: PropTypes.Requireable<object>;
40
- onCloseAttempt: PropTypes.Requireable<(...args: any[]) => any>;
41
- trapFocus: PropTypes.Requireable<boolean>;
42
- portalTarget: PropTypes.Requireable<HTMLElement>;
43
- autoFocusFirst: PropTypes.Requireable<boolean>;
44
- 'data-test': PropTypes.Requireable<string>;
45
- preventBodyScroll: PropTypes.Requireable<boolean>;
46
- };
47
26
  static defaultProps: Partial<DialogProps>;
48
27
  state: {
49
28
  shortcutsScope: string;
@@ -68,4 +47,4 @@ export default class Dialog extends PureComponent<DialogProps> {
68
47
  nativeDialog: React.RefObject<HTMLDialogElement>;
69
48
  render(): false | React.JSX.Element;
70
49
  }
71
- export type DialogAttrs = JSX.LibraryManagedAttributes<typeof Dialog, DialogProps>;
50
+ export type DialogAttrs = React.JSX.LibraryManagedAttributes<typeof Dialog, DialogProps>;
@@ -1,7 +1,6 @@
1
1
  import { createRef, PureComponent } from 'react';
2
2
  import * as React from 'react';
3
3
  import { createPortal } from 'react-dom';
4
- import PropTypes from 'prop-types';
5
4
  import classNames from 'classnames';
6
5
  import closeIcon from '@jetbrains/icons/close';
7
6
  import { AdaptiveIsland } from '../island/island';
@@ -10,7 +9,8 @@ import dataTests from '../global/data-tests';
10
9
  import Shortcuts from '../shortcuts/shortcuts';
11
10
  import TabTrap from '../tab-trap/tab-trap';
12
11
  import Button from '../button/button';
13
- import { PopupTarget } from '../popup/popup.target';
12
+ import { PopupTarget, PopupTargetContext } from '../popup/popup.target';
13
+ import { getPopupContainer } from '../popup/popup';
14
14
  import { preventerFactory as scrollPreventerFactory } from './dialog__body-scroll-preventer';
15
15
  import styles from './dialog.css';
16
16
  /**
@@ -18,32 +18,6 @@ import styles from './dialog.css';
18
18
  */
19
19
  function noop() { }
20
20
  export default class Dialog extends PureComponent {
21
- static propTypes = {
22
- label: PropTypes.string,
23
- className: PropTypes.string,
24
- contentClassName: PropTypes.string,
25
- children: PropTypes.oneOfType([
26
- PropTypes.arrayOf(PropTypes.node),
27
- PropTypes.node
28
- ]),
29
- show: PropTypes.bool.isRequired,
30
- showCloseButton: PropTypes.bool,
31
- closeButtonInside: PropTypes.bool,
32
- closeButtonTitle: PropTypes.string,
33
- onOverlayClick: PropTypes.func,
34
- onEscPress: PropTypes.func,
35
- onCloseClick: PropTypes.func,
36
- shortcutOptions: PropTypes.object,
37
- // onCloseAttempt is a common callback for ESC pressing and overlay clicking.
38
- // Use it if you don't need different behaviors for this cases.
39
- onCloseAttempt: PropTypes.func,
40
- // focusTrap may break popups inside dialog, so use it carefully
41
- trapFocus: PropTypes.bool,
42
- portalTarget: PropTypes.instanceOf(HTMLElement),
43
- autoFocusFirst: PropTypes.bool,
44
- 'data-test': PropTypes.string,
45
- preventBodyScroll: PropTypes.bool
46
- };
47
21
  static defaultProps = {
48
22
  label: 'Dialog',
49
23
  onOverlayClick: noop,
@@ -87,7 +61,12 @@ export default class Dialog extends PureComponent {
87
61
  if (this.nativeDialog.current != null) {
88
62
  if (show) {
89
63
  this.nativeDialog.current.removeAttribute('open');
90
- modal ? this.nativeDialog.current.showModal() : this.nativeDialog.current.show();
64
+ if (modal) {
65
+ this.nativeDialog.current.showModal();
66
+ }
67
+ else {
68
+ this.nativeDialog.current.show();
69
+ }
91
70
  }
92
71
  else {
93
72
  this.nativeDialog.current.close();
@@ -137,30 +116,48 @@ export default class Dialog extends PureComponent {
137
116
  <Shortcuts map={shortcutsMap} scope={this.state.shortcutsScope} options={this.props.shortcutOptions}/>
138
117
  {(onOverlayClick !== noop || onCloseAttempt !== noop) && (<div
139
118
  // click handler is duplicated in close button
140
- role="presentation" className={styles.clickableOverlay} onClick={this.handleClick}/>)}
119
+ role="presentation" className={styles.clickableOverlay} onClick={this.handleClick} data-test="ring-dialog-overlay"/>)}
141
120
  <div className={styles.innerContainer}>
142
- <AdaptiveIsland className={classNames(styles.content, contentClassName, { [styles.dense]: dense })} data-test="ring-dialog" role="dialog" aria-label={label}>
121
+ <AdaptiveIsland className={classNames(styles.content, contentClassName, {
122
+ [styles.dense]: dense
123
+ })} data-test="ring-dialog" role="dialog" aria-label={label}>
143
124
  {children}
144
- {showCloseButton &&
145
- (<Button icon={closeIcon} data-test="ring-dialog-close-button" className={classNames(styles.closeButton, {
146
- [styles.closeButtonOutside]: !closeButtonInside,
147
- [styles.closeButtonInside]: closeButtonInside
148
- })} iconClassName={styles.closeIcon} onClick={this.onCloseClick} title={closeButtonTitle} aria-label={closeButtonTitle || 'close dialog'}/>)}
125
+ {showCloseButton && (<Button icon={closeIcon} data-test="ring-dialog-close-button" className={classNames(styles.closeButton, {
126
+ [styles.closeButtonOutside]: !closeButtonInside,
127
+ [styles.closeButtonInside]: closeButtonInside
128
+ })} iconClassName={styles.closeIcon} onClick={this.onCloseClick} title={closeButtonTitle} aria-label={closeButtonTitle || 'close dialog'}/>)}
149
129
  </AdaptiveIsland>
150
130
  </div>
151
131
  </>);
152
132
  if (native) {
153
133
  return (<dialog className={classNames(styles.nativeDialog, className)} ref={this.nativeDialog}>
154
134
  <PopupTarget id={this.uid} className={styles.popupTarget}>
155
- {target => <>{content}{target}</>}
135
+ {target => (<>
136
+ {content}
137
+ {target}
138
+ </>)}
156
139
  </PopupTarget>
157
140
  </dialog>);
158
141
  }
159
- return show && createPortal(<PopupTarget id={this.uid} className={styles.popupTarget}>
160
- {target => (<TabTrap trapDisabled={!trapFocus} data-test={dataTests('ring-dialog-container', dataTest)} ref={this.dialogRef} className={classes} role="presentation" {...restProps}>
161
- {content}
162
- {target}
163
- </TabTrap>)}
164
- </PopupTarget>, portalTarget instanceof HTMLElement ? portalTarget : document.body);
142
+ return (show && (<PopupTargetContext.Consumer>
143
+ {contextTarget => {
144
+ let targetElement = document.body;
145
+ if (portalTarget instanceof HTMLElement) {
146
+ targetElement = portalTarget;
147
+ }
148
+ else if (contextTarget != null) {
149
+ const container = getPopupContainer(contextTarget);
150
+ if (container != null) {
151
+ targetElement = container;
152
+ }
153
+ }
154
+ return createPortal(<PopupTarget id={this.uid} className={styles.popupTarget}>
155
+ {target => (<TabTrap trapDisabled={!trapFocus} data-test={dataTests('ring-dialog-container', dataTest)} ref={this.dialogRef} className={classes} role="presentation" {...restProps}>
156
+ {content}
157
+ {target}
158
+ </TabTrap>)}
159
+ </PopupTarget>, targetElement);
160
+ }}
161
+ </PopupTargetContext.Consumer>));
165
162
  }
166
163
  }
@@ -28,7 +28,8 @@ export default function focusSensorHOC(ComposedComponent) {
28
28
  }
29
29
  componentDidUpdate(prevProps) {
30
30
  const { focused } = this.props;
31
- if (focused && !prevProps.focused) {
31
+ const isInFocus = this.node?.contains(document.activeElement);
32
+ if (focused && (!isInFocus || !prevProps.focused)) {
32
33
  this.onFocusRestore();
33
34
  }
34
35
  else if (!focused && prevProps.focused) {
@@ -53,7 +53,6 @@ export interface PopupProps extends BasePopupProps {
53
53
  }
54
54
  interface PopupState {
55
55
  display: Display;
56
- client?: boolean;
57
56
  direction?: Directions;
58
57
  }
59
58
  /**
@@ -98,7 +97,6 @@ export default class Popup<P extends BasePopupProps = PopupProps> extends PureCo
98
97
  uid: string;
99
98
  calculateDisplay: (prevState: PopupState) => {
100
99
  display: Display;
101
- client?: boolean;
102
100
  direction?: Directions;
103
101
  };
104
102
  static PopupProps: {
@@ -120,6 +118,7 @@ export default class Popup<P extends BasePopupProps = PopupProps> extends PureCo
120
118
  private _redraw;
121
119
  private _getAnchor;
122
120
  private _listenersEnabled?;
121
+ private _prevTimeout?;
123
122
  /**
124
123
  * @param {boolean} enable
125
124
  * @private
@@ -71,9 +71,6 @@ export default class Popup extends PureComponent {
71
71
  display: Display.SHOWING
72
72
  };
73
73
  componentDidMount() {
74
- if (!this.props.client) {
75
- this.setState({ client: true });
76
- }
77
74
  if (!this.props.hidden) {
78
75
  this._setListenersEnabled(true);
79
76
  }
@@ -195,13 +192,15 @@ export default class Popup extends PureComponent {
195
192
  return this.props.anchorElement || this.parent;
196
193
  }
197
194
  _listenersEnabled;
195
+ _prevTimeout;
198
196
  /**
199
197
  * @param {boolean} enable
200
198
  * @private
201
199
  */
202
200
  _setListenersEnabled(enable) {
203
201
  if (enable && !this._listenersEnabled) {
204
- setTimeout(() => {
202
+ clearTimeout(this._prevTimeout);
203
+ this._prevTimeout = window.setTimeout(() => {
205
204
  this._listenersEnabled = true;
206
205
  this.listeners.add(window, 'resize', this._redraw);
207
206
  if (this.props.autoPositioningOnScroll) {
@@ -218,6 +217,7 @@ export default class Popup extends PureComponent {
218
217
  }
219
218
  if (!enable && this._listenersEnabled) {
220
219
  this.listeners.removeAll();
220
+ clearTimeout(this._prevTimeout);
221
221
  this._listenersEnabled = false;
222
222
  }
223
223
  }
@@ -283,7 +283,7 @@ export default class Popup extends PureComponent {
283
283
  {this.shouldUseShortcuts() &&
284
284
  (<Shortcuts map={this.shortcutsMap} scope={this.shortcutsScope}/>)}
285
285
 
286
- {(client || this.state.client) && (keepMounted || !hidden) && createPortal(<PopupTarget id={this.uid} ref={this.containerRef} onMouseOver={onMouseOver} onFocus={onMouseOver} onMouseOut={onMouseOut} onBlur={onMouseOut} onContextMenu={onContextMenu}>
286
+ {client !== false && (keepMounted || !hidden) && createPortal(<PopupTarget id={this.uid} ref={this.containerRef} onMouseOver={onMouseOver} onFocus={onMouseOver} onMouseOut={onMouseOut} onBlur={onMouseOut} onContextMenu={onContextMenu}>
287
287
  <div data-test={dataTests('ring-popup', dataTest)} data-test-shown={!hidden && !showing} data-test-direction={direction} ref={this.popupRef} className={classes} style={style} onMouseDown={onMouseDown} onMouseUp={onMouseUp}
288
288
  // mouse handlers are used to track clicking on inner elements
289
289
  role="presentation">
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@jetbrains/ring-ui",
3
- "version": "6.0.63",
3
+ "version": "6.0.65",
4
4
  "description": "JetBrains UI library",
5
5
  "author": "JetBrains",
6
6
  "license": "Apache-2.0",