@jungherz-de/glasskit-elements 1.13.0 → 1.15.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/README.md +43 -6
- package/dist/components/base.js +253 -0
- package/dist/components/glk-accordion-item.js +2 -1
- package/dist/components/glk-accordion.js +2 -1
- package/dist/components/glk-avatar.js +2 -1
- package/dist/components/glk-badge.js +2 -1
- package/dist/components/glk-button.js +2 -1
- package/dist/components/glk-card.js +2 -1
- package/dist/components/glk-checkbox.js +2 -1
- package/dist/components/glk-divider.js +2 -1
- package/dist/components/glk-empty.js +53 -0
- package/dist/components/glk-input.js +2 -1
- package/dist/components/glk-list-item.js +2 -1
- package/dist/components/glk-list.js +2 -1
- package/dist/components/glk-modal.js +2 -1
- package/dist/components/glk-nav.js +2 -1
- package/dist/components/glk-pill.js +2 -1
- package/dist/components/glk-popover.js +2 -1
- package/dist/components/glk-progress.js +2 -1
- package/dist/components/glk-radio.js +2 -1
- package/dist/components/glk-range.js +2 -1
- package/dist/components/glk-search.js +2 -1
- package/dist/components/glk-segmented.js +124 -0
- package/dist/components/glk-select.js +2 -1
- package/dist/components/glk-sheet.js +141 -0
- package/dist/components/glk-status.js +2 -1
- package/dist/components/glk-steps.js +75 -0
- package/dist/components/glk-tab-accessory.js +2 -1
- package/dist/components/glk-tab-bar.js +2 -1
- package/dist/components/glk-tab-dock.js +2 -1
- package/dist/components/glk-tab-item.js +2 -1
- package/dist/components/glk-textarea.js +2 -1
- package/dist/components/glk-title.js +2 -1
- package/dist/components/glk-toast.js +2 -1
- package/dist/components/glk-toggle.js +2 -1
- package/dist/glasskit-elements.esm.js +380 -3
- package/dist/glasskit-elements.js +385 -2
- package/dist/glasskit-elements.min.js +1 -1
- package/package.json +4 -3
- package/src/components/content/glk-empty.js +51 -0
- package/src/components/feedback/glk-sheet.js +139 -0
- package/src/components/forms/glk-segmented.js +122 -0
- package/src/components/navigation/glk-steps.js +73 -0
- package/src/index.js +10 -0
- package/dist/components/shared/base-ClsXgLON.js +0 -273
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@jungherz-de/glasskit-elements",
|
|
3
|
-
"version": "1.
|
|
3
|
+
"version": "1.15.0",
|
|
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",
|
|
@@ -19,6 +19,7 @@
|
|
|
19
19
|
"import": "./dist/glasskit-elements.esm.js",
|
|
20
20
|
"default": "./dist/glasskit-elements.js"
|
|
21
21
|
},
|
|
22
|
+
"./base.js": "./dist/components/base.js",
|
|
22
23
|
"./components/*.js": "./dist/components/*.js",
|
|
23
24
|
"./package.json": "./package.json"
|
|
24
25
|
},
|
|
@@ -44,10 +45,10 @@
|
|
|
44
45
|
"vanilla-js"
|
|
45
46
|
],
|
|
46
47
|
"peerDependencies": {
|
|
47
|
-
"@jungherz-de/glasskit": ">=1.
|
|
48
|
+
"@jungherz-de/glasskit": ">=1.15.0"
|
|
48
49
|
},
|
|
49
50
|
"devDependencies": {
|
|
50
|
-
"@jungherz-de/glasskit": "^1.
|
|
51
|
+
"@jungherz-de/glasskit": "^1.15.0",
|
|
51
52
|
"@rollup/plugin-node-resolve": "^15.0.0",
|
|
52
53
|
"@rollup/plugin-terser": "^0.4.0",
|
|
53
54
|
"rollup": "^4.0.0"
|
|
@@ -0,0 +1,51 @@
|
|
|
1
|
+
import { GlkElement } from '../../base.js';
|
|
2
|
+
|
|
3
|
+
// Empty state for lists and result pages. Came back from EhrenPfoten in 1.15.0.
|
|
4
|
+
//
|
|
5
|
+
// Attributes: title, text — an empty one hides its element instead of
|
|
6
|
+
// leaving an empty paragraph
|
|
7
|
+
// Slots: default (icon, with a plain circle as slot fallback), action
|
|
8
|
+
// Parts: empty, icon, title, text, action
|
|
9
|
+
|
|
10
|
+
const FALLBACK_ICON = '<svg viewBox="0 0 24 24" aria-hidden="true"><circle cx="12" cy="12" r="9"/><path d="M8 12h8"/></svg>';
|
|
11
|
+
|
|
12
|
+
class GlkEmpty extends GlkElement {
|
|
13
|
+
static get observedAttributes() { return ['title', 'text']; }
|
|
14
|
+
|
|
15
|
+
render() {
|
|
16
|
+
const root = this.createElement('div', ['glass-empty'], { part: 'empty' });
|
|
17
|
+
const icon = this.createElement('span', ['glass-empty__icon'], { part: 'icon' });
|
|
18
|
+
const iconSlot = document.createElement('slot');
|
|
19
|
+
iconSlot.innerHTML = FALLBACK_ICON;
|
|
20
|
+
icon.appendChild(iconSlot);
|
|
21
|
+
this._titleEl = this.createElement('p', ['glass-empty__title'], { part: 'title' });
|
|
22
|
+
this._textEl = this.createElement('p', ['glass-empty__text'], { part: 'text' });
|
|
23
|
+
const action = this.createElement('div', ['glass-empty__action'], { part: 'action' });
|
|
24
|
+
action.appendChild(this.createElement('slot', [], { name: 'action' }));
|
|
25
|
+
root.append(icon, this._titleEl, this._textEl, action);
|
|
26
|
+
this._wrapper.appendChild(root);
|
|
27
|
+
this._update();
|
|
28
|
+
}
|
|
29
|
+
|
|
30
|
+
_update() {
|
|
31
|
+
const title = this.getAttribute('title') || '';
|
|
32
|
+
const text = this.getAttribute('text') || '';
|
|
33
|
+
this._titleEl.textContent = title;
|
|
34
|
+
this._titleEl.hidden = !title;
|
|
35
|
+
this._textEl.textContent = text;
|
|
36
|
+
this._textEl.hidden = !text;
|
|
37
|
+
}
|
|
38
|
+
|
|
39
|
+
onAttributeChanged() {
|
|
40
|
+
if (this._titleEl) this._update();
|
|
41
|
+
}
|
|
42
|
+
|
|
43
|
+
get text() { return this.getAttribute('text') || ''; }
|
|
44
|
+
set text(v) {
|
|
45
|
+
if (v) this.setAttribute('text', v);
|
|
46
|
+
else this.removeAttribute('text');
|
|
47
|
+
}
|
|
48
|
+
}
|
|
49
|
+
|
|
50
|
+
customElements.define('glk-empty', GlkEmpty);
|
|
51
|
+
export { GlkEmpty };
|
|
@@ -0,0 +1,139 @@
|
|
|
1
|
+
import { GlkElement } from '../../base.js';
|
|
2
|
+
|
|
3
|
+
// Bottom sheet — the mobile sibling of <glk-modal>. Came back from
|
|
4
|
+
// EhrenPfoten in 1.15.0.
|
|
5
|
+
//
|
|
6
|
+
// Attributes: open, inline (no overlay, always visible), title
|
|
7
|
+
// Properties: open, inline · Methods: show(), close()
|
|
8
|
+
// Slots: default (content), actions
|
|
9
|
+
// Event: glk-close — only when the user closes it (scrim click, Escape),
|
|
10
|
+
// like <glk-modal>
|
|
11
|
+
// Parts: overlay, sheet, title, body, actions
|
|
12
|
+
//
|
|
13
|
+
// Opening and closing are animated by the CSS block: the overlay gets
|
|
14
|
+
// .is-active one frame after it is unhidden, and on closing it is hidden
|
|
15
|
+
// only after transitionend (safety net 400 ms), so the blurred overlay
|
|
16
|
+
// leaves the layout instead of idling at opacity 0. Under
|
|
17
|
+
// prefers-reduced-motion it switches at once.
|
|
18
|
+
|
|
19
|
+
const HIDE_FALLBACK_MS = 400;
|
|
20
|
+
|
|
21
|
+
function reducedMotion() {
|
|
22
|
+
return typeof matchMedia === 'function' && matchMedia('(prefers-reduced-motion: reduce)').matches;
|
|
23
|
+
}
|
|
24
|
+
|
|
25
|
+
class GlkSheet extends GlkElement {
|
|
26
|
+
static get observedAttributes() { return ['open', 'inline', 'title']; }
|
|
27
|
+
|
|
28
|
+
render() {
|
|
29
|
+
this._overlay = this.createElement('div', [], { part: 'overlay' });
|
|
30
|
+
this._panel = this.createElement('div', ['glass-sheet'], { role: 'dialog', part: 'sheet' });
|
|
31
|
+
this._panel.appendChild(this.createElement('div', ['glass-sheet__grip'], { 'aria-hidden': 'true' }));
|
|
32
|
+
this._titleEl = this.createElement('h2', ['glass-sheet__title'], { part: 'title' });
|
|
33
|
+
const body = this.createElement('div', ['glass-sheet__body'], { part: 'body' });
|
|
34
|
+
body.appendChild(document.createElement('slot'));
|
|
35
|
+
const actions = this.createElement('div', ['glass-sheet__actions'], { part: 'actions' });
|
|
36
|
+
actions.appendChild(this.createElement('slot', [], { name: 'actions' }));
|
|
37
|
+
this._panel.append(this._titleEl, body, actions);
|
|
38
|
+
this._overlay.appendChild(this._panel);
|
|
39
|
+
this._wrapper.appendChild(this._overlay);
|
|
40
|
+
this._applyTitle();
|
|
41
|
+
this._applyMode();
|
|
42
|
+
}
|
|
43
|
+
|
|
44
|
+
_applyTitle() {
|
|
45
|
+
const title = this.getAttribute('title') || '';
|
|
46
|
+
this._titleEl.textContent = title;
|
|
47
|
+
this._titleEl.hidden = !title;
|
|
48
|
+
if (title) this._panel.setAttribute('aria-label', title);
|
|
49
|
+
else this._panel.removeAttribute('aria-label');
|
|
50
|
+
}
|
|
51
|
+
|
|
52
|
+
_applyMode() {
|
|
53
|
+
const inline = this.inline;
|
|
54
|
+
this._overlay.classList.toggle('glass-sheet-overlay', !inline);
|
|
55
|
+
this._panel.classList.toggle('glass-sheet--inline', inline);
|
|
56
|
+
this._panel.setAttribute('aria-modal', String(!inline));
|
|
57
|
+
clearTimeout(this._hideTimer);
|
|
58
|
+
if (inline) {
|
|
59
|
+
this._overlay.classList.remove('is-active');
|
|
60
|
+
this._overlay.hidden = false;
|
|
61
|
+
} else if (this.open) {
|
|
62
|
+
this._show();
|
|
63
|
+
} else {
|
|
64
|
+
this._overlay.classList.remove('is-active');
|
|
65
|
+
this._overlay.hidden = true;
|
|
66
|
+
}
|
|
67
|
+
}
|
|
68
|
+
|
|
69
|
+
_show() {
|
|
70
|
+
clearTimeout(this._hideTimer);
|
|
71
|
+
this._panel.removeEventListener('transitionend', this._onHidden);
|
|
72
|
+
this._overlay.hidden = false;
|
|
73
|
+
void this._overlay.offsetHeight; // reflow, so the transition starts from the hidden state
|
|
74
|
+
requestAnimationFrame(() => {
|
|
75
|
+
if (this.open && !this.inline) this._overlay.classList.add('is-active');
|
|
76
|
+
});
|
|
77
|
+
}
|
|
78
|
+
|
|
79
|
+
_hide() {
|
|
80
|
+
this._overlay.classList.remove('is-active');
|
|
81
|
+
this._onHidden = () => {
|
|
82
|
+
clearTimeout(this._hideTimer);
|
|
83
|
+
this._panel.removeEventListener('transitionend', this._onHidden);
|
|
84
|
+
if (!this.open && !this.inline) this._overlay.hidden = true;
|
|
85
|
+
};
|
|
86
|
+
if (reducedMotion()) {
|
|
87
|
+
this._onHidden();
|
|
88
|
+
return;
|
|
89
|
+
}
|
|
90
|
+
this._panel.addEventListener('transitionend', this._onHidden);
|
|
91
|
+
this._hideTimer = setTimeout(this._onHidden, HIDE_FALLBACK_MS);
|
|
92
|
+
}
|
|
93
|
+
|
|
94
|
+
_dismiss() {
|
|
95
|
+
this.removeAttribute('open');
|
|
96
|
+
this.emit('glk-close');
|
|
97
|
+
}
|
|
98
|
+
|
|
99
|
+
setupEvents() {
|
|
100
|
+
this._onOverlayClick = (event) => {
|
|
101
|
+
if (!this.inline && event.target === this._overlay) this._dismiss();
|
|
102
|
+
};
|
|
103
|
+
this._onKeydown = (event) => {
|
|
104
|
+
if (event.key === 'Escape' && this.open && !this.inline) this._dismiss();
|
|
105
|
+
};
|
|
106
|
+
this._overlay.addEventListener('click', this._onOverlayClick);
|
|
107
|
+
document.addEventListener('keydown', this._onKeydown);
|
|
108
|
+
}
|
|
109
|
+
|
|
110
|
+
teardownEvents() {
|
|
111
|
+
this._overlay?.removeEventListener('click', this._onOverlayClick);
|
|
112
|
+
document.removeEventListener('keydown', this._onKeydown);
|
|
113
|
+
}
|
|
114
|
+
|
|
115
|
+
onAttributeChanged(name) {
|
|
116
|
+
if (!this._overlay) return;
|
|
117
|
+
switch (name) {
|
|
118
|
+
case 'open':
|
|
119
|
+
if (this.inline) return;
|
|
120
|
+
if (this.open) this._show();
|
|
121
|
+
else this._hide();
|
|
122
|
+
break;
|
|
123
|
+
case 'inline': this._applyMode(); break;
|
|
124
|
+
case 'title': this._applyTitle(); break;
|
|
125
|
+
}
|
|
126
|
+
}
|
|
127
|
+
|
|
128
|
+
show() { this.setAttribute('open', ''); }
|
|
129
|
+
close() { this.removeAttribute('open'); }
|
|
130
|
+
|
|
131
|
+
get open() { return this.getBoolAttr('open'); }
|
|
132
|
+
set open(v) { this.setBoolAttr('open', v); }
|
|
133
|
+
|
|
134
|
+
get inline() { return this.getBoolAttr('inline'); }
|
|
135
|
+
set inline(v) { this.setBoolAttr('inline', v); }
|
|
136
|
+
}
|
|
137
|
+
|
|
138
|
+
customElements.define('glk-sheet', GlkSheet);
|
|
139
|
+
export { GlkSheet };
|
|
@@ -0,0 +1,122 @@
|
|
|
1
|
+
import { GlkFormElement } from '../../base.js';
|
|
2
|
+
|
|
3
|
+
// One button per option, the chosen one marked aria-pressed="true" — GlassKit
|
|
4
|
+
// styles exactly that attribute. Came back from EhrenPfoten in 1.15.0.
|
|
5
|
+
//
|
|
6
|
+
// Attributes: options (JSON [{value,label,tone?,disabled?}]), value, full,
|
|
7
|
+
// label (aria-label of the group), name (form field name)
|
|
8
|
+
// Properties: value, options (array or JSON text), full, label
|
|
9
|
+
// Event: glk-change { value } — only on a change made by the user
|
|
10
|
+
// Part: group
|
|
11
|
+
//
|
|
12
|
+
// Form-associated: a surrounding <form> receives name=value, reset restores
|
|
13
|
+
// the initial value. A value change only re-sets aria-pressed, never rebuilds,
|
|
14
|
+
// so focus stays on the button that was pressed.
|
|
15
|
+
|
|
16
|
+
const TONES = ['success', 'warning', 'error'];
|
|
17
|
+
|
|
18
|
+
function parseList(json) {
|
|
19
|
+
try {
|
|
20
|
+
const list = JSON.parse(json || '[]');
|
|
21
|
+
return Array.isArray(list) ? list : [];
|
|
22
|
+
} catch {
|
|
23
|
+
return [];
|
|
24
|
+
}
|
|
25
|
+
}
|
|
26
|
+
|
|
27
|
+
class GlkSegmented extends GlkFormElement {
|
|
28
|
+
static get observedAttributes() { return ['options', 'value', 'full', 'label']; }
|
|
29
|
+
|
|
30
|
+
render() {
|
|
31
|
+
this._group = this.createElement('div', ['glass-segmented'], { role: 'group', part: 'group' });
|
|
32
|
+
this._wrapper.appendChild(this._group);
|
|
33
|
+
this._initialValue = this.value;
|
|
34
|
+
this._build();
|
|
35
|
+
this._applyFull();
|
|
36
|
+
this._applyLabel();
|
|
37
|
+
}
|
|
38
|
+
|
|
39
|
+
_build() {
|
|
40
|
+
this._group.replaceChildren();
|
|
41
|
+
for (const option of parseList(this.getAttribute('options'))) {
|
|
42
|
+
const value = String(option.value ?? '');
|
|
43
|
+
const button = this.createElement('button', ['glass-segmented__item'], { type: 'button', 'data-value': value });
|
|
44
|
+
if (TONES.includes(option.tone)) {
|
|
45
|
+
button.classList.add(`glass-segmented__item--${option.tone}`);
|
|
46
|
+
button.appendChild(this.createElement('span', ['glass-segmented__dot']));
|
|
47
|
+
}
|
|
48
|
+
if (option.disabled) button.disabled = true;
|
|
49
|
+
button.appendChild(document.createTextNode(option.label ?? value));
|
|
50
|
+
this._group.appendChild(button);
|
|
51
|
+
}
|
|
52
|
+
this._syncValue();
|
|
53
|
+
}
|
|
54
|
+
|
|
55
|
+
_syncValue() {
|
|
56
|
+
const value = this.value;
|
|
57
|
+
for (const button of this._group.querySelectorAll('button[data-value]')) {
|
|
58
|
+
button.setAttribute('aria-pressed', String(button.dataset.value === value));
|
|
59
|
+
}
|
|
60
|
+
this.setFormValue(value);
|
|
61
|
+
}
|
|
62
|
+
|
|
63
|
+
_applyFull() {
|
|
64
|
+
this._group.classList.toggle('glass-segmented--full', this.getBoolAttr('full'));
|
|
65
|
+
}
|
|
66
|
+
|
|
67
|
+
_applyLabel() {
|
|
68
|
+
const label = this.getAttribute('label');
|
|
69
|
+
if (label) this._group.setAttribute('aria-label', label);
|
|
70
|
+
else this._group.removeAttribute('aria-label');
|
|
71
|
+
}
|
|
72
|
+
|
|
73
|
+
setupEvents() {
|
|
74
|
+
this._onClick = (event) => {
|
|
75
|
+
const button = event.target.closest('button[data-value]');
|
|
76
|
+
if (!button || button.disabled) return;
|
|
77
|
+
const { value } = button.dataset;
|
|
78
|
+
if (value === this.value) return;
|
|
79
|
+
this.value = value;
|
|
80
|
+
this.emit('glk-change', { value });
|
|
81
|
+
};
|
|
82
|
+
this._group.addEventListener('click', this._onClick);
|
|
83
|
+
}
|
|
84
|
+
|
|
85
|
+
teardownEvents() {
|
|
86
|
+
this._group?.removeEventListener('click', this._onClick);
|
|
87
|
+
}
|
|
88
|
+
|
|
89
|
+
onAttributeChanged(name) {
|
|
90
|
+
if (!this._group) return;
|
|
91
|
+
switch (name) {
|
|
92
|
+
case 'value': this._syncValue(); break;
|
|
93
|
+
case 'options': this._build(); break;
|
|
94
|
+
case 'full': this._applyFull(); break;
|
|
95
|
+
case 'label': this._applyLabel(); break;
|
|
96
|
+
}
|
|
97
|
+
}
|
|
98
|
+
|
|
99
|
+
resetValue() { this.value = this._initialValue; }
|
|
100
|
+
restoreValue(state) { if (typeof state === 'string') this.value = state; }
|
|
101
|
+
|
|
102
|
+
get value() { return this.getAttribute('value') ?? ''; }
|
|
103
|
+
set value(v) {
|
|
104
|
+
if (v == null) this.removeAttribute('value');
|
|
105
|
+
else this.setAttribute('value', String(v));
|
|
106
|
+
}
|
|
107
|
+
|
|
108
|
+
get options() { return parseList(this.getAttribute('options')); }
|
|
109
|
+
set options(v) { this.setAttribute('options', typeof v === 'string' ? v : JSON.stringify(v ?? [])); }
|
|
110
|
+
|
|
111
|
+
get full() { return this.getBoolAttr('full'); }
|
|
112
|
+
set full(v) { this.setBoolAttr('full', v); }
|
|
113
|
+
|
|
114
|
+
get label() { return this.getAttribute('label') || ''; }
|
|
115
|
+
set label(v) {
|
|
116
|
+
if (v) this.setAttribute('label', v);
|
|
117
|
+
else this.removeAttribute('label');
|
|
118
|
+
}
|
|
119
|
+
}
|
|
120
|
+
|
|
121
|
+
customElements.define('glk-segmented', GlkSegmented);
|
|
122
|
+
export { GlkSegmented };
|
|
@@ -0,0 +1,73 @@
|
|
|
1
|
+
import { GlkElement } from '../../base.js';
|
|
2
|
+
|
|
3
|
+
// Progress through a short flow — purely presentational. Came back from
|
|
4
|
+
// EhrenPfoten in 1.15.0.
|
|
5
|
+
//
|
|
6
|
+
// Attributes: steps (comma-separated labels), current (0-based), label
|
|
7
|
+
// (aria-label of the list, optional)
|
|
8
|
+
// Property: current, steps (array or comma-separated text)
|
|
9
|
+
// Part: steps
|
|
10
|
+
//
|
|
11
|
+
// The narrowing in tight frames is the CSS block's container query; the
|
|
12
|
+
// element knows nothing about it. Done steps show an SVG check, not a text
|
|
13
|
+
// glyph, so the mark does not depend on the font.
|
|
14
|
+
|
|
15
|
+
const CHECK = '<svg viewBox="0 0 24 24" aria-hidden="true"><path d="M5 12l5 5 9-10"/></svg>';
|
|
16
|
+
|
|
17
|
+
class GlkSteps extends GlkElement {
|
|
18
|
+
static get observedAttributes() { return ['steps', 'current', 'label']; }
|
|
19
|
+
|
|
20
|
+
render() {
|
|
21
|
+
this._list = this.createElement('ol', ['glass-steps'], { part: 'steps' });
|
|
22
|
+
this._wrapper.appendChild(this._list);
|
|
23
|
+
this._build();
|
|
24
|
+
this._applyLabel();
|
|
25
|
+
}
|
|
26
|
+
|
|
27
|
+
_build() {
|
|
28
|
+
const items = this.steps;
|
|
29
|
+
const current = this.current;
|
|
30
|
+
this._list.replaceChildren();
|
|
31
|
+
items.forEach((label, i) => {
|
|
32
|
+
const item = this.createElement('li', ['glass-steps__item']);
|
|
33
|
+
if (i < current) item.classList.add('glass-steps__item--done');
|
|
34
|
+
if (i === current) {
|
|
35
|
+
item.classList.add('glass-steps__item--current');
|
|
36
|
+
item.setAttribute('aria-current', 'step');
|
|
37
|
+
}
|
|
38
|
+
const num = this.createElement('span', ['glass-steps__num']);
|
|
39
|
+
if (i < current) num.innerHTML = CHECK;
|
|
40
|
+
else num.textContent = String(i + 1);
|
|
41
|
+
const text = this.createElement('span', ['glass-steps__label']);
|
|
42
|
+
text.textContent = label;
|
|
43
|
+
item.append(num, text);
|
|
44
|
+
this._list.appendChild(item);
|
|
45
|
+
if (i < items.length - 1) {
|
|
46
|
+
this._list.appendChild(this.createElement('li', ['glass-steps__line'], { 'aria-hidden': 'true' }));
|
|
47
|
+
}
|
|
48
|
+
});
|
|
49
|
+
}
|
|
50
|
+
|
|
51
|
+
_applyLabel() {
|
|
52
|
+
const label = this.getAttribute('label');
|
|
53
|
+
if (label) this._list.setAttribute('aria-label', label);
|
|
54
|
+
else this._list.removeAttribute('aria-label');
|
|
55
|
+
}
|
|
56
|
+
|
|
57
|
+
onAttributeChanged(name) {
|
|
58
|
+
if (!this._list) return;
|
|
59
|
+
if (name === 'label') this._applyLabel();
|
|
60
|
+
else this._build();
|
|
61
|
+
}
|
|
62
|
+
|
|
63
|
+
get current() { return Number(this.getAttribute('current')) || 0; }
|
|
64
|
+
set current(v) { this.setAttribute('current', String(Number(v) || 0)); }
|
|
65
|
+
|
|
66
|
+
get steps() {
|
|
67
|
+
return (this.getAttribute('steps') || '').split(',').map(s => s.trim()).filter(Boolean);
|
|
68
|
+
}
|
|
69
|
+
set steps(v) { this.setAttribute('steps', Array.isArray(v) ? v.join(',') : String(v ?? '')); }
|
|
70
|
+
}
|
|
71
|
+
|
|
72
|
+
customElements.define('glk-steps', GlkSteps);
|
|
73
|
+
export { GlkSteps };
|
package/src/index.js
CHANGED
|
@@ -1,6 +1,12 @@
|
|
|
1
1
|
// GlassKit Elements — Web Components for GlassKit CSS
|
|
2
2
|
// https://github.com/JUNGHERZ/GlassKit
|
|
3
3
|
|
|
4
|
+
// Base classes — so a project can build its own elements on the same
|
|
5
|
+
// lifecycle, stylesheet adoption, theme sync and emit(). Also reachable as
|
|
6
|
+
// GlassKitElements.GlkElement from the IIFE bundle, and via the stable
|
|
7
|
+
// subpath '@jungherz-de/glasskit-elements/base.js' for per-component setups.
|
|
8
|
+
export { GlkElement, GlkFormElement } from './base.js';
|
|
9
|
+
|
|
4
10
|
// Navigation
|
|
5
11
|
export { GlkNav } from './components/navigation/glk-nav.js';
|
|
6
12
|
export { GlkPill } from './components/navigation/glk-pill.js';
|
|
@@ -8,6 +14,7 @@ export { GlkTabBar } from './components/navigation/glk-tab-bar.js';
|
|
|
8
14
|
export { GlkTabItem } from './components/navigation/glk-tab-item.js';
|
|
9
15
|
export { GlkTabDock } from './components/navigation/glk-tab-dock.js';
|
|
10
16
|
export { GlkTabAccessory } from './components/navigation/glk-tab-accessory.js';
|
|
17
|
+
export { GlkSteps } from './components/navigation/glk-steps.js';
|
|
11
18
|
|
|
12
19
|
// Content
|
|
13
20
|
export { GlkCard } from './components/content/glk-card.js';
|
|
@@ -16,6 +23,7 @@ export { GlkAvatar } from './components/content/glk-avatar.js';
|
|
|
16
23
|
export { GlkTitle } from './components/content/glk-title.js';
|
|
17
24
|
export { GlkDivider } from './components/content/glk-divider.js';
|
|
18
25
|
export { GlkStatus } from './components/content/glk-status.js';
|
|
26
|
+
export { GlkEmpty } from './components/content/glk-empty.js';
|
|
19
27
|
|
|
20
28
|
// Buttons
|
|
21
29
|
export { GlkButton } from './components/buttons/glk-button.js';
|
|
@@ -29,12 +37,14 @@ export { GlkToggle } from './components/forms/glk-toggle.js';
|
|
|
29
37
|
export { GlkCheckbox } from './components/forms/glk-checkbox.js';
|
|
30
38
|
export { GlkRadio } from './components/forms/glk-radio.js';
|
|
31
39
|
export { GlkRange } from './components/forms/glk-range.js';
|
|
40
|
+
export { GlkSegmented } from './components/forms/glk-segmented.js';
|
|
32
41
|
|
|
33
42
|
// Feedback
|
|
34
43
|
export { GlkProgress } from './components/feedback/glk-progress.js';
|
|
35
44
|
export { GlkModal } from './components/feedback/glk-modal.js';
|
|
36
45
|
export { GlkToast } from './components/feedback/glk-toast.js';
|
|
37
46
|
export { GlkPopover } from './components/feedback/glk-popover.js';
|
|
47
|
+
export { GlkSheet } from './components/feedback/glk-sheet.js';
|
|
38
48
|
|
|
39
49
|
// Containers
|
|
40
50
|
export { GlkAccordion } from './components/containers/glk-accordion.js';
|