@reliability-design/web 1.1.1 → 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 (64) hide show
  1. package/dist/components/rel-accordion/rel-accordion.ts +17 -32
  2. package/dist/components/rel-alert/rel-alert.ts +34 -34
  3. package/dist/components/rel-avatar/rel-avatar.ts +5 -3
  4. package/dist/components/rel-badge/rel-badge.ts +2 -1
  5. package/dist/components/rel-breadcrumb/rel-breadcrumb.ts +6 -6
  6. package/dist/components/rel-button/rel-button.ts +67 -21
  7. package/dist/components/rel-calendar/rel-calendar.ts +15 -8
  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 -468
  11. package/dist/components/rel-checkbox/rel-checkbox.ts +68 -16
  12. package/dist/components/rel-chip/rel-chip.ts +291 -244
  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 +3 -3
  16. package/dist/components/rel-drawer/rel-drawer-footer.ts +0 -2
  17. package/dist/components/rel-drawer/rel-drawer.ts +41 -88
  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 -359
  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 -605
  24. package/dist/components/rel-otp/rel-otp.ts +22 -25
  25. package/dist/components/rel-pagination/rel-pagination.ts +101 -57
  26. package/dist/components/rel-popover/rel-popover-content.ts +6 -5
  27. package/dist/components/rel-popover/rel-popover.ts +26 -7
  28. package/dist/components/rel-progress/rel-progress.ts +10 -9
  29. package/dist/components/rel-radio/rel-radio.ts +228 -172
  30. package/dist/components/rel-range-picker/rel-range-picker.css +349 -0
  31. package/dist/components/rel-range-picker/rel-range-picker.ts +1079 -0
  32. package/dist/components/rel-resizable/rel-resizable-handle.ts +8 -7
  33. package/dist/components/rel-segmented-button/rel-segmented-button.ts +41 -20
  34. package/dist/components/rel-select/rel-select.ts +103 -32
  35. package/dist/components/rel-sheet/rel-sheet.ts +362 -684
  36. package/dist/components/rel-slider/rel-slider.ts +49 -27
  37. package/dist/components/rel-snackbar/rel-snackbar.ts +28 -28
  38. package/dist/components/rel-stepper/rel-stepper.ts +11 -10
  39. package/dist/components/rel-switch/rel-switch.ts +7 -6
  40. package/dist/components/rel-tab/rel-tab.ts +15 -29
  41. package/dist/components/rel-textfield/rel-textfield.ts +144 -35
  42. package/dist/components/rel-toast/rel-toast.ts +25 -12
  43. package/dist/components/rel-tooltip/rel-tooltip.ts +123 -123
  44. package/dist/components/rel-topbar/rel-topbar-actions.ts +1 -0
  45. package/dist/components/rel-topbar/rel-topbar-brand.ts +1 -0
  46. package/dist/components/rel-topbar/rel-topbar-dropdown-item.ts +32 -2
  47. package/dist/components/rel-topbar/rel-topbar-dropdown.ts +1 -1
  48. package/dist/components/rel-topbar/rel-topbar-item.ts +15 -10
  49. package/dist/components/rel-topbar/rel-topbar-mobile-panel.ts +1 -0
  50. package/dist/components/rel-topbar/rel-topbar-profile.ts +30 -56
  51. package/dist/components/rel-topbar/rel-topbar-utilities.ts +1 -0
  52. package/dist/components/rel-topbar/rel-topbar.ts +137 -28
  53. package/dist/index.d.mts +153 -178
  54. package/dist/index.d.ts +153 -178
  55. package/dist/index.js +4711 -3875
  56. package/dist/index.js.map +1 -1
  57. package/dist/index.mjs +4047 -3202
  58. package/dist/index.mjs.map +1 -1
  59. package/dist/rel-menubar-menu-BEEQDAXW.css +3 -0
  60. package/dist/styles/vars-v2.css +525 -0
  61. package/dist/styles/vars.css +346 -346
  62. package/dist/{vars-TBB4BMSD.css → vars-I2PC74XD.css} +346 -346
  63. package/dist/vars-v2-VMGWTFJZ.css +525 -0
  64. package/package.json +2 -1
