@rettangoli/ui 0.1.31 → 1.0.0-rc1

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 (89) hide show
  1. package/README.md +20 -85
  2. package/dist/rettangoli-iife-layout.min.js +113 -173
  3. package/dist/rettangoli-iife-ui.min.js +123 -183
  4. package/package.json +5 -4
  5. package/src/common/dimensions.js +72 -0
  6. package/src/common/link.js +111 -0
  7. package/src/common/responsive.js +8 -0
  8. package/src/common.js +43 -8
  9. package/src/components/accordionItem/accordionItem.handlers.js +1 -1
  10. package/src/components/accordionItem/accordionItem.schema.yaml +14 -0
  11. package/src/components/accordionItem/accordionItem.store.js +8 -8
  12. package/src/components/accordionItem/accordionItem.view.yaml +5 -35
  13. package/src/components/breadcrumb/breadcrumb.handlers.js +24 -3
  14. package/src/components/breadcrumb/breadcrumb.schema.yaml +51 -0
  15. package/src/components/breadcrumb/breadcrumb.store.js +66 -10
  16. package/src/components/breadcrumb/breadcrumb.view.yaml +18 -58
  17. package/src/components/dropdownMenu/dropdownMenu.handlers.js +17 -3
  18. package/src/components/dropdownMenu/dropdownMenu.schema.yaml +64 -0
  19. package/src/components/dropdownMenu/dropdownMenu.store.js +48 -6
  20. package/src/components/dropdownMenu/dropdownMenu.view.yaml +24 -46
  21. package/src/components/form/form.handlers.js +25 -108
  22. package/src/components/form/form.schema.yaml +283 -0
  23. package/src/components/form/form.store.js +19 -14
  24. package/src/components/form/form.view.yaml +28 -319
  25. package/src/components/globalUi/globalUi.handlers.js +2 -2
  26. package/src/components/globalUi/globalUi.schema.yaml +8 -0
  27. package/src/components/globalUi/globalUi.store.js +8 -8
  28. package/src/components/globalUi/globalUi.view.yaml +9 -46
  29. package/src/components/navbar/navbar.handlers.js +1 -1
  30. package/src/components/navbar/navbar.schema.yaml +25 -0
  31. package/src/components/navbar/navbar.store.js +28 -14
  32. package/src/components/navbar/navbar.view.yaml +21 -65
  33. package/src/components/pageOutline/pageOutline.handlers.js +17 -11
  34. package/src/components/pageOutline/pageOutline.schema.yaml +16 -0
  35. package/src/components/pageOutline/pageOutline.store.js +6 -7
  36. package/src/components/pageOutline/pageOutline.view.yaml +1 -29
  37. package/src/components/popoverInput/popoverInput.handlers.js +31 -31
  38. package/src/components/popoverInput/popoverInput.schema.yaml +18 -0
  39. package/src/components/popoverInput/popoverInput.store.js +9 -9
  40. package/src/components/popoverInput/popoverInput.view.yaml +5 -22
  41. package/src/components/select/select.handlers.js +31 -35
  42. package/src/components/select/select.schema.yaml +36 -0
  43. package/src/components/select/select.store.js +34 -35
  44. package/src/components/select/select.view.yaml +13 -56
  45. package/src/components/sidebar/sidebar.handlers.js +5 -5
  46. package/src/components/sidebar/sidebar.schema.yaml +57 -0
  47. package/src/components/sidebar/sidebar.store.js +45 -23
  48. package/src/components/sidebar/sidebar.view.yaml +79 -174
  49. package/src/components/sliderInput/sliderInput.handlers.js +28 -8
  50. package/src/components/sliderInput/sliderInput.schema.yaml +27 -0
  51. package/src/components/sliderInput/sliderInput.store.js +9 -9
  52. package/src/components/sliderInput/sliderInput.view.yaml +8 -33
  53. package/src/components/table/table.handlers.js +3 -3
  54. package/src/components/table/table.schema.yaml +27 -0
  55. package/src/components/table/table.store.js +8 -8
  56. package/src/components/table/table.view.yaml +16 -62
  57. package/src/components/tabs/tabs.schema.yaml +26 -0
  58. package/src/components/tabs/tabs.store.js +12 -9
  59. package/src/components/tabs/tabs.view.yaml +4 -60
  60. package/src/components/tooltip/tooltip.schema.yaml +18 -0
  61. package/src/components/tooltip/tooltip.store.js +7 -7
  62. package/src/components/tooltip/tooltip.view.yaml +4 -22
  63. package/src/components/waveform/waveform.handlers.js +6 -6
  64. package/src/components/waveform/waveform.schema.yaml +25 -0
  65. package/src/components/waveform/waveform.store.js +6 -6
  66. package/src/components/waveform/waveform.view.yaml +6 -34
  67. package/src/deps/createGlobalUI.js +2 -2
  68. package/src/primitives/button.js +200 -114
  69. package/src/primitives/colorPicker.js +56 -50
  70. package/src/primitives/dialog.js +2 -1
  71. package/src/primitives/image.js +73 -103
  72. package/src/primitives/input-number.js +139 -93
  73. package/src/primitives/input.js +87 -64
  74. package/src/primitives/popover.js +36 -28
  75. package/src/primitives/slider.js +6 -4
  76. package/src/primitives/svg.js +9 -10
  77. package/src/primitives/text.js +26 -47
  78. package/src/primitives/textarea.js +25 -9
  79. package/src/primitives/view.js +49 -90
  80. package/src/setup.js +1 -7
  81. package/src/styles/buttonMarginStyles.js +1 -13
  82. package/src/styles/cursorStyles.js +1 -5
  83. package/src/styles/flexDirectionStyles.js +4 -4
  84. package/src/styles/marginStylesForTarget.js +13 -0
  85. package/src/styles/textColorStyles.js +14 -6
  86. package/src/styles/textStyles.js +4 -4
  87. package/src/styles/viewStyles.js +6 -6
  88. package/src/styles/viewStylesForTarget.js +58 -0
  89. package/src/styles/flexChildStyles.js +0 -43
