@rettangoli/ui 0.1.2-rc19 → 0.1.2-rc20
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": "0.1.2-
|
|
3
|
+
"version": "0.1.2-rc20",
|
|
4
4
|
"description": "A UI component library for building web interfaces.",
|
|
5
5
|
"main": "dist/rettangoli-esm.min.js",
|
|
6
6
|
"type": "module",
|
|
@@ -49,10 +49,11 @@
|
|
|
49
49
|
"homepage": "https://github.com/yuusoft-org/rettangoli#readme",
|
|
50
50
|
"dependencies": {
|
|
51
51
|
"@floating-ui/dom": "^1.6.13",
|
|
52
|
+
"@rettangoli/fe": "0.0.7-rc11",
|
|
52
53
|
"commander": "^13.1.0",
|
|
54
|
+
"jempl": "^0.1.2",
|
|
53
55
|
"js-yaml": "^4.1.0",
|
|
54
56
|
"liquidjs": "^10.21.0",
|
|
55
|
-
"@rettangoli/fe": "0.0.7-rc11",
|
|
56
57
|
"snabbdom": "^3.6.2"
|
|
57
58
|
}
|
|
58
59
|
}
|
|
@@ -4,7 +4,7 @@ export const handleBeforeMount = (deps) => {
|
|
|
4
4
|
};
|
|
5
5
|
|
|
6
6
|
export const handleOnUpdate = (changes, deps) => {
|
|
7
|
-
const { oldAttrs, newAttrs } = changes
|
|
7
|
+
const { oldAttrs, newAttrs } = changes;
|
|
8
8
|
const { store, props, render } = deps;
|
|
9
9
|
|
|
10
10
|
if (oldAttrs?.key === newAttrs?.key) {
|
|
@@ -41,15 +41,21 @@ export const handleActionClick = (e, deps) => {
|
|
|
41
41
|
};
|
|
42
42
|
|
|
43
43
|
export const handleInputChange = (e, deps) => {
|
|
44
|
-
const { store, dispatchEvent } = deps;
|
|
44
|
+
const { store, dispatchEvent, props } = deps;
|
|
45
45
|
const name = e.currentTarget.id.replace("input-", "");
|
|
46
46
|
// TODO fix double event
|
|
47
47
|
if (name && e.detail.value !== undefined) {
|
|
48
48
|
store.setFormFieldValue({
|
|
49
49
|
name: name,
|
|
50
50
|
value: e.detail.value,
|
|
51
|
+
props,
|
|
51
52
|
});
|
|
52
|
-
dispatchFormChange(
|
|
53
|
+
dispatchFormChange(
|
|
54
|
+
name,
|
|
55
|
+
e.detail.value,
|
|
56
|
+
store.selectFormValues(),
|
|
57
|
+
dispatchEvent,
|
|
58
|
+
);
|
|
53
59
|
}
|
|
54
60
|
};
|
|
55
61
|
|
|
@@ -61,56 +67,87 @@ export const handlePopoverInputChange = (e, deps) => {
|
|
|
61
67
|
store.setFormFieldValue({
|
|
62
68
|
name: name,
|
|
63
69
|
value: e.detail.value,
|
|
70
|
+
props,
|
|
64
71
|
});
|
|
65
|
-
dispatchFormChange(
|
|
72
|
+
dispatchFormChange(
|
|
73
|
+
name,
|
|
74
|
+
e.detail.value,
|
|
75
|
+
store.selectFormValues(),
|
|
76
|
+
dispatchEvent,
|
|
77
|
+
);
|
|
66
78
|
}
|
|
67
79
|
};
|
|
68
80
|
|
|
69
81
|
export const handleSelectChange = (e, deps) => {
|
|
70
|
-
const { store, dispatchEvent } = deps;
|
|
82
|
+
const { store, dispatchEvent, render, props } = deps;
|
|
71
83
|
const name = e.currentTarget.id.replace("select-", "");
|
|
72
84
|
if (name && e.detail.selectedValue !== undefined) {
|
|
73
85
|
store.setFormFieldValue({
|
|
74
86
|
name: name,
|
|
75
87
|
value: e.detail.selectedValue,
|
|
88
|
+
props,
|
|
76
89
|
});
|
|
77
|
-
dispatchFormChange(
|
|
90
|
+
dispatchFormChange(
|
|
91
|
+
name,
|
|
92
|
+
e.detail.selectedValue,
|
|
93
|
+
store.selectFormValues(),
|
|
94
|
+
dispatchEvent,
|
|
95
|
+
);
|
|
96
|
+
render();
|
|
78
97
|
}
|
|
79
98
|
};
|
|
80
99
|
|
|
81
100
|
export const handleColorPickerChange = (e, deps) => {
|
|
82
|
-
const { store, dispatchEvent } = deps;
|
|
101
|
+
const { store, dispatchEvent, props } = deps;
|
|
83
102
|
const name = e.currentTarget.id.replace("colorpicker-", "");
|
|
84
103
|
if (name && e.detail.value !== undefined) {
|
|
85
104
|
store.setFormFieldValue({
|
|
86
105
|
name: name,
|
|
87
106
|
value: e.detail.value,
|
|
107
|
+
props,
|
|
88
108
|
});
|
|
89
|
-
dispatchFormChange(
|
|
109
|
+
dispatchFormChange(
|
|
110
|
+
name,
|
|
111
|
+
e.detail.value,
|
|
112
|
+
store.selectFormValues(),
|
|
113
|
+
dispatchEvent,
|
|
114
|
+
);
|
|
90
115
|
}
|
|
91
116
|
};
|
|
92
117
|
|
|
93
118
|
export const handleSliderChange = (e, deps) => {
|
|
94
|
-
const { store, dispatchEvent } = deps;
|
|
119
|
+
const { store, dispatchEvent, props } = deps;
|
|
95
120
|
const name = e.currentTarget.id.replace("slider-", "");
|
|
96
121
|
if (name && e.detail.value !== undefined) {
|
|
97
122
|
store.setFormFieldValue({
|
|
98
123
|
name: name,
|
|
99
124
|
value: e.detail.value,
|
|
125
|
+
props,
|
|
100
126
|
});
|
|
101
|
-
dispatchFormChange(
|
|
127
|
+
dispatchFormChange(
|
|
128
|
+
name,
|
|
129
|
+
e.detail.value,
|
|
130
|
+
store.selectFormValues(),
|
|
131
|
+
dispatchEvent,
|
|
132
|
+
);
|
|
102
133
|
}
|
|
103
134
|
};
|
|
104
135
|
|
|
105
136
|
export const handleSliderInputChange = (e, deps) => {
|
|
106
|
-
const { store, dispatchEvent } = deps;
|
|
137
|
+
const { store, dispatchEvent, props } = deps;
|
|
107
138
|
const name = e.currentTarget.id.replace("slider-input-", "");
|
|
108
139
|
if (name && e.detail.value !== undefined) {
|
|
109
140
|
store.setFormFieldValue({
|
|
110
141
|
name: name,
|
|
111
142
|
value: e.detail.value,
|
|
143
|
+
props,
|
|
112
144
|
});
|
|
113
|
-
dispatchFormChange(
|
|
145
|
+
dispatchFormChange(
|
|
146
|
+
name,
|
|
147
|
+
e.detail.value,
|
|
148
|
+
store.selectFormValues(),
|
|
149
|
+
dispatchEvent,
|
|
150
|
+
);
|
|
114
151
|
}
|
|
115
152
|
};
|
|
116
153
|
|
|
@@ -126,7 +163,7 @@ export const handleImageClick = (e, deps) => {
|
|
|
126
163
|
name: name,
|
|
127
164
|
x: e.clientX,
|
|
128
165
|
y: e.clientY,
|
|
129
|
-
trigger: e.type
|
|
166
|
+
trigger: e.type,
|
|
130
167
|
},
|
|
131
168
|
}),
|
|
132
169
|
);
|
|
@@ -144,7 +181,7 @@ export const handleWaveformClick = (e, deps) => {
|
|
|
144
181
|
name: name,
|
|
145
182
|
x: e.clientX,
|
|
146
183
|
y: e.clientY,
|
|
147
|
-
trigger: e.type
|
|
184
|
+
trigger: e.type,
|
|
148
185
|
},
|
|
149
186
|
}),
|
|
150
187
|
);
|
|
@@ -1,10 +1,19 @@
|
|
|
1
|
+
import { parseAndRender } from "jempl";
|
|
2
|
+
|
|
3
|
+
function pick(obj, keys) {
|
|
4
|
+
return keys.reduce((acc, key) => {
|
|
5
|
+
if (key in obj) acc[key] = obj[key];
|
|
6
|
+
return acc;
|
|
7
|
+
}, {});
|
|
8
|
+
}
|
|
9
|
+
|
|
1
10
|
export const INITIAL_STATE = Object.freeze({
|
|
2
|
-
formValues: {}
|
|
11
|
+
formValues: {},
|
|
3
12
|
});
|
|
4
13
|
|
|
5
14
|
// Lodash-like utility functions for nested property access
|
|
6
15
|
const get = (obj, path, defaultValue = undefined) => {
|
|
7
|
-
const keys = path.split(/[\[\].]/).filter(key => key !==
|
|
16
|
+
const keys = path.split(/[\[\].]/).filter((key) => key !== "");
|
|
8
17
|
let current = obj;
|
|
9
18
|
|
|
10
19
|
for (const key of keys) {
|
|
@@ -15,21 +24,25 @@ const get = (obj, path, defaultValue = undefined) => {
|
|
|
15
24
|
}
|
|
16
25
|
|
|
17
26
|
return current;
|
|
18
|
-
}
|
|
27
|
+
};
|
|
19
28
|
|
|
20
29
|
const set = (obj, path, value) => {
|
|
21
|
-
const keys = path.split(/[\[\].]/).filter(key => key !==
|
|
22
|
-
|
|
30
|
+
const keys = path.split(/[\[\].]/).filter((key) => key !== "");
|
|
31
|
+
|
|
23
32
|
// If path contains array notation, delete the original flat key
|
|
24
|
-
if (path.includes(
|
|
33
|
+
if (path.includes("[") && path in obj) {
|
|
25
34
|
delete obj[path];
|
|
26
35
|
}
|
|
27
|
-
|
|
36
|
+
|
|
28
37
|
let current = obj;
|
|
29
|
-
|
|
38
|
+
|
|
30
39
|
for (let i = 0; i < keys.length - 1; i++) {
|
|
31
40
|
const key = keys[i];
|
|
32
|
-
if (
|
|
41
|
+
if (
|
|
42
|
+
!(key in current) ||
|
|
43
|
+
typeof current[key] !== "object" ||
|
|
44
|
+
current[key] === null
|
|
45
|
+
) {
|
|
33
46
|
// Check if next key is a number to create array
|
|
34
47
|
const nextKey = keys[i + 1];
|
|
35
48
|
const isArrayIndex = /^\d+$/.test(nextKey);
|
|
@@ -37,71 +50,96 @@ const set = (obj, path, value) => {
|
|
|
37
50
|
}
|
|
38
51
|
current = current[key];
|
|
39
52
|
}
|
|
40
|
-
|
|
53
|
+
|
|
41
54
|
current[keys[keys.length - 1]] = value;
|
|
42
55
|
return obj;
|
|
43
|
-
}
|
|
56
|
+
};
|
|
44
57
|
|
|
45
|
-
const blacklistedAttrs = [
|
|
58
|
+
const blacklistedAttrs = ["id", "class", "style", "slot"];
|
|
46
59
|
|
|
47
60
|
const stringifyAttrs = (attrs) => {
|
|
48
|
-
return Object.entries(attrs)
|
|
49
|
-
|
|
61
|
+
return Object.entries(attrs)
|
|
62
|
+
.filter(([key]) => !blacklistedAttrs.includes(key))
|
|
63
|
+
.map(([key, value]) => `${key}=${value}`)
|
|
64
|
+
.join(" ");
|
|
65
|
+
};
|
|
66
|
+
|
|
67
|
+
export const selectForm = ({ state, props }) => {
|
|
68
|
+
const { form } = props;
|
|
69
|
+
const { context } = props;
|
|
70
|
+
|
|
71
|
+
if (context) {
|
|
72
|
+
return parseAndRender(form, context);
|
|
73
|
+
}
|
|
50
74
|
|
|
75
|
+
return form;
|
|
76
|
+
};
|
|
51
77
|
|
|
52
78
|
export const toViewData = ({ state, props, attrs }) => {
|
|
53
79
|
const containerAttrString = stringifyAttrs(attrs);
|
|
54
|
-
const fields = structuredClone(props.form.fields || []);
|
|
55
80
|
const defaultValues = props.defaultValues || {};
|
|
56
81
|
|
|
82
|
+
const form = selectForm({ state, props });
|
|
83
|
+
const fields = structuredClone(form.fields || []);
|
|
57
84
|
fields.forEach((field) => {
|
|
58
85
|
field.defaultValue = get(defaultValues, field.name);
|
|
59
|
-
|
|
60
|
-
if (field.inputType ===
|
|
86
|
+
|
|
87
|
+
if (field.inputType === "image") {
|
|
61
88
|
const src = field.src;
|
|
62
89
|
// Only set imageSrc if src exists and is not empty
|
|
63
90
|
field.imageSrc = src && src.trim() ? src : null;
|
|
64
91
|
// Set placeholder text
|
|
65
|
-
field.placeholderText = field.placeholder ||
|
|
92
|
+
field.placeholderText = field.placeholder || "No Image";
|
|
66
93
|
}
|
|
67
|
-
if (field.inputType ===
|
|
94
|
+
if (field.inputType === "waveform") {
|
|
68
95
|
const waveformData = field.waveformData;
|
|
69
96
|
// Only set waveformData if it exists
|
|
70
97
|
field.waveformData = waveformData || null;
|
|
71
98
|
// Set placeholder text
|
|
72
|
-
field.placeholderText = field.placeholder ||
|
|
99
|
+
field.placeholderText = field.placeholder || "No Waveform";
|
|
73
100
|
}
|
|
74
|
-
})
|
|
101
|
+
});
|
|
75
102
|
|
|
76
103
|
return {
|
|
77
104
|
containerAttrString,
|
|
78
|
-
title:
|
|
79
|
-
description:
|
|
105
|
+
title: form?.title || "",
|
|
106
|
+
description: form?.description || "",
|
|
80
107
|
fields: fields,
|
|
81
108
|
actions: props?.form?.actions || {
|
|
82
|
-
buttons: []
|
|
109
|
+
buttons: [],
|
|
83
110
|
},
|
|
84
111
|
formValues: state.formValues,
|
|
85
112
|
};
|
|
86
|
-
}
|
|
113
|
+
};
|
|
87
114
|
|
|
88
115
|
export const selectState = ({ state }) => {
|
|
89
116
|
return state;
|
|
90
|
-
}
|
|
117
|
+
};
|
|
91
118
|
|
|
92
|
-
export const selectFormValues = ({ state }) => {
|
|
93
|
-
|
|
94
|
-
|
|
119
|
+
export const selectFormValues = ({ state, props }) => {
|
|
120
|
+
const form = selectForm({ state, props });
|
|
121
|
+
|
|
122
|
+
return pick(
|
|
123
|
+
state.formValues,
|
|
124
|
+
form.fields.map((field) => field.name),
|
|
125
|
+
);
|
|
126
|
+
};
|
|
95
127
|
|
|
96
128
|
export const getFormFieldValue = ({ state }, name) => {
|
|
97
129
|
return get(state.formValues, name);
|
|
98
|
-
}
|
|
130
|
+
};
|
|
99
131
|
|
|
100
132
|
export const setFormValues = (state, defaultValues) => {
|
|
101
133
|
state.formValues = defaultValues || {};
|
|
102
|
-
}
|
|
134
|
+
};
|
|
103
135
|
|
|
104
|
-
export const setFormFieldValue = (state, { name, value }) => {
|
|
136
|
+
export const setFormFieldValue = (state, { name, value, props }) => {
|
|
105
137
|
set(state.formValues, name, value);
|
|
106
|
-
|
|
107
|
-
|
|
138
|
+
// remove non visible values
|
|
139
|
+
const form = selectForm({ state, props });
|
|
140
|
+
const formValues = pick(
|
|
141
|
+
state.formValues,
|
|
142
|
+
form.fields.map((field) => field.name),
|
|
143
|
+
);
|
|
144
|
+
state.formValues = formValues;
|
|
145
|
+
};
|
|
@@ -8,6 +8,8 @@ propsSchema:
|
|
|
8
8
|
properties:
|
|
9
9
|
defaultValues:
|
|
10
10
|
type: object
|
|
11
|
+
context:
|
|
12
|
+
type: object
|
|
11
13
|
form:
|
|
12
14
|
type: object
|
|
13
15
|
properties:
|
|
@@ -242,40 +244,40 @@ events:
|
|
|
242
244
|
|
|
243
245
|
template:
|
|
244
246
|
- rtgl-view w=f h=f p=md g=lg ${containerAttrString}:
|
|
245
|
-
|
|
246
|
-
|
|
247
|
-
|
|
248
|
-
|
|
249
|
-
|
|
250
|
-
|
|
251
|
-
|
|
252
|
-
|
|
253
|
-
|
|
254
|
-
|
|
255
|
-
|
|
256
|
-
|
|
257
|
-
|
|
258
|
-
|
|
259
|
-
|
|
260
|
-
|
|
261
|
-
|
|
262
|
-
|
|
263
|
-
|
|
264
|
-
|
|
265
|
-
|
|
266
|
-
|
|
267
|
-
|
|
268
|
-
|
|
269
|
-
|
|
270
|
-
|
|
271
|
-
|
|
272
|
-
|
|
273
|
-
|
|
274
|
-
|
|
275
|
-
|
|
276
|
-
|
|
277
|
-
|
|
278
|
-
|
|
279
|
-
|
|
280
|
-
|
|
281
|
-
|
|
247
|
+
- rtgl-view g=sm w=f:
|
|
248
|
+
- rtgl-text s=lg: ${title}
|
|
249
|
+
- rtgl-text c=mu-fg: ${description}
|
|
250
|
+
- rtgl-view g=lg w=f:
|
|
251
|
+
- $for field, i in fields:
|
|
252
|
+
- rtgl-view g=md w=f:
|
|
253
|
+
- rtgl-view g=sm:
|
|
254
|
+
- rtgl-text: ${field.label}
|
|
255
|
+
- rtgl-text s=sm c=mu-fg: ${field.description}
|
|
256
|
+
- $if field.inputType == "read-only-text":
|
|
257
|
+
- rtgl-text s=sm: ${field.defaultValue}
|
|
258
|
+
- $if field.inputType == "inputText":
|
|
259
|
+
- rtgl-input#input-${field.name} w=f placeholder=${field.placeholder} value=${field.defaultValue}:
|
|
260
|
+
- $if field.inputType == "popover-input":
|
|
261
|
+
- rtgl-popover-input#popover-input-${field.name} label="${field.label}" .defaultValue=fields[${i}].defaultValue:
|
|
262
|
+
- $if field.inputType == "select":
|
|
263
|
+
- rtgl-select#select-${field.name} w=f .options=fields[${i}].options .placeholder=fields[${i}].placeholder .selectedValue=fields[${i}].defaultValue:
|
|
264
|
+
- $if field.inputType == "colorPicker":
|
|
265
|
+
- rtgl-color-picker#colorpicker-${field.name} value=${field.defaultValue}:
|
|
266
|
+
- $if field.inputType == "slider":
|
|
267
|
+
- rtgl-slider#slider-${field.name} w=f min=${field.min} max=${field.max} step=${field.step} value=${field.defaultValue}:
|
|
268
|
+
- $if field.inputType == "slider-input":
|
|
269
|
+
- rtgl-slider-input#slider-input-${field.name} w=f min=${field.min} max=${field.max} step=${field.step} defaultValue=${field.defaultValue}:
|
|
270
|
+
- $if field.inputType == "image" && field.imageSrc:
|
|
271
|
+
- rtgl-image#image-${field.name} src=${field.imageSrc} w=${field.width} h=${field.height} cur=p:
|
|
272
|
+
- $if field.inputType == "image" && !field.imageSrc:
|
|
273
|
+
- rtgl-view#image-${field.name} w=${field.width} h=${field.height} bc=ac bw=sm ah=c av=c cur=p p=md:
|
|
274
|
+
- rtgl-text c=mu-fg ta=c: ${field.placeholderText}
|
|
275
|
+
- $if field.inputType == "waveform" && field.waveformData:
|
|
276
|
+
- rtgl-waveform#waveform-${field.name} .waveformData=fields[${i}].waveformData w=${field.width} h=${field.height} cur=p:
|
|
277
|
+
- $if field.inputType == "waveform" && !field.waveformData:
|
|
278
|
+
- rtgl-view#waveform-${field.name} w=${field.width} h=${field.height} bc=ac bw=sm ah=c av=c cur=p p=md:
|
|
279
|
+
- rtgl-text c=mu-fg ta=c: ${field.placeholder}
|
|
280
|
+
- rtgl-view g=sm w=f:
|
|
281
|
+
- rtgl-view d=h ah=e g=sm w=f:
|
|
282
|
+
- $for button, i in actions.buttons:
|
|
283
|
+
- rtgl-button#action-${button.id}: ${button.content}
|