@jungherz-de/glasskit-elements 1.22.1 → 1.22.3
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 +28 -1
- package/README.md +2 -2
- package/SKILL.md +11 -8
- package/dist/components/base.js +34 -0
- package/dist/components/glk-button.js +6 -9
- package/dist/components/glk-calendar.js +10 -2
- package/dist/components/glk-checkbox.js +3 -8
- package/dist/components/glk-input.js +20 -14
- package/dist/components/glk-radio.js +8 -11
- package/dist/components/glk-range.js +3 -6
- package/dist/components/glk-search.js +3 -6
- package/dist/components/glk-segmented.js +14 -3
- package/dist/components/glk-select.js +3 -8
- package/dist/components/glk-textarea.js +3 -8
- package/dist/components/glk-toggle.js +3 -8
- package/dist/glasskit-elements.esm.js +112 -85
- package/dist/glasskit-elements.js +112 -85
- package/dist/glasskit-elements.min.js +1 -1
- package/package.json +3 -3
- package/src/base.js +34 -0
- package/src/components/buttons/glk-button.js +6 -9
- package/src/components/forms/glk-calendar.js +10 -2
- package/src/components/forms/glk-checkbox.js +3 -8
- package/src/components/forms/glk-input.js +20 -14
- package/src/components/forms/glk-radio.js +8 -11
- package/src/components/forms/glk-range.js +3 -6
- package/src/components/forms/glk-search.js +3 -6
- package/src/components/forms/glk-segmented.js +14 -3
- package/src/components/forms/glk-select.js +3 -8
- package/src/components/forms/glk-textarea.js +3 -8
- package/src/components/forms/glk-toggle.js +3 -8
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@jungherz-de/glasskit-elements",
|
|
3
|
-
"version": "1.22.
|
|
3
|
+
"version": "1.22.3",
|
|
4
4
|
"description": "Vanilla JavaScript Web Components wrapping the GlassKit CSS glassmorphism library",
|
|
5
5
|
"license": "MIT",
|
|
6
6
|
"homepage": "https://glasskit-elements.jungherz.com",
|
|
@@ -49,10 +49,10 @@
|
|
|
49
49
|
"vanilla-js"
|
|
50
50
|
],
|
|
51
51
|
"peerDependencies": {
|
|
52
|
-
"@jungherz-de/glasskit": ">=1.22.
|
|
52
|
+
"@jungherz-de/glasskit": ">=1.22.2"
|
|
53
53
|
},
|
|
54
54
|
"devDependencies": {
|
|
55
|
-
"@jungherz-de/glasskit": "^1.22.
|
|
55
|
+
"@jungherz-de/glasskit": "^1.22.2",
|
|
56
56
|
"@rollup/plugin-node-resolve": "^15.0.0",
|
|
57
57
|
"@rollup/plugin-terser": "^0.4.0",
|
|
58
58
|
"rollup": "^4.0.0"
|
package/src/base.js
CHANGED
|
@@ -238,6 +238,7 @@ export class GlkElement extends HTMLElement {
|
|
|
238
238
|
this._shadow.appendChild(this._wrapper);
|
|
239
239
|
|
|
240
240
|
this.render();
|
|
241
|
+
if (this.constructor.formAssociated) this._syncDisabled();
|
|
241
242
|
} else {
|
|
242
243
|
// Back in the document. While it was out, the observer did not reach
|
|
243
244
|
// it, so a theme or density switched in the meantime is caught up here
|
|
@@ -340,6 +341,28 @@ export class GlkElement extends HTMLElement {
|
|
|
340
341
|
*/
|
|
341
342
|
refresh() { this.projectLightDom(); }
|
|
342
343
|
|
|
344
|
+
/**
|
|
345
|
+
* Form-associated elements only. Such an element is disabled by its own
|
|
346
|
+
* `disabled` attribute or by a <fieldset disabled> around it: the browser
|
|
347
|
+
* counts both — :disabled, left out of the form data — and calls
|
|
348
|
+
* formDisabledCallback() on every change, also when the element moves into
|
|
349
|
+
* or out of such a fieldset. The native controls sit in the shadow root,
|
|
350
|
+
* out of every fieldset's reach, so the state is handed on to them through
|
|
351
|
+
* applyDisabled(). Until 1.22.2 only the element's own attribute reached
|
|
352
|
+
* them: inside a disabled fieldset every field stayed usable, and a submit
|
|
353
|
+
* button sent the form.
|
|
354
|
+
*/
|
|
355
|
+
get _actuallyDisabled() { return this.matches(':disabled'); }
|
|
356
|
+
|
|
357
|
+
formDisabledCallback() {
|
|
358
|
+
if (this._initialized) this._syncDisabled();
|
|
359
|
+
}
|
|
360
|
+
|
|
361
|
+
_syncDisabled() { this.applyDisabled(this._actuallyDisabled); }
|
|
362
|
+
|
|
363
|
+
/** Form-associated subclasses override to disable their native controls. */
|
|
364
|
+
applyDisabled(disabled) {}
|
|
365
|
+
|
|
343
366
|
// ── Utility Methods ──
|
|
344
367
|
|
|
345
368
|
/**
|
|
@@ -417,6 +440,17 @@ export class GlkFormElement extends GlkElement {
|
|
|
417
440
|
if (this._initialized) this.syncValidity();
|
|
418
441
|
}
|
|
419
442
|
|
|
443
|
+
// Reflects the attribute, as on a native control: a disabled fieldset
|
|
444
|
+
// around the element disables it without changing this.
|
|
445
|
+
get disabled() { return this.getBoolAttr('disabled'); }
|
|
446
|
+
set disabled(v) { this.setBoolAttr('disabled', v); }
|
|
447
|
+
|
|
448
|
+
_syncDisabled() {
|
|
449
|
+
super._syncDisabled();
|
|
450
|
+
// A disabled field is barred from validation; enabled again, it counts.
|
|
451
|
+
this.syncValidity();
|
|
452
|
+
}
|
|
453
|
+
|
|
420
454
|
get form() { return this._internals.form; }
|
|
421
455
|
get validationMessage() { return this._internals.validationMessage; }
|
|
422
456
|
get validity() { return this._internals.validity; }
|
|
@@ -10,12 +10,13 @@ const FORWARDED_ARIA = ['aria-expanded', 'aria-haspopup', 'aria-pressed'];
|
|
|
10
10
|
|
|
11
11
|
class GlkButton extends GlkElement {
|
|
12
12
|
static get observedAttributes() {
|
|
13
|
-
return ['variant', 'size', '
|
|
13
|
+
return ['variant', 'size', 'type', ...FORWARDED_ARIA];
|
|
14
14
|
}
|
|
15
15
|
|
|
16
16
|
// The native button sits in the shadow root, outside every form. Form
|
|
17
17
|
// association gives the element its form, so type="submit" and "reset"
|
|
18
|
-
// can act on it (see _activateForm)
|
|
18
|
+
// can act on it (see _activateForm), and a disabled fieldset around it
|
|
19
|
+
// disables it (since 1.22.3; before, it still sent the form).
|
|
19
20
|
static formAssociated = true;
|
|
20
21
|
|
|
21
22
|
constructor() {
|
|
@@ -28,9 +29,6 @@ class GlkButton extends GlkElement {
|
|
|
28
29
|
type: this.getAttribute('type') || 'button'
|
|
29
30
|
});
|
|
30
31
|
|
|
31
|
-
if (this.getBoolAttr('disabled')) {
|
|
32
|
-
this._btn.disabled = true;
|
|
33
|
-
}
|
|
34
32
|
for (const attr of FORWARDED_ARIA) this._forward(attr);
|
|
35
33
|
|
|
36
34
|
this._btn.appendChild(document.createElement('slot'));
|
|
@@ -39,7 +37,7 @@ class GlkButton extends GlkElement {
|
|
|
39
37
|
|
|
40
38
|
setupEvents() {
|
|
41
39
|
this._onClick = (e) => {
|
|
42
|
-
if (this.
|
|
40
|
+
if (this._actuallyDisabled) {
|
|
43
41
|
e.preventDefault();
|
|
44
42
|
e.stopPropagation();
|
|
45
43
|
return;
|
|
@@ -98,9 +96,6 @@ class GlkButton extends GlkElement {
|
|
|
98
96
|
case 'size':
|
|
99
97
|
this._btn.className = this._computeClasses().join(' ');
|
|
100
98
|
break;
|
|
101
|
-
case 'disabled':
|
|
102
|
-
this._btn.disabled = this.getBoolAttr('disabled');
|
|
103
|
-
break;
|
|
104
99
|
case 'type':
|
|
105
100
|
this._btn.setAttribute('type', this.getAttribute('type') || 'button');
|
|
106
101
|
break;
|
|
@@ -109,6 +104,8 @@ class GlkButton extends GlkElement {
|
|
|
109
104
|
}
|
|
110
105
|
}
|
|
111
106
|
|
|
107
|
+
applyDisabled(disabled) { this._btn.disabled = disabled; }
|
|
108
|
+
|
|
112
109
|
_forward(attr) {
|
|
113
110
|
const value = this.getAttribute(attr);
|
|
114
111
|
if (value === null) this._btn.removeAttribute(attr);
|
|
@@ -10,8 +10,9 @@ import { isoDate, parseIso, addDays, parseJsonObject, resolveLocale, formatters,
|
|
|
10
10
|
// the page language, else the browser's), week-start (0 = Sunday … 6 = Saturday;
|
|
11
11
|
// default from the locale, Monday where the browser cannot say),
|
|
12
12
|
// label (aria-label of the day group), prev-label / next-label
|
|
13
|
-
// (names of the nav buttons, English by default)
|
|
14
|
-
//
|
|
13
|
+
// (names of the nav buttons, English by default), disabled
|
|
14
|
+
// (since 1.22.3, as is a disabled fieldset around it)
|
|
15
|
+
// Properties: month, value, marks, locale, label, disabled
|
|
15
16
|
// Form: associated — a surrounding <form> receives name=value, reset
|
|
16
17
|
// restores the initial value, like <glk-segmented>
|
|
17
18
|
// Events: glk-change { value } — on a pick by the user
|
|
@@ -103,9 +104,16 @@ class GlkCalendar extends GlkFormElement {
|
|
|
103
104
|
day.append(num, dots);
|
|
104
105
|
this._grid.appendChild(day);
|
|
105
106
|
}
|
|
107
|
+
this.applyDisabled(this._actuallyDisabled);
|
|
106
108
|
this._syncValue();
|
|
107
109
|
}
|
|
108
110
|
|
|
111
|
+
// Disabled as a whole: the arrows and every day. The days of another month
|
|
112
|
+
// are built again, so _build() hands the state on to them too.
|
|
113
|
+
applyDisabled(disabled) {
|
|
114
|
+
for (const button of [this._prev, this._next, ...this._days()]) button.disabled = disabled;
|
|
115
|
+
}
|
|
116
|
+
|
|
109
117
|
_days() { return [...this._grid.querySelectorAll('button[data-value]')]; }
|
|
110
118
|
_dayFor(iso) { return this._grid.querySelector(`button[data-value="${iso}"]`); }
|
|
111
119
|
|
|
@@ -4,7 +4,7 @@ const CHECKMARK_SVG = `<svg viewBox="0 0 24 24" fill="none" stroke="currentColor
|
|
|
4
4
|
|
|
5
5
|
class GlkCheckbox extends GlkFormElement {
|
|
6
6
|
static get observedAttributes() {
|
|
7
|
-
return ['checked', '
|
|
7
|
+
return ['checked', 'label', 'name', 'value', 'required'];
|
|
8
8
|
}
|
|
9
9
|
|
|
10
10
|
static get hostStyles() { return checkControlSheet; }
|
|
@@ -30,7 +30,6 @@ class GlkCheckbox extends GlkFormElement {
|
|
|
30
30
|
label.appendChild(this._labelEl);
|
|
31
31
|
|
|
32
32
|
if (this.getBoolAttr('checked')) this._input.checked = true;
|
|
33
|
-
if (this.getBoolAttr('disabled')) this._input.disabled = true;
|
|
34
33
|
if (this.getBoolAttr('required')) this._input.required = true;
|
|
35
34
|
|
|
36
35
|
this._defaultChecked = this.getBoolAttr('checked');
|
|
@@ -64,9 +63,6 @@ class GlkCheckbox extends GlkFormElement {
|
|
|
64
63
|
this._input.checked = this.getBoolAttr('checked');
|
|
65
64
|
this._syncFormValue();
|
|
66
65
|
break;
|
|
67
|
-
case 'disabled':
|
|
68
|
-
this._input.disabled = this.getBoolAttr('disabled');
|
|
69
|
-
break;
|
|
70
66
|
case 'label':
|
|
71
67
|
this._labelEl.textContent = this.getAttribute('label') || '';
|
|
72
68
|
break;
|
|
@@ -79,6 +75,8 @@ class GlkCheckbox extends GlkFormElement {
|
|
|
79
75
|
}
|
|
80
76
|
}
|
|
81
77
|
|
|
78
|
+
applyDisabled(disabled) { this._input.disabled = disabled; }
|
|
79
|
+
|
|
82
80
|
get _validityField() { return this._input; }
|
|
83
81
|
|
|
84
82
|
_syncFormValue() {
|
|
@@ -100,9 +98,6 @@ class GlkCheckbox extends GlkFormElement {
|
|
|
100
98
|
if (this._input) this._syncFormValue();
|
|
101
99
|
}
|
|
102
100
|
|
|
103
|
-
get disabled() { return this.getBoolAttr('disabled'); }
|
|
104
|
-
set disabled(v) { this.setBoolAttr('disabled', v); }
|
|
105
|
-
|
|
106
101
|
get name() { return this.getAttribute('name'); }
|
|
107
102
|
set name(v) { this.setAttribute('name', v); }
|
|
108
103
|
|
|
@@ -9,19 +9,30 @@ const FORWARDED = ['min', 'max', 'step', 'minlength', 'maxlength', 'pattern', 'a
|
|
|
9
9
|
// Prefix and suffix (since 1.22.0): two slots inside the field's box, on
|
|
10
10
|
// GlassKit's .glass-input-wrap. An affix shows only while something is
|
|
11
11
|
// slotted into it, and its width is measured, so the text keeps clear of a
|
|
12
|
-
// unit of any length. GlassKit
|
|
13
|
-
//
|
|
14
|
-
//
|
|
15
|
-
//
|
|
12
|
+
// unit of any length. As in GlassKit, a click on text, an icon or a disabled
|
|
13
|
+
// control goes through to the field, and what can be used takes its own: an
|
|
14
|
+
// enabled control (<glk-button>, <glk-select> … are form-associated, so they
|
|
15
|
+
// count), a link, an element with tabindex. GlassKit's own rule cannot reach
|
|
16
|
+
// slotted elements, hence this one. ::slotted() sees the slotted element,
|
|
17
|
+
// not what is inside it: a button wrapped in a slotted <span> needs
|
|
18
|
+
// pointer-events: auto from the page. Until 1.22.1 every slotted element took
|
|
19
|
+
// the pointer — a unit caught the click meant for the field, a disabled
|
|
20
|
+
// button took it and moved the focus into the field, read-only and locked
|
|
21
|
+
// or not. Simple selectors only inside ::slotted(), so that no browser drops
|
|
22
|
+
// the rule.
|
|
16
23
|
const affixSheet = new CSSStyleSheet();
|
|
17
24
|
affixSheet.replaceSync(`
|
|
18
|
-
.glass-input-wrap__prefix ::slotted(
|
|
19
|
-
.glass-input-
|
|
25
|
+
.glass-input-wrap__prefix ::slotted(:enabled),
|
|
26
|
+
.glass-input-wrap__prefix ::slotted(a[href]),
|
|
27
|
+
.glass-input-wrap__prefix ::slotted([tabindex]:not(:disabled)),
|
|
28
|
+
.glass-input-wrap__suffix ::slotted(:enabled),
|
|
29
|
+
.glass-input-wrap__suffix ::slotted(a[href]),
|
|
30
|
+
.glass-input-wrap__suffix ::slotted([tabindex]:not(:disabled)) { pointer-events: auto; }
|
|
20
31
|
`);
|
|
21
32
|
|
|
22
33
|
class GlkInput extends GlkFormElement {
|
|
23
34
|
static get observedAttributes() {
|
|
24
|
-
return ['label', 'type', 'placeholder', 'error', 'hint', '
|
|
35
|
+
return ['label', 'type', 'placeholder', 'error', 'hint', 'readonly', 'name', 'value', 'required', ...FORWARDED];
|
|
25
36
|
}
|
|
26
37
|
|
|
27
38
|
static get hostStyles() { return affixSheet; }
|
|
@@ -52,7 +63,6 @@ class GlkInput extends GlkFormElement {
|
|
|
52
63
|
this._pendingValue = undefined;
|
|
53
64
|
if (value) this._input.value = value;
|
|
54
65
|
|
|
55
|
-
if (this.getBoolAttr('disabled')) this._input.disabled = true;
|
|
56
66
|
if (this.getBoolAttr('readonly')) this._input.readOnly = true;
|
|
57
67
|
if (this.getBoolAttr('required')) this._input.required = true;
|
|
58
68
|
for (const attr of FORWARDED) this._forward(attr);
|
|
@@ -142,9 +152,6 @@ class GlkInput extends GlkFormElement {
|
|
|
142
152
|
}
|
|
143
153
|
this._applyDescription();
|
|
144
154
|
break;
|
|
145
|
-
case 'disabled':
|
|
146
|
-
this._input.disabled = this.getBoolAttr('disabled');
|
|
147
|
-
break;
|
|
148
155
|
case 'readonly':
|
|
149
156
|
this._input.readOnly = this.getBoolAttr('readonly');
|
|
150
157
|
break;
|
|
@@ -163,6 +170,8 @@ class GlkInput extends GlkFormElement {
|
|
|
163
170
|
}
|
|
164
171
|
}
|
|
165
172
|
|
|
173
|
+
applyDisabled(disabled) { this._input.disabled = disabled; }
|
|
174
|
+
|
|
166
175
|
/** An affix shows, and makes room in the field, only while something is slotted. */
|
|
167
176
|
_applyAffixes() {
|
|
168
177
|
for (const affix of [this._prefix, this._suffix]) {
|
|
@@ -228,9 +237,6 @@ class GlkInput extends GlkFormElement {
|
|
|
228
237
|
this._syncFormValue();
|
|
229
238
|
}
|
|
230
239
|
|
|
231
|
-
get disabled() { return this.getBoolAttr('disabled'); }
|
|
232
|
-
set disabled(v) { this.setBoolAttr('disabled', v); }
|
|
233
|
-
|
|
234
240
|
get readOnly() { return this.getBoolAttr('readonly'); }
|
|
235
241
|
set readOnly(v) { this.setBoolAttr('readonly', v); }
|
|
236
242
|
|
|
@@ -19,7 +19,7 @@ function ownerForm(el) {
|
|
|
19
19
|
|
|
20
20
|
/** Only the selected radio is a tab stop; arrow keys move within the group. */
|
|
21
21
|
function syncGroupTabIndex(group) {
|
|
22
|
-
const enabled = group.filter(el => !el.
|
|
22
|
+
const enabled = group.filter(el => !el._actuallyDisabled);
|
|
23
23
|
if (!enabled.length) return;
|
|
24
24
|
const focusable = enabled.find(el => el.checked) || enabled[0];
|
|
25
25
|
for (const el of group) {
|
|
@@ -29,7 +29,7 @@ function syncGroupTabIndex(group) {
|
|
|
29
29
|
|
|
30
30
|
class GlkRadio extends GlkFormElement {
|
|
31
31
|
static get observedAttributes() {
|
|
32
|
-
return ['checked', '
|
|
32
|
+
return ['checked', 'label', 'name', 'value', 'required'];
|
|
33
33
|
}
|
|
34
34
|
|
|
35
35
|
static get hostStyles() { return checkControlSheet; }
|
|
@@ -59,7 +59,6 @@ class GlkRadio extends GlkFormElement {
|
|
|
59
59
|
label.appendChild(this._labelEl);
|
|
60
60
|
|
|
61
61
|
if (this.getBoolAttr('checked')) this._input.checked = true;
|
|
62
|
-
if (this.getBoolAttr('disabled')) this._input.disabled = true;
|
|
63
62
|
|
|
64
63
|
this._defaultChecked = this.getBoolAttr('checked');
|
|
65
64
|
this._wrapper.appendChild(label);
|
|
@@ -77,7 +76,7 @@ class GlkRadio extends GlkFormElement {
|
|
|
77
76
|
this._onKeyDown = (e) => {
|
|
78
77
|
const dir = ARROW_KEYS[e.key];
|
|
79
78
|
if (!dir || e.ctrlKey || e.metaKey || e.altKey) return;
|
|
80
|
-
const group = this._group().filter(el => !el.
|
|
79
|
+
const group = this._group().filter(el => !el._actuallyDisabled);
|
|
81
80
|
if (group.length < 2) return;
|
|
82
81
|
e.preventDefault();
|
|
83
82
|
const next = group[(group.indexOf(this) + dir + group.length) % group.length];
|
|
@@ -159,10 +158,6 @@ class GlkRadio extends GlkFormElement {
|
|
|
159
158
|
this._syncFormValue();
|
|
160
159
|
syncGroupTabIndex(this._group());
|
|
161
160
|
break;
|
|
162
|
-
case 'disabled':
|
|
163
|
-
this._input.disabled = this.getBoolAttr('disabled');
|
|
164
|
-
syncGroupTabIndex(this._group());
|
|
165
|
-
break;
|
|
166
161
|
case 'label':
|
|
167
162
|
this._labelEl.textContent = this.getAttribute('label') || '';
|
|
168
163
|
break;
|
|
@@ -177,6 +172,11 @@ class GlkRadio extends GlkFormElement {
|
|
|
177
172
|
}
|
|
178
173
|
}
|
|
179
174
|
|
|
175
|
+
applyDisabled(disabled) {
|
|
176
|
+
this._input.disabled = disabled;
|
|
177
|
+
syncGroupTabIndex(this._group());
|
|
178
|
+
}
|
|
179
|
+
|
|
180
180
|
_syncFormValue() {
|
|
181
181
|
const val = this.getAttribute('value') || '';
|
|
182
182
|
this.setFormValue(this._input.checked ? val : null);
|
|
@@ -201,9 +201,6 @@ class GlkRadio extends GlkFormElement {
|
|
|
201
201
|
syncGroupTabIndex(this._group());
|
|
202
202
|
}
|
|
203
203
|
|
|
204
|
-
get disabled() { return this.getBoolAttr('disabled'); }
|
|
205
|
-
set disabled(v) { this.setBoolAttr('disabled', v); }
|
|
206
|
-
|
|
207
204
|
get name() { return this.getAttribute('name'); }
|
|
208
205
|
set name(v) { this.setAttribute('name', v); }
|
|
209
206
|
|
|
@@ -2,7 +2,7 @@ import { GlkFormElement } from '../../base.js';
|
|
|
2
2
|
|
|
3
3
|
class GlkRange extends GlkFormElement {
|
|
4
4
|
static get observedAttributes() {
|
|
5
|
-
return ['label', 'min', 'max', 'value', 'step', 'name'
|
|
5
|
+
return ['label', 'min', 'max', 'value', 'step', 'name'];
|
|
6
6
|
}
|
|
7
7
|
|
|
8
8
|
render() {
|
|
@@ -33,8 +33,6 @@ class GlkRange extends GlkFormElement {
|
|
|
33
33
|
const name = this.getAttribute('name');
|
|
34
34
|
if (name) this._input.setAttribute('name', name);
|
|
35
35
|
|
|
36
|
-
if (this.getBoolAttr('disabled')) this._input.disabled = true;
|
|
37
|
-
|
|
38
36
|
// The reset value is the attribute's; a value set as a property before
|
|
39
37
|
// render() has waited for it and comes on top.
|
|
40
38
|
this._defaultValue = this._input.value;
|
|
@@ -86,12 +84,11 @@ class GlkRange extends GlkFormElement {
|
|
|
86
84
|
case 'name':
|
|
87
85
|
this._input.setAttribute('name', this.getAttribute('name') || '');
|
|
88
86
|
break;
|
|
89
|
-
case 'disabled':
|
|
90
|
-
this._input.disabled = this.getBoolAttr('disabled');
|
|
91
|
-
break;
|
|
92
87
|
}
|
|
93
88
|
}
|
|
94
89
|
|
|
90
|
+
applyDisabled(disabled) { this._input.disabled = disabled; }
|
|
91
|
+
|
|
95
92
|
_updateValueDisplay() {
|
|
96
93
|
this._valueEl.textContent = `${this._input.value}%`;
|
|
97
94
|
}
|
|
@@ -4,7 +4,7 @@ const SEARCH_SVG = `<svg viewBox="0 0 24 24" fill="none" stroke="currentColor" s
|
|
|
4
4
|
|
|
5
5
|
class GlkSearch extends GlkFormElement {
|
|
6
6
|
static get observedAttributes() {
|
|
7
|
-
return ['placeholder', 'name', 'value', '
|
|
7
|
+
return ['placeholder', 'name', 'value', 'label'];
|
|
8
8
|
}
|
|
9
9
|
|
|
10
10
|
render() {
|
|
@@ -32,8 +32,6 @@ class GlkSearch extends GlkFormElement {
|
|
|
32
32
|
this._pendingValue = undefined;
|
|
33
33
|
if (value) this._input.value = value;
|
|
34
34
|
|
|
35
|
-
if (this.getBoolAttr('disabled')) this._input.disabled = true;
|
|
36
|
-
|
|
37
35
|
container.appendChild(icon);
|
|
38
36
|
container.appendChild(this._input);
|
|
39
37
|
|
|
@@ -67,15 +65,14 @@ class GlkSearch extends GlkFormElement {
|
|
|
67
65
|
this._input.value = this.getAttribute('value') || '';
|
|
68
66
|
this._syncFormValue();
|
|
69
67
|
break;
|
|
70
|
-
case 'disabled':
|
|
71
|
-
this._input.disabled = this.getBoolAttr('disabled');
|
|
72
|
-
break;
|
|
73
68
|
case 'label':
|
|
74
69
|
this._applyLabel();
|
|
75
70
|
break;
|
|
76
71
|
}
|
|
77
72
|
}
|
|
78
73
|
|
|
74
|
+
applyDisabled(disabled) { this._input.disabled = disabled; }
|
|
75
|
+
|
|
79
76
|
_applyLabel() {
|
|
80
77
|
const label = this.getAttribute('label');
|
|
81
78
|
if (label) this._input.setAttribute('aria-label', label);
|
|
@@ -7,8 +7,11 @@ import { revealCentered } from '../../reveal.js';
|
|
|
7
7
|
// Attributes: options (JSON [{value,label,tone?,disabled?}]), value, full,
|
|
8
8
|
// overflow ("scroll" | "wrap": what happens when the options
|
|
9
9
|
// do not fit — without it the row stays one line and runs past
|
|
10
|
-
// the edge), label (aria-label of the group), name (form field)
|
|
11
|
-
//
|
|
10
|
+
// the edge), label (aria-label of the group), name (form field),
|
|
11
|
+
// disabled (the whole row; since 1.22.3, as is a disabled
|
|
12
|
+
// fieldset around it)
|
|
13
|
+
// Properties: value, options (array or JSON text), full, overflow, label,
|
|
14
|
+
// disabled
|
|
12
15
|
// Event: glk-change { value } — only on a change made by the user
|
|
13
16
|
// Part: group
|
|
14
17
|
//
|
|
@@ -61,13 +64,21 @@ class GlkSegmented extends GlkFormElement {
|
|
|
61
64
|
button.classList.add(`glass-segmented__item--${option.tone}`);
|
|
62
65
|
button.appendChild(this.createElement('span', ['glass-segmented__dot']));
|
|
63
66
|
}
|
|
64
|
-
if (option.disabled) button.disabled = true;
|
|
65
67
|
button.appendChild(document.createTextNode(option.label ?? value));
|
|
66
68
|
this._group.appendChild(button);
|
|
67
69
|
}
|
|
70
|
+
this.applyDisabled(this._actuallyDisabled);
|
|
68
71
|
this._syncValue();
|
|
69
72
|
}
|
|
70
73
|
|
|
74
|
+
/** The whole row is disabled, or an option by its own `disabled`. */
|
|
75
|
+
applyDisabled(disabled) {
|
|
76
|
+
const options = this.options;
|
|
77
|
+
this._group.querySelectorAll('button[data-value]').forEach((button, i) => {
|
|
78
|
+
button.disabled = disabled || Boolean(options[i]?.disabled);
|
|
79
|
+
});
|
|
80
|
+
}
|
|
81
|
+
|
|
71
82
|
_syncValue() {
|
|
72
83
|
const value = this.value;
|
|
73
84
|
for (const button of this._group.querySelectorAll('button[data-value]')) {
|
|
@@ -12,7 +12,7 @@ import { GlkFormElement } from '../../base.js';
|
|
|
12
12
|
|
|
13
13
|
class GlkSelect extends GlkFormElement {
|
|
14
14
|
static get observedAttributes() {
|
|
15
|
-
return ['label', '
|
|
15
|
+
return ['label', 'name', 'value', 'required'];
|
|
16
16
|
}
|
|
17
17
|
|
|
18
18
|
static get observesLightDom() { return true; }
|
|
@@ -31,7 +31,6 @@ class GlkSelect extends GlkFormElement {
|
|
|
31
31
|
const name = this.getAttribute('name');
|
|
32
32
|
if (name) this._select.setAttribute('name', name);
|
|
33
33
|
|
|
34
|
-
if (this.getBoolAttr('disabled')) this._select.disabled = true;
|
|
35
34
|
if (this.getBoolAttr('required')) this._select.required = true;
|
|
36
35
|
|
|
37
36
|
group.appendChild(this._labelEl);
|
|
@@ -105,9 +104,6 @@ class GlkSelect extends GlkFormElement {
|
|
|
105
104
|
case 'label':
|
|
106
105
|
this._labelEl.textContent = this.getAttribute('label') || '';
|
|
107
106
|
break;
|
|
108
|
-
case 'disabled':
|
|
109
|
-
this._select.disabled = this.getBoolAttr('disabled');
|
|
110
|
-
break;
|
|
111
107
|
case 'name':
|
|
112
108
|
this._select.setAttribute('name', this.getAttribute('name') || '');
|
|
113
109
|
break;
|
|
@@ -122,6 +118,8 @@ class GlkSelect extends GlkFormElement {
|
|
|
122
118
|
}
|
|
123
119
|
}
|
|
124
120
|
|
|
121
|
+
applyDisabled(disabled) { this._select.disabled = disabled; }
|
|
122
|
+
|
|
125
123
|
get _validityField() { return this._select; }
|
|
126
124
|
|
|
127
125
|
_syncFormValue() {
|
|
@@ -147,9 +145,6 @@ class GlkSelect extends GlkFormElement {
|
|
|
147
145
|
this._applyValue(this._wanted);
|
|
148
146
|
this._syncFormValue();
|
|
149
147
|
}
|
|
150
|
-
|
|
151
|
-
get disabled() { return this.getBoolAttr('disabled'); }
|
|
152
|
-
set disabled(v) { this.setBoolAttr('disabled', v); }
|
|
153
148
|
}
|
|
154
149
|
|
|
155
150
|
customElements.define('glk-select', GlkSelect);
|
|
@@ -2,7 +2,7 @@ import { GlkFormElement } from '../../base.js';
|
|
|
2
2
|
|
|
3
3
|
class GlkTextarea extends GlkFormElement {
|
|
4
4
|
static get observedAttributes() {
|
|
5
|
-
return ['label', 'placeholder', 'rows', '
|
|
5
|
+
return ['label', 'placeholder', 'rows', 'readonly', 'name', 'value', 'required'];
|
|
6
6
|
}
|
|
7
7
|
|
|
8
8
|
render() {
|
|
@@ -27,7 +27,6 @@ class GlkTextarea extends GlkFormElement {
|
|
|
27
27
|
this._pendingValue = undefined;
|
|
28
28
|
if (value) this._textarea.value = value;
|
|
29
29
|
|
|
30
|
-
if (this.getBoolAttr('disabled')) this._textarea.disabled = true;
|
|
31
30
|
if (this.getBoolAttr('readonly')) this._textarea.readOnly = true;
|
|
32
31
|
if (this.getBoolAttr('required')) this._textarea.required = true;
|
|
33
32
|
|
|
@@ -63,9 +62,6 @@ class GlkTextarea extends GlkFormElement {
|
|
|
63
62
|
case 'rows':
|
|
64
63
|
this._textarea.setAttribute('rows', this.getAttribute('rows') || '');
|
|
65
64
|
break;
|
|
66
|
-
case 'disabled':
|
|
67
|
-
this._textarea.disabled = this.getBoolAttr('disabled');
|
|
68
|
-
break;
|
|
69
65
|
case 'readonly':
|
|
70
66
|
this._textarea.readOnly = this.getBoolAttr('readonly');
|
|
71
67
|
break;
|
|
@@ -82,6 +78,8 @@ class GlkTextarea extends GlkFormElement {
|
|
|
82
78
|
}
|
|
83
79
|
}
|
|
84
80
|
|
|
81
|
+
applyDisabled(disabled) { this._textarea.disabled = disabled; }
|
|
82
|
+
|
|
85
83
|
get _validityField() { return this._textarea; }
|
|
86
84
|
|
|
87
85
|
_syncFormValue() {
|
|
@@ -103,9 +101,6 @@ class GlkTextarea extends GlkFormElement {
|
|
|
103
101
|
this._syncFormValue();
|
|
104
102
|
}
|
|
105
103
|
|
|
106
|
-
get disabled() { return this.getBoolAttr('disabled'); }
|
|
107
|
-
set disabled(v) { this.setBoolAttr('disabled', v); }
|
|
108
|
-
|
|
109
104
|
get readOnly() { return this.getBoolAttr('readonly'); }
|
|
110
105
|
set readOnly(v) { this.setBoolAttr('readonly', v); }
|
|
111
106
|
}
|
|
@@ -2,7 +2,7 @@ import { GlkFormElement, checkControlSheet, forwardHostClicks } from '../../base
|
|
|
2
2
|
|
|
3
3
|
class GlkToggle extends GlkFormElement {
|
|
4
4
|
static get observedAttributes() {
|
|
5
|
-
return ['checked', '
|
|
5
|
+
return ['checked', 'label', 'name', 'value', 'required'];
|
|
6
6
|
}
|
|
7
7
|
|
|
8
8
|
static get hostStyles() { return checkControlSheet; }
|
|
@@ -34,7 +34,6 @@ class GlkToggle extends GlkFormElement {
|
|
|
34
34
|
label.appendChild(this._labelEl);
|
|
35
35
|
|
|
36
36
|
if (this.getBoolAttr('checked')) this._input.checked = true;
|
|
37
|
-
if (this.getBoolAttr('disabled')) this._input.disabled = true;
|
|
38
37
|
if (this.getBoolAttr('required')) this._input.required = true;
|
|
39
38
|
|
|
40
39
|
this._defaultChecked = this.getBoolAttr('checked');
|
|
@@ -69,9 +68,6 @@ class GlkToggle extends GlkFormElement {
|
|
|
69
68
|
this._input.checked = this.getBoolAttr('checked');
|
|
70
69
|
this._syncFormValue();
|
|
71
70
|
break;
|
|
72
|
-
case 'disabled':
|
|
73
|
-
this._input.disabled = this.getBoolAttr('disabled');
|
|
74
|
-
break;
|
|
75
71
|
case 'label':
|
|
76
72
|
this._labelEl.textContent = this.getAttribute('label') || '';
|
|
77
73
|
break;
|
|
@@ -84,6 +80,8 @@ class GlkToggle extends GlkFormElement {
|
|
|
84
80
|
}
|
|
85
81
|
}
|
|
86
82
|
|
|
83
|
+
applyDisabled(disabled) { this._input.disabled = disabled; }
|
|
84
|
+
|
|
87
85
|
get _validityField() { return this._input; }
|
|
88
86
|
|
|
89
87
|
_syncFormValue() {
|
|
@@ -112,9 +110,6 @@ class GlkToggle extends GlkFormElement {
|
|
|
112
110
|
if (this._input) this._syncFormValue();
|
|
113
111
|
}
|
|
114
112
|
|
|
115
|
-
get disabled() { return this.getBoolAttr('disabled'); }
|
|
116
|
-
set disabled(v) { this.setBoolAttr('disabled', v); }
|
|
117
|
-
|
|
118
113
|
get name() { return this.getAttribute('name'); }
|
|
119
114
|
set name(v) { this.setAttribute('name', v); }
|
|
120
115
|
|