@etsoo/react 1.3.92 → 1.3.96

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.
@@ -11,7 +11,7 @@ import { RefreshTokenRQ } from './RefreshTokenRQ';
11
11
  * Use the acess token to the service api, get a service access token
12
12
  * Use the new acess token and refresh token to login
13
13
  */
14
- export declare class ServiceApp<P extends IServicePageData = IServicePageData, U extends IServiceUser = IServiceUser, S extends IServiceAppSettings = IServiceAppSettings> extends ReactApp<S, U, P> {
14
+ export declare class ServiceApp<U extends IServiceUser = IServiceUser, P extends IServicePageData = IServicePageData, S extends IServiceAppSettings = IServiceAppSettings> extends ReactApp<S, U, P> {
15
15
  /**
16
16
  * Service API
17
17
  */
@@ -48,8 +48,6 @@ export class ServiceApp extends ReactApp {
48
48
  coreUrl +
49
49
  '?serviceId=' +
50
50
  this.settings.serviceId +
51
- '&serviceDeviceId=' +
52
- encodeURIComponent(this.deviceId) +
53
51
  '&' +
54
52
  DomUtils.CultureField +
55
53
  '=' +
package/lib/index.d.ts CHANGED
@@ -38,6 +38,7 @@ export * from './mu/CustomFabProps';
38
38
  export * from './mu/DataGridEx';
39
39
  export * from './mu/DataGridRenderers';
40
40
  export * from './mu/DialogButton';
41
+ export * from './mu/DnDList';
41
42
  export * from './mu/DraggablePaperComponent';
42
43
  export * from './mu/EmailInput';
43
44
  export * from './mu/FabBox';
package/lib/index.js CHANGED
@@ -41,6 +41,7 @@ export * from './mu/CustomFabProps';
41
41
  export * from './mu/DataGridEx';
42
42
  export * from './mu/DataGridRenderers';
43
43
  export * from './mu/DialogButton';
44
+ export * from './mu/DnDList';
44
45
  export * from './mu/DraggablePaperComponent';
45
46
  export * from './mu/EmailInput';
46
47
  export * from './mu/FabBox';
@@ -0,0 +1,49 @@
1
+ import React, { CSSProperties } from 'react';
2
+ /**
3
+ * DnD list props
4
+ */
5
+ export interface DnDListProps<D extends {}, E extends React.ElementType> {
6
+ /**
7
+ * Item renderer
8
+ */
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>;
19
+ /**
20
+ * Get list item style callback
21
+ */
22
+ getItemStyle?: (isDragging: boolean) => CSSProperties;
23
+ /**
24
+ * Get list style callback
25
+ */
26
+ getListStyle?: (isDraggingOver: boolean) => CSSProperties;
27
+ /**
28
+ * Label field
29
+ */
30
+ labelField: keyof D;
31
+ /**
32
+ * Load data
33
+ */
34
+ loadData: (name: string) => PromiseLike<D[]>;
35
+ /**
36
+ * Top and bottom sides renderer
37
+ */
38
+ sideRenderer?: (top: boolean, onAdd: (item: D) => boolean) => React.ReactNode;
39
+ /**
40
+ * Name for hidden form input
41
+ */
42
+ name: string;
43
+ }
44
+ /**
45
+ * Drag and drop list
46
+ * @param props Props
47
+ * @returns Component
48
+ */
49
+ export declare function DnDList<D extends {}, E extends React.ElementType = React.ElementType>(props: DnDListProps<D, E>): JSX.Element;
@@ -0,0 +1,74 @@
1
+ import { DataTypes } from '@etsoo/shared';
2
+ import React from 'react';
3
+ import { DragDropContext, Draggable, Droppable } from 'react-beautiful-dnd';
4
+ /**
5
+ * Drag and drop list
6
+ * @param props Props
7
+ * @returns Component
8
+ */
9
+ export function DnDList(props) {
10
+ // Destruct
11
+ const { children, Component = 'div', componentProps, getItemStyle = (_isDragging) => ({}), getListStyle = () => undefined, labelField, loadData, name, sideRenderer } = props;
12
+ // State
13
+ const [items, setItems] = React.useState([]);
14
+ // Drag end handler
15
+ const onDragEnd = (result) => {
16
+ console.log(result);
17
+ // Dropped outside the list
18
+ if (!result.destination) {
19
+ return;
20
+ }
21
+ // Clone
22
+ const newItems = [...items];
23
+ // Removed item
24
+ const [removed] = newItems.splice(result.source.index, 1);
25
+ // Insert to the destination index
26
+ newItems.splice(result.destination.index, 0, removed);
27
+ // Update the state
28
+ setItems(newItems);
29
+ };
30
+ // Add handler
31
+ const onAdd = (newItem) => {
32
+ // Existence check
33
+ if (items.some((item) => item[labelField] == newItem[labelField])) {
34
+ return false;
35
+ }
36
+ // Clone
37
+ const newItems = [newItem, ...items];
38
+ // Update the state
39
+ setItems(newItems);
40
+ return true;
41
+ };
42
+ // Delete handler
43
+ const onDelete = (index) => {
44
+ // Clone
45
+ const newItems = [...items];
46
+ // Remove the item
47
+ newItems.splice(index, 1);
48
+ // Update the state
49
+ setItems(newItems);
50
+ };
51
+ React.useEffect(() => {
52
+ loadData(name).then((items) => setItems(items));
53
+ }, [name]);
54
+ // Layout
55
+ return (React.createElement(React.Fragment, null,
56
+ sideRenderer && sideRenderer(true, onAdd),
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))))),
73
+ sideRenderer && sideRenderer(false, onAdd)));
74
+ }
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@etsoo/react",
3
- "version": "1.3.92",
3
+ "version": "1.3.96",
4
4
  "description": "TypeScript ReactJs framework",
