@jetbrains/ring-ui-built 8.0.0-beta.10 → 8.0.0-beta.11

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,16 +1,18 @@
1
1
  import { PureComponent, createRef } from 'react';
2
2
  import { createPortal } from 'react-dom';
3
3
  import classNames from 'classnames';
4
- import closeIcon from '@jetbrains/icons/close';
5
4
  import { AdaptiveIsland } from '../island/island.js';
6
5
  import getUID from '../global/get-uid.js';
7
6
  import joinDataTestAttributes from '../global/data-tests.js';
8
7
  import Shortcuts from '../shortcuts/shortcuts.js';
9
8
  import TabTrap from '../tab-trap/tab-trap.js';
10
- import { Button } from '../button/button.js';
11
9
  import { PopupTarget, PopupTargetContext, normalizePopupTarget } from '../popup/popup.target.js';
12
10
  import { getPopupContainer } from '../popup/popup.js';
13
- import { p as preventerFactory, s as styles } from '../_helpers/dialog-body-scroll-preventer.js';
11
+ import getViewportSize from '../global/get-viewport-size.js';
12
+ import { preventerFactory } from './dialog-body-scroll-preventer.js';
13
+ import DialogControls from './dialog-controls.js';
14
+ import { fitGeometry, getResizeMinimum, moveGeometry, resizeGeometry, getNativeTabIndex, getTrapDisabled } from './dialog-geometry.js';
15
+ import { s as styles } from '../_helpers/dialog.js';
14
16
  import { jsxs, Fragment, jsx } from 'react/jsx-runtime';
15
17
  import '../island/adaptive-island-hoc.js';
16
18
  import '../global/linear-function.js';
@@ -26,6 +28,15 @@ import 'combokeys';
26
28
  import '../global/sniffer.js';
27
29
  import 'sniffr';
28
30
  import '../global/dom.js';
31
+ import '../global/configuration.js';
32
+ import '../popup/position.js';
33
+ import '../popup/popup.consts.js';
34
+ import '../popup/position-css.js';
35
+ import '../_helpers/theme.js';
36
+ import 'scrollbar-width';
37
+ import '@jetbrains/icons/close';
38
+ import '@jetbrains/icons/resize-corner-12px';
39
+ import '../button/button.js';
29
40
  import '@jetbrains/icons/chevron-down';
30
41
  import '@jetbrains/icons/chevron-12px-down';
31
42
  import '../icon/icon.js';
@@ -35,13 +46,7 @@ import '../_helpers/icon-svg.js';
35
46
  import '../global/memoize.js';
36
47
  import '../link/clickable-link.js';
37
48
  import '../global/controls-height.js';
38
- import '../global/configuration.js';
39
49
  import '../_helpers/button.classes.js';
40
- import '../popup/position.js';
41
- import '../popup/popup.consts.js';
42
- import '../popup/position-css.js';
43
- import '../_helpers/theme.js';
44
- import 'scrollbar-width';
45
50
 
46
51
  function noop() {}
