@rettangoli/ui 1.0.3 → 1.0.4
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,33 +1,85 @@
|
|
|
1
|
-
|
|
2
|
-
const
|
|
1
|
+
const getDismissResult = (store) => {
|
|
2
|
+
const uiType = store.selectUiType();
|
|
3
3
|
|
|
4
|
-
|
|
5
|
-
|
|
4
|
+
if (uiType === "dropdown" || uiType === "formDialog") {
|
|
5
|
+
return null;
|
|
6
|
+
}
|
|
7
|
+
|
|
8
|
+
const config = store.selectConfig();
|
|
9
|
+
if (config.mode === "confirm") {
|
|
10
|
+
return false;
|
|
11
|
+
}
|
|
12
|
+
|
|
13
|
+
return null;
|
|
6
14
|
};
|
|
7
15
|
|
|
8
|
-
|
|
9
|
-
|
|
16
|
+
const closeCurrentUi = ({ store, render, globalUI, emitResult = false, result }) => {
|
|
17
|
+
if (!store.selectIsOpen()) {
|
|
18
|
+
return;
|
|
19
|
+
}
|
|
10
20
|
|
|
21
|
+
const resolvedResult = result !== undefined ? result : getDismissResult(store);
|
|
11
22
|
store.closeAll();
|
|
12
23
|
render();
|
|
13
|
-
|
|
24
|
+
|
|
25
|
+
if (emitResult) {
|
|
26
|
+
globalUI.emit("event", resolvedResult);
|
|
27
|
+
}
|
|
14
28
|
};
|
|
15
29
|
|
|
16
|
-
|
|
30
|
+
const closeExistingUiBeforeShow = ({ store, render, globalUI }) => {
|
|
31
|
+
if (store.selectIsOpen()) {
|
|
32
|
+
closeCurrentUi({ store, render, globalUI, emitResult: true });
|
|
33
|
+
}
|
|
34
|
+
};
|
|
35
|
+
|
|
36
|
+
const scheduleFormDialogMount = (deps, expectedKey) => {
|
|
37
|
+
setTimeout(() => {
|
|
38
|
+
const { store, refs } = deps;
|
|
39
|
+
|
|
40
|
+
if (!store.selectIsOpen() || store.selectUiType() !== "formDialog") {
|
|
41
|
+
return;
|
|
42
|
+
}
|
|
43
|
+
|
|
44
|
+
const formDialogConfig = store.selectFormDialogConfig?.();
|
|
45
|
+
if (!formDialogConfig || formDialogConfig.key !== expectedKey) {
|
|
46
|
+
return;
|
|
47
|
+
}
|
|
48
|
+
|
|
49
|
+
if (typeof formDialogConfig.mount !== "function") {
|
|
50
|
+
return;
|
|
51
|
+
}
|
|
52
|
+
|
|
53
|
+
const formEl = refs.formDialog;
|
|
54
|
+
if (!formEl) {
|
|
55
|
+
return;
|
|
56
|
+
}
|
|
57
|
+
|
|
58
|
+
formDialogConfig.mount(formEl);
|
|
59
|
+
}, 0);
|
|
60
|
+
};
|
|
61
|
+
|
|
62
|
+
export const handleDialogClose = (deps) => {
|
|
17
63
|
const { store, render, globalUI } = deps;
|
|
64
|
+
closeCurrentUi({ store, render, globalUI, emitResult: true });
|
|
65
|
+
};
|
|
18
66
|
|
|
19
|
-
|
|
20
|
-
render
|
|
21
|
-
|
|
67
|
+
export const handleConfirm = (deps) => {
|
|
68
|
+
const { store, render, globalUI } = deps;
|
|
69
|
+
const config = store.selectConfig();
|
|
70
|
+
const result = config.mode === "confirm" ? true : null;
|
|
71
|
+
|
|
72
|
+
closeCurrentUi({ store, render, globalUI, emitResult: true, result });
|
|
22
73
|
};
|
|
23
74
|
|
|
24
|
-
export const
|
|
75
|
+
export const handleCancel = (deps) => {
|
|
25
76
|
const { store, render, globalUI } = deps;
|
|
77
|
+
closeCurrentUi({ store, render, globalUI, emitResult: true, result: false });
|
|
78
|
+
};
|
|
26
79
|
|
|
27
|
-
|
|
28
|
-
store
|
|
29
|
-
render
|
|
30
|
-
globalUI.emit('event', null);
|
|
80
|
+
export const handleDropdownClose = (deps) => {
|
|
81
|
+
const { store, render, globalUI } = deps;
|
|
82
|
+
closeCurrentUi({ store, render, globalUI, emitResult: true, result: null });
|
|
31
83
|
};
|
|
32
84
|
|
|
33
85
|
export const handleDropdownItemClick = (deps, payload) => {
|
|
@@ -35,10 +87,13 @@ export const handleDropdownItemClick = (deps, payload) => {
|
|
|
35
87
|
const event = payload._event;
|
|
36
88
|
const { index, item } = event.detail;
|
|
37
89
|
|
|
38
|
-
|
|
39
|
-
|
|
40
|
-
|
|
41
|
-
|
|
90
|
+
closeCurrentUi({
|
|
91
|
+
store,
|
|
92
|
+
render,
|
|
93
|
+
globalUI,
|
|
94
|
+
emitResult: true,
|
|
95
|
+
result: { index, item },
|
|
96
|
+
});
|
|
42
97
|
};
|
|
43
98
|
|
|
44
99
|
/**
|
|
@@ -53,31 +108,29 @@ export const handleDropdownItemClick = (deps, payload) => {
|
|
|
53
108
|
* @param {string} [payload.title] - Optional alert title
|
|
54
109
|
* @param {('info'|'warning'|'error')} [payload.status] - Optional status type
|
|
55
110
|
* @param {string} [payload.confirmText] - Text for the confirm button (default: "OK")
|
|
56
|
-
* @returns {void}
|
|
111
|
+
* @returns {Promise<void>}
|
|
57
112
|
*/
|
|
58
113
|
export const handleShowAlert = (deps, payload) => {
|
|
59
|
-
const { store, render } = deps;
|
|
114
|
+
const { store, render, globalUI } = deps;
|
|
60
115
|
const options = payload;
|
|
61
116
|
|
|
62
|
-
|
|
63
|
-
if (store.selectIsOpen()) {
|
|
64
|
-
store.closeAll();
|
|
65
|
-
render();
|
|
66
|
-
}
|
|
117
|
+
closeExistingUiBeforeShow({ store, render, globalUI });
|
|
67
118
|
|
|
68
119
|
store.setAlertConfig(options);
|
|
69
120
|
render();
|
|
121
|
+
|
|
122
|
+
return new Promise((resolve) => {
|
|
123
|
+
globalUI.once("event", () => {
|
|
124
|
+
resolve();
|
|
125
|
+
});
|
|
126
|
+
});
|
|
70
127
|
};
|
|
71
128
|
|
|
72
129
|
export const handleShowConfirm = async (deps, payload) => {
|
|
73
130
|
const { store, render, globalUI } = deps;
|
|
74
131
|
const options = payload;
|
|
75
132
|
|
|
76
|
-
|
|
77
|
-
if (store.selectIsOpen()) {
|
|
78
|
-
store.closeAll();
|
|
79
|
-
render();
|
|
80
|
-
}
|
|
133
|
+
closeExistingUiBeforeShow({ store, render, globalUI });
|
|
81
134
|
|
|
82
135
|
store.setConfirmConfig(options);
|
|
83
136
|
render();
|
|
@@ -111,11 +164,7 @@ export const handleShowDropdownMenu = async (deps, payload) => {
|
|
|
111
164
|
const { store, render, globalUI } = deps;
|
|
112
165
|
const options = payload;
|
|
113
166
|
|
|
114
|
-
|
|
115
|
-
if (store.selectIsOpen()) {
|
|
116
|
-
store.closeAll();
|
|
117
|
-
render();
|
|
118
|
-
}
|
|
167
|
+
closeExistingUiBeforeShow({ store, render, globalUI });
|
|
119
168
|
|
|
120
169
|
store.setDropdownConfig(options);
|
|
121
170
|
render();
|
|
@@ -128,6 +177,55 @@ export const handleShowDropdownMenu = async (deps, payload) => {
|
|
|
128
177
|
});
|
|
129
178
|
};
|
|
130
179
|
|
|
180
|
+
export const handleShowFormDialog = async (deps, payload) => {
|
|
181
|
+
const { store, render, globalUI } = deps;
|
|
182
|
+
const options = payload;
|
|
183
|
+
|
|
184
|
+
closeExistingUiBeforeShow({ store, render, globalUI });
|
|
185
|
+
|
|
186
|
+
store.setFormDialogConfig(options);
|
|
187
|
+
render();
|
|
188
|
+
|
|
189
|
+
const expectedKey = store.selectFormDialogConfig?.().key;
|
|
190
|
+
scheduleFormDialogMount(deps, expectedKey);
|
|
191
|
+
|
|
192
|
+
return new Promise((resolve) => {
|
|
193
|
+
globalUI.once("event", (result) => {
|
|
194
|
+
resolve(result);
|
|
195
|
+
});
|
|
196
|
+
});
|
|
197
|
+
};
|
|
198
|
+
|
|
199
|
+
export const handleFormAction = (deps, payload) => {
|
|
200
|
+
const { store, render, globalUI } = deps;
|
|
201
|
+
const detail = payload._event?.detail || {};
|
|
202
|
+
|
|
203
|
+
if (detail.valid === false) {
|
|
204
|
+
return;
|
|
205
|
+
}
|
|
206
|
+
|
|
207
|
+
closeCurrentUi({
|
|
208
|
+
store,
|
|
209
|
+
render,
|
|
210
|
+
globalUI,
|
|
211
|
+
emitResult: true,
|
|
212
|
+
result: detail,
|
|
213
|
+
});
|
|
214
|
+
};
|
|
215
|
+
|
|
216
|
+
export const handleFormFieldEvent = (deps, payload) => {
|
|
217
|
+
const { store, refs } = deps;
|
|
218
|
+
const detail = payload._event?.detail || {};
|
|
219
|
+
const formDialogConfig = store.selectFormDialogConfig?.();
|
|
220
|
+
|
|
221
|
+
if (typeof formDialogConfig?.onFieldEvent === "function") {
|
|
222
|
+
formDialogConfig.onFieldEvent({
|
|
223
|
+
detail,
|
|
224
|
+
formEl: refs.formDialog || null,
|
|
225
|
+
});
|
|
226
|
+
}
|
|
227
|
+
};
|
|
228
|
+
|
|
131
229
|
/**
|
|
132
230
|
* Triggers a global event to close all UI components.
|
|
133
231
|
* This function will:
|
|
@@ -141,11 +239,6 @@ export const handleShowDropdownMenu = async (deps, payload) => {
|
|
|
141
239
|
* @returns {void}
|
|
142
240
|
*/
|
|
143
241
|
export const handleCloseAll = (deps) => {
|
|
144
|
-
const { store, render } = deps;
|
|
145
|
-
|
|
146
|
-
// Close global UI dialogs/dropdowns
|
|
147
|
-
if (store.selectIsOpen()) {
|
|
148
|
-
store.closeAll();
|
|
149
|
-
render();
|
|
150
|
-
}
|
|
242
|
+
const { store, render, globalUI } = deps;
|
|
243
|
+
closeCurrentUi({ store, render, globalUI, emitResult: true });
|
|
151
244
|
};
|
|
@@ -1,6 +1,19 @@
|
|
|
1
|
+
const VALID_DIALOG_SIZES = new Set(["sm", "md", "lg", "f"]);
|
|
2
|
+
|
|
3
|
+
const normalizeObject = (value) => {
|
|
4
|
+
if (!value || typeof value !== "object" || Array.isArray(value)) {
|
|
5
|
+
return {};
|
|
6
|
+
}
|
|
7
|
+
return value;
|
|
8
|
+
};
|
|
9
|
+
|
|
10
|
+
const normalizeDialogSize = (value, fallback = "md") => {
|
|
11
|
+
return VALID_DIALOG_SIZES.has(value) ? value : fallback;
|
|
12
|
+
};
|
|
13
|
+
|
|
1
14
|
export const createInitialState = () => Object.freeze({
|
|
2
15
|
isOpen: false,
|
|
3
|
-
uiType: "dialog", // "dialog" | "dropdown"
|
|
16
|
+
uiType: "dialog", // "dialog" | "dropdown" | "formDialog"
|
|
4
17
|
config: {
|
|
5
18
|
status: undefined, // undefined | info | warning | error
|
|
6
19
|
title: "",
|
|
@@ -15,6 +28,16 @@ export const createInitialState = () => Object.freeze({
|
|
|
15
28
|
y: 0,
|
|
16
29
|
place: "bs",
|
|
17
30
|
},
|
|
31
|
+
formDialogConfig: {
|
|
32
|
+
form: null,
|
|
33
|
+
defaultValues: {},
|
|
34
|
+
context: {},
|
|
35
|
+
disabled: false,
|
|
36
|
+
size: "md",
|
|
37
|
+
key: 0,
|
|
38
|
+
onFieldEvent: null,
|
|
39
|
+
mount: null,
|
|
40
|
+
},
|
|
18
41
|
});
|
|
19
42
|
|
|
20
43
|
export const setAlertConfig = ({ state }, options = {}) => {
|
|
@@ -66,6 +89,27 @@ export const setDropdownConfig = ({ state }, options = {}) => {
|
|
|
66
89
|
state.isOpen = true;
|
|
67
90
|
};
|
|
68
91
|
|
|
92
|
+
export const setFormDialogConfig = ({ state }, options = {}) => {
|
|
93
|
+
if (!options.form || typeof options.form !== "object" || Array.isArray(options.form)) {
|
|
94
|
+
throw new Error("form object is required for showFormDialog");
|
|
95
|
+
}
|
|
96
|
+
|
|
97
|
+
const prevKey = state.formDialogConfig?.key || 0;
|
|
98
|
+
|
|
99
|
+
state.formDialogConfig = {
|
|
100
|
+
form: options.form,
|
|
101
|
+
defaultValues: normalizeObject(options.defaultValues),
|
|
102
|
+
context: normalizeObject(options.context),
|
|
103
|
+
disabled: !!options.disabled,
|
|
104
|
+
size: normalizeDialogSize(options.size, "md"),
|
|
105
|
+
key: prevKey + 1,
|
|
106
|
+
onFieldEvent: typeof options.onFieldEvent === "function" ? options.onFieldEvent : null,
|
|
107
|
+
mount: typeof options.mount === "function" ? options.mount : null,
|
|
108
|
+
};
|
|
109
|
+
state.uiType = "formDialog";
|
|
110
|
+
state.isOpen = true;
|
|
111
|
+
};
|
|
112
|
+
|
|
69
113
|
export const closeAll = ({ state }) => {
|
|
70
114
|
state.isOpen = false;
|
|
71
115
|
state.uiType = "dialog"; // Reset to default type
|
|
@@ -73,10 +117,14 @@ export const closeAll = ({ state }) => {
|
|
|
73
117
|
|
|
74
118
|
export const selectConfig = ({ state }) => state.config;
|
|
75
119
|
export const selectDropdownConfig = ({ state }) => state.dropdownConfig;
|
|
120
|
+
export const selectFormDialogConfig = ({ state }) => state.formDialogConfig;
|
|
76
121
|
export const selectUiType = ({ state }) => state.uiType;
|
|
77
122
|
export const selectIsOpen = ({ state }) => state.isOpen;
|
|
78
123
|
|
|
79
124
|
export const selectViewData = ({ state }) => {
|
|
125
|
+
const isDialogOpen = state.isOpen && state.uiType === "dialog";
|
|
126
|
+
const isFormDialogOpen = state.isOpen && state.uiType === "formDialog";
|
|
127
|
+
|
|
80
128
|
return {
|
|
81
129
|
isOpen: state.isOpen,
|
|
82
130
|
uiType: state.uiType,
|
|
@@ -87,7 +135,20 @@ export const selectViewData = ({ state }) => {
|
|
|
87
135
|
y: state.dropdownConfig?.y || 0,
|
|
88
136
|
place: state.dropdownConfig?.place || 'bs',
|
|
89
137
|
},
|
|
90
|
-
|
|
138
|
+
formDialogConfig: {
|
|
139
|
+
form: state.formDialogConfig?.form || { fields: [], actions: { buttons: [] } },
|
|
140
|
+
defaultValues: state.formDialogConfig?.defaultValues || {},
|
|
141
|
+
context: state.formDialogConfig?.context || {},
|
|
142
|
+
disabled: !!state.formDialogConfig?.disabled,
|
|
143
|
+
size: normalizeDialogSize(state.formDialogConfig?.size, "md"),
|
|
144
|
+
key: state.formDialogConfig?.key || 0,
|
|
145
|
+
},
|
|
146
|
+
isDialogOpen,
|
|
147
|
+
isFormDialogOpen,
|
|
148
|
+
isDialogContainerOpen: isDialogOpen || isFormDialogOpen,
|
|
91
149
|
isDropdownOpen: state.isOpen && state.uiType === 'dropdown',
|
|
150
|
+
dialogSize: isFormDialogOpen
|
|
151
|
+
? normalizeDialogSize(state.formDialogConfig?.size, "md")
|
|
152
|
+
: "sm",
|
|
92
153
|
};
|
|
93
154
|
};
|
|
@@ -11,6 +11,12 @@ refs:
|
|
|
11
11
|
eventListeners:
|
|
12
12
|
click:
|
|
13
13
|
handler: handleCancel
|
|
14
|
+
formDialog:
|
|
15
|
+
eventListeners:
|
|
16
|
+
form-action:
|
|
17
|
+
handler: handleFormAction
|
|
18
|
+
form-field-event:
|
|
19
|
+
handler: handleFormFieldEvent
|
|
14
20
|
dropdownMenu:
|
|
15
21
|
eventListeners:
|
|
16
22
|
close:
|
|
@@ -18,16 +24,19 @@ refs:
|
|
|
18
24
|
item-click:
|
|
19
25
|
handler: handleDropdownItemClick
|
|
20
26
|
template:
|
|
21
|
-
- rtgl-dialog#dialog ?open=${
|
|
22
|
-
-
|
|
23
|
-
- rtgl-
|
|
24
|
-
|
|
25
|
-
|
|
26
|
-
|
|
27
|
-
|
|
28
|
-
|
|
29
|
-
|
|
30
|
-
|
|
31
|
-
|
|
32
|
-
- rtgl-
|
|
27
|
+
- rtgl-dialog#dialog ?open=${isDialogContainerOpen} s=${dialogSize}:
|
|
28
|
+
- $if isFormDialogOpen:
|
|
29
|
+
- 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:
|
|
31
|
+
- rtgl-view slot=content g=lg p=lg:
|
|
32
|
+
- rtgl-view d=h g=md:
|
|
33
|
+
- rtgl-view d=h ah=c av=c g=md:
|
|
34
|
+
- rtgl-view g=md: null
|
|
35
|
+
- rtgl-view h=24 av=c:
|
|
36
|
+
- rtgl-text s=lg: ${config.title}
|
|
37
|
+
- rtgl-text: ${config.message}
|
|
38
|
+
- rtgl-view d=h g=md mt=lg w=f ah=e:
|
|
39
|
+
- $if config.mode == 'confirm':
|
|
40
|
+
- rtgl-button#cancelButton v=se: ${config.cancelText}
|
|
41
|
+
- rtgl-button#confirmButton v=pr: ${config.confirmText}
|
|
33
42
|
- rtgl-dropdown-menu#dropdownMenu ?open=${isDropdownOpen} x=${dropdownConfig.x} y=${dropdownConfig.y} place=${dropdownConfig.place} :items=dropdownConfig.items key=dropdown-${isDropdownOpen}: null
|
|
@@ -1,6 +1,7 @@
|
|
|
1
1
|
/**
|
|
2
2
|
* Creates a GlobalUI manager instance for controlling global UI components.
|
|
3
|
-
* Provides methods for showing alerts, confirm dialogs,
|
|
3
|
+
* Provides methods for showing alerts, confirm dialogs, form dialogs,
|
|
4
|
+
* dropdown menus, and closing all UI components.
|
|
4
5
|
*
|
|
5
6
|
* @param {HTMLElement} globalUIElement - The globalUI component element
|
|
6
7
|
* @returns {Object} GlobalUI manager instance
|
|
@@ -8,6 +9,7 @@
|
|
|
8
9
|
* @returns {Function} returns.emit - Emit an event to registered listeners
|
|
9
10
|
* @returns {Function} returns.showAlert - Show an alert dialog
|
|
10
11
|
* @returns {Function} returns.showConfirm - Show a confirmation dialog
|
|
12
|
+
* @returns {Function} returns.showFormDialog - Show a form dialog
|
|
11
13
|
* @returns {Function} returns.showDropdownMenu - Show a dropdown menu
|
|
12
14
|
* @returns {Function} returns.closeAll - General-purpose function to close all currently open UI components
|
|
13
15
|
*/
|
|
@@ -66,7 +68,7 @@ const createGlobalUI = (globalUIElement) => {
|
|
|
66
68
|
{
|
|
67
69
|
throw new Error("globalUIElement is not set. Make sure to initialize the global UI component and pass it to createGlobalUIManager.");
|
|
68
70
|
}
|
|
69
|
-
globalUIElement.transformedHandlers.handleShowAlert(options);
|
|
71
|
+
return globalUIElement.transformedHandlers.handleShowAlert(options);
|
|
70
72
|
},
|
|
71
73
|
|
|
72
74
|
/**
|
|
@@ -90,6 +92,28 @@ const createGlobalUI = (globalUIElement) => {
|
|
|
90
92
|
return globalUIElement.transformedHandlers.handleShowConfirm(options);
|
|
91
93
|
},
|
|
92
94
|
|
|
95
|
+
/**
|
|
96
|
+
* Shows a dialog containing an embedded rtgl-form.
|
|
97
|
+
*
|
|
98
|
+
* @param {Object} options - Form dialog configuration options
|
|
99
|
+
* @param {Object} options.form - rtgl-form schema (required)
|
|
100
|
+
* @param {Object} [options.defaultValues] - Initial form values
|
|
101
|
+
* @param {Object} [options.context] - Context used by rtgl-form conditional rendering
|
|
102
|
+
* @param {boolean} [options.disabled] - Whether the form should be disabled
|
|
103
|
+
* @param {('sm'|'md'|'lg'|'f')} [options.size] - Dialog size token (default: "md")
|
|
104
|
+
* @param {Function} [options.onFieldEvent] - Called with `{ detail, formEl }` for form field events
|
|
105
|
+
* @param {Function} [options.mount] - Called once after the form mounts, useful for slot content
|
|
106
|
+
* @returns {Promise<Object|null>} Resolves with form-action detail or null on dismiss
|
|
107
|
+
* @throws {Error} If globalUIElement is not initialized
|
|
108
|
+
*/
|
|
109
|
+
showFormDialog: async (options) => {
|
|
110
|
+
if(!globalUIElement)
|
|
111
|
+
{
|
|
112
|
+
throw new Error("globalUIElement is not set. Make sure to initialize the global UI component and pass it to createGlobalUIManager.");
|
|
113
|
+
}
|
|
114
|
+
return globalUIElement.transformedHandlers.handleShowFormDialog(options);
|
|
115
|
+
},
|
|
116
|
+
|
|
93
117
|
/**
|
|
94
118
|
* Shows a dropdown menu at the specified position with the given items.
|
|
95
119
|
* The dropdown can contain various item types including labels, items, and separators.
|