@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
@@ -1,7 +1,12 @@
1
- import { css, dimensionWithUnit } from "../common.js";
2
- import flexChildStyles from "../styles/flexChildStyles.js";
1
+ import { css, dimensionWithUnit, applyLinkAttributes } from "../common.js";
3
2
  import buttonMarginStyles from "../styles/buttonMarginStyles.js";
4
- import anchorStyles from "../styles/anchorStyles.js";
3
+
4
+ const responsiveSizeBreakpoints = [
5
+ { prefix: "sm", maxWidth: 640 },
6
+ { prefix: "md", maxWidth: 768 },
7
+ { prefix: "lg", maxWidth: 1024 },
8
+ { prefix: "xl", maxWidth: 1280 },
9
+ ];
5
10
 
6
11
  // Internal implementation without uhtml
7
12
  class RettangoliButtonElement extends HTMLElement {
@@ -12,13 +17,13 @@ class RettangoliButtonElement extends HTMLElement {
12
17
  RettangoliButtonElement.styleSheet = new CSSStyleSheet();
13
18
  RettangoliButtonElement.styleSheet.replaceSync(css`
14
19
  :host {
15
- display: contents;
20
+ display: inline-flex;
16
21
  }
17
22
  slot {
18
23
  display: contents;
19
24
  }
20
25
 
21
- button {
26
+ .surface {
22
27
  display: flex;
23
28
  flex-direction: row;
24
29
  align-items: center;
@@ -40,9 +45,19 @@ class RettangoliButtonElement extends HTMLElement {
40
45
 
41
46
  background-color: var(--primary);
42
47
  color: var(--primary-foreground);
48
+ text-decoration: none;
49
+ }
50
+
51
+ a.surface,
52
+ a.surface:link,
53
+ a.surface:visited,
54
+ a.surface:hover,
55
+ a.surface:active {
56
+ color: inherit;
57
+ text-decoration: none;
43
58
  }
44
59
 
45
- button:hover {
60
+ .surface:hover {
46
61
  cursor: pointer;
47
62
  background-color: color-mix(
48
63
  in srgb,
@@ -51,11 +66,11 @@ class RettangoliButtonElement extends HTMLElement {
51
66
  );
52
67
  }
53
68
 
54
- button:disabled {
69
+ :host([disabled]) .surface {
55
70
  cursor: not-allowed;
56
71
  }
57
72
 
58
- button:active {
73
+ .surface:active {
59
74
  cursor: pointer;
60
75
  background-color: color-mix(
61
76
  in srgb,
@@ -64,7 +79,7 @@ class RettangoliButtonElement extends HTMLElement {
64
79
  );
65
80
  }
66
81
 
67
- :host([v="pr"]) button:hover {
82
+ :host([v="pr"]) .surface:hover {
68
83
  background-color: color-mix(
69
84
  in srgb,
70
85
  var(--primary) 85%,
@@ -72,7 +87,7 @@ class RettangoliButtonElement extends HTMLElement {
72
87
  );
73
88
  }
74
89
 
75
- :host([v="pr"]) button:active {
90
+ :host([v="pr"]) .surface:active {
76
91
  background-color: color-mix(
77
92
  in srgb,
78
93
  var(--primary) 80%,
@@ -80,7 +95,7 @@ class RettangoliButtonElement extends HTMLElement {
80
95
  );
81
96
  }
82
97
 
83
- :host([v="se"]) button:hover {
98
+ :host([v="se"]) .surface:hover {
84
99
  background-color: color-mix(
85
100
  in srgb,
86
101
  var(--secondary) 85%,
@@ -88,7 +103,7 @@ class RettangoliButtonElement extends HTMLElement {
88
103
  );
89
104
  }
90
105
 
91
- :host([v="se"]) button:active {
106
+ :host([v="se"]) .surface:active {
92
107
  background-color: color-mix(
93
108
  in srgb,
94
109
  var(--secondary) 80%,
@@ -96,7 +111,7 @@ class RettangoliButtonElement extends HTMLElement {
96
111
  );
97
112
  }
98
113
 
99
- :host([v="de"]) button:hover {
114
+ :host([v="de"]) .surface:hover {
100
115
  background-color: color-mix(
101
116
  in srgb,
102
117
  var(--destructive) 85%,
@@ -104,7 +119,7 @@ class RettangoliButtonElement extends HTMLElement {
104
119
  );
105
120
  }
106
121
 
107
- :host([v="de"]) button:active {
122
+ :host([v="de"]) .surface:active {
108
123
  background-color: color-mix(
109
124
  in srgb,
110
125
  var(--destructive) 80%,
@@ -112,48 +127,45 @@ class RettangoliButtonElement extends HTMLElement {
112
127
  );
113
128
  }
114
129
 
115
- :host([v="ol"]) button:hover {
130
+ :host([v="ol"]) .surface:hover {
116
131
  background-color: var(--accent);
117
132
  }
118
133
 
119
- :host([v="gh"]) button:hover {
134
+ :host([v="gh"]) .surface:hover {
120
135
  background-color: var(--accent);
121
136
  }
122
137
 
123
- :host([v="lk"]) button:hover {
138
+ :host([v="lk"]) .surface:hover {
124
139
  text-decoration: underline;
125
140
  }
126
141
 
127
142
  /* Square button styles */
128
- :host([sq]) button {
143
+ :host([sq]) .surface {
129
144
  width: 32px;
130
145
  height: 32px;
131
146
  padding: 0;
132
147
  gap: 0;
133
148
  }
134
149
 
135
- :host([sq][s="sm"]) button {
150
+ :host([sq][s="sm"]) .surface {
136
151
  width: 24px;
137
152
  height: 24px;
138
153
  padding: 0;
139
154
  gap: 0;
140
155
  }
141
156
 
142
- :host([sq][s="lg"]) button {
157
+ :host([sq][s="lg"]) .surface {
143
158
  width: 40px;
144
159
  height: 40px;
145
160
  padding: 0;
146
161
  gap: 0;
147
162
  }
148
163
 
149
- ${anchorStyles}
150
-
151
- a {
152
- display: contents;
164
+ .surface rtgl-svg {
165
+ color: inherit;
153
166
  }
154
167
 
155
168
  ${buttonMarginStyles}
156
- ${flexChildStyles}
157
169
  `);
158
170
  }
159
171
  }