47
52
  class Dialog extends PureComponent {
@@ -52,17 +57,21 @@ class Dialog extends PureComponent {
52
57
  onCloseClick: noop,
53
58
  onCloseAttempt: noop,
54
59
  showCloseButton: false,
55
- closeButtonInside: false,
60
+ movable: true,
61
+ resizable: true,
56
62
  shortcutOptions: {
57
63
  modal: false
58
64
  },
59
65
  trapFocus: false,
60
66
  autoFocusFirst: true,
67
+ native: true,
61
68
  modal: true,
62
69
  preventBodyScroll: true
63
70
  };
64
71
  state = {
65
- shortcutsScope: getUID('ring-dialog-')
72
+ shortcutsScope: getUID('ring-dialog-'),
73
+ geometry: null,
74
+ resized: false
66
75
  };
67
76
  componentDidMount() {
68
77
  const {
@@ -72,6 +81,7 @@ class Dialog extends PureComponent {
72
81
  if (native && show) {
73
82
  this.toggleNativeDialog();
74
83
  }
84
+ window.addEventListener('resize', this.fitGeometryToViewport);
75
85
  this.toggleScrollPreventer();
76
86
  }
77
87
  componentDidUpdate(prevProps) {
@@ -84,9 +94,16 @@ class Dialog extends PureComponent {
84
94
  }
85
95
  if (prevProps.show !== this.props.show) {
86
96
  this.toggleScrollPreventer();
97
+ if (show) {
98
+ this.fitGeometryToViewport();
99
+ } else {
100
+ this.interaction = null;
101
+ }
87
102
  }
88
103
  }
89
104
  componentWillUnmount() {
105
+ window.removeEventListener('resize', this.fitGeometryToViewport);
106
+ this.interaction = null;
90
107
  this.scrollPreventer.reset();
91
108
  }
92
109
  scrollPreventer = preventerFactory(getUID('preventer-'));
@@ -94,7 +111,8 @@ class Dialog extends PureComponent {
94
111
  toggleNativeDialog() {
95
112
  const {
96
113
  show,
97
- modal
114
+ modal,
115
+ autoFocusFirst
98
116
  } = this.props;
99
117
  if (this.nativeDialog.current) {
100
118
  if (show) {
@@ -104,6 +122,9 @@ class Dialog extends PureComponent {
104
122
  } else {
105
123
  this.nativeDialog.current.show();
106
124
  }
125
+ if (!autoFocusFirst && !this.nativeDialog.current.querySelector('[autofocus]')) {
126
+ this.nativeDialog.current.focus();
127
+ }
107
128
  } else {
108
129
  this.nativeDialog.current.close();
109
130
  }
@@ -143,6 +164,109 @@ class Dialog extends PureComponent {
143
164
  this.dialog = tabTrapObj && tabTrapObj.node;
144
165
  };
145
166
  nativeDialog = /*#__PURE__*/createRef();
167
+ innerContainer = /*#__PURE__*/createRef();
168
+ interaction = null;
169
+ resizeMinimum = null;
170
+ fitGeometryToViewport = () => {
171
+ this.setState(({
172
+ geometry
173
+ }) => {
174
+ if (!geometry) {
175
+ return null;
176
+ }
177
+ const {
178
+ width,
179
+ height
180
+ } = getViewportSize();
181
+ return {
182
+ geometry: fitGeometry(geometry, width, height)
183
+ };
184
+ });
185
+ };
186
+ startInteraction = (event, direction) => {
187
+ var _event$button, _this$resizeMinimum;
188
+ if (((_event$button = event.button) !== null && _event$button !== void 0 ? _event$button : 0) !== 0 || !this.innerContainer.current) {
189
+ return;
190
+ }
191
+ const {
192
+ left,
193
+ top,
194
+ width,
195
+ height
196
+ } = this.innerContainer.current.getBoundingClientRect();
197
+ const resizeMinimum = (_this$resizeMinimum = this.resizeMinimum) !== null && _this$resizeMinimum !== void 0 ? _this$resizeMinimum : getResizeMinimum(this.innerContainer.current.firstElementChild);
198
+ if (direction !== 'move') {
199
+ this.resizeMinimum = resizeMinimum;
200
+ }
201
+ this.interaction = {
202
+ pointerId: event.pointerId,
203
+ direction,
204
+ startX: event.clientX,
205
+ startY: event.clientY,
206
+ ...resizeMinimum,
207
+ geometry: {
208
+ left,
209
+ top,
210
+ width,
211
+ height
212
+ }
213
+ };
214
+ this.setState(({
215
+ resized
216
+ }) => ({
217
+ geometry: {
218
+ left,
219
+ top,
220
+ width,
221
+ height
222
+ },
223
+ resized: resized || direction !== 'move'
224
+ }));
225
+ event.currentTarget.setPointerCapture?.(event.pointerId);
226
+ event.preventDefault();
227
+ };
228
+ continueInteraction = event => {
229
+ const interaction = this.interaction;
230
+ if (!interaction || interaction.pointerId !== event.pointerId) {
231
+ return;
232
+ }
233
+ const dx = event.clientX - interaction.startX;
234
+ const dy = event.clientY - interaction.startY;
235
+ const {
236
+ width: viewportWidth,
237
+ height: viewportHeight
238
+ } = getViewportSize();
239
+ const start = interaction.geometry;
240
+ if (interaction.direction === 'move') {
241
+ this.setState({
242
+ geometry: moveGeometry(start, dx, dy, viewportWidth, viewportHeight)
243
+ });
244
+ return;
245
+ }
246
+ this.setState({
247
+ geometry: resizeGeometry(interaction, dx, dy, viewportWidth, viewportHeight),
248
+ resized: true
249
+ });
250
+ };
251
+ stopInteraction = event => {
252
+ if (this.interaction?.pointerId !== event.pointerId) {
253
+ return;
254
+ }
255
+ this.interaction = null;
256
+ if (event.currentTarget.hasPointerCapture?.(event.pointerId)) {
257
+ event.currentTarget.releasePointerCapture?.(event.pointerId);
258
+ }
259
+ };
260
+ startMove = event => {
261
+ const target = event.target;
262
+ if (!this.props.movable || !(target instanceof Element)) {
263
+ return;
264
+ }
265
+ const handle = target.closest('[data-ring-dialog-move-handle], [data-ring-island-header]');
266
+ if (handle?.parentElement === event.currentTarget) {
267
+ this.startInteraction(event, 'move');
268
+ }
269
+ };
146
270
  render() {
147
271
  const {
148
272
  show,
@@ -156,7 +280,6 @@ class Dialog extends PureComponent {
156
280
  contentClassName,
157
281
  trapFocus,
158
282
  'data-test': dataTest,
159
- closeButtonInside,
160
283
  portalTarget,
161
284
  label,
162
285
  closeButtonTitle,
@@ -165,15 +288,22 @@ class Dialog extends PureComponent {
165
288
  native,
166
289
  modal,
167
290
  preventBodyScroll,
291
+ movable,
292
+ resizable,
293
+ autoFocusFirst,
294
+ focusBackOnClose,
295
+ focusBackOnExit,
296
+ trapDisabled,
168
297
  ...restProps
169
298
  } = this.props;
170
299
  const classes = classNames(styles.container, className);
171
300
  const shortcutsMap = this.getShortcutsMap();
172
301
  const content = /*#__PURE__*/jsxs(Fragment, {
173
302
  children: [/*#__PURE__*/jsx(Shortcuts, {
303
+ disabled: !show,
174
304
  map: shortcutsMap,
175
305
  scope: this.state.shortcutsScope,
176
- options: this.props.shortcutOptions
306
+ options: shortcutOptions
177
307
  }), (onOverlayClick !== noop || onCloseAttempt !== noop) && /*#__PURE__*/jsx("div", {
178
308
  // click handler is duplicated in close button
179
309
  role: "presentation",
@@ -181,37 +311,52 @@ class Dialog extends PureComponent {
181
311
  onClick: this.handleClick,
182
312
  "data-test": "ring-dialog-overlay"
183
313
  }), /*#__PURE__*/jsx("div", {
184
- className: styles.innerContainer,
314
+ ref: this.innerContainer,
315
+ "data-test": "ring-dialog-inner-container",
316
+ className: classNames(styles.innerContainer, {
317
+ [styles.resized]: this.state.resized
318
+ }),
319
+ style: this.state.geometry ? {
320
+ position: 'fixed',
321
+ left: this.state.geometry.left,
322
+ top: this.state.geometry.top,
323
+ width: this.state.resized ? this.state.geometry.width : undefined,
324
+ height: this.state.resized ? this.state.geometry.height : undefined
325
+ } : undefined,
185
326
  children: /*#__PURE__*/jsxs(AdaptiveIsland, {
186
327
  className: classNames(styles.content, contentClassName, {
187
328
  [styles.dense]: dense,
188
- [styles.contentCloseButtonOutside]: !closeButtonInside,
189
- [styles.contentCloseButtonInside]: closeButtonInside
329
+ [styles.movable]: movable
190
330
  }),
191
331
  "data-test": "ring-dialog",
192
- role: "dialog",
193
- "aria-label": label,
194
- children: [children, showCloseButton && /*#__PURE__*/jsx(Button, {
195
- icon: closeIcon,
196
- "data-test": "ring-dialog-close-button",
197
- className: classNames(styles.closeButton, {
198
- [styles.closeButtonOutside]: !closeButtonInside,
199
- [styles.closeButtonInside]: closeButtonInside
200
- }),
201
- iconClassName: classNames(styles.closeIcon, {
202
- [styles.closeIconOutside]: !closeButtonInside
203
- }),
204
- onClick: this.onCloseClick,
205
- title: closeButtonTitle,
206
- "aria-label": closeButtonTitle || 'close dialog'
332
+ role: native ? undefined : 'dialog',
333
+ "aria-label": native ? undefined : label,
334
+ onPointerDown: this.startMove,
335
+ onPointerMove: this.continueInteraction,
336
+ onPointerUp: this.stopInteraction,
337
+ onPointerCancel: this.stopInteraction,
338
+ onLostPointerCapture: this.stopInteraction,
339
+ children: [children, /*#__PURE__*/jsx(DialogControls, {
340
+ movable: movable,
341
+ resizable: resizable,
342
+ showCloseButton: showCloseButton,
343
+ closeButtonTitle: closeButtonTitle,
344
+ onCloseClick: this.onCloseClick,
345
+ onStartInteraction: this.startInteraction,
346
+ onStopInteraction: this.stopInteraction
207
347
  })]
208
348
  })
209
349
  })]
210
350
  });
211
351
  if (native) {
212
352
  return /*#__PURE__*/jsx("dialog", {
353
+ ...restProps,
354
+ "aria-label": label,
213
355
  className: classNames(styles.nativeDialog, className),
356
+ "data-test": joinDataTestAttributes('ring-dialog-container', dataTest),
214
357
  ref: this.nativeDialog,
358
+ tabIndex: getNativeTabIndex(autoFocusFirst),
359
+ onCancel: event => event.preventDefault(),
215
360
  "data-rg-modal-dialog-container": modal ? '' : undefined,
216
361
  children: /*#__PURE__*/jsx(PopupTarget, {
217
362
  id: this.uid,
@@ -238,7 +383,10 @@ class Dialog extends PureComponent {
238
383
  id: this.uid,
239
384
  className: styles.popupTarget,
240
385
  children: target => /*#__PURE__*/jsxs(TabTrap, {
241
- trapDisabled: !trapFocus,
386
+ trapDisabled: getTrapDisabled(trapFocus, trapDisabled),
387
+ autoFocusFirst: autoFocusFirst,
388
+ focusBackOnClose: focusBackOnClose,
389
+ focusBackOnExit: focusBackOnExit,
242
390
  "data-test": joinDataTestAttributes('ring-dialog-container', dataTest),
243
391
  "data-rg-modal-dialog-container": "",
244
392
  ref: this.dialogRef,
@@ -0,0 +1,5 @@
1
+ declare const getViewportSize: () => {
2
+ width: number;
3
+ height: number;
4
+ };
5
+ export default getViewportSize;
@@ -0,0 +1,6 @@
1
+ const getViewportSize = () => ({
2
+ width: document.documentElement.clientWidth || window.innerWidth,
3
+ height: document.documentElement.clientHeight || window.innerHeight
4
+ });
5
+
6
+ export { getViewportSize as default };
@@ -123,23 +123,14 @@ class HTTP {
123
123
  const contentType = response.headers.get('content-type');
124
124
  const isJson = contentType && contentType.indexOf('application/json') !== -1;
125
125
  if (!response.ok) {
126
- let resJson;
127
- try {
128
- resJson = await (isJson ? response.json() : response.text());
129
- } catch (err) {
130
- // noop
131
- }
126
+ const resJson = await (isJson ? response.json() : response.text());
132
127
  throw new HTTPError(response, resJson);
133
128
  }
134
- try {
135
- const parsedResponse = await (isJson ? response.json() : {
136
- data: await response.text()
137
- });
138
- this._storeRequestMeta(parsedResponse, response);
139
- return parsedResponse;
140
- } catch (err) {
141
- return response;
142
- }
129
+ const parsedResponse = await (isJson ? response.json() : {
130
+ data: await response.text()
131
+ });
132
+ this._storeRequestMeta(parsedResponse, response);
133
+ return parsedResponse;
143
134
  }
144
135
  fetch = async (url, params = {}) => {
145
136
  const {
@@ -69,6 +69,7 @@ class Header extends Component {
69
69
  const titleStyle = this.getTitleStyle(phase);
70
70
  return /*#__PURE__*/jsxs("div", {
71
71
  ...restProps,
72
+ "data-ring-island-header": "",
72
73
  "data-test": "ring-island-header",
73
74
  className: classes,
74
75
  style: headerStyle,
@@ -82,11 +83,11 @@ class Header extends Component {
82
83
  }
83
84
  const HeaderWrapper = props => {
84
85
  const $ = c(3);
85
- if ($[0] !== "dbbfd9db484c81cb5d8abfe2d50de2fd9035c22d61c0a499e8f82dfe385f2c0e") {
86
+ if ($[0] !== "c6a29785d66819f6abbf7d95f1a562648cf4504e6b12c510c29c3956144b0c88") {
86
87
  for (let $i = 0; $i < 3; $i += 1) {
87
88
  $[$i] = Symbol.for("react.memo_cache_sentinel");
88
89
  }
89
- $[0] = "dbbfd9db484c81cb5d8abfe2d50de2fd9035c22d61c0a499e8f82dfe385f2c0e";
90
+ $[0] = "c6a29785d66819f6abbf7d95f1a562648cf4504e6b12c510c29c3956144b0c88";
90
91
  }
91
92
  let t0;
92
93
  if ($[1] !== props) {
@@ -8,7 +8,6 @@ import ContentWrapper from '../island/content.js';
8
8
  import LoaderScreen from '../loader-screen/loader-screen.js';
9
9
  import { HUB_AUTH_PAGE_OPENED } from '../auth/background-flow.js';
10
10
  import 'react-dom';
11
- import '@jetbrains/icons/close';
12
11
  import '../island/island.js';
13
12
  import '../global/data-tests.js';
14
13
  import '../island/adaptive-island-hoc.js';
@@ -25,6 +24,20 @@ import '../global/sniffer.js';
25
24
  import 'sniffr';
26
25
  import '../tab-trap/tab-trap.js';
27
26
  import '../global/dom.js';
27
+ import '../popup/popup.target.js';
28
+ import '../popup/popup.js';
29
+ import '../global/configuration.js';
30
+ import '../popup/position.js';
31
+ import '../popup/popup.consts.js';
32
+ import '../popup/position-css.js';
33
+ import '../_helpers/theme.js';
34
+ import '../global/get-viewport-size.js';
35
+ import '../dialog/dialog-body-scroll-preventer.js';
36
+ import 'scrollbar-width';
37
+ import '../_helpers/dialog.js';
38
+ import '../dialog/dialog-controls.js';
39
+ import '@jetbrains/icons/close';
40
+ import '@jetbrains/icons/resize-corner-12px';
28
41
  import '../button/button.js';
29
42
  import '@jetbrains/icons/chevron-down';
30
43
  import '@jetbrains/icons/chevron-12px-down';
@@ -35,16 +48,8 @@ import '../_helpers/icon-svg.js';
35
48
  import '../global/memoize.js';
36
49
  import '../link/clickable-link.js';
37
50
  import '../global/controls-height.js';
38
- import '../global/configuration.js';
39
51
  import '../_helpers/button.classes.js';
40
- import '../popup/popup.target.js';
41
- import '../popup/popup.js';
42
- import '../popup/position.js';
43
- import '../popup/popup.consts.js';
44
- import '../popup/position-css.js';
45
- import '../_helpers/theme.js';
46
- import '../_helpers/dialog-body-scroll-preventer.js';
47
- import 'scrollbar-width';
52
+ import '../dialog/dialog-geometry.js';
48
53
  import '../loader/loader.js';
49
54
  import '../_helpers/loader-core.js';
50
55
  import '../auth/response-parser.js';
@@ -8,7 +8,6 @@ import '../global/configuration.js';
8
8
  import '../dialog/dialog.js';
9
9
  import 'react-dom';
10
10
  import 'classnames';
11
- import '@jetbrains/icons/close';
12
11
  import '../island/island.js';
13
12
  import '../global/data-tests.js';
14
13
  import '../island/adaptive-island-hoc.js';
@@ -28,6 +27,19 @@ import '../global/sniffer.js';
28
27
  import 'sniffr';
29
28
  import '../tab-trap/tab-trap.js';
30
29
  import '../global/dom.js';
30
+ import '../popup/popup.target.js';
31
+ import '../popup/popup.js';
32
+ import '../popup/position.js';
33
+ import '../popup/popup.consts.js';
34
+ import '../popup/position-css.js';
35
+ import '../_helpers/theme.js';
36
+ import '../global/get-viewport-size.js';
37
+ import '../dialog/dialog-body-scroll-preventer.js';
38
+ import 'scrollbar-width';
39
+ import '../_helpers/dialog.js';
40
+ import '../dialog/dialog-controls.js';
41
+ import '@jetbrains/icons/close';
42
+ import '@jetbrains/icons/resize-corner-12px';
31
43
  import '../button/button.js';
32
44
  import '@jetbrains/icons/chevron-down';
33
45
  import '@jetbrains/icons/chevron-12px-down';
@@ -37,14 +49,7 @@ import '../_helpers/icon-svg.js';
37
49
  import '../global/memoize.js';
38
50
  import '../link/clickable-link.js';
39
51
  import '../_helpers/button.classes.js';
40
- import '../popup/popup.target.js';
41
- import '../popup/popup.js';
42
- import '../popup/position.js';
43
- import '../popup/popup.consts.js';
44
- import '../popup/position-css.js';
45
- import '../_helpers/theme.js';
46
- import '../_helpers/dialog-body-scroll-preventer.js';
47
- import 'scrollbar-width';
52
+ import '../dialog/dialog-geometry.js';
48
53
  import '../loader-screen/loader-screen.js';
49
54
  import '../loader/loader.js';
50
55
  import '../_helpers/loader-core.js';
@@ -58,6 +63,9 @@ const reactRoot = createRoot(containerElement);
58
63
  * Renders LoginDialog into virtual node to skip maintaining container
59
64
  */
60
65
  function renderLoginDialog(props) {
66
+ if (!containerElement.isConnected) {
67
+ document.body.appendChild(containerElement);
68
+ }
61
69
  reactRoot.render(/*#__PURE__*/jsx(ControlsHeightContext, {
62
70
  value: getGlobalControlsHeight(),
63
71
  children: /*#__PURE__*/jsx(LoginDialog, {