5
5
  "main": "lib/index.js",
6
6
  "types": "lib/index.d.ts",
@@ -50,17 +50,18 @@
50
50
  "@emotion/react": "^11.7.1",
51
51
  "@emotion/style": "^0.8.0",
52
52
  "@emotion/styled": "^11.6.0",
53
- "@etsoo/appscript": "^1.2.9",
53
+ "@etsoo/appscript": "^1.2.11",
54
54
  "@etsoo/notificationbase": "^1.0.95",
55
- "@etsoo/shared": "^1.0.94",
55
+ "@etsoo/shared": "^1.0.95",
56
56
  "@mui/icons-material": "^5.2.5",
57
- "@mui/material": "^5.2.5",
57
+ "@mui/material": "^5.2.6",
58
58
  "@reach/router": "^1.3.4",
59
59
  "@types/pica": "^5.1.3",
60
60
  "@types/pulltorefreshjs": "^0.1.5",
61
61
  "@types/reach__router": "^1.3.10",
62
62
  "@types/react": "^17.0.38",
63
63
  "@types/react-avatar-editor": "^10.3.6",
64
+ "@types/react-beautiful-dnd": "^13.1.2",
64
65
  "@types/react-dom": "^17.0.11",
65
66
  "@types/react-input-mask": "^3.0.1",
66
67
  "@types/react-window": "^1.8.5",
@@ -68,6 +69,7 @@
68
69
  "pulltorefreshjs": "^0.1.22",
69
70
  "react": "^17.0.2",
70
71
  "react-avatar-editor": "^12.0.0",
72
+ "react-beautiful-dnd": "^13.1.0",
71
73
  "react-dom": "^17.0.2",
72
74
  "react-draggable": "^4.4.4",
73
75
  "react-imask": "^6.2.2",
@@ -81,8 +83,8 @@
81
83
  "@babel/runtime-corejs3": "^7.16.5",
