@rettangoli/ui 1.0.18 → 1.0.20

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/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@rettangoli/ui",
3
- "version": "1.0.18",
3
+ "version": "1.0.20",
4
4
  "description": "A UI component library for building web interfaces.",
5
5
  "main": "dist/rettangoli-esm.min.js",
6
6
  "type": "module",
@@ -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 closeExistingUiBeforeShow = ({ store, render, globalUI }) => {
43
+ const rejectCurrentUi = ({ store, render, globalUI, refs, error }) => {
44
+ clearComponentDialogBody(refs);
45
+
31
46
  if (store.selectIsOpen()) {
32
- closeCurrentUi({ store, render, globalUI, emitResult: true });
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 new Promise((resolve) => {
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 new Promise((resolve) => {
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 new Promise((resolve) => {
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 new Promise((resolve) => {
193
- globalUI.once("event", (result) => {
194
- resolve(result);
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 || null,
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 || undefined,
50
- title: options.title || "",
120
+ status: options.status ?? undefined,
121
+ title: options.title ?? "",
51
122
  message: options.message,
52
- confirmText: options.confirmText || "OK",
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 || undefined,
67
- title: options.title || "",
137
+ status: options.status ?? undefined,
138
+ title: options.title ?? "",
68
139
  message: options.message,
69
- confirmText: options.confirmText || "Yes",
70
- cancelText: options.cancelText || "Cancel",
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 || 0,
85
- y: options.y || 0,
86
- place: options.place || "bs",
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 || 0;
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 || 0,
135
- y: state.dropdownConfig?.y || 0,
136
- place: state.dropdownConfig?.place || 'bs',
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 || { fields: [], actions: { buttons: [] } },
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 || 0,
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
- isDialogContainerOpen: isDialogOpen || isFormDialogOpen,
251
+ isComponentDialogOpen,
252
+ isDialogContainerOpen: isDialogOpen || isFormDialogOpen || isComponentDialogOpen,
149
253
  isDropdownOpen: state.isOpen && state.uiType === 'dropdown',
150
- dialogSize: isFormDialogOpen
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 !isFormDialogOpen:
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: