@reliability-design/web 1.0.6 → 1.2.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.
Files changed (78) hide show
  1. package/dist/components/rel-accordion/rel-accordion.ts +20 -31
  2. package/dist/components/rel-alert/rel-alert.ts +81 -11
  3. package/dist/components/rel-avatar/rel-avatar.ts +6 -3
  4. package/dist/components/rel-badge/rel-badge.ts +8 -3
  5. package/dist/components/rel-breadcrumb/rel-breadcrumb.ts +6 -6
  6. package/dist/components/rel-button/rel-button.ts +118 -16
  7. package/dist/components/rel-calendar/rel-calendar.ts +16 -9
  8. package/dist/components/rel-card/rel-card.ts +9 -17
  9. package/dist/components/rel-cardmedia/rel-cardmedia.ts +20 -23
  10. package/dist/components/rel-carousel/rel-carousel.ts +596 -469
  11. package/dist/components/rel-checkbox/rel-checkbox.ts +98 -15
  12. package/dist/components/rel-chip/rel-chip.ts +291 -186
  13. package/dist/components/rel-container/rel-container.ts +2 -2
  14. package/dist/components/rel-date-picker/rel-date-picker.ts +23 -19
  15. package/dist/components/rel-divider/rel-divider.ts +12 -3
  16. package/dist/components/rel-drawer/rel-drawer-footer.ts +27 -0
  17. package/dist/components/rel-drawer/rel-drawer.ts +57 -113
  18. package/dist/components/rel-kbd/rel-kbd.ts +94 -118
  19. package/dist/components/rel-layout/rel-layout.ts +49 -58
  20. package/dist/components/rel-menu/rel-menu.ts +359 -327
  21. package/dist/components/rel-menubar/rel-menubar-menu.css +3 -0
  22. package/dist/components/rel-menubar/rel-menubar-menu.ts +2 -1
  23. package/dist/components/rel-menubar/rel-menubar.ts +602 -576
  24. package/dist/components/rel-nav-menu/rel-nav-menu-item.ts +240 -143
  25. package/dist/components/rel-nav-menu/rel-nav-menu.ts +227 -331
  26. package/dist/components/rel-navbar/rel-navbar.ts +13 -0
  27. package/dist/components/rel-otp/rel-otp.ts +22 -25
  28. package/dist/components/rel-pagination/rel-pagination.ts +112 -63
  29. package/dist/components/rel-popover/rel-popover-content.ts +6 -5
  30. package/dist/components/rel-popover/rel-popover.ts +42 -20
  31. package/dist/components/rel-progress/rel-progress.ts +10 -9
  32. package/dist/components/rel-radio/rel-radio.ts +228 -155
  33. package/dist/components/rel-range-picker/rel-range-picker.css +349 -0
  34. package/dist/components/rel-range-picker/rel-range-picker.ts +1079 -0
  35. package/dist/components/rel-resizable/rel-resizable-handle.ts +12 -15
  36. package/dist/components/rel-segmented-button/rel-segmented-button.ts +41 -20
  37. package/dist/components/rel-select/rel-select.ts +112 -27
  38. package/dist/components/rel-sheet/rel-sheet.ts +362 -683
  39. package/dist/components/rel-sidebar/rel-sidebar.ts +13 -5
  40. package/dist/components/rel-slider/rel-slider.ts +74 -29
  41. package/dist/components/rel-snackbar/rel-snackbar.ts +67 -37
  42. package/dist/components/rel-stepper/rel-stepper.ts +43 -31
  43. package/dist/components/rel-switch/rel-switch.ts +26 -12
  44. package/dist/components/rel-tab/rel-tab.ts +57 -37
  45. package/dist/components/rel-table/rel-table-body.ts +5 -0
  46. package/dist/components/rel-table/rel-table-caption.ts +6 -1
  47. package/dist/components/rel-table/rel-table-cell.ts +42 -49
  48. package/dist/components/rel-table/rel-table-footer.ts +5 -0
  49. package/dist/components/rel-table/rel-table-head.ts +13 -1
  50. package/dist/components/rel-table/rel-table-header.ts +5 -0
  51. package/dist/components/rel-table/rel-table-row.ts +7 -3
  52. package/dist/components/rel-table/rel-table.ts +8 -2
  53. package/dist/components/rel-textfield/rel-textfield.ts +153 -44
  54. package/dist/components/rel-toast/rel-toast.ts +56 -22
  55. package/dist/components/rel-tooltip/rel-tooltip.ts +52 -9
  56. package/dist/components/rel-topbar/rel-topbar-actions.ts +24 -0
  57. package/dist/components/rel-topbar/rel-topbar-brand.ts +47 -0
  58. package/dist/components/rel-topbar/rel-topbar-dropdown-item.ts +63 -0
  59. package/dist/components/rel-topbar/rel-topbar-dropdown.ts +28 -0
  60. package/dist/components/rel-topbar/rel-topbar-item.ts +320 -0
  61. package/dist/components/rel-topbar/rel-topbar-mobile-panel.ts +24 -0
  62. package/dist/components/rel-topbar/rel-topbar-profile.ts +222 -0
  63. package/dist/components/rel-topbar/rel-topbar-utilities.ts +24 -0
  64. package/dist/components/rel-topbar/rel-topbar.ts +438 -0
  65. package/dist/index.d.mts +375 -411
  66. package/dist/index.d.ts +375 -411
  67. package/dist/index.js +7587 -7980
  68. package/dist/index.js.map +1 -1
  69. package/dist/index.mjs +7647 -8023
  70. package/dist/index.mjs.map +1 -1
  71. package/dist/rel-menubar-menu-BEEQDAXW.css +3 -0
  72. package/dist/styles/vars-v2.css +525 -0
  73. package/dist/styles/vars.css +79 -27
  74. package/dist/{vars-ITL2K3KO.css → vars-I2PC74XD.css} +79 -27
  75. package/dist/vars-v2-VMGWTFJZ.css +525 -0
  76. package/package.json +3 -1
  77. package/dist/components/rel-quote-page/README.md +0 -166
  78. package/dist/components/rel-quote-page/rel-quote-page.ts +0 -816
