@rettangoli/ui 0.1.19 → 0.1.21

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.19",
3
+ "version": "0.1.21",
4
4
  "description": "A UI component library for building web interfaces.",
5
5
  "main": "dist/rettangoli-esm.min.js",
6
6
  "type": "module",
@@ -8,7 +8,7 @@ const updateAttributes = ({ form, defaultValues = {}, refs }) => {
8
8
  return;
9
9
  }
10
10
 
11
- if (['inputText', 'colorPicker', 'slider', 'slider-input', 'popover-input'].includes(field.inputType)) {
11
+ if (['input-textarea', 'inputText', 'input-text', 'input-number', 'colorPicker', 'slider', 'slider-input', 'popover-input'].includes(field.inputType)) {
12
12
  const defaultValue = defaultValues[field.name];
13
13
  if (defaultValue === undefined || defaultValue === null) {
14
14
  ref.removeAttribute('value')
@@ -16,7 +16,7 @@ const updateAttributes = ({ form, defaultValues = {}, refs }) => {
16
16
  ref.setAttribute('value', defaultValue)
17
17
  }
18
18
  }
19
- if (field.inputType === 'inputText' && field.placeholder) {
19
+ if (['inputText', 'input-text', 'input-textarea'].includes(field.inputType) && field.placeholder) {
20
20
  const currentPlaceholder = ref.getAttribute('placeholder')
21
21
  if (currentPlaceholder !== field.placeholder) {
22
22
  if (field.placeholder === undefined || field.placeholder === null) {
@@ -108,14 +108,15 @@ export const handleInputChange = (deps, payload) => {
108
108
  const event = payload._event;
109
109
  let name = event.currentTarget.id.replace("field-", "");
110
110
  if (name && event.detail.value !== undefined) {
111
+ const value = event.detail.value
111
112
  store.setFormFieldValue({
112
113
  name: name,
113
- value: event.detail.value,
114
+ value,
114
115
  props,
115
116
  });
116
117
  dispatchFormChange(
117
118
  name,
118
- event.detail.value,
119
+ value,
119
120
  store.selectFormValues(),
120
121
  dispatchEvent,
121
122
  );
@@ -303,8 +303,10 @@ events:
303
303
  template:
304
304
  - rtgl-view w=f p=md g=lg ${containerAttrString}:
305
305
  - rtgl-view g=sm w=f:
306
- - rtgl-text s=lg: ${title}
307
- - rtgl-text c=mu-fg: ${description}
306
+ - $if title:
307
+ - rtgl-text s=lg: ${title}
308
+ - $if description:
309
+ - rtgl-text c=mu-fg: ${description}
308
310
  - rtgl-view g=lg w=f:
309
311
  - $for field, i in fields:
310
312
  - rtgl-view g=md w=f:
@@ -316,8 +318,12 @@ template:
316
318
  - rtgl-text s=sm c=mu-fg: ${field.description}
317
319
  - $if field.inputType == "read-only-text":
318
320
  - rtgl-text s=sm: ${field.defaultValue}
319
- - $if field.inputType == "inputText":
320
- - rtgl-input#field-${field.name} w=f:
321
+ - $if field.inputType == "inputText" || field.inputType == 'input-text':
322
+ - rtgl-input#field-${field.name} w=f min=${field.min} max=${field.max} step=${field.step}:
323
+ - $if field.inputType == "input-number":
324
+ - rtgl-input-number#field-${field.name} w=f:
325
+ - $if field.inputType == "input-textarea":
326
+ - rtgl-textarea#field-${field.name} w=f rows=${field.rows} w=f:
321
327
  - $if field.inputType == "popover-input":
322
328
  - rtgl-popover-input#field-${field.name} label="${field.label}":
323
329
  - $if field.inputType == "select":
@@ -16,7 +16,7 @@ export const handleBeforeMount = (deps) => {
16
16
 
17
17
  export const handleOnUpdate = (deps, payload) => {
18
18
  const { oldAttrs, newAttrs, oldProps, newProps } = payload;
19
- const { store, props, render } = deps;
19
+ const { store, render } = deps;
20
20
 
21
21
  // Check if key changed
22
22
  if (oldAttrs?.key !== newAttrs?.key && newAttrs?.key) {
@@ -24,8 +24,8 @@ export const handleOnUpdate = (deps, payload) => {
24
24
  store.resetSelection();
25
25
 
26
26
  // Re-apply the prop value if available
27
- const selectedValue = newProps?.selectedValue || props?.selectedValue;
28
- const options = newProps?.options || props?.options;
27
+ const selectedValue = newProps?.selectedValue;
28
+ const options = newProps?.options || [];
29
29
 
30
30
  if (selectedValue !== null && selectedValue !== undefined && options) {
31
31
  const selectedOption = options.find(opt => deepEqual(opt.value, selectedValue));
@@ -37,7 +37,7 @@ export const handleOnUpdate = (deps, payload) => {
37
37
  }
38
38
  render();
39
39
  } else if (oldProps.selectedValue !== newProps.selectedValue) {
40
- store.updateSelectedValue(newProps.selectedValue);
40
+ store.updateSelectedValue({ value: newProps.selectedValue });
41
41
  render();
42
42
  }
43
43
  }
@@ -44,16 +44,16 @@ export const selectViewData = ({ state, props, attrs }) => {
44
44
  // Calculate display label from value
45
45
  let displayLabel = attrs.placeholder || 'Select an option';
46
46
  let isPlaceholderLabel = true;
47
- if (currentValue !== null && currentValue !== undefined && props.options) {
48
- const selectedOption = props.options.find(opt => deepEqual(opt.value, currentValue));
49
- if (selectedOption) {
50
- displayLabel = selectedOption.label;
51
- isPlaceholderLabel = false;
52
- }
47
+
48
+ const options = props.options || [];
49
+ const selectedOption = options.find(opt => deepEqual(opt.value, currentValue));
50
+ if (selectedOption) {
51
+ displayLabel = selectedOption.label;
52
+ isPlaceholderLabel = false;
53
53
  }
54
54
 
55
55
  // Map options to include isSelected flag and computed background color
56
- const optionsWithSelection = (props.options || []).map((option, index) => {
56
+ const optionsWithSelection = options.map((option, index) => {
57
57
  const isSelected = deepEqual(option.value, currentValue);
58
58
  const isHovered = state.hoveredOptionId === index;
59
59
  return {
@@ -4,6 +4,7 @@ import RettangoliText from './primitives/text.js';
4
4
  import RettangoliImage from './primitives/image.js';
5
5
  import RettangoliSvg from './primitives/svg.js';
6
6
  import RettangoliInput from './primitives/input.js';
7
+ import RettangoliInputNumber from './primitives/input-number.js';
7
8
  import RettangoliTextArea from './primitives/textarea.js';
8
9
  import RettangoliDialog from './primitives/dialog.js';
9
10
 
@@ -14,5 +15,6 @@ customElements.define("rtgl-text", RettangoliText({}));
14
15
  customElements.define("rtgl-image", RettangoliImage({}));
15
16
  customElements.define("rtgl-svg", RettangoliSvg({}));
16
17
  customElements.define("rtgl-input", RettangoliInput({}));
18
+ customElements.define("rtgl-input-number", RettangoliInputNumber({}));
17
19
  customElements.define("rtgl-textarea", RettangoliTextArea({}));
18
20
  customElements.define("rtgl-dialog", RettangoliDialog({}));
@@ -4,6 +4,7 @@ import RettangoliText from './primitives/text.js';
4
4
  import RettangoliImage from './primitives/image.js';
5
5
  import RettangoliSvg from './primitives/svg.js';
6
6
  import RettangoliInput from './primitives/input.js';
7
+ import RettangoliInputNumber from './primitives/input-number.js';
7
8
  import RettangoliTextArea from './primitives/textarea.js';
8
9
  import RettangoliColorPicker from './primitives/colorPicker.js';
9
10
  import RettangoliSlider from './primitives/slider.js';
@@ -16,6 +17,7 @@ customElements.define("rtgl-text", RettangoliText({}));
16
17
  customElements.define("rtgl-image", RettangoliImage({}));
17
18
  customElements.define("rtgl-svg", RettangoliSvg({}));
18
19
  customElements.define("rtgl-input", RettangoliInput({}));
20
+ customElements.define("rtgl-input-number", RettangoliInputNumber({}));
19
21
  customElements.define("rtgl-textarea", RettangoliTextArea({}));
20
22
  customElements.define("rtgl-color-picker", RettangoliColorPicker({}));
21
23
  customElements.define("rtgl-slider", RettangoliSlider({}));
package/src/index.js CHANGED
@@ -4,6 +4,7 @@ import RettangoliText from './primitives/text.js';
4
4
  import RettangoliImage from './primitives/image.js';
5
5
  import RettangoliSvg from './primitives/svg.js';
6
6
  import RettangoliInput from './primitives/input.js';
7
+ import RettangoliInputNumber from './primitives/input-number.js';
7
8
  import RettangoliTextArea from './primitives/textarea.js';
8
9
  import RettangoliDialog from './primitives/dialog.js';
9
10
  import RettangoliPopover from './primitives/popover.js';
@@ -16,6 +17,7 @@ export {
16
17
  RettangoliImage,
17
18
  RettangoliSvg,
18
19
  RettangoliInput,
20
+ RettangoliInputNumber,
19
21
  RettangoliTextArea,
20
22
  RettangoliDialog,
21
23
  RettangoliPopover,
@@ -0,0 +1,288 @@
1
+ import {
2
+ css,
3
+ dimensionWithUnit,
4
+ convertObjectToCssString,
5
+ styleMapKeys,
6
+ permutateBreakpoints,
7
+ } from "../common.js";
8
+ import cursorStyles from "../styles/cursorStyles.js";
9
+ import marginStyles from "../styles/marginStyles.js";
10
+
11
+ // Internal implementation without uhtml
12
+ class RettangoliInputNumberElement extends HTMLElement {
13
+ static styleSheet = null;
14
+
15
+ static initializeStyleSheet() {
16
+ if (!RettangoliInputNumberElement.styleSheet) {
17
+ RettangoliInputNumberElement.styleSheet = new CSSStyleSheet();
18
+ RettangoliInputNumberElement.styleSheet.replaceSync(css`
19
+ :host {
20
+ display: contents;
21
+ }
22
+ input {
23
+ background-color: var(--background);
24
+ font-size: var(--sm-font-size);
25
+ font-weight: var(--sm-font-weight);
26
+ line-height: var(--sm-line-height);
27
+ letter-spacing: var(--sm-letter-spacing);
28
+ border: 1px solid var(--ring);
29
+ border-radius: var(--border-radius-lg);
30
+ padding-left: var(--spacing-md);
31
+ padding-right: var(--spacing-md);
32
+ height: 32px;
33
+ color: var(--foreground);
34
+ outline: none;
35
+ }
36
+ :host([s="sm"]) input {
37
+ font-size: var(--xs-font-size);
38
+ font-weight: var(--xs-font-weight);
39
+ line-height: var(--xs-line-height);
40
+ letter-spacing: var(--xs-letter-spacing);
41
+ padding-left: var(--spacing-md);
42
+ padding-right: var(--spacing-md);
43
+ height: 24px;
44
+ }
45
+ input:focus {
46
+ border-color: var(--foreground);
47
+ }
48
+ input:disabled {
49
+ cursor: not-allowed;
50
+ }
51
+ ${marginStyles}
52
+ ${cursorStyles}
53
+ `);
54
+ }
55
+ }
56
+
57
+ constructor() {
58
+ super();
59
+ RettangoliInputNumberElement.initializeStyleSheet();
60
+ this.shadow = this.attachShadow({ mode: "closed" });
61
+ this.shadow.adoptedStyleSheets = [RettangoliInputNumberElement.styleSheet];
62
+
63
+ // Initialize style tracking properties
64
+ this._styles = {
65
+ default: {},
66
+ sm: {},
67
+ md: {},
68
+ lg: {},
69
+ xl: {},
70
+ };
71
+ this._lastStyleString = "";
72
+
73
+ // Create initial DOM structure
74
+ this._inputElement = document.createElement('input');
75
+ this._styleElement = document.createElement('style');
76
+
77
+ this.shadow.appendChild(this._styleElement);
78
+ this.shadow.appendChild(this._inputElement);
79
+
80
+ // Bind event handler
81
+ this._inputElement.addEventListener('input', this._onChange);
82
+ }
83
+
84
+ static get observedAttributes() {
85
+ return [
86
+ "key",
87
+ "type",
88
+ "placeholder",
89
+ "disabled",
90
+ "value",
91
+ "step",
92
+ "min",
93
+ "max",
94
+ "s",
95
+ ...permutateBreakpoints([
96
+ ...styleMapKeys,
97
+ "wh",
98
+ "w",
99
+ "h",
100
+ "hide",
101
+ "show",
102
+ "op",
103
+ "z",
104
+ ])
105
+ ];
106
+ }
107
+
108
+ get value() {
109
+ return this._inputElement.value;
110
+ }
111
+
112
+ set value(newValue) {
113
+ this._inputElement.value = newValue;
114
+ }
115
+
116
+ focus() {
117
+ this._inputElement.focus();
118
+ }
119
+
120
+ _onChange = (event) => {
121
+ const inputValue = this._inputElement.value;
122
+ let numericValue = parseFloat(inputValue);
123
+
124
+ // Only process if the value is a valid number (not NaN)
125
+ 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
+ }
145
+
146
+ this.dispatchEvent(new CustomEvent('input-change', {
147
+ detail: {
148
+ value: numericValue,
149
+ },
150
+ }));
151
+ }
152
+ };
153
+
154
+ attributeChangedCallback(name, oldValue, newValue) {
155
+ if (name === 'value') {
156
+ requestAnimationFrame((() => {
157
+ const value = this.getAttribute("value");
158
+ this._inputElement.value = value ?? "";
159
+ }))
160
+ }
161
+
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
+ }))
171
+ }
172
+
173
+ // Handle input-specific attributes first
174
+ if (["type", "disabled", "step", "min", "max", "s"].includes(name)) {
175
+ this._updateInputAttributes();
176
+ return;
177
+ }
178
+
179
+ // 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) => {
189
+ const addSizePrefix = (tag) => {
190
+ return `${size === "default" ? "" : `${size}-`}${tag}`;
191
+ };
192
+
193
+ const wh = this.getAttribute(addSizePrefix("wh"));
194
+ const width = dimensionWithUnit(
195
+ wh === null ? this.getAttribute(addSizePrefix("w")) : wh,
196
+ );
197
+ const height = dimensionWithUnit(
198
+ wh === null ? this.getAttribute(addSizePrefix("h")) : wh,
199
+ );
200
+ const opacity = this.getAttribute(addSizePrefix("op"));
201
+ const zIndex = this.getAttribute(addSizePrefix("z"));
202
+
203
+ if (zIndex !== null) {
204
+ this._styles[size]["z-index"] = zIndex;
205
+ }
206
+
207
+ if (opacity !== null) {
208
+ this._styles[size].opacity = opacity;
209
+ }
210
+
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
+ }
218
+
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
+ }
226
+
227
+ if (this.hasAttribute(addSizePrefix("hide"))) {
228
+ this._styles[size].display = "none !important";
229
+ }
230
+
231
+ if (this.hasAttribute(addSizePrefix("show"))) {
232
+ this._styles[size].display = "block !important";
233
+ }
234
+ });
235
+
236
+ // Update styles only if changed - targeting input element
237
+ const newStyleString = convertObjectToCssString(this._styles, 'input');
238
+ if (newStyleString !== this._lastStyleString) {
239
+ this._styleElement.textContent = newStyleString;
240
+ this._lastStyleString = newStyleString;
241
+ }
242
+ }
243
+
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');
250
+
251
+ this._inputElement.setAttribute("type", type);
252
+
253
+ if (step !== null) {
254
+ this._inputElement.setAttribute("step", step);
255
+ } else {
256
+ this._inputElement.removeAttribute("step");
257
+ }
258
+
259
+ if (min !== null) {
260
+ this._inputElement.setAttribute("min", min);
261
+ } else {
262
+ this._inputElement.removeAttribute("min");
263
+ }
264
+
265
+ if (max !== null) {
266
+ this._inputElement.setAttribute("max", max);
267
+ } else {
268
+ this._inputElement.removeAttribute("max");
269
+ }
270
+
271
+ if (isDisabled) {
272
+ this._inputElement.setAttribute("disabled", "");
273
+ } else {
274
+ this._inputElement.removeAttribute("disabled");
275
+ }
276
+ }
277
+
278
+ connectedCallback() {
279
+ this._updateInputAttributes();
280
+ }
281
+ }
282
+
283
+ // Export factory function to maintain API compatibility
284
+ export default ({ render, html }) => {
285
+ // Note: render and html parameters are accepted but not used
286
+ // This maintains backward compatibility with existing code
287
+ return RettangoliInputNumberElement;
288
+ };
@@ -1,4 +1,10 @@
1
- import { css, dimensionWithUnit } from "../common.js";
1
+ import {
2
+ css,
3
+ dimensionWithUnit,
4
+ convertObjectToCssString,
5
+ styleMapKeys,
6
+ permutateBreakpoints,
7
+ } from "../common.js";
2
8
  import cursorStyles from "../styles/cursorStyles.js";
3
9
  import marginStyles from "../styles/marginStyles.js";
4
10
 
@@ -43,10 +49,23 @@ class RettangoliTextAreaElement extends HTMLElement {
43
49
  RettangoliTextAreaElement.initializeStyleSheet();
44
50
  this.shadow = this.attachShadow({ mode: "closed" });
45
51
  this.shadow.adoptedStyleSheets = [RettangoliTextAreaElement.styleSheet];
46
-
52
+
53
+ // Initialize style tracking properties
54
+ this._styles = {
55
+ default: {},
56
+ sm: {},
57
+ md: {},
58
+ lg: {},
59
+ xl: {},
60
+ };
61
+ this._lastStyleString = "";
62
+
47
63
  // Create initial DOM structure
48
64
  this._textareaElement = document.createElement('textarea');
49
65
  this._textareaElement.setAttribute('type', 'text');
66
+ this._styleElement = document.createElement('style');
67
+
68
+ this.shadow.appendChild(this._styleElement);
50
69
  this.shadow.appendChild(this._textareaElement);
51
70
 
52
71
  // Bind event handler
@@ -62,7 +81,26 @@ class RettangoliTextAreaElement extends HTMLElement {
62
81
  };
63
82
 
64
83
  static get observedAttributes() {
65
- return ["key", "w", "ellipsis", "cols", "rows", "placeholder", "value"];
84
+ return [
85
+ "key",
86
+ "type",
87
+ "placeholder",
88
+ "disabled",
89
+ "value",
90
+ "cols",
91
+ "rows",
92
+ "ellipsis",
93
+ ...permutateBreakpoints([
94
+ ...styleMapKeys,
95
+ "wh",
96
+ "w",
97
+ "h",
98
+ "hide",
99
+ "show",
100
+ "op",
101
+ "z",
102
+ ])
103
+ ];
66
104
  }
67
105
 
68
106
  get value() {
@@ -78,22 +116,99 @@ class RettangoliTextAreaElement extends HTMLElement {
78
116
  }
79
117
 
80
118
  attributeChangedCallback(name, oldValue, newValue) {
81
- // Handle key attribute change - reset value
82
- if (name === "key" && oldValue !== newValue) {
83
- requestAnimationFrame(() => {
119
+ if (name === 'value') {
120
+ requestAnimationFrame((() => {
84
121
  const value = this.getAttribute("value");
85
122
  this._textareaElement.value = value ?? "";
86
- });
123
+ }))
124
+ }
125
+
126
+ if (name === 'placeholder') {
127
+ requestAnimationFrame((() => {
128
+ const placeholder = this.getAttribute("placeholder");
129
+ if (placeholder === undefined || placeholder === 'null') {
130
+ this._textareaElement.removeAttribute('placeholder');
131
+ } else {
132
+ this._textareaElement.setAttribute('placeholder', placeholder ?? "");
133
+ }
134
+ }))
135
+ }
136
+
137
+ // Handle textarea-specific attributes first
138
+ if (["cols", "rows", "disabled"].includes(name)) {
139
+ this._updateTextareaAttributes();
87
140
  return;
88
141
  }
89
- this._updateTextareaAttributes();
142
+
143
+ // Reset styles for fresh calculation
144
+ this._styles = {
145
+ default: {},
146
+ sm: {},
147
+ md: {},
148
+ lg: {},
149
+ xl: {},
150
+ };
151
+
152
+ ["default", "sm", "md", "lg", "xl"].forEach((size) => {
153
+ const addSizePrefix = (tag) => {
154
+ return `${size === "default" ? "" : `${size}-`}${tag}`;
155
+ };
156
+
157
+ const wh = this.getAttribute(addSizePrefix("wh"));
158
+ const width = dimensionWithUnit(
159
+ wh === null ? this.getAttribute(addSizePrefix("w")) : wh,
160
+ );
161
+ const height = dimensionWithUnit(
162
+ wh === null ? this.getAttribute(addSizePrefix("h")) : wh,
163
+ );
164
+ const opacity = this.getAttribute(addSizePrefix("op"));
165
+ const zIndex = this.getAttribute(addSizePrefix("z"));
166
+
167
+ if (zIndex !== null) {
168
+ this._styles[size]["z-index"] = zIndex;
169
+ }
170
+
171
+ if (opacity !== null) {
172
+ this._styles[size].opacity = opacity;
173
+ }
174
+
175
+ if (width === "f") {
176
+ this._styles[size].width = "var(--width-stretch)";
177
+ } else if (width !== undefined) {
178
+ this._styles[size].width = width;
179
+ this._styles[size]["min-width"] = width;
180
+ this._styles[size]["max-width"] = width;
181
+ }
182
+
183
+ if (height === "f") {
184
+ this._styles[size].height = "100%";
185
+ } else if (height !== undefined) {
186
+ this._styles[size].height = height;
187
+ this._styles[size]["min-height"] = height;
188
+ this._styles[size]["max-height"] = height;
189
+ }
190
+
191
+ if (this.hasAttribute(addSizePrefix("hide"))) {
192
+ this._styles[size].display = "none !important";
193
+ }
194
+
195
+ if (this.hasAttribute(addSizePrefix("show"))) {
196
+ this._styles[size].display = "block !important";
197
+ }
198
+ });
199
+
200
+ // Update styles only if changed - targeting textarea element
201
+ const newStyleString = convertObjectToCssString(this._styles, 'textarea');
202
+ if (newStyleString !== this._lastStyleString) {
203
+ this._styleElement.textContent = newStyleString;
204
+ this._lastStyleString = newStyleString;
205
+ }
90
206
  }
91
207
 
92
208
  _updateTextareaAttributes() {
93
209
  const cols = this.getAttribute("cols");
94
210
  const rows = this.getAttribute("rows");
95
- const placeholder = this.getAttribute("placeholder");
96
- const value = this.getAttribute("value");
211
+ const isDisabled = this.hasAttribute('disabled');
97
212
 
98
213
  if (cols !== null) {
99
214
  this._textareaElement.setAttribute("cols", cols);
@@ -107,14 +222,10 @@ class RettangoliTextAreaElement extends HTMLElement {
107
222
  this._textareaElement.removeAttribute("rows");
108
223
  }
109
224
 
110
- if (placeholder !== null) {
111
- this._textareaElement.setAttribute("placeholder", placeholder);
225
+ if (isDisabled) {
226
+ this._textareaElement.setAttribute("disabled", "");
112
227
  } else {
113
- this._textareaElement.removeAttribute("placeholder");
114
- }
115
-
116
- if (value !== null) {
117
- this._textareaElement.value = value;
228
+ this._textareaElement.removeAttribute("disabled");
118
229
  }
119
230
  }
120
231
  }