@@ -4,11 +4,15 @@ import {
4
4
  convertObjectToCssString,
5
5
  styleMapKeys,
6
6
  permutateBreakpoints,
7
+ syncLinkWrapper,
8
+ createResponsiveStyleBuckets,
9
+ responsiveStyleSizes,
10
+ applyDimensionToStyleBucket,
7
11
  } from "../common.js";
8
12
  import cursorStyles from "../styles/cursorStyles.js";
9
- import marginStyles from "../styles/marginStyles.js";
10
- import viewStyles from "../styles/viewStyles.js";
11
13
  import anchorStyles from "../styles/anchorStyles.js";
14
+ import viewStylesForTarget from "../styles/viewStylesForTarget.js";
15
+ import marginStylesForTarget from "../styles/marginStylesForTarget.js";
12
16
 
13
17
  // Internal implementation without uhtml
14
18
  class RettangoliImageElement extends HTMLElement {
@@ -19,14 +23,14 @@ class RettangoliImageElement extends HTMLElement {
19
23
  RettangoliImageElement.styleSheet = new CSSStyleSheet();
20
24
  RettangoliImageElement.styleSheet.replaceSync(css`
21
25
  :host {
26
+ display: contents;
27
+ }
28
+ img, a {
22
29
  border-style: solid;
23
30
  box-sizing: border-box;
24
31
  overflow: hidden;
25
32
  border-width: 0;
26
33
  }
27
- slot {
28
- display: contents;
29
- }
30
34
  :host([of="con"]) img {
31
35
  object-fit: contain;
32
36
  }
@@ -36,10 +40,6 @@ class RettangoliImageElement extends HTMLElement {
36
40
  :host([of="none"]) img {
37
41
  object-fit: none;
38
42
  }
39
- img {
40
- height: 100%;
41
- width: 100%;
42
- }
43
43
  :host([w]:not([h]):not([wh])) img,
44
44
  :host([sm-w]:not([sm-h]):not([sm-wh])) img,
45
45
  :host([md-w]:not([md-h]):not([md-wh])) img,
@@ -56,12 +56,8 @@ class RettangoliImageElement extends HTMLElement {
56
56
  width: 100%;
57
57
  }
58
58
 
59
- :host([href]) {
60
- cursor: pointer;
61
- }
62
-
63
- ${viewStyles}
64
- ${marginStyles}
59
+ ${viewStylesForTarget('img, a')}
60
+ ${marginStylesForTarget('img, a')}
65
61
  ${cursorStyles}
66
62
  `);
67
63
  }
@@ -87,87 +83,69 @@ class RettangoliImageElement extends HTMLElement {
87
83
  ...styleMapKeys,
88
84
  "key",
89
85
  "src",
86
+ "alt",
90
87
  "href",
91
- "target",
88
+ "new-tab",
89
+ "rel",
92
90
  "wh",
93
91
  "w",
94
92
  "h",
95
93
  "hide",
96
94
  "show",
97
- "height",
98
- "width",
95
+ "op",
99
96
  "z",
97
+ "of",
100
98
  ]);