@@ -166,118 +178,181 @@ class RettangoliButtonElement extends HTMLElement {
166
178
 
167
179
  // Create initial DOM structure
168
180
  this._containerElement = null;
169
- this._buttonElement = document.createElement('button');
181
+ this._surfaceElement = document.createElement('button');
170
182
  this._slotElement = document.createElement('slot');
171
- this._iconElement = null;
183
+ this._prefixIcon = null;
184
+ this._suffixIcon = null;
172
185
 
173
- this._buttonElement.appendChild(this._slotElement);
186
+ this._surfaceElement.className = 'surface';
187
+ this._surfaceElement.appendChild(this._slotElement);
188
+
189
+ this._onWindowResize = this._onWindowResize.bind(this);
174
190
  }
175
191
 
176
192
  static get observedAttributes() {
177
- return ["key", "href", "target", "w", "icon", "disabled", "v", "s", "sq", "ip"];
193
+ return [
194
+ "key",
195
+ "href",
196
+ "new-tab",
197
+ "rel",
198
+ "w",
199
+ "pre",
200
+ "suf",
201
+ "disabled",
202
+ "v",
203
+ "s",
204
+ "sq",
205
+ "sm-s",
206
+ "md-s",
207
+ "lg-s",
208
+ "xl-s",
209
+ ];
178
210
  }
179
211
 
180
212
  connectedCallback() {
213
+ window.addEventListener("resize", this._onWindowResize);
181
214
  this._updateButton();
182
215
  }
183
216
 
217
+ disconnectedCallback() {
218
+ window.removeEventListener("resize", this._onWindowResize);
219
+ }
220
+
184
221
  attributeChangedCallback(name, oldValue, newValue) {
185
222
  this._updateButton();
186
223
  }
187
224
 
