@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.
- package/dist/components/rel-accordion/rel-accordion.ts +20 -31
- package/dist/components/rel-alert/rel-alert.ts +81 -11
- package/dist/components/rel-avatar/rel-avatar.ts +6 -3
- package/dist/components/rel-badge/rel-badge.ts +8 -3
- package/dist/components/rel-breadcrumb/rel-breadcrumb.ts +6 -6
- package/dist/components/rel-button/rel-button.ts +118 -16
- package/dist/components/rel-calendar/rel-calendar.ts +16 -9
- package/dist/components/rel-card/rel-card.ts +9 -17
- package/dist/components/rel-cardmedia/rel-cardmedia.ts +20 -23
- package/dist/components/rel-carousel/rel-carousel.ts +596 -469
- package/dist/components/rel-checkbox/rel-checkbox.ts +98 -15
- package/dist/components/rel-chip/rel-chip.ts +291 -186
- package/dist/components/rel-container/rel-container.ts +2 -2
- package/dist/components/rel-date-picker/rel-date-picker.ts +23 -19
- package/dist/components/rel-divider/rel-divider.ts +12 -3
- package/dist/components/rel-drawer/rel-drawer-footer.ts +27 -0
- package/dist/components/rel-drawer/rel-drawer.ts +57 -113
- package/dist/components/rel-kbd/rel-kbd.ts +94 -118
- package/dist/components/rel-layout/rel-layout.ts +49 -58
- package/dist/components/rel-menu/rel-menu.ts +359 -327
- package/dist/components/rel-menubar/rel-menubar-menu.css +3 -0
- package/dist/components/rel-menubar/rel-menubar-menu.ts +2 -1
- package/dist/components/rel-menubar/rel-menubar.ts +602 -576
- package/dist/components/rel-nav-menu/rel-nav-menu-item.ts +240 -143
- package/dist/components/rel-nav-menu/rel-nav-menu.ts +227 -331
- package/dist/components/rel-navbar/rel-navbar.ts +13 -0
- package/dist/components/rel-otp/rel-otp.ts +22 -25
- package/dist/components/rel-pagination/rel-pagination.ts +112 -63
- package/dist/components/rel-popover/rel-popover-content.ts +6 -5
- package/dist/components/rel-popover/rel-popover.ts +42 -20
- package/dist/components/rel-progress/rel-progress.ts +10 -9
- package/dist/components/rel-radio/rel-radio.ts +228 -155
- package/dist/components/rel-range-picker/rel-range-picker.css +349 -0
- package/dist/components/rel-range-picker/rel-range-picker.ts +1079 -0
- package/dist/components/rel-resizable/rel-resizable-handle.ts +12 -15
- package/dist/components/rel-segmented-button/rel-segmented-button.ts +41 -20
- package/dist/components/rel-select/rel-select.ts +112 -27
- package/dist/components/rel-sheet/rel-sheet.ts +362 -683
- package/dist/components/rel-sidebar/rel-sidebar.ts +13 -5
- package/dist/components/rel-slider/rel-slider.ts +74 -29
- package/dist/components/rel-snackbar/rel-snackbar.ts +67 -37
- package/dist/components/rel-stepper/rel-stepper.ts +43 -31
- package/dist/components/rel-switch/rel-switch.ts +26 -12
- package/dist/components/rel-tab/rel-tab.ts +57 -37
- package/dist/components/rel-table/rel-table-body.ts +5 -0
- package/dist/components/rel-table/rel-table-caption.ts +6 -1
- package/dist/components/rel-table/rel-table-cell.ts +42 -49
- package/dist/components/rel-table/rel-table-footer.ts +5 -0
- package/dist/components/rel-table/rel-table-head.ts +13 -1
- package/dist/components/rel-table/rel-table-header.ts +5 -0
- package/dist/components/rel-table/rel-table-row.ts +7 -3
- package/dist/components/rel-table/rel-table.ts +8 -2
- package/dist/components/rel-textfield/rel-textfield.ts +153 -44
- package/dist/components/rel-toast/rel-toast.ts +56 -22
- package/dist/components/rel-tooltip/rel-tooltip.ts +52 -9
- package/dist/components/rel-topbar/rel-topbar-actions.ts +24 -0
- package/dist/components/rel-topbar/rel-topbar-brand.ts +47 -0
- package/dist/components/rel-topbar/rel-topbar-dropdown-item.ts +63 -0
- package/dist/components/rel-topbar/rel-topbar-dropdown.ts +28 -0
- package/dist/components/rel-topbar/rel-topbar-item.ts +320 -0
- package/dist/components/rel-topbar/rel-topbar-mobile-panel.ts +24 -0
- package/dist/components/rel-topbar/rel-topbar-profile.ts +222 -0
- package/dist/components/rel-topbar/rel-topbar-utilities.ts +24 -0
- package/dist/components/rel-topbar/rel-topbar.ts +438 -0
- package/dist/index.d.mts +375 -411
- package/dist/index.d.ts +375 -411
- package/dist/index.js +7587 -7980
- package/dist/index.js.map +1 -1
- package/dist/index.mjs +7647 -8023
- package/dist/index.mjs.map +1 -1
- package/dist/rel-menubar-menu-BEEQDAXW.css +3 -0
- package/dist/styles/vars-v2.css +525 -0
- package/dist/styles/vars.css +79 -27
- package/dist/{vars-ITL2K3KO.css → vars-I2PC74XD.css} +79 -27
- package/dist/vars-v2-VMGWTFJZ.css +525 -0
- package/package.json +3 -1
- package/dist/components/rel-quote-page/README.md +0 -166
- package/dist/components/rel-quote-page/rel-quote-page.ts +0 -816
|
@@ -1,7 +1,9 @@
|
|
|
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
|
-
export type TextFieldState = "default" | "
|
|
6
|
+
export type TextFieldState = "default" | "error" | "disabled";
|
|
5
7
|
export type TextFieldSize = "small" | "medium" | "large";
|
|
6
8
|
|
|
7
9
|
@customElement("rel-textfield")
|
|
@@ -15,28 +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
|
-
@state() private internalState:
|
|
22
|
+
@state() private internalState: "default" | "focused" = "default";
|
|
23
|
+
private _wasError = false;
|
|
24
|
+
|
|
25
|
+
private uniqueId = `textfield-${Math.random().toString(36).slice(2)}`;
|
|
20
26
|
|
|
21
27
|
static styles = css`
|
|
22
28
|
:host {
|
|
23
29
|
display: block;
|
|
24
|
-
font-family: var(--rel-fontFamilies-primary
|
|
30
|
+
font-family: var(--rel-fontFamilies-primary);
|
|
25
31
|
}
|
|
26
32
|
|
|
27
33
|
/* Wrapper */
|
|
28
34
|
.textfield-wrapper {
|
|
29
35
|
display: flex;
|
|
30
36
|
flex-direction: column;
|
|
31
|
-
gap: var(--rel-spacing-space-2xs
|
|
37
|
+
gap: var(--rel-spacing-space-2xs);
|
|
32
38
|
width: 100%;
|
|
33
39
|
}
|
|
34
40
|
|
|
35
41
|
/* Label */
|
|
36
42
|
.textfield-label {
|
|
37
|
-
font-size: var(--rel-fontSizes-sm
|
|
38
|
-
font-weight: var(--rel-fontWeights-medium
|
|
39
|
-
color: var(--rel-text-heading
|
|
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);
|
|
40
120
|
}
|
|
41
121
|
|
|
42
122
|
/* Container */
|
|
@@ -44,14 +124,15 @@ export class RelTextfield extends LitElement {
|
|
|
44
124
|
display: flex;
|
|
45
125
|
align-items: center;
|
|
46
126
|
position: relative;
|
|
47
|
-
border: 1px solid var(--rel-border-default
|
|
48
|
-
border-radius: var(--rel-borders-radius-border-radius-
|
|
49
|
-
background: var(--rel-
|
|
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;
|
|
50
131
|
transition: border 0.2s;
|
|
51
132
|
}
|
|
52
133
|
|
|
53
134
|
.textfield-container.disabled {
|
|
54
|
-
background: var(--rel-
|
|
135
|
+
background: var(--rel-color-bg-tertiary);
|
|
55
136
|
cursor: not-allowed;
|
|
56
137
|
}
|
|
57
138
|
|
|
@@ -60,23 +141,23 @@ export class RelTextfield extends LitElement {
|
|
|
60
141
|
flex: 1;
|
|
61
142
|
border: none;
|
|
62
143
|
outline: none;
|
|
63
|
-
font-size: var(--rel-fontSizes-md
|
|
64
|
-
padding:
|
|
144
|
+
font-size: var(--rel-fontSizes-md);
|
|
145
|
+
padding: var(--rel-spacing-space-xs) var(--rel-spacing-space-sm);
|
|
65
146
|
background: transparent;
|
|
66
|
-
font-family: var(--rel-fontFamilies-primary
|
|
67
|
-
color: var(--rel-text-primary
|
|
147
|
+
font-family: var(--rel-fontFamilies-primary);
|
|
148
|
+
color: var(--rel-color-text-primary);
|
|
68
149
|
}
|
|
69
150
|
|
|
70
151
|
.textfield-input:disabled {
|
|
71
152
|
cursor: not-allowed;
|
|
72
|
-
color: var(--rel-text-disabled
|
|
153
|
+
color: var(--rel-color-text-disabled);
|
|
73
154
|
}
|
|
74
155
|
|
|
75
156
|
.icon {
|
|
76
157
|
position: absolute;
|
|
77
158
|
display: flex;
|
|
78
159
|
pointer-events: none;
|
|
79
|
-
color: var(--rel-text-placeholder
|
|
160
|
+
color: var(--rel-color-text-placeholder);
|
|
80
161
|
}
|
|
81
162
|
|
|
82
163
|
.icon.left {
|
|
@@ -88,32 +169,32 @@ export class RelTextfield extends LitElement {
|
|
|
88
169
|
}
|
|
89
170
|
|
|
90
171
|
.textfield-wrapper.small .textfield-input {
|
|
91
|
-
padding:
|
|
92
|
-
font-size:
|
|
172
|
+
padding: var(--rel-spacing-space-xs) var(--rel-spacing-space-sm);
|
|
173
|
+
font-size: var(--rel-fontSizes-sm);
|
|
93
174
|
}
|
|
94
175
|
|
|
95
176
|
.textfield-wrapper.medium .textfield-input {
|
|
96
|
-
padding:
|
|
97
|
-
font-size:
|
|
177
|
+
padding: var(--rel-spacing-space-sm) var(--rel-spacing-space-md);
|
|
178
|
+
font-size: var(--rel-fontSizes-md);
|
|
98
179
|
}
|
|
99
180
|
|
|
100
181
|
.textfield-wrapper.large .textfield-input {
|
|
101
|
-
padding:
|
|
102
|
-
font-size:
|
|
182
|
+
padding: var(--rel-spacing-space-md) var(--rel-spacing-space-md);
|
|
183
|
+
font-size: var(--rel-fontSizes-lg);
|
|
103
184
|
}
|
|
104
185
|
|
|
105
186
|
/* Adjust padding when icons are present */
|
|
106
187
|
.textfield-wrapper .textfield-input.has-left-icon {
|
|
107
|
-
padding-left:
|
|
188
|
+
padding-left: var(--rel-spacing-space-2xl);
|
|
108
189
|
}
|
|
109
190
|
|
|
110
191
|
.textfield-wrapper .textfield-input.has-right-icon {
|
|
111
|
-
padding-right:
|
|
192
|
+
padding-right: var(--rel-spacing-space-2xl);
|
|
112
193
|
}
|
|
113
194
|
|
|
114
195
|
/* States */
|
|
115
196
|
.textfield-wrapper.focused .textfield-container {
|
|
116
|
-
border-color: var(--rel-
|
|
197
|
+
border-color: var(--rel-color-text-primary);
|
|
117
198
|
}
|
|
118
199
|
|
|
119
200
|
.textfield-input:focus-visible {
|
|
@@ -122,40 +203,53 @@ export class RelTextfield extends LitElement {
|
|
|
122
203
|
|
|
123
204
|
.textfield-wrapper.focused .textfield-container,
|
|
124
205
|
.textfield-container:focus-within {
|
|
125
|
-
border-color: var(--rel-
|
|
126
|
-
box-shadow: 0 0 0 1px var(--rel-
|
|
206
|
+
border-color: var(--rel-color-text-primary);
|
|
207
|
+
box-shadow: 0 0 0 1px var(--rel-color-text-primary);
|
|
127
208
|
}
|
|
128
209
|
|
|
129
210
|
.textfield-wrapper.error .textfield-container {
|
|
130
|
-
border-color: var(--rel-
|
|
211
|
+
border-color: var(--rel-error-surface-default);
|
|
212
|
+
box-shadow: none;
|
|
131
213
|
}
|
|
132
214
|
|
|
133
215
|
.textfield-wrapper.disabled .textfield-container {
|
|
134
|
-
border-color: var(--rel-border-default
|
|
216
|
+
border-color: var(--rel-color-border-default);
|
|
135
217
|
}
|
|
136
218
|
|
|
137
219
|
/* Supporting text */
|
|
138
220
|
.textfield-support {
|
|
139
|
-
font-size: var(--rel-fontSizes-xs
|
|
140
|
-
color: var(--rel-text-placeholder
|
|
221
|
+
font-size: var(--rel-fontSizes-xs);
|
|
222
|
+
color: var(--rel-color-text-placeholder);
|
|
141
223
|
}
|
|
142
224
|
|
|
143
225
|
.textfield-support.error {
|
|
144
|
-
color: var(--rel-text
|
|
226
|
+
color: var(--rel-error-text);
|
|
145
227
|
}
|
|
146
228
|
|
|
147
229
|
/* Placeholder */
|
|
148
230
|
.textfield-input::placeholder {
|
|
149
|
-
color: var(--rel-text-placeholder
|
|
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);
|
|
150
240
|
}
|
|
151
241
|
`;
|
|
152
242
|
|
|
153
|
-
|
|
154
|
-
|
|
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;
|
|
155
249
|
}
|
|
156
250
|
|
|
157
251
|
private handleFocus() {
|
|
158
|
-
if (this.state !== "disabled"
|
|
252
|
+
if (this.state !== "disabled") {
|
|
159
253
|
this.internalState = "focused";
|
|
160
254
|
}
|
|
161
255
|
}
|
|
@@ -169,8 +263,15 @@ export class RelTextfield extends LitElement {
|
|
|
169
263
|
private handleInput(e: Event) {
|
|
170
264
|
const input = e.target as HTMLInputElement;
|
|
171
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
|
+
}
|
|
172
273
|
this.dispatchEvent(
|
|
173
|
-
new CustomEvent<string>("
|
|
274
|
+
new CustomEvent<string>("rel-change", {
|
|
174
275
|
detail: this.value,
|
|
175
276
|
bubbles: true,
|
|
176
277
|
composed: true,
|
|
@@ -182,8 +283,10 @@ export class RelTextfield extends LitElement {
|
|
|
182
283
|
const wrapperClasses = [
|
|
183
284
|
"textfield-wrapper",
|
|
184
285
|
this.size,
|
|
185
|
-
this.
|
|
186
|
-
|
|
286
|
+
this.state,
|
|
287
|
+
this.internalState === "focused" ? "focused" : "",
|
|
288
|
+
this.value ? "has-value" : "",
|
|
289
|
+
].filter(Boolean).join(" ");
|
|
187
290
|
|
|
188
291
|
const inputClasses = [
|
|
189
292
|
"textfield-input",
|
|
@@ -195,8 +298,8 @@ export class RelTextfield extends LitElement {
|
|
|
195
298
|
|
|
196
299
|
return html`
|
|
197
300
|
<div class="${wrapperClasses}">
|
|
198
|
-
${this.label
|
|
199
|
-
? html`<label class="textfield-label">${this.label}</label>`
|
|
301
|
+
${!this.floatingLabel && this.label
|
|
302
|
+
? html`<label class="textfield-label" for="${this.uniqueId}">${this.label}</label>`
|
|
200
303
|
: ""}
|
|
201
304
|
|
|
202
305
|
<div
|
|
@@ -204,12 +307,18 @@ export class RelTextfield extends LitElement {
|
|
|
204
307
|
? "disabled"
|
|
205
308
|
: ""}"
|
|
206
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
|
+
: ""}
|
|
207
315
|
${this.leftIcon
|
|
208
|
-
? html`<
|
|
316
|
+
? html`<rel-icon name="${this.leftIcon}" size="sm" class="icon left"></rel-icon>`
|
|
209
317
|
: ""}
|
|
210
318
|
|
|
211
319
|
<input
|
|
212
320
|
type="${this.type}"
|
|
321
|
+
id="${this.uniqueId}"
|
|
213
322
|
class="${inputClasses}"
|
|
214
323
|
placeholder="${this.placeholder}"
|
|
215
324
|
.value="${this.value}"
|
|
@@ -221,7 +330,7 @@ export class RelTextfield extends LitElement {
|
|
|
221
330
|
/>
|
|
222
331
|
|
|
223
332
|
${this.rightIcon
|
|
224
|
-
? html`<
|
|
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
|
|
|
@@ -9,9 +10,10 @@ export class RelToast extends LitElement {
|
|
|
9
10
|
@property({ type: String }) type: ToastType = "default";
|
|
10
11
|
@property({ type: String }) actionLabel?: string;
|
|
11
12
|
@property({ type: Number }) duration: number = 4000;
|
|
13
|
+
@property({ type: Boolean, reflect: true }) show = false;
|
|
12
14
|
|
|
13
15
|
@state() private visible: boolean = false;
|
|
14
|
-
private
|
|
16
|
+
private _dismissTimer: ReturnType<typeof setTimeout> | null = null;
|
|
15
17
|
|
|
16
18
|
static styles = css`
|
|
17
19
|
:host {
|
|
@@ -23,7 +25,7 @@ export class RelToast extends LitElement {
|
|
|
23
25
|
justify-content: center;
|
|
24
26
|
width: 100%;
|
|
25
27
|
pointer-events: none;
|
|
26
|
-
z-index:
|
|
28
|
+
z-index: var(--rel-z-toast, 9000);
|
|
27
29
|
font-family: var(--rel-fontFamilies-primary);
|
|
28
30
|
}
|
|
29
31
|
|
|
@@ -31,20 +33,20 @@ export class RelToast extends LitElement {
|
|
|
31
33
|
.toast {
|
|
32
34
|
display: inline-flex;
|
|
33
35
|
align-items: center;
|
|
34
|
-
gap: var(--rel-spacing-space-sm
|
|
35
|
-
background-color: var(--rel-
|
|
36
|
-
color: var(--rel-
|
|
37
|
-
font-family: var(--rel-fontFamilies-primary
|
|
38
|
-
font-size: var(--rel-fontSizes-md
|
|
39
|
-
border-radius: var(--rel-borders-radius-border-radius-200
|
|
40
|
-
padding: var(--rel-spacing-space-md
|
|
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);
|
|
41
43
|
box-shadow: var(--rel-shadows-shadow-300);
|
|
42
44
|
pointer-events: all;
|
|
43
45
|
animation: fadeInUp 0.25s ease;
|
|
44
46
|
}
|
|
45
47
|
|
|
46
48
|
.toast.error {
|
|
47
|
-
background-color: var(--rel-
|
|
49
|
+
background-color: var(--rel-error-surface-default);
|
|
48
50
|
}
|
|
49
51
|
|
|
50
52
|
.toast.hidden {
|
|
@@ -73,7 +75,7 @@ export class RelToast extends LitElement {
|
|
|
73
75
|
}
|
|
74
76
|
|
|
75
77
|
.toast-action:focus-visible {
|
|
76
|
-
outline: 2px solid
|
|
78
|
+
outline: 2px solid #FFFFFF;
|
|
77
79
|
outline-offset: 2px;
|
|
78
80
|
border-radius: 2px;
|
|
79
81
|
}
|
|
@@ -86,8 +88,8 @@ export class RelToast extends LitElement {
|
|
|
86
88
|
font-size: 1rem;
|
|
87
89
|
cursor: pointer;
|
|
88
90
|
line-height: 1;
|
|
89
|
-
padding: var(--rel-spacing-space-2xs
|
|
90
|
-
margin-left: var(--rel-spacing-space-2xs
|
|
91
|
+
padding: var(--rel-spacing-space-2xs);
|
|
92
|
+
margin-left: var(--rel-spacing-space-2xs);
|
|
91
93
|
}
|
|
92
94
|
|
|
93
95
|
.toast-close:hover {
|
|
@@ -95,11 +97,23 @@ export class RelToast extends LitElement {
|
|
|
95
97
|
}
|
|
96
98
|
|
|
97
99
|
.toast-close:focus-visible {
|
|
98
|
-
outline: 2px solid
|
|
100
|
+
outline: 2px solid #FFFFFF;
|
|
99
101
|
outline-offset: 2px;
|
|
100
102
|
border-radius: 2px;
|
|
101
103
|
}
|
|
102
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
|
+
|
|
103
117
|
@media (prefers-reduced-motion: reduce) {
|
|
104
118
|
.toast {
|
|
105
119
|
animation: none;
|
|
@@ -119,25 +133,45 @@ export class RelToast extends LitElement {
|
|
|
119
133
|
}
|
|
120
134
|
`;
|
|
121
135
|
|
|
122
|
-
|
|
123
|
-
|
|
124
|
-
|
|
125
|
-
|
|
126
|
-
|
|
136
|
+
willUpdate(changed: Map<string, unknown>) {
|
|
137
|
+
if (!changed.has('show')) return;
|
|
138
|
+
if (this.show) {
|
|
139
|
+
this.visible = true;
|
|
140
|
+
if (this._dismissTimer) clearTimeout(this._dismissTimer);
|
|
141
|
+
if (this.duration > 0) {
|
|
142
|
+
this._dismissTimer = setTimeout(() => this.close(), this.duration);
|
|
143
|
+
}
|
|
144
|
+
} else {
|
|
145
|
+
this.visible = false;
|
|
146
|
+
if (this._dismissTimer) {
|
|
147
|
+
clearTimeout(this._dismissTimer);
|
|
148
|
+
this._dismissTimer = null;
|
|
149
|
+
}
|
|
127
150
|
}
|
|
128
151
|
}
|
|
129
152
|
|
|
153
|
+
disconnectedCallback() {
|
|
154
|
+
super.disconnectedCallback();
|
|
155
|
+
if (this._dismissTimer) clearTimeout(this._dismissTimer);
|
|
156
|
+
}
|
|
157
|
+
|
|
158
|
+
open() {
|
|
159
|
+
this.show = true;
|
|
160
|
+
}
|
|
161
|
+
|
|
130
162
|
close() {
|
|
163
|
+
this.show = false;
|
|
131
164
|
this.visible = false;
|
|
165
|
+
if (this._dismissTimer) {
|
|
166
|
+
clearTimeout(this._dismissTimer);
|
|
167
|
+
this._dismissTimer = null;
|
|
168
|
+
}
|
|
132
169
|
this.dispatchEvent(
|
|
133
170
|
new CustomEvent("dismissed", {
|
|
134
171
|
bubbles: true,
|
|
135
172
|
composed: true,
|
|
136
173
|
})
|
|
137
174
|
);
|
|
138
|
-
if (this.timeoutId) {
|
|
139
|
-
clearTimeout(this.timeoutId);
|
|
140
|
-
}
|
|
141
175
|
}
|
|
142
176
|
|
|
143
177
|
private handleActionClick(event: Event) {
|
|
@@ -7,7 +7,11 @@ export type TooltipPosition = "above" | "below";
|
|
|
7
7
|
export class RelTooltip extends LitElement {
|
|
8
8
|
@property({ type: String }) text: string = "";
|
|
9
9
|
@property({ type: String }) position: TooltipPosition = "above";
|
|
10
|
-
@property({ type: Boolean }) showTail: boolean =
|
|
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);
|
|
11
15
|
|
|
12
16
|
static styles = css`
|
|
13
17
|
:host {
|
|
@@ -20,9 +24,10 @@ export class RelTooltip extends LitElement {
|
|
|
20
24
|
position: absolute;
|
|
21
25
|
left: 50%;
|
|
22
26
|
transform: translateX(-50%);
|
|
23
|
-
background-color:
|
|
24
|
-
color:
|
|
25
|
-
padding: var(--rel-spacing-space-xs, 8px)
|
|
27
|
+
background-color: #1a1a1a;
|
|
28
|
+
color: #ffffff;
|
|
29
|
+
padding: var(--rel-spacing-space-xs, 8px)
|
|
30
|
+
var(--rel-spacing-space-sm, 12px);
|
|
26
31
|
border-radius: var(--rel-borders-radius-border-radius-200, 8px);
|
|
27
32
|
font-size: var(--rel-fontSizes-sm, 12px);
|
|
28
33
|
font-family: var(--rel-fontFamilies-primary, sans-serif);
|
|
@@ -31,9 +36,11 @@ export class RelTooltip extends LitElement {
|
|
|
31
36
|
opacity: 0;
|
|
32
37
|
pointer-events: none;
|
|
33
38
|
transition: opacity 0.2s ease;
|
|
39
|
+
overflow: visible;
|
|
34
40
|
}
|
|
35
41
|
|
|
36
|
-
:host(:hover) .tooltip-bubble
|
|
42
|
+
:host(:hover) .tooltip-bubble,
|
|
43
|
+
:host(:focus-within) .tooltip-bubble {
|
|
37
44
|
opacity: 1;
|
|
38
45
|
}
|
|
39
46
|
|
|
@@ -55,23 +62,59 @@ export class RelTooltip extends LitElement {
|
|
|
55
62
|
height: 0;
|
|
56
63
|
border-left: 6px solid transparent;
|
|
57
64
|
border-right: 6px solid transparent;
|
|
65
|
+
display: block;
|
|
58
66
|
}
|
|
59
67
|
|
|
60
68
|
.tooltip-bubble.above .tooltip-tail {
|
|
61
69
|
bottom: -6px;
|
|
62
|
-
border-top: 6px solid
|
|
70
|
+
border-top: 6px solid #1a1a1a;
|
|
71
|
+
border-bottom: none;
|
|
63
72
|
}
|
|
64
73
|
|
|
65
74
|
.tooltip-bubble.below .tooltip-tail {
|
|
66
75
|
top: -6px;
|
|
67
|
-
border-bottom: 6px solid
|
|
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;
|
|
68
94
|
}
|
|
69
95
|
`;
|
|
70
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
|
+
|
|
71
110
|
render() {
|
|
72
111
|
return html`
|
|
73
|
-
<slot></slot>
|
|
74
|
-
<div
|
|
112
|
+
<slot @slotchange="${this.linkTrigger}"></slot>
|
|
113
|
+
<div
|
|
114
|
+
class="tooltip-bubble ${this.position}"
|
|
115
|
+
id="tooltip-${this.uniqueId}"
|
|
116
|
+
role="tooltip"
|
|
117
|
+
>
|
|
75
118
|
${this.text}
|
|
76
119
|
${this.showTail ? html`<span class="tooltip-tail"></span>` : ""}
|
|
77
120
|
</div>
|
|
@@ -0,0 +1,24 @@
|
|
|
1
|
+
import { LitElement, html, css } from "lit";
|
|
2
|
+
import { customElement } from "lit/decorators.js";
|
|
3
|
+
import "../../styles/vars-v2.css";
|
|
4
|
+
|
|
5
|
+
@customElement("rel-topbar-actions")
|
|
6
|
+
export class RelTopbarActions extends LitElement {
|
|
7
|
+
static styles = css`
|
|
8
|
+
.actions {
|
|
9
|
+
display: inline-flex;
|
|
10
|
+
align-items: center;
|
|
11
|
+
gap: var(--rel-spacing-space-xs, 8px);
|
|
12
|
+
}
|
|
13
|
+
`;
|
|
14
|
+
|
|
15
|
+
render() {
|
|
16
|
+
return html`<div class="actions"><slot></slot></div>`;
|
|
17
|
+
}
|
|
18
|
+
}
|
|
19
|
+
|
|
20
|
+
declare global {
|
|
21
|
+
interface HTMLElementTagNameMap {
|
|
22
|
+
"rel-topbar-actions": RelTopbarActions;
|
|
23
|
+
}
|
|
24
|
+
}
|
|
@@ -0,0 +1,47 @@
|
|
|
1
|
+
import { LitElement, html, css } from "lit";
|
|
2
|
+
import { customElement, property } from "lit/decorators.js";
|
|
3
|
+
import "../../styles/vars-v2.css";
|
|
4
|
+
|
|
5
|
+
@customElement("rel-topbar-brand")
|
|
6
|
+
export class RelTopbarBrand extends LitElement {
|
|
7
|
+
@property({ type: String }) src: string = "";
|
|
8
|
+
@property({ type: String }) href: string = "/";
|
|
9
|
+
@property({ type: String }) label: string = "";
|
|
10
|
+
|
|
11
|
+
static styles = css`
|
|
12
|
+
:host {
|
|
13
|
+
display: inline-flex;
|
|
14
|
+
align-items: center;
|
|
15
|
+
}
|
|
16
|
+
|
|
17
|
+
a {
|
|
18
|
+
display: inline-flex;
|
|
19
|
+
align-items: center;
|
|
20
|
+
gap: var(--rel-spacing-space-xs);
|
|
21
|
+
text-decoration: none;
|
|
22
|
+
color: var(--rel-color-text-primary);
|
|
23
|
+
font-weight: var(--rel-fontWeights-semibold);
|
|
24
|
+
font-size: var(--rel-fontSizes-md);
|
|
25
|
+
}
|
|
26
|
+
|
|
27
|
+
img {
|
|
28
|
+
display: block;
|
|
29
|
+
}
|
|
30
|
+
`;
|
|
31
|
+
|
|
32
|
+
render() {
|
|
33
|
+
return html`
|
|
34
|
+
<a href="${this.href}" aria-label="${this.label || "Home"}">
|
|
35
|
+
${this.src
|
|
36
|
+
? html`<img src="${this.src}" alt="${this.label}" />`
|
|
37
|
+
: html`<slot>${this.label}</slot>`}
|
|
38
|
+
</a>
|
|
39
|
+
`;
|
|
40
|
+
}
|
|
41
|
+
}
|
|
42
|
+
|
|
43
|
+
declare global {
|
|
44
|
+
interface HTMLElementTagNameMap {
|
|
45
|
+
"rel-topbar-brand": RelTopbarBrand;
|
|
46
|
+
}
|
|
47
|
+
}
|