101
99
  }
102
100
 
103
- _styles = {
104
- default: {},
105
- sm: {},
106
- md: {},
107
- lg: {},
108
- xl: {},
109
- };
101
+ _styles = createResponsiveStyleBuckets();
110
102
 
111
103
  _lastStyleString = "";
112
104
 
113
105
  _updateDOM() {
114
106
  const href = this.getAttribute("href");
115
- const target = this.getAttribute("target");
116
-
117
- if (href) {
118
- if (!this._linkElement) {
119
- // Create link wrapper
120
- this._linkElement = document.createElement("a");
121
- }
122
-
123
- // Update link attributes
124
- this._linkElement.href = href;
125
- if (target) {
126
- this._linkElement.target = target;
127
- } else {
128
- this._linkElement.removeAttribute("target");
129
- }
130
-
131
- // Wrap image in link
132
- this._linkElement.appendChild(this._imgElement);
107
+ const newTab = this.hasAttribute("new-tab");
108
+ const rel = this.getAttribute("rel");
109
+
110
+ this._linkElement = syncLinkWrapper({
111
+ shadowRoot: this.shadow,
112
+ childElement: this._imgElement,
113
+ linkElement: this._linkElement,
114
+ href,
115
+ newTab,
116
+ rel,
117
+ });
118
+ }
133
119
 
134
- // Ensure link is in shadow DOM
135
- if (this._linkElement.parentNode !== this.shadow) {
136
- this.shadow.appendChild(this._linkElement);
137
- }
138
- } else if (this._linkElement) {
139
- // Remove link wrapper
140
- if (this._imgElement.parentNode === this._linkElement) {
141
- this.shadow.appendChild(this._imgElement);
142
- }
143
- if (this._linkElement.parentNode === this.shadow) {
144
- this.shadow.removeChild(this._linkElement);
145
- }
146
- this._linkElement = null;
147
- } else {
148
- // Ensure image is in shadow DOM
149
- if (this._imgElement.parentNode !== this.shadow) {
150
- this.shadow.appendChild(this._imgElement);
151
- }
152
- }
120
+ connectedCallback() {
121
+ this._updateImageAttributes();
122
+ this.updateStyles();
153
123
  }
154
124
 
