@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-rc19",
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(name, e.detail.value, store.selectFormValues(), dispatchEvent);
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(name, e.detail.value, store.selectFormValues(), dispatchEvent);
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(name, e.detail.selectedValue, store.selectFormValues(), dispatchEvent);
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(name, e.detail.value, store.selectFormValues(), dispatchEvent);
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(name, e.detail.value, store.selectFormValues(), dispatchEvent);
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(name, e.detail.value, store.selectFormValues(), dispatchEvent);
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('[') && path in obj) {
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 (!(key in current) || typeof current[key] !== 'object' || current[key] === null) {
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 = ['id', 'class', 'style', 'slot'];
58
+ const blacklistedAttrs = ["id", "class", "style", "slot"];
46
59
 
47
60
  const stringifyAttrs = (attrs) => {
48
- return Object.entries(attrs).filter(([key]) => !blacklistedAttrs.includes(key)).map(([key, value]) => `${key}=${value}`).join(' ');
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 === 'image') {
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 || 'No Image';
92
+ field.placeholderText = field.placeholder || "No Image";
66
93
  }
67
- if (field.inputType === 'waveform') {
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 || 'No Waveform';
99
+ field.placeholderText = field.placeholder || "No Waveform";
73
100
  }
74
- })
101
+ });
75
102
 
76
103
  return {
77
104
  containerAttrString,
78
- title: props.form?.title || '',
79
- description: props?.form?.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
- return state.formValues;
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
- - rtgl-view g=sm w=f:
246
- - rtgl-text s=lg: ${title}
247
- - rtgl-text c=mu-fg: ${description}
248
- - rtgl-view g=lg w=f:
249
- - $for field, i in fields:
250
- - rtgl-view g=md w=f:
251
- - rtgl-view g=sm:
252
- - rtgl-text: ${field.label}
253
- - rtgl-text s=sm c=mu-fg: ${field.description}
254
- - $if field.inputType == "read-only-text":
255
- - rtgl-text s=sm: ${field.defaultValue}
256
- - $if field.inputType == "inputText":
257
- - rtgl-input#input-${field.name} w=f placeholder=${field.placeholder} value=${field.defaultValue}:
258
- - $if field.inputType == "popover-input":
259
- - rtgl-popover-input#popover-input-${field.name} label="${field.label}" .defaultValue=fields[${i}].defaultValue:
260
- - $if field.inputType == "select":
261
- - rtgl-select#select-${field.name} w=f .options=fields[${i}].options .placeholder=fields[${i}].placeholder .selectedValue=fields[${i}].defaultValue:
262
- - $if field.inputType == "colorPicker":
263
- - rtgl-color-picker#colorpicker-${field.name} value=${field.defaultValue}:
264
- - $if field.inputType == "slider":
265
- - rtgl-slider#slider-${field.name} w=f min=${field.min} max=${field.max} step=${field.step} value=${field.defaultValue}:
266
- - $if field.inputType == "slider-input":
267
- - rtgl-slider-input#slider-input-${field.name} w=f min=${field.min} max=${field.max} step=${field.step} defaultValue=${field.defaultValue}:
268
- - $if field.inputType == "image" && field.imageSrc:
269
- - rtgl-image#image-${field.name} src=${field.imageSrc} w=${field.width} h=${field.height} cur=p:
270
- - $if field.inputType == "image" && !field.imageSrc:
271
- - rtgl-view#image-${field.name} w=${field.width} h=${field.height} bc=ac bw=sm ah=c av=c cur=p p=md:
272
- - rtgl-text c=mu-fg ta=c: ${field.placeholderText}
273
- - $if field.inputType == "waveform" && field.waveformData:
274
- - rtgl-waveform#waveform-${field.name} .waveformData=fields[${i}].waveformData w=${field.width} h=${field.height} cur=p:
275
- - $if field.inputType == "waveform" && !field.waveformData:
276
- - rtgl-view#waveform-${field.name} w=${field.width} h=${field.height} bc=ac bw=sm ah=c av=c cur=p p=md:
277
- - rtgl-text c=mu-fg ta=c: ${field.placeholder}
278
- - rtgl-view g=sm w=f:
279
- - rtgl-view d=h ah=e g=sm w=f:
280
- - $for button, i in actions.buttons:
281
- - rtgl-button#action-${button.id}: ${button.content}
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}