@jungherz-de/glasskit-elements 1.6.2 → 1.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/dist/components/glk-accordion-item.js +62 -0
- package/dist/components/glk-accordion.js +13 -0
- package/dist/components/glk-avatar.js +59 -0
- package/dist/components/glk-badge.js +38 -0
- package/dist/components/glk-button.js +81 -0
- package/dist/components/glk-card.js +51 -0
- package/dist/components/glk-checkbox.js +104 -0
- package/dist/components/glk-divider.js +12 -0
- package/dist/components/glk-input.js +139 -0
- package/dist/components/glk-list-item.js +188 -0
- package/dist/components/glk-list.js +75 -0
- package/dist/components/glk-modal.js +101 -0
- package/dist/components/glk-nav.js +13 -0
- package/dist/components/glk-pill.js +49 -0
- package/dist/components/glk-popover.js +109 -0
- package/dist/components/glk-progress.js +78 -0
- package/dist/components/glk-radio.js +110 -0
- package/dist/components/glk-range.js +113 -0
- package/dist/components/glk-search.js +88 -0
- package/dist/components/glk-select.js +97 -0
- package/dist/components/glk-status.js +36 -0
- package/dist/components/glk-tab-accessory.js +66 -0
- package/dist/components/glk-tab-bar.js +59 -0
- package/dist/components/glk-tab-dock.js +52 -0
- package/dist/components/glk-tab-item.js +93 -0
- package/dist/components/glk-textarea.js +96 -0
- package/dist/components/glk-title.js +17 -0
- package/dist/components/glk-toast.js +105 -0
- package/dist/components/glk-toggle.js +122 -0
- package/dist/components/shared/base-Bm9Z714o.js +199 -0
- package/dist/glasskit-elements.esm.js +39 -12
- package/dist/glasskit-elements.js +39 -12
- package/dist/glasskit-elements.min.js +1 -1
- package/package.json +7 -4
- package/src/base.js +11 -1
- package/src/components/containers/glk-list.js +2 -2
- package/src/components/content/glk-card.js +19 -2
- package/src/components/feedback/glk-modal.js +5 -5
|
@@ -0,0 +1,188 @@
|
|
|
1
|
+
import { G as GlkElement } from './shared/base-Bm9Z714o.js';
|
|
2
|
+
|
|
3
|
+
// Module-level override sheet — shared by all instances.
|
|
4
|
+
// Suppresses the auto-divider when glk-list marks this item as the
|
|
5
|
+
// last-of-type via [data-last]. The default divider is rendered by
|
|
6
|
+
// glasskit.css thanks to the sentinel sibling in the shadow tree.
|
|
7
|
+
const lastChildOverrideSheet = new CSSStyleSheet();
|
|
8
|
+
lastChildOverrideSheet.replaceSync(`
|
|
9
|
+
:host([data-last]) .glass-list__item::after { content: none; }
|
|
10
|
+
`);
|
|
11
|
+
|
|
12
|
+
const VARIANTS = ['danger', 'accent'];
|
|
13
|
+
|
|
14
|
+
class GlkListItem extends GlkElement {
|
|
15
|
+
static get observedAttributes() {
|
|
16
|
+
return ['title', 'subtitle', 'interactive', 'center', 'leading-lg', 'wrap', 'detail', 'variant', 'data-last'];
|
|
17
|
+
}
|
|
18
|
+
|
|
19
|
+
constructor() {
|
|
20
|
+
super();
|
|
21
|
+
this._shadow.adoptedStyleSheets = [
|
|
22
|
+
...this._shadow.adoptedStyleSheets,
|
|
23
|
+
lastChildOverrideSheet
|
|
24
|
+
];
|
|
25
|
+
}
|
|
26
|
+
|
|
27
|
+
render() {
|
|
28
|
+
// display:contents wrapper — transparent to layout.
|
|
29
|
+
const wrap = this.createElement('div');
|
|
30
|
+
wrap.style.display = 'contents';
|
|
31
|
+
|
|
32
|
+
this._item = this.createElement('li', ['glass-list__item']);
|
|
33
|
+
if (this.getBoolAttr('interactive')) this._item.classList.add('glass-list__item--interactive');
|
|
34
|
+
if (this.getBoolAttr('center')) this._item.classList.add('glass-list__item--center');
|
|
35
|
+
const initialVariant = this.getAttribute('variant');
|
|
36
|
+
if (initialVariant && VARIANTS.includes(initialVariant)) {
|
|
37
|
+
this._item.classList.add(`glass-list__item--${initialVariant}`);
|
|
38
|
+
}
|
|
39
|
+
|
|
40
|
+
// Leading slot — hidden until a child with slot="leading" appears.
|
|
41
|
+
this._leading = this.createElement('span', ['glass-list__leading']);
|
|
42
|
+
if (this.getBoolAttr('leading-lg')) this._leading.classList.add('glass-list__leading--lg');
|
|
43
|
+
this._leadingSlot = document.createElement('slot');
|
|
44
|
+
this._leadingSlot.setAttribute('name', 'leading');
|
|
45
|
+
this._leading.appendChild(this._leadingSlot);
|
|
46
|
+
this._leading.hidden = true;
|
|
47
|
+
|
|
48
|
+
// Content — title + optional subtitle.
|
|
49
|
+
this._content = this.createElement('div', ['glass-list__content']);
|
|
50
|
+
this._titleEl = this.createElement('div', ['glass-list__title']);
|
|
51
|
+
this._titleEl.textContent = this.getAttribute('title') || '';
|
|
52
|
+
this._subtitleEl = this.createElement('div', ['glass-list__subtitle']);
|
|
53
|
+
if (this.getBoolAttr('wrap')) this._subtitleEl.classList.add('glass-list__subtitle--wrap');
|
|
54
|
+
const initialSubtitle = this.getAttribute('subtitle') || '';
|
|
55
|
+
this._subtitleEl.textContent = initialSubtitle;
|
|
56
|
+
this._subtitleEl.hidden = !initialSubtitle;
|
|
57
|
+
this._content.appendChild(this._titleEl);
|
|
58
|
+
this._content.appendChild(this._subtitleEl);
|
|
59
|
+
|
|
60
|
+
// Trailing — value span + slot for icons/badges.
|
|
61
|
+
this._trailing = this.createElement('div', ['glass-list__trailing']);
|
|
62
|
+
this._valueEl = this.createElement('span', ['glass-list__value']);
|
|
63
|
+
const initialDetail = this.getAttribute('detail') || '';
|
|
64
|
+
this._valueEl.textContent = initialDetail;
|
|
65
|
+
this._valueEl.hidden = !initialDetail;
|
|
66
|
+
this._trailing.appendChild(this._valueEl);
|
|
67
|
+
this._trailingSlot = document.createElement('slot');
|
|
68
|
+
this._trailingSlot.setAttribute('name', 'trailing');
|
|
69
|
+
this._trailing.appendChild(this._trailingSlot);
|
|
70
|
+
this._trailing.hidden = !initialDetail; // also revealed by slotchange
|
|
71
|
+
|
|
72
|
+
this._item.appendChild(this._leading);
|
|
73
|
+
this._item.appendChild(this._content);
|
|
74
|
+
this._item.appendChild(this._trailing);
|
|
75
|
+
|
|
76
|
+
// Sentinel sibling so the <li> is never :last-child inside its shadow
|
|
77
|
+
// parent — keeps the glasskit.css ::after divider rule matching.
|
|
78
|
+
const sentinel = this.createElement('span');
|
|
79
|
+
sentinel.hidden = true;
|
|
80
|
+
sentinel.setAttribute('aria-hidden', 'true');
|
|
81
|
+
|
|
82
|
+
wrap.appendChild(this._item);
|
|
83
|
+
wrap.appendChild(sentinel);
|
|
84
|
+
this._wrapper.appendChild(wrap);
|
|
85
|
+
}
|
|
86
|
+
|
|
87
|
+
setupEvents() {
|
|
88
|
+
// Reveal leading/trailing wrappers only when slotted content exists.
|
|
89
|
+
this._onLeadingSlotChange = () => {
|
|
90
|
+
this._leading.hidden = this._leadingSlot.assignedNodes().length === 0;
|
|
91
|
+
};
|
|
92
|
+
this._onTrailingSlotChange = () => {
|
|
93
|
+
const hasSlotted = this._trailingSlot.assignedNodes().length > 0;
|
|
94
|
+
const hasDetail = !this._valueEl.hidden;
|
|
95
|
+
this._trailing.hidden = !hasSlotted && !hasDetail;
|
|
96
|
+
};
|
|
97
|
+
this._leadingSlot.addEventListener('slotchange', this._onLeadingSlotChange);
|
|
98
|
+
this._trailingSlot.addEventListener('slotchange', this._onTrailingSlotChange);
|
|
99
|
+
this._onLeadingSlotChange();
|
|
100
|
+
this._onTrailingSlotChange();
|
|
101
|
+
|
|
102
|
+
// Forward clicks as glk-click — only for interactive items.
|
|
103
|
+
this._onClick = () => {
|
|
104
|
+
if (this.getBoolAttr('interactive')) {
|
|
105
|
+
this.emit('glk-click');
|
|
106
|
+
}
|
|
107
|
+
};
|
|
108
|
+
this._item.addEventListener('click', this._onClick);
|
|
109
|
+
}
|
|
110
|
+
|
|
111
|
+
teardownEvents() {
|
|
112
|
+
this._leadingSlot?.removeEventListener('slotchange', this._onLeadingSlotChange);
|
|
113
|
+
this._trailingSlot?.removeEventListener('slotchange', this._onTrailingSlotChange);
|
|
114
|
+
this._item?.removeEventListener('click', this._onClick);
|
|
115
|
+
}
|
|
116
|
+
|
|
117
|
+
onAttributeChanged(name) {
|
|
118
|
+
if (!this._item) return;
|
|
119
|
+
switch (name) {
|
|
120
|
+
case 'title':
|
|
121
|
+
this._titleEl.textContent = this.getAttribute('title') || '';
|
|
122
|
+
break;
|
|
123
|
+
case 'subtitle': {
|
|
124
|
+
const value = this.getAttribute('subtitle') || '';
|
|
125
|
+
this._subtitleEl.textContent = value;
|
|
126
|
+
this._subtitleEl.hidden = !value;
|
|
127
|
+
break;
|
|
128
|
+
}
|
|
129
|
+
case 'interactive':
|
|
130
|
+
this._item.classList.toggle('glass-list__item--interactive', this.getBoolAttr('interactive'));
|
|
131
|
+
break;
|
|
132
|
+
case 'center':
|
|
133
|
+
this._item.classList.toggle('glass-list__item--center', this.getBoolAttr('center'));
|
|
134
|
+
break;
|
|
135
|
+
case 'leading-lg':
|
|
136
|
+
this._leading.classList.toggle('glass-list__leading--lg', this.getBoolAttr('leading-lg'));
|
|
137
|
+
break;
|
|
138
|
+
case 'wrap':
|
|
139
|
+
this._subtitleEl.classList.toggle('glass-list__subtitle--wrap', this.getBoolAttr('wrap'));
|
|
140
|
+
break;
|
|
141
|
+
case 'detail': {
|
|
142
|
+
const detail = this.getAttribute('detail') || '';
|
|
143
|
+
this._valueEl.textContent = detail;
|
|
144
|
+
this._valueEl.hidden = !detail;
|
|
145
|
+
// Re-evaluate trailing visibility.
|
|
146
|
+
if (this._onTrailingSlotChange) this._onTrailingSlotChange();
|
|
147
|
+
break;
|
|
148
|
+
}
|
|
149
|
+
case 'variant': {
|
|
150
|
+
// Remove previous variant, add new one.
|
|
151
|
+
VARIANTS.forEach(v => this._item.classList.remove(`glass-list__item--${v}`));
|
|
152
|
+
const variant = this.getAttribute('variant');
|
|
153
|
+
if (variant && VARIANTS.includes(variant)) {
|
|
154
|
+
this._item.classList.add(`glass-list__item--${variant}`);
|
|
155
|
+
}
|
|
156
|
+
break;
|
|
157
|
+
}
|
|
158
|
+
}
|
|
159
|
+
}
|
|
160
|
+
|
|
161
|
+
get interactive() { return this.getBoolAttr('interactive'); }
|
|
162
|
+
set interactive(v) { this.setBoolAttr('interactive', v); }
|
|
163
|
+
|
|
164
|
+
get center() { return this.getBoolAttr('center'); }
|
|
165
|
+
set center(v) { this.setBoolAttr('center', v); }
|
|
166
|
+
|
|
167
|
+
get leadingLg() { return this.getBoolAttr('leading-lg'); }
|
|
168
|
+
set leadingLg(v) { this.setBoolAttr('leading-lg', v); }
|
|
169
|
+
|
|
170
|
+
get wrap() { return this.getBoolAttr('wrap'); }
|
|
171
|
+
set wrap(v) { this.setBoolAttr('wrap', v); }
|
|
172
|
+
|
|
173
|
+
get detail() { return this.getAttribute('detail') || ''; }
|
|
174
|
+
set detail(v) {
|
|
175
|
+
if (v) this.setAttribute('detail', v);
|
|
176
|
+
else this.removeAttribute('detail');
|
|
177
|
+
}
|
|
178
|
+
|
|
179
|
+
get variant() { return this.getAttribute('variant') || ''; }
|
|
180
|
+
set variant(v) {
|
|
181
|
+
if (v && VARIANTS.includes(v)) this.setAttribute('variant', v);
|
|
182
|
+
else this.removeAttribute('variant');
|
|
183
|
+
}
|
|
184
|
+
}
|
|
185
|
+
|
|
186
|
+
customElements.define('glk-list-item', GlkListItem);
|
|
187
|
+
|
|
188
|
+
export { GlkListItem };
|
|
@@ -0,0 +1,75 @@
|
|
|
1
|
+
import { G as GlkElement } from './shared/base-Bm9Z714o.js';
|
|
2
|
+
|
|
3
|
+
class GlkList extends GlkElement {
|
|
4
|
+
static get observedAttributes() {
|
|
5
|
+
return ['flush', 'bare', 'header'];
|
|
6
|
+
}
|
|
7
|
+
|
|
8
|
+
render() {
|
|
9
|
+
// Optional section header — sits before the <ul>.
|
|
10
|
+
this._header = this.createElement('div', ['glass-list__section-header'], { part: 'header' });
|
|
11
|
+
const initialHeader = this.getAttribute('header') || '';
|
|
12
|
+
this._header.textContent = initialHeader;
|
|
13
|
+
this._header.hidden = !initialHeader;
|
|
14
|
+
this._wrapper.appendChild(this._header);
|
|
15
|
+
|
|
16
|
+
this._ul = this.createElement('ul', ['glass-list'], { part: 'list' });
|
|
17
|
+
if (this.getBoolAttr('flush')) this._ul.classList.add('glass-list--flush');
|
|
18
|
+
if (this.getBoolAttr('bare')) this._ul.classList.add('glass-list--bare');
|
|
19
|
+
this._ul.appendChild(document.createElement('slot'));
|
|
20
|
+
this._wrapper.appendChild(this._ul);
|
|
21
|
+
}
|
|
22
|
+
|
|
23
|
+
setupEvents() {
|
|
24
|
+
this._syncLast();
|
|
25
|
+
this._mutObserver = new MutationObserver(() => this._syncLast());
|
|
26
|
+
this._mutObserver.observe(this, { childList: true });
|
|
27
|
+
}
|
|
28
|
+
|
|
29
|
+
teardownEvents() {
|
|
30
|
+
this._mutObserver?.disconnect();
|
|
31
|
+
}
|
|
32
|
+
|
|
33
|
+
_syncLast() {
|
|
34
|
+
const items = this.querySelectorAll(':scope > glk-list-item');
|
|
35
|
+
const lastIndex = items.length - 1;
|
|
36
|
+
items.forEach((item, i) => {
|
|
37
|
+
if (i === lastIndex) item.setAttribute('data-last', '');
|
|
38
|
+
else item.removeAttribute('data-last');
|
|
39
|
+
});
|
|
40
|
+
}
|
|
41
|
+
|
|
42
|
+
onAttributeChanged(name) {
|
|
43
|
+
if (!this._ul) return;
|
|
44
|
+
switch (name) {
|
|
45
|
+
case 'flush':
|
|
46
|
+
this._ul.classList.toggle('glass-list--flush', this.getBoolAttr('flush'));
|
|
47
|
+
break;
|
|
48
|
+
case 'bare':
|
|
49
|
+
this._ul.classList.toggle('glass-list--bare', this.getBoolAttr('bare'));
|
|
50
|
+
break;
|
|
51
|
+
case 'header': {
|
|
52
|
+
const value = this.getAttribute('header') || '';
|
|
53
|
+
this._header.textContent = value;
|
|
54
|
+
this._header.hidden = !value;
|
|
55
|
+
break;
|
|
56
|
+
}
|
|
57
|
+
}
|
|
58
|
+
}
|
|
59
|
+
|
|
60
|
+
get flush() { return this.getBoolAttr('flush'); }
|
|
61
|
+
set flush(v) { this.setBoolAttr('flush', v); }
|
|
62
|
+
|
|
63
|
+
get bare() { return this.getBoolAttr('bare'); }
|
|
64
|
+
set bare(v) { this.setBoolAttr('bare', v); }
|
|
65
|
+
|
|
66
|
+
get header() { return this.getAttribute('header') || ''; }
|
|
67
|
+
set header(v) {
|
|
68
|
+
if (v) this.setAttribute('header', v);
|
|
69
|
+
else this.removeAttribute('header');
|
|
70
|
+
}
|
|
71
|
+
}
|
|
72
|
+
|
|
73
|
+
customElements.define('glk-list', GlkList);
|
|
74
|
+
|
|
75
|
+
export { GlkList };
|
|
@@ -0,0 +1,101 @@
|
|
|
1
|
+
import { G as GlkElement } from './shared/base-Bm9Z714o.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'], { part: 'overlay' });
|
|
10
|
+
|
|
11
|
+
const modal = this.createElement('div', ['glass-modal'], { part: 'modal' });
|
|
12
|
+
|
|
13
|
+
// Header
|
|
14
|
+
const header = this.createElement('div', ['glass-modal__header'], { part: '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'], { part: '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'], { part: 'footer' });
|
|
25
|
+
|
|
26
|
+
modal.appendChild(header);
|
|
27
|
+
modal.appendChild(body);
|
|
28
|
+
modal.appendChild(this._footer);
|
|
29
|
+
|
|
30
|
+
// Defer footer population — children may not be parsed yet
|
|
31
|
+
requestAnimationFrame(() => this._populateFooter());
|
|
32
|
+
|
|
33
|
+
this._overlay.appendChild(modal);
|
|
34
|
+
this._wrapper.appendChild(this._overlay);
|
|
35
|
+
|
|
36
|
+
if (this.getBoolAttr('open')) {
|
|
37
|
+
this._overlay.classList.add('is-active');
|
|
38
|
+
}
|
|
39
|
+
}
|
|
40
|
+
|
|
41
|
+
_populateFooter() {
|
|
42
|
+
this._footer.innerHTML = '';
|
|
43
|
+
const actionsSlot = this.querySelector('[slot="actions"]');
|
|
44
|
+
if (actionsSlot) {
|
|
45
|
+
const buttons = actionsSlot.querySelectorAll('button');
|
|
46
|
+
buttons.forEach(btn => {
|
|
47
|
+
const clone = btn.cloneNode(true);
|
|
48
|
+
// Forward click events to the original button
|
|
49
|
+
clone.addEventListener('click', () => btn.click());
|
|
50
|
+
this._footer.appendChild(clone);
|
|
51
|
+
});
|
|
52
|
+
}
|
|
53
|
+
}
|
|
54
|
+
|
|
55
|
+
setupEvents() {
|
|
56
|
+
// Close on overlay click (outside modal)
|
|
57
|
+
this._onOverlayClick = (e) => {
|
|
58
|
+
if (e.target === this._overlay) {
|
|
59
|
+
this.removeAttribute('open');
|
|
60
|
+
this.emit('glk-close');
|
|
61
|
+
}
|
|
62
|
+
};
|
|
63
|
+
this._overlay.addEventListener('click', this._onOverlayClick);
|
|
64
|
+
|
|
65
|
+
// Close on Escape
|
|
66
|
+
this._onKeydown = (e) => {
|
|
67
|
+
if (e.key === 'Escape' && this.getBoolAttr('open')) {
|
|
68
|
+
this.removeAttribute('open');
|
|
69
|
+
this.emit('glk-close');
|
|
70
|
+
}
|
|
71
|
+
};
|
|
72
|
+
document.addEventListener('keydown', this._onKeydown);
|
|
73
|
+
}
|
|
74
|
+
|
|
75
|
+
teardownEvents() {
|
|
76
|
+
this._overlay?.removeEventListener('click', this._onOverlayClick);
|
|
77
|
+
document.removeEventListener('keydown', this._onKeydown);
|
|
78
|
+
}
|
|
79
|
+
|
|
80
|
+
onAttributeChanged(name) {
|
|
81
|
+
if (!this._overlay) return;
|
|
82
|
+
switch (name) {
|
|
83
|
+
case 'open':
|
|
84
|
+
this._overlay.classList.toggle('is-active', this.getBoolAttr('open'));
|
|
85
|
+
break;
|
|
86
|
+
case 'title':
|
|
87
|
+
this._titleEl.textContent = this.getAttribute('title') || '';
|
|
88
|
+
break;
|
|
89
|
+
}
|
|
90
|
+
}
|
|
91
|
+
|
|
92
|
+
show() { this.setAttribute('open', ''); }
|
|
93
|
+
close() { this.removeAttribute('open'); }
|
|
94
|
+
|
|
95
|
+
get open() { return this.getBoolAttr('open'); }
|
|
96
|
+
set open(v) { this.setBoolAttr('open', v); }
|
|
97
|
+
}
|
|
98
|
+
|
|
99
|
+
customElements.define('glk-modal', GlkModal);
|
|
100
|
+
|
|
101
|
+
export { GlkModal };
|
|
@@ -0,0 +1,13 @@
|
|
|
1
|
+
import { G as GlkElement } from './shared/base-Bm9Z714o.js';
|
|
2
|
+
|
|
3
|
+
class GlkNav extends GlkElement {
|
|
4
|
+
render() {
|
|
5
|
+
const nav = this.createElement('nav', ['glass-nav']);
|
|
6
|
+
nav.appendChild(document.createElement('slot'));
|
|
7
|
+
this._wrapper.appendChild(nav);
|
|
8
|
+
}
|
|
9
|
+
}
|
|
10
|
+
|
|
11
|
+
customElements.define('glk-nav', GlkNav);
|
|
12
|
+
|
|
13
|
+
export { GlkNav };
|
|
@@ -0,0 +1,49 @@
|
|
|
1
|
+
import { G as GlkElement } from './shared/base-Bm9Z714o.js';
|
|
2
|
+
|
|
3
|
+
class GlkPill extends GlkElement {
|
|
4
|
+
static get observedAttributes() {
|
|
5
|
+
return ['label', 'disabled'];
|
|
6
|
+
}
|
|
7
|
+
|
|
8
|
+
render() {
|
|
9
|
+
this._btn = this.createElement('button', ['glass-pill']);
|
|
10
|
+
|
|
11
|
+
if (this.getBoolAttr('disabled')) this._btn.disabled = true;
|
|
12
|
+
|
|
13
|
+
const ariaLabel = this.getAttribute('label');
|
|
14
|
+
if (ariaLabel) this._btn.setAttribute('aria-label', ariaLabel);
|
|
15
|
+
|
|
16
|
+
// Slotted content (SVG icons, text)
|
|
17
|
+
this._btn.appendChild(document.createElement('slot'));
|
|
18
|
+
this._wrapper.appendChild(this._btn);
|
|
19
|
+
}
|
|
20
|
+
|
|
21
|
+
setupEvents() {
|
|
22
|
+
this._onClick = () => {
|
|
23
|
+
if (!this.getBoolAttr('disabled')) {
|
|
24
|
+
this.emit('glk-click');
|
|
25
|
+
}
|
|
26
|
+
};
|
|
27
|
+
this._btn.addEventListener('click', this._onClick);
|
|
28
|
+
}
|
|
29
|
+
|
|
30
|
+
teardownEvents() {
|
|
31
|
+
this._btn?.removeEventListener('click', this._onClick);
|
|
32
|
+
}
|
|
33
|
+
|
|
34
|
+
onAttributeChanged(name) {
|
|
35
|
+
if (!this._btn) return;
|
|
36
|
+
switch (name) {
|
|
37
|
+
case 'label':
|
|
38
|
+
this._btn.setAttribute('aria-label', this.getAttribute('label') || '');
|
|
39
|
+
break;
|
|
40
|
+
case 'disabled':
|
|
41
|
+
this._btn.disabled = this.getBoolAttr('disabled');
|
|
42
|
+
break;
|
|
43
|
+
}
|
|
44
|
+
}
|
|
45
|
+
}
|
|
46
|
+
|
|
47
|
+
customElements.define('glk-pill', GlkPill);
|
|
48
|
+
|
|
49
|
+
export { GlkPill };
|
|
@@ -0,0 +1,109 @@
|
|
|
1
|
+
import { G as GlkElement } from './shared/base-Bm9Z714o.js';
|
|
2
|
+
|
|
3
|
+
const PLACEMENTS = ['top', 'bottom', 'start', 'end'];
|
|
4
|
+
|
|
5
|
+
class GlkPopover extends GlkElement {
|
|
6
|
+
static get observedAttributes() {
|
|
7
|
+
return ['open', 'placement'];
|
|
8
|
+
}
|
|
9
|
+
|
|
10
|
+
render() {
|
|
11
|
+
this._anchor = this.createElement('div', ['glass-popover-anchor']);
|
|
12
|
+
|
|
13
|
+
const triggerSlot = document.createElement('slot');
|
|
14
|
+
triggerSlot.setAttribute('name', 'trigger');
|
|
15
|
+
this._anchor.appendChild(triggerSlot);
|
|
16
|
+
|
|
17
|
+
this._popover = this.createElement('div', ['glass-popover']);
|
|
18
|
+
this._applyPlacement();
|
|
19
|
+
if (this.getBoolAttr('open')) {
|
|
20
|
+
this._popover.classList.add('is-open');
|
|
21
|
+
}
|
|
22
|
+
|
|
23
|
+
const contentSlot = document.createElement('slot');
|
|
24
|
+
this._popover.appendChild(contentSlot);
|
|
25
|
+
|
|
26
|
+
this._anchor.appendChild(this._popover);
|
|
27
|
+
this._wrapper.appendChild(this._anchor);
|
|
28
|
+
}
|
|
29
|
+
|
|
30
|
+
_applyPlacement() {
|
|
31
|
+
if (!this._popover) return;
|
|
32
|
+
PLACEMENTS.forEach(p => this._popover.classList.remove(`glass-popover--${p}`));
|
|
33
|
+
const placement = this.getAttribute('placement') || 'bottom';
|
|
34
|
+
if (placement !== 'bottom' && PLACEMENTS.includes(placement)) {
|
|
35
|
+
this._popover.classList.add(`glass-popover--${placement}`);
|
|
36
|
+
}
|
|
37
|
+
}
|
|
38
|
+
|
|
39
|
+
setupEvents() {
|
|
40
|
+
// Toggle when the slotted trigger is clicked.
|
|
41
|
+
this._onTriggerClick = (e) => {
|
|
42
|
+
const path = e.composedPath();
|
|
43
|
+
const hitTrigger = path.some(node => {
|
|
44
|
+
return node instanceof Element && node.getAttribute && node.getAttribute('slot') === 'trigger';
|
|
45
|
+
});
|
|
46
|
+
if (!hitTrigger) return;
|
|
47
|
+
e.stopPropagation();
|
|
48
|
+
this.toggle();
|
|
49
|
+
};
|
|
50
|
+
this.addEventListener('click', this._onTriggerClick);
|
|
51
|
+
|
|
52
|
+
// Close on outside click.
|
|
53
|
+
this._onDocClick = (e) => {
|
|
54
|
+
if (!this.getBoolAttr('open')) return;
|
|
55
|
+
const path = e.composedPath();
|
|
56
|
+
if (path.includes(this)) return;
|
|
57
|
+
this.close();
|
|
58
|
+
};
|
|
59
|
+
document.addEventListener('click', this._onDocClick);
|
|
60
|
+
|
|
61
|
+
// Close on Escape.
|
|
62
|
+
this._onKeydown = (e) => {
|
|
63
|
+
if (e.key === 'Escape' && this.getBoolAttr('open')) {
|
|
64
|
+
this.close();
|
|
65
|
+
}
|
|
66
|
+
};
|
|
67
|
+
document.addEventListener('keydown', this._onKeydown);
|
|
68
|
+
}
|
|
69
|
+
|
|
70
|
+
teardownEvents() {
|
|
71
|
+
this.removeEventListener('click', this._onTriggerClick);
|
|
72
|
+
document.removeEventListener('click', this._onDocClick);
|
|
73
|
+
document.removeEventListener('keydown', this._onKeydown);
|
|
74
|
+
}
|
|
75
|
+
|
|
76
|
+
onAttributeChanged(name) {
|
|
77
|
+
if (!this._popover) return;
|
|
78
|
+
switch (name) {
|
|
79
|
+
case 'open': {
|
|
80
|
+
const isOpen = this.getBoolAttr('open');
|
|
81
|
+
this._popover.classList.toggle('is-open', isOpen);
|
|
82
|
+
this.emit(isOpen ? 'glk-open' : 'glk-close');
|
|
83
|
+
break;
|
|
84
|
+
}
|
|
85
|
+
case 'placement':
|
|
86
|
+
this._applyPlacement();
|
|
87
|
+
break;
|
|
88
|
+
}
|
|
89
|
+
}
|
|
90
|
+
|
|
91
|
+
show() { this.setAttribute('open', ''); }
|
|
92
|
+
close() { this.removeAttribute('open'); }
|
|
93
|
+
toggle() {
|
|
94
|
+
if (this.getBoolAttr('open')) this.close();
|
|
95
|
+
else this.show();
|
|
96
|
+
}
|
|
97
|
+
|
|
98
|
+
get open() { return this.getBoolAttr('open'); }
|
|
99
|
+
set open(v) { this.setBoolAttr('open', v); }
|
|
100
|
+
|
|
101
|
+
get placement() { return this.getAttribute('placement') || 'bottom'; }
|
|
102
|
+
set placement(v) {
|
|
103
|
+
if (PLACEMENTS.includes(v)) this.setAttribute('placement', v);
|
|
104
|
+
}
|
|
105
|
+
}
|
|
106
|
+
|
|
107
|
+
customElements.define('glk-popover', GlkPopover);
|
|
108
|
+
|
|
109
|
+
export { GlkPopover };
|
|
@@ -0,0 +1,78 @@
|
|
|
1
|
+
import { G as GlkElement } from './shared/base-Bm9Z714o.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
|
+
|
|
78
|
+
export { GlkProgress };
|