@rettangoli/ui 0.1.2-rc8 → 0.1.3

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 (68) 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 +5 -3
  4. package/src/cli/buildSvg.js +86 -0
  5. package/src/cli/index.js +1 -0
  6. package/src/common.js +30 -2
  7. package/src/components/breadcrumb/breadcrumb.handlers.js +9 -0
  8. package/src/components/breadcrumb/breadcrumb.store.js +29 -0
  9. package/src/components/breadcrumb/breadcrumb.view.yaml +64 -0
  10. package/src/components/dropdownMenu/dropdownMenu.handlers.js +6 -6
  11. package/src/components/dropdownMenu/dropdownMenu.store.js +6 -18
  12. package/src/components/dropdownMenu/dropdownMenu.view.yaml +15 -13
  13. package/src/components/form/form.handlers.js +170 -33
  14. package/src/components/form/form.store.js +175 -21
  15. package/src/components/form/form.view.yaml +182 -27
  16. package/src/components/globalUi/globalUi.handlers.js +51 -0
  17. package/src/components/globalUi/globalUi.store.js +57 -0
  18. package/src/components/globalUi/globalUi.view.yaml +50 -0
  19. package/src/components/navbar/navbar.handlers.js +1 -1
  20. package/src/components/navbar/navbar.store.js +2 -2
  21. package/src/components/pageOutline/pageOutline.handlers.js +57 -17
  22. package/src/components/pageOutline/pageOutline.store.js +48 -3
  23. package/src/components/pageOutline/pageOutline.view.yaml +7 -5
  24. package/src/components/popoverInput/popoverInput.handlers.js +99 -0
  25. package/src/components/popoverInput/popoverInput.store.js +48 -0
  26. package/src/components/popoverInput/popoverInput.view.yaml +55 -0
  27. package/src/components/select/select.handlers.js +120 -12
  28. package/src/components/select/select.store.js +86 -20
  29. package/src/components/select/select.view.yaml +40 -10
  30. package/src/components/sidebar/sidebar.handlers.js +6 -6
  31. package/src/components/sidebar/sidebar.store.js +6 -6
  32. package/src/components/sidebar/sidebar.view.yaml +1 -1
  33. package/src/components/sliderInput/sliderInput.handlers.js +23 -6
  34. package/src/components/sliderInput/sliderInput.store.js +3 -2
  35. package/src/components/sliderInput/sliderInput.view.yaml +3 -2
  36. package/src/components/table/table.handlers.js +10 -10
  37. package/src/components/table/table.store.js +4 -4
  38. package/src/components/tabs/tabs.handlers.js +10 -0
  39. package/src/components/tabs/tabs.store.js +29 -0
  40. package/src/components/tabs/tabs.view.yaml +64 -0
  41. package/src/components/tooltip/tooltip.handlers.js +0 -0
  42. package/src/components/tooltip/tooltip.store.js +12 -0
  43. package/src/components/tooltip/tooltip.view.yaml +27 -0
  44. package/src/components/waveform/waveform.handlers.js +92 -0
  45. package/src/components/waveform/waveform.store.js +17 -0
  46. package/src/components/waveform/waveform.view.yaml +38 -0
  47. package/src/deps/createGlobalUI.js +39 -0
  48. package/src/entry-iife-layout.js +3 -0
  49. package/src/entry-iife-ui.js +4 -0
  50. package/src/index.js +7 -1
  51. package/src/primitives/button.js +10 -0
  52. package/src/primitives/colorPicker.js +13 -4
  53. package/src/primitives/dialog.js +254 -0
  54. package/src/primitives/image.js +4 -3
  55. package/src/primitives/input.js +17 -4
  56. package/src/primitives/popover.js +280 -0
  57. package/src/primitives/slider.js +14 -4
  58. package/src/primitives/svg.js +2 -0
  59. package/src/primitives/textarea.js +25 -1
  60. package/src/primitives/view.js +132 -13
  61. package/src/setup.js +7 -2
  62. package/src/styles/cursorStyles.js +38 -2
  63. package/src/components/dialog/dialog.handlers.js +0 -5
  64. package/src/components/dialog/dialog.store.js +0 -25
  65. package/src/components/dialog/dialog.view.yaml +0 -48
  66. package/src/components/popover/popover.handlers.js +0 -5
  67. package/src/components/popover/popover.store.js +0 -12
  68. 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-rc8",
