@etsoo/react 1.3.94 → 1.3.95

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.
@@ -1,13 +1,21 @@
1
- import { DataTypes } from '@etsoo/shared';
2
1
  import React, { CSSProperties } from 'react';
3
2
  /**
4
3
  * DnD list props
5
4
  */
6
- export interface DnDListProps {
5
+ export interface DnDListProps<D extends {}, L extends keyof D, E extends React.ElementType> {
7
6
  /**
8
7
  * Item renderer
9
8
  */
10
- children: (item: DataTypes.IdItem, index: number, onDelete: (index: number) => void) => React.ReactNode;
9
+ children: (item: D, index: number, onDelete: (index: number) => void) => React.ReactNode;
10
+ /**
11
+ * List container component
12
+ * https://javascript.plainenglish.io/building-a-polymorphic-component-in-react-and-typescript-d9f236950af4
13
+ */
14
+ Component?: E;
15
+ /**
16
+ * List container props
17
+ */
18
+ componentProps?: React.ComponentProps<E>;
11
19
  /**
12
20
  * Get list item style callback
13
21
  */
@@ -16,10 +24,18 @@ export interface DnDListProps {
16
24
  * Get list style callback
17
25
  */
18
26
  getListStyle?: (isDraggingOver: boolean) => CSSProperties;
27
+ /**
28
+ * Label field
29
+ */
30
+ labelField: L;
31
+ /**
32
+ * Load data
33
+ */
34
+ loadData: (name: string) => PromiseLike<D[]>;
19
35
  /**
20
36
  * Top and bottom sides renderer
21
37
  */
22
- sideRenderer?: (top: boolean, onAdd: (item: DataTypes.IdItem) => boolean) => React.ReactNode;
38
+ sideRenderer?: (top: boolean, onAdd: (item: D) => boolean) => React.ReactNode;
23
39
  /**
24
40
  * Name for hidden form input
25
41
  */
@@ -30,4 +46,4 @@ export interface DnDListProps {
30
46
  * @param props Props
31
47
  * @returns Component
32
48
  */
33
- export declare function DnDList(props: DnDListProps): JSX.Element;
49
+ export declare function DnDList<D extends {}, L extends keyof D, E extends React.ElementType = React.ElementType>(props: DnDListProps<D, L, E>): JSX.Element;
package/lib/mu/DnDList.js CHANGED
@@ -8,7 +8,7 @@ import { DragDropContext, Draggable, Droppable } from 'react-beautiful-dnd';
8
8
  */
9
9
  export function DnDList(props) {
10
10
  // Destruct
11
- const { children, getItemStyle = (_isDragging) => ({}), getListStyle = () => undefined, name, sideRenderer } = props;
11
+ const { children, Component = 'div', componentProps, getItemStyle = (_isDragging) => ({}), getListStyle = () => undefined, labelField, loadData, name, sideRenderer } = props;
12
12
  // State
13
13
  const [items, setItems] = React.useState([]);
14
14
  // Drag end handler
@@ -30,7 +30,7 @@ export function DnDList(props) {
30
30
  // Add handler
31
31
  const onAdd = (newItem) => {
32
32
  // Existence check
33
- if (items.some((item) => DataTypes.getItemId(item) === DataTypes.getItemId(newItem))) {
33
+ if (items.some((item) => item[labelField] == newItem[labelField])) {
34
34
  return false;
35
35
  }
36
36
  // Clone
@@ -48,19 +48,27 @@ export function DnDList(props) {
48
48
  // Update the state
49
49
  setItems(newItems);
50
50
  };
51
+ React.useEffect(() => {
52
+ loadData(name).then((items) => setItems(items));
53
+ }, [name]);
51
54
  // Layout
52
55
  return (React.createElement(React.Fragment, null,
53
56
  sideRenderer && sideRenderer(true, onAdd),
54
- React.createElement(DragDropContext, { onDragEnd: onDragEnd },
55
- React.createElement(Droppable, { droppableId: name }, (provided, snapshot) => (React.createElement("div", { ...provided.droppableProps, ref: provided.innerRef, style: getListStyle(snapshot.isDraggingOver) },
56
- items.map((item, index) => {
57
- const id = DataTypes.getItemId(item);
58
- return (React.createElement(Draggable, { key: id, draggableId: id, index: index }, (provided, snapshot) => (React.createElement("div", { ref: provided.innerRef, ...provided.draggableProps, ...provided.dragHandleProps, style: {
59
- ...getItemStyle(snapshot.isDragging),
60
- ...provided.draggableProps
61
- .style
62
- } }, children(item, index, onDelete)))));
63
- }),
64
- provided.placeholder)))),
57
+ React.createElement(Component, { ...componentProps },
58
+ React.createElement(DragDropContext, { onDragEnd: onDragEnd },
59
+ React.createElement(Droppable, { droppableId: name }, (provided, snapshot) => (React.createElement("div", { ...provided.droppableProps, ref: provided.innerRef, style: getListStyle(snapshot.isDraggingOver) },
60
+ items.map((item, index) => {
61
+ // Id
62
+ const id = DataTypes.convert(item[labelField], 'string');
63
+ if (id == null)
64
+ return;
65
+ return (React.createElement(Draggable, { key: id, draggableId: id, index: index }, (provided, snapshot) => (React.createElement("div", { ref: provided.innerRef, ...provided.draggableProps, ...provided.dragHandleProps, style: {
66
+ ...getItemStyle(snapshot.isDragging),
67
+ ...provided
68
+ .draggableProps
69
+ .style
70
+ } }, children(item, index, onDelete)))));
71
+ }),
72
+ provided.placeholder))))),
65
73
  sideRenderer && sideRenderer(false, onAdd)));
66
74
  }
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@etsoo/react",
3
- "version": "1.3.94",
3
+ "version": "1.3.95",
4
4
  "description": "TypeScript ReactJs framework",
5
5
  "main": "lib/index.js",
6
6
  "types": "lib/index.d.ts",
@@ -10,16 +10,31 @@ import {
10
10
  /**
11
11
  * DnD list props
12
12
  */
13
- export interface DnDListProps {
13
+ export interface DnDListProps<
14
+ D extends {},
15
+ L extends keyof D,
16
+ E extends React.ElementType
17
+ > {
14
18
  /**
15
19
  * Item renderer
16
20
  */
17
21
  children: (
18
- item: DataTypes.IdItem,
22
+ item: D,
19
23
  index: number,
20
24
  onDelete: (index: number) => void
21
25
  ) => React.ReactNode;
22
26
 
27
+ /**
28
+ * List container component
29
+ * https://javascript.plainenglish.io/building-a-polymorphic-component-in-react-and-typescript-d9f236950af4
30
+ */
31
+ Component?: E;
32
+
33
+ /**
34
+ * List container props
35
+ */
36
+ componentProps?: React.ComponentProps<E>;
37
+
23
38
  /**
24
39
  * Get list item style callback
25
40
  */
@@ -30,12 +45,22 @@ export interface DnDListProps {
30
45
  */
31
46
  getListStyle?: (isDraggingOver: boolean) => CSSProperties;
32
47
 
48
+ /**
49
+ * Label field
50
+ */
51
+ labelField: L;
52
+
53
+ /**
54
+ * Load data
55
+ */
56
+ loadData: (name: string) => PromiseLike<D[]>;
57
+
33
58
  /**
34
59
  * Top and bottom sides renderer
35
60
  */
36
61
  sideRenderer?: (
37
62
  top: boolean,
38
- onAdd: (item: DataTypes.IdItem) => boolean
63
+ onAdd: (item: D) => boolean
39
64
  ) => React.ReactNode;
40
65
 
41
66
  /**
@@ -49,18 +74,26 @@ export interface DnDListProps {
49
74
  * @param props Props
50
75
  * @returns Component
51
76
  */
52
- export function DnDList(props: DnDListProps) {
77
+ export function DnDList<
78
+ D extends {},
79
+ L extends keyof D,
80
+ E extends React.ElementType = React.ElementType
81
+ >(props: DnDListProps<D, L, E>) {
53
82
  // Destruct
54
83
  const {
55
84
  children,
85
+ Component = 'div',
86
+ componentProps,
56
87
  getItemStyle = (_isDragging) => ({}),
57
88
  getListStyle = () => undefined,
89
+ labelField,
90
+ loadData,
58
91
  name,
59
92
  sideRenderer
60
93
  } = props;
61
94
 
62
95
  // State
63
- const [items, setItems] = React.useState<DataTypes.IdItem[]>([]);
96
+ const [items, setItems] = React.useState<D[]>([]);
64
97
 
65
98
  // Drag end handler
66
99
  const onDragEnd = (result: DropResult) => {
@@ -84,14 +117,9 @@ export function DnDList(props: DnDListProps) {
84
117
  };
85
118
 
86
119
  // Add handler
87
- const onAdd = (newItem: DataTypes.IdItem) => {
120
+ const onAdd = (newItem: D) => {
88
121
  // Existence check
89
- if (
90
- items.some(
91
- (item) =>
92
- DataTypes.getItemId(item) === DataTypes.getItemId(newItem)
93
- )
94
- ) {
122
+ if (items.some((item) => item[labelField] == newItem[labelField])) {
95
123
  return false;
96
124
  }
97
125
 
@@ -116,54 +144,67 @@ export function DnDList(props: DnDListProps) {
116
144
  setItems(newItems);
117
145
  };
118
146
 
147
+ React.useEffect(() => {
148
+ loadData(name).then((items) => setItems(items));
149
+ }, [name]);
150
+
119
151
  // Layout
120
152
  return (
121
153
  <React.Fragment>
122
154
  {sideRenderer && sideRenderer(true, onAdd)}
123
- <DragDropContext onDragEnd={onDragEnd}>
124
- <Droppable droppableId={name}>
125
- {(provided, snapshot) => (
126
- <div
127
- {...provided.droppableProps}
128
- ref={provided.innerRef}
129
- style={getListStyle(snapshot.isDraggingOver)}
130
- >
131
- {items.map((item, index) => {
132
- const id = DataTypes.getItemId(item);
133
- return (
134
- <Draggable
135
- key={id}
136
- draggableId={id}
137
- index={index}
138
- >
139
- {(provided, snapshot) => (
140
- <div
141
- ref={provided.innerRef}
142
- {...provided.draggableProps}
143
- {...provided.dragHandleProps}
144
- style={{
145
- ...getItemStyle(
146
- snapshot.isDragging
147
- ),
148
- ...provided.draggableProps
149
- .style
150
- }}
151
- >
152
- {children(
153
- item,
154
- index,
155
- onDelete
156
- )}
157
- </div>
158
- )}
159
- </Draggable>
160
- );
161
- })}
162
- {provided.placeholder}
163
- </div>
164
- )}
165
- </Droppable>
166
- </DragDropContext>
155
+ <Component {...componentProps}>
156
+ <DragDropContext onDragEnd={onDragEnd}>
157
+ <Droppable droppableId={name}>
158
+ {(provided, snapshot) => (
159
+ <div
160
+ {...provided.droppableProps}
161
+ ref={provided.innerRef}
162
+ style={getListStyle(snapshot.isDraggingOver)}
163
+ >
164
+ {items.map((item, index) => {
165
+ // Id
166
+ const id = DataTypes.convert(
167
+ item[labelField],
168
+ 'string'
169
+ );
170
+ if (id == null) return;
171
+
172
+ return (
173
+ <Draggable
174
+ key={id}
175
+ draggableId={id}
176
+ index={index}
177
+ >
178
+ {(provided, snapshot) => (
179
+ <div
180
+ ref={provided.innerRef}
181
+ {...provided.draggableProps}
182
+ {...provided.dragHandleProps}
183
+ style={{
184
+ ...getItemStyle(
185
+ snapshot.isDragging
186
+ ),
187
+ ...provided
188
+ .draggableProps
189
+ .style
190
+ }}
191
+ >
192
+ {children(
193
+ item,
194
+ index,
195
+ onDelete
196
+ )}
197
+ </div>
198
+ )}
199
+ </Draggable>
200
+ );
201
+ })}
202
+ {provided.placeholder}
203
+ </div>
204
+ )}
205
+ </Droppable>
206
+ </DragDropContext>
207
+ </Component>
167
208
  {sideRenderer && sideRenderer(false, onAdd)}
168
209
  </React.Fragment>
169
210
  );