dce-reactkit 3.3.6 → 3.4.0-beta.1

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.
Files changed (33) hide show
  1. package/dist/cjs/index.js +37520 -379
  2. package/dist/cjs/index.js.map +1 -1
  3. package/dist/cjs/types/components/DBEntryManagerPanel/AddOrEditDBEntry/CreatableMultiselect.d.ts +10 -0
  4. package/dist/cjs/types/components/DBEntryManagerPanel/AddOrEditDBEntry/index.d.ts +33 -0
  5. package/dist/cjs/types/components/DBEntryManagerPanel/helpers/generateEndpointPath.d.ts +8 -0
  6. package/dist/cjs/types/components/DBEntryManagerPanel/index.d.ts +25 -0
  7. package/dist/cjs/types/components/DBEntryManagerPanel/types/DBEntry.d.ts +8 -0
  8. package/dist/cjs/types/components/DBEntryManagerPanel/types/DBEntryField.d.ts +49 -0
  9. package/dist/cjs/types/components/DBEntryManagerPanel/types/DBEntryFieldType.d.ts +12 -0
  10. package/dist/cjs/types/helpers/addDBEditorEndpoints.d.ts +40 -0
  11. package/dist/cjs/types/index.d.ts +6 -1
  12. package/dist/esm/index.js +37694 -574
  13. package/dist/esm/index.js.map +1 -1
  14. package/dist/esm/types/components/DBEntryManagerPanel/AddOrEditDBEntry/CreatableMultiselect.d.ts +10 -0
  15. package/dist/esm/types/components/DBEntryManagerPanel/AddOrEditDBEntry/index.d.ts +33 -0
  16. package/dist/esm/types/components/DBEntryManagerPanel/helpers/generateEndpointPath.d.ts +8 -0
  17. package/dist/esm/types/components/DBEntryManagerPanel/index.d.ts +25 -0
  18. package/dist/esm/types/components/DBEntryManagerPanel/types/DBEntry.d.ts +8 -0
  19. package/dist/esm/types/components/DBEntryManagerPanel/types/DBEntryField.d.ts +49 -0
  20. package/dist/esm/types/components/DBEntryManagerPanel/types/DBEntryFieldType.d.ts +12 -0
  21. package/dist/esm/types/helpers/addDBEditorEndpoints.d.ts +40 -0
  22. package/dist/esm/types/index.d.ts +6 -1
  23. package/dist/index.d.ts +166 -35
  24. package/package.json +8 -3
  25. package/src/components/DBEntryManagerPanel/AddOrEditDBEntry/CreatableMultiselect.tsx +290 -0
  26. package/src/components/DBEntryManagerPanel/AddOrEditDBEntry/index.tsx +699 -0
  27. package/src/components/DBEntryManagerPanel/helpers/generateEndpointPath.ts +15 -0
  28. package/src/components/DBEntryManagerPanel/index.tsx +511 -0
  29. package/src/components/DBEntryManagerPanel/types/DBEntry.ts +7 -0
  30. package/src/components/DBEntryManagerPanel/types/DBEntryField.ts +94 -0
  31. package/src/components/DBEntryManagerPanel/types/DBEntryFieldType.ts +18 -0
  32. package/src/helpers/addDBEditorEndpoints.ts +121 -0
  33. package/src/index.ts +11 -1
