@jungherz-de/glasskit-elements 0.8.0
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/LICENSE +21 -0
- package/README.md +263 -0
- package/dist/glasskit-elements.esm.js +1789 -0
- package/dist/glasskit-elements.js +1819 -0
- package/dist/glasskit-elements.min.js +1 -0
- package/package.json +43 -0
- package/src/base.js +181 -0
- package/src/components/buttons/glk-button.js +80 -0
- package/src/components/containers/glk-accordion-item.js +61 -0
- package/src/components/containers/glk-accordion.js +12 -0
- package/src/components/content/glk-avatar.js +58 -0
- package/src/components/content/glk-badge.js +37 -0
- package/src/components/content/glk-card.js +33 -0
- package/src/components/content/glk-divider.js +11 -0
- package/src/components/content/glk-status.js +35 -0
- package/src/components/content/glk-title.js +16 -0
- package/src/components/feedback/glk-modal.js +98 -0
- package/src/components/feedback/glk-progress.js +77 -0
- package/src/components/feedback/glk-toast.js +104 -0
- package/src/components/forms/glk-checkbox.js +103 -0
- package/src/components/forms/glk-input.js +138 -0
- package/src/components/forms/glk-radio.js +109 -0
- package/src/components/forms/glk-range.js +112 -0
- package/src/components/forms/glk-search.js +87 -0
- package/src/components/forms/glk-select.js +96 -0
- package/src/components/forms/glk-textarea.js +95 -0
- package/src/components/forms/glk-toggle.js +121 -0
- package/src/components/navigation/glk-nav.js +12 -0
- package/src/components/navigation/glk-pill.js +48 -0
- package/src/components/navigation/glk-tab-bar.js +31 -0
- package/src/components/navigation/glk-tab-item.js +74 -0
- package/src/index.js +38 -0
|
@@ -0,0 +1,33 @@
|
|
|
1
|
+
import { GlkElement } from '../../base.js';
|
|
2
|
+
|
|
3
|
+
class GlkCard extends GlkElement {
|
|
4
|
+
static get observedAttributes() {
|
|
5
|
+
return ['glow'];
|
|
6
|
+
}
|
|
7
|
+
|
|
8
|
+
render() {
|
|
9
|
+
this._card = this.createElement('div', this._computeClasses());
|
|
10
|
+
this._card.appendChild(document.createElement('slot'));
|
|
11
|
+
this._wrapper.appendChild(this._card);
|
|
12
|
+
}
|
|
13
|
+
|
|
14
|
+
onAttributeChanged(name) {
|
|
15
|
+
if (name === 'glow' && this._card) {
|
|
16
|
+
this._card.className = this._computeClasses().join(' ');
|
|
17
|
+
}
|
|
18
|
+
}
|
|
19
|
+
|
|
20
|
+
_computeClasses() {
|
|
21
|
+
const classes = ['glass-card'];
|
|
22
|
+
if (this.getBoolAttr('glow')) {
|
|
23
|
+
classes.push('glass-card--glow');
|
|
24
|
+
}
|
|
25
|
+
return classes;
|
|
26
|
+
}
|
|
27
|
+
|
|
28
|
+
get glow() { return this.getBoolAttr('glow'); }
|
|
29
|
+
set glow(v) { this.setBoolAttr('glow', v); }
|
|
30
|
+
}
|
|
31
|
+
|
|
32
|
+
customElements.define('glk-card', GlkCard);
|
|
33
|
+
export { GlkCard };
|
|
@@ -0,0 +1,11 @@
|
|
|
1
|
+
import { GlkElement } from '../../base.js';
|
|
2
|
+
|
|
3
|
+
class GlkDivider extends GlkElement {
|
|
4
|
+
render() {
|
|
5
|
+
const hr = this.createElement('div', ['glass-divider']);
|
|
6
|
+
this._wrapper.appendChild(hr);
|
|
7
|
+
}
|
|
8
|
+
}
|
|
9
|
+
|
|
10
|
+
customElements.define('glk-divider', GlkDivider);
|
|
11
|
+
export { GlkDivider };
|
|
@@ -0,0 +1,35 @@
|
|
|
1
|
+
import { GlkElement } from '../../base.js';
|
|
2
|
+
|
|
3
|
+
class GlkStatus extends GlkElement {
|
|
4
|
+
static get observedAttributes() {
|
|
5
|
+
return ['message'];
|
|
6
|
+
}
|
|
7
|
+
|
|
8
|
+
render() {
|
|
9
|
+
this._container = this.createElement('div', ['glass-status']);
|
|
10
|
+
|
|
11
|
+
// Icon via slot
|
|
12
|
+
this._iconSlot = this.createElement('span', []);
|
|
13
|
+
this._iconSlot.appendChild(this.createElement('slot', [], { name: 'icon' }));
|
|
14
|
+
|
|
15
|
+
// Message
|
|
16
|
+
this._messageEl = this.createElement('p', []);
|
|
17
|
+
this._messageEl.textContent = this.getAttribute('message') || '';
|
|
18
|
+
|
|
19
|
+
this._container.appendChild(this._iconSlot);
|
|
20
|
+
this._container.appendChild(this._messageEl);
|
|
21
|
+
this._wrapper.appendChild(this._container);
|
|
22
|
+
}
|
|
23
|
+
|
|
24
|
+
onAttributeChanged(name) {
|
|
25
|
+
if (name === 'message' && this._messageEl) {
|
|
26
|
+
this._messageEl.textContent = this.getAttribute('message') || '';
|
|
27
|
+
}
|
|
28
|
+
}
|
|
29
|
+
|
|
30
|
+
get message() { return this.getAttribute('message'); }
|
|
31
|
+
set message(v) { this.setAttribute('message', v); }
|
|
32
|
+
}
|
|
33
|
+
|
|
34
|
+
customElements.define('glk-status', GlkStatus);
|
|
35
|
+
export { GlkStatus };
|
|
@@ -0,0 +1,16 @@
|
|
|
1
|
+
import { GlkElement } from '../../base.js';
|
|
2
|
+
|
|
3
|
+
class GlkTitle extends GlkElement {
|
|
4
|
+
static get observedAttributes() {
|
|
5
|
+
return [];
|
|
6
|
+
}
|
|
7
|
+
|
|
8
|
+
render() {
|
|
9
|
+
const el = this.createElement('div', ['glass-title']);
|
|
10
|
+
el.appendChild(document.createElement('slot'));
|
|
11
|
+
this._wrapper.appendChild(el);
|
|
12
|
+
}
|
|
13
|
+
}
|
|
14
|
+
|
|
15
|
+
customElements.define('glk-title', GlkTitle);
|
|
16
|
+
export { GlkTitle };
|
|
@@ -0,0 +1,98 @@
|
|
|
1
|
+
import { GlkElement } from '../../base.js';
|
|
2
|
+
|
|
3
|
+
class GlkModal extends GlkElement {
|
|
4
|
+
static get observedAttributes() {
|
|
5
|
+
return ['open', 'title'];
|
|
6
|
+
}
|
|
7
|
+
|
|
8
|
+
render() {
|
|
9
|
+
this._overlay = this.createElement('div', ['glass-modal-overlay']);
|
|
10
|
+
|
|
11
|
+
const modal = this.createElement('div', ['glass-modal']);
|
|
12
|
+
|
|
13
|
+
// Header
|
|
14
|
+
const header = this.createElement('div', ['glass-modal__header']);
|
|
15
|
+
this._titleEl = this.createElement('h2', ['glass-modal__title']);
|
|
16
|
+
this._titleEl.textContent = this.getAttribute('title') || '';
|
|
17
|
+
header.appendChild(this._titleEl);
|
|
18
|
+
|
|
19
|
+
// Body
|
|
20
|
+
const body = this.createElement('div', ['glass-modal__body']);
|
|
21
|
+
body.appendChild(document.createElement('slot'));
|
|
22
|
+
|
|
23
|
+
// Footer — clone action buttons from light DOM into shadow DOM
|
|
24
|
+
this._footer = this.createElement('div', ['glass-modal__footer']);
|
|
25
|
+
this._populateFooter();
|
|
26
|
+
|
|
27
|
+
modal.appendChild(header);
|
|
28
|
+
modal.appendChild(body);
|
|
29
|
+
modal.appendChild(this._footer);
|
|
30
|
+
|
|
31
|
+
this._overlay.appendChild(modal);
|
|
32
|
+
this._wrapper.appendChild(this._overlay);
|
|
33
|
+
|
|
34
|
+
if (this.getBoolAttr('open')) {
|
|
35
|
+
this._overlay.classList.add('is-active');
|
|
36
|
+
}
|
|
37
|
+
}
|
|
38
|
+
|
|
39
|
+
_populateFooter() {
|
|
40
|
+
this._footer.innerHTML = '';
|
|
41
|
+
const actionsSlot = this.querySelector('[slot="actions"]');
|
|
42
|
+
if (actionsSlot) {
|
|
43
|
+
const buttons = actionsSlot.querySelectorAll('button');
|
|
44
|
+
buttons.forEach(btn => {
|
|
45
|
+
const clone = btn.cloneNode(true);
|
|
46
|
+
// Forward click events to the original button
|
|
47
|
+
clone.addEventListener('click', () => btn.click());
|
|
48
|
+
this._footer.appendChild(clone);
|
|
49
|
+
});
|
|
50
|
+
}
|
|
51
|
+
}
|
|
52
|
+
|
|
53
|
+
setupEvents() {
|
|
54
|
+
// Close on overlay click (outside modal)
|
|
55
|
+
this._onOverlayClick = (e) => {
|
|
56
|
+
if (e.target === this._overlay) {
|
|
57
|
+
this.removeAttribute('open');
|
|
58
|
+
this.emit('glk-close');
|
|
59
|
+
}
|
|
60
|
+
};
|
|
61
|
+
this._overlay.addEventListener('click', this._onOverlayClick);
|
|
62
|
+
|
|
63
|
+
// Close on Escape
|
|
64
|
+
this._onKeydown = (e) => {
|
|
65
|
+
if (e.key === 'Escape' && this.getBoolAttr('open')) {
|
|
66
|
+
this.removeAttribute('open');
|
|
67
|
+
this.emit('glk-close');
|
|
68
|
+
}
|
|
69
|
+
};
|
|
70
|
+
document.addEventListener('keydown', this._onKeydown);
|
|
71
|
+
}
|
|
72
|
+
|
|
73
|
+
teardownEvents() {
|
|
74
|
+
this._overlay?.removeEventListener('click', this._onOverlayClick);
|
|
75
|
+
document.removeEventListener('keydown', this._onKeydown);
|
|
76
|
+
}
|
|
77
|
+
|
|
78
|
+
onAttributeChanged(name) {
|
|
79
|
+
if (!this._overlay) return;
|
|
80
|
+
switch (name) {
|
|
81
|
+
case 'open':
|
|
82
|
+
this._overlay.classList.toggle('is-active', this.getBoolAttr('open'));
|
|
83
|
+
break;
|
|
84
|
+
case 'title':
|
|
85
|
+
this._titleEl.textContent = this.getAttribute('title') || '';
|
|
86
|
+
break;
|
|
87
|
+
}
|
|
88
|
+
}
|
|
89
|
+
|
|
90
|
+
show() { this.setAttribute('open', ''); }
|
|
91
|
+
close() { this.removeAttribute('open'); }
|
|
92
|
+
|
|
93
|
+
get open() { return this.getBoolAttr('open'); }
|
|
94
|
+
set open(v) { this.setBoolAttr('open', v); }
|
|
95
|
+
}
|
|
96
|
+
|
|
97
|
+
customElements.define('glk-modal', GlkModal);
|
|
98
|
+
export { GlkModal };
|
|
@@ -0,0 +1,77 @@
|
|
|
1
|
+
import { GlkElement } from '../../base.js';
|
|
2
|
+
|
|
3
|
+
const VARIANTS = ['success', 'error'];
|
|
4
|
+
const SIZES = ['sm', 'lg'];
|
|
5
|
+
|
|
6
|
+
class GlkProgress extends GlkElement {
|
|
7
|
+
static get observedAttributes() {
|
|
8
|
+
return ['value', 'label', 'variant', 'size'];
|
|
9
|
+
}
|
|
10
|
+
|
|
11
|
+
render() {
|
|
12
|
+
this._container = this.createElement('div', this._computeClasses());
|
|
13
|
+
|
|
14
|
+
// Header
|
|
15
|
+
const header = this.createElement('div', ['glass-progress__header']);
|
|
16
|
+
this._labelEl = this.createElement('span', ['glass-progress__label']);
|
|
17
|
+
this._labelEl.textContent = this.getAttribute('label') || '';
|
|
18
|
+
this._valueEl = this.createElement('span', ['glass-progress__value']);
|
|
19
|
+
|
|
20
|
+
header.appendChild(this._labelEl);
|
|
21
|
+
header.appendChild(this._valueEl);
|
|
22
|
+
|
|
23
|
+
// Track
|
|
24
|
+
const track = this.createElement('div', ['glass-progress__track']);
|
|
25
|
+
this._fill = this.createElement('div', ['glass-progress__fill']);
|
|
26
|
+
|
|
27
|
+
track.appendChild(this._fill);
|
|
28
|
+
|
|
29
|
+
this._container.appendChild(header);
|
|
30
|
+
this._container.appendChild(track);
|
|
31
|
+
|
|
32
|
+
this._updateValue();
|
|
33
|
+
|
|
34
|
+
this._wrapper.appendChild(this._container);
|
|
35
|
+
}
|
|
36
|
+
|
|
37
|
+
onAttributeChanged(name) {
|
|
38
|
+
if (!this._container) return;
|
|
39
|
+
switch (name) {
|
|
40
|
+
case 'value':
|
|
41
|
+
this._updateValue();
|
|
42
|
+
break;
|
|
43
|
+
case 'label':
|
|
44
|
+
this._labelEl.textContent = this.getAttribute('label') || '';
|
|
45
|
+
break;
|
|
46
|
+
case 'variant':
|
|
47
|
+
case 'size':
|
|
48
|
+
this._container.className = this._computeClasses().join(' ');
|
|
49
|
+
break;
|
|
50
|
+
}
|
|
51
|
+
}
|
|
52
|
+
|
|
53
|
+
_updateValue() {
|
|
54
|
+
const val = Math.min(100, Math.max(0, parseInt(this.getAttribute('value') || '0', 10)));
|
|
55
|
+
this._fill.style.width = `${val}%`;
|
|
56
|
+
this._valueEl.textContent = `${val}%`;
|
|
57
|
+
}
|
|
58
|
+
|
|
59
|
+
_computeClasses() {
|
|
60
|
+
const classes = ['glass-progress'];
|
|
61
|
+
const variant = this.getAttribute('variant');
|
|
62
|
+
if (variant && VARIANTS.includes(variant)) {
|
|
63
|
+
classes.push(`glass-progress--${variant}`);
|
|
64
|
+
}
|
|
65
|
+
const size = this.getAttribute('size');
|
|
66
|
+
if (size && SIZES.includes(size)) {
|
|
67
|
+
classes.push(`glass-progress--${size}`);
|
|
68
|
+
}
|
|
69
|
+
return classes;
|
|
70
|
+
}
|
|
71
|
+
|
|
72
|
+
get value() { return this.getAttribute('value'); }
|
|
73
|
+
set value(v) { this.setAttribute('value', String(v)); }
|
|
74
|
+
}
|
|
75
|
+
|
|
76
|
+
customElements.define('glk-progress', GlkProgress);
|
|
77
|
+
export { GlkProgress };
|
|
@@ -0,0 +1,104 @@
|
|
|
1
|
+
import { GlkElement } from '../../base.js';
|
|
2
|
+
|
|
3
|
+
const VARIANTS = ['success', 'error', 'warning'];
|
|
4
|
+
|
|
5
|
+
const ICONS = {
|
|
6
|
+
success: `<svg viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2" stroke-linecap="round"><path d="M22 11.08V12a10 10 0 1 1-5.93-9.14"/><polyline points="22 4 12 14.01 9 11.01"/></svg>`,
|
|
7
|
+
error: `<svg viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2" stroke-linecap="round"><circle cx="12" cy="12" r="10"/><line x1="15" y1="9" x2="9" y2="15"/><line x1="9" y1="9" x2="15" y2="15"/></svg>`,
|
|
8
|
+
warning: `<svg viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2" stroke-linecap="round"><path d="M10.29 3.86L1.82 18a2 2 0 0 0 1.71 3h16.94a2 2 0 0 0 1.71-3L13.71 3.86a2 2 0 0 0-3.42 0z"/><line x1="12" y1="9" x2="12" y2="13"/><line x1="12" y1="17" x2="12.01" y2="17"/></svg>`
|
|
9
|
+
};
|
|
10
|
+
|
|
11
|
+
class GlkToast extends GlkElement {
|
|
12
|
+
static get observedAttributes() {
|
|
13
|
+
return ['message', 'variant', 'duration', 'visible'];
|
|
14
|
+
}
|
|
15
|
+
|
|
16
|
+
render() {
|
|
17
|
+
this._toast = this.createElement('div', this._computeClasses());
|
|
18
|
+
|
|
19
|
+
this._iconEl = this.createElement('span', ['glass-toast__icon']);
|
|
20
|
+
this._textEl = this.createElement('span', ['glass-toast__text']);
|
|
21
|
+
this._textEl.textContent = this.getAttribute('message') || '';
|
|
22
|
+
|
|
23
|
+
this._updateIcon();
|
|
24
|
+
|
|
25
|
+
this._toast.appendChild(this._iconEl);
|
|
26
|
+
this._toast.appendChild(this._textEl);
|
|
27
|
+
this._wrapper.appendChild(this._toast);
|
|
28
|
+
|
|
29
|
+
if (this.getBoolAttr('visible')) {
|
|
30
|
+
this._show();
|
|
31
|
+
}
|
|
32
|
+
}
|
|
33
|
+
|
|
34
|
+
onAttributeChanged(name) {
|
|
35
|
+
if (!this._toast) return;
|
|
36
|
+
switch (name) {
|
|
37
|
+
case 'message':
|
|
38
|
+
this._textEl.textContent = this.getAttribute('message') || '';
|
|
39
|
+
break;
|
|
40
|
+
case 'variant':
|
|
41
|
+
this._toast.className = this._computeClasses().join(' ');
|
|
42
|
+
this._updateIcon();
|
|
43
|
+
break;
|
|
44
|
+
case 'visible':
|
|
45
|
+
if (this.getBoolAttr('visible')) {
|
|
46
|
+
this._show();
|
|
47
|
+
} else {
|
|
48
|
+
this._hide();
|
|
49
|
+
}
|
|
50
|
+
break;
|
|
51
|
+
}
|
|
52
|
+
}
|
|
53
|
+
|
|
54
|
+
_computeClasses() {
|
|
55
|
+
const classes = ['glass-toast'];
|
|
56
|
+
const variant = this.getAttribute('variant');
|
|
57
|
+
if (variant && VARIANTS.includes(variant)) {
|
|
58
|
+
classes.push(`glass-toast--${variant}`);
|
|
59
|
+
}
|
|
60
|
+
return classes;
|
|
61
|
+
}
|
|
62
|
+
|
|
63
|
+
_updateIcon() {
|
|
64
|
+
const variant = this.getAttribute('variant');
|
|
65
|
+
this._iconEl.innerHTML = ICONS[variant] || ICONS.success;
|
|
66
|
+
}
|
|
67
|
+
|
|
68
|
+
_show() {
|
|
69
|
+
this._toast.classList.add('is-visible');
|
|
70
|
+
const duration = parseInt(this.getAttribute('duration') || '3000', 10);
|
|
71
|
+
if (duration > 0) {
|
|
72
|
+
clearTimeout(this._timer);
|
|
73
|
+
this._timer = setTimeout(() => {
|
|
74
|
+
this.removeAttribute('visible');
|
|
75
|
+
this.emit('glk-dismiss');
|
|
76
|
+
}, duration);
|
|
77
|
+
}
|
|
78
|
+
}
|
|
79
|
+
|
|
80
|
+
_hide() {
|
|
81
|
+
this._toast.classList.remove('is-visible');
|
|
82
|
+
clearTimeout(this._timer);
|
|
83
|
+
}
|
|
84
|
+
|
|
85
|
+
/** Programmatic show */
|
|
86
|
+
show(message, variant, duration) {
|
|
87
|
+
if (message) this.setAttribute('message', message);
|
|
88
|
+
if (variant) this.setAttribute('variant', variant);
|
|
89
|
+
if (duration) this.setAttribute('duration', String(duration));
|
|
90
|
+
this.setAttribute('visible', '');
|
|
91
|
+
}
|
|
92
|
+
|
|
93
|
+
dismiss() {
|
|
94
|
+
this.removeAttribute('visible');
|
|
95
|
+
}
|
|
96
|
+
|
|
97
|
+
disconnectedCallback() {
|
|
98
|
+
super.disconnectedCallback();
|
|
99
|
+
clearTimeout(this._timer);
|
|
100
|
+
}
|
|
101
|
+
}
|
|
102
|
+
|
|
103
|
+
customElements.define('glk-toast', GlkToast);
|
|
104
|
+
export { GlkToast };
|
|
@@ -0,0 +1,103 @@
|
|
|
1
|
+
import { GlkFormElement } from '../../base.js';
|
|
2
|
+
|
|
3
|
+
const CHECKMARK_SVG = `<svg viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="3" stroke-linecap="round" stroke-linejoin="round"><polyline points="20 6 9 17 4 12"/></svg>`;
|
|
4
|
+
|
|
5
|
+
class GlkCheckbox extends GlkFormElement {
|
|
6
|
+
static get observedAttributes() {
|
|
7
|
+
return ['checked', 'disabled', 'label', 'name', 'value'];
|
|
8
|
+
}
|
|
9
|
+
|
|
10
|
+
render() {
|
|
11
|
+
const label = this.createElement('label', ['glass-checkbox']);
|
|
12
|
+
|
|
13
|
+
this._input = this.createElement('input', ['glass-checkbox__input'], {
|
|
14
|
+
type: 'checkbox'
|
|
15
|
+
});
|
|
16
|
+
|
|
17
|
+
const name = this.getAttribute('name');
|
|
18
|
+
if (name) this._input.setAttribute('name', name);
|
|
19
|
+
|
|
20
|
+
const box = this.createElement('span', ['glass-checkbox__box']);
|
|
21
|
+
box.innerHTML = CHECKMARK_SVG;
|
|
22
|
+
|
|
23
|
+
this._labelEl = this.createElement('span', ['glass-checkbox__label']);
|
|
24
|
+
this._labelEl.textContent = this.getAttribute('label') || '';
|
|
25
|
+
|
|
26
|
+
label.appendChild(this._input);
|
|
27
|
+
label.appendChild(box);
|
|
28
|
+
label.appendChild(this._labelEl);
|
|
29
|
+
|
|
30
|
+
if (this.getBoolAttr('checked')) this._input.checked = true;
|
|
31
|
+
if (this.getBoolAttr('disabled')) this._input.disabled = true;
|
|
32
|
+
|
|
33
|
+
this._defaultChecked = this.getBoolAttr('checked');
|
|
34
|
+
this._wrapper.appendChild(label);
|
|
35
|
+
this._syncFormValue();
|
|
36
|
+
}
|
|
37
|
+
|
|
38
|
+
setupEvents() {
|
|
39
|
+
this._onChange = () => {
|
|
40
|
+
this._syncing = true;
|
|
41
|
+
this.setBoolAttr('checked', this._input.checked);
|
|
42
|
+
this._syncing = false;
|
|
43
|
+
this._syncFormValue();
|
|
44
|
+
this.emit('glk-change', { checked: this._input.checked });
|
|
45
|
+
this.dispatchEvent(new Event('change', { bubbles: true }));
|
|
46
|
+
};
|
|
47
|
+
this._input.addEventListener('change', this._onChange);
|
|
48
|
+
}
|
|
49
|
+
|
|
50
|
+
teardownEvents() {
|
|
51
|
+
this._input?.removeEventListener('change', this._onChange);
|
|
52
|
+
}
|
|
53
|
+
|
|
54
|
+
onAttributeChanged(name) {
|
|
55
|
+
if (this._syncing) return;
|
|
56
|
+
if (!this._input) return;
|
|
57
|
+
switch (name) {
|
|
58
|
+
case 'checked':
|
|
59
|
+
this._input.checked = this.getBoolAttr('checked');
|
|
60
|
+
this._syncFormValue();
|
|
61
|
+
break;
|
|
62
|
+
case 'disabled':
|
|
63
|
+
this._input.disabled = this.getBoolAttr('disabled');
|
|
64
|
+
break;
|
|
65
|
+
case 'label':
|
|
66
|
+
this._labelEl.textContent = this.getAttribute('label') || '';
|
|
67
|
+
break;
|
|
68
|
+
case 'name':
|
|
69
|
+
this._input.setAttribute('name', this.getAttribute('name') || '');
|
|
70
|
+
break;
|
|
71
|
+
}
|
|
72
|
+
}
|
|
73
|
+
|
|
74
|
+
_syncFormValue() {
|
|
75
|
+
const val = this.getAttribute('value') || 'on';
|
|
76
|
+
this.setFormValue(this._input.checked ? val : null);
|
|
77
|
+
}
|
|
78
|
+
|
|
79
|
+
resetValue() {
|
|
80
|
+
this._input.checked = this._defaultChecked;
|
|
81
|
+
this.setBoolAttr('checked', this._defaultChecked);
|
|
82
|
+
this._syncFormValue();
|
|
83
|
+
}
|
|
84
|
+
|
|
85
|
+
get checked() { return this._input?.checked ?? false; }
|
|
86
|
+
set checked(v) {
|
|
87
|
+
if (this._input) this._input.checked = v;
|
|
88
|
+
this.setBoolAttr('checked', v);
|
|
89
|
+
this._syncFormValue();
|
|
90
|
+
}
|
|
91
|
+
|
|
92
|
+
get disabled() { return this.getBoolAttr('disabled'); }
|
|
93
|
+
set disabled(v) { this.setBoolAttr('disabled', v); }
|
|
94
|
+
|
|
95
|
+
get name() { return this.getAttribute('name'); }
|
|
96
|
+
set name(v) { this.setAttribute('name', v); }
|
|
97
|
+
|
|
98
|
+
get value() { return this.getAttribute('value') || 'on'; }
|
|
99
|
+
set value(v) { this.setAttribute('value', v); }
|
|
100
|
+
}
|
|
101
|
+
|
|
102
|
+
customElements.define('glk-checkbox', GlkCheckbox);
|
|
103
|
+
export { GlkCheckbox };
|
|
@@ -0,0 +1,138 @@
|
|
|
1
|
+
import { GlkFormElement } from '../../base.js';
|
|
2
|
+
|
|
3
|
+
class GlkInput extends GlkFormElement {
|
|
4
|
+
static get observedAttributes() {
|
|
5
|
+
return ['label', 'type', 'placeholder', 'error', 'hint', 'disabled', 'name', 'value', 'required'];
|
|
6
|
+
}
|
|
7
|
+
|
|
8
|
+
render() {
|
|
9
|
+
const group = this.createElement('div', ['glass-input-group']);
|
|
10
|
+
|
|
11
|
+
// Label
|
|
12
|
+
this._labelEl = this.createElement('label', ['glass-label']);
|
|
13
|
+
this._labelEl.textContent = this.getAttribute('label') || '';
|
|
14
|
+
|
|
15
|
+
// Input
|
|
16
|
+
this._input = this.createElement('input', this._computeInputClasses(), {
|
|
17
|
+
type: this.getAttribute('type') || 'text'
|
|
18
|
+
});
|
|
19
|
+
|
|
20
|
+
const placeholder = this.getAttribute('placeholder');
|
|
21
|
+
if (placeholder) this._input.setAttribute('placeholder', placeholder);
|
|
22
|
+
|
|
23
|
+
const name = this.getAttribute('name');
|
|
24
|
+
if (name) this._input.setAttribute('name', name);
|
|
25
|
+
|
|
26
|
+
const value = this.getAttribute('value');
|
|
27
|
+
if (value) this._input.value = value;
|
|
28
|
+
|
|
29
|
+
if (this.getBoolAttr('disabled')) this._input.disabled = true;
|
|
30
|
+
if (this.getBoolAttr('required')) this._input.required = true;
|
|
31
|
+
|
|
32
|
+
// Hint
|
|
33
|
+
this._hintEl = this.createElement('span', this._computeHintClasses());
|
|
34
|
+
this._hintEl.textContent = this.getAttribute('hint') || '';
|
|
35
|
+
|
|
36
|
+
group.appendChild(this._labelEl);
|
|
37
|
+
group.appendChild(this._input);
|
|
38
|
+
if (this.getAttribute('hint')) group.appendChild(this._hintEl);
|
|
39
|
+
|
|
40
|
+
this._group = group;
|
|
41
|
+
this._wrapper.appendChild(group);
|
|
42
|
+
|
|
43
|
+
this._syncFormValue();
|
|
44
|
+
}
|
|
45
|
+
|
|
46
|
+
setupEvents() {
|
|
47
|
+
this._onInput = () => {
|
|
48
|
+
this._syncFormValue();
|
|
49
|
+
this.emit('glk-input', { value: this._input.value });
|
|
50
|
+
this.dispatchEvent(new Event('input', { bubbles: true }));
|
|
51
|
+
};
|
|
52
|
+
this._onChangeNative = () => {
|
|
53
|
+
this.emit('glk-change', { value: this._input.value });
|
|
54
|
+
this.dispatchEvent(new Event('change', { bubbles: true }));
|
|
55
|
+
};
|
|
56
|
+
this._input.addEventListener('input', this._onInput);
|
|
57
|
+
this._input.addEventListener('change', this._onChangeNative);
|
|
58
|
+
}
|
|
59
|
+
|
|
60
|
+
teardownEvents() {
|
|
61
|
+
this._input?.removeEventListener('input', this._onInput);
|
|
62
|
+
this._input?.removeEventListener('change', this._onChangeNative);
|
|
63
|
+
}
|
|
64
|
+
|
|
65
|
+
onAttributeChanged(name) {
|
|
66
|
+
if (!this._input) return;
|
|
67
|
+
switch (name) {
|
|
68
|
+
case 'label':
|
|
69
|
+
this._labelEl.textContent = this.getAttribute('label') || '';
|
|
70
|
+
break;
|
|
71
|
+
case 'type':
|
|
72
|
+
this._input.setAttribute('type', this.getAttribute('type') || 'text');
|
|
73
|
+
break;
|
|
74
|
+
case 'placeholder':
|
|
75
|
+
this._input.setAttribute('placeholder', this.getAttribute('placeholder') || '');
|
|
76
|
+
break;
|
|
77
|
+
case 'error':
|
|
78
|
+
this._input.className = this._computeInputClasses().join(' ');
|
|
79
|
+
this._hintEl.className = this._computeHintClasses().join(' ');
|
|
80
|
+
break;
|
|
81
|
+
case 'hint':
|
|
82
|
+
this._hintEl.textContent = this.getAttribute('hint') || '';
|
|
83
|
+
if (this.getAttribute('hint') && !this._hintEl.parentNode) {
|
|
84
|
+
this._group.appendChild(this._hintEl);
|
|
85
|
+
}
|
|
86
|
+
break;
|
|
87
|
+
case 'disabled':
|
|
88
|
+
this._input.disabled = this.getBoolAttr('disabled');
|
|
89
|
+
break;
|
|
90
|
+
case 'name':
|
|
91
|
+
this._input.setAttribute('name', this.getAttribute('name') || '');
|
|
92
|
+
break;
|
|
93
|
+
case 'value':
|
|
94
|
+
this._input.value = this.getAttribute('value') || '';
|
|
95
|
+
this._syncFormValue();
|
|
96
|
+
break;
|
|
97
|
+
case 'required':
|
|
98
|
+
this._input.required = this.getBoolAttr('required');
|
|
99
|
+
break;
|
|
100
|
+
}
|
|
101
|
+
}
|
|
102
|
+
|
|
103
|
+
_computeInputClasses() {
|
|
104
|
+
const classes = ['glass-input'];
|
|
105
|
+
if (this.getBoolAttr('error')) classes.push('glass-input--error');
|
|
106
|
+
return classes;
|
|
107
|
+
}
|
|
108
|
+
|
|
109
|
+
_computeHintClasses() {
|
|
110
|
+
const classes = ['glass-hint'];
|
|
111
|
+
if (this.getBoolAttr('error')) classes.push('glass-hint--error');
|
|
112
|
+
return classes;
|
|
113
|
+
}
|
|
114
|
+
|
|
115
|
+
_syncFormValue() {
|
|
116
|
+
this.setFormValue(this._input.value);
|
|
117
|
+
}
|
|
118
|
+
|
|
119
|
+
resetValue() {
|
|
120
|
+
this._input.value = this.getAttribute('value') || '';
|
|
121
|
+
this._syncFormValue();
|
|
122
|
+
}
|
|
123
|
+
|
|
124
|
+
get value() { return this._input?.value ?? ''; }
|
|
125
|
+
set value(v) {
|
|
126
|
+
if (this._input) this._input.value = v;
|
|
127
|
+
this._syncFormValue();
|
|
128
|
+
}
|
|
129
|
+
|
|
130
|
+
get disabled() { return this.getBoolAttr('disabled'); }
|
|
131
|
+
set disabled(v) { this.setBoolAttr('disabled', v); }
|
|
132
|
+
|
|
133
|
+
get name() { return this.getAttribute('name'); }
|
|
134
|
+
set name(v) { this.setAttribute('name', v); }
|
|
135
|
+
}
|
|
136
|
+
|
|
137
|
+
customElements.define('glk-input', GlkInput);
|
|
138
|
+
export { GlkInput };
|