@rettangoli/ui 0.1.2-rc9 → 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 (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 +9 -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 +6 -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 +170 -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 +51 -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 +1 -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 +99 -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 +120 -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 +6 -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 +23 -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 +10 -10
  35. package/src/components/table/table.store.js +4 -4
  36. package/src/components/tabs/tabs.handlers.js +10 -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
@@ -0,0 +1,92 @@
1
+ export const handleAfterMount = async (deps) => {
2
+ const { props, store, render, getRefIds, } = deps;
3
+ const { waveformData } = props;
4
+
5
+ store.setWaveformData(waveformData);
6
+ render();
7
+
8
+ const canvas = getRefIds().canvas?.elm;
9
+ if (canvas) {
10
+ renderWaveform(waveformData, canvas);
11
+ }
12
+ };
13
+
14
+ export const handleOnUpdate = async (changes, deps) => {
15
+ const { store, render, getRefIds, props } = deps;
16
+ const { waveformData } = props;
17
+
18
+ if (!waveformData) {
19
+ console.log('waveform handleOnUpdate: no waveformData provided');
20
+ return;
21
+ }
22
+
23
+ store.setWaveformData(waveformData);
24
+ render();
25
+
26
+ const canvas = getRefIds().canvas?.elm;
27
+ if (canvas) {
28
+ renderWaveform(waveformData, canvas);
29
+ }
30
+ };
31
+
32
+ async function renderWaveform(waveformData, canvas) {
33
+ const ctx = canvas.getContext("2d");
34
+
35
+ // Get the actual display size of the canvas
36
+ const rect = canvas.getBoundingClientRect();
37
+ const displayWidth = rect.width;
38
+ const displayHeight = rect.height;
39
+
40
+ // Set canvas internal resolution to match display size
41
+ canvas.width = displayWidth;
42
+ canvas.height = displayHeight;
43
+
44
+ const width = canvas.width;
45
+ const height = canvas.height;
46
+
47
+ // Clear canvas
48
+ ctx.clearRect(0, 0, width, height);
49
+
50
+ // Dark theme background
51
+ ctx.fillStyle = "#1a1a1a";
52
+ ctx.fillRect(0, 0, width, height);
53
+
54
+ if (!waveformData || !waveformData.amplitudes) {
55
+ return;
56
+ }
57
+
58
+ const amplitudes = waveformData.amplitudes;
59
+ const centerY = height / 2;
60
+
61
+ // Create gradient for waveform
62
+ const gradient = ctx.createLinearGradient(0, 0, 0, height);
63
+ gradient.addColorStop(0, "#404040");
64
+ gradient.addColorStop(0.5, "#A1A1A1");
65
+ gradient.addColorStop(1, "#404040");
66
+
67
+ // Draw waveform bars
68
+ const barWidth = Math.max(1, width / amplitudes.length);
69
+ const barSpacing = 0.2; // 20% spacing between bars
70
+
71
+ for (let i = 0; i < amplitudes.length; i++) {
72
+ const amplitude = amplitudes[i];
73
+ const barHeight = amplitude * (height * 0.85);
74
+ const x = i * barWidth;
75
+ const y = centerY - barHeight / 2;
76
+
77
+ ctx.fillStyle = gradient;
78
+ ctx.fillRect(x, y, Math.max(1, barWidth * (1 - barSpacing)), barHeight);
79
+ }
80
+
81
+ // Draw subtle center line
82
+ ctx.strokeStyle = "rgba(255, 255, 255, 0.1)";
83
+ ctx.lineWidth = 1;
84
+ ctx.beginPath();
85
+ ctx.moveTo(0, centerY);
86
+ ctx.lineTo(width, centerY);
87
+ ctx.stroke();
88
+
89
+ // Add subtle glow effect
90
+ ctx.shadowBlur = 10;
91
+ ctx.shadowColor = "#2196F3";
92
+ }
@@ -0,0 +1,17 @@
1
+ export const createInitialState = () => Object.freeze({
2
+ waveformData: null,
3
+ });
4
+
5
+ export const setWaveformData = (state, data) => {
6
+ state.waveformData = data;
7
+ };
8
+
9
+ export const selectViewData = ({ state, attrs, props }) => {
10
+ return {
11
+ isLoading: props.isLoading,
12
+ w: attrs.w || "250",
13
+ h: attrs.h || "150",
14
+ cur: attrs.cur,
15
+ waveformData: props.waveformData,
16
+ };
17
+ };
@@ -0,0 +1,38 @@
1
+ elementName: rtgl-waveform
2
+
3
+ attrsSchema:
4
+ type: object
5
+ properties:
6
+ w:
7
+ type: string
8
+ description: Width of the waveform visualizer
9
+ default: '250'
10
+ h:
11
+ type: string
12
+ description: Height of the waveform visualizer
13
+ default: '150'
14
+ cur:
15
+ type: string
16
+ description: cursor
17
+
18
+ propsSchema:
19
+ type: object
20
+ properties:
21
+ waveformData:
22
+ type: object
23
+ description: File ID of the waveform data in object storage
24
+ isLoading:
25
+ type: boolean
26
+ description: Whether the waveform data is currently being loaded
27
+
28
+ refs:
29
+ canvas:
30
+ selector: canvas
31
+
32
+ template:
33
+ - rtgl-view w=f h=f pos=rel w=${w} h=${h} cur=${cur}:
34
+ - $if isLoading:
35
+ - rtgl-view w=f h=f av=c ah=c:
36
+ - rtgl-text c=mu-fg: ...
37
+ $else:
38
+ - 'canvas#canvas style="width:100%; height:100%;"':
@@ -0,0 +1,39 @@
1
+ const createGlobalUI = (globalUIElement) => {
2
+ let listeners = {};
3
+
4
+ return {
5
+ once: (event, callback) => {
6
+ if (!listeners[event]) {
7
+ listeners[event] = [];
8
+ }
9
+ const onceCallback = (...args) => {
10
+ callback(...args);
11
+ listeners[event] = listeners[event].filter(cb => cb !== onceCallback);
12
+ }
13
+ listeners[event].push(onceCallback);
14
+ },
15
+ emit: (event, ...args) => {
16
+ if (listeners[event]) {
17
+ listeners[event].forEach(callback => {
18
+ callback(...args);
19
+ });
20
+ }
21
+ },
22
+ showAlert: async (options) => {
23
+ if(!globalUIElement)
24
+ {
25
+ throw new Error("globalUIElement is not set. Make sure to initialize the global UI component and pass it to createGlobalUIManager.");
26
+ }
27
+ globalUIElement.transformedHandlers.showAlert(options);
28
+ },
29
+ showConfirm: async (options) => {
30
+ if(!globalUIElement)
31
+ {
32
+ throw new Error("globalUIElement is not set. Make sure to initialize the global UI component and pass it to createGlobalUIManager.");
33
+ }
34
+ return globalUIElement.transformedHandlers.showConfirm(options);
35
+ }
36
+ };
37
+ }
38
+
39
+ export default createGlobalUI;
@@ -5,6 +5,8 @@ import RettangoliImage from './primitives/image.js';
5
5
  import RettangoliSvg from './primitives/svg.js';
6
6
  import RettangoliInput from './primitives/input.js';
7
7
  import RettangoliTextArea from './primitives/textarea.js';
8
+ import RettangoliDialog from './primitives/dialog.js';
9
+
8
10
 
9
11
  customElements.define("rtgl-button", RettangoliButton({}));
10
12
  customElements.define("rtgl-view", RettangoliView({}));
@@ -13,3 +15,4 @@ customElements.define("rtgl-image", RettangoliImage({}));
13
15
  customElements.define("rtgl-svg", RettangoliSvg({}));
14
16
  customElements.define("rtgl-input", RettangoliInput({}));
15
17
  customElements.define("rtgl-textarea", RettangoliTextArea({}));
18
+ customElements.define("rtgl-dialog", RettangoliDialog({}));
@@ -7,6 +7,8 @@ import RettangoliInput from './primitives/input.js';
7
7
  import RettangoliTextArea from './primitives/textarea.js';
8
8
  import RettangoliColorPicker from './primitives/colorPicker.js';
9
9
  import RettangoliSlider from './primitives/slider.js';
10
+ import RettangoliDialog from './primitives/dialog.js';
11
+ import RettangoliPopover from './primitives/popover.js';
10
12
 
11
13
  customElements.define("rtgl-button", RettangoliButton({}));
12
14
  customElements.define("rtgl-view", RettangoliView({}));
@@ -17,6 +19,8 @@ customElements.define("rtgl-input", RettangoliInput({}));
17
19
  customElements.define("rtgl-textarea", RettangoliTextArea({}));
18
20
  customElements.define("rtgl-color-picker", RettangoliColorPicker({}));
19
21
  customElements.define("rtgl-slider", RettangoliSlider({}));
22
+ customElements.define("rtgl-dialog", RettangoliDialog({}));
23
+ customElements.define("rtgl-popover", RettangoliPopover({}));
20
24
 
21
25
  // built from rettangoli cli fe
22
26
  import '../.temp/dynamicImport.js'
package/src/index.js CHANGED
@@ -5,6 +5,9 @@ import RettangoliImage from './primitives/image.js';
5
5
  import RettangoliSvg from './primitives/svg.js';
6
6
  import RettangoliInput from './primitives/input.js';
7
7
  import RettangoliTextArea from './primitives/textarea.js';
8
+ import RettangoliDialog from './primitives/dialog.js';
9
+ import RettangoliPopover from './primitives/popover.js';
10
+ import createGlobalUI from './deps/createGlobalUI.js';
8
11
 
9
12
  export {
10
13
  RettangoliButton,
@@ -14,4 +17,7 @@ export {
14
17
  RettangoliSvg,
15
18
  RettangoliInput,
16
19
  RettangoliTextArea,
17
- }
20
+ RettangoliDialog,
21
+ RettangoliPopover,
22
+ createGlobalUI,
23
+ }
@@ -296,6 +296,16 @@ class RettangoliButtonElement extends HTMLElement {
296
296
  this._buttonElement.style.maxWidth = "";
297
297
  }
298
298
  }