3
+ "version": "0.1.3",
4
4
  "description": "A UI component library for building web interfaces.",
5
5
  "main": "dist/rettangoli-esm.min.js",
6
6
  "type": "module",
@@ -9,7 +9,8 @@
9
9
  "src"
10
10
  ],
11
11
  "exports": {
12
- ".": "./src/index.js"
12
+ ".": "./src/index.js",
13
+ "./cli": "./src/cli/index.js"
13
14
  },
14
15
  "module": "./src/index.js",
15
16
  "repository": {
@@ -48,10 +49,11 @@
48
49
  "homepage": "https://github.com/yuusoft-org/rettangoli#readme",
49
50
  "dependencies": {
50
51
  "@floating-ui/dom": "^1.6.13",
52
+ "@rettangoli/fe": "0.0.7-rc16",
51
53
  "commander": "^13.1.0",
54
+ "jempl": "0.1.4-rc1",
52
55
  "js-yaml": "^4.1.0",
53
56
  "liquidjs": "^10.21.0",
54
- "@rettangoli/fe": "0.0.7-rc4",
55
57
  "snabbdom": "^3.6.2"
56
58
  }
57
59
  }
@@ -0,0 +1,86 @@
1
+ import { readFileSync, writeFileSync, readdirSync, statSync } from 'node:fs';
2
+ import { join, basename } from 'node:path';
3
+
4
+ function getAllSvgFiles(dir) {
5
+ const svgFiles = [];
6
+
7
+ function traverse(currentDir) {
8
+ const files = readdirSync(currentDir);
9
+
10
+ for (const file of files) {
11
+ const fullPath = join(currentDir, file);
12
+ const stats = statSync(fullPath);
13
+
14
+ if (stats.isDirectory()) {
15
+ traverse(fullPath);
16
+ } else if (file.endsWith('.svg')) {
17
+ svgFiles.push(fullPath);
18
+ }
19
+ }
20
+ }
21
+
22
+ traverse(dir);
23
+ return svgFiles;
24
+ }
25
+
26
+ function removeFrontmatter(content) {
27
+ // Look for a line containing only '---'
28
+ const lines = content.split('\n');
29
+
30
+ for (let i = 0; i < lines.length; i++) {
31
+ if (lines[i].trim() === '---') {
32
+ // Found the separator, return everything after it
33
+ return lines.slice(i + 1).join('\n').trim();
34
+ }
35
+ }
36
+
37
+ // No frontmatter separator found, return original content
38
+ return content;
39
+ }
40
+
41
+ const buildSvgIcons = (options) => {
42
+ const { dir, outfile } = options;
43
+
44
+ if (!dir || !outfile) {
45
+ console.error('Error: Both dir and outfile options are required');
46
+ return;
47
+ }
48
+
49
+ console.log(`Scanning for SVG files in: ${dir}`);
50
+
51
+ const svgFiles = getAllSvgFiles(dir);
52
+
53
+ if (svgFiles.length === 0) {
54
+ console.log('No SVG files found');
55
+ return;
56
+ }
57
+
58
+ console.log(`Found ${svgFiles.length} SVG files`);
59
+
60
+ const icons = {};
61
+
62
+ for (const filePath of svgFiles) {
63
+ const fileName = basename(filePath, '.svg');
64
+ let content = readFileSync(filePath, 'utf8');
65
+
66
+ content = removeFrontmatter(content);
67
+
68
+ content = content.replace(/\n/g, ' ').replace(/\s+/g, ' ').trim();
69
+
70
+ icons[fileName] = content;
71
+ }
72
+
73
+ // Convert to custom format with single quotes for keys and backticks for values
74
+ const iconEntries = Object.entries(icons).map(([key, value]) => {
75
+ return ` '${key}': \`${value}\``;
76
+ });
77
+
78
+ const output = `window.rtglIcons = {\n${iconEntries.join(',\n')}\n};`;
79
+
80
+ writeFileSync(outfile, output);
81
+
82
+ console.log(`SVG icons written to: ${outfile}`);
83
+ console.log(`Total icons: ${Object.keys(icons).length}`);
84
+ };
85
+
86
+ export default buildSvgIcons;
@@ -0,0 +1 @@
1
+ export { default as buildSvg } from './buildSvg.js';
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,9 @@
1
+ export const handleClickItem = (deps, event) => {
2
+ const { dispatchEvent } = deps;
3
+ const id = event.currentTarget.dataset.id;
4
+ dispatchEvent(new CustomEvent('item-click', {
5
+ detail: {
6
+ id
7
+ }
8
+ }));
9
+ }
@@ -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,18 @@
1
1
 