@@ -1,5 +1,6 @@
1
- import { LitElement, html, css } from "lit";
1
+ import { LitElement, html, css, nothing } from "lit";
2
2
  import { customElement, property, state, query } from "lit/decorators.js";
3
+ import "@reliability-design/icons/rel-icon";
3
4
 
4
5
  export type SidebarVariant = "sidebar" | "floating" | "inset";
5
6
  export type SidebarSide = "left" | "right";
@@ -31,6 +32,11 @@ export class RelSidebarProvider extends LitElement {
31
32
 
32
33
  private mediaQuery: MediaQueryList | null = null;
33
34
  private isInitialized = false;
35
+ private _uid = Math.random().toString(36).slice(2);
36
+
37
+ private get _storageKey(): string {
38
+ return `rel-sidebar:${this.id || this._uid}`;
39
+ }
34
40
 
35
41
  static styles = css`
36
42
  :host {
@@ -154,7 +160,7 @@ export class RelSidebarProvider extends LitElement {
154
160
 
155
161
  private getPersistedState(): { open?: boolean; collapsed?: boolean } | null {
156
162
  try {
157
- const stored = localStorage.getItem(this.persistKey);
163
+ const stored = localStorage.getItem(this._storageKey);
158
164
  if (stored) {
159
165
  return JSON.parse(stored);
160
166
  }
@@ -184,7 +190,7 @@ export class RelSidebarProvider extends LitElement {
184
190
  : { open: this.activeOpen, collapsed: this.activeCollapsed };
185
191
 
186
192
  try {
187
- localStorage.setItem(this.persistKey, JSON.stringify(stateToPersist));
193
+ localStorage.setItem(this._storageKey, JSON.stringify(stateToPersist));
188
194
  } catch (e) {
189
195
  // Silently fail if localStorage is unavailable
190
196
  }
@@ -309,7 +315,8 @@ export class RelSidebar extends LitElement {
309
315
  left: 0;
310
316
  right: 0;
311
317
  bottom: 0;
312
- background: var(--rel-overlay-scrim, rgba(0, 0, 0, 0.5));
318
+ /* TODO: replace scrim fallback with a proper dark-aware token in vars.css */
319
+ background: var(--rel-overlay-scrim, rgba(0, 0, 0, 0.6));
313
320
  z-index: 999;
314
321
  opacity: 0;
315
322
  pointer-events: none;
@@ -982,6 +989,7 @@ export class RelSidebarMenuButton extends LitElement {
982
989
  @property({ type: Boolean }) active = false;
983
990
  @property({ type: Boolean }) disabled = false;
984
991
  @property({ type: String }) tooltip = "";
992
+ @property({ type: String }) icon: string = "";
985
993
 
986
994
  @state() private isCollapsed = false;
987
995
 
@@ -1147,7 +1155,7 @@ export class RelSidebarMenuButton extends LitElement {
1147
1155
  part="button"
1148
1156
  >
1149
1157
  <span class="icon" part="icon">
1150
- <slot name="icon"></slot>
1158
+ ${this.icon ? html`<rel-icon name="${this.icon}"></rel-icon>` : nothing}
1151
1159
  </span>
1152
1160
  <span class="label" part="label">
1153
1161
  <slot></slot>
@@ -1,5 +1,6 @@
1
1
  import { LitElement, html, css } from "lit";
2
2
  import { customElement, property, state } from "lit/decorators.js";
3
+ import "../../styles/vars-v2.css";
3
4
 
4
5
  export type SliderType = "continuous" | "discrete";
5
6
  export type TrackStyle = "solid" | "dotted";
@@ -26,20 +27,23 @@ export class RelSlider extends LitElement {
26
27
 
27
28
  @state() private ticks: number[] = [];
28
29
 
30
+ private _onChange: (value: number) => void = () => {};
31
+ private _onTouched: () => void = () => {};
32
+
29
33
  static styles = css`
30
34
  :host {
31
35
  --track-height: 5px;
32
36
  --thumb-size: 10px;
33
37
  --thumb-stroke: 7px;
34
- --thumb-halo-color: var(--rel-border-default);
38
+ --thumb-halo-color: var(--rel-color-border-default);
35
39
  --tick-size: 4px;
36
40
  --shadow: 0 2px 4px rgba(0, 0, 0, 0.25);
37
- --halo: 0 2px 0 var(--rel-surface-surface), 0 6px 10px rgba(0, 0, 0, 0.07);
41
+ --halo: 0 2px 0 var(--rel-color-bg-tertiary), 0 6px 10px rgba(0, 0, 0, 0.07);
38
42
  --marker-width: 24px;
39
43
  --marker-height: 28px;
40
44
 
41
45
  display: block;
42
- font-family: var(--rel-fontFamilies-primary, sans-serif);
46
+ font-family: var(--rel-fontFamilies-primary);
43
47
  }
44
48
 
45
49
  .rel-slider {
@@ -56,7 +60,7 @@ export class RelSlider extends LitElement {
56
60
  left: 0;
57
61
  width: 100%;
58
62
  height: var(--track-height);
59
- background: var(--rel-colors-gray-border);
63
+ background: var(--rel-color-border-default);
60
64
  border-radius: 2px;
61
65
  transform: translateY(-50%);
62
66
  pointer-events: none;
@@ -67,7 +71,7 @@ export class RelSlider extends LitElement {
67
71
  top: 50%;
68
72
  left: 0;
69
73
  height: var(--track-height);
70
- background: var(--rel-colors-black);
74
+ background: var(--rel-color-text-primary);
71
75
  border-radius: 2px;
72
76
  transform: translateY(-50%);
73
77
  pointer-events: none;
@@ -75,12 +79,10 @@ export class RelSlider extends LitElement {
75
79
 
76
80
  .track-active.dotted {
77
81
  background: radial-gradient(
78
- circle,
79
- var(--rel-colors-white) 0 1px,
80
- transparent 1px
81
- )
82
- center/12px 4px repeat-x,
83
- var(--rel-colors-black);
82
+ circle,
83
+ var(--rel-color-text-primary) 0 2px,
84
+ transparent 2px
85
+ ) 0 50%/12px 5px repeat-x;
84
86
  }
85
87
 
86
88
  /* Input */
@@ -112,6 +114,12 @@ export class RelSlider extends LitElement {
112
114
  border: none;
113
115
  }
114
116
 
117
+ .slider-input::slider-track {
118
+ background: transparent;
119
+ height: 100%;
120
+ border: none;
121
+ }
122
+
115
123
  /* Hide native thumb */
116
124
  .slider-input::-webkit-slider-thumb {
117
125
  -webkit-appearance: none;
@@ -131,6 +139,14 @@ export class RelSlider extends LitElement {
131
139
  cursor: pointer;
132
140
  }
133
141
 
142
+ .slider-input::slider-thumb {
143
+ width: 1px;
144
+ height: 1px;
145
+ background: transparent;
146
+ border: none;
147
+ cursor: pointer;
148
+ }
149
+
134
150
  .slider-input:focus-visible ~ .thumb-container .custom-thumb {
135
151
  box-shadow: 0 0 0 var(--thumb-stroke) var(--thumb-halo-color),
136
152
  var(--shadow), var(--halo);
@@ -147,8 +163,8 @@ export class RelSlider extends LitElement {
147
163
  .thumb-container {
148
164
  position: absolute;
149
165
  left: 0;
150
- top: 23.5%;
151
- transform: translate(-50%, -50%);
166
+ top: 50%;
167
+ transform: translate(-50%, calc(-100% + var(--thumb-size) / 2));
152
168
  pointer-events: none;
153
169
  z-index: 5;
154
170
  display: flex;
@@ -174,7 +190,7 @@ export class RelSlider extends LitElement {
174
190
  .custom-thumb {
175
191
  width: var(--thumb-size);
176
192
  height: var(--thumb-size);
177
- background: var(--rel-colors-black);
193
+ background: var(--rel-color-text-primary);
178
194
  border-radius: 50%;
179
195
  transition: box-shadow 0.15s ease;
180
196
  }
@@ -198,7 +214,7 @@ export class RelSlider extends LitElement {
198
214
  position: absolute;
199
215
  width: var(--tick-size);
200
216
  height: var(--tick-size);
201
- background: var(--rel-colors-gray-primary);
217
+ background: var(--rel-color-text-primary);
202
218
  border-radius: 50%;
203
219
  transform: translate(-50%, -50%);
204
220
  transition: background 0.2s;
@@ -206,7 +222,7 @@ export class RelSlider extends LitElement {
206
222
  }
207
223
 
208
224
  .tick.active {
209
- background: var(--rel-colors-white);
225
+ background: var(--rel-color-bg-primary);
210
226
  }
211
227
 
212
228
  /* Tick labels */
@@ -216,7 +232,7 @@ export class RelSlider extends LitElement {
216
232
  left: 0;
217
233
  width: 100%;
218
234
  font-size: var(--rel-fontSizes-xs);
219
- color: var(--rel-colors-gray-heading);
235
+ color: var(--rel-color-text-heading);
220
236
  pointer-events: none;
221
237
  }
222
238
 
@@ -227,29 +243,29 @@ export class RelSlider extends LitElement {
227
243
 
228
244
  /* Disabled State */
229
245
  .rel-slider.disabled .track {
230
- background: var(--rel-colors-gray-primary);
246
+ background: var(--rel-color-border-default);
231
247
  }
232
248
 
233
249
  .rel-slider.disabled .track-active {
234
- background: var(--rel-colors-gray-placeholder);
250
+ background: var(--rel-color-text-placeholder);
235
251
  }
236
252
 
237
253
  .rel-slider.disabled .track-active.dotted {
238
254
  background: radial-gradient(
239
255
  circle,
240
- var(--rel-surface-surface) 0 1px,
256
+ var(--rel-color-bg-tertiary) 0 1px,
241
257
  transparent 1px
242
258
  )
243
259
  center/12px 4px repeat-x,
244
- var(--rel-colors-gray-placeholder);
260
+ var(--rel-color-text-placeholder);
245
261
  }
246
262
 
247
263
  .rel-slider.disabled .tick {
248
- background: var(--rel-colors-gray-placeholder);
264
+ background: var(--rel-color-text-placeholder);
249
265
  }
250
266
 
251
267
  .rel-slider.disabled .tick-label {
252
- color: var(--rel-colors-gray-placeholder);
268
+ color: var(--rel-color-text-placeholder);
253
269
  }
254
270
 
255
271
  .rel-slider.disabled .slider-input {
@@ -257,13 +273,36 @@ export class RelSlider extends LitElement {
257
273
  }
258
274
 
259
275
  .rel-slider.disabled .custom-thumb {
260
- background: var(--rel-colors-gray-placeholder);
261
- box-shadow: 0 0 0 var(--thumb-stroke) var(--rel-surface-surface);
276
+ background: var(--rel-color-text-placeholder);
277
+ box-shadow: none;
278
+ }
279
+
280
+ .rel-slider.disabled .slider-input:active ~ .thumb-container .custom-thumb,
281
+ .rel-slider.disabled .slider-input:focus-visible ~ .thumb-container .custom-thumb {
282
+ box-shadow: none;
262
283
  }
263
284
 
264
285
  .rel-slider.disabled .value-marker svg path {
265
286
  fill: var(--rel-colors-gray-placeholder);
266
287
  }
288
+
289
+ /* Dark mode overrides */
290
+ :host-context([data-theme="dark"]),
291
+ :host-context(.dark) {
292
+ --thumb-halo-color: var(--rel-color-border-default);
293
+ --halo: 0 2px 0 var(--rel-color-bg-selected),
294
+ 0 6px 10px rgba(0, 0, 0, 0.3);
295
+ }
296
+
297
+ :host-context([data-theme="dark"]) .value-marker svg path,
298
+ :host-context(.dark) .value-marker svg path {
299
+ fill: #2B2B2B;
300
+ }
301
+
302
+ :host-context([data-theme="dark"]) .value-marker text,
303
+ :host-context(.dark) .value-marker text {
304
+ fill: #FFFFFF;
305
+ }
267
306
  `;
268
307
 
269
308
  connectedCallback() {
@@ -330,14 +369,19 @@ export class RelSlider extends LitElement {
330
369
  this.value = next;
331
370
  this.updateActiveWidth();
332
371
  this.dispatchEvent(
333
- new CustomEvent("valueChange", {
372
+ new CustomEvent("rel-change", {
334
373
  detail: { value: this.value },
335
374
  bubbles: true,
336
375
  composed: true,
337
376
  })
338
377
  );
378
+ this._onChange(this.value);
339
379
  }
340
380
 
381
+ registerOnChange(fn: (value: number) => void): void { this._onChange = fn; }
382
+ registerOnTouched(fn: () => void): void { this._onTouched = fn; }
383
+ writeValue(value: number): void { this.value = value; }
384
+
341
385
  private updateActiveWidth() {
342
386
  const activeEl = this.shadowRoot?.querySelector(".track-active") as HTMLDivElement;
343
387
  if (activeEl) {
@@ -359,12 +403,12 @@ export class RelSlider extends LitElement {
359
403
  <svg viewBox="0 0 24 32" xmlns="http://www.w3.org/2000/svg">
360
404
  <path
361
405
  d="M12 0C18.6274 0 24 5.37258 24 12C24 21 12 32 12 32C12 32 0 21 0 12C0 5.37258 5.37258 0 12 0Z"
362
- fill="var(--rel-colors-black)" />
406
+ fill="var(--rel-color-text-primary)" />
363
407
  <text
364
408
  x="12"
365
409
  y="16"
366
410
  text-anchor="middle"
367
- fill="var(--rel-colors-white)"
411
+ fill="var(--rel-color-bg-primary)"
368
412
  font-size="12"
369
413
  font-family="Poppins"
370
414
  font-weight="600">
@@ -441,7 +485,8 @@ export class RelSlider extends LitElement {
441
485
  .step="${this.type === 'discrete' ? String(this.step) : '1'}"
442
486
  .value="${String(this.value)}"
443
487
  ?disabled="${this.disabled}"
444
- @input="${this.onInput}" />
488
+ @input="${this.onInput}"
489
+ @blur="${() => this._onTouched()}" />
445
490
 
446
491
  ${this.renderThumbContainer()}
447
492
  ${this.renderTicks()}
@@ -1,5 +1,7 @@
1
1
  import { LitElement, html, css } from "lit";
2
2
  import { customElement, property, state } from "lit/decorators.js";
3
+ import "../../styles/vars-v2.css";
4
+ import "@reliability-design/icons/rel-icon";
3
5
 
4
6
  export type SnackbarLines = "single" | "double";
5
7
  export type SnackbarType = "default" | "success" | "error" | "warning";
@@ -19,10 +21,11 @@ export class RelSnackbar extends LitElement {
19
21
  @property({ type: Number }) duration: number = 4000;
20
22
 
21
23
  @property({ type: String }) type: SnackbarType = "default";
24
+ @property({ type: Boolean, reflect: true }) show = false;
22
25
 
23
- @state() private visible: boolean = true;
26
+ @state() private visible: boolean = false;
24
27
 
25
- private timeout: number | null = null;
28
+ private _dismissTimer: ReturnType<typeof setTimeout> | null = null;
26
29
 
27
30
  static styles = css`
28
31
  :host {
@@ -37,10 +40,10 @@ export class RelSnackbar extends LitElement {
37
40
  min-width: 280px;
38
41
  max-width: 500px;
39
42
  margin: 0;
40
- padding: 12px 16px;
43
+ padding: 12px 16px 12px 10px;
41
44
  border-radius: var(--rel-borders-radius-border-radius-200);
42
- background-color: var(--rel-colors-black);
43
- color: var(--rel-colors-white);
45
+ background-color: var(--rel-surface-toast);
46
+ color: #FFFFFF;
44
47
  font-family: var(--rel-fontFamilies-primary);
45
48
  box-shadow: var(--rel-shadows-shadow-300);
46
49
  animation: slide-up 0.3s ease-out;
@@ -56,17 +59,30 @@ export class RelSnackbar extends LitElement {
56
59
  display: none;
57
60
  }
58
61
 
59
- /* Type variants */
62
+ /* Type variants — border accent using semantic DS tokens */
60
63
  .snackbar.type-success {
61
- border-left-color: var(--rel-colors-green-secondary, #4ade80);
64
+ border-left-color: var(--rel-colors-green-tertiary);
62
65
  }
63
66
 
64
67
  .snackbar.type-error {
65
- border-left-color: var(--rel-colors-red-primary, #f87171);
68
+ border-left-color: var(--rel-colors-red-primary);
66
69
  }
67
70
 
68
71
  .snackbar.type-warning {
69
- border-left-color: var(--rel-colors-amber-primary, #fbbf24);
72
+ border-left-color: var(--rel-colors-orange-warning);
73
+ }
74
+
75
+ /* Icon color matches type accent */
76
+ .snackbar.type-success .snackbar-icon {
77
+ color: var(--rel-colors-green-primary);
78
+ }
79
+
80
+ .snackbar.type-error .snackbar-icon {
81
+ color: var(--rel-colors-red-secondary);
82
+ }
83
+
84
+ .snackbar.type-warning .snackbar-icon {
85
+ color: var(--rel-colors-yellow-pending);
70
86
  }
71
87
 
72
88
  .snackbar-icon {
@@ -74,7 +90,6 @@ export class RelSnackbar extends LitElement {
74
90
  align-items: center;
75
91
  margin-right: 10px;
76
92
  flex-shrink: 0;
77
- font-size: 14px;
78
93
  }
79
94
 
80
95
  .snackbar-body {
@@ -112,12 +127,14 @@ export class RelSnackbar extends LitElement {
112
127
  .snackbar-action {
113
128
  background: none;
114
129
  border: none;
115
- color: var(--rel-colors-green-secondary);
130
+ color: var(--rel-colors-green-primary);
116
131
  font-weight: var(--rel-fontWeights-semibold);
117
132
  font-size: var(--rel-fontSizes-sm);
118
133
  font-family: var(--rel-fontFamilies-primary);
119
134
  cursor: pointer;
120
135
  padding: 0;
136
+ display: flex;
137
+ align-items: center;
121
138
  transition: opacity 0.2s ease;
122
139
  }
123
140
 
@@ -130,7 +147,7 @@ export class RelSnackbar extends LitElement {
130
147
  }
131
148
 
132
149
  .snackbar-action:focus-visible {
133
- outline: 2px solid var(--rel-colors-white, #fff);
150
+ outline: 2px solid #FFFFFF;
134
151
  outline-offset: 2px;
135
152
  border-radius: 2px;
136
153
  }
@@ -138,12 +155,9 @@ export class RelSnackbar extends LitElement {
138
155
  .snackbar-close {
139
156
  background: none;
140
157
  border: none;
141
- color: var(--rel-colors-white, #fff);
158
+ color: #FFFFFF;
142
159
  cursor: pointer;
143
- font-size: 16px;
144
160
  padding: 0;
145
- width: 20px;
146
- height: 20px;
147
161
  display: flex;
148
162
  align-items: center;
149
163
  justify-content: center;
@@ -159,11 +173,16 @@ export class RelSnackbar extends LitElement {
159
173
  }
160
174
 
161
175
  .snackbar-close:focus-visible {
162
- outline: 2px solid var(--rel-colors-white, #fff);
176
+ outline: 2px solid #FFFFFF;
163
177
  outline-offset: 2px;
164
178
  border-radius: 2px;
165
179
  }
166
180
 
181
+ /* Prevent any inherited transform from firing on button click */
182
+ .snackbar button:active {
183
+ transform: none;
184
+ }
185
+
167
186
  @media (prefers-reduced-motion: reduce) {
168
187
  .snackbar {
169
188
  animation: none;
@@ -184,32 +203,42 @@ export class RelSnackbar extends LitElement {
184
203
 
185
204
  connectedCallback() {
186
205
  super.connectedCallback();
187
- this.setAutoDismiss();
206
+ }
207
+
208
+ willUpdate(changed: Map<string, unknown>) {
209
+ if (!changed.has('show')) return;
210
+ if (this.show) {
211
+ this.visible = true;
212
+ this.setAutoDismiss();
213
+ } else {
214
+ this.visible = false;
215
+ this.clearDismissTimer();
216
+ }
188
217
  }
189
218
 
190
219
  updated(changed: Map<string, unknown>) {
191
- if (changed.has("duration") || changed.has("longerAction")) {
220
+ if ((changed.has("duration") || changed.has("longerAction")) && this.show) {
192
221
  this.setAutoDismiss();
193
222
  }
194
223
  }
195
224
 
196
225
  disconnectedCallback() {
197
226
  super.disconnectedCallback();
198
- this.clearTimeout();
227
+ this.clearDismissTimer();
199
228
  }
200
229
 
201
230
  private setAutoDismiss() {
202
231
  if (this.duration > 0) {
203
- this.clearTimeout();
232
+ this.clearDismissTimer();
204
233
  const delay = this.longerAction ? this.duration * 2 : this.duration;
205
- this.timeout = window.setTimeout(() => this.dismiss(), delay);
234
+ this._dismissTimer = setTimeout(() => this.dismiss(), delay);
206
235
  }
207
236
  }
208
237
 
209
- private clearTimeout() {
210
- if (this.timeout !== null) {
211
- window.clearTimeout(this.timeout);
212
- this.timeout = null;
238
+ private clearDismissTimer() {
239
+ if (this._dismissTimer !== null) {
240
+ clearTimeout(this._dismissTimer);
241
+ this._dismissTimer = null;
213
242
  }
214
243
  }
215
244
 
@@ -224,6 +253,7 @@ export class RelSnackbar extends LitElement {
224
253
  }
225
254
 
226
255
  private dismiss() {
256
+ this.show = false;
227
257
  this.visible = false;
228
258
  this.dispatchEvent(
229
259
  new CustomEvent("close", {
@@ -233,13 +263,15 @@ export class RelSnackbar extends LitElement {
233
263
  );
234
264
  }
235
265
 
236
- private getIcon(): string {
237
- switch (this.type) {
238
- case "success": return "✓";
239
- case "error": return "✕";
240
- case "warning": return "⚠";
241
- default: return "";
242
- }
266
+ private renderIcon() {
267
+ const iconMap: Record<string, string> = {
268
+ success: "check-circle",
269
+ error: "error",
270
+ warning: "warning",
271
+ };
272
+ const name = iconMap[this.type];
273
+ if (!name) return html``;
274
+ return html`<rel-icon name="${name}" size="lg" class="snackbar-icon"></rel-icon>`;
243
275
  }
244
276
 
245
277
  render() {
@@ -252,12 +284,10 @@ export class RelSnackbar extends LitElement {
252
284
  .filter(Boolean)
253
285
  .join(" ");
254
286
 
255
- const icon = this.getIcon();
256
-
257
287
  return html`
258
288
  <div class="${snackbarClasses}">
259
289
  <div class="snackbar-body">
260
- ${icon ? html`<span class="snackbar-icon">${icon}</span>` : ""}
290
+ ${this.type !== "default" ? this.renderIcon() : ""}
261
291
  <div class="snackbar-message">${this.message}</div>
262
292
  </div>
263
293
 
@@ -272,7 +302,7 @@ export class RelSnackbar extends LitElement {
272
302
  ${this.iconClose
273
303
  ? html`
274
304
  <button class="snackbar-close" @click="${this.dismiss}">
275
- ✖
305
+ <rel-icon name="close" size="md"></rel-icon>
276
306
  </button>
277
307
  `
278
308
  : ""}