@jetbrains/ring-ui 8.0.0-beta.1 → 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.
- package/babel.config.js +1 -9
- package/components/alert/alert-actions.d.ts +4 -0
- package/components/alert/alert-actions.js +5 -0
- package/components/alert/alert-heading.d.ts +4 -0
- package/components/alert/alert-heading.js +6 -0
- package/components/alert/alert.css +63 -22
- package/components/alert/alert.d.ts +14 -1
- package/components/alert/alert.js +34 -19
- package/components/alert/container.css +1 -2
- package/components/alert-service/alert-service.d.ts +2 -1
- package/components/alert-service/alert-service.js +8 -4
- package/components/auth/auth-core.d.ts +5 -9
- package/components/auth/auth-core.js +56 -15
- package/components/auth-dialog-service/auth-dialog-service.js +5 -2
- package/components/avatar/avatar-info.js +0 -2
- package/components/avatar/avatar-size.d.ts +0 -4
- package/components/avatar/avatar-size.js +0 -4
- package/components/avatar/avatar.js +0 -6
- package/components/avatar/fallback-avatar.js +0 -28
- package/components/avatar-stack/avatar-stack.js +1 -1
- package/components/banner/banner.css +3 -3
- package/components/button/button.css +4 -4
- package/components/button/button.d.ts +0 -4
- package/components/button/button.js +2 -7
- package/components/button-group/button-group.css +5 -5
- package/components/checkbox/checkbox.d.ts +1 -1
- package/components/collapse/collapse-content.d.ts +7 -0
- package/components/collapse/collapse-content.js +44 -11
- package/components/collapse/collapse-context.d.ts +2 -0
- package/components/collapse/collapse-context.js +2 -0
- package/components/collapse/collapse-control.js +2 -2
- package/components/collapse/collapse.css +8 -2
- package/components/collapse/collapse.d.ts +9 -0
- package/components/collapse/collapse.js +12 -3
- package/components/{expand → collapsible-group}/collapsible-group.css +7 -1
- package/components/collapsible-group/collapsible-group.d.ts +33 -0
- package/components/{expand → collapsible-group}/collapsible-group.js +13 -21
- package/components/confirm/confirm.js +12 -8
- package/components/confirm-service/confirm-service.js +5 -2
- package/components/data-list/data-list.d.ts +1 -1
- package/components/data-list/data-list.mock.d.ts +1 -1
- package/components/data-list/item.d.ts +1 -1
- package/components/data-list/selection.d.ts +1 -1
- package/components/data-list/selection.js +1 -1
- package/components/date-picker/consts.d.ts +1 -0
- package/components/date-picker/date-input.js +6 -2
- package/components/date-picker/months.js +2 -2
- package/components/date-picker/use-scroll-behavior.js +5 -6
- package/components/date-picker/years.js +2 -2
- package/components/dialog/dialog-controls.d.ts +13 -0
- package/components/dialog/dialog-controls.js +17 -0
- package/components/dialog/dialog-geometry.d.ts +31 -0
- package/components/dialog/dialog-geometry.js +48 -0
- package/components/dialog/dialog.css +166 -27
- package/components/dialog/dialog.d.ts +15 -7
- package/components/dialog/dialog.js +110 -29
- package/components/dropdown-menu/dropdown-menu.d.ts +4 -4
- package/components/dropdown-menu/dropdown-menu.js +4 -4
- package/components/editable-heading/editable-heading.d.ts +1 -2
- package/components/editable-heading/editable-heading.js +18 -19
- package/components/global/compose-refs.d.ts +2 -1
- package/components/global/compose-refs.js +24 -8
- package/components/global/create-stateful-context.js +5 -5
- package/components/global/focus-with-temporary-tabindex.d.ts +11 -0
- package/components/global/focus-with-temporary-tabindex.js +21 -0
- package/components/global/get-viewport-size.d.ts +5 -0
- package/components/global/get-viewport-size.js +5 -0
- package/components/global/intersection-observer-context.d.ts +31 -11
- package/components/global/intersection-observer-context.js +47 -28
- package/components/global/is-within-interactive-element.d.ts +6 -0
- package/components/global/is-within-interactive-element.js +26 -0
- package/components/global/is-within-navigable-element.d.ts +6 -0
- package/components/global/is-within-navigable-element.js +27 -0
- package/components/global/parse-css-duration.d.ts +5 -0
- package/components/global/parse-css-duration.js +13 -0
- package/components/global/rerender-hoc.d.ts +4 -2
- package/components/global/rerender-hoc.js +4 -4
- package/components/global/schedule-with-cleanup.d.ts +12 -0
- package/components/global/schedule-with-cleanup.js +34 -0
- package/components/{legacy-table/selection.d.ts → global/table-selection.d.ts} +14 -14
- package/components/{legacy-table/selection.js → global/table-selection.js} +2 -2
- package/components/global/theme.d.ts +4 -3
- package/components/global/theme.js +8 -8
- package/components/global/variables.css +18 -28
- package/components/global/variables.interface.d.ts +0 -4
- package/components/global/variables_dark.css +18 -25
- package/components/header/header.css +3 -3
- package/components/http/http.d.ts +2 -2
- package/components/http/http.js +6 -17
- package/components/i18n/i18n-context.js +1 -1
- package/components/i18n/i18n.d.ts +1 -0
- package/components/i18n/messages.json +1 -0
- package/components/icon/icon.css +0 -27
- package/components/icon/icon.d.ts +0 -1
- package/components/icon/icon.js +2 -4
- package/components/input/input.d.ts +1 -1
- package/components/island/adaptive-island-hoc.js +4 -4
- package/components/island/content.d.ts +7 -2
- package/components/island/content.js +5 -5
- package/components/island/header.js +1 -1
- package/components/legacy-table/cell.js +1 -1
- package/components/legacy-table/header-cell.js +1 -1
- package/components/legacy-table/header.js +1 -1
- package/components/legacy-table/multitable.d.ts +1 -1
- package/components/legacy-table/row.d.ts +1 -1
- package/components/legacy-table/row.js +1 -1
- package/components/legacy-table/selection-adapter.d.ts +3 -3
- package/components/legacy-table/selection-shortcuts-hoc.d.ts +5 -5
- package/components/legacy-table/simple-table.d.ts +2 -2
- package/components/legacy-table/simple-table.js +3 -3
- package/components/legacy-table/smart-table.d.ts +5 -5
- package/components/legacy-table/smart-table.js +3 -3
- package/components/legacy-table/table.js +1 -1
- package/components/list/consts.d.ts +0 -1
- package/components/list/consts.js +0 -1
- package/components/list/list.d.ts +0 -4
- package/components/login-dialog/service.js +5 -2
- package/components/panel/panel.css +1 -1
- package/components/popup/popup.d.ts +2 -0
- package/components/popup/popup.js +2 -2
- package/components/popup/popup.target.d.ts +3 -2
- package/components/popup/popup.target.js +4 -6
- package/components/query-assist/query-assist.d.ts +3 -1
- package/components/query-assist/query-assist.js +2 -2
- package/components/radio/radio-item.d.ts +3 -3
- package/components/radio/radio-item.js +3 -4
- package/components/radio/radio.d.ts +2 -2
- package/components/radio/radio.js +1 -1
- package/components/select/select-popup.d.ts +3 -2
- package/components/select/select-popup.js +3 -3
- package/components/select/select.d.ts +6 -2
- package/components/select/select.js +2 -4
- package/components/selection-toolbar/selection-toolbar.css +86 -0
- package/components/selection-toolbar/selection-toolbar.d.ts +11 -0
- package/components/selection-toolbar/selection-toolbar.js +23 -0
- package/components/slider/slider.js +4 -5
- package/components/tab-trap/tab-trap.d.ts +3 -3
- package/components/tab-trap/tab-trap.js +3 -5
- package/components/table/default-item-renderer.d.ts +41 -11
- package/components/table/default-item-renderer.js +60 -47
- package/components/table/internal/reorder-animation-context.d.ts +21 -0
- package/components/table/internal/reorder-animation-context.js +60 -0
- package/components/table/internal/reorder-handle.d.ts +9 -0
- package/components/table/internal/reorder-handle.js +334 -0
- package/components/table/internal/reorder-layout-context.d.ts +16 -0
- package/components/table/internal/reorder-layout-context.js +69 -0
- package/components/table/internal/table-header.d.ts +1 -0
- package/components/table/internal/table-header.js +143 -0
- package/components/table/internal/virtualization.d.ts +41 -0
- package/components/table/{table-virtualize.js → internal/virtualization.js} +82 -46
- package/components/table/item-virtualization.d.ts +37 -0
- package/components/table/item-virtualization.js +26 -0
- package/components/table/reorder-animation.d.ts +37 -0
- package/components/table/reorder-animation.js +11 -0
- package/components/table/reorder-item-layout.d.ts +32 -0
- package/components/table/reorder-item-layout.js +23 -0
- package/components/table/table-const.d.ts +8 -6
- package/components/table/table-const.js +7 -5
- package/components/table/table-primitives.d.ts +64 -0
- package/components/table/table-primitives.js +34 -0
- package/components/table/table-props.d.ts +304 -0
- package/components/table/table-props.js +1 -0
- package/components/table/table.css +179 -67
- package/components/table/table.d.ts +231 -224
- package/components/table/table.js +327 -2
- package/components/tag/tag.css +3 -3
- package/components/tags-input/tags-input.d.ts +3 -1
- package/components/tooltip/tooltip.d.ts +2 -1
- package/components/tooltip/tooltip.js +6 -5
- package/components/upload/upload.d.ts +4 -3
- package/components/upload/upload.js +3 -7
- package/components/user-agreement/service.js +5 -2
- package/components/user-agreement/user-agreement.css +2 -8
- package/components/user-agreement/user-agreement.js +8 -10
- package/components/user-card/smart-user-card-tooltip.d.ts +1 -1
- package/components/util-stories.d.ts +26 -0
- package/components/util-stories.js +61 -0
- package/package.json +47 -50
- package/components/content-layout/content-layout.css +0 -109
- package/components/content-layout/content-layout.d.ts +0 -20
- package/components/content-layout/content-layout.js +0 -40
- package/components/content-layout/sidebar.d.ts +0 -26
- package/components/content-layout/sidebar.js +0 -71
- package/components/date-picker/use-intersection-observer.d.ts +0 -6
- package/components/date-picker/use-intersection-observer.js +0 -48
- package/components/expand/collapsible-group.d.ts +0 -16
- package/components/global/composeRefs.d.ts +0 -6
- package/components/global/composeRefs.js +0 -7
- package/components/global/use-event-callback.d.ts +0 -1
- package/components/global/use-event-callback.js +0 -15
- package/components/grid/col.d.ts +0 -16
- package/components/grid/col.js +0 -35
- package/components/grid/grid.css +0 -920
- package/components/grid/grid.d.ts +0 -13
- package/components/grid/grid.js +0 -19
- package/components/grid/row.d.ts +0 -21
- package/components/grid/row.js +0 -41
- package/components/old-browsers-message/__mocks__/old-browsers-message.js +0 -1
- package/components/old-browsers-message/old-browsers-message-stop.d.ts +0 -1
- package/components/old-browsers-message/old-browsers-message-stop.js +0 -2
- package/components/old-browsers-message/old-browsers-message.css +0 -26
- package/components/old-browsers-message/old-browsers-message.d.ts +0 -5
- package/components/old-browsers-message/old-browsers-message.js +0 -86
- package/components/old-browsers-message/white-list.d.ts +0 -2
- package/components/old-browsers-message/white-list.js +0 -24
- package/components/table/table-base.d.ts +0 -24
- package/components/table/table-base.js +0 -79
- package/components/table/table-component.d.ts +0 -53
- package/components/table/table-component.js +0 -101
- package/components/table/table-virtualize.d.ts +0 -32
- /package/components/legacy-table/{table.css → legacy-table.css} +0 -0
|
@@ -2,20 +2,19 @@ import { createRef, PureComponent } from 'react';
|
|
|
2
2
|
import * as React from 'react';
|
|
3
3
|
import { createPortal } from 'react-dom';
|
|
4
4
|
import classNames from 'classnames';
|
|
5
|
-
import closeIcon from '@jetbrains/icons/close';
|
|
6
5
|
import { AdaptiveIsland } from '../island/island';
|
|
7
6
|
import getUID from '../global/get-uid';
|
|
8
7
|
import dataTests from '../global/data-tests';
|
|
9
8
|
import Shortcuts from '../shortcuts/shortcuts';
|
|
10
9
|
import TabTrap from '../tab-trap/tab-trap';
|
|
11
|
-
import Button from '../button/button';
|
|
12
10
|
import { normalizePopupTarget, PopupTarget, PopupTargetContext } from '../popup/popup.target';
|
|
13
11
|
import { getPopupContainer } from '../popup/popup';
|
|
12
|
+
import getViewportSize from '../global/get-viewport-size';
|
|
14
13
|
import { preventerFactory as scrollPreventerFactory } from './dialog-body-scroll-preventer';
|
|
14
|
+
import DialogControls from './dialog-controls';
|
|
15
|
+
import { fitGeometry, getNativeTabIndex, getResizeMinimum, getTrapDisabled, moveGeometry, resizeGeometry, } from './dialog-geometry';
|
|
15
16
|
import styles from './dialog.css';
|
|
16
|
-
/**
|
|
17
|
-
* @name Dialog
|
|
18
|
-
*/
|
|
17
|
+
/** @name Dialog */
|
|
19
18
|
function noop() { }
|
|
20
19
|
export default class Dialog extends PureComponent {
|
|
21
20
|
static defaultProps = {
|
|
@@ -25,21 +24,22 @@ export default class Dialog extends PureComponent {
|
|
|
25
24
|
onCloseClick: noop,
|
|
26
25
|
onCloseAttempt: noop,
|
|
27
26
|
showCloseButton: false,
|
|
28
|
-
|
|
27
|
+
movable: true,
|
|
28
|
+
resizable: true,
|
|
29
29
|
shortcutOptions: { modal: false },
|
|
30
30
|
trapFocus: false,
|
|
31
31
|
autoFocusFirst: true,
|
|
32
|
+
native: true,
|
|
32
33
|
modal: true,
|
|
33
34
|
preventBodyScroll: true,
|
|
34
35
|
};
|
|
35
|
-
state = {
|
|
36
|
-
shortcutsScope: getUID('ring-dialog-'),
|
|
37
|
-
};
|
|
36
|
+
state = { shortcutsScope: getUID('ring-dialog-'), geometry: null, resized: false };
|
|
38
37
|
componentDidMount() {
|
|
39
38
|
const { show, native } = this.props;
|
|
40
39
|
if (native && show) {
|
|
41
40
|
this.toggleNativeDialog();
|
|
42
41
|
}
|
|
42
|
+
window.addEventListener('resize', this.fitGeometryToViewport);
|
|
43
43
|
this.toggleScrollPreventer();
|
|
44
44
|
}
|
|
45
45
|
componentDidUpdate(prevProps) {
|
|
@@ -49,15 +49,23 @@ export default class Dialog extends PureComponent {
|
|
|
49
49
|
}
|
|
50
50
|
if (prevProps.show !== this.props.show) {
|
|
51
51
|
this.toggleScrollPreventer();
|
|
52
|
+
if (show) {
|
|
53
|
+
this.fitGeometryToViewport();
|
|
54
|
+
}
|
|
55
|
+
else {
|
|
56
|
+
this.interaction = null;
|
|
57
|
+
}
|
|
52
58
|
}
|
|
53
59
|
}
|
|
54
60
|
componentWillUnmount() {
|
|
61
|
+
window.removeEventListener('resize', this.fitGeometryToViewport);
|
|
62
|
+
this.interaction = null;
|
|
55
63
|
this.scrollPreventer.reset();
|
|
56
64
|
}
|
|
57
65
|
scrollPreventer = scrollPreventerFactory(getUID('preventer-'));
|
|
58
66
|
uid = getUID('dialog-');
|
|
59
67
|
toggleNativeDialog() {
|
|
60
|
-
const { show, modal } = this.props;
|
|
68
|
+
const { show, modal, autoFocusFirst } = this.props;
|
|
61
69
|
if (this.nativeDialog.current) {
|
|
62
70
|
if (show) {
|
|
63
71
|
this.nativeDialog.current.removeAttribute('open');
|
|
@@ -67,6 +75,9 @@ export default class Dialog extends PureComponent {
|
|
|
67
75
|
else {
|
|
68
76
|
this.nativeDialog.current.show();
|
|
69
77
|
}
|
|
78
|
+
if (!autoFocusFirst && !this.nativeDialog.current.querySelector('[autofocus]')) {
|
|
79
|
+
this.nativeDialog.current.focus();
|
|
80
|
+
}
|
|
70
81
|
}
|
|
71
82
|
else {
|
|
72
83
|
this.nativeDialog.current.close();
|
|
@@ -99,42 +110,112 @@ export default class Dialog extends PureComponent {
|
|
|
99
110
|
this.props.onCloseAttempt(event);
|
|
100
111
|
}
|
|
101
112
|
};
|
|
102
|
-
return {
|
|
103
|
-
esc: onEscape,
|
|
104
|
-
};
|
|
113
|
+
return { esc: onEscape };
|
|
105
114
|
};
|
|
106
115
|
dialog;
|
|
107
|
-
dialogRef = (
|
|
108
|
-
this.dialog =
|
|
116
|
+
dialogRef = (tabTrapObj) => {
|
|
117
|
+
this.dialog = tabTrapObj && tabTrapObj.node;
|
|
109
118
|
};
|
|
110
119
|
nativeDialog = createRef();
|
|
120
|
+
innerContainer = createRef();
|
|
121
|
+
interaction = null;
|
|
122
|
+
resizeMinimum = null;
|
|
123
|
+
fitGeometryToViewport = () => {
|
|
124
|
+
this.setState(({ geometry }) => {
|
|
125
|
+
if (!geometry) {
|
|
126
|
+
return null;
|
|
127
|
+
}
|
|
128
|
+
const { width, height } = getViewportSize();
|
|
129
|
+
return { geometry: fitGeometry(geometry, width, height) };
|
|
130
|
+
});
|
|
131
|
+
};
|
|
132
|
+
startInteraction = (event, direction) => {
|
|
133
|
+
if ((event.button ?? 0) !== 0 || !this.innerContainer.current) {
|
|
134
|
+
return;
|
|
135
|
+
}
|
|
136
|
+
const { left, top, width, height } = this.innerContainer.current.getBoundingClientRect();
|
|
137
|
+
const resizeMinimum = this.resizeMinimum ?? getResizeMinimum(this.innerContainer.current.firstElementChild);
|
|
138
|
+
if (direction !== 'move') {
|
|
139
|
+
this.resizeMinimum = resizeMinimum;
|
|
140
|
+
}
|
|
141
|
+
this.interaction = {
|
|
142
|
+
pointerId: event.pointerId,
|
|
143
|
+
direction,
|
|
144
|
+
startX: event.clientX,
|
|
145
|
+
startY: event.clientY,
|
|
146
|
+
...resizeMinimum,
|
|
147
|
+
geometry: { left, top, width, height },
|
|
148
|
+
};
|
|
149
|
+
this.setState(({ resized }) => ({ geometry: { left, top, width, height }, resized: resized || direction !== 'move' }));
|
|
150
|
+
event.currentTarget.setPointerCapture?.(event.pointerId);
|
|
151
|
+
event.preventDefault();
|
|
152
|
+
};
|
|
153
|
+
continueInteraction = (event) => {
|
|
154
|
+
const interaction = this.interaction;
|
|
155
|
+
if (!interaction || interaction.pointerId !== event.pointerId) {
|
|
156
|
+
return;
|
|
157
|
+
}
|
|
158
|
+
const dx = event.clientX - interaction.startX;
|
|
159
|
+
const dy = event.clientY - interaction.startY;
|
|
160
|
+
const { width: viewportWidth, height: viewportHeight } = getViewportSize();
|
|
161
|
+
const start = interaction.geometry;
|
|
162
|
+
if (interaction.direction === 'move') {
|
|
163
|
+
this.setState({ geometry: moveGeometry(start, dx, dy, viewportWidth, viewportHeight) });
|
|
164
|
+
return;
|
|
165
|
+
}
|
|
166
|
+
this.setState({
|
|
167
|
+
geometry: resizeGeometry(interaction, dx, dy, viewportWidth, viewportHeight),
|
|
168
|
+
resized: true,
|
|
169
|
+
});
|
|
170
|
+
};
|
|
171
|
+
stopInteraction = (event) => {
|
|
172
|
+
if (this.interaction?.pointerId !== event.pointerId) {
|
|
173
|
+
return;
|
|
174
|
+
}
|
|
175
|
+
this.interaction = null;
|
|
176
|
+
if (event.currentTarget.hasPointerCapture?.(event.pointerId)) {
|
|
177
|
+
event.currentTarget.releasePointerCapture?.(event.pointerId);
|
|
178
|
+
}
|
|
179
|
+
};
|
|
180
|
+
startMove = (event) => {
|
|
181
|
+
const target = event.target;
|
|
182
|
+
if (!this.props.movable || !(target instanceof Element)) {
|
|
183
|
+
return;
|
|
184
|
+
}
|
|
185
|
+
const handle = target.closest('[data-ring-dialog-move-handle], [data-ring-island-header]');
|
|
186
|
+
if (handle?.parentElement === event.currentTarget) {
|
|
187
|
+
this.startInteraction(event, 'move');
|
|
188
|
+
}
|
|
189
|
+
};
|
|
111
190
|
render() {
|
|
112
|
-
const { show, showCloseButton, onOverlayClick, onCloseAttempt, onEscPress, onCloseClick, children, className, contentClassName, trapFocus, 'data-test': dataTest,
|
|
191
|
+
const { show, showCloseButton, onOverlayClick, onCloseAttempt, onEscPress, onCloseClick, children, className, contentClassName, trapFocus, 'data-test': dataTest, portalTarget, label, closeButtonTitle, dense, shortcutOptions, native, modal, preventBodyScroll, movable, resizable, autoFocusFirst, focusBackOnClose, focusBackOnExit, trapDisabled, ...restProps } = this.props;
|
|
113
192
|
const classes = classNames(styles.container, className);
|
|
114
193
|
const shortcutsMap = this.getShortcutsMap();
|
|
115
194
|
const content = (<>
|
|
116
|
-
<Shortcuts map={shortcutsMap} scope={this.state.shortcutsScope} options={
|
|
195
|
+
<Shortcuts disabled={!show} map={shortcutsMap} scope={this.state.shortcutsScope} options={shortcutOptions}/>
|
|
117
196
|
{(onOverlayClick !== noop || onCloseAttempt !== noop) && (<div
|
|
118
197
|
// click handler is duplicated in close button
|
|
119
198
|
role='presentation' className={styles.clickableOverlay} onClick={this.handleClick} data-test='ring-dialog-overlay'/>)}
|
|
120
|
-
<div className={styles.innerContainer}
|
|
199
|
+
<div ref={this.innerContainer} data-test='ring-dialog-inner-container' className={classNames(styles.innerContainer, { [styles.resized]: this.state.resized })} style={this.state.geometry
|
|
200
|
+
? {
|
|
201
|
+
position: 'fixed',
|
|
202
|
+
left: this.state.geometry.left,
|
|
203
|
+
top: this.state.geometry.top,
|
|
204
|
+
width: this.state.resized ? this.state.geometry.width : undefined,
|
|
205
|
+
height: this.state.resized ? this.state.geometry.height : undefined,
|
|
206
|
+
}
|
|
207
|
+
: undefined}>
|
|
121
208
|
<AdaptiveIsland className={classNames(styles.content, contentClassName, {
|
|
122
209
|
[styles.dense]: dense,
|
|
123
|
-
[styles.
|
|
124
|
-
|
|
125
|
-
})} data-test='ring-dialog' role='dialog' aria-label={label}>
|
|
210
|
+
[styles.movable]: movable,
|
|
211
|
+
})} data-test='ring-dialog' role={native ? undefined : 'dialog'} aria-label={native ? undefined : label} onPointerDown={this.startMove} onPointerMove={this.continueInteraction} onPointerUp={this.stopInteraction} onPointerCancel={this.stopInteraction} onLostPointerCapture={this.stopInteraction}>
|
|
126
212
|
{children}
|
|
127
|
-
{
|
|
128
|
-
[styles.closeButtonOutside]: !closeButtonInside,
|
|
129
|
-
[styles.closeButtonInside]: closeButtonInside,
|
|
130
|
-
})} iconClassName={classNames(styles.closeIcon, {
|
|
131
|
-
[styles.closeIconOutside]: !closeButtonInside,
|
|
132
|
-
})} onClick={this.onCloseClick} title={closeButtonTitle} aria-label={closeButtonTitle || 'close dialog'}/>)}
|
|
213
|
+
<DialogControls movable={movable} resizable={resizable} showCloseButton={showCloseButton} closeButtonTitle={closeButtonTitle} onCloseClick={this.onCloseClick} onStartInteraction={this.startInteraction} onStopInteraction={this.stopInteraction}/>
|
|
133
214
|
</AdaptiveIsland>
|
|
134
215
|
</div>
|
|
135
216
|
</>);
|
|
136
217
|
if (native) {
|
|
137
|
-
return (<dialog className={classNames(styles.nativeDialog, className)} ref={this.nativeDialog} data-rg-modal-dialog-container={modal ? '' : undefined}>
|
|
218
|
+
return (<dialog {...restProps} aria-label={label} className={classNames(styles.nativeDialog, className)} data-test={dataTests('ring-dialog-container', dataTest)} ref={this.nativeDialog} tabIndex={getNativeTabIndex(autoFocusFirst)} onCancel={event => event.preventDefault()} data-rg-modal-dialog-container={modal ? '' : undefined}>
|
|
138
219
|
<PopupTarget id={this.uid} className={styles.popupTarget}>
|
|
139
220
|
{target => (<>
|
|
140
221
|
{content}
|
|
@@ -157,7 +238,7 @@ export default class Dialog extends PureComponent {
|
|
|
157
238
|
}
|
|
158
239
|
}
|
|
159
240
|
return createPortal(<PopupTarget id={this.uid} className={styles.popupTarget}>
|
|
160
|
-
{target => (<TabTrap trapDisabled={
|
|
241
|
+
{target => (<TabTrap trapDisabled={getTrapDisabled(trapFocus, trapDisabled)} autoFocusFirst={autoFocusFirst} focusBackOnClose={focusBackOnClose} focusBackOnExit={focusBackOnExit} data-test={dataTests('ring-dialog-container', dataTest)} data-rg-modal-dialog-container='' ref={this.dialogRef} className={classes} role='presentation' {...restProps}>
|
|
161
242
|
{content}
|
|
162
243
|
{target}
|
|
163
244
|
</TabTrap>)}
|
|
@@ -1,4 +1,4 @@
|
|
|
1
|
-
import { type ReactElement, type HTMLAttributes, type SyntheticEvent, type
|
|
1
|
+
import { type ReactElement, type HTMLAttributes, type SyntheticEvent, type ReactNode } from 'react';
|
|
2
2
|
import { type SelectHandlerParams } from '../list/list';
|
|
3
3
|
import { type AnchorProps, type DropdownAttrs, type DropdownChildrenFunction } from '../dropdown/dropdown';
|
|
4
4
|
import PopupMenu, { type PopupMenuAttrs } from '../popup-menu/popup-menu';
|
|
@@ -10,6 +10,7 @@ export interface DropdownAnchorWrapperProps extends AnchorProps {
|
|
|
10
10
|
}
|
|
11
11
|
type OnSelectHandler<T> = ((item: ListDataItem<T>, event: Event | SyntheticEvent, params?: SelectHandlerParams) => void) | undefined;
|
|
12
12
|
export interface DropdownMenuProps<T = unknown> extends Omit<DropdownAttrs, 'anchor' | 'onSelect' | 'children'> {
|
|
13
|
+
ref?: React.Ref<PopupMenu<T> | null>;
|
|
13
14
|
anchor: ReactElement | ReactNode[] | string | ((props: AnchorProps, ariaProps: HTMLAttributes<HTMLElement>) => ReactElement | null);
|
|
14
15
|
data?: readonly ListDataItem<T>[] | undefined;
|
|
15
16
|
ariaLabel?: string | null | undefined;
|
|
@@ -17,9 +18,8 @@ export interface DropdownMenuProps<T = unknown> extends Omit<DropdownAttrs, 'anc
|
|
|
17
18
|
menuProps?: PopupMenuAttrs<T> | null | undefined;
|
|
18
19
|
children?: DropdownChildrenFunction;
|
|
19
20
|
}
|
|
20
|
-
declare
|
|
21
|
-
|
|
22
|
-
}) => ReactElement | null) & {
|
|
21
|
+
declare function DropdownMenu<T = unknown>({ ref, id, anchor, ariaLabel, data, onSelect, menuProps, children, ...restDropdownProps }: DropdownMenuProps<T>): import("react").JSX.Element;
|
|
22
|
+
declare const _default: typeof DropdownMenu & {
|
|
23
23
|
ListProps: {
|
|
24
24
|
Type: typeof import("../list/consts").Type;
|
|
25
25
|
Dimension: {
|
|
@@ -1,4 +1,4 @@
|
|
|
1
|
-
import {
|
|
1
|
+
import { cloneElement, useState, } from 'react';
|
|
2
2
|
import List, { ActiveItemContext } from '../list/list';
|
|
3
3
|
import Dropdown from '../dropdown/dropdown';
|
|
4
4
|
import PopupMenu from '../popup-menu/popup-menu';
|
|
@@ -31,11 +31,11 @@ function renderDropdownMenuChildren({ children, popupMenuProps }) {
|
|
|
31
31
|
}
|
|
32
32
|
return (popupProps) => children({ ...popupProps, ...popupMenuProps });
|
|
33
33
|
}
|
|
34
|
-
|
|
34
|
+
function DropdownMenu({ ref, id, anchor, ariaLabel, data, onSelect, menuProps, children, ...restDropdownProps }) {
|
|
35
35
|
const [uid] = useState(() => getUID('dropdown-menu-list'));
|
|
36
36
|
const listId = id || uid;
|
|
37
37
|
const popupMenuProps = {
|
|
38
|
-
ref
|
|
38
|
+
ref,
|
|
39
39
|
id: listId,
|
|
40
40
|
ariaLabel: ariaLabel || defaultAriaLabel,
|
|
41
41
|
closeOnSelect: true,
|
|
@@ -51,5 +51,5 @@ const DropdownMenu = forwardRef(function DropdownMenu({ id, anchor, ariaLabel, d
|
|
|
51
51
|
{renderDropdownMenuChildren({ children, popupMenuProps })}
|
|
52
52
|
</Dropdown>
|
|
53
53
|
</ActiveItemContext.Provider>);
|
|
54
|
-
}
|
|
54
|
+
}
|
|
55
55
|
export default Object.assign(DropdownMenu, { ListProps: List.ListProps });
|
|
@@ -29,5 +29,4 @@ export type EditableHeadingProps = Omit<InputHTMLAttributes<HTMLInputElement | H
|
|
|
29
29
|
translations?: EditableHeadingTranslations;
|
|
30
30
|
};
|
|
31
31
|
export declare const EditableHeading: (props: EditableHeadingProps) => React.JSX.Element;
|
|
32
|
-
|
|
33
|
-
export default _default;
|
|
32
|
+
export default EditableHeading;
|
|
@@ -1,4 +1,4 @@
|
|
|
1
|
-
import { useEffect } from 'react';
|
|
1
|
+
import { useEffect, useEffectEvent, useLayoutEffect } from 'react';
|
|
2
2
|
import * as React from 'react';
|
|
3
3
|
import classNames from 'classnames';
|
|
4
4
|
import Heading, { Levels } from '../heading/heading';
|
|
@@ -6,7 +6,6 @@ import Button from '../button/button';
|
|
|
6
6
|
import { Size } from '../input/input';
|
|
7
7
|
import getUID from '../global/get-uid';
|
|
8
8
|
import Shortcuts from '../shortcuts/shortcuts';
|
|
9
|
-
import useEventCallback from '../global/use-event-callback';
|
|
10
9
|
import inputStyles from '../input/input.css';
|
|
11
10
|
import styles from './editable-heading.css';
|
|
12
11
|
export { Levels };
|
|
@@ -46,36 +45,30 @@ export const EditableHeading = (props) => {
|
|
|
46
45
|
});
|
|
47
46
|
const headingClasses = classNames(styles.heading, headingClassName, size !== Size.AUTO && styles[`size${size}`]);
|
|
48
47
|
const inputClasses = classNames('ring-js-shortcuts', styles.input, styles.textarea, { [styles.textareaNotOverflow]: !isOverflow }, size !== Size.AUTO && inputStyles[`size${size}`], level !== Levels.H4 && styles[`level${level}`], inputClassName);
|
|
49
|
-
const
|
|
50
|
-
if (!el || !el.style) {
|
|
51
|
-
return;
|
|
52
|
-
}
|
|
53
|
-
el.style.height = '0';
|
|
54
|
-
const { paddingTop, paddingBottom } = window.getComputedStyle(el);
|
|
55
|
-
el.style.height = `${el.scrollHeight - parseFloat(paddingTop) - parseFloat(paddingBottom)}px`;
|
|
56
|
-
};
|
|
57
|
-
const checkValue = (el) => {
|
|
48
|
+
const checkValue = React.useCallback((el) => {
|
|
58
49
|
if (multiline && el && el.scrollHeight >= el.clientHeight) {
|
|
59
|
-
|
|
50
|
+
el.style.height = '0';
|
|
51
|
+
const { paddingTop, paddingBottom } = window.getComputedStyle(el);
|
|
52
|
+
el.style.height = `${el.scrollHeight - parseFloat(paddingTop) - parseFloat(paddingBottom)}px`;
|
|
60
53
|
}
|
|
61
|
-
};
|
|
62
|
-
const checkOverflow = (el) => {
|
|
54
|
+
}, [multiline]);
|
|
55
|
+
const checkOverflow = React.useCallback((el) => {
|
|
63
56
|
const scrollHeight = el.scrollHeight || 0;
|
|
64
57
|
const clientHeight = el.clientHeight || 0;
|
|
65
58
|
const scrollTop = el.scrollTop || 0;
|
|
66
59
|
setIsScrolledToBottom(scrollHeight - clientHeight <= scrollTop);
|
|
67
60
|
setIsOverflow(scrollHeight > clientHeight);
|
|
68
|
-
};
|
|
61
|
+
}, []);
|
|
69
62
|
const onHeadingMouseDown = () => {
|
|
70
63
|
setIsMouseDown(true);
|
|
71
64
|
};
|
|
72
|
-
const onMouseMove =
|
|
65
|
+
const onMouseMove = useEffectEvent(() => {
|
|
73
66
|
if (!isMouseDown) {
|
|
74
67
|
return;
|
|
75
68
|
}
|
|
76
69
|
setIsInSelectionMode(true);
|
|
77
70
|
});
|
|
78
|
-
const onMouseUp =
|
|
71
|
+
const onMouseUp = useEffectEvent(() => {
|
|
79
72
|
if (isMouseDown && !isInSelectionMode && !disabled) {
|
|
80
73
|
onEdit();
|
|
81
74
|
}
|
|
@@ -101,6 +94,12 @@ export const EditableHeading = (props) => {
|
|
|
101
94
|
setIsInFocus(false);
|
|
102
95
|
onBlur?.(e);
|
|
103
96
|
};
|
|
97
|
+
useLayoutEffect(() => {
|
|
98
|
+
if (multiline && isEditing && textAreaRef.current) {
|
|
99
|
+
checkValue(textAreaRef.current);
|
|
100
|
+
checkOverflow(textAreaRef.current);
|
|
101
|
+
}
|
|
102
|
+
}, [checkOverflow, checkValue, isEditing, multiline]);
|
|
104
103
|
useEffect(() => {
|
|
105
104
|
window.addEventListener('mousemove', onMouseMove);
|
|
106
105
|
window.addEventListener('mouseup', onMouseUp);
|
|
@@ -108,7 +107,7 @@ export const EditableHeading = (props) => {
|
|
|
108
107
|
window.removeEventListener('mousemove', onMouseMove);
|
|
109
108
|
window.removeEventListener('mouseup', onMouseUp);
|
|
110
109
|
};
|
|
111
|
-
}, [
|
|
110
|
+
}, []);
|
|
112
111
|
return (<>
|
|
113
112
|
<div className={classes}>
|
|
114
113
|
{!disabled && isEditing ? (<>
|
|
@@ -140,4 +139,4 @@ export const EditableHeading = (props) => {
|
|
|
140
139
|
{isEditing && error && (<div className={classNames(styles.errorText, size !== Size.AUTO && inputStyles[`size${size}`])}>{error}</div>)}
|
|
141
140
|
</>);
|
|
142
141
|
};
|
|
143
|
-
export default
|
|
142
|
+
export default EditableHeading;
|
|
@@ -1,2 +1,3 @@
|
|
|
1
1
|
import { type Ref } from 'react';
|
|
2
|
-
export declare function createComposedRef<T>(): import("memoize-one").MemoizedFn<(...refs: (Ref<T> | undefined)[]) => (value: T | null) => void>;
|
|
2
|
+
export declare function createComposedRef<T>(): import("memoize-one").MemoizedFn<(...refs: (Ref<T> | undefined)[]) => (value: T | null) => () => void>;
|
|
3
|
+
export declare function useComposedRef<T>(...refs: (Ref<T> | undefined)[]): Ref<T>;
|
|
@@ -1,14 +1,30 @@
|
|
|
1
|
+
import { useMemo } from 'react';
|
|
1
2
|
import memoizeOne from 'memoize-one';
|
|
2
3
|
function composeRefs(...refs) {
|
|
3
|
-
return (value) =>
|
|
4
|
-
|
|
5
|
-
|
|
6
|
-
|
|
7
|
-
|
|
8
|
-
|
|
9
|
-
|
|
10
|
-
|
|
4
|
+
return (value) => {
|
|
5
|
+
const cleanups = [];
|
|
6
|
+
refs.forEach(ref => {
|
|
7
|
+
if (typeof ref === 'function') {
|
|
8
|
+
const cleanup = ref(value);
|
|
9
|
+
if (typeof cleanup === 'function') {
|
|
10
|
+
cleanups.push(cleanup);
|
|
11
|
+
}
|
|
12
|
+
}
|
|
13
|
+
else if (ref) {
|
|
14
|
+
ref.current = value;
|
|
15
|
+
}
|
|
16
|
+
});
|
|
17
|
+
return () => cleanups.forEach(cleanup => cleanup());
|
|
18
|
+
};
|
|
11
19
|
}
|
|
12
20
|
export function createComposedRef() {
|
|
13
21
|
return memoizeOne((composeRefs));
|
|
14
22
|
}
|
|
23
|
+
export function useComposedRef(...refs) {
|
|
24
|
+
/**
|
|
25
|
+
* The React Compiler doesn't allow non-literal arrays in useMemo
|
|
26
|
+
* dependency lists, so we still use memoizeOne under the hood.
|
|
27
|
+
*/
|
|
28
|
+
const composer = useMemo(() => createComposedRef(), []);
|
|
29
|
+
return composer(...refs);
|
|
30
|
+
}
|
|
@@ -1,16 +1,16 @@
|
|
|
1
|
-
import { createContext, memo,
|
|
1
|
+
import { createContext, memo, use, useEffect, useState } from 'react';
|
|
2
2
|
export default function createStatefulContext(initialValue, name = '') {
|
|
3
3
|
const ValueContext = createContext(initialValue);
|
|
4
4
|
const UpdateContext = createContext(() => { });
|
|
5
5
|
function Provider({ children }) {
|
|
6
6
|
const [value, update] = useState(initialValue);
|
|
7
|
-
return (<ValueContext
|
|
8
|
-
<UpdateContext
|
|
9
|
-
</ValueContext
|
|
7
|
+
return (<ValueContext value={value}>
|
|
8
|
+
<UpdateContext value={update}>{children}</UpdateContext>
|
|
9
|
+
</ValueContext>);
|
|
10
10
|
}
|
|
11
11
|
Provider.displayName = `${name}Provider`;
|
|
12
12
|
function useUpdate(value, skipUpdate) {
|
|
13
|
-
const update =
|
|
13
|
+
const update = use(UpdateContext);
|
|
14
14
|
useEffect(() => {
|
|
15
15
|
if (!skipUpdate) {
|
|
16
16
|
update(value);
|
|
@@ -0,0 +1,11 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Focuses an element, temporarily adding `tabindex="0"` if necessary.
|
|
3
|
+
*
|
|
4
|
+
* If the element does not already have a `tabindex` attribute, one is
|
|
5
|
+
* added before focusing and automatically removed when the element loses
|
|
6
|
+
* focus.
|
|
7
|
+
*
|
|
8
|
+
* This is useful when implementing roving tabindex patterns on elements
|
|
9
|
+
* that are not normally focusable.
|
|
10
|
+
*/
|
|
11
|
+
export declare function focusWithTemporaryTabIndex(element: HTMLElement): void;
|
|
@@ -0,0 +1,21 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Focuses an element, temporarily adding `tabindex="0"` if necessary.
|
|
3
|
+
*
|
|
4
|
+
* If the element does not already have a `tabindex` attribute, one is
|
|
5
|
+
* added before focusing and automatically removed when the element loses
|
|
6
|
+
* focus.
|
|
7
|
+
*
|
|
8
|
+
* This is useful when implementing roving tabindex patterns on elements
|
|
9
|
+
* that are not normally focusable.
|
|
10
|
+
*/
|
|
11
|
+
export function focusWithTemporaryTabIndex(element) {
|
|
12
|
+
if (!element.hasAttribute('tabindex')) {
|
|
13
|
+
element.tabIndex = 0;
|
|
14
|
+
function onBlur() {
|
|
15
|
+
element.removeAttribute('tabindex');
|
|
16
|
+
element.removeEventListener('blur', onBlur);
|
|
17
|
+
}
|
|
18
|
+
element.addEventListener('blur', onBlur);
|
|
19
|
+
}
|
|
20
|
+
element.focus();
|
|
21
|
+
}
|
|
@@ -1,26 +1,46 @@
|
|
|
1
1
|
import { type RefObject } from 'react';
|
|
2
2
|
/**
|
|
3
|
+
* Provides access to a shared `IntersectionObserver` instance
|
|
4
|
+
* via the {@link IntersectionObserverContext} context.
|
|
5
|
+
*
|
|
6
|
+
* @see IntersectionObserverContext
|
|
7
|
+
*/
|
|
8
|
+
export interface IntersectionObserverHandle {
|
|
9
|
+
/**
|
|
10
|
+
* Starts observing an element.
|
|
11
|
+
*
|
|
12
|
+
* Returns a cleanup function that stops observing it.
|
|
13
|
+
*/
|
|
14
|
+
observe(element: Element, isIntersecting: (isIntersecting: boolean) => void): () => void;
|
|
15
|
+
}
|
|
16
|
+
/**
|
|
17
|
+
* Multiple components can share a single `IntersectionObserver` instance through this context.
|
|
18
|
+
*
|
|
3
19
|
* Usage:
|
|
4
20
|
*
|
|
5
21
|
* ```tsx
|
|
6
|
-
* <IntersectionObserverContext
|
|
22
|
+
* <IntersectionObserverContext value={useIntersectionObserverHandle()}>
|
|
7
23
|
* <YourComponent />
|
|
8
|
-
* </IntersectionObserverContext
|
|
24
|
+
* </IntersectionObserverContext>
|
|
9
25
|
*
|
|
10
26
|
* function YourComponent() {
|
|
11
27
|
* // Contains the current isIntersecting value
|
|
12
28
|
* const isIntersecting = useIsIntersecting(elementRef);
|
|
13
|
-
*
|
|
14
|
-
*
|
|
15
|
-
*
|
|
29
|
+
*
|
|
30
|
+
* // Or, to manually work with the IntersectionObserverHandle:
|
|
31
|
+
* const handle = use(IntersectionObserverContext);
|
|
32
|
+
* useEffect(() => {
|
|
33
|
+
* return handle.observe(elementRef.current, isIntersecting => { ... })
|
|
16
34
|
* })
|
|
17
35
|
* }
|
|
18
36
|
* ```
|
|
19
37
|
*/
|
|
20
|
-
export declare const IntersectionObserverContext: import("react").Context<IntersectionObserverHandle
|
|
21
|
-
|
|
22
|
-
|
|
23
|
-
|
|
24
|
-
|
|
38
|
+
export declare const IntersectionObserverContext: import("react").Context<IntersectionObserverHandle>;
|
|
39
|
+
/**
|
|
40
|
+
* Creates an IntersectionObserverHandle suitable for {@link IntersectionObserverContext}.
|
|
41
|
+
*/
|
|
42
|
+
export declare function useIntersectionObserverHandle(rootRef?: RefObject<HTMLElement | null>, rootMargin?: number, scrollMargin?: number): IntersectionObserverHandle;
|
|
43
|
+
/**
|
|
44
|
+
* Returns whether the referenced element is currently intersecting.
|
|
45
|
+
*/
|
|
25
46
|
export declare function useIsIntersecting(elementRef: RefObject<Element | null>): boolean;
|
|
26
|
-
export declare function useIsIntersectingListener(elementRef: RefObject<Element | null>, onChange: (isIntersecting: boolean) => void): void;
|