82
84
  "@types/jest": "^27.0.3",
83
85
  "@types/react-test-renderer": "^17.0.1",
84
- "@typescript-eslint/eslint-plugin": "^5.8.0",
85
- "@typescript-eslint/parser": "^5.8.0",
86
+ "@typescript-eslint/eslint-plugin": "^5.8.1",
87
+ "@typescript-eslint/parser": "^5.8.1",
86
88
  "eslint": "^8.5.0",
87
89
  "eslint-config-airbnb-base": "^15.0.0",
88
90
  "eslint-plugin-import": "^2.25.3",
@@ -21,8 +21,8 @@ import { RefreshTokenRQ } from './RefreshTokenRQ';
21
21
  * Use the new acess token and refresh token to login
22
22
  */
23
23
  export class ServiceApp<
24
- P extends IServicePageData = IServicePageData,
25
24
  U extends IServiceUser = IServiceUser,
25
+ P extends IServicePageData = IServicePageData,
26
26
  S extends IServiceAppSettings = IServiceAppSettings
27
27
  > extends ReactApp<S, U, P> {
28
28
  /**
@@ -76,8 +76,6 @@ export class ServiceApp<
76
76
  coreUrl +
77
77
  '?serviceId=' +
78
78
  this.settings.serviceId +
79
- '&serviceDeviceId=' +
80
- encodeURIComponent(this.deviceId) +
81
79
  '&' +
82
80
  DomUtils.CultureField +
83
81
  '=' +
package/src/index.ts CHANGED
@@ -45,6 +45,7 @@ export * from './mu/CustomFabProps';
45
45
  export * from './mu/DataGridEx';
46
46
  export * from './mu/DataGridRenderers';
47
47
  export * from './mu/DialogButton';
48
+ export * from './mu/DnDList';
48
49
  export * from './mu/DraggablePaperComponent';
49
50
  export * from './mu/EmailInput';
50
51
  export * from './mu/FabBox';
@@ -0,0 +1,206 @@
1
+ import { DataTypes } from '@etsoo/shared';
2
+ import React, { CSSProperties } from 'react';
3
+ import {
4
+ DragDropContext,
5
+ Draggable,
6
+ Droppable,
7
+ DropResult
8
+ } from 'react-beautiful-dnd';
9
+
10
+ /**
11
+ * DnD list props
12
+ */
13
+ export interface DnDListProps<D extends {}, E extends React.ElementType> {
14
+ /**
15
+ * Item renderer
16
+ */
17
+ children: (
18
+ item: D,
19
+ index: number,
20
+ onDelete: (index: number) => void
21
+ ) => React.ReactNode;
22
+
23
+ /**
24
+ * List container component
25
+ * https://javascript.plainenglish.io/building-a-polymorphic-component-in-react-and-typescript-d9f236950af4
26
+ */
27
+ Component?: E;
28
+
29
+ /**
30
+ * List container props
31
+ */
32
+ componentProps?: React.ComponentProps<E>;
33
+
34
+ /**
35
+ * Get list item style callback
36
+ */
37
+ getItemStyle?: (isDragging: boolean) => CSSProperties;
38
+
39
+ /**
40
+ * Get list style callback
41
+ */
42
+ getListStyle?: (isDraggingOver: boolean) => CSSProperties;
43
+
44
+ /**
45
+ * Label field
46
+ */
47
+ labelField: keyof D;
48
+
49
+ /**
50
+ * Load data
51
+ */
52
+ loadData: (name: string) => PromiseLike<D[]>;
53
+
54
+ /**
55
+ * Top and bottom sides renderer
56
+ */
57
+ sideRenderer?: (
58
+ top: boolean,
59
+ onAdd: (item: D) => boolean
60
+ ) => React.ReactNode;
61
+
62
+ /**
63
+ * Name for hidden form input
64
+ */
65
+ name: string;
66
+ }
67
+
68
+ /**
69
+ * Drag and drop list
70
+ * @param props Props
71
+ * @returns Component
72
+ */
73
+ export function DnDList<
74
+ D extends {},
75
+ E extends React.ElementType = React.ElementType
76
+ >(props: DnDListProps<D, E>) {
77
+ // Destruct
78
+ const {
79
+ children,
80
+ Component = 'div',
81
+ componentProps,
82
+ getItemStyle = (_isDragging) => ({}),
83
+ getListStyle = () => undefined,
84
+ labelField,
85
+ loadData,
86
+ name,
87
+ sideRenderer
88
+ } = props;
89
+
90
+ // State
91
+ const [items, setItems] = React.useState<D[]>([]);
92
+
93
+ // Drag end handler
94
+ const onDragEnd = (result: DropResult) => {
95
+ console.log(result);
96
+ // Dropped outside the list
97
+ if (!result.destination) {
98
+ return;
99
+ }
100
+
101
+ // Clone
102
+ const newItems = [...items];
103
+
104
+ // Removed item
105
+ const [removed] = newItems.splice(result.source.index, 1);
106
+
107
+ // Insert to the destination index
108
+ newItems.splice(result.destination.index, 0, removed);
109
+
110
+ // Update the state
111
+ setItems(newItems);
112
+ };
113
+
114
+ // Add handler
115
+ const onAdd = (newItem: D) => {
116
+ // Existence check
117
+ if (items.some((item) => item[labelField] == newItem[labelField])) {
118
+ return false;
119
+ }
120
+
121
+ // Clone
122
+ const newItems = [newItem, ...items];
123
+
124
+ // Update the state
125
+ setItems(newItems);
126
+
127
+ return true;
128
+ };
129
+
130
+ // Delete handler
131
+ const onDelete = (index: number) => {
132
+ // Clone
133
+ const newItems = [...items];
134
+
135
+ // Remove the item
136
+ newItems.splice(index, 1);
137
+
138
+ // Update the state
139
+ setItems(newItems);
140
+ };
141
+
142
+ React.useEffect(() => {
143
+ loadData(name).then((items) => setItems(items));
144
+ }, [name]);
145
+
146
+ // Layout
147
+ return (
148
+ <React.Fragment>
149
+ {sideRenderer && sideRenderer(true, onAdd)}
150
+ <Component {...componentProps}>
151
+ <DragDropContext onDragEnd={onDragEnd}>
152
+ <Droppable droppableId={name}>
153
+ {(provided, snapshot) => (
154
+ <div
155
+ {...provided.droppableProps}
156
+ ref={provided.innerRef}
157
+ style={getListStyle(snapshot.isDraggingOver)}
158
+ >
159
+ {items.map((item, index) => {
160
+ // Id
161
+ const id = DataTypes.convert(
162
+ item[labelField],
163
+ 'string'
164
+ );
165
+ if (id == null) return;
166
+
167
+ return (
168
+ <Draggable
169
+ key={id}
170
+ draggableId={id}
171
+ index={index}
172
+ >
173
+ {(provided, snapshot) => (
174
+ <div
175
+ ref={provided.innerRef}
176
+ {...provided.draggableProps}
177
+ {...provided.dragHandleProps}
178
+ style={{
179
+ ...getItemStyle(
180
+ snapshot.isDragging
181
+ ),
182
+ ...provided
183
+ .draggableProps
184
+ .style
185
+ }}
186
+ >
187
+ {children(
188
+ item,
189
+ index,
190
+ onDelete
191
+ )}
192
+ </div>
193
+ )}
194
+ </Draggable>
195
+ );
196
+ })}
197
+ {provided.placeholder}
198
+ </div>
199
+ )}
200
+ </Droppable>
201
+ </DragDropContext>
202
+ </Component>
203
+ {sideRenderer && sideRenderer(false, onAdd)}
204
+ </React.Fragment>
205
+ );
206
+ }