@@ -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 TextFieldState = "default" | "error" | "disabled";
5
7
  export type TextFieldSize = "small" | "medium" | "large";
@@ -15,30 +17,106 @@ export class RelTextfield extends LitElement {
15
17
  @property({ type: String }) supportingText?: string;
16
18
  @property({ type: String }) state: TextFieldState = "default";
17
19
  @property({ type: String }) size: TextFieldSize = "medium";
20
+ @property({ type: Boolean, reflect: true }) floatingLabel = false;
18
21
 
19
22
  @state() private internalState: "default" | "focused" = "default";
23
+ private _wasError = false;
20
24
 
21
25
  private uniqueId = `textfield-${Math.random().toString(36).slice(2)}`;
22
26
 
23
27
  static styles = css`
24
28
  :host {
25
29
  display: block;
26
- font-family: var(--rel-fontFamilies-primary, sans-serif);
30
+ font-family: var(--rel-fontFamilies-primary);
27
31
  }
28
32
 
29
33
  /* Wrapper */
30
34
  .textfield-wrapper {
31
35
  display: flex;
32
36
  flex-direction: column;
33
- gap: var(--rel-spacing-space-2xs, 4px);
37
+ gap: var(--rel-spacing-space-2xs);
34
38
  width: 100%;
35
39
  }
36
40
 
37
41
  /* Label */
38
42
  .textfield-label {
39
- font-size: var(--rel-fontSizes-sm, 12px);
40
- font-weight: var(--rel-fontWeights-medium, 500);
41
- color: var(--rel-text-heading, #2b2b2b);
43
+ font-size: var(--rel-fontSizes-sm);
44
+ font-weight: var(--rel-fontWeights-medium);
45
+ color: var(--rel-color-text-heading);
46
+ }
47
+
48
+ /* Floating label variant */
49
+ :host([floatinglabel]) .textfield-wrapper {
50
+ gap: 0;
51
+ }
52
+
53
+ :host([floatinglabel]) .textfield-container {
54
+ overflow: visible;
55
+ position: relative;
56
+ padding-top: 0;
57
+ }
58
+
59
+ :host([floatinglabel]) .textfield-label {
60
+ position: absolute;
61
+ left: var(--rel-spacing-space-sm);
62
+ top: 50%;
63
+ transform: translateY(-50%);
64
+ font-size: var(--rel-fontSizes-md);
65
+ font-weight: var(--rel-fontWeights-regular);
66
+ color: var(--rel-color-text-placeholder);
67
+ pointer-events: none;
68
+ transition: top 0.15s ease, font-size 0.15s ease, color 0.15s ease, transform 0.15s ease;
69
+ background: var(--rel-color-bg-primary);
70
+ padding: 0 2px;
71
+ z-index: 1;
72
+ line-height: 1;
73
+ white-space: nowrap;
74
+ }
75
+
76
+ :host([floatinglabel]) .textfield-wrapper.focused .textfield-label,
77
+ :host([floatinglabel]) .textfield-wrapper.has-value .textfield-label {
78
+ top: 0;
79
+ transform: translateY(-50%);
80
+ font-size: var(--rel-fontSizes-xs);
81
+ color: var(--rel-color-text-primary);
82
+ }
83
+
84
+ :host([floatinglabel]) .textfield-wrapper.error .textfield-label {
85
+ color: var(--rel-error-text);
86
+ }
87
+
88
+ :host([floatinglabel]) .textfield-wrapper.focused:not(.error) .textfield-label {
89
+ color: var(--rel-color-text-primary);
90
+ }
91
+
92
+ :host([floatinglabel]) .textfield-wrapper.focused.error .textfield-label,
93
+ :host([floatinglabel]) .textfield-wrapper.has-value.error .textfield-label {
94
+ top: 0;
95
+ transform: translateY(-50%);
96
+ font-size: var(--rel-fontSizes-xs);
97
+ color: var(--rel-error-text);
98
+ }
99
+
100
+ :host([floatinglabel]) .textfield-input {
101
+ padding-top: var(--rel-spacing-space-sm);
102
+ padding-bottom: var(--rel-spacing-space-sm);
103
+ }
104
+
105
+ :host([floatinglabel]) .textfield-input.has-left-icon {
106
+ padding-left: var(--rel-spacing-space-2xl);
107
+ }
108
+
109
+ :host([floatinglabel]) .textfield-label.has-left-icon {
110
+ left: var(--rel-spacing-space-2xl);
111
+ }
112
+
113
+ :host([floatinglabel]) .textfield-wrapper.focused .textfield-label.has-left-icon,
114
+ :host([floatinglabel]) .textfield-wrapper.has-value .textfield-label.has-left-icon {
115
+ left: var(--rel-spacing-space-sm);
116
+ }
117
+
118
+ :host([floatinglabel]) .textfield-wrapper.disabled .textfield-label {
119
+ background: var(--rel-color-bg-tertiary);
42
120
  }
43
121
 
44
122
  /* Container */
@@ -46,14 +124,15 @@ export class RelTextfield extends LitElement {
46
124
  display: flex;
47
125
  align-items: center;
48
126
  position: relative;
49
- border: 1px solid var(--rel-border-default, #ddd);
50
- border-radius: var(--rel-borders-radius-border-radius-200, 8px);
51
- background: var(--rel-colors-white, #fff);
127
+ border: 1px solid var(--rel-color-border-default);
128
+ border-radius: var(--rel-borders-radius-border-radius-100);
129
+ background: var(--rel-color-bg-primary);
130
+ overflow: hidden;
52
131
  transition: border 0.2s;
53
132
  }
54
133
 
55
134
  .textfield-container.disabled {
56
- background: var(--rel-surface-surface, #f5f5f5);
135
+ background: var(--rel-color-bg-tertiary);
57
136
  cursor: not-allowed;
58
137
  }
59
138
 
@@ -62,23 +141,23 @@ export class RelTextfield extends LitElement {
62
141
  flex: 1;
63
142
  border: none;
64
143
  outline: none;
65
- font-size: var(--rel-fontSizes-md, 14px);
66
- padding: var(--rel-spacing-space-xs, 8px) var(--rel-spacing-space-sm, 12px);
144
+ font-size: var(--rel-fontSizes-md);
145
+ padding: var(--rel-spacing-space-xs) var(--rel-spacing-space-sm);
67
146
  background: transparent;
68
- font-family: var(--rel-fontFamilies-primary, sans-serif);
69
- color: var(--rel-text-primary, #333);
147
+ font-family: var(--rel-fontFamilies-primary);
148
+ color: var(--rel-color-text-primary);
70
149
  }
71
150
 
72
151
  .textfield-input:disabled {
73
152
  cursor: not-allowed;
74
- color: var(--rel-text-disabled, #9e9e9e);
153
+ color: var(--rel-color-text-disabled);
75
154
  }
76
155
 
77
156
  .icon {
78
157
  position: absolute;
79
158
  display: flex;
80
159
  pointer-events: none;
81
- color: var(--rel-text-placeholder, #a9a9a9);
160
+ color: var(--rel-color-text-placeholder);
82
161
  }
83
162
 
84
163
  .icon.left {
@@ -90,32 +169,32 @@ export class RelTextfield extends LitElement {
90
169
  }
91
170
 
92
171
  .textfield-wrapper.small .textfield-input {
93
- padding: var(--rel-spacing-space-xs, 8px) var(--rel-spacing-space-sm, 12px);
94
- font-size: var(--rel-fontSizes-sm, 12px);
172
+ padding: var(--rel-spacing-space-xs) var(--rel-spacing-space-sm);
173
+ font-size: var(--rel-fontSizes-sm);
95
174
  }
96
175
 
97
176
  .textfield-wrapper.medium .textfield-input {
98
- padding: var(--rel-spacing-space-sm, 12px) var(--rel-spacing-space-md, 16px);
99
- font-size: var(--rel-fontSizes-md, 14px);
177
+ padding: var(--rel-spacing-space-sm) var(--rel-spacing-space-md);
178
+ font-size: var(--rel-fontSizes-md);
100
179
  }
101
180
 
102
181
  .textfield-wrapper.large .textfield-input {
103
- padding: var(--rel-spacing-space-md, 16px) var(--rel-spacing-space-md, 16px);
104
- font-size: var(--rel-fontSizes-lg, 20px);
182
+ padding: var(--rel-spacing-space-md) var(--rel-spacing-space-md);
183
+ font-size: var(--rel-fontSizes-lg);
105
184
  }
106
185
 
107
186
  /* Adjust padding when icons are present */
108
187
  .textfield-wrapper .textfield-input.has-left-icon {
109
- padding-left: var(--rel-spacing-space-2xl, 32px);
188
+ padding-left: var(--rel-spacing-space-2xl);
110
189
  }
111
190
 
112
191
  .textfield-wrapper .textfield-input.has-right-icon {
113
- padding-right: var(--rel-spacing-space-2xl, 32px);
192
+ padding-right: var(--rel-spacing-space-2xl);
114
193
  }
115
194
 
116
195
  /* States */
117
196
  .textfield-wrapper.focused .textfield-container {
118
- border-color: var(--rel-colors-primary-500, #0091ea);
197
+ border-color: var(--rel-color-text-primary);
119
198
  }
120
199
 
121
200
  .textfield-input:focus-visible {
@@ -124,34 +203,51 @@ export class RelTextfield extends LitElement {
124
203
 
125
204
  .textfield-wrapper.focused .textfield-container,
126
205
  .textfield-container:focus-within {
127
- border-color: var(--rel-colors-primary-500, #0091ea);
128
- box-shadow: 0 0 0 1px var(--rel-colors-primary-500, #0091ea);
206
+ border-color: var(--rel-color-text-primary);
207
+ box-shadow: 0 0 0 1px var(--rel-color-text-primary);
129
208
  }
130
209
 
131
210
  .textfield-wrapper.error .textfield-container {
132
- border-color: var(--rel-border-error, #cc0000);
211
+ border-color: var(--rel-error-surface-default);
212
+ box-shadow: none;
133
213
  }
134
214
 
135
215
  .textfield-wrapper.disabled .textfield-container {
136
- border-color: var(--rel-border-default, #ddd);
216
+ border-color: var(--rel-color-border-default);
137
217
  }
138
218
 
139
219
  /* Supporting text */
140
220
  .textfield-support {
141
- font-size: var(--rel-fontSizes-xs, 10px);
142
- color: var(--rel-text-placeholder, #a9a9a9);
221
+ font-size: var(--rel-fontSizes-xs);
222
+ color: var(--rel-color-text-placeholder);
143
223
  }
144
224
 
145
225
  .textfield-support.error {
146
- color: var(--rel-text-error, #cc0000);
226
+ color: var(--rel-error-text);
147
227
  }
148
228
 
149
229
  /* Placeholder */
150
230
  .textfield-input::placeholder {
151
- color: var(--rel-text-placeholder, #a9a9a9);
231
+ color: var(--rel-color-text-placeholder);
232
+ }
233
+
234
+ /* Suppress Chrome autofill blue background */
235
+ .textfield-input:-webkit-autofill,
236
+ .textfield-input:-webkit-autofill:hover,
237
+ .textfield-input:-webkit-autofill:focus {
238
+ -webkit-box-shadow: 0 0 0px 1000px var(--rel-color-bg-primary) inset;
239
+ -webkit-text-fill-color: var(--rel-color-text-primary);
152
240
  }
153
241
  `;
154
242
 
243
+ connectedCallback() {
244
+ super.connectedCallback();
245
+ const leftIcon = this.getAttribute('lefticon') || this.getAttribute('leftIcon');
246
+ if (leftIcon) this.leftIcon = leftIcon;
247
+ const rightIcon = this.getAttribute('righticon') || this.getAttribute('rightIcon');
248
+ if (rightIcon) this.rightIcon = rightIcon;
249
+ }
250
+
155
251
  private handleFocus() {
156
252
  if (this.state !== "disabled") {
157
253
  this.internalState = "focused";
@@ -167,6 +263,13 @@ export class RelTextfield extends LitElement {
167
263
  private handleInput(e: Event) {
168
264
  const input = e.target as HTMLInputElement;
169
265
  this.value = input.value;
266
+ if (this.state === "error" && this.value) {
267
+ this._wasError = true;
268
+ this.state = "default";
269
+ } else if (this._wasError && !this.value) {
270
+ this._wasError = false;
271
+ this.state = "error";
272
+ }
170
273
  this.dispatchEvent(
171
274
  new CustomEvent<string>("rel-change", {
172
275
  detail: this.value,
@@ -182,6 +285,7 @@ export class RelTextfield extends LitElement {
182
285
  this.size,
183
286
  this.state,
184
287
  this.internalState === "focused" ? "focused" : "",
288
+ this.value ? "has-value" : "",
185
289
  ].filter(Boolean).join(" ");
186
290
 
187
291
  const inputClasses = [
@@ -194,7 +298,7 @@ export class RelTextfield extends LitElement {
194
298
 
195
299
  return html`
196
300
  <div class="${wrapperClasses}">
197
- ${this.label
301
+ ${!this.floatingLabel && this.label
198
302
  ? html`<label class="textfield-label" for="${this.uniqueId}">${this.label}</label>`
199
303
  : ""}
200
304
 
@@ -203,8 +307,13 @@ export class RelTextfield extends LitElement {
203
307
  ? "disabled"
204
308
  : ""}"
205
309
  >
310
+ ${this.floatingLabel && this.label
311
+ ? html`<label
312
+ class="textfield-label${this.leftIcon ? ' has-left-icon' : ''}"
313
+ for="${this.uniqueId}">${this.label}</label>`
314
+ : ""}
206
315
  ${this.leftIcon
207
- ? html`<span class="icon left">${this.leftIcon}</span>`
316
+ ? html`<rel-icon name="${this.leftIcon}" size="sm" class="icon left"></rel-icon>`
208
317
  : ""}
209
318
 
210
319
  <input
@@ -221,7 +330,7 @@ export class RelTextfield extends LitElement {
221
330
  />
222
331
 
223
332
  ${this.rightIcon
224
- ? html`<span class="icon right">${this.rightIcon}</span>`
333
+ ? html`<rel-icon name="${this.rightIcon}" size="sm" class="icon right"></rel-icon>`
225
334
  : ""}
226
335
  </div>
227
336
 
@@ -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 ToastType = "default" | "error";
5
6
 
@@ -32,20 +33,20 @@ export class RelToast extends LitElement {
32
33
  .toast {
33
34
  display: inline-flex;
34
35
  align-items: center;
35
- gap: var(--rel-spacing-space-sm, 12px);
36
- background-color: var(--rel-surface-toast, #404040);
37
- color: var(--rel-colors-white, #fff);
38
- font-family: var(--rel-fontFamilies-primary, sans-serif);
39
- font-size: var(--rel-fontSizes-md, 14px);
40
- border-radius: var(--rel-borders-radius-border-radius-200, 8px);
41
- padding: var(--rel-spacing-space-md, 16px);
36
+ gap: var(--rel-spacing-space-sm);
37
+ background-color: var(--rel-color-text-primary);
38
+ color: var(--rel-color-bg-primary);
39
+ font-family: var(--rel-fontFamilies-primary);
40
+ font-size: var(--rel-fontSizes-md);
41
+ border-radius: var(--rel-borders-radius-border-radius-200);
42
+ padding: var(--rel-spacing-space-md);
42
43
  box-shadow: var(--rel-shadows-shadow-300);
43
44
  pointer-events: all;
44
45
  animation: fadeInUp 0.25s ease;
45
46
  }
46
47
 
47
48
  .toast.error {
48
- background-color: var(--rel-colors-red-secondary);
49
+ background-color: var(--rel-error-surface-default);
49
50
  }
50
51
 
51
52
  .toast.hidden {
@@ -74,7 +75,7 @@ export class RelToast extends LitElement {
74
75
  }
75
76
 
76
77
  .toast-action:focus-visible {
77
- outline: 2px solid var(--rel-colors-white, #fff);
78
+ outline: 2px solid #FFFFFF;
78
79
  outline-offset: 2px;
79
80
  border-radius: 2px;
80
81
  }
@@ -87,8 +88,8 @@ export class RelToast extends LitElement {
87
88
  font-size: 1rem;
88
89
  cursor: pointer;
89
90
  line-height: 1;
90
- padding: var(--rel-spacing-space-2xs, 4px);
91
- margin-left: var(--rel-spacing-space-2xs, 4px);
91
+ padding: var(--rel-spacing-space-2xs);
92
+ margin-left: var(--rel-spacing-space-2xs);
92
93
  }
93
94
 
94
95
  .toast-close:hover {
@@ -96,11 +97,23 @@ export class RelToast extends LitElement {
96
97
  }
97
98
 
98
99
  .toast-close:focus-visible {
99
- outline: 2px solid var(--rel-colors-white, #fff);
100
+ outline: 2px solid #FFFFFF;
100
101
  outline-offset: 2px;
101
102
  border-radius: 2px;
102
103
  }
103
104
 
105
+ /* Dark mode overrides */
106
+ :host-context([data-theme="dark"]) .toast-action,
107
+ :host-context(.dark) .toast-action {
108
+ color: var(--rel-colors-green-tertiary);
109
+ }
110
+
111
+ :host-context([data-theme="dark"]) .toast.error,
112
+ :host-context(.dark) .toast.error {
113
+ background-color: var(--rel-error-surface-default);
114
+ color: #ffffff;
115
+ }
116
+
104
117
  @media (prefers-reduced-motion: reduce) {
105
118
  .toast {
106
119
  animation: none;
@@ -1,123 +1,123 @@
1
- import { LitElement, html, css } from "lit";
2
- import { customElement, property } from "lit/decorators.js";
3
-
4
- export type TooltipPosition = "above" | "below";
5
-
6
- @customElement("rel-tooltip")
7
- export class RelTooltip extends LitElement {
8
- @property({ type: String }) text: string = "";
9
- @property({ type: String }) position: TooltipPosition = "above";
10
- @property({ type: Boolean, attribute: "show-tail" }) showTail: boolean =
11
- false;
12
-
13
- // Stable id so aria-describedby can reference the bubble across renders.
14
- private uniqueId = Math.random().toString(36).slice(2);
15
-
16
- static styles = css`
17
- :host {
18
- display: inline-block;
19
- position: relative;
20
- }
21
-
22
- /* Tooltip container */
23
- .tooltip-bubble {
24
- position: absolute;
25
- left: 50%;
26
- transform: translateX(-50%);
27
- background-color: #1a1a1a;
28
- color: #ffffff;
29
- padding: var(--rel-spacing-space-xs, 8px)
30
- var(--rel-spacing-space-sm, 12px);
31
- border-radius: var(--rel-borders-radius-border-radius-200, 8px);
32
- font-size: var(--rel-fontSizes-sm, 12px);
33
- font-family: var(--rel-fontFamilies-primary, sans-serif);
34
- white-space: nowrap;
35
- z-index: 1000;
36
- opacity: 0;
37
- pointer-events: none;
38
- transition: opacity 0.2s ease;
39
- overflow: visible;
40
- }
41
-
42
- :host(:hover) .tooltip-bubble,
43
- :host(:focus-within) .tooltip-bubble {
44
- opacity: 1;
45
- }
46
-
47
- /* Positioning */
48
- .tooltip-bubble.above {
49
- bottom: calc(100% + 8px);
50
- }
51
-
52
- .tooltip-bubble.below {
53
- top: calc(100% + 8px);
54
- }
55
-
56
- /* Tail/Arrow */
57
- .tooltip-tail {
58
- position: absolute;
59
- left: 50%;
60
- transform: translateX(-50%);
61
- width: 0;
62
- height: 0;
63
- border-left: 6px solid transparent;
64
- border-right: 6px solid transparent;
65
- display: block;
66
- }
67
-
68
- .tooltip-bubble.above .tooltip-tail {
69
- bottom: -6px;
70
- border-top: 6px solid #1a1a1a;
71
- border-bottom: none;
72
- }
73
-
74
- .tooltip-bubble.below .tooltip-tail {
75
- top: -6px;
76
- border-bottom: 6px solid #1a1a1a;
77
- border-top: none;
78
- }
79
-
80
- :host-context([data-theme="dark"]) .tooltip-bubble,
81
- :host-context(.dark) .tooltip-bubble {
82
- background-color: #ffffff;
83
- color: #000000;
84
- }
85
-
86
- :host-context([data-theme="dark"]) .tooltip-bubble.above .tooltip-tail,
87
- :host-context(.dark) .tooltip-bubble.above .tooltip-tail {
88
- border-top-color: #ffffff;
89
- }
90
-
91
- :host-context([data-theme="dark"]) .tooltip-bubble.below .tooltip-tail,
92
- :host-context(.dark) .tooltip-bubble.below .tooltip-tail {
93
- border-bottom-color: #ffffff;
94
- }
95
- `;
96
-
97
- firstUpdated() {
98
- this.linkTrigger();
99
- }
100
-
101
- private linkTrigger() {
102
- const slot = this.shadowRoot?.querySelector("slot");
103
- if (!slot) return;
104
- const trigger = slot.assignedElements()[0];
105
- if (trigger) {
106
- trigger.setAttribute("aria-describedby", `tooltip-${this.uniqueId}`);
107
- }
108
- }
109
-
110
- render() {
111
- return html`
112
- <slot @slotchange="${this.linkTrigger}"></slot>
113
- <div
114
- class="tooltip-bubble ${this.position}"
115
- id="tooltip-${this.uniqueId}"
116
- role="tooltip"
117
- >
118
- ${this.text}
119
- ${this.showTail ? html`<span class="tooltip-tail"></span>` : ""}
120
- </div>
121
- `;
122
- }
123
- }
1
+ import { LitElement, html, css } from "lit";
2
+ import { customElement, property } from "lit/decorators.js";
3
+
4
+ export type TooltipPosition = "above" | "below";
5
+
6
+ @customElement("rel-tooltip")
7
+ export class RelTooltip extends LitElement {
8
+ @property({ type: String }) text: string = "";
9
+ @property({ type: String }) position: TooltipPosition = "above";
10
+ @property({ type: Boolean, attribute: "show-tail" }) showTail: boolean =
11
+ false;
12
+
13
+ // Stable id so aria-describedby can reference the bubble across renders.
14
+ private uniqueId = Math.random().toString(36).slice(2);
15
+
16
+ static styles = css`
17
+ :host {
18
+ display: inline-block;
19
+ position: relative;
20
+ }
21
+
22
+ /* Tooltip container */
23
+ .tooltip-bubble {
24
+ position: absolute;
25
+ left: 50%;
26
+ transform: translateX(-50%);
27
+ background-color: #1a1a1a;
28
+ color: #ffffff;
29
+ padding: var(--rel-spacing-space-xs, 8px)
30
+ var(--rel-spacing-space-sm, 12px);
31
+ border-radius: var(--rel-borders-radius-border-radius-200, 8px);
32
+ font-size: var(--rel-fontSizes-sm, 12px);
33
+ font-family: var(--rel-fontFamilies-primary, sans-serif);
34
+ white-space: nowrap;
35
+ z-index: 1000;
36
+ opacity: 0;
37
+ pointer-events: none;
38
+ transition: opacity 0.2s ease;
39
+ overflow: visible;
40
+ }
41
+
42
+ :host(:hover) .tooltip-bubble,
43
+ :host(:focus-within) .tooltip-bubble {
44
+ opacity: 1;
45
+ }
46
+
47
+ /* Positioning */
48
+ .tooltip-bubble.above {
49
+ bottom: calc(100% + 8px);
50
+ }
51
+
52
+ .tooltip-bubble.below {
53
+ top: calc(100% + 8px);
54
+ }
55
+
56
+ /* Tail/Arrow */
57
+ .tooltip-tail {
58
+ position: absolute;
59
+ left: 50%;
60
+ transform: translateX(-50%);
61
+ width: 0;
62
+ height: 0;
63
+ border-left: 6px solid transparent;
64
+ border-right: 6px solid transparent;
65
+ display: block;
66
+ }
67
+
68
+ .tooltip-bubble.above .tooltip-tail {
69
+ bottom: -6px;
70
+ border-top: 6px solid #1a1a1a;
71
+ border-bottom: none;
72
+ }
73
+
74
+ .tooltip-bubble.below .tooltip-tail {
75
+ top: -6px;
76
+ border-bottom: 6px solid #1a1a1a;
77
+ border-top: none;
78
+ }
79
+
80
+ :host-context([data-theme="dark"]) .tooltip-bubble,
81
+ :host-context(.dark) .tooltip-bubble {
82
+ background-color: #ffffff;
83
+ color: #000000;
84
+ }
85
+
86
+ :host-context([data-theme="dark"]) .tooltip-bubble.above .tooltip-tail,
87
+ :host-context(.dark) .tooltip-bubble.above .tooltip-tail {
88
+ border-top-color: #ffffff;
89
+ }
90
+
91
+ :host-context([data-theme="dark"]) .tooltip-bubble.below .tooltip-tail,
92
+ :host-context(.dark) .tooltip-bubble.below .tooltip-tail {
93
+ border-bottom-color: #ffffff;
94
+ }
95
+ `;
96
+
97
+ firstUpdated() {
98
+ this.linkTrigger();
99
+ }
100
+
101
+ private linkTrigger() {
102
+ const slot = this.shadowRoot?.querySelector("slot");
103
+ if (!slot) return;
104
+ const trigger = slot.assignedElements()[0];
105
+ if (trigger) {
106
+ trigger.setAttribute("aria-describedby", `tooltip-${this.uniqueId}`);
107
+ }
108
+ }
109
+
110
+ render() {
111
+ return html`
112
+ <slot @slotchange="${this.linkTrigger}"></slot>
113
+ <div
114
+ class="tooltip-bubble ${this.position}"
115
+ id="tooltip-${this.uniqueId}"
116
+ role="tooltip"
117
+ >
118
+ ${this.text}
119
+ ${this.showTail ? html`<span class="tooltip-tail"></span>` : ""}
120
+ </div>
121
+ `;
122
+ }
123
+ }
@@ -1,5 +1,6 @@
1
1
  import { LitElement, html, css } from "lit";
2
2
  import { customElement } from "lit/decorators.js";
3
+ import "../../styles/vars-v2.css";
3
4
 
4
5
  @customElement("rel-topbar-actions")
5
6
  export class RelTopbarActions extends LitElement {
@@ -1,5 +1,6 @@
1
1
  import { LitElement, html, css } from "lit";
2
2
  import { customElement, property } from "lit/decorators.js";
3
+ import "../../styles/vars-v2.css";
3
4
 
4
5
  @customElement("rel-topbar-brand")
5
6
  export class RelTopbarBrand extends LitElement {