299
+
300
+ // Public method to get the actual button's bounding rect
301
+ // This is needed because the host element has display: contents
302
+ getBoundingClientRect() {
303
+ if (this._buttonElement) {
304
+ return this._buttonElement.getBoundingClientRect();
305
+ }
306
+ // Fallback to host element
307
+ return super.getBoundingClientRect();
308
+ }
299
309
  }
300
310
 
301
311
  // Export factory function to maintain API compatibility
@@ -81,8 +81,8 @@ class RettangoliColorPickerElement extends HTMLElement {
81
81
  "wh",
82
82
  "w",
83
83
  "h",
84
- "hidden",
85
- "visible",
84
+ "hide",
85
+ "show",
86
86
  "op",
87
87
  "z",
88
88
  ])
@@ -114,6 +114,15 @@ class RettangoliColorPickerElement extends HTMLElement {
114
114
  };
115
115
 
116
116
  attributeChangedCallback(name, oldValue, newValue) {
117
+ // Handle key attribute change - reset value
118
+ if (name === "key" && oldValue !== newValue) {
119
+ requestAnimationFrame(() => {
120
+ const value = this.getAttribute("value");
121
+ this._inputElement.value = value ?? "#000000";
122
+ });
123
+ return;
124
+ }
125
+
117
126
  // Handle input-specific attributes first
118
127
  if (["value", "disabled"].includes(name)) {
119
128
  this._updateInputAttributes();
@@ -168,11 +177,11 @@ class RettangoliColorPickerElement extends HTMLElement {
168
177
  this._styles[size]["max-height"] = height;
169
178
  }
170
179
 
171
- if (this.hasAttribute(addSizePrefix("hidden"))) {
180
+ if (this.hasAttribute(addSizePrefix("hide"))) {
172
181
  this._styles[size].display = "none !important";
173
182
  }
174
183
 
175
- if (this.hasAttribute(addSizePrefix("visible"))) {
184
+ if (this.hasAttribute(addSizePrefix("show"))) {
176
185
  this._styles[size].display = "block !important";
177
186
  }
178
187
  });
@@ -0,0 +1,254 @@
1
+ import { css } from "../common.js";
2
+
3
+ class RettangoliDialogElement extends HTMLElement {
4
+ static styleSheet = null;
5
+
6
+ static initializeStyleSheet() {
7
+ if (!RettangoliDialogElement.styleSheet) {
8
+ RettangoliDialogElement.styleSheet = new CSSStyleSheet();
9
+ RettangoliDialogElement.styleSheet.replaceSync(css`
10
+ :host {
11
+ display: contents;
12
+ }
13
+
14
+ dialog {
15
+ padding: 0;
16
+ border: none;
17
+ background: transparent;
18
+ margin: auto;
19
+ overflow-y: scroll;
20
+ color: inherit;
21
+ max-height: 100vh;
22
+ height: 100vh;
23
+ max-width: 100vw;
24
+ scrollbar-width: none;
25
+ outline: none;
26
+ }
27
+
28
+ dialog::backdrop {
29
+ background-color: rgba(0, 0, 0, 0.5);
30
+ }
31
+
32
+ slot[name="content"] {
33
+ background-color: var(--background) !important;
34
+ display: block;
35
+ padding: var(--spacing-lg);
36
+ border: 1px solid var(--border);
37
+ border-radius: var(--border-radius-md);
38
+ margin-left: var(--spacing-lg);
39
+ margin-right: var(--spacing-lg);
40
+ width: fit-content;
41
+ max-width: calc(100vw - 2 * var(--spacing-lg));
42
+ /* Default margins will be set dynamically via JavaScript for adaptive centering */
43
+ margin-top: 40px;
44
+ margin-bottom: 40px;
45
+ }
46
+
47
+ /* Size attribute styles */
48
+ :host([s="sm"]) slot[name="content"] {
49
+ width: 33vw;
50
+ }
51
+
52
+ :host([s="md"]) slot[name="content"] {
53
+ width: 50vw;
54
+ }
55
+
56
+ :host([s="lg"]) slot[name="content"] {
57
+ width: 80vw;
58
+ }
59
+
60
+ :host([s="f"]) slot[name="content"] {
61
+ width: 100vw;
62
+ margin-left: 0;
63
+ margin-right: 0;
64
+ }
65
+
66
+ @keyframes dialog-in {
67
+ from {
68
+ opacity: 0;
69
+ transform: scale(0.95);
70
+ }
71
+ to {
72
+ opacity: 1;
73
+ transform: scale(1);
74
+ }
75
+ }
76
+
77
+ dialog[open] slot[name="content"] {
78
+ animation: dialog-in 150ms cubic-bezier(0.16, 1, 0.3, 1);
79
+ }
80
+ `);
81
+ }
82
+ }
83
+
84
+ constructor() {
85
+ super();
86
+ RettangoliDialogElement.initializeStyleSheet();
87
+ this.shadow = this.attachShadow({ mode: "open" });
88
+ this.shadow.adoptedStyleSheets = [RettangoliDialogElement.styleSheet];
89
+
90
+ // Create dialog element
91
+ this._dialogElement = document.createElement('dialog');
92
+ this.shadow.appendChild(this._dialogElement);
93
+
94
+ // Store reference for content slot
95
+ this._slotElement = null;
96
+ this._isConnected = false;
97
+
98
+ // Handle click outside - emit custom event
99
+ this._dialogElement.addEventListener('click', (e) => {
100
+ if (e.target === this._dialogElement) {
101
+ this.dispatchEvent(new CustomEvent('close', {
102
+ detail: {}
103
+ }));
104
+ }
105
+ });
106
+
107
+ // Handle right-click on overlay to close dialog
108
+ this._dialogElement.addEventListener('contextmenu', (e) => {
109
+ if (e.target === this._dialogElement) {
110
+ e.preventDefault();
111
+ this.dispatchEvent(new CustomEvent('close', {
112
+ detail: {}
113
+ }));
114
+ }
115
+ });
116
+
117
+ // Handle ESC key - prevent native close and emit custom event
118
+ this._dialogElement.addEventListener('cancel', (e) => {
119
+ e.preventDefault();
120
+ this.dispatchEvent(new CustomEvent('close', {
121
+ detail: {}
122
+ }));
123
+ });
124
+ }
125
+
126
+ static get observedAttributes() {
127
+ return ["open", "w", "s"];
128
+ }
129
+
130
+ connectedCallback() {
131
+ this._updateDialog();
132
+ this._isConnected = true;
133
+ // Check initial open attribute
134
+ if (this.hasAttribute('open')) {
135
+ this._showModal();
136
+ }
137
+ }
138
+
139
+ attributeChangedCallback(name, oldValue, newValue) {
140
+ if (name === 'open') {
141
+ if (newValue !== null && !this._dialogElement.open && this._isConnected) {
142
+ this._showModal();
143
+ } else if (newValue === null && this._dialogElement.open) {
144
+ this._hideModal();
145
+ }
146
+ } else if (name === 'w') {
147
+ this._updateWidth();
148
+ } else if (name === 's') {
149
+ // Size is handled via CSS :host() selectors
150
+ }
151
+ }
152
+
153
+ _updateDialog() {
154
+ this._updateWidth();
155
+ }
156
+
157
+ _updateWidth() {
158
+ const width = this.getAttribute('w');
159
+ if (width) {
160
+ this._dialogElement.style.width = width;
161
+ } else {
162
+ this._dialogElement.style.width = '';
163
+ }
164
+ }
165
+
166
+ // Internal methods
167
+ _showModal() {
168
+ if (!this._dialogElement.open) {
169
+ // Create and append slot for content only if it doesn't exist
170
+ if (!this._slotElement) {
171
+ this._slotElement = document.createElement('slot');
172
+ this._slotElement.setAttribute('name', 'content');
173
+ this._dialogElement.appendChild(this._slotElement);
174
+ }
175
+
176
+ this._dialogElement.showModal();
177
+
178
+ // Reset scroll position
179
+ this._dialogElement.scrollTop = 0;
180
+
181
+ // Apply adaptive centering
182
+ this._applyAdaptiveCentering();
183
+ }
184
+ }
185
+
186
+ _hideModal() {
187
+ if (this._dialogElement.open) {
188
+ this._dialogElement.close();
189
+
190
+ // Remove slot to unmount content
191
+ if (this._slotElement) {
192
+ // Reset any inline styles applied for adaptive centering
193
+ this._slotElement.style.marginTop = '';
194
+ this._slotElement.style.marginBottom = '';
195
+
196
+ this._dialogElement.removeChild(this._slotElement);
197
+ this._slotElement = null;
198
+ }
199
+
200
+ // Reset dialog height
201
+ this._dialogElement.style.height = '';
202
+
203
+ // Don't emit any event when programmatically closed via attribute
204
+ }
205
+ }
206
+
207
+ _applyAdaptiveCentering() {
208
+ if (!this._slotElement) {
209
+ return;
210
+ }
211
+
212
+ // Use requestAnimationFrame to ensure DOM has updated
213
+ requestAnimationFrame(() => {
214
+ if (!this._slotElement) return;
215
+
216
+ // Get the actual height of the content
217
+ const contentHeight = this._slotElement.offsetHeight;
218
+ const viewportHeight = window.innerHeight;
219
+
220
+ // Calculate centered position with minimum margins for scrollability
221
+ const minMargin = 40; // Minimum margin in pixels to ensure scrollability
222
+
223
+ if (contentHeight >= viewportHeight - (2 * minMargin)) {
224
+ // Content is too tall, use minimum margins to allow scrolling
225
+ // Start near the top with small margin so content isn't pushed too far down
226
+ this._slotElement.style.marginTop = `${minMargin}px`;
227
+ this._slotElement.style.marginBottom = `${minMargin}px`;
228
+ // Keep dialog at full height for scrolling
229
+ this._dialogElement.style.height = '100vh';
230
+ } else {
231
+ // Content fits, center it vertically
232
+ const totalMargin = viewportHeight - contentHeight;
233
+ const margin = Math.floor(totalMargin / 2);
234
+ this._slotElement.style.marginTop = `${margin}px`;
235
+ this._slotElement.style.marginBottom = `${margin}px`;
236
+ // Set dialog height to auto to prevent unnecessary scrollbar
237
+ this._dialogElement.style.height = 'auto';
238
+ }
239
+ });
240
+ }
241
+
242
+
243
+ // Expose dialog element for advanced usage
244
+ get dialog() {
245
+ return this._dialogElement;
246
+ }
247
+ }
248
+
249
+ // Export factory function to maintain API compatibility
250
+ export default ({ render, html }) => {
251
+ // Note: render and html parameters are accepted but not used
252
+ // This maintains backward compatibility with existing code
253
+ return RettangoliDialogElement;
254
+ };
@@ -85,7 +85,8 @@ class RettangoliImageElement extends HTMLElement {
85
85
  "wh",
86
86
  "w",
87
87
  "h",
88
- "hidden",
88
+ "hide",
89
+ "show",
89
90
  "height",
90
91
  "width",
91
92
  "z",
@@ -198,11 +199,11 @@ class RettangoliImageElement extends HTMLElement {
198
199
  this._styles[size]["max-height"] = height;
199
200
  }
200
201
 
201
- if (this.hasAttribute(addSizePrefix("hidden"))) {
202
+ if (this.hasAttribute(addSizePrefix("hide"))) {
202
203
  this._styles[size].display = "none !important";
203
204
  }
204
205
 
205
- if (this.hasAttribute(addSizePrefix("visible"))) {
206
+ if (this.hasAttribute(addSizePrefix("show"))) {
206
207
  this._styles[size].display = "block !important";
207
208
  }
208
209
  });
@@ -94,8 +94,8 @@ class RettangoliInputElement extends HTMLElement {
94
94
  "wh",
95
95
  "w",
96
96
  "h",
97
- "hidden",
98
- "visible",
97
+ "hide",
98
+ "show",
99
99
  "op",
100
100
  "z",
101
101
  ])
@@ -110,6 +110,10 @@ class RettangoliInputElement extends HTMLElement {
110
110
  this._inputElement.value = newValue;
111
111
  }
112
112
 
113
+ focus() {
114
+ this._inputElement.focus();
115
+ }
116
+
113
117
  _onChange = (event) => {
114
118
  this.dispatchEvent(new CustomEvent('input-change', {
115
119
  detail: {
@@ -119,6 +123,15 @@ class RettangoliInputElement extends HTMLElement {
119
123
  };
120
124
 
121
125
  attributeChangedCallback(name, oldValue, newValue) {
126
+ // Handle key attribute change - reset value
127
+ if (name === "key" && oldValue !== newValue) {
128
+ requestAnimationFrame((() => {
129
+ const value = this.getAttribute("value");
130
+ this._inputElement.value = value ?? "";
131
+ }))
132
+ return;
133
+ }
134
+
122
135
  // Handle input-specific attributes first
123
136
  if (["type", "placeholder", "disabled", "value", "step", "s"].includes(name)) {
124
137
  this._updateInputAttributes();
@@ -173,11 +186,11 @@ class RettangoliInputElement extends HTMLElement {
173
186
  this._styles[size]["max-height"] = height;
174
187
  }
175
188
 
176
- if (this.hasAttribute(addSizePrefix("hidden"))) {
189
+ if (this.hasAttribute(addSizePrefix("hide"))) {
177
190
  this._styles[size].display = "none !important";
178
191
  }
179
192
 
180
- if (this.hasAttribute(addSizePrefix("visible"))) {
193
+ if (this.hasAttribute(addSizePrefix("show"))) {
181
194
  this._styles[size].display = "block !important";
182
195
  }
183
196
  });