@reliability-design/web 1.3.1 → 1.4.1
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/CHANGELOG.md +22 -0
- package/dist/components/rel-accordion/README.md +13 -13
- package/dist/components/rel-accordion/rel-accordion.ts +80 -45
- package/dist/components/rel-alert/README.md +15 -15
- package/dist/components/rel-alert/rel-alert.ts +149 -158
- package/dist/components/rel-avatar/README.md +15 -15
- package/dist/components/rel-avatar/rel-avatar.ts +42 -38
- package/dist/components/rel-badge/README.md +5 -5
- package/dist/components/rel-badge/rel-badge.ts +46 -11
- package/dist/components/rel-breadcrumb/README.md +7 -7
- package/dist/components/rel-breadcrumb/rel-breadcrumb.ts +16 -13
- package/dist/components/rel-button/README.md +20 -20
- package/dist/components/rel-button/rel-button.ts +292 -105
- package/dist/components/rel-calendar/README.md +5 -5
- package/dist/components/rel-calendar/rel-calendar.ts +68 -45
- package/dist/components/rel-card/README.md +6 -6
- package/dist/components/rel-card/rel-card.ts +88 -35
- package/dist/components/rel-cardmedia/README.md +9 -9
- package/dist/components/rel-cardmedia/rel-cardmedia.ts +27 -20
- package/dist/components/rel-carousel/README.md +3 -3
- package/dist/components/rel-carousel/rel-carousel.ts +174 -90
- package/dist/components/rel-chart/README.md +8 -8
- package/dist/components/rel-chart/rel-chart.ts +59 -41
- package/dist/components/rel-checkbox/README.md +7 -7
- package/dist/components/rel-checkbox/rel-checkbox.ts +61 -61
- package/dist/components/rel-chip/README.md +16 -16
- package/dist/components/rel-chip/rel-chip.ts +143 -111
- package/dist/components/rel-container/README.md +11 -11
- package/dist/components/rel-container/rel-container.ts +35 -9
- package/dist/components/rel-date-picker/README.md +43 -7
- package/dist/components/rel-date-picker/date-format.test.ts +43 -0
- package/dist/components/rel-date-picker/date-format.ts +47 -0
- package/dist/components/rel-date-picker/rel-date-picker.ts +154 -82
- package/dist/components/rel-divider/README.md +9 -9
- package/dist/components/rel-divider/rel-divider.ts +10 -9
- package/dist/components/rel-drawer/README.md +1 -1
- package/dist/components/rel-drawer/rel-drawer-footer.ts +1 -1
- package/dist/components/rel-drawer/rel-drawer.ts +88 -25
- package/dist/components/rel-kbd/README.md +20 -20
- package/dist/components/rel-kbd/rel-kbd.ts +119 -25
- package/dist/components/rel-layout/README.md +1 -1
- package/dist/components/rel-layout/rel-layout.ts +2 -2
- package/dist/components/rel-menu/README.md +15 -15
- package/dist/components/rel-menu/rel-menu.ts +155 -88
- package/dist/components/rel-menubar/README.md +20 -20
- package/dist/components/rel-menubar/rel-menubar.ts +47 -31
- package/dist/components/rel-nav-menu/README.md +21 -21
- package/dist/components/rel-nav-menu/rel-nav-menu-item.ts +17 -14
- package/dist/components/rel-nav-menu/rel-nav-menu-panel.ts +33 -14
- package/dist/components/rel-nav-menu/rel-nav-menu.ts +14 -7
- package/dist/components/rel-navbar/README.md +7 -7
- package/dist/components/rel-navbar/rel-navbar.ts +12 -11
- package/dist/components/rel-otp/README.md +3 -3
- package/dist/components/rel-otp/rel-otp.ts +46 -30
- package/dist/components/rel-pagination/README.md +18 -18
- package/dist/components/rel-pagination/rel-pagination.ts +141 -90
- package/dist/components/rel-popover/README.md +13 -13
- package/dist/components/rel-popover/rel-popover-content.ts +39 -14
- package/dist/components/rel-popover/rel-popover.ts +18 -7
- package/dist/components/rel-progress/README.md +5 -5
- package/dist/components/rel-progress/rel-progress.ts +16 -12
- package/dist/components/rel-radio/README.md +9 -9
- package/dist/components/rel-radio/rel-radio.ts +64 -50
- package/dist/components/rel-range-picker/rel-range-picker.ts +120 -117
- package/dist/components/rel-resizable/README.md +4 -4
- package/dist/components/rel-resizable/rel-resizable-group.ts +15 -4
- package/dist/components/rel-resizable/rel-resizable-handle.ts +13 -9
- package/dist/components/rel-resizable/rel-resizable-panel.ts +11 -0
- package/dist/components/rel-segmented-button/README.md +10 -10
- package/dist/components/rel-segmented-button/rel-segmented-button.ts +39 -40
- package/dist/components/rel-select/README.md +14 -14
- package/dist/components/rel-select/rel-select.ts +120 -188
- package/dist/components/rel-sheet/README.md +10 -10
- package/dist/components/rel-sheet/rel-sheet.ts +82 -23
- package/dist/components/rel-sidebar/README.md +5 -5
- package/dist/components/rel-sidebar/rel-sidebar.ts +75 -60
- package/dist/components/rel-skeleton/rel-skeleton.ts +8 -13
- package/dist/components/rel-slider/README.md +10 -10
- package/dist/components/rel-slider/rel-slider.ts +230 -57
- package/dist/components/rel-snackbar/README.md +9 -9
- package/dist/components/rel-snackbar/rel-snackbar.ts +44 -32
- package/dist/components/rel-stepper/README.md +10 -10
- package/dist/components/rel-stepper/rel-stepper.ts +110 -46
- package/dist/components/rel-switch/README.md +5 -5
- package/dist/components/rel-switch/rel-switch.ts +23 -12
- package/dist/components/rel-tab/README.md +13 -13
- package/dist/components/rel-tab/rel-tab.ts +63 -19
- package/dist/components/rel-table/README.md +7 -7
- package/dist/components/rel-table/rel-table-body.ts +2 -1
- package/dist/components/rel-table/rel-table-caption.ts +10 -7
- package/dist/components/rel-table/rel-table-cell.ts +7 -6
- package/dist/components/rel-table/rel-table-footer.ts +4 -3
- package/dist/components/rel-table/rel-table-head.ts +11 -9
- package/dist/components/rel-table/rel-table-header.ts +2 -1
- package/dist/components/rel-table/rel-table-row.ts +5 -4
- package/dist/components/rel-table/rel-table.ts +16 -7
- package/dist/components/rel-textfield/README.md +11 -11
- package/dist/components/rel-textfield/rel-textfield.ts +218 -92
- package/dist/components/rel-toast/README.md +11 -11
- package/dist/components/rel-toast/rel-toast.ts +33 -30
- package/dist/components/rel-tooltip/README.md +7 -7
- package/dist/components/rel-tooltip/rel-tooltip.ts +160 -123
- package/dist/components/rel-topbar/rel-topbar-actions.ts +1 -2
- package/dist/components/rel-topbar/rel-topbar-brand.ts +8 -5
- package/dist/components/rel-topbar/rel-topbar-dropdown-item.ts +10 -8
- package/dist/components/rel-topbar/rel-topbar-dropdown.ts +4 -5
- package/dist/components/rel-topbar/rel-topbar-item.ts +23 -22
- package/dist/components/rel-topbar/rel-topbar-mobile-panel.ts +0 -1
- package/dist/components/rel-topbar/rel-topbar-profile.ts +68 -50
- package/dist/components/rel-topbar/rel-topbar-utilities.ts +1 -2
- package/dist/components/rel-topbar/rel-topbar.ts +31 -29
- package/dist/index.d.mts +159 -39
- package/dist/index.d.ts +159 -39
- package/dist/index.js +3600 -2269
- package/dist/index.js.map +1 -1
- package/dist/index.mjs +3930 -2600
- package/dist/index.mjs.map +1 -1
- package/dist/styles/vars.css +866 -363
- package/dist/vars-BYCEEKWJ.css +866 -0
- package/package.json +5 -3
- package/dist/components/rel-range-picker/rel-range-picker.css +0 -349
- package/dist/styles/vars-v2.css +0 -525
- package/dist/vars-F54UGCHM.css +0 -363
- package/dist/vars-v2-VMGWTFJZ.css +0 -525
|
@@ -1,6 +1,5 @@
|
|
|
1
1
|
import { LitElement, html, css, nothing } from "lit";
|
|
2
2
|
import { customElement, property, state } from "lit/decorators.js";
|
|
3
|
-
import "../../styles/vars-v2.css";
|
|
4
3
|
import "@reliability-design/icons/rel-icon";
|
|
5
4
|
|
|
6
5
|
export type TextFieldState = "default" | "error" | "disabled";
|
|
@@ -15,6 +14,11 @@ export class RelTextfield extends LitElement {
|
|
|
15
14
|
@property({ type: String }) value: string = "";
|
|
16
15
|
@property({ type: String }) leftIcon?: string;
|
|
17
16
|
@property({ type: String }) rightIcon?: string;
|
|
17
|
+
/** Makes the trailing icon interactive (pointer + focusable) and emits
|
|
18
|
+
* `rel-right-icon-click` — e.g. a password show/hide toggle or clear button. */
|
|
19
|
+
@property({ type: Boolean, attribute: "clickable-right-icon" }) clickableRightIcon = false;
|
|
20
|
+
/** Accessible label for the trailing icon when it is clickable. */
|
|
21
|
+
@property({ type: String, attribute: "right-icon-aria-label" }) rightIconAriaLabel?: string;
|
|
18
22
|
@property({ type: String }) supportingText?: string;
|
|
19
23
|
@property({ type: String }) state: TextFieldState = "default";
|
|
20
24
|
@property({ type: String }) size: TextFieldSize = "medium";
|
|
@@ -63,27 +67,37 @@ export class RelTextfield extends LitElement {
|
|
|
63
67
|
|
|
64
68
|
static styles = css`
|
|
65
69
|
:host {
|
|
70
|
+
color: var(--rel-text-default);
|
|
66
71
|
display: block;
|
|
67
|
-
font-family: var(--rel-
|
|
72
|
+
font-family: var(--rel-fonts-font-family);
|
|
68
73
|
}
|
|
69
74
|
|
|
70
75
|
/* Wrapper */
|
|
71
76
|
.textfield-wrapper {
|
|
72
77
|
display: flex;
|
|
73
78
|
flex-direction: column;
|
|
74
|
-
gap: var(--rel-spacing-
|
|
79
|
+
gap: var(--rel-spacing-2xs);
|
|
75
80
|
width: 100%;
|
|
76
81
|
}
|
|
77
82
|
|
|
78
83
|
/* Label */
|
|
79
84
|
.textfield-label {
|
|
80
|
-
|
|
81
|
-
|
|
82
|
-
|
|
85
|
+
color: var(--rel-text-label);
|
|
86
|
+
|
|
87
|
+
font-family: var(--rel-body-sm-medium-font-family);
|
|
88
|
+
|
|
89
|
+
font-weight: var(--rel-body-sm-medium-font-weight);
|
|
90
|
+
|
|
91
|
+
font-size: var(--rel-body-sm-medium-font-size);
|
|
92
|
+
|
|
93
|
+
line-height: var(--rel-body-sm-medium-line-height);
|
|
94
|
+
|
|
95
|
+
letter-spacing: var(--rel-body-sm-medium-letter-spacing);
|
|
96
|
+
|
|
83
97
|
}
|
|
84
98
|
|
|
85
99
|
.required-mark {
|
|
86
|
-
color: var(--rel-
|
|
100
|
+
color: var(--rel-text-danger);
|
|
87
101
|
margin-left: 2px;
|
|
88
102
|
}
|
|
89
103
|
|
|
@@ -100,24 +114,26 @@ export class RelTextfield extends LitElement {
|
|
|
100
114
|
|
|
101
115
|
:host([floatinglabel]) .textfield-label {
|
|
102
116
|
position: absolute;
|
|
103
|
-
left: var(--rel-spacing-
|
|
117
|
+
left: var(--rel-spacing-sm);
|
|
104
118
|
top: 50%;
|
|
105
119
|
transform: translateY(-50%);
|
|
106
|
-
|
|
107
|
-
font-weight: var(--rel-fontWeights-regular);
|
|
108
|
-
color: var(--rel-color-text-placeholder);
|
|
120
|
+
color: var(--rel-text-placeholder);
|
|
109
121
|
pointer-events: none;
|
|
110
122
|
transition: top 0.15s ease, font-size 0.15s ease, color 0.15s ease, transform 0.15s ease;
|
|
111
|
-
background: var(--rel-
|
|
123
|
+
background: var(--rel-bg-neutral);
|
|
112
124
|
padding: 0 2px;
|
|
113
125
|
z-index: 1;
|
|
114
|
-
line-height: 1;
|
|
115
126
|
white-space: nowrap;
|
|
127
|
+
font-family: var(--rel-body-md-regular-font-family);
|
|
128
|
+
font-weight: var(--rel-body-md-regular-font-weight);
|
|
129
|
+
font-size: var(--rel-body-md-regular-font-size);
|
|
130
|
+
line-height: var(--rel-body-md-regular-line-height);
|
|
131
|
+
letter-spacing: var(--rel-body-md-regular-letter-spacing);
|
|
116
132
|
}
|
|
117
133
|
|
|
118
134
|
/* Floating label in multiline mode anchors to top instead of vertical center */
|
|
119
135
|
:host([floatinglabel][multiline]) .textfield-label {
|
|
120
|
-
top: var(--rel-spacing-
|
|
136
|
+
top: var(--rel-spacing-sm);
|
|
121
137
|
transform: none;
|
|
122
138
|
}
|
|
123
139
|
|
|
@@ -125,46 +141,54 @@ export class RelTextfield extends LitElement {
|
|
|
125
141
|
:host([floatinglabel]) .textfield-wrapper.has-value .textfield-label {
|
|
126
142
|
top: 0;
|
|
127
143
|
transform: translateY(-50%);
|
|
128
|
-
|
|
129
|
-
|
|
144
|
+
color: var(--rel-text-default);
|
|
145
|
+
font-family: var(--rel-body-xs-regular-font-family);
|
|
146
|
+
font-weight: var(--rel-body-xs-regular-font-weight);
|
|
147
|
+
font-size: var(--rel-body-xs-regular-font-size);
|
|
148
|
+
line-height: var(--rel-body-xs-regular-line-height);
|
|
149
|
+
letter-spacing: var(--rel-body-xs-regular-letter-spacing);
|
|
130
150
|
}
|
|
131
151
|
|
|
132
152
|
:host([floatinglabel]) .textfield-wrapper.error .textfield-label {
|
|
133
|
-
color: var(--rel-
|
|
153
|
+
color: var(--rel-text-danger);
|
|
134
154
|
}
|
|
135
155
|
|
|
136
156
|
:host([floatinglabel]) .textfield-wrapper.focused:not(.error) .textfield-label {
|
|
137
|
-
color: var(--rel-
|
|
157
|
+
color: var(--rel-text-default);
|
|
138
158
|
}
|
|
139
159
|
|
|
140
160
|
:host([floatinglabel]) .textfield-wrapper.focused.error .textfield-label,
|
|
141
161
|
:host([floatinglabel]) .textfield-wrapper.has-value.error .textfield-label {
|
|
142
162
|
top: 0;
|
|
143
163
|
transform: translateY(-50%);
|
|
144
|
-
|
|
145
|
-
|
|
164
|
+
color: var(--rel-text-danger);
|
|
165
|
+
font-family: var(--rel-body-xs-regular-font-family);
|
|
166
|
+
font-weight: var(--rel-body-xs-regular-font-weight);
|
|
167
|
+
font-size: var(--rel-body-xs-regular-font-size);
|
|
168
|
+
line-height: var(--rel-body-xs-regular-line-height);
|
|
169
|
+
letter-spacing: var(--rel-body-xs-regular-letter-spacing);
|
|
146
170
|
}
|
|
147
171
|
|
|
148
172
|
:host([floatinglabel]) .textfield-input {
|
|
149
|
-
padding-top: var(--rel-spacing-
|
|
150
|
-
padding-bottom: var(--rel-spacing-
|
|
173
|
+
padding-top: var(--rel-spacing-sm);
|
|
174
|
+
padding-bottom: var(--rel-spacing-sm);
|
|
151
175
|
}
|
|
152
176
|
|
|
153
177
|
:host([floatinglabel]) .textfield-input.has-left-icon {
|
|
154
|
-
padding-left: var(--rel-spacing-
|
|
178
|
+
padding-left: var(--rel-spacing-2xl);
|
|
155
179
|
}
|
|
156
180
|
|
|
157
181
|
:host([floatinglabel]) .textfield-label.has-left-icon {
|
|
158
|
-
left: var(--rel-spacing-
|
|
182
|
+
left: var(--rel-spacing-2xl);
|
|
159
183
|
}
|
|
160
184
|
|
|
161
185
|
:host([floatinglabel]) .textfield-wrapper.focused .textfield-label.has-left-icon,
|
|
162
186
|
:host([floatinglabel]) .textfield-wrapper.has-value .textfield-label.has-left-icon {
|
|
163
|
-
left: var(--rel-spacing-
|
|
187
|
+
left: var(--rel-spacing-sm);
|
|
164
188
|
}
|
|
165
189
|
|
|
166
190
|
:host([floatinglabel]) .textfield-wrapper.disabled .textfield-label {
|
|
167
|
-
background: var(--rel-
|
|
191
|
+
background: var(--rel-bg-neutral-elevated-1);
|
|
168
192
|
}
|
|
169
193
|
|
|
170
194
|
/* Container */
|
|
@@ -172,15 +196,15 @@ export class RelTextfield extends LitElement {
|
|
|
172
196
|
display: flex;
|
|
173
197
|
align-items: center;
|
|
174
198
|
position: relative;
|
|
175
|
-
border: 1px solid var(--rel-
|
|
176
|
-
border-radius: var(--rel-
|
|
177
|
-
background: var(--rel-
|
|
199
|
+
border: 1px solid var(--rel-border-default);
|
|
200
|
+
border-radius: var(--rel-border-radius-xs);
|
|
201
|
+
background: var(--rel-bg-neutral);
|
|
178
202
|
overflow: hidden;
|
|
179
203
|
transition: border 0.2s;
|
|
180
204
|
}
|
|
181
205
|
|
|
182
206
|
.textfield-container.disabled {
|
|
183
|
-
background: var(--rel-
|
|
207
|
+
background: var(--rel-bg-neutral-elevated-1);
|
|
184
208
|
cursor: not-allowed;
|
|
185
209
|
}
|
|
186
210
|
|
|
@@ -194,16 +218,19 @@ export class RelTextfield extends LitElement {
|
|
|
194
218
|
flex: 1;
|
|
195
219
|
border: none;
|
|
196
220
|
outline: none;
|
|
197
|
-
|
|
198
|
-
padding: var(--rel-spacing-space-xs) var(--rel-spacing-space-sm);
|
|
221
|
+
padding: var(--rel-spacing-xs) var(--rel-spacing-sm);
|
|
199
222
|
background: transparent;
|
|
200
|
-
|
|
201
|
-
|
|
223
|
+
color: var(--rel-text-body);
|
|
224
|
+
font-family: var(--rel-body-md-regular-font-family);
|
|
225
|
+
font-weight: var(--rel-body-md-regular-font-weight);
|
|
226
|
+
font-size: var(--rel-body-md-regular-font-size);
|
|
227
|
+
line-height: var(--rel-body-md-regular-line-height);
|
|
228
|
+
letter-spacing: var(--rel-body-md-regular-letter-spacing);
|
|
202
229
|
}
|
|
203
230
|
|
|
204
231
|
.textfield-input:disabled {
|
|
205
232
|
cursor: not-allowed;
|
|
206
|
-
color: var(--rel-
|
|
233
|
+
color: var(--rel-text-disabled);
|
|
207
234
|
}
|
|
208
235
|
|
|
209
236
|
/* Textarea */
|
|
@@ -221,7 +248,7 @@ export class RelTextfield extends LitElement {
|
|
|
221
248
|
background: transparent;
|
|
222
249
|
}
|
|
223
250
|
textarea.textfield-input::-webkit-scrollbar-thumb {
|
|
224
|
-
background: var(--rel-
|
|
251
|
+
background: var(--rel-text-placeholder);
|
|
225
252
|
border-radius: 2px;
|
|
226
253
|
}
|
|
227
254
|
|
|
@@ -229,7 +256,7 @@ export class RelTextfield extends LitElement {
|
|
|
229
256
|
position: absolute;
|
|
230
257
|
display: flex;
|
|
231
258
|
pointer-events: none;
|
|
232
|
-
color: var(--rel-
|
|
259
|
+
color: var(--rel-text-placeholder);
|
|
233
260
|
}
|
|
234
261
|
|
|
235
262
|
.icon.left {
|
|
@@ -240,33 +267,68 @@ export class RelTextfield extends LitElement {
|
|
|
240
267
|
right: 8px;
|
|
241
268
|
}
|
|
242
269
|
|
|
270
|
+
/* Interactive trailing icon (e.g. password show/hide) */
|
|
271
|
+
.icon.right.clickable {
|
|
272
|
+
pointer-events: auto;
|
|
273
|
+
cursor: pointer;
|
|
274
|
+
border-radius: var(--rel-border-radius-xs, 4px);
|
|
275
|
+
}
|
|
276
|
+
.icon.right.clickable:hover {
|
|
277
|
+
color: var(--rel-text-body);
|
|
278
|
+
}
|
|
279
|
+
.icon.right.clickable:focus-visible {
|
|
280
|
+
outline: 2px solid var(--rel-border-focus);
|
|
281
|
+
outline-offset: 2px;
|
|
282
|
+
}
|
|
283
|
+
|
|
284
|
+
.textfield-wrapper.small .textfield-support {
|
|
285
|
+
font-weight: var(--rel-body-xs-medium-font-weight);
|
|
286
|
+
}
|
|
287
|
+
|
|
243
288
|
.textfield-wrapper.small .textfield-input {
|
|
244
|
-
padding: var(--rel-spacing-
|
|
245
|
-
font-
|
|
289
|
+
padding: var(--rel-spacing-xs) var(--rel-spacing-sm);
|
|
290
|
+
font-family: var(--rel-body-sm-regular-font-family);
|
|
291
|
+
font-weight: var(--rel-body-sm-regular-font-weight);
|
|
292
|
+
font-size: var(--rel-body-sm-regular-font-size);
|
|
293
|
+
line-height: var(--rel-body-sm-regular-line-height);
|
|
294
|
+
letter-spacing: var(--rel-body-sm-regular-letter-spacing);
|
|
246
295
|
}
|
|
247
296
|
|
|
248
297
|
.textfield-wrapper.medium .textfield-input {
|
|
249
|
-
padding: var(--rel-spacing-
|
|
250
|
-
font-
|
|
298
|
+
padding: var(--rel-spacing-sm) var(--rel-spacing-md);
|
|
299
|
+
font-family: var(--rel-body-md-regular-font-family);
|
|
300
|
+
font-weight: var(--rel-body-md-regular-font-weight);
|
|
301
|
+
font-size: var(--rel-body-md-regular-font-size);
|
|
302
|
+
line-height: var(--rel-body-md-regular-line-height);
|
|
303
|
+
letter-spacing: var(--rel-body-md-regular-letter-spacing);
|
|
251
304
|
}
|
|
252
305
|
|
|
253
306
|
.textfield-wrapper.large .textfield-input {
|
|
254
|
-
padding: var(--rel-spacing-
|
|
255
|
-
font-
|
|
307
|
+
padding: var(--rel-spacing-md) var(--rel-spacing-md);
|
|
308
|
+
font-family: var(--rel-body-lg-regular-font-family);
|
|
309
|
+
font-weight: var(--rel-body-lg-regular-font-weight);
|
|
310
|
+
font-size: var(--rel-body-lg-regular-font-size);
|
|
311
|
+
line-height: var(--rel-body-lg-regular-line-height);
|
|
312
|
+
letter-spacing: var(--rel-body-lg-regular-letter-spacing);
|
|
256
313
|
}
|
|
257
314
|
|
|
258
315
|
/* Adjust padding when icons are present */
|
|
259
316
|
.textfield-wrapper .textfield-input.has-left-icon {
|
|
260
|
-
padding-left: var(--rel-spacing-
|
|
317
|
+
padding-left: var(--rel-spacing-2xl);
|
|
261
318
|
}
|
|
262
319
|
|
|
263
320
|
.textfield-wrapper .textfield-input.has-right-icon {
|
|
264
|
-
padding-right: var(--rel-spacing-
|
|
321
|
+
padding-right: var(--rel-spacing-2xl);
|
|
265
322
|
}
|
|
266
323
|
|
|
267
324
|
/* States */
|
|
325
|
+
/* Hover (Figma State=Hover): border-strong at 1px — no focus ring */
|
|
326
|
+
.textfield-wrapper:not(.focused):not(.error):not(.disabled) .textfield-container:hover {
|
|
327
|
+
border-color: var(--rel-border-strong);
|
|
328
|
+
}
|
|
329
|
+
|
|
268
330
|
.textfield-wrapper.focused .textfield-container {
|
|
269
|
-
border-color: var(--rel-
|
|
331
|
+
border-color: var(--rel-text-default);
|
|
270
332
|
}
|
|
271
333
|
|
|
272
334
|
.textfield-input:focus-visible {
|
|
@@ -275,37 +337,47 @@ export class RelTextfield extends LitElement {
|
|
|
275
337
|
|
|
276
338
|
.textfield-wrapper.focused .textfield-container,
|
|
277
339
|
.textfield-container:focus-within {
|
|
278
|
-
border-color: var(--rel-
|
|
279
|
-
box-shadow: 0 0 0 1px var(--rel-
|
|
340
|
+
border-color: var(--rel-border-strong);
|
|
341
|
+
box-shadow: 0 0 0 1px var(--rel-border-strong);
|
|
280
342
|
}
|
|
281
343
|
|
|
282
344
|
.textfield-wrapper.error .textfield-container,
|
|
283
345
|
.textfield-wrapper.error .textfield-container:focus-within {
|
|
284
|
-
border-color: var(--rel-
|
|
346
|
+
border-color: var(--rel-border-danger);
|
|
285
347
|
box-shadow: none;
|
|
286
348
|
}
|
|
287
349
|
|
|
288
350
|
.textfield-wrapper.disabled .textfield-container {
|
|
289
|
-
border-color: var(--rel-
|
|
351
|
+
border-color: var(--rel-border-default);
|
|
290
352
|
}
|
|
291
353
|
|
|
292
354
|
.textfield-wrapper.disabled .textfield-label {
|
|
293
|
-
color: var(--rel-
|
|
355
|
+
color: var(--rel-text-disabled);
|
|
294
356
|
}
|
|
295
357
|
|
|
296
358
|
/* Supporting text */
|
|
297
359
|
.textfield-support {
|
|
298
|
-
|
|
299
|
-
|
|
360
|
+
color: var(--rel-text-caption);
|
|
361
|
+
|
|
362
|
+
font-family: var(--rel-body-xs-regular-font-family);
|
|
363
|
+
|
|
364
|
+
font-weight: var(--rel-body-xs-regular-font-weight);
|
|
365
|
+
|
|
366
|
+
font-size: var(--rel-body-xs-regular-font-size);
|
|
367
|
+
|
|
368
|
+
line-height: var(--rel-body-xs-regular-line-height);
|
|
369
|
+
|
|
370
|
+
letter-spacing: var(--rel-body-xs-regular-letter-spacing);
|
|
371
|
+
|
|
300
372
|
}
|
|
301
373
|
|
|
302
374
|
.textfield-support.error {
|
|
303
|
-
color: var(--rel-
|
|
375
|
+
color: var(--rel-text-danger);
|
|
304
376
|
}
|
|
305
377
|
|
|
306
378
|
/* Placeholder */
|
|
307
379
|
.textfield-input::placeholder {
|
|
308
|
-
color: var(--rel-
|
|
380
|
+
color: var(--rel-text-placeholder);
|
|
309
381
|
}
|
|
310
382
|
|
|
311
383
|
:host([floatinglabel]) .textfield-input::placeholder {
|
|
@@ -320,34 +392,38 @@ export class RelTextfield extends LitElement {
|
|
|
320
392
|
.textfield-input:-webkit-autofill,
|
|
321
393
|
.textfield-input:-webkit-autofill:hover,
|
|
322
394
|
.textfield-input:-webkit-autofill:focus {
|
|
323
|
-
-webkit-box-shadow: 0 0 0px 1000px var(--rel-
|
|
324
|
-
-webkit-text-fill-color: var(--rel-
|
|
395
|
+
-webkit-box-shadow: 0 0 0px 1000px var(--rel-bg-surface) inset;
|
|
396
|
+
-webkit-text-fill-color: var(--rel-text-default);
|
|
325
397
|
}
|
|
326
398
|
|
|
327
399
|
/* ── Underline variant ── */
|
|
328
400
|
:host([variant="underline"]) .textfield-container {
|
|
329
401
|
border: none;
|
|
330
|
-
border-bottom: 2px solid var(--rel-
|
|
402
|
+
border-bottom: 2px solid var(--rel-border-default);
|
|
331
403
|
border-radius: 0;
|
|
332
|
-
background: var(--rel-
|
|
404
|
+
background: var(--rel-bg-neutral-elevated-1);
|
|
333
405
|
box-shadow: none;
|
|
334
406
|
overflow: visible;
|
|
335
407
|
}
|
|
336
408
|
|
|
409
|
+
:host([variant="underline"]) .textfield-wrapper:not(.focused):not(.error):not(.disabled) .textfield-container:hover {
|
|
410
|
+
border-bottom-color: var(--rel-border-strong);
|
|
411
|
+
}
|
|
412
|
+
|
|
337
413
|
:host([variant="underline"]) .textfield-wrapper.focused .textfield-container,
|
|
338
414
|
:host([variant="underline"]) .textfield-container:focus-within {
|
|
339
|
-
border-bottom: 2px solid var(--rel-
|
|
415
|
+
border-bottom: 2px solid var(--rel-text-default);
|
|
340
416
|
box-shadow: none;
|
|
341
417
|
}
|
|
342
418
|
|
|
343
419
|
:host([variant="underline"]) .textfield-wrapper.error .textfield-container {
|
|
344
|
-
border-bottom: 2px solid var(--rel-
|
|
420
|
+
border-bottom: 2px solid var(--rel-border-danger);
|
|
345
421
|
box-shadow: none;
|
|
346
422
|
}
|
|
347
423
|
|
|
348
424
|
:host([variant="underline"]) .textfield-wrapper.disabled .textfield-container {
|
|
349
|
-
border-bottom: 2px solid var(--rel-
|
|
350
|
-
background: var(--rel-
|
|
425
|
+
border-bottom: 2px solid var(--rel-border-default);
|
|
426
|
+
background: var(--rel-bg-neutral-elevated-1);
|
|
351
427
|
}
|
|
352
428
|
|
|
353
429
|
/* Remove border radius on input for underline variant */
|
|
@@ -358,8 +434,8 @@ export class RelTextfield extends LitElement {
|
|
|
358
434
|
/* Dark mode — underline variant uses same border colors as default */
|
|
359
435
|
:host-context([data-theme="dark"]) :host([variant="underline"]) .textfield-container,
|
|
360
436
|
:host-context(.dark) :host([variant="underline"]) .textfield-container {
|
|
361
|
-
background: var(--rel-
|
|
362
|
-
border-bottom-color: var(--rel-
|
|
437
|
+
background: var(--rel-bg-neutral-elevated-1);
|
|
438
|
+
border-bottom-color: var(--rel-border-default);
|
|
363
439
|
}
|
|
364
440
|
|
|
365
441
|
/* ── Full-width control (fullWidth defaults true → block, fills parent) ── */
|
|
@@ -379,19 +455,21 @@ export class RelTextfield extends LitElement {
|
|
|
379
455
|
margin: 0;
|
|
380
456
|
min-inline-size: 0;
|
|
381
457
|
padding: 0;
|
|
382
|
-
border: 1px solid var(--rel-
|
|
383
|
-
border-radius: var(--rel-
|
|
384
|
-
background: var(--rel-
|
|
458
|
+
border: 1px solid var(--rel-border-default);
|
|
459
|
+
border-radius: var(--rel-border-radius-xs);
|
|
460
|
+
background: var(--rel-bg-neutral);
|
|
385
461
|
transition: border-color 0.2s;
|
|
386
462
|
}
|
|
387
463
|
|
|
388
464
|
:host([variant="legend"]) .field-legend {
|
|
389
|
-
margin-left: var(--rel-spacing-
|
|
390
|
-
padding: 0 var(--rel-spacing-
|
|
391
|
-
|
|
392
|
-
font-
|
|
393
|
-
|
|
394
|
-
|
|
465
|
+
margin-left: var(--rel-spacing-sm);
|
|
466
|
+
padding: 0 var(--rel-spacing-2xs);
|
|
467
|
+
color: var(--rel-text-label);
|
|
468
|
+
font-family: var(--rel-body-sm-medium-font-family);
|
|
469
|
+
font-weight: var(--rel-body-sm-medium-font-weight);
|
|
470
|
+
font-size: var(--rel-body-sm-medium-font-size);
|
|
471
|
+
line-height: var(--rel-body-sm-medium-line-height);
|
|
472
|
+
letter-spacing: var(--rel-body-sm-medium-letter-spacing);
|
|
395
473
|
}
|
|
396
474
|
|
|
397
475
|
:host([variant="legend"]) .textfield-input {
|
|
@@ -402,17 +480,18 @@ export class RelTextfield extends LitElement {
|
|
|
402
480
|
/* Prefix icon (legend): vertically centered; input inset via has-left-icon */
|
|
403
481
|
:host([variant="legend"]) .icon.left {
|
|
404
482
|
top: 50%;
|
|
405
|
-
left: var(--rel-spacing-
|
|
483
|
+
left: var(--rel-spacing-sm);
|
|
406
484
|
transform: translateY(-50%);
|
|
407
485
|
}
|
|
408
486
|
:host([variant="legend"]) .field-fieldset.multiline .icon.left {
|
|
409
|
-
top: var(--rel-spacing-
|
|
487
|
+
top: var(--rel-spacing-sm);
|
|
410
488
|
transform: none;
|
|
411
489
|
}
|
|
412
490
|
|
|
413
491
|
/* Hover */
|
|
414
492
|
:host([variant="legend"]) .field-fieldset:hover {
|
|
415
|
-
border-color: var(--rel-
|
|
493
|
+
border-color: var(--rel-border-accent);
|
|
494
|
+
border-color: var(--rel-text-placeholder);
|
|
416
495
|
}
|
|
417
496
|
|
|
418
497
|
/* Focus — border-color only. A box-shadow/outline ring hugs the full
|
|
@@ -420,31 +499,31 @@ export class RelTextfield extends LitElement {
|
|
|
420
499
|
strike through the legend. The legend also recolors on focus (below). */
|
|
421
500
|
:host([variant="legend"]) .textfield-wrapper.focused .field-fieldset,
|
|
422
501
|
:host([variant="legend"]) .field-fieldset:focus-within {
|
|
423
|
-
border-color: var(--rel-
|
|
502
|
+
border-color: var(--rel-border-focus);
|
|
424
503
|
box-shadow: none;
|
|
425
504
|
}
|
|
426
505
|
:host([variant="legend"]) .textfield-wrapper.focused .field-legend,
|
|
427
506
|
:host([variant="legend"]) .field-fieldset:focus-within .field-legend {
|
|
428
|
-
color: var(--rel-
|
|
507
|
+
color: var(--rel-border-focus);
|
|
429
508
|
}
|
|
430
509
|
|
|
431
510
|
/* Error */
|
|
432
511
|
:host([variant="legend"]) .textfield-wrapper.error .field-fieldset {
|
|
433
|
-
border-color: var(--rel-
|
|
512
|
+
border-color: var(--rel-border-danger);
|
|
434
513
|
box-shadow: none;
|
|
435
514
|
}
|
|
436
515
|
:host([variant="legend"]) .textfield-wrapper.error .field-legend {
|
|
437
|
-
color: var(--rel-
|
|
516
|
+
color: var(--rel-text-danger);
|
|
438
517
|
}
|
|
439
518
|
|
|
440
519
|
/* Disabled */
|
|
441
520
|
:host([variant="legend"]) .textfield-wrapper.disabled .field-fieldset {
|
|
442
|
-
background: var(--rel-
|
|
443
|
-
border-color: var(--rel-
|
|
521
|
+
background: var(--rel-bg-neutral-elevated-1);
|
|
522
|
+
border-color: var(--rel-border-default);
|
|
444
523
|
cursor: not-allowed;
|
|
445
524
|
}
|
|
446
525
|
:host([variant="legend"]) .textfield-wrapper.disabled .field-legend {
|
|
447
|
-
color: var(--rel-
|
|
526
|
+
color: var(--rel-text-disabled);
|
|
448
527
|
}
|
|
449
528
|
|
|
450
529
|
/* Readonly */
|
|
@@ -454,10 +533,30 @@ export class RelTextfield extends LitElement {
|
|
|
454
533
|
|
|
455
534
|
/* Legend font tracks size */
|
|
456
535
|
:host([variant="legend"]) .textfield-wrapper.small .field-legend {
|
|
457
|
-
|
|
536
|
+
|
|
537
|
+
font-family: var(--rel-body-xs-regular-font-family);
|
|
538
|
+
|
|
539
|
+
font-weight: var(--rel-body-xs-regular-font-weight);
|
|
540
|
+
|
|
541
|
+
font-size: var(--rel-body-xs-regular-font-size);
|
|
542
|
+
|
|
543
|
+
line-height: var(--rel-body-xs-regular-line-height);
|
|
544
|
+
|
|
545
|
+
letter-spacing: var(--rel-body-xs-regular-letter-spacing);
|
|
546
|
+
|
|
458
547
|
}
|
|
459
548
|
:host([variant="legend"]) .textfield-wrapper.large .field-legend {
|
|
460
|
-
|
|
549
|
+
|
|
550
|
+
font-family: var(--rel-body-md-regular-font-family);
|
|
551
|
+
|
|
552
|
+
font-weight: var(--rel-body-md-regular-font-weight);
|
|
553
|
+
|
|
554
|
+
font-size: var(--rel-body-md-regular-font-size);
|
|
555
|
+
|
|
556
|
+
line-height: var(--rel-body-md-regular-line-height);
|
|
557
|
+
|
|
558
|
+
letter-spacing: var(--rel-body-md-regular-letter-spacing);
|
|
559
|
+
|
|
461
560
|
}
|
|
462
561
|
`;
|
|
463
562
|
|
|
@@ -481,6 +580,22 @@ export class RelTextfield extends LitElement {
|
|
|
481
580
|
}
|
|
482
581
|
}
|
|
483
582
|
|
|
583
|
+
private handleRightIconClick(e: Event) {
|
|
584
|
+
if (!this.clickableRightIcon) return;
|
|
585
|
+
e.stopPropagation();
|
|
586
|
+
this.dispatchEvent(
|
|
587
|
+
new CustomEvent("rel-right-icon-click", { bubbles: true, composed: true })
|
|
588
|
+
);
|
|
589
|
+
}
|
|
590
|
+
|
|
591
|
+
private handleRightIconKeydown(e: KeyboardEvent) {
|
|
592
|
+
if (!this.clickableRightIcon) return;
|
|
593
|
+
if (e.key === "Enter" || e.key === " ") {
|
|
594
|
+
e.preventDefault();
|
|
595
|
+
this.handleRightIconClick(e);
|
|
596
|
+
}
|
|
597
|
+
}
|
|
598
|
+
|
|
484
599
|
private handleInput(e: Event) {
|
|
485
600
|
const input = e.target as HTMLInputElement;
|
|
486
601
|
this.value = input.value;
|
|
@@ -532,6 +647,7 @@ export class RelTextfield extends LitElement {
|
|
|
532
647
|
const labelTemplate = (extraClass = "") => {
|
|
533
648
|
if (!this.label) return "";
|
|
534
649
|
return html`<label
|
|
650
|
+
part="label"
|
|
535
651
|
class="textfield-label${extraClass}"
|
|
536
652
|
for="${inputId}"
|
|
537
653
|
>${this.label}${this.required ? html`<span class="required-mark" aria-hidden="true">*</span>` : ""}</label>`;
|
|
@@ -540,7 +656,7 @@ export class RelTextfield extends LitElement {
|
|
|
540
656
|
const ariaLabelledby = this.variant === "legend" && this.label ? legendId : undefined;
|
|
541
657
|
|
|
542
658
|
const inputTemplate = this.multiline
|
|
543
|
-
? html`<textarea
|
|
659
|
+
? html`<textarea part="input"
|
|
544
660
|
id="${inputId}"
|
|
545
661
|
class="${inputClasses}"
|
|
546
662
|
placeholder="${this.placeholder}"
|
|
@@ -559,7 +675,7 @@ export class RelTextfield extends LitElement {
|
|
|
559
675
|
@blur="${this.handleBlur}"
|
|
560
676
|
@input="${this.handleInput}"
|
|
561
677
|
></textarea>`
|
|
562
|
-
: html`<input
|
|
678
|
+
: html`<input part="input"
|
|
563
679
|
type="${this.type}"
|
|
564
680
|
id="${inputId}"
|
|
565
681
|
class="${inputClasses}"
|
|
@@ -591,7 +707,7 @@ export class RelTextfield extends LitElement {
|
|
|
591
707
|
: "";
|
|
592
708
|
|
|
593
709
|
const belowTemplate = belowText
|
|
594
|
-
? html`<div class="textfield-support ${isError ? "error" : ""}" id="${describedById}">
|
|
710
|
+
? html`<div part="helper" class="textfield-support ${isError ? "error" : ""}" id="${describedById}">
|
|
595
711
|
${belowText}
|
|
596
712
|
</div>`
|
|
597
713
|
: "";
|
|
@@ -604,7 +720,7 @@ export class RelTextfield extends LitElement {
|
|
|
604
720
|
// is always present (only its content is dynamic).
|
|
605
721
|
return html`
|
|
606
722
|
<div class="${wrapperClasses}">
|
|
607
|
-
<fieldset class="${fieldsetClass}"><legend class="field-legend" id="${legendId}">${this.label ?? ""}${this.required ? html`<span class="required-mark" aria-hidden="true">*</span>` : ""}</legend>
|
|
723
|
+
<fieldset part="control" class="${fieldsetClass}"><legend class="field-legend" id="${legendId}">${this.label ?? ""}${this.required ? html`<span class="required-mark" aria-hidden="true">*</span>` : ""}</legend>
|
|
608
724
|
${!this.multiline ? leadingIconTemplate : ""}
|
|
609
725
|
${inputTemplate}
|
|
610
726
|
</fieldset>
|
|
@@ -617,7 +733,7 @@ export class RelTextfield extends LitElement {
|
|
|
617
733
|
<div class="${wrapperClasses}">
|
|
618
734
|
${!this.floatingLabel ? labelTemplate() : ""}
|
|
619
735
|
|
|
620
|
-
<div class="${["textfield-container", this.isDisabled ? "disabled" : "", this.multiline ? "multiline" : ""].filter(Boolean).join(" ")}">
|
|
736
|
+
<div part="control" class="${["textfield-container", this.isDisabled ? "disabled" : "", this.multiline ? "multiline" : ""].filter(Boolean).join(" ")}">
|
|
621
737
|
${this.floatingLabel
|
|
622
738
|
? labelTemplate(leadingIcon && !this.multiline ? " has-left-icon" : "")
|
|
623
739
|
: ""}
|
|
@@ -626,7 +742,17 @@ export class RelTextfield extends LitElement {
|
|
|
626
742
|
${inputTemplate}
|
|
627
743
|
|
|
628
744
|
${!this.multiline && this.rightIcon
|
|
629
|
-
? html`<rel-icon
|
|
745
|
+
? html`<rel-icon
|
|
746
|
+
part="right-icon"
|
|
747
|
+
name="${this.rightIcon}"
|
|
748
|
+
size="${this.clickableRightIcon ? "md" : "sm"}"
|
|
749
|
+
class="icon right ${this.clickableRightIcon ? "clickable" : ""}"
|
|
750
|
+
role="${this.clickableRightIcon ? "button" : nothing}"
|
|
751
|
+
tabindex="${this.clickableRightIcon ? "0" : nothing}"
|
|
752
|
+
aria-label="${this.clickableRightIcon ? (this.rightIconAriaLabel ?? nothing) : nothing}"
|
|
753
|
+
@click="${(e: Event) => this.handleRightIconClick(e)}"
|
|
754
|
+
@keydown="${(e: KeyboardEvent) => this.handleRightIconKeydown(e)}"
|
|
755
|
+
></rel-icon>`
|
|
630
756
|
: ""}
|
|
631
757
|
</div>
|
|
632
758
|
|
|
@@ -98,25 +98,25 @@ None exposed.
|
|
|
98
98
|
## Tokens / CSS Variables
|
|
99
99
|
|
|
100
100
|
### Semantic Tokens
|
|
101
|
-
- `--rel-
|
|
102
|
-
- `--rel-
|
|
101
|
+
- `--rel-fonts-font-family` - Font family
|
|
102
|
+
- `--rel-body-md-regular-font-size` - Font size
|
|
103
103
|
|
|
104
104
|
### Spacing Tokens
|
|
105
|
-
- `--rel-spacing-
|
|
106
|
-
- `--rel-spacing-
|
|
107
|
-
- `--rel-spacing-
|
|
105
|
+
- `--rel-spacing-sm` - Gap between elements
|
|
106
|
+
- `--rel-spacing-md` - Padding
|
|
107
|
+
- `--rel-spacing-2xs` - Close button padding and margin
|
|
108
108
|
|
|
109
109
|
### Color Tokens
|
|
110
|
-
- `--rel-
|
|
111
|
-
- `--rel-
|
|
112
|
-
- `--rel-
|
|
113
|
-
- `--rel-
|
|
110
|
+
- `--rel-bg-neutral-inverse-1` - Default background color (dark gray)
|
|
111
|
+
- `--rel-text-danger` - Error background color
|
|
112
|
+
- `--rel-bg-surface` - Text and focus outline color
|
|
113
|
+
- `--rel-bg-brand` - Action button text color
|
|
114
114
|
|
|
115
115
|
### Shadow Tokens
|
|
116
116
|
- `--rel-shadows-shadow-300` - Drop shadow
|
|
117
117
|
|
|
118
118
|
### Border Tokens
|
|
119
|
-
- `--rel-
|
|
119
|
+
- `--rel-border-radius-sm` - Border radius
|
|
120
120
|
|
|
121
121
|
## Accessibility
|
|
122
122
|
- Uses `role="status"` and `aria-live="polite"` for screen reader announcements
|
|
@@ -144,5 +144,5 @@ None exposed.
|
|
|
144
144
|
- The component includes a `fadeInUp` animation (20px translateY → 0, opacity 0 → 1) on appearance
|
|
145
145
|
- Animation disabled when `prefers-reduced-motion: reduce` is set
|
|
146
146
|
- When `visible` is false, `hidden` class applies `display: none`
|
|
147
|
-
- **Type variants**: `default` uses `--rel-
|
|
147
|
+
- **Type variants**: `default` uses `--rel-bg-neutral-inverse-1`, `error` uses `--rel-text-danger`
|
|
148
148
|
- The toast appears inline-flex, so it sizes to content width
|