225
+ _onWindowResize() {
226
+ if (
227
+ this.hasAttribute("sm-s") ||
228
+ this.hasAttribute("md-s") ||
229
+ this.hasAttribute("lg-s") ||
230
+ this.hasAttribute("xl-s")
231
+ ) {
232
+ this._updateIcon();
233
+ }
234
+ }
235
+
236
+ _resolveResponsiveSizeToken() {
237
+ const viewportWidth = window.innerWidth;
238
+
239
+ for (const { prefix, maxWidth } of responsiveSizeBreakpoints) {
240
+ const responsiveAttrName = `${prefix}-s`;
241
+ if (viewportWidth <= maxWidth && this.hasAttribute(responsiveAttrName)) {
242
+ return this.getAttribute(responsiveAttrName);
243
+ }
244
+ }
245
+
246
+ return this.getAttribute("s");
247
+ }
248
+
188
249
  _updateButton() {
189
250
  // Clear shadow DOM
190
251
  this.shadow.innerHTML = '';
191
-
192
- // Update icon
252
+
253
+ // Update disabled state
254
+ const isDisabled = this.hasAttribute('disabled');
255
+ const href = this.getAttribute("href");
256
+ const newTab = this.hasAttribute("new-tab");
257
+ const rel = this.getAttribute("rel");
258
+
259
+ const shouldUseAnchor = href && !isDisabled;
260
+ const requiredTag = shouldUseAnchor ? "a" : "button";
261
+ if (this._surfaceElement.tagName.toLowerCase() !== requiredTag) {
262
+ const nextSurfaceElement = document.createElement(requiredTag);
263
+ nextSurfaceElement.className = 'surface';
264
+ nextSurfaceElement.appendChild(this._slotElement);
265
+ this._surfaceElement = nextSurfaceElement;
266
+ }
267
+
268
+ // Update icon after surface element is finalized so icons are attached
269
+ // to the active tag (<button> or <a>) consistently.
193
270
  this._updateIcon();
194
-
195
- // Update width styling (skip for square buttons)
271
+
196
272
  if (!this.hasAttribute('sq')) {
197
273
  this._updateWidth();
198
- }
199
-
200
- // Update disabled state
201
- const isDisabled = this.hasAttribute('disabled');
202
- if (isDisabled) {
203
- this._buttonElement.setAttribute('disabled', '');
204
274
  } else {
205
- this._buttonElement.removeAttribute('disabled');
275
+ this.style.width = "";
276
+ this.style.minWidth = "";
277
+ this.style.maxWidth = "";
278
+ this._surfaceElement.style.width = "";
279
+ this._surfaceElement.style.minWidth = "";
280
+ this._surfaceElement.style.maxWidth = "";
206
281
  }
207
-
208
- // Handle href (link) vs button
209
- const href = this.getAttribute("href");
210
- if (href) {
211
- // Create anchor wrapper
212
- const anchorElement = document.createElement('a');
213
- anchorElement.setAttribute('href', href);
214
-
215
- const target = this.getAttribute("target");
216
- if (target) {
217
- anchorElement.setAttribute('target', target);
218
- }
219
-
220
- anchorElement.appendChild(this._buttonElement);
221
- this.shadow.appendChild(anchorElement);
222
- this._containerElement = anchorElement;
282
+
283
+ if (shouldUseAnchor) {
284
+ applyLinkAttributes({
285
+ linkElement: this._surfaceElement,
286
+ href,
287
+ newTab,
288
+ rel,
289
+ });
290
+ this._surfaceElement.removeAttribute("disabled");
223
291
  } else {
224
- // Direct button
225
- this.shadow.appendChild(this._buttonElement);
226
- this._containerElement = this._buttonElement;
292
+ this._surfaceElement.removeAttribute("href");
293
+ this._surfaceElement.removeAttribute("target");
294
+ this._surfaceElement.removeAttribute("rel");
295
+ if (isDisabled) {
296
+ this._surfaceElement.setAttribute("disabled", "");
297
+ } else {
298
+ this._surfaceElement.removeAttribute("disabled");
299
+ }
227
300
  }
301
+
302
+ this.shadow.appendChild(this._surfaceElement);
303
+ this._containerElement = this._surfaceElement;
228
304
  }
229
305
 
230
306
  _updateIcon() {
231
- // Remove existing icon if any
232
- if (this._iconElement) {
233
- this._iconElement.remove();
234
- this._iconElement = null;
307
+ // Remove existing icons if any
308
+ if (this._prefixIcon) {
309
+ this._prefixIcon.remove();
310
+ this._prefixIcon = null;
235
311
  }
236
-
237
- const icon = this.getAttribute("icon");
238
- if (icon) {
239
- const colorMap = {
240
- pr: 'pr-fg',
241
- se: 'ac-fg',
242
- de: 'pr-fg',
243
- ol: 'ac-fg',
244
- gh: 'ac-fg',
245
- lk: 'ac-fg'
246
- };
247
- const iconSizeMap = {
312
+ if (this._suffixIcon) {
313
+ this._suffixIcon.remove();
314
+ this._suffixIcon = null;
315
+ }
316
+
317
+ const iconSizeMap = {
318
+ sm: 14,
319
+ md: 18,
320
+ lg: 22
321
+ };
322
+
323
+ // For square buttons, use button size token, otherwise use icon size token.
324
+ const resolvedSizeToken = this._resolveResponsiveSizeToken();
325
+ let size = 18; // default
326
+ if (this.hasAttribute('sq')) {
327
+ const buttonSizeMap = {
248
328
  sm: 14,
249
- md: 18,
250
329
  lg: 22
251
330
  };
252
- const color = colorMap[this.getAttribute("v")] || 'pr-fg';
253
-
254
- // For square buttons, use button size (s attribute), otherwise use icon size (t attribute)
255
- let size = 18; // default
256
- if (this.hasAttribute('sq')) {
257
- const buttonSizeMap = {
258
- sm: 14,
259
- lg: 22
260
- };
261
- const buttonSize = this.getAttribute("s");
262
- size = buttonSizeMap[buttonSize] || 18;
263
- } else {
264
- size = iconSizeMap[this.getAttribute("s")] || 18;
265
- }
266
-
267
- this._iconElement = document.createElement('rtgl-svg');
268
- this._iconElement.setAttribute('svg', icon);
269
- this._iconElement.setAttribute('c', color);
270
- this._iconElement.setAttribute('wh', size.toString());
271
-
272
- // Insert icon based on position (default is right, 's' means start/left)
273
- const iconPosition = this.getAttribute("ip");
274
- if (iconPosition === 's') {
275
- // Insert icon before slot (left position)
276
- this._buttonElement.insertBefore(this._iconElement, this._slotElement);
277
- } else {
278
- // Insert icon after slot (right position - default)
279
- this._buttonElement.appendChild(this._iconElement);
280
- }
331
+ size = buttonSizeMap[resolvedSizeToken] || 18;
332
+ } else {
333
+ size = iconSizeMap[resolvedSizeToken] || 18;
334
+ }
335
+
336
+ // Create prefix icon (before text)
337
+ const prefixIcon = this.getAttribute("pre");
338
+ if (prefixIcon) {
339
+ this._prefixIcon = document.createElement('rtgl-svg');
340
+ this._prefixIcon.setAttribute('svg', prefixIcon);
341
+ this._prefixIcon.setAttribute('wh', size.toString());
342
+ this._prefixIcon.style.color = "inherit";
343
+ // Insert before slot (left position)
344
+ this._surfaceElement.insertBefore(this._prefixIcon, this._slotElement);
345
+ }
346
+
347
+ // Create suffix icon (after text)
348
+ const suffixIcon = this.getAttribute("suf");
349
+ if (suffixIcon) {
350
+ this._suffixIcon = document.createElement('rtgl-svg');
351
+ this._suffixIcon.setAttribute('svg', suffixIcon);
352
+ this._suffixIcon.setAttribute('wh', size.toString());
353
+ this._suffixIcon.style.color = "inherit";
354
+ // Insert after slot (right position)
355
+ this._surfaceElement.appendChild(this._suffixIcon);
281
356
  }
282
357
  }
283
358
 
@@ -285,23 +360,34 @@ class RettangoliButtonElement extends HTMLElement {
285
360
  const width = dimensionWithUnit(this.getAttribute("w"));
286
361
 
287
362
  if (width === "f") {
288
- this._buttonElement.style.width = "var(--width-stretch)";
363
+ this.style.width = "var(--width-stretch)";
364
+ this.style.minWidth = "";
365
+ this.style.maxWidth = "";
366
+ this._surfaceElement.style.width = "100%";
367
+ this._surfaceElement.style.minWidth = "";
368
+ this._surfaceElement.style.maxWidth = "";
289
369
  } else if (width !== undefined && width !== null) {
290
- this._buttonElement.style.width = width;
291
- this._buttonElement.style.minWidth = width;
292
- this._buttonElement.style.maxWidth = width;
370
+ this.style.width = width;
371
+ this.style.minWidth = width;
372
+ this.style.maxWidth = width;
373
+ this._surfaceElement.style.width = "100%";
374
+ this._surfaceElement.style.minWidth = "";
375
+ this._surfaceElement.style.maxWidth = "";
293
376
  } else {
294
- this._buttonElement.style.width = "";
295
- this._buttonElement.style.minWidth = "";
296
- this._buttonElement.style.maxWidth = "";
377
+ this.style.width = "";
378
+ this.style.minWidth = "";
379
+ this.style.maxWidth = "";
380
+ this._surfaceElement.style.width = "";
381
+ this._surfaceElement.style.minWidth = "";
382
+ this._surfaceElement.style.maxWidth = "";
297
383
  }
298
384
  }
299
385
 
300
386
  // Public method to get the actual button's bounding rect
301
387
  // This is needed because the host element has display: contents
302
388
  getBoundingClientRect() {
303
- if (this._buttonElement) {
304
- return this._buttonElement.getBoundingClientRect();
389
+ if (this._surfaceElement) {
390
+ return this._surfaceElement.getBoundingClientRect();
305
391
  }
306
392
  // Fallback to host element
307
393
  return super.getBoundingClientRect();
@@ -1,13 +1,18 @@
1
- import {
2
- css,
1
+ import {
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 colorPickerStyleMapKeys = ["mt", "mr", "mb", "ml", "m", "mh", "mv", "cur"];
14
+ const HEX_COLOR_REGEX = /^#[0-9a-fA-F]{6}$/;
15
+
11
16
  // Internal implementation without uhtml
12
17
  class RettangoliColorPickerElement extends HTMLElement {
13
18
  static styleSheet = null;
@@ -49,13 +54,7 @@ class RettangoliColorPickerElement extends HTMLElement {
49
54
  this.shadow.adoptedStyleSheets = [RettangoliColorPickerElement.styleSheet];
50
55
 
51
56
  // Initialize style tracking properties
52
- this._styles = {
53
- default: {},
54
- sm: {},
55
- md: {},
56
- lg: {},
57
- xl: {},
58
- };
57
+ this._styles = createResponsiveStyleBuckets();
59
58
  this._lastStyleString = "";
60
59
 
61
60
  // Create initial DOM structure
@@ -77,7 +76,7 @@ class RettangoliColorPickerElement extends HTMLElement {
77
76
  "value",
78
77
  "disabled",
79
78
  ...permutateBreakpoints([
80
- ...styleMapKeys,
79
+ ...colorPickerStyleMapKeys,
81
80
  "wh",
82
81
  "w",
83
82
  "h",
@@ -97,29 +96,32 @@ class RettangoliColorPickerElement extends HTMLElement {
97
96
  this._inputElement.value = newValue;
98
97
  }
99
98
 
100
- _onChange = (event) => {
101
- this.dispatchEvent(new CustomEvent('colorpicker-change', {
99
+ _onChange = () => {
100
+ this.dispatchEvent(new CustomEvent('value-change', {
102
101
  detail: {
103
102
  value: this._inputElement.value,
104
103
  },
104
+ bubbles: true,
105
105
  }));
106
106
  };
107
107
 
108
- _onInput = (event) => {
109
- this.dispatchEvent(new CustomEvent('colorpicker-input', {
108
+ _onInput = () => {
109
+ this.dispatchEvent(new CustomEvent('value-input', {
110
110
  detail: {
111
111
  value: this._inputElement.value,
112
112
  },
113
+ bubbles: true,
113
114
  }));
114
115
  };
115
116
 
116
117
  attributeChangedCallback(name, oldValue, newValue) {
118
+ if (oldValue === newValue) {
119
+ return;
120
+ }
121
+
117
122
  // 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
+ if (name === "key") {
124
+ this._syncValueAttribute();
123
125
  return;
124
126
  }
125
127
 
@@ -129,16 +131,14 @@ class RettangoliColorPickerElement extends HTMLElement {
129
131
  return;
130
132
  }
131
133
 
134
+ this.updateStyles();
135
+ }
136
+
137
+ updateStyles() {
132
138
  // Reset styles for fresh calculation
133
- this._styles = {
134
- default: {},
135
- sm: {},
136
- md: {},
137
- lg: {},
138
- xl: {},
139
- };
140
-
141
- ["default", "sm", "md", "lg", "xl"].forEach((size) => {
139
+ this._styles = createResponsiveStyleBuckets();
140
+
141
+ responsiveStyleSizes.forEach((size) => {
142
142
  const addSizePrefix = (tag) => {
143
143
  return `${size === "default" ? "" : `${size}-`}${tag}`;
144
144
  };
@@ -161,28 +161,26 @@ class RettangoliColorPickerElement extends HTMLElement {
161
161
  this._styles[size].opacity = opacity;
162
162
  }
163
163
 
164
- if (width === "f") {
165
- this._styles[size].width = "var(--width-stretch)";
166
- } else if (width !== undefined) {
167
- this._styles[size].width = width;
168
- this._styles[size]["min-width"] = width;
169
- this._styles[size]["max-width"] = width;
170
- }
164
+ applyDimensionToStyleBucket({
165
+ styleBucket: this._styles[size],
166
+ axis: "width",
167
+ dimension: width,
168
+ fillValue: "var(--width-stretch)",
169
+ });
171
170
 
172
- if (height === "f") {
173
- this._styles[size].height = "100%";
174
- } else if (height !== undefined) {
175
- this._styles[size].height = height;
176
- this._styles[size]["min-height"] = height;
177
- this._styles[size]["max-height"] = height;
178
- }
171
+ applyDimensionToStyleBucket({
172
+ styleBucket: this._styles[size],
173
+ axis: "height",
174
+ dimension: height,
175
+ fillValue: "100%",
176
+ });
179
177
 
180
178
  if (this.hasAttribute(addSizePrefix("hide"))) {
181
- this._styles[size].display = "none !important";
179
+ this._styles[size].display = "none";
182
180
  }
183
181
 
184
182
  if (this.hasAttribute(addSizePrefix("show"))) {
185
- this._styles[size].display = "block !important";
183
+ this._styles[size].display = "block";
186
184
  }
187
185
  });
188
186
 
@@ -194,13 +192,20 @@ class RettangoliColorPickerElement extends HTMLElement {
194
192
  }
195
193
  }
196
194
 
197
- _updateInputAttributes() {
195
+ _syncValueAttribute() {
198
196
  const value = this.getAttribute("value");
197
+ if (value === null) {
198
+ this._inputElement.value = "#000000";
199
+ return;
200
+ }
201
+
202
+ this._inputElement.value = HEX_COLOR_REGEX.test(value) ? value : "#000000";
203
+ }
204
+
205
+ _updateInputAttributes() {
199
206
  const isDisabled = this.hasAttribute('disabled');
200
207
 
201
- if (value !== null) {
202
- this._inputElement.value = value;
203
- }
208
+ this._syncValueAttribute();
204
209
 
205
210
  if (isDisabled) {
206
211
  this._inputElement.setAttribute("disabled", "");
@@ -211,6 +216,7 @@ class RettangoliColorPickerElement extends HTMLElement {
211
216
 
212
217
  connectedCallback() {
213
218
  this._updateInputAttributes();
219
+ this.updateStyles();
214
220
  }
215
221
  }
216
222
 
@@ -219,4 +225,4 @@ export default ({ render, html }) => {
219
225
  // Note: render and html parameters are accepted but not used
220
226
  // This maintains backward compatibility with existing code
221
227
  return RettangoliColorPickerElement;
222
- };
228
+ };
@@ -131,7 +131,8 @@ class RettangoliDialogElement extends HTMLElement {
131
131
 
132
132
  _attemptClose() {
133
133
  this.dispatchEvent(new CustomEvent('close', {
134
- detail: {}
134
+ detail: {},
135
+ bubbles: true,
135
136
  }));
136
137
  }
137
138