@rettangoli/ui 0.1.12 → 0.1.14

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.12",
3
+ "version": "0.1.14",
4
4
  "description": "A UI component library for building web interfaces.",
5
5
  "main": "dist/rettangoli-esm.min.js",
6
6
  "type": "module",
@@ -1,17 +1,72 @@
1
+
2
+ const updateAttributes = ({ form, defaultValues = {}, refs }) => {
3
+ const { fields = [] } = form;
4
+ fields.forEach((field) => {
5
+ const ref = refs[`field-${field.name}`]?.elm;
6
+
7
+ if (!ref) {
8
+ return;
9
+ }
10
+
11
+ if (['inputText', 'colorPicker', 'slider', 'slider-input', 'popover-input'].includes(field.inputType)) {
12
+ const defaultValue = defaultValues[field.name];
13
+ if (defaultValue !== undefined) {
14
+ ref.setAttribute('value', defaultValue)
15
+ }
16
+ }
17
+ if (field.inputType === 'inputText' && field.placeholder) {
18
+ const currentPlaceholder = ref.getAttribute('placeholder')
19
+ if (currentPlaceholder !== field.placeholder) {
20
+ ref.setAttribute('placeholder', field.placeholder)
21
+ }
22
+ }
23
+ if (field.inputType === 'select' && field.placeholder) {
24
+ if (ref.placeholder !== field.placeholder) {
25
+ ref.placeholder = field.placeholder;
26
+ }
27
+ }
28
+ if (field.inputType === 'select') {
29
+ if (field.placeholder !== ref.getAttribute('placeholder')) {
30
+ if (field.placeholder !== undefined) {
31
+ ref.setAttribute('placeholder', field.placeholder)
32
+ } else {
33
+ ref.removeAttribute('placeholder');
34
+ }
35
+ ref.render();
36
+ }
37
+
38
+ const defaultValue = defaultValues[field.name]
39
+ if (defaultValue !== ref.selectedValue) {
40
+ ref.selectedValue = defaultValue;
41
+ ref.render();
42
+ }
43
+ }
44
+ })
45
+ }
46
+
1
47
  export const handleBeforeMount = (deps) => {
2
48
  const { store, props } = deps;
3
49
  store.setFormValues(props.defaultValues);
4
50
  };
5
51
 