@@ -0,0 +1,290 @@
1
+ // Import React
2
+ import React, { KeyboardEventHandler, useReducer } from 'react';
3
+
4
+ // Import React Select
5
+ import CreatableSelect from 'react-select/creatable';
6
+ import { MultiValue } from 'react-select';
7
+
8
+ // Import other types
9
+ import DBEntryFieldType from '../types/DBEntryFieldType';
10
+
11
+
12
+ /*------------------------------------------------------------------------*/
13
+ /* -------------------------------- Types ------------------------------- */
14
+ /*------------------------------------------------------------------------*/
15
+
16
+ // Props definition
17
+ type Props = {
18
+ // Type of the field
19
+ type: DBEntryFieldType.StringArray | DBEntryFieldType.NumberArray;
20
+ // The values entered by the user
21
+ values: string[] | number[];
22
+ // Function to call when the values change
23
+ onChange: (values: string[] | number[]) => void;
24
+ // True if the field is disabled
25
+ disabled?: boolean;
26
+ };
27
+
28
+ // An option for the multiselect component
29
+ type Option = {
30
+ // What the user sees and types in for the option
31
+ label: string;
32
+ // Lowercase, no spaces, no special characters of the label
33
+ value: string;
34
+ };
35
+
36
+ /*------------------------------------------------------------------------*/
37
+ /* -------------------------------- State ------------------------------- */
38
+ /*------------------------------------------------------------------------*/
39
+
40
+ /* -------- State Definition -------- */
41
+
42
+ type State = {
43
+ // what the user has typed in so far(before pressing enter or tab)
44
+ inputValue: string,
45
+ };
46
+
47
+ /* ------------- Actions ------------ */
48
+
49
+ // Types of actions
50
+ enum ActionType {
51
+ // Update the input value
52
+ SetInputValue = 'SetInputValue',
53
+ }
54
+
55
+ // Action definitions
56
+ type Action = (
57
+ | {
58
+ // Action type
59
+ type: ActionType.SetInputValue;
60
+ // New value
61
+ value: string
62
+ }
63
+ );
64
+
65
+ /**
66
+ * Reducer that executes actions
67
+ * @author Yuen Ler Chow
68
+ * @param state current state
69
+ * @param action action to execute
70
+ */
71
+ const reducer = (state: State, action: Action): State => {
72
+ switch (action.type) {
73
+ case ActionType.SetInputValue: {
74
+ return {
75
+ ...state,
76
+ inputValue: action.value,
77
+ };
78
+ }
79
+ default: {
80
+ return state;
81
+ }
82
+ }
83
+ };
84
+
85
+ /*------------------------------------------------------------------------*/
86
+ /* -------------------------------- State ------------------------------- */
87
+ /*------------------------------------------------------------------------*/
88
+
89
+ const CreatableMultiselect: React.FC<Props> = (props) => {
90
+
91
+ // Destructure all props
92
+ const {
93
+ type,
94
+ values,
95
+ onChange,
96
+ disabled,
97
+ } = props;
98
+
99
+ /* -------------- State ------------- */
100
+
101
+ // Initial state
102
+ const initialState: State = {
103
+ inputValue: '',
104
+ };
105
+
106
+ // Initialize state
107
+ const [state, dispatch] = useReducer(reducer, initialState);
108
+
109
+ // Destructure common state
110
+ const { inputValue } = state;
111
+
112
+
113
+ /*------------------------------------------------------------------------*/
114
+ /* ------------------------- Component Functions ------------------------ */
115
+ /*------------------------------------------------------------------------*/
116
+
117
+ /**
118
+ * Creates an option for the multiselect component
119
+ * @author Yuen Ler Chow
120
+ * @param label label of the option
121
+ */
122
+ const createOption = (label: string): Option => {
123
+ // set the value to the label without special characters and spaces, and lowercase
124
+ return {
125
+ label,
126
+ value: (
127
+ label
128
+ .toLowerCase()
129
+ .replace(/\W/g, '')
130
+ .replace(' ', '-')
131
+ ),
132
+ };
133
+ };
134
+
135
+ /**
136
+ * Adds the values to the multiselect component
137
+ * @author Yuen Ler Chow
138
+ * @param newValue new value to add
139
+ */
140
+ const addValues = (newValue: string) => {
141
+ if (type === DBEntryFieldType.NumberArray) {
142
+ const newValues = (
143
+ newValue
144
+ // Split into items
145
+ .split(',')
146
+ // Trim strings
147
+ .map((val) => {
148
+ return val.trim();
149
+ })
150
+ // Filter zero length
151
+ .filter((trimmedVal) => {
152
+ return trimmedVal.length > 0;
153
+ })
154
+ // Parse to number
155
+ .map(Number.parseFloat)
156
+ // Filter out existing values
157
+ .filter((numberVal) => {
158
+ return !values.some((value) => {
159
+ return value === numberVal;
160
+ });
161
+ })
162
+ );
163
+ onChange([...values, ...newValues] as number[]);
164
+ } else {
165
+ const newValues = (
166
+ newValue
167
+ // Split into items
168
+ .split(',')
169
+ // Trim strings
170
+ .map((val) => {
171
+ return val.trim();
172
+ })
173
+ // Filter zero length
174
+ .filter((trimmedVal) => {
175
+ return (trimmedVal.length > 0);
176
+ })
177
+ // Filter out existing values
178
+ .filter((val) => {
179
+ return !values.some((value) => {
180
+ return value === val;
181
+ })
182
+ })
183
+ );
184
+ onChange([...values, ...newValues] as string[]);
185
+ }
186
+ // resets text field to empty because the values have been added
187
+ dispatch({
188
+ type: ActionType.SetInputValue,
189
+ value: '',
190
+ });
191
+ };
192
+
193
+ /**
194
+ * Adds the values to the multiselect component when enter or tab is pressed
195
+ * @author Yuen Ler Chow
196
+ * @param event keyboard event
197
+ */
198
+ const handleKeyDown: KeyboardEventHandler = (event) => {
199
+ event.preventDefault();
200
+
201
+ // Skip if no input value
202
+ if (!inputValue) {
203
+ return;
204
+ }
205
+
206
+ // Add values if enter or tab is pressed
207
+ if (['Enter', 'Tab'].includes(event.key)) {
208
+ addValues(inputValue);
209
+ }
210
+ };
211
+
212
+ /**
213
+ * Handles the input change of the multiselect component
214
+ * @author Yuen Ler Chow
215
+ * @param input input value
216
+ */
217
+ const handleInputChange = (input: string) => {
218
+ // Create copy of input value so we can modify it
219
+ let newValue = input;
220
+
221
+ // Don't allow user to type in non numbers
222
+ if (type === DBEntryFieldType.NumberArray) {
223
+ newValue = input.replace(/[^0-9,]/g, '');
224
+ }
225
+
226
+ if (input.includes(',')) {
227
+ // if the input has a comma, add the values separated by commas
228
+ addValues(newValue);
229
+ } else {
230
+ // simply update the input value to the new input value
231
+ dispatch({
232
+ type: ActionType.SetInputValue,
233
+ value: newValue,
234
+ });
235
+ }
236
+ };
237
+
238
+ /**
239
+ * Handles the value change of the multiselect component
240
+ * @author Yuen Ler Chow
241
+ * @param newValue new values
242
+ */
243
+ const handleValueChange = (newValues: MultiValue<Option>) => {
244
+ // Skip if no new values
245
+ if (!newValues) {
246
+ return;
247
+ }
248
+
249
+ // Update values based on type
250
+ if (type === DBEntryFieldType.NumberArray) {
251
+ const numberValues: number[] = newValues.map((val) => {
252
+ return Number(val.value);
253
+ });
254
+ onChange(numberValues);
255
+ } else {
256
+ const stringValues: string[] = newValues.map((val) => {
257
+ return val.value;
258
+ });
259
+ onChange(stringValues);
260
+ }
261
+ };
262
+
263
+ /*----------------------------------------*/
264
+ /* --------------- Main UI -------------- */
265
+ /*----------------------------------------*/
266
+
267
+ return (
268
+ <CreatableSelect
269
+ isDisabled={!!disabled}
270
+ components={{ DropdownIndicator: null }}
271
+ inputValue={inputValue}
272
+ isClearable
273
+ isMulti
274
+ menuIsOpen={false}
275
+ onChange={handleValueChange}
276
+ onInputChange={handleInputChange}
277
+ onKeyDown={handleKeyDown}
278
+ placeholder="Type/paste value and press enter..."
279
+ value={values.map((val) => {
280
+ return createOption(String(val));
281
+ })}
282
+ />
283
+ );
284
+ };
285
+
286
+ /*------------------------------------------------------------------------*/
287
+ /* ------------------------------- Wrap Up ------------------------------ */
288
+ /*------------------------------------------------------------------------*/
289
+
290
+ export default CreatableMultiselect;