@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
|
@@ -9,10 +9,9 @@ import { JhInput } from '../input/input.js';
|
|
|
9
9
|
* @customElement jh-input-email
|
|
10
10
|
*/
|
|
11
11
|
export class JhInputEmail extends JhInput {
|
|
12
|
-
|
|
13
|
-
super
|
|
14
|
-
|
|
15
|
-
inputEl.setAttribute('type', 'email');
|
|
12
|
+
constructor() {
|
|
13
|
+
super();
|
|
14
|
+
this.inputmode = 'email';
|
|
16
15
|
}
|
|
17
16
|
}
|
|
18
17
|
customElements.define('jh-input-email', JhInputEmail);
|
|
@@ -2,48 +2,23 @@
|
|
|
2
2
|
//
|
|
3
3
|
// SPDX-License-Identifier: Apache-2.0
|
|
4
4
|
|
|
5
|
-
import { html
|
|
5
|
+
import { html } from 'lit';
|
|
6
|
+
import { ifDefined } from 'lit/directives/if-defined.js';
|
|
6
7
|
import { JhInput } from '../input/input.js';
|
|
7
8
|
import '@jack-henry/jh-icons/icons-wc/icon-eye-slash.js';
|
|
8
9
|
import '@jack-henry/jh-icons/icons-wc/icon-eye.js';
|
|
9
10
|
|
|
11
|
+
let id = 0;
|
|
12
|
+
|
|
10
13
|
/**
|
|
11
14
|
* @slot jh-input-password-hidden - Use to insert a custom icon within the toggle password button when the input value is masked.
|
|
12
15
|
* @slot jh-input-password-visible - Use to insert a custom icon within the toggle password button when the input value is unmasked.
|
|
13
16
|
* @customElement jh-input-password
|
|
14
17
|
*/
|
|
15
18
|
export class JhInputPassword extends JhInput {
|
|
16
|
-
|
|
17
|
-
|
|
18
|
-
|
|
19
|
-
return [
|
|
20
|
-
super.styles,
|
|
21
|
-
css`
|
|
22
|
-
.password-toggle-btn {
|
|
23
|
-
position: absolute;
|
|
24
|
-
right: var(--jh-dimension-400);
|
|
25
|
-
}
|
|
26
|
-
.clear-button {
|
|
27
|
-
right: var(--jh-dimension-1400);
|
|
28
|
-
}
|
|
29
|
-
.display-clear-button input {
|
|
30
|
-
padding-right: var(--jh-dimension-2400);
|
|
31
|
-
}
|
|
32
|
-
input {
|
|
33
|
-
padding-right: var(--jh-dimension-1400);
|
|
34
|
-
}
|
|
35
|
-
:host([size='small']) .password-toggle-btn {
|
|
36
|
-
top: 4px;
|
|
37
|
-
}
|
|
38
|
-
:host([size='medium']) .password-toggle-btn {
|
|
39
|
-
top: 8px;
|
|
40
|
-
}
|
|
41
|
-
:host([size='large']) .password-toggle-btn {
|
|
42
|
-
top: 12px;
|
|
43
|
-
}
|
|
44
|
-
`
|
|
45
|
-
];
|
|
46
|
-
}
|
|
19
|
+
|
|
20
|
+
/** @type {?number} */
|
|
21
|
+
#id;
|
|
47
22
|
|
|
48
23
|
static get properties() {
|
|
49
24
|
return {
|
|
@@ -69,39 +44,74 @@ export class JhInputPassword extends JhInput {
|
|
|
69
44
|
/** @type {?string} */
|
|
70
45
|
this.accessibleLabelShowPassword = null;
|
|
71
46
|
/** @type {boolean} */
|
|
72
|
-
this.hideRightSlot = true;
|
|
73
|
-
/** @type {boolean} */
|
|
74
47
|
this.passwordVisible = false;
|
|
75
48
|
}
|
|
76
49
|
|
|
77
|
-
|
|
78
|
-
super.
|
|
79
|
-
this.#
|
|
50
|
+
connectedCallback() {
|
|
51
|
+
super.connectedCallback();
|
|
52
|
+
this.#id = id++;
|
|
80
53
|
}
|
|
81
54
|
|
|
82
|
-
|
|
83
|
-
|
|
55
|
+
renderInput() {
|
|
56
|
+
let describedby;
|
|
84
57
|
|
|
85
|
-
if (
|
|
86
|
-
|
|
87
|
-
this.#inputEl.setAttribute('type', 'text');
|
|
88
|
-
} else {
|
|
89
|
-
this.#inputEl.setAttribute('type', 'password');
|
|
90
|
-
}
|
|
58
|
+
if (this.helperText || (this.errorText && this.invalid)) {
|
|
59
|
+
describedby = this._getDescribedby();
|
|
91
60
|
}
|
|
92
|
-
|
|
61
|
+
|
|
62
|
+
const leftSlot = this.readonly ? null : this.renderLeftSlot();
|
|
63
|
+
const rightSlot = this.readonly ? null : this.renderRightSlot();
|
|
64
|
+
const clearButton = this.readonly ? null : this.renderClearButton();
|
|
65
|
+
|
|
66
|
+
return html`
|
|
67
|
+
<div class="input-container">
|
|
68
|
+
<div class="input-wrapper">
|
|
69
|
+
${leftSlot}
|
|
70
|
+
<input
|
|
71
|
+
id="jh-input-${this.#id}"
|
|
72
|
+
aria-describedby=${describedby}
|
|
73
|
+
aria-invalid=${ifDefined(this.invalid ? 'true' : null)}
|
|
74
|
+
aria-label=${ifDefined(
|
|
75
|
+
this.accessibleLabel === '' ? null : this.accessibleLabel
|
|
76
|
+
)}
|
|
77
|
+
autocomplete=${ifDefined(
|
|
78
|
+
this.autocomplete === '' ? null : this.autocomplete
|
|
79
|
+
)}
|
|
80
|
+
?disabled=${this.disabled}
|
|
81
|
+
enterkeyhint=${ifDefined(
|
|
82
|
+
this.enterkeyhint === '' ? null : this.enterkeyhint
|
|
83
|
+
)}
|
|
84
|
+
inputmode=${ifDefined(this.inputmode === '' ? null : this.inputmode)}
|
|
85
|
+
maxlength=${ifDefined(this.maxlength === '' ? null : this.maxlength)}
|
|
86
|
+
minlength=${ifDefined(this.minlength === '' ? null : this.minlength)}
|
|
87
|
+
name=${ifDefined(this.name === '' ? null : this.name)}
|
|
88
|
+
?readonly=${this.readonly}
|
|
89
|
+
?required=${this.required}
|
|
90
|
+
type=${this.passwordVisible ? 'text' : 'password'}
|
|
91
|
+
.value=${this.value}
|
|
92
|
+
@keydown=${this.inputMask ? this._handleKeydown : null}
|
|
93
|
+
@change=${this._handleChange}
|
|
94
|
+
@input=${this._handleInput}
|
|
95
|
+
@select=${this._handleSelect}
|
|
96
|
+
/>
|
|
97
|
+
${clearButton}
|
|
98
|
+
${rightSlot}
|
|
99
|
+
</div>
|
|
100
|
+
</div>
|
|
101
|
+
`;
|
|
93
102
|
}
|
|
94
103
|
|
|
95
|
-
|
|
96
|
-
|
|
97
|
-
|
|
98
|
-
|
|
104
|
+
renderRightSlot() {
|
|
105
|
+
if (this.hideRightSlot) return;
|
|
106
|
+
|
|
107
|
+
return html`
|
|
108
|
+
<slot name="jh-input-right" @slotchange=${this._handleSlotChange}>${this.#renderTogglePasswordBtn()}</slot>
|
|
109
|
+
|
|
110
|
+
`;
|
|
99
111
|
}
|
|
100
112
|
|
|
101
|
-
#
|
|
102
|
-
if (this.readonly)
|
|
103
|
-
return;
|
|
104
|
-
}
|
|
113
|
+
#renderTogglePasswordBtn() {
|
|
114
|
+
if (this.readonly) return;
|
|
105
115
|
|
|
106
116
|
let accessibleLabel = this.passwordVisible
|
|
107
117
|
? this.accessibleLabelHidePassword
|
|
@@ -2,7 +2,7 @@
|
|
|
2
2
|
//
|
|
3
3
|
// SPDX-License-Identifier: Apache-2.0
|
|
4
4
|
|
|
5
|
-
import { css } from 'lit';
|
|
5
|
+
import { css, html } from 'lit';
|
|
6
6
|
import { JhInput } from '../input/input.js';
|
|
7
7
|
import '@jack-henry/jh-icons/icons-wc/icon-magnifying-glass.js';
|
|
8
8
|
|
|
@@ -25,17 +25,20 @@ export class JhInputSearch extends JhInput {
|
|
|
25
25
|
|
|
26
26
|
firstUpdated() {
|
|
27
27
|
super.firstUpdated();
|
|
28
|
-
let leftSlot = this.shadowRoot.querySelector('slot[name="jh-input-left"]');
|
|
29
|
-
|
|
30
|
-
// insert fallback content in left slot if empty
|
|
31
|
-
if (leftSlot && leftSlot.assignedElements().length === 0) {
|
|
32
|
-
this.innerHTML +=
|
|
33
|
-
'<jh-icon-magnifying-glass slot="jh-input-left" aria-hidden="true"></jh-icon-magnifying-glass>';
|
|
34
|
-
}
|
|
35
28
|
|
|
36
29
|
// set input type to search
|
|
37
30
|
let inputEl = this.shadowRoot.querySelector('input');
|
|
38
31
|
inputEl.setAttribute('type', 'search');
|
|
39
32
|
}
|
|
33
|
+
|
|
34
|
+
renderLeftSlot() {
|
|
35
|
+
if (this.hideLeftSlot) return null;
|
|
36
|
+
|
|
37
|
+
return html`
|
|
38
|
+
<slot name="jh-input-left" @slotchange=${this._handleSlotChange}>
|
|
39
|
+
<jh-icon-magnifying-glass aria-hidden="true"></jh-icon-magnifying-glass>
|
|
40
|
+
</slot>
|
|
41
|
+
`;
|
|
42
|
+
}
|
|
40
43
|
}
|
|
41
44
|
customElements.define('jh-input-search', JhInputSearch);
|
|
@@ -18,6 +18,16 @@ let id = 0;
|
|
|
18
18
|
export class JhInputTextarea extends JhInput {
|
|
19
19
|
/** @type {?number} */
|
|
20
20
|
#id;
|
|
21
|
+
/** @type {?ResizeObserver} */
|
|
22
|
+
#resizeObserver;
|
|
23
|
+
|
|
24
|
+
get #textareaEl() {
|
|
25
|
+
return this.renderRoot?.querySelector('textarea');
|
|
26
|
+
}
|
|
27
|
+
|
|
28
|
+
get #footerContent() {
|
|
29
|
+
return this.renderRoot?.querySelector('.footer-content');
|
|
30
|
+
}
|
|
21
31
|
|
|
22
32
|
static get styles() {
|
|
23
33
|
return [
|
|
@@ -118,6 +128,7 @@ export class JhInputTextarea extends JhInput {
|
|
|
118
128
|
);
|
|
119
129
|
}
|
|
120
130
|
:host([readonly]) textarea {
|
|
131
|
+
background-color: transparent;
|
|
121
132
|
height: auto;
|
|
122
133
|
border: none;
|
|
123
134
|
padding-left: 0;
|
|
@@ -153,14 +164,14 @@ export class JhInputTextarea extends JhInput {
|
|
|
153
164
|
attribute: 'auto-grow',
|
|
154
165
|
},
|
|
155
166
|
/** Sets the width of the input field. */
|
|
156
|
-
cols: { type:
|
|
167
|
+
cols: { type: Number },
|
|
157
168
|
/** Removes native resize capability of the input field. */
|
|
158
169
|
noResize: {
|
|
159
170
|
type: Boolean,
|
|
160
171
|
attribute: 'no-resize',
|
|
161
172
|
},
|
|
162
173
|
/** Sets the height of the input field. */
|
|
163
|
-
rows: { type:
|
|
174
|
+
rows: { type: Number },
|
|
164
175
|
/** Specifies how text should be wrapped when submitted in a form. The `cols` property must be set for `wrap='hard'` to take effect. */
|
|
165
176
|
wrap: { type: String },
|
|
166
177
|
/** Prevents users from changing the input value. */
|
|
@@ -171,12 +182,12 @@ export class JhInputTextarea extends JhInput {
|
|
|
171
182
|
constructor() {
|
|
172
183
|
super();
|
|
173
184
|
/** @type {boolean} */
|
|
174
|
-
this.autoGrow =
|
|
175
|
-
/** @type {?
|
|
185
|
+
this.autoGrow = false;
|
|
186
|
+
/** @type {?number} */
|
|
176
187
|
this.cols = null;
|
|
177
188
|
/** @type {boolean} */
|
|
178
189
|
this.noResize = true;
|
|
179
|
-
/** @type {?
|
|
190
|
+
/** @type {?number} */
|
|
180
191
|
this.rows = null;
|
|
181
192
|
/** @type {'small'|'medium'|'large'} */
|
|
182
193
|
this.size = 'medium';
|
|
@@ -189,191 +200,72 @@ export class JhInputTextarea extends JhInput {
|
|
|
189
200
|
this.#id = id++;
|
|
190
201
|
}
|
|
191
202
|
|
|
192
|
-
|
|
193
|
-
|
|
194
|
-
|
|
195
|
-
|
|
196
|
-
|
|
197
|
-
|
|
198
|
-
new ResizeObserver(() => {
|
|
199
|
-
this.#updateFooterWidth(footerContent, textareaEl);
|
|
200
|
-
}).observe(textareaEl);
|
|
203
|
+
disconnectedCallback() {
|
|
204
|
+
super.disconnectedCallback();
|
|
205
|
+
if (this.#resizeObserver) {
|
|
206
|
+
this.#resizeObserver.unobserve(this.#textareaEl);
|
|
207
|
+
this.#resizeObserver.disconnect();
|
|
208
|
+
this.#resizeObserver = null;
|
|
201
209
|
}
|
|
202
210
|
}
|
|
203
211
|
|
|
204
|
-
|
|
205
|
-
|
|
212
|
+
firstUpdated() {
|
|
213
|
+
// add resize observer to update width of footer when textarea width changes
|
|
214
|
+
if (this.#footerContent) {
|
|
215
|
+
this.#resizeObserver = new ResizeObserver(() => {
|
|
216
|
+
this.#updateFooterWidth();
|
|
217
|
+
});
|
|
218
|
+
this.#resizeObserver.observe(this.#textareaEl);
|
|
219
|
+
}
|
|
206
220
|
}
|
|
207
221
|
|
|
208
|
-
#
|
|
209
|
-
this
|
|
210
|
-
|
|
211
|
-
|
|
212
|
-
bubbles: true,
|
|
213
|
-
cancelable: true,
|
|
214
|
-
composed: true,
|
|
215
|
-
})
|
|
216
|
-
);
|
|
222
|
+
#updateFooterWidth() {
|
|
223
|
+
if (this.#footerContent) {
|
|
224
|
+
this.#footerContent.style.width = this.#textareaEl.offsetWidth + 'px';
|
|
225
|
+
}
|
|
217
226
|
}
|
|
218
227
|
|
|
219
|
-
|
|
220
|
-
|
|
221
|
-
|
|
222
|
-
|
|
223
|
-
|
|
228
|
+
_handleInput(e) {
|
|
229
|
+
super._handleInput(e);
|
|
230
|
+
|
|
231
|
+
// add textarea specific autogrow
|
|
224
232
|
if (this.autoGrow) {
|
|
225
233
|
this.#autoGrowTextarea();
|
|
226
234
|
}
|
|
227
235
|
}
|
|
228
236
|
|
|
229
237
|
#autoGrowTextarea() {
|
|
230
|
-
|
|
231
|
-
textareaEl.style.height = 'auto';
|
|
232
|
-
|
|
233
|
-
|
|
234
|
-
|
|
235
|
-
#handleChange() {
|
|
236
|
-
let payload = {
|
|
237
|
-
'value': this.value,
|
|
238
|
-
};
|
|
239
|
-
this.#dispatch('jh-change', payload);
|
|
238
|
+
// Reset height to auto to get the correct scrollHeight
|
|
239
|
+
this.#textareaEl.style.height = 'auto';
|
|
240
|
+
// Set height to scrollHeight to accommodate content
|
|
241
|
+
this.#textareaEl.style.height = `${this.#textareaEl.scrollHeight}px`;
|
|
240
242
|
}
|
|
241
243
|
|
|
242
|
-
|
|
243
|
-
const selectedString = e.target.value.substring(
|
|
244
|
-
e.target.selectionStart,
|
|
245
|
-
e.target.selectionEnd
|
|
246
|
-
);
|
|
247
|
-
|
|
248
|
-
if (selectedString) {
|
|
249
|
-
this.#dispatch('jh-select', {
|
|
250
|
-
selected: selectedString,
|
|
251
|
-
selectionStart: e.target.selectionStart,
|
|
252
|
-
selectionEnd: e.target.selectionEnd,
|
|
253
|
-
});
|
|
254
|
-
}
|
|
255
|
-
}
|
|
256
|
-
|
|
257
|
-
#handleMaxlength() {
|
|
258
|
-
this.#dispatch('jh-maxlength');
|
|
259
|
-
}
|
|
260
|
-
|
|
261
|
-
#getDescribedby() {
|
|
262
|
-
let describedbyString = '';
|
|
263
|
-
|
|
264
|
-
if (this.errorText) {
|
|
265
|
-
describedbyString += `jh-input-error-${this.#id}`;
|
|
266
|
-
}
|
|
267
|
-
if (this.helperText) {
|
|
268
|
-
describedbyString += ` jh-input-helper-${this.#id}`;
|
|
269
|
-
}
|
|
270
|
-
if (this.showCharCount) {
|
|
271
|
-
describedbyString += ` jh-input-counter-${this.#id}`;
|
|
272
|
-
}
|
|
273
|
-
return describedbyString;
|
|
274
|
-
}
|
|
275
|
-
|
|
276
|
-
render() {
|
|
277
|
-
let label;
|
|
278
|
-
let indicator;
|
|
279
|
-
let helperText;
|
|
280
|
-
let input;
|
|
281
|
-
let footer;
|
|
282
|
-
let errorText;
|
|
283
|
-
let charCount;
|
|
284
|
-
let describedby;
|
|
285
|
-
|
|
286
|
-
if (this.label) {
|
|
287
|
-
if (this.showIndicator) {
|
|
288
|
-
if (this.required) {
|
|
289
|
-
indicator = html`<span class="indicator" aria-hidden="true"> *</span>`;
|
|
290
|
-
} else {
|
|
291
|
-
indicator = html`<span class="indicator"> (optional)</span>`;
|
|
292
|
-
}
|
|
293
|
-
}
|
|
294
|
-
|
|
295
|
-
if (this.helperText) {
|
|
296
|
-
helperText = html`
|
|
297
|
-
<p id="jh-input-helper-${this.#id}" class="helper-text">
|
|
298
|
-
${this.helperText}
|
|
299
|
-
</p>
|
|
300
|
-
`;
|
|
301
|
-
}
|
|
302
|
-
|
|
303
|
-
label = html`
|
|
304
|
-
<label for="jh-input-${this.#id}">${this.label}${indicator}</label>
|
|
305
|
-
${helperText}
|
|
306
|
-
`;
|
|
307
|
-
}
|
|
308
|
-
|
|
309
|
-
if (this.showCharCount) {
|
|
310
|
-
let valueLength = this.value ? this.value.length : 0;
|
|
311
|
-
let charCountValue = `${this.maxlength ? `${valueLength}/${this.maxlength}` : valueLength}`;
|
|
312
|
-
|
|
313
|
-
if (valueLength && valueLength === Number(this.maxlength)) {
|
|
314
|
-
this.#handleMaxlength();
|
|
315
|
-
}
|
|
316
|
-
|
|
317
|
-
charCount = html`
|
|
318
|
-
<p class="counter" aria-hidden="true">${charCountValue}</p>
|
|
319
|
-
`;
|
|
320
|
-
}
|
|
321
|
-
|
|
322
|
-
if (this.invalid && this.errorText) {
|
|
323
|
-
errorText = html`
|
|
324
|
-
<p id="jh-input-error-${this.#id}" class="error-text">
|
|
325
|
-
${this.errorText}
|
|
326
|
-
</p>
|
|
327
|
-
`;
|
|
328
|
-
}
|
|
329
|
-
|
|
330
|
-
if ((this.invalid && this.errorText) || this.showCharCount) {
|
|
331
|
-
footer = html`
|
|
332
|
-
<div class="footer-content">
|
|
333
|
-
${errorText}
|
|
334
|
-
${charCount}
|
|
335
|
-
</div>
|
|
336
|
-
`;
|
|
337
|
-
}
|
|
338
|
-
|
|
339
|
-
if (helperText || errorText || charCount) {
|
|
340
|
-
describedby = this.#getDescribedby();
|
|
341
|
-
}
|
|
342
|
-
|
|
343
|
-
input = html`
|
|
344
|
-
<textarea
|
|
345
|
-
id="jh-input-${this.#id}"
|
|
346
|
-
aria-describedby=${describedby}
|
|
347
|
-
aria-invalid=${ifDefined(this.invalid ? 'true' : null)}
|
|
348
|
-
aria-label=${ifDefined(
|
|
349
|
-
this.accessibleLabel === '' ? null : this.accessibleLabel
|
|
350
|
-
)}
|
|
351
|
-
autocomplete=${ifDefined(
|
|
352
|
-
this.autocomplete === '' ? null : this.autocomplete
|
|
353
|
-
)}
|
|
354
|
-
cols=${ifDefined(this.cols === '' ? null : this.cols)}
|
|
355
|
-
?disabled=${this.disabled}
|
|
356
|
-
enterkeyhint=${ifDefined(
|
|
357
|
-
this.enterkeyhint === '' ? null : this.enterkeyhint
|
|
358
|
-
)}
|
|
359
|
-
inputmode=${ifDefined(this.inputmode === '' ? null : this.inputmode)}
|
|
360
|
-
maxlength=${ifDefined(this.maxlength === '' ? null : this.maxlength)}
|
|
361
|
-
minlength=${ifDefined(this.minlength === '' ? null : this.minlength)}
|
|
362
|
-
name=${ifDefined(this.name === '' ? null : this.name)}
|
|
363
|
-
?readonly=${this.readonly}
|
|
364
|
-
?required=${this.required}
|
|
365
|
-
rows=${ifDefined(this.rows === '' ? null : this.rows)}
|
|
366
|
-
.value=${this.value}
|
|
367
|
-
wrap=${ifDefined(this.wrap === '' ? null : this.wrap)}
|
|
368
|
-
@change=${this.#handleChange}
|
|
369
|
-
@select=${this.#handleSelect}
|
|
370
|
-
@input=${this.#handleInput}
|
|
371
|
-
></textarea>
|
|
372
|
-
`;
|
|
373
|
-
|
|
244
|
+
renderInput() {
|
|
374
245
|
return html`
|
|
375
|
-
|
|
376
|
-
|
|
246
|
+
<textarea
|
|
247
|
+
id="jh-input-${this.#id}"
|
|
248
|
+
aria-describedby=${this._getDescribedby()}
|
|
249
|
+
aria-invalid=${ifDefined(this.invalid ? 'true' : null)}
|
|
250
|
+
aria-label=${ifDefined(this.accessibleLabel === '' ? null : this.accessibleLabel)}
|
|
251
|
+
autocomplete=${ifDefined(this.autocomplete === '' ? null : this.autocomplete)}
|
|
252
|
+
cols=${ifDefined(this.cols ? Number(this.cols) : null)}
|
|
253
|
+
?disabled=${this.disabled}
|
|
254
|
+
enterkeyhint=${ifDefined(this.enterkeyhint || null)}
|
|
255
|
+
inputmode=${ifDefined(this.inputmode || null)}
|
|
256
|
+
maxlength=${ifDefined(this.maxlength ? Number(this.maxlength) : null)}
|
|
257
|
+
minlength=${ifDefined(this.minlength ? Number(this.minlength) : null)}
|
|
258
|
+
name=${ifDefined(this.name || null)}
|
|
259
|
+
?readonly=${this.readonly}
|
|
260
|
+
?required=${this.required}
|
|
261
|
+
rows=${ifDefined(this.rows ? Number(this.rows) : null)}
|
|
262
|
+
.value=${this.value}
|
|
263
|
+
wrap=${ifDefined(this.wrap || null)}
|
|
264
|
+
@change=${this._handleChange}
|
|
265
|
+
@input=${this._handleInput}
|
|
266
|
+
@select=${this._handleSelect}
|
|
267
|
+
></textarea>
|
|
268
|
+
`
|
|
377
269
|
}
|
|
378
270
|
}
|
|
379
|
-
customElements.define('jh-input-textarea', JhInputTextarea);
|
|
271
|
+
customElements.define('jh-input-textarea', JhInputTextarea);
|
|
@@ -120,7 +120,10 @@ export class JhListItem extends LitElement {
|
|
|
120
120
|
border-left-width: var(--jh-border-selected-width);
|
|
121
121
|
}
|
|
122
122
|
:host([tabindex][selected]) .list-item {
|
|
123
|
-
padding-left: var(
|
|
123
|
+
padding-left: calc(var(
|
|
124
|
+
--jh-list-item-space-padding-left,
|
|
125
|
+
var(--jh-dimension-600)
|
|
126
|
+
) - var(--jh-border-selected-width));
|
|
124
127
|
}
|
|
125
128
|
:host([tabindex][disabled]) {
|
|
126
129
|
opacity: var(--jh-opacity-disabled);
|
package/components/menu/menu.js
CHANGED
|
@@ -45,6 +45,13 @@ export class JhMenu extends LitElement {
|
|
|
45
45
|
display: flex;
|
|
46
46
|
flex-direction: column;
|
|
47
47
|
position: relative;
|
|
48
|
+
overflow: hidden;
|
|
49
|
+
height: 100%;
|
|
50
|
+
}
|
|
51
|
+
.menu-content {
|
|
52
|
+
flex: 1;
|
|
53
|
+
overflow-y: auto;
|
|
54
|
+
width: 100%;
|
|
48
55
|
}
|
|
49
56
|
`;
|
|
50
57
|
}
|
|
@@ -54,7 +61,11 @@ export class JhMenu extends LitElement {
|
|
|
54
61
|
this.#internals.role = 'menu';
|
|
55
62
|
}
|
|
56
63
|
render() {
|
|
57
|
-
return html
|
|
64
|
+
return html`
|
|
65
|
+
<div class="menu-content">
|
|
66
|
+
<slot></slot>
|
|
67
|
+
</div>
|
|
68
|
+
`;
|
|
58
69
|
}
|
|
59
70
|
}
|
|
60
71
|
customElements.define('jh-menu', JhMenu);
|
|
@@ -17,6 +17,7 @@ let id = 0;
|
|
|
17
17
|
* Defaults to `--jh-color-content-secondary-enabled`.
|
|
18
18
|
* @cssprop --jh-radio-group-error-color-text - The error-text text color.
|
|
19
19
|
* Defaults to `--jh-color-content-negative-enabled`.
|
|
20
|
+
* @cssprop --jh-radio-group-opacity-disabled - The opacity of the radio group when disabled. Defaults to `--jh-opacity-disabled`.
|
|
20
21
|
*
|
|
21
22
|
* @slot default - Use to insert `<jh-radio>` components(s).
|
|
22
23
|
*
|
|
@@ -39,10 +40,14 @@ export class JhRadioGroup extends LitElement {
|
|
|
39
40
|
static get styles() {
|
|
40
41
|
return css`
|
|
41
42
|
:host {
|
|
42
|
-
font-family: var(--jh-font-helper-regular-font-family);
|
|
43
|
-
font-weight: var(--jh-font-helper-regular-font-weight);
|
|
44
|
-
font-size: var(--jh-font-helper-regular-font-size);
|
|
45
|
-
line-height: var(--jh-font-helper-regular-line-height);
|
|
43
|
+
--radio-group-helper-regular-font-family: var(--jh-font-helper-regular-font-family);
|
|
44
|
+
--radio-group-helper-regular-font-weight: var(--jh-font-helper-regular-font-weight);
|
|
45
|
+
--radio-group-helper-regular-font-size: var(--jh-font-helper-regular-font-size);
|
|
46
|
+
--radio-group-helper-regular-line-height: var(--jh-font-helper-regular-line-height);
|
|
47
|
+
font-family: var(--radio-group-helper-regular-font-family);
|
|
48
|
+
font-weight: var(--radio-group-helper-regular-font-weight);
|
|
49
|
+
font-size: var(--radio-group-helper-regular-font-size);
|
|
50
|
+
line-height: var(--radio-group-helper-regular-line-height);
|
|
46
51
|
display: block;
|
|
47
52
|
}
|
|
48
53
|
/* reset styling on fieldset and legend */
|
|
@@ -51,6 +56,18 @@ export class JhRadioGroup extends LitElement {
|
|
|
51
56
|
padding: 0;
|
|
52
57
|
margin: 0;
|
|
53
58
|
}
|
|
59
|
+
:host([disabled]) {
|
|
60
|
+
--group-disabled-opacity: var(--jh-radio-group-opacity-disabled, var(--jh-opacity-disabled));
|
|
61
|
+
}
|
|
62
|
+
:host([disabled]) .label,
|
|
63
|
+
:host([disabled]) .helper-text,
|
|
64
|
+
:host([disabled]) .error-text {
|
|
65
|
+
opacity: var(--group-disabled-opacity);
|
|
66
|
+
pointer-events: none;
|
|
67
|
+
}
|
|
68
|
+
:host([disabled]) ::slotted(jh-radio) {
|
|
69
|
+
--jh-radio-opacity-disabled: var(--group-disabled-opacity);
|
|
70
|
+
}
|
|
54
71
|
:host legend {
|
|
55
72
|
padding: 0;
|
|
56
73
|
}
|
|
@@ -85,6 +102,10 @@ export class JhRadioGroup extends LitElement {
|
|
|
85
102
|
--jh-radio-group-label-color-text,
|
|
86
103
|
var(--jh-color-content-primary-enabled)
|
|
87
104
|
);
|
|
105
|
+
font-family: var(--jh-font-helper-medium-font-family);
|
|
106
|
+
font-weight: var(--jh-font-helper-medium-font-weight);
|
|
107
|
+
font-size: var(--jh-font-helper-medium-font-size);
|
|
108
|
+
line-height: var(--jh-font-helper-medium-line-height);
|
|
88
109
|
}
|
|
89
110
|
.helper-text {
|
|
90
111
|
color: var(
|
|
@@ -110,6 +131,10 @@ export class JhRadioGroup extends LitElement {
|
|
|
110
131
|
--jh-radio-group-required-color-text-optional,
|
|
111
132
|
var(--jh-color-content-primary-enabled)
|
|
112
133
|
);
|
|
134
|
+
font-family: var(--radio-group-helper-regular-font-family);
|
|
135
|
+
font-weight: var(--radio-group-helper-regular-font-weight);
|
|
136
|
+
font-size: var(--radio-group-helper-regular-font-size);
|
|
137
|
+
line-height: var(--radio-group-helper-regular-line-height);
|
|
113
138
|
}
|
|
114
139
|
:host([show-indicator][required]) .indicator {
|
|
115
140
|
color: var(
|
|
@@ -126,6 +151,11 @@ export class JhRadioGroup extends LitElement {
|
|
|
126
151
|
type: String,
|
|
127
152
|
attribute: 'accessible-label',
|
|
128
153
|
},
|
|
154
|
+
/** Disables the radio group and prevents all user interactions. May cause the group to be ignored by assistive technologies (AT). */
|
|
155
|
+
disabled: {
|
|
156
|
+
type: Boolean,
|
|
157
|
+
reflect: true
|
|
158
|
+
},
|
|
129
159
|
/** Text to be displayed when radio group has failed validation and `invalid` is true. */
|
|
130
160
|
errorText: {
|
|
131
161
|
type: String,
|
|
@@ -181,17 +211,19 @@ export class JhRadioGroup extends LitElement {
|
|
|
181
211
|
this.#internals = this.attachInternals();
|
|
182
212
|
/** @type {?string} */
|
|
183
213
|
this.accessibleLabel = null;
|
|
214
|
+
/** @type {boolean} */
|
|
215
|
+
this.disabled = false;
|
|
184
216
|
/** @type {?string} */
|
|
185
217
|
this.errorText = null;
|
|
186
218
|
/** @type {?string} */
|
|
187
219
|
this.helperText = null;
|
|
188
|
-
/** @type {?
|
|
220
|
+
/** @type {?boolean} */
|
|
189
221
|
this.invalid = false;
|
|
190
222
|
/** @type {?string} */
|
|
191
223
|
this.label = null;
|
|
192
224
|
/** @type {?string} */
|
|
193
225
|
this.name = null;
|
|
194
|
-
/** @type {?
|
|
226
|
+
/** @type {?boolean} */
|
|
195
227
|
this.required = false;
|
|
196
228
|
/** @type {'vertical'|'horizontal'} */
|
|
197
229
|
this.orientation = 'vertical';
|
|
@@ -210,6 +242,16 @@ export class JhRadioGroup extends LitElement {
|
|
|
210
242
|
this.#id = id++;
|
|
211
243
|
}
|
|
212
244
|
|
|
245
|
+
firstUpdated() {
|
|
246
|
+
this._syncDisabledToChildren();
|
|
247
|
+
}
|
|
248
|
+
|
|
249
|
+
updated(changedProperties) {
|
|
250
|
+
if (changedProperties.has('disabled')) {
|
|
251
|
+
this._syncDisabledToChildren();
|
|
252
|
+
}
|
|
253
|
+
}
|
|
254
|
+
|
|
213
255
|
/**
|
|
214
256
|
* Returns the radio group's parent form element.
|
|
215
257
|
* @type {?HTMLFormElement}
|
|
@@ -237,6 +279,16 @@ export class JhRadioGroup extends LitElement {
|
|
|
237
279
|
this.requestUpdate('value', oldValue);
|
|
238
280
|
}
|
|
239
281
|
|
|
282
|
+
_syncDisabledToChildren() {
|
|
283
|
+
const slot = this.renderRoot.querySelector('slot');
|
|
284
|
+
if(!slot) return;
|
|
285
|
+
|
|
286
|
+
const radios = slot.assignedElements().filter((el) => el.tagName === 'JH-RADIO');
|
|
287
|
+
radios.forEach((radio) => {
|
|
288
|
+
radio.disabled = this.disabled;
|
|
289
|
+
});
|
|
290
|
+
}
|
|
291
|
+
|
|
240
292
|
#getRadios() {
|
|
241
293
|
return [...this.querySelectorAll('jh-radio')];
|
|
242
294
|
}
|
|
@@ -260,6 +312,8 @@ export class JhRadioGroup extends LitElement {
|
|
|
260
312
|
if (!this.#checked) {
|
|
261
313
|
radios[0].tabIndex = 0;
|
|
262
314
|
}
|
|
315
|
+
|
|
316
|
+
this._syncDisabledToChildren();
|
|
263
317
|
}
|
|
264
318
|
|
|
265
319
|
#handleChange(e) {
|
|
@@ -384,6 +438,7 @@ export class JhRadioGroup extends LitElement {
|
|
|
384
438
|
role="radiogroup"
|
|
385
439
|
id=${ifDefined(this.label ? `radio-group-label-${this.#id}` : null)}
|
|
386
440
|
aria-describedby=${ifDefined(this.#getAriaDescribedBy())}
|
|
441
|
+
aria-disabled=${ifDefined(this.disabled ? 'true' : null)}
|
|
387
442
|
aria-required=${ifDefined(this.required ? 'true' : 'false')}
|
|
388
443
|
aria-invalid=${ifDefined(this.invalid ? 'true' : null)}
|
|
389
444
|
aria-label=${ifDefined(this.accessibleLabel)}
|