52
+ export const handleAfterMount = (deps) => {
53
+ const { props, getRefIds, render } = deps;
54
+ const { form = {}, defaultValues } = props;
55
+ const refs = getRefIds();
56
+ updateAttributes({ form, defaultValues, refs });
57
+ render();
58
+ };
59
+
6
60
  export const handleOnUpdate = (deps, payload) => {
7
61
  const { oldAttrs, newAttrs, newProps } = payload;
8
- const { store, render } = deps;
9
-
10
- if (oldAttrs?.key === newAttrs?.key) {
62
+ const { store, render, getRefIds } = deps;
63
+ const { form = {}, defaultValues } = newProps;
64
+ if (oldAttrs?.key !== newAttrs?.key) {
65
+ const refs = getRefIds();
66
+ updateAttributes({ form, defaultValues, refs });
11
67
  return;
12
68
  }
13
-
14
- store.setFormValues(newProps.defaultValues);
69
+ store.setFormValues(defaultValues);
15
70
  render();
16
71
  };
17
72
 
@@ -11,7 +11,7 @@ const encode = (input) => {
11
11
  };
12
12
  return text.replace(/[&<>"']/g, char => map[char]);
13
13
  }
14
- if (input === undefined || input === null) {
14
+ if (input === undefined || input === null || input === "") {
15
15
  return ""
16
16
  }
17
17
  return `"${escapeHtml(String(input))}"`;
@@ -89,12 +89,13 @@ const stringifyAttrs = (attrs) => {
89
89
  .join(" ");
90
90
  };
91
91
 
92
- export const selectForm = ({ state, props }) => {
93
- const { form } = props;
92
+ export const selectForm = ({ props }) => {
93
+ const { form = {} } = props;
94
94
  const { context } = props;
95
95
 
96
96
  if (context) {
97
- return parseAndRender(form, context);
97
+ const result = parseAndRender(form, context);
98
+ return result
98
99
  }
99
100
 
100
101
  return form;
@@ -103,23 +104,15 @@ export const selectForm = ({ state, props }) => {
103
104
 
104
105
  export const selectViewData = ({ state, props, attrs }) => {
105
106
  const containerAttrString = stringifyAttrs(attrs);
106
- const defaultValues = state.formValues;
107
107
 
108
108
  const form = selectForm({ state, props });
109
109
  const fields = structuredClone(form.fields || []);
110
110
  fields.forEach((field) => {
111
111
  // Use formValues from state if available, otherwise fall back to defaultValues from props
112
- const defaultValue = get(state.formValues, field.name) ?? get(defaultValues, field.name)
113
- if (["popover-input", "select", "read-only-text"].includes(field.inputType)) {
112
+ const defaultValue = get(state.formValues, field.name)
113
+ if (["read-only-text"].includes(field.inputType)) {
114
114
  field.defaultValue = defaultValue
115
- } else {
116
- field.defaultValue = encode(defaultValue);
117
115
  }
118
-
119
- if (["inputText"].includes(field.inputType)) {
120
- field.placeholder = encode(field.placeholder)
121
- }
122
-
123
116
  if (field.inputType === "image") {
124
117
  const src = field.src;
125
118
  // Only set imageSrc if src exists and is not empty
@@ -268,26 +268,18 @@ refs:
268
268
  handler: handleTooltipMouseEnter
269
269
  mouseleave:
270
270
  handler: handleTooltipMouseLeave
271
- input-*:
271
+ field-*:
272
272
  eventListeners:
273
273
  input-change:
274
274
  handler: handleInputChange
275
- select-*:
276
- eventListeners:
277
275
  select-change:
278
276
  handler: handleSelectChange
279
277
  add-option-selected:
280
278
  handler: handleSelectAddOption
281
- colorpicker-*:
282
- eventListeners:
283
279
  colorpicker-change:
284
280
  handler: handleColorPickerChange
285
- slider-*:
286
- eventListeners:
287
281
  slider-change:
288
282
  handler: handleSliderChange
289
- slider-input-*:
290
- eventListeners:
291
283
  slider-input-value-change:
292
284
  handler: handleSliderInputChange
293
285
  image-*:
@@ -329,29 +321,29 @@ template:
329
321
  - $if field.inputType == "read-only-text":
330
322
  - rtgl-text s=sm: ${field.defaultValue}
331
323
  - $if field.inputType == "inputText":
332
- - rtgl-input#input-${field.name} key=${key} w=f placeholder=${field.placeholder} value=${field.defaultValue}:
324
+ - rtgl-input#field-${field.name} w=f:
333
325
  - $if field.inputType == "popover-input":
334
- - rtgl-popover-input#popover-input-${field.name} label="${field.label}" .defaultValue=fields[${i}].defaultValue:
326
+ - rtgl-popover-input#field-${field.name} label="${field.label}":
335
327
  - $if field.inputType == "select":
336
- - rtgl-select#select-${field.name} key=${key} w=f .options=fields[${i}].options .placeholder=fields[${i}].placeholder .selectedValue=fields[${i}].defaultValue ?no-clear=fields[${i}].noClear .addOption=fields[${i}].addOption:
328
+ - rtgl-select#field-${field.name} key=${key} w=f .options=fields[${i}].options ?no-clear=fields[${i}].noClear .addOption=fields[${i}].addOption:
337
329
  - $if field.inputType == "colorPicker":
338
- - rtgl-color-picker#colorpicker-${field.name} key=${key} value=${field.defaultValue}:
330
+ - rtgl-color-picker#field-${field.name} key=${key}:
339
331
  - $if field.inputType == "slider":
340
- - rtgl-slider#slider-${field.name} key=${key} w=f min=${field.min} max=${field.max} step=${field.step} value=${field.defaultValue}:
332
+ - rtgl-slider#field-${field.name} key=${key} w=f min=${field.min} max=${field.max} step=${field.step}:
341
333
  - $if field.inputType == "slider-input":
342
- - rtgl-slider-input#slider-input-${field.name} key=${key} w=f min=${field.min} max=${field.max} step=${field.step} defaultValue=${field.defaultValue}:
334
+ - rtgl-slider-input#field-${field.name} w=f min=${field.min} max=${field.max} step=${field.step}:
343
335
  - $if field.inputType == "image" && field.imageSrc:
344
336
  - rtgl-image#image-${field.name} src=${field.imageSrc} w=${field.width} h=${field.height} cur=p:
345
337
  - $if field.inputType == "image" && !field.imageSrc:
346
- - rtgl-view#image-${field.name} w=${field.width} h=${field.height} bc=ac bw=sm ah=c av=c cur=p p=md:
338
+ - rtgl-view#field-${field.name} w=${field.width} h=${field.height} bc=ac bw=sm ah=c av=c cur=p p=md:
347
339
  - rtgl-text c=mu-fg ta=c: ${field.placeholderText}
348
340
  - $if field.inputType == "waveform" && field.waveformData:
349
- - rtgl-waveform#waveform-${field.name} .waveformData=fields[${i}].waveformData w=${field.width} h=${field.height} cur=p:
341
+ - rtgl-waveform#field-${field.name} .waveformData=fields[${i}].waveformData w=${field.width} h=${field.height} cur=p:
350
342
  - $if field.inputType == "waveform" && !field.waveformData:
351
- - rtgl-view#waveform-${field.name} w=${field.width} h=${field.height} bc=ac bw=sm ah=c av=c cur=p p=md:
343
+ - rtgl-view#field-${field.name} w=${field.width} h=${field.height} bc=ac bw=sm ah=c av=c cur=p p=md:
352
344
  - rtgl-text c=mu-fg ta=c: ${field.placeholder}
353
345
  - $if field.inputType == "slot":
354
- - 'slot#slot-${field.slotName} name=${field.slot} style="display: contents;"':
346
+ - 'slot#field-${field.slotName} name=${field.slot} style="display: contents;"':
355
347
  - rtgl-view g=sm w=f:
356
348
  - rtgl-view d=h ah=e g=sm w=f:
357
349
  - $for button, i in actions.buttons:
@@ -1,14 +1,14 @@
1
1
  export const handleDialogClose = (deps, payload) => {
2
2
  const { store, render } = deps;
3
3
 
4
- store.closeDialog();
4
+ store.closeAll();
5
5
  render();
6
6
  };
7
7
 
8
8
  export const handleConfirm = (deps, payload) => {
9
9
  const { store, render, globalUI } = deps;
10
10
 
11
- store.closeDialog();
11
+ store.closeAll();
12
12
  render();
13
13
  globalUI.emit('event', true);
14
14
  };
@@ -16,7 +16,7 @@ export const handleConfirm = (deps, payload) => {
16
16
  export const handleCancel = (deps, payload) => {
17
17
  const { store, render, globalUI } = deps;
18
18
 
19
- store.closeDialog();
19
+ store.closeAll();
20
20
  render();
21
21
  globalUI.emit('event', false);
22
22
  };
@@ -25,7 +25,7 @@ export const handleDropdownClose = (deps, payload) => {
25
25
  const { store, render, globalUI } = deps;
26
26
 
27
27
  // Always process close events - the framework will handle if it's already closed
28
- store.closeDialog();
28
+ store.closeAll();
29
29
  render();
30
30
  globalUI.emit('event', null);
31
31
  };
@@ -36,7 +36,7 @@ export const handleDropdownItemClick = (deps, payload) => {
36
36
  const { index, item } = event.detail;
37
37
 
38
38
  // Always process click events - the framework will handle if it's already closed
39
- store.closeDialog();
39
+ store.closeAll();
40
40
  render();
41
41
  globalUI.emit('event', { index, item });
42
42
  };
@@ -61,7 +61,7 @@ export const showAlert = (deps, payload) => {
61
61
 
62
62
  // Close any existing dialog/dropdown menu first
63
63
  if (store.selectIsOpen()) {
64
- store.closeDialog();
64
+ store.closeAll();
65
65
  render();
66
66
  }
67
67
 
@@ -75,7 +75,7 @@ export const showConfirm = async (deps, payload) => {
75
75
 
76
76
  // Close any existing dialog/dropdown menu first
77
77
  if (store.selectIsOpen()) {
78
- store.closeDialog();
78
+ store.closeAll();
79
79
  render();
80
80
  }
81
81
 
@@ -113,7 +113,7 @@ export const showDropdownMenu = async (deps, payload) => {
113
113
 
114
114
  // Close any existing dialog/dropdown menu first
115
115
  if (store.selectIsOpen()) {
116
- store.closeDialog();
116
+ store.closeAll();
117
117
  render();
118
118
  }
119
119
 
@@ -126,4 +126,26 @@ export const showDropdownMenu = async (deps, payload) => {
126
126
  resolve(result)
127
127
  });
128
128
  });
129
+ };
130
+
131
+ /**
132
+ * Triggers a global event to close all UI components.
133
+ * This function will:
134
+ * 1. Close any open global UI dialogs/dropdowns managed by the store
135
+ * 2. Emit a global 'closeAll' event that other components can listen to
136
+ *
137
+ * @param {Object} deps - Dependencies object
138
+ * @param {Object} deps.store - The globalUI store instance
139
+ * @param {Function} deps.render - Function to trigger re-rendering
140
+ * @param {Object} deps.globalUI - The globalUI event emitter
141
+ * @returns {void}
142
+ */
143
+ export const closeAll = (deps) => {
144
+ const { store, render } = deps;
145
+
146
+ // Close global UI dialogs/dropdowns
147
+ if (store.selectIsOpen()) {
148
+ store.closeAll();
149
+ render();
150
+ }
129
151
  };
@@ -66,7 +66,7 @@ export const setDropdownConfig = (state, options) => {
66
66
  state.isOpen = true;
67
67
  };
68
68
 
69
- export const closeDialog = (state) => {
69
+ export const closeAll = (state) => {
70
70
  state.isOpen = false;
71
71
  state.uiType = "dialog"; // Reset to default type
72
72
  };
@@ -1,17 +1,18 @@
1
1
  export const handleBeforeMount = (deps) => {
2
- const { store, props } = deps;
2
+ const { store, attrs } = deps;
3
3
 
4
- if (props.value !== undefined || props.defaultValue !== undefined) {
5
- store.setValue(props.value || props.defaultValue || '');
4
+ if (attrs.value !== undefined) {
5
+ store.setValue(attrs.value || '');
6
6
  }
7
7
  }
8
8
 
9
9
  export const handleOnUpdate = (deps, payload) => {
10
- const { oldProps, newProps} = payload
11
- const { store, props, render } = deps;
10
+ const { oldAttrs, newAttrs } = payload;
11
+ const { store, render } = deps;
12
12
 
13
- if (oldProps.defaultValue !== newProps.defaultValue) {
14
- store.setValue(props.defaultValue || '');
13
+ if (oldAttrs?.value !== newAttrs?.value) {
14
+ const value = newAttrs?.value ?? '';
15
+ store.setValue(value);
15
16
  }
16
17
 
17
18
  render();
@@ -8,16 +8,15 @@ export const createInitialState = () => Object.freeze({
8
8
  tempValue: '',
9
9
  });
10
10
 
11
- export const selectViewData = ({ attrs, state, props }) => {
12
- // Use state's current value if it has been modified, otherwise use props
11
+ export const selectViewData = ({ attrs, state }) => {
13
12
  const value = state.value || '-';
14
13
 
15
14
  return {
16
15
  isOpen: state.isOpen,
17
16
  position: state.position,
18
- value: value ?? '-',
17
+ value: value,
19
18
  tempValue: state.tempValue,
20
- placeholder: props.placeholder ?? '',
19
+ placeholder: attrs.placeholder ?? '',
21
20
  label: attrs.label,
22
21
  };
23
22
  }
@@ -30,7 +29,6 @@ export const openPopover = (state, payload) => {
30
29
  const { position } = payload;
31
30
  state.position = position;
32
31
  state.isOpen = true;
33
- // Reset the current value to match the display value when opening
34
32
  state.hasUnsavedChanges = false;
35
33
  }
36
34
 
@@ -4,22 +4,12 @@ viewDataSchema:
4
4
  type: object
5
5
 
6
6
  attrsSchema:
7
- type: object
8
- properties:
9
- auto-focus:
10
- type: boolean
11
-
12
- propsSchema:
13
7
  type: object
14
8
  properties:
15
9
  value:
16
10
  type: string
17
- defaultValue:
18
- type: string
19
11
  placeholder:
20
12
  type: string
21
- onChange:
22
- type: function
23
13
 
24
14
  refs:
25
15
  text-display:
@@ -46,10 +36,10 @@ events:
46
36
 
47
37
  template:
48
38
  - rtgl-view#text-display w=f cur=p:
49
- - rtgl-text: ${value}
39
+ - rtgl-text: ${value}
50
40
  - rtgl-popover#popover ?open=${isOpen} x=${position.x} y=${position.y}:
51
- - rtgl-view g=md w=240 slot=content bgc=background br=md:
52
- - rtgl-text: ${label}
53
- - rtgl-input#input w=f placeholder=${placeholder}:
54
- - rtgl-view w=f ah=e:
55
- - rtgl-button#submit: Submit
41
+ - rtgl-view g=md w=240 slot=content bgc=background br=md:
42
+ - rtgl-text: ${label}
43
+ - rtgl-input#input w=f placeholder=${placeholder}:
44
+ - rtgl-view w=f ah=e:
45
+ - rtgl-button#submit: Submit
@@ -6,7 +6,9 @@ export const handleBeforeMount = (deps) => {
6
6
  if (props.selectedValue !== null && props.selectedValue !== undefined && props.options) {
7
7
  const selectedOption = props.options.find(opt => deepEqual(opt.value, props.selectedValue));
8
8
  if (selectedOption) {
9
- store.updateSelectOption(selectedOption);
9
+ store.updateSelectedValue({
10
+ value: selectedOption?.value
11
+ });
10
12
  render();
11
13
  }
12
14
  }
@@ -28,10 +30,15 @@ export const handleOnUpdate = (deps, payload) => {
28
30
  if (selectedValue !== null && selectedValue !== undefined && options) {
29
31
  const selectedOption = options.find(opt => deepEqual(opt.value, selectedValue));
30
32
  if (selectedOption) {
31
- store.updateSelectOption(selectedOption);
33
+ store.updateSelectedValue({
34
+ value: selectedOption.value
35
+ });
32
36
  }
33
37
  }
34
38
  render();
39
+ } else if (oldProps.selectedValue !== newProps.selectedValue) {
40
+ store.updateSelectedValue(newProps.selectedValue);
41
+ render();
35
42
  }
36
43
  }
37
44
 
@@ -65,7 +72,7 @@ export const handleButtonClick = (deps, payload) => {
65
72
  render();
66
73
  }
67
74
 
68
- export const handleClickOptionsPopoverOverlay = (deps, payload) => {
75
+ export const handleClickOptionsPopoverOverlay = (deps) => {
69
76
  const { store, render } = deps;
70
77
  store.closeOptionsPopover();
71
78
  render();
@@ -80,7 +87,7 @@ export const handleOptionClick = (deps, payload) => {
80
87
  const option = props.options[id];
81
88
 
82
89
  // Update internal state
83
- store.updateSelectOption(option);
90
+ store.updateSelectedValue({ value: option?.value });
84
91
 
85
92
  // Call onChange if provided
86
93
  if (props.onChange && typeof props.onChange === 'function') {
@@ -3,13 +3,13 @@ import { deepEqual } from '../../common.js';
3
3
  // Attributes that should not be passed through to the container
4
4
  // These are either handled internally or have special meaning
5
5
  const blacklistedAttrs = [
6
- "id",
7
- "class",
8
- "style",
6
+ "id",
7
+ "class",
8
+ "style",
9
9
  "slot",
10
10
  // Select-specific props that are handled separately
11
11
  "placeholder",
12
- "selectedValue",
12
+ "selectedValue",
13
13
  "selected-value",
14
14
  "onChange",
15
15
  "on-change",
@@ -42,7 +42,7 @@ export const selectViewData = ({ state, props, attrs }) => {
42
42
  const currentValue = state.selectedValue !== null ? state.selectedValue : props.selectedValue;
43
43
 
44
44
  // Calculate display label from value
45
- let displayLabel = props.placeholder || 'Select an option';
45
+ let displayLabel = attrs.placeholder || 'Select an option';
46
46
  let isPlaceholderLabel = true;
47
47
  if (currentValue !== null && currentValue !== undefined && props.options) {
48
48
  const selectedOption = props.options.find(opt => deepEqual(opt.value, currentValue));
@@ -63,6 +63,8 @@ export const selectViewData = ({ state, props, attrs }) => {
63
63
  };
64
64
  });
65
65
 
66
+ console.log('attrs.placeholder', attrs.placeholder)
67
+
66
68
  return {
67
69
  containerAttrString,
68
70
  isOpen: state.isOpen,
@@ -71,7 +73,6 @@ export const selectViewData = ({ state, props, attrs }) => {
71
73
  selectedValue: currentValue,
72
74
  selectedLabel: displayLabel,
73
75
  selectedLabelColor: isPlaceholderLabel ? "mu-fg" : "fg",
74
- placeholder: props.placeholder || 'Select an option',
75
76
  hasValue: currentValue !== null && currentValue !== undefined,
76
77
  showClear: !attrs['no-clear'] && !props['no-clear'] && (currentValue !== null && currentValue !== undefined),
77
78
  showAddOption: !!props.addOption,
@@ -102,8 +103,8 @@ export const closeOptionsPopover = (state) => {
102
103
  state.isOpen = false;
103
104
  }
104
105
 
105
- export const updateSelectOption = (state, option) => {
106
- state.selectedValue = option.value;
106
+ export const updateSelectedValue = (state, payload) => {
107
+ state.selectedValue = payload.value;
107
108
  state.isOpen = false;
108
109
  }
109
110
 
@@ -3,6 +3,12 @@ elementName: rtgl-select
3
3
  viewDataSchema:
4
4
  type: object
5
5
 
6
+ attrsSchema:
7
+ type: object
8
+ properties:
9
+ placeholder:
10
+ type: string
11
+
6
12
  propsSchema:
7
13
  type: object
8
14
  properties:
@@ -17,8 +23,6 @@ propsSchema:
17
23
  type: any
18
24
  selectedValue:
19
25
  type: any
20
- placeholder:
21
- type: string
22
26
  onChange:
23
27
  type: function
24
28
  no-clear:
@@ -1,21 +1,15 @@
1
1
  export const handleBeforeMount = (deps) => {
2
2
  const { store, attrs } = deps;
3
- store.setValue(attrs.defaultValue || 0);
3
+ store.setValue(attrs.value ?? 0);
4
4
  }
5
5
 
6
6
  export const handleOnUpdate = (deps, payload) => {
7
7
  const { oldAttrs, newAttrs } = payload;
8
- const { store, render, attrs } = deps;
8
+ const { store, render } = deps;
9
9
 
10
- // Reset when key changes
11
- if (oldAttrs?.key !== newAttrs?.key && newAttrs?.key) {
12
- const defaultValue = newAttrs?.defaultValue || attrs?.defaultValue || 0;
13
- store.setValue(defaultValue);
14
- render();
15
- } else if (oldAttrs?.defaultValue !== newAttrs?.defaultValue) {
16
- // Also reset when defaultValue changes
17
- const defaultValue = newAttrs?.defaultValue || 0;
18
- store.setValue(defaultValue);
10
+ if (oldAttrs?.value !== newAttrs?.value) {
11
+ const value = newAttrs?.value ?? 0;
12
+ store.setValue(value);
19
13
  render();
20
14
  }
21
15
  }
@@ -6,21 +6,21 @@ viewDataSchema:
6
6
  attrsSchema:
7
7
  type: object
8
8
  properties:
9
- defaultValue:
9
+ value:
10
10
  type: string
11
- default: '0'
11
+ default: "0"
12
12
  w:
13
13
  type: string
14
- default: ''
14
+ default: ""
15
15
  min:
16
16
  type: string
17
- default: '0'
17
+ default: "0"
18
18
  max:
19
19
  type: string
20
- default: '100'
20
+ default: "100"
21
21
  step:
22
22
  type: string
23
- default: '1'
23
+ default: "1"
24
24
 
25
25
  refs:
26
26
  input:
@@ -37,6 +37,7 @@ events:
37
37
 
38
38
  template:
39
39
  - rtgl-view d=h av=c g=md w=${w}:
40
- - rtgl-slider#slider key=${key} w=f type=range min=${min} max=${max} step=${step} value=${value}:
41
- - rtgl-view w=84:
42
- - rtgl-input#input key=${key} w=f type=number min=${min} max=${max} step=${step} value=${value}:
40
+ - rtgl-slider#slider key=${key} w=f type=range min=${min} max=${max} step=${step} value=${value}:
41
+ - rtgl-view w=84:
42
+ - rtgl-input#input key=${key} w=f type=number min=${min} max=${max} step=${step} value=${value}:
43
+
@@ -1,6 +1,6 @@
1
1
  /**
2
2
  * Creates a GlobalUI manager instance for controlling global UI components.
3
- * Provides methods for showing alerts, confirm dialogs, and dropdown menus.
3
+ * Provides methods for showing alerts, confirm dialogs, dropdown menus, and closing all UI components.
4
4
  *
5
5
  * @param {HTMLElement} globalUIElement - The globalUI component element
6
6
  * @returns {Object} GlobalUI manager instance
@@ -9,6 +9,7 @@
9
9
  * @returns {Function} returns.showAlert - Show an alert dialog
10
10
  * @returns {Function} returns.showConfirm - Show a confirmation dialog
11
11
  * @returns {Function} returns.showDropdownMenu - Show a dropdown menu
12
+ * @returns {Function} returns.closeAll - General-purpose function to close all currently open UI components
12
13
  */
13
14
  const createGlobalUI = (globalUIElement) => {
14
15
  let listeners = {};
@@ -109,6 +110,22 @@ const createGlobalUI = (globalUIElement) => {
109
110
  throw new Error("globalUIElement is not set. Make sure to initialize the global UI component and pass it to createGlobalUIManager.");
110
111
  }
111
112
  return globalUIElement.transformedHandlers.showDropdownMenu(options);
113
+ },
114
+
115
+ /**
116
+ * General-purpose function to close all currently open UI components.
117
+ * This includes dialogs, popovers, tooltips, selects, dropdown menus, and any other floating UI elements.
118
+ * Useful for programmatically cleaning up the entire UI surface.
119
+ *
120
+ * @returns {Promise<void>} Promise that resolves when all UI components are closed
121
+ * @throws {Error} If globalUIElement is not initialized
122
+ */
123
+ closeAll: async () => {
124
+ if(!globalUIElement)
125
+ {
126
+ throw new Error("globalUIElement is not set. Make sure to initialize the global UI component and pass it to createGlobalUIManager.");
127
+ }
128
+ return globalUIElement.transformedHandlers.closeAll();
112
129
  }
113
130
  };
114
131
  }