@rettangoli/ui 0.1.2-rc9 → 0.1.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.
Files changed (66) hide show
  1. package/dist/rettangoli-iife-layout.min.js +128 -56
  2. package/dist/rettangoli-iife-ui.min.js +187 -66
  3. package/package.json +3 -2
  4. package/src/common.js +30 -2
  5. package/src/components/breadcrumb/breadcrumb.handlers.js +10 -0
  6. package/src/components/breadcrumb/breadcrumb.store.js +29 -0
  7. package/src/components/breadcrumb/breadcrumb.view.yaml +64 -0
  8. package/src/components/dropdownMenu/dropdownMenu.handlers.js +7 -6
  9. package/src/components/dropdownMenu/dropdownMenu.store.js +6 -18
  10. package/src/components/dropdownMenu/dropdownMenu.view.yaml +15 -13
  11. package/src/components/form/form.handlers.js +181 -33
  12. package/src/components/form/form.store.js +175 -21
  13. package/src/components/form/form.view.yaml +182 -27
  14. package/src/components/globalUi/globalUi.handlers.js +53 -0
  15. package/src/components/globalUi/globalUi.store.js +57 -0
  16. package/src/components/globalUi/globalUi.view.yaml +50 -0
  17. package/src/components/navbar/navbar.handlers.js +2 -1
  18. package/src/components/navbar/navbar.store.js +2 -2
  19. package/src/components/pageOutline/pageOutline.handlers.js +57 -17
  20. package/src/components/pageOutline/pageOutline.store.js +48 -3
  21. package/src/components/pageOutline/pageOutline.view.yaml +7 -5
  22. package/src/components/popoverInput/popoverInput.handlers.js +103 -0
  23. package/src/components/popoverInput/popoverInput.store.js +48 -0
  24. package/src/components/popoverInput/popoverInput.view.yaml +55 -0
  25. package/src/components/select/select.handlers.js +124 -12
  26. package/src/components/select/select.store.js +86 -20
  27. package/src/components/select/select.view.yaml +40 -10
  28. package/src/components/sidebar/sidebar.handlers.js +8 -6
  29. package/src/components/sidebar/sidebar.store.js +6 -6
  30. package/src/components/sidebar/sidebar.view.yaml +1 -1
  31. package/src/components/sliderInput/sliderInput.handlers.js +24 -6
  32. package/src/components/sliderInput/sliderInput.store.js +3 -2
  33. package/src/components/sliderInput/sliderInput.view.yaml +3 -2
  34. package/src/components/table/table.handlers.js +12 -10
  35. package/src/components/table/table.store.js +4 -4
  36. package/src/components/tabs/tabs.handlers.js +11 -0
  37. package/src/components/tabs/tabs.store.js +29 -0
  38. package/src/components/tabs/tabs.view.yaml +64 -0
  39. package/src/components/tooltip/tooltip.handlers.js +0 -0
  40. package/src/components/tooltip/tooltip.store.js +12 -0
  41. package/src/components/tooltip/tooltip.view.yaml +27 -0
  42. package/src/components/waveform/waveform.handlers.js +92 -0
  43. package/src/components/waveform/waveform.store.js +17 -0
  44. package/src/components/waveform/waveform.view.yaml +38 -0
  45. package/src/deps/createGlobalUI.js +39 -0
  46. package/src/entry-iife-layout.js +3 -0
  47. package/src/entry-iife-ui.js +4 -0
  48. package/src/index.js +7 -1
  49. package/src/primitives/button.js +10 -0
  50. package/src/primitives/colorPicker.js +13 -4
  51. package/src/primitives/dialog.js +254 -0
  52. package/src/primitives/image.js +4 -3
  53. package/src/primitives/input.js +17 -4
  54. package/src/primitives/popover.js +280 -0
  55. package/src/primitives/slider.js +14 -4
  56. package/src/primitives/svg.js +2 -0
  57. package/src/primitives/textarea.js +25 -1
  58. package/src/primitives/view.js +132 -13
  59. package/src/setup.js +7 -2
  60. package/src/styles/cursorStyles.js +38 -2
  61. package/src/components/dialog/dialog.handlers.js +0 -5
  62. package/src/components/dialog/dialog.store.js +0 -25
  63. package/src/components/dialog/dialog.view.yaml +0 -48
  64. package/src/components/popover/popover.handlers.js +0 -5
  65. package/src/components/popover/popover.store.js +0 -12
  66. package/src/components/popover/popover.view.yaml +0 -57
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@rettangoli/ui",
3
- "version": "0.1.2-rc9",
3
+ "version": "0.1.4",
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-rc16",
52
53
  "commander": "^13.1.0",
