@rettangoli/ui 1.0.0-rc9 → 1.0.1

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.
Files changed (45) hide show
  1. package/dist/rettangoli-iife-layout.min.js +74 -42
  2. package/dist/rettangoli-iife-ui.min.js +161 -60
  3. package/dist/themes/base.css +2 -2
  4. package/dist/themes/theme-catppuccin.css +1 -1
  5. package/dist/themes/theme-rtgl-mono.css +1 -1
  6. package/dist/themes/theme-rtgl-slate.css +1 -1
  7. package/package.json +11 -7
  8. package/src/common/dimensions.js +85 -0
  9. package/src/common/responsive.js +72 -0
  10. package/src/common.js +6 -4
  11. package/src/components/dropdownMenu/dropdownMenu.schema.yaml +1 -1
  12. package/src/components/form/form.handlers.js +328 -152
  13. package/src/components/form/form.methods.js +205 -0
  14. package/src/components/form/form.schema.yaml +16 -271
  15. package/src/components/form/form.store.js +542 -97
  16. package/src/components/form/form.view.yaml +73 -52
  17. package/src/components/globalUi/globalUi.handlers.js +4 -4
  18. package/src/components/popoverInput/popoverInput.handlers.js +64 -50
  19. package/src/components/popoverInput/popoverInput.schema.yaml +3 -1
  20. package/src/components/popoverInput/popoverInput.store.js +9 -3
  21. package/src/components/popoverInput/popoverInput.view.yaml +4 -4
  22. package/src/components/select/select.handlers.js +15 -19
  23. package/src/components/select/select.schema.yaml +2 -0
  24. package/src/components/select/select.store.js +8 -6
  25. package/src/components/select/select.view.yaml +4 -4
  26. package/src/components/sliderInput/sliderInput.handlers.js +15 -1
  27. package/src/components/sliderInput/sliderInput.schema.yaml +3 -0
  28. package/src/components/sliderInput/sliderInput.store.js +2 -1
  29. package/src/components/sliderInput/sliderInput.view.yaml +2 -2
  30. package/src/components/tooltip/tooltip.schema.yaml +1 -1
  31. package/src/deps/createGlobalUI.js +4 -4
  32. package/src/entry-iife-layout.js +6 -0
  33. package/src/entry-iife-ui.js +8 -0
  34. package/src/index.js +8 -0
  35. package/src/primitives/checkbox.js +295 -0
  36. package/src/primitives/input-date.js +31 -0
  37. package/src/primitives/input-datetime.js +31 -0
  38. package/src/primitives/input-time.js +31 -0
  39. package/src/primitives/input.js +43 -1
  40. package/src/primitives/textarea.js +3 -0
  41. package/src/primitives/view.js +8 -2
  42. package/src/themes/base.css +2 -2
  43. package/src/themes/theme-catppuccin.css +1 -1
  44. package/src/themes/theme-rtgl-mono.css +1 -1
  45. package/src/themes/theme-rtgl-slate.css +1 -1
