@jetbrains/ring-ui 8.0.0-beta.1 → 8.0.0-beta.10
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 +2 -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-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/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.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/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/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 +2 -2
- 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/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 +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 +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 +2 -2
- 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 +44 -47
- 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
|
@@ -0,0 +1,334 @@
|
|
|
1
|
+
/* eslint-disable max-lines */
|
|
2
|
+
import { use, useEffect, useEffectEvent, useRef, } from 'react';
|
|
3
|
+
import classNames from 'classnames';
|
|
4
|
+
import dragIcon from '@jetbrains/icons/drag-12px';
|
|
5
|
+
import { TablePropsContext } from '../table-const';
|
|
6
|
+
import Icon from '../../icon';
|
|
7
|
+
import { useComposedRef } from '../../global/compose-refs';
|
|
8
|
+
import { parseCssDuration } from '../../global/parse-css-duration';
|
|
9
|
+
import { ReorderAnimationContext } from './reorder-animation-context';
|
|
10
|
+
import { ReorderLayoutContext } from './reorder-layout-context';
|
|
11
|
+
import styles from '../table.css';
|
|
12
|
+
const columnDragFrameAdjustmentPx = -1;
|
|
13
|
+
const itemDragFrameAdjustmentPx = -2;
|
|
14
|
+
const scrollAreaPx = 100;
|
|
15
|
+
const scrollStepPx = 100;
|
|
16
|
+
const scrollIntervalMs = 200;
|
|
17
|
+
export function ReorderHandle({ direction, index, noDragFrame, noHandleTranslate, onUserDrag, ref: userRef, className, onKeyDown, onPointerDown, onPointerMove, onPointerUp, onPointerCancel, onLostPointerCapture, ...restProps }) {
|
|
18
|
+
const localRef = useRef(null);
|
|
19
|
+
const composedRef = useComposedRef(localRef, userRef);
|
|
20
|
+
const isColumn = direction === 'columns';
|
|
21
|
+
const tableProps = use(TablePropsContext);
|
|
22
|
+
const data = tableProps?.data;
|
|
23
|
+
const columns = tableProps?.columns;
|
|
24
|
+
const canReorderItem = tableProps?.canReorderItem;
|
|
25
|
+
const onItemReorder = tableProps?.onItemReorder;
|
|
26
|
+
const onColumnReorder = tableProps?.onColumnReorder;
|
|
27
|
+
function canReorder(insertionIndex) {
|
|
28
|
+
const columnBeingReordered = columns?.[index];
|
|
29
|
+
if (isColumn && columnBeingReordered) {
|
|
30
|
+
const canReorderColumn = columnBeingReordered.canReorder;
|
|
31
|
+
if (canReorderColumn === true)
|
|
32
|
+
return true;
|
|
33
|
+
if (typeof canReorderColumn === 'function')
|
|
34
|
+
return canReorderColumn(columnBeingReordered, index, insertionIndex, columns);
|
|
35
|
+
return false;
|
|
36
|
+
}
|
|
37
|
+
if (!isColumn && data) {
|
|
38
|
+
return canReorderItem ? canReorderItem(data[index], index, insertionIndex, data) : true;
|
|
39
|
+
}
|
|
40
|
+
return false;
|
|
41
|
+
}
|
|
42
|
+
const { expectReorder } = use(ReorderAnimationContext);
|
|
43
|
+
function onReorder(insertionIndex) {
|
|
44
|
+
if (isColumn && columns) {
|
|
45
|
+
expectReorder({ direction, fromIndex: index, insertionIndex });
|
|
46
|
+
onColumnReorder?.(columns[index], index, insertionIndex, columns);
|
|
47
|
+
}
|
|
48
|
+
else if (!isColumn && data) {
|
|
49
|
+
expectReorder({ direction, fromIndex: index, insertionIndex });
|
|
50
|
+
onItemReorder?.(data[index], index, insertionIndex, data);
|
|
51
|
+
}
|
|
52
|
+
}
|
|
53
|
+
const activeDragRef = useRef(null);
|
|
54
|
+
function getDragFrame() {
|
|
55
|
+
return document.body.querySelector(`.${styles.dragFrame}`);
|
|
56
|
+
}
|
|
57
|
+
function getInsertionIndicator() {
|
|
58
|
+
return document.body.querySelector(`.${styles.insertionIndicator}`);
|
|
59
|
+
}
|
|
60
|
+
const { getItemBounds, getClosestInsertionPoint } = use(ReorderLayoutContext);
|
|
61
|
+
function renderDragFrame(clientX, clientY) {
|
|
62
|
+
const drag = activeDragRef.current;
|
|
63
|
+
if (noDragFrame || !drag)
|
|
64
|
+
return;
|
|
65
|
+
const { startX, startY, initialItemStart, initialItemEnd, indicatorStart, indicatorSize } = drag;
|
|
66
|
+
let dragFrame = getDragFrame();
|
|
67
|
+
if (!dragFrame) {
|
|
68
|
+
dragFrame = document.createElement('div');
|
|
69
|
+
dragFrame.className = styles.dragFrame;
|
|
70
|
+
const frameStart = `calc(max(0px, ${indicatorStart - 2}px))`;
|
|
71
|
+
const frameAcrossSize = `${initialItemEnd - initialItemStart}px`;
|
|
72
|
+
const frameAlongSize = indicatorSize;
|
|
73
|
+
dragFrame.style[isColumn ? 'top' : 'left'] = frameStart;
|
|
74
|
+
dragFrame.style[isColumn ? 'width' : 'height'] = frameAcrossSize;
|
|
75
|
+
dragFrame.style[isColumn ? 'height' : 'width'] = frameAlongSize;
|
|
76
|
+
document.body.appendChild(dragFrame);
|
|
77
|
+
}
|
|
78
|
+
if (isColumn) {
|
|
79
|
+
dragFrame.style.left = `${initialItemStart + clientX - startX + columnDragFrameAdjustmentPx}px`;
|
|
80
|
+
}
|
|
81
|
+
else {
|
|
82
|
+
dragFrame.style.top = `${initialItemStart + clientY - startY + itemDragFrameAdjustmentPx}px`;
|
|
83
|
+
}
|
|
84
|
+
}
|
|
85
|
+
function translateButton(clientX, clientY) {
|
|
86
|
+
const btn = localRef.current;
|
|
87
|
+
const drag = activeDragRef.current;
|
|
88
|
+
if (noHandleTranslate || !btn || !drag)
|
|
89
|
+
return;
|
|
90
|
+
const { startX, startY, initialItemStart } = drag;
|
|
91
|
+
const offsetByPointerMove = isColumn ? clientX - startX : clientY - startY;
|
|
92
|
+
const { start: itemStart } = getItemBounds(index) ?? { start: 0, end: 0 };
|
|
93
|
+
const offsetByItemMove = itemStart - initialItemStart;
|
|
94
|
+
const offset = offsetByPointerMove - offsetByItemMove;
|
|
95
|
+
btn.style.transform = isColumn ? `translateX(${offset}px)` : `translateY(${offset}px)`;
|
|
96
|
+
}
|
|
97
|
+
function getClosestInsertionPointLocal(clientX, clientY) {
|
|
98
|
+
const clientOffset = isColumn ? clientX : clientY;
|
|
99
|
+
return getClosestInsertionPoint(clientOffset, canReorder);
|
|
100
|
+
}
|
|
101
|
+
function renderInsertionIndicator({ itemIndex, after }) {
|
|
102
|
+
const drag = activeDragRef.current;
|
|
103
|
+
if (!drag)
|
|
104
|
+
return;
|
|
105
|
+
const { indicatorStart, indicatorSize } = drag;
|
|
106
|
+
const itemBounds = getItemBounds(itemIndex);
|
|
107
|
+
if (!itemBounds)
|
|
108
|
+
return;
|
|
109
|
+
const { start: itemStart, end: itemEnd } = itemBounds;
|
|
110
|
+
let indicator = getInsertionIndicator();
|
|
111
|
+
if (!indicator) {
|
|
112
|
+
indicator = document.createElement('div');
|
|
113
|
+
indicator.className = styles.insertionIndicator;
|
|
114
|
+
indicator.style[isColumn ? 'top' : 'left'] = `${indicatorStart}px`;
|
|
115
|
+
indicator.style[isColumn ? 'height' : 'width'] = indicatorSize;
|
|
116
|
+
indicator.style[isColumn ? 'width' : 'height'] = '2px';
|
|
117
|
+
document.body.appendChild(indicator);
|
|
118
|
+
}
|
|
119
|
+
const itemOffset = `${(after ? itemEnd : itemStart) - 1}px`;
|
|
120
|
+
indicator.style[isColumn ? 'left' : 'top'] = itemOffset;
|
|
121
|
+
}
|
|
122
|
+
function cleanupDrag() {
|
|
123
|
+
if (activeDragRef.current) {
|
|
124
|
+
activeDragRef.current.cleanup();
|
|
125
|
+
activeDragRef.current = null;
|
|
126
|
+
}
|
|
127
|
+
const btn = localRef.current;
|
|
128
|
+
if (btn) {
|
|
129
|
+
btn.style.removeProperty('transform');
|
|
130
|
+
btn.style.removeProperty('transition');
|
|
131
|
+
}
|
|
132
|
+
getDragFrame()?.remove();
|
|
133
|
+
getInsertionIndicator()?.remove();
|
|
134
|
+
onUserDrag?.(undefined);
|
|
135
|
+
}
|
|
136
|
+
function animateNoChangeThenCleanup() {
|
|
137
|
+
const drag = activeDragRef.current;
|
|
138
|
+
if (drag?.state !== 'is-dragging')
|
|
139
|
+
return;
|
|
140
|
+
drag.state = 'ended-with-no-change';
|
|
141
|
+
drag.cleanup();
|
|
142
|
+
drag.cleanup = () => { };
|
|
143
|
+
const dragFrame = getDragFrame();
|
|
144
|
+
if (dragFrame) {
|
|
145
|
+
const { initialItemStart } = drag;
|
|
146
|
+
if (isColumn) {
|
|
147
|
+
dragFrame.style.left = `${initialItemStart + columnDragFrameAdjustmentPx}px`;
|
|
148
|
+
}
|
|
149
|
+
else {
|
|
150
|
+
dragFrame.style.top = `${initialItemStart + itemDragFrameAdjustmentPx}px`;
|
|
151
|
+
}
|
|
152
|
+
dragFrame.style.transition = 'left var(--ring-ease), top var(--ring-ease), opacity var(--ring-ease)';
|
|
153
|
+
dragFrame.style.opacity = '0';
|
|
154
|
+
}
|
|
155
|
+
const indicator = getInsertionIndicator();
|
|
156
|
+
if (indicator) {
|
|
157
|
+
indicator.style.opacity = '0';
|
|
158
|
+
indicator.style.transition = 'opacity var(--ring-ease)';
|
|
159
|
+
}
|
|
160
|
+
const btn = localRef.current;
|
|
161
|
+
if (btn) {
|
|
162
|
+
btn.style.transform = isColumn ? 'translateX(0)' : 'translateY(0)';
|
|
163
|
+
btn.style.transition = 'transform var(--ring-ease)';
|
|
164
|
+
}
|
|
165
|
+
onUserDrag?.('cancelled');
|
|
166
|
+
const ringEaseMs = parseCssDuration(window.getComputedStyle(document.documentElement).getPropertyValue('--ring-ease'));
|
|
167
|
+
setTimeout(cleanupDrag, ringEaseMs);
|
|
168
|
+
}
|
|
169
|
+
function handlePointerDown(e) {
|
|
170
|
+
onPointerDown?.(e);
|
|
171
|
+
if (e.defaultPrevented)
|
|
172
|
+
return;
|
|
173
|
+
const { clientX, clientY, pointerId, currentTarget } = e;
|
|
174
|
+
const { start: initialItemStart, end: initialItemEnd } = getItemBounds(index) ?? { start: 0, end: 0 };
|
|
175
|
+
let indicatorStart;
|
|
176
|
+
let indicatorSize;
|
|
177
|
+
if (isColumn) {
|
|
178
|
+
const thead = currentTarget.closest('thead');
|
|
179
|
+
const table = thead?.closest('table');
|
|
180
|
+
if (!thead || !table)
|
|
181
|
+
return;
|
|
182
|
+
const { top: headerTop } = thead.getBoundingClientRect();
|
|
183
|
+
indicatorStart = headerTop;
|
|
184
|
+
const { bottom: tableBottom } = table.getBoundingClientRect();
|
|
185
|
+
const visibleTableHeight = tableBottom - headerTop;
|
|
186
|
+
const viewportBottomRelativeToHeaderTop = window.innerHeight - headerTop;
|
|
187
|
+
indicatorSize = `min(${visibleTableHeight}px, calc(${viewportBottomRelativeToHeaderTop}px - .5rem))`;
|
|
188
|
+
}
|
|
189
|
+
else {
|
|
190
|
+
const tr = currentTarget.closest('tr');
|
|
191
|
+
const tbody = tr?.closest('tbody');
|
|
192
|
+
if (!tr || !tbody)
|
|
193
|
+
return;
|
|
194
|
+
const { left: itemLeft, right: itemRight } = tr.getBoundingClientRect();
|
|
195
|
+
indicatorStart = itemLeft;
|
|
196
|
+
const visibleItemWidth = itemRight - itemLeft;
|
|
197
|
+
const viewportRightRelativeToTableLeft = window.innerWidth - itemLeft;
|
|
198
|
+
indicatorSize = `min(${visibleItemWidth}px, calc(${viewportRightRelativeToTableLeft}px - .5rem))`;
|
|
199
|
+
}
|
|
200
|
+
function keydownListener(keyEvent) {
|
|
201
|
+
if (keyEvent.key === 'Escape') {
|
|
202
|
+
animateNoChangeThenCleanup();
|
|
203
|
+
keyEvent.stopPropagation();
|
|
204
|
+
keyEvent.preventDefault();
|
|
205
|
+
}
|
|
206
|
+
}
|
|
207
|
+
currentTarget.setPointerCapture(pointerId);
|
|
208
|
+
document.addEventListener('keydown', keydownListener);
|
|
209
|
+
currentTarget.style.cursor = 'grabbing';
|
|
210
|
+
activeDragRef.current = {
|
|
211
|
+
state: 'is-dragging',
|
|
212
|
+
startX: clientX,
|
|
213
|
+
startY: clientY,
|
|
214
|
+
initialItemStart,
|
|
215
|
+
initialItemEnd,
|
|
216
|
+
indicatorStart,
|
|
217
|
+
indicatorSize,
|
|
218
|
+
cleanup: () => {
|
|
219
|
+
currentTarget.releasePointerCapture(pointerId);
|
|
220
|
+
document.removeEventListener('keydown', keydownListener);
|
|
221
|
+
currentTarget.style.removeProperty('cursor');
|
|
222
|
+
},
|
|
223
|
+
};
|
|
224
|
+
renderDragFrame(clientX, clientY);
|
|
225
|
+
onUserDrag?.('pointerdown');
|
|
226
|
+
e.preventDefault();
|
|
227
|
+
}
|
|
228
|
+
const scrollerRef = tableProps?.scrollerRef;
|
|
229
|
+
const lastScrolledRef = useRef(0);
|
|
230
|
+
function scrollThrottled(scrollDirection) {
|
|
231
|
+
const now = performance.now();
|
|
232
|
+
if (now > lastScrolledRef.current + scrollIntervalMs) {
|
|
233
|
+
lastScrolledRef.current = now;
|
|
234
|
+
const top = scrollDirection === 'up' ? -scrollStepPx : scrollStepPx;
|
|
235
|
+
const scroller = scrollerRef?.current ?? window;
|
|
236
|
+
scroller?.scrollBy({ top, behavior: 'smooth' });
|
|
237
|
+
}
|
|
238
|
+
}
|
|
239
|
+
function handlePointerMove(e) {
|
|
240
|
+
onPointerMove?.(e);
|
|
241
|
+
if (e.defaultPrevented)
|
|
242
|
+
return;
|
|
243
|
+
const drag = activeDragRef.current;
|
|
244
|
+
if (drag?.state !== 'is-dragging')
|
|
245
|
+
return;
|
|
246
|
+
const { clientX, clientY } = e;
|
|
247
|
+
renderDragFrame(clientX, clientY);
|
|
248
|
+
translateButton(clientX, clientY);
|
|
249
|
+
const insertionPoint = getClosestInsertionPointLocal(clientX, clientY);
|
|
250
|
+
if (insertionPoint)
|
|
251
|
+
renderInsertionIndicator(insertionPoint);
|
|
252
|
+
onUserDrag?.(isColumn ? clientX - drag.startX : clientY - drag.startY);
|
|
253
|
+
if (!isColumn) {
|
|
254
|
+
const scrollerRect = scrollerRef?.current?.getBoundingClientRect();
|
|
255
|
+
const scrollerTop = scrollerRect?.top ?? 0;
|
|
256
|
+
const scrollerBottom = scrollerRect ? Math.min(scrollerRect.bottom, window.innerHeight) : window.innerHeight;
|
|
257
|
+
if (clientY < scrollerTop + scrollAreaPx) {
|
|
258
|
+
scrollThrottled('up');
|
|
259
|
+
}
|
|
260
|
+
else if (clientY > scrollerBottom - scrollAreaPx) {
|
|
261
|
+
scrollThrottled('down');
|
|
262
|
+
}
|
|
263
|
+
}
|
|
264
|
+
}
|
|
265
|
+
function handlePointerUp(e) {
|
|
266
|
+
onPointerUp?.(e);
|
|
267
|
+
if (e.defaultPrevented)
|
|
268
|
+
return;
|
|
269
|
+
if (activeDragRef.current?.state !== 'is-dragging')
|
|
270
|
+
return;
|
|
271
|
+
const { clientX, clientY } = e;
|
|
272
|
+
const insertionPoint = getClosestInsertionPointLocal(clientX, clientY);
|
|
273
|
+
const insertionIndex = insertionPoint && insertionPoint.itemIndex + (insertionPoint.after ? 1 : 0);
|
|
274
|
+
if (insertionIndex == null || insertionIndex === index || insertionIndex === index + 1) {
|
|
275
|
+
animateNoChangeThenCleanup();
|
|
276
|
+
return;
|
|
277
|
+
}
|
|
278
|
+
cleanupDrag();
|
|
279
|
+
onReorder(insertionIndex);
|
|
280
|
+
}
|
|
281
|
+
function handleKeyDown(e) {
|
|
282
|
+
onKeyDown?.(e);
|
|
283
|
+
if (e.defaultPrevented)
|
|
284
|
+
return;
|
|
285
|
+
const left = isColumn && e.key === 'ArrowLeft';
|
|
286
|
+
const right = isColumn && e.key === 'ArrowRight';
|
|
287
|
+
const up = !isColumn && e.key === 'ArrowUp';
|
|
288
|
+
const down = !isColumn && e.key === 'ArrowDown';
|
|
289
|
+
if ((!left && !right && !up && !down) || !columns || !data)
|
|
290
|
+
return;
|
|
291
|
+
const backward = left || up;
|
|
292
|
+
const initialInsertionIndex = backward ? index - 1 : index + 2;
|
|
293
|
+
const maxInsertionIndex = isColumn ? columns.length : data.length;
|
|
294
|
+
const step = backward ? -1 : 1;
|
|
295
|
+
// eslint-disable-next-line yoda
|
|
296
|
+
for (let i = initialInsertionIndex; 0 <= i && i <= maxInsertionIndex; i += step) {
|
|
297
|
+
if (canReorder(i)) {
|
|
298
|
+
onReorder(i);
|
|
299
|
+
e.preventDefault();
|
|
300
|
+
return;
|
|
301
|
+
}
|
|
302
|
+
}
|
|
303
|
+
}
|
|
304
|
+
function handlePointerCancel(e) {
|
|
305
|
+
onPointerCancel?.(e);
|
|
306
|
+
if (!e.defaultPrevented)
|
|
307
|
+
animateNoChangeThenCleanup();
|
|
308
|
+
}
|
|
309
|
+
function handleLostPointerCapture(e) {
|
|
310
|
+
onLostPointerCapture?.(e);
|
|
311
|
+
if (!e.defaultPrevented)
|
|
312
|
+
animateNoChangeThenCleanup();
|
|
313
|
+
}
|
|
314
|
+
const cleanupComponent = useEffectEvent(() => {
|
|
315
|
+
if (activeDragRef.current) {
|
|
316
|
+
cleanupDrag();
|
|
317
|
+
}
|
|
318
|
+
});
|
|
319
|
+
useEffect(() => {
|
|
320
|
+
return cleanupComponent;
|
|
321
|
+
}, []);
|
|
322
|
+
const hint = isColumn
|
|
323
|
+
? `Reorder column ${columns?.[index]?.name ?? String(columns?.[index]?.key)}.`
|
|
324
|
+
: `Reorder item ${index + 1}.`;
|
|
325
|
+
const description = isColumn
|
|
326
|
+
? 'Use Left and Right arrow keys to move the column.'
|
|
327
|
+
: 'Use Up and Down arrow keys to move the item.';
|
|
328
|
+
const shortcuts = isColumn ? 'ArrowLeft ArrowRight' : 'ArrowUp ArrowDown';
|
|
329
|
+
return (
|
|
330
|
+
// eslint-disable-next-line jsx-a11y/role-supports-aria-props
|
|
331
|
+
<button ref={composedRef} type='button' className={classNames(styles.tableButton, isColumn ? styles.columnReorderHandle : styles.itemReorderHandle, className)} aria-label={hint} aria-description={description} aria-keyshortcuts={shortcuts} onKeyDown={handleKeyDown} onPointerDown={handlePointerDown} onPointerMove={handlePointerMove} onPointerUp={handlePointerUp} onPointerCancel={handlePointerCancel} onLostPointerCapture={handleLostPointerCapture} {...restProps}>
|
|
332
|
+
<Icon glyph={dragIcon} aria-hidden='true'/>
|
|
333
|
+
</button>);
|
|
334
|
+
}
|
|
@@ -0,0 +1,16 @@
|
|
|
1
|
+
interface ItemBounds {
|
|
2
|
+
start: number;
|
|
3
|
+
end: number;
|
|
4
|
+
}
|
|
5
|
+
export interface InsertionPoint {
|
|
6
|
+
itemIndex: number;
|
|
7
|
+
after: boolean;
|
|
8
|
+
}
|
|
9
|
+
interface ReorderLayoutContextValue {
|
|
10
|
+
registerReorderItem(index: number, getBounds: () => ItemBounds): () => void;
|
|
11
|
+
getItemBounds(index: number): ItemBounds | undefined;
|
|
12
|
+
getClosestInsertionPoint(clientOffset: number, canReorder: (insertionIndex: number) => boolean): InsertionPoint | undefined;
|
|
13
|
+
}
|
|
14
|
+
export declare const ReorderLayoutContext: import("react").Context<ReorderLayoutContextValue>;
|
|
15
|
+
export declare function useReorderLayoutContextValue(): ReorderLayoutContextValue;
|
|
16
|
+
export {};
|
|
@@ -0,0 +1,69 @@
|
|
|
1
|
+
import { createContext, useRef } from 'react';
|
|
2
|
+
export const ReorderLayoutContext = createContext({
|
|
3
|
+
registerReorderItem: () => () => { },
|
|
4
|
+
getItemBounds: () => undefined,
|
|
5
|
+
getClosestInsertionPoint: () => undefined,
|
|
6
|
+
});
|
|
7
|
+
export function useReorderLayoutContextValue() {
|
|
8
|
+
const getBoundsByItemIndex = useRef([]);
|
|
9
|
+
function registerReorderItem(index, getBounds) {
|
|
10
|
+
getBoundsByItemIndex.current[index] = getBounds;
|
|
11
|
+
return () => {
|
|
12
|
+
delete getBoundsByItemIndex.current[index];
|
|
13
|
+
};
|
|
14
|
+
}
|
|
15
|
+
function getItemBounds(index) {
|
|
16
|
+
const getBounds = getBoundsByItemIndex.current[index];
|
|
17
|
+
return getBounds?.();
|
|
18
|
+
}
|
|
19
|
+
function getClosestInsertionPoint(clientOffset, canReorder) {
|
|
20
|
+
const candidates = getBoundsByItemIndex.current
|
|
21
|
+
.map((getBounds, itemIndex) => ({
|
|
22
|
+
itemIndex,
|
|
23
|
+
getBounds,
|
|
24
|
+
beforeAllowed: canReorder(itemIndex),
|
|
25
|
+
afterAllowed: canReorder(itemIndex + 1),
|
|
26
|
+
}))
|
|
27
|
+
.filter(({ beforeAllowed, afterAllowed }) => beforeAllowed || afterAllowed);
|
|
28
|
+
if (!candidates.length)
|
|
29
|
+
return undefined;
|
|
30
|
+
// Lazily computed closest insertion side and distance for each candidate
|
|
31
|
+
const closest = [];
|
|
32
|
+
function computeClosest(i) {
|
|
33
|
+
if (!closest[i]) {
|
|
34
|
+
const { getBounds, beforeAllowed, afterAllowed } = candidates[i];
|
|
35
|
+
const { start, end } = getBounds();
|
|
36
|
+
const beforeDist = Math.abs(clientOffset - start);
|
|
37
|
+
const afterDist = Math.abs(clientOffset - end);
|
|
38
|
+
if (!afterAllowed) {
|
|
39
|
+
closest[i] = { distance: beforeDist, after: false };
|
|
40
|
+
}
|
|
41
|
+
else if (!beforeAllowed) {
|
|
42
|
+
closest[i] = { distance: afterDist, after: true };
|
|
43
|
+
}
|
|
44
|
+
else {
|
|
45
|
+
const after = afterDist < beforeDist;
|
|
46
|
+
closest[i] = { distance: after ? afterDist : beforeDist, after };
|
|
47
|
+
}
|
|
48
|
+
}
|
|
49
|
+
return closest[i];
|
|
50
|
+
}
|
|
51
|
+
let l = 0;
|
|
52
|
+
let r = candidates.length - 1;
|
|
53
|
+
while (l < r) {
|
|
54
|
+
const m = Math.floor((l + r) / 2);
|
|
55
|
+
const { distance } = computeClosest(m);
|
|
56
|
+
if (l <= m - 1 && computeClosest(m - 1).distance < distance) {
|
|
57
|
+
r = m - 1;
|
|
58
|
+
}
|
|
59
|
+
else if (m + 1 <= r && computeClosest(m + 1).distance < distance) {
|
|
60
|
+
l = m + 1;
|
|
61
|
+
}
|
|
62
|
+
else {
|
|
63
|
+
return { itemIndex: candidates[m].itemIndex, after: computeClosest(m).after };
|
|
64
|
+
}
|
|
65
|
+
}
|
|
66
|
+
return { itemIndex: candidates[l].itemIndex, after: computeClosest(l).after };
|
|
67
|
+
}
|
|
68
|
+
return { registerReorderItem, getItemBounds, getClosestInsertionPoint };
|
|
69
|
+
}
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
export declare function TableHeader<T>(): import("react").JSX.Element | null;
|
|
@@ -0,0 +1,143 @@
|
|
|
1
|
+
/* eslint-disable no-nested-ternary */
|
|
2
|
+
import { use, useCallback, useRef, useState } from 'react';
|
|
3
|
+
import classNames from 'classnames';
|
|
4
|
+
import arrowDownIcon from '@jetbrains/icons/arrow-12px-down';
|
|
5
|
+
import arrowUpIcon from '@jetbrains/icons/arrow-12px-up';
|
|
6
|
+
import settingsIcon from '@jetbrains/icons/settings-12px';
|
|
7
|
+
import trashIcon from '@jetbrains/icons/trash-12px';
|
|
8
|
+
import unsortedIcon from '@jetbrains/icons/unsorted-12px';
|
|
9
|
+
import { TablePropsContext } from '../table-const';
|
|
10
|
+
import Icon from '../../icon';
|
|
11
|
+
import { isWithinInteractiveElement } from '../../global/is-within-interactive-element';
|
|
12
|
+
import { ReorderHandle } from './reorder-handle';
|
|
13
|
+
import { ReorderAnimationContext } from './reorder-animation-context';
|
|
14
|
+
import { ReorderLayoutContext, useReorderLayoutContextValue } from './reorder-layout-context';
|
|
15
|
+
import { useReorderItemLayout } from '../reorder-item-layout';
|
|
16
|
+
import styles from '../table.css';
|
|
17
|
+
export function TableHeader() {
|
|
18
|
+
const { columns, noHeader, stickyHeader, columnEditing, onColumnEditingRequest, theadClassName, theadTrClassName } = use(TablePropsContext);
|
|
19
|
+
const [localColumnEditing, setLocalColumnEditing] = useState(false);
|
|
20
|
+
const effectiveColumnEditing = columnEditing ?? localColumnEditing;
|
|
21
|
+
const toggleColumnEditing = useCallback((source) => {
|
|
22
|
+
let newColumnEditing;
|
|
23
|
+
if (columnEditing == null) {
|
|
24
|
+
newColumnEditing = !localColumnEditing;
|
|
25
|
+
setLocalColumnEditing(newColumnEditing);
|
|
26
|
+
}
|
|
27
|
+
else {
|
|
28
|
+
newColumnEditing = !columnEditing;
|
|
29
|
+
}
|
|
30
|
+
onColumnEditingRequest?.(newColumnEditing, source);
|
|
31
|
+
}, [columnEditing, localColumnEditing, onColumnEditingRequest]);
|
|
32
|
+
const handleTheadClick = useCallback((e) => {
|
|
33
|
+
if (window.matchMedia('(hover: none)').matches && !isWithinInteractiveElement(e.target)) {
|
|
34
|
+
toggleColumnEditing('header');
|
|
35
|
+
}
|
|
36
|
+
}, [toggleColumnEditing]);
|
|
37
|
+
const handleEditColumnsButtonClick = useCallback(() => {
|
|
38
|
+
toggleColumnEditing('edit-button');
|
|
39
|
+
}, [toggleColumnEditing]);
|
|
40
|
+
const reorderContextValue = useReorderLayoutContextValue();
|
|
41
|
+
if (noHeader)
|
|
42
|
+
return null;
|
|
43
|
+
return (
|
|
44
|
+
// eslint-disable-next-line jsx-a11y/no-noninteractive-element-interactions, jsx-a11y/click-events-have-key-events
|
|
45
|
+
<thead className={classNames(theadClassName, effectiveColumnEditing && styles.theadColumnEditing, stickyHeader && styles.stickyHeader)} onClick={handleTheadClick}>
|
|
46
|
+
<tr className={theadTrClassName}>
|
|
47
|
+
<ReorderLayoutContext value={reorderContextValue}>
|
|
48
|
+
{columns.map((column, columnIndex) => (<TableHeaderCell key={column.key} columnIndex={columnIndex} columnEditing={effectiveColumnEditing} handleEditColumnsButtonClick={handleEditColumnsButtonClick}/>))}
|
|
49
|
+
</ReorderLayoutContext>
|
|
50
|
+
</tr>
|
|
51
|
+
</thead>);
|
|
52
|
+
}
|
|
53
|
+
function TableHeaderCell({ columnIndex, columnEditing, handleEditColumnsButtonClick, }) {
|
|
54
|
+
const ref = useRef(null);
|
|
55
|
+
const { columns, columnEditButton } = use(TablePropsContext);
|
|
56
|
+
const { key, name, renderHeader, sortOrder, deletable, canReorder, thClassName } = columns[columnIndex];
|
|
57
|
+
const { reorderAnimation } = use(ReorderAnimationContext);
|
|
58
|
+
const children = renderHeader ? renderHeader() : (name ?? String(key));
|
|
59
|
+
useReorderItemLayout({
|
|
60
|
+
index: columnIndex,
|
|
61
|
+
getBounds: () => {
|
|
62
|
+
const r = ref.current?.getBoundingClientRect();
|
|
63
|
+
return { start: r?.left ?? 0, end: r?.right ?? 0 };
|
|
64
|
+
},
|
|
65
|
+
});
|
|
66
|
+
return (<th ref={ref} className={classNames(styles.headerCell, reorderAnimation?.direction === 'columns' &&
|
|
67
|
+
reorderAnimation.index === columnIndex &&
|
|
68
|
+
reorderAnimation.className, thClassName)} scope='col' aria-sort={sortOrder}>
|
|
69
|
+
<div className={styles.headerCellInnerWrapper}>
|
|
70
|
+
<div className={styles.sortAndHeader}>
|
|
71
|
+
{canReorder && <ColumnReorderHandle columnIndex={columnIndex}/>}
|
|
72
|
+
{sortOrder ? (<SortButton columnIndex={columnIndex} aria-description={`Sort order: ${sortOrder}`}>
|
|
73
|
+
{children}
|
|
74
|
+
</SortButton>) : (children)}
|
|
75
|
+
{canReorder && <ColumnReorderHandleMirror />}
|
|
76
|
+
</div>
|
|
77
|
+
|
|
78
|
+
<div className={styles.rightButtons}>
|
|
79
|
+
{deletable && <DeleteColumnButton columnIndex={columnIndex}/>}
|
|
80
|
+
{columnIndex === columns.length - 1 && columnEditButton && (<EditColumnsButton columnEditing={columnEditing} onClick={handleEditColumnsButtonClick}/>)}
|
|
81
|
+
</div>
|
|
82
|
+
</div>
|
|
83
|
+
</th>);
|
|
84
|
+
}
|
|
85
|
+
function SortButton({ columnIndex, className, children, onClick, ...restProps }) {
|
|
86
|
+
const tableProps = use(TablePropsContext);
|
|
87
|
+
const column = tableProps?.columns[columnIndex];
|
|
88
|
+
const sortOrder = column?.sortOrder;
|
|
89
|
+
const glyph = sortOrder === 'none'
|
|
90
|
+
? unsortedIcon
|
|
91
|
+
: sortOrder === 'ascending'
|
|
92
|
+
? arrowUpIcon
|
|
93
|
+
: sortOrder === 'descending'
|
|
94
|
+
? arrowDownIcon
|
|
95
|
+
: undefined;
|
|
96
|
+
const handleClick = useCallback((e) => {
|
|
97
|
+
onClick?.(e);
|
|
98
|
+
if (!e.defaultPrevented) {
|
|
99
|
+
const nextOrder = sortOrder === 'ascending' ? 'descending' : sortOrder === 'descending' ? 'none' : 'ascending';
|
|
100
|
+
tableProps.onSort?.(columnIndex, nextOrder, tableProps.columns);
|
|
101
|
+
}
|
|
102
|
+
}, [columnIndex, onClick, sortOrder, tableProps]);
|
|
103
|
+
if (!tableProps || !column) {
|
|
104
|
+
return null;
|
|
105
|
+
}
|
|
106
|
+
return (<button type='button' className={classNames(styles.tableButton, className)} onClick={handleClick} {...restProps}>
|
|
107
|
+
{children} <Icon glyph={glyph} aria-hidden/>
|
|
108
|
+
</button>);
|
|
109
|
+
}
|
|
110
|
+
function DeleteColumnButton({ columnIndex, className, onClick, ...restProps }) {
|
|
111
|
+
const tableProps = use(TablePropsContext);
|
|
112
|
+
const column = tableProps?.columns[columnIndex];
|
|
113
|
+
const handleClick = useCallback((e) => {
|
|
114
|
+
onClick?.(e);
|
|
115
|
+
if (!e.defaultPrevented) {
|
|
116
|
+
const columns = tableProps.columns;
|
|
117
|
+
tableProps.onColumnDelete?.(columns[columnIndex], columnIndex, columns);
|
|
118
|
+
}
|
|
119
|
+
}, [columnIndex, onClick, tableProps]);
|
|
120
|
+
if (!tableProps || !column) {
|
|
121
|
+
return null;
|
|
122
|
+
}
|
|
123
|
+
const hint = `Delete column ${column.name ?? String(column.key)}.`;
|
|
124
|
+
return (<button type='button' className={classNames(styles.tableButton, styles.deleteColumnButton, className)} onClick={handleClick} aria-label={hint} title={hint} {...restProps}>
|
|
125
|
+
<Icon glyph={trashIcon} aria-hidden='true'/>
|
|
126
|
+
</button>);
|
|
127
|
+
}
|
|
128
|
+
function EditColumnsButton({ columnEditing, ...props }) {
|
|
129
|
+
const { className, ...restProps } = props;
|
|
130
|
+
const hint = columnEditing ? 'Hide column controls.' : 'Show column controls.';
|
|
131
|
+
return (<button type='button' className={classNames(styles.tableButton, styles.editColumnsButton, className)} aria-pressed={columnEditing} aria-label={hint} title={hint} {...restProps}>
|
|
132
|
+
<Icon glyph={settingsIcon} aria-hidden='true'/>
|
|
133
|
+
</button>);
|
|
134
|
+
}
|
|
135
|
+
function ColumnReorderHandle({ columnIndex, ...restProps }) {
|
|
136
|
+
return <ReorderHandle direction='columns' index={columnIndex} {...restProps}/>;
|
|
137
|
+
}
|
|
138
|
+
/**
|
|
139
|
+
* Reserves the space for the reorder handle and prevents layout shift when the handle appears on hover.
|
|
140
|
+
*/
|
|
141
|
+
function ColumnReorderHandleMirror() {
|
|
142
|
+
return <span className={styles.columnReorderHandleMirror} aria-hidden='true'/>;
|
|
143
|
+
}
|
|
@@ -0,0 +1,41 @@
|
|
|
1
|
+
import { type RefObject } from 'react';
|
|
2
|
+
import { type IntersectionObserverHandle } from '../../global/intersection-observer-context';
|
|
3
|
+
export type VirtualItem = MaterializedItem | Spacer;
|
|
4
|
+
interface MaterializedItem {
|
|
5
|
+
type: 'materialized';
|
|
6
|
+
index: number;
|
|
7
|
+
}
|
|
8
|
+
interface Spacer {
|
|
9
|
+
type: 'spacer';
|
|
10
|
+
from: number;
|
|
11
|
+
to: number;
|
|
12
|
+
height: number;
|
|
13
|
+
key: string;
|
|
14
|
+
}
|
|
15
|
+
type CollapseItemIntoSpacerCallback = (index: number, height: number) => void;
|
|
16
|
+
interface VirtualizationContextValue {
|
|
17
|
+
intersectionObserverHandle: IntersectionObserverHandle;
|
|
18
|
+
collapseItemIntoSpacer: CollapseItemIntoSpacerCallback;
|
|
19
|
+
}
|
|
20
|
+
export declare const VirtualizationContext: import("react").Context<VirtualizationContextValue>;
|
|
21
|
+
export declare function useVirtualItems<T>({ enabled, data, data: { length }, scrollerRef, tableRef, estimateHeight, lookaheadPx, retentionMarginPx, minScrollAndResizeDeltaPx, }: {
|
|
22
|
+
enabled: boolean;
|
|
23
|
+
data: readonly T[];
|
|
24
|
+
scrollerRef: RefObject<HTMLElement | null> | undefined;
|
|
25
|
+
tableRef: RefObject<HTMLTableElement | null>;
|
|
26
|
+
estimateHeight: (item: T, index: number, items: readonly T[]) => number;
|
|
27
|
+
lookaheadPx: number;
|
|
28
|
+
retentionMarginPx: number;
|
|
29
|
+
minScrollAndResizeDeltaPx: number;
|
|
30
|
+
}): {
|
|
31
|
+
virtualItems: VirtualItem[];
|
|
32
|
+
virtualizationContextValue: {
|
|
33
|
+
intersectionObserverHandle: IntersectionObserverHandle;
|
|
34
|
+
collapseItemIntoSpacer: (index: number, height: number) => void;
|
|
35
|
+
};
|
|
36
|
+
};
|
|
37
|
+
export declare function SpacerRow({ spacer: { from, to, height }, colSpan }: {
|
|
38
|
+
spacer: Spacer;
|
|
39
|
+
colSpan: number;
|
|
40
|
+
}): import("react").JSX.Element;
|
|
41
|
+
export {};
|