@rettangoli/ui 1.0.19 → 1.0.21
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/dist/rettangoli-iife-layout.min.js +2 -2
- package/dist/rettangoli-iife-ui.min.js +52 -52
- package/package.json +1 -1
- package/src/components/globalUi/globalUi.handlers.js +206 -49
- package/src/components/globalUi/globalUi.store.js +128 -22
- package/src/components/globalUi/globalUi.view.yaml +23 -1
- package/src/components/select/select.view.yaml +6 -6
- package/src/deps/createGlobalUI.js +27 -2
- package/src/primitives/popover.js +2 -2
package/package.json
CHANGED
|
@@ -1,7 +1,19 @@
|
|
|
1
|
+
const clearComponentDialogBody = (refs) => {
|
|
2
|
+
if (!refs) {
|
|
3
|
+
return;
|
|
4
|
+
}
|
|
5
|
+
|
|
6
|
+
if (typeof refs.componentDialogBodyHost?.replaceChildren === "function") {
|
|
7
|
+
refs.componentDialogBodyHost.replaceChildren();
|
|
8
|
+
}
|
|
9
|
+
|
|
10
|
+
delete refs.componentDialogBody;
|
|
11
|
+
};
|
|
12
|
+
|
|
1
13
|
const getDismissResult = (store) => {
|
|
2
14
|
const uiType = store.selectUiType();
|
|
3
15
|
|
|
4
|
-
if (uiType === "dropdown" || uiType === "formDialog") {
|
|
16
|
+
if (uiType === "dropdown" || uiType === "formDialog" || uiType === "componentDialog") {
|
|
5
17
|
return null;
|
|
6
18
|
}
|
|
7
19
|
|
|
@@ -13,12 +25,13 @@ const getDismissResult = (store) => {
|
|
|
13
25
|
return null;
|
|
14
26
|
};
|
|
15
27
|
|
|
16
|
-
const closeCurrentUi = ({ store, render, globalUI, emitResult = false, result }) => {
|
|
28
|
+
const closeCurrentUi = ({ store, render, globalUI, refs, emitResult = false, result }) => {
|
|
17
29
|
if (!store.selectIsOpen()) {
|
|
18
30
|
return;
|
|
19
31
|
}
|
|
20
32
|
|
|
21
33
|
const resolvedResult = result !== undefined ? result : getDismissResult(store);
|
|
34
|
+
clearComponentDialogBody(refs);
|
|
22
35
|
store.closeAll();
|
|
23
36
|
render();
|
|
24
37
|
|
|
@@ -27,10 +40,38 @@ const closeCurrentUi = ({ store, render, globalUI, emitResult = false, result })
|
|
|
27
40
|
}
|
|
28
41
|
};
|
|
29
42
|
|
|
30
|
-
const
|
|
43
|
+
const rejectCurrentUi = ({ store, render, globalUI, refs, error }) => {
|
|
44
|
+
clearComponentDialogBody(refs);
|
|
45
|
+
|
|
31
46
|
if (store.selectIsOpen()) {
|
|
32
|
-
|
|
47
|
+
store.closeAll();
|
|
48
|
+
render();
|
|
33
49
|
}
|
|
50
|
+
|
|
51
|
+
globalUI.emit("error", error);
|
|
52
|
+
};
|
|
53
|
+
|
|
54
|
+
const closeExistingUiBeforeShow = ({ store, render, globalUI, refs }) => {
|
|
55
|
+
if (store.selectIsOpen()) {
|
|
56
|
+
closeCurrentUi({ store, render, globalUI, refs, emitResult: true });
|
|
57
|
+
}
|
|
58
|
+
};
|
|
59
|
+
|
|
60
|
+
const createUiPromise = (globalUI, { rejectOnError = false } = {}) => {
|
|
61
|
+
return new Promise((resolve, reject) => {
|
|
62
|
+
let offError = null;
|
|
63
|
+
const offEvent = globalUI.once("event", (result) => {
|
|
64
|
+
offError?.();
|
|
65
|
+
resolve(result);
|
|
66
|
+
});
|
|
67
|
+
|
|
68
|
+
if (rejectOnError) {
|
|
69
|
+
offError = globalUI.once("error", (error) => {
|
|
70
|
+
offEvent?.();
|
|
71
|
+
reject(error);
|
|
72
|
+
});
|
|
73
|
+
}
|
|
74
|
+
});
|
|
34
75
|
};
|
|
35
76
|
|
|
36
77
|
const scheduleFormDialogMount = (deps, expectedKey) => {
|
|
@@ -59,31 +100,73 @@ const scheduleFormDialogMount = (deps, expectedKey) => {
|
|
|
59
100
|
}, 0);
|
|
60
101
|
};
|
|
61
102
|
|
|
103
|
+
const scheduleComponentDialogMount = (deps, expectedKey) => {
|
|
104
|
+
setTimeout(() => {
|
|
105
|
+
const { store, refs, render, globalUI } = deps;
|
|
106
|
+
|
|
107
|
+
if (!store.selectIsOpen() || store.selectUiType() !== "componentDialog") {
|
|
108
|
+
return;
|
|
109
|
+
}
|
|
110
|
+
|
|
111
|
+
const componentDialogConfig = store.selectComponentDialogConfig?.();
|
|
112
|
+
if (!componentDialogConfig || componentDialogConfig.key !== expectedKey) {
|
|
113
|
+
return;
|
|
114
|
+
}
|
|
115
|
+
|
|
116
|
+
const hostEl = refs.componentDialogBodyHost;
|
|
117
|
+
if (!hostEl) {
|
|
118
|
+
return;
|
|
119
|
+
}
|
|
120
|
+
|
|
121
|
+
try {
|
|
122
|
+
const bodyEl = document.createElement(componentDialogConfig.component);
|
|
123
|
+
|
|
124
|
+
Object.entries(componentDialogConfig.props ?? {}).forEach(([key, value]) => {
|
|
125
|
+
bodyEl[key] = value;
|
|
126
|
+
});
|
|
127
|
+
|
|
128
|
+
hostEl.replaceChildren(bodyEl);
|
|
129
|
+
refs.componentDialogBody = bodyEl;
|
|
130
|
+
} catch (error) {
|
|
131
|
+
rejectCurrentUi({ store, render, globalUI, refs, error });
|
|
132
|
+
}
|
|
133
|
+
}, 0);
|
|
134
|
+
};
|
|
135
|
+
|
|
136
|
+
const isActiveComponentDialog = (store, expectedKey) => {
|
|
137
|
+
if (!store.selectIsOpen() || store.selectUiType() !== "componentDialog") {
|
|
138
|
+
return false;
|
|
139
|
+
}
|
|
140
|
+
|
|
141
|
+
const componentDialogConfig = store.selectComponentDialogConfig?.();
|
|
142
|
+
return componentDialogConfig?.key === expectedKey;
|
|
143
|
+
};
|
|
144
|
+
|
|
62
145
|
export const handleDialogClose = (deps) => {
|
|
63
|
-
const { store, render, globalUI } = deps;
|
|
64
|
-
closeCurrentUi({ store, render, globalUI, emitResult: true });
|
|
146
|
+
const { store, render, globalUI, refs } = deps;
|
|
147
|
+
closeCurrentUi({ store, render, globalUI, refs, emitResult: true });
|
|
65
148
|
};
|
|
66
149
|
|
|
67
150
|
export const handleConfirm = (deps) => {
|
|
68
|
-
const { store, render, globalUI } = deps;
|
|
151
|
+
const { store, render, globalUI, refs } = deps;
|
|
69
152
|
const config = store.selectConfig();
|
|
70
153
|
const result = config.mode === "confirm" ? true : null;
|
|
71
154
|
|
|
72
|
-
closeCurrentUi({ store, render, globalUI, emitResult: true, result });
|
|
155
|
+
closeCurrentUi({ store, render, globalUI, refs, emitResult: true, result });
|
|
73
156
|
};
|
|
74
157
|
|
|
75
158
|
export const handleCancel = (deps) => {
|
|
76
|
-
const { store, render, globalUI } = deps;
|
|
77
|
-
closeCurrentUi({ store, render, globalUI, emitResult: true, result: false });
|
|
159
|
+
const { store, render, globalUI, refs } = deps;
|
|
160
|
+
closeCurrentUi({ store, render, globalUI, refs, emitResult: true, result: false });
|
|
78
161
|
};
|
|
79
162
|
|
|
80
163
|
export const handleDropdownClose = (deps) => {
|
|
81
|
-
const { store, render, globalUI } = deps;
|
|
82
|
-
closeCurrentUi({ store, render, globalUI, emitResult: true, result: null });
|
|
164
|
+
const { store, render, globalUI, refs } = deps;
|
|
165
|
+
closeCurrentUi({ store, render, globalUI, refs, emitResult: true, result: null });
|
|
83
166
|
};
|
|
84
167
|
|
|
85
168
|
export const handleDropdownItemClick = (deps, payload) => {
|
|
86
|
-
const { store, render, globalUI } = deps;
|
|
169
|
+
const { store, render, globalUI, refs } = deps;
|
|
87
170
|
const event = payload._event;
|
|
88
171
|
const { index, item } = event.detail;
|
|
89
172
|
|
|
@@ -91,6 +174,7 @@ export const handleDropdownItemClick = (deps, payload) => {
|
|
|
91
174
|
store,
|
|
92
175
|
render,
|
|
93
176
|
globalUI,
|
|
177
|
+
refs,
|
|
94
178
|
emitResult: true,
|
|
95
179
|
result: { index, item },
|
|
96
180
|
});
|
|
@@ -111,36 +195,27 @@ export const handleDropdownItemClick = (deps, payload) => {
|
|
|
111
195
|
* @returns {Promise<void>}
|
|
112
196
|
*/
|
|
113
197
|
export const handleShowAlert = (deps, payload) => {
|
|
114
|
-
const { store, render, globalUI } = deps;
|
|
198
|
+
const { store, render, globalUI, refs } = deps;
|
|
115
199
|
const options = payload;
|
|
116
200
|
|
|
117
|
-
closeExistingUiBeforeShow({ store, render, globalUI });
|
|
201
|
+
closeExistingUiBeforeShow({ store, render, globalUI, refs });
|
|
118
202
|
|
|
119
203
|
store.setAlertConfig(options);
|
|
120
204
|
render();
|
|
121
205
|
|
|
122
|
-
return
|
|
123
|
-
globalUI.once("event", () => {
|
|
124
|
-
resolve();
|
|
125
|
-
});
|
|
126
|
-
});
|
|
206
|
+
return createUiPromise(globalUI);
|
|
127
207
|
};
|
|
128
208
|
|
|
129
209
|
export const handleShowConfirm = async (deps, payload) => {
|
|
130
|
-
const { store, render, globalUI } = deps;
|
|
210
|
+
const { store, render, globalUI, refs } = deps;
|
|
131
211
|
const options = payload;
|
|
132
212
|
|
|
133
|
-
closeExistingUiBeforeShow({ store, render, globalUI });
|
|
213
|
+
closeExistingUiBeforeShow({ store, render, globalUI, refs });
|
|
134
214
|
|
|
135
215
|
store.setConfirmConfig(options);
|
|
136
216
|
render();
|
|
137
217
|
|
|
138
|
-
return
|
|
139
|
-
globalUI.once('event', (result) => {
|
|
140
|
-
// result contains info of whehter is confirm of cancel
|
|
141
|
-
resolve(result)
|
|
142
|
-
});
|
|
143
|
-
});
|
|
218
|
+
return createUiPromise(globalUI);
|
|
144
219
|
};
|
|
145
220
|
|
|
146
221
|
/**
|
|
@@ -161,27 +236,22 @@ export const handleShowConfirm = async (deps, payload) => {
|
|
|
161
236
|
* @returns {Object} [result.item] - The clicked item object
|
|
162
237
|
*/
|
|
163
238
|
export const handleShowDropdownMenu = async (deps, payload) => {
|
|
164
|
-
const { store, render, globalUI } = deps;
|
|
239
|
+
const { store, render, globalUI, refs } = deps;
|
|
165
240
|
const options = payload;
|
|
166
241
|
|
|
167
|
-
closeExistingUiBeforeShow({ store, render, globalUI });
|
|
242
|
+
closeExistingUiBeforeShow({ store, render, globalUI, refs });
|
|
168
243
|
|
|
169
244
|
store.setDropdownConfig(options);
|
|
170
245
|
render();
|
|
171
246
|
|
|
172
|
-
return
|
|
173
|
-
globalUI.once('event', (result) => {
|
|
174
|
-
// result contains info of clicked item or null if closed without selection
|
|
175
|
-
resolve(result)
|
|
176
|
-
});
|
|
177
|
-
});
|
|
247
|
+
return createUiPromise(globalUI);
|
|
178
248
|
};
|
|
179
249
|
|
|
180
250
|
export const handleShowFormDialog = async (deps, payload) => {
|
|
181
|
-
const { store, render, globalUI } = deps;
|
|
251
|
+
const { store, render, globalUI, refs } = deps;
|
|
182
252
|
const options = payload;
|
|
183
253
|
|
|
184
|
-
closeExistingUiBeforeShow({ store, render, globalUI });
|
|
254
|
+
closeExistingUiBeforeShow({ store, render, globalUI, refs });
|
|
185
255
|
|
|
186
256
|
store.setFormDialogConfig(options);
|
|
187
257
|
render();
|
|
@@ -189,16 +259,27 @@ export const handleShowFormDialog = async (deps, payload) => {
|
|
|
189
259
|
const expectedKey = store.selectFormDialogConfig?.().key;
|
|
190
260
|
scheduleFormDialogMount(deps, expectedKey);
|
|
191
261
|
|
|
192
|
-
return
|
|
193
|
-
|
|
194
|
-
|
|
195
|
-
|
|
196
|
-
}
|
|
262
|
+
return createUiPromise(globalUI);
|
|
263
|
+
};
|
|
264
|
+
|
|
265
|
+
export const handleShowComponentDialog = async (deps, payload) => {
|
|
266
|
+
const { store, render, globalUI, refs } = deps;
|
|
267
|
+
const options = payload;
|
|
268
|
+
|
|
269
|
+
closeExistingUiBeforeShow({ store, render, globalUI, refs });
|
|
270
|
+
|
|
271
|
+
store.setComponentDialogConfig(options);
|
|
272
|
+
render();
|
|
273
|
+
|
|
274
|
+
const expectedKey = store.selectComponentDialogConfig?.().key;
|
|
275
|
+
scheduleComponentDialogMount(deps, expectedKey);
|
|
276
|
+
|
|
277
|
+
return createUiPromise(globalUI, { rejectOnError: true });
|
|
197
278
|
};
|
|
198
279
|
|
|
199
280
|
export const handleFormAction = (deps, payload) => {
|
|
200
|
-
const { store, render, globalUI } = deps;
|
|
201
|
-
const detail = payload._event?.detail
|
|
281
|
+
const { store, render, globalUI, refs } = deps;
|
|
282
|
+
const detail = payload._event?.detail ?? {};
|
|
202
283
|
|
|
203
284
|
if (detail.valid === false) {
|
|
204
285
|
return;
|
|
@@ -208,6 +289,7 @@ export const handleFormAction = (deps, payload) => {
|
|
|
208
289
|
store,
|
|
209
290
|
render,
|
|
210
291
|
globalUI,
|
|
292
|
+
refs,
|
|
211
293
|
emitResult: true,
|
|
212
294
|
result: detail,
|
|
213
295
|
});
|
|
@@ -215,13 +297,13 @@ export const handleFormAction = (deps, payload) => {
|
|
|
215
297
|
|
|
216
298
|
export const handleFormFieldEvent = (deps, payload) => {
|
|
217
299
|
const { store, refs } = deps;
|
|
218
|
-
const detail = payload._event?.detail
|
|
300
|
+
const detail = payload._event?.detail ?? {};
|
|
219
301
|
const formDialogConfig = store.selectFormDialogConfig?.();
|
|
220
302
|
|
|
221
303
|
if (typeof formDialogConfig?.onFieldEvent === "function") {
|
|
222
304
|
formDialogConfig.onFieldEvent({
|
|
223
305
|
detail,
|
|
224
|
-
formEl: refs.formDialog
|
|
306
|
+
formEl: refs.formDialog ?? null,
|
|
225
307
|
});
|
|
226
308
|
}
|
|
227
309
|
};
|
|
@@ -239,6 +321,81 @@ export const handleFormFieldEvent = (deps, payload) => {
|
|
|
239
321
|
* @returns {void}
|
|
240
322
|
*/
|
|
241
323
|
export const handleCloseAll = (deps) => {
|
|
242
|
-
const { store, render, globalUI } = deps;
|
|
243
|
-
closeCurrentUi({ store, render, globalUI, emitResult: true });
|
|
324
|
+
const { store, render, globalUI, refs } = deps;
|
|
325
|
+
closeCurrentUi({ store, render, globalUI, refs, emitResult: true });
|
|
326
|
+
};
|
|
327
|
+
|
|
328
|
+
export const handleComponentDialogAction = async (deps, payload) => {
|
|
329
|
+
const { store, render, globalUI, refs } = deps;
|
|
330
|
+
const event = payload._event;
|
|
331
|
+
const actionIndex = Number(event?.currentTarget?.dataset?.actionIndex);
|
|
332
|
+
const componentDialogConfig = store.selectComponentDialogConfig?.();
|
|
333
|
+
const componentDialogKey = componentDialogConfig?.key;
|
|
334
|
+
const button = Number.isInteger(actionIndex)
|
|
335
|
+
? componentDialogConfig?.actions?.buttons?.[actionIndex]
|
|
336
|
+
: null;
|
|
337
|
+
|
|
338
|
+
if (!button) {
|
|
339
|
+
return;
|
|
340
|
+
}
|
|
341
|
+
|
|
342
|
+
if (button.role === "cancel") {
|
|
343
|
+
closeCurrentUi({
|
|
344
|
+
store,
|
|
345
|
+
render,
|
|
346
|
+
globalUI,
|
|
347
|
+
refs,
|
|
348
|
+
emitResult: true,
|
|
349
|
+
result: {
|
|
350
|
+
actionId: button.id,
|
|
351
|
+
},
|
|
352
|
+
});
|
|
353
|
+
return;
|
|
354
|
+
}
|
|
355
|
+
|
|
356
|
+
try {
|
|
357
|
+
const body = refs.componentDialogBody;
|
|
358
|
+
if (!body || typeof body.validate !== "function" || typeof body.getValues !== "function") {
|
|
359
|
+
throw new Error(
|
|
360
|
+
`component dialog body '${componentDialogConfig?.component ?? "unknown"}' must implement validate() and getValues()`,
|
|
361
|
+
);
|
|
362
|
+
}
|
|
363
|
+
|
|
364
|
+
if (button.validate) {
|
|
365
|
+
const validation = await body.validate();
|
|
366
|
+
if (!isActiveComponentDialog(store, componentDialogKey)) {
|
|
367
|
+
return;
|
|
368
|
+
}
|
|
369
|
+
|
|
370
|
+
if (!validation || typeof validation !== "object" || typeof validation.valid !== "boolean") {
|
|
371
|
+
throw new Error("component dialog body validate() must return { valid, errors? }");
|
|
372
|
+
}
|
|
373
|
+
if (validation.valid === false) {
|
|
374
|
+
return;
|
|
375
|
+
}
|
|
376
|
+
}
|
|
377
|
+
|
|
378
|
+
const values = await body.getValues();
|
|
379
|
+
if (!isActiveComponentDialog(store, componentDialogKey)) {
|
|
380
|
+
return;
|
|
381
|
+
}
|
|
382
|
+
|
|
383
|
+
closeCurrentUi({
|
|
384
|
+
store,
|
|
385
|
+
render,
|
|
386
|
+
globalUI,
|
|
387
|
+
refs,
|
|
388
|
+
emitResult: true,
|
|
389
|
+
result: {
|
|
390
|
+
actionId: button.id,
|
|
391
|
+
values,
|
|
392
|
+
},
|
|
393
|
+
});
|
|
394
|
+
} catch (error) {
|
|
395
|
+
if (!isActiveComponentDialog(store, componentDialogKey)) {
|
|
396
|
+
return;
|
|
397
|
+
}
|
|
398
|
+
|
|
399
|
+
rejectCurrentUi({ store, render, globalUI, refs, error });
|
|
400
|
+
}
|
|
244
401
|
};
|
|
@@ -1,4 +1,22 @@
|
|
|
1
1
|
const VALID_DIALOG_SIZES = new Set(["sm", "md", "lg", "f"]);
|
|
2
|
+
const VALID_COMPONENT_DIALOG_ROLES = new Set(["confirm", "cancel"]);
|
|
3
|
+
|
|
4
|
+
const DEFAULT_COMPONENT_DIALOG_BUTTONS = Object.freeze([
|
|
5
|
+
{
|
|
6
|
+
id: "cancel",
|
|
7
|
+
label: "Cancel",
|
|
8
|
+
variant: "se",
|
|
9
|
+
align: "left",
|
|
10
|
+
role: "cancel",
|
|
11
|
+
},
|
|
12
|
+
{
|
|
13
|
+
id: "confirm",
|
|
14
|
+
label: "OK",
|
|
15
|
+
variant: "pr",
|
|
16
|
+
role: "confirm",
|
|
17
|
+
validate: true,
|
|
18
|
+
},
|
|
19
|
+
]);
|
|
2
20
|
|
|
3
21
|
const normalizeObject = (value) => {
|
|
4
22
|
if (!value || typeof value !== "object" || Array.isArray(value)) {
|
|
@@ -11,9 +29,61 @@ const normalizeDialogSize = (value, fallback = "md") => {
|
|
|
11
29
|
return VALID_DIALOG_SIZES.has(value) ? value : fallback;
|
|
12
30
|
};
|
|
13
31
|
|
|
32
|
+
const normalizeComponentDialogActions = (value) => {
|
|
33
|
+
const sourceButtons = Array.isArray(value?.buttons) && value.buttons.length > 0
|
|
34
|
+
? value.buttons
|
|
35
|
+
: DEFAULT_COMPONENT_DIALOG_BUTTONS;
|
|
36
|
+
|
|
37
|
+
const buttons = sourceButtons.map((button, index) => {
|
|
38
|
+
if (!button || typeof button !== "object" || Array.isArray(button)) {
|
|
39
|
+
throw new Error("component dialog buttons must be objects");
|
|
40
|
+
}
|
|
41
|
+
|
|
42
|
+
if (typeof button.id !== "string" || button.id.length === 0) {
|
|
43
|
+
throw new Error("component dialog button id is required");
|
|
44
|
+
}
|
|
45
|
+
|
|
46
|
+
if (typeof button.label !== "string" || button.label.length === 0) {
|
|
47
|
+
throw new Error("component dialog button label is required");
|
|
48
|
+
}
|
|
49
|
+
|
|
50
|
+
if (!VALID_COMPONENT_DIALOG_ROLES.has(button.role)) {
|
|
51
|
+
throw new Error("component dialog button role must be 'confirm' or 'cancel'");
|
|
52
|
+
}
|
|
53
|
+
|
|
54
|
+
return {
|
|
55
|
+
...button,
|
|
56
|
+
_globalIdx: index,
|
|
57
|
+
variant: button.variant ?? (button.role === "confirm" ? "pr" : "se"),
|
|
58
|
+
align: button.align ?? (button.role === "cancel" ? "left" : "right"),
|
|
59
|
+
validate: button.role === "confirm" ? !!button.validate : false,
|
|
60
|
+
_disabled: !!button.disabled,
|
|
61
|
+
pre: button.pre ?? "",
|
|
62
|
+
suf: button.suf ?? "",
|
|
63
|
+
};
|
|
64
|
+
});
|
|
65
|
+
|
|
66
|
+
return {
|
|
67
|
+
_layout: "split",
|
|
68
|
+
buttons,
|
|
69
|
+
_leftButtons: buttons.filter((button) => button.align === "left"),
|
|
70
|
+
_rightButtons: buttons.filter((button) => button.align !== "left"),
|
|
71
|
+
};
|
|
72
|
+
};
|
|
73
|
+
|
|
74
|
+
const createDefaultComponentDialogConfig = () => ({
|
|
75
|
+
title: "",
|
|
76
|
+
description: "",
|
|
77
|
+
size: "md",
|
|
78
|
+
component: "",
|
|
79
|
+
props: {},
|
|
80
|
+
actions: normalizeComponentDialogActions(),
|
|
81
|
+
key: 0,
|
|
82
|
+
});
|
|
83
|
+
|
|
14
84
|
export const createInitialState = () => Object.freeze({
|
|
15
85
|
isOpen: false,
|
|
16
|
-
uiType: "dialog", // "dialog" | "dropdown" | "formDialog"
|
|
86
|
+
uiType: "dialog", // "dialog" | "dropdown" | "formDialog" | "componentDialog"
|
|
17
87
|
config: {
|
|
18
88
|
status: undefined, // undefined | info | warning | error
|
|
19
89
|
title: "",
|
|
@@ -38,6 +108,7 @@ export const createInitialState = () => Object.freeze({
|
|
|
38
108
|
onFieldEvent: null,
|
|
39
109
|
mount: null,
|
|
40
110
|
},
|
|
111
|
+
componentDialogConfig: createDefaultComponentDialogConfig(),
|
|
41
112
|
});
|
|
42
113
|
|
|
43
114
|
export const setAlertConfig = ({ state }, options = {}) => {
|
|
@@ -46,10 +117,10 @@ export const setAlertConfig = ({ state }, options = {}) => {
|
|
|
46
117
|
}
|
|
47
118
|
|
|
48
119
|
state.config = {
|
|
49
|
-
status: options.status
|
|
50
|
-
title: options.title
|
|
120
|
+
status: options.status ?? undefined,
|
|
121
|
+
title: options.title ?? "",
|
|
51
122
|
message: options.message,
|
|
52
|
-
confirmText: options.confirmText
|
|
123
|
+
confirmText: options.confirmText ?? "OK",
|
|
53
124
|
cancelText: "",
|
|
54
125
|
mode: "alert",
|
|
55
126
|
};
|
|
@@ -63,11 +134,11 @@ export const setConfirmConfig = ({ state }, options = {}) => {
|
|
|
63
134
|
}
|
|
64
135
|
|
|
65
136
|
state.config = {
|
|
66
|
-
status: options.status
|
|
67
|
-
title: options.title
|
|
137
|
+
status: options.status ?? undefined,
|
|
138
|
+
title: options.title ?? "",
|
|
68
139
|
message: options.message,
|
|
69
|
-
confirmText: options.confirmText
|
|
70
|
-
cancelText: options.cancelText
|
|
140
|
+
confirmText: options.confirmText ?? "Yes",
|
|
141
|
+
cancelText: options.cancelText ?? "Cancel",
|
|
71
142
|
mode: "confirm",
|
|
72
143
|
};
|
|
73
144
|
state.uiType = "dialog";
|
|
@@ -81,9 +152,9 @@ export const setDropdownConfig = ({ state }, options = {}) => {
|
|
|
81
152
|
|
|
82
153
|
state.dropdownConfig = {
|
|
83
154
|
items: options.items,
|
|
84
|
-
x: options.x
|
|
85
|
-
y: options.y
|
|
86
|
-
place: options.place
|
|
155
|
+
x: options.x ?? 0,
|
|
156
|
+
y: options.y ?? 0,
|
|
157
|
+
place: options.place ?? "bs",
|
|
87
158
|
};
|
|
88
159
|
state.uiType = "dropdown";
|
|
89
160
|
state.isOpen = true;
|
|
@@ -94,7 +165,7 @@ export const setFormDialogConfig = ({ state }, options = {}) => {
|
|
|
94
165
|
throw new Error("form object is required for showFormDialog");
|
|
95
166
|
}
|
|
96
167
|
|
|
97
|
-
const prevKey = state.formDialogConfig?.key
|
|
168
|
+
const prevKey = state.formDialogConfig?.key ?? 0;
|
|
98
169
|
|
|
99
170
|
state.formDialogConfig = {
|
|
100
171
|
form: options.form,
|
|
@@ -110,6 +181,26 @@ export const setFormDialogConfig = ({ state }, options = {}) => {
|
|
|
110
181
|
state.isOpen = true;
|
|
111
182
|
};
|
|
112
183
|
|
|
184
|
+
export const setComponentDialogConfig = ({ state }, options = {}) => {
|
|
185
|
+
if (typeof options.component !== "string" || !options.component.includes("-")) {
|
|
186
|
+
throw new Error("component tag name is required for showComponentDialog");
|
|
187
|
+
}
|
|
188
|
+
|
|
189
|
+
const prevKey = state.componentDialogConfig?.key ?? 0;
|
|
190
|
+
|
|
191
|
+
state.componentDialogConfig = {
|
|
192
|
+
title: typeof options.title === "string" ? options.title : "",
|
|
193
|
+
description: typeof options.description === "string" ? options.description : "",
|
|
194
|
+
size: normalizeDialogSize(options.size, "md"),
|
|
195
|
+
component: options.component,
|
|
196
|
+
props: normalizeObject(options.props),
|
|
197
|
+
actions: normalizeComponentDialogActions(options.actions),
|
|
198
|
+
key: prevKey + 1,
|
|
199
|
+
};
|
|
200
|
+
state.uiType = "componentDialog";
|
|
201
|
+
state.isOpen = true;
|
|
202
|
+
};
|
|
203
|
+
|
|
113
204
|
export const closeAll = ({ state }) => {
|
|
114
205
|
state.isOpen = false;
|
|
115
206
|
state.uiType = "dialog"; // Reset to default type
|
|
@@ -118,36 +209,51 @@ export const closeAll = ({ state }) => {
|
|
|
118
209
|
export const selectConfig = ({ state }) => state.config;
|
|
119
210
|
export const selectDropdownConfig = ({ state }) => state.dropdownConfig;
|
|
120
211
|
export const selectFormDialogConfig = ({ state }) => state.formDialogConfig;
|
|
212
|
+
export const selectComponentDialogConfig = ({ state }) => state.componentDialogConfig;
|
|
121
213
|
export const selectUiType = ({ state }) => state.uiType;
|
|
122
214
|
export const selectIsOpen = ({ state }) => state.isOpen;
|
|
123
215
|
|
|
124
216
|
export const selectViewData = ({ state }) => {
|
|
125
217
|
const isDialogOpen = state.isOpen && state.uiType === "dialog";
|
|
126
218
|
const isFormDialogOpen = state.isOpen && state.uiType === "formDialog";
|
|
219
|
+
const isComponentDialogOpen = state.isOpen && state.uiType === "componentDialog";
|
|
220
|
+
const componentDialogConfig = state.componentDialogConfig ?? createDefaultComponentDialogConfig();
|
|
127
221
|
|
|
128
222
|
return {
|
|
129
223
|
isOpen: state.isOpen,
|
|
130
224
|
uiType: state.uiType,
|
|
131
225
|
config: state.config,
|
|
132
226
|
dropdownConfig: {
|
|
133
|
-
items: state.dropdownConfig?.items
|
|
134
|
-
x: state.dropdownConfig?.x
|
|
135
|
-
y: state.dropdownConfig?.y
|
|
136
|
-
place: state.dropdownConfig?.place
|
|
227
|
+
items: state.dropdownConfig?.items ?? [],
|
|
228
|
+
x: state.dropdownConfig?.x ?? 0,
|
|
229
|
+
y: state.dropdownConfig?.y ?? 0,
|
|
230
|
+
place: state.dropdownConfig?.place ?? "bs",
|
|
137
231
|
},
|
|
138
232
|
formDialogConfig: {
|
|
139
|
-
form: state.formDialogConfig?.form
|
|
140
|
-
defaultValues: state.formDialogConfig?.defaultValues
|
|
141
|
-
context: state.formDialogConfig?.context
|
|
233
|
+
form: state.formDialogConfig?.form ?? { fields: [], actions: { buttons: [] } },
|
|
234
|
+
defaultValues: state.formDialogConfig?.defaultValues ?? {},
|
|
235
|
+
context: state.formDialogConfig?.context ?? {},
|
|
142
236
|
disabled: !!state.formDialogConfig?.disabled,
|
|
143
237
|
size: normalizeDialogSize(state.formDialogConfig?.size, "md"),
|
|
144
|
-
key: state.formDialogConfig?.key
|
|
238
|
+
key: state.formDialogConfig?.key ?? 0,
|
|
239
|
+
},
|
|
240
|
+
componentDialogConfig: {
|
|
241
|
+
title: componentDialogConfig.title ?? "",
|
|
242
|
+
description: componentDialogConfig.description ?? "",
|
|
243
|
+
size: normalizeDialogSize(componentDialogConfig.size, "md"),
|
|
244
|
+
component: componentDialogConfig.component ?? "",
|
|
245
|
+
props: componentDialogConfig.props ?? {},
|
|
246
|
+
actions: componentDialogConfig.actions ?? normalizeComponentDialogActions(),
|
|
247
|
+
key: componentDialogConfig.key ?? 0,
|
|
145
248
|
},
|
|
146
249
|
isDialogOpen,
|
|
147
250
|
isFormDialogOpen,
|
|
148
|
-
|
|
251
|
+
isComponentDialogOpen,
|
|
252
|
+
isDialogContainerOpen: isDialogOpen || isFormDialogOpen || isComponentDialogOpen,
|
|
149
253
|
isDropdownOpen: state.isOpen && state.uiType === 'dropdown',
|
|
150
|
-
dialogSize:
|
|
254
|
+
dialogSize: isComponentDialogOpen
|
|
255
|
+
? normalizeDialogSize(componentDialogConfig.size, "md")
|
|
256
|
+
: isFormDialogOpen
|
|
151
257
|
? normalizeDialogSize(state.formDialogConfig?.size, "md")
|
|
152
258
|
: "sm",
|
|
153
259
|
};
|
|
@@ -11,6 +11,11 @@ refs:
|
|
|
11
11
|
eventListeners:
|
|
12
12
|
click:
|
|
13
13
|
handler: handleCancel
|
|
14
|
+
componentDialogBodyHost: {}
|
|
15
|
+
componentDialogAction*:
|
|
16
|
+
eventListeners:
|
|
17
|
+
click:
|
|
18
|
+
handler: handleComponentDialogAction
|
|
14
19
|
formDialog:
|
|
15
20
|
eventListeners:
|
|
16
21
|
form-action:
|
|
@@ -27,7 +32,24 @@ template:
|
|
|
27
32
|
- rtgl-dialog#dialog ?open=${isDialogContainerOpen} s=${dialogSize}:
|
|
28
33
|
- $if isFormDialogOpen:
|
|
29
34
|
- rtgl-form#formDialog slot=content :form=${formDialogConfig.form} :defaultValues=${formDialogConfig.defaultValues} :context=${formDialogConfig.context} ?disabled=${formDialogConfig.disabled} key=form-dialog-${formDialogConfig.key}: null
|
|
30
|
-
- $if
|
|
35
|
+
- $if isComponentDialogOpen:
|
|
36
|
+
- rtgl-view slot=content g=lg p=lg:
|
|
37
|
+
- $if componentDialogConfig.title || componentDialogConfig.description:
|
|
38
|
+
- rtgl-view g=sm w=f:
|
|
39
|
+
- $if componentDialogConfig.title:
|
|
40
|
+
- rtgl-text s=lg: ${componentDialogConfig.title}
|
|
41
|
+
- $if componentDialogConfig.description:
|
|
42
|
+
- rtgl-text c=mu-fg: ${componentDialogConfig.description}
|
|
43
|
+
- rtgl-view#componentDialogBodyHost w=f key=component-dialog-body-${componentDialogConfig.key}: null
|
|
44
|
+
- $if componentDialogConfig.actions.buttons.length > 0:
|
|
45
|
+
- rtgl-view d=h w=f g=sm:
|
|
46
|
+
- rtgl-view d=h g=sm:
|
|
47
|
+
- $for button, i in componentDialogConfig.actions._leftButtons:
|
|
48
|
+
- rtgl-button#componentDialogAction${button._globalIdx} data-action-id=${button.id} data-action-index=${button._globalIdx} v=${button.variant} ?disabled=${button._disabled} pre=${button.pre} suf=${button.suf}: ${button.label}
|
|
49
|
+
- rtgl-view d=h g=sm ah=e w=1fg:
|
|
50
|
+
- $for button, i in componentDialogConfig.actions._rightButtons:
|
|
51
|
+
- rtgl-button#componentDialogAction${button._globalIdx} data-action-id=${button.id} data-action-index=${button._globalIdx} v=${button.variant} ?disabled=${button._disabled} pre=${button.pre} suf=${button.suf}: ${button.label}
|
|
52
|
+
- $if !isFormDialogOpen && !isComponentDialogOpen:
|
|
31
53
|
- rtgl-view slot=content g=lg p=lg:
|
|
32
54
|
- rtgl-view g=sm w=f:
|
|
33
55
|
- $if config.title:
|
|
@@ -34,12 +34,12 @@ template:
|
|
|
34
34
|
- $if showClear:
|
|
35
35
|
- rtgl-svg#clearButton ml=md svg=x wh=16 c=mu-fg cur=pointer data-testid="select-clear-button": null
|
|
36
36
|
- rtgl-svg ml=md svg=chevronDown wh=16 c=mu-fg: null
|
|
37
|
-
- rtgl-popover#popover ?open=${isOpen} x=${position.x} y=${position.y} place=rs:
|
|
38
|
-
- rtgl-view wh=300 g=xs slot=content bgc=mu
|
|
37
|
+
- 'rtgl-popover#popover ?open=${isOpen} x=${position.x} y=${position.y} place=rs style="--rtgl-popover-content-padding: var(--spacing-sm) 0"':
|
|
38
|
+
- rtgl-view wh=300 g=xs slot=content bgc=mu sv=true:
|
|
39
39
|
- $for option, i in options:
|
|
40
|
-
- rtgl-view#option${i} w=f ph=lg pv=md cur=pointer
|
|
41
|
-
- rtgl-text
|
|
40
|
+
- rtgl-view#option${i} w=f ph=lg pv=md cur=pointer bgc=${option.bgc} data-testid=${option.testId}:
|
|
41
|
+
- rtgl-text s=sm: ${option.label}
|
|
42
42
|
- $if showAddOption:
|
|
43
43
|
- rtgl-view w=f bw=xs bc=mu bwt=sm: null
|
|
44
|
-
- rtgl-view#optionAdd w=f ph=lg pv=md cur=pointer
|
|
45
|
-
- rtgl-text c=ac: ${addOptionLabel}
|
|
44
|
+
- rtgl-view#optionAdd w=f ph=lg pv=md cur=pointer bgc=${addOptionBgc} data-testid="select-add-option":
|
|
45
|
+
- rtgl-text s=sm c=ac: ${addOptionLabel}
|