54
+ "jempl": "0.1.4-rc1",
53
55
  "js-yaml": "^4.1.0",
54
56
  "liquidjs": "^10.21.0",
55
- "@rettangoli/fe": "0.0.7-rc6",
56
57
  "snabbdom": "^3.6.2"
57
58
  }
58
59
  }
package/src/common.js CHANGED
@@ -159,14 +159,23 @@ const spacing = {
159
159
 
160
160
  function convertObjectToCssString(styleObject, selector = ':host') {
161
161
  let result = "";
162
- for (const [size, mediaQuery] of Object.entries(mediaQueries)) {
162
+ // Process in correct order for max-width media queries: default first, then largest to smallest
163
+ const orderedSizes = ["default", "xl", "lg", "md", "sm"];
164
+
165
+ for (const size of orderedSizes) {
166
+ const mediaQuery = mediaQueries[size];
167
+ if (!styleObject[size] || Object.keys(styleObject[size]).length === 0) {
168
+ continue;
169
+ }
170
+
163
171
  if (size !== "default") {
164
172
  result += `${mediaQuery} {\n`;
165
173
  }
166
174
  let cssString = "";
167
175
  for (const [key, value] of Object.entries(styleObject[size])) {
168
176
  if (value !== undefined && value !== null) {
169
- cssString += `${key}: ${value};\n`;
177
+ // Add !important to override imported styles
178
+ cssString += `${key}: ${value} !important;\n`;
170
179
  }
171
180
  }
172
181
  result += `${selector} {
@@ -180,6 +189,25 @@ function convertObjectToCssString(styleObject, selector = ':host') {
180
189
  return result;
181
190
  }
182
191
 
192
+ // Deep equality helper for comparing values (including objects)
193
+ export const deepEqual = (a, b) => {
194
+ if (a === b) return true;
195
+ if (a == null || b == null) return false;
196
+ if (typeof a !== 'object' || typeof b !== 'object') return false;
197
+
198
+ const keysA = Object.keys(a);
199
+ const keysB = Object.keys(b);
200
+
201
+ if (keysA.length !== keysB.length) return false;
202
+
203
+ for (const key of keysA) {
204
+ if (!keysB.includes(key)) return false;
205
+ if (!deepEqual(a[key], b[key])) return false;
206
+ }
207
+
208
+ return true;
209
+ };
210
+
183
211
  export {
184
212
  css,
185
213
  generateCSS,
@@ -0,0 +1,10 @@
1
+ export const handleClickItem = (deps, payload) => {
2
+ const { dispatchEvent } = deps;
3
+ const event = payload._event;
4
+ const id = event.currentTarget.dataset.id;
5
+ dispatchEvent(new CustomEvent('item-click', {
6
+ detail: {
7
+ id
8
+ }
9
+ }));
10
+ }
@@ -0,0 +1,29 @@
1
+ export const createInitialState = () => Object.freeze({});
2
+
3
+ const blacklistedAttrs = ['id', 'class', 'style', 'slot'];
4
+
5
+ const stringifyAttrs = (attrs) => {
6
+ return Object.entries(attrs).filter(([key]) => !blacklistedAttrs.includes(key)).map(([key, value]) => `${key}=${value}`).join(' ');
7
+ }
8
+
9
+ export const selectViewData = ({ props, attrs }) => {
10
+ const containerAttrString = stringifyAttrs(attrs);
11
+
12
+ const items = props.items || [];
13
+ const separator = props.separator || 'breadcrumb-arrow';
14
+
15
+ // Add separators between items, but not after the last one
16
+ const itemsWithSeparators = [];
17
+ items.forEach((item, index) => {
18
+ itemsWithSeparators.push(item);
19
+ if (index < items.length - 1) {
20
+ itemsWithSeparators.push({ isSeparator: true });
21
+ }
22
+ });
23
+
24
+ return {
25
+ containerAttrString,
26
+ items: itemsWithSeparators,
27
+ separator
28
+ };
29
+ }
@@ -0,0 +1,64 @@
1
+ elementName: rtgl-breadcrumb
2
+
3
+ viewDataSchema:
4
+ type: object
5
+ properties:
6
+ containerAttrString:
7
+ type: string
8
+ items:
9
+ type: array
10
+ items:
11
+ type: object
12
+ properties:
13
+ label:
14
+ type: string
15
+ id:
16
+ type: string
17
+ separator:
18
+ type: string
19
+
20
+ propsSchema:
21
+ type: object
22
+ properties:
23
+ items:
24
+ type: array
25
+ items:
26
+ type: object
27
+ properties:
28
+ label:
29
+ type: string
30
+ id:
31
+ type: string
32
+ separator:
33
+ type: string
34
+ default: "breadcrumb-arrow"
35
+
36
+ refs:
37
+ item-*:
38
+ eventListeners:
39
+ click:
40
+ handler: handleClickItem
41
+ events:
42
+ item-click:
43
+ type: object
44
+ properties:
45
+ item:
46
+ type: object
47
+ properties:
48
+ label:
49
+ type: string
50
+ id:
51
+ type: string
52
+ index:
53
+ type: number
54
+
55
+ template:
56
+ - rtgl-view d=h av=c g=md p=sm ${containerAttrString}:
57
+ - $for item in items:
58
+ - $if item.isSeparator:
59
+ - rtgl-svg wh=16 svg=${separator} c=mu-fg:
60
+ $elif item.id:
61
+ - rtgl-view#item-${item.id} data-id=${item.id} cur=p:
62
+ - rtgl-text s=sm c=mu-fg: "${item.label}"
63
+ $else:
64
+ - rtgl-text s=sm c=mu-fg: "${item.label}"
@@ -1,18 +1,19 @@
1
1
 
2
- export const handleClickPopoverOverlay = (e, deps) => {
2
+ export const handleClosePopover = (deps, payload) => {
3
3
  const { dispatchEvent } = deps;
4
- dispatchEvent(new CustomEvent('click-overlay'));
4
+ dispatchEvent(new CustomEvent('close'));
5
5
  }
6
6
 
7
- export const handleClickMenuItem = (e, deps) => {
7
+ export const handleClickMenuItem = (deps, payload) => {
8
8
  const { dispatchEvent } = deps;
9
- const index = parseInt(e.currentTarget.id.replace('option-', ''));
9
+ const event = payload._event;
10
+ const index = parseInt(event.currentTarget.id.replace('option-', ''));
10
11
  const item = deps.props.items[index];
11
-
12
+
12
13
  dispatchEvent(new CustomEvent('click-item', {
13
14
  detail: {
14
15
  index,
15
16
  item
16
17
  }
17
18
  }));
18
- }
19
+ }
@@ -1,25 +1,13 @@
1
1
 
2
- export const INITIAL_STATE = Object.freeze({
2
+ export const createInitialState = () => Object.freeze({
3
3
  });
4
4
 
5
- export const toViewData = ({ state, props }) => {
5
+ export const selectViewData = ({ props, attrs }) => {
6
6
  return {
7
7
  items: props.items || [],
8
- isOpen: props.isOpen || false,
9
- position: props.position || {
10
- x: 0,
11
- y: 0,
12
- },
8
+ open: !!attrs.open,
9
+ x: attrs.x,
10
+ y: attrs.y,
11
+ placement: attrs.placement
13
12
  };
14
13
  }
15
-
16
- export const selectState = ({ state }) => {
17
- return state;
18
- }
19
-
20
- export const setState = (state) => {
21
- // do doSomething
22
- }
23
-
24
-
25
-
@@ -19,28 +19,31 @@ propsSchema:
19
19
  - label
20
20
  - item
21
21
  - separator
22
- isOpen:
23
- type: boolean
24
- position:
25
- type: object
26
- properties:
27
- x:
28
- type: number
29
- y:
30
- type: number
22
+
23
+ attrsSchema:
24
+ type: object
25
+ properties:
26
+ open:
27
+ type: string
28
+ x:
29
+ type: string
30
+ y:
31
+ type: string
32
+ placement:
33
+ type: string
31
34
 
32
35
  refs:
33
36
  popover:
34
37
  eventListeners:
35
- click-overlay:
36
- handler: handleClickPopoverOverlay
38
+ close:
39
+ handler: handleClosePopover
37
40
  option-*:
38
41
  eventListeners:
39
42
  click:
40
43
  handler: handleClickMenuItem
41
44
 
42
45
  template:
43
- - rtgl-popover#popover .isOpen=isOpen .position=position:
46
+ - rtgl-popover#popover ?open=${open} x=${x} y=${y} placement=${placement}:
44
47
  - rtgl-view wh=300 g=xs slot=content bgc=background br=md:
45
48
  - $for item, i in items:
46
49
  - $if item.type == 'label':
@@ -51,4 +54,3 @@ template:
51
54
  - rtgl-text: ${item.label}
52
55
  $elif item.type == 'separator':
53
56
  - rtgl-view w=f h=1 ph=lg mv=md bgc=bo:
54
-
@@ -1,8 +1,20 @@
1
- export const handleOnMount = (deps) => {
1
+ export const handleBeforeMount = (deps) => {
2
2
  const { store, props } = deps;
3
3
  store.setFormValues(props.defaultValues);
4
4
  };
5
5
 
6
+ export const handleOnUpdate = (deps, payload) => {
7
+ const { oldAttrs, newAttrs } = payload;
8
+ const { store, props, render } = deps;
9
+
10
+ if (oldAttrs?.key === newAttrs?.key) {
11
+ return;
12
+ }
13
+
14
+ store.setFormValues(props.defaultValues);
15
+ render();
16
+ };
17
+
6
18
  const dispatchFormChange = (name, fieldValue, formValues, dispatchEvent) => {
7
19
  dispatchEvent(
8
20
  new CustomEvent("form-change", {
@@ -15,9 +27,10 @@ const dispatchFormChange = (name, fieldValue, formValues, dispatchEvent) => {
15
27
  );
16
28
  };
17
29
 
18
- export const handleActionClick = (e, deps) => {
30
+ export const handleActionClick = (deps, payload) => {
19
31
  const { store, dispatchEvent } = deps;
20
- const id = e.currentTarget.id.replace("action-", "");
32
+ const event = payload._event;
33
+ const id = event.currentTarget.id.replace("action-", "");
21
34
  dispatchEvent(
22
35
  new CustomEvent("action-click", {
23
36
  detail: {
@@ -28,63 +41,198 @@ export const handleActionClick = (e, deps) => {
28
41
  );
29
42
  };
30
43
 
31
- export const handleInputChange = (e, deps) => {
32
- const { store, dispatchEvent } = deps;
33
- const name = e.currentTarget.id.replace("input-", "");
44
+ export const handleInputChange = (deps, payload) => {
45
+ const { store, dispatchEvent, props } = deps;
46
+ const event = payload._event;
47
+ const name = event.currentTarget.id.replace("input-", "");
34
48
  // TODO fix double event
35
- if (name && e.detail.value !== undefined) {
49
+ if (name && event.detail.value !== undefined) {
36
50
  store.setFormFieldValue({
37
51
  name: name,
38
- value: e.detail.value,
52
+ value: event.detail.value,
53
+ props,
39
54
  });
40
- dispatchFormChange(name, e.detail.value, store.selectFormValues(), dispatchEvent);
55
+ dispatchFormChange(
56
+ name,
57
+ event.detail.value,
58
+ store.selectFormValues(),
59
+ dispatchEvent,
60
+ );
41
61
  }
42
62
  };
43
63
 
44
- export const handleSelectChange = (e, deps) => {
45
- const { store, dispatchEvent } = deps;
46
- const name = e.currentTarget.id.replace("select-", "");
47
- if (name && e.detail.selectedValue !== undefined) {
64
+ export const handlePopoverInputChange = (deps, payload) => {
65
+ const { store, dispatchEvent, props } = deps;
66
+ const event = payload._event;
67
+ const name = event.currentTarget.id.replace("popover-input-", "");
68
+ // TODO fix double event
69
+ if (name && event.detail.value !== undefined) {
48
70
  store.setFormFieldValue({
49
71
  name: name,
50
- value: e.detail.selectedValue,
72
+ value: event.detail.value,
73
+ props,
51
74
  });
52
- dispatchFormChange(name, e.detail.selectedValue, store.selectFormValues(), dispatchEvent);
75
+ dispatchFormChange(
76
+ name,
77
+ event.detail.value,
78
+ store.selectFormValues(),
79
+ dispatchEvent,
80
+ );
53
81
  }
54
82
  };
55
83
 
56
- export const handleColorPickerChange = (e, deps) => {
57
- const { store, dispatchEvent } = deps;
58
- const name = e.currentTarget.id.replace("colorpicker-", "");
59
- if (name && e.detail.value !== undefined) {
84
+ export const handleSelectChange = (deps, payload) => {
85
+ const { store, dispatchEvent, render, props } = deps;
86
+ const event = payload._event;
87
+ const name = event.currentTarget.id.replace("select-", "");
88
+ if (name && event.detail.selectedValue !== undefined) {
60
89
  store.setFormFieldValue({
61
90
  name: name,
62
- value: e.detail.value,
91
+ value: event.detail.selectedValue,
92
+ props,
63
93
  });
64
- dispatchFormChange(name, e.detail.value, store.selectFormValues(), dispatchEvent);
94
+ dispatchFormChange(
95
+ name,
96
+ event.detail.selectedValue,
97
+ store.selectFormValues(),
98
+ dispatchEvent,
99
+ );
100
+ render();
65
101
  }
66
102
  };
67
103
 
68
- export const handleSliderChange = (e, deps) => {
69
- const { store, dispatchEvent } = deps;
70
- const name = e.currentTarget.id.replace("slider-", "");
71
- if (name && e.detail.value !== undefined) {
104
+ export const handleColorPickerChange = (deps, payload) => {
105
+ const { store, dispatchEvent, props } = deps;
106
+ const event = payload._event;
107
+ const name = event.currentTarget.id.replace("colorpicker-", "");
108
+ if (name && event.detail.value !== undefined) {
72
109
  store.setFormFieldValue({
73
110
  name: name,
74
- value: e.detail.value,
111
+ value: event.detail.value,
112
+ props,
75
113
  });
76
- dispatchFormChange(name, e.detail.value, store.selectFormValues(), dispatchEvent);
114
+ dispatchFormChange(
115
+ name,
116
+ event.detail.value,
117
+ store.selectFormValues(),
118
+ dispatchEvent,
119
+ );
77
120
  }
78
121
  };
79
122
 
80
- export const handleSliderInputChange = (e, deps) => {
81
- const { store, dispatchEvent } = deps;
82
- const name = e.currentTarget.id.replace("slider-input-", "");
83
- if (name && e.detail.value !== undefined) {
123
+ export const handleSliderChange = (deps, payload) => {
124
+ const { store, dispatchEvent, props } = deps;
125
+ const event = payload._event;
126
+ const name = event.currentTarget.id.replace("slider-", "");
127
+ if (name && event.detail.value !== undefined) {
128
+ store.setFormFieldValue({
129
+ name: name,
130
+ value: event.detail.value,
131
+ props,
132
+ });
133
+ dispatchFormChange(
134
+ name,
135
+ event.detail.value,
136
+ store.selectFormValues(),
137
+ dispatchEvent,
138
+ );
139
+ }
140
+ };
141
+
142
+ export const handleSliderInputChange = (deps, payload) => {
143
+ const { store, dispatchEvent, props } = deps;
144
+ const event = payload._event;
145
+ const name = event.currentTarget.id.replace("slider-input-", "");
146
+ if (name && event.detail.value !== undefined) {
84
147
  store.setFormFieldValue({
85
148
  name: name,
86
- value: e.detail.value,
149
+ value: event.detail.value,
150
+ props,
151
+ });
152
+ dispatchFormChange(
153
+ name,
154
+ event.detail.value,
155
+ store.selectFormValues(),
156
+ dispatchEvent,
157
+ );
158
+ }
159
+ };
160
+
161
+ export const handleImageClick = (deps, payload) => {
162
+ const event = payload._event;
163
+ if (event.type === "contextmenu") {
164
+ event.preventDefault();
165
+ }
166
+ const { dispatchEvent } = deps;
167
+ const name = event.currentTarget.id.replace("image-", "");
168
+ dispatchEvent(
169
+ new CustomEvent("extra-event", {
170
+ detail: {
171
+ name: name,
172
+ x: event.clientX,
173
+ y: event.clientY,
174
+ trigger: event.type,
175
+ },
176
+ }),
177
+ );
178
+ };
179
+
180
+ export const handleWaveformClick = (deps, payload) => {
181
+ const event = payload._event;
182
+ if (event.type === "contextmenu") {
183
+ event.preventDefault();
184
+ }
185
+ const { dispatchEvent } = deps;
186
+ const name = event.currentTarget.id.replace("waveform-", "");
187
+ dispatchEvent(
188
+ new CustomEvent("extra-event", {
189
+ detail: {
190
+ name: name,
191
+ x: event.clientX,
192
+ y: event.clientY,
193
+ trigger: event.type,
194
+ },
195
+ }),
196
+ );
197
+ };
198
+
199
+ export const handleSelectAddOption = (deps, payload) => {
200
+ const { store, dispatchEvent } = deps;
201
+ const event = payload._event;
202
+ const name = event.currentTarget.id.replace("select-", "");
203
+ dispatchEvent(
204
+ new CustomEvent("action-click", {
205
+ detail: {
206
+ actionId: 'select-options-add',
207
+ name: name,
208
+ formValues: store.selectFormValues(),
209
+ },
210
+ }),
211
+ );
212
+ };
213
+
214
+ export const handleTooltipMouseEnter = (deps, payload) => {
215
+ const { store, render, props } = deps;
216
+ const event = payload._event;
217
+ const fieldName = event.currentTarget.id.replace('tooltip-icon-', '');
218
+
219
+ // Find the field with matching name to get tooltip content
220
+ const form = props.form;
221
+ const field = form.fields.find(f => f.name === fieldName);
222
+
223
+ if (field && field.tooltip) {
224
+ const rect = event.currentTarget.getBoundingClientRect();
225
+ store.showTooltip({
226
+ x: rect.left + rect.width / 2,
227
+ y: rect.top - 8,
228
+ content: field.tooltip.content
87
229
  });
88
- dispatchFormChange(name, e.detail.value, store.selectFormValues(), dispatchEvent);
230
+ render();
89
231
  }
90
232
  };
233
+
234
+ export const handleTooltipMouseLeave = (deps, payload) => {
235
+ const { store, render } = deps;
236
+ store.hideTooltip();
237
+ render();
238
+ };