@rettangoli/ui 1.2.3 → 1.3.0

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.
@@ -76,6 +76,7 @@
76
76
  --destructive-foreground: #eff1f5;
77
77
 
78
78
  --background: #eff1f5;
79
+ --surface: #eceff4;
79
80
  --foreground: #4c4f69;
80
81
  --muted: #e6e9ef;
81
82
  --muted-foreground: #6c6f85;
@@ -94,6 +95,7 @@
94
95
  .dark {
95
96
  /* Catppuccin Mocha */
96
97
  --background: #1e1e2e;
98
+ --surface: #252536;
97
99
  --foreground: #cdd6f4;
98
100
  --primary: #89b4fa;
99
101
  --primary-foreground: #1e1e2e;
@@ -75,6 +75,7 @@
75
75
  --destructive-foreground: #fcf3f3;
76
76
 
77
77
  --background: #fff;
78
+ --surface: #fafafa;
78
79
  --foreground: #0a0a0a;
79
80
  --muted: #f5f5f5;
80
81
  --muted-foreground: #737373;
@@ -92,6 +93,7 @@
92
93
 
93
94
  .dark {
94
95
  --background: #0a0a0a;
96
+ --surface: #141414;
95
97
  --foreground: #fafafa;
96
98
  --primary: #e5e5e5;
97
99
  --primary-foreground: #171717;
@@ -75,6 +75,7 @@
75
75
  --destructive-foreground: oklch(0.145 0 0);
76
76
 
77
77
  --background: oklch(1 0 0);
78
+ --surface: oklch(0.985 0 0);
78
79
  --foreground: oklch(0.145 0 0);
79
80
  --muted: oklch(0.97 0 0);
80
81
  --muted-foreground: oklch(0.556 0 0);
@@ -92,6 +93,7 @@
92
93
 
93
94
  .dark {
94
95
  --background: rgb(29 29 29);
96
+ --surface: rgb(36 36 36);
95
97
  --foreground: rgb(242 242 242);
96
98
  --primary: oklch(0.922 0 0);
97
99
  --primary-foreground: oklch(0.305 0 0);
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@rettangoli/ui",
3
- "version": "1.2.3",
3
+ "version": "1.3.0",
4
4
  "description": "A UI component library for building web interfaces.",
5
5
  "main": "dist/rettangoli-esm.min.js",
6
6
  "type": "module",
@@ -30,7 +30,7 @@ refs:
30
30
  mouseleave:
31
31
  handler: handleAddOptionMouseLeave
32
32
  template:
33
- - 'rtgl-view#selectButton style="display: inline-flex;" d=h av=c h=32 ph=md bw=xs bc=bo h-bc=${selectButtonHoverBorderColor} br=md bgc=bg cur=${selectButtonCursor} ${containerAttrString} data-testid="select-button" role="button" tabindex=${selectButtonTabIndex} aria-disabled=${isDisabled}':
33
+ - 'rtgl-view#selectButton style="display: inline-flex;" d=h av=c h=32 ph=md bw=xs bc=bo h-bc=${selectButtonHoverBorderColor} br=md bgc=su cur=${selectButtonCursor} ${containerAttrString} data-testid="select-button" role="button" tabindex=${selectButtonTabIndex} aria-disabled=${isDisabled}':
34
34
  - rtgl-view d=h av=c ah=s w=f:
35
35
  - rtgl-text w=1fg ta=s c=${selectedLabelColor} ellipsis: ${selectedLabel}
36
36
  - $if showClear:
@@ -106,12 +106,19 @@ class RettangoliDialogElement extends HTMLElement {
106
106
  this._adaptiveFrameId = null;
107
107
  this._layoutRetryCount = 0;
108
108
  this._observedContentElement = null;
109
+ this._managedLongTokenTextElements = new Set();
110
+ this._contentMutationObserver = typeof MutationObserver !== "undefined"
111
+ ? new MutationObserver(() => {
112
+ this._syncLongTokenWrapping();
113
+ })
114
+ : null;
109
115
  this._resizeObserver = typeof ResizeObserver !== "undefined"
110
116
  ? new ResizeObserver(() => {
111
117
  this._scheduleAdaptiveCentering();
112
118
  })
113
119
  : null;
114
120
  this._onSlotChange = () => {
121
+ this._syncLongTokenWrapping();
115
122
  this._observeAssignedContent();
116
123
  this._scheduleAdaptiveCentering({ resetRetries: true });
117
124
  };
@@ -175,6 +182,7 @@ class RettangoliDialogElement extends HTMLElement {
175
182
 
176
183
  disconnectedCallback() {
177
184
  this._isConnected = false;
185
+ this._clearManagedLongTokenWrapping();
178
186
  this._stopAdaptiveObservers();
179
187
  if (this._slotElement) {
180
188
  this._slotElement.removeEventListener('slotchange', this._onSlotChange);
@@ -211,6 +219,58 @@ class RettangoliDialogElement extends HTMLElement {
211
219
  }
212
220
  }
213
221
 
222
+ _clearManagedLongTokenWrapping() {
223
+ for (const textElement of this._managedLongTokenTextElements) {
224
+ if (textElement?.isConnected) {
225
+ textElement.removeAttribute("break-long-tokens");
226
+ }
227
+ }
228
+ this._managedLongTokenTextElements.clear();
229
+ }
230
+
231
+ _collectTextElements(node, collected) {
232
+ if (!node || node.nodeType !== Node.ELEMENT_NODE) {
233
+ return;
234
+ }
235
+
236
+ if (node.localName === "rtgl-text") {
237
+ collected.push(node);
238
+ }
239
+
240
+ for (const child of node.children) {
241
+ this._collectTextElements(child, collected);
242
+ }
243
+
244
+ if (node.shadowRoot) {
245
+ for (const child of node.shadowRoot.children) {
246
+ this._collectTextElements(child, collected);
247
+ }
248
+ }
249
+ }
250
+
251
+ _syncLongTokenWrapping() {
252
+ this._clearManagedLongTokenWrapping();
253
+
254
+ if (!this._slotElement) {
255
+ return;
256
+ }
257
+
258
+ const assignedNodes = this._slotElement.assignedNodes({ flatten: true });
259
+ const textElements = [];
260
+
261
+ for (const node of assignedNodes) {
262
+ this._collectTextElements(node, textElements);
263
+ }
264
+
265
+ for (const textElement of textElements) {
266
+ if (textElement.hasAttribute("ellipsis") || textElement.hasAttribute("break-long-tokens")) {
267
+ continue;
268
+ }
269
+ textElement.setAttribute("break-long-tokens", "");
270
+ this._managedLongTokenTextElements.add(textElement);
271
+ }
272
+ }
273
+
214
274
  // Internal methods
215
275
  _showModal() {
216
276
  if (!this._dialogElement.open) {
@@ -228,6 +288,7 @@ class RettangoliDialogElement extends HTMLElement {
228
288
  this._dialogElement.scrollTop = 0;
229
289
 
230
290
  window.addEventListener("resize", this._onWindowResize);
291
+ this._syncLongTokenWrapping();
231
292
  this._observeAssignedContent();
232
293
  this._layoutRetryCount = 0;
233
294
  // Apply the first centering pass before paint so the enter animation
@@ -238,6 +299,7 @@ class RettangoliDialogElement extends HTMLElement {
238
299
 
239
300
  _hideModal() {
240
301
  if (this._dialogElement.open) {
302
+ this._clearManagedLongTokenWrapping();
241
303
  this._stopAdaptiveObservers();
242
304
  this._dialogElement.close();
243
305
 
@@ -269,6 +331,9 @@ class RettangoliDialogElement extends HTMLElement {
269
331
  if (this._resizeObserver && this._observedContentElement) {
270
332
  this._resizeObserver.unobserve(this._observedContentElement);
271
333
  }
334
+ if (this._contentMutationObserver) {
335
+ this._contentMutationObserver.disconnect();
336
+ }
272
337
  this._observedContentElement = null;
273
338
  }
274
339
 
@@ -281,7 +346,7 @@ class RettangoliDialogElement extends HTMLElement {
281
346
  }
282
347
 
283
348
  _observeAssignedContent() {
284
- if (!this._resizeObserver) {
349
+ if (!this._resizeObserver && !this._contentMutationObserver) {
285
350
  return;
286
351
  }
287
352
  const nextContentElement = this._getAssignedContentElement();
@@ -289,11 +354,25 @@ class RettangoliDialogElement extends HTMLElement {
289
354
  return;
290
355
  }
291
356
  if (this._observedContentElement) {
292
- this._resizeObserver.unobserve(this._observedContentElement);
357
+ if (this._resizeObserver) {
358
+ this._resizeObserver.unobserve(this._observedContentElement);
359
+ }
360
+ if (this._contentMutationObserver) {
361
+ this._contentMutationObserver.disconnect();
362
+ }
293
363
  }
294
364
  this._observedContentElement = nextContentElement;
295
365
  if (this._observedContentElement) {
296
- this._resizeObserver.observe(this._observedContentElement);
366
+ if (this._resizeObserver) {
367
+ this._resizeObserver.observe(this._observedContentElement);
368
+ }
369
+ if (this._contentMutationObserver) {
370
+ this._contentMutationObserver.observe(this._observedContentElement, {
371
+ childList: true,
372
+ subtree: true,
373
+ });
374
+ }
375
+ this._syncLongTokenWrapping();
297
376
  }
298
377
  }
299
378
 
@@ -195,12 +195,12 @@ class RettangoliPopoverElement extends HTMLElement {
195
195
  this._contentWrapper = document.createElement("rtgl-view");
196
196
  this._contentWrapper.setAttribute(CONTENT_WRAPPER_ATTR, "");
197
197
  this._contentWrapper.setAttribute("part", "content");
198
- this._contentWrapper.setAttribute("bgc", "bg");
198
+ this._contentWrapper.setAttribute("bgc", "su");
199
199
  this._contentWrapper.setAttribute("bw", "xs");
200
200
  this._contentWrapper.setAttribute("bc", "bo");
201
201
  this._contentWrapper.setAttribute("br", "md");
202
- this._contentWrapper.setAttribute("ph", "md");
203
- this._contentWrapper.setAttribute("pv", "md");
202
+ this._contentWrapper.setAttribute("ph", "sm");
203
+ this._contentWrapper.setAttribute("pv", "sm");
204
204
  this._contentWrapper.setAttribute("style", DEFAULT_CONTENT_STYLE);
205
205
  }
206
206
 
@@ -231,9 +231,9 @@ class RettangoliPopoverElement extends HTMLElement {
231
231
  }
232
232
  }
233
233
 
234
- wrapper.setAttribute("bgc", this.getAttribute("content-bgc") || "bg");
235
- wrapper.setAttribute("ph", "md");
236
- wrapper.setAttribute("pv", this.getAttribute("content-pv") || "md");
234
+ wrapper.setAttribute("bgc", this.getAttribute("content-bgc") || "su");
235
+ wrapper.setAttribute("ph", "sm");
236
+ wrapper.setAttribute("pv", this.getAttribute("content-pv") || "sm");
237
237
 
238
238
  const contentStyle = this.getAttribute("content-style");
239
239
  wrapper.setAttribute("style", contentStyle ? `${DEFAULT_CONTENT_STYLE} ${contentStyle}` : DEFAULT_CONTENT_STYLE);
@@ -58,7 +58,7 @@ class RettangoliTextElement extends HTMLElement {
58
58
  }
59
59
 
60
60
  static get observedAttributes() {
61
- return ["key", "w", "ellipsis", "href", "new-tab", "rel"];
61
+ return ["key", "w", "ellipsis", "href", "new-tab", "rel", "break-long-tokens"];
62
62
  }
63
63
 
64
64
  connectedCallback() {
@@ -77,15 +77,20 @@ class RettangoliTextElement extends HTMLElement {
77
77
  _updateStyling() {
78
78
  const width = dimensionWithUnit(this.getAttribute("w"));
79
79
  const ellipsis = this.hasAttribute("ellipsis");
80
+ const breakLongTokens = this.hasAttribute("break-long-tokens");
80
81
 
81
82
  if (ellipsis) {
82
83
  this.style.overflow = "hidden";
83
84
  this.style.textOverflow = "ellipsis";
84
85
  this.style.whiteSpace = "nowrap";
86
+ this.style.overflowWrap = "";
87
+ this.style.wordBreak = "";
85
88
  } else {
86
89
  this.style.overflow = "";
87
90
  this.style.textOverflow = "";
88
91
  this.style.whiteSpace = "";
92
+ this.style.overflowWrap = breakLongTokens ? "anywhere" : "";
93
+ this.style.wordBreak = breakLongTokens ? "break-word" : "";
89
94
  }
90
95
 
91
96
  // Allow shrinking in flex layouts so ellipsis and wrapping constraints work predictably.
@@ -26,6 +26,9 @@ const styles = {
26
26
  bg: `
27
27
  background-color: var(--background);
28
28
  `,
29
+ su: `
30
+ background-color: var(--surface);
31
+ `,
29
32
  mu: `
30
33
  background-color: var(--muted);
31
34
  `,
@@ -98,6 +101,7 @@ const styles = {
98
101
  de: "--destructive",
99
102
  fg: "--foreground",
100
103
  bg: "--background",
104
+ su: "--surface",
101
105
  mu: "--muted",
102
106
  ac: "--accent",
103
107
  bo: "--border",
@@ -16,6 +16,7 @@ const styles = {
16
16
  de: `background-color: var(--destructive);`,
17
17
  fg: `background-color: var(--foreground);`,
18
18
  bg: `background-color: var(--background);`,
19
+ su: `background-color: var(--surface);`,
19
20
  mu: `background-color: var(--muted);`,
20
21
  ac: `background-color: var(--accent);`,
21
22
  bo: `background-color: var(--border);`,
@@ -41,6 +42,7 @@ const styles = {
41
42
  de: "--destructive",
42
43
  fg: "--foreground",
43
44
  bg: "--background",
45
+ su: "--surface",
44
46
  mu: "--muted",
45
47
  ac: "--accent",
46
48
  bo: "--border",
@@ -76,6 +76,7 @@
76
76
  --destructive-foreground: #eff1f5;
77
77
 
78
78
  --background: #eff1f5;
79
+ --surface: #eceff4;
79
80
  --foreground: #4c4f69;
80
81
  --muted: #e6e9ef;
81
82
  --muted-foreground: #6c6f85;
@@ -94,6 +95,7 @@
94
95
  .dark {
95
96
  /* Catppuccin Mocha */
96
97
  --background: #1e1e2e;
98
+ --surface: #252536;
97
99
  --foreground: #cdd6f4;
98
100
  --primary: #89b4fa;
99
101
  --primary-foreground: #1e1e2e;
@@ -75,6 +75,7 @@
75
75
  --destructive-foreground: #fcf3f3;
76
76
 
77
77
  --background: #fff;
78
+ --surface: #fafafa;
78
79
  --foreground: #0a0a0a;
79
80
  --muted: #f5f5f5;
80
81
  --muted-foreground: #737373;
@@ -92,6 +93,7 @@
92
93
 
93
94
  .dark {
94
95
  --background: #0a0a0a;
96
+ --surface: #141414;
95
97
  --foreground: #fafafa;
96
98
  --primary: #e5e5e5;
97
99
  --primary-foreground: #171717;
@@ -75,6 +75,7 @@
75
75
  --destructive-foreground: oklch(0.145 0 0);
76
76
 
77
77
  --background: oklch(1 0 0);
78
+ --surface: oklch(0.985 0 0);
78
79
  --foreground: oklch(0.145 0 0);
79
80
  --muted: oklch(0.97 0 0);
80
81
  --muted-foreground: oklch(0.556 0 0);
@@ -92,6 +93,7 @@
92
93
 
93
94
  .dark {
94
95
  --background: rgb(29 29 29);
96
+ --surface: rgb(36 36 36);
95
97
  --foreground: rgb(242 242 242);
96
98
  --primary: oklch(0.922 0 0);
97
99
  --primary-foreground: oklch(0.305 0 0);