155
125
  attributeChangedCallback(name, oldValue, newValue) {
156
- // Handle href and target changes
157
- if (name === "href" || name === "target") {
126
+ // Handle href and link behavior changes
127
+ if (name === "href" || name === "new-tab" || name === "rel") {
158
128
  this._updateDOM();
159
129
  return;
160
130
  }
131
+
132
+ // Handle image attributes
133
+ if (name === "src" || name === "alt") {
134
+ this._updateImageAttributes();
135
+ return;
136
+ }
137
+
138
+ // Update styles for all other attributes
139
+ if (oldValue !== newValue) {
140
+ this.updateStyles();
141
+ }
142
+ }
143
+
144
+ updateStyles() {
161
145
  // Reset styles for fresh calculation
162
- this._styles = {
163
- default: {},
164
- sm: {},
165
- md: {},
166
- lg: {},
167
- xl: {},
168
- };
169
-
170
- ["default", "sm", "md", "lg", "xl"].forEach((size) => {
146
+ this._styles = createResponsiveStyleBuckets();
147
+
148
+ responsiveStyleSizes.forEach((size) => {
171
149
  const addSizePrefix = (tag) => {
172
150
  return `${size === "default" ? "" : `${size}-`}${tag}`;
173
151
  };
@@ -179,7 +157,7 @@ class RettangoliImageElement extends HTMLElement {
179
157
  const height = dimensionWithUnit(
180
158
  wh === null ? this.getAttribute(addSizePrefix("h")) : wh,
181
159
  );
182
- const opacity = this.getAttribute(addSizePrefix("o"));
160
+ const opacity = this.getAttribute(addSizePrefix("op"));
183
161
  const zIndex = this.getAttribute(addSizePrefix("z"));
184
162
 
185
163
  if (zIndex !== null) {
@@ -190,21 +168,19 @@ class RettangoliImageElement extends HTMLElement {
190
168
  this._styles[size].opacity = opacity;
191
169
  }
192
170
 
193
- if (width === "f") {
194
- this._styles[size].width = "var(--width-stretch)";
195
- } else if (width !== undefined) {
196
- this._styles[size].width = width;
197
- this._styles[size]["min-width"] = width;
198
- this._styles[size]["max-width"] = width;
199
- }
171
+ applyDimensionToStyleBucket({
172
+ styleBucket: this._styles[size],
173
+ axis: "width",
174
+ dimension: width,
175
+ fillValue: "var(--width-stretch)",
176
+ });
200
177
 
201
- if (height === "f") {
202
- this._styles[size].height = "100%";
203
- } else if (height !== undefined) {
204
- this._styles[size].height = height;
205
- this._styles[size]["min-height"] = height;
206
- this._styles[size]["max-height"] = height;
207
- }
178
+ applyDimensionToStyleBucket({
179
+ styleBucket: this._styles[size],
180
+ axis: "height",
181
+ dimension: height,
182
+ fillValue: "100%",
183
+ });
208
184
 
209
185
  if (this.hasAttribute(addSizePrefix("hide"))) {
210
186
  this._styles[size].display = "none !important";
@@ -216,34 +192,28 @@ class RettangoliImageElement extends HTMLElement {
216
192
  });
217
193
 
218
194
  // Update styles only if changed
219
- const newStyleString = convertObjectToCssString(this._styles);
195
+ const newStyleString = convertObjectToCssString(this._styles, 'img, a');
220
196
  if (newStyleString !== this._lastStyleString) {
221
197
  this._styleElement.textContent = newStyleString;
222
198
  this._lastStyleString = newStyleString;
223
199
  }
224
-
225
- // Update img attributes
226
- this._updateImageAttributes();
227
200
  }
228
201
 
229
202
  _updateImageAttributes() {
230
203
  const src = this.getAttribute("src");
231
- const width = this.getAttribute("width");
232
- const height = this.getAttribute("height");
204
+ const alt = this.getAttribute("alt");
233
205
 
234
206
  if (src !== null) {
235
207
  this._imgElement.setAttribute("src", src);
208
+ } else {
209
+ this._imgElement.removeAttribute("src");
236
210
  }
237
- if (width !== null) {
238
- this._imgElement.setAttribute("width", width);
239
- }
240
- if (height !== null) {
241
- this._imgElement.setAttribute("height", height);
242
- }
243
- }
244
211
 
245
- connectedCallback() {
246
- this._updateImageAttributes();
212
+ if (alt !== null) {
213
+ this._imgElement.setAttribute("alt", alt);
214
+ } else {
215
+ this._imgElement.removeAttribute("alt");
216
+ }
247
217
  }
248
218
  }
249
219
 
@@ -2,16 +2,28 @@ import {
2
2
  css,
3
3
  dimensionWithUnit,
4
4
  convertObjectToCssString,
5
- styleMapKeys,
6
5
  permutateBreakpoints,
6
+ createResponsiveStyleBuckets,
7
+ responsiveStyleSizes,
8
+ applyDimensionToStyleBucket,
7
9
  } from "../common.js";
8
10
  import cursorStyles from "../styles/cursorStyles.js";
9
11
  import marginStyles from "../styles/marginStyles.js";
10
12
 
13
+ const inputNumberStyleMapKeys = ["mt", "mr", "mb", "ml", "m", "mh", "mv", "cur"];
14
+
11
15
  // Internal implementation without uhtml
12
16
  class RettangoliInputNumberElement extends HTMLElement {
13
17
  static styleSheet = null;
14
18
 
19
+ static inputSpecificAttributes = [
20
+ "disabled",
21
+ "step",
22
+ "min",
23
+ "max",
24
+ "s",
25
+ ];
26
+
15
27
  static initializeStyleSheet() {
16
28
  if (!RettangoliInputNumberElement.styleSheet) {
17
29
  RettangoliInputNumberElement.styleSheet = new CSSStyleSheet();
@@ -61,13 +73,7 @@ class RettangoliInputNumberElement extends HTMLElement {
61
73
  this.shadow.adoptedStyleSheets = [RettangoliInputNumberElement.styleSheet];
62
74
 
63
75
  // Initialize style tracking properties
64
- this._styles = {
65
- default: {},
66
- sm: {},
67
- md: {},
68
- lg: {},
69
- xl: {},
70
- };
76
+ this._styles = createResponsiveStyleBuckets();
71
77
  this._lastStyleString = "";
72
78
 
73
79
  // Create initial DOM structure
@@ -77,14 +83,14 @@ class RettangoliInputNumberElement extends HTMLElement {
77
83
  this.shadow.appendChild(this._styleElement);
78
84
  this.shadow.appendChild(this._inputElement);
79
85
 
80
- // Bind event handler
81
- this._inputElement.addEventListener('input', this._onChange);
86
+ // Bind event handlers
87
+ this._inputElement.addEventListener('input', this._onInput);
88
+ this._inputElement.addEventListener('change', this._onChange);
82
89
  }
83
90
 
84
91
  static get observedAttributes() {
85
92
  return [
86
93
  "key",
87
- "type",
88
94
  "placeholder",
89
95
  "disabled",
90
96
  "value",
@@ -93,7 +99,7 @@ class RettangoliInputNumberElement extends HTMLElement {
93
99
  "max",
94
100
  "s",
95
101
  ...permutateBreakpoints([
96
- ...styleMapKeys,
102
+ ...inputNumberStyleMapKeys,
97
103
  "wh",
98
104
  "w",
99
105
  "h",
@@ -117,75 +123,79 @@ class RettangoliInputNumberElement extends HTMLElement {
117
123
  this._inputElement.focus();
118
124
  }
119
125
 
120
- _onChange = (event) => {
126
+ _emitValueEvent = (eventName) => {
121
127
  const inputValue = this._inputElement.value;
128
+ if (inputValue.trim() === "") {
129
+ this.dispatchEvent(new CustomEvent(eventName, {
130
+ detail: {
131
+ value: null,
132
+ },
133
+ bubbles: true,
134
+ }));
135
+ return;
136
+ }
137
+
122
138
  let numericValue = parseFloat(inputValue);
123
139
 
124
140
  // Only process if the value is a valid number (not NaN)
125
141
  if (!isNaN(numericValue)) {
126
- // Enforce minimum value if set
127
- const minAttr = this.getAttribute("min");
128
- if (minAttr !== null) {
129
- const minValue = parseFloat(minAttr);
130
- if (!isNaN(minValue) && numericValue < minValue) {
131
- numericValue = minValue;
132
- this._inputElement.value = minValue.toString();
133
- }
134
- }
135
-
136
- // Enforce maximum value if set
137
- const maxAttr = this.getAttribute("max");
138
- if (maxAttr !== null) {
139
- const maxValue = parseFloat(maxAttr);
140
- if (!isNaN(maxValue) && numericValue > maxValue) {
141
- numericValue = maxValue;
142
- this._inputElement.value = maxValue.toString();
143
- }
144
- }
142
+ numericValue = this._clampValueToBounds(numericValue);
143
+ this._inputElement.value = numericValue.toString();
145
144
 
146
- this.dispatchEvent(new CustomEvent('input-change', {
145
+ this.dispatchEvent(new CustomEvent(eventName, {
147
146
  detail: {
148
147
  value: numericValue,
149
148
  },
149
+ bubbles: true,
150
150
  }));
151
151
  }
152
152
  };
153
153
 
154
+ _onInput = () => {
155
+ this._emitValueEvent('value-input');
156
+ };
157
+
158
+ _onChange = () => {
159
+ this._emitValueEvent('value-change');
160
+ };
161
+
154
162
  attributeChangedCallback(name, oldValue, newValue) {
155
- if (name === 'value') {
156
- requestAnimationFrame((() => {
157
- const value = this.getAttribute("value");
158
- this._inputElement.value = value ?? "";
159
- }))
163
+ if (oldValue === newValue) {
164
+ return;
160
165
  }
161
166
 
162
- if (name === 'placeholder') {
163
- requestAnimationFrame((() => {
164
- const placeholder = this.getAttribute("placeholder");
165
- if (placeholder === undefined || placeholder === 'null') {
166
- this._inputElement.removeAttribute('placeholder');
167
- } else {
168
- this._inputElement.setAttribute('placeholder', placeholder ?? "");
169
- }
170
- }))
167
+ if (name === "key") {
168
+ this._syncValueAttribute();
169
+ return;
170
+ }
171
+
172
+ if (name === "value") {
173
+ this._syncValueAttribute();
174
+ return;
175
+ }
176
+
177
+ if (name === "placeholder") {
178
+ this._syncPlaceholderAttribute();
179
+ return;
171
180
  }
172
181
 
173
182
  // Handle input-specific attributes first
174
- if (["type", "disabled", "step", "min", "max", "s"].includes(name)) {
183
+ if (RettangoliInputNumberElement.inputSpecificAttributes.includes(name)) {
175
184
  this._updateInputAttributes();
185
+ if (name === "min" || name === "max") {
186
+ this._syncValueAttribute();
187
+ }
176
188
  return;
177
189
  }
178
190
 
191
+ this.updateStyles();
192
+ }
193
+
194
+ updateStyles() {
179
195
  // Reset styles for fresh calculation
180
- this._styles = {
181
- default: {},
182
- sm: {},
183
- md: {},
184
- lg: {},
185
- xl: {},
186
- };
187
-
188
- ["default", "sm", "md", "lg", "xl"].forEach((size) => {
196
+ this._styles = createResponsiveStyleBuckets();
197
+
198
+ responsiveStyleSizes.forEach((size) => {
189
199
  const addSizePrefix = (tag) => {
190
200
  return `${size === "default" ? "" : `${size}-`}${tag}`;
191
201
  };
@@ -208,28 +218,26 @@ class RettangoliInputNumberElement extends HTMLElement {
208
218
  this._styles[size].opacity = opacity;
209
219
  }
210
220
 
211
- if (width === "f") {
212
- this._styles[size].width = "var(--width-stretch)";
213
- } else if (width !== undefined) {
214
- this._styles[size].width = width;
215
- this._styles[size]["min-width"] = width;
216
- this._styles[size]["max-width"] = width;
217
- }
221
+ applyDimensionToStyleBucket({
222
+ styleBucket: this._styles[size],
223
+ axis: "width",
224
+ dimension: width,
225
+ fillValue: "var(--width-stretch)",
226
+ });
218
227
 
219
- if (height === "f") {
220
- this._styles[size].height = "100%";
221
- } else if (height !== undefined) {
222
- this._styles[size].height = height;
223
- this._styles[size]["min-height"] = height;
224
- this._styles[size]["max-height"] = height;
225
- }
228
+ applyDimensionToStyleBucket({
229
+ styleBucket: this._styles[size],
230
+ axis: "height",
231
+ dimension: height,
232
+ fillValue: "100%",
233
+ });
226
234
 
227
235
  if (this.hasAttribute(addSizePrefix("hide"))) {
228
- this._styles[size].display = "none !important";
236
+ this._styles[size].display = "none";
229
237
  }
230
238
 
231
239
  if (this.hasAttribute(addSizePrefix("show"))) {
232
- this._styles[size].display = "block !important";
240
+ this._styles[size].display = "block";
233
241
  }
234
242
  });
235
243
 
@@ -241,33 +249,68 @@ class RettangoliInputNumberElement extends HTMLElement {
241
249
  }
242
250
  }
243
251
 
244
- _updateInputAttributes() {
245
- const type = this.getAttribute("type") || "number";
246
- const step = this.getAttribute("step");
247
- const min = this.getAttribute("min");
248
- const max = this.getAttribute("max");
249
- const isDisabled = this.hasAttribute('disabled');
252
+ _setOrRemoveInputAttribute(name, value) {
253
+ if (value === null || value === undefined || value === "null") {
254
+ this._inputElement.removeAttribute(name);
255
+ return;
256
+ }
257
+ this._inputElement.setAttribute(name, value);
258
+ }
250
259
 
251
- this._inputElement.setAttribute("type", type);
260
+ _clampValueToBounds(value) {
261
+ let nextValue = value;
252
262
 
253
- if (step !== null) {
254
- this._inputElement.setAttribute("step", step);
255
- } else {
256
- this._inputElement.removeAttribute("step");
263
+ const minAttr = this.getAttribute("min");
264
+ if (minAttr !== null) {
265
+ const minValue = parseFloat(minAttr);
266
+ if (!isNaN(minValue)) {
267
+ nextValue = Math.max(nextValue, minValue);
268
+ }
257
269
  }
258
270
 
259
- if (min !== null) {
260
- this._inputElement.setAttribute("min", min);
261
- } else {
262
- this._inputElement.removeAttribute("min");
271
+ const maxAttr = this.getAttribute("max");
272
+ if (maxAttr !== null) {
273
+ const maxValue = parseFloat(maxAttr);
274
+ if (!isNaN(maxValue)) {
275
+ nextValue = Math.min(nextValue, maxValue);
276
+ }
263
277
  }
264
278
 
265
- if (max !== null) {
266
- this._inputElement.setAttribute("max", max);
267
- } else {
268
- this._inputElement.removeAttribute("max");
279
+ return nextValue;
280
+ }
281
+
282
+ _syncValueAttribute() {
283
+ const value = this.getAttribute("value");
284
+ if (value === null || value === undefined || value === "") {
285
+ this._inputElement.value = "";
286
+ return;
287
+ }
288
+
289
+ const numericValue = parseFloat(value);
290
+ if (isNaN(numericValue)) {
291
+ this._inputElement.value = "";
292
+ return;
269
293
  }
270
294
 
295
+ const clampedValue = this._clampValueToBounds(numericValue);
296
+ this._inputElement.value = clampedValue.toString();
297
+ }
298
+
299
+ _syncPlaceholderAttribute() {
300
+ this._setOrRemoveInputAttribute("placeholder", this.getAttribute("placeholder"));
301
+ }
302
+
303
+ _updateInputAttributes() {
304
+ const step = this.getAttribute("step");
305
+ const min = this.getAttribute("min");
306
+ const max = this.getAttribute("max");
307
+ const isDisabled = this.hasAttribute('disabled');
308
+
309
+ this._inputElement.setAttribute("type", "number");
310
+ this._setOrRemoveInputAttribute("step", step);
311
+ this._setOrRemoveInputAttribute("min", min);
312
+ this._setOrRemoveInputAttribute("max", max);
313
+
271
314
  if (isDisabled) {
272
315
  this._inputElement.setAttribute("disabled", "");
273
316
  } else {
@@ -277,6 +320,9 @@ class RettangoliInputNumberElement extends HTMLElement {
277
320
 
278
321
  connectedCallback() {
279
322
  this._updateInputAttributes();
323
+ this._syncValueAttribute();
324
+ this._syncPlaceholderAttribute();
325
+ this.updateStyles();
280
326
  }
281
327
  }
282
328
 
@@ -285,4 +331,4 @@ export default ({ render, html }) => {
285
331
  // Note: render and html parameters are accepted but not used
286
332
  // This maintains backward compatibility with existing code
287
333
  return RettangoliInputNumberElement;
288
- };
334
+ };