react-science 13.0.2 → 15.0.0
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/lib/components/activity_bar/activity_bar.js +1 -1
- package/lib/components/activity_bar/activity_bar.js.map +1 -1
- package/lib/components/activity_panel/activity_panel.js +1 -1
- package/lib/components/activity_panel/activity_panel.js.map +1 -1
- package/lib/components/drop-zone/DropZone.js +1 -1
- package/lib/components/drop-zone/DropZone.js.map +1 -1
- package/lib/components/forms/radio-button-group/RadioButton.js +4 -4
- package/lib/components/forms/radio-button-group/RadioButton.js.map +1 -1
- package/lib/components/forms/radio-button-group/RadioButtonGroup.d.ts +2 -2
- package/lib/components/forms/radio-button-group/RadioButtonGroup.d.ts.map +1 -1
- package/lib/components/forms/radio-button-group/RadioButtonGroup.js +8 -8
- package/lib/components/forms/radio-button-group/RadioButtonGroup.js.map +1 -1
- package/lib/components/forms/styles.d.ts +0 -1
- package/lib/components/forms/styles.d.ts.map +1 -1
- package/lib/components/forms/styles.js.map +1 -1
- package/lib/components/header/PanelHeader.d.ts.map +1 -1
- package/lib/components/header/PanelHeader.js +1 -1
- package/lib/components/header/PanelHeader.js.map +1 -1
- package/lib/components/index.d.ts +1 -1
- package/lib/components/index.js +1 -1
- package/lib/components/info-panel/InfoPanel.js +2 -2
- package/lib/components/info-panel/InfoPanel.js.map +1 -1
- package/lib/components/logger/FifoLoggerDialog.js +1 -1
- package/lib/components/logger/FifoLoggerDialog.js.map +1 -1
- package/lib/components/split_pane/index.d.ts +3 -0
- package/lib/components/split_pane/index.d.ts.map +1 -0
- package/lib/components/split_pane/index.js +3 -0
- package/lib/components/split_pane/index.js.map +1 -0
- package/lib/components/{split-pane/SplitPane.d.ts → split_pane/split_pane.d.ts} +7 -5
- package/lib/components/split_pane/split_pane.d.ts.map +1 -0
- package/lib/components/{split-pane/SplitPane.js → split_pane/split_pane.js} +25 -32
- package/lib/components/split_pane/split_pane.js.map +1 -0
- package/lib/components/split_pane/split_pane_helpers.d.ts +9 -0
- package/lib/components/split_pane/split_pane_helpers.d.ts.map +1 -0
- package/lib/components/split_pane/split_pane_helpers.js +10 -0
- package/lib/components/split_pane/split_pane_helpers.js.map +1 -0
- package/lib/components/{split-pane/useSplitPaneSize.d.ts → split_pane/use_split_pane_size.d.ts} +5 -3
- package/lib/components/split_pane/use_split_pane_size.d.ts.map +1 -0
- package/lib/components/split_pane/use_split_pane_size.js +78 -0
- package/lib/components/split_pane/use_split_pane_size.js.map +1 -0
- package/lib/components/table/index.d.ts +1 -0
- package/lib/components/table/index.d.ts.map +1 -1
- package/lib/components/table/index.js +1 -0
- package/lib/components/table/index.js.map +1 -1
- package/lib/components/table/reorder_rows/draggable_row_context.d.ts +9 -0
- package/lib/components/table/reorder_rows/draggable_row_context.d.ts.map +1 -0
- package/lib/components/table/reorder_rows/draggable_row_context.js +10 -0
- package/lib/components/table/reorder_rows/draggable_row_context.js.map +1 -0
- package/lib/components/table/reorder_rows/draggable_row_tr.d.ts +18 -0
- package/lib/components/table/reorder_rows/draggable_row_tr.d.ts.map +1 -0
- package/lib/components/table/reorder_rows/draggable_row_tr.js +107 -0
- package/lib/components/table/reorder_rows/draggable_row_tr.js.map +1 -0
- package/lib/components/table/reorder_rows/drop_indicator.d.ts +18 -0
- package/lib/components/table/reorder_rows/drop_indicator.d.ts.map +1 -0
- package/lib/components/table/reorder_rows/drop_indicator.js +19 -0
- package/lib/components/table/reorder_rows/drop_indicator.js.map +1 -0
- package/lib/components/table/reorder_rows/dropped_item_context.d.ts +3 -0
- package/lib/components/table/reorder_rows/dropped_item_context.d.ts.map +1 -0
- package/lib/components/table/reorder_rows/dropped_item_context.js +10 -0
- package/lib/components/table/reorder_rows/dropped_item_context.js.map +1 -0
- package/lib/components/table/reorder_rows/dropped_item_provider.d.ts +5 -0
- package/lib/components/table/reorder_rows/dropped_item_provider.d.ts.map +1 -0
- package/lib/components/table/reorder_rows/dropped_item_provider.js +8 -0
- package/lib/components/table/reorder_rows/dropped_item_provider.js.map +1 -0
- package/lib/components/table/reorder_rows/index.d.ts +5 -0
- package/lib/components/table/reorder_rows/index.d.ts.map +1 -0
- package/lib/components/table/reorder_rows/index.js +5 -0
- package/lib/components/table/reorder_rows/index.js.map +1 -0
- package/lib/components/table/reorder_rows/item_data.d.ts +26 -0
- package/lib/components/table/reorder_rows/item_data.d.ts.map +1 -0
- package/lib/components/table/reorder_rows/item_data.js +13 -0
- package/lib/components/table/reorder_rows/item_data.js.map +1 -0
- package/lib/components/table/reorder_rows/item_order_context.d.ts +15 -0
- package/lib/components/table/reorder_rows/item_order_context.d.ts.map +1 -0
- package/lib/components/table/reorder_rows/item_order_context.js +10 -0
- package/lib/components/table/reorder_rows/item_order_context.js.map +1 -0
- package/lib/components/table/reorder_rows/item_order_provider.d.ts +10 -0
- package/lib/components/table/reorder_rows/item_order_provider.d.ts.map +1 -0
- package/lib/components/table/reorder_rows/item_order_provider.js +34 -0
- package/lib/components/table/reorder_rows/item_order_provider.js.map +1 -0
- package/lib/components/table/reorder_rows/table_drag_row_handler.d.ts +2 -0
- package/lib/components/table/reorder_rows/table_drag_row_handler.d.ts.map +1 -0
- package/lib/components/table/reorder_rows/table_drag_row_handler.js +9 -0
- package/lib/components/table/reorder_rows/table_drag_row_handler.js.map +1 -0
- package/lib/components/table/reorder_rows/use_drop_monitor.d.ts +9 -0
- package/lib/components/table/reorder_rows/use_drop_monitor.d.ts.map +1 -0
- package/lib/components/table/reorder_rows/use_drop_monitor.js +57 -0
- package/lib/components/table/reorder_rows/use_drop_monitor.js.map +1 -0
- package/lib/components/table/table_body.d.ts +4 -1
- package/lib/components/table/table_body.d.ts.map +1 -1
- package/lib/components/table/table_body.js +20 -6
- package/lib/components/table/table_body.js.map +1 -1
- package/lib/components/table/table_root.d.ts +37 -1
- package/lib/components/table/table_root.d.ts.map +1 -1
- package/lib/components/table/table_root.js +41 -7
- package/lib/components/table/table_root.js.map +1 -1
- package/lib/components/table/table_row_cell.d.ts +2 -1
- package/lib/components/table/table_row_cell.d.ts.map +1 -1
- package/lib/components/table/table_row_cell.js +2 -2
- package/lib/components/table/table_row_cell.js.map +1 -1
- package/lib/components/table/table_utils.d.ts +11 -2
- package/lib/components/table/table_utils.d.ts.map +1 -1
- package/lib/components/table/table_utils.js.map +1 -1
- package/lib/components/toolbar/Toolbar.js +2 -2
- package/lib/components/toolbar/Toolbar.js.map +1 -1
- package/lib/components/toolbar/TooltipHelpContent.js +2 -2
- package/package.json +19 -16
- package/src/components/activity_bar/activity_bar.tsx +1 -1
- package/src/components/activity_panel/activity_panel.tsx +1 -1
- package/src/components/drop-zone/DropZone.tsx +1 -1
- package/src/components/forms/radio-button-group/RadioButton.tsx +7 -7
- package/src/components/forms/radio-button-group/RadioButtonGroup.tsx +15 -11
- package/src/components/forms/styles.ts +0 -2
- package/src/components/header/PanelHeader.tsx +6 -1
- package/src/components/index.ts +1 -1
- package/src/components/info-panel/InfoPanel.tsx +2 -2
- package/src/components/logger/FifoLoggerDialog.tsx +2 -2
- package/src/components/split_pane/index.ts +2 -0
- package/src/components/{split-pane/SplitPane.tsx → split_pane/split_pane.tsx} +63 -56
- package/src/components/split_pane/split_pane_helpers.ts +19 -0
- package/src/components/split_pane/use_split_pane_size.tsx +120 -0
- package/src/components/table/index.ts +1 -0
- package/src/components/table/reorder_rows/draggable_row_context.ts +23 -0
- package/src/components/table/reorder_rows/draggable_row_tr.tsx +166 -0
- package/src/components/table/reorder_rows/drop_indicator.tsx +28 -0
- package/src/components/table/reorder_rows/dropped_item_context.ts +23 -0
- package/src/components/table/reorder_rows/dropped_item_provider.tsx +13 -0
- package/src/components/table/reorder_rows/index.ts +4 -0
- package/src/components/table/reorder_rows/item_data.ts +33 -0
- package/src/components/table/reorder_rows/item_order_context.ts +27 -0
- package/src/components/table/reorder_rows/item_order_provider.tsx +61 -0
- package/src/components/table/reorder_rows/table_drag_row_handler.tsx +22 -0
- package/src/components/table/reorder_rows/use_drop_monitor.ts +74 -0
- package/src/components/table/table_body.tsx +58 -9
- package/src/components/table/table_root.tsx +167 -35
- package/src/components/table/table_row_cell.tsx +5 -3
- package/src/components/table/table_utils.ts +16 -2
- package/src/components/toolbar/Toolbar.tsx +2 -2
- package/src/components/toolbar/TooltipHelpContent.tsx +2 -2
- package/lib/components/split-pane/SplitPane.d.ts.map +0 -1
- package/lib/components/split-pane/SplitPane.js.map +0 -1
- package/lib/components/split-pane/index.d.ts +0 -2
- package/lib/components/split-pane/index.d.ts.map +0 -1
- package/lib/components/split-pane/index.js +0 -2
- package/lib/components/split-pane/index.js.map +0 -1
- package/lib/components/split-pane/useSplitPaneSize.d.ts.map +0 -1
- package/lib/components/split-pane/useSplitPaneSize.js +0 -60
- package/lib/components/split-pane/useSplitPaneSize.js.map +0 -1
- package/src/components/split-pane/index.ts +0 -1
- package/src/components/split-pane/useSplitPaneSize.tsx +0 -99
|
@@ -0,0 +1,166 @@
|
|
|
1
|
+
import { combine } from '@atlaskit/pragmatic-drag-and-drop/combine';
|
|
2
|
+
import type { ElementDragPayload } from '@atlaskit/pragmatic-drag-and-drop/element/adapter';
|
|
3
|
+
import {
|
|
4
|
+
draggable,
|
|
5
|
+
dropTargetForElements,
|
|
6
|
+
} from '@atlaskit/pragmatic-drag-and-drop/element/adapter';
|
|
7
|
+
import { pointerOutsideOfPreview } from '@atlaskit/pragmatic-drag-and-drop/element/pointer-outside-of-preview';
|
|
8
|
+
import { setCustomNativeDragPreview } from '@atlaskit/pragmatic-drag-and-drop/element/set-custom-native-drag-preview';
|
|
9
|
+
import {
|
|
10
|
+
attachClosestEdge,
|
|
11
|
+
extractClosestEdge,
|
|
12
|
+
} from '@atlaskit/pragmatic-drag-and-drop-hitbox/closest-edge';
|
|
13
|
+
import { Colors } from '@blueprintjs/core';
|
|
14
|
+
import type { Row, RowData } from '@tanstack/react-table';
|
|
15
|
+
import { useEffect, useMemo, useRef, useState } from 'react';
|
|
16
|
+
import { createPortal } from 'react-dom';
|
|
17
|
+
|
|
18
|
+
import { assert } from '../../utils/index.js';
|
|
19
|
+
import type {
|
|
20
|
+
TableRowPreviewRenderer,
|
|
21
|
+
TableRowTrProps,
|
|
22
|
+
} from '../table_utils.js';
|
|
23
|
+
|
|
24
|
+
import type { DraggableRowContext } from './draggable_row_context.js';
|
|
25
|
+
import { draggableRowContext } from './draggable_row_context.js';
|
|
26
|
+
import { useDroppedItemContext } from './dropped_item_context.js';
|
|
27
|
+
import type { DraggableItemState } from './item_data.js';
|
|
28
|
+
import { getItemData, isItemData } from './item_data.js';
|
|
29
|
+
import { useItemOrder } from './item_order_context.js';
|
|
30
|
+
|
|
31
|
+
export interface TableDraggableRowTrProps<TData extends RowData> {
|
|
32
|
+
/**
|
|
33
|
+
* Props to be spread on the `tr` element.
|
|
34
|
+
*/
|
|
35
|
+
trProps: TableRowTrProps;
|
|
36
|
+
/**
|
|
37
|
+
* Row data.
|
|
38
|
+
*/
|
|
39
|
+
row: Row<TData>;
|
|
40
|
+
/**
|
|
41
|
+
* Preview of the row being dragged.
|
|
42
|
+
*/
|
|
43
|
+
renderRowPreview: TableRowPreviewRenderer<TData>;
|
|
44
|
+
}
|
|
45
|
+
|
|
46
|
+
export function TableDraggableRowTr<TData extends RowData>(
|
|
47
|
+
props: TableDraggableRowTrProps<TData>,
|
|
48
|
+
) {
|
|
49
|
+
const { trProps, row, renderRowPreview } = props;
|
|
50
|
+
const { instanceId } = useItemOrder();
|
|
51
|
+
const innerRef = useRef<HTMLTableRowElement>(null);
|
|
52
|
+
const [state, setState] = useState<DraggableItemState>(idleState);
|
|
53
|
+
const [droppedItemId, setDroppedItemId] = useDroppedItemContext();
|
|
54
|
+
|
|
55
|
+
const dragHandleRef = useRef<HTMLButtonElement>(null);
|
|
56
|
+
useEffect(() => {
|
|
57
|
+
const trElement = innerRef.current;
|
|
58
|
+
assert(trElement, 'tr ref is null');
|
|
59
|
+
assert(dragHandleRef.current, 'dragHandleRef is null');
|
|
60
|
+
|
|
61
|
+
function canDrop({ source }: { source: ElementDragPayload }): boolean {
|
|
62
|
+
return (
|
|
63
|
+
isItemData(source.data) &&
|
|
64
|
+
source.data.instanceId === instanceId &&
|
|
65
|
+
source.data.id !== row.id
|
|
66
|
+
);
|
|
67
|
+
}
|
|
68
|
+
|
|
69
|
+
const data = getItemData(row as Row<unknown>, instanceId);
|
|
70
|
+
|
|
71
|
+
return combine(
|
|
72
|
+
draggable({
|
|
73
|
+
element: trElement,
|
|
74
|
+
dragHandle: dragHandleRef.current,
|
|
75
|
+
getInitialData: () => data,
|
|
76
|
+
onGenerateDragPreview({ nativeSetDragImage }) {
|
|
77
|
+
setCustomNativeDragPreview({
|
|
78
|
+
nativeSetDragImage,
|
|
79
|
+
getOffset: pointerOutsideOfPreview({
|
|
80
|
+
x: '8px',
|
|
81
|
+
y: '8px',
|
|
82
|
+
}),
|
|
83
|
+
render({ container }) {
|
|
84
|
+
setState({ type: 'preview', container });
|
|
85
|
+
|
|
86
|
+
return () => setState(draggingState);
|
|
87
|
+
},
|
|
88
|
+
});
|
|
89
|
+
},
|
|
90
|
+
onDragStart() {
|
|
91
|
+
setState(draggingState);
|
|
92
|
+
},
|
|
93
|
+
onDrop() {
|
|
94
|
+
setState(idleState);
|
|
95
|
+
},
|
|
96
|
+
}),
|
|
97
|
+
dropTargetForElements({
|
|
98
|
+
element: trElement,
|
|
99
|
+
canDrop,
|
|
100
|
+
getIsSticky: () => false,
|
|
101
|
+
getData({ input }) {
|
|
102
|
+
return attachClosestEdge(data, {
|
|
103
|
+
element: trElement,
|
|
104
|
+
input,
|
|
105
|
+
allowedEdges: ['top', 'bottom'],
|
|
106
|
+
});
|
|
107
|
+
},
|
|
108
|
+
onDrag({ self }) {
|
|
109
|
+
const closestEdge = extractClosestEdge(self.data);
|
|
110
|
+
setState((current) => {
|
|
111
|
+
if (
|
|
112
|
+
current.type === 'is-over' &&
|
|
113
|
+
current.closestEdge === closestEdge
|
|
114
|
+
) {
|
|
115
|
+
return current;
|
|
116
|
+
}
|
|
117
|
+
return { type: 'is-over', closestEdge };
|
|
118
|
+
});
|
|
119
|
+
},
|
|
120
|
+
onDragLeave() {
|
|
121
|
+
setState(idleState);
|
|
122
|
+
},
|
|
123
|
+
onDrop() {
|
|
124
|
+
setState(idleState);
|
|
125
|
+
},
|
|
126
|
+
}),
|
|
127
|
+
);
|
|
128
|
+
}, [row, instanceId]);
|
|
129
|
+
|
|
130
|
+
useEffect(() => {
|
|
131
|
+
if (droppedItemId === row.id && innerRef.current) {
|
|
132
|
+
triggerPostFlash(innerRef.current);
|
|
133
|
+
setDroppedItemId(undefined);
|
|
134
|
+
}
|
|
135
|
+
}, [droppedItemId, row.id, setDroppedItemId]);
|
|
136
|
+
|
|
137
|
+
const value = useMemo<DraggableRowContext>(() => {
|
|
138
|
+
return {
|
|
139
|
+
dragHandleRef,
|
|
140
|
+
state,
|
|
141
|
+
};
|
|
142
|
+
}, [state]);
|
|
143
|
+
|
|
144
|
+
return (
|
|
145
|
+
<>
|
|
146
|
+
<draggableRowContext.Provider value={value}>
|
|
147
|
+
<tr {...trProps} ref={innerRef} />
|
|
148
|
+
</draggableRowContext.Provider>
|
|
149
|
+
{state.type === 'preview' &&
|
|
150
|
+
createPortal(renderRowPreview(row), state.container)}
|
|
151
|
+
</>
|
|
152
|
+
);
|
|
153
|
+
}
|
|
154
|
+
|
|
155
|
+
const idleState: DraggableItemState = { type: 'idle' };
|
|
156
|
+
const draggingState: DraggableItemState = { type: 'dragging' };
|
|
157
|
+
|
|
158
|
+
function triggerPostFlash(element: HTMLElement) {
|
|
159
|
+
element.animate(
|
|
160
|
+
[{ backgroundColor: Colors.BLUE5, opacity: 0.5 }, { opacity: 0.5 }],
|
|
161
|
+
{
|
|
162
|
+
duration: 250,
|
|
163
|
+
iterations: 1,
|
|
164
|
+
},
|
|
165
|
+
);
|
|
166
|
+
}
|
|
@@ -0,0 +1,28 @@
|
|
|
1
|
+
import type { Edge } from '@atlaskit/pragmatic-drag-and-drop-hitbox/types';
|
|
2
|
+
import { Colors } from '@blueprintjs/core';
|
|
3
|
+
import styled from '@emotion/styled';
|
|
4
|
+
|
|
5
|
+
export interface TableDropIndicatorProps {
|
|
6
|
+
/**
|
|
7
|
+
* The edge (top or bottom) on which to render the drop indicator
|
|
8
|
+
* with respect to the nearest relatively positioned element.
|
|
9
|
+
*/
|
|
10
|
+
edge: Edge;
|
|
11
|
+
}
|
|
12
|
+
|
|
13
|
+
/**
|
|
14
|
+
* An absolutely positioned line which indicates where a dragged item will
|
|
15
|
+
* be dropped.
|
|
16
|
+
*
|
|
17
|
+
*/
|
|
18
|
+
export const TableDropIndicator = styled.div<TableDropIndicatorProps>`
|
|
19
|
+
position: absolute;
|
|
20
|
+
z-index: 1;
|
|
21
|
+
background-color: ${Colors.BLUE3};
|
|
22
|
+
height: 2px;
|
|
23
|
+
left: 0;
|
|
24
|
+
right: 0;
|
|
25
|
+
pointer-events: none;
|
|
26
|
+
${(props) => props.edge === 'top' && 'top: -1px;'}
|
|
27
|
+
${(props) => props.edge === 'bottom' && 'bottom: -1px;'}
|
|
28
|
+
`;
|
|
@@ -0,0 +1,23 @@
|
|
|
1
|
+
import type { useState } from 'react';
|
|
2
|
+
import { createContext, useContext } from 'react';
|
|
3
|
+
|
|
4
|
+
/**
|
|
5
|
+
* ID of the dropped item
|
|
6
|
+
*/
|
|
7
|
+
type DroppedItemContextValue = ReturnType<typeof useState<string>>;
|
|
8
|
+
|
|
9
|
+
export const droppedItemContext = createContext<DroppedItemContextValue | null>(
|
|
10
|
+
null,
|
|
11
|
+
);
|
|
12
|
+
|
|
13
|
+
export function useDroppedItemContext() {
|
|
14
|
+
const context = useContext(droppedItemContext);
|
|
15
|
+
|
|
16
|
+
if (!context) {
|
|
17
|
+
throw new Error(
|
|
18
|
+
'useDroppedItemId must be used within a DroppedItemProvider',
|
|
19
|
+
);
|
|
20
|
+
}
|
|
21
|
+
|
|
22
|
+
return context;
|
|
23
|
+
}
|
|
@@ -0,0 +1,13 @@
|
|
|
1
|
+
import { useState } from 'react';
|
|
2
|
+
import type { ReactNode } from 'react';
|
|
3
|
+
|
|
4
|
+
import { droppedItemContext } from './dropped_item_context.js';
|
|
5
|
+
|
|
6
|
+
export function DroppedItemProvider(props: { children: ReactNode }) {
|
|
7
|
+
const value = useState<string>();
|
|
8
|
+
return (
|
|
9
|
+
<droppedItemContext.Provider value={value}>
|
|
10
|
+
{props.children}
|
|
11
|
+
</droppedItemContext.Provider>
|
|
12
|
+
);
|
|
13
|
+
}
|
|
@@ -0,0 +1,33 @@
|
|
|
1
|
+
import type { Edge } from '@atlaskit/pragmatic-drag-and-drop-hitbox/types';
|
|
2
|
+
import type { Row } from '@tanstack/react-table';
|
|
3
|
+
|
|
4
|
+
const itemKey = Symbol('table-item-data');
|
|
5
|
+
export interface ItemData {
|
|
6
|
+
[itemKey]: true;
|
|
7
|
+
instanceId: symbol;
|
|
8
|
+
id: string;
|
|
9
|
+
index: number;
|
|
10
|
+
[key: string]: unknown;
|
|
11
|
+
[key: symbol]: unknown;
|
|
12
|
+
}
|
|
13
|
+
|
|
14
|
+
export function getItemData(row: Row<unknown>, instanceId: symbol): ItemData {
|
|
15
|
+
return {
|
|
16
|
+
[itemKey]: true,
|
|
17
|
+
id: row.id,
|
|
18
|
+
index: row.index,
|
|
19
|
+
instanceId,
|
|
20
|
+
};
|
|
21
|
+
}
|
|
22
|
+
|
|
23
|
+
export function isItemData(
|
|
24
|
+
data: Record<string | symbol, unknown>,
|
|
25
|
+
): data is ItemData {
|
|
26
|
+
return data[itemKey] === true;
|
|
27
|
+
}
|
|
28
|
+
|
|
29
|
+
export type DraggableItemState =
|
|
30
|
+
| { type: 'idle' }
|
|
31
|
+
| { type: 'preview'; container: HTMLElement }
|
|
32
|
+
| { type: 'dragging' }
|
|
33
|
+
| { type: 'is-over'; closestEdge: Edge | null };
|
|
@@ -0,0 +1,27 @@
|
|
|
1
|
+
import type { Edge } from '@atlaskit/pragmatic-drag-and-drop-hitbox/types';
|
|
2
|
+
import type { Row } from '@tanstack/react-table';
|
|
3
|
+
import { createContext, useContext } from 'react';
|
|
4
|
+
|
|
5
|
+
export type ReorderItemCallback = (args: {
|
|
6
|
+
startIndex: number;
|
|
7
|
+
indexOfTarget: number;
|
|
8
|
+
closestEdgeOfTarget: Edge | null;
|
|
9
|
+
}) => void;
|
|
10
|
+
|
|
11
|
+
export interface ItemOrderContextValue<T = unknown> {
|
|
12
|
+
items: Array<Row<T>>;
|
|
13
|
+
reorderItem: ReorderItemCallback;
|
|
14
|
+
instanceId: symbol;
|
|
15
|
+
}
|
|
16
|
+
|
|
17
|
+
export const itemOrderContext = createContext<ItemOrderContextValue | null>(
|
|
18
|
+
null,
|
|
19
|
+
);
|
|
20
|
+
|
|
21
|
+
export function useItemOrder() {
|
|
22
|
+
const context = useContext(itemOrderContext);
|
|
23
|
+
if (!context) {
|
|
24
|
+
throw new Error('useItemOrder must be used within a ListContextProvider');
|
|
25
|
+
}
|
|
26
|
+
return context;
|
|
27
|
+
}
|
|
@@ -0,0 +1,61 @@
|
|
|
1
|
+
import { reorder } from '@atlaskit/pragmatic-drag-and-drop/reorder';
|
|
2
|
+
import { getReorderDestinationIndex } from '@atlaskit/pragmatic-drag-and-drop-hitbox/util/get-reorder-destination-index';
|
|
3
|
+
import type { Row } from '@tanstack/react-table';
|
|
4
|
+
import type { ReactNode } from 'react';
|
|
5
|
+
import { useCallback, useMemo, useState } from 'react';
|
|
6
|
+
|
|
7
|
+
import type { ReorderItemCallback } from './item_order_context.js';
|
|
8
|
+
import { itemOrderContext } from './item_order_context.js';
|
|
9
|
+
|
|
10
|
+
interface ItemOrderProviderProps<T> {
|
|
11
|
+
items: Array<Row<T>>;
|
|
12
|
+
onOrderChanged: (items: Array<Row<T>>) => void;
|
|
13
|
+
children: ReactNode;
|
|
14
|
+
}
|
|
15
|
+
|
|
16
|
+
export function ItemOrderProvider<T = unknown>(
|
|
17
|
+
props: ItemOrderProviderProps<T>,
|
|
18
|
+
) {
|
|
19
|
+
// Isolated instances of this component from one another
|
|
20
|
+
const [instanceId] = useState(() => Symbol('table-instance-id'));
|
|
21
|
+
const { items, onOrderChanged, children } = props;
|
|
22
|
+
const reorderItem = useCallback<ReorderItemCallback>(
|
|
23
|
+
({ startIndex, indexOfTarget, closestEdgeOfTarget }) => {
|
|
24
|
+
const finishIndex = getReorderDestinationIndex({
|
|
25
|
+
startIndex,
|
|
26
|
+
closestEdgeOfTarget,
|
|
27
|
+
indexOfTarget,
|
|
28
|
+
axis: 'vertical',
|
|
29
|
+
});
|
|
30
|
+
|
|
31
|
+
if (finishIndex === startIndex) {
|
|
32
|
+
// If there is no change, we skip the update
|
|
33
|
+
return;
|
|
34
|
+
}
|
|
35
|
+
|
|
36
|
+
onOrderChanged(
|
|
37
|
+
reorder({
|
|
38
|
+
list: items,
|
|
39
|
+
startIndex,
|
|
40
|
+
finishIndex,
|
|
41
|
+
}),
|
|
42
|
+
);
|
|
43
|
+
},
|
|
44
|
+
[items, onOrderChanged],
|
|
45
|
+
);
|
|
46
|
+
|
|
47
|
+
const value = useMemo(
|
|
48
|
+
() => ({
|
|
49
|
+
reorderItem,
|
|
50
|
+
items: items as Array<Row<unknown>>,
|
|
51
|
+
instanceId,
|
|
52
|
+
}),
|
|
53
|
+
[reorderItem, items, instanceId],
|
|
54
|
+
);
|
|
55
|
+
|
|
56
|
+
return (
|
|
57
|
+
<itemOrderContext.Provider value={value}>
|
|
58
|
+
{children}
|
|
59
|
+
</itemOrderContext.Provider>
|
|
60
|
+
);
|
|
61
|
+
}
|
|
@@ -0,0 +1,22 @@
|
|
|
1
|
+
import { Button } from '@blueprintjs/core';
|
|
2
|
+
|
|
3
|
+
import { useTableDraggableRowContext } from './draggable_row_context.js';
|
|
4
|
+
import { TableDropIndicator } from './drop_indicator.js';
|
|
5
|
+
|
|
6
|
+
export function TableDragRowHandler() {
|
|
7
|
+
const { dragHandleRef, state } = useTableDraggableRowContext();
|
|
8
|
+
return (
|
|
9
|
+
<>
|
|
10
|
+
<Button
|
|
11
|
+
icon="drag-handle-horizontal"
|
|
12
|
+
type="button"
|
|
13
|
+
ref={dragHandleRef}
|
|
14
|
+
variant="minimal"
|
|
15
|
+
style={{ cursor: 'grab' }}
|
|
16
|
+
/>
|
|
17
|
+
{state?.type === 'is-over' && state.closestEdge && (
|
|
18
|
+
<TableDropIndicator edge={state.closestEdge} />
|
|
19
|
+
)}
|
|
20
|
+
</>
|
|
21
|
+
);
|
|
22
|
+
}
|
|
@@ -0,0 +1,74 @@
|
|
|
1
|
+
import { combine } from '@atlaskit/pragmatic-drag-and-drop/combine';
|
|
2
|
+
import type { ElementDragPayload } from '@atlaskit/pragmatic-drag-and-drop/element/adapter';
|
|
3
|
+
import { monitorForElements } from '@atlaskit/pragmatic-drag-and-drop/element/adapter';
|
|
4
|
+
import { autoScrollForElements } from '@atlaskit/pragmatic-drag-and-drop-auto-scroll/element';
|
|
5
|
+
import { extractClosestEdge } from '@atlaskit/pragmatic-drag-and-drop-hitbox/closest-edge';
|
|
6
|
+
import type { RefObject } from 'react';
|
|
7
|
+
import { useEffect } from 'react';
|
|
8
|
+
|
|
9
|
+
import { assert } from '../../utils/index.js';
|
|
10
|
+
|
|
11
|
+
import { useDroppedItemContext } from './dropped_item_context.js';
|
|
12
|
+
import { isItemData } from './item_data.js';
|
|
13
|
+
import { useItemOrder } from './item_order_context.js';
|
|
14
|
+
|
|
15
|
+
/**
|
|
16
|
+
* Monitor drop events.
|
|
17
|
+
* Check if they can be acted on to reorder items.
|
|
18
|
+
* @param scrollElementRef The element to auto-scroll when dragging elements.
|
|
19
|
+
* @param enabled Enable or disable the monitoring.
|
|
20
|
+
*/
|
|
21
|
+
export function useDropMonitor(
|
|
22
|
+
scrollElementRef: RefObject<Element>,
|
|
23
|
+
enabled: boolean,
|
|
24
|
+
) {
|
|
25
|
+
const { reorderItem, items } = useItemOrder();
|
|
26
|
+
const [, setDroppedItem] = useDroppedItemContext();
|
|
27
|
+
useEffect(() => {
|
|
28
|
+
const scrollContainer = scrollElementRef.current;
|
|
29
|
+
assert(scrollContainer, 'Missing scroll container ref');
|
|
30
|
+
|
|
31
|
+
if (enabled) {
|
|
32
|
+
function canRespond({ source }: { source: ElementDragPayload }) {
|
|
33
|
+
return isItemData(source.data);
|
|
34
|
+
}
|
|
35
|
+
return combine(
|
|
36
|
+
monitorForElements({
|
|
37
|
+
canMonitor: canRespond,
|
|
38
|
+
onDrop({ location, source }) {
|
|
39
|
+
const target = location.current.dropTargets[0];
|
|
40
|
+
if (!target) {
|
|
41
|
+
return;
|
|
42
|
+
}
|
|
43
|
+
|
|
44
|
+
const sourceData = source.data;
|
|
45
|
+
const targetData = target.data;
|
|
46
|
+
if (!isItemData(sourceData) || !isItemData(targetData)) {
|
|
47
|
+
return;
|
|
48
|
+
}
|
|
49
|
+
|
|
50
|
+
const indexOfTarget = items.findIndex(
|
|
51
|
+
(item) => item.id === targetData.id,
|
|
52
|
+
);
|
|
53
|
+
if (indexOfTarget === -1) {
|
|
54
|
+
return;
|
|
55
|
+
}
|
|
56
|
+
|
|
57
|
+
const closestEdgeOfTarget = extractClosestEdge(targetData);
|
|
58
|
+
|
|
59
|
+
reorderItem({
|
|
60
|
+
startIndex: sourceData.index,
|
|
61
|
+
indexOfTarget,
|
|
62
|
+
closestEdgeOfTarget,
|
|
63
|
+
});
|
|
64
|
+
setDroppedItem(sourceData.id);
|
|
65
|
+
},
|
|
66
|
+
}),
|
|
67
|
+
autoScrollForElements({
|
|
68
|
+
canScroll: canRespond,
|
|
69
|
+
element: scrollContainer,
|
|
70
|
+
}),
|
|
71
|
+
);
|
|
72
|
+
}
|
|
73
|
+
}, [items, reorderItem, scrollElementRef, setDroppedItem, enabled]);
|
|
74
|
+
}
|
|
@@ -1,23 +1,37 @@
|
|
|
1
|
+
import { Tag } from '@blueprintjs/core';
|
|
1
2
|
import type { Row, RowData } from '@tanstack/react-table';
|
|
2
3
|
import type { VirtualItem, Virtualizer } from '@tanstack/react-virtual';
|
|
3
4
|
import { notUndefined } from '@tanstack/react-virtual';
|
|
4
5
|
import type { ReactNode } from 'react';
|
|
5
6
|
import { Fragment } from 'react';
|
|
6
7
|
|
|
8
|
+
import { TableDraggableRowTr } from './reorder_rows/index.js';
|
|
7
9
|
import { TableRowCell } from './table_row_cell.js';
|
|
8
|
-
import type {
|
|
10
|
+
import type {
|
|
11
|
+
GetTdProps,
|
|
12
|
+
TableRowPreviewRenderer,
|
|
13
|
+
TableRowTrProps,
|
|
14
|
+
TableRowTrRenderer,
|
|
15
|
+
} from './table_utils.js';
|
|
9
16
|
|
|
10
17
|
interface TableBodyProps<TData extends RowData> {
|
|
11
18
|
rows: Array<Row<TData>>;
|
|
19
|
+
getTdProps?: GetTdProps<TData>;
|
|
12
20
|
renderRowTr: TableRowTrRenderer<TData> | undefined;
|
|
13
21
|
virtualizeRows?: boolean;
|
|
14
22
|
virtualizer: Virtualizer<HTMLDivElement, Element>;
|
|
23
|
+
isReorderingEnabled: boolean;
|
|
24
|
+
renderRowPreview?: TableRowPreviewRenderer<TData>;
|
|
15
25
|
}
|
|
16
26
|
|
|
17
27
|
export function TableBody<TData extends RowData>(props: TableBodyProps<TData>) {
|
|
18
28
|
const {
|
|
19
29
|
rows,
|
|
20
|
-
|
|
30
|
+
getTdProps,
|
|
31
|
+
renderRowTr = getDefaultRenderRowTr(
|
|
32
|
+
props.isReorderingEnabled,
|
|
33
|
+
props.renderRowPreview as TableRowPreviewRenderer<unknown>,
|
|
34
|
+
) as TableRowTrRenderer<TData>,
|
|
21
35
|
virtualizer,
|
|
22
36
|
virtualizeRows,
|
|
23
37
|
} = props;
|
|
@@ -43,7 +57,7 @@ export function TableBody<TData extends RowData>(props: TableBodyProps<TData>) {
|
|
|
43
57
|
key={virtualItem.index}
|
|
44
58
|
row={rows[virtualItem.index]}
|
|
45
59
|
renderRowTr={(row) => {
|
|
46
|
-
const trProps = getTrRenderProps<TData>(row, {
|
|
60
|
+
const trProps = getTrRenderProps<TData>(row, getTdProps, {
|
|
47
61
|
...virtualItem,
|
|
48
62
|
virtualIndex: index,
|
|
49
63
|
});
|
|
@@ -65,7 +79,9 @@ export function TableBody<TData extends RowData>(props: TableBodyProps<TData>) {
|
|
|
65
79
|
<TableRow
|
|
66
80
|
key={row.id}
|
|
67
81
|
row={row}
|
|
68
|
-
renderRowTr={(row) =>
|
|
82
|
+
renderRowTr={(row) =>
|
|
83
|
+
renderRowTr(getTrRenderProps(row, getTdProps), row)
|
|
84
|
+
}
|
|
69
85
|
/>
|
|
70
86
|
))}
|
|
71
87
|
</tbody>
|
|
@@ -84,10 +100,6 @@ function TableRow<TData>({
|
|
|
84
100
|
return <Fragment>{renderRowTr(row)}</Fragment>;
|
|
85
101
|
}
|
|
86
102
|
|
|
87
|
-
const defaultRenderRowTr: TableRowTrRenderer<unknown> = (trProps) => (
|
|
88
|
-
<tr {...trProps} />
|
|
89
|
-
);
|
|
90
|
-
|
|
91
103
|
type RenderRowVirtualItem = VirtualItem & {
|
|
92
104
|
/**
|
|
93
105
|
* The index of the element within the virtual list being currently rendered.
|
|
@@ -97,6 +109,7 @@ type RenderRowVirtualItem = VirtualItem & {
|
|
|
97
109
|
|
|
98
110
|
function getTrRenderProps<TData extends RowData>(
|
|
99
111
|
row: Row<TData>,
|
|
112
|
+
getTdProps: GetTdProps<TData> | undefined,
|
|
100
113
|
virtualItem?: RenderRowVirtualItem,
|
|
101
114
|
): TableRowTrProps {
|
|
102
115
|
const index = virtualItem ? virtualItem.index : row.index;
|
|
@@ -104,9 +117,45 @@ function getTrRenderProps<TData extends RowData>(
|
|
|
104
117
|
return {
|
|
105
118
|
// index is 0-indexed, so odd rows are even indices
|
|
106
119
|
className: index % 2 === 0 ? 'odd' : '',
|
|
120
|
+
style: { position: 'relative' },
|
|
107
121
|
children: row
|
|
108
122
|
.getVisibleCells()
|
|
109
|
-
.map((cell) =>
|
|
123
|
+
.map((cell) => (
|
|
124
|
+
<TableRowCell<TData>
|
|
125
|
+
key={cell.id}
|
|
126
|
+
cell={cell}
|
|
127
|
+
getTdProps={getTdProps}
|
|
128
|
+
/>
|
|
129
|
+
)),
|
|
110
130
|
'data-row-id': row.id,
|
|
111
131
|
};
|
|
112
132
|
}
|
|
133
|
+
|
|
134
|
+
function getDefaultRenderRowTr(
|
|
135
|
+
isReorderingEnabled: boolean,
|
|
136
|
+
renderRowPreview: TableRowPreviewRenderer<unknown> | undefined,
|
|
137
|
+
): TableRowTrRenderer<unknown> {
|
|
138
|
+
if (isReorderingEnabled) {
|
|
139
|
+
return getDefaultRenderDraggableRowTr(renderRowPreview);
|
|
140
|
+
} else {
|
|
141
|
+
return defaultRenderRowTr;
|
|
142
|
+
}
|
|
143
|
+
}
|
|
144
|
+
|
|
145
|
+
const defaultRenderRowTr: TableRowTrRenderer<unknown> = (trProps) => (
|
|
146
|
+
<tr {...trProps} />
|
|
147
|
+
);
|
|
148
|
+
|
|
149
|
+
function getDefaultRenderDraggableRowTr(
|
|
150
|
+
renderRowPreview: TableRowPreviewRenderer<unknown> | undefined,
|
|
151
|
+
): TableRowTrRenderer<unknown> {
|
|
152
|
+
return (trProps, row) => (
|
|
153
|
+
<TableDraggableRowTr
|
|
154
|
+
trProps={trProps}
|
|
155
|
+
row={row}
|
|
156
|
+
renderRowPreview={
|
|
157
|
+
renderRowPreview ?? ((row) => <Tag>Row {row.index + 1}</Tag>)
|
|
158
|
+
}
|
|
159
|
+
/>
|
|
160
|
+
);
|
|
161
|
+
}
|