@@ -0,0 +1,205 @@
1
+ import {
2
+ get,
3
+ set,
4
+ selectForm,
5
+ selectFormValues,
6
+ collectAllDataFields,
7
+ getDefaultValue,
8
+ validateForm,
9
+ } from "./form.store.js";
10
+
11
+ const VALUE_FIELD_TYPES = [
12
+ "input-text",
13
+ "input-date",
14
+ "input-time",
15
+ "input-datetime",
16
+ "input-number",
17
+ "input-textarea",
18
+ "color-picker",
19
+ "slider",
20
+ "slider-with-input",
21
+ "popover-input",
22
+ ];
23
+
24
+ const TEXT_LIKE_FIELD_TYPES = [
25
+ "input-text",
26
+ "input-date",
27
+ "input-time",
28
+ "input-datetime",
29
+ "input-number",
30
+ "input-textarea",
31
+ "popover-input",
32
+ "slider-with-input",
33
+ ];
34
+
35
+ const syncFieldValueAttribute = ({ ref, fieldType, value, forceRefresh = false }) => {
36
+ if (!VALUE_FIELD_TYPES.includes(fieldType)) return;
37
+
38
+ if (forceRefresh) {
39
+ ref.removeAttribute("value");
40
+ }
41
+
42
+ if (value === undefined || value === null) {
43
+ if (TEXT_LIKE_FIELD_TYPES.includes(fieldType) && forceRefresh) {
44
+ if (fieldType === "popover-input") {
45
+ // Empty string attributes normalize to boolean `true` in runtime prop fallback.
46
+ ref.removeAttribute("value");
47
+ return;
48
+ }
49
+ // Ensure inner primitive value is cleared even when attribute was already absent.
50
+ ref.setAttribute("value", "");
51
+ return;
52
+ }
53
+
54
+ ref.removeAttribute("value");
55
+ return;
56
+ }
57
+
58
+ ref.setAttribute("value", String(value));
59
+ };
60
+
61
+ const syncSelectFieldState = ({ ref, value }) => {
62
+ if (!ref) return;
63
+ if (!ref?.store?.updateSelectedValue) return;
64
+ ref.store.updateSelectedValue({ value });
65
+ if (typeof ref.render === "function") {
66
+ ref.render();
67
+ }
68
+ };
69
+
70
+ const buildFieldRefMap = (root) => {
71
+ const map = new Map();
72
+ if (!root || typeof root.querySelectorAll !== "function") {
73
+ return map;
74
+ }
75
+
76
+ root.querySelectorAll("[data-field-name]").forEach((ref) => {
77
+ const name = ref.getAttribute("data-field-name");
78
+ if (name) {
79
+ map.set(name, ref);
80
+ }
81
+ });
82
+
83
+ return map;
84
+ };
85
+
86
+ const resolveRenderRoot = (instance) => {
87
+ if (instance?.renderTarget) return instance.renderTarget;
88
+ if (instance?.shadowRoot) return instance.shadowRoot;
89
+ return instance?.shadow;
90
+ };
91
+
92
+ const syncSelectRefsFromValues = ({ root, values = {} }) => {
93
+ if (!root || typeof root.querySelectorAll !== "function") return;
94
+
95
+ const selectRefs = root.querySelectorAll("rtgl-select[data-field-name]");
96
+ selectRefs.forEach((ref) => {
97
+ const fieldName = ref.dataset?.fieldName;
98
+ if (!fieldName) return;
99
+
100
+ const value = get(values, fieldName);
101
+ syncSelectFieldState({ ref, value });
102
+ });
103
+ };
104
+
105
+ export const getValues = function () {
106
+ const state = this.store.getState();
107
+ return selectFormValues({ state, props: this.props });
108
+ };
109
+
110
+ export const setValues = function (payload = {}) {
111
+ const values =
112
+ payload && typeof payload === "object" && payload.values && typeof payload.values === "object"
113
+ ? payload.values
114
+ : payload;
115
+ if (!values || typeof values !== "object" || Array.isArray(values)) return;
116
+
117
+ this.store.setFormValues({ values });
118
+ this.store.pruneHiddenValues();
119
+
120
+ // Update DOM attributes for affected fields
121
+ const state = this.store.getState();
122
+ const form = selectForm({ state, props: this.props });
123
+ const dataFields = collectAllDataFields(form.fields || []);
124
+ const refsByName = buildFieldRefMap(resolveRenderRoot(this));
125
+
126
+ for (const field of dataFields) {
127
+ if (!field.name) continue;
128
+ const ref = refsByName.get(field.name);
129
+ if (!ref) continue;
130
+ const hasDirectValue = Object.prototype.hasOwnProperty.call(values, field.name);
131
+ const incomingValue = get(values, field.name);
132
+ if (!hasDirectValue && incomingValue === undefined) continue;
133
+
134
+ const value = get(state.formValues, field.name);
135
+
136
+ syncFieldValueAttribute({
137
+ ref,
138
+ fieldType: field.type,
139
+ value,
140
+ forceRefresh: true,
141
+ });
142
+
143
+ if (typeof ref?.tagName === "string" && ref.tagName.toUpperCase() === "RTGL-SELECT") {
144
+ syncSelectFieldState({ ref, value });
145
+ }
146
+
147
+ if (field.type === "checkbox") {
148
+ if (value) {
149
+ ref.setAttribute("checked", "");
150
+ } else {
151
+ ref.removeAttribute("checked");
152
+ }
153
+ }
154
+ }
155
+ this.render();
156
+ const syncSelects = () => {
157
+ const nextState = this.store.getState();
158
+ syncSelectRefsFromValues({
159
+ root: resolveRenderRoot(this),
160
+ values: nextState.formValues,
161
+ });
162
+ };
163
+ syncSelects();
164
+ setTimeout(() => {
165
+ syncSelects();
166
+ }, 0);
167
+ };
168
+
169
+ export const validate = function () {
170
+ const state = this.store.getState();
171
+ const form = selectForm({ state, props: this.props });
172
+ const dataFields = collectAllDataFields(form.fields || []);
173
+ const { valid, errors } = validateForm(dataFields, state.formValues);
174
+
175
+ this.store.setErrors({ errors });
176
+ if (!valid) {
177
+ this.store.setReactiveMode();
178
+ }
179
+ this.render();
180
+
181
+ return { valid, errors };
182
+ };
183
+
184
+ export const reset = function () {
185
+ const defaultValues = this.props?.defaultValues || {};
186
+ const seededValues = {};
187
+ Object.keys(defaultValues).forEach((path) => {
188
+ set(seededValues, path, defaultValues[path]);
189
+ });
190
+ const form = selectForm({ state: { formValues: seededValues }, props: this.props });
191
+ const dataFields = collectAllDataFields(form.fields || []);
192
+ const initial = {};
193
+
194
+ for (const field of dataFields) {
195
+ const defaultVal = get(defaultValues, field.name);
196
+ if (defaultVal !== undefined) {
197
+ set(initial, field.name, defaultVal);
198
+ } else {
199
+ set(initial, field.name, getDefaultValue(field));
200
+ }
201
+ }
202
+
203
+ this.store.resetFormValues({ defaultValues: initial });
204
+ this.setValues(initial);
205
+ };
@@ -2,282 +2,27 @@ componentName: rtgl-form
2
2
  propsSchema:
3
3
  type: object
4
4
  properties:
5
- key:
6
- type: string
7
- autofocus:
8
- type: boolean
5
+ form:
6
+ type: object
9
7
  defaultValues:
10
8
  type: object
11
9
  context:
12
10
  type: object
13
- form:
14
- type: object
15
- properties:
16
- title:
17
- type: string
18
- description:
19
- type: string
20
- fields:
21
- type: array
22
- items:
23
- anyOf:
24
- - type: object
25
- properties:
26
- name:
27
- type: string
28
- label:
29
- type: string
30
- description:
31
- type: string
32
- inputType:
33
- const: input-text
34
- placeholder:
35
- type: string
36
- testId:
37
- type: string
38
- tooltip:
39
- type: object
40
- properties:
41
- content:
42
- type: string
43
- required:
44
- - name
45
- - label
46
- - inputType
47
- additionalProperties: false
48
- - type: object
49
- properties:
50
- name:
51
- type: string
52
- label:
53
- type: string
54
- description:
55
- type: string
56
- inputType:
57
- const: select
58
- placeholder:
59
- type: string
60
- noClear:
61
- type: boolean
62
- addOption:
63
- type: object
64
- properties:
65
- label:
66
- type: string
67
- options:
68
- type: array
69
- items:
70
- type: object
71
- properties:
72
- label:
73
- type: string
74
- value:
75
- type: any
76
- required:
77
- - label
78
- - value
79
- testId:
80
- type: string
81
- tooltip:
82
- type: object
83
- properties:
84
- content:
85
- type: string
86
- required:
87
- - name
88
- - label
89
- - inputType
90
- - options
91
- additionalProperties: false
92
- - type: object
93
- properties:
94
- name:
95
- type: string
96
- label:
97
- type: string
98
- description:
99
- type: string
100
- inputType:
101
- const: color-picker
102
- value:
103
- type: string
104
- testId:
105
- type: string
106
- tooltip:
107
- type: object
108
- properties:
109
- content:
110
- type: string
111
- required:
112
- - name
113
- - label
114
- - inputType
115
- additionalProperties: false
116
- - type: object
117
- properties:
118
- name:
119
- type: string
120
- label:
121
- type: string
122
- description:
123
- type: string
124
- inputType:
125
- const: slider
126
- min:
127
- type: number
128
- max:
129
- type: number
130
- step:
131
- type: number
132
- value:
133
- type: number
134
- testId:
135
- type: string
136
- tooltip:
137
- type: object
138
- properties:
139
- content:
140
- type: string
141
- required:
142
- - name
143
- - label
144
- - inputType
145
- additionalProperties: false
146
- - type: object
147
- properties:
148
- name:
149
- type: string
150
- label:
151
- type: string
152
- description:
153
- type: string
154
- inputType:
155
- const: slider-input
156
- min:
157
- type: number
158
- max:
159
- type: number
160
- step:
161
- type: number
162
- value:
163
- type: number
164
- testId:
165
- type: string
166
- tooltip:
167
- type: object
168
- properties:
169
- content:
170
- type: string
171
- required:
172
- - name
173
- - label
174
- - inputType
175
- additionalProperties: false
176
- - type: object
177
- properties:
178
- name:
179
- type: string
180
- label:
181
- type: string
182
- description:
183
- type: string
184
- inputType:
185
- const: image
186
- width:
187
- type: number
188
- height:
189
- type: number
190
- placeholder:
191
- type: string
192
- testId:
193
- type: string
194
- tooltip:
195
- type: object
196
- properties:
197
- content:
198
- type: string
199
- required:
200
- - name
201
- - label
202
- - inputType
203
- additionalProperties: false
204
- - type: object
205
- properties:
206
- name:
207
- type: string
208
- label:
209
- type: string
210
- description:
211
- type: string
212
- inputType:
213
- const: waveform
214
- width:
215
- type: number
216
- height:
217
- type: number
218
- placeholder:
219
- type: string
220
- defaultValue:
221
- type: object
222
- waveformData:
223
- type: object
224
- testId:
225
- type: string
226
- tooltip:
227
- type: object
228
- properties:
229
- content:
230
- type: string
231
- required:
232
- - name
233
- - label
234
- - inputType
235
- additionalProperties: false
236
- - type: object
237
- properties:
238
- name:
239
- type: string
240
- label:
241
- type: string
242
- description:
243
- type: string
244
- inputType:
245
- const: popover-input
246
- placeholder:
247
- type: string
248
- testId:
249
- type: string
250
- tooltip:
251
- type: object
252
- properties:
253
- content:
254
- type: string
255
- required:
256
- - name
257
- - label
258
- - inputType
259
- additionalProperties: false
260
- actions:
261
- type: object
262
- properties:
263
- buttons:
264
- type: array
265
- items:
266
- type: object
267
- properties:
268
- id:
269
- type: string
270
- content:
271
- type: string
272
- testId:
273
- type: string
274
- required:
275
- - id
276
- - content
11
+ disabled:
12
+ type: boolean
277
13
  events:
14
+ form-input: {}
278
15
  form-change: {}
279
- extra-event: {}
280
- action-click: {}
16
+ form-field-event: {}
17
+ form-action: {}
281
18
  methods:
282
19
  type: object
283
- properties: {}
20
+ properties:
21
+ getValues:
22
+ type: function
23
+ setValues:
24
+ type: function
25
+ validate:
26
+ type: function
27
+ reset:
28
+ type: function