@jack-henry/jh-elements 2.0.0-beta.11 → 2.0.0-beta.13
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/components/checkbox-group/checkbox-group.js +16 -4
- package/components/input/input.js +313 -252
- package/components/input-email/input-email.js +3 -4
- package/components/input-password/input-password.js +64 -54
- package/components/input-search/input-search.js +11 -8
- package/components/input-textarea/input-textarea.js +67 -175
- package/components/list-item/list-item.js +4 -1
- package/components/menu/menu.js +12 -1
- package/components/radio-group/radio-group.js +61 -6
- package/components/select/filtering.js +92 -0
- package/components/select/select.js +660 -0
- package/components/toast/toast.js +1 -5
- package/components/tooltip/tooltip.js +46 -65
- package/custom-elements.json +820 -183
- package/index.d.ts +2 -0
- package/package.json +2 -2
|
@@ -11,7 +11,7 @@ let id = 0;
|
|
|
11
11
|
|
|
12
12
|
/**
|
|
13
13
|
* @cssprop --jh-input-label-color-text - The label text color. Defaults to `--jh-color-content-primary-enabled`.
|
|
14
|
-
* @cssprop --jh-input-field-color-background - The input field background-color. Defaults to `--jh-color-container-primary-enabled`.
|
|
14
|
+
* @cssprop --jh-input-field-color-background - The input field background-color when in an editable state. This property does not apply when the component is set to `readonly`. Defaults to `--jh-color-container-primary-enabled`.
|
|
15
15
|
* @cssprop --jh-input-field-color-border-enabled - The input field border-color. Defaults to `--jh-border-control-color`.
|
|
16
16
|
* @cssprop --jh-input-field-border-radius - The input field border radius. Defaults to `--jh-border-radius-100`.
|
|
17
17
|
* @cssprop --jh-input-color-focus - The input field outline when it receives keyboard focus. Defaults to `--jh-border-focus-color`.
|
|
@@ -91,26 +91,33 @@ export class JhInput extends LitElement {
|
|
|
91
91
|
// alphanumeric characters -> usernames, product codes, etc.
|
|
92
92
|
'*': /[A-Za-z0-9]/,
|
|
93
93
|
};
|
|
94
|
-
|
|
95
|
-
#
|
|
94
|
+
|
|
95
|
+
get #inputEl() {
|
|
96
|
+
return this.renderRoot?.querySelector('input');
|
|
97
|
+
}
|
|
98
|
+
|
|
99
|
+
get #leftSlot() {
|
|
100
|
+
return this.renderRoot?.querySelector('slot[name="jh-input-left"]');
|
|
101
|
+
}
|
|
102
|
+
|
|
103
|
+
get #rightSlot() {
|
|
104
|
+
return this.renderRoot?.querySelector('slot[name="jh-input-right"]');
|
|
105
|
+
}
|
|
96
106
|
|
|
97
107
|
static get styles() {
|
|
98
108
|
return css`
|
|
99
109
|
:host {
|
|
100
|
-
font-family: var(--jh-font-helper-regular-font-family);
|
|
101
|
-
font-weight: var(--jh-font-helper-regular-font-weight);
|
|
102
|
-
font-size: var(--jh-font-helper-regular-font-size);
|
|
103
|
-
line-height: var(--jh-font-helper-regular-line-height);
|
|
110
|
+
--input-helper-regular-font-family: var(--jh-font-helper-regular-font-family);
|
|
111
|
+
--input-helper-regular-font-weight: var(--jh-font-helper-regular-font-weight);
|
|
112
|
+
--input-helper-regular-font-size: var(--jh-font-helper-regular-font-size);
|
|
113
|
+
--input-helper-regular-line-height: var(--jh-font-helper-regular-line-height);
|
|
114
|
+
font-family: var(--input-helper-regular-font-family);
|
|
115
|
+
font-weight: var(--input-helper-regular-font-weight);
|
|
116
|
+
font-size: var(--input-helper-regular-font-size);
|
|
117
|
+
line-height: var(--input-helper-regular-line-height);
|
|
104
118
|
display: inline-block;
|
|
105
119
|
width: 100%;
|
|
106
|
-
--jh-button-size: var(--jh-dimension-800);
|
|
107
|
-
/* input padding + slot padding */
|
|
108
|
-
--padding-with-left-slotted-content: calc(
|
|
109
|
-
var(--jh-dimension-400) + var(--jh-dimension-200)
|
|
110
|
-
);
|
|
111
|
-
--padding-with-right-slotted-content: calc(
|
|
112
|
-
var(--jh-dimension-400) + var(--jh-dimension-200)
|
|
113
|
-
);
|
|
120
|
+
--jh-button-size: var(--jh-dimension-800);
|
|
114
121
|
--input-value-color-text: var(
|
|
115
122
|
--jh-input-value-color-text,
|
|
116
123
|
var(--jh-color-content-primary-enabled)
|
|
@@ -121,6 +128,10 @@ export class JhInput extends LitElement {
|
|
|
121
128
|
--jh-input-label-color-text,
|
|
122
129
|
var(--jh-color-content-primary-enabled)
|
|
123
130
|
);
|
|
131
|
+
font-family: var(--jh-font-helper-medium-font-family);
|
|
132
|
+
font-weight: var(--jh-font-helper-medium-font-weight);
|
|
133
|
+
font-size: var(--jh-font-helper-medium-font-size);
|
|
134
|
+
line-height: var(--jh-font-helper-medium-line-height);
|
|
124
135
|
display: block;
|
|
125
136
|
}
|
|
126
137
|
.helper-text {
|
|
@@ -138,13 +149,14 @@ export class JhInput extends LitElement {
|
|
|
138
149
|
:host([show-char-count]) .helper-text {
|
|
139
150
|
display: inline-block;
|
|
140
151
|
}
|
|
141
|
-
.input-container {
|
|
142
|
-
position: relative;
|
|
143
|
-
}
|
|
144
152
|
:host([label]) .input-container {
|
|
145
153
|
margin-top: var(--jh-dimension-200);
|
|
146
154
|
}
|
|
147
|
-
|
|
155
|
+
|
|
156
|
+
/* Flex wrapper */
|
|
157
|
+
.input-wrapper {
|
|
158
|
+
display: flex;
|
|
159
|
+
align-items: center;
|
|
148
160
|
background-color: var(
|
|
149
161
|
--jh-input-field-color-background,
|
|
150
162
|
var(--jh-color-container-primary-enabled)
|
|
@@ -153,123 +165,78 @@ export class JhInput extends LitElement {
|
|
|
153
165
|
border-style: var(--jh-border-control-style);
|
|
154
166
|
border-color: var(
|
|
155
167
|
--jh-input-field-color-border-enabled,
|
|
156
|
-
|
|
157
|
-
|
|
168
|
+
var(--jh-border-control-color)
|
|
169
|
+
);
|
|
158
170
|
border-radius: var(
|
|
159
171
|
--jh-input-field-border-radius,
|
|
160
172
|
var(--jh-border-radius-100)
|
|
161
173
|
);
|
|
162
|
-
|
|
163
|
-
font-family: var(--jh-font-body-regular-1-font-family);
|
|
164
|
-
font-weight: var(--jh-font-body-regular-1-font-weight);
|
|
165
|
-
font-size: var(--jh-font-body-regular-1-font-size);
|
|
166
|
-
line-height: var(--jh-font-body-regular-1-line-height);
|
|
167
|
-
padding: var(--jh-dimension-0) var(--jh-dimension-400) var(--jh-dimension-0) var(--jh-dimension-400);
|
|
174
|
+
padding: var(--jh-dimension-0) var(--jh-dimension-400);
|
|
168
175
|
box-sizing: border-box;
|
|
169
176
|
width: 100%;
|
|
170
177
|
}
|
|
171
|
-
|
|
172
|
-
|
|
173
|
-
|
|
174
|
-
.jh-input-left {
|
|
175
|
-
padding-left: calc(var(--padding-with-left-slotted-content) + var(--jh-input-left-width));
|
|
176
|
-
}
|
|
177
|
-
/* slot styles */
|
|
178
|
-
::slotted(*),
|
|
179
|
-
::slotted(*) {
|
|
180
|
-
position: absolute;
|
|
181
|
-
display: flex;
|
|
182
|
-
align-items: center;
|
|
183
|
-
justify-content: center;
|
|
184
|
-
}
|
|
185
|
-
::slotted([slot='jh-input-left']) {
|
|
186
|
-
left: var(--jh-dimension-400);
|
|
187
|
-
}
|
|
188
|
-
::slotted([slot='jh-input-right']) {
|
|
189
|
-
right: var(--jh-dimension-400);
|
|
190
|
-
}
|
|
191
|
-
::slotted([slot='jh-input-left']){
|
|
192
|
-
top: var(--jh-input-left-top);
|
|
193
|
-
}
|
|
194
|
-
::slotted([slot='jh-input-right']) {
|
|
195
|
-
top: var(--jh-input-right-top);
|
|
196
|
-
}
|
|
197
|
-
/* clear button */
|
|
198
|
-
.clear-button {
|
|
199
|
-
right: var(--jh-dimension-400);
|
|
200
|
-
--jh-button-border-radius: var(--jh-input-clear-border-radius);
|
|
201
|
-
--jh-button-color-background-tertiary-enabled: var(--jh-input-clear-color-background-enabled);
|
|
202
|
-
--jh-button-color-border-tertiary-enabled: var(--jh-input-clear-color-border-enabled);
|
|
203
|
-
--jh-button-icon-color-fill-tertiary-enabled: var(--jh-input-clear-icon-color-fill-enabled);
|
|
204
|
-
--jh-button-color-background-tertiary-focus: var(--jh-input-clear-color-background-focus);
|
|
205
|
-
--jh-button-color-border-tertiary-focus: var(--jh-input-clear-color-border-focus);
|
|
206
|
-
--jh-button-color-focus: var(--jh-input-clear-color-focus);
|
|
207
|
-
--jh-button-icon-color-fill-tertiary-focus: var(--jh-input-clear-icon-color-fill-focus);
|
|
208
|
-
--jh-button-color-background-tertiary-hover: var(--jh-input-clear-color-background-hover);
|
|
209
|
-
--jh-button-color-border-tertiary-hover: var(--jh-input-clear-color-border-hover);
|
|
210
|
-
--jh-button-icon-color-fill-tertiary-hover: var(--jh-input-clear-icon-color-fill-hover);
|
|
211
|
-
--jh-button-color-background-tertiary-active: var(--jh-input-clear-color-background-active);
|
|
212
|
-
--jh-button-color-border-tertiary-active: var(--jh-input-clear-color-border-active);
|
|
213
|
-
--jh-button-icon-color-fill-tertiary-active: var(--jh-input-clear-icon-color-fill-active);
|
|
214
|
-
display: none;
|
|
215
|
-
position: absolute;
|
|
216
|
-
}
|
|
217
|
-
.display-clear-button .clear-button {
|
|
218
|
-
display: inherit;
|
|
219
|
-
}
|
|
220
|
-
:host([size='small']) .clear-button {
|
|
221
|
-
top: 4px;
|
|
222
|
-
}
|
|
223
|
-
:host([size='medium']) .clear-button {
|
|
224
|
-
top: 8px;
|
|
225
|
-
}
|
|
226
|
-
:host([size='large']) .clear-button {
|
|
227
|
-
top: 12px;
|
|
228
|
-
}
|
|
229
|
-
.jh-input-right ~ .clear-button {
|
|
230
|
-
right: calc(var(--padding-with-right-slotted-content) + var(--jh-input-right-width));
|
|
231
|
-
}
|
|
232
|
-
.display-clear-button input {
|
|
233
|
-
padding-right: calc(var(--padding-with-right-slotted-content) + var(--jh-dimension-800));
|
|
234
|
-
}
|
|
235
|
-
.display-clear-button .jh-input-right {
|
|
236
|
-
padding-right: calc(var(--padding-with-right-slotted-content) + var(--jh-input-right-width) + var(--jh-dimension-800) + var(--jh-dimension-200));
|
|
237
|
-
}
|
|
238
|
-
/* Sizes */
|
|
239
|
-
:host([size='small']) input {
|
|
178
|
+
|
|
179
|
+
/* Sizes on input wrapper */
|
|
180
|
+
:host([size='small']) .input-wrapper {
|
|
240
181
|
height: var(--jh-dimension-1000);
|
|
241
182
|
}
|
|
242
|
-
:host([size='medium']) input {
|
|
183
|
+
:host([size='medium']) .input-wrapper {
|
|
243
184
|
height: var(--jh-dimension-1200);
|
|
244
185
|
}
|
|
245
|
-
:host([size='large']) input {
|
|
186
|
+
:host([size='large']) .input-wrapper {
|
|
246
187
|
height: var(--jh-dimension-1400);
|
|
247
188
|
}
|
|
248
|
-
|
|
249
|
-
|
|
250
|
-
|
|
251
|
-
|
|
252
|
-
|
|
189
|
+
|
|
190
|
+
/* Input element — no border, grows to fill */
|
|
191
|
+
input {
|
|
192
|
+
flex: 1;
|
|
193
|
+
min-width: 0;
|
|
194
|
+
border: none;
|
|
195
|
+
background: transparent;
|
|
196
|
+
outline: none;
|
|
197
|
+
padding: 0;
|
|
198
|
+
color: var(--input-value-color-text);
|
|
199
|
+
font-family: var(--jh-font-body-regular-1-font-family);
|
|
200
|
+
font-weight: var(--jh-font-body-regular-1-font-weight);
|
|
201
|
+
font-size: var(--jh-font-body-regular-1-font-size);
|
|
202
|
+
line-height: var(--jh-font-body-regular-1-line-height);
|
|
203
|
+
height: 100%;
|
|
253
204
|
}
|
|
254
|
-
|
|
255
|
-
|
|
205
|
+
:host([readonly]) input {
|
|
206
|
+
height: auto;
|
|
207
|
+
}
|
|
208
|
+
|
|
209
|
+
/* Slot wrappers */
|
|
210
|
+
.slot-wrapper {
|
|
211
|
+
display: none;
|
|
212
|
+
align-items: center;
|
|
213
|
+
flex-shrink: 0;
|
|
256
214
|
}
|
|
257
|
-
|
|
258
|
-
|
|
259
|
-
|
|
260
|
-
|
|
215
|
+
slot[name="jh-input-left"] {
|
|
216
|
+
display: none;
|
|
217
|
+
align-items: center;
|
|
218
|
+
flex-shrink: 0;
|
|
219
|
+
padding-right: var(--jh-dimension-200);
|
|
261
220
|
}
|
|
262
|
-
|
|
263
|
-
|
|
264
|
-
|
|
265
|
-
|
|
266
|
-
);
|
|
221
|
+
slot[name="jh-input-right"] {
|
|
222
|
+
display: none;
|
|
223
|
+
align-items: center;
|
|
224
|
+
flex-shrink: 0;
|
|
225
|
+
padding-left: var(--jh-dimension-200);
|
|
267
226
|
}
|
|
268
|
-
|
|
269
|
-
|
|
227
|
+
slot[name="jh-input-left"].display-slot,
|
|
228
|
+
slot[name="jh-input-right"].display-slot {
|
|
229
|
+
display: flex;
|
|
270
230
|
}
|
|
271
|
-
|
|
272
|
-
|
|
231
|
+
|
|
232
|
+
/* Slotted content alignment */
|
|
233
|
+
::slotted(*) {
|
|
234
|
+
display: flex;
|
|
235
|
+
align-items: center;
|
|
236
|
+
}
|
|
237
|
+
|
|
238
|
+
/* States on input wrapper */
|
|
239
|
+
.input-wrapper:active {
|
|
273
240
|
border-color: var(
|
|
274
241
|
--jh-input-field-color-border-active,
|
|
275
242
|
var(--jh-color-content-brand-active)
|
|
@@ -278,13 +245,15 @@ export class JhInput extends LitElement {
|
|
|
278
245
|
:host([disabled]) {
|
|
279
246
|
opacity: var(--jh-input-opacity-disabled, var(--jh-opacity-disabled));
|
|
280
247
|
}
|
|
281
|
-
:host([disabled]) input {
|
|
248
|
+
:host([disabled]) .input-wrapper {
|
|
282
249
|
border-color: var(
|
|
283
250
|
--jh-input-field-color-border-disabled,
|
|
284
251
|
var(--jh-border-control-color)
|
|
285
252
|
);
|
|
286
253
|
}
|
|
287
|
-
|
|
254
|
+
|
|
255
|
+
/* Focus-visible on wrapper when input is focused */
|
|
256
|
+
.input-wrapper:has(input:focus-visible) {
|
|
288
257
|
border-color: var(
|
|
289
258
|
--jh-input-field-color-border-focus,
|
|
290
259
|
var(--jh-color-content-brand-hover)
|
|
@@ -297,13 +266,16 @@ export class JhInput extends LitElement {
|
|
|
297
266
|
outline-width: var(--jh-border-focus-width);
|
|
298
267
|
outline-offset: 1px;
|
|
299
268
|
}
|
|
300
|
-
input:
|
|
269
|
+
input:focus-visible {
|
|
270
|
+
outline: none;
|
|
271
|
+
}
|
|
272
|
+
.input-wrapper:hover {
|
|
301
273
|
border-color: var(
|
|
302
274
|
--jh-input-field-color-border-hover,
|
|
303
275
|
var(--jh-color-content-brand-hover)
|
|
304
276
|
);
|
|
305
277
|
}
|
|
306
|
-
:host([invalid]) input {
|
|
278
|
+
:host([invalid]) .input-wrapper {
|
|
307
279
|
border-width: var(--jh-border-error-width);
|
|
308
280
|
border-style: var(--jh-border-error-style);
|
|
309
281
|
border-color: var(
|
|
@@ -311,26 +283,82 @@ export class JhInput extends LitElement {
|
|
|
311
283
|
var(--jh-border-error-color)
|
|
312
284
|
);
|
|
313
285
|
}
|
|
314
|
-
|
|
315
|
-
|
|
286
|
+
|
|
287
|
+
/* Clear button */
|
|
288
|
+
.clear-button {
|
|
289
|
+
--jh-button-border-radius: var(--jh-input-clear-border-radius);
|
|
290
|
+
--jh-button-color-background-tertiary-enabled: var(--jh-input-clear-color-background-enabled);
|
|
291
|
+
--jh-button-color-border-tertiary-enabled: var(--jh-input-clear-color-border-enabled);
|
|
292
|
+
--jh-button-icon-color-fill-tertiary-enabled: var(--jh-input-clear-icon-color-fill-enabled);
|
|
293
|
+
--jh-button-color-background-tertiary-focus: var(--jh-input-clear-color-background-focus);
|
|
294
|
+
--jh-button-color-border-tertiary-focus: var(--jh-input-clear-color-border-focus);
|
|
295
|
+
--jh-button-color-focus: var(--jh-input-clear-color-focus);
|
|
296
|
+
--jh-button-icon-color-fill-tertiary-focus: var(--jh-input-clear-icon-color-fill-focus);
|
|
297
|
+
--jh-button-color-background-tertiary-hover: var(--jh-input-clear-color-background-hover);
|
|
298
|
+
--jh-button-color-border-tertiary-hover: var(--jh-input-clear-color-border-hover);
|
|
299
|
+
--jh-button-icon-color-fill-tertiary-hover: var(--jh-input-clear-icon-color-fill-hover);
|
|
300
|
+
--jh-button-color-background-tertiary-active: var(--jh-input-clear-color-background-active);
|
|
301
|
+
--jh-button-color-border-tertiary-active: var(--jh-input-clear-color-border-active);
|
|
302
|
+
--jh-button-icon-color-fill-tertiary-active: var(--jh-input-clear-icon-color-fill-active);
|
|
303
|
+
display: none;
|
|
304
|
+
flex-shrink: 0;
|
|
305
|
+
}
|
|
306
|
+
.display-clear-button .clear-button {
|
|
307
|
+
display: flex;
|
|
308
|
+
margin-left: var(--jh-dimension-200);
|
|
309
|
+
}
|
|
310
|
+
|
|
311
|
+
/* Readonly styles */
|
|
312
|
+
:host([readonly]) .input-wrapper {
|
|
316
313
|
height: auto;
|
|
317
314
|
background-color: transparent;
|
|
318
315
|
border: none;
|
|
319
316
|
padding-left: 0;
|
|
320
317
|
padding-right: 0;
|
|
321
318
|
}
|
|
319
|
+
|
|
322
320
|
/* Override Chrome autofill styles */
|
|
323
321
|
input:autofill {
|
|
324
322
|
-webkit-text-fill-color: var(--input-value-color-text);
|
|
325
323
|
caret-color: var(--input-value-color-text);
|
|
326
324
|
background-clip: text;
|
|
327
325
|
}
|
|
326
|
+
|
|
327
|
+
/* Footer */
|
|
328
|
+
.footer-content {
|
|
329
|
+
margin: var(--jh-dimension-200) 0 0 0;
|
|
330
|
+
gap: var(--jh-dimension-200);
|
|
331
|
+
display: flex;
|
|
332
|
+
justify-content: space-between;
|
|
333
|
+
}
|
|
334
|
+
.footer-content:has(.counter):not(:has(.error-text)) {
|
|
335
|
+
justify-content: flex-end;
|
|
336
|
+
}
|
|
337
|
+
.counter {
|
|
338
|
+
color: var(--jh-input-counter-color-text,
|
|
339
|
+
var(--jh-color-content-secondary-enabled)
|
|
340
|
+
);
|
|
341
|
+
}
|
|
342
|
+
.error-text {
|
|
343
|
+
color: var(
|
|
344
|
+
--jh-input-error-color-text,
|
|
345
|
+
var(--jh-color-content-negative-enabled)
|
|
346
|
+
);
|
|
347
|
+
}
|
|
348
|
+
p {
|
|
349
|
+
margin: 0;
|
|
350
|
+
}
|
|
351
|
+
|
|
328
352
|
/* Optional/Required/Show-indicator */
|
|
329
353
|
:host([show-indicator]) span {
|
|
330
354
|
color: var(
|
|
331
355
|
--jh-input-optional-color-text,
|
|
332
356
|
var(--jh-color-content-primary-enabled)
|
|
333
357
|
);
|
|
358
|
+
font-family: var(--input-helper-regular-font-family);
|
|
359
|
+
font-weight: var(--input-helper-regular-font-weight);
|
|
360
|
+
font-size: var(--input-helper-regular-font-size);
|
|
361
|
+
line-height: var(--input-helper-regular-line-height);
|
|
334
362
|
}
|
|
335
363
|
:host([show-indicator][required]) span {
|
|
336
364
|
color: var(
|
|
@@ -338,7 +366,6 @@ export class JhInput extends LitElement {
|
|
|
338
366
|
var(--jh-color-content-negative-enabled)
|
|
339
367
|
);
|
|
340
368
|
}
|
|
341
|
-
|
|
342
369
|
`;
|
|
343
370
|
}
|
|
344
371
|
|
|
@@ -370,7 +397,7 @@ export class JhInput extends LitElement {
|
|
|
370
397
|
hideLeftSlot: { type: Boolean, attribute: 'hide-left-slot' },
|
|
371
398
|
/** Hides the right slot from input. */
|
|
372
399
|
hideRightSlot: { type: Boolean, attribute: 'hide-right-slot' },
|
|
373
|
-
/** Formats
|
|
400
|
+
/** Formats user entered data on input based on fixed lengths. This property does not support dynamic formatting or pasted values. See the input mask documentation above for implementation details. */
|
|
374
401
|
inputMask: { type: String, attribute: 'input-mask' },
|
|
375
402
|
/** Indicates expected input value type and allows for browsers to display appropriate virtual keyboard.
|
|
376
403
|
*
|
|
@@ -466,12 +493,15 @@ export class JhInput extends LitElement {
|
|
|
466
493
|
|
|
467
494
|
disconnectedCallback() {
|
|
468
495
|
super.disconnectedCallback();
|
|
469
|
-
this.#resizeObserver.disconnect();
|
|
470
496
|
if (this.inputMask) {
|
|
471
497
|
this.removeEventListener('jh-select', this.#setSelection);
|
|
472
498
|
}
|
|
473
499
|
}
|
|
474
500
|
|
|
501
|
+
get uniqueId() {
|
|
502
|
+
return this.#id;
|
|
503
|
+
}
|
|
504
|
+
|
|
475
505
|
firstUpdated() {
|
|
476
506
|
// attach event listeners to show/hide clear button
|
|
477
507
|
if (this.showClearButton) {
|
|
@@ -482,9 +512,43 @@ export class JhInput extends LitElement {
|
|
|
482
512
|
['mouseenter', 'mouseleave'].forEach(e => {
|
|
483
513
|
inputContainer.addEventListener(e, this.#toggleFocus.bind(this));
|
|
484
514
|
});
|
|
485
|
-
|
|
515
|
+
}
|
|
516
|
+
|
|
517
|
+
if (this.#leftSlot) this.#leftSlot.classList.toggle('display-slot', this.#checkSlotContent(this.#leftSlot));
|
|
518
|
+
if (this.#rightSlot) this.#rightSlot.classList.toggle('display-slot', this.#checkSlotContent(this.#rightSlot));
|
|
519
|
+
|
|
520
|
+
// clicking the wrapper should focus the input
|
|
521
|
+
const wrapper = this.shadowRoot.querySelector('.input-wrapper');
|
|
522
|
+
wrapper?.addEventListener('mousedown', (e) => {
|
|
523
|
+
if (e.target === wrapper || e.target.tagName === 'SLOT') {
|
|
524
|
+
//if the input already has focus, don't do anything. Prevent default to avoid flickering of the focus ring.
|
|
525
|
+
if (this.shadowRoot.activeElement === this.#inputEl) {
|
|
526
|
+
e.preventDefault();
|
|
527
|
+
} else {
|
|
528
|
+
//otherwise set focus to the input.
|
|
529
|
+
e.preventDefault();
|
|
530
|
+
this.#inputEl?.focus();
|
|
531
|
+
}
|
|
532
|
+
}
|
|
533
|
+
});
|
|
486
534
|
}
|
|
487
535
|
|
|
536
|
+
#checkSlotContent(slot) {
|
|
537
|
+
// Slotted and fallback elements
|
|
538
|
+
const slottedElements = slot.assignedElements({ flatten: true });
|
|
539
|
+
if (slottedElements.length > 0) {
|
|
540
|
+
return true;
|
|
541
|
+
}
|
|
542
|
+
|
|
543
|
+
// Slotted and fallback text nodes that are not just whitespace
|
|
544
|
+
if (slot.assignedNodes({ flatten: true }).some(
|
|
545
|
+
(node) => node.nodeType === Node.TEXT_NODE && node.textContent.trim() !== ''
|
|
546
|
+
)) {
|
|
547
|
+
return true;
|
|
548
|
+
}
|
|
549
|
+
return false;
|
|
550
|
+
}
|
|
551
|
+
|
|
488
552
|
#toggleFocus(e) {
|
|
489
553
|
if (this.disabled || this.readonly || !this.showClearButton) {
|
|
490
554
|
return;
|
|
@@ -581,7 +645,7 @@ export class JhInput extends LitElement {
|
|
|
581
645
|
);
|
|
582
646
|
}
|
|
583
647
|
|
|
584
|
-
|
|
648
|
+
_handleInput(e) {
|
|
585
649
|
this.value = e.target.value;
|
|
586
650
|
let inputType = e.inputType;
|
|
587
651
|
this.#deletedChar = inputType === 'deleteContentBackward' || inputType === 'deleteByCut' || inputType === 'deleteContentForward';
|
|
@@ -596,7 +660,7 @@ export class JhInput extends LitElement {
|
|
|
596
660
|
}
|
|
597
661
|
}
|
|
598
662
|
|
|
599
|
-
|
|
663
|
+
_handleKeydown(e) {
|
|
600
664
|
const value = e.target.value;
|
|
601
665
|
let selectionStart = e.target.selectionStart;
|
|
602
666
|
let selectionEnd = e.target.selectionEnd;
|
|
@@ -998,9 +1062,27 @@ export class JhInput extends LitElement {
|
|
|
998
1062
|
this.#selectedText.selectionStart = null;
|
|
999
1063
|
}
|
|
1000
1064
|
}
|
|
1065
|
+
|
|
1066
|
+
// Handle slot visibility updates
|
|
1067
|
+
if (changedProperties.has('hideLeftSlot')) {
|
|
1068
|
+
this.#updateSlotVisibility(this.#leftSlot);
|
|
1069
|
+
}
|
|
1070
|
+
if (changedProperties.has('hideRightSlot')) {
|
|
1071
|
+
this.#updateSlotVisibility(this.#rightSlot);
|
|
1072
|
+
}
|
|
1073
|
+
if (changedProperties.has('readonly')) {
|
|
1074
|
+
this.#updateSlotVisibility(this.#leftSlot);
|
|
1075
|
+
this.#updateSlotVisibility(this.#rightSlot);
|
|
1076
|
+
}
|
|
1077
|
+
}
|
|
1078
|
+
|
|
1079
|
+
#updateSlotVisibility(slot) {
|
|
1080
|
+
if (slot) {
|
|
1081
|
+
slot.classList.toggle('display-slot', this.#checkSlotContent(slot));
|
|
1082
|
+
}
|
|
1001
1083
|
}
|
|
1002
1084
|
|
|
1003
|
-
|
|
1085
|
+
_handleChange() {
|
|
1004
1086
|
let payload = {
|
|
1005
1087
|
'value': this.value,
|
|
1006
1088
|
}
|
|
@@ -1012,7 +1094,7 @@ export class JhInput extends LitElement {
|
|
|
1012
1094
|
this.#dispatch('jh-change', payload);
|
|
1013
1095
|
}
|
|
1014
1096
|
|
|
1015
|
-
|
|
1097
|
+
_handleSelect(e) {
|
|
1016
1098
|
const selectedString = e.target.value.substring(
|
|
1017
1099
|
e.target.selectionStart,
|
|
1018
1100
|
e.target.selectionEnd
|
|
@@ -1028,11 +1110,11 @@ export class JhInput extends LitElement {
|
|
|
1028
1110
|
}
|
|
1029
1111
|
}
|
|
1030
1112
|
|
|
1031
|
-
|
|
1113
|
+
_handleMaxlength() {
|
|
1032
1114
|
this.#dispatch('jh-maxlength');
|
|
1033
1115
|
}
|
|
1034
1116
|
|
|
1035
|
-
|
|
1117
|
+
_handleClearButtonClick() {
|
|
1036
1118
|
let previousValue = this.value;
|
|
1037
1119
|
// clear input value
|
|
1038
1120
|
this.value = '';
|
|
@@ -1051,115 +1133,67 @@ export class JhInput extends LitElement {
|
|
|
1051
1133
|
);
|
|
1052
1134
|
}
|
|
1053
1135
|
|
|
1054
|
-
|
|
1055
|
-
#resizeObserver = new ResizeObserver((entries) => {
|
|
1056
|
-
let inputEl = this.shadowRoot.querySelector('input');
|
|
1057
|
-
|
|
1058
|
-
for (let entry of entries) {
|
|
1059
|
-
let slottedEl = entry.target;
|
|
1060
|
-
let slottedElWidth = entry.borderBoxSize[0].inlineSize;
|
|
1061
|
-
let slottedElHeight = entry.borderBoxSize[0].blockSize;
|
|
1062
|
-
|
|
1063
|
-
this.style.setProperty(`--${slottedEl.slot}-width`, `${slottedElWidth}px`);
|
|
1064
|
-
|
|
1065
|
-
this.style.setProperty(`--${slottedEl.slot}-top`, `${(inputEl.offsetHeight - slottedElHeight) / 2}px`);
|
|
1066
|
-
}
|
|
1067
|
-
});
|
|
1068
|
-
|
|
1069
|
-
#handleSlotChange(e) {
|
|
1136
|
+
_handleSlotChange(e) {
|
|
1070
1137
|
let newSlottedElement = e.target.assignedElements()[0];
|
|
1071
|
-
let
|
|
1138
|
+
let slot = e.target;
|
|
1072
1139
|
|
|
1073
|
-
|
|
1074
|
-
|
|
1075
|
-
this.#resizeObserver.unobserve(this.#activeSlottedElement.get(slotName));
|
|
1140
|
+
if (slot.name !== 'jh-input-left' && slot.name !== 'jh-input-right') {
|
|
1141
|
+
return;
|
|
1076
1142
|
}
|
|
1143
|
+
|
|
1144
|
+
let hasContent = this.#checkSlotContent(slot);
|
|
1145
|
+
slot.classList.toggle('display-slot', hasContent);
|
|
1077
1146
|
|
|
1078
|
-
if
|
|
1079
|
-
|
|
1080
|
-
|
|
1081
|
-
if (newSlottedElement.tagName.startsWith('JH-ICON')) {
|
|
1082
|
-
newSlottedElement.setAttribute('size', 'medium');
|
|
1083
|
-
}
|
|
1084
|
-
this.#resizeObserver.observe(newSlottedElement);
|
|
1147
|
+
// Set icon size if applicable
|
|
1148
|
+
if (newSlottedElement?.tagName.startsWith('JH-ICON')) {
|
|
1149
|
+
newSlottedElement.setAttribute('size', 'medium');
|
|
1085
1150
|
}
|
|
1086
|
-
this.#addClass(slotName, newSlottedElement);
|
|
1087
1151
|
}
|
|
1088
1152
|
|
|
1089
|
-
|
|
1090
|
-
|
|
1091
|
-
|
|
1153
|
+
renderLeftSlot() {
|
|
1154
|
+
if (this.hideLeftSlot) return null;
|
|
1155
|
+
return html`
|
|
1156
|
+
<slot name="jh-input-left" @slotchange=${this._handleSlotChange}></slot>
|
|
1157
|
+
`;
|
|
1158
|
+
}
|
|
1092
1159
|
|
|
1093
|
-
|
|
1094
|
-
if (
|
|
1095
|
-
|
|
1096
|
-
|
|
1097
|
-
|
|
1098
|
-
}
|
|
1160
|
+
renderRightSlot() {
|
|
1161
|
+
if (this.hideRightSlot) return null;
|
|
1162
|
+
return html`
|
|
1163
|
+
<slot name="jh-input-right" @slotchange=${this._handleSlotChange}></slot>
|
|
1164
|
+
`;
|
|
1099
1165
|
}
|
|
1100
1166
|
|
|
1101
|
-
|
|
1102
|
-
if (this.
|
|
1103
|
-
|
|
1104
|
-
|
|
1105
|
-
|
|
1106
|
-
|
|
1107
|
-
|
|
1108
|
-
|
|
1109
|
-
|
|
1110
|
-
|
|
1111
|
-
|
|
1167
|
+
renderClearButton() {
|
|
1168
|
+
if (!this.showClearButton || !this.value || this.disabled) return null;
|
|
1169
|
+
return html`
|
|
1170
|
+
<jh-button
|
|
1171
|
+
size="small" appearance="tertiary" class="clear-button"
|
|
1172
|
+
accessible-label=${ifDefined(this.accessibleLabelClearButton)}
|
|
1173
|
+
@click=${this._handleClearButtonClick}>
|
|
1174
|
+
<slot name="jh-input-clear-button" slot="jh-button-icon">
|
|
1175
|
+
<jh-icon-circle-xmark slot="jh-button-icon" aria-hidden="true" size="medium"></jh-icon-circle-xmark>
|
|
1176
|
+
</slot>
|
|
1177
|
+
</jh-button>
|
|
1112
1178
|
`;
|
|
1113
|
-
|
|
1114
|
-
const clearBtn = this.showClearButton && this.value && !this.disabled
|
|
1115
|
-
? html`
|
|
1116
|
-
<jh-button
|
|
1117
|
-
size="small" appearance="tertiary" class="clear-button"
|
|
1118
|
-
accessible-label=${ifDefined(this.accessibleLabelClearButton)}
|
|
1119
|
-
@click=${this.#handleClearButtonClick}>
|
|
1120
|
-
<slot name="jh-input-clear-button" slot="jh-button-icon">
|
|
1121
|
-
<jh-icon-circle-xmark slot="jh-button-icon" aria-hidden="true" size="medium"></jh-icon-circle-xmark>
|
|
1122
|
-
</slot>
|
|
1123
|
-
</jh-button>
|
|
1124
|
-
`
|
|
1125
|
-
: null;
|
|
1126
|
-
|
|
1127
|
-
|
|
1128
|
-
const rightSlot = this.hideRightSlot
|
|
1129
|
-
? null
|
|
1130
|
-
: html`<slot
|
|
1131
|
-
name="jh-input-right"
|
|
1132
|
-
@slotchange=${this.#handleSlotChange}
|
|
1133
|
-
></slot>
|
|
1134
|
-
`;
|
|
1135
|
-
|
|
1136
|
-
return html`${leftSlot}${clearBtn}${rightSlot}`;
|
|
1137
1179
|
}
|
|
1138
1180
|
|
|
1139
|
-
|
|
1181
|
+
_getDescribedby() {
|
|
1140
1182
|
let describedbyString = '';
|
|
1141
1183
|
|
|
1142
1184
|
if (this.errorText) {
|
|
1143
|
-
describedbyString += `jh-input-error-${this
|
|
1185
|
+
describedbyString += `jh-input-error-${this.uniqueId}`;
|
|
1144
1186
|
}
|
|
1145
1187
|
if (this.helperText) {
|
|
1146
|
-
describedbyString += ` jh-input-helper-${this
|
|
1147
|
-
}
|
|
1148
|
-
if (this.showCharCount) {
|
|
1149
|
-
describedbyString += ` jh-input-counter-${this.#id}`;
|
|
1188
|
+
describedbyString += ` jh-input-helper-${this.uniqueId}`;
|
|
1150
1189
|
}
|
|
1151
1190
|
return describedbyString;
|
|
1152
1191
|
}
|
|
1153
1192
|
|
|
1154
|
-
|
|
1193
|
+
renderLabel() {
|
|
1155
1194
|
let label;
|
|
1156
1195
|
let indicator;
|
|
1157
1196
|
let helperText;
|
|
1158
|
-
let input;
|
|
1159
|
-
let footer;
|
|
1160
|
-
let errorText;
|
|
1161
|
-
let charCount;
|
|
1162
|
-
let describedby;
|
|
1163
1197
|
|
|
1164
1198
|
if (this.label) {
|
|
1165
1199
|
if (this.showIndicator) {
|
|
@@ -1172,17 +1206,24 @@ export class JhInput extends LitElement {
|
|
|
1172
1206
|
|
|
1173
1207
|
if (this.helperText) {
|
|
1174
1208
|
helperText = html`
|
|
1175
|
-
<p id="jh-input-helper-${this
|
|
1209
|
+
<p id="jh-input-helper-${this.uniqueId}" class="helper-text">
|
|
1176
1210
|
${this.helperText}
|
|
1177
1211
|
</p>
|
|
1178
1212
|
`;
|
|
1179
1213
|
}
|
|
1180
1214
|
|
|
1181
1215
|
label = html`
|
|
1182
|
-
<label for="jh-input-${this
|
|
1216
|
+
<label for="jh-input-${this.uniqueId}">${this.label}${indicator}</label>
|
|
1183
1217
|
${helperText}
|
|
1184
1218
|
`;
|
|
1185
1219
|
}
|
|
1220
|
+
return label;
|
|
1221
|
+
}
|
|
1222
|
+
|
|
1223
|
+
renderFooter() {
|
|
1224
|
+
let footer;
|
|
1225
|
+
let errorText;
|
|
1226
|
+
let charCount;
|
|
1186
1227
|
|
|
1187
1228
|
if (this.showCharCount) {
|
|
1188
1229
|
let valueLength = this.value ? this.value.length : 0;
|
|
@@ -1192,7 +1233,7 @@ export class JhInput extends LitElement {
|
|
|
1192
1233
|
}`;
|
|
1193
1234
|
|
|
1194
1235
|
if (valueLength && valueLength === Number(this.maxlength)) {
|
|
1195
|
-
this
|
|
1236
|
+
this._handleMaxlength();
|
|
1196
1237
|
}
|
|
1197
1238
|
|
|
1198
1239
|
charCount = html`
|
|
@@ -1202,7 +1243,7 @@ export class JhInput extends LitElement {
|
|
|
1202
1243
|
|
|
1203
1244
|
if (this.invalid && this.errorText) {
|
|
1204
1245
|
errorText = html`
|
|
1205
|
-
<p id="jh-input-error-${this
|
|
1246
|
+
<p id="jh-input-error-${this.uniqueId}" class="error-text">
|
|
1206
1247
|
${this.errorText}
|
|
1207
1248
|
</p>
|
|
1208
1249
|
`;
|
|
@@ -1216,42 +1257,62 @@ export class JhInput extends LitElement {
|
|
|
1216
1257
|
</div>
|
|
1217
1258
|
`;
|
|
1218
1259
|
}
|
|
1260
|
+
return footer;
|
|
1261
|
+
}
|
|
1262
|
+
|
|
1263
|
+
renderInput() {
|
|
1264
|
+
let describedby;
|
|
1219
1265
|
|
|
1220
|
-
if (helperText || errorText
|
|
1221
|
-
describedby = this
|
|
1266
|
+
if (this.helperText || (this.errorText && this.invalid)) {
|
|
1267
|
+
describedby = this._getDescribedby();
|
|
1222
1268
|
}
|
|
1223
1269
|
|
|
1224
|
-
|
|
1270
|
+
const leftSlot = this.readonly ? null : this.renderLeftSlot();
|
|
1271
|
+
const rightSlot = this.readonly ? null : this.renderRightSlot();
|
|
1272
|
+
const clearButton = this.readonly ? null : this.renderClearButton();
|
|
1273
|
+
|
|
1274
|
+
return html`
|
|
1225
1275
|
<div class="input-container">
|
|
1226
|
-
<input
|
|
1227
|
-
|
|
1228
|
-
|
|
1229
|
-
|
|
1230
|
-
|
|
1231
|
-
this.
|
|
1232
|
-
|
|
1233
|
-
|
|
1234
|
-
|
|
1235
|
-
|
|
1236
|
-
|
|
1237
|
-
|
|
1238
|
-
|
|
1239
|
-
|
|
1240
|
-
|
|
1241
|
-
|
|
1242
|
-
|
|
1243
|
-
|
|
1244
|
-
|
|
1245
|
-
|
|
1246
|
-
|
|
1247
|
-
|
|
1248
|
-
|
|
1249
|
-
|
|
1250
|
-
|
|
1251
|
-
|
|
1252
|
-
|
|
1276
|
+
<div class="input-wrapper">
|
|
1277
|
+
${leftSlot}
|
|
1278
|
+
<input
|
|
1279
|
+
id="jh-input-${this.uniqueId}"
|
|
1280
|
+
aria-describedby=${describedby}
|
|
1281
|
+
aria-invalid=${ifDefined(this.invalid ? 'true' : null)}
|
|
1282
|
+
aria-label=${ifDefined(
|
|
1283
|
+
this.accessibleLabel === '' ? null : this.accessibleLabel
|
|
1284
|
+
)}
|
|
1285
|
+
autocomplete=${ifDefined(
|
|
1286
|
+
this.autocomplete === '' ? null : this.autocomplete
|
|
1287
|
+
)}
|
|
1288
|
+
?disabled=${this.disabled}
|
|
1289
|
+
enterkeyhint=${ifDefined(
|
|
1290
|
+
this.enterkeyhint === '' ? null : this.enterkeyhint
|
|
1291
|
+
)}
|
|
1292
|
+
inputmode=${ifDefined(this.inputmode === '' ? null : this.inputmode)}
|
|
1293
|
+
maxlength=${ifDefined(this.maxlength === '' ? null : this.maxlength)}
|
|
1294
|
+
minlength=${ifDefined(this.minlength === '' ? null : this.minlength)}
|
|
1295
|
+
name=${ifDefined(this.name === '' ? null : this.name)}
|
|
1296
|
+
?readonly=${this.readonly}
|
|
1297
|
+
?required=${this.required}
|
|
1298
|
+
type="text"
|
|
1299
|
+
.value=${this.value}
|
|
1300
|
+
@keydown=${this.inputMask ? this._handleKeydown : null}
|
|
1301
|
+
@change=${this._handleChange}
|
|
1302
|
+
@input=${this._handleInput}
|
|
1303
|
+
@select=${this._handleSelect}
|
|
1304
|
+
/>
|
|
1305
|
+
${clearButton}
|
|
1306
|
+
${rightSlot}
|
|
1307
|
+
</div>
|
|
1253
1308
|
</div>
|
|
1254
1309
|
`;
|
|
1310
|
+
}
|
|
1311
|
+
|
|
1312
|
+
render() {
|
|
1313
|
+
const label = this.renderLabel();
|
|
1314
|
+
const input = this.renderInput();
|
|
1315
|
+
const footer = this.renderFooter();
|
|
1255
1316
|
|
|
1256
1317
|
return html`
|
|
1257
1318
|
${label} ${input} ${footer}
|