@jetbrains/ring-ui 8.0.0-beta.2 → 8.0.0-beta.4
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 -1
- package/components/auth-dialog-service/auth-dialog-service.js +2 -2
- package/components/checkbox/checkbox.d.ts +1 -1
- package/components/collapse/collapse-content.js +2 -2
- package/components/collapse/collapse-control.js +2 -2
- package/components/collapse/collapse.js +2 -2
- package/components/collapsible-group/collapsible-group.css +138 -0
- package/components/collapsible-group/collapsible-group.d.ts +20 -0
- package/components/collapsible-group/collapsible-group.js +73 -0
- package/components/confirm-service/confirm-service.js +2 -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/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.d.ts +2 -2
- package/components/dialog/dialog.js +2 -2
- 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/expand/collapsible-group.css +23 -89
- package/components/expand/collapsible-group.d.ts +8 -16
- package/components/expand/collapsible-group.js +13 -72
- 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/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/i18n/i18n-context.js +1 -1
- 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/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/login-dialog/service.js +2 -2
- 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 +1 -1
- package/components/select/select.d.ts +4 -2
- 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 +35 -11
- package/components/table/default-item-renderer.js +47 -47
- package/components/table/internal/column-animation.d.ts +16 -0
- package/components/table/internal/column-animation.js +45 -0
- package/components/table/internal/table-header.d.ts +4 -0
- package/components/table/internal/table-header.js +357 -0
- package/components/table/internal/virtual-items.d.ts +34 -0
- package/components/table/{table-virtualize.js → internal/virtual-items.js} +78 -44
- package/components/table/item-virtualization.d.ts +35 -0
- package/components/table/item-virtualization.js +28 -0
- package/components/table/table-const.d.ts +40 -6
- package/components/table/table-const.js +14 -5
- package/components/table/table-primitives.d.ts +21 -0
- package/components/table/table-primitives.js +25 -0
- package/components/table/table-props.d.ts +280 -0
- package/components/table/table-props.js +1 -0
- package/components/table/table.css +171 -66
- package/components/table/table.d.ts +205 -224
- package/components/table/table.js +298 -2
- package/components/tags-input/tags-input.d.ts +3 -1
- package/components/tooltip/tooltip.js +2 -2
- package/components/upload/upload.d.ts +4 -3
- package/components/upload/upload.js +3 -7
- package/components/user-agreement/service.js +2 -2
- package/components/util-stories.d.ts +26 -0
- package/components/util-stories.js +61 -0
- package/package.json +41 -41
- package/components/date-picker/use-intersection-observer.d.ts +0 -6
- package/components/date-picker/use-intersection-observer.js +0 -48
- 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/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
|
@@ -1,2 +1,298 @@
|
|
|
1
|
-
import
|
|
2
|
-
|
|
1
|
+
import React, { Fragment, useCallback, useRef } from 'react';
|
|
2
|
+
import classNames from 'classnames';
|
|
3
|
+
import { IntersectionObserverContext } from '../global/intersection-observer-context';
|
|
4
|
+
import { CollapseItemIntoSpacerContext, SpacerRow, useVirtualItems } from './internal/virtual-items';
|
|
5
|
+
import { DefaultItemRenderer } from './default-item-renderer';
|
|
6
|
+
import { ColumnAnimationContext, defaultRowHeight, TablePropsContext } from './table-const';
|
|
7
|
+
import { focusWithTemporaryTabIndex } from '../global/focus-with-temporary-tabindex';
|
|
8
|
+
import { useColumnAnimation } from './internal/column-animation';
|
|
9
|
+
import { useComposedRef } from '../global/compose-refs';
|
|
10
|
+
import { TableHeader } from './internal/table-header';
|
|
11
|
+
import { keyboardFocusableAttrName } from './table-primitives';
|
|
12
|
+
import { isWithinNavigableElement } from '../global/is-within-navigable-element';
|
|
13
|
+
import styles from './table.css';
|
|
14
|
+
/**
|
|
15
|
+
* Table component replacing the tables in the `legacy-table` folder.
|
|
16
|
+
*
|
|
17
|
+
* This documentation provides an overview of the most common usage patterns.
|
|
18
|
+
* See individual props and exported components for detailed behavior.
|
|
19
|
+
*
|
|
20
|
+
* ## Minimal usage
|
|
21
|
+
*
|
|
22
|
+
* You need the following props:
|
|
23
|
+
* - `data`
|
|
24
|
+
* - `getKey`
|
|
25
|
+
* - `columns`
|
|
26
|
+
* - `key`
|
|
27
|
+
* - `name` (optional but needed in most cases)
|
|
28
|
+
* - `renderCell` (optional but needed in most cases)
|
|
29
|
+
*
|
|
30
|
+
* ## Item rendering
|
|
31
|
+
*
|
|
32
|
+
* If `renderItem` is not specified, each item is rendered using
|
|
33
|
+
* `DefaultItemRenderer` (from `table/default-item-renderer`)
|
|
34
|
+
* as if the following code were used:
|
|
35
|
+
*
|
|
36
|
+
* ```tsx
|
|
37
|
+
* <Table
|
|
38
|
+
* renderItem={(_item, index, _items) => (
|
|
39
|
+
* <DefaultItemRenderer index={index} />
|
|
40
|
+
* )}
|
|
41
|
+
* />
|
|
42
|
+
* ```
|
|
43
|
+
*
|
|
44
|
+
* `DefaultItemRenderer` renders a table row using the column definitions
|
|
45
|
+
* (`Column.renderCell`) and provides built-in support for features such as
|
|
46
|
+
* selection, keyboard navigation, and virtualization. It also accepts all
|
|
47
|
+
* standard `tr` attributes, including `ref`.
|
|
48
|
+
*
|
|
49
|
+
* Use `renderItem` to configure `DefaultItemRenderer` for each item:
|
|
50
|
+
*
|
|
51
|
+
* ```tsx
|
|
52
|
+
* <Table
|
|
53
|
+
* renderItem={(item, index, items) => (
|
|
54
|
+
* <DefaultItemRenderer
|
|
55
|
+
* index={index}
|
|
56
|
+
* keyboardFocusable
|
|
57
|
+
* className='my-item'
|
|
58
|
+
* onClick={e => handleClick(e, item, items)}
|
|
59
|
+
* />
|
|
60
|
+
* )}
|
|
61
|
+
* />
|
|
62
|
+
* ```
|
|
63
|
+
*
|
|
64
|
+
* If you need complete control over rendering, `renderItem` can instead
|
|
65
|
+
* return your own table rows. See "Custom item rendering" below.
|
|
66
|
+
*
|
|
67
|
+
* ## Selection
|
|
68
|
+
*
|
|
69
|
+
* Selection is typically implemented using the following props
|
|
70
|
+
* of the `DefaultItemRenderer`:
|
|
71
|
+
*
|
|
72
|
+
* - `clickable`
|
|
73
|
+
* - `selected`
|
|
74
|
+
* - `onClick` or `onPointerUp`, etc.
|
|
75
|
+
*
|
|
76
|
+
* The following utilities (from `global`) may come in handy:
|
|
77
|
+
*
|
|
78
|
+
* - `TableSelection` class to manage selection state
|
|
79
|
+
* - An alternative approach is to keep a `selected` field on each item
|
|
80
|
+
* - `isWithinInteractiveElement()` to check if a click was made on a control
|
|
81
|
+
* or on "empty space"
|
|
82
|
+
*
|
|
83
|
+
* ```tsx
|
|
84
|
+
* <Table
|
|
85
|
+
* renderItem={(item, index) => (
|
|
86
|
+
* <DefaultItemRenderer
|
|
87
|
+
* index={index}
|
|
88
|
+
* clickable
|
|
89
|
+
* selected={selection.isSelected(item)}
|
|
90
|
+
* onClick={e => {
|
|
91
|
+
* if (!isWithinInteractiveElement(e)) {
|
|
92
|
+
* setSelection(selection.toggleSelection(item));
|
|
93
|
+
* }
|
|
94
|
+
* }}
|
|
95
|
+
* />
|
|
96
|
+
* )}
|
|
97
|
+
* />
|
|
98
|
+
* ```
|
|
99
|
+
*
|
|
100
|
+
* Note that for accessibility reasons, you should have a cell with a checkbox
|
|
101
|
+
* to display and toggle item selection.
|
|
102
|
+
*
|
|
103
|
+
* ## Rows focus
|
|
104
|
+
*
|
|
105
|
+
* The table implements the ["roving tabindex"](https://developer.mozilla.org/en-US/docs/Web/Accessibility/Guides/Keyboard-navigable_JavaScript_widgets#technique_1_roving_tabindex)
|
|
106
|
+
* technique to focus rows with the up/down arrow keys.
|
|
107
|
+
* Rows can also be focused on click or other pointer events.
|
|
108
|
+
* To support it, use the following props of the `DefaultItemRenderer`:
|
|
109
|
+
*
|
|
110
|
+
* - `keyboardFocusable`
|
|
111
|
+
* - `clickable`, if you want to react to hover
|
|
112
|
+
* - `onClick`, if you want to focus on click
|
|
113
|
+
*
|
|
114
|
+
* Useful utils:
|
|
115
|
+
* - `focusWithTemporaryTabIndex()` from `global` to focus a row temporarily
|
|
116
|
+
* patching its `tabindex`.
|
|
117
|
+
*
|
|
118
|
+
* ```tsx
|
|
119
|
+
* <Table
|
|
120
|
+
* renderItem={(item, index) => (
|
|
121
|
+
* <DefaultItemRenderer
|
|
122
|
+
* index={index}
|
|
123
|
+
* clickable
|
|
124
|
+
* keyboardFocusable
|
|
125
|
+
* onClick={e => {
|
|
126
|
+
* if (!isWithinInteractiveElement(e)) {
|
|
127
|
+
* focusWithTemporaryTabIndex(e.currentTarget);
|
|
128
|
+
* }
|
|
129
|
+
* }}
|
|
130
|
+
* />
|
|
131
|
+
* )}
|
|
132
|
+
* />
|
|
133
|
+
* ```
|
|
134
|
+
*
|
|
135
|
+
* Note that the table does not implement standard accessibility patterns such
|
|
136
|
+
* as `grid` or `treegrid`, so row focus is not announced by screen readers.
|
|
137
|
+
* Make sure all essential actions remain available without row focus, for
|
|
138
|
+
* example via standard Tab navigation.
|
|
139
|
+
*
|
|
140
|
+
* ## Sorting
|
|
141
|
+
*
|
|
142
|
+
* You need the following to support sorting:
|
|
143
|
+
*
|
|
144
|
+
* - Set `Column.sortOrder` to `'none'`, `'ascending'` or `'descending'`
|
|
145
|
+
* to render the sort button, `aria-sort`, and indicate the current
|
|
146
|
+
* sort order.
|
|
147
|
+
* - Handle `TableProps.onSort` callback in the client code.
|
|
148
|
+
*
|
|
149
|
+
* ## Deleting columns
|
|
150
|
+
*
|
|
151
|
+
* You need the following to support deleting columns:
|
|
152
|
+
*
|
|
153
|
+
* - Set `Column.deletable` to `true`. This will render a delete button in the
|
|
154
|
+
* column header.
|
|
155
|
+
* - Make sure the `column` has a proper `name` or `key` prop, which will be
|
|
156
|
+
* automatically included in the aria-label of the column delete button.
|
|
157
|
+
* - Handle `TableProps.onColumnDelete` callback in the client code. It is
|
|
158
|
+
* expected to update `columns` by removing the corresponding column.
|
|
159
|
+
*
|
|
160
|
+
* ## Moving columns
|
|
161
|
+
*
|
|
162
|
+
* - Set `Column.canReorder` to `true` or to predicate specifying possible
|
|
163
|
+
* insertion targets.
|
|
164
|
+
* This will render a reorder button in the column header.
|
|
165
|
+
* - Make sure the `column` has a proper `name` or `key` prop, which will be
|
|
166
|
+
* automatically included in the aria-label of the column reorder button.
|
|
167
|
+
* - Handle `TableProps.onColumnReorder` callback in the client code. It is
|
|
168
|
+
* expected to update `columns` by moving the corresponding column to the
|
|
169
|
+
* new position.
|
|
170
|
+
*
|
|
171
|
+
* ## Row virtualization
|
|
172
|
+
*
|
|
173
|
+
* To render only rows near the viewport while replacing off-screen rows with
|
|
174
|
+
* spacers, use:
|
|
175
|
+
*
|
|
176
|
+
* - `virtualizeRows` prop set to `true`
|
|
177
|
+
* - `scrollerRef` — required when the scrollable container is not the whole
|
|
178
|
+
* document
|
|
179
|
+
* - `estimateHeight` — recommended when rows are expected to be taller than
|
|
180
|
+
* the default height (e.g. multiline or custom content)
|
|
181
|
+
* - Fine-tuning props: `lookaheadPx`, `retentionMarginPx`,
|
|
182
|
+
* `minScrollAndResizeDeltaPx`
|
|
183
|
+
*
|
|
184
|
+
* ## Custom item rendering
|
|
185
|
+
*
|
|
186
|
+
* Use the `renderItem` prop to render an item in a completely custom way.
|
|
187
|
+
* The prop is expected to return one or more table rows for the item.
|
|
188
|
+
* Use `TableRow` and `TableCell` from `table/table-primitives` to apply
|
|
189
|
+
* the default row and cell styles.
|
|
190
|
+
*
|
|
191
|
+
* ### Focus
|
|
192
|
+
*
|
|
193
|
+
* Just like `DefaultItemRenderer`, `TableRow` accepts the
|
|
194
|
+
* `keyboardFocusable` prop.
|
|
195
|
+
*
|
|
196
|
+
* Focusable rows rendered by either component form a single keyboard
|
|
197
|
+
* navigation sequence.
|
|
198
|
+
*
|
|
199
|
+
* ### Virtualization
|
|
200
|
+
*
|
|
201
|
+
* If `Table.virtualizeRows` is set to `true`, you need to handle visibility
|
|
202
|
+
* for your custom-rendered component yourself with the
|
|
203
|
+
* `useItemVirtualization()` hook (from `table/item-virtualization`). The hook
|
|
204
|
+
* allows observing the intersection of one or multiple elements rendered for
|
|
205
|
+
* the item, and, based on their intersection status, reporting the item as
|
|
206
|
+
* eligible for virtualization.
|
|
207
|
+
*
|
|
208
|
+
* If you use `DefaultItemRenderer` as part of your custom row renderer,
|
|
209
|
+
* set the `noItemVirtualization` prop to `true`, otherwise it will also try
|
|
210
|
+
* to control the virtualization, possibly reporting incorrect item height.
|
|
211
|
+
*
|
|
212
|
+
* ### Column reorder animation
|
|
213
|
+
*
|
|
214
|
+
* Default-rendered rows highlight the column that was just reordered. To apply
|
|
215
|
+
* the same animation to your custom-rendered rows, use `ColumnAnimationContext`
|
|
216
|
+
* (from `table/table-const`) to get information about the currently animated column.
|
|
217
|
+
*/
|
|
218
|
+
export default function Table(props) {
|
|
219
|
+
const { data, columns, getKey, noHeader, stickyHeader, onSort, onColumnDelete, onColumnReorder, noColumnReorderAnimation, renderItem, virtualizeRows = false, scrollerRef, estimateHeight = () => defaultRowHeight,
|
|
220
|
+
// eslint-disable-next-line no-magic-numbers
|
|
221
|
+
lookaheadPx = 400,
|
|
222
|
+
// eslint-disable-next-line no-magic-numbers
|
|
223
|
+
retentionMarginPx = 450,
|
|
224
|
+
// eslint-disable-next-line no-magic-numbers
|
|
225
|
+
minScrollAndResizeDeltaPx = 50, columnEditing, onColumnEditingRequest, columnEditButton, theadClassName, theadTrClassName, tbodyClassName, ref: userRef, className, ...restProps } = props;
|
|
226
|
+
const localRef = useRef(null);
|
|
227
|
+
const { virtualItems, intersectionObserverHandle, collapseItemIntoSpacer } = useVirtualItems({
|
|
228
|
+
enabled: virtualizeRows,
|
|
229
|
+
data,
|
|
230
|
+
scrollerRef,
|
|
231
|
+
tableRef: localRef,
|
|
232
|
+
estimateHeight,
|
|
233
|
+
lookaheadPx,
|
|
234
|
+
retentionMarginPx,
|
|
235
|
+
minScrollAndResizeDeltaPx,
|
|
236
|
+
});
|
|
237
|
+
const { columnAnimation, expectColumnReorder } = useColumnAnimation({
|
|
238
|
+
disabled: noColumnReorderAnimation,
|
|
239
|
+
tableRef: localRef,
|
|
240
|
+
columns,
|
|
241
|
+
});
|
|
242
|
+
const handleRowNavigation = useCallback((e) => {
|
|
243
|
+
if (e.defaultPrevented || isWithinNavigableElement(e.target))
|
|
244
|
+
return;
|
|
245
|
+
const arrowUp = e.key === 'ArrowUp';
|
|
246
|
+
const arrowDown = e.key === 'ArrowDown';
|
|
247
|
+
if (!arrowUp && !arrowDown)
|
|
248
|
+
return;
|
|
249
|
+
const currentRow = e.target.closest('tr');
|
|
250
|
+
if (currentRow?.parentElement?.parentElement !== localRef.current) {
|
|
251
|
+
return;
|
|
252
|
+
}
|
|
253
|
+
let candidate = currentRow;
|
|
254
|
+
while (candidate) {
|
|
255
|
+
candidate = (arrowUp ? candidate.previousElementSibling : candidate.nextElementSibling);
|
|
256
|
+
if (candidate?.hasAttribute(keyboardFocusableAttrName)) {
|
|
257
|
+
focusWithTemporaryTabIndex(candidate);
|
|
258
|
+
e.preventDefault();
|
|
259
|
+
return;
|
|
260
|
+
}
|
|
261
|
+
}
|
|
262
|
+
}, []);
|
|
263
|
+
return (<TablePropsContext value={props}>
|
|
264
|
+
<ColumnAnimationContext value={columnAnimation}>
|
|
265
|
+
<table className={classNames(styles.table, className)} ref={useComposedRef(userRef, localRef)} {...restProps}>
|
|
266
|
+
<TableHeader expectColumnReorder={expectColumnReorder}/>
|
|
267
|
+
<IntersectionObserverContext value={intersectionObserverHandle}>
|
|
268
|
+
<CollapseItemIntoSpacerContext value={collapseItemIntoSpacer}>
|
|
269
|
+
{/* eslint-disable-next-line jsx-a11y/no-noninteractive-element-interactions */}
|
|
270
|
+
<tbody className={tbodyClassName} onKeyDown={handleRowNavigation}>
|
|
271
|
+
{(virtualizeRows ? virtualItems : data).map((item, index) => {
|
|
272
|
+
let dataItem;
|
|
273
|
+
let dataItemIndex;
|
|
274
|
+
if (virtualizeRows) {
|
|
275
|
+
const virtualItem = item;
|
|
276
|
+
if (virtualItem.type === 'spacer') {
|
|
277
|
+
return <SpacerRow key={virtualItem.key} spacer={virtualItem} colSpan={columns.length}/>;
|
|
278
|
+
}
|
|
279
|
+
dataItemIndex = virtualItem.index;
|
|
280
|
+
if (dataItemIndex < 0 || dataItemIndex >= data.length)
|
|
281
|
+
return null;
|
|
282
|
+
dataItem = data[dataItemIndex];
|
|
283
|
+
}
|
|
284
|
+
else {
|
|
285
|
+
dataItem = item;
|
|
286
|
+
dataItemIndex = index;
|
|
287
|
+
}
|
|
288
|
+
return (<Fragment key={getKey(dataItem, dataItemIndex, data)}>
|
|
289
|
+
{renderItem ? (renderItem(dataItem, dataItemIndex, data)) : (<DefaultItemRenderer index={dataItemIndex}/>)}
|
|
290
|
+
</Fragment>);
|
|
291
|
+
})}
|
|
292
|
+
</tbody>
|
|
293
|
+
</CollapseItemIntoSpacerContext>
|
|
294
|
+
</IntersectionObserverContext>
|
|
295
|
+
</table>
|
|
296
|
+
</ColumnAnimationContext>
|
|
297
|
+
</TablePropsContext>);
|
|
298
|
+
}
|
|
@@ -110,6 +110,8 @@ export default class TagsInput extends PureComponent<TagsInputProps, TagsInputSt
|
|
|
110
110
|
selectRef: (el: Select | null) => void;
|
|
111
111
|
render(): React.JSX.Element;
|
|
112
112
|
}
|
|
113
|
-
export declare const RerenderableTagsInput:
|
|
113
|
+
export declare const RerenderableTagsInput: ({ ref, ...props }: TagsInputProps & {
|
|
114
|
+
ref?: React.Ref<TagsInput> | undefined;
|
|
115
|
+
}) => React.JSX.Element;
|
|
114
116
|
export type TagsInputAttrs = React.JSX.LibraryManagedAttributes<typeof TagsInput, TagsInputProps>;
|
|
115
117
|
export {};
|
|
@@ -135,13 +135,13 @@ export default class Tooltip extends Component {
|
|
|
135
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)}>
|
|
136
136
|
{title}
|
|
137
137
|
</Popup>);
|
|
138
|
-
return (<TooltipContext
|
|
138
|
+
return (<TooltipContext value={{ onNestedTooltipShow, onNestedTooltipHide }}>
|
|
139
139
|
<span {...ariaProps} {...restProps} ref={this.containerRef} data-test={dataTests('ring-tooltip', dataTest)} data-test-title={typeof title === 'string' ? title : undefined}>
|
|
140
140
|
{children}
|
|
141
141
|
{theme === 'inherit' ? (popup) : (<ThemeProvider theme={theme} passToPopups WrapperComponent={props => <span {...props}/>}>
|
|
142
142
|
{popup}
|
|
143
143
|
</ThemeProvider>)}
|
|
144
144
|
</span>
|
|
145
|
-
</TooltipContext
|
|
145
|
+
</TooltipContext>);
|
|
146
146
|
}
|
|
147
147
|
}
|
|
@@ -1,4 +1,4 @@
|
|
|
1
|
-
import { type ReactNode } from 'react';
|
|
1
|
+
import { type ReactNode, type Ref } from 'react';
|
|
2
2
|
export type UploadVariant = 'empty' | 'error' | 'success';
|
|
3
3
|
interface Props {
|
|
4
4
|
className?: string;
|
|
@@ -10,10 +10,11 @@ interface Props {
|
|
|
10
10
|
accept?: HTMLInputElement['accept'];
|
|
11
11
|
disabled?: boolean;
|
|
12
12
|
variant?: UploadVariant;
|
|
13
|
+
ref?: Ref<UploadHandle>;
|
|
13
14
|
children?: ReactNode;
|
|
14
15
|
}
|
|
15
16
|
export interface UploadHandle {
|
|
16
17
|
openFilePicker: () => void;
|
|
17
18
|
}
|
|
18
|
-
export
|
|
19
|
-
export
|
|
19
|
+
export default function UploadInner({ children, className, onFilesSelected, onFilesRejected, validate, variant, multiple, renderIcon, accept, disabled, ref, }: Props): import("react").JSX.Element;
|
|
20
|
+
export {};
|
|
@@ -1,13 +1,13 @@
|
|
|
1
|
-
import {
|
|
1
|
+
import { useImperativeHandle, useRef, useState } from 'react';
|
|
2
2
|
import classNames from 'classnames';
|
|
3
3
|
import attachmentIcon from '@jetbrains/icons/attachment';
|
|
4
4
|
import Icon from '../icon';
|
|
5
5
|
import styles from './upload.css';
|
|
6
6
|
const defaultRenderIcon = () => <Icon className={styles.attachmentIcon} glyph={attachmentIcon}/>;
|
|
7
|
-
function UploadInner({ children, className, onFilesSelected, onFilesRejected, validate = () => true, variant = 'empty', multiple, renderIcon = defaultRenderIcon, accept, disabled,
|
|
7
|
+
export default function UploadInner({ children, className, onFilesSelected, onFilesRejected, validate = () => true, variant = 'empty', multiple, renderIcon = defaultRenderIcon, accept, disabled, ref, }) {
|
|
8
8
|
const fileInputRef = useRef(null);
|
|
9
9
|
const [dragOver, setDragOver] = useState(false);
|
|
10
|
-
useImperativeHandle(
|
|
10
|
+
useImperativeHandle(ref, () => ({ openFilePicker: () => fileInputRef.current?.click() }), []);
|
|
11
11
|
const handleSelectedFiles = (files) => {
|
|
12
12
|
if (!files.length) {
|
|
13
13
|
return;
|
|
@@ -39,7 +39,3 @@ function UploadInner({ children, className, onFilesSelected, onFilesRejected, va
|
|
|
39
39
|
{children}
|
|
40
40
|
</div>);
|
|
41
41
|
}
|
|
42
|
-
export const Upload = forwardRef(function Upload(props, ref) {
|
|
43
|
-
return <UploadInner {...props} forwardedRef={ref}/>;
|
|
44
|
-
});
|
|
45
|
-
export default Upload;
|
|
@@ -188,9 +188,9 @@ export default class UserAgreementService {
|
|
|
188
188
|
preview,
|
|
189
189
|
...restOptions,
|
|
190
190
|
};
|
|
191
|
-
this.reactRoot.render(<ControlsHeightContext
|
|
191
|
+
this.reactRoot.render(<ControlsHeightContext value={getGlobalControlsHeight()}>
|
|
192
192
|
<UserAgreement {...props}/>
|
|
193
|
-
</ControlsHeightContext
|
|
193
|
+
</ControlsHeightContext>);
|
|
194
194
|
if (onDialogShow) {
|
|
195
195
|
onDialogShow();
|
|
196
196
|
}
|
|
@@ -1 +1,27 @@
|
|
|
1
1
|
export declare const hideAddonsPanelParam = "hideAddonsPanel";
|
|
2
|
+
export declare function createRandom(seed: bigint): {
|
|
3
|
+
/**
|
|
4
|
+
* Fractional in [0, 1)
|
|
5
|
+
*/
|
|
6
|
+
(): number;
|
|
7
|
+
/**
|
|
8
|
+
* Integer in [0, to)
|
|
9
|
+
*/
|
|
10
|
+
(to: number): number;
|
|
11
|
+
/**
|
|
12
|
+
* Integer in [from, to)
|
|
13
|
+
*/
|
|
14
|
+
(from: number, to: number): number;
|
|
15
|
+
/**
|
|
16
|
+
* Date in [from, to)
|
|
17
|
+
*/
|
|
18
|
+
(from: Date, to: Date): Date;
|
|
19
|
+
/**
|
|
20
|
+
* Up to random n items (in random order) from the array
|
|
21
|
+
*/
|
|
22
|
+
<T>(array: T[], n: number): T[];
|
|
23
|
+
/**
|
|
24
|
+
* Random item from the array
|
|
25
|
+
*/
|
|
26
|
+
<T>(array: T[]): T;
|
|
27
|
+
};
|
|
@@ -1 +1,62 @@
|
|
|
1
|
+
/* eslint-disable no-magic-numbers */
|
|
1
2
|
export const hideAddonsPanelParam = 'hideAddonsPanel';
|
|
3
|
+
export function createRandom(seed) {
|
|
4
|
+
const u64Mask = 2n ** 64n - 1n;
|
|
5
|
+
const u64Range = 2n ** 64n;
|
|
6
|
+
const scrambleConst = 2685821657736338717n;
|
|
7
|
+
let x = seed & u64Mask;
|
|
8
|
+
if (!x)
|
|
9
|
+
throw new Error('Seed must be non-zero');
|
|
10
|
+
function nextFractional() {
|
|
11
|
+
x ^= x >> 12n;
|
|
12
|
+
x ^= (x << 25n) & u64Mask;
|
|
13
|
+
x ^= x >> 27n;
|
|
14
|
+
const scrambled = (x * scrambleConst) & u64Mask;
|
|
15
|
+
return Number(scrambled) / Number(u64Range);
|
|
16
|
+
}
|
|
17
|
+
// eslint-disable-next-line @typescript-eslint/no-explicit-any
|
|
18
|
+
return (...args) => {
|
|
19
|
+
if (!args.length) {
|
|
20
|
+
return nextFractional();
|
|
21
|
+
}
|
|
22
|
+
if (args.length === 1) {
|
|
23
|
+
const [a] = args;
|
|
24
|
+
if (typeof a === 'number') {
|
|
25
|
+
return Math.floor(nextFractional() * a);
|
|
26
|
+
}
|
|
27
|
+
if (Array.isArray(a)) {
|
|
28
|
+
return a[Math.floor(nextFractional() * a.length)];
|
|
29
|
+
}
|
|
30
|
+
}
|
|
31
|
+
if (args.length === 2) {
|
|
32
|
+
const [a, b] = args;
|
|
33
|
+
let fromNum;
|
|
34
|
+
let toNum;
|
|
35
|
+
let isDate = false;
|
|
36
|
+
if (typeof a === 'number' && typeof b === 'number') {
|
|
37
|
+
fromNum = a;
|
|
38
|
+
toNum = b;
|
|
39
|
+
}
|
|
40
|
+
if (a instanceof Date && b instanceof Date) {
|
|
41
|
+
fromNum = a.getTime();
|
|
42
|
+
toNum = b.getTime();
|
|
43
|
+
isDate = true;
|
|
44
|
+
}
|
|
45
|
+
if (fromNum != null && toNum != null && fromNum < toNum) {
|
|
46
|
+
const r = Math.floor(nextFractional() * (toNum - fromNum)) + fromNum;
|
|
47
|
+
return isDate ? new Date(r) : r;
|
|
48
|
+
}
|
|
49
|
+
if (Array.isArray(a) && typeof b === 'number') {
|
|
50
|
+
const aIndices = Array.from({ length: a.length }, (_, i) => i);
|
|
51
|
+
const sample = [];
|
|
52
|
+
for (let i = 0; i < b && aIndices.length; i++) {
|
|
53
|
+
const indexIndex = Math.floor(nextFractional() * aIndices.length);
|
|
54
|
+
const [aIndex] = aIndices.splice(indexIndex, 1);
|
|
55
|
+
sample.push(a[aIndex]);
|
|
56
|
+
}
|
|
57
|
+
return sample;
|
|
58
|
+
}
|
|
59
|
+
}
|
|
60
|
+
throw new Error(`Bad args: ${JSON.stringify(args)}`);
|
|
61
|
+
};
|
|
62
|
+
}
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@jetbrains/ring-ui",
|
|
3
|
-
"version": "8.0.0-beta.
|
|
3
|
+
"version": "8.0.0-beta.4",
|
|
4
4
|
"description": "JetBrains UI library",
|
|
5
5
|
"author": {
|
|
6
6
|
"name": "JetBrains"
|
|
@@ -99,29 +99,29 @@
|
|
|
99
99
|
},
|
|
100
100
|
"readmeFilename": "README.md",
|
|
101
101
|
"devDependencies": {
|
|
102
|
-
"@babel/cli": "^
|
|
103
|
-
"@babel/eslint-parser": "^7.
|
|
102
|
+
"@babel/cli": "^8.0.1",
|
|
103
|
+
"@babel/eslint-parser": "^7.29.7",
|
|
104
104
|
"@csstools/css-parser-algorithms": "^4.0.0",
|
|
105
105
|
"@csstools/stylelint-no-at-nest-rule": "^5.0.0",
|
|
106
106
|
"@eslint/compat": "^2.1.0",
|
|
107
107
|
"@eslint/eslintrc": "^3.3.5",
|
|
108
108
|
"@eslint/js": "^10.0.1",
|
|
109
|
-
"@figma/code-connect": "^1.4.
|
|
109
|
+
"@figma/code-connect": "^1.4.8",
|
|
110
110
|
"@jetbrains/eslint-config": "^6.0.5",
|
|
111
111
|
"@jetbrains/logos": "3.0.0-canary.734b213.0",
|
|
112
112
|
"@jetbrains/rollup-css-plugin": "./packages/rollup-css-plugin",
|
|
113
113
|
"@jetbrains/stylelint-config": "^4.0.2",
|
|
114
114
|
"@jetbrains/typescript-plugin-css-modules": "^5.3.1",
|
|
115
|
-
"@primer/octicons": "^19.
|
|
116
|
-
"@rollup/plugin-babel": "^7.
|
|
115
|
+
"@primer/octicons": "^19.28.1",
|
|
116
|
+
"@rollup/plugin-babel": "^7.1.0",
|
|
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.4.
|
|
121
|
-
"@storybook/addon-docs": "^10.4.
|
|
122
|
-
"@storybook/addon-themes": "^10.4.
|
|
120
|
+
"@storybook/addon-a11y": "10.4.6",
|
|
121
|
+
"@storybook/addon-docs": "^10.4.6",
|
|
122
|
+
"@storybook/addon-themes": "^10.4.6",
|
|
123
123
|
"@storybook/csf": "^0.1.13",
|
|
124
|
-
"@storybook/react-webpack5": "10.4.
|
|
124
|
+
"@storybook/react-webpack5": "10.4.6",
|
|
125
125
|
"@storybook/test-runner": "^0.24.4",
|
|
126
126
|
"@testing-library/dom": "^10.4.1",
|
|
127
127
|
"@testing-library/react": "^16.3.2",
|
|
@@ -129,33 +129,33 @@
|
|
|
129
129
|
"@types/chai-as-promised": "^8.0.2",
|
|
130
130
|
"@types/chai-dom": "1.11.3",
|
|
131
131
|
"@types/markdown-it": "^14.1.2",
|
|
132
|
-
"@types/react": "^19.2.
|
|
132
|
+
"@types/react": "^19.2.17",
|
|
133
133
|
"@types/react-dom": "^19.2.3",
|
|
134
134
|
"@types/webpack-env": "^1.18.8",
|
|
135
135
|
"@vitejs/plugin-react": "^6.0.2",
|
|
136
|
-
"@vitest/eslint-plugin": "^1.6.
|
|
137
|
-
"acorn": "^8.
|
|
136
|
+
"@vitest/eslint-plugin": "^1.6.20",
|
|
137
|
+
"acorn": "^8.17.0",
|
|
138
138
|
"babel-plugin-require-context-hook": "^1.0.0",
|
|
139
|
-
"caniuse-lite": "^1.0.
|
|
139
|
+
"caniuse-lite": "^1.0.30001799",
|
|
140
140
|
"chai-as-promised": "^8.0.2",
|
|
141
141
|
"chai-dom": "^1.12.1",
|
|
142
142
|
"cheerio": "^1.2.0",
|
|
143
143
|
"core-js": "^3.49.0",
|
|
144
144
|
"cpy-cli": "^7.0.0",
|
|
145
145
|
"dotenv-cli": "^11.0.0",
|
|
146
|
-
"eslint": "^9.39.
|
|
146
|
+
"eslint": "^9.39.4",
|
|
147
147
|
"eslint-config-prettier": "^10.1.8",
|
|
148
148
|
"eslint-formatter-jslint-xml": "^9.0.1",
|
|
149
149
|
"eslint-import-resolver-exports": "^1.0.0-beta.5",
|
|
150
|
-
"eslint-import-resolver-typescript": "^4.4.
|
|
150
|
+
"eslint-import-resolver-typescript": "^4.4.5",
|
|
151
151
|
"eslint-import-resolver-webpack": "^0.13.11",
|
|
152
152
|
"eslint-plugin-import": "^2.32.0",
|
|
153
153
|
"eslint-plugin-jsx-a11y": "^6.10.2",
|
|
154
|
-
"eslint-plugin-prettier": "^5.5.
|
|
154
|
+
"eslint-plugin-prettier": "^5.5.6",
|
|
155
155
|
"eslint-plugin-react": "^7.37.5",
|
|
156
156
|
"eslint-plugin-react-hooks": "^7.1.1",
|
|
157
|
-
"eslint-plugin-storybook": "^10.4.
|
|
158
|
-
"eslint-plugin-unicorn": "^
|
|
157
|
+
"eslint-plugin-storybook": "^10.4.6",
|
|
158
|
+
"eslint-plugin-unicorn": "^68.0.0",
|
|
159
159
|
"events": "^3.3.0",
|
|
160
160
|
"glob": "^13.0.6",
|
|
161
161
|
"globals": "^17.6.0",
|
|
@@ -166,41 +166,41 @@
|
|
|
166
166
|
"jest": "~30.4.2",
|
|
167
167
|
"jest-environment-jsdom": "^30.4.1",
|
|
168
168
|
"jest-teamcity": "^1.12.0",
|
|
169
|
-
"lint-staged": "^17.0.
|
|
169
|
+
"lint-staged": "^17.0.8",
|
|
170
170
|
"markdown-it": "^14.2.0",
|
|
171
171
|
"merge-options": "^3.0.4",
|
|
172
172
|
"pinst": "^3.0.0",
|
|
173
|
-
"prettier": "^3.8.
|
|
173
|
+
"prettier": "^3.8.4",
|
|
174
174
|
"raw-loader": "^4.0.2",
|
|
175
|
-
"react": "^19.2.
|
|
176
|
-
"react-dom": "^19.2.
|
|
175
|
+
"react": "^19.2.7",
|
|
176
|
+
"react-dom": "^19.2.7",
|
|
177
177
|
"regenerator-runtime": "^0.14.1",
|
|
178
178
|
"rimraf": "^6.1.3",
|
|
179
|
-
"rollup": "^4.
|
|
179
|
+
"rollup": "^4.62.2",
|
|
180
180
|
"rollup-plugin-clear": "^2.0.7",
|
|
181
181
|
"storage-mock": "^2.1.0",
|
|
182
|
-
"storybook": "10.4.
|
|
183
|
-
"stylelint": "^17.
|
|
182
|
+
"storybook": "10.4.6",
|
|
183
|
+
"stylelint": "^17.13.0",
|
|
184
184
|
"stylelint-config-sass-guidelines": "^13.0.0",
|
|
185
185
|
"svg-inline-loader": "^0.8.2",
|
|
186
186
|
"teamcity-service-messages": "^0.1.14",
|
|
187
|
-
"terser-webpack-plugin": "^5.6.
|
|
187
|
+
"terser-webpack-plugin": "^5.6.1",
|
|
188
188
|
"typed-css-modules": "^0.9.1",
|
|
189
189
|
"typescript": "~6.0.3",
|
|
190
|
-
"typescript-eslint": "^8.
|
|
191
|
-
"vite": "^8.0.
|
|
192
|
-
"vitest": "^4.1.
|
|
190
|
+
"typescript-eslint": "^8.61.1",
|
|
191
|
+
"vite": "^8.0.16",
|
|
192
|
+
"vitest": "^4.1.9",
|
|
193
193
|
"vitest-teamcity-reporter": "^0.4.1",
|
|
194
|
-
"webpack": "^5.107.
|
|
195
|
-
"webpack-cli": "^7.0.
|
|
194
|
+
"webpack": "^5.107.2",
|
|
195
|
+
"webpack-cli": "^7.0.3",
|
|
196
196
|
"xmlappend": "^1.0.4"
|
|
197
197
|
},
|
|
198
198
|
"peerDependencies": {
|
|
199
|
-
"@types/react": ">=
|
|
200
|
-
"@types/react-dom": ">=
|
|
199
|
+
"@types/react": ">=19.2.0",
|
|
200
|
+
"@types/react-dom": ">=19.2.0",
|
|
201
201
|
"core-js": ">=3.0.0",
|
|
202
|
-
"react": ">=
|
|
203
|
-
"react-dom": ">=
|
|
202
|
+
"react": ">=19.2.0",
|
|
203
|
+
"react-dom": ">=19.2.0",
|
|
204
204
|
"webpack": ">=5.0.0"
|
|
205
205
|
},
|
|
206
206
|
"peerDependenciesMeta": {
|
|
@@ -215,10 +215,10 @@
|
|
|
215
215
|
}
|
|
216
216
|
},
|
|
217
217
|
"dependencies": {
|
|
218
|
-
"@babel/core": "^7.29.
|
|
219
|
-
"@babel/preset-typescript": "^
|
|
218
|
+
"@babel/core": "^7.29.7",
|
|
219
|
+
"@babel/preset-typescript": "^8.0.1",
|
|
220
220
|
"@jetbrains/babel-preset-jetbrains": "^2.4.0",
|
|
221
|
-
"@jetbrains/icons": "^5.
|
|
221
|
+
"@jetbrains/icons": "^5.23.0",
|
|
222
222
|
"@jetbrains/postcss-require-hover": "^0.2.0",
|
|
223
223
|
"@types/combokeys": "^2.4.9",
|
|
224
224
|
"@types/element-resize-detector": "^1.1.6",
|
|
@@ -233,7 +233,7 @@
|
|
|
233
233
|
"combokeys": "^3.0.1",
|
|
234
234
|
"css-loader": "^7.1.4",
|
|
235
235
|
"csstype": "^3.2.1",
|
|
236
|
-
"date-fns": "^4.
|
|
236
|
+
"date-fns": "^4.4.0",
|
|
237
237
|
"dequal": "^2.0.3",
|
|
238
238
|
"element-resize-detector": "^1.2.4",
|
|
239
239
|
"fastdom": "^1.0.12",
|
|
@@ -247,7 +247,7 @@
|
|
|
247
247
|
"postcss-font-family-system-ui": "^5.0.0",
|
|
248
248
|
"postcss-loader": "^8.2.1",
|
|
249
249
|
"postcss-modules-values-replace": "^4.2.2",
|
|
250
|
-
"postcss-preset-env": "^11.3.
|
|
250
|
+
"postcss-preset-env": "^11.3.1",
|
|
251
251
|
"react-compiler-runtime": "^1.0.0",
|
|
252
252
|
"react-movable": "^3.4.1",
|
|
253
253
|
"react-virtualized": "^9.22.6",
|
|
@@ -1,6 +0,0 @@
|
|
|
1
|
-
import { type RefObject } from 'react';
|
|
2
|
-
export declare function useIntersectionObserver(containerRef: RefObject<HTMLElement | null>, scrollMargin?: number): IntersectionObserverHandle | null;
|
|
3
|
-
export interface IntersectionObserverHandle {
|
|
4
|
-
observeVisibility(element: Element, setVisible: (isVisible: boolean) => void): () => void;
|
|
5
|
-
}
|
|
6
|
-
export declare function useVisibility(handle: IntersectionObserverHandle | null, elementRef: RefObject<Element | null>): boolean;
|