2
- export const handleClickPopoverOverlay = (e, deps) => {
2
+ export const handleClosePopover = (deps, event) => {
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, event) => {
8
8
  const { dispatchEvent } = deps;
9
- const index = parseInt(e.currentTarget.id.replace('option-', ''));
9
+ const index = parseInt(event.currentTarget.id.replace('option-', ''));
10
10
  const item = deps.props.items[index];
11
-
11
+
12
12
  dispatchEvent(new CustomEvent('click-item', {
13
13
  detail: {
14
14
  index,
15
15
  item
16
16
  }
17
17
  }));
18
- }
18
+ }
@@ -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 = (changes, deps) => {
7
+ const { oldAttrs, newAttrs } = changes;
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,9 @@ const dispatchFormChange = (name, fieldValue, formValues, dispatchEvent) => {
15
27
  );
16
28
  };
17
29
 
18
- export const handleActionClick = (e, deps) => {
30
+ export const handleActionClick = (deps, event) => {
19
31
  const { store, dispatchEvent } = deps;
20
- const id = e.currentTarget.id.replace("action-", "");
32
+ const id = event.currentTarget.id.replace("action-", "");
21
33
  dispatchEvent(
22
34
  new CustomEvent("action-click", {
23
35
  detail: {
@@ -28,63 +40,188 @@ export const handleActionClick = (e, deps) => {
28
40
  );
29
41
  };
30
42
 
31
- export const handleInputChange = (e, deps) => {
32
- const { store, dispatchEvent } = deps;
33
- const name = e.currentTarget.id.replace("input-", "");
43
+ export const handleInputChange = (deps, event) => {
44
+ const { store, dispatchEvent, props } = deps;
45
+ const name = event.currentTarget.id.replace("input-", "");
34
46
  // TODO fix double event
35
- if (name && e.detail.value !== undefined) {
47
+ if (name && event.detail.value !== undefined) {
36
48
  store.setFormFieldValue({
37
49
  name: name,
38
- value: e.detail.value,
50
+ value: event.detail.value,
51
+ props,
39
52
  });
40
- dispatchFormChange(name, e.detail.value, store.selectFormValues(), dispatchEvent);
53
+ dispatchFormChange(
54
+ name,
55
+ event.detail.value,
56
+ store.selectFormValues(),
57
+ dispatchEvent,
58
+ );
41
59
  }
42
60
  };
43
61
 
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) {
62
+ export const handlePopoverInputChange = (deps, event) => {
63
+ const { store, dispatchEvent, props } = deps;
64
+ const name = event.currentTarget.id.replace("popover-input-", "");
65
+ // TODO fix double event
66
+ if (name && event.detail.value !== undefined) {
48
67
  store.setFormFieldValue({
49
68
  name: name,
50
- value: e.detail.selectedValue,
69
+ value: event.detail.value,
70
+ props,
51
71
  });
52
- dispatchFormChange(name, e.detail.selectedValue, store.selectFormValues(), dispatchEvent);
72
+ dispatchFormChange(
73
+ name,
74
+ event.detail.value,
75
+ store.selectFormValues(),
76
+ dispatchEvent,
77
+ );
53
78
  }
54
79
  };
55
80
 
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) {
81
+ export const handleSelectChange = (deps, event) => {
82
+ const { store, dispatchEvent, render, props } = deps;
83
+ const name = event.currentTarget.id.replace("select-", "");
84
+ if (name && event.detail.selectedValue !== undefined) {
60
85
  store.setFormFieldValue({
61
86
  name: name,
62
- value: e.detail.value,
87
+ value: event.detail.selectedValue,
88
+ props,
63
89
  });
64
- dispatchFormChange(name, e.detail.value, store.selectFormValues(), dispatchEvent);
90
+ dispatchFormChange(
91
+ name,
92
+ event.detail.selectedValue,
93
+ store.selectFormValues(),
94
+ dispatchEvent,
95
+ );
96
+ render();
65
97
  }
66
98
  };
67
99
 
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) {
100
+ export const handleColorPickerChange = (deps, event) => {
101
+ const { store, dispatchEvent, props } = deps;
102
+ const name = event.currentTarget.id.replace("colorpicker-", "");
103
+ if (name && event.detail.value !== undefined) {
72
104
  store.setFormFieldValue({
73
105
  name: name,
74
- value: e.detail.value,
106
+ value: event.detail.value,
107
+ props,
75
108
  });
76
- dispatchFormChange(name, e.detail.value, store.selectFormValues(), dispatchEvent);
109
+ dispatchFormChange(
110
+ name,
111
+ event.detail.value,
112
+ store.selectFormValues(),
113
+ dispatchEvent,
114
+ );
77
115
  }
78
116
  };
79
117
 
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) {
118
+ export const handleSliderChange = (deps, event) => {
119
+ const { store, dispatchEvent, props } = deps;
120
+ const name = event.currentTarget.id.replace("slider-", "");
121
+ if (name && event.detail.value !== undefined) {
122
+ store.setFormFieldValue({
123
+ name: name,
124
+ value: event.detail.value,
125
+ props,
126
+ });
127
+ dispatchFormChange(
128
+ name,
129
+ event.detail.value,
130
+ store.selectFormValues(),
131
+ dispatchEvent,
132
+ );
133
+ }
134
+ };
135
+
136
+ export const handleSliderInputChange = (deps, event) => {
137
+ const { store, dispatchEvent, props } = deps;
138
+ const name = event.currentTarget.id.replace("slider-input-", "");
139
+ if (name && event.detail.value !== undefined) {
84
140
  store.setFormFieldValue({
85
141
  name: name,
86
- value: e.detail.value,
142
+ value: event.detail.value,
143
+ props,
144
+ });
145
+ dispatchFormChange(
146
+ name,
147
+ event.detail.value,
148
+ store.selectFormValues(),
149
+ dispatchEvent,
150
+ );
151
+ }
152
+ };
153
+
154
+ export const handleImageClick = (deps, event) => {
155
+ if (event.type === "contextmenu") {
156
+ event.preventDefault();
157
+ }
158
+ const { dispatchEvent } = deps;
159
+ const name = event.currentTarget.id.replace("image-", "");
160
+ dispatchEvent(
161
+ new CustomEvent("extra-event", {
162
+ detail: {
163
+ name: name,
164
+ x: event.clientX,
165
+ y: event.clientY,
166
+ trigger: event.type,
167
+ },
168
+ }),
169
+ );
170
+ };
171
+
172
+ export const handleWaveformClick = (deps, event) => {
173
+ if (event.type === "contextmenu") {
174
+ event.preventDefault();
175
+ }
176
+ const { dispatchEvent } = deps;
177
+ const name = event.currentTarget.id.replace("waveform-", "");
178
+ dispatchEvent(
179
+ new CustomEvent("extra-event", {
180
+ detail: {
181
+ name: name,
182
+ x: event.clientX,
183
+ y: event.clientY,
184
+ trigger: event.type,
185
+ },
186
+ }),
187
+ );
188
+ };
189
+
190
+ export const handleSelectAddOption = (deps, event) => {
191
+ const { store, dispatchEvent } = deps;
192
+ const name = event.currentTarget.id.replace("select-", "");
193
+ dispatchEvent(
194
+ new CustomEvent("action-click", {
195
+ detail: {
196
+ actionId: 'select-options-add',
197
+ name: name,
198
+ formValues: store.selectFormValues(),
199
+ },
200
+ }),
201
+ );
202
+ };
203
+
204
+ export const handleTooltipMouseEnter = (deps, event) => {
205
+ const { store, render, props } = deps;
206
+ const fieldName = event.currentTarget.id.replace('tooltip-icon-', '');
207
+
208
+ // Find the field with matching name to get tooltip content
209
+ const form = props.form;
210
+ const field = form.fields.find(f => f.name === fieldName);
211
+
212
+ if (field && field.tooltip) {
213
+ const rect = event.currentTarget.getBoundingClientRect();
214
+ store.showTooltip({
215
+ x: rect.left + rect.width / 2,
216
+ y: rect.top - 8,
217
+ content: field.tooltip.content
87
218
  });
88
- dispatchFormChange(name, e.detail.value, store.selectFormValues(), dispatchEvent);
219
+ render();
89
220
  }
90
221
  };
222
+
223
+ export const handleTooltipMouseLeave = (deps, event) => {
224
+ const { store, render } = deps;
225
+ store.hideTooltip();
226
+ render();
227
+ };