@tsed/react-formio 2.0.2 → 2.1.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/coverage.json +4 -4
- package/dist/components/actions-table/actionsTable.component.d.ts +1 -1
- package/dist/components/form-access/formAccess.component.d.ts +1 -1
- package/dist/components/form-edit/formEdit.stories.d.ts +1 -1
- package/dist/components/forms-table/formsTable.component.d.ts +1 -1
- package/dist/components/submissions-table/submissionsTable.component.d.ts +1 -1
- package/dist/components/table/components/defaultCells.component.d.ts +4 -0
- package/dist/components/table/components/defaultRow.component.d.ts +12 -0
- package/dist/components/table/components/dragNDropContainer.d.ts +4 -0
- package/dist/components/table/hooks/useCustomTable.hook.d.ts +187 -0
- package/dist/components/table/hooks/useDragnDropRow.hook.d.ts +266 -0
- package/dist/components/table/index.d.ts +2 -1
- package/dist/components/table/table.component.d.ts +2 -71
- package/dist/components/table/table.stories.d.ts +25 -0
- package/dist/components/table/utils/swapElements.d.ts +1 -0
- package/dist/components/table/utils/swapElements.spec.d.ts +1 -0
- package/dist/index.js +315 -88
- package/dist/index.js.map +1 -1
- package/dist/index.modern.js +445 -225
- package/dist/index.modern.js.map +1 -1
- package/package.json +5 -3
- package/src/components/actions-table/actionsTable.component.tsx +2 -1
- package/src/components/form-access/formAccess.component.tsx +1 -1
- package/src/components/form-edit/formEdit.stories.tsx +2 -2
- package/src/components/forms-table/formsTable.component.tsx +2 -1
- package/src/components/forms-table/formsTable.stories.tsx +2 -2
- package/src/components/submissions-table/submissionsTable.component.tsx +2 -1
- package/src/components/table/components/defaultCells.component.tsx +21 -0
- package/src/components/table/components/defaultRow.component.tsx +50 -0
- package/src/components/table/components/dragNDropContainer.tsx +7 -0
- package/src/components/table/hooks/useCustomTable.hook.tsx +231 -0
- package/src/components/table/hooks/useDragnDropRow.hook.ts +80 -0
- package/src/components/table/index.ts +2 -1
- package/src/components/table/table.component.tsx +83 -233
- package/src/components/table/table.stories.tsx +56 -0
- package/src/components/table/utils/swapElements.spec.ts +7 -0
- package/src/components/table/utils/swapElements.ts +7 -0
- /package/dist/components/table/{utils → hooks}/useOperations.hook.d.ts +0 -0
- /package/src/components/table/{utils → hooks}/useOperations.hook.tsx +0 -0
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@tsed/react-formio",
|
|
3
|
-
"version": "2.0
|
|
3
|
+
"version": "2.1.0",
|
|
4
4
|
"description": "Provide a react formio wrapper. Written in TypeScript.",
|
|
5
5
|
"main": "dist/index.js",
|
|
6
6
|
"module": "dist/index.modern.js",
|
|
@@ -23,13 +23,15 @@
|
|
|
23
23
|
"lodash": ">=4.17.20",
|
|
24
24
|
"prop-types": ">=15.7.2",
|
|
25
25
|
"react": ">=16.14.0",
|
|
26
|
+
"react-dnd": ">=16.0.1",
|
|
27
|
+
"react-dnd-html5-backend": ">=16.0.1",
|
|
26
28
|
"react-dom": ">=16.14.0",
|
|
27
29
|
"react-table": ">=7.6.3",
|
|
28
30
|
"tooltip.js": ">=1.3.3"
|
|
29
31
|
},
|
|
30
32
|
"devDependencies": {
|
|
31
|
-
"@tsed/tailwind": "2.0
|
|
32
|
-
"@tsed/tailwind-formio": "2.0
|
|
33
|
+
"@tsed/tailwind": "2.1.0",
|
|
34
|
+
"@tsed/tailwind-formio": "2.1.0"
|
|
33
35
|
},
|
|
34
36
|
"repository": "https://github.com/TypedProject/tsed-formio",
|
|
35
37
|
"bugs": {
|
|
@@ -5,7 +5,8 @@ import React, { useState } from "react";
|
|
|
5
5
|
import { ActionSchema } from "../../interfaces";
|
|
6
6
|
import { iconClass } from "../../utils/iconClass";
|
|
7
7
|
import { Select } from "../select/select.component";
|
|
8
|
-
import {
|
|
8
|
+
import { TableProps } from "../table/hooks/useCustomTable.hook";
|
|
9
|
+
import { Table } from "../table/table.component";
|
|
9
10
|
|
|
10
11
|
export type ActionsTableProps = Omit<TableProps<ActionSchema>, "columns"> & {
|
|
11
12
|
onAddAction?: (actionName: string) => void;
|
|
@@ -1,7 +1,7 @@
|
|
|
1
1
|
import PropTypes from "prop-types";
|
|
2
2
|
import React, { PropsWithChildren, ReactElement, useCallback, useEffect, useMemo, useState } from "react";
|
|
3
3
|
|
|
4
|
-
import { FormOptions, FormSchema, Submission } from "../../interfaces";
|
|
4
|
+
import type { FormOptions, FormSchema, Submission } from "../../interfaces";
|
|
5
5
|
import { Card } from "../card/card.component";
|
|
6
6
|
import { Form } from "../form/form.component";
|
|
7
7
|
import { ChangedSubmission } from "../form/useForm.hook";
|
|
@@ -1,8 +1,8 @@
|
|
|
1
1
|
import React from "react";
|
|
2
2
|
|
|
3
|
-
import { FormEdit } from "
|
|
3
|
+
import { FormEdit } from "./formEdit.component";
|
|
4
4
|
import { defaultDisplayChoices } from "./formParameters.component";
|
|
5
|
-
|
|
5
|
+
console.log("===", FormEdit);
|
|
6
6
|
export default {
|
|
7
7
|
title: "ReactFormio/FormEdit",
|
|
8
8
|
component: FormEdit,
|
|
@@ -3,7 +3,8 @@ import React from "react";
|
|
|
3
3
|
import { FormSchema } from "../../interfaces";
|
|
4
4
|
import { DefaultColumnFilter } from "../table/filters/defaultColumnFilter.component";
|
|
5
5
|
import { SelectColumnFilter } from "../table/filters/selectColumnFilter.component";
|
|
6
|
-
import {
|
|
6
|
+
import { TableProps } from "../table/hooks/useCustomTable.hook";
|
|
7
|
+
import { Table } from "../table/table.component";
|
|
7
8
|
import { FormsCell as DefaultFormCell } from "./components/formCell.component";
|
|
8
9
|
|
|
9
10
|
export type FormsTableProps = Omit<TableProps<FormSchema>, "columns"> & {
|
|
@@ -1,4 +1,4 @@
|
|
|
1
|
-
import
|
|
1
|
+
import tailwind from "@tsed/tailwind-formio";
|
|
2
2
|
import React from "react";
|
|
3
3
|
|
|
4
4
|
import { FormsTable } from "./formsTable.component";
|
|
@@ -10,7 +10,7 @@ export default {
|
|
|
10
10
|
icon: {
|
|
11
11
|
control: {
|
|
12
12
|
type: "select",
|
|
13
|
-
options: Object.keys(ICONS)
|
|
13
|
+
options: Object.keys(tailwind.templates.tailwind.ICONS)
|
|
14
14
|
}
|
|
15
15
|
},
|
|
16
16
|
data: {
|
|
@@ -1,7 +1,8 @@
|
|
|
1
1
|
import React from "react";
|
|
2
2
|
|
|
3
3
|
import { FormSchema, Submission } from "../../interfaces";
|
|
4
|
-
import {
|
|
4
|
+
import { TableProps } from "../table/hooks/useCustomTable.hook";
|
|
5
|
+
import { Table } from "../table/table.component";
|
|
5
6
|
import { mapFormToColumns } from "../table/utils/mapFormToColumns";
|
|
6
7
|
|
|
7
8
|
export type SubmissionsTableProps = Omit<TableProps<Submission>, "columns"> & {
|
|
@@ -0,0 +1,21 @@
|
|
|
1
|
+
import { Row } from "react-table";
|
|
2
|
+
|
|
3
|
+
export function DefaultCells<Data extends object = {}>({ row }: { row: Row<Data> }) {
|
|
4
|
+
return (
|
|
5
|
+
<>
|
|
6
|
+
{row.cells.map((cell, i) => {
|
|
7
|
+
const { hidden, colspan } = cell.column as any;
|
|
8
|
+
|
|
9
|
+
if (hidden) {
|
|
10
|
+
return null;
|
|
11
|
+
}
|
|
12
|
+
|
|
13
|
+
return (
|
|
14
|
+
<td colSpan={colspan} {...cell.getCellProps()} key={`tableInstance.page.cells.${cell.value || "value"}.${i}`}>
|
|
15
|
+
{cell.render("Cell")}
|
|
16
|
+
</td>
|
|
17
|
+
);
|
|
18
|
+
})}
|
|
19
|
+
</>
|
|
20
|
+
);
|
|
21
|
+
}
|
|
@@ -0,0 +1,50 @@
|
|
|
1
|
+
import classnames from "classnames";
|
|
2
|
+
import React, { DetailedHTMLProps, HTMLAttributes } from "react";
|
|
3
|
+
import { Row } from "react-table";
|
|
4
|
+
|
|
5
|
+
import { iconClass } from "../../../utils/iconClass";
|
|
6
|
+
import { useDndRow } from "../hooks/useDragnDropRow.hook";
|
|
7
|
+
import { DefaultCells } from "./defaultCells.component";
|
|
8
|
+
|
|
9
|
+
export interface DefaultRowProps<Data extends object = {}>
|
|
10
|
+
extends Omit<DetailedHTMLProps<HTMLAttributes<HTMLTableRowElement>, HTMLTableRowElement>, "onClick" | "onDrag" | "onDrop"> {
|
|
11
|
+
onClick: (data: any, action: string) => void;
|
|
12
|
+
row: Row<Data>;
|
|
13
|
+
index: number;
|
|
14
|
+
onDrop: (item: Data) => void;
|
|
15
|
+
onDrag: (index: number, hoverIndex: number) => void;
|
|
16
|
+
enableDragNDrop?: boolean;
|
|
17
|
+
}
|
|
18
|
+
|
|
19
|
+
export function DefaultDndRow<Data extends object = {}>(props: DefaultRowProps<Data>) {
|
|
20
|
+
const { isDragging, dragRef, dropRef, opacity } = useDndRow(props);
|
|
21
|
+
|
|
22
|
+
return (
|
|
23
|
+
<tr ref={dropRef} style={{ opacity }}>
|
|
24
|
+
<td ref={dragRef} role='cell' style={{ cursor: isDragging ? "grabbing" : "grab" }} className='align-middle'>
|
|
25
|
+
<div className='flex items-center justify-center'>
|
|
26
|
+
<i className={classnames(iconClass(undefined, "dots-vertical-rounded"))} />
|
|
27
|
+
</div>
|
|
28
|
+
</td>
|
|
29
|
+
<DefaultCells<Data> {...props} />
|
|
30
|
+
</tr>
|
|
31
|
+
);
|
|
32
|
+
}
|
|
33
|
+
|
|
34
|
+
export function DefaultRow<Data extends object = {}>({ onClick, row, enableDragNDrop, onDrop, onDrag, ...props }: DefaultRowProps<Data>) {
|
|
35
|
+
const opts = {
|
|
36
|
+
...props,
|
|
37
|
+
onClick: () => onClick(row.original, "row"),
|
|
38
|
+
...row.getRowProps()
|
|
39
|
+
};
|
|
40
|
+
|
|
41
|
+
if (enableDragNDrop) {
|
|
42
|
+
return <DefaultDndRow<Data> {...opts} row={row} onDrag={onDrag} onDrop={onDrop} />;
|
|
43
|
+
}
|
|
44
|
+
|
|
45
|
+
return (
|
|
46
|
+
<tr {...opts}>
|
|
47
|
+
<DefaultCells<Data> row={row} />
|
|
48
|
+
</tr>
|
|
49
|
+
);
|
|
50
|
+
}
|
|
@@ -0,0 +1,7 @@
|
|
|
1
|
+
import { PropsWithChildren } from "react";
|
|
2
|
+
import { DndProvider } from "react-dnd";
|
|
3
|
+
import { HTML5Backend } from "react-dnd-html5-backend";
|
|
4
|
+
|
|
5
|
+
export function DrapNDropContainer({ enableDragNDrop, children }: PropsWithChildren<{ enableDragNDrop?: boolean }>) {
|
|
6
|
+
return enableDragNDrop ? <DndProvider backend={HTML5Backend}>{children}</DndProvider> : <>{children}</>;
|
|
7
|
+
}
|
|
@@ -0,0 +1,231 @@
|
|
|
1
|
+
import noop from "lodash/noop";
|
|
2
|
+
import React, { PropsWithChildren, useState } from "react";
|
|
3
|
+
import { CellProps, FilterProps, Renderer, TableOptions, useFilters, useGroupBy, usePagination, useSortBy, useTable } from "react-table";
|
|
4
|
+
|
|
5
|
+
import { OnClickOperation, Operation, QueryOptions } from "../../../interfaces";
|
|
6
|
+
import { Pagination as DefaultPagination } from "../../pagination/pagination.component";
|
|
7
|
+
import { DefaultArrowSort } from "../components/defaultArrowSort.component";
|
|
8
|
+
import { DefaultCellHeader, DefaultCellHeaderProps } from "../components/defaultCellHeader.component";
|
|
9
|
+
import { DefaultRow, DefaultRowProps } from "../components/defaultRow.component";
|
|
10
|
+
import { DefaultColumnFilter } from "../filters/defaultColumnFilter.component";
|
|
11
|
+
import { swapElements } from "../utils/swapElements";
|
|
12
|
+
import { useOperations } from "./useOperations.hook";
|
|
13
|
+
|
|
14
|
+
export interface TableProps<Data extends object = any> extends TableOptions<Data>, Partial<QueryOptions> {
|
|
15
|
+
className?: string;
|
|
16
|
+
/**
|
|
17
|
+
* Call the listener when a filter / pagination / sort change.
|
|
18
|
+
*/
|
|
19
|
+
onChange?: (query: QueryOptions) => void;
|
|
20
|
+
/**
|
|
21
|
+
* Call the listener when a line is clicked.
|
|
22
|
+
*/
|
|
23
|
+
onClick?: OnClickOperation<Data>;
|
|
24
|
+
/**
|
|
25
|
+
* Pagination steps list
|
|
26
|
+
*/
|
|
27
|
+
pageSizes?: number[];
|
|
28
|
+
/**
|
|
29
|
+
*
|
|
30
|
+
*/
|
|
31
|
+
isLoading?: boolean;
|
|
32
|
+
/**
|
|
33
|
+
* Custom EmptyData displayed when there is no data
|
|
34
|
+
*/
|
|
35
|
+
EmptyData?: React.ComponentType;
|
|
36
|
+
/**
|
|
37
|
+
* Custom ArrowSort
|
|
38
|
+
*/
|
|
39
|
+
ArrowSort?: React.ComponentType;
|
|
40
|
+
/**
|
|
41
|
+
* Custom default ColumnFilter
|
|
42
|
+
*/
|
|
43
|
+
ColumnFilter?: Renderer<FilterProps<Data>>;
|
|
44
|
+
/**
|
|
45
|
+
* Custom cell
|
|
46
|
+
*/
|
|
47
|
+
Cell?: React.ComponentType<CellProps<Data>>;
|
|
48
|
+
/**
|
|
49
|
+
* Custom Row
|
|
50
|
+
*/
|
|
51
|
+
Row?: React.ComponentType<DefaultRowProps<Data>>;
|
|
52
|
+
/**
|
|
53
|
+
*
|
|
54
|
+
*/
|
|
55
|
+
CellHeader?: React.ComponentType<DefaultCellHeaderProps<Data>>;
|
|
56
|
+
/**
|
|
57
|
+
*
|
|
58
|
+
*/
|
|
59
|
+
CellOperations?: React.ComponentType;
|
|
60
|
+
/**
|
|
61
|
+
* Custom Loader
|
|
62
|
+
*/
|
|
63
|
+
Loader?: React.ComponentType;
|
|
64
|
+
/**
|
|
65
|
+
* Custom Loader
|
|
66
|
+
*/
|
|
67
|
+
Pagination?: React.ComponentType;
|
|
68
|
+
/**
|
|
69
|
+
* Disable filters
|
|
70
|
+
*/
|
|
71
|
+
disableFilters?: boolean;
|
|
72
|
+
/**
|
|
73
|
+
* Disable pagination
|
|
74
|
+
*/
|
|
75
|
+
disablePagination?: boolean;
|
|
76
|
+
manualPagination?: boolean;
|
|
77
|
+
manualSortBy?: boolean;
|
|
78
|
+
manualFilters?: boolean;
|
|
79
|
+
/**
|
|
80
|
+
* Configuration operation for each line.
|
|
81
|
+
*/
|
|
82
|
+
operations?: Operation[];
|
|
83
|
+
|
|
84
|
+
i18n?: (f: string) => string;
|
|
85
|
+
|
|
86
|
+
/**
|
|
87
|
+
* Enable drag and drop rows
|
|
88
|
+
*/
|
|
89
|
+
enableDragNDrop?: boolean;
|
|
90
|
+
onDrag?: (data: Data[]) => void;
|
|
91
|
+
onDrop?: (item: Data) => void;
|
|
92
|
+
}
|
|
93
|
+
|
|
94
|
+
export function getOperationCallback(operations: Operation[], onClick: OnClickOperation) {
|
|
95
|
+
return (data: any, action: string) => {
|
|
96
|
+
const operation = operations.find((operation) => operation.action === action || operation.alias === action);
|
|
97
|
+
if (operation) {
|
|
98
|
+
onClick(data, operation);
|
|
99
|
+
}
|
|
100
|
+
};
|
|
101
|
+
}
|
|
102
|
+
|
|
103
|
+
function DefaultLoader() {
|
|
104
|
+
return <div className={"text-center p-2 pb-4 font-bold"}>Loading in progress</div>;
|
|
105
|
+
}
|
|
106
|
+
|
|
107
|
+
function DefaultEmptyData() {
|
|
108
|
+
return <div className='text-center p-2 pb-4 font-bold'>No data found</div>;
|
|
109
|
+
}
|
|
110
|
+
|
|
111
|
+
const hooks = [useFilters, useGroupBy, useSortBy, usePagination];
|
|
112
|
+
|
|
113
|
+
export function useCustomTable<Data extends object = {}>(props: PropsWithChildren<TableProps<Data>>) {
|
|
114
|
+
const {
|
|
115
|
+
children,
|
|
116
|
+
className = "",
|
|
117
|
+
columns,
|
|
118
|
+
data,
|
|
119
|
+
onChange = noop,
|
|
120
|
+
onClick = noop,
|
|
121
|
+
onDrag = noop,
|
|
122
|
+
onDrop = noop,
|
|
123
|
+
operations = [],
|
|
124
|
+
pageSizes = [10, 25, 50, 100],
|
|
125
|
+
filters: controlledFilters,
|
|
126
|
+
filterId: controlledFilterId,
|
|
127
|
+
pageSize: controlledPageSize,
|
|
128
|
+
pageIndex: controlledPageIndex,
|
|
129
|
+
sortBy: controlledSortBy,
|
|
130
|
+
isLoading,
|
|
131
|
+
disableFilters,
|
|
132
|
+
disablePagination,
|
|
133
|
+
ArrowSort = DefaultArrowSort,
|
|
134
|
+
ColumnFilter = DefaultColumnFilter,
|
|
135
|
+
EmptyData = DefaultEmptyData,
|
|
136
|
+
Loader = DefaultLoader,
|
|
137
|
+
Pagination = DefaultPagination,
|
|
138
|
+
Row = DefaultRow,
|
|
139
|
+
CellHeader = DefaultCellHeader as any,
|
|
140
|
+
CellOperations,
|
|
141
|
+
i18n = (f: string) => f,
|
|
142
|
+
...ctx
|
|
143
|
+
} = props;
|
|
144
|
+
|
|
145
|
+
const _onClick = getOperationCallback(operations, onClick);
|
|
146
|
+
|
|
147
|
+
const defaultColumn = React.useMemo(
|
|
148
|
+
() => ({
|
|
149
|
+
// Let's set up our default Filter UI
|
|
150
|
+
Filter: ColumnFilter,
|
|
151
|
+
ArrowSort
|
|
152
|
+
}),
|
|
153
|
+
[ColumnFilter, ArrowSort]
|
|
154
|
+
) as any;
|
|
155
|
+
|
|
156
|
+
const [filterId, setFilterId] = React.useState(controlledFilterId);
|
|
157
|
+
|
|
158
|
+
// DND
|
|
159
|
+
const [records, setRecords] = useState<Data[]>(data);
|
|
160
|
+
const _onDrag = (dragIndex: number, hoverIndex: number) => {
|
|
161
|
+
const newRecords = swapElements([...records], dragIndex, hoverIndex);
|
|
162
|
+
|
|
163
|
+
setRecords(newRecords);
|
|
164
|
+
|
|
165
|
+
onDrag(newRecords);
|
|
166
|
+
};
|
|
167
|
+
|
|
168
|
+
const tableInstance = useTable<Data>(
|
|
169
|
+
{
|
|
170
|
+
...props,
|
|
171
|
+
columns,
|
|
172
|
+
data,
|
|
173
|
+
ctx,
|
|
174
|
+
defaultColumn,
|
|
175
|
+
// getRowId,
|
|
176
|
+
initialState: {
|
|
177
|
+
...(props.initialState || {}),
|
|
178
|
+
filters: controlledFilters || [],
|
|
179
|
+
pageIndex: controlledPageIndex || 0,
|
|
180
|
+
pageSize: controlledPageSize || 10,
|
|
181
|
+
sortBy: controlledSortBy || []
|
|
182
|
+
} as any,
|
|
183
|
+
manualPagination: props.manualPagination === undefined ? true : props.manualPagination,
|
|
184
|
+
manualSortBy: props.manualSortBy === undefined ? true : props.manualPagination,
|
|
185
|
+
manualFilters: props.manualFilters === undefined ? true : props.manualFilters,
|
|
186
|
+
disableFilters,
|
|
187
|
+
filterId,
|
|
188
|
+
setFilterId
|
|
189
|
+
} as any,
|
|
190
|
+
...hooks,
|
|
191
|
+
useOperations({ operations, CellOperations, onClick: _onClick, ctx, i18n })
|
|
192
|
+
);
|
|
193
|
+
|
|
194
|
+
const {
|
|
195
|
+
setPageSize,
|
|
196
|
+
state: { pageIndex, pageSize, sortBy, filters }
|
|
197
|
+
} = tableInstance;
|
|
198
|
+
|
|
199
|
+
React.useEffect(() => {
|
|
200
|
+
onChange({
|
|
201
|
+
pageIndex,
|
|
202
|
+
pageSize,
|
|
203
|
+
sortBy,
|
|
204
|
+
filters,
|
|
205
|
+
filterId
|
|
206
|
+
});
|
|
207
|
+
}, [onChange, pageIndex, pageSize, sortBy, filters, filterId]);
|
|
208
|
+
|
|
209
|
+
return {
|
|
210
|
+
...props,
|
|
211
|
+
className,
|
|
212
|
+
tableInstance,
|
|
213
|
+
CellHeader,
|
|
214
|
+
isLoading,
|
|
215
|
+
onClick: _onClick,
|
|
216
|
+
Loader,
|
|
217
|
+
EmptyData,
|
|
218
|
+
Row,
|
|
219
|
+
data,
|
|
220
|
+
disablePagination,
|
|
221
|
+
Pagination,
|
|
222
|
+
pageIndex,
|
|
223
|
+
pageSize,
|
|
224
|
+
pageSizes,
|
|
225
|
+
setPageSize,
|
|
226
|
+
i18n,
|
|
227
|
+
children,
|
|
228
|
+
onDrag: _onDrag,
|
|
229
|
+
onDrop: onDrop
|
|
230
|
+
};
|
|
231
|
+
}
|
|
@@ -0,0 +1,80 @@
|
|
|
1
|
+
import { useRef } from "react";
|
|
2
|
+
import { useDrag, useDrop } from "react-dnd";
|
|
3
|
+
|
|
4
|
+
import { DefaultRowProps } from "../components/defaultRow.component";
|
|
5
|
+
|
|
6
|
+
const DND_ITEM_TYPE = "row";
|
|
7
|
+
|
|
8
|
+
export function useDndRow<Data extends object = {}>({ onDrag, onDrop, index, ...props }: DefaultRowProps<Data>) {
|
|
9
|
+
const dropRef = useRef<HTMLTableRowElement>(null);
|
|
10
|
+
const dragRef = useRef<HTMLTableDataCellElement>(null);
|
|
11
|
+
|
|
12
|
+
const [, drop] = useDrop<Data>({
|
|
13
|
+
accept: DND_ITEM_TYPE,
|
|
14
|
+
drop(item) {
|
|
15
|
+
onDrop(item);
|
|
16
|
+
},
|
|
17
|
+
hover(item: any, monitor) {
|
|
18
|
+
if (!dropRef.current) {
|
|
19
|
+
return;
|
|
20
|
+
}
|
|
21
|
+
const dragIndex = item.index;
|
|
22
|
+
const hoverIndex = index;
|
|
23
|
+
// Don't replace items with themselves
|
|
24
|
+
if (dragIndex === hoverIndex) {
|
|
25
|
+
return;
|
|
26
|
+
}
|
|
27
|
+
// Determine rectangle on screen
|
|
28
|
+
const hoverBoundingRect = dropRef.current!.getBoundingClientRect();
|
|
29
|
+
// Get vertical middle
|
|
30
|
+
const hoverMiddleY = (hoverBoundingRect.bottom - hoverBoundingRect.top) / 2;
|
|
31
|
+
// Determine mouse position
|
|
32
|
+
const clientOffset = monitor.getClientOffset();
|
|
33
|
+
if (!clientOffset) {
|
|
34
|
+
return;
|
|
35
|
+
}
|
|
36
|
+
// Get pixels to the top
|
|
37
|
+
const hoverClientY = clientOffset.y - hoverBoundingRect.top;
|
|
38
|
+
// Only perform the move when the mouse has crossed half of the items height
|
|
39
|
+
// When dragging downwards, only move when the cursor is below 50%
|
|
40
|
+
// When dragging upwards, only move when the cursor is above 50%
|
|
41
|
+
// Dragging downwards
|
|
42
|
+
if (dragIndex < hoverIndex && hoverClientY < hoverMiddleY) {
|
|
43
|
+
return;
|
|
44
|
+
}
|
|
45
|
+
// Dragging upwards
|
|
46
|
+
if (dragIndex > hoverIndex && hoverClientY > hoverMiddleY) {
|
|
47
|
+
return;
|
|
48
|
+
}
|
|
49
|
+
|
|
50
|
+
// Time to actually perform the action
|
|
51
|
+
onDrag(dragIndex, hoverIndex);
|
|
52
|
+
// Note: we're mutating the monitor item here!
|
|
53
|
+
// Generally it's better to avoid mutations,
|
|
54
|
+
// but it's good here for the sake of performance
|
|
55
|
+
// to avoid expensive index searches.
|
|
56
|
+
item.index = hoverIndex;
|
|
57
|
+
}
|
|
58
|
+
});
|
|
59
|
+
|
|
60
|
+
const [{ isDragging }, drag, preview] = useDrag(() => ({
|
|
61
|
+
type: DND_ITEM_TYPE,
|
|
62
|
+
item: { index },
|
|
63
|
+
collect: (monitor) => ({
|
|
64
|
+
isDragging: monitor.isDragging()
|
|
65
|
+
})
|
|
66
|
+
}));
|
|
67
|
+
|
|
68
|
+
const opacity = isDragging ? 0 : 1;
|
|
69
|
+
|
|
70
|
+
preview(drop(dropRef));
|
|
71
|
+
drag(dragRef);
|
|
72
|
+
|
|
73
|
+
return {
|
|
74
|
+
...props,
|
|
75
|
+
opacity,
|
|
76
|
+
isDragging,
|
|
77
|
+
dropRef,
|
|
78
|
+
dragRef
|
|
79
|
+
};
|
|
80
|
+
}
|
|
@@ -7,5 +7,6 @@ export * from "./components/defaultOperationButton.component";
|
|
|
7
7
|
export * from "./filters/defaultColumnFilter.component";
|
|
8
8
|
export * from "./filters/selectColumnFilter.component";
|
|
9
9
|
export * from "./filters/sliderColumnFilter.component";
|
|
10
|
+
export * from "./hooks/useCustomTable.hook";
|
|
11
|
+
export * from "./hooks/useOperations.hook";
|
|
10
12
|
export * from "./table.component";
|
|
11
|
-
export * from "./utils/useOperations.hook";
|