1
1
import { default as Pagination } from "antd/es/pagination" ;
2
2
import { EditorContext } from "comps/editorState" ;
3
3
import { BackgroundColorContext } from "comps/utils/backgroundColorContext" ;
4
- import _ from "lodash" ;
4
+ import _ , { findIndex } from "lodash" ;
5
5
import { ConstructorToView , deferAction } from "lowcoder-core" ;
6
- import { HintPlaceHolder , ScrollBar , pageItemRender } from "lowcoder-design" ;
6
+ import { DragIcon , HintPlaceHolder , ScrollBar , pageItemRender } from "lowcoder-design" ;
7
7
import { RefObject , useContext , createContext , useMemo , useRef , useEffect } from "react" ;
8
8
import ReactResizeDetector from "react-resize-detector" ;
9
9
import styled from "styled-components" ;
@@ -22,6 +22,10 @@ import { useMergeCompStyles } from "@lowcoder-ee/util/hooks";
22
22
import { childrenToProps } from "@lowcoder-ee/comps/generators/multi" ;
23
23
import { AnimationStyleType } from "@lowcoder-ee/comps/controls/styleControlConstants" ;
24
24
import { getBackgroundStyle } from "@lowcoder-ee/util/styleUtils" ;
25
+ import { DndContext } from "@dnd-kit/core" ;
26
+ import { SortableContext , useSortable } from "@dnd-kit/sortable" ;
27
+ import { CSS } from "@dnd-kit/utilities" ;
28
+ import { JSONObject } from "@lowcoder-ee/index.sdk" ;
25
29
26
30
const ListViewWrapper = styled . div < { $style : any ; $paddingWidth : string , $animationStyle :AnimationStyleType } > `
27
31
height: 100%;
@@ -63,6 +67,22 @@ const ListOrientationWrapper = styled.div<{
63
67
flex-direction: ${ ( props ) => ( props . $isHorizontal ? "row" : "column" ) } ;
64
68
` ;
65
69
70
+ const StyledDragIcon = styled ( DragIcon ) `
71
+ height: 16px;
72
+ width: 16px;
73
+ color: #8b8fa3;
74
+
75
+ &:hover {
76
+ cursor: grab;
77
+ outline: none;
78
+ }
79
+
80
+ &:focus {
81
+ cursor: grab;
82
+ outline: none;
83
+ }
84
+ ` ;
85
+
66
86
type MinHorizontalWidthContextType = {
67
87
horizontalWidth : string ,
68
88
minHorizontalWidth ?: string ,
@@ -73,19 +93,48 @@ const MinHorizontalWidthContext = createContext<MinHorizontalWidthContextType>({
73
93
minHorizontalWidth : '100px' ,
74
94
} ) ;
75
95
76
- const ContainerInListView = ( props : ContainerBaseProps ) => {
96
+ const ContainerInListView = ( props : ContainerBaseProps & { itemIdx : number , enableSorting ?: boolean } ) => {
77
97
const {
78
98
horizontalWidth,
79
99
minHorizontalWidth
80
100
} = useContext ( MinHorizontalWidthContext ) ;
81
101
102
+ const { attributes, listeners, setNodeRef, transform, transition } = useSortable ( {
103
+ id : String ( props . itemIdx ) ,
104
+ } ) ;
105
+
106
+ if ( ! props . enableSorting ) {
107
+ return (
108
+ < div
109
+ style = { {
110
+ width : horizontalWidth ,
111
+ minWidth : minHorizontalWidth || '0px' ,
112
+ } }
113
+ >
114
+ < InnerGrid
115
+ { ...props }
116
+ emptyRows = { 15 }
117
+ containerPadding = { [ 4 , 4 ] }
118
+ hintPlaceholder = { HintPlaceHolder }
119
+ />
120
+ </ div >
121
+ )
122
+ }
123
+
82
124
return (
83
125
< div
126
+ ref = { setNodeRef }
84
127
style = { {
85
128
width : horizontalWidth ,
86
129
minWidth : minHorizontalWidth || '0px' ,
130
+ transform : CSS . Transform . toString ( transform ) ,
131
+ transition,
132
+ display : 'flex' ,
133
+ flexWrap : 'nowrap' ,
134
+ alignItems : 'center' ,
87
135
} }
88
136
>
137
+ { < StyledDragIcon { ...attributes } { ...listeners } /> }
89
138
< InnerGrid
90
139
{ ...props }
91
140
emptyRows = { 15 }
@@ -107,6 +156,7 @@ type ListItemProps = {
107
156
unMountFn ?: ( ) => void ;
108
157
minHorizontalWidth ?: string ;
109
158
horizontalWidth : string ;
159
+ enableSorting ?: boolean ;
110
160
} ;
111
161
112
162
function ListItem ( {
@@ -122,6 +172,7 @@ function ListItem({
122
172
scrollContainerRef,
123
173
minHeight,
124
174
horizontalGridCells,
175
+ enableSorting,
125
176
} = props ;
126
177
127
178
// disable the unmount function to save user's state with pagination
@@ -133,35 +184,37 @@ function ListItem({
133
184
// }, []);
134
185
135
186
return (
136
- < MinHorizontalWidthContext . Provider
137
- value = { {
138
- horizontalWidth,
139
- minHorizontalWidth
187
+ < MinHorizontalWidthContext . Provider
188
+ value = { {
189
+ horizontalWidth,
190
+ minHorizontalWidth
191
+ } }
192
+ >
193
+ < ContainerInListView
194
+ itemIdx = { itemIdx }
195
+ layout = { containerProps . layout }
196
+ items = { gridItemCompToGridItems ( containerProps . items ) }
197
+ horizontalGridCells = { horizontalGridCells }
198
+ positionParams = { containerProps . positionParams }
199
+ // all layout changes should only reflect on the commonContainer
200
+ dispatch = { itemIdx === offset ? containerProps . dispatch : _ . noop }
201
+ style = { {
202
+ height : "100%" ,
203
+ // in case of horizontal mode, minHorizontalWidth is 0px
204
+ width : minHorizontalWidth || '100%' ,
205
+ backgroundColor : "transparent" ,
206
+ // flex: "auto",
140
207
} }
141
- >
142
- < ContainerInListView
143
- layout = { containerProps . layout }
144
- items = { gridItemCompToGridItems ( containerProps . items ) }
145
- horizontalGridCells = { horizontalGridCells }
146
- positionParams = { containerProps . positionParams }
147
- // all layout changes should only reflect on the commonContainer
148
- dispatch = { itemIdx === offset ? containerProps . dispatch : _ . noop }
149
- style = { {
150
- height : "100%" ,
151
- // in case of horizontal mode, minHorizontalWidth is 0px
152
- width : minHorizontalWidth || '100%' ,
153
- backgroundColor : "transparent" ,
154
- // flex: "auto",
155
- } }
156
- autoHeight = { autoHeight }
157
- isDroppable = { itemIdx === offset }
158
- isDraggable = { itemIdx === offset }
159
- isResizable = { itemIdx === offset }
160
- isSelectable = { itemIdx === offset }
161
- scrollContainerRef = { scrollContainerRef }
162
- overflow = { "hidden" }
163
- minHeight = { minHeight }
164
- enableGridLines = { true }
208
+ autoHeight = { autoHeight }
209
+ isDroppable = { itemIdx === offset }
210
+ isDraggable = { itemIdx === offset }
211
+ isResizable = { itemIdx === offset }
212
+ isSelectable = { itemIdx === offset }
213
+ scrollContainerRef = { scrollContainerRef }
214
+ overflow = { "hidden" }
215
+ minHeight = { minHeight }
216
+ enableGridLines = { true }
217
+ enableSorting = { enableSorting }
165
218
/>
166
219
</ MinHorizontalWidthContext . Provider >
167
220
) ;
@@ -190,6 +243,7 @@ export function ListView(props: Props) {
190
243
( ) => getData ( children . noOfRows . getView ( ) ) ,
191
244
[ children . noOfRows ]
192
245
) ;
246
+ const listData = useMemo ( ( ) => children . listData . getView ( ) , [ children . listData ] ) ;
193
247
const horizontalGridCells = useMemo ( ( ) => children . horizontalGridCells . getView ( ) , [ children . horizontalGridCells ] ) ;
194
248
const autoHeight = useMemo ( ( ) => children . autoHeight . getView ( ) , [ children . autoHeight ] ) ;
195
249
const showHorizontalScrollbar = useMemo ( ( ) => children . showHorizontalScrollbar . getView ( ) , [ children . showHorizontalScrollbar ] ) ;
@@ -213,6 +267,13 @@ export function ListView(props: Props) {
213
267
total,
214
268
} ;
215
269
} , [ children . pagination , totalCount ] ) ;
270
+
271
+ const enableSorting = useMemo ( ( ) => children . enableSorting . getView ( ) , [ children . enableSorting ] ) ;
272
+
273
+ useEffect ( ( ) => {
274
+ children . listData . dispatchChangeValueAction ( data ) ;
275
+ } , [ JSON . stringify ( data ) ] ) ;
276
+
216
277
const style = children . style . getView ( ) ;
217
278
const animationStyle = children . animationStyle . getView ( ) ;
218
279
@@ -229,6 +290,7 @@ export function ListView(props: Props) {
229
290
// log.log("List. listHeight: ", listHeight, " minHeight: ", minHeight);
230
291
const renders = _ . range ( 0 , noOfRows ) . map ( ( rowIdx ) => {
231
292
// log.log("renders. i: ", i, "containerProps: ", containerProps, " text: ", Object.values(containerProps.items as Record<string, any>)[0].children.comp.children.text);
293
+ const items = _ . range ( 0 , noOfColumns ) ;
232
294
const render = (
233
295
< div
234
296
key = { rowIdx }
@@ -238,7 +300,7 @@ export function ListView(props: Props) {
238
300
} }
239
301
>
240
302
< FlexWrapper >
241
- { _ . range ( 0 , noOfColumns ) . map ( ( colIdx ) => {
303
+ { items . map ( ( colIdx ) => {
242
304
const itemIdx = rowIdx * noOfColumns + colIdx + pageInfo . offset ;
243
305
if (
244
306
itemIdx >= pageInfo . total ||
@@ -250,7 +312,7 @@ export function ListView(props: Props) {
250
312
const containerProps = containerFn (
251
313
{
252
314
[ itemIndexName ] : itemIdx ,
253
- [ itemDataName ] : getCurrentItemParams ( data , itemIdx )
315
+ [ itemDataName ] : getCurrentItemParams ( listData as JSONObject [ ] , itemIdx )
254
316
} ,
255
317
String ( itemIdx )
256
318
) . getView ( ) ;
@@ -259,6 +321,7 @@ export function ListView(props: Props) {
259
321
deferAction ( ContextContainerComp . batchDeleteAction ( [ String ( itemIdx ) ] ) )
260
322
) ;
261
323
} ;
324
+
262
325
return (
263
326
< ListItem
264
327
key = { itemIdx }
@@ -272,12 +335,14 @@ export function ListView(props: Props) {
272
335
unMountFn = { unMountFn }
273
336
horizontalWidth = { `${ 100 / noOfColumns } %` }
274
337
minHorizontalWidth = { horizontal ? minHorizontalWidth : undefined }
338
+ enableSorting = { enableSorting }
275
339
/>
276
340
) ;
277
341
} ) }
278
342
</ FlexWrapper >
279
343
</ div >
280
344
) ;
345
+
281
346
return render ;
282
347
} ) ;
283
348
@@ -289,6 +354,23 @@ export function ListView(props: Props) {
289
354
290
355
useMergeCompStyles ( childrenProps , comp . dispatch ) ;
291
356
357
+ const handleDragEnd = ( e : { active : { id : string } ; over : { id : string } | null } ) => {
358
+ if ( ! e . over ) {
359
+ return ;
360
+ }
361
+ const fromIndex = Number ( e . active . id ) ;
362
+ const toIndex = Number ( e . over . id ) ;
363
+ if ( fromIndex < 0 || toIndex < 0 || fromIndex === toIndex ) {
364
+ return ;
365
+ }
366
+
367
+ const newData = [ ...listData ] ;
368
+ const [ movedItem ] = newData . splice ( fromIndex , 1 ) ;
369
+ newData . splice ( toIndex , 0 , movedItem ) ;
370
+
371
+ children . listData . dispatchChangeValueAction ( newData ) ;
372
+ } ;
373
+
292
374
// log.debug("renders: ", renders);
293
375
return (
294
376
< BackgroundColorContext . Provider value = { style . background } >
@@ -306,7 +388,20 @@ export function ListView(props: Props) {
306
388
$isGrid = { noOfColumns > 1 }
307
389
$autoHeight = { autoHeight }
308
390
>
309
- { renders }
391
+ { ! enableSorting
392
+ ? renders
393
+ : (
394
+ < DndContext onDragEnd = { handleDragEnd } >
395
+ < SortableContext
396
+ items = {
397
+ _ . range ( 0 , totalCount ) . map ( ( colIdx ) => String ( colIdx ) )
398
+ }
399
+ >
400
+ { renders }
401
+ </ SortableContext >
402
+ </ DndContext >
403
+ )
404
+ }
310
405
</ ListOrientationWrapper >
311
406
) }
312
407
>
0 commit comments